static int strfilter__append(struct strfilter *filter, bool _or, const char *rules, const char **err) { struct strfilter_node *right, *root; const char *ep = NULL; if (!filter || !rules) return -EINVAL; right = strfilter_node__new(rules, &ep); if (!right || *ep != '\0') { if (err) *err = ep; goto error; } root = strfilter_node__alloc(_or ? OP_or : OP_and, filter->root, right); if (!root) { ep = NULL; goto error; } filter->root = root; return 0; error: strfilter_node__delete(right); return ep ? -EINVAL : -ENOMEM; }
struct strfilter *strfilter__new(const char *rules, const char **err) { struct strfilter *ret = zalloc(sizeof(struct strfilter)); const char *ep = NULL; if (ret) ret->root = strfilter_node__new(rules, &ep); if (!ret || !ret->root || *ep != '\0') { if (err) *err = ep; strfilter__delete(ret); ret = NULL; } return ret; }
/* * Parse filter rule and return new strfilter. * Return NULL if fail, and *ep == NULL if memory allocation failed. */ struct strfilter *strfilter__new(const char *rules, const char **err) { struct strfilter *filter = zalloc(sizeof(*filter)); const char *ep = NULL; if (filter) filter->root = strfilter_node__new(rules, &ep); if (!filter || !filter->root || *ep != '\0') { if (err) *err = ep; strfilter__delete(filter); filter = NULL; } return filter; }
static struct strfilter_node *strfilter_node__new(const char *s, const char **ep) { struct strfilter_node root, *cur, *last_op; const char *e; if (!s) return NULL; memset(&root, 0, sizeof(root)); last_op = cur = &root; s = get_token(s, &e); while (*s != '\0' && *s != ')') { switch (*s) { case '&': /* */ if (!cur->r || !last_op->r) goto error; cur = strfilter_node__alloc(OP_and, last_op->r, NULL); if (!cur) goto nomem; last_op->r = cur; last_op = cur; break; case '|': /* */ if (!cur->r || !root.r) goto error; cur = strfilter_node__alloc(OP_or, root.r, NULL); if (!cur) goto nomem; root.r = cur; last_op = cur; break; case '!': /* */ if (cur->r) goto error; cur->r = strfilter_node__alloc(OP_not, NULL, NULL); if (!cur->r) goto nomem; cur = cur->r; break; case '(': /* */ if (cur->r) goto error; cur->r = strfilter_node__new(s + 1, &s); if (!s) goto nomem; if (!cur->r || *s != ')') goto error; e = s + 1; break; default: if (cur->r) goto error; cur->r = strfilter_node__alloc(NULL, NULL, NULL); if (!cur->r) goto nomem; cur->r->p = strndup(s, e - s); if (!cur->r->p) goto nomem; } s = get_token(e, &e); } if (!cur->r) goto error; *ep = s; return root.r; nomem: s = NULL; error: *ep = s; strfilter_node__delete(root.r); return NULL; }