utils: move ARRAY_SIZE from uloop to utils.h
[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 }