--- a/src/error.c Sun Mar 15 23:01:12 2009 +0200
+++ b/src/error.c Sun Mar 15 23:22:57 2009 +0200
@@ -48,9 +48,9 @@
{ ERR_INVALID_NICK_LENGTH, "Nickname is too long", ERR_EXTRA_NONE },
{ _ERR_INVALID, NULL, 0 }
}, _module_error_desc[] = {
- { ERR_MODULE_OPEN, "module dlopen() failed", ERR_EXTRA_NONE },
+ { ERR_MODULE_OPEN, "module dlopen() failed", ERR_EXTRA_STR },
{ ERR_MODULE_NAME, "invalid module name", ERR_EXTRA_NONE },
- { ERR_MODULE_INIT_FUNC, "invalid module init func", ERR_EXTRA_NONE },
+ { ERR_MODULE_INIT_FUNC, "invalid module init func", ERR_EXTRA_STR },
{ ERR_MODULE_CONF, "module_conf", ERR_EXTRA_STR },
{ _ERR_INVALID, NULL, 0 }
};
--- a/src/error.h Sun Mar 15 23:01:12 2009 +0200
+++ b/src/error.h Sun Mar 15 23:22:57 2009 +0200
@@ -181,5 +181,6 @@
/** Same as above, but also do a 'goto error' */
#define JUMP_SET_ERROR(err_info_ptr, err_code) do { SET_ERROR(err_info_ptr, err_code); goto error; } while (0)
#define JUMP_SET_ERROR_INFO(err_info_ptr, from_ptr) do { SET_ERROR_INFO(err_info_ptr, from_ptr); goto error; } while (0)
+#define JUMP_SET_ERROR_STR(err_info_ptr, err_code, err_str) do { _SET_ERROR_STR(err_info_ptr, err_code, err_str); goto error; } while (0)
#endif
--- a/src/irc_log.c Sun Mar 15 23:01:12 2009 +0200
+++ b/src/irc_log.c Sun Mar 15 23:22:57 2009 +0200
@@ -1,23 +1,27 @@
-#include "irc_log.h"
+#include "module.h"
+#include "irc_chan.h"
+#include "error.h"
#include "log.h"
+#include <stdlib.h>
#include <string.h>
+#include <event2/event.h>
// XXX: fix this err_t crap
#define LIB_ERR_H
#include <evsql.h>
/**
- * The core irc_log state
+ * The irc_log module state
*/
-static struct irc_log_ctx {
+struct irc_log_ctx {
/** The nexus this module is loaded for */
struct nexus *nexus;
/** The database connection */
struct evsql *db;
-} _ctx;
+};
static void on_chan_msg (struct irc_chan *chan, const struct irc_nm *source, const char *message, void *arg)
{
@@ -33,27 +37,27 @@
.on_msg = on_chan_msg,
};
-void* irc_log_init (struct modules *modules, struct error_info *err)
+static err_t irc_log_init (struct nexus *nexus, void **ctx_ptr, struct error_info *err)
{
struct irc_log_ctx *ctx;
-
- (void) modules;
- (void) err;
-
- // XXX: static pointer
- ctx = &_ctx;
+
+ // allocate
+ if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
+ return SET_ERROR(err, ERR_CALLOC);
// initialize
memset(ctx, 0, sizeof(*ctx));
// store
- ctx->nexus = modules->nexus;
+ ctx->nexus = nexus;
// ok
- return ctx;
+ *ctx_ptr = ctx;
+
+ return SET_ERROR(err, SUCCESS);
}
-err_t irc_log_conf (void *mod_ctx, const char *name, char *value, struct error_info *err)
+static err_t irc_log_conf (void *mod_ctx, const char *name, char *value, struct error_info *err)
{
struct irc_log_ctx *ctx = mod_ctx;
@@ -90,3 +94,10 @@
return SUCCESS;
}
+/**
+ * The module function table
+ */
+struct module_funcs irc_log_funcs = {
+ .init = &irc_log_init,
+ .conf = &irc_log_conf,
+};
--- a/src/irc_log.h Sun Mar 15 23:01:12 2009 +0200
+++ b/src/irc_log.h Sun Mar 15 23:22:57 2009 +0200
@@ -1,27 +1,1 @@
-#ifndef IRC_LOG_H
-#define IRC_LOG_H
-
-/**
- * @file
- *
- * Module for logging IRC events to an SQL database
- */
-#include "module.h"
-#include "error.h"
-#include "irc_chan.h"
-#include <event2/event.h>
-/**
- * Initialize the irc_log module to use the given configuration
- */
-void* irc_log_init (struct modules *modules, struct error_info *err);
-
-/**
- * Set one of the config options:
- *
- * db_info - the database connection string
- * channel - the '<network>/<channel>' to log
- */
-err_t irc_log_conf (void *mod_ctx, const char *name, char *value, struct error_info *err);
-
-#endif
--- a/src/module.c Sun Mar 15 23:01:12 2009 +0200
+++ b/src/module.c Sun Mar 15 23:22:57 2009 +0200
@@ -27,24 +27,22 @@
}
/**
- * Load the symbol named "<module>_<suffix>",
+ * Load the symbol named "<module>_<suffix>".
*/
static err_t module_symbol (struct module *module, void **sym, const char *suffix)
{
char sym_name[MODULE_SYMBOL_MAX];
// validate the length of the suffix
+ assert(strlen(module->info.name) <= MODULE_NAME_MAX);
assert(strlen(suffix) <= MODULE_SUFFIX_MAX);
// format
sprintf(sym_name, "%s_%s", module->info.name, suffix);
// load
- if ((*sym = dlsym(module->handle, sym_name)) == NULL) {
- log_error("dlsym(%s, %s) failed: %s", module->info.name, sym_name, dlerror());
-
- return ERR_MODULE_SYM;
- }
+ if ((*sym = dlsym(module->handle, sym_name)) == NULL)
+ return ERR_MODULE_SYM;
// ok
return SUCCESS;
@@ -53,7 +51,6 @@
err_t module_load (struct modules *modules, struct module **module_ptr, const struct module_info *info, struct error_info *err)
{
struct module *module;
- module_init_func_t init_func;
// validate the module name
if (strlen(info->name) > MODULE_NAME_MAX)
@@ -65,29 +62,21 @@
// store
module->info = *info;
- module->modules = modules;
// clear dlerrors
(void) dlerror();
// load it
- if ((module->handle = dlopen(info->path, RTLD_NOW)) == NULL) {
- log_error("dlopen(%s) failed: %s", info->path, dlerror());
-
- JUMP_SET_ERROR(err, ERR_MODULE_OPEN);
- }
+ if ((module->handle = dlopen(info->path, RTLD_NOW)) == NULL)
+ JUMP_SET_ERROR_STR(err, ERR_MODULE_OPEN, dlerror());
- // load the init symbol
- if ((ERROR_CODE(err) = module_symbol(module, (void *) &init_func, "init")))
- JUMP_SET_ERROR(err, ERR_MODULE_INIT_FUNC);
+ // load the funcs symbol
+ if ((ERROR_CODE(err) = module_symbol(module, (void **) &module->funcs, "funcs")))
+ JUMP_SET_ERROR_STR(err, ERROR_CODE(err), dlerror());
- // call it
- if ((module->ctx = init_func(modules, err)) == NULL) {
- // ensure that this results in a valid error return code!
- assert(ERROR_CODE(err));
-
+ // call the init func
+ if ((module->funcs->init(modules->nexus, &module->ctx, err)))
goto error;
- }
// add to modules list
TAILQ_INSERT_TAIL(&modules->list, module, modules_list);
@@ -106,16 +95,6 @@
err_t module_conf (struct module *module, const char *name, char *value, struct error_info *err)
{
- module_conf_func_t conf_func;
-
- // load the conf symbol
- if ((ERROR_CODE(err) = module_symbol(module, (void *) &conf_func, "conf")))
- return ERROR_CODE(err);
-
- // call it
- if (conf_func(module->ctx, name, value, err))
- return ERROR_CODE(err);
-
- // ok
- return SUCCESS;
+ // call the conf func
+ return module->funcs->conf(module->ctx, name, value, err);
}
--- a/src/module.h Sun Mar 15 23:01:12 2009 +0200
+++ b/src/module.h Sun Mar 15 23:22:57 2009 +0200
@@ -27,6 +27,36 @@
};
/**
+ * A module's behaviour is defined as a set of function pointers, which is dynamically resolved from the module DSO,
+ * using the <mod_name>_funcs symbol.
+ */
+struct module_funcs {
+ /**
+ * Initialize the module, returning an opaque context pointer that is stored in the module state, and supplied for
+ * subsequent calls. The supplied nexus arg can be used to access the global state.
+ *
+ * @param nexus a pointer to the nexus struct containing the global state
+ * @param ctx_ptr the context pointer should be returned via this
+ * @param err returned error info
+ */
+ err_t (*init) (struct nexus *nexus, void **ctx_ptr, struct error_info *err);
+
+ /**
+ * Set a configuration option with the given name and value, given by the user. Configuration settings are not
+ * regarded as unique-per-name, but rather, several invocations of 'conf' with the same name and different values
+ * could set up a multitude of things.
+ *
+ * XXX: make value a non-modifyable string
+ *
+ * @param ctx the module's context pointer as returned by init
+ * @param name the name of the configuration setting
+ * @param value the value of the configuration setting
+ * @param err returned error info
+ */
+ err_t (*conf) (void *ctx, const char *name, char *value, struct error_info *err);
+};
+
+/**
* A loaded module.
*/
struct module {
@@ -36,12 +66,12 @@
/** The dlopen handle */
void *handle;
+ /** The resolved function table */
+ struct module_funcs *funcs;
+
/** The module context object */
void *ctx;
- /** Pointer back to the modules struct used to load this */
- struct modules *modules;
-
/** Our entry in the list of modules */
TAILQ_ENTRY(module) modules_list;
};
@@ -70,24 +100,6 @@
ERR_MODULE_CONF, ///< value error in configuration data
};
-/**
- * Module initialization function type
- *
- * @param modules the module-loading context, containing the nexus
- * @param err returned error info
- * @return context pointer, or NULL on errors
- */
-typedef void* (*module_init_func_t) (struct modules *modules, struct error_info *err);
-
-/**
- * Module configuration function type
- *
- * @param ctx the module's context pointer
- * @param name the name of the configuration setting
- * @param value the value of the configuration setting
- * @return error code
- */
-typedef err_t (*module_conf_func_t) (void *ctx, const char *name, char *value, struct error_info *err);
/**
* Maximum length of a module name
--- a/src/nexus.h Sun Mar 15 23:01:12 2009 +0200
+++ b/src/nexus.h Sun Mar 15 23:22:57 2009 +0200
@@ -4,6 +4,9 @@
/**
* A nexus is the central brain of the application; the place where the main() method is implemented
*/
+
+struct nexus;
+
#include <event2/event.h>
#include "module.h"
#include "irc_client.h"