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