/*
- * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
+ * Copyright (C) 2013-2014 Jo-Philipp Wich <jo@mein.io>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* 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);
+ 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 (op->type)
{
case T_THIS:
- val = jp_match(op, cur);
+ 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);
+ val = jp_match(op, root, NULL, NULL);
if (val)
return jp_json_to_op(val, res);
}
static bool
-jp_expr(struct jp_opcode *op, struct json_object *root, struct json_object *cur)
+jp_regmatch(struct jp_opcode *op, struct json_object *root, struct json_object *cur)
+{
+ struct jp_opcode left, right;
+ char lbuf[22], rbuf[22], *lval, *rval;
+ int err, rflags = REG_NOSUB | REG_NEWLINE;
+ regex_t preg;
+
+
+ if (!jp_resolve(root, cur, op->down, &left) ||
+ !jp_resolve(root, cur, op->down->sibling, &right))
+ return false;
+
+ if (left.type == T_REGEXP)
+ {
+ switch (right.type)
+ {
+ case T_BOOL:
+ lval = right.num ? "true" : "false";
+ break;
+
+ case T_NUMBER:
+ snprintf(lbuf, sizeof(lbuf), "%d", right.num);
+ lval = lbuf;
+ break;
+
+ case T_STRING:
+ lval = right.str;
+ break;
+
+ default:
+ return false;
+ }
+
+ rval = left.str;
+ rflags = left.num;
+ }
+ else
+ {
+ switch (left.type)
+ {
+ case T_BOOL:
+ lval = left.num ? "true" : "false";
+ break;
+
+ case T_NUMBER:
+ snprintf(lbuf, sizeof(lbuf), "%d", left.num);
+ lval = lbuf;
+ break;
+
+ case T_STRING:
+ lval = left.str;
+ break;
+
+ default:
+ return false;
+ }
+
+ switch (right.type)
+ {
+ case T_BOOL:
+ rval = right.num ? "true" : "false";
+ break;
+
+ case T_NUMBER:
+ snprintf(rbuf, sizeof(rbuf), "%d", right.num);
+ rval = rbuf;
+ break;
+
+ case T_STRING:
+ rval = right.str;
+ break;
+
+ case T_REGEXP:
+ rval = right.str;
+ rflags = right.num;
+ break;
+
+ default:
+ return false;
+ }
+ }
+
+ if (regcomp(&preg, rval, rflags))
+ return false;
+
+ err = regexec(&preg, lval, 0, NULL, 0);
+
+ regfree(&preg);
+
+ return err ? false : true;
+}
+
+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;
case T_GE:
return jp_cmp(op, root, cur);
+ case T_MATCH:
+ return jp_regmatch(op, root, cur);
+
case T_ROOT:
- return !!jp_match(op, root);
+ return !!jp_match(op, root, NULL, NULL);
case T_THIS:
- return !!jp_match(op, cur);
+ return !!jp_match(op, cur, NULL, NULL);
case T_NOT:
- return !jp_expr(op->down, root, cur);
+ 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))
+ 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))
+ 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)
+ struct json_object *root, struct json_object *cur,
+ jp_match_cb_t cb, void *priv)
{
int idx, len;
struct json_object *tmp, *res = NULL;
; /* a label can only be part of a statement and a declaration is not a statement */
json_object_object_foreach(cur, key, val)
{
- if (!key)
- continue;
-
- if (jp_expr(ptr, root, val))
+ if (jp_expr(ptr, root, val, -1, key, cb, priv))
{
- tmp = jp_match_next(ptr->sibling, root, val);
+ tmp = jp_match_next(ptr->sibling, root, val, cb, priv);
if (tmp && !res)
res = tmp;
{
tmp = json_object_array_get_idx(cur, idx);
- if (jp_expr(ptr, root, tmp))
+ if (jp_expr(ptr, root, tmp, idx, NULL, cb, priv))
{
- tmp = jp_match_next(ptr->sibling, root, tmp);
+ tmp = jp_match_next(ptr->sibling, root, tmp, cb, priv);
if (tmp && !res)
res = tmp;
static struct json_object *
jp_match_next(struct jp_opcode *ptr,
- struct json_object *root, struct json_object *cur)
+ struct json_object *root, struct json_object *cur,
+ jp_match_cb_t cb, void *priv)
{
- struct json_object *next;
+ int idx;
+ struct json_object *next = NULL;
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);
+ return jp_match_next(ptr->sibling, root, next, cb, priv);
break;
case T_NUMBER:
- next = json_object_array_get_idx(cur, ptr->num);
+ if (json_object_get_type(cur) == json_type_array)
+ {
+ idx = ptr->num;
+
+ if (idx < 0)
+ idx += json_object_array_length(cur);
- if (next)
- return jp_match_next(ptr->sibling, root, next);
+ if (idx >= 0)
+ next = json_object_array_get_idx(cur, idx);
+
+ if (next)
+ return jp_match_next(ptr->sibling, root, next, cb, priv);
+ }
break;
default:
- return jp_match_expr(ptr, root, cur);
+ 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(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);
+ return jp_match_next(path->down, jsobj, jsobj, cb, priv);
}