aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathaniel McCallum <npmccallum@redhat.com>2017-01-26 17:23:31 +0100
committerNathaniel McCallum <npmccallum@redhat.com>2017-01-27 09:15:18 +0100
commit1672bb5a65b711d84c8adb12144bb997a4da02d4 (patch)
tree97ea7f5edc6348c3b669985ccfbbca13a4cc6a38
parentb900967f6fbfae098ced9dfeab7b2b51e1a22c0a (diff)
downloadjansson-1672bb5a65b711d84c8adb12144bb997a4da02d4.zip
jansson-1672bb5a65b711d84c8adb12144bb997a4da02d4.tar.gz
jansson-1672bb5a65b711d84c8adb12144bb997a4da02d4.tar.bz2
Implement json_dumpfd() and json_loadfd()
The primary use of these functions is easy loading and dumping from stream sockets. Signed-off-by: Nathaniel McCallum <npmccallum@redhat.com>
-rw-r--r--doc/apiref.rst48
-rw-r--r--src/dump.c21
-rw-r--r--src/jansson.def2
-rw-r--r--src/jansson.h2
-rw-r--r--src/jansson_private.h1
-rw-r--r--src/load.c45
-rw-r--r--test/suites/api/test_dump.c48
-rw-r--r--test/suites/api/test_load.c6
8 files changed, 166 insertions, 7 deletions
diff --git a/doc/apiref.rst b/doc/apiref.rst
index 839bb68..f104ad5 100644
--- a/doc/apiref.rst
+++ b/doc/apiref.rst
@@ -978,6 +978,23 @@ These functions output UTF-8:
*output*. In this case, the output is undefined and most likely not
valid JSON.
+.. function:: int json_dumpfd(const json_t *json, int output, size_t flags)
+
+ Write the JSON representation of *json* to the stream *output*.
+ *flags* is described above. Returns 0 on success and -1 on error.
+ If an error occurs, something may have already been written to
+ *output*. In this case, the output is undefined and most likely not
+ valid JSON.
+
+ It is important to note that this function can only succeed on stream
+ file descriptors (such as SOCK_STREAM). Using this function on a
+ non-stream file descriptor will result in undefined behavior. For
+ non-stream file descriptors, see instead :func:`json_dumpb()`.
+
+ This function requires POSIX and fails on all non-POSIX systems.
+
+ .. versionadded:: 2.10
+
.. function:: int json_dump_file(const json_t *json, const char *path, size_t flags)
Write the JSON representation of *json* to the file *path*. If
@@ -1133,7 +1150,7 @@ If no error or position information is needed, you can pass *NULL*.
above.
This function will start reading the input from whatever position
- the input file was, without attempting to seek first. If an error
+ the input file was in, without attempting to seek first. If an error
occurs, the file position will be left indeterminate. On success,
the file position will be at EOF, unless ``JSON_DISABLE_EOF_CHECK``
flag was used. In this case, the file position will be at the first
@@ -1142,6 +1159,35 @@ If no error or position information is needed, you can pass *NULL*.
multiple times, if the input consists of consecutive JSON texts,
possibly separated by whitespace.
+.. function:: json_t *json_loadfd(int input, size_t flags, json_error_t *error)
+
+ .. refcounting:: new
+
+ Decodes the JSON text in stream *input* and returns the array or
+ object it contains, or *NULL* on error, in which case *error* is
+ filled with information about the error. *flags* is described
+ above.
+
+ This function will start reading the input from whatever position
+ the input file descriptor was in, without attempting to seek first.
+ If an error occurs, the file position will be left indeterminate.
+ On success, the file position will be at EOF, unless
+ ``JSON_DISABLE_EOF_CHECK`` flag was used. In this case, the file
+ descriptor's position will be at the first character after the last
+ ``]`` or ``}`` in the JSON input. This allows calling
+ :func:`json_loadfd()` on the same file descriptor multiple times,
+ if the input consists of consecutive JSON texts, possibly separated
+ by whitespace.
+
+ It is important to note that this function can only succeed on stream
+ file descriptors (such as SOCK_STREAM). Using this function on a
+ non-stream file descriptor will result in undefined behavior. For
+ non-stream file descriptors, see instead :func:`json_loadb()`.
+
+ This function requires POSIX and fails on all non-POSIX systems.
+
+ .. versionadded:: 2.10
+
.. function:: json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
.. refcounting:: new
diff --git a/src/dump.c b/src/dump.c
index 4d97a6a..cac2790 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -9,13 +9,17 @@
#define _GNU_SOURCE
#endif
+#include "jansson_private.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
#include "jansson.h"
-#include "jansson_private.h"
#include "strbuffer.h"
#include "utf.h"
@@ -55,6 +59,16 @@ static int dump_to_file(const char *buffer, size_t size, void *data)
return 0;
}
+static int dump_to_fd(const char *buffer, size_t size, void *data)
+{
+ int *dest = (int *)data;
+#ifdef HAVE_UNISTD_H
+ if(write(*dest, buffer, size) == (ssize_t)size)
+ return 0;
+#endif
+ return -1;
+}
+
/* 32 spaces (the maximum indentation size) */
static const char whitespace[] = " ";
@@ -448,6 +462,11 @@ int json_dumpf(const json_t *json, FILE *output, size_t flags)
return json_dump_callback(json, dump_to_file, (void *)output, flags);
}
+int json_dumpfd(const json_t *json, int output, size_t flags)
+{
+ return json_dump_callback(json, dump_to_fd, (void *)&output, flags);
+}
+
int json_dump_file(const json_t *json, const char *path, size_t flags)
{
int result;
diff --git a/src/jansson.def b/src/jansson.def
index 55cb117..cbebefb 100644
--- a/src/jansson.def
+++ b/src/jansson.def
@@ -50,11 +50,13 @@ EXPORTS
json_dumps
json_dumpb
json_dumpf
+ json_dumpfd
json_dump_file
json_dump_callback
json_loads
json_loadb
json_loadf
+ json_loadfd
json_load_file
json_load_callback
json_equal
diff --git a/src/jansson.h b/src/jansson.h
index 74f11a0..b5a4d15 100644
--- a/src/jansson.h
+++ b/src/jansson.h
@@ -273,6 +273,7 @@ typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
json_t *json_loads(const char *input, size_t flags, json_error_t *error);
json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error);
json_t *json_loadf(FILE *input, size_t flags, json_error_t *error);
+json_t *json_loadfd(int input, size_t flags, json_error_t *error);
json_t *json_load_file(const char *path, size_t flags, json_error_t *error);
json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error);
@@ -294,6 +295,7 @@ typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data)
char *json_dumps(const json_t *json, size_t flags);
size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags);
int json_dumpf(const json_t *json, FILE *output, size_t flags);
+int json_dumpfd(const json_t *json, int output, size_t flags);
int json_dump_file(const json_t *json, const char *path, size_t flags);
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags);
diff --git a/src/jansson_private.h b/src/jansson_private.h
index 4a4927b..5ed9615 100644
--- a/src/jansson_private.h
+++ b/src/jansson_private.h
@@ -8,6 +8,7 @@
#ifndef JANSSON_PRIVATE_H
#define JANSSON_PRIVATE_H
+#include "jansson_private_config.h"
#include <stddef.h>
#include "jansson.h"
#include "hashtable.h"
diff --git a/src/load.c b/src/load.c
index 7a50743..c212489 100644
--- a/src/load.c
+++ b/src/load.c
@@ -9,15 +9,19 @@
#define _GNU_SOURCE
#endif
+#include "jansson_private.h"
+
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
#include "jansson.h"
-#include "jansson_private.h"
#include "strbuffer.h"
#include "utf.h"
@@ -1028,6 +1032,45 @@ json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
return result;
}
+static int fd_get_func(int *fd)
+{
+ uint8_t c;
+#ifdef HAVE_UNISTD_H
+ if (read(*fd, &c, 1) == 1)
+ return c;
+#endif
+ return EOF;
+}
+
+json_t *json_loadfd(int input, size_t flags, json_error_t *error)
+{
+ lex_t lex;
+ const char *source;
+ json_t *result;
+
+#ifdef HAVE_UNISTD_H
+ if(input == STDIN_FILENO)
+ source = "<stdin>";
+ else
+#endif
+ source = "<stream>";
+
+ jsonp_error_init(error, source);
+
+ if (input < 0) {
+ error_set(error, NULL, "wrong arguments");
+ return NULL;
+ }
+
+ if(lex_init(&lex, (get_func)fd_get_func, flags, &input))
+ return NULL;
+
+ result = parse_json(&lex, flags, error);
+
+ lex_close(&lex);
+ return result;
+}
+
json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
{
json_t *result;
diff --git a/test/suites/api/test_dump.c b/test/suites/api/test_dump.c
index e528031..8d59d40 100644
--- a/test/suites/api/test_dump.c
+++ b/test/suites/api/test_dump.c
@@ -5,8 +5,13 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
+#include "jansson_private_config.h"
+
#include <jansson.h>
#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
#include "util.h"
static int encode_null_callback(const char *buffer, size_t size, void *data)
@@ -28,6 +33,11 @@ static void encode_null()
if(json_dumpf(NULL, stderr, JSON_ENCODE_ANY) != -1)
fail("json_dumpf didn't fail for NULL");
+#ifdef HAVE_UNISTD_H
+ if(json_dumpfd(NULL, STDERR_FILENO, JSON_ENCODE_ANY) != -1)
+ fail("json_dumpfd didn't fail for NULL");
+#endif
+
/* Don't test json_dump_file to avoid creating a file */
if(json_dump_callback(NULL, encode_null_callback, NULL, JSON_ENCODE_ANY) != -1)
@@ -127,14 +137,15 @@ static void encode_other_than_array_or_object()
* succeed if the JSON_ENCODE_ANY flag is used */
json_t *json;
- FILE *fp = NULL;
char *result;
json = json_string("foo");
if(json_dumps(json, 0) != NULL)
fail("json_dumps encoded a string!");
- if(json_dumpf(json, fp, 0) == 0)
+ if(json_dumpf(json, NULL, 0) == 0)
fail("json_dumpf encoded a string!");
+ if(json_dumpfd(json, -1, 0) == 0)
+ fail("json_dumpfd encoded a string!");
result = json_dumps(json, JSON_ENCODE_ANY);
if(!result || strcmp(result, "\"foo\"") != 0)
@@ -146,8 +157,10 @@ static void encode_other_than_array_or_object()
json = json_integer(42);
if(json_dumps(json, 0) != NULL)
fail("json_dumps encoded an integer!");
- if(json_dumpf(json, fp, 0) == 0)
+ if(json_dumpf(json, NULL, 0) == 0)
fail("json_dumpf encoded an integer!");
+ if(json_dumpfd(json, -1, 0) == 0)
+ fail("json_dumpfd encoded an integer!");
result = json_dumps(json, JSON_ENCODE_ANY);
if(!result || strcmp(result, "42") != 0)
@@ -237,6 +250,34 @@ static void dumpb()
json_decref(obj);
}
+static void dumpfd()
+{
+#ifdef HAVE_UNISTD_H
+ int fds[2] = {-1, -1};
+ json_t *a, *b;
+
+ if(pipe(fds))
+ fail("pipe() failed");
+
+ a = json_pack("{s:s}", "foo", "bar");
+
+ if(json_dumpfd(a, fds[1], 0))
+ fail("json_dumpfd() failed");
+ close(fds[1]);
+
+ b = json_loadfd(fds[0], 0, NULL);
+ if (!b)
+ fail("json_loadfd() failed");
+ close(fds[0]);
+
+ if (!json_equal(a, b))
+ fail("json_equal() failed for fd test");
+
+ json_decref(a);
+ json_decref(b);
+#endif
+}
+
static void run_tests()
{
encode_null();
@@ -247,4 +288,5 @@ static void run_tests()
encode_nul_byte();
dump_file();
dumpb();
+ dumpfd();
}
diff --git a/test/suites/api/test_load.c b/test/suites/api/test_load.c
index 9b9f5f4..3416af1 100644
--- a/test/suites/api/test_load.c
+++ b/test/suites/api/test_load.c
@@ -180,9 +180,13 @@ static void load_wrong_args()
if (json)
fail("json_loadf should return NULL if the first argument is NULL");
+ json = json_loadfd(-1, 0, &error);
+ if (json)
+ fail("json_loadfd should return NULL if the first argument is < 0");
+
json = json_load_file(NULL, 0, &error);
if (json)
- fail("json_loadf should return NULL if the first argument is NULL");
+ fail("json_load_file should return NULL if the first argument is NULL");
}
static void position()