os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/win/tclWin32Dll.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
 * tclWin32Dll.c --
sl@0
     3
 *
sl@0
     4
 *	This file contains the DLL entry point.
sl@0
     5
 *
sl@0
     6
 * Copyright (c) 1995-1996 Sun Microsystems, Inc.
sl@0
     7
 * Copyright (c) 1998-2000 Scriptics Corporation.
sl@0
     8
 *
sl@0
     9
 * See the file "license.terms" for information on usage and redistribution
sl@0
    10
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    11
 *
sl@0
    12
 * RCS: @(#) $Id: tclWin32Dll.c,v 1.24.2.10 2006/10/17 04:36:45 dgp Exp $
sl@0
    13
 */
sl@0
    14
sl@0
    15
#include "tclWinInt.h"
sl@0
    16
sl@0
    17
/*
sl@0
    18
 * The following data structures are used when loading the thunking 
sl@0
    19
 * library for execing child processes under Win32s.
sl@0
    20
 */
sl@0
    21
sl@0
    22
typedef DWORD (WINAPI UT32PROC)(LPVOID lpBuff, DWORD dwUserDefined,
sl@0
    23
	LPVOID *lpTranslationList);
sl@0
    24
sl@0
    25
typedef BOOL (WINAPI UTREGISTER)(HANDLE hModule, LPCSTR SixteenBitDLL,
sl@0
    26
	LPCSTR InitName, LPCSTR ProcName, UT32PROC **ThirtyTwoBitThunk,
sl@0
    27
	FARPROC UT32Callback, LPVOID Buff);
sl@0
    28
sl@0
    29
typedef VOID (WINAPI UTUNREGISTER)(HANDLE hModule);
sl@0
    30
sl@0
    31
/* 
sl@0
    32
 * The following variables keep track of information about this DLL
sl@0
    33
 * on a per-instance basis.  Each time this DLL is loaded, it gets its own 
sl@0
    34
 * new data segment with its own copy of all static and global information.
sl@0
    35
 */
sl@0
    36
sl@0
    37
static HINSTANCE hInstance;	/* HINSTANCE of this DLL. */
sl@0
    38
static int platformId;		/* Running under NT, or 95/98? */
sl@0
    39
sl@0
    40
#ifdef HAVE_NO_SEH
sl@0
    41
sl@0
    42
/*
sl@0
    43
 * Unlike Borland and Microsoft, we don't register exception handlers
sl@0
    44
 * by pushing registration records onto the runtime stack.  Instead, we
sl@0
    45
 * register them by creating an EXCEPTION_REGISTRATION within the activation
sl@0
    46
 * record.
sl@0
    47
 */
sl@0
    48
sl@0
    49
typedef struct EXCEPTION_REGISTRATION {
sl@0
    50
    struct EXCEPTION_REGISTRATION* link;
sl@0
    51
    EXCEPTION_DISPOSITION (*handler)( struct _EXCEPTION_RECORD*, void*,
sl@0
    52
				      struct _CONTEXT*, void* );
sl@0
    53
    void* ebp;
sl@0
    54
    void* esp;
sl@0
    55
    int status;
sl@0
    56
} EXCEPTION_REGISTRATION;
sl@0
    57
sl@0
    58
#endif
sl@0
    59
sl@0
    60
/*
sl@0
    61
 * VC++ 5.x has no 'cpuid' assembler instruction, so we
sl@0
    62
 * must emulate it
sl@0
    63
 */
sl@0
    64
#if defined(_MSC_VER) && ( _MSC_VER <= 1100 )
sl@0
    65
#define cpuid __asm __emit 0fh __asm __emit 0a2h
sl@0
    66
#endif
sl@0
    67
sl@0
    68
/*
sl@0
    69
 * The following function tables are used to dispatch to either the
sl@0
    70
 * wide-character or multi-byte versions of the operating system calls,
sl@0
    71
 * depending on whether the Unicode calls are available.
sl@0
    72
 */
sl@0
    73
sl@0
    74
static TclWinProcs asciiProcs = {
sl@0
    75
    0,
sl@0
    76
sl@0
    77
    (BOOL (WINAPI *)(CONST TCHAR *, LPDCB)) BuildCommDCBA,
sl@0
    78
    (TCHAR *(WINAPI *)(TCHAR *)) CharLowerA,
sl@0
    79
    (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *, BOOL)) CopyFileA,
sl@0
    80
    (BOOL (WINAPI *)(CONST TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectoryA,
sl@0
    81
    (HANDLE (WINAPI *)(CONST TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *, 
sl@0
    82
	    DWORD, DWORD, HANDLE)) CreateFileA,
sl@0
    83
    (BOOL (WINAPI *)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES, 
sl@0
    84
	    LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *, 
sl@0
    85
	    LPSTARTUPINFOA, LPPROCESS_INFORMATION)) CreateProcessA,
sl@0
    86
    (BOOL (WINAPI *)(CONST TCHAR *)) DeleteFileA,
sl@0
    87
    (HANDLE (WINAPI *)(CONST TCHAR *, WIN32_FIND_DATAT *)) FindFirstFileA,
sl@0
    88
    (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFileA,
sl@0
    89
    (BOOL (WINAPI *)(WCHAR *, LPDWORD)) GetComputerNameA,
sl@0
    90
    (DWORD (WINAPI *)(DWORD, WCHAR *)) GetCurrentDirectoryA,
sl@0
    91
    (DWORD (WINAPI *)(CONST TCHAR *)) GetFileAttributesA,
sl@0
    92
    (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, 
sl@0
    93
	    TCHAR **)) GetFullPathNameA,
sl@0
    94
    (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameA,
sl@0
    95
    (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameA,
sl@0
    96
    (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique, 
sl@0
    97
	    WCHAR *)) GetTempFileNameA,
sl@0
    98
    (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathA,
sl@0
    99
    (BOOL (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD,
sl@0
   100
	    WCHAR *, DWORD)) GetVolumeInformationA,
sl@0
   101
    (HINSTANCE (WINAPI *)(CONST TCHAR *)) LoadLibraryA,
sl@0
   102
    (TCHAR (WINAPI *)(WCHAR *, CONST TCHAR *)) lstrcpyA,
sl@0
   103
    (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileA,
sl@0
   104
    (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryA,
sl@0
   105
    (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD, 
sl@0
   106
	    WCHAR *, TCHAR **)) SearchPathA,
sl@0
   107
    (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryA,
sl@0
   108
    (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesA,
sl@0
   109
    /* 
sl@0
   110
     * The three NULL function pointers will only be set when
sl@0
   111
     * Tcl_FindExecutable is called.  If you don't ever call that
sl@0
   112
     * function, the application will crash whenever WinTcl tries to call
sl@0
   113
     * functions through these null pointers.  That is not a bug in Tcl
sl@0
   114
     * -- Tcl_FindExecutable is obligatory in recent Tcl releases.
sl@0
   115
     */
sl@0
   116
    NULL,
sl@0
   117
    NULL,
sl@0
   118
    (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _utime,
sl@0
   119
    NULL,
sl@0
   120
    NULL,
sl@0
   121
    /* getLongPathNameProc */
sl@0
   122
    NULL,
sl@0
   123
    /* Security SDK - not available on 95,98,ME */
sl@0
   124
    NULL, NULL, NULL, NULL, NULL, NULL,
sl@0
   125
    /* ReadConsole and WriteConsole */
sl@0
   126
    (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsoleA,
sl@0
   127
    (BOOL (WINAPI *)(HANDLE, const VOID*, DWORD, LPDWORD, LPVOID)) WriteConsoleA    
sl@0
   128
};
sl@0
   129
sl@0
   130
static TclWinProcs unicodeProcs = {
sl@0
   131
    1,
sl@0
   132
sl@0
   133
    (BOOL (WINAPI *)(CONST TCHAR *, LPDCB)) BuildCommDCBW,
sl@0
   134
    (TCHAR *(WINAPI *)(TCHAR *)) CharLowerW,
sl@0
   135
    (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *, BOOL)) CopyFileW,
sl@0
   136
    (BOOL (WINAPI *)(CONST TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectoryW,
sl@0
   137
    (HANDLE (WINAPI *)(CONST TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *, 
sl@0
   138
	    DWORD, DWORD, HANDLE)) CreateFileW,
sl@0
   139
    (BOOL (WINAPI *)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES, 
sl@0
   140
	    LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *, 
sl@0
   141
	    LPSTARTUPINFOA, LPPROCESS_INFORMATION)) CreateProcessW,
sl@0
   142
    (BOOL (WINAPI *)(CONST TCHAR *)) DeleteFileW,
sl@0
   143
    (HANDLE (WINAPI *)(CONST TCHAR *, WIN32_FIND_DATAT *)) FindFirstFileW,
sl@0
   144
    (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFileW,
sl@0
   145
    (BOOL (WINAPI *)(WCHAR *, LPDWORD)) GetComputerNameW,
sl@0
   146
    (DWORD (WINAPI *)(DWORD, WCHAR *)) GetCurrentDirectoryW,
sl@0
   147
    (DWORD (WINAPI *)(CONST TCHAR *)) GetFileAttributesW,
sl@0
   148
    (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, 
sl@0
   149
	    TCHAR **)) GetFullPathNameW,
sl@0
   150
    (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameW,
sl@0
   151
    (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameW,
sl@0
   152
    (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique, 
sl@0
   153
	    WCHAR *)) GetTempFileNameW,
sl@0
   154
    (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathW,
sl@0
   155
    (BOOL (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD, 
sl@0
   156
	    WCHAR *, DWORD)) GetVolumeInformationW,
sl@0
   157
    (HINSTANCE (WINAPI *)(CONST TCHAR *)) LoadLibraryW,
sl@0
   158
    (TCHAR (WINAPI *)(WCHAR *, CONST TCHAR *)) lstrcpyW,
sl@0
   159
    (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileW,
sl@0
   160
    (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryW,
sl@0
   161
    (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD, 
sl@0
   162
	    WCHAR *, TCHAR **)) SearchPathW,
sl@0
   163
    (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryW,
sl@0
   164
    (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesW,
sl@0
   165
    /* 
sl@0
   166
     * The three NULL function pointers will only be set when
sl@0
   167
     * Tcl_FindExecutable is called.  If you don't ever call that
sl@0
   168
     * function, the application will crash whenever WinTcl tries to call
sl@0
   169
     * functions through these null pointers.  That is not a bug in Tcl
sl@0
   170
     * -- Tcl_FindExecutable is obligatory in recent Tcl releases.
sl@0
   171
     */
sl@0
   172
    NULL,
sl@0
   173
    NULL,
sl@0
   174
    (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _wutime,
sl@0
   175
    NULL,
sl@0
   176
    NULL,
sl@0
   177
    /* getLongPathNameProc */
sl@0
   178
    NULL,
sl@0
   179
    /* Security SDK - will be filled in on NT,XP,2000,2003 */
sl@0
   180
    NULL, NULL, NULL, NULL, NULL, NULL,
sl@0
   181
    /* ReadConsole and WriteConsole */
sl@0
   182
    (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsoleW,
sl@0
   183
    (BOOL (WINAPI *)(HANDLE, const VOID*, DWORD, LPDWORD, LPVOID)) WriteConsoleW
sl@0
   184
};
sl@0
   185
sl@0
   186
TclWinProcs *tclWinProcs;
sl@0
   187
static Tcl_Encoding tclWinTCharEncoding;
sl@0
   188
sl@0
   189
sl@0
   190
#ifdef HAVE_NO_SEH
sl@0
   191
sl@0
   192
/* Need to add noinline flag to DllMain declaration so that gcc -O3
sl@0
   193
 * does not inline asm code into DllEntryPoint and cause a
sl@0
   194
 * compile time error because of redefined local labels.
sl@0
   195
 */
sl@0
   196
sl@0
   197
BOOL APIENTRY		DllMain(HINSTANCE hInst, DWORD reason, 
sl@0
   198
				LPVOID reserved)
sl@0
   199
                        __attribute__ ((noinline));
sl@0
   200
sl@0
   201
#else
sl@0
   202
sl@0
   203
/*
sl@0
   204
 * The following declaration is for the VC++ DLL entry point.
sl@0
   205
 */
sl@0
   206
sl@0
   207
BOOL APIENTRY		DllMain(HINSTANCE hInst, DWORD reason, 
sl@0
   208
				LPVOID reserved);
sl@0
   209
#endif /* HAVE_NO_SEH */
sl@0
   210
sl@0
   211
sl@0
   212
/*
sl@0
   213
 * The following structure and linked list is to allow us to map between
sl@0
   214
 * volume mount points and drive letters on the fly (no Win API exists
sl@0
   215
 * for this).
sl@0
   216
 */
sl@0
   217
typedef struct MountPointMap {
sl@0
   218
    CONST WCHAR* volumeName;       /* Native wide string volume name */
sl@0
   219
    char driveLetter;              /* Drive letter corresponding to
sl@0
   220
                                    * the volume name. */
sl@0
   221
    struct MountPointMap* nextPtr; /* Pointer to next structure in list,
sl@0
   222
                                    * or NULL */
sl@0
   223
} MountPointMap;
sl@0
   224
sl@0
   225
/* 
sl@0
   226
 * This is the head of the linked list, which is protected by the
sl@0
   227
 * mutex which follows, for thread-enabled builds.
sl@0
   228
 */
sl@0
   229
MountPointMap *driveLetterLookup = NULL;
sl@0
   230
TCL_DECLARE_MUTEX(mountPointMap)
sl@0
   231
sl@0
   232
/* We will need this below */
sl@0
   233
extern Tcl_FSDupInternalRepProc TclNativeDupInternalRep;
sl@0
   234
sl@0
   235
#ifdef __WIN32__
sl@0
   236
#ifndef STATIC_BUILD
sl@0
   237
sl@0
   238

sl@0
   239
/*
sl@0
   240
 *----------------------------------------------------------------------
sl@0
   241
 *
sl@0
   242
 * DllEntryPoint --
sl@0
   243
 *
sl@0
   244
 *	This wrapper function is used by Borland to invoke the
sl@0
   245
 *	initialization code for Tcl.  It simply calls the DllMain
sl@0
   246
 *	routine.
sl@0
   247
 *
sl@0
   248
 * Results:
sl@0
   249
 *	See DllMain.
sl@0
   250
 *
sl@0
   251
 * Side effects:
sl@0
   252
 *	See DllMain.
sl@0
   253
 *
sl@0
   254
 *----------------------------------------------------------------------
sl@0
   255
 */
sl@0
   256
sl@0
   257
BOOL APIENTRY
sl@0
   258
DllEntryPoint(hInst, reason, reserved)
sl@0
   259
    HINSTANCE hInst;		/* Library instance handle. */
sl@0
   260
    DWORD reason;		/* Reason this function is being called. */
sl@0
   261
    LPVOID reserved;		/* Not used. */
sl@0
   262
{
sl@0
   263
    return DllMain(hInst, reason, reserved);
sl@0
   264
}
sl@0
   265

sl@0
   266
/*
sl@0
   267
 *----------------------------------------------------------------------
sl@0
   268
 *
sl@0
   269
 * DllMain --
sl@0
   270
 *
sl@0
   271
 *	This routine is called by the VC++ C run time library init
sl@0
   272
 *	code, or the DllEntryPoint routine.  It is responsible for
sl@0
   273
 *	initializing various dynamically loaded libraries.
sl@0
   274
 *
sl@0
   275
 * Results:
sl@0
   276
 *	TRUE on sucess, FALSE on failure.
sl@0
   277
 *
sl@0
   278
 * Side effects:
sl@0
   279
 *	Establishes 32-to-16 bit thunk and initializes sockets library.
sl@0
   280
 *
sl@0
   281
 *----------------------------------------------------------------------
sl@0
   282
 */
sl@0
   283
BOOL APIENTRY
sl@0
   284
DllMain(hInst, reason, reserved)
sl@0
   285
    HINSTANCE hInst;		/* Library instance handle. */
sl@0
   286
    DWORD reason;		/* Reason this function is being called. */
sl@0
   287
    LPVOID reserved;		/* Not used. */
sl@0
   288
{
sl@0
   289
#ifdef HAVE_NO_SEH
sl@0
   290
    EXCEPTION_REGISTRATION registration;
sl@0
   291
#endif
sl@0
   292
sl@0
   293
    switch (reason) {
sl@0
   294
    case DLL_PROCESS_ATTACH:
sl@0
   295
	DisableThreadLibraryCalls(hInst);
sl@0
   296
	TclWinInit(hInst);
sl@0
   297
	return TRUE;
sl@0
   298
sl@0
   299
    case DLL_PROCESS_DETACH:
sl@0
   300
	/*
sl@0
   301
	 * Protect the call to Tcl_Finalize.  The OS could be unloading
sl@0
   302
	 * us from an exception handler and the state of the stack might
sl@0
   303
	 * be unstable.
sl@0
   304
	 */
sl@0
   305
#ifdef HAVE_NO_SEH
sl@0
   306
        __asm__ __volatile__ (
sl@0
   307
sl@0
   308
            /*
sl@0
   309
             * Construct an EXCEPTION_REGISTRATION to protect the
sl@0
   310
             * call to Tcl_Finalize
sl@0
   311
             */
sl@0
   312
            "leal       %[registration], %%edx"         "\n\t"
sl@0
   313
            "movl       %%fs:0,         %%eax"          "\n\t"
sl@0
   314
            "movl       %%eax,          0x0(%%edx)"     "\n\t" /* link */
sl@0
   315
            "leal       1f,             %%eax"          "\n\t"
sl@0
   316
            "movl       %%eax,          0x4(%%edx)"     "\n\t" /* handler */
sl@0
   317
            "movl       %%ebp,          0x8(%%edx)"     "\n\t" /* ebp */
sl@0
   318
            "movl       %%esp,          0xc(%%edx)"     "\n\t" /* esp */
sl@0
   319
            "movl       %[error],       0x10(%%edx)"    "\n\t" /* status */
sl@0
   320
sl@0
   321
            /*
sl@0
   322
             * Link the EXCEPTION_REGISTRATION on the chain
sl@0
   323
             */
sl@0
   324
            "movl       %%edx,          %%fs:0"         "\n\t"
sl@0
   325
sl@0
   326
            /*
sl@0
   327
             * Call Tcl_Finalize
sl@0
   328
             */
sl@0
   329
            "call       _Tcl_Finalize"                  "\n\t"
sl@0
   330
sl@0
   331
            /*
sl@0
   332
             * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION
sl@0
   333
             * and store a TCL_OK status
sl@0
   334
             */
sl@0
   335
sl@0
   336
            "movl       %%fs:0,         %%edx"          "\n\t"
sl@0
   337
            "movl       %[ok],          %%eax"          "\n\t"
sl@0
   338
            "movl       %%eax,          0x10(%%edx)"    "\n\t"
sl@0
   339
            "jmp        2f"                             "\n"
sl@0
   340
sl@0
   341
            /*
sl@0
   342
             * Come here on an exception. Get the EXCEPTION_REGISTRATION
sl@0
   343
             * that we previously put on the chain.
sl@0
   344
             */
sl@0
   345
sl@0
   346
            "1:"                                        "\t"
sl@0
   347
            "movl       %%fs:0,         %%edx"          "\n\t"
sl@0
   348
            "movl       0x8(%%edx),     %%edx"          "\n"
sl@0
   349
sl@0
   350
sl@0
   351
            /* 
sl@0
   352
             * Come here however we exited.  Restore context from the
sl@0
   353
             * EXCEPTION_REGISTRATION in case the stack is unbalanced.
sl@0
   354
             */
sl@0
   355
sl@0
   356
            "2:"                                        "\t"
sl@0
   357
            "movl       0xc(%%edx),     %%esp"          "\n\t"
sl@0
   358
            "movl       0x8(%%edx),     %%ebp"          "\n\t"
sl@0
   359
            "movl       0x0(%%edx),     %%eax"          "\n\t"
sl@0
   360
            "movl       %%eax,          %%fs:0"         "\n\t"
sl@0
   361
sl@0
   362
            :
sl@0
   363
            /* No outputs */
sl@0
   364
            :
sl@0
   365
            [registration]      "m"     (registration),
sl@0
   366
            [ok]                "i"     (TCL_OK),
sl@0
   367
            [error]             "i"     (TCL_ERROR)
sl@0
   368
            :
sl@0
   369
            "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"
sl@0
   370
            );
sl@0
   371
sl@0
   372
#else /* HAVE_NO_SEH */
sl@0
   373
	__try {
sl@0
   374
	    Tcl_Finalize();
sl@0
   375
	} __except (EXCEPTION_EXECUTE_HANDLER) {
sl@0
   376
	    /* empty handler body. */
sl@0
   377
	}
sl@0
   378
#endif
sl@0
   379
sl@0
   380
	break;
sl@0
   381
    }
sl@0
   382
sl@0
   383
    return TRUE; 
sl@0
   384
}
sl@0
   385
sl@0
   386
#endif /* !STATIC_BUILD */
sl@0
   387
#endif /* __WIN32__ */
sl@0
   388

sl@0
   389
/*
sl@0
   390
 *----------------------------------------------------------------------
sl@0
   391
 *
sl@0
   392
 * TclWinGetTclInstance --
sl@0
   393
 *
sl@0
   394
 *	Retrieves the global library instance handle.
sl@0
   395
 *
sl@0
   396
 * Results:
sl@0
   397
 *	Returns the global library instance handle.
sl@0
   398
 *
sl@0
   399
 * Side effects:
sl@0
   400
 *	None.
sl@0
   401
 *
sl@0
   402
 *----------------------------------------------------------------------
sl@0
   403
 */
sl@0
   404
sl@0
   405
HINSTANCE
sl@0
   406
TclWinGetTclInstance()
sl@0
   407
{
sl@0
   408
    return hInstance;
sl@0
   409
}
sl@0
   410

sl@0
   411
/*
sl@0
   412
 *----------------------------------------------------------------------
sl@0
   413
 *
sl@0
   414
 * TclWinInit --
sl@0
   415
 *
sl@0
   416
 *	This function initializes the internal state of the tcl library.
sl@0
   417
 *
sl@0
   418
 * Results:
sl@0
   419
 *	None.
sl@0
   420
 *
sl@0
   421
 * Side effects:
sl@0
   422
 *	Initializes the tclPlatformId variable.
sl@0
   423
 *
sl@0
   424
 *----------------------------------------------------------------------
sl@0
   425
 */
sl@0
   426
sl@0
   427
void
sl@0
   428
TclWinInit(hInst)
sl@0
   429
    HINSTANCE hInst;		/* Library instance handle. */
sl@0
   430
{
sl@0
   431
    OSVERSIONINFO os;
sl@0
   432
sl@0
   433
    hInstance = hInst;
sl@0
   434
    os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
sl@0
   435
    GetVersionEx(&os);
sl@0
   436
    platformId = os.dwPlatformId;
sl@0
   437
sl@0
   438
    /*
sl@0
   439
     * We no longer support Win32s, so just in case someone manages to
sl@0
   440
     * get a runtime there, make sure they know that.
sl@0
   441
     */
sl@0
   442
sl@0
   443
    if (platformId == VER_PLATFORM_WIN32s) {
sl@0
   444
	panic("Win32s is not a supported platform");	
sl@0
   445
    }
sl@0
   446
sl@0
   447
    tclWinProcs = &asciiProcs;
sl@0
   448
}
sl@0
   449

sl@0
   450
/*
sl@0
   451
 *----------------------------------------------------------------------
sl@0
   452
 *
sl@0
   453
 * TclWinGetPlatformId --
sl@0
   454
 *
sl@0
   455
 *	Determines whether running under NT, 95, or Win32s, to allow 
sl@0
   456
 *	runtime conditional code.
sl@0
   457
 *
sl@0
   458
 * Results:
sl@0
   459
 *	The return value is one of:
sl@0
   460
 *	    VER_PLATFORM_WIN32s		Win32s on Windows 3.1. (not supported)
sl@0
   461
 *	    VER_PLATFORM_WIN32_WINDOWS	Win32 on Windows 95.
sl@0
   462
 *	    VER_PLATFORM_WIN32_NT	Win32 on Windows NT
sl@0
   463
 *
sl@0
   464
 * Side effects:
sl@0
   465
 *	None.
sl@0
   466
 *
sl@0
   467
 *----------------------------------------------------------------------
sl@0
   468
 */
sl@0
   469
sl@0
   470
int		
sl@0
   471
TclWinGetPlatformId()
sl@0
   472
{
sl@0
   473
    return platformId;
sl@0
   474
}
sl@0
   475

sl@0
   476
/*
sl@0
   477
 *-------------------------------------------------------------------------
sl@0
   478
 *
sl@0
   479
 * TclWinNoBackslash --
sl@0
   480
 *
sl@0
   481
 *	We're always iterating through a string in Windows, changing the
sl@0
   482
 *	backslashes to slashes for use in Tcl.
sl@0
   483
 *
sl@0
   484
 * Results:
sl@0
   485
 *	All backslashes in given string are changed to slashes.
sl@0
   486
 *
sl@0
   487
 * Side effects:
sl@0
   488
 *	None.
sl@0
   489
 *
sl@0
   490
 *-------------------------------------------------------------------------
sl@0
   491
 */
sl@0
   492
sl@0
   493
char *
sl@0
   494
TclWinNoBackslash(
sl@0
   495
    char *path)			/* String to change. */
sl@0
   496
{
sl@0
   497
    char *p;
sl@0
   498
sl@0
   499
    for (p = path; *p != '\0'; p++) {
sl@0
   500
	if (*p == '\\') {
sl@0
   501
	    *p = '/';
sl@0
   502
	}
sl@0
   503
    }
sl@0
   504
    return path;
sl@0
   505
}
sl@0
   506

sl@0
   507
/*
sl@0
   508
 *----------------------------------------------------------------------
sl@0
   509
 *
sl@0
   510
 * TclpCheckStackSpace --
sl@0
   511
 *
sl@0
   512
 *	Detect if we are about to blow the stack.  Called before an 
sl@0
   513
 *	evaluation can happen when nesting depth is checked.
sl@0
   514
 *
sl@0
   515
 * Results:
sl@0
   516
 *	1 if there is enough stack space to continue; 0 if not.
sl@0
   517
 *
sl@0
   518
 * Side effects:
sl@0
   519
 *	None.
sl@0
   520
 *
sl@0
   521
 *----------------------------------------------------------------------
sl@0
   522
 */
sl@0
   523
sl@0
   524
int
sl@0
   525
TclpCheckStackSpace()
sl@0
   526
{
sl@0
   527
sl@0
   528
#ifdef HAVE_NO_SEH
sl@0
   529
    EXCEPTION_REGISTRATION registration;
sl@0
   530
#endif
sl@0
   531
    int retval = 0;
sl@0
   532
sl@0
   533
    /*
sl@0
   534
     * We can recurse only if there is at least TCL_WIN_STACK_THRESHOLD
sl@0
   535
     * bytes of stack space left.  alloca() is cheap on windows; basically
sl@0
   536
     * it just subtracts from the stack pointer causing the OS to throw an
sl@0
   537
     * exception if the stack pointer is set below the bottom of the stack.
sl@0
   538
     */
sl@0
   539
sl@0
   540
#ifdef HAVE_NO_SEH
sl@0
   541
    __asm__ __volatile__ (
sl@0
   542
sl@0
   543
        /*
sl@0
   544
         * Construct an EXCEPTION_REGISTRATION to protect the
sl@0
   545
         * call to __alloca
sl@0
   546
         */
sl@0
   547
        "leal   %[registration], %%edx"         "\n\t"
sl@0
   548
        "movl   %%fs:0,         %%eax"          "\n\t"
sl@0
   549
        "movl   %%eax,          0x0(%%edx)"     "\n\t" /* link */
sl@0
   550
        "leal   1f,             %%eax"          "\n\t"
sl@0
   551
        "movl   %%eax,          0x4(%%edx)"     "\n\t" /* handler */
sl@0
   552
        "movl   %%ebp,          0x8(%%edx)"     "\n\t" /* ebp */
sl@0
   553
        "movl   %%esp,          0xc(%%edx)"     "\n\t" /* esp */
sl@0
   554
        "movl   %[error],       0x10(%%edx)"    "\n\t" /* status */
sl@0
   555
        
sl@0
   556
        /*
sl@0
   557
         * Link the EXCEPTION_REGISTRATION on the chain
sl@0
   558
         */
sl@0
   559
        "movl   %%edx,          %%fs:0"         "\n\t"
sl@0
   560
sl@0
   561
        /*
sl@0
   562
         * Attempt a call to __alloca, to determine whether there's
sl@0
   563
         * sufficient memory to be had.
sl@0
   564
         */
sl@0
   565
sl@0
   566
        "movl   %[size],        %%eax"          "\n\t"
sl@0
   567
        "pushl  %%eax"                          "\n\t"
sl@0
   568
        "call   __alloca"                       "\n\t"
sl@0
   569
sl@0
   570
        /*
sl@0
   571
         * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION
sl@0
   572
         * and store a TCL_OK status
sl@0
   573
         */
sl@0
   574
        "movl   %%fs:0,         %%edx"          "\n\t"
sl@0
   575
        "movl   %[ok],          %%eax"          "\n\t"
sl@0
   576
        "movl   %%eax,          0x10(%%edx)"    "\n\t"
sl@0
   577
        "jmp    2f"                             "\n"
sl@0
   578
sl@0
   579
        /*
sl@0
   580
         * Come here on an exception. Get the EXCEPTION_REGISTRATION
sl@0
   581
         * that we previously put on the chain.
sl@0
   582
         */
sl@0
   583
        "1:"                                    "\t"
sl@0
   584
        "movl   %%fs:0,         %%edx"          "\n\t"
sl@0
   585
        "movl   0x8(%%edx),     %%edx"          "\n\t"
sl@0
   586
        
sl@0
   587
        /* 
sl@0
   588
         * Come here however we exited.  Restore context from the
sl@0
   589
         * EXCEPTION_REGISTRATION in case the stack is unbalanced.
sl@0
   590
         */
sl@0
   591
        
sl@0
   592
        "2:"                                    "\t"
sl@0
   593
        "movl   0xc(%%edx),     %%esp"          "\n\t"
sl@0
   594
        "movl   0x8(%%edx),     %%ebp"          "\n\t"
sl@0
   595
        "movl   0x0(%%edx),     %%eax"          "\n\t"
sl@0
   596
        "movl   %%eax,          %%fs:0"         "\n\t"
sl@0
   597
        
sl@0
   598
        :
sl@0
   599
        /* No outputs */
sl@0
   600
        :
sl@0
   601
        [registration]  "m"     (registration),
sl@0
   602
        [ok]            "i"     (TCL_OK),
sl@0
   603
        [error]         "i"     (TCL_ERROR),
sl@0
   604
        [size]          "i"     (TCL_WIN_STACK_THRESHOLD)
sl@0
   605
        :
sl@0
   606
        "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"
sl@0
   607
        );
sl@0
   608
    retval = (registration.status == TCL_OK);
sl@0
   609
sl@0
   610
#else /* !HAVE_NO_SEH */
sl@0
   611
    __try {
sl@0
   612
#ifdef HAVE_ALLOCA_GCC_INLINE
sl@0
   613
        __asm__ __volatile__ (
sl@0
   614
            "movl  %0, %%eax" "\n\t"
sl@0
   615
            "call  __alloca" "\n\t"
sl@0
   616
            :
sl@0
   617
            : "i"(TCL_WIN_STACK_THRESHOLD)
sl@0
   618
            : "%eax");
sl@0
   619
#else
sl@0
   620
        alloca(TCL_WIN_STACK_THRESHOLD);
sl@0
   621
#endif /* HAVE_ALLOCA_GCC_INLINE */
sl@0
   622
        retval = 1;
sl@0
   623
    } __except (EXCEPTION_EXECUTE_HANDLER) {}
sl@0
   624
#endif /* HAVE_NO_SEH */
sl@0
   625
sl@0
   626
    return retval;
sl@0
   627
}
sl@0
   628

sl@0
   629
/*
sl@0
   630
 *----------------------------------------------------------------------
sl@0
   631
 *
sl@0
   632
 * TclWinGetPlatform --
sl@0
   633
 *
sl@0
   634
 *	This is a kludge that allows the test library to get access
sl@0
   635
 *	the internal tclPlatform variable.
sl@0
   636
 *
sl@0
   637
 * Results:
sl@0
   638
 *	Returns a pointer to the tclPlatform variable.
sl@0
   639
 *
sl@0
   640
 * Side effects:
sl@0
   641
 *	None.
sl@0
   642
 *
sl@0
   643
 *----------------------------------------------------------------------
sl@0
   644
 */
sl@0
   645
sl@0
   646
TclPlatformType *
sl@0
   647
TclWinGetPlatform()
sl@0
   648
{
sl@0
   649
    return &tclPlatform;
sl@0
   650
}
sl@0
   651

sl@0
   652
/*
sl@0
   653
 *---------------------------------------------------------------------------
sl@0
   654
 *
sl@0
   655
 * TclWinSetInterfaces --
sl@0
   656
 *
sl@0
   657
 *	A helper proc that allows the test library to change the
sl@0
   658
 *	tclWinProcs structure to dispatch to either the wide-character
sl@0
   659
 *	or multi-byte versions of the operating system calls, depending
sl@0
   660
 *	on whether Unicode is the system encoding.
sl@0
   661
 *	
sl@0
   662
 *	As well as this, we can also try to load in some additional
sl@0
   663
 *	procs which may/may not be present depending on the current
sl@0
   664
 *	Windows version (e.g. Win95 will not have the procs below).
sl@0
   665
 *
sl@0
   666
 * Results:
sl@0
   667
 *	None.
sl@0
   668
 *
sl@0
   669
 * Side effects:
sl@0
   670
 *	None.
sl@0
   671
 *
sl@0
   672
 *---------------------------------------------------------------------------
sl@0
   673
 */
sl@0
   674
sl@0
   675
void
sl@0
   676
TclWinSetInterfaces(
sl@0
   677
    int wide)			/* Non-zero to use wide interfaces, 0
sl@0
   678
				 * otherwise. */
sl@0
   679
{
sl@0
   680
    Tcl_FreeEncoding(tclWinTCharEncoding);
sl@0
   681
sl@0
   682
    if (wide) {
sl@0
   683
	tclWinProcs = &unicodeProcs;
sl@0
   684
	tclWinTCharEncoding = Tcl_GetEncoding(NULL, "unicode");
sl@0
   685
	if (tclWinProcs->getFileAttributesExProc == NULL) {
sl@0
   686
	    HINSTANCE hInstance = LoadLibraryA("kernel32");
sl@0
   687
	    if (hInstance != NULL) {
sl@0
   688
	        tclWinProcs->getFileAttributesExProc = 
sl@0
   689
		  (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS, 
sl@0
   690
		  LPVOID)) GetProcAddress(hInstance, "GetFileAttributesExW");
sl@0
   691
		tclWinProcs->createHardLinkProc = 
sl@0
   692
		  (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*, 
sl@0
   693
		  LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance, 
sl@0
   694
		  "CreateHardLinkW");
sl@0
   695
	        tclWinProcs->findFirstFileExProc = 
sl@0
   696
		  (HANDLE (WINAPI *)(CONST TCHAR*, UINT,
sl@0
   697
		  LPVOID, UINT, LPVOID, DWORD)) GetProcAddress(hInstance, 
sl@0
   698
		  "FindFirstFileExW");
sl@0
   699
	        tclWinProcs->getVolumeNameForVMPProc = 
sl@0
   700
		  (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*, 
sl@0
   701
		  DWORD)) GetProcAddress(hInstance, 
sl@0
   702
		  "GetVolumeNameForVolumeMountPointW");
sl@0
   703
		FreeLibrary(hInstance);
sl@0
   704
	    }
sl@0
   705
	    hInstance = LoadLibraryA("advapi32");
sl@0
   706
	    if (hInstance != NULL) {
sl@0
   707
		tclWinProcs->getFileSecurityProc = (BOOL (WINAPI *)(
sl@0
   708
			LPCTSTR lpFileName,
sl@0
   709
			SECURITY_INFORMATION RequestedInformation,
sl@0
   710
			PSECURITY_DESCRIPTOR pSecurityDescriptor,
sl@0
   711
			DWORD nLength, LPDWORD lpnLengthNeeded))
sl@0
   712
			GetProcAddress(hInstance, "GetFileSecurityW");
sl@0
   713
		tclWinProcs->impersonateSelfProc = (BOOL (WINAPI *) (
sl@0
   714
			SECURITY_IMPERSONATION_LEVEL ImpersonationLevel))
sl@0
   715
			GetProcAddress(hInstance, "ImpersonateSelf");
sl@0
   716
		tclWinProcs->openThreadTokenProc = (BOOL (WINAPI *) (
sl@0
   717
			HANDLE ThreadHandle, DWORD DesiredAccess,
sl@0
   718
			BOOL OpenAsSelf, PHANDLE TokenHandle))
sl@0
   719
			GetProcAddress(hInstance, "OpenThreadToken");
sl@0
   720
		tclWinProcs->revertToSelfProc = (BOOL (WINAPI *) (void))
sl@0
   721
			GetProcAddress(hInstance, "RevertToSelf");
sl@0
   722
		tclWinProcs->mapGenericMaskProc = (VOID (WINAPI *) (
sl@0
   723
			PDWORD AccessMask, PGENERIC_MAPPING GenericMapping))
sl@0
   724
			GetProcAddress(hInstance, "MapGenericMask");
sl@0
   725
		tclWinProcs->accessCheckProc = (BOOL (WINAPI *)(
sl@0
   726
			PSECURITY_DESCRIPTOR pSecurityDescriptor,
sl@0
   727
			HANDLE ClientToken, DWORD DesiredAccess,
sl@0
   728
			PGENERIC_MAPPING GenericMapping,
sl@0
   729
			PPRIVILEGE_SET PrivilegeSet,
sl@0
   730
			LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess,
sl@0
   731
			LPBOOL AccessStatus)) GetProcAddress(hInstance,
sl@0
   732
			"AccessCheck");
sl@0
   733
		FreeLibrary(hInstance);
sl@0
   734
	    }
sl@0
   735
	}
sl@0
   736
    } else {
sl@0
   737
	tclWinProcs = &asciiProcs;
sl@0
   738
	tclWinTCharEncoding = NULL;
sl@0
   739
	if (tclWinProcs->getFileAttributesExProc == NULL) {
sl@0
   740
	    HINSTANCE hInstance = LoadLibraryA("kernel32");
sl@0
   741
	    if (hInstance != NULL) {
sl@0
   742
		tclWinProcs->getFileAttributesExProc = 
sl@0
   743
		  (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS, 
sl@0
   744
		  LPVOID)) GetProcAddress(hInstance, "GetFileAttributesExA");
sl@0
   745
		tclWinProcs->createHardLinkProc = 
sl@0
   746
		  (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*, 
sl@0
   747
		  LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance, 
sl@0
   748
		  "CreateHardLinkA");
sl@0
   749
		tclWinProcs->findFirstFileExProc = 
sl@0
   750
		  (HANDLE (WINAPI *)(CONST TCHAR*, UINT,
sl@0
   751
		  LPVOID, UINT, LPVOID, DWORD)) GetProcAddress(hInstance, 
sl@0
   752
		  "FindFirstFileExA");
sl@0
   753
		tclWinProcs->getLongPathNameProc = NULL;
sl@0
   754
		tclWinProcs->getVolumeNameForVMPProc = 
sl@0
   755
		  (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*, 
sl@0
   756
		  DWORD)) GetProcAddress(hInstance, 
sl@0
   757
		  "GetVolumeNameForVolumeMountPointA");
sl@0
   758
		FreeLibrary(hInstance);
sl@0
   759
	    }
sl@0
   760
	}
sl@0
   761
    }
sl@0
   762
}
sl@0
   763

sl@0
   764
/*
sl@0
   765
 *---------------------------------------------------------------------------
sl@0
   766
 *
sl@0
   767
 * TclWinResetInterfaceEncodings --
sl@0
   768
 *
sl@0
   769
 *	Called during finalization to free up any encodings we use.
sl@0
   770
 *	The tclWinProcs-> look up table is still ok to use after
sl@0
   771
 *	this call, provided no encoding conversion is required.
sl@0
   772
 *
sl@0
   773
 *      We also clean up any memory allocated in our mount point
sl@0
   774
 *      map which is used to follow certain kinds of symlinks.
sl@0
   775
 *      That code should never be used once encodings are taken
sl@0
   776
 *      down.
sl@0
   777
 *      
sl@0
   778
 * Results:
sl@0
   779
 *	None.
sl@0
   780
 *
sl@0
   781
 * Side effects:
sl@0
   782
 *	None.
sl@0
   783
 *
sl@0
   784
 *---------------------------------------------------------------------------
sl@0
   785
 */
sl@0
   786
void
sl@0
   787
TclWinResetInterfaceEncodings()
sl@0
   788
{
sl@0
   789
    MountPointMap *dlIter, *dlIter2;
sl@0
   790
    if (tclWinTCharEncoding != NULL) {
sl@0
   791
	Tcl_FreeEncoding(tclWinTCharEncoding);
sl@0
   792
	tclWinTCharEncoding = NULL;
sl@0
   793
    }
sl@0
   794
    /* Clean up the mount point map */
sl@0
   795
    Tcl_MutexLock(&mountPointMap);
sl@0
   796
    dlIter = driveLetterLookup; 
sl@0
   797
    while (dlIter != NULL) {
sl@0
   798
	dlIter2 = dlIter->nextPtr;
sl@0
   799
	ckfree((char*)dlIter->volumeName);
sl@0
   800
	ckfree((char*)dlIter);
sl@0
   801
	dlIter = dlIter2;
sl@0
   802
    }
sl@0
   803
    Tcl_MutexUnlock(&mountPointMap);
sl@0
   804
}
sl@0
   805

sl@0
   806
/*
sl@0
   807
 *---------------------------------------------------------------------------
sl@0
   808
 *
sl@0
   809
 * TclWinResetInterfaces --
sl@0
   810
 *
sl@0
   811
 *	Called during finalization to reset us to a safe state for reuse.
sl@0
   812
 *	After this call, it is best not to use the tclWinProcs-> look
sl@0
   813
 *	up table since it is likely to be different to what is expected.
sl@0
   814
 *
sl@0
   815
 * Results:
sl@0
   816
 *	None.
sl@0
   817
 *
sl@0
   818
 * Side effects:
sl@0
   819
 *	None.
sl@0
   820
 *
sl@0
   821
 *---------------------------------------------------------------------------
sl@0
   822
 */
sl@0
   823
void
sl@0
   824
TclWinResetInterfaces()
sl@0
   825
{
sl@0
   826
    tclWinProcs = &asciiProcs;
sl@0
   827
}
sl@0
   828

sl@0
   829
/*
sl@0
   830
 *--------------------------------------------------------------------
sl@0
   831
 *
sl@0
   832
 * TclWinDriveLetterForVolMountPoint
sl@0
   833
 *
sl@0
   834
 * Unfortunately, Windows provides no easy way at all to get hold
sl@0
   835
 * of the drive letter for a volume mount point, but we need that
sl@0
   836
 * information to understand paths correctly.  So, we have to 
sl@0
   837
 * build an associated array to find these correctly, and allow
sl@0
   838
 * quick and easy lookup from volume mount points to drive letters.
sl@0
   839
 * 
sl@0
   840
 * We assume here that we are running on a system for which the wide
sl@0
   841
 * character interfaces are used, which is valid for Win 2000 and WinXP
sl@0
   842
 * which are the only systems on which this function will ever be called.
sl@0
   843
 * 
sl@0
   844
 * Result: the drive letter, or -1 if no drive letter corresponds to
sl@0
   845
 * the given mount point.
sl@0
   846
 * 
sl@0
   847
 *--------------------------------------------------------------------
sl@0
   848
 */
sl@0
   849
char 
sl@0
   850
TclWinDriveLetterForVolMountPoint(CONST WCHAR *mountPoint)
sl@0
   851
{
sl@0
   852
    MountPointMap *dlIter, *dlPtr2;
sl@0
   853
    WCHAR Target[55];         /* Target of mount at mount point */
sl@0
   854
    WCHAR drive[4] = { L'A', L':', L'\\', L'\0' };
sl@0
   855
    
sl@0
   856
    /* 
sl@0
   857
     * Detect the volume mounted there.  Unfortunately, there is no
sl@0
   858
     * simple way to map a unique volume name to a DOS drive letter.  
sl@0
   859
     * So, we have to build an associative array.
sl@0
   860
     */
sl@0
   861
    
sl@0
   862
    Tcl_MutexLock(&mountPointMap);
sl@0
   863
    dlIter = driveLetterLookup; 
sl@0
   864
    while (dlIter != NULL) {
sl@0
   865
	if (wcscmp(dlIter->volumeName, mountPoint) == 0) {
sl@0
   866
	    /* 
sl@0
   867
	     * We need to check whether this information is
sl@0
   868
	     * still valid, since either the user or various
sl@0
   869
	     * programs could have adjusted the mount points on
sl@0
   870
	     * the fly.
sl@0
   871
	     */
sl@0
   872
	    drive[0] = L'A' + (dlIter->driveLetter - 'A');
sl@0
   873
	    /* Try to read the volume mount point and see where it points */
sl@0
   874
	    if ((*tclWinProcs->getVolumeNameForVMPProc)((TCHAR*)drive, 
sl@0
   875
					       (TCHAR*)Target, 55) != 0) {
sl@0
   876
		if (wcscmp((WCHAR*)dlIter->volumeName, Target) == 0) {
sl@0
   877
		    /* Nothing has changed */
sl@0
   878
		    Tcl_MutexUnlock(&mountPointMap);
sl@0
   879
		    return dlIter->driveLetter;
sl@0
   880
		}
sl@0
   881
	    }
sl@0
   882
	    /* 
sl@0
   883
	     * If we reach here, unfortunately, this mount point is
sl@0
   884
	     * no longer valid at all
sl@0
   885
	     */
sl@0
   886
	    if (driveLetterLookup == dlIter) {
sl@0
   887
		dlPtr2 = dlIter;
sl@0
   888
		driveLetterLookup = dlIter->nextPtr;
sl@0
   889
	    } else {
sl@0
   890
		for (dlPtr2 = driveLetterLookup; 
sl@0
   891
		     dlPtr2 != NULL; dlPtr2 = dlPtr2->nextPtr) {
sl@0
   892
		    if (dlPtr2->nextPtr == dlIter) {
sl@0
   893
			dlPtr2->nextPtr = dlIter->nextPtr;
sl@0
   894
			dlPtr2 = dlIter;
sl@0
   895
			break;
sl@0
   896
		    }
sl@0
   897
		}
sl@0
   898
	    }
sl@0
   899
	    /* Now dlPtr2 points to the structure to free */
sl@0
   900
	    ckfree((char*)dlPtr2->volumeName);
sl@0
   901
	    ckfree((char*)dlPtr2);
sl@0
   902
	    /* 
sl@0
   903
	     * Restart the loop --- we could try to be clever
sl@0
   904
	     * and continue half way through, but the logic is a 
sl@0
   905
	     * bit messy, so it's cleanest just to restart
sl@0
   906
	     */
sl@0
   907
	    dlIter = driveLetterLookup;
sl@0
   908
	    continue;
sl@0
   909
	}
sl@0
   910
	dlIter = dlIter->nextPtr;
sl@0
   911
    }
sl@0
   912
   
sl@0
   913
    /* We couldn't find it, so we must iterate over the letters */
sl@0
   914
    
sl@0
   915
    for (drive[0] = L'A'; drive[0] <= L'Z'; drive[0]++) {
sl@0
   916
	/* Try to read the volume mount point and see where it points */
sl@0
   917
	if ((*tclWinProcs->getVolumeNameForVMPProc)((TCHAR*)drive, 
sl@0
   918
					   (TCHAR*)Target, 55) != 0) {
sl@0
   919
	    int alreadyStored = 0;
sl@0
   920
	    for (dlIter = driveLetterLookup; dlIter != NULL; 
sl@0
   921
		 dlIter = dlIter->nextPtr) {
sl@0
   922
		if (wcscmp((WCHAR*)dlIter->volumeName, Target) == 0) {
sl@0
   923
		    alreadyStored = 1;
sl@0
   924
		    break;
sl@0
   925
		}
sl@0
   926
	    }
sl@0
   927
	    if (!alreadyStored) {
sl@0
   928
		dlPtr2 = (MountPointMap*) ckalloc(sizeof(MountPointMap));
sl@0
   929
		dlPtr2->volumeName = TclNativeDupInternalRep(Target);
sl@0
   930
		dlPtr2->driveLetter = 'A' + (drive[0] - L'A');
sl@0
   931
		dlPtr2->nextPtr = driveLetterLookup;
sl@0
   932
		driveLetterLookup  = dlPtr2;
sl@0
   933
	    }
sl@0
   934
	}
sl@0
   935
    }
sl@0
   936
    /* Try again */
sl@0
   937
    for (dlIter = driveLetterLookup; dlIter != NULL; 
sl@0
   938
					dlIter = dlIter->nextPtr) {
sl@0
   939
	if (wcscmp(dlIter->volumeName, mountPoint) == 0) {
sl@0
   940
	    Tcl_MutexUnlock(&mountPointMap);
sl@0
   941
	    return dlIter->driveLetter;
sl@0
   942
	}
sl@0
   943
    }
sl@0
   944
    /* 
sl@0
   945
     * The volume doesn't appear to correspond to a drive letter -- we
sl@0
   946
     * remember that fact and store '-1' so we don't have to look it
sl@0
   947
     * up each time.
sl@0
   948
     */
sl@0
   949
    dlPtr2 = (MountPointMap*) ckalloc(sizeof(MountPointMap));
sl@0
   950
    dlPtr2->volumeName = TclNativeDupInternalRep((ClientData)mountPoint);
sl@0
   951
    dlPtr2->driveLetter = -1;
sl@0
   952
    dlPtr2->nextPtr = driveLetterLookup;
sl@0
   953
    driveLetterLookup  = dlPtr2;
sl@0
   954
    Tcl_MutexUnlock(&mountPointMap);
sl@0
   955
    return -1;
sl@0
   956
}
sl@0
   957

sl@0
   958
/*
sl@0
   959
 *---------------------------------------------------------------------------
sl@0
   960
 *
sl@0
   961
 * Tcl_WinUtfToTChar, Tcl_WinTCharToUtf --
sl@0
   962
 *
sl@0
   963
 *	Convert between UTF-8 and Unicode when running Windows NT or 
sl@0
   964
 *	the current ANSI code page when running Windows 95.
sl@0
   965
 *
sl@0
   966
 *	On Mac, Unix, and Windows 95, all strings exchanged between Tcl
sl@0
   967
 *	and the OS are "char" oriented.  We need only one Tcl_Encoding to
sl@0
   968
 *	convert between UTF-8 and the system's native encoding.  We use
sl@0
   969
 *	NULL to represent that encoding.
sl@0
   970
 *
sl@0
   971
 *	On NT, some strings exchanged between Tcl and the OS are "char"
sl@0
   972
 *	oriented, while others are in Unicode.  We need two Tcl_Encoding
sl@0
   973
 *	APIs depending on whether we are targeting a "char" or Unicode
sl@0
   974
 *	interface.  
sl@0
   975
 *
sl@0
   976
 *	Calling Tcl_UtfToExternal() or Tcl_ExternalToUtf() with an
sl@0
   977
 *	encoding of NULL should always used to convert between UTF-8
sl@0
   978
 *	and the system's "char" oriented encoding.  The following two
sl@0
   979
 *	functions are used in Windows-specific code to convert between
sl@0
   980
 *	UTF-8 and Unicode strings (NT) or "char" strings(95).  This saves
sl@0
   981
 *	you the trouble of writing the following type of fragment over and
sl@0
   982
 *	over:
sl@0
   983
 *
sl@0
   984
 *		if (running NT) {
sl@0
   985
 *		    encoding <- Tcl_GetEncoding("unicode");
sl@0
   986
 *		    nativeBuffer <- UtfToExternal(encoding, utfBuffer);
sl@0
   987
 *		    Tcl_FreeEncoding(encoding);
sl@0
   988
 *		} else {
sl@0
   989
 *		    nativeBuffer <- UtfToExternal(NULL, utfBuffer);
sl@0
   990
 *		}
sl@0
   991
 *
sl@0
   992
 *	By convention, in Windows a TCHAR is a character in the ANSI code
sl@0
   993
 *	page on Windows 95, a Unicode character on Windows NT.  If you
sl@0
   994
 *	plan on targeting a Unicode interfaces when running on NT and a
sl@0
   995
 *	"char" oriented interface while running on 95, these functions
sl@0
   996
 *	should be used.  If you plan on targetting the same "char"
sl@0
   997
 *	oriented function on both 95 and NT, use Tcl_UtfToExternal()
sl@0
   998
 *	with an encoding of NULL.
sl@0
   999
 *
sl@0
  1000
 * Results:
sl@0
  1001
 *	The result is a pointer to the string in the desired target
sl@0
  1002
 *	encoding.  Storage for the result string is allocated in
sl@0
  1003
 *	dsPtr; the caller must call Tcl_DStringFree() when the result
sl@0
  1004
 *	is no longer needed.
sl@0
  1005
 *
sl@0
  1006
 * Side effects:
sl@0
  1007
 *	None.
sl@0
  1008
 *
sl@0
  1009
 *---------------------------------------------------------------------------
sl@0
  1010
 */
sl@0
  1011
sl@0
  1012
TCHAR *
sl@0
  1013
Tcl_WinUtfToTChar(string, len, dsPtr)
sl@0
  1014
    CONST char *string;		/* Source string in UTF-8. */
sl@0
  1015
    int len;			/* Source string length in bytes, or < 0 for
sl@0
  1016
				 * strlen(). */
sl@0
  1017
    Tcl_DString *dsPtr;		/* Uninitialized or free DString in which 
sl@0
  1018
				 * the converted string is stored. */
sl@0
  1019
{
sl@0
  1020
    return (TCHAR *) Tcl_UtfToExternalDString(tclWinTCharEncoding, 
sl@0
  1021
	    string, len, dsPtr);
sl@0
  1022
}
sl@0
  1023
sl@0
  1024
char *
sl@0
  1025
Tcl_WinTCharToUtf(string, len, dsPtr)
sl@0
  1026
    CONST TCHAR *string;	/* Source string in Unicode when running
sl@0
  1027
				 * NT, ANSI when running 95. */
sl@0
  1028
    int len;			/* Source string length in bytes, or < 0 for
sl@0
  1029
				 * platform-specific string length. */
sl@0
  1030
    Tcl_DString *dsPtr;		/* Uninitialized or free DString in which 
sl@0
  1031
				 * the converted string is stored. */
sl@0
  1032
{
sl@0
  1033
    return Tcl_ExternalToUtfDString(tclWinTCharEncoding, 
sl@0
  1034
	    (CONST char *) string, len, dsPtr);
sl@0
  1035
}
sl@0
  1036

sl@0
  1037
/*
sl@0
  1038
 *------------------------------------------------------------------------
sl@0
  1039
 *
sl@0
  1040
 * TclWinCPUID --
sl@0
  1041
 *
sl@0
  1042
 *	Get CPU ID information on an Intel box under Windows
sl@0
  1043
 *
sl@0
  1044
 * Results:
sl@0
  1045
 *	Returns TCL_OK if successful, TCL_ERROR if CPUID is not
sl@0
  1046
 *	supported or fails.
sl@0
  1047
 *
sl@0
  1048
 * Side effects:
sl@0
  1049
 *	If successful, stores EAX, EBX, ECX and EDX registers after 
sl@0
  1050
 *      the CPUID instruction in the four integers designated by 'regsPtr'
sl@0
  1051
 *
sl@0
  1052
 *----------------------------------------------------------------------
sl@0
  1053
 */
sl@0
  1054
sl@0
  1055
int
sl@0
  1056
TclWinCPUID( unsigned int index, /* Which CPUID value to retrieve */
sl@0
  1057
	     unsigned int * regsPtr ) /* Registers after the CPUID */
sl@0
  1058
{
sl@0
  1059
sl@0
  1060
#ifdef HAVE_NO_SEH
sl@0
  1061
    EXCEPTION_REGISTRATION registration;
sl@0
  1062
#endif
sl@0
  1063
    int status = TCL_ERROR;
sl@0
  1064
sl@0
  1065
#if defined(__GNUC__) && !defined(_WIN64)
sl@0
  1066
sl@0
  1067
    /* 
sl@0
  1068
     * Execute the CPUID instruction with the given index, and
sl@0
  1069
     * store results off 'regPtr'.
sl@0
  1070
     */
sl@0
  1071
    
sl@0
  1072
    __asm__ __volatile__ (
sl@0
  1073
sl@0
  1074
        /*
sl@0
  1075
         * Construct an EXCEPTION_REGISTRATION to protect the
sl@0
  1076
         * CPUID instruction (early 486's don't have CPUID)
sl@0
  1077
         */
sl@0
  1078
        "leal   %[registration], %%edx"         "\n\t"
sl@0
  1079
        "movl   %%fs:0,         %%eax"          "\n\t"
sl@0
  1080
        "movl   %%eax,          0x0(%%edx)"     "\n\t" /* link */
sl@0
  1081
        "leal   1f,             %%eax"          "\n\t"
sl@0
  1082
        "movl   %%eax,          0x4(%%edx)"     "\n\t" /* handler */
sl@0
  1083
        "movl   %%ebp,          0x8(%%edx)"     "\n\t" /* ebp */
sl@0
  1084
        "movl   %%esp,          0xc(%%edx)"     "\n\t" /* esp */
sl@0
  1085
        "movl   %[error],       0x10(%%edx)"    "\n\t" /* status */
sl@0
  1086
        
sl@0
  1087
        /*
sl@0
  1088
         * Link the EXCEPTION_REGISTRATION on the chain
sl@0
  1089
         */
sl@0
  1090
        "movl   %%edx,          %%fs:0"         "\n\t"
sl@0
  1091
sl@0
  1092
        /*
sl@0
  1093
         * Do the CPUID instruction, and save the results in
sl@0
  1094
         * the 'regsPtr' area
sl@0
  1095
         */
sl@0
  1096
sl@0
  1097
        "movl   %[rptr],        %%edi"          "\n\t"
sl@0
  1098
        "movl   %[index],       %%eax"          "\n\t"
sl@0
  1099
        "cpuid"                                 "\n\t"
sl@0
  1100
        "movl   %%eax,          0x0(%%edi)"     "\n\t"
sl@0
  1101
        "movl   %%ebx,          0x4(%%edi)"     "\n\t"
sl@0
  1102
        "movl   %%ecx,          0x8(%%edi)"     "\n\t"
sl@0
  1103
        "movl   %%edx,          0xc(%%edi)"     "\n\t"
sl@0
  1104
sl@0
  1105
        /*
sl@0
  1106
         * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION
sl@0
  1107
         * and store a TCL_OK status
sl@0
  1108
         */
sl@0
  1109
        "movl   %%fs:0,         %%edx"          "\n\t"
sl@0
  1110
        "movl   %[ok],          %%eax"          "\n\t"
sl@0
  1111
        "movl   %%eax,          0x10(%%edx)"    "\n\t"
sl@0
  1112
        "jmp    2f"                             "\n"
sl@0
  1113
sl@0
  1114
        /*
sl@0
  1115
         * Come here on an exception. Get the EXCEPTION_REGISTRATION
sl@0
  1116
         * that we previously put on the chain.
sl@0
  1117
         */
sl@0
  1118
        "1:"                                    "\t"
sl@0
  1119
        "movl   %%fs:0,         %%edx"          "\n\t"
sl@0
  1120
        "movl   0x8(%%edx),     %%edx"          "\n\t"
sl@0
  1121
        
sl@0
  1122
        /* 
sl@0
  1123
         * Come here however we exited.  Restore context from the
sl@0
  1124
         * EXCEPTION_REGISTRATION in case the stack is unbalanced.
sl@0
  1125
         */
sl@0
  1126
        
sl@0
  1127
        "2:"                                    "\t"
sl@0
  1128
        "movl   0xc(%%edx),     %%esp"          "\n\t"
sl@0
  1129
        "movl   0x8(%%edx),     %%ebp"          "\n\t"
sl@0
  1130
        "movl   0x0(%%edx),     %%eax"          "\n\t"
sl@0
  1131
        "movl   %%eax,          %%fs:0"         "\n\t"
sl@0
  1132
sl@0
  1133
        : 
sl@0
  1134
        /* No outputs */
sl@0
  1135
        : 
sl@0
  1136
        [index]         "m"     (index),
sl@0
  1137
        [rptr]          "m"     (regsPtr),
sl@0
  1138
        [registration]  "m"     (registration),
sl@0
  1139
        [ok]            "i"     (TCL_OK),
sl@0
  1140
        [error]         "i"     (TCL_ERROR)
sl@0
  1141
        :
sl@0
  1142
        "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory" );
sl@0
  1143
    status = registration.status;
sl@0
  1144
sl@0
  1145
#elif defined(_MSC_VER) && !defined(_WIN64)
sl@0
  1146
sl@0
  1147
    /* Define a structure in the stack frame to hold the registers */
sl@0
  1148
sl@0
  1149
    struct {
sl@0
  1150
	DWORD dw0;
sl@0
  1151
	DWORD dw1;
sl@0
  1152
	DWORD dw2;
sl@0
  1153
	DWORD dw3;
sl@0
  1154
    } regs;
sl@0
  1155
    regs.dw0 = index;
sl@0
  1156
    
sl@0
  1157
    /* Execute the CPUID instruction and save regs in the stack frame */
sl@0
  1158
sl@0
  1159
    _try {
sl@0
  1160
	_asm {
sl@0
  1161
	    push    ebx
sl@0
  1162
	    push    ecx
sl@0
  1163
	    push    edx
sl@0
  1164
	    mov     eax, regs.dw0
sl@0
  1165
	    cpuid
sl@0
  1166
	    mov     regs.dw0, eax
sl@0
  1167
	    mov     regs.dw1, ebx
sl@0
  1168
	    mov     regs.dw2, ecx
sl@0
  1169
	    mov     regs.dw3, edx
sl@0
  1170
            pop     edx
sl@0
  1171
            pop     ecx
sl@0
  1172
            pop     ebx
sl@0
  1173
	}
sl@0
  1174
	
sl@0
  1175
	/* Copy regs back out to the caller */
sl@0
  1176
sl@0
  1177
	regsPtr[0]=regs.dw0;
sl@0
  1178
	regsPtr[1]=regs.dw1;
sl@0
  1179
	regsPtr[2]=regs.dw2;
sl@0
  1180
	regsPtr[3]=regs.dw3;
sl@0
  1181
sl@0
  1182
	status = TCL_OK;
sl@0
  1183
    } __except( EXCEPTION_EXECUTE_HANDLER ) {
sl@0
  1184
    }
sl@0
  1185
sl@0
  1186
#else
sl@0
  1187
				/* Don't know how to do assembly code for
sl@0
  1188
				 * this compiler and/or architecture */
sl@0
  1189
#endif
sl@0
  1190
    return status;
sl@0
  1191
}