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