From fda6079b30a4f47daf95c8b93b9c86afee008f45 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 23 May 2011 22:21:27 +0200 Subject: [PATCH] add jshn --- .gitignore | 1 + CMakeLists.txt | 13 ++- jshn.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++++ sh/jshn.sh | 115 +++++++++++++++++++++++ 4 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 jshn.c create mode 100644 sh/jshn.sh diff --git a/.gitignore b/.gitignore index 268e7f6..3308ef2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ CMakeFiles *.so *.dylib install_manifest.txt +jshn diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e8f093..2729150 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,18 @@ find_library(json json) IF(EXISTS ${json}) ADD_LIBRARY(blobmsg_json SHARED blobmsg_json.c) TARGET_LINK_LIBRARIES(blobmsg_json ubox json) - INSTALL(TARGETS blobmsg_json + + ADD_EXECUTABLE(jshn jshn.c) + TARGET_LINK_LIBRARIES(jshn json) + + INSTALL(TARGETS blobmsg_json jshn LIBRARY DESTINATION lib + RUNTIME DESTINATION bin ) + + FILE(GLOB scripts sh/*.sh) + INSTALL(FILES ${scripts} + DESTINATION share/libubox + ) + ENDIF() diff --git a/jshn.c b/jshn.c new file mode 100644 index 0000000..a2d711f --- /dev/null +++ b/jshn.c @@ -0,0 +1,245 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_VARLEN 256 + +static int add_json_element(const char *key, json_object *obj); + +static int add_json_object(json_object *obj) +{ + int ret = 0; + + json_object_object_foreach(obj, key, val) { + ret = add_json_element(key, val); + if (ret) + break; + } + return ret; +} + +static int add_json_array(struct array_list *a) +{ + char seq[12]; + int i, len; + int ret; + + for (i = 0, len = array_list_length(a); i < len; i++) { + sprintf(seq, "%d", i); + ret = add_json_element(seq, array_list_get_idx(a, i)); + if (ret) + return ret; + } + + return 0; +} + +static void add_json_string(const char *str) +{ + char *ptr = (char *) str; + int len; + char *c; + + while ((c = strchr(ptr, '\'')) != NULL) { + len = c - ptr; + if (len > 0) + fwrite(ptr, len, 1, stdout); + ptr = c + 1; + c = "'\\''"; + fwrite(c, strlen(c), 1, stdout); + } + len = strlen(ptr); + if (len > 0) + fwrite(ptr, len, 1, stdout); +} + +static void write_key_string(const char *key) +{ + while (*key) { + putc(isalnum(*key) ? *key : '_', stdout); + key++; + } +} + +static int add_json_element(const char *key, json_object *obj) +{ + char *type; + + if (!obj) + return -1; + + switch (json_object_get_type(obj)) { + case json_type_object: + type = "object"; + break; + case json_type_array: + type = "array"; + break; + case json_type_string: + type = "string"; + break; + case json_type_boolean: + type = "boolean"; + break; + case json_type_int: + type = "int"; + break; + default: + return -1; + } + + fprintf(stdout, "json_add_%s '", type); + write_key_string(key); + + switch (json_object_get_type(obj)) { + case json_type_object: + fprintf(stdout, "';\n"); + add_json_object(obj); + fprintf(stdout, "json_close_object;\n"); + break; + case json_type_array: + fprintf(stdout, "';\n"); + add_json_array(json_object_get_array(obj)); + fprintf(stdout, "json_close_array;\n"); + break; + case json_type_string: + fprintf(stdout, "' '"); + add_json_string(json_object_get_string(obj)); + fprintf(stdout, "';\n"); + break; + case json_type_boolean: + fprintf(stdout, "' %d;\n", json_object_get_boolean(obj)); + break; + case json_type_int: + fprintf(stdout, "' %d;\n", json_object_get_int(obj)); + break; + default: + return -1; + } + + return 0; +} + +static int jshn_parse(const char *str) +{ + json_object *obj; + + obj = json_tokener_parse(str); + if (is_error(obj) || json_object_get_type(obj) != json_type_object) { + fprintf(stderr, "Failed to parse message data\n"); + return 1; + } + fprintf(stdout, "json_init;\n"); + add_json_object(obj); + fflush(stdout); + + return 0; +} + +static char *get_keys(const char *prefix) +{ + char *keys; + + keys = alloca(strlen(prefix) + sizeof("KEYS_") + 1); + sprintf(keys, "KEYS_%s", prefix); + return getenv(keys); +} + +static void get_var(const char *prefix, const char *name, char **var, char **type) +{ + char *tmpname; + + tmpname = alloca(strlen(prefix) + 1 + strlen(name) + 1 + sizeof("TYPE_")); + sprintf(tmpname, "TYPE_%s_%s", prefix, name); + *var = getenv(tmpname + 5); + *type = getenv(tmpname); +} + +static json_object *jshn_add_objects(json_object *obj, const char *prefix, bool array); + +static void jshn_add_object_var(json_object *obj, bool array, const char *prefix, const char *name) +{ + json_object *new; + char *var, *type; + + get_var(prefix, name, &var, &type); + if (!var || !type) + return; + + if (!strcmp(type, "array")) { + new = json_object_new_array(); + jshn_add_objects(new, var, true); + } else if (!strcmp(type, "object")) { + new = json_object_new_object(); + jshn_add_objects(new, var, false); + } else if (!strcmp(type, "string")) { + new = json_object_new_string(var); + } else if (!strcmp(type, "int")) { + new = json_object_new_int(atoi(var)); + } else if (!strcmp(type, "boolean")) { + new = json_object_new_boolean(!!atoi(var)); + } else { + return; + } + + if (array) + json_object_array_add(obj, new); + else + json_object_object_add(obj, name, new); +} + +static json_object *jshn_add_objects(json_object *obj, const char *prefix, bool array) +{ + char *keys, *key, *brk; + + keys = get_keys(prefix); + if (!keys || !obj) + goto out; + + for (key = strtok_r(keys, " ", &brk); key; + key = strtok_r(NULL, " ", &brk)) { + jshn_add_object_var(obj, array, prefix, key); + } + +out: + return obj; +} + +static int jshn_format(void) +{ + json_object *obj; + + obj = json_object_new_object(); + jshn_add_objects(obj, "JSON_VAR", false); + fprintf(stdout, "%s\n", json_object_to_json_string(obj)); + json_object_put(obj); + return 0; +} + +static int usage(const char *progname) +{ + fprintf(stderr, "Usage: %s -r |-w\n", progname); + return 2; +} + +int main(int argc, char **argv) +{ + int ch; + + while ((ch = getopt(argc, argv, "r:w")) != -1) { + switch(ch) { + case 'r': + return jshn_parse(optarg); + case 'w': + return jshn_format(); + default: + return usage(argv[0]); + } + } + return usage(argv[0]); +} diff --git a/sh/jshn.sh b/sh/jshn.sh new file mode 100644 index 0000000..923f2b3 --- /dev/null +++ b/sh/jshn.sh @@ -0,0 +1,115 @@ +# functions for parsing and generating json + +append() { + local var="$1" + local value="$2" + local sep="${3:- }" + + eval "export ${NO_EXPORT:+-n} -- \"$var=\${$var:+\${$var}\${value:+\$sep}}\$value\"" +} + +json_init() { + [ -n "$JSON_UNSET" ] && eval "unset $JSON_UNSET" + export -- JSON_SEQ=0 JSON_STACK= JSON_CUR="JSON_VAR" JSON_UNSET= +} + +json_add_generic() { + local type="$1" + local var="$2" + local val="$3" + local cur="${4:-$JSON_CUR}" + + export ${NO_EXPORT:+-n} -- "${cur}_$var=$val" + export ${NO_EXPORT:+-n} -- "TYPE_${cur}_$var=$type" + append JSON_UNSET "${cur}_$var TYPE_${cur}_$var" + append "KEYS_${cur}" "$var" +} + +json_add_table() { + JSON_SEQ=$(($JSON_SEQ + 1)) + append JSON_STACK "$JSON_CUR" + local table="JSON_TABLE$JSON_SEQ" + export ${NO_EXPORT:+-n} -- "UP_$table=$JSON_CUR" + JSON_CUR="$table" +} + +json_add_object() { + local cur="$JSON_CUR" + json_add_table + json_add_generic object "$1" "$JSON_CUR" "$cur" +} + +json_close_object() { + local oldstack="$JSON_STACK" + export "KEYS_${JSON_CUR}" + JSON_CUR="${JSON_STACK##* }" + JSON_STACK="${JSON_STACK% *}" + [[ "$oldstack" == "$JSON_STACK" ]] && JSON_STACK= +} + +json_add_array() { + local cur="$JSON_CUR" + json_add_table + json_add_generic array "$1" "$JSON_CUR" "$cur" +} + +json_close_array() { + json_close_object +} + +json_add_string() { + json_add_generic string "$1" "$2" +} + +json_add_int() { + json_add_generic int "$1" "$2" +} + +json_add_boolean() { + json_add_generic boolean "$1" "$2" +} + +# functions read access to json variables + +json_load() { + eval `jshn -r "$1"` +} + +json_dump() { + jshn -w +} + +json_get_type() { + local dest="$1" + local var="$2" + eval "export ${NO_EXPORT:+-n} -- \"$dest=\${TYPE_${JSON_CUR}_$var}\"" +} + +json_get_var() { + local dest="$1" + local var="$2" + eval "export ${NO_EXPORT:+-n} -- \"$dest=\${${JSON_CUR}_$var}\"" +} + +json_select() { + local target="$1" + local type + + [ -z "$1" ] && { + JSON_CUR="JSON_VAR" + return + } + [[ "$1" == ".." ]] && { + eval "JSON_CUR=\"\${UP_$JSON_CUR}\"" + return; + } + json_get_type type "$target" + case "$type" in + object|array) + json_get_var JSON_CUR "$target" + ;; + *) + echo "WARNING: Variable '$target' does not exist or is not an array/object" + ;; + esac +}