diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-05-15 00:03:43 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-05-15 14:00:57 +0300 |
commit | fd64fa62bc68d8c2e0d693033e874fcc1f023544 (patch) | |
tree | 4e9f680539dc9ceb32ea6797c3f917586b2f757f /src | |
parent | f83e3229ea5c917dfb1bd1a59b1768fdcb882f9a (diff) | |
download | grecs-fd64fa62bc68d8c2e0d693033e874fcc1f023544.tar.gz grecs-fd64fa62bc68d8c2e0d693033e874fcc1f023544.tar.bz2 |
Improve wildcard matching.
* src/lookup.c (grecs_value_match): New function.
(grecs_match_buf_free): Ignore NULL argument.
(grecs_match): Implement single-occurrence wildcard (%). Match
values using fnmatch globbing patterns.
(grecs_match_first): Compress multiple contiguous *
Diffstat (limited to 'src')
-rw-r--r-- | src/lookup.c | 102 |
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 @@ | |||
22 | #include <ctype.h> | 22 | #include <ctype.h> |
23 | #include "grecs.h" | 23 | #include "grecs.h" |
24 | #include "wordsplit.h" | 24 | #include "wordsplit.h" |
25 | #include <fnmatch.h> | ||
25 | 26 | ||
26 | static int | 27 | static int |
27 | _grecs_list_eq(struct grecs_value *a, struct grecs_value *b) | 28 | _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) | |||
79 | } | 80 | } |
80 | return 0; | 81 | return 0; |
81 | } | 82 | } |
83 | |||
84 | static int | ||
85 | _grecs_list_match(struct grecs_value *pat, struct grecs_value *b, int flags) | ||
86 | { | ||
87 | struct grecs_list_entry *aent, *bent; | ||
88 | if (grecs_list_size(pat->v.list) != grecs_list_size(b->v.list)) | ||
89 | return 0; | ||
90 | |||
91 | for (aent = pat->v.list->head, bent = b->v.list->head;; | ||
92 | aent = aent->next, bent = bent->next) { | ||
93 | if (!aent) | ||
94 | return bent == NULL; | ||
95 | if (!bent) | ||
96 | return 0; | ||
97 | if (!grecs_value_match(aent->data, bent->data, flags)) | ||
98 | return 0; | ||
99 | } | ||
100 | /*notreached*/ | ||
101 | return 1; | ||
102 | } | ||
103 | |||
104 | static int | ||
105 | _grecs_array_match(struct grecs_value *pat, struct grecs_value *b, int flags) | ||
106 | { | ||
107 | size_t i; | ||
108 | |||
109 | if (pat->v.arg.c > b->v.arg.c) | ||
110 | return 0; | ||
111 | |||
112 | for (i = 0; i < pat->v.arg.c; i++) | ||
113 | if (!grecs_value_match(pat->v.arg.v[i], b->v.arg.v[i], flags)) | ||
114 | return 0; | ||
115 | return 1; | ||
116 | } | ||
117 | |||
118 | int | ||
119 | grecs_value_match(struct grecs_value *pat, struct grecs_value *b, int flags) | ||
120 | { | ||
121 | if (pat == 0 || b == 0) | ||
122 | return pat == b; | ||
123 | if (pat->type != b->type) { | ||
124 | if (pat->type != GRECS_TYPE_STRING) | ||
125 | return 0; | ||
126 | switch (b->type) { | ||
127 | case GRECS_TYPE_LIST: | ||
128 | b = grecs_list_index(b->v.list, 0); | ||
129 | break; | ||
130 | |||
131 | case GRECS_TYPE_ARRAY: | ||
132 | b = b->v.arg.v[0]; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | switch (pat->type) { | ||
137 | case GRECS_TYPE_STRING: | ||
138 | if (pat->v.string == NULL) | ||
139 | return b->v.string == NULL; | ||
140 | return fnmatch(pat->v.string, b->v.string, flags) == 0; | ||
141 | |||
142 | case GRECS_TYPE_LIST: | ||
143 | return _grecs_list_match(pat, b, flags); | ||
144 | |||
145 | case GRECS_TYPE_ARRAY: | ||
146 | return _grecs_array_match(pat, b, flags); | ||
147 | } | ||
148 | return 0; | ||
149 | } | ||
82 | 150 | ||
83 | 151 | ||
84 | struct grecs_match_buf { | 152 | struct grecs_match_buf { |
@@ -104,8 +172,10 @@ grecs_match_buf_free_contents(struct grecs_match_buf *buf) | |||
104 | void | 172 | void |
105 | grecs_match_buf_free(struct grecs_match_buf *buf) | 173 | grecs_match_buf_free(struct grecs_match_buf *buf) |
106 | { | 174 | { |
107 | grecs_match_buf_free_contents(buf); | 175 | if (buf) { |
108 | free(buf); | 176 | grecs_match_buf_free_contents(buf); |
177 | free(buf); | ||
178 | } | ||
109 | } | 179 | } |
110 | 180 | ||
111 | 181 | ||
@@ -333,10 +403,12 @@ grecs_match(struct grecs_match_buf *buf) | |||
333 | continue; | 403 | continue; |
334 | } | 404 | } |
335 | 405 | ||
336 | if (strcmp(buf->argv[buf->argi], node->ident) == 0 | 406 | if ((ISWC(buf->argv[buf->argi], '%') || |
407 | strcmp(buf->argv[buf->argi], node->ident) == 0) | ||
337 | /* FIXME: */ | 408 | /* FIXME: */ |
338 | && (!buf->labelv[buf->argi] || | 409 | && (!buf->labelv[buf->argi] || |
339 | grecs_value_eq(buf->labelv[buf->argi], node->v.value))) { | 410 | grecs_value_match(buf->labelv[buf->argi], |
411 | node->v.value, 0))) { | ||
340 | wcard = 0; | 412 | wcard = 0; |
341 | node = node->up; | 413 | node = node->up; |
342 | if (buf->argi-- == 0) | 414 | if (buf->argi-- == 0) |
@@ -365,6 +437,7 @@ struct grecs_node * | |||
365 | grecs_match_first(struct grecs_node *tree, const char *pattern, | 437 | grecs_match_first(struct grecs_node *tree, const char *pattern, |
366 | struct grecs_match_buf **pbuf) | 438 | struct grecs_match_buf **pbuf) |
367 | { | 439 | { |
440 | int i; | ||
368 | struct grecs_node *node; | 441 | struct grecs_node *node; |
369 | struct grecs_match_buf *buf; | 442 | struct grecs_match_buf *buf; |
370 | 443 | ||
@@ -381,6 +454,27 @@ grecs_match_first(struct grecs_node *tree, const char *pattern, | |||
381 | } | 454 | } |
382 | /* FIXME: Compress argv/argc by replacing contiguous sequences of *'s | 455 | /* FIXME: Compress argv/argc by replacing contiguous sequences of *'s |
383 | with a single *. */ | 456 | with a single *. */ |
457 | for (i = 0; i < buf->argc; i++) { | ||
458 | if (ISWC(buf->argv[i], '*')) { | ||
459 | int j; | ||
460 | |||
461 | for (j = i + 1; | ||
462 | j < buf->argc && ISWC(buf->argv[j], '*'); j++) | ||
463 | free(buf->argv[j]); | ||
464 | j -= i; | ||
465 | if (j > 1) { | ||
466 | memmove(&buf->argv[i+1], &buf->argv[i+j], | ||
467 | (buf->argc - (i + j)) * | ||
468 | sizeof(buf->argv[0])); | ||
469 | memmove(&buf->labelv[i+1], &buf->labelv[i+j], | ||
470 | (buf->argc - (i + j)) * | ||
471 | sizeof(buf->labelv[0])); | ||
472 | buf->argc -= j - 1; | ||
473 | } | ||
474 | } | ||
475 | } | ||
476 | |||
477 | |||
384 | buf->argi = 0; | 478 | buf->argi = 0; |
385 | buf->node = grecs_tree_first_node(tree); | 479 | buf->node = grecs_tree_first_node(tree); |
386 | *pbuf = buf; | 480 | *pbuf = buf; |