btmux/autom4te.cache/
btmux/doc/.svn/
btmux/event/.svn/
btmux/game/.svn/
btmux/game/bin/.svn/
btmux/game/data/.svn/
btmux/game/logs/.svn/
btmux/game/maps/
btmux/game/maps/.svn/
btmux/game/maps/.svn/prop-base/
btmux/game/maps/.svn/props/
btmux/game/maps/.svn/text-base/
btmux/game/maps/.svn/wcprops/
btmux/game/mechs/
btmux/game/mechs/.svn/
btmux/game/mechs/.svn/prop-base/
btmux/game/mechs/.svn/props/
btmux/game/mechs/.svn/text-base/
btmux/game/mechs/.svn/wcprops/
btmux/game/text/.svn/
btmux/include/.svn/
btmux/misc/
btmux/misc/.svn/
btmux/misc/.svn/prop-base/
btmux/misc/.svn/props/
btmux/misc/.svn/text-base/
btmux/misc/.svn/wcprops/
btmux/python/
btmux/python/.svn/
btmux/python/.svn/prop-base/
btmux/python/.svn/props/
btmux/python/.svn/text-base/
btmux/python/.svn/wcprops/
btmux/src/.svn/prop-base/
btmux/src/.svn/props/
btmux/src/.svn/text-base/
btmux/src/.svn/wcprops/
btmux/src/hcode/.svn/
btmux/src/hcode/btech/
btmux/src/hcode/btech/.svn/
btmux/src/hcode/btech/.svn/prop-base/
btmux/src/hcode/btech/.svn/props/
btmux/src/hcode/btech/.svn/text-base/
btmux/src/hcode/btech/.svn/wcprops/
btmux/src/hcode/include/.svn/
/*
 * db_rw.c 
 */

/*
 * $Id: db_rw.c,v 1.4 2005/08/08 09:43:06 murrayma Exp $ 
 */

#include "copyright.h"
#include "config.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 *getstring_noalloc(FILE *, int);
extern void putstring(FILE *, const char *);
extern void 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.
 */

static BOOLEXP *getboolexp1(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:
            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;
            break;
        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:
    abort();			/*
                         * bomb out 
                         */
    return TRUE_BOOLEXP;
}

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

static BOOLEXP *getboolexp(FILE *f) {
    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)
            || (g_format == F_MUX)) {
        if ((c = getc(f)) != '\n')
            ungetc(c, f);
    }
    return b;
}

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

static int get_list(FILE *f, dbref i, int new_strings) {
    dbref atr;
    int c;
    char *buff;

    buff = alloc_lbuf("get_list");
    while (1) {
        switch (c = getc(f)) {
            case '>':		/*
                             * read # then string 
                             */
                atr = getref(f);
                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;
            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);
        }
    }
}

/*
 * ---------------------------------------------------------------------------
 * * putbool_subexp: Write a boolean sub-expression to the flat file.
 */
static void putbool_subexp(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.
 */

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


dbref db_read(FILE *f, int *db_format, int *db_version, int *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;
    int read_powers, read_powers_player, read_powers_any;
    int deduce_version, deduce_name, deduce_zone, deduce_timestamps;
    int aflags, f1, f2, f3;
    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_money = 1;
    read_extflags = 0;
    read_3flags = 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;
    db_free();
    for (i = 0;; i++) {

        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;
            case '+':		/*
                             * MUX and MUSH header 
                             */
                switch (ch = getc(f)) {	/*
                                         * 2nd char selects 
                                         * type 
                                         */
                    case 'X':		/*
                                     * MUX VERSION 
                                     */
                        if (header_gotten) {
                            fprintf(stderr,
                                    "\nDuplicate MUX version header entry at object %d, ignored.\n",
                                    i);
                            tstr = getstring_noalloc(f, 0);
                            break;
                        }
                        header_gotten = 1;
                        deduce_version = 0;
                        g_format = F_MUX;
                        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);
                        read_3flags = (g_version & V_3FLAGS);
                        read_powers = (g_version & V_POWERS);
                        read_new_strings = (g_version & V_QUOTED);
                        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, 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 MUX header near object #%d, ignored.\n",
                                ch, i);
                        tstr = getstring_noalloc(f, 0);
                }
                break;
            case '!':		/*
                             * MUX entry/MUSH entry/MUSE non-zoned entry 
                             */
                if (deduce_version) {
                    g_format = F_MUX;
                    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, 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;

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



                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;
                    }
                }
                /*
                 * check to see if it's a player 
                 */

                if (Typeof(i) == TYPE_PLAYER) {
                    c_Connected(i);
                }
                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 {
                    /*
                     * Fix up bizarro foreign DBs 
                     */

                    *db_version = g_version;
                    *db_format = g_format;
                    *db_flags = g_flags;
                    load_player_names();
                    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, 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);
        tempbool = parse_boolexp(GOD, got, 1);
        free_lbuf(got);
        putboolexp(f, tempbool);
        if (tempbool)
            free_bool(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 
     */


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

            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(FILE *f, int format, int version) {
    dbref i;
    int flags;
    VATTR *vp;

    switch (format) {
        case F_MUX:
            flags = version;
            break;
        default:
            fprintf(stderr, "Can only write MUX format.\n");
            return -1;
    }
    i = mudstate.attr_next;
    fprintf(f, "+X%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) {

        if (!(Going(i))) {
            fprintf(f, "!%d\n", i);
            db_write_object(f, i, format, flags);
        }
    }
    fputs("***END OF DUMP***\n", f);
    fflush(f);
    return (mudstate.db_top);
}