Lauri Kenttä : msvcrt: Handle negative zero, infinity and nan in _ecvt and others.

Alexandre Julliard julliard at winehq.org
Tue Oct 26 09:40:26 CDT 2021


Module: wine
Branch: stable
Commit: ae66cb71b4df87aea0ce44f6c3791a33c178a4ae
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=ae66cb71b4df87aea0ce44f6c3791a33c178a4ae

Author: Lauri Kenttä <lauri.kentta at gmail.com>
Date:   Thu Apr  1 20:58:46 2021 +0200

msvcrt: Handle negative zero, infinity and nan in _ecvt and others.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50885
Signed-off-by: Lauri Kenttä <lauri.kentta at gmail.com>
Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
(cherry picked from commit 97b420224e767b24d89722ff5efeca38a8ecf1e2)
Signed-off-by: Michael Stefaniuc <mstefani at winehq.org>

---

 dlls/msvcrt/math.c         | 65 ++++++++++++++++++----------------------------
 dlls/msvcrt/tests/printf.c | 11 ++++++++
 2 files changed, 36 insertions(+), 40 deletions(-)

diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c
index e6e837e52c6..4e1f7b24a9c 100644
--- a/dlls/msvcrt/math.c
+++ b/dlls/msvcrt/math.c
@@ -2400,21 +2400,22 @@ char * CDECL _ecvt( double number, int ndigits, int *decpt, int *sign )
     int prec, len;
     thread_data_t *data = msvcrt_get_thread_data();
     /* FIXME: check better for overflow (native supports over 300 chars) */
-    ndigits = min( ndigits, 80 - 7); /* 7 : space for dec point, 1 for "e",
+    ndigits = min( ndigits, 80 - 8); /* 8 : space for sign, dec point, "e",
                                       * 4 for exponent and one for
                                       * terminating '\0' */
     if (!data->efcvt_buffer)
         data->efcvt_buffer = malloc( 80 ); /* ought to be enough */
 
-    if( number < 0) {
-        *sign = TRUE;
-        number = -number;
-    } else
-        *sign = FALSE;
     /* handle cases with zero ndigits or less */
     prec = ndigits;
     if( prec < 1) prec = 2;
     len = _snprintf(data->efcvt_buffer, 80, "%.*le", prec - 1, number);
+
+    if (data->efcvt_buffer[0] == '-') {
+        memmove( data->efcvt_buffer, data->efcvt_buffer + 1, len-- );
+        *sign = 1;
+    } else *sign = 0;
+
     /* take the decimal "point away */
     if( prec != 1)
         memmove( data->efcvt_buffer + 1, data->efcvt_buffer + 2, len - 1 );
@@ -2443,7 +2444,6 @@ int CDECL _ecvt_s( char *buffer, size_t length, double number, int ndigits, int
 {
     int prec, len;
     char *result;
-    const char infret[] = "1#INF";
 
     if (!MSVCRT_CHECK_PMT(buffer != NULL)) return EINVAL;
     if (!MSVCRT_CHECK_PMT(decpt != NULL)) return EINVAL;
@@ -2451,30 +2451,17 @@ int CDECL _ecvt_s( char *buffer, size_t length, double number, int ndigits, int
     if (!MSVCRT_CHECK_PMT_ERR( length > 2, ERANGE )) return ERANGE;
     if (!MSVCRT_CHECK_PMT_ERR(ndigits < (int)length - 1, ERANGE )) return ERANGE;
 
-    /* special case - inf */
-    if(number == HUGE_VAL || number == -HUGE_VAL)
-    {
-        memset(buffer, '0', ndigits);
-        memcpy(buffer, infret, min(ndigits, sizeof(infret) - 1 ) );
-        buffer[ndigits] = '\0';
-        (*decpt) = 1;
-        if(number == -HUGE_VAL)
-            (*sign) = 1;
-        else
-            (*sign) = 0;
-        return 0;
-    }
     /* handle cases with zero ndigits or less */
     prec = ndigits;
     if( prec < 1) prec = 2;
-    result = malloc(prec + 7);
-
-    if( number < 0) {
-        *sign = TRUE;
-        number = -number;
-    } else
-        *sign = FALSE;
-    len = _snprintf(result, prec + 7, "%.*le", prec - 1, number);
+    result = malloc(prec + 8);
+
+    len = _snprintf(result, prec + 8, "%.*le", prec - 1, number);
+    if (result[0] == '-') {
+        memmove( result, result + 1, len-- );
+        *sign = 1;
+    } else *sign = 0;
+
     /* take the decimal "point away */
     if( prec != 1)
         memmove( result + 1, result + 2, len - 1 );
@@ -2511,12 +2498,6 @@ char * CDECL _fcvt( double number, int ndigits, int *decpt, int *sign )
     if (!data->efcvt_buffer)
         data->efcvt_buffer = malloc( 80 ); /* ought to be enough */
 
-    if (number < 0)
-    {
-	*sign = 1;
-	number = -number;
-    } else *sign = 0;
-
     stop = _snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
     ptr1 = buf;
     ptr2 = data->efcvt_buffer;
@@ -2524,6 +2505,11 @@ char * CDECL _fcvt( double number, int ndigits, int *decpt, int *sign )
     dec1 = 0;
     dec2 = 0;
 
+    if (*ptr1 == '-') {
+        *sign = 1;
+        ptr1++;
+    } else *sign = 0;
+
     /* For numbers below the requested resolution, work out where
        the decimal point will be rather than finding it in the string */
     if (number < 1.0 && number > 0.0) {
@@ -2595,12 +2581,6 @@ int CDECL _fcvt_s(char* outbuffer, size_t size, double number, int ndigits, int
         return EINVAL;
     }
 
-    if (number < 0)
-    {
-	*sign = 1;
-	number = -number;
-    } else *sign = 0;
-
     stop = _snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
     ptr1 = buf;
     ptr2 = outbuffer;
@@ -2608,6 +2588,11 @@ int CDECL _fcvt_s(char* outbuffer, size_t size, double number, int ndigits, int
     dec1 = 0;
     dec2 = 0;
 
+    if (*ptr1 == '-') {
+        *sign = 1;
+        ptr1++;
+    } else *sign = 0;
+
     /* For numbers below the requested resolution, work out where
        the decimal point will be rather than finding it in the string */
     if (number < 1.0 && number > 0.0) {
diff --git a/dlls/msvcrt/tests/printf.c b/dlls/msvcrt/tests/printf.c
index fbb43c78168..6905b8d01ca 100644
--- a/dlls/msvcrt/tests/printf.c
+++ b/dlls/msvcrt/tests/printf.c
@@ -643,6 +643,9 @@ static struct {
     {           0.0,   5,     "00000",          "00000",          0,      0,     0 },
     {           0.0,   0,          "",               "",          0,      0,     0 },
     {           0.0,  -1,          "",               "",          0,      0,     0 },
+    {          -0.0,   5,     "00000",          "00000",          0,      0,     1 },
+    {          -0.0,   0,          "",               "",          0,      0,     1 },
+    {          -0.0,  -1,          "",               "",          0,      0,     1 },
     {     -123.0001,   0,          "",            "123",          3,      3,     1 },
     {     -123.0001,  -1,          "",             "12",          3,      3,     1 },
     {     -123.0001,  -2,          "",              "1",          3,      3,     1 },
@@ -656,6 +659,14 @@ static struct {
     {           0.4,   0,          "",               "",          0,      0,     0 },
     {          0.49,   0,          "",               "",          0,      0,     0 },
     {          0.51,   0,          "",              "1",          1,      1,     0 },
+    {           NAN,   2,        "1$",            "1#R",          1,      1,     0 },
+    {           NAN,   5,     "1#QNB",         "1#QNAN",          1,      1,     0 },
+    {          -NAN,   2,        "1$",            "1#J",          1,      1,     1 },
+    {          -NAN,   5,     "1#IND",         "1#IND0",          1,      1,     1 },
+    {      INFINITY,   2,        "1$",            "1#J",          1,      1,     0 },
+    {      INFINITY,   5,     "1#INF",         "1#INF0",          1,      1,     0 },
+    {     -INFINITY,   2,        "1$",            "1#J",          1,      1,     1 },
+    {     -INFINITY,   5,     "1#INF",         "1#INF0",          1,      1,     1 },
     {           1.0,  30, "100000000000000000000000000000",
                       "1000000000000000000000000000000",          1,      1,      0},
     {           123456789012345678901.0,  30, "123456789012345680000000000000",




More information about the wine-cvs mailing list