tmuck2.4/
tmuck2.4/admin/scripts/
tmuck2.4/docs/
tmuck2.4/minimal-db/
tmuck2.4/minimal-db/data/
tmuck2.4/minimal-db/logs/
tmuck2.4/minimal-db/muf/
tmuck2.4/old/
tmuck2.4/src/
tmuck2.4/src/compile/
tmuck2.4/src/editor/
tmuck2.4/src/game/
tmuck2.4/src/interface/
tmuck2.4/src/scripts/
tmuck2.4/src/utilprogs/
/* Copyright (c) 1992 by David Moore and Ben Jackson.  All rights reserved. */
/* dump_db.c,v 2.12 1997/08/10 04:30:41 dmoore Exp */
#include "config.h"

#include <stdio.h>
#include <string.h>
#include <ctype.h>

#include "db.h"
#include "params.h"
#include "buffer.h"
#include "externs.h"

/* Return the dbref for the specified string #x (x >= 0), NOTHING,
   AMBIGUOUS, or HOME.  NOTHING if it isn't valid. */
/* NOTE:  for now, this returns for any dbref ( x < 0 or x >= 0).
   NOTHING only for invalid string. */
dbref parse_dbref(register const char *s)
{
    long x;
 
    if (!s) return NOTHING;

    x = atol(s);
    if (x != 0) return (dbref) x;

    /* atol was 0.  Check validity. */
    while (isspace(*s)) s++;

    if (*s == '0') return (dbref) 0;
    else return NOTHING;
}


void putref(FILE *f, const dbref ref)
{
    fprintf(f, "%ld\n", ref);
}


void putstring(FILE *f, const char *s)
{
    if (s) fputs(s, f);
    putc('\n', f);
}


/* This gives us one line of push back. */
static int use_last_string = 0;
static Buffer getstring_buf;

const char *getstring(FILE *f)
{
    int eof;

    if (use_last_string) {
	use_last_string = 0;
	return Buftext(&getstring_buf);
    } 

    return Bufgets(&getstring_buf, f, &eof);
}


void putbackstring(void)
{
    use_last_string = 1;
}


/* getref MUST use it's own buffer rather than calling getstring. */
dbref getref(FILE *f)
{
    Buffer buf;
    int eof;

    if (use_last_string) {
	use_last_string = 0;
        return (dbref) atol(Buftext(&getstring_buf));
    } 

    Bufgets(&buf, f, &eof);
    return (dbref) atol(Buftext(&buf));
}


/* tmuck2.3 dump format */
static int db_write_object(FILE *f, const dbref i)
{
    int  ndest, j;
    dbref *temp;

    /* unparse_long_flags: 1 -> dump format */
    putstring(f, unparse_long_flags(i, 1));
    putstring(f, GetName(i));
    putref(f, GetLoc(i));
    putref(f, GetOwner(i));
    putref(f, GetContents(i));
    putref(f, GetActions(i));
    putref(f, GetNext(i));

    ndest = GetNDest(i);
    temp = GetDest(i);
    putref(f, ndest);
    for (j = 0; j < ndest; j++, temp++)
	putref(f, *temp);

    putproperties(f, GetProps(i));

    return 0;
}


int db_write(const char *name)
{
    FILE *f;
    dbref i;

    f = fopen(name, "w");
    if (!f) return 0;

    fputs("***Firiss TinyMUCK 2.3 DUMP Format v1***\n", f);

    fprintf(f, "DB top: %ld\n", db_top);
    fprintf(f, "Growth: %d\n", 200);
    fprintf(f, "Properties: %ld\n", total_properties());
    fprintf(f, "Interned Strings: %ld\n", total_intern_strings());
    fprintf(f, "Hash Buckets: %ld\n", total_hash_entries());
    fprintf(f, "Boolexp Nodes: %ld\n", total_boolexp_nodes());
    fprintf(f, "Global environment: %ld\n", global_environment);
    fprintf(f, "Player start: %ld\n", player_start);
    fprintf(f, "Head player: %ld\n", head_player);

    if (feof(f) || ferror(f)) return 0;

    for (i = 0; i < db_top; i++) {
	if (Typeof(i) != TYPE_GARBAGE) {
	    fprintf(f, "#%ld\n", i);
	    db_write_object(f, i);
	    if (!(i % 100)) {
	        fflush(f);
		if (feof(f) || ferror(f)) return 0;
	    }
	}
    }

    fputs("***END OF DUMP***\n", f);
    fflush(f);
    if (feof(f) || ferror(f)) return 0;

    fclose(f);
    if (feof(f) || ferror(f)) return 0;

    return 1;
}

/* tmuck 2.3 db format */
static void db_read_object(FILE *f, const dbref objno)
{
    dbref *temp;
    int ndest, i;

    make_object_internal(objno, parse_flags(getstring(f)));

    SetName(objno, getstring(f));
    SetLoc(objno, getref(f));
    SetOwner(objno, getref(f));
    SetContents(objno, getref(f));
    SetActions(objno, getref(f));
    SetNext(objno, getref(f));

    ndest = getref(f);
    SetNDest(objno, ndest);
    if (ndest) {
	MALLOC(temp, dbref, ndest);
	SetDest(objno, temp);
	for (i = 0; i < ndest; i++, temp++)
	    *temp = getref(f);
    } else {
	SetDest(objno, NULL);
    }

    getproperties(objno, f);

    /* Not really needed if programs all have proper homes. */
    if (Typeof(objno) == TYPE_PROGRAM) SetLink(objno, GetOwner(objno));
}


static int db_read_header(FILE *f)
{
    dbref old_dbtop;
    int old_growth;
    long old_properties;
    long old_interned;
    long old_hash;
    long old_bool;
    const char *line;

    /* Pre init things. */
    old_dbtop = 10000;
    old_growth = 200;
    old_properties = 1;
    old_interned = 1;
    old_hash = 1;
    old_bool = 1;
    global_environment = 0;
    player_start = 0;
    head_player = 1;

    /* Loop checking all lines of header until we hit the first object. */
    while (1) {
        line = getstring(f);

	if (*line == '#') break;

	if (muck_strprefix(line, "DB top: ")) {
	    old_dbtop = parse_dbref(strchr(line, ':')+2);
            continue;
	}
	if (muck_strprefix(line, "Growth: ")) {
	    old_growth = atoi(strchr(line, ':')+2);
	    continue;
	}
	if (muck_strprefix(line, "Properties: ")) {
	    old_properties = atol(strchr(line, ':')+2);
	    continue;
	} 
	if (muck_strprefix(line, "Interned Strings: ")) {
	    old_interned = atol(strchr(line, ':')+2);
	    continue;
	} 
	if (muck_strprefix(line, "Hash Buckets: ")) {
	    old_hash = atol(strchr(line, ':')+2);
	    continue;
	}
	if (muck_strprefix(line, "Boolexp Nodes: ")) {
	    old_bool = atol(strchr(line, ':')+2);
	    continue;
	}
	if (muck_strprefix(line, "Global environment: "))  {
	    global_environment = parse_dbref(strchr(line, ':')+2);
	    continue;
	}
	if (muck_strprefix(line, "Player start: ")) {
	    player_start = parse_dbref(strchr(line, ':')+2);
	    continue;
	}
	if (muck_strprefix(line, "Head player: ")) {
	    head_player = parse_dbref(strchr(line, ':')+2);
	    continue;
	}

	/* Only get here if this header is unknown. */
	log_status("DB Header: ignoring unknown field: %s", line);
    }

    putbackstring();			/* last line was start of object. */

    init_hash_entries(old_hash);
    init_properties(old_properties);
    init_intern_strings(old_interned);
    init_db(old_dbtop, old_growth);

    return 1;
}

dbref db_read_firiss(FILE *f)
{
    dbref expect, objno, j;
    const char *line;

    if (!db_read_header(f)) {
	fprintf(stderr, "Problem in database header.\n");
	return NOTHING;
    }

    expect = 0;
    while (1) {
	line = getstring(f);
	switch (*line) {
	case '#':
	    objno = parse_dbref(line+1);
	    db_grow(objno+1);
	    if (expect != objno) {
		for (j = expect; j < objno; j++) {
		    make_object_internal(j, TYPE_GARBAGE);
		}
	    }
	    db_read_object(f, objno);
	    if (Typeof(objno) == TYPE_PLAYER) {
		add_player(objno);
	    }
	    expect = objno+1;	/* Get ready to read next one. */
	    break;
	case '*':
	    if (strcmp(line, "***END OF DUMP***")) {
		return NOTHING;
	    } else {
		return db_top;
	    }
	default:
	    return NOTHING;
	    /* break; */
	}
    }				
}				


dbref db_read(FILE *f)
{
    const char *header;
    dbref read_result;
    dbref i;

    db_FREE();

    header = getstring(f);
    if (strcmp(header, "***Firiss TinyMUCK 2.3 DUMP Format v1***")) {
	fprintf(stderr, "Unsupported db format.\n");
	return NOTHING;
    }

    read_result = db_read_firiss(f);
    if (read_result == NOTHING) return NOTHING;

    if (!sanity_check()) return NOTHING;

    /* Update ownership	lists for the whole db.  Loop backwards
       over the db so that the head insertion of the list will
       stick them in sorted order. */
    for (i = db_top-1; i >= 0 ; i--) {
	if (Garbage(i)) continue;

	chown_object(i, GetOwner(i));
    }

    /* Stick db warning's here. */

    return read_result;
}