1/* 2 * Copyright (c) 1999 3 * Silicon Graphics Computer Systems, Inc. 4 * 5 * Copyright (c) 1999 6 * Boris Fomitchev 7 * 8 * This material is provided "as is", with absolutely no warranty expressed 9 * or implied. Any use is at your own risk. 10 * 11 * Permission to use or copy this software for any purpose is hereby granted 12 * without fee, provided the above notices are retained on all copies. 13 * Permission to modify the code and to distribute modified code is granted, 14 * provided the above notices are retained, and a notice that the code was 15 * modified is included with the above copyright notice. 16 * 17 */ 18#ifndef _STLP_MONETARY_C 19#define _STLP_MONETARY_C 20 21# ifndef _STLP_INTERNAL_MONETARY_H 22# include <stl/_monetary.h> 23# endif 24 25#ifndef _STLP_INTERNAL_IOS_H 26# include <stl/_ios.h> 27#endif 28 29#ifndef _STLP_INTERNAL_NUM_PUT_H 30# include <stl/_num_put.h> 31#endif 32 33#ifndef _STLP_INTERNAL_NUM_GET_H 34# include <stl/_num_get.h> 35#endif 36 37_STLP_BEGIN_NAMESPACE 38 39template <class _CharT, class _InputIterator> 40locale::id money_get<_CharT, _InputIterator>::id; 41 42template <class _CharT, class _OutputIterator> 43locale::id money_put<_CharT, _OutputIterator>::id; 44 45// money_get facets 46 47_STLP_MOVE_TO_PRIV_NAMESPACE 48 49// helper functions for do_get 50template <class _InIt1, class _InIt2> 51pair<_InIt1, bool> __get_string( _InIt1 __first, _InIt1 __last, 52 _InIt2 __str_first, _InIt2 __str_last) { 53 while ( __first != __last && __str_first != __str_last && *__first == *__str_first ) { 54 ++__first; 55 ++__str_first; 56 } 57 return make_pair(__first, __str_first == __str_last); 58} 59 60template <class _InIt, class _OuIt, class _CharT> 61bool 62__get_monetary_value(_InIt& __first, _InIt __last, _OuIt __out_ite, 63 const ctype<_CharT>& _c_type, 64 _CharT __point, int __frac_digits, _CharT __sep, 65 const string& __grouping, bool &__syntax_ok) { 66 if (__first == __last || !_c_type.is(ctype_base::digit, *__first)) 67 return false; 68 69 char __group_sizes[128]; 70 char* __group_sizes_end = __grouping.empty()? 0 : __group_sizes; 71 char __current_group_size = 0; 72 73 while (__first != __last) { 74 if (_c_type.is(ctype_base::digit, *__first)) { 75 ++__current_group_size; 76 *__out_ite++ = *__first++; 77 } 78 else if (__group_sizes_end) { 79 if (*__first == __sep) { 80 *__group_sizes_end++ = __current_group_size; 81 __current_group_size = 0; 82 ++__first; 83 } 84 else break; 85 } 86 else 87 break; 88 } 89 90 if (__grouping.empty()) 91 __syntax_ok = true; 92 else { 93 if (__group_sizes_end != __group_sizes) 94 *__group_sizes_end++ = __current_group_size; 95 96 __syntax_ok = __valid_grouping(__group_sizes, __group_sizes_end, 97 __grouping.data(), __grouping.data()+ __grouping.size()); 98 99 if (__first == __last || *__first != __point) { 100 for (int __digits = 0; __digits != __frac_digits; ++__digits) 101 *__out_ite++ = _CharT('0'); 102 return true; // OK not to have decimal point 103 } 104 } 105 106 ++__first; 107 108 int __digits = 0; 109 110 while (__first != __last && _c_type.is(ctype_base::digit, *__first)) { 111 *__out_ite++ = *__first++; 112 ++__digits; 113 } 114 115 __syntax_ok = __syntax_ok && (__digits == __frac_digits); 116 117 return true; 118} 119 120 121template <class _CharT, class _InputIter, class _StrType> 122_InputIter __money_do_get(_InputIter __s, _InputIter __end, bool __intl, 123 ios_base& __str, ios_base::iostate& __err, 124 _StrType& __digits, bool &__is_positive, _CharT* /*__dummy*/) { 125 if (__s == __end) { 126 __err |= ios_base::eofbit; 127 return __s; 128 } 129 130 typedef _CharT char_type; 131 typedef _StrType string_type; 132 typedef _InputIter iter_type; 133 typedef moneypunct<char_type, false> _Punct; 134 typedef moneypunct<char_type, true> _Punct_intl; 135 typedef ctype<char_type> _Ctype; 136 137 locale __loc = __str.getloc(); 138 const _Punct& __punct = use_facet<_Punct>(__loc) ; 139 const _Punct_intl& __punct_intl = use_facet<_Punct_intl>(__loc) ; 140 const _Ctype& __c_type = use_facet<_Ctype>(__loc) ; 141 142 money_base::pattern __format = __intl ? __punct_intl.neg_format() 143 : __punct.neg_format(); 144 string_type __ns = __intl ? __punct_intl.negative_sign() 145 : __punct.negative_sign(); 146 string_type __ps = __intl ? __punct_intl.positive_sign() 147 : __punct.positive_sign(); 148 int __i; 149 bool __symbol_required = (__str.flags() & ios_base::showbase) != 0; 150 string_type __buf; 151 back_insert_iterator<string_type> __out_ite(__buf); 152 153 for (__i = 0; __i < 4; ++__i) { 154 switch (__format.field[__i]) { 155 case money_base::space: 156 if (!__c_type.is(ctype_base::space, *__s)) { 157 __err = ios_base::failbit; 158 return __s; 159 } 160 ++__s; 161 case money_base::none: 162 while (__s != __end && __c_type.is(ctype_base::space, *__s)) 163 ++__s; 164 break; 165 case money_base::symbol: { 166 string_type __curs = __intl ? __punct_intl.curr_symbol() 167 : __punct.curr_symbol(); 168 pair<iter_type, bool> 169 __result = __get_string(__s, __end, __curs.begin(), __curs.end()); 170 if (!__result.second && __symbol_required) 171 __err = ios_base::failbit; 172 __s = __result.first; 173 break; 174 } 175 case money_base::sign: { 176 if (__s == __end) { 177 if (__ps.empty()) 178 break; 179 if (__ns.empty()) { 180 __is_positive = false; 181 break; 182 } 183 __err = ios_base::failbit; 184 return __s; 185 } 186 else { 187 if (__ps.empty()) { 188 if (__ns.empty()) 189 break; 190 if (*__s == __ns[0]) { 191 ++__s; 192 __is_positive = false; 193 } 194 break; 195 } 196 else { 197 if (*__s == __ps[0]) { 198 ++__s; 199 break; 200 } 201 if (__ns.empty()) 202 break; 203 if (*__s == __ns[0]) { 204 ++__s; 205 __is_positive = false; 206 break; 207 } 208 __err = ios_base::failbit; 209 } 210 } 211 return __s; 212 } 213 case money_base::value: { 214 char_type __point = __intl ? __punct_intl.decimal_point() 215 : __punct.decimal_point(); 216 int __frac_digits = __intl ? __punct_intl.frac_digits() 217 : __punct.frac_digits(); 218 string __grouping = __intl ? __punct_intl.grouping() 219 : __punct.grouping(); 220 bool __syntax_ok = true; 221 222 bool __result; 223 224 char_type __sep = __grouping.empty() ? char_type() : 225 __intl ? __punct_intl.thousands_sep() : __punct.thousands_sep(); 226 227 __result = __get_monetary_value(__s, __end, __out_ite, __c_type, 228 __point, __frac_digits, 229 __sep, 230 __grouping, __syntax_ok); 231 232 if (!__syntax_ok) 233 __err |= ios_base::failbit; 234 if (!__result) { 235 __err = ios_base::failbit; 236 return __s; 237 } 238 break; 239 240 } // Close money_base::value case 241 } // Close switch statement 242 } // Close for loop 243 244 if (__is_positive) { 245 if (__ps.size() > 1) { 246 pair<_InputIter, bool> 247 __result = __get_string(__s, __end, __ps.begin() + 1, __ps.end()); 248 __s = __result.first; 249 if (!__result.second) 250 __err |= ios::failbit; 251 } 252 if (!(__err & ios_base::failbit)) 253 __digits = __buf; 254 } 255 else { 256 if (__ns.size() > 1) { 257 pair<_InputIter, bool> 258 __result = __get_string(__s, __end, __ns.begin() + 1, __ns.end()); 259 __s = __result.first; 260 if (!__result.second) 261 __err |= ios::failbit; 262 } 263 if (!(__err & ios::failbit)) { 264 __digits = __c_type.widen('-'); 265 __digits += __buf; 266 } 267 } 268 if (__s == __end) 269 __err |= ios::eofbit; 270 271 return __s; 272} 273 274_STLP_MOVE_TO_STD_NAMESPACE 275 276//===== methods ====== 277template <class _CharT, class _InputIter> 278_InputIter 279money_get<_CharT, _InputIter>::do_get(_InputIter __s, _InputIter __end, bool __intl, 280 ios_base& __str, ios_base::iostate& __err, 281 _STLP_LONGEST_FLOAT_TYPE& __units) const { 282 string_type __buf; 283 bool __is_positive = true; 284 __s = _STLP_PRIV __money_do_get(__s, __end, __intl, __str, __err, __buf, __is_positive, (_CharT*)0); 285 286 if (__err == ios_base::goodbit || __err == ios_base::eofbit) { 287 typename string_type::iterator __b = __buf.begin(), __e = __buf.end(); 288 289 if (!__is_positive) ++__b; 290 // Can't use atold, since it might be wchar_t. Don't get confused by name below : 291 // it's perfectly capable of reading long double. 292 _STLP_PRIV __get_decimal_integer(__b, __e, __units, (_CharT*)0); 293 294 if (!__is_positive) { 295 __units = -__units; 296 } 297 } 298 299 return __s; 300} 301 302template <class _CharT, class _InputIter> 303_InputIter 304money_get<_CharT, _InputIter>::do_get(iter_type __s, iter_type __end, bool __intl, 305 ios_base& __str, ios_base::iostate& __err, 306 string_type& __digits) const { 307 bool __is_positive = true; 308 return _STLP_PRIV __money_do_get(__s, __end, __intl, __str, __err, __digits, __is_positive, (_CharT*)0); 309} 310 311// money_put facets 312 313_STLP_MOVE_TO_PRIV_NAMESPACE 314 315template <class _CharT, class _OutputIter, class _Str_Type, class _Str> 316_OutputIter __money_do_put(_OutputIter __s, bool __intl, ios_base& __str, 317 _CharT __fill, const _Str& __digits, bool __check_digits, 318 _Str_Type * /*__dummy*/) { 319 typedef _CharT char_type; 320 typedef _Str_Type string_type; 321 typedef ctype<char_type> _Ctype; 322 typedef moneypunct<char_type, false> _Punct; 323 typedef moneypunct<char_type, true> _Punct_intl; 324 325 locale __loc = __str.getloc(); 326 const _Ctype& __c_type = use_facet<_Ctype>(__loc) ; 327 const _Punct& __punct = use_facet<_Punct>(__loc) ; 328 const _Punct_intl& __punct_intl = use_facet<_Punct_intl>(__loc) ; 329 330 // some special characters 331 char_type __minus = __c_type.widen('-'); 332 char_type __plus = __c_type.widen('+'); 333 char_type __space = __c_type.widen(' '); 334 char_type __zero = __c_type.widen('0'); 335 char_type __point = __intl ? __punct_intl.decimal_point() 336 : __punct.decimal_point(); 337 338 char_type __sep = __intl ? __punct_intl.thousands_sep() 339 : __punct.thousands_sep(); 340 341 string __grouping = __intl ? __punct_intl.grouping() 342 : __punct.grouping(); 343 344 int __frac_digits = __intl ? __punct_intl.frac_digits() 345 : __punct.frac_digits(); 346 347 string_type __curr_sym = __intl ? __punct_intl.curr_symbol() 348 : __punct.curr_symbol(); 349 350 // if there are no digits we are going to return __s. If there 351 // are digits, but not enough to fill the frac_digits, we are 352 // going to add zeros. I don't know whether this is right or 353 // not. 354 if (__digits.empty()) 355 return __s; 356 357 typename string_type::const_iterator __digits_first = __digits.begin(); 358 typename string_type::const_iterator __digits_last = __digits.end(); 359 360 bool __is_negative = *__digits_first == __minus; 361 if (__is_negative) 362 ++__digits_first; 363 364#if !defined (__BORLANDC__) 365 string_type __sign = __intl ? __is_negative ? __punct_intl.negative_sign() 366 : __punct_intl.positive_sign() 367 : __is_negative ? __punct.negative_sign() 368 : __punct.positive_sign(); 369#else 370 string_type __sign; 371 if (__intl) { 372 if (__is_negative) 373 __sign = __punct_intl.negative_sign(); 374 else 375 __sign = __punct_intl.positive_sign(); 376 } 377 else { 378 if (__is_negative) 379 __sign = __punct.negative_sign(); 380 else 381 __sign = __punct.positive_sign(); 382 } 383#endif 384 385 if (__check_digits) { 386 typename string_type::const_iterator __cp = __digits_first; 387 while (__cp != __digits_last && __c_type.is(ctype_base::digit, *__cp)) 388 ++__cp; 389 if (__cp == __digits_first) 390 return __s; 391 __digits_last = __cp; 392 } 393 394 // If grouping is required, we make a copy of __digits and 395 // insert the grouping. 396 _STLP_BASIC_IOSTRING(char_type) __new_digits; 397 if (!__grouping.empty()) { 398 __new_digits.assign(__digits_first, __digits_last); 399 __insert_grouping(__new_digits, 400 __new_digits.size() - __frac_digits, 401 __grouping, 402 __sep, __plus, __minus, 0); 403 __digits_first = __new_digits.begin(); // <<-- 404 __digits_last = __new_digits.end(); // <<-- 405 } 406 407 // Determine the amount of padding required, if any. 408 streamsize __width = __str.width(); 409 410#if defined (_STLP_DEBUG) && (defined(__HP_aCC) && (__HP_aCC <= 1)) 411 size_t __value_length = operator -(__digits_last, __digits_first); 412#else 413 size_t __value_length = __digits_last - __digits_first; 414#endif 415 416 size_t __length = __value_length + __sign.size(); 417 418 if (__frac_digits != 0) 419 ++__length; 420 421 bool __generate_curr = (__str.flags() & ios_base::showbase) !=0; 422 if (__generate_curr) 423 __length += __curr_sym.size(); 424 money_base::pattern __format = __intl ? (__is_negative ? __punct_intl.neg_format() 425 : __punct_intl.pos_format()) 426 : (__is_negative ? __punct.neg_format() 427 : __punct.pos_format()); 428 { 429 //For the moment the following is commented for decoding reason. 430 //No reason to add a space last if the money symbol do not have to be display 431 //if (__format.field[3] == (char) money_base::symbol && !__generate_curr) { 432 // if (__format.field[2] == (char) money_base::space) { 433 // __format.field[2] = (char) money_base::none; 434 // } 435 //} 436 //space can only be second or third and only once (22.2.6.3-1): 437 if ((__format.field[1] == (char) money_base::space) || 438 (__format.field[2] == (char) money_base::space)) 439 ++__length; 440 } 441 442 const bool __need_fill = (((sizeof(streamsize) > sizeof(size_t)) && (__STATIC_CAST(streamsize, __length) < __width)) || 443 ((sizeof(streamsize) <= sizeof(size_t)) && (__length < __STATIC_CAST(size_t, __width)))); 444 streamsize __fill_amt = __need_fill ? __width - __length : 0; 445 446 ios_base::fmtflags __fill_pos = __str.flags() & ios_base::adjustfield; 447 448 if (__fill_amt != 0 && 449 !(__fill_pos & (ios_base::left | ios_base::internal))) 450 __s = _STLP_PRIV __fill_n(__s, __fill_amt, __fill); 451 452 for (int __i = 0; __i < 4; ++__i) { 453 char __ffield = __format.field[__i]; 454 switch (__ffield) { 455 case money_base::space: 456 *__s++ = __space; 457 case money_base::none: 458 if (__fill_amt != 0 && __fill_pos == ios_base::internal) 459 __s = _STLP_PRIV __fill_n(__s, __fill_amt, __fill); 460 break; 461 case money_base::symbol: 462 if (__generate_curr) 463 __s = _STLP_STD::copy(__curr_sym.begin(), __curr_sym.end(), __s); 464 break; 465 case money_base::sign: 466 if (!__sign.empty()) 467 *__s++ = __sign[0]; 468 break; 469 case money_base::value: 470 if (__frac_digits == 0) { 471 __s = _STLP_STD::copy(__digits_first, __digits_last, __s); 472 } else { 473 if ((int)__value_length <= __frac_digits) { 474 // if we see '9' here, we should out 0.09 475 *__s++ = __zero; // integer part is zero 476 *__s++ = __point; // decimal point 477 __s = _STLP_PRIV __fill_n(__s, __frac_digits - __value_length, __zero); // zeros 478 __s = _STLP_STD::copy(__digits_first, __digits_last, __s); // digits 479 } else { 480 __s = _STLP_STD::copy(__digits_first, __digits_last - __frac_digits, __s); 481 if (__frac_digits != 0) { 482 *__s++ = __point; 483 __s = _STLP_STD::copy(__digits_last - __frac_digits, __digits_last, __s); 484 } 485 } 486 } 487 break; 488 } //Close for switch 489 } // Close for loop 490 491 // Ouput rest of sign if necessary. 492 if (__sign.size() > 1) 493 __s = _STLP_STD::copy(__sign.begin() + 1, __sign.end(), __s); 494 if (__fill_amt != 0 && 495 !(__fill_pos & (ios_base::right | ios_base::internal))) 496 __s = _STLP_PRIV __fill_n(__s, __fill_amt, __fill); 497 498 return __s; 499} 500 501_STLP_MOVE_TO_STD_NAMESPACE 502 503template <class _CharT, class _OutputIter> 504_OutputIter 505money_put<_CharT, _OutputIter> 506 ::do_put(_OutputIter __s, bool __intl, ios_base& __str, 507 char_type __fill, _STLP_LONGEST_FLOAT_TYPE __units) const { 508 _STLP_BASIC_IOSTRING(char_type) __digits; 509 _STLP_PRIV __get_money_digits(__digits, __str, __units); 510 return _STLP_PRIV __money_do_put(__s, __intl, __str, __fill, __digits, false, __STATIC_CAST(string_type*, 0)); 511} 512 513template <class _CharT, class _OutputIter> 514_OutputIter 515money_put<_CharT, _OutputIter> 516 ::do_put(_OutputIter __s, bool __intl, ios_base& __str, 517 char_type __fill, const string_type& __digits) const { 518 return _STLP_PRIV __money_do_put(__s, __intl, __str, __fill, __digits, true, __STATIC_CAST(string_type*, 0)); 519} 520 521_STLP_END_NAMESPACE 522 523#endif /* _STLP_MONETARY_C */ 524 525// Local Variables: 526// mode:C++ 527// End: 528