78fa0e4087b65fcce272020445829a4d65f74ebd
[oweals/jsonpath.git] / main.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 <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 "lexer.h"
29 #include "parser.h"
30 #include "matcher.h"
31
32 static struct json_object *
33 parse_json(FILE *fd, const char *source, const char **error)
34 {
35         int len;
36         char buf[256];
37         struct json_object *obj = NULL;
38         struct json_tokener *tok = json_tokener_new();
39         enum json_tokener_error err = json_tokener_continue;
40
41         if (!tok)
42                 return NULL;
43
44         if (source)
45         {
46                 obj = json_tokener_parse_ex(tok, source, strlen(source));
47                 err = json_tokener_get_error(tok);
48         }
49         else
50         {
51                 while ((len = fread(buf, 1, sizeof(buf), fd)) > 0)
52                 {
53                         obj = json_tokener_parse_ex(tok, buf, len);
54                         err = json_tokener_get_error(tok);
55
56                         if (!err || err != json_tokener_continue)
57                                 break;
58                 }
59         }
60
61         json_tokener_free(tok);
62
63         if (err)
64         {
65                 if (err == json_tokener_continue)
66                         err = json_tokener_error_parse_eof;
67
68                 *error = json_tokener_error_desc(err);
69                 return NULL;
70         }
71
72         return obj;
73 }
74
75 static void
76 print_string(const char *s)
77 {
78         const char *p;
79
80         printf("'");
81
82         for (p = s; *p; p++)
83         {
84                 if (*p == '\'')
85                         printf("'\"'\"'");
86                 else
87                         printf("%c", *p);
88         }
89
90         printf("'");
91 }
92
93 static void
94 export_value(struct json_object *jsobj, const char *prefix)
95 {
96         int n, len;
97         bool first = true;
98
99         if (prefix)
100         {
101                 switch (json_object_get_type(jsobj))
102                 {
103                 case json_type_object:
104                         printf("export %s=", prefix);
105                         json_object_object_foreach(jsobj, key, val)
106                         {
107                                 if (!val)
108                                         continue;
109
110                                 if (!first)
111                                         printf("\\ ");
112
113                                 print_string(key);
114                                 first = false;
115                         }
116                         printf("; ");
117                         break;
118
119                 case json_type_array:
120                         printf("export %s=", prefix);
121                         for (n = 0, len = json_object_array_length(jsobj); n < len; n++)
122                         {
123                                 if (!first)
124                                         printf("\\ ");
125
126                                 printf("%d", n);
127                                 first = false;
128                         }
129                         printf("; ");
130                         break;
131
132                 case json_type_boolean:
133                         printf("export %s=%d; ", prefix, json_object_get_boolean(jsobj));
134                         break;
135
136                 case json_type_int:
137                         printf("export %s=%d; ", prefix, json_object_get_int(jsobj));
138                         break;
139
140                 case json_type_double:
141                         printf("export %s=%f; ", prefix, json_object_get_double(jsobj));
142                         break;
143
144                 case json_type_string:
145                         printf("export %s=", prefix);
146                         print_string(json_object_get_string(jsobj));
147                         printf("; ");
148                         break;
149
150                 case json_type_null:
151                         break;
152                 }
153         }
154         else
155         {
156                 printf("%s\n", json_object_to_json_string(jsobj));
157         }
158 }
159
160 static void
161 export_type(struct json_object *jsobj, const char *prefix)
162 {
163         const char *types[] = {
164                 "null",
165                 "boolean",
166                 "double",
167                 "int",
168                 "object",
169                 "array",
170                 "string"
171         };
172
173         if (prefix)
174                 printf("export %s=%s; ", prefix, types[json_object_get_type(jsobj)]);
175         else
176                 printf("%s\n", types[json_object_get_type(jsobj)]);
177 }
178
179 static bool
180 filter_json(int opt, struct json_object *jsobj, char *expr)
181 {
182         struct jp_state *state;
183         struct json_object *res = NULL;
184         const char *prefix = NULL;
185
186         state = jp_parse(expr);
187
188         if (!state || state->error)
189         {
190                 fprintf(stderr, "In expression '%s': %s\n",
191                         expr, state ? state->error : "Out of memory");
192
193                 goto out;
194         }
195
196         res = jp_match(state->path, jsobj);
197
198         if (res)
199         {
200                 prefix = (state->path->type == T_LABEL) ? state->path->str : NULL;
201
202                 switch (opt)
203                 {
204                 case 't':
205                         export_type(res, prefix);
206                         break;
207
208                 default:
209                         export_value(res, prefix);
210                         break;
211                 }
212         }
213
214 out:
215         if (state)
216                 jp_free(state);
217
218         return !!res;
219 }
220
221 int main(int argc, char **argv)
222 {
223         int opt, rv = 0;
224         FILE *input = stdin;
225         struct json_object *jsobj = NULL;
226         const char *jserr = NULL, *source = NULL;
227
228         while ((opt = getopt(argc, argv, "i:s:e:t:q")) != -1)
229         {
230                 switch (opt)
231                 {
232                 case 'i':
233                         input = fopen(optarg, "r");
234
235                         if (!input)
236                         {
237                                 fprintf(stderr, "Failed to open %s: %s\n",
238                                                 optarg, strerror(errno));
239
240                                 rv = 125;
241                                 goto out;
242                         }
243
244                         break;
245
246                 case 's':
247                         source = optarg;
248                         break;
249
250                 case 't':
251                 case 'e':
252                         if (!jsobj)
253                         {
254                                 jsobj = parse_json(input, source, &jserr);
255
256                                 if (!jsobj)
257                                 {
258                                         fprintf(stderr, "Failed to parse json data: %s\n",
259                                                 jserr);
260
261                                         rv = 126;
262                                         goto out;
263                                 }
264                         }
265
266                         if (!filter_json(opt, jsobj, optarg))
267                                 rv = 1;
268
269                         break;
270
271                 case 'q':
272                         fclose(stderr);
273                         break;
274                 }
275         }
276
277 out:
278         if (jsobj)
279                 json_object_put(jsobj);
280
281         if (input != stdin)
282                 fclose(input);
283
284         return rv;
285 }