msvcirt: Implement istream::getdouble.
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:
parent
73f60910e4
commit
ae5343bd97
|
@ -3479,10 +3479,67 @@ int __thiscall istream_getint(istream *this, char *str)
|
||||||
/* ?getdouble@istream@@AAEHPADH@Z */
|
/* ?getdouble@istream@@AAEHPADH@Z */
|
||||||
/* ?getdouble@istream@@AEAAHPEADH@Z */
|
/* ?getdouble@istream@@AEAAHPEADH@Z */
|
||||||
DEFINE_THISCALL_WRAPPER(istream_getdouble, 12)
|
DEFINE_THISCALL_WRAPPER(istream_getdouble, 12)
|
||||||
int __thiscall istream_getdouble(istream *this, char *str, int n)
|
int __thiscall istream_getdouble(istream *this, char *str, int count)
|
||||||
{
|
{
|
||||||
FIXME("(%p %p %d) stub\n", this, str, n);
|
ios *base = istream_get_ios(this);
|
||||||
return 0;
|
int ch, i = 0;
|
||||||
|
BOOL scan_sign = TRUE, scan_dot = TRUE, scan_exp = TRUE,
|
||||||
|
valid_mantissa = FALSE, valid_exponent = FALSE;
|
||||||
|
|
||||||
|
TRACE("(%p %p %d)\n", this, str, count);
|
||||||
|
|
||||||
|
if (istream_ipfx(this, 0)) {
|
||||||
|
if (!count) {
|
||||||
|
/* can't output anything */
|
||||||
|
base->state |= IOSTATE_failbit;
|
||||||
|
i = -1;
|
||||||
|
} else {
|
||||||
|
/* valid mantissas: +d. +.d +d.d (where d are sequences of digits and the sign is optional) */
|
||||||
|
/* valid exponents: e+d E+d (where d are sequences of digits and the sign is optional) */
|
||||||
|
for (ch = streambuf_sgetc(base->sb); i < count; ch = streambuf_snextc(base->sb)) {
|
||||||
|
if ((ch == '+' || ch == '-') && scan_sign) {
|
||||||
|
/* no additional sign allowed */
|
||||||
|
scan_sign = FALSE;
|
||||||
|
} else if (ch == '.' && scan_dot) {
|
||||||
|
/* no sign or additional dot allowed */
|
||||||
|
scan_sign = scan_dot = FALSE;
|
||||||
|
} else if ((ch == 'e' || ch == 'E') && scan_exp) {
|
||||||
|
/* sign is allowed again but not dots or exponents */
|
||||||
|
scan_sign = TRUE;
|
||||||
|
scan_dot = scan_exp = FALSE;
|
||||||
|
} else if (isdigit(ch)) {
|
||||||
|
if (scan_exp)
|
||||||
|
valid_mantissa = TRUE;
|
||||||
|
else
|
||||||
|
valid_exponent = TRUE;
|
||||||
|
/* no sign allowed after a digit */
|
||||||
|
scan_sign = FALSE;
|
||||||
|
} else {
|
||||||
|
/* unexpected character, stop scanning */
|
||||||
|
/* check whether the result is a valid double */
|
||||||
|
if (!scan_exp && !valid_exponent) {
|
||||||
|
/* put the last character back into the stream, usually the 'e' or 'E' */
|
||||||
|
if (streambuf_sputbackc(base->sb, str[i--]) == EOF)
|
||||||
|
base->state |= IOSTATE_badbit; /* characters have been lost for good */
|
||||||
|
} else if (ch == EOF)
|
||||||
|
base->state |= IOSTATE_eofbit;
|
||||||
|
if (!valid_mantissa)
|
||||||
|
base->state |= IOSTATE_failbit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str[i++] = ch;
|
||||||
|
}
|
||||||
|
/* check if character limit has been reached */
|
||||||
|
if (i == count) {
|
||||||
|
base->state |= IOSTATE_failbit;
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
/* append a null terminator */
|
||||||
|
str[i] = 0;
|
||||||
|
}
|
||||||
|
istream_isfx(this);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ?ws@@YAAAVistream@@AAV1@@Z */
|
/* ?ws@@YAAAVistream@@AAV1@@Z */
|
||||||
|
|
|
@ -326,6 +326,7 @@ static istream* (*__thiscall p_istream_seekg_offset)(istream*, streamoff, ios_se
|
||||||
static int (*__thiscall p_istream_sync)(istream*);
|
static int (*__thiscall p_istream_sync)(istream*);
|
||||||
static streampos (*__thiscall p_istream_tellg)(istream*);
|
static streampos (*__thiscall p_istream_tellg)(istream*);
|
||||||
static int (*__thiscall p_istream_getint)(istream*, char*);
|
static int (*__thiscall p_istream_getint)(istream*, char*);
|
||||||
|
static int (*__thiscall p_istream_getdouble)(istream*, char*, int);
|
||||||
|
|
||||||
/* Emulate a __thiscall */
|
/* Emulate a __thiscall */
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
|
@ -540,6 +541,7 @@ static BOOL init(void)
|
||||||
SET(p_istream_sync, "?sync@istream@@QEAAHXZ");
|
SET(p_istream_sync, "?sync@istream@@QEAAHXZ");
|
||||||
SET(p_istream_tellg, "?tellg@istream@@QEAAJXZ");
|
SET(p_istream_tellg, "?tellg@istream@@QEAAJXZ");
|
||||||
SET(p_istream_getint, "?getint@istream@@AEAAHPEAD@Z");
|
SET(p_istream_getint, "?getint@istream@@AEAAHPEAD@Z");
|
||||||
|
SET(p_istream_getdouble, "?getdouble@istream@@AEAAHPEADH@Z");
|
||||||
} else {
|
} else {
|
||||||
p_operator_new = (void*)GetProcAddress(msvcrt, "??2@YAPAXI@Z");
|
p_operator_new = (void*)GetProcAddress(msvcrt, "??2@YAPAXI@Z");
|
||||||
p_operator_delete = (void*)GetProcAddress(msvcrt, "??3@YAXPAX@Z");
|
p_operator_delete = (void*)GetProcAddress(msvcrt, "??3@YAXPAX@Z");
|
||||||
|
@ -676,6 +678,7 @@ static BOOL init(void)
|
||||||
SET(p_istream_sync, "?sync@istream@@QAEHXZ");
|
SET(p_istream_sync, "?sync@istream@@QAEHXZ");
|
||||||
SET(p_istream_tellg, "?tellg@istream@@QAEJXZ");
|
SET(p_istream_tellg, "?tellg@istream@@QAEJXZ");
|
||||||
SET(p_istream_getint, "?getint@istream@@AAEHPAD@Z");
|
SET(p_istream_getint, "?getint@istream@@AAEHPAD@Z");
|
||||||
|
SET(p_istream_getdouble, "?getdouble@istream@@AAEHPADH@Z");
|
||||||
}
|
}
|
||||||
SET(p_ios_static_lock, "?x_lockc@ios@@0U_CRT_CRITICAL_SECTION@@A");
|
SET(p_ios_static_lock, "?x_lockc@ios@@0U_CRT_CRITICAL_SECTION@@A");
|
||||||
SET(p_ios_lockc, "?lockc@ios@@KAXXZ");
|
SET(p_ios_lockc, "?lockc@ios@@KAXXZ");
|
||||||
|
@ -4735,6 +4738,119 @@ static void test_istream_getint(void)
|
||||||
call_func1(p_strstreambuf_dtor, &ssb);
|
call_func1(p_strstreambuf_dtor, &ssb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_istream_getdouble(void)
|
||||||
|
{
|
||||||
|
istream is, *pis;
|
||||||
|
strstreambuf ssb, *pssb;
|
||||||
|
int i, len, ret;
|
||||||
|
char buffer[32];
|
||||||
|
|
||||||
|
struct istream_getdouble_test {
|
||||||
|
const char *stream_content;
|
||||||
|
int count;
|
||||||
|
ios_io_state initial_state;
|
||||||
|
ios_flags flags;
|
||||||
|
int expected_return;
|
||||||
|
ios_io_state expected_state;
|
||||||
|
int expected_offset;
|
||||||
|
const char *expected_buffer;
|
||||||
|
BOOL broken;
|
||||||
|
} tests[] = {
|
||||||
|
{"", 32, IOSTATE_badbit, FLAGS_skipws, 0, IOSTATE_badbit|IOSTATE_failbit, 0, "", FALSE},
|
||||||
|
{"", 0, IOSTATE_badbit, FLAGS_skipws, 0, IOSTATE_badbit|IOSTATE_failbit, 0, "", FALSE},
|
||||||
|
{"", 32, IOSTATE_eofbit, FLAGS_skipws, 0, IOSTATE_eofbit|IOSTATE_failbit, 0, "", FALSE},
|
||||||
|
{"", 32, IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_eofbit|IOSTATE_failbit, 0, "", FALSE},
|
||||||
|
{" ", 32, IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_eofbit|IOSTATE_failbit, 1, "", FALSE},
|
||||||
|
{" 0", 32, IOSTATE_goodbit, FLAGS_skipws, 1, IOSTATE_eofbit, 2, "0", FALSE},
|
||||||
|
{"156", 32, IOSTATE_goodbit, FLAGS_skipws, 3, IOSTATE_eofbit, 3, "156", FALSE},
|
||||||
|
{"123 ", 32, IOSTATE_goodbit, FLAGS_skipws, 3, IOSTATE_goodbit, 3, "123", FALSE},
|
||||||
|
{"+4 5", 32, IOSTATE_goodbit, FLAGS_skipws, 2, IOSTATE_goodbit, 2, "+4", FALSE},
|
||||||
|
{"-88a", 32, IOSTATE_goodbit, FLAGS_skipws, 3, IOSTATE_goodbit, 3, "-88", FALSE},
|
||||||
|
{"-+5", 32, IOSTATE_goodbit, FLAGS_skipws, 1, IOSTATE_failbit, 1, "-", FALSE},
|
||||||
|
{"++7", 32, IOSTATE_goodbit, FLAGS_skipws, 1, IOSTATE_failbit, 1, "+", FALSE},
|
||||||
|
{"+", 32, IOSTATE_goodbit, FLAGS_skipws, 1, IOSTATE_eofbit|IOSTATE_failbit, 1, "+", FALSE},
|
||||||
|
{"abc", 32, IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_failbit, 0, "", FALSE},
|
||||||
|
{"0xabc", 32, IOSTATE_goodbit, FLAGS_skipws, 1, IOSTATE_goodbit, 1, "0", FALSE},
|
||||||
|
{"01", 32, IOSTATE_goodbit, FLAGS_skipws, 2, IOSTATE_eofbit, 2, "01", FALSE},
|
||||||
|
{"10000000000000000000", 32, IOSTATE_goodbit, FLAGS_skipws, 20, IOSTATE_eofbit, 20, "10000000000000000000", FALSE},
|
||||||
|
{"1.2", 32, IOSTATE_goodbit, FLAGS_skipws, 3, IOSTATE_eofbit, 3, "1.2", FALSE},
|
||||||
|
{"\t-0.4444f", 32, IOSTATE_goodbit, FLAGS_skipws, 7, IOSTATE_goodbit, 8, "-0.4444", FALSE},
|
||||||
|
{"3.-14159", 32, IOSTATE_goodbit, FLAGS_skipws, 2, IOSTATE_goodbit, 2, "3.", FALSE},
|
||||||
|
{"3.14.159", 32, IOSTATE_goodbit, FLAGS_skipws, 4, IOSTATE_goodbit, 4, "3.14", FALSE},
|
||||||
|
{"3.000", 32, IOSTATE_goodbit, FLAGS_skipws, 5, IOSTATE_eofbit, 5, "3.000", FALSE},
|
||||||
|
{".125f", 32, IOSTATE_goodbit, FLAGS_skipws, 4, IOSTATE_goodbit, 4, ".125", FALSE},
|
||||||
|
{"-.125f", 32, IOSTATE_goodbit, FLAGS_skipws, 5, IOSTATE_goodbit, 5, "-.125", FALSE},
|
||||||
|
{"5L", 32, IOSTATE_goodbit, FLAGS_skipws, 1, IOSTATE_goodbit, 1, "5", FALSE},
|
||||||
|
{"1.", 32, IOSTATE_goodbit, FLAGS_skipws, 2, IOSTATE_eofbit, 2, "1.", FALSE},
|
||||||
|
{"55.!", 32, IOSTATE_goodbit, FLAGS_skipws, 3, IOSTATE_goodbit, 3, "55.", FALSE},
|
||||||
|
{"99.99999999999", 32, IOSTATE_goodbit, FLAGS_skipws, 14, IOSTATE_eofbit, 14, "99.99999999999", FALSE},
|
||||||
|
{"9.9999999999999999999", 32, IOSTATE_goodbit, FLAGS_skipws, 21, IOSTATE_eofbit, 21, "9.9999999999999999999", FALSE},
|
||||||
|
{"0.0000000000000f", 32, IOSTATE_goodbit, FLAGS_skipws, 15, IOSTATE_goodbit, 15, "0.0000000000000", FALSE},
|
||||||
|
{"1.0000e5 ", 32, IOSTATE_goodbit, FLAGS_skipws, 8, IOSTATE_goodbit, 8, "1.0000e5", FALSE},
|
||||||
|
{"-2.12345e1000 ", 32, IOSTATE_goodbit, FLAGS_skipws, 13, IOSTATE_goodbit, 13, "-2.12345e1000", FALSE},
|
||||||
|
{" 8E1", 32, IOSTATE_goodbit, FLAGS_skipws, 3, IOSTATE_eofbit, 5, "8E1", FALSE},
|
||||||
|
{"99.99E-99E5", 32, IOSTATE_goodbit, FLAGS_skipws, 9, IOSTATE_goodbit, 9, "99.99E-99", FALSE},
|
||||||
|
{"0e0", 32, IOSTATE_goodbit, FLAGS_skipws|FLAGS_uppercase, 3, IOSTATE_eofbit, 3, "0e0", FALSE},
|
||||||
|
{"1.e8.5", 32, IOSTATE_goodbit, 0, 4, IOSTATE_goodbit, 4, "1.e8", FALSE},
|
||||||
|
{"1.0e-1000000000000000000 ", 32, IOSTATE_goodbit, 0, 24, IOSTATE_goodbit, 24, "1.0e-1000000000000000000", FALSE},
|
||||||
|
{"1.e+f", 32, IOSTATE_goodbit, 0, 3, IOSTATE_goodbit, 3, "1.e", FALSE},
|
||||||
|
{"1.ef", 32, IOSTATE_goodbit, 0, 2, IOSTATE_goodbit, 2, "1.", FALSE},
|
||||||
|
{"1.E-z", 32, IOSTATE_goodbit, 0, 3, IOSTATE_goodbit, 3, "1.E", FALSE},
|
||||||
|
{".", 32, IOSTATE_goodbit, 0, 1, IOSTATE_eofbit|IOSTATE_failbit, 1, ".", FALSE},
|
||||||
|
{".e", 32, IOSTATE_goodbit, 0, 1, IOSTATE_failbit, 1, ".", FALSE},
|
||||||
|
{".e.", 32, IOSTATE_goodbit, 0, 1, IOSTATE_failbit, 1, ".", FALSE},
|
||||||
|
{".e5", 32, IOSTATE_goodbit, 0, 3, IOSTATE_eofbit|IOSTATE_failbit, 3, ".e5", FALSE},
|
||||||
|
{".2e5", 32, IOSTATE_goodbit, 0, 4, IOSTATE_eofbit, 4, ".2e5", FALSE},
|
||||||
|
{"9.e", 32, IOSTATE_goodbit, 0, 2, IOSTATE_goodbit, 2, "9.", FALSE},
|
||||||
|
{"0.0e-0", 32, IOSTATE_goodbit, 0, 6, IOSTATE_eofbit, 6, "0.0e-0", FALSE},
|
||||||
|
{"e5.2", 32, IOSTATE_goodbit, 0, 2, IOSTATE_failbit, 2, "e5", FALSE},
|
||||||
|
{"1.0000", 5, IOSTATE_goodbit, 0, 4, IOSTATE_failbit, 5, "1.00", TRUE},
|
||||||
|
{"-123456", 5, IOSTATE_goodbit, 0, 4, IOSTATE_failbit, 5, "-123", TRUE},
|
||||||
|
{"3.5e2", 5, IOSTATE_goodbit, 0, 4, IOSTATE_failbit, 5, "3.5e", TRUE},
|
||||||
|
{"3.e25", 5, IOSTATE_goodbit, 0, 4, IOSTATE_failbit, 5, "3.e2", TRUE},
|
||||||
|
{"1.11f", 5, IOSTATE_goodbit, 0, 4, IOSTATE_goodbit, 4, "1.11", FALSE},
|
||||||
|
{".5e-5", 5, IOSTATE_goodbit, 0, 4, IOSTATE_failbit, 5, ".5e-", TRUE},
|
||||||
|
{".5e-", 5, IOSTATE_goodbit, 0, 3, IOSTATE_goodbit, 3, ".5e", FALSE},
|
||||||
|
{".5e2", 5, IOSTATE_goodbit, 0, 4, IOSTATE_eofbit, 4, ".5e2", FALSE},
|
||||||
|
{"1", 0, IOSTATE_goodbit, 0, -1, IOSTATE_failbit, 0, "", TRUE},
|
||||||
|
{"x", 0, IOSTATE_goodbit, 0, -1, IOSTATE_failbit, 0, "", TRUE},
|
||||||
|
{"", 0, IOSTATE_goodbit, 0, -1, IOSTATE_failbit, 0, "", TRUE},
|
||||||
|
{"", 1, IOSTATE_goodbit, 0, 0, IOSTATE_eofbit|IOSTATE_failbit, 0, "", FALSE},
|
||||||
|
{"1.0", 1, IOSTATE_goodbit, 0, 0, IOSTATE_failbit, 1, "", TRUE},
|
||||||
|
{"1.0", 2, IOSTATE_goodbit, 0, 1, IOSTATE_failbit, 2, "1", TRUE}
|
||||||
|
};
|
||||||
|
|
||||||
|
pssb = call_func2(p_strstreambuf_dynamic_ctor, &ssb, 64);
|
||||||
|
ok(pssb == &ssb, "wrong return, expected %p got %p\n", &ssb, pssb);
|
||||||
|
ret = (int) call_func1(p_streambuf_allocate, &ssb.base);
|
||||||
|
ok(ret == 1, "expected 1 got %d\n", ret);
|
||||||
|
pis = call_func3(p_istream_sb_ctor, &is, &ssb.base, TRUE);
|
||||||
|
ok(pis == &is, "wrong return, expected %p got %p\n", &is, pis);
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
|
||||||
|
len = strlen(tests[i].stream_content);
|
||||||
|
is.base_ios.state = tests[i].initial_state;
|
||||||
|
is.base_ios.flags = tests[i].flags;
|
||||||
|
ssb.base.eback = ssb.base.gptr = ssb.base.base;
|
||||||
|
ssb.base.egptr = ssb.base.base + len;
|
||||||
|
memcpy(ssb.base.base, tests[i].stream_content, len);
|
||||||
|
|
||||||
|
ret = (int) call_func3(p_istream_getdouble, &is, buffer, tests[i].count);
|
||||||
|
ok(ret == tests[i].expected_return ||
|
||||||
|
/* xp, 2k3 */ broken(tests[i].broken && ret == tests[i].expected_return + 1),
|
||||||
|
"Test %d: wrong return, expected %d got %d\n", i, tests[i].expected_return, ret);
|
||||||
|
ok(is.base_ios.state == tests[i].expected_state, "Test %d: expected %d got %d\n", i,
|
||||||
|
tests[i].expected_state, is.base_ios.state);
|
||||||
|
ok(ssb.base.gptr == ssb.base.base + tests[i].expected_offset, "Test %d: expected %p got %p\n",
|
||||||
|
i, ssb.base.base + tests[i].expected_offset, ssb.base.gptr);
|
||||||
|
ok(!strncmp(buffer, tests[i].expected_buffer, strlen(tests[i].expected_buffer)),
|
||||||
|
"Test %d: unexpected buffer content, got '%s'\n", i, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
call_func1(p_istream_vbase_dtor, &is);
|
||||||
|
call_func1(p_strstreambuf_dtor, &ssb);
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(msvcirt)
|
START_TEST(msvcirt)
|
||||||
{
|
{
|
||||||
if(!init())
|
if(!init())
|
||||||
|
@ -4749,6 +4865,7 @@ START_TEST(msvcirt)
|
||||||
test_ostream_print();
|
test_ostream_print();
|
||||||
test_istream();
|
test_istream();
|
||||||
test_istream_getint();
|
test_istream_getint();
|
||||||
|
test_istream_getdouble();
|
||||||
|
|
||||||
FreeLibrary(msvcrt);
|
FreeLibrary(msvcrt);
|
||||||
FreeLibrary(msvcirt);
|
FreeLibrary(msvcirt);
|
||||||
|
|
Loading…
Reference in New Issue