Improve new config prototype code

Sort ARRAYs if optional key comparison function is given in schema, no longer
the role of the validator function.
This commit is contained in:
Andrew Bettison 2012-11-29 11:48:01 +10:30
parent e2f6989fe8
commit b940ac8617
3 changed files with 163 additions and 24 deletions

View File

@ -199,7 +199,7 @@ struct pattern_list {
}; };
#define PATTERN_LIST_EMPTY ((struct pattern_list){.patc = 0}) #define PATTERN_LIST_EMPTY ((struct pattern_list){.patc = 0})
// Generate value structs, struct config_SECTION. // Generate value structs, struct config_NAME.
#define STRUCT(__name, __validator...) \ #define STRUCT(__name, __validator...) \
struct config_##__name { struct config_##__name {
#define NODE(__type, __element, __default, __parser, __flags, __comment) \ #define NODE(__type, __element, __default, __parser, __flags, __comment) \
@ -218,9 +218,9 @@ struct pattern_list {
struct config_##__name { \ struct config_##__name { \
unsigned ac; \ unsigned ac; \
struct config_##__name##__element { struct config_##__name##__element {
#define KEY_ATOM(__type, __eltparser) \ #define KEY_ATOM(__type, __eltparser, __cmpfunc...) \
__type key; __type key;
#define KEY_STRING(__strsize, __eltparser) \ #define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \
char key[(__strsize) + 1]; char key[(__strsize) + 1];
#define VALUE_ATOM(__type, __eltparser) \ #define VALUE_ATOM(__type, __eltparser) \
__type value; __type value;
@ -270,7 +270,7 @@ struct pattern_list {
strbuf strbuf_cf_flags(strbuf, int); strbuf strbuf_cf_flags(strbuf, int);
// Generate default functions, dfl_config_SECTION(). // Generate default functions, dfl_config_NAME().
#define STRUCT(__name, __validator...) \ #define STRUCT(__name, __validator...) \
int dfl_config_##__name(struct config_##__name *s) { int dfl_config_##__name(struct config_##__name *s) {
@ -292,8 +292,8 @@ strbuf strbuf_cf_flags(strbuf, int);
a->ac = 0; \ a->ac = 0; \
return CFOK; \ return CFOK; \
} }
#define KEY_ATOM(__type, __eltparser) #define KEY_ATOM(__type, __eltparser, __cmpfunc...)
#define KEY_STRING(__strsize, __eltparser) #define KEY_STRING(__strsize, __eltparser, __cmpfunc...)
#define VALUE_ATOM(__type, __eltparser) #define VALUE_ATOM(__type, __eltparser)
#define VALUE_STRING(__strsize, __eltparser) #define VALUE_STRING(__strsize, __eltparser)
#define VALUE_NODE(__type, __eltparser) #define VALUE_NODE(__type, __eltparser)
@ -353,9 +353,9 @@ struct cf_om_node {
#define ARRAY(__name, __validator...) \ #define ARRAY(__name, __validator...) \
int opt_config_##__name(struct config_##__name *, const struct cf_om_node *); \ int opt_config_##__name(struct config_##__name *, const struct cf_om_node *); \
__VALIDATOR(__name, ##__validator) __VALIDATOR(__name, ##__validator)
#define KEY_ATOM(__type, __eltparser) \ #define KEY_ATOM(__type, __eltparser, __cmpfunc...) \
int __eltparser(__type *, const char *); int __eltparser(__type *, const char *);
#define KEY_STRING(__strsize, __eltparser) \ #define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \
int __eltparser(char *, size_t, const char *); int __eltparser(char *, size_t, const char *);
#define VALUE_ATOM(__type, __eltparser) \ #define VALUE_ATOM(__type, __eltparser) \
int __eltparser(__type *, const char *); int __eltparser(__type *, const char *);
@ -369,6 +369,55 @@ struct cf_om_node {
int __eltparser(struct config_##__structname *, const struct cf_om_node *); int __eltparser(struct config_##__structname *, const struct cf_om_node *);
#define END_ARRAY(__size) #define END_ARRAY(__size)
#include "config_schema.h" #include "config_schema.h"
#undef __VALIDATOR
#undef STRUCT
#undef NODE
#undef ATOM
#undef STRING
#undef SUB_STRUCT
#undef NODE_STRUCT
#undef END_STRUCT
#undef ARRAY
#undef KEY_ATOM
#undef KEY_STRING
#undef VALUE_ATOM
#undef VALUE_STRING
#undef VALUE_NODE
#undef VALUE_SUB_STRUCT
#undef VALUE_NODE_STRUCT
#undef END_ARRAY
// Generate array key comparison function prototypes.
#define STRUCT(__name, __validator...)
#define NODE(__type, __element, __default, __parser, __flags, __comment)
#define ATOM(__type, __element, __default, __parser, __flags, __comment)
#define STRING(__size, __element, __default, __parser, __flags, __comment)
#define SUB_STRUCT(__name, __element, __flags)
#define NODE_STRUCT(__name, __element, __parser, __flags)
#define END_STRUCT
#define ARRAY(__name, __validator...) \
typedef int __compare_func__config_##__name##__t
#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \
(const __type *, const __type *);
#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \
(const char *, const char *);
#define VALUE_ATOM(__type, __eltparser)
#define VALUE_STRING(__strsize, __eltparser)
#define VALUE_NODE(__type, __eltparser)
#define VALUE_SUB_STRUCT(__structname)
#define VALUE_NODE_STRUCT(__structname, __eltparser)
#define END_ARRAY(__size)
#include "config_schema.h"
#undef ARRAY
#undef KEY_ATOM
#undef KEY_STRING
#define ARRAY(__name, __validator...) \
__compare_func__config_##__name##__t __dummy__compare_func__config_##__name
#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \
,##__cmpfunc;
#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \
,##__cmpfunc;
#include "config_schema.h"
#undef STRUCT #undef STRUCT
#undef NODE #undef NODE
#undef ATOM #undef ATOM

View File

@ -111,8 +111,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* *
* where key-declaration is one of: * where key-declaration is one of:
* *
* KEY_ATOM(type, parsefunc) * KEY_ATOM(type, parsefunc[, comparefunc])
* KEY_STRING(strlen, parsefunc) * KEY_STRING(strlen, parsefunc[, comparefunc])
* *
* and value-declaration is one of: * and value-declaration is one of:
* *
@ -155,6 +155,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* nul-terminated text. The parse functions for NODE, NODE_STRUCT, VALUE_NODE and * nul-terminated text. The parse functions for NODE, NODE_STRUCT, VALUE_NODE and
* VALUE_NODE_STRUCT take a pointer to a COM node (const struct cf_om_node *), and are * VALUE_NODE_STRUCT take a pointer to a COM node (const struct cf_om_node *), and are
* responsible for parsing the node's text and all of its descendents (children). * responsible for parsing the node's text and all of its descendents (children).
* 'comparefunc'
* A function used to sort an array after all elements have been parsed, and before being
* validated (see below).
* 'validatorfunc' * 'validatorfunc'
* A function that is called after the struct/array is fully parsed and populated. This * 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 * function can perform validation checks on the whole struct/array that cannot be performed by
@ -195,7 +198,7 @@ ATOM(uint32_t, tick_ms, 0, opt_uint32_nonzero,, "Tick interval f
END_STRUCT END_STRUCT
ARRAY(mdp_iftypelist) ARRAY(mdp_iftypelist)
KEY_ATOM(short, opt_interface_type) KEY_ATOM(short, opt_interface_type, cmp_short)
VALUE_SUB_STRUCT(mdp_iftype) VALUE_SUB_STRUCT(mdp_iftype)
END_ARRAY(5) END_ARRAY(5)
@ -205,7 +208,7 @@ SUB_STRUCT(mdp_iftypelist, iftype,)
END_STRUCT END_STRUCT
ARRAY(argv, vld_argv) ARRAY(argv, vld_argv)
KEY_ATOM(unsigned short, opt_ushort_nonzero) KEY_ATOM(unsigned short, opt_ushort_nonzero, cmp_ushort)
VALUE_STRING(128, opt_str) VALUE_STRING(128, opt_str)
END_ARRAY(16) END_ARRAY(16)
@ -250,7 +253,7 @@ ATOM(uint16_t, port, PORT_DNA, opt_port,, "Port number")
END_STRUCT END_STRUCT
ARRAY(host_list) ARRAY(host_list)
KEY_ATOM(sid_t, opt_sid) KEY_ATOM(sid_t, opt_sid, cmp_sid)
VALUE_SUB_STRUCT(host) VALUE_SUB_STRUCT(host)
END_ARRAY(32) END_ARRAY(32)

View File

@ -267,6 +267,11 @@ void warn_children(const char *file, unsigned line, const struct cf_om_node *nod
va_end(ap); va_end(ap);
} }
void warn_duplicate_node(const struct cf_om_node *parent, const char *key)
{
warn_node(__FILE__, __LINE__, parent, key, "is duplicate");
}
void warn_missing_node(const struct cf_om_node *parent, const char *key) void warn_missing_node(const struct cf_om_node *parent, const char *key)
{ {
warn_node(__FILE__, __LINE__, parent, key, "is missing"); warn_node(__FILE__, __LINE__, parent, key, "is missing");
@ -632,20 +637,47 @@ int opt_ushort_nonzero(unsigned short *ushortp, const char *text)
return CFOK; return CFOK;
} }
int cmp_argv(const struct config_argv__element *a, const struct config_argv__element *b) int cmp_short(const short *a, const short *b)
{ {
return a->key < b->key ? -1 : a->key > b->key ? 1 : 0; return *a < *b ? -1 : *a > *b ? 1 : 0;
}
int cmp_ushort(const unsigned short *a, const unsigned short *b)
{
return *a < *b ? -1 : *a > *b ? 1 : 0;
}
int cmp_sid(const sid_t *a, const sid_t *b)
{
return memcmp(a->binary, b->binary, sizeof a->binary);
} }
int vld_argv(const struct cf_om_node *parent, struct config_argv *array, int result) int vld_argv(const struct cf_om_node *parent, struct config_argv *array, int result)
{ {
qsort(array->av, array->ac, sizeof array->av[0], (int (*)(const void *, const void *)) cmp_argv);
unsigned short last_key = 0; unsigned short last_key = 0;
int i; int i;
if (array->ac) {
unsigned short last_key = array->av[0].key;
for (i = 1; i < array->ac; ++i) {
unsigned short key = array->av[i].key;
if (last_key > key) {
warn_node(__FILE__, __LINE__, parent, NULL, "array is not sorted");
return CFERROR;
}
last_key = key;
}
}
for (i = 0; i < array->ac; ++i) { for (i = 0; i < array->ac; ++i) {
unsigned short key = array->av[i].key; unsigned short key = array->av[i].key;
assert(key >= 1); assert(key >= 1);
while (last_key != -1 && ++last_key < key && last_key <= sizeof(array->av)) { assert(key >= last_key);
if (last_key == key) {
char labelkey[12];
sprintf(labelkey, "%u", last_key);
warn_duplicate_node(parent, labelkey);
result |= CFINVALID;
}
while (++last_key < key && last_key <= sizeof(array->av)) {
char labelkey[12]; char labelkey[12];
sprintf(labelkey, "%u", last_key); sprintf(labelkey, "%u", last_key);
warn_missing_node(parent, labelkey); warn_missing_node(parent, labelkey);
@ -907,6 +939,48 @@ bye:
return result; return result;
} }
// Generate array element comparison functions.
#define STRUCT(__name, __validator...)
#define NODE(__type, __element, __default, __parser, __flags, __comment)
#define ATOM(__type, __element, __default, __parser, __flags, __comment)
#define STRING(__size, __element, __default, __parser, __flags, __comment)
#define SUB_STRUCT(__name, __element, __flags)
#define NODE_STRUCT(__name, __element, __parser, __flags)
#define END_STRUCT
#define ARRAY(__name, __validator...) \
static int __cmp_config_##__name(const struct config_##__name##__element *a, const struct config_##__name##__element *b) { \
__compare_func__config_##__name##__t *cmp = (NULL
#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \
,##__cmpfunc); \
return cmp ? (*cmp)(&a->key, &b->key) : 0;
#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \
,##__cmpfunc); \
return cmp ? (*cmp)(a->key, b->key) : 0;
#define VALUE_ATOM(__type, __eltparser)
#define VALUE_STRING(__strsize, __eltparser)
#define VALUE_NODE(__type, __eltparser)
#define VALUE_SUB_STRUCT(__structname)
#define VALUE_NODE_STRUCT(__structname, __eltparser)
#define END_ARRAY(__size) \
}
#include "config_schema.h"
#undef STRUCT
#undef NODE
#undef ATOM
#undef STRING
#undef SUB_STRUCT
#undef NODE_STRUCT
#undef END_STRUCT
#undef ARRAY
#undef KEY_ATOM
#undef KEY_STRING
#undef VALUE_ATOM
#undef VALUE_STRING
#undef VALUE_NODE
#undef VALUE_SUB_STRUCT
#undef VALUE_NODE_STRUCT
#undef END_ARRAY
// Schema item flags. // Schema item flags.
#define __MANDATORY (1<<0) #define __MANDATORY (1<<0)
#define __TEXT (1<<1) #define __TEXT (1<<1)
@ -981,6 +1055,8 @@ bye:
#define ARRAY(__name, __validator...) \ #define ARRAY(__name, __validator...) \
int opt_config_##__name(struct config_##__name *array, const struct cf_om_node *node) { \ int opt_config_##__name(struct config_##__name *array, const struct cf_om_node *node) { \
__compare_func__config_##__name##__t *cmp = NULL; \
int (*eltcmp)(const struct config_##__name##__element *, const struct config_##__name##__element *) = __cmp_config_##__name; \
int (*validator)(const struct cf_om_node *, struct config_##__name *, int) = (NULL, ##__validator); \ int (*validator)(const struct cf_om_node *, struct config_##__name *, int) = (NULL, ##__validator); \
int result = CFOK; \ int result = CFOK; \
int i, n; \ int i, n; \
@ -1018,6 +1094,8 @@ bye:
warn_list_overflow(node->nodv[i]); \ warn_list_overflow(node->nodv[i]); \
} \ } \
array->ac = n; \ array->ac = n; \
if (cmp) \
qsort(array->av, array->ac, sizeof array->av[0], (int (*)(const void *, const void *)) eltcmp); \
if (validator) \ if (validator) \
result = (*validator)(node, array, result); \ result = (*validator)(node, array, result); \
if (result & ~CFEMPTY) { \ if (result & ~CFEMPTY) { \
@ -1028,13 +1106,22 @@ bye:
result |= CFEMPTY; \ result |= CFEMPTY; \
return result; \ return result; \
} }
#define KEY_ATOM(__type, __eltparser) __ARRAY_KEY(__eltparser(&array->av[n].key, child->key)) #define KEY_ATOM(__type, __eltparser, __cmpfunc...) \
#define KEY_STRING(__strsize, __eltparser) __ARRAY_KEY(__eltparser(array->av[n].key, sizeof array->av[n].key, child->key)) __ARRAY_KEY(__eltparser(&array->av[n].key, child->key)) \
#define VALUE_ATOM(__type, __eltparser) __ARRAY_VALUE(child->text ? __eltparser(&array->av[n].value, child->text) : CFEMPTY) cmp = (NULL, ##__cmpfunc);
#define VALUE_STRING(__strsize, __eltparser) __ARRAY_VALUE(child->text ? __eltparser(array->av[n].value, sizeof array->av[n].value, child->text) : CFEMPTY) #define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \
#define VALUE_NODE(__type, __eltparser) __ARRAY_VALUE(__eltparser(&array->av[n].value, child)) __ARRAY_KEY(__eltparser(array->av[n].key, sizeof array->av[n].key, child->key)) \
#define VALUE_SUB_STRUCT(__structname) __ARRAY_VALUE(opt_config_##__structname(&array->av[n].value, child)) cmp = (NULL, ##__cmpfunc);
#define VALUE_NODE_STRUCT(__structname, __eltparser) __ARRAY_VALUE(__eltparser(&array->av[n].value, child)) #define VALUE_ATOM(__type, __eltparser) \
__ARRAY_VALUE(child->text ? __eltparser(&array->av[n].value, child->text) : CFEMPTY)
#define VALUE_STRING(__strsize, __eltparser) \
__ARRAY_VALUE(child->text ? __eltparser(array->av[n].value, sizeof array->av[n].value, child->text) : CFEMPTY)
#define VALUE_NODE(__type, __eltparser) \
__ARRAY_VALUE(__eltparser(&array->av[n].value, child))
#define VALUE_SUB_STRUCT(__structname) \
__ARRAY_VALUE(opt_config_##__structname(&array->av[n].value, child))
#define VALUE_NODE_STRUCT(__structname, __eltparser) \
__ARRAY_VALUE(__eltparser(&array->av[n].value, child))
#include "config_schema.h" #include "config_schema.h"