Skip to content

Commit

Permalink
Merge pull request akheron#404 from coreyfarrell/func-attrs
Browse files Browse the repository at this point in the history
Build: Add JANSSON_ATTRS macro.
  • Loading branch information
akheron committed Mar 20, 2018
2 parents d098c0f + 749bef0 commit b23025d
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 50 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -493,6 +493,7 @@ if (NOT JANSSON_WITHOUT_TESTS)
test_equal
test_load
test_loadb
test_load_callback
test_number
test_object
test_pack
Expand Down
2 changes: 1 addition & 1 deletion src/hashtable.h
Expand Up @@ -55,7 +55,7 @@ typedef struct hashtable {
*
* Returns 0 on success, -1 on error (out of memory).
*/
int hashtable_init(hashtable_t *hashtable);
int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS(warn_unused_result);

/**
* hashtable_close - Release all resources used by a hashtable object
Expand Down
38 changes: 22 additions & 16 deletions src/jansson.h
Expand Up @@ -39,6 +39,12 @@ extern "C" {
#define JANSSON_THREAD_SAFE_REFCOUNT 1
#endif

#if defined(__GNUC__) || defined(__clang__)
#define JANSSON_ATTRS(...) __attribute__((__VA_ARGS__))
#else
#define JANSSON_ATTRS(...)
#endif

/* types */

typedef enum {
Expand Down Expand Up @@ -185,7 +191,7 @@ static JSON_INLINE enum json_error_code json_error_code(const json_error_t *e) {

void json_object_seed(size_t seed);
size_t json_object_size(const json_t *object);
json_t *json_object_get(const json_t *object, const char *key);
json_t *json_object_get(const json_t *object, const char *key) JANSSON_ATTRS(warn_unused_result);
int json_object_set_new(json_t *object, const char *key, json_t *value);
int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
int json_object_del(json_t *object, const char *key);
Expand Down Expand Up @@ -237,7 +243,7 @@ int json_object_iter_set(json_t *object, void *iter, json_t *value)
}

size_t json_array_size(const json_t *array);
json_t *json_array_get(const json_t *array, size_t index);
json_t *json_array_get(const json_t *array, size_t index) JANSSON_ATTRS(warn_unused_result);
int json_array_set_new(json_t *array, size_t index, json_t *value);
int json_array_append_new(json_t *array, json_t *value);
int json_array_insert_new(json_t *array, size_t index, json_t *value);
Expand Down Expand Up @@ -278,9 +284,9 @@ int json_real_set(json_t *real, double value);

/* pack, unpack */

json_t *json_pack(const char *fmt, ...);
json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...);
json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap);
json_t *json_pack(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result);
json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) JANSSON_ATTRS(warn_unused_result);
json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result);

#define JSON_VALIDATE_ONLY 0x1
#define JSON_STRICT 0x2
Expand All @@ -291,8 +297,8 @@ int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char

/* sprintf */

json_t *json_sprintf(const char *fmt, ...);
json_t *json_vsprintf(const char *fmt, va_list ap);
json_t *json_sprintf(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 2));
json_t *json_vsprintf(const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 0));


/* equality */
Expand All @@ -302,8 +308,8 @@ int json_equal(const json_t *value1, const json_t *value2);

/* copying */

json_t *json_copy(json_t *value);
json_t *json_deep_copy(const json_t *value);
json_t *json_copy(json_t *value) JANSSON_ATTRS(warn_unused_result);
json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS(warn_unused_result);


/* decoding */
Expand All @@ -316,12 +322,12 @@ json_t *json_deep_copy(const json_t *value);

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);
json_t *json_loads(const char *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
json_t *json_loadfd(int input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
json_t *json_load_file(const char *path, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);


/* encoding */
Expand All @@ -339,7 +345,7 @@ json_t *json_load_callback(json_load_callback_t callback, void *data, size_t fla

typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);

char *json_dumps(const json_t *json, size_t flags);
char *json_dumps(const json_t *json, size_t flags) JANSSON_ATTRS(warn_unused_result);
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);
Expand Down
8 changes: 4 additions & 4 deletions src/jansson_private.h
Expand Up @@ -84,11 +84,11 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out);
int jsonp_dtostr(char *buffer, size_t size, double value, int prec);

/* Wrappers for custom memory functions */
void* jsonp_malloc(size_t size);
void* jsonp_malloc(size_t size) JANSSON_ATTRS(warn_unused_result);
void jsonp_free(void *ptr);
char *jsonp_strndup(const char *str, size_t length);
char *jsonp_strdup(const char *str);
char *jsonp_strndup(const char *str, size_t len);
char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS(warn_unused_result);
char *jsonp_strdup(const char *str) JANSSON_ATTRS(warn_unused_result);
char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS(warn_unused_result);


/* Windows compatibility */
Expand Down
40 changes: 13 additions & 27 deletions src/pack_unpack.c
Expand Up @@ -511,48 +511,34 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
if(root && strict == 1) {
/* We need to check that all non optional items have been parsed */
const char *key;
int have_unrecognized_keys = 0;
/* keys_res is 1 for uninitialized, 0 for success, -1 for error. */
int keys_res = 1;
strbuffer_t unrecognized_keys;
json_t *value;
long unpacked = 0;
if (gotopt) {
/* We have optional keys, we need to iter on each key */

if (gotopt || json_object_size(root) != key_set.size) {
json_object_foreach(root, key, value) {
if(!hashtable_get(&key_set, key)) {
unpacked++;

/* Save unrecognized keys for the error message */
if (!have_unrecognized_keys) {
strbuffer_init(&unrecognized_keys);
have_unrecognized_keys = 1;
} else {
strbuffer_append_bytes(&unrecognized_keys, ", ", 2);
if (keys_res == 1) {
keys_res = strbuffer_init(&unrecognized_keys);
} else if (!keys_res) {
keys_res = strbuffer_append_bytes(&unrecognized_keys, ", ", 2);
}
strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));

if (!keys_res)
keys_res = strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));
}
}
} else {
/* No optional keys, we can just compare the number of items */
unpacked = (long)json_object_size(root) - (long)key_set.size;
}
if (unpacked) {
if (!gotopt) {
/* Save unrecognized keys for the error message */
json_object_foreach(root, key, value) {
if(!hashtable_get(&key_set, key)) {
if (!have_unrecognized_keys) {
strbuffer_init(&unrecognized_keys);
have_unrecognized_keys = 1;
} else {
strbuffer_append_bytes(&unrecognized_keys, ", ", 2);
}
strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));
}
}
}
set_error(s, "<validation>", json_error_end_of_input_expected,
"%li object item(s) left unpacked: %s",
unpacked, strbuffer_value(&unrecognized_keys));
unpacked,
keys_res ? "<unknown>" : strbuffer_value(&unrecognized_keys));
strbuffer_close(&unrecognized_keys);
goto out;
}
Expand Down
2 changes: 1 addition & 1 deletion src/strbuffer.h
Expand Up @@ -16,7 +16,7 @@ typedef struct {
size_t size; /* bytes allocated */
} strbuffer_t;

int strbuffer_init(strbuffer_t *strbuff);
int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS(warn_unused_result);
void strbuffer_close(strbuffer_t *strbuff);

void strbuffer_clear(strbuffer_t *strbuff);
Expand Down
64 changes: 63 additions & 1 deletion test/suites/api/test_chaos.c
Expand Up @@ -43,6 +43,53 @@ void chaos_free(void *obj)
#define chaos_loop_new_value(json, initcall) \
chaos_loop(!json, json = initcall;, json_decref(json); json = NULL;)

int test_unpack()
{
int ret = -1;
int v1;
int v2;
json_error_t error;
json_t *root = json_pack("{s:i, s:i, s:i, s:i}", "n1", 1, "n2", 2, "n3", 3, "n4", 4);

if (!root)
return -1;

if (!json_unpack_ex(root, &error, JSON_STRICT, "{s:i, s:i}", "n1", &v1, "n2", &v2))
fail("Unexpected success");

if (json_error_code(&error) != json_error_end_of_input_expected) {
if (json_error_code(&error) != json_error_out_of_memory)
fail("Unexpected error code");

goto out;
}

if (strcmp(error.text, "2 object item(s) left unpacked: n3, n4"))
goto out;

ret = 0;

out:
json_decref(root);
return ret;
}

int dump_chaos_callback(const char *buffer, size_t size, void *data)
{
json_t *obj = json_object();

(void)buffer;
(void)size;
(void)data;

if (!obj)
return -1;

json_decref(obj);

return 0;
}

static void test_chaos()
{
json_malloc_t orig_malloc;
Expand All @@ -54,9 +101,13 @@ static void test_chaos()
json_t *txt = json_string("test");
json_t *intnum = json_integer(1);
json_t *dblnum = json_real(0.5);
char *dumptxt = NULL;
json_t *dumpobj = json_pack("{s:[iiis], s:s}",
"key1", 1, 2, 3, "txt",
"key2", "v2");
int keyno;

if (!obj || !arr1 || !arr2 || !txt || !intnum || !dblnum)
if (!obj || !arr1 || !arr2 || !txt || !intnum || !dblnum || !dumpobj)
fail("failed to allocate basic objects");

json_get_alloc_funcs(&orig_malloc, &orig_free);
Expand All @@ -73,6 +124,12 @@ static void test_chaos()
"another long string to force yet another reallocation of the string because "
"that's what we are testing."));

chaos_loop(test_unpack(),,);

chaos_loop(json_dump_callback(dumpobj, dump_chaos_callback, NULL, JSON_INDENT(1)),,);
chaos_loop(json_dump_callback(dumpobj, dump_chaos_callback, NULL, JSON_INDENT(1) | JSON_SORT_KEYS),,);
chaos_loop(!dumptxt, dumptxt = json_dumps(dumpobj, JSON_COMPACT);, free(dumptxt); dumptxt = NULL;);

chaos_loop_new_value(json, json_copy(obj));
chaos_loop_new_value(json, json_deep_copy(obj));

Expand All @@ -83,6 +140,10 @@ static void test_chaos()
chaos_loop_new_value(json, json_copy(intnum));
chaos_loop_new_value(json, json_copy(dblnum));

#define JSON_LOAD_TXT "{\"n\":[1,2,3,4,5,6,7,8,9,10]}"
chaos_loop_new_value(json, json_loads(JSON_LOAD_TXT, 0, NULL));
chaos_loop_new_value(json, json_loadb(JSON_LOAD_TXT, strlen(JSON_LOAD_TXT), 0, NULL));

chaos_loop_new_value(json, json_sprintf("%s", "string"));

for (keyno = 0; keyno < 100; ++keyno) {
Expand All @@ -107,6 +168,7 @@ static void test_chaos()
json_decref(txt);
json_decref(intnum);
json_decref(dblnum);
json_decref(dumpobj);
}

static void run_tests()
Expand Down

0 comments on commit b23025d

Please sign in to comment.