Support 'config get' var pattern matching

This commit is contained in:
Andrew Bettison 2012-12-10 15:26:35 +10:30
parent c869e00421
commit 96d524200c
3 changed files with 97 additions and 3 deletions

View File

@ -1001,13 +1001,13 @@ int app_config_get(int argc, const char *const *argv, const struct command_line_
{
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
const char *var;
if (cli_arg(argc, argv, o, "variable", &var, is_configvarname, NULL) == -1)
if (cli_arg(argc, argv, o, "variable", &var, is_configvarpattern, NULL) == -1)
return -1;
if (create_serval_instance_dir() == -1)
return -1;
if (cf_om_reload() == -1)
return -1;
if (var) {
if (var && is_configvarname(var)) {
const char *value = cf_om_get(cf_om_root, var);
if (value) {
cli_puts(var);
@ -1018,6 +1018,8 @@ int app_config_get(int argc, const char *const *argv, const struct command_line_
} else {
struct cf_om_iterator it;
for (cf_om_iter_start(&it, cf_om_root); it.node; cf_om_iter_next(&it)) {
if (var && cf_om_match(var, it.node) <= 0)
continue;
if (it.node->text) {
cli_puts(it.node->fullkey);
cli_delim("=");

2
conf.h
View File

@ -232,6 +232,7 @@ struct cf_om_node {
};
int is_configvarname(const char *);
int is_configvarpattern(const char *);
int cf_om_parse(const char *source, const char *buf, size_t len, struct cf_om_node **rootp);
int cf_om_get_child(const struct cf_om_node *parent, const char *key, const char *keyend);
const char *cf_om_get(const struct cf_om_node *root, const char *fullkey);
@ -239,6 +240,7 @@ int cf_om_set(struct cf_om_node **nodep, const char *fullkey, const char *text);
int cf_om_add_child(struct cf_om_node **const parentp, const char *const key);
void cf_om_free_node(struct cf_om_node **nodep);
void cf_om_dump_node(const struct cf_om_node *node, int indent);
int cf_om_match(const char *pattern, const struct cf_om_node *node);
struct cf_om_iterator {
const struct cf_om_node *node;

View File

@ -44,8 +44,30 @@ static const char *cf_find_keyend(const char *const key, const char *const fullk
return s;
}
static const char *cf_find_keypattern_end(const char *const key, const char *const fullkeyend)
{
const char *s = cf_find_keyend(key, fullkeyend);
if (s == NULL) {
s = key;
if (s < fullkeyend && *s == '*')
++s;
if (s + 1 == fullkeyend && *s == '*')
++s;
if (s == key || (s < fullkeyend && *s != '.'))
return NULL;
}
return s;
}
/* This predicate function defines the constraints on configuration option names.
* Valid:
*
* OPTION_NAME ::= ( KEY "." )* LASTKEY
* KEY ::= ( ALPHA | "_") ( ALPHANUM | "_" )*
* LASTKEY ::= KEY
* ALPHA ::= "A" .. "Z" | "a" .. "z"
* ALPHANUM ::= ALPHA | "0" .. "9"
*
* Valid examples:
* foo
* foo.bar
* foo.bar.chow
@ -72,6 +94,25 @@ int is_configvarname(const char *text)
return keyend != NULL;
}
/* This predicate function defines the constraints on configuration option patterns.
* Similar to is_configvarname().
*
* OPTION_PATTERN ::= ( KEY_PATTERN "." )* LASTKEY_PATTERN
* KEY_PATTERN ::= "*" | KEY
* LASTKEY_PATTERN ::= "**" | KEY_PATTERN
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int is_configvarpattern(const char *text)
{
const char *const textend = text + strlen(text);
const char *key = text;
const char *keyend = NULL;
while (key <= textend && (keyend = cf_find_keypattern_end(key, textend)) != NULL)
key = keyend + 1;
return keyend != NULL;
}
static int cf_om_make_child(struct cf_om_node **const parentp, const char *const fullkey, const char *const key, const char *const keyend)
{
// Allocate parent node if it is not present.
@ -253,6 +294,55 @@ void cf_om_dump_node(const struct cf_om_node *node, int indent)
}
}
int cf_om_match(const char *pattern, const struct cf_om_node *node)
{
if (node == NULL) {
//DEBUGF("pattern='%s' node=NULL", pattern);
return 0;
}
if (node->fullkey == NULL) {
//DEBUGF("pattern='%s' node->fullkey=NULL", pattern);
return 0;
}
/*
DEBUGF("pattern='%s' node->fullkey=%s node->nodc=%d node->text=%s",
pattern,
alloca_str_toprint(node->fullkey),
node->nodc,
alloca_str_toprint(node->text)
);
*/
if (!pattern[0])
return -1;
const char *const pattern_end = pattern + strlen(pattern);
const char *pat = pattern;
const char *key = node->fullkey;
const char *const fullkeyend = node->fullkey + strlen(node->fullkey);
const char *keyend = NULL;
const char *patend = pat;
//DEBUGF(" pat=%s key=%s", alloca_str_toprint(pat), alloca_str_toprint(key));
while (pat < pattern_end && key <= fullkeyend && (keyend = cf_find_keyend(key, fullkeyend)) && (patend = cf_find_keypattern_end(pat, pattern_end))) {
if (pat[0] == '*') {
if (pat[1] == '*')
return 1;
pat = patend;
key = keyend;
} else {
while (pat < patend && key < fullkeyend && *pat == *key)
++pat, ++key;
if (pat != patend || key != keyend)
return 0;
}
if (*pat)
++pat;
if (*key)
++key;
//DEBUGF(" pat=%s key=%s", alloca_str_toprint(pat), alloca_str_toprint(key));
}
//DEBUGF(" patend=%s keyend=%s", alloca_str_toprint(patend), alloca_str_toprint(keyend));
return patend == NULL ? -1 : keyend && keyend == fullkeyend && pat == pattern_end;
}
const char *cf_om_get(const struct cf_om_node *node, const char *fullkey)
{
if (node == NULL)