www.pudn.com > bayes.rar > attset1.c
/*----------------------------------------------------------------------
File : attset1.c
Contents: attribute set management, base functions
Author : Christian Borgelt
History : 26.10.1995 file created
21.12.1995 function att_valsort added
17.03.1996 attribute types added
04.07.1996 attribute weights added
26.02.1997 default attribute name generation added
12.03.1997 attribute marks added
27.05.1997 function att_conv added
30.08.1997 removal of field vector made possible
22.06.1998 deletion function moved to function as_create
23.06.1998 major redesign, attribute functions introduced
23.08.1998 attribute creation and deletion functions added
30.08.1998 parameters map and dir added to att_valsort
01.09.1998 several assertions added
06.09.1998 second major redesign completed
12.09.1998 deletion function parameter changed to ATT
24.09.1998 parameter map added to function att_conv
25.09.1988 function as_attaddm added
25.11.1998 functions att_valcopy and as_attcopy added
29.11.1998 functions att_dup and as_dup added
04.02.1999 long int changed to int
22.11.2000 functions sc_format and sc_fmtlen exported
23.06.2001 module split into two files
16.07.2001 return code of as_attadd set to 1 if att. exists
21.05.2004 bug concerning unknown value output fixed
19.12.2005 cast from object to function pointer removed
----------------------------------------------------------------------*/
#include
#include
#include
#include
#include
#include "vecops.h"
#include "attset.h"
#include "scan.h"
#ifdef STORAGE
#include "storage.h"
#endif
/*----------------------------------------------------------------------
Preprocessor Definitions
----------------------------------------------------------------------*/
#define BLKSIZE 16 /* block size for vectors */
/*----------------------------------------------------------------------
Type Definitions
----------------------------------------------------------------------*/
typedef struct _valcmp { VAL_CMPFN* cmpfn; } VALCMP;
/*----------------------------------------------------------------------
Auxiliary Functions
----------------------------------------------------------------------*/
static int _length (const char *s)
{ /* --- compute bounded string length */
register int n = AS_MAXLEN; /* character counter */
while (*s++ && (--n > 0)); /* determine the bounded length */
return AS_MAXLEN -n; /* of the string (max. AS_MAXLEN) */
} /* _length() */
/*--------------------------------------------------------------------*/
static char* _copy (char *d, const char *s)
{ /* --- copy string bounded */
register int n = AS_MAXLEN; /* character counter */
register char *p = d; /* to traverse the destination string */
while (*s && (--n >= 0)) *p++ = *s++;
*p = '\0'; /* copy string (max. AS_MAXLEN ch.) */
return d; /* and return the destination */
} /* _copy() */
/*--------------------------------------------------------------------*/
static unsigned int _hash (const char *s)
{ /* --- hash function */
register unsigned int h = 0; /* hash value */
register int n = AS_MAXLEN; /* character counter */
while ((--n >= 0) && *s) h ^= (h << 3) ^ (unsigned int)(*s++);
return h; /* compute and return hash value */
} /* _hash() */
/*--------------------------------------------------------------------*/
static int _valcmp (const void *p1, const void *p2, void *data)
{ /* --- compare two attribute values */
return (((VALCMP*)data)->cmpfn)(((const VAL*)p1)->name,
((const VAL*)p2)->name);
} /* _valcmp() */
/*--------------------------------------------------------------------*/
#if defined AS_RDWR || defined AS_FLDS
static void _delflds (ATTSET *set)
{ /* --- delete field map */
if (set->flds) { free(set->flds); set->flds = NULL; }
set->fldcnt = set->fldvsz = 0;/* delete field vector */
} /* _delflds() */ /* and clear counters */
#else
#define _delflds(s)
#endif
/*----------------------------------------------------------------------
Attribute Functions
----------------------------------------------------------------------*/
static int att_resize (ATT *att, int size)
{ /* --- resize value vector */
int i; /* loop variable */
VAL **p; /* to traverse values */
VAL **hb; /* to traverse hash bucket */
assert(att); /* check the function argument */
i = att->valvsz; /* get current vector size */
if (size > 0) { /* if to enlarge the vector */
if (i >= size) return 0; /* if vector is large enough, abort */
i += (i > BLKSIZE) ? i >> 1 : BLKSIZE;
if (i > size) size = i; } /* compute new vector size */
else { /* if to shrink the vector */
size = att->valcnt << 1; /* get max. tolerable size */
if (size < BLKSIZE) size = BLKSIZE;
if (i <= size) return 0; /* if vector is small enough, abort */
size = att->valcnt +(att->valcnt >> 1);
if (size < BLKSIZE) size = BLKSIZE;
} /* compute new vector size */
p = (VAL**)realloc(att->vals, size *sizeof(VAL*));
if (!p) return -1; /* resize value vector */
att->vals = p; /* and set new vector */
hb = (VAL**)realloc(att->htab, size *sizeof(VAL*));
if (!hb) return -1; /* resize hash table */
att->htab = hb; /* and set new hash table */
att->valvsz = size; /* set new vector size */
for (i = size; --i >= 0; ) /* clear hash table */
hb[i] = NULL; /* and traverse values */
for (i = att->valcnt; --i >= 0; ) {
hb = att->htab +(*p)->hval % size;
(*p)->succ = *hb; /* get pointer to hash bucket and */
*hb = *p++; /* insert value into hash table */
} /* (at the head of the bucket list) */
return 0; /* return 'ok' */
} /* att_resize() */
/*--------------------------------------------------------------------*/
ATT* att_create (const char *name, int type)
{ /* --- create an attribute */
ATT *att; /* created attribute */
assert(name && *name); /* check the function argument */
att = (ATT*)malloc(sizeof(ATT));
if (!att) return NULL; /* allocate memory for att. and name */
att->name = (char*)malloc((_length(name) +1) *sizeof(char));
if (!att->name) { free(att); return NULL; }
_copy(att->name, name); /* copy attribute name and */
att->hval = _hash(att->name); /* compute its hash value */
att->attwd[0] = sc_fmtlen(att->name, att->attwd +1);
att->vals = att->htab = NULL;
att->valcnt = att->valvsz = att->mark = 0;
att->valwd[0] = att->valwd[1] = 0;
att->weight = 1.0F; /* initialize fields */
att->succ = att->info.p = NULL;
att->set = NULL; att->id = -1;
if (type == AT_INT) { /* if attribute is integer valued, */
att->type = AT_INT; /* note type */
att->min.i = INT_MAX; /* initialize minimal */
att->max.i = -INT_MAX; /* and maximal value */
att->inst.i = UV_INT; } /* and clear instance */
else if (type == AT_FLT) { /* if attribute is real valued, */
att->type = AT_FLT; /* note type */
att->min.f = FLT_MAX; /* initialize minimal */
att->max.f = -FLT_MAX; /* and maximal value */
att->inst.f = UV_FLT; } /* and clear instance */
else { /* if attribute is symbolic, */
att->type = AT_SYM; /* note type */
att->min.i = 0; /* initialize minimal */
att->max.i = -1; /* and maximal value */
att->inst.i = UV_SYM; /* and clear instance */
}
return att; /* return created attribute */
} /* att_create() */
/*--------------------------------------------------------------------*/
ATT* att_dup (const ATT *att)
{ /* --- duplicate an attribute */
ATT *dup; /* created duplicate */
assert(att); /* check the function arguments */
dup = att_create(att->name, att->type);
if (!dup) return NULL; /* create a new attribute */
if (att_valcopy(dup, att, 0) != 0) { att_delete(dup); return NULL; }
dup->mark = att->mark; /* copy all attribute values */
dup->weight = att->weight; /* and all other information */
dup->inst = att->inst; /* into the duplicate */
dup->info = att->info;
return dup; /* return the created duplicate */
} /* att_dup() */
/*--------------------------------------------------------------------*/
void att_delete (ATT *att)
{ /* --- delete an attribute */
int i; /* loop variable */
VAL **p; /* to traverse the value vector */
assert(att && att->name); /* check the function argument */
if (att->set) /* if there is a containing set, */
as_attrem(att->set,att->id);/* remove the attribute from it */
if (att->vals) { /* if there are values */
for (p = att->vals +(i = att->valcnt); --i >= 0; )
free(*--p); /* traverse and delete valeus */
free(att->vals); /* delete the value vector */
} /* and the hash table */
if (att->htab) free(att->htab);
free(att->name); /* delete attribute name */
free(att); /* and attribute body */
} /* att_delete() */
/*--------------------------------------------------------------------*/
int att_rename (ATT *att, const char *name)
{ /* --- rename an attribute */
int hval; /* hash value of new attribute name */
char *tmp; /* temporary buffer for name */
ATT **p, **hb = NULL; /* buffers for hash buckets */
ATT *t; /* to traverse a hash bucket */
assert(att && name && *name); /* check the function arguments */
hval = _hash(name); /* and compute its hash value */
if (att->set) { /* if attribute is contained in a set */
hb = att->set->htab +hval % att->set->attvsz;
for (t = *hb; t; t = t->succ)
if ((t != att) && strncmp(name, t->name, AS_MAXLEN) == 0)
return -2; /* check for another attribute */
} /* with the same name */
tmp = (char*)realloc(att->name, (_length(name) +1) *sizeof(char));
if (!tmp) return -1; /* reallocate memory for the new name */
att->name = _copy(tmp, name); /* copy name and determine its widths */
att->attwd[0] = sc_fmtlen(att->name, att->attwd +1);
if (att->set) { /* if attribute is contained in a set */
p = att->set->htab +att->hval % att->set->attvsz;
while (att != *p) p = &(*p)->succ;
*p = (*p)->succ; /* remove the attribute from the */
att->succ = *hb; *hb = att; /* hash table and reinsert it */
} /* into another hash bucket */
att->hval = hval; /* set the new hash value */
return 0; /* return 'ok' */
} /* att_rename() */
/*--------------------------------------------------------------------*/
int att_conv (ATT *att, int type, INST *map)
{ /* --- convert attribute to new type */
int i, k; /* loop variables, buffers */
double f; /* buffer for a floating point value */
VAL **p; /* to traverse the attribute values */
char *s; /* end pointer for conversion */
assert(att); /* check the function argument */
if ((att->type == AT_INT) /* if to convert integer */
&& (type == AT_FLT)) { /* to real/float */
att->type = AT_FLT; /* set new attribute type */
att->min.f = (float)att->min.i; /* adapt minimal */
att->max.f = (float)att->max.i; /* and maximal value */
att->inst.f = (att->inst.i <= UV_INT)
? UV_FLT : (float)att->inst.i;
return 0; /* adapt attribute instance */
} /* and return 'ok' */
if ((att->type == AT_FLT) /* if to convert real/float */
&& (type == AT_INT)) { /* to integer */
att->type = AT_INT; /* set new attribute type */
att->min.i = (att->min.f > -INT_MAX) /* adapt minimal */
? (int)att->min.f : -INT_MAX; /* and */
att->max.i = (att->max.f < INT_MAX) /* maximal value */
? (int)att->max.f : INT_MAX;
if (att->inst.f <= UV_FLT) att->inst.i = UV_INT;
else if (att->inst.f < -INT_MAX) att->inst.i = -INT_MAX;
else if (att->inst.f > INT_MAX) att->inst.i = INT_MAX;
else att->inst.i = (int)att->inst.f;
return 0; /* adapt attribute instance */
} /* and return 'ok' */
if (att->type != AT_SYM) { /* if attribute is not symbolic */
if (type != AT_SYM) return -1;
att->type = AT_SYM; /* if to convert to symbolic */
att->min.i = 0; /* clear minimal */
att->max.i = -1; /* and maximal value, */
att->valwd[0] = -1; /* value widths, and */
att->inst.i = UV_SYM; /* attribute instance */
return 0; /* return 'ok' */
}
if (type == AT_AUTO) { /* if automatic type determination */
type = (att->valcnt > 0) ? AT_INT : AT_SYM;
p = att->vals; /* traverse attribute values */
for (k = att->valcnt; --k >= 0; p++) {
i = (int)strtol((*p)->name, &s, 0); /* try to convert to int */
if ((s == (*p)->name) || (*s != '\0') || (i <= UV_INT)) {
type = AT_FLT; break; } /* if conversion was not successful, */
} /* try to convert to float */
for (k++; --k >= 0; p++) { /* traverse remaining values */
f = strtod((*p)->name, &s); /* try to convert to float */
if ((s == (*p)->name) || (*s != '\0')
|| (f <= UV_FLT) || (f > FLT_MAX)) {
type = AT_SYM; break; } /* if conversion was not successful, */
} /* attribute must stay symbolic */
} /* (determine most specific type) */
if (type == AT_INT) { /* if to convert to integer */
att->min.i = INT_MAX; /* initialize */
att->max.i = -INT_MAX; /* range of values */
for (p = att->vals +(k = att->valcnt); --k >= 0; ) {
i = (int)strtol((*--p)->name, &s, 0); /* convert value to int */
if (s == (*p)->name) { /* skip unconvertable names */
if (map) map[k].i = UV_INT; continue; }
if (map) map[k].i = i; /* if a map is requested, set it */
if (i < att->min.i) att->min.i = i;
if (i > att->max.i) att->max.i = i;
} /* adapt range of values */
if (att->min.i < -INT_MAX) att->min.i = -INT_MAX;
if (att->inst.i < 0) /* if the current value is unknown, */
att->inst.i = UV_INT; /* set instance to unknown integer */
else { /* if the current value is known */
p = att->vals +att->inst.i;
i = (int)strtol((*p)->name, &s, 10);
att->inst.i = (s == (*p)->name) ? UV_INT : i;
} } /* adapt attribute instance */
else if (type == AT_FLT) { /* if to convert to float/real */
att->min.f = FLT_MAX; /* initialize */
att->max.f = -FLT_MAX; /* range of values */
for (p = att->vals +(k = att->valcnt); --k >= 0; ) {
f = strtod((*--p)->name, &s); /* convert value to float */
if (s == (*p)->name) { /* skip unconvertable names */
if (map) map[k].f = UV_FLT; continue; }
if (map) map[k].f = (float)f; /* if a map is requested, set it */
if (f < att->min.f) att->min.f = (float)f;
if (f > att->max.f) att->max.f = (float)f;
} /* adapt range of values */
if (att->inst.i < 0) /* if the current value is unknown, */
att->inst.f = UV_FLT; /* set instance to unknown float */
else { /* if the current value is known */
p = att->vals +att->inst.i;
f = strtod((*p)->name, &s);
att->inst.f = (s == (*p)->name) ? UV_FLT : (float)f;
} } /* adapt attribute instance */
else /* if no correct new type given or */
return -1; /* no conversion possible, abort */
att->type = type; /* set new attribute type */
if (att->vals) { /* if there are attribute values, */
for (p = att->vals +(i = att->valcnt); --i >= 0; )
free(*--p); /* delete attribute values */
free(att->vals); free(att->htab);
att->vals = att->htab = NULL;
} /* delete value vector and hash table */
att->valvsz = att->valcnt = 0;/* clear vector size and counter */
return 0; /* return 'ok' */
} /* att_conv() */
/*--------------------------------------------------------------------*/
int att_cmp (const ATT *att1, const ATT *att2)
{ /* --- compare two attributes */
int i; /* loop variable */
VAL *const*p, *const*q; /* to traverse values */
assert(att1 && att2); /* check the function arguments */
if (att1->type != att2->type) /* compare attribute types and */
return 1; /* if they are not equal, abort */
if (att1->type == AT_INT) { /* if attribute is integer valued */
return ((att1->min.i != att2->min.i)
|| (att1->max.i != att2->max.i));
} /* compare range of values */
if (att1->type == AT_FLT) { /* if attribute is real/float valued */
return ((att1->min.f != att2->min.f)
|| (att1->max.f != att2->max.f));
} /* compare range of values */
if (att1->valcnt != att2->valcnt)
return 1; /* compare number of values */
p = att1->vals +att1->valcnt; /* traverse attribute values */
q = att2->vals +att2->valcnt; /* and compare them */
for (i = att1->valcnt; --i >= 0; )
if (strcmp((*--p)->name, (*--q)->name) != 0)
return 1; /* if a value differs, abort */
return 0; /* otherwise return 'equal' */
} /* att_cmp() */
/*----------------------------------------------------------------------
Attribute Value Functions
----------------------------------------------------------------------*/
int att_valadd (ATT *att, const char *name, INST *inst)
{ /* --- add a value to an attribute */
int i; /* buffer for value, loop variable */
double f; /* buffer for value */
char *s; /* end pointer for conversion */
VAL *val; /* created symbolic value */
VAL **p; /* to traverse values */
int len; /* length of value name */
int w, sw; /* value name widths */
unsigned int h; /* hash value of value name */
assert(att); /* check the function arguments */
/* --- integer attribute --- */
if (att->type == AT_INT) { /* if attribute is integer valued */
if (!name) { /* if no value name given, */
if (!inst) { /* if no instance given */
att->min.i = -INT_MAX; /* otherwise set the */
att->max.i = INT_MAX; /* maximal range of values */
return 0; /* and abort the function */
} /* if an instance is given, */
i = inst->i; len = 0; } /* get the value from the instance */
else { /* if a value name is given, */
i = (int)strtol(name, &s, 10); /* convert name to int */
if ((s == name) || (*s != '\0'))
return -2; /* if the conversion failed, abort */
len = (int)((const char*)s -name);
} /* get the length of the name */
if (i <= UV_INT) return -2; /* check for an unknown value */
if (name && inst && ((i < att->min.i) || (i > att->max.i)))
return -3; /* check for a new value */
if (i < att->min.i) att->min.i = i; /* update minimal */
if (i > att->max.i) att->max.i = i; /* and maximal value */
att->inst.i = i; /* and set instance */
if (len > att->valwd[0]) att->valwd[0] = att->valwd[1] = len;
return 0; /* adapt value widths */
} /* and return 'ok' */
/* --- real/float attribute --- */
if (att->type == AT_FLT) { /* if attribute is real valued */
if (!name) { /* if no value name given */
if (!inst) { /* if no instance given */
att->min.f = -FLT_MAX; /* otherwise set the */
att->max.f = FLT_MAX; /* maximal range of values */
return 0; /* and abort the function */
} /* if an instance is given, */
f = inst->f; len = 0; } /* get the value from the instance */
else { /* if a value name is given, */
f = strtod(name, &s); /* convert name to float value */
if ((s == name) || (*s != '\0') || (f > FLT_MAX))
return -2; /* if the conversion failed, abort */
len = (int)((const char*)s -name);
} /* get the length of the name */
if (f <= UV_FLT) return -2; /* check for an unknown value */
if (name && inst /* check for a new value */
&& (((float)f < att->min.f) /* (the conversion to float is */
|| ((float)f > att->max.f))) /* necessary to avoid problems */
return -3; /* of representational accuracy */
if (f < att->min.f) att->min.f = (float)f; /* update minimal */
if (f > att->max.f) att->max.f = (float)f; /* and maximal value */
att->inst.f = (float)f; /* and set instance */
if (len > att->valwd[0]) att->valwd[0] = att->valwd[1] = len;
return 0; /* adapt value widths */
} /* and return 'ok' */
/* --- symbolic attribute --- */
assert(name && *name); /* check for a valid name */
if (att_resize(att, att->valcnt +1) != 0)
return -1; /* resize the value vector */
h = _hash(name); /* compute the name's hash value */
p = att->htab +h % att->valvsz;
for (val = *p; val; val = val->succ) {
if (strncmp(name, val->name, AS_MAXLEN) == 0) {
att->inst.i = val->id; return 1; }
} /* if name already exists, abort */
if (inst) return -3; /* if not to extend the domain, abort */
val = (VAL*)malloc(sizeof(VAL) +_length(name) *sizeof(char));
if (!val) return -1; /* allocate memory for a value */
_copy(val->name, name); /* copy name and set hash value */
val->hval = h; /* set value identifier and instance */
val->id = att->inst.i = att->valcnt;
val->succ = *p; *p = val; /* insert value into the hash table */
att->vals[att->valcnt++] = val; /* and the value vector */
att->max.i++; /* adapt maximal value identifier */
if (att->valwd[0] >= 0) { /* if value name widths are valid */
w = sc_fmtlen(val->name, &sw); /* determine value name widths */
if (w > att->valwd[0]) att->valwd[0] = w;
if (sw > att->valwd[1]) att->valwd[1] = sw;
} /* update maximal value widths */
return 0; /* return 'ok' */
} /* att_valadd() */
/*--------------------------------------------------------------------*/
void att_valrem (ATT *att, int valid)
{ /* --- remove an attribute value */
int i; /* loop variable */
VAL **p; /* to traverse value vector */
VAL **hb; /* to traverse hash bucket */
assert(att /* check the function arguments */
&& (att->type == AT_SYM) && (valid < att->valcnt));
/* --- remove all attribute values --- */
if (valid < 0) { /* if no value identifier given */
if (!att->vals) return; /* if there are no values, abort */
for (p = att->vals +(i = att->valcnt); --i >= 0; )
free(*--p); /* delete attribute values */
free(att->vals); free(att->htab);
att->vals = att->htab = NULL;
att->valcnt = att->valvsz = 0;
att->max.i = 0; /* delete vector and hash table, */
att->inst.i = UV_SYM; /* clear value counter, maximal id, */
return; /* and instance (current value) */
} /* and abort the function */
/* --- remove one attribute value --- */
p = att->vals +valid; /* get value to remove */
hb = att->htab +(*p)->hval % att->valvsz;
while (*hb != *p) hb = &(*hb)->succ;
*hb = (*hb)->succ; /* remove value from hash table */
free(*p); /* and delete it */
for (i = --att->valcnt -valid; --i >= 0; ) {
*p = p[1]; (*p++)->id--; } /* shift values and adapt identifiers */
att->max.i--; /* adapt maximal value identifier */
att->valwd[0] = -1; /* invalidate value widths */
if (att->inst.i > valid) att->inst.i--;
else if (att->inst.i == valid) att->inst.i = UV_SYM;
att_resize(att, 0); /* adapt instance (current value) */
} /* att_valrem() */ /* and try to shrink the value vector */
/*--------------------------------------------------------------------*/
void att_valexg (ATT *att, int valid1, int valid2)
{ /* --- exchange two attribute values */
VAL **p1, **p2, *val; /* temporary buffers */
assert(att && (att->type == AT_SYM)
&& (valid1 >= 0) && (valid1 < att->valcnt)
&& (valid2 >= 0) && (valid2 < att->valcnt));
p1 = att->vals +valid1; val = *p1;
p2 = att->vals +valid2; /* get pointers to values, */
*p1 = *p2; (*p1)->id = valid1;/* exchange them, and */
*p2 = val; val->id = valid2;/* set new identifiers */
if (att->inst.i == valid1) att->inst.i = valid2;
else if (att->inst.i == valid2) att->inst.i = valid1;
} /* att_valexg() */ /* adapt instance (current value) */
/*--------------------------------------------------------------------*/
void att_valmove (ATT *att, int off, int cnt, int pos)
{ /* --- move some attribute values */
int n; /* temporary buffer */
VAL **p; /* to traverse values */
VAL *curr; /* current value (instance) */
assert(att && (att->type == AT_SYM)); /* check function arguments */
curr = (att->inst.i >= 0) /* note instance (current value) */
? att->vals[att->inst.i] : NULL;
n = att->valcnt; /* check and adapt insert position */
if (pos > n) pos = n; /* and number of values */
if (cnt > n -off) cnt = n -off;
assert((cnt >= 0) && (off >= 0)
&& (pos >= 0) && ((pos <= off) || (pos >= off +cnt)));
v_move(att->vals, off, cnt, pos, (int)sizeof(VAL*));
if (pos <= off) { /* move values in vector */
cnt += off; off = pos; pos = cnt; }
p = att->vals +off; /* set new value identifiers */
while (off < pos) (*p++)->id = off++;
if (curr) att->inst.i = curr->id;
} /* att_valmove() */ /* adapt instance (current value) */
/*--------------------------------------------------------------------*/
int att_valcut (ATT *dst, ATT *src, int mode, ...)
{ /* --- cut some attribute values */
va_list args; /* list of variable arguments */
int i; /* loop variable, buffer */
int off, cnt; /* range of values */
VAL **s; /* to traverse source values */
VAL **d, **p, *hb; /* to traverse dest. values */
assert(src /* check the function arguments */
&& (!dst || (dst->type == src->type)));
/* --- numeric attributes --- */
if (src->type != AT_SYM) { /* if attribute is numeric */
if (dst) { /* if there is a destination */
if (src->type == AT_INT){ /* if integer attribute */
if (src->min.i < dst->min.i) dst->min.i = src->min.i;
if (src->max.i > dst->max.i) dst->max.i = src->max.i; }
else { /* if real/float attribute */
if (src->min.f < dst->min.f) dst->min.f = src->min.f;
if (src->max.f > dst->max.f) dst->max.f = src->max.f;
} /* adapt range of values */
if (src->valwd[0] > dst->valwd[0])
dst->valwd[0] = dst->valwd[1] = src->valwd[0];
} /* adapt value widths */
if (src->type == AT_INT) { /* if integer attribute */
src->min.i = INT_MAX; src->max.i = -INT_MAX;
src->inst.i = UV_INT; } /* clear range of values and instance */
else { /* if real/float attribute */
src->min.f = FLT_MAX; src->max.f = -FLT_MAX;
src->inst.f = UV_FLT; /* clear range of values and */
} /* instance (current value) */
src->valwd[0] = src->valwd[1] = 0;
return 0; /* clear value widths */
} /* and return 'ok' */
/* --- symbolic attributes: get range of values --- */
if (mode & AS_RANGE) { /* if an index range is given */
va_start(args, mode); /* start variable argument evaluation */
off = va_arg(args, int); /* get offset to first value */
cnt = va_arg(args, int); /* and number of values */
va_end(args); /* end variable argument evaluation */
i = src->valcnt -off; /* check and adapt */
if (cnt > i) cnt = i; /* number of values */
assert((off >= 0) && (cnt >= 0)); }
else { /* if no index range given */
off = 0; cnt = src->valcnt; /* get full index range */
}
if (cnt <= 0) return 0; /* if range is empty, abort */
if (dst && (att_resize(dst, dst->valcnt +cnt) != 0))
return -1; /* resize vector and hash table */
/* --- cut source values --- */
d = (dst) ? dst->vals +dst->valcnt : NULL;
s = src->vals +off; /* get destination and source */
for (i = cnt; --i >= 0; s++){ /* traverse the source values */
p = src->htab +(*s)->hval % src->valvsz;
while (*p != *s) p = &(*p)->succ;
*p = (*p)->succ; /* remove value from the hash table */
if (dst) { /* if there is a destination */
hb = dst->htab[(*s)->hval % dst->valvsz];
for (; hb; hb = hb->succ) /* search value in destination */
if (strcmp((*s)->name, hb->name) == 0) break;
if (!hb) { *d++ = *s; continue; }
} /* store value in destination or */
free(*s); /* delete it (if there is no dest. */
} /* or the value is already present) */
p = src->vals +off; /* traverse rear part of the vector */
for (i = src->valcnt -off -cnt; --i >= 0; ) {
(*s)->id -= cnt; *p++ = *s++;
} /* shift left/down remaining values */
src->valcnt -= cnt; /* adapt number of values */
src->max.i -= cnt; /* and maximal identifier */
src->valwd[0] = -1; /* invalidate value widths */
i = src->inst.i; /* adapt instance (current value) */
if (i >= off) src->inst.i = (i -cnt >= off) ? i -cnt : UV_SYM;
att_resize(src, 0); /* try to shrink the value vector */
/* --- insert values into destination --- */
if (dst) { /* if there is a destination */
s = dst->vals +dst->valcnt; /* get pointer to first new value */
dst->valcnt += i = (int)(d -s); /* adapt number of values and */
dst->max.i += i; /* maximal value identifier */
while (--i >= 0) { /* traverse inserted values */
(*s)->id = (int)(s -dst->vals); /* set value identifier */
p = dst->htab +(*s)->hval % dst->valvsz;
(*s)->succ = *p; *p = *s++;
} /* insert value into the hash table */
dst->valwd[0] = -1; /* invalidate value widths */
att_resize(dst, 0); /* try to shrink the value vector */
}
return 0; /* return 'ok' */
} /* att_valcut() */
/*--------------------------------------------------------------------*/
int att_valcopy (ATT *dst, const ATT *src, int mode, ...)
{ /* --- copy some attribute values */
va_list args; /* list of variable arguments */
int i; /* loop variable, buffer */
int off, cnt; /* range of values */
VAL *const *s; /* to traverse source values */
VAL **d, **p, *hb; /* to traverse destination values */
assert(src && dst /* check the function arguments */
&& (dst->type == src->type));
/* --- numeric attributes --- */
if (src->type != AT_SYM) { /* if attribute is numeric */
if (src->type == AT_INT) { /* if integer attribute */
if (src->min.i < dst->min.i) dst->min.i = src->min.i;
if (src->max.i > dst->max.i) dst->max.i = src->max.i; }
else { /* if real/float attribute */
if (src->min.f < dst->min.f) dst->min.f = src->min.f;
if (src->max.f > dst->max.f) dst->max.f = src->max.f;
} /* adapt range of values */
if (src->valwd[0] > dst->valwd[0])
dst->valwd[0] = dst->valwd[1] = src->valwd[0];
return 0; /* adapt value widths */
} /* and return 'ok' */
/* --- symbolic attributes: get range of values --- */
if (mode & AS_RANGE) { /* if an index range is given */
va_start(args, mode); /* start variable argument evaluation */
off = va_arg(args, int); /* get offset to first value */
cnt = va_arg(args, int); /* and number of values */
va_end(args); /* end variable argument evaluation */
i = src->valcnt -off; /* check and adapt */
if (cnt > i) cnt = i; /* number of values */
assert((off >= 0) && (cnt >= 0)); }
else { /* if no index range given */
off = 0; cnt = src->valcnt; /* get full index range */
}
if (cnt <= 0) return 0; /* if range is empty, abort */
if (att_resize(dst, dst->valcnt +cnt) != 0)
return -1; /* resize vector and hash table */
/* --- cut/copy source values --- */
d = dst->vals +dst->valcnt; /* get destination */
s = src->vals +off; /* and source pointers */
for (i = cnt; --i >= 0; s++, d++) {
hb = dst->htab[(*s)->hval % dst->valvsz];
for ( ; hb; hb = hb->succ) /* search value in destination */
if (strcmp((*s)->name, hb->name) == 0) break;
if (hb) continue; /* if value already exists, skip it */
*d = (VAL*)malloc(sizeof(VAL) +strlen((*s)->name) *sizeof(char));
if (!*d) break; /* allocate memory for a new value */
strcpy((*d)->name, (*s)->name);
(*d)->hval = (*s)->hval; /* copy value name and hash value */
} /* (the identifier is set later) */
if (i >= 0) { /* if an error occured */
for (i = (int)(d -(dst->vals +dst->valcnt)); --i > 0; )
free(*--d); /* delete all copied values */
return -1; /* and abort the function */
}
/* --- insert values into destination --- */
p = dst->vals +dst->valcnt; /* get pointer to first new value */
dst->valcnt += i = (int)(d-p);/* adapt number of values and */
dst->max.i += i; /* maximal value identifier */
while (--i >= 0) { /* traverse inserted values */
(*p)->id = (int)(p -dst->vals); /* set value identifier */
d = dst->htab +(*p)->hval % dst->valvsz;
(*p)->succ = *d; *d = *p++; /* insert value into the hash table */
}
dst->valwd[0] = -1; /* invalidate value widths */
att_resize(dst, 0); /* try to shrink the value vector */
return 0; /* return 'ok' */
} /* att_valcopy() */
/*--------------------------------------------------------------------*/
void att_valsort (ATT *att, VAL_CMPFN cmpfn, int *map, int dir)
{ /* --- sort attribute values */
VAL *curr; /* buffer for current value */
int i; /* loop variable */
VAL **p; /* to traverse the value vector */
VALCMP vc; /* buffer for comparison function */
assert(att && (att->type == AT_SYM)); /* check function arguments */
curr = (att->inst.i >= 0) /* note instance (current value) */
? att->vals[att->inst.i] : NULL;
vc.cmpfn = cmpfn; /* sort the attribute values */
v_sort(att->vals, att->valcnt, _valcmp, (void*)&vc);
if (map) { /* if an identifier map is requested, */
p = att->vals +(i = att->valcnt); /* traverse sorted vector */
if (dir < 0) /* if backward map (i.e. new -> old) */
while (--i >= 0) map[i] = (*--p)->id;
else /* if forward map (i.e. old -> new) */
while (--i >= 0) map[(*--p)->id] = i;
} /* (build identifier map) */
for (p = att->vals +(i = att->valcnt); --i >= 0; )
(*--p)->id = i; /* set new value identifiers */
if (curr) att->inst.i = curr->id;
} /* att_valsort() */ /* adapt instance (current value) */
/*--------------------------------------------------------------------*/
int att_valwd (ATT *att, int scform)
{ /* --- determine widths of values */
int i; /* loop variable */
VAL **p; /* to traverse values */
int w, sw; /* value name widths */
assert(att); /* check the function argument */
if (att->valwd[0] < 0) { /* if the value widths are invalid */
att->valwd[0] = att->valwd[1] = 0;
p = att->vals +att->valcnt; /* traverse attribute values */
for (i = att->valcnt; --i >= 0; ) {
w = sc_fmtlen((*--p)->name, &sw);
if (w > att->valwd[0]) att->valwd[0] = w;
if (sw > att->valwd[1]) att->valwd[1] = sw;
} /* determine maximal widths and */
} /* return width of widest value */
return att->valwd[(scform) ? 1 : 0];
} /* att_valwd() */
/*--------------------------------------------------------------------*/
int att_valid (const ATT *att, const char *name)
{ /* --- get the identifier of a value */
VAL *val; /* to traverse hash bucket */
assert(att /* check the function arguments */
&& name && (att->type == AT_SYM));
if (att->valcnt <= 0) return UV_SYM;
val = att->htab[_hash(name) % att->valvsz];
for ( ; val; val = val->succ) /* traverse hash bucket list */
if (strncmp(name, val->name, AS_MAXLEN) == 0)
break; /* if value found, abort loop */
return (val) ? val->id : UV_SYM;
} /* att_valid() */ /* return value identifier */
/*----------------------------------------------------------------------
Attribute Set Functions
----------------------------------------------------------------------*/
static int as_resize (ATTSET *set, int size)
{ /* --- resize attribute vector */
int i; /* loop variable */
ATT **p; /* to traverse attributes */
ATT **hb; /* to traverse hash bucket */
assert(set); /* check the function argument */
i = set->attvsz; /* get current vector size */
if (size > 0) { /* if to enlarge the vector */
if (i >= size) return 0; /* if vector is large enough, abort */
i += (i > BLKSIZE) ? i >> 1 : BLKSIZE;
if (i > size) size = i; } /* compute new vector size */
else { /* if to shrink the vector */
size = set->attcnt << 1; /* get maximal tolerable size */
if (size < BLKSIZE) size = BLKSIZE;
if (i <= size) return 0; /* if vector is small enough, abort */
size = set->attcnt +(set->attcnt >> 1);
if (size < BLKSIZE) size = BLKSIZE;
} /* compute new vector size */
p = (ATT**)realloc(set->atts, size *sizeof(ATT*));
if (!p) return -1; /* resize attribute vector */
set->atts = p; /* and set new vector */
hb = (ATT**)realloc(set->htab, size *sizeof(ATT*));
if (!hb) return -1; /* resize hash table */
set->htab = hb; /* and set new hash table */
set->attvsz = size; /* set new vector size */
for (i = size; --i >= 0; ) /* clear hash table */
hb[i] = NULL; /* and traverse attributes */
for (i = set->attcnt; --i >= 0; ) {
hb = set->htab +(*p)->hval % size;
(*p)->succ = *hb; /* get pointer to hash bucket and */
*hb = *p++; /* insert attribute into hash table */
} /* (at the head of the bucket list) */
return 0; /* return 'ok' */
} /* as_resize() */
/*--------------------------------------------------------------------*/
ATTSET* as_create (const char *name, ATT_DELFN delfn)
{ /* --- create an attribute set */
ATTSET *set; /* created attribute set */
assert(name && *name && delfn); /* check the function arguments */
set = (ATTSET*)malloc(sizeof(ATTSET));
if (!set) return NULL; /* allocate memory for an att. set */
set->name = (char*)malloc((_length(name) +1) *sizeof(char));
if (!set->name) { free(set); return NULL; }
_copy(set->name, name); /* copy attribute set name */
set->atts = set->htab = NULL;
set->attcnt = set->attvsz = 0;
set->delfn = delfn; /* initialize fields */
set->weight = 1.0F;
#if defined AS_FLDS || defined AS_RDWR
set->fldvsz = set->fldcnt = 0;
set->flds = NULL; /* clear field map */
#endif
#ifdef AS_RDWR /* if to compile read/write functions */
set->chars[0] = ' '; /* blank character */
set->chars[1] = ' '; /* field separator */
set->chars[2] = '\n'; /* record separator */
set->chars[3] = '?'; /* unknown value character */
set->chars[4] = 0;
set->tfscan = tfs_create(); /* create table file scanner */
if (!set->tfscan) { as_delete(set); return NULL; }
set->err = tfs_err(set->tfscan);
set->err->s = set->buf; /* initialize the error information */
tfs_chars(set->tfscan, TFS_OTHER, "?");
#endif /* set '?' as unknown value character */
return set; /* return created attribute set */
} /* as_create() */
/*--------------------------------------------------------------------*/
ATTSET* as_dup (const ATTSET *set)
{ /* --- duplicate an attribute set */
ATTSET *dup; /* created duplicate */
#if defined AS_FLDS || defined AS_RDWR
int i; /* loop variable */
int *d; const int *s; /* to traverse the field vector */
#endif
assert(set); /* check the function argument */
dup = as_create(set->name, set->delfn);
if (!dup) return NULL; /* create a new attribute set */
if (as_attcopy(dup, set, 0) != 0) { as_delete(dup); return NULL; }
dup->weight = set->weight; /* copy all attributes and */
dup->info = set->info; /* all other information */
#if defined AS_FLDS || defined AS_RDWR
if (set->flds) { /* if there is a field vector */
dup->flds = (int*)malloc(set->fldvsz *sizeof(int));
if (!dup->flds) { as_delete(dup); return NULL; }
s = set->flds +set->fldcnt; /* create a field vector and */
d = dup->flds +set->fldcnt; /* copy the source field vector */
for (i = set->fldcnt; --i >= 0; ) *--d = *--s;
}
#endif
#ifdef AS_RDWR /* if to compile read/write functions */
for (i = 4; --i >= 0; ) dup->chars[i] = set->chars[i];
dup->chars[4] = 0; /* copy chars. and table file scanner */
tfs_copy(dup->tfscan, set->tfscan);
#endif
return dup; /* return created duplicate */
} /* as_dup() */
/*--------------------------------------------------------------------*/
void as_delete (ATTSET *set)
{ /* --- delete an attribute set */
int i; /* loop variable */
ATT **p; /* to traverse the attribute vector */
assert(set); /* check the function argument */
if (set->atts) { /* if there are attributes, */
for (p = set->atts +(i = set->attcnt); --i >= 0; ) {
(*--p)->set = NULL; (*p)->id = -1; set->delfn(*p); }
free(set->atts); /* delete attributes, vector, */
} /* and hash table */
if (set->htab) free(set->htab);
#if defined AS_FLDS || defined AS_RDWR
if (set->flds) free(set->flds);
#endif /* delete field map */
#ifdef AS_RDWR /* if to compile read/write functions */
if (set->tfscan) tfs_delete(set->tfscan);
#endif /* delete table file scanner */
free(set->name); /* delete attribute set name */
free(set); /* and attribute set body */
} /* as_delete() */
/*--------------------------------------------------------------------*/
int as_rename (ATTSET *set, const char *name)
{ /* --- rename an attribute set */
char *t; /* temporary buffer for name */
assert(set && name && *name); /* check the function arguments */
t = (char*)realloc(set->name, (_length(name) +1) *sizeof(char));
if (!t) return -1; /* reallocate memory block */
set->name = _copy(t, name); /* and copy the new name */
return 0; /* return 'ok' */
} /* as_rename() */
/*--------------------------------------------------------------------*/
int as_cmp (const ATTSET *set1, const ATTSET *set2)
{ /* --- compare two attribute sets */
int i; /* loop variable, attribute index */
ATT **p1, **p2; /* to traverse attributes */
assert(set1 && set2); /* check the function arguments */
if (set1->attcnt != set2->attcnt)
return 1; /* compare number of attributes */
p1 = set1->atts +set1->attcnt;/* traverse all attributes */
p2 = set2->atts +set1->attcnt;/* and compare them */
for (i = set1->attcnt; --i >= 0; )
if (att_cmp(*--p1, *--p2) != 0)
return 1; /* if an attribute differs, abort */
return 0; /* otherwise return 'equal' */
} /* as_cmp() */
/*--------------------------------------------------------------------*/
int as_attadd (ATTSET *set, ATT *att)
{ /* --- add one attribute */
ATT **p, *hb; /* to traverse the hash bucket */
assert(set && att); /* check the function arguments */
if (as_resize(set, set->attcnt +1) != 0)
return -1; /* resize the attribute vector */
p = set->htab +att->hval % set->attvsz;
for (hb = *p; hb; hb = hb->succ) /* traverse hash bucket list */
if (strcmp(att->name, hb->name) == 0)
return 1; /* if name already exists, abort */
if (att->set) /* remove attribute from old set */
as_attrem(att->set, att->id);
att->set = set; /* set containing attribute set */
att->id = set->attcnt; /* and attribute identifier */
att->succ = *p; *p = att; /* insert attribute into hash table */
set->atts[set->attcnt++] = att; /* and attribute vector */
return 0; /* return 'ok' */
} /* as_attadd() */
/*--------------------------------------------------------------------*/
int as_attaddm (ATTSET *set, ATT **atts, int cnt)
{ /* --- add several attributes */
int i; /* loop variable */
ATT **p, *hb; /* to traverse the hash bucket */
ATT *att; /* buffer for attribute */
assert(set && atts && (cnt >= 0)); /* check function arguments */
if (as_resize(set, set->attcnt +cnt) != 0)
return -1; /* resize the attribute vector */
for (i = cnt; --i >= 0; ) { /* traverse new attributes */
att = atts[i]; /* get next attribute */
hb = (ATT*)set->htab[att->hval % set->attvsz];
for ( ; hb; hb = hb->succ) /* traverse hash bucket list */
if (strcmp(att->name, hb->name) == 0)
return -2; /* if name already exists, */
} /* abort the function */
for (i = cnt; --i >= 0; ) { /* traverse new attributes again */
att = *atts++; /* get next attribute and */
if (att->set) /* remove it from old set */
as_attrem(att->set, att->id);
att->set = set; /* set containing attribute set */
att->id = set->attcnt; /* and attribute identifier */
set->atts[set->attcnt++] = att;
p = set->htab +att->hval % set->attvsz;
att->succ = *p; *p = att; /* insert attribute into */
} /* attribute vector and hash table */
return 0; /* return 'ok' */
} /* as_attaddm() */
/*--------------------------------------------------------------------*/
ATT* as_attrem (ATTSET *set, int attid)
{ /* --- remove an attribute */
ATT **p; /* to traverse attribute vector */
ATT **hb; /* to traverse hash bucket */
ATT *att; /* buffer for removed attribute */
assert(set && (attid < set->attcnt)); /* check function arguments */
/* --- remove all attributes --- */
if (attid < 0) { /* if no attribute identifier given */
if (!set->atts) return NULL;/* if there are no attributes, abort */
for (p = set->atts +(attid = set->attcnt); --attid >= 0; ) {
(*--p)->set = NULL; (*p)->id = -1;
set->delfn(*p); /* delete all attributes */
}
free(set->atts); free(set->htab);
set->atts = set->htab = NULL;
set->attcnt = set->attvsz = 0;
return NULL; /* delete att. vector and hash table, */
} /* clear size and counter and abort */
/* --- remove one attribute --- */
p = set->atts +attid; att = *p; /* get the attribute to remove */
hb = set->htab +att->hval % set->attvsz;
while (*hb != att) hb = &(*hb)->succ;
*hb = att->succ; /* remove att. from the hash table */
att->set = NULL; /* clear reference to containing set */
att->id = -1; /* and attribute identifier */
for (attid = --set->attcnt -attid; --attid >= 0; ) {
*p = p[1]; (*p++)->id--; } /* shift atts. and adapt identifiers */
as_resize(set, 0); /* try to shrink attribute vector */
_delflds(set); /* and delete the field map */
return att; /* return removed attribute */
} /* as_attrem() */
/*--------------------------------------------------------------------*/
void as_attexg (ATTSET *set, int attid1, int attid2)
{ /* --- exchange two attributes */
ATT **p1, **p2, *att; /* temporary buffers */
assert(set /* check the function arguments */
&& (attid1 >= 0) && (attid1 < set->attcnt)
&& (attid2 >= 0) && (attid2 < set->attcnt));
p1 = set->atts +attid1; att = *p1;
p2 = set->atts +attid2; /* get pointers to attributes, */
*p1 = *p2; (*p1)->id = attid1;/* exchange them, and */
*p2 = att; att->id = attid2;/* set new identifiers */
_delflds(set); /* delete field map */
} /* as_attexg() */
/*--------------------------------------------------------------------*/
void as_attmove (ATTSET *set, int off, int cnt, int pos)
{ /* --- move some attributes */
int n; /* temporary buffer */
ATT **p; /* to traverse attributes */
assert(set); /* check the function argument */
n = set->attcnt; /* check and adapt insert position */
if (pos > n) pos = n; /* and number of attributes */
if (cnt > n -off) cnt = n -off;
assert((cnt >= 0) && (off >= 0)
&& (pos >= 0) && ((pos <= off) || (pos >= off +cnt)));
v_move(set->atts, off, cnt, pos, (int)sizeof(ATT*));
if (pos <= off) { /* move attributes in vector */
cnt += off; off = pos; pos = cnt; }
p = set->atts +off; /* set new attribute identifiers */
while (off < pos) (*p++)->id = off++;
_delflds(set); /* delete field map */
} /* as_attmove() */
/*--------------------------------------------------------------------*/
int as_attcut (ATTSET *dst, ATTSET *src, int mode, ...)
{ /* --- cut/copy attributes */
va_list args; /* list of variable arguments */
int i; /* loop variable, buffer */
int off, cnt; /* range of attributes */
ATT **s, **r; /* to traverse source attributes */
ATT **d, **p; /* to traverse dest. attributes */
ATT *hb; /* to traverse hash bucket list */
ATT_SELFN *selfn = 0; /* attribute selection function */
void *data = NULL; /* attribute selection data */
assert(src); /* check the function arguments */
/* --- get range of attributes --- */
va_start(args, mode); /* start variable argument evaluation */
if (mode & AS_RANGE) { /* if an index range is given */
off = va_arg(args, int); /* get offset to first attribute */
cnt = va_arg(args, int); /* and number of attributes */
i = src->attcnt -off; /* check and adapt */
if (cnt > i) cnt = i; /* number of attributes */
assert((off >= 0) && (cnt >= 0)); }
else { /* if no index range given */
off = 0; cnt = src->attcnt; /* get full index range */
}
if (mode & AS_SELECT) { /* if to select atts. by a function */
selfn = va_arg(args, ATT_SELFN*);
data = va_arg(args, void*);/* get attribute selection function */
} /* and attribute selection data */
va_end(args); /* end variable argument evaluation */
if (cnt <= 0) return 0; /* if range is empty, abort */
if (dst && (as_resize(dst, dst->attcnt +cnt) != 0))
return -1; /* resize vector and hash table */
/* --- cut source attributes --- */
d = (dst) ? dst->atts +dst->attcnt : NULL;
s = r = src->atts +off; /* get destination and source */
for (i = cnt; --i >= 0; s++){ /* traverse the values in range */
if (((mode & AS_MARKED) /* if in marked mode */
&& ((*s)->mark < 0)) /* and attribute is not marked */
|| ((mode & AS_SELECT) /* or in selection mode */
&& (!selfn(*s, data)))) { /* and attribute does not qualify, */
(*s)->id = (int)(r -src->atts); /* set new attribute id. */
*r++ = *s; continue; /* and shift down/left attribute */
} /* otherwise (if to cut attribute) */
p = src->htab +(*s)->hval % src->attvsz;
while (*p != *s) p = &(*p)->succ;
*p = (*p)->succ; /* remove att. from the hash table */
if (dst) { /* if there is a destination */
hb = dst->htab[(*s)->hval % dst->attvsz];
for (; hb; hb = hb->succ) /* search attribute in destination */
if (strcmp((*s)->name, hb->name) == 0) break;
if (!hb) { *d++ = *s; continue; }
} /* if attribute does not exist, */
(*s)->set = NULL; (*s)->id = -1; /* store it, */
src->delfn(*s); /* otherwise delete the attribute */
}
for (i = src->attcnt -off -cnt; --i >= 0; ) {
(*s)->id = (int)(r -src->atts); *r++ = *s++;
} /* shift down/left rem. attributes */
src->attcnt = (int)(r -src->atts); /* set new number of values */
as_resize(src, 0); /* try to shrink the attribute vector */
_delflds(src); /* and delete the field map */
/* --- insert attributes into destination --- */
if (dst) { /* if there is a destination */
s = dst->atts +dst->attcnt; /* get first new attribute and */
dst->attcnt += i = (int)(d -s); /* adapt number of attributes */
while (--i >= 0) { /* traverse inserted attributes */
p = dst->htab +(*s)->hval % dst->attvsz;
(*s)->succ = *p; *p = *s; /* insert attribute into hash table */
(*s)->id = (int)(s -dst->atts); /* set attribute identifier */
(*s)->set = dst; s++; /* and attribute set reference */
}
as_resize(dst, 0); /* try to shrink the attribute vector */
}
return 0; /* return 'ok' */
} /* as_attcut() */
/*--------------------------------------------------------------------*/
int as_attcopy (ATTSET *dst, const ATTSET *src, int mode, ...)
{ /* --- cut/copy attributes */
va_list args; /* list of variable arguments */
int i; /* loop variable, buffer */
int off, cnt; /* range of attributes */
ATT *const*s; /* to traverse source attributes */
ATT **d, **p; /* to traverse dest. attributes */
ATT *hb; /* to traverse hash bucket list */
ATT_SELFN *selfn = 0; /* attribute selection function */
void *data = NULL; /* attribute selection data */
assert(src && dst); /* check the function arguments */
/* --- get range of attributes --- */
va_start(args, mode); /* start variable argument evaluation */
if (mode & AS_RANGE) { /* if an index range is given */
off = va_arg(args, int); /* get offset to first attribute */
cnt = va_arg(args, int); /* and number of attributes */
i = src->attcnt -off; /* check and adapt */
if (cnt > i) cnt = i; /* number of attributes */
assert((off >= 0) && (cnt >= 0)); }
else { /* if no index range given */
off = 0; cnt = src->attcnt; /* get full index range */
}
if (mode & AS_SELECT) { /* if to select atts. by a function */
selfn = va_arg(args, ATT_SELFN*);
data = va_arg(args, void*);/* get attribute selection function */
} /* and attribute selection data */
va_end(args); /* end variable argument evaluation */
if (cnt <= 0) return 0; /* if range is empty, abort */
if (as_resize(dst, dst->attcnt +cnt) != 0)
return -1; /* resize vector and hash table */
/* --- copy source attributes --- */
d = dst->atts +dst->attcnt; /* get destination and */
s = src->atts +off; /* source attributes */
for (i = cnt; --i >= 0; s++){ /* traverse the values in range */
if (((mode & AS_MARKED) /* if in marked mode */
&& ((*s)->mark < 0)) /* and attribute is not marked */
|| ((mode & AS_SELECT) /* or in selection mode */
&& (!selfn(*s, data)))) /* and attribute does not qualify, */
continue; /* skip this attribute */
hb = dst->htab[(*s)->hval % dst->attvsz];
for ( ; hb; hb = hb->succ) /* search attribute in destination */
if (strcmp((*s)->name, hb->name) == 0) break;
if (hb) continue; /* if attribute exists, skip it */
*d = att_dup(*s); /* otherwise duplicate */
if (!*d) break; d++; /* the source attribute */
}
if (i >= 0) { /* if an error occured */
for (i = (int)(d -(dst->atts +dst->attcnt)); --i > 0; )
att_delete(*--d); /* delete all copied attributes */
return -1; /* and abort the function */
}
/* --- insert attributes into destination --- */
p = dst->atts +dst->attcnt; /* get first new attribute and */
dst->attcnt += i = (int)(d-p);/* adapt number of attributes */
while (--i >= 0) { /* traverse inserted attributes */
d = dst->htab +(*p)->hval % dst->attvsz;
(*p)->succ = *d; *d = *p; /* insert attribute into hash table */
(*p)->id = (int)(p -dst->atts); /* set attribute identifier */
(*p)->set = dst; p++; /* and attribute set reference */
}
as_resize(dst, 0); /* try to shrink the attribute vector */
return 0; /* return 'ok' */
} /* as_attcopy() */
/*--------------------------------------------------------------------*/
int as_attid (const ATTSET *set, const char *name)
{ /* --- get the id of an attribute */
ATT *att; /* to traverse hash bucket list */
assert(set && name); /* check the function arguments */
if (set->attcnt <= 0) return -1;
att = set->htab[_hash(name) % set->attvsz];
for ( ; att; att = att->succ) /* traverse hash bucket list */
if (strncmp(name, att->name, AS_MAXLEN) == 0)
break; /* if attribute found, abort loop */
return (att) ? att->id : -1; /* return attribute identifier */
} /* as_attid() */
/*--------------------------------------------------------------------*/
void as_apply (ATTSET *set, ATT_APPFN appfn, void *data)
{ /* --- apply a function to all atts. */
int i; /* loop variable */
ATT **p; /* to traverse attribute vector */
assert(set && appfn); /* check the function arguments */
for (p = set->atts +(i = set->attcnt); --i >= 0; )
appfn(*--p, data); /* apply function to all attributes */
} /* as_apply() */