fstream.tcc (_M_overflow): Rewrote to call _M_convert_to_external only once (_M_buf_s...
authorPaolo Carlini <pcarlini@unitus.it>
Thu, 15 May 2003 23:43:15 +0000 (01:43 +0200)
committerBenjamin Kosnik <bkoz@gcc.gnu.org>
Thu, 15 May 2003 23:43:15 +0000 (23:43 +0000)
2003-05-15  Paolo Carlini  <pcarlini@unitus.it>
    Nathan Myers  <ncm@cantrip.org>

* include/bits/fstream.tcc (_M_overflow): Rewrote to call
_M_convert_to_external only once (_M_buf_size is now the size of
the put area + 1 for the overflow char of a full area); call
_M_set_buffer instead of _M_set_indeterminate.
(setbuf): Don't accept a buffer smaller than 2 chars.
(_M_underflow): Refill _M_buf_size - 1 chars; call _M_set_buffer,
instead of _M_set_determinate.
(open): Call _M_set_buffer, instead of _M_set_indeterminate.
(seekoff): Likewise.
* include/ext/stdio_filebuf.h (stdio_filebuf(int,
std::ios_base::openmode, bool, size_t),
stdio_filebuf(std::__c_file*, std::ios_base::openmode, size_t):
Likewise.
* include/std/std_fstream.h (_M_set_indeterminate): Remove.
(_M_set_determinate): Rename as _M_set_buffer, _M_buf_size ->
_M_buf_size - 1.
* include/std/std_streambuf.h: Tweak _M_out_lim comment.
* testsuite/27_io/basic_filebuf/sgetn/char/1.cc: Tweak, taking
into account that, for _M_buf_size == BUFSIZ == 8192, the size of
the put area is now BUFSIZ - 1.
* testsuite/ext/stdio_filebuf_2.cc: Tweak, taking into account
that now the smallest _M_buf_size is 2 (still fails, for the same
reason, with 3.2.3)

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

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/fstream.tcc
libstdc++-v3/include/ext/stdio_filebuf.h
libstdc++-v3/include/std/std_fstream.h
libstdc++-v3/include/std/std_streambuf.h
libstdc++-v3/testsuite/27_io/basic_filebuf/sgetn/char/1.cc
libstdc++-v3/testsuite/ext/stdio_filebuf_2.cc

index d5cb45daecb1ddcc56aa0dfb6990a256af6929dc..10ad1d6e0122ee457d94212a1beeb8aa397cf483 100644 (file)
@@ -1,3 +1,30 @@
+2003-05-15  Paolo Carlini  <pcarlini@unitus.it>
+           Nathan Myers  <ncm@cantrip.org>
+
+       * include/bits/fstream.tcc (_M_overflow): Rewrote to call
+       _M_convert_to_external only once (_M_buf_size is now the size of
+       the put area + 1 for the overflow char of a full area); call
+       _M_set_buffer instead of _M_set_indeterminate.
+       (setbuf): Don't accept a buffer smaller than 2 chars.
+       (_M_underflow): Refill _M_buf_size - 1 chars; call _M_set_buffer,
+       instead of _M_set_determinate.
+       (open): Call _M_set_buffer, instead of _M_set_indeterminate.
+       (seekoff): Likewise.
+       * include/ext/stdio_filebuf.h (stdio_filebuf(int,
+       std::ios_base::openmode, bool, size_t),
+       stdio_filebuf(std::__c_file*, std::ios_base::openmode, size_t):
+       Likewise.
+       * include/std/std_fstream.h (_M_set_indeterminate): Remove.
+       (_M_set_determinate): Rename as _M_set_buffer, _M_buf_size ->
+       _M_buf_size - 1.
+       * include/std/std_streambuf.h: Tweak _M_out_lim comment.
+       * testsuite/27_io/basic_filebuf/sgetn/char/1.cc: Tweak, taking
+       into account that, for _M_buf_size == BUFSIZ == 8192, the size of
+       the put area is now BUFSIZ - 1.
+       * testsuite/ext/stdio_filebuf_2.cc: Tweak, taking into account
+       that now the smallest _M_buf_size is 2 (still fails, for the same
+       reason, with 3.2.3)
+
 2003-05-14  Loren J. Rittle  <ljrittle@acm.org>
 
        * testsuite/thread/pthread4.cc: Tweak test.
index 3397071bd84f465dcd97c57be97654735c8ae626..4fb153ff72438e13fa864e8f19e6b6dac68c3a82 100644 (file)
@@ -48,7 +48,7 @@ namespace std
     basic_filebuf<_CharT, _Traits>::
     _M_allocate_internal_buffer()
     {
-      if (!this->_M_buf && this->_M_buf_size)
+      if (!_M_buf_allocated && this->_M_buf_size)
        {
          // Allocate internal buffer.
          this->_M_buf = new char_type[this->_M_buf_size];
@@ -101,9 +101,9 @@ namespace std
              this->_M_mode = __mode;
 
              // Setup initial position of buffer.
-             _M_set_indeterminate();
+             _M_set_buffer(0);
 
-             if ((__mode & ios_base::ate)
+             if ((__mode & ios_base::ate) 
                  && this->seekoff(0, ios_base::end, __mode) < 0)
                // 27.8.1.3,4
                this->close();
@@ -218,27 +218,28 @@ namespace std
                                ios_base::in);
            }
 
-         if (_M_buf_size)
+         if (_M_buf_size > 1)
            {
              streamsize __elen = 0;
              streamsize __ilen = 0;
 
              if (__check_facet(_M_codecvt).always_noconv())
                {
-                 __elen = _M_file.xsgetn(reinterpret_cast<char*>(this->_M_in_beg), _M_buf_size);
+                 __elen = _M_file.xsgetn(reinterpret_cast<char*>(this->_M_in_beg), _M_buf_size - 1);
                  __ilen = __elen;
                }
              else
                {
-                 char* __buf = static_cast<char*>(__builtin_alloca(_M_buf_size));
-                 __elen = _M_file.xsgetn(__buf, _M_buf_size);
+                 char* __buf = static_cast<char*>(__builtin_alloca(_M_buf_size - 1));
+                 __elen = _M_file.xsgetn(__buf, _M_buf_size - 1);
                  
                  const char* __eend;
                  char_type* __iend;
                  codecvt_base::result __r;
                  __r = _M_codecvt->in(_M_state_cur, __buf, __buf + __elen, 
                                       __eend, this->_M_in_beg, 
-                                      this->_M_in_beg + _M_buf_size, __iend);
+                                      this->_M_in_beg + _M_buf_size - 1, 
+                                      __iend);
                  if (__r == codecvt_base::ok)
                    __ilen = __iend - this->_M_in_beg;
                  else if (__r == codecvt_base::noconv)
@@ -258,7 +259,7 @@ namespace std
 
              if (0 < __ilen)
                {
-                 _M_set_determinate(__ilen);
+                 _M_set_buffer(__ilen);
                  __ret = traits_type::to_int_type(*this->_M_in_cur);
                  if (__bump)
                    _M_move_in_cur(1);
@@ -338,41 +339,30 @@ namespace std
     _M_overflow(int_type __c)
     {
       int_type __ret = traits_type::eof();
+      const bool __testeof = traits_type::eq_int_type(__c, __ret);
       const bool __testput = this->_M_out_beg < this->_M_out_lim;
 
       if (__testput)
-       {
-         // Need to restore current position. The position of the external
-         // byte sequence (_M_file) corresponds to _M_filepos, and we need
-         // to move it to _M_out_beg for the write.
-         if (_M_filepos && _M_filepos != this->_M_out_beg)
-           {
-             off_type __off = this->_M_out_beg - _M_filepos;
-             _M_file.seekoff(__off, ios_base::cur);
-           }
-
-         // Convert internal buffer to external representation, output.
-         if (_M_convert_to_external(this->_M_out_beg, 
-                                    this->_M_out_lim - this->_M_out_beg))
+       {
+         // Need to restore current position. The position of the
+         // external byte sequence (_M_file) corresponds to
+         // _M_filepos, and we need to move it to _M_out_beg for the
+         // write.
+         if (_M_filepos != this->_M_out_beg)
+           _M_file.seekoff(this->_M_out_beg - _M_filepos, ios_base::cur);
+
+         // If appropriate, append the overflow char.
+         if (!__testeof)
+           *this->_M_out_lim++ = traits_type::to_char_type(__c);
+
+         // Convert pending sequence to external representation,
+         // output. 
+         if (_M_convert_to_external(this->_M_out_beg,
+                                    this->_M_out_lim - this->_M_out_beg)
+             && (!__testeof || (__testeof && !_M_file.sync())))
            {
-             // Convert pending sequence to external representation, output.
-             // If eof, then just attempt sync.
-             if (!traits_type::eq_int_type(__c, traits_type::eof()))
-               {
-                 // User code must flush when switching modes (thus
-                 // don't sync).
-                 char_type __pending = traits_type::to_char_type(__c);
-                 if (_M_convert_to_external(&__pending, 1))
-                   {
-                     _M_set_indeterminate();
-                     __ret = traits_type::not_eof(__c);
-                   }
-               }
-             else if (!_M_file.sync())
-               {
-                 _M_set_indeterminate();
-                 __ret = traits_type::not_eof(__c);
-               }
+             _M_set_buffer(0);
+             __ret = traits_type::not_eof(__c);
            }
        }
       _M_last_overflowed = true;       
@@ -388,20 +378,22 @@ namespace std
       const bool __testput = this->_M_out_cur < this->_M_out_end;
       const bool __testout = this->_M_mode & ios_base::out;
       
+      // Perhaps set below in _M_overflow.
+      _M_last_overflowed = false;
+
       if (__testout)
        {
          if (traits_type::eq_int_type(__c, traits_type::eof()))
            __ret = traits_type::not_eof(__c);
          else if (__testput)
            {
-             *this->_M_out_cur = traits_type::to_char_type(__c);
+             *this->_M_out_cur = traits_type::to_char_type(__c);
              _M_move_out_cur(1);
              __ret = traits_type::not_eof(__c);
            }
          else 
            __ret = this->_M_overflow(__c);
        }
-      _M_last_overflowed = false;    // Set in _M_overflow, below.
       return __ret;
     }
   
@@ -479,12 +471,15 @@ namespace std
     {
       if (!this->is_open() && __s == 0 && __n == 0)
        this->_M_buf_size = 0;
-      else if (__s && __n)
+      else if (__s && __n > 1)
        {
-         // This is implementation-defined behavior, and assumes
-         // 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.
+         // This is implementation-defined behavior, and assumes 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. The length argument __n must
+         // be greater than 1 because __n - 1 positions will be used
+         // for the get and put areas, and 1 position is needed to
+         // host the overflow char of a full put area.
 
          // Step 1: Destroy the current internal array.
          _M_destroy_internal_buffer();
@@ -492,7 +487,7 @@ namespace std
          // Step 2: Use the external array.
          this->_M_buf = __s;
          this->_M_buf_size = __n;
-         _M_set_indeterminate();
+         _M_set_buffer(0);
        }
       _M_last_overflowed = false;      
       return this; 
@@ -539,7 +534,7 @@ namespace std
 
              // Return pos_type(off_type(-1)) in case of failure.
              __ret = _M_file.seekoff(__computed_off, __way, __mode);
-             _M_set_indeterminate();
+             _M_set_buffer(0);
            }
          else
            {
index 4d3c9d07eeec85140672a5782e67475dcdf4c2c4..3f7cd1c69f5b1bf17af5d5165b924eead25e7d7f 100644 (file)
@@ -67,19 +67,23 @@ namespace __gnu_cxx
        *  @param  mode  Same meaning as in a standard filebuf.
        *  @param  del  Whether to close the file on destruction.
        *  @param  size  Optimal or preferred size of internal buffer, in bytes.
+       *                Note that it includes a position for the overflow char,
+       *                therefore, can't be smaller than 2.
        *
        *  This constructor associates a file stream buffer with an open
        *  POSIX file descriptor.  Iff @a del is true, then the associated
        *  file will be closed when the stdio_filebuf is closed/destroyed.
       */
       stdio_filebuf(int __fd, std::ios_base::openmode __mode, bool __del, 
-                   size_t __size);
+                   size_t __size = static_cast<size_t>(BUFSIZ));
 
       /**
        *  @param  f  An open @c FILE*.
        *  @param  mode  Same meaning as in a standard filebuf.
        *  @param  size  Optimal or preferred size of internal buffer, in bytes.
-       *                Defaults to system's @c BUFSIZ.
+       *                Defaults to system's @c BUFSIZ. Note that it includes
+       *                a position for the overflow char, therefore, can't be
+       *                smaller than 2.
        *
        *  This constructor associates a file stream buffer with an open
        *  C @c FILE*.  The @c FILE* will not be automatically closed when the
@@ -123,7 +127,7 @@ namespace __gnu_cxx
          this->_M_mode = __mode;
          this->_M_buf_size = __size;
          _M_allocate_internal_buffer();
-         _M_set_indeterminate();
+         _M_set_buffer(0);
        }
     }
 
@@ -138,7 +142,7 @@ namespace __gnu_cxx
          this->_M_mode = __mode;
          this->_M_buf_size = __size;
          _M_allocate_internal_buffer();
-         _M_set_indeterminate();
+         _M_set_buffer(0);
        }
     }
 } // namespace __gnu_cxx
index 2ff4ec15d103c323497a33daa7639d3516397579..e99d8103286f735d0656cf2668dd178b1197800b 100644 (file)
@@ -123,7 +123,9 @@ namespace std
 
       /**
        *  @if maint
-       *  Actual size of internal buffer.
+       *  Actual size of internal buffer. This number is equal to the size
+       *  of the put area + 1 position, reserved for the overflow char of
+       *  a full area.
        *  @endif
       */
       size_t                   _M_buf_size;
@@ -452,41 +454,30 @@ namespace std
       void
       _M_output_unshift();
 
-      // These two functions are used to clarify internal buffer
-      // maintenance. After an overflow, or after a seekoff call that
-      // started at beg or end, or possibly when the stream becomes
-      // unbuffered, and a myrid other obscure corner cases, the
-      // internal buffer does not truly reflect the contents of the
-      // external buffer. At this point, for whatever reason, it is in
-      // an indeterminate state.
-      /**
-       *  @if maint
-       *  @doctodo
-       *  @endif
-      */
-      void
-      _M_set_indeterminate(void)
-      { _M_set_determinate(off_type(0)); }
-
-      /**
-       *  @if maint
-       *  @doctodo
-       *  @endif
-      */
-      void
-      _M_set_determinate(off_type __off)
-      {
-       const bool __testin = this->_M_mode & ios_base::in;
-       const bool __testout = this->_M_mode & ios_base::out;
-       if (__testin)
-         this->setg(this->_M_buf, this->_M_buf, this->_M_buf + __off);
-       if (__testout)
+       // This function sets the pointers of the internal buffer, both get
+       // and put areas. Typically, __off == _M_in_end - _M_in_beg upon
+       // _M_underflow; __off == 0 upon _M_overflow, seekoff, open, setbuf.
+       // 
+       // NB: _M_out_end - _M_out_beg == _M_buf_size - 1, since _M_buf_size
+       // reflects the actual allocated memory and the last cell is reserved
+       // for the overflow char of a full put area.
+       void
+       _M_set_buffer(streamsize __off)
+       {
+       const bool __testin = this->_M_mode & ios_base::in;
+       const bool __testout = this->_M_mode & ios_base::out;
+       if (_M_buf_size)
          {
-           this->setp(this->_M_buf, this->_M_buf + this->_M_buf_size);
-           this->_M_out_lim += __off;
+           if (__testin)
+             this->setg(this->_M_buf, this->_M_buf, this->_M_buf + __off);
+           if (__testout)
+             {
+               this->setp(this->_M_buf, this->_M_buf + this->_M_buf_size - 1);
+               this->_M_out_lim += __off;
+             }
+           _M_filepos = this->_M_buf + __off;
          }
-       _M_filepos = this->_M_buf + __off;
-      }
+       }
     };
 
   // [27.8.1.5] Template class basic_ifstream
index e258501c18b6e4521d8b5d64a864040062ff7805..38aa6075f03dd133315674f1a9d11bc80a49d90d 100644 (file)
@@ -187,9 +187,9 @@ namespace std
       //@{
       /**
        *  @if maint
-       *  _M_set_indeterminate and setp set it equal to _M_out_beg, then
-       *  at each put operation it may be moved forward (toward _M_out_end)
-       *  by _M_out_cur_move.
+       *  setp (and _M_set_buffer(0) in basic_filebuf) set it equal to
+       *  _M_out_beg, then at each put operation it may be moved
+       *  forward (toward _M_out_end) by _M_out_cur_move.
        *  @endif
       */      
       char_type*                _M_out_lim;    // End limit of used put area.
index 05fbd23a573874c47203333b8b005cee5abd6999..d890f3e7dcf01dc247df34d81c1653862539e783 100644 (file)
@@ -123,11 +123,11 @@ void test05()
   VERIFY( c7 == c2 ); // n != i
   strmsz_1 = fb_03.sgetn(carray1, 10);
   VERIFY( !strmsz_1 ); //zero
-  strmsz_1 = fb_01.in_avail();
+  strmsz_1 = fb_01.in_avail(); // N.B.: _M_in_end - _M_in_beg == BUFSIZ - 1
   strmsz_2 = fb_01.sgetn(carray2, strmsz_1 + 5);
   VERIFY( strmsz_1 == strmsz_2 - 5 ); 
   c4 = fb_01.sgetc(); // buffer should have underflowed from above.
-  VERIFY( c4 == 'i' );
+  VERIFY( c4 == 'h' );
   strmsz_1 = fb_01.in_avail();
   VERIFY( strmsz_1 > 0 );
   strmsz_2 = fb_01.sgetn(carray2, strmsz_1 + 5);
index b4b30c65c93ab727ae8f6240235c9c9050e1db83..a46f2399b4274cb63368578d190d9f948224195c 100644 (file)
@@ -29,7 +29,6 @@
 // out by _M_really_overflow upon overflow.
 void test01()
 {
-  
   using namespace std;
   bool test = true;
 
@@ -37,11 +36,10 @@ void test01()
   FILE* file = fopen(name, "w");
   {
     using namespace __gnu_cxx;
-    
-    // One char big stack-based buffer.
-    stdio_filebuf<char> sbuf(file, ios_base::out, 1); 
+    stdio_filebuf<char> sbuf(file, ios_base::out, 2); 
     sbuf.sputc('T');
     sbuf.sputc('S');
+    sbuf.sputc('P');
   }
   fclose(file);
 
@@ -51,8 +49,8 @@ void test01()
   streamsize n = fbuf.sgetn(buf, sizeof(buf)); 
   fbuf.close();
   
-  VERIFY( n == 2 );
-  VERIFY( !memcmp(buf, "TS", 2) );
+  VERIFY( n == 3 );
+  VERIFY( !memcmp(buf, "TSP", 3) );
 }
 
 int main()