tinymush-3.0b21/game/bin/
tinymush-3.0b21/game/data/
tinymush-3.0b21/src/tools/
/*
 * 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);
}