diff -r 000000000000 -r bde4ae8d615e os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/win/tclWin32Dll.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/win/tclWin32Dll.c Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,1191 @@ +/* + * tclWin32Dll.c -- + * + * This file contains the DLL entry point. + * + * Copyright (c) 1995-1996 Sun Microsystems, Inc. + * Copyright (c) 1998-2000 Scriptics Corporation. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tclWin32Dll.c,v 1.24.2.10 2006/10/17 04:36:45 dgp Exp $ + */ + +#include "tclWinInt.h" + +/* + * The following data structures are used when loading the thunking + * library for execing child processes under Win32s. + */ + +typedef DWORD (WINAPI UT32PROC)(LPVOID lpBuff, DWORD dwUserDefined, + LPVOID *lpTranslationList); + +typedef BOOL (WINAPI UTREGISTER)(HANDLE hModule, LPCSTR SixteenBitDLL, + LPCSTR InitName, LPCSTR ProcName, UT32PROC **ThirtyTwoBitThunk, + FARPROC UT32Callback, LPVOID Buff); + +typedef VOID (WINAPI UTUNREGISTER)(HANDLE hModule); + +/* + * The following variables keep track of information about this DLL + * on a per-instance basis. Each time this DLL is loaded, it gets its own + * new data segment with its own copy of all static and global information. + */ + +static HINSTANCE hInstance; /* HINSTANCE of this DLL. */ +static int platformId; /* Running under NT, or 95/98? */ + +#ifdef HAVE_NO_SEH + +/* + * Unlike Borland and Microsoft, we don't register exception handlers + * by pushing registration records onto the runtime stack. Instead, we + * register them by creating an EXCEPTION_REGISTRATION within the activation + * record. + */ + +typedef struct EXCEPTION_REGISTRATION { + struct EXCEPTION_REGISTRATION* link; + EXCEPTION_DISPOSITION (*handler)( struct _EXCEPTION_RECORD*, void*, + struct _CONTEXT*, void* ); + void* ebp; + void* esp; + int status; +} EXCEPTION_REGISTRATION; + +#endif + +/* + * VC++ 5.x has no 'cpuid' assembler instruction, so we + * must emulate it + */ +#if defined(_MSC_VER) && ( _MSC_VER <= 1100 ) +#define cpuid __asm __emit 0fh __asm __emit 0a2h +#endif + +/* + * The following function tables are used to dispatch to either the + * wide-character or multi-byte versions of the operating system calls, + * depending on whether the Unicode calls are available. + */ + +static TclWinProcs asciiProcs = { + 0, + + (BOOL (WINAPI *)(CONST TCHAR *, LPDCB)) BuildCommDCBA, + (TCHAR *(WINAPI *)(TCHAR *)) CharLowerA, + (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *, BOOL)) CopyFileA, + (BOOL (WINAPI *)(CONST TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectoryA, + (HANDLE (WINAPI *)(CONST TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *, + DWORD, DWORD, HANDLE)) CreateFileA, + (BOOL (WINAPI *)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES, + LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *, + LPSTARTUPINFOA, LPPROCESS_INFORMATION)) CreateProcessA, + (BOOL (WINAPI *)(CONST TCHAR *)) DeleteFileA, + (HANDLE (WINAPI *)(CONST TCHAR *, WIN32_FIND_DATAT *)) FindFirstFileA, + (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFileA, + (BOOL (WINAPI *)(WCHAR *, LPDWORD)) GetComputerNameA, + (DWORD (WINAPI *)(DWORD, WCHAR *)) GetCurrentDirectoryA, + (DWORD (WINAPI *)(CONST TCHAR *)) GetFileAttributesA, + (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, + TCHAR **)) GetFullPathNameA, + (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameA, + (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameA, + (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique, + WCHAR *)) GetTempFileNameA, + (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathA, + (BOOL (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD, + WCHAR *, DWORD)) GetVolumeInformationA, + (HINSTANCE (WINAPI *)(CONST TCHAR *)) LoadLibraryA, + (TCHAR (WINAPI *)(WCHAR *, CONST TCHAR *)) lstrcpyA, + (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileA, + (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryA, + (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD, + WCHAR *, TCHAR **)) SearchPathA, + (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryA, + (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesA, + /* + * The three NULL function pointers will only be set when + * Tcl_FindExecutable is called. If you don't ever call that + * function, the application will crash whenever WinTcl tries to call + * functions through these null pointers. That is not a bug in Tcl + * -- Tcl_FindExecutable is obligatory in recent Tcl releases. + */ + NULL, + NULL, + (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _utime, + NULL, + NULL, + /* getLongPathNameProc */ + NULL, + /* Security SDK - not available on 95,98,ME */ + NULL, NULL, NULL, NULL, NULL, NULL, + /* ReadConsole and WriteConsole */ + (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsoleA, + (BOOL (WINAPI *)(HANDLE, const VOID*, DWORD, LPDWORD, LPVOID)) WriteConsoleA +}; + +static TclWinProcs unicodeProcs = { + 1, + + (BOOL (WINAPI *)(CONST TCHAR *, LPDCB)) BuildCommDCBW, + (TCHAR *(WINAPI *)(TCHAR *)) CharLowerW, + (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *, BOOL)) CopyFileW, + (BOOL (WINAPI *)(CONST TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectoryW, + (HANDLE (WINAPI *)(CONST TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *, + DWORD, DWORD, HANDLE)) CreateFileW, + (BOOL (WINAPI *)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES, + LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *, + LPSTARTUPINFOA, LPPROCESS_INFORMATION)) CreateProcessW, + (BOOL (WINAPI *)(CONST TCHAR *)) DeleteFileW, + (HANDLE (WINAPI *)(CONST TCHAR *, WIN32_FIND_DATAT *)) FindFirstFileW, + (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFileW, + (BOOL (WINAPI *)(WCHAR *, LPDWORD)) GetComputerNameW, + (DWORD (WINAPI *)(DWORD, WCHAR *)) GetCurrentDirectoryW, + (DWORD (WINAPI *)(CONST TCHAR *)) GetFileAttributesW, + (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, + TCHAR **)) GetFullPathNameW, + (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameW, + (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameW, + (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique, + WCHAR *)) GetTempFileNameW, + (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathW, + (BOOL (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD, + WCHAR *, DWORD)) GetVolumeInformationW, + (HINSTANCE (WINAPI *)(CONST TCHAR *)) LoadLibraryW, + (TCHAR (WINAPI *)(WCHAR *, CONST TCHAR *)) lstrcpyW, + (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileW, + (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryW, + (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD, + WCHAR *, TCHAR **)) SearchPathW, + (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryW, + (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesW, + /* + * The three NULL function pointers will only be set when + * Tcl_FindExecutable is called. If you don't ever call that + * function, the application will crash whenever WinTcl tries to call + * functions through these null pointers. That is not a bug in Tcl + * -- Tcl_FindExecutable is obligatory in recent Tcl releases. + */ + NULL, + NULL, + (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _wutime, + NULL, + NULL, + /* getLongPathNameProc */ + NULL, + /* Security SDK - will be filled in on NT,XP,2000,2003 */ + NULL, NULL, NULL, NULL, NULL, NULL, + /* ReadConsole and WriteConsole */ + (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsoleW, + (BOOL (WINAPI *)(HANDLE, const VOID*, DWORD, LPDWORD, LPVOID)) WriteConsoleW +}; + +TclWinProcs *tclWinProcs; +static Tcl_Encoding tclWinTCharEncoding; + + +#ifdef HAVE_NO_SEH + +/* Need to add noinline flag to DllMain declaration so that gcc -O3 + * does not inline asm code into DllEntryPoint and cause a + * compile time error because of redefined local labels. + */ + +BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason, + LPVOID reserved) + __attribute__ ((noinline)); + +#else + +/* + * The following declaration is for the VC++ DLL entry point. + */ + +BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason, + LPVOID reserved); +#endif /* HAVE_NO_SEH */ + + +/* + * The following structure and linked list is to allow us to map between + * volume mount points and drive letters on the fly (no Win API exists + * for this). + */ +typedef struct MountPointMap { + CONST WCHAR* volumeName; /* Native wide string volume name */ + char driveLetter; /* Drive letter corresponding to + * the volume name. */ + struct MountPointMap* nextPtr; /* Pointer to next structure in list, + * or NULL */ +} MountPointMap; + +/* + * This is the head of the linked list, which is protected by the + * mutex which follows, for thread-enabled builds. + */ +MountPointMap *driveLetterLookup = NULL; +TCL_DECLARE_MUTEX(mountPointMap) + +/* We will need this below */ +extern Tcl_FSDupInternalRepProc TclNativeDupInternalRep; + +#ifdef __WIN32__ +#ifndef STATIC_BUILD + + +/* + *---------------------------------------------------------------------- + * + * DllEntryPoint -- + * + * This wrapper function is used by Borland to invoke the + * initialization code for Tcl. It simply calls the DllMain + * routine. + * + * Results: + * See DllMain. + * + * Side effects: + * See DllMain. + * + *---------------------------------------------------------------------- + */ + +BOOL APIENTRY +DllEntryPoint(hInst, reason, reserved) + HINSTANCE hInst; /* Library instance handle. */ + DWORD reason; /* Reason this function is being called. */ + LPVOID reserved; /* Not used. */ +{ + return DllMain(hInst, reason, reserved); +} + +/* + *---------------------------------------------------------------------- + * + * DllMain -- + * + * This routine is called by the VC++ C run time library init + * code, or the DllEntryPoint routine. It is responsible for + * initializing various dynamically loaded libraries. + * + * Results: + * TRUE on sucess, FALSE on failure. + * + * Side effects: + * Establishes 32-to-16 bit thunk and initializes sockets library. + * + *---------------------------------------------------------------------- + */ +BOOL APIENTRY +DllMain(hInst, reason, reserved) + HINSTANCE hInst; /* Library instance handle. */ + DWORD reason; /* Reason this function is being called. */ + LPVOID reserved; /* Not used. */ +{ +#ifdef HAVE_NO_SEH + EXCEPTION_REGISTRATION registration; +#endif + + switch (reason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hInst); + TclWinInit(hInst); + return TRUE; + + case DLL_PROCESS_DETACH: + /* + * Protect the call to Tcl_Finalize. The OS could be unloading + * us from an exception handler and the state of the stack might + * be unstable. + */ +#ifdef HAVE_NO_SEH + __asm__ __volatile__ ( + + /* + * Construct an EXCEPTION_REGISTRATION to protect the + * call to Tcl_Finalize + */ + "leal %[registration], %%edx" "\n\t" + "movl %%fs:0, %%eax" "\n\t" + "movl %%eax, 0x0(%%edx)" "\n\t" /* link */ + "leal 1f, %%eax" "\n\t" + "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */ + "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */ + "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */ + "movl %[error], 0x10(%%edx)" "\n\t" /* status */ + + /* + * Link the EXCEPTION_REGISTRATION on the chain + */ + "movl %%edx, %%fs:0" "\n\t" + + /* + * Call Tcl_Finalize + */ + "call _Tcl_Finalize" "\n\t" + + /* + * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION + * and store a TCL_OK status + */ + + "movl %%fs:0, %%edx" "\n\t" + "movl %[ok], %%eax" "\n\t" + "movl %%eax, 0x10(%%edx)" "\n\t" + "jmp 2f" "\n" + + /* + * Come here on an exception. Get the EXCEPTION_REGISTRATION + * that we previously put on the chain. + */ + + "1:" "\t" + "movl %%fs:0, %%edx" "\n\t" + "movl 0x8(%%edx), %%edx" "\n" + + + /* + * Come here however we exited. Restore context from the + * EXCEPTION_REGISTRATION in case the stack is unbalanced. + */ + + "2:" "\t" + "movl 0xc(%%edx), %%esp" "\n\t" + "movl 0x8(%%edx), %%ebp" "\n\t" + "movl 0x0(%%edx), %%eax" "\n\t" + "movl %%eax, %%fs:0" "\n\t" + + : + /* No outputs */ + : + [registration] "m" (registration), + [ok] "i" (TCL_OK), + [error] "i" (TCL_ERROR) + : + "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory" + ); + +#else /* HAVE_NO_SEH */ + __try { + Tcl_Finalize(); + } __except (EXCEPTION_EXECUTE_HANDLER) { + /* empty handler body. */ + } +#endif + + break; + } + + return TRUE; +} + +#endif /* !STATIC_BUILD */ +#endif /* __WIN32__ */ + +/* + *---------------------------------------------------------------------- + * + * TclWinGetTclInstance -- + * + * Retrieves the global library instance handle. + * + * Results: + * Returns the global library instance handle. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +HINSTANCE +TclWinGetTclInstance() +{ + return hInstance; +} + +/* + *---------------------------------------------------------------------- + * + * TclWinInit -- + * + * This function initializes the internal state of the tcl library. + * + * Results: + * None. + * + * Side effects: + * Initializes the tclPlatformId variable. + * + *---------------------------------------------------------------------- + */ + +void +TclWinInit(hInst) + HINSTANCE hInst; /* Library instance handle. */ +{ + OSVERSIONINFO os; + + hInstance = hInst; + os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&os); + platformId = os.dwPlatformId; + + /* + * We no longer support Win32s, so just in case someone manages to + * get a runtime there, make sure they know that. + */ + + if (platformId == VER_PLATFORM_WIN32s) { + panic("Win32s is not a supported platform"); + } + + tclWinProcs = &asciiProcs; +} + +/* + *---------------------------------------------------------------------- + * + * TclWinGetPlatformId -- + * + * Determines whether running under NT, 95, or Win32s, to allow + * runtime conditional code. + * + * Results: + * The return value is one of: + * VER_PLATFORM_WIN32s Win32s on Windows 3.1. (not supported) + * VER_PLATFORM_WIN32_WINDOWS Win32 on Windows 95. + * VER_PLATFORM_WIN32_NT Win32 on Windows NT + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclWinGetPlatformId() +{ + return platformId; +} + +/* + *------------------------------------------------------------------------- + * + * TclWinNoBackslash -- + * + * We're always iterating through a string in Windows, changing the + * backslashes to slashes for use in Tcl. + * + * Results: + * All backslashes in given string are changed to slashes. + * + * Side effects: + * None. + * + *------------------------------------------------------------------------- + */ + +char * +TclWinNoBackslash( + char *path) /* String to change. */ +{ + char *p; + + for (p = path; *p != '\0'; p++) { + if (*p == '\\') { + *p = '/'; + } + } + return path; +} + +/* + *---------------------------------------------------------------------- + * + * TclpCheckStackSpace -- + * + * Detect if we are about to blow the stack. Called before an + * evaluation can happen when nesting depth is checked. + * + * Results: + * 1 if there is enough stack space to continue; 0 if not. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclpCheckStackSpace() +{ + +#ifdef HAVE_NO_SEH + EXCEPTION_REGISTRATION registration; +#endif + int retval = 0; + + /* + * We can recurse only if there is at least TCL_WIN_STACK_THRESHOLD + * bytes of stack space left. alloca() is cheap on windows; basically + * it just subtracts from the stack pointer causing the OS to throw an + * exception if the stack pointer is set below the bottom of the stack. + */ + +#ifdef HAVE_NO_SEH + __asm__ __volatile__ ( + + /* + * Construct an EXCEPTION_REGISTRATION to protect the + * call to __alloca + */ + "leal %[registration], %%edx" "\n\t" + "movl %%fs:0, %%eax" "\n\t" + "movl %%eax, 0x0(%%edx)" "\n\t" /* link */ + "leal 1f, %%eax" "\n\t" + "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */ + "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */ + "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */ + "movl %[error], 0x10(%%edx)" "\n\t" /* status */ + + /* + * Link the EXCEPTION_REGISTRATION on the chain + */ + "movl %%edx, %%fs:0" "\n\t" + + /* + * Attempt a call to __alloca, to determine whether there's + * sufficient memory to be had. + */ + + "movl %[size], %%eax" "\n\t" + "pushl %%eax" "\n\t" + "call __alloca" "\n\t" + + /* + * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION + * and store a TCL_OK status + */ + "movl %%fs:0, %%edx" "\n\t" + "movl %[ok], %%eax" "\n\t" + "movl %%eax, 0x10(%%edx)" "\n\t" + "jmp 2f" "\n" + + /* + * Come here on an exception. Get the EXCEPTION_REGISTRATION + * that we previously put on the chain. + */ + "1:" "\t" + "movl %%fs:0, %%edx" "\n\t" + "movl 0x8(%%edx), %%edx" "\n\t" + + /* + * Come here however we exited. Restore context from the + * EXCEPTION_REGISTRATION in case the stack is unbalanced. + */ + + "2:" "\t" + "movl 0xc(%%edx), %%esp" "\n\t" + "movl 0x8(%%edx), %%ebp" "\n\t" + "movl 0x0(%%edx), %%eax" "\n\t" + "movl %%eax, %%fs:0" "\n\t" + + : + /* No outputs */ + : + [registration] "m" (registration), + [ok] "i" (TCL_OK), + [error] "i" (TCL_ERROR), + [size] "i" (TCL_WIN_STACK_THRESHOLD) + : + "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory" + ); + retval = (registration.status == TCL_OK); + +#else /* !HAVE_NO_SEH */ + __try { +#ifdef HAVE_ALLOCA_GCC_INLINE + __asm__ __volatile__ ( + "movl %0, %%eax" "\n\t" + "call __alloca" "\n\t" + : + : "i"(TCL_WIN_STACK_THRESHOLD) + : "%eax"); +#else + alloca(TCL_WIN_STACK_THRESHOLD); +#endif /* HAVE_ALLOCA_GCC_INLINE */ + retval = 1; + } __except (EXCEPTION_EXECUTE_HANDLER) {} +#endif /* HAVE_NO_SEH */ + + return retval; +} + +/* + *---------------------------------------------------------------------- + * + * TclWinGetPlatform -- + * + * This is a kludge that allows the test library to get access + * the internal tclPlatform variable. + * + * Results: + * Returns a pointer to the tclPlatform variable. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +TclPlatformType * +TclWinGetPlatform() +{ + return &tclPlatform; +} + +/* + *--------------------------------------------------------------------------- + * + * TclWinSetInterfaces -- + * + * A helper proc that allows the test library to change the + * tclWinProcs structure to dispatch to either the wide-character + * or multi-byte versions of the operating system calls, depending + * on whether Unicode is the system encoding. + * + * As well as this, we can also try to load in some additional + * procs which may/may not be present depending on the current + * Windows version (e.g. Win95 will not have the procs below). + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +void +TclWinSetInterfaces( + int wide) /* Non-zero to use wide interfaces, 0 + * otherwise. */ +{ + Tcl_FreeEncoding(tclWinTCharEncoding); + + if (wide) { + tclWinProcs = &unicodeProcs; + tclWinTCharEncoding = Tcl_GetEncoding(NULL, "unicode"); + if (tclWinProcs->getFileAttributesExProc == NULL) { + HINSTANCE hInstance = LoadLibraryA("kernel32"); + if (hInstance != NULL) { + tclWinProcs->getFileAttributesExProc = + (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS, + LPVOID)) GetProcAddress(hInstance, "GetFileAttributesExW"); + tclWinProcs->createHardLinkProc = + (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*, + LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance, + "CreateHardLinkW"); + tclWinProcs->findFirstFileExProc = + (HANDLE (WINAPI *)(CONST TCHAR*, UINT, + LPVOID, UINT, LPVOID, DWORD)) GetProcAddress(hInstance, + "FindFirstFileExW"); + tclWinProcs->getVolumeNameForVMPProc = + (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*, + DWORD)) GetProcAddress(hInstance, + "GetVolumeNameForVolumeMountPointW"); + FreeLibrary(hInstance); + } + hInstance = LoadLibraryA("advapi32"); + if (hInstance != NULL) { + tclWinProcs->getFileSecurityProc = (BOOL (WINAPI *)( + LPCTSTR lpFileName, + SECURITY_INFORMATION RequestedInformation, + PSECURITY_DESCRIPTOR pSecurityDescriptor, + DWORD nLength, LPDWORD lpnLengthNeeded)) + GetProcAddress(hInstance, "GetFileSecurityW"); + tclWinProcs->impersonateSelfProc = (BOOL (WINAPI *) ( + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)) + GetProcAddress(hInstance, "ImpersonateSelf"); + tclWinProcs->openThreadTokenProc = (BOOL (WINAPI *) ( + HANDLE ThreadHandle, DWORD DesiredAccess, + BOOL OpenAsSelf, PHANDLE TokenHandle)) + GetProcAddress(hInstance, "OpenThreadToken"); + tclWinProcs->revertToSelfProc = (BOOL (WINAPI *) (void)) + GetProcAddress(hInstance, "RevertToSelf"); + tclWinProcs->mapGenericMaskProc = (VOID (WINAPI *) ( + PDWORD AccessMask, PGENERIC_MAPPING GenericMapping)) + GetProcAddress(hInstance, "MapGenericMask"); + tclWinProcs->accessCheckProc = (BOOL (WINAPI *)( + PSECURITY_DESCRIPTOR pSecurityDescriptor, + HANDLE ClientToken, DWORD DesiredAccess, + PGENERIC_MAPPING GenericMapping, + PPRIVILEGE_SET PrivilegeSet, + LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess, + LPBOOL AccessStatus)) GetProcAddress(hInstance, + "AccessCheck"); + FreeLibrary(hInstance); + } + } + } else { + tclWinProcs = &asciiProcs; + tclWinTCharEncoding = NULL; + if (tclWinProcs->getFileAttributesExProc == NULL) { + HINSTANCE hInstance = LoadLibraryA("kernel32"); + if (hInstance != NULL) { + tclWinProcs->getFileAttributesExProc = + (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS, + LPVOID)) GetProcAddress(hInstance, "GetFileAttributesExA"); + tclWinProcs->createHardLinkProc = + (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*, + LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance, + "CreateHardLinkA"); + tclWinProcs->findFirstFileExProc = + (HANDLE (WINAPI *)(CONST TCHAR*, UINT, + LPVOID, UINT, LPVOID, DWORD)) GetProcAddress(hInstance, + "FindFirstFileExA"); + tclWinProcs->getLongPathNameProc = NULL; + tclWinProcs->getVolumeNameForVMPProc = + (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*, + DWORD)) GetProcAddress(hInstance, + "GetVolumeNameForVolumeMountPointA"); + FreeLibrary(hInstance); + } + } + } +} + +/* + *--------------------------------------------------------------------------- + * + * TclWinResetInterfaceEncodings -- + * + * Called during finalization to free up any encodings we use. + * The tclWinProcs-> look up table is still ok to use after + * this call, provided no encoding conversion is required. + * + * We also clean up any memory allocated in our mount point + * map which is used to follow certain kinds of symlinks. + * That code should never be used once encodings are taken + * down. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ +void +TclWinResetInterfaceEncodings() +{ + MountPointMap *dlIter, *dlIter2; + if (tclWinTCharEncoding != NULL) { + Tcl_FreeEncoding(tclWinTCharEncoding); + tclWinTCharEncoding = NULL; + } + /* Clean up the mount point map */ + Tcl_MutexLock(&mountPointMap); + dlIter = driveLetterLookup; + while (dlIter != NULL) { + dlIter2 = dlIter->nextPtr; + ckfree((char*)dlIter->volumeName); + ckfree((char*)dlIter); + dlIter = dlIter2; + } + Tcl_MutexUnlock(&mountPointMap); +} + +/* + *--------------------------------------------------------------------------- + * + * TclWinResetInterfaces -- + * + * Called during finalization to reset us to a safe state for reuse. + * After this call, it is best not to use the tclWinProcs-> look + * up table since it is likely to be different to what is expected. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ +void +TclWinResetInterfaces() +{ + tclWinProcs = &asciiProcs; +} + +/* + *-------------------------------------------------------------------- + * + * TclWinDriveLetterForVolMountPoint + * + * Unfortunately, Windows provides no easy way at all to get hold + * of the drive letter for a volume mount point, but we need that + * information to understand paths correctly. So, we have to + * build an associated array to find these correctly, and allow + * quick and easy lookup from volume mount points to drive letters. + * + * We assume here that we are running on a system for which the wide + * character interfaces are used, which is valid for Win 2000 and WinXP + * which are the only systems on which this function will ever be called. + * + * Result: the drive letter, or -1 if no drive letter corresponds to + * the given mount point. + * + *-------------------------------------------------------------------- + */ +char +TclWinDriveLetterForVolMountPoint(CONST WCHAR *mountPoint) +{ + MountPointMap *dlIter, *dlPtr2; + WCHAR Target[55]; /* Target of mount at mount point */ + WCHAR drive[4] = { L'A', L':', L'\\', L'\0' }; + + /* + * Detect the volume mounted there. Unfortunately, there is no + * simple way to map a unique volume name to a DOS drive letter. + * So, we have to build an associative array. + */ + + Tcl_MutexLock(&mountPointMap); + dlIter = driveLetterLookup; + while (dlIter != NULL) { + if (wcscmp(dlIter->volumeName, mountPoint) == 0) { + /* + * We need to check whether this information is + * still valid, since either the user or various + * programs could have adjusted the mount points on + * the fly. + */ + drive[0] = L'A' + (dlIter->driveLetter - 'A'); + /* Try to read the volume mount point and see where it points */ + if ((*tclWinProcs->getVolumeNameForVMPProc)((TCHAR*)drive, + (TCHAR*)Target, 55) != 0) { + if (wcscmp((WCHAR*)dlIter->volumeName, Target) == 0) { + /* Nothing has changed */ + Tcl_MutexUnlock(&mountPointMap); + return dlIter->driveLetter; + } + } + /* + * If we reach here, unfortunately, this mount point is + * no longer valid at all + */ + if (driveLetterLookup == dlIter) { + dlPtr2 = dlIter; + driveLetterLookup = dlIter->nextPtr; + } else { + for (dlPtr2 = driveLetterLookup; + dlPtr2 != NULL; dlPtr2 = dlPtr2->nextPtr) { + if (dlPtr2->nextPtr == dlIter) { + dlPtr2->nextPtr = dlIter->nextPtr; + dlPtr2 = dlIter; + break; + } + } + } + /* Now dlPtr2 points to the structure to free */ + ckfree((char*)dlPtr2->volumeName); + ckfree((char*)dlPtr2); + /* + * Restart the loop --- we could try to be clever + * and continue half way through, but the logic is a + * bit messy, so it's cleanest just to restart + */ + dlIter = driveLetterLookup; + continue; + } + dlIter = dlIter->nextPtr; + } + + /* We couldn't find it, so we must iterate over the letters */ + + for (drive[0] = L'A'; drive[0] <= L'Z'; drive[0]++) { + /* Try to read the volume mount point and see where it points */ + if ((*tclWinProcs->getVolumeNameForVMPProc)((TCHAR*)drive, + (TCHAR*)Target, 55) != 0) { + int alreadyStored = 0; + for (dlIter = driveLetterLookup; dlIter != NULL; + dlIter = dlIter->nextPtr) { + if (wcscmp((WCHAR*)dlIter->volumeName, Target) == 0) { + alreadyStored = 1; + break; + } + } + if (!alreadyStored) { + dlPtr2 = (MountPointMap*) ckalloc(sizeof(MountPointMap)); + dlPtr2->volumeName = TclNativeDupInternalRep(Target); + dlPtr2->driveLetter = 'A' + (drive[0] - L'A'); + dlPtr2->nextPtr = driveLetterLookup; + driveLetterLookup = dlPtr2; + } + } + } + /* Try again */ + for (dlIter = driveLetterLookup; dlIter != NULL; + dlIter = dlIter->nextPtr) { + if (wcscmp(dlIter->volumeName, mountPoint) == 0) { + Tcl_MutexUnlock(&mountPointMap); + return dlIter->driveLetter; + } + } + /* + * The volume doesn't appear to correspond to a drive letter -- we + * remember that fact and store '-1' so we don't have to look it + * up each time. + */ + dlPtr2 = (MountPointMap*) ckalloc(sizeof(MountPointMap)); + dlPtr2->volumeName = TclNativeDupInternalRep((ClientData)mountPoint); + dlPtr2->driveLetter = -1; + dlPtr2->nextPtr = driveLetterLookup; + driveLetterLookup = dlPtr2; + Tcl_MutexUnlock(&mountPointMap); + return -1; +} + +/* + *--------------------------------------------------------------------------- + * + * Tcl_WinUtfToTChar, Tcl_WinTCharToUtf -- + * + * Convert between UTF-8 and Unicode when running Windows NT or + * the current ANSI code page when running Windows 95. + * + * On Mac, Unix, and Windows 95, all strings exchanged between Tcl + * and the OS are "char" oriented. We need only one Tcl_Encoding to + * convert between UTF-8 and the system's native encoding. We use + * NULL to represent that encoding. + * + * On NT, some strings exchanged between Tcl and the OS are "char" + * oriented, while others are in Unicode. We need two Tcl_Encoding + * APIs depending on whether we are targeting a "char" or Unicode + * interface. + * + * Calling Tcl_UtfToExternal() or Tcl_ExternalToUtf() with an + * encoding of NULL should always used to convert between UTF-8 + * and the system's "char" oriented encoding. The following two + * functions are used in Windows-specific code to convert between + * UTF-8 and Unicode strings (NT) or "char" strings(95). This saves + * you the trouble of writing the following type of fragment over and + * over: + * + * if (running NT) { + * encoding <- Tcl_GetEncoding("unicode"); + * nativeBuffer <- UtfToExternal(encoding, utfBuffer); + * Tcl_FreeEncoding(encoding); + * } else { + * nativeBuffer <- UtfToExternal(NULL, utfBuffer); + * } + * + * By convention, in Windows a TCHAR is a character in the ANSI code + * page on Windows 95, a Unicode character on Windows NT. If you + * plan on targeting a Unicode interfaces when running on NT and a + * "char" oriented interface while running on 95, these functions + * should be used. If you plan on targetting the same "char" + * oriented function on both 95 and NT, use Tcl_UtfToExternal() + * with an encoding of NULL. + * + * Results: + * The result is a pointer to the string in the desired target + * encoding. Storage for the result string is allocated in + * dsPtr; the caller must call Tcl_DStringFree() when the result + * is no longer needed. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +TCHAR * +Tcl_WinUtfToTChar(string, len, dsPtr) + CONST char *string; /* Source string in UTF-8. */ + int len; /* Source string length in bytes, or < 0 for + * strlen(). */ + Tcl_DString *dsPtr; /* Uninitialized or free DString in which + * the converted string is stored. */ +{ + return (TCHAR *) Tcl_UtfToExternalDString(tclWinTCharEncoding, + string, len, dsPtr); +} + +char * +Tcl_WinTCharToUtf(string, len, dsPtr) + CONST TCHAR *string; /* Source string in Unicode when running + * NT, ANSI when running 95. */ + int len; /* Source string length in bytes, or < 0 for + * platform-specific string length. */ + Tcl_DString *dsPtr; /* Uninitialized or free DString in which + * the converted string is stored. */ +{ + return Tcl_ExternalToUtfDString(tclWinTCharEncoding, + (CONST char *) string, len, dsPtr); +} + +/* + *------------------------------------------------------------------------ + * + * TclWinCPUID -- + * + * Get CPU ID information on an Intel box under Windows + * + * Results: + * Returns TCL_OK if successful, TCL_ERROR if CPUID is not + * supported or fails. + * + * Side effects: + * If successful, stores EAX, EBX, ECX and EDX registers after + * the CPUID instruction in the four integers designated by 'regsPtr' + * + *---------------------------------------------------------------------- + */ + +int +TclWinCPUID( unsigned int index, /* Which CPUID value to retrieve */ + unsigned int * regsPtr ) /* Registers after the CPUID */ +{ + +#ifdef HAVE_NO_SEH + EXCEPTION_REGISTRATION registration; +#endif + int status = TCL_ERROR; + +#if defined(__GNUC__) && !defined(_WIN64) + + /* + * Execute the CPUID instruction with the given index, and + * store results off 'regPtr'. + */ + + __asm__ __volatile__ ( + + /* + * Construct an EXCEPTION_REGISTRATION to protect the + * CPUID instruction (early 486's don't have CPUID) + */ + "leal %[registration], %%edx" "\n\t" + "movl %%fs:0, %%eax" "\n\t" + "movl %%eax, 0x0(%%edx)" "\n\t" /* link */ + "leal 1f, %%eax" "\n\t" + "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */ + "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */ + "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */ + "movl %[error], 0x10(%%edx)" "\n\t" /* status */ + + /* + * Link the EXCEPTION_REGISTRATION on the chain + */ + "movl %%edx, %%fs:0" "\n\t" + + /* + * Do the CPUID instruction, and save the results in + * the 'regsPtr' area + */ + + "movl %[rptr], %%edi" "\n\t" + "movl %[index], %%eax" "\n\t" + "cpuid" "\n\t" + "movl %%eax, 0x0(%%edi)" "\n\t" + "movl %%ebx, 0x4(%%edi)" "\n\t" + "movl %%ecx, 0x8(%%edi)" "\n\t" + "movl %%edx, 0xc(%%edi)" "\n\t" + + /* + * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION + * and store a TCL_OK status + */ + "movl %%fs:0, %%edx" "\n\t" + "movl %[ok], %%eax" "\n\t" + "movl %%eax, 0x10(%%edx)" "\n\t" + "jmp 2f" "\n" + + /* + * Come here on an exception. Get the EXCEPTION_REGISTRATION + * that we previously put on the chain. + */ + "1:" "\t" + "movl %%fs:0, %%edx" "\n\t" + "movl 0x8(%%edx), %%edx" "\n\t" + + /* + * Come here however we exited. Restore context from the + * EXCEPTION_REGISTRATION in case the stack is unbalanced. + */ + + "2:" "\t" + "movl 0xc(%%edx), %%esp" "\n\t" + "movl 0x8(%%edx), %%ebp" "\n\t" + "movl 0x0(%%edx), %%eax" "\n\t" + "movl %%eax, %%fs:0" "\n\t" + + : + /* No outputs */ + : + [index] "m" (index), + [rptr] "m" (regsPtr), + [registration] "m" (registration), + [ok] "i" (TCL_OK), + [error] "i" (TCL_ERROR) + : + "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory" ); + status = registration.status; + +#elif defined(_MSC_VER) && !defined(_WIN64) + + /* Define a structure in the stack frame to hold the registers */ + + struct { + DWORD dw0; + DWORD dw1; + DWORD dw2; + DWORD dw3; + } regs; + regs.dw0 = index; + + /* Execute the CPUID instruction and save regs in the stack frame */ + + _try { + _asm { + push ebx + push ecx + push edx + mov eax, regs.dw0 + cpuid + mov regs.dw0, eax + mov regs.dw1, ebx + mov regs.dw2, ecx + mov regs.dw3, edx + pop edx + pop ecx + pop ebx + } + + /* Copy regs back out to the caller */ + + regsPtr[0]=regs.dw0; + regsPtr[1]=regs.dw1; + regsPtr[2]=regs.dw2; + regsPtr[3]=regs.dw3; + + status = TCL_OK; + } __except( EXCEPTION_EXECUTE_HANDLER ) { + } + +#else + /* Don't know how to do assembly code for + * this compiler and/or architecture */ +#endif + return status; +}