/* dump.c: Routines to handle binary and text database dumps. */
#define _POSIX_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "x.tab.h"
#include "dump.h"
#include "cache.h"
#include "object.h"
#include "log.h"
#include "data.h"
#include "config.h"
#include "util.h"
#include "execute.h"
#include "grammar.h"
#include "db.h"
#include "ident.h"
static Method *text_dump_get_method(FILE *fp, Object *obj, char *name);
extern int cur_search;
/* Binary dump. This dump must not allocate any memory, since we may be
* performing it under low-memory conditions. */
int binary_dump(void)
{
cache_sync();
return 1;
}
/* Text dump. This dump can allocate memory, and thus shouldn't be used as a
* panic dump for low-memory situations. */
int text_dump(void)
{
FILE *fp;
Object *obj;
/* Open the output file. */
fp = open_scratch_file("textdump", "w");
if (!fp)
return 0;
/* Now dump the database. */
cur_search++;
for (obj = cache_first(); obj; obj = cache_next()) {
object_text_dump(obj->dbref, fp);
cache_discard(obj);
}
close_scratch_file(fp);
return 1;
}
void text_dump_read(FILE *fp)
{
String *line;
Object *obj = NULL;
List *parents;
Data d;
long dbref = -1, name;
char *p;
Method *method;
/* Initialize parents to an empty list. */
parents = list_new(0);
while ((line = fgetstring(fp))) {
if (!strnccmp(line->s, "parent", 6) && isspace(line->s[6])) {
for (p = line->s + 7; isspace(*p); p++);
/* Add this parent to the parents list. */
d.type = DBREF;
d.u.dbref = ident_get(p);
if (cache_check(d.u.dbref))
parents = list_add(parents, &d);
else
write_log("Invalid parent %s", ident_name(d.u.dbref));
ident_discard(d.u.dbref);
} else if (!strnccmp(line->s, "object", 6) && isspace(line->s[6])) {
for (p = line->s + 7; isspace(*p); p++);
/* If the parents list is empty, and this isn't "root", parent it
* to root. */
if (!parents->len && strcmp(p, "root") != 0) {
write_log("Orphan object %s parented to root", p);
if (!cache_check(root_id))
fail_to_start("Root object not first in text dump.");
d.type = DBREF;
d.u.dbref = root_id;
parents = list_add(parents, &d);
}
/* Get the dbref. */
dbref = ident_get(p);
/* Discard the old object if we had one. Also see if dbref already
* exists, and delete it if it does. */
if (obj)
cache_discard(obj);
obj = cache_retrieve(dbref);
if (obj) {
obj->dead = 1;
cache_discard(obj);
}
/* Create the new object. */
obj = object_new(dbref, parents);
list_discard(parents);
parents = list_new(0);
} else if (!strnccmp(line->s, "var", 3) && isspace(line->s[3])) {
for (p = line->s + 4; isspace(*p); p++);
/* Get variable owner. */
dbref = parse_ident(&p);
/* Skip spaces and get variable name. */
while (isspace(*p))
p++;
name = parse_ident(&p);
/* Skip spaces and get variable value. */
while (isspace(*p))
p++;
data_from_literal(&d, p);
/* Create the variable. */
object_put_var(obj, dbref, name, &d);
ident_discard(dbref);
ident_discard(name);
data_discard(&d);
} else if (!strccmp(line->s, "eval")) {
method = text_dump_get_method(fp, obj, "<eval>");
if (method) {
task_eval(NULL, obj, method);
method_discard(method);
}
} else if (!strnccmp(line->s, "method", 6) && isspace(line->s[6])) {
for (p = line->s + 7; *p == ' '; p++);
method = text_dump_get_method(fp, obj, p);
if (method) {
name = ident_get(p);
object_add_method(obj, name, method);
method_discard(method);
ident_discard(name);
}
}
string_discard(line);
}
if (obj)
cache_discard(obj);
list_discard(parents);
}
static Method *text_dump_get_method(FILE *fp, Object *obj, char *name)
{
Method *method;
List *code, *errors;
String *line;
Data d;
int i;
code = list_new(0);
d.type = STRING;
while ((line = fgetstring(fp))) {
if (line->len == 1 && *line->s == '.') {
/* End of the code. Compile the method, display any error
* messages we may have received, and return the method. */
string_discard(line);
method = compile(obj, code->el, code->len, &errors);
list_discard(code);
for (i = 0; i < errors->len; i++) {
write_log("$%I %s: %S", obj->dbref, name,
data_sptr(&errors->el[i]),
errors->el[i].u.substr.span);
}
list_discard(errors);
return method;
}
substr_set_to_full_string(&d.u.substr, line);
code = list_add(code, &d);
string_discard(line);
}
/* We ran out of lines. This wasn't supposed to happen. */
write_log("Text dump ended inside method.");
return NULL;
}