From af848c27b467afff371aa22af9da2f3e1e15692a Mon Sep 17 00:00:00 2001 From: Krzysztof Gabis Date: Sat, 11 Dec 2021 18:11:18 +0100 Subject: [PATCH] 1.3.0: Adds json_set_float_serialization_format function. --- CMakeLists.txt | 2 +- package.json | 2 +- parson.c | 36 +++++++++++++++++++++++++++++------- parson.h | 14 +++++++++++--- tests.c | 16 +++++++++++++++- 5 files changed, 57 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f0382a8..6945b44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ project(parson C) include (GNUInstallDirs) -set(PARSON_VERSION 1.2.1) +set(PARSON_VERSION 1.3.0) add_library(parson parson.c) target_include_directories(parson PUBLIC $) diff --git a/package.json b/package.json index 589bc1c..5d0b930 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parson", - "version": "1.2.1", + "version": "1.3.0", "repo": "kgabis/parson", "description": "Small json parser and reader", "keywords": [ "json", "parser" ], diff --git a/parson.c b/parson.c index 617ce5e..006b756 100644 --- a/parson.c +++ b/parson.c @@ -31,8 +31,8 @@ #include "parson.h" #define PARSON_IMPL_VERSION_MAJOR 1 -#define PARSON_IMPL_VERSION_MINOR 2 -#define PARSON_IMPL_VERSION_PATCH 1 +#define PARSON_IMPL_VERSION_MINOR 3 +#define PARSON_IMPL_VERSION_PATCH 0 #if (PARSON_VERSION_MAJOR != PARSON_IMPL_VERSION_MAJOR)\ || (PARSON_VERSION_MINOR != PARSON_IMPL_VERSION_MINOR)\ @@ -63,8 +63,13 @@ #define STARTING_CAPACITY 16 #define MAX_NESTING 2048 -#define FLOAT_FORMAT "%1.17g" /* do not increase precision without incresing NUM_BUF_SIZE */ -#define NUM_BUF_SIZE 64 /* double printed with "%1.17g" shouldn't be longer than 25 bytes so let's be paranoid and use 64 */ +#ifndef PARSON_DEFAULT_FLOAT_FORMAT +#define PARSON_DEFAULT_FLOAT_FORMAT "%1.17g" /* do not increase precision without incresing NUM_BUF_SIZE */ +#endif + +#ifndef PARSON_NUM_BUF_SIZE +#define PARSON_NUM_BUF_SIZE 64 /* double printed with "%1.17g" shouldn't be longer than 25 bytes so let's be paranoid and use 64 */ +#endif #define SIZEOF_TOKEN(a) (sizeof(a) - 1) #define SKIP_CHAR(str) ((*str)++) @@ -87,6 +92,8 @@ static JSON_Free_Function parson_free = free; static int parson_escape_slashes = 1; +static char *parson_float_format = NULL; + #define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */ typedef int parson_bool_t; @@ -1212,7 +1219,11 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le if (buf != NULL) { num_buf = buf; } - written = sprintf(num_buf, FLOAT_FORMAT, num); + if (parson_float_format) { + written = sprintf(num_buf, parson_float_format, num); + } else { + written = sprintf(num_buf, PARSON_DEFAULT_FLOAT_FORMAT, num); + } if (written < 0) { return -1; } @@ -1757,7 +1768,7 @@ JSON_Value * json_value_deep_copy(const JSON_Value *value) { } size_t json_serialization_size(const JSON_Value *value) { - char num_buf[NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ + char num_buf[PARSON_NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ int res = json_serialize_to_buffer_r(value, NULL, 0, PARSON_FALSE, num_buf); return res < 0 ? 0 : (size_t)(res) + 1; } @@ -1817,7 +1828,7 @@ char * json_serialize_to_string(const JSON_Value *value) { } size_t json_serialization_size_pretty(const JSON_Value *value) { - char num_buf[NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ + char num_buf[PARSON_NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ int res = json_serialize_to_buffer_r(value, NULL, 0, PARSON_TRUE, num_buf); return res < 0 ? 0 : (size_t)(res) + 1; } @@ -2422,3 +2433,14 @@ void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Fu void json_set_escape_slashes(int escape_slashes) { parson_escape_slashes = escape_slashes; } + +void json_set_float_serialization_format(const char *format) { + if (parson_float_format) { + parson_free(parson_float_format); + } + if (!format) { + parson_float_format = NULL; + return; + } + parson_float_format = parson_strdup(format); +} diff --git a/parson.h b/parson.h index beeca4c..ee68ee2 100644 --- a/parson.h +++ b/parson.h @@ -30,12 +30,15 @@ extern "C" { #endif +#if 0 +} /* unconfuse xcode */ +#endif #define PARSON_VERSION_MAJOR 1 -#define PARSON_VERSION_MINOR 2 -#define PARSON_VERSION_PATCH 1 +#define PARSON_VERSION_MINOR 3 +#define PARSON_VERSION_PATCH 0 -#define PARSON_VERSION_STRING "1.2.1" +#define PARSON_VERSION_STRING "1.3.0" #include /* size_t */ @@ -72,6 +75,11 @@ void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Fu This function sets a global setting and is not thread safe. */ void json_set_escape_slashes(int escape_slashes); +/* Sets float format used for serialization of numbers. + Make sure it can't serialize to a string longer than PARSON_NUM_BUF_SIZE. + If format is null then the default format is used. */ +void json_set_float_serialization_format(const char *format); + /* Parses first JSON value in a file, returns NULL in case of error */ JSON_Value * json_parse_file(const char *filename); diff --git a/tests.c b/tests.c index cf05065..e53616f 100644 --- a/tests.c +++ b/tests.c @@ -62,6 +62,7 @@ void test_suite_10(void); /* Testing for memory leaks */ void test_suite_11(void); /* Additional things that require testing */ void test_memory_leaks(void); void test_failing_allocations(void); +void test_custom_number_format(void); void print_commits_info(const char *username, const char *repo); void persistence_example(void); @@ -97,6 +98,9 @@ int main(int argc, char *argv[]) { #else int tests_main(int argc, char *argv[]); int tests_main(int argc, char *argv[]) { +#endif +#if 0 /* unconfuse xcode */ +} #endif /* Example functions from readme file: */ /* print_commits_info("torvalds", "linux"); */ @@ -127,6 +131,7 @@ int tests_main(int argc, char *argv[]) { test_suite_11(); test_memory_leaks(); test_failing_allocations(); + test_custom_number_format(); printf("Tests failed: %d\n", g_tests_failed); printf("Tests passed: %d\n", g_tests_passed); @@ -682,10 +687,19 @@ void test_failing_allocations() { } } - json_set_allocation_functions(NULL, NULL); + json_set_allocation_functions(malloc, free); printf("OK (tested %d failing allocations)\n", n - 1); g_tests_passed++; +} +void test_custom_number_format() { + char *serialized = NULL; + JSON_Value *val = json_value_init_number(0.6); + json_set_float_serialization_format("%.1f"); + serialized = json_serialize_to_string(val); + TEST(STREQ(serialized, "0.6")); + json_free_serialized_string(serialized); + json_value_free(val); } void print_commits_info(const char *username, const char *repo) {