1 /* 2 * Copyright (C) 2011-2013 Felix Fietkau <nbd@openwrt.org> 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 #include <json.h> 17 #include <string.h> 18 #include <stdlib.h> 19 #include <stdio.h> 20 #include <stdbool.h> 21 #include <ctype.h> 22 #include <getopt.h> 23 #include <sys/stat.h> 24 #include <fcntl.h> 25 #include <inttypes.h> 26 #include "list.h" 27 28 #include "avl.h" 29 #include "blob.h" 30 #include "blobmsg_json.h" 31 32 #define MAX_VARLEN 256 33 34 static struct avl_tree env_vars; 35 static struct blob_buf b = { 0 }; 36 37 static const char *var_prefix = ""; 38 static int var_prefix_len = 0; 39 40 static int add_json_element(const char *key, json_object *obj); 41 42 struct env_var { 43 struct avl_node avl; 44 char *val; 45 }; 46 47 static int add_json_object(json_object *obj) 48 { 49 int ret = 0; 50 51 json_object_object_foreach(obj, key, val) { 52 ret = add_json_element(key, val); 53 if (ret) 54 break; 55 } 56 return ret; 57 } 58 59 static int add_json_array(struct array_list *a) 60 { 61 char seq[12]; 62 int i, len; 63 int ret; 64 65 for (i = 0, len = array_list_length(a); i < len; i++) { 66 snprintf(seq, sizeof(seq), "%d", i); 67 ret = add_json_element(seq, array_list_get_idx(a, i)); 68 if (ret) 69 return ret; 70 } 71 72 return 0; 73 } 74 75 static void add_json_string(const char *str) 76 { 77 char *ptr = (char *) str; 78 int len; 79 char *c; 80 81 while ((c = strchr(ptr, '\'')) != NULL) { 82 len = c - ptr; 83 if (len > 0) 84 fwrite(ptr, len, 1, stdout); 85 ptr = c + 1; 86 c = "'\\''"; 87 fwrite(c, strlen(c), 1, stdout); 88 } 89 len = strlen(ptr); 90 if (len > 0) 91 fwrite(ptr, len, 1, stdout); 92 } 93 94 static void write_key_string(const char *key) 95 { 96 while (*key) { 97 putc(isalnum(*key) ? *key : '_', stdout); 98 key++; 99 } 100 } 101 102 static int add_json_element(const char *key, json_object *obj) 103 { 104 char *type; 105 106 switch (json_object_get_type(obj)) { 107 case json_type_object: 108 type = "object"; 109 break; 110 case json_type_array: 111 type = "array"; 112 break; 113 case json_type_string: 114 type = "string"; 115 break; 116 case json_type_boolean: 117 type = "boolean"; 118 break; 119 case json_type_int: 120 type = "int"; 121 break; 122 case json_type_double: 123 type = "double"; 124 break; 125 case json_type_null: 126 type = "null"; 127 break; 128 default: 129 return -1; 130 } 131 132 fprintf(stdout, "json_add_%s '", type); 133 write_key_string(key); 134 135 switch (json_object_get_type(obj)) { 136 case json_type_object: 137 fprintf(stdout, "';\n"); 138 add_json_object(obj); 139 fprintf(stdout, "json_close_object;\n"); 140 break; 141 case json_type_array: 142 fprintf(stdout, "';\n"); 143 add_json_array(json_object_get_array(obj)); 144 fprintf(stdout, "json_close_array;\n"); 145 break; 146 case json_type_string: 147 fprintf(stdout, "' '"); 148 add_json_string(json_object_get_string(obj)); 149 fprintf(stdout, "';\n"); 150 break; 151 case json_type_boolean: 152 fprintf(stdout, "' %d;\n", json_object_get_boolean(obj)); 153 break; 154 case json_type_int: 155 fprintf(stdout, "' %"PRId64";\n", json_object_get_int64(obj)); 156 break; 157 case json_type_double: 158 fprintf(stdout, "' %lf;\n", json_object_get_double(obj)); 159 break; 160 case json_type_null: 161 fprintf(stdout, "';\n"); 162 break; 163 default: 164 return -1; 165 } 166 167 return 0; 168 } 169 170 static int jshn_parse(const char *str) 171 { 172 json_object *obj; 173 174 obj = json_tokener_parse(str); 175 if (!obj || json_object_get_type(obj) != json_type_object) { 176 if (obj) 177 json_object_put(obj); 178 fprintf(stderr, "Failed to parse message data\n"); 179 return 1; 180 } 181 fprintf(stdout, "json_init;\n"); 182 add_json_object(obj); 183 fflush(stdout); 184 json_object_put(obj); 185 186 return 0; 187 } 188 189 static char *getenv_avl(const char *key) 190 { 191 struct env_var *var = avl_find_element(&env_vars, key, var, avl); 192 return var ? var->val : NULL; 193 } 194 195 static char *get_keys(const char *prefix) 196 { 197 char *keys; 198 size_t len = var_prefix_len + strlen(prefix) + sizeof("K_") + 1; 199 200 keys = alloca(len); 201 snprintf(keys, len, "%sK_%s", var_prefix, prefix); 202 return getenv_avl(keys); 203 } 204 205 static void get_var(const char *prefix, const char **name, char **var, char **type) 206 { 207 char *tmpname, *varname; 208 size_t len = var_prefix_len + strlen(prefix) + 1 + strlen(*name) + 1 + sizeof("T_"); 209 210 tmpname = alloca(len); 211 212 snprintf(tmpname, len, "%s%s_%s", var_prefix, prefix, *name); 213 *var = getenv_avl(tmpname); 214 215 snprintf(tmpname, len, "%sT_%s_%s", var_prefix, prefix, *name); 216 *type = getenv_avl(tmpname); 217 218 snprintf(tmpname, len, "%sN_%s_%s", var_prefix, prefix, *name); 219 varname = getenv_avl(tmpname); 220 if (varname) 221 *name = varname; 222 } 223 224 static json_object *jshn_add_objects(json_object *obj, const char *prefix, bool array); 225 226 static void jshn_add_object_var(json_object *obj, bool array, const char *prefix, const char *name) 227 { 228 json_object *new; 229 char *var, *type; 230 231 get_var(prefix, &name, &var, &type); 232 if (!var || !type) 233 return; 234 235 if (!strcmp(type, "array")) { 236 new = json_object_new_array(); 237 jshn_add_objects(new, var, true); 238 } else if (!strcmp(type, "object")) { 239 new = json_object_new_object(); 240 jshn_add_objects(new, var, false); 241 } else if (!strcmp(type, "string")) { 242 new = json_object_new_string(var); 243 } else if (!strcmp(type, "int")) { 244 new = json_object_new_int64(atoll(var)); 245 } else if (!strcmp(type, "double")) { 246 new = json_object_new_double(strtod(var, NULL)); 247 } else if (!strcmp(type, "boolean")) { 248 new = json_object_new_boolean(!!atoi(var)); 249 } else if (!strcmp(type, "null")) { 250 new = NULL; 251 } else { 252 return; 253 } 254 255 if (array) 256 json_object_array_add(obj, new); 257 else 258 json_object_object_add(obj, name, new); 259 } 260 261 static json_object *jshn_add_objects(json_object *obj, const char *prefix, bool array) 262 { 263 char *keys, *key, *brk; 264 265 keys = get_keys(prefix); 266 if (!keys || !obj) 267 goto out; 268 269 for (key = strtok_r(keys, " ", &brk); key; 270 key = strtok_r(NULL, " ", &brk)) { 271 jshn_add_object_var(obj, array, prefix, key); 272 } 273 274 out: 275 return obj; 276 } 277 278 static int jshn_format(bool no_newline, bool indent, FILE *stream) 279 { 280 json_object *obj; 281 const char *output; 282 char *blobmsg_output = NULL; 283 int ret = -1; 284 285 if (!(obj = json_object_new_object())) 286 return -1; 287 288 jshn_add_objects(obj, "J_V", false); 289 if (!(output = json_object_to_json_string(obj))) 290 goto out; 291 292 if (indent) { 293 blob_buf_init(&b, 0); 294 if (!blobmsg_add_json_from_string(&b, output)) 295 goto out; 296 if (!(blobmsg_output = blobmsg_format_json_indent(b.head, 1, 0))) 297 goto out; 298 output = blobmsg_output; 299 } 300 fprintf(stream, "%s%s", output, no_newline ? "" : "\n"); 301 free(blobmsg_output); 302 ret = 0; 303 304 out: 305 json_object_put(obj); 306 return ret; 307 } 308 309 static int usage(const char *progname) 310 { 311 fprintf(stderr, "Usage: %s [-n] [-i] -r <message>|-R <file>|-o <file>|-p <prefix>|-w\n", progname); 312 return 2; 313 } 314 315 static int avl_strcmp_var(const void *k1, const void *k2, void *ptr) 316 { 317 const char *s1 = k1; 318 const char *s2 = k2; 319 char c1, c2; 320 321 while (*s1 && *s1 == *s2) { 322 s1++; 323 s2++; 324 } 325 326 c1 = *s1; 327 c2 = *s2; 328 if (c1 == '=') 329 c1 = 0; 330 if (c2 == '=') 331 c2 = 0; 332 333 return c1 - c2; 334 } 335 336 static int jshn_parse_file(const char *path) 337 { 338 struct stat sb; 339 int ret = 0; 340 char *fbuf; 341 int fd; 342 343 if ((fd = open(path, O_RDONLY)) == -1) { 344 fprintf(stderr, "Error opening %s\n", path); 345 return 3; 346 } 347 348 if (fstat(fd, &sb) == -1) { 349 fprintf(stderr, "Error getting size of %s\n", path); 350 close(fd); 351 return 3; 352 } 353 354 if (!(fbuf = calloc(1, sb.st_size+1))) { 355 fprintf(stderr, "Error allocating memory for %s\n", path); 356 close(fd); 357 return 3; 358 } 359 360 if (read(fd, fbuf, sb.st_size) != sb.st_size) { 361 fprintf(stderr, "Error reading %s\n", path); 362 free(fbuf); 363 close(fd); 364 return 3; 365 } 366 367 ret = jshn_parse(fbuf); 368 free(fbuf); 369 close(fd); 370 371 return ret; 372 } 373 374 static int jshn_format_file(const char *path, bool no_newline, bool indent) 375 { 376 FILE *fp = NULL; 377 int ret = 0; 378 379 fp = fopen(path, "w"); 380 if (!fp) { 381 fprintf(stderr, "Error opening %s\n", path); 382 return 3; 383 } 384 385 ret = jshn_format(no_newline, indent, fp); 386 fclose(fp); 387 388 return ret; 389 } 390 391 int main(int argc, char **argv) 392 { 393 extern char **environ; 394 bool no_newline = false; 395 bool indent = false; 396 struct env_var *vars; 397 int i; 398 int ret = 0; 399 int ch; 400 401 avl_init(&env_vars, avl_strcmp_var, false, NULL); 402 for (i = 0; environ[i]; i++); 403 404 vars = calloc(i, sizeof(*vars)); 405 if (!vars) { 406 fprintf(stderr, "%m\n"); 407 return -1; 408 } 409 for (i = 0; environ[i]; i++) { 410 char *c; 411 412 vars[i].avl.key = environ[i]; 413 c = strchr(environ[i], '='); 414 if (!c) 415 continue; 416 417 vars[i].val = c + 1; 418 avl_insert(&env_vars, &vars[i].avl); 419 } 420 421 while ((ch = getopt(argc, argv, "p:nir:R:o:w")) != -1) { 422 switch(ch) { 423 case 'p': 424 var_prefix = optarg; 425 var_prefix_len = strlen(var_prefix); 426 break; 427 case 'r': 428 ret = jshn_parse(optarg); 429 goto exit; 430 case 'R': 431 ret = jshn_parse_file(optarg); 432 goto exit; 433 case 'w': 434 ret = jshn_format(no_newline, indent, stdout); 435 goto exit; 436 case 'o': 437 ret = jshn_format_file(optarg, no_newline, indent); 438 goto exit; 439 case 'n': 440 no_newline = true; 441 break; 442 case 'i': 443 indent = true; 444 break; 445 default: 446 free(vars); 447 return usage(argv[0]); 448 } 449 } 450 451 free(vars); 452 return usage(argv[0]); 453 454 exit: 455 free(vars); 456 return ret; 457 } 458
This page was automatically generated by LXR 0.3.1. • OpenWrt