Extended the "property" command and modified the way that properties

are handled.  Properties were previously only character strings,
which had become cumbersome because properties were being used for
mask hints and bounding boxes, with the necessity of constantly
converting values from string to integer and back, which can cause
a performance impact as well as just being messy.  The main difference
to the command is the addition of an optional first keyword argument
for the property type, which can be "string", "integer", "dimension",
or "double".  All types except "string" can consist of multiple
values.  Multiple values can be specified as separate arguments on
the command line, so that, for example, values of FIXED_BBOX or
MASKHINTS_* no longer need to be quoted.  In addition, this completes
the handling of "units" implemented recently, as all properties of
the type "dimension" can be entered in the current units, will display
in the current units, and will scale with the database.
This commit is contained in:
R. Timothy Edwards 2026-02-18 10:48:47 -05:00
parent 7e9b6fb61e
commit cb30ac369b
26 changed files with 1489 additions and 781 deletions

View File

@ -1 +1 @@
8.3.604
8.3.605

View File

@ -505,28 +505,33 @@ calmaParseStructure(
if (CalmaReadOnly || predefined)
{
PropertyRecord *proprec;
char cstring[1024];
/* Writing the file position into a string is slow, but */
/* it prevents requiring special handling when printing */
/* out the properties. */
char *fpcopy = (char *)mallocMagic(20);
char *fncopy;
/* Substitute variable for PDK path or ~ for home directory */
/* the same way that cell references are handled in .mag files. */
DBPathSubstitute(filename, cstring, cifReadCellDef);
fncopy = StrDup(NULL, cstring);
sprintf(fpcopy, "%"DLONG_PREFIX"d", (dlong) filepos);
DBPropPut(cifReadCellDef, "GDS_START", (ClientData)fpcopy);
fpcopy = (char *)mallocMagic(20);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
proprec->prop_type = PROPERTY_TYPE_DOUBLE;
proprec->prop_len = 1;
proprec->prop_value.prop_double[0] = filepos;
DBPropPut(cifReadCellDef, "GDS_START", (ClientData)proprec);
filepos = FTELL(calmaInputFile);
sprintf(fpcopy, "%"DLONG_PREFIX"d", (dlong) filepos);
DBPropPut(cifReadCellDef, "GDS_END", (ClientData)fpcopy);
DBPropPut(cifReadCellDef, "GDS_FILE", (ClientData)fncopy);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
proprec->prop_type = PROPERTY_TYPE_DOUBLE;
proprec->prop_len = 1;
proprec->prop_value.prop_double[0] = filepos;
DBPropPut(cifReadCellDef, "GDS_END", (ClientData)proprec);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) - 7 +
strlen(cstring));
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = 1;
strcpy(proprec->prop_value.prop_string, cstring);
DBPropPut(cifReadCellDef, "GDS_FILE", (ClientData)proprec);
if (predefined)
{

View File

@ -528,7 +528,7 @@ calmaDumpStructure(
/* Is view abstract? */
DBPropGet(edef, "LEFview", &isAbstract);
chklibname = (char *)DBPropGet(edef, "GDS_FILE", &isReadOnly);
chklibname = DBPropGetString(edef, "GDS_FILE", &isReadOnly);
if (isAbstract && isReadOnly)
{
@ -738,7 +738,7 @@ calmaFullDump(
* names in the GDS file do not shadow any names in the database.
*/
viewopts = (char *)DBPropGet(def, "LEFview", &isAbstract);
viewopts = DBPropGetString(def, "LEFview", &isAbstract);
if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
{
/* Generate a SHORT name for this cell (else it is easy to run into the
@ -918,7 +918,7 @@ calmaProcessDef(
DBPropGet(def, "GDS_END", &hasGDSEnd);
DBPropGet(def, "CIFhier", &needHier);
filename = (char *)DBPropGet(def, "GDS_FILE", &isReadOnly);
filename = DBPropGetString(def, "GDS_FILE", &isReadOnly);
/* When used with "calma addendum true", don't output the read-only */
/* cells. This makes the library incomplete and dependent on the */
@ -1033,13 +1033,12 @@ calmaProcessDef(
}
else
{
offptr = (char *)DBPropGet(def, "GDS_END", NULL);
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cval = DBPropGetDouble(def, "GDS_END", NULL);
cellend = (off_t)cval;
offptr = (char *)DBPropGet(def, "GDS_BEGIN", &oldStyle);
cval = DBPropGetDouble(def, "GDS_BEGIN", &oldStyle);
if (!oldStyle)
{
offptr = (char *)DBPropGet(def, "GDS_START", NULL);
cval = DBPropGetDouble(def, "GDS_START", NULL);
/* Write our own header and string name, to ensure */
/* that the magic cell name and GDS name match. */
@ -1056,7 +1055,6 @@ calmaProcessDef(
calmaOutStructName(CALMA_STRNAME, def, outf);
}
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cellstart = (off_t)cval;
/* GDS_START has been defined as the start of data after the cell */
@ -1263,7 +1261,7 @@ calmaOutFunc(
int dbunits;
calmaOutputStruct cos;
bool propfound;
char *propvalue;
PropertyRecord *proprec;
cos.f = f;
cos.area = (cliprect == &TiPlaneRect) ? NULL : cliprect;
@ -1323,14 +1321,20 @@ calmaOutFunc(
/* Include any fixed bounding box as part of the area to process, */
/* in case the fixed bounding box is larger than the geometry. */
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
if (propfound)
{
Rect bbox;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
GeoInclude(&bbox, &bigArea);
}
}
CIFErrorDef = def;

View File

@ -508,7 +508,7 @@ calmaDumpStructureZ(
/* Is view abstract? */
DBPropGet(edef, "LEFview", &isAbstract);
chklibname = (char *)DBPropGet(edef, "GDS_FILE", &isReadOnly);
chklibname = DBPropGetString(edef, "GDS_FILE", &isReadOnly);
if (isAbstract && isReadOnly)
{
@ -716,7 +716,7 @@ calmaFullDumpZ(
* names in the GDS file do not shadow any names in the database.
*/
viewopts = (char *)DBPropGet(def, "LEFview", &isAbstract);
viewopts = DBPropGetString(def, "LEFview", &isAbstract);
if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix")))
{
/* Generate a SHORT name for this cell (else it is easy to run into the
@ -870,7 +870,7 @@ calmaProcessDefZ(
DBPropGet(def, "GDS_START", &hasContent);
DBPropGet(def, "GDS_END", &hasGDSEnd);
DBPropGet(def, "CIFhier", &needHier);
filename = (char *)DBPropGet(def, "GDS_FILE", &isReadOnly);
filename = DBPropGetString(def, "GDS_FILE", &isReadOnly);
/* When used with "calma addendum true", don't output the read-only */
/* cells. This makes the library incomplete and dependent on the */
@ -985,13 +985,12 @@ calmaProcessDefZ(
}
else
{
offptr = (char *)DBPropGet(def, "GDS_END", NULL);
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cval = DBPropGetDouble(def, "GDS_END", NULL);
cellend = (z_off_t)cval;
offptr = (char *)DBPropGet(def, "GDS_BEGIN", &oldStyle);
cval = DBPropGetDouble(def, "GDS_BEGIN", &oldStyle);
if (!oldStyle)
{
offptr = (char *)DBPropGet(def, "GDS_START", NULL);
cval = DBPropGetDouble(def, "GDS_START", NULL);
/* Write our own header and string name, to ensure */
/* that the magic cell name and GDS name match. */
@ -1008,7 +1007,6 @@ calmaProcessDefZ(
calmaOutStructNameZ(CALMA_STRNAME, def, outf);
}
sscanf(offptr, "%"DLONG_PREFIX"d", &cval);
cellstart = (z_off_t)cval;
/* GDS_START has been defined as the start of data after the cell */
@ -1186,6 +1184,7 @@ calmaOutFuncZ(
int dbunits;
calmaOutputStructZ cos;
bool propfound;
PropertyRecord *proprec;
char *propvalue;
extern int compport(const void *one, const void *two); /* Forward declaration */
@ -1247,14 +1246,20 @@ calmaOutFuncZ(
/* Include any fixed bounding box as part of the area to process, */
/* in case the fixed bounding box is larger than the geometry. */
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
if (propfound)
{
Rect bbox;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
GeoInclude(&bbox, &bigArea);
}
}
CIFErrorDef = def;

View File

@ -4998,6 +4998,7 @@ CIFGenLayer(
BridgeData *bridge;
BloatData *bloats;
bool hstop = FALSE;
PropertyRecord *proprec;
char *propvalue;
bool found;
@ -5454,10 +5455,17 @@ CIFGenLayer(
if (origDef && (origDef->cd_flags & CDFIXEDBBOX))
{
propvalue = (char *)DBPropGet(origDef, "FIXED_BBOX", &found);
proprec = DBPropGet(origDef, "FIXED_BBOX", &found);
if (!found) break;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) != 4) break;
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
}
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
bbox.r_xbot *= cifScale;
@ -5519,44 +5527,37 @@ CIFGenLayer(
case CIFOP_MASKHINTS:
{
int j, numfound;
int n;
char propname[512];
char *propptr;
char *layername = (char *)op->co_client;
sprintf(propname, "MASKHINTS_%s", layername);
snprintf(propname, 512, "MASKHINTS_%s", layername);
propvalue = (char *)DBPropGet(cellDef, propname, &found);
proprec = DBPropGet(cellDef, propname, &found);
if (!found) break; /* No mask hints available */
propptr = propvalue;
while (*propptr)
{
numfound = sscanf(propptr, "%d %d %d %d",
&bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop);
if (numfound != 4)
if (proprec->prop_type == PROPERTY_TYPE_DIMENSION)
{
for (n = 0; n < proprec->prop_len; n += 4)
{
/* To do: Allow keyword "rect", "tri", or "poly"
* at the start of the list and parse accordingly.
* For now, this only flags an error.
*/
TxError("%s: Cannot read rectangle values.\n", propname);
break;
}
cifPlane = curPlane;
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
bbox.r_xbot *= cifScale;
bbox.r_xtop *= cifScale;
bbox.r_ybot *= cifScale;
bbox.r_ytop *= cifScale;
cifScale = 1;
DBNMPaintPlane(curPlane, CIF_SOLIDTYPE, &bbox,
CIFPaintTable, (PaintUndoInfo *)NULL);
for (j = 0; j < 4; j++)
{
while (*propptr && isspace(*propptr)) propptr++;
while (*propptr && !isspace(*propptr)) propptr++;
if ((n + 3) >= proprec->prop_len) break;
cifPlane = curPlane;
cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
bbox.r_xbot = proprec->prop_value.prop_integer[n];
bbox.r_ybot = proprec->prop_value.prop_integer[n + 1];
bbox.r_xtop = proprec->prop_value.prop_integer[n + 2];
bbox.r_ytop = proprec->prop_value.prop_integer[n + 3];
bbox.r_xbot *= cifScale;
bbox.r_ybot *= cifScale;
bbox.r_xtop *= cifScale;
bbox.r_ytop *= cifScale;
cifScale = 1;
DBNMPaintPlane(curPlane, CIF_SOLIDTYPE, &bbox,
CIFPaintTable, (PaintUndoInfo *)NULL);
}
}
}

View File

@ -211,53 +211,6 @@ typedef struct _maskHintsData
CellDef *mh_def;
} MaskHintsData;
/*
* ----------------------------------------------------------------------------
*
* cifMaskHints --
*
* Copy a mask hint into a target cell by adding it to the
* property list of the target cell. If the target cell already
* has the same mask hint key, then the mask hint value is
* appended to the property in the target cell def.
*
* Returns:
* 0 to keep the search going.
*
* Side effects:
* Modifies properties of the target cell def.
*
* ----------------------------------------------------------------------------
*/
/* DEPRECATED */
int
cifMaskHints(
char *name,
char *value,
CellDef *targetDef)
{
char *propvalue, *newval;
bool propfound;
if (!strncmp(name, "MASKHINTS_", 10))
{
/* Check if name exists already in the flattened cell */
propvalue = (char *)DBPropGet(targetDef, name, &propfound);
if (propfound)
{
/* Append value to the property */
newval = mallocMagic(strlen(value) + strlen(propvalue) + 2);
sprintf(newval, "%s %s", propvalue, value);
}
else
newval = StrDup((char **)NULL, value);
DBPropPut(targetDef, name, newval);
}
return 0;
}
/*
* ----------------------------------------------------------------------------
*
@ -279,67 +232,68 @@ cifMaskHints(
int
cifFlatMaskHints(
char *name,
char *value,
PropertyRecord *proprec,
MaskHintsData *mhd)
{
Rect r, newr;
char *vptr, *newval, *lastval, *propvalue;
bool propfound;
int lastlen, numvals;
int i, lastlen, numvals;
PropertyRecord *newproprec, *oldproprec;
if (!strncmp(name, "MASKHINTS_", 10))
{
newval = (char *)NULL;
vptr = value;
while (*vptr != '\0')
/* Check if name exists already in the flattened cell */
oldproprec = (PropertyRecord *)DBPropGet(mhd->mh_def, name, &propfound);
if (propfound)
{
numvals = sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop);
if (numvals == 4)
{
/* Transform rectangle to top level coordinates */
GeoTransRect(mhd->mh_trans, &r, &newr);
lastval = newval;
lastlen = (lastval) ? strlen(lastval) : 0;
newval = mallocMagic(40 + lastlen);
if (lastval)
strcpy(newval, lastval);
else
*newval = '\0';
sprintf(newval + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
newr.r_xbot, newr.r_ybot, newr.r_xtop, newr.r_ytop);
if (lastval) freeMagic(lastval);
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(oldproprec->prop_len + proprec->prop_len - 2) * sizeof(int));
newproprec->prop_len = oldproprec->prop_len + proprec->prop_len;
newproprec->prop_type = PROPERTY_TYPE_DIMENSION;
}
else
{
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(proprec->prop_len - 2) * sizeof(int));
newproprec->prop_len = proprec->prop_len;
newproprec->prop_type = PROPERTY_TYPE_DIMENSION;
}
/* Parse through the four values and check if there's more */
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
}
else
for (i = 0; i < proprec->prop_len; i += 4)
{
/* There should be a multiple of 4 values but avoid an array overrun
* if not.
*/
if ((i + 3) >= proprec->prop_len)
{
TxError("MASKHINTS_%s: Expected 4 values, found only %d\n",
name + 10, numvals);
break;
}
r.r_xbot = proprec->prop_value.prop_integer[i];
r.r_ybot = proprec->prop_value.prop_integer[i + 1];
r.r_xtop = proprec->prop_value.prop_integer[i + 2];
r.r_ytop = proprec->prop_value.prop_integer[i + 3];
/* Transform rectangle to top level coordinates */
GeoTransRect(mhd->mh_trans, &r, &newr);
newproprec->prop_value.prop_integer[i] = newr.r_xbot;
newproprec->prop_value.prop_integer[i + 1] = newr.r_ybot;
newproprec->prop_value.prop_integer[i + 2] = newr.r_xtop;
newproprec->prop_value.prop_integer[i + 3] = newr.r_ytop;
}
/* Check if name exists already in the flattened cell */
propvalue = (char *)DBPropGet(mhd->mh_def, name, &propfound);
/* If there were existing entries, copy them into the new property */
if (propfound)
{
/* Append newval to the property */
lastval = newval;
newval = mallocMagic(strlen(lastval) + strlen(propvalue) + 2);
sprintf(newval, "%s %s", propvalue, lastval);
freeMagic(lastval);
for (i = 0; i < oldproprec->prop_len; i++)
newproprec->prop_value.prop_integer[i + proprec->prop_len] =
oldproprec->prop_value.prop_integer[i];
}
DBPropPut(mhd->mh_def, name, newval);
DBPropPut(mhd->mh_def, name, newproprec);
}
return 0;
}

View File

@ -824,46 +824,43 @@ CIFPaintCurrent(
if (lrec != NULL)
{
PropertyRecord *proprec;
char *propname;
int proplen;
propname = (char *)mallocMagic(11 + strlen(cifReadLayers[i]));
sprintf(propname, "MASKHINTS_%s", cifReadLayers[i]);
propstr = (char *)NULL;
/* Turn all linked Rects into a mask-hints property in the
* target cell.
*/
proplen = 0;
while (lrec != NULL) proplen += 4;
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) *
(proplen - 2) * sizeof(int));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = proplen;
proplen = 0;
while (lrec != NULL)
{
char *newstr;
sprintf(locstr, "%d %d %d %d",
lrec->r_r.r_xbot / CIFCurStyle->cs_scaleFactor,
lrec->r_r.r_ybot / CIFCurStyle->cs_scaleFactor,
lrec->r_r.r_xtop / CIFCurStyle->cs_scaleFactor,
lrec->r_r.r_ytop / CIFCurStyle->cs_scaleFactor);
if (propstr == NULL)
{
newstr = (char *)mallocMagic(strlen(locstr) + 1);
sprintf(newstr, "%s", locstr);
}
else
{
newstr = (char *)mallocMagic(strlen(locstr)
+ strlen(propstr) + 2);
sprintf(newstr, "%s %s", propstr, locstr);
freeMagic(propstr);
}
propstr = newstr;
proprec->prop_value.prop_integer[proplen] =
lrec->r_r.r_xbot / CIFCurStyle->cs_scaleFactor;
proprec->prop_value.prop_integer[proplen + 1] =
lrec->r_r.r_ybot / CIFCurStyle->cs_scaleFactor;
proprec->prop_value.prop_integer[proplen + 2] =
lrec->r_r.r_xtop / CIFCurStyle->cs_scaleFactor;
proprec->prop_value.prop_integer[proplen + 3] =
lrec->r_r.r_ytop / CIFCurStyle->cs_scaleFactor;
free_magic1_t mm1 = freeMagic1_init();
freeMagic1(&mm1, lrec);
lrec = lrec->r_next;
freeMagic1_end(&mm1);
proplen += 4;
}
/* NOTE: propstr is transferred to the CellDef and should
* not be free'd here.
*/
DBPropPut(cifReadCellDef, propname, propstr);
DBPropPut(cifReadCellDef, propname, proprec);
freeMagic(propname);
}
@ -902,6 +899,7 @@ cifMakeBoundaryFunc(
/* If there are multiple rectangles defined with the boundary */
/* layer, then the last one defines the FIXED_BBOX property. */
PropertyRecord *proprec;
Rect area;
char propertyvalue[128], *storedvalue;
int savescale;
@ -933,19 +931,24 @@ cifMakeBoundaryFunc(
if (cifReadCellDef->cd_flags & CDFIXEDBBOX)
{
char *propvalue;
PropertyRecord *proprec;
bool found;
/* Only flag a warning if the redefined boundary was */
/* different from the original. */
propvalue = (char *)DBPropGet(cifReadCellDef, "FIXED_BBOX", &found);
proprec = DBPropGet(cifReadCellDef, "FIXED_BBOX", &found);
if (found)
{
Rect bbox;
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
if ((bbox.r_xbot != area.r_xbot) ||
(bbox.r_ybot != area.r_ybot) ||
(bbox.r_xtop != area.r_xtop) ||
@ -962,10 +965,15 @@ cifMakeBoundaryFunc(
}
}
sprintf(propertyvalue, "%d %d %d %d",
area.r_xbot, area.r_ybot, area.r_xtop, area.r_ytop);
storedvalue = StrDup((char **)NULL, propertyvalue);
DBPropPut(cifReadCellDef, "FIXED_BBOX", storedvalue);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) + 2 * sizeof(int));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = 4;
proprec->prop_value.prop_integer[0] = area.r_xbot;
proprec->prop_value.prop_integer[1] = area.r_ybot;
proprec->prop_value.prop_integer[2] = area.r_xtop;
proprec->prop_value.prop_integer[3] = area.r_ytop;
DBPropPut(cifReadCellDef, "FIXED_BBOX", proprec);
cifReadCellDef->cd_flags |= CDFIXEDBBOX;
return 0;
}

View File

@ -504,10 +504,10 @@ CIFCoverageLayer(
}
else
{
TxPrintf("%s Area = %lld CIF units^2\n", doBox ? "Cursor Box" :
TxPrintf("%s Area = %"DLONG_PREFIX"d CIF units^2\n", doBox ? "Cursor Box" :
"Cell", btotal);
TxPrintf("Layer Bounding Area = %lld CIF units^2\n", atotal);
TxPrintf("Layer Total Area = %lld CIF units^2\n", cstats.coverage);
TxPrintf("Layer Bounding Area = %"DLONG_PREFIX"d CIF units^2\n", atotal);
TxPrintf("Layer Total Area = %"DLONG_PREFIX"d CIF units^2\n", cstats.coverage);
TxPrintf("Coverage in %s = %1.1f%%\n", doBox ? "box" :
"cell", 100.0 * fcover);
}

View File

@ -1300,7 +1300,7 @@ CmdCellname(
if (cellDef == (CellDef *) NULL)
TxError("Unknown cell %s\n", cellname);
else
CmdDoProperty(cellDef, cmd, 3 + ((dolist) ? 1 : 0));
CmdDoProperty(cellDef, w, cmd, 3 + ((dolist) ? 1 : 0));
break;
case IDX_DELETE:
@ -4991,15 +4991,20 @@ cmdDumpParseArgs(
bbox = def->cd_bbox;
if (def->cd_flags & CDFIXEDBBOX)
{
char *propvalue;
PropertyRecord *proprec;
bool found;
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &found);
proprec = DBPropGet(def, "FIXED_BBOX", &found);
if (found)
{
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) != 4)
bbox = def->cd_bbox;
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
}
}
}

View File

@ -2319,30 +2319,145 @@ parsepositions:
void
CmdDoProperty(
CellDef *def,
MagWindow *w,
TxCommand *cmd,
int argstart)
{
int printPropertiesFunc();
PropertyRecord *proprec;
char *value;
bool propfound;
int proptype, proplen, propvalue, i;
dlong dvalue;
int locargc = cmd->tx_argc - argstart + 1;
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj;
#endif
int printPropertiesFunc(); /* Forward declaration */
/* These should match the property codes in database.h.in */
static const char * const cmdPropertyType[] = {
"string", "integer", "dimension", "double", NULL
};
/* If a property type is given, parse it and then strip it from
* the arguments list.
*/
if (locargc > 1)
{
proptype = Lookup(cmd->tx_argv[argstart], cmdPropertyType);
if (proptype >= 0)
{
locargc--;
argstart++;
}
else
proptype = PROPERTY_TYPE_STRING; /* default */
}
else
proptype = PROPERTY_TYPE_STRING; /* default */
if (locargc == 1)
{
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj;
/* Create an empty list for the interpreter result; the
* printPropertiesFunc() function will append values to it.
*/
tobj = Tcl_NewListObj(0, NULL);
Tcl_SetObjResult(magicinterp, tobj);
#endif
/* print all properties and their values */
DBPropEnum(def, printPropertiesFunc, NULL);
DBPropEnum(def, printPropertiesFunc, (ClientData)w);
}
else if (locargc == 2)
{
/* print the value of the indicated property */
value = (char *)DBPropGet(def, cmd->tx_argv[argstart], &propfound);
proprec = (PropertyRecord *)DBPropGet(def, cmd->tx_argv[argstart], &propfound);
if (propfound)
{
proptype = proprec->prop_type;
#ifdef MAGIC_WRAPPER
Tcl_SetResult(magicinterp, value, NULL);
switch (proptype)
{
case PROPERTY_TYPE_STRING:
Tcl_SetResult(magicinterp, proprec->prop_value.prop_string, NULL);
break;
case PROPERTY_TYPE_INTEGER:
if (proprec->prop_len == 1)
Tcl_SetObjResult(magicinterp,
Tcl_NewIntObj(proprec->prop_value.prop_integer[0]));
else
{
tobj = Tcl_NewListObj(0, NULL);
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewIntObj(
proprec->prop_value.prop_integer[i]));
Tcl_SetObjResult(magicinterp, tobj);
}
break;
case PROPERTY_TYPE_DIMENSION:
if (proprec->prop_len == 1)
Tcl_SetResult(magicinterp,
DBWPrintValue(proprec->prop_value.prop_integer[0],
w, TRUE), NULL);
else
{
tobj = Tcl_NewListObj(0, NULL);
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewStringObj(DBWPrintValue(
proprec->prop_value.prop_integer[i], w,
((i % 2) == 0) ? TRUE : FALSE), -1));
Tcl_SetObjResult(magicinterp, tobj);
}
break;
case PROPERTY_TYPE_DOUBLE:
if (proprec->prop_len == 1)
Tcl_SetObjResult(magicinterp,
Tcl_NewWideIntObj((Tcl_WideInt)
proprec->prop_value.prop_double[0]));
else
{
tobj = Tcl_NewListObj(0, NULL);
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, tobj,
Tcl_NewWideIntObj((Tcl_WideInt)
proprec->prop_value.prop_double[i]));
Tcl_SetObjResult(magicinterp, tobj);
}
break;
}
#else
TxPrintf("%s", value);
switch (proptype)
{
case PROPERTY_TYPE_STRING:
TxPrintf("%s\n", proprec->prop_value.prop_string);
break;
case PROPERTY_TYPE_INTEGER:
for (i = 0; i < proprec->prop_len; i++)
TxPrintf("%d ", proprec->prop_value.prop_integer[i]);
TxPrintf("\n");
break;
case PROPERTY_TYPE_DIMENSION:
for (i = 0; i < proprec->prop_len; i++)
TxPrintf("%s ", DBWPrintValue(
proprec->prop_value.prop_integer[i], w,
((i % 2) == 0) ? TRUE : FALSE);
TxPrintf("\n");
break;
case PROPERTY_TYPE_DOUBLE:
for (i = 0; i < proprec->prop_len; i++)
TxPrintf( "%"DLONG_PREFIX"d",
proprec->prop_value.prop_double[i]);
TxPrintf("\n");
break;
}
#endif
}
else {
#ifdef MAGIC_WRAPPER
/* If the command was "cellname list property ...", then */
@ -2352,14 +2467,159 @@ CmdDoProperty(
TxError("Property name \"%s\" is not defined\n", cmd->tx_argv[1]);
}
}
else if (locargc == 3)
else if (locargc >= 3)
{
/* Catch the following known reserved keywords and cast them to the
* expected property type. If any property type was already given
* to the command, it is overridden. This ensures that the reserved
* keyword functions work correctly.
*
* GDS_START, GDS_END: PROPERTY_TYPE_DOUBLE
* MASKHINTS_*: PROPERTY_TYPE_DIMENSION
* FIXED_BBOX: PROPERTY_TYPE_DIMENSION
*/
if (!strcmp(cmd->tx_argv[argstart], "GDS_START"))
proptype = PROPERTY_TYPE_DOUBLE;
else if (!strcmp(cmd->tx_argv[argstart], "GDS_END"))
proptype = PROPERTY_TYPE_DOUBLE;
else if (!strcmp(cmd->tx_argv[argstart], "GDS_FILE"))
proptype = PROPERTY_TYPE_STRING;
else if (!strcmp(cmd->tx_argv[argstart], "FIXED_BBOX"))
proptype = PROPERTY_TYPE_DIMENSION;
else if (!strcmp(cmd->tx_argv[argstart], "OBS_BBOX"))
proptype = PROPERTY_TYPE_DIMENSION;
else if (!strncmp(cmd->tx_argv[argstart], "MASKHINTS_", 10))
proptype = PROPERTY_TYPE_DIMENSION;
if (strlen(cmd->tx_argv[argstart + 1]) == 0)
DBPropPut(def, cmd->tx_argv[argstart], NULL);
else
{
value = StrDup((char **)NULL, cmd->tx_argv[argstart + 1]);
DBPropPut(def, cmd->tx_argv[argstart], value);
if (proptype == PROPERTY_TYPE_STRING)
{
proplen = strlen(cmd->tx_argv[argstart + 1]);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) -
7 + proplen);
proprec->prop_type = proptype;
proprec->prop_len = proplen;
strcpy(proprec->prop_value.prop_string, cmd->tx_argv[argstart + 1]);
}
else /* PROPERTY_TYPE_INTEGER or PROPERTY_TYPE_DIMENSION */
{
/* Two choices: If locargc == 3 then all values are in one
* argument. If locargc > 3, then parse each argument as a
* separate value.
*/
if (locargc > 3)
{
proplen = locargc - 2;
if (proptype == PROPERTY_TYPE_DOUBLE)
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(proplen - 1)*sizeof(dlong));
else
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(proplen - 2)*sizeof(int));
proprec->prop_type = proptype;
proprec->prop_len = proplen;
for (i = 1; i < locargc - 1; i++)
{
if (proptype == PROPERTY_TYPE_INTEGER)
{
if (sscanf(cmd->tx_argv[argstart + i], "%d",
&propvalue) == 1)
proprec->prop_value.prop_integer[i - 1] = propvalue;
else
{
TxError("Unable to parse value \"%s\" as an integer\n",
cmd->tx_argv[argstart + i]);
proprec->prop_value.prop_integer[i - 1] = 0;
}
}
else if (proptype == PROPERTY_TYPE_DOUBLE)
{
if (sscanf(cmd->tx_argv[argstart + i], "%"DLONG_PREFIX"d",
&dvalue) == 1)
proprec->prop_value.prop_double[i - 1] = dvalue;
else
{
TxError("Unable to parse value \"%s\" as an integer\n",
cmd->tx_argv[argstart + i]);
proprec->prop_value.prop_double[i - 1] = 0;
}
}
else /* PROPERTY_TYPE_DIMENSION */
{
propvalue = cmdParseCoord(w, cmd->tx_argv[argstart + i],
FALSE, ((i % 2) == 0) ? FALSE : TRUE);
proprec->prop_value.prop_integer[i - 1] = propvalue;
}
}
}
else
{
/* Make two passes through the argument string, once to get
* the valid number of arguments, then again to parse the
* values, once the property record has been allocated
*/
value = cmd->tx_argv[argstart + 1];
for (proplen = 0; *value != '\0'; )
{
if (isspace(*value) && (*value != '\0')) value++;
if (!isspace(*value))
{
proplen++;
while (!isspace(*value) && (*value != '\0')) value++;
}
}
if (proplen > 0)
{
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(proplen - 2)*sizeof(int));
proprec->prop_type = proptype;
proprec->prop_len = proplen;
}
/* Second pass */
value = cmd->tx_argv[argstart + 1];
for (proplen = 0; proplen < proprec->prop_len; proplen++)
{
if (isspace(*value) && (*value != '\0')) value++;
if (!isspace(*value))
{
if (proptype == PROPERTY_TYPE_INTEGER)
{
if (sscanf(value, "%d", &propvalue) != 1)
{
TxError("Unable to parse integer "
"value from \"%s\"\n",
value);
propvalue = 0;
}
proprec->prop_value.prop_integer[proplen] = propvalue;
}
else if (proptype == PROPERTY_TYPE_DOUBLE)
{
if (sscanf(value, "%"DLONG_PREFIX"d", &dvalue) != 1)
{
TxError("Unable to parse integer "
"value from \"%s\"\n",
value);
propvalue = 0;
}
proprec->prop_value.prop_double[proplen] = dvalue;
}
else /* PROPERTY_TYPE_DIMENSION */
{
propvalue = cmdParseCoord(w, value, FALSE,
((proplen % 2) == 0) ? TRUE : FALSE);
proprec->prop_value.prop_integer[proplen] = propvalue;
}
while (!isspace(*value) && (*value != '\0')) value++;
}
}
}
}
DBPropPut(def, cmd->tx_argv[argstart], proprec);
}
def->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
}
@ -2380,10 +2640,14 @@ CmdDoProperty(
* defined in database/DBprop.c.
*
* Usage:
* property [name] [value]
* property [string|integer|dimension] [name] [value]
*
* "name" is a unique string tag for the property, and "value" is its
* string value.
* If the first argument is present, it must be one of the known
* keywords, and determines the form in which "value" is interpreted and
* stored. "name" is a unique string tag for the property. "value" is
* the value of the property, which is either a string, integer, or a
* list of integers. The difference between an "integer" and a "dimension"
* is that all values which are dimensions are scaled with internal units.
*
* Results:
* None.
@ -2410,7 +2674,7 @@ CmdProperty(
else
def = ((CellUse *) w->w_surfaceID)->cu_def;
CmdDoProperty(def, cmd, 1);
CmdDoProperty(def, w, cmd, 1);
}
/*
@ -2422,27 +2686,71 @@ CmdProperty(
int
printPropertiesFunc(
const char *name,
ClientData value,
ClientData cdata) /* not used */
PropertyRecord *proprec,
MagWindow *w)
{
#ifdef MAGIC_WRAPPER
char *keyvalue;
int i;
if (value == NULL)
#ifdef MAGIC_WRAPPER
Tcl_Obj *tobj, *lobj;
tobj = Tcl_GetObjResult(magicinterp);
lobj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_NewStringObj(name, -1));
switch (proprec->prop_type)
{
keyvalue = (char *)mallocMagic(strlen(name) + 4);
sprintf(keyvalue, "%s {}", name);
case PROPERTY_TYPE_STRING:
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(proprec->prop_value.prop_string, -1));
break;
case PROPERTY_TYPE_INTEGER:
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewIntObj(proprec->prop_value.prop_integer[i]));
break;
case PROPERTY_TYPE_DIMENSION:
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewStringObj(
DBWPrintValue(proprec->prop_value.prop_integer[i],
w, ((i % 2) == 0) ? TRUE : FALSE), -1));
break;
case PROPERTY_TYPE_DOUBLE:
for (i = 0; i < proprec->prop_len; i++)
Tcl_ListObjAppendElement(magicinterp, lobj,
Tcl_NewWideIntObj(proprec->prop_value.prop_double[i]));
break;
}
else
{
keyvalue = (char *)mallocMagic(strlen(name) + strlen((const char *)value) + 2);
sprintf(keyvalue, "%s %s", name, (const char *)value);
}
Tcl_AppendElement(magicinterp, keyvalue);
freeMagic(keyvalue);
Tcl_ListObjAppendElement(magicinterp, tobj, lobj);
Tcl_SetObjResult(magicinterp, tobj);
#else
TxPrintf("%s = %s\n", name, (const char *)value);
switch (proprec->prop_type)
{
case PROPERTY_TYPE_STRING:
TxPrintf("%s = %s\n", name, (const char *)proprec->prop_string);
break;
case PROPERTY_TYPE_INTEGER:
TxPrintf("%s = ", name);
for (i = 0; i < proprec->prop_len; i++)
TxPrintf("%d ", proprec->prop_integer[i]);
TxPrintf("\n");
break;
case PROPERTY_TYPE_DIMENSION:
TxPrintf("%s = ", name);
for (i = 0; i < proprec->prop_len; i++)
TxPrintf("%s ", DBWPrintValue(proprec->prop_value.prop_integer[i],
w, ((i % 2) == 0) ? TRUE : FALSE);
TxPrintf("\n");
break;
case PROPERTY_TYPE_DOUBLE:
TxPrintf("%s = ", name);
for (i = 0; i < proprec->prop_len; i++)
TxPrintf("%"DLONG_PREFIX"d ", proprec->prop_double[i]);
TxPrintf("\n");
break;
}
#endif
return 0; /* keep the search alive */

View File

@ -72,7 +72,7 @@ extern int cmdParseCoord(MagWindow *w, char *arg, bool is_relative, bool is_x);
extern void cmdSaveCell(CellDef *cellDef, char *newName, bool noninteractive, bool tryRename);
extern void CmdInit(void);
extern void CmdDoProperty(CellDef *def, TxCommand *cmd, int argstart);
extern void CmdDoProperty(CellDef *def, MagWindow *w, TxCommand *cmd, int argstart);
extern void CmdPaintEraseButton(MagWindow *w, Point *refPoint, bool isPaint, bool isScreen);
#endif /* _MAGIC__COMMANDS__COMMANDS_H */

View File

@ -380,17 +380,18 @@ struct propUseDefStruct {
*/
int
dbCopyMaskHintsFunc(key, value, puds)
dbCopyMaskHintsFunc(key, proprec, puds)
char *key;
ClientData value;
PropertyRecord *proprec;
struct propUseDefStruct *puds;
{
CellDef *dest = puds->puds_dest;
Transform *trans = puds->puds_trans;
char *propstr = (char *)value;
PropertyRecord *parentproprec, *newproprec;
char *parentprop, *newvalue, *vptr;
Rect r, rnew;
bool propfound;
int i;
if (!strncmp(key, "MASKHINTS_", 10))
{
@ -398,43 +399,48 @@ dbCopyMaskHintsFunc(key, value, puds)
int lastlen;
/* Append to existing mask hint (if any) */
parentprop = (char *)DBPropGet(dest, key, &propfound);
newvalue = (propfound) ? StrDup((char **)NULL, parentprop) : (char *)NULL;
parentproprec = (PropertyRecord *)DBPropGet(dest, key, &propfound);
vptr = propstr;
while (*vptr != '\0')
if (propfound)
{
if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop) == 4)
{
GeoTransRect(trans, &r, &rnew);
lastval = newvalue;
lastlen = (lastval) ? strlen(lastval) : 0;
newvalue = mallocMagic(40 + lastlen);
if (lastval)
strcpy(newvalue, lastval);
else
*newvalue = '\0';
sprintf(newvalue + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
rnew.r_xbot, rnew.r_ybot, rnew.r_xtop, rnew.r_ytop);
if (lastval) freeMagic(lastval);
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
}
else break;
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(proprec->prop_len + parentproprec->prop_len - 2) *
sizeof(int));
newproprec->prop_type = PROPERTY_TYPE_DIMENSION;
newproprec->prop_len = proprec->prop_len + parentproprec->prop_len;
}
if (newvalue)
DBPropPut(dest, key, newvalue);
else
{
newproprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(proprec->prop_len - 2) * sizeof(int));
newproprec->prop_type = PROPERTY_TYPE_DIMENSION;
newproprec->prop_len = proprec->prop_len;
}
for (i = 0; i < proprec->prop_len; i += 4)
{
r.r_xbot = proprec->prop_value.prop_integer[i];
r.r_ybot = proprec->prop_value.prop_integer[i + 1];
r.r_xtop = proprec->prop_value.prop_integer[i + 2];
r.r_ytop = proprec->prop_value.prop_integer[i + 3];
GeoTransRect(trans, &r, &rnew);
newproprec->prop_value.prop_integer[i] = rnew.r_xbot;
newproprec->prop_value.prop_integer[i + 1] = rnew.r_ybot;
newproprec->prop_value.prop_integer[i + 2] = rnew.r_xtop;
newproprec->prop_value.prop_integer[i + 3] = rnew.r_ytop;
}
if (propfound)
{
/* Append the original values to the end of the list */
for (i = 0; i < parentproprec->prop_len; i++)
newproprec->prop_value.prop_integer[i + proprec->prop_len] =
parentproprec->prop_value.prop_integer[i];
}
DBPropPut(dest, key, newproprec);
}
return 0;

View File

@ -152,10 +152,9 @@ DBCellRename(cellname, newname, doforce)
if (doforce && ((celldef->cd_flags & CDVENDORGDS) == CDVENDORGDS))
{
char *chkgdsfile;
bool isReadOnly;
chkgdsfile = (char *)DBPropGet(celldef, "GDS_FILE", &isReadOnly);
DBPropGet(celldef, "GDS_FILE", &isReadOnly);
/* Note that clearing GDS_FILE will also clear CDVENDORGDS flag */
if (isReadOnly) DBPropPut(celldef, "GDS_FILE", NULL);

View File

@ -1806,84 +1806,33 @@ typedef struct _cellpropstruct {
* ----------------------------------------------------------------------------
*/
int dbScaleProp(name, value, cps)
int dbScaleProp(name, proprec, cps)
char *name;
char *value;
PropertyRecord *proprec;
CellPropStruct *cps;
{
int scalen, scaled;
char *newvalue, *vptr;
Rect r;
int i, scalen, scaled;
Point p;
if ((strlen(name) > 5) && !strncmp(name + strlen(name) - 5, "_BBOX", 5))
/* Only "dimension" type properties get scaled */
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
/* Scale numerator held in point X value, */
/* scale denominator held in point Y value */
scalen = cps->cps_point.p_x;
scaled = cps->cps_point.p_y;
for (i = 0; i < proprec->prop_len; i += 2)
{
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop) == 4)
{
/* Scale numerator held in point X value, */
/* scale denominator held in point Y value */
if ((i + 1) >= proprec->prop_len) break;
scalen = cps->cps_point.p_x;
scaled = cps->cps_point.p_y;
DBScalePoint(&r.r_ll, scalen, scaled);
DBScalePoint(&r.r_ur, scalen, scaled);
newvalue = (char *)mallocMagic(40);
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
r.r_xtop, r.r_ytop);
DBPropPut(cps->cps_def, name, newvalue);
}
p.p_x = proprec->prop_value.prop_integer[i];
p.p_y = proprec->prop_value.prop_integer[i + 1];
DBScalePoint(&p, scalen, scaled);
proprec->prop_value.prop_integer[i] = p.p_x;
proprec->prop_value.prop_integer[i + 1] = p.p_y;
}
else if (!strncmp(name, "MASKHINTS_", 10))
{
char *vptr, *lastval;
int lastlen;
newvalue = (char *)NULL;
vptr = value;
while (*vptr != '\0')
{
if (sscanf(vptr, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop) == 4)
{
/* Scale numerator held in point X value, */
/* scale denominator held in point Y value */
scalen = cps->cps_point.p_x;
scaled = cps->cps_point.p_y;
DBScalePoint(&r.r_ll, scalen, scaled);
DBScalePoint(&r.r_ur, scalen, scaled);
lastval = newvalue;
lastlen = (lastval) ? strlen(lastval) : 0;
newvalue = mallocMagic(40 + lastlen);
if (lastval)
strcpy(newvalue, lastval);
else
*newvalue = '\0';
sprintf(newvalue + lastlen, "%s%d %d %d %d", (lastval) ? " " : "",
r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
if (lastval) freeMagic(lastval);
/* Parse through the four values and check if there's more */
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
while (*vptr && !isspace(*vptr)) vptr++;
while (*vptr && isspace(*vptr)) vptr++;
}
else break;
}
if (newvalue)
DBPropPut(cps->cps_def, name, newvalue);
}
return 0; /* Keep enumerating through properties */
}
@ -1899,33 +1848,32 @@ int dbScaleProp(name, value, cps)
* ----------------------------------------------------------------------------
*/
int dbMoveProp(name, value, cps)
int dbMoveProp(name, proprec, cps)
char *name;
char *value;
PropertyRecord *proprec;
CellPropStruct *cps;
{
int origx, origy;
int i, origx, origy;
char *newvalue;
Rect r;
Point p;
if (((strlen(name) > 5) && !strncmp(name + strlen(name) - 5, "_BBOX", 5))
|| !strncmp(name, "MASKHINTS_", 10))
/* Only "dimension" type properties get scaled */
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
origx = cps->cps_point.p_x;
origy = cps->cps_point.p_y;
for (i = 0; i < proprec->prop_len; i += 2)
{
if (sscanf(value, "%d %d %d %d", &r.r_xbot, &r.r_ybot,
&r.r_xtop, &r.r_ytop) == 4)
{
origx = cps->cps_point.p_x;
origy = cps->cps_point.p_y;
if ((i + 1) >= proprec->prop_len) break;
DBMovePoint(&r.r_ll, origx, origy);
DBMovePoint(&r.r_ur, origx, origy);
newvalue = (char *)mallocMagic(40);
sprintf(newvalue, "%d %d %d %d", r.r_xbot, r.r_ybot,
r.r_xtop, r.r_ytop);
DBPropPut(cps->cps_def, name, newvalue);
}
p.p_x = proprec->prop_value.prop_integer[i];
p.p_y = proprec->prop_value.prop_integer[i + 1];
DBMovePoint(&p, origx, origy);
proprec->prop_value.prop_integer[i] = p.p_x;
proprec->prop_value.prop_integer[i + 1] = p.p_y;
}
return 0; /* Keep enumerating through properties */
}

View File

@ -2375,7 +2375,6 @@ nextLine:
return (dbFgets(line, len, f) != NULL);
}
/*
* ----------------------------------------------------------------------------
*
@ -2398,23 +2397,32 @@ nextLine:
bool
dbReadProperties(cellDef, line, len, f, scalen, scaled)
CellDef *cellDef; /* Cell whose elements are being read */
char *line; /* Line containing << elements >> */
CellDef *cellDef; /* Cell whose properties are being read */
char *line; /* Line containing << properties >> */
int len; /* Size of buffer pointed to by line */
FILETYPE f; /* Input file */
int scalen; /* Scale up by this factor */
int scaled; /* Scale down by this factor */
{
char propertyname[128], propertyvalue[2049], *storedvalue;
char *pvalueptr;
int ntok;
char propertytype[32], propertyname[128], propertyvalue[2049];
PropertyRecord *proprec;
char *storedvalue, *pvalueptr;
int ntok, option, proplen;
unsigned int noeditflag;
char *pptr;
int numvals, ival;
dlong dval;
/* These type indexes must align with the property codes in database.h.in */
static const char * const propType[] = {
"string", "integer", "dimension", "double", 0
};
/* Save CDNOEDIT flag if set, and clear it */
noeditflag = cellDef->cd_flags & CDNOEDIT;
cellDef->cd_flags &= ~CDNOEDIT;
/* Get first element line */
/* Get first property line */
line[len - 1] = 'X';
if (dbFgets(line, len, f) == NULL) return (FALSE);
@ -2428,139 +2436,102 @@ dbReadProperties(cellDef, line, len, f, scalen, scaled)
return (TRUE);
}
/* Stop when at end of properties section (currently, only "string"
* is defined)
*/
if (line[0] != 's') break;
/* Tokenize the input line */
ntok = sscanf(line, "%31s %127s %2048[^\n]",
propertytype, propertyname, propertyvalue);
/*
* Properties may only be "string", for now. This may be the only
* property type ever needed. Handle possible string buffer
* overflows.
*/
if (line[0] == 's')
if (ntok > 0)
{
pvalueptr = &propertyvalue[0];
option = Lookup(propertytype, propType);
if ((ntok = sscanf(line, "string %127s %2048[^\n]",
propertyname, propertyvalue)) != 2)
/* Stop when at end of properties section */
if (option < 0) break;
}
if (ntok != 3)
{
TxError("Skipping bad property line: %s", line);
goto nextproperty;
}
/* Read the string value from the file, accounting for overflow */
pvalueptr = &propertyvalue[0];
/* Handle string overflows in property values */
if (line[len - 1] == '\0')
{
int pvlen = strlen(pvalueptr);
*(pvalueptr + pvlen - 1) = '\0';
while (*(pvalueptr + pvlen - 1) == '\0')
{
TxError("Skipping bad property line: %s", line);
goto nextproperty;
}
char *newpvalue;
/* Handle string overflows in property values */
if (line[len - 1] == '\0')
{
int pvlen = strlen(pvalueptr);
*(pvalueptr + pvlen - 1) = '\0';
while (*(pvalueptr + pvlen - 1) == '\0')
pvlen += 2048;
newpvalue = (char *)mallocMagic(pvlen);
strcpy(newpvalue, pvalueptr);
if (pvalueptr != &propertyvalue[0])
freeMagic(pvalueptr);
pvalueptr = newpvalue;
*(pvalueptr + pvlen - 1) = 'X';
if (dbFgets(newpvalue + pvlen - 2048, 2048, f) == NULL)
{
char *newpvalue;
pvlen += 2048;
newpvalue = (char *)mallocMagic(pvlen);
strcpy(newpvalue, pvalueptr);
if (pvalueptr != &propertyvalue[0])
freeMagic(pvalueptr);
pvalueptr = newpvalue;
*(pvalueptr + pvlen - 1) = 'X';
if (dbFgets(newpvalue + pvlen - 2048, 2048, f) == NULL)
{
freeMagic(pvalueptr);
cellDef->cd_flags |= noeditflag;
return (TRUE);
}
/* Oops, hit end-of-file in the middle of a property */
freeMagic(pvalueptr);
cellDef->cd_flags |= noeditflag;
return (TRUE);
}
}
/* Go ahead and process the vendor GDS property */
if (!strcmp(propertyname, "GDS_FILE"))
cellDef->cd_flags |= CDVENDORGDS;
/* "pvalueptr" now points to a string containing the complete
* property value.
*/
}
/* Also process FIXED_BBOX property, as units must match, */
/* and ditto for MASKHINTS_*. */
/* Handle properties by type. Property types are:
* (1) "string" (the default)
* (2) "integer" (a fixed integer or list of integers)
* (3) "dimension" (an integer that scales with internal units)
* (4) "double" (a fixed double-wide integer or list thereof)
*/
if (!strcmp(propertyname, "FIXED_BBOX"))
{
Rect locbbox;
switch (option)
{
case PROPERTY_TYPE_STRING:
/* Go ahead and process the vendor GDS property */
if (!strcmp(propertyname, "GDS_FILE"))
cellDef->cd_flags |= CDVENDORGDS;
if (sscanf(pvalueptr, "%d %d %d %d",
&(locbbox.r_xbot),
&(locbbox.r_ybot),
&(locbbox.r_xtop),
&(locbbox.r_ytop)) != 4)
/* Also process FIXED_BBOX property, as units must */
/* match, and ditto for MASKHINTS_*. This is */
/* backwards-compatibility handling for files that have */
/* either property as a string. The property is best */
/* handled as a dimension to avoid parsing the string */
/* value every time the coordinates are needed. */
if (!strcmp(propertyname, "FIXED_BBOX"))
{
TxError("Cannot read bounding box values in %s property",
propertyname);
storedvalue = StrDup((char **)NULL, pvalueptr);
(void) DBPropPut(cellDef, propertyname, storedvalue);
}
else
{
if (scalen > 1)
{
locbbox.r_xbot *= scalen;
locbbox.r_ybot *= scalen;
locbbox.r_xtop *= scalen;
locbbox.r_ytop *= scalen;
}
if (scaled > 1)
{
locbbox.r_xbot /= scaled;
locbbox.r_ybot /= scaled;
locbbox.r_xtop /= scaled;
locbbox.r_ytop /= scaled;
}
cellDef->cd_flags |= CDFIXEDBBOX;
storedvalue = (char *)mallocMagic(40);
sprintf(storedvalue, "%d %d %d %d",
locbbox.r_xbot, locbbox.r_ybot,
locbbox.r_xtop, locbbox.r_ytop);
(void) DBPropPut(cellDef, propertyname, storedvalue);
}
}
else if (!strncmp(propertyname, "MASKHINTS_", 10))
{
Rect locbbox;
char *pptr = pvalueptr;
int numvals, numrects = 0, slen, n;
Rect locbbox;
while (*pptr != '\0')
{
numvals = sscanf(pptr, "%d %d %d %d",
if (sscanf(pvalueptr, "%d %d %d %d",
&(locbbox.r_xbot),
&(locbbox.r_ybot),
&(locbbox.r_xtop),
&(locbbox.r_ytop));
if (numvals <= 0)
break;
else if (numvals != 4)
&(locbbox.r_ytop)) != 4)
{
TxError("Cannot read bounding box values in %s property",
propertyname);
/* Unable to parse correctly. Save as a string value */
proplen = strlen(pvalueptr);
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) - 7 + proplen);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = proplen;
strcpy(proprec->prop_value.prop_string, pvalueptr);
(void) DBPropPut(cellDef, propertyname, proprec);
break;
}
else
{
if (numrects == 0)
{
storedvalue = (char *)mallocMagic(40);
*storedvalue = '\0';
slen = -1;
}
else
{
char *newvalue;
slen = strlen(storedvalue);
newvalue = (char *)mallocMagic(40 + slen);
sprintf(newvalue, "%s ", storedvalue);
freeMagic(storedvalue);
storedvalue = newvalue;
}
numrects++;
if (scalen > 1)
{
locbbox.r_xbot *= scalen;
@ -2575,27 +2546,308 @@ dbReadProperties(cellDef, line, len, f, scalen, scaled)
locbbox.r_xtop /= scaled;
locbbox.r_ytop /= scaled;
}
sprintf(storedvalue + slen + 1, "%d %d %d %d",
locbbox.r_xbot, locbbox.r_ybot,
locbbox.r_xtop, locbbox.r_ytop);
cellDef->cd_flags |= CDFIXEDBBOX;
/* Skip forward four values in pvalueptr */
for (n = 0; n < 4; n++)
{
while ((*pptr != '\0') && !isspace(*pptr)) pptr++;
while ((*pptr != '\0') && isspace(*pptr)) pptr++;
}
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) + 2 * sizeof(int));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = 4;
proprec->prop_value.prop_integer[0] = locbbox.r_xbot;
proprec->prop_value.prop_integer[1] = locbbox.r_ybot;
proprec->prop_value.prop_integer[2] = locbbox.r_xtop;
proprec->prop_value.prop_integer[3] = locbbox.r_ytop;
(void) DBPropPut(cellDef, propertyname, proprec);
}
}
(void) DBPropPut(cellDef, propertyname, storedvalue);
}
else
{
storedvalue = StrDup((char **)NULL, pvalueptr);
(void) DBPropPut(cellDef, propertyname, storedvalue);
}
if (pvalueptr != &propertyvalue[0])
freeMagic(pvalueptr);
else if (!strncmp(propertyname, "MASKHINTS_", 10))
{
pptr = pvalueptr;
/* Do one pass through the string to count the number of
* values and make sure they all parse as integers.
*/
numvals = 0;
while (*pptr != '\0')
{
while (isspace(*pptr) && (*pptr != '\0')) pptr++;
if (!isspace(*pptr))
{
char *endptr;
long result;
/* Check that the value is an integer */
result = strtol(pptr, &endptr, 0);
if (endptr == pptr)
{
/* Unable to parse correctly. Save as a string value */
proplen = strlen(pvalueptr);
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) - 7 + proplen);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = proplen;
strcpy(proprec->prop_value.prop_string, pvalueptr);
(void) DBPropPut(cellDef, propertyname, proprec);
break;
}
while (!isspace(*pptr) && (*pptr != '\0')) pptr++;
numvals++;
}
}
if (numvals % 4 != 0)
{
TxError("Cannot read bounding box values in %s property",
propertyname);
/* This does not need to be a fatal error. Extra
* values will be unused.
*/
}
pptr = pvalueptr;
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) + ((numvals - 2) * sizeof(int)));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = numvals;
/* Do a second pass through the string to convert the values
* to dimensions and save as an integer array.
*/
numvals = 0;
while (*pptr != '\0')
{
while (isspace(*pptr) && (*pptr != '\0')) pptr++;
if (!isspace(*pptr))
{
sscanf(pptr, "%d", &ival);
if (scalen > 1) ival *= scalen;
if (scaled > 1) ival /= scaled;
proprec->prop_value.prop_integer[numvals] = ival;
while (!isspace(*pptr) && (*pptr != '\0')) pptr++;
numvals++;
}
}
(void) DBPropPut(cellDef, propertyname, proprec);
}
else if ((!strncmp(propertyname, "GDS_START", 9)) ||
(!strncmp(propertyname, "GDS_BEGIN", 9)) ||
(!strncmp(propertyname, "GDS_END", 7)))
{
if (sscanf(pvalueptr, "%"DLONG_PREFIX"d", &dval) == 1)
{
TxError("Cannot read file offset value in %s property",
propertyname);
/* Unable to parse correctly. Save as a string value */
proplen = strlen(pvalueptr);
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) - 7 + proplen);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = proplen;
strcpy(proprec->prop_value.prop_string, pvalueptr);
(void) DBPropPut(cellDef, propertyname, proprec);
break;
}
else
{
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
proprec->prop_type = PROPERTY_TYPE_DOUBLE;
proprec->prop_len = 1;
proprec->prop_value.prop_double[0] = dval;
(void) DBPropPut(cellDef, propertyname, proprec);
}
}
else
{
proplen = strlen(pvalueptr);
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) - 7 + proplen);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = proplen;
strcpy(proprec->prop_value.prop_string, pvalueptr);
(void) DBPropPut(cellDef, propertyname, proprec);
}
if (pvalueptr != &propertyvalue[0])
freeMagic(pvalueptr);
break;
case PROPERTY_TYPE_INTEGER:
pptr = pvalueptr;
/* Do one pass through the string to count the number of
* values and make sure they all parse as integers.
*/
numvals = 0;
while (*pptr != '\0')
{
while (isspace(*pptr) && (*pptr != '\0')) pptr++;
if (!isspace(*pptr))
{
char *endptr;
long result;
/* Check that the value is an integer */
result = strtol(pptr, &endptr, 0);
if (endptr == pptr)
{
/* Unable to parse correctly. Save as a string value */
proplen = strlen(pvalueptr);
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) - 7 + proplen);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = proplen;
strcpy(proprec->prop_value.prop_string, pvalueptr);
(void) DBPropPut(cellDef, propertyname, proprec);
break;
}
while (!isspace(*pptr) && (*pptr != '\0')) pptr++;
numvals++;
}
}
pptr = pvalueptr;
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) + ((numvals - 2) * sizeof(int)));
proprec->prop_type = PROPERTY_TYPE_INTEGER;
proprec->prop_len = numvals;
/* Do a second pass through the string to convert the values
* to dimensions and save as an integer array.
*/
numvals = 0;
while (*pptr != '\0')
{
while (isspace(*pptr) && (*pptr != '\0')) pptr++;
if (!isspace(*pptr))
{
sscanf(pptr, "%d", &ival);
proprec->prop_value.prop_integer[numvals] = ival;
while (!isspace(*pptr) && (*pptr != '\0')) pptr++;
numvals++;
}
}
(void) DBPropPut(cellDef, propertyname, proprec);
break;
case PROPERTY_TYPE_DOUBLE:
pptr = pvalueptr;
/* Do one pass through the string to count the number of
* values and make sure they all parse as integers.
*/
numvals = 0;
while (*pptr != '\0')
{
while (isspace(*pptr) && (*pptr != '\0')) pptr++;
if (!isspace(*pptr))
{
char *endptr;
dlong result;
/* Check that the value is an integer */
result = strtoll(pptr, &endptr, 0);
if (endptr == pptr)
{
/* Unable to parse correctly. Save as a string value */
proplen = strlen(pvalueptr);
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) - 7 + proplen);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = proplen;
strcpy(proprec->prop_value.prop_string, pvalueptr);
(void) DBPropPut(cellDef, propertyname, proprec);
break;
}
while (!isspace(*pptr) && (*pptr != '\0')) pptr++;
numvals++;
}
}
pptr = pvalueptr;
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) + ((numvals - 1) * sizeof(dlong)));
proprec->prop_type = PROPERTY_TYPE_DOUBLE;
proprec->prop_len = numvals;
/* Do a second pass through the string to convert the values
* to dimensions and save as an integer array.
*/
numvals = 0;
while (*pptr != '\0')
{
while (isspace(*pptr) && (*pptr != '\0')) pptr++;
if (!isspace(*pptr))
{
sscanf(pptr, "%"DLONG_PREFIX"d", &dval);
proprec->prop_value.prop_double[numvals] = dval;
while (!isspace(*pptr) && (*pptr != '\0')) pptr++;
numvals++;
}
}
(void) DBPropPut(cellDef, propertyname, proprec);
break;
case PROPERTY_TYPE_DIMENSION:
pptr = pvalueptr;
/* Do one pass through the string to count the number of
* values and make sure they all parse as integers.
*/
numvals = 0;
while (*pptr != '\0')
{
while (isspace(*pptr) && (*pptr != '\0')) pptr++;
if (!isspace(*pptr))
{
char *endptr;
long result;
/* Check that the value is an integer */
result = strtol(pptr, &endptr, 0);
if (endptr == pptr)
{
/* Unable to parse correctly. Save as a string value */
proplen = strlen(pvalueptr);
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) - 7 + proplen);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = proplen;
strcpy(proprec->prop_value.prop_string, pvalueptr);
(void) DBPropPut(cellDef, propertyname, proprec);
break;
}
while (!isspace(*pptr) && (*pptr != '\0')) pptr++;
numvals++;
}
}
pptr = pvalueptr;
proprec = (PropertyRecord *)mallocMagic(
sizeof(PropertyRecord) + ((numvals - 2) * sizeof(int)));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = numvals;
/* Do a second pass through the string to convert the values
* to dimensions and save as an integer array.
*/
numvals = 0;
while (*pptr != '\0')
{
while (isspace(*pptr) && (*pptr != '\0')) pptr++;
if (!isspace(*pptr))
{
sscanf(pptr, "%d", &ival);
if (scalen > 1) ival *= scalen;
if (scaled > 1) ival /= scaled;
proprec->prop_value.prop_integer[numvals] = ival;
while (!isspace(*pptr) && (*pptr != '\0')) pptr++;
numvals++;
}
}
(void) DBPropPut(cellDef, propertyname, proprec);
break;
}
nextproperty:
@ -3290,68 +3542,23 @@ dbFindCellGCFFunc(cellUse, ggcf)
}
int
dbFindPropGCFFunc(key, value, ggcf)
dbFindPropGCFFunc(key, proprec, ggcf)
char *key;
ClientData value;
PropertyRecord *proprec;
int *ggcf; /* Client data */
{
Rect bbox;
char *vptr = value, *sptr;
int numvals, n;
int value, n;
if (!strcmp(key, "FIXED_BBOX"))
{
if (sscanf(value, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
{
/* Check bounding box */
if (bbox.r_xtop % (*ggcf) != 0)
*ggcf = FindGCF(bbox.r_xtop, *ggcf);
if (bbox.r_xbot % (*ggcf) != 0)
*ggcf = FindGCF(bbox.r_xbot, *ggcf);
if (bbox.r_ytop % (*ggcf) != 0)
*ggcf = FindGCF(bbox.r_ytop, *ggcf);
if (bbox.r_ybot % (*ggcf) != 0)
*ggcf = FindGCF(bbox.r_ybot, *ggcf);
}
else
TxError("Error: Cannot parse FIXED_BBOX property value!\n");
}
else if (!strncmp(key, "MASKHINTS_", 10))
{
while (TRUE)
{
numvals = sscanf(vptr, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop);
if (numvals <= 0)
break;
else if (numvals != 4)
{
TxError("Error: Cannot parse %s property value at \"%s\"!\n",
key, vptr);
break;
}
else
{
/* Check bounding box */
if (bbox.r_xtop % (*ggcf) != 0)
*ggcf = FindGCF(bbox.r_xtop, *ggcf);
if (bbox.r_xbot % (*ggcf) != 0)
*ggcf = FindGCF(bbox.r_xbot, *ggcf);
if (bbox.r_ytop % (*ggcf) != 0)
*ggcf = FindGCF(bbox.r_ytop, *ggcf);
if (bbox.r_ybot % (*ggcf) != 0)
*ggcf = FindGCF(bbox.r_ybot, *ggcf);
}
/* Only PROPERTY_TYPE_DIMENSION properties get handled */
if (proprec->prop_type != PROPERTY_TYPE_DIMENSION) return 0;
/* Skip forward four values in value */
for (n = 0; n < 4; n++)
{
while (!isspace(*vptr) && (*vptr != '\0')) vptr++;
while (isspace(*vptr) && (*vptr != '\0')) vptr++;
}
}
for (n = 0; n < proprec->prop_len; n++)
{
value = proprec->prop_value.prop_integer[n];
if (value % (*ggcf) != 0)
*ggcf = FindGCF(value, *ggcf);
}
return (*ggcf == 1) ? 1 : 0;
}
@ -3443,7 +3650,7 @@ dbCountUseFunc(cellUse, count)
struct keyValuePair {
char *key;
char *value;
PropertyRecord *value;
};
/*
@ -3493,15 +3700,15 @@ struct cellPropList {
*/
int
dbGetPropFunc(key, value, propRec)
dbGetPropFunc(key, proprec, propRec)
char *key;
ClientData value;
PropertyRecord *proprec;
struct cellPropList *propRec;
{
propRec->keyValueList[propRec->idx] =
(struct keyValuePair *)mallocMagic(sizeof(struct keyValuePair));
propRec->keyValueList[propRec->idx]->key = key;
propRec->keyValueList[propRec->idx]->value = (char *)value;
propRec->keyValueList[propRec->idx]->value = proprec;
propRec->idx++;
return 0;
@ -3522,9 +3729,9 @@ dbGetPropFunc(key, value, propRec)
*/
int
dbCountPropFunc(key, value, count)
dbCountPropFunc(key, proprec, count)
char *key;
ClientData value;
PropertyRecord *proprec;
int *count; /* Client data */
{
(*count)++;
@ -3868,120 +4075,70 @@ ioerror:
* Side effects:
* Writes to the disk file.
*
* Warnings:
* This function assumes that all property values are strings!
* This is currently true; if it changes in the future, this
* function will have to check each property against a list of
* expected property strings and output the value based on the
* known format of what it points to.
*
* Also, this function assumes that properties FIXED_BBOX and
* MASKHINTS_* are in internal units, and converts them by
* dividing by the reducer value passed in cdata. No other
* properties are altered.
*
* ----------------------------------------------------------------------------
*/
int
dbWritePropFunc(key, value, cdata)
dbWritePropFunc(key, proprec, cdata)
char *key;
char *value;
PropertyRecord *proprec;
ClientData cdata;
{
pwfrec *pwf = (pwfrec *)cdata;
FILE *f = pwf->pwf_file;
int reducer = pwf->pwf_reducer;
char *newvalue = value;
int i;
char newvalue[20];
/* NOTE: FIXED_BBOX is treated specially; values are database */
/* values and should be divided by reducer. Easiest to do it */
/* here and revert values after. Ditto for MASKHINTS_*. */
if (!strcmp(key, "FIXED_BBOX"))
switch (proprec->prop_type)
{
Rect scalebox, bbox;
if (sscanf(value, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
{
scalebox.r_xbot = bbox.r_xbot / reducer;
scalebox.r_xtop = bbox.r_xtop / reducer;
scalebox.r_ybot = bbox.r_ybot / reducer;
scalebox.r_ytop = bbox.r_ytop / reducer;
newvalue = mallocMagic(strlen(value) + 5);
sprintf(newvalue, "%d %d %d %d",
scalebox.r_xbot, scalebox.r_ybot,
scalebox.r_xtop, scalebox.r_ytop);
}
else
TxError("Error: Cannot parse FIXED_BBOX property value!\n");
case PROPERTY_TYPE_STRING:
FPUTSR(f, "string ");
break;
case PROPERTY_TYPE_INTEGER:
FPUTSR(f, "integer ");
break;
case PROPERTY_TYPE_DIMENSION:
FPUTSR(f, "dimension ");
break;
case PROPERTY_TYPE_DOUBLE:
FPUTSR(f, "double ");
break;
}
else if (!strncmp(key, "MASKHINTS_", 10))
{
Rect scalebox, bbox;
char *vptr = value, *sptr;
int numvals, numrects = 0, n;
while (TRUE)
{
numvals = sscanf(vptr, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop);
if (numvals <= 0)
break;
else if (numvals != 4)
{
TxError("Error: Cannot parse %s property value!\n", key);
/* Revert property value to original string */
if (newvalue != value) freeMagic(newvalue);
newvalue = value;
break;
}
else
{
scalebox.r_xbot = bbox.r_xbot / reducer;
scalebox.r_xtop = bbox.r_xtop / reducer;
scalebox.r_ybot = bbox.r_ybot / reducer;
scalebox.r_ytop = bbox.r_ytop / reducer;
if (numrects == 0)
{
newvalue = mallocMagic(40);
sptr = newvalue;
}
else
{
char *tempvalue;
tempvalue = mallocMagic(strlen(newvalue) + 40);
sprintf(tempvalue, "%s ", newvalue);
sptr = tempvalue + strlen(newvalue) + 1;
freeMagic(newvalue);
newvalue = tempvalue;
}
sprintf(sptr, "%d %d %d %d",
scalebox.r_xbot, scalebox.r_ybot,
scalebox.r_xtop, scalebox.r_ytop);
numrects++;
}
/* Skip forward four values in value */
for (n = 0; n < 4; n++)
{
while (!isspace(*vptr)) vptr++;
while (isspace(*vptr) && (*vptr != '\0')) vptr++;
}
}
}
FPUTSR(f, "string ");
FPUTSR(f, key);
FPUTSR(f, " ");
FPUTSR(f, newvalue);
switch (proprec->prop_type)
{
case PROPERTY_TYPE_STRING:
FPUTSR(f, proprec->prop_value.prop_string);
break;
case PROPERTY_TYPE_INTEGER:
for (i = 0; i < proprec->prop_len; i++)
{
snprintf(newvalue, 20, " %d", proprec->prop_value.prop_integer[i]);
FPUTSR(f, newvalue);
}
break;
case PROPERTY_TYPE_DIMENSION:
/* Dimensions scale by the reducer */
for (i = 0; i < proprec->prop_len; i++)
{
snprintf(newvalue, 20, " %d", proprec->prop_value.prop_integer[i]
/ reducer);
FPUTSR(f, newvalue);
}
break;
case PROPERTY_TYPE_DOUBLE:
for (i = 0; i < proprec->prop_len; i++)
{
snprintf(newvalue, 20, " %"DLONG_PREFIX"d",
proprec->prop_value.prop_double[i]);
FPUTSR(f, newvalue);
}
break;
}
FPUTSR(f, "\n");
if (newvalue != value) freeMagic(newvalue);
return 0;
}
@ -4311,32 +4468,62 @@ dbWriteUseCommandsFunc(cellUse, cdarg)
*/
int
dbWritePropCommandsFunc(key, value, cdarg)
dbWritePropCommandsFunc(key, proprec, cdarg)
char *key;
char *value;
PropertyRecord *proprec;
ClientData cdarg;
{
struct writeArg *arg = (struct writeArg *) cdarg;
char *escstr, *p, *v;
int vallen;
char *escstr, *p, *v, *value;
int i, vallen;
FILE *f = arg->wa_file;
MagWindow *w;
/* Probably need to escape more than just quotes here. */
vallen = strlen(value) + 1;
for (v = value; *v != '\0'; v++)
if (*v == '"') vallen++;
escstr = (char *)mallocMagic(vallen);
p = escstr;
for (v = value; *v != '\0'; v++)
switch (proprec->prop_type)
{
if (*v == '"')
*p++ = '\\';
*p++ = *v;
case PROPERTY_TYPE_STRING:
/* Probably need to escape more than just quotes here. */
value = proprec->prop_value.prop_string;
vallen = strlen(value) + 1;
for (v = value; *v != '\0'; v++)
if (*v == '"') vallen++;
escstr = (char *)mallocMagic(vallen);
p = escstr;
for (v = value; *v != '\0'; v++)
{
if (*v == '"')
*p++ = '\\';
*p++ = *v;
}
*p = '\0';
fprintf(f, "property string %s \"%s\"\n", key, escstr);
freeMagic(escstr);
break;
case PROPERTY_TYPE_INTEGER:
fprintf(f, "property integer ");
for (i = 0; i < proprec->prop_len; i++)
fprintf(f, "%d ", proprec->prop_value.prop_integer[i]);
fprintf(f, "\n");
break;
case PROPERTY_TYPE_DIMENSION:
windCheckOnlyWindow(&w, DBWclientID);
fprintf(f, "property dimension ");
for (i = 0; i < proprec->prop_len; i++)
fprintf(f, "%d ", DBWPrintValue(proprec->prop_value.prop_integer[i],
w, ((i % 2) == 0) ? TRUE : FALSE));
fprintf(f, "\n");
break;
case PROPERTY_TYPE_DOUBLE:
fprintf(f, "property double ");
for (i = 0; i < proprec->prop_len; i++)
fprintf(f, "%"DLONG_PREFIX"d ", proprec->prop_value.prop_double[i]);
fprintf(f, "\n");
break;
}
*p = '\0';
fprintf(f, "property %s \"%s\"\n", key, escstr);
freeMagic(escstr);
return 0;
}

View File

@ -47,16 +47,16 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
void
DBPropPut(cellDef, name, value)
CellDef *cellDef; /* Pointer to definition of cell. */
char *name; /* The name of the property desired. */
ClientData value; /* MUST point to a malloc'ed structure, or NULL.
* This will be freed when the CellDef is freed.
*/
CellDef *cellDef; /* Pointer to definition of cell. */
char *name; /* The name of the property desired. */
PropertyRecord *value; /* MUST point to a malloc'ed structure, or NULL.
* This will be freed when the CellDef is freed.
*/
{
HashTable *htab;
HashEntry *entry;
char *oldvalue;
PropertyRecord *oldvalue;
/* Honor the NOEDIT flag. Note that the caller always assumes that */
/* the value would be saved in the hash table, so if it is not */
@ -95,12 +95,12 @@ DBPropPut(cellDef, name, value)
}
entry = HashFind(htab, name);
oldvalue = (char *)HashGetValue(entry);
if (oldvalue != NULL) freeMagic(oldvalue);
if (value == (ClientData)NULL)
oldvalue = (PropertyRecord *)HashGetValue(entry);
if (oldvalue != NULL) freeMagic((char *)oldvalue);
if (value == (PropertyRecord *)NULL)
HashRemove(htab, name);
else
HashSetValue(entry, value);
HashSetValue(entry, PTR2CD(value));
}
/* ----------------------------------------------------------------------------
@ -110,13 +110,13 @@ DBPropPut(cellDef, name, value)
* Get a property from a celldef.
*
* Results:
* NULL if the property didn't exist, or if the property value was NULL.
* Otherwise, ClientData that represents the property.
* NULL if the property didn't exist, or if the property record was NULL.
* Otherwise, returns a pointer to the property record.
*
* ----------------------------------------------------------------------------
*/
ClientData
PropertyRecord *
DBPropGet(cellDef, name, found)
CellDef *cellDef; /* Pointer to definition of cell. */
char *name; /* The name of the property desired. */
@ -124,12 +124,12 @@ DBPropGet(cellDef, name, found)
* exists.
*/
{
ClientData result;
PropertyRecord *result;
bool haveit;
HashTable *htab;
HashEntry *entry;
result = (ClientData) NULL;
result = (PropertyRecord *)NULL;
haveit = FALSE;
htab = (HashTable *) cellDef->cd_props;
if (htab == (HashTable *) NULL) goto done;
@ -138,7 +138,7 @@ DBPropGet(cellDef, name, found)
if (entry != NULL)
{
haveit = TRUE;
result = (ClientData) HashGetValue(entry);
result = (PropertyRecord *)HashGetValue(entry);
}
done:
@ -146,6 +146,109 @@ done:
return result;
}
/* ----------------------------------------------------------------------------
*
* DBPropGetString --
*
* Get a string property from a celldef.
*
* Results:
* NULL if the property didn't exist, or if the property record was NULL.
* Otherwise, returns a pointer to the property's string record.
*
* Notes:
* This is basically the original DBPropGet(), when properties were only
* allowed to be strings.
*
* ----------------------------------------------------------------------------
*/
char *
DBPropGetString(cellDef, name, found)
CellDef *cellDef; /* Pointer to definition of cell. */
char *name; /* The name of the property desired. */
bool *found; /* If not NULL, filled in with TRUE iff the property
* exists.
*/
{
char *result = NULL;
PropertyRecord *proprec;
bool haveit;
HashTable *htab;
HashEntry *entry;
haveit = FALSE;
htab = (HashTable *) cellDef->cd_props;
if (htab == (HashTable *) NULL) goto pdone;
entry = HashLookOnly(htab, name);
if (entry != NULL)
{
proprec = (PropertyRecord *)HashGetValue(entry);
if (proprec->prop_type == PROPERTY_TYPE_STRING)
{
haveit = TRUE;
result = proprec->prop_value.prop_string;
}
}
pdone:
if (found != (bool *) NULL) *found = haveit;
return result;
}
/* ----------------------------------------------------------------------------
*
* DBPropGetDouble --
*
* Get a single double-long integer property from a celldef.
*
* Results:
* NULL if the property didn't exist, or if the property record was NULL.
* Otherwise, returns a pointer to the property's value record.
*
* ----------------------------------------------------------------------------
*/
dlong
DBPropGetDouble(cellDef, name, found)
CellDef *cellDef; /* Pointer to definition of cell. */
char *name; /* The name of the property desired. */
bool *found; /* If not NULL, filled in with TRUE iff the property
* exists.
*/
{
dlong result = 0;
PropertyRecord *proprec;
bool haveit;
HashTable *htab;
HashEntry *entry;
haveit = FALSE;
htab = (HashTable *) cellDef->cd_props;
if (htab == (HashTable *) NULL) goto ddone;
entry = HashLookOnly(htab, name);
if (entry != NULL)
{
proprec = (PropertyRecord *)HashGetValue(entry);
if (proprec->prop_type == PROPERTY_TYPE_DOUBLE)
{
haveit = TRUE;
result = proprec->prop_value.prop_double[0];
}
else if (proprec->prop_type == PROPERTY_TYPE_STRING)
{
haveit = TRUE;
sscanf(proprec->prop_value.prop_string, "%"DLONG_PREFIX"d", &result);
}
}
ddone:
if (found != (bool *) NULL) *found = haveit;
return result;
}
/* ----------------------------------------------------------------------------
*
* DBPropEnum --
@ -168,7 +271,7 @@ DBPropEnum(cellDef, func, cdata)
*
* int foo(name, value, cdata)
* char *name;
* ClientData value;
* PropertyRecord *value;
* ClientData cdata;
* {
* -- return 0 to continue,
@ -189,7 +292,7 @@ DBPropEnum(cellDef, func, cdata)
HashStartSearch(&hs);
while ((entry = HashNext(htab, &hs)) != NULL)
{
res = (*func)(entry->h_key.h_name, (ClientData) entry->h_pointer, cdata);
res = (*func)(entry->h_key.h_name, (PropertyRecord *)entry->h_pointer, cdata);
if (res != 0) return res;
}

View File

@ -704,6 +704,24 @@ struct conSrArg2
#define CSA2_LIST_SIZE 65536 /* Number of entries per list */
/* ------------------------ Properties ------------------------------ */
/* Note that the property record is a single allocated block large enough
* to hold the string or integer list, and can be freed as a single block.
* The array bounds, like those of lab_text for labels, are placeholders.
*/
typedef struct
{
int prop_type; /* See codes below; e.g., PROPERTY_TYPE_STRING */
int prop_len; /* String length or number of values */
union {
char prop_string[8]; /* For PROPERTY_TYPE_STRING */
int prop_integer[2]; /* For PROPERTY_TYPE_INTEGER or _DIMENSION */
dlong prop_double[1]; /* For PROPERTY_TYPE_DOUBLE */
} prop_value;
} PropertyRecord;
/* -------------- Undo information passed to DBPaintPlane ------------- */
typedef struct
@ -736,6 +754,13 @@ typedef struct
#define PAINT_MARK 1 /* Mark tiles that are painted */
#define PAINT_XOR 2 /* Use with XOR function to prevent double-painting */
/* ---------------------- Codes for properties -------------------------*/
#define PROPERTY_TYPE_STRING 0 /* ASCII string property */
#define PROPERTY_TYPE_INTEGER 1 /* Fixed integer property */
#define PROPERTY_TYPE_DIMENSION 2 /* Integer property that scales with units */
#define PROPERTY_TYPE_DOUBLE 3 /* Double-long integer (for file positions) */
/* -------------------- Exported procedure headers -------------------- */
/* Painting/erasing */
@ -921,7 +946,9 @@ extern void DBFreePaintPlane();
/* Cell properties */
extern void DBPropPut();
extern ClientData DBPropGet();
extern PropertyRecord *DBPropGet();
extern char *DBPropGetString();
extern dlong DBPropGetDouble();
extern int DBPropEnum();
extern void DBPropClearAll();

View File

@ -25,9 +25,11 @@ Attach a "property" (string key and value pair) to the edit cell
<H3>Usage:</H3>
<BLOCKQUOTE>
<B>property</B> [<I>key</I> [<I>value</I>]] <BR><BR>
<B>property</B> [<I>type</I>] [<I>key</I> [<I>value</I>]] <BR><BR>
<BLOCKQUOTE>
where <I>key</I> and <I>value</I> are any text strings.
where <I>key</I> and <I>value</I> are any text strings. <BR>
<I>type</I> may be one of <B>string</B>, <B>integer</B>,
<B>dimension</B>, or <B>double</B>.
</BLOCKQUOTE>
</BLOCKQUOTE>
@ -45,11 +47,48 @@ Attach a "property" (string key and value pair) to the edit cell
with the key is returned. With both arguments, the string
<I>value</I> is associated with the string <I>key</I> as a
property of the cell. If <I>key</I> is an existing key, then
its original value will be overwritten.
its original value will be overwritten. <P>
By default, properties are interpreted as verbatim string values,
with exceptions for the reserved types (see below). To force the
values of the property to be interpreted as a specific type, use
the <I>type</I> option.
</BLOCKQUOTE>
<BLOCKQUOTE>
Property names reserved by and used by magic:
Types are interpreted as follows:
<DL>
<DT> <B>string</B> type:
<DD> The property value is a character string. Character strings
may contain spaces, but if so, then the string should be quoted
or in braces, per Tcl syntax.
<DT> <B>integer</I> type:
<DD> The property value is an integer value or a list of integer
values. The values are not considered to be measurements and
do not scale. Multiple values may be passed on the command
line as additional arguments, or the set of values may be
given as a list.
<DT> <B>dimension</I> type:
<DD> The property value is an integer value or a list of integer
values. The values are considered to be (linear) dimensional
measurements and therefore scale with the database internal
units. They are interpreted as having the values currently
specified for <B>units</B>, and display back in the same
units. Multiple values may be passed on the command line as
additional arguments, or the set of values may be given as a
list.
<DT> <B>double</I> type:
<DD> The property value is a double-wide (64-bit) integer value or
a list of double-wide integer values. The values are not
considered to be measurements and do not scale. Multiple
values may be passed on the command line as additional arguments,
or the set of values may be given as a list.
</DL>
</BLOCKQUOTE>
<BLOCKQUOTE>
Property names reserved by and used by magic (types are <B>string</B>
unless otherwise noted):
<DL>
<DT> <B>GDS_FILE</B>
<DD> The value is the name of a GDS file which contains the mask
@ -60,12 +99,14 @@ Attach a "property" (string key and value pair) to the edit cell
<DD> If a <B>GDS_FILE</B> is defined, then this value indicates the
byte position of the start of mask data for this cell definition
in the file. If set to value <B>0</B>, then the file will be
searched for the data bounds.
searched for the data bounds. This property is always of type
<B>double</B>.
<DT> <B>GDS_END</B>
<DD> If a <B>GDS_FILE</B> is defined, then this value indicates the
byte position of the end of mask data for this cell definition
in the file. If <B>GDS_START</B> is set to <B>0</B>, then this
property may be omitted.
property may be omitted. This property is always of type
<B>double</B>.
<DT> <B>LEFview</B>
<DD> If set to <B>TRUE</B>, this cell is an abstract view such as that
obtained from a LEF macro, and should not be used for extraction
@ -97,6 +138,8 @@ Attach a "property" (string key and value pair) to the edit cell
corresponding to the abutment box of the cell, in magic's internal
units. The abutment box is automatically read from LEF files, but
may be defined for any file and can be used for placement alignment.
This property is always of type <B>dimension</B> and must contain
exactly four values.
<DT> <B>OBS_BBOX</B>
<DD> This property value is a space-sparated list of four integer values
corresponding to a bounding box to be used when generating a LEF
@ -104,7 +147,8 @@ Attach a "property" (string key and value pair) to the edit cell
will be entirely covered in obstruction layers (unless cut-outs
are required to accommodate pins). Any set-back applied by the
"lef write -hide <value>" option will be applied to this obstruction
box.
box. This property is always of type <B>dimension</B> and must
contain exactly four values.
<DT> <B>flatten</B>
<DD> This property is used in conjunction with the "flatten -doproperty"
command option and marks the cell for flattening. Cells without
@ -146,7 +190,8 @@ Attach a "property" (string key and value pair) to the edit cell
always generate mask layer <I>type</I> in the specified rectangle
area when writing GDS or CIF output. <I>type</I> may be a templayer,
such that <I>type</I> could be defined as the absence of a mask layer,
for example.
for example. This property is always of type <B>dimension</B> and
must have a multiple of four values.
</DL>
</BLOCKQUOTE>
@ -157,6 +202,11 @@ Attach a "property" (string key and value pair) to the edit cell
the cell definition structure.
</BLOCKQUOTE>
<H3>See Also:</H3>
<BLOCKQUOTE>
<A HREF=units.html><B>units</B></A> <BR>
</BLOCKQUOTE>
<P><IMG SRC=graphics/line1.gif><P>
<TABLE BORDER=0>
<TR>

View File

@ -326,7 +326,7 @@ extBasic(def, outFile)
}
/* Check for "device", as it modifies handling of parasitics */
propptr = (char *)DBPropGet(def, "device", &propfound);
propptr = DBPropGetString(def, "device", &propfound);
if (propfound)
{
/* Remove parasitics from local nodes */
@ -1702,7 +1702,7 @@ extOutputParameters(def, transList, outFile)
* and device name, and if detected, add the type corresponding to the
* device name to the mask so it gets handled, too.
*/
propptr = DBPropGet(def, "device", &propfound);
propptr = DBPropGetString(def, "device", &propfound);
if (propfound)
{
char *devname;

View File

@ -594,7 +594,7 @@ extHeader(def, f)
/* are to be passed to instances of the cell */
/* (created by defining property "parameter") */
propvalue = (char *)DBPropGet(def, "parameter", &propfound);
propvalue = DBPropGetString(def, "parameter", &propfound);
if (propfound)
{
// Use device parameter table to store the cell def parameters,

View File

@ -1359,15 +1359,21 @@ DefReadLocation(
if (use->cu_def->cd_flags & CDFIXEDBBOX)
{
char *propval;
PropertyRecord *proprec;
bool found;
propval = (char *)DBPropGet(use->cu_def, "FIXED_BBOX", &found);
proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
if (found)
{
if (sscanf(propval, "%d %d %d %d", &rect.r_xbot, &rect.r_ybot,
&rect.r_xtop, &rect.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
rect.r_xbot = proprec->prop_value.prop_integer[0];
rect.r_ybot = proprec->prop_value.prop_integer[1];
rect.r_xtop = proprec->prop_value.prop_integer[2];
rect.r_ytop = proprec->prop_value.prop_integer[3];
r = &rect;
}
}
}
}
@ -2453,7 +2459,7 @@ DefRead(
FILE *f;
char *filename;
const char *token;
char *bboxstr;
PropertyRecord *proprec;
int keyword, dscale, total;
float oscale;
Rect *dierect;
@ -2605,14 +2611,17 @@ DefRead(
break;
case DEF_DIEAREA:
dierect = LefReadRect(f, 0, oscale);
bboxstr = mallocMagic(40);
sprintf(bboxstr, "%d %d %d %d",
dierect->r_xbot,
dierect->r_ybot,
dierect->r_xtop,
dierect->r_ytop);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
2 * sizeof(int));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = 4;
proprec->prop_value.prop_integer[0] = dierect->r_xbot;
proprec->prop_value.prop_integer[1] = dierect->r_ybot;
proprec->prop_value.prop_integer[2] = dierect->r_xtop;
proprec->prop_value.prop_integer[3] = dierect->r_ytop;
if (rootDef == NULL) rootDef = DefNewCell(inName);
DBPropPut(rootDef, "FIXED_BBOX", bboxstr);
DBPropPut(rootDef, "FIXED_BBOX", proprec);
LefEndStatement(f);
break;
case DEF_PROPERTYDEFINITIONS:

View File

@ -108,7 +108,7 @@ defWriteHeader(
float oscale,
int units) /* Units for UNITS; could be derived from oscale */
{
char *propvalue;
PropertyRecord *proprec;
bool propfound;
TxPrintf("Diagnostic: Write DEF header for cell %s\n", def->cd_name);
@ -141,15 +141,20 @@ defWriteHeader(
/* For DIEAREA, use the FIXED_BBOX property if present. Otherwise, */
/* use the extents of geometry (CellDef bounding box) */
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
if (propfound)
{
Rect bbox;
/* Die area, taken from the declared FIXED_BBOX. */
if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
{
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
fprintf(f, " DIEAREA ( %.10g %.10g ) ( %.10g %.10g ) ;\n",
(float)bbox.r_xbot * oscale,
(float)bbox.r_ybot * oscale,
@ -2786,15 +2791,21 @@ arrayDefFunc(
if (use->cu_def->cd_flags & CDFIXEDBBOX)
{
char *propval;
PropertyRecord *proprec;
bool found;
propval = (char *)DBPropGet(use->cu_def, "FIXED_BBOX", &found);
proprec = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
if (found)
{
if (sscanf(propval, "%d %d %d %d", &rect.r_xbot, &rect.r_ybot,
&rect.r_xtop, &rect.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
rect.r_xbot = proprec->prop_value.prop_integer[0];
rect.r_ybot = proprec->prop_value.prop_integer[1];
rect.r_xtop = proprec->prop_value.prop_integer[2];
rect.r_ytop = proprec->prop_value.prop_integer[3];
r = &rect;
}
}
}
@ -2844,15 +2855,20 @@ defComponentFunc(
xoff = yoff = 0;
if (cellUse->cu_def->cd_flags & CDFIXEDBBOX)
{
char *propval;
PropertyRecord *proprec;
bool found;
propval = (char *)DBPropGet(cellUse->cu_def, "FIXED_BBOX", &found);
proprec = DBPropGet(cellUse->cu_def, "FIXED_BBOX", &found);
if (found)
{
if (sscanf(propval, "%d %d %d %d", &rect.r_xbot, &rect.r_ybot,
&rect.r_xtop, &rect.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
rect.r_xbot = proprec->prop_value.prop_integer[0];
rect.r_ybot = proprec->prop_value.prop_integer[1];
rect.r_xtop = proprec->prop_value.prop_integer[2];
rect.r_ytop = proprec->prop_value.prop_integer[3];
r = &rect;
GeoTransRect(&cellUse->cu_transform, &rect, &bbrect);
GeoTransRect(&cellUse->cu_transform, &cellUse->cu_def->cd_bbox, &defrect);

View File

@ -2150,6 +2150,7 @@ LefReadMacro(
int keyword, pinNum, propsize, result;
float x, y;
bool has_size, is_imported = FALSE, propfound;
PropertyRecord *proprec;
Rect lefBBox;
Point gdsOffset; /* Difference between GDS and LEF coordinates */
@ -2250,7 +2251,12 @@ LefReadMacro(
sprintf(tsave + strlen(tsave), " %s", token);
token = LefNextToken(f, TRUE);
}
DBPropPut(lefMacro, "LEFclass", StrDup((char **)NULL, tsave + 1));
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
strlen(tsave + 1) - 7);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = strlen(tsave + 1);
strcpy(proprec->prop_value.prop_string, tsave + 1);
DBPropPut(lefMacro, "LEFclass", proprec);
break;
case LEF_SIZE:
token = LefNextToken(f, TRUE);
@ -2294,7 +2300,12 @@ origin_error:
sprintf(tsave + strlen(tsave), " %s", token);
token = LefNextToken(f, TRUE);
}
DBPropPut(lefMacro, "LEFsymmetry", StrDup((char **)NULL, tsave + 1));
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
strlen(tsave + 1) - 7);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = strlen(tsave + 1);
strcpy(proprec->prop_value.prop_string, tsave + 1);
DBPropPut(lefMacro, "LEFsymmetry", proprec);
break;
case LEF_SOURCE:
token = LefNextToken(f, TRUE);
@ -2305,12 +2316,19 @@ origin_error:
case LEF_SITE:
token = LefNextToken(f, TRUE);
if (*token != '\n')
DBPropPut(lefMacro, "LEFsite", StrDup((char **)NULL, token));
{
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
strlen(token) - 7);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = strlen(token);
strcpy(proprec->prop_value.prop_string, token);
DBPropPut(lefMacro, "LEFsite", proprec);
}
LefEndStatement(f);
break;
case LEF_PROPERTY:
/* Append property key:value pairs to the cell property LEFproperties */
propval = (char *)DBPropGet(lefMacro, "LEFproperties", &propfound);
propval = DBPropGetString(lefMacro, "LEFproperties", &propfound);
if (propfound)
propsize = strlen(propval);
else
@ -2322,14 +2340,19 @@ origin_error:
char *propext;
sprintf(tsave, "%.127s", token);
token = LefNextToken(f, TRUE);
propext = (char *)mallocMagic(propsize + strlen(tsave) +
strlen(token) + 4);
if (propsize > 0)
sprintf(propext, "%s %s %s", propval, tsave, token);
else
sprintf(propext, "%s %s", tsave, token);
DBPropPut(lefMacro, "LEFproperties", StrDup((char **)NULL, propext));
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
propsize + strlen(tsave) + strlen(token) - 3);
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = propsize + strlen(tsave) + strlen(token) + 4;
if (propsize > 0)
sprintf(proprec->prop_value.prop_string, "%s %s %s",
propval, tsave, token);
else
sprintf(proprec->prop_value.prop_string, "%s %s", tsave, token);
DBPropPut(lefMacro, "LEFproperties", proprec);
}
LefEndStatement(f);
break;
@ -2405,11 +2428,16 @@ foreign_error:
if (has_size)
{
lefMacro->cd_flags |= CDFIXEDBBOX;
propval = (char *)mallocMagic(40);
sprintf(propval, "%d %d %d %d",
lefBBox.r_xbot, lefBBox.r_ybot,
lefBBox.r_xtop, lefBBox.r_ytop);
DBPropPut(lefMacro, "FIXED_BBOX", propval);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(2 * sizeof(int)));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = 4;
proprec->prop_value.prop_integer[0] = lefBBox.r_xbot;
proprec->prop_value.prop_integer[1] = lefBBox.r_ybot;
proprec->prop_value.prop_integer[2] = lefBBox.r_xtop;
proprec->prop_value.prop_integer[3] = lefBBox.r_ytop;
DBPropPut(lefMacro, "FIXED_BBOX", proprec);
}
}
else
@ -2419,11 +2447,16 @@ foreign_error:
if (has_size)
{
lefMacro->cd_flags |= CDFIXEDBBOX;
propval = (char *)mallocMagic(40);
sprintf(propval, "%d %d %d %d",
lefBBox.r_xbot, lefBBox.r_ybot,
lefBBox.r_xtop, lefBBox.r_ytop);
DBPropPut(lefMacro, "FIXED_BBOX", propval);
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(2 * sizeof(int)));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = 4;
proprec->prop_value.prop_integer[0] = lefBBox.r_xbot;
proprec->prop_value.prop_integer[1] = lefBBox.r_ybot;
proprec->prop_value.prop_integer[2] = lefBBox.r_xtop;
proprec->prop_value.prop_integer[3] = lefBBox.r_ytop;
DBPropPut(lefMacro, "FIXED_BBOX", proprec);
}
else
{
@ -2432,13 +2465,17 @@ foreign_error:
/* Set the placement bounding box property to the current bounding box */
lefMacro->cd_flags |= CDFIXEDBBOX;
propval = (char *)mallocMagic(40);
sprintf(propval, "%d %d %d %d",
lefMacro->cd_bbox.r_xbot,
lefMacro->cd_bbox.r_ybot,
lefMacro->cd_bbox.r_xtop,
lefMacro->cd_bbox.r_ytop);
DBPropPut(lefMacro, "FIXED_BBOX", propval);
lefMacro->cd_flags |= CDFIXEDBBOX;
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord) +
(2 * sizeof(int)));
proprec->prop_type = PROPERTY_TYPE_DIMENSION;
proprec->prop_len = 4;
proprec->prop_value.prop_integer[0] = lefMacro->cd_bbox.r_xbot;
proprec->prop_value.prop_integer[1] = lefMacro->cd_bbox.r_ybot;
proprec->prop_value.prop_integer[2] = lefMacro->cd_bbox.r_xtop;
proprec->prop_value.prop_integer[3] = lefMacro->cd_bbox.r_ytop;
DBPropPut(lefMacro, "FIXED_BBOX", proprec);
DRCCheckThis(lefMacro, TT_CHECKPAINT, &lefMacro->cd_bbox);
}
}
@ -2453,7 +2490,13 @@ foreign_error:
/* i.e., setting it to "FALSE" would be ineffective. */
if (!is_imported)
DBPropPut(lefMacro, "LEFview", StrDup((char **)NULL, "TRUE"));
{
proprec = (PropertyRecord *)mallocMagic(sizeof(PropertyRecord));
proprec->prop_type = PROPERTY_TYPE_STRING;
proprec->prop_len = 4;
strcpy(proprec->prop_value.prop_string, "TRUE");
DBPropPut(lefMacro, "LEFview", proprec);
}
DBWAreaChanged(lefMacro, &lefMacro->cd_bbox, DBW_ALLWINDOWS,
&DBAllButSpaceBits);

View File

@ -328,14 +328,14 @@ lefWriteHeader(
{
fprintf(f, "SITE %s\n", siteDef->cd_name);
propvalue = (char *)DBPropGet(siteDef, "LEFsymmetry", &propfound);
propvalue = DBPropGetString(siteDef, "LEFsymmetry", &propfound);
if (propfound)
fprintf(f, IN0 "SYMMETRY %s ;\n", propvalue);
else
/* Usually core cells have symmetry Y only. */
fprintf(f, IN0 "SYMMETRY Y ;\n");
propvalue = (char *)DBPropGet(siteDef, "LEFclass", &propfound);
propvalue = DBPropGetString(siteDef, "LEFclass", &propfound);
if (propfound)
fprintf(f, IN0 "CLASS %s ;\n", propvalue);
else
@ -345,10 +345,20 @@ lefWriteHeader(
boundary = siteDef->cd_bbox;
if (siteDef->cd_flags & CDFIXEDBBOX)
{
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &propfound);
PropertyRecord *proprec;
proprec = DBPropGet(def, "FIXED_BBOX", &propfound);
if (propfound)
sscanf(propvalue, "%d %d %d %d", &boundary.r_xbot,
&boundary.r_ybot, &boundary.r_xtop, &boundary.r_ytop);
{
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
boundary.r_xbot = proprec->prop_value.prop_integer[0];
boundary.r_ybot = proprec->prop_value.prop_integer[1];
boundary.r_xtop = proprec->prop_value.prop_integer[2];
boundary.r_ytop = proprec->prop_value.prop_integer[3];
}
}
}
scale = CIFGetOutputScale(1000); /* conversion to microns */
@ -1288,7 +1298,7 @@ lefWriteMacro(
/* default values are optional, so in this case we will leave those */
/* entries blank. */
propvalue = (char *)DBPropGet(def, "LEFclass", &propfound);
propvalue = DBPropGetString(def, "LEFclass", &propfound);
if (propfound)
{
fprintf(f, IN0 "CLASS %s ;\n", propvalue);
@ -1324,13 +1334,21 @@ lefWriteMacro(
if (def->cd_flags & CDFIXEDBBOX)
{
char *propvalue;
PropertyRecord *proprec;
bool found;
propvalue = (char *)DBPropGet(def, "FIXED_BBOX", &found);
proprec = DBPropGet(def, "FIXED_BBOX", &found);
if (found)
sscanf(propvalue, "%d %d %d %d", &boundary.r_xbot,
&boundary.r_ybot, &boundary.r_xtop, &boundary.r_ytop);
{
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
boundary.r_xbot = proprec->prop_value.prop_integer[0];
boundary.r_ybot = proprec->prop_value.prop_integer[1];
boundary.r_xtop = proprec->prop_value.prop_integer[2];
boundary.r_ytop = proprec->prop_value.prop_integer[3];
}
}
}
/* Check if (boundry less setback) is degenerate. If so, then */
@ -1358,11 +1376,11 @@ lefWriteMacro(
lc.origin.p_x = 0;
lc.origin.p_y = 0;
propvalue = (char *)DBPropGet(def, "LEFsymmetry", &propfound);
propvalue = DBPropGetString(def, "LEFsymmetry", &propfound);
if (propfound)
fprintf(f, IN0 "SYMMETRY %s ;\n", propvalue);
propvalue = (char *)DBPropGet(def, "LEFsite", &propfound);
propvalue = DBPropGetString(def, "LEFsite", &propfound);
if (propfound)
fprintf(f, IN0 "SITE %s ;\n", propvalue);
@ -1821,20 +1839,24 @@ lefWriteMacro(
Rect layerBound, manualBound;
labelLinkedList *thislll;
bool propfound;
char *propvalue;
PropertyRecord *proprec;
/* If there is a property OBS_BBOX, then use the value of the */
/* defined box to set the minimum hidden area. This will still */
/* get clipped to the setback. */
propvalue = (char *)DBPropGet(def, "OBS_BBOX", &propfound);
proprec = DBPropGet(def, "OBS_BBOX", &propfound);
if (propfound)
{
if (sscanf(propvalue, "%d %d %d %d",
&(manualBound.r_xbot),
&(manualBound.r_ybot),
&(manualBound.r_xtop),
&(manualBound.r_ytop)) != 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
manualBound.r_xbot = proprec->prop_value.prop_integer[0];
manualBound.r_ybot = proprec->prop_value.prop_integer[1];
manualBound.r_xtop = proprec->prop_value.prop_integer[2];
manualBound.r_ytop = proprec->prop_value.prop_integer[3];
}
else
{
TxError("Improper values for obstruction bounding box "
"OBS_BBOX property");
@ -2016,7 +2038,7 @@ lefWriteMacro(
/* If there are any properties saved in LEFproperties, write them out */
propvalue = (char *)DBPropGet(def, "LEFproperties", &propfound);
propvalue = DBPropGetString(def, "LEFproperties", &propfound);
if (propfound)
{
char *delim;
@ -2094,7 +2116,7 @@ lefGetSites(
bool propfound;
char *propvalue;
propvalue = (char *)DBPropGet(def, "LEFsite", &propfound);
propvalue = DBPropGetString(def, "LEFsite", &propfound);
if (propfound)
he = HashFind(lefSiteTbl, propvalue); /* FIXME return value not used from call to function with no side-effects (reevaluate this entire func purpose?) */
@ -2124,7 +2146,7 @@ lefGetProperties(
bool propfound;
char *propvalue;
propvalue = (char *)DBPropGet(def, "LEFproperties", &propfound);
propvalue = DBPropGetString(def, "LEFproperties", &propfound);
if (propfound)
{
char *key;

View File

@ -58,6 +58,8 @@ MAGIC_8.0 {
DBPlaneTypes;
DBPrintUseId;
DBPropGet;
DBPropGetString;
DBPropGetDouble;
DBPutLabel;
DBReComputeBbox;
DBSeeTypesAll;

View File

@ -321,14 +321,20 @@ selRedisplayCellFunc(scx, window)
if (scx->scx_use->cu_def->cd_flags & CDFIXEDBBOX)
{
bool found;
char *propval;
PropertyRecord *proprec;
propval = (char *)DBPropGet(scx->scx_use->cu_def, "FIXED_BBOX", &found);
proprec = DBPropGet(scx->scx_use->cu_def, "FIXED_BBOX", &found);
if (found)
{
if (sscanf(propval, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot,
&bbox.r_xtop, &bbox.r_ytop) == 4)
if ((proprec->prop_type == PROPERTY_TYPE_DIMENSION) &&
(proprec->prop_len == 4))
{
bbox.r_xbot = proprec->prop_value.prop_integer[0];
bbox.r_ybot = proprec->prop_value.prop_integer[1];
bbox.r_xtop = proprec->prop_value.prop_integer[2];
bbox.r_ytop = proprec->prop_value.prop_integer[3];
GeoTransRect(&scx->scx_trans, &bbox, &tmp);
}
else
found = FALSE;
}