Yet another pass at the problem caused by implementing DRC

exceptions;  avoided the use of "signed char" altogether by just
making the drcc_exception value a bit mask with the lower 7 bits
being the index and the upper bit being the flag for exception (0)
vs. exemption (1), with the value 0xff being reserved for "none"
(no exception or exemption).  This implementation should avoid any
issues caused by ambiguity in the use of signed vs. unsigned char.
This commit is contained in:
R. Timothy Edwards 2026-03-24 09:37:50 -04:00
parent 460a357730
commit e789f18523
4 changed files with 37 additions and 35 deletions

View File

@ -1 +1 @@
8.3.626 8.3.627

View File

@ -765,13 +765,12 @@ drcTile (tile, dinfo, arg)
cptr = cptr->drcc_next) cptr = cptr->drcc_next)
{ {
/* Handle rule exceptions and exemptions */ /* Handle rule exceptions and exemptions */
if (cptr->drcc_exception != (char)DRC_EXCEPTION_NONE) if (cptr->drcc_exception != DRC_EXCEPTION_NONE)
{ {
PropertyRecord *proprec; PropertyRecord *proprec;
bool propfound, isinside = FALSE; bool propfound, isinside = FALSE;
char *name; char *name;
signed char idx = cptr->drcc_exception; int idx = cptr->drcc_exception & ~DRC_EXCEPTION_MASK;
if (idx < 0) idx = -idx - 1;
name = DRCCurStyle->DRCExceptionList[idx]; name = DRCCurStyle->DRCExceptionList[idx];
/* Is there any exception area defined? */ /* Is there any exception area defined? */
@ -797,8 +796,10 @@ drcTile (tile, dinfo, arg)
* an exception area. Exception rules are ignored if * an exception area. Exception rules are ignored if
* the edge is outside an exception area. * the edge is outside an exception area.
*/ */
if (!isinside && (cptr->drcc_exception >= 0)) continue; if (!isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) == 0)))
if (isinside && (cptr->drcc_exception < 0)) continue; continue;
if (isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) == 1)))
continue;
} }
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */ /* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
@ -1211,24 +1212,17 @@ drcTile (tile, dinfo, arg)
cptr = cptr->drcc_next) cptr = cptr->drcc_next)
{ {
/* Handle rule exceptions and exemptions */ /* Handle rule exceptions and exemptions */
if (cptr->drcc_exception != (char)DRC_EXCEPTION_NONE) if (cptr->drcc_exception != DRC_EXCEPTION_NONE)
{ {
PropertyRecord *proprec; PropertyRecord *proprec;
bool propfound, isinside = FALSE; bool propfound, isinside = FALSE;
char *name; char *name;
signed char idx = cptr->drcc_exception; int idx = cptr->drcc_exception & ~DRC_EXCEPTION_MASK;
if (idx < 0) idx = -idx - 1;
name = DRCCurStyle->DRCExceptionList[idx]; name = DRCCurStyle->DRCExceptionList[idx];
/* Is there any exception area defined? */ /* Is there any exception area defined? */
proprec = DBPropGet(arg->dCD_celldef, name, &propfound); proprec = DBPropGet(arg->dCD_celldef, name, &propfound);
/* Quickest case: Rule is an exception but there are no
* exception areas.
*/
if ((!propfound) && (cptr->drcc_exception >= 0))
continue;
/* If an exception area exists, is the error edge inside? */ /* If an exception area exists, is the error edge inside? */
if (propfound) if (propfound)
{ {
@ -1249,8 +1243,10 @@ drcTile (tile, dinfo, arg)
* an exception area. Exception rules are ignored if * an exception area. Exception rules are ignored if
* the edge is outside an exception area. * the edge is outside an exception area.
*/ */
if (isinside && (cptr->drcc_exception < 0)) continue; if (!isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) == 0)))
if (!isinside && (cptr->drcc_exception >= 0)) continue; continue;
if (isinside && ((cptr->drcc_exception & DRC_EXCEPTION_MASK) == 1)))
continue;
} }
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */ /* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */

View File

@ -76,7 +76,7 @@ static int DRCtag = 0;
* while reading the DRC tech file section. * while reading the DRC tech file section.
*/ */
static signed char drcCurException = (char)DRC_EXCEPTION_NONE; static unsigned char drcCurException = DRC_EXCEPTION_NONE;
/* /*
* Forward declarations. * Forward declarations.
@ -405,7 +405,9 @@ drcWhyCreate(whystring)
* not already exist. * not already exist.
* *
* Results: * Results:
* The index of the exception (which is a signed character). * The index of the exception (which is an unsigned character containing
* the index in the lower 7 bits and a high bit indicating if the rule
* is an exception (0) or an exemption (1)).
* *
* Side effects: * Side effects:
* Adds to the DRCExceptionList if "name" has not been used before. * Adds to the DRCExceptionList if "name" has not been used before.
@ -414,7 +416,7 @@ drcWhyCreate(whystring)
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
char unsigned char
drcExceptionCreate(name) drcExceptionCreate(name)
char *name; char *name;
{ {
@ -424,13 +426,14 @@ drcExceptionCreate(name)
/* NOTE: DRCExceptionList has "MASKHINTS_" prepended to the names */ /* NOTE: DRCExceptionList has "MASKHINTS_" prepended to the names */
for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++) for (i = 0; i < DRCCurStyle->DRCExceptionSize; i++)
if (!strcmp(name, DRCCurStyle->DRCExceptionList[i] + 10)) if (!strcmp(name, DRCCurStyle->DRCExceptionList[i] + 10))
return (char)i; return (unsigned char)i;
if (i > 127) /* Note that i cannot be 127 as this is reserved for DRC_EXCEPTION_NONE */
if (i > 126)
{ {
/* I would be shocked if this code ever got executed. */ /* I would be shocked if this code ever got executed. */
TxError("Error: Too many rule exceptions! Limit is 127.\n"); TxError("Error: Too many rule exceptions! Limit is 126.\n");
return (char)DRC_EXCEPTION_NONE; return DRC_EXCEPTION_NONE;
} }
/* Create a new list that is one entry longer than the old list. /* Create a new list that is one entry longer than the old list.
@ -448,7 +451,7 @@ drcExceptionCreate(name)
if (DRCCurStyle->DRCExceptionList != (char **)NULL) if (DRCCurStyle->DRCExceptionList != (char **)NULL)
freeMagic(DRCCurStyle->DRCExceptionList); freeMagic(DRCCurStyle->DRCExceptionList);
DRCCurStyle->DRCExceptionList = newlist; DRCCurStyle->DRCExceptionList = newlist;
return (char)i; return (unsigned char)i;
} }
/* /*
@ -732,7 +735,7 @@ DRCTechStyleInit()
} }
drcCifInit(); drcCifInit();
drcCurException = (char)DRC_EXCEPTION_NONE; drcCurException = DRC_EXCEPTION_NONE;
} }
/* /*
@ -3726,9 +3729,10 @@ drcRectangle(argc, argv)
* Returns 0. * Returns 0.
* *
* Side effects: * Side effects:
* Updates drcCurException. drcCurException is zero or positive for * Updates drcCurException. drcCurException contains the index in
* exceptions and negative for exemptions. The index can be * the lower 7 bits, and a flag in the upper bit (0 = exception rule,
* recovered from a negative value by negating it and subtracting 1. * 1 = exemption rule). The index can be recovered by masking off
* the upper bit.
* *
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
@ -3745,7 +3749,7 @@ drcException(argc, argv)
/* Assume that argc must be 2 because the parser insists upon it */ /* Assume that argc must be 2 because the parser insists upon it */
if (!strcmp(argv[1], "none")) if (!strcmp(argv[1], "none"))
drcCurException = (char)DRC_EXCEPTION_NONE; drcCurException = DRC_EXCEPTION_NONE;
else else
drcCurException = drcExceptionCreate(argv[1]); drcCurException = drcExceptionCreate(argv[1]);
return (0); return (0);
@ -3763,9 +3767,9 @@ drcExemption(argc, argv)
/* Assume that argc must be 2 because the parser insists upon it */ /* Assume that argc must be 2 because the parser insists upon it */
if (!strcmp(argv[1], "none")) if (!strcmp(argv[1], "none"))
drcCurException = (char)DRC_EXCEPTION_NONE; drcCurException = DRC_EXCEPTION_NONE;
else else
drcCurException = -(drcExceptionCreate(argv[1])) - 1; drcCurException = drcExceptionCreate(argv[1]) | DRC_EXCEPTION_MASK;
return (0); return (0);
} }

View File

@ -36,7 +36,7 @@ typedef struct drccookie
TileTypeBitMask drcc_mask; /* Legal types on RHS */ TileTypeBitMask drcc_mask; /* Legal types on RHS */
TileTypeBitMask drcc_corner; /* Types that trigger corner check */ TileTypeBitMask drcc_corner; /* Types that trigger corner check */
unsigned short drcc_flags; /* Miscellaneous flags, see below. */ unsigned short drcc_flags; /* Miscellaneous flags, see below. */
signed char drcc_exception; /* Index to list of exceptions */ unsigned char drcc_exception; /* Index to list of exceptions */
int drcc_edgeplane; /* Plane of edge */ int drcc_edgeplane; /* Plane of edge */
int drcc_plane; /* Index of plane on which to check int drcc_plane; /* Index of plane on which to check
* legal types. */ * legal types. */
@ -92,8 +92,10 @@ typedef struct drccookie
#define DRC_UNPROCESSED CLIENTDEFAULT #define DRC_UNPROCESSED CLIENTDEFAULT
#define DRC_PROCESSED 1 #define DRC_PROCESSED 1
/* drcc_exception defaults to -128 (0x80) meaning no exceptions/exemptions */ /* drcc_exception defaults to 255 meaning no exceptions/exemptions */
#define DRC_EXCEPTION_NONE (char)0x80 #define DRC_EXCEPTION_NONE ((unsigned char)0xff)
/* The high bit of the value determines if this is an exception or an exemption.
#define DRC_EXCEPTION_MASK ((unsigned char)0x80)
/* /*
* Background DRC (DRC Idle proc) for Tcl-based Magic * Background DRC (DRC Idle proc) for Tcl-based Magic