build: use -ffunction-sections and --gc-sections
[oweals/jsonpath.git] / main.c
1 /*
2  * Copyright (C) 2013-2014 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 <stdio.h>
18 #include <stdbool.h>
19 #include <unistd.h>
20 #include <errno.h>
21
22 #ifdef JSONC
23         #include <json.h>
24 #else
25         #include <json-c/json.h>
26 #endif
27
28 #include <libubox/list.h>
29
30 #include "lexer.h"
31 #include "parser.h"
32 #include "matcher.h"
33
34
35 struct match_item {
36         struct json_object *jsobj;
37         struct list_head list;
38 };
39
40 static struct json_object *
41 parse_json(FILE *fd, const char *source, const char **error)
42 {
43         int len;
44         char buf[256];
45         struct json_object *obj = NULL;
46         struct json_tokener *tok = json_tokener_new();
47         enum json_tokener_error err = json_tokener_continue;
48
49         if (!tok)
50                 return NULL;
51
52         if (source)
53         {
54                 obj = json_tokener_parse_ex(tok, source, strlen(source));
55                 err = json_tokener_get_error(tok);
56         }
57         else
58         {
59                 while ((len = fread(buf, 1, sizeof(buf), fd)) > 0)
60                 {
61                         obj = json_tokener_parse_ex(tok, buf, len);
62                         err = json_tokener_get_error(tok);
63
64                         if (!err || err != json_tokener_continue)
65                                 break;
66                 }
67         }
68
69         json_tokener_free(tok);
70
71         if (err)
72         {
73                 if (err == json_tokener_continue)
74                         err = json_tokener_error_parse_eof;
75
76                 *error = json_tokener_error_desc(err);
77                 return NULL;
78         }
79
80         return obj;
81 }
82
83 static void
84 print_string(const char *s)
85 {
86         const char *p;
87
88         printf("'");
89
90         for (p = s; *p; p++)
91         {
92                 if (*p == '\'')
93                         printf("'\"'\"'");
94                 else
95                         printf("%c", *p);
96         }
97
98         printf("'");
99 }
100
101 static void
102 export_value(struct list_head *matches, const char *prefix)
103 {
104         int n, len;
105         bool first = true;
106         struct match_item *item;
107
108         if (list_empty(matches))
109                 return;
110
111         if (prefix)
112         {
113                 printf("export %s=", prefix);
114
115                 list_for_each_entry(item, matches, list)
116                 {
117                         switch (json_object_get_type(item->jsobj))
118                         {
119                         case json_type_object:
120                                 ; /* a label can only be part of a statement */
121                                 json_object_object_foreach(item->jsobj, key, val)
122                                 {
123                                         if (!val)
124                                                 continue;
125
126                                         if (!first)
127                                                 printf("\\ ");
128
129                                         print_string(key);
130                                         first = false;
131                                 }
132                                 break;
133
134                         case json_type_array:
135                                 for (n = 0, len = json_object_array_length(item->jsobj);
136                                      n < len; n++)
137                                 {
138                                         if (!first)
139                                                 printf("\\ ");
140
141                                         printf("%d", n);
142                                         first = false;
143                                 }
144                                 break;
145
146                         case json_type_boolean:
147                                 if (!first)
148                                         printf("\\ ");
149                                 printf("%d", json_object_get_boolean(item->jsobj));
150                                 break;
151
152                         case json_type_int:
153                                 if (!first)
154                                         printf("\\ ");
155                                 printf("%d", json_object_get_int(item->jsobj));
156                                 break;
157
158                         case json_type_double:
159                                 if (!first)
160                                         printf("\\ ");
161                                 printf("%f", json_object_get_double(item->jsobj));
162                                 break;
163
164                         case json_type_string:
165                                 if (!first)
166                                         printf("\\ ");
167                                 print_string(json_object_get_string(item->jsobj));
168                                 break;
169
170                         case json_type_null:
171                                 break;
172                         }
173
174                         first = false;
175                 }
176
177                 printf("; ");
178         }
179         else
180         {
181                 list_for_each_entry(item, matches, list)
182                 {
183                         switch (json_object_get_type(item->jsobj))
184                         {
185                         case json_type_object:
186                         case json_type_array:
187                         case json_type_boolean:
188                         case json_type_int:
189                         case json_type_double:
190                                 printf("%s\n", json_object_to_json_string(item->jsobj));
191                                 break;
192
193                         case json_type_string:
194                                 printf("%s\n", json_object_get_string(item->jsobj));
195                                 break;
196
197                         case json_type_null:
198                                 break;
199                         }
200                 }
201         }
202 }
203
204 static void
205 export_type(struct list_head *matches, const char *prefix)
206 {
207         bool first = true;
208         struct match_item *item;
209         const char *types[] = {
210                 "null",
211                 "boolean",
212                 "double",
213                 "int",
214                 "object",
215                 "array",
216                 "string"
217         };
218
219         if (list_empty(matches))
220                 return;
221
222         if (prefix)
223                 printf("export %s=", prefix);
224
225         list_for_each_entry(item, matches, list)
226         {
227                 if (!first)
228                         printf("\\ ");
229
230                 printf("%s", types[json_object_get_type(item->jsobj)]);
231                 first = false;
232         }
233
234         if (prefix)
235                 printf("; ");
236         else
237                 printf("\n");
238 }
239
240 static void
241 match_cb(struct json_object *res, void *priv)
242 {
243         struct list_head *h = priv;
244         struct match_item *i = calloc(1, sizeof(*i));
245
246         if (i)
247         {
248                 i->jsobj = res;
249                 list_add_tail(&i->list, h);
250         }
251 }
252
253 static bool
254 filter_json(int opt, struct json_object *jsobj, char *expr)
255 {
256         struct jp_state *state;
257         const char *prefix = NULL;
258         struct list_head matches;
259         struct match_item *item, *tmp;
260         struct json_object *res = NULL;
261
262         state = jp_parse(expr);
263
264         if (!state || state->error)
265         {
266                 fprintf(stderr, "In expression '%s': %s\n",
267                         expr, state ? state->error : "Out of memory");
268
269                 goto out;
270         }
271
272         INIT_LIST_HEAD(&matches);
273
274         res = jp_match(state->path, jsobj, match_cb, &matches);
275         prefix = (state->path->type == T_LABEL) ? state->path->str : NULL;
276
277         switch (opt)
278         {
279         case 't':
280                 export_type(&matches, prefix);
281                 break;
282
283         default:
284                 export_value(&matches, prefix);
285                 break;
286         }
287
288         list_for_each_entry_safe(item, tmp, &matches, list)
289                 free(item);
290
291 out:
292         if (state)
293                 jp_free(state);
294
295         return !!res;
296 }
297
298 int main(int argc, char **argv)
299 {
300         int opt, rv = 0;
301         FILE *input = stdin;
302         struct json_object *jsobj = NULL;
303         const char *jserr = NULL, *source = NULL;
304
305         while ((opt = getopt(argc, argv, "i:s:e:t:q")) != -1)
306         {
307                 switch (opt)
308                 {
309                 case 'i':
310                         input = fopen(optarg, "r");
311
312                         if (!input)
313                         {
314                                 fprintf(stderr, "Failed to open %s: %s\n",
315                                                 optarg, strerror(errno));
316
317                                 rv = 125;
318                                 goto out;
319                         }
320
321                         break;
322
323                 case 's':
324                         source = optarg;
325                         break;
326
327                 case 't':
328                 case 'e':
329                         if (!jsobj)
330                         {
331                                 jsobj = parse_json(input, source, &jserr);
332
333                                 if (!jsobj)
334                                 {
335                                         fprintf(stderr, "Failed to parse json data: %s\n",
336                                                 jserr);
337
338                                         rv = 126;
339                                         goto out;
340                                 }
341                         }
342
343                         if (!filter_json(opt, jsobj, optarg))
344                                 rv = 1;
345
346                         break;
347
348                 case 'q':
349                         fclose(stderr);
350                         break;
351                 }
352         }
353
354 out:
355         if (jsobj)
356                 json_object_put(jsobj);
357
358         if (input != stdin)
359                 fclose(input);
360
361         return rv;
362 }