66f3f22dcfb9b5ec7a9fd447135ab493c7360f92
1 /*
2 * SysDB - src/core/store_lookup.c
3 * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 /*
29 * This module implements operators which may be used to select contents of
30 * the store by matching various attributes of the stored objects. For now, a
31 * simple full table scan is supported only.
32 */
34 #if HAVE_CONFIG_H
35 # include "config.h"
36 #endif /* HAVE_CONFIG_H */
38 #include "sysdb.h"
39 #include "core/store-private.h"
40 #include "core/object.h"
42 #include <assert.h>
44 #include <sys/types.h>
45 #include <regex.h>
47 #include <stdlib.h>
48 #include <string.h>
50 #include <limits.h>
52 /*
53 * private data types
54 */
56 typedef struct {
57 sdb_store_matcher_t *m;
58 sdb_store_lookup_cb cb;
59 void *user_data;
60 } lookup_iter_data_t;
62 /*
63 * private helper functions
64 */
66 static int
67 lookup_iter(sdb_store_base_t *obj, void *user_data)
68 {
69 lookup_iter_data_t *d = user_data;
71 if (sdb_store_matcher_matches(d->m, obj))
72 return d->cb(obj, d->user_data);
73 return 0;
74 } /* lookup_iter */
76 static sdb_store_base_t *
77 attr_get(sdb_host_t *host, const char *name)
78 {
79 sdb_llist_iter_t *iter = NULL;
80 sdb_store_base_t *attr = NULL;
82 iter = sdb_llist_get_iter(host->attributes);
83 while (sdb_llist_iter_has_next(iter)) {
84 sdb_attribute_t *a = ATTR(sdb_llist_iter_get_next(iter));
86 if (strcasecmp(name, SDB_OBJ(a)->name))
87 continue;
88 attr = STORE_BASE(a);
89 break;
90 }
91 sdb_llist_iter_destroy(iter);
92 return attr;
93 } /* attr_get */
95 /*
96 * conditional implementations
97 */
99 static int
100 attr_cmp(sdb_store_base_t *obj, sdb_store_cond_t *cond)
101 {
102 sdb_attribute_t *attr;
104 attr = ATTR(attr_get(HOST(obj), ATTR_C(cond)->name));
105 if (! attr)
106 return INT_MAX;
107 if (attr->value.type != ATTR_C(cond)->value.type)
108 return INT_MAX;
109 return sdb_data_cmp(&attr->value, &ATTR_C(cond)->value);
110 } /* attr_cmp */
112 /*
113 * matcher implementations
114 */
116 static int
117 match_string(string_matcher_t *m, const char *name)
118 {
119 if ((! m->name) && (! m->name_re))
120 return 1;
122 if (! name)
123 name = "";
125 if (m->name && strcasecmp(m->name, name))
126 return 0;
127 if (m->name_re && regexec(m->name_re, name,
128 /* matches */ 0, NULL, /* flags = */ 0))
129 return 0;
130 return 1;
131 } /* match_string */
133 static int
134 match_logical(sdb_store_matcher_t *m, sdb_store_base_t *obj)
135 {
136 int status;
138 assert((m->type == MATCHER_AND) || (m->type == MATCHER_OR));
139 assert(OP_M(m)->left && OP_M(m)->right);
141 status = sdb_store_matcher_matches(OP_M(m)->left, obj);
142 /* lazy evaluation */
143 if ((! status) && (m->type == MATCHER_AND))
144 return status;
145 else if (status && (m->type == MATCHER_OR))
146 return status;
148 return sdb_store_matcher_matches(OP_M(m)->right, obj);
149 } /* match_logical */
151 static int
152 match_unary(sdb_store_matcher_t *m, sdb_store_base_t *obj)
153 {
154 assert(m->type == MATCHER_NOT);
155 assert(UOP_M(m)->op);
157 return !sdb_store_matcher_matches(UOP_M(m)->op, obj);
158 } /* match_unary */
160 static int
161 match_name(sdb_store_matcher_t *m, sdb_store_base_t *obj)
162 {
163 sdb_llist_iter_t *iter = NULL;
164 int status = 0;
166 assert(m->type == MATCHER_NAME);
168 switch (NAME_M(m)->obj_type) {
169 case SDB_HOST:
170 return match_string(&NAME_M(m)->name, obj->super.name);
171 break;
172 case SDB_SERVICE:
173 iter = sdb_llist_get_iter(HOST(obj)->services);
174 break;
175 case SDB_ATTRIBUTE:
176 iter = sdb_llist_get_iter(HOST(obj)->attributes);
177 break;
178 }
180 while (sdb_llist_iter_has_next(iter)) {
181 sdb_store_base_t *child = STORE_BASE(sdb_llist_iter_get_next(iter));
182 if (match_string(&NAME_M(m)->name, child->super.name)) {
183 status = 1;
184 break;
185 }
186 }
187 sdb_llist_iter_destroy(iter);
188 return status;
189 } /* match_name */
191 static int
192 match_attr(sdb_store_matcher_t *m, sdb_store_base_t *obj)
193 {
194 sdb_attribute_t *attr;
196 assert(m->type == MATCHER_ATTR);
197 assert(ATTR_M(m)->name);
199 attr = ATTR(attr_get(HOST(obj), ATTR_M(m)->name));
200 if (attr) {
201 char buf[sdb_data_strlen(&attr->value) + 1];
202 if (sdb_data_format(&attr->value, buf, sizeof(buf), SDB_UNQUOTED) <= 0)
203 return 0;
204 if (match_string(&ATTR_M(m)->value, buf))
205 return 1;
206 }
207 return 0;
208 } /* match_attr */
210 static int
211 match_lt(sdb_store_matcher_t *m, sdb_store_base_t *obj)
212 {
213 int status;
214 assert(m->type == MATCHER_LT);
215 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond);
216 return (status != INT_MAX) && (status < 0);
217 } /* match_lt */
219 static int
220 match_le(sdb_store_matcher_t *m, sdb_store_base_t *obj)
221 {
222 int status;
223 assert(m->type == MATCHER_LE);
224 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond);
225 return (status != INT_MAX) && (status <= 0);
226 } /* match_le */
228 static int
229 match_eq(sdb_store_matcher_t *m, sdb_store_base_t *obj)
230 {
231 int status;
232 assert(m->type == MATCHER_EQ);
233 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond);
234 return (status != INT_MAX) && (! status);
235 } /* match_eq */
237 static int
238 match_ge(sdb_store_matcher_t *m, sdb_store_base_t *obj)
239 {
240 int status;
241 assert(m->type == MATCHER_GE);
242 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond);
243 return (status != INT_MAX) && (status >= 0);
244 } /* match_ge */
246 static int
247 match_gt(sdb_store_matcher_t *m, sdb_store_base_t *obj)
248 {
249 int status;
250 assert(m->type == MATCHER_GT);
251 status = COND_M(m)->cond->cmp(obj, COND_M(m)->cond);
252 return (status != INT_MAX) && (status > 0);
253 } /* match_gt */
255 typedef int (*matcher_cb)(sdb_store_matcher_t *, sdb_store_base_t *);
257 /* this array needs to be indexable by the matcher types;
258 * -> update the enum in store-private.h when updating this */
259 static matcher_cb matchers[] = {
260 match_logical,
261 match_logical,
262 match_unary,
263 match_name,
264 match_attr,
265 match_lt,
266 match_le,
267 match_eq,
268 match_ge,
269 match_gt,
270 };
272 /*
273 * private conditional types
274 */
276 static int
277 attr_cond_init(sdb_object_t *obj, va_list ap)
278 {
279 const char *name = va_arg(ap, const char *);
280 const sdb_data_t *value = va_arg(ap, const sdb_data_t *);
282 if (! name)
283 return -1;
285 SDB_STORE_COND(obj)->cmp = attr_cmp;
287 ATTR_C(obj)->name = strdup(name);
288 if (! ATTR_C(obj)->name)
289 return -1;
290 if (sdb_data_copy(&ATTR_C(obj)->value, value))
291 return -1;
292 return 0;
293 } /* attr_cond_init */
295 static void
296 attr_cond_destroy(sdb_object_t *obj)
297 {
298 if (ATTR_C(obj)->name)
299 free(ATTR_C(obj)->name);
300 sdb_data_free_datum(&ATTR_C(obj)->value);
301 } /* attr_cond_destroy */
303 static sdb_type_t attr_cond_type = {
304 /* size = */ sizeof(attr_cond_t),
305 /* init = */ attr_cond_init,
306 /* destroy = */ attr_cond_destroy,
307 };
309 /*
310 * private matcher types
311 */
313 /* initializes a string matcher consuming two elements from ap */
314 static int
315 string_matcher_init(string_matcher_t *m, va_list ap)
316 {
317 const char *name = va_arg(ap, const char *);
318 const char *name_re = va_arg(ap, const char *);
320 if (name) {
321 m->name = strdup(name);
322 if (! m->name)
323 return -1;
324 }
325 if (name_re) {
326 m->name_re = malloc(sizeof(*m->name_re));
327 if (! m->name_re)
328 return -1;
329 if (regcomp(m->name_re, name_re, REG_EXTENDED | REG_ICASE | REG_NOSUB))
330 return -1;
331 }
332 return 0;
333 } /* string_matcher_init */
335 static void
336 string_matcher_destroy(string_matcher_t *m)
337 {
338 if (m->name)
339 free(m->name);
340 if (m->name_re) {
341 regfree(m->name_re);
342 free(m->name_re);
343 }
344 } /* string_matcher_destroy */
346 static char *
347 string_tostring(string_matcher_t *m, char *buf, size_t buflen)
348 {
349 snprintf(buf, buflen, "{ %s%s%s, %p }",
350 m->name ? "'" : "", m->name ? m->name : "NULL", m->name ? "'" : "",
351 m->name_re);
352 return buf;
353 } /* string_tostring */
355 /* initializes a name matcher */
356 static int
357 name_matcher_init(sdb_object_t *obj, va_list ap)
358 {
359 name_matcher_t *m = NAME_M(obj);
360 M(obj)->type = MATCHER_NAME;
361 return string_matcher_init(&m->name, ap);
362 } /* name_matcher_init */
364 static void
365 name_matcher_destroy(sdb_object_t *obj)
366 {
367 name_matcher_t *m = NAME_M(obj);
368 string_matcher_destroy(&m->name);
369 } /* name_matcher_destroy */
371 static char *
372 name_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
373 {
374 char name[buflen + 1];
375 assert(m->type == MATCHER_NAME);
376 snprintf(buf, buflen, "OBJ[%s]{ NAME%s }",
377 SDB_STORE_TYPE_TO_NAME(NAME_M(m)->obj_type),
378 string_tostring(&NAME_M(m)->name, name, sizeof(name)));
379 return buf;
380 } /* name_tostring */
382 static int
383 attr_matcher_init(sdb_object_t *obj, va_list ap)
384 {
385 attr_matcher_t *attr = ATTR_M(obj);
386 const char *name = va_arg(ap, const char *);
388 M(obj)->type = MATCHER_ATTR;
389 if (name) {
390 attr->name = strdup(name);
391 if (! attr->name)
392 return -1;
393 }
394 return string_matcher_init(&attr->value, ap);
395 } /* attr_matcher_init */
397 static void
398 attr_matcher_destroy(sdb_object_t *obj)
399 {
400 attr_matcher_t *attr = ATTR_M(obj);
401 if (attr->name)
402 free(attr->name);
403 attr->name = NULL;
404 string_matcher_destroy(&attr->value);
405 } /* attr_matcher_destroy */
407 static char *
408 attr_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
409 {
410 char value[buflen + 1];
412 if (! m) {
413 snprintf(buf, buflen, "ATTR{}");
414 return buf;
415 }
417 assert(m->type == MATCHER_ATTR);
418 snprintf(buf, buflen, "ATTR[%s]{ VALUE%s }", ATTR_M(m)->name,
419 string_tostring(&ATTR_M(m)->value, value, sizeof(value)));
420 return buf;
421 } /* attr_tostring */
423 static int
424 cond_matcher_init(sdb_object_t *obj, va_list ap)
425 {
426 int type = va_arg(ap, int);
427 sdb_store_cond_t *cond = va_arg(ap, sdb_store_cond_t *);
429 if (! cond)
430 return -1;
432 sdb_object_ref(SDB_OBJ(cond));
434 M(obj)->type = type;
435 COND_M(obj)->cond = cond;
436 return 0;
437 } /* cond_matcher_init */
439 static void
440 cond_matcher_destroy(sdb_object_t *obj)
441 {
442 sdb_object_deref(SDB_OBJ(COND_M(obj)->cond));
443 } /* cond_matcher_destroy */
445 static char *
446 cond_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
447 {
448 if (COND_M(m)->cond->cmp == attr_cmp) {
449 char value[buflen];
450 if (sdb_data_format(&ATTR_C(COND_M(m)->cond)->value,
451 value, sizeof(value), SDB_SINGLE_QUOTED) < 0)
452 snprintf(value, sizeof(value), "ERR");
453 snprintf(buf, buflen, "ATTR[%s]{ %s %s }",
454 ATTR_C(COND_M(m)->cond)->name, MATCHER_SYM(m->type), value);
455 }
456 return buf;
457 } /* cond_tostring */
459 static int
460 op_matcher_init(sdb_object_t *obj, va_list ap)
461 {
462 M(obj)->type = va_arg(ap, int);
463 if ((M(obj)->type != MATCHER_OR) && (M(obj)->type != MATCHER_AND))
464 return -1;
466 OP_M(obj)->left = va_arg(ap, sdb_store_matcher_t *);
467 sdb_object_ref(SDB_OBJ(OP_M(obj)->left));
468 OP_M(obj)->right = va_arg(ap, sdb_store_matcher_t *);
469 sdb_object_ref(SDB_OBJ(OP_M(obj)->right));
471 if ((! OP_M(obj)->left) || (! OP_M(obj)->right))
472 return -1;
473 return 0;
474 } /* op_matcher_init */
476 static void
477 op_matcher_destroy(sdb_object_t *obj)
478 {
479 if (OP_M(obj)->left)
480 sdb_object_deref(SDB_OBJ(OP_M(obj)->left));
481 if (OP_M(obj)->right)
482 sdb_object_deref(SDB_OBJ(OP_M(obj)->right));
483 } /* op_matcher_destroy */
485 static char *
486 op_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
487 {
488 char left[buflen + 1], right[buflen + 1];
490 if (! m) {
491 /* this should not happen */
492 snprintf(buf, buflen, "()");
493 return buf;
494 }
496 assert((m->type == MATCHER_OR) || (m->type == MATCHER_AND));
497 snprintf(buf, buflen, "(%s, %s, %s)",
498 m->type == MATCHER_OR ? "OR" : "AND",
499 sdb_store_matcher_tostring(OP_M(m)->left, left, sizeof(left)),
500 sdb_store_matcher_tostring(OP_M(m)->right, right, sizeof(right)));
501 return buf;
502 } /* op_tostring */
504 static int
505 uop_matcher_init(sdb_object_t *obj, va_list ap)
506 {
507 M(obj)->type = va_arg(ap, int);
508 if (M(obj)->type != MATCHER_NOT)
509 return -1;
511 UOP_M(obj)->op = va_arg(ap, sdb_store_matcher_t *);
512 sdb_object_ref(SDB_OBJ(UOP_M(obj)->op));
514 if (! UOP_M(obj)->op)
515 return -1;
516 return 0;
517 } /* uop_matcher_init */
519 static void
520 uop_matcher_destroy(sdb_object_t *obj)
521 {
522 if (UOP_M(obj)->op)
523 sdb_object_deref(SDB_OBJ(UOP_M(obj)->op));
524 } /* uop_matcher_destroy */
526 static char *
527 uop_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
528 {
529 char op[buflen + 1];
531 if (! m) {
532 /* this should not happen */
533 snprintf(buf, buflen, "()");
534 return buf;
535 }
537 assert(m->type == MATCHER_NOT);
538 snprintf(buf, buflen, "(NOT, %s)",
539 sdb_store_matcher_tostring(UOP_M(m)->op, op, sizeof(op)));
540 return buf;
541 } /* uop_tostring */
543 static sdb_type_t name_type = {
544 /* size = */ sizeof(name_matcher_t),
545 /* init = */ name_matcher_init,
546 /* destroy = */ name_matcher_destroy,
547 };
549 static sdb_type_t attr_type = {
550 /* size = */ sizeof(attr_matcher_t),
551 /* init = */ attr_matcher_init,
552 /* destroy = */ attr_matcher_destroy,
553 };
555 static sdb_type_t cond_type = {
556 /* size = */ sizeof(cond_matcher_t),
557 /* init = */ cond_matcher_init,
558 /* destroy = */ cond_matcher_destroy,
559 };
561 static sdb_type_t op_type = {
562 /* size = */ sizeof(op_matcher_t),
563 /* init = */ op_matcher_init,
564 /* destroy = */ op_matcher_destroy,
565 };
567 static sdb_type_t uop_type = {
568 /* size = */ sizeof(uop_matcher_t),
569 /* init = */ uop_matcher_init,
570 /* destroy = */ uop_matcher_destroy,
571 };
573 typedef char *(*matcher_tostring_cb)(sdb_store_matcher_t *, char *, size_t);
575 /* this array needs to be indexable by the matcher types;
576 * -> update the enum in store-private.h when updating this */
577 static matcher_tostring_cb matchers_tostring[] = {
578 op_tostring,
579 op_tostring,
580 uop_tostring,
581 name_tostring,
582 attr_tostring,
583 cond_tostring,
584 cond_tostring,
585 cond_tostring,
586 cond_tostring,
587 cond_tostring,
588 };
590 /*
591 * public API
592 */
594 sdb_store_cond_t *
595 sdb_store_attr_cond(const char *name, const sdb_data_t *value)
596 {
597 return SDB_STORE_COND(sdb_object_create("attr-cond", attr_cond_type,
598 name, value));
599 } /* sdb_store_attr_cond */
601 sdb_store_matcher_t *
602 sdb_store_name_matcher(int type, const char *name, _Bool re)
603 {
604 sdb_store_matcher_t *m;
606 if (re)
607 m = M(sdb_object_create("name-matcher", name_type,
608 NULL, name));
609 else
610 m = M(sdb_object_create("name-matcher", name_type,
611 name, NULL));
613 if (! m)
614 return NULL;
616 NAME_M(m)->obj_type = type;
617 return m;
618 } /* sdb_store_name_matcher */
620 sdb_store_matcher_t *
621 sdb_store_attr_matcher(const char *name, const char *value, _Bool re)
622 {
623 if (! name)
624 return NULL;
626 if (re)
627 return M(sdb_object_create("attr-matcher", attr_type,
628 name, NULL, value));
629 return M(sdb_object_create("attr-matcher", attr_type,
630 name, value, NULL));
631 } /* sdb_store_attr_matcher */
633 sdb_store_matcher_t *
634 sdb_store_lt_matcher(sdb_store_cond_t *cond)
635 {
636 return M(sdb_object_create("lt-matcher", cond_type,
637 MATCHER_LT, cond));
638 } /* sdb_store_lt_matcher */
640 sdb_store_matcher_t *
641 sdb_store_le_matcher(sdb_store_cond_t *cond)
642 {
643 return M(sdb_object_create("le-matcher", cond_type,
644 MATCHER_LE, cond));
645 } /* sdb_store_le_matcher */
647 sdb_store_matcher_t *
648 sdb_store_eq_matcher(sdb_store_cond_t *cond)
649 {
650 return M(sdb_object_create("eq-matcher", cond_type,
651 MATCHER_EQ, cond));
652 } /* sdb_store_eq_matcher */
654 sdb_store_matcher_t *
655 sdb_store_ge_matcher(sdb_store_cond_t *cond)
656 {
657 return M(sdb_object_create("ge-matcher", cond_type,
658 MATCHER_GE, cond));
659 } /* sdb_store_ge_matcher */
661 sdb_store_matcher_t *
662 sdb_store_gt_matcher(sdb_store_cond_t *cond)
663 {
664 return M(sdb_object_create("gt-matcher", cond_type,
665 MATCHER_GT, cond));
666 } /* sdb_store_gt_matcher */
668 static sdb_store_matcher_t *
669 parse_attr_cmp(const char *attr, const char *op, const sdb_data_t *value)
670 {
671 sdb_store_matcher_t *(*matcher)(sdb_store_cond_t *) = NULL;
672 sdb_store_matcher_t *m;
673 sdb_store_cond_t *cond;
674 _Bool inv = 0;
676 /* TODO: this will reject any attributes called "name";
677 * use a different syntax for querying objects by name */
678 if (! strcasecmp(attr, "name"))
679 return NULL;
681 if (! strcasecmp(op, "<"))
682 matcher = sdb_store_lt_matcher;
683 else if (! strcasecmp(op, "<="))
684 matcher = sdb_store_le_matcher;
685 else if (! strcasecmp(op, "="))
686 matcher = sdb_store_eq_matcher;
687 else if (! strcasecmp(op, ">="))
688 matcher = sdb_store_ge_matcher;
689 else if (! strcasecmp(op, ">"))
690 matcher = sdb_store_gt_matcher;
691 else if (! strcasecmp(op, "!=")) {
692 matcher = sdb_store_eq_matcher;
693 inv = 1;
694 }
695 else
696 return NULL;
698 cond = sdb_store_attr_cond(attr, value);
699 if (! cond)
700 return NULL;
702 m = matcher(cond);
703 /* pass ownership to 'm' or destroy in case of an error */
704 sdb_object_deref(SDB_OBJ(cond));
705 if (! m)
706 return NULL;
708 if (inv) {
709 sdb_store_matcher_t *tmp;
710 tmp = sdb_store_inv_matcher(m);
711 /* pass ownership to the inverse matcher */
712 sdb_object_deref(SDB_OBJ(m));
713 m = tmp;
714 }
715 return m;
716 } /* parse_attr_cmp */
718 sdb_store_matcher_t *
719 sdb_store_matcher_parse_cmp(const char *obj_type, const char *attr,
720 const char *op, const sdb_data_t *value)
721 {
722 int type = -1;
723 _Bool inv = 0;
724 _Bool re = 0;
726 sdb_store_matcher_t *m = NULL;
728 if (! strcasecmp(obj_type, "host"))
729 type = SDB_HOST;
730 else if (! strcasecmp(obj_type, "service"))
731 type = SDB_SERVICE;
732 else if (! strcasecmp(obj_type, "attribute"))
733 type = SDB_ATTRIBUTE;
734 else
735 return NULL;
737 /* XXX: this code sucks! */
738 if (! strcasecmp(op, "=")) {
739 /* nothing to do */
740 }
741 else if (! strcasecmp(op, "!=")) {
742 inv = 1;
743 }
744 else if (! strcasecmp(op, "=~")) {
745 re = 1;
746 }
747 else if (! strcasecmp(op, "!~")) {
748 inv = 1;
749 re = 1;
750 }
751 else if (type == SDB_ATTRIBUTE)
752 return parse_attr_cmp(attr, op, value);
753 else
754 return NULL;
756 if (value->type != SDB_TYPE_STRING) {
757 if (type == SDB_ATTRIBUTE)
758 return parse_attr_cmp(attr, op, value);
759 return NULL;
760 }
762 if (! strcasecmp(attr, "name"))
763 m = sdb_store_name_matcher(type, value->data.string, re);
764 else if (type == SDB_ATTRIBUTE)
765 m = sdb_store_attr_matcher(attr, value->data.string, re);
767 if (! m)
768 return NULL;
770 if (inv) {
771 sdb_store_matcher_t *tmp;
772 tmp = sdb_store_inv_matcher(m);
773 /* pass ownership to the inverse matcher */
774 sdb_object_deref(SDB_OBJ(m));
775 m = tmp;
776 }
777 return m;
778 } /* sdb_store_matcher_parse_cmp */
780 sdb_store_matcher_t *
781 sdb_store_dis_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
782 {
783 return M(sdb_object_create("dis-matcher", op_type, MATCHER_OR,
784 left, right));
785 } /* sdb_store_dis_matcher */
787 sdb_store_matcher_t *
788 sdb_store_con_matcher(sdb_store_matcher_t *left, sdb_store_matcher_t *right)
789 {
790 return M(sdb_object_create("con-matcher", op_type, MATCHER_AND,
791 left, right));
792 } /* sdb_store_con_matcher */
794 sdb_store_matcher_t *
795 sdb_store_inv_matcher(sdb_store_matcher_t *m)
796 {
797 return M(sdb_object_create("inv-matcher", uop_type, MATCHER_NOT, m));
798 } /* sdb_store_inv_matcher */
800 int
801 sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_base_t *obj)
802 {
803 if (obj->type != SDB_HOST)
804 return 0;
806 /* "NULL" always matches */
807 if ((! m) || (! obj))
808 return 1;
810 if ((m->type < 0) || ((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers)))
811 return 0;
813 return matchers[m->type](m, obj);
814 } /* sdb_store_matcher_matches */
816 char *
817 sdb_store_matcher_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
818 {
819 if (! m)
820 return NULL;
822 if ((m->type < 0)
823 || (((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers_tostring))))
824 return NULL;
825 return matchers_tostring[m->type](m, buf, buflen);
826 } /* sdb_store_matcher_tostring */
828 int
829 sdb_store_lookup(sdb_store_matcher_t *m, sdb_store_lookup_cb cb,
830 void *user_data)
831 {
832 lookup_iter_data_t data = { m, cb, user_data };
834 if (! cb)
835 return -1;
836 return sdb_store_iterate(lookup_iter, &data);
837 } /* sdb_store_lookup */
839 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */