--- a/src/config.c Tue Apr 07 21:09:25 2009 +0300
+++ b/src/config.c Wed Apr 08 01:28:46 2009 +0300
@@ -8,7 +8,7 @@
const struct config_option *option;
// find the matching config opt
- for (option = options; option->name && option->type; option++) {
+ for (option = options; option->name; option++) {
if (strcmp(option->name, name) == 0)
return option;
}
@@ -27,20 +27,22 @@
const char *network, *channel;
struct irc_chan *chan;
+ // XXX: wrong error code
+
// parse required args
if ((network = strsep(&raw_value, "/")) == NULL)
- JUMP_SET_ERROR_STR(err, ERR_MODULE_CONF, "invalid <network> for CONFIG_IRC_CHAN value");
+ JUMP_SET_ERROR_STR(err, ERR_CONFIG_VALUE, "invalid <network> for CONFIG_IRC_CHAN value");
if ((channel = strsep(&raw_value, "/")) == NULL)
- JUMP_SET_ERROR_STR(err, ERR_MODULE_CONF, "invalid <channel> for CONFIG_IRC_CHAN value");
+ JUMP_SET_ERROR_STR(err, ERR_CONFIG_VALUE, "invalid <channel> for CONFIG_IRC_CHAN value");
// extraneous stuff?
if (raw_value)
- JUMP_SET_ERROR_STR(err, ERR_MODULE_CONF, "trailing data for CONFIG_IRC_CHAN value");
+ JUMP_SET_ERROR_STR(err, ERR_CONFIG_VALUE, "trailing data for CONFIG_IRC_CHAN value");
// get the channel?
if ((chan = irc_client_get_chan(nexus->client, network, channel)) == NULL)
- JUMP_SET_ERROR_STR(err, ERR_MODULE_CONF, "unknown network/channel name for CONFIG_IRC_CHAN value");
+ JUMP_SET_ERROR_STR(err, ERR_CONFIG_VALUE, "unknown network/channel name for CONFIG_IRC_CHAN value");
// ok
return chan;
@@ -51,8 +53,15 @@
err_t config_parse (const struct config_option *option, struct nexus *nexus, struct config_value *value, char *raw_value, struct error_info *err)
{
+ // use the first param
+ const struct config_param *param = &option->params[0];
+
+ // must have exactly one param
+ if (!param->type || (param + 1)->type)
+ return SET_ERROR(err, ERR_CONFIG_PARAMS);
+
// parse the value
- switch (option->type) {
+ switch (param->type) {
case CONFIG_STRING:
// simple!
value->string = raw_value;
@@ -70,32 +79,66 @@
}
// copy the type
- value->type = option->type;
+ value->type = param->type;
// ok
return SUCCESS;
}
-err_t config_apply_opt (const struct config_option *option, void *ctx, const struct config_value *value, struct error_info *err)
+err_t config_check_param (const struct config_param *param, const struct config_value *value, struct error_info *err)
{
+ // no value given?
+ if (!value || !value->type)
+ RETURN_SET_ERROR_STR(err, ERR_CONFIG_REQUIRED, param->name);
+
// wrong type?
- if (option->type != value->type)
+ if (param->type != value->type)
// XXX: info about type names
return SET_ERROR(err, ERR_CONFIG_TYPE);
- // null?
- if (!value)
- RETURN_SET_ERROR_STR(err, ERR_CONFIG_REQUIRED, option->name);
-
- // call the handler
- switch (option->type) {
- case CONFIG_STRING: return option->func.string(ctx, value->string, err);
- case CONFIG_IRC_CHAN: return option->func.irc_chan(ctx, value->irc_chan, err);
- default: NOT_REACHED();
- }
+ // ok
+ return SUCCESS;
}
-err_t config_apply (const struct config_option *options, void *ctx, const char *name, const struct config_value *value, struct error_info *err)
+err_t config_apply_opt (const struct config_option *option, void *ctx, const struct config_value values[], struct error_info *err)
+{
+ const struct config_param *param;
+ const struct config_value *value;
+
+ // handle each param
+ for (param = option->params, value = values; param->name && param->type; param++, value++) {
+ // check the given value
+ if (config_check_param(param, value, err))
+ goto error;
+
+ if (param->is_handler) {
+ err_t tmp;
+
+ // invoke the handler
+ switch (param->type) {
+ case CONFIG_STRING: tmp = param->func.string(ctx, value->string, err); break;
+ case CONFIG_IRC_CHAN: tmp = param->func.irc_chan(ctx, value->irc_chan, err); break;
+ default: NOT_REACHED();
+ }
+
+ // abort on errors
+ if (tmp)
+ goto error;
+ }
+ }
+
+ // the option's handler?
+ if (option->func && option->func(ctx, values, err))
+ goto error;
+
+ // ok
+ return SUCCESS;
+
+error:
+ return ERROR_CODE(err);
+}
+
+err_t config_apply (const struct config_option *options, void *ctx, const char *name, const struct config_value values[], struct error_info *err)
{
const struct config_option *option;
@@ -104,37 +147,46 @@
return ERROR_CODE(err);
// apply it
- return config_apply_opt(option, ctx, value, err);
+ return config_apply_opt(option, ctx, values, err);
}
err_t config_apply_string (const struct config_option *options, void *ctx, const char *name, char *value, struct error_info *err)
{
- struct config_value conf_value = { CONFIG_STRING, { .string = value } };
+ struct config_value conf_value[] = {
+ CONFIG_VALUE_STRING(value),
+ CONFIG_VALUE_END,
+ };
- return config_apply(options, ctx, name, &conf_value, err);
+ return config_apply(options, ctx, name, conf_value, err);
}
err_t config_apply_irc_chan (const struct config_option *options, void *ctx, const char *name, struct irc_chan *value, struct error_info *err)
{
- struct config_value conf_value = { CONFIG_STRING, { .irc_chan = value } };
+ struct config_value conf_value[] = {
+ CONFIG_VALUE_IRC_CHAN(value),
+ CONFIG_VALUE_END,
+ };
- return config_apply(options, ctx, name, &conf_value, err);
+ return config_apply(options, ctx, name, conf_value, err);
}
err_t config_apply_raw (const struct config_option *options, struct nexus *nexus, void *ctx, const char *name, char *raw_value, struct error_info *err)
{
const struct config_option *option;
- struct config_value value;
+ struct config_value value[2] = {
+ CONFIG_VALUE_END,
+ CONFIG_VALUE_END,
+ };
// no matching option found?
if (!(option = config_lookup(options, name, err)))
return ERROR_CODE(err);
// parse it
- if (config_parse(option, nexus, &value, raw_value, err))
+ if (config_parse(option, nexus, &value[0], raw_value, err))
return ERROR_CODE(err);
// apply it
- return config_apply_opt(option, ctx, &value, err);
+ return config_apply_opt(option, ctx, value, err);
}
--- a/src/config.h Tue Apr 07 21:09:25 2009 +0300
+++ b/src/config.h Wed Apr 08 01:28:46 2009 +0300
@@ -7,6 +7,7 @@
* Support for module configuration parameters
*/
#include "error.h"
+#include <stdbool.h>
/**
* Different types of configuration parameters
@@ -39,36 +40,84 @@
};
/**
- * A single configuration option, with a name, type, handler function, etc.
+ * Structure to define a single parameter for an option
*/
-struct config_option {
- /** The name of the config option */
+struct config_param {
+ /** The name of the arg */
const char *name;
- /** The type of the value expected */
+ /** The type */
enum config_type type;
-
- /** The value handler func, by type */
+
+ /** Description */
+ const char *description;
+
+ /** Optional value handler function, by type */
union {
err_t (*string) (void *ctx, char *value, struct error_info *err);
err_t (*irc_chan) (void *ctx, struct irc_chan *chan, struct error_info *err);
} func;
- /** The value description */
- const char *description;
+ /** Use handler function? */
+ bool is_handler;
+};
+
+/**
+ * The maximum number of parameters that a single option can have, although this includes the terminating NULL
+ */
+#define CONFIG_PARAMS_MAX (15 + 1)
+
+/**
+ * The maximum number of values that an option can access, including the terminating NULL
+ */
+#define CONFIG_VALUES_MAX CONFIG_PARAMS_MAX
+
+/**
+ * A more complicated configuration option that can have multiple parameters
+ */
+struct config_option {
+ /** The name of the config option */
+ const char *name;
+
+ /** The list of parameters */
+ const struct config_param params[CONFIG_PARAMS_MAX];
+
+ /** The handler function */
+ err_t (*func) (void *ctx, const struct config_value values[], struct error_info *err);
/** Help text */
const char *help;
};
+#define CONFIG_PARAM(name, type, desc) \
+ { name, type, desc, { NULL }, false }
+
+#define CONFIG_PARAM_HANDLER(name, type, desc, _func_name_, func) \
+ { name, type, desc, {._func_name_ = func }, true }
+
+#define CONFIG_OPT(name, params, func, help) \
+ { name, params, func, help }
+
#define CONFIG_OPT_STRING(name, func, desc, help) \
- { name, CONFIG_STRING, { .string = func }, desc, help }
+ { name, { CONFIG_PARAM_HANDLER(name, CONFIG_STRING, desc, string, func) }, NULL, help }
#define CONFIG_OPT_IRC_CHAN(name, func, desc, help) \
- { name, CONFIG_IRC_CHAN, { .irc_chan = func }, desc, help }
+ { name, { CONFIG_PARAM_HANDLER(name, CONFIG_IRC_CHAN, desc, irc_chan, func) }, NULL, help }
#define CONFIG_OPT_END \
- { NULL, CONFIG_INVALID, { NULL }, NULL, NULL }
+ { NULL, {}, NULL, NULL }
+
+#define CONFIG_VALUE(type, _name_, value) \
+ { (type), { ._name_ = (value) } }
+
+#define CONFIG_VALUE_STRING(str_value) \
+ CONFIG_VALUE(CONFIG_STRING, string, str_value)
+
+#define CONFIG_VALUE_IRC_CHAN(irc_chan_value) \
+ CONFIG_VALUE(CONFIG_IRC_CHAN, irc_chan, irc_chan_value)
+
+#define CONFIG_VALUE_END \
+ { 0, { NULL } }
/**
* Lookup a config option by name.
@@ -83,7 +132,7 @@
// XXX: move this into nexus
#include "nexus.h"
/**
- * Parse a raw value into a suitable configuration value, based on the config option type.
+ * Parse a raw value into a suitable configuration value for a single-param option, based on the config option type.
*
* Since this needs to access the application state, you need to pass in the nexus as an argument.
*
@@ -99,27 +148,27 @@
err_t config_parse (const struct config_option *option, struct nexus *nexus, struct config_value *value, char *raw_value, struct error_info *err);
/**
- * Apply a parsed configuration value to the given option.
+ * Apply a list of parsed configuration values to the given config_option struct.
*
* The config option handlers take a context argument; the value of this depends on the implementor of the config_option.
*
* @param option the option to apply
* @param ctx the context pointer for the option handler
- * @param value the parsed value
+ * @param values the NULL-terminated array of parsed values
* @param err returned error info
*/
-err_t config_apply_opt (const struct config_option *option, void *ctx, const struct config_value *value, struct error_info *err);
+err_t config_apply_opt (const struct config_option *option, void *ctx, const struct config_value values[], struct error_info *err);
/**
- * Apply a parsed configuration value for the named config opt.
+ * Apply a list of parsed configuration values for the named config opt.
*
* @param options a CONFIG_OPT_END-terminated array of config_option's
* @param ctx the context pointer for the option handler
* @param name the config_option::name to look up
- * @param value the parsed value
+ * @param values the NULL-termianted array of parsed values
* @param err returned error info
*/
-err_t config_apply (const struct config_option *options, void *ctx, const char *name, const struct config_value *value, struct error_info *err);
+err_t config_apply (const struct config_option *options, void *ctx, const char *name, const struct config_value values[], struct error_info *err);
/**
* Apply a string value for the named config opt.
--- a/src/error.h Tue Apr 07 21:09:25 2009 +0300
+++ b/src/error.h Wed Apr 08 01:28:46 2009 +0300
@@ -90,9 +90,11 @@
/** config errors */
_ERR_CONFIG = 0x000b00,
- ERR_CONFIG_NAME,
- ERR_CONFIG_TYPE,
- ERR_CONFIG_REQUIRED,
+ ERR_CONFIG_NAME, ///< unknown option name
+ ERR_CONFIG_TYPE, ///< invalid value type for parameter
+ ERR_CONFIG_REQUIRED, ///< missing value for required parameter
+ ERR_CONFIG_VALUE, ///< invalid value
+ ERR_CONFIG_PARAMS, ///< invalid number of parameters
/** lua errors */
_ERR_LUA = 0x000c00,
--- a/src/lua_objs.c Tue Apr 07 21:09:25 2009 +0300
+++ b/src/lua_objs.c Wed Apr 08 01:28:46 2009 +0300
@@ -132,7 +132,10 @@
{
struct lua_module *lua_module = lua_obj_get_obj(L, __func__, "spbot.module");
const struct config_option *option;
- struct config_value value;
+ struct config_value values[2] = {
+ CONFIG_VALUE_END,
+ CONFIG_VALUE_END
+ }, *value = &values[0];
struct error_info err;
// XXX: come up with some better way...
@@ -170,8 +173,8 @@
struct lua_chan *lua_chan = lua_touserdata(L, 3);
// build the value
- value.type = CONFIG_IRC_CHAN;
- value.irc_chan = lua_chan->chan;
+ value->type = CONFIG_IRC_CHAN;
+ value->irc_chan = lua_chan->chan;
break;
@@ -181,7 +184,7 @@
}
// apply it
- if (module_conf(lua_module->module, option, &value, &err))
+ if (module_conf(lua_module->module, option, values, &err))
return luaL_error(L, "module_conf: %s/%s: %s", module_name(lua_module->module), option->name, error_msg(&err));
// ok
--- a/src/nexus.c Tue Apr 07 21:09:25 2009 +0300
+++ b/src/nexus.c Wed Apr 08 01:28:46 2009 +0300
@@ -83,8 +83,8 @@
if (module->desc->config_options) {
const struct config_option *opt;
- for (opt = module->desc->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);
+ for (opt = module->desc->config_options; opt->name; opt++) {
+ printf(" --config %s:%s:%s\t\t%s\n", module->info.name, opt->name, "xxx", opt->help);
}
} else {