diff options
author | Petur Runolfsson <peturr02@ru.is> | 2003-11-04 05:27:41 +0000 |
---|---|---|
committer | Benjamin Kosnik <bkoz@gcc.gnu.org> | 2003-11-04 05:27:41 +0000 |
commit | 5e93f39f64234c07447aca0d466c8ae989306669 (patch) | |
tree | dbeb51f2111e74f88fe23facb07d9567776a19a5 /libstdc++-v3/include/bits/fstream.tcc | |
parent | 99f8b2501d1ba3247656c37cd820222c366d6a31 (diff) | |
download | gcc-5e93f39f64234c07447aca0d466c8ae989306669.zip gcc-5e93f39f64234c07447aca0d466c8ae989306669.tar.gz gcc-5e93f39f64234c07447aca0d466c8ae989306669.tar.bz2 |
re PR libstdc++/12790 (basic_filebuf doesn't handle stateful encodings)
2003-11-03 Petur Runolfsson <peturr02@ru.is>
PR libstdc++/12790
* include/bits/fstream.tcc: Delete _M_last_overflowed.
(basic_filebuf::basic_filebuf): Initialize _M_state_last.
(basic_filebuf::open, basic_filebuf::close): Assign
_M_state_beg to _M_state_cur and _M_state_last.
(basic_filebuf::close): Call _M_terminate_output to handle
unshift and flushing.
(basic_filebuf::underflow): Assign _M_state_last, throw
exception instead of calling abort when codecvt::max_length()
is bad.
(basic_filebuf::seekoff): Use _M_state_last when calling
codecvt::length(), pass correct state to _M_seek.
(basic_filebuf::seekpos): Pass __pos.state() to _M_seek.
(basic_filebuf::_M_seek): Add __state_type parameter,
set _M_state_cur correctly, store the resulting state in
the return value and use _M_terminate_output to handle
flushing and unshift.
(basic_filebuf::_M_terminate_output): Flush contents of
output buffer, if any, then call codecvt::unshift as
needed and output the result.
(basic_filebuf::sync): Move here, don't modify _M_writing
or _M_reading.
* include/std/std_fstream.h
(basic_filebuf::_M_state_last): Declare it.
(basic_filebuf::_M_last_overflowed): Delete.
(basic_filebuf::_M_seek): Add __state_type parameter.
(basic_filebuf::sync): Declare only.
(basic_filebuf::_M_output_unshift): Delete.
(basic_filebuf::_M_terminate_output): Declare it.
* testsuite/testsuite_character.h:
Define character class and state class plus char_traits and
codecvt specializations for same for testing support for
stateful encodings.
* testsuite/27_io/basic_filebuf/close/12790-1.cc,
* testsuite/27_io/basic_filebuf/close/char/12790-1.cc,
* testsuite/27_io/basic_filebuf/close/char/12790-2.cc,
* testsuite/27_io/basic_filebuf/close/char/12790-3.cc,
* testsuite/27_io/basic_filebuf/close/char/12790-4.cc,
* testsuite/27_io/basic_filebuf/close/wchar_t/12790-1.cc,
* testsuite/27_io/basic_filebuf/close/wchar_t/12790-2.cc,
* testsuite/27_io/basic_filebuf/close/wchar_t/12790-3.cc,
* testsuite/27_io/basic_filebuf/close/wchar_t/12790-4.cc,
* testsuite/27_io/basic_filebuf/open/12790-1.cc,
* testsuite/27_io/basic_filebuf/seekoff/12790-1.cc,
* testsuite/27_io/basic_filebuf/seekoff/12790-2.cc,
* testsuite/27_io/basic_filebuf/seekoff/12790-3.cc,
* testsuite/27_io/basic_filebuf/seekoff/12790-4.cc,
* testsuite/27_io/basic_filebuf/seekoff/char/12790-1.cc,
* testsuite/27_io/basic_filebuf/seekoff/char/12790-2.cc,
* testsuite/27_io/basic_filebuf/seekoff/char/12790-3.cc,
* testsuite/27_io/basic_filebuf/seekoff/char/12790-4.cc,
* testsuite/27_io/basic_filebuf/seekoff/wchar_t/12790-1.cc,
* testsuite/27_io/basic_filebuf/seekoff/wchar_t/12790-2.cc,
* testsuite/27_io/basic_filebuf/seekoff/wchar_t/12790-3.cc,
* testsuite/27_io/basic_filebuf/seekoff/wchar_t/12790-4.cc,
* testsuite/27_io/basic_filebuf/seekoff/wchar_t/3.cc,
* testsuite/27_io/basic_filebuf/seekpos/12790-1.cc,
* testsuite/27_io/basic_filebuf/seekpos/12790-2.cc,
* testsuite/27_io/basic_filebuf/seekpos/12790-3.cc,
* testsuite/27_io/basic_filebuf/seekpos/char/12790-1.cc,
* testsuite/27_io/basic_filebuf/seekpos/char/12790-2.cc,
* testsuite/27_io/basic_filebuf/seekpos/char/12790-3.cc,
* testsuite/27_io/basic_filebuf/seekpos/char/12790-4.cc,
* testsuite/27_io/basic_filebuf/seekpos/wchar_t/1.cc,
* testsuite/27_io/basic_filebuf/seekpos/wchar_t/12790-1.cc,
* testsuite/27_io/basic_filebuf/seekpos/wchar_t/12790-2.cc,
* testsuite/27_io/basic_filebuf/seekpos/wchar_t/12790-3.cc,
* testsuite/27_io/basic_filebuf/seekpos/wchar_t/12790-4.cc,
* testsuite/27_io/basic_filebuf/sync/char/1.cc,
* testsuite/27_io/basic_filebuf/sync/wchar_t/1.cc:
New tests.
* testsuite/27_io/basic_filebuf/3.cc,
* testsuite/27_io/basic_filebuf/seekoff/10132-2.cc,
* testsuite/27_io/basic_filebuf/seekpos/10132-3.cc,
* testsuite/27_io/basic_fstream/3.cc,
* testsuite/27_io/basic_ifstream/3.cc,
* testsuite/27_io/basic_ofstream/3.cc:
Use streamoff as off_type and fpos<state_type> as pos_type.
* testsuite/27_io/basic_filebuf/seekpos/char/1-io.cc,
* testsuite/27_io/basic_filebuf/seekpos/char/1-out.cc:
Check that sync does *not* set _M_writing to false.
From-SVN: r73245
Diffstat (limited to 'libstdc++-v3/include/bits/fstream.tcc')
-rw-r--r-- | libstdc++-v3/include/bits/fstream.tcc | 179 |
1 files changed, 127 insertions, 52 deletions
diff --git a/libstdc++-v3/include/bits/fstream.tcc b/libstdc++-v3/include/bits/fstream.tcc index 29fe0e8..5649741 100644 --- a/libstdc++-v3/include/bits/fstream.tcc +++ b/libstdc++-v3/include/bits/fstream.tcc @@ -74,12 +74,12 @@ namespace std template<typename _CharT, typename _Traits> basic_filebuf<_CharT, _Traits>:: basic_filebuf() : __streambuf_type(), _M_file(&_M_lock), - _M_mode(ios_base::openmode(0)), _M_state_cur(__state_type()), - _M_state_beg(__state_type()), _M_buf(NULL), _M_buf_size(BUFSIZ), + _M_mode(ios_base::openmode(0)), _M_state_beg(), _M_state_cur(), + _M_state_last(), _M_buf(NULL), _M_buf_size(BUFSIZ), _M_buf_allocated(false), _M_reading(false), _M_writing(false), - _M_last_overflowed(false), _M_pback_cur_save(0), _M_pback_end_save(0), - _M_pback_init(false), _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), - _M_ext_next(0), _M_ext_end(0) + _M_pback_cur_save(0), _M_pback_end_save(0), _M_pback_init(false), + _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), _M_ext_next(0), + _M_ext_end(0) { if (has_facet<__codecvt_type>(this->_M_buf_locale)) _M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale); @@ -104,9 +104,12 @@ namespace std _M_writing = false; _M_set_buffer(-1); + // Reset to initial state. + _M_state_last = _M_state_cur = _M_state_beg; + // 27.8.1.3,4 if ((__mode & ios_base::ate) - && this->seekoff(0, ios_base::end, __mode) + && this->seekoff(0, ios_base::end, __mode) == pos_type(off_type(-1))) this->close(); else @@ -127,18 +130,8 @@ namespace std bool __testfail = false; try { - if (this->pbase() < this->pptr() - && traits_type::eq_int_type(this->overflow(), - traits_type::eof())) + if (!_M_terminate_output()) __testfail = true; -#if 0 - // XXX not done - if (_M_last_overflowed) - { - _M_output_unshift(); - this->overflow(); - } -#endif } catch(...) { @@ -152,6 +145,7 @@ namespace std _M_reading = false; _M_writing = false; _M_set_buffer(-1); + _M_state_last = _M_state_cur = _M_state_beg; if (!_M_file.close()) __testfail = true; @@ -159,7 +153,6 @@ namespace std if (!__testfail) __ret = this; } - _M_last_overflowed = false; return __ret; } @@ -180,7 +173,6 @@ namespace std __ret += _M_file.showmanyc() / _M_codecvt->max_length(); } - _M_last_overflowed = false; return __ret; } @@ -252,6 +244,7 @@ namespace std _M_ext_next = _M_ext_buf; _M_ext_end = _M_ext_buf + __remainder; + _M_state_last = _M_state_cur; do { @@ -261,7 +254,10 @@ namespace std // This may fail if the return value of // codecvt::max_length() is bogus. if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size) - std::abort(); + { + __throw_ios_failure("codecvt::max_length() " + "is not valid"); + } streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen); if (__elen == 0) __got_eof = true; @@ -280,8 +276,7 @@ namespace std size_t __avail = _M_ext_end - _M_ext_buf; __ilen = std::min(__avail, __buflen); traits_type::copy(this->eback(), - reinterpret_cast<char_type*>(_M_ext_buf), - __ilen); + reinterpret_cast<char_type*>(_M_ext_buf), __ilen); _M_ext_next = _M_ext_buf + __ilen; } else @@ -309,7 +304,6 @@ namespace std _M_reading = false; } } - _M_last_overflowed = false; return __ret; } @@ -364,7 +358,6 @@ namespace std __ret = __i; } } - _M_last_overflowed = false; return __ret; } @@ -423,7 +416,6 @@ namespace std } } } - _M_last_overflowed = true; return __ret; } @@ -521,7 +513,8 @@ namespace std const streamsize __buffill = this->pptr() - this->pbase(); const char* __buf = reinterpret_cast<const char*>(this->pbase()); __ret = _M_file.xsputn_2(__buf, __buffill, - reinterpret_cast<const char*>(__s), __n); + reinterpret_cast<const char*>(__s), + __n); if (__ret == __buffill + __n) { _M_set_buffer(0); @@ -569,7 +562,6 @@ namespace std _M_writing = false; _M_set_buffer(-1); } - _M_last_overflowed = false; return this; } @@ -589,12 +581,18 @@ namespace std if (__width < 0) __width = 0; - const bool __testfail = __off != 0 && __width <= 0; + const bool __testfail = __off != 0 && __width <= 0; if (this->is_open() && !__testfail) { // Ditch any pback buffers to avoid confusion. _M_destroy_pback(); + // Correct state at destination. Note that this is the correct + // state for the current position during output, because + // codecvt::unshift() returns the state to the initial state. + // This is also the correct state at the end of the file because + // an unshift sequence should have been written at the end. + __state_type __state = _M_state_beg; off_type __computed_off = __off * __width; if (_M_reading && __way == ios_base::cur) { @@ -603,16 +601,20 @@ namespace std else { // Calculate offset from _M_ext_buf that corresponds - // to gptr(). + // to gptr(). Note: uses _M_state_last, which + // corresponds to eback(). const int __gptr_off = - _M_codecvt->length(_M_state_cur, _M_ext_buf, _M_ext_next, + _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next, this->gptr() - this->eback()); __computed_off += _M_ext_buf + __gptr_off - _M_ext_end; + + // _M_state_last is modified by codecvt::length() so + // it now corresponds to gptr(). + __state = _M_state_last; } } - __ret = _M_seek(__computed_off, __way); + __ret = _M_seek(__computed_off, __way, __state); } - _M_last_overflowed = false; return __ret; } @@ -632,41 +634,115 @@ namespace std // Ditch any pback buffers to avoid confusion. _M_destroy_pback(); - __ret = _M_seek(off_type(__pos), ios_base::beg); + __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state()); } - _M_last_overflowed = false; return __ret; } template<typename _CharT, typename _Traits> typename basic_filebuf<_CharT, _Traits>::pos_type basic_filebuf<_CharT, _Traits>:: - _M_seek(off_type __off, ios_base::seekdir __way) + _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state) + { + pos_type __ret = pos_type(off_type(-1)); + if (_M_terminate_output()) + { + // Returns pos_type(off_type(-1)) in case of failure. + __ret = pos_type(_M_file.seekoff(__off, __way)); + + _M_reading = false; + _M_writing = false; + _M_ext_next = _M_ext_end = _M_ext_buf; + _M_set_buffer(-1); + _M_state_cur = __state; + __ret.state(_M_state_cur); + } + return __ret; + } + + template<typename _CharT, typename _Traits> + bool + basic_filebuf<_CharT, _Traits>:: + _M_terminate_output() { + bool __testvalid = true; + + // Part one: update the output sequence. if (this->pbase() < this->pptr()) { - // Part one: update the output sequence. - this->sync(); + const int_type __tmp = this->overflow(); + if (traits_type::eq_int_type(__tmp, traits_type::eof())) + __testvalid = false; + } - // Part two: output unshift sequence. - _M_output_unshift(); + // Part two: output unshift sequence. + if (_M_writing && !__check_facet(_M_codecvt).always_noconv() + && __testvalid) + { + // Note: this value is arbitrary, since there is no way to + // get the length of the unshift sequence from codecvt, + // without calling unshift. + const size_t __blen = 128; + + char __buf[__blen]; + codecvt_base::result __r; + streamsize __ilen = 0; + + do + { + char* __next; + __r = _M_codecvt->unshift(_M_state_cur, __buf, + __buf + __blen, __next); + if (__r == codecvt_base::error) + __testvalid = false; + else if (__r == codecvt_base::ok || + __r == codecvt_base::partial) + { + __ilen = __next - __buf; + + if (__ilen > 0) + { + const streamsize __elen = _M_file.xsputn(__buf, __ilen); + if (__elen != __ilen) + __testvalid = false; + } + } + } + while (__r == codecvt_base::partial && __ilen > 0 && __testvalid); + + if (__testvalid) + { + // This second call to overflow() is required by the standard, + // but it's not clear why it's needed, since the output buffer + // should be empty by this point (it should have been emptied + // in the first call to overflow()). + const int_type __tmp = this->overflow(); + if (traits_type::eq_int_type(__tmp, traits_type::eof())) + __testvalid = false; + } } - - // Returns pos_type(off_type(-1)) in case of failure. - pos_type __ret (_M_file.seekoff(__off, __way)); - - _M_reading = false; - _M_writing = false; - _M_ext_next = _M_ext_end = _M_ext_buf; - _M_set_buffer(-1); - return __ret; + return __testvalid; } template<typename _CharT, typename _Traits> - void + int basic_filebuf<_CharT, _Traits>:: - _M_output_unshift() - { } + sync() + { + int __ret = 0; + + // Make sure that the internal buffer resyncs its idea of + // the file position with the external file. + // NB: _M_file.sync() will be called within. + if (this->pbase() < this->pptr()) + { + const int_type __tmp = this->overflow(); + if (traits_type::eq_int_type(__tmp, traits_type::eof())) + __ret = -1; + } + + return __ret; + } template<typename _CharT, typename _Traits> void @@ -703,7 +779,6 @@ namespace std // encoding, or that the filebuf be closed. Opinions may differ. } } - _M_last_overflowed = false; } // Inhibit implicit instantiations for required instantiations, |