add declarations for lua{open,close}_uloop to avoid warnings
[project/libubox.git] / jshn.c
1 #include <json/json.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <stdbool.h>
6 #include <ctype.h>
7 #include <getopt.h>
8 #include "list.h"
9
10 #define MAX_VARLEN 256
11
12 static int add_json_element(const char *key, json_object *obj);
13
14 static int add_json_object(json_object *obj)
15 {
16 int ret = 0;
17
18 json_object_object_foreach(obj, key, val) {
19 ret = add_json_element(key, val);
20 if (ret)
21 break;
22 }
23 return ret;
24 }
25
26 static int add_json_array(struct array_list *a)
27 {
28 char seq[12];
29 int i, len;
30 int ret;
31
32 for (i = 0, len = array_list_length(a); i < len; i++) {
33 sprintf(seq, "%d", i);
34 ret = add_json_element(seq, array_list_get_idx(a, i));
35 if (ret)
36 return ret;
37 }
38
39 return 0;
40 }
41
42 static void add_json_string(const char *str)
43 {
44 char *ptr = (char *) str;
45 int len;
46 char *c;
47
48 while ((c = strchr(ptr, '\'')) != NULL) {
49 len = c - ptr;
50 if (len > 0)
51 fwrite(ptr, len, 1, stdout);
52 ptr = c + 1;
53 c = "'\\''";
54 fwrite(c, strlen(c), 1, stdout);
55 }
56 len = strlen(ptr);
57 if (len > 0)
58 fwrite(ptr, len, 1, stdout);
59 }
60
61 static void write_key_string(const char *key)
62 {
63 while (*key) {
64 putc(isalnum(*key) ? *key : '_', stdout);
65 key++;
66 }
67 }
68
69 static int add_json_element(const char *key, json_object *obj)
70 {
71 char *type;
72
73 if (!obj)
74 return -1;
75
76 switch (json_object_get_type(obj)) {
77 case json_type_object:
78 type = "object";
79 break;
80 case json_type_array:
81 type = "array";
82 break;
83 case json_type_string:
84 type = "string";
85 break;
86 case json_type_boolean:
87 type = "boolean";
88 break;
89 case json_type_int:
90 type = "int";
91 break;
92 default:
93 return -1;
94 }
95
96 fprintf(stdout, "json_add_%s '", type);
97 write_key_string(key);
98
99 switch (json_object_get_type(obj)) {
100 case json_type_object:
101 fprintf(stdout, "';\n");
102 add_json_object(obj);
103 fprintf(stdout, "json_close_object;\n");
104 break;
105 case json_type_array:
106 fprintf(stdout, "';\n");
107 add_json_array(json_object_get_array(obj));
108 fprintf(stdout, "json_close_array;\n");
109 break;
110 case json_type_string:
111 fprintf(stdout, "' '");
112 add_json_string(json_object_get_string(obj));
113 fprintf(stdout, "';\n");
114 break;
115 case json_type_boolean:
116 fprintf(stdout, "' %d;\n", json_object_get_boolean(obj));
117 break;
118 case json_type_int:
119 fprintf(stdout, "' %d;\n", json_object_get_int(obj));
120 break;
121 default:
122 return -1;
123 }
124
125 return 0;
126 }
127
128 static int jshn_parse(const char *str)
129 {
130 json_object *obj;
131
132 obj = json_tokener_parse(str);
133 if (is_error(obj) || json_object_get_type(obj) != json_type_object) {
134 fprintf(stderr, "Failed to parse message data\n");
135 return 1;
136 }
137 fprintf(stdout, "json_init;\n");
138 add_json_object(obj);
139 fflush(stdout);
140
141 return 0;
142 }
143
144 static char *get_keys(const char *prefix)
145 {
146 char *keys;
147
148 keys = alloca(strlen(prefix) + sizeof("KEYS_") + 1);
149 sprintf(keys, "KEYS_%s", prefix);
150 return getenv(keys);
151 }
152
153 static void get_var(const char *prefix, const char **name, char **var, char **type)
154 {
155 char *tmpname, *varname;
156
157 tmpname = alloca(strlen(prefix) + 1 + strlen(*name) + 1 + sizeof("TYPE_"));
158 sprintf(tmpname, "TYPE_%s_%s", prefix, *name);
159 *var = getenv(tmpname + 5);
160 *type = getenv(tmpname);
161
162 memcpy(tmpname, "NAME", 4);
163 varname = getenv(tmpname);
164 if (varname)
165 *name = varname;
166 }
167
168 static json_object *jshn_add_objects(json_object *obj, const char *prefix, bool array);
169
170 static void jshn_add_object_var(json_object *obj, bool array, const char *prefix, const char *name)
171 {
172 json_object *new;
173 char *var, *type;
174
175 get_var(prefix, &name, &var, &type);
176 if (!var || !type)
177 return;
178
179 if (!strcmp(type, "array")) {
180 new = json_object_new_array();
181 jshn_add_objects(new, var, true);
182 } else if (!strcmp(type, "object")) {
183 new = json_object_new_object();
184 jshn_add_objects(new, var, false);
185 } else if (!strcmp(type, "string")) {
186 new = json_object_new_string(var);
187 } else if (!strcmp(type, "int")) {
188 new = json_object_new_int(atoi(var));
189 } else if (!strcmp(type, "boolean")) {
190 new = json_object_new_boolean(!!atoi(var));
191 } else {
192 return;
193 }
194
195 if (array)
196 json_object_array_add(obj, new);
197 else
198 json_object_object_add(obj, name, new);
199 }
200
201 static json_object *jshn_add_objects(json_object *obj, const char *prefix, bool array)
202 {
203 char *keys, *key, *brk;
204
205 keys = get_keys(prefix);
206 if (!keys || !obj)
207 goto out;
208
209 for (key = strtok_r(keys, " ", &brk); key;
210 key = strtok_r(NULL, " ", &brk)) {
211 jshn_add_object_var(obj, array, prefix, key);
212 }
213
214 out:
215 return obj;
216 }
217
218 static int jshn_format(bool no_newline)
219 {
220 json_object *obj;
221
222 obj = json_object_new_object();
223 jshn_add_objects(obj, "JSON_VAR", false);
224 fprintf(stdout, "%s%s", json_object_to_json_string(obj),
225 no_newline ? "" : "\n");
226 json_object_put(obj);
227 return 0;
228 }
229
230 static int usage(const char *progname)
231 {
232 fprintf(stderr, "Usage: %s [-n] -r <message>|-w\n", progname);
233 return 2;
234 }
235
236 int main(int argc, char **argv)
237 {
238 bool no_newline = false;
239 int ch;
240
241 while ((ch = getopt(argc, argv, "nr:w")) != -1) {
242 switch(ch) {
243 case 'r':
244 return jshn_parse(optarg);
245 case 'w':
246 return jshn_format(no_newline);
247 case 'n':
248 no_newline = true;
249 break;
250 default:
251 return usage(argv[0]);
252 }
253 }
254 return usage(argv[0]);
255 }