This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
[Patch] Fix libstdc++/20914
- From: Paolo Carlini <pcarlini at suse dot de>
- To: libstdc++ <libstdc++ at gcc dot gnu dot org>
- Date: Sat, 16 Apr 2005 17:04:46 +0200
- Subject: [Patch] Fix libstdc++/20914
Hi!
The below is the best fix I have for this annoying issue. It's nice that
actually fixing it this way (i.e., as already discussed: prepend
numeric base or sign *after* the grouping) allows for quite a bit of
clean up elsewhere.
I believe the ChangeLog entry and the code are sufficiently clear,
please let me know if something doesn't convince you, otherwise I'm
going to test it a bit more and probably apply tomorrow (and rather
soon, after the release, to 4_0-branch too).
Tested x86-linux.
Paolo.
////////////////
2005-04-17 Paolo Carlini <pcarlini@suse.de>
PR libstdc++/20914
* include/bits/locale_facets.tcc (__int_to_char(_CharT*, _ValueT,
const _CharT*, ios_base::fmtflags, bool)): Don't deal with numeric
base or sign here, instead...
(_M_insert_int(_OutIter, ios_base&, _CharT, _ValueT)): ... here,
after adding the grouping. This fixes the bug and also allows to
clean-up the code dealing with integer types.
(_M_group_int(const char*, size_t, _CharT, ios_base&, _CharT*,
_CharT*, int&)): Simplify, remove bits dealing with numeric base.
(__int_to_char(_CharT*, unsigned long, const _CharT*,
ios_base::fmtflags), __int_to_char(_CharT*, unsigned long long,
const _CharT*, ios_base::fmtflags)): Remove hackish fix for
libstdc++/15565.
(__int_to_char(_CharT*, long, const _CharT*, ios_base::fmtflags),
__int_to_char(_CharT*, long long, const _CharT*, ios_base::fmtflags)):
Simplify, don't pass the sign.
(_M_insert_float(_OutIter, ios_base&, _CharT, char, _ValueT)):
Deal with a sign at the beginning of __cs; robustify the grouping
check.
* testsuite/22_locale/num_put/put/char/20914.cc: New.
* testsuite/22_locale/num_put/put/wchar_t/20914.cc: Likewise.
diff -prN libstdc++-v3-orig/include/bits/locale_facets.tcc libstdc++-v3/include/bits/locale_facets.tcc
*** libstdc++-v3-orig/include/bits/locale_facets.tcc Sat Apr 9 02:08:56 2005
--- libstdc++-v3/include/bits/locale_facets.tcc Sat Apr 16 15:43:40 2005
***************
*** 1,6 ****
// Locale support -*- C++ -*-
! // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
// Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
--- 1,6 ----
// Locale support -*- C++ -*-
! // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
// Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
*************** namespace std
*** 853,876 ****
ios_base::fmtflags __flags)
{
unsigned long __ul = static_cast<unsigned long>(__v);
- bool __neg = false;
if (__v < 0)
! {
! __ul = -__ul;
! __neg = true;
! }
! return __int_to_char(__bufend, __ul, __lit, __flags, __neg);
}
template<typename _CharT>
inline int
__int_to_char(_CharT* __bufend, unsigned long __v, const _CharT* __lit,
ios_base::fmtflags __flags)
! {
! // About showpos, see Table 60 and C99 7.19.6.1, p6 (+).
! return __int_to_char(__bufend, __v, __lit,
! __flags & ~ios_base::showpos, false);
! }
#ifdef _GLIBCXX_USE_LONG_LONG
template<typename _CharT>
--- 853,868 ----
ios_base::fmtflags __flags)
{
unsigned long __ul = static_cast<unsigned long>(__v);
if (__v < 0)
! __ul = -__ul;
! return __int_to_char(__bufend, __ul, __lit, __flags, false);
}
template<typename _CharT>
inline int
__int_to_char(_CharT* __bufend, unsigned long __v, const _CharT* __lit,
ios_base::fmtflags __flags)
! { return __int_to_char(__bufend, __v, __lit, __flags, false); }
#ifdef _GLIBCXX_USE_LONG_LONG
template<typename _CharT>
*************** namespace std
*** 879,937 ****
ios_base::fmtflags __flags)
{
unsigned long long __ull = static_cast<unsigned long long>(__v);
- bool __neg = false;
if (__v < 0)
! {
! __ull = -__ull;
! __neg = true;
! }
! return __int_to_char(__bufend, __ull, __lit, __flags, __neg);
}
template<typename _CharT>
inline int
__int_to_char(_CharT* __bufend, unsigned long long __v,
const _CharT* __lit, ios_base::fmtflags __flags)
! { return __int_to_char(__bufend, __v, __lit,
! __flags & ~ios_base::showpos, false); }
#endif
template<typename _CharT, typename _ValueT>
int
__int_to_char(_CharT* __bufend, _ValueT __v, const _CharT* __lit,
! ios_base::fmtflags __flags, bool __neg)
{
- // Don't write base if already 0.
- const bool __showbase = (__flags & ios_base::showbase) && __v;
const ios_base::fmtflags __basefield = __flags & ios_base::basefield;
! _CharT* __buf = __bufend - 1;
! if (__builtin_expect(__basefield != ios_base::oct &&
! __basefield != ios_base::hex, true))
{
// Decimal.
do
{
! *__buf-- = __lit[(__v % 10) + __num_base::_S_odigits];
__v /= 10;
}
while (__v != 0);
- if (__neg)
- *__buf-- = __lit[__num_base::_S_ominus];
- else if (__flags & ios_base::showpos)
- *__buf-- = __lit[__num_base::_S_oplus];
}
else if (__basefield == ios_base::oct)
{
// Octal.
do
{
! *__buf-- = __lit[(__v & 0x7) + __num_base::_S_odigits];
__v >>= 3;
}
while (__v != 0);
- if (__showbase)
- *__buf-- = __lit[__num_base::_S_odigits];
}
else
{
--- 871,917 ----
ios_base::fmtflags __flags)
{
unsigned long long __ull = static_cast<unsigned long long>(__v);
if (__v < 0)
! __ull = -__ull;
! return __int_to_char(__bufend, __ull, __lit, __flags, false);
}
template<typename _CharT>
inline int
__int_to_char(_CharT* __bufend, unsigned long long __v,
const _CharT* __lit, ios_base::fmtflags __flags)
! { return __int_to_char(__bufend, __v, __lit, __flags, false); }
#endif
+ // N.B. The last argument is currently unused (see libstdc++/20914).
template<typename _CharT, typename _ValueT>
int
__int_to_char(_CharT* __bufend, _ValueT __v, const _CharT* __lit,
! ios_base::fmtflags __flags, bool)
{
const ios_base::fmtflags __basefield = __flags & ios_base::basefield;
! _CharT* __buf = __bufend;
! if (__builtin_expect(__basefield != ios_base::oct
! && __basefield != ios_base::hex, true))
{
// Decimal.
do
{
! *--__buf = __lit[(__v % 10) + __num_base::_S_odigits];
__v /= 10;
}
while (__v != 0);
}
else if (__basefield == ios_base::oct)
{
// Octal.
do
{
! *--__buf = __lit[(__v & 0x7) + __num_base::_S_odigits];
__v >>= 3;
}
while (__v != 0);
}
else
{
*************** namespace std
*** 941,993 ****
: __num_base::_S_odigits;
do
{
! *__buf-- = __lit[(__v & 0xf) + __case_offset];
__v >>= 4;
}
while (__v != 0);
- if (__showbase)
- {
- // 'x' or 'X'
- *__buf-- = __lit[__num_base::_S_ox + __uppercase];
- // '0'
- *__buf-- = __lit[__num_base::_S_odigits];
- }
}
! return __bufend - __buf - 1;
}
template<typename _CharT, typename _OutIter>
void
num_put<_CharT, _OutIter>::
_M_group_int(const char* __grouping, size_t __grouping_size, _CharT __sep,
! ios_base& __io, _CharT* __new, _CharT* __cs, int& __len) const
{
! // By itself __add_grouping cannot deal correctly with __cs when
! // ios::showbase is set and ios_base::oct || ios_base::hex.
! // Therefore we take care "by hand" of the initial 0, 0x or 0X.
! // However, remember that the latter do not occur if the number
! // printed is '0' (__len == 1).
! streamsize __off = 0;
! const ios_base::fmtflags __basefield = __io.flags()
! & ios_base::basefield;
! if ((__io.flags() & ios_base::showbase) && __len > 1)
! if (__basefield == ios_base::oct)
! {
! __off = 1;
! __new[0] = __cs[0];
! }
! else if (__basefield == ios_base::hex)
! {
! __off = 2;
! __new[0] = __cs[0];
! __new[1] = __cs[1];
! }
! _CharT* __p = std::__add_grouping(__new + __off, __sep, __grouping,
! __grouping_size, __cs + __off,
! __cs + __len);
__len = __p - __new;
}
!
template<typename _CharT, typename _OutIter>
template<typename _ValueT>
_OutIter
--- 921,945 ----
: __num_base::_S_odigits;
do
{
! *--__buf = __lit[(__v & 0xf) + __case_offset];
__v >>= 4;
}
while (__v != 0);
}
! return __bufend - __buf;
}
template<typename _CharT, typename _OutIter>
void
num_put<_CharT, _OutIter>::
_M_group_int(const char* __grouping, size_t __grouping_size, _CharT __sep,
! ios_base&, _CharT* __new, _CharT* __cs, int& __len) const
{
! _CharT* __p = std::__add_grouping(__new, __sep, __grouping,
! __grouping_size, __cs, __cs + __len);
__len = __p - __new;
}
!
template<typename _CharT, typename _OutIter>
template<typename _ValueT>
_OutIter
*************** namespace std
*** 1000,1027 ****
const locale& __loc = __io._M_getloc();
const __cache_type* __lc = __uc(__loc);
const _CharT* __lit = __lc->_M_atoms_out;
// Long enough to hold hex, dec, and octal representations.
! const int __ilen = 4 * sizeof(_ValueT);
_CharT* __cs = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
* __ilen));
// [22.2.2.2.2] Stage 1, numeric conversion to character.
// Result is returned right-justified in the buffer.
int __len;
! __len = __int_to_char(__cs + __ilen, __v, __lit, __io.flags());
__cs += __ilen - __len;
// Add grouping, if necessary.
if (__lc->_M_use_grouping)
{
! // Grouping can add (almost) as many separators as the
! // number of digits, but no more.
_CharT* __cs2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
! * __len * 2));
_M_group_int(__lc->_M_grouping, __lc->_M_grouping_size,
! __lc->_M_thousands_sep, __io, __cs2, __cs, __len);
! __cs = __cs2;
}
// Pad.
--- 952,1016 ----
const locale& __loc = __io._M_getloc();
const __cache_type* __lc = __uc(__loc);
const _CharT* __lit = __lc->_M_atoms_out;
+ const ios_base::fmtflags __flags = __io.flags();
// Long enough to hold hex, dec, and octal representations.
! const int __ilen = 5 * sizeof(_ValueT);
_CharT* __cs = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
* __ilen));
// [22.2.2.2.2] Stage 1, numeric conversion to character.
// Result is returned right-justified in the buffer.
int __len;
! __len = __int_to_char(__cs + __ilen, __v, __lit, __flags);
__cs += __ilen - __len;
// Add grouping, if necessary.
if (__lc->_M_use_grouping)
{
! // Grouping can add (almost) as many separators as the number
! // of digits + space is reserved for numeric base or sign.
_CharT* __cs2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
! * (__len + 1)
! * 2));
_M_group_int(__lc->_M_grouping, __lc->_M_grouping_size,
! __lc->_M_thousands_sep, __io, __cs2 + 2, __cs, __len);
! __cs = __cs2 + 2;
! }
!
! // Complete Stage 1, prepend numeric base or sign.
! const ios_base::fmtflags __basefield = __flags & ios_base::basefield;
! if (__builtin_expect(__basefield != ios_base::oct
! && __basefield != ios_base::hex, true))
! {
! // Decimal.
! if (__v > 0)
! {
! if (__flags & ios_base::showpos
! && numeric_limits<_ValueT>::is_signed)
! *--__cs = __lit[__num_base::_S_oplus], ++__len;
! }
! else if (__v)
! *--__cs = __lit[__num_base::_S_ominus], ++__len;
! }
! else if (__basefield == ios_base::oct)
! {
! // Octal.
! if (__flags & ios_base::showbase && __v)
! *--__cs = __lit[__num_base::_S_odigits], ++__len;
! }
! else
! {
! // Hex.
! if (__flags & ios_base::showbase && __v)
! {
! // 'x' or 'X'
! const bool __uppercase = __flags & ios_base::uppercase;
! *--__cs = __lit[__num_base::_S_ox + __uppercase];
! // '0'
! *--__cs = __lit[__num_base::_S_odigits];
! __len += 2;
! }
}
// Pad.
*************** namespace std
*** 1137,1189 ****
_S_get_c_locale(), __prec);
#endif
! // [22.2.2.2.2] Stage 2, convert to char_type, using correct
! // numpunct.decimal_point() values for '.' and adding grouping.
! const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
!
! _CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
! * __len));
! __ctype.widen(__cs, __cs + __len, __ws);
!
! // Replace decimal point.
! const _CharT __cdec = __ctype.widen('.');
! const _CharT __dec = __lc->_M_decimal_point;
! const _CharT* __p = char_traits<_CharT>::find(__ws, __len, __cdec);
! if (__p)
! __ws[__p - __ws] = __dec;
!
! // Add grouping, if necessary.
! // N.B. Make sure to not group things like 2e20, i.e., no decimal
! // point, scientific notation.
! if (__lc->_M_use_grouping
! && (__p || __len < 3 || (__cs[1] != 'e' && __cs[2] != 'e'
! && __cs[1] != 'E' && __cs[2] != 'E')))
! {
! // Grouping can add (almost) as many separators as the
! // number of digits, but no more.
! _CharT* __ws2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
! * __len * 2));
! _M_group_float(__lc->_M_grouping, __lc->_M_grouping_size,
! __lc->_M_thousands_sep, __p, __ws2, __ws, __len);
! __ws = __ws2;
! }
!
! // Pad.
! const streamsize __w = __io.width();
! if (__w > static_cast<streamsize>(__len))
! {
! _CharT* __ws3 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
! * __w));
! _M_pad(__fill, __w, __io, __ws3, __ws, __len);
! __ws = __ws3;
! }
! __io.width(0);
! // [22.2.2.2.2] Stage 4.
! // Write resulting, fully-formatted string to output iterator.
! return std::__write(__s, __ws, __len);
}
!
template<typename _CharT, typename _OutIter>
_OutIter
num_put<_CharT, _OutIter>::
--- 1126,1190 ----
_S_get_c_locale(), __prec);
#endif
! // [22.2.2.2.2] Stage 2, convert to char_type, using correct
! // numpunct.decimal_point() values for '.' and adding grouping.
! const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
!
! _CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
! * __len));
! __ctype.widen(__cs, __cs + __len, __ws);
!
! // Replace decimal point.
! const _CharT __cdec = __ctype.widen('.');
! const _CharT __dec = __lc->_M_decimal_point;
! const _CharT* __p = char_traits<_CharT>::find(__ws, __len, __cdec);
! if (__p)
! __ws[__p - __ws] = __dec;
!
! // Add grouping, if necessary.
! // N.B. Make sure to not group things like 2e20, i.e., no decimal
! // point, scientific notation.
! if (__lc->_M_use_grouping
! && (__p || __len < 3 || (__cs[1] <= '9' && __cs[2] <= '9'
! && __cs[1] >= '0' && __cs[2] >= '0')))
! {
! // Grouping can add (almost) as many separators as the
! // number of digits, but no more.
! _CharT* __ws2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
! * __len * 2));
!
! streamsize __off = 0;
! if (__cs[0] == '-' || __cs[0] == '+')
! {
! __off = 1;
! __ws2[0] = __ws[0];
! __len -= 1;
! }
!
! _M_group_float(__lc->_M_grouping, __lc->_M_grouping_size,
! __lc->_M_thousands_sep, __p, __ws2 + __off,
! __ws + __off, __len);
! __len += __off;
!
! __ws = __ws2;
! }
! // Pad.
! const streamsize __w = __io.width();
! if (__w > static_cast<streamsize>(__len))
! {
! _CharT* __ws3 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
! * __w));
! _M_pad(__fill, __w, __io, __ws3, __ws, __len);
! __ws = __ws3;
! }
! __io.width(0);
!
! // [22.2.2.2.2] Stage 4.
! // Write resulting, fully-formatted string to output iterator.
! return std::__write(__s, __ws, __len);
}
!
template<typename _CharT, typename _OutIter>
_OutIter
num_put<_CharT, _OutIter>::
diff -prN libstdc++-v3-orig/testsuite/22_locale/num_put/put/char/20914.cc libstdc++-v3/testsuite/22_locale/num_put/put/char/20914.cc
*** libstdc++-v3-orig/testsuite/22_locale/num_put/put/char/20914.cc Thu Jan 1 01:00:00 1970
--- libstdc++-v3/testsuite/22_locale/num_put/put/char/20914.cc Sat Apr 16 10:24:21 2005
***************
*** 0 ****
--- 1,79 ----
+ // 2005-04-17 Paolo Carlini <pcarlini@suse.de>
+
+ // Copyright (C) 2005 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
+ // terms of the GNU General Public License as published by the
+ // Free Software Foundation; either version 2, or (at your option)
+ // any later version.
+
+ // This library is distributed in the hope that it will be useful,
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ // GNU General Public License for more details.
+
+ // You should have received a copy of the GNU General Public License along
+ // with this library; see the file COPYING. If not, write to the Free
+ // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ // USA.
+
+ // 22.2.2.2.1 num_put members
+
+ #include <locale>
+ #include <sstream>
+ #include <testsuite_hooks.h>
+
+ // libstdc++/20914
+ void test01()
+ {
+ using namespace std;
+ bool test __attribute__((unused)) = true;
+
+ // A locale that expects grouping.
+ locale loc_de = __gnu_test::try_named_locale("de_DE");
+
+ const string empty;
+ string result;
+
+ ostringstream oss;
+ oss.imbue(loc_de);
+ const num_put<char>& np = use_facet<num_put<char> >(oss.getloc());
+
+ long l0 = -300000;
+ long l1 = 300;
+ double d0 = -300000;
+ double d1 = 300;
+
+ oss.str(empty);
+ oss.clear();
+ np.put(oss.rdbuf(), oss, '*', l0);
+ result = oss.str();
+ VERIFY( result == "-300.000" );
+
+ oss.str(empty);
+ oss.clear();
+ np.put(oss.rdbuf(), oss, '*', d0);
+ result = oss.str();
+ VERIFY( result == "-300.000" );
+
+ oss.str(empty);
+ oss.clear();
+ oss.setf(ios::showpos);
+ np.put(oss.rdbuf(), oss, '*', l1);
+ result = oss.str();
+ VERIFY( result == "+300" );
+
+ oss.str(empty);
+ oss.clear();
+ oss.setf(ios::showpos);
+ np.put(oss.rdbuf(), oss, '*', d1);
+ result = oss.str();
+ VERIFY( result == "+300" );
+ }
+
+ int main()
+ {
+ test01();
+ return 0;
+ }
diff -prN libstdc++-v3-orig/testsuite/22_locale/num_put/put/wchar_t/20914.cc libstdc++-v3/testsuite/22_locale/num_put/put/wchar_t/20914.cc
*** libstdc++-v3-orig/testsuite/22_locale/num_put/put/wchar_t/20914.cc Thu Jan 1 01:00:00 1970
--- libstdc++-v3/testsuite/22_locale/num_put/put/wchar_t/20914.cc Sat Apr 16 10:24:21 2005
***************
*** 0 ****
--- 1,79 ----
+ // 2005-04-17 Paolo Carlini <pcarlini@suse.de>
+
+ // Copyright (C) 2005 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
+ // terms of the GNU General Public License as published by the
+ // Free Software Foundation; either version 2, or (at your option)
+ // any later version.
+
+ // This library is distributed in the hope that it will be useful,
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ // GNU General Public License for more details.
+
+ // You should have received a copy of the GNU General Public License along
+ // with this library; see the file COPYING. If not, write to the Free
+ // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ // USA.
+
+ // 22.2.2.2.1 num_put members
+
+ #include <locale>
+ #include <sstream>
+ #include <testsuite_hooks.h>
+
+ // libstdc++/20914
+ void test01()
+ {
+ using namespace std;
+ bool test __attribute__((unused)) = true;
+
+ // A locale that expects grouping.
+ locale loc_de = __gnu_test::try_named_locale("de_DE");
+
+ const wstring empty;
+ wstring result;
+
+ wostringstream oss;
+ oss.imbue(loc_de);
+ const num_put<wchar_t>& np = use_facet<num_put<wchar_t> >(oss.getloc());
+
+ long l0 = -300000;
+ long l1 = 300;
+ double d0 = -300000;
+ double d1 = 300;
+
+ oss.str(empty);
+ oss.clear();
+ np.put(oss.rdbuf(), oss, L'*', l0);
+ result = oss.str();
+ VERIFY( result == L"-300.000" );
+
+ oss.str(empty);
+ oss.clear();
+ np.put(oss.rdbuf(), oss, L'*', d0);
+ result = oss.str();
+ VERIFY( result == L"-300.000" );
+
+ oss.str(empty);
+ oss.clear();
+ oss.setf(ios::showpos);
+ np.put(oss.rdbuf(), oss, L'*', l1);
+ result = oss.str();
+ VERIFY( result == L"+300" );
+
+ oss.str(empty);
+ oss.clear();
+ oss.setf(ios::showpos);
+ np.put(oss.rdbuf(), oss, L'*', d1);
+ result = oss.str();
+ VERIFY( result == L"+300" );
+ }
+
+ int main()
+ {
+ test01();
+ return 0;
+ }