| /*************************************************************************** |
| * |
| * _money_get.cc - definition of std::money_get members |
| * |
| * $Id$ |
| * |
| *************************************************************************** |
| * |
| * 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 <streambuf> |
| #include <loc/_ctype.h> |
| #include <loc/_moneypunct.h> |
| #include <rw/_defs.h> |
| |
| |
| _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 <class _CharT, class _InputIter> |
| _RW::__rw_facet_id money_get<_CharT, _InputIter>::id; |
| |
| |
| template <class _CharT, class _InputIter> |
| 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 |