Improve config schema declaration

Remove array key SORTED flag; all arrays are now sorted by key

Use representation's comparison function for sorting arrays, not
a schema-supplied comparison function.
This commit is contained in:
Andrew Bettison 2013-03-01 15:27:28 +10:30
parent 2ac35bfdf7
commit 54ce857cff
3 changed files with 39 additions and 136 deletions

68
conf.h
View File

@ -322,10 +322,10 @@ struct pattern_list {
struct config_##__name { \
unsigned ac; \
struct config_##__name##__element {
#define KEY_ATOM(__type, __keyrepr, __cmpfunc...) \
__type key;
#define KEY_STRING(__strsize, __keyrepr, __cmpfunc...) \
char key[(__strsize) + 1];
#define KEY_ATOM(__type, __keyrepr) \
__type key; // key must be first element in struct
#define KEY_STRING(__strsize, __keyrepr) \
char key[(__strsize) + 1]; // key must be first element in struct
#define VALUE_ATOM(__type, __eltrepr) \
__type value;
#define VALUE_STRING(__strsize, __eltrepr) \
@ -370,8 +370,8 @@ struct pattern_list {
#define ARRAY(__name, __flags, __validator...) \
int cf_dfl_config_##__name(struct config_##__name *a); \
int cf_sch_config_##__name(struct cf_om_node **parentp);
#define KEY_ATOM(__type, __keyrepr, __cmpfunc...)
#define KEY_STRING(__strsize, __keyrepr, __cmpfunc...)
#define KEY_ATOM(__type, __keyrepr)
#define KEY_STRING(__strsize, __keyrepr)
#define VALUE_ATOM(__type, __eltrepr)
#define VALUE_STRING(__strsize, __eltrepr)
#define VALUE_NODE(__type, __eltrepr)
@ -432,11 +432,11 @@ struct pattern_list {
int cf_fmt_config_##__name(struct cf_om_node **, const struct config_##__name *); \
int cf_cmp_config_##__name(const struct config_##__name *, const struct config_##__name *); \
__VALIDATOR(__name, ##__validator)
#define KEY_ATOM(__type, __keyrepr, __cmpfunc...) \
#define KEY_ATOM(__type, __keyrepr) \
int cf_opt_##__keyrepr(__type *, const char *); \
int cf_fmt_##__keyrepr(const char **, const __type *); \
int cf_cmp_##__keyrepr(const __type *, const __type *);
#define KEY_STRING(__strsize, __keyrepr, __cmpfunc...) \
#define KEY_STRING(__strsize, __keyrepr) \
int cf_opt_##__keyrepr(char *, size_t, const char *); \
int cf_fmt_##__keyrepr(const char **, const char *); \
int cf_cmp_##__keyrepr(const char *, const char *);
@ -481,54 +481,6 @@ struct pattern_list {
#undef VALUE_NODE_STRUCT
#undef END_ARRAY
// Generate config array key comparison function prototypes.
#define STRUCT(__name, __validator...)
#define NODE(__type, __element, __default, __repr, __flags, __comment)
#define ATOM(__type, __element, __default, __repr, __flags, __comment)
#define STRING(__size, __element, __default, __repr, __flags, __comment)
#define SUB_STRUCT(__name, __element, __flags)
#define NODE_STRUCT(__name, __element, __repr, __flags)
#define END_STRUCT
#define ARRAY(__name, __flags, __validator...) \
typedef int __compare_func__config_##__name##__t
#define KEY_ATOM(__type, __keyrepr, __cmpfunc...) \
(const __type *, const __type *);
#define KEY_STRING(__strsize, __keyrepr, __cmpfunc...) \
(const char *, const char *);
#define VALUE_ATOM(__type, __eltrepr)
#define VALUE_STRING(__strsize, __eltrepr)
#define VALUE_NODE(__type, __eltrepr)
#define VALUE_SUB_STRUCT(__structname)
#define VALUE_NODE_STRUCT(__structname, __eltrepr)
#define END_ARRAY(__size)
#include "conf_schema.h"
#undef ARRAY
#undef KEY_ATOM
#undef KEY_STRING
#define ARRAY(__name, __flags, __validator...) \
__compare_func__config_##__name##__t __dummy__compare_func__config_##__name
#define KEY_ATOM(__type, __keyrepr, __cmpfunc...) \
,##__cmpfunc;
#define KEY_STRING(__strsize, __keyrepr, __cmpfunc...) \
,##__cmpfunc;
#include "conf_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
// Generate config array search-by-key function prototypes.
#define STRUCT(__name, __validator...)
#define NODE(__type, __element, __default, __repr, __flags, __comment)
@ -539,9 +491,9 @@ struct pattern_list {
#define END_STRUCT
#define ARRAY(__name, __flags, __validator...) \
int config_##__name##__get(const struct config_##__name *,
#define KEY_ATOM(__type, __keyrepr, __cmpfunc...) \
#define KEY_ATOM(__type, __keyrepr) \
const __type *);
#define KEY_STRING(__strsize, __keyrepr, __cmpfunc...) \
#define KEY_STRING(__strsize, __keyrepr) \
const char *);
#define VALUE_ATOM(__type, __eltrepr)
#define VALUE_STRING(__strsize, __eltrepr)

View File

@ -42,8 +42,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
a->ac = 0; \
return CFOK; \
}
#define KEY_ATOM(__type, __keyrepr, __cmpfunc...)
#define KEY_STRING(__strsize, __keyrepr, __cmpfunc...)
#define KEY_ATOM(__type, __keyrepr)
#define KEY_STRING(__strsize, __keyrepr)
#define VALUE_ATOM(__type, __eltrepr)
#define VALUE_STRING(__strsize, __eltrepr)
#define VALUE_NODE(__type, __eltrepr)
@ -68,60 +68,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#undef VALUE_NODE_STRUCT
#undef END_ARRAY
// Generate array element comparison functions.
#define STRUCT(__name, __validator...)
#define NODE(__type, __element, __default, __repr, __flags, __comment)
#define ATOM(__type, __element, __default, __repr, __flags, __comment)
#define STRING(__size, __element, __default, __repr, __flags, __comment)
#define SUB_STRUCT(__name, __element, __flags)
#define NODE_STRUCT(__name, __element, __repr, __flags)
#define END_STRUCT
#define ARRAY(__name, __flags, __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, __keyrepr, __cmpfunc...) \
,##__cmpfunc); \
return cmp ? (*cmp)(&a->key, &b->key) : memcmp(&a->key, &b->key, sizeof a->key);
#define KEY_STRING(__strsize, __keyrepr, __cmpfunc...) \
,##__cmpfunc); \
return cmp ? (*cmp)(a->key, b->key) : strcmp(a->key, b->key);
#define VALUE_ATOM(__type, __eltrepr)
#define VALUE_STRING(__strsize, __eltrepr)
#define VALUE_NODE(__type, __eltrepr)
#define VALUE_SUB_STRUCT(__structname)
#define VALUE_NODE_STRUCT(__structname, __eltrepr)
#define END_ARRAY(__size) \
}
#include "conf_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.
#define __MANDATORY (1<<0)
#define __TEXT (1<<1)
#define __CHILDREN (1<<2)
#define __SORTED (1<<3)
#define __NO_DUPLICATES (1<<4)
#define __NO_DUPLICATES (1<<3)
// Schema flag symbols, to be used in the '__flags' macro arguments.
#define MANDATORY |__MANDATORY
#define USES_TEXT |__TEXT
#define USES_CHILDREN |__CHILDREN
#define SORTED |__SORTED
#define NO_DUPLICATES |__NO_DUPLICATES
// Generate parsing functions, cf_opt_config_SECTION()
@ -188,14 +144,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define ARRAY(__name, __flags, __validator...) \
int cf_opt_config_##__name(struct config_##__name *array, const struct cf_om_node *node) { \
int flags = (0 __flags); \
int (*eltcmp)(const struct config_##__name##__element *, const struct config_##__name##__element *) = __cmp_config_##__name; \
int (*keycmp)(const void *, const void *) = NULL; \
int (*validator)(const struct cf_om_node *, 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 = CFEMPTY;
#define __ARRAY_KEY(__parseexpr, __cmpfunc...) \
#define __ARRAY_KEY(__parseexpr, __cmpfunc, __cmpfuncargs) \
keycmp = (int (*)(const void *, const void *)) __cmpfunc; \
ret = (__parseexpr); \
if (ret == CFERROR) \
return CFERROR; \
@ -205,7 +162,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
if (ret == CFOK && (flags & __NO_DUPLICATES)) { \
int j; \
for (j = 0; j < n; ++j) { \
if ((*eltcmp)(&array->av[j], &array->av[n]) == 0) { \
if (__cmpfunc __cmpfuncargs == 0) { \
cf_warn_duplicate_node(child, NULL); \
ret |= CFDUPLICATE; \
} \
@ -237,8 +194,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
cf_warn_list_overflow(node->nodv[i]); \
} \
array->ac = n; \
if (flags & __SORTED) \
qsort(array->av, array->ac, sizeof array->av[0], (int (*)(const void *, const void *)) eltcmp); \
qsort(array->av, array->ac, sizeof array->av[0], (int (*)(const void *, const void *)) keycmp); \
if (validator) \
result = (*validator)(node, array, result); \
if (result & ~CFEMPTY) { \
@ -249,10 +205,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
result |= CFEMPTY; \
return result; \
}
#define KEY_ATOM(__type, __keyrepr, __cmpfunc...) \
__ARRAY_KEY(cf_opt_##__keyrepr(&array->av[n].key, child->key), ##__cmpfunc)
#define KEY_STRING(__strsize, __keyrepr, __cmpfunc...) \
__ARRAY_KEY(cf_opt_##__keyrepr(array->av[n].key, sizeof array->av[n].key, child->key), ##__cmpfunc)
#define KEY_ATOM(__type, __keyrepr) \
__ARRAY_KEY(cf_opt_##__keyrepr(&array->av[n].key, child->key), cf_cmp_##__keyrepr, (&array->av[j].key, &array->av[n].key))
#define KEY_STRING(__strsize, __keyrepr) \
__ARRAY_KEY(cf_opt_##__keyrepr(array->av[n].key, sizeof array->av[n].key, child->key), cf_cmp_##__keyrepr, (&array->av[j].key[0], &array->av[n].key[0]))
#define VALUE_ATOM(__type, __eltrepr) \
__ARRAY_VALUE(CFOK, child->text ? cf_opt_##__eltrepr(&array->av[n].value, child->text) : CFEMPTY)
#define VALUE_STRING(__strsize, __eltrepr) \
@ -293,21 +249,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define END_STRUCT
#define ARRAY(__name, __flags, __validator...) \
int config_##__name##__get(const struct config_##__name *array,
#define KEY_ATOM(__type, __keyrepr, __cmpfunc...) \
#define KEY_ATOM(__type, __keyrepr) \
const __type *key) { \
int (*cmp)(const __type *, const __type *) = (NULL, ##__cmpfunc); \
int i; \
for (i = 0; i < array->ac; ++i) \
if ((cmp ? (*cmp)(key, &array->av[i].key) : memcmp(key, &array->av[i].key, sizeof *key)) == 0) \
if ((cf_cmp_##__keyrepr(key, &array->av[i].key)) == 0) \
return i; \
return -1; \
}
#define KEY_STRING(__strsize, __keyrepr, __cmpfunc...) \
#define KEY_STRING(__strsize, __keyrepr) \
const char *key) { \
int (*cmp)(const char *, const char *) = (NULL, ##__cmpfunc); \
int i; \
for (i = 0; i < array->ac; ++i) \
if ((cmp ? (*cmp)(key, array->av[i].key) : strcmp(key, array->av[i].key)) == 0) \
if ((cf_cmp_##__keyrepr(&key[0], &array->av[i].key[0])) == 0) \
return i; \
return -1; \
}
@ -375,9 +329,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
int cf_sch_config_##__name(struct cf_om_node **rootp) { \
int i; \
struct cf_om_node **childp;
#define KEY_ATOM(__type, __keyrepr, __cmpfunc...) \
#define KEY_ATOM(__type, __keyrepr) \
__ADD_CHILD(rootp, "[" #__keyrepr "]")
#define KEY_STRING(__strsize, __keyrepr, __cmpfunc...) \
#define KEY_STRING(__strsize, __keyrepr) \
__ADD_CHILD(rootp, "[" #__keyrepr "]")
#define VALUE_ATOM(__type, __eltrepr) \
__ATOM(childp, "(" #__eltrepr ")")
@ -538,9 +492,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
cf_om_free_node(parentp); \
return result; \
}
#define KEY_ATOM(__type, __keyrepr, __cmpfunc...) \
#define KEY_ATOM(__type, __keyrepr) \
__ARRAY_KEY(cf_fmt_##__keyrepr, &array->av[i].key);
#define KEY_STRING(__strsize, __keyrepr, __cmpfunc...) \
#define KEY_STRING(__strsize, __keyrepr) \
__ARRAY_KEY(cf_fmt_##__keyrepr, &array->av[i].key[0]);
#define VALUE_ATOM(__type, __eltrepr) \
__ARRAY_TEXT(cf_fmt_##__eltrepr, &array->av[i].value)
@ -603,10 +557,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
int c; \
int i; \
for (i = 0; i < a->ac && i < b->ac; ++i) {
#define KEY_ATOM(__type, __keyrepr, __cmpfunc...) \
#define KEY_ATOM(__type, __keyrepr) \
if ((c = cf_cmp_##__keyrepr(&a->av[i].key, &b->av[i].key))) \
return c;
#define KEY_STRING(__strsize, __keyrepr, __cmpfunc...) \
#define KEY_STRING(__strsize, __keyrepr) \
if ((c = cf_cmp_##__keyrepr(&a->av[i].key[0], &b->av[i].key[0]))) \
return c;
#define VALUE_ATOM(__type, __eltrepr) \

View File

@ -111,8 +111,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* where key-declaration is one of:
*
* KEY_ATOM(type, repr[, comparefunc])
* KEY_STRING(strlen, repr[, comparefunc])
* KEY_ATOM(type, repr)
* KEY_STRING(strlen, repr)
*
* and value-declaration is one of:
*
@ -168,9 +168,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* or 1 to indicate the natural ordering of the values. These functions are used to detect
* when config elements have their default values, to avoid calling cf_fmt_<repr>(). They
* are also used to sort array keys.
* 'comparefunc'
* A function used to sort an array after all elements have been parsed, and before being
* validated (see below).
* '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
@ -252,7 +249,7 @@ ATOM(int32_t, packet_interval, -1, int32_nonneg,, "Minimum interva
END_STRUCT
ARRAY(mdp_iftypelist, NO_DUPLICATES)
KEY_ATOM(short, interface_type, cf_cmp_short)
KEY_ATOM(short, interface_type)
VALUE_SUB_STRUCT(mdp_iftype)
END_ARRAY(5)
@ -267,8 +264,8 @@ ATOM(uint16_t, remote_port,4130, uint16_nonzero,, "Remote port numb
ATOM(uint16_t, local_port, 4131, uint16_nonzero,, "Local port number")
END_STRUCT
ARRAY(argv, SORTED NO_DUPLICATES, vld_argv)
KEY_ATOM(unsigned short, ushort_nonzero, cf_cmp_ushort)
ARRAY(argv, NO_DUPLICATES, vld_argv)
KEY_ATOM(unsigned short, ushort_nonzero)
VALUE_STRING(128, str)
END_ARRAY(16)
@ -350,7 +347,7 @@ ATOM(uint16_t, port, PORT_DNA, uint16_nonzero,, "Port number"
END_STRUCT
ARRAY(host_list, NO_DUPLICATES)
KEY_ATOM(sid_t, sid, cf_cmp_sid)
KEY_ATOM(sid_t, sid)
VALUE_SUB_STRUCT(host)
END_ARRAY(32)
@ -373,7 +370,7 @@ ATOM(char, default_route, 0, char_boolean,, "If true, use this
ATOM(char, prefer_unicast, 0, char_boolean,, "If true, send unicast data as unicast IP packets if available")
END_STRUCT
ARRAY(interface_list, SORTED NO_DUPLICATES)
ARRAY(interface_list, NO_DUPLICATES)
KEY_ATOM(unsigned, uint)
VALUE_NODE_STRUCT(network_interface, network_interface)
END_ARRAY(10)