#ifndef CONFIG_H
#define CONFIG_H
/**
* @file
*
* Support for module configuration parameters
*/
#include "error.h"
#include <stdbool.h>
/**
* Different types of configuration parameters
*/
enum config_type {
CONFIG_INVALID,
/** No value at all */
CONFIG_NULL,
/** A plain NUL-terminated string */
CONFIG_STRING,
/** A user-defined type, further identified by a string */
CONFIG_USER,
/** An IRC channel */
CONFIG_IRC_CHAN,
};
/**
* A CONFIG_USER type info
*/
struct config_user_type {
/** The name of the type */
const char *name;
};
/**
* Structure to hold a value as defined by config_type
*/
struct config_value {
/** The type of the value */
enum config_type type;
/** The typed value */
union {
/** Value for CONFIG_STRING */
char *string;
/** Value for CONFIG_IRC_CHAN */
struct irc_chan *irc_chan;
/** Value for CONFIG_USER */
struct {
/** The specific user type */
const struct config_user_type *type;
/** The pointer value */
void *ptr;
} user;
};
};
/**
* Structure to define a single parameter for an option
*/
struct config_param {
/** The name of the arg */
const char *name;
/** The type */
enum config_type type;
/** The specific type for CONFIG_USER */
const struct config_user_type *user_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;
/** Use handler function? */
bool is_handler;
/** Optional value? */
bool optional;
};
/**
* 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_option *option, const struct config_value values[], struct error_info *err);
/** Help text */
const char *help;
};
#define CONFIG_PARAM(name, type, desc, optional) \
{ name, type, NULL, desc, { NULL }, false, optional }
#define CONFIG_PARAM_OPTIONAL(name, type, desc) \
CONFIG_PARAM(name, type, desc, true)
#define CONFIG_PARAM_USER(name, user_type, desc, optional) \
{ name, CONFIG_USER, user_type, desc, { NULL }, false, optional }
#define CONFIG_PARAM_USER_OPTIONAL(name, user_type, desc) \
CONFIG_PARAM_USER(name, user_type, desc, true)
#define CONFIG_PARAM_HANDLER(name, type, desc, _func_name_, func) \
{ name, type, NULL, desc, {._func_name_ = func }, true, false }
#define CONFIG_PARAM_END \
{ NULL, 0, NULL, NULL, { NULL }, false, false }
#define CONFIG_OPT(name, func, help, ...) \
{ name, { __VA_ARGS__, CONFIG_PARAM_END }, func, help }
#define CONFIG_OPT_STRING(name, func, desc, help) \
CONFIG_OPT(name, NULL, help, CONFIG_PARAM_HANDLER(name, CONFIG_STRING, desc, string, func))
#define CONFIG_OPT_IRC_CHAN(name, func, desc, help) \
CONFIG_OPT(name, NULL, help, CONFIG_PARAM_HANDLER(name, CONFIG_IRC_CHAN, desc, irc_chan, func))
#define CONFIG_OPT_END \
{ NULL, {}, NULL, NULL }
#define CONFIG_OPTIONS(...) \
{ __VA_ARGS__, CONFIG_OPT_END }
#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_USER(user_type, user_value) \
CONFIG_VALUE(CONFIG_USER, user, { user_type, user_value })
#define CONFIG_VALUE_END \
{ 0, { NULL } }
/**
* Lookup a config option by name.
*
* @param options a CONFIG_OPT_END-terminated array of config_option's
* @param name the config_option::name to look up
* @param err returned error info if not found
* @return a direct pointer to the config_option if found
*/
const struct config_option* config_lookup (const struct config_option *options, const char *name, struct error_info *err);
/**
* Returns the number of params that an option has
*
* @param option the option to count
* @return the number of params
*/
int config_params_count (const struct config_option *option);
// XXX: move this into nexus
#include "nexus.h"
/**
* Parse a raw value into a suitable configuration value for the given param, based on its type.
*
* Since this needs to access the application state, you need to pass in the nexus as an argument.
*
* Formats supported:
* CONFIG_IRC_CHAN - uses a '<network>/<channel>' format and irc_client_get_chan
*
*/
err_t config_parse_param (const struct config_param *param, struct nexus *nexus, struct config_value *value, char *raw_value, struct error_info *err);
/**
* Parse a raw value into a suitable configuration value for a single-param option, based on the config option type.
*
* @param option the option to parse the value for, use config_lookup to find it
* @param nexus the application state
* @param value the returned value, if succesfull
* @param raw_value the raw value to parse based on the type
* @param err returned error info
*/
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 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 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 values[], struct error_info *err);
/**
* 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 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 values[], struct error_info *err);
/**
* Apply a string value 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 string value
* @param err returned error info
*/
err_t config_apply_string (const struct config_option *options, void *ctx, const char *name, char *value, struct error_info *err);
/**
* Apply an irc_chan value 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 irc_chan value
* @param err returned error info
*/
err_t config_apply_irc_chan (const struct config_option *options, void *ctx, const char *name, struct irc_chan *value, struct error_info *err);
/**
* Parse and apply a configuration value for the named config opt.
*
* See config_parse() for more info.
*
* @param options a CONFIG_OPT_END-terminated array of config_option's
* @param nexus the application state
* @param ctx the context pointer for the option handler
* @param name the config_option::name to look up
* @param raw_value the raw value to parse
* @param err returned error info
*
* @see config_parse
*/
err_t config_apply_raw (const struct config_option option[], struct nexus *nexus, void *ctx, const char *name, char *raw_value, struct error_info *err);
/**
* Lookup a config_value by name from the given list of config_values for the given config_option
*/
const struct config_value* config_get_value (const struct config_option *option, const struct config_value values[], const char *name);
const char* config_get_string (const struct config_option *option, const struct config_value values[], const char *name);
struct irc_chan* config_get_irc_chan (const struct config_option *option, const struct config_value values[], const char *name);
void* config_get_user (const struct config_option *option, const struct config_value values[], const char *name, const struct config_user_type *user_type);
#endif