This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
[PATCH,RFC] Change __convert_from_v to use snprintf and use it
- From: Paolo Carlini <pcarlini at unitus dot it>
- To: libstdc++ at gcc dot gnu dot org
- Cc: bkoz at redhat dot com, ncm at cantrip dot org
- Date: Sun, 17 Mar 2002 15:51:28 +0100
- Subject: [PATCH,RFC] Change __convert_from_v to use snprintf and use it
Hi,
I went ahead and implemented what I presented in my previous message.
Indeed, it seems to me that using snprintf, allows for a /much/ cleaner allocation of the
memory required for the various staging buffers. As part of the work I have also fixed the
problem with money_put, of course.
Please let me know what do you think of it, if perhaps may be only viable for the head,
being to invasive. Tested i686-pc-linux-gnu.
Ciao,
Paolo.
/////////////////
2002-03-17 Paolo Carlini <pcarlini@unitus.it>
* include/bits/locale_facets.tcc
(__convert_from_v): Change to use snprintf.
(num_put::_M_convert_float): Use the new __convert_from_v.
(num_put::_M_convert_int): Same.
(money_put::do_put(long double)): Same.
* src/locale-inst.cc (__convert_from_v): Adjust declarations.
* include/bits/locale_facets.tcc
(money_put::do_put(string)): Fix dimensioning of the buffer
used to add the grouping chars.
* testsuite/22_locale/money_put_members_char.cc: Add test06.
* testsuite/22_locale/money_put_members_char.cc: Ditto.
* include/bits/locale_facets.tcc
(collate::do_transform): Simplify.
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 Mon Mar 11 00:51:31 2002
--- libstdc++-v3/include/bits/locale_facets.tcc Sun Mar 17 14:56:35 2002
*************** namespace std
*** 613,643 ****
// we get the full available precision.
const int __max_digits = numeric_limits<_ValueT>::digits10 + 1;
streamsize __prec = __io.precision();
! // Protect against sprintf() buffer overflows.
if (__prec > static_cast<streamsize>(__max_digits))
__prec = static_cast<streamsize>(__max_digits);
// Long enough for the max format spec.
char __fbuf[16];
! // Consider the possibility of long ios_base::fixed outputs
! const bool __fixed = __io.flags() & ios_base::fixed;
! const int __max_exp = numeric_limits<_ValueT>::max_exponent10;
! // ios_base::fixed outputs may need up to __max_exp+1 chars
! // for the integer part + up to __max_digits chars for the
! // fractional part + 3 chars for sign, decimal point, '\0'. On
! // the other hand, for non-fixed outputs __max_digits*3 chars
! // are largely sufficient.
! const int __cs_size = __fixed ? __max_exp + __max_digits + 4
! : __max_digits * 3;
char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
int __len;
// [22.2.2.2.2] Stage 1, numeric conversion to character.
! if (_S_format_float(__io, __fbuf, __mod, __prec))
! __len = __convert_from_v(__cs, __fbuf, __v, _S_c_locale, __prec);
else
! __len = __convert_from_v(__cs, __fbuf, __v, _S_c_locale);
return _M_widen_float(__s, __io, __fill, __cs, __len);
}
--- 613,648 ----
// we get the full available precision.
const int __max_digits = numeric_limits<_ValueT>::digits10 + 1;
streamsize __prec = __io.precision();
!
if (__prec > static_cast<streamsize>(__max_digits))
__prec = static_cast<streamsize>(__max_digits);
// Long enough for the max format spec.
char __fbuf[16];
! // First try a buffer perhaps big enough.
! int __cs_size = __max_digits * 3;
char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
int __len;
// [22.2.2.2.2] Stage 1, numeric conversion to character.
! const bool __fp = _S_format_float(__io, __fbuf, __mod, __prec);
! if (__fp)
! __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale, __prec);
else
! __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale);
!
! // If the buffer was not large enough, try again with the correct size.
! if (__len >= __cs_size)
! {
! __cs_size = __len + 1;
! __cs = static_cast<char*>(__builtin_alloca(__cs_size));
! if (__fp)
! __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale, __prec);
! else
! __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale);
! }
!
return _M_widen_float(__s, __io, __fill, __cs, __len);
}
*************** namespace std
*** 649,661 ****
char __modl, _ValueT __v) const
{
// [22.2.2.2.2] Stage 1, numeric conversion to character.
- // Leave room for "+/-," "0x," and commas. This size is
- // arbitrary, but should work.
- char __cs[64];
// Long enough for the max format spec.
char __fbuf[16];
_S_format_int(__io, __fbuf, __mod, __modl);
! int __len = __convert_from_v(__cs, __fbuf, __v, _S_c_locale);
return _M_widen_int(__s, __io, __fill, __cs, __len);
}
--- 654,673 ----
char __modl, _ValueT __v) const
{
// [22.2.2.2.2] Stage 1, numeric conversion to character.
// Long enough for the max format spec.
char __fbuf[16];
_S_format_int(__io, __fbuf, __mod, __modl);
! // First try a buffer perhaps big enough.
! int __cs_size = 64;
! char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
! int __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale);
! // If the buffer was not large enough, try again with the correct size.
! if (__len >= __cs_size)
! {
! __cs_size = __len + 1;
! __cs = static_cast<char*>(__builtin_alloca(__cs_size));
! __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale);
! }
return _M_widen_int(__s, __io, __fill, __cs, __len);
}
*************** namespace std
*** 1111,1120 ****
{
const locale __loc = __io.getloc();
const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
! const int __n = numeric_limits<long double>::digits10;
! char* __cs = static_cast<char*>(__builtin_alloca(sizeof(char) * __n));
! _CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __n));
! int __len = __convert_from_v(__cs, "%.01Lf", __units, _S_c_locale);
__ctype.widen(__cs, __cs + __len, __ws);
string_type __digits(__ws);
return this->do_put(__s, __intl, __io, __fill, __digits);
--- 1123,1140 ----
{
const locale __loc = __io.getloc();
const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
! // First try a buffer perhaps big enough.
! int __cs_size = 64;
! char* __cs = static_cast<char*>(__builtin_alloca(sizeof(char) * __cs_size));
! int __len = __convert_from_v(__cs, __cs_size, "%.01Lf", __units, _S_c_locale);
! // If the buffer was not large enough, try again with the correct size.
! if (__len >= __cs_size)
! {
! __cs_size = __len + 1;
! __cs = static_cast<char*>(__builtin_alloca(sizeof(char) * __cs_size));
! __len = __convert_from_v(__cs, __cs_size, "%.01Lf", __units, _S_c_locale);
! }
! _CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __cs_size));
__ctype.widen(__cs, __cs + __len, __ws);
string_type __digits(__ws);
return this->do_put(__s, __intl, __io, __fill, __digits);
*************** namespace std
*** 1206,1212 ****
: __mpf.thousands_sep();
const char* __gbeg = __grouping.c_str();
const char* __gend = __gbeg + __grouping.size();
! const int __n = numeric_limits<long double>::digits10 * 2;
_CharT* __ws2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __n));
_CharT* __ws_end = __add_grouping(__ws2, __sep, __gbeg,
__gend, __beg, __end);
--- 1226,1232 ----
: __mpf.thousands_sep();
const char* __gbeg = __grouping.c_str();
const char* __gend = __gbeg + __grouping.size();
! const int __n = (__end - __beg) * 2;
_CharT* __ws2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __n));
_CharT* __ws_end = __add_grouping(__ws2, __sep, __gbeg,
__gend, __beg, __end);
*************** namespace std
*** 1863,1872 ****
// If the buffer was not large enough, try again with the correct size.
if (__res >= __len)
{
! _CharT* __c2 =
! static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * (__res + 1)));
! _M_transform_helper(__c2, __lo, __res + 1);
! return string_type(__c2);
}
return string_type(__c);
}
--- 1883,1890 ----
// If the buffer was not large enough, try again with the correct size.
if (__res >= __len)
{
! __c = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * (__res + 1)));
! _M_transform_helper(__c, __lo, __res + 1);
}
return string_type(__c);
}
*************** namespace std
*** 1894,1908 ****
// Convert numeric value of type _Tv to string and return length of string.
template<typename _Tv>
int
! __convert_from_v(char* __out, const char* __fmt, _Tv __v,
const __c_locale&, int __prec = -1)
{
int __ret;
const char* __old = setlocale(LC_ALL, "C");
if (__prec >= 0)
! __ret = sprintf(__out, __fmt, __prec, __v);
else
! __ret = sprintf(__out, __fmt, __v);
setlocale(LC_ALL, __old);
return __ret;
}
--- 1912,1926 ----
// Convert numeric value of type _Tv to string and return length of string.
template<typename _Tv>
int
! __convert_from_v(char* __out, const int __size, const char* __fmt, _Tv __v,
const __c_locale&, int __prec = -1)
{
int __ret;
const char* __old = setlocale(LC_ALL, "C");
if (__prec >= 0)
! __ret = snprintf(__out, __size, __fmt, __prec, __v);
else
! __ret = snprintf(__out, __size, __fmt, __v);
setlocale(LC_ALL, __old);
return __ret;
}
diff -prN libstdc++-v3-orig/src/locale-inst.cc libstdc++-v3/src/locale-inst.cc
*** libstdc++-v3-orig/src/locale-inst.cc Fri Mar 8 07:05:20 2002
--- libstdc++-v3/src/locale-inst.cc Sun Mar 17 15:03:01 2002
*************** namespace std
*** 461,488 ****
template
int
! __convert_from_v(char*, const char*, double, const __c_locale&, int);
template
int
! __convert_from_v(char*, const char*, long double, const __c_locale&, int);
template
int
! __convert_from_v(char*, const char*, long, const __c_locale&, int);
template
int
! __convert_from_v(char*, const char*, unsigned long,
const __c_locale&, int);
template
int
! __convert_from_v(char*, const char*, long long, const __c_locale&, int);
template
int
! __convert_from_v(char*, const char*, unsigned long long,
const __c_locale&, int);
template
--- 461,488 ----
template
int
! __convert_from_v(char*, const int, const char*, double, const __c_locale&, int);
template
int
! __convert_from_v(char*, const int, const char*, long double, const __c_locale&,
int);
template
int
! __convert_from_v(char*, const int, const char*, long, const __c_locale&, int);
template
int
! __convert_from_v(char*, const int, const char*, unsigned long,
const __c_locale&, int);
template
int
! __convert_from_v(char*, const int, const char*, long long, const __c_locale&, int);
template
int
! __convert_from_v(char*, const int, const char*, unsigned long long,
const __c_locale&, int);
template
diff -prN libstdc++-v3-orig/testsuite/22_locale/money_put_members_char.cc
libstdc++-v3/testsuite/22_locale/money_put_members_char.cc
*** libstdc++-v3-orig/testsuite/22_locale/money_put_members_char.cc Wed Feb 20 22:06:40
2002
--- libstdc++-v3/testsuite/22_locale/money_put_members_char.cc Sun Mar 17 14:03:41 2002
*************** void test02()
*** 226,232 ****
oss.setf(ios_base::showbase);
oss.str(empty);
! iterator_type os_it03 = mon_put.put(oss.rdbuf(), true, oss, ' ', digits1);
string result3 = oss.str();
VERIFY( result3 == "7.200.000.000,00 DEM ");
--- 226,232 ----
oss.setf(ios_base::showbase);
oss.str(empty);
! iterator_type os_it03 = mon_put.put(oss.rdbuf(), true, oss, ' ', digits1);
string result3 = oss.str();
VERIFY( result3 == "7.200.000.000,00 DEM ");
*************** void test05()
*** 341,346 ****
--- 341,373 ----
VERIFY( fmt.str() == "*(1,234.56)" );
}
+ struct My_money_io_2 : public std::moneypunct<char,false>
+ {
+ char_type do_thousands_sep() const { return ','; }
+ std::string do_grouping() const { return "\001"; }
+ };
+
+ // Make sure we can output a very big amount of money (with grouping too).
+ void test06()
+ {
+ using namespace std;
+ typedef ostreambuf_iterator<char> OutIt;
+
+ locale loc(locale::classic(), new My_money_io_2);
+
+ bool intl = false;
+
+ long double val = 1e50L;
+ const money_put<char,OutIt>& mp =
+ use_facet<money_put<char, OutIt> >(loc);
+
+ ostringstream fmt;
+ fmt.imbue(loc);
+ OutIt out(fmt);
+ mp.put(out,intl,fmt,'*',val);
+ VERIFY( fmt );
+ }
+
int main()
{
test01();
*************** int main()
*** 348,352 ****
--- 375,380 ----
test03();
test04();
test05();
+ test06();
return 0;
}
diff -prN libstdc++-v3-orig/testsuite/22_locale/money_put_members_wchar_t.cc
libstdc++-v3/testsuite/22_locale/money_put_members_wchar_t.cc
*** libstdc++-v3-orig/testsuite/22_locale/money_put_members_wchar_t.cc Wed Feb 20 22:06:40
2002
--- libstdc++-v3/testsuite/22_locale/money_put_members_wchar_t.cc Sun Mar 17 14:03:49 2002
*************** void test02()
*** 226,232 ****
oss.setf(ios_base::showbase);
oss.str(empty);
! iterator_type os_it03 = mon_put.put(oss.rdbuf(), true, oss, ' ', digits1);
wstring result3 = oss.str();
VERIFY( result3 == L"7.200.000.000,00 DEM ");
--- 226,232 ----
oss.setf(ios_base::showbase);
oss.str(empty);
! iterator_type os_it03 = mon_put.put(oss.rdbuf(), true, oss, ' ', digits1);
wstring result3 = oss.str();
VERIFY( result3 == L"7.200.000.000,00 DEM ");
*************** void test05()
*** 340,345 ****
--- 340,372 ----
mp.put(out,intl,fmt,L'*',val);
VERIFY( fmt.str() == L"*(1,234.56)" );
}
+
+ struct My_money_io_2 : public std::moneypunct<wchar_t,false>
+ {
+ char_type do_thousands_sep() const { return L','; }
+ std::string do_grouping() const { return "\001"; }
+ };
+
+ // Make sure we can output a very big amount of money (with grouping too).
+ void test06()
+ {
+ using namespace std;
+ typedef ostreambuf_iterator<wchar_t> OutIt;
+
+ locale loc(locale::classic(), new My_money_io_2);
+
+ bool intl = false;
+
+ long double val = 1e50L;
+ const money_put<wchar_t,OutIt>& mp =
+ use_facet<money_put<wchar_t, OutIt> >(loc);
+
+ wostringstream fmt;
+ fmt.imbue(loc);
+ OutIt out(fmt);
+ mp.put(out,intl,fmt,'*',val);
+ VERIFY( fmt );
+ }
#endif
int main()
*************** int main()
*** 350,355 ****
--- 377,383 ----
test03();
test04();
test05();
+ test06();
#endif
return 0;
}