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