]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR libstdc++/9404, PR libstdc++/9701 (partial)
authorPaolo Carlini <pcarlini@unitus.it>
Mon, 24 Feb 2003 18:22:58 +0000 (19:22 +0100)
committerPaolo Carlini <paolo@gcc.gnu.org>
Mon, 24 Feb 2003 18:22:58 +0000 (18:22 +0000)
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

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/fstream.tcc
libstdc++-v3/include/bits/sstream.tcc
libstdc++-v3/include/bits/streambuf.tcc
libstdc++-v3/include/std/std_fstream.h
libstdc++-v3/include/std/std_sstream.h
libstdc++-v3/include/std/std_streambuf.h
libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc
libstdc++-v3/testsuite/27_io/stringbuf_virtuals.cc

index eb7a66d835780b3c8a97a9e722e99413981cc3c3..30d0c0c049ef48c4c3353bb8ed618fcc223306cc 100644 (file)
@@ -1,3 +1,46 @@
+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>
 
        * testsuite/27_io/ios_base_storage.cc (main): Call
index 0c6e7b04b6bf16cbdca7fff4d2386a50f1a2df62..be4b0c029473445f82343fbcdeb71ffeab612f5f 100644 (file)
@@ -48,8 +48,10 @@ namespace std
        {
          this->_M_buf_size = this->_M_buf_size_opt;
 
-         // Allocate internal buffer.
-         this->_M_buf = new char_type[this->_M_buf_size]; 
+         // Allocate internal buffer...
+         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;
        }
     }
@@ -125,7 +127,7 @@ namespace std
        {
          const int_type __eof = traits_type::eof();
          bool __testput = this->_M_out_cur
-           && this->_M_out_beg < this->_M_out_end;
+           && this->_M_out_beg < this->_M_out_lim;
          if (__testput 
              && traits_type::eq_int_type(_M_really_overflow(__eof), __eof))
            return __ret;
@@ -245,8 +247,7 @@ namespace std
     overflow(int_type __c)
     {
       int_type __ret = traits_type::eof();
-      bool __testput = this->_M_out_cur
-       && this->_M_out_cur < this->_M_buf + this->_M_buf_size;
+      bool __testput = _M_out_buf_size();
       bool __testout = this->_M_mode & ios_base::out;
       
       if (__testout)
@@ -314,7 +315,7 @@ namespace std
          if (__r == codecvt_base::partial)
            {
              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, 
                              __iend, __buf, __buf + __blen, __bend);
              if (__r != codecvt_base::error)
@@ -336,7 +337,7 @@ namespace std
     _M_really_overflow(int_type __c)
     {
       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;
 
       if (__testput || __testunbuffered)
@@ -358,7 +359,7 @@ namespace std
          // NB: In the unbuffered case, no internal buffer exists. 
          if (!__testunbuffered)
            _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);
 
          // Convert pending sequence to external representation, output.
@@ -398,12 +399,15 @@ namespace std
          // that an external char_type array of length (__s + __n)
          // exists and has been pre-allocated. If this is not the
          // case, things will quickly blow up.
+
          // 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_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_last_overflowed = false;      
@@ -437,7 +441,7 @@ namespace std
              bool __testget = this->_M_in_cur
                && this->_M_in_beg < this->_M_in_end;
              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.
              // out
              if (__testput || _M_last_overflowed)
index 489f79f20a318f1506775025a598ca4bd4565442..5f9f62e93427deada42a3077e7a28cb2ec869e50 100644 (file)
@@ -80,38 +80,35 @@ namespace std
     basic_stringbuf<_CharT, _Traits, _Alloc>::
     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;
+      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.
       // Order these tests done in is unspecified by the standard.
-      if (__testout)
+      if (!__testwrite)
        {
-         if (!__testeof)
-           {
-             __size_type __len = std::max(this->_M_buf_size, 
-                                          this->_M_buf_size_opt);
-             __len *= 2;
-
-             if (__testwrite)
-               __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);
+         // Force-allocate, re-sync.
+         _M_string = this->str();
+         // ... the next times. That's easy to implement thanks to the
+         // exponential growth policy builtin into basic_string.
+         _M_string.reserve(__len);
+         _M_really_sync(this->_M_in_cur - this->_M_in_beg, 
+                        this->_M_out_cur - this->_M_out_beg);
        }
-      return __ret;
+      return this->sputc(traits_type::to_char_type(__c));
     }
 
   template <class _CharT, class _Traits, class _Alloc>
@@ -126,7 +123,7 @@ namespace std
       __testin &= !(__mode & ios_base::out);
       __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* __curi = NULL;
@@ -142,7 +139,9 @@ namespace std
          if (__testout || __testboth)
            {
              __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;
@@ -181,7 +180,7 @@ namespace std
     {
       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.
          char_type* __beg = NULL;
@@ -205,7 +204,7 @@ namespace std
          if (__testout || __testboth)
            {
              __beg = this->pbase();
-             __end = this->_M_buf + this->_M_buf_size;
+             __end = this->epptr();
              if (0 <= __pos && __pos <= __end - __beg)
                __testposo = true;
            }
index e721f25ed91e47426544fa78b3803a59465d1bb6..c14139988af3b0e2b38d2de4dff316d4c46e9241 100644 (file)
@@ -93,11 +93,6 @@ namespace std
       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>
     typename basic_streambuf<_CharT, _Traits>::int_type
     basic_streambuf<_CharT, _Traits>::
@@ -149,11 +144,6 @@ namespace std
       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>
     streamsize
     basic_streambuf<_CharT, _Traits>::
index d7a0e0956bdf931c39ad92c8b58ed38453821aed..6dd75dd1bba3929a835a2d8a8c6b6d2c857fefd8 100644 (file)
@@ -312,14 +312,14 @@ namespace std
       sync()
       {
        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
        // the file position with the external file.
        if (__testput)
          {
            // 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
            if (__off)
              _M_file.seekoff(__off, ios_base::cur);
@@ -387,11 +387,7 @@ namespace std
       void
       _M_set_indeterminate(void)
       {
-       if (this->_M_mode & ios_base::in)
-         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;
+       _M_set_determinate(off_type(0));
       }
 
       /**
@@ -405,9 +401,15 @@ namespace std
        bool __testin = this->_M_mode & ios_base::in;
        bool __testout = this->_M_mode & ios_base::out;
        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)
-         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;
       }
 
@@ -419,16 +421,18 @@ namespace std
       bool
       _M_is_indeterminate(void)
       { 
+       bool __testin = this->_M_mode & ios_base::in;
+       bool __testout = this->_M_mode & ios_base::out;
        bool __ret = false;
        // Don't return true if unbuffered.
        if (this->_M_buf)
          {
-           if (this->_M_mode & ios_base::in)
+           if (__testin)
              __ret = this->_M_in_beg == this->_M_in_cur
                && 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
-               && this->_M_out_cur == this->_M_out_end;
+               && this->_M_out_cur == this->_M_out_lim;
          }
        return __ret;
       }
index 268478f3339bc547763767b39d7294dc8041147b..cb538b563040deffbad5b02e387b3dd90d42a172 100644 (file)
@@ -140,8 +140,8 @@ namespace std
            // _M_string, and may not be the correct size of the
            // current stringbuf internal buffer.
            __size_type __len = _M_string.size();
-           if (this->_M_out_end > this->_M_out_beg)
-             __len = std::max(__size_type(this->_M_out_end 
+           if (this->_M_out_lim > this->_M_out_beg)
+             __len = std::max(__size_type(this->_M_out_lim 
                                           - this->_M_out_beg), __len);
            return __string_type(this->_M_out_beg, this->_M_out_beg + __len);
          }
@@ -174,13 +174,6 @@ namespace std
       void
       _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
        // experimental value (pronounced "arbitrary" in some of the
        // hipper english-speaking countries), and can be changed to
@@ -188,7 +181,7 @@ namespace std
        this->_M_buf_size_opt = 512;
        this->_M_mode = __mode;
        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
          _M_really_sync(0, 0);
       }
@@ -268,7 +261,9 @@ namespace std
            this->setg(__base, __base + __i, __base + __len);
        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;
          }
        return 0;
index e7dca92d00bc72d5b3b31ebaaf9a1988f8870c41..850f2015530056e10bcca1686ced6aa66762f632 100644 (file)
@@ -172,7 +172,8 @@ namespace std
 
       /**
        *  @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
       */
       size_t                   _M_buf_size;
@@ -202,12 +203,15 @@ namespace std
        *  -  put == output == write
        *  @endif
       */
-      char_type*               _M_in_beg;      // Start of get area. 
-      char_type*               _M_in_cur;      // Current read area. 
-      char_type*               _M_in_end;      // End of get area. 
-      char_type*               _M_out_beg;     // Start of put area. 
-      char_type*               _M_out_cur;     // Current put area. 
-      char_type*               _M_out_end;     // End of put area. 
+      char_type*               _M_in_beg;     // Start of get area. 
+      char_type*               _M_in_cur;     // Current read area. 
+      char_type*               _M_in_end;     // End of get area. 
+      char_type*               _M_out_beg;    // Start of put area. 
+      char_type*               _M_out_cur;    // Current 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
       }
 
       // Correctly sets the _M_out_cur pointer, and bumps the
-      // appropriate _M_*_end pointers as well. Necessary for the
-      // un-tied stringbufs, in in|out mode.
+      // appropriate _M_out_lim and _M_in_end pointers as well. Necessary
+      // for the un-tied stringbufs, in in|out mode.
       // Invariant:
-      // __n + _M_out_[cur, end] <= _M_buf + _M_buf_size
-      // Assuming all _M_*_[beg, cur, end] pointers are operating on
+      // __n + _M_out_[cur, lim] <= _M_out_end
+      // Assuming all _M_out_[beg, cur, lim] pointers are operating on
       // the same range:
-      // _M_buf <= _M_*_ <= _M_buf + _M_buf_size
+      // _M_buf <= _M_*_ <= _M_out_end
       void 
       _M_out_cur_move(off_type __n) // argument needs to be +-
       {
@@ -320,32 +324,23 @@ namespace std
        _M_out_cur += __n;
        if (__testin && _M_buf_unified)
          _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...
            if (__testin)
              _M_in_end += __n;
          }
       }
 
-      // Return the size of the output buffer.  This depends on the
-      // buffer in use: allocated buffers have a stored size in
-      // _M_buf_size and setbuf() buffers don't.
+      // Returns zero if the output buffer is full (-> overflow).
       off_type
       _M_out_buf_size()
       {
-       off_type __ret = 0;
        if (_M_out_cur)
-         {
-           // Using allocated buffer.
-           if (_M_out_beg == _M_buf)
-             __ret = _M_out_beg + _M_buf_size - _M_out_cur;
-           // Using non-allocated buffer.
-           else
-             __ret = _M_out_end - _M_out_cur;
-         }
-       return __ret;
+         return _M_out_end - _M_out_cur;
+       else
+         return off_type(0);
       }
 
   public:
@@ -568,8 +563,8 @@ namespace std
       */
       basic_streambuf()
       : _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_out_beg(0), _M_out_cur(0), _M_out_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_lim(0),
       _M_mode(ios_base::openmode(0)), _M_buf_locale(locale()), 
       _M_pback_cur_save(0), _M_pback_end_save(0), 
       _M_pback_init(false)
@@ -666,7 +661,7 @@ namespace std
       setp(char_type* __pbeg, char_type* __pend)
       { 
        _M_out_beg = _M_out_cur = __pbeg; 
-       _M_out_end = __pend; 
+       _M_out_end = __pend;
        if (!(_M_mode & ios_base::out) && __pbeg && __pend)
          _M_mode = _M_mode | ios_base::out;
       }
index 843038aab482381e7eec4cebb137139a985dc8bd..fc9262f8e75007ac25c9464df99e39b8348cfbfb 100644 (file)
@@ -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_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_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
 {
@@ -607,14 +608,14 @@ void test10()
   {
     ofstream out;
     out.imbue(loc);
-    out.open("filebuf_virtuals-4.txt");
+    out.open(name_04);
     copy(str.begin(), str.end(),
         ostreambuf_iterator<char>(out));
   }
 
   {
     ifstream in;
-    in.open("filebuf_virtuals-4.txt");
+    in.open(name_04);
     copy(istreambuf_iterator<char>(in),
         istreambuf_iterator<char>(),
         back_inserter(tmp));
@@ -624,6 +625,62 @@ void test10()
   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() 
 {
   test01();
@@ -638,5 +695,6 @@ main()
   test08();
   test09();
   test10();
+  test11();
   return 0;
 }
index 8a6add9dfc596e0aaee70fa7c73a329d4212235b..a2a8368abfc6798f1d62defdeead6375807a87f9 100644 (file)
@@ -92,6 +92,61 @@ void test08()
   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() 
 {
   using namespace std;
@@ -106,5 +161,6 @@ int main()
   test02(in3, false);
 
   test08();
+  test09();
   return 0;
 }