1 /*
2  * main.c --
3  *
4  * The topmost module of the Magic VLSI tool.  This module
5  * initializes the other modules and then calls the 'textio'
6  * module to read and execute commands.
7  *
8  *     *********************************************************************
9  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
10  *     * Permission to use, copy, modify, and distribute this              *
11  *     * software and its documentation for any purpose and without        *
12  *     * fee is hereby granted, provided that the above copyright          *
13  *     * notice appear in all copies.  The University of California        *
14  *     * makes no representations about the suitability of this            *
15  *     * software for any purpose.  It is provided "as is" without         *
16  *     * express or implied warranty.  Export of this software outside     *
17  *     * of the United States of America may require an export license.    *
18  *     *********************************************************************
19  */
20 
21 #ifndef lint
22 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/utils/main.c,v 1.2 2008/02/07 17:33:19 tim Exp $";
23 #endif  /* not lint */
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include <sys/types.h>
30 #include <sys/times.h>
31 #include <sys/time.h>
32 
33 #include "tcltk/tclmagic.h"
34 #include "utils/main.h"
35 #include "utils/magic.h"
36 #include "utils/malloc.h"
37 #include "utils/magsgtty.h"
38 #include "utils/hash.h"
39 #include "utils/macros.h"
40 #include "textio/textio.h"
41 #include "utils/geometry.h"
42 #include "textio/txcommands.h"
43 #include "tiles/tile.h"
44 #include "utils/tech.h"
45 #include "database/database.h"
46 #include "drc/drc.h"
47 #include "windows/windows.h"
48 #include "graphics/graphics.h"
49 #include "dbwind/dbwind.h"
50 #include "commands/commands.h"
51 #include "utils/signals.h"
52 #include "utils/utils.h"
53 #include "utils/runstats.h"
54 #include "cif/cif.h"
55 #ifdef ROUTE_MODULE
56 #include "router/router.h"
57 #endif
58 #ifdef LEF_MODULE
59 #include "lef/lef.h"
60 #endif
61 #include "extract/extract.h"
62 #include "utils/undo.h"
63 #include "netmenu/netmenu.h"
64 #include "plow/plow.h"
65 #include "utils/paths.h"
66 #include "wiring/wiring.h"
67 #ifdef PLOT_MODULE
68 #include "plot/plot.h"
69 #endif
70 #include "sim/sim.h"
71 #include "utils/list.h"
72 #ifdef ROUTE_MODULE
73 #include "mzrouter/mzrouter.h"
74 #endif
75 #include "lisp/lisp.h"
76 #ifdef THREE_D
77 #include "graphics/wind3d.h"
78 #endif
79 
80 
81 /*
82  * Global data structures
83  *
84  */
85 
86 global char	*Path = NULL;		/* Search path */
87 global char	*CellLibPath = NULL;	/* Used to find cells. */
88 global char	*SysLibPath = NULL;	/* Used to find color maps, styles, */
89 					/* technologies, etc. */
90 
91 /*
92  * Flag that tells if various options have been set on the command line
93  * (see utils.h for explanation of individual flags).
94  */
95 
96 global short RuntimeFlags = MAIN_MAKE_WINDOW;
97 
98 /*
99  * See the file main.h for a description of the information kept
100  * pertaining to the edit cell.
101  */
102 
103 global CellUse	*EditCellUse = NULL;
104 global CellDef	*EditRootDef = NULL;
105 global Transform EditToRootTransform;
106 global Transform RootToEditTransform;
107 
108 
109 /*
110  * data structures local to main.c
111  *
112  */
113 
114 /* the filename specified on the command line */
115 static char *MainFileName = NULL;
116 
117 /* RC file specified on the command line */
118 static char *RCFileName = NULL;
119 
120 /* Definition of file types that magic can read */
121 #define FN_MAGIC_DB	0
122 #define FN_LEF_FILE	1
123 #define FN_DEF_FILE	2
124 #define FN_GDS_FILE	3
125 #define FN_CIF_FILE	4
126 #define FN_TCL_SCRIPT	5
127 
128 /* List of filenames specified on the command line */
129 typedef struct filename {
130     char *fn;
131     unsigned char fn_type;
132     struct filename *fn_prev;
133 } FileName;
134 FileName *CurrentName;
135 
136 /* tech name specified on the command line */
137 static char *TechDefault = NULL;
138 
139 /* the filename for the graphics and mouse ports */
140 global char *MainGraphicsFile = NULL;
141 global char *MainMouseFile = NULL;
142 
143 /* information about the color display. */
144 global char *MainDisplayType = NULL;
145 global char *MainMonType = NULL;
146 
147 
148 /* Copyright notice for the binary file. */
149 global char *MainCopyright = "\n--- MAGIC: Copyright (C) 1985, 1990 "
150 		"Regents of the University of California.  ---\n";
151 
152 /* Forward declarations */
153 char *mainArg();
154 
155 
156 /*
157  * ----------------------------------------------------------------------------
158  * MainExit:
159  *
160  *	Magic's own exit procedure
161  *
162  * Results:
163  *	None.
164  *
165  * Side effects:
166  *	We exit.
167  * ----------------------------------------------------------------------------
168  */
169 
170 void
MainExit(errNum)171 MainExit(errNum)
172     int errNum;
173 {
174 #ifdef	MOCHA
175     MochaExit(errNum);
176 #endif
177     if (GrClosePtr != NULL) /* We are not guarenteed that everthing will
178 			     * be initialized already!
179 			     */
180 	GrClose();
181 
182     DBRemoveBackup();
183 
184     TxFlush();
185     TxResetTerminal();
186 
187 #ifdef MAGIC_WRAPPER
188 
189     // NOTE:  This needs to be done in conjunction with the following
190     // commands in the console:
191     // (1) tkcon eval rename ::exit ::quit
192     // (2) tkcon eval proc::exit args {slave eval quit}
193     //
194     // The lines above redirect tkcon's "exit" routine to be named
195     // "quit" (in the console, not the slave!).  Because the tkcon
196     // File->Exit callback is set to eval "exit", we then can create
197     // a new proc called "exit" in the console that runs "quit" in
198     // the slave (magic), and will therefore do the usual checks to
199     // save work before exiting;  if all responses are to exit without
200     // saving, then it finally gets to here, where it runs the (renamed)
201     // "quit" command in tkcon.  That will ensure that tkcon runs
202     // various cleanup activities such as saving the command-line
203     // history file before the final (!) exit.
204 
205     if (TxTkConsole)
206 	Tcl_Eval(magicinterp, "catch {tkcon eval quit}\n");
207 #endif
208 
209     exit(errNum);
210 }
211 
212 /*
213  * ----------------------------------------------------------------------------
214  *
215  * mainDoArgs:
216  *
217  *	Process command line arguments
218  *
219  * Results:
220  *	Return 0 on success, 1 on failure
221  *
222  * Side effects:
223  *	Global variables are modified
224  *
225  * Notes:
226  *	In order to work properly with the -F flag, we need to
227  *	use StrDup() to make copies of any arguments we want
228  *	to be visible when we restart a frozen file.
229  *
230  * ----------------------------------------------------------------------------
231  */
232 
233 int
mainDoArgs(argc,argv)234 mainDoArgs(argc, argv)
235     int argc;
236     char **argv;
237 {
238     bool haveDashI = FALSE;
239     char *cp;
240 
241     /* Startup filename (may be changed with the "-rcfile" option or	*/
242     /* the "-norcfile" option).						*/
243 
244     RCFileName = StrDup((char **) NULL, ".magicrc");
245 
246     while (--argc > 0)
247     {
248 	argv++;
249 	if (**argv == '-')
250 	{
251 	    switch (argv[0][1])
252 	    {
253 		case 'g':
254 		    if ((cp = mainArg(&argc, &argv, "tty name")) == NULL)
255 			return 1;
256 		    MainGraphicsFile = StrDup((char **) NULL, cp);
257 		    if (!haveDashI)
258 			MainMouseFile = MainGraphicsFile;
259 		    break;
260 
261 		case 'i':
262 		    haveDashI = TRUE;
263 		    if ((cp = mainArg(&argc, &argv, "tty name")) == NULL)
264 			return 1;
265 		    MainMouseFile = StrDup((char **) NULL, cp);
266 		    break;
267 
268 		case 'd':
269 		    if ((cp = mainArg(&argc, &argv, "display type")) ==NULL)
270 			return 1;
271 		    MainDisplayType = StrDup((char **) NULL, cp);
272 		    break;
273 
274 		case 'm':
275 		    if ((cp = mainArg(&argc, &argv, "monitor type")) ==NULL)
276 			return 1;
277 		    MainMonType = StrDup((char **) NULL, cp);
278 		    break;
279 
280 		/*
281 		 * Declare the technology.
282 		 */
283 		case 'T':
284 		    if ((cp = mainArg(&argc, &argv, "technology")) == NULL)
285 			return 1;
286 		    TechDefault = StrDup((char **) NULL, cp);
287 		    TechOverridesDefault = TRUE;
288 		    break;
289 
290 		/*
291 		 * -r or -re or -recover: Recover a crash file.
292 		 * -rc or -rcfile: Declare a specific startup file to read.
293 		 */
294 		case 'r':
295 		    if ((strlen(argv[0]) <= 2) || argv[0][2] == 'e')
296 			RuntimeFlags |= MAIN_RECOVER;
297 		    else if ((argc > 1) && (argv[0][2] == 'c'))
298 		    {
299 			argv[0][2] = '\0';
300 		        if ((cp = mainArg(&argc, &argv, "startup file")) == NULL)
301 			    return 1;
302 			RCFileName = StrDup((char **) NULL, cp);
303 		    }
304 		    else
305 		    {
306 			TxError("Unknown option: '%s'\n", *argv);
307 			return 1;
308 		    }
309 		    break;
310 
311 		/*
312 		 * We are being debugged.
313 		 */
314 		case 'D':
315 		    RuntimeFlags |= MAIN_DEBUG;
316 		    break;
317 
318 #ifdef MAGIC_WRAPPER
319 		/*
320 		 * "-w" for wrapper * implies -nowindow (no initial window)
321 		 */
322 		case 'w':
323 		    RuntimeFlags &= ~MAIN_MAKE_WINDOW;
324 		    break;
325 		/*
326 		 * No initial window / no console options / no startup file read.
327 		 */
328 		case 'n':
329 		    if (strlen(argv[0]) < 4)
330 		    {
331 			TxError("Ambiguous option %s:  use -nowindow, -noconsole, "
332 				"or -norcfile\n", argv[0]);
333 			return 1;
334 		    }
335 		    else if (argv[0][3] == 'c')
336 			RuntimeFlags &= ~MAIN_TK_CONSOLE;
337 		    else if (argv[0][3] == 'w')
338 			RuntimeFlags &= ~MAIN_MAKE_WINDOW;
339 		    else if (argv[0][3] == 'r')
340 		    {
341 			freeMagic(RCFileName);
342 			RCFileName = NULL;
343 		    }
344 		    else
345 		    {
346 			TxError("Unknown option: '%s'\n", *argv);
347 			return 1;
348 		    }
349 		    break;
350 #endif
351 		default:
352 		    TxError("Unknown option: '%s'\n", *argv);
353 		    TxError("Usage:  magic [-g gPort] [-d devType] [-m monType] "
354 				"[-i tabletPort] [-D] [-F objFile saveFile]\n"
355 				"[-T technology] [-rcfile startupFile | -norcfile]"
356 #ifdef MAGIC_WRAPPER
357 				"[-noconsole] [-nowindow] [-wrapper] "
358 #endif
359 				"[file]\n");
360 		    return 1;
361 	    }
362 	}
363 	else if (MakeMainWindow)
364 	{
365 	    if (MainFileName == NULL) {
366 		MainFileName = StrDup((char **) NULL, *argv);
367 		CurrentName = (FileName *) mallocMagic(sizeof(FileName));
368 		CurrentName->fn = MainFileName;
369 		CurrentName->fn_prev = (FileName *) NULL;
370 		CurrentName->fn_type = FN_MAGIC_DB;
371 	    }
372 	    else
373 	    {
374 		FileName *temporary;
375 
376 		temporary = (FileName *) mallocMagic(sizeof(FileName));
377 		temporary->fn = StrDup((char **) NULL, *argv);
378 		temporary->fn_prev = CurrentName;
379 		temporary->fn_type = FN_MAGIC_DB;
380 		CurrentName = temporary;
381 	    }
382 
383 	    /* Remove suffix if the file name already has it */
384 	    {
385 		char *c,*d;
386 
387 		for(c = CurrentName->fn; (*c) != '\0'; c++);
388 		for(d = DBSuffix; (*d) != '\0'; d++);
389 		while( (*c) == (*d) ) {
390 		    if (c == MainFileName) break;
391 		    if (d == DBSuffix) {
392 			(*c) = '\0';
393 			break;
394 		    }
395 		    c--;
396 		    d--;
397 		}
398 
399 		// Additional checks
400 		if ((c = strrchr(CurrentName->fn, '.')) != NULL)
401 		{
402 #ifdef LEF_MODULE
403 		    if (!strcasecmp(c, ".lef"))
404 			CurrentName->fn_type = FN_LEF_FILE;
405 		    else if (!strcasecmp(c, ".def"))
406 			CurrentName->fn_type = FN_DEF_FILE;
407 #endif
408 #ifdef CIF_MODULE
409 		    if (!strcasecmp(c, ".cif"))
410 			CurrentName->fn_type = FN_CIF_FILE;
411 		    else if (!strncasecmp(c, ".gds", 3))
412 			CurrentName->fn_type = FN_GDS_FILE;
413 #endif
414 #ifdef MAGIC_WRAPPER
415 		    if (!strcasecmp(c, ".tcl"))
416 		    {
417 			CurrentName->fn_type = FN_TCL_SCRIPT;
418 			/* Behavior:  If a .tcl file is passed on the
419 			 * command line, then all following arguments
420 			 * are assumed to be arguments of the script,
421 			 * and not to be processed as additional
422 			 * input file types.
423 			 */
424 			break;
425 		    }
426 #endif
427 		}
428 	    }
429 	}
430     }
431 
432     return 0;
433 }
434 
435 /*
436  * ----------------------------------------------------------------------------
437  *
438  * mainArg --
439  *
440  * Pull off an argument from the (argc, argv) pair and also check
441  * to make sure it's not another flag (i.e, it doesn't begin with
442  * a '-').
443  *
444  * Results:
445  *	Return pointer to the argument string.
446  *
447  * Side effects:
448  *	See the comments in ArgStr() in the utils module -- they
449  *	apply here.
450  *
451  * ----------------------------------------------------------------------------
452  */
453 
454 char *
mainArg(pargc,pargv,mesg)455 mainArg(pargc, pargv, mesg)
456     int *pargc;
457     char ***pargv;
458     char *mesg;
459 {
460     char option, *cp;
461 
462     option = (*pargv)[0][1];
463     cp = ArgStr(pargc, pargv, mesg);
464     if (cp == NULL)
465 	return (char *) NULL;
466 
467     if (*cp == '-')
468     {
469 	TxError("Bad name after '-%c' option: '%s'\n", option, cp);
470 	return (char *) NULL;
471     }
472     return cp;
473 }
474 
475 
476 /*
477  * ----------------------------------------------------------------------------
478  * mainInitBeforeArgs:
479  *
480  *	Initializes things before argument processing.
481  *
482  * Results:
483  *	0 on success.  As written, there are no failure modes.
484  *
485  * Side effects:
486  *	All sorts of initialization.  Most initialization, however, is done
487  *	in 'mainInitAfterArgs'.
488  * ----------------------------------------------------------------------------
489  */
490 
491 int
mainInitBeforeArgs(argc,argv)492 mainInitBeforeArgs(argc, argv)
493     int argc;
494     char *argv[];
495 {
496     TechOverridesDefault = FALSE;
497     if (Path == NULL)
498 	Path = StrDup((char **) NULL, ".");
499 
500     /* initialize text display */
501     TxInit();
502     TxSetTerminal();
503 
504 #ifdef SCHEME_INTERPRETER
505     /* Initialize Lisp module. (rajit@cs.caltch.edu) */
506     LispInit();
507 #endif
508 
509     /*
510      * Get preliminary info on the graphics display.
511      * This may be overriden later.
512      */
513     GrGuessDisplayType(&MainGraphicsFile, &MainMouseFile,
514 	&MainDisplayType, &MainMonType);
515     FindDisplay((char *)NULL, "displays", CAD_LIB_PATH, &MainGraphicsFile,
516 	&MainMouseFile, &MainDisplayType, &MainMonType);
517 
518     return 0;
519 }
520 
521 
522 /*
523  * ----------------------------------------------------------------------------
524  * mainInitAfterArgs:
525  *
526  *	Initializes things after argument processing.
527  *
528  * Results:
529  *	Status: 0 = success, 1 = failure to set graphics display,
530  *	2 = failure to load technology file.
531  *
532  * Side effects:
533  *	All sorts of initialization.
534  * ----------------------------------------------------------------------------
535  */
536 
537 int
mainInitAfterArgs()538 mainInitAfterArgs()
539 {
540     int (*nullProc)() = 0;
541     SectionID sec_tech, sec_planes, sec_types, sec_aliases;
542     SectionID sec_styles;
543     SectionID sec_connect, sec_contact, sec_compose;
544     SectionID sec_cifinput, sec_cifoutput;
545     SectionID sec_drc, sec_extract, sec_wiring, sec_router;
546     SectionID sec_plow, sec_plot, sec_mzrouter;
547 
548     DBTypeInit();
549     MacroInit();
550 
551 #ifdef LEF_MODULE
552     /* Pre-techfile-loading intialization of the LEF module */
553     LefInit();
554 #endif
555 
556 #ifdef OPENACCESS
557     OAInit();
558 #endif
559 
560     /*
561      * Setup path names for system directory searches
562      */
563 
564     StrDup(&SysLibPath, MAGIC_SYS_PATH);
565 
566     /*
567      * Historic behavior:  Expect to search for cells in a directory
568      * inside the install area with the same name as the technology.
569      * Deprecated but kept for backwards compatibility.  If directory
570      * does not exist, it will be ignored.
571      */
572 
573     if (TechFileName != NULL)
574     {
575 	CellLibPath = (char *)mallocMagic(strlen(MAGIC_LIB_PATH_FORMAT)
576 		+ strlen(TechFileName) - 1);
577 	sprintf(CellLibPath, MAGIC_LIB_PATH_FORMAT, TechFileName);
578 	PaAppend(&CellLibPath, MAGIC_LIB_PATH_DEFAULT);
579     }
580     else if ((TechDefault != NULL) && TechOverridesDefault)
581     {
582 	CellLibPath = (char *)mallocMagic(strlen(MAGIC_LIB_PATH_FORMAT)
583 		+ strlen(TechDefault) - 1);
584 	sprintf(CellLibPath, MAGIC_LIB_PATH_FORMAT, TechDefault);
585 	PaAppend(&CellLibPath, MAGIC_LIB_PATH_DEFAULT);
586     }
587     else
588 	StrDup(&CellLibPath, MAGIC_LIB_PATH_DEFAULT);
589 
590     if (MainGraphicsFile == NULL) MainGraphicsFile = "/dev/null";
591     if (MainMouseFile == NULL) MainMouseFile = MainGraphicsFile;
592 
593 #ifdef MAGIC_WRAPPER
594     /* Check for batch mode operation and disable interrupts in	*/
595     /* batch mode by not calling SigInit().			*/
596     if (Tcl_GetVar(magicinterp, "batch_mode", TCL_GLOBAL_ONLY) != NULL)
597 	SigInit(1);
598     else
599 #endif
600 
601     /* catch signals, must come after mainDoArgs & before SigWatchFile */
602     SigInit(0);
603 
604     /* set up graphics */
605     if ( !GrSetDisplay(MainDisplayType, MainGraphicsFile, MainMouseFile) )
606     {
607 	return 1;
608     }
609 
610     /* initialize technology */
611     TechInit();
612     TechAddClient("tech", DBTechInit, DBTechSetTech, nullProc,
613 			(SectionID) 0, &sec_tech, FALSE);
614     TechAddClient("version", DBTechInitVersion, DBTechSetVersion, nullProc,
615 			(SectionID) 0, (int *)0, TRUE);
616     TechAddClient("planes",	DBTechInitPlane, DBTechAddPlane, nullProc,
617 			(SectionID) 0, &sec_planes, FALSE);
618     TechAddClient("types", DBTechInitType, DBTechAddType, DBTechFinalType,
619 			sec_planes, &sec_types, FALSE);
620 
621     TechAddClient("styles", nullProc, DBWTechAddStyle, nullProc,
622 			sec_types, &sec_styles, FALSE);
623 
624     TechAddClient("contact", DBTechInitContact,
625 			DBTechAddContact, DBTechFinalContact,
626 			sec_types|sec_planes, &sec_contact, FALSE);
627 
628     TechAddAlias("contact", "images");
629     TechAddClient("aliases", nullProc, DBTechAddAlias, nullProc,
630 			sec_planes|sec_types|sec_contact, &sec_aliases, TRUE);
631 
632     TechAddClient("compose", DBTechInitCompose,
633 			DBTechAddCompose, DBTechFinalCompose,
634 			sec_types|sec_planes|sec_contact, &sec_compose, FALSE);
635 
636     TechAddClient("connect", DBTechInitConnect,
637 			DBTechAddConnect, DBTechFinalConnect,
638 			sec_types|sec_planes|sec_contact, &sec_connect, FALSE);
639 
640 #ifdef CIF_MODULE
641     TechAddClient("cifoutput", CIFTechStyleInit, CIFTechLine, CIFTechFinal,
642 			(SectionID) 0, &sec_cifoutput, FALSE);
643 
644     TechAddClient("cifinput", CIFReadTechStyleInit, CIFReadTechLine,
645 		    CIFReadTechFinal, (SectionID) 0, &sec_cifinput, FALSE);
646 #else
647     TechAddClient("cifoutput", nullProc,nullProc,nullProc,
648 			(SectionID) 0, &sec_cifoutput, FALSE);
649 
650     TechAddClient("cifinput", nullProc,nullProc,nullProc,
651 		     (SectionID) 0, &sec_cifinput, FALSE);
652 #endif
653 #ifdef ROUTE_MODULE
654     TechAddClient("mzrouter", MZTechInit, MZTechLine, MZTechFinal,
655 			sec_types|sec_planes, &sec_mzrouter, TRUE);
656 #else
657     TechAddClient("mzrouter", nullProc,nullProc,nullProc,
658 			sec_types|sec_planes, &sec_mzrouter, TRUE);
659 #endif
660     TechAddClient("drc", DRCTechStyleInit, DRCTechLine, DRCTechFinal,
661 			sec_types|sec_planes, &sec_drc, FALSE);
662     /* Plow rules are generated from the same lines as the DRC rules */
663     TechAddClient("drc", PlowDRCInit, PlowDRCLine, PlowDRCFinal,
664 			sec_types|sec_planes, &sec_drc, FALSE);
665 
666 #ifdef LEF_MODULE
667     TechAddClient("lef", LefTechInit, LefTechLine, nullProc,
668 			sec_types|sec_planes, (SectionID *) 0, TRUE);
669 #endif
670 
671 #ifdef NO_EXT
672     TechAddClient("extract", nullProc, nullProc,nullProc,
673 			sec_types|sec_connect, &sec_extract, FALSE);
674 #else
675     TechAddClient("extract", nullProc, ExtTechLine, ExtTechFinal,
676 			sec_types|sec_connect, &sec_extract, FALSE);
677 #endif
678 
679     TechAddClient("wiring", WireTechInit, WireTechLine, WireTechFinal,
680 			sec_types, &sec_wiring, TRUE);
681 
682 #ifdef ROUTE_MODULE
683     TechAddClient("router", RtrTechInit, RtrTechLine, RtrTechFinal,
684 			sec_types, &sec_router, TRUE);
685 #else
686     TechAddClient("router", nullProc,nullProc,nullProc,
687 			sec_types, &sec_router, TRUE);
688 #endif
689     TechAddClient("plowing", PlowTechInit, PlowTechLine, PlowTechFinal,
690 			sec_types|sec_connect|sec_contact, &sec_plow, TRUE);
691 #ifdef PLOT_MODULE
692     TechAddClient("plot", PlotTechInit, PlotTechLine, PlotTechFinal,
693 			sec_types, &sec_plot, TRUE);
694 #else
695     TechAddClient("plot", nullProc,nullProc,nullProc,
696 			sec_types, &sec_plot, TRUE);
697 #endif
698 
699     /* Load minimum technology file needed to keep things from	*/
700     /* crashing during initialization.				*/
701 
702     if (!TechLoad("minimum", 0))
703     {
704 	TxError("Cannot load technology \"minimum\" for initialization\n");
705 	return 2;
706     }
707 
708     /* The minimum tech has been loaded only to keep the database from	*/
709     /* becoming corrupted during initialization.  Free the tech file	*/
710     /* name so that a "real" technology file can be forced to replace	*/
711     /* it in mainInitFinal().						*/
712 
713     if (TechFileName != NULL)
714     {
715 	freeMagic(TechFileName);
716 	TechFileName = NULL;
717     }
718 
719     /* initialize the undo package */
720     (void) UndoInit((char *) NULL, (char *) NULL);
721 
722     /* initialize windows */
723     WindInit();
724 
725     /* initialize commands */
726     CmdInit();
727 
728     /* Initialize the interface between windows and its clients */
729     DBWinit();
730 #ifdef USE_READLINE
731     TxInitReadline();
732 #endif
733     CMWinit();
734 #ifdef THREE_D
735     W3Dinit();
736 #endif
737 
738     /* Initialize the circuit extractor */
739 #ifndef NO_EXT
740     ExtInit();
741 #endif
742 
743     /* Initialize plowing */
744     PlowInit();
745 
746     /* Initialize selection */
747     SelectInit();
748 
749     /* Initialize the wiring module */
750     WireInit();
751 
752 #ifdef ROUTE_MODULE
753     /* Initialize the netlist menu */
754     NMinit();
755 #endif
756 
757     /* Initialize the design-rule checker */
758     DRCInit();
759 
760     /* Initialize the maze router */
761 #ifdef ROUTE_MODULE
762     MZInit();
763 
764     /* Initialize the interactive router -
765      * NOTE the mzrouter must be initialized prior to the irouter
766      * so that default parameters will be completely setup
767      */
768     IRDebugInit();
769     IRAfterTech();
770 #endif
771 
772 	/* Initialize the Sim Module (the part of it which involves (i)rsim) */
773 #if !defined(NO_SIM_MODULE) && defined(RSIM_MODULE)
774     SimInit();
775 #endif
776 
777     TxSetPoint(GR_CURSOR_X, GR_CURSOR_Y, WIND_UNKNOWN_WINDOW);
778 
779     return 0;
780 }
781 
tcl_exit_hook(ClientData clientData)782 void tcl_exit_hook(ClientData clientData)
783 {
784     TxResetTerminal();
785     exit(0);
786 }
787 
788 /*
789  * ----------------------------------------------------------------------------
790  * mainInitFinal:
791  *
792  *	Final initialization; reads startup files and any initial file
793  *	specified.
794  *
795  * Results:
796  *	Return 0 on success.  As written, there is no failure mode.
797  *
798  * Side effects:
799  *	All sorts of initialization.
800  * ----------------------------------------------------------------------------
801  */
802 
803 int
mainInitFinal()804 mainInitFinal()
805 {
806     char *home, cwd[512];
807     char startupFileName[256];
808     FILE *f;
809     char *rname;
810     int result;
811 
812     /* Reset terminal if exit is called inside a TCL script */
813     Tcl_SetExitProc(tcl_exit_hook);
814 
815 #ifdef MAGIC_WRAPPER
816 
817     /* Read in system pre-startup file, if it exists. */
818 
819     /* Use PaOpen first to perform variable substitutions, and	*/
820     /* return the actual filename in rname.			*/
821 
822     f = PaOpen(MAGIC_PRE_DOT, "r", (char *) NULL, ".",
823 	    (char *) NULL, (char **) &rname);
824     if (f != NULL)
825     {
826 	fclose(f);
827 	result = Tcl_EvalFile(magicinterp, rname);
828 	if (result != TCL_OK)
829 	{
830 	    TxError("Error parsing pre-startup file \"%s\": %s\n", rname,
831 				Tcl_GetStringResult(magicinterp));
832 	    Tcl_ResetResult(magicinterp);
833 	}
834     }
835 #endif	/* MAGIC_WRAPPER */
836 
837     // Make a first attempt to load the technology if specified on the
838     // command line with the -T option.  This will preempt most other
839     // ways that the technology file is determined.  If the technology
840     // specified cannot be loaded, then the forced override is revoked.
841 
842     if ((TechFileName == NULL) && (TechDefault != NULL) && TechOverridesDefault)
843     {
844         if (!TechLoad(TechDefault, -2))
845 	{
846             TxError("Failed to load technology \"%s\"\n", TechDefault);
847 	    TechOverridesDefault = FALSE;
848 	}
849         else if (!TechLoad(TechDefault, 0))
850 	{
851             TxError("Error loading technology \"%s\"\n", TechDefault);
852 	    TechOverridesDefault = FALSE;
853 	}
854     }
855 
856 #ifndef MAGIC_WRAPPER
857 
858     // Let the wrapper script be responsible for formatting and
859     // printing the technology file informaiton.
860 
861     if (DBTechName != 0) {
862 	TxPrintf("Using technology \"%s\"", DBTechName);
863 	if (DBTechVersion != 0) TxPrintf(", version %s.", DBTechVersion);
864 	TxPrintf("\n");
865     }
866     if (DBTechDescription != 0) TxPrintf("%s\n", DBTechDescription);
867 #endif
868 
869 #ifdef MAGIC_WRAPPER
870     /* Read in system startup file, if it exists. */
871 
872     /* Use PaOpen first to perform variable substitutions, and	*/
873     /* return the actual filename in rname.			*/
874 
875     f = PaOpen(MAGIC_SYS_DOT, "r", (char *) NULL, ".",
876 	    (char *) NULL, (char **) &rname);
877     if (f != NULL)
878     {
879 	fclose(f);
880 	result = Tcl_EvalFile(magicinterp, rname);
881 	if (result != TCL_OK)
882 	{
883 	    TxError("Error parsing system startup file \"%s\": %s\n", rname,
884 				Tcl_GetStringResult(magicinterp));
885 	    Tcl_ResetResult(magicinterp);
886 	}
887     }
888 
889 #else /* !MAGIC_WRAPPER */
890 
891     f = PaOpen(MAGIC_SYS_DOT, "r", (char *) NULL, ".",
892 	    (char *) NULL, (char **) NULL);
893     if (f != NULL)
894     {
895 	TxDispatch(f);
896 	(void) fclose(f);
897     }
898 
899 #endif  /* !MAGIC_WRAPPER */
900 
901     /*
902      * Strive for a wee bit more parallelism; let the graphics
903      * display run while we're reading in startup files & initial cell.
904      */
905 
906     GrFlush();
907 
908     /* Ignore this whole section if we have received the -norc option */
909     if (RCFileName != NULL)
910     {
911 
912 	/* Read in user's startup files, if there are any. */
913 	/* If the "-rcfile" option has been used, and it doesn't specify   */
914 	/* a full path, then look for this file in the home directory too. */
915 
916 	home = getenv("HOME");
917 
918 #ifdef MAGIC_WRAPPER
919 
920 	if (home != NULL && (RCFileName[0] != '/'))
921 	{
922 	    Tcl_Channel fc;
923 
924 	    (void) sprintf(startupFileName, "%s/%s", home, RCFileName);
925 
926 	    fc = Tcl_OpenFileChannel(magicinterp, startupFileName, "r", 0);
927 	    if (fc != NULL)
928 	    {
929 		Tcl_Close(magicinterp, fc);
930 		result = Tcl_EvalFile(magicinterp, startupFileName);
931 		if (result != TCL_OK)
932 		{
933 		    TxError("Error parsing user \"%s\": %s\n", RCFileName,
934 				Tcl_GetStringResult(magicinterp));
935 		    Tcl_ResetResult(magicinterp);
936 		}
937 	    }
938 	    else
939 	    {
940 		/* Try the (deprecated) name ".magic" */
941 		(void) sprintf(startupFileName, "%s/.magic", home);
942 		fc = Tcl_OpenFileChannel(magicinterp, startupFileName, "r", 0);
943 		if (fc != NULL)
944 		{
945 		    TxPrintf("Note:  Use of the file name \"~/.magic\" is deprecated."
946 			"  Please change this to \"~/.magicrc\".\n");
947 
948 		    Tcl_Close(magicinterp, fc);
949 		    result = Tcl_EvalFile(magicinterp, startupFileName);
950 
951 		    if (result != TCL_OK)
952 		    {
953 			TxError("Error parsing user \".magic\": %s\n",
954 				Tcl_GetStringResult(magicinterp));
955 			Tcl_ResetResult(magicinterp);
956 		    }
957 		}
958 	    }
959 	}
960 
961         if (getcwd(cwd, 512) == NULL || strcmp(cwd, home) || (RCFileName[0] == '/'))
962 	{
963 	    /* Read in the .magicrc file from the current directory, if	*/
964 	    /* different from HOME.					*/
965 
966 	    Tcl_Channel fc;
967 
968 	    fc = Tcl_OpenFileChannel(magicinterp, RCFileName, "r", 0);
969 	    if (fc != NULL)
970 	    {
971 		Tcl_Close(magicinterp, fc);
972 		result = Tcl_EvalFile(magicinterp, RCFileName);
973 
974 		if (result != TCL_OK)
975 		{
976 		    // Print error message but continue anyway
977 
978 		    TxError("Error parsing \"%s\": %s\n", RCFileName,
979 				Tcl_GetStringResult(magicinterp));
980 		    Tcl_ResetResult(magicinterp);
981 		    TxPrintf("Bad local startup file \"%s\", continuing without.\n",
982 					RCFileName);
983 		}
984 	    }
985 	    else
986 	    {
987 		/* Try the (deprecated) name ".magic" */
988 
989 		Tcl_ResetResult(magicinterp);
990 		fc = Tcl_OpenFileChannel(magicinterp, ".magic", "r", 0);
991 		if (fc != NULL)
992 		{
993 		    Tcl_Close(magicinterp, fc);
994 
995 		    TxPrintf("Note:  Use of the file name \".magic\" is deprecated."
996 				"  Please change this to \".magicrc\".\n");
997 
998 		    result = Tcl_EvalFile(magicinterp, ".magic");
999 
1000 		    if (result != TCL_OK)
1001 		    {
1002 			// Print error message but continue anyway
1003 
1004 			TxError("Error parsing local \".magic\": %s\n",
1005 				Tcl_GetStringResult(magicinterp));
1006 			Tcl_ResetResult(magicinterp);
1007 			TxPrintf("Bad local startup file \".magic\","
1008 					" continuing without.\n");
1009 		    }
1010 		}
1011 		else
1012 		{
1013 		    /* Try the alternative name "magic_setup" */
1014 
1015 		    Tcl_ResetResult(magicinterp);
1016 
1017 		    fc = Tcl_OpenFileChannel(magicinterp, "magic_setup", "r", 0);
1018 		    if (fc != NULL)
1019 		    {
1020 			Tcl_Close(magicinterp, fc);
1021 
1022 			result = Tcl_EvalFile(magicinterp, "magic_setup");
1023 			if (result != TCL_OK)
1024 			{
1025 			    TxError("Error parsing local \"magic_setup\": %s\n",
1026 					Tcl_GetStringResult(magicinterp));
1027 			    TxError("%s\n", Tcl_GetStringResult(magicinterp));
1028 			    Tcl_ResetResult(magicinterp);	// Still not an error
1029 			    TxPrintf("Bad local startup file \"magic_setup\","
1030 					" continuing without.\n");
1031 			}
1032 		    }
1033 		}
1034 	    }
1035 	}
1036 
1037 #else /* !MAGIC_WRAPPER */
1038 
1039 	if (home != NULL && (RCFileName[0] != '/'))
1040 	{
1041 	    (void) sprintf(startupFileName, "%s/%s", home, RCFileName);
1042 
1043 
1044 	    f = PaOpen(startupFileName, "r", (char *) NULL, ".",
1045 		(char *) NULL, (char **) NULL);
1046 
1047 	    if ((f == NULL) && (!strcmp(RCFileName, ".magicrc")))
1048 	    {
1049 		/* Try the (deprecated) name ".magic" */
1050 		(void) sprintf(startupFileName, "%s/.magic", home);
1051 		f = PaOpen(startupFileName, "r", (char *) NULL, ".",
1052 		    (char *) NULL, (char **) NULL);
1053 		if (f != NULL)
1054 		    TxPrintf("Note:  Use of the file name \"~/.magic\" is deprecated."
1055 			"  Please change this to \"~/.magicrc\".\n");
1056 	    }
1057 
1058 	    if (f != NULL)
1059 	    {
1060 		TxDispatch(f);
1061 		(void) fclose(f);
1062 	    }
1063 	}
1064 
1065 	/* Read in any startup file in the current directory, or one that was	*/
1066 	/* specified on the commandline by the "-rcfile <name>" option.		*/
1067 
1068 	f = PaOpen(RCFileName, "r", (char *) NULL, ".",
1069 			(char *) NULL, (char **) NULL);
1070 
1071 	/* Again, check for the deprecated name ".magic" */
1072 	if (f == NULL)
1073 	{
1074 	    if (!strcmp(RCFileName, ".magicrc"))
1075 	    {
1076 		f = PaOpen(".magic", "r", (char *) NULL, ".",
1077 			(char *) NULL, (char **) NULL);
1078 		if (f != NULL)
1079 		    TxPrintf("Note:  Use of the file name \"./.magic\" is deprecated."
1080 				"  Please change this to \"./.magicrc\".\n");
1081 
1082 		else
1083 		    f = PaOpen("magic_setup", "r", (char *) NULL, ".",
1084 				(char *) NULL, (char **) NULL);
1085 	    }
1086 	    else
1087 		TxError("Startup file \"%s\" not found or unreadable!\n", RCFileName);
1088 	}
1089 
1090 	if (f != NULL)
1091 	{
1092 	    TxDispatch(f);
1093 	    fclose(f);
1094 	}
1095 
1096 #endif /* !MAGIC_WRAPPER */
1097 
1098     }
1099 
1100     /* We are done forcing the "tech load" command to be ignored */
1101     TechOverridesDefault = FALSE;
1102 
1103     /* If no technology has been specified yet, try to read one from
1104      * the initial cell, or else assign a default.
1105      */
1106 
1107     if ((TechFileName == NULL) && (TechDefault == NULL) && (MainFileName != NULL))
1108 	StrDup(&TechDefault, DBGetTech(MainFileName));
1109 
1110     /* Load the technology file.  If any startup file loaded a		*/
1111     /* technology file, then "TechFileName" will be set, and we		*/
1112     /* should not override it.						*/
1113 
1114     if ((TechFileName == NULL) && (TechDefault != NULL))
1115     {
1116         if (!TechLoad(TechDefault, -2))
1117             TxError("Failed to load technology \"%s\"\n", TechDefault);
1118         else if (!TechLoad(TechDefault, 0))
1119             TxError("Error loading technology \"%s\"\n", TechDefault);
1120     }
1121 
1122     if (TechDefault != NULL)
1123     {
1124 	freeMagic(TechDefault);
1125 	TechDefault = NULL;
1126     }
1127 
1128     /* If that failed, then load the "minimum" technology again and	*/
1129     /* keep it.  It's not very useful, but it will keep everything	*/
1130     /* up and running.  In the worst case, if site.pre has removed the	*/
1131     /* standard locations from the system path, then magic will exit.	*/
1132 
1133     if (TechFileName == NULL)
1134 	if (!TechLoad("minimum", 0))
1135 	    return -1;
1136 
1137 #ifdef SCHEME_INTERPRETER
1138     /* Pass technology name to Lisp interpreter (rajit@cs.caltech.edu) */
1139     LispSetTech (TechFileName);
1140 #endif
1141 
1142     /*
1143      * Recover crash files from the temp directory if we have specified
1144      * the -r option on the command line (non-tcl version.  Tcl version
1145      * uses the command-line command crashrecover.
1146      */
1147 
1148     if (mainRecover && MakeMainWindow)
1149     {
1150 	DBFileRecovery();
1151     }
1152 
1153     /*
1154      * Bring in a new cell or cells to start up if one was given
1155      * on the command line
1156      */
1157 
1158     else if (MainFileName && MakeMainWindow)
1159     {
1160 	FileName *temporary;
1161 
1162 	while(CurrentName != NULL)
1163 	{
1164 	    temporary = CurrentName;
1165 	    CurrentName = temporary->fn_prev;
1166 	    TxPrintf("Loading \"%s\" from command line.\n", temporary->fn);
1167 	    switch (temporary->fn_type)
1168 	    {
1169 		case FN_MAGIC_DB:
1170 		    DBWreload(temporary->fn);
1171 		    break;
1172 #ifdef LEF_MODULE
1173 		case FN_LEF_FILE:
1174 		    LefRead(temporary->fn, FALSE, FALSE);
1175 		    break;
1176 		case FN_DEF_FILE:
1177 		    DefRead(temporary->fn, FALSE);
1178 		    break;
1179 #endif
1180 #ifdef MAGIC_WRAPPER
1181 		case FN_TCL_SCRIPT:
1182 		    result = Tcl_EvalFile(magicinterp, temporary->fn);
1183 		    if (result != TCL_OK)
1184 		    {
1185 			TxError("Error parsing \"%s\": %s\n",
1186 				temporary->fn,
1187 				Tcl_GetStringResult(magicinterp));
1188 			Tcl_ResetResult(magicinterp);
1189 		    }
1190 		    break;
1191 #endif
1192 	    }
1193 	    freeMagic(temporary);
1194 	}
1195     }
1196 
1197     /* Create an initial box. */
1198 
1199     if (MakeMainWindow && EditCellUse)
1200 	DBWSetBox(EditCellUse->cu_def, &EditCellUse->cu_def->cd_bbox);
1201 
1202     /* Set the initial fence for undo-ing:  don't want to be able to
1203      * undo past this point.
1204      */
1205     UndoFlush();
1206     TxClearPoint();
1207 
1208     Tcl_SetExitProc(NULL);
1209 
1210     return 0;
1211 }
1212 
1213 
1214 /*
1215  * ----------------------------------------------------------------------------
1216  * mainFinish:
1217  *
1218  *	Finish up things for Magic.  This routine is NOT called on an
1219  *	error exit.
1220  *
1221  * Results:
1222  *	None.
1223  *
1224  * Side effects:
1225  *	Various things, such as stopping measurement gathering.
1226  * ----------------------------------------------------------------------------
1227  */
1228 
1229 void
mainFinished()1230 mainFinished()
1231 {
1232     /* Close up things */
1233     MainExit(0);
1234 }
1235 
1236 /*---------------------------------------------------------------------------
1237  * magicMain:
1238  *
1239  *	Top-level procedure of the Magic Layout System.  There is purposely
1240  *	not much in here so that we have more flexibility.  Also, it is
1241  *	not called 'main' so that other programs that use Magic may do
1242  *	something else.
1243  *
1244  * Results:
1245  *	None.
1246  *
1247  * Side Effects:
1248  *	None.
1249  *
1250  * Note:  Try not to add code to this procedure.  Add it instead to one of the
1251  *	procedures that it calls.
1252  *
1253  *----------------------------------------------------------------------------
1254  */
1255 
1256 void
magicMain(argc,argv)1257 magicMain(argc, argv)
1258     int argc;
1259     char *argv[];
1260 {
1261     int rstatus;
1262 
1263     if ((rstatus = mainInitBeforeArgs(argc, argv)) != 0) MainExit(rstatus);
1264     if ((rstatus = mainDoArgs(argc, argv)) != 0) MainExit(rstatus);
1265     if ((rstatus = mainInitAfterArgs()) != 0) MainExit(rstatus);
1266     if ((rstatus = mainInitFinal()) != 0) MainExit(rstatus);
1267     TxDispatch( (FILE *) NULL);
1268     mainFinished();
1269 }
1270 
1271 
1272 
1273