mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-08-29 17:39:28 +02:00
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.
364 lines
9.9 KiB
C
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;
|
|
}
|