+2002-02-07 Benjamin Kosnik <bkoz@redhat.com>
+
+ libstdc++/5286
+ libstdc++/3860
+ * include/std/std_fstream.h (filebuf::__file_type): Change to
+ __basic_file<char>.
+ (filebuf::_M_convert_to_external): Declare.
+ * include/bits/fstream.tcc (filebuf::_M_convert_to_external): Define
+ codecvt bits for wide streams.
+ (filebuf::_M_really_overflow): Use it.
+ (filebuf::underflow): Use codecvt.
+ * config/locale/codecvt_specializations_ieee_1003.1-200x.h:
+ (codecvt<__enc_traits>::do_out): Deal with partial.
+ (codecvt<__enc_traits>::do_encoding): Return something useful.
+ * src/codecvt.cc (codecvt<wchar_t>::do_encoding): Return sizeof
+ wchar_t.
+ * testsuite/22_locale/codecvt_members_unicode_char.cc (test01):
+ Change expected encoding output.
+ (test02): Same.
+ * testsuite/22_locale/codecvt_members_wchar_t_char.cc (test01): Same.
+ (test02): Same.
+
2002-02-07 Benjamin Kosnik <bkoz@redhat.com>
Wolfgang Bangerth <wolfgang.bangerth@iwr.uni-heidelberg.de>
// This adaptor works around the signature problems of the second
// argument to iconv(): SUSv2 and others use 'const char**', but glibc 2.2
- // uses 'char**', which is what the standard is (apparently) due to use
- // in the future. Using this adaptor, g++ will do the work for us.
+ // uses 'char**', which matches the POSIX 1003.1-2001 standard.
+ // Using this adaptor, g++ will do the work for us.
template<typename _T>
inline size_t
- __iconv_adaptor(size_t(*iconv_func)(iconv_t, _T, size_t*, char**, size_t*),
- iconv_t cd, char** inbuf, size_t* inbytesleft,
- char** outbuf, size_t* outbytesleft)
- { return iconv_func(cd, (_T)inbuf, inbytesleft, outbuf, outbytesleft); }
+ __iconv_adaptor(size_t(*__func)(iconv_t, _T, size_t*, char**, size_t*),
+ iconv_t __cd, char** __inbuf, size_t* __inbytes,
+ char** __outbuf, size_t* __outbytes)
+ { return __func(__cd, (_T)__inbuf, __inbytes, __outbuf, __outbytes); }
template<typename _InternT, typename _ExternT>
codecvt_base::result
typedef state_type::__desc_type __desc_type;
const __desc_type* __desc = __state._M_get_out_descriptor();
const size_t __fmultiple = sizeof(intern_type) / sizeof(char);
- size_t __flen = __fmultiple * (__from_end - __from);
+ size_t __fbytes = __fmultiple * (__from_end - __from);
const size_t __tmultiple = sizeof(extern_type) / sizeof(char);
- size_t __tlen = __tmultiple * (__to_end - __to);
+ size_t __tbytes = __tmultiple * (__to_end - __to);
// Argument list for iconv specifies a byte sequence. Thus,
// all to/from arrays must be brutally casted to char*.
char_traits<intern_type>::copy(__cfixed + 1, __from, __size);
__cfrom = reinterpret_cast<char*>(__cfixed);
__conv = __iconv_adaptor(iconv, *__desc, &__cfrom,
- &__flen, &__cto, &__tlen);
+ &__fbytes, &__cto, &__tbytes);
}
else
{
intern_type* __cfixed = const_cast<intern_type*>(__from);
__cfrom = reinterpret_cast<char*>(__cfixed);
- __conv = __iconv_adaptor(iconv, *__desc, &__cfrom,
- &__flen, &__cto, &__tlen);
+ __conv = __iconv_adaptor(iconv, *__desc, &__cfrom, &__fbytes,
+ &__cto, &__tbytes);
}
if (__conv != size_t(-1))
}
else
{
- if (__flen < static_cast<size_t>(__from_end - __from))
+ if (__fbytes < __fmultiple * (__from_end - __from))
{
__from_next = reinterpret_cast<const intern_type*>(__cfrom);
__to_next = reinterpret_cast<extern_type*>(__cto);
int
codecvt<_InternT, _ExternT, __enc_traits>::
do_encoding() const throw()
- { return 0; }
+ {
+ int __ret = 0;
+ if (sizeof(_ExternT) <= sizeof(_InternT))
+ __ret = sizeof(_InternT)/sizeof(_ExternT);
+ return __ret;
+ }
template<typename _InternT, typename _ExternT>
bool
bool __testin = _M_mode & ios_base::in;
bool __testout = _M_mode & ios_base::out;
- // XXX Should re-enable codecvt bits disabled after 2.90.8.
if (__testin)
{
// Check for pback madness, and if so swich back to the
return traits_type::to_int_type(*_M_in_cur);
}
- bool __testget = _M_in_cur && _M_in_beg < _M_in_cur;
- bool __testinit = _M_is_indeterminate();
// Sync internal and external buffers.
// NB: __testget -> __testput as _M_buf_unified here.
+ bool __testget = _M_in_cur && _M_in_beg < _M_in_cur;
+ bool __testinit = _M_is_indeterminate();
if (__testget)
{
if (__testout)
if (__testinit || __testget)
{
- // Assume buffered case, need to refill internal buffers.
- streamsize __size = _M_file->xsgetn(_M_in_beg, _M_buf_size);
- if (0 < __size)
+ typedef codecvt<char_type, char, __state_type> __codecvt_type;
+ const locale __loc = this->getloc();
+ const __codecvt_type& __cvt = use_facet<__codecvt_type>(__loc);
+
+ streamsize __elen = 0;
+ streamsize __ilen = 0;
+ if (__cvt.always_noconv())
+ {
+ __elen = _M_file->xsgetn(reinterpret_cast<char*>(_M_in_beg),
+ _M_buf_size);
+ __ilen = __elen;
+ }
+ else
{
- _M_set_determinate(__size);
+ char* __buf = static_cast<char*>(__builtin_alloca(_M_buf_size));
+ __elen = _M_file->xsgetn(__buf, _M_buf_size);
+
+ const char* __eend;
+ char_type* __iend;
+ __res_type __r = __cvt.in(_M_state_cur, __buf,
+ __buf + __elen, __eend, _M_in_beg,
+ _M_in_beg + _M_buf_size, __iend);
+ if (__r == codecvt_base::ok)
+ __ilen = __iend - _M_in_beg;
+ else
+ {
+ // Unwind.
+ __ilen = 0;
+ _M_file->seekoff(-__elen, ios_base::cur, ios_base::in);
+ }
+ }
+
+ if (0 < __ilen)
+ {
+ _M_set_determinate(__ilen);
if (__testout)
_M_out_cur = _M_in_cur;
__ret = traits_type::to_int_type(*_M_in_cur);
#if _GLIBCPP_AVOID_FSEEK
- if (__size == 1)
+ if (__elen == 1)
_M_file->sys_ungetc(*_M_in_cur);
else
{
#endif
- streamoff __p = _M_file->seekoff(0 - __size, ios_base::cur,
- ios_base::in);
- if (__p == -1)
- {
- // XXX Something is wrong, do error checking.
- }
+ _M_file->seekoff(-__elen, ios_base::cur, ios_base::in);
#if _GLIBCPP_AVOID_FSEEK
}
#endif
return __ret;
}
+ template<typename _CharT, typename _Traits>
+ void
+ basic_filebuf<_CharT, _Traits>::
+ _M_convert_to_external(_CharT* __ibuf, streamsize __ilen,
+ streamsize& __elen, streamsize& __plen)
+ {
+ typedef codecvt<char_type, char, __state_type> __codecvt_type;
+ 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.
+ int __ext_multiplier = __cvt.encoding();
+ if (__ext_multiplier == -1 || __ext_multiplier == 0)
+ __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>
typename basic_filebuf<_CharT, _Traits>::int_type
basic_filebuf<_CharT, _Traits>::
if (__testput || __testunbuffered)
{
-#if 1
- int __plen = _M_out_end - _M_out_beg;
- streamsize __len = 0;
-
- if (__plen)
- __len = _M_file->xsputn(_M_out_beg, __plen);
-
- if (__c != traits_type::eof())
+ // Sizes of external and pending output.
+ streamsize __elen = 0;
+ streamsize __plen = 0;
+
+ // 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 (!traits_type::eq_int_type(__c, traits_type::eof()))
{
- char_type __pending = traits_type::to_char_type(__c);
- __len += _M_file->xsputn(&__pending, 1);
- ++__plen;
+ char_type __pending = traits_type::to_char_type(__c);
+ _M_convert_to_external(&__pending, 1, __elen, __plen);
}
+ // Last, sync internal and external buffers.
// NB: Need this so that external byte sequence reflects
- // internal buffer.
- if (__len == __plen && !_M_file->sync())
+ // internal buffer plus pending sequence.
+ if (__elen == __plen && !_M_file->sync())
{
_M_set_indeterminate();
__ret = traits_type::not_eof(__c);
}
-#else
- // Part one: Allocate temporary conversion buffer on
- // stack. Convert internal buffer plus __c (ie,
- // "pending sequence") to temporary conversion buffer.
- int __plen = _M_out_end - _M_out_beg;
- char_type* __pbuf = static_cast<char_type*>(__builtin_alloca(sizeof(char_type) * __plen + 1));
- traits_type::copy(__pbuf, this->pbase(), __plen);
- if (!__testeof)
- {
- __pbuf[__plen] = traits_type::to_char_type(__c);
- ++__plen;
- }
-
- char_type* __pend;
- char* __conv_buf = static_cast<char*>(__builtin_alloca(__plen));
- char* __conv_end;
- _M_state_beg = _M_state_cur;
-
- __res_type __r = _M_fcvt->out(_M_state_cur,
- __pbuf, __pbuf + __plen,
- const_cast<const char_type*&>(__pend),
- __conv_buf, __conv_buf + __plen,
- __conv_end);
-
- // Part two: (Re)spill converted "pending sequence"
- // contents (now in temporary conversion buffer) to
- // external buffer (_M_file->_IO_*) using
- // _M_file->sys_write(), and do error (minimal) checking.
- if (__r != codecvt_base::error)
- {
- streamsize __len = _M_file->xsputn(__conv_buf, __plen);
- // NB: Need this so that external byte sequence reflects
- // internal buffer.
- _M_file->sync(); // XXX error check
- if (__len == __plen)
- {
- _M_set_indeterminate();
- __ret = traits_type::not_eof(__c);
- }
- }
-#endif
}
_M_last_overflowed = true;
return __ret;
// Non-standard Types:
typedef basic_streambuf<char_type, traits_type> __streambuf_type;
typedef basic_filebuf<char_type, traits_type> __filebuf_type;
- typedef __basic_file<char_type> __file_type;
+ typedef __basic_file<char> __file_type;
typedef typename traits_type::state_type __state_type;
typedef codecvt<char_type, char, __state_type> __codecvt_type;
typedef typename __codecvt_type::result __res_type;
// Members:
bool
- is_open(void) const { return _M_file ? _M_file->is_open() : false; }
+ is_open() const { return _M_file ? _M_file->is_open() : false; }
__filebuf_type*
open(const char* __s, ios_base::openmode __mode);
__filebuf_type*
- close(void);
+ close();
protected:
void
// Overridden virtual functions:
virtual streamsize
- showmanyc(void);
+ showmanyc();
// Stroustrup, 1998, p. 628
// underflow() and uflow() functions are called to get the next
// charater from the real input source when the buffer is empty.
// Buffered input uses underflow()
virtual int_type
- underflow(void);
+ underflow();
virtual int_type
pbackfail(int_type __c = _Traits::eof());
int_type
_M_really_overflow(int_type __c = _Traits::eof());
+ // Convert internal byte sequence to external, char-based
+ // sequence via codecvt.
+ void
+ _M_convert_to_external(char_type*, streamsize, streamsize&, streamsize&);
+
virtual __streambuf_type*
setbuf(char_type* __s, streamsize __n);
ios_base::openmode __mode = ios_base::in | ios_base::out);
virtual int
- sync(void)
+ sync()
{
bool __testput = _M_out_cur && _M_out_beg < _M_out_end;
{ return const_cast<__filebuf_type*>(&_M_filebuf); }
bool
- is_open(void) { return _M_filebuf.is_open(); }
+ is_open() { return _M_filebuf.is_open(); }
void
open(const char* __s, ios_base::openmode __mode = ios_base::in)
/** Close the file. */
void
- close(void)
+ close()
{
if (!_M_filebuf.close())
this->setstate(ios_base::failbit);
* @return Pointer to basic_filebuf.
*/
__filebuf_type*
- rdbuf(void) const
+ rdbuf() const
{ return const_cast<__filebuf_type*>(&_M_filebuf); }
/**
* @return True if stream is open.
*/
bool
- is_open(void) { return _M_filebuf.is_open(); }
+ is_open() { return _M_filebuf.is_open(); }
/**
* @brief Specify a file to open for output.
/** Close the file stream. */
void
- close(void)
+ close()
{
if (!_M_filebuf.close())
this->setstate(ios_base::failbit);
* @return Pointer to basic_filebuf.
*/
__filebuf_type*
- rdbuf(void) const
+ rdbuf() const
{ return const_cast<__filebuf_type*>(&_M_filebuf); }
/**
* @return True if stream is open.
*/
bool
- is_open(void) { return _M_filebuf.is_open(); }
+ is_open() { return _M_filebuf.is_open(); }
/**
* @brief Specify a file to open for input and/or output.
/** Close the file stream. */
void
- close(void)
+ close()
{
if (!_M_filebuf.close())
setstate(ios_base::failbit);
-// Copyright (C) 2000 Free Software Foundation, Inc.
+// Copyright (C) 2000, 2002 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
int
codecvt<wchar_t, char, mbstate_t>::
do_encoding() const throw()
- { return 0; }
+ { return sizeof(wchar_t); }
bool
codecvt<wchar_t, char, mbstate_t>::
// 2000-08-22 Benjamin Kosnik <bkoz@cygnus.com>
-// Copyright (C) 2000, 2001 Free Software Foundation
+// Copyright (C) 2000, 2001, 2002 Free Software Foundation
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
VERIFY( eto_next == e_arr );
int i = cvt.encoding();
- VERIFY( i == 0 );
+ VERIFY( i == 2 ); // Target-dependent.
VERIFY( !cvt.always_noconv() );
VERIFY( eto_next == e_arr );
int i = cvt.encoding();
- VERIFY( i == 0 );
+ VERIFY( i == 2 ); // Target-dependent.
VERIFY( !cvt.always_noconv() );
VERIFY( eto_next == e_arr );
int i = cvt->encoding();
- VERIFY( i == 0 );
+ VERIFY( i == 4 ); // Target-dependent.
VERIFY( !cvt->always_noconv() );