src/config.h
author Tero Marttila <terom@fixme.fi>
Mon, 04 May 2009 20:55:04 +0300
branchnew-transport
changeset 168 a58ad50911fc
parent 154 f4472119de3b
permissions -rw-r--r--
refactor test.c into tests/*
#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