2017-04-25 14:41:48 +02:00
|
|
|
/* CIFreadutils.c -
|
|
|
|
|
*
|
|
|
|
|
* This file contains routines that parse a file in CIF
|
|
|
|
|
* format. This file contains the top-level routine for
|
|
|
|
|
* reading CIF files, plus a bunch of utility routines
|
|
|
|
|
* for skipping white space, parsing numbers and points, etc.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
|
|
|
|
* * Permission to use, copy, modify, and distribute this *
|
|
|
|
|
* * software and its documentation for any purpose and without *
|
|
|
|
|
* * fee is hereby granted, provided that the above copyright *
|
|
|
|
|
* * notice appear in all copies. The University of California *
|
|
|
|
|
* * makes no representations about the suitability of this *
|
|
|
|
|
* * software for any purpose. It is provided "as is" without *
|
|
|
|
|
* * express or implied warranty. Export of this software outside *
|
|
|
|
|
* * of the United States of America may require an export license. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
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 $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/*
|
|
|
|
|
* C99 compat
|
|
|
|
|
* Mind: tcltk/tclmagic.h must be included prior to all the other headers
|
|
|
|
|
*/
|
|
|
|
|
#include "tcltk/tclmagic.h"
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "tiles/tile.h"
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
#include "database/database.h"
|
|
|
|
|
#include "cif/CIFint.h"
|
|
|
|
|
#include "cif/CIFread.h"
|
|
|
|
|
#include "cif/cif.h"
|
|
|
|
|
#include "textio/textio.h"
|
|
|
|
|
#include "utils/signals.h"
|
|
|
|
|
#include "utils/undo.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/* C99 compat */
|
|
|
|
|
#include "lef/lef.h"
|
|
|
|
|
#include "drc/drc.h"
|
|
|
|
|
#include "extract/extract.h"
|
|
|
|
|
#include "wiring/wiring.h"
|
|
|
|
|
#include "router/router.h"
|
|
|
|
|
#include "mzrouter/mzrouter.h"
|
|
|
|
|
#include "irouter/irouter.h"
|
|
|
|
|
#include "plow/plow.h"
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* The following variables are used to provide one character of
|
|
|
|
|
* lookahead. cifParseLaAvail is TRUE if cifParseLaChar contains
|
|
|
|
|
* a valid character, FALSE otherwise. The PEEK and TAKE macros
|
|
|
|
|
* are used to manipulate this stuff.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool cifParseLaAvail = FALSE;
|
|
|
|
|
int cifParseLaChar = EOF;
|
|
|
|
|
|
|
|
|
|
/* Below is a variable pointing to the CIF input file. It's used
|
|
|
|
|
* by the PEEK and TAKE macros. The other stuff is used to keep
|
|
|
|
|
* track of our location in the CIF file for error reporting
|
|
|
|
|
* purposes.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
FILE *cifInputFile;
|
|
|
|
|
FILE *cifErrorFile;
|
|
|
|
|
int cifLineNumber; /* Number of current line. */
|
|
|
|
|
int cifTotalWarnings; /* Number of warnings detected */
|
|
|
|
|
int cifTotalErrors; /* Number of errors detected */
|
2020-10-14 23:20:45 +02:00
|
|
|
bool cifSeenSnapWarning; /* Track this to prevent excessive messaging */
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* The variables used below hold general information about what
|
|
|
|
|
* we're currently working on.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int cifReadScale1; /* Scale factor: multiply by Scale1 */
|
|
|
|
|
int cifReadScale2; /* then divide by Scale2. */
|
|
|
|
|
int CIFRescaleLimit = CIFMAXRESCALE; /* Don't increase cifReadScale1 by more
|
|
|
|
|
* than this amount; internal units
|
|
|
|
|
* finer than this will be rounded.
|
|
|
|
|
*/
|
|
|
|
|
bool CIFRescaleAllow = TRUE; /* Don't subdivide the magic internal
|
|
|
|
|
* grid if this is FALSE.
|
|
|
|
|
*/
|
|
|
|
|
bool CIFNoDRCCheck = FALSE; /* If TRUE, then cell is marked DRC clean
|
|
|
|
|
* and not DRC checked.
|
|
|
|
|
*/
|
|
|
|
|
char *CIFErrorFilename; /* Name of file for error redirection */
|
|
|
|
|
|
|
|
|
|
int CifPolygonCount; /* Count of generated subcells
|
|
|
|
|
* containing polygons. This number
|
|
|
|
|
* is used to create a unique cell name.
|
|
|
|
|
*/
|
|
|
|
|
bool CIFSubcellPolygons = FALSE; /* If TRUE, each non-Manhattan polygon
|
|
|
|
|
* will be put in a separate subcell
|
|
|
|
|
* to avoid too much tile splitting
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Plane *cifReadPlane; /* Plane into which to paint material
|
|
|
|
|
* NULL means no layer command has
|
|
|
|
|
* been seen for the current cell.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFReadError --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is called to print out error messages during
|
|
|
|
|
* CIF file reading.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* An error message is printed.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* VARARGS1 */
|
|
|
|
|
void
|
2024-10-03 23:47:50 +02:00
|
|
|
CIFReadError(const char *format, ...)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
cifTotalErrors++;
|
|
|
|
|
if (CIFWarningLevel == CIF_WARN_NONE) return;
|
|
|
|
|
if ((cifTotalErrors < 100) || (CIFWarningLevel != CIF_WARN_LIMIT))
|
|
|
|
|
{
|
2019-11-19 17:39:59 +01:00
|
|
|
if (cifLineNumber > 0)
|
|
|
|
|
TxError("Error at line %d of CIF file: ", cifLineNumber);
|
|
|
|
|
else
|
|
|
|
|
TxError("CIF file read error: ", cifLineNumber);
|
2017-04-25 14:41:48 +02:00
|
|
|
va_start(args, format);
|
|
|
|
|
Vfprintf(stderr, format, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
}
|
|
|
|
|
else if ((cifTotalErrors == 100) && (CIFWarningLevel == CIF_WARN_LIMIT))
|
|
|
|
|
{
|
|
|
|
|
TxError("Error limit set: Remaining errors will not be reported.\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
void
|
2024-10-03 23:47:50 +02:00
|
|
|
CIFReadWarning(const char *format, ...)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
cifTotalWarnings++;
|
|
|
|
|
if (CIFWarningLevel == CIF_WARN_NONE) return;
|
|
|
|
|
if ((cifTotalWarnings < 100) || (CIFWarningLevel != CIF_WARN_LIMIT))
|
|
|
|
|
{
|
2019-11-19 17:39:59 +01:00
|
|
|
if (cifLineNumber > 0)
|
|
|
|
|
TxError("Warning at line %d of CIF file: ", cifLineNumber);
|
|
|
|
|
else
|
|
|
|
|
TxError("CIF file read warning: ");
|
2017-04-25 14:41:48 +02:00
|
|
|
va_start(args, format);
|
|
|
|
|
Vfprintf(stderr, format, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
}
|
|
|
|
|
else if ((cifTotalWarnings == 100) && (CIFWarningLevel == CIF_WARN_LIMIT))
|
|
|
|
|
{
|
|
|
|
|
TxError("Warning limit set: Remaining warnings will not be reported.\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFScaleCoord
|
|
|
|
|
*
|
|
|
|
|
* This procedure does rounding and division to convert from
|
|
|
|
|
* CIF units back into Magic units.
|
|
|
|
|
*
|
|
|
|
|
* "snap_type" may be one of:
|
|
|
|
|
* COORD_EXACT: result must be an exact integer. If not, the
|
|
|
|
|
* magic grid spacing is changed such that the result will
|
|
|
|
|
* be an integer.
|
|
|
|
|
* COORD_HALF_U: twice the result must be an exact integer. If
|
|
|
|
|
* not, the magic grid spacing is changed as above. If the
|
|
|
|
|
* result is 1/2, it is rounded up to the nearest integer.
|
|
|
|
|
* COORD_HALF_L: same as above, but result is rounded down.
|
|
|
|
|
* COORD_ANY: result may be fractional, and will be snapped to
|
|
|
|
|
* the nearest magic grid. Generally, this is used for
|
|
|
|
|
* labels whose position need not be exact.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The result is the Magic unit equivalent to cifCoord.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFScaleCoord(
|
|
|
|
|
int cifCoord, /* A coordinate in CIF units. */
|
|
|
|
|
int snap_type) /* How to deal with fractional results */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
int result, scale, remain, denom;
|
|
|
|
|
int mult, mfactor;
|
|
|
|
|
|
|
|
|
|
/* If internal grid subdivision is disallowed, always round to the */
|
|
|
|
|
/* nearest grid unit. */
|
|
|
|
|
|
|
|
|
|
if (!CIFRescaleAllow)
|
|
|
|
|
snap_type = COORD_ANY;
|
|
|
|
|
|
|
|
|
|
scale = cifCurReadStyle->crs_scaleFactor;
|
|
|
|
|
mult = cifCurReadStyle->crs_multiplier;
|
|
|
|
|
|
|
|
|
|
/* Check for non-integer result and warn of fractional-lambda violation */
|
|
|
|
|
|
|
|
|
|
if ((remain = (cifCoord % scale)) != 0)
|
|
|
|
|
{
|
|
|
|
|
int lgcf = FindGCF(abs(cifCoord), scale);
|
|
|
|
|
|
|
|
|
|
remain = abs(remain) / lgcf;
|
|
|
|
|
denom = scale / lgcf;
|
|
|
|
|
|
|
|
|
|
if (CIFReadTechLimitScale(1, denom)) snap_type = COORD_ANY;
|
|
|
|
|
|
|
|
|
|
switch (snap_type)
|
|
|
|
|
{
|
|
|
|
|
case COORD_EXACT:
|
2020-10-14 23:20:45 +02:00
|
|
|
if (!cifSeenSnapWarning)
|
|
|
|
|
CIFReadWarning("Input off lambda grid by %d/%d; grid redefined.\n",
|
2017-04-25 14:41:48 +02:00
|
|
|
remain, denom);
|
2020-10-14 23:20:45 +02:00
|
|
|
cifSeenSnapWarning = TRUE;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
CIFTechInputScale(1, denom, FALSE);
|
|
|
|
|
CIFTechOutputScale(1, denom);
|
|
|
|
|
DRCTechScale(1, denom);
|
|
|
|
|
ExtTechScale(1, denom);
|
|
|
|
|
WireTechScale(1, denom);
|
|
|
|
|
#ifdef LEF_MODULE
|
|
|
|
|
LefTechScale(1, denom);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef ROUTE_MODULE
|
|
|
|
|
RtrTechScale(1, denom);
|
|
|
|
|
MZAfterTech();
|
|
|
|
|
IRAfterTech();
|
|
|
|
|
#endif
|
|
|
|
|
DBScaleEverything(denom, 1);
|
|
|
|
|
DBLambda[1] *= denom;
|
|
|
|
|
ReduceFraction(&DBLambda[0], &DBLambda[1]);
|
|
|
|
|
scale = cifCurReadStyle->crs_scaleFactor;
|
|
|
|
|
result = cifCoord / scale;
|
|
|
|
|
break;
|
|
|
|
|
case COORD_HALF_U: case COORD_HALF_L:
|
|
|
|
|
if (denom > 2)
|
|
|
|
|
{
|
2020-10-14 23:20:45 +02:00
|
|
|
if (!cifSeenSnapWarning)
|
|
|
|
|
CIFReadWarning("Input off lambda grid by %d/%d; "
|
|
|
|
|
"grid redefined.\n", remain, denom);
|
|
|
|
|
cifSeenSnapWarning = TRUE;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* scale to nearest half-lambda */
|
|
|
|
|
if (!(denom & 0x1)) denom >>= 1;
|
|
|
|
|
|
|
|
|
|
CIFTechInputScale(1, denom, FALSE);
|
|
|
|
|
CIFTechOutputScale(1, denom);
|
|
|
|
|
DRCTechScale(1, denom);
|
|
|
|
|
PlowAfterTech();
|
|
|
|
|
ExtTechScale(1, denom);
|
|
|
|
|
WireTechScale(1, denom);
|
|
|
|
|
MZAfterTech();
|
|
|
|
|
IRAfterTech();
|
|
|
|
|
#ifdef LEF_MODULE
|
|
|
|
|
LefTechScale(1, denom);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef ROUTE_MODULE
|
|
|
|
|
RtrTechScale(1, denom);
|
|
|
|
|
#endif
|
|
|
|
|
DBScaleEverything(denom, 1);
|
|
|
|
|
DBLambda[1] *= denom;
|
|
|
|
|
ReduceFraction(&DBLambda[0], &DBLambda[1]);
|
|
|
|
|
scale = cifCurReadStyle->crs_scaleFactor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (snap_type == COORD_HALF_U)
|
|
|
|
|
result = cifCoord + (scale >> 1);
|
|
|
|
|
else
|
|
|
|
|
result = cifCoord - (scale >> 1);
|
|
|
|
|
result /= scale;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case COORD_ANY:
|
2020-10-14 23:20:45 +02:00
|
|
|
if (!cifSeenSnapWarning)
|
|
|
|
|
CIFReadWarning("Input off lambda grid by %d/%d; snapped to grid.\n",
|
|
|
|
|
abs(remain), abs(denom));
|
|
|
|
|
cifSeenSnapWarning = TRUE;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* Careful: must round down a bit more for negative numbers, in
|
|
|
|
|
* order to ensure that a point exactly halfway between Magic units
|
|
|
|
|
* always gets rounded down, rather than towards zero (this would
|
|
|
|
|
* result in different treatment of the same paint, depending on
|
|
|
|
|
* where it is in the coordinate system.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (cifCoord < 0)
|
|
|
|
|
result = cifCoord - ((scale)>>1);
|
|
|
|
|
else
|
|
|
|
|
result = cifCoord + ((scale-1)>>1);
|
|
|
|
|
result /= scale;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
result = cifCoord / scale;
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifIsBlank --
|
|
|
|
|
*
|
|
|
|
|
* Figures out whether a character qualifies as a blank in CIF.
|
|
|
|
|
* A blank is anything except a digit, an upper-case character,
|
|
|
|
|
* or the symbols "-", "(", "(", and ";".
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns TRUE if ch is a CIF blank, FALSE otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifIsBlank(
|
|
|
|
|
int ch)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if ( isdigit(ch) || isupper(ch)
|
|
|
|
|
|| (ch == '-') || (ch == ';')
|
|
|
|
|
|| (ch == '(') || (ch == ')')
|
|
|
|
|
|| (ch == EOF))
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
else return TRUE;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFSkipBlanks --
|
|
|
|
|
*
|
|
|
|
|
* This procedure skips over whitespace in the CIF file,
|
|
|
|
|
* keeping track of the line number and other information
|
|
|
|
|
* for error reporting.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Advances through the CIF file.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFSkipBlanks(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
while (cifIsBlank(PEEK())) {
|
|
|
|
|
if (TAKE() == '\n')
|
|
|
|
|
{
|
|
|
|
|
cifLineNumber++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFSkipSep --
|
|
|
|
|
*
|
|
|
|
|
* Skip over separators in the CIF file. Blanks and upper-case
|
|
|
|
|
* characters are separators.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Advances through the CIF file.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFSkipSep(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
int ch;
|
|
|
|
|
|
|
|
|
|
for (ch = PEEK() ; isupper(ch) || cifIsBlank(ch) ; ch = PEEK()) {
|
|
|
|
|
if (TAKE() == '\n')
|
|
|
|
|
{
|
|
|
|
|
cifLineNumber++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFSkipToSemi --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is called after errors. It skips everything
|
|
|
|
|
* in the CIF file up to the next semi-colon.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Advances through the CIF file.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFSkipToSemi(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
int ch;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
for (ch = PEEK() ; ((ch != ';') && (ch != EOF)) ; ch = PEEK()) {
|
|
|
|
|
if (TAKE() == '\n')
|
|
|
|
|
{
|
|
|
|
|
cifLineNumber++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFSkipSemi --
|
|
|
|
|
*
|
|
|
|
|
* Skips a semi-colon, including blanks around the semi-colon.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Advances through the CIF file.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFSkipSemi(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
CIFSkipBlanks();
|
|
|
|
|
if (PEEK() != ';') {
|
|
|
|
|
CIFReadError("`;\' expected.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
TAKE();
|
|
|
|
|
CIFSkipBlanks();
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFParseSInteger --
|
|
|
|
|
*
|
|
|
|
|
* This procedure parses a signed integer from the CIF file.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE is returned if the parse completed without error,
|
|
|
|
|
* FALSE otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The integer pointed to by valuep is modified with the
|
|
|
|
|
* value of the signed integer.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFParseSInteger(
|
|
|
|
|
int *valuep)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
bool is_signed;
|
|
|
|
|
char buffer[ BUFSIZ ];
|
|
|
|
|
char *bufferp;
|
|
|
|
|
|
|
|
|
|
*valuep = 0;
|
|
|
|
|
CIFSkipSep();
|
|
|
|
|
if (PEEK() == '-')
|
|
|
|
|
{
|
|
|
|
|
TAKE();
|
|
|
|
|
is_signed = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else is_signed = FALSE;
|
|
|
|
|
bufferp = &buffer[0];
|
|
|
|
|
while (isdigit(PEEK()))
|
|
|
|
|
*bufferp++ = TAKE();
|
|
|
|
|
if (bufferp == &buffer[0])
|
|
|
|
|
return FALSE;
|
|
|
|
|
*bufferp = '\0';
|
|
|
|
|
*valuep = atoi(&buffer[0]);
|
|
|
|
|
if (is_signed)
|
|
|
|
|
*valuep = -(*valuep);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFParseInteger --
|
|
|
|
|
*
|
|
|
|
|
* Parses a positive integer from the CIF file.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE is returned if the parse was completed successfully,
|
|
|
|
|
* FALSE otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The value pointed to by valuep is modified to hold the integer.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFParseInteger(
|
|
|
|
|
int *valuep)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (!CIFParseSInteger(valuep))
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (*valuep < 0)
|
|
|
|
|
CIFReadError("negative integer not permitted.\n");
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFParsePoint --
|
|
|
|
|
*
|
|
|
|
|
* Parse a point from a CIF file. A point is two integers
|
|
|
|
|
* separated by CIF separators.
|
|
|
|
|
* parameter "iscale" (internal scale factor) is usually 1, but
|
|
|
|
|
* can be 2 to deal with half-lambda entries in the CIF by
|
|
|
|
|
* returning double the result.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE is returned if the point was parsed correctly, otherwise
|
|
|
|
|
* FALSE is returned.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The parameter pointp is filled in with the coordinates of
|
|
|
|
|
* the point.
|
|
|
|
|
*
|
|
|
|
|
* If the CIF scalefactors are such that the result would be a
|
|
|
|
|
* fractional value, the definition of the CIF scale is altered
|
|
|
|
|
* such that the result is integer, and all geometry read so far
|
|
|
|
|
* is altered to match. This does not immediately affect the geometry
|
|
|
|
|
* in the magic database; if that also appears to have fractional
|
|
|
|
|
* units, it will be discovered by CIFScaleCoord and corrected.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFParsePoint(
|
|
|
|
|
Point *pointp,
|
|
|
|
|
int iscale)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
int rescale;
|
|
|
|
|
|
|
|
|
|
pointp->p_x = 0;
|
|
|
|
|
pointp->p_y = 0;
|
|
|
|
|
if (!CIFParseSInteger(&pointp->p_x))
|
|
|
|
|
return FALSE;
|
|
|
|
|
pointp->p_x *= (cifReadScale1 * iscale);
|
|
|
|
|
if (pointp->p_x % cifReadScale2 != 0)
|
|
|
|
|
{
|
|
|
|
|
rescale = cifReadScale2 / FindGCF(cifReadScale2, abs(pointp->p_x));
|
|
|
|
|
if ((cifReadScale1 * rescale) > CIFRescaleLimit)
|
|
|
|
|
{
|
|
|
|
|
CIFReadWarning("CIF units at maximum scale; value is rounded\n");
|
|
|
|
|
/* prepare for nearest-integer rounding */
|
|
|
|
|
if (pointp->p_x < 0)
|
|
|
|
|
pointp->p_x -= ((cifReadScale2 - 1) >> 1);
|
|
|
|
|
else
|
|
|
|
|
pointp->p_x += (cifReadScale2 >> 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cifReadScale1 *= rescale;
|
|
|
|
|
CIFInputRescale(rescale, 1);
|
|
|
|
|
pointp->p_x *= rescale;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pointp->p_x /= cifReadScale2;
|
|
|
|
|
if (!CIFParseSInteger(&pointp->p_y))
|
|
|
|
|
return FALSE;
|
|
|
|
|
pointp->p_y *= (cifReadScale1 * iscale);
|
|
|
|
|
if (pointp->p_y % cifReadScale2 != 0)
|
|
|
|
|
{
|
|
|
|
|
rescale = cifReadScale2 / FindGCF(cifReadScale2, abs(pointp->p_y));
|
|
|
|
|
if ((cifReadScale1 * rescale) > CIFRescaleLimit)
|
|
|
|
|
{
|
|
|
|
|
CIFReadWarning("CIF units at maximum scale; value is rounded\n");
|
|
|
|
|
/* prepare for nearest-integer rounding */
|
|
|
|
|
if (pointp->p_y < 0)
|
|
|
|
|
pointp->p_y -= ((cifReadScale2 - 1) >> 1);
|
|
|
|
|
else
|
|
|
|
|
pointp->p_y += (cifReadScale2 >> 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cifReadScale1 *= rescale;
|
|
|
|
|
CIFInputRescale(rescale, 1);
|
|
|
|
|
pointp->p_x *= rescale;
|
|
|
|
|
pointp->p_y *= rescale;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pointp->p_y /= cifReadScale2;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFParsePath --
|
|
|
|
|
*
|
|
|
|
|
* This procedure parses a CIF path, which is sequence of
|
|
|
|
|
* one or more points.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE is returned if the path was parsed successfully,
|
|
|
|
|
* FALSE otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Modifies the parameter pathheadpp to point to the path
|
|
|
|
|
* that is constructed.
|
|
|
|
|
*
|
|
|
|
|
* Corrections:
|
|
|
|
|
* CIF coordinates are multiplied by 2 to cover the case where
|
|
|
|
|
* the path centerline lies on the half lambda grid but the line
|
|
|
|
|
* itself is on-grid. This can't be done for polygons, so a
|
|
|
|
|
* parameter "iscale" (internal scale) is added, and set to 1 for
|
|
|
|
|
* polygons, 2 for wires when calling CIFParsePath().
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFParsePath(
|
|
|
|
|
CIFPath **pathheadpp,
|
|
|
|
|
int iscale)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
CIFPath *pathtailp, *newpathp;
|
|
|
|
|
bool nonManhattan = FALSE; /* diagnostic only */
|
|
|
|
|
CIFPath path;
|
|
|
|
|
int savescale;
|
|
|
|
|
|
|
|
|
|
*pathheadpp = NULL;
|
|
|
|
|
pathtailp = NULL;
|
|
|
|
|
path.cifp_next = NULL;
|
|
|
|
|
while (TRUE)
|
|
|
|
|
{
|
|
|
|
|
CIFSkipSep();
|
|
|
|
|
if (PEEK() == ';')
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
savescale = cifReadScale1;
|
|
|
|
|
if (!CIFParsePoint(&path.cifp_point, iscale))
|
|
|
|
|
{
|
|
|
|
|
CIFFreePath(*pathheadpp);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (savescale != cifReadScale1)
|
|
|
|
|
{
|
|
|
|
|
CIFPath *phead = *pathheadpp;
|
|
|
|
|
int newscale = cifReadScale1 / savescale;
|
|
|
|
|
while (phead != NULL)
|
|
|
|
|
{
|
|
|
|
|
phead->cifp_x *= newscale;
|
|
|
|
|
phead->cifp_y *= newscale;
|
|
|
|
|
phead = phead->cifp_next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
newpathp = (CIFPath *) mallocMagic((unsigned) (sizeof (CIFPath)));
|
|
|
|
|
*newpathp = path;
|
|
|
|
|
if (*pathheadpp)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Check that this segment is Manhattan. If not, remember the
|
|
|
|
|
* fact and later introduce extra stair-steps to make the path
|
|
|
|
|
* Manhattan. We don't do the stair-step introduction here for
|
|
|
|
|
* two reasons: first, the same code is also used by the Calma
|
|
|
|
|
* module, and second, it is important to know which side of
|
|
|
|
|
* the polygon is the outside when generating the stair steps.
|
|
|
|
|
*/
|
|
|
|
|
if (pathtailp->cifp_x != newpathp->cifp_x
|
|
|
|
|
&& pathtailp->cifp_y != (newpathp->cifp_y))
|
|
|
|
|
{
|
|
|
|
|
nonManhattan = TRUE;
|
|
|
|
|
}
|
|
|
|
|
pathtailp->cifp_next = newpathp;
|
|
|
|
|
}
|
|
|
|
|
else *pathheadpp = newpathp;
|
|
|
|
|
pathtailp = newpathp;
|
|
|
|
|
}
|
|
|
|
|
return (*pathheadpp != NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* test_insideness --
|
|
|
|
|
*
|
|
|
|
|
* Determine if a point is inside a rectangle defined by the
|
|
|
|
|
* first three points in the given CIF path.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
2020-05-23 23:13:14 +02:00
|
|
|
* TRUE if point is inside, FALSE if outside or on the border
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
test_insideness(
|
|
|
|
|
CIFPath *start,
|
|
|
|
|
Point *tpoint)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
Rect tmprect, irect;
|
|
|
|
|
|
|
|
|
|
tmprect.r_xbot = start->cifp_x;
|
|
|
|
|
tmprect.r_ybot = start->cifp_y;
|
|
|
|
|
tmprect.r_xtop = start->cifp_next->cifp_next->cifp_x;
|
|
|
|
|
tmprect.r_ytop = start->cifp_next->cifp_next->cifp_y;
|
|
|
|
|
|
|
|
|
|
GeoCanonicalRect(&tmprect, &irect);
|
|
|
|
|
|
|
|
|
|
return ((tpoint->p_x > irect.r_xbot)
|
|
|
|
|
&& (tpoint->p_x < irect.r_xtop)
|
|
|
|
|
&& (tpoint->p_y > irect.r_ybot)
|
|
|
|
|
&& (tpoint->p_y < irect.r_ytop)) ? TRUE : FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* seg_intersect --
|
|
|
|
|
*
|
|
|
|
|
* Determine if two line segments intersect or touch
|
|
|
|
|
* Expects first line to be manhattan.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* returns TRUE if segments intersect, FALSE otherwise
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* value of respt contains point to which segment will be
|
|
|
|
|
* truncated.
|
2020-05-23 23:13:14 +02:00
|
|
|
*
|
2017-04-25 14:41:48 +02:00
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
seg_intersect(
|
|
|
|
|
CIFPath *tstart,
|
|
|
|
|
Point *bf,
|
|
|
|
|
Point *bs,
|
|
|
|
|
Point *respt)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
int afx = tstart->cifp_x;
|
|
|
|
|
int afy = tstart->cifp_y;
|
|
|
|
|
int asx = tstart->cifp_next->cifp_x;
|
|
|
|
|
int asy = tstart->cifp_next->cifp_y;
|
|
|
|
|
int adx, ady;
|
|
|
|
|
|
|
|
|
|
if (afx == asx) /* "a" is a vertical line */
|
|
|
|
|
{
|
|
|
|
|
adx = afx + ((tstart->cifp_next->cifp_next->cifp_x > afx) ? 1 : -1);
|
|
|
|
|
|
|
|
|
|
/* Ignore if b does not cross the x boundary of ad */
|
|
|
|
|
if ((bf->p_x > adx && bs->p_x > adx) ||
|
|
|
|
|
(bf->p_x < adx && bs->p_x < adx))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (bs->p_x == bf->p_x) /* nonintersecting vertical lines */
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
respt->p_x = afx;
|
|
|
|
|
respt->p_y = bf->p_y + (int)
|
|
|
|
|
(((dlong)(bs->p_y - bf->p_y) * (dlong)(afx - bf->p_x)) /
|
|
|
|
|
(dlong)(bs->p_x - bf->p_x));
|
|
|
|
|
if (((respt->p_y > afy) && (respt->p_y < asy)) ||
|
|
|
|
|
((respt->p_y < afy) && (respt->p_y > asy)))
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
else /* (afy == asy), "a" is a horizontal line */
|
|
|
|
|
{
|
|
|
|
|
ady = afy + ((tstart->cifp_next->cifp_next->cifp_y > afy) ? 1 : -1);
|
|
|
|
|
|
|
|
|
|
/* Ignore if b does not cross the y boundary of ad */
|
|
|
|
|
if ((bf->p_y > ady && bs->p_y > ady) ||
|
|
|
|
|
(bf->p_y < ady && bs->p_y < ady))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (bs->p_y == bf->p_y) /* nonintersecting horizontal lines */
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
respt->p_y = afy;
|
|
|
|
|
respt->p_x = bf->p_x + (int)
|
|
|
|
|
(((dlong)(bs->p_x - bf->p_x) * (dlong)(afy - bf->p_y)) /
|
|
|
|
|
(dlong)(bs->p_y - bf->p_y));
|
|
|
|
|
if (((respt->p_x > afx) && (respt->p_x < asx)) ||
|
|
|
|
|
((respt->p_x < afx) && (respt->p_x > asx)))
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* path_intersect --
|
|
|
|
|
*
|
|
|
|
|
* Determine if a path intersects the given line segment.
|
|
|
|
|
* A path sharing a portion of the segment is not an intersection.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
path_intersect(
|
|
|
|
|
CIFPath *pathHead,
|
|
|
|
|
CIFPath *start,
|
|
|
|
|
Point *respt)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
CIFPath *path, *segcrossed, *new;
|
|
|
|
|
Point tmppt;
|
|
|
|
|
bool does_cross = FALSE, diagonal = FALSE;
|
|
|
|
|
int tdist, newdist;
|
|
|
|
|
|
|
|
|
|
tdist = newdist = INFINITY;
|
|
|
|
|
for (path = pathHead; path->cifp_next; path = path->cifp_next)
|
|
|
|
|
{
|
|
|
|
|
/* don't compare with self */
|
|
|
|
|
if (path == start || path == start->cifp_next) continue;
|
|
|
|
|
|
|
|
|
|
/* Does the path intersect the first line of the */
|
|
|
|
|
/* right triangle, continuing in the direction of */
|
|
|
|
|
/* the last point on the triangle? */
|
|
|
|
|
|
|
|
|
|
if (seg_intersect(start, &path->cifp_point,
|
|
|
|
|
&path->cifp_next->cifp_point, &tmppt))
|
|
|
|
|
{
|
|
|
|
|
newdist = (start->cifp_x - tmppt.p_x) + (start->cifp_y - tmppt.p_y);
|
|
|
|
|
diagonal = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Is the point inside the triangle, and the path is Manhattan? */
|
|
|
|
|
/* (Note that *both* tests can be true, in which case the one */
|
|
|
|
|
/* with the smaller absolute distance takes precedence.) */
|
|
|
|
|
|
|
|
|
|
if (test_insideness(start, &path->cifp_point)) {
|
2020-05-23 23:13:14 +02:00
|
|
|
int tmpdist = abs(newdist); /* save this value */
|
2017-04-25 14:41:48 +02:00
|
|
|
if (path->cifp_x == path->cifp_next->cifp_x ||
|
|
|
|
|
path->cifp_y == path->cifp_next->cifp_y)
|
|
|
|
|
{
|
|
|
|
|
if (start->cifp_x == start->cifp_next->cifp_x)
|
|
|
|
|
{
|
|
|
|
|
newdist = path->cifp_y - start->cifp_y;
|
|
|
|
|
if (abs(newdist) < tmpdist)
|
|
|
|
|
{
|
|
|
|
|
tmppt.p_x = start->cifp_x;
|
|
|
|
|
tmppt.p_y = path->cifp_y;
|
|
|
|
|
diagonal = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
newdist = path->cifp_x - start->cifp_x;
|
|
|
|
|
if (abs(newdist) < tmpdist)
|
|
|
|
|
{
|
|
|
|
|
tmppt.p_y = start->cifp_y;
|
|
|
|
|
tmppt.p_x = path->cifp_x;
|
|
|
|
|
diagonal = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-11-25 22:09:16 +01:00
|
|
|
else if (diagonal == FALSE)
|
|
|
|
|
continue;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
else if (diagonal == FALSE)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
newdist = abs(newdist);
|
|
|
|
|
if ((!does_cross) || (newdist < tdist))
|
|
|
|
|
{
|
|
|
|
|
does_cross = TRUE;
|
|
|
|
|
respt->p_x = tmppt.p_x;
|
|
|
|
|
respt->p_y = tmppt.p_y;
|
|
|
|
|
tdist = newdist;
|
|
|
|
|
segcrossed = (diagonal) ? path : NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we're limited by another side of the polygon, then we're */
|
|
|
|
|
/* guaranteed that we'll have to add another point there. By */
|
|
|
|
|
/* doing it here, we avoid problems due to roundoff errors. */
|
|
|
|
|
|
|
|
|
|
if (does_cross && segcrossed)
|
|
|
|
|
{
|
|
|
|
|
new = (CIFPath *) mallocMagic((unsigned) (sizeof (CIFPath)));
|
|
|
|
|
new->cifp_next = segcrossed->cifp_next;
|
|
|
|
|
segcrossed->cifp_next = new;
|
|
|
|
|
new->cifp_x = respt->p_x;
|
|
|
|
|
new->cifp_y = respt->p_y;
|
|
|
|
|
}
|
|
|
|
|
return does_cross;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* is_clockwise --
|
|
|
|
|
*
|
|
|
|
|
* Determine if a path is clockwise or counterclockwise.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE if the path is clockwise, FALSE otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
is_clockwise(
|
|
|
|
|
CIFPath *pathHead)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
CIFPath *path, *midx = NULL, *last;
|
|
|
|
|
Point *p1, *p2, *p3;
|
|
|
|
|
dlong sdir;
|
|
|
|
|
int minx = INFINITY;
|
|
|
|
|
|
|
|
|
|
/* Find out if this is a clockwise or counterclockwise path by */
|
|
|
|
|
/* finding the (a) leftmost point and assuming the polygon to fill */
|
|
|
|
|
/* is to the right. */
|
|
|
|
|
|
|
|
|
|
for (path = pathHead; path->cifp_next; path = path->cifp_next)
|
|
|
|
|
{
|
|
|
|
|
if (path->cifp_next->cifp_x < minx)
|
|
|
|
|
{
|
|
|
|
|
minx = path->cifp_next->cifp_x;
|
|
|
|
|
midx = path->cifp_next;
|
|
|
|
|
last = path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!midx) return TRUE; /* one-point polygon? */
|
|
|
|
|
|
|
|
|
|
/* Rare case of colinear points (implies degenerate polygon) requires */
|
|
|
|
|
/* moving along pointlist until points are not colinear and repeating */
|
|
|
|
|
/* the search for the minimum. */
|
|
|
|
|
|
|
|
|
|
if (last->cifp_x == midx->cifp_x)
|
|
|
|
|
{
|
|
|
|
|
for (path = pathHead; path && path->cifp_x == minx;
|
|
|
|
|
path = path->cifp_next);
|
|
|
|
|
if (!path) return TRUE; /* completely degenerate; direc. irrelevant */
|
|
|
|
|
minx = INFINITY;
|
|
|
|
|
for (; path->cifp_next; path = path->cifp_next)
|
|
|
|
|
{
|
|
|
|
|
if (path->cifp_next->cifp_x < minx)
|
|
|
|
|
{
|
|
|
|
|
minx = path->cifp_next->cifp_x;
|
|
|
|
|
midx = path->cifp_next;
|
|
|
|
|
last = path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(midx->cifp_next)) midx = pathHead;
|
|
|
|
|
|
|
|
|
|
/* p2 is the (a) leftmost point; p1 and p3 are the points before */
|
|
|
|
|
/* and after in the CIF path, respectively. */
|
|
|
|
|
|
|
|
|
|
p1 = &(last->cifp_point);
|
|
|
|
|
p2 = &(midx->cifp_point);
|
|
|
|
|
p3 = &(midx->cifp_next->cifp_point);
|
|
|
|
|
|
|
|
|
|
/* Find which side p3 falls on relative to the line p1-p2. This */
|
|
|
|
|
/* determines whether the path is clockwise or counterclockwise. */
|
|
|
|
|
/* Use type dlong to avoid integer overflow. */
|
|
|
|
|
|
|
|
|
|
sdir = ((dlong)(p2->p_x - p1->p_x) * (dlong)(p3->p_y - p1->p_y) -
|
|
|
|
|
(dlong)(p2->p_y - p1->p_y) * (dlong)(p3->p_x - p1->p_x));
|
|
|
|
|
|
|
|
|
|
return (sdir < 0) ? TRUE : FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFMakeManhattanPath --
|
|
|
|
|
*
|
|
|
|
|
* Convert a non-Manhattan path into a Manhattan one by
|
|
|
|
|
* breaking out triangles and leaving all Manhattan edges.
|
|
|
|
|
* Additional points are added which reroute the CIF path
|
|
|
|
|
* around the triangle. In the simplest case, each non-Manhattan
|
|
|
|
|
* edge becomes a split tile bounding the edge endpoints.
|
|
|
|
|
* However, if that split tile would extend beyond the boundary
|
|
|
|
|
* of the CIF path, the edge is subdivided into as many
|
|
|
|
|
* triangles as are necessary to complete the path while remaining
|
|
|
|
|
* within the polygon boundary. Unfortunately, for non-45-degree
|
|
|
|
|
* edges, the edge subdivision might not fall on an integer lambda
|
|
|
|
|
* value, so the resulting edge could be off by as much as 1/2
|
|
|
|
|
* lambda. In this case, flag a warning.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* May insert additional points in the path.
|
|
|
|
|
* May alter the intended geometry of a non-manhattan edge by as
|
|
|
|
|
* much as 1/2 lambda.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFMakeManhattanPath(
|
|
|
|
|
CIFPath *pathHead,
|
|
|
|
|
Plane *plane,
|
|
|
|
|
PaintResultType *resultTbl,
|
|
|
|
|
PaintUndoInfo *ui)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
CIFPath *new, *new2, *next, *path;
|
|
|
|
|
int xinit, xdiff, xincr, xlast, x;
|
|
|
|
|
int yinit, ydiff, yincr, ylast, y;
|
|
|
|
|
|
|
|
|
|
bool clockwise;
|
|
|
|
|
CIFPath *first, *last;
|
|
|
|
|
Rect tt, tr;
|
|
|
|
|
TileType type;
|
|
|
|
|
|
|
|
|
|
clockwise = is_clockwise(pathHead);
|
|
|
|
|
|
|
|
|
|
for (path = pathHead; path->cifp_next; path = path->cifp_next)
|
|
|
|
|
{
|
|
|
|
|
Point clipbase;
|
|
|
|
|
int edir;
|
|
|
|
|
next = path->cifp_next;
|
|
|
|
|
|
|
|
|
|
/* No work if this segment is Manhattan */
|
|
|
|
|
if (path->cifp_x == next->cifp_x || path->cifp_y == next->cifp_y)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Otherwise, break out the triangle, then adjust as necessary */
|
|
|
|
|
|
|
|
|
|
new = (CIFPath *) mallocMagic((unsigned) (sizeof (CIFPath)));
|
|
|
|
|
path->cifp_next = new;
|
|
|
|
|
new->cifp_next = next;
|
|
|
|
|
|
|
|
|
|
/* Generate split tiles as necessary to reach next->cifp_y */
|
|
|
|
|
|
|
|
|
|
if (clockwise)
|
|
|
|
|
{
|
|
|
|
|
first = next;
|
|
|
|
|
last = path;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
first = path;
|
|
|
|
|
last = next;
|
|
|
|
|
}
|
|
|
|
|
edir = CIFEdgeDirection(first, last);
|
|
|
|
|
if (edir == CIF_DIAG_DL || edir == CIF_DIAG_UR)
|
|
|
|
|
{
|
2020-05-23 23:13:14 +02:00
|
|
|
new->cifp_x = first->cifp_x;
|
2017-04-25 14:41:48 +02:00
|
|
|
new->cifp_y = last->cifp_y;
|
|
|
|
|
}
|
|
|
|
|
else /* edir == CIF_DIAG_DR || edir == CIF_DIAG_UL */
|
|
|
|
|
{
|
|
|
|
|
new->cifp_x = last->cifp_x;
|
|
|
|
|
new->cifp_y = first->cifp_y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check if the segment from first to base intersects */
|
|
|
|
|
/* the polygon edge */
|
|
|
|
|
|
|
|
|
|
if (path_intersect(pathHead, path, &clipbase))
|
|
|
|
|
{
|
|
|
|
|
new->cifp_x = clipbase.p_x;
|
|
|
|
|
new->cifp_y = clipbase.p_y;
|
|
|
|
|
|
|
|
|
|
new2 = (CIFPath *) mallocMagic((unsigned) (sizeof (CIFPath)));
|
|
|
|
|
new->cifp_next = new2;
|
|
|
|
|
new2->cifp_next = next;
|
|
|
|
|
|
|
|
|
|
/* Use double long for the multiplication and */
|
|
|
|
|
/* division, or else integer overflow can occur. */
|
|
|
|
|
|
|
|
|
|
if (path->cifp_x == new->cifp_x) /* vertical line */
|
|
|
|
|
{
|
|
|
|
|
new2->cifp_y = new->cifp_y;
|
|
|
|
|
new2->cifp_x = path->cifp_x + (int)
|
|
|
|
|
((dlong)(new2->cifp_y - path->cifp_y)
|
|
|
|
|
* (dlong)(next->cifp_x - path->cifp_x)
|
|
|
|
|
/ (dlong)(next->cifp_y - path->cifp_y));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
new2->cifp_x = new->cifp_x;
|
|
|
|
|
new2->cifp_y = path->cifp_y + (int)
|
|
|
|
|
((dlong)(new2->cifp_x - path->cifp_x)
|
|
|
|
|
* (dlong)(next->cifp_y - path->cifp_y)
|
|
|
|
|
/ (dlong)(next->cifp_x - path->cifp_x));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Break out the diagonal tile from the polygon and paint it. */
|
|
|
|
|
|
|
|
|
|
type = (edir == CIF_DIAG_UR || edir == CIF_DIAG_UL) ? 0 : TT_SIDE;
|
|
|
|
|
type |= (edir == CIF_DIAG_UR || edir == CIF_DIAG_DL) ? 0 : TT_DIRECTION;
|
|
|
|
|
type |= TT_DIAGONAL;
|
|
|
|
|
|
|
|
|
|
tt.r_ll = path->cifp_point;
|
|
|
|
|
tt.r_ur = path->cifp_next->cifp_next->cifp_point;
|
|
|
|
|
GeoCanonicalRect(&tt, &tr);
|
|
|
|
|
|
|
|
|
|
// TxPrintf("CIF read: Triangle %s %c at (%d, %d) plane %x\n",
|
|
|
|
|
// (type & TT_SIDE) ? "right" : "left", (type & TT_DIRECTION)
|
|
|
|
|
// ? '\\' : '/', tt.r_xbot, tt.r_ybot, plane);
|
|
|
|
|
|
|
|
|
|
/* Final check---ensure that rectangle is not degenerate */
|
|
|
|
|
|
|
|
|
|
if (plane && (tr.r_xtop - tr.r_xbot > 0) && (tr.r_ytop - tr.r_ybot > 0))
|
2023-12-30 20:10:09 +01:00
|
|
|
{
|
2017-04-25 14:41:48 +02:00
|
|
|
DBNMPaintPlane(plane, type, &tr, resultTbl, ui);
|
2023-12-30 20:10:09 +01:00
|
|
|
GEO_EXPAND(&tr, 1, &tr);
|
|
|
|
|
DBMergeNMTiles(plane, &tr, ui);
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFEdgeDirection --
|
|
|
|
|
*
|
|
|
|
|
* This procedure assigns a direction to the given edge.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* CIF_ZERO if the two points are the same
|
|
|
|
|
* CIF_LEFT if the edge goes left
|
|
|
|
|
* CIF_UP if the edge goes up
|
|
|
|
|
* CIF_RIGHT if the edge goes right
|
|
|
|
|
* CIF_DOWN if the edge goes down
|
|
|
|
|
* CIF_DIAG if the edge is non-manhattan
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFEdgeDirection(
|
|
|
|
|
CIFPath *first,
|
|
|
|
|
CIFPath *last) /* Edge to be categorized. */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (first->cifp_x < last->cifp_x)
|
|
|
|
|
{
|
|
|
|
|
if (first->cifp_y < last->cifp_y)
|
|
|
|
|
return CIF_DIAG_UR;
|
|
|
|
|
if (first->cifp_y > last->cifp_y)
|
|
|
|
|
return CIF_DIAG_DR;
|
|
|
|
|
return CIF_RIGHT;
|
|
|
|
|
}
|
|
|
|
|
if (first->cifp_x > last->cifp_x)
|
|
|
|
|
{
|
|
|
|
|
if (first->cifp_y < last->cifp_y)
|
|
|
|
|
return CIF_DIAG_UL;
|
|
|
|
|
if (first->cifp_y > last->cifp_y)
|
|
|
|
|
return CIF_DIAG_DL;
|
|
|
|
|
return CIF_LEFT;
|
|
|
|
|
}
|
|
|
|
|
if (first->cifp_y < last->cifp_y)
|
|
|
|
|
return CIF_UP;
|
|
|
|
|
if (first->cifp_y > last->cifp_y)
|
|
|
|
|
return CIF_DOWN;
|
|
|
|
|
return CIF_ZERO;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFCleanPath --
|
|
|
|
|
*
|
|
|
|
|
* Removes a edge in a path if it has zero length (repeated points).
|
|
|
|
|
* Combines two consecutive edges if their direction is the same,
|
|
|
|
|
* and their direction is manhattan.
|
|
|
|
|
* CIFCleanPath assumes that the path is closed, and will eliminate
|
|
|
|
|
* the last edge if its direction is the same as the first.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* May delete points in the path.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFCleanPath(
|
|
|
|
|
CIFPath *pathHead)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
CIFPath *next, *path, *prev, *last;
|
|
|
|
|
int dir1, dir2;
|
|
|
|
|
|
|
|
|
|
if (!pathHead) return;
|
|
|
|
|
prev = pathHead;
|
|
|
|
|
path = prev->cifp_next;
|
|
|
|
|
if (!path) return;
|
|
|
|
|
while((dir1 = CIFEdgeDirection(prev, path)) == CIF_ZERO)
|
|
|
|
|
{
|
|
|
|
|
/* This is a repeated point. */
|
|
|
|
|
next = path->cifp_next;
|
|
|
|
|
prev->cifp_next = next;
|
|
|
|
|
freeMagic((char *) path);
|
|
|
|
|
path = next;
|
|
|
|
|
if (!path) return;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2024-10-04 18:21:15 +02:00
|
|
|
while ((next = path->cifp_next))
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
if ((dir2 = CIFEdgeDirection(path, next)) == CIF_ZERO)
|
|
|
|
|
{
|
|
|
|
|
/* This is a repeated point. */
|
|
|
|
|
path->cifp_next = next->cifp_next;
|
|
|
|
|
freeMagic((char *) next);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Skip any non-manhattan (diagonal) edges. */
|
|
|
|
|
if (dir2 >= CIF_DIAG)
|
|
|
|
|
goto path_inc;
|
|
|
|
|
|
|
|
|
|
if (dir1 == dir2)
|
|
|
|
|
{
|
|
|
|
|
/* The middle point must go. */
|
|
|
|
|
prev->cifp_next = next;
|
|
|
|
|
freeMagic((char *) path);
|
|
|
|
|
path = next;
|
|
|
|
|
dir1 = CIFEdgeDirection(prev, path);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
path_inc:
|
|
|
|
|
dir1 = dir2;
|
|
|
|
|
prev = path;
|
|
|
|
|
path = next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Ensure that the path has more than one point. */
|
|
|
|
|
if (!pathHead->cifp_next)
|
|
|
|
|
{
|
|
|
|
|
/* Ensure that the resulting path is closed. */
|
2020-05-23 23:13:14 +02:00
|
|
|
if ((pathHead->cifp_x != path->cifp_x) ||
|
2017-04-25 14:41:48 +02:00
|
|
|
(pathHead->cifp_y != path->cifp_y))
|
|
|
|
|
{
|
|
|
|
|
next = (CIFPath *) mallocMagic((unsigned) (sizeof (CIFPath)));
|
|
|
|
|
next->cifp_x = pathHead->cifp_x;
|
|
|
|
|
next->cifp_y = pathHead->cifp_y;
|
|
|
|
|
next->cifp_next = (CIFPath *) 0;
|
|
|
|
|
path->cifp_next = next;
|
|
|
|
|
prev = path;
|
|
|
|
|
path = next;
|
|
|
|
|
dir1 = CIFEdgeDirection(prev, path);
|
|
|
|
|
}
|
|
|
|
|
if ((dir2 = CIFEdgeDirection(pathHead, pathHead->cifp_next)) <
|
|
|
|
|
CIF_DIAG)
|
|
|
|
|
{
|
|
|
|
|
/* We have at least two edges in the path. We have to */
|
|
|
|
|
/* fix the first edge and eliminate the last edge if */
|
|
|
|
|
/* the first and last edge have the same direction. */
|
|
|
|
|
if (dir1 == dir2)
|
|
|
|
|
{
|
|
|
|
|
pathHead->cifp_x = prev->cifp_x;
|
|
|
|
|
pathHead->cifp_y = prev->cifp_y;
|
|
|
|
|
prev->cifp_next = (CIFPath *) 0;
|
|
|
|
|
freeMagic((char *) path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFFreePath --
|
|
|
|
|
*
|
|
|
|
|
* This procedure frees up a path once it has been used.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* All the elements of path are returned to the storage allocator.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFFreePath(
|
|
|
|
|
CIFPath *path) /* Path to be freed. */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
while (path != NULL)
|
|
|
|
|
{
|
|
|
|
|
freeMagic((char *) path);
|
|
|
|
|
path = path->cifp_next;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifCommandError --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is called when unknown CIF commands are found
|
|
|
|
|
* in CIF files. It skips the command and advances to the next
|
|
|
|
|
* command.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifCommandError(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
CIFReadError("unknown command `%c'; ignored.\n" , PEEK());
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifParseEnd --
|
|
|
|
|
*
|
|
|
|
|
* This procedure processes the "end" statement in a CIF file
|
|
|
|
|
* (it ignores it).
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Always returns TRUE.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifParseEnd(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
TAKE();
|
|
|
|
|
CIFSkipBlanks();
|
|
|
|
|
if (PEEK() != EOF)
|
|
|
|
|
{
|
|
|
|
|
CIFReadError("End command isn't at end of file.\n");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifParseComment --
|
|
|
|
|
*
|
|
|
|
|
* This command skips over user comments in CIF files.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifParseComment(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
int opens;
|
|
|
|
|
int ch;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* take the '('
|
|
|
|
|
*/
|
|
|
|
|
TAKE();
|
|
|
|
|
opens = 1;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
ch = TAKE();
|
|
|
|
|
if (ch == '(')
|
|
|
|
|
opens++;
|
|
|
|
|
else if (ch == ')')
|
|
|
|
|
opens--;
|
|
|
|
|
else if (ch == '\n')
|
|
|
|
|
{
|
|
|
|
|
cifLineNumber++;
|
|
|
|
|
}
|
|
|
|
|
else if (ch == EOF)
|
|
|
|
|
{
|
|
|
|
|
CIFReadError("(comment) extends to end of file.\n");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
} while (opens > 0);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFDirectionToTrans --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is used to convert from a direction vector
|
|
|
|
|
* to a Magic transformation. The direction vector is a point
|
|
|
|
|
* giving a direction from the origin. It better be along
|
|
|
|
|
* one of the axes.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* The return value is the transformation corresponding to
|
|
|
|
|
* the direction, or the identity transform if the direction
|
|
|
|
|
* isn't along one of the axes.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
2024-10-12 15:01:10 +02:00
|
|
|
const Transform *
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFDirectionToTrans(
|
2024-10-12 15:01:10 +02:00
|
|
|
const Point *point) /* Direction vector from origin. */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
if ((point->p_x != 0) && (point->p_y == 0))
|
|
|
|
|
{
|
|
|
|
|
if (point->p_x > 0)
|
|
|
|
|
return &GeoIdentityTransform;
|
|
|
|
|
else return &Geo180Transform;
|
|
|
|
|
}
|
|
|
|
|
else if ((point->p_y != 0) && (point->p_x == 0))
|
|
|
|
|
{
|
|
|
|
|
if (point->p_y > 0)
|
|
|
|
|
return &Geo270Transform;
|
|
|
|
|
else return &Geo90Transform;
|
|
|
|
|
}
|
|
|
|
|
CIFReadError("non-manhattan direction vector (%d, %d); ignored.\n",
|
|
|
|
|
point->p_x, point->p_y);
|
|
|
|
|
return &GeoIdentityTransform;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFParseTransform --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is called to read in a transform from a
|
|
|
|
|
* CIF file.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE is returned if the parse completed successfully, and
|
|
|
|
|
* FALSE is returned otherwise.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The parameter pointed to by transformp is modified to
|
|
|
|
|
* contain the transform indicated by the CIF file.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFParseTransform(
|
|
|
|
|
Transform *transformp)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
char ch;
|
|
|
|
|
Point point;
|
|
|
|
|
Transform tmp;
|
|
|
|
|
int savescale;
|
|
|
|
|
|
|
|
|
|
*transformp = GeoIdentityTransform;
|
|
|
|
|
CIFSkipBlanks();
|
|
|
|
|
for (ch = PEEK() ; ch != ';' ; ch = PEEK())
|
|
|
|
|
{
|
|
|
|
|
switch (ch)
|
|
|
|
|
{
|
|
|
|
|
case 'T':
|
|
|
|
|
TAKE();
|
|
|
|
|
if (!CIFParsePoint(&point, 1))
|
|
|
|
|
{
|
|
|
|
|
CIFReadError("translation, but no point.\n");
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
GeoTranslateTrans(transformp, point.p_x, point.p_y, &tmp);
|
|
|
|
|
*transformp = tmp;
|
|
|
|
|
break;
|
|
|
|
|
case 'M':
|
|
|
|
|
TAKE();
|
|
|
|
|
CIFSkipBlanks();
|
|
|
|
|
ch = PEEK();
|
|
|
|
|
if (ch == 'X')
|
|
|
|
|
GeoTransTrans(transformp, &GeoSidewaysTransform, &tmp);
|
|
|
|
|
else if (ch == 'Y')
|
|
|
|
|
GeoTransTrans(transformp, &GeoUpsideDownTransform,
|
|
|
|
|
&tmp);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CIFReadError("mirror, but not in X or Y.\n");
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
TAKE();
|
|
|
|
|
*transformp = tmp;
|
|
|
|
|
break;
|
|
|
|
|
case 'R':
|
|
|
|
|
TAKE();
|
|
|
|
|
if (!CIFParseSInteger(&point.p_x) ||
|
|
|
|
|
!CIFParseSInteger(&point.p_y))
|
|
|
|
|
{
|
|
|
|
|
CIFReadError("rotation, but no direction.\n");
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
GeoTransTrans(transformp, CIFDirectionToTrans(&point),
|
|
|
|
|
&tmp);
|
|
|
|
|
*transformp = tmp;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
CIFReadError("transformation expected.\n");
|
|
|
|
|
CIFSkipToSemi();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
CIFSkipBlanks();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Before returning, we must scale the transform into Magic units. */
|
|
|
|
|
|
|
|
|
|
transformp->t_c = CIFScaleCoord(transformp->t_c, COORD_EXACT);
|
|
|
|
|
savescale = cifCurReadStyle->crs_scaleFactor;
|
|
|
|
|
transformp->t_f = CIFScaleCoord(transformp->t_f, COORD_EXACT);
|
|
|
|
|
if (savescale != cifCurReadStyle->crs_scaleFactor)
|
|
|
|
|
transformp->t_c *= (savescale / cifCurReadStyle->crs_scaleFactor);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFParseCommand --
|
|
|
|
|
*
|
|
|
|
|
* Parse one CIF command and farm it out to a routine to handle
|
|
|
|
|
* that command.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* May modify the contents of cifReadCellDef by painting or adding
|
|
|
|
|
* new uses or labels. May also create new CellDefs.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFReadFile(
|
|
|
|
|
FILE *file) /* File from which to read CIF. */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
/* We will use 1-word CIF numbers as keys in this hash table */
|
|
|
|
|
CIFReadCellInit(1);
|
|
|
|
|
|
|
|
|
|
if (cifCurReadStyle == NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("Don't know how to read CIF: nothing in tech file.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
TxPrintf("Warning: CIF reading is not undoable! I hope that's OK.\n");
|
|
|
|
|
UndoDisable();
|
|
|
|
|
|
|
|
|
|
cifTotalWarnings = 0;
|
|
|
|
|
cifTotalErrors = 0;
|
|
|
|
|
CifPolygonCount = 0;
|
2020-10-14 23:20:45 +02:00
|
|
|
cifSeenSnapWarning = FALSE;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
cifInputFile = file;
|
|
|
|
|
cifReadScale1 = 1;
|
|
|
|
|
cifReadScale2 = 1;
|
|
|
|
|
cifParseLaAvail = FALSE;
|
|
|
|
|
cifLineNumber = 1;
|
|
|
|
|
cifReadPlane = (Plane *) NULL;
|
|
|
|
|
cifCurLabelType = TT_SPACE;
|
|
|
|
|
while (PEEK() != EOF)
|
|
|
|
|
{
|
|
|
|
|
if (SigInterruptPending) goto done;
|
|
|
|
|
CIFSkipBlanks();
|
|
|
|
|
switch (PEEK())
|
|
|
|
|
{
|
|
|
|
|
case EOF:
|
|
|
|
|
break;
|
|
|
|
|
case ';':
|
|
|
|
|
break;
|
|
|
|
|
case 'B':
|
|
|
|
|
(void) CIFParseBox();
|
|
|
|
|
break;
|
|
|
|
|
case 'C':
|
|
|
|
|
(void) CIFParseCall();
|
|
|
|
|
break;
|
|
|
|
|
case 'D':
|
|
|
|
|
TAKE();
|
|
|
|
|
CIFSkipBlanks();
|
|
|
|
|
switch (PEEK())
|
|
|
|
|
{
|
|
|
|
|
case 'D':
|
|
|
|
|
(void) CIFParseDelete();
|
|
|
|
|
break;
|
|
|
|
|
case 'F':
|
|
|
|
|
(void) CIFParseFinish();
|
|
|
|
|
break;
|
|
|
|
|
case 'S':
|
|
|
|
|
(void) CIFParseStart();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
cifCommandError();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'E':
|
|
|
|
|
(void) cifParseEnd();
|
|
|
|
|
goto done;
|
|
|
|
|
case 'L':
|
|
|
|
|
(void) CIFParseLayer();
|
|
|
|
|
break;
|
|
|
|
|
case 'P':
|
|
|
|
|
(void) CIFParsePoly();
|
|
|
|
|
break;
|
|
|
|
|
case 'R':
|
|
|
|
|
(void) CIFParseFlash();
|
|
|
|
|
break;
|
|
|
|
|
case 'W':
|
|
|
|
|
(void) CIFParseWire();
|
|
|
|
|
break;
|
|
|
|
|
case '(':
|
|
|
|
|
(void) cifParseComment();
|
|
|
|
|
break;
|
|
|
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
|
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
|
|
|
(void) CIFParseUser();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
cifCommandError();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
CIFSkipSemi();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CIFReadError("no \"End\" statement.\n");
|
|
|
|
|
|
|
|
|
|
done:
|
2019-07-23 14:45:42 +02:00
|
|
|
CIFReadCellCleanup(FILE_CIF);
|
2017-04-25 14:41:48 +02:00
|
|
|
UndoEnable();
|
|
|
|
|
}
|