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