server/src/util/attrib.c

326 lines
7.4 KiB
C
Raw Normal View History

2010-08-08 10:06:34 +02:00
/*
Copyright (c) 1998-2010, Enno Rehling <enno@eressea.de>
Katja Zedel <katze@felidae.kn-bremen.de
Christian Schlittchen <corwin@amber.kn-bremen.de>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#include <platform.h>
#include "attrib.h"
#include "log.h"
#include "storage.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#define MAXATHASH 61
2011-03-07 08:02:35 +01:00
attrib_type *at_hash[MAXATHASH];
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
static unsigned int __at_hashkey(const char *s)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
int key = 0;
size_t i = strlen(s);
while (i > 0) {
key = (s[--i] + key * 37);
}
return key & 0x7fffffff;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
void at_register(attrib_type * at)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
attrib_type *find;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
if (at->read == NULL) {
log_warning("registering non-persistent attribute %s.\n", at->name);
2010-08-08 10:06:34 +02:00
}
at->hashkey = __at_hashkey(at->name);
find = at_hash[at->hashkey % MAXATHASH];
2011-03-07 08:02:35 +01:00
while (find && at->hashkey != find->hashkey)
find = find->nexthash;
if (find && find == at) {
log_warning("attribute '%s' was registered more than once\n", at->name);
2010-08-08 10:06:34 +02:00
return;
} else {
assert(!find || !"hashkey is already in use");
}
at->nexthash = at_hash[at->hashkey % MAXATHASH];
at_hash[at->hashkey % MAXATHASH] = at;
}
2011-03-07 08:02:35 +01:00
static attrib_type *at_find(unsigned int hk)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const char *translate[3][2] = {
{"zielregion", "targetregion"}, /* remapping: from 'zielregion, heute targetregion */
{"verzaubert", "curse"}, /* remapping: fr<66>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;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
attrib *a_select(attrib * a, const void *data,
boolean(*compare) (const attrib *, const void *))
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
while (a && !compare(a, data))
a = a->next;
return a;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
attrib *a_find(attrib * a, const attrib_type * at)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
while (a && a->type != at)
a = a->nexttype;
return a;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
const attrib *a_findc(const attrib * a, const attrib_type * at)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
while (a && a->type != at)
a = a->nexttype;
return a;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static attrib *a_insert(attrib * head, attrib * a)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
attrib **pa = &head->next;
2010-08-08 10:06:34 +02:00
assert(!(a->type->flags & ATF_UNIQUE));
2011-03-07 08:02:35 +01:00
assert(head && head->type == a->type);
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
while (*pa && (*pa)->type == a->type) {
2010-08-08 10:06:34 +02:00
pa = &(*pa)->next;
}
a->next = *pa;
return *pa = a;
}
2011-03-07 08:02:35 +01:00
attrib *a_add(attrib ** pa, attrib * a)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
attrib *first = *pa;
assert(a->next == NULL && a->nexttype == NULL);
if (first == NULL)
return *pa = a;
if (first->type == a->type) {
2010-08-08 10:06:34 +02:00
return a_insert(first, a);
}
for (;;) {
2011-03-07 08:02:35 +01:00
attrib *next = first->nexttype;
if (next == NULL) {
2010-08-08 10:06:34 +02:00
/* the type is not in the list, append it behind the last type */
2011-03-07 08:02:35 +01:00
attrib **insert = &first->next;
2010-08-08 10:06:34 +02:00
first->nexttype = a;
2011-03-07 08:02:35 +01:00
while (*insert)
insert = &(*insert)->next;
2010-08-08 10:06:34 +02:00
*insert = a;
break;
}
2011-03-07 08:02:35 +01:00
if (next->type == a->type) {
2010-08-08 10:06:34 +02:00
return a_insert(next, a);
}
first = next;
}
return a;
}
2011-03-07 08:02:35 +01:00
void a_free(attrib * a)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const attrib_type *at = a->type;
if (at->finalize)
at->finalize(a);
free(a);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static int a_unlink(attrib ** pa, attrib * a)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
attrib **pnexttype = pa;
attrib **pnext = NULL;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
assert(a != NULL);
2010-08-08 10:06:34 +02:00
while (*pnexttype) {
2011-03-07 08:02:35 +01:00
attrib *next = *pnexttype;
if (next->type == a->type)
break;
2010-08-08 10:06:34 +02:00
pnexttype = &next->nexttype;
pnext = &next->next;
}
2011-03-07 08:02:35 +01:00
if (*pnexttype && (*pnexttype)->type == a->type) {
if (*pnexttype == a) {
2010-08-08 10:06:34 +02:00
*pnexttype = a->next;
2011-03-07 08:02:35 +01:00
if (a->next != a->nexttype) {
2010-08-08 10:06:34 +02:00
a->next->nexttype = a->nexttype;
}
2011-03-07 08:02:35 +01:00
if (pnext == NULL)
return 1;
while (*pnext && (*pnext)->type != a->type)
pnext = &(*pnext)->next;
2010-08-08 10:06:34 +02:00
} else {
pnext = &(*pnexttype)->next;
}
2011-03-07 08:02:35 +01:00
while (*pnext && (*pnext)->type == a->type) {
if (*pnext == a) {
2010-08-08 10:06:34 +02:00
*pnext = a->next;
return 1;
}
pnext = &(*pnext)->next;
}
}
return 0;
}
2011-03-07 08:02:35 +01:00
int a_remove(attrib ** pa, attrib * a)
2010-08-08 10:06:34 +02:00
{
int ok;
2011-03-07 08:02:35 +01:00
assert(a != NULL);
2010-08-08 10:06:34 +02:00
ok = a_unlink(pa, a);
2011-03-07 08:02:35 +01:00
if (ok)
a_free(a);
2010-08-08 10:06:34 +02:00
return ok;
}
2011-03-07 08:02:35 +01:00
void a_removeall(attrib ** pa, const attrib_type * at)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
attrib **pnexttype = pa;
attrib **pnext = NULL;
2010-08-08 10:06:34 +02:00
while (*pnexttype) {
2011-03-07 08:02:35 +01:00
attrib *next = *pnexttype;
if (next->type == at)
break;
2010-08-08 10:06:34 +02:00
pnexttype = &next->nexttype;
pnext = &next->next;
}
2011-03-07 08:02:35 +01:00
if (*pnexttype && (*pnexttype)->type == at) {
attrib *a = *pnexttype;
2010-08-08 10:06:34 +02:00
*pnexttype = a->nexttype;
if (pnext) {
2011-03-07 08:02:35 +01:00
while (*pnext && (*pnext)->type != at)
pnext = &(*pnext)->next;
2010-08-08 10:06:34 +02:00
*pnext = a->nexttype;
}
2011-03-07 08:02:35 +01:00
while (a && a->type == at) {
attrib *ra = a;
2010-08-08 10:06:34 +02:00
a = a->next;
a_free(ra);
}
}
}
2011-03-07 08:02:35 +01:00
attrib *a_new(const attrib_type * at)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
attrib *a = (attrib *) calloc(1, sizeof(attrib));
assert(at != NULL);
a->type = at;
if (at->initialize)
at->initialize(a);
return a;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int a_age(attrib ** p)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
attrib **ap = p;
/* Attribute altern, und die Entfernung (age()==0) eines Attributs
* hat Einflu<EFBFBD> auf den Besitzer */
while (*ap) {
attrib *a = *ap;
if (a->type->age) {
int result = a->type->age(a);
assert(result >= 0 || !"age() returned a negative value");
if (result == 0) {
a_remove(p, a);
continue;
}
}
ap = &a->next;
}
return (*p != NULL);
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int a_read(struct storage *store, attrib ** attribs, void *owner)
2010-08-08 10:06:34 +02:00
{
int key, retval = AT_READ_OK;
char zText[128];
zText[0] = 0;
2010-08-08 10:06:34 +02:00
key = -1;
store->r_tok_buf(store, zText, sizeof(zText));
2011-03-07 08:02:35 +01:00
if (strcmp(zText, "end") == 0)
return retval;
else
key = __at_hashkey(zText);
while (key != -1) {
attrib_type *at = at_find(key);
2010-08-08 10:06:34 +02:00
if (!at) {
fprintf(stderr, "attribute hash: %d (%s)\n", key, zText);
assert(at || !"attribute not registered");
}
if (at->read) {
2011-03-07 08:02:35 +01:00
attrib *na = a_new(at);
2010-08-08 10:06:34 +02:00
int i = at->read(na, owner, store);
switch (i) {
case AT_READ_OK:
a_add(attribs, na);
break;
case AT_READ_FAIL:
retval = AT_READ_FAIL;
a_free(na);
break;
default:
assert(!"invalid return value");
break;
}
} else {
assert(!"fehler: keine laderoutine f<>r attribut");
}
store->r_tok_buf(store, zText, sizeof(zText));
2011-03-07 08:02:35 +01:00
if (!strcmp(zText, "end"))
break;
2010-08-08 10:06:34 +02:00
key = __at_hashkey(zText);
}
return retval;
}
2011-03-07 08:02:35 +01:00
void a_write(struct storage *store, const attrib * attribs, const void *owner)
2010-08-08 10:06:34 +02:00
{
2011-03-07 08:02:35 +01:00
const attrib *na = attribs;
2010-08-08 10:06:34 +02:00
2011-03-07 08:02:35 +01:00
while (na) {
2010-08-08 10:06:34 +02:00
if (na->type->write) {
assert(na->type->hashkey || !"attribute not registered");
store->w_tok(store, na->type->name);
na->type->write(na, owner, store);
na = na->next;
} else {
na = na->nexttype;
}
}
store->w_tok(store, "end");
}