os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/win/tclWinInit.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/* 
sl@0
     2
 * tclWinInit.c --
sl@0
     3
 *
sl@0
     4
 *	Contains the Windows-specific interpreter initialization functions.
sl@0
     5
 *
sl@0
     6
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
sl@0
     7
 * Copyright (c) 1998-1999 by Scriptics Corporation.
sl@0
     8
 * All rights reserved.
sl@0
     9
 *
sl@0
    10
 * RCS: @(#) $Id: tclWinInit.c,v 1.40.2.6 2005/10/23 22:01:31 msofer Exp $
sl@0
    11
 */
sl@0
    12
sl@0
    13
#include "tclWinInt.h"
sl@0
    14
#include <winnt.h>
sl@0
    15
#include <winbase.h>
sl@0
    16
#include <lmcons.h>
sl@0
    17
sl@0
    18
/*
sl@0
    19
 * The following declaration is a workaround for some Microsoft brain damage.
sl@0
    20
 * The SYSTEM_INFO structure is different in various releases, even though the
sl@0
    21
 * layout is the same.  So we overlay our own structure on top of it so we
sl@0
    22
 * can access the interesting slots in a uniform way.
sl@0
    23
 */
sl@0
    24
sl@0
    25
typedef struct {
sl@0
    26
    WORD wProcessorArchitecture;
sl@0
    27
    WORD wReserved;
sl@0
    28
} OemId;
sl@0
    29
sl@0
    30
/*
sl@0
    31
 * The following macros are missing from some versions of winnt.h.
sl@0
    32
 */
sl@0
    33
sl@0
    34
#ifndef PROCESSOR_ARCHITECTURE_INTEL
sl@0
    35
#define PROCESSOR_ARCHITECTURE_INTEL 0
sl@0
    36
#endif
sl@0
    37
#ifndef PROCESSOR_ARCHITECTURE_MIPS
sl@0
    38
#define PROCESSOR_ARCHITECTURE_MIPS  1
sl@0
    39
#endif
sl@0
    40
#ifndef PROCESSOR_ARCHITECTURE_ALPHA
sl@0
    41
#define PROCESSOR_ARCHITECTURE_ALPHA 2
sl@0
    42
#endif
sl@0
    43
#ifndef PROCESSOR_ARCHITECTURE_PPC
sl@0
    44
#define PROCESSOR_ARCHITECTURE_PPC   3
sl@0
    45
#endif
sl@0
    46
#ifndef PROCESSOR_ARCHITECTURE_SHX  
sl@0
    47
#define PROCESSOR_ARCHITECTURE_SHX   4
sl@0
    48
#endif
sl@0
    49
#ifndef PROCESSOR_ARCHITECTURE_ARM
sl@0
    50
#define PROCESSOR_ARCHITECTURE_ARM   5
sl@0
    51
#endif
sl@0
    52
#ifndef PROCESSOR_ARCHITECTURE_IA64
sl@0
    53
#define PROCESSOR_ARCHITECTURE_IA64  6
sl@0
    54
#endif
sl@0
    55
#ifndef PROCESSOR_ARCHITECTURE_ALPHA64
sl@0
    56
#define PROCESSOR_ARCHITECTURE_ALPHA64 7
sl@0
    57
#endif
sl@0
    58
#ifndef PROCESSOR_ARCHITECTURE_MSIL
sl@0
    59
#define PROCESSOR_ARCHITECTURE_MSIL  8
sl@0
    60
#endif
sl@0
    61
#ifndef PROCESSOR_ARCHITECTURE_AMD64
sl@0
    62
#define PROCESSOR_ARCHITECTURE_AMD64 9
sl@0
    63
#endif
sl@0
    64
#ifndef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
sl@0
    65
#define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10
sl@0
    66
#endif
sl@0
    67
#ifndef PROCESSOR_ARCHITECTURE_UNKNOWN
sl@0
    68
#define PROCESSOR_ARCHITECTURE_UNKNOWN 0xFFFF
sl@0
    69
#endif
sl@0
    70
sl@0
    71
/*
sl@0
    72
 * The following arrays contain the human readable strings for the Windows
sl@0
    73
 * platform and processor values.
sl@0
    74
 */
sl@0
    75
sl@0
    76
sl@0
    77
#define NUMPLATFORMS 4
sl@0
    78
static char* platforms[NUMPLATFORMS] = {
sl@0
    79
    "Win32s", "Windows 95", "Windows NT", "Windows CE"
sl@0
    80
};
sl@0
    81
sl@0
    82
#define NUMPROCESSORS 11
sl@0
    83
static char* processors[NUMPROCESSORS] = {
sl@0
    84
    "intel", "mips", "alpha", "ppc", "shx", "arm", "ia64", "alpha64", "msil",
sl@0
    85
    "amd64", "ia32_on_win64"
sl@0
    86
};
sl@0
    87
sl@0
    88
/* Used to store the encoding used for binary files */
sl@0
    89
static Tcl_Encoding binaryEncoding = NULL;
sl@0
    90
/* Has the basic library path encoding issue been fixed */
sl@0
    91
static int libraryPathEncodingFixed = 0;
sl@0
    92
sl@0
    93
/*
sl@0
    94
 * The Init script (common to Windows and Unix platforms) is
sl@0
    95
 * defined in tkInitScript.h
sl@0
    96
 */
sl@0
    97
sl@0
    98
#include "tclInitScript.h"
sl@0
    99
sl@0
   100
static void		AppendEnvironment(Tcl_Obj *listPtr, CONST char *lib);
sl@0
   101
static void		AppendDllPath(Tcl_Obj *listPtr, HMODULE hModule,
sl@0
   102
			    CONST char *lib);
sl@0
   103
static int		ToUtf(CONST WCHAR *wSrc, char *dst);
sl@0
   104

sl@0
   105
/*
sl@0
   106
 *---------------------------------------------------------------------------
sl@0
   107
 *
sl@0
   108
 * TclpInitPlatform --
sl@0
   109
 *
sl@0
   110
 *	Initialize all the platform-dependant things like signals and
sl@0
   111
 *	floating-point error handling.
sl@0
   112
 *
sl@0
   113
 *	Called at process initialization time.
sl@0
   114
 *
sl@0
   115
 * Results:
sl@0
   116
 *	None.
sl@0
   117
 *
sl@0
   118
 * Side effects:
sl@0
   119
 *	None.
sl@0
   120
 *
sl@0
   121
 *---------------------------------------------------------------------------
sl@0
   122
 */
sl@0
   123
sl@0
   124
void
sl@0
   125
TclpInitPlatform()
sl@0
   126
{
sl@0
   127
    tclPlatform = TCL_PLATFORM_WINDOWS;
sl@0
   128
sl@0
   129
    /*
sl@0
   130
     * The following code stops Windows 3.X and Windows NT 3.51 from 
sl@0
   131
     * automatically putting up Sharing Violation dialogs, e.g, when 
sl@0
   132
     * someone tries to access a file that is locked or a drive with no 
sl@0
   133
     * disk in it.  Tcl already returns the appropriate error to the 
sl@0
   134
     * caller, and they can decide to put up their own dialog in response 
sl@0
   135
     * to that failure.  
sl@0
   136
     *
sl@0
   137
     * Under 95 and NT 4.0, this is a NOOP because the system doesn't 
sl@0
   138
     * automatically put up dialogs when the above operations fail.
sl@0
   139
     */
sl@0
   140
sl@0
   141
    SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS);
sl@0
   142
sl@0
   143
#ifdef STATIC_BUILD
sl@0
   144
    /*
sl@0
   145
     * If we are in a statically linked executable, then we need to
sl@0
   146
     * explicitly initialize the Windows function tables here since
sl@0
   147
     * DllMain() will not be invoked.
sl@0
   148
     */
sl@0
   149
sl@0
   150
    TclWinInit(GetModuleHandle(NULL));
sl@0
   151
#endif
sl@0
   152
}
sl@0
   153

sl@0
   154
/*
sl@0
   155
 *---------------------------------------------------------------------------
sl@0
   156
 *
sl@0
   157
 * TclpInitLibraryPath --
sl@0
   158
 *
sl@0
   159
 *	Initialize the library path at startup.  
sl@0
   160
 *
sl@0
   161
 *	This call sets the library path to strings in UTF-8. Any 
sl@0
   162
 *	pre-existing library path information is assumed to have been 
sl@0
   163
 *	in the native multibyte encoding.
sl@0
   164
 *
sl@0
   165
 *	Called at process initialization time.
sl@0
   166
 *
sl@0
   167
 * Results:
sl@0
   168
 *	Return 0, indicating that the UTF is clean.
sl@0
   169
 *
sl@0
   170
 * Side effects:
sl@0
   171
 *	None.
sl@0
   172
 *
sl@0
   173
 *---------------------------------------------------------------------------
sl@0
   174
 */
sl@0
   175
sl@0
   176
int
sl@0
   177
TclpInitLibraryPath(path)
sl@0
   178
    CONST char *path;		/* Potentially dirty UTF string that is */
sl@0
   179
				/* the path to the executable name.     */
sl@0
   180
{
sl@0
   181
#define LIBRARY_SIZE	    32
sl@0
   182
    Tcl_Obj *pathPtr, *objPtr;
sl@0
   183
    CONST char *str;
sl@0
   184
    Tcl_DString ds;
sl@0
   185
    int pathc;
sl@0
   186
    CONST char **pathv;
sl@0
   187
    char installLib[LIBRARY_SIZE], developLib[LIBRARY_SIZE];
sl@0
   188
sl@0
   189
    Tcl_DStringInit(&ds);
sl@0
   190
    pathPtr = Tcl_NewObj();
sl@0
   191
sl@0
   192
    /*
sl@0
   193
     * Initialize the substrings used when locating an executable.  The
sl@0
   194
     * installLib variable computes the path as though the executable
sl@0
   195
     * is installed.  The developLib computes the path as though the
sl@0
   196
     * executable is run from a develpment directory.
sl@0
   197
     */
sl@0
   198
sl@0
   199
    sprintf(installLib, "lib/tcl%s", TCL_VERSION);
sl@0
   200
    sprintf(developLib, "tcl%s/library", TCL_PATCH_LEVEL);
sl@0
   201
sl@0
   202
    /*
sl@0
   203
     * Look for the library relative to default encoding dir.
sl@0
   204
     */
sl@0
   205
sl@0
   206
    str = Tcl_GetDefaultEncodingDir();
sl@0
   207
    if ((str != NULL) && (str[0] != '\0')) {
sl@0
   208
	objPtr = Tcl_NewStringObj(str, -1);
sl@0
   209
	Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
sl@0
   210
    }
sl@0
   211
sl@0
   212
    /*
sl@0
   213
     * Look for the library relative to the TCL_LIBRARY env variable.
sl@0
   214
     * If the last dirname in the TCL_LIBRARY path does not match the
sl@0
   215
     * last dirname in the installLib variable, use the last dir name
sl@0
   216
     * of installLib in addition to the orginal TCL_LIBRARY path.
sl@0
   217
     */
sl@0
   218
sl@0
   219
    AppendEnvironment(pathPtr, installLib);
sl@0
   220
sl@0
   221
    /*
sl@0
   222
     * Look for the library relative to the DLL.  Only use the installLib
sl@0
   223
     * because in practice, the DLL is always installed.
sl@0
   224
     */
sl@0
   225
sl@0
   226
    AppendDllPath(pathPtr, TclWinGetTclInstance(), installLib);
sl@0
   227
    
sl@0
   228
sl@0
   229
    /*
sl@0
   230
     * Look for the library relative to the executable.  This algorithm
sl@0
   231
     * should be the same as the one in the tcl_findLibrary procedure.
sl@0
   232
     *
sl@0
   233
     * This code looks in the following directories:
sl@0
   234
     *
sl@0
   235
     *	<bindir>/../<installLib>
sl@0
   236
     *	  (e.g. /usr/local/bin/../lib/tcl8.4)
sl@0
   237
     *	<bindir>/../../<installLib>
sl@0
   238
     * 	  (e.g. /usr/local/TclPro/solaris-sparc/bin/../../lib/tcl8.4)
sl@0
   239
     *	<bindir>/../library
sl@0
   240
     * 	  (e.g. /usr/src/tcl8.4.0/unix/../library)
sl@0
   241
     *	<bindir>/../../library
sl@0
   242
     *	  (e.g. /usr/src/tcl8.4.0/unix/solaris-sparc/../../library)
sl@0
   243
     *	<bindir>/../../<developLib>
sl@0
   244
     *	  (e.g. /usr/src/tcl8.4.0/unix/../../tcl8.4.0/library)
sl@0
   245
     *	<bindir>/../../../<developLib>
sl@0
   246
     *	   (e.g. /usr/src/tcl8.4.0/unix/solaris-sparc/../../../tcl8.4.0/library)
sl@0
   247
     */
sl@0
   248
     
sl@0
   249
    /*
sl@0
   250
     * The variable path holds an absolute path.  Take care not to
sl@0
   251
     * overwrite pathv[0] since that might produce a relative path.
sl@0
   252
     */
sl@0
   253
sl@0
   254
    if (path != NULL) {
sl@0
   255
	int i, origc;
sl@0
   256
	CONST char **origv;
sl@0
   257
sl@0
   258
	Tcl_SplitPath(path, &origc, &origv);
sl@0
   259
	pathc = 0;
sl@0
   260
	pathv = (CONST char **) ckalloc((unsigned int)(origc * sizeof(char *)));
sl@0
   261
	for (i=0; i< origc; i++) {
sl@0
   262
	    if (origv[i][0] == '.') {
sl@0
   263
		if (strcmp(origv[i], ".") == 0) {
sl@0
   264
		    /* do nothing */
sl@0
   265
		} else if (strcmp(origv[i], "..") == 0) {
sl@0
   266
		    pathc--;
sl@0
   267
		} else {
sl@0
   268
		    pathv[pathc++] = origv[i];
sl@0
   269
		}
sl@0
   270
	    } else {
sl@0
   271
		pathv[pathc++] = origv[i];
sl@0
   272
	    }
sl@0
   273
	}
sl@0
   274
	if (pathc > 2) {
sl@0
   275
	    str = pathv[pathc - 2];
sl@0
   276
	    pathv[pathc - 2] = installLib;
sl@0
   277
	    path = Tcl_JoinPath(pathc - 1, pathv, &ds);
sl@0
   278
	    pathv[pathc - 2] = str;
sl@0
   279
	    objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
sl@0
   280
	    Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
sl@0
   281
	    Tcl_DStringFree(&ds);
sl@0
   282
	}
sl@0
   283
	if (pathc > 3) {
sl@0
   284
	    str = pathv[pathc - 3];
sl@0
   285
	    pathv[pathc - 3] = installLib;
sl@0
   286
	    path = Tcl_JoinPath(pathc - 2, pathv, &ds);
sl@0
   287
	    pathv[pathc - 3] = str;
sl@0
   288
	    objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
sl@0
   289
	    Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
sl@0
   290
	    Tcl_DStringFree(&ds);
sl@0
   291
	}
sl@0
   292
	if (pathc > 2) {
sl@0
   293
	    str = pathv[pathc - 2];
sl@0
   294
	    pathv[pathc - 2] = "library";
sl@0
   295
	    path = Tcl_JoinPath(pathc - 1, pathv, &ds);
sl@0
   296
	    pathv[pathc - 2] = str;
sl@0
   297
	    objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
sl@0
   298
	    Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
sl@0
   299
	    Tcl_DStringFree(&ds);
sl@0
   300
	}
sl@0
   301
	if (pathc > 3) {
sl@0
   302
	    str = pathv[pathc - 3];
sl@0
   303
	    pathv[pathc - 3] = "library";
sl@0
   304
	    path = Tcl_JoinPath(pathc - 2, pathv, &ds);
sl@0
   305
	    pathv[pathc - 3] = str;
sl@0
   306
	    objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
sl@0
   307
	    Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
sl@0
   308
	    Tcl_DStringFree(&ds);
sl@0
   309
	}
sl@0
   310
	if (pathc > 3) {
sl@0
   311
	    str = pathv[pathc - 3];
sl@0
   312
	    pathv[pathc - 3] = developLib;
sl@0
   313
	    path = Tcl_JoinPath(pathc - 2, pathv, &ds);
sl@0
   314
	    pathv[pathc - 3] = str;
sl@0
   315
	    objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
sl@0
   316
	    Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
sl@0
   317
	    Tcl_DStringFree(&ds);
sl@0
   318
	}
sl@0
   319
	if (pathc > 4) {
sl@0
   320
	    str = pathv[pathc - 4];
sl@0
   321
	    pathv[pathc - 4] = developLib;
sl@0
   322
	    path = Tcl_JoinPath(pathc - 3, pathv, &ds);
sl@0
   323
	    pathv[pathc - 4] = str;
sl@0
   324
	    objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
sl@0
   325
	    Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
sl@0
   326
	    Tcl_DStringFree(&ds);
sl@0
   327
	}
sl@0
   328
	ckfree((char *) origv);
sl@0
   329
	ckfree((char *) pathv);
sl@0
   330
    }
sl@0
   331
sl@0
   332
    TclSetLibraryPath(pathPtr);
sl@0
   333
sl@0
   334
    return 0; /* 0 indicates that pathPtr is clean (true) utf */
sl@0
   335
}
sl@0
   336

sl@0
   337
/*
sl@0
   338
 *---------------------------------------------------------------------------
sl@0
   339
 *
sl@0
   340
 * AppendEnvironment --
sl@0
   341
 *
sl@0
   342
 *	Append the value of the TCL_LIBRARY environment variable onto the
sl@0
   343
 *	path pointer.  If the env variable points to another version of
sl@0
   344
 *	tcl (e.g. "tcl7.6") also append the path to this version (e.g.,
sl@0
   345
 *	"tcl7.6/../tcl8.2")
sl@0
   346
 *
sl@0
   347
 * Results:
sl@0
   348
 *	None.
sl@0
   349
 *
sl@0
   350
 * Side effects:
sl@0
   351
 *	None.
sl@0
   352
 *
sl@0
   353
 *---------------------------------------------------------------------------
sl@0
   354
 */
sl@0
   355
sl@0
   356
static void
sl@0
   357
AppendEnvironment(
sl@0
   358
    Tcl_Obj *pathPtr,
sl@0
   359
    CONST char *lib)
sl@0
   360
{
sl@0
   361
    int pathc;
sl@0
   362
    WCHAR wBuf[MAX_PATH];
sl@0
   363
    char buf[MAX_PATH * TCL_UTF_MAX];
sl@0
   364
    Tcl_Obj *objPtr;
sl@0
   365
    Tcl_DString ds;
sl@0
   366
    CONST char **pathv;
sl@0
   367
    char *shortlib;
sl@0
   368
sl@0
   369
    /*
sl@0
   370
     * The shortlib value needs to be the tail component of the
sl@0
   371
     * lib path. For example, "lib/tcl8.4" -> "tcl8.4" while
sl@0
   372
     * "usr/share/tcl8.5" -> "tcl8.5".
sl@0
   373
     */
sl@0
   374
    for (shortlib = (char *) (lib + strlen(lib) - 1); shortlib > lib ; shortlib--) {
sl@0
   375
        if (*shortlib == '/') { 
sl@0
   376
            if (shortlib == (lib + strlen(lib) - 1)) {
sl@0
   377
                Tcl_Panic("last character in lib cannot be '/'");
sl@0
   378
            }
sl@0
   379
            shortlib++;
sl@0
   380
            break;
sl@0
   381
        }
sl@0
   382
    }
sl@0
   383
    if (shortlib == lib) {
sl@0
   384
        Tcl_Panic("no '/' character found in lib");
sl@0
   385
    }
sl@0
   386
sl@0
   387
    /*
sl@0
   388
     * The "L" preceeding the TCL_LIBRARY string is used to tell VC++
sl@0
   389
     * that this is a unicode string.
sl@0
   390
     */
sl@0
   391
    
sl@0
   392
    if (GetEnvironmentVariableW(L"TCL_LIBRARY", wBuf, MAX_PATH) == 0) {
sl@0
   393
        buf[0] = '\0';
sl@0
   394
	GetEnvironmentVariableA("TCL_LIBRARY", buf, MAX_PATH);
sl@0
   395
    } else {
sl@0
   396
	ToUtf(wBuf, buf);
sl@0
   397
    }
sl@0
   398
sl@0
   399
    if (buf[0] != '\0') {
sl@0
   400
	objPtr = Tcl_NewStringObj(buf, -1);
sl@0
   401
	Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
sl@0
   402
sl@0
   403
	TclWinNoBackslash(buf);
sl@0
   404
	Tcl_SplitPath(buf, &pathc, &pathv);
sl@0
   405
sl@0
   406
	/* 
sl@0
   407
	 * The lstrcmpi() will work even if pathv[pathc - 1] is random
sl@0
   408
	 * UTF-8 chars because I know shortlib is ascii.
sl@0
   409
	 */
sl@0
   410
sl@0
   411
	if ((pathc > 0) && (lstrcmpiA(shortlib, pathv[pathc - 1]) != 0)) {
sl@0
   412
	    CONST char *str;
sl@0
   413
	    /*
sl@0
   414
	     * TCL_LIBRARY is set but refers to a different tcl
sl@0
   415
	     * installation than the current version.  Try fiddling with the
sl@0
   416
	     * specified directory to make it refer to this installation by
sl@0
   417
	     * removing the old "tclX.Y" and substituting the current
sl@0
   418
	     * version string.
sl@0
   419
	     */
sl@0
   420
	    
sl@0
   421
	    pathv[pathc - 1] = shortlib;
sl@0
   422
	    Tcl_DStringInit(&ds);
sl@0
   423
	    str = Tcl_JoinPath(pathc, pathv, &ds);
sl@0
   424
	    objPtr = Tcl_NewStringObj(str, Tcl_DStringLength(&ds));
sl@0
   425
	    Tcl_DStringFree(&ds);
sl@0
   426
	} else {
sl@0
   427
	    objPtr = Tcl_NewStringObj(buf, -1);
sl@0
   428
	}
sl@0
   429
	Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
sl@0
   430
	ckfree((char *) pathv);
sl@0
   431
    }
sl@0
   432
}
sl@0
   433

sl@0
   434
/*
sl@0
   435
 *---------------------------------------------------------------------------
sl@0
   436
 *
sl@0
   437
 * AppendDllPath --
sl@0
   438
 *
sl@0
   439
 *	Append a path onto the path pointer that tries to locate the Tcl
sl@0
   440
 *	library relative to the location of the Tcl DLL.
sl@0
   441
 *
sl@0
   442
 * Results:
sl@0
   443
 *	None.
sl@0
   444
 *
sl@0
   445
 * Side effects:
sl@0
   446
 *	None.
sl@0
   447
 *
sl@0
   448
 *---------------------------------------------------------------------------
sl@0
   449
 */
sl@0
   450
sl@0
   451
static void 
sl@0
   452
AppendDllPath(
sl@0
   453
    Tcl_Obj *pathPtr, 
sl@0
   454
    HMODULE hModule,
sl@0
   455
    CONST char *lib)
sl@0
   456
{
sl@0
   457
    WCHAR wName[MAX_PATH + LIBRARY_SIZE];
sl@0
   458
    char name[(MAX_PATH + LIBRARY_SIZE) * TCL_UTF_MAX];
sl@0
   459
sl@0
   460
    if (GetModuleFileNameW(hModule, wName, MAX_PATH) == 0) {
sl@0
   461
	GetModuleFileNameA(hModule, name, MAX_PATH);
sl@0
   462
    } else {
sl@0
   463
	ToUtf(wName, name);
sl@0
   464
    }
sl@0
   465
    if (lib != NULL) {
sl@0
   466
	char *end, *p;
sl@0
   467
sl@0
   468
	end = strrchr(name, '\\');
sl@0
   469
	*end = '\0';
sl@0
   470
	p = strrchr(name, '\\');
sl@0
   471
	if (p != NULL) {
sl@0
   472
	    end = p;
sl@0
   473
	}
sl@0
   474
	*end = '\\';
sl@0
   475
	strcpy(end + 1, lib);
sl@0
   476
    }
sl@0
   477
    TclWinNoBackslash(name);
sl@0
   478
    Tcl_ListObjAppendElement(NULL, pathPtr, Tcl_NewStringObj(name, -1));
sl@0
   479
}
sl@0
   480

sl@0
   481
/*
sl@0
   482
 *---------------------------------------------------------------------------
sl@0
   483
 *
sl@0
   484
 * ToUtf --
sl@0
   485
 *
sl@0
   486
 *	Convert a char string to a UTF string.  
sl@0
   487
 *
sl@0
   488
 * Results:
sl@0
   489
 *	None.
sl@0
   490
 *
sl@0
   491
 * Side effects:
sl@0
   492
 *	None.
sl@0
   493
 *
sl@0
   494
 *---------------------------------------------------------------------------
sl@0
   495
 */
sl@0
   496
sl@0
   497
static int
sl@0
   498
ToUtf(
sl@0
   499
    CONST WCHAR *wSrc,
sl@0
   500
    char *dst)
sl@0
   501
{
sl@0
   502
    char *start;
sl@0
   503
sl@0
   504
    start = dst;
sl@0
   505
    while (*wSrc != '\0') {
sl@0
   506
	dst += Tcl_UniCharToUtf(*wSrc, dst);
sl@0
   507
	wSrc++;
sl@0
   508
    }
sl@0
   509
    *dst = '\0';
sl@0
   510
    return (int) (dst - start);
sl@0
   511
}
sl@0
   512

sl@0
   513
/*
sl@0
   514
 *---------------------------------------------------------------------------
sl@0
   515
 *
sl@0
   516
 * TclWinEncodingsCleanup --
sl@0
   517
 *
sl@0
   518
 *	Reset information to its original state in finalization to
sl@0
   519
 *	allow for reinitialization to be possible.  This must not
sl@0
   520
 *	be called until after the filesystem has been finalised, or
sl@0
   521
 *	exit crashes may occur when using virtual filesystems.
sl@0
   522
 *
sl@0
   523
 * Results:
sl@0
   524
 *	None.
sl@0
   525
 *
sl@0
   526
 * Side effects:
sl@0
   527
 *	Static information reset to startup state.
sl@0
   528
 *
sl@0
   529
 *---------------------------------------------------------------------------
sl@0
   530
 */
sl@0
   531
sl@0
   532
void
sl@0
   533
TclWinEncodingsCleanup()
sl@0
   534
{
sl@0
   535
    TclWinResetInterfaceEncodings();
sl@0
   536
    libraryPathEncodingFixed = 0;
sl@0
   537
    if (binaryEncoding != NULL) {
sl@0
   538
	Tcl_FreeEncoding(binaryEncoding);
sl@0
   539
	binaryEncoding = NULL;
sl@0
   540
    }
sl@0
   541
}
sl@0
   542

sl@0
   543
/*
sl@0
   544
 *---------------------------------------------------------------------------
sl@0
   545
 *
sl@0
   546
 * TclpSetInitialEncodings --
sl@0
   547
 *
sl@0
   548
 *	Based on the locale, determine the encoding of the operating
sl@0
   549
 *	system and the default encoding for newly opened files.
sl@0
   550
 *
sl@0
   551
 *	Called at process initialization time, and part way through
sl@0
   552
 *	startup, we verify that the initial encodings were correctly
sl@0
   553
 *	setup.  Depending on Tcl's environment, there may not have been
sl@0
   554
 *	enough information first time through (above).
sl@0
   555
 *
sl@0
   556
 * Results:
sl@0
   557
 *	None.
sl@0
   558
 *
sl@0
   559
 * Side effects:
sl@0
   560
 *	The Tcl library path is converted from native encoding to UTF-8,
sl@0
   561
 *	on the first call, and the encodings may be changed on first or
sl@0
   562
 *	second call.
sl@0
   563
 *
sl@0
   564
 *---------------------------------------------------------------------------
sl@0
   565
 */
sl@0
   566
sl@0
   567
void
sl@0
   568
TclpSetInitialEncodings()
sl@0
   569
{
sl@0
   570
    CONST char *encoding;
sl@0
   571
    char buf[4 + TCL_INTEGER_SPACE];
sl@0
   572
sl@0
   573
    if (libraryPathEncodingFixed == 0) {
sl@0
   574
	int platformId, useWide;
sl@0
   575
sl@0
   576
	platformId = TclWinGetPlatformId();
sl@0
   577
	useWide = ((platformId == VER_PLATFORM_WIN32_NT)
sl@0
   578
		|| (platformId == VER_PLATFORM_WIN32_CE));
sl@0
   579
	TclWinSetInterfaces(useWide);
sl@0
   580
sl@0
   581
	wsprintfA(buf, "cp%d", GetACP());
sl@0
   582
	Tcl_SetSystemEncoding(NULL, buf);
sl@0
   583
sl@0
   584
	if (!useWide) {
sl@0
   585
	    Tcl_Obj *pathPtr = TclGetLibraryPath();
sl@0
   586
	    if (pathPtr != NULL) {
sl@0
   587
		int i, objc;
sl@0
   588
		Tcl_Obj **objv;
sl@0
   589
		
sl@0
   590
		objc = 0;
sl@0
   591
		Tcl_ListObjGetElements(NULL, pathPtr, &objc, &objv);
sl@0
   592
		for (i = 0; i < objc; i++) {
sl@0
   593
		    int length;
sl@0
   594
		    char *string;
sl@0
   595
		    Tcl_DString ds;
sl@0
   596
sl@0
   597
		    string = Tcl_GetStringFromObj(objv[i], &length);
sl@0
   598
		    Tcl_ExternalToUtfDString(NULL, string, length, &ds);
sl@0
   599
		    Tcl_SetStringObj(objv[i], Tcl_DStringValue(&ds), 
sl@0
   600
			    Tcl_DStringLength(&ds));
sl@0
   601
		    Tcl_DStringFree(&ds);
sl@0
   602
		}
sl@0
   603
	    }
sl@0
   604
	}
sl@0
   605
	
sl@0
   606
	libraryPathEncodingFixed = 1;
sl@0
   607
    } else {
sl@0
   608
	wsprintfA(buf, "cp%d", GetACP());
sl@0
   609
	Tcl_SetSystemEncoding(NULL, buf);
sl@0
   610
    }
sl@0
   611
sl@0
   612
    /* This is only ever called from the startup thread */
sl@0
   613
    if (binaryEncoding == NULL) {
sl@0
   614
	/*
sl@0
   615
	 * Keep this encoding preloaded.  The IO package uses it for
sl@0
   616
	 * gets on a binary channel.
sl@0
   617
	 */
sl@0
   618
	encoding = "iso8859-1";
sl@0
   619
	binaryEncoding = Tcl_GetEncoding(NULL, encoding);
sl@0
   620
    }
sl@0
   621
}
sl@0
   622

sl@0
   623
/*
sl@0
   624
 *---------------------------------------------------------------------------
sl@0
   625
 *
sl@0
   626
 * TclpSetVariables --
sl@0
   627
 *
sl@0
   628
 *	Performs platform-specific interpreter initialization related to
sl@0
   629
 *	the tcl_platform and env variables, and other platform-specific
sl@0
   630
 *	things.
sl@0
   631
 *
sl@0
   632
 * Results:
sl@0
   633
 *	None.
sl@0
   634
 *
sl@0
   635
 * Side effects:
sl@0
   636
 *	Sets "tcl_platform", and "env(HOME)" Tcl variables.
sl@0
   637
 *
sl@0
   638
 *----------------------------------------------------------------------
sl@0
   639
 */
sl@0
   640
sl@0
   641
void
sl@0
   642
TclpSetVariables(interp)
sl@0
   643
    Tcl_Interp *interp;		/* Interp to initialize. */	
sl@0
   644
{	    
sl@0
   645
    CONST char *ptr;
sl@0
   646
    char buffer[TCL_INTEGER_SPACE * 2];
sl@0
   647
    SYSTEM_INFO sysInfo;
sl@0
   648
    OemId *oemId;
sl@0
   649
    OSVERSIONINFOA osInfo;
sl@0
   650
    Tcl_DString ds;
sl@0
   651
    TCHAR szUserName[ UNLEN+1 ];
sl@0
   652
    DWORD dwUserNameLen = sizeof(szUserName);
sl@0
   653
sl@0
   654
    osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
sl@0
   655
    GetVersionExA(&osInfo);
sl@0
   656
sl@0
   657
    oemId = (OemId *) &sysInfo;
sl@0
   658
    GetSystemInfo(&sysInfo);
sl@0
   659
sl@0
   660
    /*
sl@0
   661
     * Define the tcl_platform array.
sl@0
   662
     */
sl@0
   663
sl@0
   664
    Tcl_SetVar2(interp, "tcl_platform", "platform", "windows",
sl@0
   665
	    TCL_GLOBAL_ONLY);
sl@0
   666
    if (osInfo.dwPlatformId < NUMPLATFORMS) {
sl@0
   667
	Tcl_SetVar2(interp, "tcl_platform", "os",
sl@0
   668
		platforms[osInfo.dwPlatformId], TCL_GLOBAL_ONLY);
sl@0
   669
    }
sl@0
   670
    wsprintfA(buffer, "%d.%d", osInfo.dwMajorVersion, osInfo.dwMinorVersion);
sl@0
   671
    Tcl_SetVar2(interp, "tcl_platform", "osVersion", buffer, TCL_GLOBAL_ONLY);
sl@0
   672
    if (oemId->wProcessorArchitecture < NUMPROCESSORS) {
sl@0
   673
	Tcl_SetVar2(interp, "tcl_platform", "machine",
sl@0
   674
		processors[oemId->wProcessorArchitecture],
sl@0
   675
		TCL_GLOBAL_ONLY);
sl@0
   676
    }
sl@0
   677
sl@0
   678
#ifdef _DEBUG
sl@0
   679
    /*
sl@0
   680
     * The existence of the "debug" element of the tcl_platform array indicates
sl@0
   681
     * that this particular Tcl shell has been compiled with debug information.
sl@0
   682
     * Using "info exists tcl_platform(debug)" a Tcl script can direct the 
sl@0
   683
     * interpreter to load debug versions of DLLs with the load command.
sl@0
   684
     */
sl@0
   685
sl@0
   686
    Tcl_SetVar2(interp, "tcl_platform", "debug", "1",
sl@0
   687
	    TCL_GLOBAL_ONLY);
sl@0
   688
#endif
sl@0
   689
sl@0
   690
    /*
sl@0
   691
     * Set up the HOME environment variable from the HOMEDRIVE & HOMEPATH
sl@0
   692
     * environment variables, if necessary.
sl@0
   693
     */
sl@0
   694
sl@0
   695
    Tcl_DStringInit(&ds);
sl@0
   696
    ptr = Tcl_GetVar2(interp, "env", "HOME", TCL_GLOBAL_ONLY);
sl@0
   697
    if (ptr == NULL) {
sl@0
   698
	ptr = Tcl_GetVar2(interp, "env", "HOMEDRIVE", TCL_GLOBAL_ONLY);
sl@0
   699
	if (ptr != NULL) {
sl@0
   700
	    Tcl_DStringAppend(&ds, ptr, -1);
sl@0
   701
	}
sl@0
   702
	ptr = Tcl_GetVar2(interp, "env", "HOMEPATH", TCL_GLOBAL_ONLY);
sl@0
   703
	if (ptr != NULL) {
sl@0
   704
	    Tcl_DStringAppend(&ds, ptr, -1);
sl@0
   705
	}
sl@0
   706
	if (Tcl_DStringLength(&ds) > 0) {
sl@0
   707
	    Tcl_SetVar2(interp, "env", "HOME", Tcl_DStringValue(&ds),
sl@0
   708
		    TCL_GLOBAL_ONLY);
sl@0
   709
	} else {
sl@0
   710
	    Tcl_SetVar2(interp, "env", "HOME", "c:\\", TCL_GLOBAL_ONLY);
sl@0
   711
	}
sl@0
   712
    }
sl@0
   713
sl@0
   714
    /*
sl@0
   715
     * Initialize the user name from the environment first, since this is much
sl@0
   716
     * faster than asking the system.
sl@0
   717
     */
sl@0
   718
sl@0
   719
    Tcl_DStringInit( &ds );
sl@0
   720
    if (TclGetEnv("USERNAME", &ds) == NULL) {
sl@0
   721
sl@0
   722
	if ( GetUserName( szUserName, &dwUserNameLen ) != 0 ) {
sl@0
   723
	    Tcl_WinTCharToUtf( szUserName, dwUserNameLen, &ds );
sl@0
   724
	}	
sl@0
   725
    }
sl@0
   726
    Tcl_SetVar2(interp, "tcl_platform", "user", Tcl_DStringValue(&ds),
sl@0
   727
	    TCL_GLOBAL_ONLY);
sl@0
   728
    Tcl_DStringFree(&ds);
sl@0
   729
}
sl@0
   730

sl@0
   731
/*
sl@0
   732
 *----------------------------------------------------------------------
sl@0
   733
 *
sl@0
   734
 * TclpFindVariable --
sl@0
   735
 *
sl@0
   736
 *	Locate the entry in environ for a given name.  On Unix this 
sl@0
   737
 *	routine is case sensetive, on Windows this matches mioxed case.
sl@0
   738
 *
sl@0
   739
 * Results:
sl@0
   740
 *	The return value is the index in environ of an entry with the
sl@0
   741
 *	name "name", or -1 if there is no such entry.   The integer at
sl@0
   742
 *	*lengthPtr is filled in with the length of name (if a matching
sl@0
   743
 *	entry is found) or the length of the environ array (if no matching
sl@0
   744
 *	entry is found).
sl@0
   745
 *
sl@0
   746
 * Side effects:
sl@0
   747
 *	None.
sl@0
   748
 *
sl@0
   749
 *----------------------------------------------------------------------
sl@0
   750
 */
sl@0
   751
sl@0
   752
int
sl@0
   753
TclpFindVariable(name, lengthPtr)
sl@0
   754
    CONST char *name;		/* Name of desired environment variable
sl@0
   755
				 * (UTF-8). */
sl@0
   756
    int *lengthPtr;		/* Used to return length of name (for
sl@0
   757
				 * successful searches) or number of non-NULL
sl@0
   758
				 * entries in environ (for unsuccessful
sl@0
   759
				 * searches). */
sl@0
   760
{
sl@0
   761
    int i, length, result = -1;
sl@0
   762
    register CONST char *env, *p1, *p2;
sl@0
   763
    char *envUpper, *nameUpper;
sl@0
   764
    Tcl_DString envString;
sl@0
   765
sl@0
   766
    /*
sl@0
   767
     * Convert the name to all upper case for the case insensitive
sl@0
   768
     * comparison.
sl@0
   769
     */
sl@0
   770
sl@0
   771
    length = strlen(name);
sl@0
   772
    nameUpper = (char *) ckalloc((unsigned) length+1);
sl@0
   773
    memcpy((VOID *) nameUpper, (VOID *) name, (size_t) length+1);
sl@0
   774
    Tcl_UtfToUpper(nameUpper);
sl@0
   775
    
sl@0
   776
    Tcl_DStringInit(&envString);
sl@0
   777
    for (i = 0, env = environ[i]; env != NULL; i++, env = environ[i]) {
sl@0
   778
	/*
sl@0
   779
	 * Chop the env string off after the equal sign, then Convert
sl@0
   780
	 * the name to all upper case, so we do not have to convert
sl@0
   781
	 * all the characters after the equal sign.
sl@0
   782
	 */
sl@0
   783
	
sl@0
   784
	envUpper = Tcl_ExternalToUtfDString(NULL, env, -1, &envString);
sl@0
   785
	p1 = strchr(envUpper, '=');
sl@0
   786
	if (p1 == NULL) {
sl@0
   787
	    continue;
sl@0
   788
	}
sl@0
   789
	length = (int) (p1 - envUpper);
sl@0
   790
	Tcl_DStringSetLength(&envString, length+1);
sl@0
   791
	Tcl_UtfToUpper(envUpper);
sl@0
   792
sl@0
   793
	p1 = envUpper;
sl@0
   794
	p2 = nameUpper;
sl@0
   795
	for (; *p2 == *p1; p1++, p2++) {
sl@0
   796
	    /* NULL loop body. */
sl@0
   797
	}
sl@0
   798
	if ((*p1 == '=') && (*p2 == '\0')) {
sl@0
   799
	    *lengthPtr = length;
sl@0
   800
	    result = i;
sl@0
   801
	    goto done;
sl@0
   802
	}
sl@0
   803
	
sl@0
   804
	Tcl_DStringFree(&envString);
sl@0
   805
    }
sl@0
   806
    
sl@0
   807
    *lengthPtr = i;
sl@0
   808
sl@0
   809
    done:
sl@0
   810
    Tcl_DStringFree(&envString);
sl@0
   811
    ckfree(nameUpper);
sl@0
   812
    return result;
sl@0
   813
}
sl@0
   814

sl@0
   815
/*
sl@0
   816
 *----------------------------------------------------------------------
sl@0
   817
 *
sl@0
   818
 * Tcl_Init --
sl@0
   819
 *
sl@0
   820
 *	This procedure is typically invoked by Tcl_AppInit procedures
sl@0
   821
 *	to perform additional initialization for a Tcl interpreter,
sl@0
   822
 *	such as sourcing the "init.tcl" script.
sl@0
   823
 *
sl@0
   824
 * Results:
sl@0
   825
 *	Returns a standard Tcl completion code and sets the interp's
sl@0
   826
 *	result if there is an error.
sl@0
   827
 *
sl@0
   828
 * Side effects:
sl@0
   829
 *	Depends on what's in the init.tcl script.
sl@0
   830
 *
sl@0
   831
 *----------------------------------------------------------------------
sl@0
   832
 */
sl@0
   833
sl@0
   834
int
sl@0
   835
Tcl_Init(interp)
sl@0
   836
    Tcl_Interp *interp;		/* Interpreter to initialize. */
sl@0
   837
{
sl@0
   838
    Tcl_Obj *pathPtr;
sl@0
   839
sl@0
   840
    if (tclPreInitScript != NULL) {
sl@0
   841
	if (Tcl_Eval(interp, tclPreInitScript) == TCL_ERROR) {
sl@0
   842
	    return (TCL_ERROR);
sl@0
   843
	};
sl@0
   844
    }
sl@0
   845
sl@0
   846
    pathPtr = TclGetLibraryPath();
sl@0
   847
    if (pathPtr == NULL) {
sl@0
   848
	pathPtr = Tcl_NewObj();
sl@0
   849
    }
sl@0
   850
    Tcl_IncrRefCount(pathPtr);    
sl@0
   851
    Tcl_SetVar2Ex(interp, "tcl_libPath", NULL, pathPtr, TCL_GLOBAL_ONLY);
sl@0
   852
    Tcl_DecrRefCount(pathPtr);    
sl@0
   853
    return Tcl_Eval(interp, initScript);
sl@0
   854
}
sl@0
   855

sl@0
   856
/*
sl@0
   857
 *----------------------------------------------------------------------
sl@0
   858
 *
sl@0
   859
 * Tcl_SourceRCFile --
sl@0
   860
 *
sl@0
   861
 *	This procedure is typically invoked by Tcl_Main of Tk_Main
sl@0
   862
 *	procedure to source an application specific rc file into the
sl@0
   863
 *	interpreter at startup time.
sl@0
   864
 *
sl@0
   865
 * Results:
sl@0
   866
 *	None.
sl@0
   867
 *
sl@0
   868
 * Side effects:
sl@0
   869
 *	Depends on what's in the rc script.
sl@0
   870
 *
sl@0
   871
 *----------------------------------------------------------------------
sl@0
   872
 */
sl@0
   873
sl@0
   874
void
sl@0
   875
Tcl_SourceRCFile(interp)
sl@0
   876
    Tcl_Interp *interp;		/* Interpreter to source rc file into. */
sl@0
   877
{
sl@0
   878
    Tcl_DString temp;
sl@0
   879
    CONST char *fileName;
sl@0
   880
    Tcl_Channel errChannel;
sl@0
   881
sl@0
   882
    fileName = Tcl_GetVar(interp, "tcl_rcFileName", TCL_GLOBAL_ONLY);
sl@0
   883
sl@0
   884
    if (fileName != NULL) {
sl@0
   885
        Tcl_Channel c;
sl@0
   886
	CONST char *fullName;
sl@0
   887
sl@0
   888
        Tcl_DStringInit(&temp);
sl@0
   889
	fullName = Tcl_TranslateFileName(interp, fileName, &temp);
sl@0
   890
	if (fullName == NULL) {
sl@0
   891
	    /*
sl@0
   892
	     * Couldn't translate the file name (e.g. it referred to a
sl@0
   893
	     * bogus user or there was no HOME environment variable).
sl@0
   894
	     * Just do nothing.
sl@0
   895
	     */
sl@0
   896
	} else {
sl@0
   897
sl@0
   898
	    /*
sl@0
   899
	     * Test for the existence of the rc file before trying to read it.
sl@0
   900
	     */
sl@0
   901
sl@0
   902
            c = Tcl_OpenFileChannel(NULL, fullName, "r", 0);
sl@0
   903
            if (c != (Tcl_Channel) NULL) {
sl@0
   904
                Tcl_Close(NULL, c);
sl@0
   905
		if (Tcl_EvalFile(interp, fullName) != TCL_OK) {
sl@0
   906
		    errChannel = Tcl_GetStdChannel(TCL_STDERR);
sl@0
   907
		    if (errChannel) {
sl@0
   908
			Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
sl@0
   909
			Tcl_WriteChars(errChannel, "\n", 1);
sl@0
   910
		    }
sl@0
   911
		}
sl@0
   912
	    }
sl@0
   913
	}
sl@0
   914
        Tcl_DStringFree(&temp);
sl@0
   915
    }
sl@0
   916
}