/*************************************************************************** * * _money_get.cc - definition of std::money_get members * * $Id: _money_get.cc 637130 2008-03-14 15:16:33Z faridz $ * *************************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Copyright 2001-2008 Rogue Wave Software, Inc. * **************************************************************************/ #include #include #include #include _RWSTD_NAMESPACE (__rw) { _RWSTD_EXPORT int __rw_get_num (void*, const char*, int, int, const char*, _RWSTD_SIZE_T, const char*, _RWSTD_SIZE_T); _RWSTD_EXPORT int __rw_check_grouping (const char*, _RWSTD_SIZE_T, const char*, _RWSTD_SIZE_T); } // namespace __rw _RWSTD_NAMESPACE (std) { template _RW::__rw_facet_id money_get<_CharT, _InputIter>::id; template _TYPENAME money_get<_CharT, _InputIter>::iter_type money_get<_CharT, _InputIter>:: _C_get (iter_type __it, iter_type __end, bool __intl, ios_base &__flags, _RWSTD_IOSTATE &__err, void *__pval, string_type *__pstr) const { typedef moneypunct<_CharT, false> _Punct0; typedef moneypunct<_CharT, true> _Punct1; const _Punct0 &__pun = __intl ? _RWSTD_REINTERPRET_CAST (const _Punct0&, _RWSTD_USE_FACET (_Punct1, __flags.getloc ())) : _RWSTD_USE_FACET (_Punct0, __flags.getloc ()); // retrieve positive and negative sign, currency symbol, // the grouping string and the pattern format const string_type __ps = __pun.positive_sign (); const string_type __ns = __pun.negative_sign (); const string_type __cs = __pun.curr_symbol (); const string __gr = __pun.grouping (); const money_base::pattern __pat = __pun.neg_format (); _RWSTD_IOSTATE __ebits = _RW::__rw_goodbit; bool __needws = false; // whitespace required? bool __seendp = false; // seen decimal point in input const ctype<_CharT> &__ctp = _RWSTD_USE_FACET (ctype<_CharT>, __flags.getloc ()); char __buf [304]; char *__pcur = __buf; typedef _TYPENAME string_type::traits_type _Traits; char __grpbuf [sizeof __buf]; // holds sizes of discovered groups char *__pgrp = __grpbuf; // current group const char *__grpstart = 0; // the start of the last group const char *__grpend = 0; // the end of the last group int __sign = 0; // the sign of the result if detected (-1, 0, or +1) // buffer must always start with a sign (__rw_get_num requirement) // use a '+' and overwrite it with a '-' if necessary *__pcur++ = '+'; const int __fl = __flags.flags (); typedef _RWSTD_SIZE_T _SizeT; for (_SizeT __i = 0; !__ebits && __i != sizeof __pat.field; ++__i) { switch (__pat.field [__i]) { case /* '\1' */ money_base::space: __needws = true; // fall through... case /* '\0' */ money_base::none: { // optional or even required whitespace is consumed only if // other characters may be required to complete the format if ( sizeof __pat.field == __i + 1 || 2 == __i && money_base::symbol == __pat.field [3] && (!(__fl & _RW::__rw_showbase) || 0 == __cs.size ()) && !( __sign < 0 && __ns.size () > 1 || __sign > 0 && __ps.size () > 1) || 1 == __i && money_base::value == __pat.field [0] && 0 == __ns.size () && 0 == __ps.size () && (0 == __cs.size () || !(__fl & _RW::__rw_showbase))) break; _SizeT __nc = 0; while (__it != __end && __ctp.is (ctype_base::space, *__it)) { ++__it; ++__nc; } if (__needws && !__nc) __ebits |= _RW::__rw_failbit; break; } case /* '\2' */ money_base::symbol: { // if optional, currency symbol is not extracted unless // it is consumed only if it is followed by characters // required to complete the pattern (see example in // 22.2.6.1.2, p3) if ( __fl & _RW::__rw_showbase || __i < 2 || 2 == __i && (money_base::none != __pat.field [3]) || __sign < 0 && __ns.size () > 1 || __sign > 0 && __ps.size () > 1) { for (_SizeT __nc = 0; __nc != __cs.size (); ++__nc, ++__it) { if (__it == __end || !_Traits::eq (*__it, __cs [__nc])) { // 22.2.6.1.2, p2: unless showbase is set, // curr_symbol is optional if (__nc || __fl & _RW::__rw_showbase) __ebits |= _RW::__rw_failbit; break; } } } break; } case /* '\3' */ money_base::sign: { if (__it == __end) { if (__ps.size () && __ns.size ()) __ebits |= _RW::__rw_failbit; else __sign = __ps.empty () - 1; break; } const char_type __c = *__it; // 22.2.6.1.2, p3: if the first character of positive // and negative sign is the same, the result is positive if (__ps.size () && _Traits::eq (__c, __ps [0])) { __sign = 1; ++__it; } else if (__ns.size () && _Traits::eq (__c, __ns [0])) { __sign = -1; ++__it; } break; } case /* '\4' */ money_base::value: { const char_type __ts = __gr.size () && __gr [0] && __gr [0] != _RWSTD_CHAR_MAX ? __pun.thousands_sep () : __ctp.widen ('0'); int __fd = __pun.frac_digits (); for (; __it != __end; ++__it) { // read and narrow a character (note that narrow() may // yield the same narrow char for more than one wide // character; e.g., there may be two sets of digits) const char_type __c = *__it; const char __ch = __ctp.narrow (__c, '\0'); if (__ch >= '0' && __ch <= '9') { if (!__seendp || __fd-- > 0) *__pcur++ = __ch; } else if ( !__seendp && __fd > 0 && _Traits::eq (__c, __pun.decimal_point ())) { __grpend = __pcur; __seendp = true; } else if (!__seendp && _Traits::eq (__c, __ts)) { // add the length of the current group to the array groups // store UCHAR_MAX if group length exceeds the size of char _RWSTD_PTRDIFF_T __len; if (__grpstart) __len = __pcur - __grpstart; else { __grpstart = __pcur; __len = __pcur - __buf - 1; } typedef unsigned char _UChar; *__pgrp++ = char (__len < _UChar (-1) ? __len : -1); __grpstart = __pcur; } else break; } if (__pcur - __buf > 1) { // append zeros to a non-empty string of digits // up to the number of frac_digits while (__fd-- > 0) *__pcur++ = '0'; } *__pcur = '\0'; break; } default: __ebits = _RW::__rw_failbit; break; } } if (!(__ebits & _RW::__rw_failbit)) { if (__buf [1]) { // process the remainder of a multicharacter sign const _SizeT __sizes [] = { __ps.size () ? __ps.size () -1 : 0, __ns.size () ? __ns.size () -1 : 0 }; const char_type* const __names [] = { __ps.data () + !!__sizes [0], __ns.data () + !!__sizes [1] }; if (__sign && (__sizes [0] || __sizes [1])) { // if the first character of a multi-character sign // has been seen, try to extract the rest of the sign _SizeT __inx = 0; int __errtmp = 1; // no duplicates allowed __it = _RW::__rw_match_name (__it, __end, __names, __sizes, sizeof __names / sizeof *__names, __inx, __errtmp, 0); if (1 < __inx && __sizes [__sign < 0]) { // failed to match the remainder of the sign to // the input and the first character of the sign // does not form the complete (positive or negative) // sign __ebits = _RW::__rw_failbit; __buf [1] = '\0'; } else if (!_Traits::eq (*__ps.data (), *__ns.data ())) { // if the first extracted character of the sign string // forms the complete sign whose first character doesn't // form an initial substring of the other sign string // the resulting sign is determined by the one-character // sign string if (1 < __inx) __inx = 0 < __sizes [__sign < 0]; // if both signs begin with the same character, // the result is positive (22.2.6.1.2, p3) *__buf = __inx ? '-' : '+'; __sign = -int (__inx); } } else if (__sign < 0) { *__buf = '-'; } if (__pstr && !(__ebits & _RW::__rw_failbit)) { // skip over the leading sign and any redundant zeros after it const char *__start = __buf + 1; for (; '0' == *__start && '0' == __start [1]; ++__start); // invert the sign if negative __sign = __sign < 0; // widen narrow digits optionally preceded by the minus sign // into the basic_string object as required by 22.2.6.1.2, p1 __pstr->resize ((__pcur - __start) + _SizeT (__sign)); if (__sign) _Traits::assign ((*__pstr)[0], __ctp.widen ('-')); __ctp.widen (__start, __pcur, &(*__pstr)[_SizeT (__sign)]); } const char *__grs = ""; _SizeT __grn = 0; // 22.2.6.1.2, p1: thousands separators are optional // add the length of the last group to the array of groups // store UCHAR_MAX if group length exceeds the size of char if (__grpstart) { const _RWSTD_PTRDIFF_T __len = (__grpend ? __grpend : __pcur) - __grpstart; typedef unsigned char _UChar; *__pgrp++ = char (__len < _UChar (-1) ? __len : -1); *__pgrp = '\0'; __grs = __gr.data (); __grn = __gr.size (); } if (__pval) { // produce a number from the extracted string of digits // and (optionally) check grouping const int __errtmp = _RW::__rw_get_num (__pval, __buf, _C_ldouble, 0, __grpbuf, __pgrp - __grpbuf, __grs, __grn); __ebits |= _RWSTD_IOSTATE (__errtmp); } else if (0 > _RW::__rw_check_grouping (__grpbuf, __pgrp - __grpbuf, __grs, __grn)) __ebits |= _RW::__rw_failbit; } else __ebits |= _RW::__rw_failbit; } if (__it == __end) __ebits |= _RW::__rw_eofbit; __err |= __ebits; return __it; } } // namespace std