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