main: fix spurious premature parse aborts in array mode
[project/jsonpath.git] / matcher.c
index 9d2aa89e878ea715732a66e3f7a94c3b375c60ff..d2a8767c7ca399a204e0c52dcc4b69d6885c8880 100644 (file)
--- a/matcher.c
+++ b/matcher.c
@@ -1,5 +1,5 @@
 /*
- * 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,
@@ -129,6 +131,99 @@ jp_cmp(struct jp_opcode *op, struct json_object *root, struct json_object *cur)
        }
 }
 
+static bool
+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)
@@ -148,6 +243,9 @@ jp_expr(struct jp_opcode *op, struct json_object *root, struct json_object *cur,
        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, NULL, NULL);
 
@@ -164,6 +262,7 @@ jp_expr(struct jp_opcode *op, struct json_object *root, struct json_object *cur,
                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;
@@ -235,7 +334,8 @@ 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;
+       int idx;
+       struct json_object *next = NULL;
 
        if (!ptr)
        {
@@ -255,10 +355,19 @@ jp_match_next(struct jp_opcode *ptr,
                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 (next)
-                       return jp_match_next(ptr->sibling, root, next, cb, priv);
+                       if (idx < 0)
+                               idx += json_object_array_length(cur);
+
+                       if (idx >= 0)
+                               next = json_object_array_get_idx(cur, idx);
+
+                       if (next)
+                               return jp_match_next(ptr->sibling, root, next, cb, priv);
+               }
 
                break;