Commit 391cd095 by Paolo Carlini Committed by Paolo Carlini

PR libstdc++/9404, PR libstdc++/9701 (partial)

2003-02-24  Paolo Carlini <pcarlini@unitus.it>
	    Nathan Myers <ncm@cantrip.org>

	PR libstdc++/9404, PR libstdc++/9701 (partial)
	(aka pptr == epptr implies overflow)
	* include/bits/fstream.tcc (_M_allocate_internal_buffer):
	Consistently, _M_out_end points to the end of the buffer just
	created.
	(overflow): Tweak to use _M_out_buf_size().
	(_M_convert_to_external): The role of the old _M_out_end is
	now played by _M_out_lim.
	(_M_really_overflow): Likewise.
	(seekoff): Likewise.
	(setbuf): _M_out_end points to the end of the external buffer.
	* include/bits/sstream.tcc (overflow): Rewrote, taking into
	account the resolution of DR 169 (TC).
	(seekoff): Use _M_string.capacity(); ios_base::end is now _M_out_lim.
	(seekpos): Use _M_string.capacity(); tweak.
	* include/bits/streambuf.tcc (sputc, xsputn): Remove comments.
	* include/std/std_fstream.h (sync): The role of the old
	_M_out_end is now played by _M_out_lim.
	(_M_set_indeterminate): Use _M_set_determinate.
	(_M_set_determinate): _M_out_end is now _M_out_lim.
	(_M_is_indeterminate): Likewise.
	* include/std/std_sstream.h (str()): _M_out_end is now _M_out_lim.
	(_M_stringbuf_init): Don't set _M_buf_size, unused for sstreams,
	which have the information readily available as _M_string.capacity();
	for ate and app modes, pass the string size to _M_really_sync.
	(_M_really_sync): Consistently set _M_out_end and _M_out_lim, to
	point to the end of the buffer (i.e., epptr) and to the string end,
	respectively.
	* include/std/std_streambuf.h: tweak comments, add _M_out_lim,
	which points to the right limit of the used put area.
	(_M_out_cur_move): The role of the old _M_out_end is now played
	by _M_out_lim.
	(_M_out_buf_size): Simplify: now (when _M_out_cur) return simply
	_M_out_end  - _M_out_cur (i.e., pptr), _very_ close to the letter
	of the standard.
	(basic_streambuf()): Initialize _M_out_lim too.
	* testsuite/27_io/filebuf_virtuals.cc (test10): Trivial tweak.
	* testsuite/27_io/filebuf_virtuals.cc (test11): Add.
 	* testsuite/27_io/stringbuf_virtuals.cc (test09): Add.

Co-Authored-By: Nathan Myers <ncm@cantrip.org>

From-SVN: r63367
parent 2e812a0a
2003-02-24 Paolo Carlini <pcarlini@unitus.it>
Nathan Myers <ncm@cantrip.org>
PR libstdc++/9404, PR libstdc++/9701 (partial)
(aka pptr == epptr implies overflow)
* include/bits/fstream.tcc (_M_allocate_internal_buffer):
Consistently, _M_out_end points to the end of the buffer just
created.
(overflow): Tweak to use _M_out_buf_size().
(_M_convert_to_external): The role of the old _M_out_end is
now played by _M_out_lim.
(_M_really_overflow): Likewise.
(seekoff): Likewise.
(setbuf): _M_out_end points to the end of the external buffer.
* include/bits/sstream.tcc (overflow): Rewrote, taking into
account the resolution of DR 169 (TC).
(seekoff): Use _M_string.capacity(); ios_base::end is now _M_out_lim.
(seekpos): Use _M_string.capacity(); tweak.
* include/bits/streambuf.tcc (sputc, xsputn): Remove comments.
* include/std/std_fstream.h (sync): The role of the old
_M_out_end is now played by _M_out_lim.
(_M_set_indeterminate): Use _M_set_determinate.
(_M_set_determinate): _M_out_end is now _M_out_lim.
(_M_is_indeterminate): Likewise.
* include/std/std_sstream.h (str()): _M_out_end is now _M_out_lim.
(_M_stringbuf_init): Don't set _M_buf_size, unused for sstreams,
which have the information readily available as _M_string.capacity();
for ate and app modes, pass the string size to _M_really_sync.
(_M_really_sync): Consistently set _M_out_end and _M_out_lim, to
point to the end of the buffer (i.e., epptr) and to the string end,
respectively.
* include/std/std_streambuf.h: tweak comments, add _M_out_lim,
which points to the right limit of the used put area.
(_M_out_cur_move): The role of the old _M_out_end is now played
by _M_out_lim.
(_M_out_buf_size): Simplify: now (when _M_out_cur) return simply
_M_out_end - _M_out_cur (i.e., pptr), _very_ close to the letter
of the standard.
(basic_streambuf()): Initialize _M_out_lim too.
* testsuite/27_io/filebuf_virtuals.cc (test10): Trivial tweak.
* testsuite/27_io/filebuf_virtuals.cc (test11): Add.
* testsuite/27_io/stringbuf_virtuals.cc (test09): Add.
2003-02-24 Benjamin Kosnik <bkoz@redhat.com> 2003-02-24 Benjamin Kosnik <bkoz@redhat.com>
* testsuite/27_io/ios_base_storage.cc (main): Call * testsuite/27_io/ios_base_storage.cc (main): Call
......
...@@ -48,8 +48,10 @@ namespace std ...@@ -48,8 +48,10 @@ namespace std
{ {
this->_M_buf_size = this->_M_buf_size_opt; this->_M_buf_size = this->_M_buf_size_opt;
// Allocate internal buffer. // Allocate internal buffer...
this->_M_buf = new char_type[this->_M_buf_size]; this->_M_buf = new char_type[this->_M_buf_size];
// ... and consistently set the end of buffer pointer.
this->_M_out_end = this->_M_buf + this->_M_buf_size;
_M_buf_allocated = true; _M_buf_allocated = true;
} }
} }
...@@ -125,7 +127,7 @@ namespace std ...@@ -125,7 +127,7 @@ namespace std
{ {
const int_type __eof = traits_type::eof(); const int_type __eof = traits_type::eof();
bool __testput = this->_M_out_cur bool __testput = this->_M_out_cur
&& this->_M_out_beg < this->_M_out_end; && this->_M_out_beg < this->_M_out_lim;
if (__testput if (__testput
&& traits_type::eq_int_type(_M_really_overflow(__eof), __eof)) && traits_type::eq_int_type(_M_really_overflow(__eof), __eof))
return __ret; return __ret;
...@@ -245,8 +247,7 @@ namespace std ...@@ -245,8 +247,7 @@ namespace std
overflow(int_type __c) overflow(int_type __c)
{ {
int_type __ret = traits_type::eof(); int_type __ret = traits_type::eof();
bool __testput = this->_M_out_cur bool __testput = _M_out_buf_size();
&& this->_M_out_cur < this->_M_buf + this->_M_buf_size;
bool __testout = this->_M_mode & ios_base::out; bool __testout = this->_M_mode & ios_base::out;
if (__testout) if (__testout)
...@@ -314,7 +315,7 @@ namespace std ...@@ -314,7 +315,7 @@ namespace std
if (__r == codecvt_base::partial) if (__r == codecvt_base::partial)
{ {
const char_type* __iresume = __iend; const char_type* __iresume = __iend;
streamsize __rlen = this->_M_out_end - __iend; streamsize __rlen = this->_M_out_lim - __iend;
__r = __cvt.out(_M_state_cur, __iresume, __iresume + __rlen, __r = __cvt.out(_M_state_cur, __iresume, __iresume + __rlen,
__iend, __buf, __buf + __blen, __bend); __iend, __buf, __buf + __blen, __bend);
if (__r != codecvt_base::error) if (__r != codecvt_base::error)
...@@ -336,7 +337,7 @@ namespace std ...@@ -336,7 +337,7 @@ namespace std
_M_really_overflow(int_type __c) _M_really_overflow(int_type __c)
{ {
int_type __ret = traits_type::eof(); int_type __ret = traits_type::eof();
bool __testput = this->_M_out_cur && this->_M_out_beg < this->_M_out_end; bool __testput = this->_M_out_cur && this->_M_out_beg < this->_M_out_lim;
bool __testunbuffered = _M_file.is_open() && !this->_M_buf_size_opt; bool __testunbuffered = _M_file.is_open() && !this->_M_buf_size_opt;
if (__testput || __testunbuffered) if (__testput || __testunbuffered)
...@@ -358,7 +359,7 @@ namespace std ...@@ -358,7 +359,7 @@ namespace std
// NB: In the unbuffered case, no internal buffer exists. // NB: In the unbuffered case, no internal buffer exists.
if (!__testunbuffered) if (!__testunbuffered)
_M_convert_to_external(this->_M_out_beg, _M_convert_to_external(this->_M_out_beg,
this->_M_out_end - this->_M_out_beg, this->_M_out_lim - this->_M_out_beg,
__elen, __plen); __elen, __plen);
// Convert pending sequence to external representation, output. // Convert pending sequence to external representation, output.
...@@ -398,12 +399,15 @@ namespace std ...@@ -398,12 +399,15 @@ namespace std
// that an external char_type array of length (__s + __n) // that an external char_type array of length (__s + __n)
// exists and has been pre-allocated. If this is not the // exists and has been pre-allocated. If this is not the
// case, things will quickly blow up. // case, things will quickly blow up.
// Step 1: Destroy the current internal array. // Step 1: Destroy the current internal array.
_M_destroy_internal_buffer(); _M_destroy_internal_buffer();
// Step 2: Use the external array. // Step 2: Use the external array.
this->_M_buf = __s; this->_M_buf = __s;
this->_M_buf_size_opt = this->_M_buf_size = __n; this->_M_buf_size_opt = this->_M_buf_size = __n;
// Consistently set the end of buffer pointer.
this->_M_out_end = this->_M_buf + this->_M_buf_size;
_M_set_indeterminate(); _M_set_indeterminate();
} }
_M_last_overflowed = false; _M_last_overflowed = false;
...@@ -437,7 +441,7 @@ namespace std ...@@ -437,7 +441,7 @@ namespace std
bool __testget = this->_M_in_cur bool __testget = this->_M_in_cur
&& this->_M_in_beg < this->_M_in_end; && this->_M_in_beg < this->_M_in_end;
bool __testput = this->_M_out_cur bool __testput = this->_M_out_cur
&& this->_M_out_beg < this->_M_out_end; && this->_M_out_beg < this->_M_out_lim;
// Sync the internal and external streams. // Sync the internal and external streams.
// out // out
if (__testput || _M_last_overflowed) if (__testput || _M_last_overflowed)
......
...@@ -80,38 +80,35 @@ namespace std ...@@ -80,38 +80,35 @@ namespace std
basic_stringbuf<_CharT, _Traits, _Alloc>:: basic_stringbuf<_CharT, _Traits, _Alloc>::
overflow(int_type __c) overflow(int_type __c)
{ {
int_type __ret = traits_type::eof();
bool __testeof = traits_type::eq_int_type(__c, __ret);
bool __testwrite = this->_M_out_cur < this->_M_buf + this->_M_buf_size;
bool __testout = this->_M_mode & ios_base::out; bool __testout = this->_M_mode & ios_base::out;
if (__builtin_expect(!__testout, false))
return traits_type::eof();
bool __testeof = traits_type::eq_int_type(__c, traits_type::eof());
if (__builtin_expect(__testeof, false))
return traits_type::not_eof(__c);
// In virtue of DR 169 (TC) we are allowed to grow more than
// one char the first time and also...
__size_type __len =
std::max(_M_string.capacity() + 1, this->_M_buf_size_opt);
bool __testwrite = _M_out_buf_size();
if (__builtin_expect(!__testwrite && __len > _M_string.max_size(), false))
return traits_type::eof();
// Try to append __c into output sequence in one of two ways. // Try to append __c into output sequence in one of two ways.
// Order these tests done in is unspecified by the standard. // Order these tests done in is unspecified by the standard.
if (__testout) if (!__testwrite)
{ {
if (!__testeof) // Force-allocate, re-sync.
{ _M_string = this->str();
__size_type __len = std::max(this->_M_buf_size, // ... the next times. That's easy to implement thanks to the
this->_M_buf_size_opt); // exponential growth policy builtin into basic_string.
__len *= 2; _M_string.reserve(__len);
_M_really_sync(this->_M_in_cur - this->_M_in_beg,
if (__testwrite) this->_M_out_cur - this->_M_out_beg);
__ret = this->sputc(traits_type::to_char_type(__c));
else if (__len <= _M_string.max_size())
{
// Force-allocate, re-sync.
_M_string = this->str();
_M_string.reserve(__len);
this->_M_buf_size = __len;
_M_really_sync(this->_M_in_cur - this->_M_in_beg,
this->_M_out_cur - this->_M_out_beg);
__ret = this->sputc(traits_type::to_char_type(__c));
}
}
else
__ret = traits_type::not_eof(__c);
} }
return __ret; return this->sputc(traits_type::to_char_type(__c));
} }
template <class _CharT, class _Traits, class _Alloc> template <class _CharT, class _Traits, class _Alloc>
...@@ -126,7 +123,7 @@ namespace std ...@@ -126,7 +123,7 @@ namespace std
__testin &= !(__mode & ios_base::out); __testin &= !(__mode & ios_base::out);
__testout &= !(__mode & ios_base::in); __testout &= !(__mode & ios_base::in);
if (this->_M_buf_size && (__testin || __testout || __testboth)) if (_M_string.capacity() && (__testin || __testout || __testboth))
{ {
char_type* __beg = this->_M_buf; char_type* __beg = this->_M_buf;
char_type* __curi = NULL; char_type* __curi = NULL;
...@@ -142,7 +139,9 @@ namespace std ...@@ -142,7 +139,9 @@ namespace std
if (__testout || __testboth) if (__testout || __testboth)
{ {
__curo = this->pptr(); __curo = this->pptr();
__endo = this->epptr(); // Due to the resolution of DR169, ios_base::end
// is this->_M_out_lim, not epptr().
__endo = this->_M_out_lim;
} }
off_type __newoffi = 0; off_type __newoffi = 0;
...@@ -181,7 +180,7 @@ namespace std ...@@ -181,7 +180,7 @@ namespace std
{ {
pos_type __ret = pos_type(off_type(-1)); pos_type __ret = pos_type(off_type(-1));
if (this->_M_buf_size) if (_M_string.capacity())
{ {
off_type __pos = __sp; // Use streamoff operator to do conversion. off_type __pos = __sp; // Use streamoff operator to do conversion.
char_type* __beg = NULL; char_type* __beg = NULL;
...@@ -205,7 +204,7 @@ namespace std ...@@ -205,7 +204,7 @@ namespace std
if (__testout || __testboth) if (__testout || __testboth)
{ {
__beg = this->pbase(); __beg = this->pbase();
__end = this->_M_buf + this->_M_buf_size; __end = this->epptr();
if (0 <= __pos && __pos <= __end - __beg) if (0 <= __pos && __pos <= __end - __beg)
__testposo = true; __testposo = true;
} }
......
...@@ -93,11 +93,6 @@ namespace std ...@@ -93,11 +93,6 @@ namespace std
return __ret; return __ret;
} }
// Don't test against _M_buf + _M_buf_size, because _M_buf reflects
// allocated space, and on certain (rare but entirely legal)
// situations, there will be no allocated space yet the internal
// buffers will still be valid. (This happens if setp is used to set
// the internal buffer to say some externally-allocated sequence.)
template<typename _CharT, typename _Traits> template<typename _CharT, typename _Traits>
typename basic_streambuf<_CharT, _Traits>::int_type typename basic_streambuf<_CharT, _Traits>::int_type
basic_streambuf<_CharT, _Traits>:: basic_streambuf<_CharT, _Traits>::
...@@ -149,11 +144,6 @@ namespace std ...@@ -149,11 +144,6 @@ namespace std
return __ret; return __ret;
} }
// Don't test against _M_buf + _M_buf_size, because _M_buf reflects
// allocated space, and on certain (rare but entirely legal)
// situations, there will be no allocated space yet the internal
// buffers will still be valid. (This happens if setp is used to set
// the internal buffer to say some externally-allocated sequence.)
template<typename _CharT, typename _Traits> template<typename _CharT, typename _Traits>
streamsize streamsize
basic_streambuf<_CharT, _Traits>:: basic_streambuf<_CharT, _Traits>::
......
...@@ -312,14 +312,14 @@ namespace std ...@@ -312,14 +312,14 @@ namespace std
sync() sync()
{ {
bool __testput = this->_M_out_cur bool __testput = this->_M_out_cur
&& this->_M_out_beg < this->_M_out_end; && this->_M_out_beg < this->_M_out_lim;
// Make sure that the internal buffer resyncs its idea of // Make sure that the internal buffer resyncs its idea of
// the file position with the external file. // the file position with the external file.
if (__testput) if (__testput)
{ {
// Need to restore current position after the write. // Need to restore current position after the write.
off_type __off = this->_M_out_cur - this->_M_out_end; off_type __off = this->_M_out_cur - this->_M_out_lim;
_M_really_overflow(); // _M_file.sync() will be called within _M_really_overflow(); // _M_file.sync() will be called within
if (__off) if (__off)
_M_file.seekoff(__off, ios_base::cur); _M_file.seekoff(__off, ios_base::cur);
...@@ -387,11 +387,7 @@ namespace std ...@@ -387,11 +387,7 @@ namespace std
void void
_M_set_indeterminate(void) _M_set_indeterminate(void)
{ {
if (this->_M_mode & ios_base::in) _M_set_determinate(off_type(0));
this->setg(this->_M_buf, this->_M_buf, this->_M_buf);
if (this->_M_mode & ios_base::out)
this->setp(this->_M_buf, this->_M_buf);
_M_filepos = this->_M_buf;
} }
/** /**
...@@ -405,9 +401,15 @@ namespace std ...@@ -405,9 +401,15 @@ namespace std
bool __testin = this->_M_mode & ios_base::in; bool __testin = this->_M_mode & ios_base::in;
bool __testout = this->_M_mode & ios_base::out; bool __testout = this->_M_mode & ios_base::out;
if (__testin) if (__testin)
this->setg(this->_M_buf, this->_M_buf, this->_M_buf + __off); {
this->_M_in_beg = this->_M_in_cur = this->_M_buf;
this->_M_in_end = this->_M_buf + __off;
}
if (__testout) if (__testout)
this->setp(this->_M_buf, this->_M_buf + __off); {
this->_M_out_beg = this->_M_out_cur = this->_M_buf;
this->_M_out_lim = this->_M_buf + __off;
}
_M_filepos = this->_M_buf + __off; _M_filepos = this->_M_buf + __off;
} }
...@@ -419,16 +421,18 @@ namespace std ...@@ -419,16 +421,18 @@ namespace std
bool bool
_M_is_indeterminate(void) _M_is_indeterminate(void)
{ {
bool __testin = this->_M_mode & ios_base::in;
bool __testout = this->_M_mode & ios_base::out;
bool __ret = false; bool __ret = false;
// Don't return true if unbuffered. // Don't return true if unbuffered.
if (this->_M_buf) if (this->_M_buf)
{ {
if (this->_M_mode & ios_base::in) if (__testin)
__ret = this->_M_in_beg == this->_M_in_cur __ret = this->_M_in_beg == this->_M_in_cur
&& this->_M_in_cur == this->_M_in_end; && this->_M_in_cur == this->_M_in_end;
if (this->_M_mode & ios_base::out) if (__testout)
__ret = this->_M_out_beg == this->_M_out_cur __ret = this->_M_out_beg == this->_M_out_cur
&& this->_M_out_cur == this->_M_out_end; && this->_M_out_cur == this->_M_out_lim;
} }
return __ret; return __ret;
} }
......
...@@ -140,8 +140,8 @@ namespace std ...@@ -140,8 +140,8 @@ namespace std
// _M_string, and may not be the correct size of the // _M_string, and may not be the correct size of the
// current stringbuf internal buffer. // current stringbuf internal buffer.
__size_type __len = _M_string.size(); __size_type __len = _M_string.size();
if (this->_M_out_end > this->_M_out_beg) if (this->_M_out_lim > this->_M_out_beg)
__len = std::max(__size_type(this->_M_out_end __len = std::max(__size_type(this->_M_out_lim
- this->_M_out_beg), __len); - this->_M_out_beg), __len);
return __string_type(this->_M_out_beg, this->_M_out_beg + __len); return __string_type(this->_M_out_beg, this->_M_out_beg + __len);
} }
...@@ -174,13 +174,6 @@ namespace std ...@@ -174,13 +174,6 @@ namespace std
void void
_M_stringbuf_init(ios_base::openmode __mode) _M_stringbuf_init(ios_base::openmode __mode)
{ {
// _M_buf_size is a convenient alias for "what the streambuf
// thinks the allocated size of the string really is." This is
// necessary as ostringstreams are implemented with the
// streambufs having control of the allocation and
// re-allocation of the internal string object, _M_string.
this->_M_buf_size = _M_string.size();
// NB: Start ostringstream buffers at 512 bytes. This is an // NB: Start ostringstream buffers at 512 bytes. This is an
// experimental value (pronounced "arbitrary" in some of the // experimental value (pronounced "arbitrary" in some of the
// hipper english-speaking countries), and can be changed to // hipper english-speaking countries), and can be changed to
...@@ -188,7 +181,7 @@ namespace std ...@@ -188,7 +181,7 @@ namespace std
this->_M_buf_size_opt = 512; this->_M_buf_size_opt = 512;
this->_M_mode = __mode; this->_M_mode = __mode;
if (this->_M_mode & (ios_base::ate | ios_base::app)) if (this->_M_mode & (ios_base::ate | ios_base::app))
_M_really_sync(0, this->_M_buf_size); _M_really_sync(0, _M_string.size());
else else
_M_really_sync(0, 0); _M_really_sync(0, 0);
} }
...@@ -268,7 +261,9 @@ namespace std ...@@ -268,7 +261,9 @@ namespace std
this->setg(__base, __base + __i, __base + __len); this->setg(__base, __base + __i, __base + __len);
if (__testout) if (__testout)
{ {
this->setp(__base, __base + __len); this->setp(__base, __base + _M_string.capacity());
// _M_out_lim points to the string end.
this->_M_out_lim = __base + __len;
this->_M_out_cur += __o; this->_M_out_cur += __o;
} }
return 0; return 0;
......
...@@ -172,7 +172,8 @@ namespace std ...@@ -172,7 +172,8 @@ namespace std
/** /**
* @if maint * @if maint
* Actual size of allocated internal buffer, in bytes. * Actual size of allocated internal buffer, in bytes. Unused
* for sstreams, which have readily available _M_string.capacity().
* @endif * @endif
*/ */
size_t _M_buf_size; size_t _M_buf_size;
...@@ -202,12 +203,15 @@ namespace std ...@@ -202,12 +203,15 @@ namespace std
* - put == output == write * - put == output == write
* @endif * @endif
*/ */
char_type* _M_in_beg; // Start of get area. char_type* _M_in_beg; // Start of get area.
char_type* _M_in_cur; // Current read area. char_type* _M_in_cur; // Current read area.
char_type* _M_in_end; // End of get area. char_type* _M_in_end; // End of get area.
char_type* _M_out_beg; // Start of put area. char_type* _M_out_beg; // Start of put area.
char_type* _M_out_cur; // Current put area. char_type* _M_out_cur; // Current put area.
char_type* _M_out_end; // End of put area. char_type* _M_out_end; // End of put area.
char_type* _M_out_lim; // Right limit of used put area.
//@} //@}
/** /**
...@@ -305,13 +309,13 @@ namespace std ...@@ -305,13 +309,13 @@ namespace std
} }
// Correctly sets the _M_out_cur pointer, and bumps the // Correctly sets the _M_out_cur pointer, and bumps the
// appropriate _M_*_end pointers as well. Necessary for the // appropriate _M_out_lim and _M_in_end pointers as well. Necessary
// un-tied stringbufs, in in|out mode. // for the un-tied stringbufs, in in|out mode.
// Invariant: // Invariant:
// __n + _M_out_[cur, end] <= _M_buf + _M_buf_size // __n + _M_out_[cur, lim] <= _M_out_end
// Assuming all _M_*_[beg, cur, end] pointers are operating on // Assuming all _M_out_[beg, cur, lim] pointers are operating on
// the same range: // the same range:
// _M_buf <= _M_*_ <= _M_buf + _M_buf_size // _M_buf <= _M_*_ <= _M_out_end
void void
_M_out_cur_move(off_type __n) // argument needs to be +- _M_out_cur_move(off_type __n) // argument needs to be +-
{ {
...@@ -320,32 +324,23 @@ namespace std ...@@ -320,32 +324,23 @@ namespace std
_M_out_cur += __n; _M_out_cur += __n;
if (__testin && _M_buf_unified) if (__testin && _M_buf_unified)
_M_in_cur += __n; _M_in_cur += __n;
if (_M_out_cur > _M_out_end) if (_M_out_cur > _M_out_lim)
{ {
_M_out_end = _M_out_cur; _M_out_lim = _M_out_cur;
// NB: in | out buffers drag the _M_in_end pointer along... // NB: in | out buffers drag the _M_in_end pointer along...
if (__testin) if (__testin)
_M_in_end += __n; _M_in_end += __n;
} }
} }
// Return the size of the output buffer. This depends on the // Returns zero if the output buffer is full (-> overflow).
// buffer in use: allocated buffers have a stored size in
// _M_buf_size and setbuf() buffers don't.
off_type off_type
_M_out_buf_size() _M_out_buf_size()
{ {
off_type __ret = 0;
if (_M_out_cur) if (_M_out_cur)
{ return _M_out_end - _M_out_cur;
// Using allocated buffer. else
if (_M_out_beg == _M_buf) return off_type(0);
__ret = _M_out_beg + _M_buf_size - _M_out_cur;
// Using non-allocated buffer.
else
__ret = _M_out_end - _M_out_cur;
}
return __ret;
} }
public: public:
...@@ -568,8 +563,8 @@ namespace std ...@@ -568,8 +563,8 @@ namespace std
*/ */
basic_streambuf() basic_streambuf()
: _M_buf(NULL), _M_buf_size(0), _M_buf_size_opt(BUFSIZ), : _M_buf(NULL), _M_buf_size(0), _M_buf_size_opt(BUFSIZ),
_M_buf_unified(false), _M_in_beg(0), _M_in_cur(0), _M_in_end(0), _M_buf_unified(false), _M_in_beg(0), _M_in_cur(0), _M_in_end(0),
_M_out_beg(0), _M_out_cur(0), _M_out_end(0), _M_out_beg(0), _M_out_cur(0), _M_out_end(0), _M_out_lim(0),
_M_mode(ios_base::openmode(0)), _M_buf_locale(locale()), _M_mode(ios_base::openmode(0)), _M_buf_locale(locale()),
_M_pback_cur_save(0), _M_pback_end_save(0), _M_pback_cur_save(0), _M_pback_end_save(0),
_M_pback_init(false) _M_pback_init(false)
...@@ -666,7 +661,7 @@ namespace std ...@@ -666,7 +661,7 @@ namespace std
setp(char_type* __pbeg, char_type* __pend) setp(char_type* __pbeg, char_type* __pend)
{ {
_M_out_beg = _M_out_cur = __pbeg; _M_out_beg = _M_out_cur = __pbeg;
_M_out_end = __pend; _M_out_end = __pend;
if (!(_M_mode & ios_base::out) && __pbeg && __pend) if (!(_M_mode & ios_base::out) && __pbeg && __pend)
_M_mode = _M_mode | ios_base::out; _M_mode = _M_mode | ios_base::out;
} }
......
...@@ -71,7 +71,8 @@ const char carray_02[] = "memphis, new orleans, and savanah"; ...@@ -71,7 +71,8 @@ const char carray_02[] = "memphis, new orleans, and savanah";
const char name_01[] = "filebuf_virtuals-1.txt"; // file with data in it const char name_01[] = "filebuf_virtuals-1.txt"; // file with data in it
const char name_02[] = "filebuf_virtuals-2.txt"; // empty file, need to create const char name_02[] = "filebuf_virtuals-2.txt"; // empty file, need to create
const char name_03[] = "filebuf_virtuals-3.txt"; // empty file, need to create const char name_03[] = "filebuf_virtuals-3.txt"; // empty file, need to create
const char name_04[] = "filebuf_virtuals-4.txt"; // empty file, need to create
const char name_05[] = "filebuf_virtuals-5.txt"; // empty file, need to create
class derived_filebuf: public std::filebuf class derived_filebuf: public std::filebuf
{ {
...@@ -607,14 +608,14 @@ void test10() ...@@ -607,14 +608,14 @@ void test10()
{ {
ofstream out; ofstream out;
out.imbue(loc); out.imbue(loc);
out.open("filebuf_virtuals-4.txt"); out.open(name_04);
copy(str.begin(), str.end(), copy(str.begin(), str.end(),
ostreambuf_iterator<char>(out)); ostreambuf_iterator<char>(out));
} }
{ {
ifstream in; ifstream in;
in.open("filebuf_virtuals-4.txt"); in.open(name_04);
copy(istreambuf_iterator<char>(in), copy(istreambuf_iterator<char>(in),
istreambuf_iterator<char>(), istreambuf_iterator<char>(),
back_inserter(tmp)); back_inserter(tmp));
...@@ -624,6 +625,62 @@ void test10() ...@@ -624,6 +625,62 @@ void test10()
VERIFY( tmp == str ); VERIFY( tmp == str );
} }
bool over_called;
class Derived_filebuf : public std::filebuf
{
public:
int_type overflow(int_type c)
{
over_called = true;
return std::filebuf::overflow(c);
}
const char_type* pub_epptr() const
{
return epptr();
}
const char_type* pub_pptr() const
{
return pptr();
}
};
// libstdc++/9701 (partial)
void test11()
{
bool test = true;
bool over_expected;
// sputc
Derived_filebuf dfbuf_01;
dfbuf_01.open(name_05, std::ios_base::out);
over_called = false;
dfbuf_01.sputc('i');
VERIFY( !over_called );
over_expected = dfbuf_01.pub_epptr() == dfbuf_01.pub_pptr();
over_called = false;
dfbuf_01.sputc('v');
VERIFY( (!over_expected && !over_called)
|| (over_expected && over_called) );
dfbuf_01.close();
// sputn
Derived_filebuf dfbuf_02;
dfbuf_02.open(name_05, std::ios_base::out);
over_called = false;
dfbuf_02.sputn("sonne's", 7);
VERIFY( !over_called );
over_expected = dfbuf_02.pub_epptr() == dfbuf_02.pub_pptr();
over_called = false;
dfbuf_02.sputn(" peak", 5);
VERIFY( (!over_expected && !over_called)
|| (over_expected && over_called) );
dfbuf_02.close();
}
main() main()
{ {
test01(); test01();
...@@ -638,5 +695,6 @@ main() ...@@ -638,5 +695,6 @@ main()
test08(); test08();
test09(); test09();
test10(); test10();
test11();
return 0; return 0;
} }
...@@ -92,6 +92,61 @@ void test08() ...@@ -92,6 +92,61 @@ void test08()
VERIFY( ob.getloc() == loc_de ); VERIFY( ob.getloc() == loc_de );
} }
bool over_called;
class Derived_stringbuf : public std::stringbuf
{
public:
int_type overflow(int_type c)
{
over_called = true;
return std::stringbuf::overflow(c);
}
const char_type* pub_epptr() const
{
return epptr();
}
const char_type* pub_pptr() const
{
return pptr();
}
};
// libstdc++/9404
void test09()
{
bool test = true;
bool over_expected;
// sputc
Derived_stringbuf dsbuf_01;
over_called = false;
dsbuf_01.sputc('i');
VERIFY( over_called );
over_expected = dsbuf_01.pub_epptr() == dsbuf_01.pub_pptr();
over_called = false;
dsbuf_01.sputc('v');
VERIFY( (!over_expected && !over_called)
|| (over_expected && over_called) );
dsbuf_01.sputc('i');
VERIFY( dsbuf_01.str() == "ivi" ); // Sanity check.
// sputn
Derived_stringbuf dsbuf_02;
over_called = false;
dsbuf_02.sputn("sonne's", 7);
VERIFY( over_called );
over_expected = dsbuf_02.pub_epptr() == dsbuf_02.pub_pptr();
over_called = false;
dsbuf_02.sputn(" peak", 5);
VERIFY( (!over_expected && !over_called)
|| (over_expected && over_called) );
VERIFY( dsbuf_02.str() == "sonne's peak" ); // Sanity check.
}
int main() int main()
{ {
using namespace std; using namespace std;
...@@ -106,5 +161,6 @@ int main() ...@@ -106,5 +161,6 @@ int main()
test02(in3, false); test02(in3, false);
test08(); test08();
test09();
return 0; return 0;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment