implement POSIX regexp support
[oweals/jsonpath.git] / matcher.c
1 /*
2  * Copyright (C) 2013-2014 Jo-Philipp Wich <jo@mein.io>
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include "parser.h"
18 #include "matcher.h"
19
20
21 static struct json_object *
22 jp_match_next(struct jp_opcode *ptr,
23               struct json_object *root, struct json_object *cur,
24               jp_match_cb_t cb, void *priv);
25
26 static bool
27 jp_json_to_op(struct json_object *obj, struct jp_opcode *op)
28 {
29         switch (json_object_get_type(obj))
30         {
31         case json_type_boolean:
32                 op->type = T_BOOL;
33                 op->num = json_object_get_boolean(obj);
34                 return true;
35
36         case json_type_int:
37                 op->type = T_NUMBER;
38                 op->num = json_object_get_int(obj);
39                 return true;
40
41         case json_type_string:
42                 op->type = T_STRING;
43                 op->str = (char *)json_object_get_string(obj);
44                 return true;
45
46         default:
47                 return false;
48         }
49 }
50
51 static bool
52 jp_resolve(struct json_object *root, struct json_object *cur,
53            struct jp_opcode *op, struct jp_opcode *res)
54 {
55         struct json_object *val;
56
57         switch (op->type)
58         {
59         case T_THIS:
60                 val = jp_match(op, cur, NULL, NULL);
61
62                 if (val)
63                         return jp_json_to_op(val, res);
64
65                 return false;
66
67         case T_ROOT:
68                 val = jp_match(op, root, NULL, NULL);
69
70                 if (val)
71                         return jp_json_to_op(val, res);
72
73                 return false;
74
75         default:
76                 *res = *op;
77                 return true;
78         }
79 }
80
81 static bool
82 jp_cmp(struct jp_opcode *op, struct json_object *root, struct json_object *cur)
83 {
84         int delta;
85         struct jp_opcode left, right;
86
87         if (!jp_resolve(root, cur, op->down, &left) ||
88         !jp_resolve(root, cur, op->down->sibling, &right))
89                 return false;
90
91         if (left.type != right.type)
92                 return false;
93
94         switch (left.type)
95         {
96         case T_BOOL:
97         case T_NUMBER:
98                 delta = left.num - right.num;
99                 break;
100
101         case T_STRING:
102                 delta = strcmp(left.str, right.str);
103                 break;
104
105         default:
106                 return false;
107         }
108
109         switch (op->type)
110         {
111         case T_EQ:
112                 return (delta == 0);
113
114         case T_LT:
115                 return (delta < 0);
116
117         case T_LE:
118                 return (delta <= 0);
119
120         case T_GT:
121                 return (delta > 0);
122
123         case T_GE:
124                 return (delta >= 0);
125
126         case T_NE:
127                 return (delta != 0);
128
129         default:
130                 return false;
131         }
132 }
133
134 static bool
135 jp_regmatch(struct jp_opcode *op, struct json_object *root, struct json_object *cur)
136 {
137         struct jp_opcode left, right;
138         char lbuf[22], rbuf[22], *lval, *rval;
139         int err, rflags = REG_NOSUB | REG_NEWLINE;
140         regex_t preg;
141
142
143         if (!jp_resolve(root, cur, op->down, &left) ||
144             !jp_resolve(root, cur, op->down->sibling, &right))
145                 return false;
146
147         if (left.type == T_REGEXP)
148         {
149                 switch (right.type)
150                 {
151                 case T_BOOL:
152                         lval = right.num ? "true" : "false";
153                         break;
154
155                 case T_NUMBER:
156                         snprintf(lbuf, sizeof(lbuf), "%d", right.num);
157                         lval = lbuf;
158                         break;
159
160                 case T_STRING:
161                         lval = right.str;
162                         break;
163
164                 default:
165                         return false;
166                 }
167
168                 rval = left.str;
169                 rflags = left.num;
170         }
171         else
172         {
173                 switch (left.type)
174                 {
175                 case T_BOOL:
176                         lval = left.num ? "true" : "false";
177                         break;
178
179                 case T_NUMBER:
180                         snprintf(lbuf, sizeof(lbuf), "%d", left.num);
181                         lval = lbuf;
182                         break;
183
184                 case T_STRING:
185                         lval = left.str;
186                         break;
187
188                 default:
189                         return false;
190                 }
191
192                 switch (right.type)
193                 {
194                 case T_BOOL:
195                         rval = right.num ? "true" : "false";
196                         break;
197
198                 case T_NUMBER:
199                         snprintf(rbuf, sizeof(rbuf), "%d", right.num);
200                         rval = rbuf;
201                         break;
202
203                 case T_STRING:
204                         rval = right.str;
205                         break;
206
207                 case T_REGEXP:
208                         rval = right.str;
209                         rflags = right.num;
210                         break;
211
212                 default:
213                         return false;
214                 }
215         }
216
217         if (regcomp(&preg, rval, rflags))
218                 return false;
219
220         err = regexec(&preg, lval, 0, NULL, 0);
221
222         regfree(&preg);
223
224         return err ? false : true;
225 }
226
227 static bool
228 jp_expr(struct jp_opcode *op, struct json_object *root, struct json_object *cur,
229         int idx, const char *key, jp_match_cb_t cb, void *priv)
230 {
231         struct jp_opcode *sop;
232
233         switch (op->type)
234         {
235         case T_WILDCARD:
236                 return true;
237
238         case T_EQ:
239         case T_NE:
240         case T_LT:
241         case T_LE:
242         case T_GT:
243         case T_GE:
244                 return jp_cmp(op, root, cur);
245
246         case T_MATCH:
247                 return jp_regmatch(op, root, cur);
248
249         case T_ROOT:
250                 return !!jp_match(op, root, NULL, NULL);
251
252         case T_THIS:
253                 return !!jp_match(op, cur, NULL, NULL);
254
255         case T_NOT:
256                 return !jp_expr(op->down, root, cur, idx, key, cb, priv);
257
258         case T_AND:
259                 for (sop = op->down; sop; sop = sop->sibling)
260                         if (!jp_expr(sop, root, cur, idx, key, cb, priv))
261                                 return false;
262                 return true;
263
264         case T_OR:
265         case T_UNION:
266                 for (sop = op->down; sop; sop = sop->sibling)
267                         if (jp_expr(sop, root, cur, idx, key, cb, priv))
268                                 return true;
269                 return false;
270
271         case T_STRING:
272                 return (key && !strcmp(op->str, key));
273
274         case T_NUMBER:
275                 return (idx == op->num);
276
277         default:
278                 return false;
279         }
280 }
281
282 static struct json_object *
283 jp_match_expr(struct jp_opcode *ptr,
284               struct json_object *root, struct json_object *cur,
285               jp_match_cb_t cb, void *priv)
286 {
287         int idx, len;
288         struct json_object *tmp, *res = NULL;
289
290         switch (json_object_get_type(cur))
291         {
292         case json_type_object:
293                 ; /* a label can only be part of a statement and a declaration is not a statement */
294                 json_object_object_foreach(cur, key, val)
295                 {
296                         if (jp_expr(ptr, root, val, -1, key, cb, priv))
297                         {
298                                 tmp = jp_match_next(ptr->sibling, root, val, cb, priv);
299
300                                 if (tmp && !res)
301                                         res = tmp;
302                         }
303                 }
304
305                 break;
306
307         case json_type_array:
308                 len = json_object_array_length(cur);
309
310                 for (idx = 0; idx < len; idx++)
311                 {
312                         tmp = json_object_array_get_idx(cur, idx);
313
314                         if (jp_expr(ptr, root, tmp, idx, NULL, cb, priv))
315                         {
316                                 tmp = jp_match_next(ptr->sibling, root, tmp, cb, priv);
317
318                                 if (tmp && !res)
319                                         res = tmp;
320                         }
321                 }
322
323                 break;
324
325         default:
326                 break;
327         }
328
329         return res;
330 }
331
332 static struct json_object *
333 jp_match_next(struct jp_opcode *ptr,
334               struct json_object *root, struct json_object *cur,
335               jp_match_cb_t cb, void *priv)
336 {
337         int idx;
338         struct json_object *next = NULL;
339
340         if (!ptr)
341         {
342                 if (cb)
343                         cb(cur, priv);
344
345                 return cur;
346         }
347
348         switch (ptr->type)
349         {
350         case T_STRING:
351         case T_LABEL:
352                 if (json_object_object_get_ex(cur, ptr->str, &next))
353                         return jp_match_next(ptr->sibling, root, next, cb, priv);
354
355                 break;
356
357         case T_NUMBER:
358                 if (json_object_get_type(cur) == json_type_array)
359                 {
360                         idx = ptr->num;
361
362                         if (idx < 0)
363                                 idx += json_object_array_length(cur);
364
365                         if (idx >= 0)
366                                 next = json_object_array_get_idx(cur, idx);
367
368                         if (next)
369                                 return jp_match_next(ptr->sibling, root, next, cb, priv);
370                 }
371
372                 break;
373
374         default:
375                 return jp_match_expr(ptr, root, cur, cb, priv);
376         }
377
378         return NULL;
379 }
380
381 struct json_object *
382 jp_match(struct jp_opcode *path, json_object *jsobj,
383          jp_match_cb_t cb, void *priv)
384 {
385         if (path->type == T_LABEL)
386                 path = path->down;
387
388         return jp_match_next(path->down, jsobj, jsobj, cb, priv);
389 }