From 8e8a3b1ea25266201bc2dd5f3ebbe7514b0e06d4 Mon Sep 17 00:00:00 2001 From: Andrew Bettison Date: Tue, 27 Nov 2012 18:10:51 +1030 Subject: [PATCH] Improve new config prototype code Add label parser functions to ARRAY schema, use to enforce numeric argv labels numbered from 1. --- config.h | 35 ++++----- config_schema.h | 43 +++++++---- config_test.c | 194 ++++++++++++++++++++++++++++-------------------- 3 files changed, 163 insertions(+), 109 deletions(-) diff --git a/config.h b/config.h index 5cce977a..08eddc3c 100644 --- a/config.h +++ b/config.h @@ -211,10 +211,10 @@ struct pattern_list { __decl; \ } av[(__size)]; \ }; -#define ARRAY_ATOM(__name, __size, __type, __eltparser, __validator...) __ARRAY(__name, __size, __type value) -#define ARRAY_STRING(__name, __size, __strsize, __eltparser, __validator...) __ARRAY(__name, __size, char value[(__strsize) + 1]) -#define ARRAY_NODE(__name, __size, __type, __eltparser, __validator...) __ARRAY(__name, __size, __type value) -#define ARRAY_STRUCT(__name, __size, __structname, __validator...) __ARRAY(__name, __size, struct config_##__structname value) +#define ARRAY_ATOM(__name, __size, __type, __lblparser, __eltparser, __validator...) __ARRAY(__name, __size, __type value) +#define ARRAY_STRING(__name, __size, __strsize, __lblparser, __eltparser, __validator...) __ARRAY(__name, __size, char value[(__strsize) + 1]) +#define ARRAY_NODE(__name, __size, __type, __lblparser, __eltparser, __validator...) __ARRAY(__name, __size, __type value) +#define ARRAY_STRUCT(__name, __size, __structname, __lblparser, __validator...) __ARRAY(__name, __size, struct config_##__structname value) #include "config_schema.h" #undef STRUCT #undef NODE @@ -268,10 +268,10 @@ strbuf strbuf_cf_flags(strbuf, int); a->ac = 0; \ return CFOK; \ } -#define ARRAY_ATOM(__name, __size, __type, __eltparser, __validator...) __ARRAY(__name) -#define ARRAY_STRING(__name, __size, __strsize, __eltparser, __validator...) __ARRAY(__name) -#define ARRAY_NODE(__name, __size, __type, __eltparser, __validator...) __ARRAY(__name) -#define ARRAY_STRUCT(__name, __size, __structname, __validator...) __ARRAY(__name) +#define ARRAY_ATOM(__name, __size, __type, __lblparser, __eltparser, __validator...) __ARRAY(__name) +#define ARRAY_STRING(__name, __size, __strsize, __lblparser, __eltparser, __validator...) __ARRAY(__name) +#define ARRAY_NODE(__name, __size, __type, __lblparser, __eltparser, __validator...) __ARRAY(__name) +#define ARRAY_STRUCT(__name, __size, __structname, __lblparser, __validator...) __ARRAY(__name) #include "config_schema.h" #undef STRUCT #undef NODE @@ -318,20 +318,21 @@ struct cf_om_node { #define NODE_STRUCT(__name, __element, __parser, __flags) \ int __parser(struct config_##__name *, const struct cf_om_node *); #define END_STRUCT -#define __ARRAY(__name, __validator...) \ +#define __ARRAY(__name, __lblparser, __validator...) \ int opt_config_##__name(struct config_##__name *, const struct cf_om_node *); \ + int __lblparser(char *, size_t, const char *); \ __VALIDATOR(__name, ##__validator) -#define ARRAY_ATOM(__name, __size, __type, __eltparser, __validator...) \ - __ARRAY(__name, ##__validator) \ +#define ARRAY_ATOM(__name, __size, __type, __lblparser, __eltparser, __validator...) \ + __ARRAY(__name, __lblparser, ##__validator) \ int __eltparser(__type *, const struct cf_om_node *); -#define ARRAY_STRING(__name, __size, __strsize, __eltparser, __validator...) \ - __ARRAY(__name, ##__validator) \ +#define ARRAY_STRING(__name, __size, __strsize, __lblparser, __eltparser, __validator...) \ + __ARRAY(__name, __lblparser, ##__validator) \ int __eltparser(char *, size_t, const char *); -#define ARRAY_NODE(__name, __size, __type, __eltparser, __validator...) \ - __ARRAY(__name, ##__validator) \ +#define ARRAY_NODE(__name, __size, __type, __lblparser, __eltparser, __validator...) \ + __ARRAY(__name, __lblparser, ##__validator) \ int __eltparser(__type *, const struct cf_om_node *); -#define ARRAY_STRUCT(__name, __size, __structname, __validator...) \ - __ARRAY(__name, ##__validator) \ +#define ARRAY_STRUCT(__name, __size, __structname, __lblparser, __validator...) \ + __ARRAY(__name, __lblparser, ##__validator) \ int opt_config_##__structname(struct config_##__structname *, const struct cf_om_node *); #include "config_schema.h" #undef STRUCT diff --git a/config_schema.h b/config_schema.h index b20b9c2b..d21356d4 100644 --- a/config_schema.h +++ b/config_schema.h @@ -25,6 +25,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 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. * + * A configuration file consists of lines of the form: + * + * FULLKEY "=" VALUE "\n" + * + * where FULLKEY has the form KEY [ "." KEY [ "." KEY [ ... ] ] ] and VALUE is any string not + * containing newline. Lines ending with "\r\n" have the "\r" stripped from the end of VALUE. + * Otherwise VALUE is preserved exactly, with all leading and trailing spaces intact. + * * To describe a configuration file that looks like this: * * some.thing.element1=integer @@ -42,7 +50,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 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") + * ARRAY_STRUCT(joy, 16, happy, opt_str,, "An array of integer-string pairs") * * STRUCT(love) * SUB_STRUCT(happy, thing,) @@ -87,10 +95,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * NODE_STRUCT(structname, element, parsefunc, flags) * END_STRUCT * - * ARRAY_ATOM(name, size, type, parsefunc[, validatorfunc]) - * ARRAY_STRING(name, size, strsize, parsefunc[, validatorfunc]) - * ARRAY_NODE(name, size, type, parsefunc[, validatorfunc]) - * ARRAY_STRUCT(name, size, structname[, validatorfunc]) + * ARRAY_ATOM(name, size, type, labelparsefunc, valueparsefunc[, validatorfunc]) + * ARRAY_STRING(name, size, strsize, labelparsefunc, valueparsefunc[, validatorfunc]) + * ARRAY_NODE(name, size, type, labelparsefunc, valueparsefunc[, validatorfunc]) + * ARRAY_STRUCT(name, size, structname, labelparsefunc[, validatorfunc]) * * The meanings of the parameters are: * @@ -120,11 +128,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 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 a text 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). For arrays, the parsefunc is used to parse each element's value, not the - * entire array. Returns a CFxxx result code as documented in "config.h". + * The function used to parse a VALUE from the config file for a STRUCT element. The and ATOM + * and STRING parse functions take a string argument (const char *) which is the nul-terminated + * text of the VALUE (excluding the trailing \n or \r\n). The NODE and NODE_STRUCT parse + * functions take a pointer to a COM node (const struct cf_om_node *), which is the tree of all + * lines starting with the same partial FULLKEY. + * 'labelparsefunc' + * The function used to parse a KEY from the config file (the ) for each ARRAY element value. + * Takes a string argument (const char *). Returns a CFxxx result code as documented in + * "config.h". + * 'valueparsefunc' + * The function used to parse a VALUE from the config file for each ARRAY element value. The + * ARRAY_ATOM and ARRAY_STRING parse functions take a string argument (const char *). The + * ARRAY_NODE and ARRAY_STRUCT parse functions take a pointer to a COM node (const struct + * cf_om_node *). Returns a CFxxx result code as documented in "config.h". * 'validatorfunc' * A function that is called after the struct/array is fully parsed and populated. This * function can perform validation checks on the whole struct/array that cannot be performed by @@ -155,7 +172,7 @@ STRUCT(server) STRING(256, chdir, "/", opt_absolute_path,, "Absolute path of chdir(2) for server process") END_STRUCT -ARRAY_STRING(argv, 8, 128, opt_str, vld_argv) +ARRAY_STRING(argv, 8, 128, opt_argv_label, opt_str, vld_argv) STRUCT(executable) STRING(256, executable, "", opt_absolute_path, MANDATORY, "Absolute path of dna helper executable") @@ -172,7 +189,7 @@ STRING(256, host, "", opt_str_nonempty, MANDATORY, "Host n ATOM(uint16_t, port, RHIZOME_HTTP_PORT, opt_port,, "Port number") END_STRUCT -ARRAY_NODE(peerlist, 10, struct config_rhizomepeer, opt_rhizome_peer) +ARRAY_NODE(peerlist, 10, struct config_rhizomepeer, opt_str, opt_rhizome_peer) STRUCT(rhizomedirect) SUB_STRUCT(peerlist, peer,) @@ -196,7 +213,7 @@ ATOM(uint16_t, port, RHIZOME_HTTP_PORT, opt_port,, "Port numb ATOM(uint64_t, speed, 1000000, opt_uint64_scaled,, "Speed in bits per second") END_STRUCT -ARRAY_STRUCT(interface_list, 10, network_interface) +ARRAY_STRUCT(interface_list, 10, network_interface, opt_str) STRUCT(main) NODE_STRUCT(interface_list, interfaces, opt_interface_list, MANDATORY) diff --git a/config_test.c b/config_test.c index faed0c02..4366d18e 100644 --- a/config_test.c +++ b/config_test.c @@ -287,45 +287,61 @@ strbuf strbuf_cf_flags(strbuf sb, int flags) return sb; } -void warn_ignoring_node(const struct cf_om_node *node, int reason) + + +strbuf strbuf_cf_flag_reason(strbuf sb, int flags) { - const char *adj = NULL; - const char *why = NULL; - if (reason == CFERROR) - why = "unrecoverable error"; - else if (reason & CFINVALID) - adj = "invalid"; - else if (reason & CFINCOMPLETE) - why = "incomplete"; - else if (reason & CFARRAYOVERFLOW) - why = "array overflow"; - else if (reason & CFSTRINGOVERFLOW) - why = "string overflow"; - else if (reason & CFUNSUPPORTED) - adj = "unsupported"; - else if (reason & CFSUB(CFINVALID)) - adj = "contains invalid element"; - else if (reason & CFSUB(CFINCOMPLETE)) - why = "contains incomplete element"; - else if (reason & CFSUB(CFARRAYOVERFLOW)) - why = "contains array overflow"; - else if (reason & CFSUB(CFSTRINGOVERFLOW)) - why = "contains string overflow"; - else if (reason & CFSUB(CFUNSUPPORTED)) - why = "contains unsupported element"; - else if (reason & CFEMPTY) - why = "empty"; - else if (reason) - why = "unknown reason"; - else { - adj = "valid"; - why = "no reason"; + if (flags == CFERROR) + return strbuf_puts(sb, "unrecoverable error"); + size_t n = strbuf_len(sb); + static struct { int flag; const char *reason; } flagdefs[] = { + { CFEMPTY, "empty" }, + { CFSTRINGOVERFLOW, "string overflow" }, + { CFARRAYOVERFLOW, "array overflow" }, + { CFINCOMPLETE, "incomplete" }, + { CFINVALID, "invalid" }, + { CFUNSUPPORTED, "not supported" }, + { CFSUB(CFEMPTY), "contains empty element" }, + { CFSUB(CFSTRINGOVERFLOW), "contains string overflow" }, + { CFSUB(CFARRAYOVERFLOW), "contains array overflow" }, + { CFSUB(CFINCOMPLETE), "contains incomplete element" }, + { CFSUB(CFINVALID), "contains invalid element" }, + { CFSUB(CFUNSUPPORTED), "contains unsupported element" }, + }; + int i; + for (i = 0; i < NELS(flagdefs); ++i) { + if (flags & flagdefs[i].flag) { + if (strbuf_len(sb) != n) + strbuf_puts(sb, ", "); + strbuf_puts(sb, flagdefs[i].reason); + flags &= ~flagdefs[i].flag; + } + } + if (strbuf_len(sb) == n) + strbuf_puts(sb, "no reason"); + return sb; +} + +void warn_ignoring_value(const struct cf_om_node *node, int reason) +{ + strbuf b = strbuf_alloca(180); + strbuf_cf_flag_reason(b, reason); + warn_node(__FILE__, __LINE__, node, "ignoring value %s -- %s", alloca_str(node->text), strbuf_str(b)); +} + +void warn_unsupported_node(const struct cf_om_node *node) +{ + warn_node(__FILE__, __LINE__, node, "not supported"); +} + +void warn_unsupported_children(const struct cf_om_node *parent) +{ + int i; + for (i = 0; i < parent->nodc; ++i) { + if (parent->nodv[i]->text) + warn_unsupported_node(parent->nodv[i]); + warn_unsupported_children(parent->nodv[i]); } - warn_node(__FILE__, __LINE__, node, "ignoring%s%s value %s%s%s", - adj ? " " : "", adj ? adj : "", - alloca_str(node->text), - why ? " -- " : "", why ? why : "" - ); } void ignore_node(const struct cf_om_node *node, const char *msg) @@ -351,34 +367,31 @@ void ignore_tree(const struct cf_om_node *node, const char *msg) ignore_children(node, msg); } -void unsupported_node(const struct cf_om_node *node) -{ - ignore_node(node, "not supported"); -} - -void list_overflow(const struct cf_om_node *node) +void warn_list_overflow(const struct cf_om_node *node) { ignore_children(node, "list overflow"); } -void list_omit_element(const struct cf_om_node *node) -{ - ignore_node(node, "omitted from list"); -} - void spurious_children(const struct cf_om_node *parent) { ignore_children(parent, "spurious"); } -void unsupported_children(const struct cf_om_node *parent) +void warn_array_label(const struct cf_om_node *node, int reason) { - ignore_children(parent, "not supported"); + strbuf b = strbuf_alloca(180); + strbuf_cf_flag_reason(b, reason); + warn_node(__FILE__, __LINE__, node, "array label %s -- %s", alloca_str(node->key), strbuf_str(b)); } -void unsupported_tree(const struct cf_om_node *node) +void warn_array_value(const struct cf_om_node *node, int reason) { - ignore_tree(node, "not supported"); + strbuf b = strbuf_alloca(180); + strbuf_cf_flag_reason(b, reason); + if (node->text) + warn_node(__FILE__, __LINE__, node, "array value %s -- %s", alloca_str(node->text), strbuf_str(b)); + else + warn_node(__FILE__, __LINE__, node, "array element -- %s", strbuf_str(b)); } int opt_boolean(int *booleanp, const char *text); @@ -470,11 +483,11 @@ int opt_debugflags(debugflags_t *flagsp, const struct cf_om_node *node) int i; for (i = 0; i < node->nodc; ++i) { const struct cf_om_node *child = node->nodv[i]; - unsupported_children(child); + warn_unsupported_children(child); debugflags_t mask = debugFlagMask(child->key); int flag = -1; if (!mask) - unsupported_node(child); + warn_unsupported_node(child); else if (child->text) { int ret = opt_boolean(&flag, child->text); switch (ret) { @@ -494,7 +507,7 @@ int opt_debugflags(debugflags_t *flagsp, const struct cf_om_node *node) } break; default: - warn_ignoring_node(child, ret); + warn_ignoring_value(child, ret); result |= ret; break; } @@ -597,8 +610,27 @@ int opt_uint64_scaled(uint64_t *intp, const char *text) return CFOK; } +int opt_argv_label(char *str, size_t len, const char *text) +{ + const char *s = text; + if (isdigit(*s) && *s != '0') { + ++s; + while (isdigit(*s)) + ++s; + } + if (s == text || *s) + return CFINVALID; + if (s - text >= len) + return CFSTRINGOVERFLOW; + strncpy(str, text, len - 1)[len - 1] = '\0'; + return CFOK; +} + int vld_argv(struct config_argv *array, int result) { + int i; + for (i = 0; i < array->ac; ++i) { + } return result; } @@ -852,10 +884,8 @@ bye: } void missing_node(const struct cf_om_node *parent, const char *key); -void unsupported_node(const struct cf_om_node *node); -void unsupported_tree(const struct cf_om_node *node); -void list_overflow(const struct cf_om_node *node); -void list_omit_element(const struct cf_om_node *node); +void warn_unsupported_node(const struct cf_om_node *node); +void warn_list_overflow(const struct cf_om_node *node); // Schema item flags. #define __MANDATORY (1<<0) @@ -896,7 +926,7 @@ void list_omit_element(const struct cf_om_node *node); if (ret & ~CFEMPTY) { \ assert(child != NULL); \ if (child->text) \ - warn_ignoring_node(child, ret); \ + warn_ignoring_value(child, ret); \ result |= CFSUB(ret); \ } \ } @@ -915,11 +945,11 @@ void list_omit_element(const struct cf_om_node *node); int i; \ for (i = 0; i < node->nodc; ++i) { \ if (node->nodv[i]->text && !(used[i] & __TEXT)) { \ - unsupported_node(node->nodv[i]); \ + warn_unsupported_node(node->nodv[i]); \ result |= CFSUB(CFUNSUPPORTED); \ } \ if (node->nodv[i]->nodc && !(used[i] & __CHILDREN)) { \ - unsupported_children(node->nodv[i]); \ + warn_unsupported_children(node->nodv[i]); \ result |= CFSUB(CFUNSUPPORTED); \ } \ } \ @@ -929,32 +959,38 @@ void list_omit_element(const struct cf_om_node *node); return result; \ } -#define __ARRAY(__name, __parseexpr, __validator...) \ +#define __ARRAY(__name, __lblparser, __parseexpr, __validator...) \ int opt_config_##__name(struct config_##__name *array, const struct cf_om_node *node) { \ int (*validator)(struct config_##__name *, int) = (NULL, ##__validator); \ int result = CFOK; \ int i, n; \ for (n = 0, i = 0; i < node->nodc && n < NELS(array->av); ++i) { \ const struct cf_om_node *child = node->nodv[i]; \ - int ret = (__parseexpr); \ + int ret = __lblparser(array->av[n].label, sizeof array->av[n].label, child->key); \ if (ret == CFERROR) \ return CFERROR; \ result |= ret & CF__SUBFLAGS; \ ret &= CF__FLAGS; \ - if (ret == CFOK) { \ - strncpy(array->av[n].label, child->key, sizeof array->av[n].label - 1)\ - [sizeof array->av[n].label - 1] = '\0'; \ - ++n; \ - } else { \ - list_omit_element(child); \ + if (ret != CFOK) \ + warn_array_label(child, ret); \ + else { \ + ret = (__parseexpr); \ + if (ret == CFERROR) \ + return CFERROR; \ + result |= ret & CF__SUBFLAGS; \ + ret &= CF__FLAGS; \ result |= CFSUB(ret); \ + if (ret == CFOK) \ + ++n; \ + else \ + warn_array_value(child, ret); \ } \ } \ if (i < node->nodc) { \ assert(n == NELS(array->av)); \ result |= CFARRAYOVERFLOW; \ for (; i < node->nodc; ++i) \ - list_overflow(node->nodv[i]); \ + warn_list_overflow(node->nodv[i]); \ } \ array->ac = n; \ if (validator) \ @@ -965,14 +1001,14 @@ void list_omit_element(const struct cf_om_node *node); result |= CFEMPTY; \ return result; \ } -#define ARRAY_ATOM(__name, __size, __type, __eltparser, __validator...) \ - __ARRAY(__name, child->text ? __eltparser(&array->av[n].value, child->text) : CFEMPTY, ##__validator) -#define ARRAY_STRING(__name, __size, __strsize, __eltparser, __validator...) \ - __ARRAY(__name, child->text ? __eltparser(array->av[n].value, sizeof array->av[n].value, child->text) : CFEMPTY, ##__validator) -#define ARRAY_NODE(__name, __size, __type, __eltparser, __validator...) \ - __ARRAY(__name, __eltparser(&array->av[n].value, child), ##__validator) -#define ARRAY_STRUCT(__name, __size, __structname, __validator...) \ - __ARRAY(__name, opt_config_##__structname(&array->av[n].value, child), ##__validator) +#define ARRAY_ATOM(__name, __size, __type, __lblparser, __eltparser, __validator...) \ + __ARRAY(__name, __lblparser, child->text ? __eltparser(&array->av[n].value, child->text) : CFEMPTY, ##__validator) +#define ARRAY_STRING(__name, __size, __strsize, __lblparser, __eltparser, __validator...) \ + __ARRAY(__name, __lblparser, child->text ? __eltparser(array->av[n].value, sizeof array->av[n].value, child->text) : CFEMPTY, ##__validator) +#define ARRAY_NODE(__name, __size, __type, __lblparser, __eltparser, __validator...) \ + __ARRAY(__name, __lblparser, __eltparser(&array->av[n].value, child), ##__validator) +#define ARRAY_STRUCT(__name, __size, __structname, __lblparser, __validator...) \ + __ARRAY(__name, __lblparser, opt_config_##__structname(&array->av[n].value, child), ##__validator) #include "config_schema.h"