|
- // File based streams -*- C++ -*-
-
- // Copyright (C) 1997-2020 Free Software Foundation, Inc.
- //
- // This file is part of the GNU ISO C++ Library. This library is free
- // software; you can redistribute it and/or modify it under the
- // terms of the GNU General Public License as published by the
- // Free Software Foundation; either version 3, or (at your option)
- // any later version.
-
- // This library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
-
- // Under Section 7 of GPL version 3, you are granted additional
- // permissions described in the GCC Runtime Library Exception, version
- // 3.1, as published by the Free Software Foundation.
-
- // You should have received a copy of the GNU General Public License and
- // a copy of the GCC Runtime Library Exception along with this program;
- // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
- // <http://www.gnu.org/licenses/>.
-
- /** @file bits/fstream.tcc
- * This is an internal header file, included by other library headers.
- * Do not attempt to use it directly. @headername{fstream}
- */
-
- //
- // ISO C++ 14882: 27.8 File-based streams
- //
-
- #ifndef _FSTREAM_TCC
- #define _FSTREAM_TCC 1
-
- #pragma GCC system_header
-
- #include <bits/cxxabi_forced.h>
- #include <bits/move.h> // for swap
- #include <cerrno>
-
- namespace std _GLIBCXX_VISIBILITY(default)
- {
- _GLIBCXX_BEGIN_NAMESPACE_VERSION
-
- template<typename _CharT, typename _Traits>
- void
- basic_filebuf<_CharT, _Traits>::
- _M_allocate_internal_buffer()
- {
- // Allocate internal buffer only if one doesn't already exist
- // (either allocated or provided by the user via setbuf).
- if (!_M_buf_allocated && !_M_buf)
- {
- _M_buf = new char_type[_M_buf_size];
- _M_buf_allocated = true;
- }
- }
-
- template<typename _CharT, typename _Traits>
- void
- basic_filebuf<_CharT, _Traits>::
- _M_destroy_internal_buffer() throw()
- {
- if (_M_buf_allocated)
- {
- delete [] _M_buf;
- _M_buf = 0;
- _M_buf_allocated = false;
- }
- delete [] _M_ext_buf;
- _M_ext_buf = 0;
- _M_ext_buf_size = 0;
- _M_ext_next = 0;
- _M_ext_end = 0;
- }
-
- template<typename _CharT, typename _Traits>
- basic_filebuf<_CharT, _Traits>::
- basic_filebuf() : __streambuf_type(), _M_lock(), _M_file(&_M_lock),
- _M_mode(ios_base::openmode(0)), _M_state_beg(), _M_state_cur(),
- _M_state_last(), _M_buf(0), _M_buf_size(BUFSIZ),
- _M_buf_allocated(false), _M_reading(false), _M_writing(false), _M_pback(),
- _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);
- }
-
- #if __cplusplus >= 201103L
- template<typename _CharT, typename _Traits>
- basic_filebuf<_CharT, _Traits>::
- basic_filebuf(basic_filebuf&& __rhs)
- : __streambuf_type(__rhs),
- _M_lock(), _M_file(std::move(__rhs._M_file), &_M_lock),
- _M_mode(std::__exchange(__rhs._M_mode, ios_base::openmode(0))),
- _M_state_beg(std::move(__rhs._M_state_beg)),
- _M_state_cur(std::move(__rhs._M_state_cur)),
- _M_state_last(std::move(__rhs._M_state_last)),
- _M_buf(std::__exchange(__rhs._M_buf, nullptr)),
- _M_buf_size(std::__exchange(__rhs._M_buf_size, 1)),
- _M_buf_allocated(std::__exchange(__rhs._M_buf_allocated, false)),
- _M_reading(std::__exchange(__rhs._M_reading, false)),
- _M_writing(std::__exchange(__rhs._M_writing, false)),
- _M_pback(__rhs._M_pback),
- _M_pback_cur_save(std::__exchange(__rhs._M_pback_cur_save, nullptr)),
- _M_pback_end_save(std::__exchange(__rhs._M_pback_end_save, nullptr)),
- _M_pback_init(std::__exchange(__rhs._M_pback_init, false)),
- _M_codecvt(__rhs._M_codecvt),
- _M_ext_buf(std::__exchange(__rhs._M_ext_buf, nullptr)),
- _M_ext_buf_size(std::__exchange(__rhs._M_ext_buf_size, 0)),
- _M_ext_next(std::__exchange(__rhs._M_ext_next, nullptr)),
- _M_ext_end(std::__exchange(__rhs._M_ext_end, nullptr))
- {
- __rhs._M_set_buffer(-1);
- __rhs._M_state_last = __rhs._M_state_cur = __rhs._M_state_beg;
- }
-
- template<typename _CharT, typename _Traits>
- basic_filebuf<_CharT, _Traits>&
- basic_filebuf<_CharT, _Traits>::
- operator=(basic_filebuf&& __rhs)
- {
- this->close();
- __streambuf_type::operator=(__rhs);
- _M_file.swap(__rhs._M_file);
- _M_mode = std::__exchange(__rhs._M_mode, ios_base::openmode(0));
- _M_state_beg = std::move(__rhs._M_state_beg);
- _M_state_cur = std::move(__rhs._M_state_cur);
- _M_state_last = std::move(__rhs._M_state_last);
- _M_buf = std::__exchange(__rhs._M_buf, nullptr);
- _M_buf_size = std::__exchange(__rhs._M_buf_size, 1);
- _M_buf_allocated = std::__exchange(__rhs._M_buf_allocated, false);
- _M_ext_buf = std::__exchange(__rhs._M_ext_buf, nullptr);
- _M_ext_buf_size = std::__exchange(__rhs._M_ext_buf_size, 0);
- _M_ext_next = std::__exchange(__rhs._M_ext_next, nullptr);
- _M_ext_end = std::__exchange(__rhs._M_ext_end, nullptr);
- _M_reading = std::__exchange(__rhs._M_reading, false);
- _M_writing = std::__exchange(__rhs._M_writing, false);
- _M_pback_cur_save = std::__exchange(__rhs._M_pback_cur_save, nullptr);
- _M_pback_end_save = std::__exchange(__rhs._M_pback_end_save, nullptr);
- _M_pback_init = std::__exchange(__rhs._M_pback_init, false);
- __rhs._M_set_buffer(-1);
- __rhs._M_state_last = __rhs._M_state_cur = __rhs._M_state_beg;
- return *this;
- }
-
- template<typename _CharT, typename _Traits>
- void
- basic_filebuf<_CharT, _Traits>::
- swap(basic_filebuf& __rhs)
- {
- __streambuf_type::swap(__rhs);
- _M_file.swap(__rhs._M_file);
- std::swap(_M_mode, __rhs._M_mode);
- std::swap(_M_state_beg, __rhs._M_state_beg);
- std::swap(_M_state_cur, __rhs._M_state_cur);
- std::swap(_M_state_last, __rhs._M_state_last);
- std::swap(_M_buf, __rhs._M_buf);
- std::swap(_M_buf_size, __rhs._M_buf_size);
- std::swap(_M_buf_allocated, __rhs._M_buf_allocated);
- std::swap(_M_ext_buf, __rhs._M_ext_buf);
- std::swap(_M_ext_buf_size, __rhs._M_ext_buf_size);
- std::swap(_M_ext_next, __rhs._M_ext_next);
- std::swap(_M_ext_end, __rhs._M_ext_end);
- std::swap(_M_reading, __rhs._M_reading);
- std::swap(_M_writing, __rhs._M_writing);
- std::swap(_M_pback_cur_save, __rhs._M_pback_cur_save);
- std::swap(_M_pback_end_save, __rhs._M_pback_end_save);
- std::swap(_M_pback_init, __rhs._M_pback_init);
- }
- #endif
-
- template<typename _CharT, typename _Traits>
- typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
- basic_filebuf<_CharT, _Traits>::
- open(const char* __s, ios_base::openmode __mode)
- {
- __filebuf_type *__ret = 0;
- if (!this->is_open())
- {
- _M_file.open(__s, __mode);
- if (this->is_open())
- {
- _M_allocate_internal_buffer();
- _M_mode = __mode;
-
- // Setup initial buffer to 'uncommitted' mode.
- _M_reading = false;
- _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)
- == pos_type(off_type(-1)))
- this->close();
- else
- __ret = this;
- }
- }
- return __ret;
- }
-
- #if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
- template<typename _CharT, typename _Traits>
- basic_filebuf<_CharT, _Traits>*
- basic_filebuf<_CharT, _Traits>::
- open(const wchar_t* __s, ios_base::openmode __mode)
- {
- __filebuf_type *__ret = 0;
- if (!this->is_open())
- {
- _M_file.open(__s, __mode);
- if (this->is_open())
- {
- _M_allocate_internal_buffer();
- _M_mode = __mode;
-
- // Setup initial buffer to 'uncommitted' mode.
- _M_reading = false;
- _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)
- == pos_type(off_type(-1)))
- this->close();
- else
- __ret = this;
- }
- }
- return __ret;
- }
- #endif // HAVE__WFOPEN && USE_WCHAR_T
-
- template<typename _CharT, typename _Traits>
- typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
- basic_filebuf<_CharT, _Traits>::
- close()
- {
- if (!this->is_open())
- return 0;
-
- bool __testfail = false;
- {
- // NB: Do this here so that re-opened filebufs will be cool...
- struct __close_sentry
- {
- basic_filebuf *__fb;
- __close_sentry (basic_filebuf *__fbi): __fb(__fbi) { }
- ~__close_sentry ()
- {
- __fb->_M_mode = ios_base::openmode(0);
- __fb->_M_pback_init = false;
- __fb->_M_destroy_internal_buffer();
- __fb->_M_reading = false;
- __fb->_M_writing = false;
- __fb->_M_set_buffer(-1);
- __fb->_M_state_last = __fb->_M_state_cur = __fb->_M_state_beg;
- }
- } __cs (this);
-
- __try
- {
- if (!_M_terminate_output())
- __testfail = true;
- }
- __catch(...)
- {
- _M_file.close();
- __throw_exception_again;
- }
- }
-
- if (!_M_file.close())
- __testfail = true;
-
- if (__testfail)
- return 0;
- else
- return this;
- }
-
- template<typename _CharT, typename _Traits>
- streamsize
- basic_filebuf<_CharT, _Traits>::
- showmanyc()
- {
- streamsize __ret = -1;
- const bool __testin = _M_mode & ios_base::in;
- if (__testin && this->is_open())
- {
- // For a stateful encoding (-1) the pending sequence might be just
- // shift and unshift prefixes with no actual character.
- __ret = this->egptr() - this->gptr();
-
- #if _GLIBCXX_HAVE_DOS_BASED_FILESYSTEM
- // About this workaround, see libstdc++/20806.
- const bool __testbinary = _M_mode & ios_base::binary;
- if (__check_facet(_M_codecvt).encoding() >= 0
- && __testbinary)
- #else
- if (__check_facet(_M_codecvt).encoding() >= 0)
- #endif
- __ret += _M_file.showmanyc() / _M_codecvt->max_length();
- }
- return __ret;
- }
-
- template<typename _CharT, typename _Traits>
- typename basic_filebuf<_CharT, _Traits>::int_type
- basic_filebuf<_CharT, _Traits>::
- underflow()
- {
- int_type __ret = traits_type::eof();
- const bool __testin = _M_mode & ios_base::in;
- if (__testin)
- {
- if (_M_writing)
- {
- if (overflow() == traits_type::eof())
- return __ret;
- _M_set_buffer(-1);
- _M_writing = false;
- }
- // Check for pback madness, and if so switch back to the
- // normal buffers and jet outta here before expensive
- // fileops happen...
- _M_destroy_pback();
-
- if (this->gptr() < this->egptr())
- return traits_type::to_int_type(*this->gptr());
-
- // Get and convert input sequence.
- const size_t __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
-
- // Will be set to true if ::read() returns 0 indicating EOF.
- 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()),
- __buflen);
- if (__ilen == 0)
- __got_eof = true;
- }
- else
- {
- // Worst-case number of external bytes.
- // 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)
- __blen = __rlen = __buflen * __enc;
- else
- {
- __blen = __buflen + _M_codecvt->max_length() - 1;
- __rlen = __buflen;
- }
- const streamsize __remainder = _M_ext_end - _M_ext_next;
- __rlen = __rlen > __remainder ? __rlen - __remainder : 0;
-
- // An imbue in 'read' mode implies first converting the external
- // chars already present.
- if (_M_reading && this->egptr() == this->eback() && __remainder)
- __rlen = 0;
-
- // Allocate buffer if necessary and move unconverted
- // bytes to front.
- if (_M_ext_buf_size < __blen)
- {
- char* __buf = new char[__blen];
- if (__remainder)
- __builtin_memcpy(__buf, _M_ext_next, __remainder);
-
- delete [] _M_ext_buf;
- _M_ext_buf = __buf;
- _M_ext_buf_size = __blen;
- }
- else if (__remainder)
- __builtin_memmove(_M_ext_buf, _M_ext_next, __remainder);
-
- _M_ext_next = _M_ext_buf;
- _M_ext_end = _M_ext_buf + __remainder;
- _M_state_last = _M_state_cur;
-
- do
- {
- if (__rlen > 0)
- {
- // Sanity check!
- // 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)
- {
- __throw_ios_failure(__N("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 = this->eback();
- if (_M_ext_next < _M_ext_end)
- __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::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);
- _M_ext_next = _M_ext_buf + __ilen;
- }
- 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 (__ilen == 0 && !__got_eof);
- }
-
- if (__ilen > 0)
- {
- _M_set_buffer(__ilen);
- _M_reading = true;
- __ret = traits_type::to_int_type(*this->gptr());
- }
- else if (__got_eof)
- {
- // If the actual end of file is reached, set 'uncommitted'
- // mode, thus allowing an immediate write without an
- // 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(__N("basic_filebuf::underflow "
- "incomplete character in file"));
- }
- else if (__r == codecvt_base::error)
- __throw_ios_failure(__N("basic_filebuf::underflow "
- "invalid byte sequence in file"));
- else
- __throw_ios_failure(__N("basic_filebuf::underflow "
- "error reading the file"), errno);
- }
- return __ret;
- }
-
- template<typename _CharT, typename _Traits>
- typename basic_filebuf<_CharT, _Traits>::int_type
- basic_filebuf<_CharT, _Traits>::
- pbackfail(int_type __i)
- {
- int_type __ret = traits_type::eof();
- const bool __testin = _M_mode & ios_base::in;
- if (__testin)
- {
- if (_M_writing)
- {
- if (overflow() == traits_type::eof())
- return __ret;
- _M_set_buffer(-1);
- _M_writing = false;
- }
- // Remember whether the pback buffer is active, otherwise below
- // we may try to store in it a second char (libstdc++/9761).
- const bool __testpb = _M_pback_init;
- const bool __testeof = traits_type::eq_int_type(__i, __ret);
- int_type __tmp;
- if (this->eback() < this->gptr())
- {
- this->gbump(-1);
- __tmp = traits_type::to_int_type(*this->gptr());
- }
- else if (this->seekoff(-1, ios_base::cur) != pos_type(off_type(-1)))
- {
- __tmp = this->underflow();
- if (traits_type::eq_int_type(__tmp, __ret))
- return __ret;
- }
- else
- {
- // At the beginning of the buffer, need to make a
- // putback position available. But the seek may fail
- // (f.i., at the beginning of a file, see
- // libstdc++/9439) and in that case we return
- // traits_type::eof().
- return __ret;
- }
-
- // Try to put back __i into input sequence in one of three ways.
- // Order these tests done in is unspecified by the standard.
- if (!__testeof && traits_type::eq_int_type(__i, __tmp))
- __ret = __i;
- else if (__testeof)
- __ret = traits_type::not_eof(__i);
- else if (!__testpb)
- {
- _M_create_pback();
- _M_reading = true;
- *this->gptr() = traits_type::to_char_type(__i);
- __ret = __i;
- }
- }
- return __ret;
- }
-
- template<typename _CharT, typename _Traits>
- typename basic_filebuf<_CharT, _Traits>::int_type
- basic_filebuf<_CharT, _Traits>::
- overflow(int_type __c)
- {
- int_type __ret = traits_type::eof();
- const bool __testeof = traits_type::eq_int_type(__c, __ret);
- const bool __testout = (_M_mode & ios_base::out
- || _M_mode & ios_base::app);
- if (__testout)
- {
- if (_M_reading)
- {
- _M_destroy_pback();
- const int __gptr_off = _M_get_ext_pos(_M_state_last);
- if (_M_seek(__gptr_off, ios_base::cur, _M_state_last)
- == pos_type(off_type(-1)))
- return __ret;
- }
- if (this->pbase() < this->pptr())
- {
- // If appropriate, append the overflow char.
- if (!__testeof)
- {
- *this->pptr() = traits_type::to_char_type(__c);
- this->pbump(1);
- }
-
- // Convert pending sequence to external representation,
- // and output.
- if (_M_convert_to_external(this->pbase(),
- this->pptr() - this->pbase()))
- {
- _M_set_buffer(0);
- __ret = traits_type::not_eof(__c);
- }
- }
- else if (_M_buf_size > 1)
- {
- // Overflow in 'uncommitted' mode: set _M_writing, set
- // the buffer to the initial 'write' mode, and put __c
- // into the buffer.
- _M_set_buffer(0);
- _M_writing = true;
- if (!__testeof)
- {
- *this->pptr() = traits_type::to_char_type(__c);
- this->pbump(1);
- }
- __ret = traits_type::not_eof(__c);
- }
- else
- {
- // Unbuffered.
- char_type __conv = traits_type::to_char_type(__c);
- if (__testeof || _M_convert_to_external(&__conv, 1))
- {
- _M_writing = true;
- __ret = traits_type::not_eof(__c);
- }
- }
- }
- return __ret;
- }
-
- template<typename _CharT, typename _Traits>
- bool
- basic_filebuf<_CharT, _Traits>::
- _M_convert_to_external(_CharT* __ibuf, streamsize __ilen)
- {
- // Sizes of external and pending output.
- streamsize __elen;
- streamsize __plen;
- if (__check_facet(_M_codecvt).always_noconv())
- {
- __elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
- __plen = __ilen;
- }
- else
- {
- // Worst-case number of external bytes needed.
- // XXX Not done encoding() == -1.
- streamsize __blen = __ilen * _M_codecvt->max_length();
- char* __buf = static_cast<char*>(__builtin_alloca(__blen));
-
- char* __bend;
- const char_type* __iend;
- codecvt_base::result __r;
- __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen,
- __iend, __buf, __buf + __blen, __bend);
-
- if (__r == codecvt_base::ok || __r == codecvt_base::partial)
- __blen = __bend - __buf;
- else if (__r == codecvt_base::noconv)
- {
- // Same as the always_noconv case above.
- __buf = reinterpret_cast<char*>(__ibuf);
- __blen = __ilen;
- }
- else
- __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "
- "conversion error"));
-
- __elen = _M_file.xsputn(__buf, __blen);
- __plen = __blen;
-
- // Try once more for partial conversions.
- if (__r == codecvt_base::partial && __elen == __plen)
- {
- const char_type* __iresume = __iend;
- streamsize __rlen = this->pptr() - __iend;
- __r = _M_codecvt->out(_M_state_cur, __iresume,
- __iresume + __rlen, __iend, __buf,
- __buf + __blen, __bend);
- if (__r != codecvt_base::error)
- {
- __rlen = __bend - __buf;
- __elen = _M_file.xsputn(__buf, __rlen);
- __plen = __rlen;
- }
- else
- __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "
- "conversion error"));
- }
- }
- return __elen == __plen;
- }
-
- template<typename _CharT, typename _Traits>
- streamsize
- basic_filebuf<_CharT, _Traits>::
- xsgetn(_CharT* __s, streamsize __n)
- {
- // Clear out pback buffer before going on to the real deal...
- streamsize __ret = 0;
- if (_M_pback_init)
- {
- if (__n > 0 && this->gptr() == this->eback())
- {
- *__s++ = *this->gptr(); // emulate non-underflowing sbumpc
- this->gbump(1);
- __ret = 1;
- --__n;
- }
- _M_destroy_pback();
- }
- else if (_M_writing)
- {
- if (overflow() == traits_type::eof())
- return __ret;
- _M_set_buffer(-1);
- _M_writing = false;
- }
-
- // Optimization in the always_noconv() case, to be generalized in the
- // future: when __n > __buflen we read directly instead of using the
- // buffer repeatedly.
- const bool __testin = _M_mode & ios_base::in;
- const streamsize __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
-
- if (__n > __buflen && __check_facet(_M_codecvt).always_noconv()
- && __testin)
- {
- // First, copy the chars already present in the buffer.
- const streamsize __avail = this->egptr() - this->gptr();
- if (__avail != 0)
- {
- traits_type::copy(__s, this->gptr(), __avail);
- __s += __avail;
- this->setg(this->eback(), this->gptr() + __avail, this->egptr());
- __ret += __avail;
- __n -= __avail;
- }
-
- // Need to loop in case of short reads (relatively common
- // with pipes).
- streamsize __len;
- for (;;)
- {
- __len = _M_file.xsgetn(reinterpret_cast<char*>(__s), __n);
- if (__len == -1)
- __throw_ios_failure(__N("basic_filebuf::xsgetn "
- "error reading the file"), errno);
- if (__len == 0)
- break;
-
- __n -= __len;
- __ret += __len;
- if (__n == 0)
- break;
-
- __s += __len;
- }
-
- if (__n == 0)
- {
- // Set _M_reading. Buffer is already in initial 'read' mode.
- _M_reading = true;
- }
- else if (__len == 0)
- {
- // If end of file is reached, set 'uncommitted'
- // mode, thus allowing an immediate write without
- // an intervening seek.
- _M_set_buffer(-1);
- _M_reading = false;
- }
- }
- else
- __ret += __streambuf_type::xsgetn(__s, __n);
-
- return __ret;
- }
-
- template<typename _CharT, typename _Traits>
- streamsize
- 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.
- const bool __testout = (_M_mode & ios_base::out
- || _M_mode & ios_base::app);
- if (__check_facet(_M_codecvt).always_noconv()
- && __testout && !_M_reading)
- {
- // Measurement would reveal the best choice.
- const streamsize __chunk = 1ul << 10;
- streamsize __bufavail = this->epptr() - this->pptr();
-
- // Don't mistake 'uncommitted' mode buffered with unbuffered.
- if (!_M_writing && _M_buf_size > 1)
- __bufavail = _M_buf_size - 1;
-
- const streamsize __limit = std::min(__chunk, __bufavail);
- if (__n >= __limit)
- {
- 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);
- if (__ret == __buffill + __n)
- {
- _M_set_buffer(0);
- _M_writing = true;
- }
- if (__ret > __buffill)
- __ret -= __buffill;
- else
- __ret = 0;
- }
- else
- __ret = __streambuf_type::xsputn(__s, __n);
- }
- else
- __ret = __streambuf_type::xsputn(__s, __n);
- return __ret;
- }
-
- template<typename _CharT, typename _Traits>
- typename basic_filebuf<_CharT, _Traits>::__streambuf_type*
- basic_filebuf<_CharT, _Traits>::
- setbuf(char_type* __s, streamsize __n)
- {
- if (!this->is_open())
- {
- if (__s == 0 && __n == 0)
- _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.
- _M_buf = __s;
- _M_buf_size = __n;
- }
- }
- return this;
- }
-
-
- // According to 27.8.1.4 p11 - 13, seekoff should ignore the last
- // argument (of type openmode).
- template<typename _CharT, typename _Traits>
- typename basic_filebuf<_CharT, _Traits>::pos_type
- basic_filebuf<_CharT, _Traits>::
- seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode)
- {
- int __width = 0;
- if (_M_codecvt)
- __width = _M_codecvt->encoding();
- if (__width < 0)
- __width = 0;
-
- pos_type __ret = pos_type(off_type(-1));
- const bool __testfail = __off != 0 && __width <= 0;
- if (this->is_open() && !__testfail)
- {
- // tellg and tellp queries do not affect any state, unless
- // ! always_noconv and the put sequence is not empty.
- // In that case, determining the position requires converting the
- // put sequence. That doesn't use ext_buf, so requires a flush.
- bool __no_movement = __way == ios_base::cur && __off == 0
- && (!_M_writing || _M_codecvt->always_noconv());
-
- // Ditch any pback buffers to avoid confusion.
- if (!__no_movement)
- _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)
- {
- __state = _M_state_last;
- __computed_off += _M_get_ext_pos(__state);
- }
- if (!__no_movement)
- __ret = _M_seek(__computed_off, __way, __state);
- else
- {
- if (_M_writing)
- __computed_off = this->pptr() - this->pbase();
-
- off_type __file_off = _M_file.seekoff(0, ios_base::cur);
- if (__file_off != off_type(-1))
- {
- __ret = __file_off + __computed_off;
- __ret.state(__state);
- }
- }
- }
- return __ret;
- }
-
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 171. Strange seekpos() semantics due to joint position
- // According to the resolution of DR 171, seekpos should ignore the last
- // argument (of type openmode).
- template<typename _CharT, typename _Traits>
- typename basic_filebuf<_CharT, _Traits>::pos_type
- basic_filebuf<_CharT, _Traits>::
- 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, __pos.state());
- }
- 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, __state_type __state)
- {
- pos_type __ret = pos_type(off_type(-1));
- if (_M_terminate_output())
- {
- off_type __file_off = _M_file.seekoff(__off, __way);
- if (__file_off != off_type(-1))
- {
- _M_reading = false;
- _M_writing = false;
- _M_ext_next = _M_ext_end = _M_ext_buf;
- _M_set_buffer(-1);
- _M_state_cur = __state;
- __ret = __file_off;
- __ret.state(_M_state_cur);
- }
- }
- return __ret;
- }
-
- // Returns the distance from the end of the ext buffer to the point
- // corresponding to gptr(). This is a negative value. Updates __state
- // from eback() correspondence to gptr().
- template<typename _CharT, typename _Traits>
- int basic_filebuf<_CharT, _Traits>::
- _M_get_ext_pos(__state_type& __state)
- {
- if (_M_codecvt->always_noconv())
- return this->gptr() - this->egptr();
- else
- {
- // Calculate offset from _M_ext_buf that corresponds to
- // gptr(). Precondition: __state == _M_state_last, which
- // corresponds to eback().
- const int __gptr_off =
- _M_codecvt->length(__state, _M_ext_buf, _M_ext_next,
- this->gptr() - this->eback());
- return _M_ext_buf + __gptr_off - _M_ext_end;
- }
- }
-
- 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())
- {
- const int_type __tmp = this->overflow();
- if (traits_type::eq_int_type(__tmp, traits_type::eof()))
- __testvalid = false;
- }
-
- // 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;
- }
- }
- return __testvalid;
- }
-
- template<typename _CharT, typename _Traits>
- int
- basic_filebuf<_CharT, _Traits>::
- sync()
- {
- // Make sure that the internal buffer resyncs its idea of
- // the file position with the external file.
- 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)
- {
- bool __testvalid = true;
-
- const __codecvt_type* _M_codecvt_tmp = 0;
- if (__builtin_expect(has_facet<__codecvt_type>(__loc), true))
- _M_codecvt_tmp = &use_facet<__codecvt_type>(__loc);
-
- if (this->is_open())
- {
- // encoding() == -1 is ok only at the beginning.
- if ((_M_reading || _M_writing)
- && __check_facet(_M_codecvt).encoding() == -1)
- __testvalid = false;
- else
- {
- if (_M_reading)
- {
- if (__check_facet(_M_codecvt).always_noconv())
- {
- if (_M_codecvt_tmp
- && !__check_facet(_M_codecvt_tmp).always_noconv())
- __testvalid = this->seekoff(0, ios_base::cur, _M_mode)
- != pos_type(off_type(-1));
- }
- else
- {
- // External position corresponding to gptr().
- _M_ext_next = _M_ext_buf
- + _M_codecvt->length(_M_state_last, _M_ext_buf,
- _M_ext_next,
- this->gptr() - this->eback());
- const streamsize __remainder = _M_ext_end - _M_ext_next;
- if (__remainder)
- __builtin_memmove(_M_ext_buf, _M_ext_next, __remainder);
-
- _M_ext_next = _M_ext_buf;
- _M_ext_end = _M_ext_buf + __remainder;
- _M_set_buffer(-1);
- _M_state_last = _M_state_cur = _M_state_beg;
- }
- }
- else if (_M_writing && (__testvalid = _M_terminate_output()))
- _M_set_buffer(-1);
- }
- }
-
- if (__testvalid)
- _M_codecvt = _M_codecvt_tmp;
- else
- _M_codecvt = 0;
- }
-
- // Inhibit implicit instantiations for required instantiations,
- // which are defined via explicit instantiations elsewhere.
- #if _GLIBCXX_EXTERN_TEMPLATE
- extern template class basic_filebuf<char>;
- extern template class basic_ifstream<char>;
- extern template class basic_ofstream<char>;
- extern template class basic_fstream<char>;
-
- #ifdef _GLIBCXX_USE_WCHAR_T
- extern template class basic_filebuf<wchar_t>;
- extern template class basic_ifstream<wchar_t>;
- extern template class basic_ofstream<wchar_t>;
- extern template class basic_fstream<wchar_t>;
- #endif
- #endif
-
- _GLIBCXX_END_NAMESPACE_VERSION
- } // namespace std
-
- #endif
|