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