diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec index 703a78d17d8..9080ba1e6eb 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 c622b0e9918..76c25e7b757 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 52f49c52c30..49b71395966 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 c0fc11cbbbc..ab9cec4307a 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -1422,6 +1422,95 @@ char * CDECL _fcvt( double number, int ndigits, int *decpt, int *sign ) return first; } +/*********************************************************************** + * _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.@) */ diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index 37d2425d274..64cb2813eb9 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 d32ef737abb..f05d124a005 100644 --- a/dlls/msvcrt/tests/printf.c +++ b/dlls/msvcrt/tests/printf.c @@ -26,6 +26,7 @@ #define _CRT_NON_CONFORMING_SWPRINTFS #include +#include #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, ...)