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