2015-07-06 21:31:27 +02:00
/*
2015-01-30 22:10:29 +01:00
Copyright ( c ) 1998 - 2015 , Enno Rehling < enno @ eressea . de >
2014-10-18 14:16:26 +02:00
Katja Zedel < katze @ felidae . kn - bremen . de
Christian Schlittchen < corwin @ amber . kn - bremen . de >
2010-08-08 10:06:34 +02:00
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"
2012-06-17 20:08:48 +02:00
# include <critbit.h>
2010-08-08 10:06:34 +02:00
# include <assert.h>
# include <string.h>
# include <stdlib.h>
# define MAXATHASH 61
2014-10-18 14:16:26 +02:00
static 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
{
2014-10-18 14:16:26 +02:00
int key = 0 ;
size_t i = strlen ( s ) ;
2011-03-07 08:02:35 +01:00
2014-10-18 14:16:26 +02:00
while ( i > 0 ) {
key = ( s [ - - i ] + key * 37 ) ;
}
2015-07-12 10:35:09 +02:00
return key & 0x7fffffff ; //TODO: V112 http://www.viva64.com/en/V112 Dangerous magic number 0x7fffffff used: 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
{
2014-10-18 14:16:26 +02:00
attrib_type * find ;
if ( at - > read = = NULL ) {
2015-07-12 10:35:09 +02:00
log_warning ( " registering non-persistent attribute %s. \n " , at - > name ) ; //TODO: V111 http://www.viva64.com/en/V111 Call of function 'log_warning' with variable number of arguments. Second argument has memsize type.
2014-10-18 14:16:26 +02:00
}
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 ) {
2015-07-12 10:35:09 +02:00
log_warning ( " attribute '%s' was registered more than once \n " , at - > name ) ; //TODO: V111 http://www.viva64.com/en/V111 Call of function 'log_warning' with variable number of arguments. Second argument has memsize type.
2014-10-18 14:16:26 +02:00
return ;
}
else {
assert ( ! find | | ! " hashkey is already in use " ) ;
}
at - > nexthash = at_hash [ at - > hashkey % MAXATHASH ] ;
at_hash [ at - > hashkey % MAXATHASH ] = at ;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
static attrib_type * at_find ( unsigned int hk )
2010-08-08 10:06:34 +02:00
{
2014-10-18 14:16:26 +02:00
const char * translate [ 3 ] [ 2 ] = {
2015-01-30 20:37:14 +01:00
{ " zielregion " , " targetregion " } , /* remapping: from 'zielregion, heute targetregion */
2015-07-06 21:31:27 +02:00
{ " verzaubert " , " curse " } , /* remapping: früher verzaubert, jetzt curse */
2015-01-30 20:37:14 +01:00
{ NULL , NULL }
2014-10-18 14:16:26 +02:00
} ;
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 ;
}
2011-03-07 08:02:35 +01:00
}
2014-10-18 14:16:26 +02:00
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 ,
2014-10-18 14:16:26 +02:00
bool ( * compare ) ( const attrib * , const void * ) )
2010-08-08 10:06:34 +02:00
{
2014-10-18 14:16:26 +02: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
{
2014-10-18 14:16:26 +02: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
{
2015-07-07 00:49:12 +02:00
attrib * * pa ;
2014-10-18 14:16:26 +02:00
assert ( ! ( a - > type - > flags & ATF_UNIQUE ) ) ;
assert ( head & & head - > type = = a - > type ) ;
2010-08-08 10:06:34 +02:00
2015-07-07 00:49:12 +02:00
pa = & head - > next ;
2014-10-18 14:16:26 +02:00
while ( * pa & & ( * pa ) - > type = = a - > type ) {
pa = & ( * pa ) - > next ;
}
a - > next = * pa ;
return * pa = a ;
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
attrib * a_add ( attrib * * pa , attrib * a )
2010-08-08 10:06:34 +02:00
{
2014-10-18 14:16:26 +02:00
attrib * first = * pa ;
assert ( a - > next = = NULL & & a - > nexttype = = NULL ) ;
2011-03-07 08:02:35 +01:00
2014-10-18 14:16:26 +02:00
if ( first = = NULL )
return * pa = a ;
if ( first - > type = = a - > type ) {
return a_insert ( first , a ) ;
2010-08-08 10:06:34 +02:00
}
2014-10-18 14:16:26 +02:00
for ( ; ; ) {
attrib * next = first - > nexttype ;
if ( next = = NULL ) {
/* the type is not in the list, append it behind the last type */
attrib * * insert = & first - > next ;
first - > nexttype = a ;
while ( * insert )
insert = & ( * insert ) - > next ;
* insert = a ;
break ;
}
if ( next - > type = = a - > type ) {
return a_insert ( next , a ) ;
}
first = next ;
2010-08-08 10:06:34 +02:00
}
2014-10-18 14:16:26 +02:00
return 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
{
2014-10-18 14:16:26 +02:00
attrib * * pnexttype = pa ;
attrib * * pnext = NULL ;
assert ( a ! = NULL ) ;
while ( * pnexttype ) {
attrib * next = * pnexttype ;
if ( next - > type = = a - > type )
break ;
pnexttype = & next - > nexttype ;
pnext = & next - > next ;
2010-08-08 10:06:34 +02:00
}
2014-10-18 14:16:26 +02:00
if ( * pnexttype & & ( * pnexttype ) - > type = = a - > type ) {
if ( * pnexttype = = a ) {
* pnexttype = a - > next ;
if ( a - > next ! = a - > nexttype ) {
a - > next - > nexttype = a - > nexttype ;
}
if ( pnext = = NULL )
return 1 ;
while ( * pnext & & ( * pnext ) - > type ! = a - > type )
pnext = & ( * pnext ) - > next ;
}
else {
pnext = & ( * pnexttype ) - > next ;
}
while ( * pnext & & ( * pnext ) - > type = = a - > type ) {
if ( * pnext = = a ) {
* pnext = a - > next ;
return 1 ;
}
pnext = & ( * pnext ) - > next ;
}
2010-08-08 10:06:34 +02:00
}
2014-10-18 14:16:26 +02:00
return 0 ;
2010-08-08 10:06:34 +02:00
}
2014-10-18 19:23:36 +02:00
static void a_free ( attrib * a )
{
const attrib_type * at = a - > type ;
if ( at - > finalize )
at - > finalize ( a ) ;
free ( a ) ;
}
2011-03-07 08:02:35 +01:00
int a_remove ( attrib * * pa , attrib * a )
2010-08-08 10:06:34 +02:00
{
2015-10-29 08:53:40 +01:00
attrib * head = * pa ;
2014-10-18 14:16:26 +02:00
int ok ;
2015-10-29 08:53:40 +01:00
2014-10-18 14:16:26 +02:00
assert ( a ! = NULL ) ;
ok = a_unlink ( pa , a ) ;
2015-10-29 08:53:40 +01:00
if ( ok ) {
if ( head = = a ) {
* pa = a - > next ;
}
2014-10-18 14:16:26 +02:00
a_free ( a ) ;
2015-10-29 08:53:40 +01:00
}
2014-10-18 14:16:26 +02:00
return ok ;
2010-08-08 10:06:34 +02:00
}
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
{
2014-10-18 14:16:26 +02:00
attrib * * pnexttype = pa ;
2016-02-06 10:56:08 +01:00
if ( ! at ) {
while ( * pnexttype ) {
attrib * a = * pnexttype ;
* pnexttype = a - > next ;
a_free ( a ) ;
}
2010-08-08 10:06:34 +02:00
}
2016-02-06 10:56:08 +01:00
else {
attrib * * pnext = NULL ;
while ( * pnexttype ) {
attrib * a = * pnexttype ;
if ( a - > type = = at )
break ;
pnexttype = & a - > nexttype ;
pnext = & a - > next ;
2014-10-18 14:16:26 +02:00
}
2016-02-06 10:56:08 +01:00
if ( * pnexttype & & ( * pnexttype ) - > type = = at ) {
attrib * a = * pnexttype ;
* pnexttype = a - > nexttype ;
if ( pnext ) {
while ( * pnext & & ( * pnext ) - > type ! = at )
pnext = & ( * pnext ) - > next ;
* pnext = a - > nexttype ;
}
while ( a & & a - > type = = at ) {
attrib * ra = a ;
a = a - > next ;
a_free ( ra ) ;
}
2014-10-18 14:16:26 +02:00
}
2010-08-08 10:06:34 +02:00
}
}
2011-03-07 08:02:35 +01:00
attrib * a_new ( const attrib_type * at )
2010-08-08 10:06:34 +02:00
{
2014-10-18 14:16:26 +02: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
}
2015-12-16 22:18:44 +01:00
int a_age ( attrib * * p , void * owner )
2010-08-08 10:06:34 +02:00
{
2014-10-18 14:16:26 +02:00
attrib * * ap = p ;
/* Attribute altern, und die Entfernung (age()==0) eines Attributs
2015-07-06 21:31:27 +02:00
* hat Einfluß auf den Besitzer */
2014-10-18 14:16:26 +02:00
while ( * ap ) {
attrib * a = * ap ;
if ( a - > type - > age ) {
2015-12-16 22:18:44 +01:00
int result = a - > type - > age ( a , owner ) ;
2014-10-18 14:16:26 +02:00
assert ( result > = 0 | | ! " age() returned a negative value " ) ;
2015-08-25 22:50:58 +02:00
if ( result = = AT_AGE_REMOVE ) {
2014-10-18 14:16:26 +02:00
a_remove ( p , a ) ;
continue ;
}
}
ap = & a - > next ;
2011-03-07 08:02:35 +01:00
}
2014-10-18 14:16:26 +02:00
return ( * p ! = NULL ) ;
2010-08-08 10:06:34 +02:00
}
2012-06-17 20:08:48 +02:00
static critbit_tree cb_deprecated = { 0 } ;
2014-10-18 14:16:26 +02:00
void at_deprecate ( const char * name , int ( * reader ) ( attrib * , void * , struct storage * ) )
2012-06-17 20:08:48 +02:00
{
2014-10-18 14:16:26 +02:00
char buffer [ 64 ] ;
size_t len = strlen ( name ) ;
len = cb_new_kv ( name , len , & reader , sizeof ( reader ) , buffer ) ;
cb_insert ( & cb_deprecated , buffer , len ) ;
2012-06-17 20:08:48 +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
{
2014-10-18 14:16:26 +02:00
int key , retval = AT_READ_OK ;
char zText [ 128 ] ;
2010-08-08 10:06:34 +02:00
2014-10-18 14:16:26 +02:00
zText [ 0 ] = 0 ;
key = - 1 ;
2013-12-31 10:06:28 +01:00
READ_TOK ( store , zText , sizeof ( zText ) ) ;
2014-10-18 14:16:26 +02:00
if ( strcmp ( zText , " end " ) = = 0 )
return retval ;
else
key = __at_hashkey ( zText ) ;
while ( key ! = - 1 ) {
int ( * reader ) ( attrib * , void * , struct storage * ) = 0 ;
attrib_type * at = at_find ( key ) ;
attrib * na = 0 ;
if ( at ) {
reader = at - > read ;
na = a_new ( at ) ;
}
else {
2015-07-12 10:35:09 +02:00
void * kv = 0 ;
2014-10-18 14:16:26 +02:00
cb_find_prefix ( & cb_deprecated , zText , strlen ( zText ) + 1 , & kv , 1 , 0 ) ;
if ( kv ) {
cb_get_kv ( kv , & reader , sizeof ( reader ) ) ;
}
else {
fprintf ( stderr , " attribute hash: %d (%s) \n " , key , zText ) ;
assert ( at | | ! " attribute not registered " ) ;
}
}
if ( reader ) {
int i = reader ( na , owner , store ) ;
if ( na ) {
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 ( ! " error: no registered callback can read attribute " ) ;
}
READ_TOK ( store , zText , sizeof ( zText ) ) ;
if ( ! strcmp ( zText , " end " ) )
break ;
key = __at_hashkey ( zText ) ;
}
return retval ;
2010-08-08 10:06:34 +02:00
}
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
{
2014-10-18 14:16:26 +02:00
const attrib * na = attribs ;
while ( na ) {
if ( na - > type - > write ) {
assert ( na - > type - > hashkey | | ! " attribute not registered " ) ;
WRITE_TOK ( store , na - > type - > name ) ;
na - > type - > write ( na , owner , store ) ;
na = na - > next ;
}
else {
na = na - > nexttype ;
}
2010-08-08 10:06:34 +02:00
}
2014-10-18 14:16:26 +02:00
WRITE_TOK ( store , " end " ) ;
2010-08-08 10:06:34 +02:00
}
2014-12-31 01:17:49 +01:00
void free_attribs ( void ) {
cb_clear ( & cb_deprecated ) ;
}