/* * main.c -- * * The topmost module of the Magic VLSI tool. This module * initializes the other modules and then calls the 'textio' * module to read and execute commands. * * ********************************************************************* * * Copyright (C) 1985, 1990 Regents of the University of California. * * * Permission to use, copy, modify, and distribute this * * * software and its documentation for any purpose and without * * * fee is hereby granted, provided that the above copyright * * * notice appear in all copies. The University of California * * * makes no representations about the suitability of this * * * software for any purpose. It is provided "as is" without * * * express or implied warranty. Export of this software outside * * * of the United States of America may require an export license. * * ********************************************************************* */ #ifndef lint 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 $"; #endif /* not lint */ #include #include #include #include #include #include #include #ifdef HAVE_SYS_TIME_H #include #endif #include "tcltk/tclmagic.h" #include "utils/main.h" #include "utils/magic.h" #include "utils/malloc.h" #include "utils/magsgtty.h" #include "utils/hash.h" #include "utils/macros.h" #include "textio/textio.h" #include "utils/geometry.h" #include "textio/txcommands.h" #include "tiles/tile.h" #include "utils/tech.h" #include "database/database.h" #include "drc/drc.h" #include "windows/windows.h" #include "graphics/graphics.h" #include "dbwind/dbwind.h" #include "commands/commands.h" #include "utils/signals.h" #include "utils/utils.h" #include "utils/runstats.h" #include "cif/cif.h" #ifdef ROUTE_MODULE #include "router/router.h" #endif #ifdef LEF_MODULE #include "lef/lef.h" #endif #include "extract/extract.h" #include "utils/undo.h" #include "netmenu/netmenu.h" #include "plow/plow.h" #include "utils/paths.h" #include "wiring/wiring.h" #ifdef PLOT_MODULE #include "plot/plot.h" #endif #include "sim/sim.h" #include "utils/list.h" #ifdef ROUTE_MODULE #include "mzrouter/mzrouter.h" #endif #ifdef SCHEME_INTERPRETER #include "lisp/lisp.h" #endif #ifdef THREE_D #include "graphics/wind3d.h" #endif /* C99 compat */ #include "utils/utils.h" #include "utils/tech.h" #include "commands/commands.h" #include "dbwind/dbwind.h" #include "cmwind/cmwind.h" #include "extract/extract.h" #include "plow/plow.h" #include "select/select.h" #include "irouter/irouter.h" #include "lef/lefInt.h" /* * Global data structures * */ global char *Path = NULL; /* Search path */ global char *CellLibPath = NULL; /* Used to find cells. */ global char *SysLibPath = NULL; /* Used to find color maps, styles, */ /* technologies, etc. */ /* * Flag that tells if various options have been set on the command line * (see utils.h for explanation of individual flags). */ global short RuntimeFlags = MAIN_MAKE_WINDOW; /* * See the file main.h for a description of the information kept * pertaining to the edit cell. */ global CellUse *EditCellUse = NULL; global CellDef *EditRootDef = NULL; global Transform EditToRootTransform; global Transform RootToEditTransform; /* * data structures local to main.c * */ /* the filename specified on the command line */ static char *MainFileName = NULL; /* RC file specified on the command line */ static char *RCFileName = NULL; /* Definition of file types that magic can read */ #define FN_MAGIC_DB 0 #define FN_LEF_FILE 1 #define FN_DEF_FILE 2 #define FN_GDS_FILE 3 #define FN_CIF_FILE 4 #define FN_TCL_SCRIPT 5 /* List of filenames specified on the command line */ typedef struct filename { char *fn; unsigned char fn_type; struct filename *fn_prev; } FileName; FileName *CurrentName; /* tech name specified on the command line */ static char *TechDefault = NULL; /* the filename for the graphics and mouse ports */ global char *MainGraphicsFile = NULL; global char *MainMouseFile = NULL; /* information about the color display. */ global char *MainDisplayType = NULL; global char *MainMonType = NULL; /* Copyright notice for the binary file. */ global char *MainCopyright = "\n--- MAGIC: Copyright (C) 1985, 1990 " "Regents of the University of California. ---\n"; /* Forward declarations */ char *mainArg(); /* * ---------------------------------------------------------------------------- * MainExit: * * Magic's own exit procedure * * Results: * None. * * Side effects: * We exit. * ---------------------------------------------------------------------------- */ void MainExit(errNum) int errNum; { #ifdef MOCHA MochaExit(errNum); #endif if (GrClosePtr != NULL) /* We are not guarenteed that everthing will * be initialized already! */ GrClose(); DBRemoveBackup(); TxFlush(); TxResetTerminal(FALSE); /* set also atexit() handler */ #ifdef MAGIC_WRAPPER // NOTE: This needs to be done in conjunction with the following // commands in the console: // (1) tkcon eval rename ::exit ::quit // (2) tkcon eval proc::exit args {slave eval quit} // // The lines above redirect tkcon's "exit" routine to be named // "quit" (in the console, not the slave!). Because the tkcon // File->Exit callback is set to eval "exit", we then can create // a new proc called "exit" in the console that runs "quit" in // the slave (magic), and will therefore do the usual checks to // save work before exiting; if all responses are to exit without // saving, then it finally gets to here, where it runs the (renamed) // "quit" command in tkcon. That will ensure that tkcon runs // various cleanup activities such as saving the command-line // history file before the final (!) exit. if (TxTkConsole) Tcl_Eval(magicinterp, "catch {tkcon eval quit}\n"); #endif exit(errNum); } /* * ---------------------------------------------------------------------------- * * mainDoArgs: * * Process command line arguments * * Results: * Return 0 on success, 1 on failure * * Side effects: * Global variables are modified * * Notes: * In order to work properly with the -F flag, we need to * use StrDup() to make copies of any arguments we want * to be visible when we restart a frozen file. * * ---------------------------------------------------------------------------- */ int mainDoArgs(argc, argv) int argc; char **argv; { bool haveDashI = FALSE; char *cp; /* Startup filename (may be changed with the "-rcfile" option or */ /* the "-norcfile" option). */ RCFileName = StrDup((char **) NULL, ".magicrc"); while (--argc > 0) { argv++; if (**argv == '-') { switch (argv[0][1]) { case 'g': if ((cp = mainArg(&argc, &argv, "tty name")) == NULL) return 1; MainGraphicsFile = StrDup((char **) NULL, cp); if (!haveDashI) MainMouseFile = MainGraphicsFile; break; case 'i': haveDashI = TRUE; if ((cp = mainArg(&argc, &argv, "tty name")) == NULL) return 1; MainMouseFile = StrDup((char **) NULL, cp); break; case 'd': if ((cp = mainArg(&argc, &argv, "display type")) ==NULL) return 1; MainDisplayType = StrDup((char **) NULL, cp); break; case 'm': if ((cp = mainArg(&argc, &argv, "monitor type")) ==NULL) return 1; MainMonType = StrDup((char **) NULL, cp); break; /* * Declare the technology. */ case 'T': if ((cp = mainArg(&argc, &argv, "technology")) == NULL) return 1; TechDefault = StrDup((char **) NULL, cp); TechOverridesDefault = TRUE; break; /* * -r or -re or -recover: Recover a crash file. * -rc or -rcfile: Declare a specific startup file to read. */ case 'r': if ((strlen(argv[0]) <= 2) || argv[0][2] == 'e') RuntimeFlags |= MAIN_RECOVER; else if ((argc > 1) && (argv[0][2] == 'c')) { argv[0][2] = '\0'; if ((cp = mainArg(&argc, &argv, "startup file")) == NULL) return 1; RCFileName = StrDup((char **) NULL, cp); } else { TxError("Unknown option: '%s'\n", *argv); return 1; } break; /* * We are being debugged. */ case 'D': RuntimeFlags |= MAIN_DEBUG; break; #ifdef MAGIC_WRAPPER /* * "-w" for wrapper * implies -nowindow (no initial window) */ case 'w': RuntimeFlags &= ~MAIN_MAKE_WINDOW; break; /* * No initial window / no console options / no startup file read. */ case 'n': if (strlen(argv[0]) < 4) { TxError("Ambiguous option %s: use -nowindow, -noconsole, " "or -norcfile\n", argv[0]); return 1; } else if (argv[0][3] == 'c') RuntimeFlags &= ~MAIN_TK_CONSOLE; else if (argv[0][3] == 'w') RuntimeFlags &= ~MAIN_MAKE_WINDOW; else if (argv[0][3] == 'r') { freeMagic(RCFileName); RCFileName = NULL; } else { TxError("Unknown option: '%s'\n", *argv); return 1; } break; #endif default: TxError("Unknown option: '%s'\n", *argv); TxError("Usage: magic [-g gPort] [-d devType] [-m monType] " "[-i tabletPort] [-D] [-F objFile saveFile]\n" "[-T technology] [-rcfile startupFile | -norcfile]" #ifdef MAGIC_WRAPPER "[-noconsole] [-nowindow] [-wrapper] " #endif "[file]\n"); return 1; } } else if (MakeMainWindow) { if (MainFileName == NULL) { MainFileName = StrDup((char **) NULL, *argv); CurrentName = (FileName *) mallocMagic(sizeof(FileName)); CurrentName->fn = MainFileName; CurrentName->fn_prev = (FileName *) NULL; CurrentName->fn_type = FN_MAGIC_DB; } else { FileName *temporary; temporary = (FileName *) mallocMagic(sizeof(FileName)); temporary->fn = StrDup((char **) NULL, *argv); temporary->fn_prev = CurrentName; temporary->fn_type = FN_MAGIC_DB; CurrentName = temporary; } /* Remove suffix if the file name already has it */ { char *c,*d; for(c = CurrentName->fn; (*c) != '\0'; c++); for(d = DBSuffix; (*d) != '\0'; d++); while( (*c) == (*d) ) { if (c == MainFileName) break; if (d == DBSuffix) { (*c) = '\0'; break; } c--; d--; } // Additional checks if ((c = strrchr(CurrentName->fn, '.')) != NULL) { #ifdef LEF_MODULE if (!strcasecmp(c, ".lef")) CurrentName->fn_type = FN_LEF_FILE; else if (!strcasecmp(c, ".def")) CurrentName->fn_type = FN_DEF_FILE; #endif #ifdef CIF_MODULE if (!strcasecmp(c, ".cif")) CurrentName->fn_type = FN_CIF_FILE; else if (!strncasecmp(c, ".gds", 3)) CurrentName->fn_type = FN_GDS_FILE; #endif #ifdef MAGIC_WRAPPER if (!strcasecmp(c, ".tcl")) { CurrentName->fn_type = FN_TCL_SCRIPT; /* Behavior: If a .tcl file is passed on the * command line, then all following arguments * are assumed to be arguments of the script, * and not to be processed as additional * input file types. */ break; } #endif } } } } return 0; } /* * ---------------------------------------------------------------------------- * * mainArg -- * * Pull off an argument from the (argc, argv) pair and also check * to make sure it's not another flag (i.e, it doesn't begin with * a '-'). * * Results: * Return pointer to the argument string. * * Side effects: * See the comments in ArgStr() in the utils module -- they * apply here. * * ---------------------------------------------------------------------------- */ char * mainArg(pargc, pargv, mesg) int *pargc; char ***pargv; char *mesg; { char option, *cp; option = (*pargv)[0][1]; cp = ArgStr(pargc, pargv, mesg); if (cp == NULL) return (char *) NULL; if (*cp == '-') { TxError("Bad name after '-%c' option: '%s'\n", option, cp); return (char *) NULL; } return cp; } /* * ---------------------------------------------------------------------------- * mainInitBeforeArgs: * * Initializes things before argument processing. * * Results: * 0 on success. As written, there are no failure modes. * * Side effects: * All sorts of initialization. Most initialization, however, is done * in 'mainInitAfterArgs'. * ---------------------------------------------------------------------------- */ int mainInitBeforeArgs(argc, argv) int argc; char *argv[]; { TechOverridesDefault = FALSE; if (Path == NULL) Path = StrDup((char **) NULL, "."); /* initialize text display */ TxInit(); TxSetTerminal(); #ifdef SCHEME_INTERPRETER /* Initialize Lisp module. (rajit@cs.caltch.edu) */ LispInit(); #endif /* * Get preliminary info on the graphics display. * This may be overriden later. */ GrGuessDisplayType(&MainGraphicsFile, &MainMouseFile, &MainDisplayType, &MainMonType); FindDisplay((char *)NULL, "displays", CAD_LIB_PATH, &MainGraphicsFile, &MainMouseFile, &MainDisplayType, &MainMonType); return 0; } /* * ---------------------------------------------------------------------------- * mainInitAfterArgs: * * Initializes things after argument processing. * * Results: * Status: 0 = success, 1 = failure to set graphics display, * 2 = failure to load technology file. * * Side effects: * All sorts of initialization. * ---------------------------------------------------------------------------- */ int mainInitAfterArgs() { int (*nullProc)() = 0; SectionID sec_tech, sec_planes, sec_types, sec_aliases; SectionID sec_styles; SectionID sec_connect, sec_contact, sec_compose; SectionID sec_cifinput, sec_cifoutput; SectionID sec_drc, sec_extract, sec_wiring, sec_router; SectionID sec_plow, sec_plot, sec_mzrouter; DBTypeInit(); MacroInit(); #ifdef LEF_MODULE /* Pre-techfile-loading intialization of the LEF module */ LefInit(); #endif #ifdef OPENACCESS OAInit(); #endif /* * Setup path names for system directory searches */ StrDup(&SysLibPath, MAGIC_SYS_PATH); /* * Historic behavior: Expect to search for cells in a directory * inside the install area with the same name as the technology. * Deprecated but kept for backwards compatibility. If directory * does not exist, it will be ignored. */ if (TechFileName != NULL) { CellLibPath = (char *)mallocMagic(strlen(MAGIC_LIB_PATH_FORMAT) + strlen(TechFileName) - 1); sprintf(CellLibPath, MAGIC_LIB_PATH_FORMAT, TechFileName); PaAppend(&CellLibPath, MAGIC_LIB_PATH_DEFAULT); } else if ((TechDefault != NULL) && TechOverridesDefault) { CellLibPath = (char *)mallocMagic(strlen(MAGIC_LIB_PATH_FORMAT) + strlen(TechDefault) - 1); sprintf(CellLibPath, MAGIC_LIB_PATH_FORMAT, TechDefault); PaAppend(&CellLibPath, MAGIC_LIB_PATH_DEFAULT); } else StrDup(&CellLibPath, MAGIC_LIB_PATH_DEFAULT); if (MainGraphicsFile == NULL) MainGraphicsFile = "/dev/null"; if (MainMouseFile == NULL) MainMouseFile = MainGraphicsFile; #ifdef MAGIC_WRAPPER /* Check for batch mode operation and disable interrupts in */ /* batch mode by not calling SigInit(). */ if (Tcl_GetVar(magicinterp, "batch_mode", TCL_GLOBAL_ONLY) != NULL) SigInit(1); else #endif /* catch signals, must come after mainDoArgs & before SigWatchFile */ SigInit(0); /* set up graphics */ if ( !GrSetDisplay(MainDisplayType, MainGraphicsFile, MainMouseFile) ) { return 1; } /* initialize technology */ TechInit(); TechAddClient("tech", DBTechInit, DBTechSetTech, nullProc, (SectionID) 0, &sec_tech, FALSE); TechAddClient("version", DBTechInitVersion, DBTechSetVersion, nullProc, (SectionID) 0, (int *)0, TRUE); TechAddClient("planes", DBTechInitPlane, DBTechAddPlane, nullProc, (SectionID) 0, &sec_planes, FALSE); TechAddClient("types", DBTechInitType, DBTechAddType, DBTechFinalType, sec_planes, &sec_types, FALSE); TechAddClient("styles", nullProc, DBWTechAddStyle, nullProc, sec_types, &sec_styles, FALSE); TechAddClient("contact", DBTechInitContact, DBTechAddContact, DBTechFinalContact, sec_types|sec_planes, &sec_contact, FALSE); TechAddAlias("contact", "images"); TechAddClient("aliases", nullProc, DBTechAddAlias, nullProc, sec_planes|sec_types|sec_contact, &sec_aliases, TRUE); TechAddClient("compose", DBTechInitCompose, DBTechAddCompose, DBTechFinalCompose, sec_types|sec_planes|sec_contact, &sec_compose, FALSE); TechAddClient("connect", DBTechInitConnect, DBTechAddConnect, DBTechFinalConnect, sec_types|sec_planes|sec_contact, &sec_connect, FALSE); #ifdef CIF_MODULE TechAddClient("cifoutput", CIFTechStyleInit, CIFTechLine, CIFTechFinal, (SectionID) 0, &sec_cifoutput, FALSE); TechAddClient("cifinput", CIFReadTechStyleInit, CIFReadTechLine, CIFReadTechFinal, (SectionID) 0, &sec_cifinput, FALSE); #else TechAddClient("cifoutput", nullProc,nullProc,nullProc, (SectionID) 0, &sec_cifoutput, FALSE); TechAddClient("cifinput", nullProc,nullProc,nullProc, (SectionID) 0, &sec_cifinput, FALSE); #endif #ifdef ROUTE_MODULE TechAddClient("mzrouter", MZTechInit, MZTechLine, MZTechFinal, sec_types|sec_planes, &sec_mzrouter, TRUE); #else TechAddClient("mzrouter", nullProc,nullProc,nullProc, sec_types|sec_planes, &sec_mzrouter, TRUE); #endif TechAddClient("drc", DRCTechStyleInit, DRCTechLine, DRCTechFinal, sec_types|sec_planes, &sec_drc, FALSE); /* Plow rules are generated from the same lines as the DRC rules */ TechAddClient("drc", PlowDRCInit, PlowDRCLine, PlowDRCFinal, sec_types|sec_planes, &sec_drc, FALSE); #ifdef LEF_MODULE TechAddClient("lef", LefTechInit, LefTechLine, nullProc, sec_types|sec_planes, (SectionID *) 0, TRUE); #endif #ifdef NO_EXT TechAddClient("extract", nullProc, nullProc,nullProc, sec_types|sec_connect, &sec_extract, FALSE); #else TechAddClient("extract", nullProc, ExtTechLine, ExtTechFinal, sec_types|sec_connect, &sec_extract, FALSE); #endif TechAddClient("wiring", WireTechInit, WireTechLine, WireTechFinal, sec_types, &sec_wiring, TRUE); #ifdef ROUTE_MODULE TechAddClient("router", RtrTechInit, RtrTechLine, RtrTechFinal, sec_types, &sec_router, TRUE); #else TechAddClient("router", nullProc,nullProc,nullProc, sec_types, &sec_router, TRUE); #endif TechAddClient("plowing", PlowTechInit, PlowTechLine, PlowTechFinal, sec_types|sec_connect|sec_contact, &sec_plow, TRUE); #ifdef PLOT_MODULE TechAddClient("plot", PlotTechInit, PlotTechLine, PlotTechFinal, sec_types, &sec_plot, TRUE); #else TechAddClient("plot", nullProc,nullProc,nullProc, sec_types, &sec_plot, TRUE); #endif /* Load minimum technology file needed to keep things from */ /* crashing during initialization. */ if (!TechLoad("minimum", 0)) { TxError("Cannot load technology \"minimum\" for initialization\n"); return 2; } /* The minimum tech has been loaded only to keep the database from */ /* becoming corrupted during initialization. Free the tech file */ /* name so that a "real" technology file can be forced to replace */ /* it in mainInitFinal(). */ if (TechFileName != NULL) { freeMagic(TechFileName); TechFileName = NULL; } /* initialize the undo package */ (void) UndoInit((char *) NULL, (char *) NULL); /* initialize windows */ WindInit(); /* initialize commands */ CmdInit(); /* Initialize the interface between windows and its clients */ DBWinit(); #ifdef USE_READLINE TxInitReadline(); #endif CMWinit(); #ifdef THREE_D W3Dinit(); #endif /* Initialize the circuit extractor */ #ifndef NO_EXT ExtInit(); #endif /* Initialize plowing */ PlowInit(); /* Initialize selection */ SelectInit(); /* Initialize the wiring module */ WireInit(); #ifdef ROUTE_MODULE /* Initialize the netlist menu */ NMinit(); #endif /* Initialize the design-rule checker */ DRCInit(); /* Initialize the maze router */ #ifdef ROUTE_MODULE MZInit(); /* Initialize the interactive router - * NOTE the mzrouter must be initialized prior to the irouter * so that default parameters will be completely setup */ IRDebugInit(); IRAfterTech(); #endif /* Initialize the Sim Module (the part of it which involves (i)rsim) */ #if !defined(NO_SIM_MODULE) && defined(RSIM_MODULE) SimInit(); #endif TxSetPoint(GR_CURSOR_X, GR_CURSOR_Y, WIND_UNKNOWN_WINDOW); return 0; } /* * Tcl_SetExitProc() was removed in TCL9 and used to perform this function * see: https://core.tcl-lang.org/tips/doc/trunk/tip/512.md * * Note this change will slightly alter the order, the termios restore will * not longer be performed before exit() is called. * * The default Tcl_Exit() does manage calling exit(status) by default. * This assumes TxResetTerminal() will only attempt a restore if state * was saved. * TxResetTerminal() does not do anything if TxTkConsole is set that appears * to be the popup shell window. */ static void atexit_exit_hook(void) { TxResetTerminal(TRUE); } /* * ---------------------------------------------------------------------------- * mainInitFinal: * * Final initialization; reads startup files and any initial file * specified. * * Results: * Return 0 on success. As written, there is no failure mode. * * Side effects: * All sorts of initialization. * ---------------------------------------------------------------------------- */ int mainInitFinal() { char *home, cwd[512]; char startupFileName[256]; FILE *f; char *rname; int result; #ifdef MAGIC_WRAPPER /* Reset terminal if exit is called inside a TCL script */ atexit(atexit_exit_hook); /* Read in system pre-startup file, if it exists. */ /* Use PaOpen first to perform variable substitutions, and */ /* return the actual filename in rname. */ f = PaOpen(MAGIC_PRE_DOT, "r", (char *) NULL, ".", (char *) NULL, (char **) &rname); if (f != NULL) { fclose(f); result = Tcl_EvalFile(magicinterp, rname); if (result != TCL_OK) { TxError("Error parsing pre-startup file \"%s\": %s\n", rname, Tcl_GetStringResult(magicinterp)); Tcl_ResetResult(magicinterp); } } #endif /* MAGIC_WRAPPER */ // Make a first attempt to load the technology if specified on the // command line with the -T option. This will preempt most other // ways that the technology file is determined. If the technology // specified cannot be loaded, then the forced override is revoked. if ((TechFileName == NULL) && (TechDefault != NULL) && TechOverridesDefault) { if (!TechLoad(TechDefault, -2)) { TxError("Failed to load technology \"%s\"\n", TechDefault); TechOverridesDefault = FALSE; } else if (!TechLoad(TechDefault, 0)) { TxError("Error loading technology \"%s\"\n", TechDefault); TechOverridesDefault = FALSE; } } #ifndef MAGIC_WRAPPER // Let the wrapper script be responsible for formatting and // printing the technology file informaiton. if (DBTechName != 0) { TxPrintf("Using technology \"%s\"", DBTechName); if (DBTechVersion != 0) TxPrintf(", version %s.", DBTechVersion); TxPrintf("\n"); } if (DBTechDescription != 0) TxPrintf("%s\n", DBTechDescription); #endif #ifdef MAGIC_WRAPPER /* Read in system startup file, if it exists. */ /* Use PaOpen first to perform variable substitutions, and */ /* return the actual filename in rname. */ f = PaOpen(MAGIC_SYS_DOT, "r", (char *) NULL, ".", (char *) NULL, (char **) &rname); if (f != NULL) { fclose(f); result = Tcl_EvalFile(magicinterp, rname); if (result != TCL_OK) { TxError("Error parsing system startup file \"%s\": %s\n", rname, Tcl_GetStringResult(magicinterp)); Tcl_ResetResult(magicinterp); } } #else /* !MAGIC_WRAPPER */ f = PaOpen(MAGIC_SYS_DOT, "r", (char *) NULL, ".", (char *) NULL, (char **) NULL); if (f != NULL) { TxDispatch(f); (void) fclose(f); } #endif /* !MAGIC_WRAPPER */ /* * Strive for a wee bit more parallelism; let the graphics * display run while we're reading in startup files & initial cell. */ GrFlush(); /* Ignore this whole section if we have received the -norc option */ if (RCFileName != NULL) { /* Read in user's startup files, if there are any. */ /* If the "-rcfile" option has been used, and it doesn't specify */ /* a full path, then look for this file in the home directory too. */ home = getenv("HOME"); #ifdef MAGIC_WRAPPER if (home != NULL && (RCFileName[0] != '/')) { Tcl_Channel fc; (void) sprintf(startupFileName, "%s/%s", home, RCFileName); fc = Tcl_OpenFileChannel(magicinterp, startupFileName, "r", 0); if (fc != NULL) { Tcl_Close(magicinterp, fc); result = Tcl_EvalFile(magicinterp, startupFileName); if (result != TCL_OK) { TxError("Error parsing user \"%s\": %s\n", RCFileName, Tcl_GetStringResult(magicinterp)); Tcl_ResetResult(magicinterp); } } else { /* Try the (deprecated) name ".magic" */ (void) sprintf(startupFileName, "%s/.magic", home); fc = Tcl_OpenFileChannel(magicinterp, startupFileName, "r", 0); if (fc != NULL) { TxPrintf("Note: Use of the file name \"~/.magic\" is deprecated." " Please change this to \"~/.magicrc\".\n"); Tcl_Close(magicinterp, fc); result = Tcl_EvalFile(magicinterp, startupFileName); if (result != TCL_OK) { TxError("Error parsing user \".magic\": %s\n", Tcl_GetStringResult(magicinterp)); Tcl_ResetResult(magicinterp); } } } } if (getcwd(cwd, 512) == NULL || strcmp(cwd, home) || (RCFileName[0] == '/')) { /* Read in the .magicrc file from the current directory, if */ /* different from HOME. */ Tcl_Channel fc; fc = Tcl_OpenFileChannel(magicinterp, RCFileName, "r", 0); if (fc != NULL) { Tcl_Close(magicinterp, fc); result = Tcl_EvalFile(magicinterp, RCFileName); if (result != TCL_OK) { // Print error message but continue anyway TxError("Error parsing \"%s\": %s\n", RCFileName, Tcl_GetStringResult(magicinterp)); Tcl_ResetResult(magicinterp); TxPrintf("Bad local startup file \"%s\", continuing without.\n", RCFileName); } } else { /* Try the (deprecated) name ".magic" */ Tcl_ResetResult(magicinterp); fc = Tcl_OpenFileChannel(magicinterp, ".magic", "r", 0); if (fc != NULL) { Tcl_Close(magicinterp, fc); TxPrintf("Note: Use of the file name \".magic\" is deprecated." " Please change this to \".magicrc\".\n"); result = Tcl_EvalFile(magicinterp, ".magic"); if (result != TCL_OK) { // Print error message but continue anyway TxError("Error parsing local \".magic\": %s\n", Tcl_GetStringResult(magicinterp)); Tcl_ResetResult(magicinterp); TxPrintf("Bad local startup file \".magic\"," " continuing without.\n"); } } else { /* Try the alternative name "magic_setup" */ Tcl_ResetResult(magicinterp); fc = Tcl_OpenFileChannel(magicinterp, "magic_setup", "r", 0); if (fc != NULL) { Tcl_Close(magicinterp, fc); result = Tcl_EvalFile(magicinterp, "magic_setup"); if (result != TCL_OK) { TxError("Error parsing local \"magic_setup\": %s\n", Tcl_GetStringResult(magicinterp)); TxError("%s\n", Tcl_GetStringResult(magicinterp)); Tcl_ResetResult(magicinterp); // Still not an error TxPrintf("Bad local startup file \"magic_setup\"," " continuing without.\n"); } } } } } #else /* !MAGIC_WRAPPER */ if (home != NULL && (RCFileName[0] != '/')) { (void) sprintf(startupFileName, "%s/%s", home, RCFileName); f = PaOpen(startupFileName, "r", (char *) NULL, ".", (char *) NULL, (char **) NULL); if ((f == NULL) && (!strcmp(RCFileName, ".magicrc"))) { /* Try the (deprecated) name ".magic" */ (void) sprintf(startupFileName, "%s/.magic", home); f = PaOpen(startupFileName, "r", (char *) NULL, ".", (char *) NULL, (char **) NULL); if (f != NULL) TxPrintf("Note: Use of the file name \"~/.magic\" is deprecated." " Please change this to \"~/.magicrc\".\n"); } if (f != NULL) { TxDispatch(f); (void) fclose(f); } } /* Read in any startup file in the current directory, or one that was */ /* specified on the commandline by the "-rcfile " option. */ f = PaOpen(RCFileName, "r", (char *) NULL, ".", (char *) NULL, (char **) NULL); /* Again, check for the deprecated name ".magic" */ if (f == NULL) { if (!strcmp(RCFileName, ".magicrc")) { f = PaOpen(".magic", "r", (char *) NULL, ".", (char *) NULL, (char **) NULL); if (f != NULL) TxPrintf("Note: Use of the file name \"./.magic\" is deprecated." " Please change this to \"./.magicrc\".\n"); else f = PaOpen("magic_setup", "r", (char *) NULL, ".", (char *) NULL, (char **) NULL); } else TxError("Startup file \"%s\" not found or unreadable!\n", RCFileName); } if (f != NULL) { TxDispatch(f); fclose(f); } #endif /* !MAGIC_WRAPPER */ } /* We are done forcing the "tech load" command to be ignored */ TechOverridesDefault = FALSE; /* If no technology has been specified yet, try to read one from * the initial cell, or else assign a default. */ if ((TechFileName == NULL) && (TechDefault == NULL) && (MainFileName != NULL)) StrDup(&TechDefault, DBGetTech(MainFileName)); /* Load the technology file. If any startup file loaded a */ /* technology file, then "TechFileName" will be set, and we */ /* should not override it. */ if ((TechFileName == NULL) && (TechDefault != NULL)) { if (!TechLoad(TechDefault, -2)) TxError("Failed to load technology \"%s\"\n", TechDefault); else if (!TechLoad(TechDefault, 0)) TxError("Error loading technology \"%s\"\n", TechDefault); } if (TechDefault != NULL) { freeMagic(TechDefault); TechDefault = NULL; } /* If that failed, then load the "minimum" technology again and */ /* keep it. It's not very useful, but it will keep everything */ /* up and running. In the worst case, if site.pre has removed the */ /* standard locations from the system path, then magic will exit. */ if (TechFileName == NULL) if (!TechLoad("minimum", 0)) return -1; #ifdef SCHEME_INTERPRETER /* Pass technology name to Lisp interpreter (rajit@cs.caltech.edu) */ LispSetTech (TechFileName); #endif /* * Recover crash files from the temp directory if we have specified * the -r option on the command line (non-tcl version. Tcl version * uses the command-line command crashrecover. */ if (mainRecover && MakeMainWindow) { DBFileRecovery(NULL); /* automatic search most recent */ } /* * Bring in a new cell or cells to start up if one was given * on the command line */ else if (MainFileName && MakeMainWindow) { FileName *temporary; while(CurrentName != NULL) { temporary = CurrentName; CurrentName = temporary->fn_prev; TxPrintf("Loading \"%s\" from command line.\n", temporary->fn); switch (temporary->fn_type) { case FN_MAGIC_DB: DBWreload(temporary->fn); break; #ifdef LEF_MODULE case FN_LEF_FILE: LefRead(temporary->fn, FALSE, FALSE, -1); break; case FN_DEF_FILE: DefRead(temporary->fn, FALSE, FALSE, FALSE); break; #endif #ifdef MAGIC_WRAPPER case FN_TCL_SCRIPT: result = Tcl_EvalFile(magicinterp, temporary->fn); if (result != TCL_OK) { TxError("Error parsing \"%s\": %s\n", temporary->fn, Tcl_GetStringResult(magicinterp)); Tcl_ResetResult(magicinterp); } break; #endif } freeMagic(temporary); } } /* Create an initial box. */ if (MakeMainWindow && EditCellUse) DBWSetBox(EditCellUse->cu_def, &EditCellUse->cu_def->cd_bbox); /* Set the initial fence for undo-ing: don't want to be able to * undo past this point. */ UndoFlush(); TxClearPoint(); return 0; } /* * ---------------------------------------------------------------------------- * mainFinish: * * Finish up things for Magic. This routine is NOT called on an * error exit. * * Results: * None. * * Side effects: * Various things, such as stopping measurement gathering. * ---------------------------------------------------------------------------- */ void mainFinished() { /* Close up things */ MainExit(0); } /*--------------------------------------------------------------------------- * magicMain: * * Top-level procedure of the Magic Layout System. There is purposely * not much in here so that we have more flexibility. Also, it is * not called 'main' so that other programs that use Magic may do * something else. * * Results: * None. * * Side Effects: * None. * * Note: Try not to add code to this procedure. Add it instead to one of the * procedures that it calls. * *---------------------------------------------------------------------------- */ void magicMain(argc, argv) int argc; char *argv[]; { int rstatus; if ((rstatus = mainInitBeforeArgs(argc, argv)) != 0) MainExit(rstatus); if ((rstatus = mainDoArgs(argc, argv)) != 0) MainExit(rstatus); if ((rstatus = mainInitAfterArgs()) != 0) MainExit(rstatus); if ((rstatus = mainInitFinal()) != 0) MainExit(rstatus); TxDispatch( (FILE *) NULL); mainFinished(); }