msvcirt: Implement istream::getint.
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
c484ee409f
commit
21ea9f0efb
|
@ -3407,13 +3407,73 @@ streampos __thiscall istream_tellg(istream *this)
|
|||
return pos;
|
||||
}
|
||||
|
||||
static int getint_is_valid_digit(char ch, int base)
|
||||
{
|
||||
if (base == 8) return (ch >= '0' && ch <= '7');
|
||||
if (base == 16) return isxdigit(ch);
|
||||
return isdigit(ch);
|
||||
}
|
||||
|
||||
/* ?getint@istream@@AAEHPAD@Z */
|
||||
/* ?getint@istream@@AEAAHPEAD@Z */
|
||||
DEFINE_THISCALL_WRAPPER(istream_getint, 8)
|
||||
int __thiscall istream_getint(istream *this, char *str)
|
||||
{
|
||||
FIXME("(%p %p) stub\n", this, str);
|
||||
return 0;
|
||||
ios *base = istream_get_ios(this);
|
||||
int ch, num_base = 0, i = 0;
|
||||
BOOL scan_sign = TRUE, scan_prefix = TRUE, scan_x = FALSE, valid_integer = FALSE;
|
||||
|
||||
TRACE("(%p %p)\n", this, str);
|
||||
|
||||
if (istream_ipfx(this, 0)) {
|
||||
num_base = (base->flags & FLAGS_dec) ? 10 :
|
||||
(base->flags & FLAGS_hex) ? 16 :
|
||||
(base->flags & FLAGS_oct) ? 8 : 0; /* 0 = autodetect */
|
||||
/* scan valid characters, up to 15 (hard limit on Windows) */
|
||||
for (ch = streambuf_sgetc(base->sb); i < 15; ch = streambuf_snextc(base->sb)) {
|
||||
if ((ch == '+' || ch == '-') && scan_sign) {
|
||||
/* no additional sign allowed */
|
||||
scan_sign = FALSE;
|
||||
} else if ((ch == 'x' || ch == 'X') && scan_x) {
|
||||
/* only hex digits can (and must) follow */
|
||||
scan_x = valid_integer = FALSE;
|
||||
num_base = 16;
|
||||
} else if (ch == '0' && scan_prefix) {
|
||||
/* might be the octal prefix, the beginning of the hex prefix or a decimal zero */
|
||||
scan_sign = scan_prefix = FALSE;
|
||||
scan_x = !num_base || num_base == 16;
|
||||
valid_integer = TRUE;
|
||||
if (!num_base)
|
||||
num_base = 8;
|
||||
} else if (getint_is_valid_digit(ch, num_base)) {
|
||||
/* only digits in the corresponding base can follow */
|
||||
scan_sign = scan_prefix = scan_x = FALSE;
|
||||
valid_integer = TRUE;
|
||||
} else {
|
||||
/* unexpected character, stop scanning */
|
||||
if (!valid_integer) {
|
||||
/* the result is not a valid integer */
|
||||
base->state |= IOSTATE_failbit;
|
||||
/* put any extracted character back into the stream */
|
||||
while (i > 0)
|
||||
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 (scan_x && !(base->flags & ios_basefield)) {
|
||||
/* when autodetecting, a single zero followed by EOF is regarded as decimal */
|
||||
num_base = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
str[i++] = ch;
|
||||
}
|
||||
/* append a null terminator */
|
||||
str[i] = 0;
|
||||
istream_isfx(this);
|
||||
}
|
||||
return num_base;
|
||||
}
|
||||
|
||||
/* ?getdouble@istream@@AAEHPADH@Z */
|
||||
|
|
|
@ -325,6 +325,7 @@ static istream* (*__thiscall p_istream_seekg)(istream*, streampos);
|
|||
static istream* (*__thiscall p_istream_seekg_offset)(istream*, streamoff, ios_seek_dir);
|
||||
static int (*__thiscall p_istream_sync)(istream*);
|
||||
static streampos (*__thiscall p_istream_tellg)(istream*);
|
||||
static int (*__thiscall p_istream_getint)(istream*, char*);
|
||||
|
||||
/* Emulate a __thiscall */
|
||||
#ifdef __i386__
|
||||
|
@ -538,6 +539,7 @@ static BOOL init(void)
|
|||
SET(p_istream_seekg_offset, "?seekg@istream@@QEAAAEAV1@JW4seek_dir@ios@@@Z");
|
||||
SET(p_istream_sync, "?sync@istream@@QEAAHXZ");
|
||||
SET(p_istream_tellg, "?tellg@istream@@QEAAJXZ");
|
||||
SET(p_istream_getint, "?getint@istream@@AEAAHPEAD@Z");
|
||||
} else {
|
||||
p_operator_new = (void*)GetProcAddress(msvcrt, "??2@YAPAXI@Z");
|
||||
p_operator_delete = (void*)GetProcAddress(msvcrt, "??3@YAXPAX@Z");
|
||||
|
@ -673,6 +675,7 @@ static BOOL init(void)
|
|||
SET(p_istream_seekg_offset, "?seekg@istream@@QAEAAV1@JW4seek_dir@ios@@@Z");
|
||||
SET(p_istream_sync, "?sync@istream@@QAEHXZ");
|
||||
SET(p_istream_tellg, "?tellg@istream@@QAEJXZ");
|
||||
SET(p_istream_getint, "?getint@istream@@AAEHPAD@Z");
|
||||
}
|
||||
SET(p_ios_static_lock, "?x_lockc@ios@@0U_CRT_CRITICAL_SECTION@@A");
|
||||
SET(p_ios_lockc, "?lockc@ios@@KAXXZ");
|
||||
|
@ -4623,6 +4626,115 @@ if (0) /* crashes on native */
|
|||
ok(_unlink(filename2) == 0, "Couldn't unlink file named '%s'\n", filename2);
|
||||
}
|
||||
|
||||
static void test_istream_getint(void)
|
||||
{
|
||||
istream is, *pis;
|
||||
strstreambuf ssb, *pssb;
|
||||
int i, len, ret;
|
||||
char buffer[32];
|
||||
|
||||
struct istream_getint_test {
|
||||
const char *stream_content;
|
||||
ios_io_state initial_state;
|
||||
ios_flags flags;
|
||||
int expected_return;
|
||||
ios_io_state expected_state;
|
||||
int expected_offset;
|
||||
const char *expected_buffer;
|
||||
} tests[] = {
|
||||
{"", IOSTATE_badbit, FLAGS_skipws, 0, IOSTATE_badbit|IOSTATE_failbit, 0, ""},
|
||||
{"", IOSTATE_eofbit, FLAGS_skipws, 0, IOSTATE_eofbit|IOSTATE_failbit, 0, ""},
|
||||
{"", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_eofbit|IOSTATE_failbit, 0, ""},
|
||||
{" 0 ", IOSTATE_goodbit, FLAGS_skipws, 8, IOSTATE_goodbit, 2, "0"},
|
||||
{" \n0", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_eofbit, 3, "0"},
|
||||
{"-0", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_eofbit, 2, "-0"},
|
||||
{"000\n", IOSTATE_goodbit, FLAGS_skipws, 8, IOSTATE_goodbit, 3, "000"},
|
||||
{"015 16", IOSTATE_goodbit, FLAGS_skipws, 8, IOSTATE_goodbit, 3, "015"},
|
||||
{"099", IOSTATE_goodbit, FLAGS_skipws, 8, IOSTATE_goodbit, 1, "0"},
|
||||
{" 12345", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_eofbit, 6, "12345"},
|
||||
{"12345\r", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_goodbit, 5, "12345"},
|
||||
{"0xab ", IOSTATE_goodbit, FLAGS_skipws, 16, IOSTATE_goodbit, 4, "0xab"},
|
||||
{" 0xefg", IOSTATE_goodbit, FLAGS_skipws, 16, IOSTATE_goodbit, 5, "0xef"},
|
||||
{"0XABc", IOSTATE_goodbit, FLAGS_skipws, 16, IOSTATE_eofbit, 5, "0XABc"},
|
||||
{"0xzzz", IOSTATE_goodbit, FLAGS_skipws, 16, IOSTATE_failbit, 0, ""},
|
||||
{"0y123", IOSTATE_goodbit, FLAGS_skipws, 8, IOSTATE_goodbit, 1, "0"},
|
||||
{"\t+42 ", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_goodbit, 4, "+42"},
|
||||
{"+\t42", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_failbit, 0, ""},
|
||||
{"+4\t2", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_goodbit, 2, "+4"},
|
||||
{"+0xc", IOSTATE_goodbit, FLAGS_skipws, 16, IOSTATE_eofbit, 4, "+0xc"},
|
||||
{" -1 ", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_goodbit, 3, "-1"},
|
||||
{" -005 ", IOSTATE_goodbit, FLAGS_skipws, 8, IOSTATE_goodbit, 5, "-005"},
|
||||
{" 2-0 ", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_goodbit, 2, "2"},
|
||||
{"--3 ", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_failbit, 0, ""},
|
||||
{"+-7", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_failbit, 0, ""},
|
||||
{"+", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_failbit, 0, ""},
|
||||
{"-0x123abc", IOSTATE_goodbit, FLAGS_skipws, 16, IOSTATE_eofbit, 9, "-0x123abc"},
|
||||
{"0-x123abc", IOSTATE_goodbit, FLAGS_skipws, 8, IOSTATE_goodbit, 1, "0"},
|
||||
{"0x-123abc", IOSTATE_goodbit, FLAGS_skipws, 16, IOSTATE_failbit, 0, ""},
|
||||
{"2147483648", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_eofbit, 10, "2147483648"},
|
||||
{"99999999999999", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_eofbit, 14, "99999999999999"},
|
||||
{"999999999999999", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_goodbit, 15, "999999999999999"},
|
||||
{"123456789123456789", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_goodbit, 15, "123456789123456"},
|
||||
{"000000000000000000", IOSTATE_goodbit, FLAGS_skipws, 8, IOSTATE_goodbit, 15, "000000000000000"},
|
||||
{"-0xffffffffffffffffff", IOSTATE_goodbit, FLAGS_skipws, 16, IOSTATE_goodbit, 15, "-0xffffffffffff"},
|
||||
{"3.14159", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_goodbit, 1, "3"},
|
||||
{"deadbeef", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_failbit, 0, ""},
|
||||
{"0deadbeef", IOSTATE_goodbit, FLAGS_skipws, 8, IOSTATE_goodbit, 1, "0"},
|
||||
{"98765L", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_goodbit, 5, "98765"},
|
||||
{"9999l", IOSTATE_goodbit, FLAGS_skipws, 0, IOSTATE_goodbit, 4, "9999"},
|
||||
{" 1", IOSTATE_goodbit, 0, 0, IOSTATE_failbit, 0, ""},
|
||||
{"1 ", IOSTATE_goodbit, 0, 0, IOSTATE_goodbit, 1, "1"},
|
||||
{"010", IOSTATE_goodbit, FLAGS_dec, 10, IOSTATE_eofbit, 3, "010"},
|
||||
{"0x123", IOSTATE_goodbit, FLAGS_dec, 10, IOSTATE_goodbit, 1, "0"},
|
||||
{"x1", IOSTATE_goodbit, FLAGS_dec, 10, IOSTATE_failbit, 0, ""},
|
||||
{"33", IOSTATE_goodbit, FLAGS_dec|FLAGS_oct, 10, IOSTATE_eofbit, 2, "33"},
|
||||
{"abc", IOSTATE_goodbit, FLAGS_dec|FLAGS_hex, 10, IOSTATE_failbit, 0, ""},
|
||||
{"33", IOSTATE_goodbit, FLAGS_oct, 8, IOSTATE_eofbit, 2, "33"},
|
||||
{"9", IOSTATE_goodbit, FLAGS_oct, 8, IOSTATE_failbit, 0, ""},
|
||||
{"0", IOSTATE_goodbit, FLAGS_oct, 8, IOSTATE_eofbit, 1, "0"},
|
||||
{"x1", IOSTATE_goodbit, FLAGS_oct, 8, IOSTATE_failbit, 0, ""},
|
||||
{"9", IOSTATE_goodbit, FLAGS_oct|FLAGS_hex, 16, IOSTATE_eofbit, 1, "9"},
|
||||
{"abc", IOSTATE_goodbit, FLAGS_oct|FLAGS_hex, 16, IOSTATE_eofbit, 3, "abc"},
|
||||
{"123 ", IOSTATE_goodbit, FLAGS_hex, 16, IOSTATE_goodbit, 3, "123"},
|
||||
{"x123 ", IOSTATE_goodbit, FLAGS_hex, 16, IOSTATE_failbit, 0, ""},
|
||||
{"0x123 ", IOSTATE_goodbit, FLAGS_hex, 16, IOSTATE_goodbit, 5, "0x123"},
|
||||
{"-a", IOSTATE_goodbit, FLAGS_hex, 16, IOSTATE_eofbit, 2, "-a"},
|
||||
{"-j", IOSTATE_goodbit, FLAGS_hex, 16, IOSTATE_failbit, 0, ""},
|
||||
{"-0x-1", IOSTATE_goodbit, FLAGS_hex, 16, IOSTATE_failbit, 0, ""},
|
||||
{"0", IOSTATE_goodbit, FLAGS_dec|FLAGS_oct|FLAGS_hex, 10, IOSTATE_eofbit, 1, "0"},
|
||||
{"0z", IOSTATE_goodbit, FLAGS_dec|FLAGS_oct|FLAGS_hex, 10, IOSTATE_goodbit, 1, "0"}
|
||||
};
|
||||
|
||||
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_func2(p_istream_getint, &is, buffer);
|
||||
ok(ret == tests[i].expected_return, "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)
|
||||
{
|
||||
if(!init())
|
||||
|
@ -4636,6 +4748,7 @@ START_TEST(msvcirt)
|
|||
test_ostream();
|
||||
test_ostream_print();
|
||||
test_istream();
|
||||
test_istream_getint();
|
||||
|
||||
FreeLibrary(msvcrt);
|
||||
FreeLibrary(msvcirt);
|
||||
|
|
Loading…
Reference in New Issue