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 |
}
|