X-Git-Url: https://git.librecmc.org/?p=oweals%2Fjsonpath.git;a=blobdiff_plain;f=main.c;h=ebd52c0cecf0cbb5542cb52ce20a43ec9d6bd150;hp=7a19091900573f656617c5ea699afac7c45eff7a;hb=f3830138661374ca10fe6a0b6f2f4b949dea3e5c;hpb=ba3e89199b78c33fc5b0dce6a4456096c71c2e19 diff --git a/main.c b/main.c index 7a19091..ebd52c0 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Jo-Philipp Wich + * Copyright (C) 2013-2014 Jo-Philipp Wich * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,6 +15,7 @@ */ #include +#include #include #include @@ -24,12 +25,20 @@ #include #endif +#include + #include "lexer.h" #include "parser.h" #include "matcher.h" + +struct match_item { + struct json_object *jsobj; + struct list_head list; +}; + static struct json_object * -parse_json(FILE *fd) +parse_json(FILE *fd, const char *source, const char **error) { int len; char buf[256]; @@ -40,18 +49,35 @@ parse_json(FILE *fd) if (!tok) return NULL; - while ((len = fread(buf, 1, sizeof(buf), fd)) > 0) + if (source) { - obj = json_tokener_parse_ex(tok, buf, len); + obj = json_tokener_parse_ex(tok, source, strlen(source)); err = json_tokener_get_error(tok); + } + else + { + while ((len = fread(buf, 1, sizeof(buf), fd)) > 0) + { + obj = json_tokener_parse_ex(tok, buf, len); + err = json_tokener_get_error(tok); - if (!err || err != json_tokener_continue) - break; + if (!err || err != json_tokener_continue) + break; + } } json_tokener_free(tok); - return err ? NULL : obj; + if (err) + { + if (err == json_tokener_continue) + err = json_tokener_error_parse_eof; + + *error = json_tokener_error_desc(err); + return NULL; + } + + return obj; } static void @@ -73,106 +99,211 @@ print_string(const char *s) } static void -export_json(struct json_object *jsobj, char *expr) +export_value(struct list_head *matches, const char *prefix) { - bool first; - struct jp_opcode *tree; - struct json_object *res; - const char *error, *prefix; + int n, len; + bool first = true; + struct match_item *item; - tree = jp_parse(expr, &error); - - if (error) - { - fprintf(stderr, "In expression '%s': %s\n", expr, error); + if (list_empty(matches)) return; - } - res = jp_match(tree, jsobj); - - if (tree->type == T_LABEL) + if (prefix) { - prefix = tree->str; + printf("export %s=", prefix); - switch (json_object_get_type(res)) + list_for_each_entry(item, matches, list) { - case json_type_object: - printf("export %s_TYPE=object; ", prefix); - - first = true; - printf("export %s_KEYS=", prefix); - json_object_object_foreach(res, key, val) + switch (json_object_get_type(item->jsobj)) { - if (!val) - continue; + case json_type_object: + ; /* a label can only be part of a statement */ + json_object_object_foreach(item->jsobj, key, val) + { + if (!val) + continue; + if (!first) + printf("\\ "); + + print_string(key); + first = false; + } + break; + + case json_type_array: + for (n = 0, len = json_object_array_length(item->jsobj); + n < len; n++) + { + if (!first) + printf("\\ "); + + printf("%d", n); + first = false; + } + break; + + case json_type_boolean: if (!first) printf("\\ "); + printf("%d", json_object_get_boolean(item->jsobj)); + break; - print_string(key); - first = false; - } - printf("; "); + case json_type_int: + if (!first) + printf("\\ "); + printf("%d", json_object_get_int(item->jsobj)); + break; - //printf("export %s=", prefix); - //print_string(json_object_to_json_string(res)); - //printf("; "); + case json_type_double: + if (!first) + printf("\\ "); + printf("%f", json_object_get_double(item->jsobj)); + break; - break; + case json_type_string: + if (!first) + printf("\\ "); + print_string(json_object_get_string(item->jsobj)); + break; - case json_type_array: - printf("export %s_TYPE=array; ", prefix); - printf("export %s_LENGTH=%d; ", - prefix, json_object_array_length(res)); + case json_type_null: + break; + } - //printf("export %s=", prefix); - //print_string(json_object_to_json_string(res)); - //printf("; "); - break; + first = false; + } - case json_type_boolean: - printf("export %s_TYPE=bool; ", prefix); - printf("export %s=%d; ", prefix, json_object_get_boolean(res)); - break; + printf("; "); + } + else + { + list_for_each_entry(item, matches, list) + { + switch (json_object_get_type(item->jsobj)) + { + case json_type_object: + case json_type_array: + case json_type_boolean: + case json_type_int: + case json_type_double: + printf("%s\n", json_object_to_json_string(item->jsobj)); + break; + + case json_type_string: + printf("%s\n", json_object_get_string(item->jsobj)); + break; + + case json_type_null: + break; + } + } + } +} - case json_type_int: - printf("export %s_TYPE=int; ", prefix); - printf("export %s=%d; ", prefix, json_object_get_int(res)); - break; +static void +export_type(struct list_head *matches, const char *prefix) +{ + bool first = true; + struct match_item *item; + const char *types[] = { + "null", + "boolean", + "double", + "int", + "object", + "array", + "string" + }; + + if (list_empty(matches)) + return; - case json_type_double: - printf("export %s_TYPE=double; ", prefix); - printf("export %s=%f; ", prefix, json_object_get_double(res)); - break; + if (prefix) + printf("export %s=", prefix); - case json_type_string: - printf("export %s_TYPE=string; ", prefix); - printf("export %s=", prefix); - print_string(json_object_get_string(res)); - printf("; "); - break; + list_for_each_entry(item, matches, list) + { + if (!first) + printf("\\ "); - case json_type_null: - printf("unset %s %s_TYPE %s_LENGTH %s_KEYS; ", - prefix, prefix, prefix, prefix); - break; - } + printf("%s", types[json_object_get_type(item->jsobj)]); + first = false; } + + if (prefix) + printf("; "); else + printf("\n"); +} + +static void +match_cb(struct json_object *res, void *priv) +{ + struct list_head *h = priv; + struct match_item *i = calloc(1, sizeof(*i)); + + if (i) + { + i->jsobj = res; + list_add_tail(&i->list, h); + } +} + +static bool +filter_json(int opt, struct json_object *jsobj, char *expr) +{ + struct jp_state *state; + const char *prefix = NULL; + struct list_head matches; + struct match_item *item, *tmp; + struct json_object *res = NULL; + + state = jp_parse(expr); + + if (!state || state->error) { - printf("%s\n", json_object_to_json_string(res)); + fprintf(stderr, "Syntax error near {%s}: %s\n", + state ? expr + state->erroff : expr, + state ? state->error : "Out of memory"); + + goto out; } - jp_free(); + INIT_LIST_HEAD(&matches); + + res = jp_match(state->path, jsobj, match_cb, &matches); + prefix = (state->path->type == T_LABEL) ? state->path->str : NULL; + + switch (opt) + { + case 't': + export_type(&matches, prefix); + break; + + default: + export_value(&matches, prefix); + break; + } + + list_for_each_entry_safe(item, tmp, &matches, list) + free(item); + +out: + if (state) + jp_free(state); + + return !!res; } int main(int argc, char **argv) { - int opt; + int opt, rv = 0; FILE *input = stdin; struct json_object *jsobj = NULL; + const char *jserr = NULL, *source = NULL; - while ((opt = getopt(argc, argv, "i:e:")) != -1) + while ((opt = getopt(argc, argv, "i:s:e:t:q")) != -1) { switch (opt) { @@ -184,32 +315,49 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to open %s: %s\n", optarg, strerror(errno)); - exit(1); + rv = 125; + goto out; } break; + case 's': + source = optarg; + break; + + case 't': case 'e': if (!jsobj) { - jsobj = parse_json(input); + jsobj = parse_json(input, source, &jserr); if (!jsobj) { - fprintf(stderr, "Failed to parse json data\n"); - exit(2); + fprintf(stderr, "Failed to parse json data: %s\n", + jserr); + + rv = 126; + goto out; } } - export_json(jsobj, optarg); + if (!filter_json(opt, jsobj, optarg)) + rv = 1; + + break; + + case 'q': + fclose(stderr); break; } } +out: if (jsobj) json_object_put(jsobj); - fclose(input); + if (input != stdin) + fclose(input); - return 0; + return rv; }