Improve new config prototype code

Add label parser functions to ARRAY schema, use to enforce numeric argv labels
numbered from 1.
This commit is contained in:
Andrew Bettison 2012-11-27 18:10:51 +10:30
parent 479ec5d0df
commit 8e8a3b1ea2
3 changed files with 163 additions and 109 deletions

View File

@ -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

View File

@ -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)

View File

@ -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"