From 6f271e511f2e4efe2d2be7043c896423365b004a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 12:56:01 +0100 Subject: [PATCH 1/5] print_number: Use sprintf's return value This is used to update the buffer offset and determine success --- cJSON.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/cJSON.c b/cJSON.c index 392da69..25977fa 100644 --- a/cJSON.c +++ b/cJSON.c @@ -329,6 +329,7 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const { unsigned char *output_pointer = NULL; double d = item->valuedouble; + int length = 0; if (output_buffer == NULL) { @@ -342,7 +343,7 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const output_pointer = ensure(output_buffer, 21, hooks); if (output_pointer != NULL) { - sprintf((char*)output_pointer, "%d", item->valueint); + length = sprintf((char*)output_pointer, "%d", item->valueint); } } /* value is a floating point number */ @@ -355,23 +356,31 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const /* This checks for NaN and Infinity */ if ((d * 0) != 0) { - sprintf((char*)output_pointer, "null"); + length = sprintf((char*)output_pointer, "null"); } else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60)) { - sprintf((char*)output_pointer, "%.0f", d); + length = sprintf((char*)output_pointer, "%.0f", d); } else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) { - sprintf((char*)output_pointer, "%e", d); + length = sprintf((char*)output_pointer, "%e", d); } else { - sprintf((char*)output_pointer, "%f", d); + length = sprintf((char*)output_pointer, "%f", d); } } } + /* sprintf failed */ + if (length < 0) + { + return NULL; + } + + output_buffer->offset += (size_t)length; + return output_pointer; } From e78bc423622e8276e22e3d788ccd2588b9432205 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 13:00:52 +0100 Subject: [PATCH 2/5] print_number: Return buffer + offset instead of beginning of the number --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 25977fa..a823e60 100644 --- a/cJSON.c +++ b/cJSON.c @@ -381,7 +381,7 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const output_buffer->offset += (size_t)length; - return output_pointer; + return output_buffer->buffer + output_buffer->offset; } /* parse 4 digit hexadecimal number */ From 1ea72f8260916bb70e6443509556b6f53922b941 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 13:20:14 +0100 Subject: [PATCH 3/5] print_number: Remove trailing zeroes (for doubles) --- cJSON.c | 41 +++++++++++++++++++++++++++++++++++++ tests/inputs/test7.expected | 6 +++--- tests/print_number.c | 4 ++-- tests/print_value.c | 2 +- 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/cJSON.c b/cJSON.c index a823e60..5f58689 100644 --- a/cJSON.c +++ b/cJSON.c @@ -324,12 +324,44 @@ static void update_offset(printbuffer * const buffer) buffer->offset += strlen((const char*)buffer_pointer); } +/* Removes trailing zeroes from the end of a printed number */ +static unsigned char *trim_trailing_zeroes(printbuffer * const buffer) +{ + size_t offset = 0; + unsigned char *content = NULL; + + if ((buffer == NULL) || (buffer->buffer == NULL) || (buffer->offset < 1)) + { + return NULL; + } + + offset = buffer->offset - 1; + content = buffer->buffer; + + while ((offset > 0) && (content[offset] == '0')) + { + offset--; + } + if ((offset > 0) && (content[offset] == '.')) + { + offset--; + } + + offset++; + content[offset] = '\0'; + + buffer->offset = offset; + + return content + offset; +} + /* Render the number nicely from the given item into a string. */ static unsigned char *print_number(const cJSON * const item, printbuffer * const output_buffer, const internal_hooks * const hooks) { unsigned char *output_pointer = NULL; double d = item->valuedouble; int length = 0; + cjbool trim_zeroes = true; /* should at the end be removed? */ if (output_buffer == NULL) { @@ -339,6 +371,8 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const /* value is an int */ if ((fabs(((double)item->valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN)) { + trim_zeroes = false; /* don't remove zeroes for integers */ + /* 2^64+1 can be represented in 21 chars. */ output_pointer = ensure(output_buffer, 21, hooks); if (output_pointer != NULL) @@ -361,10 +395,12 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60)) { length = sprintf((char*)output_pointer, "%.0f", d); + trim_zeroes = false; /* don't remove zeroes for "big integers" */ } else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) { length = sprintf((char*)output_pointer, "%e", d); + trim_zeroes = false; /* don't remove zeroes in engineering notation */ } else { @@ -381,6 +417,11 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const output_buffer->offset += (size_t)length; + if (trim_zeroes) + { + return trim_trailing_zeroes(output_buffer); + } + return output_buffer->buffer + output_buffer->offset; } diff --git a/tests/inputs/test7.expected b/tests/inputs/test7.expected index 6e2e075..15adf79 100644 --- a/tests/inputs/test7.expected +++ b/tests/inputs/test7.expected @@ -1,7 +1,7 @@ [{ "precision": "zip", - "Latitude": 37.766800, - "Longitude": -122.395900, + "Latitude": 37.7668, + "Longitude": -122.3959, "Address": "", "City": "SAN FRANCISCO", "State": "CA", @@ -10,7 +10,7 @@ }, { "precision": "zip", "Latitude": 37.371991, - "Longitude": -122.026020, + "Longitude": -122.02602, "Address": "", "City": "SUNNYVALE", "State": "CA", diff --git a/tests/print_number.c b/tests/print_number.c index b195ccd..e903734 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -62,7 +62,7 @@ static void print_number_should_print_positive_integers(void) static void print_number_should_print_positive_reals(void) { - assert_print_number("0.123000", 0.123); + assert_print_number("0.123", 0.123); assert_print_number("1.000000e-09", 10e-10); assert_print_number("1000000000000", 10e11); assert_print_number("1.230000e+129", 123e+127); @@ -71,7 +71,7 @@ static void print_number_should_print_positive_reals(void) static void print_number_should_print_negative_reals(void) { - assert_print_number("-0.012300", -0.0123); + assert_print_number("-0.0123", -0.0123); assert_print_number("-1.000000e-09", -10e-10); assert_print_number("-1000000000000000000000", -10e20); assert_print_number("-1.230000e+129", -123e+127); diff --git a/tests/print_value.c b/tests/print_value.c index e72b78d..41ee286 100644 --- a/tests/print_value.c +++ b/tests/print_value.c @@ -66,7 +66,7 @@ static void print_value_should_print_false(void) static void print_value_should_print_number(void) { - assert_print_value("1.500000"); + assert_print_value("1.5"); } static void print_value_should_print_string(void) From dd4cb5400ffd02dc4c09d50501a22d63e65bb497 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 13:26:52 +0100 Subject: [PATCH 4/5] print_number: Remove unnecessary integer handling --- cJSON.c | 53 +++++++++++++++++++---------------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/cJSON.c b/cJSON.c index 5f58689..8bb545d 100644 --- a/cJSON.c +++ b/cJSON.c @@ -368,44 +368,29 @@ static unsigned char *print_number(const cJSON * const item, printbuffer * const return NULL; } - /* value is an int */ - if ((fabs(((double)item->valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN)) + /* This is a nice tradeoff. */ + output_pointer = ensure(output_buffer, 64, hooks); + if (output_pointer != NULL) { - trim_zeroes = false; /* don't remove zeroes for integers */ - - /* 2^64+1 can be represented in 21 chars. */ - output_pointer = ensure(output_buffer, 21, hooks); - if (output_pointer != NULL) + /* This checks for NaN and Infinity */ + if ((d * 0) != 0) { - length = sprintf((char*)output_pointer, "%d", item->valueint); + length = sprintf((char*)output_pointer, "null"); } - } - /* value is a floating point number */ - else - { - /* This is a nice tradeoff. */ - output_pointer = ensure(output_buffer, 64, hooks); - if (output_pointer != NULL) + else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60)) { - /* This checks for NaN and Infinity */ - if ((d * 0) != 0) - { - length = sprintf((char*)output_pointer, "null"); - } - else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60)) - { - length = sprintf((char*)output_pointer, "%.0f", d); - trim_zeroes = false; /* don't remove zeroes for "big integers" */ - } - else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) - { - length = sprintf((char*)output_pointer, "%e", d); - trim_zeroes = false; /* don't remove zeroes in engineering notation */ - } - else - { - length = sprintf((char*)output_pointer, "%f", d); - } + /* integer */ + length = sprintf((char*)output_pointer, "%.0f", d); + trim_zeroes = false; /* don't remove zeroes for "big integers" */ + } + else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) + { + length = sprintf((char*)output_pointer, "%e", d); + trim_zeroes = false; /* don't remove zeroes in engineering notation */ + } + else + { + length = sprintf((char*)output_pointer, "%f", d); } } From 0c0dd4a5b099a5a748da9f074fbd8aac062c1a26 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 1 Mar 2017 18:29:01 +0100 Subject: [PATCH 5/5] tests: test trim_trailing_zeroes --- tests/print_number.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/print_number.c b/tests/print_number.c index e903734..ad25b74 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -87,6 +87,22 @@ static void print_number_should_print_non_number(void) /* assert_print_number("null", -INFTY); */ } +static void trim_trailing_zeroes_should_trim_trailing_zeroes(void) +{ + printbuffer buffer; + unsigned char number[100]; + unsigned char *pointer = NULL; + buffer.length = sizeof(number); + buffer.buffer = number; + + strcpy((char*)number, "10.00"); + buffer.offset = sizeof("10.00") - 1; + pointer = trim_trailing_zeroes(&buffer); + TEST_ASSERT_EQUAL_UINT8('\0', *pointer); + TEST_ASSERT_EQUAL_STRING("10", number); + TEST_ASSERT_EQUAL_UINT(sizeof("10") - 1, buffer.offset); +} + int main(void) { /* initialize cJSON item */ @@ -98,6 +114,7 @@ int main(void) RUN_TEST(print_number_should_print_positive_reals); RUN_TEST(print_number_should_print_negative_reals); RUN_TEST(print_number_should_print_non_number); + RUN_TEST(trim_trailing_zeroes_should_trim_trailing_zeroes); return UNITY_END(); }