Module: wine Branch: master Commit: 1ab5f4191da001de527315eaf2f02c9e07990eb9 URL: http://source.winehq.org/git/wine.git/?a=commit;h=1ab5f4191da001de527315eaf2...
Author: Rein Klazes wijn@online.nl Date: Mon Apr 13 09:06:41 2009 +0200
msvcrt: Correct implementation of _ecvt() with tests.
---
dlls/msvcrt/math.c | 38 ++++++++++++++++--- dlls/msvcrt/tests/printf.c | 85 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 6 deletions(-)
diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c index 0c6290c..3b026a3 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -836,16 +836,42 @@ double CDECL _nextafter(double num, double next) */ char * CDECL _ecvt( double number, int ndigits, int *decpt, int *sign ) { + int prec; thread_data_t *data = msvcrt_get_thread_data(); - char *dec; - + /* FIXME: check better for overflow (native supports over 300 chars's) */ + ndigits = min( ndigits, 80 - 7); /* 7 : space for dec point, 1 for "e", + * 4 for exponent and one for + * terminating '\0' */ if (!data->efcvt_buffer) data->efcvt_buffer = MSVCRT_malloc( 80 ); /* ought to be enough */
- snprintf(data->efcvt_buffer, 80, "%.*e", ndigits /* FIXME wrong */, number); - *sign = (number < 0); - dec = strchr(data->efcvt_buffer, '.'); - *decpt = (dec) ? dec - data->efcvt_buffer : -1; + if( number < 0) { + *sign = TRUE; + number = -number; + } else + *sign = FALSE; + /* handle cases with zero ndigits or less */ + prec = ndigits; + if( prec < 1) prec = 2; + snprintf(data->efcvt_buffer, 80, "%.*le", prec - 1, number); + /* take the decimal "point away */ + if( prec != 1) + strcpy( data->efcvt_buffer + 1, data->efcvt_buffer + 2); + /* take the exponential "e" out */ + data->efcvt_buffer[ prec] = '\0'; + /* read the exponent */ + sscanf( data->efcvt_buffer + prec + 1, "%d", decpt); + (*decpt)++; + /* adjust for some border cases */ + if( data->efcvt_buffer[0] == '0')/* value is zero */ + *decpt = 0; + /* handle cases with zero ndigits or less */ + if( ndigits < 1){ + if( data->efcvt_buffer[ 0] >= '5') + (*decpt)++; + data->efcvt_buffer[ 0] = '\0'; + } + TRACE("out="%s"\n",data->efcvt_buffer); return data->efcvt_buffer; }
diff --git a/dlls/msvcrt/tests/printf.c b/dlls/msvcrt/tests/printf.c index 5f72b47..66bab15 100644 --- a/dlls/msvcrt/tests/printf.c +++ b/dlls/msvcrt/tests/printf.c @@ -698,6 +698,90 @@ static void test_fcvt(void) ok( 0 == sign, "sign wrong\n"); }
+static struct { + double value; + int nrdigits; + const char *expstr_e; + const char *expstr_f; + int expdecpt_e; + int expdecpt_f; + int expsign; +} test_cvt_testcases[] = { + { 45.0, 2, "45", "4500", 2, 2, 0 }, + /* Numbers less than 1.0 with different precisions */ + { 0.0001, 1, "1", "", -3, -3, 0 }, + { 0.0001, -10, "", "", -3, -3, 0 }, + { 0.0001, 10,"1000000000", "1000000", -3, -3, 0 }, + /* Basic sign test */ + { -111.0001, 5, "11100", "11100010", 3, 3, 1 }, + { 111.0001, 5, "11100", "11100010", 3, 3, 0 }, + /* big numbers with low precision */ + { 3333.3, 2, "33", "333330", 4, 4, 0 }, + {999999999999.9, 3, "100","999999999999900", 13, 12, 0 }, + /* 0.0 with different precisions */ + { 0.0, 5, "00000", "00000", 0, 0, 0 }, + { 0.0, 0, "", "", 0, 0, 0 }, + { 0.0, -1, "", "", 0, 0, 0 }, + /* Numbers > 1.0 with 0 or -ve precision */ + { -123.0001, 0, "", "123", 3, 3, 1 }, + { -123.0001, -1, "", "12", 3, 3, 1 }, + { -123.0001, -2, "", "1", 3, 3, 1 }, + { -123.0001, -3, "", "", 3, 3, 1 }, + /* Numbers > 1.0, but with rounding at the point of precision */ + { 99.99, 1, "1", "1000", 3, 3, 0 }, + /* Numbers < 1.0 where rounding occurs at the point of precision */ + { 0.0063, 2, "63", "1", -2, -1, 0 }, + { 0.0063, 3, "630", "6", -2, -2, 0 }, + { 0.09999999996, 2, "10", "10", 0, 0, 0 }, + { 0.6, 1, "6", "6", 0, 0, 0 }, + { 0.6, 0, "", "1", 1, 1, 0 }, + { 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 */ + { 1.0, 30, "100000000000000000000000000000", + "1000000000000000000000000000000", 1, 1, 0}, + { 123456789012345678901.0, 30, "123456789012345680000000000000", + "123456789012345680000000000000000000000000000000000", 21, 21, 0}, + /* end marker */ + { 0, 0, "END"} +}; + +static void test_xcvt(void) +{ + char *str; + int i, decpt, sign; + for( i = 0; strcmp( test_cvt_testcases[i].expstr_e, "END"); i++){ + decpt = sign = 100; + str = _ecvt( test_cvt_testcases[i].value, + test_cvt_testcases[i].nrdigits, + &decpt, + &sign); + ok( 0 == strncmp( str, test_cvt_testcases[i].expstr_e, 15), + "_ecvt() bad return, got \n'%s' expected \n'%s'\n", str, + test_cvt_testcases[i].expstr_e); + ok( decpt == test_cvt_testcases[i].expdecpt_e, + "_ecvt() decimal point wrong, got %d expected %d\n", decpt, + test_cvt_testcases[i].expdecpt_e); + } + for( i = 0; strcmp( test_cvt_testcases[i].expstr_e, "END"); i++){ + decpt = sign = 100; + str = _fcvt( test_cvt_testcases[i].value, + test_cvt_testcases[i].nrdigits, + &decpt, + &sign); + ok( 0 == strncmp( str, test_cvt_testcases[i].expstr_f, 15), + "_fcvt() bad return, got \n'%s' expected \n'%s'\n", str, + test_cvt_testcases[i].expstr_f); + ok( decpt == test_cvt_testcases[i].expdecpt_f, + "_fcvt() decimal point wrong, got %d expected %d\n", decpt, + test_cvt_testcases[i].expdecpt_f); + ok( sign == test_cvt_testcases[i].expsign, + "_ecvt() sign wrong, got %d expected %d\n", sign, + test_cvt_testcases[i].expsign); + } +} + static int _vsnwprintf_wrapper(wchar_t *str, size_t len, const wchar_t *format, ...) { int ret; @@ -774,6 +858,7 @@ START_TEST(printf) test_swprintf(); test_snprintf(); test_fcvt(); + test_xcvt(); test_vsnwprintf();
p__vscprintf = (void *)GetProcAddress(GetModuleHandle("msvcrt.dll"), "_vscprintf");