forked from github/server
287 lines
5.7 KiB
C
287 lines
5.7 KiB
C
/* vi: set ts=2:
|
|
*
|
|
* $Id: attrib.c,v 1.3 2001/01/27 18:15:32 enno Exp $
|
|
* Eressea PB(E)M host Copyright (C) 1998-2000
|
|
* Christian Schlittchen (corwin@amber.kn-bremen.de)
|
|
* Katja Zedel (katze@felidae.kn-bremen.de)
|
|
* Henning Peters (faroul@beyond.kn-bremen.de)
|
|
* Enno Rehling (enno@eressea-pbem.de)
|
|
* Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
|
|
*
|
|
* This program may not be used, modified or distributed without
|
|
* prior permission by the authors of Eressea.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include "attrib.h"
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#define MAXATHASH 63
|
|
attrib_type * at_hash[MAXATHASH];
|
|
|
|
static unsigned int
|
|
__at_hashkey(const char* s)
|
|
{
|
|
int key = 0;
|
|
int i = strlen(s);
|
|
|
|
while (i) {
|
|
--i;
|
|
key = ((key & 1) << 31) ^ (key >> 1) ^ s[i];
|
|
}
|
|
return key & 0x7fffffff;
|
|
}
|
|
|
|
void
|
|
at_register(attrib_type * at)
|
|
{
|
|
attrib_type * find;
|
|
|
|
at->hashkey = __at_hashkey(at->name);
|
|
find = at_hash[at->hashkey % MAXATHASH];
|
|
while (find && at->hashkey!=find->hashkey) find = find->nexthash;
|
|
if (find && find==at) {
|
|
fprintf(stderr, "WARNING: attribute '%s' was registered more than once\n", at->name);
|
|
return;
|
|
} else {
|
|
assert(!find || !"hashkey is already in use");
|
|
}
|
|
at->nexthash = at_hash[at->hashkey % MAXATHASH];
|
|
at_hash[at->hashkey % MAXATHASH] = at;
|
|
}
|
|
|
|
static attrib_type *
|
|
at_find(unsigned int hk)
|
|
{
|
|
const char* translate[3][2] = {
|
|
{ "zielregion", "targetregion" }, /* remapping: früher zielregion, heute targetregion */
|
|
{ "verzaubert", "curse" }, /* remapping: früher verzaubert, jetzt curse */
|
|
{ NULL, NULL }
|
|
};
|
|
attrib_type * find = at_hash[hk % MAXATHASH];
|
|
while (find && hk!=find->hashkey) find = find->nexthash;
|
|
if (!find) {
|
|
int i = 0;
|
|
while (translate[i][0]) {
|
|
if (__at_hashkey(translate[i][0])==hk)
|
|
return at_find(__at_hashkey(translate[i][1]));
|
|
++i;
|
|
}
|
|
}
|
|
return find;
|
|
}
|
|
|
|
attrib *
|
|
a_select(attrib * a, void * data, boolean(*compare)(const attrib *, void *))
|
|
{
|
|
attrib * find = a;
|
|
while (find && !compare(find, data)) find = find->next;
|
|
return find;
|
|
}
|
|
|
|
attrib *
|
|
a_find(attrib * a, const attrib_type * at) {
|
|
attrib * find = a;
|
|
while (find && find->type!=at) find = find->next;
|
|
return find;
|
|
}
|
|
|
|
attrib *
|
|
a_add(attrib ** pa, attrib * a) {
|
|
attrib ** find = pa;
|
|
assert(a->next==NULL && a->nexttype==NULL);
|
|
while (*find && (*find)->type!=a->type) find = &(*find)->next;
|
|
if (a->type->flags & ATF_PRESERVE) {
|
|
while (*find) find = &(*find)->nexttype;
|
|
}
|
|
if (a->type->flags & ATF_UNIQUE && *find) {
|
|
if ((*find)->type == a->type) {
|
|
/* fprintf(stderr, "duplicate attribute: %s\n", a->type->name); */
|
|
return a;
|
|
}
|
|
}
|
|
if (*find) {
|
|
attrib ** last = find;
|
|
while (*last) last = &(*last)->nexttype;
|
|
*last = a;
|
|
while (*find && (*find)->type==a->type) find = &(*find)->next;
|
|
}
|
|
a->next = *find;
|
|
*find = a;
|
|
return a;
|
|
}
|
|
|
|
void
|
|
a_free(attrib * a) {
|
|
const attrib_type * at = a->type;
|
|
if (at->finalize) at->finalize(a);
|
|
free(a);
|
|
}
|
|
|
|
static int
|
|
a_unlink(attrib ** p, attrib * a) {
|
|
attrib ** pa = p;
|
|
while (*pa && *pa!=a) pa = &(*pa)->next;
|
|
if (*pa) {
|
|
attrib ** pnt;
|
|
for (pnt=p;*pnt;pnt=&(*pnt)->next)
|
|
if ((*pnt)->nexttype == a) {
|
|
(*pnt)->nexttype = a->nexttype;
|
|
break;
|
|
}
|
|
*pa = (*pa)->next;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
a_remove(attrib ** p, attrib * a) {
|
|
int ok;
|
|
ok = a_unlink(p, a);
|
|
if( ok ) a_free(a);
|
|
return ok;
|
|
}
|
|
|
|
void
|
|
a_removeall(attrib **p, const attrib_type * at)
|
|
{
|
|
attrib *find = *p, *findnext;
|
|
while(find && find->type == at) {
|
|
findnext = find->next;
|
|
a_remove(p, find);
|
|
find = findnext;
|
|
}
|
|
}
|
|
|
|
attrib *
|
|
a_new(const attrib_type * at) {
|
|
attrib * a = calloc(1, sizeof(attrib));
|
|
a->type = at;
|
|
if (at->initialize) at->initialize(a);
|
|
return a;
|
|
}
|
|
|
|
int
|
|
a_readdefault(attrib * a, FILE * f)
|
|
{
|
|
assert(sizeof(int)==sizeof(a->data));
|
|
fscanf(f, "%d", &a->data.i);
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
a_writedefault(const attrib * a, FILE * f)
|
|
{
|
|
fprintf(f, "%d ", a->data.i);
|
|
}
|
|
|
|
static char *
|
|
read_quoted(FILE * f, char *c, size_t size)
|
|
{
|
|
char * s = c;
|
|
do {
|
|
*s = (char) fgetc(f);
|
|
} while (*s!='"');
|
|
|
|
for (;;) {
|
|
*s = (char) fgetc(f);
|
|
if (*s=='"') break;
|
|
if (s<c+size) ++s;
|
|
}
|
|
*s = 0;
|
|
return c;
|
|
}
|
|
|
|
int
|
|
a_readstring(attrib * a, FILE * f)
|
|
{
|
|
char zText[4096];
|
|
read_quoted(f, zText, sizeof(zText));
|
|
a->data.v = strdup(zText);
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
a_writestring(const attrib * a, FILE * f)
|
|
{
|
|
assert(a->data.v);
|
|
fprintf(f, "\"%s\" ", (char*)a->data.v);
|
|
}
|
|
|
|
void
|
|
a_finalizestring(attrib * a)
|
|
{
|
|
free(a->data.v);
|
|
}
|
|
|
|
int
|
|
a_age(attrib ** p)
|
|
{
|
|
attrib ** ap = p;
|
|
/* Attribute altern, und die Entfernung (age()==0) eines Attributs
|
|
* hat Einfluß auf den Besitzer */
|
|
while(*ap) {
|
|
attrib * a = *ap;
|
|
if(a->type->age && a->type->age(a)==0) a_remove(p, a);
|
|
else ap=&a->next;
|
|
}
|
|
return (*p!=NULL);
|
|
}
|
|
|
|
void
|
|
a_read(FILE * f, attrib ** attribs)
|
|
{
|
|
int key;
|
|
char zText[128];
|
|
strcpy(zText, "unknown");
|
|
|
|
key = -1;
|
|
fscanf(f, "%s", zText);
|
|
if (!strcmp(zText, "end")) return;
|
|
/* { fgets(zText, sizeof(zText), f); ENNO: was ist das? "always ends with \n" ? */
|
|
/* key=-1; }*/
|
|
else key = __at_hashkey(zText);
|
|
|
|
while(key!=-1) {
|
|
attrib_type * at = at_find(key);
|
|
attrib * na;
|
|
if (!at) {
|
|
fprintf(stderr, "attribute hash: %d (%s)\n", key, zText);
|
|
assert(at || !"attribute not registered");
|
|
}
|
|
if (at->read) {
|
|
na = a_new(at);
|
|
if (at->read(na, f))
|
|
a_add(attribs, na);
|
|
else
|
|
a_free(na);
|
|
} else {
|
|
assert(!"fehler: keine laderoutine für attribut");
|
|
}
|
|
|
|
fscanf(f, " %s", zText);
|
|
if (!strcmp(zText, "end")) break;
|
|
key = __at_hashkey(zText);
|
|
}
|
|
}
|
|
|
|
void
|
|
a_write(FILE * f, const attrib * attribs)
|
|
{
|
|
const attrib * na = attribs;
|
|
|
|
while(na) {
|
|
if (na->type->write) {
|
|
assert(na->type->hashkey || !"attribute not registered");
|
|
fprintf(f, "%s ", na->type->name);
|
|
na->type->write(na, f);
|
|
putc(' ', f);
|
|
}
|
|
na = na->next;
|
|
}
|
|
fprintf(f, "end");
|
|
}
|