[3/3] msvcirt: Improve implementation of streambuf::pbackfail (resend)

Iván Matellanes matellanesivan at gmail.com
Wed Oct 7 16:19:32 CDT 2015


Signed-off-by: Iván Matellanes <matellanesivan at gmail.com>
---
 dlls/msvcirt/msvcirt.c       | 35 +++++++++++-------
 dlls/msvcirt/tests/msvcirt.c | 88 +++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 108 insertions(+), 15 deletions(-)

diff --git a/dlls/msvcirt/msvcirt.c b/dlls/msvcirt/msvcirt.c
index bfef1a3..f590d0e 100644
--- a/dlls/msvcirt/msvcirt.c
+++ b/dlls/msvcirt/msvcirt.c
@@ -501,18 +501,6 @@ int __thiscall streambuf_overflow(streambuf *this, int c)
     return EOF;
 }
 
-/* ?pbackfail at streambuf@@UAEHH at Z */
-/* ?pbackfail at streambuf@@UEAAHH at Z */
-DEFINE_THISCALL_WRAPPER(streambuf_pbackfail, 8)
-#define call_streambuf_pbackfail(this, c) CALL_VTBL_FUNC(this, 36, int, (streambuf*, int), (this, c))
-int __thiscall streambuf_pbackfail(streambuf *this, int c)
-{
-    TRACE("(%p %d)\n", this, c);
-    if (this->gptr <= this->eback)
-        return EOF;
-    return *--this->gptr = c;
-}
-
 /* ?seekoff at streambuf@@UAEJJW4seek_dir at ios@@H at Z */
 /* ?seekoff at streambuf@@UEAAJJW4seek_dir at ios@@H at Z */
 DEFINE_THISCALL_WRAPPER(streambuf_seekoff, 16)
@@ -532,6 +520,25 @@ streampos __thiscall streambuf_seekpos(streambuf *this, streampos pos, int mode)
     return call_streambuf_seekoff(this, pos, SEEKDIR_beg, mode);
 }
 
+/* ?pbackfail at streambuf@@UAEHH at Z */
+/* ?pbackfail at streambuf@@UEAAHH at Z */
+DEFINE_THISCALL_WRAPPER(streambuf_pbackfail, 8)
+#define call_streambuf_pbackfail(this, c) CALL_VTBL_FUNC(this, 36, int, (streambuf*, int), (this, c))
+int __thiscall streambuf_pbackfail(streambuf *this, int c)
+{
+    TRACE("(%p %d)\n", this, c);
+    if (this->gptr > this->eback)
+        return *--this->gptr = c;
+    if (call_streambuf_seekoff(this, -1, SEEKDIR_cur, OPENMODE_in) == EOF)
+        return EOF;
+    if (!this->unbuffered && this->egptr) {
+        /* 'c' should be the next character read */
+        memmove(this->gptr + 1, this->gptr, this->egptr - this->gptr - 1);
+        *this->gptr = c;
+    }
+    return c;
+}
+
 /* ?setb at streambuf@@IAEXPAD0H at Z */
 /* ?setb at streambuf@@IEAAXPEAD0H at Z */
 DEFINE_THISCALL_WRAPPER(streambuf_setb, 16)
@@ -1562,8 +1569,8 @@ int __thiscall stdiobuf_overflow(stdiobuf *this, int c)
 DEFINE_THISCALL_WRAPPER(stdiobuf_pbackfail, 8)
 int __thiscall stdiobuf_pbackfail(stdiobuf *this, int c)
 {
-    FIXME("(%p %d) stub\n", this, c);
-    return EOF;
+    TRACE("(%p %d)\n", this, c);
+    return streambuf_pbackfail(&this->base, c);
 }
 
 /* ?seekoff at stdiobuf@@UAEJJW4seek_dir at ios@@H at Z */
diff --git a/dlls/msvcirt/tests/msvcirt.c b/dlls/msvcirt/tests/msvcirt.c
index 704a6c2..27ca169 100644
--- a/dlls/msvcirt/tests/msvcirt.c
+++ b/dlls/msvcirt/tests/msvcirt.c
@@ -210,6 +210,7 @@ static int (*__thiscall p_strstreambuf_underflow)(strstreambuf*);
 static stdiobuf* (*__thiscall p_stdiobuf_file_ctor)(stdiobuf*, FILE*);
 static void (*__thiscall p_stdiobuf_dtor)(stdiobuf*);
 static int (*__thiscall p_stdiobuf_overflow)(stdiobuf*, int);
+static int (*__thiscall p_stdiobuf_pbackfail)(stdiobuf*, int);
 static streampos (*__thiscall p_stdiobuf_seekoff)(stdiobuf*, streamoff, ios_seek_dir, int);
 static int (*__thiscall p_stdiobuf_setrwbuf)(stdiobuf*, int, int);
 static int (*__thiscall p_stdiobuf_sync)(stdiobuf*);
@@ -376,6 +377,7 @@ static BOOL init(void)
         SET(p_stdiobuf_file_ctor, "??0stdiobuf@@QEAA at PEAU_iobuf@@@Z");
         SET(p_stdiobuf_dtor, "??1stdiobuf@@UEAA at XZ");
         SET(p_stdiobuf_overflow, "?overflow at stdiobuf@@UEAAHH at Z");
+        SET(p_stdiobuf_pbackfail, "?pbackfail at stdiobuf@@UEAAHH at Z");
         SET(p_stdiobuf_seekoff, "?seekoff at stdiobuf@@UEAAJJW4seek_dir at ios@@H at Z");
         SET(p_stdiobuf_setrwbuf, "?setrwbuf at stdiobuf@@QEAAHHH at Z");
         SET(p_stdiobuf_sync, "?sync at stdiobuf@@UEAAHXZ");
@@ -462,6 +464,7 @@ static BOOL init(void)
         SET(p_stdiobuf_file_ctor, "??0stdiobuf@@QAE at PAU_iobuf@@@Z");
         SET(p_stdiobuf_dtor, "??1stdiobuf@@UAE at XZ");
         SET(p_stdiobuf_overflow, "?overflow at stdiobuf@@UAEHH at Z");
+        SET(p_stdiobuf_pbackfail, "?pbackfail at stdiobuf@@UAEHH at Z");
         SET(p_stdiobuf_seekoff, "?seekoff at stdiobuf@@UAEJJW4seek_dir at ios@@H at Z");
         SET(p_stdiobuf_setrwbuf, "?setrwbuf at stdiobuf@@QAEHHH at Z");
         SET(p_stdiobuf_sync, "?sync at stdiobuf@@UAEHXZ");
@@ -1432,6 +1435,38 @@ static void test_filebuf(void)
     ret = (int) call_func4(p_filebuf_seekoff, &fb1, 16, SEEKDIR_beg, 0);
     ok(ret == 16, "wrong return, expected 16 got %d\n", ret);
 
+    /* pbackfail */
+    ret = (int) call_func2(p_streambuf_pbackfail, &fb1.base, 'B');
+    ok(ret == 'B', "wrong return, expected 'B' got %d\n", ret);
+    ok(fb1.base.gptr == NULL, "wrong get pointer, expected %p got %p\n", NULL, fb1.base.gptr);
+    ok(fb1.base.pptr == NULL, "wrong put pointer, expected %p got %p\n", NULL, fb1.base.pptr);
+    ok(_tell(fb1.fd) == 15, "_tell failed\n");
+    fb1.base.eback = fb1.base.gptr = fb1.base.base;
+    fb1.base.egptr = fb1.base.pbase = fb1.base.pptr = fb1.base.base + 256;
+    fb1.base.epptr = fb1.base.ebuf;
+    ret = (int) call_func2(p_streambuf_pbackfail, &fb1.base, 'C');
+    ok(ret == EOF, "wrong return, expected EOF got %d\n", ret);
+    ok(fb1.base.gptr == fb1.base.base, "wrong get pointer, expected %p got %p\n", fb1.base.base, fb1.base.gptr);
+    ok(fb1.base.pptr == NULL, "wrong put pointer, expected %p got %p\n", NULL, fb1.base.pptr);
+    ok(_tell(fb1.fd) == 15, "_tell failed\n");
+    fb1.base.eback = fb1.base.gptr = fb1.base.base;
+    fb1.base.egptr = fb1.base.base + 2;
+    ret = (int) call_func2(p_streambuf_pbackfail, &fb1.base, 'C');
+    ok(ret == 'C', "wrong return, expected 'C' got %d\n", ret);
+    ok(fb1.base.gptr == NULL, "wrong get pointer, expected %p got %p\n", NULL, fb1.base.gptr);
+    ok(fb1.base.pptr == NULL, "wrong put pointer, expected %p got %p\n", NULL, fb1.base.pptr);
+    ok(_tell(fb1.fd) == 12, "_tell failed\n");
+    fb1.base.eback = fb1.base.gptr = fb1.base.base;
+    fb1.base.egptr = fb1.base.ebuf;
+    *fb1.base.gptr++ = 'D';
+    ret = (int) call_func2(p_streambuf_pbackfail, &fb1.base, 'C');
+    ok(ret == 'C', "wrong return, expected 'C' got %d\n", ret);
+    ok(fb1.base.gptr == fb1.base.base, "wrong get pointer, expected %p got %p\n", fb1.base.base, fb1.base.gptr);
+    ok(*fb1.base.gptr == 'C', "wrong character, expected 'C' got '%c'\n", *fb1.base.gptr);
+    ok(fb1.base.pptr == NULL, "wrong put pointer, expected %p got %p\n", NULL, fb1.base.pptr);
+    ok(_tell(fb1.fd) == 12, "_tell failed\n");
+    fb1.base.eback = fb1.base.gptr = fb1.base.egptr = NULL;
+
     /* close */
     pret = (filebuf*) call_func1(p_filebuf_close, &fb2);
     ok(pret == NULL, "wrong return, expected %p got %p\n", NULL, pret);
@@ -1833,6 +1868,21 @@ static void test_strstreambuf(void)
     ok(ret == 74, "expected 74 got %d\n", ret);
     ok(ssb2.base.pptr == ssb2.base.epptr, "wrong put pointer, expected %p got %p\n", ssb2.base.epptr, ssb2.base.pptr);
 
+    /* pbackfail */
+    *(ssb1.base.gptr-1) = 'A';
+    ret = (int) call_func2(p_streambuf_pbackfail, &ssb1.base, 'X');
+    ok(ret == 'X', "wrong return, expected 'X' got %d\n", ret);
+    ok(ssb1.base.gptr == ssb1.base.eback + 51, "wrong get pointer, expected %p got %p\n", ssb1.base.eback + 51, ssb1.base.gptr);
+    ok(*ssb1.base.gptr == 'X', "expected 'X' got '%c'\n", *ssb1.base.gptr);
+    ssb1.base.gptr = ssb1.base.eback;
+    ret = (int) call_func2(p_streambuf_pbackfail, &ssb1.base, 'Y');
+    ok(ret == EOF, "wrong return, expected EOF got %d\n", ret);
+    ssb1.base.gptr = ssb1.base.eback + 1;
+    ret = (int) call_func2(p_streambuf_pbackfail, &ssb1.base, EOF);
+    ok(ret == EOF, "wrong return, expected EOF got %d\n", ret);
+    ok(ssb1.base.gptr == ssb1.base.eback, "wrong get pointer, expected %p got %p\n", ssb1.base.eback, ssb1.base.gptr);
+    ok((signed char)*ssb1.base.gptr == EOF, "expected EOF got '%c'\n", *ssb1.base.gptr);
+
     call_func1(p_strstreambuf_dtor, &ssb1);
     call_func1(p_strstreambuf_dtor, &ssb2);
 }
@@ -1843,7 +1893,7 @@ static void test_stdiobuf(void)
     FILE *file1, *file2;
     const char filename1[] = "stdiobuf_test1";
     const char filename2[] = "stdiobuf_test2";
-    int ret;
+    int ret, last;
     char buffer[64];
 
     memset(&stb1, 0xab, sizeof(stdiobuf));
@@ -2108,6 +2158,42 @@ static void test_stdiobuf(void)
     stb2.base.gptr = stb2.base.egptr;
     stb2.base.unbuffered = 1;
 
+    /* pbackfail */
+    last = fgetc(stb1.file);
+    ok(last == 'r', "expected 'r' got %d\n", last);
+    ok(ftell(stb1.file) == 30, "ftell failed\n");
+    ret = (int) call_func2(p_stdiobuf_pbackfail, &stb1, 'i');
+    ok(ret == 'i', "expected 'i' got %d\n", ret);
+    ok(ftell(stb1.file) == 29, "ftell failed\n");
+    last = fgetc(stb1.file);
+    ok(last == 'r', "expected 'r' got %d\n", last);
+    ok(ftell(stb1.file) == 30, "ftell failed\n");
+    stb1.base.eback = stb1.base.base;
+    stb1.base.gptr = stb1.base.egptr = stb1.base.base + 9;
+    strcpy(stb1.base.eback, "pbackfail");
+    ret = (int) call_func2(p_stdiobuf_pbackfail, &stb1, 'j');
+    ok(ret == 'j', "expected 'j' got %d\n", ret);
+    ok(stb1.base.gptr == stb1.base.base + 8, "wrong get pointer, expected %p got %p\n", stb1.base.base + 8, stb1.base.gptr);
+    ok(strncmp(stb1.base.eback, "pbackfaij", 9) == 0, "strncmp failed\n");
+    ok(ftell(stb1.file) == 30, "ftell failed\n");
+    stb1.base.gptr = stb1.base.eback;
+    ret = (int) call_func2(p_stdiobuf_pbackfail, &stb1, 'k');
+    ok(ret == 'k', "expected 'k' got %d\n", ret);
+    ok(stb1.base.gptr == stb1.base.base, "wrong get pointer, expected %p got %p\n", stb1.base.base, stb1.base.gptr);
+    ok(strncmp(stb1.base.eback, "pbackfaij", 9) == 0, "strncmp failed\n");
+    ok(ftell(stb1.file) == 29, "ftell failed\n");
+    stb1.base.unbuffered = 0;
+    ret = (int) call_func2(p_stdiobuf_pbackfail, &stb1, 'l');
+    ok(ret == 'l', "expected 'l' got %d\n", ret);
+    ok(strncmp(stb1.base.eback, "lpbackfai", 9) == 0, "strncmp failed\n");
+    ok(ftell(stb1.file) == 28, "ftell failed\n");
+    stb1.base.egptr = NULL;
+    ret = (int) call_func2(p_stdiobuf_pbackfail, &stb1, 'm');
+    ok(ret == 'm', "expected 'm' got %d\n", ret);
+    ok(strncmp(stb1.base.eback, "lpbackfai", 9) == 0, "strncmp failed\n");
+    ok(ftell(stb1.file) == 27, "ftell failed\n");
+    stb1.base.unbuffered = 1;
+
     call_func1(p_stdiobuf_dtor, &stb1);
     call_func1(p_stdiobuf_dtor, &stb2);
     fclose(file1);
-- 
2.1.4




More information about the wine-patches mailing list