/*
* vattr.c -- Manages the user-defined attributes.
*/
/*
* $Id: vattr.c,v 1.12.2.1 2000/05/25 06:22:22 cvs Exp $
*/
#include "copyright.h"
#include "autoconf.h"
#include "copyright.h"
#include "mudconf.h"
#include "vattr.h"
#include "alloc.h"
#include "htab.h"
#include "externs.h"
static void FDECL(fixcase, (char *));
static char FDECL(*store_string, (char *));
/*
* Allocate space for strings in lumps this big.
*/
#define STRINGBLOCK 1000
/*
* Current block we're putting stuff in
*/
static char *stringblock = (char *)0;
/*
* High water mark.
*/
static int stringblock_hwm = 0;
void NDECL(vattr_init)
{
hashinit(&mudstate.vattr_name_htab, VATTR_HASH_SIZE);
}
VATTR *vattr_find(name)
char *name;
{
register VATTR *vp;
if (!ok_attr_name(name))
return (NULL);
vp = (VATTR *)hashfind(name, &mudstate.vattr_name_htab);
/*
* vp is NULL or the right thing. It's right, either way.
*/
return (vp);
}
VATTR *vattr_alloc(name, flags)
char *name;
int flags;
{
int number;
if (((number = mudstate.attr_next++) & 0x7f) == 0)
number = mudstate.attr_next++;
anum_extend(number);
return (vattr_define(name, number, flags));
}
VATTR *vattr_define(name, number, flags)
char *name;
int number, flags;
{
VATTR *vp;
/*
* Be ruthless.
*/
if (strlen(name) >= VNAME_SIZE)
name[VNAME_SIZE - 1] = '\0';
fixcase(name);
if (!ok_attr_name(name))
return (NULL);
if ((vp = vattr_find(name)) != NULL)
return (vp);
vp = (VATTR *) malloc(sizeof(VATTR));
vp->name = store_string(name);
vp->flags = flags;
vp->number = number;
hashadd(vp->name, (int *) vp, &mudstate.vattr_name_htab);
anum_extend(vp->number);
anum_set(vp->number, (ATTR *) vp);
return (vp);
}
void do_dbclean(player, cause, key)
dbref player, cause;
int key;
{
#ifndef STANDALONE
VATTR *vp;
dbref i;
int ca;
char *as;
int *used_table;
raw_broadcast(0,
"GAME: Cleaning database. Game may freeze for a few minutes.");
used_table = (int *) calloc(mudstate.attr_next, sizeof(int));
/* Walk the database. Mark all the attribute numbers in use. */
DO_WHOLE_DB(i) {
for (ca = atr_head(i, &as); ca; ca = atr_next(&as)) {
used_table[ca] = 1;
}
#ifndef MEMORY_BASED
if ((i % 100) == 0)
cache_reset(0);
#endif
}
/* Walk the vattr table. If a number isn't in use, zorch it. */
for (vp = vattr_first(); vp; vp = vattr_next(vp)) {
if (used_table[vp->number] == 0) {
anum_set(vp->number, NULL);
hashdelete(vp->name, &mudstate.vattr_name_htab);
free((VATTR *) vp);
}
}
free(used_table);
raw_broadcast(0, "GAME: Database cleaning complete.");
#endif /* STANDALONE */
}
void vattr_delete(name)
char *name;
{
VATTR *vp;
int number;
fixcase(name);
if (!ok_attr_name(name))
return;
number = 0;
vp = (VATTR *)hashfind(name, &mudstate.vattr_name_htab);
if (vp) {
number = vp->number;
anum_set(number, NULL);
hashdelete(name, &mudstate.vattr_name_htab);
free((char *)vp);
}
return;
}
VATTR *vattr_rename(name, newname)
char *name, *newname;
{
VATTR *vp;
fixcase(name);
if (!ok_attr_name(name))
return (NULL);
/*
* Be ruthless.
*/
if (strlen(newname) >= VNAME_SIZE)
newname[VNAME_SIZE - 1] = '\0';
fixcase(newname);
if (!ok_attr_name(newname))
return (NULL);
/* We must explicitly delete and add the name to the hashtable,
* since we are changing the data.
*/
vp = (VATTR *)hashfind(name, &mudstate.vattr_name_htab);
if (vp) {
vp->name = store_string(newname);
hashdelete(name, &mudstate.vattr_name_htab);
hashadd(newname, (int *) vp, &mudstate.vattr_name_htab);
}
return (vp);
}
VATTR *NDECL(vattr_first)
{
return (VATTR *)hash_firstentry(&mudstate.vattr_name_htab);
}
VATTR *vattr_next(vp)
VATTR *vp;
{
if (vp == NULL)
return (vattr_first());
return ((VATTR *)hash_nextentry(&mudstate.vattr_name_htab));
}
static void fixcase(name)
char *name;
{
char *cp = name;
while (*cp) {
*cp = ToUpper(*cp);
cp++;
}
return;
}
/*
* Some goop for efficiently storing strings we expect to
* keep forever. There is no freeing mechanism.
*/
static char *store_string(str)
char *str;
{
int len;
char *ret;
len = strlen(str);
/*
* If we have no block, or there's not enough room left in the * * *
* current one, get a new one.
*/
if (!stringblock || (STRINGBLOCK - stringblock_hwm) < (len + 1)) {
stringblock = (char *)malloc(STRINGBLOCK);
if (!stringblock)
return ((char *)0);
stringblock_hwm = 0;
}
ret = stringblock + stringblock_hwm;
StringCopy(ret, str);
stringblock_hwm += (len + 1);
return (ret);
}