gurba-0.40/
gurba-0.40/bin/
gurba-0.40/lib/
gurba-0.40/lib/cmds/guild/fighter/
gurba-0.40/lib/cmds/monster/
gurba-0.40/lib/cmds/race/catfolk/
gurba-0.40/lib/cmds/race/dwarf/
gurba-0.40/lib/cmds/verb/
gurba-0.40/lib/daemons/data/
gurba-0.40/lib/data/boards/
gurba-0.40/lib/data/messages/
gurba-0.40/lib/data/players/
gurba-0.40/lib/design/
gurba-0.40/lib/domains/gurba/
gurba-0.40/lib/domains/gurba/guilds/fighter/
gurba-0.40/lib/domains/gurba/monsters/
gurba-0.40/lib/domains/gurba/objects/armor/
gurba-0.40/lib/domains/gurba/objects/clothing/
gurba-0.40/lib/domains/gurba/objects/weapons/
gurba-0.40/lib/domains/gurba/vendors/
gurba-0.40/lib/kernel/cmds/admin/
gurba-0.40/lib/kernel/daemons/
gurba-0.40/lib/kernel/include/
gurba-0.40/lib/kernel/lib/
gurba-0.40/lib/kernel/net/
gurba-0.40/lib/kernel/sys/
gurba-0.40/lib/logs/
gurba-0.40/lib/pub/
gurba-0.40/lib/std/modules/languages/
gurba-0.40/lib/std/races/
gurba-0.40/lib/std/races/monsters/
gurba-0.40/lib/wiz/fudge/
gurba-0.40/lib/wiz/spud/
gurba-0.40/src/host/beos/
gurba-0.40/src/host/pc/res/
gurba-0.40/src/kfun/
gurba-0.40/src/lpc/
gurba-0.40/src/parser/
gurba-0.40/tmp/
# define INCLUDE_FILE_IO
# define INCLUDE_CTYPE
# include "dgd.h"
# include "str.h"
# include "array.h"
# include "object.h"
# include "interpret.h"
# include "data.h"

# define OBJ_NONE		UINDEX_MAX

object *otable;			/* object table */
static uindex otabsize;		/* size of object table */
static hashtab *htab;		/* object name hash table */
static object *clean_obj;	/* list of objects to clean */
static object *upgrade_obj;	/* list of upgrade objects */
static uindex dest_obj;		/* destructed object list */
static uindex free_obj;		/* free object list */
static uindex nobjects;		/* number of objects in object table */
static uindex nfreeobjs;	/* number of objects in free list */
static Uint ocount;		/* object creation count */
Uint odcount;			/* objects destructed count */

/*
 * NAME:	object->init()
 * DESCRIPTION:	initialize the object tables
 */
void o_init(n)
register unsigned int n;
{
    otable = ALLOC(object, otabsize = n);
    for (n = 4; n < otabsize; n <<= 1) ;
    htab = ht_new(n >> 2, OBJHASHSZ);
    upgrade_obj = clean_obj = (object *) NULL;
    free_obj = dest_obj = OBJ_NONE;
    nobjects = 0;
    nfreeobjs = 0;
    ocount = odcount = 1;
}

/*
 * NAME:	object->alloc()
 * DESCRIPTION:	allocate a new object
 */
static object *o_alloc()
{
    object *o;

    if (free_obj != OBJ_NONE) {
	/* get space from free object list */
	o = &otable[free_obj];
	free_obj = o->prev;
	--nfreeobjs;
    } else {
	/* use new space in object table */
	if (nobjects == otabsize) {
	    fatal("too many objects");
	}
	o = &otable[nobjects++];
    }

    o->data = (dataspace *) NULL;
    o->cfirst = SW_UNUSED;
    o->dfirst = SW_UNUSED;

    return o;
}

/*
 * NAME:	object->new()
 * DESCRIPTION:	create a new object
 */
object *o_new(name, ctrl)
char *name;
register control *ctrl;
{
    register object *o;
    register dinherit *inh;
    register int i;
    hte **h;

    /* allocate object */
    o = o_alloc();

    /* put object in object name hash table */
    m_static();
    strcpy(o->chain.name = ALLOC(char, strlen(name) + 1), name);
    m_dynamic();
    h = ht_lookup(htab, name, FALSE);
    o->chain.next = *h;
    *h = (hte *) o;

    o->flags = O_MASTER;
    o->cref = 0;
    o->prev = OBJ_NONE;
    o->index = o - otable;
    o->count = ++ocount;
    o->update = 0;
    o->ctrl = ctrl;
    ctrl->inherits[ctrl->ninherits - 1].obj = ctrl->obj = o;

    /* add reference to all inherited objects */
    o->u_ref = 0;	/* increased to 1 in following loop */
    inh = ctrl->inherits;
    for (i = ctrl->ninherits; i > 0; --i) {
	(inh++)->obj->u_ref++;
    }

    return o;
}

/*
 * NAME:	object->clone()
 * DESCRIPTION:	clone an object
 */
object *o_clone(master)
register object *master;
{
    register object *o;

    /* allocate object */
    o = o_alloc();

    o->chain.name = (char *) NULL;
    o->flags = 0;
    o->index = o - otable;
    o->count = ++ocount;
    o->update = master->update;
    o->u_master = master->index;
    o->ctrl = (control *) NULL;
    o->data = d_new_dataspace(o);	/* clones always have a dataspace */

    /* add reference to master object */
    master->cref++;
    master->u_ref++;

    return o;
}

/*
 * NAME:	object->delete()
 * DESCRIPTION:	the last reference to a master object was removed
 */
static void o_delete(o, f)
register object *o;
register frame *f;
{
    register control *ctrl;
    register dinherit *inh;
    register int i;

    ctrl = (O_UPGRADING(o)) ? otable[o->prev].ctrl : o_control(o);

    /* put in deleted list */
    o->u_master = dest_obj;
    dest_obj = o - otable;

    /* callback to the system */
    (--f->sp)->type = T_STRING;
    str_ref(f->sp->u.string = str_new(NULL, strlen(o->chain.name) + 1L));
    f->sp->u.string->text[0] = '/';
    strcpy(f->sp->u.string->text + 1, o->chain.name);
    (--f->sp)->type = T_INT;
    f->sp->u.number = ctrl->compiled;
    (--f->sp)->type = T_INT;
    f->sp->u.number = o->index;
    if (i_call_critical(f, "remove_program", 3, TRUE)) {
	i_del_value(f->sp++);
    }

    /* remove references to inherited objects too */
    inh = ctrl->inherits;
    i = ctrl->ninherits;
    while (--i > 0) {
	o = (inh++)->obj;
	if (--(o->u_ref) == 0) {
	    o_delete(o, f);
	}
    }
}

/*
 * NAME:	object->upgrade()
 * DESCRIPTION:	upgrade an object to a new program
 */
void o_upgrade(obj, ctrl, f)
object *obj;
control *ctrl;
register frame *f;
{
    register object *o;
    register dinherit *inh;
    register int i;

    /* allocate upgrade object */
    o = o_alloc();
    o->chain.name = (char *) NULL;
    o->flags = O_MASTER;
    o->count = 0;
    o->u_master = obj->index;
    o->ctrl = ctrl;
    ctrl->inherits[ctrl->ninherits - 1].obj = obj;

    /* add reference to inherited objects */
    inh = ctrl->inherits;
    i = ctrl->ninherits;
    while (--i > 0) {
	(inh++)->obj->u_ref++;
    }

    /* add to upgrades list */
    o->chain.next = (hte *) upgrade_obj;
    upgrade_obj = o;

    /* mark as upgrading */
    obj->cref += 2;
    o->prev = obj->prev;
    obj->prev = o - otable;

    /* remove references to old inherited objects */
    ctrl = o_control(obj);
    inh = ctrl->inherits;
    i = ctrl->ninherits;
    while (--i > 0) {
	o = (inh++)->obj;
	if (--(o->u_ref) == 0) {
	    o_delete(o, f);
	}
    }
}

/*
 * NAME:	object->upgraded()
 * DESCRIPTION:	an object has been upgraded
 */
void o_upgraded(old, new)
register object *old, *new;
{
    if (new->count != 0) {
	if (!(new->flags & O_MASTER)) {
	    new->update = otable[new->u_master].update;
	    new = &otable[new->u_master];
	    new->cref++;
	    new->u_ref++;
	}
	while (--(old->u_ref) == 0) {
	    /* put in deleted list */
	    old->u_master = dest_obj;
	    dest_obj = old - otable;

# ifdef DEBUG
	    if (old->prev != OBJ_NONE) {
		fatal("removing issue in middle of list");
	    }
# endif
	    /* remove from issue list */
	    old = &otable[old->cref];
	    old->prev = OBJ_NONE;
	    if (old == new) {
		new->cref--;
		new->u_ref--;
		break;
	    }
	}
    } else if (!(new->flags & O_MASTER)) {
	new->update = otable[new->u_master].update;
    }
}

/*
 * NAME:	object->del()
 * DESCRIPTION:	delete an object
 */
void o_del(o, f)
register object *o;
frame *f;
{
    if (o->count == 0) {
	/* can happen if object selfdestructs in close()-on-destruct */
	error("Destructing destructed object");
    }
    o->count = 0;
    odcount++;

    if (o->flags & O_MASTER) {
	/* remove from object name hash table */
	*ht_lookup(htab, o->chain.name, FALSE) = o->chain.next;

	if (--(o->u_ref) == 0) {
	    o_delete(o, f);
	}
    } else {
	register object *m;

	/* clone */
	m = &otable[o->u_master];
	if (m->update == o->update) {
	    m->cref--;
	    if (--(m->u_ref) == 0) {
		o_delete(m, f);
	    }
	} else {
	    /* non-upgraded clone of old issue */
	    do {
		m = &otable[m->prev];
	    } while (m->update != o->update);
	    if (--(m->u_ref) == 0) {
		/* put old issue in deleted list */
		m->u_master = dest_obj;
		dest_obj = m - otable;

		m = &otable[o->u_master];
		if (--(m->u_ref) == 0) {
		    o_delete(m, f);
		}
	    }
	}
    }

    /* put in clean list */
    o->chain.next = (hte *) clean_obj;
    clean_obj = o;
}

/*
 * NAME:	object->name()
 * DESCRIPTION:	return the name of an object
 */
char *o_name(o)
register object *o;
{
    if (o->chain.name != (char *) NULL) {
	return o->chain.name;
    } else {
	static char name[STRINGSZ + 12];
	char num[12];
	register char *p;
	register uindex n;

	/*
	 * return the name of the master object with the index appended
	 */
	n = o->index;
	p = num + 11;
	*p = '\0';
	do {
	    *--p = '0' + n % 10;
	    n /= 10;
	} while (n != 0);
	*--p = '#';

	strcpy(name, otable[o->u_master].chain.name);
	strcat(name, p);
	return name;
    }
}

/*
 * NAME:	object->find()
 * DESCRIPTION:	find an object by name
 */
object *o_find(name)
char *name;
{
    char *hash;

    hash = strchr(name, '#');
    if (hash != (char *) NULL) {
	register char *p;
	register unsigned long number;
	register object *o;

	/*
	 * Look for a cloned object, which cannot be found directly in the
	 * object name hash table.
	 * The name must be of the form filename#1234, where 1234 is the
	 * decimal representation of the index in the object table.
	 */
	p = hash + 1;
	if (*p == '\0' || (p[0] == '0' && p[1] != '\0')) {
	    /* don't accept "filename#" or "filename#01" */
	    return (object *) NULL;
	}

	/* convert the string to a number */
	number = 0;
	do {
	    if (!isdigit(*p)) {
		return (object *) NULL;
	    }
	    number = number * 10 + *p++ - '0';
	    if (number >= nobjects) {
		return (object *) NULL;
	    }
	} while (*p != '\0');

	o = &otable[number];
	if (o->count == 0 || (o->flags & O_MASTER) ||
	    strncmp(name, otable[o->u_master].chain.name, hash - name) != 0 ||
	    otable[o->u_master].chain.name[hash - name] != '\0') {
	    /*
	     * no entry, not a clone, or object name doesn't match
	     */
	    return (object *) NULL;
	}
	return o;
    } else {
	/* look it up in the hash table */
	return (object *) *ht_lookup(htab, name, TRUE);
    }
}

/*
 * NAME:	object->control()
 * DESCRIPTION:	return the control block for an object
 */
control *o_control(obj)
object *obj;
{
    register object *o;

    o = obj;
    if (!(o->flags & O_MASTER)) {
	o = &otable[o->u_master];	/* get control block of master object */
    }
    if (o->ctrl == (control *) NULL) {
	o->ctrl = d_load_control(o);	/* reload */
    } else {
	d_ref_control(o->ctrl);
    }
    return obj->ctrl = o->ctrl;
}

/*
 * NAME:	object->dataspace()
 * DESCRIPTION:	return the dataspace block for an object
 */
dataspace *o_dataspace(o)
register object *o;
{
    if (o->data == (dataspace *) NULL) {
	if (o->dfirst == SW_UNUSED) {
	    /* create new dataspace block */
	    o->data = d_new_dataspace(o);
	} else {
	    /* load dataspace block */
	    o->data = d_load_dataspace(o);
	}
    } else {
	d_ref_dataspace(o->data);
    }
    return o->data;
}

/*
 * NAME:	object->clean()
 * DESCRIPTION:	clean up the object table
 */
void o_clean()
{
    register object *o;

    for (o = clean_obj; o != (object *) NULL; o = (object *) o->chain.next) {
	/* free dataspace block (if it exists) */
	if (o->data == (dataspace *) NULL && o->dfirst != SW_UNUSED) {
	    /* reload dataspace block (sectors are needed) */
	    o->data = d_load_dataspace(o);
	}
	if (o->data != (dataspace *) NULL) {
	    d_del_dataspace(o->data);
	}

	if (!(o->flags & O_MASTER)) {
	    /* put clone in free list */
	    o->prev = free_obj;
	    free_obj = o - otable;
	    nfreeobjs++;
	}
    }
    clean_obj = (object *) NULL;

    for (o = upgrade_obj; o != (object *) NULL; o = (object *) o->chain.next) {
	register object *up;
	register control *ctrl;

	up = &otable[o->u_master];
	up->cref -= 2;
	up->prev = o->prev;

	if (up->count == 0 && up->cref == 0) {
	    /* also remove upgrader */
	    o->u_master = dest_obj;
	    dest_obj = o - otable;
	} else {
	    /* upgrade objects */
	    up->flags &= ~O_COMPILED;
	    o->u_ref = up->u_ref;
	    ctrl = up->ctrl;

	    if (ctrl->vmapsize != 0 &&
		(up->data != (dataspace *) NULL || up->dfirst != SW_UNUSED ||
		 up->count == 0 || --(o->u_ref) != 0)) {
		/* upgrade variables */
		o->cref = o->index = up->index;
		if (o->prev != OBJ_NONE) {
		    otable[o->prev].cref = o - otable;
		}
		o->update = up->update;

		up->prev = o - otable;
		up->cref = 1;
		up->u_ref = 1;
		up->update++;
		if (up->count != 0) {
		    up->u_ref++;
		    if (up->data == (dataspace *) NULL &&
			up->dfirst != SW_UNUSED) {
			/* load dataspace (with old control block) */
			up->data = d_load_dataspace(up);
		    }
		}
	    } else {
		/* no variable upgrading */
		o->u_master = dest_obj;
		dest_obj = o - otable;
	    }

	    /* swap control blocks */
	    up->ctrl = o->ctrl;
	    up->ctrl->obj = up;
	    o->ctrl = ctrl;
	    ctrl->obj = o;
	    o->cfirst = up->cfirst;
	    up->cfirst = SW_UNUSED;

	    if (ctrl->ndata != 0) {
		/* upgrade all dataspaces in memory */
		d_upgrade_all(o, up);
	    }
	}
    }
    upgrade_obj = (object *) NULL;

    while (dest_obj != OBJ_NONE) {
	o = &otable[dest_obj];

	/* free control block */
	d_del_control(o_control(o));

	if (o->chain.name != (char *) NULL) {
	    /* free object name */
	    FREE(o->chain.name);
	    o->chain.name = (char *) NULL;
	}

	/* put object in free list */
	o->prev = free_obj;
	free_obj = o - otable;
	nfreeobjs++;

	dest_obj = o->u_master;
	o->u_ref = 0;
    }
}

/*
 * NAME:	object->count()
 * DESCRIPTION:	return the number of objects in use
 */
uindex o_count()
{
    return nobjects - nfreeobjs;
}


typedef struct {
    uindex free_obj;	/* free object list */
    uindex nobjects;	/* # objects */
    uindex nfreeobjs;	/* # free objects */
    Uint onamelen;	/* length of all object names */
} dump_header;

static char dh_layout[] = "uuui";

# define CHUNKSZ	16384

/*
 * NAME:	object->dump()
 * DESCRIPTION:	dump the object table
 */
bool o_dump(fd)
int fd;
{
    register uindex i;
    register object *o;
    register unsigned int len, buflen;
    dump_header dh;
    char buffer[CHUNKSZ];

    /* prepare header */
    dh.free_obj = free_obj;
    dh.nobjects = nobjects;
    dh.nfreeobjs = nfreeobjs;
    dh.onamelen = 0;
    for (i = nobjects, o = otable; i > 0; --i, o++) {
	if (o->chain.name != (char *) NULL) {
	    dh.onamelen += strlen(o->chain.name) + 1;
	}
    }

    /* write header and objects */
    if (write(fd, (char *) &dh, sizeof(dump_header)) < 0 ||
	write(fd, (char *) otable, nobjects * sizeof(object)) < 0) {
	return FALSE;
    }

    /* write object names */
    buflen = 0;
    for (i = nobjects, o = otable; i > 0; --i, o++) {
	if (o->chain.name != (char *) NULL) {
	    len = strlen(o->chain.name) + 1;
	    if (buflen + len > CHUNKSZ) {
		if (write(fd, buffer, buflen) < 0) {
		    return FALSE;
		}
		buflen = 0;
	    }
	    memcpy(buffer + buflen, o->chain.name, len);
	    buflen += len;
	}
    }
    return (buflen == 0 || write(fd, buffer, buflen) >= 0);
}

/*
 * NAME:	object->restore()
 * DESCRIPTION:	restore the object table
 */
void o_restore(fd)
int fd;
{
    register uindex i;
    register object *o;
    register unsigned int len, buflen;
    register char *p;
    dump_header dh;
    char buffer[CHUNKSZ];

    /*
     * Free object names of precompiled objects.
     */
    for (i = nobjects, o = otable; i > 0; --i, o++) {
	*ht_lookup(htab, o->chain.name, FALSE) = o->chain.next;
	FREE(o->chain.name);
    }

    /* read header and object table */
    conf_dread(fd, (char *) &dh, dh_layout, (Uint) 1);
    if (dh.nobjects > otabsize) {
	error("Too many objects in restore file");
    }
    conf_dread(fd, (char *) otable, OBJ_LAYOUT, (Uint) dh.nobjects);
    free_obj = dh.free_obj;
    nobjects = dh.nobjects;
    nfreeobjs = dh.nfreeobjs;

    /* read object names, and patch all objects and control blocks */
    buflen = 0;
    for (i = nobjects, o = otable; i > 0; --i, o++) {
	if (o->chain.name != (char *) NULL) {
	    /*
	     * restore name
	     */
	    if (buflen == 0 ||
		(char *) memchr(p, '\0', buflen) == (char *) NULL) {
		/* move remainder to beginning, and refill buffer */
		if (buflen != 0) {
		    memcpy(buffer, p, buflen);
		}
		len = (dh.onamelen > CHUNKSZ - buflen) ?
		       CHUNKSZ - buflen : dh.onamelen;
		if (read(fd, buffer + buflen, len) != len) {
		    fatal("cannot restore object names");
		}
		dh.onamelen -= len;
		buflen += len;
		p = buffer;
	    }
	    m_static();
	    strcpy(o->chain.name = ALLOC(char, len = strlen(p) + 1), p);
	    m_dynamic();

	    if (o->count != 0) {
		register hte **h;

		h = ht_lookup(htab, p, FALSE);
		o->chain.next = *h;
		*h = (hte *) o;
	    }
	    p += len;
	    buflen -= len;
	}

	if (o->count != 0) {
	    /* there are no user or editor objects after a restore */
	    o->flags &= ~(O_USER | O_EDITOR | O_PENDIO);
	}

	/* check memory */
	if (!m_check()) {
	    m_purge();
	}
    }
}

static int cmp P((cvoid*, cvoid*));

/*
 * NAME:	cmp()
 * DESCRIPTION:	compare two objects
 */
static int cmp(cv1, cv2)
cvoid *cv1, *cv2;
{
    register object *o1, *o2;

    /* non-objects first, then objects sorted by count */
    o1 = &otable[*((Uint *) cv1)];
    o2 = &otable[*((Uint *) cv2)];
    if (o1->count == 0) {
	if (o2->count == 0) {
	    return (o1 <= o2) ? (o1 < o2) ? -1 : 0 : 1;
	}
	return -1;
    } else if (o2->count == 0) {
	return 1;
    } else {
	return (o1->count <= o2->count) ? (o1->count < o2->count) ? -1 : 0 : 1;
    }
}

/*
 * NAME:	object->conv()
 * DESCRIPTION:	convert all objects, creating a new swap file
 */
void o_conv()
{
    register Uint *counts, *sorted;
    register uindex i;
    register object *o;

    if (nobjects != 0) {
	/*
	 * create new object count table
	 */
	counts = ALLOCA(Uint, nobjects);
	sorted = ALLOCA(Uint, nobjects) + nobjects;
	i = nobjects;
	while (i != 0) {
	    *--sorted = --i;
	}
	/* sort by count */
	qsort(sorted, nobjects, sizeof(Uint), cmp);
	/* skip destructed objects */
	for (i = 0; i < nobjects; i++) {
	    if (otable[*sorted].count != 0) {
		break;
	    }
	    sorted++;
	}
	/* fill in counts table */
	while (i < nobjects) {
	    counts[*sorted++] = ++i + 1;
	}
	AFREE(sorted - i);
	ocount = i + 1;

	/*
	 * convert all control blocks
	 */
	for (i = nobjects, o = otable; i > 0; --i, o++) {
	    if ((o->count != 0 || ((o->flags & O_MASTER) && o->u_ref != 0)) &&
		o->cfirst != SW_UNUSED) {
		d_conv_control(o);
	    }
	}

	/*
	 * convert all data blocks
	 */
	for (i = nobjects, o = otable; i > 0; --i, o++) {
	    if (o->count != 0 && o->dfirst != SW_UNUSED) {
		d_conv_dataspace(o, counts);
		d_swapout(1);
	    }
	}

	/*
	 * fix count and update fields of all objects
	 */
	for (i = nobjects, o = otable; i > 0; --i, o++, counts++) {
	    if (o->count != 0) {
		o->count = *counts;
	    }
	    o->update = 0;
	}
	AFREE(counts - nobjects);
	o_clean();
    }
}