Module Core Code Phase 1 -
authorRick Bird <nveid@bender.theari.com>
Sat, 2 Apr 2011 20:20:25 +0000 (16:20 -0400)
committerRick Bird <nveid@bender.theari.com>
Sat, 2 Apr 2011 20:20:25 +0000 (16:20 -0400)
  @module - Lists Modules loaded
  @module/load <module> - loads a module
  @module/unload <module> - unloads a module

  netmud now linked using libtool's export-dynamic instead of straight
  gcc

Makefile.SH
hdrs/modules.h [new file with mode: 0644]
src/Makefile.SH
src/SWITCHES
src/bsd.c
src/command.c
src/modules.c [new file with mode: 0644]

index 57996f9e1e52fdb0221d89b17368b666263f9063..d35e6ca7e1b7af4b775a920ec3e8459597cde6f2 100644 (file)
@@ -52,7 +52,7 @@ $make_set_make
 CC=$cc
 CCFLAGS=$optimize -I.. -I../hdrs -Wall -Wno-comment -Wno-parentheses -Wno-switch -Werror $ccflags $warnings
 LDFLAGS=$ldflags
-CLIBS=$libs $cryptlib $libssl $libcrypto $libmysqlclient
+CLIBS=-ltdl $libs $cryptlib $libssl $libcrypto $libmysqlclient
 INSTALL=$install
 INSTALLDIR=$installdir
 CP=$cp
diff --git a/hdrs/modules.h b/hdrs/modules.h
new file mode 100644 (file)
index 0000000..8664dc5
--- /dev/null
@@ -0,0 +1,37 @@
+/* CobraMUSH Module System based upon cross-platform libldl */
+#ifndef _MODULES_H_
+#define _MODULES_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 */
+  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);
+
+
+/* Iterate through Module List */
+#define MODULE_ITER(m) for(m = module_list ; m != NULL ; m = m->next)
+/* Check and Free */
+#define MODULE_CAF(mem,check)  if(mem != NULL) \
+                                 mush_free(mem, check);
+/* Retrieve Module Function */
+#define MODULE_FUNC(h, m, func, ...) \
+  if((h = lt_dlsym(m, func))) { \
+    h(__VAR_ARGS__) \
+  }
+
+#define MODULE_FUNCRET(m, func) lt_dlsym(m, func);
+
+
+#endif /* _MODULES_H_ */
index 337ed717f660cbc3467cc74af7db63d36ffb5e57..cd4612c8093d546e93478b1579b542dbbdb4de56 100644 (file)
@@ -50,6 +50,7 @@ LINTFILT=egrep -v '(possible pointer|long assign|not yet im|:$$)'
 
 # Libs
 LIBS=$(CLIBS) $(RLIBS) $(ILIBS)
+CC=libtool
 
 CFLAGS=$(CCFLAGS) $(RDEFS) $(IDEFS)
 
@@ -64,7 +65,7 @@ C_FILES=access.c atr_tab.c attrib.c boolexp.c bsd.c bufferq.c \
        extmail.c filecopy.c flaglocal.c flags.c funcrypt.c function.c \
        fundb.c fundiv.c funlist.c funlocal.c funmath.c funmisc.c funstr.c funtime.c \
        funufun.c game.c help.c htab.c ident.c local.c lock.c log.c look.c \
-       malias.c match.c memcheck.c move.c mushlua.c mushlua_wrap.c mycrypt.c mymalloc.c mysocket.c \
+       malias.c match.c memcheck.c move.c modules.c mushlua.c mushlua_wrap.c mycrypt.c mymalloc.c mysocket.c \
        myssl.c notify.c parse.c pcre.c player.c plyrlist.c \
        predicat.c privtab.c prog.o ptab.c rob.c rplog.c services.c set.c shs.c  \
        sig.c speech.c sql.c strdup.c strtree.c  strutil.c tables.c timer.c unparse.c  \
@@ -78,7 +79,7 @@ H_FILES = ../config.h ../confmagic.h ../hdrs/ansi.h ../hdrs/atr_tab.h \
          ../hdrs/function.h ../hdrs/game.h ../hdrs/getpgsiz.h ../hdrs/help.h \
          ../hdrs/htab.h ../hdrs/htab.h ../hdrs/ident.h ../hdrs/lock.h \
          ../hdrs/log.h ../hdrs/log.h ../hdrs/malias.h ../hdrs/match.h \
-         ../hdrs/mushdb.h ../hdrs/mushlua.h ../hdrs/mushtype.h \
+         ../hdrs/modules.h ../hdrs/mushdb.h ../hdrs/mushlua.h ../hdrs/mushtype.h \
          ../hdrs/mymalloc.h ../hdrs/mysocket.h ../hdrs/myssl.h \
          ../hdrs/parse.h ../hdrs/pcre.h ../hdrs/privtab.h ../hdrs/ptab.h \
          ../hdrs/strtree.h ../hdrs/version.h ../options.h ../hdrs/division.h ../hdrs/cron.h
@@ -90,7 +91,7 @@ COMMON_O_FILES=access.o atr_tab.o attrib.o boolexp.o bufferq.o \
        extmail.o filecopy.o flaglocal.o flags.o funcrypt.o function.o \
        fundb.o funlist.o fundiv.o funlocal.o funmath.o funmisc.o funstr.o funtime.o \
        funufun.o game.o help.o htab.o ident.o local.o lock.o log.o look.o \
-       malias.o match.o memcheck.o move.o mushlua.o mushlua_wrap.o mycrypt.o mymalloc.o \
+       malias.o match.o memcheck.o move.o modules.o mushlua.o mushlua_wrap.o mycrypt.o mymalloc.o \
        mysocket.o myssl.o notify.o parse.o pcre.o player.o plyrlist.o predicat.o privtab.o \
        prog.o   ptab.o rob.o rplog.o services.o set.o shs.o sig.o speech.o sql.o  strdup.o \
        strtree.o  strutil.o tables.o timer.o unparse.o utils.o version.o warnings.o \
@@ -110,12 +111,13 @@ all: $(OUTFILES)
 netmud: $(O_FILES) 
        @echo "Making netmud."
        -mv -f netmud netmud~
-       $(CC) $(LDFLAGS) $(CCFLAGS) -o netmud $(O_FILES) $(LIBS) 
+       $(LIBTOOL) --mode=link $(CC) -export-dynamic $(LDFLAGS) $(CCFLAGS) -o netmud $(O_FILES) $(LIBS) 
 
 console: $(CONSOLE_O_FILES)
        @echo "Making console."
        -mv -f console console~
-       $(CC) $(LDFLAGS) $(CCFLAGS) -o console $(CONSOLE_O_FILES) $(LIBS)
+       $(LIBTOOL) --mode=link $(CC) -export-dynamic $(LDFLAGS) $(CCFLAGS) -o netmud $(O_FILES) $(LIBS) 
+
 
 # By default, db.c initially allocates enough space for 5000 objects, then
 #   grows the space if needed.  To change this value, include
index ec68f3df0584223f0304640b5e9b1bc56227121c..e99dcd4e71dbdae53a37ca580afdc7705434ce19 100644 (file)
@@ -70,6 +70,7 @@ JOIN
 LEAVE
 LETTER
 LIST
+LOAD
 LOGOUT
 LOWERCASE
 LOCK
@@ -147,6 +148,7 @@ THINGS
 TITLE
 TRACE
 TYPE
+UNLOAD
 UNCLEAR
 UNHIDE
 UNGAG
index 934399b5cadff8803756a35d70237ff0cc46af6f..12ada57d1578b699dacd193c338e4a4c6d2a2d79 100644 (file)
--- a/src/bsd.c
+++ b/src/bsd.c
 #include "game.h"
 #include "dbio.h"
 #include "confmagic.h"
+#include "modules.h"
 #include "lua.h"
 #include "mushlua.h"
 #ifdef HAS_WAITPID
@@ -505,6 +506,8 @@ main(int argc, char **argv)
 #endif
 
   time(&mudtime);
+  /* Initialize Module interface */
+  modules_init();
 
   /* If we have setlocale, call it to set locale info
    * from environment variables
index cb74d13f57cf8d11ad2fd958e324910a28e4746c..c6882baa3ef587de98b9981957b9bf9ccb748d90 100644 (file)
@@ -191,6 +191,7 @@ COMLIST commands[] = {
 #endif
   {"@MAP", "DELIMIT", cmd_map, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_NOPARSE,
    NULL},
+  {"@MODULE", "LOAD UNLOAD", cmd_module, CMD_T_ANY, "POWER^SITE"},
   {"@MOTD", "CONNECT LIST DOWN FULL", cmd_motd,
    CMD_T_ANY | CMD_T_NOGAGGED, NULL},
   {"@MVATTR", "CONVERT NOFLAGCOPY", cmd_mvattr,
diff --git a/src/modules.c b/src/modules.c
new file mode 100644 (file)
index 0000000..210ce58
--- /dev/null
@@ -0,0 +1,190 @@
+/* CobraMUSH Module/Plugin System - File created 3/31/11
+ *
+ * Our Approach shall be one using the libtool library, mostly for the fact 
+ * that is a cross-platform designed library.
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <ltdl.h>
+
+#include "conf.h"
+#include "externs.h"
+#include "command.h"
+#include "switches.h"
+#include "mushtype.h"
+#include "log.h"
+#include "modules.h"
+
+struct module_entry_t *module_list = NULL;
+
+/* Ads a module entry and returns */
+struct module_entry_t *module_entry_add(char *name) {
+  struct module_entry_t *entry;
+
+  entry = (struct module_entry_t *) mush_malloc(sizeof(struct module_entry_t), "MODULE_ENTRY");
+
+  if(!entry) {
+    return NULL; /* Should really panic here.. */
+  }
+
+  entry->name = mush_strdup(name, "MODULE_ENTRY.NAME");
+  entry->info = NULL;
+  entry->load = NULL;
+  entry->unload = NULL;
+  entry->next = module_list;
+  module_list = entry;
+
+  return entry;
+}
+
+/* removes a module entry from the list */
+int module_entry_del(struct module_entry_t *entry) {
+  struct module_entry_t *m, *e = NULL;
+
+  if(module_list == entry)
+    e = module_list;
+  else MODULE_ITER(m)
+    if(m->next != NULL && m->next == entry) {
+      e = m;
+      m->next = m->next->next;
+      break;
+    }
+
+  if(e == NULL)
+    return 0;
+  
+  MODULE_CAF(e->name, "MODULE_ENTRY.NAME");
+  MODULE_CAF(e->info, "MODULE_ENTRY.INFO");
+  MODULE_CAF(e, "MODULE_ENTRY");
+
+  return 1;
+}
+
+/* Initialize Module Interface */
+int modules_init() {
+  return lt_dlinit(); /* Initialize libltdl. 0 is good */
+}
+
+/* Load Module name */
+int module_open(char *path, char *name) {
+  char file[BUFFER_LEN];
+  int (*module_loader)(struct module_entry_t *);
+  struct module_entry_t *module;
+  void *handle;
+
+  memset(file, '\0', BUFFER_LEN);
+  snprintf(file, BUFFER_LEN, "%s/%s", path, name);
+
+  handle = lt_dlopen(file);
+
+  if(!handle) {
+    do_rawlog(LT_ERR, "Error Loading Module: %s | %s ", file, lt_dlerror());
+    return 0;
+  }
+
+  /* Some OSes may need symbols to be prefixed with _.. Will need to look into autoconfig code for this */
+  module_loader = MODULE_FUNCRET(handle, "module_load");
+
+  if(!module_loader) {
+    do_rawlog(LT_ERR, "Error Loading Module: Could not call module_load | %s", file);
+    return 0;
+  }
+
+  /* Add the module to the linked list */
+  module = module_entry_add(name);
+  if(module == NULL) {
+    return 0;
+  }
+  module->handle = handle;
+  module->load = module_loader;
+  module->unload = MODULE_FUNCRET(handle, "module_unload");
+  
+  /* Grab info and version from module & put it in */
+  /* Success.. Call the module */
+  return module_loader(module);
+}
+
+/* Unload one Module */
+int module_close(struct module_entry_t *m) {
+  int ret;
+
+  ret =  m->unload(m); /* first run requierd unload code */
+  
+  if(!ret)
+    return 0;
+
+  /* next unload the modules for real */
+  ret = lt_dlclose(m->handle);
+
+  if(ret != 0) {
+    do_rawlog(LT_ERR, "Could not unload module: %s/%d | %s", __FILE__, __LINE__, lt_dlerror());
+    return 0;
+  }
+
+  if(!module_entry_del(m)) {
+    do_rawlog(LT_ERR, "Could not unload module: %s/%d ", __FILE__, __LINE__);
+    return 0;
+  }
+
+  return 1;
+}
+
+/* Unload all modules */
+int modules_shutdown() {
+  struct module_entry_t *m;
+
+  MODULE_ITER(m)
+    m->unload(m);
+
+  return lt_dlexit(); /* 0 is good */
+}
+
+/* MUSH Module Interface Portion... Much of this section will probably actually move to a module itself and become a resident module */
+
+  /* command will be restricted to Director player in nature from the command file */
+COMMAND(cmd_module) {
+  struct module_entry_t *m;
+  char tbuf1[BUFFER_LEN];
+  int ret;
+
+  if(SW_ISSET(sw, SWITCH_LOAD)) {
+    if(!arg_left) {
+      notify(player, "Requires at least one argument.");
+      return;
+    }
+    /* Load a Module By name in arg_left */
+    (void) getcwd(tbuf1, BUFFER_LEN);
+    ret = module_open(tbuf1, arg_left);
+    if(ret) 
+      notify(player, "module successfully loaded.");
+    else
+      notify(player, "module could not load.");
+
+  } else if(module_list == NULL) {
+    notify_format(player, "Search-path: %s", lt_dlgetsearchpath());
+    notify(player, "No modules loaded.");
+    return;
+  } else if(SW_ISSET(sw, SWITCH_UNLOAD)) {
+    /* This is after the no modules loaded one.. because you have to modules loaded in order to unload something */
+    if(!arg_left) {
+      notify(player, "Reqiures at least one argument.");
+      return;
+    }
+    MODULE_ITER(m)
+      if(!strcasecmp(arg_left, m->name)) {
+       if(module_close(m))
+         notify(player, "unloaded module");
+       else
+         notify(player, "could not unload module");
+       return;
+      }
+  } else {
+  /* No Switches.. Just view modules loaded */
+   MODULE_ITER(m)  {
+    notify_format(player, "Module-Name: %s", m->name);
+   }
+  }
+}
+
+