From 75b17eeca0394e27759acf2f6b039851a5a28f98 Mon Sep 17 00:00:00 2001 From: Joey Adams Date: Tue, 10 Aug 2010 01:10:19 -0400 Subject: Added explicit NULL and '\0' checks, and documented more functions/structures. --- jsonpath.c | 88 ++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 28 deletions(-) (limited to 'jsonpath.c') diff --git a/jsonpath.c b/jsonpath.c index 253f2cb..edfa6e8 100644 --- a/jsonpath.c +++ b/jsonpath.c @@ -158,6 +158,11 @@ mkRefChar(const char *bytes, size_t length) return ref; } +/* + * jp_show + * Unparse a JSONPath expression. This is used by parse_json_path + * to stringify successfully parsed JSONPaths. + */ char * jp_show(JSONPath * jp) { @@ -201,6 +206,12 @@ jp_show(JSONPath * jp) return string->data; } +/* + * Parse a long starting at *s . + * + * On success, return true and update *s to point to the end of the number. + * On failure, return false and leave *s untouched. + */ static bool parse_long(const char **s, long *out) { @@ -215,6 +226,13 @@ parse_long(const char **s, long *out) return true; } +/* + * jp_parse + * Parse a JSONPath expression (into a List of jp_element items). + * + * TODO: Get rid of all those gotos. The parser uses constant space, + * so there's no chance of a stack overflow anyway. + */ JSONPath * jp_parse(const char *pattern) { @@ -232,7 +250,7 @@ jp_parse(const char *pattern) skip_spaces(&s); /* pattern may not be empty */ - if (!*s) + if (*s == '\0') return NULL; jp = lappend(jp, mkRoot()); @@ -346,7 +364,7 @@ identifier: if (*s == '(') { - if (end - start == 4 && !memcmp(start, "char", 4)) + if (end - start == 4 && memcmp(start, "char", 4) == 0) { s++; skip_spaces(&s); @@ -364,7 +382,7 @@ identifier: string: key = json_decode_string(&s, &key_length, false); - if (!key) + if (key == NULL) goto failed; jp = lappend(jp, mkKeySubscript(key, key_length, recursive_descent)); @@ -420,7 +438,7 @@ static void match_recurse(void on_match(void *ctx, JPRef * ref), void *ctx, switch (elem->type) { case JP_WILDCARD: - if (json) + if (json != NULL) { json_foreach(child, json) match_recurse(on_match, ctx, lnext(path), mkRefNode(child)); @@ -428,43 +446,36 @@ static void match_recurse(void on_match(void *ctx, JPRef * ref), void *ctx, break; case JP_INDEX_SUBSCRIPT: - if (json && json->type == JSON_ARRAY) + if (json != NULL && json->type == JSON_ARRAY && + elem->data.index >= 0 && + (size_t) elem->data.index < json->v.children.count) { size_t i; - size_t index = elem->data.index; - /* - * Note: elem->data.index is signed (long), while index is - * unsigned (size_t). - */ - - if (elem->data.index >= 0 && index < json->v.children.count) + for (child = json->v.children.head, i = 0; + child != NULL && i < (size_t) elem->data.index; + child = child->next, i++) { - for (child = json->v.children.head, i = 0; - child != NULL && i < index; - child = child->next, i++) - { - } + } - /* - * If this fails, it means json->v.children.count was - * greater than the actual number of children. - */ - Assert(i == index && child != NULL); + /* + * If this fails, it means json->v.children.count was greater + * than the actual number of children. + */ + Assert(i == elem->data.index && child != NULL); - match_recurse(on_match, ctx, lnext(path), mkRefNode(child)); - } + match_recurse(on_match, ctx, lnext(path), mkRefNode(child)); } break; case JP_KEY_SUBSCRIPT: - if (json && json->type == JSON_OBJECT) + if (json != NULL && json->type == JSON_OBJECT) { json_foreach(child, json) { if (child->key != NULL && child->key_length == elem->data.key.length && - !memcmp(child->key, elem->data.key.ptr, child->key_length)) + memcmp(child->key, elem->data.key.ptr, child->key_length) == 0) { match_recurse(on_match, ctx, lnext(path), mkRefNode(child)); } @@ -473,7 +484,8 @@ static void match_recurse(void on_match(void *ctx, JPRef * ref), void *ctx, break; case JP_CALL_CHAR: - if (json && json->type == JSON_STRING && elem->data.index >= 0) + if (json != NULL && json->type == JSON_STRING && + elem->data.index >= 0) { const char *sub_start; size_t sub_bytes; @@ -497,7 +509,7 @@ static void match_recurse(void on_match(void *ctx, JPRef * ref), void *ctx, default:; } - if (elem->recursive_descent && json) + if (elem->recursive_descent && json != NULL) { json_foreach(child, json) { @@ -513,6 +525,13 @@ jp_match_callback(List **results, JPRef * ref) *results = lappend(*results, ref); } +/* + * jp_match + * Match a parsed JSONPath expression against a JSON tree, + * yielding a List of JPRef* items. + * + * To convert the JPRef* items to JSON-formatted strings, use jpref_encode. + */ List * jp_match(JSONPath * jp, JSON * json) { @@ -538,6 +557,15 @@ jp_set_callback(JSON * value, JPRef * ref) } } +/* + * jp_set + * Set all elements that match a parsed JSONPath expression + * in a JSON tree to a new value. + * + * Note that jp_set uses json_replace_value so it doesn't have to deep-copy + * on every assignment if @value is a tree. This means that parent pointers + * of the resulting tree will not be trustworthy. + */ void jp_set(JSONPath * jp, JSON * json, JSON * value) { @@ -546,6 +574,10 @@ jp_set(JSONPath * jp, JSON * json, JSON * value) match_recurse((void *) jp_set_callback, value, lc, mkRefNode(json)); } +/* + * jpref_encode + * Convert a JPRef to a JSON-formatted string. + */ char * jpref_encode(JPRef * ref) { -- cgit v1.2.3