/* $Header: db.c,v 2.0 90/05/05 12:45:30 lachesis Exp $
* $Log: db.c,v $
* Revision 2.0 90/05/05 12:45:30 lachesis
* Incorporated ABODE and HAVEN flags (remembering to convert FireFoot's
* usage of those flags to ours).
* Added Examine of objects that don't belong to you, added GOD_PRIV.
*
* Revision 1.3 90/04/21 17:20:40 lachesis
* Added property lists.
*
* Revision 1.2 90/04/20 14:06:02 lachesis
* Added @odrop && @drop.
*
* Revision 1.1 90/04/14 14:56:41 lachesis
* Initial revision
*
*/
#include "copyright.h"
#include "os.h"
#include "db.h"
#include "config.h"
#include "interface.h"
#include "externs.h"
struct object *db = 0;
dbref db_top = 0;
#ifdef RECYCLE
dbref recyclable = NOTHING;
#endif
#ifdef TEST_MALLOC
int malloc_count = 0;
#endif /* TEST_MALLOC */
#ifndef DB_INITIAL_SIZE
#define DB_INITIAL_SIZE 10000
#endif /* DB_INITIAL_SIZE */
#ifdef DB_DOUBLING
dbref db_size = DB_INITIAL_SIZE;
#endif /* DB_DOUBLING */
struct plist *new_prop (void);
void free_prop (struct plist *p);
int number (char *s);
void putproperties (FILE * f, struct plist *p);
void putprop (FILE * f, struct plist *p);
struct plist *getproperties (FILE * f);
char *alloc_string (const char *string)
{
char *s;
/* NULL, "" -> NULL */
if (string == 0 || *string == '\0')
return 0;
if ((s = (char *) malloc (strlen (string) + 1)) == 0) {
abort ();
}
(void) strcpy (s, string);
return s;
}
#ifdef DB_DOUBLING
static void db_grow (dbref newtop)
{
struct object *newdb;
if (newtop > db_top) {
db_top = newtop;
if (!db) {
/* make the initial one */
db_size = DB_INITIAL_SIZE;
if ((db = (struct object *)
malloc (db_size * sizeof (struct object))) == 0) {
abort ();
}
}
/* maybe grow it */
if (db_top > db_size) {
/* make sure it's big enough */
while (db_top > db_size)
db_size *= 2;
if ((newdb = (struct object *)
realloc ((void *) db, db_size * sizeof (struct object))) == 0) {
abort ();
}
db = newdb;
}
}
}
#else /* DB_DOUBLING */
static void db_grow (dbref newtop)
{
struct object *newdb;
if (newtop > db_top) {
db_top = newtop;
if (db) {
if ((newdb = (struct object *)
realloc ((void *) db, db_top * sizeof (struct object))) == 0) {
abort ();
}
db = newdb;
} else {
/* make the initial one */
if ((db = (struct object *)
malloc (DB_INITIAL_SIZE * sizeof (struct object))) == 0) {
abort ();
}
}
}
}
#endif /* DB_DOUBLING */
dbref new_object (void)
{
dbref newobj;
struct object *o;
#ifdef RECYCLE
if (recyclable != NOTHING) {
newobj = recyclable;
recyclable = db[newobj].next;
} else
#endif
{
newobj = db_top;
db_grow (db_top + 1);
}
/* clear it out */
o = db + newobj;
o->name = 0;
o->description = 0;
o->location = NOTHING;
o->contents = NOTHING;
o->next = NOTHING;
o->key = TRUE_BOOLEXP;
o->fail_message = 0;
o->succ_message = 0;
o->drop_message = 0;
o->ofail = 0;
o->osuccess = 0;
o->odrop = 0;
o->properties = 0;
/* flags you must initialize yourself */
/* type-specific fields you must also initialize */
return newobj;
}
#define DB_MSGLEN 512
void putref (FILE * f, dbref ref)
{
fprintf (f, "%d\n", ref);
}
static void putstring (FILE * f, const char *s)
{
if (s) {
fputs (s, f);
}
putc ('\n', f);
}
static void putbool_subexp (FILE * f, struct boolexp *b)
{
switch (b->type) {
case BOOLEXP_AND:
putc ('(', f);
putbool_subexp (f, b->sub1);
putc (AND_TOKEN, f);
putbool_subexp (f, b->sub2);
putc (')', f);
break;
case BOOLEXP_OR:
putc ('(', f);
putbool_subexp (f, b->sub1);
putc (OR_TOKEN, f);
putbool_subexp (f, b->sub2);
putc (')', f);
break;
case BOOLEXP_NOT:
putc ('(', f);
putc (NOT_TOKEN, f);
putbool_subexp (f, b->sub1);
putc (')', f);
break;
case BOOLEXP_CONST:
fprintf (f, "%d", b->thing);
break;
case BOOLEXP_PROP:
putc ('[', f);
putprop (f, b->prop_check);
putc (']', f);
break;
default:
break;
}
}
void putprop (FILE * f, struct plist *prop)
{
fputs (prop->type, f);
putc (PROP_DELIMITER, f);
if (prop->class)
fputs (prop->class, f);
#ifdef NUMBER_PROPS
else
fprintf (f, "%d", prop->value);
#endif
}
void putboolexp (FILE * f, struct boolexp *b)
{
if (b != TRUE_BOOLEXP) {
putbool_subexp (f, b);
}
putc ('\n', f);
}
void putproperties (FILE * f, struct plist *p)
{
while (p) {
putprop (f, p);
putc ('\n', f);
p = p->next;
}
}
int db_write_object (FILE * f, dbref i)
{
struct object *o;
int j;
o = db + i;
putstring (f, o->name);
putstring (f, o->description);
putref (f, o->location);
putref (f, o->contents);
putref (f, o->next);
putboolexp (f, o->key);
putstring (f, o->fail_message);
putstring (f, o->succ_message);
putstring (f, o->drop_message);
putstring (f, o->ofail);
putstring (f, o->osuccess);
putstring (f, o->odrop);
putref (f, o->flags);
/* putstring(f, "***Property list start ***"); */
putproperties (f, o->properties);
/* putstring(f, "***Property list end ***"); */
putstring (f, ":");
switch (Typeof (i)) {
case TYPE_THING:
putref (f, o->sp.thing.home);
putref (f, o->sp.thing.actions);
putref (f, o->sp.thing.owner);
putref (f, o->sp.thing.value);
break;
case TYPE_ROOM:
putref (f, o->sp.room.dropto);
putref (f, o->sp.room.exits);
putref (f, o->sp.room.owner);
break;
case TYPE_EXIT:
putref (f, o->sp.exit.ndest);
for (j = 0; j < o->sp.exit.ndest; j++) {
putref (f, (o->sp.exit.dest)[j]);
}
putref (f, o->sp.exit.owner);
break;
case TYPE_PLAYER:
putref (f, o->sp.player.home);
putref (f, o->sp.player.actions);
putref (f, o->sp.player.pennies);
putstring (f, o->sp.player.password);
break;
}
return 0;
}
dbref db_write (FILE * f)
{
dbref i;
fputs ("***Christina Applegate TinyMUCK DUMP Format***\n", f);
for (i = 0; i < db_top; i++) {
fprintf (f, "#%d\n", i);
db_write_object (f, i);
}
fputs ("***END OF DUMP***\n", f);
fflush (f);
return (db_top);
}
dbref parse_dbref (const char *s)
{
const char *p;
long x;
x = atol (s);
if (x > 0) {
return x;
} else if (x == 0) {
/* check for 0 */
for (p = s; *p; p++) {
if (*p == '0')
return 0;
if (!isspace (*p))
break;
}
}
/* else x < 0 or s != 0 */
return NOTHING;
}
dbref getref (FILE * f)
{
static char buf[DB_MSGLEN];
fgets (buf, sizeof (buf), f);
return (atol (buf));
}
static const char *getstring_noalloc (FILE * f)
{
static char buf[DB_MSGLEN];
char *p;
fgets (buf, sizeof (buf), f);
for (p = buf; *p; p++) {
if (*p == '\n') {
*p = '\0';
break;
}
}
return buf;
}
#define getstring(x) alloc_string(getstring_noalloc(x))
#ifdef COMPRESS
extern const char *compress (const char *);
#define getstring_compress(x) alloc_string(compress(getstring_noalloc(x)));
#else
#define getstring_compress(x) getstring(x)
#endif /* COMPRESS */
static struct boolexp *negate_boolexp (struct boolexp *b)
{
struct boolexp *n;
/* Obscure fact: !NOTHING == NOTHING in old-format databases! */
if (b == TRUE_BOOLEXP)
return TRUE_BOOLEXP;
n = (struct boolexp *) malloc (sizeof (struct boolexp));
n->type = BOOLEXP_NOT;
n->sub1 = b;
return n;
}
/* returns true for numbers of form [ + | - ] <series of digits> */
int number (char *s)
{
while (isspace (*s))
s++;
if (*s == '+' || *s == '-')
s++;
for (; s; s++)
if (*s < '0' || *s > '9')
return 0;
return 1;
}
static struct boolexp *getboolexp1 (FILE * f)
{
struct boolexp *b;
struct plist *p;
char buf[BUFFER_LEN]; /* holds string for reading in property */
int c;
int i; /* index into buf */
c = getc (f);
switch (c) {
case '\n':
ungetc (c, f);
return TRUE_BOOLEXP;
/* break; */
case EOF:
abort (); /* unexpected EOF in boolexp */
break;
case '(':
b = (struct boolexp *) malloc (sizeof (struct boolexp));
if ((c = getc (f)) == '!') {
b->type = BOOLEXP_NOT;
b->sub1 = getboolexp1 (f);
if (getc (f) != ')')
goto error;
return b;
} else {
ungetc (c, f);
b->sub1 = getboolexp1 (f);
switch (c = getc (f)) {
case AND_TOKEN:
b->type = BOOLEXP_AND;
break;
case OR_TOKEN:
b->type = BOOLEXP_OR;
break;
default:
goto error;
/* break */
}
b->sub2 = getboolexp1 (f);
if (getc (f) != ')')
goto error;
return b;
}
/* break; */
case '-':
/* obsolete NOTHING key */
/* eat it */
while ((c = getc (f)) != '\n')
if (c == EOF)
abort (); /* unexp EOF */
ungetc (c, f);
return TRUE_BOOLEXP;
/* break */
case '[':
/* property type */
b = (struct boolexp *) malloc (sizeof (struct boolexp));
b->type = BOOLEXP_PROP;
b->sub1 = b->sub2 = 0;
p = b->prop_check = new_prop ();
i = 0;
while ((c = getc (f)) != PROP_DELIMITER && i < BUFFER_LEN) {
buf[i] = c;
i++;
}
if (i >= BUFFER_LEN && c != PROP_DELIMITER)
goto error;
buf[i] = '\0';
p->type = alloc_string (buf);
i = 0;
while ((c = getc (f)) != ']') {
buf[i] = c;
i++;
}
buf[i] = '\0';
if (i >= BUFFER_LEN && c != ']')
goto error;
#ifdef NUMBER_PROPS
if (number (buf))
p->value = atol (buf);
else
#endif
p->class = alloc_string (buf);
return b;
default:
/* better be a dbref */
ungetc (c, f);
b = (struct boolexp *) malloc (sizeof (struct boolexp));
b->type = BOOLEXP_CONST;
b->thing = 0;
/* NOTE possibly non-portable code */
/* Will need to be changed if putref/getref change */
while (isdigit (c = getc (f))) {
b->thing = b->thing * 10 + c - '0';
}
ungetc (c, f);
return b;
}
error:
abort (); /* bomb out */
return TRUE_BOOLEXP;
}
struct boolexp *getboolexp (FILE * f)
{
struct boolexp *b;
b = getboolexp1 (f);
if (getc (f) != '\n')
abort (); /* parse error, we lose */
return b;
}
void free_boolexp (struct boolexp *b)
{
if (b != TRUE_BOOLEXP) {
switch (b->type) {
case BOOLEXP_AND:
case BOOLEXP_OR:
free_boolexp (b->sub1);
free_boolexp (b->sub2);
free ((void *) b);
break;
case BOOLEXP_NOT:
free_boolexp (b->sub1);
free ((void *) b);
break;
case BOOLEXP_CONST:
free ((void *) b);
break;
case BOOLEXP_PROP:
free_prop (b->prop_check);
free ((void *) b);
break;
}
}
}
struct plist *getproperties (FILE * f)
{
char buf[BUFFER_LEN], s[BUFFER_LEN];
int i, j;
struct plist *head, *curr;
head = curr = 0;
/* initialize first line stuff */
if (fgets (buf, sizeof (buf), f) == NULL)
return NULL;
while (strcmp (buf, "***Property list end ***\n") && strcmp (buf, ":\n")) {
if (!head)
head = curr = new_prop ();
else {
curr->next = new_prop ();
curr = curr->next;
}
for (i = 0; buf[i] != PROP_DELIMITER; i++)
s[i] = buf[i];
s[i] = '\0';
curr->type = alloc_string (s);
for (i++, j = 0; i < (int) strlen (buf) - 1; i++, j++) /* don't include \n */
s[j] = buf[i];
s[j] = '\0';
#ifdef NUMBER_PROPS
if (number (s))
curr->value = atol (s);
else
#endif
curr->class = alloc_string (s);
if (fgets (buf, sizeof (buf), f) == NULL)
return head;
if (curr->next)
curr = curr->next;
}
return head;
}
void free_prop (struct plist *p)
{
if (p->class)
free ((void *) p->class);
if (p->type)
free ((void *) p->type);
free ((void *) p);
}
void db_free (void)
{
dbref i;
struct object *o;
if (db) {
for (i = 0; i < db_top; i++) {
o = &db[i];
if (o->name)
free ((void *) o->name);
if (o->description)
free ((void *) o->description);
if (o->succ_message)
free ((void *) o->succ_message);
if (o->fail_message)
free ((void *) o->fail_message);
if (o->drop_message)
free ((void *) o->drop_message);
if (o->ofail)
free ((void *) o->ofail);
if (o->osuccess)
free ((void *) o->osuccess);
if (o->odrop)
free ((void *) o->odrop);
if (o->key)
free_boolexp (o->key);
if (o->properties) {
struct plist *p, *next;
for (p = o->properties; p; p = next) {
next = p->next;
free_prop (p);
}
}
if (Typeof (i) == TYPE_EXIT && o->sp.exit.dest) {
free ((void *) o->sp.exit.dest);
} else if (Typeof (i) == TYPE_PLAYER && o->sp.player.password) {
free ((void *) o->sp.player.password);
}
}
free ((void *) db);
db = 0;
db_top = 0;
}
#ifdef RECYCLE
recyclable = NOTHING;
#endif
}
struct plist *new_prop (void)
{
struct plist *p;
p = (struct plist *) malloc (sizeof (struct plist));
p->type = 0;
p->class = 0;
#ifdef NUMBER_PROPS
p->value = 0;
#endif
p->next = 0;
return p;
}
void db_read_object_old (FILE * f, struct object *o)
{
dbref exits, owner;
int pennies;
const char *password;
o->name = getstring (f);
o->description = getstring_compress (f);
o->location = getref (f);
o->contents = getref (f);
exits = getref (f);
o->next = getref (f);
o->key = getboolexp (f);
o->fail_message = getstring_compress (f);
o->succ_message = getstring_compress (f);
o->drop_message = NULL;
o->ofail = getstring_compress (f);
o->osuccess = getstring_compress (f);
o->odrop = NULL;
owner = getref (f);
pennies = getref (f);
o->flags = getref (f);
/* flags have to be checked for conflict --- if they happen to coincide
with chown_ok flags and jump_ok flags, we bump them up to
the corresponding HAVEN and ABODE flags */
if (o->flags & CHOWN_OK) {
o->flags &= ~CHOWN_OK;
#ifdef HAVEN
o->flags |= HAVEN;
#endif /* HAVEN */
}
if (o->flags & JUMP_OK) {
o->flags &= ~JUMP_OK;
#ifdef ABODE
o->flags |= ABODE;
#endif /* ABODE */
}
password = getstring (f);
#ifdef GENDER
if ((o->flags & TYPE_MASK) == TYPE_PLAYER) {
o->properties = new_prop ();
o->properties->type = alloc_string ("sex");
/* convert GENDER flag to property */
switch ((o->flags & GENDER_MASK) >> GENDER_SHIFT) {
case GENDER_NEUTER:
o->properties->class = alloc_string ("neuter");
break;
case GENDER_FEMALE:
o->properties->class = alloc_string ("female");
break;
case GENDER_MALE:
o->properties->class = alloc_string ("male");
break;
default:
o->properties->class = alloc_string ("unassigned");
break;
}
}
#endif /* GENDER */
/* For downward compatibility with databases using the */
/* obsolete ANTILOCK flag. */
if (o->flags & ANTILOCK) {
o->key = negate_boolexp (o->key);
o->flags &= ~ANTILOCK;
}
switch (o->flags & TYPE_MASK) {
case TYPE_THING:
o->sp.thing.home = exits;
o->sp.thing.actions = NOTHING;
o->sp.thing.owner = owner;
o->sp.thing.value = pennies;
break;
case TYPE_ROOM:
o->sp.room.dropto = o->location;
o->location = NOTHING;
o->sp.room.exits = exits;
o->sp.room.owner = owner;
break;
case TYPE_EXIT:
if (o->location == NOTHING) {
o->sp.exit.ndest = 0;
o->sp.exit.dest = NULL;
} else {
o->sp.exit.ndest = 1;
o->sp.exit.dest = (dbref *) malloc (sizeof (dbref));
(o->sp.exit.dest)[0] = o->location;
}
o->location = NOTHING;
o->sp.exit.owner = owner;
break;
case TYPE_PLAYER:
o->sp.player.home = exits;
o->sp.player.actions = NOTHING;
o->sp.player.pennies = pennies;
o->sp.player.password = password;
break;
#ifdef RECYCLE
case TYPE_GARBAGE:
o->next = recyclable;
recyclable = o - db;
free ((void *) o->name);
free ((void *) o->description);
o->name = "<garbage>";
o->description = "<recyclable>";
break;
#endif
}
}
void db_read_object_new (FILE * f, struct object *o)
{
int j;
o->name = getstring (f);
o->description = getstring_compress (f);
o->location = getref (f);
o->contents = getref (f);
/* o->exits = getref(f); */
o->next = getref (f);
o->key = getboolexp (f);
o->fail_message = getstring_compress (f);
o->succ_message = getstring_compress (f);
o->drop_message = NULL;
o->ofail = getstring_compress (f);
o->osuccess = getstring_compress (f);
o->odrop = NULL;
/* o->owner = getref(f); */
/* o->pennies = getref(f); */
o->flags = getref (f);
/* flags have to be checked for conflict --- if they happen to coincide
with chown_ok flags and jump_ok flags, we bump them up to
the corresponding HAVEN and ABODE flags */
if (o->flags & CHOWN_OK) {
o->flags &= ~CHOWN_OK;
#ifdef HAVEN
o->flags |= HAVEN;
#endif /* HAVEN */
}
if (o->flags & JUMP_OK) {
o->flags &= ~JUMP_OK;
#ifdef ABODE
o->flags |= ABODE;
#endif /* ABODE */
}
#ifdef GENDER
if ((o->flags & TYPE_MASK) == TYPE_PLAYER) {
o->properties = new_prop ();
o->properties->type = alloc_string ("sex");
/* convert GENDER flag to property */
switch ((o->flags & GENDER_MASK) >> GENDER_SHIFT) {
case GENDER_NEUTER:
o->properties->class = alloc_string ("neuter");
break;
case GENDER_FEMALE:
o->properties->class = alloc_string ("female");
break;
case GENDER_MALE:
o->properties->class = alloc_string ("male");
break;
default:
o->properties->class = alloc_string ("unassigned");
break;
}
}
#endif /* GENDER */
/* o->password = getstring(f); */
/* For downward compatibility with databases using the */
/* obsolete ANTILOCK flag. */
if (o->flags & ANTILOCK) {
o->key = negate_boolexp (o->key);
o->flags &= ~ANTILOCK;
}
switch (o->flags & TYPE_MASK) {
case TYPE_THING:
o->sp.thing.home = getref (f);
o->sp.thing.actions = getref (f);
o->sp.thing.owner = getref (f);
o->sp.thing.value = getref (f);
break;
case TYPE_ROOM:
o->sp.room.dropto = getref (f);
o->sp.room.exits = getref (f);
o->sp.room.owner = getref (f);
break;
case TYPE_EXIT:
o->sp.exit.ndest = getref (f);
o->sp.exit.dest = (dbref *) malloc (sizeof (dbref)
* o->sp.exit.ndest);
for (j = 0; j < o->sp.exit.ndest; j++) {
(o->sp.exit.dest)[j] = getref (f);
}
o->sp.exit.owner = getref (f);
break;
case TYPE_PLAYER:
o->sp.player.home = getref (f);
o->sp.player.actions = getref (f);
o->sp.player.pennies = getref (f);
o->sp.player.password = getstring (f);
break;
#ifdef RECYCLE
case TYPE_GARBAGE:
o->next = recyclable;
recyclable = o - db;
free ((void *) o->name);
free ((void *) o->description);
o->name = "<garbage>";
o->description = "<recyclable>";
break;
#endif
}
}
void db_read_object_lachesis (FILE * f, struct object *o, int old)
{
dbref j;
struct plist *newp;
char buf[BUFFER_LEN];
o->name = getstring (f);
o->description = getstring_compress (f);
o->location = getref (f);
o->contents = getref (f);
/* o->exits = getref(f); */
o->next = getref (f);
o->key = getboolexp (f);
o->fail_message = getstring_compress (f);
o->succ_message = getstring_compress (f);
o->drop_message = getstring_compress (f);
o->ofail = getstring_compress (f);
o->osuccess = getstring_compress (f);
o->odrop = getstring_compress (f);
/* o->owner = getref(f); */
/* o->pennies = getref(f); */
o->flags = getref (f);
if (old)
(void) fgets (buf, sizeof (buf), f);
o->properties = getproperties (f);
#if 0
#ifdef GENDER
/* set gender stuff */
if (old && ((o->flags & TYPE_MASK) == TYPE_PLAYER)) {
newp = new_prop ();
if (!o->properties)
o->properties = newp;
else {
newp->next = o->properties;
o->properties = newp;
}
newp->type = alloc_string ("sex");
/* convert GENDER flag to property */
switch ((o->flags & GENDER_MASK) >> GENDER_SHIFT) {
case GENDER_NEUTER:
newp->class = alloc_string ("neuter");
break;
case GENDER_FEMALE:
newp->class = alloc_string ("female");
break;
case GENDER_MALE:
newp->class = alloc_string ("male");
break;
default:
newp->class = alloc_string ("unassigned");
break;
}
}
#endif /* GENDER */
#endif
/* o->password = getstring(f); */
/* For downward compatibility with databases using the */
/* obsolete ANTILOCK flag. */
if (o->flags & ANTILOCK) {
o->key = negate_boolexp (o->key);
o->flags &= ~ANTILOCK;
}
switch (o->flags & TYPE_MASK) {
case TYPE_THING:
o->sp.thing.home = getref (f);
o->sp.thing.actions = getref (f);
o->sp.thing.owner = getref (f);
o->sp.thing.value = getref (f);
break;
case TYPE_ROOM:
o->sp.room.dropto = getref (f);
o->sp.room.exits = getref (f);
o->sp.room.owner = getref (f);
break;
case TYPE_EXIT:
o->sp.exit.ndest = getref (f);
o->sp.exit.dest = (dbref *) malloc (sizeof (dbref)
* o->sp.exit.ndest);
for (j = 0; j < o->sp.exit.ndest; j++) {
(o->sp.exit.dest)[j] = getref (f);
}
o->sp.exit.owner = getref (f);
break;
case TYPE_PLAYER:
o->sp.player.home = getref (f);
o->sp.player.actions = getref (f);
o->sp.player.pennies = getref (f);
o->sp.player.password = getstring (f);
break;
#ifdef RECYCLE
case TYPE_GARBAGE:
o->next = recyclable;
recyclable = o - db;
free ((void *) o->name);
free ((void *) o->description);
o->name = "<garbage>";
o->description = "<recyclable>";
break;
#endif
}
}
dbref db_read (FILE * f)
{
dbref i, j, next;
struct object *o;
const char *special;
int newformat;
char c;
newformat = 0;
if ((c = getc (f)) == '*') {
special = getstring (f);
if (!strcmp (special, "**TinyMUCK DUMP Format***")) {
newformat = 1;
} else if (!strcmp (special, "**Lachesis TinyMUCK DUMP Format***")) {
newformat = 2;
} else if (!strcmp (special,
"**Christina Applegate TinyMUCK DUMP Format***")) {
newformat = 3;
}
free ((void *) special);
c = getc (f); /* get next char */
}
db_free ();
clear_players ();
for (i = 0;; i++) {
switch (c) {
case '#':
/* another entry, yawn */
if (i != getref (f)) {
/* we blew it */
return -1;
}
/* make space */
db_grow (i + 1);
/* read it in */
o = db + i;
switch (newformat) {
case 0:
db_read_object_old (f, o);
break;
case 1:
db_read_object_new (f, o);
break;
case 2:
db_read_object_lachesis (f, o, 1);
break;
case 3:
db_read_object_lachesis (f, o, 0);
break;
}
if (Typeof (i) == TYPE_PLAYER)
add_player (i);
break;
case '*':
special = getstring_noalloc (f);
if (strcmp (special, "**END OF DUMP***")) {
return -1;
} else {
if (newformat < 2) {
for (i = 0; i < db_top; i++) {
if (Typeof (i) == TYPE_ROOM) {
DOLIST (j, db[i].sp.room.exits) {
db[j].location = i;
}
} else if (Typeof (i) == TYPE_PLAYER) {
for (j = db[i].contents; j != NOTHING; j = next) {
next = db[j].next;
if (Typeof (j) == TYPE_EXIT) {
fprintf (stderr, "Exit %d found on %s(%d)\n",
j, db[i].name, i);
db[i].contents = remove_first (db[i].contents, j);
db[j].location = i;
PUSH (j, db[i].sp.player.actions);
if (db[j].sp.exit.ndest) {
free ((void *) db[j].sp.exit.dest);
db[j].sp.exit.dest = NULL;
}
db[j].sp.exit.ndest = 0;
}
}
}
}
}
return db_top;
}
default:
return -1;
/* break; */
}
c = getc (f);
} /* for */
} /* db_read */
void db_free_object (dbref i)
{
struct object *o;
o = &db[i];
if (o->name)
free ((void *) o->name);
if (o->description)
free ((void *) o->description);
if (o->succ_message)
free ((void *) o->succ_message);
if (o->fail_message)
free ((void *) o->fail_message);
if (o->drop_message)
free ((void *) o->drop_message);
if (o->ofail)
free ((void *) o->ofail);
if (o->osuccess)
free ((void *) o->osuccess);
if (o->odrop)
free ((void *) o->odrop);
if (o->key)
free_boolexp (o->key);
if (o->properties) {
struct plist *p, *next;
for (p = o->properties; p; p = next) {
next = p->next;
free_prop (p);
}
}
if (Typeof (i) == TYPE_EXIT && o->sp.exit.dest) {
free ((void *) o->sp.exit.dest);
} else if (Typeof (i) == TYPE_PLAYER && o->sp.player.password) {
free ((void *) o->sp.player.password);
}
}
void db_clear_object (dbref i)
{
struct object *o = db + i;
o->name = 0;
o->description = 0;
o->location = NOTHING;
o->contents = NOTHING;
o->next = NOTHING;
o->key = TRUE_BOOLEXP;
o->fail_message = 0;
o->succ_message = 0;
o->drop_message = 0;
o->ofail = 0;
o->osuccess = 0;
o->odrop = 0;
o->properties = 0;
/* flags you must initialize yourself */
/* type-specific fields you must also initialize */
}