#include "copyright.h"
#include "config.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "db.h"
#include "params.h"
#include "interface.h"
#include "externs.h"
static char garbagebuf[BUFFER_LEN];
object *db = 0;
dbref db_top = 0;
dbref compost_heap = NOTHING;
static char buf[BUFSIZ];
#ifndef DB_INITIAL_SIZE
#define DB_INITIAL_SIZE 1000
#endif /* DB_INITIAL_SIZE */
#define COUNTER_MAX 10000
#define VALIDATE_LISTS
#ifdef DB_DOUBLING
dbref db_size = DB_INITIAL_SIZE;
#endif /* DB_DOUBLING */
macrotable *macrotop;
extern char *dup_string(char *);
int number(char *s);
extern char *crypt(char *key, char *salt);
/* returns 0 if password matches */
int check_password(char *plaintext, dbref player)
{
char salt[3];
salt[0] = DBFETCH(player)->sp.player.password[0];
salt[1] = DBFETCH(player)->sp.player.password[1];
salt[2] = '\0';
return(strcmp(DBFETCH(player)->sp.player.password,crypt(plaintext,salt)));
}
char *make_password(char *plaintext)
{
static char salt_chars[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890./";
char salt[3];
char *tmp;
if (!plaintext) return NULL;
salt[0] = salt_chars[random() % 64];
salt[1] = salt_chars[random() % 64];
salt[2] = '\0';
tmp = (char *)malloc(sizeof(char)*14);
strcpy(tmp,crypt(plaintext,salt));
free(plaintext);
return(tmp);
}
void free_line(line *l)
{
if (l->this_line) free((void *) l->this_line);
free((void *) l);
}
void free_prog_text(line *l)
{
line *next;
while (l)
{
next = l->next;
free_line(l);
l = next;
}
}
#ifdef DB_DOUBLING
static void db_grow(dbref newtop)
{
object *newdb;
if(newtop > db_top)
{
db_top = newtop;
if(!db)
{
/* make the initial one */
db_size = DB_INITIAL_SIZE;
if((db = (object *)malloc(db_size * sizeof(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 = (object *)realloc((void *) db,
db_size * sizeof(object))) == 0) abort();
db = newdb;
}
}
}
#else /* DB_DOUBLING */
static void db_grow(dbref newtop)
{
object *newdb;
if(newtop > db_top)
{
db_top = newtop;
if(db)
{
if((newdb = (object *)
realloc((void *) db,
db_top * sizeof(object))) == 0)
abort();
db = newdb;
}
else
{
/* make the initial one */
if((db = (object *)
malloc(DB_INITIAL_SIZE * sizeof(object))) == 0)
abort();
}
}
}
#endif /* DB_DOUBLING */
void db_clear_object(dbref i)
{
DBSTORE(i, name, NULL);
#ifndef USE_DBP_STR
DBSTORE(i, desc, NULL);
DBSTORE(i, succ, NULL);
DBSTORE(i, fail, NULL);
DBSTORE(i, drop, NULL);
DBSTORE(i, osucc, NULL);
DBSTORE(i, ofail, NULL);
DBSTORE(i, odrop, NULL);
#endif
DBSTOREPROP(i, NULL);
DBSTORE(i, backlinks, NULL);
DBSTORE(i, backlocks, NULL);
DBSTORE(i, exits, NOTHING);
DBSTORE(i, location, NOTHING);
DBSTORE(i, contents, NOTHING);
DBSTORE(i, next, NOTHING);
DBSTORE(i, nextowned, NOTHING);
DBSTORE(i, key, TRUE_BOOLEXP);
DBSTORE(i, link, NOTHING);
DBSTORE(i, pennies, 0);
#ifdef TIMESTAMPS
DBSTORE(i, time_created, time(NULL));
DBSTORE(i, time_modified, DBFETCH(i)->time_created);
DBSTORE(i, time_used, DBFETCH(i)->time_created);
#endif
}
void add_compost(dbref d)
{
dbref scan;
if ((compost_heap == NOTHING) || (d < compost_heap))
{
/* insert at head of list */
DBSTORE(d, next, compost_heap);
compost_heap = d;
}
else
{
for(scan = compost_heap; (DBFETCH(scan)->next != NOTHING) &&
(DBFETCH(scan)->next < d); scan = DBFETCH(scan)->next);
DBSTORE(d, next, DBFETCH(scan)->next);
DBSTORE(scan, next, d);
}
}
dbref new_object()
{
dbref newobj;
if(compost_heap != NOTHING)
{
newobj = compost_heap;
compost_heap = DBFETCH(newobj)->next;
}
else
{
newobj = db_top;
db_grow(db_top + 1);
}
/* clear it out */
db_clear_object(newobj);
#ifdef USE_DBP
dbp_load(newobj);
#endif
return newobj;
}
#define DB_MSGLEN 512
void putref(FILE *f, dbref ref)
{
fprintf(f, "%ld\n", ref);
}
static void putstring(FILE *f, char *s)
{
if(s) fputs(s, f);
putc('\n', f);
}
static void putbool_subexp(FILE *f, 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, "%ld", b->thing);
break;
case BOOLEXP_PROP:
fprintf(f, "[%s:%s]", b->prop_name, b->prop_data);
break;
default:
break;
}
}
void putboolexp(FILE *f, boolexp *b)
{
if(b != TRUE_BOOLEXP) putbool_subexp(f, b);
putc('\n', f);
}
void macrodump(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)
{
if (!fgets(buf, BUFSIZ, f)) return NULL;
buf[strlen(buf) - 1] = '\0';
return dup_string(buf);
}
void foldtree (macrotable *center)
{
int count = 0;
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(macrotable *lastnode, FILE *f)
{
char *line1, *line2;
macrotable *newmacro;
if (!(line1 = file_line(f))) return 0;
line2 = file_line(f);
newmacro = (macrotable *)new_macro(line1, line2, getref(f));
/* file_line returns malloc'd strings */
/* new_macro dup_strings it's arguments, so we need to free */
if (line1)
free(line1);
if (line2)
free(line2);
if (!macrotop) macrotop = (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(line *first, dbref i)
{
FILE *f;
sprintf(buf, "muf/%ld.m", i);
f = fopen(buf, "w");
if (!f)
{
log_status("Couldn't open file %s!\n", buf);
return;
}
while (first)
{
if (!first->this_line) continue;
fputs(first->this_line, f);
fputc('\n', f);
first = first->next;
}
fclose(f);
}
int db_write_object(FILE *f, dbref i)
{
int j;
object *o = DBFETCH(i);
#ifndef STRINGS_ONLY
putstring(f, NAME(i));
#endif
#ifndef USE_DBP_STR
putstring(f, o->desc);
#else
putc('\n', f);
#endif
#ifndef STRINGS_ONLY
putref(f, o->location);
putref(f, o->contents);
putref(f, o->link);
putref(f, o->exits);
putref(f, o->pennies);
putref(f, o->next);
putref(f, o->nextowned);
putref(f, o->owner);
putboolexp(f, o->key);
#endif
#ifndef USE_DBP_STR
putstring(f, o->fail);
putstring(f, o->succ);
putstring(f, o->drop);
putstring(f, o->ofail);
putstring(f, o->osucc);
putstring(f, o->odrop);
#else
putc('\n', f);
putc('\n', f);
putc('\n', f);
putc('\n', f);
putc('\n', f);
putc('\n', f);
#endif /* USE_DBP_STR */
#ifndef STRINGS_ONLY
putref(f, (FLAGS(i) & ~INTERACTIVE));
#ifdef TIMESTAMPS
putref(f, o->time_created);
putref(f, o->time_modified);
putref(f, o->time_used);
#else
putref(f, 0);
putref(f, 0);
putref(f, 0);
#endif
putstring(f, "*backlinks*");
dbreflist_dump(f, o->backlinks);
putstring(f, "*end backlinks*");
putstring(f, "*backlocks*");
dbreflist_dump(f, o->backlocks);
putstring(f, "*end backlocks*");
putstring(f, "***Property list start ***");
#endif /* STRINGS_ONLY */
#ifndef USE_DBP
putproperties(f, i);
#endif
#ifndef STRINGS_ONLY
putstring(f, "***Property list end ***");
switch (Typeof(i))
{
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]);
break;
case TYPE_PLAYER:
putstring(f, o->sp.player.password);
}
#endif /* STRINGS_ONLY */
return 0;
}
/* what a hack! Let people write lachesis style dumps... */
int db_write_object_lachesis(FILE *f, dbref i)
{
object *o = DBFETCH(i);
int j;
putstring(f, NAME(i));
#ifndef USE_DBP_STR
putstring(f, o->desc);
#else
putstring(f, get_property_data(i, "desc", ACCESS_WI));
#endif
putref(f, o->location);
putref(f, o->contents);
putref(f, o->next);
putboolexp(f, o->key);
#ifndef USE_DBP_STR
putstring(f, o->fail);
putstring(f, o->succ);
putstring(f, o->drop);
putstring(f, o->ofail);
putstring(f, o->osucc);
putstring(f, o->odrop);
#else
putstring(f, get_property_data(i, "fail", ACCESS_WI));
putstring(f, get_property_data(i, "succ", ACCESS_WI));
putstring(f, get_property_data(i, "drop", ACCESS_WI));
putstring(f, get_property_data(i, "ofail", ACCESS_WI));
putstring(f, get_property_data(i, "osucc", ACCESS_WI));
putstring(f, get_property_data(i, "odrop", ACCESS_WI));
#endif
putref(f, (FLAGS(i) & ~INTERACTIVE));
putstring(f, "***Property list start ***");
#ifndef USE_DBP
putproperties(f, i);
#endif
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->pennies);
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->pennies);
putstring(f, o->sp.player.password);
break;
case TYPE_PROGRAM:
putref(f, OWNER(i));
break;
}
return 0;
}
dbref db_write_lachesis(FILE *f)
{
dbref i;
fputs("***Lachesis TinyMUCK DUMP Format***\n", f);
for(i = 0; i < db_top; i++)
{
fprintf(f, "#%ld\n", i);
db_write_object_lachesis(f, i);
}
fputs("***END OF DUMP***\n", f);
fflush(f);
return(db_top);
}
dbref db_write(FILE *f)
{
dbref i;
fputs("***MULCH***\n", f);
for(i = 0; i < db_top; i++)
{
fprintf(f, "#%ld\n", i);
db_write_object(f, i);
}
fputs("***END OF DUMP***\n", f);
fflush(f);
return(db_top);
}
dbref parse_dbref(char *s)
{
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)
{
fgets(buf, sizeof(buf), f);
return(atol(buf));
}
static char *getstring_noalloc(FILE *f)
{
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');
}
buf[strlen(buf) - 1] = '\0';
return buf;
}
#define getstring(x) dup_string(getstring_noalloc(x))
#ifdef COMPRESS
#define alloc_compressed(x) dup_string(compress(x))
#define getstring_compress(x) dup_string(compress(getstring_noalloc(x)))
#else
#define alloc_compressed(x) dup_string(x)
#define getstring_compress(x) getstring(x)
#endif /* COMPRESS */
static boolexp *negate_boolexp(boolexp *b)
{
boolexp *n;
/* Obscure fact: !NOTHING == NOTHING in old-format databases! */
if(b == TRUE_BOOLEXP) return TRUE_BOOLEXP;
n = (boolexp *) malloc(sizeof(boolexp));
n->type = BOOLEXP_NOT;
n->sub1 = b;
return n;
}
/* returns true for numbers of form [ + | - ] <series of digits> */
int number(char *s)
{
if (!s) return 0;
while (isspace(*s)) s++;
if (*s == '+' || *s == '-') s++;
if (*s < '0' || *s > '9') return 0;
return 1;
}
static boolexp *getboolexp1(FILE *f)
{
boolexp *b;
int c;
int i;
c = getc(f);
switch(c)
{
case '\n':
ungetc(c, f);
return TRUE_BOOLEXP;
case EOF:
abort();
break;
case '(':
b = (boolexp *) malloc(sizeof(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;
}
b->sub2 = getboolexp1(f);
if(getc(f) != ')') goto error;
return b;
}
case '[':
/* property type */
b = (boolexp *)malloc(sizeof(boolexp));
b->type = BOOLEXP_PROP;
b->sub1 = b->sub2 = 0;
for(i = 0; ((c = getc(f)) != PROP_DELIMITER) && (i < BUFSIZ); i++)
buf[i] = c;
if (i >= BUFSIZ && (c != PROP_DELIMITER)) goto error;
buf[i] = '\0';
b->prop_name = dup_string(buf);
for (i = 0; (c = getc(f)) != ']'; i++) buf[i] = c;
buf[i] = '\0';
if (i >= BUFSIZ && c != ']') goto error;
b->prop_data = dup_string(buf);
return b;
case '-':
/* uncomment if old format db
while((c = getc(f)) != '\n') if(c == EOF) abort();
ungetc(c, f);
return TRUE_BOOLEXP; */
default:
/* better be a dbref */
ungetc(c, f);
b = (boolexp *)malloc(sizeof(boolexp));
b->type = BOOLEXP_CONST;
b->thing = 0;
i = (c == '-') ? -1 : 1;
if (c == '-') c = getc(f);
/* 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';
}
b->thing *= i;
ungetc(c, f);
return b;
}
error:
abort(); /* bomb out */
return TRUE_BOOLEXP;
}
boolexp *getboolexp(FILE *f)
{
boolexp *b;
b = getboolexp1(f);
if(getc(f) != '\n') abort(); /* parse error, we lose */
return b;
}
void free_boolexp(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(b->prop_name);
free(b->prop_data);
free(b);
break;
}
}
}
void db_free_object(dbref i)
{
object *o;
int j;
inst *code;
o = DBFETCH(i);
if(NAME(i)) free(NAME(i));
#ifndef USE_DBP_STR
if(o->desc) free(o->desc);
if(o->succ) free(o->succ);
if(o->fail) free(o->fail);
if(o->drop) free(o->drop);
if(o->ofail) free(o->ofail);
if(o->osucc) free(o->osucc);
if(o->odrop) free(o->odrop);
#endif
if(o->key) free_boolexp(o->key);
dbreflist_burn(o->backlinks);
dbreflist_burn(o->backlocks);
#ifndef USE_DBP
burn_proptree(o->properties);
#else
DBFETCHPROP(i);
burn_proptree(o->properties);
o->properties = NULL;
#endif
switch (Typeof(i))
{
case TYPE_EXIT:
if (o->sp.exit.dest) free (o->sp.exit.dest);
break;
case TYPE_PLAYER:
if (o->sp.player.password) free (o->sp.player.password);
break;
case TYPE_DAEMON:
break;
case TYPE_PROGRAM:
dbreflist_burn(DBFETCH(i)->sp.program.editlocks);
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()
{
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();
compost_heap = NOTHING;
}
line *get_new_line()
{
line *new;
new = (line *)malloc(sizeof(line));
new->this_line = NULL;
new->next = NULL;
new->prev = NULL;
return new;
}
line *read_program(dbref i)
{
line *first, *prev, *new;
FILE *f;
first = NULL;
sprintf(buf, "muf/%ld.m", i);
f = fopen(buf, "r");
if (!f) return 0;
while (fgets(buf, BUFSIZ, f))
{
new = get_new_line();
buf[strlen(buf) - 1] = '\0';
new->this_line = dup_string(buf);
if (!first)
first = prev = new;
else
{
prev->next = new;
new->prev = prev;
prev = new;
}
}
fclose(f);
return first;
}
void db_read_object_old(FILE *f, object *o, dbref objno)
{
dbref exits;
int pennies;
char *password, *gender;
NAME(objno) = getstring(f);
#ifndef USE_DBP_STR
o->desc = getstring_compress(f);
#endif
o->location = getref(f);
o->contents = getref(f);
exits = getref(f);
o->backlinks = NULL;
o->backlocks = NULL;
o->next = getref(f);
o->nextowned = NOTHING;
o->key = getboolexp(f);
#ifndef USE_DBP_STR
o->fail = getstring_compress(f);
o->succ = getstring_compress(f);
o->ofail = getstring_compress(f);
o->osucc = getstring_compress(f);
#endif
o->properties = NULL;
OWNER(objno) = getref(f);
pennies = getref(f);
FLAGS(objno) = 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 (FLAGS(objno) & CHOWN_OK)
{
FLAGS(objno) &= ~CHOWN_OK;
FLAGS(objno) |= HAVEN;
}
if (FLAGS(objno) & JUMP_OK)
{
FLAGS(objno) &= ~JUMP_OK;
FLAGS(objno) |= ABODE;
}
password = getstring(f);
/* convert GENDER flag to property */
if (FLAGS(objno) & TYPE_PLAYER)
{
switch((FLAGS(objno) & GENDER_MASK) >> GENDER_SHIFT)
{
case GENDER_NEUTER:
gender = "neuter";
break;
case GENDER_FEMALE:
gender = "female";
break;
case GENDER_MALE:
gender = "male";
break;
default:
gender = "unassigned";
break;
}
add_property(objno, "sex", gender, PERMS_COREAD | PERMS_COWRITE |
PERMS_OTREAD, ACCESS_CO);
}
/* Blast the gender flags (Doran) */
FLAGS(objno) &= (~GENDER_MASK);
/* For downward compatibility with databases using the */
/* obsolete ANTILOCK flag. */
if(FLAGS(objno) & ANTILOCK)
{
o->key = negate_boolexp(o->key);
FLAGS(objno) &= ~ANTILOCK;
}
switch (FLAGS(objno) & TYPE_MASK)
{
case TYPE_THING:
o->link = exits;
o->pennies = pennies;
break;
case TYPE_ROOM:
o->link = o->location;
o->location = NOTHING;
o->exits = exits;
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;
break;
case TYPE_PLAYER:
o->link = exits;
o->exits = NOTHING;
o->pennies = pennies;
o->sp.player.password = make_password(password);
OWNER(objno) = objno;
add_player(objno);
break;
case TYPE_PROGRAM:
o->sp.program.editlocks = NULL;
o->link = o->owner;
break;
case TYPE_GARBAGE:
OWNER(objno) = NOTHING;
add_compost(objno);
free(NAME(objno));
#ifndef USE_DBP_STR
free(o->desc);
#endif
NAME(objno) = COMPOST_NAME;
#ifndef USE_DBP_STR
o->desc = COMPOST_DESC;
#endif
FLAGS(objno) = TYPE_GARBAGE;
break;
}
}
void db_read_object_new(FILE *f, object *o, dbref objno)
{
int j;
char *gender;
NAME(objno) = getstring(f);
#ifndef USE_DBP_STR
o->desc = getstring_compress(f);
#endif
o->location = getref(f);
o->contents = getref(f);
o->backlinks = NULL;
o->backlocks = NULL;
o->next = getref(f);
o->nextowned = NOTHING;
o->key = getboolexp(f);
#ifndef USE_DBP_STR
o->fail = getstring_compress(f);
o->succ = getstring_compress(f);
o->ofail = getstring_compress(f);
o->osucc = getstring_compress(f);
#endif
o->properties = NULL;
FLAGS(objno) = 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 (FLAGS(objno) & CHOWN_OK)
{
FLAGS(objno) &= ~CHOWN_OK;
FLAGS(objno) |= HAVEN;
}
if (FLAGS(objno) & JUMP_OK)
{
FLAGS(objno) &= ~JUMP_OK;
FLAGS(objno) |= ABODE;
}
/* convert GENDER flag to property */
if (FLAGS(objno) & TYPE_PLAYER)
{
switch((FLAGS(objno) & GENDER_MASK) >> GENDER_SHIFT)
{
case GENDER_NEUTER:
gender = "neuter";
break;
case GENDER_FEMALE:
gender = "female";
break;
case GENDER_MALE:
gender = "male";
break;
default:
gender = "unassigned";
break;
}
add_property(objno, "sex", gender, PERMS_COREAD | PERMS_COWRITE |
PERMS_OTREAD, ACCESS_CO);
}
/* Blast the gender flags (Doran) */
FLAGS(objno) &= (~GENDER_MASK);
/* o->password = getstring(f); */
/* For downward compatibility with databases using the */
/* obsolete ANTILOCK flag. */
if(FLAGS(objno) & ANTILOCK)
{
o->key = negate_boolexp(o->key);
FLAGS(objno) &= ~ANTILOCK;
}
switch (FLAGS(objno) & TYPE_MASK)
{
case TYPE_THING:
o->link = getref(f);
o->exits = getref(f);
OWNER(objno) = getref(f);
o->pennies = getref(f);
break;
case TYPE_ROOM:
o->link = getref(f);
o->exits = getref(f);
OWNER(objno) = 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);
}
OWNER(objno) = getref(f);
break;
case TYPE_PLAYER:
o->link = getref(f);
o->exits = getref(f);
o->pennies = getref(f);
o->sp.player.password = getstring(f);
o->sp.player.password = make_password(o->sp.player.password);
OWNER(objno) = objno;
add_player(objno);
break;
}
}
void db_read_object_lachesis(FILE *f, object *o, dbref objno)
{
int c, j, prop_flag = 0;
char *gender;
NAME(objno) = getstring(f);
#ifndef USE_DBP_STR
o->desc = getstring_compress(f);
#endif
o->location = getref(f);
o->contents = getref(f);
o->backlinks = NULL;
o->backlocks = NULL;
o->next = getref(f);
o->nextowned = NOTHING;
o->key = getboolexp(f);
#ifndef USE_DBP_STR
o->fail = getstring_compress(f);
o->succ = getstring_compress(f);
o->drop = getstring_compress(f);
o->ofail = getstring_compress(f);
o->osucc = getstring_compress(f);
o->odrop = getstring_compress(f);
#endif
FLAGS(objno) = getref(f);
c = getc(f);
if (c == '*')
{
getproperties(f, objno, 0);
prop_flag++;
}
else
{
/* do our own getref */
int sign = 0;
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:
gender = "neuter";
break;
case GENDER_FEMALE:
gender = "female";
break;
case GENDER_MALE:
gender = "male";
break;
default:
gender = "unassigned";
break;
}
add_property(objno, "sex", gender, PERMS_COREAD | PERMS_COWRITE |
PERMS_OTREAD, ACCESS_CO);
}
/* o->password = getstring(f); */
/* For downward compatibility with databases using the */
/* obsolete ANTILOCK flag. */
if(FLAGS(objno) & ANTILOCK)
{
o->key = negate_boolexp(o->key);
FLAGS(objno) &= ~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->pennies = 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->pennies = getref(f);
o->sp.player.password = getstring(f);
o->curr_prog = NOTHING;
o->sp.player.insert_mode = 0;
o->sp.player.password = make_password(o->sp.player.password);
OWNER(objno) = objno;
add_player(objno);
break;
case TYPE_PROGRAM:
OWNER(objno) = getref(f);
FLAGS(objno) &= ~INTERNAL;
o->link = o->owner;
o->sp.program.curr_line = 0;
o->sp.program.code = 0;
o->sp.program.siz = 0;
o->sp.program.start = 0;
o->sp.program.editlocks = NULL;
#ifdef COMPILE_ON_LOAD
o->sp.program.first = read_program(objno);
do_compile(NOTHING, objno);
free_prog_text(o->sp.program.first);
#endif /* COMPILE_ON_LOAD */
o->sp.program.first = 0;
break;
case TYPE_GARBAGE:
add_compost(objno);
free(NAME(objno));
#ifndef USE_DBP_STR
free(o->desc);
#endif
NAME(objno) = COMPOST_NAME;
#ifndef USE_DBP_STR
o->desc = COMPOST_DESC;
#endif
break;
}
}
void db_read_object_doran(FILE *f, object *o, dbref objno)
{
int j, c, prop_flag = 0;
char *gender;
NAME(objno) = getstring(f);
#ifndef USE_DBP_STR
o->desc = getstring_compress(f);
#endif
o->location = getref(f);
o->contents = getref(f);
o->backlinks = NULL;
o->backlocks = NULL;
o->next = getref(f);
o->nextowned = NOTHING;
o->key = getboolexp(f);
#ifndef USE_DBP_STR
o->fail = getstring_compress(f);
o->succ = getstring_compress(f);
o->drop = getstring_compress(f);
o->ofail = getstring_compress(f);
o->osucc = getstring_compress(f);
o->odrop = getstring_compress(f);
#endif
FLAGS(objno) = getref(f);
o->time_created = getref(f);
o->time_modified = getref(f);
o->time_used = getref(f);
c = getc(f);
if (c == '*')
{
getproperties(f, objno, 0);
prop_flag++;
}
else
{
/* do our own getref */
int sign = 0;
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:
gender = "neuter";
break;
case GENDER_FEMALE:
gender = "female";
break;
case GENDER_MALE:
gender = "male";
break;
default:
gender = "unassigned";
break;
}
add_property(objno, "sex", gender, PERMS_COREAD | PERMS_COWRITE |
PERMS_OTREAD, ACCESS_CO);
}
/* Blast the gender flags (Doran) */
FLAGS(objno) &= (~GENDER_MASK);
/* o->password = getstring(f); */
/* For downward compatibility with databases using the */
/* obsolete ANTILOCK flag. */
if(FLAGS(objno) & ANTILOCK)
{
o->key = negate_boolexp(o->key);
FLAGS(objno) &= ~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->pennies = 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->pennies = getref(f);
o->sp.player.password = getstring(f);
o->curr_prog = NOTHING;
o->sp.player.insert_mode = 0;
OWNER(objno) = objno;
add_player(objno);
break;
case TYPE_DAEMON:
if (prop_flag) getref(f); /* just throw away the data */
getref(f);
getref(f);
free(getstring(f));
recycle((dbref) 1, objno);
break;
case TYPE_PROGRAM:
OWNER(objno) = getref(f);
FLAGS(objno) &= ~INTERNAL;
o->sp.program.curr_line = 0;
o->sp.program.code = 0;
o->sp.program.siz = 0;
o->sp.program.start = 0;
o->link = o->owner;
o->sp.program.editlocks = NULL;
#ifdef COMPILE_ON_LOAD
o->sp.program.first = read_program(objno);
do_compile(NOTHING, objno);
free_prog_text(o->sp.program.first);
#endif /* COMPILE_ON_LOAD */
o->sp.program.first = 0;
break;
case TYPE_GARBAGE:
add_compost(objno);
free(NAME(objno));
NAME(objno) = COMPOST_NAME;
#ifndef USE_DBP_STR
free(o->desc);
o->desc = COMPOST_DESC;
#endif
break;
}
}
void burn_dbref_list(dbref_list *drl)
{
dbref_list *drl_tmp;
for (;drl; drl = drl_tmp)
{
drl_tmp = drl->next;
free(drl);
}
}
void db_read_object_daemon(FILE *f, object *o, dbref objno,
int permsflag)
{
int j, c, prop_flag = 0;
NAME(objno) = getstring(f);
#ifndef USE_DBP_STR
o->desc = getstring_compress(f);
#endif
o->location = getref(f);
o->contents = getref(f);
o->backlinks = NULL;
o->backlocks = NULL;
o->next = getref(f);
o->nextowned = getref(f);
#ifdef RESET_LISTS
o->nextowned = NOTHING;
#endif
o->owner = getref(f);
o->key = getboolexp(f);
#ifndef USE_DBP_STR
o->fail = getstring_compress(f);
o->succ = getstring_compress(f);
o->drop = getstring_compress(f);
o->ofail = getstring_compress(f);
o->osucc = getstring_compress(f);
o->odrop = getstring_compress(f);
#endif
FLAGS(objno) = getref(f);
o->time_created = getref(f);
o->time_modified = getref(f);
o->time_used = getref(f);
fgets(garbagebuf, BUFFER_LEN, f);/* getstring_compress(f); Someone kill me */
o->backlinks = dbreflist_read(f);
fgets(garbagebuf, BUFFER_LEN, f);/* getstring_compress(f); Someone kill me */
o->backlocks = dbreflist_read(f);
c = getc(f);
if (c == '*')
{
getproperties(f, objno, permsflag);
prop_flag++;
}
else
{
/* do our own getref */
int sign = 0;
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);
o->pennies = getref(f);
break;
case TYPE_ROOM:
o->link = prop_flag ? getref(f) : j;
o->exits = 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);
break;
case TYPE_PLAYER:
o->link = prop_flag ? getref(f) : j;
o->exits = getref(f);
o->pennies = getref(f);
o->sp.player.password = getstring(f);
o->curr_prog = NOTHING;
o->sp.player.insert_mode = 0;
add_player(objno);
break;
case TYPE_DAEMON:
recycle((dbref) 1, objno);
break;
case TYPE_PROGRAM:
FLAGS(objno) &= ~INTERNAL;
o->link = o->owner;
o->sp.program.curr_line = 0;
o->sp.program.code = 0;
o->sp.program.siz = 0;
o->sp.program.start = 0;
o->sp.program.editlocks = NULL;
#ifdef COMPILE_ON_LOAD
o->sp.program.first = read_program(objno);
do_compile(NOTHING, objno);
free_prog_text(o->sp.program.first);
#endif /* COMPILE_ON_LOAD */
o->sp.program.first = 0;
break;
case TYPE_GARBAGE:
add_compost(objno);
free(NAME(objno));
NAME(objno) = COMPOST_NAME;
#ifndef USE_DBP_STR
free(o->desc);
o->desc = COMPOST_DESC;
#endif
break;
}
}
void db_read_object_mulch(FILE *f, object *o, dbref objno)
{
int c;
int j;
o->backlinks = NULL;
o->backlocks = NULL;
o->curr_prog = NOTHING;
NAME(objno) = getstring(f);
#ifndef USE_DBP_STR
o->desc = getstring_compress(f);
#else
getstring_noalloc(f);
#endif /* DBP_STR */
o->location = getref(f);
o->contents = getref(f);
o->link = getref(f);
o->exits = getref(f);
o->pennies = getref(f);
o->next = getref(f);
o->nextowned = getref(f);
#ifdef RESET_LISTS
o->nextowned = NOTHING;
#endif
o->owner = getref(f);
o->key = getboolexp(f);
#ifndef USE_DBP_STR
o->fail = getstring_compress(f);
o->succ = getstring_compress(f);
o->drop = getstring_compress(f);
o->ofail = getstring_compress(f);
o->osucc = getstring_compress(f);
o->odrop = getstring_compress(f);
#else
getstring_noalloc(f);
getstring_noalloc(f);
getstring_noalloc(f);
getstring_noalloc(f);
getstring_noalloc(f);
getstring_noalloc(f);
#endif /* USE_DBP_STR */
FLAGS(objno) = getref(f);
if (Typeof(objno) == TYPE_EXIT) o->link = NOTHING;
o->time_created = getref(f);
o->time_modified = getref(f);
o->time_used = getref(f);
fgets(garbagebuf, BUFFER_LEN, f);/* getstring_compress(f); Someone kill me */
o->backlinks = dbreflist_read(f);
fgets(garbagebuf, BUFFER_LEN, f);/* getstring_compress(f); Someone kill me */
o->backlocks = dbreflist_read(f);
c = getc(f);
if (c == '*')
{
getproperties(f, objno, 1);
}
else
{
/* do our own getref */
int sign = 0;
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_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);
break;
case TYPE_PLAYER:
o->sp.player.password = getstring(f);
o->sp.player.insert_mode = 0;
add_player(objno);
break;
case TYPE_PROGRAM:
FLAGS(objno) &= ~INTERNAL;
o->sp.program.curr_line = 0;
o->sp.program.code = 0;
o->sp.program.siz = 0;
o->sp.program.start = 0;
o->sp.program.editlocks = NULL;
#ifdef COMPILE_ON_LOAD
o->sp.program.first = read_program(objno);
do_compile(NOTHING, objno);
free_prog_text(o->sp.program.first);
#endif /* COMPILE_ON_LOAD */
o->sp.program.first = 0;
break;
case TYPE_GARBAGE:
add_compost(objno);
free(NAME(objno));
NAME(objno) = COMPOST_NAME;
#ifndef USE_DBP_STR
free(o->desc);
o->desc = COMPOST_DESC;
#endif
}
}
void db_chown(dbref thing, dbref newowner)
{
DBSTORE(thing, time_modified, time(NULL));
remove_ownerlist(thing);
DBSTORE(thing, owner, newowner);
add_ownerlist(thing);
}
void add_ownerlist(dbref d)
{
dbref owner;
owner = DBFETCH(d)->owner;
if (owner == d) return;
if (Typeof(owner) == TYPE_PLAYER)
{
DBSTORE(d, nextowned, DBFETCH(owner)->nextowned);
DBSTORE(owner, nextowned, d);
}
else fputs ("Error, illegal owner value.\n", stderr);
}
void remove_ownerlist(dbref d)
{
dbref step;
for (step = DBFETCH(d)->owner;
(DBFETCH(step)->nextowned != NOTHING) &&
(DBFETCH(step)->nextowned != d);
step = DBFETCH(step)->nextowned);
if (DBFETCH(step)->nextowned == d)
{
DBSTORE(step, nextowned, DBFETCH(DBFETCH(step)->nextowned)->nextowned);
}
DBSTORE(d, nextowned, NULL);
}
void add_backlocks_parse(dbref src, boolexp *b)
{
if (b)
{
switch (b->type)
{
case BOOLEXP_AND:
case BOOLEXP_OR:
add_backlocks_parse(src, b->sub1);
add_backlocks_parse(src, b->sub2);
break;
case BOOLEXP_NOT:
add_backlocks_parse(src, b->sub1);
break;
case BOOLEXP_CONST:
if (b->thing != NOTHING) {
if (b->thing == HOME) {
fprintf(stderr, "Object locked to HOME. %d\n", src);
exit(999);
}
DBSTORE(b->thing, backlocks,
dbreflist_add(DBFETCH(b->thing)->backlocks, src));
}
}
}
}
void remove_backlocks_parse(dbref src, boolexp *b)
{
if (b)
{
switch (b->type)
{
case BOOLEXP_AND:
case BOOLEXP_OR:
remove_backlocks_parse(src, b->sub1);
remove_backlocks_parse(src, b->sub2);
break;
case BOOLEXP_NOT:
remove_backlocks_parse(src, b->sub1);
break;
case BOOLEXP_CONST:
if (b->thing != NOTHING) DBSTORE(b->thing, backlocks,
dbreflist_remove(DBFETCH(b->thing)->backlocks, src));
}
}
}
void establish_lists()
{
dbref d;
for (d = 0; d < db_top; d++)
{
if (Typeof(d) != TYPE_GARBAGE)
{
add_backlocks_parse(d, DBFETCH(d)->key);
add_backlinks(d);
add_ownerlist(d);
}
}
}
void reset_lists()
{
dbref d;
fputs ("Resetting lists...\n", stderr);
for (d = 0; d < db_top; d++)
{
dbreflist_burn(DBFETCH(d)->backlinks);
dbreflist_burn(DBFETCH(d)->backlocks);
DBSTORE(d, backlinks, NULL);
DBSTORE(d, backlocks, NULL);
DBSTORE(d, nextowned, NOTHING);
}
establish_lists();
}
/* returns object a is linked to b... */
int validate_lists_backlinks(dbref a, dbref b)
{
int c, flag;
switch(Typeof(a))
{
case TYPE_PLAYER:
case TYPE_PROGRAM:
case TYPE_THING:
return ((DBFETCH(a)->link == HOME) ?
(DBFETCH(OWNER(a))->link == b) :
(DBFETCH(a)->link == b));
case TYPE_ROOM:
return ((DBFETCH(a)->link == HOME) ? 0 : (DBFETCH(a)->link == b));
case TYPE_EXIT:
for (c = 0, flag = 0; c < DBFETCH(a)->sp.exit.ndest; c++)
{
flag |= ((DBFETCH(a)->sp.exit.dest[c] == HOME) ?
0 :
(DBFETCH(a)->sp.exit.dest[c] == b));
}
return (flag);
}
return 0;
}
int validate_lists_backlocks (boolexp *a, dbref b)
{
if (a)
{
switch(a->type)
{
case BOOLEXP_AND:
case BOOLEXP_OR:
return (validate_lists_backlocks(a->sub1, b) ||
validate_lists_backlocks(a->sub2, b));
case BOOLEXP_NOT:
return (validate_lists_backlocks(a->sub1, b));
case BOOLEXP_CONST:
return (a->thing == b);
default:
return 0;
}
}
return 0;
}
int validate_lists_blback(dbref a, boolexp *bxp)
{
int flag;
dbref_list *drl;
if (bxp)
{
switch(bxp->type)
{
case BOOLEXP_AND:
case BOOLEXP_OR:
return (validate_lists_blback(a, bxp->sub1) &&
validate_lists_blback(a, bxp->sub2));
case BOOLEXP_NOT:
return (validate_lists_blback(a, bxp->sub1));
case BOOLEXP_CONST:
flag = 0;
if (bxp->thing == NOTHING || bxp->thing == HOME) return 1;
for (drl = DBFETCH(bxp->thing)->backlocks; drl; drl = drl->next)
{
if (drl->object == a) flag++;
}
if (flag == 0) return 0;
return 1;
}
}
return 1;
}
int validate_lists()
{
dbref d, d2;
dbref_list *drl;
int counter, counter2, flag = 1, i;
fputs ("Validating lists.\n", stderr);
for (d = 0; d < db_top; d++)
{
if (!(d % 1000)) fprintf (stderr, "%ld...\n", d);
if ((Typeof(d) != TYPE_GARBAGE) && (Typeof(OWNER(d)) != TYPE_PLAYER))
{
flag = 0;
if (Typeof(d) == TYPE_PLAYER)
{
DBSTORE(d, owner, d);
fprintf (stderr, "Player %ld doesn't own themself.\n", d);
}
else
{
DBSTORE(d, owner, GOD_DBREF);
fprintf (stderr, "Object %ld not owned by a player.\n", d);
}
}
/* check backlinks list */
for (drl = DBFETCH(d)->backlinks, counter = 0;
(drl) && (counter < COUNTER_MAX);
drl = drl->next, counter++)
{
if (!validate_lists_backlinks(drl->object, d))
{
flag = 0;
fprintf
(stderr, "Illegal backlink connection %ld->%ld\n", drl->object, d);
}
}
if (counter == COUNTER_MAX)
{
flag = 0;
fprintf (stderr, "Possible backlinks loop for object %ld.\n", d);
}
/* check backlocks */
for (drl = DBFETCH(d)->backlocks, counter = 0;
(drl) && (counter < COUNTER_MAX);
drl = drl->next, counter++)
{
if (!validate_lists_backlocks(DBFETCH(drl->object)->key, d))
{
fprintf (stderr, "Illegal backlock %ld is not locked to %ld.\n",
drl->object, d);
}
}
if (counter == COUNTER_MAX)
{
flag = 0;
fprintf (stderr, "Possible backlocks loop on %ld.\n", d);
}
}
for (d = 0; d < db_top; d++)
{
if (Typeof(d) != TYPE_GARBAGE)
{
for (d2 = OWNER(d), counter = counter2 = 0;
(d2 != NOTHING) && (counter < COUNTER_MAX);
d2 = DBFETCH(d2)->nextowned, counter++)
{
if (d2 == d) counter2++;
}
if (counter2 != 1)
{
flag = 0;
fprintf (stderr, "Object %ld in %ld ownerlist %ld times.\n", d,
OWNER(d), counter2);
}
}
counter = 0;
switch(Typeof(d))
{
case TYPE_PLAYER:
/* Check owner lists... */
for (d2 = d, counter = 0;
(d2 != NOTHING) && (counter < COUNTER_MAX);
d2 = DBFETCH(d2)->nextowned, counter++)
{
if (OWNER(d2) != d)
{
flag = 0;
fprintf (stderr, "%ld is not owned by %ld.\n", d2, OWNER(d));
}
}
if (counter == COUNTER_MAX)
{
flag = 0;
fprintf (stderr, "Possible owner list loop for %ld.\n", OWNER(d));
}
case TYPE_THING:
case TYPE_PROGRAM:
if (DBFETCH(d)->link != NOTHING)
{
d2 = (DBFETCH(d)->link == HOME) ? DBFETCH(OWNER(d))->link :
DBFETCH(d)->link;
for (drl = DBFETCH(d2)->backlinks, counter = 0; drl; drl = drl->next)
{
if (drl->object == d) counter++;
}
if (counter != 1)
{
flag = 0;
fprintf(stderr, "Object %ld in %ld backlink list %ld times.\n", d,
d2, counter);
}
}
else
{
fprintf (stderr, "Object %ld linked to nothing.\n", d);
if (Typeof(d) == TYPE_PLAYER)
{
DBSTORE(d, link, DBFETCH(d)->location);
}
else
{
DBSTORE(d, link, OWNER(d));
}
flag = 0;
}
break;
case TYPE_ROOM:
d2 = DBFETCH(d)->link;
if ((d2 != NOTHING) && (d2 != HOME))
{
for (drl = DBFETCH(d2)->backlinks; drl; drl = drl->next)
{
if (drl->object == d) counter++;
}
if (counter != 1)
{
flag = 0;
fprintf(stderr, "Object %ld in %ld backlink list %ld times.\n", d,
d2, counter);
}
}
break;
case TYPE_EXIT:
for (i = 0; i < DBFETCH(d)->sp.exit.ndest; i++)
{
d2 = DBFETCH(d)->sp.exit.dest[i];
if (d2 != HOME)
{
counter = 0;
for (drl = DBFETCH(d2)->backlinks; drl; drl = drl->next)
{
if (drl->object == d) counter++;
}
if (counter == 0)
{
flag = 0;
fprintf(stderr, "Object %ld not in %ld backlink list.\n", d, d2);
}
}
}
}
if (!validate_lists_blback(d, DBFETCH(d)->key))
{
fprintf (stderr, "Object %ld not in correct backlock list.\n", d);
flag = 0;
}
}
return flag;
}
dbref db_read(FILE *f)
{
dbref i;
object *o;
char *special;
int newformat;
char c;
if ( (c = getc(f)) == '*')
{
special = getstring(f);
if(!strcmp(special, "**TinyMUCK DUMP Format***"))
{
newformat = 1;
fputs ("Database in TinyMUCK format.\n", stderr);
}
else if (!strcmp(special, "**Lachesis TinyMUCK DUMP Format***"))
{
newformat = 2;
fputs ("Database in Lachesis format.\n", stderr);
}
else if (!strcmp(special, "**Doran TinyMUCK DUMP Format***"))
{
newformat = 3;
fputs ("Database in Doran format.\n", stderr);
}
else if (!strcmp(special, "**DaemonMUCK DUMP Format***"))
{
newformat = 4;
fputs ("Database in DaemonMUCK format.\n", stderr);
}
else if (!strcmp(special, "**DaemonMUCK P DUMP Format***"))
{
newformat = 5;
fputs ("Database in DaemonMUCK P format.\n", stderr);
}
else if (!strcmp(special, "**MULCH***"))
{
newformat = 6;
fputs ("Database in MULCH format.\n", stderr);
}
free((void *)special);
c = getc(f); /* get next char */
}
db_free();
fputs("Initializing primitives.\n", stderr);
init_primitives();
fputs("Reading database.\n", stderr);
for(i = 0;; i++)
{
if (!(i % 1000)) fprintf(stderr, "%ld...\n", i);
switch(c)
{
case '#':
/* another entry, yawn */
if(i != getref(f)) return -1; /* we blew it */
db_grow(i+1); /* make space */
db_clear_object(i);
o = DBFETCH(i); /* read it in */
#ifdef USE_DBP
o->dbp_size = -1L;
o->lru_next = NOTHING;
#endif
switch (newformat)
{
case 0:
db_read_object_old(f, o, i);
break;
case 1:
db_read_object_new(f, o, i);
break;
case 2:
db_read_object_lachesis(f, o, i);
break;
case 3:
db_read_object_doran(f, o, i);
break;
case 4:
db_read_object_daemon(f, o, i, 0); /* db sans perms */
break;
case 5:
db_read_object_daemon(f, o, i, 1); /* db with perms */
break;
case 6:
db_read_object_mulch(f, o, i);
}
break;
case '*':
special = getstring(f);
if(strcmp(special, "**END OF DUMP***"))
{
free((void *) special);
fputs("Done.\n", stderr);
return NOTHING;
}
else
{
free((void *) special);
if (newformat < 4) establish_lists();
#ifdef RESET_LISTS
reset_lists();
#endif
#ifdef VALIDATE_LISTS
if (!validate_lists()) reset_lists();
#endif
return db_top;
}
default:
return -1;
}
c = getc(f);
} /* for */
} /* db_read */
void add_backlinks(dbref obj)
{
int i;
dbref tmp;
if (obj == NOTHING) return;
switch(Typeof(obj))
{
case TYPE_EXIT:
for(i = 0; i < DBFETCH(obj)->sp.exit.ndest; i++)
{
tmp = DBFETCH(obj)->sp.exit.dest[i];
if (tmp != HOME)
{
DBSTORE(tmp, backlinks, dbreflist_add(DBFETCH(tmp)->backlinks, obj));
}
}
return;
case TYPE_ROOM:
tmp = DBFETCH(obj)->link;
if ((tmp != HOME) && (tmp != NOTHING))
{
DBSTORE(tmp, backlinks, dbreflist_add(DBFETCH(tmp)->backlinks, obj));
}
return;
default:
tmp = DBFETCH(obj)->link;
if (tmp == HOME) tmp = DBFETCH(OWNER(obj))->link;
if (tmp == NOTHING) return;
DBSTORE(tmp, backlinks, dbreflist_add(DBFETCH(tmp)->backlinks, obj));
}
}
void remove_backlinks(dbref obj)
{
int i;
dbref tmp;
if (obj == NOTHING) return;
switch(Typeof(obj))
{
case TYPE_EXIT:
for(i = 0; i < DBFETCH(obj)->sp.exit.ndest; i++)
{
tmp = DBFETCH(obj)->sp.exit.dest[i];
if (tmp != HOME)
{
DBSTORE(tmp, backlinks,
dbreflist_remove(DBFETCH(tmp)->backlinks, obj));
}
}
return;
case TYPE_ROOM:
tmp = DBFETCH(obj)->link;
if ((tmp != HOME) && (tmp != NOTHING))
{
DBSTORE(tmp, backlinks, dbreflist_remove(DBFETCH(tmp)->backlinks, obj));
}
return;
default:
tmp = DBFETCH(obj)->link;
if (tmp == HOME) tmp = DBFETCH(OWNER(obj))->link;
if (tmp == NOTHING) return;
DBSTORE(tmp, backlinks, dbreflist_remove(DBFETCH(tmp)->backlinks, obj));
}
}