diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-05-14 19:00:52 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-05-14 19:33:15 +0300 |
commit | f83e3229ea5c917dfb1bd1a59b1768fdcb882f9a (patch) | |
tree | 1032eebedf5bb28b1b7fdd2e2da5918e0e0225fb /src | |
parent | 3b336240d9ac05bac621568b95086dbff2371acd (diff) | |
download | grecs-f83e3229ea5c917dfb1bd1a59b1768fdcb882f9a.tar.gz grecs-f83e3229ea5c917dfb1bd1a59b1768fdcb882f9a.tar.bz2 |
Wildcard look-ups (initial implementation).
* src/grecs-gram.y (union)<ident>: New field.
(IDENT): Change type to <ident>. All uses changed.
* src/grecs-lex.l (ident): Initialize ident.locus.
* src/grecs.h (GRECS_NODE_FLAG_NODESCEND): New flag.
(grecs_match_buf_t): New data type.
(grecs_match_first,grecs_match_next)
(grecs_match_buf_free): New protos.
(grecs_tree_first_node,grecs_next_node): New protos.
* src/format.c (grecs_format_node): Handle GRECS_NODE_FLAG_NODESCEND flag.
* src/lookup.c (grecs_match_buf): New struct.
(grecs_match_first,grecs_match_next)
(grecs_match_buf_free): New functions.
(split_cfg_path): Fill in array of values, if given.
(parse_tag): Remove. All uses updated.
(node_finder): Use grecs_match_buf.
* src/tree.c (grecs_tree_reduce): Fill config_keywords with 0s.
(grecs_tree_first_node, grecs_next_node): New functions.
* tests/.gitignore: Add gcfenum
* tests/enum.at: New file.
* tests/glob00.at: New file.
* tests/glob01.at: New file.
* tests/glob02.at: New file.
* tests/gcfenum.c: New file.
* tests/Makefile.am: Build gcfenum. Add enum.at test.
* tests/testsuite.at: Include enum.at.
* tests/gcfpeek.c: Implement -match option.
Diffstat (limited to 'src')
-rw-r--r-- | src/format.c | 12 | ||||
-rw-r--r-- | src/grecs-gram.y | 23 | ||||
-rw-r--r-- | src/grecs-lex.l | 3 | ||||
-rw-r--r-- | src/grecs.h | 12 | ||||
-rw-r--r-- | src/lookup.c | 252 | ||||
-rw-r--r-- | src/tree.c | 28 |
6 files changed, 240 insertions, 90 deletions
diff --git a/src/format.c b/src/format.c index b4a4340..1302520 100644 --- a/src/format.c +++ b/src/format.c @@ -273,8 +273,10 @@ grecs_format_node(struct grecs_node *node, int flags, FILE *fp) case grecs_node_block: - for (node = node->down; node; node = node->next) { - grecs_format_node(node, flags, fp); - if (node->next) - fputc('\n', fp); + if (!(flags & GRECS_NODE_FLAG_NODESCEND)) { + for (node = node->down; node; node = node->next) { + grecs_format_node(node, flags, fp); + if (node->next) + fputc('\n', fp); + } + break; } - break; diff --git a/src/grecs-gram.y b/src/grecs-gram.y index 960567e..9f8d000 100644 --- a/src/grecs-gram.y +++ b/src/grecs-gram.y @@ -36,2 +36,6 @@ int grecs_default_port = 0; %union { + struct { + grecs_locus_t locus; + char *string; + } ident; char *string; @@ -40,2 +44,3 @@ int grecs_default_port = 0; struct grecs_node *node; + grecs_locus_t locus; struct { struct grecs_node *head, *tail; } node_list; @@ -43,3 +48,4 @@ int grecs_default_port = 0; -%token <string> IDENT STRING QSTRING MSTRING +%token <ident> IDENT +%token <string> STRING QSTRING MSTRING %type <string> string slist @@ -80,4 +86,4 @@ simple : IDENT vallist ';' $$ = grecs_node_create(grecs_node_stmt, - &grecs_current_locus); - $$->ident = $1; + &$1.locus); + $$->ident = $1.string; $$->v.value = $2; @@ -87,4 +93,4 @@ simple : IDENT vallist ';' $$ = grecs_node_create(grecs_node_stmt, - &grecs_current_locus); - $$->ident = $1; + &$1.locus); + $$->ident = $1.string; $$->v.value = NULL; @@ -96,4 +102,4 @@ block : IDENT tag '{' stmtlist '}' opt_sc $$ = grecs_node_create(grecs_node_block, - &grecs_current_locus); - $$->ident = $1; + &$1.locus); + $$->ident = $1.string; $$->v.value = $2; @@ -163,2 +169,5 @@ string : STRING | IDENT + { + $$ = $1.string; + } | slist diff --git a/src/grecs-lex.l b/src/grecs-lex.l index a3cc7d8..4d491fe 100644 --- a/src/grecs-lex.l +++ b/src/grecs-lex.l @@ -413,3 +413,4 @@ ident() strcpy(str, p); - yylval.string = str; + yylval.ident.locus = grecs_current_locus; + yylval.ident.string = str; return IDENT; diff --git a/src/grecs.h b/src/grecs.h index 05eeff2..61a915b 100644 --- a/src/grecs.h +++ b/src/grecs.h @@ -275,2 +275,3 @@ void grecs_format_value(struct grecs_value *val, int flags, FILE *fp); #define GRECS_NODE_FLAG_QUOTE_HEX 0x2000 +#define GRECS_NODE_FLAG_NODESCEND 0x4000 #define GRECS_NODE_FLAG_DEFAULT \ @@ -356,4 +357,12 @@ int grecs_tree_process(struct grecs_node *node, struct grecs_keyword *kwd); +typedef struct grecs_match_buf *grecs_match_buf_t; +struct grecs_node *grecs_match_first(struct grecs_node *tree, + const char *pattern, + grecs_match_buf_t *buf); +struct grecs_node *grecs_match_next(struct grecs_match_buf *buf); +void grecs_match_buf_free(struct grecs_match_buf *buf); + int grecs_value_eq(struct grecs_value *a, struct grecs_value *b); struct grecs_node *grecs_find_node(struct grecs_node *node, const char *path); + struct grecs_node *grecs_node_from_path(const char *path, const char *value); @@ -365,2 +374,5 @@ void grecs_tree_sort(struct grecs_node *node, struct grecs_node const *)); + +struct grecs_node *grecs_tree_first_node(struct grecs_node *tree); +struct grecs_node *grecs_next_node(struct grecs_node *node); diff --git a/src/lookup.c b/src/lookup.c index 09b7e85..d30d348 100644 --- a/src/lookup.c +++ b/src/lookup.c @@ -83,46 +83,30 @@ grecs_value_eq(struct grecs_value *a, struct grecs_value *b) -static int -split_cfg_path(const char *path, int *pargc, char ***pargv) -{ +struct grecs_match_buf { int argc; char **argv; - char *delim = "."; - char static_delim[2] = { 0, 0 }; - - if (path[0] == '\\') { - argv = calloc(2, sizeof (*argv)); - if (!argv) - return ENOMEM; - argv[0] = strdup(path + 1); - if (!argv[0]) { - free(argv); - return ENOMEM; - } - argv[1] = NULL; - argc = 1; - } else { - struct wordsplit ws; - - if (ispunct(path[0])) { - delim = static_delim; - delim[0] = path[0]; - path++; - } - ws.ws_delim = delim; - - if (wordsplit(path, &ws, WRDSF_DEFFLAGS|WRDSF_DELIM)) - return errno; - argc = ws.ws_wordc; - argv = ws.ws_wordv; - ws.ws_wordc = 0; - ws.ws_wordv = NULL; - wordsplit_free(&ws); + int argi; + struct grecs_value **labelv; + struct grecs_node *node; +}; + +static void +grecs_match_buf_free_contents(struct grecs_match_buf *buf) +{ + size_t i; + for (i = 0; i < buf->argc; i++) { + free(buf->argv[i]); + grecs_value_free(buf->labelv[i]); } - - *pargc = argc; - *pargv = argv; - - return 0; + free(buf->argv); + free(buf->labelv); } +void +grecs_match_buf_free(struct grecs_match_buf *buf) +{ + grecs_match_buf_free_contents(buf); + free(buf); +} + + static struct grecs_value * @@ -180,23 +164,61 @@ parse_label(const char *str) - -struct find_closure { +static int +split_cfg_path(const char *path, int *pargc, char ***pargv, + grecs_value_t ***pvalv) +{ int argc; char **argv; - int tag; - struct grecs_value *label; - struct grecs_node *node; -}; + char *delim = "."; + char static_delim[2] = { 0, 0 }; + + if (path[0] == '\\') { + argv = calloc(2, sizeof (*argv)); + if (!argv) + return ENOMEM; + argv[0] = strdup(path + 1); + if (!argv[0]) { + free(argv); + return ENOMEM; + } + argv[1] = NULL; + argc = 1; + } else { + struct wordsplit ws; + + if (ispunct(path[0])) { + delim = static_delim; + delim[0] = path[0]; + path++; + } + ws.ws_delim = delim; + + if (wordsplit(path, &ws, WRDSF_DEFFLAGS|WRDSF_DELIM)) + return errno; + argc = ws.ws_wordc; + argv = ws.ws_wordv; + ws.ws_wordc = 0; + ws.ws_wordv = NULL; + wordsplit_free(&ws); + } -static void -parse_tag(struct find_closure *fptr) -{ - char *p = strchr(fptr->argv[fptr->tag], '='); - if (p) { - *p++ = 0; - fptr->label = parse_label(p); + *pargv = argv; + *pargc = argc; + if (pvalv) { + int i; + grecs_value_t **valv; + + valv = grecs_calloc(argc, sizeof(valv[0])); + for (i = 0; i < argc; i++) { + char *p = strchr(argv[i], '='); + if (p) { + *p++ = 0; + valv[i] = parse_label(p); + } + } + *pvalv = valv; } - else - fptr->label = NULL; + return 0; } + static enum grecs_tree_recurse_res @@ -204,3 +226,3 @@ node_finder(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) { - struct find_closure *fdptr = data; + struct grecs_match_buf *buf = data; @@ -209,11 +231,10 @@ node_finder(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) - if (strcmp(fdptr->argv[fdptr->tag], node->ident) == 0 - && (!fdptr->label || - grecs_value_eq(fdptr->label, node->v.value))) { - fdptr->tag++; - if (fdptr->tag == fdptr->argc) { - fdptr->node = node; + if (strcmp(buf->argv[buf->argi], node->ident) == 0 + && (!buf->labelv[buf->argi] || + grecs_value_eq(buf->labelv[buf->argi], node->v.value))) { + buf->argi++; + if (buf->argi == buf->argc) { + buf->node = node; return grecs_tree_recurse_stop; } - parse_tag(fdptr); return grecs_tree_recurse_ok; @@ -228,18 +249,13 @@ grecs_find_node(struct grecs_node *node, const char *path) { - int rc, i; - struct find_closure clos; + int rc; + struct grecs_match_buf buf; - rc = split_cfg_path(path, &clos.argc, &clos.argv); - if (rc || !clos.argc) + rc = split_cfg_path(path, &buf.argc, &buf.argv, &buf.labelv); + if (rc || !buf.argc) return NULL; - clos.tag = 0; - clos.label = NULL; - clos.node = NULL; - parse_tag(&clos); - grecs_tree_recurse(node, node_finder, &clos); - for (i = 0; i < clos.argc; i++) - free(clos.argv[i]); - free(clos.argv); - grecs_value_free(clos.label); - return clos.node; + buf.argi = 0; + buf.node = NULL; + grecs_tree_recurse(node, node_finder, &buf); + grecs_match_buf_free_contents(&buf); + return buf.node; } @@ -256,3 +272,3 @@ grecs_node_from_path(const char *path, const char *value) - rc = split_cfg_path(path, &argc, &argv); + rc = split_cfg_path(path, &argc, &argv, NULL); if (rc) @@ -299 +315,83 @@ grecs_node_from_path(const char *path, const char *value) + +#define ISWC(c,w) ((c)[0] == (w) && (c)[1] == 0) + +static int +grecs_match(struct grecs_match_buf *buf) +{ + struct grecs_node *node; + int wcard = 0; + + buf->argi = buf->argc - 1; + node = buf->node; + + while (buf->argi >= 0) { + if (ISWC(buf->argv[buf->argi], '*')) { + wcard = 1; + if (buf->argi-- == 0) + return 1; + continue; + } + + if (strcmp(buf->argv[buf->argi], node->ident) == 0 + /* FIXME: */ + && (!buf->labelv[buf->argi] || + grecs_value_eq(buf->labelv[buf->argi], node->v.value))) { + wcard = 0; + node = node->up; + if (buf->argi-- == 0) + return !node || + node->type == grecs_node_root; + } else if (!wcard) + return 0; + else + node = node->up; + if (!node || node->type == grecs_node_root) + return ISWC(buf->argv[buf->argi], '*'); + } + return 0; +} + +struct grecs_node * +grecs_match_next(struct grecs_match_buf *buf) +{ + while (buf->node = grecs_next_node(buf->node)) + if (grecs_match(buf)) + break; + return buf->node; +} + +struct grecs_node * +grecs_match_first(struct grecs_node *tree, const char *pattern, + struct grecs_match_buf **pbuf) +{ + struct grecs_node *node; + struct grecs_match_buf *buf; + + if (tree->type != grecs_node_root) { + errno = EINVAL; + return NULL; + } + errno = 0; + + buf = grecs_zalloc(sizeof(*buf)); + if (split_cfg_path(pattern, &buf->argc, &buf->argv, &buf->labelv)) { + free(buf); + return NULL; + } + /* FIXME: Compress argv/argc by replacing contiguous sequences of *'s + with a single *. */ + buf->argi = 0; + buf->node = grecs_tree_first_node(tree); + *pbuf = buf; + if (grecs_match(buf)) + node = buf->node; + else + node = grecs_match_next(buf); + if (!node) { + grecs_match_buf_free(buf); + *pbuf = NULL; + } + return node; +} + @@ -1074,2 +1074,3 @@ grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd, + memset(&config_keywords, 0, sizeof(config_keywords)); config_keywords.kwd = kwd; @@ -1087 +1088,28 @@ grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd, } + + +struct grecs_node * +grecs_tree_first_node(struct grecs_node *tree) +{ + if (tree->type != grecs_node_root) { + errno = EINVAL; + return NULL; + } + errno = 0; + return tree->down; +} + +struct grecs_node * +grecs_next_node(struct grecs_node *node) +{ + if (!node) + return NULL; + if (node->down) + return node->down; + while (!node->next) { + node = node->up; + if (!node || node->type == grecs_node_root) + return NULL; + } + return node->next; +} |