This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] libstdc++/9169 and libstdc++/9182


Hi,

This patch fixes basic_filebuf<>::_M_convert_to_external so that
return values of noconv and error from codecvt<>::out are handled
correctly.

The added function _M_write_to_file(char* buf, streamsize len)
just calls _M_file.xsputn(buf, len) if len > 0. I noticed this
check was being done everytime xsputn was called so I factored
it out into a separate function.

The testsuite function test09 reads the file itself to check if
it was written correctly. It seems that the contents of the files
filebuf_virtuals-*.txt are never checked against
filebuf_virtuals-*.tst so this seems to be the easiest way to
check output.

Tested on linux on x86.

Regards,
Petur


2003-01-25  Petur Runolfsson  <peturr02@ru.is>

	PR libstdc++/9169
	PR libstdc++/9182
	* include/std/std_fstream.h
	(basic_filebuf):  Add _M_write_to_file, change signature of
	_M_convert_to_external.
	(basic_filebuf::sync):  Fail if _M_really_overflow fails.
	* include/bits/fstream.tcc
	(basic_filebuf::_M_write_to_file):  Add.
	(basic_filebuf::_M_convert_to_external):  Fail if codecvt::out
	returns error, write output if codecvt::out returns noconv.
	(basic_filebuf::_M_really_overflow):
	Fail if _M_convert_to_external fails.
	* gcc-20030120/libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc
	(noconv_codecvt, error_codecvt, test09, test10, test11):  Add.

diff -c3pr ../tmp/gcc-20030120-patched/libstdc++-v3/include/bits/fstream.tcc gcc-20030120/libstdc++-v3/include/bits/fstream.tcc
*** ../tmp/gcc-20030120-patched/libstdc++-v3/include/bits/fstream.tcc	2003-01-23 22:01:06.000000000 +0000
--- gcc-20030120/libstdc++-v3/include/bits/fstream.tcc	2003-01-24 22:10:41.000000000 +0000
*************** namespace std
*** 255,273 ****
      }
    
    template<typename _CharT, typename _Traits>
!     void
      basic_filebuf<_CharT, _Traits>::
!     _M_convert_to_external(_CharT* __ibuf, streamsize __ilen,
! 			   streamsize& __elen, streamsize& __plen)
      {
        const locale __loc = this->getloc();
        const __codecvt_type& __cvt = use_facet<__codecvt_type>(__loc);
        
!       if (__cvt.always_noconv() && __ilen)
! 	{
! 	  __elen += _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
! 	  __plen += __ilen;
! 	}
        else
  	{
  	  // Worst-case number of external bytes needed.
--- 255,283 ----
      }
    
    template<typename _CharT, typename _Traits>
!     bool
!     basic_filebuf<_CharT, _Traits>::
!     _M_write_to_file(char* __ibuf, streamsize __ilen)
!     {
!       streamsize __elen = 0;
!       if (__ilen)
! 	__elen = _M_file.xsputn(__ibuf, __ilen);
!       return __elen == __ilen;
!     }
! 
!   template<typename _CharT, typename _Traits>
!     bool
      basic_filebuf<_CharT, _Traits>::
!     _M_convert_to_external(_CharT* __ibuf, streamsize __ilen)
      {
+       bool __success = true;
+       streamsize __elen = 0;
+ 
        const locale __loc = this->getloc();
        const __codecvt_type& __cvt = use_facet<__codecvt_type>(__loc);
        
!       if (__cvt.always_noconv())
! 	__success = _M_write_to_file(reinterpret_cast<char*>(__ibuf), __ilen);
        else
  	{
  	  // Worst-case number of external bytes needed.
*************** namespace std
*** 276,316 ****
  	    __ext_multiplier = sizeof(char_type);
  	  streamsize __blen = __ilen * __ext_multiplier;
  	  char* __buf = static_cast<char*>(__builtin_alloca(__blen));
- 	  char* __bend;
- 	  const char_type* __iend;
- 	  __res_type __r = __cvt.out(_M_state_cur, __ibuf, __ibuf + __ilen, 
- 		 		     __iend, __buf, __buf + __blen, __bend);
- 	  // Result == ok, partial, noconv
- 	  if (__r != codecvt_base::error)
- 	    __blen = __bend - __buf;
- 	  // Result == error
- 	  else 
- 	    __blen = 0;
- 	  
- 	  if (__blen)
- 	    {
- 	      __elen += _M_file.xsputn(__buf, __blen);
- 	      __plen += __blen;
- 	    }
  
! 	  // Try once more for partial conversions.
! 	  if (__r == codecvt_base::partial)
  	    {
! 	      const char_type* __iresume = __iend;
! 	      streamsize __rlen = _M_out_end - __iend;
! 	      __r = __cvt.out(_M_state_cur, __iresume, __iresume + __rlen, 
! 			      __iend, __buf, __buf + __blen, __bend);
! 	      if (__r != codecvt_base::error)
! 		__rlen = __bend - __buf;
! 	      else 
! 		__rlen = 0;
! 	      if (__rlen)
  		{
! 		  __elen += _M_file.xsputn(__buf, __rlen);
! 		  __plen += __rlen;
  		}
  	    }
  	}
      }
  
    template<typename _CharT, typename _Traits>
--- 286,333 ----
  	    __ext_multiplier = sizeof(char_type);
  	  streamsize __blen = __ilen * __ext_multiplier;
  	  char* __buf = static_cast<char*>(__builtin_alloca(__blen));
  
! 	  int __retry = 2;
! 	  __res_type __r = codecvt_base::error;
! 	  char_type* __ibeg = __ibuf;
! 	  const char_type* __iend = __ibuf + __ilen;
! 
! 	  do
  	    {
! 	      char* __bnext;
! 	      const char_type* __inext;
! 	      __r = __cvt.out(_M_state_cur, __ibeg, __iend, __inext,
! 			      __buf, __buf + __blen, __bnext);
! 
! 	      if (__r == codecvt_base::error)
! 		{
! 		  __success = false;
! 		  __retry = 0;
! 		}
! 	      else if (__r == codecvt_base::noconv)
! 		{
! 		  // According to DR19, codecvt::out returns noconv only if
! 		  // intern_type and and extern_type are the same type, in
! 		  // this case if char_type is char. This cast is therefore
! 		  // safe.
! 		  __success = _M_write_to_file(reinterpret_cast<char*>(__ibeg),
! 					       __iend - __ibeg);
! 		  __retry = 0;
! 		}
! 	      else
  		{
! 		  __success = _M_write_to_file(__buf, __bnext - __buf);
! 		  __retry--;
! 
! 		  if (__r == codecvt_base::partial && __success && __retry)
! 		    __ibeg += (__inext - __ibeg);
! 		  else
! 		    __retry = 0;
  		}
  	    }
+ 	  while (__retry);
  	}
+       return __success;
      }
  
    template<typename _CharT, typename _Traits>
*************** namespace std
*** 324,332 ****
  
        if (__testput || __testunbuffered)
  	{
! 	  // Sizes of external and pending output.
! 	  streamsize __elen = 0;
! 	  streamsize __plen = 0;
  
  	  // Need to restore current position. The position of the external
  	  // byte sequence (_M_file) corresponds to _M_filepos, and we need
--- 341,347 ----
  
        if (__testput || __testunbuffered)
  	{
! 	  bool __success = true;
  
  	  // Need to restore current position. The position of the external
  	  // byte sequence (_M_file) corresponds to _M_filepos, and we need
*************** namespace std
*** 340,367 ****
  	  // Convert internal buffer to external representation, output.
  	  // NB: In the unbuffered case, no internal buffer exists. 
  	  if (!__testunbuffered)
! 	    _M_convert_to_external(_M_out_beg,  _M_out_end - _M_out_beg, 
! 				   __elen, __plen);
  
! 	  // Convert pending sequence to external representation, output.
! 	  // If eof, then just attempt sync.
! 	  if (!traits_type::eq_int_type(__c, traits_type::eof()))
  	    {
! 	      char_type __pending = traits_type::to_char_type(__c);
! 	      _M_convert_to_external(&__pending, 1, __elen, __plen);
  
! 	      // User code must flush when switching modes (thus don't sync).
! 	      if (__elen == __plen)
  		{
  		  _M_set_indeterminate();
  		  __ret = traits_type::not_eof(__c);
  		}
  	    }
- 	  else if (!_M_file.sync())
- 	    {
- 	      _M_set_indeterminate();
- 	      __ret = traits_type::not_eof(__c);
- 	    }
  	}	      
        _M_last_overflowed = true;	
        return __ret;
--- 355,386 ----
  	  // Convert internal buffer to external representation, output.
  	  // NB: In the unbuffered case, no internal buffer exists. 
  	  if (!__testunbuffered)
! 	    __success = _M_convert_to_external(_M_out_beg,
! 					       _M_out_end - _M_out_beg);
  
! 	  if (__success)
  	    {
! 	      // Convert pending sequence to external representation, output.
! 	      // If eof, then just attempt sync.
! 	      if (!traits_type::eq_int_type(__c, traits_type::eof()))
! 		{
! 		  char_type __pending = traits_type::to_char_type(__c);
! 		  __success = _M_convert_to_external(&__pending, 1);
  
! 		  // User code must flush when switching modes
! 		  // (thus don't sync).
! 		  if (__success)
! 		    {
! 		      _M_set_indeterminate();
! 		      __ret = traits_type::not_eof(__c);
! 		    }
! 		}
! 	      else if (!_M_file.sync())
  		{
  		  _M_set_indeterminate();
  		  __ret = traits_type::not_eof(__c);
  		}
  	    }
  	}	      
        _M_last_overflowed = true;	
        return __ret;
diff -c3pr ../tmp/gcc-20030120-patched/libstdc++-v3/include/std/std_fstream.h gcc-20030120/libstdc++-v3/include/std/std_fstream.h
*** ../tmp/gcc-20030120-patched/libstdc++-v3/include/std/std_fstream.h	2003-01-14 19:30:28.000000000 +0000
--- gcc-20030120/libstdc++-v3/include/std/std_fstream.h	2003-01-24 23:12:44.000000000 +0000
*************** namespace std
*** 279,286 ****
         *  @doctodo
         *  @endif
        */
!       void
!       _M_convert_to_external(char_type*, streamsize, streamsize&, streamsize&);
  
        /**
         *  @brief  Manipulates the buffer.
--- 279,295 ----
         *  @doctodo
         *  @endif
        */
!       bool
!       _M_convert_to_external(char_type*, streamsize);
! 
!       // Write char-based sequence to file
!       /**
!        *  @if maint
!        *  @doctodo
!        *  @endif
!       */
!       bool
!       _M_write_to_file(char*, streamsize);
  
        /**
         *  @brief  Manipulates the buffer.
*************** namespace std
*** 311,316 ****
--- 320,326 ----
        virtual int
        sync()
        {
+ 	int __ret = 0;
  	bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
  
  	// Make sure that the internal buffer resyncs its idea of
*************** namespace std
*** 319,332 ****
  	  {
  	    // Need to restore current position after the write.
  	    off_type __off = _M_out_cur - _M_out_end;
! 	    _M_really_overflow(); // _M_file.sync() will be called within
! 	    if (__off)
  	      _M_file.seekoff(__off, ios_base::cur);
  	  }
  	else
  	  _M_file.sync();
  	_M_last_overflowed = false;
! 	return 0;
        }
  
        // [documentation is inherited]
--- 329,345 ----
  	  {
  	    // Need to restore current position after the write.
  	    off_type __off = _M_out_cur - _M_out_end;
! 	    // _M_file.sync() will be called within
! 	    int_type __result = _M_really_overflow();
! 	    if (traits_type::eq_int_type(__result, traits_type::eof()))
! 	      __ret = -1; 
! 	    else if (__off)
  	      _M_file.seekoff(__off, ios_base::cur);
  	  }
  	else
  	  _M_file.sync();
  	_M_last_overflowed = false;
! 	return __ret;
        }
  
        // [documentation is inherited]
diff -c3pr ../tmp/gcc-20030120-patched/libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc gcc-20030120/libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc
*** ../tmp/gcc-20030120-patched/libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc	2003-01-23 22:01:06.000000000 +0000
--- gcc-20030120/libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc	2003-01-24 23:24:19.000000000 +0000
***************
*** 22,27 ****
--- 22,28 ----
  
  #include <fstream>
  #include <locale>
+ #include <cwchar>
  #include <testsuite_hooks.h>
  
  // @require@ %-*.tst %-*.txt
*************** void test08()
*** 537,542 ****
--- 538,656 ----
    VERIFY( ob.getloc() == loc_de );
  }
  
+ class noconv_codecvt : public std::codecvt<char, char, std::mbstate_t>
+ {
+   bool do_always_noconv() const throw()
+   {
+     return false;
+   }
+ };
+ 
+ // libstdc++/9169
+ void test09()
+ {
+   using namespace std;
+   bool test = true;
+ 
+   const char* name = "tmp";
+ 
+   locale loc;
+   loc = locale(loc, new noconv_codecvt);
+   
+   filebuf fb_out;
+   fb_out.pubimbue(loc);
+   fb_out.open(name, ios_base::out | ios_base::trunc);
+ 
+   const char* strlit = "Underworld: Born Slippy\n";
+   streamsize sz = strlen(strlit);
+ 
+   streamsize ret = fb_out.sputn(strlit, sz);
+   VERIFY( ret == sz );
+ 
+   int ps = fb_out.pubsync();
+   VERIFY( ps == 0 );
+ 
+   fb_out.close();
+ 
+   filebuf fb_in;
+   fb_in.open(name, ios_base::in);
+ 
+   char buf[256];
+   ret = fb_in.sgetn(buf, sizeof(buf));
+   VERIFY( ret == sz );
+   VERIFY( !memcmp(buf, strlit, sz) );
+   fb_in.close();
+ }
+ 
+ class error_codecvt : public std::codecvt<char, char, std::mbstate_t>
+ {
+   result
+   do_out(state_type&, const intern_type* from, const intern_type*,
+ 	 const intern_type*& from_next, extern_type* to, extern_type*,
+ 	 extern_type*& to_next) const
+   {
+     from_next = from;
+     to_next = to;
+     return error;
+   }
+ 
+   bool do_always_noconv() const throw()
+   {
+     return false;
+   }
+ };
+ 
+ // libstdc++/9182
+ void test10()
+ {
+   using namespace std;
+   bool test = true;
+ 
+   const char* name = "tmp";
+ 
+   locale loc;
+   loc = locale(loc, new error_codecvt);
+ 
+   filebuf fb_out;
+   fb_out.pubimbue(loc);
+   fb_out.open(name, ios_base::out | ios_base::trunc);
+ 
+   const char* strlit = "Bedrock featuring KYO: For What You Dream Of\n";
+   streamsize sz = strlen(strlit);
+ 
+   streamsize ret = fb_out.sputn(strlit, sz);
+   VERIFY( ret == sz );
+   int ps = fb_out.pubsync();
+   VERIFY( ps == -1 );
+ 
+   fb_out.close();
+ }
+ 
+ // libstdc++/9182
+ void test11()
+ {
+   using namespace std;
+   bool test = true;
+ 
+   const char* name = "tmp";
+ 
+   locale loc;
+   loc = locale(loc, new error_codecvt);
+ 
+   filebuf fb_out;
+   fb_out.pubimbue(loc);
+   fb_out.pubsetbuf(0, 0);
+   fb_out.open(name, ios_base::out | ios_base::trunc);
+ 
+   const char* strlit = "Iggy Pop: Lust For Life\n";
+   streamsize sz = strlen(strlit);
+ 
+   streamsize ret = fb_out.sputn(strlit, sz);
+   VERIFY( ret == 0 );
+ 
+   fb_out.close();
+ }
+ 
  int main() 
  {
    test01();
*************** int main() 
*** 548,552 ****
--- 662,670 ----
    test06();
  
    test08();
+   test09();
+   test10();
+   test11();
+ 
    return 0;
  }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]