msvcirt: Implement ostream::operator<< for floats.

Signed-off-by: Iván Matellanes <matellanes.ivan@gmail.com>
Signed-off-by: Piotr Caban <piotr@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Iván Matellanes 2016-06-22 13:59:50 +01:00 committed by Alexandre Julliard
parent c969efcaf2
commit e4df032cce
2 changed files with 143 additions and 6 deletions

View File

@ -2631,6 +2631,47 @@ static ostream* ostream_internal_print_integer(ostream *ostr, int n, BOOL unsig,
return ostr;
}
static ostream* ostream_internal_print_float(ostream *ostr, double d, BOOL dbl)
{
ios *base = ostream_get_ios(ostr);
char prefix_str[2] = {0}, number_str[24], sprintf_fmt[6] = {'%','.','*','f',0};
int prec, max_prec = dbl ? 15 : 6;
int str_length = 1; /* null end char */
TRACE("(%p %lf %d)\n", ostr, d, dbl);
if (ostream_opfx(ostr)) {
if ((base->flags & FLAGS_showpos) && d > 0) {
prefix_str[0] = '+';
str_length++; /* plus sign */
}
if ((base->flags & (FLAGS_scientific|FLAGS_fixed)) == FLAGS_scientific)
sprintf_fmt[3] = (base->flags & FLAGS_uppercase) ? 'E' : 'e';
else if ((base->flags & (FLAGS_scientific|FLAGS_fixed)) != FLAGS_fixed)
sprintf_fmt[3] = (base->flags & FLAGS_uppercase) ? 'G' : 'g';
if (base->flags & FLAGS_showpoint) {
sprintf_fmt[4] = sprintf_fmt[3];
sprintf_fmt[3] = sprintf_fmt[2];
sprintf_fmt[2] = sprintf_fmt[1];
sprintf_fmt[1] = '#';
}
prec = (base->precision >= 0 && base->precision <= max_prec) ? base->precision : max_prec;
str_length += _scprintf(sprintf_fmt, prec, d); /* number representation */
if (str_length > 24) {
/* when the output length exceeds 24 characters, Windows prints an empty string with padding */
ostream_writepad(ostr, "", "");
} else {
if (sprintf(number_str, sprintf_fmt, prec, d) > 0)
ostream_writepad(ostr, prefix_str, number_str);
else
base->state |= IOSTATE_failbit;
}
ostream_osfx(ostr);
}
return ostr;
}
/* ??6ostream@@QAEAAV0@C@Z */
/* ??6ostream@@QEAAAEAV0@C@Z */
/* ??6ostream@@QAEAAV0@D@Z */
@ -2721,8 +2762,7 @@ ostream* __thiscall ostream_print_unsigned_int(ostream *this, unsigned int n)
DEFINE_THISCALL_WRAPPER(ostream_print_float, 8)
ostream* __thiscall ostream_print_float(ostream *this, float f)
{
FIXME("(%p %f) stub\n", this, f);
return this;
return ostream_internal_print_float(this, f, FALSE);
}
/* ??6ostream@@QAEAAV0@N@Z */
@ -2732,8 +2772,7 @@ ostream* __thiscall ostream_print_float(ostream *this, float f)
DEFINE_THISCALL_WRAPPER(ostream_print_double, 12)
ostream* __thiscall ostream_print_double(ostream *this, double d)
{
FIXME("(%p %lf) stub\n", this, d);
return this;
return ostream_internal_print_float(this, d, TRUE);
}
/* ??6ostream@@QAEAAV0@PBX@Z */

View File

@ -17,6 +17,7 @@
*/
#include <fcntl.h>
#include <float.h>
#include <io.h>
#include <stdio.h>
#include <windef.h>
@ -145,6 +146,20 @@ typedef struct _ostream {
ios base_ios; /* virtually inherited */
} ostream;
static inline float __port_infinity(void)
{
static const unsigned __inf_bytes = 0x7f800000;
return *(const float *)&__inf_bytes;
}
#define INFINITY __port_infinity()
static inline float __port_nan(void)
{
static const unsigned __nan_bytes = 0x7fc00000;
return *(const float *)&__nan_bytes;
}
#define NAN __port_nan()
#undef __thiscall
#ifdef __i386__
#define __thiscall __stdcall
@ -273,6 +288,8 @@ static ostream* (*__thiscall p_ostream_writepad)(ostream*, const char*, const ch
static ostream* (*__thiscall p_ostream_print_char)(ostream*, char);
static ostream* (*__thiscall p_ostream_print_str)(ostream*, const char*);
static ostream* (*__thiscall p_ostream_print_int)(ostream*, int);
static ostream* (*__thiscall p_ostream_print_float)(ostream*, float);
static ostream* (*__thiscall p_ostream_print_double)(ostream*, double);
/* Emulate a __thiscall */
#ifdef __i386__
@ -295,6 +312,8 @@ static void * (WINAPI *call_thiscall_func4)( void *func, void *this, const void
const void *c );
static void * (WINAPI *call_thiscall_func5)( void *func, void *this, const void *a, const void *b,
const void *c, const void *d );
static void * (WINAPI *call_thiscall_func2_ptr_dbl)( void *func, void *this, double a );
static void * (WINAPI *call_thiscall_func2_ptr_flt)( void *func, void *this, float a );
static void init_thiscall_thunk(void)
{
@ -310,6 +329,8 @@ static void init_thiscall_thunk(void)
call_thiscall_func3 = (void *)thunk;
call_thiscall_func4 = (void *)thunk;
call_thiscall_func5 = (void *)thunk;
call_thiscall_func2_ptr_dbl = (void *)thunk;
call_thiscall_func2_ptr_flt = (void *)thunk;
}
#define call_func1(func,_this) call_thiscall_func1(func,_this)
@ -319,6 +340,8 @@ static void init_thiscall_thunk(void)
(const void*)(c))
#define call_func5(func,_this,a,b,c,d) call_thiscall_func5(func,_this,(const void*)(a),(const void*)(b), \
(const void*)(c), (const void *)(d))
#define call_func2_ptr_dbl(func,_this,a) call_thiscall_func2_ptr_dbl(func,_this,a)
#define call_func2_ptr_flt(func,_this,a) call_thiscall_func2_ptr_flt(func,_this,a)
#else
@ -328,6 +351,8 @@ static void init_thiscall_thunk(void)
#define call_func3(func,_this,a,b) func(_this,a,b)
#define call_func4(func,_this,a,b,c) func(_this,a,b,c)
#define call_func5(func,_this,a,b,c,d) func(_this,a,b,c,d)
#define call_func2_ptr_dbl call_func2
#define call_func2_ptr_flt call_func2
#endif /* __i386__ */
@ -450,6 +475,8 @@ static BOOL init(void)
SET(p_ostream_print_char, "??6ostream@@QEAAAEAV0@D@Z");
SET(p_ostream_print_str, "??6ostream@@QEAAAEAV0@PEBD@Z");
SET(p_ostream_print_int, "??6ostream@@QEAAAEAV0@H@Z");
SET(p_ostream_print_float, "??6ostream@@QEAAAEAV0@M@Z");
SET(p_ostream_print_double, "??6ostream@@QEAAAEAV0@N@Z");
} else {
p_operator_new = (void*)GetProcAddress(msvcrt, "??2@YAPAXI@Z");
p_operator_delete = (void*)GetProcAddress(msvcrt, "??3@YAXPAX@Z");
@ -557,6 +584,8 @@ static BOOL init(void)
SET(p_ostream_print_char, "??6ostream@@QAEAAV0@D@Z");
SET(p_ostream_print_str, "??6ostream@@QAEAAV0@PBD@Z");
SET(p_ostream_print_int, "??6ostream@@QAEAAV0@H@Z");
SET(p_ostream_print_float, "??6ostream@@QAEAAV0@M@Z");
SET(p_ostream_print_double, "??6ostream@@QAEAAV0@N@Z");
}
SET(p_ios_static_lock, "?x_lockc@ios@@0U_CRT_CRITICAL_SECTION@@A");
SET(p_ios_lockc, "?lockc@ios@@KAXXZ");
@ -3021,8 +3050,12 @@ static void test_ostream_print(void)
char param_char[] = {'a', '9', 'e'};
const char* param_str[] = {"Test", "800", "3.14159", " Test"};
int param_int[] = {0, 7, 10, 24 ,55, 1024, 1023, 65536, 2147483647, 2147483648u, 4294967295u, -20};
float param_float[] = {1.0f, 0.0f, 4.25f, 3.999f, 12.0005f, 15.33582f, 15.0f, 15.22f, 21.123f, 0.1f,
13.14159f, 0.00013f, 0.000013f, INFINITY, -INFINITY, NAN};
double param_double[] = {1.0, 3.141592653589793238, 314.1592653589793238, 314.159265358979,
1231314.269811862199, 9.961472e6, 8.98846567431e307, DBL_MAX};
struct ostream_print_test {
enum { type_chr, type_str, type_int } type;
enum { type_chr, type_str, type_int, type_flt, type_dbl } type;
int param_index;
ios_io_state state;
ios_flags flags;
@ -3087,7 +3120,68 @@ static void test_ostream_print(void)
{type_int, /* 4294967295 */ 10, IOSTATE_goodbit, FLAGS_internal, 6, ' ', 8, " -1", IOSTATE_goodbit},
{type_int, /* -20 */ 11, IOSTATE_goodbit, FLAGS_internal|FLAGS_oct|FLAGS_showbase, 6, ' ', 8, "037777777754", IOSTATE_goodbit},
{type_int, /* -20 */ 11, IOSTATE_goodbit, FLAGS_dec|FLAGS_showpos, 6, ' ', 0, "-20", IOSTATE_goodbit},
{type_int, /* 0 */ 0, IOSTATE_goodbit, FLAGS_internal|FLAGS_showpos, 6, ' ', 8, " 0", IOSTATE_goodbit}
{type_int, /* 0 */ 0, IOSTATE_goodbit, FLAGS_internal|FLAGS_showpos, 6, ' ', 8, " 0", IOSTATE_goodbit},
/* float */
{type_flt, /* 1.0f */ 0, IOSTATE_badbit, 0, 6, ' ', 0, "", IOSTATE_badbit|IOSTATE_failbit},
{type_flt, /* 1.0f */ 0, IOSTATE_eofbit, 0, 6, ' ', 0, "", IOSTATE_eofbit|IOSTATE_failbit},
{type_flt, /* 1.0f */ 0, IOSTATE_goodbit, 0, 6, ' ', 0, "1", IOSTATE_goodbit},
{type_flt, /* 0.0f */ 1, IOSTATE_goodbit, 0, 6, ' ', 0, "0", IOSTATE_goodbit},
{type_flt, /* 4.25f */ 2, IOSTATE_goodbit, 0, 6, ' ', 0, "4.25", IOSTATE_goodbit},
{type_flt, /* 3.999f */ 3, IOSTATE_goodbit, 0, 6, ' ', 0, "3.999", IOSTATE_goodbit},
{type_flt, /* 3.999f */ 3, IOSTATE_goodbit, 0, 3, ' ', 0, "4", IOSTATE_goodbit},
{type_flt, /* 12.0005f */ 4, IOSTATE_goodbit, 0, 6, ' ', 0, "12.0005", IOSTATE_goodbit},
{type_flt, /* 12.0005f */ 4, IOSTATE_goodbit, 0, 5, ' ', 0, "12", IOSTATE_goodbit},
{type_flt, /* 15.33582f */ 5, IOSTATE_goodbit, 0, 4, ' ', 0, "15.34", IOSTATE_goodbit},
{type_flt, /* 15.0f */ 6, IOSTATE_goodbit, FLAGS_internal|FLAGS_hex|FLAGS_showbase, 6, ' ', 4, " 15", IOSTATE_goodbit},
{type_flt, /* 15.22f */ 7, IOSTATE_goodbit, FLAGS_left|FLAGS_hex|FLAGS_showbase, 3, ' ', 6, "15.2 ", IOSTATE_goodbit},
{type_flt, /* 15.22 */ 7, IOSTATE_goodbit, FLAGS_internal, 3, 'x', 6, "xx15.2", IOSTATE_goodbit},
{type_flt, /* 21.123f */ 8, IOSTATE_goodbit, FLAGS_showpoint, 9, ' ', 0, "21.1230", IOSTATE_goodbit},
{type_flt, /* 21.123f */ 8, IOSTATE_goodbit, FLAGS_showpos, 9, ' ', 0, "+21.123", IOSTATE_goodbit},
{type_flt, /* 21.123f */ 8, IOSTATE_goodbit, FLAGS_internal|FLAGS_showpos, 9, ' ', 8, "+ 21.123", IOSTATE_goodbit},
{type_flt, /* 21.123f */ 8, IOSTATE_goodbit, FLAGS_showpos, 0, ' ', 0, "+2e+001", IOSTATE_goodbit},
{type_flt, /* 21.123f */ 8, IOSTATE_goodbit, 0, 1, ' ', 0, "2e+001", IOSTATE_goodbit},
{type_flt, /* 21.123f */ 8, IOSTATE_goodbit, FLAGS_showpos, 2, ' ', 0, "+21", IOSTATE_goodbit},
{type_flt, /* 21.123f */ 8, IOSTATE_goodbit, 0, 4, ' ', 0, "21.12", IOSTATE_goodbit},
{type_flt, /* 21.123f */ 8, IOSTATE_goodbit, FLAGS_scientific, 2, ' ', 0, "2.11e+001", IOSTATE_goodbit},
{type_flt, /* 21.123f */ 8, IOSTATE_goodbit, FLAGS_scientific, 4, ' ', 0, "2.1123e+001", IOSTATE_goodbit},
{type_flt, /* 21.123f */ 8, IOSTATE_goodbit, FLAGS_scientific, 6, ' ', 0, "2.112300e+001", IOSTATE_goodbit},
{type_flt, /* 21.123f */ 8, IOSTATE_goodbit, FLAGS_scientific|FLAGS_uppercase, 2, ' ', 0, "2.11E+001", IOSTATE_goodbit},
{type_flt, /* 21.123f */ 8, IOSTATE_goodbit, FLAGS_scientific|FLAGS_uppercase, 2, '*', 10, "*2.11E+001", IOSTATE_goodbit},
{type_flt, /* 21.123f */ 8, IOSTATE_goodbit, FLAGS_fixed, 6, ' ', 0, "21.122999", IOSTATE_goodbit},
{type_flt, /* 0.1f */ 9, IOSTATE_goodbit, FLAGS_fixed, 6, ' ', 0, "0.100000", IOSTATE_goodbit},
{type_flt, /* 0.1f */ 9, IOSTATE_goodbit, FLAGS_scientific, 6, ' ', 0, "1.000000e-001", IOSTATE_goodbit},
{type_flt, /* 13.14159f */ 10, IOSTATE_goodbit, FLAGS_fixed, 3, ' ', 0, "13.142", IOSTATE_goodbit},
{type_flt, /* 13.14159f */ 10, IOSTATE_goodbit, FLAGS_fixed, 8, ' ', 0, "13.141590", IOSTATE_goodbit},
{type_flt, /* 13.14159f */ 10, IOSTATE_goodbit, FLAGS_fixed|FLAGS_showpoint, 8, ' ', 0, "13.141590", IOSTATE_goodbit},
{type_flt, /* 13.14159f */ 10, IOSTATE_goodbit, FLAGS_scientific|FLAGS_fixed, 8, ' ', 0, "13.1416", IOSTATE_goodbit},
{type_flt, /* 13.14159f */ 10, IOSTATE_goodbit, FLAGS_scientific|FLAGS_fixed, 2, ' ', 0, "13", IOSTATE_goodbit},
{type_flt, /* 0.00013f */ 11, IOSTATE_goodbit, 0, -1, ' ', 0, "0.00013", IOSTATE_goodbit},
{type_flt, /* 0.00013f */ 11, IOSTATE_goodbit, 0, -1, ' ', 0, "0.00013", IOSTATE_goodbit},
{type_flt, /* 0.00013f */ 11, IOSTATE_goodbit, 0, -1, ' ', 0, "0.00013", IOSTATE_goodbit},
{type_flt, /* 0.000013f */ 12, IOSTATE_goodbit, 0, 4, ' ', 0, "1.3e-005", IOSTATE_goodbit},
{type_flt, /* 0.000013f */ 12, IOSTATE_goodbit, FLAGS_showpoint, 4, ' ', 0, "1.300e-005", IOSTATE_goodbit},
{type_flt, /* 0.000013f */ 12, IOSTATE_goodbit, FLAGS_showpoint, 6, ' ', 0, "1.30000e-005", IOSTATE_goodbit},
{type_flt, /* INFINITY */ 13, IOSTATE_goodbit, 0, 6, ' ', 0, "1.#INF", IOSTATE_goodbit},
{type_flt, /* INFINITY */ 13, IOSTATE_goodbit, 0, 4, ' ', 0, "1.#IO", IOSTATE_goodbit},
{type_flt, /* -INFINITY */ 14, IOSTATE_goodbit, 0, 6, ' ', 0, "-1.#INF", IOSTATE_goodbit},
{type_flt, /* NAN */ 15, IOSTATE_goodbit, 0, 6, ' ', 0, "1.#QNAN", IOSTATE_goodbit},
/* double */
{type_dbl, /* 1.0 */ 0, IOSTATE_goodbit, 0, 6, ' ', 0, "1", IOSTATE_goodbit},
{type_dbl, /* 3.141592653589793238 */ 1, IOSTATE_goodbit, 0, 6, ' ', 0, "3.14159", IOSTATE_goodbit},
{type_dbl, /* 3.141592653589793238 */ 1, IOSTATE_goodbit, 0, 9, ' ', 0, "3.14159265", IOSTATE_goodbit},
{type_dbl, /* 3.141592653589793238 */ 1, IOSTATE_goodbit, 0, 12, ' ', 0, "3.14159265359", IOSTATE_goodbit},
{type_dbl, /* 3.141592653589793238 */ 1, IOSTATE_goodbit, 0, 15, ' ', 0, "3.14159265358979", IOSTATE_goodbit},
{type_dbl, /* 3.141592653589793238 */ 1, IOSTATE_goodbit, 0, 16, ' ', 0, "3.14159265358979", IOSTATE_goodbit},
{type_dbl, /* 314.1592653589793238 */ 2, IOSTATE_goodbit, 0, 16, ' ', 0, "314.159265358979", IOSTATE_goodbit},
{type_dbl, /* 3.141592653589793238 */ 1, IOSTATE_goodbit, FLAGS_scientific, 16, ' ', 0, "3.141592653589793e+000", IOSTATE_goodbit},
{type_dbl, /* 314.1592653589793238 */ 2, IOSTATE_goodbit, FLAGS_scientific, 16, ' ', 0, "3.141592653589793e+002", IOSTATE_goodbit},
{type_dbl, /* 3.141592653589793238 */ 1, IOSTATE_goodbit, FLAGS_fixed, -1, ' ', 0, "3.141592653589793", IOSTATE_goodbit},
{type_dbl, /* 314.159265358979 */ 3, IOSTATE_goodbit, FLAGS_fixed, 12, ' ', 0, "314.159265358979", IOSTATE_goodbit},
{type_dbl, /* 1231314.269811862199 */ 4, IOSTATE_goodbit, FLAGS_fixed, 10, ' ', 0, "1231314.2698118621", IOSTATE_goodbit},
{type_dbl, /* 9.961472e6 */ 5, IOSTATE_goodbit, FLAGS_fixed, 500, ' ', 0, "9961472.000000000000000", IOSTATE_goodbit},
/* crashes on XP/2k3 {type_dbl, 8.98846567431e307 6, IOSTATE_goodbit, FLAGS_fixed, 500, ' ', 0, "", IOSTATE_goodbit}, */
/* crashes on XP/2k3 {type_dbl, DBL_MAX 7, IOSTATE_goodbit, FLAGS_fixed|FLAGS_showpos, 500, ' ', 5, " ", IOSTATE_goodbit}, */
{type_dbl, /* DBL_MAX */ 7, IOSTATE_goodbit, FLAGS_showpoint, 500, ' ', 0, "1.79769313486232e+308", IOSTATE_goodbit}
};
pssb = call_func1(p_strstreambuf_ctor, &ssb);
@ -3110,6 +3204,10 @@ static void test_ostream_print(void)
pos = call_func2(p_ostream_print_str, &os, param_str[tests[i].param_index]); break;
case type_int:
pos = call_func2(p_ostream_print_int, &os, param_int[tests[i].param_index]); break;
case type_flt:
pos = call_func2_ptr_flt(p_ostream_print_float, &os, param_float[tests[i].param_index]); break;
case type_dbl:
pos = call_func2_ptr_dbl(p_ostream_print_double, &os, param_double[tests[i].param_index]); break;
}
length = ssb.base.pptr - ssb.base.pbase;