root/1.8.3/tags/p6/src/flags.c

Revision 1167, 81.3 KB (checked in by shawnw, 13 months ago)

Merge devel into trunk for p6 release

Line 
1/**
2 * \file flags.c
3 *
4 * \brief Flags and powers (and sometimes object types) in PennMUSH
5 *
6 *
7 * Functions to cope with flags and powers (and also object types,
8 * in some cases).
9 *
10 * Flag functions actually involve with several related entities:
11 *  Flag spaces (FLAGSPACE objects)
12 *  Flag definitions (FLAG objects)
13 *  Bitmasks representing sets of flags (object_flag_type's). The
14 *    bits involved may differ between dbs.
15 *  Strings of space-separated flag names. This is a string representation
16 *    of a bitmask, suitable for display and storage
17 *  Strings of flag characters
18 *
19 */
20
21#include "config.h"
22
23#ifdef I_SYS_TIME
24#include <sys/time.h>
25#ifdef TIME_WITH_SYS_TIME
26#include <time.h>
27#endif
28#else
29#include <time.h>
30#endif
31#include <string.h>
32#include <stdlib.h>
33
34#include "conf.h"
35#include "externs.h"
36#include "command.h"
37#include "attrib.h"
38#include "mushdb.h"
39#include "parse.h"
40#include "match.h"
41#include "ptab.h"
42#include "htab.h"
43#include "privtab.h"
44#include "game.h"
45#include "flags.h"
46#include "dbdefs.h"
47#include "lock.h"
48#include "log.h"
49#include "dbio.h"
50#include "sort.h"
51#include "mymalloc.h"
52#include "oldflags.h"
53#include "confmagic.h"
54
55
56static int can_set_flag(dbref player, dbref thing, FLAG *flagp, int negate);
57static FLAG *letter_to_flagptr(FLAGSPACE *n, char c, int type);
58static void flag_add(FLAGSPACE *n, const char *name, FLAG *f);
59static int has_flag_ns(FLAGSPACE *n, dbref thing, FLAG *f);
60
61static FLAG *flag_read(FILE * in);
62static FLAG *flag_read_oldstyle(FILE * in);
63static void flag_read_all_oldstyle(FILE * in, const char *ns);
64static void flag_write(FILE * out, FLAG *f, const char *name);
65static FLAG *flag_hash_lookup(FLAGSPACE *n, const char *name, int type);
66static FLAG *clone_flag(FLAG *f);
67static FLAG *new_flag(void);
68static void flag_add_additional(FLAGSPACE *n);
69static char *list_aliases(FLAGSPACE *n, FLAG *given);
70static void realloc_object_flag_bitmasks(FLAGSPACE *n);
71static FLAG *match_flag_ns(FLAGSPACE *n, const char *name);
72
73PTAB ptab_flag;                 /**< Table of flags by name, inc. aliases */
74PTAB ptab_power;                /**< Table of powers by name, inc. aliases */
75HASHTAB htab_flagspaces;                /**< Hash of flagspaces */
76slab *flag_slab = NULL;
77extern PTAB ptab_command;       /* Uses flag bitmasks */
78
79/** Attempt to find a flagspace from its name */
80#define Flagspace_Lookup(n,ns)  if (!(n = (FLAGSPACE *)hashfind(ns,&htab_flagspaces))) mush_panic("Unable to locate flagspace");
81
82/** This is the old default flag table. We still use it when we have to
83 * convert old dbs, but once you have a converted db, it's the flag
84 * table in the db that counts, not this one.
85 */
86/* Name     Letter   Type(s)   Flag   Perms   Negate_Perm */
87static FLAG flag_table[] = {
88  {"CHOWN_OK", 'C', NOTYPE, CHOWN_OK, F_ANY, F_ANY},
89  {"DARK", 'D', NOTYPE, DARK, F_ANY, F_ANY},
90  {"GOING", 'G', NOTYPE, GOING, F_INTERNAL, F_INTERNAL},
91  {"HAVEN", 'H', NOTYPE, HAVEN, F_ANY, F_ANY},
92  {"TRUST", 'I', NOTYPE, INHERIT, F_INHERIT, F_INHERIT},
93  {"LINK_OK", 'L', NOTYPE, LINK_OK, F_ANY, F_ANY},
94  {"OPAQUE", 'O', NOTYPE, LOOK_OPAQUE, F_ANY, F_ANY},
95  {"QUIET", 'Q', NOTYPE, QUIET, F_ANY, F_ANY},
96  {"STICKY", 'S', NOTYPE, STICKY, F_ANY, F_ANY},
97  {"UNFINDABLE", 'U', NOTYPE, UNFIND, F_ANY, F_ANY},
98  {"VISUAL", 'V', NOTYPE, VISUAL, F_ANY, F_ANY},
99  {"WIZARD", 'W', NOTYPE, WIZARD, F_INHERIT | F_WIZARD | F_LOG,
100   F_INHERIT | F_WIZARD},
101  {"SAFE", 'X', NOTYPE, SAFE, F_ANY, F_ANY},
102  {"AUDIBLE", 'a', NOTYPE, AUDIBLE, F_ANY, F_ANY},
103  {"DEBUG", 'b', NOTYPE, DEBUGGING, F_ANY, F_ANY},
104  {"NO_WARN", 'w', NOTYPE, NOWARN, F_ANY, F_ANY},
105  {"ENTER_OK", 'e', NOTYPE, ENTER_OK, F_ANY, F_ANY},
106  {"HALT", 'h', NOTYPE, HALT, F_ANY, F_ANY},
107  {"NO_COMMAND", 'n', NOTYPE, NO_COMMAND, F_ANY, F_ANY},
108  {"LIGHT", 'l', NOTYPE, LIGHT, F_ANY, F_ANY},
109  {"ROYALTY", 'r', NOTYPE, ROYALTY, F_INHERIT | F_ROYAL | F_LOG,
110   F_INHERIT | F_ROYAL},
111  {"TRANSPARENT", 't', NOTYPE, TRANSPARENTED, F_ANY, F_ANY},
112  {"VERBOSE", 'v', NOTYPE, VERBOSE, F_ANY, F_ANY},
113  {"ANSI", 'A', TYPE_PLAYER, PLAYER_ANSI, F_ANY, F_ANY},
114  {"COLOR", 'C', TYPE_PLAYER, PLAYER_COLOR, F_ANY, F_ANY},
115  {"MONITOR", 'M', TYPE_PLAYER | TYPE_ROOM | TYPE_THING, 0, F_ANY, F_ANY},
116  {"NOSPOOF", '"', TYPE_PLAYER, PLAYER_NOSPOOF, F_ANY | F_ODARK,
117   F_ANY | F_ODARK},
118  {"SHARED", 'Z', TYPE_PLAYER, PLAYER_ZONE, F_ANY, F_ANY},
119  {"TRACK_MONEY", '\0', TYPE_PLAYER, 0, F_ANY, F_ANY},
120  {"CONNECTED", 'c', TYPE_PLAYER, PLAYER_CONNECT, F_INTERNAL | F_MDARK,
121   F_INTERNAL | F_MDARK},
122  {"GAGGED", 'g', TYPE_PLAYER, PLAYER_GAGGED, F_WIZARD, F_WIZARD},
123  {"MYOPIC", 'm', TYPE_PLAYER, PLAYER_MYOPIC, F_ANY, F_ANY},
124  {"TERSE", 'x', TYPE_PLAYER | TYPE_THING, PLAYER_TERSE, F_ANY, F_ANY},
125  {"JURY_OK", 'j', TYPE_PLAYER, PLAYER_JURY, F_ROYAL, F_ROYAL},
126  {"JUDGE", 'J', TYPE_PLAYER, PLAYER_JUDGE, F_ROYAL, F_ROYAL},
127  {"FIXED", 'F', TYPE_PLAYER, PLAYER_FIXED, F_WIZARD, F_WIZARD},
128  {"UNREGISTERED", '?', TYPE_PLAYER, PLAYER_UNREG, F_ROYAL, F_ROYAL},
129  {"ON-VACATION", 'o', TYPE_PLAYER, PLAYER_VACATION, F_ANY, F_ANY},
130  {"SUSPECT", 's', TYPE_PLAYER, PLAYER_SUSPECT, F_WIZARD | F_MDARK | F_LOG,
131   F_WIZARD | F_MDARK},
132  {"PARANOID", '\0', TYPE_PLAYER, PLAYER_PARANOID, F_ANY | F_ODARK,
133   F_ANY | F_ODARK},
134  {"NOACCENTS", '~', TYPE_PLAYER, PLAYER_NOACCENTS, F_ANY, F_ANY},
135  {"DESTROY_OK", 'd', TYPE_THING, THING_DEST_OK, F_ANY, F_ANY},
136  {"PUPPET", 'p', TYPE_THING, THING_PUPPET, F_ANY, F_ANY},
137  {"NO_LEAVE", 'N', TYPE_THING, THING_NOLEAVE, F_ANY, F_ANY},
138  {"LISTEN_PARENT", '^', TYPE_THING | TYPE_ROOM, 0, F_ANY, F_ANY},
139  {"Z_TEL", 'Z', TYPE_THING | TYPE_ROOM, 0, F_ANY, F_ANY},
140  {"ABODE", 'A', TYPE_ROOM, ROOM_ABODE, F_ANY, F_ANY},
141  {"FLOATING", 'F', TYPE_ROOM, ROOM_FLOATING, F_ANY, F_ANY},
142  {"JUMP_OK", 'J', TYPE_ROOM, ROOM_JUMP_OK, F_ANY, F_ANY},
143  {"NO_TEL", 'N', TYPE_ROOM, ROOM_NO_TEL, F_ANY, F_ANY},
144  {"UNINSPECTED", 'u', TYPE_ROOM, ROOM_UNINSPECT, F_ROYAL, F_ROYAL},
145  {"CLOUDY", 'x', TYPE_EXIT, EXIT_CLOUDY, F_ANY, F_ANY},
146  {"GOING_TWICE", '\0', NOTYPE, GOING_TWICE, F_INTERNAL | F_DARK,
147   F_INTERNAL | F_DARK},
148  {"KEEPALIVE", 'k', TYPE_PLAYER, 0, F_ANY, F_ANY},
149  {NULL, '\0', 0, 0, 0, 0}
150};
151
152/** The old table to kludge multi-type toggles. Now used only
153 * for conversion.
154 */
155static FLAG hack_table[] = {
156  {"MONITOR", 'M', TYPE_PLAYER, PLAYER_MONITOR, F_ROYAL, F_ROYAL},
157  {"MONITOR", 'M', TYPE_THING, THING_LISTEN, F_ANY, F_ANY},
158  {"MONITOR", 'M', TYPE_ROOM, ROOM_LISTEN, F_ANY, F_ANY},
159  {"LISTEN_PARENT", '^', TYPE_THING, THING_INHEARIT, F_ANY, F_ANY},
160  {"LISTEN_PARENT", '^', TYPE_ROOM, ROOM_INHEARIT, F_ANY, F_ANY},
161  {"Z_TEL", 'Z', TYPE_THING, THING_Z_TEL, F_ANY, F_ANY},
162  {"Z_TEL", 'Z', TYPE_ROOM, ROOM_Z_TEL, F_ANY, F_ANY},
163  {NULL, '\0', 0, 0, 0, 0}
164};
165
166
167/** A table of types, as if they were flags. Some functions that
168 * expect flags also accept, for historical reasons, types.
169 */
170static FLAG type_table[] = {
171  {"PLAYER", 'P', TYPE_PLAYER, TYPE_PLAYER, F_INTERNAL, F_INTERNAL},
172  {"ROOM", 'R', TYPE_ROOM, TYPE_ROOM, F_INTERNAL, F_INTERNAL},
173  {"EXIT", 'E', TYPE_EXIT, TYPE_EXIT, F_INTERNAL, F_INTERNAL},
174  {"THING", 'T', TYPE_THING, TYPE_THING, F_INTERNAL, F_INTERNAL},
175  {NULL, '\0', 0, 0, 0, 0}
176};
177
178/** A table of types, as privileges. */
179static PRIV type_privs[] = {
180  {"PLAYER", 'P', TYPE_PLAYER, TYPE_PLAYER},
181  {"ROOM", 'R', TYPE_ROOM, TYPE_ROOM},
182  {"EXIT", 'E', TYPE_EXIT, TYPE_EXIT},
183  {"THING", 'T', TYPE_THING, TYPE_THING},
184  {NULL, '\0', 0, 0}
185};
186
187/** The old default aliases for flags. This table is only used in conversion
188 * of old databases. Once a database is converted, the alias list in the
189 * database is what counts.
190 */
191static FLAG_ALIAS flag_alias_tab[] = {
192  {"INHERIT", "TRUST"},
193  {"TRACE", "DEBUG"},
194  {"NOWARN", "NO_WARN"},
195  {"NOCOMMAND", "NO_COMMAND"},
196  {"LISTENER", "MONITOR"},
197  {"WATCHER", "MONITOR"},
198  {"ZONE", "SHARED"},
199  {"COLOUR", "COLOR"},
200  {"JURYOK", "JURY_OK"},
201#ifdef VACATION_FLAG
202  {"VACATION", "ON-VACATION"},
203#endif
204  {"DEST_OK", "DESTROY_OK"},
205  {"NOLEAVE", "NO_LEAVE"},
206  {"TEL_OK", "JUMP_OK"},
207  {"TELOK", "JUMP_OK"},
208  {"TEL-OK", "JUMP_OK"},
209  {"^", "LISTEN_PARENT"},
210
211  {NULL, NULL}
212};
213
214/** This is the old defaultpowr table. We still use it when we
215 * have to convert old dbs, but once you have a converted db,
216 * it's the power table in the db that counts, not this one.
217 */
218/*   Name      Flag   */
219static FLAG power_table[] = {
220  {"Announce", '\0', NOTYPE, CAN_WALL, F_WIZARD | F_LOG, F_WIZARD},
221  {"Boot", '\0', NOTYPE, CAN_BOOT, F_WIZARD | F_LOG, F_WIZARD},
222  {"Builder", '\0', NOTYPE, CAN_BUILD, F_WIZARD | F_LOG, F_WIZARD},
223  {"Cemit", '\0', NOTYPE, CEMIT, F_WIZARD | F_LOG, F_WIZARD},
224  {"Chat_Privs", '\0', NOTYPE, CHAT_PRIVS, F_WIZARD | F_LOG, F_WIZARD},
225  {"Functions", '\0', NOTYPE, GLOBAL_FUNCS, F_WIZARD | F_LOG, F_WIZARD},
226  {"Guest", '\0', NOTYPE, IS_GUEST, F_WIZARD | F_LOG, F_WIZARD},
227  {"Halt", '\0', NOTYPE, HALT_ANYTHING, F_WIZARD | F_LOG, F_WIZARD},
228  {"Hide", '\0', NOTYPE, CAN_HIDE, F_WIZARD | F_LOG, F_WIZARD},
229  {"Idle", '\0', NOTYPE, UNLIMITED_IDLE, F_WIZARD | F_LOG, F_WIZARD},
230  {"Immortal", '\0', NOTYPE, NO_PAY | NO_QUOTA | UNKILLABLE, F_WIZARD,
231   F_WIZARD},
232  {"Link_Anywhere", '\0', NOTYPE, LINK_ANYWHERE, F_WIZARD | F_LOG, F_WIZARD},
233  {"Login", '\0', NOTYPE, LOGIN_ANYTIME, F_WIZARD | F_LOG, F_WIZARD},
234  {"Long_Fingers", '\0', NOTYPE, LONG_FINGERS, F_WIZARD | F_LOG, F_WIZARD},
235  {"No_Pay", '\0', NOTYPE, NO_PAY, F_WIZARD | F_LOG, F_WIZARD},
236  {"No_Quota", '\0', NOTYPE, NO_QUOTA, F_WIZARD | F_LOG, F_WIZARD},
237  {"Open_Anywhere", '\0', NOTYPE, OPEN_ANYWHERE, F_WIZARD | F_LOG, F_WIZARD},
238  {"Pemit_All", '\0', NOTYPE, PEMIT_ALL, F_WIZARD | F_LOG, F_WIZARD},
239  {"Player_Create", '\0', NOTYPE, CREATE_PLAYER, F_WIZARD | F_LOG, F_WIZARD},
240  {"Poll", '\0', NOTYPE, SET_POLL, F_WIZARD | F_LOG, F_WIZARD},
241  {"Queue", '\0', NOTYPE, HUGE_QUEUE, F_WIZARD | F_LOG, F_WIZARD},
242  {"Quotas", '\0', NOTYPE, CHANGE_QUOTAS, F_WIZARD | F_LOG, F_WIZARD},
243  {"Search", '\0', NOTYPE, SEARCH_EVERYTHING, F_WIZARD | F_LOG, F_WIZARD},
244  {"See_All", '\0', NOTYPE, SEE_ALL, F_WIZARD | F_LOG, F_WIZARD},
245  {"See_Queue", '\0', NOTYPE, PS_ALL, F_WIZARD | F_LOG, F_WIZARD},
246  {"Tport_Anything", '\0', NOTYPE, TEL_OTHER, F_WIZARD | F_LOG, F_WIZARD},
247  {"Tport_Anywhere", '\0', NOTYPE, TEL_ANYWHERE, F_WIZARD | F_LOG, F_WIZARD},
248  {"Unkillable", '\0', NOTYPE, UNKILLABLE, F_WIZARD | F_LOG, F_WIZARD},
249  {"Can_nspemit", '\0', NOTYPE, CAN_NSPEMIT, F_WIZARD | F_LOG, F_WIZARD},
250  {NULL, '\0', 0, 0, 0, 0}
251};
252
253/** A table of aliases for powers. */
254static FLAG_ALIAS power_alias_tab[] = {
255  {"@cemit", "Cemit"},
256  {"@wall", "Announce"},
257  {"wall", "Announce"},
258  {NULL, NULL}
259};
260
261/** The table of flag privilege bits. */
262static PRIV flag_privs[] = {
263  {"trusted", '\0', F_INHERIT, F_INHERIT},
264  {"owned", '\0', F_OWNED, F_OWNED},
265  {"royalty", '\0', F_ROYAL, F_ROYAL},
266  {"wizard", '\0', F_WIZARD, F_WIZARD},
267  {"god", '\0', F_GOD, F_GOD},
268  {"internal", '\0', F_INTERNAL, F_INTERNAL},
269  {"dark", '\0', F_DARK, F_DARK},
270  {"mdark", '\0', F_MDARK, F_MDARK},
271  {"odark", '\0', F_ODARK, F_ODARK},
272  {"disabled", '\0', F_DISABLED, F_DISABLED},
273  {"log", '\0', F_LOG, F_LOG},
274  {NULL, '\0', 0, 0}
275};
276
277
278
279/*---------------------------------------------------------------------------
280 * Flag definition functions, including flag hash table handlers
281 */
282
283/** Convenience function to return a pointer to a flag struct
284 * given the name.
285 * \param name name of flag to find.
286 * \return poiner to flag structure, or NULL.
287 */
288FLAG *
289match_flag(const char *name)
290{
291  return (FLAG *) match_flag_ns(hashfind("FLAG", &htab_flagspaces), name);
292}
293
294/** Convenience function to return a pointer to a flag struct
295 * given the name.
296 * \param name name of flag to find.
297 * \return poiner to flag structure, or NULL.
298 */
299FLAG *
300match_power(const char *name)
301{
302  return (FLAG *) match_flag_ns(hashfind("POWER", &htab_flagspaces), name);
303}
304
305/** Convenience function to return a pointer to a flag struct
306 * given the name.
307 * \param name name of flag to find.
308 * \return poiner to flag structure, or NULL.
309 */
310static FLAG *
311match_flag_ns(FLAGSPACE *n, const char *name)
312{
313  return (FLAG *) ptab_find(n->tab, name);
314}
315
316/** Given a flag name and mask of types, return a pointer to a flag struct.
317 * This function first attempts to match the flag name to a flag of the
318 * right type. If that fails, it tries to match flag characters if the
319 * name is a single character. If all else fails, it tries to match
320 * against an object type name.
321 * \param n pointer to flagspace to search.
322 * \param name name of flag to find.
323 * \param type mask of desired flag object types.
324 * \return pointer to flag structure, or NULL.
325 */
326static FLAG *
327flag_hash_lookup(FLAGSPACE *n, const char *name, int type)
328{
329  FLAG *f;
330
331  f = match_flag_ns(n, name);
332  if (f && !(f->perms & F_DISABLED)) {
333    if (f->type & type)
334      return f;
335    return NULL;
336  }
337
338  /* If the name is a single character, search the flag characters */
339  if (name && *name && !*(name + 1)) {
340    if ((f = letter_to_flagptr(n, *name, type)))
341      return f;
342  }
343
344  if (n->tab == &ptab_flag) {
345    /* provided for backwards compatibility: type flag checking */
346    if (n->flag_table == flag_table) {
347      for (f = type_table; f->name != NULL; f++)
348        if (string_prefix(name, f->name))
349          return f;
350    }
351  }
352
353  return NULL;
354}
355
356/* Allocate a new FLAG definition */
357static FLAG *
358new_flag(void)
359{
360  FLAG *f;
361
362  if (flag_slab == NULL)
363    flag_slab = slab_create("flags", sizeof(FLAG));
364  f = slab_malloc(flag_slab, NULL);
365  if (!f)
366    mush_panic("Unable to allocate memory for a new flag!\n");
367  return f;
368}
369
370/* Deallocate all flag-related memory */
371static void
372clear_all_flags(FLAGSPACE *n)
373{
374  FLAG *f;
375
376  for (f = ptab_firstentry(n->tab); f; f = ptab_nextentry(n->tab)) {
377    f->perms = DECR_FLAG_REF(f->perms);
378    if (FLAG_REF(f->perms) == 0) {
379      mush_free((void *) f->name, "flag.name");
380      slab_free(flag_slab, f);
381    }
382  }
383
384  ptab_free(n->tab);
385
386  /* Finally, the flags array */
387  if (n->flags)
388    mush_free(n->flags, "flagspace.flags");
389  n->flags = NULL;
390  n->flagbits = 0;
391
392}
393
394static FLAG *
395clone_flag(FLAG *f)
396{
397  FLAG *clone = new_flag();
398  clone->name = mush_strdup(f->name, "flag.name");
399  clone->letter = f->letter;
400  clone->type = f->type;
401  clone->bitpos = f->bitpos;
402  clone->perms = f->perms;
403  clone->negate_perms = f->negate_perms;
404  return clone;
405}
406
407/* This is a stub function to add a flag. It performs no error-checking,
408 * so it's up to you to be sure you're adding a flag that's properly
409 * set up and that'll work ok. If called with autopos == 0, this
410 * auto-allocates the next bitpos. Otherwise, bitpos is ignored and
411 * f->bitpos is used.
412 */
413static void
414flag_add(FLAGSPACE *n, const char *name, FLAG *f)
415{
416  /* If this flag has no bitpos assigned, assign it the next one.
417   * We could improve this algorithm to use the next available
418   * slot after deletions, too, but this will do for now.
419   */
420
421  /* Can't have more than 255 references to the same flag */
422  if (FLAG_REF(f->perms) == 0xFFU)
423    return;
424
425  if (f->bitpos < 0)
426    f->bitpos = n->flagbits;
427
428  f->perms = INCR_FLAG_REF(f->perms);
429
430  /* Insert the flag in the ptab by the given name (maybe an alias) */
431  ptab_insert_one(n->tab, name, f);
432
433  /* Is this a canonical flag (as opposed to an alias?)
434   * If it's an alias, we're done.
435   * A canonical flag has either been given a new bitpos
436   * or has not yet been stored in the flags array.
437   * (An alias would have a previously used bitpos that's already
438   * indexing a flag in the flags array)
439   */
440  if ((f->bitpos >= n->flagbits) || (n->flags[f->bitpos] == NULL)) {
441    /* It's a canonical flag */
442    int i;
443    if (f->bitpos >= n->flagbits) {
444      /* Oops, we need a bigger array */
445      n->flags =
446        mush_realloc(n->flags, (f->bitpos + 1) * sizeof(FLAG *),
447                     "flagspace.flags");
448      if (!n->flags)
449        mush_panic("Unable to reallocate flags array!\n");
450
451      /* Make sure the new space is full of NULLs */
452      for (i = n->flagbits; i <= f->bitpos; i++)
453        n->flags[i] = NULL;
454    }
455    /* Put the canonical flag in the flags array */
456    n->flags[f->bitpos] = f;
457    n->flagbits = f->bitpos + 1;
458    if (n->flagbits % 8 == 1) {
459      /* We've crossed over a byte boundary, so we need to realloc
460       * all the flags on all our objects to get them an additional
461       * byte.
462       */
463      realloc_object_flag_bitmasks(n);
464    }
465  }
466}
467
468static void
469realloc_object_flag_bitmasks(FLAGSPACE *n)
470{
471  dbref it;
472  object_flag_type p;
473  COMMAND_INFO *command;
474  int numbytes = (n->flagbits + 7) / 8;
475
476  for (it = 0; it < db_top; it++) {
477    if (n->tab == &ptab_flag) {
478      Flags(it) = (object_flag_type) realloc(Flags(it), numbytes);
479      p = Flags(it) + numbytes - 1;
480    } else {
481      Powers(it) = (object_flag_type) realloc(Powers(it), numbytes);
482      p = Powers(it) + numbytes - 1;
483    }
484    /* Zero them out */
485    memset(p, 0, 1);
486  }
487  /* We also need to make sure that all the command flagmasks are
488   * reallocated!
489   */
490  command = (COMMAND_INFO *) ptab_firstentry(&ptab_command);
491  while (command) {
492    if (n->tab == &ptab_flag && command->flagmask) {
493      command->flagmask =
494        (object_flag_type) realloc(command->flagmask, numbytes);
495      /* Zero them out */
496      p = command->flagmask + numbytes - 1;
497      memset(p, 0, 1);
498    }
499    if (n->tab == &ptab_power && command->powers) {
500      command->powers = (object_flag_type) realloc(command->powers, numbytes);
501      /* Zero them out */
502      p = command->powers + numbytes - 1;
503      memset(p, 0, 1);
504    }
505    command = (COMMAND_INFO *) ptab_nextentry(&ptab_command);
506  }
507}
508
509
510/* Read in a flag from a file and return it */
511static FLAG *
512flag_read_oldstyle(FILE * in)
513{
514  FLAG *f;
515  char *c;
516  c = mush_strdup(getstring_noalloc(in), "flag.name");
517  if (!strcmp(c, "FLAG ALIASES")) {
518    mush_free(c, "flag.name");
519    return NULL;                /* We're done */
520  }
521  f = new_flag();
522  f->name = c;
523  c = (char *) getstring_noalloc(in);
524  f->letter = *c;
525  f->bitpos = -1;
526  f->type = getref(in);
527  f->perms = getref(in);
528  f->negate_perms = getref(in);
529  return f;
530}
531
532static FLAG *
533flag_alias_read_oldstyle(FILE * in, char *alias, FLAGSPACE *n)
534{
535  FLAG *f;
536  char *c;
537  /* Real name first */
538  c = mush_strdup(getstring_noalloc(in), "flag alias");
539  if (!strcmp(c, "END OF FLAGS")) {
540    mush_free(c, "flag alias");
541    return NULL;                /* We're done */
542  }
543  f = match_flag_ns(n, c);
544  if (!f) {
545    /* Corrupt db. Recover as well as we can. */
546    do_rawlog(LT_ERR,
547              T
548              ("FLAG READ: flag alias %s matches no known flag. Skipping aliases."),
549              c);
550    mush_free(c, "flag alias");
551    do {
552      c = (char *) getstring_noalloc(in);
553    } while (strcmp(c, "END OF FLAGS"));
554    return NULL;
555  } else
556    mush_free(c, "flag alias");
557
558  /* Get the alias name */
559  strcpy(alias, getstring_noalloc(in));
560  return f;
561}
562
563/** Read flags and aliases from the database. This function expects
564 * to receive file pointer that's already reading in a database file
565 * and pointing at the start of the flag table. It reads the flags,
566 * reads the aliases, and then does any additional flag adding that
567 * needs to happen.
568 * \param in file pointer to read from.
569 * \param ns name of namespace to search.
570 */
571static void
572flag_read_all_oldstyle(FILE * in, const char *ns)
573{
574  FLAG *f;
575  FLAGSPACE *n;
576  char alias[BUFFER_LEN];
577
578  if (!(n = (FLAGSPACE *) hashfind(ns, &htab_flagspaces))) {
579    do_rawlog(LT_ERR, T("FLAG READ: Unable to locate flagspace %s."), ns);
580    return;
581  }
582  /* If we are reading flags from the db, they are definitive. */
583  clear_all_flags(n);
584  while ((f = flag_read_oldstyle(in))) {
585    flag_add(n, f->name, f);
586  }
587  /* Assumes we'll always have at least one alias */
588  while ((f = flag_alias_read_oldstyle(in, alias, n))) {
589    flag_add(n, alias, f);
590  }
591  flag_add_additional(n);
592}
593
594/* Read in a flag from a file and return it */
595static FLAG *
596flag_read(FILE * in)
597{
598  FLAG *f;
599  char *c;
600  char *tmp;
601
602  db_read_this_labeled_string(in, "name", &tmp);
603  c = mush_strdup(tmp, "flag.name");
604  f = new_flag();
605  f->name = c;
606  db_read_this_labeled_string(in, "letter", &tmp);
607  f->letter = *tmp;
608  f->bitpos = -1;
609  db_read_this_labeled_string(in, "type", &tmp);
610  f->type = string_to_privs(type_privs, tmp, 0);
611  db_read_this_labeled_string(in, "perms", &tmp);
612  f->perms = F_REF_NOT & string_to_privs(flag_privs, tmp, 0);
613  db_read_this_labeled_string(in, "negate_perms", &tmp);
614  f->negate_perms = string_to_privs(flag_privs, tmp, 0);
615  return f;
616}
617
618static FLAG *
619flag_alias_read(FILE * in, char *alias, FLAGSPACE *n)
620{
621  FLAG *f;
622  char *c;
623  char *tmp;
624  /* Real name first */
625  db_read_this_labeled_string(in, "name", &tmp);
626  c = mush_strdup(tmp, "flag alias");
627  f = match_flag_ns(n, c);
628  if (!f) {
629    /* Corrupt db. Recover as well as we can. */
630    do_rawlog(LT_ERR,
631              T
632              ("FLAG READ: flag alias %s matches no known flag. Skipping this alias."),
633              c);
634    mush_free(c, "flag alias");
635    (void) getstring_noalloc(in);
636    return NULL;
637  } else
638    mush_free(c, "flag alias");
639
640  /* Get the alias name */
641  db_read_this_labeled_string(in, "alias", &tmp);
642  strcpy(alias, tmp);
643  return f;
644}
645
646/** Read flags and aliases from the database. This function expects
647 * to receive file pointer that's already reading in a database file
648 * and pointing at the start of the flag table. It reads the flags,
649 * reads the aliases, and then does any additional flag adding that
650 * needs to happen.
651 * \param in file pointer to read from.
652 * \param ns name of namespace to search.
653 */
654void
655flag_read_all(FILE * in, const char *ns)
656{
657  FLAG *f;
658  FLAGSPACE *n;
659  char alias[BUFFER_LEN];
660  int count, found = 0;
661
662  if (!(globals.indb_flags & DBF_LABELS)) {
663    flag_read_all_oldstyle(in, ns);
664    return;
665  }
666
667  if (!(n = (FLAGSPACE *) hashfind(ns, &htab_flagspaces))) {
668    do_rawlog(LT_ERR, T("FLAG READ: Unable to locate flagspace %s."), ns);
669    return;
670  }
671  /* If we are reading flags from the db, they are definitive. */
672  clear_all_flags(n);
673  db_read_this_labeled_int(in, "flagcount", &count);
674  for (;;) {
675    int c;
676
677    c = fgetc(in);
678    ungetc(c, in);
679
680    if (c != ' ')
681      break;
682
683    found++;
684
685    if ((f = flag_read(in)))
686      flag_add(n, f->name, f);
687