1 /* CIFreadcell.c -
2  *
3  *	This file contains more routines to parse CIF files.  In
4  *	particular, it contains the routines to handle cells,
5  *	both definitions and calls, and user-defined features
6  *	like labels.
7  *
8  *     *********************************************************************
9  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
10  *     * Permission to use, copy, modify, and distribute this              *
11  *     * software and its documentation for any purpose and without        *
12  *     * fee is hereby granted, provided that the above copyright          *
13  *     * notice appear in all copies.  The University of California        *
14  *     * makes no representations about the suitability of this            *
15  *     * software for any purpose.  It is provided "as is" without         *
16  *     * express or implied warranty.  Export of this software outside     *
17  *     * of the United States of America may require an export license.    *
18  *     *********************************************************************
19  */
20 
21 #ifndef lint
22 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFrdcl.c,v 1.5 2010/08/25 17:33:55 tim Exp $";
23 #endif  /* not lint */
24 
25 #include <stdio.h>
26 #include <string.h>
27 #include <ctype.h>
28 
29 #include "utils/magic.h"
30 #include "utils/malloc.h"
31 #include "utils/geometry.h"
32 #include "tiles/tile.h"
33 #include "utils/hash.h"
34 #include "utils/undo.h"
35 #include "database/database.h"
36 #include "cif/CIFint.h"
37 #include "cif/CIFread.h"
38 #include "cif/cif.h"
39 #include "calma/calma.h"
40 #include "utils/utils.h"
41 #include "windows/windows.h"
42 #include "dbwind/dbwind.h"
43 #include "utils/main.h"
44 #include "drc/drc.h"
45 
46 /* The following variable is made available to the outside world,
47  * and is the cell definition currently being modified.
48  */
49 
50 CellDef *cifReadCellDef;
51 
52 /*
53  * The following hash table is used internally to keep track of
54  * of all the cells we've seen definitions for or calls on.
55  * The hash table entries contain pointers to cellDefs, and
56  * are indexed by CIF cell number.  If the CDAVAILABLE bit is
57  * set it means we've read the cell's contents.  If not set, it
58  * means that the cell has been called but not yet defined.
59  */
60 HashTable CifCellTable;
61 
62 /* The following variable is used to save and restore current
63  * paint layer information so that we can resume the correct
64  * layer after a subcell definition.
65  */
66 
67 Plane *cifOldReadPlane = NULL;
68 
69 /* The following boolean is TRUE if a subcell definition is being
70  * read.  FALSE means we're working on the EditCell.
71  */
72 
73 bool cifSubcellBeingRead;
74 
75 /* The following two collections of planes are used to hold CIF
76  * information while cells are being read in (one set for the
77  * outermost, unnamed cell, and one for the current subcell).
78  * When a cell is complete, then geometrical operations are
79  * performed on the layers and stuff is painted into Magic.
80  */
81 
82 Plane *cifEditCellPlanes[MAXCIFRLAYERS];
83 Plane *cifSubcellPlanes[MAXCIFRLAYERS];
84 Plane **cifCurReadPlanes = cifEditCellPlanes;	/* Set of planes currently
85 						 * in force.
86 						 */
87 TileType cifCurLabelType = TT_SPACE;	/* Magic layer on which to put '94'
88 					 * labels that aren't identified by
89 					 * type.
90 					 */
91 
92 /* Structure used when flattening the CIF hierarchy on read-in */
93 
94 typedef struct {
95     Plane *plane;
96     Transform *trans;
97 } CIFCopyRec;
98 
99 /* The following variable is used to hold a subcell id between
100  * the 91 statement and the (immediately-following?) call statement.
101  * The string this points to is dynamically allocated, so it must
102  * also be freed explicitly.
103  */
104 
105 char *cifSubcellId = NULL;
106 
107 /*
108  * ----------------------------------------------------------------------------
109  *
110  * CIFReadCellInit --
111  *
112  * 	This procedure initializes the data structures in this
113  *	module just prior to reading a CIF file.
114  *
115  *	If ptrkeys is 0, the keys used in this hash table will
116  *	be strings; if it is 1, the keys will be CIF numbers.
117  *
118  * Results:
119  *	None.
120  *
121  * Side effects:
122  *	The cell hash table is initialized, and things are set up
123  *	to put information in the EditCell first.
124  *
125  * ----------------------------------------------------------------------------
126  */
127 
128 void
CIFReadCellInit(ptrkeys)129 CIFReadCellInit(ptrkeys)
130     int ptrkeys;
131 {
132     int i;
133 
134     HashInit(&CifCellTable, 32, ptrkeys);
135     cifReadCellDef = EditCellUse->cu_def;
136     cifSubcellBeingRead = FALSE;
137     cifCurReadPlanes = cifEditCellPlanes;
138     for (i = 0; i < MAXCIFRLAYERS; i += 1)
139     {
140 	if (cifEditCellPlanes[i] == NULL)
141 	    cifEditCellPlanes[i] = DBNewPlane((ClientData) TT_SPACE);
142 	if (cifSubcellPlanes[i] == NULL)
143 	    cifSubcellPlanes[i] = DBNewPlane((ClientData) TT_SPACE);
144     }
145 }
146 
147 /*
148  * ----------------------------------------------------------------------------
149  *
150  * cifForgetCell --
151  *
152  * 	This local procedure is used to find a cell in the subcell
153  *	table and remove its CellDef entry.
154  *
155  * Results:
156  *	FALSE if no such entry was found, otherwise TRUE.
157  *
158  * Side effects:
159  *	Mucks with the CIF cell name hash table.
160  *
161  * ----------------------------------------------------------------------------
162  */
163 
164 bool
cifForgetCell(cifNum)165 cifForgetCell(cifNum)
166     int cifNum;
167 {
168     HashEntry *h;
169 
170     h = HashLookOnly(&CifCellTable, (char *)(spointertype)cifNum);
171     if (h == NULL)
172 	return FALSE;
173     else if (HashGetValue(h) == 0)
174 	return FALSE;
175 
176     HashSetValue(h, 0);
177     return TRUE;
178 }
179 
180 /*
181  * ----------------------------------------------------------------------------
182  *
183  * cifUniqueCell --
184  *
185  *	Attempt to find a cell in the CIF subcell name hash table.
186  *	If one exists, rename its definition so that it will not
187  *	be overwritten when the cell is redefined.
188  *
189  * Results:
190  *	None.
191  *
192  * Side effects:
193  *	None.
194  *
195  * ----------------------------------------------------------------------------
196  */
197 
198 void
cifUniqueCell(cifNum)199 cifUniqueCell(cifNum)
200    int cifNum;
201 {
202     HashEntry *h;
203     CellDef *def, *testdef;
204     char name[17];
205     int reused = 0;
206 
207     h = HashLookOnly(&CifCellTable, (char *)(spointertype)cifNum);
208 
209     if ((h == NULL) || HashGetValue(h) == 0)
210     {
211 	/* Cell was deleted with "DD".  Don't rename anything */
212 	return;
213     }
214 
215     sprintf(name, "%d", cifNum);
216     def = DBCellLookDef(name);
217     if (def == (CellDef *)NULL)
218 	return;
219 
220     /* Cell may have been called but not yet defined---this is okay. */
221     else if ((def->cd_flags & CDAVAILABLE) == 0)
222         return;
223 
224     testdef = def;
225     while (testdef != NULL)
226     {
227 	sprintf(name, "%d_%d", cifNum, ++reused);
228 	testdef = DBCellLookDef(name);
229     }
230     DBCellRenameDef(def, name);
231 
232     h = HashFind(&CifCellTable, (char *)(spointertype)cifNum);
233     HashSetValue(h, 0);
234 
235     CIFReadError("Warning: cell definition %d reused.\n", cifNum);
236 }
237 
238 /*
239  * ----------------------------------------------------------------------------
240  *
241  * cifFindCell --
242  *
243  * 	This local procedure is used to find a cell in the subcell
244  *	table, and create a new subcell if there isn't already
245  *	one there.  If a new subcell is created, its CDAVAILABLE
246  *	is left FALSE.
247  *
248  * Results:
249  *	The return value is a pointer to the definition for the
250  *	cell whose CIF number is cifNum.
251  *
252  * Side effects:
253  *	A new CellDef may be created.
254  *
255  * ----------------------------------------------------------------------------
256  */
257 
258 CellDef *
cifFindCell(cifNum)259 cifFindCell(cifNum)
260     int cifNum;			/* The CIF number of the desired cell. */
261 {
262     HashEntry *h;
263     CellDef *def, *testdef;
264     int reused;
265 
266     h = HashFind(&CifCellTable, (char *)(spointertype)cifNum);
267 
268     if (HashGetValue(h) == 0)
269     {
270 	char name[15];
271 
272 	sprintf(name, "%d", cifNum);
273 	def = DBCellLookDef(name);
274 	if (def == NULL)
275 	{
276 	    def = DBCellNewDef(name);
277 
278 	    /* Tricky point:  call DBReComputeBbox here to make SURE
279 	     * that the cell has a valid bounding box.  Otherwise,
280 	     * if the cell is used in a parent before being defined
281 	     * then it will cause a core dump.
282 	     */
283 
284 	    DBReComputeBbox(def);
285 	}
286 	HashSetValue(h, def);
287     }
288     return (CellDef *) HashGetValue(h);
289 }
290 
291 /*
292  * ----------------------------------------------------------------------------
293  *
294  * CIFScalePlanes --
295  *
296  *   Scale all of the CIF planes by the amount (scalen / scaled)
297  *
298  * ----------------------------------------------------------------------------
299  */
300 
301 void
CIFScalePlanes(scalen,scaled,planearray)302 CIFScalePlanes(scalen, scaled, planearray)
303     int scalen;
304     int scaled;
305     Plane **planearray;
306 {
307     int pNum;
308     Plane *newplane;
309 
310     for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++)
311     {
312 	if (planearray[pNum] != NULL)
313 	{
314 	    newplane = DBNewPlane((ClientData) TT_SPACE);
315 	    DBClearPaintPlane(newplane);
316 	    dbScalePlane(planearray[pNum], newplane, pNum,
317 			scalen, scaled, TRUE);
318 	    DBFreePaintPlane(planearray[pNum]);
319 	    TiFreePlane(planearray[pNum]);
320 	    planearray[pNum] = newplane;
321 	}
322     }
323 }
324 
325 /*
326  * ----------------------------------------------------------------------------
327  *
328  * CIFInputRescale --
329  *
330  *	Scale all CIF distances by n / d.  Normally, rescaling is done in
331  *	the upward direction (n > 1, d = 1) in response to a value in the
332  *	CIF input that does not divide evenly into the database units of
333  *	the CIF planes.  Currently there is no call to CIFInputRescale
334  *	with d > 1, but it is left for the possibility that scalefactors
335  *	could be restored after finishing a subcell definition, possibly
336  *	preventing integer overflow in large designs.
337  *
338  * Results:
339  *	None.
340  *
341  * Side effects:
342  *	Many.  Adjusts the CIF input style scalefactor (CIF vs. magic
343  *	units), multiplier (CIF units vs. centimicrons), distances of all
344  *	CIF boolean operations, and the scale of all existing planes in
345  *	the current CIF database.
346  *
347  * ----------------------------------------------------------------------------
348  */
349 
350 void
CIFInputRescale(n,d)351 CIFInputRescale(n, d)
352     int n, d;
353 {
354     CIFReadStyle *istyle = cifCurReadStyle;
355     CIFReadLayer *cl;
356     CIFOp *op;
357     int i;
358 
359     /* 2-step process for efficiency */
360 
361     if (n > 1)
362     {
363 	istyle->crs_scaleFactor *= n;
364 	istyle->crs_multiplier *= n;
365 
366 	for (i = 0; i < istyle->crs_nLayers; i++)
367 	{
368 	    cl = istyle->crs_layers[i];
369 	    for (op = cl->crl_ops; op != NULL; op = op->co_next)
370 		if (op->co_distance)
371 		    op->co_distance *= n;
372 	}
373     }
374 
375     if (d > 1)
376     {
377 	istyle->crs_scaleFactor /= d;
378 	istyle->crs_multiplier /= d;
379 
380 	for (i = 0; i < istyle->crs_nLayers; i++)
381 	{
382 	    cl = istyle->crs_layers[i];
383 	    for (op = cl->crl_ops; op != NULL; op = op->co_next)
384 		if (op->co_distance)
385 		    op->co_distance /= d;
386 	}
387     }
388 
389     CIFScalePlanes(n, d, cifCurReadPlanes);
390     if (cifCurReadPlanes != cifEditCellPlanes)
391 	CIFScalePlanes(n, d, cifEditCellPlanes);
392     if (cifEditCellPlanes != cifSubcellPlanes && cifCurReadPlanes != cifSubcellPlanes)
393 	CIFScalePlanes(n, d, cifSubcellPlanes);
394 
395     CIFReadWarning("CIF style %s: units rescaled by factor of %d / %d\n",
396 		istyle->crs_name, n, d);
397 }
398 
399 /*
400  * ----------------------------------------------------------------------------
401  *
402  * CIFParseStart --
403  *
404  * 	Parse the beginning of a symbol (cell) definition.
405  *	ds ::= D { blank } S integer [ sep integer sep integer ]
406  *
407  * Results:
408  *	TRUE is returned if the parse completed successfully, and
409  *	FALSE is returned otherwise.
410  *
411  * Side effects:
412  *	Set up information for the new cell, including the CIF
413  *	planes and creating a Magic cell (if one doesn't exist
414  *	already).
415  *
416  * ----------------------------------------------------------------------------
417  */
418 
419 bool
CIFParseStart()420 CIFParseStart()
421 {
422     int		number;
423 
424     if (cifSubcellBeingRead)
425     {
426 	CIFReadError("definition start inside other definition; ignored.\n");
427 	CIFSkipToSemi();
428 	return FALSE;
429     }
430     if (cifSubcellId != NULL)
431     {
432 	CIFReadError("pending call identifier %s discarded.\n", cifSubcellId);
433 	(void) StrDup(&cifSubcellId, (char *) NULL);
434     }
435 
436     /* Take the `S'. */
437 
438     TAKE();
439     if (!CIFParseInteger(&number))
440     {
441 	CIFReadError("definition start, but no symbol number; ignored.\n");
442 	CIFSkipToSemi();
443 	return FALSE;
444     }
445     else if (number < 0)
446     {
447 	CIFReadError("illegal negative symbol number; definition ignored.\n");
448 	CIFSkipToSemi();
449 	return FALSE;
450     }
451 
452     if (!CIFParseInteger(&cifReadScale1))
453     {
454 	cifReadScale1 = 1;
455 	cifReadScale2 = 1;
456     }
457     else
458     {
459 	cifReadScale1 *= cifCurReadStyle->crs_multiplier;  /* Units not centimicrons */
460 
461 	if (!CIFParseInteger(&cifReadScale2))
462 	{
463 	    CIFReadError(
464 	        "only one of two scale factors given; ignored.\n");
465 	    cifReadScale1 = 1;
466 	    cifReadScale2 = 1;
467 	}
468     }
469 
470     if (cifReadScale1 <= 0 || cifReadScale2 <= 0)
471     {
472 	CIFReadError("Illegal scale %d / %d changed to 1 / 1\n",
473 		cifReadScale1, cifReadScale2);
474 	cifReadScale1 = 1;
475 	cifReadScale2 = 1;
476     }
477 
478 
479     /*
480      * Set up the cell definition.
481      */
482 
483     cifUniqueCell(number);
484     cifReadCellDef = cifFindCell(number);
485     DBCellClearDef(cifReadCellDef);
486     DBCellSetAvail(cifReadCellDef);
487 
488     cifOldReadPlane = cifReadPlane;
489     cifReadPlane = (Plane *) NULL;
490     cifSubcellBeingRead = TRUE;
491     cifCurReadPlanes = cifSubcellPlanes;
492     return TRUE;
493 }
494 
495 
496 /*
497  * ----------------------------------------------------------------------------
498  * cifCheckPaintFunc ---
499  *
500  *	Callback function for checking if any paint has been generated
501  *	on the CIF target plane for a "copyup" layer.
502  * ----------------------------------------------------------------------------
503  */
504 
cifCheckPaintFunc(tile,clientData)505 int cifCheckPaintFunc(tile, clientData)
506     Tile *tile;
507     ClientData clientData;
508 {
509     return 1;
510 }
511 
512 /* Callback function for copying paint from one CIF cell into another */
513 
514 int
cifCopyPaintFunc(tile,cifCopyRec)515 cifCopyPaintFunc(tile, cifCopyRec)
516     Tile *tile;
517     CIFCopyRec *cifCopyRec;
518 {
519     int pNum;
520     TileType dinfo;
521     Rect sourceRect, targetRect;
522     Transform *trans = cifCopyRec->trans;
523     Plane *plane = cifCopyRec->plane;
524 
525     dinfo = TiGetTypeExact(tile);
526 
527     if (trans)
528     {
529         TiToRect(tile, &sourceRect);
530         GeoTransRect(trans, &sourceRect, &targetRect);
531 	if (IsSplit(tile))
532 	    dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans);
533     }
534     else
535         TiToRect(tile, &targetRect);
536 
537     DBNMPaintPlane(plane, dinfo, &targetRect, CIFPaintTable,
538                 (PaintUndoInfo *)NULL);
539 
540     return 0;
541 }
542 
543 /*
544  * ----------------------------------------------------------------------------
545  *
546  * CIFPaintCurrent --
547  *
548  * 	This procedure does geometrical processing on the current
549  *	set of CIF planes, and paints the results into the current
550  *	CIF cell.
551  *
552  * Results:
553  *	Return 0
554  *
555  * Side effects:
556  *	Lots of information gets added to the current Magic cell.
557  *
558  * ----------------------------------------------------------------------------
559  */
560 
561 int
CIFPaintCurrent(filetype)562 CIFPaintCurrent(filetype)
563     bool filetype;
564 {
565     extern int cifMakeBoundaryFunc();	/* Forward declaration. */
566     extern int cifPaintCurrentFunc();	/* Forward declaration. */
567 
568     Plane *plane, *swapplane;
569     int i;
570 
571     for (i = 0; i < cifCurReadStyle->crs_nLayers; i++)
572     {
573 	TileType type;
574 	CIFOp *op;
575 
576 	plane = CIFGenLayer(cifCurReadStyle->crs_layers[i]->crl_ops,
577 	    &TiPlaneRect, (CellDef *)NULL, (CellDef *)NULL,
578 	    cifCurReadPlanes, FALSE, (ClientData)NULL);
579 
580 	/* Generate a paint/erase table, then paint from the CIF
581 	 * plane into the current Magic cell.
582 	 */
583 	type = cifCurReadStyle->crs_layers[i]->crl_magicType;
584 
585 	if (cifCurReadStyle->crs_layers[i]->crl_flags & CIFR_TEMPLAYER)
586 	{
587 	    op = cifCurReadStyle->crs_layers[i]->crl_ops;
588 	    while (op)
589 	    {
590 		if (op->co_opcode == CIFOP_COPYUP) break;
591 		op = op->co_next;
592 	    }
593 
594 	    /* Quick check to see if anything was generated	*/
595 	    /* on this layer.					*/
596 
597 	    if (op && (DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
598 			&DBAllButSpaceBits, cifCheckPaintFunc,
599 			(ClientData)NULL) == 1))
600 	    {
601 		/* Copy-up function */
602 
603 		int pNum;
604 		Plane *newplane;
605 		Plane **parray;
606 		extern char *(cifReadLayers[MAXCIFRLAYERS]);
607 
608 		/* NOTE:  The condition cd_client == 0 when CDFLATGDS
609 		 * indicates that the cell was already in memory when the
610 		 * GDS was read.  This condition should be properly caught
611 		 * and handled.
612 		 */
613 		if ((cifReadCellDef->cd_flags & CDFLATGDS) &&
614 				(cifReadCellDef->cd_client != (ClientData)0))
615 		    parray = (Plane **)cifReadCellDef->cd_client;
616 		else
617 		{
618 		    parray = (Plane **)mallocMagic(MAXCIFRLAYERS * sizeof(Plane *));
619 		    cifReadCellDef->cd_flags |= CDFLATGDS;
620 		    cifReadCellDef->cd_flags &= ~CDFLATTENED;
621 		    cifReadCellDef->cd_client = (ClientData)parray;
622 		    for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++)
623 			parray[pNum] = NULL;
624 		}
625 
626 		for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++)
627 		{
628 		    if (TTMaskHasType(&op->co_cifMask, pNum))
629 		    {
630 			CIFCopyRec cifCopyRec;
631 
632 			newplane = parray[pNum];
633 			if (newplane == NULL)
634 		 	{
635 			    newplane = DBNewPlane((ClientData) TT_SPACE);
636 			    DBClearPaintPlane(newplane);
637 			}
638 
639 			cifCopyRec.plane = newplane;
640 			cifCopyRec.trans = NULL;
641 
642 			DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
643 				&DBAllButSpaceBits, cifCopyPaintFunc,
644 				&cifCopyRec);
645 
646 			parray[pNum] = newplane;
647 		    }
648 		}
649 	    }
650 	    else if (op == NULL)
651 	    {
652 		/* Handle boundary layer */
653 
654 		op = cifCurReadStyle->crs_layers[i]->crl_ops;
655 		while (op)
656 		{
657 		    if (op->co_opcode == CIFOP_BOUNDARY) break;
658 		    op = op->co_next;
659 		}
660 
661 		if (op && (DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
662 			&DBAllButSpaceBits, cifCheckPaintFunc,
663 			(ClientData)NULL) == 1))
664 		    DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
665 			&CIFSolidBits, cifMakeBoundaryFunc, (ClientData)filetype);
666 	    }
667 
668 	    /* Swap planes */
669 	    swapplane = cifCurReadPlanes[type];
670 	    cifCurReadPlanes[type] = plane;
671 	    plane = swapplane;
672 	}
673 	else
674 	{
675 	    DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect,
676 			&CIFSolidBits, cifPaintCurrentFunc,
677 			(ClientData)type);
678 	}
679 
680 	/* Recycle the plane, which was dynamically allocated. */
681 
682 	DBFreePaintPlane(plane);
683 	TiFreePlane(plane);
684     }
685 
686     /* Now go through all the current planes and zero them out. */
687 
688     for (i = 0; i < MAXCIFRLAYERS; i++)
689 	DBClearPaintPlane(cifCurReadPlanes[i]);
690 
691     return 0;
692 }
693 
694 /* Use CIF layer geometry to define a fixed bounding box for the current cell */
695 
696 int
cifMakeBoundaryFunc(tile,clientdata)697 cifMakeBoundaryFunc(tile, clientdata)
698     Tile *tile;			/* Tile of CIF information. */
699     ClientData clientdata;	/* Pass the file type (CIF or CALMA) */
700 {
701     /* It is assumed that there is one rectangle for the boundary.  */
702     /* If there are multiple rectangles defined with the boundary   */
703     /* layer, then the last one defines the FIXED_BBOX property.    */
704 
705     Rect area;
706     char propertyvalue[128], *storedvalue;
707     int savescale;
708     bool filetype = (bool)clientdata;
709 
710     TiToRect(tile, &area);
711     area.r_xtop = CIFScaleCoord(area.r_xtop, COORD_EXACT);
712     savescale = cifCurReadStyle->crs_scaleFactor;
713     area.r_ytop = CIFScaleCoord(area.r_ytop, COORD_EXACT);
714     if (savescale != cifCurReadStyle->crs_scaleFactor)
715     {
716 	area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor);
717 	savescale = cifCurReadStyle->crs_scaleFactor;
718     }
719     area.r_xbot = CIFScaleCoord(area.r_xbot, COORD_EXACT);
720     if (savescale != cifCurReadStyle->crs_scaleFactor)
721     {
722 	area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor);
723 	area.r_ytop *= (savescale / cifCurReadStyle->crs_scaleFactor);
724 	savescale = cifCurReadStyle->crs_scaleFactor;
725     }
726     area.r_ybot = CIFScaleCoord(area.r_ybot, COORD_EXACT);
727     if (savescale != cifCurReadStyle->crs_scaleFactor)
728     {
729 	area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor);
730 	area.r_ytop *= (savescale / cifCurReadStyle->crs_scaleFactor);
731 	area.r_xbot *= (savescale / cifCurReadStyle->crs_scaleFactor);
732     }
733 
734     if (cifReadCellDef->cd_flags & CDFIXEDBBOX)
735     {
736 	char *propvalue;
737 	bool found;
738 
739 	/* Only flag a warning if the redefined boundary was	*/
740 	/* different from the original.				*/
741 
742 	propvalue = (char *)DBPropGet(cifReadCellDef, "FIXED_BBOX", &found);
743 	if (found)
744 	{
745 	    Rect bbox;
746 	    if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
747 		    &bbox.r_xtop, &bbox.r_ytop) == 4)
748 	    {
749 		if ((bbox.r_xbot != area.r_xbot) ||
750 			(bbox.r_ybot != area.r_ybot) ||
751 			(bbox.r_xtop != area.r_xtop) ||
752 			(bbox.r_ytop != area.r_ytop))
753 		{
754 		    if (filetype == FILE_CIF)
755 			CIFReadError("Warning:  Cell %s boundary was redefined.\n",
756 				cifReadCellDef->cd_name);
757 		    else
758 			CalmaReadError("Warning:  Cell %s boundary was redefined.\n",
759 				cifReadCellDef->cd_name);
760 		}
761 	    }
762 	}
763     }
764 
765     sprintf(propertyvalue, "%d %d %d %d",
766 	    area.r_xbot, area.r_ybot, area.r_xtop, area.r_ytop);
767     storedvalue = StrDup((char **)NULL, propertyvalue);
768     DBPropPut(cifReadCellDef, "FIXED_BBOX", storedvalue);
769     cifReadCellDef->cd_flags |= CDFIXEDBBOX;
770     return 0;
771 }
772 
773 /* Paint CIF layer geometry into the current cell def as magic layer "type"	*/
774 
775 int
cifPaintCurrentFunc(tile,type)776 cifPaintCurrentFunc(tile, type)
777     Tile *tile;			/* Tile of CIF information. */
778     TileType type;		/* Magic type to be painted. */
779 {
780     Rect area;
781     int pNum;
782     int savescale;
783     bool snap_type = COORD_EXACT;
784 
785     /* Contact types are allowed to be on half-lambda spacing, and are	*/
786     /* snapped to the nearest magic coordinate if the result is a	*/
787     /* fractional magic coordinate.					*/
788 
789     if (DBIsContact(type)) snap_type = COORD_HALF_U;
790 
791     /* Compute the area of the CIF tile, then scale it into
792      * Magic coordinates.
793      */
794 
795     TiToRect(tile, &area);
796     area.r_xtop = CIFScaleCoord(area.r_xtop, snap_type);
797     savescale = cifCurReadStyle->crs_scaleFactor;
798     area.r_ytop = CIFScaleCoord(area.r_ytop, snap_type);
799     if (snap_type == COORD_HALF_U) snap_type = COORD_HALF_L;
800     if (savescale != cifCurReadStyle->crs_scaleFactor)
801     {
802 	area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor);
803 	savescale = cifCurReadStyle->crs_scaleFactor;
804     }
805     area.r_xbot = CIFScaleCoord(area.r_xbot, snap_type);
806     if (savescale != cifCurReadStyle->crs_scaleFactor)
807     {
808 	area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor);
809 	area.r_ytop *= (savescale / cifCurReadStyle->crs_scaleFactor);
810 	savescale = cifCurReadStyle->crs_scaleFactor;
811     }
812     area.r_ybot = CIFScaleCoord(area.r_ybot, snap_type);
813     if (savescale != cifCurReadStyle->crs_scaleFactor)
814     {
815 	area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor);
816 	area.r_ytop *= (savescale / cifCurReadStyle->crs_scaleFactor);
817 	area.r_xbot *= (savescale / cifCurReadStyle->crs_scaleFactor);
818     }
819 
820     /* Check for degenerate areas (from rescale limiting) before painting */
821     if ((area.r_xbot == area.r_xtop) || (area.r_ybot == area.r_ytop))
822 	return 0;
823 
824     for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
825 	if (DBPaintOnPlane(type, pNum))
826 	{
827 	    DBNMPaintPlane(cifReadCellDef->cd_planes[pNum], TiGetTypeExact(tile),
828 		    &area, DBStdPaintTbl(type, pNum), (PaintUndoInfo *) NULL);
829 	}
830 
831     return  0;		/* To keep the search alive. */
832 }
833 
834 /*
835  * ----------------------------------------------------------------------------
836  *
837  * CIFParseFinish --
838  *
839  * 	This procedure is called at the end of a cell definition.
840  *
841  * Results:
842  *	TRUE is returned if the parse completed successfully, and
843  *	FALSE is returned otherwise.
844  *
845  * Side effects:
846  *	Process the CIF planes and paint the results into the Magic
847  *	cell.
848  *
849  * ----------------------------------------------------------------------------
850  */
851 
852 bool
CIFParseFinish()853 CIFParseFinish()
854 {
855     if (!cifSubcellBeingRead)
856     {
857 	CIFReadError("definition finish without definition start; ignored.\n");
858 	CIFSkipToSemi();
859 	return FALSE;
860     }
861     if (cifSubcellId != NULL)
862     {
863 	CIFReadError("pending call identifier %s discarded.\n", cifSubcellId);
864 	(void) StrDup(&cifSubcellId, (char *) NULL);
865     }
866 
867     /* Take the `F'. */
868 
869     TAKE();
870 
871     /* Do the geometrical processing and paint this material back into
872      * the appropriate cell of the database.  Then restore the saved
873      * layer info.
874      */
875 
876     CIFPaintCurrent(FILE_CIF);
877 
878     DBAdjustLabels(cifReadCellDef, &TiPlaneRect);
879     DBReComputeBbox(cifReadCellDef);
880     cifReadCellDef = EditCellUse->cu_def;
881     cifReadPlane = cifOldReadPlane;
882     cifReadScale1 = 1;
883     cifReadScale2 = 1;
884     cifSubcellBeingRead = FALSE;
885     cifCurReadPlanes = cifEditCellPlanes;
886     return TRUE;
887 }
888 
889 /*
890  * ----------------------------------------------------------------------------
891  *
892  * CIFParseDelete --
893  *
894  * 	This procedure is called to handle delete-symbol statements.
895  *
896  * Results:
897  *	TRUE is returned if the parse completed successfully, and
898  *	FALSE is returned otherwise.
899  *
900  * Side effects:
901  *	The mapping between numbers and cells is modified to eliminate
902  *	some symbols.
903  *
904  * ----------------------------------------------------------------------------
905  */
906 
907 bool
CIFParseDelete()908 CIFParseDelete()
909 {
910     int		number;
911 
912     /* Take the `D'. */
913 
914     TAKE();
915     if (!CIFParseInteger(&number))
916     {
917 	CIFReadError("definition delete, but no symbol number; ignored.\n");
918 	CIFSkipToSemi();
919 	return FALSE;
920     }
921 
922     /* Unlink the hash entry from its target definition */
923     cifForgetCell(number);
924 
925     CIFSkipToSemi();
926     return TRUE;
927 }
928 
929 /*
930  * ----------------------------------------------------------------------------
931  *
932  * cifParseName --
933  *
934  * 	Parse a name, which is a string of alphabetics, numerics,
935  *	or underscores, possibly preceded by whitespace.
936  *
937  * Results:
938  *	The return value is a pointer to the name read from the
939  *	CIF file.  This is a statically-allocated area, so the
940  *	caller should copy out of this area before invoking this
941  *	procedure again.
942  *
943  * Side effects:
944  *	None.
945  *
946  * ----------------------------------------------------------------------------
947  */
948 
949 char *
cifParseName()950 cifParseName()
951 {
952     char	ch;
953     char	*bufferp;
954     static char	buffer[128];
955 
956     /* Skip white space. */
957 
958     for (ch = PEEK() ; ch == ' ' || ch == '\t' ; ch = PEEK())
959 	TAKE();
960 
961     /* Read the string. */
962 
963     bufferp = &buffer[0];
964     for (ch = PEEK() ; (! isspace(ch)) && ch != ';' ; ch = PEEK())
965     {
966 	*bufferp++ = TAKE();
967     }
968     *bufferp = '\0';
969     return buffer;
970 }
971 
972 /*
973  * ----------------------------------------------------------------------------
974  *
975  * cifParseUser9 --
976  *
977  * 	This procedure processes user extension 9: the name of the
978  *	current symbol (cell) definition.
979  *
980  * Results:
981  *	TRUE is returned if the parse completed successfully, and
982  *	FALSE is returned otherwise.
983  *
984  * Side effects:
985  *	The current CIF symbol is renamed from its default "cifxx" name
986  *	to the given name.
987  *
988  * ----------------------------------------------------------------------------
989  */
990 
991 bool
cifParseUser9()992 cifParseUser9()
993 {
994     char *name;
995 
996     name = cifParseName();
997     if (!DBCellRenameDef(cifReadCellDef, name))
998     {
999 	CIFReadError("%s already exists, so cell from CIF is named %s.\n",
1000 		name, cifReadCellDef->cd_name);
1001     }
1002     return TRUE;
1003 }
1004 
1005 /*
1006  * ----------------------------------------------------------------------------
1007  *
1008  * CIFParseCall --
1009  *
1010  * 	This procedure processes subcell uses.  The syntax of a call is
1011  *	call ::= C integer transform
1012  *
1013  * Results:
1014  *	TRUE is returned if the parse completed successfully, and
1015  *	FALSE is returned otherwise.
1016  *
1017  * Side effects:
1018  *	A subcell is added to the current Magic cell we're generating.
1019  *
1020  * ----------------------------------------------------------------------------
1021  */
1022 
1023 bool
CIFParseCall()1024 CIFParseCall()
1025 {
1026     int		called;
1027     Transform	transform;
1028     CellUse 	*use;
1029     CellDef	*def;
1030 
1031     /* Take the `C'. */
1032 
1033     TAKE();
1034     if (!CIFParseInteger(&called))
1035     {
1036 	CIFReadError("call, but no symbol number; ignored.\n");
1037 	CIFSkipToSemi();
1038 	return FALSE;
1039     }
1040 
1041     /* Get optional transformation. */
1042 
1043     (void) CIFParseTransform(&transform);
1044 
1045     def = cifFindCell(called);
1046 
1047     /* avoid recursion
1048      */
1049 
1050     if (DBIsAncestor(def, cifReadCellDef))
1051     {
1052 	CIFReadError("attempt to place cell use inside its own definition!\n");
1053 	CIFSkipToSemi();
1054 	return FALSE;
1055     }
1056 
1057     /* Find the use and add it to the current cell.  Give it an
1058      * id also.
1059      */
1060 
1061     use = DBCellNewUse(def, cifSubcellId);
1062     (void) DBLinkCell(use, cifReadCellDef);
1063     DBSetTrans(use, &transform);
1064     DBPlaceCell(use, cifReadCellDef);
1065 
1066     (void) StrDup(&cifSubcellId, (char *) NULL);
1067     return TRUE;
1068 }
1069 
1070 /*
1071  * ----------------------------------------------------------------------------
1072  *
1073  * cifParseUser91 --
1074  *
1075  * 	This procedure handles 91 user commands, which provide id's
1076  *	for following cell calls.  The syntax is:
1077  *	91 ::= 91 blanks name
1078  *
1079  * Results:
1080  *	TRUE is returned if the parse completed successfully, and
1081  *	FALSE is returned otherwise.
1082  *
1083  * Side effects:
1084  *	The identifier is saved until the call is read.  Then it is
1085  *	used as the identifier for the cell.
1086  *
1087  * ----------------------------------------------------------------------------
1088  */
1089 
1090 bool
cifParseUser91()1091 cifParseUser91()
1092 {
1093     if (cifSubcellId != NULL)
1094     {
1095 	CIFReadError("91 command with identifier %s pending; %s discarded.\n" ,
1096 	    cifSubcellId , cifSubcellId);
1097     }
1098     (void) StrDup(&cifSubcellId, cifParseName());
1099     return TRUE;
1100 }
1101 
1102 /*
1103  * ----------------------------------------------------------------------------
1104  *
1105  * cifParseUser94 --
1106  *
1107  * 	This procedure parses 94 user commands, which are labelled
1108  *	points.  The syntax is:
1109  *	94 ::= 94 blanks name point
1110  *
1111  * Results:
1112  *	TRUE is returned if the parse completed successfully, and
1113  *	FALSE is returned otherwise.
1114  *
1115  * Side effects:
1116  *	A label is added to the current cell.
1117  *
1118  * ----------------------------------------------------------------------------
1119  */
1120 
1121 bool
cifParseUser94()1122 cifParseUser94()
1123 {
1124     Rect rectangle;
1125     char *name = NULL;
1126     TileType type;
1127     int layer, flags, i;
1128     int savescale;
1129 
1130     (void) StrDup(&name, cifParseName());
1131     if (! CIFParsePoint(&rectangle.r_ll, 1))
1132     {
1133 	CIFReadError("94 command, but no location; ignored.\n");
1134 	CIFSkipToSemi();
1135 	return FALSE;
1136     }
1137 
1138     /* Scale the coordinates, then make the location into a
1139      * rectangle.
1140      */
1141 
1142     rectangle.r_xbot = CIFScaleCoord(rectangle.r_xbot, COORD_ANY);
1143     savescale = cifCurReadStyle->crs_scaleFactor;
1144     rectangle.r_ybot = CIFScaleCoord(rectangle.r_ybot, COORD_ANY);
1145     if (savescale != cifCurReadStyle->crs_scaleFactor)
1146 	rectangle.r_xbot *= (savescale / cifCurReadStyle->crs_scaleFactor);
1147 
1148     rectangle.r_ur = rectangle.r_ll;
1149 
1150     /* Get a layer, lookup the layer, then add the label to the
1151      * current cell.  Tricky business: in order for the default
1152      * label location to be computed
1153      */
1154 
1155     CIFSkipBlanks();
1156     if (PEEK() != ';')
1157     {
1158 	char *lname = cifParseName();
1159 	layer = CIFReadNameToType(lname, FALSE);
1160 	if (layer < 0)
1161 	{
1162 	    CIFReadError("label attached to unknown layer %s.\n",
1163 		    lname);
1164 	    type = TT_SPACE;
1165 	}
1166 	else {
1167 	    type = cifCurReadStyle->crs_labelLayer[layer];
1168 	}
1169     } else {
1170 	type = cifCurLabelType;
1171 
1172 	/* Should do this better, by defining cifCurLabelFlags. . . */
1173 	layer = -1;
1174 	for (i = 0; i < cifCurReadStyle->crs_nLayers; i++)
1175 	    if (cifCurReadStyle->crs_labelLayer[i] == type) {
1176 		layer = i;
1177 		break;
1178 	    }
1179     }
1180     if (type >=0 )
1181     {
1182 	if (layer >= 0 && cifCurReadStyle->crs_labelSticky[layer])
1183 	    flags = LABEL_STICKY;
1184 	else
1185 	    flags = 0;
1186     	(void) DBPutLabel(cifReadCellDef, &rectangle, -1, name, type, flags, 0);
1187     }
1188     freeMagic(name);
1189     return TRUE;
1190 }
1191 
1192 /*
1193  * ----------------------------------------------------------------------------
1194  *
1195  * cifParseUser95 --
1196  *
1197  * 	This procedure parses 95 user commands, which are labelled
1198  *	points.  The syntax is:
1199  *	95 ::= 95 blanks name length width point
1200  *
1201  * Results:
1202  *	TRUE is returned if the parse completed successfully, and
1203  *	FALSE is returned otherwise.
1204  *
1205  * Side effects:
1206  *	An area label is added to the current cell.
1207  *
1208  * ----------------------------------------------------------------------------
1209  */
1210 
1211 bool
cifParseUser95()1212 cifParseUser95()
1213 {
1214     /* Modified by BIM 1/8/2018 */
1215     Rect rectangle;
1216     Point size, center, lowerleft, upperright;
1217     char *name = NULL;
1218     TileType type;
1219     int layer, i;
1220     int savescale;
1221 
1222     (void) StrDup(&name, cifParseName());
1223 
1224     if (! CIFParsePoint(&size, 1))
1225     {
1226 	CIFReadError("95 command, but no size; ignored.\n");
1227 	CIFSkipToSemi();
1228 	return FALSE;
1229     }
1230 
1231     savescale = cifCurReadStyle->crs_scaleFactor;
1232 
1233     /* The center coordinates returned are in CIF units *2              */
1234     /* the values will be halved later before conversion to magic units */
1235 
1236     if (! CIFParsePoint(&center, 2))
1237     {
1238 	CIFReadError("95 command, but no location; ignored.\n");
1239 	CIFSkipToSemi();
1240 	return FALSE;
1241     }
1242 
1243     /* If reading the center causes a CIF input scale to be redefined,	*/
1244     /* then the length and width must also be changed.			*/
1245 
1246     if (savescale != cifCurReadStyle->crs_scaleFactor)
1247     {
1248 	size.p_x *= (cifCurReadStyle->crs_scaleFactor / savescale);
1249 	size.p_y *= (cifCurReadStyle->crs_scaleFactor / savescale);
1250     }
1251 
1252     /* Scale the coordinates and create the rectangular area.		*/
1253     /* Explicitly calculate lowerleft and upperright using CIF units *2 */
1254     /* so that half-lambda centers are resolved before remapping to	*/
1255     /* magic coordinates.						*/
1256 
1257     lowerleft.p_x = center.p_x - size.p_x;
1258     lowerleft.p_y = center.p_y - size.p_y;
1259 
1260     upperright.p_x = center.p_x + size.p_x;
1261     upperright.p_y = center.p_y + size.p_y;
1262 
1263     if ((lowerleft.p_x % 2 == 0) && (lowerleft.p_y % 2 == 0)) {
1264 
1265       /* if possible convert values to CIF units by dividing by two */
1266 
1267       lowerleft.p_x /= 2;
1268       lowerleft.p_y /= 2;
1269 
1270       upperright.p_x /= 2;
1271       upperright.p_y /= 2;
1272 
1273     } else {
1274 
1275       /* if division by two would create inaccuracy then rescale to accommodate */
1276 
1277       CIFInputRescale(2, 1);
1278 
1279     }
1280 
1281     /* now scale each of the co-ordinates in turn */
1282 
1283     lowerleft.p_x = CIFScaleCoord(lowerleft.p_x, COORD_ANY);
1284     savescale = cifCurReadStyle->crs_scaleFactor;
1285 
1286     lowerleft.p_y = CIFScaleCoord(lowerleft.p_y, COORD_ANY);
1287     if (savescale != cifCurReadStyle->crs_scaleFactor)
1288     {
1289 	lowerleft.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor);
1290 	savescale = cifCurReadStyle->crs_scaleFactor;
1291     }
1292 
1293     upperright.p_x = CIFScaleCoord(upperright.p_x, COORD_ANY);
1294     if (savescale != cifCurReadStyle->crs_scaleFactor)
1295     {
1296 	lowerleft.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor);
1297 	lowerleft.p_y *= (savescale / cifCurReadStyle->crs_scaleFactor);
1298 	savescale = cifCurReadStyle->crs_scaleFactor;
1299     }
1300 
1301     upperright.p_y = CIFScaleCoord(upperright.p_y, COORD_ANY);
1302     if (savescale != cifCurReadStyle->crs_scaleFactor)
1303     {
1304 	lowerleft.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor);
1305 	lowerleft.p_y *= (savescale / cifCurReadStyle->crs_scaleFactor);
1306 	upperright.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor);
1307     }
1308 
1309     rectangle.r_xbot = lowerleft.p_x;
1310     rectangle.r_ybot = lowerleft.p_y;
1311     rectangle.r_xtop = upperright.p_x;
1312     rectangle.r_ytop = upperright.p_y;
1313 
1314     /* Get a layer, lookup the layer, then add the label to the
1315      * current cell.  Tricky business: in order for the default
1316      * label location to be computed
1317      */
1318     CIFSkipBlanks();
1319     if (PEEK() != ';')
1320     {
1321 	char *name = cifParseName();
1322 	layer = CIFReadNameToType(name, FALSE);
1323 	if (layer < 0)
1324 	{
1325 	    CIFReadError("label attached to unknown layer %s.\n",
1326 		    name);
1327 	    type = TT_SPACE;
1328 	}
1329 	else type = cifCurReadStyle->crs_labelLayer[layer];
1330     }
1331     else {
1332 	type = TT_SPACE;
1333 	layer = -1;
1334 	for (i = 0; i < cifCurReadStyle->crs_nLayers; i++)
1335 	    if (cifCurReadStyle->crs_labelLayer[i] == type) {
1336 		layer = i;
1337 		break;
1338 	    }
1339     }
1340     if (type >=0 )
1341     {
1342 	int flags;
1343 	if (layer >= 0 && cifCurReadStyle->crs_labelSticky[layer])
1344 	    flags = LABEL_STICKY;
1345 	else
1346 	    flags = 0;
1347     	(void) DBPutLabel(cifReadCellDef, &rectangle, -1, name, type, flags, 0);
1348     }
1349 
1350     freeMagic(name);
1351     return TRUE;
1352 }
1353 
1354 /*
1355  * ----------------------------------------------------------------------------
1356  *
1357  * CIFParseUser --
1358  *
1359  * 	This procedure is called to process user-defined statements.
1360  *	The syntax is user ::= digit usertext.
1361  *
1362  * Results:
1363  *	TRUE is returned if the parse completed successfully, and
1364  *	FALSE is returned otherwise.
1365  *
1366  * Side effects:
1367  *	Depends on the user command.
1368  *
1369  * ----------------------------------------------------------------------------
1370  */
1371 bool
CIFParseUser()1372 CIFParseUser()
1373 {
1374     char	ch;
1375 
1376     ch = TAKE();
1377     switch (ch)
1378     {
1379 	case '9':
1380 		ch = PEEK();
1381 		switch (ch)
1382 		{
1383 		    case '1':
1384 			(void) TAKE();
1385 			return cifParseUser91();
1386 		    case '4':
1387 			(void) TAKE();
1388 			return cifParseUser94();
1389 		    case '5':
1390 			(void) TAKE();
1391 			return cifParseUser95();
1392 		    default:
1393 			if (isspace(ch)) return cifParseUser9();
1394 		}
1395 	default:
1396 		CIFReadError("unimplemented user extension; ignored.\n");
1397 		CIFSkipToSemi();
1398 		return FALSE;
1399     }
1400 }
1401 
1402 /*
1403  * ----------------------------------------------------------------------------
1404  *
1405  * CIFReadCellCleanup --
1406  *
1407  * 	This procedure is called after processing the CIF file.
1408  *	It performs various cleanup functions on the cells that
1409  *	have been read in.
1410  *
1411  * Results:
1412  *	None.
1413  *
1414  * Side effects:
1415  *	The area of each cell is DRC'ed and redisplayed.  Error
1416  *	messages are output for any cells whose contents weren't
1417  *	in the CIF file.  An error message is also output if
1418  *	we're still in the middle of reading a subcell.
1419  *
1420  * ----------------------------------------------------------------------------
1421  */
1422 
1423 void
CIFReadCellCleanup(filetype)1424 CIFReadCellCleanup(filetype)
1425     bool filetype;
1426 {
1427     HashEntry *h;
1428     HashSearch hs;
1429     CellDef *def;
1430     MagWindow *window;
1431     int flags;
1432 
1433     if (cifSubcellBeingRead)
1434     {
1435 	if (filetype == FILE_CIF)
1436 	    CIFReadError("CIF ended partway through a symbol definition.\n");
1437 	else
1438 	    CalmaReadError("GDS ended partway through a symbol definition.\n");
1439 	(void) CIFParseFinish();
1440     }
1441 
1442     HashStartSearch(&hs);
1443     while (TRUE)
1444     {
1445 	h = HashNext(&CifCellTable, &hs);
1446 	if (h == NULL) break;
1447 
1448 	def = (CellDef *) HashGetValue(h);
1449 	if (def == NULL)
1450 	{
1451 	    if (filetype == FILE_CIF)
1452 		CIFReadError("cell table has NULL entry (Magic error).\n");
1453 	    else
1454 		CalmaReadError("cell table has NULL entry (Magic error).\n");
1455 	    continue;
1456 	}
1457 	flags = def->cd_flags;
1458 	if (!(flags & CDAVAILABLE))
1459 	{
1460 	    if (filetype == FILE_CIF)
1461 		CIFReadError("cell %s was used but not defined.\n", def->cd_name);
1462 	    else
1463 		CalmaReadError("cell %s was used but not defined.\n", def->cd_name);
1464         }
1465 	def->cd_flags &= ~CDPROCESSEDGDS;
1466 
1467 	if ((filetype == FILE_CIF && CIFNoDRCCheck == FALSE) ||
1468 			(filetype == 1 && CalmaNoDRCCheck == FALSE))
1469 	    DRCCheckThis(def, TT_CHECKPAINT, &def->cd_bbox);
1470 	DBWAreaChanged(def, &def->cd_bbox, DBW_ALLWINDOWS, &DBAllButSpaceBits);
1471 	DBCellSetModified(def, TRUE);
1472     }
1473 
1474     /* Do geometrical processing on the top-level cell. */
1475 
1476     CIFPaintCurrent(FILE_CIF);
1477     DBAdjustLabels(EditCellUse->cu_def, &TiPlaneRect);
1478     DBReComputeBbox(EditCellUse->cu_def);
1479     DBWAreaChanged(EditCellUse->cu_def, &EditCellUse->cu_def->cd_bbox,
1480 	    DBW_ALLWINDOWS, &DBAllButSpaceBits);
1481     DBCellSetModified(EditCellUse->cu_def, TRUE);
1482 
1483     /* Clean up saved CIF/GDS planes in cd_client records of cells */
1484 
1485     HashStartSearch(&hs);
1486     while (TRUE)
1487     {
1488 	h = HashNext(&CifCellTable, &hs);
1489 	if (h == NULL) break;
1490 
1491 	def = (CellDef *) HashGetValue(h);
1492 	if (def == NULL) continue;
1493 
1494 	if (def->cd_flags & CDFLATGDS)
1495 	{
1496 	    /* These cells have been flattened and are no longer needed. */
1497 
1498 	    int pNum;
1499 	    Plane **cifplanes = (Plane **)def->cd_client;
1500 
1501 	    UndoDisable();
1502 
1503 	    /* cifplanes should be valid, but don't crash magic if not */
1504 	    if (cifplanes != (Plane **)0)
1505 	    {
1506 
1507 		for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++)
1508 		{
1509 		    if (cifplanes[pNum] != NULL)
1510 		    {
1511 			DBFreePaintPlane(cifplanes[pNum]);
1512 			TiFreePlane(cifplanes[pNum]);
1513 		    }
1514 		}
1515 		freeMagic((char *)def->cd_client);
1516 	    }
1517 	    def->cd_client = (ClientData)0;
1518 
1519 #if 0
1520 	    /* If the CDFLATTENED flag was not set, then this geometry	*/
1521 	    /* was never instantiated, and should generate a message.	*/
1522 	    /* However, this is not an error condition as there are a	*/
1523 	    /* number of useful reasons to copy lots of information up	*/
1524 	    /* the GDS hierarchy for "just in case" scenarios.		*/
1525 
1526 	    if (!(def->cd_flags & CDFLATTENED))
1527 		CIFReadWarning("%s read:  Unresolved geometry in cell"
1528 			" %s maps to no magic layers\n",
1529 			(filetype == FILE_CIF) ? "CIF" : "GDS", def->cd_name);
1530 #endif
1531 
1532 #if 0
1533 	    /* Remove the cell if it has no parents, no children, and no geometry */
1534 	    /* To-do:  Check that these conditions are valid */
1535 
1536 	    if (def->cd_parents == (CellUse *)NULL)
1537 	    {
1538 		char *savename = StrDup((char **)NULL, def->cd_name);
1539 
1540 		if (DBCellDeleteDef(def) == FALSE)
1541 		{
1542 		    CIFReadError("%s read error:  Unable to delete cell %s\n",
1543 				(filetype == FILE_CIF) ? "CIF" : "GDS", savename);
1544 		}
1545 		else
1546 		{
1547 		    if (filetype == FILE_CIF)
1548 			TxPrintf("CIF read:  Removed flattened cell %s\n", savename);
1549 		    else
1550 			TxPrintf("GDS read:  Removed flattened cell %s\n", savename);
1551 		}
1552 		freeMagic(savename);
1553 	    }
1554 #endif
1555 	    UndoEnable();
1556 	}
1557     }
1558     HashKill(&CifCellTable);
1559 }
1560