/* db.c */ #include "copyright.h" #include <stdio.h> #include <ctype.h> #include <string.h> #include "config.h" #include "interface.h" #include "db.h" #include "attrib.h" #include "externs.h" #ifdef MEM_CHECK #include "mem_check.h" #endif #ifdef USE_NALLOC #include "nalloc.h" NALLOC *db_strings = NULL; #endif struct object *db = 0; dbref db_top = 0; dbref errobj; #ifndef DB_INITIAL_SIZE #define DB_INITIAL_SIZE 10000 #endif /* DB_INITIAL_SIZE */ dbref db_size = DB_INITIAL_SIZE; extern char ccom[]; /* manage boolean expression free list */ struct boolexp *alloc_bool() { #ifdef MEM_CHECK add_check("boolexp"); #endif #ifdef USE_NALLOC return ((struct boolexp *) na_alloc(db_strings, sizeof(struct boolexp))); #else return ((struct boolexp *) malloc(sizeof(struct boolexp))); #endif } void free_bool(b) struct boolexp *b; { if (b != TRUE_BOOLEXP && b) { #ifdef USE_NALLOC na_unalloc(db_strings, (char *) b); #else free((char *) b); #endif #ifdef MEM_CHECK del_check("boolexp"); #endif } } char *set_string(ptr, new) char **ptr; char *new; { /* if pointer not null unalloc it */ if (*ptr) { #ifdef USE_NALLOC na_unalloc(db_strings, *ptr); #else free((char *) *ptr); #endif #ifdef MEM_CHECK del_check("object_name"); #endif } if (!new || !*new) return (*ptr = NULL); #ifdef USE_NALLOC *ptr = (char *)na_ualloc(db_strings, strlen(new) + 1); #else *ptr = (char *) malloc(strlen(new) +1); #endif #ifdef MEM_CHECK add_check("object_name"); #endif strcpy(*ptr, new); return (*ptr); } int db_init = 0; static void db_grow(newtop) dbref newtop; { struct object *newdb; if (newtop > db_top) { db_top = newtop; if (!db) { /* make the initial one */ db_size = (db_init) ? db_init : DB_INITIAL_SIZE; #ifdef USE_NALLOC if((db = 5 + (struct object *) bigalloc ((db_size + 5) * sizeof(struct object))) == NULL) { #else if((db = (struct object *) malloc(db_size * sizeof(struct object))) == NULL) { #endif fprintf(stderr, "ERROR: out of memory!\n"); fflush(stderr); abort(); } } /* maybe grow it */ if (db_top > db_size) { /* make sure it's big enough */ while (db_top > db_size) db_size *= 2; #ifdef USE_NALLOC if((newdb = 5 + (struct object *) bigalloc((5 + db_size) * sizeof(struct object))) == NULL) { #else if((newdb = (struct object *) realloc(db, db_size * sizeof(struct object))) == NULL) { #endif fprintf(stderr, "ERROR: out of memory!\n"); fflush(stderr); abort(); } #ifdef USE_NALLOC memcpy(newdb, db, db_top * sizeof(struct object)); bigfree(db - 5); #endif db = newdb; } } } dbref new_object() { dbref newobj; struct object *o; #ifdef DESTROY /* if stuff in free list use it */ if ((newobj = free_get()) == NOTHING) /* allocate more space */ #endif /* DESTROY */ { newobj = db_top; db_grow(db_top + 1); } /* clear it out */ o = db + newobj; o->name = 0; o->list = 0; o->location = NOTHING; o->contents = NOTHING; o->exits = NOTHING; o->next = NOTHING; o->key = TRUE_BOOLEXP; o->usekey = TRUE_BOOLEXP; o->enterkey = TRUE_BOOLEXP; o->owner = NOTHING; o->zone = NOTHING; o->penn = 0; /* flags you must initialize yourself */ return newobj; } void putref(f, ref) FILE *f; dbref ref; { fprintf(f, "%d\n", ref); } static void putstring(f, s) FILE *f; const char *s; { if (s) { fputs(s, f); } putc('\n', f); } static void putbool_subexp(f, b) 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(IN_TOKEN,f); putbool_subexp(f,b->sub1); putc(')', f); break; case BOOLEXP_IND: putc('(', f); putc(AT_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, "%s:%s", b->atr_lock->name, uncompress(b->atr_lock->text)); default: break; } } void putboolexp(f, b) FILE *f; struct boolexp *b; { if (b != TRUE_BOOLEXP) { putbool_subexp(f, b); } putc('\n', f); } int db_write_object(f, i) FILE *f; dbref i; { struct object *o; ALIST *list; o = db + i; putstring(f, o->name); putref(f, o->location); putref(f, o->contents); putref(f, o->exits); putref(f, o->next); putboolexp(f, o->key); putboolexp(f, o->usekey); putboolexp(f, o->enterkey); putref(f, o->owner); putref(f, o->zone); putref(f, Pennies(i)); putref(f, o->flags); /* write the attribute list */ for (list = o->list; list; list = AL_NEXT(list)) { if (!AL_BAD(list)) { fprintf(f, "]%s^%d^%d\n", AL_NAME(list), db[AL_CREATOR(list)].owner, AL_FLAGS(list)); fprintf(f, "%s\n", uncompress(AL_STR(list))); } } fprintf(f, "<\n"); return 0; } dbref db_write(f) FILE *f; { dbref i; fprintf(f, "+V2\n"); fprintf(f, "~%d\n", db_top); for (i = 0; i < db_top; i++) { fprintf(f, "!%d\n", i); db_write_object(f, i); } fputs("***END OF DUMP***\n", f); fflush(f); return (db_top); } dbref parse_dbref(s) const char *s; { const char *p; long x; x = atol(s); if (x > 0) { return x; } else if (x == 0) { /* check for 0 */ for (p = s; *p; p++) { if (*p == '0') return 0; if (!isspace(*p)) break; } } /* else x < 0 or s != 0 */ return NOTHING; } dbref getref(f) FILE *f; { static char buf[BUFFER_LEN]; fgets(buf, sizeof(buf), f); return (atol(buf)); } static const char *getstring_noalloc(f) FILE *f; { static char buf[2*BUFFER_LEN]; char *p; fgets(buf, sizeof(buf), f); for (p = buf; *p; p++) { if (*p == '\n') { *p = '\0'; break; } } return buf; } #define getstring(x,p) {p=NULL; SET(p,getstring_noalloc(x));} #define getstring_compress(x,p) {p=NULL; SETC(p,getstring_noalloc(x));} static struct boolexp *getboolexp1(f) FILE *f; { struct boolexp *b; int c; char tbuf1[BUFFER_LEN], tbuf2[BUFFER_LEN]; c = getc(f); switch (c) { case '\n': ungetc(c, f); return TRUE_BOOLEXP; /* break; */ case EOF: fprintf(stderr, "ERROR: Unexpected EOF in boolexp. Object #%d", errobj); return TRUE_BOOLEXP; /*NOTREACHED*/ break; case '(': b = alloc_bool(); if ((c = getc(f)) == NOT_TOKEN) { b->type = BOOLEXP_NOT; b->sub1 = getboolexp1(f); if (getc(f) != ')') goto error; return b; } else if (c == IS_TOKEN) { b->type = BOOLEXP_IS; b->sub1 = getboolexp1(f); if (getc(f) != ')') goto error; return b; } else if (c == IN_TOKEN) { b->type = BOOLEXP_CARRY; b->sub1 = getboolexp1(f); if (getc(f) != ')') goto error; return b; } else if (c == AT_TOKEN) { b->type = BOOLEXP_IND; b->sub1 = getboolexp1(f); if (getc(f) != ')') goto error; return b; } else { ungetc(c, f); b->sub1 = getboolexp1(f); switch (c = getc(f)) { case AND_TOKEN: b->type = BOOLEXP_AND; break; case OR_TOKEN: b->type = BOOLEXP_OR; break; default: goto error; /* break */ } b->sub2 = getboolexp1(f); if (getc(f) != ')') goto error; return b; } /* break; */ case '-': /* obsolete NOTHING key */ /* eat it */ while ((c = getc(f)) != '\n') if (c == EOF) { fprintf(stderr, "ERROR: Unexpected EOF in boolexp. Object #%d\n", errobj); return TRUE_BOOLEXP; } ungetc(c, f); return TRUE_BOOLEXP; /* break */ default: /* can be either a dbref or : seperated string */ ungetc(c, f); b = alloc_bool(); b->type = BOOLEXP_CONST; b->thing = 0; /* constant dbref */ if(isdigit(c = getc(f))) { while(isdigit(c)) { b->thing = b->thing * 10 + c - '0'; c = getc(f); } switch(c) { case ':': /* old style boolexp lock */ { char *p; for(p = tbuf1; ((c = getc(f)) != EOF) && (c != '\n') && (c != ')'); *p++ = c); *p = '\0'; if(c == EOF) goto error; b->atr_lock = alloc_atr(convert_atr(b->thing), tbuf1); b->thing = 0; b->type = BOOLEXP_ATR; /* this is only needed because of the braindeath of the previous * version of atrlocks.. bleah. */ if(c == '\n') return(b); } default: ungetc(c, f); break; } return(b); } else { /* MUST be a colon seperated string for attrib lock */ char *p = tbuf1, *s; *p++ = c; for(; ((c = getc(f)) != EOF) && (c != '\n') && (c != ':'); *p++ = c); *p = '\0'; if (c == EOF || c == '\n') goto error; if (c != ':') goto error; for (s = tbuf2; ((c = getc(f)) != EOF) && (c != '\n') && (c != ')' && (c != OR_TOKEN) && (c != AND_TOKEN)); *s++ = c) ; if (c == EOF) goto error; *s++ = 0; ungetc(c, f); b->atr_lock = alloc_atr(tbuf1, tbuf2); b->type = BOOLEXP_ATR; return (b); } } error: fprintf(stderr, "ERROR: Unknown error in boolexp. Object #%d\n", errobj); return TRUE_BOOLEXP; } struct boolexp *getboolexp(f) FILE *f; { struct boolexp *b; b = getboolexp1(f); if (getc(f) != '\n') { fprintf(stderr, "ERROR: Invalid boolexp format on object #%d\n", errobj); return TRUE_BOOLEXP; } return b; } void free_boolexp(b) struct boolexp *b; { if (b != TRUE_BOOLEXP && b) { switch (b->type) { case BOOLEXP_AND: case BOOLEXP_OR: free_boolexp(b->sub1); free_boolexp(b->sub2); free_bool(b); break; case BOOLEXP_NOT: case BOOLEXP_CARRY: case BOOLEXP_IND: case BOOLEXP_IS: free_boolexp(b->sub1); free_bool(b); break; case BOOLEXP_CONST: free_bool(b); break; case BOOLEXP_ATR: #ifdef USE_NALLOC if (b->atr_lock->name) na_unalloc(db_strings, (char *)b->atr_lock->name); if (b->atr_lock->text) na_unalloc(db_strings, (char *)b->atr_lock->text); if (b->atr_lock) na_unalloc(db_strings, (char *)b->atr_lock); #else if (b->atr_lock->name) free((char *)b->atr_lock->name); if (b->atr_lock->text) free((char *)b->atr_lock->text); if (b->atr_lock) free((char *)b->atr_lock); #endif #ifdef MEM_CHECK del_check("bool_atr"); del_check("bool_atr_name"); del_check("bool_atr_val"); #endif free_bool(b); break; } } } struct boolexp *dup_bool(b) struct boolexp *b; { struct boolexp *r; if (b == TRUE_BOOLEXP) return (TRUE_BOOLEXP); r = alloc_bool(); switch (r->type = b->type) { case BOOLEXP_AND: case BOOLEXP_OR: r->sub2 = dup_bool(b->sub2); case BOOLEXP_NOT: case BOOLEXP_IND: case BOOLEXP_IS: case BOOLEXP_CARRY: r->sub1 = dup_bool(b->sub1); case BOOLEXP_CONST: r->thing = b->thing; break; case BOOLEXP_ATR: r->atr_lock = alloc_atr(b->atr_lock->name, b->atr_lock->text); break; default: fprintf(stderr, "ERROR: bad bool type in dup_bool!\n"); return (TRUE_BOOLEXP); } return (r); } void db_free() { dbref i; struct object *o; if (db) { for (i = 0; i < db_top; i++) { o = &db[i]; SET(o->name, NULL); atr_free(i); if (o->key) free_boolexp(o->key); } #ifdef USE_NALLOC bigfree(db - 5); #else free((char *)db); #endif db = NULL; db_init = db_top = '\0'; } #ifdef USE_NALLOC if(db_strings) na_close(db_strings); db_strings = na_open(sizeof(char *)); #endif } /* read attribute list */ int get_list(f, i) FILE *f; dbref i; { int c; char *p, *q; char tbuf1[BUFFER_LEN]; db[i].list = NULL; while (1) switch (c = getc(f)) { case ']': /* new style attribs, read name then value */ strcpy(tbuf1, getstring_noalloc(f)); if(!(p = index(tbuf1, '^'))) { fprintf(stderr, "ERROR: Bad format on new attributes. object #%d\n", i); return 0; } *p++ = '\0'; if(!(q = index(p, '^'))) { fprintf(stderr, "ERROR: Bad format on new attributes. object #%d\n", i); return 0; } *q++ = '\0'; atr_new_add(i, tbuf1, getstring_noalloc(f), atoi(p), ((q) ? atoi(q) : NOTHING)); break; case '>': /* old style attribs, read # then value*/ atr_new_add(i, convert_atr(getref(f)), getstring_noalloc(f), db[i].owner, NOTHING); break; case '<': /* end of list */ if ('\n' != getc(f)) { fprintf(stderr, "ERROR: no line feed on object %d\n", i); return (0); } return (1); default: if(c == EOF) { fprintf(stderr, "ERROR: Unexpected EOF on file.\n" ); return (0); } fprintf(stderr, "ERROR: Bad character %c on object %d\n", c, i); return (0); } } dbref db_read(f) FILE *f; { int c; dbref i; const char *dummy; struct object *o; const char *end; clear_players(); db_free(); for (i = 0;; i++) { errobj = i; c = getc(f); switch (c) { /* make sure database is at least this big *1.5 */ case '~': db_init = (getref(f) * 3) / 2; break; /* skip over MUSH 2.0 header stuff so we can move up eventually */ case '+': dummy = getstring_noalloc(f); break; /* old fashioned database */ case '#': /* another entry, yawn */ if (i != getref(f)) return -1; /* we blew it */ /* make space */ db_grow(i + 1); /* read it in */ o = db + i; o->list = NULL; getstring(f, o->name); s_Desc(i, getstring_noalloc(f)); o->location = getref(f); o->contents = getref(f); o->exits = getref(f); o->next = getref(f); o->key = getboolexp(f); #ifdef ADD_LOCKS o->usekey = TRUE_BOOLEXP; o->enterkey = TRUE_BOOLEXP; #else o->usekey = getboolexp(f); o->enterkey = getboolexp(f); #endif s_Fail(i, getstring_noalloc(f)); s_Succ(i, getstring_noalloc(f)); s_Ofail(i, getstring_noalloc(f)); s_Osucc(i, getstring_noalloc(f)); o->owner = getref(f); #ifdef ADD_ZONES o->zone = NOTHING; #else o->zone = getref(f); #endif s_Pennies(i, getref(f)); o->flags = getref(f); s_Pass(i, getstring_noalloc(f)); /* check to see if it's a player */ if (Typeof(i) == TYPE_PLAYER) add_player(i); break; /* new database */ case '!': /* non-zone oriented database */ case '&': /* zone oriented database */ /* make space */ i = getref(f); db_grow(i + 1); /* read it in */ o = db + i; getstring(f, o->name); o->location = getref(f); /* --- get zone number --- */ (c == '&') ? (int) getref(f) : 0; /* ----------------------- */ o->contents = getref(f); o->exits = getref(f); o->next = getref(f); o->key = getboolexp(f); #ifdef ADD_LOCKS o->usekey = TRUE_BOOLEXP; o->enterkey = TRUE_BOOLEXP; #else o->usekey = getboolexp(f); o->enterkey = getboolexp(f); #endif o->owner = getref(f); #ifdef ADD_ZONES o->zone = NOTHING; #else o->zone = getref(f); #endif s_Pennies(i, getref(f)); o->flags = getref(f); /* read attribute list for item */ if (!get_list(f, i)) { fprintf(stderr, "ERROR: bad attribute list object %d\n", i); return -1; } /* check to see if it's a player */ if (Typeof(i) == TYPE_PLAYER) { add_player(i); db[i].flags &= ~PLAYER_CONNECT; } break; case '*': end = getstring_noalloc(f); if (strcmp(end, "**END OF DUMP***")) { fprintf(stderr, "ERROR: No end of dump %d\n", i); return -1; } else { { fprintf(stderr, "done\n"); FIX; return db_top; } } default: fprintf(stderr, "ERROR: failed object %d\n", i); return -1; } } }