2 Unix SMB/CIFS implementation.
4 parse a LDAP-like expression
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 - add RFC2254 binary string handling
26 - possibly add ~=, <= and >= handling
27 - expand the test suite
28 - add better parse error handling
36 a filter is defined by:
37 <filter> ::= '(' <filtercomp> ')'
38 <filtercomp> ::= <and> | <or> | <not> | <simple>
39 <and> ::= '&' <filterlist>
40 <or> ::= '|' <filterlist>
41 <not> ::= '!' <filter>
42 <filterlist> ::= <filter> | <filter> <filterlist>
43 <simple> ::= <attributetype> <filtertype> <attributevalue>
44 <filtertype> ::= '=' | '~=' | '<=' | '>='
48 return next token element. Caller frees
50 static char *ldb_parse_lex(const char **s)
64 if (strchr("()&|=!", *p)) {
73 while (*p && (isalnum(*p) || !strchr("()&|=!", *p))) {
81 ret = strndup(*s, p - *s);
92 find a matching close brace in a string
94 static const char *match_brace(const char *s)
96 unsigned int count = 0;
97 while (*s && (count != 0 || *s != ')')) {
113 static struct ldb_parse_tree *ldb_parse_filter(const char **s);
116 <simple> ::= <attributetype> <filtertype> <attributevalue>
118 static struct ldb_parse_tree *ldb_parse_simple(const char *s)
121 struct ldb_parse_tree *ret;
123 l = ldb_parse_lex(&s);
125 fprintf(stderr, "Unexpected end of expression\n");
129 if (strchr("()&|=", *l)) {
130 fprintf(stderr, "Unexpected token '%s'\n", l);
135 eq = ldb_parse_lex(&s);
136 if (!eq || strcmp(eq, "=") != 0) {
137 fprintf(stderr, "Expected '='\n");
144 val = ldb_parse_lex(&s);
145 if (val && strchr("()&|=", *val)) {
146 fprintf(stderr, "Unexpected token '%s'\n", val);
152 ret = malloc_p(struct ldb_parse_tree);
158 ret->operation = LDB_OP_SIMPLE;
159 ret->u.simple.attr = l;
160 ret->u.simple.value.data = val;
161 ret->u.simple.value.length = val?strlen(val):0;
169 <and> ::= '&' <filterlist>
170 <or> ::= '|' <filterlist>
171 <filterlist> ::= <filter> | <filter> <filterlist>
173 static struct ldb_parse_tree *ldb_parse_filterlist(enum ldb_parse_op op, const char *s)
175 struct ldb_parse_tree *ret, *next;
177 ret = malloc_p(struct ldb_parse_tree);
184 ret->u.list.num_elements = 1;
185 ret->u.list.elements = malloc_p(struct ldb_parse_tree *);
186 if (!ret->u.list.elements) {
192 ret->u.list.elements[0] = ldb_parse_filter(&s);
193 if (!ret->u.list.elements[0]) {
194 free(ret->u.list.elements);
199 while (isspace(*s)) s++;
201 while (*s && (next = ldb_parse_filter(&s))) {
202 struct ldb_parse_tree **e;
203 e = realloc_p(ret->u.list.elements,
204 struct ldb_parse_tree *,
205 ret->u.list.num_elements+1);
208 ldb_parse_tree_free(next);
209 ldb_parse_tree_free(ret);
212 ret->u.list.elements = e;
213 ret->u.list.elements[ret->u.list.num_elements] = next;
214 ret->u.list.num_elements++;
215 while (isspace(*s)) s++;
223 <not> ::= '!' <filter>
225 static struct ldb_parse_tree *ldb_parse_not(const char *s)
227 struct ldb_parse_tree *ret;
229 ret = malloc_p(struct ldb_parse_tree);
235 ret->operation = LDB_OP_NOT;
236 ret->u.not.child = ldb_parse_filter(&s);
237 if (!ret->u.not.child) {
247 <filtercomp> ::= <and> | <or> | <not> | <simple>
249 static struct ldb_parse_tree *ldb_parse_filtercomp(const char *s)
251 while (isspace(*s)) s++;
255 return ldb_parse_filterlist(LDB_OP_AND, s+1);
258 return ldb_parse_filterlist(LDB_OP_OR, s+1);
261 return ldb_parse_not(s+1);
265 fprintf(stderr, "Unexpected token '%c'\n", *s);
269 return ldb_parse_simple(s);
274 <filter> ::= '(' <filtercomp> ')'
276 static struct ldb_parse_tree *ldb_parse_filter(const char **s)
280 struct ldb_parse_tree *ret;
282 l = ldb_parse_lex(s);
284 fprintf(stderr, "Unexpected end of expression\n");
288 if (strcmp(l, "(") != 0) {
290 fprintf(stderr, "Expected '('\n");
297 fprintf(stderr, "Parse error - mismatched braces\n");
302 s2 = strndup(*s, p - *s);
308 ret = ldb_parse_filtercomp(s2);
318 main parser entry point. Takes a search string and returns a parse tree
320 expression ::= <simple> | <filter>
322 struct ldb_parse_tree *ldb_parse_tree(const char *s)
324 while (isspace(*s)) s++;
327 return ldb_parse_filter(&s);
330 return ldb_parse_simple(s);
334 free a parse tree returned from ldb_parse_tree()
336 void ldb_parse_tree_free(struct ldb_parse_tree *tree)
340 switch (tree->operation) {
342 free(tree->u.simple.attr);
343 if (tree->u.simple.value.data) free(tree->u.simple.value.data);
348 for (i=0;i<tree->u.list.num_elements;i++) {
349 ldb_parse_tree_free(tree->u.list.elements[i]);
351 if (tree->u.list.elements) free(tree->u.list.elements);
355 ldb_parse_tree_free(tree->u.not.child);
364 return a string representation of a parse tree
367 static char *tree_string(struct ldb_parse_tree *tree)
373 switch (tree->operation) {
375 asprintf(&s, "( %s = \"%s\" )", tree->u.simple.attr,
376 (char *)tree->u.simple.value.data);
381 asprintf(&s, "( %c", tree->operation==LDB_OP_AND?'&':'|');
384 for (i=0;i<tree->u.list.num_elements;i++) {
385 s1 = tree_string(tree->u.list.elements[i]);
390 asprintf(&s2, "%s %s", s, s1);
398 asprintf(&s2, "%s )", s);
404 s1 = tree_string(tree->u.not.child);
405 asprintf(&s, "( ! %s )", s1);
416 static void print_tree(struct ldb_parse_tree *tree)
418 char *s = tree_string(tree);
429 while (fgets(line, sizeof(line)-1, stdin)) {
430 struct ldb_parse_tree *tree;
432 if (line[strlen(line)-1] == '\n') {
433 line[strlen(line)-1] = 0;
435 tree = ldb_parse_tree(line);
437 fprintf(stderr, "Failed to parse\n");
442 ldb_parse_tree_free(tree);
447 #endif /* TEST_PROGRAM */