1 /* CIFreadutils.c -
2 *
3 * This file contains routines that parse a file in CIF
4 * format. This file contains the top-level routine for
5 * reading CIF files, plus a bunch of utility routines
6 * for skipping white space, parsing numbers and points, etc.
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/CIFrdutils.c,v 1.4 2010/06/24 12:37:15 tim Exp $";
23 #endif /* not lint */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <ctype.h>
29
30 #include "utils/magic.h"
31 #include "utils/geometry.h"
32 #include "tiles/tile.h"
33 #include "utils/hash.h"
34 #include "database/database.h"
35 #include "cif/CIFint.h"
36 #include "cif/CIFread.h"
37 #include "cif/cif.h"
38 #include "textio/textio.h"
39 #include "utils/signals.h"
40 #include "utils/undo.h"
41 #include "utils/malloc.h"
42
43 /* The following variables are used to provide one character of
44 * lookahead. cifParseLaAvail is TRUE if cifParseLaChar contains
45 * a valid character, FALSE otherwise. The PEEK and TAKE macros
46 * are used to manipulate this stuff.
47 */
48
49 bool cifParseLaAvail = FALSE;
50 int cifParseLaChar = EOF;
51
52 /* Below is a variable pointing to the CIF input file. It's used
53 * by the PEEK and TAKE macros. The other stuff is used to keep
54 * track of our location in the CIF file for error reporting
55 * purposes.
56 */
57
58 FILE *cifInputFile;
59 FILE *cifErrorFile;
60 int cifLineNumber; /* Number of current line. */
61 int cifTotalWarnings; /* Number of warnings detected */
62 int cifTotalErrors; /* Number of errors detected */
63 bool cifSeenSnapWarning; /* Track this to prevent excessive messaging */
64
65 /* The variables used below hold general information about what
66 * we're currently working on.
67 */
68
69 int cifReadScale1; /* Scale factor: multiply by Scale1 */
70 int cifReadScale2; /* then divide by Scale2. */
71 int CIFRescaleLimit = CIFMAXRESCALE; /* Don't increase cifReadScale1 by more
72 * than this amount; internal units
73 * finer than this will be rounded.
74 */
75 bool CIFRescaleAllow = TRUE; /* Don't subdivide the magic internal
76 * grid if this is FALSE.
77 */
78 bool CIFNoDRCCheck = FALSE; /* If TRUE, then cell is marked DRC clean
79 * and not DRC checked.
80 */
81 char *CIFErrorFilename; /* Name of file for error redirection */
82
83 int CifPolygonCount; /* Count of generated subcells
84 * containing polygons. This number
85 * is used to create a unique cell name.
86 */
87 bool CIFSubcellPolygons = FALSE; /* If TRUE, each non-Manhattan polygon
88 * will be put in a separate subcell
89 * to avoid too much tile splitting
90 */
91
92 Plane *cifReadPlane; /* Plane into which to paint material
93 * NULL means no layer command has
94 * been seen for the current cell.
95 */
96
97 /*
98 * ----------------------------------------------------------------------------
99 *
100 * CIFReadError --
101 *
102 * This procedure is called to print out error messages during
103 * CIF file reading.
104 *
105 * Results:
106 * None.
107 *
108 * Side effects:
109 * An error message is printed.
110 *
111 * ----------------------------------------------------------------------------
112 */
113
114 /* VARARGS1 */
115 void
CIFReadError(char * format,...)116 CIFReadError(char *format, ...)
117 {
118 va_list args;
119
120 cifTotalErrors++;
121 if (CIFWarningLevel == CIF_WARN_NONE) return;
122 if ((cifTotalErrors < 100) || (CIFWarningLevel != CIF_WARN_LIMIT))
123 {
124 if (cifLineNumber > 0)
125 TxError("Error at line %d of CIF file: ", cifLineNumber);
126 else
127 TxError("CIF file read error: ", cifLineNumber);
128 va_start(args, format);
129 Vfprintf(stderr, format, args);
130 va_end(args);
131 }
132 else if ((cifTotalErrors == 100) && (CIFWarningLevel == CIF_WARN_LIMIT))
133 {
134 TxError("Error limit set: Remaining errors will not be reported.\n");
135 }
136 }
137
138
139 void
CIFReadWarning(char * format,...)140 CIFReadWarning(char *format, ...)
141 {
142 va_list args;
143
144 cifTotalWarnings++;
145 if (CIFWarningLevel == CIF_WARN_NONE) return;
146 if ((cifTotalWarnings < 100) || (CIFWarningLevel != CIF_WARN_LIMIT))
147 {
148 if (cifLineNumber > 0)
149 TxError("Warning at line %d of CIF file: ", cifLineNumber);
150 else
151 TxError("CIF file read warning: ");
152 va_start(args, format);
153 Vfprintf(stderr, format, args);
154 va_end(args);
155 }
156 else if ((cifTotalWarnings == 100) && (CIFWarningLevel == CIF_WARN_LIMIT))
157 {
158 TxError("Warning limit set: Remaining warnings will not be reported.\n");
159 }
160 }
161
162 /*
163 * ----------------------------------------------------------------------------
164 *
165 * CIFScaleCoord
166 *
167 * This procedure does rounding and division to convert from
168 * CIF units back into Magic units.
169 *
170 * "snap_type" may be one of:
171 * COORD_EXACT: result must be an exact integer. If not, the
172 * magic grid spacing is changed such that the result will
173 * be an integer.
174 * COORD_HALF_U: twice the result must be an exact integer. If
175 * not, the magic grid spacing is changed as above. If the
176 * result is 1/2, it is rounded up to the nearest integer.
177 * COORD_HALF_L: same as above, but result is rounded down.
178 * COORD_ANY: result may be fractional, and will be snapped to
179 * the nearest magic grid. Generally, this is used for
180 * labels whose position need not be exact.
181 *
182 * Results:
183 * The result is the Magic unit equivalent to cifCoord.
184 *
185 * Side effects:
186 * None.
187 *
188 * ----------------------------------------------------------------------------
189 */
190
191 int
CIFScaleCoord(cifCoord,snap_type)192 CIFScaleCoord(cifCoord, snap_type)
193 int cifCoord; /* A coordinate in CIF units. */
194 int snap_type; /* How to deal with fractional results */
195 {
196 int result, scale, remain, denom;
197 int mult, mfactor;
198
199 /* If internal grid subdivision is disallowed, always round to the */
200 /* nearest grid unit. */
201
202 if (!CIFRescaleAllow)
203 snap_type = COORD_ANY;
204
205 scale = cifCurReadStyle->crs_scaleFactor;
206 mult = cifCurReadStyle->crs_multiplier;
207
208 /* Check for non-integer result and warn of fractional-lambda violation */
209
210 if ((remain = (cifCoord % scale)) != 0)
211 {
212 int lgcf = FindGCF(abs(cifCoord), scale);
213
214 remain = abs(remain) / lgcf;
215 denom = scale / lgcf;
216
217 if (CIFReadTechLimitScale(1, denom)) snap_type = COORD_ANY;
218
219 switch (snap_type)
220 {
221 case COORD_EXACT:
222 if (!cifSeenSnapWarning)
223 CIFReadWarning("Input off lambda grid by %d/%d; grid redefined.\n",
224 remain, denom);
225 cifSeenSnapWarning = TRUE;
226
227 CIFTechInputScale(1, denom, FALSE);
228 CIFTechOutputScale(1, denom);
229 DRCTechScale(1, denom);
230 ExtTechScale(1, denom);
231 WireTechScale(1, denom);
232 #ifdef LEF_MODULE
233 LefTechScale(1, denom);
234 #endif
235 #ifdef ROUTE_MODULE
236 RtrTechScale(1, denom);
237 MZAfterTech();
238 IRAfterTech();
239 #endif
240 DBScaleEverything(denom, 1);
241 DBLambda[1] *= denom;
242 ReduceFraction(&DBLambda[0], &DBLambda[1]);
243 scale = cifCurReadStyle->crs_scaleFactor;
244 result = cifCoord / scale;
245 break;
246 case COORD_HALF_U: case COORD_HALF_L:
247 if (denom > 2)
248 {
249 if (!cifSeenSnapWarning)
250 CIFReadWarning("Input off lambda grid by %d/%d; "
251 "grid redefined.\n", remain, denom);
252 cifSeenSnapWarning = TRUE;
253
254 /* scale to nearest half-lambda */
255 if (!(denom & 0x1)) denom >>= 1;
256
257 CIFTechInputScale(1, denom, FALSE);
258 CIFTechOutputScale(1, denom);
259 DRCTechScale(1, denom);
260 PlowAfterTech();
261 ExtTechScale(1, denom);
262 WireTechScale(1, denom);
263 MZAfterTech();
264 IRAfterTech();
265 #ifdef LEF_MODULE
266 LefTechScale(1, denom);
267 #endif
268 #ifdef ROUTE_MODULE
269 RtrTechScale(1, denom);
270 #endif
271 DBScaleEverything(denom, 1);
272 DBLambda[1] *= denom;
273 ReduceFraction(&DBLambda[0], &DBLambda[1]);
274 scale = cifCurReadStyle->crs_scaleFactor;
275 }
276
277 if (snap_type == COORD_HALF_U)
278 result = cifCoord + (scale >> 1);
279 else
280 result = cifCoord - (scale >> 1);
281 result /= scale;
282
283 break;
284 case COORD_ANY:
285 if (!cifSeenSnapWarning)
286 CIFReadWarning("Input off lambda grid by %d/%d; snapped to grid.\n",
287 abs(remain), abs(denom));
288 cifSeenSnapWarning = TRUE;
289
290 /* Careful: must round down a bit more for negative numbers, in
291 * order to ensure that a point exactly halfway between Magic units
292 * always gets rounded down, rather than towards zero (this would
293 * result in different treatment of the same paint, depending on
294 * where it is in the coordinate system.
295 */
296
297 if (cifCoord < 0)
298 result = cifCoord - ((scale)>>1);
299 else
300 result = cifCoord + ((scale-1)>>1);
301 result /= scale;
302 break;
303 }
304 }
305 else
306 result = cifCoord / scale;
307
308 return result;
309 }
310
311 /*
312 * ----------------------------------------------------------------------------
313 *
314 * cifIsBlank --
315 *
316 * Figures out whether a character qualifies as a blank in CIF.
317 * A blank is anything except a digit, an upper-case character,
318 * or the symbols "-", "(", "(", and ";".
319 *
320 * Results:
321 * Returns TRUE if ch is a CIF blank, FALSE otherwise.
322 *
323 * Side effects:
324 * None.
325 *
326 * ----------------------------------------------------------------------------
327 */
328
329 bool
cifIsBlank(ch)330 cifIsBlank(ch)
331 int ch;
332 {
333
334 if ( isdigit(ch) || isupper(ch)
335 || (ch == '-') || (ch == ';')
336 || (ch == '(') || (ch == ')')
337 || (ch == EOF))
338 {
339 return FALSE;
340 }
341 else return TRUE;
342 }
343
344 /*
345 * ----------------------------------------------------------------------------
346 *
347 * CIFSkipBlanks --
348 *
349 * This procedure skips over whitespace in the CIF file,
350 * keeping track of the line number and other information
351 * for error reporting.
352 *
353 * Results:
354 * None.
355 *
356 * Side effects:
357 * Advances through the CIF file.
358 *
359 * ----------------------------------------------------------------------------
360 */
361
362 void
CIFSkipBlanks()363 CIFSkipBlanks()
364 {
365
366 while (cifIsBlank(PEEK())) {
367 if (TAKE() == '\n')
368 {
369 cifLineNumber++;
370 }
371 }
372 }
373
374 /*
375 * ----------------------------------------------------------------------------
376 *
377 * CIFSkipSep --
378 *
379 * Skip over separators in the CIF file. Blanks and upper-case
380 * characters are separators.
381 *
382 * Results:
383 * None.
384 *
385 * Side effects:
386 * Advances through the CIF file.
387 *
388 * ----------------------------------------------------------------------------
389 */
390
391 void
CIFSkipSep()392 CIFSkipSep()
393 {
394 int ch;
395
396 for (ch = PEEK() ; isupper(ch) || cifIsBlank(ch) ; ch = PEEK()) {
397 if (TAKE() == '\n')
398 {
399 cifLineNumber++;
400 }
401 }
402 }
403
404 /*
405 * ----------------------------------------------------------------------------
406 *
407 * CIFSkipToSemi --
408 *
409 * This procedure is called after errors. It skips everything
410 * in the CIF file up to the next semi-colon.
411 *
412 * Results:
413 * None.
414 *
415 * Side effects:
416 * Advances through the CIF file.
417 *
418 * ----------------------------------------------------------------------------
419 */
420
421 void
CIFSkipToSemi()422 CIFSkipToSemi()
423 {
424 int ch;
425
426 for (ch = PEEK() ; ((ch != ';') && (ch != EOF)) ; ch = PEEK()) {
427 if (TAKE() == '\n')
428 {
429 cifLineNumber++;
430 }
431 }
432 }
433
434 /*
435 * ----------------------------------------------------------------------------
436 *
437 * CIFSkipSemi --
438 *
439 * Skips a semi-colon, including blanks around the semi-colon.
440 *
441 * Results:
442 * None.
443 *
444 * Side effects:
445 * Advances through the CIF file.
446 *
447 * ----------------------------------------------------------------------------
448 */
449
450 void
CIFSkipSemi()451 CIFSkipSemi()
452 {
453
454 CIFSkipBlanks();
455 if (PEEK() != ';') {
456 CIFReadError("`;\' expected.\n");
457 return;
458 }
459 TAKE();
460 CIFSkipBlanks();
461 }
462
463 /*
464 * ----------------------------------------------------------------------------
465 *
466 * CIFParseSInteger --
467 *
468 * This procedure parses a signed integer from the CIF file.
469 *
470 * Results:
471 * TRUE is returned if the parse completed without error,
472 * FALSE otherwise.
473 *
474 * Side effects:
475 * The integer pointed to by valuep is modified with the
476 * value of the signed integer.
477 *
478 * ----------------------------------------------------------------------------
479 */
480
481 bool
CIFParseSInteger(valuep)482 CIFParseSInteger(valuep)
483 int *valuep;
484 {
485 bool is_signed;
486 char buffer[ BUFSIZ ];
487 char *bufferp;
488
489 *valuep = 0;
490 CIFSkipSep();
491 if (PEEK() == '-')
492 {
493 TAKE();
494 is_signed = TRUE;
495 }
496 else is_signed = FALSE;
497 bufferp = &buffer[0];
498 while (isdigit(PEEK()))
499 *bufferp++ = TAKE();
500 if (bufferp == &buffer[0])
501 return FALSE;
502 *bufferp = '\0';
503 *valuep = atoi(&buffer[0]);
504 if (is_signed)
505 *valuep = -(*valuep);
506 return TRUE;
507 }
508
509 /*
510 * ----------------------------------------------------------------------------
511 *
512 * CIFParseInteger --
513 *
514 * Parses a positive integer from the CIF file.
515 *
516 * Results:
517 * TRUE is returned if the parse was completed successfully,
518 * FALSE otherwise.
519 *
520 * Side effects:
521 * The value pointed to by valuep is modified to hold the integer.
522 *
523 * ----------------------------------------------------------------------------
524 */
525
526 bool
CIFParseInteger(valuep)527 CIFParseInteger(valuep)
528 int *valuep;
529 {
530
531 if (!CIFParseSInteger(valuep))
532 return FALSE;
533 if (*valuep < 0)
534 CIFReadError("negative integer not permitted.\n");
535 return TRUE;
536 }
537
538 /*
539 * ----------------------------------------------------------------------------
540 *
541 * CIFParsePoint --
542 *
543 * Parse a point from a CIF file. A point is two integers
544 * separated by CIF separators.
545 * parameter "iscale" (internal scale factor) is usually 1, but
546 * can be 2 to deal with half-lambda entries in the CIF by
547 * returning double the result.
548 *
549 * Results:
550 * TRUE is returned if the point was parsed correctly, otherwise
551 * FALSE is returned.
552 *
553 * Side effects:
554 * The parameter pointp is filled in with the coordinates of
555 * the point.
556 *
557 * If the CIF scalefactors are such that the result would be a
558 * fractional value, the definition of the CIF scale is altered
559 * such that the result is integer, and all geometry read so far
560 * is altered to match. This does not immediately affect the geometry
561 * in the magic database; if that also appears to have fractional
562 * units, it will be discovered by CIFScaleCoord and corrected.
563 *
564 * ----------------------------------------------------------------------------
565 */
566
567 bool
CIFParsePoint(pointp,iscale)568 CIFParsePoint(pointp, iscale)
569 Point *pointp;
570 int iscale;
571 {
572 int rescale;
573
574 pointp->p_x = 0;
575 pointp->p_y = 0;
576 if (!CIFParseSInteger(&pointp->p_x))
577 return FALSE;
578 pointp->p_x *= (cifReadScale1 * iscale);
579 if (pointp->p_x % cifReadScale2 != 0)
580 {
581 rescale = cifReadScale2 / FindGCF(cifReadScale2, abs(pointp->p_x));
582 if ((cifReadScale1 * rescale) > CIFRescaleLimit)
583 {
584 CIFReadWarning("CIF units at maximum scale; value is rounded\n");
585 /* prepare for nearest-integer rounding */
586 if (pointp->p_x < 0)
587 pointp->p_x -= ((cifReadScale2 - 1) >> 1);
588 else
589 pointp->p_x += (cifReadScale2 >> 1);
590 }
591 else
592 {
593 cifReadScale1 *= rescale;
594 CIFInputRescale(rescale, 1);
595 pointp->p_x *= rescale;
596 }
597 }
598 pointp->p_x /= cifReadScale2;
599 if (!CIFParseSInteger(&pointp->p_y))
600 return FALSE;
601 pointp->p_y *= (cifReadScale1 * iscale);
602 if (pointp->p_y % cifReadScale2 != 0)
603 {
604 rescale = cifReadScale2 / FindGCF(cifReadScale2, abs(pointp->p_y));
605 if ((cifReadScale1 * rescale) > CIFRescaleLimit)
606 {
607 CIFReadWarning("CIF units at maximum scale; value is rounded\n");
608 /* prepare for nearest-integer rounding */
609 if (pointp->p_y < 0)
610 pointp->p_y -= ((cifReadScale2 - 1) >> 1);
611 else
612 pointp->p_y += (cifReadScale2 >> 1);
613 }
614 else
615 {
616 cifReadScale1 *= rescale;
617 CIFInputRescale(rescale, 1);
618 pointp->p_x *= rescale;
619 pointp->p_y *= rescale;
620 }
621 }
622 pointp->p_y /= cifReadScale2;
623 return TRUE;
624 }
625
626
627 /*
628 * ----------------------------------------------------------------------------
629 *
630 * CIFParsePath --
631 *
632 * This procedure parses a CIF path, which is sequence of
633 * one or more points.
634 *
635 * Results:
636 * TRUE is returned if the path was parsed successfully,
637 * FALSE otherwise.
638 *
639 * Side effects:
640 * Modifies the parameter pathheadpp to point to the path
641 * that is constructed.
642 *
643 * Corrections:
644 * CIF coordinates are multiplied by 2 to cover the case where
645 * the path centerline lies on the half lambda grid but the line
646 * itself is on-grid. This can't be done for polygons, so a
647 * parameter "iscale" (internal scale) is added, and set to 1 for
648 * polygons, 2 for wires when calling CIFParsePath().
649 *
650 * ----------------------------------------------------------------------------
651 */
652
653 bool
CIFParsePath(pathheadpp,iscale)654 CIFParsePath(pathheadpp, iscale)
655 CIFPath **pathheadpp;
656 int iscale;
657 {
658 CIFPath *pathtailp, *newpathp;
659 bool nonManhattan = FALSE; /* diagnostic only */
660 CIFPath path;
661 int savescale;
662
663 *pathheadpp = NULL;
664 pathtailp = NULL;
665 path.cifp_next = NULL;
666 while (TRUE)
667 {
668 CIFSkipSep();
669 if (PEEK() == ';')
670 break;
671
672 savescale = cifReadScale1;
673 if (!CIFParsePoint(&path.cifp_point, iscale))
674 {
675 CIFFreePath(*pathheadpp);
676 return FALSE;
677 }
678 if (savescale != cifReadScale1)
679 {
680 CIFPath *phead = *pathheadpp;
681 int newscale = cifReadScale1 / savescale;
682 while (phead != NULL)
683 {
684 phead->cifp_x *= newscale;
685 phead->cifp_y *= newscale;
686 phead = phead->cifp_next;
687 }
688 }
689 newpathp = (CIFPath *) mallocMagic((unsigned) (sizeof (CIFPath)));
690 *newpathp = path;
691 if (*pathheadpp)
692 {
693 /*
694 * Check that this segment is Manhattan. If not, remember the
695 * fact and later introduce extra stair-steps to make the path
696 * Manhattan. We don't do the stair-step introduction here for
697 * two reasons: first, the same code is also used by the Calma
698 * module, and second, it is important to know which side of
699 * the polygon is the outside when generating the stair steps.
700 */
701 if (pathtailp->cifp_x != newpathp->cifp_x
702 && pathtailp->cifp_y != (newpathp->cifp_y))
703 {
704 nonManhattan = TRUE;
705 }
706 pathtailp->cifp_next = newpathp;
707 }
708 else *pathheadpp = newpathp;
709 pathtailp = newpathp;
710 }
711 return (*pathheadpp != NULL);
712 }
713
714 /*
715 * ----------------------------------------------------------------------------
716 *
717 * test_insideness --
718 *
719 * Determine if a point is inside a rectangle defined by the
720 * first three points in the given CIF path.
721 *
722 * Results:
723 * TRUE if point is inside, FALSE if outside or on the border
724 *
725 * Side effects:
726 * None.
727 * ----------------------------------------------------------------------------
728 */
729
730 bool
test_insideness(start,tpoint)731 test_insideness(start, tpoint)
732 CIFPath *start;
733 Point *tpoint;
734 {
735 Rect tmprect, irect;
736
737 tmprect.r_xbot = start->cifp_x;
738 tmprect.r_ybot = start->cifp_y;
739 tmprect.r_xtop = start->cifp_next->cifp_next->cifp_x;
740 tmprect.r_ytop = start->cifp_next->cifp_next->cifp_y;
741
742 GeoCanonicalRect(&tmprect, &irect);
743
744 return ((tpoint->p_x > irect.r_xbot)
745 && (tpoint->p_x < irect.r_xtop)
746 && (tpoint->p_y > irect.r_ybot)
747 && (tpoint->p_y < irect.r_ytop)) ? TRUE : FALSE;
748 }
749
750 /*
751 * ----------------------------------------------------------------------------
752 *
753 * seg_intersect --
754 *
755 * Determine if two line segments intersect or touch
756 * Expects first line to be manhattan.
757 *
758 * Results:
759 * returns TRUE if segments intersect, FALSE otherwise
760 *
761 * Side effects:
762 * value of respt contains point to which segment will be
763 * truncated.
764 *
765 * ----------------------------------------------------------------------------
766 */
767
768 bool
seg_intersect(tstart,bf,bs,respt)769 seg_intersect(tstart, bf, bs, respt)
770 CIFPath *tstart;
771 Point *bf, *bs;
772 Point *respt;
773 {
774 int afx = tstart->cifp_x;
775 int afy = tstart->cifp_y;
776 int asx = tstart->cifp_next->cifp_x;
777 int asy = tstart->cifp_next->cifp_y;
778 int adx, ady;
779
780 if (afx == asx) /* "a" is a vertical line */
781 {
782 adx = afx + ((tstart->cifp_next->cifp_next->cifp_x > afx) ? 1 : -1);
783
784 /* Ignore if b does not cross the x boundary of ad */
785 if ((bf->p_x > adx && bs->p_x > adx) ||
786 (bf->p_x < adx && bs->p_x < adx))
787 return FALSE;
788
789 if (bs->p_x == bf->p_x) /* nonintersecting vertical lines */
790 return FALSE;
791
792 respt->p_x = afx;
793 respt->p_y = bf->p_y + (int)
794 (((dlong)(bs->p_y - bf->p_y) * (dlong)(afx - bf->p_x)) /
795 (dlong)(bs->p_x - bf->p_x));
796 if (((respt->p_y > afy) && (respt->p_y < asy)) ||
797 ((respt->p_y < afy) && (respt->p_y > asy)))
798 return TRUE;
799 }
800 else /* (afy == asy), "a" is a horizontal line */
801 {
802 ady = afy + ((tstart->cifp_next->cifp_next->cifp_y > afy) ? 1 : -1);
803
804 /* Ignore if b does not cross the y boundary of ad */
805 if ((bf->p_y > ady && bs->p_y > ady) ||
806 (bf->p_y < ady && bs->p_y < ady))
807 return FALSE;
808
809 if (bs->p_y == bf->p_y) /* nonintersecting horizontal lines */
810 return FALSE;
811
812 respt->p_y = afy;
813 respt->p_x = bf->p_x + (int)
814 (((dlong)(bs->p_x - bf->p_x) * (dlong)(afy - bf->p_y)) /
815 (dlong)(bs->p_y - bf->p_y));
816 if (((respt->p_x > afx) && (respt->p_x < asx)) ||
817 ((respt->p_x < afx) && (respt->p_x > asx)))
818 return TRUE;
819 }
820 return FALSE;
821 }
822
823 /*
824 * ----------------------------------------------------------------------------
825 *
826 * path_intersect --
827 *
828 * Determine if a path intersects the given line segment.
829 * A path sharing a portion of the segment is not an intersection.
830 *
831 * ----------------------------------------------------------------------------
832 */
833
834 bool
path_intersect(pathHead,start,respt)835 path_intersect(pathHead, start, respt)
836 CIFPath *pathHead, *start;
837 Point *respt;
838 {
839 CIFPath *path, *segcrossed, *new;
840 Point tmppt;
841 bool does_cross = FALSE, diagonal = FALSE;
842 int tdist, newdist;
843
844 tdist = newdist = INFINITY;
845 for (path = pathHead; path->cifp_next; path = path->cifp_next)
846 {
847 /* don't compare with self */
848 if (path == start || path == start->cifp_next) continue;
849
850 /* Does the path intersect the first line of the */
851 /* right triangle, continuing in the direction of */
852 /* the last point on the triangle? */
853
854 if (seg_intersect(start, &path->cifp_point,
855 &path->cifp_next->cifp_point, &tmppt))
856 {
857 newdist = (start->cifp_x - tmppt.p_x) + (start->cifp_y - tmppt.p_y);
858 diagonal = TRUE;
859 }
860
861 /* Is the point inside the triangle, and the path is Manhattan? */
862 /* (Note that *both* tests can be true, in which case the one */
863 /* with the smaller absolute distance takes precedence.) */
864
865 if (test_insideness(start, &path->cifp_point)) {
866 int tmpdist = abs(newdist); /* save this value */
867 if (path->cifp_x == path->cifp_next->cifp_x ||
868 path->cifp_y == path->cifp_next->cifp_y)
869 {
870 if (start->cifp_x == start->cifp_next->cifp_x)
871 {
872 newdist = path->cifp_y - start->cifp_y;
873 if (abs(newdist) < tmpdist)
874 {
875 tmppt.p_x = start->cifp_x;
876 tmppt.p_y = path->cifp_y;
877 diagonal = FALSE;
878 }
879 }
880 else
881 {
882 newdist = path->cifp_x - start->cifp_x;
883 if (abs(newdist) < tmpdist)
884 {
885 tmppt.p_y = start->cifp_y;
886 tmppt.p_x = path->cifp_x;
887 diagonal = FALSE;
888 }
889 }
890 }
891 else if (diagonal == FALSE)
892 continue;
893 }
894 else if (diagonal == FALSE)
895 continue;
896
897 newdist = abs(newdist);
898 if ((!does_cross) || (newdist < tdist))
899 {
900 does_cross = TRUE;
901 respt->p_x = tmppt.p_x;
902 respt->p_y = tmppt.p_y;
903 tdist = newdist;
904 segcrossed = (diagonal) ? path : NULL;
905 }
906 }
907
908 /* If we're limited by another side of the polygon, then we're */
909 /* guaranteed that we'll have to add another point there. By */
910 /* doing it here, we avoid problems due to roundoff errors. */
911
912 if (does_cross && segcrossed)
913 {
914 new = (CIFPath *) mallocMagic((unsigned) (sizeof (CIFPath)));
915 new->cifp_next = segcrossed->cifp_next;
916 segcrossed->cifp_next = new;
917 new->cifp_x = respt->p_x;
918 new->cifp_y = respt->p_y;
919 }
920 return does_cross;
921 }
922
923 /*
924 * ----------------------------------------------------------------------------
925 *
926 * is_clockwise --
927 *
928 * Determine if a path is clockwise or counterclockwise.
929 *
930 * Results:
931 * TRUE if the path is clockwise, FALSE otherwise.
932 *
933 * Side effects:
934 * None.
935 *
936 * ----------------------------------------------------------------------------
937 */
938
939 bool
is_clockwise(pathHead)940 is_clockwise(pathHead)
941 CIFPath *pathHead;
942 {
943 CIFPath *path, *midx = NULL, *last;
944 Point *p1, *p2, *p3;
945 dlong sdir;
946 int minx = INFINITY;
947
948 /* Find out if this is a clockwise or counterclockwise path by */
949 /* finding the (a) leftmost point and assuming the polygon to fill */
950 /* is to the right. */
951
952 for (path = pathHead; path->cifp_next; path = path->cifp_next)
953 {
954 if (path->cifp_next->cifp_x < minx)
955 {
956 minx = path->cifp_next->cifp_x;
957 midx = path->cifp_next;
958 last = path;
959 }
960 }
961
962 if (!midx) return TRUE; /* one-point polygon? */
963
964 /* Rare case of colinear points (implies degenerate polygon) requires */
965 /* moving along pointlist until points are not colinear and repeating */
966 /* the search for the minimum. */
967
968 if (last->cifp_x == midx->cifp_x)
969 {
970 for (path = pathHead; path && path->cifp_x == minx;
971 path = path->cifp_next);
972 if (!path) return TRUE; /* completely degenerate; direc. irrelevant */
973 minx = INFINITY;
974 for (; path->cifp_next; path = path->cifp_next)
975 {
976 if (path->cifp_next->cifp_x < minx)
977 {
978 minx = path->cifp_next->cifp_x;
979 midx = path->cifp_next;
980 last = path;
981 }
982 }
983 }
984
985 if (!(midx->cifp_next)) midx = pathHead;
986
987 /* p2 is the (a) leftmost point; p1 and p3 are the points before */
988 /* and after in the CIF path, respectively. */
989
990 p1 = &(last->cifp_point);
991 p2 = &(midx->cifp_point);
992 p3 = &(midx->cifp_next->cifp_point);
993
994 /* Find which side p3 falls on relative to the line p1-p2. This */
995 /* determines whether the path is clockwise or counterclockwise. */
996 /* Use type dlong to avoid integer overflow. */
997
998 sdir = ((dlong)(p2->p_x - p1->p_x) * (dlong)(p3->p_y - p1->p_y) -
999 (dlong)(p2->p_y - p1->p_y) * (dlong)(p3->p_x - p1->p_x));
1000
1001 return (sdir < 0) ? TRUE : FALSE;
1002 }
1003
1004 /*
1005 * ----------------------------------------------------------------------------
1006 *
1007 * CIFMakeManhattanPath --
1008 *
1009 * Convert a non-Manhattan path into a Manhattan one by
1010 * breaking out triangles and leaving all Manhattan edges.
1011 * Additional points are added which reroute the CIF path
1012 * around the triangle. In the simplest case, each non-Manhattan
1013 * edge becomes a split tile bounding the edge endpoints.
1014 * However, if that split tile would extend beyond the boundary
1015 * of the CIF path, the edge is subdivided into as many
1016 * triangles as are necessary to complete the path while remaining
1017 * within the polygon boundary. Unfortunately, for non-45-degree
1018 * edges, the edge subdivision might not fall on an integer lambda
1019 * value, so the resulting edge could be off by as much as 1/2
1020 * lambda. In this case, flag a warning.
1021 *
1022 * Results:
1023 * None.
1024 *
1025 * Side effects:
1026 * May insert additional points in the path.
1027 * May alter the intended geometry of a non-manhattan edge by as
1028 * much as 1/2 lambda.
1029 *
1030 * ----------------------------------------------------------------------------
1031 */
1032
1033 void
CIFMakeManhattanPath(pathHead,plane,resultTbl,ui)1034 CIFMakeManhattanPath(pathHead, plane, resultTbl, ui)
1035 CIFPath *pathHead;
1036 Plane *plane;
1037 PaintResultType *resultTbl;
1038 PaintUndoInfo *ui;
1039 {
1040 CIFPath *new, *new2, *next, *path;
1041 int xinit, xdiff, xincr, xlast, x;
1042 int yinit, ydiff, yincr, ylast, y;
1043
1044 bool clockwise;
1045 CIFPath *first, *last;
1046 Rect tt, tr;
1047 TileType type;
1048
1049 clockwise = is_clockwise(pathHead);
1050
1051 for (path = pathHead; path->cifp_next; path = path->cifp_next)
1052 {
1053 Point clipbase;
1054 int edir;
1055 next = path->cifp_next;
1056
1057 /* No work if this segment is Manhattan */
1058 if (path->cifp_x == next->cifp_x || path->cifp_y == next->cifp_y)
1059 continue;
1060
1061 /* Otherwise, break out the triangle, then adjust as necessary */
1062
1063 new = (CIFPath *) mallocMagic((unsigned) (sizeof (CIFPath)));
1064 path->cifp_next = new;
1065 new->cifp_next = next;
1066
1067 /* Generate split tiles as necessary to reach next->cifp_y */
1068
1069 if (clockwise)
1070 {
1071 first = next;
1072 last = path;
1073 }
1074 else
1075 {
1076 first = path;
1077 last = next;
1078 }
1079 edir = CIFEdgeDirection(first, last);
1080 if (edir == CIF_DIAG_DL || edir == CIF_DIAG_UR)
1081 {
1082 new->cifp_x = first->cifp_x;
1083 new->cifp_y = last->cifp_y;
1084 }
1085 else /* edir == CIF_DIAG_DR || edir == CIF_DIAG_UL */
1086 {
1087 new->cifp_x = last->cifp_x;
1088 new->cifp_y = first->cifp_y;
1089 }
1090
1091 /* Check if the segment from first to base intersects */
1092 /* the polygon edge */
1093
1094 if (path_intersect(pathHead, path, &clipbase))
1095 {
1096 new->cifp_x = clipbase.p_x;
1097 new->cifp_y = clipbase.p_y;
1098
1099 new2 = (CIFPath *) mallocMagic((unsigned) (sizeof (CIFPath)));
1100 new->cifp_next = new2;
1101 new2->cifp_next = next;
1102
1103 /* Use double long for the multiplication and */
1104 /* division, or else integer overflow can occur. */
1105
1106 if (path->cifp_x == new->cifp_x) /* vertical line */
1107 {
1108 new2->cifp_y = new->cifp_y;
1109 new2->cifp_x = path->cifp_x + (int)
1110 ((dlong)(new2->cifp_y - path->cifp_y)
1111 * (dlong)(next->cifp_x - path->cifp_x)
1112 / (dlong)(next->cifp_y - path->cifp_y));
1113 }
1114 else
1115 {
1116 new2->cifp_x = new->cifp_x;
1117 new2->cifp_y = path->cifp_y + (int)
1118 ((dlong)(new2->cifp_x - path->cifp_x)
1119 * (dlong)(next->cifp_y - path->cifp_y)
1120 / (dlong)(next->cifp_x - path->cifp_x));
1121 }
1122 }
1123
1124 /* Break out the diagonal tile from the polygon and paint it. */
1125
1126 type = (edir == CIF_DIAG_UR || edir == CIF_DIAG_UL) ? 0 : TT_SIDE;
1127 type |= (edir == CIF_DIAG_UR || edir == CIF_DIAG_DL) ? 0 : TT_DIRECTION;
1128 type |= TT_DIAGONAL;
1129
1130 tt.r_ll = path->cifp_point;
1131 tt.r_ur = path->cifp_next->cifp_next->cifp_point;
1132 GeoCanonicalRect(&tt, &tr);
1133
1134 // TxPrintf("CIF read: Triangle %s %c at (%d, %d) plane %x\n",
1135 // (type & TT_SIDE) ? "right" : "left", (type & TT_DIRECTION)
1136 // ? '\\' : '/', tt.r_xbot, tt.r_ybot, plane);
1137
1138 /* Final check---ensure that rectangle is not degenerate */
1139
1140 if (plane && (tr.r_xtop - tr.r_xbot > 0) && (tr.r_ytop - tr.r_ybot > 0))
1141 DBNMPaintPlane(plane, type, &tr, resultTbl, ui);
1142 }
1143 }
1144
1145
1146 /*
1147 * ----------------------------------------------------------------------------
1148 *
1149 * CIFEdgeDirection --
1150 *
1151 * This procedure assigns a direction to the given edge.
1152 *
1153 * Results:
1154 * CIF_ZERO if the two points are the same
1155 * CIF_LEFT if the edge goes left
1156 * CIF_UP if the edge goes up
1157 * CIF_RIGHT if the edge goes right
1158 * CIF_DOWN if the edge goes down
1159 * CIF_DIAG if the edge is non-manhattan
1160 *
1161 * Side effects:
1162 * None.
1163 *
1164 * ----------------------------------------------------------------------------
1165 */
1166
1167 int
CIFEdgeDirection(first,last)1168 CIFEdgeDirection(first, last)
1169 CIFPath *first, *last; /* Edge to be categorized. */
1170 {
1171
1172 if (first->cifp_x < last->cifp_x)
1173 {
1174 if (first->cifp_y < last->cifp_y)
1175 return CIF_DIAG_UR;
1176 if (first->cifp_y > last->cifp_y)
1177 return CIF_DIAG_DR;
1178 return CIF_RIGHT;
1179 }
1180 if (first->cifp_x > last->cifp_x)
1181 {
1182 if (first->cifp_y < last->cifp_y)
1183 return CIF_DIAG_UL;
1184 if (first->cifp_y > last->cifp_y)
1185 return CIF_DIAG_DL;
1186 return CIF_LEFT;
1187 }
1188 if (first->cifp_y < last->cifp_y)
1189 return CIF_UP;
1190 if (first->cifp_y > last->cifp_y)
1191 return CIF_DOWN;
1192 return CIF_ZERO;
1193 }
1194
1195 /*
1196 * ----------------------------------------------------------------------------
1197 *
1198 * CIFCleanPath --
1199 *
1200 * Removes a edge in a path if it has zero length (repeated points).
1201 * Combines two consecutive edges if their direction is the same,
1202 * and their direction is manhattan.
1203 * CIFCleanPath assumes that the path is closed, and will eliminate
1204 * the last edge if its direction is the same as the first.
1205 *
1206 * Results:
1207 * None.
1208 *
1209 * Side effects:
1210 * May delete points in the path.
1211 *
1212 * ----------------------------------------------------------------------------
1213 */
1214
1215 void
CIFCleanPath(pathHead)1216 CIFCleanPath(pathHead)
1217 CIFPath *pathHead;
1218 {
1219 CIFPath *next, *path, *prev, *last;
1220 int dir1, dir2;
1221
1222 if (!pathHead) return;
1223 prev = pathHead;
1224 path = prev->cifp_next;
1225 if (!path) return;
1226 while((dir1 = CIFEdgeDirection(prev, path)) == CIF_ZERO)
1227 {
1228 /* This is a repeated point. */
1229 next = path->cifp_next;
1230 prev->cifp_next = next;
1231 freeMagic((char *) path);
1232 path = next;
1233 if (!path) return;
1234 }
1235
1236 while (next = path->cifp_next)
1237 {
1238 if ((dir2 = CIFEdgeDirection(path, next)) == CIF_ZERO)
1239 {
1240 /* This is a repeated point. */
1241 path->cifp_next = next->cifp_next;
1242 freeMagic((char *) next);
1243 continue;
1244 }
1245
1246 /* Skip any non-manhattan (diagonal) edges. */
1247 if (dir2 >= CIF_DIAG)
1248 goto path_inc;
1249
1250 if (dir1 == dir2)
1251 {
1252 /* The middle point must go. */
1253 prev->cifp_next = next;
1254 freeMagic((char *) path);
1255 path = next;
1256 dir1 = CIFEdgeDirection(prev, path);
1257 continue;
1258 }
1259 path_inc:
1260 dir1 = dir2;
1261 prev = path;
1262 path = next;
1263 }
1264
1265 /* Ensure that the path has more than one point. */
1266 if (!pathHead->cifp_next)
1267 {
1268 /* Ensure that the resulting path is closed. */
1269 if ((pathHead->cifp_x != path->cifp_x) ||
1270 (pathHead->cifp_y != path->cifp_y))
1271 {
1272 next = (CIFPath *) mallocMagic((unsigned) (sizeof (CIFPath)));
1273 next->cifp_x = pathHead->cifp_x;
1274 next->cifp_y = pathHead->cifp_y;
1275 next->cifp_next = (CIFPath *) 0;
1276 path->cifp_next = next;
1277 prev = path;
1278 path = next;
1279 dir1 = CIFEdgeDirection(prev, path);
1280 }
1281 if ((dir2 = CIFEdgeDirection(pathHead, pathHead->cifp_next)) <
1282 CIF_DIAG)
1283 {
1284 /* We have at least two edges in the path. We have to */
1285 /* fix the first edge and eliminate the last edge if */
1286 /* the first and last edge have the same direction. */
1287 if (dir1 == dir2)
1288 {
1289 pathHead->cifp_x = prev->cifp_x;
1290 pathHead->cifp_y = prev->cifp_y;
1291 prev->cifp_next = (CIFPath *) 0;
1292 freeMagic((char *) path);
1293 }
1294 }
1295 }
1296 }
1297
1298 /*
1299 * ----------------------------------------------------------------------------
1300 *
1301 * CIFFreePath --
1302 *
1303 * This procedure frees up a path once it has been used.
1304 *
1305 * Results:
1306 * None.
1307 *
1308 * Side effects:
1309 * All the elements of path are returned to the storage allocator.
1310 *
1311 * ----------------------------------------------------------------------------
1312 */
1313
1314 void
CIFFreePath(path)1315 CIFFreePath(path)
1316 CIFPath *path; /* Path to be freed. */
1317 {
1318 while (path != NULL)
1319 {
1320 freeMagic((char *) path);
1321 path = path->cifp_next;
1322 }
1323 }
1324
1325 /*
1326 * ----------------------------------------------------------------------------
1327 *
1328 * cifCommandError --
1329 *
1330 * This procedure is called when unknown CIF commands are found
1331 * in CIF files. It skips the command and advances to the next
1332 * command.
1333 *
1334 * Results:
1335 * None.
1336 *
1337 * Side effects:
1338 * None.
1339 *
1340 * ----------------------------------------------------------------------------
1341 */
1342
1343 void
cifCommandError()1344 cifCommandError()
1345 {
1346 CIFReadError("unknown command `%c'; ignored.\n" , PEEK());
1347 CIFSkipToSemi();
1348 }
1349
1350
1351 /*
1352 * ----------------------------------------------------------------------------
1353 *
1354 * cifParseEnd --
1355 *
1356 * This procedure processes the "end" statement in a CIF file
1357 * (it ignores it).
1358 *
1359 * Results:
1360 * Always returns TRUE.
1361 *
1362 * Side effects:
1363 * None.
1364 *
1365 * ----------------------------------------------------------------------------
1366 */
1367
1368 bool
cifParseEnd()1369 cifParseEnd()
1370 {
1371 TAKE();
1372 CIFSkipBlanks();
1373 if (PEEK() != EOF)
1374 {
1375 CIFReadError("End command isn't at end of file.\n");
1376 return FALSE;
1377 }
1378 return TRUE;
1379 }
1380
1381 /*
1382 * ----------------------------------------------------------------------------
1383 *
1384 * cifParseComment --
1385 *
1386 * This command skips over user comments in CIF files.
1387 *
1388 * Results:
1389 * None.
1390 *
1391 * Side effects:
1392 * None.
1393 *
1394 * ----------------------------------------------------------------------------
1395 */
1396
1397 bool
cifParseComment()1398 cifParseComment()
1399 {
1400 int opens;
1401 int ch;
1402
1403 /*
1404 * take the '('
1405 */
1406 TAKE();
1407 opens = 1;
1408 do
1409 {
1410 ch = TAKE();
1411 if (ch == '(')
1412 opens++;
1413 else if (ch == ')')
1414 opens--;
1415 else if (ch == '\n')
1416 {
1417 cifLineNumber++;
1418 }
1419 else if (ch == EOF)
1420 {
1421 CIFReadError("(comment) extends to end of file.\n");
1422 return FALSE;
1423 }
1424 } while (opens > 0);
1425 return TRUE;
1426 }
1427
1428 /*
1429 * ----------------------------------------------------------------------------
1430 *
1431 * CIFDirectionToTrans --
1432 *
1433 * This procedure is used to convert from a direction vector
1434 * to a Magic transformation. The direction vector is a point
1435 * giving a direction from the origin. It better be along
1436 * one of the axes.
1437 *
1438 * Results:
1439 * The return value is the transformation corresponding to
1440 * the direction, or the identity transform if the direction
1441 * isn't along one of the axes.
1442 *
1443 * Side effects:
1444 * None.
1445 *
1446 * ----------------------------------------------------------------------------
1447 */
1448
1449 Transform *
CIFDirectionToTrans(point)1450 CIFDirectionToTrans(point)
1451 Point *point; /* Direction vector from origin. */
1452 {
1453 if ((point->p_x != 0) && (point->p_y == 0))
1454 {
1455 if (point->p_x > 0)
1456 return &GeoIdentityTransform;
1457 else return &Geo180Transform;
1458 }
1459 else if ((point->p_y != 0) && (point->p_x == 0))
1460 {
1461 if (point->p_y > 0)
1462 return &Geo270Transform;
1463 else return &Geo90Transform;
1464 }
1465 CIFReadError("non-manhattan direction vector (%d, %d); ignored.\n",
1466 point->p_x, point->p_y);
1467 return &GeoIdentityTransform;
1468 }
1469
1470 /*
1471 * ----------------------------------------------------------------------------
1472 *
1473 * CIFParseTransform --
1474 *
1475 * This procedure is called to read in a transform from a
1476 * CIF file.
1477 *
1478 * Results:
1479 * TRUE is returned if the parse completed successfully, and
1480 * FALSE is returned otherwise.
1481 *
1482 * Side effects:
1483 * The parameter pointed to by transformp is modified to
1484 * contain the transform indicated by the CIF file.
1485 *
1486 * ----------------------------------------------------------------------------
1487 */
1488
1489 bool
CIFParseTransform(transformp)1490 CIFParseTransform(transformp)
1491 Transform *transformp;
1492 {
1493 char ch;
1494 Point point;
1495 Transform tmp;
1496 int savescale;
1497
1498 *transformp = GeoIdentityTransform;
1499 CIFSkipBlanks();
1500 for (ch = PEEK() ; ch != ';' ; ch = PEEK())
1501 {
1502 switch (ch)
1503 {
1504 case 'T':
1505 TAKE();
1506 if (!CIFParsePoint(&point, 1))
1507 {
1508 CIFReadError("translation, but no point.\n");
1509 CIFSkipToSemi();
1510 return FALSE;
1511 }
1512 GeoTranslateTrans(transformp, point.p_x, point.p_y, &tmp);
1513 *transformp = tmp;
1514 break;
1515 case 'M':
1516 TAKE();
1517 CIFSkipBlanks();
1518 ch = PEEK();
1519 if (ch == 'X')
1520 GeoTransTrans(transformp, &GeoSidewaysTransform, &tmp);
1521 else if (ch == 'Y')
1522 GeoTransTrans(transformp, &GeoUpsideDownTransform,
1523 &tmp);
1524 else
1525 {
1526 CIFReadError("mirror, but not in X or Y.\n");
1527 CIFSkipToSemi();
1528 return FALSE;
1529 }
1530 TAKE();
1531 *transformp = tmp;
1532 break;
1533 case 'R':
1534 TAKE();
1535 if (!CIFParseSInteger(&point.p_x) ||
1536 !CIFParseSInteger(&point.p_y))
1537 {
1538 CIFReadError("rotation, but no direction.\n");
1539 CIFSkipToSemi();
1540 return FALSE;
1541 }
1542 GeoTransTrans(transformp, CIFDirectionToTrans(&point),
1543 &tmp);
1544 *transformp = tmp;
1545 break;
1546 default:
1547 CIFReadError("transformation expected.\n");
1548 CIFSkipToSemi();
1549 return FALSE;
1550 }
1551 CIFSkipBlanks();
1552 }
1553
1554 /* Before returning, we must scale the transform into Magic units. */
1555
1556 transformp->t_c = CIFScaleCoord(transformp->t_c, COORD_EXACT);
1557 savescale = cifCurReadStyle->crs_scaleFactor;
1558 transformp->t_f = CIFScaleCoord(transformp->t_f, COORD_EXACT);
1559 if (savescale != cifCurReadStyle->crs_scaleFactor)
1560 transformp->t_c *= (savescale / cifCurReadStyle->crs_scaleFactor);
1561
1562 return TRUE;
1563 }
1564
1565 /*
1566 * ----------------------------------------------------------------------------
1567 *
1568 * CIFParseCommand --
1569 *
1570 * Parse one CIF command and farm it out to a routine to handle
1571 * that command.
1572 *
1573 * Results:
1574 * None.
1575 *
1576 * Side effects:
1577 * May modify the contents of cifReadCellDef by painting or adding
1578 * new uses or labels. May also create new CellDefs.
1579 *
1580 * ----------------------------------------------------------------------------
1581 */
1582
1583 void
CIFReadFile(file)1584 CIFReadFile(file)
1585 FILE *file; /* File from which to read CIF. */
1586 {
1587 /* We will use 1-word CIF numbers as keys in this hash table */
1588 CIFReadCellInit(1);
1589
1590 if (cifCurReadStyle == NULL)
1591 {
1592 TxError("Don't know how to read CIF: nothing in tech file.\n");
1593 return;
1594 }
1595 TxPrintf("Warning: CIF reading is not undoable! I hope that's OK.\n");
1596 UndoDisable();
1597
1598 cifTotalWarnings = 0;
1599 cifTotalErrors = 0;
1600 CifPolygonCount = 0;
1601 cifSeenSnapWarning = FALSE;
1602
1603 cifInputFile = file;
1604 cifReadScale1 = 1;
1605 cifReadScale2 = 1;
1606 cifParseLaAvail = FALSE;
1607 cifLineNumber = 1;
1608 cifReadPlane = (Plane *) NULL;
1609 cifCurLabelType = TT_SPACE;
1610 while (PEEK() != EOF)
1611 {
1612 if (SigInterruptPending) goto done;
1613 CIFSkipBlanks();
1614 switch (PEEK())
1615 {
1616 case EOF:
1617 break;
1618 case ';':
1619 break;
1620 case 'B':
1621 (void) CIFParseBox();
1622 break;
1623 case 'C':
1624 (void) CIFParseCall();
1625 break;
1626 case 'D':
1627 TAKE();
1628 CIFSkipBlanks();
1629 switch (PEEK())
1630 {
1631 case 'D':
1632 (void) CIFParseDelete();
1633 break;
1634 case 'F':
1635 (void) CIFParseFinish();
1636 break;
1637 case 'S':
1638 (void) CIFParseStart();
1639 break;
1640 default:
1641 cifCommandError();
1642 break;
1643 }
1644 break;
1645 case 'E':
1646 (void) cifParseEnd();
1647 goto done;
1648 case 'L':
1649 (void) CIFParseLayer();
1650 break;
1651 case 'P':
1652 (void) CIFParsePoly();
1653 break;
1654 case 'R':
1655 (void) CIFParseFlash();
1656 break;
1657 case 'W':
1658 (void) CIFParseWire();
1659 break;
1660 case '(':
1661 (void) cifParseComment();
1662 break;
1663 case '0': case '1': case '2': case '3': case '4':
1664 case '5': case '6': case '7': case '8': case '9':
1665 (void) CIFParseUser();
1666 break;
1667 default:
1668 cifCommandError();
1669 break;
1670 }
1671 CIFSkipSemi();
1672 }
1673
1674 CIFReadError("no \"End\" statement.\n");
1675
1676 done:
1677 CIFReadCellCleanup(FILE_CIF);
1678 UndoEnable();
1679 }
1680