diff --git a/commandline.c b/commandline.c index 9b3d260d..33cc4c60 100644 --- a/commandline.c +++ b/commandline.c @@ -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("="); diff --git a/conf.h b/conf.h index d4b3a367..74fcc68d 100644 --- a/conf.h +++ b/conf.h @@ -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; diff --git a/conf_om.c b/conf_om.c index e54b37d6..b635a7ae 100644 --- a/conf_om.c +++ b/conf_om.c @@ -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 + */ +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)