remove obsolete /opt/local include/lib directories on mac os x
[oweals/jsonpath.git] / main.c
diff --git a/main.c b/main.c
index 2da2acf2944d469a39b4ea29a99b3b18469e58c8..85a53f4af40e4d02429ee2fdfda597780b7e1f96 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
+ * Copyright (C) 2013-2014 Jo-Philipp Wich <jo@mein.io>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -16,6 +16,7 @@
 
 #include <stdio.h>
 #include <stdbool.h>
+#include <stdint.h>
 #include <unistd.h>
 #include <errno.h>
 
@@ -37,6 +38,42 @@ struct match_item {
        struct list_head list;
 };
 
+static void
+print_usage(char *app)
+{
+       printf(
+       "== Usage ==\n\n"
+       "  # %s [-i <file> | -s \"json...\"] {-t <pattern> | -e <pattern>}\n"
+       "  -q           Quiet, no errors are printed\n"
+       "  -h, --help   Print this help\n"
+       "  -i path      Specify a JSON file to parse\n"
+       "  -s \"json\"  Specify a JSON string to parse\n"
+       "  -l limit     Specify max number of results to show\n"
+       "  -F separator Specify a field separator when using export\n"
+       "  -t <pattern> Print the type of values matched by pattern\n"
+       "  -e <pattern> Print the values matched by pattern\n"
+       "  -e VAR=<pat> Serialize matched value for shell \"eval\"\n\n"
+       "== Patterns ==\n\n"
+       "  Patterns are JsonPath: http://goessner.net/articles/JsonPath/\n"
+       "  This tool implements $, @, [], * and the union operator ','\n"
+       "  plus the usual expressions and literals.\n"
+       "  It does not support the recursive child search operator '..' or\n"
+       "  the '?()' and '()' filter expressions as those would require a\n"
+       "  complete JavaScript engine to support them.\n\n"
+       "== Examples ==\n\n"
+       "  Display the first IPv4 address on lan:\n"
+       "  # ifstatus lan | %s -e '@[\"ipv4-address\"][0].address'\n\n"
+       "  Extract the release string from the board information:\n"
+       "  # ubus call system board | %s -e '@.release.description'\n\n"
+       "  Find all interfaces which are up:\n"
+       "  # ubus call network.interface dump | \\\n"
+       "       %s -e '@.interface[@.up=true].interface'\n\n"
+       "  Export br-lan traffic counters for shell eval:\n"
+       "  # devstatus br-lan | %s -e 'RX=@.statistics.rx_bytes' \\\n"
+       "       -e 'TX=@.statistics.tx_bytes'\n",
+               app, app, app, app, app);
+}
+
 static struct json_object *
 parse_json(FILE *fd, const char *source, const char **error)
 {
@@ -126,7 +163,8 @@ print_separator(const char *sep, int *sc, int sl)
 }
 
 static void
-export_value(struct list_head *matches, const char *prefix, const char *sep)
+export_value(struct list_head *matches, const char *prefix, const char *sep,
+             int limit)
 {
        int n, len;
        int sc = 0, sl = strlen(sep);
@@ -141,6 +179,9 @@ export_value(struct list_head *matches, const char *prefix, const char *sep)
 
                list_for_each_entry(item, matches, list)
                {
+                       if (limit-- <= 0)
+                               break;
+
                        switch (json_object_get_type(item->jsobj))
                        {
                        case json_type_object:
@@ -171,7 +212,7 @@ export_value(struct list_head *matches, const char *prefix, const char *sep)
 
                        case json_type_int:
                                print_separator(sep, &sc, sl);
-                               printf("%d", json_object_get_int(item->jsobj));
+                               printf("%" PRId64, json_object_get_int64(item->jsobj));
                                break;
 
                        case json_type_double:
@@ -195,6 +236,9 @@ export_value(struct list_head *matches, const char *prefix, const char *sep)
        {
                list_for_each_entry(item, matches, list)
                {
+                       if (limit-- <= 0)
+                               break;
+
                        switch (json_object_get_type(item->jsobj))
                        {
                        case json_type_object:
@@ -217,7 +261,7 @@ export_value(struct list_head *matches, const char *prefix, const char *sep)
 }
 
 static void
-export_type(struct list_head *matches, const char *prefix)
+export_type(struct list_head *matches, const char *prefix, int limit)
 {
        bool first = true;
        struct match_item *item;
@@ -242,6 +286,9 @@ export_type(struct list_head *matches, const char *prefix)
                if (!first)
                        printf("\\ ");
 
+               if (limit-- <= 0)
+                       break;
+
                printf("%s", types[json_object_get_type(item->jsobj)]);
                first = false;
        }
@@ -317,7 +364,8 @@ print_error(struct jp_state *state, char *expr)
 }
 
 static bool
-filter_json(int opt, struct json_object *jsobj, char *expr, const char *sep)
+filter_json(int opt, struct json_object *jsobj, char *expr, const char *sep,
+            int limit)
 {
        struct jp_state *state;
        const char *prefix = NULL;
@@ -346,11 +394,11 @@ filter_json(int opt, struct json_object *jsobj, char *expr, const char *sep)
        switch (opt)
        {
        case 't':
-               export_type(&matches, prefix);
+               export_type(&matches, prefix, limit);
                break;
 
        default:
-               export_value(&matches, prefix, sep);
+               export_value(&matches, prefix, sep, limit);
                break;
        }
 
@@ -366,15 +414,25 @@ out:
 
 int main(int argc, char **argv)
 {
-       int opt, rv = 0;
+       int opt, rv = 0, limit = 0x7FFFFFFF;
        FILE *input = stdin;
        struct json_object *jsobj = NULL;
        const char *jserr = NULL, *source = NULL, *separator = " ";
 
-       while ((opt = getopt(argc, argv, "i:s:e:t:F:q")) != -1)
+       if (argc == 1)
+       {
+               print_usage(argv[0]);
+               goto out;
+       }
+
+       while ((opt = getopt(argc, argv, "hi:s:e:t:F:l:q")) != -1)
        {
                switch (opt)
                {
+               case 'h':
+                       print_usage(argv[0]);
+                       goto out;
+
                case 'i':
                        input = fopen(optarg, "r");
 
@@ -398,6 +456,10 @@ int main(int argc, char **argv)
                                separator = optarg;
                        break;
 
+               case 'l':
+                       limit = atoi(optarg);
+                       break;
+
                case 't':
                case 'e':
                        if (!jsobj)
@@ -414,7 +476,7 @@ int main(int argc, char **argv)
                                }
                        }
 
-                       if (!filter_json(opt, jsobj, optarg, separator))
+                       if (!filter_json(opt, jsobj, optarg, separator, limit))
                                rv = 1;
 
                        break;
@@ -429,7 +491,7 @@ out:
        if (jsobj)
                json_object_put(jsobj);
 
-       if (input != stdin)
+       if (input && input != stdin)
                fclose(input);
 
        return rv;