aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lookup.c102
-rw-r--r--tests/Makefile.am1
-rw-r--r--tests/glob02.at2
-rw-r--r--tests/glob03.at53
-rw-r--r--tests/testsuite.at1
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])

Return to:

Send suggestions and report system problems to the System administrator.