# HG changeset patch # User Tero Marttila # Date 1238167363 -7200 # Node ID c8e2dac08207381e797df4308042978bb7413c0c # Parent bc767e01648d9a79af1141cb671cbf82d4ebf0de add config module and modify irc_log/nexus to use it diff -r bc767e01648d -r c8e2dac08207 src/CMakeLists.txt --- a/src/CMakeLists.txt Fri Mar 27 01:01:34 2009 +0200 +++ b/src/CMakeLists.txt Fri Mar 27 17:22:43 2009 +0200 @@ -12,7 +12,7 @@ set (SOCK_SOURCES sock.c sock_tcp.c sock_gnutls.c sock_test.c line_proto.c) set (IRC_SOURCES irc_line.c irc_conn.c irc_net.c irc_chan.c chain.c irc_cmd.c irc_proto.c irc_client.c irc_user.c) -set (NEXUS_SOURCES nexus.c ${CORE_SOURCES} ${SOCK_SOURCES} ${IRC_SOURCES} signals.c module.c) +set (NEXUS_SOURCES nexus.c ${CORE_SOURCES} ${SOCK_SOURCES} ${IRC_SOURCES} signals.c module.c config.c) set (TEST_SOURCES test.c ${CORE_SOURCES} ${SOCK_SOURCES} ${IRC_SOURCES}) set (IRC_LOG_SOURCES irc_log.c) diff -r bc767e01648d -r c8e2dac08207 src/config.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/config.c Fri Mar 27 17:22:43 2009 +0200 @@ -0,0 +1,21 @@ +#include "config.h" + +#include + +err_t config_apply (struct config_option *options, void *ctx, const char *name, char *value, struct error_info *err) +{ + struct config_option *option; + + // find the matching config opt + for (option = options; option->name && option->type; option++) { + if (strcmp(option->name, name) == 0) + break; + } + + // no matching option found? + if (!option) + RETURN_SET_ERROR_STR(err, ERR_CONFIG_NAME, name); + + // call the handler + return option->func(ctx, value, err); +} diff -r bc767e01648d -r c8e2dac08207 src/config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/config.h Fri Mar 27 17:22:43 2009 +0200 @@ -0,0 +1,43 @@ +#ifndef CONFIG_H +#define CONFIG_H + +/** + * Support for module configuration parameters + */ +#include "error.h" + +/** + * Different types of configuration parameters + */ +enum config_type { + CONFIG_INVALID, + + /** A plain NUL-terminated string */ + CONFIG_STRING, +}; + +struct config_option { + /** The name of the config option */ + const char *name; + + /** The type of the value, XXX: unused */ + enum config_type type; + + /** The value handler func */ + err_t (*func) (void *ctx, char *value, struct error_info *err); + + /** The value description */ + const char *description; + + /** Help text */ + const char *help; +}; + +/** + * Apply a configuration name/value to an array of config_option's. + * + * This finds the appropriate config_option and calls its func. + */ +err_t config_apply (struct config_option *options, void *ctx, const char *name, char *value, struct error_info *err); + +#endif diff -r bc767e01648d -r c8e2dac08207 src/error.c --- a/src/error.c Fri Mar 27 01:01:34 2009 +0200 +++ b/src/error.c Fri Mar 27 17:22:43 2009 +0200 @@ -19,6 +19,7 @@ { ERR_EVENT_ADD, "event_add", ERR_EXTRA_NONE }, { ERR_EVSQL_NEW_PQ, "evsql_new_pq", ERR_EXTRA_NONE }, { ERR_EVSQL_QUERY_EXEC, "evsql_query_exec", ERR_EXTRA_NONE }, + { ERR_CONFIG_NAME, "no matching config name", ERR_EXTRA_STR }, { ERR_CMD_OPT, "argv", ERR_EXTRA_STR }, { _ERR_INVALID, NULL, 0 } diff -r bc767e01648d -r c8e2dac08207 src/error.h --- a/src/error.h Fri Mar 27 01:01:34 2009 +0200 +++ b/src/error.h Fri Mar 27 17:22:43 2009 +0200 @@ -86,9 +86,14 @@ /** @see module_error_code */ _ERR_MODULE = 0x000a00, + /** config errors */ + _ERR_CONFIG = 0x000b00, + ERR_CONFIG_NAME, + /** General errors */ _ERR_GENERAL = 0xffff00, ERR_CMD_OPT, + }; /** diff -r bc767e01648d -r c8e2dac08207 src/irc_chan.c --- a/src/irc_chan.c Fri Mar 27 01:01:34 2009 +0200 +++ b/src/irc_chan.c Fri Mar 27 17:22:43 2009 +0200 @@ -158,7 +158,6 @@ strcpy(names, arg_names); // iterate over each name - // XXX: nickflags while ((nickname = strsep(&names, " "))) { // skip empty token at end if (strlen(nickname) == 0) diff -r bc767e01648d -r c8e2dac08207 src/irc_log.c --- a/src/irc_log.c Fri Mar 27 01:01:34 2009 +0200 +++ b/src/irc_log.c Fri Mar 27 17:22:43 2009 +0200 @@ -1,5 +1,6 @@ #include "module.h" #include "irc_chan.h" +#include "config.h" #include "error.h" #include "log.h" @@ -398,8 +399,10 @@ * * Fails if ctx->db is already set. */ -static err_t irc_log_conf_db_info (struct irc_log_ctx *ctx, char *value, struct error_info *err) +static err_t irc_log_conf_db_info (void *_ctx, char *value, struct error_info *err) { + struct irc_log_ctx *ctx = _ctx; + log_info("connect to database: %s", value); // already connected? @@ -422,8 +425,9 @@ * Fails if the value is invalid, we don't have a database connected, the channel doesn't exist, adding our command * handlers/callbacks fails, or sending the initial INSERT-OPEN query fails. */ -static err_t irc_log_conf_channel (struct irc_log_ctx *ctx, char *value, struct error_info *err) +static err_t irc_log_conf_channel (void *_ctx, char *value, struct error_info *err) { + struct irc_log_ctx *ctx = _ctx; const char *network, *channel; struct irc_chan *chan; @@ -455,6 +459,15 @@ } /** + * Our configuration options + */ +struct config_option irc_log_config_options[] = { + { "db_info", CONFIG_STRING, &irc_log_conf_db_info, "[= [...]]", "set database connection info, see libpq docs" }, + { "channel", CONFIG_STRING, &irc_log_conf_channel, ":", "log the given channel" }, + { NULL, 0, NULL, NULL, NULL } +}; + +/** * Set a config option */ static err_t irc_log_conf (void *_ctx, const char *name, char *value, struct error_info *err) @@ -465,19 +478,8 @@ if (ctx->unloading) RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "module is being unloaded"); - // apply the config setting - if (strcmp(name, "db_info") == 0) { - return irc_log_conf_db_info(ctx, value, err); - - } else if (strcmp(name, "channel") == 0) { - return irc_log_conf_channel(ctx, value, err); - - } else { - RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "unknown configuration option"); - } - - // ok - return SUCCESS; + // apply it + return config_apply(irc_log_config_options, ctx, name, value, err); } /** @@ -504,8 +506,9 @@ * The module function table */ struct module_funcs irc_log_funcs = { - .init = &irc_log_init, - .conf = &irc_log_conf, - .unload = &irc_log_unload, + .init = &irc_log_init, + .conf = &irc_log_conf, + .config_options = irc_log_config_options, + .unload = &irc_log_unload, }; diff -r bc767e01648d -r c8e2dac08207 src/module.h --- a/src/module.h Fri Mar 27 01:01:34 2009 +0200 +++ b/src/module.h Fri Mar 27 17:22:43 2009 +0200 @@ -6,11 +6,12 @@ * * Dynamically loadable modules for use with nexus. * - * The modules are loaded using dlopen(), and hence should be standard dynamic libraries. Module initialization happens - * using a module_init_func_t named "_init", which should return some kind of context pointer, which can later be - * used to perform other operations on the module. + * The modules are loaded using dlopen(), and hence should be standard dynamic libraries. Modules are then "loaded" by + * resolving a `struct module_funcs` symbol called '_funcs', and then using the init func to construct a + * "context", which is then further manipulated by various other module functions. */ #include "nexus.h" +#include "config.h" #include "error.h" #include @@ -29,6 +30,8 @@ /** * A module's behaviour is defined as a set of function pointers, which is dynamically resolved from the module DSO, * using the _funcs symbol. + * + * XXX: this also includes non-functions now... */ struct module_funcs { /** @@ -57,6 +60,12 @@ err_t (*conf) (void *ctx, const char *name, char *value, struct error_info *err); /** + * Optionally, a module may also provide some kind of list of available configuration parameters, by setting this + * to a pointer to an array of those. + */ + const struct config_option *config_options; + + /** * Unload the module, removing all handlers/callbacks added to the nexus' irc_client. This does not have to act * immediately, and will still have access to all irc_* resources it had earlier, and may perform I/O to unload * cleanly. But the unloading should complete reasonably quickly, after which all event handlers added by the diff -r bc767e01648d -r c8e2dac08207 src/nexus.c --- a/src/nexus.c Fri Mar 27 01:01:34 2009 +0200 +++ b/src/nexus.c Fri Mar 27 17:22:43 2009 +0200 @@ -43,9 +43,11 @@ }; /** - * Display --help output on stdout + * Display --help output on stdout. + * + * If nexus is given, --config options for loaded modules are also listed */ -static void usage (const char *exe) +static void usage (struct nexus *nexus, const char *exe) { printf("Usage: %s [OPTIONS]\n", exe); printf("\n"); @@ -55,6 +57,29 @@ printf(" --module / -m add a module using ':' format\n"); printf(" --config / -C add a module configuration option using ':[:]' format\n"); printf(" --debug / -d set logging level to DEBUG\n"); + + if (nexus && !TAILQ_EMPTY(&nexus->modules->list)) { + struct module *module; + + printf("\n"); + printf("Module configuration options\n"); + + TAILQ_FOREACH(module, &nexus->modules->list, modules_list) { + printf("\n"); + printf("%s:\n", module->info.name); + + if (module->funcs->config_options) { + const struct config_option *opt; + + for (opt = module->funcs->config_options; opt->name && opt->type; opt++) { + printf(" --config %s:%s:%s\t\t%s\n", module->info.name, opt->name, opt->description, opt->help); + } + + } else { + printf("\t???\n"); + } + } + } } /** @@ -218,7 +243,7 @@ while ((opt = getopt_long(argc, argv, "hn:c:m:C:", options, &option_index)) != -1) { switch (opt) { case OPT_HELP: - usage(argv[0]); + usage(nexus, argv[0]); // XXX: return instead exit(EXIT_SUCCESS); @@ -252,7 +277,7 @@ break; case '?': - usage(argv[0]); + usage(nexus, argv[0]); return SET_ERROR(err, ERR_CMD_OPT); } }