123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- /*
- * Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include "parser.h"
- #include "matcher.h"
- static struct json_object *
- jp_match_next(struct jp_opcode *ptr,
- struct json_object *root, struct json_object *cur,
- jp_match_cb_t cb, void *priv);
- static bool
- jp_json_to_op(struct json_object *obj, struct jp_opcode *op)
- {
- switch (json_object_get_type(obj))
- {
- case json_type_boolean:
- op->type = T_BOOL;
- op->num = json_object_get_boolean(obj);
- return true;
- case json_type_int:
- op->type = T_NUMBER;
- op->num = json_object_get_int(obj);
- return true;
- case json_type_string:
- op->type = T_STRING;
- op->str = (char *)json_object_get_string(obj);
- return true;
- default:
- return false;
- }
- }
- static bool
- jp_resolve(struct json_object *root, struct json_object *cur,
- struct jp_opcode *op, struct jp_opcode *res)
- {
- struct json_object *val;
- switch (op->type)
- {
- case T_THIS:
- val = jp_match(op, cur, NULL, NULL);
- if (val)
- return jp_json_to_op(val, res);
- return false;
- case T_ROOT:
- val = jp_match(op, root, NULL, NULL);
- if (val)
- return jp_json_to_op(val, res);
- return false;
- default:
- *res = *op;
- return true;
- }
- }
- static bool
- jp_cmp(struct jp_opcode *op, struct json_object *root, struct json_object *cur)
- {
- int delta;
- struct jp_opcode left, right;
- if (!jp_resolve(root, cur, op->down, &left) ||
- !jp_resolve(root, cur, op->down->sibling, &right))
- return false;
- if (left.type != right.type)
- return false;
- switch (left.type)
- {
- case T_BOOL:
- case T_NUMBER:
- delta = left.num - right.num;
- break;
- case T_STRING:
- delta = strcmp(left.str, right.str);
- break;
- default:
- return false;
- }
- switch (op->type)
- {
- case T_EQ:
- return (delta == 0);
- case T_LT:
- return (delta < 0);
- case T_LE:
- return (delta <= 0);
- case T_GT:
- return (delta > 0);
- case T_GE:
- return (delta >= 0);
- case T_NE:
- return (delta != 0);
- default:
- return false;
- }
- }
- static bool
- jp_expr(struct jp_opcode *op, struct json_object *root, struct json_object *cur,
- int idx, const char *key, jp_match_cb_t cb, void *priv)
- {
- struct jp_opcode *sop;
- switch (op->type)
- {
- case T_WILDCARD:
- return true;
- case T_EQ:
- case T_NE:
- case T_LT:
- case T_LE:
- case T_GT:
- case T_GE:
- return jp_cmp(op, root, cur);
- case T_ROOT:
- return !!jp_match(op, root, NULL, NULL);
- case T_THIS:
- return !!jp_match(op, cur, NULL, NULL);
- case T_NOT:
- return !jp_expr(op->down, root, cur, idx, key, cb, priv);
- case T_AND:
- for (sop = op->down; sop; sop = sop->sibling)
- if (!jp_expr(sop, root, cur, idx, key, cb, priv))
- return false;
- return true;
- case T_OR:
- case T_UNION:
- for (sop = op->down; sop; sop = sop->sibling)
- if (jp_expr(sop, root, cur, idx, key, cb, priv))
- return true;
- return false;
- case T_STRING:
- return (key && !strcmp(op->str, key));
- case T_NUMBER:
- return (idx == op->num);
- default:
- return false;
- }
- }
- static struct json_object *
- jp_match_expr(struct jp_opcode *ptr,
- struct json_object *root, struct json_object *cur,
- jp_match_cb_t cb, void *priv)
- {
- int idx, len;
- struct json_object *tmp, *res = NULL;
- switch (json_object_get_type(cur))
- {
- case json_type_object:
- ; /* a label can only be part of a statement and a declaration is not a statement */
- json_object_object_foreach(cur, key, val)
- {
- if (jp_expr(ptr, root, val, -1, key, cb, priv))
- {
- tmp = jp_match_next(ptr->sibling, root, val, cb, priv);
- if (tmp && !res)
- res = tmp;
- }
- }
- break;
- case json_type_array:
- len = json_object_array_length(cur);
- for (idx = 0; idx < len; idx++)
- {
- tmp = json_object_array_get_idx(cur, idx);
- if (jp_expr(ptr, root, tmp, idx, NULL, cb, priv))
- {
- tmp = jp_match_next(ptr->sibling, root, tmp, cb, priv);
- if (tmp && !res)
- res = tmp;
- }
- }
- break;
- default:
- break;
- }
- return res;
- }
- static struct json_object *
- jp_match_next(struct jp_opcode *ptr,
- struct json_object *root, struct json_object *cur,
- jp_match_cb_t cb, void *priv)
- {
- struct json_object *next;
- if (!ptr)
- {
- if (cb)
- cb(cur, priv);
- return cur;
- }
- switch (ptr->type)
- {
- case T_STRING:
- case T_LABEL:
- if (json_object_object_get_ex(cur, ptr->str, &next))
- return jp_match_next(ptr->sibling, root, next, cb, priv);
- break;
- case T_NUMBER:
- next = json_object_array_get_idx(cur, ptr->num);
- if (next)
- return jp_match_next(ptr->sibling, root, next, cb, priv);
- break;
- default:
- return jp_match_expr(ptr, root, cur, cb, priv);
- }
- return NULL;
- }
- struct json_object *
- jp_match(struct jp_opcode *path, json_object *jsobj,
- jp_match_cb_t cb, void *priv)
- {
- if (path->type == T_LABEL)
- path = path->down;
- return jp_match_next(path->down, jsobj, jsobj, cb, priv);
- }
|