1// Locale support -*- C++ -*-
2
3// Copyright (C) 2007-2022 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
35namespace 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 const moneypunct<_CharT, _Intl>& __mp =
72 use_facet<moneypunct<_CharT, _Intl> >(__loc);
73
74 struct _Scoped_str
75 {
76 size_t _M_len;
77 _CharT* _M_str;
78
79 explicit
80 _Scoped_str(const basic_string<_CharT>& __str)
81 : _M_len(__str.size()), _M_str(new _CharT[_M_len])
82 { __str.copy(_M_str, _M_len); }
83
84 ~_Scoped_str() { delete[] _M_str; }
85
86 void
87 _M_release(const _CharT*& __p, size_t& __n)
88 {
89 __p = _M_str;
90 __n = _M_len;
91 _M_str = 0;
92 }
93 };
94
95 _Scoped_str __curr_symbol(__mp.curr_symbol());
96 _Scoped_str __positive_sign(__mp.positive_sign());
97 _Scoped_str __negative_sign(__mp.negative_sign());
98
99 const string& __g = __mp.grouping();
100 const size_t __g_size = __g.size();
101 char* const __grouping = new char[__g_size];
102 __g.copy(__grouping, __g_size);
103
104 // All allocations succeeded without throwing, OK to modify *this now.
105
106 _M_grouping = __grouping;
107 _M_grouping_size = __g_size;
108 _M_use_grouping = (__g_size
109 && static_cast<signed char>(__grouping[0]) > 0
110 && (__grouping[0]
111 != __gnu_cxx::__numeric_traits<char>::__max));
112
113 _M_decimal_point = __mp.decimal_point();
114 _M_thousands_sep = __mp.thousands_sep();
115
116 __curr_symbol._M_release(_M_curr_symbol, _M_curr_symbol_size);
117 __positive_sign._M_release(_M_positive_sign, _M_positive_sign_size);
118 __negative_sign._M_release(_M_negative_sign, _M_negative_sign_size);
119
120 _M_frac_digits = __mp.frac_digits();
121 _M_pos_format = __mp.pos_format();
122 _M_neg_format = __mp.neg_format();
123
124 const ctype<_CharT>& __ct = use_facet<ctype<_CharT> >(__loc);
125 __ct.widen(money_base::_S_atoms,
126 money_base::_S_atoms + money_base::_S_end, _M_atoms);
127
128 _M_allocated = true;
129 }
130
131_GLIBCXX_BEGIN_NAMESPACE_LDBL_OR_CXX11
132
133 template<typename _CharT, typename _InIter>
134 template<bool _Intl>
135 _InIter
136 money_get<_CharT, _InIter>::
137 _M_extract(iter_type __beg, iter_type __end, ios_base& __io,
138 ios_base::iostate& __err, string& __units) const
139 {
140 typedef char_traits<_CharT> __traits_type;
141 typedef typename string_type::size_type size_type;
142 typedef money_base::part part;
143 typedef __moneypunct_cache<_CharT, _Intl> __cache_type;
144
145 const locale& __loc = __io._M_getloc();
146 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
147
148 __use_cache<__cache_type> __uc;
149 const __cache_type* __lc = __uc(__loc);
150 const char_type* __lit = __lc->_M_atoms;
151
152 // Deduced sign.
153 bool __negative = false;
154 // Sign size.
155 size_type __sign_size = 0;
156 // True if sign is mandatory.
157 const bool __mandatory_sign = (__lc->_M_positive_sign_size
158 && __lc->_M_negative_sign_size);
159 // String of grouping info from thousands_sep plucked from __units.
160 string __grouping_tmp;
161 if (__lc->_M_use_grouping)
162 __grouping_tmp.reserve(32);
163 // Last position before the decimal point.
164 int __last_pos = 0;
165 // Separator positions, then, possibly, fractional digits.
166 int __n = 0;
167 // If input iterator is in a valid state.
168 bool __testvalid = true;
169 // Flag marking when a decimal point is found.
170 bool __testdecfound = false;
171
172 // The tentative returned string is stored here.
173 string __res;
174 __res.reserve(32);
175
176 const char_type* __lit_zero = __lit + money_base::_S_zero;
177 const money_base::pattern __p = __lc->_M_neg_format;
178 for (int __i = 0; __i < 4 && __testvalid; ++__i)
179 {
180 const part __which = static_cast<part>(__p.field[__i]);
181 switch (__which)
182 {
183 case money_base::symbol:
184 // According to 22.2.6.1.2, p2, symbol is required
185 // if (__io.flags() & ios_base::showbase), otherwise
186 // is optional and consumed only if other characters
187 // are needed to complete the format.
188 if (__io.flags() & ios_base::showbase || __sign_size > 1
189 || __i == 0
190 || (__i == 1 && (__mandatory_sign
191 || (static_cast<part>(__p.field[0])
192 == money_base::sign)
193 || (static_cast<part>(__p.field[2])
194 == money_base::space)))
195 || (__i == 2 && ((static_cast<part>(__p.field[3])
196 == money_base::value)
197 || (__mandatory_sign
198 && (static_cast<part>(__p.field[3])
199 == money_base::sign)))))
200 {
201 const size_type __len = __lc->_M_curr_symbol_size;
202 size_type __j = 0;
203 for (; __beg != __end && __j < __len
204 && *__beg == __lc->_M_curr_symbol[__j];
205 ++__beg, (void)++__j);
206 if (__j != __len
207 && (__j || __io.flags() & ios_base::showbase))
208 __testvalid = false;
209 }
210 break;
211 case money_base::sign:
212 // Sign might not exist, or be more than one character long.
213 if (__lc->_M_positive_sign_size && __beg != __end
214 && *__beg == __lc->_M_positive_sign[0])
215 {
216 __sign_size = __lc->_M_positive_sign_size;
217 ++__beg;
218 }
219 else if (__lc->_M_negative_sign_size && __beg != __end
220 && *__beg == __lc->_M_negative_sign[0])
221 {
222 __negative = true;
223 __sign_size = __lc->_M_negative_sign_size;
224 ++__beg;
225 }
226 else if (__lc->_M_positive_sign_size
227 && !__lc->_M_negative_sign_size)
228 // "... if no sign is detected, the result is given the sign
229 // that corresponds to the source of the empty string"
230 __negative = true;
231 else if (__mandatory_sign)
232 __testvalid = false;
233 break;
234 case money_base::value:
235 // Extract digits, remove and stash away the
236 // grouping of found thousands separators.
237 for (; __beg != __end; ++__beg)
238 {
239 const char_type __c = *__beg;
240 const char_type* __q = __traits_type::find(__lit_zero,
241 10, __c);
242 if (__q != 0)
243 {
244 __res += money_base::_S_atoms[__q - __lit];
245 ++__n;
246 }
247 else if (__c == __lc->_M_decimal_point
248 && !__testdecfound)
249 {
250 if (__lc->_M_frac_digits <= 0)
251 break;
252
253 __last_pos = __n;
254 __n = 0;
255 __testdecfound = true;
256 }
257 else if (__lc->_M_use_grouping
258 && __c == __lc->_M_thousands_sep
259 && !__testdecfound)
260 {
261 if (__n)
262 {
263 // Mark position for later analysis.
264 __grouping_tmp += static_cast<char>(__n);
265 __n = 0;
266 }
267 else
268 {
269 __testvalid = false;
270 break;
271 }
272 }
273 else
274 break;
275 }
276 if (__res.empty())
277 __testvalid = false;
278 break;
279 case money_base::space:
280 // At least one space is required.
281 if (__beg != __end && __ctype.is(ctype_base::space, *__beg))
282 ++__beg;
283 else
284 __testvalid = false;
285 // fallthrough
286 case money_base::none:
287 // Only if not at the end of the pattern.
288 if (__i != 3)
289 for (; __beg != __end
290 && __ctype.is(ctype_base::space, *__beg); ++__beg);
291 break;
292 }
293 }
294
295 // Need to get the rest of the sign characters, if they exist.
296 if (__sign_size > 1 && __testvalid)
297 {
298 const char_type* __sign = __negative ? __lc->_M_negative_sign
299 : __lc->_M_positive_sign;
300 size_type __i = 1;
301 for (; __beg != __end && __i < __sign_size
302 && *__beg == __sign[__i]; ++__beg, (void)++__i);
303
304 if (__i != __sign_size)
305 __testvalid = false;
306 }
307
308 if (__testvalid)
309 {
310 // Strip leading zeros.
311 if (__res.size() > 1)
312 {
313 const size_type __first = __res.find_first_not_of('0');
314 const bool __only_zeros = __first == string::npos;
315 if (__first)
316 __res.erase(0, __only_zeros ? __res.size() - 1 : __first);
317 }
318
319 // 22.2.6.1.2, p4
320 if (__negative && __res[0] != '0')
321 __res.insert(__res.begin(), '-');
322
323 // Test for grouping fidelity.
324 if (__grouping_tmp.size())
325 {
326 // Add the ending grouping.
327 __grouping_tmp += static_cast<char>(__testdecfound ? __last_pos
328 : __n);
329 if (!std::__verify_grouping(__lc->_M_grouping,
330 __lc->_M_grouping_size,
331 __grouping_tmp))
332 __err |= ios_base::failbit;
333 }
334
335 // Iff not enough digits were supplied after the decimal-point.
336 if (__testdecfound && __n != __lc->_M_frac_digits)
337 __testvalid = false;
338 }
339
340 // Iff valid sequence is not recognized.
341 if (!__testvalid)
342 __err |= ios_base::failbit;
343 else
344 __units.swap(__res);
345
346 // Iff no more characters are available.
347 if (__beg == __end)
348 __err |= ios_base::eofbit;
349 return __beg;
350 }
351
352#if defined _GLIBCXX_LONG_DOUBLE_COMPAT && defined __LONG_DOUBLE_128__ \
353 && (_GLIBCXX_USE_CXX11_ABI == 0 || defined __LONG_DOUBLE_IEEE128__)
354 template<typename _CharT, typename _InIter>
355 _InIter
356 money_get<_CharT, _InIter>::
357 __do_get(iter_type __beg, iter_type __end, bool __intl, ios_base& __io,
358 ios_base::iostate& __err, double& __units) const
359 {
360 string __str;
361 __beg = __intl ? _M_extract<true>(__beg, __end, __io, __err, __str)
362 : _M_extract<false>(__beg, __end, __io, __err, __str);
363 std::__convert_to_v(__str.c_str(), __units, __err, _S_get_c_locale());
364 return __beg;
365 }
366#endif
367
368 template<typename _CharT, typename _InIter>
369 _InIter
370 money_get<_CharT, _InIter>::
371 do_get(iter_type __beg, iter_type __end, bool __intl, ios_base& __io,
372 ios_base::iostate& __err, long double& __units) const
373 {
374 string __str;
375 __beg = __intl ? _M_extract<true>(__beg, __end, __io, __err, __str)
376 : _M_extract<false>(__beg, __end, __io, __err, __str);
377 std::__convert_to_v(__str.c_str(), __units, __err, _S_get_c_locale());
378 return __beg;
379 }
380
381 template<typename _CharT, typename _InIter>
382 _InIter
383 money_get<_CharT, _InIter>::
384 do_get(iter_type __beg, iter_type __end, bool __intl, ios_base& __io,
385 ios_base::iostate& __err, string_type& __digits) const
386 {
387 typedef typename string::size_type size_type;
388
389 const locale& __loc = __io._M_getloc();
390 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
391
392 string __str;
393 __beg = __intl ? _M_extract<true>(__beg, __end, __io, __err, __str)
394 : _M_extract<false>(__beg, __end, __io, __err, __str);
395 const size_type __len = __str.size();
396 if (__len)
397 {
398 __digits.resize(__len);
399 __ctype.widen(__str.data(), __str.data() + __len, &__digits[0]);
400 }
401 return __beg;
402 }
403
404#if defined _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT \
405 && defined __LONG_DOUBLE_IEEE128__
406 template<typename _CharT, typename _InIter>
407 _InIter
408 money_get<_CharT, _InIter>::
409 __do_get(iter_type __beg, iter_type __end, bool __intl, ios_base& __io,
410 ios_base::iostate& __err, __ibm128& __units) const
411 {
412 string __str;
413 __beg = __intl ? _M_extract<true>(__beg, __end, __io, __err, __str)
414 : _M_extract<false>(__beg, __end, __io, __err, __str);
415 std::__convert_to_v(__str.c_str(), __units, __err, _S_get_c_locale());
416 return __beg;
417 }
418#endif
419
420 template<typename _CharT, typename _OutIter>
421 template<bool _Intl>
422 _OutIter
423 money_put<_CharT, _OutIter>::
424 _M_insert(iter_type __s, ios_base& __io, char_type __fill,
425 const string_type& __digits) const
426 {
427 typedef typename string_type::size_type size_type;
428 typedef money_base::part part;
429 typedef __moneypunct_cache<_CharT, _Intl> __cache_type;
430
431 const locale& __loc = __io._M_getloc();
432 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
433
434 __use_cache<__cache_type> __uc;
435 const __cache_type* __lc = __uc(__loc);
436 const char_type* __lit = __lc->_M_atoms;
437
438 // Determine if negative or positive formats are to be used, and
439 // discard leading negative_sign if it is present.
440 const char_type* __beg = __digits.data();
441
442 money_base::pattern __p;
443 const char_type* __sign;
444 size_type __sign_size;
445 if (!(*__beg == __lit[money_base::_S_minus]))
446 {
447 __p = __lc->_M_pos_format;
448 __sign = __lc->_M_positive_sign;
449 __sign_size = __lc->_M_positive_sign_size;
450 }
451 else
452 {
453 __p = __lc->_M_neg_format;
454 __sign = __lc->_M_negative_sign;
455 __sign_size = __lc->_M_negative_sign_size;
456 if (__digits.size())
457 ++__beg;
458 }
459
460 // Look for valid numbers in the ctype facet within input digits.
461 size_type __len = __ctype.scan_not(ctype_base::digit, __beg,
462 __beg + __digits.size()) - __beg;
463 if (__len)
464 {
465 // Assume valid input, and attempt to format.
466 // Break down input numbers into base components, as follows:
467 // final_value = grouped units + (decimal point) + (digits)
468 string_type __value;
469 __value.reserve(2 * __len);
470
471 // Add thousands separators to non-decimal digits, per
472 // grouping rules.
473 long __paddec = __len - __lc->_M_frac_digits;
474 if (__paddec > 0)
475 {
476 if (__lc->_M_frac_digits < 0)
477 __paddec = __len;
478 if (__lc->_M_grouping_size)
479 {
480 __value.assign(2 * __paddec, char_type());
481 _CharT* __vend =
482 std::__add_grouping(&__value[0], __lc->_M_thousands_sep,
483 __lc->_M_grouping,
484 __lc->_M_grouping_size,
485 __beg, __beg + __paddec);
486 __value.erase(__vend - &__value[0]);
487 }
488 else
489 __value.assign(__beg, __paddec);
490 }
491
492 // Deal with decimal point, decimal digits.
493 if (__lc->_M_frac_digits > 0)
494 {
495 __value += __lc->_M_decimal_point;
496 if (__paddec >= 0)
497 __value.append(__beg + __paddec, __lc->_M_frac_digits);
498 else
499 {
500 // Have to pad zeros in the decimal position.
501 __value.append(-__paddec, __lit[money_base::_S_zero]);
502 __value.append(__beg, __len);
503 }
504 }
505
506 // Calculate length of resulting string.
507 const ios_base::fmtflags __f = __io.flags()
508 & ios_base::adjustfield;
509 __len = __value.size() + __sign_size;
510 __len += ((__io.flags() & ios_base::showbase)
511 ? __lc->_M_curr_symbol_size : 0);
512
513 string_type __res;
514 __res.reserve(2 * __len);
515
516 const size_type __width = static_cast<size_type>(__io.width());
517 const bool __testipad = (__f == ios_base::internal
518 && __len < __width);
519 // Fit formatted digits into the required pattern.
520 for (int __i = 0; __i < 4; ++__i)
521 {
522 const part __which = static_cast<part>(__p.field[__i]);
523 switch (__which)
524 {
525 case money_base::symbol:
526 if (__io.flags() & ios_base::showbase)
527 __res.append(__lc->_M_curr_symbol,
528 __lc->_M_curr_symbol_size);
529 break;
530 case money_base::sign:
531 // Sign might not exist, or be more than one
532 // character long. In that case, add in the rest
533 // below.
534 if (__sign_size)
535 __res += __sign[0];
536 break;
537 case money_base::value:
538 __res += __value;
539 break;
540 case money_base::space:
541 // At least one space is required, but if internal
542 // formatting is required, an arbitrary number of
543 // fill spaces will be necessary.
544 if (__testipad)
545 __res.append(__width - __len, __fill);
546 else
547 __res += __fill;
548 break;
549 case money_base::none:
550 if (__testipad)
551 __res.append(__width - __len, __fill);
552 break;
553 }
554 }
555
556 // Special case of multi-part sign parts.
557 if (__sign_size > 1)
558 __res.append(__sign + 1, __sign_size - 1);
559
560 // Pad, if still necessary.
561 __len = __res.size();
562 if (__width > __len)
563 {
564 if (__f == ios_base::left)
565 // After.
566 __res.append(__width - __len, __fill);
567 else
568 // Before.
569 __res.insert(0, __width - __len, __fill);
570 __len = __width;
571 }
572
573 // Write resulting, fully-formatted string to output iterator.
574 __s = std::__write(__s, __res.data(), __len);
575 }
576 __io.width(0);
577 return __s;
578 }
579
580#if defined _GLIBCXX_LONG_DOUBLE_COMPAT && defined __LONG_DOUBLE_128__ \
581 && (_GLIBCXX_USE_CXX11_ABI == 0 || defined __LONG_DOUBLE_IEEE128__)
582 template<typename _CharT, typename _OutIter>
583 _OutIter
584 money_put<_CharT, _OutIter>::
585 __do_put(iter_type __s, bool __intl, ios_base& __io, char_type __fill,
586 double __units) const
587 { return this->do_put(__s, __intl, __io, __fill, (long double) __units); }
588#endif
589
590 template<typename _CharT, typename _OutIter>
591 _OutIter
592 money_put<_CharT, _OutIter>::
593 do_put(iter_type __s, bool __intl, ios_base& __io, char_type __fill,
594 long double __units) const
595 {
596 const locale __loc = __io.getloc();
597 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
598#if _GLIBCXX_USE_C99_STDIO
599 // First try a buffer perhaps big enough.
600 int __cs_size = 64;
601 char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
602 // _GLIBCXX_RESOLVE_LIB_DEFECTS
603 // 328. Bad sprintf format modifier in money_put<>::do_put()
604 int __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
605 "%.*Lf", 0, __units);
606 // If the buffer was not large enough, try again with the correct size.
607 if (__len >= __cs_size)
608 {
609 __cs_size = __len + 1;
610 __cs = static_cast<char*>(__builtin_alloca(__cs_size));
611 __len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
612 "%.*Lf", 0, __units);
613 }
614#else
615 // max_exponent10 + 1 for the integer part, + 2 for sign and '\0'.
616 const int __cs_size =
617 __gnu_cxx::__numeric_traits<long double>::__max_exponent10 + 3;
618 char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
619 int __len = std::__convert_from_v(_S_get_c_locale(), __cs, 0, "%.*Lf",
620 0, __units);
621#endif
622 string_type __digits(__len, char_type());
623 __ctype.widen(__cs, __cs + __len, &__digits[0]);
624 return __intl ? _M_insert<true>(__s, __io, __fill, __digits)
625 : _M_insert<false>(__s, __io, __fill, __digits);
626 }
627
628 template<typename _CharT, typename _OutIter>
629 _OutIter
630 money_put<_CharT, _OutIter>::
631 do_put(iter_type __s, bool __intl, ios_base& __io, char_type __fill,
632 const string_type& __digits) const
633 { return __intl ? _M_insert<true>(__s, __io, __fill, __digits)
634 : _M_insert<false>(__s, __io, __fill, __digits); }
635
636#if defined _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT \
637 && defined __LONG_DOUBLE_IEEE128__
638extern "C"
639__typeof__(__builtin_snprintf) __glibcxx_snprintfibm128 __asm__("snprintf");
640
641 template<typename _CharT, typename _OutIter>
642 _OutIter
643 money_put<_CharT, _OutIter>::
644 __do_put(iter_type __s, bool __intl, ios_base& __io, char_type __fill,
645 __ibm128 __units) const
646 {
647 const locale __loc = __io.getloc();
648 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
649 // First try a buffer perhaps big enough.
650 int __cs_size = 64;
651 char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
652 const __c_locale __old = __gnu_cxx::__uselocale(_S_get_c_locale());
653
654 // _GLIBCXX_RESOLVE_LIB_DEFECTS
655 // 328. Bad sprintf format modifier in money_put<>::do_put()
656 int __len = __glibcxx_snprintfibm128(__cs, __cs_size, "%.*Lf", 0,
657 __units);
658 // If the buffer was not large enough, try again with the correct size.
659 if (__len >= __cs_size)
660 {
661 __cs_size = __len + 1;
662 __cs = static_cast<char*>(__builtin_alloca(__cs_size));
663 __len = __glibcxx_snprintfibm128(__cs, __cs_size, "%.*Lf", 0,
664 __units);
665 }
666 __gnu_cxx::__uselocale(__old);
667 string_type __digits(__len, char_type());
668 __ctype.widen(__cs, __cs + __len, &__digits[0]);
669 return __intl ? _M_insert<true>(__s, __io, __fill, __digits)
670 : _M_insert<false>(__s, __io, __fill, __digits);
671 }
672#endif
673
674_GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11
675
676 // NB: Not especially useful. Without an ios_base object or some
677 // kind of locale reference, we are left clawing at the air where
678 // the side of the mountain used to be...
679 template<typename _CharT, typename _InIter>
680 time_base::dateorder
681 time_get<_CharT, _InIter>::do_date_order() const
682 { return time_base::no_order; }
683
684 // Expand a strptime format string and parse it. E.g., do_get_date() may
685 // pass %m/%d/%Y => extracted characters.
686 template<typename _CharT, typename _InIter>
687 _InIter
688 time_get<_CharT, _InIter>::
689 _M_extract_via_format(iter_type __beg, iter_type __end, ios_base& __io,
690 ios_base::iostate& __err, tm* __tm,
691 const _CharT* __format,
692 __time_get_state &__state) const
693 {
694 const locale& __loc = __io._M_getloc();
695 const __timepunct<_CharT>& __tp = use_facet<__timepunct<_CharT> >(__loc);
696 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
697 const size_t __len = char_traits<_CharT>::length(__format);
698
699 ios_base::iostate __tmperr = ios_base::goodbit;
700 size_t __i = 0;
701 for (; __beg != __end && __i < __len && !__tmperr; ++__i)
702 {
703 if (__ctype.narrow(__format[__i], 0) == '%')
704 {
705 // Verify valid formatting code, attempt to extract.
706 char __c = __ctype.narrow(__format[++__i], 0);
707 int __mem = 0;
708 if (__c == 'E' || __c == 'O')
709 __c = __ctype.narrow(__format[++__i], 0);
710 switch (__c)
711 {
712 const char* __cs;
713 _CharT __wcs[10];
714 case 'a':
715 case 'A':
716 // Weekday name (possibly abbreviated) [tm_wday]
717 const char_type* __days[14];
718 __tp._M_days(&__days[0]);
719 __tp._M_days_abbreviated(&__days[7]);
720 __beg = _M_extract_name(__beg, __end, __mem, __days,
721 14, __io, __tmperr);
722 if (!__tmperr)
723 {
724 __tm->tm_wday = __mem % 7;
725 __state._M_have_wday = 1;
726 }
727 break;
728 case 'h':
729 case 'b':
730 case 'B':
731 // Month name (possibly abbreviated) [tm_mon]
732 const char_type* __months[24];
733 __tp._M_months(&__months[0]);
734 __tp._M_months_abbreviated(&__months[12]);
735 __beg = _M_extract_name(__beg, __end, __mem,
736 __months, 24, __io, __tmperr);
737 if (!__tmperr)
738 {
739 __tm->tm_mon = __mem % 12;
740 __state._M_have_mon = 1;
741 __state._M_want_xday = 1;
742 }
743 break;
744 case 'c':
745 // Default time and date representation.
746 const char_type* __dt[2];
747 __tp._M_date_time_formats(__dt);
748 __beg = _M_extract_via_format(__beg, __end, __io, __tmperr,
749 __tm, __dt[0], __state);
750 if (!__tmperr)
751 __state._M_want_xday = 1;
752 break;
753 case 'C':
754 // Century.
755 __beg = _M_extract_num(__beg, __end, __mem, 0, 99, 2,
756 __io, __tmperr);
757 if (!__tmperr)
758 {
759 __state._M_century = __mem;
760 __state._M_have_century = 1;
761 __state._M_want_xday = 1;
762 }
763 break;
764 case 'd':
765 case 'e':
766 // Day [1, 31]. [tm_mday]
767 if (__ctype.is(ctype_base::space, *__beg))
768 ++__beg;
769 __beg = _M_extract_num(__beg, __end, __mem, 1, 31, 2,
770 __io, __tmperr);
771 if (!__tmperr)
772 {
773 __tm->tm_mday = __mem;
774 __state._M_have_mday = 1;
775 __state._M_want_xday = 1;
776 }
777 break;
778 case 'D':
779 // Equivalent to %m/%d/%y.[tm_mon, tm_mday, tm_year]
780 __cs = "%m/%d/%y";
781 __ctype.widen(__cs, __cs + 9, __wcs);
782 __beg = _M_extract_via_format(__beg, __end, __io, __tmperr,
783 __tm, __wcs, __state);
784 if (!__tmperr)
785 __state._M_want_xday = 1;
786 break;
787 case 'H':
788 // Hour [00, 23]. [tm_hour]
789 __beg = _M_extract_num(__beg, __end, __mem, 0, 23, 2,
790 __io, __tmperr);
791 if (!__tmperr)
792 {
793 __tm->tm_hour = __mem;
794 __state._M_have_I = 0;
795 }
796 break;
797 case 'I':
798 // Hour [01, 12]. [tm_hour]
799 __beg = _M_extract_num(__beg, __end, __mem, 1, 12, 2,
800 __io, __tmperr);
801 if (!__tmperr)
802 {
803 __tm->tm_hour = __mem % 12;
804 __state._M_have_I = 1;
805 }
806 break;
807 case 'j':
808 // Day number of year.
809 __beg = _M_extract_num(__beg, __end, __mem, 1, 366, 3,
810 __io, __tmperr);
811 if (!__tmperr)
812 {
813 __tm->tm_yday = __mem - 1;
814 __state._M_have_yday = 1;
815 }
816 break;
817 case 'm':
818 // Month [01, 12]. [tm_mon]
819 __beg = _M_extract_num(__beg, __end, __mem, 1, 12, 2,
820 __io, __tmperr);
821 if (!__tmperr)
822 {
823 __tm->tm_mon = __mem - 1;
824 __state._M_have_mon = 1;
825 }
826 break;
827 case 'M':
828 // Minute [00, 59]. [tm_min]
829 __beg = _M_extract_num(__beg, __end, __mem, 0, 59, 2,
830 __io, __tmperr);
831 if (!__tmperr)
832 __tm->tm_min = __mem;
833 break;
834 case 'n':
835 case 't':
836 while (__beg != __end
837 && __ctype.is(ctype_base::space, *__beg))
838 ++__beg;
839 break;
840 case 'p':
841 // Locale's a.m. or p.m.
842 const char_type* __ampm[2];
843 __tp._M_am_pm(&__ampm[0]);
844 if (!__ampm[0][0] || !__ampm[1][0])
845 break;
846 __beg = _M_extract_name(__beg, __end, __mem, __ampm,
847 2, __io, __tmperr);
848 if (!__tmperr && __mem)
849 __state._M_is_pm = 1;
850 break;
851 case 'r':
852 // Locale's 12-hour clock time format (in C %I:%M:%S %p).
853 const char_type* __ampm_format;
854 __tp._M_am_pm_format(&__ampm_format);
855 __beg = _M_extract_via_format(__beg, __end, __io, __tmperr,
856 __tm, __ampm_format, __state);
857 break;
858 case 'R':
859 // Equivalent to (%H:%M).
860 __cs = "%H:%M";
861 __ctype.widen(__cs, __cs + 6, __wcs);
862 __beg = _M_extract_via_format(__beg, __end, __io, __tmperr,
863 __tm, __wcs, __state);
864 break;
865 case 'S':
866 // Seconds. [tm_sec]
867 // [00, 60] in C99 (one leap-second), [00, 61] in C89.
868#if _GLIBCXX_USE_C99
869 __beg = _M_extract_num(__beg, __end, __mem, 0, 60, 2,
870#else
871 __beg = _M_extract_num(__beg, __end, __mem, 0, 61, 2,
872#endif
873 __io, __tmperr);
874 if (!__tmperr)
875 __tm->tm_sec = __mem;
876 break;
877 case 'T':
878 // Equivalent to (%H:%M:%S).
879 __cs = "%H:%M:%S";
880 __ctype.widen(__cs, __cs + 9, __wcs);
881 __beg = _M_extract_via_format(__beg, __end, __io, __tmperr,
882 __tm, __wcs, __state);
883 break;
884 case 'U':
885 // Week number of the year (Sunday as first day of week).
886 __beg = _M_extract_num(__beg, __end, __mem, 0, 53, 2,
887 __io, __tmperr);
888 if (!__tmperr)
889 {
890 __state._M_week_no = __mem;
891 __state._M_have_uweek = 1;
892 }
893 break;
894 case 'w':
895 // Weekday [tm_wday]
896 __beg = _M_extract_num(__beg, __end, __mem, 0, 6, 1,
897 __io, __tmperr);
898 if (!__tmperr)
899 {
900 __tm->tm_wday = __mem;
901 __state._M_have_wday = 1;
902 }
903 break;
904 case 'W':
905 // Week number of the year (Monday as first day of week).
906 __beg = _M_extract_num(__beg, __end, __mem, 0, 53, 2,
907 __io, __tmperr);
908 if (!__tmperr)
909 {
910 __state._M_week_no = __mem;
911 __state._M_have_wweek = 1;
912 }
913 break;
914 case 'x':
915 // Locale's date.
916 const char_type* __dates[2];
917 __tp._M_date_formats(__dates);
918 __beg = _M_extract_via_format(__beg, __end, __io, __tmperr,
919 __tm, __dates[0], __state);
920 break;
921 case 'X':
922 // Locale's time.
923 const char_type* __times[2];
924 __tp._M_time_formats(__times);
925 __beg = _M_extract_via_format(__beg, __end, __io, __tmperr,
926 __tm, __times[0], __state);
927 break;
928 case 'y':
929 // The last 2 digits of year.
930 __beg = _M_extract_num(__beg, __end, __mem, 0, 99, 2,
931 __io, __tmperr);
932 if (!__tmperr)
933 {
934 __state._M_want_century = 1;
935 __state._M_want_xday = 1;
936 // As an extension, if the 2 digits are followed by
937 // 1-2 further digits, treat it like %Y.
938 __c = 0;
939 if (__beg != __end)
940 __c = __ctype.narrow(*__beg, '*');
941 if (__c >= '0' && __c <= '9')
942 {
943 ++__beg;
944 __mem = __mem * 10 + (__c - '0');
945 if (__beg != __end)
946 {
947 __c = __ctype.narrow(*__beg, '*');
948 if (__c >= '0' && __c <= '9')
949 {
950 ++__beg;
951 __mem = __mem * 10 + (__c - '0');
952 }
953 }
954 __mem -= 1900;
955 __state._M_want_century = 0;
956 }
957 // Otherwise, as per POSIX 2008, 00-68 is 2000-2068,
958 // while 69-99 is 1969-1999.
959 else if (__mem < 69)
960 __mem += 100;
961 __tm->tm_year = __mem;
962 }
963 break;
964 case 'Y':
965 // Year.
966 __beg = _M_extract_num(__beg, __end, __mem, 0, 9999, 4,
967 __io, __tmperr);
968 if (!__tmperr)
969 {
970 __tm->tm_year = __mem - 1900;
971 __state._M_want_century = 0;
972 __state._M_want_xday = 1;
973 }
974 break;
975 case 'Z':
976 // Timezone info.
977 if (__ctype.is(ctype_base::upper, *__beg))
978 {
979 int __tmp;
980 __beg = _M_extract_name(__beg, __end, __tmp,
981 __timepunct_cache<_CharT>::_S_timezones,
982 14, __io, __tmperr);
983
984 // GMT requires special effort.
985 if (__beg != __end && !__tmperr && __tmp == 0
986 && (*__beg == __ctype.widen('-')
987 || *__beg == __ctype.widen('+')))
988 {
989 __beg = _M_extract_num(__beg, __end, __tmp, 0, 23, 2,
990 __io, __tmperr);
991 __beg = _M_extract_num(__beg, __end, __tmp, 0, 59, 2,
992 __io, __tmperr);
993 }
994 }
995 else
996 __tmperr |= ios_base::failbit;
997 break;
998 case '%':
999 if (*__beg == __ctype.widen('%'))
1000 ++__beg;
1001 else
1002 __tmperr |= ios_base::failbit;
1003 break;
1004 default:
1005 // Not recognized.
1006 __tmperr |= ios_base::failbit;
1007 }
1008 }
1009 else if (__ctype.is(ctype_base::space, __format[__i]))
1010 {
1011 // Skip any whitespace.
1012 while (__beg != __end
1013 && __ctype.is(ctype_base::space, *__beg))
1014 ++__beg;
1015 }
1016 else
1017 {
1018 // Verify format and input match, extract and discard.
1019 // TODO real case-insensitive comparison
1020 if (__ctype.tolower(__format[__i]) == __ctype.tolower(*__beg)
1021 || __ctype.toupper(__format[__i]) == __ctype.toupper(*__beg))
1022 ++__beg;
1023 else
1024 __tmperr |= ios_base::failbit;
1025 }
1026 }
1027
1028 if (__tmperr || __i != __len)
1029 __err |= ios_base::failbit;
1030
1031 return __beg;
1032 }
1033
1034 template<typename _CharT, typename _InIter>
1035 _InIter
1036 time_get<_CharT, _InIter>::
1037 _M_extract_via_format(iter_type __beg, iter_type __end, ios_base& __io,
1038 ios_base::iostate& __err, tm* __tm,
1039 const _CharT* __format) const
1040 {
1041 __time_get_state __state = __time_get_state();
1042 return _M_extract_via_format(__beg, __end, __io, __err, __tm,
1043 __format, __state);
1044 }
1045
1046 template<typename _CharT, typename _InIter>
1047 _InIter
1048 time_get<_CharT, _InIter>::
1049 _M_extract_num(iter_type __beg, iter_type __end, int& __member,
1050 int __min, int __max, size_t __len,
1051 ios_base& __io, ios_base::iostate& __err) const
1052 {
1053 const locale& __loc = __io._M_getloc();
1054 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
1055
1056 size_t __i = 0;
1057 int __value = 0;
1058 for (; __beg != __end && __i < __len; ++__beg, (void)++__i)
1059 {
1060 const char __c = __ctype.narrow(*__beg, '*');
1061 if (__c >= '0' && __c <= '9')
1062 {
1063 __value = __value * 10 + (__c - '0');
1064 if (__value > __max)
1065 break;
1066 }
1067 else
1068 break;
1069 }
1070 if (__i && __value >= __min && __value <= __max)
1071 __member = __value;
1072 else
1073 __err |= ios_base::failbit;
1074
1075 return __beg;
1076 }
1077
1078 // Assumptions:
1079 // All elements in __names are unique, except if __indexlen is
1080 // even __names in the first half could be the same as corresponding
1081 // __names in the second half (May is abbreviated as May). Some __names
1082 // elements could be prefixes of other __names elements.
1083 template<typename _CharT, typename _InIter>
1084 _InIter
1085 time_get<_CharT, _InIter>::
1086 _M_extract_name(iter_type __beg, iter_type __end, int& __member,
1087 const _CharT** __names, size_t __indexlen,
1088 ios_base& __io, ios_base::iostate& __err) const
1089 {
1090 typedef char_traits<_CharT> __traits_type;
1091 const locale& __loc = __io._M_getloc();
1092 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
1093
1094 size_t* __matches
1095 = static_cast<size_t*>(__builtin_alloca(2 * sizeof(size_t)
1096 * __indexlen));
1097 size_t* __lengths = __matches + __indexlen;
1098 size_t __nmatches = 0;
1099 size_t __pos = 0;
1100 bool __testvalid = true;
1101 const char_type* __name;
1102 bool __begupdated = false;
1103
1104 // Look for initial matches.
1105 if (__beg != __end)
1106 {
1107 const char_type __c = *__beg;
1108 // TODO real case-insensitive comparison
1109 const char_type __cl = __ctype.tolower(__c);
1110 const char_type __cu = __ctype.toupper(__c);
1111 for (size_t __i1 = 0; __i1 < __indexlen; ++__i1)
1112 if (__cl == __ctype.tolower(__names[__i1][0])
1113 || __cu == __ctype.toupper(__names[__i1][0]))
1114 {
1115 __lengths[__nmatches]
1116 = __traits_type::length(__names[__i1]);
1117 __matches[__nmatches++] = __i1;
1118 }
1119 }
1120
1121 while (__nmatches > 1)
1122 {
1123 // Find smallest matching string.
1124 size_t __minlen = __lengths[0];
1125 for (size_t __i2 = 1; __i2 < __nmatches; ++__i2)
1126 __minlen = std::min(__minlen, __lengths[__i2]);
1127 ++__pos;
1128 ++__beg;
1129 if (__pos == __minlen)
1130 {
1131 // If some match has remaining length of 0,
1132 // need to decide if any match with remaining
1133 // length non-zero matches the next character.
1134 // If so, remove all matches with remaining length
1135 // 0 from consideration, otherwise keep only matches
1136 // with remaining length 0.
1137 bool __match_longer = false;
1138
1139 if (__beg != __end)
1140 {
1141 // TODO real case-insensitive comparison
1142 const char_type __cl = __ctype.tolower(*__beg);
1143 const char_type __cu = __ctype.toupper(*__beg);
1144 for (size_t __i3 = 0; __i3 < __nmatches; ++__i3)
1145 {
1146 __name = __names[__matches[__i3]];
1147 if (__lengths[__i3] > __pos
1148 && (__ctype.tolower(__name[__pos]) == __cl
1149 || __ctype.toupper(__name[__pos]) == __cu))
1150 {
1151 __match_longer = true;
1152 break;
1153 }
1154 }
1155 }
1156 for (size_t __i4 = 0; __i4 < __nmatches;)
1157 if (__match_longer == (__lengths[__i4] == __pos))
1158 {
1159 __matches[__i4] = __matches[--__nmatches];
1160 __lengths[__i4] = __lengths[__nmatches];
1161 }
1162 else
1163 ++__i4;
1164 if (__match_longer)
1165 {
1166 __minlen = __lengths[0];
1167 for (size_t __i5 = 1; __i5 < __nmatches; ++__i5)
1168 __minlen = std::min(__minlen, __lengths[__i5]);
1169 }
1170 else
1171 {
1172 // Deal with May being full as well as abbreviated month
1173 // name. Pick the smaller index.
1174 if (__nmatches == 2 && (__indexlen & 1) == 0)
1175 {
1176 if (__matches[0] < __indexlen / 2)
1177 {
1178 if (__matches[1] == __matches[0] + __indexlen / 2)
1179 __nmatches = 1;
1180 }
1181 else if (__matches[1] == __matches[0] - __indexlen / 2)
1182 {
1183 __matches[0] = __matches[1];
1184 __lengths[0] = __lengths[1];
1185 __nmatches = 1;
1186 }
1187 }
1188 __begupdated = true;
1189 break;
1190 }
1191 }
1192 if (__pos < __minlen && __beg != __end)
1193 {
1194 // TODO real case-insensitive comparison
1195 const char_type __cl = __ctype.tolower(*__beg);
1196 const char_type __cu = __ctype.toupper(*__beg);
1197 for (size_t __i6 = 0; __i6 < __nmatches;)
1198 {
1199 __name = __names[__matches[__i6]];
1200 if (__ctype.tolower(__name[__pos]) != __cl
1201 && __ctype.toupper(__name[__pos]) != __cu)
1202 {
1203 __matches[__i6] = __matches[--__nmatches];
1204 __lengths[__i6] = __lengths[__nmatches];
1205 }
1206 else
1207 ++__i6;
1208 }
1209 }
1210 else
1211 break;
1212 }
1213
1214 if (__nmatches == 1)
1215 {
1216 // Make sure found name is completely extracted.
1217 if (!__begupdated)
1218 {
1219 ++__beg;
1220 ++__pos;
1221 }
1222 __name = __names[__matches[0]];
1223 const size_t __len = __lengths[0];
1224 while (__pos < __len
1225 && __beg != __end
1226 // TODO real case-insensitive comparison
1227 && (__ctype.tolower(__name[__pos]) == __ctype.tolower(*__beg)
1228 || (__ctype.toupper(__name[__pos])
1229 == __ctype.toupper(*__beg))))
1230 ++__beg, (void)++__pos;
1231
1232 if (__len == __pos)
1233 __member = __matches[0];
1234 else
1235 __testvalid = false;
1236 }
1237 else
1238 __testvalid = false;
1239 if (!__testvalid)
1240 __err |= ios_base::failbit;
1241
1242 return __beg;
1243 }
1244
1245 template<typename _CharT, typename _InIter>
1246 _InIter
1247 time_get<_CharT, _InIter>::
1248 _M_extract_wday_or_month(iter_type __beg, iter_type __end, int& __member,
1249 const _CharT** __names, size_t __indexlen,
1250 ios_base& __io, ios_base::iostate& __err) const
1251 {
1252 typedef char_traits<_CharT> __traits_type;
1253 const locale& __loc = __io._M_getloc();
1254 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
1255
1256 int* __matches = static_cast<int*>(__builtin_alloca(2 * sizeof(int)
1257 * __indexlen));
1258 size_t __nmatches = 0;
1259 size_t* __matches_lengths = 0;
1260 size_t __pos = 0;
1261
1262 if (__beg != __end)
1263 {
1264 const char_type __c = *__beg;
1265 for (size_t __i = 0; __i < 2 * __indexlen; ++__i)
1266 if (__c == __names[__i][0]
1267 || __c == __ctype.toupper(__names[__i][0]))
1268 __matches[__nmatches++] = __i;
1269 }
1270
1271 if (__nmatches)
1272 {
1273 ++__beg;
1274 ++__pos;
1275
1276 __matches_lengths
1277 = static_cast<size_t*>(__builtin_alloca(sizeof(size_t)
1278 * __nmatches));
1279 for (size_t __i = 0; __i < __nmatches; ++__i)
1280 __matches_lengths[__i]
1281 = __traits_type::length(__names[__matches[__i]]);
1282 }
1283
1284 for (; __beg != __end; ++__beg, (void)++__pos)
1285 {
1286 size_t __nskipped = 0;
1287 const char_type __c = *__beg;
1288 for (size_t __i = 0; __i < __nmatches;)
1289 {
1290 const char_type* __name = __names[__matches[__i]];
1291 if (__pos >= __matches_lengths[__i])
1292 ++__nskipped, ++__i;
1293 else if (!(__name[__pos] == __c))
1294 {
1295 --__nmatches;
1296 __matches[__i] = __matches[__nmatches];
1297 __matches_lengths[__i] = __matches_lengths[__nmatches];
1298 }
1299 else
1300 ++__i;
1301 }
1302 if (__nskipped == __nmatches)
1303 break;
1304 }
1305
1306 if ((__nmatches == 1 && __matches_lengths[0] == __pos)
1307 || (__nmatches == 2 && (__matches_lengths[0] == __pos
1308 || __matches_lengths[1] == __pos)))
1309 __member = (__matches[0] >= (int)__indexlen
1310 ? __matches[0] - (int)__indexlen : __matches[0]);
1311 else
1312 __err |= ios_base::failbit;
1313
1314 return __beg;
1315 }
1316
1317 template<typename _CharT, typename _InIter>
1318 _InIter
1319 time_get<_CharT, _InIter>::
1320 do_get_time(iter_type __beg, iter_type __end, ios_base& __io,
1321 ios_base::iostate& __err, tm* __tm) const
1322 {
1323 const locale& __loc = __io._M_getloc();
1324 const __timepunct<_CharT>& __tp = use_facet<__timepunct<_CharT> >(__loc);
1325 const char_type* __times[2];
1326 __tp._M_time_formats(__times);
1327 __time_get_state __state = __time_get_state();
1328 __beg = _M_extract_via_format(__beg, __end, __io, __err,
1329 __tm, __times[0], __state);
1330 __state._M_finalize_state(__tm);
1331 if (__beg == __end)
1332 __err |= ios_base::eofbit;
1333 return __beg;
1334 }
1335
1336 template<typename _CharT, typename _InIter>
1337 _InIter
1338 time_get<_CharT, _InIter>::
1339 do_get_date(iter_type __beg, iter_type __end, ios_base& __io,
1340 ios_base::iostate& __err, tm* __tm) const
1341 {
1342 const locale& __loc = __io._M_getloc();
1343 const __timepunct<_CharT>& __tp = use_facet<__timepunct<_CharT> >(__loc);
1344 const char_type* __dates[2];
1345 __tp._M_date_formats(__dates);
1346 __time_get_state __state = __time_get_state();
1347 __beg = _M_extract_via_format(__beg, __end, __io, __err,
1348 __tm, __dates[0], __state);
1349 __state._M_finalize_state(__tm);
1350 if (__beg == __end)
1351 __err |= ios_base::eofbit;
1352 return __beg;
1353 }
1354
1355 template<typename _CharT, typename _InIter>
1356 _InIter
1357 time_get<_CharT, _InIter>::
1358 do_get_weekday(iter_type __beg, iter_type __end, ios_base& __io,
1359 ios_base::iostate& __err, tm* __tm) const
1360 {
1361 const locale& __loc = __io._M_getloc();
1362 const __timepunct<_CharT>& __tp = use_facet<__timepunct<_CharT> >(__loc);
1363 const char_type* __days[14];
1364 __tp._M_days_abbreviated(__days);
1365 __tp._M_days(__days + 7);
1366 int __tmpwday;
1367 ios_base::iostate __tmperr = ios_base::goodbit;
1368
1369 __beg = _M_extract_wday_or_month(__beg, __end, __tmpwday, __days, 7,
1370 __io, __tmperr);
1371 if (!__tmperr)
1372 __tm->tm_wday = __tmpwday;
1373 else
1374 __err |= ios_base::failbit;
1375
1376 if (__beg == __end)
1377 __err |= ios_base::eofbit;
1378 return __beg;
1379 }
1380
1381 template<typename _CharT, typename _InIter>
1382 _InIter
1383 time_get<_CharT, _InIter>::
1384 do_get_monthname(iter_type __beg, iter_type __end,
1385 ios_base& __io, ios_base::iostate& __err, tm* __tm) const
1386 {
1387 const locale& __loc = __io._M_getloc();
1388 const __timepunct<_CharT>& __tp = use_facet<__timepunct<_CharT> >(__loc);
1389 const char_type* __months[24];
1390 __tp._M_months_abbreviated(__months);
1391 __tp._M_months(__months + 12);
1392 int __tmpmon;
1393 ios_base::iostate __tmperr = ios_base::goodbit;
1394
1395 __beg = _M_extract_wday_or_month(__beg, __end, __tmpmon, __months, 12,
1396 __io, __tmperr);
1397 if (!__tmperr)
1398 __tm->tm_mon = __tmpmon;
1399 else
1400 __err |= ios_base::failbit;
1401
1402 if (__beg == __end)
1403 __err |= ios_base::eofbit;
1404 return __beg;
1405 }
1406
1407 template<typename _CharT, typename _InIter>
1408 _InIter
1409 time_get<_CharT, _InIter>::
1410 do_get_year(iter_type __beg, iter_type __end, ios_base& __io,
1411 ios_base::iostate& __err, tm* __tm) const
1412 {
1413 int __tmpyear;
1414 ios_base::iostate __tmperr = ios_base::goodbit;
1415 const locale& __loc = __io._M_getloc();
1416 const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
1417
1418 __beg = _M_extract_num(__beg, __end, __tmpyear, 0, 99, 2,
1419 __io, __tmperr);
1420 if (!__tmperr)
1421 {
1422 char __c = 0;
1423 if (__beg != __end)
1424 __c = __ctype.narrow(*__beg, '*');
1425 // For 1-2 digit year, assume 69-99 is 1969-1999, 0-68 is 2000-2068.
1426 // For 3-4 digit year, use it as year.
1427 // __tm->tm_year needs year - 1900 though.
1428 if (__c >= '0' && __c <= '9')
1429 {
1430 ++__beg;
1431 __tmpyear = __tmpyear * 10 + (__c - '0');
1432 if (__beg != __end)
1433 {
1434 __c = __ctype.narrow(*__beg, '*');
1435 if (__c >= '0' && __c <= '9')
1436 {
1437 ++__beg;
1438 __tmpyear = __tmpyear * 10 + (__c - '0');
1439 }
1440 }
1441 __tmpyear -= 1900;
1442 }
1443 else if (__tmpyear < 69)
1444 __tmpyear += 100;
1445 __tm->tm_year = __tmpyear;
1446 }
1447 else
1448 __err |= ios_base::failbit;
1449
1450 if (__beg == __end)
1451 __err |= ios_base::eofbit;
1452 return __beg;
1453 }
1454
1455#if __cplusplus >= 201103L
1456 template<typename _CharT, typename _InIter>
1457 inline
1458 _InIter
1459 time_get<_CharT, _InIter>::
1460 get(iter_type __s, iter_type __end, ios_base& __io,
1461 ios_base::iostate& __err, tm* __tm, const char_type* __fmt,
1462 const char_type* __fmtend) const
1463 {
1464 const locale& __loc = __io._M_getloc();
1465 ctype<_CharT> const& __ctype = use_facet<ctype<_CharT> >(__loc);
1466 __err = ios_base::goodbit;
1467 bool __use_state = false;
1468#if __GNUC__ >= 5 && !defined(__clang__)
1469#pragma GCC diagnostic push
1470#pragma GCC diagnostic ignored "-Wpmf-conversions"
1471 // Nasty hack. The C++ standard mandates that get invokes the do_get
1472 // virtual method, but unfortunately at least without an ABI change
1473 // for the facets we can't keep state across the different do_get
1474 // calls. So e.g. if __fmt is "%p %I:%M:%S", we can't handle it
1475 // properly, because we first handle the %p am/pm specifier and only
1476 // later the 12-hour format specifier.
1477 if ((void*)(this->*(&time_get::do_get)) == (void*)(&time_get::do_get))
1478 __use_state = true;
1479#pragma GCC diagnostic pop
1480#endif
1481 __time_get_state __state = __time_get_state();
1482 while (__fmt != __fmtend &&
1483 __err == ios_base::goodbit)
1484 {
1485 if (__s == __end)
1486 {
1487 __err = ios_base::eofbit | ios_base::failbit;
1488 break;
1489 }
1490 else if (__ctype.narrow(*__fmt, 0) == '%')
1491 {
1492 const char_type* __fmt_start = __fmt;
1493 char __format;
1494 char __mod = 0;
1495 if (++__fmt == __fmtend)
1496 {
1497 __err = ios_base::failbit;
1498 break;
1499 }
1500 const char __c = __ctype.narrow(*__fmt, 0);
1501 if (__c != 'E' && __c != 'O')
1502 __format = __c;
1503 else if (++__fmt != __fmtend)
1504 {
1505 __mod = __c;
1506 __format = __ctype.narrow(*__fmt, 0);
1507 }
1508 else
1509 {
1510 __err = ios_base::failbit;
1511 break;
1512 }
1513 if (__use_state)
1514 {
1515 char_type __new_fmt[4];
1516 __new_fmt[0] = __fmt_start[0];
1517 __new_fmt[1] = __fmt_start[1];
1518 if (__mod)
1519 {
1520 __new_fmt[2] = __fmt_start[2];
1521 __new_fmt[3] = char_type();
1522 }
1523 else
1524 __new_fmt[2] = char_type();
1525 __s = _M_extract_via_format(__s, __end, __io, __err, __tm,
1526 __new_fmt, __state);
1527 if (__s == __end)
1528 __err |= ios_base::eofbit;
1529 }
1530 else
1531 __s = this->do_get(__s, __end, __io, __err, __tm, __format,
1532 __mod);
1533 ++__fmt;
1534 }
1535 else if (__ctype.is(ctype_base::space, *__fmt))
1536 {
1537 ++__fmt;
1538 while (__fmt != __fmtend &&
1539 __ctype.is(ctype_base::space, *__fmt))
1540 ++__fmt;
1541
1542 while (__s != __end &&
1543 __ctype.is(ctype_base::space, *__s))
1544 ++__s;
1545 }
1546 // TODO real case-insensitive comparison
1547 else if (__ctype.tolower(*__s) == __ctype.tolower(*__fmt) ||
1548 __ctype.toupper(*__s) == __ctype.toupper(*__fmt))
1549 {
1550 ++__s;
1551 ++__fmt;
1552 }
1553 else
1554 {
1555 __err = ios_base::failbit;
1556 break;
1557 }
1558 }
1559 if (__use_state)
1560 __state._M_finalize_state(__tm);
1561 return __s;
1562 }
1563
1564 template<typename _CharT, typename _InIter>
1565 inline
1566 _InIter
1567 time_get<_CharT, _InIter>::
1568 do_get(iter_type __beg, iter_type __end, ios_base& __io,
1569 ios_base::iostate& __err, tm* __tm,
1570 char __format, char __mod) const
1571 {
1572 const locale& __loc = __io._M_getloc();
1573 ctype<_CharT> const& __ctype = use_facet<ctype<_CharT> >(__loc);
1574 __err = ios_base::goodbit;
1575
1576 char_type __fmt[4];
1577 __fmt[0] = __ctype.widen('%');
1578 if (!__mod)
1579 {
1580 __fmt[1] = __format;
1581 __fmt[2] = char_type();
1582 }
1583 else
1584 {
1585 __fmt[1] = __mod;
1586 __fmt[2] = __format;
1587 __fmt[3] = char_type();
1588 }
1589
1590 __time_get_state __state = __time_get_state();
1591 __beg = _M_extract_via_format(__beg, __end, __io, __err, __tm, __fmt,
1592 __state);
1593 __state._M_finalize_state(__tm);
1594 if (__beg == __end)
1595 __err |= ios_base::eofbit;
1596 return __beg;
1597 }
1598
1599#endif // __cplusplus >= 201103L
1600
1601 template<typename _CharT, typename _OutIter>
1602 _OutIter
1603 time_put<_CharT, _OutIter>::
1604 put(iter_type __s, ios_base& __io, char_type __fill, const tm* __tm,
1605 const _CharT* __beg, const _CharT* __end) const
1606 {
1607 const locale& __loc = __io._M_getloc();
1608 ctype<_CharT> const& __ctype = use_facet<ctype<_CharT> >(__loc);
1609 for (; __beg != __end; ++__beg)
1610 if (__ctype.narrow(*__beg, 0) != '%')
1611 {
1612 *__s = *__beg;
1613 ++__s;
1614 }
1615 else if (++__beg != __end)
1616 {
1617 char __format;
1618 char __mod = 0;
1619 const char __c = __ctype.narrow(*__beg, 0);
1620 if (__c != 'E' && __c != 'O')
1621 __format = __c;
1622 else if (++__beg != __end)
1623 {
1624 __mod = __c;
1625 __format = __ctype.narrow(*__beg, 0);
1626 }
1627 else
1628 break;
1629 __s = this->do_put(__s, __io, __fill, __tm, __format, __mod);
1630 }
1631 else
1632 break;
1633 return __s;
1634 }
1635
1636 template<typename _CharT, typename _OutIter>
1637 _OutIter
1638 time_put<_CharT, _OutIter>::
1639 do_put(iter_type __s, ios_base& __io, char_type, const tm* __tm,
1640 char __format, char __mod) const
1641 {
1642 const locale& __loc = __io._M_getloc();
1643 ctype<_CharT> const& __ctype = use_facet<ctype<_CharT> >(__loc);
1644 __timepunct<_CharT> const& __tp = use_facet<__timepunct<_CharT> >(__loc);
1645
1646 // NB: This size is arbitrary. Should this be a data member,
1647 // initialized at construction?
1648 const size_t __maxlen = 128;
1649 char_type __res[__maxlen];
1650
1651 // NB: In IEE 1003.1-200x, and perhaps other locale models, it
1652 // is possible that the format character will be longer than one
1653 // character. Possibilities include 'E' or 'O' followed by a
1654 // format character: if __mod is not the default argument, assume
1655 // it's a valid modifier.
1656 char_type __fmt[4];
1657 __fmt[0] = __ctype.widen('%');
1658 if (!__mod)
1659 {
1660 __fmt[1] = __format;
1661 __fmt[2] = char_type();
1662 }
1663 else
1664 {
1665 __fmt[1] = __mod;
1666 __fmt[2] = __format;
1667 __fmt[3] = char_type();
1668 }
1669
1670 __tp._M_put(__res, __maxlen, __fmt, __tm);
1671
1672 // Write resulting, fully-formatted string to output iterator.
1673 return std::__write(__s, __res, char_traits<char_type>::length(__res));
1674 }
1675
1676
1677 // Inhibit implicit instantiations for required instantiations,
1678 // which are defined via explicit instantiations elsewhere.
1679#if _GLIBCXX_EXTERN_TEMPLATE
1680 extern template class moneypunct<char, false>;
1681 extern template class moneypunct<char, true>;
1682 extern template class moneypunct_byname<char, false>;
1683 extern template class moneypunct_byname<char, true>;
1684 extern template class _GLIBCXX_NAMESPACE_LDBL_OR_CXX11 money_get<char>;
1685 extern template class _GLIBCXX_NAMESPACE_LDBL_OR_CXX11 money_put<char>;
1686 extern template class __timepunct<char>;
1687 extern template class time_put<char>;
1688 extern template class time_put_byname<char>;
1689 extern template class time_get<char>;
1690 extern template class time_get_byname<char>;
1691 extern template class messages<char>;
1692 extern template class messages_byname<char>;
1693
1694 extern template
1695 const moneypunct<char, true>&
1696 use_facet<moneypunct<char, true> >(const locale&);
1697
1698 extern template
1699 const moneypunct<char, false>&
1700 use_facet<moneypunct<char, false> >(const locale&);
1701
1702 extern template
1703 const money_put<char>&
1704 use_facet<money_put<char> >(const locale&);
1705
1706 extern template
1707 const money_get<char>&
1708 use_facet<money_get<char> >(const locale&);
1709
1710 extern template
1711 const __timepunct<char>&
1712 use_facet<__timepunct<char> >(const locale&);
1713
1714 extern template
1715 const time_put<char>&
1716 use_facet<time_put<char> >(const locale&);
1717
1718 extern template
1719 const time_get<char>&
1720 use_facet<time_get<char> >(const locale&);
1721
1722 extern template
1723 const messages<char>&
1724 use_facet<messages<char> >(const locale&);
1725
1726 extern template
1727 bool
1728 has_facet<moneypunct<char> >(const locale&);
1729
1730 extern template
1731 bool
1732 has_facet<money_put<char> >(const locale&);
1733
1734 extern template
1735 bool
1736 has_facet<money_get<char> >(const locale&);
1737
1738 extern template
1739 bool
1740 has_facet<__timepunct<char> >(const locale&);
1741
1742 extern template
1743 bool
1744 has_facet<time_put<char> >(const locale&);
1745
1746 extern template
1747 bool
1748 has_facet<time_get<char> >(const locale&);
1749
1750 extern template
1751 bool
1752 has_facet<messages<char> >(const locale&);
1753
1754#ifdef _GLIBCXX_USE_WCHAR_T
1755 extern template class moneypunct<wchar_t, false>;
1756 extern template class moneypunct<wchar_t, true>;
1757 extern template class moneypunct_byname<wchar_t, false>;
1758 extern template class moneypunct_byname<wchar_t, true>;
1759 extern template class _GLIBCXX_NAMESPACE_LDBL_OR_CXX11 money_get<wchar_t>;
1760 extern template class _GLIBCXX_NAMESPACE_LDBL_OR_CXX11 money_put<wchar_t>;
1761 extern template class __timepunct<wchar_t>;
1762 extern template class time_put<wchar_t>;
1763 extern template class time_put_byname<wchar_t>;
1764 extern template class time_get<wchar_t>;
1765 extern template class time_get_byname<wchar_t>;
1766 extern template class messages<wchar_t>;
1767 extern template class messages_byname<wchar_t>;
1768
1769 extern template
1770 const moneypunct<wchar_t, true>&
1771 use_facet<moneypunct<wchar_t, true> >(const locale&);
1772
1773 extern template
1774 const moneypunct<wchar_t, false>&
1775 use_facet<moneypunct<wchar_t, false> >(const locale&);
1776
1777 extern template
1778 const money_put<wchar_t>&
1779 use_facet<money_put<wchar_t> >(const locale&);
1780
1781 extern template
1782 const money_get<wchar_t>&
1783 use_facet<money_get<wchar_t> >(const locale&);
1784
1785 extern template
1786 const __timepunct<wchar_t>&
1787 use_facet<__timepunct<wchar_t> >(const locale&);
1788
1789 extern template
1790 const time_put<wchar_t>&
1791 use_facet<time_put<wchar_t> >(const locale&);
1792
1793 extern template
1794 const time_get<wchar_t>&
1795 use_facet<time_get<wchar_t> >(const locale&);
1796
1797 extern template
1798 const messages<wchar_t>&
1799 use_facet<messages<wchar_t> >(const locale&);
1800
1801 extern template
1802 bool
1803 has_facet<moneypunct<wchar_t> >(const locale&);
1804
1805 extern template
1806 bool
1807 has_facet<money_put<wchar_t> >(const locale&);
1808
1809 extern template
1810 bool
1811 has_facet<money_get<wchar_t> >(const locale&);
1812
1813 extern template
1814 bool
1815 has_facet<__timepunct<wchar_t> >(const locale&);
1816
1817 extern template
1818 bool
1819 has_facet<time_put<wchar_t> >(const locale&);
1820
1821 extern template
1822 bool
1823 has_facet<time_get<wchar_t> >(const locale&);
1824
1825 extern template
1826 bool
1827 has_facet<messages<wchar_t> >(const locale&);
1828#endif
1829#endif
1830
1831_GLIBCXX_END_NAMESPACE_VERSION
1832} // namespace std
1833
1834#endif
1835