cli: additional flags and cleanup
[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 }