terom@83: #ifndef CONFIG_H terom@83: #define CONFIG_H terom@83: terom@83: /** terom@87: * @file terom@87: * terom@83: * Support for module configuration parameters terom@83: */ terom@217: #include terom@120: #include terom@83: terom@217: enum config_error_code { terom@217: ERR_CONFIG_NONE, terom@217: ERR_CONFIG_NAME, ///< unknown option name terom@217: ERR_CONFIG_TYPE, ///< invalid value type for parameter terom@217: ERR_CONFIG_REQUIRED, ///< missing value for required parameter terom@217: ERR_CONFIG_VALUE, ///< invalid value terom@217: ERR_CONFIG_PARAMS, ///< invalid number of parameters terom@217: }; terom@217: terom@217: const struct error_list config_errors; terom@217: terom@83: /** terom@83: * Different types of configuration parameters terom@83: */ terom@83: enum config_type { terom@83: CONFIG_INVALID, terom@83: terom@121: /** No value at all */ terom@121: CONFIG_NULL, terom@121: terom@83: /** A plain NUL-terminated string */ terom@83: CONFIG_STRING, terom@100: terom@121: /** A user-defined type, further identified by a string */ terom@121: CONFIG_USER, terom@121: terom@100: /** An IRC channel */ terom@100: CONFIG_IRC_CHAN, terom@100: }; terom@100: terom@100: /** terom@154: * A CONFIG_USER type info terom@154: */ terom@154: struct config_user_type { terom@154: /** The name of the type */ terom@154: const char *name; terom@154: }; terom@154: terom@154: /** terom@100: * Structure to hold a value as defined by config_type terom@100: */ terom@100: struct config_value { terom@100: /** The type of the value */ terom@100: enum config_type type; terom@100: terom@100: /** The typed value */ terom@100: union { terom@100: /** Value for CONFIG_STRING */ terom@100: char *string; terom@100: terom@100: /** Value for CONFIG_IRC_CHAN */ terom@100: struct irc_chan *irc_chan; terom@121: terom@121: /** Value for CONFIG_USER */ terom@121: struct { terom@121: /** The specific user type */ terom@154: const struct config_user_type *type; terom@121: terom@154: /** The pointer value */ terom@121: void *ptr; terom@121: } user; terom@100: }; terom@83: }; terom@83: terom@87: /** terom@120: * Structure to define a single parameter for an option terom@87: */ terom@120: struct config_param { terom@120: /** The name of the arg */ terom@83: const char *name; terom@83: terom@120: /** The type */ terom@83: enum config_type type; terom@120: terom@121: /** The specific type for CONFIG_USER */ terom@154: const struct config_user_type *user_type; terom@121: terom@120: /** Description */ terom@120: const char *description; terom@120: terom@120: /** Optional value handler function, by type */ terom@100: union { terom@217: err_t (*string) (void *ctx, char *value, error_t *err); terom@217: err_t (*irc_chan) (void *ctx, struct irc_chan *chan, error_t *err); terom@100: } func; terom@83: terom@120: /** Use handler function? */ terom@120: bool is_handler; terom@121: terom@121: /** Optional value? */ terom@121: bool optional; terom@120: }; terom@120: terom@120: /** terom@120: * The maximum number of parameters that a single option can have, although this includes the terminating NULL terom@120: */ terom@120: #define CONFIG_PARAMS_MAX (15 + 1) terom@120: terom@120: /** terom@120: * The maximum number of values that an option can access, including the terminating NULL terom@120: */ terom@120: #define CONFIG_VALUES_MAX CONFIG_PARAMS_MAX terom@120: terom@120: /** terom@120: * A more complicated configuration option that can have multiple parameters terom@120: */ terom@120: struct config_option { terom@120: /** The name of the config option */ terom@120: const char *name; terom@120: terom@120: /** The list of parameters */ terom@120: const struct config_param params[CONFIG_PARAMS_MAX]; terom@120: terom@120: /** The handler function */ terom@217: err_t (*func) (void *ctx, const struct config_option *option, const struct config_value values[], error_t *err); terom@83: terom@83: /** Help text */ terom@83: const char *help; terom@83: }; terom@83: terom@121: #define CONFIG_PARAM(name, type, desc, optional) \ terom@121: { name, type, NULL, desc, { NULL }, false, optional } terom@121: terom@121: #define CONFIG_PARAM_OPTIONAL(name, type, desc) \ terom@121: CONFIG_PARAM(name, type, desc, true) terom@121: terom@121: #define CONFIG_PARAM_USER(name, user_type, desc, optional) \ terom@121: { name, CONFIG_USER, user_type, desc, { NULL }, false, optional } terom@121: terom@121: #define CONFIG_PARAM_USER_OPTIONAL(name, user_type, desc) \ terom@121: CONFIG_PARAM_USER(name, user_type, desc, true) terom@120: terom@120: #define CONFIG_PARAM_HANDLER(name, type, desc, _func_name_, func) \ terom@121: { name, type, NULL, desc, {._func_name_ = func }, true, false } terom@120: terom@121: #define CONFIG_PARAM_END \ terom@121: { NULL, 0, NULL, NULL, { NULL }, false, false } terom@121: terom@121: #define CONFIG_OPT(name, func, help, ...) \ terom@121: { name, { __VA_ARGS__, CONFIG_PARAM_END }, func, help } terom@120: terom@100: #define CONFIG_OPT_STRING(name, func, desc, help) \ terom@121: CONFIG_OPT(name, NULL, help, CONFIG_PARAM_HANDLER(name, CONFIG_STRING, desc, string, func)) terom@100: terom@100: #define CONFIG_OPT_IRC_CHAN(name, func, desc, help) \ terom@121: CONFIG_OPT(name, NULL, help, CONFIG_PARAM_HANDLER(name, CONFIG_IRC_CHAN, desc, irc_chan, func)) terom@100: terom@100: #define CONFIG_OPT_END \ terom@120: { NULL, {}, NULL, NULL } terom@120: terom@121: #define CONFIG_OPTIONS(...) \ terom@121: { __VA_ARGS__, CONFIG_OPT_END } terom@121: terom@120: #define CONFIG_VALUE(type, _name_, value) \ terom@121: { (type), { ._name_ = value } } terom@120: terom@120: #define CONFIG_VALUE_STRING(str_value) \ terom@121: CONFIG_VALUE(CONFIG_STRING, string, (str_value)) terom@120: terom@120: #define CONFIG_VALUE_IRC_CHAN(irc_chan_value) \ terom@121: CONFIG_VALUE(CONFIG_IRC_CHAN, irc_chan, (irc_chan_value)) terom@121: terom@121: #define CONFIG_VALUE_USER(user_type, user_value) \ terom@121: CONFIG_VALUE(CONFIG_USER, user, { user_type, user_value }) terom@120: terom@120: #define CONFIG_VALUE_END \ terom@120: { 0, { NULL } } terom@100: terom@83: /** terom@100: * Lookup a config option by name. terom@83: * terom@100: * @param options a CONFIG_OPT_END-terminated array of config_option's terom@100: * @param name the config_option::name to look up terom@100: * @param err returned error info if not found terom@100: * @return a direct pointer to the config_option if found terom@83: */ terom@217: const struct config_option* config_lookup (const struct config_option *options, const char *name, error_t *err); terom@100: terom@122: /** terom@122: * Returns the number of params that an option has terom@122: * terom@122: * @param option the option to count terom@122: * @return the number of params terom@122: */ terom@122: int config_params_count (const struct config_option *option); terom@122: terom@100: // XXX: move this into nexus terom@100: #include "nexus.h" terom@100: /** terom@122: * Parse a raw value into a suitable configuration value for the given param, based on its type. terom@100: * terom@100: * Since this needs to access the application state, you need to pass in the nexus as an argument. terom@100: * terom@100: * Formats supported: terom@100: * CONFIG_IRC_CHAN - uses a '/' format and irc_client_get_chan terom@100: * terom@122: */ terom@217: err_t config_parse_param (const struct config_param *param, struct nexus *nexus, struct config_value *value, char *raw_value, error_t *err); terom@122: terom@122: /** terom@122: * Parse a raw value into a suitable configuration value for a single-param option, based on the config option type. terom@122: * terom@100: * @param option the option to parse the value for, use config_lookup to find it terom@100: * @param nexus the application state terom@100: * @param value the returned value, if succesfull terom@100: * @param raw_value the raw value to parse based on the type terom@100: * @param err returned error info terom@100: */ terom@217: err_t config_parse (const struct config_option *option, struct nexus *nexus, struct config_value *value, char *raw_value, error_t *err); terom@100: terom@100: /** terom@120: * Apply a list of parsed configuration values to the given config_option struct. terom@100: * terom@100: * The config option handlers take a context argument; the value of this depends on the implementor of the config_option. terom@100: * terom@100: * @param option the option to apply terom@100: * @param ctx the context pointer for the option handler terom@120: * @param values the NULL-terminated array of parsed values terom@100: * @param err returned error info terom@100: */ terom@217: err_t config_apply_opt (const struct config_option *option, void *ctx, const struct config_value values[], error_t *err); terom@100: terom@100: /** terom@120: * Apply a list of parsed configuration values for the named config opt. terom@100: * terom@100: * @param options a CONFIG_OPT_END-terminated array of config_option's terom@100: * @param ctx the context pointer for the option handler terom@100: * @param name the config_option::name to look up terom@120: * @param values the NULL-termianted array of parsed values terom@100: * @param err returned error info terom@100: */ terom@217: err_t config_apply (const struct config_option *options, void *ctx, const char *name, const struct config_value values[], error_t *err); terom@100: terom@100: /** terom@100: * Apply a string value for the named config opt. terom@100: * terom@100: * @param options a CONFIG_OPT_END-terminated array of config_option's terom@100: * @param ctx the context pointer for the option handler terom@100: * @param name the config_option::name to look up terom@100: * @param value the string value terom@100: * @param err returned error info terom@100: */ terom@217: err_t config_apply_string (const struct config_option *options, void *ctx, const char *name, char *value, error_t *err); terom@100: terom@100: /** terom@100: * Apply an irc_chan value for the named config opt. terom@100: * terom@100: * @param options a CONFIG_OPT_END-terminated array of config_option's terom@100: * @param ctx the context pointer for the option handler terom@100: * @param name the config_option::name to look up terom@100: * @param value the irc_chan value terom@100: * @param err returned error info terom@100: */ terom@217: err_t config_apply_irc_chan (const struct config_option *options, void *ctx, const char *name, struct irc_chan *value, error_t *err); terom@100: terom@100: /** terom@100: * Parse and apply a configuration value for the named config opt. terom@100: * terom@100: * See config_parse() for more info. terom@100: * terom@100: * @param options a CONFIG_OPT_END-terminated array of config_option's terom@100: * @param nexus the application state terom@100: * @param ctx the context pointer for the option handler terom@100: * @param name the config_option::name to look up terom@100: * @param raw_value the raw value to parse terom@100: * @param err returned error info terom@100: * terom@100: * @see config_parse terom@100: */ terom@217: err_t config_apply_raw (const struct config_option option[], struct nexus *nexus, void *ctx, const char *name, char *raw_value, error_t *err); terom@121: terom@121: /** terom@121: * Lookup a config_value by name from the given list of config_values for the given config_option terom@121: */ terom@121: const struct config_value* config_get_value (const struct config_option *option, const struct config_value values[], const char *name); terom@121: terom@121: const char* config_get_string (const struct config_option *option, const struct config_value values[], const char *name); terom@121: struct irc_chan* config_get_irc_chan (const struct config_option *option, const struct config_value values[], const char *name); terom@154: void* config_get_user (const struct config_option *option, const struct config_value values[], const char *name, const struct config_user_type *user_type); terom@83: terom@83: #endif