Code

store: Split store_obj into separate host and service objects.
[sysdb.git] / src / core / store_lookup.c
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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 : */