Began Core Hook System. this will be the basis as a replacement for how
authorRick L Bird <nveid@yahoo.com>
Tue, 10 May 2011 09:52:09 +0000 (05:52 -0400)
committerRick L Bird <nveid@yahoo.com>
Tue, 10 May 2011 09:52:09 +0000 (05:52 -0400)
C modules, lua extensions, and SC events will all be called from.

Right now I only have one example Hook, and thats for @log's to the SC.
@event LOG_ALL=<OBJ>/<ATR> to see how it works.

Still need to write actual C module & lua interfaces to this system.

Refs #3

hdrs/modules.h
src/bsd.c
src/command.c
src/game.c
src/log.c
src/modules.c

index dfc2f94a7f58ff1ce21c63ea2ffa3df1fdba6c7f..f678af3b6e5d81819b475e024846f7e326a8945f 100644 (file)
@@ -1,24 +1,97 @@
-/* CobraMUSH Module System based upon cross-platform libldl */
+/* CobraMUSH Module System based upon cross-platform libldl
+ */
 #ifndef _MODULES_H_
 #define _MODULES_H_
+#include <stdarg.h>
 
-struct module_entry_t {
-  char *name; /* Name of module */
-  char *info; /* Short Description */
-  float version; /* Version of Module */
-  int (*load)(struct module_entry_t *); /* Load Function */
-  int (*unload)(struct module_entry_t *); /* Unload function */
+/* Externs */
+extern HASHTAB chook_htab;
+
+/* This is the linked list entry for each hash event */
+struct core_entry_t
+{
+  char flags;                  /* Individual Hook Flags */
+  char priority;               /* Priority 0-10 */
+  void *data;                  /* Handler of type of event */
+  struct core_entry_t *next;
+  struct core_entry_t *prev;
+  struct core_hook_t *up;
+};
+
+/* Priority levels: */
+#define MODHOOK_PRI_LOW        0       /* Lowest Priority */
+#define MODHOOK_PRI_SC         2       /* Default SoftCode Priority */
+#define MODHOOK_PRI_HIGH       10      /* Highest Priority */
+
+/* Flags for how the hook is executed */
+#define MODHOOK_SOFTCODE       0x01    /* Use the Softcode hook interface */
+#define MODHOOK_MODULE         0x02    /* Use the Module hook interface */
+#define MODHOOK_LUA            0x04    /* Use the lua interface to execute */
+
+struct core_hook_t
+{
+  const char *key;             /* Hook Name for all of this */
+  char flags;                  /* Hook flags */
+  struct core_entry_t *hooks;  /* Points to first hook in list.. highest priority */
+};
+/* Flags for overall hook information */
+#define MODHOOK_NONE           0x0     /* No special values */
+#define MODHOOK_INTRET         0x01    /* The call hook will return an int value */
+#define MODHOOK_CHARRET                0x02    /* the call hook will return a char string */
+#define MODHOOK_AROUND         0x04    /* The call hook is an around method.. Take the highest priority & stop */
+#define MODHOOK_AFTER          0x08
+#define MODHOOK_BEFORE         0x10
+
+/* And now our table to load all our chooks at first */
+struct chook_table_t {
+  const char *key; /* This is the internal key we'll use to reference it */
+  const char *mush_key; /* If we're a SC Hook, this is the SC Hook name. This will primarily exist in a small htab that just points to the regular key. */
+  char flags;
+};
+
+
+/* Entry for softcode core hook */
+struct softcode_hook
+{
+  dbref obj;                           /* Object to Execute */
+  char attribute[ATTRIBUTE_NAME_LIMIT];         /* Attribute Name to Execute */
+};
+
+/* Entry for Module core hook */
+struct module_hook {
+  void *func;                   /* This will serve as storage for our function ptr */
+  struct module_entry_t *module; /* Incase the hook needs to reference back to the module */
+};
+
+
+/* Our Table of loaded modules */
+struct module_entry_t
+{
+  char *name;                  /* Name of module */
+  char *info;                  /* Short Description */
+  float version;               /* Version of Module */
+  int (*load) (struct module_entry_t *);       /* Load Function */
+  int (*unload) (struct module_entry_t *);     /* Unload function */
   void *handle;
   struct module_entry_t *next;
 };
 
-struct module_entry_t *module_entry_add(char *name);
-int module_entry_del(struct module_entry_t *entry);
-int modules_init(void);
-int module_open(char *path, char *name);
-int module_close(struct module_entry_t *m);
-int modules_shutdown(void);
+/* Module Functions */
+struct module_entry_t *module_entry_add (char *name);
+int module_entry_del (struct module_entry_t *entry);
+int modules_init (void);
+int module_open (char *path, char *name);
+int module_close (struct module_entry_t *m);
+int modules_shutdown (void);
 
+/* Core Hook Functions */
+void CHooks_Init ();           /* Initialize the Core Hook interface */
+struct core_hook_t *CHook_Create (const char *key, int flags); /* Create a CHook */
+struct core_entry_t *CHook_Insert (const char *key, char priority, int flags, void *data);     /* inserts an individual piece of data in hook table */
+int CHook_Delete(struct core_entry_t *entry);
+int CHook_Run (struct core_entry_t *entry, char *format, ...); /* Given a chook entry executes it however it suppose to be executed.. */
+int CHook_SC(struct core_entry_t *entry, char *format, va_list args); /* Execution function to run SC associated with a hook */
+int CHook_Insert_Module(char *key, char priority, struct module_hook *hook); /* Insert a module hook */ 
 
 /* Iterate through Module List */
 #define MODULE_ITER(m) for(m = module_list ; m != NULL ; m = m->next)
@@ -41,4 +114,5 @@ int modules_shutdown(void);
 
 #define MODULE_FUNCPTR(var, m, func) *((void **) (&var)) = lt_dlsym(m, func)
 
+
 #endif /* _MODULES_H_ */
index fd3c3e66e044743d98f6004d6ef54021afcf50c0..ec3f02a77de29f33a72321875b5d4c813e71315c 100644 (file)
--- a/src/bsd.c
+++ b/src/bsd.c
@@ -625,9 +625,6 @@ main(int argc, char **argv)
 
   options.mem_check = 1;
 
-  /* Initialize Module interface */
-  modules_init();
-
   /* If we have setlocale, call it to set locale info
    * from environment variables
    */
index 0c91faeb0232514f59826f802623ab2388a1d925..0f76307b36aca57725b4ff167ffcd9a039410cad 100644 (file)
@@ -154,6 +154,7 @@ COMLIST commands[] = {
    CMD_T_NOGAGGED, NULL},
   {"@ELOCK", NULL, cmd_elock, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_NOGAGGED,
    NULL},
+  {"@EVENT", NULL, cmd_event, CMD_T_ANY | CMD_T_EQSPLIT, "POWER^SITE"},
   {"@EMIT", "ROOM NOEVAL SILENT SPOOF", cmd_emit, CMD_T_ANY | CMD_T_NOGAGGED, NULL},
   {"@EMPOWER", NULL, cmd_empower, CMD_T_ANY | CMD_T_EQSPLIT, "POWER^EMPOWER"},
   {"@ENABLE", NULL, cmd_enable, CMD_T_ANY | CMD_T_NOGAGGED, "POWER^SITE"},
index 4ed9440fc40ff34f8cf92c785455917cea0fc9fc..abf3a29f96f5ff374629a419632ee2ff4778c5fa 100644 (file)
@@ -761,6 +761,9 @@ init_game_config(const char *conf)
   /* initialize random number generator */
   initialize_mt();
 
+  CHooks_Init(); /* Initialize Core Hooks */
+  modules_init(); /* Initialize Module Interface */
+
   init_queue();
 
   global_eval_context.process_command_port = 0;
index e30c09bf0c31445b1fcdc6016e8b553b9e1df3e7..4ec8e8b32e684ad8b248fbcfea5b5f54b8289d9c 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -36,6 +36,7 @@
 #include "htab.h"
 #include "bufferq.h"
 #include "log.h"
+#include "modules.h"
 
 static char *quick_unparse(dbref object);
 static void start_log(FILE ** fp, const char *filename);
@@ -191,6 +192,8 @@ end_all_logs(void)
 void WIN32_CDECL
 do_rawlog(int logtype, const char *fmt, ...)
 {
+  struct core_hook_t *chook;
+  struct core_entry_t *centry;
   struct tm *ttm;
   char timebuf[18];
   char tbuf1[BUFFER_LEN + 50];
@@ -239,6 +242,10 @@ do_rawlog(int logtype, const char *fmt, ...)
     f = stderr;
     break;
   }
+  if((chook = (struct core_hook_t *) hashfind("LOG_ALL.AFTER", &chook_htab))) {
+    for(centry = chook->hooks; centry != NULL ; centry = centry->next)
+      CHook_Run(centry, "%# %d %s", global_eval_context.cplr, logtype, tbuf1);
+  }
   lock_file(f);
   fprintf(f, "%s %s\n", timebuf, tbuf1);
   fflush(f);
index 9e538df0e4650d6506bc15e85af6e029ed4230ce..6a0581fc574b5fc33e62c66b93f6bba5c3863798 100644 (file)
@@ -8,6 +8,7 @@
 #include <string.h>
 #include <ltdl.h>
 #include <ctype.h>
+#include <signal.h>
 #include "config.h"
 
 #include "conf.h"
 #include "switches.h"
 #include "mushtype.h"
 #include "log.h"
+#include "htab.h"
+#include "attrib.h"
+#include "parse.h"
+#include "match.h"
 #include "modules.h"
 
 struct module_entry_t *module_list = NULL;
+HASHTAB chook_htab;
+HASHTAB chook_mevents; /* MUSH Events aliased to Hooks */
+extern sig_atomic_t cpu_time_limit_hit; /**< Have we used too much CPU? */
+
+
+struct chook_table_t chook_tab[] = {
+  /* Key,       MUSH Event Name(or NULL if not),  flags */
+  {"DUMP_5MIN.AROUND", "DUMP_5MIN", MODHOOK_AROUND}, /* Overrides the default 5min message */
+  {"DUMP_1MIN.AROUND", "DUMP_1MIN", MODHOOK_AROUND}, /* Overrides teh default 1min message */ 
+  {"PCREATE.AROUND", NULL, MODHOOK_AROUND},
+  {"PCREATE.BEFORE", NULL, MODHOOK_BEFORE},
+  {"PCREATE.AFTER", "PCREATE", MODHOOK_AFTER},
+  {"LOG_ALL.AFTER", "LOG_ALL", MODHOOK_AFTER}, 
+  {"OBJECT_CREATE.AROUND", NULL, MODHOOK_AROUND | MODHOOK_INTRET},
+  {"OBJECT_CREATE.BEFORE", NULL, MODHOOK_BEFORE | MODHOOK_INTRET },
+  {"OBJECT_CREATE.AFTER", "OBJECT_CREATE", MODHOOK_AFTER | MODHOOK_NONE},
+  {"OBJECT_DESTROY.AFTER", "OBJECT_DESTROY", MODHOOK_AFTER | MODHOOK_NONE},
+  {"OBJECT_MOVE.BEFORE", NULL, MODHOOK_BEFORE | MODHOOK_INTRET},
+  {"OBJECT_MOVE.AROUND", NULL, MODHOOK_AROUND | MODHOOK_INTRET},
+  {"OBJECT_MOVE.AFTER", "OBJECT_MOVE", MODHOOK_AFTER},
+  {"PLAYER_CONNECT.AFTER", "PLAYER_CONNECT", MODHOOK_NONE},
+  {"PLAYER_DISCONNECT.AROUND", NULL, MODHOOK_AROUND},
+  {"PLAYER_DISCONNECT.BEFORE", NULL, MODHOOK_BEFORE | MODHOOK_INTRET},
+  {"PLAYER_DISCONNECT.AFTER", "PLAYER_DISCONNECT", MODHOOK_AFTER},
+  {"PLAYER_IDLEOUT", "PLAYER_IDLEOUT", MODHOOK_AFTER}, /* Run after a player idles out */
+  {"SOCKET_CONNECT.AFTER", "SOCKET_CONNECT", MODHOOK_AFTER},
+  {"SOCKET_DISCONNECT.AFTER", "SOCKET_DISCONNECT", MODHOOK_AFTER},
+  {"SOCKET_LOGINFAIL.AFTER", "SOCKET_LOGINFAIL", MODHOOK_AFTER},
+  {"SOCKET_CREATEFAIL.AFTER", "SOCKET_CREATEFAIL", MODHOOK_AFTER},
+  {"SQL_CONNECT.AFTER", "SQL_CONNECT", MODHOOK_AFTER},
+  {NULL, NULL, MODHOOK_NONE}
+};
+
+void CHooks_Init() {
+  int i, sz;
+
+  /* Figure out size */
+  for(i = 0 ;chook_tab[i].key != NULL; i++)
+    ;
+  hashinit(&chook_htab, i);
+  /* Initialize Chook Hashtab */
+
+  for(i = 0; chook_tab[i].key != NULL; i++)
+    CHook_Create(chook_tab[i].key, chook_tab[i].flags);
+
+  /* Setup the MUSH Event aliases to our actual Hooks */
+  for(sz = i = 0 ;chook_tab[i].key != NULL; i++)
+    if(chook_tab[i].mush_key != NULL)
+      sz++;
+  hashinit(&chook_mevents, sz);
+  for(sz = i = 0 ;chook_tab[i].key != NULL; i++)
+    if(chook_tab[i].mush_key != NULL)
+      hashadd( chook_tab[i].mush_key, (void *)chook_tab[i].key, &chook_mevents);
+}
+
+struct core_hook_t *CHook_Create(const char *key, int flags) {
+  struct core_hook_t *chook;
+
+  /* check to see if we need to create it */
+  if((chook = (struct core_hook_t *) hashfind(key, &chook_htab))) {
+    /* It already exists.. just return this one */
+    return chook;
+  } 
+  
+  /* First Create our struct */
+  chook = mush_malloc(sizeof(struct core_hook_t), "CORE_HOOK.PARENT"); 
+  
+  if(!chook) 
+    mush_panic("Out of memory!");
+
+  /* Initialize data */
+  chook->key = mush_strdup(strupper(key), "CORE_HOOK.KEY");
+  chook->flags = flags;
+  chook->hooks = NULL; /* Initialized as having no children */
+  /* Add to the hashtab */
+  hashadd(key, chook, &chook_htab);
+
+  return chook;
+}
+
+struct core_entry_t *CHook_Insert (const char *key, char priority, int flags, void *data) {
+   struct core_hook_t *parent;
+   struct core_entry_t *new_child, *cur_child;
+
+   /* Ok first look for the htab entry */
+   parent = hashfind(key, &chook_htab);
+
+   if(!parent) /* It doesn't exist, return NULL */
+     return NULL;
+
+   /* It does exist lets allocate some information for this entry */
+   new_child = mush_malloc(sizeof(struct core_entry_t), "CORE_HOOK.CHILD");
+
+   if(!new_child) 
+     mush_panic("Out of memory!");
+   /* Now go ahead, give it priority, flags & data */
+   new_child->priority = priority;
+   new_child->flags = flags;
+   new_child->data = data;
+   new_child->up = parent;
+   new_child->next = NULL;
+   new_child->prev = NULL;
+
+   /* Find a place before it within the parent */
+   if(parent->hooks == NULL) { /* simple. set it and return */
+     parent->hooks = new_child;
+     return new_child;
+   }
+
+   for(cur_child = parent->hooks ; cur_child != NULL; cur_child = cur_child->next)
+     if(cur_child->priority < priority)
+       break;
+     else if(cur_child->next == NULL) {
+       /* We're going at the end of the list */
+       new_child->prev = cur_child; 
+       cur_child->next = new_child;
+       return new_child;  
+     }
+
+   /* Place us in prev */
+   cur_child->prev->next = new_child;
+   new_child->next = cur_child;
+   new_child->prev = cur_child->prev;
+   cur_child->prev = new_child;
+   return new_child;
+  }
+
+/* Create SC event associated with 'key' */
+int CHook_Insert_SC(char *key, dbref object, char *attribute) {
+  struct core_entry_t *entry;
+  struct softcode_hook *softcode_block;
+
+  if(!GoodObject(object))
+    return 0;
+  softcode_block = (struct softcode_hook *) mush_malloc(sizeof(struct softcode_hook), "CHOOK.SOFTCODE_BLOCK");
+  softcode_block->obj = object;
+  memset(softcode_block->attribute, '\0', ATTRIBUTE_NAME_LIMIT);
+  strncpy(softcode_block->attribute, strupper(attribute), ATTRIBUTE_NAME_LIMIT-1);
+
+  entry = CHook_Insert(key,  MODHOOK_PRI_SC, MODHOOK_SOFTCODE, (void *) softcode_block);  
+  if(!entry) {
+    /* Free the softcode block we created */
+    mush_free(softcode_block, "CHOOK.SOFTCODE_BLOCK");
+    return 0;
+  }
+  /* We inserted it succesfully */
+  return 1;
+}
+
+/* Insert a hook for a module for the key */
+int CHook_Insert_Module(char *key __attribute__ ((__unused__)), char priority __attribute__ ((__unused__)), struct module_hook *hook __attribute__ ((__unused__))) {
+  return 0;
+}
+
+/* arg_left -> key
+ * arg_right -> obj/attribute 
+ */
+COMMAND(cmd_event) {
+  dbref thing;
+  char *key;
+  char *s;
+
+  s = strchr(arg_right, '/');
+  *s++ = '\0';
+
+  if(!s) {
+    notify(player, "Bad Event format");
+    return;
+  }
+  thing = match_thing(player, arg_right);
+  if(!GoodObject(thing))
+    return;
+
+  /* Look for event */
+  if(!(key = (char *) hashfind(arg_left, &chook_mevents))) {
+    notify(player, "No such event.");
+    return;
+  }
+
+  if(!CHook_Insert_SC(key, thing, s)) {
+    /* This shouldn't happen.. */
+    notify(player, "ERROR: Could not add event.");
+    return;
+  }
+  notify(player, "Event added.");
+}
+
+/* Give a hook parent, delete the child from its linked list */
+int CHook_Delete(struct core_entry_t *entry) { 
+
+  if(!entry)
+    return 0;
+  /* Detach from list */
+  if(entry->next == NULL && entry->up->hooks == entry) {
+    /* Quick one */
+    entry->up->hooks = NULL;
+    goto free_chook_child;
+  } else if(entry->prev)
+    entry->prev->next = entry->next;
+  else if(entry->up) /* We're rooted from the parent.. deal with that situation */
+    entry->up->hooks = entry->next;
+  if(entry->next)
+    entry->next->prev = entry->prev;
+free_chook_child:
+  /* Free entry */
+  mush_free(entry, "CORE_HOOK.CHILD");
+
+  return 1;
+}
+
+int CHook_Run(struct core_entry_t *entry, char *format, ...) {
+  va_list argp;
+  int rval;
+  int (*module_func)(struct core_entry_t *entry, va_list argp);
+
+  module_func = NULL; /* Just for initialization purposes */
+  va_start(argp, format);
+  if(entry->flags &  MODHOOK_SOFTCODE) {
+      rval = CHook_SC(entry, format, argp);
+      va_end(argp);
+  } else if(entry->flags & MODHOOK_MODULE) {
+    /* We'll do this code later */
+    va_end(argp);
+    return -1;
+  } else {
+    va_end(argp);
+    return -1;
+  }
+
+  /* We get ehre something is wrong */
+  return -2;
+
+}
+
+int CHook_SC(struct core_entry_t *entry, char *format, va_list arguments) {
+  /* Register Saving */
+  char *preserve_wnxt[10], *preserve_rnxt[NUMQ];
+  char *val_wnxt[10], *val_rnxt[NUMQ];
+  char *preserves[10], *preserveq[NUMQ];
+  HASHTAB preserve_namedregs;
+  /* */
+  struct softcode_hook *sc_hook;
+  const char *s;
+  char cmd_buf[BUFFER_LEN], tbuf[BUFFER_LEN];
+  char *fptr, *r;
+  char next = 0;
+  ATTR *atr;
+  dbref enactor, cause,executor;
+  dbref local_ooref;
+  int break_count, spot = 0;
+    
+  sc_hook = (struct softcode_hook *) entry->data;
+
+  /* Before we bother with va_list .. Make sure A) Its a good object, B) Its a good attribute */
+  if(!GoodObject(sc_hook->obj))
+    return -1;
+  atr = atr_get(sc_hook->obj, sc_hook->attribute);
+  if(!atr)
+    return -1;
+  /* Save Environment */
+  save_global_nxt("chook_sc_save", preserve_wnxt, preserve_rnxt, val_wnxt, val_rnxt);
+  save_global_regs("chook_sc_save", preserveq);
+  save_global_env("chook_sc_save", preserves);
+  init_namedregs(&preserve_namedregs);
+  copy_namedregs(&preserve_namedregs, &global_eval_context.namedregs);
+  clear_namedregs(&global_eval_context.namedregs);
+  enactor = executor = cause = sc_hook->obj; 
+
+   /* Ok.. Now that we haev all the info we need we need to build a parse_que with 0-10 being the args passed */
+  for(fptr = format; fptr && *fptr ; fptr++) {
+    /* Look for the '%' symbol.. Thats are argument starting processor */
+    if(*fptr != '%' && !next)
+      continue;
+    if(!next) { /* we caught % */
+      next = 1;
+      continue;
+    }
+    switch(*fptr) {
+      case '@': /* The cause */
+       cause = (dbref) va_arg(arguments, dbref);
+       next = 0;
+       break;
+      case '#': /* This should set the enactor */
+       enactor =  (dbref) va_arg(arguments, dbref);
+       next = 0;
+       break;
+      case 'D':
+      case 'd':
+       global_eval_context.wenv[spot++] = unparse_integer(va_arg(arguments, intmax_t));
+       next = 0;
+       break;
+      case 'S':
+      case 's':
+       global_eval_context.wenv[spot++] = va_arg(arguments, char *);
+       next = 0;
+       break;
+      case ' ': /* this shouldn't happen.. but just in case */
+       break;
+      default:
+       /* Bad Format.. don't run & return an error */
+       do_rawlog(LT_ERR, "%s:%d -> Unexpected format character '%c' in format \"%s\"", __FILE__, __LINE__, *fptr, format);
+       /* Restore Environment */
+       copy_namedregs(&global_eval_context.namedregs, &preserve_namedregs);
+       free_namedregs(&preserve_namedregs);
+       restore_global_regs("chook_sc_save", preserveq);
+       restore_global_env("chook_sc_save", preserves);
+       restore_global_nxt("chook_sc_save", preserve_wnxt, preserve_rnxt,
+           val_wnxt, val_rnxt);
+
+       return -2;
+    }
+  }
+  strncpy(cmd_buf, atr_value(atr), BUFFER_LEN-1);
+  /* FIXME: Make immediate parse execution.. And alter the cause/enactor appropriately.. parse_que doesn't give us that flexibility */
+  s = cmd_buf;
+  global_eval_context.process_command_port = 0;
+  *(global_eval_context.break_replace) = '\0';
+  global_eval_context.break_called = 0;
+  break_count = 100;
+  start_cpu_timer();
+  while (!cpu_time_limit_hit && *s) {
+          r = cmd_buf;
+          local_ooref = ooref;
+          ooref = atr->creator;
+            process_expression(cmd_buf, &r, &s,
+                               executor, enactor, cause, PE_NOTHING, PT_SEMI,
+                               NULL);
+            *r = '\0';
+            if (*s == ';')
+              s++;
+            strcpy(tbuf, cmd_buf);
+            process_command(executor, tbuf, enactor,
+                            cause, 0);
+            if (global_eval_context.break_called) {
+              global_eval_context.break_called = 0;
+              s = global_eval_context.break_replace;
+              if (!*global_eval_context.break_replace) {
+                ooref = local_ooref;
+                break;
+              }
+              break_count--;
+              if (!break_count) {
+                notify(global_eval_context.cplr,
+                       T("@break recursion exceeded."));
+                ooref = local_ooref;
+                break;
+              }
+            }
+         ooref = local_ooref;
+        }
+  reset_cpu_timer();
+  /* Restore Environment */
+  copy_namedregs(&global_eval_context.namedregs, &preserve_namedregs);
+  free_namedregs(&preserve_namedregs);
+  restore_global_regs("chook_sc_save", preserveq);
+  restore_global_env("chook_sc_save", preserves);
+  restore_global_nxt("chook_sc_save", preserve_wnxt, preserve_rnxt,
+      val_wnxt, val_rnxt);
+  return 1;
+
+}
+
+
+/* FIXME: The rest of the module code has to be adjusted to fit into the new CoreHook system */
+
 
 /* Ads a module entry and returns */
 struct module_entry_t *module_entry_add(char *name) {