os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacInit.c
Update contrib.
4 * Contains the Mac-specific interpreter initialization functions.
6 * Copyright (c) 1995-1998 Sun Microsystems, Inc.
8 * See the file "license.terms" for information on usage and redistribution
9 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 * RCS: @(#) $Id: tclMacInit.c,v 1.9.2.2 2005/10/23 22:01:31 msofer Exp $
14 #include <AppleEvents.h>
15 #include <AEDataModel.h>
16 #include <AEObjects.h>
17 #include <AEPackObject.h>
18 #include <AERegistry.h>
22 #include <TextUtils.h>
23 #include <Resources.h>
26 #include "tclMacInt.h"
28 #include "tclInitScript.h"
31 * The following string is the startup script executed in new
32 * interpreters. It looks on the library path and in the resource fork for
33 * a script "init.tcl" that is compatible with this version of Tcl. The
34 * init.tcl script does all of the real work of initialization.
37 static char initCmd[] = "if {[info proc tclInit]==\"\"} {\n\
39 global tcl_pkgPath env\n\
40 proc sourcePath {file} {\n\
41 foreach i $::auto_path {\n\
42 set init [file join $i $file.tcl]\n\
43 if {[catch {uplevel #0 [list source $init]}] == 0} {\n\
47 if {[catch {uplevel #0 [list source -rsrc $file]}] == 0} {\n\
50 rename sourcePath {}\n\
51 set msg \"Can't find $file resource or a usable $file.tcl file\"\n\
52 append msg \" in the following directories:\"\n\
53 append msg \" $::auto_path\"\n\
54 append msg \" perhaps you need to install Tcl or set your\"\n\
55 append msg \" TCL_LIBRARY environment variable?\"\n\
58 if {[info exists env(EXT_FOLDER)]} {\n\
59 lappend tcl_pkgPath [file join $env(EXT_FOLDER) {Tool Command Language}]\n\
61 if {[info exists tcl_pkgPath] == 0} {\n\
62 set tcl_pkgPath {no extension folder}\n\
70 rename sourcePath {}\n\
75 * The following structures are used to map the script/language codes of a
76 * font to the name that should be passed to Tcl_GetEncoding() to obtain
77 * the encoding for that font. The set of numeric constants is fixed and
86 static Map scriptMap[] = {
87 {smRoman, "macRoman"},
88 {smJapanese, "macJapan"},
89 {smTradChinese, "macChinese"},
90 {smKorean, "macKorean"},
91 {smArabic, "macArabic"},
92 {smHebrew, "macHebrew"},
93 {smGreek, "macGreek"},
94 {smCyrillic, "macCyrillic"},
95 {smRSymbol, "macRSymbol"},
96 {smDevanagari, "macDevanagari"},
97 {smGurmukhi, "macGurmukhi"},
98 {smGujarati, "macGujarati"},
99 {smOriya, "macOriya"},
100 {smBengali, "macBengali"},
101 {smTamil, "macTamil"},
102 {smTelugu, "macTelugu"},
103 {smKannada, "macKannada"},
104 {smMalayalam, "macMalayalam"},
105 {smSinhalese, "macSinhalese"},
106 {smBurmese, "macBurmese"},
107 {smKhmer, "macKhmer"},
108 {smThai, "macThailand"},
109 {smLaotian, "macLaos"},
110 {smGeorgian, "macGeorgia"},
111 {smArmenian, "macArmenia"},
112 {smSimpChinese, "macSimpChinese"},
113 {smTibetan, "macTIbet"},
114 {smMongolian, "macMongolia"},
115 {smGeez, "macEthiopia"},
116 {smEastEurRoman, "macCentEuro"},
117 {smVietnamese, "macVietnam"},
118 {smExtArabic, "macSindhi"},
122 static Map romanMap[] = {
123 {langCroatian, "macCroatian"},
124 {langSlovenian, "macCroatian"},
125 {langIcelandic, "macIceland"},
126 {langRomanian, "macRomania"},
127 {langTurkish, "macTurkish"},
128 {langGreek, "macGreek"},
132 static Map cyrillicMap[] = {
133 {langUkrainian, "macUkraine"},
134 {langBulgarian, "macBulgaria"},
138 static int GetFinderFont(int *finderID);
140 /* Used to store the encoding used for binary files */
141 static Tcl_Encoding binaryEncoding = NULL;
142 /* Has the basic library path encoding issue been fixed */
143 static int libraryPathEncodingFixed = 0;
147 *----------------------------------------------------------------------
151 * Gets the "views" font of the Macintosh Finder
154 * Standard Tcl result, and sets finderID to the font family
155 * id for the current finder font.
160 *----------------------------------------------------------------------
163 GetFinderFont(int *finderID)
166 OSType finderPrefs, viewFont = 'vfnt';
169 long result, sys8Mask = 0x0800;
170 static AppleEvent outgoingAevt = {typeNull, NULL};
171 AppleEvent returnAevt;
172 AEAddressDesc fndrAddress;
173 AEDesc nullContainer = {typeNull, NULL},
174 tempDesc = {typeNull, NULL},
175 tempDesc2 = {typeNull, NULL},
176 finalDesc = {typeNull, NULL};
177 const OSType finderSignature = 'MACS';
180 if (outgoingAevt.descriptorType == typeNull) {
181 if ((Gestalt(gestaltSystemVersion, &result) != noErr)
182 || (result >= sys8Mask)) {
183 finderPrefs = 'pfrp';
185 finderPrefs = 'pvwp';
188 AECreateDesc(typeApplSignature, &finderSignature,
189 sizeof(finderSignature), &fndrAddress);
191 err = AECreateAppleEvent(kAECoreSuite, kAEGetData, &fndrAddress,
192 kAutoGenerateReturnID, kAnyTransactionID, &outgoingAevt);
194 AEDisposeDesc(&fndrAddress);
198 * the property view font ('vfnt')
199 * of the property view preferences ('pvwp')
200 * of the Null Container (i.e. the Finder itself).
203 AECreateDesc(typeType, &finderPrefs, sizeof(finderPrefs), &tempDesc);
204 err = CreateObjSpecifier(typeType, &nullContainer, formPropertyID,
205 &tempDesc, true, &tempDesc2);
206 AECreateDesc(typeType, &viewFont, sizeof(viewFont), &tempDesc);
207 err = CreateObjSpecifier(typeType, &tempDesc2, formPropertyID,
208 &tempDesc, true, &finalDesc);
210 AEPutKeyDesc(&outgoingAevt, keyDirectObject, &finalDesc);
211 AEDisposeDesc(&finalDesc);
214 err = AESend(&outgoingAevt, &returnAevt, kAEWaitReply, kAEHighPriority,
215 kAEDefaultTimeout, NULL, NULL);
217 err = AEGetKeyPtr(&returnAevt, keyDirectObject, typeInteger,
218 &returnType, (void *) finderID, sizeof(int), &returnSize);
227 *---------------------------------------------------------------------------
229 * TclMacGetFontEncoding --
231 * Determine the encoding of the specified font. The encoding
232 * can be used to convert bytes from UTF-8 into the encoding of
236 * The return value is a string that specifies the font's encoding
237 * and that can be passed to Tcl_GetEncoding() to construct the
238 * encoding. If the font's encoding could not be identified, NULL
244 *---------------------------------------------------------------------------
248 TclMacGetFontEncoding(
255 script = FontToScript(fontId);
256 lang = GetScriptVariable(script, smScriptLang);
258 if (script == smRoman) {
259 for (mapPtr = romanMap; mapPtr->strKey != NULL; mapPtr++) {
260 if (mapPtr->numKey == lang) {
261 name = mapPtr->strKey;
265 } else if (script == smCyrillic) {
266 for (mapPtr = cyrillicMap; mapPtr->strKey != NULL; mapPtr++) {
267 if (mapPtr->numKey == lang) {
268 name = mapPtr->strKey;
274 for (mapPtr = scriptMap; mapPtr->strKey != NULL; mapPtr++) {
275 if (mapPtr->numKey == script) {
276 name = mapPtr->strKey;
285 *---------------------------------------------------------------------------
287 * TclpInitPlatform --
289 * Initialize all the platform-dependant things like signals and
290 * floating-point error handling.
292 * Called at process initialization time.
300 *---------------------------------------------------------------------------
306 tclPlatform = TCL_PLATFORM_MAC;
310 *---------------------------------------------------------------------------
312 * TclpInitLibraryPath --
314 * Initialize the library path at startup. We have a minor
315 * metacircular problem that we don't know the encoding of the
316 * operating system but we may need to talk to operating system
317 * to find the library directories so that we know how to talk to
318 * the operating system.
320 * We do not know the encoding of the operating system.
321 * We do know that the encoding is some multibyte encoding.
322 * In that multibyte encoding, the characters 0..127 are equivalent
325 * So although we don't know the encoding, it's safe:
326 * to look for the last colon character in a path in the encoding.
327 * to append an ascii string to a path.
328 * to pass those strings back to the operating system.
330 * But any strings that we remembered before we knew the encoding of
331 * the operating system must be translated to UTF-8 once we know the
332 * encoding so that the rest of Tcl can use those strings.
334 * This call sets the library path to strings in the unknown native
335 * encoding. TclpSetInitialEncodings() will translate the library
336 * path from the native encoding to UTF-8 as soon as it determines
337 * what the native encoding actually is.
339 * Called at process initialization time.
342 * Return 1, indicating that the UTF may be dirty and require "cleanup"
343 * after encodings are initialized.
348 *---------------------------------------------------------------------------
352 TclpInitLibraryPath(argv0)
353 CONST char *argv0; /* Name of executable from argv[0] to main().
354 * Not used because we can determine the name
355 * by querying the module handle. */
357 Tcl_Obj *objPtr, *pathPtr;
363 pathPtr = Tcl_NewObj();
366 * Look for the library relative to default encoding dir.
369 str = Tcl_GetDefaultEncodingDir();
370 if ((str != NULL) && (str[0] != '\0')) {
371 objPtr = Tcl_NewStringObj(str, -1);
372 Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
375 str = TclGetEnv("TCL_LIBRARY", &ds);
376 if ((str != NULL) && (str[0] != '\0')) {
378 * If TCL_LIBRARY is set, search there.
381 objPtr = Tcl_NewStringObj(str, Tcl_DStringLength(&ds));
382 Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
383 Tcl_DStringFree(&ds);
386 objPtr = TclGetLibraryPath();
387 if (objPtr != NULL) {
388 Tcl_ListObjAppendList(NULL, pathPtr, objPtr);
392 * lappend path [file join $env(EXT_FOLDER) \
393 * "Tool Command Language" "tcl[info version]"
396 str = TclGetEnv("EXT_FOLDER", &ds);
397 if ((str != NULL) && (str[0] != '\0')) {
398 Tcl_DString libPath, path;
402 argv[1] = "Tool Command Language";
403 Tcl_DStringInit(&libPath);
404 Tcl_DStringAppend(&libPath, "tcl", -1);
405 argv[2] = Tcl_DStringAppend(&libPath, TCL_VERSION, -1);
406 Tcl_DStringInit(&path);
407 str = Tcl_JoinPath(3, argv, &path);
408 objPtr = Tcl_NewStringObj(str, Tcl_DStringLength(&path));
409 Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
410 Tcl_DStringFree(&ds);
411 Tcl_DStringFree(&libPath);
412 Tcl_DStringFree(&path);
414 TclSetLibraryPath(pathPtr);
416 return 1; /* 1 indicates that pathPtr may be dirty utf (needs cleaning) */
420 *---------------------------------------------------------------------------
422 * TclpSetInitialEncodings --
424 * Based on the locale, determine the encoding of the operating
425 * system and the default encoding for newly opened files.
427 * Called at process initialization time, and part way through
428 * startup, we verify that the initial encodings were correctly
429 * setup. Depending on Tcl's environment, there may not have been
430 * enough information first time through (above).
436 * The Tcl library path is converted from native encoding to UTF-8,
437 * on the first call, and the encodings may be changed on first or
440 *---------------------------------------------------------------------------
444 TclpSetInitialEncodings()
446 CONST char *encoding;
451 GetFinderFont(&fontId);
452 encoding = TclMacGetFontEncoding(fontId);
453 if (encoding == NULL) {
454 encoding = "macRoman";
457 err = Tcl_SetSystemEncoding(NULL, encoding);
459 if (err == TCL_OK && libraryPathEncodingFixed == 0) {
462 * Until the system encoding was actually set, the library path was
463 * actually in the native multi-byte encoding, and not really UTF-8
464 * as advertised. We cheated as follows:
466 * 1. It was safe to allow the Tcl_SetSystemEncoding() call to
467 * append the ASCII chars that make up the encoding's filename to
468 * the names (in the native encoding) of directories in the library
469 * path, since all Unix multi-byte encodings have ASCII in the
472 * 2. To open the encoding file, the native bytes in the file name
473 * were passed to the OS, without translating from UTF-8 to native,
474 * because the name was already in the native encoding.
476 * Now that the system encoding was actually successfully set,
477 * translate all the names in the library path to UTF-8. That way,
478 * next time we search the library path, we'll translate the names
479 * from UTF-8 to the system encoding which will be the native
483 pathPtr = TclGetLibraryPath();
484 if (pathPtr != NULL) {
489 Tcl_ListObjGetElements(NULL, pathPtr, &objc, &objv);
490 for (i = 0; i < objc; i++) {
495 string = Tcl_GetStringFromObj(objv[i], &length);
496 Tcl_ExternalToUtfDString(NULL, string, length, &ds);
497 Tcl_SetStringObj(objv[i], Tcl_DStringValue(&ds),
498 Tcl_DStringLength(&ds));
499 Tcl_DStringFree(&ds);
501 Tcl_InvalidateStringRep(pathPtr);
503 libraryPathEncodingFixed = 1;
506 /* This is only ever called from the startup thread */
507 if (binaryEncoding == NULL) {
509 * Keep the iso8859-1 encoding preloaded. The IO package uses
510 * it for gets on a binary channel.
512 binaryEncoding = Tcl_GetEncoding(NULL, "iso8859-1");
517 *---------------------------------------------------------------------------
519 * TclpSetVariables --
521 * Performs platform-specific interpreter initialization related to
522 * the tcl_library and tcl_platform variables, and other platform-
529 * Sets "tcl_library" and "tcl_platform" Tcl variables.
531 *----------------------------------------------------------------------
535 TclpSetVariables(interp)
538 long int gestaltResult;
539 int minor, major, objc;
541 char versStr[2 * TCL_INTEGER_SPACE];
547 pathPtr = TclGetLibraryPath();
548 if (pathPtr != NULL) {
550 Tcl_ListObjGetElements(NULL, pathPtr, &objc, &objv);
552 str = Tcl_GetStringFromObj(objv[0], NULL);
555 Tcl_SetVar(interp, "tcl_library", str, TCL_GLOBAL_ONLY);
557 if (pathPtr != NULL) {
558 Tcl_SetVar2Ex(interp, "tcl_pkgPath", NULL, pathPtr, TCL_GLOBAL_ONLY);
561 Tcl_SetVar2(interp, "tcl_platform", "platform", "macintosh",
563 Tcl_SetVar2(interp, "tcl_platform", "os", "MacOS", TCL_GLOBAL_ONLY);
564 Gestalt(gestaltSystemVersion, &gestaltResult);
565 major = (gestaltResult & 0x0000FF00) >> 8;
566 minor = (gestaltResult & 0x000000F0) >> 4;
567 sprintf(versStr, "%d.%d", major, minor);
568 Tcl_SetVar2(interp, "tcl_platform", "osVersion", versStr, TCL_GLOBAL_ONLY);
569 #if GENERATINGPOWERPC
570 Tcl_SetVar2(interp, "tcl_platform", "machine", "ppc", TCL_GLOBAL_ONLY);
572 Tcl_SetVar2(interp, "tcl_platform", "machine", "68k", TCL_GLOBAL_ONLY);
576 * Copy USER or LOGIN environment variable into tcl_platform(user)
577 * These are set by SystemVariables in tclMacEnv.c
580 Tcl_DStringInit(&ds);
581 str = TclGetEnv("USER", &ds);
583 str = TclGetEnv("LOGIN", &ds);
588 Tcl_SetVar2(interp, "tcl_platform", "user", str, TCL_GLOBAL_ONLY);
589 Tcl_DStringFree(&ds);
593 *----------------------------------------------------------------------
595 * TclpCheckStackSpace --
597 * On a 68K Mac, we can detect if we are about to blow the stack.
598 * Called before an evaluation can happen when nesting depth is
602 * 1 if there is enough stack space to continue; 0 if not.
607 *----------------------------------------------------------------------
611 TclpCheckStackSpace()
613 return StackSpace() > TCL_MAC_STACK_THRESHOLD;
617 *----------------------------------------------------------------------
619 * TclpFindVariable --
621 * Locate the entry in environ for a given name. On Unix and Macthis
622 * routine is case sensitive, on Windows this matches mixed case.
625 * The return value is the index in environ of an entry with the
626 * name "name", or -1 if there is no such entry. The integer at
627 * *lengthPtr is filled in with the length of name (if a matching
628 * entry is found) or the length of the environ array (if no matching
634 *----------------------------------------------------------------------
638 TclpFindVariable(name, lengthPtr)
639 CONST char *name; /* Name of desired environment variable
641 int *lengthPtr; /* Used to return length of name (for
642 * successful searches) or number of non-NULL
643 * entries in environ (for unsuccessful
647 register CONST char *env, *p1, *p2;
648 Tcl_DString envString;
650 Tcl_DStringInit(&envString);
651 for (i = 0, env = environ[i]; env != NULL; i++, env = environ[i]) {
652 p1 = Tcl_ExternalToUtfDString(NULL, env, -1, &envString);
655 for (; *p2 == *p1; p1++, p2++) {
656 /* NULL loop body. */
658 if ((*p1 == '=') && (*p2 == '\0')) {
659 *lengthPtr = p2 - name;
664 Tcl_DStringFree(&envString);
670 Tcl_DStringFree(&envString);
675 *----------------------------------------------------------------------
679 * This procedure is typically invoked by Tcl_AppInit procedures
680 * to perform additional initialization for a Tcl interpreter,
681 * such as sourcing the "init.tcl" script.
684 * Returns a standard Tcl completion code and sets the interp's result
685 * if there is an error.
688 * Depends on what's in the init.tcl script.
690 *----------------------------------------------------------------------
695 Tcl_Interp *interp) /* Interpreter to initialize. */
699 if (tclPreInitScript != NULL) {
700 if (Tcl_Eval(interp, tclPreInitScript) == TCL_ERROR) {
706 * For Macintosh applications the Init function may be contained in
707 * the application resources. If it exists we use it - otherwise we
708 * look in the tcl_library directory. Ditto for the history command.
711 pathPtr = TclGetLibraryPath();
712 if (pathPtr == NULL) {
713 pathPtr = Tcl_NewObj();
715 Tcl_IncrRefCount(pathPtr);
716 Tcl_SetVar2Ex(interp, "auto_path", NULL, pathPtr, TCL_GLOBAL_ONLY);
717 Tcl_DecrRefCount(pathPtr);
718 return Tcl_Eval(interp, initCmd);
722 *----------------------------------------------------------------------
724 * Tcl_SourceRCFile --
726 * This procedure is typically invoked by Tcl_Main or Tk_Main
727 * procedure to source an application specific rc file into the
728 * interpreter at startup time. This will either source a file
729 * in the "tcl_rcFileName" variable or a TEXT resource in the
730 * "tcl_rcRsrcName" variable.
736 * Depends on what's in the rc script.
738 *----------------------------------------------------------------------
743 Tcl_Interp *interp) /* Interpreter to source rc file into. */
746 CONST char *fileName;
747 Tcl_Channel errChannel;
750 fileName = Tcl_GetVar(interp, "tcl_rcFileName", TCL_GLOBAL_ONLY);
752 if (fileName != NULL) {
754 CONST char *fullName;
756 Tcl_DStringInit(&temp);
757 fullName = Tcl_TranslateFileName(interp, fileName, &temp);
758 if (fullName == NULL) {
760 * Couldn't translate the file name (e.g. it referred to a
761 * bogus user or there was no HOME environment variable).
767 * Test for the existence of the rc file before trying to read it.
770 c = Tcl_OpenFileChannel(NULL, fullName, "r", 0);
771 if (c != (Tcl_Channel) NULL) {
773 if (Tcl_EvalFile(interp, fullName) != TCL_OK) {
774 errChannel = Tcl_GetStdChannel(TCL_STDERR);
776 Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
777 Tcl_WriteChars(errChannel, "\n", 1);
782 Tcl_DStringFree(&temp);
785 fileName = Tcl_GetVar(interp, "tcl_rcRsrcName", TCL_GLOBAL_ONLY);
787 if (fileName != NULL) {
790 Tcl_UtfToExternalDString(NULL, fileName, -1, &ds);
791 strcpy((char *) rezName + 1, Tcl_DStringValue(&ds));
792 rezName[0] = (unsigned) Tcl_DStringLength(&ds);
793 h = GetNamedResource('TEXT', rezName);
794 Tcl_DStringFree(&ds);
796 if (Tcl_MacEvalResource(interp, fileName, 0, NULL) != TCL_OK) {
797 errChannel = Tcl_GetStdChannel(TCL_STDERR);
799 Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
800 Tcl_WriteChars(errChannel, "\n", 1);
803 Tcl_ResetResult(interp);