PennMUSH Community

root/1.8.3/trunk/src/db.c

Revision 1117, 53.6 kB (checked in by shawnw, 1 year ago)

Merge with devel

Line 
1 /**
2  * \file db.c
3  *
4  * \brief Loading and saving the PennMUSH object database.
5  *
6  *
7  */
8
9 #include "copyrite.h"
10 #include "config.h"
11
12 #include <stdio.h>
13 #include <ctype.h>
14 #include <string.h>
15 #ifdef I_SYS_TIME
16 #include <sys/time.h>
17 #ifdef TIME_WITH_SYS_TIME
18 #include <time.h>
19 #endif
20 #else
21 #include <time.h>
22 #endif
23 #include <stdlib.h>
24 #include "conf.h"
25 #include "dbio.h"
26 #include "externs.h"
27 #include "mushdb.h"
28 #include "attrib.h"
29 #include "mymalloc.h"
30 #include "game.h"
31 #include "flags.h"
32 #include "lock.h"
33 #include "dbdefs.h"
34 #include "log.h"
35 #include "strtree.h"
36 #include "parse.h"
37 #include "privtab.h"
38 #include "htab.h"
39 #include "extmail.h"
40 #include "confmagic.h"
41 #include "ansi.h"
42
43 #ifdef WIN32
44 #pragma warning( disable : 4761)        /* disable warning re conversion */
45 #endif
46
47 #ifdef WIN32SERVICES
48 void shutdown_checkpoint(void);
49 #endif
50
51 /** Get a ref out of the database if a given db flag is set */
52 #define MAYBE_GET(f,x) \
53         (globals.indb_flags & (x)) ? getref(f) : 0
54
55
56 int loading_db = 0;   /**< Are we loading the database? */
57
58 char db_timestamp[100]; /**< Time the read database was saved. */
59
60 struct object *db = NULL; /**< The object db array */
61 dbref db_top = 0;         /**< The number of objects in the db array */
62
63 dbref errobj;             /**< Dbref of object on which an error has occurred */
64
65 int dbline = 0;           /**< Line of the database file being read */
66
67 /** String that markes the end of dumps */
68 const char *EOD = "***END OF DUMP***\n";
69
70 #ifndef DB_INITIAL_SIZE
71 #define DB_INITIAL_SIZE 5000   /**< Initial size for db array */
72 #endif                          /* DB_INITIAL_SIZE */
73
74 dbref db_size = DB_INITIAL_SIZE;  /**< Current size of db array */
75
76 HASHTAB htab_objdata;         /**< Object data hash table */
77 HASHTAB htab_objdata_keys;    /**< Object data keys hash table */
78
79 static void db_grow(dbref newtop);
80
81 static void db_write_obj_basic(FILE * f, dbref i, struct object *o);
82 int db_paranoid_write_object(FILE * f, dbref i, int flag);
83 int db_write_object(FILE * f, dbref i);
84 void putlocks(FILE * f, lock_list *l);
85 void getlocks(dbref i, FILE * f);
86 void get_new_locks(dbref i, FILE * f, int c);
87 void db_read_attrs(FILE * f, dbref i, int c);
88 int get_list(FILE * f, dbref i);
89 void db_free(void);
90 static void init_objdata_htab(int size, void (*free_data) (void *));
91 static void db_write_flags(FILE * f);
92 static dbref db_read_oldstyle(FILE * f);
93
94 StrTree object_names;       /**< String tree of object names */
95 extern StrTree atr_names;
96
97 void init_names(void);
98
99 void create_minimal_db(void);
100
101 extern struct db_stat_info current_state;
102
103 /** Initialize the name strtree.
104  */
105 void
106 init_names(void)
107 {
108   st_init(&object_names);
109 }
110
111 /** Set an object's name through the name strtree.
112  * We maintain object names in a strtree because many objects have
113  * the same name (cardinal exits, weapons and armor, etc.)
114  * This function is used to set an object's name; if the name's already
115  * in the strtree, we just get a pointer to it, saving memory.
116  * (If not, we add it to the strtree and use that pointer).
117  * \param obj dbref of object whose name is to be set.
118  * \param newname name to set on the object, or NULL to clear the name.
119  * \return object's new name, or NULL if none is given.
120  */
121 const char *
122 set_name(dbref obj, const char *newname)
123 {
124   /* if pointer not null unalloc it */
125   if (Name(obj))
126     st_delete(Name(obj), &object_names);
127   if (!newname || !*newname)
128     return NULL;
129   Name(obj) = st_insert(newname, &object_names);
130   return Name(obj);
131 }
132
133 int db_init = 0;  /**< Has the db array been initialized yet? */
134
135 static void
136 db_grow(dbref newtop)
137 {
138   struct object *newdb;
139   dbref initialized;
140   struct object *o;
141
142   if (newtop > db_top) {
143     initialized = db_top;
144     current_state.total = newtop;
145     current_state.garbage += newtop - db_top;
146     db_top = newtop;
147     if (!db) {
148       /* make the initial one */
149       db_size = (db_init) ? db_init : DB_INITIAL_SIZE;
150       while (db_top > db_size)
151         db_size *= 2;
152       if ((db = (struct object *)
153            malloc(db_size * sizeof(struct object))) == NULL) {
154         do_rawlog(LT_ERR, "ERROR: out of memory while creating database!");
155         abort();
156       }
157     }
158     /* maybe grow it */
159     if (db_top > db_size) {
160       /* make sure it's big enough */
161       while (db_top > db_size)
162         db_size *= 2;
163       if ((newdb = (struct object *)
164            realloc(db, db_size * sizeof(struct object))) == NULL) {
165         do_rawlog(LT_ERR, "ERROR: out of memory while extending database!");
166         abort();
167       }
168       db = newdb;
169     }
170     while (initialized < db_top) {
171       o = db + initialized;
172       o->name = 0;
173       o->list = 0;
174       o->location = NOTHING;
175       o->contents = NOTHING;
176       o->exits = NOTHING;
177       o->next = NOTHING;
178       o->parent = NOTHING;
179       o->locks = NULL;
180       o->owner = GOD;
181       o->zone = NOTHING;
182       o->penn = 0;
183       o->type = TYPE_GARBAGE;
184       o->flags = NULL;
185       o->powers = NULL;
186       o->warnings = 0;
187       o->modification_time = o->creation_time = mudtime;
188       o->attrcount = 0;
189       initialized++;
190     }
191   }
192 }
193
194 /** Allocate a new object structure.
195  * This function allocates and returns a new object structure.
196  * The caller must see that it gets appropriately typed and otherwise
197  * initialized.
198  * \return dbref of newly allocated object.
199  */
200 dbref
201 new_object(void)
202 {
203   dbref newobj;
204   struct object *o;
205   /* if stuff in free list use it */
206   if ((newobj = free_get()) == NOTHING) {
207     /* allocate more space */
208     newobj = db_top;
209     db_grow(db_top + 1);
210   }
211   /* clear it out */
212   o = db + newobj;
213   o->name = 0;
214   o->list = 0;
215   o->location = NOTHING;
216   o->contents = NOTHING;
217   o->exits = NOTHING;
218   o->next = NOTHING;
219   o->parent = NOTHING;
220   o->locks = NULL;
221   o->owner = GOD;
222   o->zone = NOTHING;
223   o->penn = 0;
224   o->type = TYPE_GARBAGE;
225   o->warnings = 0;
226   o->modification_time = o->creation_time = mudtime;
227   o->attrcount = 0;
228   /* Flags are set by the functions that call this */
229   o->powers = new_flag_bitmask("POWER");
230   if (current_state.garbage)
231     current_state.garbage--;
232   return newobj;
233 }
234
235 /** Output a long int to a file.
236  * \param f file pointer to write to.
237  * \param ref value to write.
238  */
239 void
240 putref(FILE * f, long int ref)
241 {
242   OUTPUT(fprintf(f, "%ld\n", ref));
243 }
244
245 /** Output a string to a file.
246  * This function writes a string to a file, double-quoted,
247  * appropriately escaping quotes and backslashes (the escape character).
248  * \param f file pointer to write to.
249  * \param s value to write.
250  */
251 void
252 putstring(FILE * f, const char *s)
253 {
254   OUTPUT(putc('"', f));
255   while (*s) {
256     switch (*s) {
257     case '\\':
258     case '"':
259       OUTPUT(putc('\\', f));
260       /* FALL THROUGH */
261     default:
262       OUTPUT(putc(*s, f));
263     }
264     s++;
265   }
266   OUTPUT(putc('"', f));
267   OUTPUT(putc('\n', f));
268 }
269
270 /** Read a labeled entry from a database.
271  * Labeled entries look like 'label entry', and are used
272  * extensively in the current database format, and to a lesser
273  * extent in older versions.
274  * \param f the file to read from
275  * \param label pointer to update to the address of a static
276  * buffer containing the label that was read.
277  * \param value pointer to update to the address of a static
278  * buffer containing the value that was read.
279  */
280 void
281 db_read_labeled_string(FILE * f, char **label, char **value)
282 {
283   static char lbuf[BUFFER_LEN], vbuf[BUFFER_LEN];
284   int c;
285   char *p;
286
287   *label = lbuf;
288   *value = vbuf;
289
290   /* invariant: we start at the beginning of a line. */
291
292   dbline++;
293
294   do {
295     c = getc(f);
296     while (isspace(c)) {
297       if (c == '\n')
298         dbline++;
299       c = getc(f);
300     }
301     if (c == '#') {
302       while ((c = getc(f)) != '\n' && c != EOF) {
303         /* nothing */
304       }
305       if (c == '\n')
306         dbline++;
307     }
308   } while (c != EOF && isspace(c));
309
310   if (c == EOF) {
311     do_rawlog(LT_ERR, T("DB: Unexpected EOF at line %d"), dbline);
312     longjmp(db_err, 1);
313   }
314
315   /* invariant: we should have the first character of a label in 'c'. */
316
317   p = lbuf;
318   do {
319     if (c != '_' && c != '-' && c != '!' && c != '.' && c != '>' && c != '<' && c != '#' &&     /* these really should only be first time */
320         !isalnum(c)) {
321       do_rawlog(LT_ERR, "DB: Illegal character '%c'(%d) in label, line %d",
322                 c, c, dbline);
323       longjmp(db_err, 1);
324     }
325     safe_chr(c, lbuf, &p);
326     c = getc(f);
327   } while (c != EOF && !isspace(c));
328   *p++ = '\0';
329   if (p >= lbuf + BUFFER_LEN)
330     do_rawlog(LT_ERR, "DB: warning: very long label, line %d", dbline);
331
332   /* suck up separating whitespace */
333   while (c != '\n' && c != EOF && isspace(c))
334     c = getc(f);
335
336   /* check for presence of a value, which we must have. */
337   if (c == EOF || c == '\n') {
338     if (c == EOF)
339       do_rawlog(LT_ERR, T("DB: Unexpected EOF at line %d"), dbline);
340     else
341       do_rawlog(LT_ERR, T("DB: Missing value for '%s' at line %d"), lbuf,
342                 dbline);
343     longjmp(db_err, 1);
344   }
345
346   /* invariant: we should have the first character of a value in 'c'. */
347
348   p = vbuf;
349   if (c == '"') {
350     /* quoted string */
351     int sline;
352     sline = dbline;
353     for (;;) {
354       c = getc(f);
355       if (c == '"')
356         break;
357       if (c == '\\')
358         c = getc(f);
359       if (c == EOF) {
360         do_rawlog(LT_ERR, "DB: Unclosed quoted string starting on line %d",
361                   sline);
362         longjmp(db_err, 1);
363       }
364       if (c == '\0')
365         do_rawlog(LT_ERR,
366                   "DB: warning: null in quoted string, remainder lost, line %d",
367                   dbline);
368       if (c == '\n')
369         dbline++;
370       safe_chr(c, vbuf, &p);
371     }
372     do {
373       c = getc(f);
374       if (c != EOF && !isspace(c)) {
375         do_rawlog(LT_ERR, "DB: Garbage after quoted string, line %d", dbline);
376         longjmp(db_err, 1);
377       }
378     } while (c != '\n' && c != EOF);
379   } else {
380     /* non-quoted value */
381     do {
382       if (c != '_' && c != '-' && c != '!' && c != '.' &&
383           c != '#' && !isalnum(c) && !isspace(c)) {
384         do_rawlog(LT_ERR, "DB: Illegal character '%c'(%d) in value, line %d",
385                   c, c, dbline);
386         longjmp(db_err, 1);
387       }
388       safe_chr(c, vbuf, &p);
389       c = getc(f);
390     } while (c != EOF && c != '\n');
391     if (c == '\n' && (p - vbuf >= 2) && (*(p - 2) == '\r')) {
392       /* Oops, we read in \r\n at the end of this value. Drop the \r */
393       p--;
394       *(p - 1) = '\n';
395     }
396   }
397   *p++ = '\0';
398   if (p >= vbuf + BUFFER_LEN)
399     do_rawlog(LT_ERR, "DB: warning: very long value, line %d", dbline);
400
401   /* note no line increment for final newline because of initial increment */
402 }
403
404 /** Read a string with a given label.
405  * If the label read is different than the one being checked, the
406  * database load will abort with an error.
407  * \param f the file to read from.
408  * \param label the label that should be read.
409  * \param value pointer to update to the address of a static
410  * buffer containing the value that was read.
411  */
412 void
413 db_read_this_labeled_string(FILE * f, const char *label, char **value)
414 {
415   char *readlabel;
416
417   db_read_labeled_string(f, &readlabel, value);
418
419   if (strcmp(readlabel, label)) {
420     do_rawlog(LT_ERR,
421               T("DB: error: Got label '%s', expected label '%s' at line %d"),
422               readlabel, label, dbline);
423     longjmp(db_err, 1);
424   }
425 }
426
427 /** Read an int with a given label.
428  * If the label read is different than the one being checked, the
429  * database load will abort with an error.
430  * \param f the file to read from.
431  * \param label the label that should be read.
432  * \param value pointer to update to the number that was read.
433  */
434 void
435 db_read_this_labeled_int(FILE * f, const char *label, int *value)
436 {
437   char *readlabel;
438   char *readvalue;
439
440   db_read_labeled_string(f, &readlabel, &readvalue);
441
442   if (strcmp(readlabel, label)) {
443     do_rawlog(LT_ERR,
444               T("DB: error: Got label '%s', expected label '%s' at line %d"),
445               readlabel, label, dbline);
446     longjmp(db_err, 1);
447   }
448
449   *value = parse_integer(readvalue);
450 }
451
452 /** Read an int and label.
453  * \param f the file to read from.
454  * \param label pointer to update to the address of a static
455  * buffer containing the label that was read.
456  * \param value pointer to update to the number that was read.
457  */
458 void
459 db_read_labeled_int(FILE * f, char **label, int *value)
460 {
461   char *readvalue;
462   db_read_labeled_string(f, label, &readvalue);
463   *value = parse_integer(readvalue);
464 }
465
466
467 /** Read a uint32_t with a given label.
468  * If the label read is different than the one being checked, the
469  * database load will abort with an error.
470  * \param f the file to read from.
471  * \param label the label that should be read.
472  * \param value pointer to update to the number that was read.
473  */
474 void
475 db_read_this_labeled_uint32(FILE * f, const char *label, uint32_t * value)
476 {
477   char *readlabel;
478   char *readvalue;
479
480   db_read_labeled_string(f, &readlabel, &readvalue);
481
482   if (strcmp(readlabel, label)) {
483     do_rawlog(LT_ERR,
484               T("DB: error: Got label '%s', expected label '%s' at line %d"),
485               readlabel, label, dbline);
486     longjmp(db_err, 1);
487   }
488
489   *value = parse_uint32(readvalue, NULL, 10);
490 }
491
492 /** Read a uint32_t and label.
493  * \param f the file to read from.
494  * \param label pointer to update to the address of a static
495  * buffer containing the label that was read.
496  * \param value pointer to update to the number that was read.
497  */
498 void
499 db_read_labeled_uint32(FILE * f, char **label, uint32_t * value)
500 {
501   char *readvalue;
502   db_read_labeled_string(f, label, &readvalue);
503   *value = parse_uint32(readvalue, NULL, 10);
504 }
505
506
507 /** Read a dbref with a given label.
508  * If the label read is different than the one being checked, the
509  * database load will abort with an error.
510  * \param f the file to read from.
511  * \param label the label that should be read.
512  * \param value pointer to update to the dbref that was read.
513  */
514 void
515 db_read_this_labeled_dbref(FILE * f, const char *label, dbref *val)
516 {
517   char *readlabel;
518   char *readvalue;
519
520   db_read_labeled_string(f, &readlabel, &readvalue);
521
522   if (strcmp(readlabel, label)) {
523     do_rawlog(LT_ERR,
524               T("DB: error: Got label '%s', expected label '%s' at line %d"),
525               readlabel, label, dbline);
526     longjmp(db_err, 1);
527   }
528   *val = qparse_dbref(readvalue);
529 }
530
531 /** Read a dbref and label.
532  * \param f the file to read from.
533  * \param label pointer to update to the address of a static
534  * buffer containing the label that was read.
535  * \param value pointer to update to the dbref that was read.
536  */
537 void
538 db_read_labeled_dbref(FILE * f, char **label, dbref *val)
539 {
540   char *readvalue;
541   db_read_labeled_string(f, label, &readvalue);
542   *val = qparse_dbref(readvalue);
543 }
544
545 static void
546 db_write_label(FILE * f, char const *l)
547 {
548   OUTPUT(fputs(l, f));
549   OUTPUT(putc(' ', f));
550 }
551
552 void
553 db_write_labeled_string(FILE * f, char const *label, char const *value)
554 {
555   db_write_label(f, label);
556   putstring(f, value);
557 }
558
559 void
560 db_write_labeled_int(FILE * f, char const *label, int value)
561 {
562   OUTPUT(fprintf(f, "%s %d\n", label, value));
563 }
564
565 void
566 db_write_labeled_dbref(FILE * f, char const *label, dbref value)
567 {
568   OUTPUT(fprintf(f, "%s #%d\n", label, value));
569 }
570
571 /** Write a boolexp to a file in unparsed (text) form.
572  * \param f file pointer to write to.
573  * \param b pointer to boolexp to write.
574  */
575 void
576 putboolexp(FILE * f