Rein Klazes : msvcrt: Correct implementation of _ecvt() with tests.
Alexandre Julliard
julliard at winehq.org
Tue Apr 14 16:00:00 CDT 2009
Module: wine
Branch: master
Commit: 1ab5f4191da001de527315eaf2f02c9e07990eb9
URL: http://source.winehq.org/git/wine.git/?a=commit;h=1ab5f4191da001de527315eaf2f02c9e07990eb9
Author: Rein Klazes <wijn at 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");
More information about the wine-cvs
mailing list