Introduction
Introduction Statistics Contact Development Disclaimer Help
improvements - json2tsv - JSON to TSV converter
git clone git://git.codemadness.org/json2tsv
Log
Files
Refs
README
LICENSE
---
commit 2f12ae56971af8acaa52357fe1042d37f71ffbd4
parent 9a85d6c5f69749ac71c690e5b4d36b8e70b15d16
Author: Hiltjo Posthuma <[email protected]>
Date: Sun, 20 Oct 2019 14:30:24 +0200
improvements
- separate into more precise JSON types: primitives to: bool, null, number.
- separate JSON code into a reusable "library": json.c.
- remove errstr from parsejson(): just return an error code for out-of-memory
and a JSON parse error. The tool returns exit code 2 when out-of-memory.
- much more strict JSON parsing for incorrect input.
- make primitives a fixed buffer. The longest size data for primitives are
numbers and cannot be long anyway.
- improve README example (reddit).
Diffstat:
M Makefile | 26 +++++++++++++++++++++-----
M README | 35 ++++++++++++++++-------------…
A json.c | 314 +++++++++++++++++++++++++++++…
A json.h | 26 ++++++++++++++++++++++++++
M json2tsv.c | 301 +----------------------------…
5 files changed, 386 insertions(+), 316 deletions(-)
---
diff --git a/Makefile b/Makefile
@@ -8,35 +8,51 @@ PREFIX = /usr/local
MANPREFIX = ${PREFIX}/man
DOCPREFIX = ${PREFIX}/share/doc/${NAME}
+RANLIB = ranlib
+
BIN = ${NAME}
SRC = ${BIN:=.c}
+HDR = json.h
MAN1 = ${BIN:=.1}
DOC = \
LICENSE\
README
+LIBJSON = libjson.a
+LIBJSONSRC = json.c
+LIBJSONOBJ = ${LIBJSONSRC:.c=.o}
+
+LIB = ${LIBJSON}
+
all: ${BIN}
-${BIN}: ${@:=.o}
+${BIN}: ${LIB} ${@:=.o}
-OBJ = ${SRC:.c=.o}
+OBJ = ${SRC:.c=.o} ${LIBJSONOBJ}
+
+${OBJ}: ${HDR}
.o:
- ${CC} ${LDFLAGS} -o $@ $<
+ ${CC} ${LDFLAGS} -o $@ $< ${LIB}
.c.o:
${CC} ${CFLAGS} ${CPPFLAGS} -o $@ -c $<
+${LIBJSON}: ${LIBJSONOBJ}
+ ${AR} rc $@ $?
+ ${RANLIB} $@
+
dist:
rm -rf "${NAME}-${VERSION}"
mkdir -p "${NAME}-${VERSION}"
- cp -f ${MAN1} ${DOC} ${SRC} Makefile "${NAME}-${VERSION}"
+ cp -f ${MAN1} ${DOC} ${HDR} \
+ ${SRC} ${LIBJSONSRC} Makefile "${NAME}-${VERSION}"
# make tarball
tar -cf - "${NAME}-${VERSION}" | gzip -c > "${NAME}-${VERSION}.tar.gz"
rm -rf "${NAME}-${VERSION}"
clean:
- rm -f ${BIN} ${OBJ}
+ rm -f ${BIN} ${OBJ} ${LIB}
install: all
# installing executable files.
diff --git a/README b/README
@@ -16,10 +16,16 @@ The output format per line is:
The nodename and value are escaped (\n, \t and \\). Control-characters are
removed.
-The type can be: o (for object), a (for array), p (for primitive such as true,
-false, null, a number) or s (for string).
+The type field is a single byte and can be:
-Then filtering is easy using some awk script on the node "selector".
+ a for array
+ b for bool
+ n for number
+ o for object
+ s for string
+ ? for null
+
+Filtering on the first field "nodename" is easy using awk for example.
See the json2tsv(1) man page for the full documentation.
@@ -32,29 +38,24 @@ plain-text list using awk:
#!/bin/sh
-curl -s -H 'User-Agent:' 'https://old.reddit.com/.json' | \
+curl -s -H 'User-Agent:' 'https://old.reddit.com/.json?raw_json=1&limit=100' |…
json2tsv | \
-awk 'BEGIN {
- FS = OFS = "\t";
- n = 0;
- title = author = subreddit = "";
-}
+awk -F '\t' '
function show() {
- if (length(title) == 0)
+ if (length(o["title"]) == 0)
return;
- print n ". " title " by " author " in r/" subreddit;
- print url;
+ print n ". " o["title"] " by " o["author"] " in r/" o["subreddit"];
+ print o["url"];
print "";
}
$1 == ".data.children[].data" {
show();
n++;
- title = url = author = subreddit = "";
+ delete o;
+}
+$1 ~ /^\.data\.children\[\]\.data\.[a-zA-Z0-9_]*$/ {
+ o[substr($1, 23)] = $3;
}
-$1 == ".data.children[].data.url" { url = $3; }
-$1 == ".data.children[].data.title" { title = $3; }
-$1 == ".data.children[].data.author" { author = $3; }
-$1 == ".data.children[].data.subreddit" { subreddit = $3; }
END {
show();
}'
diff --git a/json.c b/json.c
@@ -0,0 +1,314 @@
+#include <ctype.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define GETNEXT getchar
+
+#include "json.h"
+
+int
+codepointtoutf8(long r, char *s)
+{
+ if (r == 0) {
+ return 0; /* NUL byte */
+ } else if (r <= 0x7F) {
+ /* 1 byte: 0aaaaaaa */
+ s[0] = r;
+ return 1;
+ } else if (r <= 0x07FF) {
+ /* 2 bytes: 00000aaa aabbbbbb */
+ s[0] = 0xC0 | ((r & 0x0007C0) >> 6); /* 110aaaaa */
+ s[1] = 0x80 | (r & 0x00003F); /* 10bbbbbb */
+ return 2;
+ } else if (r <= 0xFFFF) {
+ /* 3 bytes: aaaabbbb bbcccccc */
+ s[0] = 0xE0 | ((r & 0x00F000) >> 12); /* 1110aaaa */
+ s[1] = 0x80 | ((r & 0x000FC0) >> 6); /* 10bbbbbb */
+ s[2] = 0x80 | (r & 0x00003F); /* 10cccccc */
+ return 3;
+ } else {
+ /* 4 bytes: 000aaabb bbbbcccc ccdddddd */
+ s[0] = 0xF0 | ((r & 0x1C0000) >> 18); /* 11110aaa */
+ s[1] = 0x80 | ((r & 0x03F000) >> 12); /* 10bbbbbb */
+ s[2] = 0x80 | ((r & 0x000FC0) >> 6); /* 10cccccc */
+ s[3] = 0x80 | (r & 0x00003F); /* 10dddddd */
+ return 4;
+ }
+}
+
+int
+hexdigit(int c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'a' && c <= 'f')
+ return 10 + (c - 'a');
+ else if (c >= 'A' && c <= 'F')
+ return 10 + (c - 'A');
+ return 0;
+}
+
+int
+capacity(char **value, size_t *sz, size_t cur, size_t inc)
+{
+ size_t need, newsiz;
+ char *newp;
+
+ /* check for addition overflow */
+ if (cur > SIZE_MAX - inc) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ need = cur + inc;
+
+ if (need > *sz) {
+ if (need > SIZE_MAX / 2) {
+ newsiz = SIZE_MAX;
+ } else {
+ for (newsiz = *sz < 64 ? 64 : *sz; newsiz <= need; new…
+ ;
+ }
+ if (!(newp = realloc(*value, newsiz)))
+ return -1; /* up to caller to free *value */
+ *value = newp;
+ *sz = newsiz;
+ }
+ return 0;
+}
+
+#define EXPECT_VALUE "{[\"-0123456789tfn"
+#define EXPECT_STRING "\""
+#define EXPECT_END "}],"
+#define EXPECT_NOTHING ""
+#define EXPECT_OBJECT_STRING EXPECT_STRING "}"
+#define EXPECT_ARRAY_VALUE EXPECT_VALUE "]"
+
+#define JSON_INVALID() do { ret = JSON_ERROR_INVALID; goto end; } while …
+
+int
+parsejson(void (*cb)(struct json_node *, size_t, const char *))
+{
+ struct json_node nodes[JSON_MAX_NODE_DEPTH] = { 0 };
+ size_t depth = 0, p = 0, len, sz = 0;
+ long cp, hi, lo;
+ char pri[128], *str = NULL;
+ int c, i, escape, iskey = 0, ret = JSON_ERROR_MEM;
+ const char *expect = EXPECT_VALUE;
+
+ if (capacity(&(nodes[0].name), &(nodes[0].namesiz), 0, 1) == -1)
+ goto end;
+ nodes[0].name[0] = '\0';
+
+ while (1) {
+ c = GETNEXT();
+handlechr:
+ if (c == EOF)
+ break;
+
+ if (c && strchr(" \t\n\r", c)) /* (no \v, \f, \b etc) */
+ continue;
+
+ if (!c || !strchr(expect, c))
+ JSON_INVALID();
+
+ switch (c) {
+ case ':':
+ /* not in an object or key in object is not a string */
+ if (!depth || nodes[depth - 1].type != TYPE_OBJECT ||
+ nodes[depth].type != TYPE_STRING)
+ JSON_INVALID();
+ iskey = 0;
+ expect = EXPECT_VALUE;
+ break;
+ case '"':
+ nodes[depth].type = TYPE_STRING;
+ escape = 0;
+ len = 0;
+ while (1) {
+ c = GETNEXT();
+chr:
+ /* EOF or control char: 0x7f is not defined as…
+ if (c < 0x20)
+ JSON_INVALID();
+
+ if (escape) {
+escchr:
+ escape = 0;
+ switch (c) {
+ case '"': /* FALLTHROUGH */
+ case '\\':
+ case '/': break;
+ case 'b': c = '\b'; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case 'u': /* hex hex hex hex */
+ if (capacity(&str, &sz, len, 4…
+ goto end;
+ for (i = 12, cp = 0; i >= 0; i…
+ if ((c = GETNEXT()) ==…
+ JSON_INVALID()…
+ cp |= (hexdigit(c) << …
+ }
+ /* RFC8259 - 7. Strings - surr…
+ * 0xd800 - 0xdb7f - high surr…
+ if (cp >= 0xd800 && cp <= 0xdb…
+ if ((c = GETNEXT()) !=…
+ len += codepoi…
+ goto chr;
+ }
+ if ((c = GETNEXT()) !=…
+ len += codepoi…
+ goto escchr;
+ }
+ for (hi = cp, i = 12, …
+ if ((c = GETNE…
+ JSON_I…
+ lo |= (hexdigi…
+ }
+ /* 0xdc00 - 0xdfff - l…
+ if (lo >= 0xdc00 && lo…
+ cp = (hi << 10…
+ } else {
+ /* handle grac…
+ len += codepoi…
+ if (capacity(&…
+ goto e…
+ len += codepoi…
+ continue;
+ }
+ }
+ len += codepointtoutf8(cp, &st…
+ continue;
+ default:
+ JSON_INVALID(); /* invalid esc…
+ }
+ if (capacity(&str, &sz, len, 1) == -1)
+ goto end;
+ str[len++] = c;
+ } else if (c == '\\') {
+ escape = 1;
+ } else if (c == '"') {
+ if (capacity(&str, &sz, len, 1) == -1)
+ goto end;
+ str[len++] = '\0';
+
+ if (iskey) {
+ if (capacity(&(nodes[depth].na…
+ goto end;
+ memcpy(nodes[depth].name, str,…
+ } else {
+ cb(nodes, depth + 1, str);
+ }
+ break;
+ } else {
+ if (capacity(&str, &sz, len, 1) == -1)
+ goto end;
+ str[len++] = c;
+ }
+ }
+ if (iskey)
+ expect = ":";
+ else
+ expect = EXPECT_END;
+ break;
+ case '[':
+ case '{':
+ if (depth + 1 >= JSON_MAX_NODE_DEPTH)
+ JSON_INVALID(); /* too deep */
+
+ nodes[depth].index = 0;
+ nodes[depth].type = TYPE_OBJECT;
+ if (c == '{') {
+ iskey = 1;
+ nodes[depth].type = TYPE_OBJECT;
+ expect = EXPECT_OBJECT_STRING;
+ } else if (c == '[') {
+ nodes[depth].type = TYPE_ARRAY;
+ expect = EXPECT_ARRAY_VALUE;
+ }
+
+ cb(nodes, depth + 1, "");
+
+ depth++;
+ nodes[depth].index = 0;
+ if (capacity(&(nodes[depth].name), &(nodes[depth].name…
+ goto end;
+ nodes[depth].name[0] = '\0';
+ break;
+ case ']':
+ case '}':
+ if (!depth ||
+ (c == ']' && nodes[depth - 1].type != TYPE_ARRAY) ||
+ (c == '}' && nodes[depth - 1].type != TYPE_OBJECT))
+ JSON_INVALID(); /* unbalanced nodes */
+
+ nodes[--depth].index++;
+ if (!depth)
+ expect = EXPECT_NOTHING;
+ else
+ expect = EXPECT_END;
+ break;
+ case ',':
+ nodes[depth - 1].index++;
+ if (nodes[depth - 1].type == TYPE_OBJECT) {
+ iskey = 1;
+ expect = EXPECT_STRING;
+ } else {
+ expect = EXPECT_VALUE;
+ }
+ break;
+ case 't': /* true */
+ if (GETNEXT() != 'r' || GETNEXT() != 'u' || GETNEXT() …
+ JSON_INVALID();
+ nodes[depth].type = TYPE_BOOL;
+ cb(nodes, depth + 1, "true");
+ expect = EXPECT_END;
+ break;
+ case 'f': /* false */
+ if (GETNEXT() != 'a' || GETNEXT() != 'l' || GETNEXT() …
+ JSON_INVALID();
+ nodes[depth].type = TYPE_BOOL;
+ cb(nodes, depth + 1, "false");
+ expect = EXPECT_END;
+ break;
+ case 'n': /* null */
+ if (GETNEXT() != 'u' || GETNEXT() != 'l' || GETNEXT() …
+ JSON_INVALID();
+ nodes[depth].type = TYPE_NULL;
+ cb(nodes, depth + 1, "null");
+ expect = EXPECT_END;
+ break;
+ default: /* number */
+ nodes[depth].type = TYPE_NUMBER;
+ p = 0;
+ pri[p++] = c;
+ expect = EXPECT_END;
+ while (1) {
+ c = GETNEXT();
+ if (!c || !strchr("0123456789eE+-.", c) ||
+ c == EOF || p + 1 >= sizeof(pri)) {
+ pri[p] = '\0';
+ cb(nodes, depth + 1, pri);
+ goto handlechr; /* do not read next ch…
+ } else {
+ pri[p++] = c;
+ }
+ }
+ }
+ }
+ if (depth)
+ JSON_INVALID(); /* unbalanced nodes */
+
+ ret = 0; /* success */
+end:
+ for (depth = 0; depth < sizeof(nodes) / sizeof(nodes[0]); depth++)
+ free(nodes[depth].name);
+ free(str);
+
+ return ret;
+}
diff --git a/json.h b/json.h
@@ -0,0 +1,26 @@
+#include <stdint.h>
+
+enum JSONType {
+ TYPE_ARRAY = 'a',
+ TYPE_OBJECT = 'o',
+ TYPE_STRING = 's',
+ TYPE_BOOL = 'b',
+ TYPE_NULL = '?',
+ TYPE_NUMBER = 'n'
+};
+
+enum JSONError {
+ JSON_ERROR_MEM = -2,
+ JSON_ERROR_INVALID = -1
+};
+
+#define JSON_MAX_NODE_DEPTH 64
+
+struct json_node {
+ enum JSONType type;
+ char *name;
+ size_t namesiz;
+ size_t index; /* count/index for array or object type */
+};
+
+int parsejson(void (*cb)(struct json_node *, size_t, const char *));
diff --git a/json2tsv.c b/json2tsv.c
@@ -11,299 +11,10 @@
#define pledge(a,b) 0
#endif
-#define GETNEXT getchar
-
-enum JSONType {
- TYPE_PRIMITIVE = 'p',
- TYPE_STRING = 's',
- TYPE_ARRAY = 'a',
- TYPE_OBJECT = 'o'
-};
-
-#define JSON_MAX_NODE_DEPTH 64
-
-struct json_node {
- enum JSONType type;
- char *name;
- size_t namesiz;
- size_t index; /* count/index for array or object type */
-};
-
-const char *JSON_ERROR_ALLOC = "cannot allocate enough memory";
-const char *JSON_ERROR_BALANCE = "unbalanced nodes";
-const char *JSON_ERROR_CODEPOINT = "invalid codepoint";
-const char *JSON_ERROR_DEPTH = "max node depth reached";
-const char *JSON_ERROR_ESCAPE_CHAR = "unknown escape character in string";
-const char *JSON_ERROR_INVALID_CHAR = "invalid character in string";
-const char *JSON_ERROR_OBJECT_MEMBER = "object member, but not in an object";
+#include "json.h"
static int showindices = 0; /* -n flag: show indices count for arrays */
-int
-codepointtoutf8(long r, char *s)
-{
- if (r == 0) {
- return 0; /* NUL byte */
- } else if (r <= 0x7F) {
- /* 1 byte: 0aaaaaaa */
- s[0] = r;
- return 1;
- } else if (r <= 0x07FF) {
- /* 2 bytes: 00000aaa aabbbbbb */
- s[0] = 0xC0 | ((r & 0x0007C0) >> 6); /* 110aaaaa */
- s[1] = 0x80 | (r & 0x00003F); /* 10bbbbbb */
- return 2;
- } else if (r <= 0xFFFF) {
- /* 3 bytes: aaaabbbb bbcccccc */
- s[0] = 0xE0 | ((r & 0x00F000) >> 12); /* 1110aaaa */
- s[1] = 0x80 | ((r & 0x000FC0) >> 6); /* 10bbbbbb */
- s[2] = 0x80 | (r & 0x00003F); /* 10cccccc */
- return 3;
- } else {
- /* 4 bytes: 000aaabb bbbbcccc ccdddddd */
- s[0] = 0xF0 | ((r & 0x1C0000) >> 18); /* 11110aaa */
- s[1] = 0x80 | ((r & 0x03F000) >> 12); /* 10bbbbbb */
- s[2] = 0x80 | ((r & 0x000FC0) >> 6); /* 10cccccc */
- s[3] = 0x80 | (r & 0x00003F); /* 10dddddd */
- return 4;
- }
-}
-
-int
-hexdigit(int c)
-{
- if (c >= '0' && c <= '9')
- return c - '0';
- else if (c >= 'a' && c <= 'f')
- return 10 + (c - 'a');
- else if (c >= 'A' && c <= 'F')
- return 10 + (c - 'A');
- return 0;
-}
-
-int
-capacity(char **value, size_t *sz, size_t cur, size_t inc)
-{
- size_t need, newsiz;
- char *newp;
-
- /* check for addition overflow */
- if (cur > SIZE_MAX - inc) {
- errno = EOVERFLOW;
- return -1;
- }
- need = cur + inc;
-
- if (need > *sz) {
- if (need > SIZE_MAX / 2) {
- newsiz = SIZE_MAX;
- } else {
- for (newsiz = *sz < 64 ? 64 : *sz; newsiz <= need; new…
- ;
- }
- if (!(newp = realloc(*value, newsiz)))
- return -1; /* up to caller to free *value */
- *value = newp;
- *sz = newsiz;
- }
- return 0;
-}
-
-int
-parsejson(void (*cb)(struct json_node *, size_t, const char *), const char **e…
-{
- struct json_node nodes[JSON_MAX_NODE_DEPTH] = { 0 };
- size_t depth = 0, v = 0, vz = 0;
- long cp, hi, lo;
- int c, i, escape, ret = -1;
- char *value = NULL;
-
- *errstr = JSON_ERROR_ALLOC;
- if (capacity(&(nodes[0].name), &(nodes[0].namesiz), 0, 1) == -1)
- goto end;
- nodes[0].name[0] = '\0';
- nodes[depth].type = TYPE_PRIMITIVE;
-
- while ((c = GETNEXT()) != EOF) {
- /* not whitespace or control character */
- if (c <= 0x20 || c == 0x7f)
- continue;
-
- switch (c) {
- case ':':
- if (!depth || nodes[depth - 1].type != TYPE_OBJECT) {
- *errstr = JSON_ERROR_OBJECT_MEMBER;
- goto end;
- }
-
- if (capacity(&value, &vz, v, 1) == -1)
- goto end;
- value[v] = '\0';
- if (capacity(&(nodes[depth].name), &(nodes[depth].name…
- goto end;
- memcpy(nodes[depth].name, value, v);
- nodes[depth].name[v] = '\0';
- v = 0;
- nodes[depth].type = TYPE_PRIMITIVE;
- break;
- case '"':
- nodes[depth].type = TYPE_STRING;
- escape = 0;
- for (;;) {
- c = GETNEXT();
-chr:
- if (c < 0x20) {
- /* EOF or control char: 0x7f is not de…
- *errstr = JSON_ERROR_INVALID_CHAR;
- goto end;
- }
-
- if (escape) {
-escchr:
- escape = 0;
- switch (c) {
- case '"': /* FALLTHROUGH */
- case '\\':
- case '/': break;
- case 'b': c = '\b'; break;
- case 'f': c = '\f'; break;
- case 'n': c = '\n'; break;
- case 'r': c = '\r'; break;
- case 't': c = '\t'; break;
- case 'u': /* hex hex hex hex */
- if (capacity(&value, &vz, v, 4…
- goto end;
- for (i = 12, cp = 0; i >= 0; i…
- if ((c = GETNEXT()) ==…
- *errstr = JSON…
- goto end;
- }
- cp |= (hexdigit(c) << …
- }
- /* RFC8259 - 7. Strings - surr…
- * 0xd800 - 0xdb7f - high surr…
- if (cp >= 0xd800 && cp <= 0xdb…
- if ((c = GETNEXT()) !=…
- v += codepoint…
- goto chr;
- }
- if ((c = GETNEXT()) !=…
- v += codepoint…
- goto escchr;
- }
- for (hi = cp, i = 12, …
- if ((c = GETNE…
- *errst…
- goto e…
- }
- lo |= (hexdigi…
- }
- /* 0xdc00 - 0xdfff - l…
- if (lo >= 0xdc00 && lo…
- cp = (hi << 10…
- } else {
- /* handle grac…
- v += codepoint…
- if (capacity(&…
- goto e…
- v += codepoint…
- continue;
- }
- }
- v += codepointtoutf8(cp, &valu…
- continue;
- default:
- *errstr = JSON_ERROR_ESCAPE_CH…
- goto end;
- }
- if (capacity(&value, &vz, v, 1) == -1)
- goto end;
- value[v++] = c;
- } else if (c == '\\') {
- escape = 1;
- } else if (c == '"') {
- break;
- } else {
- if (capacity(&value, &vz, v, 1) == -1)
- goto end;
- value[v++] = c;
- }
- }
- if (capacity(&value, &vz, v, 1) == -1)
- goto end;
- value[v] = '\0';
- break;
- case '[':
- case '{':
- if (depth + 1 >= JSON_MAX_NODE_DEPTH) {
- *errstr = JSON_ERROR_DEPTH;
- goto end;
- }
-
- nodes[depth].index = 0;
- nodes[depth].type = c == '{' ? TYPE_OBJECT : TYPE_ARRA…
-
- cb(nodes, depth + 1, "");
- v = 0;
-
- depth++;
- nodes[depth].index = 0;
- nodes[depth].type = TYPE_PRIMITIVE;
- if (capacity(&(nodes[depth].name), &(nodes[depth].name…
- goto end;
- nodes[depth].name[0] = '\0';
- break;
- case ']':
- case '}':
- case ',':
- if (v || nodes[depth].type == TYPE_STRING) {
- if (capacity(&value, &vz, v, 1) == -1)
- goto end;
- value[v] = '\0';
- cb(nodes, depth + 1, value);
- v = 0;
- }
- if (!depth ||
- (c == ']' && nodes[depth - 1].type != TYPE_ARRAY) …
- (c == '}' && nodes[depth - 1].type != TYPE_OBJECT)…
- *errstr = JSON_ERROR_BALANCE;
- goto end;
- }
-
- if (c == ']' || c == '}') {
- nodes[--depth].index++;
- } else if (c == ',') {
- nodes[depth - 1].index++;
- nodes[depth].type = TYPE_PRIMITIVE;
- }
- break;
- default:
- if (capacity(&value, &vz, v, 1) == -1)
- goto end;
- value[v++] = c;
- }
- }
- if (depth) {
- *errstr = JSON_ERROR_BALANCE;
- goto end;
- }
- if (v || nodes[depth].type == TYPE_STRING) {
- if (capacity(&value, &vz, v, 1) == -1)
- goto end;
- value[v] = '\0';
- cb(nodes, depth + 1, value);
- }
-
- ret = 0; /* success */
- *errstr = NULL;
-end:
- for (depth = 0; depth < sizeof(nodes) / sizeof(nodes[0]); depth++)
- free(nodes[depth].name);
- free(value);
-
- return ret;
-}
-
void
printvalue(const char *s)
{
@@ -356,8 +67,6 @@ processnode(struct json_node *nodes, size_t depth, const cha…
int
main(int argc, char *argv[])
{
- const char *errstr;
-
if (pledge("stdio", NULL) == -1) {
fprintf(stderr, "pledge stdio: %s\n", strerror(errno));
return 1;
@@ -366,8 +75,12 @@ main(int argc, char *argv[])
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'n')
showindices = 1;
- if (parsejson(processnode, &errstr) == -1) {
- fprintf(stderr, "error: %s\n", errstr);
+ switch (parsejson(processnode)) {
+ case JSON_ERROR_MEM:
+ fputs("error: cannot allocate enough memory\n", stderr);
+ return 2;
+ case JSON_ERROR_INVALID:
+ fputs("error: invalid JSON\n", stderr);
return 1;
}
You are viewing proxied material from codemadness.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.