parser: change exitcode in case of oom errors
[project/jsonpath.git] / matcher.c
1 /*
2  * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
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 "matcher.h"
18
19 static struct json_object *
20 jp_match_next(struct jp_opcode *ptr,
21               struct json_object *root, struct json_object *cur);
22
23 static bool
24 jp_json_to_op(struct json_object *obj, struct jp_opcode *op)
25 {
26         switch (json_object_get_type(obj))
27         {
28         case json_type_boolean:
29                 op->type = T_BOOL;
30                 op->num = json_object_get_boolean(obj);
31                 return true;
32
33         case json_type_int:
34                 op->type = T_NUMBER;
35                 op->num = json_object_get_int(obj);
36                 return true;
37
38         case json_type_string:
39                 op->type = T_STRING;
40                 op->str = (char *)json_object_get_string(obj);
41                 return true;
42
43         default:
44                 return false;
45         }
46 }
47
48 static bool
49 jp_resolve(struct json_object *root, struct json_object *cur,
50            struct jp_opcode *op, struct jp_opcode *res)
51 {
52         struct json_object *val;
53
54         switch (op->type)
55         {
56         case T_THIS:
57                 val = jp_match(op, cur);
58
59                 if (val)
60                         return jp_json_to_op(val, res);
61
62                 return false;
63
64         case T_ROOT:
65                 val = jp_match(op, root);
66
67                 if (val)
68                         return jp_json_to_op(val, res);
69
70                 return false;
71
72         default:
73                 *res = *op;
74                 return true;
75         }
76 }
77
78 static bool
79 jp_cmp(struct jp_opcode *op, struct json_object *root, struct json_object *cur)
80 {
81         int delta;
82         struct jp_opcode left, right;
83
84         if (!jp_resolve(root, cur, op->down, &left) ||
85         !jp_resolve(root, cur, op->down->sibling, &right))
86                 return false;
87
88         if (left.type != right.type)
89                 return false;
90
91         switch (left.type)
92         {
93         case T_BOOL:
94         case T_NUMBER:
95                 delta = left.num - right.num;
96                 break;
97
98         case T_STRING:
99                 delta = strcmp(left.str, right.str);
100                 break;
101
102         default:
103                 return false;
104         }
105
106         switch (op->type)
107         {
108         case T_EQ:
109                 return (delta == 0);
110
111         case T_LT:
112                 return (delta < 0);
113
114         case T_LE:
115                 return (delta <= 0);
116
117         case T_GT:
118                 return (delta > 0);
119
120         case T_GE:
121                 return (delta >= 0);
122
123         case T_NE:
124                 return (delta != 0);
125
126         default:
127                 return false;
128         }
129 }
130
131 static bool
132 jp_expr(struct jp_opcode *op, struct json_object *root, struct json_object *cur)
133 {
134         struct jp_opcode *sop;
135
136         switch (op->type)
137         {
138         case T_WILDCARD:
139                 return true;
140
141         case T_EQ:
142         case T_NE:
143         case T_LT:
144         case T_LE:
145         case T_GT:
146         case T_GE:
147                 return jp_cmp(op, root, cur);
148
149         case T_ROOT:
150                 return !!jp_match(op, root);
151
152         case T_THIS:
153                 return !!jp_match(op, cur);
154
155         case T_NOT:
156                 return !jp_expr(op->down, root, cur);
157
158         case T_AND:
159                 for (sop = op->down; sop; sop = sop->sibling)
160                         if (!jp_expr(sop, root, cur))
161                                 return false;
162                 return true;
163
164         case T_OR:
165                 for (sop = op->down; sop; sop = sop->sibling)
166                         if (jp_expr(sop, root, cur))
167                                 return true;
168                 return false;
169
170         default:
171                 return false;
172         }
173 }
174
175 static struct json_object *
176 jp_match_expr(struct jp_opcode *ptr,
177               struct json_object *root, struct json_object *cur)
178 {
179         int idx, len;
180         struct json_object *tmp, *res = NULL;
181
182         switch (json_object_get_type(cur))
183         {
184         case json_type_object:
185                 ; /* a label can only be part of a statement and a declaration is not a statement */
186                 json_object_object_foreach(cur, key, val)
187                 {
188                         if (!key)
189                                 continue;
190
191                         if (jp_expr(ptr, root, val))
192                         {
193                                 tmp = jp_match_next(ptr->sibling, root, val);
194
195                                 if (tmp && !res)
196                                         res = tmp;
197                         }
198                 }
199
200                 break;
201
202         case json_type_array:
203                 len = json_object_array_length(cur);
204
205                 for (idx = 0; idx < len; idx++)
206                 {
207                         tmp = json_object_array_get_idx(cur, idx);
208
209                         if (jp_expr(ptr, root, tmp))
210                         {
211                                 tmp = jp_match_next(ptr->sibling, root, tmp);
212
213                                 if (tmp && !res)
214                                         res = tmp;
215                         }
216                 }
217
218                 break;
219
220         default:
221                 break;
222         }
223
224         return res;
225 }
226
227 static struct json_object *
228 jp_match_next(struct jp_opcode *ptr,
229               struct json_object *root, struct json_object *cur)
230 {
231         struct json_object *next;
232
233         if (!ptr)
234                 return cur;
235
236         switch (ptr->type)
237         {
238         case T_STRING:
239         case T_LABEL:
240                 if (json_object_object_get_ex(cur, ptr->str, &next))
241                         return jp_match_next(ptr->sibling, root, next);
242
243                 break;
244
245         case T_NUMBER:
246                 next = json_object_array_get_idx(cur, ptr->num);
247
248                 if (next)
249                         return jp_match_next(ptr->sibling, root, next);
250
251                 break;
252
253         default:
254                 return jp_match_expr(ptr, root, cur);
255         }
256
257         return NULL;
258 }
259
260 struct json_object *
261 jp_match(struct jp_opcode *path, json_object *jsobj)
262 {
263         if (path->type == T_LABEL)
264                 path = path->down;
265
266         return jp_match_next(path->down, jsobj, jsobj);
267 }