add jshn (JSON SHell Notation), a small utility and shell library for parsing and...
[openwrt/svn-archive/archive.git] / package / jshn / src / jshn.c
1 #include <json/json.h>
2 #include <libubox/list.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <stdbool.h>
7 #include <ctype.h>
8 #include <getopt.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(void)
214 {
215 json_object *obj;
216
217 obj = json_object_new_object();
218 jshn_add_objects(obj, "JSON_VAR", false);
219 fprintf(stdout, "%s\n", json_object_to_json_string(obj));
220 json_object_put(obj);
221 return 0;
222 }
223
224 static int usage(const char *progname)
225 {
226 fprintf(stderr, "Usage: %s -r <message>|-w\n", progname);
227 return 2;
228 }
229
230 int main(int argc, char **argv)
231 {
232 int ch;
233
234 while ((ch = getopt(argc, argv, "r:w")) != -1) {
235 switch(ch) {
236 case 'r':
237 return jshn_parse(optarg);
238 case 'w':
239 return jshn_format();
240 default:
241 return usage(argv[0]);
242 }
243 }
244 return usage(argv[0]);
245 }