Files
magic/extract/ExtMain.c
T
Tim Edwards cff2b97678 Changed the default extraction options to include "do aliases" by
default, since not setting it can have unfortunate consequences
for cells that don't declare ports and have multiple conflicting
labels on a node.
2023-04-16 12:18:16 -04:00

1006 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. (Update: "do labelcheck" and "do aliases" have been
* added to the default options because they generally are required
* and would only need to be disabled under exceptional circumstances.)
*/
int ExtDoWarn = EXTWARN_DUP|EXTWARN_FETS;
int ExtOptions = EXT_DOALL|EXT_DOLABELCHECK|EXT_DOALIASES;
/* --------------------------- 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" : "");
}
}