magic/extract/ExtMain.c

1004 lines
27 KiB
C

/*
* ExtMain.c --
*
* Circuit extraction.
* Command interface.
*
* *********************************************************************
* * 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/extract/ExtMain.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <math.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/styles.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "utils/malloc.h"
#include "textio/textio.h"
#include "debug/debug.h"
#include "extract/extract.h"
#include "extract/extractInt.h"
#include "utils/signals.h"
#include "utils/stack.h"
#include "utils/utils.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/main.h"
#include "utils/undo.h"
/* Imports from elsewhere in this module */
extern FILE *extFileOpen();
/* ------------------------ Exported variables ------------------------ */
/*
* See extract.h for the bit flags that may be set in the following.
* If any are set, the corresponding warnings get generated, leaving
* feedback messages. If this word is zero, only errors are
* reported.
*/
int ExtDoWarn = EXTWARN_DUP|EXTWARN_FETS;
int ExtOptions = EXT_DOALL|EXT_DOLABELCHECK;
/* --------------------------- Global data ---------------------------- */
/* Cumulative yank buffer for hierarchical circuit extraction */
CellUse *extYuseCum = NULL;
CellDef *extYdefCum = NULL;
/* Identifier returned by the debug module for circuit extraction */
ClientData extDebugID;
/* Number of errors encountered during extraction */
int extNumErrors;
int extNumWarnings;
/* Dummy use pointing to def being extracted */
CellUse *extParentUse;
/* ------------------------ Data local to this file ------------------- */
typedef struct _linkedDef {
CellDef *ld_def;
struct _linkedDef *ld_next;
} LinkedDef;
/* Linked list structure to use to store the substrate plane from each */
/* extracted CellDef so that they can be returned to the original after */
/* extraction. */
struct saveList {
Plane *sl_plane;
CellDef *sl_def;
struct saveList *sl_next;
};
/* Stack of defs pending extraction */
Stack *extDefStack;
/* Forward declarations */
int extDefInitFunc();
void extDefPush();
void extDefIncremental();
void extParents();
void extDefParentFunc();
void extDefParentAreaFunc();
void extExtractStack();
bool extContainsGeometry();
bool extContainsCellFunc();
bool extTimestampMisMatch();
/*
* ----------------------------------------------------------------------------
*
* ExtInit --
*
* Initialize the technology-independent part of the extraction module.
* This procedure should be called once, after the database module has
* been initialized.
*
* Results:
* None.
*
* Side effects:
* Initializes the local variables of the extraction module.
* Registers the extractor with the debugging module.
*
* ----------------------------------------------------------------------------
*/
void
ExtInit()
{
int n;
static struct
{
char *di_name;
int *di_id;
} debugFlags[] = {
"areaenum", &extDebAreaEnum,
"array", &extDebArray,
"hardway", &extDebHardWay,
"hiercap", &extDebHierCap,
"hierareacap", &extDebHierAreaCap,
"label", &extDebLabel,
"length", &extDebLength,
"neighbor", &extDebNeighbor,
"noarray", &extDebNoArray,
"nofeedback", &extDebNoFeedback,
"nohard", &extDebNoHard,
"nosubcell", &extDebNoSubcell,
"perimeter", &extDebPerim,
"resist", &extDebResist,
"visonly", &extDebVisOnly,
"yank", &extDebYank,
0
};
/* Register ourselves with the debugging module */
extDebugID =
DebugAddClient("extract", sizeof debugFlags/sizeof debugFlags[0]);
for (n = 0; debugFlags[n].di_name; n++)
*(debugFlags[n].di_id) =
DebugAddFlag(extDebugID, debugFlags[n].di_name);
/* Create the yank buffer used for hierarchical extraction */
DBNewYank("__ext_cumulative", &extYuseCum, &extYdefCum);
/* Create the dummy use also used in hierarchical extraction */
extParentUse = DBCellNewUse(extYdefCum, (char *) NULL);
DBSetTrans(extParentUse, &GeoIdentityTransform);
/* Initialize the hash tables used in ExtLength.c */
extLengthInit();
}
/*
* ----------------------------------------------------------------------------
*
* Simple callback returns 1 if any cell is not marked with the CDDONTUSE
* flag. If DBCellEnum() returns 0 then all children of the CellDef are
* marked CDDONTUSE.
*
* ----------------------------------------------------------------------------
*/
int
extIsUsedFunc(use, clientData)
CellUse *use;
ClientData clientData; /* unused */
{
CellDef *def = use->cu_def;
/* If any cell is not marked CDDONTUSE then return 1 and stop the search. */
if (!(def->cd_flags & CDDONTUSE)) return 1;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* Simple callback returns 1 if any non-space tile is found in a cell.
* Used to determine if a cell does not need extracting because it is
* an empty placeholder cell created when flattening part of a vendor
* GDS, and exists only to reference the GDS file location for writing
* GDS.
*
* ----------------------------------------------------------------------------
*/
int
extEnumFunc(tile, plane)
Tile *tile;
int *plane;
{
return 1;
}
/*
* ----------------------------------------------------------------------------
*
* ----------------------------------------------------------------------------
*/
int
extDefListFunc(use, defList)
CellUse *use;
LinkedDef **defList;
{
CellDef *def = use->cu_def;
LinkedDef *newLD;
/* Ignore all internal cells and cells that are marked "don't use" */
if (def->cd_flags & (CDINTERNAL | CDDONTUSE)) return 0;
/* Recurse to the bottom first */
(void) DBCellEnum(def, extDefListFunc, (ClientData)defList);
/* Don't add cells that have already been visited */
if (def->cd_client) return 0;
/* Mark self as visited */
def->cd_client = (ClientData) 1;
/* Check if all descendents are marked as "don't use" */
if (DBCellEnum(def, extIsUsedFunc, (ClientData)NULL) == 0)
{
int plane;
/* Nothing below this cell had anything to extract. */
/* Check this cell for paint. If it has none, then */
/* ignore it. */
for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
if (DBSrPaintArea((Tile *)NULL, def->cd_planes[plane], &TiPlaneRect,
&DBAllButSpaceAndDRCBits, extEnumFunc, (ClientData)NULL))
break;
if (plane == DBNumPlanes)
{
/* Cell has no material. Mark it and return. */
def->cd_flags |= CDDONTUSE;
return 0;
}
}
/* When done with descendents, add self to the linked list */
newLD = (LinkedDef *)mallocMagic(sizeof(LinkedDef));
newLD->ld_def = def;
newLD->ld_next = *defList;
*defList = newLD;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* ----------------------------------------------------------------------------
*/
int
extDefListFuncIncremental(use, defList)
CellUse *use;
LinkedDef **defList;
{
CellDef *def = use->cu_def;
LinkedDef *newLD;
/* Ignore all internal cells and cells marked "don't use" */
if (def->cd_flags & (CDINTERNAL | CDDONTUSE)) return 0;
/* Mark cells that don't need updating */
if (!extTimestampMisMatch(def))
def->cd_flags |= CDNOEXTRACT;
/* Recurse to the bottom first */
(void) DBCellEnum(def, extDefListFuncIncremental, (ClientData)defList);
/* Don't add cells that have already been visited */
if (def->cd_client) return 0;
/* Mark self as visited */
def->cd_client = (ClientData) 1;
/* Check if all descendents are marked as "don't use" */
if (DBCellEnum(def, extIsUsedFunc, (ClientData)NULL) == 0)
{
int plane;
/* Nothing below this cell had anything to extract. */
/* Check this cell for paint. If it has none, then */
/* ignore it. */
for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
if (DBSrPaintArea((Tile *)NULL, def->cd_planes[plane], &TiPlaneRect,
&DBAllButSpaceAndDRCBits, extEnumFunc, (ClientData)NULL))
break;
if (plane == DBNumPlanes)
{
/* Cell has no material. Mark it and return. */
def->cd_flags |= CDDONTUSE;
return 0;
}
}
/* When done with descendents, add self to the linked list */
newLD = (LinkedDef *)mallocMagic(sizeof(LinkedDef));
newLD->ld_def = def;
newLD->ld_next = *defList;
*defList = newLD;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* ExtAll --
*
* Extract the subtree rooted at the CellDef 'rootUse->cu_def'.
* Each cell is extracted to a file in the current directory
* whose name consists of the last part of the cell's path,
* with a .ext suffix.
*
* Results:
* None.
*
* Side effects:
* Creates a number of .ext files and writes to them.
* Adds feedback information where errors have occurred.
*
* ----------------------------------------------------------------------------
*/
void
ExtAll(rootUse)
CellUse *rootUse;
{
LinkedDef *defList = NULL;
/* Make sure the entire subtree is read in */
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
{
TxError("Failure to read entire subtree of cell.\n");
return;
}
/* Fix up bounding boxes if they've changed */
DBFixMismatch();
/* Mark all defs as being unvisited */
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
/* Recursively visit all defs in the tree and create a linked list */
/* from bottommost back up to the top. */
extDefListFunc(rootUse, &defList);
/* Now reverse the list onto a stack such that the bottommost cell */
/* is the first to be extracted, and so forth back up to the top. */
extDefStack = StackNew(100);
extDefPush(defList);
/* Now extract all the cells we just found */
extExtractStack(extDefStack, TRUE, rootUse->cu_def);
StackFree(extDefStack);
}
/*
* Function to initialize the client data field of all
* cell defs, in preparation for extracting a subtree
* rooted at a particular def.
*/
int
extDefInitFunc(def)
CellDef *def;
{
def->cd_client = (ClientData) 0;
return (0);
}
/*
* Function to reverse the linked list of CellDefs to extract by
* pushing each cell def from the list onto extDefStack.
*/
void
extDefPush(defList)
LinkedDef *defList;
{
while (defList != NULL)
{
StackPush((ClientData)defList->ld_def, extDefStack);
freeMagic(defList);
defList = defList->ld_next;
}
}
/*
* ----------------------------------------------------------------------------
*
* ExtUnique --
*
* For each cell in the subtree rooted at rootUse->cu_def, make
* sure that there are not two different nodes with the same label.
* If there are, we generate unique names by appending a numeric
* suffix to all but one of the offending labels.
* If "option" is 1 (tagged mode), then only labels ending in the
* character "#" are forced to be unique. If "option" is 2 ("noports"
* mode), then port labels are not forced to be unique. If "option"
* is 3 ("notopports" mode), then port labels on the top level are
* not forced to be unique. Finally, if the label has been changed
* and doesn't end in a '!', we leave feedback.
*
* Results:
* None.
*
* Side effects:
* May modify the label lists of some of the cells rooted
* at rootUse->cu_def, and mark the cells as CDMODIFIED.
* May also leave feedback.
*
* ----------------------------------------------------------------------------
*/
void
ExtUnique(rootUse, option)
CellUse *rootUse;
int option;
{
CellDef *def;
LinkedDef *defList = NULL;
int nwarn;
int locoption;
/* Make sure the entire subtree is read in */
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
{
TxError("Failure to read entire subtree of cell.\n");
return;
}
/* Fix up bounding boxes if they've changed */
DBFixMismatch();
/* Mark all defs as being unvisited */
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
/* Recursively visit all defs in the tree and create a linked list */
/* from bottommost back up to the top. */
extDefListFunc(rootUse, &defList);
/* Now reverse the list onto a stack such that the bottommost cell */
/* is the first to be extracted, and so forth back up to the top. */
extDefStack = StackNew(100);
extDefPush(defList);
/* Now process all the cells we just found */
nwarn = 0;
while (def = (CellDef *) StackPop(extDefStack))
{
/* EXT_UNIQ_NOTOPPORTS: Use EXT_UNIQ_ALL on all cells other than the top */
if ((option == EXT_UNIQ_NOTOPPORTS) &&
(StackLook(extDefStack) != (ClientData)NULL))
locoption = EXT_UNIQ_ALL;
else
locoption = option;
def->cd_client = (ClientData) 0;
if (!SigInterruptPending)
nwarn += extUniqueCell(def, locoption);
}
StackFree(extDefStack);
if (nwarn)
TxError("%d uncorrected errors (see the feedback info)\n", nwarn);
}
/*
* ----------------------------------------------------------------------------
*
* ExtParents --
* ExtShowParents --
*
* ExtParents extracts the cell use->cu_def and all its parents.
* ExtShowParents merely finds and prints all the parents without
* extracting them.
*
* As in ExtAll, each cell is extracted to a file in the current
* directory whose name consists of the last part of the cell's path,
* with a .ext suffix.
*
* Results:
* None.
*
* Side effects:
* Creates a number of .ext files and writes to them.
* Adds feedback information where errors have occurred.
*
* ----------------------------------------------------------------------------
*/
void
ExtParents(use)
CellUse *use;
{
extParents(use, TRUE);
}
void
ExtShowParents(use)
CellUse *use;
{
extParents(use, FALSE);
}
void
extParents(use, doExtract)
CellUse *use;
bool doExtract; /* If TRUE, we extract; if FALSE, we print */
{
LinkedDef *defList = NULL;
CellDef *def;
Plane *saveSub;
struct saveList *newsl, *sl = (struct saveList *)NULL;
/* Mark all defs as being unvisited */
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
/* All children of use->cu_def need substrate preparation */
extDefListFunc(use, &defList);
/* use->cu_def is on the top of the list, so remove it */
freeMagic(defList);
defList = defList->ld_next;
while (defList != NULL)
{
def = defList->ld_def;
saveSub = extPrepSubstrate(def);
if (saveSub != NULL)
{
newsl = (struct saveList *)mallocMagic(sizeof(struct saveList));
newsl->sl_plane = saveSub;
newsl->sl_def = def;
newsl->sl_next = sl;
sl = newsl;
}
freeMagic(defList);
defList = defList->ld_next;
}
/* Mark all defs as being unvisited */
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
/* Recursively visit all defs in the tree and push on stack */
extDefStack = StackNew(100);
extDefParentFunc(use->cu_def);
/* Now extract all the cells we just found */
extExtractStack(extDefStack, doExtract, (CellDef *) NULL);
StackFree(extDefStack);
/* Replace any modified substrate planes in use->cu_def's children */
for (; sl; sl = sl->sl_next)
{
ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
freeMagic(sl);
}
}
/*
* Function to visit all the parents of 'def' and push them on
* extDefStack. We only push a def if it is unmarked, ie, its
* cd_client field is 0. After pushing a def, we mark it by
* setting its cd_client field to 1.
*/
void
extDefParentFunc(def)
CellDef *def;
{
CellUse *parent;
if (def->cd_client || (def->cd_flags&CDINTERNAL))
return;
def->cd_client = (ClientData) 1;
StackPush((ClientData) def, extDefStack);
for (parent = def->cd_parents; parent; parent = parent->cu_nextuse)
if (parent->cu_parent)
extDefParentFunc(parent->cu_parent);
}
/*
* ----------------------------------------------------------------------------
*
* ExtParentArea --
*
* ExtParentArea extracts the cell use->cu_def and each of its
* parents that contain geometry touching or overlapping the area
* of use->cu_def.
*
* Results:
* None.
*
* Side effects:
* Creates one or more .ext files and writes to them.
* Adds feedback information where errors have occurred.
*
* ----------------------------------------------------------------------------
*/
void
ExtParentArea(use, changedArea, doExtract)
CellUse *use; /* Use->cu_def changed; extract its affected parents */
Rect *changedArea; /* Area changed in use->cu_def coordinates */
bool doExtract; /* If TRUE, we extract; if FALSE, we just print names
* of the cells we would extract.
*/
{
Rect area;
/* Mark all defs as being unvisited */
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
/*
* Recursively visit all defs in the tree
* and push on stack if they contain any geometry
* overlapping or touching the area 'changedArea'.
*/
area = *changedArea;
area.r_xbot--, area.r_ybot--;
area.r_xtop++, area.r_ytop++;
extDefStack = StackNew(100);
extDefParentAreaFunc(use->cu_def, use->cu_def, (CellUse *) NULL, &area);
/* Now extract all the cells we just found */
extExtractStack(extDefStack, doExtract, (CellDef *) NULL);
StackFree(extDefStack);
}
/*
* Function to visit all the parents of 'def' and push them on
* extDefStack. We only push a def if it is unmarked, ie, its
* cd_client field is 0, and if it is either 'baseDef' or it
* contains geometry or other subcells in the area 'area'.
* We mark each def visited by setting cd_client to 1.
*/
void
extDefParentAreaFunc(def, baseDef, allButUse, area)
CellDef *def;
CellDef *baseDef;
CellUse *allButUse;
Rect *area;
{
int x, y, xoff, yoff;
CellUse *parent;
Transform t, t2;
Rect parArea;
if (def->cd_client || (def->cd_flags&CDINTERNAL))
return;
if (def == baseDef || extContainsGeometry(def, allButUse, area))
{
def->cd_client = (ClientData) 1;
StackPush((ClientData) def, extDefStack);
}
for (parent = def->cd_parents; parent; parent = parent->cu_nextuse)
{
if (parent->cu_parent)
{
for (x = parent->cu_xlo; x <= parent->cu_xhi; x++)
{
for (y = parent->cu_ylo; y <= parent->cu_yhi; y++)
{
xoff = (x - parent->cu_xlo) * parent->cu_xsep;
yoff = (y - parent->cu_ylo) * parent->cu_ysep;
GeoTranslateTrans(&GeoIdentityTransform, xoff, yoff, &t);
GeoTransTrans(&t, &parent->cu_transform, &t2);
GeoTransRect(&t2, area, &parArea);
extDefParentAreaFunc(parent->cu_parent, baseDef,
parent, &parArea);
}
}
}
}
}
/*
* ----------------------------------------------------------------------------
*
* ExtractOneCell ---
*
* Extract a single cell by preparing the substrate plane of all of its
* children, calling ExtCell(), then restoring the substrate planes of
* all the cells.
*
* ----------------------------------------------------------------------------
*/
void
ExtractOneCell(def, outName, doLength)
CellDef *def; /* Cell being extracted */
char *outName; /* Name of output file; if NULL, derive from def name */
bool doLength; /* If TRUE, extract pathlengths from drivers to
* receivers (the names are stored in ExtLength.c).
* Should only be TRUE for the root cell in a
* hierarchy.
*/
{
LinkedDef *defList = NULL;
CellUse dummyUse;
CellDef *subDef;
Plane *savePlane;
struct saveList *newsl, *sl = (struct saveList *)NULL;
dummyUse.cu_def = def;
/* Mark all defs as being unvisited */
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
extDefListFunc(&dummyUse, &defList);
/* def is on top of the list, so remove it */
freeMagic(defList);
defList = defList->ld_next;
/* Prepare substrates of all children of def */
while (defList != NULL)
{
subDef = defList->ld_def;
savePlane = extPrepSubstrate(subDef);
if (savePlane != NULL)
{
newsl = (struct saveList *)mallocMagic(sizeof(struct saveList));
newsl->sl_plane = savePlane;
newsl->sl_def = subDef;
newsl->sl_next = sl;
sl = newsl;
}
freeMagic(defList);
defList = defList->ld_next;
}
savePlane = ExtCell(def, outName, doLength);
/* Restore all modified substrate planes */
if (savePlane != NULL) ExtRevertSubstrate(def, savePlane);
for (; sl; sl = sl->sl_next)
{
ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
freeMagic(sl);
}
}
/* ------------------------------------------------------------------------- */
bool
extContainsGeometry(def, allButUse, area)
CellDef *def;
CellUse *allButUse;
Rect *area;
{
int extContainsPaintFunc();
bool extContainsCellFunc();
int pNum;
if (DBSrCellPlaneArea(def->cd_cellPlane, area,
extContainsCellFunc, (ClientData) allButUse))
return (TRUE);
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
area, &DBAllButSpaceBits,
extContainsPaintFunc, (ClientData) NULL))
return (TRUE);
return (FALSE);
}
/* ------------------------------------------------------------------------- */
bool
extContainsCellFunc(use, allButUse)
CellUse *use;
CellUse *allButUse;
{
return (use != allButUse) ? TRUE : FALSE;
}
int
extContainsPaintFunc()
{
return (1);
}
/*
* ----------------------------------------------------------------------------
*
* ExtIncremental --
*
* Starting at 'rootUse', extract all cell defs that have changed.
* Right now, we forcibly read in the entire tree before doing the
* extraction.
*
* Results:
* None.
*
* Side effects:
* Creates a number of .ext files and writes to them.
* Adds feedback information where errors have occurred.
*
* ----------------------------------------------------------------------------
*/
void
ExtIncremental(rootUse)
CellUse *rootUse;
{
LinkedDef *defList = NULL;
/* Make sure the entire subtree is read in */
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
{
TxError("Failure to read entire subtree of cell.\n");
return;
}
/* Fix up bounding boxes if they've changed */
DBFixMismatch();
/* Update all timestamps */
DBUpdateStamps(NULL);
/* Mark all defs as being unvisited */
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
/* Recursively visit all defs in the tree and create a linked list */
/* from bottommost back up to the top. */
extDefListFuncIncremental(rootUse, &defList);
/* Now reverse the list onto a stack such that the bottommost cell */
/* is the first to be extracted, and so forth back up to the top. */
extDefStack = StackNew(100);
extDefPush(defList);
/* Now extract all the cells we just found */
extExtractStack(extDefStack, TRUE, rootUse->cu_def);
StackFree(extDefStack);
}
/*
* ----------------------------------------------------------------------------
* Function returning TRUE if 'def' needs re-extraction.
* This will be the case if either the .ext file for 'def'
* does not exist, or if its timestamp fails to match that
* recorded in 'def'.
* ----------------------------------------------------------------------------
*/
bool
extTimestampMisMatch(def)
CellDef *def;
{
char line[256];
FILE *extFile;
bool ret = TRUE;
int stamp;
bool doLocal;
doLocal = (ExtOptions & EXT_DOLOCAL) ? TRUE : FALSE;
extFile = extFileOpen(def, (char *) NULL, "r", doLocal, (char **) NULL);
if (extFile == NULL)
return (TRUE);
if (fgets(line, sizeof line, extFile) == NULL) goto closeit;
if (sscanf(line, "timestamp %d", &stamp) != 1) goto closeit;
if (def->cd_timestamp != stamp) goto closeit;
ret = FALSE;
closeit:
(void) fclose(extFile);
return (ret);
}
/*
* ----------------------------------------------------------------------------
*
* extExtractStack --
*
* If 'doExtract' is TRUE, call ExtCell for each def on the stack 'stack';
* otherwise, print the name of each def on the stack 'stack'.
* The root cell of the tree being processed is 'rootDef'; we only
* extract pathlength information for this cell.
*
* Results:
* None.
*
* Side effects:
* Leaves 'stack' empty.
* Calls ExtCell on each def on the stack if 'doExtract' is TRUE.
* Resets cd_client to 0 for each def on the stack.
* Prints the total number of errors and warnings.
*
* ----------------------------------------------------------------------------
*/
void
extExtractStack(stack, doExtract, rootDef)
Stack *stack;
bool doExtract;
CellDef *rootDef;
{
int errorcnt = 0, warnings = 0;
bool first = TRUE;
Plane *savePlane;
CellDef *def;
struct saveList *newsl, *sl = (struct saveList *)NULL;
while (def = (CellDef *) StackPop(stack))
{
def->cd_client = (ClientData) 0;
if (!SigInterruptPending)
{
if (doExtract)
{
savePlane = ExtCell(def, (char *) NULL, (def == rootDef));
if (savePlane != NULL)
{
newsl = (struct saveList *)mallocMagic(sizeof(struct saveList));
newsl->sl_plane = savePlane;
newsl->sl_def = def;
newsl->sl_next = sl;
sl = newsl;
}
errorcnt += extNumErrors;
warnings += extNumWarnings;
}
else if (!(def->cd_flags & CDNOEXTRACT))
{
if (!first) TxPrintf(", ");
TxPrintf("%s", def->cd_name);
TxFlush();
first = FALSE;
}
}
}
/* Replace any modified substrate planes */
for (; sl; sl = sl->sl_next)
{
ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
sl->sl_def->cd_flags &= ~CDNOEXTRACT;
freeMagic(sl);
}
if (!doExtract)
{
TxPrintf("\n");
}
else
{
if (errorcnt > 0)
TxError("Total of %d error%s (check feedback entries).\n",
errorcnt, errorcnt != 1 ? "s" : "");
if (warnings > 0)
TxError("Total of %d warning%s.\n",
warnings, warnings != 1 ? "s" : "");
}
}