tclUnixInit.cGo to the documentation of this file.00001 /* 00002 * tclUnixInit.c -- 00003 * 00004 * Contains the Unix-specific interpreter initialization functions. 00005 * 00006 * Copyright (c) 1995-1997 Sun Microsystems, Inc. 00007 * Copyright (c) 1999 by Scriptics Corporation. 00008 * All rights reserved. 00009 * 00010 * RCS: @(#) $Id: tclUnixInit.c,v 1.82 2007/12/13 15:28:42 dgp Exp $ 00011 */ 00012 00013 #include "tclInt.h" 00014 #include <stddef.h> 00015 #include <locale.h> 00016 #ifdef HAVE_LANGINFO 00017 # include <langinfo.h> 00018 # ifdef __APPLE__ 00019 # if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1030 00020 /* Support for weakly importing nl_langinfo on Darwin. */ 00021 # define WEAK_IMPORT_NL_LANGINFO 00022 extern char *nl_langinfo(nl_item) WEAK_IMPORT_ATTRIBUTE; 00023 # endif 00024 # endif 00025 #endif 00026 #include <sys/resource.h> 00027 #if defined(__FreeBSD__) && defined(__GNUC__) 00028 # include <floatingpoint.h> 00029 #endif 00030 #if defined(__bsdi__) 00031 # include <sys/param.h> 00032 # if _BSDI_VERSION > 199501 00033 # include <dlfcn.h> 00034 # endif 00035 #endif 00036 #ifdef HAVE_COREFOUNDATION 00037 #include <CoreFoundation/CoreFoundation.h> 00038 #endif 00039 00040 /* 00041 * Define TCL_NO_STACK_CHECK in the compiler options if you want to revert to 00042 * the old behavior of never checking the stack. 00043 */ 00044 00045 /* 00046 * Define this if you want to see a lot of output regarding stack checking. 00047 */ 00048 00049 #undef TCL_DEBUG_STACK_CHECK 00050 00051 /* 00052 * Values used to compute how much space is really available for Tcl's use for 00053 * the stack. 00054 * 00055 * The getrlimit() function is documented to return the maximum stack size in 00056 * bytes. However, with threads enabled, the pthread library on some platforms 00057 * does bad things to the stack size limits. First, the limits cannot be 00058 * changed. Second, they appear to be sometimes reported incorrectly. 00059 * 00060 * The defines below may need to be adjusted if more platforms have this 00061 * broken behavior with threads enabled. 00062 */ 00063 00064 #ifndef TCL_MAGIC_STACK_DIVISOR 00065 #define TCL_MAGIC_STACK_DIVISOR 1 00066 #endif 00067 #ifndef TCL_RESERVED_STACK_PAGES 00068 #define TCL_RESERVED_STACK_PAGES 8 00069 #endif 00070 00071 /* 00072 * Thread specific data for stack checking. 00073 */ 00074 00075 #ifndef TCL_NO_STACK_CHECK 00076 typedef struct ThreadSpecificData { 00077 int *outerVarPtr; /* The "outermost" stack frame pointer for 00078 * this thread. */ 00079 int *stackBound; /* The current stack boundary */ 00080 } ThreadSpecificData; 00081 static Tcl_ThreadDataKey dataKey; 00082 #ifdef TCL_CROSS_COMPILE 00083 static int stackGrowsDown = -1; 00084 static int StackGrowsDown(int *parent); 00085 #elif defined(TCL_STACK_GROWS_UP) 00086 #define stackGrowsDown 0 00087 #else 00088 #define stackGrowsDown 1 00089 #endif 00090 #endif /* TCL_NO_STACK_CHECK */ 00091 00092 #ifdef TCL_DEBUG_STACK_CHECK 00093 #define STACK_DEBUG(args) printf args 00094 #else 00095 #define STACK_DEBUG(args) (void)0 00096 #endif /* TCL_DEBUG_STACK_CHECK */ 00097 00098 /* 00099 * Tcl tries to use standard and homebrew methods to guess the right encoding 00100 * on the platform. However, there is always a final fallback, and this value 00101 * is it. Make sure it is a real Tcl encoding. 00102 */ 00103 00104 #ifndef TCL_DEFAULT_ENCODING 00105 #define TCL_DEFAULT_ENCODING "iso8859-1" 00106 #endif 00107 00108 /* 00109 * Default directory in which to look for Tcl library scripts. The symbol is 00110 * defined by Makefile. 00111 */ 00112 00113 static char defaultLibraryDir[sizeof(TCL_LIBRARY)+200] = TCL_LIBRARY; 00114 00115 /* 00116 * Directory in which to look for packages (each package is typically 00117 * installed as a subdirectory of this directory). The symbol is defined by 00118 * Makefile. 00119 */ 00120 00121 static char pkgPath[sizeof(TCL_PACKAGE_PATH)+200] = TCL_PACKAGE_PATH; 00122 00123 /* 00124 * The following table is used to map from Unix locale strings to encoding 00125 * files. If HAVE_LANGINFO is defined, then this is a fallback table when the 00126 * result from nl_langinfo isn't a recognized encoding. Otherwise this is the 00127 * first list checked for a mapping from env encoding to Tcl encoding name. 00128 */ 00129 00130 typedef struct LocaleTable { 00131 CONST char *lang; 00132 CONST char *encoding; 00133 } LocaleTable; 00134 00135 /* 00136 * The table below is sorted for the sake of doing binary searches on it. The 00137 * indenting reflects different categories of data. The leftmost data 00138 * represent the encoding names directly implemented by data files in Tcl's 00139 * default encoding directory. Indented by one TAB are the encoding names that 00140 * are common alternative spellings. Indented by two TABs are the accumulated 00141 * "bug fixes" that have been added to deal with the wide variability seen 00142 * among existing platforms. 00143 */ 00144 00145 static CONST LocaleTable localeTable[] = { 00146 {"", "iso8859-1"}, 00147 {"ansi-1251", "cp1251"}, 00148 {"ansi_x3.4-1968", "iso8859-1"}, 00149 {"ascii", "ascii"}, 00150 {"big5", "big5"}, 00151 {"cp1250", "cp1250"}, 00152 {"cp1251", "cp1251"}, 00153 {"cp1252", "cp1252"}, 00154 {"cp1253", "cp1253"}, 00155 {"cp1254", "cp1254"}, 00156 {"cp1255", "cp1255"}, 00157 {"cp1256", "cp1256"}, 00158 {"cp1257", "cp1257"}, 00159 {"cp1258", "cp1258"}, 00160 {"cp437", "cp437"}, 00161 {"cp737", "cp737"}, 00162 {"cp775", "cp775"}, 00163 {"cp850", "cp850"}, 00164 {"cp852", "cp852"}, 00165 {"cp855", "cp855"}, 00166 {"cp857", "cp857"}, 00167 {"cp860", "cp860"}, 00168 {"cp861", "cp861"}, 00169 {"cp862", "cp862"}, 00170 {"cp863", "cp863"}, 00171 {"cp864", "cp864"}, 00172 {"cp865", "cp865"}, 00173 {"cp866", "cp866"}, 00174 {"cp869", "cp869"}, 00175 {"cp874", "cp874"}, 00176 {"cp932", "cp932"}, 00177 {"cp936", "cp936"}, 00178 {"cp949", "cp949"}, 00179 {"cp950", "cp950"}, 00180 {"dingbats", "dingbats"}, 00181 {"ebcdic", "ebcdic"}, 00182 {"euc-cn", "euc-cn"}, 00183 {"euc-jp", "euc-jp"}, 00184 {"euc-kr", "euc-kr"}, 00185 {"eucjp", "euc-jp"}, 00186 {"euckr", "euc-kr"}, 00187 {"euctw", "euc-cn"}, 00188 {"gb12345", "gb12345"}, 00189 {"gb1988", "gb1988"}, 00190 {"gb2312", "gb2312"}, 00191 {"gb2312-1980", "gb2312"}, 00192 {"gb2312-raw", "gb2312-raw"}, 00193 {"greek8", "cp869"}, 00194 {"ibm1250", "cp1250"}, 00195 {"ibm1251", "cp1251"}, 00196 {"ibm1252", "cp1252"}, 00197 {"ibm1253", "cp1253"}, 00198 {"ibm1254", "cp1254"}, 00199 {"ibm1255", "cp1255"}, 00200 {"ibm1256", "cp1256"}, 00201 {"ibm1257", "cp1257"}, 00202 {"ibm1258", "cp1258"}, 00203 {"ibm437", "cp437"}, 00204 {"ibm737", "cp737"}, 00205 {"ibm775", "cp775"}, 00206 {"ibm850", "cp850"}, 00207 {"ibm852", "cp852"}, 00208 {"ibm855", "cp855"}, 00209 {"ibm857", "cp857"}, 00210 {"ibm860", "cp860"}, 00211 {"ibm861", "cp861"}, 00212 {"ibm862", "cp862"}, 00213 {"ibm863", "cp863"}, 00214 {"ibm864", "cp864"}, 00215 {"ibm865", "cp865"}, 00216 {"ibm866", "cp866"}, 00217 {"ibm869", "cp869"}, 00218 {"ibm874", "cp874"}, 00219 {"ibm932", "cp932"}, 00220 {"ibm936", "cp936"}, 00221 {"ibm949", "cp949"}, 00222 {"ibm950", "cp950"}, 00223 {"iso-2022", "iso2022"}, 00224 {"iso-2022-jp", "iso2022-jp"}, 00225 {"iso-2022-kr", "iso2022-kr"}, 00226 {"iso-8859-1", "iso8859-1"}, 00227 {"iso-8859-10", "iso8859-10"}, 00228 {"iso-8859-13", "iso8859-13"}, 00229 {"iso-8859-14", "iso8859-14"}, 00230 {"iso-8859-15", "iso8859-15"}, 00231 {"iso-8859-16", "iso8859-16"}, 00232 {"iso-8859-2", "iso8859-2"}, 00233 {"iso-8859-3", "iso8859-3"}, 00234 {"iso-8859-4", "iso8859-4"}, 00235 {"iso-8859-5", "iso8859-5"}, 00236 {"iso-8859-6", "iso8859-6"}, 00237 {"iso-8859-7", "iso8859-7"}, 00238 {"iso-8859-8", "iso8859-8"}, 00239 {"iso-8859-9", "iso8859-9"}, 00240 {"iso2022", "iso2022"}, 00241 {"iso2022-jp", "iso2022-jp"}, 00242 {"iso2022-kr", "iso2022-kr"}, 00243 {"iso8859-1", "iso8859-1"}, 00244 {"iso8859-10", "iso8859-10"}, 00245 {"iso8859-13", "iso8859-13"}, 00246 {"iso8859-14", "iso8859-14"}, 00247 {"iso8859-15", "iso8859-15"}, 00248 {"iso8859-16", "iso8859-16"}, 00249 {"iso8859-2", "iso8859-2"}, 00250 {"iso8859-3", "iso8859-3"}, 00251 {"iso8859-4", "iso8859-4"}, 00252 {"iso8859-5", "iso8859-5"}, 00253 {"iso8859-6", "iso8859-6"}, 00254 {"iso8859-7", "iso8859-7"}, 00255 {"iso8859-8", "iso8859-8"}, 00256 {"iso8859-9", "iso8859-9"}, 00257 {"iso88591", "iso8859-1"}, 00258 {"iso885915", "iso8859-15"}, 00259 {"iso88592", "iso8859-2"}, 00260 {"iso88595", "iso8859-5"}, 00261 {"iso88596", "iso8859-6"}, 00262 {"iso88597", "iso8859-7"}, 00263 {"iso88598", "iso8859-8"}, 00264 {"iso88599", "iso8859-9"}, 00265 #ifdef hpux 00266 {"ja", "shiftjis"}, 00267 #else 00268 {"ja", "euc-jp"}, 00269 #endif 00270 {"ja_jp", "euc-jp"}, 00271 {"ja_jp.euc", "euc-jp"}, 00272 {"ja_jp.eucjp", "euc-jp"}, 00273 {"ja_jp.jis", "iso2022-jp"}, 00274 {"ja_jp.mscode", "shiftjis"}, 00275 {"ja_jp.sjis", "shiftjis"}, 00276 {"ja_jp.ujis", "euc-jp"}, 00277 {"japan", "euc-jp"}, 00278 #ifdef hpux 00279 {"japanese", "shiftjis"}, 00280 #else 00281 {"japanese", "euc-jp"}, 00282 #endif 00283 {"japanese-sjis", "shiftjis"}, 00284 {"japanese-ujis", "euc-jp"}, 00285 {"japanese.euc", "euc-jp"}, 00286 {"japanese.sjis", "shiftjis"}, 00287 {"jis0201", "jis0201"}, 00288 {"jis0208", "jis0208"}, 00289 {"jis0212", "jis0212"}, 00290 {"jp_jp", "shiftjis"}, 00291 {"ko", "euc-kr"}, 00292 {"ko_kr", "euc-kr"}, 00293 {"ko_kr.euc", "euc-kr"}, 00294 {"ko_kw.euckw", "euc-kr"}, 00295 {"koi8-r", "koi8-r"}, 00296 {"koi8-u", "koi8-u"}, 00297 {"korean", "euc-kr"}, 00298 {"ksc5601", "ksc5601"}, 00299 {"maccenteuro", "macCentEuro"}, 00300 {"maccroatian", "macCroatian"}, 00301 {"maccyrillic", "macCyrillic"}, 00302 {"macdingbats", "macDingbats"}, 00303 {"macgreek", "macGreek"}, 00304 {"maciceland", "macIceland"}, 00305 {"macjapan", "macJapan"}, 00306 {"macroman", "macRoman"}, 00307 {"macromania", "macRomania"}, 00308 {"macthai", "macThai"}, 00309 {"macturkish", "macTurkish"}, 00310 {"macukraine", "macUkraine"}, 00311 {"roman8", "iso8859-1"}, 00312 {"ru", "iso8859-5"}, 00313 {"ru_ru", "iso8859-5"}, 00314 {"ru_su", "iso8859-5"}, 00315 {"shiftjis", "shiftjis"}, 00316 {"sjis", "shiftjis"}, 00317 {"symbol", "symbol"}, 00318 {"tis-620", "tis-620"}, 00319 {"tis620", "tis-620"}, 00320 {"turkish8", "cp857"}, 00321 {"utf8", "utf-8"}, 00322 {"zh", "cp936"}, 00323 {"zh_cn.gb2312", "euc-cn"}, 00324 {"zh_cn.gbk", "euc-cn"}, 00325 {"zh_cz.gb2312", "euc-cn"}, 00326 {"zh_tw", "euc-tw"}, 00327 {"zh_tw.big5", "big5"}, 00328 }; 00329 00330 #ifndef TCL_NO_STACK_CHECK 00331 static int GetStackSize(size_t *stackSizePtr); 00332 #endif /* TCL_NO_STACK_CHECK */ 00333 #ifdef HAVE_COREFOUNDATION 00334 static int MacOSXGetLibraryPath(Tcl_Interp *interp, 00335 int maxPathLen, char *tclLibPath); 00336 #endif /* HAVE_COREFOUNDATION */ 00337 #if defined(__APPLE__) && (defined(TCL_LOAD_FROM_MEMORY) || ( \ 00338 defined(TCL_THREADS) && defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ 00339 MAC_OS_X_VERSION_MIN_REQUIRED < 1030) || ( \ 00340 defined(__LP64__) && defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ 00341 MAC_OS_X_VERSION_MIN_REQUIRED < 1050)) 00342 /* 00343 * Need to check Darwin release at runtime in tclUnixFCmd.c and tclLoadDyld.c: 00344 * initialize release global at startup from uname(). 00345 */ 00346 #define GET_DARWIN_RELEASE 1 00347 MODULE_SCOPE long tclMacOSXDarwinRelease; 00348 long tclMacOSXDarwinRelease = 0; 00349 #endif 00350 00351 00352 /* 00353 *--------------------------------------------------------------------------- 00354 * 00355 * TclpInitPlatform -- 00356 * 00357 * Initialize all the platform-dependant things like signals and 00358 * floating-point error handling. 00359 * 00360 * Called at process initialization time. 00361 * 00362 * Results: 00363 * None. 00364 * 00365 * Side effects: 00366 * None. 00367 * 00368 *--------------------------------------------------------------------------- 00369 */ 00370 00371 void 00372 TclpInitPlatform(void) 00373 { 00374 #ifdef DJGPP 00375 tclPlatform = TCL_PLATFORM_WINDOWS; 00376 #else 00377 tclPlatform = TCL_PLATFORM_UNIX; 00378 #endif 00379 00380 /* 00381 * Make sure, that the standard FDs exist. [Bug 772288] 00382 */ 00383 00384 if (TclOSseek(0, (Tcl_SeekOffset) 0, SEEK_CUR) == -1 && errno == EBADF) { 00385 open("/dev/null", O_RDONLY); 00386 } 00387 if (TclOSseek(1, (Tcl_SeekOffset) 0, SEEK_CUR) == -1 && errno == EBADF) { 00388 open("/dev/null", O_WRONLY); 00389 } 00390 if (TclOSseek(2, (Tcl_SeekOffset) 0, SEEK_CUR) == -1 && errno == EBADF) { 00391 open("/dev/null", O_WRONLY); 00392 } 00393 00394 /* 00395 * The code below causes SIGPIPE (broken pipe) errors to be ignored. This 00396 * is needed so that Tcl processes don't die if they create child 00397 * processes (e.g. using "exec" or "open") that terminate prematurely. 00398 * The signal handler is only set up when the first interpreter is 00399 * created; after this the application can override the handler with a 00400 * different one of its own, if it wants. 00401 */ 00402 00403 #ifdef SIGPIPE 00404 (void) signal(SIGPIPE, SIG_IGN); 00405 #endif /* SIGPIPE */ 00406 00407 #if defined(__FreeBSD__) && defined(__GNUC__) 00408 /* 00409 * Adjust the rounding mode to be more conventional. Note that FreeBSD 00410 * only provides the __fpsetreg() used by the following two for the GNU 00411 * Compiler. When using, say, Intel's icc they break. (Partially based on 00412 * patch in BSD ports system from root@celsius.bychok.com) 00413 */ 00414 00415 fpsetround(FP_RN); 00416 (void) fpsetmask(0L); 00417 #endif 00418 00419 #if defined(__bsdi__) && (_BSDI_VERSION > 199501) 00420 /* 00421 * Find local symbols. Don't report an error if we fail. 00422 */ 00423 00424 (void) dlopen(NULL, RTLD_NOW); /* INTL: Native. */ 00425 #endif 00426 00427 /* 00428 * Initialize the C library's locale subsystem. This is required for input 00429 * methods to work properly on X11. We only do this for LC_CTYPE because 00430 * that's the necessary one, and we don't want to affect LC_TIME here. 00431 * The side effect of setting the default locale should be to load any 00432 * locale specific modules that are needed by X. [BUG: 5422 3345 4236 2522 00433 * 2521]. 00434 */ 00435 00436 setlocale(LC_CTYPE, ""); 00437 00438 /* 00439 * In case the initial locale is not "C", ensure that the numeric 00440 * processing is done in "C" locale regardless. This is needed because Tcl 00441 * relies on routines like strtod, but should not have locale dependent 00442 * behavior. 00443 */ 00444 00445 setlocale(LC_NUMERIC, "C"); 00446 00447 #ifdef GET_DARWIN_RELEASE 00448 { 00449 struct utsname name; 00450 00451 if (!uname(&name)) { 00452 tclMacOSXDarwinRelease = strtol(name.release, NULL, 10); 00453 } 00454 } 00455 #endif 00456 } 00457 00458 /* 00459 *--------------------------------------------------------------------------- 00460 * 00461 * TclpInitLibraryPath -- 00462 * 00463 * This is the fallback routine that sets the library path if the 00464 * application has not set one by the first time it is needed. 00465 * 00466 * Results: 00467 * None. 00468 * 00469 * Side effects: 00470 * Sets the library path to an initial value. 00471 * 00472 *------------------------------------------------------------------------- 00473 */ 00474 00475 void 00476 TclpInitLibraryPath( 00477 char **valuePtr, 00478 int *lengthPtr, 00479 Tcl_Encoding *encodingPtr) 00480 { 00481 #define LIBRARY_SIZE 32 00482 Tcl_Obj *pathPtr, *objPtr; 00483 CONST char *str; 00484 Tcl_DString buffer; 00485 00486 pathPtr = Tcl_NewObj(); 00487 00488 /* 00489 * Look for the library relative to the TCL_LIBRARY env variable. If the 00490 * last dirname in the TCL_LIBRARY path does not match the last dirname in 00491 * the installLib variable, use the last dir name of installLib in 00492 * addition to the orginal TCL_LIBRARY path. 00493 */ 00494 00495 str = getenv("TCL_LIBRARY"); /* INTL: Native. */ 00496 Tcl_ExternalToUtfDString(NULL, str, -1, &buffer); 00497 str = Tcl_DStringValue(&buffer); 00498 00499 if ((str != NULL) && (str[0] != '\0')) { 00500 Tcl_DString ds; 00501 int pathc; 00502 CONST char **pathv; 00503 char installLib[LIBRARY_SIZE]; 00504 00505 Tcl_DStringInit(&ds); 00506 00507 /* 00508 * Initialize the substrings used when locating an executable. The 00509 * installLib variable computes the path as though the executable is 00510 * installed. 00511 */ 00512 00513 sprintf(installLib, "lib/tcl%s", TCL_VERSION); 00514 00515 /* 00516 * If TCL_LIBRARY is set, search there. 00517 */ 00518 00519 objPtr = Tcl_NewStringObj(str, -1); 00520 Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); 00521 00522 Tcl_SplitPath(str, &pathc, &pathv); 00523 if ((pathc > 0) && (strcasecmp(installLib + 4, pathv[pathc-1]) != 0)) { 00524 /* 00525 * If TCL_LIBRARY is set but refers to a different tcl 00526 * installation than the current version, try fiddling with the 00527 * specified directory to make it refer to this installation by 00528 * removing the old "tclX.Y" and substituting the current version 00529 * string. 00530 */ 00531 00532 pathv[pathc - 1] = installLib + 4; 00533 str = Tcl_JoinPath(pathc, pathv, &ds); 00534 objPtr = Tcl_NewStringObj(str, Tcl_DStringLength(&ds)); 00535 Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); 00536 Tcl_DStringFree(&ds); 00537 } 00538 ckfree((char *) pathv); 00539 } 00540 00541 /* 00542 * Finally, look for the library relative to the compiled-in path. This is 00543 * needed when users install Tcl with an exec-prefix that is different 00544 * from the prefix. 00545 */ 00546 00547 { 00548 #ifdef HAVE_COREFOUNDATION 00549 char tclLibPath[MAXPATHLEN + 1]; 00550 00551 if (MacOSXGetLibraryPath(NULL, MAXPATHLEN, tclLibPath) == TCL_OK) { 00552 str = tclLibPath; 00553 } else 00554 #endif /* HAVE_COREFOUNDATION */ 00555 { 00556 /* 00557 * TODO: Pull this value from the TIP 59 table. 00558 */ 00559 00560 str = defaultLibraryDir; 00561 } 00562 if (str[0] != '\0') { 00563 objPtr = Tcl_NewStringObj(str, -1); 00564 Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); 00565 } 00566 } 00567 Tcl_DStringFree(&buffer); 00568 00569 *encodingPtr = Tcl_GetEncoding(NULL, NULL); 00570 str = Tcl_GetStringFromObj(pathPtr, lengthPtr); 00571 *valuePtr = ckalloc((unsigned int) (*lengthPtr)+1); 00572 memcpy(*valuePtr, str, (size_t)(*lengthPtr)+1); 00573 Tcl_DecrRefCount(pathPtr); 00574 } 00575 00576 /* 00577 *--------------------------------------------------------------------------- 00578 * 00579 * TclpSetInitialEncodings -- 00580 * 00581 * Based on the locale, determine the encoding of the operating system 00582 * and the default encoding for newly opened files. 00583 * 00584 * Called at process initialization time, and part way through startup, 00585 * we verify that the initial encodings were correctly setup. Depending 00586 * on Tcl's environment, there may not have been enough information first 00587 * time through (above). 00588 * 00589 * Results: 00590 * None. 00591 * 00592 * Side effects: 00593 * The Tcl library path is converted from native encoding to UTF-8, on 00594 * the first call, and the encodings may be changed on first or second 00595 * call. 00596 * 00597 *--------------------------------------------------------------------------- 00598 */ 00599 00600 void 00601 TclpSetInitialEncodings(void) 00602 { 00603 Tcl_DString encodingName; 00604 Tcl_SetSystemEncoding(NULL, 00605 Tcl_GetEncodingNameFromEnvironment(&encodingName)); 00606 Tcl_DStringFree(&encodingName); 00607 } 00608 00609 void 00610 TclpSetInterfaces(void) 00611 { 00612 /* do nothing */ 00613 } 00614 00615 static CONST char * 00616 SearchKnownEncodings( 00617 CONST char *encoding) 00618 { 00619 int left = 0; 00620 int right = sizeof(localeTable)/sizeof(LocaleTable); 00621 00622 while (left <= right) { 00623 int test = (left + right)/2; 00624 int code = strcmp(localeTable[test].lang, encoding); 00625 00626 if (code == 0) { 00627 return localeTable[test].encoding; 00628 } 00629 if (code < 0) { 00630 left = test+1; 00631 } else { 00632 right = test-1; 00633 } 00634 } 00635 return NULL; 00636 } 00637 00638 CONST char * 00639 Tcl_GetEncodingNameFromEnvironment( 00640 Tcl_DString *bufPtr) 00641 { 00642 CONST char *encoding; 00643 CONST char *knownEncoding; 00644 00645 Tcl_DStringInit(bufPtr); 00646 00647 /* 00648 * Determine the current encoding from the LC_* or LANG environment 00649 * variables. We previously used setlocale() to determine the locale, but 00650 * this does not work on some systems (e.g. Linux/i386 RH 5.0). 00651 */ 00652 00653 #ifdef HAVE_LANGINFO 00654 if ( 00655 #ifdef WEAK_IMPORT_NL_LANGINFO 00656 nl_langinfo != NULL && 00657 #endif 00658 setlocale(LC_CTYPE, "") != NULL) { 00659 Tcl_DString ds; 00660 00661 /* 00662 * Use a DString so we can modify case. 00663 */ 00664 00665 Tcl_DStringInit(&ds); 00666 encoding = Tcl_DStringAppend(&ds, nl_langinfo(CODESET), -1); 00667 Tcl_UtfToLower(Tcl_DStringValue(&ds)); 00668 knownEncoding = SearchKnownEncodings(encoding); 00669 if (knownEncoding != NULL) { 00670 Tcl_DStringAppend(bufPtr, knownEncoding, -1); 00671 } else if (NULL != Tcl_GetEncoding(NULL, encoding)) { 00672 Tcl_DStringAppend(bufPtr, encoding, -1); 00673 } 00674 Tcl_DStringFree(&ds); 00675 if (Tcl_DStringLength(bufPtr)) { 00676 return Tcl_DStringValue(bufPtr); 00677 } 00678 } 00679 #endif /* HAVE_LANGINFO */ 00680 00681 /* 00682 * Classic fallback check. This tries a homebrew algorithm to determine 00683 * what encoding should be used based on env vars. 00684 */ 00685 00686 encoding = getenv("LC_ALL"); 00687 00688 if (encoding == NULL || encoding[0] == '\0') { 00689 encoding = getenv("LC_CTYPE"); 00690 } 00691 if (encoding == NULL || encoding[0] == '\0') { 00692 encoding = getenv("LANG"); 00693 } 00694 if (encoding == NULL || encoding[0] == '\0') { 00695 encoding = NULL; 00696 } 00697 00698 if (encoding != NULL) { 00699 CONST char *p; 00700 Tcl_DString ds; 00701 00702 Tcl_DStringInit(&ds); 00703 p = encoding; 00704 encoding = Tcl_DStringAppend(&ds, p, -1); 00705 Tcl_UtfToLower(Tcl_DStringValue(&ds)); 00706 00707 knownEncoding = SearchKnownEncodings(encoding); 00708 if (knownEncoding != NULL) { 00709 Tcl_DStringAppend(bufPtr, knownEncoding, -1); 00710 } else if (NULL != Tcl_GetEncoding(NULL, encoding)) { 00711 Tcl_DStringAppend(bufPtr, encoding, -1); 00712 } 00713 if (Tcl_DStringLength(bufPtr)) { 00714 Tcl_DStringFree(&ds); 00715 return Tcl_DStringValue(bufPtr); 00716 } 00717 00718 /* 00719 * We didn't recognize the full value as an encoding name. If there is 00720 * an encoding subfield, we can try to guess from that. 00721 */ 00722 00723 for (p = encoding; *p != '\0'; p++) { 00724 if (*p == '.') { 00725 p++; 00726 break; 00727 } 00728 } 00729 if (*p != '\0') { 00730 knownEncoding = SearchKnownEncodings(p); 00731 if (knownEncoding != NULL) { 00732 Tcl_DStringAppend(bufPtr, knownEncoding, -1); 00733 } else if (NULL != Tcl_GetEncoding(NULL, p)) { 00734 Tcl_DStringAppend(bufPtr, p, -1); 00735 } 00736 } 00737 Tcl_DStringFree(&ds); 00738 if (Tcl_DStringLength(bufPtr)) { 00739 return Tcl_DStringValue(bufPtr); 00740 } 00741 } 00742 return Tcl_DStringAppend(bufPtr, TCL_DEFAULT_ENCODING, -1); 00743 } 00744 00745 /* 00746 *--------------------------------------------------------------------------- 00747 * 00748 * TclpSetVariables -- 00749 * 00750 * Performs platform-specific interpreter initialization related to the 00751 * tcl_library and tcl_platform variables, and other platform-specific 00752 * things. 00753 * 00754 * Results: 00755 * None. 00756 * 00757 * Side effects: 00758 * Sets "tclDefaultLibrary", "tcl_pkgPath", and "tcl_platform" Tcl 00759 * variables. 00760 * 00761 *---------------------------------------------------------------------- 00762 */ 00763 00764 void 00765 TclpSetVariables( 00766 Tcl_Interp *interp) 00767 { 00768 #ifndef NO_UNAME 00769 struct utsname name; 00770 #endif 00771 int unameOK; 00772 Tcl_DString ds; 00773 00774 #ifdef HAVE_COREFOUNDATION 00775 char tclLibPath[MAXPATHLEN + 1]; 00776 00777 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1020 00778 /* 00779 * Set msgcat fallback locale to current CFLocale identifier. 00780 */ 00781 00782 CFLocaleRef localeRef; 00783 00784 if (CFLocaleCopyCurrent != NULL && CFLocaleGetIdentifier != NULL && 00785 (localeRef = CFLocaleCopyCurrent())) { 00786 CFStringRef locale = CFLocaleGetIdentifier(localeRef); 00787 00788 if (locale) { 00789 char loc[256]; 00790 00791 if (CFStringGetCString(locale, loc, 256, kCFStringEncodingUTF8)) { 00792 if (!Tcl_CreateNamespace(interp, "::tcl::mac", NULL, NULL)) { 00793 Tcl_ResetResult(interp); 00794 } 00795 Tcl_SetVar(interp, "::tcl::mac::locale", loc, TCL_GLOBAL_ONLY); 00796 } 00797 } 00798 CFRelease(localeRef); 00799 } 00800 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED > 1020 */ 00801 00802 if (MacOSXGetLibraryPath(interp, MAXPATHLEN, tclLibPath) == TCL_OK) { 00803 CONST char *str; 00804 CFBundleRef bundleRef; 00805 00806 Tcl_SetVar(interp, "tclDefaultLibrary", tclLibPath, TCL_GLOBAL_ONLY); 00807 Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath, TCL_GLOBAL_ONLY); 00808 Tcl_SetVar(interp, "tcl_pkgPath", " ", 00809 TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); 00810 00811 str = TclGetEnv("DYLD_FRAMEWORK_PATH", &ds); 00812 if ((str != NULL) && (str[0] != '\0')) { 00813 char *p = Tcl_DStringValue(&ds); 00814 00815 /* 00816 * Convert DYLD_FRAMEWORK_PATH from colon to space separated. 00817 */ 00818 00819 do { 00820 if (*p == ':') { 00821 *p = ' '; 00822 } 00823 } while (*p++); 00824 Tcl_SetVar(interp, "tcl_pkgPath", Tcl_DStringValue(&ds), 00825 TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); 00826 Tcl_SetVar(interp, "tcl_pkgPath", " ", 00827 TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); 00828 Tcl_DStringFree(&ds); 00829 } 00830 bundleRef = CFBundleGetMainBundle(); 00831 if (bundleRef) { 00832 CFURLRef frameworksURL; 00833 Tcl_StatBuf statBuf; 00834 00835 frameworksURL = CFBundleCopyPrivateFrameworksURL(bundleRef); 00836 if (frameworksURL) { 00837 if (CFURLGetFileSystemRepresentation(frameworksURL, TRUE, 00838 (unsigned char*) tclLibPath, MAXPATHLEN) && 00839 ! TclOSstat(tclLibPath, &statBuf) && 00840 S_ISDIR(statBuf.st_mode)) { 00841 Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath, 00842 TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); 00843 Tcl_SetVar(interp, "tcl_pkgPath", " ", 00844 TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); 00845 } 00846 CFRelease(frameworksURL); 00847 } 00848 frameworksURL = CFBundleCopySharedFrameworksURL(bundleRef); 00849 if (frameworksURL) { 00850 if (CFURLGetFileSystemRepresentation(frameworksURL, TRUE, 00851 (unsigned char*) tclLibPath, MAXPATHLEN) && 00852 ! TclOSstat(tclLibPath, &statBuf) && 00853 S_ISDIR(statBuf.st_mode)) { 00854 Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath, 00855 TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); 00856 Tcl_SetVar(interp, "tcl_pkgPath", " ", 00857 TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); 00858 } 00859 CFRelease(frameworksURL); 00860 } 00861 } 00862 Tcl_SetVar(interp, "tcl_pkgPath", pkgPath, 00863 TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); 00864 } else 00865 #endif /* HAVE_COREFOUNDATION */ 00866 { 00867 Tcl_SetVar(interp, "tcl_pkgPath", pkgPath, TCL_GLOBAL_ONLY); 00868 } 00869 00870 #ifdef DJGPP 00871 Tcl_SetVar2(interp, "tcl_platform", "platform", "dos", TCL_GLOBAL_ONLY); 00872 #else 00873 Tcl_SetVar2(interp, "tcl_platform", "platform", "unix", TCL_GLOBAL_ONLY); 00874 #endif 00875 00876 unameOK = 0; 00877 #ifndef NO_UNAME 00878 if (uname(&name) >= 0) { 00879 CONST char *native; 00880 00881 unameOK = 1; 00882 00883 native = Tcl_ExternalToUtfDString(NULL, name.sysname, -1, &ds); 00884 Tcl_SetVar2(interp, "tcl_platform", "os", native, TCL_GLOBAL_ONLY); 00885 Tcl_DStringFree(&ds); 00886 00887 /* 00888 * The following code is a special hack to handle differences in the 00889 * way version information is returned by uname. On most systems the 00890 * full version number is available in name.release. However, under 00891 * AIX the major version number is in name.version and the minor 00892 * version number is in name.release. 00893 */ 00894 00895 if ((strchr(name.release, '.') != NULL) 00896 || !isdigit(UCHAR(name.version[0]))) { /* INTL: digit */ 00897 Tcl_SetVar2(interp, "tcl_platform", "osVersion", name.release, 00898 TCL_GLOBAL_ONLY); 00899 } else { 00900 #ifdef DJGPP 00901 /* 00902 * For some obscure reason DJGPP puts major version into 00903 * name.release and minor into name.version. As of DJGPP 2.04 this 00904 * is documented in djgpp libc.info file. 00905 */ 00906 00907 Tcl_SetVar2(interp, "tcl_platform", "osVersion", name.release, 00908 TCL_GLOBAL_ONLY); 00909 Tcl_SetVar2(interp, "tcl_platform", "osVersion", ".", 00910 TCL_GLOBAL_ONLY|TCL_APPEND_VALUE); 00911 Tcl_SetVar2(interp, "tcl_platform", "osVersion", name.version, 00912 TCL_GLOBAL_ONLY|TCL_APPEND_VALUE); 00913 #else 00914 Tcl_SetVar2(interp, "tcl_platform", "osVersion", name.version, 00915 TCL_GLOBAL_ONLY); 00916 Tcl_SetVar2(interp, "tcl_platform", "osVersion", ".", 00917 TCL_GLOBAL_ONLY|TCL_APPEND_VALUE); 00918 Tcl_SetVar2(interp, "tcl_platform", "osVersion", name.release, 00919 TCL_GLOBAL_ONLY|TCL_APPEND_VALUE); 00920 00921 #endif /* DJGPP */ 00922 } 00923 Tcl_SetVar2(interp, "tcl_platform", "machine", name.machine, 00924 TCL_GLOBAL_ONLY); 00925 } 00926 #endif /* !NO_UNAME */ 00927 if (!unameOK) { 00928 Tcl_SetVar2(interp, "tcl_platform", "os", "", TCL_GLOBAL_ONLY); 00929 Tcl_SetVar2(interp, "tcl_platform", "osVersion", "", TCL_GLOBAL_ONLY); 00930 Tcl_SetVar2(interp, "tcl_platform", "machine", "", TCL_GLOBAL_ONLY); 00931 } 00932 00933 /* 00934 * Copy the username of the real user (according to getuid()) into 00935 * tcl_platform(user). 00936 */ 00937 00938 { 00939 struct passwd *pwEnt = TclpGetPwUid(getuid()); 00940 const char *user; 00941 00942 if (pwEnt == NULL) { 00943 user = ""; 00944 Tcl_DStringInit(&ds); /* ensure cleanliness */ 00945 } else { 00946 user = Tcl_ExternalToUtfDString(NULL, pwEnt->pw_name, -1, &ds); 00947 } 00948 00949 Tcl_SetVar2(interp, "tcl_platform", "user", user, TCL_GLOBAL_ONLY); 00950 Tcl_DStringFree(&ds); 00951 } 00952 } 00953 00954 /* 00955 *---------------------------------------------------------------------- 00956 * 00957 * TclpFindVariable -- 00958 * 00959 * Locate the entry in environ for a given name. On Unix this routine is 00960 * case sensetive, on Windows this matches mixed case. 00961 * 00962 * Results: 00963 * The return value is the index in environ of an entry with the name 00964 * "name", or -1 if there is no such entry. The integer at *lengthPtr is 00965 * filled in with the length of name (if a matching entry is found) or 00966 * the length of the environ array (if no matching entry is found). 00967 * 00968 * Side effects: 00969 * None. 00970 * 00971 *---------------------------------------------------------------------- 00972 */ 00973 00974 int 00975 TclpFindVariable( 00976 CONST char *name, /* Name of desired environment variable 00977 * (native). */ 00978 int *lengthPtr) /* Used to return length of name (for 00979 * successful searches) or number of non-NULL 00980 * entries in environ (for unsuccessful 00981 * searches). */ 00982 { 00983 int i, result = -1; 00984 register CONST char *env, *p1, *p2; 00985 Tcl_DString envString; 00986 00987 Tcl_DStringInit(&envString); 00988 for (i = 0, env = environ[i]; env != NULL; i++, env = environ[i]) { 00989 p1 = Tcl_ExternalToUtfDString(NULL, env, -1, &envString); 00990 p2 = name; 00991 00992 for (; *p2 == *p1; p1++, p2++) { 00993 /* NULL loop body. */ 00994 } 00995 if ((*p1 == '=') && (*p2 == '\0')) { 00996 *lengthPtr = p2 - name; 00997 result = i; 00998 goto done; 00999 } 01000 01001 Tcl_DStringFree(&envString); 01002 } 01003 01004 *lengthPtr = i; 01005 01006 done: 01007 Tcl_DStringFree(&envString); 01008 return result; 01009 } 01010 01011 #ifndef TCL_NO_STACK_CHECK 01012 /* 01013 *---------------------------------------------------------------------- 01014 * 01015 * TclpGetCStackParams -- 01016 * 01017 * Determine the stack params for the current thread: in which 01018 * direction does the stack grow, and what is the stack lower (resp. 01019 * upper) bound for safe invocation of a new command? This is used to 01020 * cache the values needed for an efficient computation of 01021 * TclpCheckStackSpace() when the interp is known. 01022 * 01023 * Results: 01024 * Returns 1 if the stack grows down, in which case a stack lower bound 01025 * is stored at stackBoundPtr. If the stack grows up, 0 is returned and 01026 * an upper bound is stored at stackBoundPtr. If a bound cannot be 01027 * determined NULL is stored at stackBoundPtr. 01028 * 01029 *---------------------------------------------------------------------- 01030 */ 01031 01032 int 01033 TclpGetCStackParams( 01034 int **stackBoundPtr) 01035 { 01036 int result = TCL_OK; 01037 size_t stackSize = 0; /* The size of the current stack. */ 01038 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 01039 /* Most variables are actually in a 01040 * thread-specific data block to minimise the 01041 * impact on the stack. */ 01042 #ifdef TCL_CROSS_COMPILE 01043 if (stackGrowsDown == -1) { 01044 /* 01045 * Not initialised! 01046 */ 01047 01048 stackGrowsDown = StackGrowsDown(&result); 01049 } 01050 #endif 01051 01052 /* 01053 * The first time through in a thread: record the "outermost" stack 01054 * frame and inquire with the OS about the stack size. 01055 */ 01056 01057 if (tsdPtr->outerVarPtr == NULL) { 01058 tsdPtr->outerVarPtr = &result; 01059 result = GetStackSize(&stackSize); 01060 if (result != TCL_OK) { 01061 /* Can't check, assume it always succeeds */ 01062 #ifdef TCL_CROSS_COMPILE 01063 stackGrowsDown = 1; 01064 #endif 01065 tsdPtr->stackBound = NULL; 01066 goto done; 01067 } 01068 } 01069 01070 if (stackSize || (tsdPtr->stackBound && 01071 ((stackGrowsDown && (&result < tsdPtr->stackBound)) || 01072 (!stackGrowsDown && (&result > tsdPtr->stackBound))))) { 01073 /* 01074 * Either the thread's first pass or stack failure: set the params 01075 */ 01076 01077 if (!stackSize) { 01078 /* 01079 * Stack failure: if we didn't already blow up, we are within the 01080 * safety area. Recheck with the OS in case the stack was grown. 01081 */ 01082 result = GetStackSize(&stackSize); 01083 if (result != TCL_OK) { 01084 /* Can't check, assume it always succeeds */ 01085 #ifdef TCL_CROSS_COMPILE 01086 stackGrowsDown = 1; 01087 #endif 01088 tsdPtr->stackBound = NULL; 01089 goto done; 01090 } 01091 } 01092 01093 if (stackGrowsDown) { 01094 tsdPtr->stackBound = (int *) ((char *)tsdPtr->outerVarPtr - 01095 stackSize); 01096 } else { 01097 tsdPtr->stackBound = (int *) ((char *)tsdPtr->outerVarPtr + 01098 stackSize); 01099 } 01100 } 01101 01102 done: 01103 *stackBoundPtr = tsdPtr->stackBound; 01104 return stackGrowsDown; 01105 } 01106 01107 #ifdef TCL_CROSS_COMPILE 01108 int 01109 StackGrowsDown( 01110 int *parent) 01111 { 01112 int here; 01113 return (&here < parent); 01114 } 01115 #endif 01116 01117 /* 01118 *---------------------------------------------------------------------- 01119 * 01120 * GetStackSize -- 01121 * 01122 * Discover what the stack size for the current thread/process actually 01123 * is. Expects to only ever be called once per thread and then only at a 01124 * point when there is a reasonable amount of space left on the current 01125 * stack; TclpCheckStackSpace is called sufficiently frequently that that 01126 * is true. 01127 * 01128 * Results: 01129 * TCL_OK if the stack space was discovered, TCL_BREAK if the stack space 01130 * was undiscoverable in a way that stack checks should fail, and 01131 * TCL_CONTINUE if the stack space was undiscoverable in a way that stack 01132 * checks should succeed. 01133 * 01134 * Side effects: 01135 * None 01136 * 01137 *---------------------------------------------------------------------- 01138 */ 01139 01140 static int 01141 GetStackSize( 01142 size_t *stackSizePtr) 01143 { 01144 size_t rawStackSize; 01145 struct rlimit rLimit; /* The result from getrlimit(). */ 01146 01147 #ifdef TCL_THREADS 01148 rawStackSize = TclpThreadGetStackSize(); 01149 if (rawStackSize == (size_t) -1) { 01150 /* 01151 * Some kind of confirmed error in TclpThreadGetStackSize?! Fall back 01152 * to whatever getrlimit can determine. 01153 */ 01154 STACK_DEBUG(("stack checks: TclpThreadGetStackSize failed in \n")); 01155 } 01156 if (rawStackSize > 0) { 01157 goto finalSanityCheck; 01158 } 01159 01160 /* 01161 * If we have zero or an error, try the system limits instead. After all, 01162 * the pthread documentation states that threads should always be bound by 01163 * the system stack size limit in any case. 01164 */ 01165 #endif /* TCL_THREADS */ 01166 01167 if (getrlimit(RLIMIT_STACK, &rLimit) != 0) { 01168 /* 01169 * getrlimit() failed, just fail the whole thing. 01170 */ 01171 STACK_DEBUG(("skipping stack checks with failure: getrlimit failed\n")); 01172 return TCL_BREAK; 01173 } 01174 if (rLimit.rlim_cur == RLIM_INFINITY) { 01175 /* 01176 * Limit is "infinite"; there is no stack limit. 01177 */ 01178 STACK_DEBUG(("skipping stack checks with success: infinite limit\n")); 01179 return TCL_CONTINUE; 01180 } 01181 rawStackSize = rLimit.rlim_cur; 01182 01183 /* 01184 * Final sanity check on the determined stack size. If we fail this, 01185 * assume there are bogus values about and that we can't actually figure 01186 * out what the stack size really is. 01187 */ 01188 01189 #ifdef TCL_THREADS /* Stop warning... */ 01190 finalSanityCheck: 01191 #endif 01192 if (rawStackSize <= 0) { 01193 STACK_DEBUG(("skipping stack checks with success\n")); 01194 return TCL_CONTINUE; 01195 } 01196 01197 /* 01198 * Calculate a stack size with a safety margin. 01199 */ 01200 01201 *stackSizePtr = (rawStackSize / TCL_MAGIC_STACK_DIVISOR) 01202 - (getpagesize() * TCL_RESERVED_STACK_PAGES); 01203 01204 return TCL_OK; 01205 } 01206 #endif /* TCL_NO_STACK_CHECK */ 01207 01208 /* 01209 *---------------------------------------------------------------------- 01210 * 01211 * MacOSXGetLibraryPath -- 01212 * 01213 * If we have a bundle structure for the Tcl installation, then check 01214 * there first to see if we can find the libraries there. 01215 * 01216 * Results: 01217 * TCL_OK if we have found the tcl library; TCL_ERROR otherwise. 01218 * 01219 * Side effects: 01220 * Same as for Tcl_MacOSXOpenVersionedBundleResources. 01221 * 01222 *---------------------------------------------------------------------- 01223 */ 01224 01225 #ifdef HAVE_COREFOUNDATION 01226 static int 01227 MacOSXGetLibraryPath( 01228 Tcl_Interp *interp, 01229 int maxPathLen, 01230 char *tclLibPath) 01231 { 01232 int foundInFramework = TCL_ERROR; 01233 01234 #ifdef TCL_FRAMEWORK 01235 foundInFramework = Tcl_MacOSXOpenVersionedBundleResources(interp, 01236 "com.tcltk.tcllibrary", TCL_FRAMEWORK_VERSION, 0, maxPathLen, 01237 tclLibPath); 01238 #endif 01239 01240 return foundInFramework; 01241 } 01242 #endif /* HAVE_COREFOUNDATION */ 01243 01244 /* 01245 * Local Variables: 01246 * mode: c 01247 * c-basic-offset: 4 01248 * fill-column: 78 01249 * End: 01250 */
Generated on Wed Mar 12 12:18:26 2008 by 1.5.1 |