aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/include/bits/fstream.tcc
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/include/bits/fstream.tcc')
-rw-r--r--libstdc++-v3/include/bits/fstream.tcc325
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,