[v3 4/7] msvcirt: Implement ostream::operator<< for floats
Iván Matellanes
matellanesivan at gmail.com
Wed Jun 22 07:59:50 CDT 2016
Signed-off-by: Iván Matellanes <matellanes.ivan at gmail.com>
---
dlls/msvcirt/msvcirt.c | 47 ++++++++++++++++++--
dlls/msvcirt/tests/msvcirt.c | 102 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 143 insertions(+), 6 deletions(-)
diff --git a/dlls/msvcirt/msvcirt.c b/dlls/msvcirt/msvcirt.c
index 9988944..cfea9c1 100644
--- a/dlls/msvcirt/msvcirt.c
+++ b/dlls/msvcirt/msvcirt.c
@@ -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 at C@Z */
/* ??6ostream@@QEAAAEAV0 at C@Z */
/* ??6ostream@@QAEAAV0 at 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 at 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 at PBX@Z */
diff --git a/dlls/msvcirt/tests/msvcirt.c b/dlls/msvcirt/tests/msvcirt.c
index c07585b..ddb53eb 100644
--- a/dlls/msvcirt/tests/msvcirt.c
+++ b/dlls/msvcirt/tests/msvcirt.c
@@ -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 at D@Z");
SET(p_ostream_print_str, "??6ostream@@QEAAAEAV0 at PEBD@Z");
SET(p_ostream_print_int, "??6ostream@@QEAAAEAV0 at H@Z");
+ SET(p_ostream_print_float, "??6ostream@@QEAAAEAV0 at M@Z");
+ SET(p_ostream_print_double, "??6ostream@@QEAAAEAV0 at N@Z");
} else {
p_operator_new = (void*)GetProcAddress(msvcrt, "??2 at YAPAXI@Z");
p_operator_delete = (void*)GetProcAddress(msvcrt, "??3 at YAXPAX@Z");
@@ -557,6 +584,8 @@ static BOOL init(void)
SET(p_ostream_print_char, "??6ostream@@QAEAAV0 at D@Z");
SET(p_ostream_print_str, "??6ostream@@QAEAAV0 at PBD@Z");
SET(p_ostream_print_int, "??6ostream@@QAEAAV0 at H@Z");
+ SET(p_ostream_print_float, "??6ostream@@QAEAAV0 at M@Z");
+ SET(p_ostream_print_double, "??6ostream@@QAEAAV0 at N@Z");
}
SET(p_ios_static_lock, "?x_lockc at ios@@0U_CRT_CRITICAL_SECTION@@A");
SET(p_ios_lockc, "?lockc at 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;
--
2.7.4
More information about the wine-patches
mailing list