libstdc++

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