1 /****************************************************************************
2 Copyright (C) 1987-2015 by Jeffery P. Hansen
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 Last edit by hansen on Wed Mar 18 04:23:18 2009
19 ****************************************************************************/
20
21 #ifndef _GNU_SOURCE
22 #define _GNU_SOURCE
23 #endif
24
25 #ifdef __cplusplus
26 #include <cstdlib>
27 #include <cstring>
28 #else
29 #include <stdlib.h>
30 #include <string.h>
31 #endif
32
33 #include <dirent.h>
34 #include <pwd.h>
35
36 #include "tkgate.h"
37 #include "print.h"
38
39 void MSS_init(); /* Module symbol table initialization */
40
41 static char *tkgateHomeDir = 0;
42
43 int verify_only = 0;
44
45 extern int flashCPath;
46 extern int ob_max_undo;
47 extern int security_exec_level;
48
49 int do_panic_save = 1;
50 int want_exit = 0;
51 int is_verbose = 0;
52
53 static char *print_options = 0;
54 static char *print_file = 0;
55 static char *print_printer = 0;
56
57 int debugContinuousVerify = 0;
58 int debugSimInterface = 0;
59 int sync_Xserver = 0;
60
61 int doBackupOnSave = 0;
62 int doSafeSave = 0;
63 int wantCheckpoint = 0;
64 int checkpointenabled = 0;
65
66 int blockDropConnect = 0;
67
68 /*****************************************************************************
69 *
70 * Table of messages loaded from the locale-specific messages file.
71 *
72 *****************************************************************************/
73 SHash *message_table = 0;
74
75 /*
76 * Global variables used in main/Tk_AppInit
77 */
78 static const char **loadList = 0;
79 static int numLoads = 0;
80 static const char **libLoadList = 0;
81 static int numLibLoads = 0;
82 static int start_sim = 0;
83 static int do_splash = 1;
84 static char *sim_script = 0;
85 static int debug = 0;
86 extern int guiActive;
87
88 int quietMode = 0;
89
90 char *tkgate_exampledir = 0;
91 char *tkgate_tutorialdir = 0;
92
93 /*****************************************************************************
94 *
95 * Catch a ctrl-c interrupt and do something about it so we can shut down
96 * cleanly.
97 *
98 *****************************************************************************/
catchInterrupt(int s)99 static void catchInterrupt(int s)
100 {
101 FlagRedraw();
102 want_exit = 1;
103 }
104
105 /*****************************************************************************
106 *
107 * Test to see if 'path' is a valid tkgate home directory. We do this by
108 * trying to open some files we expect to be there and returning non-zero
109 * if we find all of the expected files. Returns 0 if one or more expected
110 * files are not found.
111 *
112 *****************************************************************************/
testHome(char * path)113 static int testHome(char *path)
114 {
115 char buf[STRMAX];
116 FILE *f;
117
118 sprintf(buf,"%s/site-preferences",path);
119 if (!(f = fopen(buf,"r"))) return 0;
120 fclose(f);
121
122 sprintf(buf,"%s/locale/en/messages",path);
123 if (!(f = fopen(buf,"r"))) return 0;
124 fclose(f);
125
126 sprintf(buf,"%s/locale/en/tutorials/welcome.v",path);
127 if (!(f = fopen(buf,"r"))) return 0;
128 fclose(f);
129
130 return 1;
131 }
132
133 /*****************************************************************************
134 *
135 * Figure out which directory we should use as the tkgate home.
136 *
137 * 1) Directory specified by TKGATE_HOME environment variable
138 * 2) Current directory
139 * 3) Directory specified by TKGATE_HOMEDIR in config.h
140 * 4) Directory specified by TKGATE_SECONDARYHOME in config.h
141 *
142 * The #define value TKGATE_HOMEDIR is normally generated automatically by the
143 * configure script using TKGATE_HOMEDIRBASE as a prefix and tkgate-x.y (where
144 * x.y is the version number) the subdirectory. The #define value TKGATE_SECONDARYHOME
145 * is normally set to the directory in which tkgate was configured/compiled.
146 *
147 *****************************************************************************/
findTkGateHome(char * homeDir)148 void findTkGateHome(char *homeDir)
149 {
150 char buf[STRMAX];
151 char *trydirs[4];
152 int i;
153
154 trydirs[0] = getenv("TKGATE_HOME");
155 trydirs[1] = getcwd(buf,STRMAX);
156 trydirs[2] = TKGATE_HOMEDIR;
157 trydirs[3] = TKGATE_SECONDARYHOME;
158
159 for (i = 0;i < 4;i++) {
160 if (!trydirs[i]) continue;
161 strcpy(homeDir,trydirs[i]);
162 if (testHome(homeDir)) break;
163 }
164
165 if (i == 4) {
166 printf("\n");
167 printf("I could not locate the tkgate home directory. I tried looking in:\n");
168 if (trydirs[0]) printf(" %s (TKGATE_HOME env. variable)\n", trydirs[0]);
169 if (trydirs[1]) printf(" %s (current directory)\n", trydirs[1]);
170 if (trydirs[2]) printf(" %s (primary location)\n", trydirs[2]);
171 if (trydirs[3]) printf(" %s (secondary location)\n", trydirs[3]);
172 printf("\n");
173 printf("Try setting the environment variable TKGATE_HOME.\n");
174 exit(1);
175 }
176 }
177
PrintCopyright()178 static void PrintCopyright()
179 {
180 extern char *release_date;
181
182 printf("TkGate %s - %s (released %s)\n",VERSIONS[0].vd_name,TKGATE_DESCRIPTION,release_date);
183 printf("[Compiled %s %s]\n",__DATE__,__TIME__);
184 printf("%s\n",TKGATE_COPYRIGHT);
185 printf(" TkGate comes with ABSOLUTELY NO WARRANTY; see 'Help...License' menu\n");
186 printf(" for license and warranty details. Report problems to %s\n",PACKAGE_BUGREPORT);
187
188 fflush(stdout);
189 }
190
LogCopyright()191 static void LogCopyright()
192 {
193 extern char *release_date;
194
195 message(MC_MSGLOG|MC_SILENT,"TkGate %s - %s (released %s)",VERSIONS[0].vd_name,TKGATE_DESCRIPTION,release_date);
196 message(MC_MSGLOG|MC_SILENT,"[Compiled %s %s]",__DATE__,__TIME__);
197 message(MC_MSGLOG|MC_SILENT,"%s",TKGATE_COPYRIGHT);
198 message(MC_MSGLOG|MC_SILENT," TkGate comes with ABSOLUTELY NO WARRANTY; see 'Help...License' menu");
199 message(MC_MSGLOG|MC_SILENT," for license and warranty details. Report problems to %s",PACKAGE_BUGREPORT);
200 }
201
init_linkvars(Tcl_Interp * tcl)202 void init_linkvars(Tcl_Interp *tcl)
203 {
204 extern int stepsize;
205 static char randomstate[128];
206
207 initstate(getpid() | time(0),randomstate,128);
208
209 Tcl_SetVar(tcl,"tkg_progVer",VERSIONS[0].vd_name,TCL_GLOBAL_ONLY);
210 Tcl_SetVar(tcl,"tkg_description",TKGATE_DESCRIPTION,TCL_GLOBAL_ONLY);
211 Tcl_SetVar(tcl,"tkg_copyright",TKGATE_COPYRIGHT,TCL_GLOBAL_ONLY);
212 Tcl_SetVar(tcl,"tkg_mailContact",PACKAGE_BUGREPORT,TCL_GLOBAL_ONLY);
213 Tcl_SetVar(tcl,"tkg_homepage",PACKAGE_URL,TCL_GLOBAL_ONLY);
214 Tcl_SetVar(tcl,"tkg_localdoc",TKGATE_LOCALDOC,TCL_GLOBAL_ONLY);
215 Tcl_SetVar(tcl,"tkg_gateHome",TkGate.homedir,TCL_GLOBAL_ONLY);
216 Tcl_SetVar(tcl,"tkg_doSplash",binstr(do_splash),TCL_GLOBAL_ONLY);
217
218 Tcl_LinkVar(tcl,"tkg_errorLogFile",(char*)&TkGate.errorLogFile,TCL_LINK_STRING);
219 Tcl_LinkVar(tcl,"tkg_siteName",(char*)&TkGate.siteName,TCL_LINK_STRING);
220 Tcl_LinkVar(tcl,"tkg_defaultTech",(char*)&TkGate.defaultTech,TCL_LINK_STRING);
221 Tcl_LinkVar(tcl,"tkg_browserCommand",(char*)&TkGate.browserCommand,TCL_LINK_STRING);
222 Tcl_LinkVar(tcl,"tkg_emailCommand",(char*)&TkGate.emailCommand,TCL_LINK_STRING);
223
224 Tcl_LinkVar(tcl,"tkg_contVerify",(char*)&debugContinuousVerify,TCL_LINK_INT);
225 Tcl_LinkVar(tcl,"tkg_simStepSize",(char*)&stepsize,TCL_LINK_INT);
226 Tcl_LinkVar(tcl,"tkg_checkpointEnabled",(char*)&checkpointenabled,TCL_LINK_INT);
227 Tcl_LinkVar(tcl,"tkg_wantCheckpoint",(char*)&wantCheckpoint,TCL_LINK_INT);
228 Tcl_LinkVar(tcl,"tkg_simDebugInterface",(char*)&debugSimInterface,TCL_LINK_INT);
229 Tcl_LinkVar(tcl,"tkg_baderMode",(char*)&TkGate.baderp,TCL_LINK_INT);
230 Tcl_LinkVar(tcl,"tkg_trekMode",(char*)&TkGate.startrekp,TCL_LINK_INT);
231 Tcl_LinkVar(tcl,"tkg_batMode",(char*)&TkGate.batp,TCL_LINK_INT);
232 Tcl_LinkVar(tcl,"tkg_modifiedFlag",(char*)&TkGate.changedp,TCL_LINK_INT);
233 Tcl_LinkVar(tcl,"tkg_regionUpdate",(char*)&TkGate.regionUpdate,TCL_LINK_INT);
234 Tcl_LinkVar(tcl,"tkg_doBackupOnSave",(char*)&doBackupOnSave,TCL_LINK_INT);
235 Tcl_LinkVar(tcl,"tkg_doSafeSave",(char*)&doSafeSave,TCL_LINK_INT);
236 Tcl_LinkVar(tcl,"tkg_smoothScroll",(char*)&TkGate.smoothScroll,TCL_LINK_INT);
237 Tcl_LinkVar(tcl,"tkg_flashCPath",(char*)&TkGate.flashCPath,TCL_LINK_INT);
238 Tcl_LinkVar(tcl,"tkg_undoLength",(char*)&ob_max_undo,TCL_LINK_INT);
239 Tcl_LinkVar(tcl,"tkg_securityExec",(char*)&security_exec_level,TCL_LINK_INT);
240 Tcl_LinkVar(tcl,"tkg_blockDropConnect",(char*)&blockDropConnect,TCL_LINK_INT);
241 Tcl_LinkVar(tcl,"tkg_extendBars",(char*)&TkGate.extendBars,TCL_LINK_INT);
242 Tcl_LinkVar(tcl,"tkg_showSwitchNets",(char*)&TkGate.showSwitchNets,TCL_LINK_INT);
243
244 Tcl_LinkVar(tcl,"simOn",(char*)&TkGate.circuit->simulator.active,TCL_LINK_INT);
245 Tcl_LinkVar(tcl,"tkg_discardChanges",(char*)&TkGate.circuit->discardChanges,TCL_LINK_INT);
246 Tcl_LinkVar(tcl,"tkg_useExtBars",(char*)&TkGate.circuit->useExtBars,TCL_LINK_INT);
247
248 Tcl_LinkVar(tcl,"tkg_saveTraces",(char*)&TkGate.saveTraces,TCL_LINK_INT);
249 Tcl_LinkVar(tcl,"tkg_simSortTraces", (char*)&TkGate.sortTraces, TCL_LINK_INT);
250
251 DoTcl("namespace eval HdlEditor {}");
252 Tcl_LinkVar(tcl,"HdlEditor::isActive",(char*)&hdl_isactive, TCL_LINK_INT);
253 }
254
255 /*
256 * Set handlers on various signals we might receive. Most abnormal signals
257 * are caught by panicSave which attempts to save the current circuit.
258 */
tkgate_signalSetup()259 void tkgate_signalSetup()
260 {
261 /*
262 Make sure they really want to exit when ctl-c is typed.
263 */
264 signal(SIGINT,catchInterrupt);
265
266 /*
267 Do a panic save on any core dump producing signal, or
268 on a SIGHUP.
269 */
270 if (do_panic_save) {
271 signal(SIGHUP,panicSave);
272 signal(SIGQUIT,panicSave);
273 signal(SIGILL,panicSave);
274 signal(SIGTRAP,panicSave);
275 signal(SIGFPE,panicSave);
276 signal(SIGBUS,panicSave);
277 signal(SIGSEGV,panicSave);
278 #ifdef SIGEMT
279 signal(SIGEMT,panicSave);
280 #endif
281 #ifdef SIGSYS
282 signal(SIGSYS,panicSave);
283 #endif
284 }
285 }
286
undoSignals()287 void undoSignals()
288 {
289 #ifdef SIGABRT
290 signal(SIGABRT,SIG_DFL);
291 #endif
292 signal(SIGHUP,SIG_DFL);
293 signal(SIGQUIT,SIG_DFL);
294 signal(SIGILL,SIG_DFL);
295 signal(SIGTRAP,SIG_DFL);
296 signal(SIGFPE,SIG_DFL);
297 signal(SIGBUS,SIG_DFL);
298 signal(SIGSEGV,SIG_DFL);
299 #ifdef SIGEMT
300 signal(SIGEMT,SIG_DFL);
301 #endif
302 #ifdef SIGSYS
303 signal(SIGSYS,SIG_DFL);
304 #endif
305 }
306
307
308 /*****************************************************************************
309 *
310 * Load the circuits on the command line only to check their integrety.
311 *
312 *****************************************************************************/
doVerifyLoad()313 void doVerifyLoad()
314 {
315 extern int VerilogErrorCount;
316 int i;
317
318 TkGate.tcl = 0;
319
320 MSS_init();
321 init_gates();
322
323 TkGate.circuit = new_Circuit();
324 TkGate.ed = (EditData*) malloc(sizeof(EditData));
325 TkGate.errl = (ErrorList*) malloc(sizeof(ErrorList));
326
327 for (i = 0;i < numLoads;i++) {
328 VerilogOpen(&TkGate.circuit->es,loadList[i],(i > 0));
329
330 /*
331 * We got an error reading a circuit file.
332 */
333 if (VerilogErrorCount > 0)
334 exit(1);
335 }
336
337 /*
338 * We found inconsistencies in the file.
339 */
340 if (verify_circuit() > 0)
341 exit(2);
342
343 exit(0);
344 }
345
trimQuotes(char * str)346 void trimQuotes(char *str)
347 {
348 if (*str == '"') {
349 int l;
350
351 memmove(str,str+1,strlen(str));
352 l = strlen(str);
353 if (l > 0 && str[l-1] == '"')
354 str[l-1] = 0;
355 }
356 }
357
358 /*
359 * Do defaults setup for command line printing. We need to find out what the site
360 * name is and get the options from the user's preferences file. We need to read
361 * the preferences file manually since we are not starting the tcl/tk interpreter.
362 */
commandLinePrintSetup(GPrintOpt * PO)363 void commandLinePrintSetup(GPrintOpt *PO)
364 {
365 FILE *f;
366 char buf[STRMAX];
367 char *p;
368
369 /*
370 * Get the default site name from the
371 */
372 sprintf(buf,"%s/site-preferences",TkGate.homedir);
373 f = fopen(buf,"r");
374 if (f) {
375 char str[STRMAX];
376
377 while (fgets(buf,STRMAX,f)) {
378 if (sscanf(buf,"Option::value siteName %[^\n]",str) == 1) {
379 trimQuotes(str);
380 TkGate.siteName = strdup(str);
381 }
382 }
383
384 fclose(f);
385 }
386
387 GPrintOpt_clDefault(PO);
388
389 /*
390 * If we have a home directory, open the preferences file and read
391 * printing related defaults from it.
392 */
393 p = getenv("HOME");
394 if (p) {
395 extern PaperSize paperSizes[];
396
397 sprintf(buf,"%s/.tkgate2-preferences",p);
398 f = fopen(buf,"r");
399 if (f) {
400 const char *lang = getenv("LANG");
401 char str[STRMAX];
402 int d;
403
404 while (fgets(buf,STRMAX,f)) {
405 if (sscanf(buf,"Option::value siteName %[^\n]",str) == 1) {
406 trimQuotes(str);
407 TkGate.siteName = strdup(str);
408 } else if (sscanf(buf,"Option::value printCommand %[^\n]",str) == 1) {
409 trimQuotes(str);
410 PO->po_cmd = strdup(str);
411 } else if (sscanf(buf,"Option::value printPgSizeA4 %d",&d) == 1) {
412 if (strncmp(lang,"en",2) != 0)
413 PO->po_paper = strdup(paperSizes[d].ps_size);
414 } else if (sscanf(buf,"Option::value printPgSize %d",&d) == 1) {
415 if (strncmp(lang,"en",2) == 0)
416 PO->po_paper = strdup(paperSizes[d].ps_size);
417 } else if (sscanf(buf,"Option::value printPgOrient %s",str) == 1) {
418 PO->po_orient = strdup(str);
419 } else if (sscanf(buf,"Option::value printStyle %s",str) == 1) {
420 PO->po_style = strdup(str);
421 } else if (sscanf(buf,"Option::value printDuplex %s",str) == 1) {
422 PO->po_isDuplex = strdup(str);
423 } else if (sscanf(buf,"Option::value printIndex %s",str) == 1) {
424 PO->po_index = strdup(str);
425 } else if (sscanf(buf,"Option::value printGraph %s",str) == 1) {
426 PO->po_graph = strdup(str);
427 }
428 }
429 fclose(f);
430 }
431 }
432
433 if (!TkGate.siteName)
434 TkGate.siteName = strdup("CLP");
435
436 }
437
438 /*****************************************************************************
439 *
440 * Set up for doing printing from the command line.
441 *
442 *****************************************************************************/
commandLinePrint()443 void commandLinePrint()
444 {
445 extern int VerilogErrorCount;
446 char *p;
447 int i;
448 GPrintOpt PO;
449 extern PaperSize paperSizes[];
450
451 TkGate.tcl = 0;
452 init_gates();
453 TkGate.ed = (EditData*) malloc(sizeof(EditData));
454 TkGate.errl = (ErrorList*) malloc(sizeof(ErrorList));
455 TkGate.circuit = new_Circuit(0);
456
457
458 for (i = 0;i < numLoads;i++) {
459 VerilogOpen(&TkGate.circuit->es,loadList[i],(i > 0));
460
461 /*
462 * We got an error reading a circuit file.
463 */
464 if (VerilogErrorCount > 0)
465 exit(1);
466 }
467
468 /*
469 * Apply default options
470 */
471 commandLinePrintSetup(&PO);
472
473
474 if (print_file) {
475 PO.po_file = print_file;
476 PO.po_cmd = 0;
477 } else {
478 PO.po_cmd = print_printer;
479 PO.po_file = 0;
480 }
481
482 /*
483 * Apply printer options
484 */
485 for (p = strtok(print_options,":");p;p = strtok(0,":")) {
486 char name[STRMAX];
487 char sval[STRMAX];
488 int n;
489
490 if (!*p) continue; /* Ignore empty options */
491
492 if (sscanf(p,"%[^=]=%s",name,sval) == 2) {
493 } else if (sscanf(p,"%[^=]",name) == 1) {
494 strcpy(sval,"1");
495 } else {
496 fprintf(stderr,"tkgate: Badly formatted print option '%s'\n",p);
497 fprintf(stderr," run 'tkgate -h' for help.\n");
498 exit(1);
499 }
500
501 n = strlen(name);
502 if (strncmp(name,"duplex",n) == 0) {
503 PO.po_isDuplex = strdup(sval);
504 } else if (strncmp(name,"epsf",n) == 0) {
505 PO.po_epsf = strdup(sval);
506 } else if (strncmp(name,"index",n) == 0) {
507 PO.po_index = strdup(sval);
508 } else if (strncmp(name,"hierarchy",n) == 0) {
509 PO.po_graph = strdup(sval);
510 } else if (strncmp(name,"paper",n) == 0) {
511 PO.po_paper = strdup(sval);
512 } else if (strncmp(name,"modules",n) == 0) {
513 PO.po_select = "sel";
514 PO.po_modlist = strdup(sval);
515 } else if (strncmp(name,"4up",n) == 0) {
516 PO.po_4up = strdup(sval);
517 } else {
518 fprintf(stderr,"tkgate: Unknown print option '%s'\n",name);
519 fprintf(stderr," run 'tkgate -h' for help.\n");
520 exit(1);
521 }
522 }
523
524
525 /*
526 * Check for valid paper size and convert to expected case if necessary.
527 */
528 for (i = 0;paperSizes[i].ps_size;i++)
529 if (strcasecmp(PO.po_paper,paperSizes[i].ps_size) == 0) {
530 PO.po_paper = paperSizes[i].ps_size;
531 break;
532 }
533 if (!paperSizes[i].ps_size) {
534 fprintf(stderr,"tkgate: Unknown paper size '%s'\n",PO.po_paper);
535 exit(1);
536 }
537
538
539 ob_begin_frame("Print");
540 /* Html_setFormatTarget(HT_FORCEPRINT);*/
541 GPrintOpt_print(&PO);
542 ob_end_frame();
543
544 exit(0);
545 }
546
usage()547 void usage()
548 {
549 fprintf(stderr,"Usage: tkgate [options][file]\n\n");
550 fprintf(stderr," Options:\n");
551 fprintf(stderr," -h Print this summary of options.\n");
552 fprintf(stderr," -s Run in X11 synchronous mode (slow).\n");
553 fprintf(stderr," -q Suppress some messages to the tty.\n");
554 fprintf(stderr," -x Start simulator immediately.\n");
555 fprintf(stderr," -n Do not display the splash window on startup.\n");
556 fprintf(stderr," -V Verify a save file..\n");
557 fprintf(stderr," -X file Start simulator immediately and execute script.\n");
558 /* fprintf(stderr," -l file Load file as a library.\n");*/
559 fprintf(stderr," -L lang Specify language (if configured).\n");
560 fprintf(stderr," -p file Print to a file.\n");
561 fprintf(stderr," -P prn Output to a printer.\n");
562 fprintf(stderr," -O opts Printer options.\n");
563 fprintf(stderr,"\n");
564 fprintf(stderr," Printer options are specified as a colon separated list of\n");
565 fprintf(stderr," the following items (identifiers can be abreviated):\n");
566 fprintf(stderr,"\n");
567 fprintf(stderr," epsf=bool Use encapsulated Postscript format\n");
568 fprintf(stderr," duplex=bool Use duplex printing\n");
569 fprintf(stderr," index=bool Include index\n");
570 fprintf(stderr," hier=bool Include hierarchy graph\n");
571 fprintf(stderr," paper=type Use specified paper type\n");
572 fprintf(stderr," 4up=bool Do 4-up printing of small modules\n");
573 fprintf(stderr," modules=list List of modules to print (comma separated)\n");
574 fprintf(stderr,"\n");
575 exit(0);
576 }
577
setLanguage(const char * lang)578 void setLanguage(const char *lang)
579 {
580 static char buf[128];
581
582 if (strlen(lang) > 100) {
583 putenv("TKGATE_LANG=ASCII");
584 return;
585 }
586
587 /*
588 * Solaris putenv man page claims the actual string passed
589 * to putenv is used in the environment so we must make a
590 * a copy for the putenv().
591 */
592 sprintf(buf,"TKGATE_LANG=%s",lang);
593 putenv(strdup(buf));
594
595 if (strcasecmp(lang,"ja") == 0) {
596 lang = "ja_JP.eucJP";
597
598 sprintf(buf,"LC_ALL=%s",lang);
599 putenv(strdup(buf));
600
601 sprintf(buf,"LC_CTYPE=%s",lang);
602 putenv(strdup(buf));
603
604 sprintf(buf,"LANG=%s",lang);
605 putenv(strdup(buf));
606 }
607 }
608
609 /*****************************************************************************
610 *
611 * Parse the command-line options to tkgate.
612 *
613 * Parameters:
614 * argc Number of command-line arguments
615 * argv Command-line argument array
616 *
617 *****************************************************************************/
parse_options(int argc,const char * argv[])618 void parse_options(int argc,const char *argv[])
619 {
620 int c;
621 // extern char *optarg;
622 // extern int optind;
623 #if OPTRESET
624 extern int optreset;
625 #endif
626 char *lib_env;
627
628 loadList = (const char**) calloc(argc,sizeof(char*));
629 libLoadList = (const char**) calloc(argc,sizeof(char*));
630
631 /*
632 * Check environment variable for libraries to load
633 */
634 lib_env = getenv("TKGATE_LIBS");
635 if (lib_env) {
636 char *t;
637
638 lib_env = strdup(lib_env);
639 for (t = strtok(lib_env,":");t;t = strtok(0,":")) {
640 libLoadList[numLibLoads++] = strdup(t);
641 }
642 free(lib_env);
643 }
644
645 while (argc > 0) {
646 /*
647 * NOTE: The '-l' option has been disabled
648 */
649 while ((c = getopt(argc,(char**)argv,"vVAhdxqsnX:L:p:P:O:H:")) != EOF) {
650 switch (c) {
651 case 'H' :
652 tkgateHomeDir = strdup(optarg);
653 break;
654 case 'v' :
655 is_verbose = 1;
656 break;
657 case 'V' :
658 verify_only = 1;
659 break;
660 case 'A' :
661 do_panic_save = 0;
662 break;
663 case 'n' :
664 do_splash = 0;
665 break;
666 case 'X' :
667 start_sim = 1;
668 sim_script = strdup(optarg);
669 break;
670 case 'O' :
671 if (print_options) {
672 print_options = realloc(print_options,strlen(print_options)+strlen(optarg)+2);
673 strcat(print_options,":");
674 strcat(print_options,optarg);
675 } else
676 print_options = strdup(optarg);
677 break;
678 case 'p' :
679 print_file = strdup(optarg);
680 break;
681 case 'P' :
682 print_printer = strdup(optarg);
683 break;
684 case 'x' :
685 start_sim = 1;
686 break;
687 case 'q' :
688 quietMode = 1;
689 break;
690 case 's' :
691 sync_Xserver = 1;
692 break;
693 case 'd' :
694 debug = 1;
695 break;
696 case 'l' :
697 libLoadList[numLibLoads++] = strdup(optarg);
698 break;
699 case 'L' :
700 setLanguage(optarg);
701 break;
702 case 'h' :
703 default :
704 usage();
705 break;
706 }
707 }
708 argc -= optind;
709 argv += optind;
710 #if OPTRESET
711 optreset = 1;
712 #endif
713 optind = 0;
714 if (argc > 0) {
715 loadList[numLoads++] = strdup(argv[0]);
716 argc--;
717 argv++;
718 }
719 }
720 }
721
722 /*****************************************************************************
723 *
724 * See if Miles Bader is running this program and harass him just a bit.
725 *
726 *****************************************************************************/
bader_check()727 void bader_check()
728 {
729 struct passwd *pw = getpwuid(getuid());
730 char buf[STRMAX],*p;
731
732 strcpy(buf,pw->pw_gecos);
733 for (p = buf;*p;p++)
734 if (isupper(*p)) *p = tolower(*p);
735
736 if (strcasestr(buf,"miles") != 0 && strcasestr(buf,"bader") != 0) {
737 TkGate.baderp = 1;
738 printf("Hi sMiles!\n");
739 } else if ((strcasestr(buf,"james") != 0 || strcasestr(buf,"jim") != 0) && strcasestr(buf,"kirk") != 0) {
740 TkGate.startrekp = 1;
741 printf("Kirk, this place is swarming with Klingons!\n");
742 } else if ((strcasestr(buf,"william") != 0 || strcasestr(buf,"bill") != 0) && strcasestr(buf,"shatner") != 0) {
743 TkGate.startrekp = 1;
744 printf("Do you have a point Spock?\n");
745 } else if (strcasestr(buf,"bruce") != 0 && strcasestr(buf,"wayne") != 0) {
746 TkGate.batp = 1;
747 printf("Let's go, Robin. The longer we tarry, the more dire the peril.\n");
748 }
749 }
750
751 /*****************************************************************************
752 *
753 * Read delay files and associate them with gates
754 *
755 *****************************************************************************/
TkGate_initDelay()756 void TkGate_initDelay()
757 {
758 char buf[STRMAX];
759 HashElem *E;
760 int i;
761 const char *p;
762
763 GDelayDef_flush();
764
765 p = Tcl_GetVar(TkGate.tcl,"tkg_simDefaultDelayFile",TCL_GLOBAL_ONLY);
766 if (GDelayDef_readFile(p) < 0)
767 message(1,"Can not open default delay file '%s'.",p);
768
769 p = Tcl_GetVar(TkGate.tcl,"tkg_simDelayFile",TCL_GLOBAL_ONLY);
770 strcpy(buf,p);
771 for (p = strtok(buf," ");p;p = strtok(0," ")) {
772 if (GDelayDef_readFile(p) < 0)
773 message(1,"tkgate: Can not open delay file '%s'.",p);
774 }
775
776 for (E = Hash_first(GateIdxHash);E;E = Hash_next(GateIdxHash,E)) {
777 GGateInfo *gi = (GGateInfo*) HashElem_obj(E);
778
779 for (i = 0;gi->delayNames[i];i++);
780 gi->num_delays = i;
781
782 if (!gi->num_delays) continue;
783
784 gi->delay_defs = GDelayDef_findList(gi->name);
785 if (!gi->delay_defs) {
786 message(1,"No delay definitions found for primitive '%s'.",gi->name);
787 } else {
788 GDelayDef *dd = GDelayDef_findTech(gi->delay_defs,TKGATE_DEFAULT_TECH);
789 if (strcmp(dd->dd_tech,TKGATE_DEFAULT_TECH) != 0)
790 message(1,"No 'default' delay definition found for primitive '%s'.",gi->name);
791 }
792 }
793
794 DoTcl("ToolBar::resetTechList");
795 }
796
797 /*****************************************************************************
798 *
799 * Called to do final tkgate initilization (called from tcl script)
800 *
801 *****************************************************************************/
TkGate_init(Tcl_Interp * tcl)802 void TkGate_init(Tcl_Interp *tcl)
803 {
804 int i;
805
806 TkGate_initDelay();
807
808 sel_updateMenuState();
809
810 LogCopyright();
811
812 /*
813 * Load first file on command line. If the load fails, treat this as a new
814 * circuit using the specified file.
815 */
816 if (numLoads > 0) {
817 const char *result;
818
819 DoTclL("gat_load",loadList[0],NULL);
820 result = Tcl_GetStringResult(tcl);
821 if (*result == '0')
822 DoTclL("gat_new",loadList[0],"main",NULL);
823 }
824
825 if (numLoads == 0)
826 DoTcl("File::loadWelcomeCircuit");
827
828
829 /*
830 * Load modules from additional files as libraries
831 */
832 for (i = 1;i < numLoads;i++) {
833 DoTclL("gat_loadMore",loadList[i],NULL);
834 }
835 for (i = 0;i < numLibLoads;i++) {
836 DoTclL("gat_loadLibrary",libLoadList[i],NULL);
837 }
838
839
840 /*
841 * Open the root module in the module tree list.
842 */
843 DoTcl("BlockTree::openRoot");
844
845 free(libLoadList);
846 free(loadList);
847
848 guiActive = 1;
849
850 if (start_sim) {
851 if (sim_script)
852 Tcl_SetVar(TkGate.tcl,"sopts_simInitScript",sim_script,TCL_GLOBAL_ONLY);
853 tkgate_setMajorMode(MM_SIMULATE);
854 }
855
856
857 /*
858 * If a print file has been specified. Print the file and exit tkgate.
859 */
860 if (print_file) {
861 DoTcl("tkg_printWithDefaults 1 %s",print_file);
862 exit(0);
863 }
864
865 /*
866 * If a printer has been specified. Print to specified printer and
867 * exit tkgate.
868 */
869 if (print_printer) {
870 DoTcl("tkg_printWithDefaults 0 %s",print_printer);
871 exit(0);
872 }
873
874 bader_check();
875 tkgate_signalSetup(); /* set traps on signals */
876 }
877
878 /*****************************************************************************
879 *
880 * Look for the tutorials based on the current locale, or fall back on the
881 * English locale tutorials if they can not be located.
882 *
883 *****************************************************************************/
init_tutorials(Tcl_Interp * tcl)884 void init_tutorials(Tcl_Interp *tcl)
885 {
886 char buf[STRMAX];
887 const char *lang = Tcl_GetVar(tcl,"lang",TCL_GLOBAL_ONLY);
888 struct stat sb;
889
890 sprintf(buf,"%s/locale/%s/tutorials",TkGate.homedir,lang);
891 if (stat(buf,&sb) || ((sb.st_mode & S_IFMT) != S_IFDIR)) {
892 sprintf(buf,"%s/locale/en/tutorials",TkGate.homedir);
893 printf("[No tutorials found for locale '%s'. Using English tutorials.]\n",lang);
894 if (stat(buf,&sb) || ((sb.st_mode & S_IFMT) != S_IFDIR)) {
895 printf("[No tutorials found for English either'. Help!]\n");
896 exit(1);
897 }
898 }
899
900 tkgate_tutorialdir = ob_strdup(buf);
901 Tcl_SetVar(tcl,"tkgate_tutorialdir",buf,TCL_GLOBAL_ONLY);
902
903 sprintf(buf,"%s/locale/%s/examples",TkGate.homedir,lang);
904 if (stat(buf,&sb) || ((sb.st_mode & S_IFMT) != S_IFDIR)) {
905 sprintf(buf,"%s/locale/en/examples",TkGate.homedir);
906 printf("[No examples found for locale '%s'. Using English examples.]\n",lang);
907 if (stat(buf,&sb) || ((sb.st_mode & S_IFMT) != S_IFDIR)) {
908 printf("[No examples found for English either'. Help!]\n");
909 exit(1);
910 }
911 }
912
913 tkgate_exampledir = ob_strdup(buf);
914 Tcl_SetVar(tcl,"tkgate_exampledir",buf,TCL_GLOBAL_ONLY);
915 }
916
917 /*****************************************************************************
918 *
919 * Initialize the application description object to all zeros.
920 *
921 *****************************************************************************/
init_TkGate()922 void init_TkGate()
923 {
924 memset(&TkGate,0,sizeof(TkGate));
925 TkGate.libraries = new_SHash();
926 TkGate.homedir = tkgateHomeDir;
927 }
928
929 /*****************************************************************************
930 *
931 * Create a new current file object
932 *
933 *****************************************************************************/
new_CurrentFile()934 CurrentFile *new_CurrentFile()
935 {
936 CurrentFile *cf = (CurrentFile*)ob_malloc(sizeof(CurrentFile),"CurrentFile");
937
938 cf->baseName = ob_strdup("");
939 cf->dirName = ob_strdup("");
940 cf->fullPathName = ob_strdup("");
941
942 return cf;
943 }
944
945 /*****************************************************************************
946 *
947 * Convert a file path name to a full path name.
948 *
949 * Parameters:
950 * ipath Specified path name (full or relative)
951 * rpath Return for full path name
952 *
953 *****************************************************************************/
canonical_path(const char * ipath,char * rpath)954 char *canonical_path(const char *ipath,char *rpath)
955 {
956 char *p;
957
958 /*
959 * If no leading '/', look up the current directory and append it to the file name.
960 */
961 if (*ipath == '/') {
962 strcpy(rpath, ipath);
963 } else {
964 char cwd[PATH_MAX];
965
966 if (!getcwd(cwd,PATH_MAX))
967 return NULL;
968 sprintf(rpath,"%s/%s",cwd,ipath);
969 }
970
971 /*
972 * Replace any // with /
973 */
974 while ((p = strstr(rpath,"//"))) {
975 memmove(p,p+1,strlen(p+1)+1);
976 }
977
978 /*
979 * Handle any
980 */
981 while ((p = strstr(rpath,"/../"))) {
982 if (p == rpath)
983 memmove(p,p+3,strlen(p+3)+1);
984 else {
985 char *q;
986
987 for (q = p-1;q > rpath;q--)
988 if (*q == '/') break;
989
990 memmove(q,p+3,strlen(p+3)+1);
991 }
992 }
993
994 while ((p = strstr(rpath,"/./"))) {
995 memmove(p,p+2,strlen(p+2)+1);
996 }
997
998 return rpath;
999 }
1000
1001 /*****************************************************************************
1002 *
1003 * Change the file name in a current file object.
1004 *
1005 * Parameters:
1006 * cf Current file object to set
1007 * name Name of file.
1008 *
1009 *****************************************************************************/
CurrentFile_set(CurrentFile * cf,const char * name)1010 int CurrentFile_set(CurrentFile *cf,const char *name)
1011 {
1012 char full_path[PATH_MAX];
1013 char *base_point;
1014
1015 ob_touch(cf);
1016
1017 if (!canonical_path(name, full_path))
1018 return -1;
1019
1020 base_point = strrchr(full_path,'/');
1021 if (!base_point && base_point[1]) /* There is a '/' and there are chars after it */
1022 return -1;
1023
1024 ob_free(cf->fullPathName);
1025 ob_free(cf->dirName);
1026 ob_free(cf->baseName);
1027
1028 cf->fullPathName = ob_strdup(full_path);
1029 cf->dirName = ob_strdup(full_path);
1030 cf->dirName[base_point-full_path] = 0;
1031 cf->baseName = ob_strdup(base_point+1);
1032
1033 if (TkGate.tcl) {
1034 Tcl_SetVar(TkGate.tcl,"tkg_currentFile",cf->fullPathName,TCL_GLOBAL_ONLY);
1035 }
1036
1037 return 0;
1038 }
1039
init_tk(Tcl_Interp * tcl)1040 static void init_tk(Tcl_Interp *tcl)
1041 {
1042 int r;
1043
1044 /*
1045 * Start up Tk
1046 */
1047 r = Tk_Init(tcl);
1048 if (r == TCL_ERROR) {
1049 fprintf(stderr,"Tk_Init Error in tkgate:\n%s\n",Tcl_GetStringResult(tcl));
1050 fprintf(stderr,"Perhaps you could try setting the environment variable TK_LIBRARY\n");
1051 fprintf(stderr,"to the directory in which tk init files can be found. You can also\n");
1052 fprintf(stderr,"set TK_LIBRARY in options.h.\n");
1053 exit(1);
1054 }
1055 }
1056
1057 /*****************************************************************************
1058 *
1059 * This is the beginning of the tkgate initialization
1060 *
1061 *****************************************************************************/
tkgate_main(ClientData _d,Tcl_Interp * tcl,int argc,const char * argv[])1062 static int tkgate_main(ClientData _d,Tcl_Interp *tcl,int argc,const char *argv[])
1063 {
1064 parse_options(argc,argv); /* Parse the command line options */
1065
1066 init_TkGate(); /* tkgate "main" object */
1067 ob_init(); /* Object memory handeling */
1068 init_gateHashTables(); /* Hash tables for gates */
1069 init_tclProcs(tcl); /* install tkgate tcl commands */
1070 init_localeSet(); /* Get set of supported locales, and set English as default */
1071 init_iconTables(); /* Tables for storing icons */
1072 init_cpathNetDelayTable(); /* Initialize delay tables for critical path analysis */
1073
1074 localization_Setup(tcl); /* Set up for the selected locale */
1075 if (verify_only) /* Do verify and exit if we had the -V switch */
1076 doVerifyLoad();
1077 if (print_file || print_printer) /* Print file and exit if we have the -p or -P switches */
1078 commandLinePrint();
1079 if (!quietMode) /* Print the copyright notice (unless we are in quiet mode) */
1080 PrintCopyright();
1081
1082 return TCL_OK;
1083 }
1084
tkgate_starttk(ClientData _d,Tcl_Interp * tcl,int argc,const char * argv[])1085 static int tkgate_starttk(ClientData _d,Tcl_Interp *tcl,int argc,const char *argv[])
1086 {
1087 init_tk(tcl);
1088 return TCL_OK;
1089 }
1090
tkgate_posttk(ClientData _d,Tcl_Interp * tcl,int argc,const char * argv[])1091 static int tkgate_posttk(ClientData _d,Tcl_Interp *tcl,int argc,const char *argv[])
1092 {
1093 init_tutorials(tcl); /* Set up tutorials for selected locale. */
1094 init_mainWindow(tcl); /* The main window for all your editing needs */
1095 init_linkvars(tcl); /* bindings between tcl and C variables */
1096 init_cursors(); /* various mouse cursors we need*/
1097 init_specials(); /* special images that we need (arrows, etc.) */
1098 init_gates(); /* initialized built-in component types */
1099
1100 return TCL_OK;
1101 }
1102
1103 /*****************************************************************************
1104 *
1105 * Register the main proceedure for tkgate
1106 *
1107 *****************************************************************************/
Tkgate_Init(Tcl_Interp * tcl)1108 int Tkgate_Init(Tcl_Interp *tcl)
1109 {
1110 Tk_Init(tcl);
1111 Tcl_CreateCommand(tcl,"tkgate_main",tkgate_main,0,0);
1112 Tcl_CreateCommand(tcl,"tkgate_starttk",tkgate_starttk,0,0);
1113 Tcl_CreateCommand(tcl,"tkgate_posttk",tkgate_posttk,0,0);
1114 return 0;
1115 }
1116