sslbd/config.hpp
#pragma once
#include "common.hpp"
#include "files.hpp"
#include "hooks.hpp"
#include <vector>
#define CONFIG_MAX_STR_LEN 100
/** When inherited from, this is a factory for use with CONF_KEY_INST(), passing the actual config value to the constructor. */
template <class A> class ConfigInst {
protected:
ConfigInst() {}
public:
virtual ~ConfigInst() {}
virtual bool is_valid() const = 0;
template <class C> static ConfigInst<A>* getConfigInst(A a) {
ConfigInst<A>* rv = new C(a);
if (rv->is_valid()) return rv;
delete rv;
return NULL;
}
};
class ConfigKey {
public:
typedef bool (*handler_t)(void*&, char*); ///< parser, false rv rejects whole config
typedef void (*unhandler_t)(void*&); ///< upon shutdown or config rollback/switch (for cleanup)
typedef ConfigInst<char*>* (*getinst_str_t)(char*);
typedef ConfigInst<size_t>* (*getinst_size_t)(size_t); ///< 0 means disabled
typedef enum {CONFIG_TYPE_STR, CONFIG_TYPE_INT, CONFIG_TYPE_BOOL, CONFIG_TYPE_STR_CLASS, CONFIG_TYPE_SIZE_CLASS, CONFIG_TYPE_HANDLER} type_t;
typedef union { // ConfigKey must be iterable/same size, so no templated sub-class here (w/ partial specialization)
struct {
char str[CONFIG_MAX_STR_LEN+1];
size_t len;
} str;
int num;
bool bin;
struct {
handler_t handler;
unhandler_t unhandler;
void* ctx; ///< opaque, for module's usage w/ handlers
} handler;
struct {
union {
getinst_str_t str_handler;
getinst_size_t num_handler;
};
void* ctx; // ConfigInst* actually
} inst;
} val_t;
private:
char key[CONFIG_MAX_STR_LEN+1];
const bool reconfigurable; ///< can be reconfigured between config instances?
const bool multi; ///< can be stated multiple times within the same config instance? also false if not reconfigurable lateron.
bool parsed; ///< some value has been set (non-default). true also after dup() if not reconfigurable.
ConfigKey* child; ///< refcount for #val destruction, @see dup()
ConfigKey* parent; ///< refcount for #val destruction, @see dup()
const type_t type;
val_t default_val;
ConfigKey(ConfigKey*); ///< @see dup()
public:
ConfigKey(const char*, bool, const char*);
ConfigKey(const char*, bool, int);
ConfigKey(const char*, bool, bool);
ConfigKey(const char*, bool, bool, handler_t, unhandler_t=NULL); ///< multiple calls only for custom handler type
ConfigKey(const char*, bool, getinst_str_t);
ConfigKey(const char*, bool, getinst_size_t);
~ConfigKey();
val_t val;
template <class T> INLINE T* ctx_as() { ///< convenience wrapper for omitting cast for val.[handler|inst].ctx
return (type == CONFIG_TYPE_HANDLER)? (T*)val.handler.ctx: ((type == CONFIG_TYPE_STR_CLASS || type == CONFIG_TYPE_SIZE_CLASS)? (T*)val.inst.ctx: NULL);
}
INLINE const char* get_key() const { return key; }
bool parse(char*); ///< config value parsing
bool parse() const { return !parsed || reconfigurable || multi; } ///< could parse again w/o expected error?
void dup(ConfigKey*); ///< creates a child from a parent for new config instance
void info() const;
};
class Config {
private:
typedef struct config_s {
ConfigKey** conf; ///< pointer to the module's local storage. NOTE: configs must be iterable, i.e. castable to ConfigKey[]
ConfigKey* next_conf; ///< the next config, currently being processed
size_t len; ///< # of entries in #conf
void(*init)(ConfigKey*); ///< user-defined initialization func
} config_t;
static std::vector<config_t> configs; ///< all statically registered configs
static bool load(char*, size_t, intptr_t); // line handler
bool load(char*); // line
bool load(const char*, char*); // k/v
bool loaded;
public:
Config(const char*); ///< finalizes #configs from NULL to default values
~Config();
const char* const fn;
bool load(); ///< (re-)loads the config file (blocking read).
bool load(char*, size_t); ///< (re-)loads the config from given buffer (possibly read async).
void info() const;
static void add(ConfigKey**, size_t, void(*)(ConfigKey*)); ///< exclusive use by CONF_KEY_INIT()
};
#define CONF_DEF(cname) \
struct CONCAT(cname, _s); \
static CONCAT(cname, _s)* cname = NULL; \
struct CONCAT(cname, _s)
#define CONF_INIT(cname) \
static void CONCAT(cname, _i)(CONCAT(cname, _s)*); \
UNUSED static const int CONCAT(cname, _dummy) = (Config::add((ConfigKey**)&cname, sizeof(CONCAT(cname, _s))/sizeof(ConfigKey), (void(*)(ConfigKey*))&CONCAT(cname, _i)), 42); \
static void CONCAT(cname, _i)(CONCAT(cname, _s)* c)
#define CONF_KEY_INIT(k, r, ...) new (&c->k)ConfigKey(STRINGIFY(k), r, __VA_ARGS__)
#define CONF_KEY_INST(k, r, t, a) new (&c->k)ConfigKey(STRINGIFY(k), r, &ConfigInst<a>::getConfigInst<t>)