Added a new command "archive" that works roughly like the "crash"

command, but with some critical differences, since the "crash"
command is designed for crash backups.  "crash" will save in a
temp file and removes the file after a successful recovery.
"archive" can be used at any time to make a complete snapshot of
a layout in a single file, or to read back that snapshot.
There is a "writeall" option that will make a snapshot including
layout of all read-only (PDK) cells.
This commit is contained in:
R. Timothy Edwards 2025-09-10 12:40:40 -04:00
parent 6195c20d3d
commit 741216d6f3
9 changed files with 417 additions and 186 deletions

View File

@ -1 +1 @@
8.3.549
8.3.550

View File

@ -81,6 +81,70 @@ CmdAddPath(
PaAppend(&Path, cmd->tx_argv[1]);
}
/*
* ----------------------------------------------------------------------------
*
* CmdArchive --
*
* Save an entire database to a "crash recovery"-type archive file, or
* load a database from a "crash recovery"-type archive file. Option
* "writeall" writes everything, including read-only PDK cells, while
* "readref" does not dereference and will prefer files found in the
* search path over content in the archive.
*
*
* Usage:
* archive write|writeall|read|readref file
*
* Results:
* None.
*
* Side effects:
* Writes a single file with the contents of the entire database,
* or loads the database with multiple cells from the file.
*
* ----------------------------------------------------------------------------
*/
void
CmdArchive(
MagWindow *w,
TxCommand *cmd)
{
int option = -1;
char *filename = NULL;
static const char * const cmdArchiveOpt[] = {"write", "writeall",
"read", "readref", 0};
if (cmd->tx_argc != 3)
TxError("Usage: %s write|writeall|read|readref filename\n", cmd->tx_argv[0]);
else
{
option = Lookup(cmd->tx_argv[1], cmdArchiveOpt);
if (option < 0)
{
TxError("Usage: %s write|writeall|read|readref filename\n", cmd->tx_argv[0]);
return;
}
}
filename = cmd->tx_argv[2];
switch(option) {
case 0: /* write */
DBWriteBackup(filename, TRUE, FALSE);
break;
case 1: /* writeall */
DBWriteBackup(filename, TRUE, TRUE);
break;
case 2: /* read */
DBReadBackup(filename, TRUE, TRUE);
break;
case 3: /* readref */
DBReadBackup(filename, TRUE, FALSE);
break;
}
}
/* Linked-list structure for returning information about arrayed cells */

View File

@ -3678,7 +3678,7 @@ cmdBevelFunc(
* Save cells to or recover cells from a crash backup file
*
* Usage:
* crash save|recover [file]
* crash save|recover|archive|read [file]
*
* Results:
* None.
@ -3713,7 +3713,7 @@ CmdCrash(
switch(option) {
case 0: /* save */
DBWriteBackup(filename);
DBWriteBackup(filename, FALSE, FALSE);
break;
case 1: /* recover */
DBFileRecovery(filename);

View File

@ -1186,7 +1186,7 @@ DBFileRecovery(filename)
switch(action)
{
case 0: /* Read */
if (DBReadBackup(DBbackupFile) == TRUE)
if (DBReadBackup(DBbackupFile, FALSE, TRUE) == TRUE)
DBRemoveBackup();
break;
case 1: /* Cancel */
@ -1222,24 +1222,38 @@ DBFileRecovery(filename)
*/
bool
DBReadBackup(name)
DBReadBackup(name, archive, usederef)
char *name; /* Name of the backup file */
bool archive; /* TRUE if this is an archive file */
bool usederef; /* If TRUE, then dereference all cells */
{
FILETYPE f;
char *filename, *rootname, *chrptr;
static const char *filetypes[] = {"archive", "backup", 0};
char *filename, *rootname, *chrptr, *suffix, *filetype;
char line[256];
CellDef *cellDef;
bool result = TRUE;
if ((f = PaZOpen(name, "r", NULL, "", NULL, NULL)) == NULL)
if (archive)
{
TxError("Cannot open backup file \"%s\"\n", name);
suffix = DBSuffix;
filetype = (char *)filetypes[0];
}
else
{
suffix = NULL;
filetype = (char *)filetypes[1];
}
if ((f = PaZOpen(name, "r", suffix, Path, NULL, NULL)) == NULL)
{
TxError("Cannot open %s file \"%s\"\n", filetype, name);
return FALSE;
}
if (dbFgets(line, sizeof(line), f) == NULL)
{
TxError("Bad backup file %s; can't restore!\n", name);
TxError("Bad %s file %s; can't read!\n", filetype, name);
return FALSE;
}
@ -1273,22 +1287,26 @@ DBReadBackup(name)
cellDef->cd_flags &= ~CDNOTFOUND;
cellDef->cd_flags |= CDAVAILABLE;
if (dbCellReadDef(f, cellDef, TRUE, FALSE) == FALSE)
if (dbCellReadDef(f, cellDef, TRUE, usederef) == FALSE)
return FALSE;
if (dbFgets(line, sizeof(line), f) == NULL)
{
TxError("Error in backup file %s; partial restore only!\n",
name);
TxError("Error in %s file %s; partial restore only!\n",
filetype, name);
return FALSE;
}
/* Update timestamp flags from dbCellReadDef() */
DBFlagMismatches(cellDef);
/* Update bounding boxes */
DBReComputeBbox(cellDef);
}
else
{
TxError("Error in backup file %s; expected keyword"
" \"file\", got \"%s\"!\n", name, line);
TxError("Error in %s file %s; expected keyword"
" \"file\", got \"%s\"!\n", filetype, name, line);
return FALSE;
}
}
@ -1299,6 +1317,7 @@ DBReadBackup(name)
*chrptr = '\0';
DBWreload(line + 4);
}
return TRUE;
}
@ -4107,6 +4126,10 @@ dbWritePaintCommandsFunc(tile, cdarg)
int diridx;
static const char *directionNames[] = {"nw", "se", "sw", "ne", 0};
/* Don't write out error tiles */
if ((type == TT_ERROR_P) || (type == TT_ERROR_S) || (type == TT_ERROR_PS))
return 0;
/* This could be refined by merging metal areas across contacts,
* but the brute force procedure will do the job.
*/
@ -4910,7 +4933,7 @@ DBGetTech(cellName)
static char line[512];
char *p;
f = PaZOpen(cellName, "r", DBSuffix, Path, CellLibPath, (char **) NULL);
f = PaZOpen(cellName, "r", DBSuffix, ".", CellLibPath, (char **) NULL);
if (f == NULL) return NULL;
p = (char *) NULL;
@ -4930,6 +4953,15 @@ ret:
return (p);
}
/* File and flags record used to hold information for dbWriteBackupFunc()
* in DBWriteBackup()
*/
typedef struct _fileAndFlags {
FILE *ff_file;
int ff_flags;
} FileAndFlags;
/*
* ----------------------------------------------------------------------------
*
@ -4943,6 +4975,13 @@ ret:
* is set to this name, erasing any previous value. If "filename" is
* an empty string, then the DBbackupFile reverts to NULL.
*
* If "archive" is TRUE, then save all read/write files, not just modified
* ones, and do not remove the file when magic exits.
*
* If "doforall" is TRUE, the save all files including read-only PDK
* cells. By definition, if "archive" is not chosen, then "doforall"
* has no impact, since read-only cells cannot be modified.
*
* Results:
* TRUE if the backup file was created, FALSE if an error was
* encountered.
@ -4956,25 +4995,39 @@ ret:
*/
bool
DBWriteBackup(filename)
DBWriteBackup(filename, archive, doforall)
char *filename;
bool archive;
bool doforall;
{
FILE *f;
int fd, pid;
char *tempdir;
char *tempdir, *saveName = NULL;
MagWindow *mw;
FileAndFlags ff;
int dbWriteBackupFunc(), dbCheckModifiedCellsFunc();
int flags = CDMODIFIED;
int flags = 0;
int result;
/* First check if there are any modified cells that need to be written */
result = DBCellSrDefs(flags, dbCheckModifiedCellsFunc, (ClientData)NULL);
if (result == 0) return TRUE; /* Nothing to write */
if (archive == FALSE)
{
flags = CDMODIFIED;
result = DBCellSrDefs(flags, dbCheckModifiedCellsFunc, (ClientData)NULL);
/*
* Avoid unnecessary backups: If there's nothing modified, then
* there's nothing to write.
*/
if (result == 0) return TRUE;
}
if (filename == NULL)
{
/* A NULL filename is used by the backup mechanism to save to /tmp/. */
if (DBbackupFile == (char *)NULL)
{
char *doslash, *template;
@ -5008,8 +5061,14 @@ DBWriteBackup(filename)
StrDup(&DBbackupFile, (char *)NULL);
return TRUE;
}
if (archive == TRUE)
{
TxPrintf("Created database archive file %s\n", filename);
saveName = StrDup((char **)NULL, DBbackupFile);
}
else
TxPrintf("Created database crash recovery file %s\n", DBbackupFile);
StrDup(&DBbackupFile, filename);
TxPrintf("Created database crash recovery file %s\n", DBbackupFile);
}
f = fopen(filename, "w");
@ -5019,7 +5078,15 @@ DBWriteBackup(filename)
return FALSE;
}
result = DBCellSrDefs(flags, dbWriteBackupFunc, (ClientData)f);
ff.ff_file = f;
/* Flags for recognizing which cells to ignore. Note that flags
* for recognizing which cells to search is in "flags".
*/
ff.ff_flags = CDINTERNAL | CDNOTFOUND;
if (!doforall) ff.ff_flags |= CDNOEDIT;
result = DBCellSrDefs(flags, dbWriteBackupFunc, (ClientData)&ff);
/* End by printing the keyword "end" followed by the cell to load */
/* into the first available window, so that we don't have a default */
@ -5031,6 +5098,17 @@ DBWriteBackup(filename)
else
fprintf(f, "end\n");
fclose(f);
/* If archiving, put DBbackupFile back to the name that it contained
* prior to doing the archive, so that the archive does not interfere
* with the backup mechanism.
*/
if (archive == TRUE)
{
StrDup(&DBbackupFile, saveName);
if (saveName)
freeMagic(saveName);
}
return TRUE;
}
@ -5042,14 +5120,18 @@ DBWriteBackup(filename)
*/
int
dbWriteBackupFunc(def, f)
dbWriteBackupFunc(def, clientData)
CellDef *def; /* Pointer to CellDef to be saved */
FILE *f; /* File to append to */
ClientData clientData;
{
char *name = def->cd_file;
int result, save_flags;
FileAndFlags *ff = (FileAndFlags *)clientData;
if (def->cd_flags & (CDINTERNAL | CDNOEDIT | CDNOTFOUND)) return 0;
FILE *f = ff->ff_file;
int flags = ff->ff_flags;
if (def->cd_flags & flags) return 0;
else if (!(def->cd_flags & CDAVAILABLE)) return 0;
if (name == NULL) name = def->cd_name;

View File

@ -38,7 +38,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
* Standard DBWind command set
*/
extern void CmdAddPath(), CmdAntennaCheck(), CmdArray();
extern void CmdAddPath(), CmdAntennaCheck(), CmdArchive(), CmdArray();
extern void CmdBox(), CmdCellname(), CmdClockwise();
extern void CmdContact(), CmdCopy(), CmdCorner();
extern void CmdCrash(), CmdCrosshair();
@ -228,6 +228,10 @@ DBWInitCommands()
"antennacheck [path] check for antenna violations",
CmdAntennaCheck, FALSE);
#endif
WindAddCommand(DBWclientID,
"archive write|read file\n"
" write or read the archive file \"file\".",
CmdArchive, FALSE);
WindAddCommand(DBWclientID,
"array xsize ysize OR\n"
"array xlo xhi ylo yhi\n"

67
doc/html/archive.html Normal file
View File

@ -0,0 +1,67 @@
<HTML>
<HEAD>
<STYLE type="text/css">
H1 {color: black }
H2 {color: maroon }
H3 {color: #007090 }
A.head:link {color: #0060a0 }
A.head:visited {color: #3040c0 }
A.head:active {color: white }
A.head:hover {color: yellow }
A.red:link {color: red }
A.red:visited {color: maroon }
A.red:active {color: yellow }
</STYLE>
</HEAD>
<TITLE>Magic-8.3 Command Reference</TITLE>
<BODY BACKGROUND=graphics/blpaper.gif>
<H1> <IMG SRC=graphics/magic_title8_3.png ALT="Magic VLSI Layout Tool Version 8.3">
<IMG SRC=graphics/magic_OGL_sm.gif ALIGN="top" ALT="*"> </H1>
<H2>archive</H2>
<HR>
Handle archive files
<HR>
<H3>Usage:</H3>
<BLOCKQUOTE>
<B>archive write</B> | <B>read</B> <I>filename</I> <BR><BR>
</BLOCKQUOTE>
<H3>Summary:</H3>
<BLOCKQUOTE>
The <B>archive</B> command handles archive files. The exact
operation depends on the option, and are outlined below:
<DL>
<DT> <B>archive write</B> <I>filename</I>
<DD> creates and writes to the file <I>filename</I> a copy of
the contents of all database cells. <P>
<DT> <B>archive read</B> <I>filename</I>
<DD> recovers the database from the contents of the saved archive
file <I>filename</I>. <P>
</DL>
</BLOCKQUOTE>
Archive files use the same format as crash recovery files, which is a
single file containing all database files with additional metadata
about the original location of each file.
<H3>Implementation Notes:</H3>
<BLOCKQUOTE>
<B>archive</B> is implemented as a built-in command in <B>magic</B>.
</BLOCKQUOTE>
<H3>See Also:</H3>
<BLOCKQUOTE>
<A HREF=crash.html><B>crash</B></A> <BR>
</BLOCKQUOTE>
<P><IMG SRC=graphics/line1.gif><P>
<TABLE BORDER=0>
<TR>
<TD> <A HREF=commands.html>Return to command index</A>
</TR>
</TABLE>
<P><I>Last updated:</I> January 12, 2021 at 10:10am <P>
</BODY>
</HTML>

View File

@ -362,184 +362,189 @@
cellpadding="5" bgcolor="#ccccff">
<TBODY>
<TR>
<TD> <A HREF=addcommandentry.html><B>addcommandentry</B></A><TD>
<TD> <A HREF=addpath.html> <B>addpath</B></A><TD>
<TD> <A HREF=antennacheck.html> <B>antennacheck</B></A><TD>
<TD> <A HREF=addcommandentry.html><B>addcommandentry</B></A></TD>
<TD> <A HREF=addpath.html> <B>addpath</B></A></TD>
<TD> <A HREF=antennacheck.html> <B>antennacheck</B></A></TD>
</TR>
<TR>
<TD> <A HREF=array.html> <B>array</B></A><TD>
<TD> <A HREF=box.html> <B>box</B></A><TD>
<TD> <A HREF=calma.html> <B>calma</B></A><TD>
<TD> <A HREF=archive.html> <B>array</B></A></TD>
<TD> <A HREF=array.html> <B>array</B></A></TD>
<TD> <A HREF=box.html> <B>box</B></A></TD>
</TR>
<TR>
<TD> <A HREF=caption.html> <B>caption</B></A><TD>
<TD> <A HREF=cellmanager.html> <B>cellmanager</B></A><TD>
<TD> <A HREF=cellname.html> <B>cellname</B></A><TD>
<TD> <A HREF=calma.html> <B>calma</B></A></TD>
<TD> <A HREF=caption.html> <B>caption</B></A></TD>
<TD> <A HREF=cellmanager.html> <B>cellmanager</B></A></TD>
</TR>
<TR>
<TD> <A HREF=cellsearch.html> <B>cellsearch</B></A><TD>
<TD> <A HREF=channels.html> <B>channels</B></A><TD>
<TD> <A HREF=cif.html> <B>cif</B></A><TD>
<TD> <A HREF=cellname.html> <B>cellname</B></A></TD>
<TD> <A HREF=cellsearch.html> <B>cellsearch</B></A></TD>
<TD> <A HREF=channels.html> <B>channels</B></A></TD>
</TR>
<TR>
<TD> <A HREF=clockwise.html> <B>clockwise</B></A><TD>
<TD> <A HREF=closewrapper.html> <B>closewrapper</B></A><TD>
<TD> <A HREF=contact.html> <B>contact</B></A><TD>
<TD> <A HREF=cif.html> <B>cif</B></A></TD>
<TD> <A HREF=clockwise.html> <B>clockwise</B></A></TD>
<TD> <A HREF=closewrapper.html> <B>closewrapper</B></A></TD>
</TR>
<TR>
<TD> <A HREF=copy.html> <B>copy</B></A><TD>
<TD> <A HREF=corner.html> <B>corner</B></A><TD>
<TD> <A HREF=crash.html> <B>crash</B></A><TD>
<TD> <A HREF=contact.html> <B>contact</B></A></TD>
<TD> <A HREF=copy.html> <B>copy</B></A></TD>
<TD> <A HREF=corner.html> <B>corner</B></A></TD>
</TR>
<TR>
<TD> <A HREF=crashbackups.html> <B>crashbackups</B></A><TD>
<TD> <A HREF=crosshair.html> <B>crosshair</B></A><TD>
<TD> <A HREF=def.html> <B>def</B></A><TD>
<TD> <A HREF=crash.html> <B>crash</B></A></TD>
<TD> <A HREF=crashbackups.html> <B>crashbackups</B></A></TD>
<TD> <A HREF=crosshair.html> <B>crosshair</B></A></TD>
</TR>
<TR>
<TD> <A HREF=delete.html> <B>delete</B></A><TD>
<TD> <A HREF=deletecommandentry.html> <B>deletecommandentry</B></A><TD>
<TD> <A HREF=down.html> <B>down</B></A><TD>
<TD> <A HREF=def.html> <B>def</B></A></TD>
<TD> <A HREF=delete.html> <B>delete</B></A></TD>
<TD> <A HREF=deletecommandentry.html> <B>deletecommandentry</B></A></TD>
</TR>
<TR>
<TD> <A HREF=drc.html> <B>drc</B></A><TD>
<TD> <A HREF=dump.html> <B>dump</B></A><TD>
<TD> <A HREF=edit.html> <B>edit</B></A><TD>
<TD> <A HREF=down.html> <B>down</B></A></TD>
<TD> <A HREF=drc.html> <B>drc</B></A></TD>
<TD> <A HREF=dump.html> <B>dump</B></A></TD>
</TR>
<TR>
<TD> <A HREF=element.html> <B>element</B></A><TD>
<TD> <A HREF=erase.html> <B>erase</B></A><TD>
<TD> <A HREF=expand.html> <B>expand</B></A><TD>
<TD> <A HREF=edit.html> <B>edit</B></A></TD>
<TD> <A HREF=element.html> <B>element</B></A></TD>
<TD> <A HREF=erase.html> <B>erase</B></A></TD>
</TR>
<TR>
<TD> <A HREF=ext.html> <B>ext</B></A><TD>
<TD> <A HREF=ext2sim.html> <B>ext2sim</B></A><TD>
<TD> <A HREF=ext2spice.html> <B>ext2spice</B></A><TD>
<TD> <A HREF=expand.html> <B>expand</B></A></TD>
<TD> <A HREF=ext.html> <B>ext</B></A></TD>
<TD> <A HREF=ext2sim.html> <B>ext2sim</B></A></TD>
</TR>
<TR>
<TD> <A HREF=extract.html> <B>extract</B></A><TD>
<TD> <A HREF=extresist.html> <B>extresist</B></A><TD>
<TD> <A HREF=ext2sim.html> <B>exttosim</B></A><TD>
<TD> <A HREF=ext2spice.html> <B>ext2spice</B></A></TD>
<TD> <A HREF=extract.html> <B>extract</B></A></TD>
<TD> <A HREF=extresist.html> <B>extresist</B></A></TD>
</TR>
<TR>
<TD> <A HREF=ext2spice.html> <B>exttospice</B></A><TD>
<TD> <A HREF=feedback.html> <B>feedback</B></A><TD>
<TD> <A HREF=fill.html> <B>fill</B></A><TD>
<TD> <A HREF=ext2sim.html> <B>exttosim</B></A></TD>
<TD> <A HREF=ext2spice.html> <B>exttospice</B></A></TD>
<TD> <A HREF=feedback.html> <B>feedback</B></A></TD>
</TR>
<TR>
<TD> <A HREF=findbox.html> <B>findbox</B></A><TD>
<TD> <A HREF=findlabel.html> <B>findlabel</B></A><TD>
<TD> <A HREF=flatten.html> <B>flatten</B></A><TD>
<TD> <A HREF=fill.html> <B>fill</B></A></TD>
<TD> <A HREF=findbox.html> <B>findbox</B></A></TD>
<TD> <A HREF=findlabel.html> <B>findlabel</B></A></TD>
</TR>
<TR>
<TD> <A HREF=flush.html> <B>flush</B></A><TD>
<TD> <A HREF=garoute.html> <B>garoute</B></A><TD>
<TD> <A HREF=gds.html> <B>gds</B></A><TD>
<TD> <A HREF=flatten.html> <B>flatten</B></A></TD>
<TD> <A HREF=flush.html> <B>flush</B></A></TD>
<TD> <A HREF=garoute.html> <B>garoute</B></A></TD>
</TR>
<TR>
<TD> <A HREF=get.html> <B>get</B></A><TD>
<TD> <A HREF=getcell.html> <B>getcell</B></A><TD>
<TD> <A HREF=getnode.html> <B>getnode</B></A><TD>
<TD> <A HREF=gds.html> <B>gds</B></A></TD>
<TD> <A HREF=get.html> <B>get</B></A></TD>
<TD> <A HREF=getcell.html> <B>getcell</B></A></TD>
</TR>
<TR>
<TD> <A HREF=goto.html> <B>goto</B></A><TD>
<TD> <A HREF=grid.html> <B>grid</B></A><TD>
<TD> <A HREF=help.html> <B>help</B></A><TD>
<TD> <A HREF=getnode.html> <B>getnode</B></A></TD>
<TD> <A HREF=goto.html> <B>goto</B></A></TD>
<TD> <A HREF=grid.html> <B>grid</B></A></TD>
</TR>
<TR>
<TD> <A HREF=identify.html> <B>identify</B></A><TD>
<TD> <A HREF=initialize.html> <B>initialize</B></A><TD>
<TD> <A HREF=instance.html> <B>instance</B></A><TD>
<TD> <A HREF=help.html> <B>help</B></A></TD>
<TD> <A HREF=identify.html> <B>identify</B></A></TD>
<TD> <A HREF=initialize.html> <B>initialize</B></A></TD>
</TR>
<TR>
<TD> <A HREF=iroute.html> <B>iroute</B></A><TD>
<TD> <A HREF=irsim.html> <B>irsim</B></A><TD>
<TD> <A HREF=label.html> <B>label</B></A><TD>
<TD> <A HREF=instance.html> <B>instance</B></A></TD>
<TD> <A HREF=iroute.html> <B>iroute</B></A></TD>
<TD> <A HREF=irsim.html> <B>irsim</B></A></TD>
</TR>
<TR>
<TD> <A HREF=lef.html> <B>lef</B></A><TD>
<TD> <A HREF=load.html> <B>load</B></A><TD>
<TD> <A HREF=maketoolbar.html> <B>maketoolbar</B></A><TD>
<TD> <A HREF=label.html> <B>label</B></A></TD>
<TD> <A HREF=lef.html> <B>lef</B></A></TD>
<TD> <A HREF=load.html> <B>load</B></A></TD>
</TR>
<TR>
<TD> <A HREF=move.html> <B>move</B></A><TD>
<TD> <A HREF=measure.html> <B>measure</B></A><TD>
<TD> <A HREF=openwrapper.html> <B>openwrapper</B></A><TD>
<TD> <A HREF=maketoolbar.html> <B>maketoolbar</B></A></TD>
<TD> <A HREF=move.html> <B>move</B></A></TD>
<TD> <A HREF=measure.html> <B>measure</B></A></TD>
</TR>
<TR>
<TD> <A HREF=paint.html> <B>paint</B></A><TD>
<TD> <A HREF=path.html> <B>path</B></A><TD>
<TD> <A HREF=peekbox.html> <B>peekbox</B></A><TD>
<TD> <A HREF=openwrapper.html> <B>openwrapper</B></A></TD>
<TD> <A HREF=paint.html> <B>paint</B></A></TD>
<TD> <A HREF=path.html> <B>path</B></A></TD>
</TR>
<TR>
<TD> <A HREF=plot.html> <B>plot</B></A><TD>
<TD> <A HREF=plow.html> <B>plow</B></A><TD>
<TD> <A HREF=polygon.html> <B>polygon</B></A><TD>
<TD> <A HREF=peekbox.html> <B>peekbox</B></A></TD>
<TD> <A HREF=plot.html> <B>plot</B></A></TD>
<TD> <A HREF=plow.html> <B>plow</B></A></TD>
</TR>
<TR>
<TD> <A HREF=popbox.html> <B>popbox</B></A><TD>
<TD> <A HREF=popstack.html> <B>popstack</B></A><TD>
<TD> <A HREF=port.html> <B>port</B></A><TD>
<TD> <A HREF=polygon.html> <B>polygon</B></A></TD>
<TD> <A HREF=popbox.html> <B>popbox</B></A></TD>
<TD> <A HREF=popstack.html> <B>popstack</B></A></TD>
</TR>
<TR>
<TD> <A HREF=promptload.html> <B>promptload</B></A><TD>
<TD> <A HREF=promptsave.html> <B>promptsave</B></A><TD>
<TD> <A HREF=property.html> <B>property</B></A><TD>
<TD> <A HREF=port.html> <B>port</B></A></TD>
<TD> <A HREF=promptload.html> <B>promptload</B></A></TD>
<TD> <A HREF=promptsave.html> <B>promptsave</B></A></TD>
</TR>
<TR>
<TD> <A HREF=pushbox.html> <B>pushbox</B></A><TD>
<TD> <A HREF=pushstack.html> <B>pushstack</B></A><TD>
<TD> <A HREF=render3d.html> <B>render3d</B></A><TD>
<TD> <A HREF=property.html> <B>property</B></A></TD>
<TD> <A HREF=pushbox.html> <B>pushbox</B></A></TD>
<TD> <A HREF=pushstack.html> <B>pushstack</B></A></TD>
</TR>
<TR>
<TD> <A HREF=resumeall.html> <B>resumeall</B></A><TD>
<TD> <A HREF=rotate.html> <B>rotate</B></A><TD>
<TD> <A HREF=route.html> <B>route</B></A><TD>
<TD> <A HREF=render3d.html> <B>render3d</B></A></TD>
<TD> <A HREF=resumeall.html> <B>resumeall</B></A></TD>
<TD> <A HREF=rotate.html> <B>rotate</B></A></TD>
</TR>
<TR>
<TD> <A HREF=save.html> <B>save</B></A><TD>
<TD> <A HREF=scalegrid.html> <B>scalegrid</B></A><TD>
<TD> <A HREF=search.html> <B>search</B></A><TD>
<TD> <A HREF=route.html> <B>route</B></A></TD>
<TD> <A HREF=save.html> <B>save</B></A></TD>
<TD> <A HREF=scalegrid.html> <B>scalegrid</B></A></TD>
</TR>
<TR>
<TD> <A HREF=see.html> <B>see</B></A><TD>
<TD> <A HREF=select.html> <B>select</B></A><TD>
<TD> <A HREF=setlabel.html> <B>setlabel</B> <I>(version 8.0)</I></A><TD>
<TD> <A HREF=search.html> <B>search</B></A></TD>
<TD> <A HREF=see.html> <B>see</B></A></TD>
<TD> <A HREF=select.html> <B>select</B></A></TD>
</TR>
<TR>
<TD> <A HREF=shell.html> <B>shell</B></A><TD>
<TD> <A HREF=sideways.html> <B>sideways</B></A><TD>
<TD> <A HREF=snap.html> <B>snap</B></A><TD>
<TD> <A HREF=setlabel.html> <B>setlabel</B> <I>(version 8.0)</I></A></TD>
<TD> <A HREF=shell.html> <B>shell</B></A></TD>
<TD> <A HREF=sideways.html> <B>sideways</B></A></TD>
</TR>
<TR>
<TD> <A HREF=spliterase.html> <B>spliterase</B></A><TD>
<TD> <A HREF=splitpaint.html> <B>splitpaint</B></A><TD>
<TD> <A HREF=startup.html> <B>startup</B></A><TD>
<TD> <A HREF=snap.html> <B>snap</B></A></TD>
<TD> <A HREF=spliterase.html> <B>spliterase</B></A></TD>
<TD> <A HREF=splitpaint.html> <B>splitpaint</B></A></TD>
</TR>
<TR>
<TD> <A HREF=straighten.html> <B>straighten</B></A><TD>
<TD> <A HREF=stretch.html> <B>stretch</B></A><TD>
<TD> <A HREF=suspendall.html> <B>suspendall</B></A><TD>
<TD> <A HREF=startup.html> <B>startup</B></A></TD>
<TD> <A HREF=straighten.html> <B>straighten</B></A></TD>
<TD> <A HREF=stretch.html> <B>stretch</B></A></TD>
</TR>
<TR>
<TD> <A HREF=tag.html> <B>tag</B></A><TD>
<TD> <A HREF=tech.html> <B>tech</B></A><TD>
<TD> <A HREF=techmanager.html> <B>techmanager</B></A><TD>
<TD> <A HREF=suspendall.html> <B>suspendall</B></A></TD>
<TD> <A HREF=tag.html> <B>tag</B></A></TD>
<TD> <A HREF=tech.html> <B>tech</B></A></TD>
</TR>
<TR>
<TD> <A HREF=tool.html> <B>tool</B> <I>(non-Tcl version)</I></A><TD>
<TD> <A HREF=changetool.html> <B>tool</B> <I>(Tcl version)</I></A><TD>
<TD> <A HREF=unexpand.html> <B>unexpand</B></A><TD>
<TD> <A HREF=techmanager.html> <B>techmanager</B></A></TD>
<TD> <A HREF=tool.html> <B>tool</B> <I>(non-Tcl version)</I></A></TD>
<TD> <A HREF=changetool.html> <B>tool</B> <I>(Tcl version)</I></A></TD>
</TR>
<TR>
<TD> <A HREF=unmeasure.html> <B>unmeasure</B></A><TD>
<TD> <A HREF=upsidedown.html> <B>upsidedown</B></A><TD>
<TD> <A HREF=what.html> <B>what</B></A><TD>
<TD> <A HREF=unexpand.html> <B>unexpand</B></A></TD>
<TD> <A HREF=unmeasure.html> <B>unmeasure</B></A></TD>
<TD> <A HREF=upsidedown.html> <B>upsidedown</B></A></TD>
</TR>
<TR>
<TD> <A HREF=wire.html> <B>wire</B></A><TD>
<TD> <A HREF=writeall.html> <B>writeall</B></A><TD>
<TD> <A HREF=xload.html> <B>xload</B></A><TD>
<TD> <A HREF=what.html> <B>what</B></A></TD>
<TD> <A HREF=wire.html> <B>wire</B></A></TD>
<TD> <A HREF=writeall.html> <B>writeall</B></A></TD>
</TR>
<TR>
<TD> <A HREF=xload.html> <B>xload</B></A></TD>
<TD> </TD>
<TD> </TD>
</TR>
</TBODY>
</TABLE>
@ -551,38 +556,38 @@
cellpadding="5" bgcolor="#ffcccc">
<TBODY>
<TR>
<TD> <A HREF=netlist/add.html><B>add</B></A><TD>
<TD> <A HREF=netlist/cleanup.html><B>cleanup</B></A><TD>
<TD> <A HREF=netlist/cull.html><B>cull</B></A><TD>
<TD> <A HREF=netlist/add.html><B>add</B></A></TD>
<TD> <A HREF=netlist/cleanup.html><B>cleanup</B></A></TD>
<TD> <A HREF=netlist/cull.html><B>cull</B></A></TD>
</TR>
<TR>
<TD> <A HREF=netlist/dnet.html><B>dnet</B></A><TD>
<TD> <A HREF=netlist/dterm.html><B>dterm</B></A><TD>
<TD> <A HREF=netlist/extract.html><B>extract</B></A><TD>
<TD> <A HREF=netlist/dnet.html><B>dnet</B></A></TD>
<TD> <A HREF=netlist/dterm.html><B>dterm</B></A></TD>
<TD> <A HREF=netlist/extract.html><B>extract</B></A></TD>
</TR>
<TR>
<TD> <A HREF=netlist/find.html><B>find</B></A><TD>
<TD> <A HREF=netlist/flush.html><B>flush</B></A><TD>
<TD> <A HREF=netlist/join.html><B>join</B></A><TD>
<TD> <A HREF=netlist/find.html><B>find</B></A></TD>
<TD> <A HREF=netlist/flush.html><B>flush</B></A></TD>
<TD> <A HREF=netlist/join.html><B>join</B></A></TD>
</TR>
<TR>
<TD> <A HREF=netlist/netlist.html><B>netlist</B></A><TD>
<TD> <A HREF=netlist/orient.html><B>orient</B></A><TD>
<TD> <A HREF=netlist/pushbutton.html><B>pushbutton</B></A><TD>
<TD> <A HREF=netlist/netlist.html><B>netlist</B></A></TD>
<TD> <A HREF=netlist/orient.html><B>orient</B></A></TD>
<TD> <A HREF=netlist/pushbutton.html><B>pushbutton</B></A></TD>
</TR>
<TR>
<TD> <A HREF=netlist/print.html><B>print</B></A><TD>
<TD> <A HREF=netlist/ripup.html><B>ripup</B></A><TD>
<TD> <A HREF=netlist/savenetlist.html><B>savenetlist</B></A><TD>
<TD> <A HREF=netlist/print.html><B>print</B></A></TD>
<TD> <A HREF=netlist/ripup.html><B>ripup</B></A></TD>
<TD> <A HREF=netlist/savenetlist.html><B>savenetlist</B></A></TD>
</TR>
<TR>
<TD> <A HREF=netlist/shownet.html><B>shownet</B></A><TD>
<TD> <A HREF=netlist/showterms.html><B>showterms</B></A><TD>
<TD> <A HREF=netlist/trace.html><B>trace</B></A><TD>
<TD> <A HREF=netlist/shownet.html><B>shownet</B></A></TD>
<TD> <A HREF=netlist/showterms.html><B>showterms</B></A></TD>
<TD> <A HREF=netlist/trace.html><B>trace</B></A></TD>
</TR>
<TR>
<TD> <A HREF=netlist/verify.html><B>verify</B></A><TD>
<TD> <A HREF=netlist/writeall.html><B>writeall</B></A><TD>
<TD> <A HREF=netlist/verify.html><B>verify</B></A></TD>
<TD> <A HREF=netlist/writeall.html><B>writeall</B></A></TD>
<TD></TD>
</TR>
</TBODY>
@ -595,24 +600,24 @@
cellpadding="5" bgcolor="#ccffcc">
<TBODY>
<TR>
<TD> <A HREF=wind3d/cif.html><B>cif</B></A><TD>
<TD> <A HREF=wind3d/closewindow.html><B>closewindow</B></A><TD>
<TD> <A HREF=wind3d/cutbox.html><B>cutbox</B></A><TD>
<TD> <A HREF=wind3d/cif.html><B>cif</B></A></TD>
<TD> <A HREF=wind3d/closewindow.html><B>closewindow</B></A></TD>
<TD> <A HREF=wind3d/cutbox.html><B>cutbox</B></A></TD>
</TR>
<TR>
<TD> <A HREF=wind3d/defaults.html><B>defaults</B></A><TD>
<TD> <A HREF=wind3d/help.html><B>help</B></A><TD>
<TD> <A HREF=wind3d/level.html><B>level</B></A><TD>
<TD> <A HREF=wind3d/defaults.html><B>defaults</B></A></TD>
<TD> <A HREF=wind3d/help.html><B>help</B></A></TD>
<TD> <A HREF=wind3d/level.html><B>level</B></A></TD>
</TR>
<TR>
<TD> <A HREF=wind3d/refresh.html><B>refresh</B></A><TD>
<TD> <A HREF=wind3d/render.html><B>render</B></A><TD>
<TD> <A HREF=wind3d/scroll.html><B>scroll</B></A><TD>
<TD> <A HREF=wind3d/refresh.html><B>refresh</B></A></TD>
<TD> <A HREF=wind3d/render.html><B>render</B></A></TD>
<TD> <A HREF=wind3d/scroll.html><B>scroll</B></A></TD>
</TR>
<TR>
<TD> <A HREF=wind3d/see.html><B>see</B></A><TD>
<TD> <A HREF=wind3d/view.html><B>view</B></A><TD>
<TD> <A HREF=wind3d/zoom.html><B>zoom</B></A><TD>
<TD> <A HREF=wind3d/see.html><B>see</B></A></TD>
<TD> <A HREF=wind3d/view.html><B>view</B></A></TD>
<TD> <A HREF=wind3d/zoom.html><B>zoom</B></A></TD>
</TR>
</TBODY>
</TABLE>
@ -624,12 +629,12 @@
cellpadding="5" bgcolor="#ffccff">
<TBODY>
<TR>
<TD> <A HREF=color/pushbutton.html><B>pushbutton</B></A><TD>
<TD> <A HREF=color/color.html><B>color</B></A><TD>
<TD> <A HREF=color/load.html><B>load</B></A><TD>
<TD> <A HREF=color/pushbutton.html><B>pushbutton</B></A></TD>
<TD> <A HREF=color/color.html><B>color</B></A></TD>
<TD> <A HREF=color/load.html><B>load</B></A></TD>
</TR>
<TR>
<TD> <A HREF=color/save.html><B>save</B></A><TD>
<TD> <A HREF=color/save.html><B>save</B></A></TD>
<TD></TD>
<TD></TD>
</TR>
@ -643,19 +648,19 @@
cellpadding="5" bgcolor="#ffffcc">
<TBODY>
<TR>
<TD> <A HREF=wizard/bypass.html><B>*bypass</B></A><TD>
<TD> <A HREF=wizard/coord.html><B>*coord</B></A><TD>
<TD> <A HREF=wizard/extract.html><B>*extract</B></A><TD>
<TD> <A HREF=wizard/bypass.html><B>*bypass</B></A></TD>
<TD> <A HREF=wizard/coord.html><B>*coord</B></A></TD>
<TD> <A HREF=wizard/extract.html><B>*extract</B></A></TD>
</TR>
<TR>
<TD> <A HREF=wizard/plow.html><B>*plow</B></A><TD>
<TD> <A HREF=wizard/psearch.html><B>*psearch</B></A><TD>
<TD> <A HREF=wizard/showtech.html><B>*showtech</B></A><TD>
<TD> <A HREF=wizard/plow.html><B>*plow</B></A></TD>
<TD> <A HREF=wizard/psearch.html><B>*psearch</B></A></TD>
<TD> <A HREF=wizard/showtech.html><B>*showtech</B></A></TD>
</TR>
<TR>
<TD> <A HREF=wizard/tilestats.html><B>*tilestats</B></A><TD>
<TD> <A HREF=wizard/tsearch.html><B>*tsearch</B></A><TD>
<TD> <A HREF=wizard/watch.html><B>*watch</B></A><TD>
<TD> <A HREF=wizard/tilestats.html><B>*tilestats</B></A></TD>
<TD> <A HREF=wizard/tsearch.html><B>*tsearch</B></A></TD>
<TD> <A HREF=wizard/watch.html><B>*watch</B></A></TD>
</TR>
</TBODY>
</TABLE>
@ -667,14 +672,14 @@
cellpadding="5" bgcolor="#cccccc">
<TBODY>
<TR>
<TD> <A HREF=wizard/crash.html><B>*crash</B></A><TD>
<TD> <A HREF=wizard/files.html><B>*files</B></A><TD>
<TD> <A HREF=wizard/grstats.html><B>*grstats</B></A><TD>
<TD> <A HREF=wizard/crash.html><B>*crash</B></A></TD>
<TD> <A HREF=wizard/files.html><B>*files</B></A></TD>
<TD> <A HREF=wizard/grstats.html><B>*grstats</B></A></TD>
</TR>
<TR>
<TD> <A HREF=wizard/pause.html><B>*pause</B></A><TD>
<TD> <A HREF=wizard/winddebug.html><B>*winddebug</B></A><TD>
<TD> <A HREF=wizard/winddump.html><B>*winddump</B></A><TD>
<TD> <A HREF=wizard/pause.html><B>*pause</B></A></TD>
<TD> <A HREF=wizard/winddebug.html><B>*winddebug</B></A></TD>
<TD> <A HREF=wizard/winddump.html><B>*winddump</B></A></TD>
</TR>
</TBODY>
</TABLE>

View File

@ -1,6 +1,7 @@
addcommandentry
addpath
antennacheck
archive
array
box
calma

View File

@ -41,7 +41,15 @@ Save edit cell on disk
The <B>save</B> command differs from <B>writeall</B> in several
ways: <B>save</B> does not descend the hierarchy, and does not
prompt the user for an action.
prompt the user for an action. <P>
As of magic version 8.3.549, if <I>filename</I> ends with
"<B>.tcl</B>", then magic will save a script file containing
a sequence of magic command-line commands that completely
reproduces the file layout. The cell can then be regenerated
by sourcing the script. This is not a substitution for a
database (<B>.mag</B>) file, and magic will not normally
search for or source these type of script files itself. <P>
</BLOCKQUOTE>
<H3>Implementation Notes:</H3>