summaryrefslogtreecommitdiff
path: root/jsonpath.c
diff options
context:
space:
mode:
authorJoey Adams2010-07-23 22:01:36 +0000
committerJoey Adams2010-07-23 22:01:36 +0000
commit8a019e04b817ffca00ec9759f3d12c60c808e67f (patch)
tree59846b7f57946d2b2c9a9208a34435e2ef43a178 /jsonpath.c
parentf5cbbbe875326dbe5d0c43bc3c692f64f77a30bd (diff)
Ran pg_indent and made a few purely cosmetic changes (before running pg_indent again).
Diffstat (limited to 'jsonpath.c')
-rw-r--r--jsonpath.c297
1 files changed, 183 insertions, 114 deletions
diff --git a/jsonpath.c b/jsonpath.c
index b3a0b76..361c996 100644
--- a/jsonpath.c
+++ b/jsonpath.c
@@ -6,7 +6,7 @@
/* NB: These macros evaluate their argument multiple times. */
#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
- /* isalpha() is locale-specific. This simply matches [A-Za-z] . */
+ /* isalpha() is locale-specific. This simply matches [A-Za-z] . */
#define isextended(c) ((unsigned char)(c) > 127)
/* Note that Unicode characters are allowed in identifiers. */
@@ -23,10 +23,11 @@
* This function returns the first cell,
* making sure it is of type JP_ROOT.
*/
-static ListCell *jp_root(JSONPath *jp)
+static ListCell *
+jp_root(JSONPath * jp)
{
- ListCell *cell;
- jp_element *elem;
+ ListCell *cell;
+ jp_element *elem;
Assert(jp != NULL);
@@ -41,7 +42,8 @@ static ListCell *jp_root(JSONPath *jp)
* This function returns the second cell of a JSONPath list
* (the first cell after the JP_ROOT).
*/
-static ListCell *jp_head(JSONPath *jp)
+static ListCell *
+jp_head(JSONPath * jp)
{
return lnext(jp_root(jp));
}
@@ -53,93 +55,116 @@ static ListCell *jp_head(JSONPath *jp)
* whitespace, but since this is JSONPath,
* we can do whatever we want here :-)
*/
-static void skip_spaces(const char **sp)
+static void
+skip_spaces(const char **sp)
{
const char *s = *sp;
+
while (isspace(*s))
s++;
*sp = s;
}
-static jp_element *mkElement(jp_element_type type, bool rd)
+static jp_element *
+mkElement(jp_element_type type, bool rd)
{
jp_element *elem = palloc0(sizeof(*elem));
+
elem->type = type;
elem->recursive_descent = rd;
return elem;
}
-static jp_element *mkRoot(void)
+static jp_element *
+mkRoot(void)
{
jp_element *elem = mkElement(JP_ROOT, false);
+
return elem;
}
-static jp_element *mkWildcard(bool rd)
+static jp_element *
+mkWildcard(bool rd)
{
jp_element *elem = mkElement(JP_WILDCARD, rd);
+
return elem;
}
-static jp_element *mkIndexSubscript(long index, bool rd)
+static jp_element *
+mkIndexSubscript(long index, bool rd)
{
jp_element *elem = mkElement(JP_INDEX_SUBSCRIPT, rd);
+
elem->data.index = index;
return elem;
}
-static jp_element *mkKeySubscript(char *key, size_t length, bool rd)
+static jp_element *
+mkKeySubscript(char *key, size_t length, bool rd)
{
jp_element *elem = mkElement(JP_KEY_SUBSCRIPT, rd);
+
elem->data.key.ptr = key;
elem->data.key.length = length;
return elem;
}
-static jp_element *mkCallChar(long index, bool rd)
+static jp_element *
+mkCallChar(long index, bool rd)
{
jp_element *elem = mkElement(JP_CALL_CHAR, rd);
+
elem->data.index = index;
return elem;
}
-static JPRef *mkRef(JPRefType type)
+static JPRef *
+mkRef(JPRefType type)
{
- JPRef *ref = palloc0(sizeof(*ref));
+ JPRef *ref = palloc0(sizeof(*ref));
+
ref->type = type;
return ref;
}
-static JPRef *mkRefNode(json_node *node)
+static JPRef *
+mkRefNode(json_node * node)
{
- JPRef *ref = mkRef(JP_REF_NODE);
+ JPRef *ref = mkRef(JP_REF_NODE);
+
ref->u.node = node;
return ref;
}
-static JPRef *mkRefChar(const char *bytes, size_t length)
+static JPRef *
+mkRefChar(const char *bytes, size_t length)
{
- JPRef *ref = mkRef(JP_REF_CHAR);
- ref->u.chr.bytes = bytes;
- ref->u.chr.length = length;
+ JPRef *ref = mkRef(JP_REF_CHAR);
+ ref->u.chr. bytes = bytes;
+ ref->u.chr. length = length;
+
return ref;
}
-char *jp_show(JSONPath *jp)
+char *
+jp_show(JSONPath * jp)
{
- StringInfoData string[1];
- ListCell *cell;
- jp_element *elem;
- bool rd;
- char *tmp;
+ StringInfoData string[1];
+ ListCell *cell;
+ jp_element *elem;
+ bool rd;
+ char *tmp;
initStringInfo(string);
- foreach(cell, jp) {
+ foreach(cell, jp)
+ {
elem = lfirst(cell);
- rd = elem->recursive_descent;
+ rd = elem->recursive_descent;
- switch (elem->type) {
+ switch (elem->type)
+ {
case JP_ROOT:
appendStringInfoChar(string, '$');
break;
@@ -166,12 +191,13 @@ char *jp_show(JSONPath *jp)
return string->data;
}
-static bool parse_long(const char **s, long *out)
+static bool
+parse_long(const char **s, long *out)
{
const char *p = *s;
errno = 0;
- *out = strtol(*s, (char**)&p, 10);
+ *out = strtol(*s, (char **) &p, 10);
if (p <= *s || errno != 0)
return false;
@@ -179,34 +205,39 @@ static bool parse_long(const char **s, long *out)
return true;
}
-JSONPath *jp_parse(const char *pattern)
+JSONPath *
+jp_parse(const char *pattern)
{
- JSONPath *jp = NIL;
- const char *s = pattern;
- const char *start;
- const char *end;
- bool recursive_descent = false;
- bool bracket = false;
- const char *err_msg = NULL;
+ JSONPath *jp = NIL;
+ const char *s = pattern;
+ const char *start;
+ const char *end;
+ bool recursive_descent = false;
+ bool bracket = false;
+ const char *err_msg = NULL;
long index;
- char *key;
+ char *key;
size_t key_length;
-
+
skip_spaces(&s);
-
+
/* pattern may not be empty */
if (!*s)
return NULL;
-
+
jp = lappend(jp, mkRoot());
-
- if (*s == '$') {
+
+ if (*s == '$')
+ {
s++;
goto begin_element;
- } else if (*s != '.') {
- goto dot_subscript; // implicit '.' at beginning
}
-
+ else if (*s != '.')
+ {
+ goto dot_subscript;
+ /* implicit '.' at beginning */
+ }
+
begin_element:
skip_spaces(&s);
begin_element_noskip:
@@ -216,16 +247,19 @@ begin_element_noskip:
if (*s == '\0')
goto end;
- if (s[0] == '.' && s[1] == '.') {
+ if (s[0] == '.' && s[1] == '.')
+ {
recursive_descent = true;
s += 2;
goto dot_subscript;
}
- if (s[0] == '.') {
+ if (s[0] == '.')
+ {
s++;
goto dot_subscript;
}
- if (s[0] == '[') {
+ if (s[0] == '[')
+ {
s++;
goto bracket_subscript;
}
@@ -233,7 +267,8 @@ begin_element_noskip:
goto failed;
next_element:
- if (bracket) {
+ if (bracket)
+ {
skip_spaces(&s);
if (*s != ']')
goto failed;
@@ -243,7 +278,7 @@ next_element:
dot_subscript:
skip_spaces(&s);
-
+
if (*s == '*')
goto wildcard;
if (integer_start(*s))
@@ -252,7 +287,8 @@ dot_subscript:
goto identifier;
if (*s == '"' || *s == '\'')
goto string;
- if (*s == '[') {
+ if (*s == '[')
+ {
s++;
goto bracket_subscript;
}
@@ -268,13 +304,14 @@ bracket_subscript:
goto wildcard;
if (integer_start(*s))
goto integer;
- if (identifier_start(*s)) {
+ if (identifier_start(*s))
+ {
err_msg = "Identifiers may not be bracketed. This syntax is reserved for future use.";
goto failed;
}
if (*s == '"' || *s == '\'')
goto string;
-
+
goto failed;
wildcard:
@@ -285,7 +322,7 @@ wildcard:
integer:
if (!parse_long(&s, &index))
goto failed;
-
+
jp = lappend(jp, mkIndexSubscript(index, recursive_descent));
goto next_element;
@@ -297,7 +334,8 @@ identifier:
skip_spaces(&s);
- if (*s == '(') {
+ if (*s == '(')
+ {
if (end - start == 4 && !memcmp(start, "char", 4))
{
s++;
@@ -318,7 +356,7 @@ string:
key = json_decode_string(&s, &key_length, false);
if (!key)
goto failed;
-
+
jp = lappend(jp, mkKeySubscript(key, key_length, recursive_descent));
goto next_element;
@@ -341,34 +379,40 @@ failed:
return NULL;
}
-static size_t utf8_substring(
- const char *src, size_t srcbytes,
- size_t start, size_t length,
- const char **out_start, size_t *out_bytes)
+static size_t
+utf8_substring(
+ const char *src, size_t srcbytes,
+ size_t start, size_t length,
+ const char **out_start, size_t *out_bytes)
{
- const char *e = src + srcbytes;
- const char *sub_start;
- const char *sub_end;
+ const char *e = src + srcbytes;
+ const char *sub_start;
+ const char *sub_end;
size_t sub_length;
sub_start = src;
- while (start > 0 && sub_start < e) {
- sub_start += pg_utf_mblen((const unsigned char*)sub_start);
+ while (start > 0 && sub_start < e)
+ {
+ sub_start += pg_utf_mblen((const unsigned char *) sub_start);
start--;
}
sub_end = sub_start;
sub_length = 0;
- while (sub_length < length && sub_end < e) {
- sub_end += pg_utf_mblen((const unsigned char*)sub_end);
+ while (sub_length < length && sub_end < e)
+ {
+ sub_end += pg_utf_mblen((const unsigned char *) sub_end);
sub_length++;
}
/* Make sure the input didn't have a clipped UTF-8 character */
- if(sub_start > e) {
+ if (sub_start > e)
+ {
Assert(false);
sub_start = sub_end = e;
- } else if (sub_end > e) {
+ }
+ else if (sub_end > e)
+ {
Assert(false);
sub_end = e;
}
@@ -385,13 +429,15 @@ JPRef could merged with json_node by adding JPRef's specialty types to the
json_type enum and json_node union. JPRef is currently not merged with
json_node in an attempt to keep the codebase tidy and easier to extend.
*/
-static void match_recurse(void on_match(void *ctx, JPRef *ref), void *ctx,
- ListCell *path, JPRef *ref)
+static void match_recurse(void on_match(void *ctx, JPRef * ref), void *ctx,
+ ListCell *path, JPRef * ref)
{
- jp_element *elem;
- json_node *json, *child;
+ jp_element *elem;
+ json_node *json,
+ *child;
- if (path == NULL) {
+ if (path == NULL)
+ {
/* The end of the JSONPath list is the "accept" state. */
on_match(ctx, ref);
return;
@@ -404,30 +450,39 @@ static void match_recurse(void on_match(void *ctx, JPRef *ref), void *ctx,
else
json = NULL;
- switch (elem->type) {
+ switch (elem->type)
+ {
case JP_WILDCARD:
- if (json) {
+ if (json)
+ {
json_foreach(child, json)
match_recurse(on_match, ctx, lnext(path), mkRefNode(child));
}
break;
case JP_INDEX_SUBSCRIPT:
- if (json && json->type == JSON_ARRAY) {
- 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) {
+ if (json && json->type == JSON_ARRAY)
+ {
+ 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 < index;
+ 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. */
+ /*
+ * If this fails, it means json->v.children.count was
+ * greater than the actual number of children.
+ */
Assert(i == index && child != NULL);
match_recurse(on_match, ctx, lnext(path), mkRefNode(child));
@@ -436,8 +491,10 @@ static void match_recurse(void on_match(void *ctx, JPRef *ref), void *ctx,
break;
case JP_KEY_SUBSCRIPT:
- if (json && json->type == JSON_OBJECT) {
- json_foreach(child, json) {
+ if (json && 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))
@@ -449,19 +506,22 @@ 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) {
- const char *sub_start;
- size_t sub_bytes;
- size_t sub_length;
+ if (json && json->type == JSON_STRING && elem->data.index >= 0)
+ {
+ const char *sub_start;
+ size_t sub_bytes;
+ size_t sub_length;
sub_length = utf8_substring(
- json->v.string.str, json->v.string.length,
- elem->data.index, 1,
- &sub_start, &sub_bytes);
+ json->v.string.str, json->v.string.length,
+ elem->data.index, 1,
+ &sub_start, &sub_bytes);
if (sub_length == 1)
match_recurse(on_match, ctx, lnext(path), mkRefChar(sub_start, sub_bytes));
- } else if (ref->type == JP_REF_CHAR && elem->data.index == 0) {
+ }
+ else if (ref->type == JP_REF_CHAR && elem->data.index == 0)
+ {
/* char(0) on a character yields itself. */
match_recurse(on_match, ctx, lnext(path), ref);
}
@@ -470,51 +530,60 @@ static void match_recurse(void on_match(void *ctx, JPRef *ref), void *ctx,
default:;
}
- if (elem->recursive_descent && json) {
- json_foreach(child, json) {
+ if (elem->recursive_descent && json)
+ {
+ json_foreach(child, json)
+ {
if (!child->jp_changed)
match_recurse(on_match, ctx, path, mkRefNode(child));
}
}
}
-static void jp_match_callback(List **results, JPRef *ref)
+static void
+jp_match_callback(List **results, JPRef * ref)
{
*results = lappend(*results, ref);
}
-List *jp_match(JSONPath *jp, json_node *json)
+List *
+jp_match(JSONPath * jp, json_node * json)
{
- ListCell *lc = jp_head(jp);
- List *results = NIL;
+ ListCell *lc = jp_head(jp);
+ List *results = NIL;
- match_recurse((void*)jp_match_callback, &results, lc, mkRefNode(json));
+ match_recurse((void *) jp_match_callback, &results, lc, mkRefNode(json));
return results;
}
-static void jp_set_callback(json_node *value, JPRef *ref)
+static void
+jp_set_callback(json_node * value, JPRef * ref)
{
- switch (ref->type) {
+ switch (ref->type)
+ {
case JP_REF_NODE:
json_replace_value(ref->u.node, value);
ref->u.node->jp_changed = true;
break;
- default:; /* Do nothing if ref is immutable. */
+ default:; /* Do nothing if ref is immutable. */
}
}
-void jp_set(JSONPath *jp, json_node *json, json_node *value)
+void
+jp_set(JSONPath * jp, json_node * json, json_node * value)
{
- ListCell *lc = jp_head(jp);
+ ListCell *lc = jp_head(jp);
- match_recurse((void*)jp_set_callback, value, lc, mkRefNode(json));
+ match_recurse((void *) jp_set_callback, value, lc, mkRefNode(json));
}
-char *jpref_encode(JPRef *ref)
+char *
+jpref_encode(JPRef * ref)
{
- switch (ref->type) {
+ switch (ref->type)
+ {
case JP_REF_NODE:
return json_encode(ref->u.node, JSONOPT_USE_ORIG);