summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2018-02-04 15:37:15 +0100
committerJo-Philipp Wich <jo@mein.io>2018-02-04 15:37:15 +0100
commit8614470400daf36d9b189d9ea9085ef6e19afd0e (patch)
tree216d354d3010e42761b7ff467a15658e43e20ca0
parentdea067ad67d977c247c300c06676a06adf21e0c7 (diff)
downloadjsonpath-8614470400daf36d9b189d9ea9085ef6e19afd0e.tar.gz
main: implement array mode
Implement a new option "-a" which turns on array mode, meaning that the program will attempt to parse multiple consecutive JSON objects from the source data and merge them into a JSON array. This is mainly useful for operating on JSON log files with one object per line. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--main.c80
1 files changed, 68 insertions, 12 deletions
diff --git a/main.c b/main.c
index 85a53f4..5041d10 100644
--- a/main.c
+++ b/main.c
@@ -43,9 +43,10 @@ print_usage(char *app)
{
printf(
"== Usage ==\n\n"
- " # %s [-i <file> | -s \"json...\"] {-t <pattern> | -e <pattern>}\n"
+ " # %s [-a] [-i <file> | -s \"json...\"] {-t <pattern> | -e <pattern>}\n"
" -q Quiet, no errors are printed\n"
" -h, --help Print this help\n"
+ " -a Implicitely treat input as array, useful for JSON logs\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"
@@ -75,30 +76,80 @@ print_usage(char *app)
}
static struct json_object *
-parse_json(FILE *fd, const char *source, const char **error)
+parse_json_chunk(struct json_tokener *tok, struct json_object *array,
+ const char *buf, size_t len, enum json_tokener_error *err)
{
- int len;
- char buf[256];
struct json_object *obj = NULL;
+
+ while (len)
+ {
+ obj = json_tokener_parse_ex(tok, buf, len);
+ *err = json_tokener_get_error(tok);
+
+ if (*err == json_tokener_success)
+ {
+ if (array)
+ {
+ json_object_array_add(array, obj);
+ }
+ else
+ {
+ break;
+ }
+ }
+ else if (*err != json_tokener_continue)
+ {
+ break;
+ }
+
+ buf += tok->char_offset;
+ len -= tok->char_offset;
+ }
+
+ return obj;
+}
+
+static struct json_object *
+parse_json(FILE *fd, const char *source, const char **error, bool array_mode)
+{
+ size_t len;
+ char buf[256];
+ struct json_object *obj = NULL, *array = NULL;
struct json_tokener *tok = json_tokener_new();
enum json_tokener_error err = json_tokener_continue;
if (!tok)
+ {
+ *error = "Out of memory";
return NULL;
+ }
+
+ if (array_mode)
+ {
+ array = json_object_new_array();
+
+ if (!array)
+ {
+ json_tokener_free(tok);
+ *error = "Out of memory";
+ return NULL;
+ }
+ }
if (source)
{
- obj = json_tokener_parse_ex(tok, source, strlen(source));
- err = json_tokener_get_error(tok);
+ obj = parse_json_chunk(tok, array, source, strlen(source), &err);
}
else
{
while ((len = fread(buf, 1, sizeof(buf), fd)) > 0)
{
- obj = json_tokener_parse_ex(tok, buf, len);
- err = json_tokener_get_error(tok);
+ obj = parse_json_chunk(tok, array, buf, len, &err);
- if (!err || err != json_tokener_continue)
+ if (err == json_tokener_success && !array)
+ break;
+
+ if (err != json_tokener_continue)
break;
}
}
@@ -114,7 +165,7 @@ parse_json(FILE *fd, const char *source, const char **error)
return NULL;
}
- return obj;
+ return array ? array : obj;
}
static void
@@ -414,6 +465,7 @@ out:
int main(int argc, char **argv)
{
+ bool array_mode = false;
int opt, rv = 0, limit = 0x7FFFFFFF;
FILE *input = stdin;
struct json_object *jsobj = NULL;
@@ -425,10 +477,14 @@ int main(int argc, char **argv)
goto out;
}
- while ((opt = getopt(argc, argv, "hi:s:e:t:F:l:q")) != -1)
+ while ((opt = getopt(argc, argv, "ahi:s:e:t:F:l:q")) != -1)
{
switch (opt)
{
+ case 'a':
+ array_mode = true;
+ break;
+
case 'h':
print_usage(argv[0]);
goto out;
@@ -464,7 +520,7 @@ int main(int argc, char **argv)
case 'e':
if (!jsobj)
{
- jsobj = parse_json(input, source, &jserr);
+ jsobj = parse_json(input, source, &jserr, array_mode);
if (!jsobj)
{