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