| 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 | |
|---|
| 56 | static int can_set_flag(dbref player, dbref thing, FLAG *flagp, int negate); |
|---|
| 57 | static FLAG *letter_to_flagptr(FLAGSPACE *n, char c, int type); |
|---|
| 58 | static void flag_add(FLAGSPACE *n, const char *name, FLAG *f); |
|---|
| 59 | static int has_flag_ns(FLAGSPACE *n, dbref thing, FLAG *f); |
|---|
| 60 | |
|---|
| 61 | static FLAG *flag_read(FILE * in); |
|---|
| 62 | static FLAG *flag_read_oldstyle(FILE * in); |
|---|
| 63 | static void flag_read_all_oldstyle(FILE * in, const char *ns); |
|---|
| 64 | static void flag_write(FILE * out, FLAG *f, const char *name); |
|---|
| 65 | static FLAG *flag_hash_lookup(FLAGSPACE *n, const char *name, int type); |
|---|
| 66 | static FLAG *clone_flag(FLAG *f); |
|---|
| 67 | static FLAG *new_flag(void); |
|---|
| 68 | static void flag_add_additional(FLAGSPACE *n); |
|---|
| 69 | static char *list_aliases(FLAGSPACE *n, FLAG *given); |
|---|
| 70 | static void realloc_object_flag_bitmasks(FLAGSPACE *n); |
|---|
| 71 | static FLAG *match_flag_ns(FLAGSPACE *n, const char *name); |
|---|
| 72 | |
|---|
| 73 | PTAB ptab_flag; /**< Table of flags by name, inc. aliases */ |
|---|
| 74 | PTAB ptab_power; /**< Table of powers by name, inc. aliases */ |
|---|
| 75 | HASHTAB htab_flagspaces; /**< Hash of flagspaces */ |
|---|
| 76 | slab *flag_slab = NULL; |
|---|
| 77 | extern 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 */ |
|---|
| 87 | static 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 | */ |
|---|
| 155 | static 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 | */ |
|---|
| 170 | static 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. */ |
|---|
| 179 | static 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 | */ |
|---|
| 191 | static 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 */ |
|---|
| 219 | static 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. */ |
|---|
| 254 | static 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. */ |
|---|
| 262 | static 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 | */ |
|---|
| 288 | FLAG * |
|---|
| 289 | match_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 | */ |
|---|
| 299 | FLAG * |
|---|
| 300 | match_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 | */ |
|---|
| 310 | static FLAG * |
|---|
| 311 | match_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 | */ |
|---|
| 326 | static FLAG * |
|---|
| 327 | flag_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 */ |
|---|
| 357 | static FLAG * |
|---|
| 358 | new_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 */ |
|---|
| 371 | static void |
|---|
| 372 | clear_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 | |
|---|
| 394 | static FLAG * |
|---|
| 395 | clone_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 | */ |
|---|
| 413 | static void |
|---|
| 414 | flag_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 | |
|---|
| 468 | static void |
|---|
| 469 | realloc_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 */ |
|---|
| 511 | static FLAG * |
|---|
| 512 | flag_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 | |
|---|
| 532 | static FLAG * |
|---|
| 533 | flag_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 | */ |
|---|
| 571 | static void |
|---|
| 572 | flag_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 */ |
|---|
| 595 | static FLAG * |
|---|
| 596 | flag_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 | |
|---|
| 618 | static FLAG * |
|---|
| 619 | flag_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 | */ |
|---|
| 654 | void |
|---|
| 655 | flag_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 |
|---|