tinymush-3.0b21/game/bin/
tinymush-3.0b21/game/data/
tinymush-3.0b21/src/tools/
/* db_rw.c */
/* $Id: db_rw.c,v 1.32.2.1 2000/05/25 06:22:20 cvs Exp $ */

#include "copyright.h"
#include "autoconf.h"

#include <sys/file.h>

#include "mudconf.h"
#include "config.h"
#include "externs.h"
#include "db.h"
#include "vattr.h"
#include "attrs.h"
#include "alloc.h"
#include "powers.h"

extern const char *FDECL(getstring_noalloc, (FILE *, int));
extern void FDECL(putstring, (FILE *, const char *));
extern void FDECL(db_grow, (dbref));

extern struct object *db;

static int g_version;
static int g_format;
static int g_flags;

/* ---------------------------------------------------------------------------
 * getboolexp1: Get boolean subexpression from file.
 */

BOOLEXP *getboolexp1(f)
FILE *f;
{
	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:
	        fprintf(stderr, "ABORT! db_rw.c, unexpected EOF in boolexp in getboolexp1().\n");
		abort();
		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) {
			fprintf(stderr, "ABORT! db_rw.c, unexpected EOF in getboolexp1().\n");
			abort();
		    }
		}
		ungetc(c, f);
		return TRUE_BOOLEXP;
	case '"':
		ungetc(c, f);
		buff = alloc_lbuf("getboolexp_quoted");
		StringCopy(buff, getstring_noalloc(f, 1));
		c = fgetc(f);
		if (c == EOF) {
			free_lbuf(buff);
			return TRUE_BOOLEXP;
		}

		b = alloc_bool("getboolexp1_quoted");
		anum = mkattr(buff);
		if (anum <= 0) {
			free_bool(b);
			free_lbuf(buff);
			goto error;
		}
		free_lbuf(buff);
		b->thing = anum;

		/* if last character is : then this is an attribute lock. A 
		 * last character of / means an eval lock 
		 */

		if ((c == ':') || (c == '/')) {
			if (c == '/')
				b->type = BOOLEXP_EVAL;
			else
				b->type = BOOLEXP_ATR;
			buff = alloc_lbuf("getboolexp1.attr_lock");
			StringCopy(buff, getstring_noalloc(f, 1));
			b->sub1 = (BOOLEXP *) strsave(buff);
			free_lbuf(buff);
		}
		return b;
	default:		/* dbref or attribute */
		ungetc(c, f);
		b = alloc_bool("getboolexp1.default");
		b->type = BOOLEXP_CONST;
		b->thing = 0;

		/* This is either an attribute, eval, or constant lock.
		 * Constant locks are of the form <num>, while attribute and 
		 * eval locks are of the form <anam-or-anum>:<string> or
		 * <aname-or-anum>/<string> respectively. 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 != ':') && (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. A 
		 * last character of / means an eval lock 
		 */

		if ((c == ':') || (c == '/')) {
			if (c == '/')
				b->type = BOOLEXP_EVAL;
			else
				b->type = BOOLEXP_ATR;
			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 = (BOOLEXP *) strsave(buff);
			free_lbuf(buff);
		}
		ungetc(c, f);
		return b;
	}

      error:
	fprintf(stderr,
		"ABORT! db_rw.c, reached error case in getboolexp1().\n");
	abort();		/* bomb out */
	return TRUE_BOOLEXP;	/* NOTREACHED */
}

/* ---------------------------------------------------------------------------
 * getboolexp: Read a boolean expression from the flat file.
 */

static BOOLEXP *getboolexp(f)
FILE *f;
{
	BOOLEXP *b;
	char c;

	b = getboolexp1(f);
	if (getc(f) != '\n') {
	    fprintf(stderr, "ABORT! db_rw.c, parse error in getboolexp().\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) || (g_format == F_MUX) ||
	    (g_format == F_TINYMUSH)) {
		if ((c = getc(f)) != '\n')
			ungetc(c, f);
	}
	return b;
}

#ifdef STANDALONE
/* ---------------------------------------------------------------------------
 * unscramble_attrnum: Fix up attribute numbers from foreign muds
 */

static int unscramble_attrnum(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:

	    if (g_version != 2) {

		/* TinyMUSH 2.2:  Deal with different attribute numbers. */

		switch (attrnum) {
		    case 208:
			return A_NEWOBJS;
			break;
		    case 209:
			return A_LCON_FMT;
			break;
		    case 210:
			return A_LEXITS_FMT;
			break;
		    case 211:
			return A_PROGCMD;
			break;
		    default:
			return attrnum;
		}

	    } else {

		/* Penn variant */

		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;
	}
}
#endif

/* ---------------------------------------------------------------------------
 * get_list: Read attribute list from flat file.
 */

static int get_list(f, i, new_strings)
FILE *f;
dbref i;
int new_strings;
{
	dbref atr;
	int c;
	char *buff;
#ifdef STANDALONE
	int aflags, xflags, anum;
	char *buf2, *buf2p, *ownp, *flagp;
	dbref aowner;
#endif

	buff = alloc_lbuf("get_list");
	while (1) {
		switch (c = getc(f)) {
		case '>':	/* read # then string */
#ifdef STANDALONE
			atr = unscramble_attrnum(getref(f));
#else
			atr = getref(f);
#endif
			if (atr > 0) {
				/* Store the attr */

				atr_add_raw(i, atr,
					 (char *)getstring_noalloc(f, new_strings));
			} else {
				/* Silently discard */

				getstring_noalloc(f, new_strings);
			}
			break;
#ifdef STANDALONE
		case ']':	/* Pern 1.13 style text attribute */
			strcpy(buff, (char *)getstring_noalloc(f, new_strings));

			/* 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;

			if (!strcmp(buff, "XYXXY"))
				s_Pass(i, (char *)getstring_noalloc(f, new_strings));
			else {
				/* 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);
				}
				/*
				 * MAILFOLDERS under MUSH must be owned by the 
				 * player, not GOD 
				 */

				if (!strcmp(buff, "MAILFOLDERS")) {
					aowner = Owner(i);
				}
				if (anum < 0) {
					fprintf(stderr,
						"Bad attribute name '%s' on object %d, ignoring...\n",
						buff, i);
					(void)getstring_noalloc(f, new_strings);
				} else {
					atr_add(i, anum, (char *)getstring_noalloc(f, new_strings),
						aowner, aflags);
				}
			}
			break;
#endif
		case '\n':	/* ignore newlines. They're due to v(r). */
			break;
		case '<':	/* end of list */
			free_lbuf(buff);
			c = getc(f);
			if (c != '\n') {
				ungetc(c, f);
				fprintf(stderr,
					"No line feed on object %d\n", i);
				return 1;
			}
			return 1;
		default:
			fprintf(stderr,
				"Bad character '%c' when getting attributes on object %d\n",
				c, i);
			/* We've found a bad spot.  I hope things aren't
			 * too bad. 
			 */

			(void)getstring_noalloc(f, new_strings);
		}
	}
	return 1;		/* UNREACHED */
}

/* ---------------------------------------------------------------------------
 * putbool_subexp: Write a boolean sub-expression to the flat file.
 */
static void putbool_subexp(f, b)
FILE *f;
BOOLEXP *b;
{
	ATTR *va;

	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:
		va = atr_num(b->thing);
		if (va) {
			fprintf(f, "%s:%s", va->name, (char *)b->sub1);
		} else {
			fprintf(f, "%d:%s\n", b->thing, (char *)b->sub1);
		}
		break;
	case BOOLEXP_EVAL:
		va = atr_num(b->thing);
		if (va) {
			fprintf(f, "%s/%s\n", va->name, (char *)b->sub1);
		} else {
			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.
 */

void putboolexp(f, b)
FILE *f;
BOOLEXP *b;
{
	if (b != TRUE_BOOLEXP) {
		putbool_subexp(f, b);
	}
	putc('\n', f);
}

#ifdef STANDALONE
/* ---------------------------------------------------------------------------
 * upgrade_flags: Convert foreign flags to MUSH format.
 */

static void upgrade_flags(flags1, flags2, flags3, thing, db_format, db_version)
FLAG *flags1, *flags2, *flags3;
dbref thing;
int db_format, db_version;
{
	FLAG f1, f2, f3, newf1, newf2, newf3;

	f1 = *flags1;
	f2 = *flags2;
	f3 = *flags3;
	newf1 = 0;
	newf2 = 0;
	newf3 = 0;
	if (db_format == F_MUD) {

		/* Old TinyMUD format */

		newf1 = f1 & (TYPE_MASK | WIZARD | LINK_OK | DARK | STICKY | HAVEN);
		if (f1 & MUD_ABODE)
			newf2 |= ABODE;
		if (f1 & MUD_ROBOT)
			newf1 |= ROBOT;
		if (f1 & MUD_CHOWN_OK)
			newf1 |= CHOWN_OK;

	} else if (db_format == F_MUSE) {
		if (db_version == 1)
			return;

		/* Convert level-based players to normal */

		switch (f1 & 0xf) {
		case 0:	/* room */
		case 1:	/* thing */
		case 2:	/* exit  */
			newf1 = f1 & 0x3;
			break;
		case 8:	/* guest */
		case 9:	/* trial player */
		case 10:	/* member */
		case 11:	/* junior official */
		case 12:	/* official */
			newf1 = TYPE_PLAYER;
			break;
		case 13:	/* honorary wizard */
		case 14:	/* administrator */
		case 15:	/* director */
			newf1 = TYPE_PLAYER | WIZARD;
			break;
		default:	/* A bad type, mark going */
			fprintf(stderr, "Funny object type for #%d\n", thing);
			*flags1 = GOING;
			return;
		}

		/* Player #1 is always a wizard */

		if (thing == (dbref) 1)
			newf1 |= WIZARD;

		/* Set type-specific flags */

		switch (newf1 & TYPE_MASK) {
		case TYPE_PLAYER:	/* Lose CONNECT TERSE QUITE NOWALLS
					 * WARPTEXT 
					 */
			if (f1 & MUSE_BUILD)
				s_Powers(thing, Powers(thing) | POW_BUILDER);
			if (f1 & MUSE_SLAVE)
				newf2 |= SLAVE;
			if (f1 & MUSE_UNFIND)
				newf2 |= UNFINDABLE;
			break;
		case TYPE_THING:	/* lose LIGHT SACR_OK */
			if (f1 & MUSE_KEY)
				newf2 |= KEY;
			if (f1 & MUSE_DEST_OK)
				newf1 |= DESTROY_OK;
			break;
		case TYPE_ROOM:
			if (f1 & MUSE_ABODE)
				newf2 |= ABODE;
			break;
		case TYPE_EXIT:
			if (f1 & MUSE_SEETHRU)
				newf1 |= SEETHRU;
		default:
			break;
		}

		/* Convert common flags */
		/* Lose: MORTAL ACCESSED MARKED SEE_OK UNIVERSAL */

		if (f1 & MUSE_CHOWN_OK)
			newf1 |= CHOWN_OK;
		if (f1 & MUSE_DARK)
			newf1 |= DARK;
		if (f1 & MUSE_STICKY)
			newf1 |= STICKY;
		if (f1 & MUSE_HAVEN)
			newf1 |= HAVEN;
		if (f1 & MUSE_INHERIT)
			newf1 |= INHERIT;
		if (f1 & MUSE_GOING)
			newf1 |= GOING;
		if (f1 & MUSE_PUPPET)
			newf1 |= PUPPET;
		if (f1 & MUSE_LINK_OK)
			newf1 |= LINK_OK;
		if (f1 & MUSE_ENTER_OK)
			newf1 |= ENTER_OK;
		if (f1 & MUSE_VISUAL)
			newf1 |= VISUAL;
		if (f1 & MUSE_OPAQUE)
			newf1 |= OPAQUE;
		if (f1 & MUSE_QUIET)
			newf1 |= QUIET;

	} else if ((db_format == F_MUSH) && (db_version == 2)) {

		/* Pern variants */

		newf1 = (f1 & TYPE_MASK);
		newf2 = 0;

		newf1 &= ~PENN_COMBAT;
		newf1 &= ~PENN_ACCESSED;
		newf1 &= ~PENN_MARKED;
		newf1 &= ~ROYALTY;

		if (f1 & PENN_INHERIT)
			newf1 |= INHERIT;
		if (f1 & PENN_AUDIBLE)
			newf1 |= HEARTHRU;
		if (f1 & PENN_ROYALTY)
			newf1 |= ROYALTY;
		if (f1 & PENN_WIZARD)
			newf1 |= WIZARD;
		if (f1 & PENN_LINK_OK)
			newf1 |= LINK_OK;
		if (f1 & PENN_DARK)
			newf1 |= DARK;
		if (f1 & PENN_VERBOSE)
			newf1 |= VERBOSE;
		if (f1 & PENN_STICKY)
			newf1 |= STICKY;
		if (f1 & PENN_TRANSPARENT)
			newf1 |= SEETHRU;
		if (f1 & PENN_HAVEN)
			newf1 |= HAVEN;
		if (f1 & PENN_QUIET)
			newf1 |= QUIET;
		if (f1 & PENN_HALT)
			newf1 |= HALT;
		if (f1 & PENN_UNFIND)
			newf2 |= UNFINDABLE;
		if (f1 & PENN_GOING)
			newf1 |= GOING;
		if (f1 & PENN_CHOWN_OK)
			newf1 |= CHOWN_OK;
		if (f1 & PENN_ENTER_OK)
			newf1 |= ENTER_OK;
		if (f1 & PENN_VISUAL)
			newf1 |= VISUAL;
		if (f1 & PENN_OPAQUE)
			newf1 |= OPAQUE;
		if (f1 & PENN_DEBUGGING)
			newf1 |= TRACE;
		if (f1 & PENN_SAFE)
			newf1 |= SAFE;
		if (f1 & PENN_STARTUP)
			newf1 |= HAS_STARTUP;

		switch (newf1 & TYPE_MASK) {
		case TYPE_PLAYER:
			if (f2 & PENN_PLAYER_TERSE)
				newf1 |= TERSE;
			if (f2 & PENN_PLAYER_MYOPIC)
				newf1 |= MYOPIC;
			if (f2 & PENN_PLAYER_NOSPOOF)
				newf1 |= NOSPOOF;
			if (f2 & PENN_PLAYER_SUSPECT)
				newf2 |= SUSPECT;
			if (f2 & PENN_PLAYER_GAGGED)
				newf2 |= SLAVE;
			if (f2 & PENN_PLAYER_MONITOR)
				newf1 |= MONITOR;
			if (f2 & PENN_PLAYER_CONNECT)
				newf2 &= ~CONNECTED;
			if (f2 & PENN_PLAYER_ANSI)
				newf2 |= ANSI;
			if (f2 & PENN_PLAYER_HEAD)
				newf2 |= HEAD_FLAG;
			if (f2 & PENN_PLAYER_FIXED)
				newf2 |= FIXED;
			if (f2 & PENN_PLAYER_ADMIN)
				newf2 |= STAFF;
			if (f2 & PENN_PLAYER_SLAVE)
				newf2 |= SLAVE;
			if (f2 & PENN_PLAYER_COLOR)
				newf2 |= ANSI;
			if (f2 & PENN_PLAYER_WEIRDANSI)
				newf2 |= NOBLEED;
			break;
		case TYPE_EXIT:
			if (f2 & PENN_EXIT_LIGHT)
				newf2 |= LIGHT;
			break;
		case TYPE_THING:
			if (f2 & PENN_THING_DEST_OK)
				newf1 |= DESTROY_OK;
			if (f2 & PENN_THING_PUPPET)
				newf1 |= PUPPET;
			if (f2 & PENN_THING_LISTEN)
				newf1 |= MONITOR;
			break;
		case TYPE_ROOM:
			if (f2 & PENN_ROOM_FLOATING)
				newf2 |= FLOATING;
			if (f2 & PENN_ROOM_ABODE)
				newf2 |= ABODE;
			if (f2 & PENN_ROOM_JUMP_OK)
				newf1 |= JUMP_OK;
			if (f2 & PENN_ROOM_LISTEN)
				newf1 |= MONITOR;
			if (f2 & PENN_ROOM_UNINSPECT)
				newf2 |= UNINSPECTED;
		}
	} else if ((db_format == F_MUSH) && (db_version >= 3)) {
		newf1 = f1;
		newf2 = f2;
		newf3 = 0;
		switch (db_version) {
		case 3:
			(newf1 &= ~V2_ACCESSED);	/* Clear ACCESSED */
		case 4:
			(newf1 &= ~V3_MARKED);	/* Clear MARKED */
		case 5:
			/* Merge GAGGED into SLAVE, move SUSPECT */

			if ((newf1 & TYPE_MASK) == TYPE_PLAYER) {
				if (newf1 & V4_GAGGED) {
					newf2 |= SLAVE;
					newf1 &= ~V4_GAGGED;
				}
				if (newf1 & V4_SUSPECT) {
					newf2 |= SUSPECT;
					newf1 &= ~V4_SUSPECT;
				}
			}
		case 6:
			switch (newf1 & TYPE_MASK) {
			case TYPE_PLAYER:
				if (newf1 & V6_BUILDER) {
					s_Powers(thing, Powers(thing) | POW_BUILDER);
					newf1 &= ~V6_BUILDER;
				}
				if (newf1 & V6_SUSPECT) {
					newf2 |= SUSPECT;
					newf1 &= ~V6_SUSPECT;
				}
				if (newf1 & V6PLYR_UNFIND) {
					newf2 |= UNFINDABLE;
					newf1 &= ~V6PLYR_UNFIND;
				}
				if (newf1 & V6_SLAVE) {
					newf2 |= SLAVE;
					newf1 &= ~V6_SLAVE;
				}
				break;
			case TYPE_ROOM:
				if (newf1 & V6_FLOATING) {
					newf2 |= FLOATING;
					newf1 &= ~V6_FLOATING;
				}
				if (newf1 & V6_ABODE) {
					newf2 |= ABODE;
					newf1 &= ~V6_ABODE;
				}
				if (newf1 & V6ROOM_JUMPOK) {
					newf1 |= JUMP_OK;
					newf1 &= ~V6ROOM_JUMPOK;
				}
				if (newf1 & V6ROOM_UNFIND) {
					newf2 |= UNFINDABLE;
					newf1 &= ~V6ROOM_UNFIND;
				}
				break;
			case TYPE_THING:
				if (newf1 & V6OBJ_KEY) {
					newf2 |= KEY;
					newf1 &= ~V6OBJ_KEY;
				}
				break;
			case TYPE_EXIT:
				if (newf1 & V6EXIT_KEY) {
					newf2 |= KEY;
					newf1 &= ~V6EXIT_KEY;
				}
				break;
			}
		}

		/* Then we have to do the 2.2 to 3.0 flag conversion */

		if (newf1 & ROYALTY) {
		    newf1 &= ~ROYALTY;
		    newf2 |= CONTROL_OK;
		}
		if (newf2 & HAS_COMMANDS) {
		    newf2 &= ~HAS_COMMANDS;
		    newf2 |= NOBLEED;
		}
		if (newf2 & AUDITORIUM) {
		    newf2 &= ~AUDITORIUM;
		    newf2 |= ZONE_PARENT;
		}
		if (newf2 & ANSI) {
		    newf2 &= ~ANSI;
		    newf2 |= STOP_MATCH;
		}
		if (newf2 & HEAD_FLAG) {
		    newf2 &= ~HEAD_FLAG;
		    newf2 |= HAS_COMMANDS;
		}
		if (newf2 & FIXED) {
		    newf2 &= ~FIXED;
		    newf2 |= BOUNCE;
		}
		if (newf2 & STAFF) {
		    newf2 &= STAFF;
		    newf2 |= HTML;
		}
		if (newf2 & HAS_DAILY) {
		    newf2 &= ~HAS_DAILY;
		    /* This is the unimplemented TICKLER flag. */
		}
		if (newf2 & GAGGED) {
		    newf2 &= ~GAGGED;
		    newf2 |= ANSI;
		}
		if (newf2 & COMPRESS) {
		    newf2 &= ~COMPRESS;
		    s_Powers(thing, Powers(thing) | POW_BUILDER);
		}
	} else if (db_format == F_MUX) {

	    /* TinyMUX to 3.0 flag conversion */

	    newf1 = f1;
	    newf2 = f2;
	    newf3 = f3;

	    if (newf2 & ZONE_PARENT) {
		/* This used to be an object set NO_COMMAND. We unset the
		 * flag.
		 */
		newf2 &= ~ZONE_PARENT;
	    } else {
		/* And if it wasn't NO_COMMAND, then it should be COMMANDS. */
		newf2 |= HAS_COMMANDS;
	    }

	} else if (db_format == F_TINYMUSH) {
		newf1 = f1;
		newf2 = f2;
		newf3 = f3;
	}
	*flags1 = newf1;
	*flags2 = newf2;
	*flags3 = newf3;
	return;
}


/* ---------------------------------------------------------------------------
 * efo_convert: Fix things up for Exits-From-Objects
 */

void NDECL(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;
		}
	}
}

/* ---------------------------------------------------------------------------
 * fix_mux_zones: Convert MUX-style zones to 3.0-style zones.
 */

#ifdef STANDALONE
static void fix_mux_zones()
{
    /* For all objects in the database where Zone(thing) != NOTHING,
     * set the CONTROL_OK flag on them.
     *
     * For all objects in the database that are ZMOs (that have other
     * objects zoned to them), copy the EnterLock of those objects to
     * the ControlLock.
     */

    int i;
    int *zmarks;
    char *astr;

    zmarks = (int *) calloc(mudstate.db_top, sizeof(int));

    DO_WHOLE_DB(i) {
	if (Zone(i) != NOTHING) {
	    s_Flags2(i, Flags2(i) | CONTROL_OK);
	    zmarks[Zone(i)] = 1;
	}
    }

    DO_WHOLE_DB(i) {
	if (zmarks[i]) {
	    astr = atr_get_raw(i, A_LENTER);
	    if (astr) {
		atr_add_raw(i, A_LCONTROL, astr);
	    }
	}
    }

    free(zmarks);
}
#endif /* STANDALONE */

/* ---------------------------------------------------------------------------
 * fix_typed_quotas: Explode standard quotas into typed quotas
 */

#ifdef STANDALONE
static void fix_typed_quotas()
{
	/* If we have a pre-2.2 or MUX database, only the QUOTA and RQUOTA
	 * attributes  exist. For simplicity's sake, we assume that players
	 * will have the  same quotas for all types, equal to the current
	 * value. This is  going to produce incorrect values for RQUOTA;
	 * this is easily fixed  by a @quota/fix done from within-game. 
	 *
	 * If we have a early beta 2.2 release, we have quotas which are
	 * spread out over ten attributes. We're going to have to grab
	 * those, make the new quotas, and then delete the old attributes.
	 */

	int i;
	char *qbuf, *rqbuf;

#ifdef BETA_QUOTAS
	char *roombuf, *r_roombuf, *exitbuf, *r_exitbuf, *tbuf, *r_tbuf,
	*pbuf, *r_pbuf;

#endif

	DO_WHOLE_DB(i) {
		if (isPlayer(i)) {
			qbuf = atr_get_raw(i, A_QUOTA);
			rqbuf = atr_get_raw(i, A_RQUOTA);
			if (!qbuf || !*qbuf)
				qbuf = (char *)"1";
			if (!rqbuf || !*rqbuf)
				rqbuf = (char *)"0";
#ifdef BETA_QUOTAS
			roombuf = atr_get_raw(i, A_QUOTAROOM);
			r_roombuf = atr_get_raw(i, A_RQUOTAROOM);
			exitbuf = atr_get_raw(i, A_QUOTAEXIT);
			r_exitbuf = atr_get_raw(i, A_RQUOTAEXIT);
			tbuf = atr_get_raw(i, A_QUOTATHING);
			r_tbuf = atr_get_raw(i, A_RQUOTATHING);
			pbuf = atr_get_raw(i, A_QUOTAPLAYER);
			r_pbuf = atr_get_raw(i, A_RQUOTAPLAYER);
			atr_add_raw(i, A_QUOTA,
				    tprintf("%s %s %s %s %s", qbuf,
				     (roombuf && *roombuf) ? roombuf : qbuf,
				     (exitbuf && *exitbuf) ? exitbuf : qbuf,
					    (tbuf && *tbuf) ? tbuf : qbuf,
					    (pbuf && *pbuf) ? pbuf : qbuf));
			atr_add_raw(i, A_RQUOTA,
				    tprintf("%s %s %s %s %s", rqbuf,
			      (r_roombuf && *r_roombuf) ? r_roombuf : rqbuf,
			      (r_exitbuf && *r_exitbuf) ? r_exitbuf : rqbuf,
				       (r_tbuf && *r_tbuf) ? r_tbuf : rqbuf,
				     (r_pbuf && *r_pbuf) ? r_pbuf : rqbuf));
			atr_add_raw(i, A_QUOTAROOM, NULL);
			atr_add_raw(i, A_RQUOTAROOM, NULL);
			atr_add_raw(i, A_QUOTAEXIT, NULL);
			atr_add_raw(i, A_RQUOTAEXIT, NULL);
			atr_add_raw(i, A_QUOTATHING, NULL);
			atr_add_raw(i, A_RQUOTATHING, NULL);
			atr_add_raw(i, A_QUOTAPLAYER, NULL);
			atr_add_raw(i, A_RQUOTAPLAYER, NULL);
#else /* else if no BETA_QUOTAS */
			atr_add_raw(i, A_QUOTA,
				    tprintf("%s %s %s %s %s",
					    qbuf, qbuf, qbuf, qbuf, qbuf));
			atr_add_raw(i, A_RQUOTA,
				    tprintf("%s %s %s %s %s",
					rqbuf, rqbuf, rqbuf, rqbuf, rqbuf));
#endif /* BETA_QUOTAS */
		}
	}
}

#endif /* STANDALONE */


/* ---------------------------------------------------------------------------
 * unscraw_foreign: Fix up strange object linking conventions for other formats
 */

void unscraw_foreign(db_format, db_version, db_flags)
int db_format, db_version, db_flags;
{
	dbref tmp, i, aowner;
	int aflags, alen;
	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, &alen);
				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 <= 5) && (db_flags & V_GDBM)) {

			/* Check for FORWARDLIST attribute */

			DO_WHOLE_DB(i) {
				if (atr_get_raw(i, A_FORWARDLIST))
					s_Flags2(i, Flags2(i) | HAS_FWDLIST);
			}
		}
		if (db_version <= 6) {
			DO_WHOLE_DB(i) {

				/* Make sure A_QUEUEMAX is empty */

				atr_clr(i, A_QUEUEMAX);

				if (db_flags & V_GDBM) {

					/* HAS_LISTEN now tracks LISTEN attr */

					if (atr_get_raw(i, A_LISTEN))
						s_Flags2(i, Flags2(i) | HAS_LISTEN);

					/* Undo V6 overloading of HAS_STARTUP
					 * with HAS_FWDLIST 
					 */

					if ((db_version == 6) &&
					    (Flags2(i) & HAS_STARTUP) &&
					    atr_get_raw(i, A_FORWARDLIST)) {

						/* We have FORWARDLIST */

						s_Flags2(i, Flags2(i) | HAS_FWDLIST);

						/* Maybe no STARTUP */

						if (!atr_get_raw(i, A_STARTUP))
							s_Flags2(i, Flags2(i) & ~HAS_STARTUP);
					}
				}
			}
		}
		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(f, i, set)
FILE *f;
dbref i;
int set;
{
	int count;

	count = getref(f);
	for (count--; count >= 0; count--) {
		if (set)
			s_Parent(i, getref(f));
		else
			(void)getref(f);
	}
}

static void get_atrdefs_discard(f)
FILE *f;
{
	const char *sp;

	for (;;) {
		sp = getstring_noalloc(f, 0);	/* flags or endmarker */
		if (*sp == '\\')
			return;
		sp = getstring_noalloc(f, 0);	/* object */
		sp = getstring_noalloc(f, 0);	/* name */
	}
}

static void getpenn_new_locks(f, i)
    FILE *f;
    dbref i;
{
	int c;
	char *buf, *p;
	struct boolexp *tempbool;

	buf = alloc_lbuf("getpenn_new_locks");
	p = buf;
	while (c = getc(f), (c != EOF) && (c != '|'))
		*p++ = c;

	*p = '\0';
	
	tempbool = getboolexp(f);
	
	if (tempbool == TRUE_BOOLEXP)
		return;
		
	if (!strcmp(buf, "Basic"))
		atr_add_raw(i, A_LOCK,
			    unparse_boolexp_quiet(1, tempbool));
	else if (!strcmp(buf, "Use"))
		atr_add_raw(i, A_LUSE,
			    unparse_boolexp_quiet(1, tempbool));
	else if (!strcmp(buf, "Enter"))
		atr_add_raw(i, A_LENTER,
			    unparse_boolexp_quiet(1, tempbool));
	else if (!strcmp(buf, "Page"))
		atr_add_raw(i, A_LPAGE,
			    unparse_boolexp_quiet(1, tempbool));
	else if (!strcmp(buf, "Teleport"))
		atr_add_raw(i, A_LTPORT,
			    unparse_boolexp_quiet(1, tempbool));
	else if (!strcmp(buf, "Speech"))
		atr_add_raw(i, A_LSPEECH,
			    unparse_boolexp_quiet(1, tempbool));
	else if (!strcmp(buf, "Parent"))
		atr_add_raw(i, A_LPARENT,
			    unparse_boolexp_quiet(1, tempbool));
	else if (!strcmp(buf, "Link"))
		atr_add_raw(i, A_LLINK,
			    unparse_boolexp_quiet(1, tempbool));
	else if (!strcmp(buf, "Leave"))
		atr_add_raw(i, A_LLEAVE,
			    unparse_boolexp_quiet(1, tempbool));
	else if (!strcmp(buf, "Drop"))
		atr_add_raw(i, A_LDROP,
			    unparse_boolexp_quiet(1, tempbool));
	else if (!strcmp(buf, "Give"))
		atr_add_raw(i, A_LGIVE,
			    unparse_boolexp_quiet(1, tempbool));
	free_lbuf(buf);
}
#endif 

dbref db_read(f, db_format, db_version, db_flags)
FILE *f;
int *db_format, *db_version, *db_flags;
{
	dbref i, anum;
	char ch;
	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_extflags, read_3flags, read_money, read_timestamps, read_new_strings;
#ifdef STANDALONE
	int is_penn, read_pern_key, read_pern_comm, read_pern_parent;
	int read_pern_warnings, read_pern_creation, read_pern_powers;
	int read_pern_new_locks, is_dark;
	int read_dark_comm, read_dark_slock, read_dark_mc, read_dark_mpar;
	int read_dark_class, read_dark_rank, read_dark_droplock;
	int read_dark_givelock, read_dark_getlock;
	int read_dark_threepow, penn_version;
	int read_muse_parents, read_muse_atrdefs;
	char peek;
#endif
	int read_powers, read_powers_player, read_powers_any;
	int has_typed_quotas;
	int deduce_version, deduce_name, deduce_zone, deduce_timestamps;
	int aflags, f1, f2, f3;
	BOOLEXP *tempbool;
#ifndef NO_TIMECHECKING
	struct timeval obj_time;
#endif

	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_money = 1;
	read_extflags = 0;
	read_3flags = 0;
	has_typed_quotas = 0;
	read_timestamps = 0;
	read_new_strings = 0;
	read_powers = 0;
	read_powers_player = 0;
	read_powers_any = 0;
	deduce_version = 1;
	deduce_zone = 1;
	deduce_name = 1;
	deduce_timestamps = 1;
#ifdef STANDALONE
	is_penn = 0;
	is_dark = 0;
	read_pern_key = 0;
	read_pern_comm = 0;
	read_pern_parent = 0;
	read_pern_warnings = 0;
	read_pern_creation = 0;
	read_pern_powers = 0;
	read_pern_new_locks = 0;
	read_dark_comm = 0;
	read_dark_slock = 0;
	read_dark_mc = 0;
	read_dark_mpar = 0;
	read_dark_class = 0;
	read_dark_rank = 0;
	read_dark_droplock = 0;
	read_dark_givelock = 0;
	read_dark_getlock = 0;
	read_dark_threepow = 0;
	penn_version = 0;
	read_muse_parents = 0;
	read_muse_atrdefs = 0;

	fprintf(stderr, "Reading ");
	fflush(stderr);
#endif
	db_free();
	for (i = 0;; i++) {

#ifndef MEMORY_BASED
		if (!(i % 25)) {
			cache_reset(0);
		}
#endif /* MEMORY_BASED */
#ifdef STANDALONE
		if (!(i % 100)) {
			fputc('.', stderr);
			fflush(stderr);
		}
#endif

		switch (ch = getc(f)) {
		case '-':	/* Misc tag */
			switch (ch = getc(f)) {	
			case 'R':	/* Record number of players */
				mudstate.record_players = getref(f);
				break;
			default:
				(void)getstring_noalloc(f, 0);
			}
			break;
#ifdef STANDALONE
		case '~':	/* Database size tag */
			is_penn = 1;
			if (!is_dark && penn_version) {
				g_format = F_MUSH;
				g_version = (((penn_version - 2) / 256) - 5);
				/* Okay, let's try and unscraw version
				 * encoding method they use in later Penn 
				 * 1.50. 
				 */

				/* Handle Pern veriants specially */

				if (g_version & 0x20)
					read_new_strings = 1;

				if (g_version & 0x10)
					read_pern_new_locks = 1;

				if (!(g_version & 0x08))
					read_pern_powers = 1;

				if (g_version & 0x04)
					read_pern_creation = 1;

				if (g_version & 0x02)
					read_pern_warnings = 1;

				if (!(g_version & 0x01))
					read_pern_comm = 1;

				g_version = 2;
			}
			if (size_gotten) {
				fprintf(stderr,
					"\nDuplicate size entry at object %d, ignored.\n",
					i);
				tstr = getstring_noalloc(f, 0);	/* junk */
				break;
			}
			mudstate.min_size = getref(f);
			size_gotten = 1;
			break;
#endif
		case '+':	/* MUX and MUSH header */

		    ch = getc(f); /* 2nd char selects type */

		    if ((ch == 'V') || (ch == 'X') || (ch == 'T')) {

			/* The following things are common across 2.x, MUX,
			 * and 3.0.
			 */
		        
			 if (header_gotten) {
			     fprintf(stderr,
				     "\nDuplicate MUSH version header entry at object %d, ignored.\n",
				     i);
			     tstr = getstring_noalloc(f, 0);
			     break;
			 }
			 header_gotten = 1;
			 deduce_version = 0;
			 g_version = getref(f);
			 
			 /* 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);
			 read_money = !(g_version & V_ATRMONEY);
			 read_extflags = (g_version & V_XFLAGS);
			 has_typed_quotas = (g_version & V_TQUOTAS);
			 g_flags = g_version & ~V_MASK;

			 deduce_name = 0;
			 deduce_version = 0;
			 deduce_zone = 0;
		    }

		    /* More generic switch. */

		    switch (ch) {
			case 'T':	/* 3.0 VERSION */
			    g_format = F_TINYMUSH;
			    read_3flags = (g_version & V_3FLAGS);
			    read_powers = (g_version & V_POWERS);
			    read_new_strings = (g_version & V_QUOTED);
			    g_version &= V_MASK;
			    break;

#ifdef STANDALONE
			case 'V':	/* 2.0 VERSION */
			    g_format = F_MUSH;
			    penn_version = g_version;
			    g_version &= V_MASK;
			    break;

			case 'X':	/* MUX VERSION */
			    g_format = F_MUX;
			    read_3flags = (g_version & V_3FLAGS);
			    read_powers = (g_version & V_POWERS);
			    read_new_strings = (g_version & V_QUOTED);
			    g_version &= V_MASK;
			    break;

			case 'K':	/* Kalkin's DarkZone dist */
				/* Him and his #defines... */
				if (header_gotten) {
					fprintf(stderr,
						"\nDuplicate MUSH version header entry at object %d, ignored.\n",
						i);
					tstr = getstring_noalloc(f, 0);
					break;
				}
				header_gotten = 1;
				deduce_version = 0;
				g_format = F_MUSH;
				g_version = getref(f);
				is_dark = 1;
				is_penn = 1;

				read_pern_powers = 1;
				if (g_version & DB_CHANNELS)
					read_dark_comm = 1;
				if (g_version & DB_SLOCK)
					read_dark_slock = 1;
				if (g_version & DB_MC)
					read_dark_mc = 1;
				if (g_version & DB_MPAR)
					read_dark_mpar = 1;
				if (g_version & DB_CLASS)
					read_dark_class = 1;
				if (g_version & DB_RANK)
					read_dark_rank = 1;
				if (g_version & DB_DROPLOCK)
					read_dark_droplock = 1;
				if (g_version & DB_GIVELOCK)
					read_dark_givelock = 1;
				if (g_version & DB_GETLOCK)
					read_dark_getlock = 1;
				if (g_version & DB_THREEPOW)
					read_dark_threepow = 1;
				g_version = 2;
				break;
#endif /* STANDALONE */
			case 'S':	/* SIZE */
				if (size_gotten) {
					fprintf(stderr,
						"\nDuplicate size entry at object %d, ignored.\n",
						i);
					tstr = getstring_noalloc(f, 0);
				} else {
					mudstate.min_size = getref(f);
				}
				size_gotten = 1;
				break;
			case 'A':	/* USER-NAMED ATTRIBUTE */
				anum = getref(f);
				tstr = getstring_noalloc(f, read_new_strings);
				if (isdigit(*tstr)) {
					aflags = 0;
					while (isdigit(*tstr))
						aflags = (aflags * 10) +
							(*tstr++ - '0');
					tstr++;		/* skip ':' */
				} else {
					aflags = mudconf.vattr_flags;
				}
				vattr_define((char *)tstr, anum, aflags);
				break;
			case 'F':	/* OPEN USER ATTRIBUTE SLOT */
				anum = getref(f);
				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, 0);
				} 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, 0);
			}
			break;
#ifdef STANDALONE
		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_money = (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, (char *)getstring_noalloc(f, 0));
			atr_add_raw(i, A_DESC, (char *)getstring_noalloc(f, 0));
			s_Location(i, getref(f));
			s_Contents(i, getref(f));
			s_Exits(i, getref(f));
			s_Link(i, NOTHING);
			s_Next(i, getref(f));
#ifndef NO_TIMECHECKING
			obj_time.tv_sec = obj_time.tv_usec = 0;
			s_Time_Used(i, obj_time);
#endif
			s_StackCount(i, 0);
			s_VarsCount(i, 0);
			s_StructCount(i, 0);
			s_InstanceCount(i, 0);
/* 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, 0));
			atr_add_raw(i, A_SUCC, (char *)getstring_noalloc(f, 0));
			atr_add_raw(i, A_OFAIL, (char *)getstring_noalloc(f, 0));
			atr_add_raw(i, A_OSUCC, (char *)getstring_noalloc(f, 0));
			s_Owner(i, getref(f));
			s_Parent(i, NOTHING);
			s_Pennies(i, getref(f));
			f1 = getref(f);
			f2 = 0;
			f3 = 0;
			upgrade_flags(&f1, &f2, &f3, i, g_format, g_version);
			s_Flags(i, f1);
			s_Flags2(i, f2);
			s_Flags3(i, f3);
			s_Pass(i, getstring_noalloc(f, 0));
			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;
			}
#endif
		case '!':	/* MUX entry/MUSH entry/MUSE non-zoned entry */
			if (deduce_version) {
				g_format = F_TINYMUSH;
				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);

#ifndef NO_TIMECHECKING
			obj_time.tv_sec = obj_time.tv_usec = 0;
			s_Time_Used(i, obj_time);
#endif
			s_StackCount(i, 0);
			s_VarsCount(i, 0);
			s_StructCount(i, 0);
			s_InstanceCount(i, 0);

#ifdef STANDALONE
			if (is_penn) {
				tstr = getstring_noalloc(f, read_new_strings);
				s_Name(i, (char *)tstr);
				s_Location(i, getref(f));
				s_Contents(i, getref(f));
				s_Exits(i, getref(f));
				s_Next(i, getref(f));
				/* have no equivalent to multi-parents yet,
				 * so we have to throw
				 * them away... 
				 */

				if (read_dark_mpar) {
					/* Parents */
					getlist_discard(f, i, 1);
					/* Children */
					getlist_discard(f, i, 0);
				} else {
					s_Parent(i, getref(f));
				}

				if (read_pern_new_locks) {
					while ((ch = getc(f)) == '_')
						getpenn_new_locks(f, i);
					ungetc(ch, f);
				} else {
					tempbool = getboolexp(f);
					atr_add_raw(i, A_LOCK,
					unparse_boolexp_quiet(1, tempbool));
					free_boolexp(tempbool);
					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);
				}

				if (read_dark_slock)
					(void)getref(f);

				if (read_dark_droplock)
					(void)getref(f);

				if (read_dark_givelock)
					(void)getref(f);

				if (read_dark_getlock)
					(void)getref(f);

				s_Owner(i, getref(f));
				s_Zone(i, getref(f));
				s_Pennies(i, getref(f));
				f1 = getref(f);
				f2 = getref(f);
				f3 = 0;
				upgrade_flags(&f1, &f2, &f3, i, F_MUSH, 2);

				s_Flags(i, f1);
				s_Flags2(i, f2);
				s_Flags3(i, f3);

				if (read_pern_powers)
					(void)getref(f);

				/* Kalkin's extra two powers words... */
				if (read_dark_threepow) {
					(void)getref(f);
					(void)getref(f);
				}
				/* Kalkin's @class */
				if (read_dark_class)
					(void)getref(f);

				/* Kalkin put his creation times BEFORE
				 * channels unlike standard Penn... 
				 */

				if (read_dark_mc) {
					(void)getref(f);
					(void)getref(f);
				}
				if (read_pern_comm || read_dark_comm)
					(void)getref(f);

				if (read_pern_warnings)
					(void)getref(f);

				if (read_pern_creation) {
					(void)getref(f);
					(void)getref(f);
				}
				/* In Penn, clear the player's parent. */
				if (isPlayer(i)) {
					s_Parent(i, NOTHING);
				}
				if (!get_list(f, i, read_new_strings)) {
					fprintf(stderr,
						"\nError reading attrs for object #%d\n",
						i);
					return -1;
				}
			} else {
#endif
				if (read_name) {
					tstr = getstring_noalloc(f, read_new_strings);
					if (deduce_name) {
						if (isdigit(*tstr)) {
							read_name = 0;
							s_Location(i, atoi(tstr));
						} else {
							s_Name(i, (char *)tstr);
							s_Location(i, getref(f));
						}
						deduce_name = 0;
					} else {
						s_Name(i, (char *)tstr);
						s_Location(i, getref(f));
					}
				} else {
					s_Location(i, getref(f));
				}

				/* ZONE on MUSE databases and some others */

				if (read_zone)
					s_Zone(i, getref(f));
/* else s_Zone(i, NOTHING); */

				/* CONTENTS and EXITS */

				s_Contents(i, getref(f));
				s_Exits(i, getref(f));

				/* LINK */

				if (read_link)
					s_Link(i, getref(f));
				else
					s_Link(i, NOTHING);

				/* NEXT */

				s_Next(i, getref(f));

				/* LOCK */

				if (read_key) {
					tempbool = getboolexp(f);
					atr_add_raw(i, A_LOCK,
					unparse_boolexp_quiet(1, tempbool));
					free_boolexp(tempbool);
				}
				/* OWNER */

				s_Owner(i, getref(f));

				/* PARENT: PennMUSH uses this field for ZONE
				 * (which we  use as PARENT if we
				 * didn't already read in a  
				 * non-NOTHING parent. 
				 */

				if (read_parent) {
					s_Parent(i, getref(f));
				} else {
					s_Parent(i, NOTHING);
				}

				/* PENNIES */

				if (read_money)		/* if not fix in
							 * unscraw_foreign  
							 */
					s_Pennies(i, getref(f));

				/* FLAGS */

				f1 = getref(f);
				if (read_extflags)
					f2 = getref(f);
				else
					f2 = 0;
				
				if (read_3flags)
					f3 = getref(f);
				else
					f3 = 0;

#ifdef STANDALONE					
				upgrade_flags(&f1, &f2, &f3, i, g_format, g_version);
#endif
				s_Flags(i, f1);
				s_Flags2(i, f2);
				s_Flags3(i, f3);


#ifdef STANDALONE
				/* POWERS from MUSE.  Discard. */

				if (read_powers_any ||
				    ((Typeof(i) == TYPE_PLAYER) && read_powers_player))
					(void)getstring_noalloc(f, 0);
#endif

				if (read_powers) {
					f1 = getref(f);
					f2 = getref(f);
					s_Powers(i, f1);
					s_Powers2(i, f2);
				}
				
				/* ATTRIBUTES */

				if (read_attribs) {
					if (!get_list(f, i, read_new_strings)) {
						fprintf(stderr,
							"\nError reading attrs for object #%d\n",
							i);
						return -1;
					}
				}

#ifdef STANDALONE
				/* PARENTS from MUSE.  Ewwww. */

				if (read_muse_parents) {
					getlist_discard(f, i, 1);
					getlist_discard(f, i, 0);
				}
				/* ATTRIBUTE DEFINITIONS from MUSE.  Ewwww.
				 * Ewwww. 
				 */

				if (read_muse_atrdefs) {
					get_atrdefs_discard(f);
				}

#endif
				/* check to see if it's a player */

				if (Typeof(i) == TYPE_PLAYER) {
					c_Connected(i);
				}
#ifdef STANDALONE
			}
#endif
			break;
		case '*':	/* EOF marker */
			tstr = getstring_noalloc(f, 0);
			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 */

#ifdef STANDALONE
				unscraw_foreign(g_format, g_version, g_flags);
#endif
				*db_version = g_version;
				*db_format = g_format;
				*db_flags = g_flags;
#ifndef STANDALONE
				load_player_names();
#endif
#ifdef STANDALONE				
				if (!has_typed_quotas)
					fix_typed_quotas();
				if (g_format == F_MUX)
					fix_mux_zones();
#endif
				return mudstate.db_top;
			}
		default:
			fprintf(stderr, "\nIllegal character '%c' near object #%d\n",
				ch, i);
			return -1;
		}


	}

}

static int db_write_object(f, i, db_format, flags)
FILE *f;
dbref i;
int db_format, flags;
{
#ifndef STANDALONE
	ATTR *a;

#endif
	char *got, *as;
	dbref aowner;
	int ca, aflags, alen, save, j;
	BOOLEXP *tempbool;

	if (!(flags & V_ATRNAME))
		putstring(f, Name(i));
	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, &alen);
		tempbool = parse_boolexp(GOD, got, 1);
		free_lbuf(got);
		putboolexp(f, tempbool);
		if (tempbool)
			free_boolexp(tempbool);
	}
	putref(f, Owner(i));
	if (flags & V_PARENT)
		putref(f, Parent(i));
	if (!(flags & V_ATRMONEY))
		putref(f, Pennies(i));
	putref(f, Flags(i));
	if (flags & V_XFLAGS)
		putref(f, Flags2(i));
	if (flags & V_3FLAGS)
		putref(f, Flags3(i));
	if (flags & V_POWERS) {
		putref(f, Powers(i));
		putref(f, Powers2(i));
	}
	/* write the attribute list */


#ifndef STANDALONE
	if ((!(flags & V_GDBM)) || (mudstate.panicking == 1)) {
#else
	if ((!(flags & V_GDBM))) {
#endif
		for (ca = atr_head(i, &as); ca; ca = atr_next(&as)) {
			save = 0;
#ifndef STANDALONE
			a = atr_num(ca);
			if (a)
				j = a->number;
			else
				j = -1;
#else
			j = ca;
#endif

			if (j > 0) {
				switch (j) {
				case A_NAME:
					if (flags & V_ATRNAME)
						save = 1;
					break;
				case A_LOCK:
					if (flags & V_ATRKEY)
						save = 1;
					break;
				case A_LIST:
				case A_MONEY:
					break;
				default:
					save = 1;
				}
			}
			if (save) {
				got = atr_get_raw(i, j);
				fprintf(f, ">%d\n", j);
				putstring(f, got);
			}
		}
		fprintf(f, "<\n");
	}
	return 0;
}

dbref db_write(f, format, version)
FILE *f;
int format, version;
{
	dbref i;
	int flags;
	VATTR *vp;

#ifndef MEMORY_BASED
	al_store();
#endif /* MEMORY_BASED */

	switch (format) {
	case F_TINYMUSH:
		flags = version;
		break;
	default:
		fprintf(stderr, "Can only write TinyMUSH 3 format.\n");
		return -1;
	}
#ifdef STANDALONE
	fprintf(stderr, "Writing ");
	fflush(stderr);
#endif
	i = mudstate.attr_next;
	/* TinyMUSH 2 wrote '+V', MUX wrote '+X', 3.0 writes '+T'. */
	fprintf(f, "+T%d\n+S%d\n+N%d\n", flags, mudstate.db_top, i);
	fprintf(f, "-R%d\n", mudstate.record_players);
	
	/* Dump user-named attribute info */

	vp = vattr_first();
	while (vp != NULL) {
		if (!(vp->flags & AF_DELETED))
			fprintf(f, "+A%d\n\"%d:%s\"\n",
				vp->number, vp->flags, vp->name);
		vp = vattr_next(vp);
	}

	DO_WHOLE_DB(i) {
#ifndef MEMORY_BASED
		if (!(i % 25)) {
			cache_reset(0);
		}
#endif /* MEMORY_BASED */

#ifdef STANDALONE
		if (!(i % 100)) {
			fputc('.', stderr);
			fflush(stderr);
		}
#endif

		if (!(Going(i))) {
			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);
}