cli: additional flags and cleanup
[oweals/jsonpath.git] / main.c
diff --git a/main.c b/main.c
index 05e445c..7d530fa 100644 (file)
--- a/main.c
+++ b/main.c
@@ -15,6 +15,7 @@
  */
 
 #include <stdio.h>
+#include <stdbool.h>
 #include <unistd.h>
 #include <errno.h>
 
@@ -29,7 +30,7 @@
 #include "matcher.h"
 
 static struct json_object *
-parse_json(FILE *fd)
+parse_json(FILE *fd, const char **error)
 {
        int len;
        char buf[256];
@@ -51,7 +52,16 @@ parse_json(FILE *fd)
 
        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,37 +83,18 @@ print_string(const char *s)
 }
 
 static void
-export_json(struct json_object *jsobj, char *expr)
+export_value(struct json_object *jsobj, const char *prefix)
 {
-       bool first;
-       struct jp_state *state;
-       struct json_object *res;
-       const char *prefix;
-
-       state = jp_parse(expr);
-
-       if (!state || state->error)
-       {
-               fprintf(stderr, "In expression '%s': %s\n",
-                       expr, state ? state->error : "Out of memory");
-
-               goto out;
-       }
-
-       res = jp_match(state->path, jsobj);
+       int n, len;
+       bool first = true;
 
-       if (state->path->type == T_LABEL)
+       if (prefix)
        {
-               prefix = state->path->str;
-
-               switch (json_object_get_type(res))
+               switch (json_object_get_type(jsobj))
                {
                case json_type_object:
-                       printf("export %s_TYPE=object; ", prefix);
-
-                       first = true;
-                       printf("export %s_KEYS=", prefix);
-                       json_object_object_foreach(res, key, val)
+                       printf("export %s=", prefix);
+                       json_object_object_foreach(jsobj, key, val)
                        {
                                if (!val)
                                        continue;
@@ -115,68 +106,118 @@ export_json(struct json_object *jsobj, char *expr)
                                first = false;
                        }
                        printf("; ");
-
-                       //printf("export %s=", prefix);
-                       //print_string(json_object_to_json_string(res));
-                       //printf("; ");
-
                        break;
 
                case json_type_array:
-                       printf("export %s_TYPE=array; ", prefix);
-                       printf("export %s_LENGTH=%d; ",
-                              prefix, json_object_array_length(res));
+                       printf("export %s=", prefix);
+                       for (n = 0, len = json_object_array_length(jsobj); n < len; n++)
+                       {
+                               if (!first)
+                                       printf("\\ ");
 
-                       //printf("export %s=", prefix);
-                       //print_string(json_object_to_json_string(res));
-                       //printf("; ");
+                               printf("%d", n);
+                               first = false;
+                       }
+                       printf("; ");
                        break;
 
                case json_type_boolean:
-                       printf("export %s_TYPE=bool; ", prefix);
-                       printf("export %s=%d; ", prefix, json_object_get_boolean(res));
+                       printf("export %s=%d; ", prefix, json_object_get_boolean(jsobj));
                        break;
 
                case json_type_int:
-                       printf("export %s_TYPE=int; ", prefix);
-                       printf("export %s=%d; ", prefix, json_object_get_int(res));
+                       printf("export %s=%d; ", prefix, json_object_get_int(jsobj));
                        break;
 
                case json_type_double:
-                       printf("export %s_TYPE=double; ", prefix);
-                       printf("export %s=%f; ", prefix, json_object_get_double(res));
+                       printf("export %s=%f; ", prefix, json_object_get_double(jsobj));
                        break;
 
                case json_type_string:
-                       printf("export %s_TYPE=string; ", prefix);
                        printf("export %s=", prefix);
-                       print_string(json_object_get_string(res));
+                       print_string(json_object_get_string(jsobj));
                        printf("; ");
                        break;
 
                case json_type_null:
-                       printf("unset %s %s_TYPE %s_LENGTH %s_KEYS; ",
-                                  prefix, prefix, prefix, prefix);
                        break;
                }
        }
        else
        {
-               printf("%s\n", json_object_to_json_string(res));
+               printf("%s\n", json_object_to_json_string(jsobj));
+       }
+}
+
+static void
+export_type(struct json_object *jsobj, const char *prefix)
+{
+       const char *types[] = {
+               "null",
+               "boolean",
+               "double",
+               "int",
+               "object",
+               "array",
+               "string"
+       };
+
+       if (prefix)
+               printf("export %s=%s; ", prefix, types[json_object_get_type(jsobj)]);
+       else
+               printf("%s\n", types[json_object_get_type(jsobj)]);
+}
+
+static bool
+filter_json(int opt, struct json_object *jsobj, char *expr)
+{
+       struct jp_state *state;
+       struct json_object *res = NULL;
+       const char *prefix = NULL;
+
+       state = jp_parse(expr);
+
+       if (!state || state->error)
+       {
+               fprintf(stderr, "In expression '%s': %s\n",
+                       expr, state ? state->error : "Out of memory");
+
+               goto out;
+       }
+
+       res = jp_match(state->path, jsobj);
+
+       if (res)
+       {
+               prefix = (state->path->type == T_LABEL) ? state->path->str : NULL;
+
+               switch (opt)
+               {
+               case 't':
+                       export_type(res, prefix);
+                       break;
+
+               default:
+                       export_value(res, prefix);
+                       break;
+               }
        }
 
 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;
 
-       while ((opt = getopt(argc, argv, "i:e:")) != -1)
+       while ((opt = getopt(argc, argv, "i:e:t:q")) != -1)
        {
                switch (opt)
                {
@@ -188,32 +229,45 @@ 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 't':
                case 'e':
                        if (!jsobj)
                        {
-                               jsobj = parse_json(input);
+                               jsobj = parse_json(input, &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;
 }