diff options
-rw-r--r-- | src/lookup.c | 102 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rw-r--r-- | tests/glob02.at | 2 | ||||
-rw-r--r-- | tests/glob03.at | 53 | ||||
-rw-r--r-- | tests/testsuite.at | 1 |
5 files changed, 154 insertions, 5 deletions
diff --git a/src/lookup.c b/src/lookup.c index d30d348..a557845 100644 --- a/src/lookup.c +++ b/src/lookup.c @@ -22,6 +22,7 @@ #include <ctype.h> #include "grecs.h" #include "wordsplit.h" +#include <fnmatch.h> static int _grecs_list_eq(struct grecs_value *a, struct grecs_value *b) @@ -79,6 +80,73 @@ grecs_value_eq(struct grecs_value *a, struct grecs_value *b) } return 0; } + +static int +_grecs_list_match(struct grecs_value *pat, struct grecs_value *b, int flags) +{ + struct grecs_list_entry *aent, *bent; + if (grecs_list_size(pat->v.list) != grecs_list_size(b->v.list)) + return 0; + + for (aent = pat->v.list->head, bent = b->v.list->head;; + aent = aent->next, bent = bent->next) { + if (!aent) + return bent == NULL; + if (!bent) + return 0; + if (!grecs_value_match(aent->data, bent->data, flags)) + return 0; + } + /*notreached*/ + return 1; +} + +static int +_grecs_array_match(struct grecs_value *pat, struct grecs_value *b, int flags) +{ + size_t i; + + if (pat->v.arg.c > b->v.arg.c) + return 0; + + for (i = 0; i < pat->v.arg.c; i++) + if (!grecs_value_match(pat->v.arg.v[i], b->v.arg.v[i], flags)) + return 0; + return 1; +} + +int +grecs_value_match(struct grecs_value *pat, struct grecs_value *b, int flags) +{ + if (pat == 0 || b == 0) + return pat == b; + if (pat->type != b->type) { + if (pat->type != GRECS_TYPE_STRING) + return 0; + switch (b->type) { + case GRECS_TYPE_LIST: + b = grecs_list_index(b->v.list, 0); + break; + + case GRECS_TYPE_ARRAY: + b = b->v.arg.v[0]; + } + } + + switch (pat->type) { + case GRECS_TYPE_STRING: + if (pat->v.string == NULL) + return b->v.string == NULL; + return fnmatch(pat->v.string, b->v.string, flags) == 0; + + case GRECS_TYPE_LIST: + return _grecs_list_match(pat, b, flags); + + case GRECS_TYPE_ARRAY: + return _grecs_array_match(pat, b, flags); + } + return 0; +} struct grecs_match_buf { @@ -104,8 +172,10 @@ grecs_match_buf_free_contents(struct grecs_match_buf *buf) void grecs_match_buf_free(struct grecs_match_buf *buf) { - grecs_match_buf_free_contents(buf); - free(buf); + if (buf) { + grecs_match_buf_free_contents(buf); + free(buf); + } } @@ -333,10 +403,12 @@ grecs_match(struct grecs_match_buf *buf) continue; } - if (strcmp(buf->argv[buf->argi], node->ident) == 0 + if ((ISWC(buf->argv[buf->argi], '%') || + strcmp(buf->argv[buf->argi], node->ident) == 0) /* FIXME: */ && (!buf->labelv[buf->argi] || - grecs_value_eq(buf->labelv[buf->argi], node->v.value))) { + grecs_value_match(buf->labelv[buf->argi], + node->v.value, 0))) { wcard = 0; node = node->up; if (buf->argi-- == 0) @@ -365,6 +437,7 @@ struct grecs_node * grecs_match_first(struct grecs_node *tree, const char *pattern, struct grecs_match_buf **pbuf) { + int i; struct grecs_node *node; struct grecs_match_buf *buf; @@ -381,6 +454,27 @@ grecs_match_first(struct grecs_node *tree, const char *pattern, } /* FIXME: Compress argv/argc by replacing contiguous sequences of *'s with a single *. */ + for (i = 0; i < buf->argc; i++) { + if (ISWC(buf->argv[i], '*')) { + int j; + + for (j = i + 1; + j < buf->argc && ISWC(buf->argv[j], '*'); j++) + free(buf->argv[j]); + j -= i; + if (j > 1) { + memmove(&buf->argv[i+1], &buf->argv[i+j], + (buf->argc - (i + j)) * + sizeof(buf->argv[0])); + memmove(&buf->labelv[i+1], &buf->labelv[i+j], + (buf->argc - (i + j)) * + sizeof(buf->labelv[0])); + buf->argc -= j - 1; + } + } + } + + buf->argi = 0; buf->node = grecs_tree_first_node(tree); *pbuf = buf; diff --git a/tests/Makefile.am b/tests/Makefile.am index 448d4e5..73ffeae 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -48,6 +48,7 @@ TESTSUITE_AT = \ glob00.at\ glob01.at\ glob02.at\ + glob03.at\ enum.at\ join.at\ peek00.at\ diff --git a/tests/glob02.at b/tests/glob02.at index 54be577..bc6dfd7 100644 --- a/tests/glob02.at +++ b/tests/glob02.at @@ -15,7 +15,7 @@ # along with Grecs. If not, see <http://www.gnu.org/licenses/>. AT_SETUP(Globbing: intermediate wildcard) -AT_KEYWORDS([peek peek05 glob02]) +AT_KEYWORDS([peek peek05 glob glob02]) AT_CHECK([gcfpeek -match $abs_srcdir/gcf1.conf .program="foo".*.facility], [0], diff --git a/tests/glob03.at b/tests/glob03.at new file mode 100644 index 0000000..1886ff7 --- /dev/null +++ b/tests/glob03.at @@ -0,0 +1,53 @@ +# This file is part of grecs -*- Autotest -*- +# Copyright (C) 2007, 2009-2011 Sergey Poznyakoff +# +# Grecs is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# Grecs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Grecs. If not, see <http://www.gnu.org/licenses/>. + +AT_SETUP(Globbing: multiple wildcards) +AT_KEYWORDS([peek peek06 glob glob03]) + +AT_DATA([test.cf],[ +foo { + bar { + baz { + quz { + quux 10; + } + } + } +} +foo { + bar { + quz { + quux 9; + } + } +} +foo { + bar { + baz { + quz { + mux 8; + } + } + } +} +]) + +AT_CHECK([gcfpeek -match test.cf .*.baz.*.quux], +[0], +[.foo.bar.baz.quz.quux: "10" +]) + +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index 08bc37a..3816c00 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -61,6 +61,7 @@ m4_include([peek03.at]) m4_include([glob00.at]) m4_include([glob01.at]) m4_include([glob02.at]) +m4_include([glob03.at]) m4_include([cfhelp.at]) m4_include([set.at]) |