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(¢er, 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