diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 2d96e45cb3a..eaca30d41cc 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,38 @@ +2003-09-03 Petur Runolfsson + + PR libstdc++/12048 + * include/ext/stdio_sync_filebuf.h + (stdio_sync_filebuf::_M_unget_buf): Declare it. + (stdio_sync_filebuf::stdio_sync_filebuf): Initialize _M_unget_buf. + (stdio_sync_filebuf::uflow): Store the returned character in + _M_unget_buf. + (stdio_sync_filebuf::pbackfail): If argument is eof(), pass + _M_unget_buf to syncungetc(). Set _M_unget_buf to eof(). + (stdio_sync_filebuf::xsgetn): Store last read character in + _M_unget_buf, if any, else eof(). + (stdio_sync_filebuf::xsgetn: Store last read character in + _M_unget_buf, if any, else eof(). + * testsuite/27_io/objects/char/12048.cc: Rename to... + * testsuite/27_io/objects/char/12048-1.cc: ...this. + * testsuite/27_io/objects/char/12048-2.cc: New test. + * testsuite/27_io/objects/char/12048-3.cc: New test. + * testsuite/27_io/objects/char/12048-4.cc: New test. + * testsuite/27_io/objects/char/12048-5.cc: New test. XFAIL. + * testsuite/27_io/objects/wchar_t/12048-1.cc: New test. + * testsuite/27_io/objects/wchar_t/12048-2.cc: New test. + * testsuite/27_io/objects/wchar_t/12048-3.cc: New test. + * testsuite/27_io/objects/wchar_t/12048-4.cc: New test. + * testsuite/27_io/objects/wchar_t/12048-5.cc: New test. XFAIL. + * testsuite/ext/stdio_sync_filebuf_char.cc + (test02, test03, test04, test05): New tests. + * testsuite/ext/stdio_sync_filebuf_wchar_t.cc + (test02, test03, test04, test05): New tests. + +2003-09-03 Petur Runolfsson + + * docs/html/27_io/howto.html: setbuf(0, 0) has no effect on + stringbuf or strstreambuf. Fix typos. + 2003-09-02 Phil Edwards * acinclude.m4 (GLIBCXX_ENABLE_HOSTED): #define _GLIBCXX_HOSTED diff --git a/libstdc++-v3/docs/html/27_io/howto.html b/libstdc++-v3/docs/html/27_io/howto.html index 4a0b6a927fb..35568c453ff 100644 --- a/libstdc++-v3/docs/html/27_io/howto.html +++ b/libstdc++-v3/docs/html/27_io/howto.html @@ -185,9 +185,10 @@ setbuf()-ish functions; the classes derived from streambuf each define behavior that "makes sense" for that class: an argument of (0,0) turns off buffering - for filebuf but has undefined behavior for its sibling - stringbuf, and specifying anything other than (0,0) has - varying effects. Other user-defined class derived from streambuf can + for filebuf but does nothing at all for its siblings + stringbuf and strstreambuf, and specifying + anything other than (0,0) has varying effects. + User-defined classes derived from streambuf can do whatever they want. (For filebuf and arguments for (p,s) other than zeros, libstdc++ does what you'd expect: the first s bytes of p are used as a buffer, diff --git a/libstdc++-v3/include/ext/stdio_sync_filebuf.h b/libstdc++-v3/include/ext/stdio_sync_filebuf.h index 64ec2d97340..7697d86816e 100644 --- a/libstdc++-v3/include/ext/stdio_sync_filebuf.h +++ b/libstdc++-v3/include/ext/stdio_sync_filebuf.h @@ -57,10 +57,7 @@ namespace __gnu_cxx template > class stdio_sync_filebuf : public std::basic_streambuf<_CharT, _Traits> { - private: - std::__c_file* const _M_file; - - public: + public: // Types: typedef _CharT char_type; typedef _Traits traits_type; @@ -68,8 +65,19 @@ namespace __gnu_cxx typedef typename traits_type::pos_type pos_type; typedef typename traits_type::off_type off_type; + private: + // Underlying stdio FILE + std::__c_file* const _M_file; + + // Last character gotten. This is used when pbackfail is + // called from basic_streambuf::sungetc() + int_type _M_unget_buf; + + public: explicit - stdio_sync_filebuf(std::__c_file* __f) : _M_file(__f) { } + stdio_sync_filebuf(std::__c_file* __f) + : _M_file(__f), _M_unget_buf(traits_type::eof()) + { } protected: @@ -91,11 +99,33 @@ namespace __gnu_cxx virtual int_type uflow() - { return this->syncgetc(); } + { + // Store the gotten character in case we need to unget it. + _M_unget_buf = this->syncgetc(); + return _M_unget_buf; + } virtual int_type pbackfail(int_type __c = traits_type::eof()) - { return this->syncungetc(__c); } + { + int_type __ret; + const int_type __eof = traits_type::eof(); + + // Check if the unget or putback was requested + if (traits_type::eq_int_type(__c, __eof)) // unget + { + if (!traits_type::eq_int_type(_M_unget_buf, __eof)) + __ret = this->syncungetc(_M_unget_buf); + else // buffer invalid, fail. + __ret = __eof; + } + else // putback + __ret = this->syncungetc(__c); + + // The buffered character is no longer valid, discard it. + _M_unget_buf = __eof; + return __ret; + } virtual std::streamsize xsgetn(char_type* __s, std::streamsize __n); @@ -179,7 +209,14 @@ namespace __gnu_cxx template<> inline std::streamsize stdio_sync_filebuf::xsgetn(char* __s, std::streamsize __n) - { return std::fread(__s, 1, __n, _M_file); } + { + std::streamsize __ret = std::fread(__s, 1, __n, _M_file); + if (__ret > 0) + _M_unget_buf = traits_type::to_int_type(__s[__ret - 1]); + else + _M_unget_buf = traits_type::eof(); + return __ret; + } template<> inline std::streamsize @@ -213,9 +250,14 @@ namespace __gnu_cxx int_type __c = this->syncgetc(); if (traits_type::eq_int_type(__c, __eof)) break; - *__s++ = __c; + __s[__ret] = traits_type::to_char_type(__c); ++__ret; } + + if (__ret > 0) + _M_unget_buf = traits_type::to_int_type(__s[__ret - 1]); + else + _M_unget_buf = traits_type::eof(); return __ret; } diff --git a/libstdc++-v3/testsuite/ext/stdio_sync_filebuf_char.cc b/libstdc++-v3/testsuite/ext/stdio_sync_filebuf_char.cc index cffcf37590f..095829621fb 100644 --- a/libstdc++-v3/testsuite/ext/stdio_sync_filebuf_char.cc +++ b/libstdc++-v3/testsuite/ext/stdio_sync_filebuf_char.cc @@ -52,13 +52,89 @@ void test01() VERIFY( sbuf.sgetn(buf, 5) == 5 ); VERIFY( !memcmp(buf, c_lit + 3, 5) ); VERIFY( getc(fin) == c_lit[8] ); - VERIFY( sbuf.sungetc() == EOF ); fclose(fin); } +// libstdc++/12048 +void test02() +{ + bool test = true; + const char* name = "cin_unget-1.txt"; + + std::FILE* file = std::fopen(name, "r"); + __gnu_cxx::stdio_sync_filebuf sbuf(file); + int c1 = sbuf.sbumpc(); + VERIFY( c1 != EOF ); + int c2 = sbuf.sungetc(); + VERIFY( c2 != EOF ); + int c3 = sbuf.sbumpc(); + VERIFY( c3 == c1 ); + + std::fclose(file); +} + +// libstdc++/12048 +void test03() +{ + bool test = true; + const char* name = "cin_unget-1.txt"; + + std::FILE* file = std::fopen(name, "r"); + __gnu_cxx::stdio_sync_filebuf sbuf(file); + int c1 = sbuf.sbumpc(); + VERIFY( c1 != EOF ); + int c2 = sbuf.sungetc(); + VERIFY( c2 != EOF ); + int c3 = std::fgetc(file); + VERIFY( c3 == c1 ); + + std::fclose(file); +} + +// libstdc++/12048 +void test04() +{ + bool test = true; + const char* name = "cin_unget-1.txt"; + + std::FILE* file = std::fopen(name, "r"); + __gnu_cxx::stdio_sync_filebuf sbuf(file); + char buf[2]; + VERIFY( sbuf.sgetn(buf, 2) == 2 ); + int c2 = sbuf.sungetc(); + VERIFY( c2 != EOF ); + int c3 = sbuf.sbumpc(); + VERIFY( c3 == std::char_traits::to_int_type(buf[1]) ); + + std::fclose(file); +} + +// libstdc++/12048 +void test05() +{ + bool test = true; + const char* name = "cin_unget-1.txt"; + + std::FILE* file = std::fopen(name, "r"); + __gnu_cxx::stdio_sync_filebuf sbuf(file); + char buf[2]; + VERIFY( sbuf.sgetn(buf, 2) == 2 ); + int c2 = sbuf.sungetc(); + VERIFY( c2 != EOF ); + int c3 = std::fgetc(file); + VERIFY( c3 == std::char_traits::to_int_type(buf[1]) ); + + std::fclose(file); +} + int main () { test01(); + test02(); + test03(); + test04(); + test05(); + return 0; } diff --git a/libstdc++-v3/testsuite/ext/stdio_sync_filebuf_wchar_t.cc b/libstdc++-v3/testsuite/ext/stdio_sync_filebuf_wchar_t.cc index a8cde4abda1..25276a2d677 100644 --- a/libstdc++-v3/testsuite/ext/stdio_sync_filebuf_wchar_t.cc +++ b/libstdc++-v3/testsuite/ext/stdio_sync_filebuf_wchar_t.cc @@ -53,13 +53,89 @@ void test01() VERIFY( wsbuf.sgetn(buf, 5) == 5 ); VERIFY( !wmemcmp(buf, w_lit + 3, 5) ); VERIFY( getwc(fin) == w_lit[8] ); - VERIFY( wsbuf.sungetc() == WEOF ); fclose(fin); } +// libstdc++/12048 +void test02() +{ + bool test = true; + const char* name = "cin_unget-1.txt"; + + std::FILE* file = std::fopen(name, "r"); + __gnu_cxx::stdio_sync_filebuf sbuf(file); + std::wint_t c1 = sbuf.sbumpc(); + VERIFY( c1 != WEOF ); + std::wint_t c2 = sbuf.sungetc(); + VERIFY( c2 != WEOF ); + std::wint_t c3 = sbuf.sbumpc(); + VERIFY( c3 == c1 ); + + std::fclose(file); +} + +// libstdc++/12048 +void test03() +{ + bool test = true; + const char* name = "cin_unget-1.txt"; + + std::FILE* file = std::fopen(name, "r"); + __gnu_cxx::stdio_sync_filebuf sbuf(file); + std::wint_t c1 = sbuf.sbumpc(); + VERIFY( c1 != WEOF ); + std::wint_t c2 = sbuf.sungetc(); + VERIFY( c2 != WEOF ); + std::wint_t c3 = std::fgetwc(file); + VERIFY( c3 == c1 ); + + std::fclose(file); +} + +// libstdc++/12048 +void test04() +{ + bool test = true; + const char* name = "cin_unget-1.txt"; + + std::FILE* file = std::fopen(name, "r"); + __gnu_cxx::stdio_sync_filebuf sbuf(file); + wchar_t buf[2]; + VERIFY( sbuf.sgetn(buf, 2) == 2 ); + std::wint_t c2 = sbuf.sungetc(); + VERIFY( c2 != WEOF ); + std::wint_t c3 = sbuf.sbumpc(); + VERIFY( c3 == std::char_traits::to_int_type(buf[1]) ); + + std::fclose(file); +} + +// libstdc++/12048 +void test05() +{ + bool test = true; + const char* name = "cin_unget-1.txt"; + + std::FILE* file = std::fopen(name, "r"); + __gnu_cxx::stdio_sync_filebuf sbuf(file); + wchar_t buf[2]; + VERIFY( sbuf.sgetn(buf, 2) == 2 ); + std::wint_t c2 = sbuf.sungetc(); + VERIFY( c2 != WEOF ); + std::wint_t c3 = std::fgetwc(file); + VERIFY( c3 == std::char_traits::to_int_type(buf[1]) ); + + std::fclose(file); +} + int main () { test01(); + test02(); + test03(); + test04(); + test05(); + return 0; }