From 0091cf082b8de9cc9375f0170c1b855e2e2a9612 Mon Sep 17 00:00:00 2001 From: Andrew Bettison Date: Mon, 26 Nov 2012 16:15:59 +1030 Subject: [PATCH] Add documentation comments for new config code --- config.h | 101 +++++++++++++++++++++++++++++++++++++++++++ config_schema.h | 113 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+) diff --git a/config.h b/config.h index ab70694c..64743b65 100644 --- a/config.h +++ b/config.h @@ -20,6 +20,107 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef __SERVALDNA_CONFIG_H #define __SERVALDNA_CONFIG_H +/* This file defines the internal API to the configuration file. See "config_schema.h" for the + * definition of the configuration schema, which is used to generate these API components. + * + * Each STRUCT(foo) schema declaration produces the following data declaration: + * + * struct config_foo { + * TYPE NAME; + * ... + * }; + * + * A C struct definition containing exactly one element per schema declaration inside the + * STRUCT..END_STRUCT block, in the defined order. The TYPE and NAME of each element depends + * on the schema declaration that produces it: + * + * ATOM(TYPE, bar, ...) + * NODE(TYPE, bar, ...) + * + * TYPE bar; + * + * STRING(SIZE, bar, ...) + * + * char bar[SIZE+1]; + * + * SUB_STRUCT(NAME, bar, ...) + * NODE_STRUCT(NAME, bar, ...) + * + * struct config_NAME bar; + * + * Each ARRAY_*(SIZE, bar, ...) schema declaration produces the following data declaration: + * + * struct config_bar { + * unsigned ac; + * struct { + * char label[N]; // please discover N using sizeof() + * TYPE value; + * } av[SIZE]; + * }; + * + * A C struct definition containing a count 'ac' of the number of array elements [0..SIZE-1] + * and 'av' an array of element values, each one consisting of a label and the value itself, + * whose TYPE depends on the ARRAY_* declaration itself: + * + * ARRAY_ATOM(NAME, SIZE, TYPE, ...) + * ARRAY_NODE(NAME, SIZE, TYPE, ...) + * + * TYPE value; + * + * ARRAY_STRING(NAME, SIZE, STRINGSIZE, ...) + * + * char value[STRINGSIZE]; + * + * ARRAY_STRUCT(NAME, SIZE, STRUCTNAME, ...) + * + * struct config_STRUCTNAME value; + * + * Each STRUCT(foo) and ARRAY_*(SIZE, foo, ...) schema declaration produces the following API + * functions: + * + * - int dfl_config_foo(struct config_foo *dest); + * + * A C function which sets the entire contents of the given C structure to its default values + * as defined in the schema. This will only return CFOK or CFERROR; see below. + * + * - int opt_config_foo(struct config_foo *dest, const struct cf_om_node *node); + * + * A C function which parses the given COM (configuration object model) and assigns the parsed + * result into the given C structure. See below for the return value. + * + * All parse functions assign the result of their parsing into the struct given in their 'dest' + * argument, and return a bitmask of the following flags: + * + * - CFERROR (all bits set, == -1) if an unrecoverable error occurrs (eg, malloc() fails); the + * result in *dest is undefined and may be malformed or inconsistent; + * + * - CFEMPTY if no items were encountered in the COM (ie, no array elements or no struct elements); + * the memory at *dest is unchanged; + * + * - CFARRAYOVERFLOW if the size of any array was exceeded; a valid result is produced and the + * overflowed array(s) are fully populated, arbitrarily omitting some elements that were found in + * the COM; + * + * - CFSTRINGFOVERFLOW if the size of any string element was exceeded, a valid result is produced + * but the overflowed string elements are unchanged -- those parts of *dest are not overwritten; + * + * - CFINCOMPLETE if any MANDATORY element was missing; a valid result is produced but the missing + * mandatory element(s) are unchanged -- those parts of *dest are not overwritten; + * + * - CFINVALID if any invalid configuration value was encountered, ie, any parse function returned + * CFINVALID in its return flags; a valid result is produced but the invalid elements are + * unchanged -- those parts of *dest are not overwritten; + * + * - CFSUB(CFxxx) if the STRUCT parser function encountered the error CFxxx when parsing a struct + * element, ie, a parse function returned CFxxx; a valid result is produced but some parts of + * *dest will not be overwritten; + * + * The special value CFOK is zero (no bits set); in this case a valid result is produced and all of + * *dest is overwritten (except unused array elements). + * + * @author Andrew Bettison + */ + #include #include "constants.h" #include "strbuf.h" diff --git a/config_schema.h b/config_schema.h index a116042a..104c7891 100644 --- a/config_schema.h +++ b/config_schema.h @@ -17,6 +17,119 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/* This file contains definitions for the schema of the Serval DNA configuration file. See comments + * in "config.h" for a description of the internal configuration API. + * + * A configuration schema is set of nested structures and arrays. By convention, the top level, or + * root of the schema is called "main", but every structure and array has its own complete API which + * can be used by itself. So if there were two independent configuration files, both could be + * defined in this file, each with a conventional name for its own root element. + * + * To describe a configuration file that looks like this: + * + * some.thing.element1=integer + * some.thing.element2=string + * some.list.foo.element1=integer + * some.list.foo.element2=string + * some.list.bar.element1=integer + * some.list.bar.element2=string + * another_thing=http://my.host.com:1234/path/to/nowhere + * + * the following schema would do: + * + * STRUCT(happy) + * ATOM(int32_t, element1, 0, opt_int32_nonnegative,, "An integer >= 0") + * STRING(80, element2, "boo!", opt_str_nonempty, MANDATORY, "A non-empty string") + * END_STRUCT + * + * ARRAY_STRUCT(joy, 16, happy, "An array of integer-string pairs") + * + * STRUCT(love) + * SUB_STRUCT(happy, thing,) + * SUB_STRUCT(joy, list,) + * END_STRUCT + * + * STRUCT(main) + * SUB_STRUCT(love, some,) + * STRING(128, another_thing, "", opt_uri,, "URL; protocol://hostname[:port][/path]") + * END_STRUCT + * + * which would produce an API based on the following definitions (see "config.h" for more + * information): + * + * struct config_happy { + * int32_t element1; + * char element2[81]; + * }; + * struct config_joy { + * unsigned ac; + * struct { + * char label[N]; // please discover N using sizeof() + * struct config_happy value; + * } av[16]; + * }; + * struct config_love { + * struct config_happy thing; + * struct config_joy list; + * }; + * struct config_main { + * struct config_love some; + * char another_thing[129]; + * }; + * + * A schema definition is composed from the following STRUCT and ARRAY definitions: + * + * STRUCT(name) + * ATOM(type, element, default, parsefunc, flags, comment) + * NODE(type, element, default, parsefunc, flags, comment) + * STRING(size, element, default, parsefunc, flags, comment) + * SUB_STRUCT(structname, element, flags) + * NODE_STRUCT(structname, element, parsefunc, flags) + * END_STRUCT + * + * ARRAY_ATOM(name, size, type, parsefunc, comment) + * ARRAY_STRING(name, size, parsefunc, comment) + * ARRAY_NODE(name, size, type, parsefunc, comment) + * ARRAY_STRUCT(name, size, structname, comment) + * + * The meanings of the parameters are: + * + * 'name' + * A label used to qualify this struct/array's API from the API components of other structs and + * arrays. This label does not appear anywhere in the config file itself; it is purely for + * internal code-related purposes. + * 'type' + * Only used for ATOM, NODE, ARRAY_ATOM and ARRAY_NODE declarations. Gives the C type of the + * element. For STRING and ARRAY_STRING, this is implicitly (const char *). + * 'structname' + * Only used for SUB_STRUCT, NODE_STRUCT and ARRAY_STRUCT declarations. Identifies a sub- + * structure by 'name' to nest in the enclosing struct or array. + * 'element' + * The name of the struct element and the key in the configuration file. This name does appear + * in the config file and also in the API, so that an option mamed "some.thing.element1" in the + * file is referred to as some.thing.element1 in the C code. Arrays are more complicated: + * "some.list.foo.element1" in the config file is referred to as some.list.av[n].value.element1 + * in the C code, and some.list.ac gives the size of the some.list.av array. + * 'default' + * Only used for ATOM and NODE struct elements. Gives the default value for the element if + * absent from the config file. + * 'parsefunc' + * The function used to parse the value from the config file. The ATOM, STRING, ARRAY_ATOM and + * ARRAY_STRING parse functions take a string argument (const char *). The NODE, NODE_STRUCT + * and ARRAY_NODE parse functions take a pointer to a COM node (const struct cf_om_node). + * 'flags' + * A space-separated list of flags. At present only the MANDATORY flag is supported, which + * will cause parsing to fail if the given STRUCT element is not set in the config file. In + * the case of struct elements that are arrays, the config file must set at least one element + * of the array, or parsing fails. + * 'comment' + * A human-readable string describing the value of the configuration option. Must be + * informative enough to help users diagnose parse errors. Eg, "An integer" is not enough; + * better would be "Integer >= 0, number of seconds since Unix epoch". + * + * @author Andrew Bettison + */ + STRUCT(log) STRING(256, file, "", opt_absolute_path,, "Absolute path of log file") ATOM(int, show_pid, 1, opt_boolean,, "If true, all log lines contain PID of logging process")