PennMUSH Community

Changeset 1162

Show
Ignore:
Timestamp:
11/24/07 02:24:13 (10 months ago)
Author:
shawnw
Message:

#5822: Dynamic switch table

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • 1.8.3/branches/devel/CHANGES.183

    r1157 r1162  
    3434 * A wildcard help topic search (help foo*) that only matches one 
    3535   entry will display that entry. Suggested by Cheetah. 
     36 * New switches for commands no longer have to be added to the 
     37   SWITCHES file; the internal list of switches is now built based on 
     38   what switches are given in the command table and cmdlocal.c 
     39   additions. Suggested by Talek.  
     40 
    3641 
    3742Flags and powers: 
  • 1.8.3/branches/devel/hdrs/command.h

    r905 r1162  
    22#define __COMMAND_H 
    33 
    4 #define NUM_BYTES 20 
    5 typedef unsigned char switch_mask[NUM_BYTES]; 
     4 
     5typedef uint8_t *switch_mask; 
     6extern int switch_bytes; 
     7#define SW_ALLOC()      mush_calloc(switch_bytes, 1, "cmd.switch.vector"); 
     8#define SW_FREE(s)      mush_free((s), "cmd.switch.vector"); 
    69#define SW_SET(m,n)     (m[(n) >> 3] |= (1 << ((n) & 0x7))) 
    710#define SW_CLR(m,n)     (m[(n) >> 3] &= ~(1 << ((n) & 0x7))) 
    811#define SW_ISSET(m,n)   (m[(n) >> 3] & (1 << ((n) & 0x7))) 
    9 #define SW_ZERO(m)      memset(m, 0, NUM_BYTES) 
     12bool SW_BY_NAME(switch_mask, const char *); 
     13#define SW_ZERO(m)      memset(m, 0, switch_bytes) 
     14#define SW_COPY(new,old) memcpy((new), (old), switch_bytes) 
    1015 
    1116/* These are type restrictors */ 
     
    129134  object_flag_type flagmask;    /**< Flags to which the command is restricted */ 
    130135  object_flag_type powers;      /**< Powers to which the command is restricted */ 
    131   switch_mask sw;       /**< Bitflags of switches this command can take */ 
     136  /** Switches for this command. */ 
     137  union { 
     138    switch_mask mask;       /**< Bitflags of switches this command can take */ 
     139    const char *names; /**< Space-seperated list of switches */ 
     140  } sw; 
    132141  /** Hooks on this command. 
    133142   */ 
     
    189198#include "switches.h" 
    190199 
    191 extern switch_mask *switchmask(const char *switches); 
    192 extern COMMAND_INFO *command_find(const char *name); 
    193 extern COMMAND_INFO *command_find_exact(const char *name); 
    194 extern COMMAND_INFO *command_add 
     200switch_mask switchmask(const char *switches); 
     201COMMAND_INFO *command_find(const char *name); 
     202COMMAND_INFO *command_find_exact(const char *name); 
     203COMMAND_INFO *command_add 
    195204  (const char *name, int type, const char *flagstr, const char *powers, 
    196205   const char *switchstr, command_func func); 
    197 extern COMMAND_INFO *make_command 
     206COMMAND_INFO *make_command 
    198207  (const char *name, int type, object_flag_type flagmask, 
    199    object_flag_type powers, switch_mask *sw, command_func func); 
    200 extern COMMAND_INFO *command_modify(const char *name, int type, 
    201                                     object_flag_type flagmask, 
    202                                     object_flag_type powers, switch_mask *sw, 
    203                                     command_func func); 
    204 extern void reserve_alias(const char *a); 
    205 extern int alias_command(const char *command, const char *alias); 
    206 extern void command_init_preconfig(void); 
    207 extern void command_init_postconfig(void); 
    208 extern void command_splitup 
     208   object_flag_type powers, const char *sw, command_func func); 
     209COMMAND_INFO *command_modify(const char *name, int type, 
     210                             object_flag_type flagmask, 
     211                             object_flag_type powers, switch_mask sw, 
     212                             command_func func); 
     213void reserve_alias(const char *a); 
     214int alias_command(const char *command, const char *alias); 
     215void command_init_preconfig(void); 
     216void command_init_postconfig(void); 
     217void command_splitup 
    209218  (dbref player, dbref cause, char *from, char *to, char **args, 
    210219   COMMAND_INFO *cmd, int side); 
    211 extern void command_argparse 
     220void command_argparse 
    212221  (dbref player, dbref cause, char **from, char *to, char **argv, 
    213222   COMMAND_INFO *cmd, int side, int forcenoparse); 
    214 extern char *command_parse 
    215   (dbref player, dbref cause, char *string, int fromport); 
    216 extern void do_list_commands(dbref player, int lc); 
    217 extern char *list_commands(void); 
    218 extern int command_check_byname(dbref player, const char *name); 
    219 extern int restrict_command(const char *name, const char *restriction); 
    220 extern void reserve_aliases(void); 
    221 extern void local_commands(void); 
    222 extern void do_command_add(dbref player, char *name, int flags); 
    223 extern void do_command_delete(dbref player, char *name); 
     223char *command_parse(dbref player, dbref cause, char *string, int fromport); 
     224void do_list_commands(dbref player, int lc); 
     225char *list_commands(void); 
     226int command_check_byname(dbref player, const char *name); 
     227int restrict_command(const char *name, const char *restriction); 
     228void reserve_aliases(void); 
     229void local_commands(void); 
     230void do_command_add(dbref player, char *name, int flags); 
     231void do_command_delete(dbref player, char *name); 
    224232 
    225233 
  • 1.8.3/branches/devel/hdrs/strtree.h

    r905 r1162  
    3737void st_delete(char const *s, StrTree *root); 
    3838void st_print(StrTree *root); 
     39typedef void (*STFunc) (const char *, int, void *); 
     40void st_walk(StrTree *, STFunc, void *); 
    3941void st_flush(StrTree *root); 
    4042 
  • 1.8.3/branches/devel/src/cmdlocal.dst

    r905 r1162  
     1/* -*- c -*- 
    12/*----------------------------------------------------------------- 
    23 * Local stuff 
     
    5354  if (SW_ISSET(sw, SWITCH_NOISY)) 
    5455    notify_format(player, "Noisy silly with %s", arg_left); 
     56  if (SW_BY_NAME(sw, "VERY")) 
     57    notify(player, "The following line will be very silly indeed."); 
    5558  notify_format(player, "SillyCommand %s", arg_left); 
    5659} 
     
    7679{ 
    7780#ifdef EXAMPLE 
    78   command_add("@SILLY", CMD_T_ANY, "WIZARD ROYALTY", "SEE_ALL", "NOISY NOEVAL", 
    79               cmd_local_silly); 
     81  command_add("@SILLY", CMD_T_ANY, "WIZARD ROYALTY", "SEE_ALL", 
     82              "NOISY NOEVAL VERY", cmd_local_silly); 
    8083#endif 
    8184} 
  • 1.8.3/branches/devel/src/command.c

    r1150 r1162  
    1414 
    1515#include <string.h> 
     16#include <assert.h> 
     17#include <stdlib.h> 
    1618 
    1719#include "conf.h" 
     
    2830#include "ptab.h" 
    2931#include "htab.h" 
     32#include "strtree.h" 
    3033#include "function.h" 
    3134#include "command.h" 
     
    4649static const char *command_isattr(char *command); 
    4750static int command_check(dbref player, COMMAND_INFO *cmd); 
    48 static int switch_find(COMMAND_INFO *cmd, char *sw); 
     51static int switch_find(COMMAND_INFO *cmd, const char *sw); 
    4952static void strccat(char *buff, char **bp, const char *from); 
    5053static int has_hook(struct hook_data *hook); 
    51 extern int global_fun_invocations;      /**< Counter for function invocations */ 
     54extern int global_fun_invocations;      /**< Counter for function invocations */ 
    5255extern int global_fun_recursions;       /**< Counter for function recursion */ 
     56 
     57SWITCH_VALUE *dyn_switch_list = NULL; 
     58int switch_bytes = 0; 
     59size_t num_switches = 0; 
     60 
     61enum command_load_state { CMD_LOAD_BUILTIN, 
     62  CMD_LOAD_LOCAL, 
     63  CMD_LOAD_DONE 
     64}; 
     65static enum command_load_state command_state = CMD_LOAD_BUILTIN; 
     66static StrTree switch_names; 
    5367 
    5468int run_hook(dbref player, dbref cause, struct hook_data *hook, 
     
    396410}; 
    397411 
    398  
    399412static void 
    400413strccat(char *buff, char **bp, const char *from) 
     
    404417  safe_str(from, buff, bp); 
    405418} 
     419 
     420/* Comparison function for bsearch() */ 
    406421static int 
    407 switch_find(COMMAND_INFO *cmd, char *sw) 
     422switch_cmp(const void *a, const void *b) 
     423
     424  const char *name = a; 
     425  const SWITCH_VALUE *sw = b; 
     426  return strcmp(name, sw->name); 
     427
     428 
     429/* This has different semantics than a prefix table, or we'd use that. */ 
     430static int 
     431switch_find(COMMAND_INFO *cmd, const char *sw) 
    408432{ 
    409433  SWITCH_VALUE *sw_val; 
    410   int i = 0; 
    411   int len; 
    412   if (!sw || !*sw) 
     434 
     435  if (!sw || !*sw || !dyn_switch_list) 
    413436    return 0; 
    414   len = strlen(sw); 
    415   /* Special case, for init */ 
    416   sw_val = switch_list; 
     437 
    417438  if (!cmd) { 
     439    sw_val = bsearch(sw, dyn_switch_list, num_switches, sizeof(SWITCH_VALUE), 
     440                     switch_cmp); 
     441    if (sw_val) 
     442      return sw_val->value; 
     443    else 
     444      return 0; 
     445  } else { 
     446    size_t len = strlen(sw); 
     447    sw_val = dyn_switch_list; 
    418448    while (sw_val->name) { 
    419       if (strcmp(sw_val->name, sw) == 0) 
     449      if (SW_ISSET(cmd->sw.mask, sw_val->value) 
     450          && (strncmp(sw_val->name, sw, len) == 0)) 
    420451        return sw_val->value; 
    421452      sw_val++; 
    422453    } 
    423     return 0; 
    424   } else { 
    425     while (sw_val->name) { 
    426       i++; 
    427       if (SW_ISSET(cmd->sw, i) && (strncmp(sw_val->name, sw, len) == 0)) 
    428         return i; 
    429       sw_val++; 
    430     } 
    431454  } 
    432455  return 0; 
     456} 
     457 
     458/** Test if a particular switch was given, using name 
     459 * \param sw the switch mask to test 
     460 * \param name the name of the switch to test for. 
     461 */ 
     462bool 
     463SW_BY_NAME(switch_mask sw, const char *name) 
     464{ 
     465  int idx = switch_find(NULL, name); 
     466  if (idx) 
     467    return SW_ISSET(sw, idx); 
     468  else 
     469    return false; 
    433470} 
    434471 
     
    448485make_command(const char *name, int type, 
    449486             object_flag_type flagmask, object_flag_type powers, 
    450              switch_mask *sw, command_func func) 
     487             const char *sw, command_func func) 
    451488{ 
    452489  COMMAND_INFO *cmd; 
     
    459496  cmd->flagmask = flagmask; 
    460497  cmd->powers = powers; 
    461   if (sw) 
    462     memcpy(cmd->sw, sw, sizeof(switch_mask)); 
    463   else 
    464     SW_ZERO(cmd->sw); 
     498  switch (command_state) { 
     499  case CMD_LOAD_BUILTIN: 
     500    cmd->sw.names = sw; 
     501    break; 
     502  case CMD_LOAD_LOCAL:{ 
     503      char sw_copy[BUFFER_LEN]; 
     504      char *pos; 
     505      cmd->sw.names = sw; 
     506      mush_strncpy(sw_copy, sw, BUFFER_LEN); 
     507      pos = sw_copy; 
     508      while (pos) { 
     509        char *thisone = split_token(&pos, ' '); 
     510        st_insert(thisone, &switch_names); 
     511      } 
     512      break; 
     513    } 
     514  case CMD_LOAD_DONE:{ 
     515      switch_mask mask = switchmask(sw); 
     516      if (mask) { 
     517        cmd->sw.mask = SW_ALLOC(); 
     518        SW_COPY(cmd->sw.mask, mask); 
     519      } else 
     520        cmd->sw.mask = NULL; 
     521    } 
     522  } 
    465523  cmd->hooks.before.obj = NOTHING; 
    466524  cmd->hooks.before.attrname = NULL; 
     
    489547{ 
    490548  object_flag_type flagmask = NULL, powers = NULL; 
    491   switch_mask *sw = switchmask(switchstr); 
    492549 
    493550  if (flagstr) 
     
    496553    powers = string_to_bits("POWER", powerstr); 
    497554  ptab_insert_one(&ptab_command, name, 
    498                   make_command(name, type, flagmask, powers, sw, func)); 
     555                  make_command(name, type, flagmask, powers, switchstr, func)); 
    499556  return command_find(name); 
    500557} 
     
    556613command_modify(const char *name, int type, 
    557614               object_flag_type flagmask, object_flag_type powers, 
    558                switch_mask *sw, command_func func) 
     615               switch_mask sw, command_func func) 
    559616{ 
    560617  COMMAND_INFO *cmd; 
     
    569626    cmd->powers = powers; 
    570627  if (sw) 
    571     memcpy(cmd->sw, sw, sizeof(switch_mask)); 
     628    SW_COPY(cmd->sw.mask, sw); 
    572629  if (func) 
    573630    cmd->func = func; 
     
    581638 * \return pointer to a static switch mask. 
    582639 */ 
    583 switch_mask * 
     640switch_mask 
    584641switchmask(const char *switches) 
    585642{ 
    586   static switch_mask sw; 
     643  static switch_mask sw = NULL; 
     644  static int sm_bytes = 0; 
    587645  char buff[BUFFER_LEN]; 
    588646  char *p, *s; 
    589647  int switchnum; 
     648 
     649  if (sm_bytes < switch_bytes) { 
     650    sw = mush_realloc(sw, switch_bytes, "cmd.switch.vector"); 
     651    sm_bytes = switch_bytes; 
     652  } 
     653 
    590654  SW_ZERO(sw); 
    591655  if (!switches || !switches[0]) 
     
    601665      SW_SET(sw, switchnum); 
    602666  } 
    603   return &sw; 
     667  return sw; 
    604668} 
    605669 
     
    617681  hashadd(strupper(a), (void *) placeholder, &htab_reserved_aliases); 
    618682} 
     683 
     684static StrTree switch_names; 
    619685 
    620686/** Initialize command tables (before reading config file). 
     
    632698  struct command_perms_t *c; 
    633699  COMLIST *cmd; 
     700  SWITCH_VALUE *sv; 
    634701  static int done = 0; 
    635702  if (done == 1) 
     
    639706  ptab_init(&ptab_command); 
    640707  hashinit(&htab_reserved_aliases, 16); 
     708 
     709  /* Build initial switch table. */ 
     710  st_init(&switch_names); 
     711  for (sv = switch_list; sv->name; sv++) 
     712    st_insert(sv->name, &switch_names); 
     713 
    641714  command_slab = slab_create("commands", sizeof(COMMAND_INFO)); 
    642715  reserve_aliases(); 
     716 
    643717  ptab_start_inserts(&ptab_command); 
     718  command_state = CMD_LOAD_BUILTIN; 
    644719  for (cmd = commands; cmd->name; cmd++) { 
     720    if (cmd->switches) { 
     721      char sw_copy[BUFFER_LEN]; 
     722      char *pos; 
     723      strcpy(sw_copy, cmd->switches); 
     724      pos = sw_copy; 
     725      while (pos) { 
     726        char *sw = split_token(&pos, ' '); 
     727        st_insert(sw, &switch_names); 
     728      } 
     729    } 
    645730    ptab_insert(&ptab_command, cmd->name, 
    646731                make_command(cmd->name, cmd->type, 
    647732                             string_to_bits("FLAG", cmd->flagstr), 
    648733                             string_to_bits("POWER", cmd->powers), 
    649                              switchmask(cmd->switches), cmd->func)); 
     734                             cmd->switches, cmd->func)); 
    650735  } 
    651736  ptab_end_inserts(&ptab_command); 
     
    657742  ptab_end_inserts(&ptab_command_perms); 
    658743 
     744  command_state = CMD_LOAD_LOCAL; 
    659745  local_commands(); 
     746} 
     747 
     748struct bst_data { 
     749  SWITCH_VALUE *table; 
     750  size_t n; 
     751  size_t start; 
     752}; 
     753 
     754static void 
     755build_switch_table(const char *sw, int count __attribute__ ((__unused__)), 
     756                   void *d) 
     757{ 
     758  SWITCH_VALUE *s; 
     759  struct bst_data *data = d; 
     760 
     761  for (s = switch_list; s->name; s++) { 
     762    if (strcmp(s->name, sw) == 0) { 
     763      data->table[data->n++] = *s; 
     764      return; 
     765    } 
     766  } 
     767  /* Not in switchinc.c table */ 
     768  data->table[data->n].value = data->start++; 
     769  data->table[data->n++].name = mush_strdup(sw, "switch.name"); 
    660770} 
    661771 
     
    668778command_init_postconfig(void) 
    669779{ 
     780  struct bst_data sw_data; 
     781  COMMAND_INFO *c; 
     782  size_t sl_size; 
     783 
     784  command_state = CMD_LOAD_DONE; 
     785 
     786  /* First make the switch table */ 
     787  dyn_switch_list = mush_calloc(switch_names.count + 2, sizeof(SWITCH_VALUE), 
     788                                "cmd_switch_table"); 
     789  if (!dyn_switch_list) 
     790    mush_panic(T("Unable to allocate command switch table")); 
     791  sw_data.table = dyn_switch_list; 
     792  sw_data.n = 0; 
     793  sw_data.start = sizeof switch_list / sizeof(SWITCH_VALUE); 
     794  sl_size = sw_data.start - 2; 
     795  st_walk(&switch_names, build_switch_table, &sw_data); 
     796  num_switches = sw_data.start; 
     797  dyn_switch_list[sw_data.n].name = NULL; 
     798  st_flush(&switch_names); 
     799  switch_bytes = ceil((double) num_switches / 8.0); 
     800 
     801  /* Then convert the list of switch names in all commands to masks */ 
     802  for (c = ptab_firstentry(&ptab_command); c; c = ptab_nextentry(&ptab_command)) { 
     803    const char *switchstr = c->sw.names; 
     804    if (switchstr) { 
     805      c->sw.mask = SW_ALLOC(); 
     806      SW_COPY(c->sw.mask, switchmask(switchstr)); 
     807    } 
     808  } 
     809 
    670810  return; 
    671811} 
     
    8691009  char b; 
    8701010  int switchnum; 
    871   switch_mask sw
     1011  switch_mask sw = NULL
    8721012  char switch_err[BUFFER_LEN], *se; 
    8731013  int noeval; 
     
    8771017  rhs_present = 0; 
    8781018 
    879   command = (char *) mush_malloc(BUFFER_LEN, "string"); 
    880   swtch = (char *) mush_malloc(BUFFER_LEN, "string"); 
    881   ls = (char *) mush_malloc(BUFFER_LEN, "string"); 
    882   rs = (char *) mush_malloc(BUFFER_LEN, "string"); 
    883   switches = (char *) mush_malloc(BUFFER_LEN, "string"); 
     1019  command = mush_malloc(BUFFER_LEN, "string"); 
     1020  swtch = mush_malloc(BUFFER_LEN, "string"); 
     1021  ls = mush_malloc(BUFFER_LEN, "string"); 
     1022  rs = mush_malloc(BUFFER_LEN, "string"); 
     1023  switches = mush_malloc(BUFFER_LEN, "string"); 
    8841024  if (!command || !swtch || !ls || !rs || !switches) 
    8851025    mush_panic("Couldn't allocate memory in command_parse"); 
     
    10621202  } 
    10631203  /* Parse out any switches */ 
    1064   SW_ZERO(sw); 
     1204  sw = SW_ALLOC(); 
    10651205  swp = switches; 
    10661206  *swp = '\0'; 
     
    12271367  } 
    12281368 
     1369  SW_FREE(sw); 
    12291370  command_parse_free_args; 
    12301371  return retval; 
     
    16201761    buff[0] = '\0'; 
    16211762    notify(player, show_command_flags(command->flagmask, command->powers)); 
    1622     bp = buff; 
    1623     for (sw_val = switch_list; sw_val->name; sw_val++) 
    1624       if (SW_ISSET(command->sw, sw_val->value)) 
    1625         strccat(buff, &bp, sw_val->name); 
    1626     *bp = '\0'; 
    1627     notify_format(player, "Switches   : %s", buff); 
     1763    if (command->sw.mask) { 
     1764      bp = buff; 
     1765      for (sw_val = dyn_switch_list; sw_val->name; sw_val++) 
     1766        if (SW_ISSET(command->sw.mask, sw_val->value)) 
     1767          strccat(buff, &bp, sw_val->name); 
     1768      *bp = '\0'; 
     1769      notify_format(player, "Switches   : %s", buff); 
     1770    } else 
     1771      notify(player, "Switches   :"); 
    16281772    buff[0] = '\0'; 
    16291773    bp = buff; 
  • 1.8.3/branches/devel/src/strtree.c

    r905 r1162  
    531531} 
    532532 
     533static void 
     534st_node_walk(StrNode *node, STFunc callback, void *data) 
     535{ 
     536  if (node->left) 
     537    st_node_walk(node->left, callback, data); 
     538  callback(node->string, node->info >> ST_COLOR, data); 
     539  if (node->right) 
     540    st_node_walk(node->right, callback, data); 
     541} 
     542 
     543/** Call a function for each node in the tree, in-order */ 
     544void 
     545st_walk(StrTree *tree, STFunc callback, void *data) 
     546{ 
     547  if (!tree || !tree->root) 
     548    return; 
     549  st_node_walk(tree->root, callback, data); 
     550} 
     551 
    533552/* Print the tree, for debugging purposes. */ 
    534553static void 
     
    589608    (*perms)++; 
    590609  else 
    591     (*nperms) += node->info
     610    (*nperms) += node->info >> ST_COLOR
    592611 
    593612  if (count > *maxdepth)