From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp46.i.mail.ru (smtp46.i.mail.ru [94.100.177.106]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id D9B1042EF5D for ; Thu, 25 Jun 2020 17:24:06 +0300 (MSK) From: Chris Sosnin Date: Thu, 25 Jun 2020 17:23:55 +0300 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [Tarantool-patches] [PATCH 2/2] decimal: introduce strtodec function List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: tarantool-patches@dev.tarantool.org, v.shpilevoy@tarantool.org The behavior is similar with other strto* functions: parse the valid beginning of the string and optionally store the pointer to the first invalid character. Needed for tarantool/tarantool#4415 --- src/lib/core/decimal.c | 14 +++++++++++++- src/lib/core/decimal.h | 15 +++++++++++++++ test/unit/decimal.c | 20 +++++++++++++++++++- test/unit/decimal.result | 18 +++++++++++++++++- 4 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/lib/core/decimal.c b/src/lib/core/decimal.c index 019c68338..e762266c5 100644 --- a/src/lib/core/decimal.c +++ b/src/lib/core/decimal.c @@ -112,7 +112,19 @@ decimal_zero(decimal_t *dec) decimal_t * decimal_from_string(decimal_t *dec, const char *str) { - decNumberFromString(dec, str, &decimal_context); + const char *end = decNumberFromString(dec, str, &decimal_context); + if (*end != '\0') { + decContextZeroStatus(&decimal_context); + return NULL; + } + return decimal_check_status(dec, &decimal_context); +} + +decimal_t * +strtodec(decimal_t *dec, const char *str, const char **endptr) { + const char *end = decNumberFromString(dec, str, &decimal_context); + if (endptr != NULL) + *endptr = end; return decimal_check_status(dec, &decimal_context); } diff --git a/src/lib/core/decimal.h b/src/lib/core/decimal.h index e276344d2..992fbd267 100644 --- a/src/lib/core/decimal.h +++ b/src/lib/core/decimal.h @@ -77,6 +77,21 @@ decimal_zero(decimal_t *dec); decimal_t * decimal_from_string(decimal_t *dec, const char *str); +/** + * Initialize a decimal with a value from the valid beginning + * of the string. + * If \a endptr is not NULL, store the address of the first + * invalid character in *endptr. + * + * If the number is less, than 10^DECIMAL_MAX_DIGITS, + * but has excess digits in fractional part, it will be rounded. + * + * @return NULL if string is invalid or + * the number is too big (>= 10^DECIMAL_MAX_DIGITS) + */ +decimal_t * +strtodec(decimal_t *dec, const char *str, const char **endptr); + /** * Initialize a decimal from double. * diff --git a/test/unit/decimal.c b/test/unit/decimal.c index 179723d02..cf74de313 100644 --- a/test/unit/decimal.c +++ b/test/unit/decimal.c @@ -73,6 +73,15 @@ is(decimal_##op(&b, &a), NULL, "decimal_"#op"("#stra") - error on wrong operands.");\ }) +#define test_strtodec(str, end, expect) ({\ + decimal_t dec;\ + const char *endptr;\ + is(strtodec(&dec, str, &endptr), expect(&dec), "strtodec("#str") "\ + #expect);\ + is(*endptr, end, "strtodec("#str") - expected end of valid string at "\ + #end);\ +}) + char buf[32]; #define test_mpdec(str) ({\ @@ -317,7 +326,7 @@ test_mp_print(void) int main(void) { - plan(282); + plan(298); dectest(314, 271, uint64, uint64_t); dectest(65535, 23456, uint64, uint64_t); @@ -384,5 +393,14 @@ main(void) test_mp_decimal(); test_mp_print(); + test_strtodec("15.e", 'e', success); + test_strtodec("15.e+", 'e', success); + test_strtodec(".0e-1", '\0', success); + test_strtodec("1.1003 2.2", ' ', success); + test_strtodec("cCC", 'c', failure); + test_strtodec(".e--", '.', failure); + test_strtodec("NaN", 'N', failure); + test_strtodec("inf", 'i', failure); + return check_plan(); } diff --git a/test/unit/decimal.result b/test/unit/decimal.result index f11396df3..8be8ea122 100644 --- a/test/unit/decimal.result +++ b/test/unit/decimal.result @@ -1,4 +1,4 @@ -1..282 +1..298 ok 1 - decimal(314) ok 2 - decimal(271) ok 3 - decimal(314) + decimal(271) @@ -707,3 +707,19 @@ ok 281 - subtests ok 5 - correct mp_fprint result *** test_mp_print: done *** ok 282 - subtests +ok 283 - strtodec("15.e") success +ok 284 - strtodec("15.e") - expected end of valid string at 'e' +ok 285 - strtodec("15.e+") success +ok 286 - strtodec("15.e+") - expected end of valid string at 'e' +ok 287 - strtodec(".0e-1") success +ok 288 - strtodec(".0e-1") - expected end of valid string at '\0' +ok 289 - strtodec("1.1003 2.2") success +ok 290 - strtodec("1.1003 2.2") - expected end of valid string at ' ' +ok 291 - strtodec("cCC") failure +ok 292 - strtodec("cCC") - expected end of valid string at 'c' +ok 293 - strtodec(".e--") failure +ok 294 - strtodec(".e--") - expected end of valid string at '.' +ok 295 - strtodec("NaN") failure +ok 296 - strtodec("NaN") - expected end of valid string at 'N' +ok 297 - strtodec("inf") failure +ok 298 - strtodec("inf") - expected end of valid string at 'i' -- 2.21.1 (Apple Git-122.3)