Enable optional object/array members in json_pack()

This commit is contained in:
Nathaniel McCallum 2017-04-18 11:05:38 -04:00
parent 74028ff958
commit 28666cead0
3 changed files with 64 additions and 2 deletions

View File

@ -1269,6 +1269,14 @@ arguments.
.. versionadded:: 2.8 .. versionadded:: 2.8
``s*`` (string) [const char \*]
Like ``s``, but if the argument is *NULL*, do not output any value.
This format can only be used inside an object or an array. If used
inside an object, the corresponding key is additionally suppressed
when the value is omitted. See below for an example.
.. versionadded:: 2.11
``s#`` (string) [const char \*, int] ``s#`` (string) [const char \*, int]
Convert a UTF-8 buffer of a given length to a JSON string. Convert a UTF-8 buffer of a given length to a JSON string.
@ -1324,11 +1332,20 @@ arguments.
yourself. yourself.
``o?``, ``O?`` (any value) [json_t \*] ``o?``, ``O?`` (any value) [json_t \*]
Like ``o`` and ``O?``, respectively, but if the argument is Like ``o`` and ``O``, respectively, but if the argument is
*NULL*, output a JSON null value. *NULL*, output a JSON null value.
.. versionadded:: 2.8 .. versionadded:: 2.8
``o*``, ``O*`` (any value) [json_t \*]
Like ``o`` and ``O``, respectively, but if the argument is
*NULL*, do not output any value. This format can only be used
inside an object or an array. If used inside an object, the
corresponding key is additionally suppressed. See below for an
example.
.. versionadded:: 2.11
``[fmt]`` (array) ``[fmt]`` (array)
Build an array with contents from the inner format string. ``fmt`` Build an array with contents from the inner format string. ``fmt``
may contain objects and arrays, i.e. recursive value building is may contain objects and arrays, i.e. recursive value building is
@ -1387,6 +1404,10 @@ More examples::
/* Concatenate strings together to build the JSON string "foobarbaz" */ /* Concatenate strings together to build the JSON string "foobarbaz" */
json_pack("s++", "foo", "bar", "baz"); json_pack("s++", "foo", "bar", "baz");
/* Create an empty object or array when optional members are missing */
json_pack("{s:s*,s:o*,s:O*}", "foo", NULL, "bar", NULL, "baz", NULL);
json_pack("[s*,o*,O*]", NULL, NULL, NULL);
.. _apiref-unpack: .. _apiref-unpack:

View File

@ -235,6 +235,12 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
if(ours) if(ours)
jsonp_free(key); jsonp_free(key);
if(strchr("soO", token(s)) && s->next_token.token == '*') {
next_token(s);
next_token(s);
continue;
}
goto error; goto error;
} }
@ -249,6 +255,8 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
if(ours) if(ours)
jsonp_free(key); jsonp_free(key);
if(strchr("soO", token(s)) && s->next_token.token == '*')
next_token(s);
next_token(s); next_token(s);
} }
@ -273,14 +281,23 @@ static json_t *pack_array(scanner_t *s, va_list *ap)
} }
value = pack(s, ap); value = pack(s, ap);
if(!value) if(!value) {
if(strchr("soO", token(s)) && s->next_token.token == '*') {
next_token(s);
next_token(s);
continue;
}
goto error; goto error;
}
if(json_array_append_new(array, value)) { if(json_array_append_new(array, value)) {
set_error(s, "<internal>", "Unable to append to array"); set_error(s, "<internal>", "Unable to append to array");
goto error; goto error;
} }
if(strchr("soO", token(s)) && s->next_token.token == '*')
next_token(s);
next_token(s); next_token(s);
} }
return array; return array;

View File

@ -240,6 +240,18 @@ static void run_tests()
fail("json_pack object refcount failed"); fail("json_pack object refcount failed");
json_decref(value); json_decref(value);
/* object with optional members */
value = json_pack("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL);
if(value)
fail("json_pack object optional incorrectly succeeded");
value = json_pack("{s:**}", "a", NULL);
if(value)
fail("json_pack object optional invalid incorrectly succeeded");
value = json_pack("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL);
if(!json_is_object(value) || json_object_size(value) != 0)
fail("json_pack object optional failed");
json_decref(value);
/* simple array */ /* simple array */
value = json_pack("[i,i,i]", 0, 1, 2); value = json_pack("[i,i,i]", 0, 1, 2);
if(!json_is_array(value) || json_array_size(value) != 3) if(!json_is_array(value) || json_array_size(value) != 3)
@ -253,6 +265,18 @@ static void run_tests()
} }
json_decref(value); json_decref(value);
/* simple array with optional members */
value = json_pack("[s,o,O]", NULL, NULL, NULL);
if(value)
fail("json_pack array optional incorrectly succeeded");
value = json_pack("[**]", NULL);
if(value)
fail("json_pack array optional invalid incorrectly succeeded");
value = json_pack("[s*,o*,O*]", NULL, NULL, NULL);
if(!json_is_array(value) || json_array_size(value) != 0)
fail("json_pack array optional failed");
json_decref(value);
/* Whitespace; regular string */ /* Whitespace; regular string */
value = json_pack(" s ", "test"); value = json_pack(" s ", "test");
if(!json_is_string(value) || strcmp("test", json_string_value(value))) if(!json_is_string(value) || strcmp("test", json_string_value(value)))