Files
magic/database/DBtechtype.c
T
Patrick Kurth ea03883829 Fixed unused-parameters/unused-variables warnings
Added a ARG_UNUSED macro in utils/magic.h, which
produces a simple cast to void to silence the warnings.
The reasons this is used as opposed to an attribute is
that most compilers should support this.
Besides this, the macro can be easily searched for in
the future to potentially remove (where possible) the
unused parameters.
2025-10-10 22:12:19 +02:00

830 lines
21 KiB
C

/*
* DBtechtype.c --
*
* Creation of tile and plane types and their names.
* Lookup procedures are in DBtechname.c
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/database/DBtechtype.c,v 1.2 2008/09/05 13:56:25 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/utils.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "database/databaseInt.h"
#include "utils/tech.h"
#include "textio/textio.h"
#include "utils/malloc.h"
/* Types and their names */
int DBNumTypes;
const char *DBTypeLongNameTbl[NT];
int DBTypePlaneTbl[NT]; /* Normally accessed as macro "DBPlane(x)" */
NameList dbTypeNameLists = {NULL, NULL, NULL, (ClientData)0, FALSE};
HashTable DBTypeAliasTable;
/* Planes and their names */
int DBNumPlanes;
const char *DBPlaneLongNameTbl[PL_MAXTYPES];
NameList dbPlaneNameLists = {NULL, NULL, NULL, (ClientData)0, FALSE};
/*
* Sets of types.
* These are generated after the "types" section of the
* technology file has been read, but before any automatically
* generated types (contact images) are created.
*/
int DBNumUserLayers;
TileTypeBitMask DBZeroTypeBits;
TileTypeBitMask DBAllTypeBits;
TileTypeBitMask DBBuiltinLayerBits;
TileTypeBitMask DBAllButSpaceBits;
TileTypeBitMask DBAllButSpaceAndDRCBits;
TileTypeBitMask DBSpaceBits;
TileTypeBitMask DBUserLayerBits;
TileTypeBitMask DBActiveLayerBits; /* Layers that are locked */
TileTypeBitMask DBTechActiveLayerBits; /* Layers marked locked in the techfile */
/* Table of default, builtin planes */
DefaultPlane dbTechDefaultPlanes[] =
{
{PL_ROUTER, "router"},
{PL_DRC_ERROR, "designRuleError"},
{PL_DRC_CHECK, "designRuleCheck"},
{PL_M_HINT, "mhint"},
{PL_F_HINT, "fhint"},
{PL_R_HINT, "rhint"},
{0, NULL}
};
/* Table of default, builtin types */
DefaultType dbTechDefaultTypes[] =
{
{TT_SPACE, -1, "space", FALSE},
{TT_CHECKPAINT, PL_DRC_CHECK, "checkpaint,CP", FALSE},
{TT_CHECKSUBCELL, PL_DRC_CHECK, "checksubcell,CS", FALSE},
{TT_ERROR_P, PL_DRC_ERROR, "error_p,EP", FALSE},
{TT_ERROR_S, PL_DRC_ERROR, "error_s,ES", FALSE},
{TT_ERROR_PS, PL_DRC_ERROR, "error_ps,EPS", FALSE},
{TT_MAGNET, PL_M_HINT, "magnet,mag", TRUE},
{TT_FENCE, PL_F_HINT, "fence,f", TRUE},
{TT_ROTATE, PL_R_HINT, "rotate,r", TRUE},
{0, 0, NULL, 0}
};
/* Forward declarations */
char *dbTechNameAdd();
NameList *dbTechNameAddOne();
/*
* ----------------------------------------------------------------------------
*
* DBTechInitPlane --
*
* Initialize the default plane information.
*
* Results:
* None.
*
* Side effects:
* Initializes DBNumPlanes to PL_TECHDEPBASE.
* Initializes DBPlaneLongNameTbl[] for builtin planes.
*
* ----------------------------------------------------------------------------
*/
void
DBTechInitPlane(void)
{
DefaultPlane *dpp;
const char *cp;
/* Clear out any old information */
if (dbPlaneNameLists.sn_next != NULL)
{
NameList *tbl;
for (tbl = dbPlaneNameLists.sn_next; tbl != &dbPlaneNameLists;
tbl = tbl->sn_next)
{
freeMagic(tbl->sn_name);
freeMagic(tbl);
}
}
/* Tables of short names */
dbPlaneNameLists.sn_next = &dbPlaneNameLists;
dbPlaneNameLists.sn_prev = &dbPlaneNameLists;
for (dpp = dbTechDefaultPlanes; dpp->dp_names; dpp++)
{
cp = dbTechNameAdd(dpp->dp_names, INT2CD(dpp->dp_plane),
&dbPlaneNameLists, FALSE);
if (cp == NULL)
{
TxError("DBTechInit: can't add plane names %s\n", dpp->dp_names);
niceabort();
}
DBPlaneLongNameTbl[dpp->dp_plane] = cp;
}
DBNumPlanes = PL_TECHDEPBASE;
}
/*
* ----------------------------------------------------------------------------
*
* DBTypeInit --
*
* Initialization routine for the types database on startup (runs only
* once).
*
* Results:
* None.
*
* Side effects:
* Hash table initialization.
*
* ----------------------------------------------------------------------------
*/
void
DBTypeInit()
{
HashInit(&DBTypeAliasTable, 8, HT_STRINGKEYS);
}
/*
* ----------------------------------------------------------------------------
*
* DBTechInitType --
*
* Add the names and planes of the builtin types.
*
* Results:
* None.
*
* Side effects:
* See above.
* Initializes DBNumTypes to TT_TECHDEPBASE.
*
* ----------------------------------------------------------------------------
*/
void
DBTechInitType()
{
DefaultType *dtp;
char *cp;
/* Clear out any old information */
if (dbTypeNameLists.sn_next != NULL)
{
NameList *tbl;
for (tbl = dbTypeNameLists.sn_next; tbl != &dbTypeNameLists;
tbl = tbl->sn_next)
{
freeMagic(tbl->sn_name);
freeMagic(tbl);
}
}
/* Tables of short names */
dbTypeNameLists.sn_next = &dbTypeNameLists;
dbTypeNameLists.sn_prev = &dbTypeNameLists;
/*
* Add the type names to the list of known names, and set
* the default plane for each type.
*/
for (dtp = dbTechDefaultTypes; dtp->dt_names; dtp++)
{
cp = dbTechNameAdd(dtp->dt_names, INT2CD(dtp->dt_type),
&dbTypeNameLists, FALSE);
if (cp == NULL)
{
TxError("DBTechInit: can't add type names %s\n", dtp->dt_names);
niceabort();
}
DBTypeLongNameTbl[dtp->dt_type] = cp;
DBPlane(dtp->dt_type) = dtp->dt_plane;
TTMaskSetOnlyType(&DBLayerTypeMaskTbl[dtp->dt_type], dtp->dt_type);
}
/* Zero the active layers (this mask is inverted later) */
TTMaskZero(&DBActiveLayerBits);
/* Hash table of layer aliases, free'ing the allocated type masks */
HashFreeKill(&DBTypeAliasTable);
HashInit(&DBTypeAliasTable, 8, HT_STRINGKEYS);
DBNumTypes = TT_TECHDEPBASE;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechAddPlane --
*
* Define a tile plane type for the new technology.
*
* Results:
* TRUE if successful, FALSE on error
*
* Side effects:
* Updates the database technology variables.
* In particular, updates the number of known tile planes.
*
* ----------------------------------------------------------------------------
*/
/*ARGSUSED*/
bool
DBTechAddPlane(
const char *sectionName,
int argc,
char *argv[])
{
ARG_UNUSED(sectionName);
const char *cp;
if (DBNumPlanes >= PL_MAXTYPES)
{
TechError("Too many tile planes (max=%d)\n", PL_MAXTYPES);
return FALSE;
}
if (argc != 1)
{
TechError("Line must contain names for plane\n");
return FALSE;
}
cp = dbTechNameAdd(argv[0], INT2CD(DBNumPlanes), &dbPlaneNameLists, FALSE);
if (cp == NULL)
return FALSE;
DBPlaneLongNameTbl[DBNumPlanes++] = cp;
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechAddNameToType --
*
* Add a new name (alias) to an existing tile type.
*
* Results:
* None.
*
* Side Effects:
* Adds "newname" to dbTypeNameLists. May change the primary name
* of the type stored in the pointer array DBTypeLongNameTbl[].
*
* ----------------------------------------------------------------------------
*/
void
DBTechAddNameToType(newname, ttype, canonical)
char *newname;
TileType ttype;
bool canonical;
{
char *cp;
cp = dbTechNameAdd(newname, INT2CD(ttype), &dbTypeNameLists, TRUE);
if (canonical)
DBTypeLongNameTbl[ttype] = cp;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechAddAlias --
*
* Define an alias representing a mask of one or more tiletypes
*
* Results:
* TRUE if successful, FALSE on error. Returns TRUE on some
* errors that may not necessarily be fatal.
*
* Side effects:
* Updates the database technology variables.
* In particular, updates the alias hash table.
*
* ----------------------------------------------------------------------------
*/
bool
DBTechAddAlias(sectionName, argc, argv)
char *sectionName;
int argc;
char *argv[];
{
ARG_UNUSED(sectionName);
HashEntry *he;
TileType atype;
TileTypeBitMask *amask, tmask;
if (argc < 2)
{
TechError("Line must contain at least 2 fields\n");
return TRUE;
}
/* First check that the alias name does not shadow an existing type */
if (DBTechNameTypeExact(argv[0]) >= 0)
{
TechError("Type alias \"%s\" shadows a defined type\n", argv[0]);
return TRUE;
}
/* Next, check the type list. If there is only one type, then */
/* add the name to the type's names as usual, instead of adding */
/* it to the alias hash table, which is meant for names that */
/* map to multiple types. */
DBTechNoisyNameMask(argv[1], &tmask);
if ((atype = DBTechNameType(argv[1])) >= 0)
if (TTMaskEqual(&DBLayerTypeMaskTbl[atype], &tmask))
{
DBTechAddNameToType(argv[0], atype, FALSE);
return TRUE;
}
he = HashFind(&DBTypeAliasTable, argv[0]);
amask = (TileTypeBitMask *)HashGetValue(he);
if (amask == NULL)
{
amask = (TileTypeBitMask *)mallocMagic(sizeof(TileTypeBitMask));
TTMaskZero(amask);
TTMaskSetMask(amask, &tmask);
HashSetValue(he, amask);
}
else
{
TechError("Type \"%s\" is already defined and cannot be an alias\n",
argv[0]);
return TRUE;
}
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechAddType --
*
* Define a tile type for the new technology.
*
* Results:
* TRUE if successful, FALSE on error. Returns TRUE on some
* errors that may not necessarily be fatal.
*
* Side effects:
* Updates the database technology variables.
* In particular, updates the number of known tile types.
*
* ----------------------------------------------------------------------------
*/
/*ARGSUSED*/
bool
DBTechAddType(sectionName, argc, argv)
char *sectionName;
int argc;
char *argv[];
{
char *cp;
int pNum;
if (DBNumTypes >= TT_MAXTYPES-TT_RESERVEDTYPES)
{
TechError("Too many tile types (max=%d)\n",
TT_MAXTYPES-TT_RESERVEDTYPES);
return FALSE;
}
if (argc < 2)
{
TechError("Line must contain at least 2 fields\n");
return TRUE;
}
if (!strcmp(argv[0], "alias"))
{
/* Check that we have not used "*" in the alias list, since if */
/* we define aliases in the "types" section (which is allowed */
/* for backwards compatibility), the contacts have not yet been */
/* defined. */
if (strchr(argv[2], '*') != NULL)
{
TechError("Type alias \"%s\" contains the wildcard character "
"\"*\" (alias ignored).\n"
"Perhaps you want to define aliases in "
"the \"alias\" section?\n", argv[2]);
return TRUE;
}
return (DBTechAddAlias(sectionName, argc - 1, argv + 1));
}
else
{
cp = dbTechNameAdd(argv[1], INT2CD(DBNumTypes), &dbTypeNameLists, FALSE);
if (cp == NULL)
return FALSE;
/* Set the lock layer bit if the plane name begins with '-' */
if (*argv[0] == LOCKLAYERCHAR)
{
TTMaskSetType(&DBActiveLayerBits, DBNumTypes);
argv[0]++;
}
pNum = DBTechNoisyNamePlane(argv[0]);
if (pNum < 0)
return FALSE;
DBTypeLongNameTbl[DBNumTypes] = cp;
DBPlane(DBNumTypes) = pNum;
TTMaskSetOnlyType(&DBLayerTypeMaskTbl[DBNumTypes], DBNumTypes);
DBNumTypes++;
}
return TRUE;
}
/*
* ----------------------------------------------------------------------------
* dbTechNewStackedType --
*
* Generate a new tiletype for a stacked layer (generally speaking,
* a stacked contact). Return the new tile type for the stacked
* contact type.
*
* Results:
* The new tile type
*
* Side effects:
* Updates the name tables with the new type name. Note that other
* tables, such as the home plane table, are not affected by this
* routine.
* ----------------------------------------------------------------------------
*/
TileType
dbTechNewStackedType(type1, type2)
TileType type1, type2;
{
char buf[1024], *cp;
if (DBNumTypes >= TT_MAXTYPES - TT_RESERVEDTYPES)
{
TechError("Too many types to generate a new contact. Maximum=%d\n",
TT_MAXTYPES - TT_RESERVEDTYPES);
return (TileType) -1;
}
sprintf(buf, "%s+%s", DBTypeShortName(type1), DBTypeShortName(type2));
cp = dbTechNameAdd(buf, INT2CD(DBNumTypes), &dbTypeNameLists, FALSE);
if (cp == NULL)
{
TechError("Couldn't generate new stacking type %s\n", buf);
return (TileType) -1;
}
DBTypeLongNameTbl[DBNumTypes] = cp;
return DBNumTypes++;
}
/*
* ----------------------------------------------------------------------------
*
* DBTechFinalType --
*
* After processing the types and planes sections, compute the
* various derived type and plane masks and tables.
*
* Results:
* None.
*
* Side effects:
* Initializes DBNumUserLayers to be DBNumTypes at the time
* this procedure is called, since none of the automatically
* generated plane images have yet been created.
* Initializes the following bit masks:
* DBAllTypeBits
* DBSpaceBits
* DBBuiltinLayerBits
* DBAllButSpaceBits
* DBAllButSpaceAndDRCBits
* DBUserLayerBits
*
* ----------------------------------------------------------------------------
*/
void
DBTechFinalType()
{
TileType i;
int pNum;
DBNumUserLayers = DBNumTypes;
for (i = 0; i < TT_MAXTYPES; i++)
{
if (i >= TT_SELECTBASE)
TTMaskSetType(&DBAllButSpaceAndDRCBits, i);
if (i < TT_TECHDEPBASE)
TTMaskSetType(&DBBuiltinLayerBits, i);
else if (i < DBNumUserLayers)
TTMaskSetType(&DBUserLayerBits, i);
}
TTMaskCom2(&DBAllTypeBits, &DBZeroTypeBits);
TTMaskSetOnlyType(&DBSpaceBits, TT_SPACE);
TTMaskCom2(&DBAllButSpaceBits, &DBSpaceBits);
/* UserLayerBits includes space */
TTMaskSetType(&DBUserLayerBits, TT_SPACE);
/* Set locked layer bitmask */
TTMaskCom(&DBActiveLayerBits);
TTMaskAndMask(&DBActiveLayerBits, &DBAllButSpaceAndDRCBits);
/* Save this mask for later reference */
TTMaskZero(&DBTechActiveLayerBits);
TTMaskSetMask(&DBTechActiveLayerBits, &DBActiveLayerBits);
/* Space is visible on all planes except the router */
TTMaskZero(&DBPlaneTypes[PL_ROUTER]);
for (pNum = PL_PAINTBASE; pNum < PL_MAXTYPES; pNum++)
TTMaskSetOnlyType(&DBPlaneTypes[pNum], TT_SPACE);
}
/*
* ----------------------------------------------------------------------------
*
* dbTechNameLookupExact --
*
* Lookup a type or plane name.
* Case is significant.
*
* Results:
* Returns the ClientData associated with the given name.
* If the name was not found, we return -2. Unlike dbTechNameLookup,
* this routine requires an exact name match, and never returns -1
* (which indicates ambiguity in dbTechNameLookup()).
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
ClientData
dbTechNameLookupExact(str, table)
char *str; /* The name to be looked up */
NameList *table; /* Table of names to search */
{
NameList *top;
top = table;
while ((top = top->sn_next) != table)
if (!strcmp(top->sn_name, str))
return (top->sn_value);
return ((ClientData) -2);
}
/*
* ----------------------------------------------------------------------------
*
* dbTechNameLookup --
*
* Lookup a type or plane name.
* Case is significant.
*
* Results:
* Returns the ClientData associated with the given name.
* If the name was not found, we return -2; if it was ambiguous,
* we return -1.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
ClientData
dbTechNameLookup(str, table)
char *str; /* The name to be looked up */
NameList *table; /* Table of names to search */
{
/*
* The search is carried out by using two pointers, one which moves
* forward through list from its start, and one which moves backward
* through table from its end. The two pointers mark the range of
* strings that match the portion of str that we have scanned. When
* all of the characters of str have been scanned, then the two
* pointers better be identical, or one of the strings in the range
* between the two pointers better match 'str' exactly.
*/
NameList *bot, *top;
char currentchar;
int indx;
bot = table->sn_next;
top = table->sn_prev;
if (top == bot) return ((ClientData) -2);
for (indx = 0; ; indx++)
{
/* Check for the end of string */
currentchar = str[indx];
if (currentchar == '\0')
{
if (bot == top)
return (bot->sn_value);
/*
* Several entries match this one up to the last character
* of the string. If one is an exact match, we allow it;
* otherwise, we claim the string was ambiguous.
*/
for ( ; bot != top; bot = bot->sn_next)
if (bot->sn_name[indx] == '\0')
return (bot->sn_value);
return ((ClientData) -1);
}
/*
* Move bot up until the string it points to matches str in the
* indx'th position. Make match refer to the indx of bot in table.
*/
while (bot->sn_name[indx] != currentchar)
{
if (bot == top) return((ClientData) -2);
bot = bot->sn_next;
}
/* Move top down until it matches */
while (top->sn_name[indx] != currentchar)
{
if (bot == top) return((ClientData) -2);
top = top->sn_prev;
}
}
/*NOTREACHED*/
}
/*
* ----------------------------------------------------------------------------
*
* dbTechNameAdd --
*
* Add several names to a name table.
* The shortest name is marked as the standard "short" name
* for this cdata value.
*
* Results:
* Returns a pointer to the first name added if successful,
* or NULL if not. In this latter case, we print error messages.
*
* Side effects:
* Adds new entries to the table pointed to by *ptable, and
* modifies *ptable if necessary.
*
* ----------------------------------------------------------------------------
*/
char *
dbTechNameAdd(name, cdata, ptable, alias)
char *name; /* Comma-separated list of names to be added */
ClientData cdata; /* Value to be stored with each name above */
NameList *ptable; /* Table to which we will add names */
int alias; /* 1 if this is an alias (never make primary) */
{
char *cp;
char onename[BUFSIZ];
char *first;
int shortestLength, length;
NameList *primary, *current;
if (name == NULL)
return (NULL);
first = NULL;
shortestLength = INFINITY;
primary = NULL;
while (*name)
{
if (*name == ',')
{
name++;
continue;
}
for (cp = onename; *name && *name != ','; *cp++ = *name++)
/* Nothing */;
*cp = '\0';
if (*(cp = onename))
{
if ((current = dbTechNameAddOne(cp, cdata, FALSE, alias, ptable)) == NULL)
return (NULL);
if (first == NULL)
first = current->sn_name;
length = strlen(onename);
if (length < shortestLength)
shortestLength = length, primary = current;
}
}
if (primary && (alias == 0))
primary->sn_primary = TRUE;
return (first);
}
/*
* ----------------------------------------------------------------------------
*
* dbTechNameAddOne --
*
* Add a single name to the table.
*
* Results:
* Returns a pointer to the new entry if succesful,
* or NULL if the name was already in the table.
*
* Side effects:
* See above.
*
* ----------------------------------------------------------------------------
*/
NameList *
dbTechNameAddOne(name, cdata, isPrimary, isAlias, ptable)
char *name; /* Name to be added */
ClientData cdata; /* Client value associated with this name */
bool isPrimary; /* TRUE if this is the primary abbreviation */
bool isAlias; /* TRUE if this name is an alias */
NameList *ptable; /* Table of names to which we're adding this */
{
int cmp;
NameList *tbl, *new;
/* Sort the name into the existing list */
for (tbl = ptable->sn_next ;tbl != ptable; tbl = tbl->sn_next)
if ((cmp = strcmp(name, tbl->sn_name)) == 0)
{
TechError("Duplicate name: %s\n", name);
return (NULL);
}
else if (cmp < 0)
break;
/* Create a new name */
new = (NameList *) mallocMagic((unsigned) (sizeof (NameList)));
new->sn_name = StrDup((char **) NULL, name);
new->sn_value = cdata;
new->sn_primary = isPrimary;
new->sn_alias = isAlias;
/* Link this entry in to the list before 'tbl' */
new->sn_next = tbl;
new->sn_prev = tbl->sn_prev;
tbl->sn_prev->sn_next = new;
tbl->sn_prev = new;
return (new);
}