diff --git a/VERSION b/VERSION
index 8606ed34..a3437885 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-8.3.403
+8.3.404
diff --git a/commands/CmdE.c b/commands/CmdE.c
index dcf45b0a..537c1f2f 100644
--- a/commands/CmdE.c
+++ b/commands/CmdE.c
@@ -862,10 +862,11 @@ cmdExpandFunc(use, windowMask)
#define EXTLENGTH 5
#define EXTNO 6
#define EXTPARENTS 7
-#define EXTSHOWPARENTS 8
-#define EXTSTYLE 9
-#define EXTUNIQUE 10
-#define EXTWARN 11
+#define EXTPATH 8
+#define EXTSHOWPARENTS 9
+#define EXTSTYLE 10
+#define EXTUNIQUE 11
+#define EXTWARN 12
#define WARNALL 0
#define WARNDUP 1
@@ -957,6 +958,7 @@ CmdExtract(w, cmd)
"length [option] control pathlength extraction information",
"no [option] disable extractor option",
"parents extract selected cell and all its parents",
+ "path [path] if set, extract into the indicated path",
"showparents show all parents of selected cell",
"style [stylename] set current extraction parameter style",
"unique [option] generate unique names when different nodes\n\
@@ -1113,6 +1115,13 @@ CmdExtract(w, cmd)
ExtShowParents(selectedUse);
return;
+ case EXTPATH:
+ if (argc == 2)
+ ExtPrintPath(dolist);
+ else
+ ExtSetPath(argv[2]);
+ return;
+
case EXTSTYLE:
if (argc == 2)
ExtPrintStyle(dolist, doforall, !doforall);
@@ -1188,7 +1197,6 @@ CmdExtract(w, cmd)
TxPrintf("%s capacitance\n", OPTSET(EXT_DOCAPACITANCE));
TxPrintf("%s coupling\n", OPTSET(EXT_DOCOUPLING));
TxPrintf("%s length\n", OPTSET(EXT_DOLENGTH));
- TxPrintf("%s local\n", OPTSET(EXT_DOLOCAL));
TxPrintf("%s resistance\n", OPTSET(EXT_DORESISTANCE));
TxPrintf("%s label check\n", OPTSET(EXT_DOLABELCHECK));
TxPrintf("%s aliases\n", OPTSET(EXT_DOALIASES));
@@ -1218,10 +1226,19 @@ CmdExtract(w, cmd)
case DOCAPACITANCE: option = EXT_DOCAPACITANCE; break;
case DOCOUPLING: option = EXT_DOCOUPLING; break;
case DOLENGTH: option = EXT_DOLENGTH; break;
- case DOLOCAL: option = EXT_DOLOCAL; break;
case DORESISTANCE: option = EXT_DORESISTANCE; break;
case DOLABELCHECK: option = EXT_DOLABELCHECK; break;
case DOALIASES: option = EXT_DOALIASES; break;
+ case DOLOCAL:
+ /* "extract do local" and "extract no local" are kept for
+ * backwards compatibility, but now effectively implement
+ * "extract path ." and "extract path none", respectively.
+ */
+ if (no)
+ StrDup(&ExtLocalPath, NULL);
+ else
+ StrDup(&ExtLocalPath, ".");
+ return;
}
if (no) ExtOptions &= ~option;
else ExtOptions |= option;
diff --git a/doc/html/ext.html b/doc/html/ext.html
deleted file mode 100644
index 262d774f..00000000
--- a/doc/html/ext.html
+++ /dev/null
@@ -1,138 +0,0 @@
-
-
-
-
-Magic-7.3 Command Reference
-
-
-
-
-ext, extract
-
-Circuit netlist extractor
-
-
-Usage:
-
- extract option
-
- where option may be one of the following:
-
- - all
-
- Extract the root cell and all its children. This bypasses
- the incremental extraction and ensures that a new .ext
- file is written for every cell definition.
-
- cell name
-
- Extract the indicated cell into file name
-
- do|no [option]
-
- Enable or disable an extractor option, where option
- may be one of the following:
-
-
- - capacitance
-
-
-
- resistance
-
-
-
- coupling
-
-
-
- length
-
-
-
- adjust
-
-
-
- all
-
-
-
-
-
- - length [option]
-
- Control pathlength extraction information, where option
- may be one of the following:
-
-
- - driver termname
-
-
-
- receiver termname
-
-
-
- clear
-
-
-
-
-
- - help
-
- Print help information
-
- parents
-
- Extract the selected cell and all its parents
-
- showparents
-
- List the cell and all parents of selected cell. Note that
- this is not really an extract option and is superceded by
- the cellname command.
-
- [list|listall] style [stylename]
-
- Set the current extraction style to stylename.
- Without arguments, print the current extraction style.
- With keyword list, return the current extraction
- style as a Tcl result. With keyword listall, return
- all valid extraction styles for the technology as a Tcl
- list.
-
- unique [#]
-
- Generate unique names when different nodes have the same name
-
- warn [[no] option]
-
- Enable/disable reporting of non-fatal errors, where option
- may be one of the following:
-
-
- - fets
-
-
-
- labels
-
-
-
- dup
-
-
-
- all
-
-
-
-
-
-
-
-
-Summary:
-
- With no options given, the extract command incrementally
- extracts the root cell and all its children into separate
- .ext files. With options, the effect is as described
- in the Usage section above.
-
-
-Implementation Notes:
-
- extract is implemented as a built-in magic command.
- ext is an alias for command extract (allowed
- abbreviation where the usage would otherwise be ambiguous).
-
-
-See Also:
-
- extresist
- ext2spice
- ext2sim
-
-
-
-
-Last updated: March 7, 2020 at 1:06pm
-
-
diff --git a/doc/html/ext.html b/doc/html/ext.html
new file mode 120000
index 00000000..4742931f
--- /dev/null
+++ b/doc/html/ext.html
@@ -0,0 +1 @@
+extract.html
\ No newline at end of file
diff --git a/doc/html/extract.html b/doc/html/extract.html
index d7c6857d..e71ed0c4 100644
--- a/doc/html/extract.html
+++ b/doc/html/extract.html
@@ -80,7 +80,11 @@ Circuit netlist extractor
same directory as the .mag file from which it is
derived, unless the .mag file is in a directory which
is not writable. In that case, the .ext file will also
- be written to the current working directory.
+ be written to the current working directory.
+ Note: As of magic version 8.3.404, "extract
+ do local" effectively implements "extract path ."
+ and "extract no local" implements " extract
+ path none".
labelcheck
Check for labels which have zero area and connect
to a subcell on the edge; this case is rare but is
@@ -124,6 +128,19 @@ Circuit netlist extractor
help
Print help information
+ path [pathname|none]
+ Extract locally into the directory pathname. If
+ pathname does not exist, then magic will attempt to
+ create it. If it cannot be created, then the behavior will
+ be to save extract files in the current working directory.
+ If no path is set, or if none is specified as the
+ path, then the behavior will be to extract files in the
+ same directory as where the magic database (.mag)
+ file is located, unless that directory is unwritable by
+ the user, in which case the file is extracted to the
+ current working diretory. Note that "extract do local"
+ is the same as "extract path ." and "extract no local"
+ is the same as "extract path none".
parents
Extract the selected cell and all its parents
showparents
diff --git a/extflat/EFargs.c b/extflat/EFargs.c
index 970b07dc..14d92b16 100644
--- a/extflat/EFargs.c
+++ b/extflat/EFargs.c
@@ -26,6 +26,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include
#include
+#include "utils/main.h"
#include "utils/magic.h"
#include "utils/paths.h"
#include "utils/geometry.h"
@@ -35,8 +36,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/pathvisit.h"
#include "extflat/extflat.h"
#include "extflat/EFint.h"
-
-/* C99 compat */
#include "textio/textio.h"
#include "utils/pathvisit.h"
@@ -59,13 +58,6 @@ char *EFTech = NULL;
char *EFStyle = NULL; /* Start with no extraction style */
bool EFCompat = TRUE; /* Start with backwards compatibility enabled */
-#ifdef MAGIC_WRAPPER
-extern char *Path; /* magic's search path---note this should */
- /* be done with #include "utils/main.h" but */
- /* this is easier. */
-#endif
-
-
/* -------------------- Visible only inside extflat ------------------- */
/* Command-line flags */
@@ -203,9 +195,10 @@ EFArgs(argc, argv, err_result, argsProc, cdata)
EFCapThreshold = atoCap(cp); /* Femtofarads */
break;
case 'p':
- EFSearchPath = ArgStr(&argc, &argv, "search path");
- if (EFSearchPath == NULL)
+ cp = ArgStr(&argc, &argv, "search path");
+ if (cp == NULL)
goto usage;
+ StrDup(&EFSearchPath, cp);
break;
case 'r':
if ((cp = ArgStr(&argc, &argv, "resist threshold")) == NULL)
@@ -302,13 +295,9 @@ EFArgs(argc, argv, err_result, argsProc, cdata)
}
}
- /* Find the search path if one was not specified */
- if (EFSearchPath == NULL)
-#ifdef MAGIC_WRAPPER
- /* Set the search path to be the same as magic's search path */
- EFSearchPath = StrDup(NULL, Path);
-#else
- efLoadSearchPath(&EFSearchPath);
+#ifndef MAGIC_WRAPPER
+ /* This is probably not useful */
+ if (EFSearchPath == NULL) efLoadSearchPath(&EFSearchPath);
#endif
EFLibPath = libpath;
diff --git a/extflat/EFdef.c b/extflat/EFdef.c
index edf05906..1947c82c 100644
--- a/extflat/EFdef.c
+++ b/extflat/EFdef.c
@@ -173,6 +173,13 @@ EFDone(func)
/* Final cleanup */
HashKill(&efDefHashTable);
+
+ /* EFSearchPath does not persist beyond the command that set it */
+ if (EFSearchPath)
+ {
+ freeMagic(EFSearchPath);
+ EFSearchPath = NULL;
+ }
}
/*
diff --git a/extflat/EFread.c b/extflat/EFread.c
index 11287bf0..415757d8 100644
--- a/extflat/EFread.c
+++ b/extflat/EFread.c
@@ -27,6 +27,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include
#include "tcltk/tclmagic.h"
+#include "utils/main.h"
#include "utils/magic.h"
#include "utils/malloc.h"
#include "utils/geometry.h"
@@ -201,10 +202,15 @@ efReadDef(def, dosubckt, resist, noscale, toplevel)
def->def_flags |= DEF_AVAILABLE;
name = def->def_name;
- /* If cell is in main database, check if there is a file path set. */
+ /* If the search path was specified with the "-p" argument to the calling
+ * command (e.g., ext2spice or ext2sim), then use that path.
+ */
+ if (EFSearchPath != NULL)
+ inf = PaOpen(name, "r", ".ext", EFSearchPath, EFLibPath, &efReadFileName);
- if ((dbdef = DBCellLookDef(name)) != NULL)
+ if ((inf == NULL) && (dbdef = DBCellLookDef(name)) != NULL)
{
+ /* If cell is in main database, check if there is a file path set. */
if (dbdef->cd_file != NULL)
{
char *filepath, *sptr;
@@ -218,18 +224,11 @@ efReadDef(def, dosubckt, resist, noscale, toplevel)
freeMagic(filepath);
}
}
- if (inf == NULL)
- inf = PaOpen(name, "r", ".ext", EFSearchPath, EFLibPath, &efReadFileName);
- if (inf == NULL)
- {
- /* Complementary to .ext file write: If file is in a read-only */
- /* directory, then .ext file is written to CWD. */
- char *proot;
- proot = strrchr(name, '/');
- if (proot != NULL)
- inf = PaOpen(proot + 1, "r", ".ext", ".", ".", &efReadFileName);
- }
+ /* Try with the standard search path */
+ if ((inf == NULL) && (EFSearchPath == NULL))
+ inf = PaOpen(name, "r", ".ext", Path, EFLibPath, &efReadFileName);
+
if (inf == NULL)
{
#ifdef MAGIC_WRAPPER
diff --git a/extract/ExtCell.c b/extract/ExtCell.c
index bd94bb26..997eca19 100644
--- a/extract/ExtCell.c
+++ b/extract/ExtCell.c
@@ -22,6 +22,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#endif /* not lint */
#include
+#include
+#include
+#include
#include
#include
@@ -95,9 +98,6 @@ ExtCell(def, outName, doLength)
char *filename;
FILE *f = NULL;
Plane *savePlane;
- bool doLocal;
-
- doLocal = (ExtOptions & EXT_DOLOCAL) ? TRUE : FALSE;
/* Incremental extraction: If the cell is marked for no extraction,
* then just prepare the substrate plane and return it to the caller.
@@ -105,7 +105,7 @@ ExtCell(def, outName, doLength)
if (def->cd_flags & CDNOEXTRACT)
return extPrepSubstrate(def);
- f = extFileOpen(def, outName, "w", doLocal, &filename);
+ f = extFileOpen(def, outName, "w", &filename);
TxPrintf("Extracting %s into %s:\n", def->cd_name, filename);
@@ -159,7 +159,7 @@ ExtCell(def, outName, doLength)
*/
FILE *
-extFileOpen(def, file, mode, doLocal, prealfile)
+extFileOpen(def, file, mode, prealfile)
CellDef *def; /* Cell whose .ext file is to be written */
char *file; /* If non-NULL, open 'name'.ext; otherwise,
* derive filename from 'def' as described
@@ -168,7 +168,6 @@ extFileOpen(def, file, mode, doLocal, prealfile)
char *mode; /* Either "r" or "w", the mode in which the .ext
* file is to be opened.
*/
- bool doLocal; /* If true, always write to local directory */
char **prealfile; /* If this is non-NULL, it gets set to point to
* a string holding the name of the .ext file.
*/
@@ -178,8 +177,33 @@ extFileOpen(def, file, mode, doLocal, prealfile)
FILE *rfile, *testf;
if (file) name = file;
- else if (doLocal)
- name = def->cd_name; /* No path component, so save locally */
+ else if (ExtLocalPath != NULL)
+ {
+ if (!strcmp(ExtLocalPath, "."))
+ name = def->cd_name; /* Save locally */
+ else
+ {
+ struct stat st = {0};
+
+ /* Test presence of the directory */
+ if (stat(ExtLocalPath, &st) == -1) {
+ TxError("Path \"%s\" does not exist; attempting to create it.\n",
+ ExtLocalPath);
+ mkdir(ExtLocalPath, 0755);
+ if (stat(ExtLocalPath, &st) == -1) {
+ TxError("Path \"%s\" does not exist; saving locally.\n",
+ ExtLocalPath);
+ name = def->cd_name; /* Save locally */
+ }
+ }
+ else
+ {
+ /* Save locally in specified path, which is assumed to exist */
+ name = namebuf;
+ sprintf(namebuf, "%s/%s", ExtLocalPath, def->cd_name);
+ }
+ }
+ }
else if (def->cd_file)
{
name = def->cd_file;
diff --git a/extract/ExtMain.c b/extract/ExtMain.c
index 96c1fe71..d05aad4b 100644
--- a/extract/ExtMain.c
+++ b/extract/ExtMain.c
@@ -58,6 +58,7 @@ extern FILE *extFileOpen();
*/
int ExtDoWarn = EXTWARN_DUP|EXTWARN_FETS;
int ExtOptions = EXT_DOALL|EXT_DOLABELCHECK|EXT_DOALIASES;
+char *ExtLocalPath = NULL;
/* --------------------------- Global data ---------------------------- */
@@ -908,9 +909,9 @@ extTimestampMisMatch(def)
int stamp;
bool doLocal;
- doLocal = (ExtOptions & EXT_DOLOCAL) ? TRUE : FALSE;
+ doLocal = (ExtLocalPath == NULL) ? FALSE : TRUE;
- extFile = extFileOpen(def, (char *) NULL, "r", doLocal, (char **) NULL);
+ extFile = extFileOpen(def, (char *) NULL, "r", (char **) NULL);
if (extFile == NULL)
return (TRUE);
diff --git a/extract/ExtTech.c b/extract/ExtTech.c
index 5023a8b3..4309e197 100644
--- a/extract/ExtTech.c
+++ b/extract/ExtTech.c
@@ -577,6 +577,87 @@ ExtGetZAxis(tile, height, thick)
}
#endif /* THREE_D */
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * ExtPrintPath --
+ *
+ * Print the path where extraction files will be written
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Output.
+ *
+ * ----------------------------------------------------------------------------
+ */
+
+void
+ExtPrintPath(dolist)
+ bool dolist;
+{
+ if (ExtLocalPath == NULL)
+ {
+ if (dolist)
+ {
+#ifdef MAGIC_WRAPPER
+ Tcl_SetObjResult(magicinterp, Tcl_NewStringObj("(none)", -1));
+#else
+ TxPrintf("(none)\n");
+#endif
+ }
+ else
+ TxPrintf("(none)\n");
+ }
+ else
+ {
+ if (dolist)
+ {
+#ifdef MAGIC_WRAPPER
+ Tcl_SetObjResult(magicinterp, Tcl_NewStringObj(ExtLocalPath, -1));
+#else
+ TxPrintf("%s\n", ExtLocalPath);
+#endif
+ }
+ else
+ TxPrintf("The extraction path is: %s\n", ExtLocalPath);
+ }
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ *
+ * ExtSetPath --
+ *
+ * Set the current extraction path to 'path', unless 'path' is "none" or
+ * "(none)", in which case clear the path and set it to NULL.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Just told you.
+ *
+ * ----------------------------------------------------------------------------
+ */
+
+void
+ExtSetPath(path)
+ char *path;
+{
+ if (path != NULL)
+ {
+ if (!strcasecmp(path, "none") || !strcasecmp(path, "(none)") ||
+ !strcasecmp(path, "null"))
+ {
+ StrDup(&ExtLocalPath, NULL);
+ return;
+ }
+ }
+ StrDup(&ExtLocalPath, path);
+ return;
+}
/*
* ----------------------------------------------------------------------------
diff --git a/extract/extract.h b/extract/extract.h
index 74c16e99..2ace2ae1 100644
--- a/extract/extract.h
+++ b/extract/extract.h
@@ -69,11 +69,11 @@ extern char *extDevTable[];
#define EXT_DOLENGTH 0x010 /* Extract pathlengths */
#define EXT_DOFRINGEHALO 0x020 /* Distributed fringe capacitance */
#define EXT_DOALL 0x03f /* ALL OF THE ABOVE */
-#define EXT_DOLOCAL 0x040 /* Write to local directory only */
-#define EXT_DOLABELCHECK 0x080 /* Check for connections by label */
-#define EXT_DOALIASES 0x100 /* Output all node aliases */
+#define EXT_DOLABELCHECK 0x040 /* Check for connections by label */
+#define EXT_DOALIASES 0x080 /* Output all node aliases */
extern int ExtOptions; /* Bitmask of above */
+extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */
/* Options for "extract unique" */
#define EXT_UNIQ_ALL 0
@@ -86,6 +86,8 @@ extern void ExtTechInit();
extern void ExtTechFinal();
extern void ExtSetStyle();
extern void ExtPrintStyle();
+extern void ExtSetPath();
+extern void ExtPrintPath();
extern void ExtRevertSubstrate();
extern Plane *ExtCell();
extern void ExtractOneCell();