[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