1 /*
2 * DBcellname.c --
3 *
4 * CellUse/CellDef creation, deletion, naming.
5 *
6 * *********************************************************************
7 * * Copyright (C) 1985, 1990 Regents of the University of California. *
8 * * Permission to use, copy, modify, and distribute this *
9 * * software and its documentation for any purpose and without *
10 * * fee is hereby granted, provided that the above copyright *
11 * * notice appear in all copies. The University of California *
12 * * makes no representations about the suitability of this *
13 * * software for any purpose. It is provided "as is" without *
14 * * express or implied warranty. Export of this software outside *
15 * * of the United States of America may require an export license. *
16 * *********************************************************************
17 */
18
19 #ifndef lint
20 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBcellname.c,v 1.5 2009/07/27 00:56:56 tim Exp $";
21 #endif /* not lint */
22
23 #include <stdio.h>
24 #include <stdlib.h> /* for qsort() */
25 #include <string.h>
26 #include <ctype.h>
27
28 #include "tcltk/tclmagic.h"
29 #include "utils/magic.h"
30 #include "utils/hash.h"
31 #include "utils/utils.h"
32 #include "utils/geometry.h"
33 #include "tiles/tile.h"
34 #include "database/database.h"
35 #include "database/databaseInt.h"
36 #include "select/select.h"
37 #include "utils/signals.h"
38 #include "utils/undo.h"
39 #include "utils/malloc.h"
40 #include "windows/windows.h"
41 #include "textio/textio.h"
42 #include "dbwind/dbwind.h"
43 #include "utils/main.h"
44 #include "drc/drc.h"
45
46 /*
47 * Hash tables for CellDefs and CellUses
48 */
49
50 #define NCELLDEFBUCKETS 64 /* Initial number of buckets for CellDef tbl */
51 #define NCELLUSEBUCKETS 128 /* Initial number of buckets for CellUse tbl */
52
53 HashTable dbCellDefTable;
54 HashTable dbUniqueDefTable;
55 HashTable dbUniqueNameTable;
56 bool dbWarnUniqueIds;
57
58 /*
59 * Routines used before defined
60 */
61 extern CellDef *DBCellDefAlloc();
62 extern int dbLinkFunc();
63 extern void dbUsePrintInfo();
64 extern void DBsetUseIdHash();
65 extern void DBUnLinkCell();
66
67 /*
68 * Routines from other database modules
69 */
70
71 extern void DBSetUseIdHash();
72
73 /*
74 * ----------------------------------------------------------------------------
75 *
76 * DBCellRename --
77 *
78 * Rename a cell. This differs from the "save" command in that the
79 * cell is not immediately written to disk. However, the cell is
80 * marked as modified. If "doforce" is TRUE, then allow renaming
81 * of vendor (read-only) cells. Because vendor cells are tied to
82 * a GDS file, then the vendor status gets revoked and the pointer
83 * to the GDS file gets removed.
84 *
85 * Results:
86 * Return TRUE if the cell was successfully renamed. Return FALSE
87 * otherwise.
88 *
89 * Side Effects:
90 * Cellname is changed.
91 *
92 * ----------------------------------------------------------------------------
93 */
94 bool
DBCellRename(cellname,newname,doforce)95 DBCellRename(cellname, newname, doforce)
96 char *cellname;
97 char *newname;
98 bool doforce;
99 {
100 HashEntry *entry;
101 CellDef *celldef;
102 bool result;
103
104 entry = HashLookOnly(&dbCellDefTable, cellname);
105 if (entry == NULL)
106 {
107 TxError("No such cell \"%s\"\n", cellname);
108 return FALSE;
109 }
110
111 celldef = (CellDef *)HashGetValue(entry);
112 if (celldef == NULL) return FALSE;
113
114 if ((celldef->cd_flags & CDINTERNAL) == CDINTERNAL)
115 {
116 TxError("Error: Attempt to rename internal cell \"%s\"\n", cellname);
117 return FALSE;
118 }
119
120 /* Disallow renaming if the cell has the READONLY flag set, */
121 /* because the cellname must match the name in the GDS */
122 /* file referenced. */
123
124 if ((celldef->cd_flags & CDVENDORGDS) == CDVENDORGDS)
125 {
126 if (doforce)
127 {
128 TxPrintf("Warning: Renaming read-only cell \"%s\"\n", cellname);
129 TxPrintf("Read-only status will be revoked and GDS file pointer removed.\n");
130 }
131 else
132 {
133 TxError("Error: Attempt to rename read-only cell \"%s\"\n", cellname);
134 return FALSE;
135 }
136 }
137
138 /* Good to go! */
139
140 UndoDisable();
141 result = DBCellRenameDef(celldef, newname);
142 DBWAreaChanged(celldef, &celldef->cd_bbox, DBW_ALLWINDOWS,
143 (TileTypeBitMask *) NULL);
144
145 if (doforce && ((celldef->cd_flags & CDVENDORGDS) == CDVENDORGDS))
146 {
147 char *chkgdsfile;
148 bool isReadOnly;
149
150 chkgdsfile = (char *)DBPropGet(celldef, "GDS_FILE", &isReadOnly);
151 /* Note that clearing GDS_FILE will also clear CDVENDORGDS flag */
152 if (isReadOnly) DBPropPut(celldef, "GDS_FILE", NULL);
153
154 DBPropGet(celldef, "GDS_START", &isReadOnly);
155 if (isReadOnly) DBPropPut(celldef, "GDS_START", NULL);
156 DBPropGet(celldef, "GDS_END", &isReadOnly);
157 if (isReadOnly) DBPropPut(celldef, "GDS_END", NULL);
158 }
159
160 UndoEnable();
161 return result;
162 }
163
164 /*
165 * ----------------------------------------------------------------------------
166 *
167 * DBEnumerateTypes
168 *
169 * Generate a mask of all known types in all known cells.
170 *
171 * Results:
172 * None.
173 *
174 * Side effects:
175 * Returns the OR of the layer mask of each cell definition in
176 * the pointer to rMask.
177 *
178 * Notes:
179 * cd_types needs to be properly handled through paint/erase
180 * operations, or else we should not rely on cd_types.
181 * ----------------------------------------------------------------------------
182 */
183
184 void
DBEnumerateTypes(rMask)185 DBEnumerateTypes(rMask)
186 TileTypeBitMask *rMask;
187 {
188 HashSearch hs;
189 HashEntry *entry;
190 CellDef *cellDef;
191
192 TTMaskZero(rMask);
193 HashStartSearch(&hs);
194 while ((entry = HashNext(&dbCellDefTable, &hs)) != NULL)
195 {
196 cellDef = (CellDef *) HashGetValue(entry);
197 if (cellDef != (CellDef *)NULL)
198 if ((cellDef->cd_flags & CDINTERNAL) != CDINTERNAL)
199 TTMaskSetMask(rMask, &cellDef->cd_types);
200 }
201 }
202
203 /*
204 * ----------------------------------------------------------------------------
205 *
206 * DBCellDelete --
207 *
208 * Destroy a cell.
209 *
210 * Results:
211 * Return TRUE if the cell was successfully eliminated. Return FALSE
212 * if the cell could not be deleted (i.e., has dependencies).
213 *
214 * Side Effects:
215 * Frees memory. May prompt the user to save, if the cell has been
216 * changed.
217 *
218 * ----------------------------------------------------------------------------
219 */
220 bool
DBCellDelete(cellname,force)221 DBCellDelete(cellname, force)
222 char *cellname;
223 bool force;
224 {
225 HashEntry *entry;
226 CellDef *celldef;
227 CellUse *celluse;
228 bool result;
229
230 entry = HashLookOnly(&dbCellDefTable, cellname);
231 if (entry == NULL)
232 {
233 TxError("No such cell \"%s\"\n", cellname);
234 return FALSE;
235 }
236
237 celldef = (CellDef *)HashGetValue(entry);
238 if (celldef == NULL) return FALSE;
239
240 if ((celldef->cd_flags & CDINTERNAL) == CDINTERNAL)
241 {
242 TxError("Attempt to delete internal cell \"%s\"\n", cellname);
243 return FALSE;
244 }
245
246 /* If the cell has any instances which are not top-level */
247 /* uses, don't allow the deletion. */
248
249 for (celluse = celldef->cd_parents; celluse != (CellUse *) NULL;
250 celluse = celluse->cu_nextuse)
251 if (celluse->cu_parent != (CellDef *) NULL)
252 if ((celluse->cu_parent->cd_flags & CDINTERNAL) != CDINTERNAL)
253 break;
254
255 if (celluse != (CellUse *)NULL)
256 {
257 TxError("Cell has non-top-level dependency in use \"%s\"\n",
258 celluse->cu_id);
259 return FALSE;
260 }
261
262 /* Cleared to delete. . . now prompt user if the cell has changes. */
263 /* Last chance to save! */
264
265 if ((force == FALSE) &&
266 (celldef->cd_flags & (CDMODIFIED|CDBOXESCHANGED|CDSTAMPSCHANGED)))
267 {
268 static char *yesno[] = { "no", "yes", 0 };
269 int code;
270 char *prompt = TxPrintString("Cell %s has been modified.\n Do you"
271 " want to delete it and lose all changes? ",
272 cellname);
273 code = TxDialog(prompt, yesno, 0);
274 if (code == 0) return FALSE;
275 }
276
277 /* If we're destroying the cell pointed to by dbUndoLastCell, we */
278 /* need to NULL it and flush the Undo queue. */
279
280 DBUndoReset(celldef);
281
282 /* If we're destroying "UNNAMED", then we want to rename it first */
283 /* so that WindUnload() will create a new one. */
284
285 if (!strcmp(cellname, UNNAMED))
286 DBCellRename(cellname, "__UNNAMED__");
287
288 /* For all top-level cell uses, check if any windows have this */
289 /* use. If so, load the window with (UNNAMED). */
290
291 UndoDisable();
292 for (celluse = celldef->cd_parents; celluse != (CellUse *) NULL;
293 celluse = celluse->cu_nextuse)
294 {
295 if (celluse->cu_parent == (CellDef *) NULL)
296 {
297 WindUnload(celluse);
298 freeMagic(celluse->cu_id);
299 }
300 freeMagic((char *)celluse);
301 }
302 celldef->cd_parents = (CellUse *)NULL;
303
304 DBWResetBox(celldef);
305 result = DBCellDeleteDef(celldef);
306
307 if (result == FALSE)
308 TxError("Error: Deleted all cell uses, but could not delete cell.\n");
309
310 UndoEnable();
311 return result;
312 }
313
314 /*
315 * ----------------------------------------------------------------------------
316 *
317 * DBCellInit --
318 *
319 * Initialize the world of the cell.
320 *
321 * Results:
322 * None.
323 *
324 * Side effects:
325 * Sets up the symbol tables for CellDefs and CellUses.
326 *
327 * ----------------------------------------------------------------------------
328 */
329
330 void
DBCellInit()331 DBCellInit()
332 {
333 HashInit(&dbCellDefTable, NCELLDEFBUCKETS, 0);
334 }
335
336 /*
337 * ----------------------------------------------------------------------------
338 *
339 * dbGetUseName --
340 *
341 * Returns the name of the indicated cell use. If the use is part of
342 * an array, it returns the largest array member in x, y, or both.
343 *
344 * Results:
345 * An allocated char * array which must be free'd using freeMagic().
346 *
347 * ----------------------------------------------------------------------------
348 */
349
350 char *
dbGetUseName(celluse)351 dbGetUseName(celluse)
352 CellUse *celluse;
353 {
354 char *useID, *newID, xbuf[10], ybuf[10];
355 int arxl, aryl, arxh, aryh;
356 int newsize;
357 bool isx, isy;
358
359 arxl = celluse->cu_array.ar_xlo;
360 aryl = celluse->cu_array.ar_ylo;
361 arxh = celluse->cu_array.ar_xhi;
362 aryh = celluse->cu_array.ar_yhi;
363
364 isx = (arxh == arxl) ? FALSE : TRUE;
365 isy = (aryh == aryl) ? FALSE : TRUE;
366
367 xbuf[0] = '\0';
368 ybuf[0] = '\0';
369
370 useID = celluse->cu_id;
371 newsize = strlen(useID) + 1;
372 if (isx || isy)
373 {
374 newsize += 4;
375 if (isx && isy) newsize += 1;
376 if (isx)
377 {
378 snprintf(xbuf, 9, "%d", arxl);
379 newsize += strlen(xbuf);
380 }
381 if (isy)
382 {
383 snprintf(ybuf, 9, "%d", aryl);
384 newsize += strlen(ybuf);
385 }
386 }
387
388 newID = (char *)mallocMagic(newsize);
389 strcpy(newID, useID);
390 if (isx || isy)
391 {
392 strcat(newID, "\\[");
393 if (isx) strcat(newID, xbuf);
394 if (isx && isy) strcat(newID, ",");
395 if (isy) strcat(newID, ybuf);
396 strcat(newID, "\\]");
397 }
398 return (newID);
399 }
400
401
402 /*
403 * ----------------------------------------------------------------------------
404 *
405 * dbCellPrintInfo --
406 *
407 * This is the working function for DBCellPrint.
408 *
409 * Results:
410 * None (Tcl returns list if "dolist" is true in magic Tcl version).
411 *
412 * Side effects:
413 * Stuff is printed.
414 *
415 * ----------------------------------------------------------------------------
416 */
417
418 void
dbCellPrintInfo(StartDef,who,dolist)419 dbCellPrintInfo(StartDef, who, dolist)
420 CellDef *StartDef;
421 int who;
422 bool dolist;
423 {
424 HashSearch hs;
425 HashEntry *entry;
426 CellDef *celldef;
427 CellUse *celluse;
428 char *cu_name;
429 bool topdone;
430
431 switch (who) {
432 case SELF:
433
434 if (StartDef->cd_name == NULL)
435 {
436 if (dolist)
437 #ifdef MAGIC_WRAPPER
438 Tcl_AppendElement(magicinterp, "1");
439 #else
440 TxPrintf("TRUE\n");
441 #endif
442 else
443 TxPrintf("Cell is currently loaded.\n");
444 }
445 else
446 {
447 if (dolist)
448 #ifdef MAGIC_WRAPPER
449 Tcl_AppendElement(magicinterp, StartDef->cd_name);
450 #else
451 TxPrintf("%s\n", StartDef->cd_name);
452 #endif
453 else
454 TxPrintf("Cell %s is currently loaded.\n", StartDef->cd_name);
455 }
456 break;
457
458 case OTHER:
459 if (!dolist)
460 TxPrintf("Names of cell instances:\n");
461
462 for (celluse = StartDef->cd_parents; celluse != NULL;
463 celluse = celluse->cu_nextuse)
464 {
465 if ((celluse->cu_parent != NULL) &&
466 ((celluse->cu_parent->cd_flags & CDINTERNAL)
467 == CDINTERNAL))
468 continue;
469
470 if (celluse->cu_id != NULL)
471 {
472 cu_name = dbGetUseName(celluse);
473 if (dolist)
474 #ifdef MAGIC_WRAPPER
475 Tcl_AppendElement(magicinterp, cu_name);
476 #else
477 TxPrintf("%s\n", cu_name);
478 #endif
479 else
480 TxPrintf(" %s\n", cu_name);
481 freeMagic(cu_name);
482 }
483 }
484 break;
485
486 case CHILDINST:
487 if (!dolist)
488 TxPrintf("Def %s's children are:\n", StartDef->cd_name);
489
490 HashStartSearch(&hs);
491 while ((entry = HashNext(&StartDef->cd_idHash, &hs)) != NULL)
492 {
493 celluse = (CellUse *)HashGetValue(entry);
494 if (celluse != (CellUse *)NULL)
495 dbCellUsePrintFunc(celluse, &dolist);
496 }
497 break;
498
499 case PARENTS:
500
501 /*
502 *
503 * Print out a list of all the parents by scanning the 'use' list.
504 *
505 */
506
507 if (StartDef->cd_name == NULL && (!dolist))
508 {
509 TxPrintf("Cell's parents are:\n");
510 }
511 else if (!dolist)
512 {
513 TxPrintf("Cell %s's parents are:\n", StartDef->cd_name);
514 }
515 for (celluse = StartDef->cd_parents; celluse != (CellUse *) NULL;
516 celluse = celluse->cu_nextuse)
517 {
518 if (celluse->cu_parent != (CellDef *) NULL)
519 {
520 celluse->cu_parent->cd_client = (ClientData) 1;
521 }
522 }
523 for (celluse = StartDef->cd_parents; celluse != (CellUse *) NULL;
524 celluse = celluse->cu_nextuse)
525 {
526 if (celluse->cu_parent != (CellDef *) NULL)
527 {
528 if (celluse->cu_parent->cd_client == (ClientData) 1)
529 {
530 celluse->cu_parent->cd_client = (ClientData) NULL;
531 if ( (celluse->cu_parent->cd_flags & CDINTERNAL)
532 != CDINTERNAL)
533 {
534 if (dolist)
535 #ifdef MAGIC_WRAPPER
536 Tcl_AppendElement(magicinterp,
537 celluse->cu_parent->cd_name);
538 #else
539 TxPrintf("%s ", celluse->cu_parent->cd_name);
540 #endif
541 else
542 TxPrintf(" %s\n", celluse->cu_parent->cd_name);
543 }
544 }
545 }
546 }
547 break;
548
549 case CHILDREN:
550
551 /*
552 *
553 * Print out a list of all the children by checking all the cells.
554 *
555 */
556
557 if (StartDef->cd_name == NULL && (!dolist))
558 {
559 TxPrintf("Cell's children are:\n");
560 }
561 else if (!dolist)
562 {
563 TxPrintf("Cell %s's children are:\n", StartDef->cd_name);
564 }
565 HashStartSearch(&hs);
566 while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
567 {
568 celldef = (CellDef *) HashGetValue(entry);
569 if (!celldef) continue;
570 for (celluse = celldef->cd_parents; celluse != (CellUse *) NULL;
571 celluse = celluse->cu_nextuse)
572 {
573 if (celluse->cu_parent == StartDef)
574 {
575 if (dolist)
576 #ifdef MAGIC_WRAPPER
577 Tcl_AppendElement(magicinterp, celldef->cd_name);
578 #else
579 TxPrintf("%s ", celldef->cd_name);
580 #endif
581 else
582 TxPrintf(" %s\n", celldef->cd_name);
583 break;
584 }
585 }
586 }
587 break;
588 } /* endswitch */
589 }
590
591
592
593 /*
594 * ----------------------------------------------------------------------------
595 *
596 * DBTopPrint --
597 *
598 * This routine prints the cell definition name of the topmost instance
599 * in the window.
600 *
601 * ----------------------------------------------------------------------------
602 */
603 void
DBTopPrint(mw,dolist)604 DBTopPrint(mw, dolist)
605 MagWindow *mw;
606 bool dolist;
607 {
608 CellDef *celldef;
609 CellUse *celluse;
610
611 if (mw == NULL)
612 {
613 TxError("No window was selected for search.\n");
614 }
615 else
616 {
617 celluse = (CellUse *)mw->w_surfaceID;
618 celldef = celluse->cu_def;
619
620 if (celldef == NULL) return;
621 #ifdef MAGIC_WRAPPER
622 if (dolist)
623 Tcl_AppendElement(magicinterp, celldef->cd_name);
624 else
625 #endif
626 TxPrintf("Top-level cell in the window is: %s\n", celldef->cd_name);
627 }
628 }
629
630 /*
631 * ----------------------------------------------------------------------------
632 * Simple natural sort routine
633 * https://stackoverflow.com/questions/34518/natural-sorting-algorithm
634 * By Norman Ramsey, edited for style.
635 * ----------------------------------------------------------------------------
636 */
637
strcmpbynum(const char * s1,const char * s2)638 int strcmpbynum(const char *s1, const char *s2)
639 {
640 /* Like strcmp() but compare sequences of digits numerically */
641 for (;;)
642 {
643 if (*s2 == '\0')
644 return *s1 != '\0';
645 else if (*s1 == '\0')
646 return 1;
647 else if (!(isdigit(*s1) && isdigit(*s2)))
648 {
649 if (*s1 != *s2)
650 return (int)*s1 - (int)*s2;
651 else
652 {
653 ++s1;
654 ++s2;
655 }
656 }
657 else
658 {
659 char *lim1, *lim2;
660 unsigned long n1 = strtoul(s1, &lim1, 10);
661 unsigned long n2 = strtoul(s2, &lim2, 10);
662 if (n1 > n2)
663 return 1;
664 else if (n1 < n2)
665 return -1;
666 s1 = lim1;
667 s2 = lim2;
668 }
669 }
670 }
671
672 /*
673 * ----------------------------------------------------------------------------
674 * Sort routine for qsort() to be used by DBCellPrint(). Sorts in alphabetical
675 * order using the natural sort routine above. List is reverse sorted since
676 * the code below prints from the end to the beginning of the list.
677 * ----------------------------------------------------------------------------
678 */
679
680 int
qcompare(const void * one,const void * two)681 qcompare(const void *one, const void *two)
682 {
683 int cval;
684
685 char *s1 = *((char **)one);
686 char *s2 = *((char **)two);
687 cval = strcmpbynum(s1, s2);
688 return -cval;
689 }
690
691 /*
692 * ----------------------------------------------------------------------------
693 *
694 * DBCellPrint --
695 *
696 * This routine prints out cell names.
697 *
698 * Results:
699 * None.
700 *
701 * Side effects:
702 * Stuff is printed.
703 *
704 * Notes: "who" takes one of the options defined in database.h:
705 * PARENTS, CHILDREN, SELF, OTHER, ALLCELLS, MODIFIED, or TOPCELLS.
706 * "SELF" lists celldef names (most useful to list the name of
707 * a selected cell). "OTHER" lists instance names.
708 *
709 * ----------------------------------------------------------------------------
710 */
711
712 void
DBCellPrint(CellName,who,dolist)713 DBCellPrint(CellName, who, dolist)
714 char *CellName;
715 int who;
716 bool dolist;
717 {
718 int found, numcells;
719 HashSearch hs;
720 HashEntry *entry;
721 CellDef *celldef;
722 CellUse *celluse;
723 char **celllist;
724
725 if (!dolist)
726 {
727 switch (who)
728 {
729 case ALLCELLS:
730 TxPrintf("Cell currently loaded:\n");
731 break;
732 case MODIFIED:
733 TxPrintf("Modified cells:\n");
734 break;
735 case TOPCELLS:
736 TxPrintf("Top level cells are:\n");
737 break;
738 }
739 }
740
741 switch (who)
742 {
743 case ALLCELLS:
744 case MODIFIED:
745 /*
746 * Print the name of all the 'known' cells.
747 * If "MODIFIED", print only those cells that have the
748 * CDMODIFIED flag set.
749 */
750
751 numcells = dbCellDefTable.ht_nEntries;
752 if (numcells == 0) numcells = 1;
753 celllist = (char **)mallocMagic(numcells * sizeof(char *));
754 numcells = 0;
755
756 HashStartSearch(&hs);
757 while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
758 {
759 celldef = (CellDef *) HashGetValue(entry);
760 if (celldef != (CellDef *) NULL)
761 {
762 if (((celldef->cd_flags & CDINTERNAL) != CDINTERNAL) &&
763 ((who != MODIFIED) ||
764 (celldef->cd_flags & CDMODIFIED)))
765 if (celldef->cd_name != NULL)
766 celllist[numcells++] = celldef->cd_name;
767
768 }
769 }
770
771 qsort(celllist, numcells, sizeof(char *), qcompare);
772
773 while (--numcells >= 0)
774 {
775 if (dolist)
776 #ifdef MAGIC_WRAPPER
777 Tcl_AppendElement(magicinterp, celllist[numcells]);
778 #else
779 TxPrintf("%s ", celllist[numcells]);
780 #endif
781 else
782 TxPrintf(" %s\n", celllist[numcells]);
783 }
784
785 freeMagic(celllist);
786 break;
787
788 case TOPCELLS:
789 /*
790 * Print the name of all the 'top' cells. Sort alphabetically.
791 */
792
793 numcells = dbCellDefTable.ht_nEntries;
794 if (numcells == 0) numcells = 1;
795 celllist = (char **)mallocMagic(numcells * sizeof(char *));
796 numcells = 0;
797
798 HashStartSearch(&hs);
799 while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
800 {
801 celldef = (CellDef *) HashGetValue(entry);
802 if (celldef != (CellDef *) NULL)
803 {
804 if ( (celldef->cd_flags & CDINTERNAL) != CDINTERNAL)
805 {
806 found = 0;
807 for (celluse = celldef->cd_parents;
808 celluse != (CellUse *) NULL;
809 celluse = celluse->cu_nextuse)
810 {
811 if (celluse->cu_parent != (CellDef *) NULL)
812 {
813 if ( (celluse->cu_parent->cd_flags & CDINTERNAL)
814 != CDINTERNAL)
815 {
816 found = 1;
817 break;
818 }
819 }
820 }
821 if ( (found == 0) && (celldef->cd_name != NULL) )
822 celllist[numcells++] = celldef->cd_name;
823 }
824 }
825 }
826
827 qsort(celllist, numcells, sizeof(char *), qcompare);
828
829 while (--numcells >= 0)
830 {
831 if (dolist)
832 #ifdef MAGIC_WRAPPER
833 Tcl_AppendElement(magicinterp, celllist[numcells]);
834 #else
835 TxPrintf("%s ", celllist[numcells]);
836 #endif
837 else
838 TxPrintf(" %s\n", celllist[numcells]);
839 }
840 freeMagic(celllist);
841 break;
842
843 default:
844
845 /*
846 * Check to see if a cell name was specified. If not,
847 * search for selected cells.
848 */
849
850 if (CellName == NULL)
851 {
852 found = 0;
853 HashStartSearch(&hs);
854 while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
855 {
856 celldef = (CellDef *) HashGetValue(entry);
857 if (celldef != (CellDef *) NULL)
858 {
859 for (celluse = celldef->cd_parents;
860 celluse != (CellUse *) NULL;
861 celluse = celluse->cu_nextuse)
862 {
863 if (celluse->cu_parent == SelectDef)
864 {
865 dbCellPrintInfo(celldef, who, dolist);
866 found = 1;
867 break;
868 }
869 }
870 }
871 }
872 if (found == 0)
873 {
874 if (EditRootDef == NULL)
875 {
876 if (!dolist)
877 TxPrintf("No cells selected.\n");
878 }
879 else
880 {
881 dbCellPrintInfo(EditRootDef, who, dolist);
882 found = 1;
883 break;
884 }
885 }
886 }
887 else
888 {
889 celldef = DBCellLookDef(CellName);
890 if (celldef == (CellDef *) NULL)
891 {
892 if (dolist)
893 #ifdef MAGIC_WRAPPER
894 Tcl_AppendElement(magicinterp, "0");
895 #else
896 TxPrintf("Not loaded\n");
897 #endif
898 else
899 TxError("Cell %s is not currently loaded.\n", CellName);
900 }
901 else
902 {
903 dbCellPrintInfo(celldef, who, dolist);
904 }
905 }
906 break;
907 } /* endswitch */
908 }
909
910 /*
911 * ----------------------------------------------------------------------------
912 *
913 * dbUsePrintInfo --
914 *
915 * This is the working function for DBUsePrint.
916 *
917 * Results:
918 * None (Tcl returns list if "dolist" is true in magic Tcl version).
919 *
920 * Side effects:
921 * Stuff is printed.
922 *
923 * ----------------------------------------------------------------------------
924 */
925
926 void
dbUsePrintInfo(StartUse,who,dolist)927 dbUsePrintInfo(StartUse, who, dolist)
928 CellUse *StartUse;
929 int who;
930 bool dolist;
931 {
932 CellDef *celldef;
933 CellUse *celluse;
934 char *cu_name;
935 HashSearch hs;
936 HashEntry *entry;
937
938 int dbCellUsePrintFunc();
939
940 /* fprintf(stderr, "dbCellUseInfo called with %s, %d, %s\n",
941 * StartUse->cu_id == NULL ? "(unnamed)" : StartUse->cu_id,
942 * who, (dolist) ? "list" : "no list" );
943 * fflush(stderr);
944 */
945
946 switch (who) {
947 case SELF:
948 if (StartUse->cu_id == NULL)
949 {
950 if (dolist)
951 #ifdef MAGIC_WRAPPER
952 Tcl_AppendElement(magicinterp, "1");
953 #else
954 TxPrintf("TRUE\n");
955 #endif
956 else
957 TxPrintf("Use is currently loaded.\n");
958 }
959 else
960 {
961 cu_name = dbGetUseName(StartUse);
962 if (dolist)
963 #ifdef MAGIC_WRAPPER
964 Tcl_AppendElement(magicinterp, cu_name);
965 #else
966 TxPrintf("%s\n", cu_name);
967 #endif
968 else
969 TxPrintf("Use %s is currently loaded.\n", cu_name);
970 freeMagic(cu_name);
971 }
972 break;
973
974 case OTHER:
975 if (StartUse->cu_def->cd_name == NULL)
976 {
977 if (dolist)
978 #ifdef MAGIC_WRAPPER
979 Tcl_AppendElement(magicinterp, "0");
980 #else
981 TxPrintf("FALSE\n");
982 #endif
983 else
984 TxPrintf("Cell definition has no name.\n");
985 }
986 else
987 {
988 if (dolist)
989 #ifdef MAGIC_WRAPPER
990 Tcl_AppendElement(magicinterp, StartUse->cu_def->cd_name);
991 #else
992 TxPrintf("%s\n", StartUse->cu_def->cd_name);
993 #endif
994 else
995 TxPrintf("Cell definition is %s.\n", StartUse->cu_def->cd_name);
996 }
997 break;
998
999 case PARENTS:
1000
1001 /*
1002 *
1003 * Print out a list of all the parents by scanning the 'use' list.
1004 *
1005 */
1006
1007 if (StartUse->cu_id == NULL && (!dolist))
1008 {
1009 TxPrintf("Use's parent is:\n");
1010 }
1011 else if (!dolist)
1012 {
1013 cu_name = dbGetUseName(StartUse);
1014 TxPrintf("Use %s's parent is:\n", cu_name);
1015 freeMagic(cu_name);
1016 }
1017 if (StartUse->cu_parent != (CellDef *) NULL)
1018 {
1019 if ((StartUse->cu_parent->cd_flags & CDINTERNAL)
1020 != CDINTERNAL)
1021 {
1022 if (dolist)
1023 #ifdef MAGIC_WRAPPER
1024 Tcl_AppendElement(magicinterp,
1025 StartUse->cu_parent->cd_name);
1026 #else
1027 TxPrintf("%s ", StartUse->cu_parent->cd_name);
1028 #endif
1029 else
1030 TxPrintf(" %s\n", StartUse->cu_parent->cd_name);
1031 }
1032 }
1033 break;
1034
1035 case CHILDREN:
1036
1037 /*
1038 *
1039 * Print out a list of all the children by checking all the cells.
1040 *
1041 */
1042
1043 if (StartUse->cu_id == NULL && (!dolist))
1044 {
1045 TxPrintf("Use's children are:\n");
1046 }
1047 else if (!dolist)
1048 {
1049 cu_name = dbGetUseName(StartUse);
1050 TxPrintf("Use %s's children are:\n", cu_name);
1051 freeMagic(cu_name);
1052 }
1053 celldef = StartUse->cu_def;
1054 HashStartSearch(&hs);
1055 while ((entry = HashNext(&celldef->cd_idHash, &hs)) != NULL)
1056 {
1057 celluse = (CellUse *)HashGetValue(entry);
1058 if (celluse != (CellUse *)NULL)
1059 dbCellUsePrintFunc(celluse, &dolist);
1060 }
1061 break;
1062 } /* endswitch */
1063 }
1064
1065 /*
1066 * ----------------------------------------------------------------------------
1067 *
1068 * DBUsePrint --
1069 *
1070 * This routine prints out cell use names.
1071 *
1072 * Results:
1073 * None.
1074 *
1075 * Side effects:
1076 * Stuff is printed.
1077 *
1078 * Notes: "who" takes one of the options defined in database.h:
1079 * PARENTS, CHILDREN, SELF, OTHER, or ALLCELLS.
1080 * "SELF" lists instance names (most useful to list the name of
1081 * a selected instance). "OTHER" lists the celldef name of the
1082 * instance.
1083 *
1084 * CellName should be referenced either to the current edit cell,
1085 * if it is not a hierarchical name; otherwise, if it is a
1086 * hierarchical name, the instance before the last '/' is mapped
1087 * to its cellDef, and that cellDef is searched for the indicated
1088 * instance.
1089 *
1090 * ----------------------------------------------------------------------------
1091 */
1092
1093 void
DBUsePrint(CellName,who,dolist)1094 DBUsePrint(CellName, who, dolist)
1095 char *CellName;
1096 int who;
1097 bool dolist;
1098 {
1099 int found;
1100 HashSearch hs;
1101 HashEntry *entry;
1102 CellDef *celldef;
1103 CellUse *celluse;
1104 char *lasthier;
1105
1106 int dbCellUsePrintFunc();
1107
1108 if ((CellName != NULL) && ((lasthier = strrchr(CellName, '/')) != NULL))
1109 {
1110 char *prevhier;
1111 *lasthier = '\0';
1112 prevhier = strrchr(CellName, '/');
1113 if (prevhier == NULL)
1114 prevhier = CellName;
1115 else
1116 prevhier++;
1117
1118 celldef = DBCellLookDef(CellName);
1119 *lasthier = '/';
1120 }
1121 else
1122 {
1123 /* Referenced cellDef is the current edit def */
1124 celldef = EditCellUse->cu_def;
1125 }
1126
1127 switch (who)
1128 {
1129 case ALLCELLS:
1130 /*
1131 * Print the name of all the 'known' cell uses (hierarchical names).
1132 */
1133
1134 break;
1135
1136 default:
1137
1138 /*
1139 *
1140 * Check to see if a cell name was specified. If not,
1141 * search for selected cells.
1142 *
1143 */
1144
1145 if (CellName == NULL)
1146 {
1147 found = 0;
1148 HashStartSearch(&hs);
1149 while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
1150 {
1151 celldef = (CellDef *) HashGetValue(entry);
1152 if (celldef != (CellDef *) NULL)
1153 {
1154 for (celluse = celldef->cd_parents;
1155 celluse != (CellUse *) NULL;
1156 celluse = celluse->cu_nextuse)
1157 {
1158 if (celluse->cu_parent == SelectDef)
1159 {
1160 dbUsePrintInfo(celluse, who, dolist);
1161 found = 1;
1162 }
1163 }
1164 }
1165 }
1166 if (found == 0)
1167 if (!dolist)
1168 TxPrintf("No cells selected.\n");
1169 }
1170 else
1171 {
1172 celluse = DBFindUse(CellName, celldef);
1173
1174 if (celluse == NULL)
1175 {
1176 if (!dolist)
1177 TxError("Cell %s is not currently loaded.\n", CellName);
1178 }
1179 else
1180 {
1181 dbUsePrintInfo(celluse, who, dolist);
1182 }
1183 }
1184 break;
1185
1186 } /* endswitch */
1187 }
1188
1189 int
dbCellUsePrintFunc(cellUse,dolist)1190 dbCellUsePrintFunc(cellUse, dolist)
1191 CellUse *cellUse;
1192 bool *dolist;
1193 {
1194 char *cu_name;
1195
1196 if (cellUse->cu_id != NULL)
1197 {
1198 cu_name = dbGetUseName(cellUse);
1199 if (*dolist)
1200 #ifdef MAGIC_WRAPPER
1201 Tcl_AppendElement(magicinterp, cu_name);
1202 #else
1203 TxPrintf("%s ", cu_name);
1204 #endif
1205 else
1206 TxPrintf(" %s\n", cu_name);
1207 freeMagic(cu_name);
1208 }
1209 return 0;
1210 }
1211
1212 /*
1213 * dbLockUseFunc()
1214 */
1215
1216 int
dbLockUseFunc(selUse,use,transform,data)1217 dbLockUseFunc(selUse, use, transform, data)
1218 CellUse *selUse; /* Use from selection cell */
1219 CellUse *use; /* Use from layout corresponding to selection */
1220 Transform *transform;
1221 ClientData data;
1222 {
1223 bool dolock = *((bool *)data);
1224
1225 if (EditCellUse && !DBIsChild(use, EditCellUse))
1226 {
1227 TxError("Cell %s (%s) isn't a child of the edit cell.\n",
1228 use->cu_id, use->cu_def->cd_name);
1229 return 0;
1230 }
1231 if ((dolock && (use->cu_flags & CU_LOCKED)) ||
1232 (!dolock && !(use->cu_flags & CU_LOCKED)))
1233 return 0; /* nothing to do */
1234
1235 if (UndoIsEnabled()) DBUndoCellUse(use, UNDO_CELL_LOCKDOWN);
1236 if (dolock) use->cu_flags |= CU_LOCKED;
1237 else use->cu_flags &= ~CU_LOCKED;
1238 if (UndoIsEnabled()) DBUndoCellUse(use, UNDO_CELL_LOCKDOWN);
1239
1240 if (selUse != NULL)
1241 {
1242 if (dolock) selUse->cu_flags |= CU_LOCKED;
1243 else selUse->cu_flags &= ~CU_LOCKED;
1244 }
1245
1246 DBWAreaChanged(use->cu_parent, &use->cu_bbox,
1247 (int) ~(use->cu_expandMask), &DBAllButSpaceBits);
1248 DBWHLRedraw(EditRootDef, &selUse->cu_bbox, TRUE);
1249 return 0;
1250 }
1251
1252 /*
1253 * ----------------------------------------------------------------------------
1254 *
1255 * DBLockUse --
1256 *
1257 * This routine sets or clears a cell instance's lock flag
1258 *
1259 * Results:
1260 * None.
1261 *
1262 * Side effects:
1263 * cu_flags changed for indicated cell use.
1264 *
1265 * ----------------------------------------------------------------------------
1266 */
1267
1268 void
DBLockUse(UseName,bval)1269 DBLockUse(UseName, bval)
1270 char *UseName;
1271 bool bval;
1272 {
1273 int found;
1274 HashSearch hs;
1275 HashEntry *entry;
1276 CellDef *celldef;
1277 CellUse *celluse;
1278
1279 int dbLockUseFunc();
1280
1281 /*
1282 *
1283 * Check to see if a cell name was specified. If not,
1284 * search for selected cells.
1285 *
1286 */
1287
1288 if (UseName == NULL)
1289 {
1290 if (EditCellUse == NULL)
1291 TxError("Cannot set lock in a non-edit cell!\n");
1292 else
1293 SelEnumCells(TRUE, (int *)NULL, (SearchContext *)NULL,
1294 dbLockUseFunc, (ClientData)&bval);
1295 }
1296 else
1297 {
1298 SearchContext scx;
1299
1300 bzero(&scx, sizeof(SearchContext));
1301 found = 0;
1302
1303 HashStartSearch(&hs);
1304 while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
1305 {
1306 celldef = (CellDef *) HashGetValue(entry);
1307 if (celldef != (CellDef *) NULL)
1308 {
1309 celluse = celldef->cd_parents; /* only need one */
1310 if (celluse != (CellUse *)NULL) {
1311 DBTreeFindUse(UseName, celluse, &scx);
1312 if (scx.scx_use != NULL) break;
1313 }
1314 }
1315 }
1316
1317 if (scx.scx_use == NULL)
1318 TxError("Cell %s is not currently loaded.\n", UseName);
1319 else
1320 dbLockUseFunc(NULL, scx.scx_use, NULL, (ClientData)&bval);
1321 }
1322 }
1323
1324 /*
1325 * ----------------------------------------------------------------------------
1326 *
1327 * DBOrientUse --
1328 *
1329 * This routine reports a cell instance's orientation.
1330 * UseName is the name of a specific CellUse. If NULL, then the
1331 * operation applies to all selected cell uses.
1332 *
1333 * Results:
1334 * None.
1335 *
1336 * Side effects:
1337 * In the Tcl/Tk implementation, the result is set in the interpreter.
1338 *
1339 * Notes:
1340 * This routine only reports orientation. Setting orientation must
1341 * be done through the selection interface (i.e., commands "sideways",
1342 * "upsidedown", "clockwise" ("rotate"), or "orient" (added 10/30/2020)).
1343 *
1344 * ----------------------------------------------------------------------------
1345 */
1346
1347 void
DBOrientUse(UseName,dodef)1348 DBOrientUse(UseName, dodef)
1349 char *UseName;
1350 bool dodef;
1351 {
1352 int found;
1353 HashSearch hs;
1354 HashEntry *entry;
1355 CellDef *celldef;
1356 CellUse *celluse;
1357
1358 int dbOrientUseFunc();
1359
1360 /*
1361 *
1362 * Check to see if a cell name was specified. If not, then search
1363 * for selected cells.
1364 *
1365 */
1366
1367 if (UseName == NULL)
1368 {
1369 if (EditCellUse == NULL)
1370 TxError("Cannot set orientation of a non-edit cell!\n");
1371 else
1372 SelEnumCells(TRUE, (int *)NULL, (SearchContext *)NULL,
1373 dbOrientUseFunc, (ClientData)&dodef);
1374 }
1375 else
1376 {
1377 SearchContext scx;
1378
1379 bzero(&scx, sizeof(SearchContext));
1380 found = 0;
1381
1382 HashStartSearch(&hs);
1383 while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
1384 {
1385 celldef = (CellDef *) HashGetValue(entry);
1386 if (celldef != (CellDef *) NULL)
1387 {
1388 celluse = celldef->cd_parents; /* only need one */
1389 if (celluse != (CellUse *)NULL) {
1390 DBTreeFindUse(UseName, celluse, &scx);
1391 if (scx.scx_use != NULL) break;
1392 }
1393 }
1394 }
1395
1396 if (scx.scx_use == NULL)
1397 TxError("Cell %s is not currently loaded.\n", UseName);
1398 else
1399 dbOrientUseFunc(NULL, scx.scx_use, NULL, (ClientData)&dodef);
1400 }
1401 }
1402
1403 /*
1404 * dbOrientUseFunc()
1405 */
1406
1407 /* For corresponding enumerations, see GeoTransOrient() */
1408 enum def_orient {ORIENT_NORTH, ORIENT_SOUTH, ORIENT_EAST, ORIENT_WEST,
1409 ORIENT_FLIPPED_NORTH, ORIENT_FLIPPED_SOUTH, ORIENT_FLIPPED_EAST,
1410 ORIENT_FLIPPED_WEST};
1411
1412 int
dbOrientUseFunc(selUse,use,transform,data)1413 dbOrientUseFunc(selUse, use, transform, data)
1414 CellUse *selUse; /* Use from selection cell */
1415 CellUse *use; /* Use from layout corresponding to selection */
1416 Transform *transform;
1417 ClientData data;
1418 {
1419 bool *dodef = (bool *)data;
1420 int orient;
1421
1422 if (EditCellUse && !DBIsChild(use, EditCellUse))
1423 {
1424 TxError("Cell %s (%s) isn't a child of the edit cell.\n",
1425 use->cu_id, use->cu_def->cd_name);
1426 return 0;
1427 }
1428
1429 orient = -1;
1430
1431 if (selUse != NULL)
1432 orient = GeoTransOrient(&selUse->cu_transform);
1433 else if (use != NULL)
1434 orient = GeoTransOrient(&use->cu_transform);
1435
1436 if (orient != -1)
1437 {
1438 switch (orient) {
1439 #ifdef MAGIC_WRAPPER
1440 case ORIENT_NORTH:
1441 Tcl_AppendElement(magicinterp, (*dodef) ? "N" : "0");
1442 break;
1443 case ORIENT_EAST:
1444 Tcl_AppendElement(magicinterp, (*dodef) ? "E" : "90");
1445 break;
1446 case ORIENT_SOUTH:
1447 Tcl_AppendElement(magicinterp, (*dodef) ? "S" : "180");
1448 break;
1449 case ORIENT_WEST:
1450 Tcl_AppendElement(magicinterp, (*dodef) ? "W" : "270");
1451 break;
1452 case ORIENT_FLIPPED_NORTH:
1453 Tcl_AppendElement(magicinterp, (*dodef) ? "FN" : "0h");
1454 break;
1455 case ORIENT_FLIPPED_EAST:
1456 Tcl_AppendElement(magicinterp, (*dodef) ? "FE" : "90h");
1457 break;
1458 case ORIENT_FLIPPED_SOUTH:
1459 Tcl_AppendElement(magicinterp, (*dodef) ? "FS" : "180h");
1460 break;
1461 case ORIENT_FLIPPED_WEST:
1462 Tcl_AppendElement(magicinterp, (*dodef) ? "FW" : "270h");
1463 break;
1464 #else
1465 case ORIENT_NORTH:
1466 TxPrintf((*dodef) ? "N" : "0");
1467 break;
1468 case ORIENT_EAST:
1469 TxPrintf((*dodef) ? "E" : "90");
1470 break;
1471 case ORIENT_SOUTH:
1472 TxPrintf((*dodef) ? "S" : "180");
1473 break;
1474 case ORIENT_WEST:
1475 TxPrintf((*dodef) ? "W" : "270");
1476 break;
1477 case ORIENT_FLIPPED_NORTH:
1478 TxPrintf((*dodef) ? "FN" : "0h");
1479 break;
1480 case ORIENT_FLIPPED_EAST:
1481 TxPrintf((*dodef) ? "FE" : "90h");
1482 break;
1483 case ORIENT_FLIPPED_SOUTH:
1484 TxPrintf((*dodef) ? "FS" : "180h");
1485 break;
1486 case ORIENT_FLIPPED_WEST:
1487 TxPrintf((*dodef) ? "FW" : "270h");
1488 break;
1489 #endif
1490 }
1491
1492 }
1493 return 0;
1494 }
1495
1496 /*
1497 * ----------------------------------------------------------------------------
1498 *
1499 * DBAbutmentUse --
1500 *
1501 * This routine reports the cell instance's abutment box in the
1502 * coordinate system of the parent (edit) cell.
1503 *
1504 * Results:
1505 * None.
1506 *
1507 * Side effects:
1508 * None.
1509 *
1510 * ----------------------------------------------------------------------------
1511 */
1512
1513 void
DBAbutmentUse(UseName,dolist)1514 DBAbutmentUse(UseName, dolist)
1515 char *UseName;
1516 bool dolist;
1517 {
1518 int found;
1519 HashSearch hs;
1520 HashEntry *entry;
1521 CellDef *celldef;
1522 CellUse *celluse;
1523
1524 int dbAbutmentUseFunc();
1525
1526 /*
1527 *
1528 * Check to see if a cell name was specified. If not, then search
1529 * for selected cells.
1530 *
1531 */
1532
1533 if (UseName == NULL)
1534 {
1535 SelEnumCells(TRUE, (int *)NULL, (SearchContext *)NULL,
1536 dbAbutmentUseFunc, (ClientData)&dolist);
1537 }
1538 else
1539 {
1540 SearchContext scx;
1541
1542 bzero(&scx, sizeof(SearchContext));
1543 found = 0;
1544
1545 HashStartSearch(&hs);
1546 while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL)
1547 {
1548 celldef = (CellDef *) HashGetValue(entry);
1549 if (celldef != (CellDef *) NULL)
1550 {
1551 celluse = celldef->cd_parents; /* only need one */
1552 if (celluse != (CellUse *)NULL) {
1553 DBTreeFindUse(UseName, celluse, &scx);
1554 if (scx.scx_use != NULL) break;
1555 }
1556 }
1557 }
1558
1559 if (scx.scx_use == NULL)
1560 TxError("Cell %s is not currently loaded.\n", UseName);
1561 else
1562 dbAbutmentUseFunc(NULL, scx.scx_use, NULL, (ClientData)&dolist);
1563 }
1564 }
1565
1566 /*
1567 * dbAbutmentUseFunc()
1568 */
1569
1570 int
dbAbutmentUseFunc(selUse,use,transform,data)1571 dbAbutmentUseFunc(selUse, use, transform, data)
1572 CellUse *selUse; /* Use from selection cell */
1573 CellUse *use; /* Use from layout corresponding to selection */
1574 Transform *transform;
1575 ClientData data;
1576 {
1577 Rect bbox, refbox;
1578 Transform *trans;
1579 char *propvalue;
1580 bool found;
1581 bool *dolist = (bool *)data;
1582
1583 #ifdef MAGIC_WRAPPER
1584 Tcl_Obj *pobj;
1585 #endif
1586
1587 if (EditCellUse && !DBIsChild(use, EditCellUse))
1588 {
1589 TxError("Cell %s (%s) isn't a child of the edit cell.\n",
1590 use->cu_id, use->cu_def->cd_name);
1591 return 0;
1592 }
1593
1594 if (use == NULL)
1595 {
1596 TxError("No instance in selection!\n");
1597 return 0;
1598 }
1599
1600 trans = &use->cu_transform;
1601 propvalue = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
1602 if (!found)
1603 bbox = use->cu_def->cd_bbox;
1604 else
1605 {
1606 if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
1607 &bbox.r_xtop, &bbox.r_ytop) != 4)
1608 bbox = use->cu_def->cd_bbox;
1609 }
1610 GeoTransRect(trans, &bbox, &refbox);
1611
1612 #ifdef MAGIC_WRAPPER
1613 if (*dolist)
1614 {
1615 pobj = Tcl_NewListObj(0, NULL);
1616 Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_xbot));
1617 Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_ybot));
1618 Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_xtop));
1619 Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(refbox.r_ytop));
1620 Tcl_SetObjResult(magicinterp, pobj);
1621 }
1622 else
1623 #endif
1624 TxPrintf("Abutment box: %d %d %d %d\n", refbox.r_xbot, refbox.r_ybot,
1625 refbox.r_xtop, refbox.r_ytop);
1626
1627 return 0;
1628 }
1629
1630 /*
1631 * ----------------------------------------------------------------------------
1632 *
1633 * DBCellLookDef --
1634 *
1635 * Find the definition of the cell with the given name.
1636 *
1637 * Results:
1638 * Returns a pointer to the CellDef with the given name if it
1639 * exists. Otherwise, returns (CellDef *) NULL.
1640 *
1641 * Side effects:
1642 * None.
1643 * ----------------------------------------------------------------------------
1644 */
1645
1646 CellDef *
DBCellLookDef(cellName)1647 DBCellLookDef(cellName)
1648 char *cellName;
1649 {
1650 HashEntry *entry;
1651
1652 entry = HashLookOnly(&dbCellDefTable, cellName);
1653 if (entry == (HashEntry *)NULL) return (CellDef *)NULL;
1654 return (CellDef *)HashGetValue(entry);
1655 }
1656
1657
1658 /*
1659 * ----------------------------------------------------------------------------
1660 *
1661 * DBCellNewDef --
1662 *
1663 * Create a new cell definition with the given name. There must not
1664 * be any cells already known with the same name.
1665 *
1666 * Results:
1667 * Returns a pointer to the newly created CellDef. The CellDef
1668 * is completely initialized, showing no uses and having all
1669 * tile planes initialized via TiNewPlane() to contain a single
1670 * space tile. The filename associated with the cell is set to
1671 * the name supplied, but no attempt is made to open it or create
1672 * it.
1673 *
1674 * If the cellName supplied is NULL, the cell is entered into
1675 * the symbol table with a name of UNNAMED.
1676 *
1677 * Returns NULL if a cell by the given name already exists.
1678 *
1679 * Side effects:
1680 * The name of the CellDef is entered into the symbol table
1681 * of known cells.
1682 *
1683 * ----------------------------------------------------------------------------
1684 */
1685
1686 CellDef *
DBCellNewDef(cellName)1687 DBCellNewDef(cellName)
1688 char *cellName; /* Name by which the cell is known */
1689 {
1690 CellDef *cellDef;
1691 HashEntry *entry;
1692 char *dotptr;
1693
1694 if (cellName == (char *) NULL)
1695 cellName = UNNAMED;
1696
1697 entry = HashFind(&dbCellDefTable, cellName);
1698 if (HashGetValue(entry) != (ClientData) NULL)
1699 return ((CellDef *) NULL);
1700
1701 cellDef = DBCellDefAlloc();
1702 HashSetValue(entry, (ClientData) cellDef);
1703 cellDef->cd_name = StrDup((char **) NULL, cellName);
1704
1705 /* Strip any .mag extension off of the cell name */
1706 dotptr = strrchr(cellDef->cd_name, '.');
1707 if (dotptr && !strcmp(dotptr, ".mag")) *dotptr = '\0';
1708
1709 cellDef->cd_file = NULL;
1710 return (cellDef);
1711 }
1712
1713 /*
1714 * ----------------------------------------------------------------------------
1715 *
1716 * DBCellDefAlloc --
1717 *
1718 * Create a new cell definition structure. The new def is not added
1719 * to any symbol tables.
1720 *
1721 * Results:
1722 * Returns a pointer to the newly created CellDef. The CellDef
1723 * is completely initialized, showing no uses and having all
1724 * tile planes initialized via TiNewPlane() to contain a single
1725 * space tile.
1726 *
1727 * Side effects:
1728 * None.
1729 *
1730 * ----------------------------------------------------------------------------
1731 */
1732
1733 CellDef *
DBCellDefAlloc()1734 DBCellDefAlloc()
1735 {
1736 CellDef *cellDef;
1737 int pNum;
1738
1739 cellDef = (CellDef *) mallocMagic((unsigned) (sizeof (CellDef)));
1740 cellDef->cd_flags = 0;
1741 cellDef->cd_bbox.r_xbot = 0;
1742 cellDef->cd_bbox.r_ybot = 0;
1743 cellDef->cd_bbox.r_xtop = 1;
1744 cellDef->cd_bbox.r_ytop = 1;
1745 cellDef->cd_extended = cellDef->cd_bbox;
1746 cellDef->cd_name = (char *) NULL;
1747 cellDef->cd_file = (char *) NULL;
1748 #ifdef FILE_LOCKS
1749 cellDef->cd_fd = -1;
1750 #endif
1751 cellDef->cd_parents = (CellUse *) NULL;
1752 cellDef->cd_labels = (Label *) NULL;
1753 cellDef->cd_lastLabel = (Label *) NULL;
1754 cellDef->cd_client = (ClientData) 0;
1755 cellDef->cd_props = (ClientData) NULL;
1756 cellDef->cd_timestamp = 0;
1757 TTMaskZero(&cellDef->cd_types);
1758 HashInit(&cellDef->cd_idHash, 16, HT_STRINGKEYS);
1759
1760 cellDef->cd_cellPlane = BPNew();
1761 cellDef->cd_planes[PL_ROUTER] = DBNewPlane((ClientData) NULL);
1762 for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
1763 cellDef->cd_planes[pNum] = DBNewPlane((ClientData) TT_SPACE);
1764
1765 /* Definitively zero out all other plane entries */
1766 for (pNum = DBNumPlanes; pNum < MAXPLANES; pNum++)
1767 cellDef->cd_planes[pNum] = NULL;
1768
1769 return (cellDef);
1770 }
1771
1772 /*
1773 * ----------------------------------------------------------------------------
1774 *
1775 * DBCellNewUse --
1776 *
1777 * Create a new cell use of the supplied CellDef.
1778 *
1779 * Results:
1780 * Returns a pointer to the new CellUse. The CellUse is initialized
1781 * to reflect that cellDef is its definition. The transform is
1782 * initialized to the identity, and the parent pointer initialized
1783 * to NULL.
1784 *
1785 * Side effects:
1786 * Updates the use list for cellDef.
1787 *
1788 * ----------------------------------------------------------------------------
1789 */
1790
1791 CellUse *
DBCellNewUse(cellDef,useName)1792 DBCellNewUse(cellDef, useName)
1793 CellDef *cellDef; /* Pointer to definition of the cell */
1794 char *useName; /* Pointer to use identifier for the cell. This may
1795 * be NULL, in which case a unique use identifier is
1796 * generated automatically when the cell use is linked
1797 * into a parent def.
1798 */
1799 {
1800 CellUse *cellUse;
1801
1802 cellUse = (CellUse *) mallocMagic((unsigned) (sizeof (CellUse)));
1803 cellUse->cu_id = StrDup((char **) NULL, useName);
1804 cellUse->cu_flags = (unsigned char)0;
1805 cellUse->cu_expandMask = 0;
1806 cellUse->cu_transform = GeoIdentityTransform;
1807 cellUse->cu_def = cellDef;
1808 cellUse->cu_parent = (CellDef *) NULL;
1809 cellUse->cu_xlo = 0;
1810 cellUse->cu_ylo = 0;
1811 cellUse->cu_xhi = 0;
1812 cellUse->cu_yhi = 0;
1813 cellUse->cu_xsep = 0;
1814 cellUse->cu_ysep = 0;
1815 cellUse->cu_nextuse = cellDef->cd_parents;
1816
1817 /* Initial client field */
1818 /* (commands can use this field for whatever
1819 * they like, but should restore its value to CLIENTDEFAULT before exiting.)
1820 */
1821 cellUse->cu_client = (ClientData) CLIENTDEFAULT;
1822
1823 cellDef->cd_parents = cellUse;
1824 DBComputeUseBbox(cellUse);
1825 return (cellUse);
1826 }
1827
1828 /*
1829 * ----------------------------------------------------------------------------
1830 *
1831 * DBCellRenameDef --
1832 *
1833 * Renames the indicated CellDef.
1834 *
1835 * Results:
1836 * TRUE if successful, FALSE if the new name was not unique.
1837 *
1838 * Side effects:
1839 * The name of the CellDef is entered into the symbol table
1840 * of known cells. The CDMODIFIED bit is set in the flags
1841 * of each of the parents of the CellDef to force them to
1842 * be written out using the new name.
1843 *
1844 * ----------------------------------------------------------------------------
1845 */
1846
1847 bool
DBCellRenameDef(cellDef,newName)1848 DBCellRenameDef(cellDef, newName)
1849 CellDef *cellDef; /* Pointer to CellDef being renamed */
1850 char *newName; /* Pointer to new name */
1851 {
1852 HashEntry *oldEntry, *newEntry;
1853 CellUse *parent;
1854
1855 oldEntry = HashFind(&dbCellDefTable, cellDef->cd_name);
1856 ASSERT(HashGetValue(oldEntry) == (ClientData) cellDef, "DBCellRenameDef");
1857
1858 newEntry = HashFind(&dbCellDefTable, newName);
1859 if (HashGetValue(newEntry) != (ClientData) NULL)
1860 return (FALSE);
1861
1862 HashSetValue(oldEntry, (ClientData) NULL);
1863 HashSetValue(newEntry, (ClientData) cellDef);
1864 (void) StrDup(&cellDef->cd_name, newName);
1865
1866 for (parent = cellDef->cd_parents; parent; parent = parent->cu_nextuse)
1867 if (parent->cu_parent)
1868 parent->cu_parent->cd_flags |= CDMODIFIED|CDGETNEWSTAMP;
1869
1870 return (TRUE);
1871 }
1872
1873 /*
1874 * ----------------------------------------------------------------------------
1875 *
1876 * DBCellDeleteDef --
1877 *
1878 * Removes the CellDef from the symbol table of known CellDefs and
1879 * frees the storage allocated to the CellDef. The CellDef must have
1880 * no CellUses.
1881 *
1882 * Results:
1883 * TRUE if successful, FALSE if there were any outstanding
1884 * CellUses found.
1885 *
1886 * Side effects:
1887 * The CellDef is removed from the table of known CellDefs.
1888 * All storage for the CellDef and its tile planes is freed.
1889 *
1890 * ----------------------------------------------------------------------------
1891 */
1892
1893 bool
DBCellDeleteDef(cellDef)1894 DBCellDeleteDef(cellDef)
1895 CellDef *cellDef; /* Pointer to CellDef to be deleted */
1896 {
1897 HashEntry *entry;
1898
1899 if (cellDef->cd_parents != (CellUse *) NULL)
1900 return (FALSE);
1901
1902 entry = HashFind(&dbCellDefTable, cellDef->cd_name);
1903 ASSERT(HashGetValue(entry) == (ClientData) cellDef, "DBCellDeleteDef");
1904 HashSetValue(entry, (ClientData) NULL);
1905 if (cellDef->cd_props)
1906 DBPropClearAll(cellDef);
1907
1908 /* Need to check the DRC pending queue, and remove */
1909 /* this cell if it's there. */
1910 DRCRemovePending(cellDef);
1911
1912 DBCellDefFree(cellDef);
1913 return TRUE;
1914 }
1915
1916 /*
1917 * ----------------------------------------------------------------------------
1918 *
1919 * DBCellDefFree --
1920 *
1921 * Does all the dirty work of freeing up stuff inside a celldef.
1922 *
1923 * Results:
1924 * None.
1925 *
1926 * Side effects:
1927 * All memory associated with the cellDef is freed. This may
1928 * cause lower-level cellUses and defs to be freed up. This
1929 * procedure is separated from DBDeleteCellDef so that it can
1930 * be used for cells that aren't in the hash table (e.g. cells
1931 * used by the window manager).
1932 *
1933 * ----------------------------------------------------------------------------
1934 */
1935
1936 void
DBCellDefFree(cellDef)1937 DBCellDefFree(cellDef)
1938 CellDef *cellDef;
1939
1940 {
1941 int pNum;
1942 Label *lab;
1943
1944 if (cellDef->cd_file != (char *) NULL)
1945 freeMagic(cellDef->cd_file);
1946 if (cellDef->cd_name != (char *) NULL)
1947 freeMagic(cellDef->cd_name);
1948
1949 /*
1950 * We want the following searching to be non-interruptible
1951 * to guarantee that all storage gets freed.
1952 */
1953
1954 SigDisableInterrupts();
1955 DBClearCellPlane(cellDef); /* Remove instances only */
1956 BPFree(cellDef->cd_cellPlane); /* Remove the cell plane itself */
1957
1958 TiFreePlane(cellDef->cd_planes[PL_ROUTER]);
1959 for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
1960 {
1961 DBFreePaintPlane(cellDef->cd_planes[pNum]);
1962 TiFreePlane(cellDef->cd_planes[pNum]);
1963 cellDef->cd_planes[pNum] = (Plane *) NULL;
1964 }
1965
1966 for (lab = cellDef->cd_labels; lab; lab = lab->lab_next)
1967 freeMagic((char *) lab);
1968 SigEnableInterrupts();
1969 HashKill(&cellDef->cd_idHash);
1970
1971 freeMagic((char *) cellDef);
1972 }
1973
1974 /*
1975 * ----------------------------------------------------------------------------
1976 *
1977 * DBCellDeleteUse --
1978 *
1979 * Frees the storage allocated to the CellUse.
1980 *
1981 * It is required that the CellUse has been removed from any CellTileBodies
1982 * in the subcell plane of its parent. The parent pointer for this
1983 * CellUse must therefore be NULL.
1984 *
1985 * Results:
1986 * TRUE if the CellUse was successfully removed, FALSE if
1987 * the parent pointer were not NULL.
1988 *
1989 * Side effects:
1990 * All storage for the CellUse is freed.
1991 * The list of all CellUses associated with a given CellDef is
1992 * updated to reflect the absence of the deleted CellUse.
1993 *
1994 * ----------------------------------------------------------------------------
1995 */
1996
1997 bool
DBCellDeleteUse(cellUse)1998 DBCellDeleteUse(cellUse)
1999 CellUse *cellUse; /* Pointer to CellUse to be deleted */
2000 {
2001 CellDef *cellDef;
2002 CellUse *useptr;
2003
2004 if (cellUse->cu_parent != (CellDef *) NULL)
2005 return (FALSE);
2006
2007 cellDef = cellUse->cu_def;
2008 if (cellUse->cu_id != (char *) NULL)
2009 freeMagic(cellUse->cu_id);
2010 cellUse->cu_id = (char *) NULL;
2011 cellUse->cu_def = (CellDef *) NULL;
2012
2013 ASSERT(cellDef->cd_parents != (CellUse *) NULL, "DBCellDeleteUse");
2014
2015 if (cellDef->cd_parents == cellUse)
2016 cellDef->cd_parents = cellUse->cu_nextuse;
2017 else for (useptr = cellDef->cd_parents; useptr != NULL;
2018 useptr = useptr->cu_nextuse)
2019 {
2020 if (useptr->cu_nextuse == cellUse)
2021 {
2022 useptr->cu_nextuse = cellUse->cu_nextuse;
2023 break;
2024 }
2025 }
2026
2027 freeMagic((char *) cellUse);
2028 return (TRUE);
2029 }
2030
2031 /*
2032 * ----------------------------------------------------------------------------
2033 *
2034 * DBCellSrDefs --
2035 *
2036 * Search for all cell definitions matching a given pattern.
2037 * For each cell definition whose flag word contains any of the
2038 * bits in pattern, the supplied procedure is invoked.
2039 *
2040 * The procedure should be of the following form:
2041 * int
2042 * func(cellDef, cdata)
2043 * CellDef *cellDef;
2044 * ClientData cdata;
2045 * {
2046 * }
2047 * Func should normally return 0. If it returns 1 then the
2048 * search is aborted.
2049 *
2050 * Results:
2051 * Returns 1 if the search completed normally, 1 if it aborted.
2052 *
2053 * Side effects:
2054 * Whatever the user-supplied procedure does.
2055 *
2056 * ----------------------------------------------------------------------------
2057 */
2058
2059 int
DBCellSrDefs(pattern,func,cdata)2060 DBCellSrDefs(pattern, func, cdata)
2061 int pattern; /* Used for selecting cell definitions. If any
2062 * of the bits in the pattern are in a def->cd_flags,
2063 * or if pattern is 0, the user-supplied function
2064 * is invoked.
2065 */
2066 int (*func)(); /* Function to be applied to each matching CellDef */
2067 ClientData cdata; /* Client data also passed to function */
2068 {
2069 HashSearch hs;
2070 HashEntry *he;
2071 CellDef *cellDef;
2072
2073 HashStartSearch(&hs);
2074 while ((he = HashNext(&dbCellDefTable, &hs)) != (HashEntry *) NULL)
2075 {
2076 cellDef = (CellDef *) HashGetValue(he);
2077 if (cellDef == (CellDef *) NULL)
2078 continue;
2079 if ((pattern != 0) && !(cellDef->cd_flags & pattern))
2080 continue;
2081 if ((*func)(cellDef, cdata)) return 1;
2082 }
2083 return 0;
2084 }
2085
2086 /*
2087 * ----------------------------------------------------------------------------
2088 *
2089 * DBLinkCell --
2090 *
2091 * Set the cu_id for the supplied CellUse appropriately for linking into
2092 * the parent CellDef. If the cu_id is NULL, a cu_id unique within the
2093 * CellDef is automatically generated and stored in cu_id; otherwise, the
2094 * one supplied in cu_id is used.
2095 *
2096 * *** WARNING ***
2097 *
2098 * This operation is not recorded on the undo list, as it always accompanies
2099 * the creation of a new cell use.
2100 *
2101 * Results:
2102 * TRUE if the CellUse is unique within the parent CellDef, FALSE
2103 * if there would be a name conflict. If the cu_id of the CellUse
2104 * is NULL, TRUE is always returned; FALSE is only returned if
2105 * there is an existing name which would conflict with names already
2106 * present in the CellUse.
2107 *
2108 * Side effects:
2109 * Will set cu_id to an automatically generated instance id if
2110 * it was originally NULL.
2111 *
2112 * ----------------------------------------------------------------------------
2113 */
2114
2115 bool
DBLinkCell(use,parentDef)2116 DBLinkCell(use, parentDef)
2117 CellUse *use;
2118 CellDef *parentDef;
2119 {
2120 char useId[100], *lastName;
2121 HashEntry *he;
2122 int n;
2123
2124 if (use->cu_id)
2125 {
2126 if (DBFindUse(use->cu_id, parentDef))
2127 return FALSE;
2128 DBSetUseIdHash(use, parentDef);
2129 return TRUE;
2130 }
2131
2132 HashInit(&dbUniqueNameTable, 32, 0); /* Indexed by use-id */
2133
2134 /*
2135 * Uses can't contain slashes (otherwise they'd interfere with
2136 * terminal naming conventions). If the cellName has a slash,
2137 * just use the part of it after the last slash.
2138 */
2139 lastName = strrchr(use->cu_def->cd_name, '/');
2140 if (lastName == NULL) lastName = use->cu_def->cd_name;
2141 else lastName++;
2142
2143 /* This search must not be interrupted */
2144 SigDisableInterrupts();
2145 (void) DBCellEnum(parentDef, dbLinkFunc, (ClientData) lastName);
2146 SigEnableInterrupts();
2147
2148 /* This loop terminates only when an empty useid is found */
2149 /* This loop should *not* terminate on interrupt, because */
2150 /* lots of code relies on a NULL cu_id being passed to ensure */
2151 /* that the cell gets linked in. */
2152
2153 for (n = 0;; n++)
2154 {
2155 (void) sprintf(useId, "%s_%d", lastName, n);
2156 he = HashLookOnly(&dbUniqueNameTable, useId);
2157 if (he == (HashEntry *) NULL)
2158 {
2159 HashKill(&dbUniqueNameTable);
2160 use->cu_id = StrDup((char **) NULL, useId);
2161 DBSetUseIdHash(use, parentDef);
2162 return (TRUE);
2163 }
2164 }
2165
2166 /* Never gets here */
2167 /* HashKill(&dbUniqueNameTable); */
2168 /* return (FALSE); */
2169 }
2170
2171 /*
2172 * dbLinkFunc --
2173 *
2174 * Filter function called via DBCellEnum by DBLinkCell above.
2175 * Creates an entry in the hash table dbUniqueNameTable to
2176 * indicate that the name "defname_#" is not available.
2177 */
2178
2179 int
dbLinkFunc(cellUse,defname)2180 dbLinkFunc(cellUse, defname)
2181 CellUse *cellUse;
2182 char *defname;
2183 {
2184 char *usep = cellUse->cu_id;
2185
2186 /* Skip in the unlikely event that this cell has no use-id */
2187 if (usep == (char *) NULL)
2188 return (0);
2189
2190 /*
2191 * Only add names whose initial part matches 'defname',
2192 * and which are of the form 'defname_something'.
2193 */
2194 while (*defname)
2195 if (*defname++ != *usep++)
2196 return 0;
2197 if (*usep++ != '_') return 0;
2198 if (*usep == '\0') return 0;
2199
2200 /* Remember this name as being in use */
2201 (void) HashFind(&dbUniqueNameTable, cellUse->cu_id);
2202
2203 return 0;
2204 }
2205
2206 /*
2207 * ----------------------------------------------------------------------------
2208 *
2209 * DBReLinkCell --
2210 *
2211 * Change the instance id of the supplied CellUse.
2212 * If the instance id is non-NULL, and the new id is the same
2213 * as the old one, we do nothing.
2214 *
2215 * Results:
2216 * Returns TRUE if successful, FALSE if the new name was not
2217 * unique within the parent def.
2218 *
2219 * Side effects:
2220 * May modify the cu_id of the supplied CellUse.
2221 * Marks the parent of the cell use as having been modified.
2222 * ----------------------------------------------------------------------------
2223 */
2224
2225 bool
DBReLinkCell(cellUse,newName)2226 DBReLinkCell(cellUse, newName)
2227 CellUse *cellUse;
2228 char *newName;
2229 {
2230 if (cellUse->cu_id && strcmp(cellUse->cu_id, newName) == 0)
2231 return (TRUE);
2232
2233 if (DBFindUse(newName, cellUse->cu_parent))
2234 return (FALSE);
2235
2236 if (cellUse->cu_parent)
2237 cellUse->cu_parent->cd_flags |= CDMODIFIED;
2238
2239 /* Old id (may be NULL) */
2240 if (cellUse->cu_id)
2241 DBUnLinkCell(cellUse, cellUse->cu_parent);
2242 if (UndoIsEnabled()) DBUndoCellUse(cellUse, UNDO_CELL_CLRID);
2243
2244 /* New id */
2245 (void) StrDup(&cellUse->cu_id, newName);
2246 DBSetUseIdHash(cellUse, cellUse->cu_parent);
2247 if (UndoIsEnabled()) DBUndoCellUse(cellUse, UNDO_CELL_SETID);
2248 return (TRUE);
2249 }
2250
2251 /*
2252 * ----------------------------------------------------------------------------
2253 *
2254 * DBFindUse --
2255 *
2256 * Find a CellUse with the given name in the supplied parent CellDef.
2257 *
2258 * Results:
2259 * Returns a pointer to the found CellUse, or NULL if it was not
2260 * found.
2261 *
2262 * Side effects:
2263 * None.
2264 *
2265 * ----------------------------------------------------------------------------
2266 */
2267
2268 CellUse *
DBFindUse(id,parentDef)2269 DBFindUse(id, parentDef)
2270 char *id;
2271 CellDef *parentDef;
2272 {
2273 HashEntry *he;
2274 char *delimit;
2275
2276 /* Sanity checks */
2277 if (id == NULL) return NULL;
2278 if (parentDef == NULL) return NULL;
2279
2280 /* Array delimiters should be ignored */
2281 if ((delimit = strrchr(id, '[')) != NULL) *delimit = '\0';
2282
2283 he = HashLookOnly(&parentDef->cd_idHash, id);
2284 if (delimit != NULL) *delimit = '[';
2285 if (he == NULL)
2286 return (CellUse *) NULL;
2287
2288 return (CellUse *) HashGetValue(he);
2289 }
2290
2291 /*
2292 * ----------------------------------------------------------------------------
2293 *
2294 * DBGenerateUniqueIds --
2295 *
2296 * Make certain that the use-id of each CellUse under 'def' is unique
2297 * if it exists. If duplicates are detected, all but one is freed and
2298 * set to NULL.
2299 *
2300 * The second pass consists of giving each CellUse beneath 'def' with
2301 * a NULL use-id a uniquely generated one.
2302 *
2303 * Results:
2304 * None.
2305 *
2306 * Side effects:
2307 * May modify the use-id's of the cells in the cell plane of 'def'.
2308 * Prints error messages if use-ids had to be reassigned.
2309 *
2310 * ----------------------------------------------------------------------------
2311 */
2312
2313 void
DBGenerateUniqueIds(def,warn)2314 DBGenerateUniqueIds(def, warn)
2315 CellDef *def;
2316 bool warn; /* If TRUE, warn user when we assign new ids */
2317 {
2318 int dbFindNamesFunc();
2319 int dbGenerateUniqueIdsFunc();
2320
2321 dbWarnUniqueIds = warn;
2322 HashInit(&dbUniqueDefTable, 32, 1); /* Indexed by (CellDef *) */
2323 HashInit(&dbUniqueNameTable, 32, 0); /* Indexed by use-id */
2324
2325 /* Build up tables of names, complaining about duplicates */
2326 (void) DBCellEnum(def, dbFindNamesFunc, (ClientData) def);
2327
2328 /* Assign unique use-ids to all cells */
2329 (void) DBCellEnum(def, dbGenerateUniqueIdsFunc, (ClientData) def);
2330
2331 HashKill(&dbUniqueDefTable);
2332 HashKill(&dbUniqueNameTable);
2333 }
2334
2335 /*
2336 * ----------------------------------------------------------------------------
2337 *
2338 * dbFindNamesFunc --
2339 *
2340 * Called via DBCellEnum() on behalf of DBGenerateUniqueIds() above,
2341 * for each subcell of the def just processed. If any cell has a
2342 * use-id, we add it to our table of in-use names (dbUniqueNameTable).
2343 *
2344 * Results:
2345 * Returns 0 always.
2346 *
2347 * Side effects:
2348 * If the name already is in the table, free this cell's use-id
2349 * and set it to NULL. In any event, add the name to the table.
2350 *
2351 * ----------------------------------------------------------------------------
2352 */
2353
2354 int
dbFindNamesFunc(use,parentDef)2355 dbFindNamesFunc(use, parentDef)
2356 CellUse *use;
2357 CellDef *parentDef;
2358 {
2359 HashEntry *he;
2360
2361 if (use->cu_id)
2362 {
2363 he = HashFind(&dbUniqueNameTable, use->cu_id);
2364 if (HashGetValue(he))
2365 {
2366 TxError("Duplicate instance-id for cell %s (%s) will be renamed\n",
2367 use->cu_def->cd_name, use->cu_id);
2368 DBUnLinkCell(use, parentDef);
2369 freeMagic(use->cu_id);
2370 use->cu_id = (char *) NULL;
2371 }
2372 HashSetValue(he, use);
2373 }
2374 return (0);
2375 }
2376
2377 /*
2378 * ----------------------------------------------------------------------------
2379 *
2380 * dbGenerateUniqueIdsFunc --
2381 *
2382 * Called via DBCellEnum() on behalf of DBGenerateUniqueIds() above,
2383 * for each subcell of the def just processed. If the cell has no
2384 * use-id, we generate one automatically. In any event, install the
2385 * use identifier for each cell processed in the HashTable
2386 * parentDef->cd_idHash.
2387 *
2388 * Algorithm:
2389 * We generate unique use-id's of the form def_# where #
2390 * is an integer such that no other use-id in this cell has
2391 * the same name. The HashTable dbUniqueDefTable is indexed
2392 * by CellDef and contains the highest sequence number (#
2393 * above) processed for that CellDef. Each time we process
2394 * a cell, we start with this sequence number and continue
2395 * to increment it until we find a name that is not in
2396 * calmaNamesTable, then generate the use-id, and store
2397 * the next sequence number in the HashEntry for the CellDef.
2398 *
2399 * Results:
2400 * Returns 0 always.
2401 *
2402 * Side effects:
2403 * See above.
2404 *
2405 * ----------------------------------------------------------------------------
2406 */
2407
2408 int
dbGenerateUniqueIdsFunc(use,parentDef)2409 dbGenerateUniqueIdsFunc(use, parentDef)
2410 CellUse *use;
2411 CellDef *parentDef;
2412 {
2413 HashEntry *hedef, *hename;
2414 int suffix;
2415 char name[1024];
2416
2417 if (use->cu_id)
2418 goto setHash;
2419
2420 hedef = HashFind(&dbUniqueDefTable, (char *) use->cu_def);
2421 for (suffix = (spointertype) HashGetValue(hedef); ; suffix++)
2422 {
2423 (void) sprintf(name, "%s_%d", use->cu_def->cd_name, suffix);
2424 hename = HashLookOnly(&dbUniqueNameTable, name);
2425 if (hename == NULL)
2426 break;
2427 }
2428
2429 if (dbWarnUniqueIds)
2430 TxPrintf("Setting instance-id of cell %s to %s\n",
2431 use->cu_def->cd_name, name);
2432 use->cu_id = StrDup((char **) NULL, name);
2433 HashSetValue(hedef, (spointertype)suffix + 1);
2434
2435 setHash:
2436 DBSetUseIdHash(use, parentDef);
2437 return (0);
2438 }
2439
2440 /*
2441 * ----------------------------------------------------------------------------
2442 *
2443 * DBSetUseIdHash --
2444 *
2445 * Update the use-id hash table in parentDef to reflect the fact
2446 * that 'use' now has instance-id use->cu_id.
2447 *
2448 * Results:
2449 * None.
2450 *
2451 * Side effects:
2452 * See above.
2453 *
2454 * ----------------------------------------------------------------------------
2455 */
2456
2457 void
DBSetUseIdHash(use,parentDef)2458 DBSetUseIdHash(use, parentDef)
2459 CellUse *use;
2460 CellDef *parentDef;
2461 {
2462 HashEntry *he;
2463
2464 he = HashFind(&parentDef->cd_idHash, use->cu_id);
2465 HashSetValue(he, (ClientData) use);
2466 }
2467
2468 /*
2469 * ----------------------------------------------------------------------------
2470 *
2471 * DBUnLinkCell --
2472 *
2473 * Update the use-id hash table in parentDef to reflect the fact
2474 * that 'use' no longer is known by instance-id use->cu_id.
2475 *
2476 * Results:
2477 * None.
2478 *
2479 * Side effects:
2480 * See above.
2481 *
2482 * ----------------------------------------------------------------------------
2483 */
2484
2485 void
DBUnLinkCell(use,parentDef)2486 DBUnLinkCell(use, parentDef)
2487 CellUse *use;
2488 CellDef *parentDef;
2489 {
2490 HashEntry *he;
2491
2492 if (he = HashLookOnly(&parentDef->cd_idHash, use->cu_id))
2493 HashSetValue(he, (ClientData) NULL);
2494 }
2495
2496
2497 /*
2498 * ----------------------------------------------------------------------------
2499 *
2500 * DBNewYank --
2501 *
2502 * Create a new yank buffer with name 'yname'.
2503 *
2504 * Results:
2505 * None.
2506 *
2507 * Side effects:
2508 * Fills in *pydef with a newly created CellDef by that name, and
2509 * *pyuse with a newly created CellUse pointing to the new def.
2510 * The CellDef pointed to by *pydef has the CD_INTERNAL flag
2511 * set, and is marked as being available.
2512 *
2513 * ----------------------------------------------------------------------------
2514 */
2515
2516 void
DBNewYank(yname,pyuse,pydef)2517 DBNewYank(yname, pyuse, pydef)
2518 char *yname; /* Name of yank buffer */
2519 CellUse **pyuse; /* Pointer to new cell use is stored in *pyuse */
2520 CellDef **pydef; /* Similarly for def */
2521 {
2522 *pydef = DBCellLookDef(yname);
2523 if (*pydef == (CellDef *) NULL)
2524 {
2525 *pydef = DBCellNewDef(yname);
2526 ASSERT(*pydef != (CellDef *) NULL, "DBNewYank");
2527 DBCellSetAvail(*pydef);
2528 (*pydef)->cd_flags |= CDINTERNAL;
2529 }
2530 *pyuse = DBCellNewUse(*pydef, (char *) NULL);
2531 DBSetTrans(*pyuse, &GeoIdentityTransform);
2532 (*pyuse)->cu_expandMask = CU_DESCEND_SPECIAL; /* This is always expanded. */
2533 }
2534
2535