This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
[PATCH] libstdc++/9169 and libstdc++/9182
- From: Pétur Runólfsson <peturr02 at ru dot is>
- To: <libstdc++ at gcc dot gnu dot org>
- Cc: <gcc-patches at gcc dot gnu dot org>
- Date: Sat, 25 Jan 2003 12:13:02 -0000
- Subject: [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;
}