1 |
/* $Header$ */ |
2 |
|
3 |
/* |
4 |
* winMain.c -- |
5 |
* |
6 |
* Main entry point for wish and other Tk-based applications. |
7 |
* |
8 |
* Copyright (c) 1995-1997 Sun Microsystems, Inc. |
9 |
* Copyright (c) 1998-1999 by Scriptics Corporation. |
10 |
* |
11 |
* See the file "license.terms" for information on usage and redistribution |
12 |
* of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
13 |
* |
14 |
* RCS: @(#) $Id: winmain.c,v 1.1.1.1 2001/06/13 05:15:23 dtashley Exp $ |
15 |
*/ |
16 |
|
17 |
#include "tk.h" |
18 |
#define WIN32_LEAN_AND_MEAN |
19 |
#include <windows.h> |
20 |
#undef WIN32_LEAN_AND_MEAN |
21 |
#include <malloc.h> |
22 |
#include <locale.h> |
23 |
|
24 |
#include "tkInt.h" |
25 |
|
26 |
/* |
27 |
* The following declarations refer to internal Tk routines. These |
28 |
* interfaces are available for use, but are not supported. |
29 |
*/ |
30 |
|
31 |
|
32 |
/* |
33 |
* Forward declarations for procedures defined later in this file: |
34 |
*/ |
35 |
|
36 |
static void setargv _ANSI_ARGS_((int *argcPtr, char ***argvPtr)); |
37 |
static void WishPanic _ANSI_ARGS_(TCL_VARARGS(char *,format)); |
38 |
|
39 |
#ifdef TK_TEST |
40 |
extern int Tktest_Init(Tcl_Interp *interp); |
41 |
#endif /* TK_TEST */ |
42 |
|
43 |
#ifdef TCL_TEST |
44 |
extern int TclObjTest_Init _ANSI_ARGS_((Tcl_Interp *interp)); |
45 |
extern int Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp)); |
46 |
#endif /* TCL_TEST */ |
47 |
|
48 |
static BOOL consoleRequired = TRUE; |
49 |
|
50 |
/* |
51 |
* The following #if block allows you to change the AppInit |
52 |
* function by using a #define of TCL_LOCAL_APPINIT instead |
53 |
* of rewriting this entire file. The #if checks for that |
54 |
* #define and uses Tcl_AppInit if it doesn't exist. |
55 |
*/ |
56 |
|
57 |
#ifndef TK_LOCAL_APPINIT |
58 |
#define TK_LOCAL_APPINIT Tcl_AppInit |
59 |
#endif |
60 |
extern int TK_LOCAL_APPINIT _ANSI_ARGS_((Tcl_Interp *interp)); |
61 |
|
62 |
/* |
63 |
* The following #if block allows you to change how Tcl finds the startup |
64 |
* script, prime the library or encoding paths, fiddle with the argv, |
65 |
* etc., without needing to rewrite Tk_Main() |
66 |
*/ |
67 |
|
68 |
#ifdef TK_LOCAL_MAIN_HOOK |
69 |
extern int TK_LOCAL_MAIN_HOOK _ANSI_ARGS_((int *argc, char ***argv)); |
70 |
#endif |
71 |
|
72 |
|
73 |
/* |
74 |
*---------------------------------------------------------------------- |
75 |
* |
76 |
* WinMain -- |
77 |
* |
78 |
* Main entry point from Windows. |
79 |
* |
80 |
* Results: |
81 |
* Returns false if initialization fails, otherwise it never |
82 |
* returns. |
83 |
* |
84 |
* Side effects: |
85 |
* Just about anything, since from here we call arbitrary Tcl code. |
86 |
* |
87 |
*---------------------------------------------------------------------- |
88 |
*/ |
89 |
|
90 |
int APIENTRY |
91 |
WinMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow) |
92 |
HINSTANCE hInstance; |
93 |
HINSTANCE hPrevInstance; |
94 |
LPSTR lpszCmdLine; |
95 |
int nCmdShow; |
96 |
{ |
97 |
char **argv; |
98 |
int argc; |
99 |
char buffer[MAX_PATH+1]; |
100 |
char *p; |
101 |
|
102 |
Tcl_SetPanicProc(WishPanic); |
103 |
|
104 |
/* |
105 |
* Increase the application queue size from default value of 8. |
106 |
* At the default value, cross application SendMessage of WM_KILLFOCUS |
107 |
* will fail because the handler will not be able to do a PostMessage! |
108 |
* This is only needed for Windows 3.x, since NT dynamically expands |
109 |
* the queue. |
110 |
*/ |
111 |
|
112 |
SetMessageQueue(64); |
113 |
|
114 |
/* |
115 |
* Create the console channels and install them as the standard |
116 |
* channels. All I/O will be discarded until Tk_CreateConsoleWindow is |
117 |
* called to attach the console to a text widget. |
118 |
*/ |
119 |
|
120 |
consoleRequired = TRUE; |
121 |
|
122 |
/* |
123 |
* Set up the default locale to be standard "C" locale so parsing |
124 |
* is performed correctly. |
125 |
*/ |
126 |
|
127 |
setlocale(LC_ALL, "C"); |
128 |
setargv(&argc, &argv); |
129 |
|
130 |
/* |
131 |
* Replace argv[0] with full pathname of executable, and forward |
132 |
* slashes substituted for backslashes. |
133 |
*/ |
134 |
|
135 |
GetModuleFileName(NULL, buffer, sizeof(buffer)); |
136 |
argv[0] = buffer; |
137 |
for (p = buffer; *p != '\0'; p++) { |
138 |
if (*p == '\\') { |
139 |
*p = '/'; |
140 |
} |
141 |
} |
142 |
|
143 |
#ifdef TK_LOCAL_MAIN_HOOK |
144 |
TK_LOCAL_MAIN_HOOK(&argc, &argv); |
145 |
#endif |
146 |
|
147 |
Tk_Main(argc, argv, Tcl_AppInit); |
148 |
|
149 |
return 1; |
150 |
} |
151 |
|
152 |
|
153 |
|
154 |
/* |
155 |
*---------------------------------------------------------------------- |
156 |
* |
157 |
* Tcl_AppInit -- |
158 |
* |
159 |
* This procedure performs application-specific initialization. |
160 |
* Most applications, especially those that incorporate additional |
161 |
* packages, will have their own version of this procedure. |
162 |
* |
163 |
* Results: |
164 |
* Returns a standard Tcl completion code, and leaves an error |
165 |
* message in the interp's result if an error occurs. |
166 |
* |
167 |
* Side effects: |
168 |
* Depends on the startup script. |
169 |
* |
170 |
*---------------------------------------------------------------------- |
171 |
*/ |
172 |
|
173 |
int |
174 |
Tcl_AppInit(interp) |
175 |
Tcl_Interp *interp; /* Interpreter for application. */ |
176 |
{ |
177 |
if (Tcl_Init(interp) == TCL_ERROR) { |
178 |
goto error; |
179 |
} |
180 |
if (Tk_Init(interp) == TCL_ERROR) { |
181 |
goto error; |
182 |
} |
183 |
Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); |
184 |
|
185 |
/* |
186 |
* Initialize the console only if we are running as an interactive |
187 |
* application. |
188 |
*/ |
189 |
|
190 |
if (consoleRequired) { |
191 |
if (Tk_CreateConsoleWindow(interp) == TCL_ERROR) { |
192 |
goto error; |
193 |
} |
194 |
} |
195 |
|
196 |
#ifdef TCL_TEST |
197 |
if (Tcltest_Init(interp) == TCL_ERROR) { |
198 |
return TCL_ERROR; |
199 |
} |
200 |
Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init, |
201 |
(Tcl_PackageInitProc *) NULL); |
202 |
if (TclObjTest_Init(interp) == TCL_ERROR) { |
203 |
return TCL_ERROR; |
204 |
} |
205 |
#endif /* TCL_TEST */ |
206 |
|
207 |
#ifdef TK_TEST |
208 |
if (Tktest_Init(interp) == TCL_ERROR) { |
209 |
goto error; |
210 |
} |
211 |
Tcl_StaticPackage(interp, "Tktest", Tktest_Init, |
212 |
(Tcl_PackageInitProc *) NULL); |
213 |
#endif /* TK_TEST */ |
214 |
|
215 |
Tcl_SetVar(interp, "tcl_rcFileName", "~/wishrc.tcl", TCL_GLOBAL_ONLY); |
216 |
return TCL_OK; |
217 |
|
218 |
error: |
219 |
MessageBeep(MB_ICONEXCLAMATION); |
220 |
MessageBox(NULL, Tcl_GetStringResult(interp), "Error in Wish", |
221 |
MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND); |
222 |
ExitProcess(1); |
223 |
/* we won't reach this, but we need the return */ |
224 |
return TCL_ERROR; |
225 |
} |
226 |
|
227 |
/* |
228 |
*---------------------------------------------------------------------- |
229 |
* |
230 |
* WishPanic -- |
231 |
* |
232 |
* Display a message and exit. |
233 |
* |
234 |
* Results: |
235 |
* None. |
236 |
* |
237 |
* Side effects: |
238 |
* Exits the program. |
239 |
* |
240 |
*---------------------------------------------------------------------- |
241 |
*/ |
242 |
|
243 |
void |
244 |
WishPanic TCL_VARARGS_DEF(char *,arg1) |
245 |
{ |
246 |
va_list argList; |
247 |
char buf[1024]; |
248 |
char *format; |
249 |
|
250 |
format = TCL_VARARGS_START(char *,arg1,argList); |
251 |
vsprintf(buf, format, argList); |
252 |
|
253 |
MessageBeep(MB_ICONEXCLAMATION); |
254 |
MessageBox(NULL, buf, "Fatal Error in Wish", |
255 |
MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND); |
256 |
#ifdef _MSC_VER |
257 |
DebugBreak(); |
258 |
#endif |
259 |
ExitProcess(1); |
260 |
} |
261 |
/* |
262 |
*------------------------------------------------------------------------- |
263 |
* |
264 |
* setargv -- |
265 |
* |
266 |
* Parse the Windows command line string into argc/argv. Done here |
267 |
* because we don't trust the builtin argument parser in crt0. |
268 |
* Windows applications are responsible for breaking their command |
269 |
* line into arguments. |
270 |
* |
271 |
* 2N backslashes + quote -> N backslashes + begin quoted string |
272 |
* 2N + 1 backslashes + quote -> literal |
273 |
* N backslashes + non-quote -> literal |
274 |
* quote + quote in a quoted string -> single quote |
275 |
* quote + quote not in quoted string -> empty string |
276 |
* quote -> begin quoted string |
277 |
* |
278 |
* Results: |
279 |
* Fills argcPtr with the number of arguments and argvPtr with the |
280 |
* array of arguments. |
281 |
* |
282 |
* Side effects: |
283 |
* Memory allocated. |
284 |
* |
285 |
*-------------------------------------------------------------------------- |
286 |
*/ |
287 |
|
288 |
static void |
289 |
setargv(argcPtr, argvPtr) |
290 |
int *argcPtr; /* Filled with number of argument strings. */ |
291 |
char ***argvPtr; /* Filled with argument strings (malloc'd). */ |
292 |
{ |
293 |
char *cmdLine, *p, *arg, *argSpace; |
294 |
char **argv; |
295 |
int argc, size, inquote, copy, slashes; |
296 |
|
297 |
cmdLine = GetCommandLine(); /* INTL: BUG */ |
298 |
|
299 |
/* |
300 |
* Precompute an overly pessimistic guess at the number of arguments |
301 |
* in the command line by counting non-space spans. |
302 |
*/ |
303 |
|
304 |
size = 2; |
305 |
for (p = cmdLine; *p != '\0'; p++) { |
306 |
if ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ |
307 |
size++; |
308 |
while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ |
309 |
p++; |
310 |
} |
311 |
if (*p == '\0') { |
312 |
break; |
313 |
} |
314 |
} |
315 |
} |
316 |
argSpace = (char *) Tcl_Alloc( |
317 |
(unsigned) (size * sizeof(char *) + strlen(cmdLine) + 1)); |
318 |
argv = (char **) argSpace; |
319 |
argSpace += size * sizeof(char *); |
320 |
size--; |
321 |
|
322 |
p = cmdLine; |
323 |
for (argc = 0; argc < size; argc++) { |
324 |
argv[argc] = arg = argSpace; |
325 |
while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ |
326 |
p++; |
327 |
} |
328 |
if (*p == '\0') { |
329 |
break; |
330 |
} |
331 |
|
332 |
inquote = 0; |
333 |
slashes = 0; |
334 |
while (1) { |
335 |
copy = 1; |
336 |
while (*p == '\\') { |
337 |
slashes++; |
338 |
p++; |
339 |
} |
340 |
if (*p == '"') { |
341 |
if ((slashes & 1) == 0) { |
342 |
copy = 0; |
343 |
if ((inquote) && (p[1] == '"')) { |
344 |
p++; |
345 |
copy = 1; |
346 |
} else { |
347 |
inquote = !inquote; |
348 |
} |
349 |
} |
350 |
slashes >>= 1; |
351 |
} |
352 |
|
353 |
while (slashes) { |
354 |
*arg = '\\'; |
355 |
arg++; |
356 |
slashes--; |
357 |
} |
358 |
|
359 |
if ((*p == '\0') |
360 |
|| (!inquote && ((*p == ' ') || (*p == '\t')))) { /* INTL: ISO space. */ |
361 |
break; |
362 |
} |
363 |
if (copy != 0) { |
364 |
*arg = *p; |
365 |
arg++; |
366 |
} |
367 |
p++; |
368 |
} |
369 |
*arg = '\0'; |
370 |
argSpace = arg + 1; |
371 |
} |
372 |
argv[argc] = NULL; |
373 |
|
374 |
*argcPtr = argc; |
375 |
*argvPtr = argv; |
376 |
} |
377 |
|
378 |
|
379 |
/* |
380 |
*---------------------------------------------------------------------- |
381 |
* |
382 |
* main -- |
383 |
* |
384 |
* Main entry point from the console. |
385 |
* |
386 |
* Results: |
387 |
* None: Tk_Main never returns here, so this procedure never |
388 |
* returns either. |
389 |
* |
390 |
* Side effects: |
391 |
* Whatever the applications does. |
392 |
* |
393 |
*---------------------------------------------------------------------- |
394 |
*/ |
395 |
|
396 |
int main(int argc, char **argv) |
397 |
{ |
398 |
Tcl_SetPanicProc(WishPanic); |
399 |
|
400 |
/* |
401 |
* Set up the default locale to be standard "C" locale so parsing |
402 |
* is performed correctly. |
403 |
*/ |
404 |
|
405 |
setlocale(LC_ALL, "C"); |
406 |
/* |
407 |
* Increase the application queue size from default value of 8. |
408 |
* At the default value, cross application SendMessage of WM_KILLFOCUS |
409 |
* will fail because the handler will not be able to do a PostMessage! |
410 |
* This is only needed for Windows 3.x, since NT dynamically expands |
411 |
* the queue. |
412 |
*/ |
413 |
|
414 |
SetMessageQueue(64); |
415 |
|
416 |
/* |
417 |
* Create the console channels and install them as the standard |
418 |
* channels. All I/O will be discarded until Tk_CreateConsoleWindow is |
419 |
* called to attach the console to a text widget. |
420 |
*/ |
421 |
|
422 |
consoleRequired = FALSE; |
423 |
|
424 |
Tk_Main(argc, argv, Tcl_AppInit); |
425 |
return 0; |
426 |
} |
427 |
|
428 |
/* End of winmain.c */ |