1 |
/* |
2 |
* DriverNoGUI.c |
3 |
* by Ben Allan |
4 |
* Created: 7/2004 |
5 |
* Version: $Revision: 1.1 $ |
6 |
* Version control file: $RCSfile: DriverNoTickle.c,v $ |
7 |
* Date last modified: $Date: 2004/07/13 07:42:30 $ |
8 |
* Last modified by: $Author: ballan $ |
9 |
* |
10 |
* This file is part of the ASCEND Tcl interface |
11 |
* |
12 |
* Copyright 1997, Carnegie Mellon University |
13 |
* |
14 |
* The ASCEND Tcl 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 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 |
#define WITH_TK 0 |
31 |
#define CONST84 const |
32 |
|
33 |
#include <stdarg.h> |
34 |
#include <ctype.h> |
35 |
#include <signal.h> |
36 |
#include <time.h> |
37 |
#include <utilities/ascConfig.h> |
38 |
|
39 |
#ifndef __WIN32__ |
40 |
# include <unistd.h> |
41 |
#else |
42 |
# define WIN32_LEAN_AND_MEAN |
43 |
# include <windows.h> |
44 |
# include <locale.h> |
45 |
# undef WIN32_LEAN_AND_MEAN |
46 |
#endif /* __WIN32__ */ |
47 |
|
48 |
#include <utilities/config.h> |
49 |
#include <utilities/ascMalloc.h> /* for ascshutdown */ |
50 |
#include <utilities/ascPanic.h> /* for Asc_Panic */ |
51 |
#include <utilities/ascEnvVar.h> |
52 |
#include <compiler/compiler.h> |
53 |
#include <compiler/ascCompiler.h> |
54 |
#include <compiler/instance_enum.h> |
55 |
#include <compiler/fractions.h> |
56 |
#include <compiler/dimen.h> |
57 |
#include <compiler/compiler.h> /* for symchar for units.h */ |
58 |
#include <compiler/units.h> |
59 |
#include <solver/slv_types.h> |
60 |
#include <solver/var.h> |
61 |
#include <solver/rel.h> |
62 |
#include <solver/logrel.h> |
63 |
#include <solver/discrete.h> |
64 |
#include <solver/mtx.h> |
65 |
#include <solver/slv_stdcalls.h> |
66 |
|
67 |
#ifndef lint |
68 |
static CONST char DriverID[] = "$Id: DriverNoTickle.c,v 1.1 2004/07/13 07:42:30 ballan Exp $"; |
69 |
#endif |
70 |
|
71 |
/* |
72 |
* EXPORTED VARIABLES |
73 |
*/ |
74 |
|
75 |
/** |
76 |
* g_compiler_timing |
77 |
* |
78 |
* TRUE if compiler timing is to be printed. |
79 |
* default is false, set to TRUE by passing -t on the command line |
80 |
*/ |
81 |
int g_compiler_timing = 0; |
82 |
|
83 |
|
84 |
/* |
85 |
* zz_debug |
86 |
* |
87 |
* Comes from the yacc file if yacc was built with debugging information |
88 |
*/ |
89 |
#ifdef ZZ_DEBUG |
90 |
extern int zz_debug; |
91 |
#endif |
92 |
|
93 |
|
94 |
/* |
95 |
* Forward declarations for procedures defined later in this file. |
96 |
*/ |
97 |
static int AscDriver(int, CONST84 char * argv[]); |
98 |
static void AscTrap(int); |
99 |
static void AscPrintHelpExit(CONST char *); |
100 |
static int AscProcessCommandLine( int argc, CONST84 char **argv); |
101 |
#ifdef DEBUG_MALLOC |
102 |
static void InitDebugMalloc(void); |
103 |
#endif /* DEBUG_MALLOC */ |
104 |
#ifdef __WIN32__ |
105 |
static void setargv(int*, char ***); |
106 |
#endif /* __WIN32__ */ |
107 |
|
108 |
|
109 |
/* |
110 |
* LOCALLY GLOBAL VARIABLES |
111 |
*/ |
112 |
|
113 |
/* |
114 |
* g_interface_simplify_relations |
115 |
* |
116 |
* TRUE for compiler optimizations |
117 |
* default is TRUE, set to FALSE by passing +s on the command line |
118 |
*/ |
119 |
static int g_interface_simplify_relations = TRUE; |
120 |
|
121 |
/* |
122 |
* g_interfacever |
123 |
* |
124 |
* TRUE if windows to be built; default is TRUE, false is not supported |
125 |
*/ |
126 |
static int g_interfacever = 0; |
127 |
|
128 |
/* |
129 |
* tty |
130 |
* |
131 |
* Non-zero means standard input is a terminal-like device. |
132 |
* Zero means it's a file. |
133 |
*/ |
134 |
static int tty; |
135 |
|
136 |
/* |
137 |
* This assumes tcl_library has been found and that tcl8.0 and tk8.0 |
138 |
* are installed in the same lib directory -- the default tcl/tk install. |
139 |
*/ |
140 |
|
141 |
/* |
142 |
* build_name |
143 |
* |
144 |
* who built this binary and when |
145 |
*/ |
146 |
#ifndef TIMESTAMP |
147 |
static char build_name[]="by anonymous"; |
148 |
#else |
149 |
static char build_name[]=TIMESTAMP; |
150 |
#endif /* TIMESTAMP */ |
151 |
|
152 |
|
153 |
|
154 |
/* |
155 |
* main or WinMain |
156 |
* |
157 |
* The main entry point for a Unix or Windows application. |
158 |
* |
159 |
* Each just calls AscDriver(). |
160 |
* These are based on functions from the Tk 8.0 distribution. |
161 |
* See unix/tkAppInit.c and win/winMain.c in their sources. |
162 |
*/ |
163 |
#ifndef __WIN32__ |
164 |
|
165 |
int main(int argc, CONST84 char *argv[]) |
166 |
{ |
167 |
AscDriver(argc, argv); |
168 |
return 0; |
169 |
} |
170 |
|
171 |
#else /* __WIN32__ */ |
172 |
/* this may need fixing undfer windows, if winmain requires tk */ |
173 |
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, |
174 |
LPSTR lpszCmdLine, int nCmdShow) |
175 |
{ |
176 |
int argc; |
177 |
char **argv; |
178 |
char *p; |
179 |
char buffer[MAX_PATH]; |
180 |
|
181 |
/* |
182 |
* Set up the default locale to be standard "C" locale so parsing |
183 |
* is performed correctly. |
184 |
*/ |
185 |
setlocale(LC_ALL, "C"); |
186 |
|
187 |
/* |
188 |
* Increase the application queue size from default value of 8. |
189 |
* At the default value, cross application SendMessage of WM_KILLFOCUS |
190 |
* will fail because the handler will not be able to do a PostMessage! |
191 |
* This is only needed for Windows 3.x, since NT dynamically expands |
192 |
* the queue. |
193 |
*/ |
194 |
SetMessageQueue(64); |
195 |
|
196 |
/* |
197 |
* Create the console channels and install them as the standard |
198 |
* channels. All I/O will be discarded until TkConsoleInit is |
199 |
* called to attach the console to a text widget. |
200 |
*/ |
201 |
|
202 |
/* |
203 |
* Windows expects us to parse our arguments ourselves. |
204 |
*/ |
205 |
setargv(&argc, &argv); |
206 |
|
207 |
/* |
208 |
* Replace argv[0] with full pathname of executable, and forward |
209 |
* slashes substituted for backslashes. |
210 |
*/ |
211 |
GetModuleFileName(NULL, buffer, sizeof(buffer)); |
212 |
argv[0] = buffer; |
213 |
for (p = buffer; *p != '\0'; p++) { |
214 |
if (*p == '\\') { |
215 |
*p = '/'; |
216 |
} |
217 |
} |
218 |
|
219 |
AscDriver(argc, argv); |
220 |
return 1; |
221 |
} |
222 |
#endif /* __WIN32__ */ |
223 |
|
224 |
|
225 |
/* |
226 |
* int AscDriver( argc, argv ) |
227 |
* int argc; |
228 |
* char *argv; |
229 |
* |
230 |
* A common entry point for Windows and Unix. The corresponding |
231 |
* WinMain() and main() functions just call this function. |
232 |
* |
233 |
* This function creates a Tcl interpreter, initializes Tcl and Tk, |
234 |
* initializes the Ascend data structures, sets up the user's |
235 |
* environment, sources ASCEND's startup script, and calls Tk_MainLoop |
236 |
* so the user can interact with ASCEND. Cleans up and exits the |
237 |
* program when Tk_MainLoop returns. |
238 |
* |
239 |
* This function is based on the functions Tk_Main and Tcl_AppInit |
240 |
* from the Tk8.0 distribution. See the files tkMain.c and tkAppInit.c |
241 |
* in the Tk sources. |
242 |
* |
243 |
*/ |
244 |
static int AscDriver(int argc, CONST84 char *argv[]) |
245 |
{ |
246 |
|
247 |
/* |
248 |
* Set the "tcl_interactive" variable. |
249 |
* |
250 |
* ASCEND sets tty to `1', since we assume ASCEND is always interactive. |
251 |
*/ |
252 |
tty = 1; |
253 |
#ifdef USE_ASC_PRINTF |
254 |
Asc_PrintInit(); |
255 |
#endif /* USE_ASC_PRINTF */ |
256 |
|
257 |
/* |
258 |
* Now that our console and printing functions are properly |
259 |
* initialized, print our startup banner. |
260 |
*/ |
261 |
PRINTF("ASCEND VERSION IV\n"); |
262 |
PRINTF("Compiler Implemention Version: 2.0\n"); |
263 |
PRINTF("Written by Tom Epperly,Kirk Abbott, and Ben Allan\n"); |
264 |
PRINTF("Copyright(C) 1990, 1993, 1994 Thomas Guthrie Epperly\n"); |
265 |
PRINTF(" Built: %s %s %s\n",__DATE__,__TIME__,build_name); |
266 |
PRINTF("Copyright(C) 1993-1996 Kirk Andre Abbott, Ben Allan\n"); |
267 |
PRINTF("Copyright(C) 1997 Carnegie Mellon University\n"); |
268 |
|
269 |
|
270 |
/* |
271 |
* Initialize ASCEND C Structures |
272 |
* Create ASCEND Tcl Commands |
273 |
*/ |
274 |
clock(); |
275 |
/* the next line should NOT be Asc_SignalHandlerPush */ |
276 |
(void)signal(SIGINT, AscTrap); |
277 |
#ifdef DEBUG_MALLOC |
278 |
InitDebugMalloc(); |
279 |
ascstatus("Memory status after calling InitDebugMalloc()"); |
280 |
#endif /* DEBUG_MALLOC */ |
281 |
if ( Asc_CompilerInit(g_interface_simplify_relations) != 0 ) { |
282 |
Asc_Panic(2, "Asc_CompilerInit", |
283 |
"Insufficient memory to initialize compiler."); |
284 |
} |
285 |
SlvRegisterStandardClients(); |
286 |
/* |
287 |
* Loop infinitely, waiting for commands to execute. When there |
288 |
* are no windows left, Tk_MainLoop returns and we exit. |
289 |
*/ |
290 |
#ifdef DEBUG_MALLOC |
291 |
ascstatus("Memory status before calling Tk_MainLoop()"); |
292 |
#endif /* DEBUG_MALLOC */ |
293 |
#ifdef DEBUG_MALLOC |
294 |
ascstatus("Memory status after Tk_MainLoop() exits"); |
295 |
#endif /* DEBUG_MALLOC */ |
296 |
|
297 |
AscProcessCommandLine( argc, argv); |
298 |
/* * App goes here. */ |
299 |
|
300 |
|
301 |
/* app done now. */ |
302 |
|
303 |
/* |
304 |
* Do ASCEND Cleanup |
305 |
*/ |
306 |
Asc_HelpDestroy(); |
307 |
Asc_UnitValue(NULL); |
308 |
Asc_SolvMemoryCleanup(); |
309 |
Asc_CompilerDestroy(); |
310 |
Asc_DestroyEnvironment(); |
311 |
#ifdef DEBUG_MALLOC |
312 |
ascshutdown("Memory status just before exiting"); |
313 |
#endif /* DEBUG_MALLOC */ |
314 |
|
315 |
return 0; |
316 |
} |
317 |
|
318 |
|
319 |
static int AscProcessCommandLine( int argc, CONST84 char **argv) |
320 |
{ |
321 |
int i; |
322 |
int flag; /* set to 1 for `+arg', -1 for `-arg' */ |
323 |
size_t length; /* length of an argv */ |
324 |
char *args; |
325 |
char buf[MAXIMUM_NUMERIC_LENGTH]; /* space for integer->string conversion */ |
326 |
int new_argc = 0; /* the argc we will pass to Tcl */ |
327 |
#ifdef ZZ_DEBUG |
328 |
zz_debug = 0; /* nonzero to print parser debugging info*/ |
329 |
#endif |
330 |
|
331 |
for( i = 1; i < argc; i++ ) { |
332 |
if( (length = strlen(argv[i])) == 0 ) { |
333 |
/* ignore 0-length arguments */ |
334 |
continue; |
335 |
} |
336 |
|
337 |
if(( length >= 2 ) && ( strncmp(argv[i],"-h",2) == 0 )) { |
338 |
AscPrintHelpExit(argv[0]); |
339 |
} |
340 |
if(( length >= 2 ) && ( strncmp(argv[i],"-H",2) == 0 )) { |
341 |
AscPrintHelpExit(argv[0]); |
342 |
} |
343 |
if(( length >= 4 ) && ( strncmp(argv[i],"help",4) == 0 )) { |
344 |
AscPrintHelpExit(argv[0]); |
345 |
} |
346 |
|
347 |
if( argv[i][0] == '-' ) { |
348 |
flag = -1; |
349 |
} else if( argv[i][0] == '+' ) { |
350 |
flag = 1; |
351 |
} else { |
352 |
flag = 0; |
353 |
} |
354 |
|
355 |
if(( length == 2 ) && ( flag != 0 )) { |
356 |
switch( argv[i][1] ) { |
357 |
case 'd': |
358 |
/* '-d' turns on scanner debugging (if ascend was built with it) |
359 |
* '+d' turns off scanner debugging [default] |
360 |
*/ |
361 |
if( flag == -1 ) { |
362 |
#ifdef ZZ_DEBUG |
363 |
zz_debug = 1; |
364 |
} else { |
365 |
zz_debug = 0; |
366 |
#else |
367 |
FPRINTF(ASCERR, "Sorry, %s wasn't compiled with %s defined.\n", |
368 |
argv[0], "ZZ_DEBUG"); |
369 |
#endif /* ZZ_DEBUG */ |
370 |
} |
371 |
break; |
372 |
case 's': |
373 |
/* '-s' turns on compiler optimizations [default] |
374 |
* '+s' turns off compiler optimizations |
375 |
*/ |
376 |
if( flag == -1 ) { |
377 |
g_interface_simplify_relations = 1; |
378 |
} else { |
379 |
g_interface_simplify_relations = 0; |
380 |
} |
381 |
break; |
382 |
case 't': |
383 |
/* '-t' turns on timing of compiler optimizations |
384 |
* '+t' turns off timing of compiler optimizations [default] |
385 |
*/ |
386 |
if( flag == 0 ) { |
387 |
g_compiler_timing = 1; |
388 |
} else { |
389 |
g_compiler_timing = 0; |
390 |
} |
391 |
break; |
392 |
case 'c': |
393 |
case 'g': |
394 |
fprintf(ASCERR, "WARNING! Obsolete ASCEND option \"%s\"\n", argv[i]); |
395 |
break; |
396 |
default: |
397 |
/* unknown ASCEND option, pass it on to Tcl |
398 |
*/ |
399 |
argv[++new_argc] = argv[i]; |
400 |
break; |
401 |
} |
402 |
} else { |
403 |
/* unknown ASCEND option, pass it on to Tcl |
404 |
*/ |
405 |
argv[++new_argc] = argv[i]; |
406 |
} |
407 |
} |
408 |
|
409 |
return 0; |
410 |
} |
411 |
|
412 |
/* |
413 |
* AscPrintHelpExit(invoke_name) |
414 |
* CONST char *invoke_name; |
415 |
* |
416 |
* Print a help message and exit. Use invoke_name as the name of |
417 |
* the binary |
418 |
*/ |
419 |
static |
420 |
void AscPrintHelpExit(CONST char *invoke_name) |
421 |
{ |
422 |
PRINTF("usage: %s [options]\n" |
423 |
"\n" |
424 |
"where options include [default value]:\n" |
425 |
" -h print this message\n" |
426 |
" -/+d turn on/off yacc debugging [off]\n" |
427 |
" -/+s turn on/off compiler optimizations [on]\n" |
428 |
" -/+t turn on/off timing of compiler operations [off]\n", |
429 |
invoke_name); |
430 |
exit(0); |
431 |
} |
432 |
|
433 |
|
434 |
/* |
435 |
* AscTrap(sig) |
436 |
* int sig; |
437 |
* |
438 |
* Function to call when we receive an interrupt. |
439 |
*/ |
440 |
static |
441 |
void AscTrap(int sig) |
442 |
{ |
443 |
putchar('\n'); |
444 |
Asc_Panic(sig, "AscTrap", "Caught Signal: %d", sig); |
445 |
} |
446 |
|
447 |
|
448 |
|
449 |
/* |
450 |
*---------------------------------------------------------------------- |
451 |
* Tom Epperly's Malloc Debugger |
452 |
*---------------------------------------------------------------------- |
453 |
*/ |
454 |
#ifdef DEBUG_MALLOC |
455 |
static void InitDebugMalloc(void) |
456 |
{ |
457 |
union dbmalloptarg m; |
458 |
m.str = NULL; |
459 |
m.i = 0; |
460 |
dbmallopt(MALLOC_CKDATA,&m); |
461 |
} |
462 |
|
463 |
#endif /* DEBUG_MALLOC */ |
464 |
|
465 |
#ifdef __WIN32__ |
466 |
/* |
467 |
*------------------------------------------------------------------------- |
468 |
* |
469 |
* setargv -- |
470 |
* |
471 |
* Parse the Windows command line string into argc/argv. Done here |
472 |
* because we don't trust the builtin argument parser in crt0. |
473 |
* Windows applications are responsible for breaking their command |
474 |
* line into arguments. |
475 |
* |
476 |
* 2N backslashes + quote -> N backslashes + begin quoted string |
477 |
* 2N + 1 backslashes + quote -> literal |
478 |
* N backslashes + non-quote -> literal |
479 |
* quote + quote in a quoted string -> single quote |
480 |
* quote + quote not in quoted string -> empty string |
481 |
* quote -> begin quoted string |
482 |
* |
483 |
* Results: |
484 |
* Fills argcPtr with the number of arguments and argvPtr with the |
485 |
* array of arguments. |
486 |
* |
487 |
* Side effects: |
488 |
* Memory allocated. |
489 |
* |
490 |
* This function is from the Tk 8.0 distribution. See win/winMain.c in |
491 |
* their sources. |
492 |
* |
493 |
*-------------------------------------------------------------------------- |
494 |
*/ |
495 |
static void |
496 |
setargv(argcPtr, argvPtr) |
497 |
int *argcPtr; /* Filled with number of argument strings. */ |
498 |
char ***argvPtr; /* Filled with argument strings (malloc'd). */ |
499 |
{ |
500 |
char *cmdLine, *p, *arg, *argSpace; |
501 |
char **argv; |
502 |
int argc, size, inquote, copy, slashes; |
503 |
|
504 |
cmdLine = GetCommandLine(); |
505 |
|
506 |
/* |
507 |
* Precompute an overly pessimistic guess at the number of arguments |
508 |
* in the command line by counting non-space spans. |
509 |
*/ |
510 |
|
511 |
size = 2; |
512 |
for (p = cmdLine; *p != '\0'; p++) { |
513 |
if (isspace(*p)) { |
514 |
size++; |
515 |
while (isspace(*p)) { |
516 |
p++; |
517 |
} |
518 |
if (*p == '\0') { |
519 |
break; |
520 |
} |
521 |
} |
522 |
} |
523 |
argSpace = (char *) ckalloc((unsigned) (size * sizeof(char *) |
524 |
+ strlen(cmdLine) + 1)); |
525 |
argv = (char **) argSpace; |
526 |
argSpace += size * sizeof(char *); |
527 |
size--; |
528 |
|
529 |
p = cmdLine; |
530 |
for (argc = 0; argc < size; argc++) { |
531 |
argv[argc] = arg = argSpace; |
532 |
while (isspace(*p)) { |
533 |
p++; |
534 |
} |
535 |
if (*p == '\0') { |
536 |
break; |
537 |
} |
538 |
|
539 |
inquote = 0; |
540 |
slashes = 0; |
541 |
while (1) { |
542 |
copy = 1; |
543 |
while (*p == '\\') { |
544 |
slashes++; |
545 |
p++; |
546 |
} |
547 |
if (*p == '"') { |
548 |
if ((slashes & 1) == 0) { |
549 |
copy = 0; |
550 |
if ((inquote) && (p[1] == '"')) { |
551 |
p++; |
552 |
copy = 1; |
553 |
} else { |
554 |
inquote = !inquote; |
555 |
} |
556 |
} |
557 |
slashes >>= 1; |
558 |
} |
559 |
|
560 |
while (slashes) { |
561 |
*arg = '\\'; |
562 |
arg++; |
563 |
slashes--; |
564 |
} |
565 |
|
566 |
if ((*p == '\0') || (!inquote && isspace(*p))) { |
567 |
break; |
568 |
} |
569 |
if (copy != 0) { |
570 |
*arg = *p; |
571 |
arg++; |
572 |
} |
573 |
p++; |
574 |
} |
575 |
*arg = '\0'; |
576 |
argSpace = arg + 1; |
577 |
} |
578 |
argv[argc] = NULL; |
579 |
|
580 |
*argcPtr = argc; |
581 |
*argvPtr = argv; |
582 |
} |
583 |
|
584 |
#endif /* __WIN32__ */ |