1 /*
2  * tclAppInit.c --
3  *
4  *	Provides a default version of the main program and Tcl_AppInit
5  *	function for Tcl applications (without Tk). Note that this program
6  *	must be built in Win32 console mode to work properly.
7  *
8  * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
9  * Copyright (c) 1998-1999 by Scriptics Corporation.
10  *
11  * See the file "license.terms" for information on usage and redistribution of
12  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
13  */
14 
15 #include "tcl.h"
16 #include <windows.h>
17 #include <locale.h>
18 
19 #ifdef TCL_TEST
20 extern Tcl_PackageInitProc	Procbodytest_Init;
21 extern Tcl_PackageInitProc	Procbodytest_SafeInit;
22 extern Tcl_PackageInitProc	Tcltest_Init;
23 extern Tcl_PackageInitProc	TclObjTest_Init;
24 #endif /* TCL_TEST */
25 
26 #if defined(__GNUC__)
27 int _CRT_glob = 0;
28 static void		setargv(int *argcPtr, char ***argvPtr);
29 #endif /* __GNUC__ */
30 
31 /*
32  *----------------------------------------------------------------------
33  *
34  * main --
35  *
36  *	This is the main program for the application.
37  *
38  * Results:
39  *	None: Tcl_Main never returns here, so this function never returns
40  *	either.
41  *
42  * Side effects:
43  *	Whatever the application does.
44  *
45  *----------------------------------------------------------------------
46  */
47 
48 int
main(int argc,char * argv[])49 main(
50     int argc,
51     char *argv[])
52 {
53     /*
54      * The following #if block allows you to change the AppInit function by
55      * using a #define of TCL_LOCAL_APPINIT instead of rewriting this entire
56      * file. The #if checks for that #define and uses Tcl_AppInit if it
57      * doesn't exist.
58      */
59 
60 #ifndef TCL_LOCAL_APPINIT
61 #define TCL_LOCAL_APPINIT Tcl_AppInit
62 #endif
63     extern int TCL_LOCAL_APPINIT (Tcl_Interp *interp);
64 
65     /*
66      * The following #if block allows you to change how Tcl finds the startup
67      * script, prime the library or encoding paths, fiddle with the argv,
68      * etc., without needing to rewrite Tcl_Main()
69      */
70 
71 #ifdef TCL_LOCAL_MAIN_HOOK
72     extern int TCL_LOCAL_MAIN_HOOK (int *argc, char ***argv);
73 #endif
74 
75     char *p;
76 
77     /*
78      * Set up the default locale to be standard "C" locale so parsing is
79      * performed correctly.
80      */
81 
82 #if defined(__GNUC__)
83     setargv( &argc, &argv );
84 #endif
85     setlocale(LC_ALL, "C");
86 
87     /*
88      * Forward slashes substituted for backslashes.
89      */
90 
91     for (p = argv[0]; *p != '\0'; p++) {
92 	if (*p == '\\') {
93 	    *p = '/';
94 	}
95     }
96 
97 #ifdef TCL_LOCAL_MAIN_HOOK
98     TCL_LOCAL_MAIN_HOOK(&argc, &argv);
99 #endif
100 
101     Tcl_Main(argc, argv, TCL_LOCAL_APPINIT);
102 
103     return 0;			/* Needed only to prevent compiler warning. */
104 }
105 
106 /*
107  *----------------------------------------------------------------------
108  *
109  * Tcl_AppInit --
110  *
111  *	This function performs application-specific initialization. Most
112  *	applications, especially those that incorporate additional packages,
113  *	will have their own version of this function.
114  *
115  * Results:
116  *	Returns a standard Tcl completion code, and leaves an error message in
117  *	the interp's result if an error occurs.
118  *
119  * Side effects:
120  *	Depends on the startup script.
121  *
122  *----------------------------------------------------------------------
123  */
124 
125 int
Tcl_AppInit(Tcl_Interp * interp)126 Tcl_AppInit(
127     Tcl_Interp *interp)		/* Interpreter for application. */
128 {
129     if (Tcl_Init(interp) == TCL_ERROR) {
130 	return TCL_ERROR;
131     }
132 
133 #ifdef TCL_TEST
134     if (Tcltest_Init(interp) == TCL_ERROR) {
135 	return TCL_ERROR;
136     }
137     Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init, NULL);
138     if (TclObjTest_Init(interp) == TCL_ERROR) {
139 	return TCL_ERROR;
140     }
141     if (Procbodytest_Init(interp) == TCL_ERROR) {
142 	return TCL_ERROR;
143     }
144     Tcl_StaticPackage(interp, "procbodytest", Procbodytest_Init,
145 	    Procbodytest_SafeInit);
146 #endif /* TCL_TEST */
147 
148 #if defined(STATIC_BUILD) && TCL_USE_STATIC_PACKAGES
149     {
150 	extern Tcl_PackageInitProc Registry_Init;
151 	extern Tcl_PackageInitProc Dde_Init;
152 	extern Tcl_PackageInitProc Dde_SafeInit;
153 
154 	if (Registry_Init(interp) == TCL_ERROR) {
155 	    return TCL_ERROR;
156 	}
157 	Tcl_StaticPackage(interp, "registry", Registry_Init, NULL);
158 
159 	if (Dde_Init(interp) == TCL_ERROR) {
160 	    return TCL_ERROR;
161 	}
162 	Tcl_StaticPackage(interp, "dde", Dde_Init, Dde_SafeInit);
163    }
164 #endif
165 
166     /*
167      * Call the init functions for included packages. Each call should look
168      * like this:
169      *
170      * if (Mod_Init(interp) == TCL_ERROR) {
171      *     return TCL_ERROR;
172      * }
173      *
174      * where "Mod" is the name of the module.
175      */
176 
177     /*
178      * Call Tcl_CreateCommand for application-specific commands, if they
179      * weren't already created by the init functions called above.
180      */
181 
182     /*
183      * Specify a user-specific startup file to invoke if the application is
184      * run interactively. Typically the startup file is "~/.apprc" where "app"
185      * is the name of the application. If this line is deleted then no
186      * user-specific startup file will be run under any conditions.
187      */
188 
189     Tcl_SetVar(interp, "tcl_rcFileName", "~/tclshrc.tcl", TCL_GLOBAL_ONLY);
190     return TCL_OK;
191 }
192 
193 /*
194  *-------------------------------------------------------------------------
195  *
196  * setargv --
197  *
198  *	Parse the Windows command line string into argc/argv. Done here
199  *	because we don't trust the builtin argument parser in crt0. Windows
200  *	applications are responsible for breaking their command line into
201  *	arguments.
202  *
203  *	2N backslashes + quote -> N backslashes + begin quoted string
204  *	2N + 1 backslashes + quote -> literal
205  *	N backslashes + non-quote -> literal
206  *	quote + quote in a quoted string -> single quote
207  *	quote + quote not in quoted string -> empty string
208  *	quote -> begin quoted string
209  *
210  * Results:
211  *	Fills argcPtr with the number of arguments and argvPtr with the array
212  *	of arguments.
213  *
214  * Side effects:
215  *	Memory allocated.
216  *
217  *--------------------------------------------------------------------------
218  */
219 
220 #if defined(__GNUC__)
221 static void
setargv(int * argcPtr,char *** argvPtr)222 setargv(
223     int *argcPtr,		/* Filled with number of argument strings. */
224     char ***argvPtr)		/* Filled with argument strings (malloc'd). */
225 {
226     char *cmdLine, *p, *arg, *argSpace;
227     char **argv;
228     int argc, size, inquote, copy, slashes;
229 
230     cmdLine = GetCommandLine();	/* INTL: BUG */
231 
232     /*
233      * Precompute an overly pessimistic guess at the number of arguments in
234      * the command line by counting non-space spans.
235      */
236 
237     size = 2;
238     for (p = cmdLine; *p != '\0'; p++) {
239 	if ((*p == ' ') || (*p == '\t')) {	/* INTL: ISO space. */
240 	    size++;
241 	    while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */
242 		p++;
243 	    }
244 	    if (*p == '\0') {
245 		break;
246 	    }
247 	}
248     }
249     argSpace = (char *) ckalloc(
250 	    (unsigned) (size * sizeof(char *) + strlen(cmdLine) + 1));
251     argv = (char **) argSpace;
252     argSpace += size * sizeof(char *);
253     size--;
254 
255     p = cmdLine;
256     for (argc = 0; argc < size; argc++) {
257 	argv[argc] = arg = argSpace;
258 	while ((*p == ' ') || (*p == '\t')) {	/* INTL: ISO space. */
259 	    p++;
260 	}
261 	if (*p == '\0') {
262 	    break;
263 	}
264 
265 	inquote = 0;
266 	slashes = 0;
267 	while (1) {
268 	    copy = 1;
269 	    while (*p == '\\') {
270 		slashes++;
271 		p++;
272 	    }
273 	    if (*p == '"') {
274 		if ((slashes & 1) == 0) {
275 		    copy = 0;
276 		    if ((inquote) && (p[1] == '"')) {
277 			p++;
278 			copy = 1;
279 		    } else {
280 			inquote = !inquote;
281 		    }
282 		}
283 		slashes >>= 1;
284 	    }
285 
286 	    while (slashes) {
287 		*arg = '\\';
288 		arg++;
289 		slashes--;
290 	    }
291 
292 	    if ((*p == '\0') || (!inquote &&
293 		    ((*p == ' ') || (*p == '\t')))) {	/* INTL: ISO space. */
294 		break;
295 	    }
296 	    if (copy != 0) {
297 		*arg = *p;
298 		arg++;
299 	    }
300 	    p++;
301 	}
302 	*arg = '\0';
303 	argSpace = arg + 1;
304     }
305     argv[argc] = NULL;
306 
307     *argcPtr = argc;
308     *argvPtr = argv;
309 }
310 #endif /* __GNUC__ */
311 
312 /*
313  * Local Variables:
314  * mode: c
315  * c-basic-offset: 4
316  * fill-column: 78
317  * End:
318  */
319