/* * DBcellname.c -- * * CellUse/CellDef creation, deletion, naming. * * ********************************************************************* * * 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[] = "$Header: /ufs/repository/magic/database/DBcellname.c,v 1.4 2001/05/23 20:57:42 jsolomon Exp $"; #endif #include #ifdef SYSV #include #endif #include "misc/magic.h" #include "utils/hash.h" #include "utils/utils.h" #include "utils/geometry.h" #include "tiles/tile.h" #include "database/database.h" #include "database/databaseInt.h" #include "select/select.h" #include "signals/signals.h" #include "undo/undo.h" #include "utils/malloc.h" #include "windows/windows.h" #include "textio/textio.h" #include "main/main.h" /* * Hash tables for CellDefs and CellUses */ #define NCELLDEFBUCKETS 64 /* Initial number of buckets for CellDef tbl */ #define NCELLUSEBUCKETS 128 /* Initial number of buckets for CellUse tbl */ HashTable dbCellDefTable; HashTable dbUniqueDefTable; HashTable dbUniqueNameTable; bool dbWarnUniqueIds; /* * Routines used before defined */ CellDef *DBCellDefAlloc(); int dbLinkFunc(); /* * Routines from other database modules */ extern void dbComputeBbox(); /* * ---------------------------------------------------------------------------- * * DBCellInit -- * * Initialize the world of the cell. * * Results: * None. * * Side effects: * Sets up the symbol tables for CellDefs and CellUses. * * ---------------------------------------------------------------------------- */ void DBCellInit() { HashInit(&dbCellDefTable, NCELLDEFBUCKETS, 0); } /* * ---------------------------------------------------------------------------- * * DBCellPrintInfo -- * * This is the working function for DBCellPrint. * * Results: * None. * * Side effects: * Stuff is printed. * * ---------------------------------------------------------------------------- */ void DBCellPrintInfo(StartDef, parents, children) CellDef *StartDef; int parents; int children; { HashSearch hs; HashEntry *entry; CellDef *celldef; CellUse *celluse; if ( (parents == 0) && (children == 0) ) { if (StartDef->cd_name == NULL) { TxPrintf("Cell is currently loaded.\n"); } else { TxPrintf("Cell %s is currently loaded.\n", StartDef->cd_name); } return; } /* * * Print out a list of all the parents by scanning the 'use' list. * */ if (parents == 1) { if (StartDef->cd_name == NULL) { TxPrintf("Cell's parents are:\n"); } else { TxPrintf("Cell %s's parents are:\n", StartDef->cd_name); } for (celluse = StartDef->cd_parents; celluse != (CellUse *) NULL; celluse = celluse->cu_nextuse) { if (celluse->cu_parent != (CellDef *) NULL) { celluse->cu_parent->cd_client = (ClientData) 1; } } for (celluse = StartDef->cd_parents; celluse != (CellUse *) NULL; celluse = celluse->cu_nextuse) { if (celluse->cu_parent != (CellDef *) NULL) { if (celluse->cu_parent->cd_client == (ClientData) 1) { celluse->cu_parent->cd_client = (ClientData) NULL; if ( (celluse->cu_parent->cd_flags & CDINTERNAL) != CDINTERNAL) { TxPrintf(" %s\n", celluse->cu_parent->cd_name); } } } } } /* * * Print out a list of all the children by checking all the cells. * */ if (children == 1) { if (StartDef->cd_name == NULL) { TxPrintf("Cell's children are:\n"); } else { TxPrintf("Cell %s's children are:\n", StartDef->cd_name); } HashStartSearch(&hs); while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL) { celldef = (CellDef *) HashGetValue(entry); for (celluse = celldef->cd_parents; celluse != (CellUse *) NULL; celluse = celluse->cu_nextuse) { if (celluse->cu_parent == StartDef) { TxPrintf(" %s\n", celldef->cd_name); break; } } } } } /* * ---------------------------------------------------------------------------- * * DBCellPrint -- * * This routine prints out cell names. * * Results: * None. * * Side effects: * Stuff is printed. * * ---------------------------------------------------------------------------- */ void DBCellPrint(CellName, parents, children, all) char *CellName; int parents; int children; int all; { int found; HashSearch hs; HashEntry *entry; CellDef *celldef; CellUse *celluse; /* * * Check to see if the 'all' option was specified. If so * print the name of all the 'known' cells. * */ if (all == 1) { TxPrintf("Cell currently loaded:\n"); HashStartSearch(&hs); while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL) { celldef = (CellDef *) HashGetValue(entry); if (celldef != (CellDef *) NULL) { if ( (celldef->cd_flags & CDINTERNAL) != CDINTERNAL) { if (celldef->cd_name != NULL) { TxPrintf(" %s\n", celldef->cd_name); } } } } return; } /* * * Check to see if the 'top' option was specified. If so * print the name of all the 'top' cells. * */ if (all == 2) { TxPrintf("Top level cells are:\n"); HashStartSearch(&hs); while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL) { celldef = (CellDef *) HashGetValue(entry); if (celldef != (CellDef *) NULL) { if ( (celldef->cd_flags & CDINTERNAL) != CDINTERNAL) { found = 0; for (celluse = celldef->cd_parents; celluse != (CellUse *) NULL; celluse = celluse->cu_nextuse) { if (celluse->cu_parent != (CellDef *) NULL) { if ( (celluse->cu_parent->cd_flags & CDINTERNAL) != CDINTERNAL) { found = 1; break; } } } if ( (found == 0) && (celldef->cd_name != NULL) ) { TxPrintf(" %s\n", celldef->cd_name); } } } } return; } /* * * Check to see if a cell name was specified. If not, * search for selected cells. * */ if (CellName == NULL) { found = 0; HashStartSearch(&hs); while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL) { celldef = (CellDef *) HashGetValue(entry); if (celldef != (CellDef *) NULL) { for (celluse = celldef->cd_parents; celluse != (CellUse *) NULL; celluse = celluse->cu_nextuse) { if (celluse->cu_parent == SelectDef) { DBCellPrintInfo(celldef, parents, children); found = 1; break; } } } } if (found == 0) { TxPrintf("No cells selected.\n"); } } else { celldef = DBCellLookDef(CellName); if (celldef == (CellDef *) NULL) { TxError("Cell %s is not currently loaded.\n", CellName); } else { DBCellPrintInfo(celldef, parents, children); } } } /* * ---------------------------------------------------------------------------- * * DBCellLookDef -- * * Find the definition of the cell with the given name. * * Results: * Returns a pointer to the CellDef with the given name if it * exists. Otherwise, returns (CellDef *) NULL. * * Side effects: * None. * ---------------------------------------------------------------------------- */ CellDef * DBCellLookDef(cellName) char *cellName; { HashEntry *entry; entry = HashFind(&dbCellDefTable, cellName); return ((CellDef *) HashGetValue(entry)); } /* * ---------------------------------------------------------------------------- * * DBCellNewDef -- * * Create a new cell definition with the given name. There must not * be any cells already known with the same name. * * Results: * Returns a pointer to the newly created CellDef. The CellDef * is completely initialized, showing no uses and having all * tile planes initialized via TiNewPlane() to contain a single * space tile. The filename associated with the cell is set to * the name supplied, but no attempt is made to open it or create * it. * * If the cellName supplied is NULL, the cell is entered into * the symbol table with a name of UNNAMED. * * Returns NULL if a cell by the given name already exists. * * Side effects: * The name of the CellDef is entered into the symbol table * of known cells. * * ---------------------------------------------------------------------------- */ CellDef * DBCellNewDef(cellName, cellFileName) char *cellName; /* Name by which the cell is known */ char *cellFileName; /* Name of disk file in which the cell * should be kept when written out. */ { CellDef *cellDef; HashEntry *entry; if (cellName == (char *) NULL) cellName = UNNAMED; entry = HashFind(&dbCellDefTable, cellName); if (HashGetValue(entry) != (ClientData) NULL) return ((CellDef *) NULL); cellDef = DBCellDefAlloc(); HashSetValue(entry, (ClientData) cellDef); cellDef->cd_name = StrDup((char **) NULL, cellName); if (cellFileName == (char *) NULL) cellDef->cd_file = cellFileName; else cellDef->cd_file = StrDup((char **) NULL, cellFileName); return (cellDef); } /* * ---------------------------------------------------------------------------- * * DBCellDefAlloc -- * * Create a new cell definition structure. The new def is not added * to any symbol tables. * * Results: * Returns a pointer to the newly created CellDef. The CellDef * is completely initialized, showing no uses and having all * tile planes initialized via TiNewPlane() to contain a single * space tile. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ CellDef * DBCellDefAlloc() { CellDef *cellDef; int pNum; MALLOC(CellDef *, cellDef, sizeof (CellDef)); cellDef->cd_flags = 0; cellDef->cd_bbox.r_xbot = 0; cellDef->cd_bbox.r_ybot = 0; cellDef->cd_bbox.r_xtop = 1; cellDef->cd_bbox.r_ytop = 1; cellDef->cd_name = (char *) NULL; cellDef->cd_file = (char *) NULL; cellDef->cd_parents = (CellUse *) NULL; cellDef->cd_labels = (Label *) NULL; cellDef->cd_lastLabel = (Label *) NULL; cellDef->cd_client = (ClientData) 0; cellDef->cd_props = (ClientData) NULL; cellDef->cd_timestamp = 0; TTMaskZero(&cellDef->cd_types); HashInit(&cellDef->cd_idHash, 16, HT_STRINGKEYS); cellDef->cd_planes[PL_CELL] = DBNewPlane((ClientData) NULL); for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++) cellDef->cd_planes[pNum] = DBNewPlane((ClientData) TT_SPACE); return (cellDef); } /* * ---------------------------------------------------------------------------- * * DBCellNewUse -- * * Create a new cell use of the supplied CellDef. * * Results: * Returns a pointer to the new CellUse. The CellUse is initialized * to reflect that cellDef is its definition. The transform is * initialized to the identity, and the parent pointer initialized * to NULL. * * Side effects: * Updates the use list for cellDef. * * ---------------------------------------------------------------------------- */ CellUse * DBCellNewUse(cellDef, useName) CellDef *cellDef; /* Pointer to definition of the cell */ char *useName; /* Pointer to use identifier for the cell. This may * be NULL, in which case a unique use identifier is * generated automatically when the cell use is linked * into a parent def. */ { CellUse *cellUse; MALLOC(CellUse *, cellUse, sizeof (CellUse)); cellUse->cu_id = StrDup((char **) NULL, useName); cellUse->cu_expandMask = 0; cellUse->cu_transform = GeoIdentityTransform; cellUse->cu_def = cellDef; cellUse->cu_parent = (CellDef *) NULL; cellUse->cu_xlo = 0; cellUse->cu_ylo = 0; cellUse->cu_xhi = 0; cellUse->cu_yhi = 0; cellUse->cu_xsep = 0; cellUse->cu_ysep = 0; cellUse->cu_delta = 0; /* For plowing */ cellUse->cu_nextuse = cellDef->cd_parents; /* Initial client field */ /* (commands can use this field for whatever * they like, but should restore its value to MINFINITY before exiting.) */ cellUse->cu_client = (ClientData) MINFINITY; cellDef->cd_parents = cellUse; dbComputeBbox(cellUse); return (cellUse); } /* * ---------------------------------------------------------------------------- * * DBCellRenameDef -- * * Renames the indicated CellDef. * * Results: * TRUE if successful, FALSE if the new name was not unique. * * Side effects: * The name of the CellDef is entered into the symbol table * of known cells. The CDMODIFIED bit is set in the flags * of each of the parents of the CellDef to force them to * be written out using the new name. * * ---------------------------------------------------------------------------- */ bool DBCellRenameDef(cellDef, newName) CellDef *cellDef; /* Pointer to CellDef being renamed */ char *newName; /* Pointer to new name */ { HashEntry *oldEntry, *newEntry; CellUse *parent; oldEntry = HashFind(&dbCellDefTable, cellDef->cd_name); ASSERT(HashGetValue(oldEntry) == (ClientData) cellDef, "DBCellRenameDef"); newEntry = HashFind(&dbCellDefTable, newName); if (HashGetValue(newEntry) != (ClientData) NULL) return (FALSE); HashSetValue(oldEntry, (ClientData) NULL); HashSetValue(newEntry, (ClientData) cellDef); (void) StrDup(&cellDef->cd_name, newName); for (parent = cellDef->cd_parents; parent; parent = parent->cu_nextuse) if (parent->cu_parent) parent->cu_parent->cd_flags |= CDMODIFIED|CDGETNEWSTAMP; return (TRUE); } /* * ---------------------------------------------------------------------------- * * DBCellDeleteDef -- * * Removes the CellDef from the symbol table of known CellDefs and * frees the storage allocated to the CellDef. The CellDef must have * no CellUses. * * Results: * TRUE if successful, FALSE if there were any outstanding * CellUses found. * * Side effects: * The CellDef is removed from the table of known CellDefs. * All storage for the CellDef and its tile planes is freed. * * ---------------------------------------------------------------------------- */ bool DBCellDeleteDef(cellDef) CellDef *cellDef; /* Pointer to CellDef to be deleted */ { HashEntry *entry; if (cellDef->cd_parents != (CellUse *) NULL) return (FALSE); entry = HashFind(&dbCellDefTable, cellDef->cd_name); ASSERT(HashGetValue(entry) == (ClientData) cellDef, "DBCellDeleteDef"); HashSetValue(entry, (ClientData) NULL); if (cellDef->cd_props) DBPropClearAll(cellDef); DBCellDefFree(cellDef); return TRUE; } /* * ---------------------------------------------------------------------------- * * DBCellDefFree -- * * Does all the dirty work of freeing up stuff inside a celldef. * * Results: * None. * * Side effects: * All memory associated with the cellDef is freed. This may * cause lower-level cellUses and defs to be freed up. This * procedure is separated from DBDeleteCellDef so that it can * be used for cells that aren't in the hash table (e.g. cells * used by the window manager). * * ---------------------------------------------------------------------------- */ void DBCellDefFree(cellDef) CellDef *cellDef; { int pNum; register Label *lab; if (cellDef->cd_file != (char *) NULL) FREE(cellDef->cd_file); if (cellDef->cd_name != (char *) NULL) FREE(cellDef->cd_name); /* * We want the following searching to be non-interruptible * to guarantee that all storage gets freed. */ SigDisableInterrupts(); DBFreeCellPlane(cellDef->cd_planes[PL_CELL]); TiFreePlane(cellDef->cd_planes[PL_CELL]); for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++) { DBFreePaintPlane(cellDef->cd_planes[pNum]); TiFreePlane(cellDef->cd_planes[pNum]); cellDef->cd_planes[pNum] = (Plane *) NULL; } for (lab = cellDef->cd_labels; lab; lab = lab->lab_next) FREE((char *) lab); SigEnableInterrupts(); HashKill(&cellDef->cd_idHash); FREE((char *) cellDef); } /* * ---------------------------------------------------------------------------- * * DBCellDeleteUse -- * * Frees the storage allocated to the CellUse. * * It is required that the CellUse has been removed from any CellTileBodies * in the subcell plane of its parent. The parent pointer for this * CellUse must therefore be NULL. * * Results: * TRUE if the CellUse was successfully removed, FALSE if * the parent pointer were not NULL. * * Side effects: * All storage for the CellUse is freed. * The list of all CellUses associated with a given CellDef is * updated to reflect the absence of the deleted CellUse. * * ---------------------------------------------------------------------------- */ bool DBCellDeleteUse(cellUse) CellUse *cellUse; /* Pointer to CellUse to be deleted */ { CellDef *cellDef; CellUse *useptr; if (cellUse->cu_parent != (CellDef *) NULL) return (FALSE); cellDef = cellUse->cu_def; if (cellUse->cu_id != (char *) NULL) FREE(cellUse->cu_id); cellUse->cu_id = (char *) NULL; cellUse->cu_def = (CellDef *) NULL; ASSERT(cellDef->cd_parents != (CellUse *) NULL, "DBCellDeleteUse"); if (cellDef->cd_parents == cellUse) cellDef->cd_parents = cellUse->cu_nextuse; else for (useptr = cellDef->cd_parents; useptr != NULL; useptr = useptr->cu_nextuse) { if (useptr->cu_nextuse == cellUse) { useptr->cu_nextuse = cellUse->cu_nextuse; break; } } FREE((char *) cellUse); return (TRUE); } /* * ---------------------------------------------------------------------------- * * DBCellSrDefs -- * * Search for all cell definitions matching a given pattern. * For each cell definition whose flag word contains any of the * bits in pattern, the supplied procedure is invoked. * * The procedure should be of the following form: * int * func(cellDef, cdata) * CellDef *cellDef; * ClientData cdata; * { * } * Func should normally return 0. If it returns 1 then the * search is aborted. * * Results: * Returns 1 if the search completed normally, 1 if it aborted. * * Side effects: * Whatever the user-supplied procedure does. * * ---------------------------------------------------------------------------- */ int DBCellSrDefs(pattern, func, cdata) int pattern; /* Used for selecting cell definitions. If any * of the bits in the pattern are in a def->cd_flags, * or if pattern is 0, the user-supplied function * is invoked. */ int (*func)(); /* Function to be applied to each matching CellDef */ ClientData cdata; /* Client data also passed to function */ { HashSearch hs; HashEntry *he; CellDef *cellDef; HashStartSearch(&hs); while ((he = HashNext(&dbCellDefTable, &hs)) != (HashEntry *) NULL) { cellDef = (CellDef *) HashGetValue(he); if (cellDef == (CellDef *) NULL) continue; if ((pattern != 0) && !(cellDef->cd_flags & pattern)) continue; if ((*func)(cellDef, cdata)) return 1; } return 0; } /* * ---------------------------------------------------------------------------- * * DBLinkCell -- * * Set the cu_id for the supplied CellUse appropriately for linking into * the parent CellDef. If the cu_id is NULL, a cu_id unique within the * CellDef is automatically generated and stored in cu_id; otherwise, the * one supplied in cu_id is used. * * *** WARNING *** * * This operation is not recorded on the undo list, as it always accompanies * the creation of a new cell use. * * Results: * TRUE if the CellUse is unique within the parent CellDef, FALSE * if there would be a name conflict. If the cu_id of the CellUse * is NULL, TRUE is always returned; FALSE is only returned if * there is an existing name which would conflict with names already * present in the CellUse. * * Side effects: * Will set cu_id to an automatically generated instance id if * it was originally NULL. * * ---------------------------------------------------------------------------- */ bool DBLinkCell(use, parentDef) CellUse *use; CellDef *parentDef; { char useId[100], *lastName; HashEntry *he; int n; if (use->cu_id) { if (DBFindUse(use->cu_id, parentDef)) return FALSE; DBSetUseIdHash(use, parentDef); return TRUE; } HashInit(&dbUniqueNameTable, 32, 0); /* Indexed by use-id */ /* * Uses can't contain slashes (otherwise they'd interfere with * terminal naming conventions). If the cellName has a slash, * just use the part of it after the last slash. */ lastName = rindex(use->cu_def->cd_name, '/'); if (lastName == NULL) lastName = use->cu_def->cd_name; else lastName++; /* This search must not be interrupted */ SigDisableInterrupts(); (void) DBCellEnum(parentDef, dbLinkFunc, (ClientData) lastName); SigEnableInterrupts(); /* This loop terminates only when an empty useid is found */ /* This loop should *not* terminate on interrupt, because */ /* lots of code relies on a NULL cu_id being passed to ensure */ /* that the cell gets linked in. */ for (n = 0;; n++) { (void) sprintf(useId, "%s_%d", lastName, n); he = HashLookOnly(&dbUniqueNameTable, useId); if (he == (HashEntry *) NULL) { HashKill(&dbUniqueNameTable); use->cu_id = StrDup((char **) NULL, useId); DBSetUseIdHash(use, parentDef); return (TRUE); } } /* Never gets here */ /* HashKill(&dbUniqueNameTable); */ /* return (FALSE); */ } /* * dbLinkFunc -- * * Filter function called via DBCellEnum by DBLinkCell above. * Creates an entry in the hash table dbUniqueNameTable to * indicate that the name "defname_#" is not available. */ int dbLinkFunc(cellUse, defname) CellUse *cellUse; register char *defname; { register char *usep = cellUse->cu_id; /* Skip in the unlikely event that this cell has no use-id */ if (usep == (char *) NULL) return (0); /* * Only add names whose initial part matches 'defname', * and which are of the form 'defname_something'. */ while (*defname) if (*defname++ != *usep++) return 0; if (*usep++ != '_') return 0; if (*usep == '\0') return 0; /* Remember this name as being in use */ (void) HashFind(&dbUniqueNameTable, cellUse->cu_id); return 0; } /* * ---------------------------------------------------------------------------- * * DBReLinkCell -- * * Change the instance id of the supplied CellUse. * If the instance id is non-NULL, and the new id is the same * as the old one, we do nothing. * * Results: * Returns TRUE if successful, FALSE if the new name was not * unique within the parent def. * * Side effects: * May modify the cu_id of the supplied CellUse. * Marks the parent of the cell use as having been modified. * ---------------------------------------------------------------------------- */ bool DBReLinkCell(cellUse, newName) CellUse *cellUse; char *newName; { if (cellUse->cu_id && strcmp(cellUse->cu_id, newName) == 0) return (TRUE); if (DBFindUse(newName, cellUse->cu_parent)) return (FALSE); if (cellUse->cu_parent) cellUse->cu_parent->cd_flags |= CDMODIFIED; /* Old id (may be NULL) */ if (cellUse->cu_id) DBUnLinkCell(cellUse, cellUse->cu_parent); if (UndoIsEnabled()) DBUndoCellUse(cellUse, UNDO_CELL_CLRID); /* New id */ (void) StrDup(&cellUse->cu_id, newName); DBSetUseIdHash(cellUse, cellUse->cu_parent); if (UndoIsEnabled()) DBUndoCellUse(cellUse, UNDO_CELL_SETID); return (TRUE); } /* * ---------------------------------------------------------------------------- * * DBFindUse -- * * Find a CellUse with the given name in the supplied parent CellDef. * * Results: * Returns a pointer to the found CellUse, or NULL if it was not * found. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ CellUse * DBFindUse(id, parentDef) char *id; CellDef *parentDef; { HashEntry *he; he = HashLookOnly(&parentDef->cd_idHash, id); if (he == NULL) return (CellUse *) NULL; return (CellUse *) HashGetValue(he); } /* * ---------------------------------------------------------------------------- * * DBGenerateUniqueIds -- * * Make certain that the use-id of each CellUse under 'def' is unique * if it exists. If duplicates are detected, all but one is freed and * set to NULL. * * The second pass consists of giving each CellUse beneath 'def' with * a NULL use-id a uniquely generated one. * * Results: * None. * * Side effects: * May modify the use-id's of the cells in the cell plane of 'def'. * Prints error messages if use-ids had to be reassigned. * * ---------------------------------------------------------------------------- */ Void DBGenerateUniqueIds(def, warn) CellDef *def; bool warn; /* If TRUE, warn user when we assign new ids */ { int dbFindNamesFunc(); int dbGenerateUniqueIdsFunc(); dbWarnUniqueIds = warn; HashInit(&dbUniqueDefTable, 32, 1); /* Indexed by (CellDef *) */ HashInit(&dbUniqueNameTable, 32, 0); /* Indexed by use-id */ /* Build up tables of names, complaining about duplicates */ (void) DBCellEnum(def, dbFindNamesFunc, (ClientData) def); /* Assign unique use-ids to all cells */ (void) DBCellEnum(def, dbGenerateUniqueIdsFunc, (ClientData) def); HashKill(&dbUniqueDefTable); HashKill(&dbUniqueNameTable); } /* * ---------------------------------------------------------------------------- * * dbFindNamesFunc -- * * Called via DBCellEnum() on behalf of DBGenerateUniqueIds() above, * for each subcell of the def just processed. If any cell has a * use-id, we add it to our table of in-use names (dbUniqueNameTable). * * Results: * Returns 0 always. * * Side effects: * If the name already is in the table, free this cell's use-id * and set it to NULL. In any event, add the name to the table. * * ---------------------------------------------------------------------------- */ int dbFindNamesFunc(use, parentDef) register CellUse *use; CellDef *parentDef; { register HashEntry *he; if (use->cu_id) { he = HashFind(&dbUniqueNameTable, use->cu_id); if (HashGetValue(he)) { TxError("Duplicate instance-id for cell %s (%s) will be renamed\n", use->cu_def->cd_name, use->cu_id); DBUnLinkCell(use, parentDef); FREE(use->cu_id); use->cu_id = (char *) NULL; } HashSetValue(he, use); } return (0); } /* * ---------------------------------------------------------------------------- * * dbGenerateUniqueIdsFunc -- * * Called via DBCellEnum() on behalf of DBGenerateUniqueIds() above, * for each subcell of the def just processed. If the cell has no * use-id, we generate one automatically. In any event, install the * use identifier for each cell processed in the HashTable * parentDef->cd_idHash. * * Algorithm: * We generate unique use-id's of the form def_# where # * is an integer such that no other use-id in this cell has * the same name. The HashTable dbUniqueDefTable is indexed * by CellDef and contains the highest sequence number (# * above) processed for that CellDef. Each time we process * a cell, we start with this sequence number and continue * to increment it until we find a name that is not in * calmaNamesTable, then generate the use-id, and store * the next sequence number in the HashEntry for the CellDef. * * Results: * Returns 0 always. * * Side effects: * See above. * * ---------------------------------------------------------------------------- */ int dbGenerateUniqueIdsFunc(use, parentDef) register CellUse *use; CellDef *parentDef; { register HashEntry *hedef, *hename; register int suffix; char name[1024]; if (use->cu_id) goto setHash; hedef = HashFind(&dbUniqueDefTable, (char *) use->cu_def); for (suffix = (int) HashGetValue(hedef); ; suffix++) { (void) sprintf(name, "%s_%d", use->cu_def->cd_name, suffix); hename = HashLookOnly(&dbUniqueNameTable, name); if (hename == NULL) break; } if (dbWarnUniqueIds) TxPrintf("Setting instance-id of cell %s to %s\n", use->cu_def->cd_name, name); use->cu_id = StrDup((char **) NULL, name); HashSetValue(hedef, suffix+1); setHash: DBSetUseIdHash(use, parentDef); return (0); } /* * ---------------------------------------------------------------------------- * * DBSetUseIdHash -- * * Update the use-id hash table in parentDef to reflect the fact * that 'use' now has instance-id use->cu_id. * * Results: * None. * * Side effects: * See above. * * ---------------------------------------------------------------------------- */ DBSetUseIdHash(use, parentDef) CellUse *use; CellDef *parentDef; { HashEntry *he; he = HashFind(&parentDef->cd_idHash, use->cu_id); HashSetValue(he, (ClientData) use); } /* * ---------------------------------------------------------------------------- * * DBUnLinkCell -- * * Update the use-id hash table in parentDef to reflect the fact * that 'use' no longer is known by instance-id use->cu_id. * * Results: * None. * * Side effects: * See above. * * ---------------------------------------------------------------------------- */ DBUnLinkCell(use, parentDef) CellUse *use; CellDef *parentDef; { HashEntry *he; if (he = HashLookOnly(&parentDef->cd_idHash, use->cu_id)) HashSetValue(he, (ClientData) NULL); } /* * ---------------------------------------------------------------------------- * * DBNewYank -- * * Create a new yank buffer with name 'yname'. * * Results: * None. * * Side effects: * Fills in *pydef with a newly created CellDef by that name, and * *pyuse with a newly created CellUse pointing to the new def. * The CellDef pointed to by *pydef has the CD_INTERNAL flag * set, and is marked as being available. * * ---------------------------------------------------------------------------- */ DBNewYank(yname, pyuse, pydef) char *yname; /* Name of yank buffer */ CellUse **pyuse; /* Pointer to new cell use is stored in *pyuse */ CellDef **pydef; /* Similarly for def */ { *pydef = DBCellLookDef(yname); if (*pydef == (CellDef *) NULL) { *pydef = DBCellNewDef (yname,(char *) NULL); ASSERT(*pydef != (CellDef *) NULL, "DBNewYank"); DBCellSetAvail(*pydef); (*pydef)->cd_flags |= CDINTERNAL; } *pyuse = DBCellNewUse(*pydef, (char *) NULL); DBSetTrans(*pyuse, &GeoIdentityTransform); (*pyuse)->cu_expandMask = (~0); /* This is always expanded. */ }