From: Iván Matellanes Subject: [4/9] msvcirt: Implement stdiobuf::underflow Message-Id: <1443791007-29648-4-git-send-email-matellanesivan@gmail.com> Date: Fri, 2 Oct 2015 15:03:22 +0200 In-Reply-To: <1443791007-29648-1-git-send-email-matellanesivan@gmail.com> References: <1443791007-29648-1-git-send-email-matellanesivan@gmail.com> Signed-off-by: Iván Matellanes --- dlls/msvcirt/msvcirt.c | 25 +++++++++++++++++++++-- dlls/msvcirt/tests/msvcirt.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/dlls/msvcirt/msvcirt.c b/dlls/msvcirt/msvcirt.c index 81519d0..2b54f5b 100644 --- a/dlls/msvcirt/msvcirt.c +++ b/dlls/msvcirt/msvcirt.c @@ -1607,8 +1607,29 @@ int __thiscall stdiobuf_sync(stdiobuf *this) DEFINE_THISCALL_WRAPPER(stdiobuf_underflow, 4) int __thiscall stdiobuf_underflow(stdiobuf *this) { - FIXME("(%p) stub\n", this); - return EOF; + TRACE("(%p)\n", this); + if (!this->file) + return EOF; + if (this->base.unbuffered) + return fgetc(this->file); + if (streambuf_allocate(&this->base) == EOF) + return EOF; + + if (!this->base.egptr) { + /* set the get area to the first half of the buffer */ + char *middle = this->base.base + (this->base.ebuf - this->base.base) / 2; + streambuf_setg(&this->base, this->base.base, middle, middle); + } + if (this->base.gptr >= this->base.egptr) { + /* read characters from the file */ + int buffer_size = this->base.egptr - this->base.eback, read_bytes; + if (!this->base.eback || + (read_bytes = fread(this->base.eback, sizeof(char), buffer_size, this->file)) <= 0) + return EOF; + memmove(this->base.egptr - read_bytes, this->base.eback, read_bytes); + this->base.gptr = this->base.egptr - read_bytes; + } + return *this->base.gptr++; } /* ??0ios@@IAE@ABV0@@Z */ diff --git a/dlls/msvcirt/tests/msvcirt.c b/dlls/msvcirt/tests/msvcirt.c index 53af65c..1f85186 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_underflow)(stdiobuf*); /* ios */ static ios* (*__thiscall p_ios_copy_ctor)(ios*, const ios*); @@ -372,6 +373,7 @@ static BOOL init(void) SET(p_stdiobuf_file_ctor, "??0stdiobuf@@QEAA@PEAU_iobuf@@@Z"); SET(p_stdiobuf_dtor, "??1stdiobuf@@UEAA@XZ"); SET(p_stdiobuf_overflow, "?overflow@stdiobuf@@UEAAHH@Z"); + SET(p_stdiobuf_underflow, "?underflow@stdiobuf@@UEAAHXZ"); SET(p_ios_copy_ctor, "??0ios@@IEAA@AEBV0@@Z"); SET(p_ios_ctor, "??0ios@@IEAA@XZ"); @@ -454,6 +456,7 @@ static BOOL init(void) SET(p_stdiobuf_file_ctor, "??0stdiobuf@@QAE@PAU_iobuf@@@Z"); SET(p_stdiobuf_dtor, "??1stdiobuf@@UAE@XZ"); SET(p_stdiobuf_overflow, "?overflow@stdiobuf@@UAEHH@Z"); + SET(p_stdiobuf_underflow, "?underflow@stdiobuf@@UAEHXZ"); SET(p_ios_copy_ctor, "??0ios@@IAE@ABV0@@Z"); SET(p_ios_ctor, "??0ios@@IAE@XZ"); @@ -1913,6 +1916,50 @@ static void test_stdiobuf(void) stb2.base.epptr = buffer + 64; stb2.base.unbuffered = 1; + /* underflow */ + ret = (int) call_func1(p_stdiobuf_underflow, &stb1); + ok(ret == 'N', "expected 'N' got %d\n", ret); + stb1.base.unbuffered = 0; + ret = (int) call_func1(p_stdiobuf_underflow, &stb1); + ok(ret == 'e', "expected 'e' got %d\n", ret); + ok(stb1.base.eback == stb1.base.base, "wrong get base, expected %p got %p\n", stb1.base.base, stb1.base.eback); + ok(stb1.base.gptr == stb1.base.egptr - 47, "wrong get pointer, expected %p got %p\n", stb1.base.egptr - 47, stb1.base.gptr); + ok(stb1.base.egptr == stb1.base.base + 256, "wrong get end, expected %p got %p\n", stb1.base.base + 256, stb1.base.egptr); + ok(*stb1.base.gptr == 'v', "expected 'v' got '%c'\n", *stb1.base.gptr); + stb1.base.pbase = stb1.base.pptr = stb1.base.epptr = NULL; + ret = (int) call_func1(p_stdiobuf_underflow, &stb1); + ok(ret == 'v', "expected 'v' got %d\n", ret); + ok(stb1.base.gptr == stb1.base.egptr - 46, "wrong get pointer, expected %p got %p\n", stb1.base.egptr - 46, stb1.base.gptr); + stb1.base.gptr = stb1.base.egptr; + ret = (int) call_func1(p_stdiobuf_underflow, &stb1); + ok(ret == EOF, "expected EOF got %d\n", ret); + stb1.base.unbuffered = 1; + ret = (int) call_func1(p_stdiobuf_underflow, &stb1); + ok(ret == EOF, "expected EOF got %d\n", ret); + rewind(stb2.file); + ret = (int) call_func1(p_stdiobuf_underflow, &stb2); + ok(ret == 'a', "expected 'a' got %d\n", ret); + stb2.base.unbuffered = 0; + stb2.base.eback = stb2.base.gptr = buffer + 16; + stb2.base.egptr = buffer + 32; + strcpy(buffer + 16, "and desert you"); + ret = (int) call_func1(p_stdiobuf_underflow, &stb2); + ok(ret == 'a', "expected 'a' got %d\n", ret); + ok(stb2.base.gptr == buffer + 17, "wrong get pointer, expected %p got %p\n", buffer + 17, stb2.base.gptr); + stb2.base.eback = buffer; + stb2.base.gptr = stb2.base.egptr; + stb2.base.pbase = stb2.base.pptr = stb2.base.epptr = NULL; + ret = (int) call_func1(p_stdiobuf_underflow, &stb2); + ok(ret == 'N', "expected 'N' got %d\n", ret); + ok(stb2.base.gptr == stb2.base.egptr - 22, "wrong get pointer, expected %p got %p\n", stb2.base.egptr - 22, stb2.base.gptr); + ok(ftell(stb2.file) == 24, "ftell failed\n"); + stb2.base.gptr = stb2.base.egptr; + ret = (int) call_func1(p_stdiobuf_underflow, &stb2); + ok(ret == EOF, "expected EOF got %d\n", ret); + stb2.base.unbuffered = 1; + ret = (int) call_func1(p_stdiobuf_underflow, &stb2); + ok(ret == EOF, "expected EOF got %d\n", ret); + call_func1(p_stdiobuf_dtor, &stb1); call_func1(p_stdiobuf_dtor, &stb2); fclose(file1); -- 2.1.4