fix a bug in blobmsg_parse
[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;
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
163 static json_object *jshn_add_objects(json_object *obj, const char *prefix, bool array);
164
165 static void jshn_add_object_var(json_object *obj, bool array, const char *prefix, const char *name)
166 {
167         json_object *new;
168         char *var, *type;
169
170         get_var(prefix, name, &var, &type);
171         if (!var || !type)
172                 return;
173
174         if (!strcmp(type, "array")) {
175                 new = json_object_new_array();
176                 jshn_add_objects(new, var, true);
177         } else if (!strcmp(type, "object")) {
178                 new = json_object_new_object();
179                 jshn_add_objects(new, var, false);
180         } else if (!strcmp(type, "string")) {
181                 new = json_object_new_string(var);
182         } else if (!strcmp(type, "int")) {
183                 new = json_object_new_int(atoi(var));
184         } else if (!strcmp(type, "boolean")) {
185                 new = json_object_new_boolean(!!atoi(var));
186         } else {
187                 return;
188         }
189
190         if (array)
191                 json_object_array_add(obj, new);
192         else
193                 json_object_object_add(obj, name, new);
194 }
195
196 static json_object *jshn_add_objects(json_object *obj, const char *prefix, bool array)
197 {
198         char *keys, *key, *brk;
199
200         keys = get_keys(prefix);
201         if (!keys || !obj)
202                 goto out;
203
204         for (key = strtok_r(keys, " ", &brk); key;
205              key = strtok_r(NULL, " ", &brk)) {
206                 jshn_add_object_var(obj, array, prefix, key);
207         }
208
209 out:
210         return obj;
211 }
212
213 static int jshn_format(bool no_newline)
214 {
215         json_object *obj;
216
217         obj = json_object_new_object();
218         jshn_add_objects(obj, "JSON_VAR", false);
219         fprintf(stdout, "%s%s", json_object_to_json_string(obj),
220                 no_newline ? "" : "\n");
221         json_object_put(obj);
222         return 0;
223 }
224
225 static int usage(const char *progname)
226 {
227         fprintf(stderr, "Usage: %s [-n] -r <message>|-w\n", progname);
228         return 2;
229 }
230
231 int main(int argc, char **argv)
232 {
233         bool no_newline = false;
234         int ch;
235
236         while ((ch = getopt(argc, argv, "nr:w")) != -1) {
237                 switch(ch) {
238                 case 'r':
239                         return jshn_parse(optarg);
240                 case 'w':
241                         return jshn_format(no_newline);
242                 case 'n':
243                         no_newline = true;
244                         break;
245                 default:
246                         return usage(argv[0]);
247                 }
248         }
249         return usage(argv[0]);
250 }