aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lookup.c102
1 files changed, 98 insertions, 4 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;

Return to:

Send suggestions and report system problems to the System administrator.