libstdc++
|
00001 // Locale support -*- C++ -*- 00002 00003 // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 00004 // 2006, 2007, 2008, 2009 00005 // Free Software Foundation, Inc. 00006 // 00007 // This file is part of the GNU ISO C++ Library. This library is free 00008 // software; you can redistribute it and/or modify it under the 00009 // terms of the GNU General Public License as published by the 00010 // Free Software Foundation; either version 3, or (at your option) 00011 // any later version. 00012 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 // GNU General Public License for more details. 00017 00018 // Under Section 7 of GPL version 3, you are granted additional 00019 // permissions described in the GCC Runtime Library Exception, version 00020 // 3.1, as published by the Free Software Foundation. 00021 00022 // You should have received a copy of the GNU General Public License and 00023 // a copy of the GCC Runtime Library Exception along with this program; 00024 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 00025 // <http://www.gnu.org/licenses/>. 00026 00027 /** @file locale_facets.tcc 00028 * This is an internal header file, included by other library headers. 00029 * You should not attempt to use it directly. 00030 */ 00031 00032 #ifndef _LOCALE_FACETS_TCC 00033 #define _LOCALE_FACETS_TCC 1 00034 00035 #pragma GCC system_header 00036 00037 _GLIBCXX_BEGIN_NAMESPACE(std) 00038 00039 // Routine to access a cache for the facet. If the cache didn't 00040 // exist before, it gets constructed on the fly. 00041 template<typename _Facet> 00042 struct __use_cache 00043 { 00044 const _Facet* 00045 operator() (const locale& __loc) const; 00046 }; 00047 00048 // Specializations. 00049 template<typename _CharT> 00050 struct __use_cache<__numpunct_cache<_CharT> > 00051 { 00052 const __numpunct_cache<_CharT>* 00053 operator() (const locale& __loc) const 00054 { 00055 const size_t __i = numpunct<_CharT>::id._M_id(); 00056 const locale::facet** __caches = __loc._M_impl->_M_caches; 00057 if (!__caches[__i]) 00058 { 00059 __numpunct_cache<_CharT>* __tmp = NULL; 00060 __try 00061 { 00062 __tmp = new __numpunct_cache<_CharT>; 00063 __tmp->_M_cache(__loc); 00064 } 00065 __catch(...) 00066 { 00067 delete __tmp; 00068 __throw_exception_again; 00069 } 00070 __loc._M_impl->_M_install_cache(__tmp, __i); 00071 } 00072 return static_cast<const __numpunct_cache<_CharT>*>(__caches[__i]); 00073 } 00074 }; 00075 00076 template<typename _CharT> 00077 void 00078 __numpunct_cache<_CharT>::_M_cache(const locale& __loc) 00079 { 00080 _M_allocated = true; 00081 00082 const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__loc); 00083 00084 _M_grouping_size = __np.grouping().size(); 00085 char* __grouping = new char[_M_grouping_size]; 00086 __np.grouping().copy(__grouping, _M_grouping_size); 00087 _M_grouping = __grouping; 00088 _M_use_grouping = (_M_grouping_size 00089 && static_cast<signed char>(_M_grouping[0]) > 0 00090 && (_M_grouping[0] 00091 != __gnu_cxx::__numeric_traits<char>::__max)); 00092 00093 _M_truename_size = __np.truename().size(); 00094 _CharT* __truename = new _CharT[_M_truename_size]; 00095 __np.truename().copy(__truename, _M_truename_size); 00096 _M_truename = __truename; 00097 00098 _M_falsename_size = __np.falsename().size(); 00099 _CharT* __falsename = new _CharT[_M_falsename_size]; 00100 __np.falsename().copy(__falsename, _M_falsename_size); 00101 _M_falsename = __falsename; 00102 00103 _M_decimal_point = __np.decimal_point(); 00104 _M_thousands_sep = __np.thousands_sep(); 00105 00106 const ctype<_CharT>& __ct = use_facet<ctype<_CharT> >(__loc); 00107 __ct.widen(__num_base::_S_atoms_out, 00108 __num_base::_S_atoms_out + __num_base::_S_oend, _M_atoms_out); 00109 __ct.widen(__num_base::_S_atoms_in, 00110 __num_base::_S_atoms_in + __num_base::_S_iend, _M_atoms_in); 00111 } 00112 00113 // Used by both numeric and monetary facets. 00114 // Check to make sure that the __grouping_tmp string constructed in 00115 // money_get or num_get matches the canonical grouping for a given 00116 // locale. 00117 // __grouping_tmp is parsed L to R 00118 // 1,222,444 == __grouping_tmp of "\1\3\3" 00119 // __grouping is parsed R to L 00120 // 1,222,444 == __grouping of "\3" == "\3\3\3" 00121 bool 00122 __verify_grouping(const char* __grouping, size_t __grouping_size, 00123 const string& __grouping_tmp); 00124 00125 _GLIBCXX_BEGIN_LDBL_NAMESPACE 00126 00127 template<typename _CharT, typename _InIter> 00128 _InIter 00129 num_get<_CharT, _InIter>:: 00130 _M_extract_float(_InIter __beg, _InIter __end, ios_base& __io, 00131 ios_base::iostate& __err, string& __xtrc) const 00132 { 00133 typedef char_traits<_CharT> __traits_type; 00134 typedef __numpunct_cache<_CharT> __cache_type; 00135 __use_cache<__cache_type> __uc; 00136 const locale& __loc = __io._M_getloc(); 00137 const __cache_type* __lc = __uc(__loc); 00138 const _CharT* __lit = __lc->_M_atoms_in; 00139 char_type __c = char_type(); 00140 00141 // True if __beg becomes equal to __end. 00142 bool __testeof = __beg == __end; 00143 00144 // First check for sign. 00145 if (!__testeof) 00146 { 00147 __c = *__beg; 00148 const bool __plus = __c == __lit[__num_base::_S_iplus]; 00149 if ((__plus || __c == __lit[__num_base::_S_iminus]) 00150 && !(__lc->_M_use_grouping && __c == __lc->_M_thousands_sep) 00151 && !(__c == __lc->_M_decimal_point)) 00152 { 00153 __xtrc += __plus ? '+' : '-'; 00154 if (++__beg != __end) 00155 __c = *__beg; 00156 else 00157 __testeof = true; 00158 } 00159 } 00160 00161 // Next, look for leading zeros. 00162 bool __found_mantissa = false; 00163 int __sep_pos = 0; 00164 while (!__testeof) 00165 { 00166 if ((__lc->_M_use_grouping && __c == __lc->_M_thousands_sep) 00167 || __c == __lc->_M_decimal_point) 00168 break; 00169 else if (__c == __lit[__num_base::_S_izero]) 00170 { 00171 if (!__found_mantissa) 00172 { 00173 __xtrc += '0'; 00174 __found_mantissa = true; 00175 } 00176 ++__sep_pos; 00177 00178 if (++__beg != __end) 00179 __c = *__beg; 00180 else 00181 __testeof = true; 00182 } 00183 else 00184 break; 00185 } 00186 00187 // Only need acceptable digits for floating point numbers. 00188 bool __found_dec = false; 00189 bool __found_sci = false; 00190 string __found_grouping; 00191 if (__lc->_M_use_grouping) 00192 __found_grouping.reserve(32); 00193 const char_type* __lit_zero = __lit + __num_base::_S_izero; 00194 00195 if (!__lc->_M_allocated) 00196 // "C" locale 00197 while (!__testeof) 00198 { 00199 const int __digit = _M_find(__lit_zero, 10, __c); 00200 if (__digit != -1) 00201 { 00202 __xtrc += '0' + __digit; 00203 __found_mantissa = true; 00204 } 00205 else if (__c == __lc->_M_decimal_point 00206 && !__found_dec && !__found_sci) 00207 { 00208 __xtrc += '.'; 00209 __found_dec = true; 00210 } 00211 else if ((__c == __lit[__num_base::_S_ie] 00212 || __c == __lit[__num_base::_S_iE]) 00213 && !__found_sci && __found_mantissa) 00214 { 00215 // Scientific notation. 00216 __xtrc += 'e'; 00217 __found_sci = true; 00218 00219 // Remove optional plus or minus sign, if they exist. 00220 if (++__beg != __end) 00221 { 00222 __c = *__beg; 00223 const bool __plus = __c == __lit[__num_base::_S_iplus]; 00224 if (__plus || __c == __lit[__num_base::_S_iminus]) 00225 __xtrc += __plus ? '+' : '-'; 00226 else 00227 continue; 00228 } 00229 else 00230 { 00231 __testeof = true; 00232 break; 00233 } 00234 } 00235 else 00236 break; 00237 00238 if (++__beg != __end) 00239 __c = *__beg; 00240 else 00241 __testeof = true; 00242 } 00243 else 00244 while (!__testeof) 00245 { 00246 // According to 22.2.2.1.2, p8-9, first look for thousands_sep 00247 // and decimal_point. 00248 if (__lc->_M_use_grouping && __c == __lc->_M_thousands_sep) 00249 { 00250 if (!__found_dec && !__found_sci) 00251 { 00252 // NB: Thousands separator at the beginning of a string 00253 // is a no-no, as is two consecutive thousands separators. 00254 if (__sep_pos) 00255 { 00256 __found_grouping += static_cast<char>(__sep_pos); 00257 __sep_pos = 0; 00258 } 00259 else 00260 { 00261 // NB: __convert_to_v will not assign __v and will 00262 // set the failbit. 00263 __xtrc.clear(); 00264 break; 00265 } 00266 } 00267 else 00268 break; 00269 } 00270 else if (__c == __lc->_M_decimal_point) 00271 { 00272 if (!__found_dec && !__found_sci) 00273 { 00274 // If no grouping chars are seen, no grouping check 00275 // is applied. Therefore __found_grouping is adjusted 00276 // only if decimal_point comes after some thousands_sep. 00277 if (__found_grouping.size()) 00278 __found_grouping += static_cast<char>(__sep_pos); 00279 __xtrc += '.'; 00280 __found_dec = true; 00281 } 00282 else 00283 break; 00284 } 00285 else 00286 { 00287 const char_type* __q = 00288 __traits_type::find(__lit_zero, 10, __c); 00289 if (__q) 00290 { 00291 __xtrc += '0' + (__q - __lit_zero); 00292 __found_mantissa = true; 00293 ++__sep_pos; 00294 } 00295 else if ((__c == __lit[__num_base::_S_ie] 00296 || __c == __lit[__num_base::_S_iE]) 00297 && !__found_sci && __found_mantissa) 00298 { 00299 // Scientific notation. 00300 if (__found_grouping.size() && !__found_dec) 00301 __found_grouping += static_cast<char>(__sep_pos); 00302 __xtrc += 'e'; 00303 __found_sci = true; 00304 00305 // Remove optional plus or minus sign, if they exist. 00306 if (++__beg != __end) 00307 { 00308 __c = *__beg; 00309 const bool __plus = __c == __lit[__num_base::_S_iplus]; 00310 if ((__plus || __c == __lit[__num_base::_S_iminus]) 00311 && !(__lc->_M_use_grouping 00312 && __c == __lc->_M_thousands_sep) 00313 && !(__c == __lc->_M_decimal_point)) 00314 __xtrc += __plus ? '+' : '-'; 00315 else 00316 continue; 00317 } 00318 else 00319 { 00320 __testeof = true; 00321 break; 00322 } 00323 } 00324 else 00325 break; 00326 } 00327 00328 if (++__beg != __end) 00329 __c = *__beg; 00330 else 00331 __testeof = true; 00332 } 00333 00334 // Digit grouping is checked. If grouping and found_grouping don't 00335 // match, then get very very upset, and set failbit. 00336 if (__found_grouping.size()) 00337 { 00338 // Add the ending grouping if a decimal or 'e'/'E' wasn't found. 00339 if (!__found_dec && !__found_sci) 00340 __found_grouping += static_cast<char>(__sep_pos); 00341 00342 if (!std::__verify_grouping(__lc->_M_grouping, 00343 __lc->_M_grouping_size, 00344 __found_grouping)) 00345 __err = ios_base::failbit; 00346 } 00347 00348 return __beg; 00349 } 00350 00351 template<typename _CharT, typename _InIter> 00352 template<typename _ValueT> 00353 _InIter 00354 num_get<_CharT, _InIter>:: 00355 _M_extract_int(_InIter __beg, _InIter __end, ios_base& __io, 00356 ios_base::iostate& __err, _ValueT& __v) const 00357 { 00358 typedef char_traits<_CharT> __traits_type; 00359 using __gnu_cxx::__add_unsigned; 00360 typedef typename __add_unsigned<_ValueT>::__type __unsigned_type; 00361 typedef __numpunct_cache<_CharT> __cache_type; 00362 __use_cache<__cache_type> __uc; 00363 const locale& __loc = __io._M_getloc(); 00364 const __cache_type* __lc = __uc(__loc); 00365 const _CharT* __lit = __lc->_M_atoms_in; 00366 char_type __c = char_type(); 00367 00368 // NB: Iff __basefield == 0, __base can change based on contents. 00369 const ios_base::fmtflags __basefield = __io.flags() 00370 & ios_base::basefield; 00371 const bool __oct = __basefield == ios_base::oct; 00372 int __base = __oct ? 8 : (__basefield == ios_base::hex ? 16 : 10); 00373 00374 // True if __beg becomes equal to __end. 00375 bool __testeof = __beg == __end; 00376 00377 // First check for sign. 00378 bool __negative = false; 00379 if (!__testeof) 00380 { 00381 __c = *__beg; 00382 __negative = __c == __lit[__num_base::_S_iminus]; 00383 if ((__negative || __c == __lit[__num_base::_S_iplus]) 00384 && !(__lc->_M_use_grouping && __c == __lc->_M_thousands_sep) 00385 && !(__c == __lc->_M_decimal_point)) 00386 { 00387 if (++__beg != __end) 00388 __c = *__beg; 00389 else 00390 __testeof = true; 00391 } 00392 } 00393 00394 // Next, look for leading zeros and check required digits 00395 // for base formats. 00396 bool __found_zero = false; 00397 int __sep_pos = 0; 00398 while (!__testeof) 00399 { 00400 if ((__lc->_M_use_grouping && __c == __lc->_M_thousands_sep) 00401 || __c == __lc->_M_decimal_point) 00402 break; 00403 else if (__c == __lit[__num_base::_S_izero] 00404 && (!__found_zero || __base == 10)) 00405 { 00406 __found_zero = true; 00407 ++__sep_pos; 00408 if (__basefield == 0) 00409 __base = 8; 00410 if (__base == 8) 00411 __sep_pos = 0; 00412 } 00413 else if (__found_zero 00414 && (__c == __lit[__num_base::_S_ix] 00415 || __c == __lit[__num_base::_S_iX])) 00416 { 00417 if (__basefield == 0) 00418 __base = 16; 00419 if (__base == 16) 00420 { 00421 __found_zero = false; 00422 __sep_pos = 0; 00423 } 00424 else 00425 break; 00426 } 00427 else 00428 break; 00429 00430 if (++__beg != __end) 00431 { 00432 __c = *__beg; 00433 if (!__found_zero) 00434 break; 00435 } 00436 else 00437 __testeof = true; 00438 } 00439 00440 // At this point, base is determined. If not hex, only allow 00441 // base digits as valid input. 00442 const size_t __len = (__base == 16 ? __num_base::_S_iend 00443 - __num_base::_S_izero : __base); 00444 00445 // Extract. 00446 string __found_grouping; 00447 if (__lc->_M_use_grouping) 00448 __found_grouping.reserve(32); 00449 bool __testfail = false; 00450 bool __testoverflow = false; 00451 const __unsigned_type __max = 00452 (__negative && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed) 00453 ? -__gnu_cxx::__numeric_traits<_ValueT>::__min 00454 : __gnu_cxx::__numeric_traits<_ValueT>::__max; 00455 const __unsigned_type __smax = __max / __base; 00456 __unsigned_type __result = 0; 00457 int __digit = 0; 00458 const char_type* __lit_zero = __lit + __num_base::_S_izero; 00459 00460 if (!__lc->_M_allocated) 00461 // "C" locale 00462 while (!__testeof) 00463 { 00464 __digit = _M_find(__lit_zero, __len, __c); 00465 if (__digit == -1) 00466 break; 00467 00468 if (__result > __smax) 00469 __testoverflow = true; 00470 else 00471 { 00472 __result *= __base; 00473 __testoverflow |= __result > __max - __digit; 00474 __result += __digit; 00475 ++__sep_pos; 00476 } 00477 00478 if (++__beg != __end) 00479 __c = *__beg; 00480 else 00481 __testeof = true; 00482 } 00483 else 00484 while (!__testeof) 00485 { 00486 // According to 22.2.2.1.2, p8-9, first look for thousands_sep 00487 // and decimal_point. 00488 if (__lc->_M_use_grouping && __c == __lc->_M_thousands_sep) 00489 { 00490 // NB: Thousands separator at the beginning of a string 00491 // is a no-no, as is two consecutive thousands separators. 00492 if (__sep_pos) 00493 { 00494 __found_grouping += static_cast<char>(__sep_pos); 00495 __sep_pos = 0; 00496 } 00497 else 00498 { 00499 __testfail = true; 00500 break; 00501 } 00502 } 00503 else if (__c == __lc->_M_decimal_point) 00504 break; 00505 else 00506 { 00507 const char_type* __q = 00508 __traits_type::find(__lit_zero, __len, __c); 00509 if (!__q) 00510 break; 00511 00512 __digit = __q - __lit_zero; 00513 if (__digit > 15) 00514 __digit -= 6; 00515 if (__result > __smax) 00516 __testoverflow = true; 00517 else 00518 { 00519 __result *= __base; 00520 __testoverflow |= __result > __max - __digit; 00521 __result += __digit; 00522 ++__sep_pos; 00523 } 00524 } 00525 00526 if (++__beg != __end) 00527 __c = *__beg; 00528 else 00529 __testeof = true; 00530 } 00531 00532 // Digit grouping is checked. If grouping and found_grouping don't 00533 // match, then get very very upset, and set failbit. 00534 if (__found_grouping.size()) 00535 { 00536 // Add the ending grouping. 00537 __found_grouping += static_cast<char>(__sep_pos); 00538 00539 if (!std::__verify_grouping(__lc->_M_grouping, 00540 __lc->_M_grouping_size, 00541 __found_grouping)) 00542 __err = ios_base::failbit; 00543 } 00544 00545 // _GLIBCXX_RESOLVE_LIB_DEFECTS 00546 // 23. Num_get overflow result. 00547 if ((!__sep_pos && !__found_zero && !__found_grouping.size()) 00548 || __testfail) 00549 { 00550 __v = 0; 00551 __err = ios_base::failbit; 00552 } 00553 else if (__testoverflow) 00554 { 00555 if (__negative 00556 && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed) 00557 __v = __gnu_cxx::__numeric_traits<_ValueT>::__min; 00558 else 00559 __v = __gnu_cxx::__numeric_traits<_ValueT>::__max; 00560 __err = ios_base::failbit; 00561 } 00562 else 00563 __v = __negative ? -__result : __result; 00564 00565 if (__testeof) 00566 __err |= ios_base::eofbit; 00567 return __beg; 00568 } 00569 00570 // _GLIBCXX_RESOLVE_LIB_DEFECTS 00571 // 17. Bad bool parsing 00572 template<typename _CharT, typename _InIter> 00573 _InIter 00574 num_get<_CharT, _InIter>:: 00575 do_get(iter_type __beg, iter_type __end, ios_base& __io, 00576 ios_base::iostate& __err, bool& __v) const 00577 { 00578 if (!(__io.flags() & ios_base::boolalpha)) 00579 { 00580 // Parse bool values as long. 00581 // NB: We can't just call do_get(long) here, as it might 00582 // refer to a derived class. 00583 long __l = -1; 00584 __beg = _M_extract_int(__beg, __end, __io, __err, __l); 00585 if (__l == 0 || __l == 1) 00586 __v = bool(__l); 00587 else 00588 { 00589 // _GLIBCXX_RESOLVE_LIB_DEFECTS 00590 // 23. Num_get overflow result. 00591 __v = true; 00592 __err = ios_base::failbit; 00593 if (__beg == __end) 00594 __err |= ios_base::eofbit; 00595 } 00596 } 00597 else 00598 { 00599 // Parse bool values as alphanumeric. 00600 typedef __numpunct_cache<_CharT> __cache_type; 00601 __use_cache<__cache_type> __uc; 00602 const locale& __loc = __io._M_getloc(); 00603 const __cache_type* __lc = __uc(__loc); 00604 00605 bool __testf = true; 00606 bool __testt = true; 00607 bool __donef = __lc->_M_falsename_size == 0; 00608 bool __donet = __lc->_M_truename_size == 0; 00609 bool __testeof = false; 00610 size_t __n = 0; 00611 while (!__donef || !__donet) 00612 { 00613 if (__beg == __end) 00614 { 00615 __testeof = true; 00616 break; 00617 } 00618 00619 const char_type __c = *__beg; 00620 00621 if (!__donef) 00622 __testf = __c == __lc->_M_falsename[__n]; 00623 00624 if (!__testf && __donet) 00625 break; 00626 00627 if (!__donet) 00628 __testt = __c == __lc->_M_truename[__n]; 00629 00630 if (!__testt && __donef) 00631 break; 00632 00633 if (!__testt && !__testf) 00634 break; 00635 00636 ++__n; 00637 ++__beg; 00638 00639 __donef = !__testf || __n >= __lc->_M_falsename_size; 00640 __donet = !__testt || __n >= __lc->_M_truename_size; 00641 } 00642 if (__testf && __n == __lc->_M_falsename_size && __n) 00643 { 00644 __v = false; 00645 if (__testt && __n == __lc->_M_truename_size) 00646 __err = ios_base::failbit; 00647 else 00648 __err = __testeof ? ios_base::eofbit : ios_base::goodbit; 00649 } 00650 else if (__testt && __n == __lc->_M_truename_size && __n) 00651 { 00652 __v = true; 00653 __err = __testeof ? ios_base::eofbit : ios_base::goodbit; 00654 } 00655 else 00656 { 00657 // _GLIBCXX_RESOLVE_LIB_DEFECTS 00658 // 23. Num_get overflow result. 00659 __v = false; 00660 __err = ios_base::failbit; 00661 if (__testeof) 00662 __err |= ios_base::eofbit; 00663 } 00664 } 00665 return __beg; 00666 } 00667 00668 template<typename _CharT, typename _InIter> 00669 _InIter 00670 num_get<_CharT, _InIter>:: 00671 do_get(iter_type __beg, iter_type __end, ios_base& __io, 00672 ios_base::iostate& __err, float& __v) const 00673 { 00674 string __xtrc; 00675 __xtrc.reserve(32); 00676 __beg = _M_extract_float(__beg, __end, __io, __err, __xtrc); 00677 std::__convert_to_v(__xtrc.c_str(), __v, __err, _S_get_c_locale()); 00678 if (__beg == __end) 00679 __err |= ios_base::eofbit; 00680 return __beg; 00681 } 00682 00683 template<typename _CharT, typename _InIter> 00684 _InIter 00685 num_get<_CharT, _InIter>:: 00686 do_get(iter_type __beg, iter_type __end, ios_base& __io, 00687 ios_base::iostate& __err, double& __v) const 00688 { 00689 string __xtrc; 00690 __xtrc.reserve(32); 00691 __beg = _M_extract_float(__beg, __end, __io, __err, __xtrc); 00692 std::__convert_to_v(__xtrc.c_str(), __v, __err, _S_get_c_locale()); 00693 if (__beg == __end) 00694 __err |= ios_base::eofbit; 00695 return __beg; 00696 } 00697 00698 #if defined _GLIBCXX_LONG_DOUBLE_COMPAT && defined __LONG_DOUBLE_128__ 00699 template<typename _CharT, typename _InIter> 00700 _InIter 00701 num_get<_CharT, _InIter>:: 00702 __do_get(iter_type __beg, iter_type __end, ios_base& __io, 00703 ios_base::iostate& __err, double& __v) const 00704 { 00705 string __xtrc; 00706 __xtrc.reserve(32); 00707 __beg = _M_extract_float(__beg, __end, __io, __err, __xtrc); 00708 std::__convert_to_v(__xtrc.c_str(), __v, __err, _S_get_c_locale()); 00709 if (__beg == __end) 00710 __err |= ios_base::eofbit; 00711 return __beg; 00712 } 00713 #endif 00714 00715 template<typename _CharT, typename _InIter> 00716 _InIter 00717 num_get<_CharT, _InIter>:: 00718 do_get(iter_type __beg, iter_type __end, ios_base& __io, 00719 ios_base::iostate& __err, long double& __v) const 00720 { 00721 string __xtrc; 00722 __xtrc.reserve(32); 00723 __beg = _M_extract_float(__beg, __end, __io, __err, __xtrc); 00724 std::__convert_to_v(__xtrc.c_str(), __v, __err, _S_get_c_locale()); 00725 if (__beg == __end) 00726 __err |= ios_base::eofbit; 00727 return __beg; 00728 } 00729 00730 template<typename _CharT, typename _InIter> 00731 _InIter 00732 num_get<_CharT, _InIter>:: 00733 do_get(iter_type __beg, iter_type __end, ios_base& __io, 00734 ios_base::iostate& __err, void*& __v) const 00735 { 00736 // Prepare for hex formatted input. 00737 typedef ios_base::fmtflags fmtflags; 00738 const fmtflags __fmt = __io.flags(); 00739 __io.flags((__fmt & ~ios_base::basefield) | ios_base::hex); 00740 00741 typedef __gnu_cxx::__conditional_type<(sizeof(void*) 00742 <= sizeof(unsigned long)), 00743 unsigned long, unsigned long long>::__type _UIntPtrType; 00744 00745 _UIntPtrType __ul; 00746 __beg = _M_extract_int(__beg, __end, __io, __err, __ul); 00747 00748 // Reset from hex formatted input. 00749 __io.flags(__fmt); 00750 00751 __v = reinterpret_cast<void*>(__ul); 00752 return __beg; 00753 } 00754 00755 // For use by integer and floating-point types after they have been 00756 // converted into a char_type string. 00757 template<typename _CharT, typename _OutIter> 00758 void 00759 num_put<_CharT, _OutIter>:: 00760 _M_pad(_CharT __fill, streamsize __w, ios_base& __io, 00761 _CharT* __new, const _CharT* __cs, int& __len) const 00762 { 00763 // [22.2.2.2.2] Stage 3. 00764 // If necessary, pad. 00765 __pad<_CharT, char_traits<_CharT> >::_S_pad(__io, __fill, __new, 00766 __cs, __w, __len); 00767 __len = static_cast<int>(__w); 00768 } 00769 00770 _GLIBCXX_END_LDBL_NAMESPACE 00771 00772 template<typename _CharT, typename _ValueT> 00773 int 00774 __int_to_char(_CharT* __bufend, _ValueT __v, const _CharT* __lit, 00775 ios_base::fmtflags __flags, bool __dec) 00776 { 00777 _CharT* __buf = __bufend; 00778 if (__builtin_expect(__dec, true)) 00779 { 00780 // Decimal. 00781 do 00782 { 00783 *--__buf = __lit[(__v % 10) + __num_base::_S_odigits]; 00784 __v /= 10; 00785 } 00786 while (__v != 0); 00787 } 00788 else if ((__flags & ios_base::basefield) == ios_base::oct) 00789 { 00790 // Octal. 00791 do 00792 { 00793 *--__buf = __lit[(__v & 0x7) + __num_base::_S_odigits]; 00794 __v >>= 3; 00795 } 00796 while (__v != 0); 00797 } 00798 else 00799 { 00800 // Hex. 00801 const bool __uppercase = __flags & ios_base::uppercase; 00802 const int __case_offset = __uppercase ? __num_base::_S_oudigits 00803 : __num_base::_S_odigits; 00804 do 00805 { 00806 *--__buf = __lit[(__v & 0xf) + __case_offset]; 00807 __v >>= 4; 00808 } 00809 while (__v != 0); 00810 } 00811 return __bufend - __buf; 00812 } 00813 00814 _GLIBCXX_BEGIN_LDBL_NAMESPACE 00815 00816 template<typename _CharT, typename _OutIter> 00817 void 00818 num_put<_CharT, _OutIter>:: 00819 _M_group_int(const char* __grouping, size_t __grouping_size, _CharT __sep, 00820 ios_base&, _CharT* __new, _CharT* __cs, int& __len) const 00821 { 00822 _CharT* __p = std::__add_grouping(__new, __sep, __grouping, 00823 __grouping_size, __cs, __cs + __len); 00824 __len = __p - __new; 00825 } 00826 00827 template<typename _CharT, typename _OutIter> 00828 template<typename _ValueT> 00829 _OutIter 00830 num_put<_CharT, _OutIter>:: 00831 _M_insert_int(_OutIter __s, ios_base& __io, _CharT __fill, 00832 _ValueT __v) const 00833 { 00834 using __gnu_cxx::__add_unsigned; 00835 typedef typename __add_unsigned<_ValueT>::__type __unsigned_type; 00836 typedef __numpunct_cache<_CharT> __cache_type; 00837 __use_cache<__cache_type> __uc; 00838 const locale& __loc = __io._M_getloc(); 00839 const __cache_type* __lc = __uc(__loc); 00840 const _CharT* __lit = __lc->_M_atoms_out; 00841 const ios_base::fmtflags __flags = __io.flags(); 00842 00843 // Long enough to hold hex, dec, and octal representations. 00844 const int __ilen = 5 * sizeof(_ValueT); 00845 _CharT* __cs = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) 00846 * __ilen)); 00847 00848 // [22.2.2.2.2] Stage 1, numeric conversion to character. 00849 // Result is returned right-justified in the buffer. 00850 const ios_base::fmtflags __basefield = __flags & ios_base::basefield; 00851 const bool __dec = (__basefield != ios_base::oct 00852 && __basefield != ios_base::hex); 00853 const __unsigned_type __u = ((__v > 0 || !__dec) 00854 ? __unsigned_type(__v) 00855 : -__unsigned_type(__v)); 00856 int __len = __int_to_char(__cs + __ilen, __u, __lit, __flags, __dec); 00857 __cs += __ilen - __len; 00858 00859 // Add grouping, if necessary. 00860 if (__lc->_M_use_grouping) 00861 { 00862 // Grouping can add (almost) as many separators as the number 00863 // of digits + space is reserved for numeric base or sign. 00864 _CharT* __cs2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) 00865 * (__len + 1) 00866 * 2)); 00867 _M_group_int(__lc->_M_grouping, __lc->_M_grouping_size, 00868 __lc->_M_thousands_sep, __io, __cs2 + 2, __cs, __len); 00869 __cs = __cs2 + 2; 00870 } 00871 00872 // Complete Stage 1, prepend numeric base or sign. 00873 if (__builtin_expect(__dec, true)) 00874 { 00875 // Decimal. 00876 if (__v >= 0) 00877 { 00878 if (bool(__flags & ios_base::showpos) 00879 && __gnu_cxx::__numeric_traits<_ValueT>::__is_signed) 00880 *--__cs = __lit[__num_base::_S_oplus], ++__len; 00881 } 00882 else 00883 *--__cs = __lit[__num_base::_S_ominus], ++__len; 00884 } 00885 else if (bool(__flags & ios_base::showbase) && __v) 00886 { 00887 if (__basefield == ios_base::oct) 00888 *--__cs = __lit[__num_base::_S_odigits], ++__len; 00889 else 00890 { 00891 // 'x' or 'X' 00892 const bool __uppercase = __flags & ios_base::uppercase; 00893 *--__cs = __lit[__num_base::_S_ox + __uppercase]; 00894 // '0' 00895 *--__cs = __lit[__num_base::_S_odigits]; 00896 __len += 2; 00897 } 00898 } 00899 00900 // Pad. 00901 const streamsize __w = __io.width(); 00902 if (__w > static_cast<streamsize>(__len)) 00903 { 00904 _CharT* __cs3 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) 00905 * __w)); 00906 _M_pad(__fill, __w, __io, __cs3, __cs, __len); 00907 __cs = __cs3; 00908 } 00909 __io.width(0); 00910 00911 // [22.2.2.2.2] Stage 4. 00912 // Write resulting, fully-formatted string to output iterator. 00913 return std::__write(__s, __cs, __len); 00914 } 00915 00916 template<typename _CharT, typename _OutIter> 00917 void 00918 num_put<_CharT, _OutIter>:: 00919 _M_group_float(const char* __grouping, size_t __grouping_size, 00920 _CharT __sep, const _CharT* __p, _CharT* __new, 00921 _CharT* __cs, int& __len) const 00922 { 00923 // _GLIBCXX_RESOLVE_LIB_DEFECTS 00924 // 282. What types does numpunct grouping refer to? 00925 // Add grouping, if necessary. 00926 const int __declen = __p ? __p - __cs : __len; 00927 _CharT* __p2 = std::__add_grouping(__new, __sep, __grouping, 00928 __grouping_size, 00929 __cs, __cs + __declen); 00930 00931 // Tack on decimal part. 00932 int __newlen = __p2 - __new; 00933 if (__p) 00934 { 00935 char_traits<_CharT>::copy(__p2, __p, __len - __declen); 00936 __newlen += __len - __declen; 00937 } 00938 __len = __newlen; 00939 } 00940 00941 // The following code uses vsnprintf (or vsprintf(), when 00942 // _GLIBCXX_USE_C99 is not defined) to convert floating point values 00943 // for insertion into a stream. An optimization would be to replace 00944 // them with code that works directly on a wide buffer and then use 00945 // __pad to do the padding. It would be good to replace them anyway 00946 // to gain back the efficiency that C++ provides by knowing up front 00947 // the type of the values to insert. Also, sprintf is dangerous 00948 // since may lead to accidental buffer overruns. This 00949 // implementation follows the C++ standard fairly directly as 00950 // outlined in 22.2.2.2 [lib.locale.num.put] 00951 template<typename _CharT, typename _OutIter> 00952 template<typename _ValueT> 00953 _OutIter 00954 num_put<_CharT, _OutIter>:: 00955 _M_insert_float(_OutIter __s, ios_base& __io, _CharT __fill, char __mod, 00956 _ValueT __v) const 00957 { 00958 typedef __numpunct_cache<_CharT> __cache_type; 00959 __use_cache<__cache_type> __uc; 00960 const locale& __loc = __io._M_getloc(); 00961 const __cache_type* __lc = __uc(__loc); 00962 00963 // Use default precision if out of range. 00964 const streamsize __prec = __io.precision() < 0 ? 6 : __io.precision(); 00965 00966 const int __max_digits = 00967 __gnu_cxx::__numeric_traits<_ValueT>::__digits10; 00968 00969 // [22.2.2.2.2] Stage 1, numeric conversion to character. 00970 int __len; 00971 // Long enough for the max format spec. 00972 char __fbuf[16]; 00973 __num_base::_S_format_float(__io, __fbuf, __mod); 00974 00975 #ifdef _GLIBCXX_USE_C99 00976 // First try a buffer perhaps big enough (most probably sufficient 00977 // for non-ios_base::fixed outputs) 00978 int __cs_size = __max_digits * 3; 00979 char* __cs = static_cast<char*>(__builtin_alloca(__cs_size)); 00980 __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size, 00981 __fbuf, __prec, __v); 00982 00983 // If the buffer was not large enough, try again with the correct size. 00984 if (__len >= __cs_size) 00985 { 00986 __cs_size = __len + 1; 00987 __cs = static_cast<char*>(__builtin_alloca(__cs_size)); 00988 __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size, 00989 __fbuf, __prec, __v); 00990 } 00991 #else 00992 // Consider the possibility of long ios_base::fixed outputs 00993 const bool __fixed = __io.flags() & ios_base::fixed; 00994 const int __max_exp = 00995 __gnu_cxx::__numeric_traits<_ValueT>::__max_exponent10; 00996 00997 // The size of the output string is computed as follows. 00998 // ios_base::fixed outputs may need up to __max_exp + 1 chars 00999 // for the integer part + __prec chars for the fractional part 01000 // + 3 chars for sign, decimal point, '\0'. On the other hand, 01001 // for non-fixed outputs __max_digits * 2 + __prec chars are 01002 // largely sufficient. 01003 const int __cs_size = __fixed ? __max_exp + __prec + 4 01004 : __max_digits * 2 + __prec; 01005 char* __cs = static_cast<char*>(__builtin_alloca(__cs_size)); 01006 __len = std::__convert_from_v(_S_get_c_locale(), __cs, 0, __fbuf, 01007 __prec, __v); 01008 #endif 01009 01010 // [22.2.2.2.2] Stage 2, convert to char_type, using correct 01011 // numpunct.decimal_point() values for '.' and adding grouping. 01012 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc); 01013 01014 _CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) 01015 * __len)); 01016 __ctype.widen(__cs, __cs + __len, __ws); 01017 01018 // Replace decimal point. 01019 _CharT* __wp = 0; 01020 const char* __p = char_traits<char>::find(__cs, __len, '.'); 01021 if (__p) 01022 { 01023 __wp = __ws + (__p - __cs); 01024 *__wp = __lc->_M_decimal_point; 01025 } 01026 01027 // Add grouping, if necessary. 01028 // N.B. Make sure to not group things like 2e20, i.e., no decimal 01029 // point, scientific notation. 01030 if (__lc->_M_use_grouping 01031 && (__wp || __len < 3 || (__cs[1] <= '9' && __cs[2] <= '9' 01032 && __cs[1] >= '0' && __cs[2] >= '0'))) 01033 { 01034 // Grouping can add (almost) as many separators as the 01035 // number of digits, but no more. 01036 _CharT* __ws2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) 01037 * __len * 2)); 01038 01039 streamsize __off = 0; 01040 if (__cs[0] == '-' || __cs[0] == '+') 01041 { 01042 __off = 1; 01043 __ws2[0] = __ws[0]; 01044 __len -= 1; 01045 } 01046 01047 _M_group_float(__lc->_M_grouping, __lc->_M_grouping_size, 01048 __lc->_M_thousands_sep, __wp, __ws2 + __off, 01049 __ws + __off, __len); 01050 __len += __off; 01051 01052 __ws = __ws2; 01053 } 01054 01055 // Pad. 01056 const streamsize __w = __io.width(); 01057 if (__w > static_cast<streamsize>(__len)) 01058 { 01059 _CharT* __ws3 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) 01060 * __w)); 01061 _M_pad(__fill, __w, __io, __ws3, __ws, __len); 01062 __ws = __ws3; 01063 } 01064 __io.width(0); 01065 01066 // [22.2.2.2.2] Stage 4. 01067 // Write resulting, fully-formatted string to output iterator. 01068 return std::__write(__s, __ws, __len); 01069 } 01070 01071 template<typename _CharT, typename _OutIter> 01072 _OutIter 01073 num_put<_CharT, _OutIter>:: 01074 do_put(iter_type __s, ios_base& __io, char_type __fill, bool __v) const 01075 { 01076 const ios_base::fmtflags __flags = __io.flags(); 01077 if ((__flags & ios_base::boolalpha) == 0) 01078 { 01079 const long __l = __v; 01080 __s = _M_insert_int(__s, __io, __fill, __l); 01081 } 01082 else 01083 { 01084 typedef __numpunct_cache<_CharT> __cache_type; 01085 __use_cache<__cache_type> __uc; 01086 const locale& __loc = __io._M_getloc(); 01087 const __cache_type* __lc = __uc(__loc); 01088 01089 const _CharT* __name = __v ? __lc->_M_truename 01090 : __lc->_M_falsename; 01091 int __len = __v ? __lc->_M_truename_size 01092 : __lc->_M_falsename_size; 01093 01094 const streamsize __w = __io.width(); 01095 if (__w > static_cast<streamsize>(__len)) 01096 { 01097 const streamsize __plen = __w - __len; 01098 _CharT* __ps 01099 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) 01100 * __plen)); 01101 01102 char_traits<_CharT>::assign(__ps, __plen, __fill); 01103 __io.width(0); 01104 01105 if ((__flags & ios_base::adjustfield) == ios_base::left) 01106 { 01107 __s = std::__write(__s, __name, __len); 01108 __s = std::__write(__s, __ps, __plen); 01109 } 01110 else 01111 { 01112 __s = std::__write(__s, __ps, __plen); 01113 __s = std::__write(__s, __name, __len); 01114 } 01115 return __s; 01116 } 01117 __io.width(0); 01118 __s = std::__write(__s, __name, __len); 01119 } 01120 return __s; 01121 } 01122 01123 template<typename _CharT, typename _OutIter> 01124 _OutIter 01125 num_put<_CharT, _OutIter>:: 01126 do_put(iter_type __s, ios_base& __io, char_type __fill, double __v) const 01127 { return _M_insert_float(__s, __io, __fill, char(), __v); } 01128 01129 #if defined _GLIBCXX_LONG_DOUBLE_COMPAT && defined __LONG_DOUBLE_128__ 01130 template<typename _CharT, typename _OutIter> 01131 _OutIter 01132 num_put<_CharT, _OutIter>:: 01133 __do_put(iter_type __s, ios_base& __io, char_type __fill, double __v) const 01134 { return _M_insert_float(__s, __io, __fill, char(), __v); } 01135 #endif 01136 01137 template<typename _CharT, typename _OutIter> 01138 _OutIter 01139 num_put<_CharT, _OutIter>:: 01140 do_put(iter_type __s, ios_base& __io, char_type __fill, 01141 long double __v) const 01142 { return _M_insert_float(__s, __io, __fill, 'L', __v); } 01143 01144 template<typename _CharT, typename _OutIter> 01145 _OutIter 01146 num_put<_CharT, _OutIter>:: 01147 do_put(iter_type __s, ios_base& __io, char_type __fill, 01148 const void* __v) const 01149 { 01150 const ios_base::fmtflags __flags = __io.flags(); 01151 const ios_base::fmtflags __fmt = ~(ios_base::basefield 01152 | ios_base::uppercase); 01153 __io.flags((__flags & __fmt) | (ios_base::hex | ios_base::showbase)); 01154 01155 typedef __gnu_cxx::__conditional_type<(sizeof(const void*) 01156 <= sizeof(unsigned long)), 01157 unsigned long, unsigned long long>::__type _UIntPtrType; 01158 01159 __s = _M_insert_int(__s, __io, __fill, 01160 reinterpret_cast<_UIntPtrType>(__v)); 01161 __io.flags(__flags); 01162 return __s; 01163 } 01164 01165 _GLIBCXX_END_LDBL_NAMESPACE 01166 01167 // Construct correctly padded string, as per 22.2.2.2.2 01168 // Assumes 01169 // __newlen > __oldlen 01170 // __news is allocated for __newlen size 01171 01172 // NB: Of the two parameters, _CharT can be deduced from the 01173 // function arguments. The other (_Traits) has to be explicitly specified. 01174 template<typename _CharT, typename _Traits> 01175 void 01176 __pad<_CharT, _Traits>::_S_pad(ios_base& __io, _CharT __fill, 01177 _CharT* __news, const _CharT* __olds, 01178 streamsize __newlen, streamsize __oldlen) 01179 { 01180 const size_t __plen = static_cast<size_t>(__newlen - __oldlen); 01181 const ios_base::fmtflags __adjust = __io.flags() & ios_base::adjustfield; 01182 01183 // Padding last. 01184 if (__adjust == ios_base::left) 01185 { 01186 _Traits::copy(__news, __olds, __oldlen); 01187 _Traits::assign(__news + __oldlen, __plen, __fill); 01188 return; 01189 } 01190 01191 size_t __mod = 0; 01192 if (__adjust == ios_base::internal) 01193 { 01194 // Pad after the sign, if there is one. 01195 // Pad after 0[xX], if there is one. 01196 // Who came up with these rules, anyway? Jeeze. 01197 const locale& __loc = __io._M_getloc(); 01198 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc); 01199 01200 if (__ctype.widen('-') == __olds[0] 01201 || __ctype.widen('+') == __olds[0]) 01202 { 01203 __news[0] = __olds[0]; 01204 __mod = 1; 01205 ++__news; 01206 } 01207 else if (__ctype.widen('0') == __olds[0] 01208 && __oldlen > 1 01209 && (__ctype.widen('x') == __olds[1] 01210 || __ctype.widen('X') == __olds[1])) 01211 { 01212 __news[0] = __olds[0]; 01213 __news[1] = __olds[1]; 01214 __mod = 2; 01215 __news += 2; 01216 } 01217 // else Padding first. 01218 } 01219 _Traits::assign(__news, __plen, __fill); 01220 _Traits::copy(__news + __plen, __olds + __mod, __oldlen - __mod); 01221 } 01222 01223 template<typename _CharT> 01224 _CharT* 01225 __add_grouping(_CharT* __s, _CharT __sep, 01226 const char* __gbeg, size_t __gsize, 01227 const _CharT* __first, const _CharT* __last) 01228 { 01229 size_t __idx = 0; 01230 size_t __ctr = 0; 01231 01232 while (__last - __first > __gbeg[__idx] 01233 && static_cast<signed char>(__gbeg[__idx]) > 0 01234 && __gbeg[__idx] != __gnu_cxx::__numeric_traits<char>::__max) 01235 { 01236 __last -= __gbeg[__idx]; 01237 __idx < __gsize - 1 ? ++__idx : ++__ctr; 01238 } 01239 01240 while (__first != __last) 01241 *__s++ = *__first++; 01242 01243 while (__ctr--) 01244 { 01245 *__s++ = __sep; 01246 for (char __i = __gbeg[__idx]; __i > 0; --__i) 01247 *__s++ = *__first++; 01248 } 01249 01250 while (__idx--) 01251 { 01252 *__s++ = __sep; 01253 for (char __i = __gbeg[__idx]; __i > 0; --__i) 01254 *__s++ = *__first++; 01255 } 01256 01257 return __s; 01258 } 01259 01260 // Inhibit implicit instantiations for required instantiations, 01261 // which are defined via explicit instantiations elsewhere. 01262 // NB: This syntax is a GNU extension. 01263 #if _GLIBCXX_EXTERN_TEMPLATE 01264 extern template class numpunct<char>; 01265 extern template class numpunct_byname<char>; 01266 extern template class _GLIBCXX_LDBL_NAMESPACE num_get<char>; 01267 extern template class _GLIBCXX_LDBL_NAMESPACE num_put<char>; 01268 extern template class ctype_byname<char>; 01269 01270 extern template 01271 const ctype<char>& 01272 use_facet<ctype<char> >(const locale&); 01273 01274 extern template 01275 const numpunct<char>& 01276 use_facet<numpunct<char> >(const locale&); 01277 01278 extern template 01279 const num_put<char>& 01280 use_facet<num_put<char> >(const locale&); 01281 01282 extern template 01283 const num_get<char>& 01284 use_facet<num_get<char> >(const locale&); 01285 01286 extern template 01287 bool 01288 has_facet<ctype<char> >(const locale&); 01289 01290 extern template 01291 bool 01292 has_facet<numpunct<char> >(const locale&); 01293 01294 extern template 01295 bool 01296 has_facet<num_put<char> >(const locale&); 01297 01298 extern template 01299 bool 01300 has_facet<num_get<char> >(const locale&); 01301 01302 #ifdef _GLIBCXX_USE_WCHAR_T 01303 extern template class numpunct<wchar_t>; 01304 extern template class numpunct_byname<wchar_t>; 01305 extern template class _GLIBCXX_LDBL_NAMESPACE num_get<wchar_t>; 01306 extern template class _GLIBCXX_LDBL_NAMESPACE num_put<wchar_t>; 01307 extern template class ctype_byname<wchar_t>; 01308 01309 extern template 01310 const ctype<wchar_t>& 01311 use_facet<ctype<wchar_t> >(const locale&); 01312 01313 extern template 01314 const numpunct<wchar_t>& 01315 use_facet<numpunct<wchar_t> >(const locale&); 01316 01317 extern template 01318 const num_put<wchar_t>& 01319 use_facet<num_put<wchar_t> >(const locale&); 01320 01321 extern template 01322 const num_get<wchar_t>& 01323 use_facet<num_get<wchar_t> >(const locale&); 01324 01325 extern template 01326 bool 01327 has_facet<ctype<wchar_t> >(const locale&); 01328 01329 extern template 01330 bool 01331 has_facet<numpunct<wchar_t> >(const locale&); 01332 01333 extern template 01334 bool 01335 has_facet<num_put<wchar_t> >(const locale&); 01336 01337 extern template 01338 bool 01339 has_facet<num_get<wchar_t> >(const locale&); 01340 #endif 01341 #endif 01342 01343 _GLIBCXX_END_NAMESPACE 01344 01345 #endif