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