Files
magic/database/DBprop.c
T
R. Timothy Edwards 7bdd9e1d4f Reworked the method from the previous set of commits, which creates
yet another property type "plane".  This allows mask hints to be
handled like tile planes.  That is, after all, what they represent.
Although this change is transparent to the end user (apart from a
slight performance improvement that is probably not noticeable), it
allows for a number of useful future extensions, including the
ability to handle non-Manhattan geometry in mask hints, and the
ability to view and edit mask hints like any other layout.
2026-03-10 14:25:02 -04:00

364 lines
9.9 KiB
C

/*
* DBprop.c --
*
* Implement properties on database cells. Properties are name-value pairs
* and provide a flexible way of extending the data that is stored in a
* CellDef. Maybe in the future properties will be added to other database
* objects.
*
* *********************************************************************
* * 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/DBprop.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "utils/malloc.h"
/* Global variable */
bool DBPropCompat = TRUE; /* If TRUE, then always save properties to
* .mag files as type "string" for backwards
* compatibility. If FALSE, then properties
* are saved to the .mag file along with their
* type. Regardless of the setting, properties
* which are reserved keywords are converted
* to the best internal representation on input.
*/
/* ----------------------------------------------------------------------------
*
* DBPropPut --
*
* Put a property onto a celldef.
*
* Results:
* None.
*
* ----------------------------------------------------------------------------
*/
void
DBPropPut(cellDef, name, value)
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;
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 */
/* being used, then it must be freed here. */
if (cellDef->cd_flags & CDNOEDIT)
{
if (value != (ClientData)NULL)
freeMagic((char *)value);
return;
}
if (cellDef->cd_props == (ClientData) NULL)
{
cellDef->cd_props = (ClientData) mallocMagic(sizeof(HashTable));
HashInit( (HashTable *) cellDef->cd_props, 8, 0);
}
htab = (HashTable *) cellDef->cd_props;
/* Special handling of FIXED_BBOX, which uses CDFIXEDBBOX as a quick lookup */
if (!strcmp(name, "FIXED_BBOX"))
{
if (value == (ClientData)NULL)
cellDef->cd_flags &= ~CDFIXEDBBOX;
else
cellDef->cd_flags |= CDFIXEDBBOX;
}
/* Special handling of GDS_FILE, which uses CDVENDORGDS as a quick lookup */
if (!strcmp(name, "GDS_FILE"))
{
if (value == (ClientData)NULL)
cellDef->cd_flags &= ~CDVENDORGDS;
else
cellDef->cd_flags |= CDVENDORGDS;
}
entry = HashFind(htab, name);
oldvalue = (PropertyRecord *)HashGetValue(entry);
/* All properties are allocated as a single block and can just be freed,
* except for plane properties, which require freeing the plane.
*/
if (oldvalue != NULL)
{
if (oldvalue->prop_type == PROPERTY_TYPE_PLANE)
{
DBFreePaintPlane(oldvalue->prop_value.prop_plane);
TiFreePlane(oldvalue->prop_value.prop_plane);
}
freeMagic((char *)oldvalue);
}
if (value == (PropertyRecord *)NULL)
HashRemove(htab, name);
else
HashSetValue(entry, PTR2CD(value));
}
/* ----------------------------------------------------------------------------
*
* DBPropGet --
*
* Get a 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 record.
*
* ----------------------------------------------------------------------------
*/
PropertyRecord *
DBPropGet(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.
*/
{
PropertyRecord *result;
bool haveit;
HashTable *htab;
HashEntry *entry;
result = (PropertyRecord *)NULL;
haveit = FALSE;
htab = (HashTable *) cellDef->cd_props;
if (htab == (HashTable *) NULL) goto done;
entry = HashLookOnly(htab, name);
if (entry != NULL)
{
haveit = TRUE;
result = (PropertyRecord *)HashGetValue(entry);
}
done:
if (found != (bool *) NULL) *found = haveit;
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 --
*
* Enumerate all the properties on a cell.
*
* Results:
* 0 if the search completed, else whatever value was returned by the
* called proc.
*
* Side effects:
* Depends on the called proc.
* ----------------------------------------------------------------------------
*/
int
DBPropEnum(cellDef, func, cdata)
CellDef *cellDef; /* Pointer to definition of cell. */
int (*func)(); /* Function of the form:
*
* int foo(name, value, cdata)
* char *name;
* PropertyRecord *value;
* ClientData cdata;
* {
* -- return 0 to continue,
* -- nonzero to abort.
* return result;
* }
*/
ClientData cdata;
{
HashTable *htab;
HashSearch hs;
HashEntry *entry;
int res;
if (cellDef->cd_props == (ClientData) NULL) return 0;
htab = (HashTable *) cellDef->cd_props;
HashStartSearch(&hs);
while ((entry = HashNext(htab, &hs)) != NULL)
{
res = (*func)(entry->h_key.h_name, (PropertyRecord *)entry->h_pointer, cdata);
if (res != 0) return res;
}
return 0;
}
/* ----------------------------------------------------------------------------
*
* DBPropClearAll --
*
* Free up all properties and associated storage for a CellDef.
*
* Results:
* none.
*
* Side effects:
* Frees up storage, even for the property table itself.
* ----------------------------------------------------------------------------
*/
void
DBPropClearAll(cellDef)
CellDef *cellDef; /* Pointer to definition of cell. */
{
HashTable *htab;
HashSearch hs;
HashEntry *entry;
if (cellDef->cd_props == (ClientData) NULL) return;
htab = (HashTable *) cellDef->cd_props;
HashStartSearch(&hs);
while ((entry = HashNext(htab, &hs)) != NULL)
{
if (entry->h_pointer != NULL) freeMagic((char *) entry->h_pointer);
HashSetValue(entry, NULL);
}
HashKill(htab);
freeMagic((char *) htab);
cellDef->cd_props = (ClientData) NULL;
/* Since CDFIXEDBBOX requires a FIXED_BBOX property, clearing all */
/* properties necessarily means this flag must be clear. */
cellDef->cd_flags &= ~CDFIXEDBBOX;
}