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