/* db.c */ #include "os.h" #include "copyright.h" #include "config.h" #include "interface.h" #include "db.h" #include "attrib.h" #include "externs.h" #ifdef MEM_CHECK #include "mem_check.h" #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; /* manage boolean expression free list */ struct boolexp *alloc_bool (void) { #ifdef MEM_CHECK add_check ("boolexp"); #endif return ((struct boolexp *) malloc (sizeof (struct boolexp))); } void free_bool (struct boolexp *b) { if (b != TRUE_BOOLEXP && b) { free ((char *) b); #ifdef MEM_CHECK del_check ("boolexp"); #endif } } char *set_string (char **ptr, char *new) { /* if pointer not null unalloc it */ if (*ptr) { free ((char *) *ptr); #ifdef MEM_CHECK del_check ("object_name"); #endif } if (!new || !*new) return (*ptr = NULL); *ptr = (char *) malloc (strlen (new) + 1); #ifdef MEM_CHECK add_check ("object_name"); #endif strcpy (*ptr, new); return (*ptr); } int db_init = 0; static void db_grow (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; if ((db = (struct object *) malloc (db_size * sizeof (struct object))) == NULL) { 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; if ((newdb = (struct object *) realloc (db, db_size * sizeof (struct object))) == NULL) { fprintf (stderr, "ERROR: out of memory!\n"); fflush (stderr); abort (); } 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 (FILE *f, dbref ref) { fprintf (f, "%d\n", ref); } static void putstring (FILE *f, const char *s) { if (s) { fputs (s, f); } putc ('\n', f); } 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 (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 (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 (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 (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 ((int)*p)) break; } } /* else x < 0 or s != 0 */ return NOTHING; } dbref getref (FILE *f) { static char buf[BUFFER_LEN]; fgets (buf, sizeof (buf), f); return (atol (buf)); } static char *getstring_noalloc (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 (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 ((int)(c = getc (f)))) { while (isdigit ((int)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 (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 (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: 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); #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 (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); } free ((char *) db); db = NULL; db_init = db_top = '\0'; } } /* read attribute list */ static int get_list (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); } return 0; } dbref db_read (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; } } }