/* db_rw.c -- I/O to/from flat file databases */
#include "copyright.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#ifdef WANT_ANSI
#ifdef __STDC__
#include <stdlib.h>
#endif /* __STDC__ */
#endif /* WANT_ANSI */
#include <sys/file.h>
#include <sys/types.h>
#include "mudconf.h"
#include "config.h"
#include "externs.h"
#include "db.h"
extern const char *getstring_noalloc(FILE * f);
extern void putstring(FILE * f, const char *s);
extern void db_grow(dbref newtop);
extern struct object *db;
static int g_version;
static int g_format;
static int g_flags;
/* ---------------------------------------------------------------------------
* getboolexp1: Get boolean subexpression from file.
*/
static struct boolexp *getboolexp1(FILE *f)
{
struct boolexp *b;
char *buff, *s;
int c, d, anum;
c = getc(f);
switch (c) {
case '\n':
ungetc(c, f);
return TRUE_BOOLEXP;
/* break; */
case EOF:
abort(); /* unexpected EOF in boolexp */
break;
case '(':
b = alloc_bool("getboolexp1.openparen");
switch (c = getc(f)) {
case NOT_TOKEN:
b->type = BOOLEXP_NOT;
b->sub1 = getboolexp1(f);
if ((d = getc(f)) == '\n') d = getc(f);
if (d != ')') goto error;
return b;
case INDIR_TOKEN:
b->type = BOOLEXP_INDIR;
b->sub1 = getboolexp1(f);
if ((d = getc(f)) == '\n') d = getc(f);
if (d != ')') goto error;
return b;
case IS_TOKEN:
b->type = BOOLEXP_IS;
b->sub1 = getboolexp1(f);
if ((d = getc(f)) == '\n') d = getc(f);
if (d != ')') goto error;
return b;
case CARRY_TOKEN:
b->type = BOOLEXP_CARRY;
b->sub1 = getboolexp1(f);
if ((d = getc(f)) == '\n') d = getc(f);
if (d != ')') goto error;
return b;
case OWNER_TOKEN:
b->type = BOOLEXP_OWNER;
b->sub1 = getboolexp1(f);
if ((d = getc(f)) == '\n') d = getc(f);
if (d != ')') goto error;
return b;
default:
ungetc(c, f);
b->sub1 = getboolexp1(f);
if ((c = getc(f)) == '\n') c = getc(f);
switch (c) {
case AND_TOKEN:
b->type = BOOLEXP_AND;
break;
case OR_TOKEN:
b->type = BOOLEXP_OR;
break;
default:
goto error;
}
b->sub2 = getboolexp1(f);
if ((d = getc(f)) == '\n') d = getc(f);
if (d != ')') goto error;
return b;
}
case '-': /* obsolete NOTHING key, eat it */
while ((c = getc(f)) != '\n')
if (c == EOF)
abort(); /* unexp EOF */
ungetc(c, f);
return TRUE_BOOLEXP;
default: /* dbref or attribute */
ungetc(c, f);
b = alloc_bool("getboolexp1.default");
b->type = BOOLEXP_CONST;
b->thing = 0;
/* This is either an attribute or a constant lock. Constant
* locks are of the form <num>, while attribute locks are of
* the form <aname>:<string> or <anum>:<string>.
* The characters <nl>, |, and & terminate the string.
*/
if (isdigit(c)) {
while (isdigit(c = getc(f))) {
b->thing = b->thing * 10 + c - '0';
}
} else if (isalpha(c)) {
buff = alloc_lbuf("getboolexp1.atr_name");
for (s=buff;
((c=getc(f))!=EOF) && (c!='\n') && (c!=':');
*s++=c);
if (c == EOF) {
free_lbuf(buff);
free_bool(b);
goto error;
}
*s = '\0';
/* Look the name up as an attribute. If not found,
* create a new attribute.
*/
anum = mkattr(buff);
if (anum <= 0) {
free_bool(b);
free_lbuf(buff);
goto error;
}
free_lbuf(buff);
b->thing = anum;
} else {
free_bool(b);
goto error;
}
/* if last character is : then this is an attribute lock */
if (c == ':') {
buff = alloc_lbuf("getboolexp1.attr_lock");
for (s=buff;
((c=getc(f))!=EOF) && (c!='\n') && (c!=')') &&
(c!=OR_TOKEN) && (c!=AND_TOKEN);
*s++=c);
if (c == EOF)
goto error;
*s++ = 0;
b->sub1 = (struct boolexp *)strsave(buff);
b->type = BOOLEXP_ATR;
free_lbuf(buff);
}
ungetc(c, f);
return b;
}
error:
abort(); /* bomb out */
return TRUE_BOOLEXP;
}
/* ---------------------------------------------------------------------------
* getboolexp: Read a boolean expression from the flat file.
*/
static struct boolexp *getboolexp(FILE *f)
{
struct boolexp *b;
char c;
b = getboolexp1(f);
if (getc(f) != '\n')
abort(); /* parse error, we lose */
/* MUSH (except for PernMUSH) and MUSE can have an extra CR,
* MUD does not. */
if (((g_format == F_MUSH) && (g_version != 2)) ||
(g_format == F_MUSE)) {
if ((c = getc(f)) != '\n') ungetc(c, f);
}
return b;
}
/* ---------------------------------------------------------------------------
* unscramble_attrnum: Fix up attribute numbers from foreign muds
*/
static int unscramble_attrnum (int attrnum)
{
char anam[4];
switch (g_format) {
case F_MUSE:
switch (attrnum) {
case 39: return A_IDLE;
case 40: return A_AWAY;
case 41: return 0; /* mailk */
case 42: return A_ALIAS;
case 43: return A_EFAIL;
case 44: return A_OEFAIL;
case 45: return A_AEFAIL;
case 46: return 0; /* it */
case 47: return A_LEAVE;
case 48: return A_OLEAVE;
case 49: return A_ALEAVE;
case 50: return 0; /* channel */
case 51: return A_QUOTA;
case 52: return A_TEMP; /* temp for pennies */
case 53: return 0; /* huhto */
case 54: return 0; /* haven */
case 57: return mkattr((char *)"TZ");
case 58: return 0; /* doomsday */
case 59: return mkattr((char *)"Email");
case 98: return mkattr((char *)"Status");
case 99: return mkattr((char *)"Race");
default: return attrnum;
}
case F_MUSH:
/* Only need to muck with Pern variants */
if (g_version != 2)
return attrnum;
switch (attrnum) {
case 34: return A_OENTER;
case 41: return A_LEAVE;
case 42: return A_ALEAVE;
case 43: return A_OLEAVE;
case 44: return A_OXENTER;
case 45: return A_OXLEAVE;
default:
if ((attrnum >= 126) && (attrnum < 152)) {
anam[0]='W';
anam[1]=attrnum - 126 + 'A';
anam[2]='\0';
return mkattr(anam);
}
if ((attrnum >= 152) && (attrnum < 178)) {
anam[0]='X';
anam[1]=attrnum - 152 + 'A';
anam[2]='\0';
return mkattr(anam);
}
return attrnum;
}
default:
return attrnum;
}
}
/* ---------------------------------------------------------------------------
* get_list: Read attribute list from flat file.
*/
static int get_list(FILE * f, dbref i)
{
dbref atr, aowner;
int c, aflags, xflags, anum;
char *buff, *buf2, *buf2p, *ownp, *flagp;
buff = alloc_lbuf("get_list");
while (1) {
switch (c = getc(f)) {
case '>': /* read # then string */
atr = unscramble_attrnum(getref(f));
if (atr > 0) {
/* Store the attr */
atr_add_raw(i, atr,
(char *)getstring_noalloc(f));
} else {
/* Silently discard */
getstring_noalloc(f);
}
break;
case ']': /* Pern 1.13 style text attribute */
strcpy(buff, (char *)getstring_noalloc(f));
/* Get owner number */
ownp = (char *)index(buff, '^');
if (!ownp) {
fprintf(stderr,
"Bad format in attribute on object %d\n",
i);
free_lbuf(buff);
return 0;
}
*ownp++ = '\0';
/* Get attribute flags */
flagp = (char *)index(ownp, '^');
if (!flagp) {
fprintf(stderr,
"Bad format in attribute on object %d\n",
i);
free_lbuf(buff);
return 0;
}
*flagp++ = '\0';
/* Convert Pern-style owner and flags to 2.0 format */
aowner = atoi(ownp);
xflags = atoi(flagp);
aflags = 0;
if (!aowner) aowner = NOTHING;
if (xflags & 0x10) aflags |= AF_LOCK|AF_NOPROG;
if (xflags & 0x20) aflags |= AF_NOPROG;
/* Look up the attribute name in the attribute table.
* If the name isn't found, create a new attribute.
* If the create fails, try prefixing the attr name
* with ATR_ (Pern allows attributes to start with a
* non-alphabetic character.
*/
anum = mkattr(buff);
if (anum < 0) {
buf2 = alloc_mbuf("get_list.new_attr_name");
buf2p = buf2;
safe_mb_str((char *)"ATR_", buf2, &buf2p);
safe_mb_str(buff, buf2, &buf2p);
*buf2p = '\0';
anum = mkattr(buf2);
free_mbuf(buf2);
}
if (anum < 0) {
fprintf(stderr,
"Bad attribute name '%s' on object %d, ignoring...\n",
buff, i);
(void)getstring_noalloc(f);
} else {
atr_add(i, anum, (char *)getstring_noalloc(f),
aowner, aflags);
}
break;
case '\n': /* ignore newlines. They're due to v(r). */
break;
case '<': /* end of list */
free_lbuf(buff);
if ('\n' != getc(f)) {
fprintf(stderr,
"No line feed on object %d\n", i);
return 0;
}
return 1;
default:
fprintf(stderr,
"Bad character '%c' when getting attributes on object %d\n",
c, i);
free_lbuf(buff);
return 0;
}
}
}
/* ---------------------------------------------------------------------------
* putbool_subexp: Write a boolean sub-expression to the flat file.
*/
static void putbool_subexp(FILE * f, struct boolexp * b)
{
switch (b->type) {
case BOOLEXP_IS:
putc('(', f);
putc(IS_TOKEN, f);
putbool_subexp(f, b->sub1);
putc(')', f);
break;
case BOOLEXP_CARRY:
putc('(', f);
putc(CARRY_TOKEN, f);
putbool_subexp(f, b->sub1);
putc(')', f);
break;
case BOOLEXP_INDIR:
putc('(', f);
putc(INDIR_TOKEN, f);
putbool_subexp(f, b->sub1);
putc(')', f);
break;
case BOOLEXP_OWNER:
putc('(', f);
putc(OWNER_TOKEN, f);
putbool_subexp(f, b->sub1);
putc(')', f);
break;
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_ATR:
fprintf(f, "%d:%s\n", b->thing, (char *)b->sub1);
break;
default:
fprintf(stderr, "Unknown boolean type in putbool_subexp: %d\n",
b->type);
}
}
/* ---------------------------------------------------------------------------
* putboolexp: Write boolean expression to the flat file.
*/
static void putboolexp(FILE * f, struct boolexp * b)
{
if (b != TRUE_BOOLEXP) {
putbool_subexp(f, b);
}
putc('\n', f);
}
/* ---------------------------------------------------------------------------
* upgrade_flags: Convert foreign flags to MUSH format.
*/
static FLAG upgrade_flags (FLAG oldflags, dbref thing, int db_format,
int db_version)
{
FLAG newflags;
if (db_format == F_MUSE) {
if (db_version == 1)
return oldflags;
/* Convert level-based players to normal */
switch (oldflags & 0xf) {
case 0: /* room */
case 1: /* thing */
case 2: /* exit */
newflags = oldflags & 0x3;
break;
case 8: /* guest */
case 9: /* trial player */
case 10: /* member */
case 11: /* junior official */
case 12: /* official */
newflags = TYPE_PLAYER;
break;
case 13: /* honorary wizard */
case 14: /* administrator */
case 15: /* director */
newflags = TYPE_PLAYER|WIZARD;
break;
default: /* A bad type, mark going */
fprintf(stderr, "Funny object type for #%d\n", thing);
return GOING;
}
/* Player #1 is always a wizard */
if (thing == (dbref)1) newflags |= WIZARD;
/* Set type-specific flags */
switch(newflags & TYPE_MASK) {
case TYPE_PLAYER: /* Lose CONNECT TERSE QUITE NOWALLS WARPTEXT */
if (oldflags & 0x10) newflags |= PLAYER_BUILD;
if (oldflags & 0x80) newflags |= PLAYER_SLAVE;
if (oldflags & 0x1000) newflags |= PLAYER_UNFIND;
break;
case TYPE_THING: /* lose LIGHT SACR_OK */
if (oldflags & 0x10) newflags |= THING_KEY;
if (oldflags & 0x200) newflags |= THING_DEST_OK;
break;
case TYPE_ROOM:
if (oldflags & 0x80) newflags |= ROOM_TEMPLE;
if (oldflags & 0x200) newflags |= ROOM_ABODE;
break;
case TYPE_EXIT:
if (oldflags & 0x200) newflags |= EXIT_SEETHRU;
default:
break;
}
/* Convert common flags */
/* Lose: MORTAL ACCESSED MARKED SEE_OK UNIVERSAL */
if (oldflags & 0x20) newflags |= CHOWN_OK;
if (oldflags & 0x40) newflags |= DARK;
if (oldflags & 0x100) newflags |= STICKY;
if (oldflags & 0x400) newflags |= HAVEN;
if (oldflags & 0x2000) newflags |= INHERIT;
if (oldflags & 0x4000) newflags |= GOING;
if (oldflags & 0x20000) newflags |= PUPPET;
if (oldflags & 0x40000) newflags |= LINK_OK;
if (oldflags & 0x80000) newflags |= ENTER_OK;
if (oldflags & 0x100000) newflags |= VISUAL;
if (oldflags & 0x800000) newflags |= OPAQUE;
if (oldflags & 0x1000000) newflags |= QUIET;
return newflags;
} else if ((db_format == F_MUSH) && (db_version == 2)) {
/* Pern variants */
newflags = oldflags &
(TYPE_MASK|LINK_OK|HAVEN|QUIET|HALT|DARK|
GOING|PUPPET|CHOWN_OK|ENTER_OK|VISUAL|OPAQUE);
if (oldflags & 0x1000000) newflags |= INHERIT;
if (oldflags & 0x10000000) newflags |= HEARTHRU;
switch(newflags & TYPE_MASK) {
case TYPE_PLAYER:
newflags |= oldflags &
(WIZARD|PLAYER_BUILD|PLAYER_GAGGED|PLAYER_UNFIND);
if (oldflags & 0x200000) newflags |= NOSPOOF;
if (oldflags & 0x4000000) newflags |= PLAYER_SUSPECT;
break;
case TYPE_EXIT:
newflags |= oldflags & (STICKY|EXIT_SEETHRU);
if (oldflags & 0x8) newflags |= EXIT_KEY;
if (oldflags & WIZARD) newflags |= INHERIT;
break;
case TYPE_THING:
newflags |= oldflags &
(THING_KEY|THING_DEST_OK|STICKY);
if (oldflags & WIZARD) newflags |= INHERIT;
if (oldflags & 0x80) newflags |= VERBOSE;
if (oldflags & 0x2000) newflags |= IMMORTAL;
if (oldflags & 0x200000) newflags |= MONITOR;
if (oldflags & 0x4000000) newflags |= THING_SAFE;
break;
case TYPE_ROOM:
newflags |= oldflags &
(ROOM_FLOATING|ROOM_TEMPLE|ROOM_ABODE|
ROOM_JUMP_OK);
if (oldflags & WIZARD) newflags |= INHERIT;
}
return newflags;
} else if ((db_format == F_MUSH) && (db_version == 3)) {
/* MUSH 2.0 format 3: Clear the ACCESSED bit */
return (oldflags & ~0x8000);
} else if ((db_format == F_MUSH) && (db_version == 4)) {
/* MUSH 2.0 format 4: Clear the MARKED bit */
return (oldflags & ~0x10000);
}
return oldflags;
}
/* ---------------------------------------------------------------------------
* efo_convert: Fix things up for Exits-From-Objects
*/
void efo_convert ()
{
int i;
dbref link;
DO_WHOLE_DB(i) {
switch (Typeof(i)) {
case TYPE_PLAYER:
case TYPE_THING:
/* swap Exits and Link */
link = Link(i);
s_Link(i, Exits(i));
s_Exits(i, link);
break;
}
}
}
/* ---------------------------------------------------------------------------
* unscraw_foreign: Fix up strange object linking conventions for other formats
*/
static void unscraw_pern_object (dbref i, int db_flags)
{
dbref aowner;
int aflags;
char *p_str;
if (db_flags & V_PERNKEY) {
/* Use lock on players is really the page lock */
if (Typeof(i) == TYPE_PLAYER) {
p_str = atr_get(i, A_LUSE, &aowner, &aflags);
if (*p_str) {
atr_add_raw(i, A_LPAGE, p_str);
atr_clr(i, A_LUSE);
}
free_lbuf(p_str);
}
/* Enter lock on rooms is the teleport-out lock (not imp) */
if (Typeof(i) == TYPE_ROOM) {
atr_clr(i, A_LENTER);
}
}
}
void unscraw_foreign(int db_format, int db_version, int db_flags)
{
dbref tmp, i, aowner;
int aflags;
char *p_str;
switch (db_format) {
case F_MUSE:
DO_WHOLE_DB(i) {
if (Typeof(i) == TYPE_EXIT) {
/* MUSE exits are bass-ackwards */
tmp = Exits(i);
s_Exits(i, Location(i));
s_Location(i, tmp);
}
if (db_version > 3) {
/* MUSEs with pennies in an attribute have
* it stored in attr 255 (see
* unscramble_attrnum)
*/
p_str = atr_get(i, A_TEMP, &aowner, &aflags);
s_Pennies(i, atoi(p_str));
free_lbuf(p_str);
atr_clr(i, A_TEMP);
}
}
if (!(db_flags & V_LINK)) {
efo_convert();
}
break;
case F_MUSH:
if (db_version <= 3) {
if (db_version == 2) {
DO_WHOLE_DB(i) {
unscraw_pern_object(i, db_flags);
}
}
efo_convert();
}
break;
case F_MUD:
efo_convert();
}
}
/* ---------------------------------------------------------------------------
* getlist_discard, get_atrdefs_discard: Throw away data from MUSE that we
* don't use.
*/
static void getlist_discard (FILE *f)
{
int count;
for (count=getref(f); count>0; count--)
(void)getref(f);
}
static void get_atrdefs_discard (FILE *f)
{
const char *sp;
for (;;) {
sp = getstring_noalloc(f); /* flags or endmarker */
if (*sp == '\\')
return;
sp = getstring_noalloc(f); /* object */
sp = getstring_noalloc(f); /* name */
}
}
dbref db_read(FILE *f, int *db_format, int *db_version, int *db_flags)
{
dbref i, anum;
char ch, peek;
const char *tstr;
int header_gotten, size_gotten, nextattr_gotten;
int read_attribs, read_name, read_zone, read_link, read_key, read_parent;
int read_pennies, read_timestamps;
int read_pern_key, read_pern_comm, read_powers_player, read_powers_any;
int read_muse_parents, read_muse_atrdefs;
int deduce_version, deduce_name, deduce_zone, deduce_timestamps;
int aflags;
struct boolexp *tempbool;
header_gotten = 0;
size_gotten = 0;
nextattr_gotten = 0;
g_format = F_UNKNOWN;
g_version = 0;
g_flags = 0;
read_attribs = 1;
read_name = 1;
read_zone = 0;
read_link = 0;
read_key = 1;
read_parent = 0;
read_pennies = 1;
read_timestamps = 0;
read_pern_key = 0;
read_pern_comm = 0;
read_powers_player = 0;
read_powers_any = 0;
read_muse_parents = 0;
read_muse_atrdefs = 0;
deduce_version = 1;
deduce_zone = 1;
deduce_name = 1;
deduce_timestamps = 1;
#ifdef STANDALONE
fprintf(stderr, "Reading ");
fflush(stderr);
#endif
db_free();
for (i = 0;; i++) {
#ifdef STANDALONE
if (!(i % 100)) {
fputc('.', stderr);
fflush(stderr);
tmp_sync();
cache_reset();
}
#endif
switch (ch = getc(f)) {
case '~': /* Database size tag */
if (size_gotten) {
fprintf(stderr,
"\nDuplicate size entry at object %d, ignored.\n",
i);
tstr = getstring_noalloc(f); /* junk */
break;
}
mudstate.min_size = getref(f);
size_gotten = 1;
break;
case '+': /* MUSH 2.0 header */
switch (ch = getc(f)) { /* 2nd char selects type */
case 'V': /* VERSION */
if (header_gotten) {
fprintf(stderr,
"\nDuplicate MUSH version header entry at object %d, ignored.\n",
i);
tstr = getstring_noalloc(f); /* junk */
break;
}
header_gotten = 1;
deduce_version = 0;
g_format = F_MUSH;
g_version = getref(f);
if ((g_version & V_MASK) == 2) {
/* Handle Pern veriants specially */
switch (g_version >> 8) {
case 2:
read_pern_comm = 1;
g_flags |= V_COMM;
case 1:
read_pern_key = 1;
read_parent = 1;
g_flags |= V_PERNKEY|V_ZONE;
}
} else {
/* Otherwise extract feature flags */
if (g_version & V_GDBM) {
read_attribs = 0;
read_name = !(g_version & V_ATRNAME);
}
read_zone = (g_version & V_ZONE);
read_link = (g_version & V_LINK);
read_key = !(g_version & V_ATRKEY);
read_parent = (g_version & V_PARENT);
g_flags = g_version & ~V_MASK;
}
g_version &= V_MASK;
deduce_name = 0;
deduce_version = 0;
deduce_zone = 0;
break;
case 'S': /* SIZE */
if (size_gotten) {
fprintf(stderr,
"\nDuplicate size entry at object %d, ignored.\n",
i);
tstr = getstring_noalloc(f); /* junk */
} else {
mudstate.min_size = getref(f);
}
size_gotten = 1;
break;
case 'A': /* USER-NAMED ATTRIBUTE */
anum = getref(f);
tstr = getstring_noalloc(f);
if (isdigit(*tstr)) {
aflags = 0;
while (isdigit(*tstr))
aflags = (aflags * 10) +
(*tstr++ - '0');
tstr++; /* skip ':' */
} else {
aflags = mudconf.vattr_flags;
}
define_vattr((char *)tstr, anum, aflags);
break;
case 'F': /* OPEN USER ATTRIBUTE SLOT */
anum = getref(f);
free_vattr(anum);
break;
case 'N': /* NEXT ATTR TO ALLOC WHEN NO FREELIST */
if (nextattr_gotten) {
fprintf(stderr,
"\nDuplicate next free vattr entry at object %d, ignored.\n",
i);
tstr = getstring_noalloc(f); /* junk */
} else {
mudstate.attr_next = getref(f);
nextattr_gotten = 1;
}
break;
default:
fprintf(stderr,
"\nUnexpected character '%c' in MUSH header near object #%d, ignored.\n",
ch, i);
tstr = getstring_noalloc(f); /* toss line */
}
break;
case '@': /* MUSE header */
if (header_gotten) {
fprintf(stderr,
"\nDuplicate MUSE header entry at object #%d.\n",
i);
return -1;
}
header_gotten = 1;
deduce_version = 0;
g_format = F_MUSE;
g_version = getref(f);
deduce_name = 0;
deduce_zone = 1;
read_pennies = (g_version <= 3);
read_link = (g_version >= 5);
read_powers_player = (g_version >= 6);
read_powers_any = (g_version == 6);
read_muse_parents = (g_version >= 8);
read_muse_atrdefs = (g_version >= 8);
if (read_link) g_flags |= V_LINK;
break;
case '#':
if (deduce_version) {
g_format = F_MUD;
g_version = 1;
deduce_version = 0;
}
if (g_format != F_MUD) {
fprintf(stderr,
"\nMUD-style object found in non-MUD database at object #%d\n",
i);
return -1;
}
if (i != getref(f)) {
fprintf(stderr,
"\nSequence error at object #%d\n", i);
return -1;
}
db_grow(i+1);
s_Name(i, getstring_noalloc(f));
atr_add_raw(i, A_DESC, (char *)getstring_noalloc(f));
s_Location(i, getref(f));
s_Contents(i, getref(f));
s_Exits(i, getref(f));
s_Link(i, NOTHING);
s_Next(i, getref(f));
s_Zone(i, NOTHING);
tempbool = getboolexp(f);
atr_add_raw(i, A_LOCK,
unparse_boolexp_quiet(1, tempbool));
free_boolexp(tempbool);
atr_add_raw(i, A_FAIL, (char *)getstring_noalloc(f));
atr_add_raw(i, A_SUCC, (char *)getstring_noalloc(f));
atr_add_raw(i, A_OFAIL, (char *)getstring_noalloc(f));
atr_add_raw(i, A_OSUCC, (char *)getstring_noalloc(f));
s_Owner(i, getref(f));
s_Parent(i, NOTHING);
s_Pennies(i, getref(f));
s_Flags(i, upgrade_flags(getref(f), i,
g_format, g_version));
s_Pass(i, getstring_noalloc(f));
if (deduce_timestamps) {
peek = getc(f);
if ((peek != '#') && (peek != '*')) {
read_timestamps = 1;
}
deduce_timestamps = 0;
ungetc(peek,f);
}
if (read_timestamps) {
aflags = getref(f); /* created */
aflags = getref(f); /* lastused */
aflags = getref(f); /* usecount */
}
break;
case '&': /* MUSH 2.0a stub entry/MUSE zoned entry */
if (deduce_version) {
deduce_version = 0;
g_format = F_MUSH;
g_version = 1;
deduce_name = 1;
deduce_zone = 0;
read_key = 0;
read_attribs = 0;
} else if (deduce_zone) {
deduce_zone = 0;
read_zone = 1;
g_flags |= V_ZONE;
}
case '!': /* MUSH entry/MUSE non-zoned entry */
if (deduce_version) {
g_format = F_MUSH;
g_version = 1;
deduce_name = 0;
deduce_zone = 0;
deduce_version = 0;
} else if (deduce_zone) {
deduce_zone = 0;
read_zone = 0;
}
i = getref(f);
db_grow(i+1);
if (read_name) {
tstr = getstring_noalloc(f);
if (deduce_name) {
if (isdigit(*tstr)) {
read_name = 0;
s_Location(i, atol(tstr));
} else {
s_Name(i, tstr);
s_Location(i, getref(f));
}
deduce_name = 0;
} else {
s_Name(i, tstr);
s_Location(i, getref(f));
}
} else {
s_Location(i, getref(f));
}
if (read_zone)
s_Zone(i, getref(f));
else
s_Zone(i, NOTHING);
s_Contents(i, getref(f));
s_Exits(i, getref(f));
if (read_link)
s_Link(i, getref(f));
else
s_Link(i, NOTHING);
s_Next(i, getref(f));
if (read_key) {
tempbool = getboolexp(f);
atr_add_raw(i, A_LOCK,
unparse_boolexp_quiet(1, tempbool));
free_boolexp(tempbool);
if (read_pern_key) {
/* Read Pern 1.17-style locks */
tempbool = getboolexp(f);
atr_add_raw(i, A_LUSE,
unparse_boolexp_quiet(1,
tempbool));
free_boolexp(tempbool);
tempbool = getboolexp(f);
atr_add_raw(i, A_LENTER,
unparse_boolexp_quiet(1,
tempbool));
free_boolexp(tempbool);
}
}
s_Owner(i, getref(f));
if (read_parent)
s_Parent(i, getref(f));
else
s_Parent(i, NOTHING);
if (read_pennies) /* if not fix in unscraw_foreign */
s_Pennies(i, getref(f));
s_Flags(i, upgrade_flags(getref(f), i,
g_format, g_version));
if (read_powers_any ||
((Typeof(i) == TYPE_PLAYER) && read_powers_player))
(void)getstring_noalloc(f);
if (read_pern_comm)
(void)getref(f);
if (read_attribs) {
if (!get_list(f, i)) {
fprintf(stderr,
"\nError reading attrs for object #%d\n",
i);
return -1;
}
}
if (read_muse_parents) {
getlist_discard(f);
getlist_discard(f);
}
if (read_muse_atrdefs) {
get_atrdefs_discard(f);
}
/* check to see if it's a player */
if (Typeof(i) == TYPE_PLAYER) {
s_Flags(i, Flags(i) & (~PLAYER_CONNECT));
}
break;
case '*': /* EOF marker */
tstr = getstring_noalloc(f);
if (strcmp(tstr, "**END OF DUMP***")) {
fprintf(stderr,
"\nBad EOF marker at object #%d\n",
i);
return -1;
} else {
#ifdef STANDALONE
fprintf(stderr, "\n");
fflush(stderr);
#endif
/* Fix up bizarro foreign DBs */
unscraw_foreign(g_format, g_version, g_flags);
*db_version = g_version;
*db_format = g_format;
*db_flags = g_flags;
#ifndef STANDALONE
load_player_names();
#endif
return mudstate.db_top;
}
default:
fprintf(stderr, "\nIllegal character '%c' near object #%d\n",
ch, i);
return -1;
}
}
}
static int db_write_object(FILE * f, dbref i, int db_format, int flags)
{
ATTR *a;
char *got, *as;
dbref aowner;
int ca, aflags, save;
struct boolexp *tempbool;
#ifdef ATR_NAME
if (!(flags & V_ATRNAME))
putstring(f, Name(i));
#else
putstring(f, Name(i));
#endif
putref(f, Location(i));
if (flags & V_ZONE)
putref(f, Zone(i));
putref(f, Contents(i));
putref(f, Exits(i));
if (flags & V_LINK)
putref(f, Link(i));
putref(f, Next(i));
if (!(flags & V_ATRKEY)) {
got = atr_get(i, A_LOCK, &aowner, &aflags);
tempbool = parse_boolexp(GOD, got);
free_lbuf(got);
putboolexp(f, tempbool);
free_bool(tempbool);
}
putref(f, Owner(i));
if (flags & V_PARENT)
putref(f, Parent(i));
putref(f, Pennies(i));
putref(f, Flags(i));
/* write the attribute list */
if (!(flags & V_GDBM)) {
for (ca=atr_head(i,&as); ca; ca=atr_next(&as)) {
a = atr_num(ca);
save = 0;
if (a) {
switch (a->number) {
case A_NAME:
if (flags & V_ATRNAME) save = 1;
break;
case A_LOCK:
if (flags & V_ATRKEY) save = 1;
break;
case A_LIST:
break;
default:
save = 1;
}
}
if (save) {
got = atr_get_raw(i, a->number);
fprintf(f, ">%d\n%s\n", a->number, got);
}
}
fprintf(f, "<\n");
}
return 0;
}
dbref db_write(FILE * f, int format, int version)
{
dbref i;
int flags;
VATTR *vp;
al_store();
switch (format) {
case F_MUSH:
flags = version;
break;
default:
fprintf(stderr, "Can only write MUSH format.\n");
return -1;
}
#ifdef STANDALONE
fprintf(stderr, "Writing ");
fflush(stderr);
#endif
i = mudstate.attr_next;
fprintf(f, "+V%d\n+S%d\n+N%d\n", flags, mudstate.db_top, i);
/* Dump user-named attribute info */
vp = mudstate.user_attrs;
while (vp != NULL) {
if (!(vp->flags & AF_DELETED))
fprintf(f, "+A%d\n%d:%s\n",
vp->number, vp->flags, vp->name);
vp = vp->next;
}
vp = mudstate.user_attr_free;
while (vp != NULL) {
fprintf(f, "+F%d\n", vp->number);
vp = vp->next;
}
DO_WHOLE_DB(i) {
#ifdef STANDALONE
if (!(i % 100)) {
fputc('.', stderr);
fflush(stderr);
tmp_sync();
cache_reset();
}
#endif
fprintf(f, "!%d\n", i);
db_write_object(f, i, format, flags);
}
fputs("***END OF DUMP***\n", f);
fflush(f);
#ifdef STANDALONE
fprintf(stderr, "\n");
fflush(stderr);
#endif
return (mudstate.db_top);
}