From 793734867f317d091827f1d2a2f3339a8ce79cf6 Mon Sep 17 00:00:00 2001 From: bkoz Date: Thu, 13 Sep 2001 23:21:25 +0000 Subject: [PATCH] 2001-09-13 Benjamin Kosnik Implement std::money_get. * include/bits/locale_facets.tcc (money_get::do_get): Implement. * include/bits/locale_facets.h (money_get): Correct signatures. * testsuite/22_locale/money_get.cc: New file. * testsuite/22_locale/money_get_members_char.cc: New file. * include/bits/locale_facets.tcc (__verify_grouping): New function. Consolidate num_get and money_get group checking into one function. (money_get): Use it. * src/locale.cc (num_get::_M_extract): Use it. * src/locale-inst.cc: Add instantiation. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@45585 138bc75d-0d04-0410-961f-82ee72b054a4 --- libstdc++-v3/ChangeLog | 15 + libstdc++-v3/include/bits/locale_facets.h | 162 +++++----- libstdc++-v3/include/bits/locale_facets.tcc | 327 ++++++++++++++++++--- libstdc++-v3/src/locale-inst.cc | 8 + libstdc++-v3/src/locale.cc | 23 +- libstdc++-v3/testsuite/22_locale/money_get.cc | 53 ++++ .../testsuite/22_locale/money_get_members_char.cc | 279 ++++++++++++++++++ 7 files changed, 720 insertions(+), 147 deletions(-) create mode 100644 libstdc++-v3/testsuite/22_locale/money_get.cc create mode 100644 libstdc++-v3/testsuite/22_locale/money_get_members_char.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index f52b092..66a4b8e 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,18 @@ +2001-09-13 Benjamin Kosnik + + Implement std::money_get. + * include/bits/locale_facets.tcc (money_get::do_get): Implement. + * include/bits/locale_facets.h (money_get): Correct signatures. + * testsuite/22_locale/money_get.cc: New file. + * testsuite/22_locale/money_get_members_char.cc: New file. + + * include/bits/locale_facets.tcc (__verify_grouping): New + function. Consolidate num_get and money_get group checking into + one function. + (money_get): Use it. + * src/locale.cc (num_get::_M_extract): Use it. + * src/locale-inst.cc: Add instantiation. + 2001-09-12 Gabriel Dos Reis * include/bits/std_limits.h (numeric_limits::radix, diff --git a/libstdc++-v3/include/bits/locale_facets.h b/libstdc++-v3/include/bits/locale_facets.h index 1e64224..9b81336 100644 --- a/libstdc++-v3/include/bits/locale_facets.h +++ b/libstdc++-v3/include/bits/locale_facets.h @@ -1212,88 +1212,6 @@ namespace std }; - template - class money_get : public locale::facet - { - public: - typedef _CharT char_type; - typedef _InIter iter_type; - typedef basic_string<_CharT> string_type; - - static locale::id id; - - explicit - money_get(size_t __refs = 0) : locale::facet(__refs) { } - - iter_type - get(iter_type __s, iter_type __end, bool __intl, - ios_base& __f, ios_base::iostate& __err, long double& __units) const - { return do_get(__s, __end, __intl, __f, __err, __units); } - - iter_type - get(iter_type __s, iter_type __end, bool __intl, ios_base& __f, - ios_base::iostate& __err, string_type& __digits) const - { return do_get(__s, __end, __intl, __f, __err, __digits); } - - protected: - virtual - ~money_get() { } - - virtual iter_type - do_get(iter_type __s, iter_type /*__end*/, bool /*__intl*/, - ios_base& /*__io*/, ios_base::iostate& /*__err*/, - long double& /*__units*/) const - { return __s; } - - virtual iter_type - do_get(iter_type __s, iter_type /*__end*/, bool /*__intl*/, - ios_base& /*__io*/, ios_base::iostate& /*__err*/, - string_type& /*__digits*/) const - { return __s; } - }; - - template - locale::id money_get<_CharT, _InIter>::id; - - template - class money_put : public locale::facet - { - public: - typedef _CharT char_type; - typedef _OutIter iter_type; - typedef basic_string<_CharT> string_type; - - static locale::id id; - - explicit - money_put(size_t __refs = 0) : locale::facet(__refs) { } - - iter_type - put(iter_type __s, bool __intl, ios_base& __f, - char_type __fill, long double __units) const - { return this->do_put(__s, __intl, __f, __fill, __units); } - - iter_type - put(iter_type __s, bool __intl, ios_base& __f, - char_type __fill, const string_type& __digits) const - { return this->do_put(__s, __intl, __f, __fill, __digits); } - - protected: - virtual - ~money_put() { } - - virtual iter_type - do_put(iter_type __s, bool __intl, ios_base& __io, char_type __fill, - long double __units) const; - - virtual iter_type - do_put(iter_type __s, bool __intl, ios_base& __io, char_type __fill, - const string_type& __digits) const; - }; - - template - locale::id money_put<_CharT, _OutIter>::id; - struct money_base { enum part { none, space, symbol, sign, value }; @@ -1477,6 +1395,86 @@ namespace std template const bool moneypunct_byname<_CharT, _Intl>::intl; + template + class money_get : public locale::facet + { + public: + typedef _CharT char_type; + typedef _InIter iter_type; + typedef basic_string<_CharT> string_type; + + static locale::id id; + + explicit + money_get(size_t __refs = 0) : locale::facet(__refs) { } + + iter_type + get(iter_type __s, iter_type __end, bool __intl, + ios_base& __f, ios_base::iostate& __err, long double& __units) const + { return this->do_get(__s, __end, __intl, __f, __err, __units); } + + iter_type + get(iter_type __s, iter_type __end, bool __intl, ios_base& __f, + ios_base::iostate& __err, string_type& __digits) const + { return this->do_get(__s, __end, __intl, __f, __err, __digits); } + + protected: + virtual + ~money_get() { } + + virtual iter_type + do_get(iter_type __s, iter_type __end, bool __intl, + ios_base& __io, ios_base::iostate& __err, + long double& __units) const; + + virtual iter_type + do_get(iter_type __s, iter_type __end, bool __intl, + ios_base& __io, ios_base::iostate& __err, + string_type& __digits) const; + }; + + template + locale::id money_get<_CharT, _InIter>::id; + + template + class money_put : public locale::facet + { + public: + typedef _CharT char_type; + typedef _OutIter iter_type; + typedef basic_string<_CharT> string_type; + + static locale::id id; + + explicit + money_put(size_t __refs = 0) : locale::facet(__refs) { } + + iter_type + put(iter_type __s, bool __intl, ios_base& __f, + char_type __fill, long double __units) const + { return this->do_put(__s, __intl, __f, __fill, __units); } + + iter_type + put(iter_type __s, bool __intl, ios_base& __f, + char_type __fill, const string_type& __digits) const + { return this->do_put(__s, __intl, __f, __fill, __digits); } + + protected: + virtual + ~money_put() { } + + virtual iter_type + do_put(iter_type __s, bool __intl, ios_base& __io, char_type __fill, + long double __units) const; + + virtual iter_type + do_put(iter_type __s, bool __intl, ios_base& __io, char_type __fill, + const string_type& __digits) const; + }; + + template + locale::id money_put<_CharT, _OutIter>::id; + struct messages_base { diff --git a/libstdc++-v3/include/bits/locale_facets.tcc b/libstdc++-v3/include/bits/locale_facets.tcc index 5ed35d1..ccf227e 100644 --- a/libstdc++-v3/include/bits/locale_facets.tcc +++ b/libstdc++-v3/include/bits/locale_facets.tcc @@ -227,19 +227,227 @@ namespace std return __ncp; } + template + money_get<_CharT, _InIter>::iter_type + money_get<_CharT, _InIter>::do_get(iter_type __s, iter_type __end, + bool __intl, ios_base& __io, + ios_base::iostate& __err, + long double& __units) const + { + string_type __str; + this->do_get(__s, __end, __intl, __io, __err, __str); + + const int __n = numeric_limits::digits10; + char* __cs = static_cast(__builtin_alloca(sizeof(char) * __n)); + const locale __loc = __io.getloc(); + const ctype<_CharT>& __ctype = use_facet >(__loc); + const _CharT* __wcs = __str.c_str(); + __ctype.narrow(__wcs, __wcs + __str.size() + 1, char(), __cs); + + char* __sanity; + errno = 0; + long double __ld = strtold(__cs, &__sanity); + if (!(__err & ios_base::failbit) + && __sanity != __cs && *__sanity == '\0' && errno == 0) + __units = __ld; + return __s; + } + + template + money_get<_CharT, _InIter>::iter_type + money_get<_CharT, _InIter>::do_get(iter_type __s, iter_type __end, + bool __intl, ios_base& __io, + ios_base::iostate& __err, + string_type& __units) const + { + // These contortions are quite unfortunate. + typedef moneypunct<_CharT, true> __money_true; + typedef moneypunct<_CharT, false> __money_false; + typedef money_base::part part; + typedef typename string_type::size_type size_type; + + const locale __loc = __io.getloc(); + const __money_true& __mpt = use_facet<__money_true>(__loc); + const __money_false& __mpf = use_facet<__money_false>(__loc); + const ctype<_CharT>& __ctype = use_facet >(__loc); + + const money_base::pattern __p = __intl ? __mpt.neg_format() + : __mpf.neg_format(); + + const string_type __pos_sign =__intl ? __mpt.positive_sign() + : __mpf.positive_sign(); + const string_type __neg_sign =__intl ? __mpt.negative_sign() + : __mpf.negative_sign(); + const char_type __d = __intl ? __mpt.decimal_point() + : __mpf.decimal_point(); + const char_type __sep = __intl ? __mpt.thousands_sep() + : __mpf.thousands_sep(); + + const string __grouping = __intl ? __mpt.grouping() + : __mpf.grouping(); + + // Set to deduced positive or negative sign, depending. + string_type __sign; + // String of grouping info from thousands_sep plucked from __units. + string __grouping_tmp; + // Marker for thousands_sep position. + int __sep_pos = 0; + // If input iterator is in a valid state. + bool __testvalid = true; + // Flag marking when a decimal point is found. + bool __testdecfound = false; + + char_type __c = *__s; + char_type __eof = static_cast(char_traits::eof()); + for (int __i = 0; __s != __end && __i < 4 && __testvalid; ++__i) + { + part __which = static_cast(__p.field[__i]); + switch (__which) + { + case money_base::symbol: + if (__io.flags() & ios_base::showbase) + { + // Symbol is required. + const string_type __symbol = __intl ? __mpt.curr_symbol() + : __mpf.curr_symbol(); + size_type __len = __symbol.size(); + size_type __i = 0; + while (__s != __end + && __i < __len && __symbol[__i] == __c) + { + __c = *(++__s); + ++__i; + } + if (__i != __len) + __testvalid = false; + } + break; + case money_base::sign: + // Sign might not exist, or be more than one character long. + if (__pos_sign.size() && __neg_sign.size()) + { + // Sign is mandatory. + if (__c == __pos_sign[0]) + { + __sign = __pos_sign; + __c = *(++__s); + } + else if (__c == __neg_sign[0]) + { + __sign = __neg_sign; + __c = *(++__s); + } + else + __testvalid = false; + } + else if (__pos_sign.size() && __c == __pos_sign[0]) + { + __sign = __pos_sign; + __c = *(++__s); + } + else if (__neg_sign.size() && __c == __neg_sign[0]) + { + __sign = __neg_sign; + __c = *(++__s); + } + break; + case money_base::value: + // Extract digits, remove and stash away the + // grouping of found thousands separators. + while (__s != __end + && (__ctype.is(ctype_base::digit, __c) + || (__c == __d && !__testdecfound) + || __c == __sep)) + { + if (__c == __d) + { + __grouping_tmp += static_cast(__sep_pos); + __sep_pos = 0; + __testdecfound = true; + } + else if (__c == __sep) + { + if (__grouping.size()) + { + // Mark position for later analysis. + __grouping_tmp += static_cast(__sep_pos); + __sep_pos = 0; + } + else + { + __testvalid = false; + break; + } + } + else + { + __units += __c; + ++__sep_pos; + } + __c = *(++__s); + } + break; + case money_base::space: + case money_base::none: + // Only if not at the end of the pattern. + if (__i != 3) + while (__s != __end && __ctype.is(ctype_base::space, __c)) + __c = *(++__s); + break; + } + } + + // Need to get the rest of the sign characters, if they exist. + if (__sign.size() > 1) + { + size_type __len = __sign.size(); + size_type __i = 1; + for (; __c != __eof && __i < __len; ++__i) + while (__s != __end && __c != __sign[__i]) + __c = *(++__s); + + if (__i != __len) + __testvalid = false; + } + + // Strip leading zeros. + while (__units[0] == __ctype.widen('0')) + __units.erase(__units.begin()); + + if (__sign == __neg_sign) + __units.insert(__units.begin(), __ctype.widen('-')); + + // Test for grouping fidelity. + if (__grouping.size() && __grouping_tmp.size()) + { + if (!__verify_grouping(__grouping, __grouping_tmp)) + __testvalid = false; + } + + // Iff no more characters are available. + if (__c == __eof) + __err |= ios_base::eofbit; + + // Iff valid sequence is not recognized. + if (!__testvalid || !__units.size()) + __err |= ios_base::failbit; + + return __s; + } + template money_put<_CharT, _OutIter>::iter_type money_put<_CharT, _OutIter>::do_put(iter_type __s, bool __intl, ios_base& __io, char_type __fill, long double __units) const { - locale __loc = __io.getloc(); - const ctype<_CharT>& __ct = use_facet >(__loc); + const locale __loc = __io.getloc(); + const ctype<_CharT>& __ctype = use_facet >(__loc); const int __n = numeric_limits::digits10; char* __cs = static_cast(__builtin_alloca(sizeof(char) * __n)); _CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __n)); int __len = sprintf(__cs, "%.01Lf", __units); - __ct.widen(__cs, __cs + __len, __ws); + __ctype.widen(__cs, __cs + __len, __ws); string_type __digits(__ws); return this->do_put(__s, __intl, __io, __fill, __digits); } @@ -250,17 +458,18 @@ namespace std ios_base& __io, char_type __fill, const string_type& __digits) const { - typedef typename string_type::size_type size_type; + typedef typename string_type::size_type size_type; + typedef money_base::part part; - locale __loc = __io.getloc(); - size_type __width = static_cast(__io.width()); + const locale __loc = __io.getloc(); + const size_type __width = static_cast(__io.width()); // These contortions are quite unfortunate. typedef moneypunct<_CharT, true> __money_true; typedef moneypunct<_CharT, false> __money_false; const __money_true& __mpt = use_facet<__money_true>(__loc); const __money_false& __mpf = use_facet<__money_false>(__loc); - const ctype<_CharT>& __ct = use_facet >(__loc); + const ctype<_CharT>& __ctype = use_facet >(__loc); // Determine if negative or positive formats are to be used, and // discard leading negative_sign if it is present. @@ -268,7 +477,7 @@ namespace std const char_type* __end = __beg + __digits.size(); money_base::pattern __p; string_type __sign; - if (*__beg != __ct.widen('-')) + if (*__beg != __ctype.widen('-')) { __p = __intl ? __mpt.pos_format() : __mpf.pos_format(); __sign =__intl ? __mpt.positive_sign() : __mpf.positive_sign(); @@ -281,7 +490,7 @@ namespace std } // Look for valid numbers in the current ctype facet within input digits. - __end = __ct.scan_not(ctype_base::digit, __beg, __end); + __end = __ctype.scan_not(ctype_base::digit, __beg, __end); if (__beg != __end) { // Assume valid input, and attempt to format. @@ -289,15 +498,16 @@ namespace std // final_value = grouped units + (decimal point) + (digits) string_type __res; string_type __value; - string_type __symbol = __intl - ? __mpt.curr_symbol() : __mpf.curr_symbol(); + const string_type __symbol = __intl ? __mpt.curr_symbol() + : __mpf.curr_symbol(); // Deal with decimal point, decimal digits. - int __frac = __intl ? __mpt.frac_digits() : __mpf.frac_digits(); + const int __frac = __intl ? __mpt.frac_digits() + : __mpf.frac_digits(); if (__frac > 0) { - char_type __d = __intl - ? __mpt.decimal_point() : __mpf.decimal_point(); + const char_type __d = __intl ? __mpt.decimal_point() + : __mpf.decimal_point(); if (__end - __beg >= __frac) { __value = string_type(__end - __frac, __end); @@ -309,7 +519,7 @@ namespace std // Have to pad zeros in the decimal position. __value = string_type(__beg, __end); int __paddec = __frac - (__end - __beg); - char_type __zero = __ct.widen('0'); + char_type __zero = __ctype.widen('0'); __value.insert(__value.begin(), __paddec, __zero); __value.insert(__value.begin(), __d); __beg = __end; @@ -320,11 +530,12 @@ namespace std // grouping rules. if (__beg != __end) { - string __grouping = __intl ? __mpt.grouping() : __mpf.grouping(); + const string __grouping = __intl ? __mpt.grouping() + : __mpf.grouping(); if (__grouping.size()) { - char_type __sep = __intl ? __mpt.thousands_sep() - : __mpf.thousands_sep(); + const char_type __sep = __intl ? __mpt.thousands_sep() + : __mpf.thousands_sep(); const char* __gbeg = __grouping.data(); const char* __gend = __gbeg + __grouping.size(); const int __n = numeric_limits::digits10 * 2; @@ -346,7 +557,6 @@ namespace std // Fit formatted digits into the required pattern. for (int __i = 0; __i < 4; ++__i) { - typedef money_base::part part; part __which = static_cast(__p.field[__i]); switch (__which) { @@ -371,7 +581,7 @@ namespace std if (__testipad) __res += string_type(__width - __len, __fill); else - __res += __ct.widen(' '); + __res += __ctype.widen(' '); break; case money_base::none: if (__testipad) @@ -888,11 +1098,11 @@ namespace std } // __pad is specialized for ostreambuf_iterator, random access iterator. - template + template inline _OutIter __pad(_OutIter __s, _CharT __fill, int __padding); - template + template _RaIter __pad(_RaIter __s, _CharT __fill, int __padding, random_access_iterator_tag) @@ -901,7 +1111,7 @@ namespace std return __s + __padding; } - template + template _OutIter __pad(_OutIter __s, _CharT __fill, int __padding, _Tag) { @@ -909,7 +1119,7 @@ namespace std return __s; } - template + template inline _OutIter __pad(_OutIter __s, _CharT __fill, int __padding) { @@ -917,7 +1127,7 @@ namespace std typename iterator_traits<_OutIter>::iterator_category()); } - template + template _OutIter __pad_numeric(_OutIter __s, ios_base::fmtflags /*__flags*/, _CharT /*__fill*/, int /*__width*/, @@ -929,7 +1139,7 @@ namespace std } // Partial specialization for ostreambuf_iterator. - template + template ostreambuf_iterator<_CharT> __pad_numeric(ostreambuf_iterator<_CharT> __s, ios_base::fmtflags __flags, _CharT __fill, int __width, _CharT const* __first, @@ -966,7 +1176,7 @@ namespace std return __s3; } - template + template _OutIter num_put<_CharT, _OutIter>:: do_put(iter_type __s, ios_base& __io, char_type __fill, bool __v) const @@ -998,11 +1208,42 @@ namespace std return __s; } - // __group_digits inserts "group separator" characters into an array - // of characters. It's recursive, one iteration per group. It moves - // the characters in the buffer this way: "xxxx12345" -> "12,345xxx". - // Call this only with __gbeg != __gend. - template + // Check to make sure that the __grouping_tmp string constructed in + // money_get or num_get matches the canonical grouping for a given + // locale. + // __grouping_tmp is parsed L to R + // 1,222,444 == __grouping_tmp of "/1/3/3" + // __grouping is parsed R to L + // 1,222,444 == __grouping of "/3" == "/3/3/3" + template + bool + __verify_grouping(const basic_string<_CharT>& __grouping, + basic_string<_CharT>& __grouping_tmp) + { + int __i = 0; + int __j = 0; + const int __len = __grouping.size(); + const int __n = __grouping_tmp.size(); + bool __test = true; + + // Parsed number groupings have to match the + // numpunct::grouping string exactly, starting at the + // right-most point of the parsed sequence of elements ... + while (__test && __i < __n - 1) + for (__j = 0; __test && __j < __len && __i < __n - 1; ++__j,++__i) + __test &= __grouping[__j] == __grouping_tmp[__n - __i - 1]; + // ... but the last parsed grouping can be <= numpunct + // grouping. + __j == __len ? __j = 0 : __j; + __test &= __grouping[__j] >= __grouping_tmp[__n - __i - 1]; + return __test; + } + + // Inserts "group separator" characters into an array of characters. + // It's recursive, one iteration per group. It moves the characters + // in the buffer this way: "xxxx12345" -> "12,345xxx". Call this + // only with __gbeg != __gend. + template _CharT* __group_digits(_CharT* __s, _CharT __sep, const char* __gbeg, const char* __gend, @@ -1024,7 +1265,7 @@ namespace std return __s; } - template + template _OutIter __output_integer(_OutIter __s, ios_base& __io, _CharT __fill, bool __neg, _ValueT __v) @@ -1097,7 +1338,7 @@ namespace std __digits, __p, __digits_end); } - template + template _OutIter num_put<_CharT, _OutIter>:: do_put(iter_type __s, ios_base& __io, char_type __fill, long __v) const @@ -1112,7 +1353,7 @@ namespace std return __output_integer(__s, __io, __fill, __neg, __uv); } - template + template _OutIter num_put<_CharT, _OutIter>:: do_put(iter_type __s, ios_base& __io, char_type __fill, @@ -1120,7 +1361,7 @@ namespace std { return __output_integer(__s, __io, __fill, false, __v); } #ifdef _GLIBCPP_USE_LONG_LONG - template + template _OutIter num_put<_CharT, _OutIter>:: do_put(iter_type __s, ios_base& __b, char_type __fill, long long __v) const @@ -1135,7 +1376,7 @@ namespace std return __output_integer(__s, __b, __fill, __neg, __uv); } - template + template _OutIter num_put<_CharT, _OutIter>:: do_put(iter_type __s, ios_base& __io, char_type __fill, @@ -1162,7 +1403,7 @@ namespace std size_t __padding = __io.width() > streamsize(__slen) ? __io.width() -__slen : 0; locale __loc = __io.getloc(); - ctype<_CharT> const& __ct = use_facet >(__loc); + ctype<_CharT> const& __ctype = use_facet >(__loc); ios_base::fmtflags __adjfield = __io.flags() & ios_base::adjustfield; const char* const __eptr = __sptr + __slen; // [22.2.2.2.2.19] Table 61 @@ -1171,7 +1412,7 @@ namespace std // [22.2.2.2.2.14]; widen() if (__sptr < __eptr && (*__sptr == '+' || *__sptr == '-')) { - __s = __ct.widen(*__sptr); + __s = __ctype.widen(*__sptr); ++__s; ++__sptr; } @@ -1193,7 +1434,7 @@ namespace std __s = __fmt->_M_decimal_point; // [22.2.2.2.2.14]; widen() else - __s = __ct.widen(*__sptr); + __s = __ctype.widen(*__sptr); } // [22.2.2.2.2.19] Table 61 if (__padding) @@ -1206,7 +1447,7 @@ namespace std __build_float_format(ios_base& __io, char* __fptr, char __modifier, streamsize __prec); - template + template _OutIter num_put<_CharT, _OutIter>:: do_put(iter_type __s, ios_base& __io, char_type __fill, double __v) const @@ -1229,7 +1470,7 @@ namespace std return __output_float(__s, __io, __fill, __sbuf, __slen); } - template + template _OutIter num_put<_CharT, _OutIter>:: do_put(iter_type __s, ios_base& __io, char_type __fill, @@ -1254,7 +1495,7 @@ namespace std return __output_float(__s, __io, __fill, __sbuf, __slen); } - template + template _OutIter num_put<_CharT, _OutIter>:: do_put(iter_type __s, ios_base& __io, char_type __fill, diff --git a/libstdc++-v3/src/locale-inst.cc b/libstdc++-v3/src/locale-inst.cc index 78464a6..df0a3af 100644 --- a/libstdc++-v3/src/locale-inst.cc +++ b/libstdc++-v3/src/locale-inst.cc @@ -264,6 +264,10 @@ namespace std __group_digits(char*, char, char const*, char const*, char const*, char const*); + template + bool + __verify_grouping(const basic_string&, basic_string&); + template ostreambuf_iter __output_integer @@ -298,6 +302,10 @@ namespace std wchar_t* __group_digits(wchar_t*, wchar_t, char const*, char const*, wchar_t const*, wchar_t const*); + template + bool + __verify_grouping(const basic_string&, + basic_string&); template wostreambuf_iter diff --git a/libstdc++-v3/src/locale.cc b/libstdc++-v3/src/locale.cc index 990e662..d69e7e6 100644 --- a/libstdc++-v3/src/locale.cc +++ b/libstdc++-v3/src/locale.cc @@ -646,28 +646,7 @@ namespace std // Add the ending grouping __grp += static_cast(__sep_pos); - // __grp is parsed L to R - // 1,222,444 == __grp of "/1/3/3" - // __fmt->_M_grouping is parsed R to L - // 1,222,444 == __fmt->_M_grouping of "/3" == "/3/3/3" - int __i = 0; - int __j = 0; - const int __len = __fmt->_M_grouping.size(); - int __n = __grp.size(); - bool __test = true; - - // Parsed number groupings have to match the - // numpunct::grouping string exactly, starting at the - // right-most point of the parsed sequence of elements ... - while (__test && __i < __n - 1) - for (__j = 0; __test && __j < __len && __i < __n - 1; ++__j,++__i) - __test &= __fmt->_M_grouping[__j] == __grp[__n - __i - 1]; - // ... but the last parsed grouping can be <= numpunct - // grouping. - __j == __len ? __j = 0 : __j; - __test &= __fmt->_M_grouping[__j] >= __grp[__n - __i - 1]; - - if (!__test) + if (!__verify_grouping(__fmt->_M_grouping, __grp)) { __err |= ios_base::failbit; __xtrc[__pos] = '\0'; diff --git a/libstdc++-v3/testsuite/22_locale/money_get.cc b/libstdc++-v3/testsuite/22_locale/money_get.cc new file mode 100644 index 0000000..333af26 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/money_get.cc @@ -0,0 +1,53 @@ +// 2001-09-12 Benjamin Kosnik + +// Copyright (C) 2001 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.6.1 Template class money_get + +#include + +void test01() +{ + // Check for required base class. + typedef std::money_get test_type; + typedef std::locale::facet base_type; + const test_type& obj = std::use_facet(std::locale()); + const base_type* base = &obj; + + // Check for required typedefs + typedef test_type::char_type char_type; + typedef test_type::string_type string_type; + typedef test_type::iter_type iter_type; +} + +// Should be able to instantiate this for other types besides char, wchar_t +class gnu_money_get: public std::money_get +{ }; + +void test02() +{ + gnu_money_get facet01; +} + +int main() +{ + test01(); + test02(); + return 0; +} diff --git a/libstdc++-v3/testsuite/22_locale/money_get_members_char.cc b/libstdc++-v3/testsuite/22_locale/money_get_members_char.cc new file mode 100644 index 0000000..6b035e5 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/money_get_members_char.cc @@ -0,0 +1,279 @@ +// 2001-09-12 Benjamin Kosnik + +// Copyright (C) 2001 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.6.1.1 money_get members + +#include +#include +#include + +// XXX This test is not working for non-glibc locale models. +// { dg-do run { xfail *-*-* } } + +// test string version +void test01() +{ + using namespace std; + typedef money_base::part part; + typedef money_base::pattern pattern; + typedef istreambuf_iterator iterator_type; + + bool test = true; + string str; + + // basic construction + locale loc_c = locale::classic(); + str = loc_c.name(); + + locale loc_hk("en_HK"); + str = loc_hk.name(); + VERIFY( loc_c != loc_hk ); + + locale loc_fr("fr_FR@euro"); + str = loc_fr.name(); + VERIFY( loc_c != loc_fr ); + + locale loc_de("de_DE"); + str = loc_de.name(); + VERIFY( loc_c != loc_de ); + + VERIFY( loc_hk != loc_fr ); + VERIFY( loc_hk != loc_de ); + VERIFY( loc_de != loc_fr ); + + // cache the moneypunct facets + typedef moneypunct __money_true; + typedef moneypunct __money_false; + const __money_true& monpunct_c_t = use_facet<__money_true>(loc_c); + const __money_true& monpunct_de_t = use_facet<__money_true>(loc_de); + const __money_false& monpunct_c_f = use_facet<__money_false>(loc_c); + const __money_false& monpunct_de_f = use_facet<__money_false>(loc_de); + const __money_true& monpunct_hk_t = use_facet<__money_true>(loc_hk); + const __money_false& monpunct_hk_f = use_facet<__money_false>(loc_hk); + + // sanity check the data is correct. + const string empty; + + // total EPA budget FY 2002 + const string digits1("720000000000"); + + // est. cost, national missle "defense", expressed as a loss in USD 2001 + const string digits2("-10000000000000"); + + // not valid input + const string digits3("-A"); + + // input less than frac_digits + const string digits4("-1"); + + iterator_type end; + istringstream iss; + iss.imbue(loc_de); + // cache the money_get facet + const money_get& mon_get = use_facet >(iss.getloc()); + + + iss.str("7.200.000.000,00 "); + iterator_type is_it01(iss); + string result1; + ios_base::iostate err01 = ios_base::goodbit; + mon_get.get(is_it01, end, true, iss, err01, result1); + VERIFY( result1 == digits1 ); + VERIFY( err01 == ios_base::eofbit ); + + iss.str("7.200.000.000,00 "); + iterator_type is_it02(iss); + string result2; + ios_base::iostate err02 = ios_base::goodbit; + mon_get.get(is_it02, end, true, iss, err02, result2); + VERIFY( result2 == digits1 ); + VERIFY( err02 == ios_base::eofbit ); + + iss.str("7.200.000.000,00 a"); + iterator_type is_it03(iss); + string result3; + ios_base::iostate err03 = ios_base::goodbit; + mon_get.get(is_it03, end, true, iss, err03, result3); + VERIFY( result3 == digits1 ); + VERIFY( err03 == ios_base::goodbit ); + + iss.str(""); + iterator_type is_it04(iss); + string result4; + ios_base::iostate err04 = ios_base::goodbit; + mon_get.get(is_it04, end, true, iss, err04, result4); + VERIFY( result4 == empty ); + VERIFY( err04 == ios_base::failbit | ios_base::eofbit ); + + iss.str("working for enlightenment and peace in a mad world"); + iterator_type is_it05(iss); + string result5; + ios_base::iostate err05 = ios_base::goodbit; + mon_get.get(is_it05, end, true, iss, err05, result5); + VERIFY( result5 == empty ); + VERIFY( err05 == ios_base::failbit ); + + // now try with showbase, to get currency symbol in format + iss.setf(ios_base::showbase); + + iss.str("7.200.000.000,00 DEM "); + iterator_type is_it06(iss); + string result6; + ios_base::iostate err06 = ios_base::goodbit; + mon_get.get(is_it06, end, true, iss, err06, result6); + VERIFY( result6 == digits1 ); + VERIFY( err06 == ios_base::eofbit ); + + iss.str("7.200.000.000,00 DEM "); // Extra space. + iterator_type is_it07(iss); + string result7; + ios_base::iostate err07 = ios_base::goodbit; + mon_get.get(is_it07, end, true, iss, err07, result7); + VERIFY( result7 == digits1 ); + VERIFY( err07 == ios_base::goodbit ); + + iss.str("7.200.000.000,00 DM"); + iterator_type is_it08(iss); + string result8; + ios_base::iostate err08 = ios_base::goodbit; + mon_get.get(is_it08, end, false, iss, err08, result8); + VERIFY( result8 == digits1 ); + VERIFY( err08 == ios_base::eofbit ); + + iss.imbue(loc_hk); + iss.str("HK$7,200,000,000.00"); + iterator_type is_it09(iss); + string result9; + ios_base::iostate err09 = ios_base::goodbit; + mon_get.get(is_it09, end, false, iss, err09, result9); + VERIFY( result9 == digits1 ); + VERIFY( err09 == ios_base::eofbit ); + + iss.str("(HKD 100,000,000,000.00)"); + iterator_type is_it10(iss); + string result10; + ios_base::iostate err10 = ios_base::goodbit; + mon_get.get(is_it10, end, true, iss, err10, result10); + VERIFY( result10 == digits2 ); + VERIFY( err10 == ios_base::goodbit ); + + iss.str("(HKD .01)"); + iterator_type is_it11(iss); + string result11; + ios_base::iostate err11 = ios_base::goodbit; + mon_get.get(is_it11, end, true, iss, err11, result11); + VERIFY( result11 == digits4 ); + VERIFY( err11 == ios_base::goodbit ); +} + +// test double/string versions +void test02() +{ + using namespace std; + typedef money_base::part part; + typedef money_base::pattern pattern; + typedef istreambuf_iterator iterator_type; + + bool test = true; + string str; + + // basic construction + locale loc_c = locale::classic(); + str = loc_c.name(); + + locale loc_hk("en_HK"); + str = loc_hk.name(); + VERIFY( loc_c != loc_hk ); + + locale loc_fr("fr_FR@euro"); + str = loc_fr.name(); + VERIFY( loc_c != loc_fr ); + + locale loc_de("de_DE"); + str = loc_de.name(); + VERIFY( loc_c != loc_de ); + + VERIFY( loc_hk != loc_fr ); + VERIFY( loc_hk != loc_de ); + VERIFY( loc_de != loc_fr ); + + // cache the moneypunct facets + typedef moneypunct __money_true; + typedef moneypunct __money_false; + const __money_true& monpunct_c_t = use_facet<__money_true>(loc_c); + const __money_true& monpunct_de_t = use_facet<__money_true>(loc_de); + const __money_false& monpunct_c_f = use_facet<__money_false>(loc_c); + const __money_false& monpunct_de_f = use_facet<__money_false>(loc_de); + const __money_true& monpunct_hk_t = use_facet<__money_true>(loc_hk); + const __money_false& monpunct_hk_f = use_facet<__money_false>(loc_hk); + + // sanity check the data is correct. + const string empty; + + // total EPA budget FY 2002 + const long double digits1 = 720000000000; + + // est. cost, national missle "defense", expressed as a liss in USD 2001 + const long double digits2 = -10000000000000; + + // input less than frac_digits + const long double digits4 = -1; + + iterator_type end; + istringstream iss; + iss.imbue(loc_de); + // cache the money_get facet + const money_get& mon_get = use_facet >(iss.getloc()); + + iss.str("7.200.000.000,00 "); + iterator_type is_it01(iss); + long double result1; + ios_base::iostate err01 = ios_base::goodbit; + mon_get.get(is_it01, end, true, iss, err01, result1); + VERIFY( result1 == digits1 ); + VERIFY( err01 == ios_base::eofbit ); + + iss.str("7.200.000.000,00 "); + iterator_type is_it02(iss); + long double result2; + ios_base::iostate err02 = ios_base::goodbit; + mon_get.get(is_it02, end, false, iss, err02, result2); + VERIFY( result2 == digits1 ); + VERIFY( err02 == ios_base::eofbit ); + + // now try with showbase, to get currency symbol in format + iss.setf(ios_base::showbase); + + iss.imbue(loc_hk); + iss.str("(HKD .01)"); + iterator_type is_it03(iss); + long double result3; + ios_base::iostate err03 = ios_base::goodbit; + mon_get.get(is_it03, end, true, iss, err03, result3); + VERIFY( result3 == digits4 ); + VERIFY( err03 == ios_base::goodbit ); +} + +int main() +{ + test01(); + test02(); + return 0; +} -- 2.7.4