]> www.wagner.pp.ru Git - oss/ck.git/blob - winMain.c
Ck console graphics toolkit
[oss/ck.git] / winMain.c
1 /* 
2  * winMain.c --
3  *
4  *      Main entry point for cwsh.
5  *
6  * Copyright (c) 1995 Sun Microsystems, Inc.
7  * Copyright (c) 1999 Christian Werner
8  *
9  * See the file "license.terms" for information on usage and redistribution
10  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11  *
12  * RCS: @(#) $Id: winMain.c,v 1.1 2006-02-24 18:59:53 vitus Exp $
13  */
14
15 #include "ck.h"
16 #define WIN32_LEAN_AND_MEAN
17 #include <windows.h>
18 #undef WIN32_LEAN_AND_MEAN
19 #include <malloc.h>
20 #include <locale.h>
21
22 /*
23  * Forward declarations for procedures defined later in this file:
24  */
25
26 static void             setargv _ANSI_ARGS_((int *argcPtr, char ***argvPtr));
27 static void             CwshPanic _ANSI_ARGS_(TCL_VARARGS(char *,format));
28
29 \f
30 /*
31  *----------------------------------------------------------------------
32  *
33  * WinMain --
34  *
35  *      Main entry point from Windows.
36  *
37  * Results:
38  *      Returns false if initialization fails, otherwise it never
39  *      returns. 
40  *
41  * Side effects:
42  *      Just about anything, since from here we call arbitrary Tcl code.
43  *
44  *----------------------------------------------------------------------
45  */
46
47 int APIENTRY
48 WinMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow)
49     HINSTANCE hInstance;
50     HINSTANCE hPrevInstance;
51     LPSTR lpszCmdLine;
52     int nCmdShow;
53 {
54     char **argv, *p;
55     int argc;
56     char buffer[MAX_PATH];
57
58     Tcl_SetPanicProc(CwshPanic);
59
60     fclose(stdin);
61     fclose(stdout);
62     fclose(stderr);
63     FreeConsole();
64     if (!AllocConsole()) {
65         CwshPanic("Error allocating console");
66     }
67     freopen("CONIN$", "r", stdin);
68     freopen("CONOUT$", "w", stdout);
69     freopen("CONOUT$", "w", stderr);
70
71     /*
72      * Set up the default locale to be standard "C" locale so parsing
73      * is performed correctly.
74      */
75
76     setlocale(LC_ALL, "C");
77
78     /*
79      * Increase the application queue size from default value of 8.
80      * At the default value, cross application SendMessage of WM_KILLFOCUS
81      * will fail because the handler will not be able to do a PostMessage!
82      * This is only needed for Windows 3.x, since NT dynamically expands
83      * the queue.
84      */
85     SetMessageQueue(64);
86
87     setargv(&argc, &argv);
88
89     /*
90      * Replace argv[0] with full pathname of executable, and forward
91      * slashes substituted for backslashes.
92      */
93
94     GetModuleFileName(NULL, buffer, sizeof(buffer));
95     argv[0] = buffer;
96     for (p = buffer; *p != '\0'; p++) {
97         if (*p == '\\') {
98             *p = '/';
99         }
100     }
101
102     Ck_Main(argc, argv, Tcl_AppInit);
103     return 1;
104 }
105 \f
106 /*
107  *----------------------------------------------------------------------
108  *
109  * Tcl_AppInit --
110  *
111  *      This procedure performs application-specific initialization.
112  *      Most applications, especially those that incorporate additional
113  *      packages, will have their own version of this procedure.
114  *
115  * Results:
116  *      Returns a standard Tcl completion code, and leaves an error
117  *      message in interp->result if an error occurs.
118  *
119  * Side effects:
120  *      Depends on the startup script.
121  *
122  *----------------------------------------------------------------------
123  */
124
125 int
126 Tcl_AppInit(interp)
127     Tcl_Interp *interp;         /* Interpreter for application. */
128 {
129     if (Tcl_Init(interp) == TCL_ERROR) {
130         goto error;
131     }
132     if (Ck_Init(interp) == TCL_ERROR) {
133         goto error;
134     }
135 #if (TCL_MAJOR_VERSION == 7) && (TCL_MINOR_VERSION <= 4)
136     tcl_RcFileName = "~/.cwshrc";
137 #else
138     Tcl_StaticPackage(interp, "Ck", Ck_Init, (Tcl_PackageInitProc *) NULL);
139     Tcl_SetVar(interp, "tcl_rcFileName", "~/.cwshrc", TCL_GLOBAL_ONLY);
140 #endif
141     return TCL_OK;
142
143 error:
144     CwshPanic(interp->result);
145     return TCL_ERROR;
146 }
147 \f
148 /*
149  *----------------------------------------------------------------------
150  *
151  * CwshPanic --
152  *
153  *      Display a message and exit.
154  *
155  * Results:
156  *      None.
157  *
158  * Side effects:
159  *      Exits the program.
160  *
161  *----------------------------------------------------------------------
162  */
163
164 void
165 CwshPanic TCL_VARARGS_DEF(char *,arg1)
166 {
167     va_list argList;
168     char buf[1024];
169     char *format;
170     
171     format = TCL_VARARGS_START(char *,arg1,argList);
172     vsprintf(buf, format, argList);
173
174     MessageBeep(MB_ICONEXCLAMATION);
175     MessageBox(NULL, buf, "Fatal Error in CWSH",
176             MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
177 #ifdef _MSC_VER
178     DebugBreak();
179 #endif
180     ExitProcess(1);
181 }
182 /*
183  *-------------------------------------------------------------------------
184  *
185  * setargv --
186  *
187  *      Parse the Windows command line string into argc/argv.  Done here
188  *      because we don't trust the builtin argument parser in crt0.  
189  *      Windows applications are responsible for breaking their command
190  *      line into arguments.
191  *
192  *      2N backslashes + quote -> N backslashes + begin quoted string
193  *      2N + 1 backslashes + quote -> literal
194  *      N backslashes + non-quote -> literal
195  *      quote + quote in a quoted string -> single quote
196  *      quote + quote not in quoted string -> empty string
197  *      quote -> begin quoted string
198  *
199  * Results:
200  *      Fills argcPtr with the number of arguments and argvPtr with the
201  *      array of arguments.
202  *
203  * Side effects:
204  *      Memory allocated.
205  *
206  *--------------------------------------------------------------------------
207  */
208
209 static void
210 setargv(argcPtr, argvPtr)
211     int *argcPtr;               /* Filled with number of argument strings. */
212     char ***argvPtr;            /* Filled with argument strings (malloc'd). */
213 {
214     char *cmdLine, *p, *arg, *argSpace;
215     char **argv;
216     int argc, size, inquote, copy, slashes;
217     
218     cmdLine = GetCommandLine();
219
220     /*
221      * Precompute an overly pessimistic guess at the number of arguments
222      * in the command line by counting non-space spans.
223      */
224
225     size = 2;
226     for (p = cmdLine; *p != '\0'; p++) {
227         if (isspace(*p)) {
228             size++;
229             while (isspace(*p)) {
230                 p++;
231             }
232             if (*p == '\0') {
233                 break;
234             }
235         }
236     }
237     argSpace = (char *) ckalloc((unsigned) (size * sizeof(char *) 
238             + strlen(cmdLine) + 1));
239     argv = (char **) argSpace;
240     argSpace += size * sizeof(char *);
241     size--;
242
243     p = cmdLine;
244     for (argc = 0; argc < size; argc++) {
245         argv[argc] = arg = argSpace;
246         while (isspace(*p)) {
247             p++;
248         }
249         if (*p == '\0') {
250             break;
251         }
252
253         inquote = 0;
254         slashes = 0;
255         while (1) {
256             copy = 1;
257             while (*p == '\\') {
258                 slashes++;
259                 p++;
260             }
261             if (*p == '"') {
262                 if ((slashes & 1) == 0) {
263                     copy = 0;
264                     if ((inquote) && (p[1] == '"')) {
265                         p++;
266                         copy = 1;
267                     } else {
268                         inquote = !inquote;
269                     }
270                 }
271                 slashes >>= 1;
272             }
273
274             while (slashes) {
275                 *arg = '\\';
276                 arg++;
277                 slashes--;
278             }
279
280             if ((*p == '\0') || (!inquote && isspace(*p))) {
281                 break;
282             }
283             if (copy != 0) {
284                 *arg = *p;
285                 arg++;
286             }
287             p++;
288         }
289         *arg = '\0';
290         argSpace = arg + 1;
291     }
292     argv[argc] = NULL;
293
294     *argcPtr = argc;
295     *argvPtr = argv;
296 }
297