1 // Locale support -*- C++ -*- 2 3 // Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 /** @file locale_facets_nonio.tcc 26 * This is an internal header file, included by other library headers. 27 * You should not attempt to use it directly. 28 */ 29 30 #ifndef _LOCALE_FACETS_NONIO_TCC 31 #define _LOCALE_FACETS_NONIO_TCC 1 32 33 #pragma GCC system_header 34 35 _GLIBCXX_BEGIN_NAMESPACE(std) 36 37 template<typename _CharT, bool _Intl> 38 struct __use_cache<__moneypunct_cache<_CharT, _Intl> > 39 { 40 const __moneypunct_cache<_CharT, _Intl>* 41 operator() (const locale& __loc) const 42 { 43 const size_t __i = moneypunct<_CharT, _Intl>::id._M_id(); 44 const locale::facet** __caches = __loc._M_impl->_M_caches; 45 if (!__caches[__i]) 46 { 47 __moneypunct_cache<_CharT, _Intl>* __tmp = NULL; 48 __try 49 { 50 __tmp = new __moneypunct_cache<_CharT, _Intl>; 51 __tmp->_M_cache(__loc); 52 } 53 __catch(...) 54 { 55 delete __tmp; 56 __throw_exception_again; 57 } 58 __loc._M_impl->_M_install_cache(__tmp, __i); 59 } 60 return static_cast< 61 const __moneypunct_cache<_CharT, _Intl>*>(__caches[__i]); 62 } 63 }; 64 65 template<typename _CharT, bool _Intl> 66 void 67 __moneypunct_cache<_CharT, _Intl>::_M_cache(const locale& __loc) 68 { 69 _M_allocated = true; 70 71 const moneypunct<_CharT, _Intl>& __mp = 72 use_facet<moneypunct<_CharT, _Intl> >(__loc); 73 74 _M_grouping_size = __mp.grouping().size(); 75 char* __grouping = new char[_M_grouping_size]; 76 __mp.grouping().copy(__grouping, _M_grouping_size); 77 _M_grouping = __grouping; 78 _M_use_grouping = (_M_grouping_size 79 && static_cast<signed char>(_M_grouping[0]) > 0 80 && (_M_grouping[0] 81 != __gnu_cxx::__numeric_traits<char>::__max)); 82 83 _M_decimal_point = __mp.decimal_point(); 84 _M_thousands_sep = __mp.thousands_sep(); 85 _M_frac_digits = __mp.frac_digits(); 86 87 _M_curr_symbol_size = __mp.curr_symbol().size(); 88 _CharT* __curr_symbol = new _CharT[_M_curr_symbol_size]; 89 __mp.curr_symbol().copy(__curr_symbol, _M_curr_symbol_size); 90 _M_curr_symbol = __curr_symbol; 91 92 _M_positive_sign_size = __mp.positive_sign().size(); 93 _CharT* __positive_sign = new _CharT[_M_positive_sign_size]; 94 __mp.positive_sign().copy(__positive_sign, _M_positive_sign_size); 95 _M_positive_sign = __positive_sign; 96 97 _M_negative_sign_size = __mp.negative_sign().size(); 98 _CharT* __negative_sign = new _CharT[_M_negative_sign_size]; 99 __mp.negative_sign().copy(__negative_sign, _M_negative_sign_size); 100 _M_negative_sign = __negative_sign; 101 102 _M_pos_format = __mp.pos_format(); 103 _M_neg_format = __mp.neg_format(); 104 105 const ctype<_CharT>& __ct = use_facet<ctype<_CharT> >(__loc); 106 __ct.widen(money_base::_S_atoms, 107 money_base::_S_atoms + money_base::_S_end, _M_atoms); 108 } 109 110 _GLIBCXX_BEGIN_LDBL_NAMESPACE 111 112 template<typename _CharT, typename _InIter> 113 template<bool _Intl> 114 _InIter 115 money_get<_CharT, _InIter>:: 116 _M_extract(iter_type __beg, iter_type __end, ios_base& __io, 117 ios_base::iostate& __err, string& __units) const 118 { 119 typedef char_traits<_CharT> __traits_type; 120 typedef typename string_type::size_type size_type; 121 typedef money_base::part part; 122 typedef __moneypunct_cache<_CharT, _Intl> __cache_type; 123 124 const locale& __loc = __io._M_getloc(); 125 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc); 126 127 __use_cache<__cache_type> __uc; 128 const __cache_type* __lc = __uc(__loc); 129 const char_type* __lit = __lc->_M_atoms; 130 131 // Deduced sign. 132 bool __negative = false; 133 // Sign size. 134 size_type __sign_size = 0; 135 // True if sign is mandatory. 136 const bool __mandatory_sign = (__lc->_M_positive_sign_size 137 && __lc->_M_negative_sign_size); 138 // String of grouping info from thousands_sep plucked from __units. 139 string __grouping_tmp; 140 if (__lc->_M_use_grouping) 141 __grouping_tmp.reserve(32); 142 // Last position before the decimal point. 143 int __last_pos = 0; 144 // Separator positions, then, possibly, fractional digits. 145 int __n = 0; 146 // If input iterator is in a valid state. 147 bool __testvalid = true; 148 // Flag marking when a decimal point is found. 149 bool __testdecfound = false; 150 151 // The tentative returned string is stored here. 152 string __res; 153 __res.reserve(32); 154 155 const char_type* __lit_zero = __lit + money_base::_S_zero; 156 const money_base::pattern __p = __lc->_M_neg_format; 157 for (int __i = 0; __i < 4 && __testvalid; ++__i) 158 { 159 const part __which = static_cast<part>(__p.field[__i]); 160 switch (__which) 161 { 162 case money_base::symbol: 163 // According to 22.2.6.1.2, p2, symbol is required 164 // if (__io.flags() & ios_base::showbase), otherwise 165 // is optional and consumed only if other characters 166 // are needed to complete the format. 167 if (__io.flags() & ios_base::showbase || __sign_size > 1 168 || __i == 0 169 || (__i == 1 && (__mandatory_sign 170 || (static_cast<part>(__p.field[0]) 171 == money_base::sign) 172 || (static_cast<part>(__p.field[2]) 173 == money_base::space))) 174 || (__i == 2 && ((static_cast<part>(__p.field[3]) 175 == money_base::value) 176 || (__mandatory_sign 177 && (static_cast<part>(__p.field[3]) 178 == money_base::sign))))) 179 { 180 const size_type __len = __lc->_M_curr_symbol_size; 181 size_type __j = 0; 182 for (; __beg != __end && __j < __len 183 && *__beg == __lc->_M_curr_symbol[__j]; 184 ++__beg, ++__j); 185 if (__j != __len 186 && (__j || __io.flags() & ios_base::showbase)) 187 __testvalid = false; 188 } 189 break; 190 case money_base::sign: 191 // Sign might not exist, or be more than one character long. 192 if (__lc->_M_positive_sign_size && __beg != __end 193 && *__beg == __lc->_M_positive_sign[0]) 194 { 195 __sign_size = __lc->_M_positive_sign_size; 196 ++__beg; 197 } 198 else if (__lc->_M_negative_sign_size && __beg != __end 199 && *__beg == __lc->_M_negative_sign[0]) 200 { 201 __negative = true; 202 __sign_size = __lc->_M_negative_sign_size; 203 ++__beg; 204 } 205 else if (__lc->_M_positive_sign_size 206 && !__lc->_M_negative_sign_size) 207 // "... if no sign is detected, the result is given the sign 208 // that corresponds to the source of the empty string" 209 __negative = true; 210 else if (__mandatory_sign) 211 __testvalid = false; 212 break; 213 case money_base::value: 214 // Extract digits, remove and stash away the 215 // grouping of found thousands separators. 216 for (; __beg != __end; ++__beg) 217 { 218 const char_type __c = *__beg; 219 const char_type* __q = __traits_type::find(__lit_zero, 220 10, __c); 221 if (__q != 0) 222 { 223 __res += money_base::_S_atoms[__q - __lit]; 224 ++__n; 225 } 226 else if (__c == __lc->_M_decimal_point 227 && !__testdecfound) 228 { 229 if (__lc->_M_frac_digits <= 0) 230 break; 231 232 __last_pos = __n; 233 __n = 0; 234 __testdecfound = true; 235 } 236 else if (__lc->_M_use_grouping 237 && __c == __lc->_M_thousands_sep 238 && !__testdecfound) 239 { 240 if (__n) 241 { 242 // Mark position for later analysis. 243 __grouping_tmp += static_cast<char>(__n); 244 __n = 0; 245 } 246 else 247 { 248 __testvalid = false; 249 break; 250 } 251 } 252 else 253 break; 254 } 255 if (__res.empty()) 256 __testvalid = false; 257 break; 258 case money_base::space: 259 // At least one space is required. 260 if (__beg != __end && __ctype.is(ctype_base::space, *__beg)) 261 ++__beg; 262 else 263 __testvalid = false; 264 case money_base::none: 265 // Only if not at the end of the pattern. 266 if (__i != 3) 267 for (; __beg != __end 268 && __ctype.is(ctype_base::space, *__beg); ++__beg); 269 break; 270 } 271 } 272 273 // Need to get the rest of the sign characters, if they exist. 274 if (__sign_size > 1 && __testvalid) 275 { 276 const char_type* __sign = __negative ? __lc->_M_negative_sign 277 : __lc->_M_positive_sign; 278 size_type __i = 1; 279 for (; __beg != __end && __i < __sign_size 280 && *__beg == __sign[__i]; ++__beg, ++__i); 281 282 if (__i != __sign_size) 283 __testvalid = false; 284 } 285 286 if (__testvalid) 287 { 288 // Strip leading zeros. 289 if (__res.size() > 1) 290 { 291 const size_type __first = __res.find_first_not_of('0'); 292 const bool __only_zeros = __first == string::npos; 293 if (__first) 294 __res.erase(0, __only_zeros ? __res.size() - 1 : __first); 295 } 296 297 // 22.2.6.1.2, p4 298 if (__negative && __res[0] != '0') 299 __res.insert(__res.begin(), '-'); 300 301 // Test for grouping fidelity. 302 if (__grouping_tmp.size()) 303 { 304 // Add the ending grouping. 305 __grouping_tmp += static_cast<char>(__testdecfound ? __last_pos 306 : __n); 307 if (!std::__verify_grouping(__lc->_M_grouping, 308 __lc->_M_grouping_size, 309 __grouping_tmp)) 310 __err |= ios_base::failbit; 311 } 312 313 // Iff not enough digits were supplied after the decimal-point. 314 if (__testdecfound && __n != __lc->_M_frac_digits) 315 __testvalid = false; 316 } 317 318 // Iff valid sequence is not recognized. 319 if (!__testvalid) 320 __err |= ios_base::failbit; 321 else 322 __units.swap(__res); 323 324 // Iff no more characters are available. 325 if (__beg == __end) 326 __err |= ios_base::eofbit; 327 return __beg; 328 } 329 330 #if defined _GLIBCXX_LONG_DOUBLE_COMPAT && defined __LONG_DOUBLE_128__ 331 template<typename _CharT, typename _InIter> 332 _InIter 333 money_get<_CharT, _InIter>:: 334 __do_get(iter_type __beg, iter_type __end, bool __intl, ios_base& __io, 335 ios_base::iostate& __err, double& __units) const 336 { 337 string __str; 338 __beg = __intl ? _M_extract<true>(__beg, __end, __io, __err, __str) 339 : _M_extract<false>(__beg, __end, __io, __err, __str); 340 std::__convert_to_v(__str.c_str(), __units, __err, _S_get_c_locale()); 341 return __beg; 342 } 343 #endif 344 345 template<typename _CharT, typename _InIter> 346 _InIter 347 money_get<_CharT, _InIter>:: 348 do_get(iter_type __beg, iter_type __end, bool __intl, ios_base& __io, 349 ios_base::iostate& __err, long double& __units) const 350 { 351 string __str; 352 __beg = __intl ? _M_extract<true>(__beg, __end, __io, __err, __str) 353 : _M_extract<false>(__beg, __end, __io, __err, __str); 354 std::__convert_to_v(__str.c_str(), __units, __err, _S_get_c_locale()); 355 return __beg; 356 } 357 358 template<typename _CharT, typename _InIter> 359 _InIter 360 money_get<_CharT, _InIter>:: 361 do_get(iter_type __beg, iter_type __end, bool __intl, ios_base& __io, 362 ios_base::iostate& __err, string_type& __digits) const 363 { 364 typedef typename string::size_type size_type; 365 366 const locale& __loc = __io._M_getloc(); 367 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc); 368 369 string __str; 370 __beg = __intl ? _M_extract<true>(__beg, __end, __io, __err, __str) 371 : _M_extract<false>(__beg, __end, __io, __err, __str); 372 const size_type __len = __str.size(); 373 if (__len) 374 { 375 __digits.resize(__len); 376 __ctype.widen(__str.data(), __str.data() + __len, &__digits[0]); 377 } 378 return __beg; 379 } 380 381 template<typename _CharT, typename _OutIter> 382 template<bool _Intl> 383 _OutIter 384 money_put<_CharT, _OutIter>:: 385 _M_insert(iter_type __s, ios_base& __io, char_type __fill, 386 const string_type& __digits) const 387 { 388 typedef typename string_type::size_type size_type; 389 typedef money_base::part part; 390 typedef __moneypunct_cache<_CharT, _Intl> __cache_type; 391 392 const locale& __loc = __io._M_getloc(); 393 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc); 394 395 __use_cache<__cache_type> __uc; 396 const __cache_type* __lc = __uc(__loc); 397 const char_type* __lit = __lc->_M_atoms; 398 399 // Determine if negative or positive formats are to be used, and 400 // discard leading negative_sign if it is present. 401 const char_type* __beg = __digits.data(); 402 403 money_base::pattern __p; 404 const char_type* __sign; 405 size_type __sign_size; 406 if (!(*__beg == __lit[money_base::_S_minus])) 407 { 408 __p = __lc->_M_pos_format; 409 __sign = __lc->_M_positive_sign; 410 __sign_size = __lc->_M_positive_sign_size; 411 } 412 else 413 { 414 __p = __lc->_M_neg_format; 415 __sign = __lc->_M_negative_sign; 416 __sign_size = __lc->_M_negative_sign_size; 417 if (__digits.size()) 418 ++__beg; 419 } 420 421 // Look for valid numbers in the ctype facet within input digits. 422 size_type __len = __ctype.scan_not(ctype_base::digit, __beg, 423 __beg + __digits.size()) - __beg; 424 if (__len) 425 { 426 // Assume valid input, and attempt to format. 427 // Break down input numbers into base components, as follows: 428 // final_value = grouped units + (decimal point) + (digits) 429 string_type __value; 430 __value.reserve(2 * __len); 431 432 // Add thousands separators to non-decimal digits, per 433 // grouping rules. 434 long __paddec = __len - __lc->_M_frac_digits; 435 if (__paddec > 0) 436 { 437 if (__lc->_M_frac_digits < 0) 438 __paddec = __len; 439 if (__lc->_M_grouping_size) 440 { 441 __value.assign(2 * __paddec, char_type()); 442 _CharT* __vend = 443 std::__add_grouping(&__value[0], __lc->_M_thousands_sep, 444 __lc->_M_grouping, 445 __lc->_M_grouping_size, 446 __beg, __beg + __paddec); 447 __value.erase(__vend - &__value[0]); 448 } 449 else 450 __value.assign(__beg, __paddec); 451 } 452 453 // Deal with decimal point, decimal digits. 454 if (__lc->_M_frac_digits > 0) 455 { 456 __value += __lc->_M_decimal_point; 457 if (__paddec >= 0) 458 __value.append(__beg + __paddec, __lc->_M_frac_digits); 459 else 460 { 461 // Have to pad zeros in the decimal position. 462 __value.append(-__paddec, __lit[money_base::_S_zero]); 463 __value.append(__beg, __len); 464 } 465 } 466 467 // Calculate length of resulting string. 468 const ios_base::fmtflags __f = __io.flags() 469 & ios_base::adjustfield; 470 __len = __value.size() + __sign_size; 471 __len += ((__io.flags() & ios_base::showbase) 472 ? __lc->_M_curr_symbol_size : 0); 473 474 string_type __res; 475 __res.reserve(2 * __len); 476 477 const size_type __width = static_cast<size_type>(__io.width()); 478 const bool __testipad = (__f == ios_base::internal 479 && __len < __width); 480 // Fit formatted digits into the required pattern. 481 for (int __i = 0; __i < 4; ++__i) 482 { 483 const part __which = static_cast<part>(__p.field[__i]); 484 switch (__which) 485 { 486 case money_base::symbol: 487 if (__io.flags() & ios_base::showbase) 488 __res.append(__lc->_M_curr_symbol, 489 __lc->_M_curr_symbol_size); 490 break; 491 case money_base::sign: 492 // Sign might not exist, or be more than one 493 // character long. In that case, add in the rest 494 // below. 495 if (__sign_size) 496 __res += __sign[0]; 497 break; 498 case money_base::value: 499 __res += __value; 500 break; 501 case money_base::space: 502 // At least one space is required, but if internal 503 // formatting is required, an arbitrary number of 504 // fill spaces will be necessary. 505 if (__testipad) 506 __res.append(__width - __len, __fill); 507 else 508 __res += __fill; 509 break; 510 case money_base::none: 511 if (__testipad) 512 __res.append(__width - __len, __fill); 513 break; 514 } 515 } 516 517 // Special case of multi-part sign parts. 518 if (__sign_size > 1) 519 __res.append(__sign + 1, __sign_size - 1); 520 521 // Pad, if still necessary. 522 __len = __res.size(); 523 if (__width > __len) 524 { 525 if (__f == ios_base::left) 526 // After. 527 __res.append(__width - __len, __fill); 528 else 529 // Before. 530 __res.insert(0, __width - __len, __fill); 531 __len = __width; 532 } 533 534 // Write resulting, fully-formatted string to output iterator. 535 __s = std::__write(__s, __res.data(), __len); 536 } 537 __io.width(0); 538 return __s; 539 } 540 541 #if defined _GLIBCXX_LONG_DOUBLE_COMPAT && defined __LONG_DOUBLE_128__ 542 template<typename _CharT, typename _OutIter> 543 _OutIter 544 money_put<_CharT, _OutIter>:: 545 __do_put(iter_type __s, bool __intl, ios_base& __io, char_type __fill, 546 double __units) const 547 { return this->do_put(__s, __intl, __io, __fill, (long double) __units); } 548 #endif 549 550 template<typename _CharT, typename _OutIter> 551 _OutIter 552 money_put<_CharT, _OutIter>:: 553 do_put(iter_type __s, bool __intl, ios_base& __io, char_type __fill, 554 long double __units) const 555 { 556 const locale __loc = __io.getloc(); 557 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc); 558 #ifdef _GLIBCXX_USE_C99 559 // First try a buffer perhaps big enough. 560 int __cs_size = 64; 561 char* __cs = static_cast<char*>(__builtin_alloca(__cs_size)); 562 // _GLIBCXX_RESOLVE_LIB_DEFECTS 563 // 328. Bad sprintf format modifier in money_put<>::do_put() 564 int __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size, 565 "%.*Lf", 0, __units); 566 // If the buffer was not large enough, try again with the correct size. 567 if (__len >= __cs_size) 568 { 569 __cs_size = __len + 1; 570 __cs = static_cast<char*>(__builtin_alloca(__cs_size)); 571 __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size, 572 "%.*Lf", 0, __units); 573 } 574 #else 575 // max_exponent10 + 1 for the integer part, + 2 for sign and '\0'. 576 const int __cs_size = 577 __gnu_cxx::__numeric_traits<long double>::__max_exponent10 + 3; 578 char* __cs = static_cast<char*>(__builtin_alloca(__cs_size)); 579 int __len = std::__convert_from_v(_S_get_c_locale(), __cs, 0, "%.*Lf", 580 0, __units); 581 #endif 582 string_type __digits(__len, char_type()); 583 __ctype.widen(__cs, __cs + __len, &__digits[0]); 584 return __intl ? _M_insert<true>(__s, __io, __fill, __digits) 585 : _M_insert<false>(__s, __io, __fill, __digits); 586 } 587 588 template<typename _CharT, typename _OutIter> 589 _OutIter 590 money_put<_CharT, _OutIter>:: 591 do_put(iter_type __s, bool __intl, ios_base& __io, char_type __fill, 592 const string_type& __digits) const 593 { return __intl ? _M_insert<true>(__s, __io, __fill, __digits) 594 : _M_insert<false>(__s, __io, __fill, __digits); } 595 596 _GLIBCXX_END_LDBL_NAMESPACE 597 598 // NB: Not especially useful. Without an ios_base object or some 599 // kind of locale reference, we are left clawing at the air where 600 // the side of the mountain used to be... 601 template<typename _CharT, typename _InIter> 602 time_base::dateorder 603 time_get<_CharT, _InIter>::do_date_order() const 604 { return time_base::no_order; } 605 606 // Expand a strftime format string and parse it. E.g., do_get_date() may 607 // pass %m/%d/%Y => extracted characters. 608 template<typename _CharT, typename _InIter> 609 _InIter 610 time_get<_CharT, _InIter>:: 611 _M_extract_via_format(iter_type __beg, iter_type __end, ios_base& __io, 612 ios_base::iostate& __err, tm* __tm, 613 const _CharT* __format) const 614 { 615 const locale& __loc = __io._M_getloc(); 616 const __timepunct<_CharT>& __tp = use_facet<__timepunct<_CharT> >(__loc); 617 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc); 618 const size_t __len = char_traits<_CharT>::length(__format); 619 620 ios_base::iostate __tmperr = ios_base::goodbit; 621 for (size_t __i = 0; __beg != __end && __i < __len && !__tmperr; ++__i) 622 { 623 if (__ctype.narrow(__format[__i], 0) == '%') 624 { 625 // Verify valid formatting code, attempt to extract. 626 char __c = __ctype.narrow(__format[++__i], 0); 627 int __mem = 0; 628 if (__c == 'E' || __c == 'O') 629 __c = __ctype.narrow(__format[++__i], 0); 630 switch (__c) 631 { 632 const char* __cs; 633 _CharT __wcs[10]; 634 case 'a': 635 // Abbreviated weekday name [tm_wday] 636 const char_type* __days1[7]; 637 __tp._M_days_abbreviated(__days1); 638 __beg = _M_extract_name(__beg, __end, __tm->tm_wday, __days1, 639 7, __io, __tmperr); 640 break; 641 case 'A': 642 // Weekday name [tm_wday]. 643 const char_type* __days2[7]; 644 __tp._M_days(__days2); 645 __beg = _M_extract_name(__beg, __end, __tm->tm_wday, __days2, 646 7, __io, __tmperr); 647 break; 648 case 'h': 649 case 'b': 650 // Abbreviated month name [tm_mon] 651 const char_type* __months1[12]; 652 __tp._M_months_abbreviated(__months1); 653 __beg = _M_extract_name(__beg, __end, __tm->tm_mon, 654 __months1, 12, __io, __tmperr); 655 break; 656 case 'B': 657 // Month name [tm_mon]. 658 const char_type* __months2[12]; 659 __tp._M_months(__months2); 660 __beg = _M_extract_name(__beg, __end, __tm->tm_mon, 661 __months2, 12, __io, __tmperr); 662 break; 663 case 'c': 664 // Default time and date representation. 665 const char_type* __dt[2]; 666 __tp._M_date_time_formats(__dt); 667 __beg = _M_extract_via_format(__beg, __end, __io, __tmperr, 668 __tm, __dt[0]); 669 break; 670 case 'd': 671 // Day [01, 31]. [tm_mday] 672 __beg = _M_extract_num(__beg, __end, __tm->tm_mday, 1, 31, 2, 673 __io, __tmperr); 674 break; 675 case 'e': 676 // Day [1, 31], with single digits preceded by 677 // space. [tm_mday] 678 if (__ctype.is(ctype_base::space, *__beg)) 679 __beg = _M_extract_num(++__beg, __end, __tm->tm_mday, 1, 9, 680 1, __io, __tmperr); 681 else 682 __beg = _M_extract_num(__beg, __end, __tm->tm_mday, 10, 31, 683 2, __io, __tmperr); 684 break; 685 case 'D': 686 // Equivalent to %m/%d/%y.[tm_mon, tm_mday, tm_year] 687 __cs = "%m/%d/%y"; 688 __ctype.widen(__cs, __cs + 9, __wcs); 689 __beg = _M_extract_via_format(__beg, __end, __io, __tmperr, 690 __tm, __wcs); 691 break; 692 case 'H': 693 // Hour [00, 23]. [tm_hour] 694 __beg = _M_extract_num(__beg, __end, __tm->tm_hour, 0, 23, 2, 695 __io, __tmperr); 696 break; 697 case 'I': 698 // Hour [01, 12]. [tm_hour] 699 __beg = _M_extract_num(__beg, __end, __tm->tm_hour, 1, 12, 2, 700 __io, __tmperr); 701 break; 702 case 'm': 703 // Month [01, 12]. [tm_mon] 704 __beg = _M_extract_num(__beg, __end, __mem, 1, 12, 2, 705 __io, __tmperr); 706 if (!__tmperr) 707 __tm->tm_mon = __mem - 1; 708 break; 709 case 'M': 710 // Minute [00, 59]. [tm_min] 711 __beg = _M_extract_num(__beg, __end, __tm->tm_min, 0, 59, 2, 712 __io, __tmperr); 713 break; 714 case 'n': 715 if (__ctype.narrow(*__beg, 0) == '\n') 716 ++__beg; 717 else 718 __tmperr |= ios_base::failbit; 719 break; 720 case 'R': 721 // Equivalent to (%H:%M). 722 __cs = "%H:%M"; 723 __ctype.widen(__cs, __cs + 6, __wcs); 724 __beg = _M_extract_via_format(__beg, __end, __io, __tmperr, 725 __tm, __wcs); 726 break; 727 case 'S': 728 // Seconds. [tm_sec] 729 // [00, 60] in C99 (one leap-second), [00, 61] in C89. 730 #ifdef _GLIBCXX_USE_C99 731 __beg = _M_extract_num(__beg, __end, __tm->tm_sec, 0, 60, 2, 732 #else 733 __beg = _M_extract_num(__beg, __end, __tm->tm_sec, 0, 61, 2, 734 #endif 735 __io, __tmperr); 736 break; 737 case 't': 738 if (__ctype.narrow(*__beg, 0) == '\t') 739 ++__beg; 740 else 741 __tmperr |= ios_base::failbit; 742 break; 743 case 'T': 744 // Equivalent to (%H:%M:%S). 745 __cs = "%H:%M:%S"; 746 __ctype.widen(__cs, __cs + 9, __wcs); 747 __beg = _M_extract_via_format(__beg, __end, __io, __tmperr, 748 __tm, __wcs); 749 break; 750 case 'x': 751 // Locale's date. 752 const char_type* __dates[2]; 753 __tp._M_date_formats(__dates); 754 __beg = _M_extract_via_format(__beg, __end, __io, __tmperr, 755 __tm, __dates[0]); 756 break; 757 case 'X': 758 // Locale's time. 759 const char_type* __times[2]; 760 __tp._M_time_formats(__times); 761 __beg = _M_extract_via_format(__beg, __end, __io, __tmperr, 762 __tm, __times[0]); 763 break; 764 case 'y': 765 case 'C': // C99 766 // Two digit year. [tm_year] 767 __beg = _M_extract_num(__beg, __end, __tm->tm_year, 0, 99, 2, 768 __io, __tmperr); 769 break; 770 case 'Y': 771 // Year [1900). [tm_year] 772 __beg = _M_extract_num(__beg, __end, __mem, 0, 9999, 4, 773 __io, __tmperr); 774 if (!__tmperr) 775 __tm->tm_year = __mem - 1900; 776 break; 777 case 'Z': 778 // Timezone info. 779 if (__ctype.is(ctype_base::upper, *__beg)) 780 { 781 int __tmp; 782 __beg = _M_extract_name(__beg, __end, __tmp, 783 __timepunct_cache<_CharT>::_S_timezones, 784 14, __io, __tmperr); 785 786 // GMT requires special effort. 787 if (__beg != __end && !__tmperr && __tmp == 0 788 && (*__beg == __ctype.widen('-') 789 || *__beg == __ctype.widen('+'))) 790 { 791 __beg = _M_extract_num(__beg, __end, __tmp, 0, 23, 2, 792 __io, __tmperr); 793 __beg = _M_extract_num(__beg, __end, __tmp, 0, 59, 2, 794 __io, __tmperr); 795 } 796 } 797 else 798 __tmperr |= ios_base::failbit; 799 break; 800 default: 801 // Not recognized. 802 __tmperr |= ios_base::failbit; 803 } 804 } 805 else 806 { 807 // Verify format and input match, extract and discard. 808 if (__format[__i] == *__beg) 809 ++__beg; 810 else 811 __tmperr |= ios_base::failbit; 812 } 813 } 814 815 if (__tmperr) 816 __err |= ios_base::failbit; 817 818 return __beg; 819 } 820 821 template<typename _CharT, typename _InIter> 822 _InIter 823 time_get<_CharT, _InIter>:: 824 _M_extract_num(iter_type __beg, iter_type __end, int& __member, 825 int __min, int __max, size_t __len, 826 ios_base& __io, ios_base::iostate& __err) const 827 { 828 const locale& __loc = __io._M_getloc(); 829 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc); 830 831 // As-is works for __len = 1, 2, 4, the values actually used. 832 int __mult = __len == 2 ? 10 : (__len == 4 ? 1000 : 1); 833 834 ++__min; 835 size_t __i = 0; 836 int __value = 0; 837 for (; __beg != __end && __i < __len; ++__beg, ++__i) 838 { 839 const char __c = __ctype.narrow(*__beg, '*'); 840 if (__c >= '0' && __c <= '9') 841 { 842 __value = __value * 10 + (__c - '0'); 843 const int __valuec = __value * __mult; 844 if (__valuec > __max || __valuec + __mult < __min) 845 break; 846 __mult /= 10; 847 } 848 else 849 break; 850 } 851 if (__i == __len) 852 __member = __value; 853 else 854 __err |= ios_base::failbit; 855 856 return __beg; 857 } 858 859 // Assumptions: 860 // All elements in __names are unique. 861 template<typename _CharT, typename _InIter> 862 _InIter 863 time_get<_CharT, _InIter>:: 864 _M_extract_name(iter_type __beg, iter_type __end, int& __member, 865 const _CharT** __names, size_t __indexlen, 866 ios_base& __io, ios_base::iostate& __err) const 867 { 868 typedef char_traits<_CharT> __traits_type; 869 const locale& __loc = __io._M_getloc(); 870 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc); 871 872 int* __matches = static_cast<int*>(__builtin_alloca(sizeof(int) 873 * __indexlen)); 874 size_t __nmatches = 0; 875 size_t __pos = 0; 876 bool __testvalid = true; 877 const char_type* __name; 878 879 // Look for initial matches. 880 // NB: Some of the locale data is in the form of all lowercase 881 // names, and some is in the form of initially-capitalized 882 // names. Look for both. 883 if (__beg != __end) 884 { 885 const char_type __c = *__beg; 886 for (size_t __i1 = 0; __i1 < __indexlen; ++__i1) 887 if (__c == __names[__i1][0] 888 || __c == __ctype.toupper(__names[__i1][0])) 889 __matches[__nmatches++] = __i1; 890 } 891 892 while (__nmatches > 1) 893 { 894 // Find smallest matching string. 895 size_t __minlen = __traits_type::length(__names[__matches[0]]); 896 for (size_t __i2 = 1; __i2 < __nmatches; ++__i2) 897 __minlen = std::min(__minlen, 898 __traits_type::length(__names[__matches[__i2]])); 899 ++__beg, ++__pos; 900 if (__pos < __minlen && __beg != __end) 901 for (size_t __i3 = 0; __i3 < __nmatches;) 902 { 903 __name = __names[__matches[__i3]]; 904 if (!(__name[__pos] == *__beg)) 905 __matches[__i3] = __matches[--__nmatches]; 906 else 907 ++__i3; 908 } 909 else 910 break; 911 } 912 913 if (__nmatches == 1) 914 { 915 // Make sure found name is completely extracted. 916 ++__beg, ++__pos; 917 __name = __names[__matches[0]]; 918 const size_t __len = __traits_type::length(__name); 919 while (__pos < __len && __beg != __end && __name[__pos] == *__beg) 920 ++__beg, ++__pos; 921 922 if (__len == __pos) 923 __member = __matches[0]; 924 else 925 __testvalid = false; 926 } 927 else 928 __testvalid = false; 929 if (!__testvalid) 930 __err |= ios_base::failbit; 931 932 return __beg; 933 } 934 935 template<typename _CharT, typename _InIter> 936 _InIter 937 time_get<_CharT, _InIter>:: 938 do_get_time(iter_type __beg, iter_type __end, ios_base& __io, 939 ios_base::iostate& __err, tm* __tm) const 940 { 941 const locale& __loc = __io._M_getloc(); 942 const __timepunct<_CharT>& __tp = use_facet<__timepunct<_CharT> >(__loc); 943 const char_type* __times[2]; 944 __tp._M_time_formats(__times); 945 __beg = _M_extract_via_format(__beg, __end, __io, __err, 946 __tm, __times[0]); 947 if (__beg == __end) 948 __err |= ios_base::eofbit; 949 return __beg; 950 } 951 952 template<typename _CharT, typename _InIter> 953 _InIter 954 time_get<_CharT, _InIter>:: 955 do_get_date(iter_type __beg, iter_type __end, ios_base& __io, 956 ios_base::iostate& __err, tm* __tm) const 957 { 958 const locale& __loc = __io._M_getloc(); 959 const __timepunct<_CharT>& __tp = use_facet<__timepunct<_CharT> >(__loc); 960 const char_type* __dates[2]; 961 __tp._M_date_formats(__dates); 962 __beg = _M_extract_via_format(__beg, __end, __io, __err, 963 __tm, __dates[0]); 964 if (__beg == __end) 965 __err |= ios_base::eofbit; 966 return __beg; 967 } 968 969 template<typename _CharT, typename _InIter> 970 _InIter 971 time_get<_CharT, _InIter>:: 972 do_get_weekday(iter_type __beg, iter_type __end, ios_base& __io, 973 ios_base::iostate& __err, tm* __tm) const 974 { 975 typedef char_traits<_CharT> __traits_type; 976 const locale& __loc = __io._M_getloc(); 977 const __timepunct<_CharT>& __tp = use_facet<__timepunct<_CharT> >(__loc); 978 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc); 979 const char_type* __days[7]; 980 __tp._M_days_abbreviated(__days); 981 int __tmpwday; 982 ios_base::iostate __tmperr = ios_base::goodbit; 983 __beg = _M_extract_name(__beg, __end, __tmpwday, __days, 7, 984 __io, __tmperr); 985 986 // Check to see if non-abbreviated name exists, and extract. 987 // NB: Assumes both _M_days and _M_days_abbreviated organized in 988 // exact same order, first to last, such that the resulting 989 // __days array with the same index points to a day, and that 990 // day's abbreviated form. 991 // NB: Also assumes that an abbreviated name is a subset of the name. 992 if (!__tmperr && __beg != __end) 993 { 994 size_t __pos = __traits_type::length(__days[__tmpwday]); 995 __tp._M_days(__days); 996 const char_type* __name = __days[__tmpwday]; 997 if (__name[__pos] == *__beg) 998 { 999 // Extract the rest of it. 1000 const size_t __len = __traits_type::length(__name); 1001 while (__pos < __len && __beg != __end 1002 && __name[__pos] == *__beg) 1003 ++__beg, ++__pos; 1004 if (__len != __pos) 1005 __tmperr |= ios_base::failbit; 1006 } 1007 } 1008 if (!__tmperr) 1009 __tm->tm_wday = __tmpwday; 1010 else 1011 __err |= ios_base::failbit; 1012 1013 if (__beg == __end) 1014 __err |= ios_base::eofbit; 1015 return __beg; 1016 } 1017 1018 template<typename _CharT, typename _InIter> 1019 _InIter 1020 time_get<_CharT, _InIter>:: 1021 do_get_monthname(iter_type __beg, iter_type __end, 1022 ios_base& __io, ios_base::iostate& __err, tm* __tm) const 1023 { 1024 typedef char_traits<_CharT> __traits_type; 1025 const locale& __loc = __io._M_getloc(); 1026 const __timepunct<_CharT>& __tp = use_facet<__timepunct<_CharT> >(__loc); 1027 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc); 1028 const char_type* __months[12]; 1029 __tp._M_months_abbreviated(__months); 1030 int __tmpmon; 1031 ios_base::iostate __tmperr = ios_base::goodbit; 1032 __beg = _M_extract_name(__beg, __end, __tmpmon, __months, 12, 1033 __io, __tmperr); 1034 1035 // Check to see if non-abbreviated name exists, and extract. 1036 // NB: Assumes both _M_months and _M_months_abbreviated organized in 1037 // exact same order, first to last, such that the resulting 1038 // __months array with the same index points to a month, and that 1039 // month's abbreviated form. 1040 // NB: Also assumes that an abbreviated name is a subset of the name. 1041 if (!__tmperr && __beg != __end) 1042 { 1043 size_t __pos = __traits_type::length(__months[__tmpmon]); 1044 __tp._M_months(__months); 1045 const char_type* __name = __months[__tmpmon]; 1046 if (__name[__pos] == *__beg) 1047 { 1048 // Extract the rest of it. 1049 const size_t __len = __traits_type::length(__name); 1050 while (__pos < __len && __beg != __end 1051 && __name[__pos] == *__beg) 1052 ++__beg, ++__pos; 1053 if (__len != __pos) 1054 __tmperr |= ios_base::failbit; 1055 } 1056 } 1057 if (!__tmperr) 1058 __tm->tm_mon = __tmpmon; 1059 else 1060 __err |= ios_base::failbit; 1061 1062 if (__beg == __end) 1063 __err |= ios_base::eofbit; 1064 return __beg; 1065 } 1066 1067 template<typename _CharT, typename _InIter> 1068 _InIter 1069 time_get<_CharT, _InIter>:: 1070 do_get_year(iter_type __beg, iter_type __end, ios_base& __io, 1071 ios_base::iostate& __err, tm* __tm) const 1072 { 1073 const locale& __loc = __io._M_getloc(); 1074 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc); 1075 1076 size_t __i = 0; 1077 int __value = 0; 1078 for (; __beg != __end && __i < 4; ++__beg, ++__i) 1079 { 1080 const char __c = __ctype.narrow(*__beg, '*'); 1081 if (__c >= '0' && __c <= '9') 1082 __value = __value * 10 + (__c - '0'); 1083 else 1084 break; 1085 } 1086 if (__i == 2 || __i == 4) 1087 __tm->tm_year = __i == 2 ? __value : __value - 1900; 1088 else 1089 __err |= ios_base::failbit; 1090 1091 if (__beg == __end) 1092 __err |= ios_base::eofbit; 1093 return __beg; 1094 } 1095 1096 template<typename _CharT, typename _OutIter> 1097 _OutIter 1098 time_put<_CharT, _OutIter>:: 1099 put(iter_type __s, ios_base& __io, char_type __fill, const tm* __tm, 1100 const _CharT* __beg, const _CharT* __end) const 1101 { 1102 const locale& __loc = __io._M_getloc(); 1103 ctype<_CharT> const& __ctype = use_facet<ctype<_CharT> >(__loc); 1104 for (; __beg != __end; ++__beg) 1105 if (__ctype.narrow(*__beg, 0) != '%') 1106 { 1107 *__s = *__beg; 1108 ++__s; 1109 } 1110 else if (++__beg != __end) 1111 { 1112 char __format; 1113 char __mod = 0; 1114 const char __c = __ctype.narrow(*__beg, 0); 1115 if (__c != 'E' && __c != 'O') 1116 __format = __c; 1117 else if (++__beg != __end) 1118 { 1119 __mod = __c; 1120 __format = __ctype.narrow(*__beg, 0); 1121 } 1122 else 1123 break; 1124 __s = this->do_put(__s, __io, __fill, __tm, __format, __mod); 1125 } 1126 else 1127 break; 1128 return __s; 1129 } 1130 1131 template<typename _CharT, typename _OutIter> 1132 _OutIter 1133 time_put<_CharT, _OutIter>:: 1134 do_put(iter_type __s, ios_base& __io, char_type, const tm* __tm, 1135 char __format, char __mod) const 1136 { 1137 const locale& __loc = __io._M_getloc(); 1138 ctype<_CharT> const& __ctype = use_facet<ctype<_CharT> >(__loc); 1139 __timepunct<_CharT> const& __tp = use_facet<__timepunct<_CharT> >(__loc); 1140 1141 // NB: This size is arbitrary. Should this be a data member, 1142 // initialized at construction? 1143 const size_t __maxlen = 128; 1144 char_type* __res = 1145 static_cast<char_type*>(__builtin_alloca(sizeof(char_type) * __maxlen)); 1146 1147 // NB: In IEE 1003.1-200x, and perhaps other locale models, it 1148 // is possible that the format character will be longer than one 1149 // character. Possibilities include 'E' or 'O' followed by a 1150 // format character: if __mod is not the default argument, assume 1151 // it's a valid modifier. 1152 char_type __fmt[4]; 1153 __fmt[0] = __ctype.widen('%'); 1154 if (!__mod) 1155 { 1156 __fmt[1] = __format; 1157 __fmt[2] = char_type(); 1158 } 1159 else 1160 { 1161 __fmt[1] = __mod; 1162 __fmt[2] = __format; 1163 __fmt[3] = char_type(); 1164 } 1165 1166 __tp._M_put(__res, __maxlen, __fmt, __tm); 1167 1168 // Write resulting, fully-formatted string to output iterator. 1169 return std::__write(__s, __res, char_traits<char_type>::length(__res)); 1170 } 1171 1172 1173 // Inhibit implicit instantiations for required instantiations, 1174 // which are defined via explicit instantiations elsewhere. 1175 // NB: This syntax is a GNU extension. 1176 #if _GLIBCXX_EXTERN_TEMPLATE 1177 extern template class moneypunct<char, false>; 1178 extern template class moneypunct<char, true>; 1179 extern template class moneypunct_byname<char, false>; 1180 extern template class moneypunct_byname<char, true>; 1181 extern template class _GLIBCXX_LDBL_NAMESPACE money_get<char>; 1182 extern template class _GLIBCXX_LDBL_NAMESPACE money_put<char>; 1183 extern template class __timepunct<char>; 1184 extern template class time_put<char>; 1185 extern template class time_put_byname<char>; 1186 extern template class time_get<char>; 1187 extern template class time_get_byname<char>; 1188 extern template class messages<char>; 1189 extern template class messages_byname<char>; 1190 1191 extern template 1192 const moneypunct<char, true>& 1193 use_facet<moneypunct<char, true> >(const locale&); 1194 1195 extern template 1196 const moneypunct<char, false>& 1197 use_facet<moneypunct<char, false> >(const locale&); 1198 1199 extern template 1200 const money_put<char>& 1201 use_facet<money_put<char> >(const locale&); 1202 1203 extern template 1204 const money_get<char>& 1205 use_facet<money_get<char> >(const locale&); 1206 1207 extern template 1208 const __timepunct<char>& 1209 use_facet<__timepunct<char> >(const locale&); 1210 1211 extern template 1212 const time_put<char>& 1213 use_facet<time_put<char> >(const locale&); 1214 1215 extern template 1216 const time_get<char>& 1217 use_facet<time_get<char> >(const locale&); 1218 1219 extern template 1220 const messages<char>& 1221 use_facet<messages<char> >(const locale&); 1222 1223 extern template 1224 bool 1225 has_facet<moneypunct<char> >(const locale&); 1226 1227 extern template 1228 bool 1229 has_facet<money_put<char> >(const locale&); 1230 1231 extern template 1232 bool 1233 has_facet<money_get<char> >(const locale&); 1234 1235 extern template 1236 bool 1237 has_facet<__timepunct<char> >(const locale&); 1238 1239 extern template 1240 bool 1241 has_facet<time_put<char> >(const locale&); 1242 1243 extern template 1244 bool 1245 has_facet<time_get<char> >(const locale&); 1246 1247 extern template 1248 bool 1249 has_facet<messages<char> >(const locale&); 1250 1251 #ifdef _GLIBCXX_USE_WCHAR_T 1252 extern template class moneypunct<wchar_t, false>; 1253 extern template class moneypunct<wchar_t, true>; 1254 extern template class moneypunct_byname<wchar_t, false>; 1255 extern template class moneypunct_byname<wchar_t, true>; 1256 extern template class _GLIBCXX_LDBL_NAMESPACE money_get<wchar_t>; 1257 extern template class _GLIBCXX_LDBL_NAMESPACE money_put<wchar_t>; 1258 extern template class __timepunct<wchar_t>; 1259 extern template class time_put<wchar_t>; 1260 extern template class time_put_byname<wchar_t>; 1261 extern template class time_get<wchar_t>; 1262 extern template class time_get_byname<wchar_t>; 1263 extern template class messages<wchar_t>; 1264 extern template class messages_byname<wchar_t>; 1265 1266 extern template 1267 const moneypunct<wchar_t, true>& 1268 use_facet<moneypunct<wchar_t, true> >(const locale&); 1269 1270 extern template 1271 const moneypunct<wchar_t, false>& 1272 use_facet<moneypunct<wchar_t, false> >(const locale&); 1273 1274 extern template 1275 const money_put<wchar_t>& 1276 use_facet<money_put<wchar_t> >(const locale&); 1277 1278 extern template 1279 const money_get<wchar_t>& 1280 use_facet<money_get<wchar_t> >(const locale&); 1281 1282 extern template 1283 const __timepunct<wchar_t>& 1284 use_facet<__timepunct<wchar_t> >(const locale&); 1285 1286 extern template 1287 const time_put<wchar_t>& 1288 use_facet<time_put<wchar_t> >(const locale&); 1289 1290 extern template 1291 const time_get<wchar_t>& 1292 use_facet<time_get<wchar_t> >(const locale&); 1293 1294 extern template 1295 const messages<wchar_t>& 1296 use_facet<messages<wchar_t> >(const locale&); 1297 1298 extern template 1299 bool 1300 has_facet<moneypunct<wchar_t> >(const locale&); 1301 1302 extern template 1303 bool 1304 has_facet<money_put<wchar_t> >(const locale&); 1305 1306 extern template 1307 bool 1308 has_facet<money_get<wchar_t> >(const locale&); 1309 1310 extern template 1311 bool 1312 has_facet<__timepunct<wchar_t> >(const locale&); 1313 1314 extern template 1315 bool 1316 has_facet<time_put<wchar_t> >(const locale&); 1317 1318 extern template 1319 bool 1320 has_facet<time_get<wchar_t> >(const locale&); 1321 1322 extern template 1323 bool 1324 has_facet<messages<wchar_t> >(const locale&); 1325 #endif 1326 #endif 1327 1328 _GLIBCXX_END_NAMESPACE 1329 1330 #endif 1331