tclUnixInit.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:33k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclUnixInit.c --
  3.  *
  4.  * Contains the Unix-specific interpreter initialization functions.
  5.  *
  6.  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
  7.  * Copyright (c) 1999 by Scriptics Corporation.
  8.  * All rights reserved.
  9.  *
  10.  * RCS: @(#) $Id: tclUnixInit.c,v 1.34.2.15 2007/04/29 02:19:51 das Exp $
  11.  */
  12. #if defined(HAVE_COREFOUNDATION)
  13. #include <CoreFoundation/CoreFoundation.h>
  14. #endif
  15. #include "tclInt.h"
  16. #include "tclPort.h"
  17. #include <locale.h>
  18. #ifdef HAVE_LANGINFO
  19. #   include <langinfo.h>
  20. #   ifdef __APPLE__
  21. #       if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1030
  22.     /* Support for weakly importing nl_langinfo on Darwin. */
  23. #           define WEAK_IMPORT_NL_LANGINFO
  24.     extern char *nl_langinfo(nl_item) WEAK_IMPORT_ATTRIBUTE;
  25. #       endif
  26. #    endif
  27. #endif
  28. #if defined(__FreeBSD__) && defined(__GNUC__)
  29. #   include <floatingpoint.h>
  30. #endif
  31. #if defined(__bsdi__)
  32. #   include <sys/param.h>
  33. #   if _BSDI_VERSION > 199501
  34. # include <dlfcn.h>
  35. #   endif
  36. #endif
  37. /*
  38.  * The Init script (common to Windows and Unix platforms) is
  39.  * defined in tkInitScript.h
  40.  */
  41. #include "tclInitScript.h"
  42. /* Used to store the encoding used for binary files */
  43. static Tcl_Encoding binaryEncoding = NULL;
  44. /* Has the basic library path encoding issue been fixed */
  45. static int libraryPathEncodingFixed = 0;
  46. /*
  47.  * Tcl tries to use standard and homebrew methods to guess the right
  48.  * encoding on the platform.  However, there is always a final fallback,
  49.  * and this value is it.  Make sure it is a real Tcl encoding.
  50.  */
  51. #ifndef TCL_DEFAULT_ENCODING
  52. #define TCL_DEFAULT_ENCODING "iso8859-1"
  53. #endif
  54. /*
  55.  * Default directory in which to look for Tcl library scripts.  The
  56.  * symbol is defined by Makefile.
  57.  */
  58. static char defaultLibraryDir[sizeof(TCL_LIBRARY)+200] = TCL_LIBRARY;
  59. /*
  60.  * Directory in which to look for packages (each package is typically
  61.  * installed as a subdirectory of this directory).  The symbol is
  62.  * defined by Makefile.
  63.  */
  64. static char pkgPath[sizeof(TCL_PACKAGE_PATH)+200] = TCL_PACKAGE_PATH;
  65. /*
  66.  * The following table is used to map from Unix locale strings to
  67.  * encoding files.  If HAVE_LANGINFO is defined, then this is a fallback
  68.  * table when the result from nl_langinfo isn't a recognized encoding.
  69.  * Otherwise this is the first list checked for a mapping from env
  70.  * encoding to Tcl encoding name.
  71.  */
  72. typedef struct LocaleTable {
  73.     CONST char *lang;
  74.     CONST char *encoding;
  75. } LocaleTable;
  76. static CONST LocaleTable localeTable[] = {
  77. #ifdef HAVE_LANGINFO
  78.     {"gb2312-1980", "gb2312"},
  79.     {"ansi-1251", "cp1251"}, /* Solaris gets this wrong. */
  80. #ifdef __hpux
  81.     {"SJIS", "shiftjis"},
  82.     {"eucjp", "euc-jp"},
  83.     {"euckr", "euc-kr"},
  84.     {"euctw", "euc-cn"},
  85.     {"greek8", "cp869"},
  86.     {"iso88591", "iso8859-1"},
  87.     {"iso88592", "iso8859-2"},
  88.     {"iso88595", "iso8859-5"},
  89.     {"iso88596", "iso8859-6"},
  90.     {"iso88597", "iso8859-7"},
  91.     {"iso88598", "iso8859-8"},
  92.     {"iso88599", "iso8859-9"},
  93.     {"iso885915", "iso8859-15"},
  94.     {"roman8", "iso8859-1"},
  95.     {"tis620", "tis-620"},
  96.     {"turkish8", "cp857"},
  97.     {"utf8", "utf-8"},
  98. #endif /* __hpux */
  99. #endif /* HAVE_LANGINFO */
  100.     {"ja_JP.SJIS", "shiftjis"},
  101.     {"ja_JP.EUC", "euc-jp"},
  102.     {"ja_JP.eucJP",     "euc-jp"},
  103.     {"ja_JP.JIS", "iso2022-jp"},
  104.     {"ja_JP.mscode", "shiftjis"},
  105.     {"ja_JP.ujis", "euc-jp"},
  106.     {"ja_JP", "euc-jp"},
  107.     {"Ja_JP", "shiftjis"},
  108.     {"Jp_JP", "shiftjis"},
  109.     {"japan", "euc-jp"},
  110. #ifdef hpux
  111.     {"japanese", "shiftjis"},
  112.     {"ja", "shiftjis"},
  113. #else
  114.     {"japanese", "euc-jp"},
  115.     {"ja", "euc-jp"},
  116. #endif
  117.     {"japanese.sjis", "shiftjis"},
  118.     {"japanese.euc", "euc-jp"},
  119.     {"japanese-sjis", "shiftjis"},
  120.     {"japanese-ujis", "euc-jp"},
  121.     {"ko",              "euc-kr"},
  122.     {"ko_KR",           "euc-kr"},
  123.     {"ko_KR.EUC",       "euc-kr"},
  124.     {"ko_KR.euc",       "euc-kr"},
  125.     {"ko_KR.eucKR",     "euc-kr"},
  126.     {"korean",          "euc-kr"},
  127.     {"ru", "iso8859-5"},
  128.     {"ru_RU", "iso8859-5"},
  129.     {"ru_SU", "iso8859-5"},
  130.     {"zh", "cp936"},
  131.     {"zh_CN.gb2312", "euc-cn"},
  132.     {"zh_CN.GB2312", "euc-cn"},
  133.     {"zh_CN.GBK", "euc-cn"},
  134.     {"zh_TW.Big5", "big5"},
  135.     {"zh_TW", "euc-tw"},
  136.     {NULL, NULL}
  137. };
  138. #ifdef HAVE_COREFOUNDATION
  139. static int MacOSXGetLibraryPath _ANSI_ARGS_((
  140.     Tcl_Interp *interp, int maxPathLen,
  141.     char *tclLibPath));
  142. #endif /* HAVE_COREFOUNDATION */
  143. #if defined(__APPLE__) && (defined(TCL_LOAD_FROM_MEMORY) || ( 
  144. defined(TCL_THREADS) && defined(MAC_OS_X_VERSION_MIN_REQUIRED) && 
  145. MAC_OS_X_VERSION_MIN_REQUIRED < 1030) || ( 
  146. defined(__LP64__) && defined(MAC_OS_X_VERSION_MIN_REQUIRED) && 
  147. MAC_OS_X_VERSION_MIN_REQUIRED < 1050))
  148. /*
  149.  * Need to check Darwin release at runtime in tclUnixFCmd.c and tclLoadDyld.c:
  150.  * initialize release global at startup from uname().
  151.  */
  152. #define GET_DARWIN_RELEASE 1
  153. long tclMacOSXDarwinRelease = 0;
  154. #endif
  155. /*
  156.  *---------------------------------------------------------------------------
  157.  *
  158.  * TclpInitPlatform --
  159.  *
  160.  * Initialize all the platform-dependant things like signals and
  161.  * floating-point error handling.
  162.  *
  163.  * Called at process initialization time.
  164.  *
  165.  * Results:
  166.  * None.
  167.  *
  168.  * Side effects:
  169.  * None.
  170.  *
  171.  *---------------------------------------------------------------------------
  172.  */
  173. void
  174. TclpInitPlatform()
  175. {
  176.     tclPlatform = TCL_PLATFORM_UNIX;
  177.     /*
  178.      * Make sure, that the standard FDs exist. [Bug 772288]
  179.      */
  180.     if (TclOSseek(0, (Tcl_SeekOffset) 0, SEEK_CUR) == -1 && errno == EBADF) {
  181. open("/dev/null", O_RDONLY);
  182.     }
  183.     if (TclOSseek(1, (Tcl_SeekOffset) 0, SEEK_CUR) == -1 && errno == EBADF) {
  184. open("/dev/null", O_WRONLY);
  185.     }
  186.     if (TclOSseek(2, (Tcl_SeekOffset) 0, SEEK_CUR) == -1 && errno == EBADF) {
  187. open("/dev/null", O_WRONLY);
  188.     }
  189.     /*
  190.      * The code below causes SIGPIPE (broken pipe) errors to
  191.      * be ignored.  This is needed so that Tcl processes don't
  192.      * die if they create child processes (e.g. using "exec" or
  193.      * "open") that terminate prematurely.  The signal handler
  194.      * is only set up when the first interpreter is created;
  195.      * after this the application can override the handler with
  196.      * a different one of its own, if it wants.
  197.      */
  198. #ifdef SIGPIPE
  199.     (void) signal(SIGPIPE, SIG_IGN);
  200. #endif /* SIGPIPE */
  201. #if defined(__FreeBSD__) && defined(__GNUC__)
  202.     /*
  203.      * Adjust the rounding mode to be more conventional. Note that FreeBSD
  204.      * only provides the __fpsetreg() used by the following two for the GNU
  205.      * Compiler. When using, say, Intel's icc they break. (Partially based on
  206.      * patch in BSD ports system from root@celsius.bychok.com)
  207.      */
  208.     fpsetround(FP_RN);
  209.     fpsetmask(0L);
  210. #endif
  211. #if defined(__bsdi__) && (_BSDI_VERSION > 199501)
  212.     /*
  213.      * Find local symbols. Don't report an error if we fail.
  214.      */
  215.     (void) dlopen (NULL, RTLD_NOW); /* INTL: Native. */
  216. #endif
  217. #ifdef GET_DARWIN_RELEASE
  218.     {
  219. struct utsname name;
  220. if (!uname(&name)) {
  221.     tclMacOSXDarwinRelease = strtol(name.release, NULL, 10);
  222. }
  223.     }
  224. #endif
  225. }
  226. /*
  227.  *---------------------------------------------------------------------------
  228.  *
  229.  * TclpInitLibraryPath --
  230.  *
  231.  * Initialize the library path at startup.  We have a minor
  232.  * metacircular problem that we don't know the encoding of the
  233.  * operating system but we may need to talk to operating system
  234.  * to find the library directories so that we know how to talk to
  235.  * the operating system.
  236.  *
  237.  * We do not know the encoding of the operating system.
  238.  * We do know that the encoding is some multibyte encoding.
  239.  * In that multibyte encoding, the characters 0..127 are equivalent
  240.  *     to ascii.
  241.  *
  242.  * So although we don't know the encoding, it's safe:
  243.  *     to look for the last slash character in a path in the encoding.
  244.  *     to append an ascii string to a path.
  245.  *     to pass those strings back to the operating system.
  246.  *
  247.  * But any strings that we remembered before we knew the encoding of
  248.  * the operating system must be translated to UTF-8 once we know the
  249.  * encoding so that the rest of Tcl can use those strings.
  250.  *
  251.  * This call sets the library path to strings in the unknown native
  252.  * encoding.  TclpSetInitialEncodings() will translate the library
  253.  * path from the native encoding to UTF-8 as soon as it determines
  254.  * what the native encoding actually is.
  255.  *
  256.  * Called at process initialization time.
  257.  *
  258.  * Results:
  259.  * Return 1, indicating that the UTF may be dirty and require "cleanup"
  260.  * after encodings are initialized.
  261.  *
  262.  * Side effects:
  263.  * None.
  264.  *
  265.  *---------------------------------------------------------------------------
  266.  */
  267. int
  268. TclpInitLibraryPath(path)
  269. CONST char *path; /* Path to the executable in native 
  270.  * multi-byte encoding. */
  271. {
  272. #define LIBRARY_SIZE     32
  273.     Tcl_Obj *pathPtr, *objPtr;
  274.     CONST char *str;
  275.     Tcl_DString buffer, ds;
  276.     int pathc;
  277.     CONST char **pathv;
  278.     char installLib[LIBRARY_SIZE], developLib[LIBRARY_SIZE];
  279.     Tcl_DStringInit(&ds);
  280.     pathPtr = Tcl_NewObj();
  281.     /*
  282.      * Initialize the substrings used when locating an executable.  The
  283.      * installLib variable computes the path as though the executable
  284.      * is installed.  The developLib computes the path as though the
  285.      * executable is run from a develpment directory.
  286.      */
  287.      
  288.     sprintf(installLib, "lib/tcl%s", TCL_VERSION);
  289.     sprintf(developLib, "tcl%s/library", TCL_PATCH_LEVEL);
  290.     /*
  291.      * Look for the library relative to default encoding dir.
  292.      */
  293.     str = Tcl_GetDefaultEncodingDir();
  294.     if ((str != NULL) && (str[0] != '')) {
  295. objPtr = Tcl_NewStringObj(str, -1);
  296. Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
  297.     }
  298.     /*
  299.      * Look for the library relative to the TCL_LIBRARY env variable.
  300.      * If the last dirname in the TCL_LIBRARY path does not match the
  301.      * last dirname in the installLib variable, use the last dir name
  302.      * of installLib in addition to the orginal TCL_LIBRARY path.
  303.      */
  304.     str = getenv("TCL_LIBRARY"); /* INTL: Native. */
  305.     Tcl_ExternalToUtfDString(NULL, str, -1, &buffer);
  306.     str = Tcl_DStringValue(&buffer);
  307.     if ((str != NULL) && (str[0] != '')) {
  308. /*
  309.  * If TCL_LIBRARY is set, search there.
  310.  */
  311.  
  312. objPtr = Tcl_NewStringObj(str, -1);
  313. Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
  314. Tcl_SplitPath(str, &pathc, &pathv);
  315. if ((pathc > 0) && (strcasecmp(installLib + 4, pathv[pathc-1]) != 0)) {
  316.     /*
  317.      * If TCL_LIBRARY is set but refers to a different tcl
  318.      * installation than the current version, try fiddling with the
  319.      * specified directory to make it refer to this installation by
  320.      * removing the old "tclX.Y" and substituting the current
  321.      * version string.
  322.      */
  323.     
  324.     pathv[pathc - 1] = installLib + 4;
  325.     str = Tcl_JoinPath(pathc, pathv, &ds);
  326.     objPtr = Tcl_NewStringObj(str, Tcl_DStringLength(&ds));
  327.     Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
  328.     Tcl_DStringFree(&ds);
  329. }
  330. ckfree((char *) pathv);
  331.     }
  332.     /*
  333.      * Look for the library relative to the executable.  This algorithm
  334.      * should be the same as the one in the tcl_findLibrary procedure.
  335.      *
  336.      * This code looks in the following directories:
  337.      *
  338.      * <bindir>/../<installLib>
  339.      *   (e.g. /usr/local/bin/../lib/tcl8.4)
  340.      * <bindir>/../../<installLib>
  341.      *   (e.g. /usr/local/TclPro/solaris-sparc/bin/../../lib/tcl8.4)
  342.      * <bindir>/../library
  343.      *   (e.g. /usr/src/tcl8.4.0/unix/../library)
  344.      * <bindir>/../../library
  345.      *   (e.g. /usr/src/tcl8.4.0/unix/solaris-sparc/../../library)
  346.      * <bindir>/../../<developLib>
  347.      *   (e.g. /usr/src/tcl8.4.0/unix/../../tcl8.4.0/library)
  348.      * <bindir>/../../../<developLib>
  349.      *   (e.g. /usr/src/tcl8.4.0/unix/solaris-sparc/../../../tcl8.4.0/library)
  350.      */
  351.      
  352.      /*
  353.       * The variable path holds an absolute path.  Take care not to
  354.       * overwrite pathv[0] since that might produce a relative path.
  355.       */
  356.     if (path != NULL) {
  357. int i, origc;
  358. CONST char **origv;
  359. Tcl_SplitPath(path, &origc, &origv);
  360. pathc = 0;
  361. pathv = (CONST char **) ckalloc((unsigned int)(origc * sizeof(char *)));
  362. for (i=0; i< origc; i++) {
  363.     if (origv[i][0] == '.') {
  364. if (strcmp(origv[i], ".") == 0) {
  365.     /* do nothing */
  366. } else if (strcmp(origv[i], "..") == 0) {
  367.     pathc--;
  368. } else {
  369.     pathv[pathc++] = origv[i];
  370. }
  371.     } else {
  372. pathv[pathc++] = origv[i];
  373.     }
  374. }
  375. if (pathc > 2) {
  376.     str = pathv[pathc - 2];
  377.     pathv[pathc - 2] = installLib;
  378.     path = Tcl_JoinPath(pathc - 1, pathv, &ds);
  379.     pathv[pathc - 2] = str;
  380.     objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
  381.     Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
  382.     Tcl_DStringFree(&ds);
  383. }
  384. if (pathc > 3) {
  385.     str = pathv[pathc - 3];
  386.     pathv[pathc - 3] = installLib;
  387.     path = Tcl_JoinPath(pathc - 2, pathv, &ds);
  388.     pathv[pathc - 3] = str;
  389.     objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
  390.     Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
  391.     Tcl_DStringFree(&ds);
  392. }
  393. if (pathc > 2) {
  394.     str = pathv[pathc - 2];
  395.     pathv[pathc - 2] = "library";
  396.     path = Tcl_JoinPath(pathc - 1, pathv, &ds);
  397.     pathv[pathc - 2] = str;
  398.     objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
  399.     Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
  400.     Tcl_DStringFree(&ds);
  401. }
  402. if (pathc > 3) {
  403.     str = pathv[pathc - 3];
  404.     pathv[pathc - 3] = "library";
  405.     path = Tcl_JoinPath(pathc - 2, pathv, &ds);
  406.     pathv[pathc - 3] = str;
  407.     objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
  408.     Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
  409.     Tcl_DStringFree(&ds);
  410. }
  411. if (pathc > 3) {
  412.     str = pathv[pathc - 3];
  413.     pathv[pathc - 3] = developLib;
  414.     path = Tcl_JoinPath(pathc - 2, pathv, &ds);
  415.     pathv[pathc - 3] = str;
  416.     objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
  417.     Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
  418.     Tcl_DStringFree(&ds);
  419. }
  420. if (pathc > 4) {
  421.     str = pathv[pathc - 4];
  422.     pathv[pathc - 4] = developLib;
  423.     path = Tcl_JoinPath(pathc - 3, pathv, &ds);
  424.     pathv[pathc - 4] = str;
  425.     objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
  426.     Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
  427.     Tcl_DStringFree(&ds);
  428. }
  429. ckfree((char *) origv);
  430. ckfree((char *) pathv);
  431.     }
  432.     /*
  433.      * Finally, look for the library relative to the compiled-in path.
  434.      * This is needed when users install Tcl with an exec-prefix that
  435.      * is different from the prtefix.
  436.      */
  437.     {
  438. #ifdef HAVE_COREFOUNDATION
  439.     char tclLibPath[MAXPATHLEN + 1];
  440.     if (MacOSXGetLibraryPath(NULL, MAXPATHLEN, tclLibPath) == TCL_OK) {
  441.         str = tclLibPath;
  442.     } else
  443. #endif /* HAVE_COREFOUNDATION */
  444.     {
  445.         str = defaultLibraryDir;
  446.     }
  447.     if (str[0] != '') {
  448.         objPtr = Tcl_NewStringObj(str, -1);
  449.         Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
  450.     }
  451.     }
  452.     TclSetLibraryPath(pathPtr);    
  453.     Tcl_DStringFree(&buffer);
  454.     return 1; /* 1 indicates that pathPtr may be dirty utf (needs cleaning) */
  455. }
  456. /*
  457.  *---------------------------------------------------------------------------
  458.  *
  459.  * TclpSetInitialEncodings --
  460.  *
  461.  * Based on the locale, determine the encoding of the operating
  462.  * system and the default encoding for newly opened files.
  463.  *
  464.  * Called at process initialization time, and part way through
  465.  * startup, we verify that the initial encodings were correctly
  466.  * setup.  Depending on Tcl's environment, there may not have been
  467.  * enough information first time through (above).
  468.  *
  469.  * Results:
  470.  * None.
  471.  *
  472.  * Side effects:
  473.  * The Tcl library path is converted from native encoding to UTF-8,
  474.  * on the first call, and the encodings may be changed on first or
  475.  * second call.
  476.  *
  477.  *---------------------------------------------------------------------------
  478.  */
  479. void
  480. TclpSetInitialEncodings()
  481. {
  482. CONST char *encoding = NULL;
  483. int i, setSysEncCode = TCL_ERROR;
  484. Tcl_Obj *pathPtr;
  485. /*
  486.  * Determine the current encoding from the LC_* or LANG environment
  487.  * variables.  We previously used setlocale() to determine the locale,
  488.  * but this does not work on some systems (e.g. Linux/i386 RH 5.0).
  489.  */
  490. #ifdef HAVE_LANGINFO
  491. if (
  492. #ifdef WEAK_IMPORT_NL_LANGINFO
  493. nl_langinfo != NULL &&
  494. #endif
  495. setlocale(LC_CTYPE, "") != NULL) {
  496.     Tcl_DString ds;
  497.     /*
  498.      * Use a DString so we can overwrite it in name compatability
  499.      * checks below.
  500.      */
  501.     Tcl_DStringInit(&ds);
  502.     encoding = Tcl_DStringAppend(&ds, nl_langinfo(CODESET), -1);
  503.     Tcl_UtfToLower(Tcl_DStringValue(&ds));
  504. #ifdef HAVE_LANGINFO_DEBUG
  505.     fprintf(stderr, "encoding '%s'", encoding);
  506. #endif
  507.     if (encoding[0] == 'i' && encoding[1] == 's' && encoding[2] == 'o'
  508.     && encoding[3] == '-') {
  509. char *p, *q;
  510. /* need to strip '-' from iso-* encoding */
  511. for(p = Tcl_DStringValue(&ds)+3, q = Tcl_DStringValue(&ds)+4;
  512.     *p; *p++ = *q++);
  513.     } else if (encoding[0] == 'i' && encoding[1] == 'b'
  514.     && encoding[2] == 'm' && encoding[3] >= '0'
  515.     && encoding[3] <= '9') {
  516. char *p, *q;
  517. /* if langinfo reports "ibm*" we should use "cp*" */
  518. p = Tcl_DStringValue(&ds);
  519. *p++ = 'c'; *p++ = 'p';
  520. for(q = p+1; *p ; *p++ = *q++);
  521.     } else if ((*encoding == '')
  522.     || !strcmp(encoding, "ansi_x3.4-1968")) {
  523. /* Use iso8859-1 for empty or 'ansi_x3.4-1968' encoding */
  524. encoding = "iso8859-1";
  525.     }
  526. #ifdef HAVE_LANGINFO_DEBUG
  527.     fprintf(stderr, " ?%s?", encoding);
  528. #endif
  529.     setSysEncCode = Tcl_SetSystemEncoding(NULL, encoding);
  530.     if (setSysEncCode != TCL_OK) {
  531. /*
  532.  * If this doesn't return TCL_OK, the encoding returned by
  533.  * nl_langinfo or as we translated it wasn't accepted.  Do
  534.  * this fallback check.  If this fails, we will enter the
  535.  * old fallback below.
  536.  */
  537. for (i = 0; localeTable[i].lang != NULL; i++) {
  538.     if (strcmp(localeTable[i].lang, encoding) == 0) {
  539. setSysEncCode = Tcl_SetSystemEncoding(NULL,
  540. localeTable[i].encoding);
  541. break;
  542.     }
  543. }
  544.     }
  545. #ifdef HAVE_LANGINFO_DEBUG
  546.     fprintf(stderr, " => '%s'n", encoding);
  547. #endif
  548.     Tcl_DStringFree(&ds);
  549. }
  550. #ifdef HAVE_LANGINFO_DEBUG
  551. else {
  552.     fprintf(stderr, "setlocale returned NULLn");
  553. }
  554. #endif
  555. #endif /* HAVE_LANGINFO */
  556. if (setSysEncCode != TCL_OK) {
  557.     /*
  558.      * Classic fallback check.  This tries a homebrew algorithm to
  559.      * determine what encoding should be used based on env vars.
  560.      */
  561.     char *langEnv = getenv("LC_ALL");
  562.     encoding = NULL;
  563.     if (langEnv == NULL || langEnv[0] == '') {
  564. langEnv = getenv("LC_CTYPE");
  565.     }
  566.     if (langEnv == NULL || langEnv[0] == '') {
  567. langEnv = getenv("LANG");
  568.     }
  569.     if (langEnv == NULL || langEnv[0] == '') {
  570. langEnv = NULL;
  571.     }
  572.     if (langEnv != NULL) {
  573. for (i = 0; localeTable[i].lang != NULL; i++) {
  574.     if (strcmp(localeTable[i].lang, langEnv) == 0) {
  575. encoding = localeTable[i].encoding;
  576. break;
  577.     }
  578. }
  579. /*
  580.  * There was no mapping in the locale table.  If there is an
  581.  * encoding subfield, we can try to guess from that.
  582.  */
  583. if (encoding == NULL) {
  584.     char *p;
  585.     for (p = langEnv; *p != ''; p++) {
  586. if (*p == '.') {
  587.     p++;
  588.     break;
  589. }
  590.     }
  591.     if (*p != '') {
  592. Tcl_DString ds;
  593. Tcl_DStringInit(&ds);
  594. encoding = Tcl_DStringAppend(&ds, p, -1);
  595. Tcl_UtfToLower(Tcl_DStringValue(&ds));
  596. setSysEncCode = Tcl_SetSystemEncoding(NULL, encoding);
  597. if (setSysEncCode != TCL_OK) {
  598.     encoding = NULL;
  599. }
  600. Tcl_DStringFree(&ds);
  601.     }
  602. }
  603. #ifdef HAVE_LANGINFO_DEBUG
  604. fprintf(stderr, "encoding fallback check '%s' => '%s'n",
  605. langEnv, encoding);
  606. #endif
  607.     }
  608.     if (setSysEncCode != TCL_OK) {
  609. if (encoding == NULL) {
  610.     encoding = TCL_DEFAULT_ENCODING;
  611. }
  612. Tcl_SetSystemEncoding(NULL, encoding);
  613.     }
  614.     /*
  615.      * Initialize the C library's locale subsystem.  This is required
  616.      * for input methods to work properly on X11.  We only do this for
  617.      * LC_CTYPE because that's the necessary one, and we don't want to
  618.      * affect LC_TIME here.  The side effect of setting the default
  619.      * locale should be to load any locale specific modules that are
  620.      * needed by X.  [BUG: 5422 3345 4236 2522 2521].
  621.      * In HAVE_LANGINFO, this call is already done above.
  622.      */
  623. #ifndef HAVE_LANGINFO
  624.     setlocale(LC_CTYPE, "");
  625. #endif
  626. }
  627. /*
  628.  * In case the initial locale is not "C", ensure that the numeric
  629.  * processing is done in "C" locale regardless.  This is needed because
  630.  * Tcl relies on routines like strtod, but should not have locale
  631.  * dependent behavior.
  632.  */
  633. setlocale(LC_NUMERIC, "C");
  634.     if ((libraryPathEncodingFixed == 0) && strcmp("identity",
  635.     Tcl_GetEncodingName(Tcl_GetEncoding(NULL, NULL))) ) {
  636. /*
  637.  * Until the system encoding was actually set, the library path was
  638.  * actually in the native multi-byte encoding, and not really UTF-8
  639.  * as advertised.  We cheated as follows:
  640.  *
  641.  * 1. It was safe to allow the Tcl_SetSystemEncoding() call to 
  642.  * append the ASCII chars that make up the encoding's filename to 
  643.  * the names (in the native encoding) of directories in the library 
  644.  * path, since all Unix multi-byte encodings have ASCII in the
  645.  * beginning.
  646.  *
  647.  * 2. To open the encoding file, the native bytes in the file name
  648.  * were passed to the OS, without translating from UTF-8 to native,
  649.  * because the name was already in the native encoding.
  650.  *
  651.  * Now that the system encoding was actually successfully set,
  652.  * translate all the names in the library path to UTF-8.  That way,
  653.  * next time we search the library path, we'll translate the names 
  654.  * from UTF-8 to the system encoding which will be the native 
  655.  * encoding.
  656.  */
  657. pathPtr = TclGetLibraryPath();
  658. if (pathPtr != NULL) {
  659.     int objc;
  660.     Tcl_Obj **objv;
  661.     
  662.     objc = 0;
  663.     Tcl_ListObjGetElements(NULL, pathPtr, &objc, &objv);
  664.     for (i = 0; i < objc; i++) {
  665. int length;
  666. char *string;
  667. Tcl_DString ds;
  668. string = Tcl_GetStringFromObj(objv[i], &length);
  669. Tcl_ExternalToUtfDString(NULL, string, length, &ds);
  670. Tcl_SetStringObj(objv[i], Tcl_DStringValue(&ds), 
  671. Tcl_DStringLength(&ds));
  672. Tcl_DStringFree(&ds);
  673.     }
  674. }
  675. libraryPathEncodingFixed = 1;
  676.     }
  677.     
  678.     /* This is only ever called from the startup thread */
  679.     if (binaryEncoding == NULL) {
  680. /*
  681.  * Keep the iso8859-1 encoding preloaded.  The IO package uses
  682.  * it for gets on a binary channel.
  683.  */
  684. binaryEncoding = Tcl_GetEncoding(NULL, "iso8859-1");
  685.     }
  686. }
  687. /*
  688.  *---------------------------------------------------------------------------
  689.  *
  690.  * TclpSetVariables --
  691.  *
  692.  * Performs platform-specific interpreter initialization related to
  693.  * the tcl_library and tcl_platform variables, and other platform-
  694.  * specific things.
  695.  *
  696.  * Results:
  697.  * None.
  698.  *
  699.  * Side effects:
  700.  * Sets "tclDefaultLibrary", "tcl_pkgPath", and "tcl_platform" Tcl
  701.  * variables.
  702.  *
  703.  *----------------------------------------------------------------------
  704.  */
  705. void
  706. TclpSetVariables(interp)
  707.     Tcl_Interp *interp;
  708. {
  709. #ifndef NO_UNAME
  710.     struct utsname name;
  711. #endif
  712.     int unameOK;
  713.     CONST char *user;
  714.     Tcl_DString ds;
  715. #ifdef HAVE_COREFOUNDATION
  716.     char tclLibPath[MAXPATHLEN + 1];
  717. #if MAC_OS_X_VERSION_MAX_ALLOWED > 1020
  718.     /*
  719.      * Set msgcat fallback locale to current CFLocale identifier.
  720.      */
  721.     CFLocaleRef localeRef;
  722.     
  723.     if (CFLocaleCopyCurrent != NULL && CFLocaleGetIdentifier != NULL &&
  724.     (localeRef = CFLocaleCopyCurrent())) {
  725. CFStringRef locale = CFLocaleGetIdentifier(localeRef);
  726. if (locale) {
  727.     char loc[256];
  728.     if (CFStringGetCString(locale, loc, 256, kCFStringEncodingUTF8)) {
  729. if (!Tcl_CreateNamespace(interp, "::tcl::mac", NULL, NULL)) {
  730.     Tcl_ResetResult(interp);
  731. }
  732. Tcl_SetVar(interp, "::tcl::mac::locale", loc, TCL_GLOBAL_ONLY);
  733.     }
  734. }
  735. CFRelease(localeRef);
  736.     }
  737. #endif
  738.     if (MacOSXGetLibraryPath(interp, MAXPATHLEN, tclLibPath) == TCL_OK) {
  739.         CONST char *str;
  740.         Tcl_DString ds;
  741.         CFBundleRef bundleRef;
  742.         Tcl_SetVar(interp, "tclDefaultLibrary", tclLibPath, 
  743.                 TCL_GLOBAL_ONLY);
  744.         Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath,
  745.                 TCL_GLOBAL_ONLY);
  746.         Tcl_SetVar(interp, "tcl_pkgPath", " ",
  747.                 TCL_GLOBAL_ONLY | TCL_APPEND_VALUE);
  748.         str = TclGetEnv("DYLD_FRAMEWORK_PATH", &ds);
  749.         if ((str != NULL) && (str[0] != '')) {
  750.             char *p = Tcl_DStringValue(&ds);
  751.             /* convert DYLD_FRAMEWORK_PATH from colon to space separated */
  752.             do {
  753.                 if(*p == ':') *p = ' ';
  754.             } while (*p++);
  755.             Tcl_SetVar(interp, "tcl_pkgPath", Tcl_DStringValue(&ds),
  756.                     TCL_GLOBAL_ONLY | TCL_APPEND_VALUE);
  757.             Tcl_SetVar(interp, "tcl_pkgPath", " ",
  758.                     TCL_GLOBAL_ONLY | TCL_APPEND_VALUE);
  759.             Tcl_DStringFree(&ds);
  760.         }
  761.         if ((bundleRef = CFBundleGetMainBundle())) {
  762.             CFURLRef frameworksURL;
  763.             Tcl_StatBuf statBuf;
  764.             if((frameworksURL = CFBundleCopyPrivateFrameworksURL(bundleRef))) {
  765.                 if(CFURLGetFileSystemRepresentation(frameworksURL, TRUE,
  766.                             (unsigned char*) tclLibPath, MAXPATHLEN) &&
  767.                         ! TclOSstat(tclLibPath, &statBuf) &&
  768.                         S_ISDIR(statBuf.st_mode)) {
  769.                     Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath,
  770.                             TCL_GLOBAL_ONLY | TCL_APPEND_VALUE);
  771.                     Tcl_SetVar(interp, "tcl_pkgPath", " ",
  772.                             TCL_GLOBAL_ONLY | TCL_APPEND_VALUE);
  773.                 }
  774.                 CFRelease(frameworksURL);
  775.             }
  776.             if((frameworksURL = CFBundleCopySharedFrameworksURL(bundleRef))) {
  777.                 if(CFURLGetFileSystemRepresentation(frameworksURL, TRUE,
  778.                             (unsigned char*) tclLibPath, MAXPATHLEN) &&
  779.                         ! TclOSstat(tclLibPath, &statBuf) &&
  780.                         S_ISDIR(statBuf.st_mode)) {
  781.                     Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath,
  782.                             TCL_GLOBAL_ONLY | TCL_APPEND_VALUE);
  783.                     Tcl_SetVar(interp, "tcl_pkgPath", " ",
  784.                             TCL_GLOBAL_ONLY | TCL_APPEND_VALUE);
  785.                 }
  786.                 CFRelease(frameworksURL);
  787.             }
  788.         }
  789.         Tcl_SetVar(interp, "tcl_pkgPath", pkgPath,
  790.                 TCL_GLOBAL_ONLY | TCL_APPEND_VALUE);
  791.     } else
  792. #endif /* HAVE_COREFOUNDATION */
  793.     {
  794.         Tcl_SetVar(interp, "tclDefaultLibrary", defaultLibraryDir, 
  795.                 TCL_GLOBAL_ONLY);
  796.         Tcl_SetVar(interp, "tcl_pkgPath", pkgPath, TCL_GLOBAL_ONLY);
  797.     }
  798. #ifdef DJGPP
  799.     Tcl_SetVar2(interp, "tcl_platform", "platform", "dos", TCL_GLOBAL_ONLY);
  800. #else
  801.     Tcl_SetVar2(interp, "tcl_platform", "platform", "unix", TCL_GLOBAL_ONLY);
  802. #endif
  803.     unameOK = 0;
  804. #ifndef NO_UNAME
  805.     if (uname(&name) >= 0) {
  806. CONST char *native;
  807. unameOK = 1;
  808. native = Tcl_ExternalToUtfDString(NULL, name.sysname, -1, &ds);
  809. Tcl_SetVar2(interp, "tcl_platform", "os", native, TCL_GLOBAL_ONLY);
  810. Tcl_DStringFree(&ds);
  811. /*
  812.  * The following code is a special hack to handle differences in
  813.  * the way version information is returned by uname.  On most
  814.  * systems the full version number is available in name.release.
  815.  * However, under AIX the major version number is in
  816.  * name.version and the minor version number is in name.release.
  817.  */
  818. if ((strchr(name.release, '.') != NULL)
  819. || !isdigit(UCHAR(name.version[0]))) { /* INTL: digit */
  820.     Tcl_SetVar2(interp, "tcl_platform", "osVersion", name.release,
  821.     TCL_GLOBAL_ONLY);
  822. } else {
  823.     Tcl_SetVar2(interp, "tcl_platform", "osVersion", name.version,
  824.     TCL_GLOBAL_ONLY);
  825.     Tcl_SetVar2(interp, "tcl_platform", "osVersion", ".",
  826.     TCL_GLOBAL_ONLY|TCL_APPEND_VALUE);
  827.     Tcl_SetVar2(interp, "tcl_platform", "osVersion", name.release,
  828.     TCL_GLOBAL_ONLY|TCL_APPEND_VALUE);
  829. }
  830. Tcl_SetVar2(interp, "tcl_platform", "machine", name.machine,
  831. TCL_GLOBAL_ONLY);
  832.     }
  833. #endif
  834.     if (!unameOK) {
  835. Tcl_SetVar2(interp, "tcl_platform", "os", "", TCL_GLOBAL_ONLY);
  836. Tcl_SetVar2(interp, "tcl_platform", "osVersion", "", TCL_GLOBAL_ONLY);
  837. Tcl_SetVar2(interp, "tcl_platform", "machine", "", TCL_GLOBAL_ONLY);
  838.     }
  839.     /*
  840.      * Copy USER or LOGNAME environment variable into tcl_platform(user)
  841.      */
  842.     Tcl_DStringInit(&ds);
  843.     user = TclGetEnv("USER", &ds);
  844.     if (user == NULL) {
  845. user = TclGetEnv("LOGNAME", &ds);
  846. if (user == NULL) {
  847.     user = "";
  848. }
  849.     }
  850.     Tcl_SetVar2(interp, "tcl_platform", "user", user, TCL_GLOBAL_ONLY);
  851.     Tcl_DStringFree(&ds);
  852. }
  853. /*
  854.  *----------------------------------------------------------------------
  855.  *
  856.  * TclpFindVariable --
  857.  *
  858.  * Locate the entry in environ for a given name.  On Unix this 
  859.  * routine is case sensetive, on Windows this matches mixed case.
  860.  *
  861.  * Results:
  862.  * The return value is the index in environ of an entry with the
  863.  * name "name", or -1 if there is no such entry.   The integer at
  864.  * *lengthPtr is filled in with the length of name (if a matching
  865.  * entry is found) or the length of the environ array (if no matching
  866.  * entry is found).
  867.  *
  868.  * Side effects:
  869.  * None.
  870.  *
  871.  *----------------------------------------------------------------------
  872.  */
  873. int
  874. TclpFindVariable(name, lengthPtr)
  875.     CONST char *name; /* Name of desired environment variable
  876.  * (native). */
  877.     int *lengthPtr; /* Used to return length of name (for
  878.  * successful searches) or number of non-NULL
  879.  * entries in environ (for unsuccessful
  880.  * searches). */
  881. {
  882.     int i, result = -1;
  883.     register CONST char *env, *p1, *p2;
  884.     Tcl_DString envString;
  885.     Tcl_DStringInit(&envString);
  886.     for (i = 0, env = environ[i]; env != NULL; i++, env = environ[i]) {
  887. p1 = Tcl_ExternalToUtfDString(NULL, env, -1, &envString);
  888. p2 = name;
  889. for (; *p2 == *p1; p1++, p2++) {
  890.     /* NULL loop body. */
  891. }
  892. if ((*p1 == '=') && (*p2 == '')) {
  893.     *lengthPtr = p2 - name;
  894.     result = i;
  895.     goto done;
  896. }
  897. Tcl_DStringFree(&envString);
  898.     }
  899.     
  900.     *lengthPtr = i;
  901.     done:
  902.     Tcl_DStringFree(&envString);
  903.     return result;
  904. }
  905. /*
  906.  *----------------------------------------------------------------------
  907.  *
  908.  * Tcl_Init --
  909.  *
  910.  * This procedure is typically invoked by Tcl_AppInit procedures
  911.  * to find and source the "init.tcl" script, which should exist
  912.  * somewhere on the Tcl library path.
  913.  *
  914.  * Results:
  915.  * Returns a standard Tcl completion code and sets the interp's
  916.  * result if there is an error.
  917.  *
  918.  * Side effects:
  919.  * Depends on what's in the init.tcl script.
  920.  *
  921.  *----------------------------------------------------------------------
  922.  */
  923. int
  924. Tcl_Init(interp)
  925.     Tcl_Interp *interp; /* Interpreter to initialize. */
  926. {
  927.     Tcl_Obj *pathPtr;
  928.     if (tclPreInitScript != NULL) {
  929. if (Tcl_Eval(interp, tclPreInitScript) == TCL_ERROR) {
  930.     return (TCL_ERROR);
  931. };
  932.     }
  933.     
  934.     pathPtr = TclGetLibraryPath();
  935.     if (pathPtr == NULL) {
  936. pathPtr = Tcl_NewObj();
  937.     }
  938.     Tcl_IncrRefCount(pathPtr);
  939.     Tcl_SetVar2Ex(interp, "tcl_libPath", NULL, pathPtr, TCL_GLOBAL_ONLY);
  940.     Tcl_DecrRefCount(pathPtr);
  941.     return Tcl_Eval(interp, initScript);
  942. }
  943. /*
  944.  *----------------------------------------------------------------------
  945.  *
  946.  * Tcl_SourceRCFile --
  947.  *
  948.  * This procedure is typically invoked by Tcl_Main of Tk_Main
  949.  * procedure to source an application specific rc file into the
  950.  * interpreter at startup time.
  951.  *
  952.  * Results:
  953.  * None.
  954.  *
  955.  * Side effects:
  956.  * Depends on what's in the rc script.
  957.  *
  958.  *----------------------------------------------------------------------
  959.  */
  960. void
  961. Tcl_SourceRCFile(interp)
  962.     Tcl_Interp *interp; /* Interpreter to source rc file into. */
  963. {
  964.     Tcl_DString temp;
  965.     CONST char *fileName;
  966.     Tcl_Channel errChannel;
  967.     fileName = Tcl_GetVar(interp, "tcl_rcFileName", TCL_GLOBAL_ONLY);
  968.     if (fileName != NULL) {
  969.         Tcl_Channel c;
  970. CONST char *fullName;
  971.         Tcl_DStringInit(&temp);
  972. fullName = Tcl_TranslateFileName(interp, fileName, &temp);
  973. if (fullName == NULL) {
  974.     /*
  975.      * Couldn't translate the file name (e.g. it referred to a
  976.      * bogus user or there was no HOME environment variable).
  977.      * Just do nothing.
  978.      */
  979. } else {
  980.     /*
  981.      * Test for the existence of the rc file before trying to read it.
  982.      */
  983.             c = Tcl_OpenFileChannel(NULL, fullName, "r", 0);
  984.             if (c != (Tcl_Channel) NULL) {
  985.                 Tcl_Close(NULL, c);
  986. if (Tcl_EvalFile(interp, fullName) != TCL_OK) {
  987.     errChannel = Tcl_GetStdChannel(TCL_STDERR);
  988.     if (errChannel) {
  989. Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
  990. Tcl_WriteChars(errChannel, "n", 1);
  991.     }
  992. }
  993.     }
  994. }
  995.         Tcl_DStringFree(&temp);
  996.     }
  997. }
  998. /*
  999.  *----------------------------------------------------------------------
  1000.  *
  1001.  * TclpCheckStackSpace --
  1002.  *
  1003.  * Detect if we are about to blow the stack.  Called before an 
  1004.  * evaluation can happen when nesting depth is checked.
  1005.  *
  1006.  * Results:
  1007.  * 1 if there is enough stack space to continue; 0 if not.
  1008.  *
  1009.  * Side effects:
  1010.  * None.
  1011.  *
  1012.  *----------------------------------------------------------------------
  1013.  */
  1014. int
  1015. TclpCheckStackSpace()
  1016. {
  1017.     /*
  1018.      * This function is unimplemented on Unix platforms.
  1019.      */
  1020.     return 1;
  1021. }
  1022. /*
  1023.  *----------------------------------------------------------------------
  1024.  *
  1025.  * MacOSXGetLibraryPath --
  1026.  *
  1027.  * If we have a bundle structure for the Tcl installation,
  1028.  * then check there first to see if we can find the libraries
  1029.  * there.
  1030.  *
  1031.  * Results:
  1032.  * TCL_OK if we have found the tcl library; TCL_ERROR otherwise.
  1033.  *
  1034.  * Side effects:
  1035.  * Same as for Tcl_MacOSXOpenVersionedBundleResources.
  1036.  *
  1037.  *----------------------------------------------------------------------
  1038.  */
  1039. #ifdef HAVE_COREFOUNDATION
  1040. static int
  1041. MacOSXGetLibraryPath(Tcl_Interp *interp, int maxPathLen, char *tclLibPath)
  1042. {
  1043.     int foundInFramework = TCL_ERROR;
  1044. #ifdef TCL_FRAMEWORK
  1045.     foundInFramework = Tcl_MacOSXOpenVersionedBundleResources(interp, 
  1046. "com.tcltk.tcllibrary", TCL_FRAMEWORK_VERSION, 0, maxPathLen, tclLibPath);
  1047. #endif
  1048.     return foundInFramework;
  1049. }
  1050. #endif /* HAVE_COREFOUNDATION */