Nikolay Sivov : msvcrt: Implement _fcvt_s().

Alexandre Julliard julliard at winehq.org
Mon Jan 31 11:26:13 CST 2011


Module: wine
Branch: master
Commit: 7a57f02b8d275c1e8af1ea1c8e8c1bb2e9b02971
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=7a57f02b8d275c1e8af1ea1c8e8c1bb2e9b02971

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Sat Jan 29 20:47:34 2011 +0300

msvcrt: Implement _fcvt_s().

---

 dlls/msvcr100/msvcr100.spec |    2 +-
 dlls/msvcr80/msvcr80.spec   |    2 +-
 dlls/msvcr90/msvcr90.spec   |    2 +-
 dlls/msvcrt/math.c          |   89 +++++++++++++++++++++++++++++++++++++++++++
 dlls/msvcrt/msvcrt.spec     |    2 +-
 dlls/msvcrt/tests/printf.c  |   35 ++++++++++++++--
 6 files changed, 123 insertions(+), 9 deletions(-)

diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec
index 703a78d..9080ba1 100644
--- a/dlls/msvcr100/msvcr100.spec
+++ b/dlls/msvcr100/msvcr100.spec
@@ -606,7 +606,7 @@
 @ stub _fclose_nolock
 @ cdecl _fcloseall() msvcrt._fcloseall
 @ cdecl _fcvt(double long ptr ptr) msvcrt._fcvt
-@ stub _fcvt_s
+@ cdecl _fcvt_s(ptr long double long ptr ptr) msvcrt._fcvt_s
 @ cdecl _fdopen(long str) msvcrt._fdopen
 @ stub _fflush_nolock
 @ cdecl _fgetchar() msvcrt._fgetchar
diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec
index c622b0e..76c25e7 100644
--- a/dlls/msvcr80/msvcr80.spec
+++ b/dlls/msvcr80/msvcr80.spec
@@ -447,7 +447,7 @@
 @ stub _fclose_nolock
 @ cdecl _fcloseall() msvcrt._fcloseall
 @ cdecl _fcvt(double long ptr ptr) msvcrt._fcvt
-@ stub _fcvt_s
+@ cdecl _fcvt_s(ptr long double long ptr ptr) msvcrt._fcvt_s
 @ cdecl _fdopen(long str) msvcrt._fdopen
 @ stub _fflush_nolock
 @ cdecl _fgetchar() msvcrt._fgetchar
diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec
index 52f49c5..49b7139 100644
--- a/dlls/msvcr90/msvcr90.spec
+++ b/dlls/msvcr90/msvcr90.spec
@@ -439,7 +439,7 @@
 @ stub _fclose_nolock
 @ cdecl _fcloseall() msvcrt._fcloseall
 @ cdecl _fcvt(double long ptr ptr) msvcrt._fcvt
-@ stub _fcvt_s
+@ cdecl _fcvt_s(ptr long double long ptr ptr) msvcrt._fcvt_s
 @ cdecl _fdopen(long str) msvcrt._fdopen
 @ stub _fflush_nolock
 @ cdecl _fgetchar() msvcrt._fgetchar
diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c
index c0fc11c..ab9cec4 100644
--- a/dlls/msvcrt/math.c
+++ b/dlls/msvcrt/math.c
@@ -1423,6 +1423,95 @@ char * CDECL _fcvt( double number, int ndigits, int *decpt, int *sign )
 }
 
 /***********************************************************************
+ *		_fcvt_s  (MSVCRT.@)
+ */
+int CDECL _fcvt_s(char* outbuffer, MSVCRT_size_t size, double number, int ndigits, int *decpt, int *sign)
+{
+    int stop, dec1, dec2;
+    char *ptr1, *ptr2, *first;
+    char buf[80]; /* ought to be enough */
+
+    if (!outbuffer || !decpt || !sign || size == 0)
+    {
+        *MSVCRT__errno() = MSVCRT_EINVAL;
+        return MSVCRT_EINVAL;
+    }
+
+    if (number < 0)
+    {
+	*sign = 1;
+	number = -number;
+    } else *sign = 0;
+
+    snprintf(buf, 80, "%.*f", ndigits < 0 ? 0 : ndigits, number);
+    ptr1 = buf;
+    ptr2 = outbuffer;
+    first = NULL;
+    dec1 = 0;
+    dec2 = 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) {
+	dec2 = log10(number + 1e-10);
+	if (-dec2 <= ndigits) dec2 = 0;
+    }
+
+    /* If requested digits is zero or less, we will need to truncate
+     * the returned string */
+    if (ndigits < 1) {
+	stop = strlen(buf) + ndigits;
+    } else {
+	stop = strlen(buf);
+    }
+
+    while (*ptr1 == '0') ptr1++; /* Skip leading zeroes */
+    while (*ptr1 != '\0' && *ptr1 != '.') {
+	if (!first) first = ptr2;
+	if ((ptr1 - buf) < stop) {
+	    if (size > 1) {
+                *ptr2++ = *ptr1++;
+                size--;
+            }
+	} else {
+	    ptr1++;
+	}
+	dec1++;
+    }
+
+    if (ndigits > 0) {
+	ptr1++;
+	if (!first) {
+	    while (*ptr1 == '0') { /* Process leading zeroes */
+                if (number == 0.0 && size > 1) {
+                    *ptr2++ = '0';
+                    size--;
+                }
+                ptr1++;
+		dec1--;
+	    }
+	}
+	while (*ptr1 != '\0') {
+	    if (!first) first = ptr2;
+	    if (size > 1) {
+                *ptr2++ = *ptr1++;
+                size--;
+            }
+	}
+    }
+
+    *ptr2 = '\0';
+
+    /* We never found a non-zero digit, then our number is either
+     * smaller than the requested precision, or 0.0 */
+    if (!first && (number <= 0.0))
+        dec1 = 0;
+
+    *decpt = dec2 ? dec2 : dec1;
+    return 0;
+}
+
+/***********************************************************************
  *		_gcvt  (MSVCRT.@)
  */
 char * CDECL _gcvt( double number, int ndigit, char *buff )
diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec
index 37d2425..64cb281 100644
--- a/dlls/msvcrt/msvcrt.spec
+++ b/dlls/msvcrt/msvcrt.spec
@@ -400,7 +400,7 @@
 # stub _expand_dbg
 @ cdecl _fcloseall() MSVCRT__fcloseall
 @ cdecl _fcvt(double long ptr ptr)
-# stub _fcvt_s
+@ cdecl _fcvt_s(ptr long double long ptr ptr)
 @ cdecl _fdopen(long str) MSVCRT__fdopen
 @ cdecl _fgetchar()
 @ cdecl _fgetwchar()
diff --git a/dlls/msvcrt/tests/printf.c b/dlls/msvcrt/tests/printf.c
index d32ef73..f05d124 100644
--- a/dlls/msvcrt/tests/printf.c
+++ b/dlls/msvcrt/tests/printf.c
@@ -26,6 +26,7 @@
 #define _CRT_NON_CONFORMING_SWPRINTFS
  
 #include <stdio.h>
+#include <errno.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -760,7 +761,7 @@ static struct {
     {           0.4,   0,          "",               "",          0,      0,     0 },
     {          0.49,   0,          "",               "",          0,      0,     0 },
     {          0.51,   0,          "",              "1",          1,      1,     0 },
-    /* ask ridiculous amunt of precision, ruin formatting this table */
+    /* ask for ridiculous precision, ruin formatting this table */
     {           1.0,  30, "100000000000000000000000000000",
                       "1000000000000000000000000000000",          1,      1,      0},
     {           123456789012345678901.0,  30, "123456789012345680000000000000",
@@ -773,6 +774,7 @@ static void test_xcvt(void)
 {
     char *str;
     int i, decpt, sign, err;
+
     for( i = 0; strcmp( test_cvt_testcases[i].expstr_e, "END"); i++){
         decpt = sign = 100;
         str = _ecvt( test_cvt_testcases[i].value,
@@ -830,17 +832,40 @@ static void test_xcvt(void)
 
     if (p__fcvt_s)
     {
+        int i;
+
         str = malloc(1024);
+
+        /* invalid arguments */
+        err = p__fcvt_s(NULL, 0, 0.0, 0, &i, &i);
+        ok(err == EINVAL, "got %d, expected EINVAL\n", err);
+
+        err = p__fcvt_s(str, 0, 0.0, 0, &i, &i);
+        ok(err == EINVAL, "got %d, expected EINVAL\n", err);
+
+        str[0] = ' ';
+        str[1] = 0;
+        err = p__fcvt_s(str, -1, 0.0, 0, &i, &i);
+        ok(err == 0, "got %d, expected 0\n", err);
+        ok(str[0] == 0, "got %c, expected 0\n", str[0]);
+        ok(str[1] == 0, "got %c, expected 0\n", str[1]);
+
+        err = p__fcvt_s(str, 1, 0.0, 0, NULL, &i);
+        ok(err == EINVAL, "got %d, expected EINVAL\n", err);
+
+        err = p__fcvt_s(str, 1, 0.0, 0, &i, NULL);
+        ok(err == EINVAL, "got %d, expected EINVAL\n", err);
+
         for( i = 0; strcmp( test_cvt_testcases[i].expstr_e, "END"); i++){
             decpt = sign = 100;
             err = p__fcvt_s(str, 1024, test_cvt_testcases[i].value, test_cvt_testcases[i].nrdigits, &decpt, &sign);
             ok(err == 0, "_fcvt_s() failed with error code %d", err);
             ok( 0 == strncmp( str, test_cvt_testcases[i].expstr_f, 15),
-                   "_fcvt_s() bad return, got \n'%s' expected \n'%s'\n", str,
-                  test_cvt_testcases[i].expstr_e);
+                   "_fcvt_s() bad return, got '%s' expected '%s'. test %d\n", str,
+                  test_cvt_testcases[i].expstr_f, i);
             ok( decpt == test_cvt_testcases[i].expdecpt_f,
                     "_fcvt_s() decimal point wrong, got %d expected %d\n", decpt,
-                    test_cvt_testcases[i].expdecpt_e);
+                    test_cvt_testcases[i].expdecpt_f);
             ok( sign == test_cvt_testcases[i].expsign,
                     "_fcvt_s() sign wrong, got %d expected %d\n", sign,
                     test_cvt_testcases[i].expsign);
@@ -848,7 +873,7 @@ static void test_xcvt(void)
         free(str);
     }
     else
-        todo_wine win_skip("_fcvt_s not available\n");
+        win_skip("_fcvt_s not available\n");
 }
 
 static int __cdecl _vsnwprintf_wrapper(wchar_t *str, size_t len, const wchar_t *format, ...)




More information about the wine-cvs mailing list