/* $Header: /belch_a/users/rearl/tinymuck/src/RCS/db.c,v 1.11 90/09/28 12:19:46 rearl Exp $ */
/*
* $Log: db.c,v $
* Revision 1.11 90/09/28 12:19:46 rearl
* Took out alloc_string(), moved it to stringutil.c
*
* Revision 1.10 90/09/18 07:55:13 rearl
* Added hash tables, changed program `locked' field to INTERNAL flag.
*
* Revision 1.9 90/09/16 04:41:54 rearl
* Preparation code added for disk-based MUCK.
*
* Revision 1.8 90/09/10 02:19:46 rearl
* Introduced string compression of properties, for the
* COMPRESS compiler option.
*
* Revision 1.7 90/09/01 05:57:03 rearl
* Took out TEST_MALLOC references.
*
* Revision 1.6 90/08/27 03:22:33 rearl
* Disk-based MUF source code, added neccesary locking.
*
* Revision 1.5 90/08/15 03:00:59 rearl
* Cleaned up some stuff, took out #ifdef GENDER.
*
* Revision 1.4 90/08/02 18:47:46 rearl
* Fixed calls to logging functions.
*
* Revision 1.3 90/07/29 17:31:20 rearl
* One picky pointer cast fixed.
*
* Revision 1.2 90/07/23 03:12:27 casie
* Cleaned up various gcc warnings.
*
* Revision 1.1 90/07/19 23:03:24 casie
* Initial revision
*
*
*/
#include "copyright.h"
#include "config.h"
#include <stdio.h>
#include <ctype.h>
#include "db.h"
#include "params.h"
#include "interface.h"
#include "externs.h"
struct object *db = 0;
dbref db_top = 0;
#ifdef RECYCLE
dbref recyclable = NOTHING;
#endif
#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 macrotable *macrotop;
struct plist *new_prop(void);
void free_prop(struct plist *p);
int number(const char *s);
void putproperties(FILE *f, struct plist *p);
void putprop(FILE *f, struct plist *p);
void getproperties(FILE *f, dbref objno);
void getpropertieslach(FILE *f, dbref objno);
void
free_line(struct line *l)
{
if (l -> this_line)
free((void *) l -> this_line);
free((void *) l);
}
void
free_prog_text(struct line *l)
{
struct line *next;
while (l) {
next = l -> next;
free_line(l);
l = next;
}
}
#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 */
void db_clear_object(dbref i)
{
struct object *o = DBFETCH(i);
NAME(i) = 0;
o->location = NOTHING;
o->contents = NOTHING;
o->next = NOTHING;
o->key = TRUE_BOOLEXP;
o->attributes = 0;
o->properties = 0;
DBDIRTY(i);
o->exits=NOTHING;
o->contents=NOTHING;
o->curr_prog=NOTHING;
o->insert_mode=0;
o->run=0;
/* flags you must initialize yourself */
/* type-specific fields you must also initialize */
}
dbref new_object(void)
{
dbref newobj;
#ifdef RECYCLE
if(recyclable != NOTHING) {
newobj = recyclable;
recyclable = DBFETCH(newobj)->next;
} else
#endif
{
newobj = db_top;
db_grow(db_top + 1);
}
/* clear it out */
db_clear_object(newobj);
return newobj;
}
#define DB_MSGLEN 1024
void putref(FILE *f, dbref ref)
{
fprintf(f, "%d\n", ref);
}
static void putstring(FILE *f, const char *s)
{
if(s) {
fputs((char *)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((char *)prop -> type, f);
putc(PROP_DELIMITER, f);
fputs(prop -> class, f);
}
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;
}
}
void
macrodump(struct macrotable *node, FILE *f)
{
if (!node) return;
macrodump(node -> left, f);
putstring(f, node -> name);
putstring(f, node -> definition);
putref(f, node -> implementor);
macrodump(node -> right, f);
}
char *
file_line(FILE *f)
{
char buf[BUFFER_LEN];
if (!fgets(buf, BUFFER_LEN, f)) return NULL;
buf[strlen(buf) - 1] = '\0';
return alloc_string(buf);
}
void
foldtree (struct macrotable *center)
{
int count = 0;
struct macrotable *nextcent = center;
for (; nextcent; nextcent = nextcent -> left) count++;
if (count > 1) {
for (nextcent = center, count /= 2; count--; nextcent = nextcent -> left);
if (center -> left) center -> left -> right = NULL;
center -> left = nextcent;
foldtree(center -> left);
}
for (count = 0, nextcent = center; nextcent; nextcent = nextcent -> right)
count++;
if (count > 1) {
for (nextcent = center, count /= 2; count--; nextcent = nextcent -> right);
if (center -> right) center -> right -> left = NULL;
foldtree(center -> right);
}
}
int
macrochain (struct macrotable *lastnode, FILE *f)
{
char *line, *line2;
struct macrotable *newmacro;
if (!(line = file_line(f))) return 0;
line2 = file_line(f);
newmacro = (struct macrotable *)new_macro(line, line2, getref(f));
if (!macrotop) macrotop = (struct macrotable *)newmacro;
else {
newmacro -> left = lastnode;
lastnode -> right = newmacro;
}
return (1 + macrochain(newmacro, f));
}
void macroload(FILE *f)
{
int count = 0;
macrotop = NULL;
count = macrochain(macrotop, f);
fclose(f);
for (count /= 2; count--; macrotop = macrotop -> right);
foldtree(macrotop);
return;
}
void
write_program(struct line *first, dbref i)
{
FILE *f;
char fname[BUFFER_LEN];
sprintf(fname, "muf/%d.m", (int) i);
f = fopen(fname, "w");
if (!f) {
log_status("Couldn't open file %s!\n", fname);
return;
}
while (first) {
if (!first -> this_line)
continue;
fputs((char *)first -> this_line, f);
fputc('\n', f);
first = first -> next;
}
fclose(f);
}
int db_write_object(FILE *f, dbref i)
{
struct object *o = DBFETCH(i);
int j;
putstring(f, NAME(i));
putref(f, o->location);
putref(f, o->contents);
putref(f, o->next);
putboolexp(f, o->key);
putref(f, (FLAGS(i) & ~INTERACTIVE));
putstring(f, "***Property list start ***");
putproperties(f, o->attributes);
putproperties(f, o->properties);
putstring(f, "***Property list end ***");
switch (Typeof(i)) {
case TYPE_THING:
putref(f, o->link);
putref(f, o->exits);
putref(f, OWNER(i));
putref(f, o->sp.thing.value);
break;
case TYPE_ROOM:
putref(f, o->link);
putref(f, o->exits);
putref(f, OWNER(i));
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, OWNER(i));
break;
case TYPE_PLAYER:
putref(f, o->link);
putref(f, o->exits);
putref(f, o->sp.player.pennies);
putstring(f, o->sp.player.password);
break;
case TYPE_PROGRAM:
putref(f, OWNER(i));
break;
}
return 0;
}
dbref db_write(FILE *f)
{
dbref i;
fputs("***MAGE 1.1 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;
char c;
fgets(buf, sizeof(buf), f);
if (strlen(buf) == DB_MSGLEN - 1)
{
/* ignore whatever comes after */
if (buf[DB_MSGLEN - 2] != '\n')
while ((c = fgetc(f)) != '\n')
;
}
for(p = buf; *p; p++) {
if(*p == '\n') {
*p = '\0';
break;
}
}
return buf;
}
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(const char *s)
{
if (!s) return 0;
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;
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;
}
}
}
void
getproperties(FILE *f, dbref object)
{
char buf[BUFFER_LEN], s[BUFFER_LEN];
int i, j;
char *type, *class;
/* get rid of first line */
fgets(buf, sizeof(buf), f);
/* initialize first line stuff */
fgets(buf, sizeof(buf), f);
while (strcmp(buf, "***Property list end ***\n")) /* fgets reads in \n too! */
{
for (i = 0; buf[i] != PROP_DELIMITER; i++)
s[i] = buf[i];
s[i] = '\0';
type = alloc_string(s);
for (i++, j = 0; i < strlen(buf) - 1; i++, j++) /* don't include \n */
s[j] = buf[i];
s[j] = '\0';
class = alloc_compressed(s);
add_property(object, type, class);
free((void *) class);
free((void *) type);
fgets(buf, sizeof(buf), f);
}
}
void
getpropertieslach(FILE *f, dbref object)
{
char buf[BUFFER_LEN], s[BUFFER_LEN];
int i, j;
int flag;
char *type, *class;
const static char *toattr[11] = { "Ahear", "Aahear", "Amhear", "Adesc",
"Adrop", "Afail", "Asucc", "Listen",
"Sex", "Idesc", "Odesc" };
/* get rid of first line */
fgets(buf, sizeof(buf), f);
/* initialize first line stuff */
fgets(buf, sizeof(buf), f);
while (strcmp(buf, "***Property list end ***\n")) /* fgets reads in \n too! */
{
for (i = 0; buf[i] != PROP_DELIMITER; i++)
s[i] = buf[i];
s[i] = '\0';
type = alloc_string(s);
for (i++, j = 0; i < strlen(buf) - 1; i++, j++) /* don't include \n */
s[j] = buf[i];
s[j] = '\0';
if(s[0] == '^')
class = alloc_compressed(s + 1);
else if(!strncmp(s, "*s*", 3)) /* for MAGE 1.0 db */
class = alloc_compressed(s + 3);
else if(!strncmp(s, "*i*", 3))
class = alloc_compressed(s + 3);
else
class = alloc_compressed(s);
/* convert Va - Vz properties to attributes.. */
if((tolower(type[0]) == 'v') && (strlen(type) == 2)) {
if(tolower(type[1]) < 'a' || tolower(type[1]) > 'z') {
add_property(object, type, class); /* normal property */
} else {
type[0] = 'V';
type[1] = tolower(type[1]);
add_attr(object, type, class);
}
}
else { /* convert special properties to attributes */
flag = 1;
for(i = 0; (i < 11) && flag; i++) {
if(!string_compare(toattr[i], type)) {
add_attr(object, toattr[i], class);
flag = 0;
}
}
if(flag) /* type was not was of the attributes */
add_property(object, type, class);
}
free((void *) class);
free((void *) type);
fgets(buf, sizeof(buf), f);
}
}
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_object(dbref i)
{
struct object *o;
o = DBFETCH(i);
if(NAME(i)) free((void *) NAME(i));
if(o->key) free_boolexp(o->key);
if (o->attributes)
{
struct plist *p, *next;
for(p = o->attributes; p; p = next)
{
next = p -> next;
free_prop(p);
}
}
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);
}
if (Typeof(i) == TYPE_PROGRAM)
{
int j;
struct inst *code;
code = o->sp.program.code;
if (code)
{
for (j = 0; j < o->sp.program.siz; j++)
if (code[j].type == PROG_STRING && code[j].data.string)
free((void *) code[j].data.string);
free((void *) code);
}
}
DBDIRTY(i);
}
void db_free(void)
{
dbref i;
if(db) {
for(i = 0; i < db_top; i++)
db_free_object(i);
free((void *) db);
db = 0;
db_top = 0;
}
clear_players();
clear_primitives();
#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; p -> next = 0;
return p;
}
struct line *
get_new_line()
{
struct line *new;
new = (struct line *) malloc(sizeof(struct line));
new -> this_line = NULL;
new -> next = NULL;
new -> prev = NULL;
return new;
}
struct line *
read_program(dbref i)
{
char buf[BUFFER_LEN];
struct line *first;
struct line *prev;
struct line *new;
FILE *f;
first = NULL;
sprintf(buf, "muf/%d.m", (int) i);
f = fopen(buf, "r");
if (!f) return 0;
while (fgets(buf, BUFFER_LEN, f))
{
new = get_new_line();
buf[strlen(buf) - 1] = '\0';
new -> this_line = alloc_string(buf);
if (!first)
first = prev = new;
else
{
prev -> next = new;
new -> prev = prev;
prev = new;
}
}
fclose(f);
return first;
}
void db_read_object_mage(FILE *f, register struct object *o, dbref objno)
{
int j, c, prop_flag = 0;
NAME(objno) = getstring(f);
o->location = getref(f);
o->contents = getref(f);
o->next = getref(f);
o->key = getboolexp(f);
o->flags = getref(f);
c = getc(f);
if (c == '*')
{
getproperties(f, objno);
prop_flag++;
}
else
{
/* do our own getref */
int sign = 0;
char buf[BUFFER_LEN];
int i = 0;
if (c == '-')
sign = 1;
else if (c != '+')
{
buf[i] = c;
i++;
}
while ((c = getc(f)) != '\n')
{
buf[i] = c;
i++;
}
buf[i] = '\0';
j = atol(buf);
if (sign)
j = -j;
}
switch (FLAGS(objno) & TYPE_MASK) {
case TYPE_THING:
o->link = prop_flag ? getref(f) : j;
o->exits = getref(f);
OWNER(objno) = getref(f);
o->sp.thing.value = getref(f);
break;
case TYPE_ROOM:
o->link = prop_flag ? getref(f) : j;
o->exits = getref(f);
OWNER(objno) = getref(f);
break;
case TYPE_EXIT:
o->sp.exit.ndest = prop_flag ? getref(f) : j;
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);
}
OWNER(objno) = getref(f);
break;
case TYPE_PLAYER:
o->link = prop_flag ? getref(f) : j;
o->exits = getref(f);
o->sp.player.pennies = getref(f);
o->sp.player.password = getstring(f);
o->curr_prog = NOTHING;
o->insert_mode = 0;
o->run = 0;
break;
case TYPE_PROGRAM:
OWNER(objno) = getref(f);
FLAGS(objno) &= ~INTERNAL;
o -> sp.program.curr_line = 0;
/* o -> sp.program.first = read_program(objno); */
o -> sp.program.code = 0;
o -> sp.program.siz = 0;
o -> sp.program.start = 0;
/* do_compile(GOD, objno);
free_prog_text(o -> sp.program.first); */
break;
#ifdef RECYCLE
case TYPE_GARBAGE:
o->next = recyclable;
recyclable = objno;
free((void *)NAME(objno));
NAME(objno) = "<garbage>";
add_attr(objno, "Desc", "<recyclable>");
break;
#endif
}
}
void db_read_object_lachesis(FILE *f,register struct object *o, dbref objno)
{
int j, c, prop_flag = 0;
NAME(objno) = getstring(f);
add_attr(objno, "Desc", getstring_compress(f));
o->location = getref(f);
o->contents = getref(f);
o->next = getref(f);
o->key = getboolexp(f);
add_attr(objno, "Fail", getstring_compress(f));
add_attr(objno, "Succ", getstring_compress(f));
add_attr(objno, "Drop", getstring_compress(f));
add_attr(objno, "Ofail", getstring_compress(f));
add_attr(objno, "Osucc", getstring_compress(f));
add_attr(objno, "Odrop", getstring_compress(f));
/* OWNER(objno) = getref(f); */
/* o->pennies = getref(f); */
o->flags = getref(f); /* FLAGS(objno) = getref(f);*/
c = getc(f);
if (c == '*')
{
getpropertieslach(f, objno);
prop_flag++;
}
else
{
/* do our own getref */
int sign = 0;
char buf[BUFFER_LEN];
int i = 0;
if (c == '-')
sign = 1;
else if (c != '+')
{
buf[i] = c;
i++;
}
while ((c = getc(f)) != '\n')
{
buf[i] = c;
i++;
}
buf[i] = '\0';
j = atol(buf);
if (sign)
j = -j;
/* set gender stuff */
/* convert GENDER flag to property */
switch((FLAGS(objno) & GENDER_MASK) >> GENDER_SHIFT)
{
case GENDER_NEUTER:
add_attr(objno, "sex", "neuter");
break;
case GENDER_FEMALE:
add_attr(objno, "sex", "female");
break;
case GENDER_MALE:
add_attr(objno, "sex", "male");
break;
default:
add_attr(objno, "sex", "unassigned");
break;
}
}
/* 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 (FLAGS(objno) & TYPE_MASK) {
case TYPE_THING:
o->link = prop_flag ? getref(f) : j;
o->exits = getref(f);
OWNER(objno) = getref(f);
o->sp.thing.value = getref(f);
break;
case TYPE_ROOM:
o->link = prop_flag ? getref(f) : j;
o->exits = getref(f);
OWNER(objno) = getref(f);
break;
case TYPE_EXIT:
o->sp.exit.ndest = prop_flag ? getref(f) : j;
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);
}
OWNER(objno) = getref(f);
break;
case TYPE_PLAYER:
o->link = prop_flag ? getref(f) : j;
o->exits = getref(f);
o->sp.player.pennies = getref(f);
o->sp.player.password = getstring(f);
o->curr_prog = NOTHING;
o->insert_mode = 0;
o->run = 0;
break;
case TYPE_PROGRAM:
OWNER(objno) = getref(f);
FLAGS(objno) &= ~INTERNAL;
o -> sp.program.curr_line = 0;
o -> sp.program.first = read_program(objno);
o -> sp.program.code = 0;
o -> sp.program.siz = 0;
o -> sp.program.start = 0;
do_compile(GOD, objno);
free_prog_text(o -> sp.program.first);
break;
#ifdef RECYCLE
case TYPE_GARBAGE:
o->next = recyclable;
recyclable = objno;
free((void *)NAME(objno));
NAME(objno) = "<garbage>";
add_attr(objno, "Desc", "<recyclable>");
break;
#endif
}
}
dbref db_read(FILE *f)
{
dbref i;
struct object *o;
const char *special;
int newformat;
char c;
newformat = 0;
if ( (c = getc(f)) == '*') {
special = getstring(f);
if(!strcmp(special, "**MAGE 1.1 DUMP Format***")) {
newformat = 1;
}
else if (!strcmp(special, "**Lachesis TinyMUCK DUMP Format***"))
{
newformat = 2;
}
free((void *)special);
c = getc(f); /* get next char */
}
db_free();
init_primitives();
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 = DBFETCH(i);
switch (newformat)
{
/* case 0:
db_read_object_old(f, o, i);
break; */
case 1:
db_read_object_mage(f, o, i);
break;
case 2:
db_read_object_lachesis(f, o, i);
break;
}
if (Typeof(i) == TYPE_PLAYER) {
OWNER(i) = i;
add_player(i);
}
break;
case '*':
special = getstring(f);
if(strcmp(special, "**END OF DUMP***")) {
free((void *) special);
return -1;
} else {
free((void *) special);
return db_top;
}
default:
return -1;
/* break; */
}
c = getc(f);
} /* for */
} /* db_read */