/[ascend]/trunk/tcltk98/generic/interface/Driver.c
ViewVC logotype

Annotation of /trunk/tcltk98/generic/interface/Driver.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 21 - (hide annotations) (download) (as text)
Thu Dec 9 02:03:34 2004 UTC (18 years, 3 months ago) by aw0a
File MIME type: text/x-csrc
File size: 40335 byte(s)
fixed environment vars
1 aw0a 1 /*
2     * Driver.c
3     * by Kirk Abbott and Ben Allan
4     * Created: 1/94
5     * Version: $Revision: 1.48 $
6     * Version control file: $RCSfile: Driver.c,v $
7     * Date last modified: $Date: 2003/08/23 18:43:06 $
8     * Last modified by: $Author: ballan $
9     *
10     * This file is part of the ASCEND Tcl/Tk interface
11     *
12     * Copyright 1997, Carnegie Mellon University
13     *
14     * The ASCEND Tcl/Tk interface is free software; you can redistribute
15     * it and/or modify it under the terms of the GNU General Public License as
16     * published by the Free Software Foundation; either version 2 of the
17     * License, or (at your option) any later version.
18     *
19     * The ASCEND Tcl/Tk interface is distributed in hope that it will be
20     * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
21     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22     * General Public License for more details.
23     *
24     * You should have received a copy of the GNU General Public License
25     * along with the program; if not, write to the Free Software Foundation,
26     * Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named
27     * COPYING. COPYING is found in ../compiler.
28     */
29    
30     #include <stdarg.h>
31     #include <ctype.h>
32     #include <signal.h>
33     #include <time.h>
34     #include "tcl.h"
35     #include "tk.h"
36     #include "utilities/ascConfig.h"
37     #ifndef __WIN32__
38     #include <unistd.h>
39     #else
40     #define WIN32_LEAN_AND_MEAN
41     #include <windows.h>
42     #include <locale.h>
43     #undef WIN32_LEAN_AND_MEAN
44     #endif /* __WIN32__ */
45     #include "utilities/ascMalloc.h" /* for ascshutdown */
46     #include "utilities/ascPanic.h" /* for Asc_Panic */
47     #include "utilities/ascEnvVar.h"
48     #include "compiler/compiler.h"
49     #include "compiler/ascCompiler.h"
50     #include "compiler/instance_enum.h"
51     #include "compiler/fractions.h"
52     #include "compiler/dimen.h"
53     #include "compiler/compiler.h" /* for symchar for units.h */
54     #include "compiler/units.h"
55     #include "solver/slv_types.h"
56     #include "solver/var.h"
57     #include "solver/rel.h"
58     #include "solver/logrel.h"
59     #include "solver/discrete.h"
60     #include "solver/mtx.h"
61     #include "solver/slv_stdcalls.h"
62     #include "interface/AscBitmaps.h"
63     #include "interface/HelpProc.h"
64     #include "interface/Commands.h"
65     #include "interface/Driver.h"
66     #include "interface/ScriptProc.h"
67     #include "interface/SolverProc.h"
68     #include "interface/UnitsProc.h"
69    
70     #ifndef lint
71     static CONST char DriverID[] = "$Id: Driver.c,v 1.48 2003/08/23 18:43:06 ballan Exp $";
72     #endif
73    
74    
75     /*
76     * The following are the environment variables ASCEND requires.
77     * If the user does not have the DIST_ENVIRONVAR set in his or her
78     * environment, a default value is set based on the directory where the
79     * ascend binary lives. The other enviornment variables will be set
80     * to default values keyed off of DIST_ENVIRONVAR. See the function
81     * CheckEnvironmentVars later in this file for the details.
82     */
83     #define DIST_ENVIRONVAR "ASCENDDIST"
84     #define ASCTK_ENVIRONVAR "ASCENDTK"
85     #define BITMAP_ENVIRONVAR "ASCENDBITMAPS"
86     #define LIBR_ENVIRONVAR "ASCENDLIBRARY"
87    
88     /*
89     * EXPORTED VARIABLES
90     */
91    
92     /**
93     * g_compiler_timing
94     *
95     * TRUE if compiler timing is to be printed.
96     * default is false, set to TRUE by passing -t on the command line
97     */
98     int g_compiler_timing = 0;
99    
100     /**
101     * g_interp
102     *
103     * Interpreter for this application. We need to make it global
104     * so that our signal/floating-porint traps can access it.
105     */
106     Tcl_Interp *g_interp;
107    
108     /*
109     * zz_debug
110     *
111     * Comes from the yacc file if yacc was built with debugging information
112     */
113     #ifdef ZZ_DEBUG
114     extern int zz_debug;
115     #endif
116    
117    
118     /*
119     * Declarations for procedures defined outside of this file.
120     */
121     extern int Tktable_Init(Tcl_Interp*);
122    
123     /*
124     * Forward declarations for procedures defined later in this file.
125     */
126     static int AscDriver(int, CONST84 char * argv[]);
127     static void AscTrap(int);
128     static int AscCheckEnvironVars(Tcl_Interp*);
129     static void AscPrintHelpExit(CONST char *);
130     static int AscProcessCommandLine(Tcl_Interp*, int, CONST84 char **);
131     static void Prompt(Tcl_Interp*, int);
132     static int AscSetStartupFile(Tcl_Interp*);
133     static void StdinProc(ClientData, int);
134     #ifdef DEBUG_MALLOC
135     static void InitDebugMalloc(void);
136     #endif /* DEBUG_MALLOC */
137     #ifdef __WIN32__
138     static void setargv(int*, char ***);
139     #endif /* __WIN32__ */
140    
141    
142     /*
143     * LOCALLY GLOBAL VARIABLES
144     */
145    
146     /*
147     * g_interface_simplify_relations
148     *
149     * TRUE for compiler optimizations
150     * default is TRUE, set to FALSE by passing +s on the command line
151     */
152     static int g_interface_simplify_relations = TRUE;
153    
154     /*
155     * g_interfacever
156     *
157     * TRUE if windows to be built; default is TRUE, false is not supported
158     */
159     static int g_interfacever = 1;
160    
161     /*
162     * g_command
163     *
164     * Used to assemble lines of terminal input into Tcl commands.
165     */
166     static Tcl_DString g_command;
167    
168     /*
169     * g_line
170     *
171     * Used to read the next line from the terminal input.
172     */
173     static Tcl_DString g_line;
174    
175     /*
176     * tty
177     *
178     * Non-zero means standard input is a terminal-like device.
179     * Zero means it's a file.
180     */
181     static int tty;
182    
183     /*
184     * initScriptTclAdjust
185     * initScriptTkAdjust
186     *
187     * These two variables hold Tcl scripts that will set the TCL_LIBRARY
188     * and TK_LIBRARY environment variables if they are not already
189     * set in the user's environment.
190     * TCL_LIBRARY is set to: dirnameofexecutable/../../Tcl/lib/tcl8.0
191     * TK_LIBRARY is set to $tcl_library/../tk8.0
192     */
193     static char initScriptTclAdjust[] =
194     "proc asc_tclInit {} {\n\
195     global env\n\
196     rename asc_tclInit {}\n\
197     set errors {}\n\
198     set dirs {}\n\
199     if [info exists env(TCL_LIBRARY)] {\n\
200     return\n\
201     } else {\n\
202     set parentDir [file dirname [info nameofexecutable]]\n\
203     set env(TCL_LIBRARY) $parentDir/../../Tcl/lib/tcl8.0\n\
204     }\n\
205     }\n\
206     asc_tclInit";
207     /* for tcl, FOO/ascend4/bin/ascend4.exe is the executable, then
208     * /-- up to FOO/ascend4/bin
209     * set parentDir [file dirname [info nameofexecutable]]\n\
210     * Then if Tcl is next to ascend4, ../../Tcl/lib/tcl8.0 should work.
211     */
212    
213     static char initScriptTkAdjust[] =
214     "proc asc_tkInit {} {\n\
215     global env\n\
216     rename asc_tkInit {}\n\
217     set errors {}\n\
218     set dirs {}\n\
219     if [info exists env(TK_LIBRARY)] {\n\
220     return\n\
221     } else {\n\
222     set parentDir [file dirname [info library]]\n\
223     set env(TK_LIBRARY) $parentDir/tk8.0\n\
224     }\n\
225     }\n\
226     asc_tkInit";
227     /*
228     * This assumes tcl_library has been found and that tcl8.0 and tk8.0
229     * are installed in the same lib directory -- the default tcl/tk install.
230     */
231    
232     /*
233     * build_name
234     *
235     * who built this binary and when
236     */
237     #ifndef TIMESTAMP
238     static char build_name[]="by anonymous";
239     #else
240     static char build_name[]=TIMESTAMP;
241     #endif /* TIMESTAMP */
242    
243    
244    
245     /*
246     * main or WinMain
247     *
248     * The main entry point for a Unix or Windows application.
249     *
250     * Each just calls AscDriver().
251     * These are based on functions from the Tk 8.0 distribution.
252     * See unix/tkAppInit.c and win/winMain.c in their sources.
253     */
254     #ifndef __WIN32__
255    
256     int main(int argc, CONST84 char *argv[])
257     {
258     AscDriver(argc, argv);
259     return 0;
260     }
261    
262     #else /* __WIN32__ */
263    
264     int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
265     LPSTR lpszCmdLine, int nCmdShow)
266     {
267     int argc;
268     char **argv;
269     char *p;
270     char buffer[MAX_PATH];
271    
272     /*
273     * Set up the default locale to be standard "C" locale so parsing
274     * is performed correctly.
275     */
276     setlocale(LC_ALL, "C");
277    
278     /*
279     * Increase the application queue size from default value of 8.
280     * At the default value, cross application SendMessage of WM_KILLFOCUS
281     * will fail because the handler will not be able to do a PostMessage!
282     * This is only needed for Windows 3.x, since NT dynamically expands
283     * the queue.
284     */
285     SetMessageQueue(64);
286    
287     /*
288     * Create the console channels and install them as the standard
289     * channels. All I/O will be discarded until TkConsoleInit is
290     * called to attach the console to a text widget.
291     */
292    
293     /*
294     * Windows expects us to parse our arguments ourselves.
295     */
296     setargv(&argc, &argv);
297    
298     /*
299     * Replace argv[0] with full pathname of executable, and forward
300     * slashes substituted for backslashes.
301     */
302     GetModuleFileName(NULL, buffer, sizeof(buffer));
303     argv[0] = buffer;
304     for (p = buffer; *p != '\0'; p++) {
305     if (*p == '\\') {
306     *p = '/';
307     }
308     }
309    
310     AscDriver(argc, argv);
311     return 1;
312     }
313     #endif /* __WIN32__ */
314    
315    
316     /*
317     * int AscDriver( argc, argv )
318     * int argc;
319     * char *argv;
320     *
321     * A common entry point for Windows and Unix. The corresponding
322     * WinMain() and main() functions just call this function.
323     *
324     * This function creates a Tcl interpreter, initializes Tcl and Tk,
325     * initializes the Ascend data structures, sets up the user's
326     * environment, sources ASCEND's startup script, and calls Tk_MainLoop
327     * so the user can interact with ASCEND. Cleans up and exits the
328     * program when Tk_MainLoop returns.
329     *
330     * This function is based on the functions Tk_Main and Tcl_AppInit
331     * from the Tk8.0 distribution. See the files tkMain.c and tkAppInit.c
332     * in the Tk sources.
333     *
334     */
335     static int AscDriver(int argc, CONST84 char *argv[])
336     {
337     Tcl_Interp *interp; /* local version of global g_interp */
338     Tcl_Channel inChannel;
339     Tcl_Channel outChannel;
340    
341     /*
342     * Create the Tk Console
343     *
344     * Create the console channels and install them as the standard
345     * channels. All I/O will be discarded until TkConsoleInit() is
346     * called to attach the console to a text widget.
347     */
348     #ifdef ASC_USE_TK_CONSOLE
349     TkConsoleCreate();
350     #endif /* ASC_USE_TK_CONSOLE */
351    
352     /*
353     * Find the name of the current executable---available in the
354     * Tcl command `info nameofexecutable'
355     */
356     Tcl_FindExecutable(argv[0]);
357    
358     /*
359     * Create the interpreter
360     */
361     g_interp = Tcl_CreateInterp();
362     interp = g_interp;
363     if( interp == NULL ) {
364     Asc_Panic(2, "Asc_Driver",
365     "Call to Tcl_CreateInterp returned NULL interpreter");
366     }
367    
368     /*
369     * Check the arguments on the command line
370     */
371     AscProcessCommandLine(interp, argc, argv);
372    
373     /*
374     * Set the "tcl_interactive" variable.
375     *
376     * ASCEND sets tty to `1', since we assume ASCEND is always interactive.
377     */
378     tty = 1;
379     Tcl_SetVar(interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
380    
381     /*
382     * Initialize Tcl and Tk
383     */
384     (void)Tcl_Eval(interp,initScriptTclAdjust);
385     if (Tcl_Init(interp) == TCL_ERROR) {
386     Asc_Panic(2, "Asc_Driver", "Tcl initialization failed:\n%s",
387     Tcl_GetStringResult(interp));
388     }
389     (void)Tcl_Eval(interp,initScriptTkAdjust);
390     if (Tk_Init(interp) == TCL_ERROR) {
391     Asc_Panic(2, "Asc_Driver", "Tk initialization failed:\n%s",
392     Tcl_GetStringResult(interp));
393     }
394     Tcl_StaticPackage( interp, "Tk", Tk_Init, Tk_SafeInit );
395    
396     /*
397     * Initialize the console and the ASCEND printf() substitutes.
398     * All output before this point is lost.
399     */
400     #ifdef ASC_USE_TK_CONSOLE
401     if (TkConsoleInit(interp) == TCL_ERROR) {
402     Asc_Panic(2, "Asc_Driver",
403     "Call to TkConsoleInit failed:\n%s",
404     Tcl_GetStringResult(interp));
405     }
406     #endif /* ASC_USE_TK_CONSOLE */
407     #ifdef USE_ASC_PRINTF
408     Asc_PrintInit();
409     #endif /* USE_ASC_PRINTF */
410    
411     /*
412     * Now that our console and printing functions are properly
413     * initialized, print our startup banner.
414     */
415     PRINTF("ASCEND VERSION IV\n");
416     PRINTF("Compiler Implemention Version: 2.0\n");
417     PRINTF("Written by Tom Epperly,Kirk Abbott, and Ben Allan\n");
418     PRINTF(" Built: %s %s %s\n",__DATE__,__TIME__,build_name);
419     PRINTF("Copyright(C) 1990, 1993, 1994 Thomas Guthrie Epperly\n");
420     PRINTF("Copyright(C) 1993-1996 Kirk Andre Abbott, Ben Allan\n");
421     PRINTF("Copyright(C) 1997 Carnegie Mellon University\n");
422    
423     /*
424     * Call the init procedures for included packages.
425     */
426     #ifdef STATIC_TKTABLE
427     if( Tktable_Init(interp) == TCL_ERROR ) {
428     Asc_Panic(2, "Asc_Driver",
429     "Call to Tktable_Init failed:\n%s",
430     Tcl_GetStringResult(interp));
431     }
432     #endif /* STATIC_TKTABLE */
433    
434     /*
435     * Initialize ASCEND C Structures
436     * Create ASCEND Tcl Commands
437     */
438     clock();
439     /* the next line should NOT be Asc_SignalHandlerPush */
440     (void)signal(SIGINT, AscTrap);
441     #ifdef DEBUG_MALLOC
442     InitDebugMalloc();
443     ascstatus("Memory status after calling InitDebugMalloc()");
444     #endif /* DEBUG_MALLOC */
445     if ( Asc_CompilerInit(g_interface_simplify_relations) != 0 ) {
446     Asc_Panic(2, "Asc_CompilerInit",
447     "Insufficient memory to initialize compiler.");
448     }
449     SlvRegisterStandardClients();
450     if( Asc_HelpInit() == TCL_ERROR ) {
451     Asc_Panic(2, "Asc_HelpInit",
452     "Insufficient memory to initialize help system.");
453     }
454     Asc_CreateCommands(interp);
455     Asc_RegisterBitmaps(interp);
456    
457     /*
458     * Set the environment, and set find the
459     * location of ASCEND's startup file.
460     */
461     AscCheckEnvironVars(interp);
462     if( AscSetStartupFile(interp) != TCL_OK ) {
463     Asc_Panic(2, "Asc_Driver",
464     "Cannot find ~/.ascendrc nor the default AscendRC\n%s",
465     Tcl_GetStringResult(interp));
466     }
467    
468     /*
469     * Evaluate the ~/.ascendrc or $ASCENDTK/AscendRC file
470     */
471     Tcl_SourceRCFile(interp);
472    
473     /*
474     * Establish a channel handlers for stdin and stdout
475     */
476     inChannel = Tcl_GetStdChannel(TCL_STDIN);
477     if (inChannel) {
478     Tcl_CreateChannelHandler(inChannel, TCL_READABLE, StdinProc,
479     (ClientData) inChannel);
480     }
481     if (tty) {
482     Prompt(interp, 0);
483     }
484     outChannel = Tcl_GetStdChannel(TCL_STDOUT);
485     if (outChannel) {
486     Tcl_Flush(outChannel);
487     }
488    
489     /*
490     * Initialize the Dynamic Strings used in StdinProc()
491     */
492     Tcl_DStringInit(&g_command);
493     Tcl_DStringInit(&g_line);
494     Tcl_ResetResult(interp);
495    
496     /*
497     * Loop infinitely, waiting for commands to execute. When there
498     * are no windows left, Tk_MainLoop returns and we exit.
499     */
500     #ifdef DEBUG_MALLOC
501     ascstatus("Memory status before calling Tk_MainLoop()");
502     #endif /* DEBUG_MALLOC */
503     if (Asc_ScriptConfigureInterrupt(1,interp)!=0) {
504     Asc_Panic(2, "Asc_ScriptConfigureInterrupt",
505     "Unable to configure script interrupt.");
506     }
507     Tk_MainLoop();
508     Asc_ScriptConfigureInterrupt(0,interp);
509     #ifdef DEBUG_MALLOC
510     ascstatus("Memory status after Tk_MainLoop() exits");
511     #endif /* DEBUG_MALLOC */
512    
513     /*
514     * Do ASCEND Cleanup
515     */
516     Asc_HelpDestroy();
517     Asc_UnitValue(NULL);
518     Asc_SolvMemoryCleanup();
519     Asc_CompilerDestroy();
520     Asc_DestroyEnvironment();
521     #ifdef DEBUG_MALLOC
522     ascshutdown("Memory status just before exiting");
523     #endif /* DEBUG_MALLOC */
524    
525     /*
526     * Destroy the interpreter and exit
527     */
528     Tcl_DeleteInterp(interp);
529     Tcl_Exit(0);
530     return 0;
531     }
532    
533    
534     /*
535     *-----------------------------------------------------------------
536     * int AscCheckEnvironVars(interp)
537     * Tcl_Interp *interp;
538     *
539     * This function checks the following environment variables and sets them
540     * to the default value if they are not set. This function will set
541     * DIST_ENVIRONVAR to the parent of the directory where the ASCEND binary
542     * lives if it is not set, e.g., if the ascend binary is
543     * /foo/bar/ascend4
544     * DIST_ENVIRONVAR is set to "/foo".
545     *
546     * We check to see if ASCTK_ENVIRONVAR points to the proper place by
547     * looking for the ASCEND startup script "AscendRC". If we find it, set
548     * the Tcl variable tcl_rcFileName to its location, otherwise, call
549     * Asc_Panic() to exit.
550     *
551     * Returns a standard Tcl return code.
552     *
553     * CPP_MACRO ENVIRONMENT VAR DEFAULT VALUE
554     * ================= =============== =============
555     * DIST_ENVIRONVAR ASCENDDIST parent of binary's directory
556 aw0a 21 * AWW20041208: ASCTK_ENVIRONVAR ASCENDTK ASCENDDIST/TK
557     * ASCTK_ENVIRONVAR ASCENDTK ASCENDDIST/../../tcltk98/TK
558 aw0a 1 * BITMAP_ENVIRONVAR ASCENDBITMAPS ASCENDTK/bitmaps
559     * LIBR_ENVIRONVAR ASCENDLIBRARY
560     * .:ASCENDDIST/models/libraries:ASCENDDIST/models/examples
561     *
562     */
563     static int AscCheckEnvironVars(Tcl_Interp *interp)
564     {
565     char *tmpenv; /* holds values returned by Asc_GetEnv() */
566     Tcl_DString ascenddist; /* holds the value of DIST_ENVIRONVAR */
567     Tcl_DString buffer2; /* used to incrementally build environment
568     * variable values
569     */
570     Tcl_DString buffer1; /* holds the environment variable value in the
571     * native format: result of passing buffer2
572     * into Tcl_TranslateFileName()
573     */
574     Tcl_Channel c; /* used to test if file exists */
575    
576     /* initialize */
577     Tcl_DStringInit(&ascenddist);
578     Tcl_DStringInit(&buffer1);
579     Tcl_DStringInit(&buffer2);
580    
581     /*
582     * Get the value of the ASCENDDIST environment variable;
583     * if not set, set it to the parent of the directory containing
584     * the ascend binary. For example, if the ascend binary is
585     * /foo/bar/bin/ascend4, set ASCENDDIST to /foo/bar
586     * If Tcl doesn't know where we are---the Tcl command
587     * `info nameofexecutable' returns ""---then ASCENDDIST is set
588     * to "."
589     */
590     if( Asc_ImportPathList(DIST_ENVIRONVAR) == 0 ) {
591     if( (tmpenv = Asc_GetEnv(DIST_ENVIRONVAR)) == NULL ) {
592     /* shouldn't be NULL since we just imported it successfully */
593     Asc_Panic(2, "CheckEnvironmentVars",
594     "Asc_GetEnv(%s) returned NULL value.", DIST_ENVIRONVAR);
595     }
596     Tcl_DStringAppend(&ascenddist, tmpenv, -1);
597     ascfree(tmpenv);
598     } else {
599     char cmd[] =
600     "file nativename [file dirname [file dirname [info nameofexecutable]]]";
601     if( Tcl_Eval(interp, cmd) == TCL_OK ) {
602     Tcl_DStringGetResult(interp, &ascenddist);
603     if(Asc_SetPathList(DIST_ENVIRONVAR,Tcl_DStringValue(&ascenddist)) != 0) {
604     Asc_Panic(2, "AscCheckEnvironVars",
605     "Asc_SetPathList() returned Nonzero: "
606     "Not enough memory to extend the environment");
607     }
608     }
609     }
610     /* Make sure the Tcl side can also see this variable */
611     Tcl_SetVar2(interp, "env", DIST_ENVIRONVAR,
612     Tcl_DStringValue(&ascenddist), TCL_GLOBAL_ONLY);
613    
614     /*
615     * If the user's environment does not have ASCENDLIBRARY set, then set
616     * it to a reasonable default.
617     */
618     if( Asc_ImportPathList(LIBR_ENVIRONVAR) == 0 ) {
619     if( (tmpenv = Asc_GetEnv(LIBR_ENVIRONVAR)) == NULL ) {
620     /* shouldn't be NULL since we just imported it successfully */
621     Asc_Panic(2, "CheckEnvironmentVars",
622     "Asc_GetEnv(%s) returned NULL value.", LIBR_ENVIRONVAR);
623     }
624     /* Make sure the Tcl side can also see this variable */
625     Tcl_SetVar2(interp, "env", LIBR_ENVIRONVAR, tmpenv, TCL_GLOBAL_ONLY);
626     ascfree(tmpenv);
627     } else {
628     /* Add ``.'' to the ASCENDLIBRARY envar */
629     if( Asc_SetPathList(LIBR_ENVIRONVAR, ".") != 0 ) {
630     Asc_Panic(2, "AscCheckEnvironVars",
631     "Asc_SetPathList() returned Nonzero: "
632     "Not enough memory to extend the environment");
633     }
634    
635     /* Add ``$ASCENDDIST/models'' to the ASCENDLIBRARY envar */
636     Tcl_DStringAppend(&buffer2, Tcl_DStringValue(&ascenddist), -1);
637     Tcl_DStringAppend(&buffer2, "/models", -1);
638     if( NULL != (Tcl_TranslateFileName(interp, Tcl_DStringValue(&buffer2),
639     &buffer1))) {
640     if(Asc_AppendPath(LIBR_ENVIRONVAR, Tcl_DStringValue(&buffer1)) != 0) {
641     Asc_Panic(2, "AscCheckEnvironVars",
642     "Asc_AppendPath() returned Nonzero: "
643     "Not enough memory to extend the environment");
644     }
645     Tcl_DStringFree(&buffer1);
646     }
647     Tcl_DStringFree(&buffer2);
648    
649     /* Add ``$ASCENDDIST/models/examples'' to the ASCENDLIBRARY envar */
650     Tcl_DStringAppend(&buffer2, Tcl_DStringValue(&ascenddist), -1);
651     Tcl_DStringAppend(&buffer2, "/models/examples", -1);
652     if( NULL != (Tcl_TranslateFileName(interp, Tcl_DStringValue(&buffer2),
653     &buffer1))) {
654     if(Asc_AppendPath(LIBR_ENVIRONVAR, Tcl_DStringValue(&buffer1)) != 0) {
655     Asc_Panic(2, "AscCheckEnvironVars",
656     "Asc_AppendPath() returned Nonzero: "
657     "Not enough memory to extend the environment");
658     }
659     Tcl_DStringFree(&buffer1);
660     }
661     Tcl_DStringFree(&buffer2);
662    
663     /* Add ``$ASCENDDIST/models/libraries'' to the ASCENDLIBRARY envar */
664     Tcl_DStringAppend(&buffer2, Tcl_DStringValue(&ascenddist), -1);
665     Tcl_DStringAppend(&buffer2, "/models/libraries", -1);
666     if( NULL != (Tcl_TranslateFileName(interp, Tcl_DStringValue(&buffer2),
667     &buffer1))) {
668     if(Asc_AppendPath(LIBR_ENVIRONVAR, Tcl_DStringValue(&buffer1)) != 0) {
669     Asc_Panic(2, "AscCheckEnvironVars",
670     "Asc_AppendPath() returned Nonzero: "
671     "Not enough memory to extend the environment");
672     }
673     Tcl_DStringFree(&buffer1);
674     }
675     Tcl_DStringFree(&buffer2);
676    
677     /* Get the full value of the environment variable and set
678     * $env(ASCENDLIBRARY) in the Tcl code
679     */
680     if( (tmpenv = Asc_GetEnv(LIBR_ENVIRONVAR)) == NULL ) {
681     /* shouldn't be NULL since we just set it. memory error! */
682     Asc_Panic(2, "CheckEnvironmentVars",
683     "Asc_GetEnv(%s) returned NULL value.", LIBR_ENVIRONVAR);
684     }
685     /* Make sure the Tcl side can also see this variable */
686     Tcl_SetVar2(interp, "env", LIBR_ENVIRONVAR, tmpenv, TCL_GLOBAL_ONLY);
687     ascfree(tmpenv);
688     }
689    
690     /*
691     * If the user's environment does not have ASCENDTK set, then set it
692     * by appending `TK' to ASCENDDIST. Later in this function, we check
693     * to make sure it is a valid directory by checking for the existence
694     * of `AscendRC' in that directory.
695     */
696     if( Asc_ImportPathList(ASCTK_ENVIRONVAR) == 0 ) {
697     if( (tmpenv = Asc_GetEnv(ASCTK_ENVIRONVAR)) == NULL ) {
698     /* shouldn't be NULL since we just imported it successfully */
699     Asc_Panic(2, "CheckEnvironmentVars",
700     "Asc_GetEnv(%s) returned NULL value.", ASCTK_ENVIRONVAR);
701     }
702     /* store ASCENDTK in ``buffer1'' so we can check for ASCENDTK/AscendRC
703     * below
704     */
705     Tcl_DStringAppend(&buffer1, tmpenv, -1);
706     ascfree(tmpenv);
707     } else {
708     Tcl_DStringAppend(&buffer2, Tcl_DStringValue(&ascenddist), -1);
709 aw0a 21 /* AWW20041208: Tcl_DStringAppend(&buffer2, "/TK", -1);
710     */
711     Tcl_DStringAppend(&buffer2, "/../../tcltk98/TK", -1);
712 aw0a 1 if(NULL != (Tcl_TranslateFileName(interp, Tcl_DStringValue(&buffer2),
713     &buffer1))) {
714     if( Asc_SetPathList(ASCTK_ENVIRONVAR, Tcl_DStringValue(&buffer1)) != 0) {
715     Asc_Panic(2, "Asc_EnvironmentInit",
716     "Not enough memory to initialize the environment");
717     }
718     }
719     Tcl_DStringFree(&buffer2);
720     }
721     /* Make sure the Tcl side can also see this variable */
722     Tcl_SetVar2(interp, "env", ASCTK_ENVIRONVAR,
723     Tcl_DStringValue(&buffer1), TCL_GLOBAL_ONLY);
724    
725     /*
726     * Check to see if ASCENDTK looks reasonable by checking
727     * for ASCENDTK/AscendRC We use the Tcl channel
728     * mechanism to see if file exists.
729     */
730     Tcl_DStringAppend(&buffer1, "/AscendRC", -1 );
731     c = Tcl_OpenFileChannel( NULL, Tcl_DStringValue(&buffer1), "r", 0 );
732     if( c != (Tcl_Channel)NULL ) {
733     /*
734     * file exists. close the channel and set tcl_rcfilename to
735     * this location
736     */
737     Tcl_Close( NULL, c );
738     Tcl_SetVar(interp, "tcl_rcFileName", Tcl_DStringValue(&buffer1),
739     TCL_GLOBAL_ONLY);
740     } else {
741     Asc_Panic(2, "AscCheckEnvironVars",
742 aw0a 21 "ERROR: Cannot find the file \"%s\" in the subdirectory \"..\/..\/tcltk98\/TK\"\n"
743 aw0a 1 "under the directory \"%s\"\n"
744     "Please check the value of the environment variables %s and\n"
745     "and %s and start ASCEND again.\n",
746     "AscendRC", Tcl_DStringValue(&ascenddist), DIST_ENVIRONVAR,
747     ASCTK_ENVIRONVAR);
748     }
749     Tcl_DStringFree(&buffer1);
750    
751     /*
752     * If the user's environment does not have ASCENDBITMAPS set, then set
753     * it by appending `bitmaps' to ASCENDTK.
754     */
755     if( Asc_ImportPathList(BITMAP_ENVIRONVAR) == 0 ) {
756     if( (tmpenv = Asc_GetEnv(BITMAP_ENVIRONVAR)) == NULL ) {
757     /* shouldn't be NULL since we just imported it successfully */
758     Asc_Panic(2, "CheckEnvironmentVars",
759     "Asc_GetEnv(%s) returned NULL value.", BITMAP_ENVIRONVAR);
760     }
761     /* Make sure the Tcl side can also see this variable */
762     Tcl_SetVar2(interp, "env", BITMAP_ENVIRONVAR, tmpenv, TCL_GLOBAL_ONLY);
763     ascfree(tmpenv);
764     } else {
765     Tcl_DStringAppend(&buffer2, Tcl_DStringValue(&ascenddist), -1);
766     Tcl_DStringAppend(&buffer2, "/TK/bitmaps", -1);
767     if(NULL != (Tcl_TranslateFileName(interp, Tcl_DStringValue(&buffer2),
768     &buffer1))) {
769     if(Asc_SetPathList(BITMAP_ENVIRONVAR, Tcl_DStringValue(&buffer1)) != 0) {
770     Asc_Panic(2, "Asc_EnvironmentInit",
771     "Not enough memory to initialize the environment");
772     }
773     }
774     Tcl_DStringFree(&buffer2);
775     /* Make sure the Tcl side can also see this variable */
776     Tcl_SetVar2(interp, "env", BITMAP_ENVIRONVAR,
777     Tcl_DStringValue(&buffer1), TCL_GLOBAL_ONLY);
778     Tcl_DStringFree(&buffer1);
779     }
780    
781     /* Cleanup */
782     Tcl_DStringFree(&ascenddist);
783    
784     return TCL_OK;
785     }
786    
787    
788     /*
789     * int AscSetStartupFile(interp)
790     * Tcl_Interp *interp;
791     *
792     * Look for ~/.ascendrc; if found, set the Tcl variable tcl_rcFileName
793     * to this file's location. This overrides the value set in
794     * AscCheckEnvironVars().
795     * If ~/_ascendrc is available it only gets used if ~/.ascendrc is not.
796     * Returns a standard Tcl return code.
797     */
798     static int AscSetStartupFile(Tcl_Interp *interp)
799     {
800     char *fullname; /* try to find this if first fails */
801     Tcl_DString buffer;
802     Tcl_Channel c; /* used to check for file existance */
803    
804     Tcl_ResetResult(interp);
805    
806     fullname = Tcl_TranslateFileName( interp, "~/.ascendrc", &buffer );
807     if( fullname != NULL ) {
808     /*
809     * Use the Tcl file channel routines to determine if ~/.ascendrc
810     * exists. We cannot use access() since Windows doesn't use it.
811     */
812     c = Tcl_OpenFileChannel( NULL, fullname, "r", 0 );
813     if( c != (Tcl_Channel)NULL ) {
814     /* file exists. close the channel and set tcl_rcFileName. */
815     Tcl_Close( NULL, c );
816     Tcl_SetVar(interp, "tcl_rcFileName", fullname, TCL_GLOBAL_ONLY);
817     Tcl_DStringFree(&buffer);
818     return TCL_OK;
819     }
820     Tcl_DStringFree(&buffer);
821     }
822     fullname = Tcl_TranslateFileName( interp, "~/_ascendrc", &buffer );
823     if( fullname != NULL ) {
824     /*
825     * Use the Tcl file channel routines to determine if ~/_ascendrc
826     * exists. We cannot use access() since Windows doesn't use it.
827     */
828     c = Tcl_OpenFileChannel( NULL, fullname, "r", 0 );
829     if( c != (Tcl_Channel)NULL ) {
830     /* file exists. close the channel and set tcl_rcFileName */
831     Tcl_Close( NULL, c );
832     Tcl_SetVar(interp, "tcl_rcFileName", fullname, TCL_GLOBAL_ONLY);
833     Tcl_DStringFree(&buffer);
834     return TCL_OK;
835     }
836     Tcl_DStringFree(&buffer);
837     }
838     return TCL_OK; /* probably should be TCL_ERROR */
839     }
840    
841    
842    
843     /*
844     * file = AscProcessCommandLine(argc, argv)
845     * char *file;
846     * int argc;
847     * char *argv[];
848     *
849     * Process the options given on the command line `argv' where `argc' is
850     * the length of argv.
851     *
852     * Strip out ASCEND specific flags and then pass the rest to Tcl so it
853     * can set what it needs.
854     *
855     * This function may call exit() if the user requests help.
856     */
857     static int AscProcessCommandLine(Tcl_Interp *interp, int argc, CONST84 char **argv)
858     {
859     int i;
860     int flag; /* set to 1 for `+arg', -1 for `-arg' */
861     size_t length; /* length of an argv */
862     char *args;
863     char buf[MAXIMUM_NUMERIC_LENGTH]; /* space for integer->string conversion */
864     int new_argc = 0; /* the argc we will pass to Tcl */
865     #ifdef ZZ_DEBUG
866     zz_debug = 0; /* nonzero to print parser debugging info*/
867     #endif
868    
869     for( i = 1; i < argc; i++ ) {
870     if( (length = strlen(argv[i])) == 0 ) {
871     /* ignore 0-length arguments */
872     continue;
873     }
874    
875     if(( length >= 2 ) && ( strncmp(argv[i],"-h",2) == 0 )) {
876     AscPrintHelpExit(argv[0]);
877     }
878     if(( length >= 2 ) && ( strncmp(argv[i],"-H",2) == 0 )) {
879     AscPrintHelpExit(argv[0]);
880     }
881     if(( length >= 4 ) && ( strncmp(argv[i],"help",4) == 0 )) {
882     AscPrintHelpExit(argv[0]);
883     }
884    
885     if( argv[i][0] == '-' ) {
886     flag = -1;
887     } else if( argv[i][0] == '+' ) {
888     flag = 1;
889     } else {
890     flag = 0;
891     }
892    
893     if(( length == 2 ) && ( flag != 0 )) {
894     switch( argv[i][1] ) {
895     case 'd':
896     /* '-d' turns on scanner debugging (if ascend was built with it)
897     * '+d' turns off scanner debugging [default]
898     */
899     if( flag == -1 ) {
900     #ifdef ZZ_DEBUG
901     zz_debug = 1;
902     } else {
903     zz_debug = 0;
904     #else
905     FPRINTF(ASCERR, "Sorry, %s wasn't compiled with %s defined.\n",
906     argv[0], "ZZ_DEBUG");
907     #endif /* ZZ_DEBUG */
908     }
909     break;
910     case 's':
911     /* '-s' turns on compiler optimizations [default]
912     * '+s' turns off compiler optimizations
913     */
914     if( flag == -1 ) {
915     g_interface_simplify_relations = 1;
916     } else {
917     g_interface_simplify_relations = 0;
918     }
919     break;
920     case 't':
921     /* '-t' turns on timing of compiler optimizations
922     * '+t' turns off timing of compiler optimizations [default]
923     */
924     if( flag == 0 ) {
925     g_compiler_timing = 1;
926     } else {
927     g_compiler_timing = 0;
928     }
929     break;
930     case 'c':
931     case 'g':
932     fprintf(ASCERR, "WARNING! Obsolete ASCEND option \"%s\"\n", argv[i]);
933     break;
934     default:
935     /* unknown ASCEND option, pass it on to Tcl
936     */
937     argv[++new_argc] = argv[i];
938     break;
939     }
940     } else {
941     /* unknown ASCEND option, pass it on to Tcl
942     */
943     argv[++new_argc] = argv[i];
944     }
945     }
946    
947     /*
948     * Make command-line arguments available in the Tcl variables "argc"
949     * and "argv".
950     */
951     args = Tcl_Merge(new_argc, (argv+1));
952     Tcl_SetVar(interp, "argv", args, TCL_GLOBAL_ONLY);
953     ckfree(args);
954     sprintf(buf, "%d", new_argc);
955     Tcl_SetVar(interp, "argc", buf, TCL_GLOBAL_ONLY);
956     Tcl_SetVar(interp, "argv0", argv[0], TCL_GLOBAL_ONLY);
957    
958     return TCL_OK;
959     }
960    
961    
962     /*
963     * AscPrintHelpExit(invoke_name)
964     * CONST char *invoke_name;
965     *
966     * Print a help message and exit. Use invoke_name as the name of
967     * the binary
968     */
969     static
970     void AscPrintHelpExit(CONST char *invoke_name)
971     {
972     PRINTF("usage: %s [options]\n"
973     "\n"
974     "where options include [default value]:\n"
975     " -h print this message\n"
976     " -/+d turn on/off yacc debugging [off]\n"
977     " -/+s turn on/off compiler optimizations [on]\n"
978     " -/+t turn on/off timing of compiler operations [off]\n",
979     invoke_name);
980     Tcl_Exit(0); /* Show this help message and leave */
981     }
982    
983    
984     /*
985     * AscTrap(sig)
986     * int sig;
987     *
988     * Function to call when we receive an interrupt.
989     */
990     static
991     void AscTrap(int sig)
992     {
993     putchar('\n');
994     Asc_Panic(sig, "AscTrap", "Caught Signal: %d", sig);
995     }
996    
997    
998     /*
999     * See this file's header for documentation.
1000     */
1001     int Asc_LoadWin(ClientData cdata, Tcl_Interp *interp,
1002     int argc, CONST84 char *argv[])
1003     {
1004     (void)cdata; /* stop gcc whine about unused parameter */
1005     (void)argv; /* stop gcc whine about unused parameter */
1006    
1007     if ( argc != 1 ) {
1008     FPRINTF(stderr,"call is: ascloadwin <no args> \n");
1009     return TCL_ERROR;
1010     }
1011     if (g_interfacever) {
1012     Tcl_SetResult(interp, "1", TCL_STATIC);
1013     } else {
1014     Tcl_SetResult(interp, "0", TCL_STATIC);
1015     }
1016     return TCL_OK;
1017     }
1018    
1019    
1020     /*
1021     *----------------------------------------------------------------------
1022     *----------------------------------------------------------------------
1023     * The following StdinProc() and Prompt() are from tkMain.c in
1024     * the Tk4.1 distribution (and did not change in Tk8.0).
1025     *----------------------------------------------------------------------
1026     *----------------------------------------------------------------------
1027     */
1028     /*
1029     *----------------------------------------------------------------------
1030     *
1031     * StdinProc --
1032     *
1033     * This procedure is invoked by the event dispatcher whenever
1034     * standard input becomes readable. It grabs the next line of
1035     * input characters, adds them to a command being assembled, and
1036     * executes the command if it's complete.
1037     *
1038     * Results:
1039     * None.
1040     *
1041     * Side effects:
1042     * Could be almost arbitrary, depending on the command that's
1043     * typed.
1044     *
1045     *----------------------------------------------------------------------
1046     */
1047    
1048     /* ARGSUSED */
1049     static void
1050     StdinProc(clientData, mask)
1051     ClientData clientData; /* Not used. */
1052     int mask; /* Not used. */
1053     {
1054     static int gotPartial = 0;
1055     char *cmd;
1056     int code, count;
1057     Tcl_Channel chan = (Tcl_Channel) clientData;
1058    
1059     Tcl_Interp *interp = g_interp; /* use a local copy of the
1060     * global tcl interpreter
1061     */
1062    
1063     (void)clientData; /* stop gcc whine about unused parameter */
1064     (void)mask; /* stop gcc whine about unused parameter */
1065    
1066     count = Tcl_Gets(chan, &g_line);
1067    
1068     if (count < 0) {
1069     if (!gotPartial) {
1070     if (tty) {
1071     return;
1072     } else {
1073     Tcl_DeleteChannelHandler(chan, StdinProc, (ClientData) chan);
1074     }
1075     return;
1076     } else {
1077     count = 0;
1078     }
1079     }
1080    
1081     (void) Tcl_DStringAppend(&g_command, Tcl_DStringValue(&g_line), -1);
1082     cmd = Tcl_DStringAppend(&g_command, "\n", -1);
1083     Tcl_DStringFree(&g_line);
1084    
1085     if (!Tcl_CommandComplete(cmd)) {
1086     gotPartial = 1;
1087     goto prompt;
1088     }
1089     gotPartial = 0;
1090    
1091     /*
1092     * Disable the stdin channel handler while evaluating the command;
1093     * otherwise if the command re-enters the event loop we might
1094     * process commands from stdin before the current command is
1095     * finished. Among other things, this will trash the text of the
1096     * command being evaluated.
1097     */
1098    
1099     Tcl_CreateChannelHandler(chan, 0, StdinProc, (ClientData) chan);
1100     code = Tcl_RecordAndEval(interp, cmd, TCL_EVAL_GLOBAL);
1101     Tcl_CreateChannelHandler(chan, TCL_READABLE, StdinProc,
1102     (ClientData) chan);
1103     Tcl_DStringFree(&g_command);
1104     if (*interp->result != 0) {
1105     if ((code != TCL_OK) || (tty)) {
1106     /*
1107     * The statement below used to call "printf", but that resulted
1108     * in core dumps under Solaris 2.3 if the result was very long.
1109     *
1110     * NOTE: This probably will not work under Windows either.
1111     */
1112    
1113     puts(interp->result);
1114     }
1115     }
1116    
1117     /*
1118     * Output a prompt.
1119     */
1120    
1121     prompt:
1122     if (tty) {
1123     Prompt(interp, gotPartial);
1124     }
1125     Tcl_ResetResult(interp);
1126     }
1127    
1128     /*
1129     *----------------------------------------------------------------------
1130     *
1131     * Prompt --
1132     *
1133     * Issue a prompt on standard output, or invoke a script
1134     * to issue the prompt.
1135     *
1136     * Results:
1137     * None.
1138     *
1139     * Side effects:
1140     * A prompt gets output, and a Tcl script may be evaluated
1141     * in interp.
1142     *
1143     *----------------------------------------------------------------------
1144     */
1145    
1146     static void
1147     Prompt(interp, partial)
1148     Tcl_Interp *interp; /* Interpreter to use for prompting. */
1149     int partial; /* Non-zero means there already
1150     * exists a partial command, so use
1151     * the secondary prompt. */
1152     {
1153     CONST84 char *promptCmd;
1154     int code;
1155     Tcl_Channel outChannel, errChannel;
1156     CONST84 char *subPrompt;
1157    
1158     errChannel = Tcl_GetChannel(interp, "stderr", NULL);
1159    
1160     subPrompt = (partial ? "tcl_prompt2" : "tcl_prompt1");
1161     promptCmd = Tcl_GetVar(interp, subPrompt, TCL_GLOBAL_ONLY);
1162     if (promptCmd == NULL) {
1163     defaultPrompt:
1164    
1165     /*
1166     * We must check that outChannel is a real channel - it
1167     * is possible that someone has transferred stdout out of
1168     * this interpreter with "interp transfer".
1169     */
1170    
1171     outChannel = Tcl_GetChannel(interp, "stdout", NULL);
1172     if (outChannel != (Tcl_Channel) NULL) {
1173     if (!partial) {
1174     Tcl_Write(outChannel, "AscendIV% ", 10);
1175     } else {
1176     Tcl_Write(outChannel, "more? ", 6);
1177     }
1178     }
1179     } else {
1180     code = Tcl_Eval(interp, promptCmd);
1181     if (code != TCL_OK) {
1182     Tcl_AddErrorInfo(interp,
1183     "\n (script that generates prompt)");
1184     /*
1185     * We must check that errChannel is a real channel - it
1186     * is possible that someone has transferred stderr out of
1187     * this interpreter with "interp transfer".
1188     */
1189    
1190     errChannel = Tcl_GetChannel(interp, "stderr", NULL);
1191     if (errChannel != (Tcl_Channel) NULL) {
1192     Tcl_Write(errChannel, interp->result, -1);
1193     Tcl_Write(errChannel, "\n", 1);
1194     }
1195     goto defaultPrompt;
1196     }
1197     }
1198     outChannel = Tcl_GetChannel(interp, "stdout", NULL);
1199     if (outChannel != (Tcl_Channel) NULL) {
1200     Tcl_Flush(outChannel);
1201     }
1202     }
1203    
1204     /*
1205     *----------------------------------------------------------------------
1206     * Tom Epperly's Malloc Debugger
1207     *----------------------------------------------------------------------
1208     */
1209     #ifdef DEBUG_MALLOC
1210     static void InitDebugMalloc(void)
1211     {
1212     union dbmalloptarg m;
1213     m.str = NULL;
1214     m.i = 0;
1215     dbmallopt(MALLOC_CKDATA,&m);
1216     }
1217    
1218     int Asc_DebugMallocCmd(ClientData cdata, Tcl_Interp *interp,
1219     int argc, CONST84 char *argv[])
1220     {
1221     union dbmalloptarg m;
1222    
1223     if ( argc != 2 ) {
1224     Tcl_SetResult(interp, "wrong # args : Usage __dbmalloc ?on?off?",
1225     TCL_STATIC);
1226     return TCL_ERROR;
1227     }
1228     m.str = NULL;
1229     if (strcmp(argv[1],"on")==0) {
1230     m.i = 1;
1231     } else if (strcmp(argv[1],"off")==0) {
1232     m.i = 0;
1233     } else {
1234     Tcl_SetResult(interp, "incorrect args : should be \"on\" or \"off\"",
1235     TCL_STATIC);
1236     return TCL_ERROR;
1237     }
1238     dbmallopt(MALLOC_CKDATA,&m); /* turn on str* mem* and b* checking */
1239     return TCL_OK;
1240     }
1241     #endif /* DEBUG_MALLOC */
1242    
1243     #ifdef __WIN32__
1244     /*
1245     *-------------------------------------------------------------------------
1246     *
1247     * setargv --
1248     *
1249     * Parse the Windows command line string into argc/argv. Done here
1250     * because we don't trust the builtin argument parser in crt0.
1251     * Windows applications are responsible for breaking their command
1252     * line into arguments.
1253     *
1254     * 2N backslashes + quote -> N backslashes + begin quoted string
1255     * 2N + 1 backslashes + quote -> literal
1256     * N backslashes + non-quote -> literal
1257     * quote + quote in a quoted string -> single quote
1258     * quote + quote not in quoted string -> empty string
1259     * quote -> begin quoted string
1260     *
1261     * Results:
1262     * Fills argcPtr with the number of arguments and argvPtr with the
1263     * array of arguments.
1264     *
1265     * Side effects:
1266     * Memory allocated.
1267     *
1268     * This function is from the Tk 8.0 distribution. See win/winMain.c in
1269     * their sources.
1270     *
1271     *--------------------------------------------------------------------------
1272     */
1273     static void
1274     setargv(argcPtr, argvPtr)
1275     int *argcPtr; /* Filled with number of argument strings. */
1276     char ***argvPtr; /* Filled with argument strings (malloc'd). */
1277     {
1278     char *cmdLine, *p, *arg, *argSpace;
1279     char **argv;
1280     int argc, size, inquote, copy, slashes;
1281    
1282     cmdLine = GetCommandLine();
1283    
1284     /*
1285     * Precompute an overly pessimistic guess at the number of arguments
1286     * in the command line by counting non-space spans.
1287     */
1288    
1289     size = 2;
1290     for (p = cmdLine; *p != '\0'; p++) {
1291     if (isspace(*p)) {
1292     size++;
1293     while (isspace(*p)) {
1294     p++;
1295     }
1296     if (*p == '\0') {
1297     break;
1298     }
1299     }
1300     }
1301     argSpace = (char *) ckalloc((unsigned) (size * sizeof(char *)
1302     + strlen(cmdLine) + 1));
1303     argv = (char **) argSpace;
1304     argSpace += size * sizeof(char *);
1305     size--;
1306    
1307     p = cmdLine;
1308     for (argc = 0; argc < size; argc++) {
1309     argv[argc] = arg = argSpace;
1310     while (isspace(*p)) {
1311     p++;
1312     }
1313     if (*p == '\0') {
1314     break;
1315     }
1316    
1317     inquote = 0;
1318     slashes = 0;
1319     while (1) {
1320     copy = 1;
1321     while (*p == '\\') {
1322     slashes++;
1323     p++;
1324     }
1325     if (*p == '"') {
1326     if ((slashes & 1) == 0) {
1327     copy = 0;
1328     if ((inquote) && (p[1] == '"')) {
1329     p++;
1330     copy = 1;
1331     } else {
1332     inquote = !inquote;
1333     }
1334     }
1335     slashes >>= 1;
1336     }
1337    
1338     while (slashes) {
1339     *arg = '\\';
1340     arg++;
1341     slashes--;
1342     }
1343    
1344     if ((*p == '\0') || (!inquote && isspace(*p))) {
1345     break;
1346     }
1347     if (copy != 0) {
1348     *arg = *p;
1349     arg++;
1350     }
1351     p++;
1352     }
1353     *arg = '\0';
1354     argSpace = arg + 1;
1355     }
1356     argv[argc] = NULL;
1357    
1358     *argcPtr = argc;
1359     *argvPtr = argv;
1360     }
1361    
1362     #endif /* __WIN32__ */

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22