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