From d74f6b2b1ac3ac0a11f4b328e3dfdb90c6acfc62 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Wed, 14 Mar 2018 23:26:04 +0900 Subject: [PATCH] implement fixed number APIs --- Makefile | 2 +- parson.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ parson.h | 36 +++++++++++++++ tests.c | 16 +++++++ 4 files changed, 191 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 98654de..d5e1be1 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC = gcc -CFLAGS = -O0 -g -Wall -Wextra -std=c89 -pedantic-errors +CFLAGS = -O0 -g -Wall -Wextra -std=c89 -pedantic-errors -DJSON_FIXED_NUMBER -Wno-format -Wlong-long CPPC = g++ CPPFLAGS = -O0 -g -Wall -Wextra diff --git a/parson.c b/parson.c index 583524b..513946f 100644 --- a/parson.c +++ b/parson.c @@ -42,6 +42,11 @@ #define STARTING_CAPACITY 16 #define MAX_NESTING 2048 #define FLOAT_FORMAT "%1.17g" +#ifdef PRId64 +#define FIXED_FORMAT "%"PRId64 +#else +#define FIXED_FORMAT "%jd" +#endif #define SIZEOF_TOKEN(a) (sizeof(a) - 1) #define SKIP_CHAR(str) ((*str)++) @@ -60,6 +65,9 @@ static JSON_Free_Function parson_free = free; typedef union json_value_value { char *string; double number; +#ifdef JSON_FIXED_NUMBER + intmax_t fixed; +#endif JSON_Object *object; JSON_Array *array; int boolean; @@ -775,6 +783,13 @@ static JSON_Value * parse_boolean_value(const char **string) { static JSON_Value * parse_number_value(const char **string) { char *end; double number = 0; +#ifdef JSON_FIXED_NUMBER + intmax_t fixed = strtoimax(*string, &end, 10); + if (errno == 0 && INT64_MIN <= fixed && fixed <= INT64_MAX) { + *string = end; + return json_value_init_fixed(fixed); + } +#endif errno = 0; number = strtod(*string, &end); if (errno || !is_decimal(*string, end - *string)) { @@ -812,6 +827,9 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le JSON_Object *object = NULL; size_t i = 0, count = 0; double num = 0.0; +#ifdef JSON_FIXED_NUMBER + intmax_t inum = 0; +#endif int written = -1, written_total = 0; switch (json_value_get_type(value)) { @@ -916,6 +934,22 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le APPEND_STRING("false"); } return written_total; +#ifdef JSON_FIXED_NUMBER + case JSONFixed: + inum = json_value_get_fixed(value); + if (buf != NULL) { + num_buf = buf; + } + written = sprintf(num_buf, FIXED_FORMAT, inum); + if (written < 0) { + return -1; + } + if (buf != NULL) { + buf += written; + } + written_total += written; + return written_total; +#endif case JSONNumber: num = json_value_get_number(value); if (buf != NULL) { @@ -1085,6 +1119,12 @@ double json_object_get_number(const JSON_Object *object, const char *name) { return json_value_get_number(json_object_get_value(object, name)); } +#ifdef JSON_FIXED_NUMBER +intmax_t json_object_get_fixed(const JSON_Object *object, const char *name) { + return json_value_get_fixed(json_object_get_value(object, name)); +} +#endif + JSON_Object * json_object_get_object(const JSON_Object *object, const char *name) { return json_value_get_object(json_object_get_value(object, name)); } @@ -1114,6 +1154,12 @@ double json_object_dotget_number(const JSON_Object *object, const char *name) { return json_value_get_number(json_object_dotget_value(object, name)); } +#ifdef JSON_FIXED_NUMBER +intmax_t json_object_dotget_fixed(const JSON_Object *object, const char *name) { + return json_value_get_fixed(json_object_dotget_value(object, name)); +} +#endif + JSON_Object * json_object_dotget_object(const JSON_Object *object, const char *name) { return json_value_get_object(json_object_dotget_value(object, name)); } @@ -1182,6 +1228,12 @@ double json_array_get_number(const JSON_Array *array, size_t index) { return json_value_get_number(json_array_get_value(array, index)); } +#ifdef JSON_FIXED_NUMBER +intmax_t json_array_get_fixed(const JSON_Array *array, size_t index) { + return json_value_get_fixed(json_array_get_value(array, index)); +} +#endif + JSON_Object * json_array_get_object(const JSON_Array *array, size_t index) { return json_value_get_object(json_array_get_value(array, index)); } @@ -1223,6 +1275,12 @@ double json_value_get_number(const JSON_Value *value) { return json_value_get_type(value) == JSONNumber ? value->value.number : 0; } +#ifdef JSON_FIXED_NUMBER +intmax_t json_value_get_fixed(const JSON_Value *value) { + return json_value_get_type(value) == JSONFixed ? value->value.fixed : 0; +} +#endif + int json_value_get_boolean(const JSON_Value *value) { return json_value_get_type(value) == JSONBoolean ? value->value.boolean : -1; } @@ -1315,6 +1373,20 @@ JSON_Value * json_value_init_number(double number) { return new_value; } +#ifdef JSON_FIXED_NUMBER +JSON_Value * json_value_init_fixed(intmax_t fixed) { + JSON_Value *new_value = NULL; + new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); + if (new_value == NULL) { + return NULL; + } + new_value->parent = NULL; + new_value->type = JSONFixed; + new_value->value.fixed = fixed; + return new_value; +} +#endif + JSON_Value * json_value_init_boolean(int boolean) { JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); if (!new_value) { @@ -1392,6 +1464,10 @@ JSON_Value * json_value_deep_copy(const JSON_Value *value) { return json_value_init_boolean(json_value_get_boolean(value)); case JSONNumber: return json_value_init_number(json_value_get_number(value)); +#ifdef JSON_FIXED_NUMBER + case JSONFixed: + return json_value_init_fixed(json_value_get_fixed(value)); +#endif case JSONString: temp_string = json_value_get_string(value); if (temp_string == NULL) { @@ -1585,6 +1661,20 @@ JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number return JSONSuccess; } +#ifdef JSON_FIXED_NUMBER +JSON_Status json_array_replace_fixed(JSON_Array *array, size_t i, intmax_t fixed) { + JSON_Value *value = json_value_init_fixed(fixed); + if (value == NULL) { + return JSONFailure; + } + if (json_array_replace_value(array, i, value) == JSONFailure) { + json_value_free(value); + return JSONFailure; + } + return JSONSuccess; +} +#endif + JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean) { JSON_Value *value = json_value_init_boolean(boolean); if (value == NULL) { @@ -1652,6 +1742,20 @@ JSON_Status json_array_append_number(JSON_Array *array, double number) { return JSONSuccess; } +#ifdef JSON_FIXED_NUMBER +JSON_Status json_array_append_fixed(JSON_Array *array, intmax_t fixed) { + JSON_Value *value = json_value_init_fixed(fixed); + if (value == NULL) { + return JSONFailure; + } + if (json_array_append_value(array, value) == JSONFailure) { + json_value_free(value); + return JSONFailure; + } + return JSONSuccess; +} +#endif + JSON_Status json_array_append_boolean(JSON_Array *array, int boolean) { JSON_Value *value = json_value_init_boolean(boolean); if (value == NULL) { @@ -1705,6 +1809,12 @@ JSON_Status json_object_set_number(JSON_Object *object, const char *name, double return json_object_set_value(object, name, json_value_init_number(number)); } +#ifdef JSON_FIXED_NUMBER +JSON_Status json_object_set_fixed(JSON_Object *object, const char *name, intmax_t fixed) { + return json_object_set_value(object, name, json_value_init_fixed(fixed)); +} +#endif + JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean) { return json_object_set_value(object, name, json_value_init_boolean(boolean)); } @@ -1769,6 +1879,20 @@ JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, dou return JSONSuccess; } +#ifdef JSON_FIXED_NUMBER +JSON_Status json_object_dotset_fixed(JSON_Object *object, const char *name, intmax_t fixed) { + JSON_Value *value = json_value_init_fixed(fixed); + if (value == NULL) { + return JSONFailure; + } + if (json_object_dotset_value(object, name, value) == JSONFailure) { + json_value_free(value); + return JSONFailure; + } + return JSONSuccess; +} +#endif + JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean) { JSON_Value *value = json_value_init_boolean(boolean); if (value == NULL) { @@ -1899,6 +2023,10 @@ JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value) { return JSONSuccess; case JSONString: case JSONNumber: case JSONBoolean: case JSONNull: return JSONSuccess; /* equality already tested before switch */ +#ifdef JSON_FIXED_NUMBER + case JSONFixed: + return JSONSuccess; +#endif case JSONError: default: return JSONFailure; } @@ -1959,6 +2087,10 @@ int json_value_equals(const JSON_Value *a, const JSON_Value *b) { return json_value_get_boolean(a) == json_value_get_boolean(b); case JSONNumber: return fabs(json_value_get_number(a) - json_value_get_number(b)) < 0.000001; /* EPSILON */ +#ifdef JSON_FIXED_NUMBER + case JSONFixed: + return json_value_get_fixed(a) == json_value_get_fixed(b); +#endif case JSONError: return 1; case JSONNull: @@ -1988,6 +2120,12 @@ double json_number (const JSON_Value *value) { return json_value_get_number(value); } +#ifdef JSON_FIXED_NUMBER +intmax_t json_fixed (const JSON_Value *value) { + return json_value_get_fixed(value); +} +#endif + int json_boolean(const JSON_Value *value) { return json_value_get_boolean(value); } diff --git a/parson.h b/parson.h index 6438c93..1fa1756 100644 --- a/parson.h +++ b/parson.h @@ -30,6 +30,9 @@ extern "C" #endif #include /* size_t */ +#ifdef JSON_FIXED_NUMBER +#include +#endif /* Types and enums */ typedef struct json_object_t JSON_Object; @@ -41,6 +44,9 @@ enum json_value_type { JSONNull = 1, JSONString = 2, JSONNumber = 3, +#ifdef JSON_FIXED_NUMBER + JSONFixed = 7, +#endif JSONObject = 4, JSONArray = 5, JSONBoolean = 6 @@ -111,6 +117,9 @@ const char * json_object_get_string (const JSON_Object *object, const char *nam JSON_Object * json_object_get_object (const JSON_Object *object, const char *name); JSON_Array * json_object_get_array (const JSON_Object *object, const char *name); double json_object_get_number (const JSON_Object *object, const char *name); /* returns 0 on fail */ +#ifdef JSON_FIXED_NUMBER +intmax_t json_object_get_fixed (const JSON_Object *object, const char *name); /* returns 0 on fail */ +#endif int json_object_get_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */ /* dotget functions enable addressing values with dot notation in nested objects, @@ -122,6 +131,9 @@ const char * json_object_dotget_string (const JSON_Object *object, const char * JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name); JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name); double json_object_dotget_number (const JSON_Object *object, const char *name); /* returns 0 on fail */ +#ifdef JSON_FIXED_NUMBER +intmax_t json_object_dotget_fixed (const JSON_Object *object, const char *name); +#endif int json_object_dotget_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */ /* Functions to get available names */ @@ -143,6 +155,9 @@ int json_object_dothas_value_of_type(const JSON_Object *object, const char *name JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value); JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string); JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number); +#ifdef JSON_FIXED_NUMBER +JSON_Status json_object_set_fixed(JSON_Object *object, const char *name, intmax_t fixed); +#endif JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean); JSON_Status json_object_set_null(JSON_Object *object, const char *name); @@ -151,6 +166,9 @@ JSON_Status json_object_set_null(JSON_Object *object, const char *name); JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value); JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string); JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number); +#ifdef JSON_FIXED_NUMBER +JSON_Status json_object_dotset_fixed(JSON_Object *object, const char *name, intmax_t fixed); +#endif JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean); JSON_Status json_object_dotset_null(JSON_Object *object, const char *name); @@ -171,6 +189,9 @@ const char * json_array_get_string (const JSON_Array *array, size_t index); JSON_Object * json_array_get_object (const JSON_Array *array, size_t index); JSON_Array * json_array_get_array (const JSON_Array *array, size_t index); double json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */ +#ifdef JSON_FIXED_NUMBER +intmax_t json_array_get_fixed (const JSON_Array *array, size_t index); +#endif int json_array_get_boolean(const JSON_Array *array, size_t index); /* returns -1 on fail */ size_t json_array_get_count (const JSON_Array *array); JSON_Value * json_array_get_wrapping_value(const JSON_Array *array); @@ -185,6 +206,9 @@ JSON_Status json_array_remove(JSON_Array *array, size_t i); JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value); JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string); JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number); +#ifdef JSON_FIXED_NUMBER +JSON_Status json_array_replace_fixed(JSON_Array *array, size_t i, intmax_t fixed); +#endif JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean); JSON_Status json_array_replace_null(JSON_Array *array, size_t i); @@ -196,6 +220,9 @@ JSON_Status json_array_clear(JSON_Array *array); JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value); JSON_Status json_array_append_string(JSON_Array *array, const char *string); JSON_Status json_array_append_number(JSON_Array *array, double number); +#ifdef JSON_FIXED_NUMBER +JSON_Status json_array_append_fixed(JSON_Array *array, intmax_t fixed); +#endif JSON_Status json_array_append_boolean(JSON_Array *array, int boolean); JSON_Status json_array_append_null(JSON_Array *array); @@ -206,6 +233,9 @@ JSON_Value * json_value_init_object (void); JSON_Value * json_value_init_array (void); JSON_Value * json_value_init_string (const char *string); /* copies passed string */ JSON_Value * json_value_init_number (double number); +#ifdef JSON_FIXED_NUMBER +JSON_Value * json_value_init_fixed (intmax_t fixed); +#endif JSON_Value * json_value_init_boolean(int boolean); JSON_Value * json_value_init_null (void); JSON_Value * json_value_deep_copy (const JSON_Value *value); @@ -216,6 +246,9 @@ JSON_Object * json_value_get_object (const JSON_Value *value); JSON_Array * json_value_get_array (const JSON_Value *value); const char * json_value_get_string (const JSON_Value *value); double json_value_get_number (const JSON_Value *value); +#ifdef JSON_FIXED_NUMBER +intmax_t json_value_get_fixed (const JSON_Value *value); +#endif int json_value_get_boolean(const JSON_Value *value); JSON_Value * json_value_get_parent (const JSON_Value *value); @@ -225,6 +258,9 @@ JSON_Object * json_object (const JSON_Value *value); JSON_Array * json_array (const JSON_Value *value); const char * json_string (const JSON_Value *value); double json_number (const JSON_Value *value); +#ifdef JSON_FIXED_NUMBER +intmax_t json_fixed (const JSON_Value *value); +#endif int json_boolean(const JSON_Value *value); #ifdef __cplusplus diff --git a/tests.c b/tests.c index 1d82192..87efa61 100644 --- a/tests.c +++ b/tests.c @@ -49,6 +49,9 @@ void test_suite_7(void); /* Test schema validation */ void test_suite_8(void); /* Test serialization */ void test_suite_9(void); /* Test serialization (pretty) */ void test_suite_10(void); /* Testing for memory leaks */ +#ifdef JSON_FIXED_NUMBER +void test_suite_11(void); /* Testing for fixed number */ +#endif void print_commits_info(const char *username, const char *repo); void persistence_example(void); @@ -80,6 +83,9 @@ int main() { test_suite_8(); test_suite_9(); test_suite_10(); +#ifdef JSON_FIXED_NUMBER + test_suite_11(); +#endif printf("Tests failed: %d\n", tests_failed); printf("Tests passed: %d\n", tests_passed); return 0; @@ -538,6 +544,16 @@ void test_suite_10(void) { TEST(malloc_count == 0); } +#ifdef JSON_FIXED_NUMBER +void test_suite_11(void) { + JSON_Value *val; + + TEST((val = json_parse_string("{\"foo\": -1096377938905861812}")) != NULL); + TEST(json_value_equals(json_parse_string(json_serialize_to_string(val)), val)); + if (val) { json_value_free(val); } +} +#endif + void print_commits_info(const char *username, const char *repo) { JSON_Value *root_value; JSON_Array *commits;