[4/5] msvcirt: Implement istream::getint
Iván Matellanes
matellanesivan at gmail.com
Wed Jul 20 04:56:08 CDT 2016
Signed-off-by: Iván Matellanes <matellanes.ivan at gmail.com>
---
dlls/msvcirt/msvcirt.c | 64 +++++++++++++++++++++++-
dlls/msvcirt/tests/msvcirt.c | 113 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 175 insertions(+), 2 deletions(-)
diff --git a/dlls/msvcirt/msvcirt.c b/dlls/msvcirt/msvcirt.c
index 617928a..94f9a31 100644
--- a/dlls/msvcirt/msvcirt.c
+++ b/dlls/msvcirt/msvcirt.c
@@ -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 at istream@@AAEHPAD at Z */
/* ?getint at istream@@AEAAHPEAD at 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 at istream@@AAEHPADH at Z */
diff --git a/dlls/msvcirt/tests/msvcirt.c b/dlls/msvcirt/tests/msvcirt.c
index fab46f5..99fd087 100644
--- a/dlls/msvcirt/tests/msvcirt.c
+++ b/dlls/msvcirt/tests/msvcirt.c
@@ -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 at istream@@QEAAAEAV1 at JW4seek_dir@ios@@@Z");
SET(p_istream_sync, "?sync at istream@@QEAAHXZ");
SET(p_istream_tellg, "?tellg at istream@@QEAAJXZ");
+ SET(p_istream_getint, "?getint at istream@@AEAAHPEAD at Z");
} else {
p_operator_new = (void*)GetProcAddress(msvcrt, "??2 at YAPAXI@Z");
p_operator_delete = (void*)GetProcAddress(msvcrt, "??3 at YAXPAX@Z");
@@ -673,6 +675,7 @@ static BOOL init(void)
SET(p_istream_seekg_offset, "?seekg at istream@@QAEAAV1 at JW4seek_dir@ios@@@Z");
SET(p_istream_sync, "?sync at istream@@QAEHXZ");
SET(p_istream_tellg, "?tellg at istream@@QAEJXZ");
+ SET(p_istream_getint, "?getint at istream@@AAEHPAD at Z");
}
SET(p_ios_static_lock, "?x_lockc at ios@@0U_CRT_CRITICAL_SECTION@@A");
SET(p_ios_lockc, "?lockc at 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);
--
2.7.4
More information about the wine-patches
mailing list