diff options
Diffstat (limited to 'libstdc++-v3/include/bits/fstream.tcc')
-rw-r--r-- | libstdc++-v3/include/bits/fstream.tcc | 325 |
1 files changed, 187 insertions, 138 deletions
diff --git a/libstdc++-v3/include/bits/fstream.tcc b/libstdc++-v3/include/bits/fstream.tcc index a93459a71f3..998e0c34429 100644 --- a/libstdc++-v3/include/bits/fstream.tcc +++ b/libstdc++-v3/include/bits/fstream.tcc @@ -44,15 +44,15 @@ namespace std basic_filebuf<_CharT, _Traits>:: _M_allocate_internal_buffer() { - if (!_M_buf_allocated && this->_M_buf_size) + // Allocate internal buffer only if one doesn't already exist + // (either allocated or provided by the user via setbuf). + if (!_M_buf_allocated && !this->_M_buf) { - // Allocate internal buffer. this->_M_buf = new char_type[this->_M_buf_size]; _M_buf_allocated = true; } } - // Both close and setbuf need to deallocate internal buffers, if it exists. template<typename _CharT, typename _Traits> void basic_filebuf<_CharT, _Traits>:: @@ -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,23 +130,11 @@ 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(...) - { - __testfail = true; - } + { __testfail = true; } // NB: Do this here so that re-opened filebufs will be cool... this->_M_mode = ios_base::openmode(0); @@ -152,6 +143,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 +151,6 @@ namespace std if (!__testfail) __ret = this; } - _M_last_overflowed = false; return __ret; } @@ -170,7 +161,6 @@ namespace std { streamsize __ret = -1; const bool __testin = this->_M_mode & ios_base::in; - if (__testin && this->is_open()) { // For a stateful encoding (-1) the pending sequence might be just @@ -179,8 +169,6 @@ namespace std if (__check_facet(_M_codecvt).encoding() >= 0) __ret += _M_file.showmanyc() / _M_codecvt->max_length(); } - - _M_last_overflowed = false; return __ret; } @@ -192,7 +180,6 @@ namespace std int_type __ret = traits_type::eof(); const bool __testin = this->_M_mode & ios_base::in; const bool __testout = this->_M_mode & ios_base::out; - if (__testin && !_M_writing) { // Check for pback madness, and if so swich back to the @@ -211,6 +198,7 @@ namespace std bool __got_eof = false; // Number of internal characters produced. streamsize __ilen = 0; + codecvt_base::result __r = codecvt_base::ok; if (__check_facet(_M_codecvt).always_noconv()) { __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()), @@ -221,8 +209,8 @@ namespace std else { // Worst-case number of external bytes. - // XXX Not done encoding() == -1. - const int __enc = _M_codecvt->encoding(); + // XXX Not done encoding() == -1. + const int __enc = _M_codecvt->encoding(); streamsize __blen; // Minimum buffer size. streamsize __rlen; // Number of chars to read. if (__enc > 0) @@ -252,6 +240,7 @@ namespace std _M_ext_next = _M_ext_buf; _M_ext_end = _M_ext_buf + __remainder; + _M_state_last = _M_state_cur; do { @@ -261,37 +250,43 @@ 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("basic_filebuf::underflow " + "codecvt::max_length() " + "is not valid"); + } streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen); if (__elen == 0) __got_eof = true; + else if (__elen == -1) + break; _M_ext_end += __elen; } - + char_type* __iend; - codecvt_base::result __r; __r = _M_codecvt->in(_M_state_cur, _M_ext_next, _M_ext_end, _M_ext_next, this->eback(), this->eback() + __buflen, __iend); - if (__r == codecvt_base::ok || __r == codecvt_base::partial) - __ilen = __iend - this->eback(); - else if (__r == codecvt_base::noconv) + if (__r == codecvt_base::noconv) { 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 - { - __ilen = 0; - break; - } + else + __ilen = __iend - this->eback(); + + // _M_codecvt->in may return error while __ilen > 0: this is + // ok, and actually occurs in case of mixed encodings (e.g., + // XML files). + if (__r == codecvt_base::error) + break; + __rlen = 1; } - while (!__got_eof && __ilen == 0); + while (__ilen == 0 && !__got_eof); } if (__ilen > 0) @@ -307,9 +302,19 @@ namespace std // intervening seek. _M_set_buffer(-1); _M_reading = false; + // However, reaching it while looping on partial means that + // the file has got an incomplete character. + if (__r == codecvt_base::partial) + __throw_ios_failure("basic_filebuf::underflow " + "incomplete character in file"); } + else if (__r == codecvt_base::error) + __throw_ios_failure("basic_filebuf::underflow " + "invalid byte sequence in file"); + else + __throw_ios_failure("basic_filebuf::underflow " + "error reading the file"); } - _M_last_overflowed = false; return __ret; } @@ -320,14 +325,12 @@ namespace std { int_type __ret = traits_type::eof(); const bool __testin = this->_M_mode & ios_base::in; - if (__testin && !_M_writing) { // Remember whether the pback buffer is active, otherwise below // we may try to store in it a second char (libstdc++/9761). const bool __testpb = this->_M_pback_init; const bool __testeof = traits_type::eq_int_type(__i, __ret); - int_type __tmp; if (this->eback() < this->gptr()) { @@ -364,7 +367,6 @@ namespace std __ret = __i; } } - _M_last_overflowed = false; return __ret; } @@ -376,7 +378,6 @@ namespace std int_type __ret = traits_type::eof(); const bool __testeof = traits_type::eq_int_type(__c, __ret); const bool __testout = this->_M_mode & ios_base::out; - if (__testout && !_M_reading) { if (this->pbase() < this->pptr()) @@ -389,7 +390,7 @@ namespace std } // Convert pending sequence to external representation, - // output. + // and output. if (_M_convert_to_external(this->pbase(), this->pptr() - this->pbase()) && (!__testeof || (__testeof && !_M_file.sync()))) @@ -423,7 +424,6 @@ namespace std } } } - _M_last_overflowed = true; return __ret; } @@ -435,7 +435,6 @@ namespace std // Sizes of external and pending output. streamsize __elen = 0; streamsize __plen = 0; - if (__check_facet(_M_codecvt).always_noconv()) { __elen += _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen); @@ -498,11 +497,10 @@ namespace std basic_filebuf<_CharT, _Traits>:: xsputn(const _CharT* __s, streamsize __n) { - streamsize __ret = 0; - // Optimization in the always_noconv() case, to be generalized in the // future: when __n is sufficiently large we write directly instead of // using the buffer. + streamsize __ret = 0; const bool __testout = this->_M_mode & ios_base::out; if (__testout && !_M_reading && __check_facet(_M_codecvt).always_noconv()) @@ -521,7 +519,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); @@ -536,8 +535,7 @@ namespace std __ret = __streambuf_type::xsputn(__s, __n); } else - __ret = __streambuf_type::xsputn(__s, __n); - + __ret = __streambuf_type::xsputn(__s, __n); return __ret; } @@ -546,30 +544,22 @@ namespace std basic_filebuf<_CharT, _Traits>:: setbuf(char_type* __s, streamsize __n) { - if (!this->is_open() && __s == 0 && __n == 0) - this->_M_buf_size = 1; - else if (__s && __n > 0) - { - // This is implementation-defined behavior, and assumes that - // an external char_type array of length __n exists and has - // been pre-allocated. If this is not the case, things will - // quickly blow up. When __n > 1, __n - 1 positions will be - // used for the get area, __n - 1 for the put area and 1 - // position to host the overflow char of a full put area. - // When __n == 1, 1 position will be used for the get area - // and 0 for the put area, as in the unbuffered case above. - - // Step 1: Destroy the current internal array. - _M_destroy_internal_buffer(); - - // Step 2: Use the external array. - this->_M_buf = __s; - this->_M_buf_size = __n; - _M_reading = false; - _M_writing = false; - _M_set_buffer(-1); - } - _M_last_overflowed = false; + if (!this->is_open()) + if (__s == 0 && __n == 0) + this->_M_buf_size = 1; + else if (__s && __n > 0) + { + // This is implementation-defined behavior, and assumes that + // an external char_type array of length __n exists and has + // been pre-allocated. If this is not the case, things will + // quickly blow up. When __n > 1, __n - 1 positions will be + // used for the get area, __n - 1 for the put area and 1 + // position to host the overflow char of a full put area. + // When __n == 1, 1 position will be used for the get area + // and 0 for the put area, as in the unbuffered case above. + this->_M_buf = __s; + this->_M_buf_size = __n; + } return this; } @@ -581,20 +571,25 @@ namespace std basic_filebuf<_CharT, _Traits>:: seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode) { - pos_type __ret = pos_type(off_type(-1)); - int __width = 0; if (_M_codecvt) __width = _M_codecvt->encoding(); if (__width < 0) __width = 0; - const bool __testfail = __off != 0 && __width <= 0; + pos_type __ret = pos_type(off_type(-1)); + 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,17 +598,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; } @@ -627,84 +625,135 @@ namespace std seekpos(pos_type __pos, ios_base::openmode) { pos_type __ret = pos_type(off_type(-1)); - if (this->is_open()) { // 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() { + // Part one: update the output sequence. + bool __testvalid = true; 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() + { + // 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. + int __ret = 0; + 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 basic_filebuf<_CharT, _Traits>:: imbue(const locale& __loc) { - if (this->_M_buf_locale != __loc) + bool __testfail = false; + if (this->is_open()) { - bool __testfail = false; - if (this->is_open()) - { - const bool __testbeg = - this->seekoff(0, ios_base::cur, this->_M_mode) == - pos_type(off_type(0)); - const bool __teststate = - __check_facet(_M_codecvt).encoding() == -1; - - __testfail = !__testbeg || __teststate; - } + const pos_type __ret = this->seekoff(0, ios_base::cur, + this->_M_mode); + const bool __teststate = __check_facet(_M_codecvt).encoding() == -1; + __testfail = __teststate && __ret != pos_type(off_type(0)); + } - if (!__testfail) - { - this->_M_buf_locale = __loc; - if (__builtin_expect(has_facet<__codecvt_type>(__loc), true)) - _M_codecvt = &use_facet<__codecvt_type>(__loc); - else - _M_codecvt = 0; - - // NB This may require the reconversion of previously - // converted chars. This in turn may cause the - // reconstruction of the original file. YIKES!! This - // implementation interprets this requirement as requiring - // the file position be at the beginning, and a stateless - // encoding, or that the filebuf be closed. Opinions may differ. - } + if (!__testfail) + { + if (__builtin_expect(has_facet<__codecvt_type>(__loc), true)) + _M_codecvt = &use_facet<__codecvt_type>(__loc); + else + _M_codecvt = 0; } - _M_last_overflowed = false; } // Inhibit implicit instantiations for required instantiations, |