Adds json_pack / json_unpack variadic functions.
This commit is contained in:
parent
1acd1a7b56
commit
198d537be7
@ -11,7 +11,8 @@ libjansson_la_SOURCES = \
|
|||||||
strbuffer.h \
|
strbuffer.h \
|
||||||
utf.c \
|
utf.c \
|
||||||
utf.h \
|
utf.h \
|
||||||
value.c
|
value.c \
|
||||||
|
variadic.c
|
||||||
libjansson_la_LDFLAGS = \
|
libjansson_la_LDFLAGS = \
|
||||||
-export-symbols-regex '^json_' \
|
-export-symbols-regex '^json_' \
|
||||||
-version-info 3:0:3
|
-version-info 3:0:3
|
||||||
|
@ -85,6 +85,14 @@ void json_decref(json_t *json)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* error reporting */
|
||||||
|
|
||||||
|
typedef struct json_error_t json_error_t;
|
||||||
|
|
||||||
|
const char *json_error_msg(const json_error_t *error);
|
||||||
|
int json_error_line(const json_error_t *error);
|
||||||
|
|
||||||
|
|
||||||
/* getters, setters, manipulation */
|
/* getters, setters, manipulation */
|
||||||
|
|
||||||
size_t json_object_size(const json_t *object);
|
size_t json_object_size(const json_t *object);
|
||||||
@ -156,6 +164,8 @@ int json_string_set_nocheck(json_t *string, const char *value);
|
|||||||
int json_integer_set(json_t *integer, json_int_t value);
|
int json_integer_set(json_t *integer, json_int_t value);
|
||||||
int json_real_set(json_t *real, double value);
|
int json_real_set(json_t *real, double value);
|
||||||
|
|
||||||
|
json_t *json_pack(json_error_t **error, const char *fmt, ...);
|
||||||
|
int json_unpack(json_t *root, json_error_t **error, const char *fmt, ...);
|
||||||
|
|
||||||
/* equality */
|
/* equality */
|
||||||
|
|
||||||
@ -168,14 +178,6 @@ json_t *json_copy(json_t *value);
|
|||||||
json_t *json_deep_copy(json_t *value);
|
json_t *json_deep_copy(json_t *value);
|
||||||
|
|
||||||
|
|
||||||
/* error reporting */
|
|
||||||
|
|
||||||
typedef struct json_error_t json_error_t;
|
|
||||||
|
|
||||||
const char *json_error_msg(const json_error_t *error);
|
|
||||||
int json_error_line(const json_error_t *error);
|
|
||||||
|
|
||||||
|
|
||||||
/* loading, printing */
|
/* loading, printing */
|
||||||
|
|
||||||
json_t *json_loads(const char *input, size_t flags, json_error_t **error);
|
json_t *json_loads(const char *input, size_t flags, json_error_t **error);
|
||||||
|
@ -63,4 +63,11 @@ typedef struct {
|
|||||||
|
|
||||||
const object_key_t *jsonp_object_iter_fullkey(void *iter);
|
const object_key_t *jsonp_object_iter_fullkey(void *iter);
|
||||||
|
|
||||||
|
#define JSON_ERROR_MSG_LENGTH 160
|
||||||
|
|
||||||
|
struct json_error_t {
|
||||||
|
char msg[JSON_ERROR_MSG_LENGTH];
|
||||||
|
int line;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -60,13 +60,6 @@ typedef struct {
|
|||||||
|
|
||||||
/*** error reporting ***/
|
/*** error reporting ***/
|
||||||
|
|
||||||
#define JSON_ERROR_MSG_LENGTH 160
|
|
||||||
|
|
||||||
struct json_error_t {
|
|
||||||
char msg[JSON_ERROR_MSG_LENGTH];
|
|
||||||
int line;
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *json_error_msg(const json_error_t *error)
|
const char *json_error_msg(const json_error_t *error)
|
||||||
{
|
{
|
||||||
return error ? error->msg : NULL;
|
return error ? error->msg : NULL;
|
||||||
|
589
src/variadic.c
Normal file
589
src/variadic.c
Normal file
@ -0,0 +1,589 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
|
||||||
|
* Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
|
||||||
|
*
|
||||||
|
* Jansson is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <jansson.h>
|
||||||
|
#include "jansson_private.h"
|
||||||
|
|
||||||
|
static void error_init(json_error_t **error)
|
||||||
|
{
|
||||||
|
if(error)
|
||||||
|
*error = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void error_set(json_error_t **error, const int line, const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if(!error || *error)
|
||||||
|
return;
|
||||||
|
|
||||||
|
*error = calloc(1, sizeof(json_error_t));
|
||||||
|
if(!*error)
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_start(ap, msg);
|
||||||
|
vsnprintf((*error)->msg, JSON_ERROR_MSG_LENGTH, msg, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
va_start(ap, msg);
|
||||||
|
vfprintf(stderr, msg, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
(*error)->line = line;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_t *json_pack(json_error_t **error, const char *fmt, ...) {
|
||||||
|
int fmt_length = strlen(fmt);
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
/* Keep a stack of containers (lists and objects) */
|
||||||
|
int depth = 0;
|
||||||
|
json_t **stack = NULL;
|
||||||
|
|
||||||
|
/* Keep a list of objects we create in case of error */
|
||||||
|
int free_count = 0;
|
||||||
|
json_t **free_list = NULL;
|
||||||
|
|
||||||
|
json_t *cur = NULL; /* Current container */
|
||||||
|
json_t *root = NULL; /* root object */
|
||||||
|
json_t *obj = NULL;
|
||||||
|
|
||||||
|
char *key = NULL; /* Current key in an object */
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
int line = 1;
|
||||||
|
|
||||||
|
/* Allocation provisioned for worst case */
|
||||||
|
stack = calloc(fmt_length, sizeof(json_t *));
|
||||||
|
free_list = calloc(fmt_length, sizeof(json_t *));
|
||||||
|
|
||||||
|
error_init(error);
|
||||||
|
|
||||||
|
if(!stack || !free_list)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
while(*fmt) {
|
||||||
|
switch(*fmt) {
|
||||||
|
case '\n':
|
||||||
|
line++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ' ': /* Whitespace */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ',': /* Element spacer */
|
||||||
|
if(!root)
|
||||||
|
{
|
||||||
|
error_set(error, line,
|
||||||
|
"Unexpected COMMA precedes root element!");
|
||||||
|
root = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!cur)
|
||||||
|
{
|
||||||
|
error_set(error, line,
|
||||||
|
"Unexpected COMMA outside a list or object!");
|
||||||
|
root = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(key)
|
||||||
|
{
|
||||||
|
error_set(error, line, "Expected KEY, got COMMA!");
|
||||||
|
root = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ':': /* Key/value separator */
|
||||||
|
if(!key)
|
||||||
|
{
|
||||||
|
error_set(error, line, "Got key/value separator without "
|
||||||
|
"a key preceding it!");
|
||||||
|
root = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!json_is_object(cur))
|
||||||
|
{
|
||||||
|
error_set(error, line, "Got a key/value separator "
|
||||||
|
"(':') outside an object!");
|
||||||
|
root = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ']': /* Close array or object */
|
||||||
|
case '}':
|
||||||
|
|
||||||
|
if(key)
|
||||||
|
{
|
||||||
|
error_set(error, line, "OBJECT or ARRAY ended with an "
|
||||||
|
"incomplete key/value pair!");
|
||||||
|
root = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(depth <= 0)
|
||||||
|
{
|
||||||
|
error_set(error, line,
|
||||||
|
"Too many close-brackets '%c'", *fmt);
|
||||||
|
root = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*fmt == ']' && !json_is_array(cur))
|
||||||
|
{
|
||||||
|
error_set(error, line,
|
||||||
|
"Stray close-array ']' character");
|
||||||
|
root = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*fmt == '}' && !json_is_object(cur))
|
||||||
|
{
|
||||||
|
error_set(error, line,
|
||||||
|
"Stray close-object '}' character");
|
||||||
|
root = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = stack[--depth];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '[':
|
||||||
|
obj = json_array();
|
||||||
|
goto obj_common;
|
||||||
|
|
||||||
|
case '{':
|
||||||
|
obj = json_object();
|
||||||
|
goto obj_common;
|
||||||
|
|
||||||
|
case 's': /* string */
|
||||||
|
s = va_arg(ap, char*);
|
||||||
|
|
||||||
|
if(!s)
|
||||||
|
{
|
||||||
|
error_set(error, line,
|
||||||
|
"Refusing to handle a NULL string");
|
||||||
|
root = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(json_is_object(cur) && !key)
|
||||||
|
{
|
||||||
|
/* It's a key */
|
||||||
|
key = s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = json_string(s);
|
||||||
|
goto obj_common;
|
||||||
|
|
||||||
|
case 'n': /* null */
|
||||||
|
obj = json_null();
|
||||||
|
goto obj_common;
|
||||||
|
|
||||||
|
case 'b': /* boolean */
|
||||||
|
obj = va_arg(ap, int) ?
|
||||||
|
json_true() : json_false();
|
||||||
|
goto obj_common;
|
||||||
|
|
||||||
|
case 'i': /* integer */
|
||||||
|
obj = json_integer(va_arg(ap, int));
|
||||||
|
goto obj_common;
|
||||||
|
|
||||||
|
case 'f': /* double-precision float */
|
||||||
|
obj = json_real(va_arg(ap, double));
|
||||||
|
goto obj_common;
|
||||||
|
|
||||||
|
case 'O': /* a json_t object; increments refcount */
|
||||||
|
obj = va_arg(ap, json_t *);
|
||||||
|
json_incref(obj);
|
||||||
|
goto obj_common;
|
||||||
|
|
||||||
|
case 'o': /* a json_t object; doesn't increment refcount */
|
||||||
|
obj = va_arg(ap, json_t *);
|
||||||
|
goto obj_common;
|
||||||
|
|
||||||
|
obj_common: free_list[free_count++] = obj;
|
||||||
|
|
||||||
|
/* Root this object to its parent */
|
||||||
|
if(json_is_object(cur)) {
|
||||||
|
if(!key)
|
||||||
|
{
|
||||||
|
error_set(error, line,
|
||||||
|
"Expected key, got identifier '%c'!", *fmt);
|
||||||
|
root = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object_set_new(cur, key, obj);
|
||||||
|
key = NULL;
|
||||||
|
}
|
||||||
|
else if(json_is_array(cur))
|
||||||
|
{
|
||||||
|
json_array_append_new(cur, obj);
|
||||||
|
}
|
||||||
|
else if(!root)
|
||||||
|
{
|
||||||
|
printf("Rooting\n");
|
||||||
|
root = obj;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error_set(error, line, "Can't figure out where to attach "
|
||||||
|
"'%c' object!", *fmt);
|
||||||
|
root = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If it was a container ('[' or '{'), descend on the stack */
|
||||||
|
if(json_is_array(obj) || json_is_object(obj))
|
||||||
|
{
|
||||||
|
stack[depth++] = cur;
|
||||||
|
cur = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fmt++;
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if(depth != 0) {
|
||||||
|
error_set(error, line,
|
||||||
|
"Missing object or array close-brackets in format string");
|
||||||
|
root = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success: don't free everything we just built! */
|
||||||
|
free_count = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
while(free_count)
|
||||||
|
json_decref(free_list[--free_count]);
|
||||||
|
|
||||||
|
if(free_list)
|
||||||
|
free(free_list);
|
||||||
|
|
||||||
|
if(stack)
|
||||||
|
free(stack);
|
||||||
|
|
||||||
|
return(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_unpack(json_t *root, json_error_t **error, const char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
int rv=0; /* Return value */
|
||||||
|
int line = 1; /* Line number */
|
||||||
|
|
||||||
|
/* Keep a stack of containers (lists and objects) */
|
||||||
|
int depth = 0;
|
||||||
|
json_t **stack;
|
||||||
|
|
||||||
|
int array_index = 0;
|
||||||
|
char *key = NULL; /* Current key in an object */
|
||||||
|
|
||||||
|
json_t *cur = NULL; /* Current container */
|
||||||
|
json_t *obj = NULL;
|
||||||
|
|
||||||
|
int fmt_length = strlen(fmt);
|
||||||
|
|
||||||
|
error_init(error);
|
||||||
|
|
||||||
|
/* Allocation provisioned for worst case */
|
||||||
|
stack = calloc(fmt_length, sizeof(json_t *));
|
||||||
|
if(!stack)
|
||||||
|
{
|
||||||
|
error_set(error, line, "Out of memory!");
|
||||||
|
rv = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Even if we're successful, we need to know if the number of
|
||||||
|
* arguments provided matches the number of JSON objects.
|
||||||
|
* We can do this by counting the elements in every array or
|
||||||
|
* object we open up, and decrementing the count as we visit
|
||||||
|
* their children. */
|
||||||
|
int unvisited = 0;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
while(*fmt)
|
||||||
|
{
|
||||||
|
switch(*fmt)
|
||||||
|
{
|
||||||
|
case ' ': /* Whitespace */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\n': /* Line break */
|
||||||
|
line++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ',': /* Element spacer */
|
||||||
|
|
||||||
|
if(!cur)
|
||||||
|
{
|
||||||
|
error_set(error, line,
|
||||||
|
"Unexpected COMMA outside a list or object!");
|
||||||
|
rv = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(key)
|
||||||
|
{
|
||||||
|
error_set(error, line, "Expected KEY, got COMMA!");
|
||||||
|
rv = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ':': /* Key/value separator */
|
||||||
|
if(!json_is_object(cur) || !key)
|
||||||
|
{
|
||||||
|
error_set(error, line, "Unexpected ':'");
|
||||||
|
rv = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '[':
|
||||||
|
case '{':
|
||||||
|
/* Fetch object */
|
||||||
|
if(!cur)
|
||||||
|
{
|
||||||
|
obj = root;
|
||||||
|
}
|
||||||
|
else if(json_is_object(cur))
|
||||||
|
{
|
||||||
|
if(!key)
|
||||||
|
{
|
||||||
|
error_set(error, line, "Objects can't be keys");
|
||||||
|
rv = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
obj = json_object_get(cur, key);
|
||||||
|
unvisited--;
|
||||||
|
key = NULL;
|
||||||
|
}
|
||||||
|
else if(json_is_array(cur))
|
||||||
|
{
|
||||||
|
obj = json_array_get(cur, array_index);
|
||||||
|
unvisited--;
|
||||||
|
array_index++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure we got what we expected */
|
||||||
|
if(*fmt=='{' && !json_is_object(obj))
|
||||||
|
{
|
||||||
|
rv = -2;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*fmt=='[' && !json_is_array(obj))
|
||||||
|
{
|
||||||
|
rv = -2;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
unvisited += json_is_object(obj) ?
|
||||||
|
json_object_size(obj) :
|
||||||
|
json_array_size(obj);
|
||||||
|
|
||||||
|
/* Descend */
|
||||||
|
stack[depth++] = cur;
|
||||||
|
cur = obj;
|
||||||
|
|
||||||
|
key = NULL;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case ']':
|
||||||
|
case '}':
|
||||||
|
|
||||||
|
if(json_is_array(cur) && *fmt!=']')
|
||||||
|
{
|
||||||
|
error_set(error, line, "Missing ']'");
|
||||||
|
rv = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(json_is_object(cur) && *fmt!='}')
|
||||||
|
{
|
||||||
|
error_set(error, line, "Missing '}'");
|
||||||
|
rv = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(key)
|
||||||
|
{
|
||||||
|
error_set(error, line, "Unexpected '%c'", *fmt);
|
||||||
|
rv = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(depth <= 0)
|
||||||
|
{
|
||||||
|
error_set(error, line, "Unexpected '%c'", *fmt);
|
||||||
|
rv = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = stack[--depth];
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
if(!key && json_is_object(cur))
|
||||||
|
{
|
||||||
|
/* constant string for key */
|
||||||
|
key = va_arg(ap, char*);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
|
||||||
|
case 'i': /* integer */
|
||||||
|
case 'f': /* double-precision float */
|
||||||
|
case 'O': /* a json_t object; increments refcount */
|
||||||
|
case 'o': /* a json_t object; borrowed reference */
|
||||||
|
case 'b': /* boolean */
|
||||||
|
case 'n': /* null */
|
||||||
|
|
||||||
|
/* Fetch object */
|
||||||
|
if(!cur)
|
||||||
|
{
|
||||||
|
obj = root;
|
||||||
|
}
|
||||||
|
else if(json_is_object(cur))
|
||||||
|
{
|
||||||
|
if(!key)
|
||||||
|
{
|
||||||
|
error_set(error, line,
|
||||||
|
"Only strings may be used as keys!");
|
||||||
|
rv = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = json_object_get(cur, key);
|
||||||
|
unvisited--;
|
||||||
|
key = NULL;
|
||||||
|
}
|
||||||
|
else if(json_is_array(cur))
|
||||||
|
{
|
||||||
|
obj = json_array_get(cur, array_index);
|
||||||
|
unvisited--;
|
||||||
|
array_index++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error_set(error, line,
|
||||||
|
"Unsure how to retrieve JSON object '%c'",
|
||||||
|
*fmt);
|
||||||
|
rv = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(*fmt)
|
||||||
|
{
|
||||||
|
case 's':
|
||||||
|
if(!json_is_string(obj))
|
||||||
|
{
|
||||||
|
error_set(error, line,
|
||||||
|
"Type mismatch! Object wasn't a string.");
|
||||||
|
rv = -2;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
*va_arg(ap, const char**) = json_string_value(obj);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
if(!json_is_integer(obj))
|
||||||
|
{
|
||||||
|
error_set(error, line,
|
||||||
|
"Type mismatch! Object wasn't an integer.");
|
||||||
|
rv = -2;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
*va_arg(ap, int*) = json_integer_value(obj);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
if(!json_is_boolean(obj))
|
||||||
|
{
|
||||||
|
error_set(error, line,
|
||||||
|
"Type mismatch! Object wasn't a boolean.");
|
||||||
|
rv = -2;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
*va_arg(ap, int*) = json_is_true(obj);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
if(!json_is_number(obj))
|
||||||
|
{
|
||||||
|
error_set(error, line,
|
||||||
|
"Type mismatch! Object wasn't a real.");
|
||||||
|
rv = -2;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
*va_arg(ap, double*) = json_number_value(obj);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'O':
|
||||||
|
json_incref(obj);
|
||||||
|
/* Fall through */
|
||||||
|
|
||||||
|
case 'o':
|
||||||
|
*va_arg(ap, json_t**) = obj;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
/* Don't actually assign anything; we're just happy
|
||||||
|
* the null turned up as promised in the format
|
||||||
|
* string. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error_set(error, line,
|
||||||
|
"Unknown format character '%c'", *fmt);
|
||||||
|
rv = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return 0 if everything was matched; otherwise the number of JSON
|
||||||
|
* objects we didn't get to. */
|
||||||
|
rv = unvisited;
|
||||||
|
|
||||||
|
out:
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if(stack)
|
||||||
|
free(stack);
|
||||||
|
|
||||||
|
return(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vim: ts=4:expandtab:sw=4
|
||||||
|
*/
|
2
test/.gitignore
vendored
2
test/.gitignore
vendored
@ -9,3 +9,5 @@ suites/api/test_number
|
|||||||
suites/api/test_object
|
suites/api/test_object
|
||||||
suites/api/test_simple
|
suites/api/test_simple
|
||||||
suites/api/test_cpp
|
suites/api/test_cpp
|
||||||
|
suites/api/test_pack
|
||||||
|
suites/api/test_unpack
|
||||||
|
@ -8,7 +8,9 @@ check_PROGRAMS = \
|
|||||||
test_load \
|
test_load \
|
||||||
test_simple \
|
test_simple \
|
||||||
test_number \
|
test_number \
|
||||||
test_object
|
test_object \
|
||||||
|
test_pack \
|
||||||
|
test_unpack
|
||||||
|
|
||||||
test_array_SOURCES = test_array.c util.h
|
test_array_SOURCES = test_array.c util.h
|
||||||
test_copy_SOURCES = test_copy.c util.h
|
test_copy_SOURCES = test_copy.c util.h
|
||||||
@ -17,6 +19,8 @@ test_load_SOURCES = test_load.c util.h
|
|||||||
test_simple_SOURCES = test_simple.c util.h
|
test_simple_SOURCES = test_simple.c util.h
|
||||||
test_number_SOURCES = test_number.c util.h
|
test_number_SOURCES = test_number.c util.h
|
||||||
test_object_SOURCES = test_object.c util.h
|
test_object_SOURCES = test_object.c util.h
|
||||||
|
test_pack_SOURCES = test_pack.c util.h
|
||||||
|
test_unpack_SOURCES = test_unpack.c util.h
|
||||||
|
|
||||||
AM_CPPFLAGS = -I$(top_srcdir)/src
|
AM_CPPFLAGS = -I$(top_srcdir)/src
|
||||||
AM_CFLAGS = -Wall -Werror
|
AM_CFLAGS = -Wall -Werror
|
||||||
|
@ -55,6 +55,8 @@ json_load_file
|
|||||||
json_equal
|
json_equal
|
||||||
json_copy
|
json_copy
|
||||||
json_deep_copy
|
json_deep_copy
|
||||||
|
json_pack
|
||||||
|
json_unpack
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# The list of functions are not exported in the library because they
|
# The list of functions are not exported in the library because they
|
||||||
|
155
test/suites/api/test_pack.c
Normal file
155
test/suites/api/test_pack.c
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
|
||||||
|
* Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
|
||||||
|
*
|
||||||
|
* Jansson is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
json_t *value;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple, valid json_pack cases
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* true */
|
||||||
|
value = json_pack(NULL, "b", 1);
|
||||||
|
if(!json_is_true(value))
|
||||||
|
fail("json_pack boolean failed");
|
||||||
|
if(value->refcount != (ssize_t)-1)
|
||||||
|
fail("json_pack boolean refcount failed");
|
||||||
|
json_decref(value);
|
||||||
|
|
||||||
|
/* false */
|
||||||
|
value = json_pack(NULL, "b", 0);
|
||||||
|
if(!json_is_false(value))
|
||||||
|
fail("json_pack boolean failed");
|
||||||
|
if(value->refcount != (ssize_t)-1)
|
||||||
|
fail("json_pack boolean refcount failed");
|
||||||
|
json_decref(value);
|
||||||
|
|
||||||
|
/* null */
|
||||||
|
value = json_pack(NULL, "n");
|
||||||
|
if(!json_is_null(value))
|
||||||
|
fail("json_pack null failed");
|
||||||
|
if(value->refcount != (ssize_t)-1)
|
||||||
|
fail("json_pack null refcount failed");
|
||||||
|
json_decref(value);
|
||||||
|
|
||||||
|
/* integer */
|
||||||
|
value = json_pack(NULL, "i", 1);
|
||||||
|
if(!json_is_integer(value) || json_integer_value(value) != 1)
|
||||||
|
fail("json_pack integer failed");
|
||||||
|
if(value->refcount != (ssize_t)1)
|
||||||
|
fail("json_pack integer refcount failed");
|
||||||
|
json_decref(value);
|
||||||
|
|
||||||
|
|
||||||
|
/* real */
|
||||||
|
value = json_pack(NULL, "f", 1.0);
|
||||||
|
if(!json_is_real(value) || json_real_value(value) != 1.0)
|
||||||
|
fail("json_pack real failed");
|
||||||
|
if(value->refcount != (ssize_t)1)
|
||||||
|
fail("json_pack real refcount failed");
|
||||||
|
json_decref(value);
|
||||||
|
|
||||||
|
/* string */
|
||||||
|
value = json_pack(NULL, "s", "test");
|
||||||
|
if(!json_is_string(value) || strcmp("test", json_string_value(value)))
|
||||||
|
fail("json_pack string failed");
|
||||||
|
if(value->refcount != (ssize_t)1)
|
||||||
|
fail("json_pack string refcount failed");
|
||||||
|
json_decref(value);
|
||||||
|
|
||||||
|
/* empty object */
|
||||||
|
value = json_pack(NULL, "{}", 1.0);
|
||||||
|
if(!json_is_object(value) || json_object_size(value) != 0)
|
||||||
|
fail("json_pack empty object failed");
|
||||||
|
if(value->refcount != (ssize_t)1)
|
||||||
|
fail("json_pack empty object refcount failed");
|
||||||
|
json_decref(value);
|
||||||
|
|
||||||
|
/* empty list */
|
||||||
|
value = json_pack(NULL, "[]", 1.0);
|
||||||
|
if(!json_is_array(value) || json_array_size(value) != 0)
|
||||||
|
fail("json_pack empty list failed");
|
||||||
|
if(value->refcount != (ssize_t)1)
|
||||||
|
fail("json_pack empty list failed");
|
||||||
|
json_decref(value);
|
||||||
|
|
||||||
|
/* non-incref'd object */
|
||||||
|
value = json_pack(NULL, "o", json_integer(1));
|
||||||
|
if(!json_is_integer(value) || json_integer_value(value) != 1)
|
||||||
|
fail("json_pack object failed");
|
||||||
|
if(value->refcount != (ssize_t)1)
|
||||||
|
fail("json_pack integer refcount failed");
|
||||||
|
json_decref(value);
|
||||||
|
|
||||||
|
/* incref'd object */
|
||||||
|
value = json_pack(NULL, "O", json_integer(1));
|
||||||
|
if(!json_is_integer(value) || json_integer_value(value) != 1)
|
||||||
|
fail("json_pack object failed");
|
||||||
|
if(value->refcount != (ssize_t)2)
|
||||||
|
fail("json_pack integer refcount failed");
|
||||||
|
json_decref(value);
|
||||||
|
json_decref(value);
|
||||||
|
|
||||||
|
/* simple object */
|
||||||
|
value = json_pack(NULL, "{s:[]}", "foo");
|
||||||
|
if(!json_is_object(value) || json_object_size(value) != 1)
|
||||||
|
fail("json_pack object failed");
|
||||||
|
if(!json_is_array(json_object_get(value, "foo")))
|
||||||
|
fail("json_pack object failed");
|
||||||
|
if(json_object_get(value, "foo")->refcount != (ssize_t)1)
|
||||||
|
fail("json_pack object refcount failed");
|
||||||
|
json_decref(value);
|
||||||
|
|
||||||
|
/* simple array */
|
||||||
|
value = json_pack(NULL, "[i,i,i]", 0, 1, 2);
|
||||||
|
if(!json_is_array(value) || json_array_size(value) != 3)
|
||||||
|
fail("json_pack object failed");
|
||||||
|
for(i=0; i<3; i++)
|
||||||
|
{
|
||||||
|
if(!json_is_integer(json_array_get(value, i)) ||
|
||||||
|
json_integer_value(json_array_get(value, i)) != i)
|
||||||
|
|
||||||
|
fail("json_pack integer array failed");
|
||||||
|
}
|
||||||
|
json_decref(value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Invalid cases
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* mismatched open/close array/object */
|
||||||
|
if(json_pack(NULL, "[}"))
|
||||||
|
fail("json_pack failed to catch mismatched '}'");
|
||||||
|
|
||||||
|
if(json_pack(NULL, "{]"))
|
||||||
|
fail("json_pack failed to catch mismatched ']'");
|
||||||
|
|
||||||
|
/* missing close array */
|
||||||
|
if(json_pack(NULL, "["))
|
||||||
|
fail("json_pack failed to catch missing ']'");
|
||||||
|
|
||||||
|
/* missing close object */
|
||||||
|
if(json_pack(NULL, "{"))
|
||||||
|
fail("json_pack failed to catch missing '}'");
|
||||||
|
|
||||||
|
/* NULL string */
|
||||||
|
if(json_pack(NULL, "s", NULL))
|
||||||
|
fail("json_pack failed to catch null string");
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vim: ts=4:expandtab:sw=4
|
||||||
|
*/
|
110
test/suites/api/test_unpack.c
Normal file
110
test/suites/api/test_unpack.c
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
|
||||||
|
* Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
|
||||||
|
*
|
||||||
|
* Jansson is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
json_t *j, *j2;
|
||||||
|
int i1, i2, i3;
|
||||||
|
int rv;
|
||||||
|
//void* v;
|
||||||
|
double f;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple, valid json_pack cases
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* true */
|
||||||
|
rv = json_unpack(json_true(), NULL, "b", &i1);
|
||||||
|
if(rv || !i1)
|
||||||
|
fail("json_unpack boolean failed");
|
||||||
|
|
||||||
|
/* false */
|
||||||
|
rv = json_unpack(json_false(), NULL, "b", &i1);
|
||||||
|
if(rv || i1)
|
||||||
|
fail("json_unpack boolean failed");
|
||||||
|
|
||||||
|
/* null */
|
||||||
|
rv = json_unpack(json_null(), NULL, "n");
|
||||||
|
if(rv)
|
||||||
|
fail("json_unpack null failed");
|
||||||
|
|
||||||
|
/* integer */
|
||||||
|
j = json_integer(1);
|
||||||
|
rv = json_unpack(j, NULL, "i", &i1);
|
||||||
|
if(rv || i1 != 1)
|
||||||
|
fail("json_unpack integer failed");
|
||||||
|
json_decref(j);
|
||||||
|
|
||||||
|
/* real */
|
||||||
|
j = json_real(1.0);
|
||||||
|
rv = json_unpack(j, NULL, "f", &f);
|
||||||
|
if(rv || f != 1.0)
|
||||||
|
fail("json_unpack real failed");
|
||||||
|
json_decref(j);
|
||||||
|
|
||||||
|
/* string */
|
||||||
|
j = json_string("foo");
|
||||||
|
rv = json_unpack(j, NULL, "s", &s);
|
||||||
|
if(rv || strcmp(s, "foo"))
|
||||||
|
fail("json_unpack string failed");
|
||||||
|
json_decref(j);
|
||||||
|
|
||||||
|
/* empty object */
|
||||||
|
j = json_object();
|
||||||
|
rv = json_unpack(j, NULL, "{}");
|
||||||
|
if(rv)
|
||||||
|
fail("json_unpack empty object failed");
|
||||||
|
json_decref(j);
|
||||||
|
|
||||||
|
/* empty list */
|
||||||
|
j = json_array();
|
||||||
|
rv = json_unpack(j, NULL, "[]");
|
||||||
|
if(rv)
|
||||||
|
fail("json_unpack empty list failed");
|
||||||
|
json_decref(j);
|
||||||
|
|
||||||
|
/* non-incref'd object */
|
||||||
|
j = json_object();
|
||||||
|
rv = json_unpack(j, NULL, "o", &j2);
|
||||||
|
if(j2 != j || j->refcount != (ssize_t)1)
|
||||||
|
fail("json_unpack object failed");
|
||||||
|
json_decref(j);
|
||||||
|
|
||||||
|
/* incref'd object */
|
||||||
|
j = json_object();
|
||||||
|
rv = json_unpack(j, NULL, "O", &j2);
|
||||||
|
if(j2 != j || j->refcount != (ssize_t)2)
|
||||||
|
fail("json_unpack object failed");
|
||||||
|
json_decref(j);
|
||||||
|
json_decref(j);
|
||||||
|
|
||||||
|
/* simple object */
|
||||||
|
j = json_pack(NULL, "{s:i}", "foo", 1);
|
||||||
|
rv = json_unpack(j, NULL, "{s:i}", "foo", &i1);
|
||||||
|
if(rv || i1!=1)
|
||||||
|
fail("json_unpack simple object failed");
|
||||||
|
json_decref(j);
|
||||||
|
|
||||||
|
/* simple array */
|
||||||
|
j = json_pack(NULL, "[iii]", 1, 2, 3);
|
||||||
|
rv = json_unpack(j, NULL, "[i,i,i]", &i1, &i2, &i3);
|
||||||
|
if(rv || i1 != 1 || i2 != 2 || i3 != 3)
|
||||||
|
fail("json_unpack simple array failed");
|
||||||
|
json_decref(j);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vim: ts=4:expandtab:sw=4
|
||||||
|
*/
|
Loading…
Reference in New Issue
Block a user