This source file includes following definitions.
- fwrite_lowcase
- fwrite_uppcase
- memcpy_lowcase
- memcpy_uppcase
- tm_diff
- iso_week_days
- my_strftime
- libc_hidden_def
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 #ifdef _LIBC
18 # define USE_IN_EXTENDED_LOCALE_MODEL 1
19 # define HAVE_STRUCT_ERA_ENTRY 1
20 # define HAVE_TM_GMTOFF 1
21 # define HAVE_STRUCT_TM_TM_ZONE 1
22 # define HAVE_TZNAME 1
23 # include "../locale/localeinfo.h"
24 #else
25 # include <libc-config.h>
26 # if FPRINTFTIME
27 # include "fprintftime.h"
28 # else
29 # include "strftime.h"
30 # endif
31 # include "time-internal.h"
32 #endif
33
34 #include <ctype.h>
35 #include <errno.h>
36 #include <time.h>
37
38 #if HAVE_TZNAME && !HAVE_DECL_TZNAME
39 extern char *tzname[];
40 #endif
41
42
43
44
45
46
47
48
49
50
51
52
53
54 #if !(defined __osf__ && 0)
55 # define MULTIBYTE_IS_FORMAT_SAFE 1
56 #endif
57 #define DO_MULTIBYTE (! MULTIBYTE_IS_FORMAT_SAFE)
58
59 #if DO_MULTIBYTE
60 # include <wchar.h>
61 static const mbstate_t mbstate_zero;
62 #endif
63
64 #include <limits.h>
65 #include <stdckdint.h>
66 #include <stddef.h>
67 #include <stdlib.h>
68 #include <string.h>
69
70 #include "attribute.h"
71 #include <intprops.h>
72
73 #ifdef COMPILE_WIDE
74 # include <endian.h>
75 # define CHAR_T wchar_t
76 # define UCHAR_T unsigned int
77 # define L_(Str) L##Str
78 # define NLW(Sym) _NL_W##Sym
79
80 # define MEMCPY(d, s, n) __wmemcpy (d, s, n)
81 # define STRLEN(s) __wcslen (s)
82
83 #else
84 # define CHAR_T char
85 # define UCHAR_T unsigned char
86 # define L_(Str) Str
87 # define NLW(Sym) Sym
88 # define ABALTMON_1 _NL_ABALTMON_1
89
90 # define MEMCPY(d, s, n) memcpy (d, s, n)
91 # define STRLEN(s) strlen (s)
92
93 #endif
94
95
96
97
98
99
100
101
102
103
104
105 #define SHR(a, b) \
106 (-1 >> 1 == -1 \
107 ? (a) >> (b) \
108 : ((a) + ((a) < 0)) / (1 << (b)) - ((a) < 0))
109
110 #define TM_YEAR_BASE 1900
111
112 #ifndef __isleap
113
114
115 # define __isleap(year) \
116 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
117 #endif
118
119
120 #ifdef _LIBC
121 # define mktime_z(tz, tm) mktime (tm)
122 # define tzname __tzname
123 # define tzset __tzset
124 #endif
125
126 #ifndef FPRINTFTIME
127 # define FPRINTFTIME 0
128 #endif
129
130 #if FPRINTFTIME
131 # define STREAM_OR_CHAR_T FILE
132 # define STRFTIME_ARG(x)
133 #else
134 # define STREAM_OR_CHAR_T CHAR_T
135 # define STRFTIME_ARG(x) x,
136 #endif
137
138 #if FPRINTFTIME
139 # define memset_byte(P, Len, Byte) \
140 do { size_t _i; for (_i = 0; _i < Len; _i++) fputc (Byte, P); } while (0)
141 # define memset_space(P, Len) memset_byte (P, Len, ' ')
142 # define memset_zero(P, Len) memset_byte (P, Len, '0')
143 #elif defined COMPILE_WIDE
144 # define memset_space(P, Len) (wmemset (P, L' ', Len), (P) += (Len))
145 # define memset_zero(P, Len) (wmemset (P, L'0', Len), (P) += (Len))
146 #else
147 # define memset_space(P, Len) (memset (P, ' ', Len), (P) += (Len))
148 # define memset_zero(P, Len) (memset (P, '0', Len), (P) += (Len))
149 #endif
150
151 #if FPRINTFTIME
152 # define advance(P, N)
153 #else
154 # define advance(P, N) ((P) += (N))
155 #endif
156
157 #define add(n, f) width_add (width, n, f)
158 #define width_add(width, n, f) \
159 do \
160 { \
161 size_t _n = (n); \
162 size_t _w = pad == L_('-') || width < 0 ? 0 : width; \
163 size_t _incr = _n < _w ? _w : _n; \
164 if (_incr >= maxsize - i) \
165 { \
166 errno = ERANGE; \
167 return 0; \
168 } \
169 if (p) \
170 { \
171 if (_n < _w) \
172 { \
173 size_t _delta = _w - _n; \
174 if (pad == L_('0') || pad == L_('+')) \
175 memset_zero (p, _delta); \
176 else \
177 memset_space (p, _delta); \
178 } \
179 f; \
180 advance (p, _n); \
181 } \
182 i += _incr; \
183 } while (0)
184
185 #define add1(c) width_add1 (width, c)
186 #if FPRINTFTIME
187 # define width_add1(width, c) width_add (width, 1, fputc (c, p))
188 #else
189 # define width_add1(width, c) width_add (width, 1, *p = c)
190 #endif
191
192 #define cpy(n, s) width_cpy (width, n, s)
193 #if FPRINTFTIME
194 # define width_cpy(width, n, s) \
195 width_add (width, n, \
196 do \
197 { \
198 if (to_lowcase) \
199 fwrite_lowcase (p, (s), _n); \
200 else if (to_uppcase) \
201 fwrite_uppcase (p, (s), _n); \
202 else \
203 { \
204
205
206
207
208 \
209 fwrite (s, _n, 1, p); \
210 } \
211 } \
212 while (0) \
213 )
214 #else
215 # define width_cpy(width, n, s) \
216 width_add (width, n, \
217 if (to_lowcase) \
218 memcpy_lowcase (p, (s), _n LOCALE_ARG); \
219 else if (to_uppcase) \
220 memcpy_uppcase (p, (s), _n LOCALE_ARG); \
221 else \
222 MEMCPY ((void *) p, (void const *) (s), _n))
223 #endif
224
225 #ifdef COMPILE_WIDE
226 # ifndef USE_IN_EXTENDED_LOCALE_MODEL
227 # undef __mbsrtowcs_l
228 # define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
229 # endif
230 #endif
231
232
233 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
234
235
236
237
238 # define strftime __strftime_l
239 # define wcsftime __wcsftime_l
240 # undef _NL_CURRENT
241 # define _NL_CURRENT(category, item) \
242 (current->values[_NL_ITEM_INDEX (item)].string)
243 # define LOCALE_PARAM , locale_t loc
244 # define LOCALE_ARG , loc
245 # define HELPER_LOCALE_ARG , current
246 #else
247 # define LOCALE_PARAM
248 # define LOCALE_ARG
249 # ifdef _LIBC
250 # define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
251 # else
252 # define HELPER_LOCALE_ARG
253 # endif
254 #endif
255
256 #ifdef COMPILE_WIDE
257 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
258 # define TOUPPER(Ch, L) __towupper_l (Ch, L)
259 # define TOLOWER(Ch, L) __towlower_l (Ch, L)
260 # else
261 # define TOUPPER(Ch, L) towupper (Ch)
262 # define TOLOWER(Ch, L) towlower (Ch)
263 # endif
264 #else
265 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
266 # define TOUPPER(Ch, L) __toupper_l (Ch, L)
267 # define TOLOWER(Ch, L) __tolower_l (Ch, L)
268 # else
269 # define TOUPPER(Ch, L) toupper (Ch)
270 # define TOLOWER(Ch, L) tolower (Ch)
271 # endif
272 #endif
273
274
275
276
277 #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
278
279
280
281
282
283 #if __GNUC__ >= 7 && !__OPTIMIZE__
284 # pragma GCC diagnostic ignored "-Wstringop-overflow"
285 #endif
286
287 #if FPRINTFTIME
288 static void
289 fwrite_lowcase (FILE *fp, const CHAR_T *src, size_t len)
290 {
291 while (len-- > 0)
292 {
293 fputc (TOLOWER ((UCHAR_T) *src, loc), fp);
294 ++src;
295 }
296 }
297
298 static void
299 fwrite_uppcase (FILE *fp, const CHAR_T *src, size_t len)
300 {
301 while (len-- > 0)
302 {
303 fputc (TOUPPER ((UCHAR_T) *src, loc), fp);
304 ++src;
305 }
306 }
307 #else
308 static CHAR_T *memcpy_lowcase (CHAR_T *dest, const CHAR_T *src,
309 size_t len LOCALE_PARAM);
310
311 static CHAR_T *
312 memcpy_lowcase (CHAR_T *dest, const CHAR_T *src, size_t len LOCALE_PARAM)
313 {
314 while (len-- > 0)
315 dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
316 return dest;
317 }
318
319 static CHAR_T *memcpy_uppcase (CHAR_T *dest, const CHAR_T *src,
320 size_t len LOCALE_PARAM);
321
322 static CHAR_T *
323 memcpy_uppcase (CHAR_T *dest, const CHAR_T *src, size_t len LOCALE_PARAM)
324 {
325 while (len-- > 0)
326 dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
327 return dest;
328 }
329 #endif
330
331
332 #if ! HAVE_TM_GMTOFF
333
334
335 # define tm_diff ftime_tm_diff
336 static int tm_diff (const struct tm *, const struct tm *);
337 static int
338 tm_diff (const struct tm *a, const struct tm *b)
339 {
340
341
342
343 int a4 = SHR (a->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (a->tm_year & 3);
344 int b4 = SHR (b->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (b->tm_year & 3);
345 int a100 = (a4 + (a4 < 0)) / 25 - (a4 < 0);
346 int b100 = (b4 + (b4 < 0)) / 25 - (b4 < 0);
347 int a400 = SHR (a100, 2);
348 int b400 = SHR (b100, 2);
349 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
350 int years = a->tm_year - b->tm_year;
351 int days = (365 * years + intervening_leap_days
352 + (a->tm_yday - b->tm_yday));
353 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
354 + (a->tm_min - b->tm_min))
355 + (a->tm_sec - b->tm_sec));
356 }
357 #endif
358
359
360
361
362
363
364
365 #define ISO_WEEK_START_WDAY 1
366 #define ISO_WEEK1_WDAY 4
367 #define YDAY_MINIMUM (-366)
368 static int iso_week_days (int, int);
369 static __inline int
370 iso_week_days (int yday, int wday)
371 {
372
373 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
374 return (yday
375 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
376 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
377 }
378
379
380
381
382
383
384 #if FPRINTFTIME
385 # undef my_strftime
386 # define my_strftime fprintftime
387 #endif
388
389 #ifdef my_strftime
390 # define extra_args , tz, ns
391 # define extra_args_spec , timezone_t tz, int ns
392 #else
393 # if defined COMPILE_WIDE
394 # define my_strftime wcsftime
395 # define nl_get_alt_digit _nl_get_walt_digit
396 # else
397 # define my_strftime strftime
398 # define nl_get_alt_digit _nl_get_alt_digit
399 # endif
400 # define extra_args
401 # define extra_args_spec
402
403 # define tz 1
404 # define ns 0
405 #endif
406
407 static size_t __strftime_internal (STREAM_OR_CHAR_T *, STRFTIME_ARG (size_t)
408 const CHAR_T *, const struct tm *,
409 bool, int, int, bool *
410 extra_args_spec LOCALE_PARAM);
411
412
413
414
415
416
417
418 size_t
419 my_strftime (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
420 const CHAR_T *format,
421 const struct tm *tp extra_args_spec LOCALE_PARAM)
422 {
423 bool tzset_called = false;
424 return __strftime_internal (s, STRFTIME_ARG (maxsize) format, tp, false,
425 0, -1, &tzset_called extra_args LOCALE_ARG);
426 }
427 libc_hidden_def (my_strftime)
428
429
430
431
432
433 static size_t
434 __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
435 const CHAR_T *format,
436 const struct tm *tp, bool upcase,
437 int yr_spec, int width, bool *tzset_called
438 extra_args_spec LOCALE_PARAM)
439 {
440 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
441 struct __locale_data *const current = loc->__locales[LC_TIME];
442 #endif
443 #if FPRINTFTIME
444 size_t maxsize = (size_t) -1;
445 #endif
446
447 int saved_errno = errno;
448 int hour12 = tp->tm_hour;
449 #ifdef _NL_CURRENT
450
451
452
453
454
455
456 # define a_wkday \
457 ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6 \
458 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday)))
459 # define f_wkday \
460 ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6 \
461 ? "?" : _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday)))
462 # define a_month \
463 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
464 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon)))
465 # define f_month \
466 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
467 ? "?" : _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon)))
468 # define a_altmonth \
469 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
470 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABALTMON_1) + tp->tm_mon)))
471 # define f_altmonth \
472 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
473 ? "?" : _NL_CURRENT (LC_TIME, NLW(ALTMON_1) + tp->tm_mon)))
474 # define ampm \
475 ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
476 ? NLW(PM_STR) : NLW(AM_STR)))
477
478 # define aw_len STRLEN (a_wkday)
479 # define am_len STRLEN (a_month)
480 # define aam_len STRLEN (a_altmonth)
481 # define ap_len STRLEN (ampm)
482 #endif
483 #if HAVE_TZNAME
484 char **tzname_vec = tzname;
485 #endif
486 const char *zone;
487 size_t i = 0;
488 STREAM_OR_CHAR_T *p = s;
489 const CHAR_T *f;
490 #if DO_MULTIBYTE && !defined COMPILE_WIDE
491 const char *format_end = NULL;
492 #endif
493
494 zone = NULL;
495 #if HAVE_STRUCT_TM_TM_ZONE
496
497
498
499
500
501
502 zone = (const char *) tp->tm_zone;
503 #endif
504 #if HAVE_TZNAME
505 if (!tz)
506 {
507 if (! (zone && *zone))
508 zone = "GMT";
509 }
510 else
511 {
512 # if !HAVE_STRUCT_TM_TM_ZONE
513
514 tzname_vec = tz->tzname_copy;
515 # endif
516 }
517
518 if (!(zone && *zone) && tp->tm_isdst >= 0)
519 {
520
521
522 # ifndef my_strftime
523 if (!*tzset_called)
524 {
525 tzset ();
526 *tzset_called = true;
527 }
528 # endif
529 zone = tzname_vec[tp->tm_isdst != 0];
530 }
531 #endif
532 if (! zone)
533 zone = "";
534
535 if (hour12 > 12)
536 hour12 -= 12;
537 else
538 if (hour12 == 0)
539 hour12 = 12;
540
541 for (f = format; *f != '\0'; width = -1, f++)
542 {
543 int pad = 0;
544 int modifier;
545 int digits = 0;
546 int number_value;
547 unsigned int u_number_value;
548 bool negative_number;
549 bool always_output_a_sign;
550 int tz_colon_mask;
551 const CHAR_T *subfmt;
552 CHAR_T *bufp;
553 CHAR_T buf[1
554 + 2
555 + (sizeof (int) < sizeof (time_t)
556 ? INT_STRLEN_BOUND (time_t)
557 : INT_STRLEN_BOUND (int))];
558 bool to_lowcase = false;
559 bool to_uppcase = upcase;
560 size_t colons;
561 bool change_case = false;
562 int format_char;
563 int subwidth;
564
565 #if DO_MULTIBYTE && !defined COMPILE_WIDE
566 switch (*f)
567 {
568 case L_('%'):
569 break;
570
571 case L_('\b'): case L_('\t'): case L_('\n'):
572 case L_('\v'): case L_('\f'): case L_('\r'):
573 case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
574 case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
575 case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
576 case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
577 case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
578 case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
579 case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
580 case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
581 case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
582 case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
583 case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
584 case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
585 case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
586 case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
587 case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
588 case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
589 case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
590 case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
591 case L_('~'):
592
593
594
595
596 add1 (*f);
597 continue;
598
599 default:
600
601
602 {
603 mbstate_t mbstate = mbstate_zero;
604 size_t len = 0;
605 size_t fsize;
606
607 if (! format_end)
608 format_end = f + strlen (f) + 1;
609 fsize = format_end - f;
610
611 do
612 {
613 size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
614
615 if (bytes == 0)
616 break;
617
618 if (bytes == (size_t) -2)
619 {
620 len += strlen (f + len);
621 break;
622 }
623
624 if (bytes == (size_t) -1)
625 {
626 len++;
627 break;
628 }
629
630 len += bytes;
631 }
632 while (! mbsinit (&mbstate));
633
634 cpy (len, f);
635 f += len - 1;
636 continue;
637 }
638 }
639
640 #else
641
642
643
644
645 if (*f != L_('%'))
646 {
647 add1 (*f);
648 continue;
649 }
650
651 #endif
652
653 char const *percent = f;
654
655
656 while (1)
657 {
658 switch (*++f)
659 {
660
661 case L_('_'):
662 case L_('-'):
663 case L_('+'):
664 case L_('0'):
665 pad = *f;
666 continue;
667
668
669 case L_('^'):
670 to_uppcase = true;
671 continue;
672 case L_('#'):
673 change_case = true;
674 continue;
675
676 default:
677 break;
678 }
679 break;
680 }
681
682 if (ISDIGIT (*f))
683 {
684 width = 0;
685 do
686 {
687 if (ckd_mul (&width, width, 10)
688 || ckd_add (&width, width, *f - L_('0')))
689 width = INT_MAX;
690 ++f;
691 }
692 while (ISDIGIT (*f));
693 }
694
695
696 switch (*f)
697 {
698 case L_('E'):
699 case L_('O'):
700 modifier = *f++;
701 break;
702
703 default:
704 modifier = 0;
705 break;
706 }
707
708
709 format_char = *f;
710 switch (format_char)
711 {
712 #define DO_NUMBER(d, v) \
713 do \
714 { \
715 digits = d; \
716 number_value = v; \
717 goto do_number; \
718 } \
719 while (0)
720 #define DO_SIGNED_NUMBER(d, negative, v) \
721 DO_MAYBE_SIGNED_NUMBER (d, negative, v, do_signed_number)
722 #define DO_YEARISH(d, negative, v) \
723 DO_MAYBE_SIGNED_NUMBER (d, negative, v, do_yearish)
724 #define DO_MAYBE_SIGNED_NUMBER(d, negative, v, label) \
725 do \
726 { \
727 digits = d; \
728 negative_number = negative; \
729 u_number_value = v; \
730 goto label; \
731 } \
732 while (0)
733
734
735
736
737 #define DO_TZ_OFFSET(d, mask, v) \
738 do \
739 { \
740 digits = d; \
741 tz_colon_mask = mask; \
742 u_number_value = v; \
743 goto do_tz_offset; \
744 } \
745 while (0)
746 #define DO_NUMBER_SPACEPAD(d, v) \
747 do \
748 { \
749 digits = d; \
750 number_value = v; \
751 goto do_number_spacepad; \
752 } \
753 while (0)
754
755 case L_('%'):
756 if (f - 1 != percent)
757 goto bad_percent;
758 add1 (*f);
759 break;
760
761 case L_('a'):
762 if (modifier != 0)
763 goto bad_format;
764 if (change_case)
765 {
766 to_uppcase = true;
767 to_lowcase = false;
768 }
769 #ifdef _NL_CURRENT
770 cpy (aw_len, a_wkday);
771 break;
772 #else
773 goto underlying_strftime;
774 #endif
775
776 case 'A':
777 if (modifier != 0)
778 goto bad_format;
779 if (change_case)
780 {
781 to_uppcase = true;
782 to_lowcase = false;
783 }
784 #ifdef _NL_CURRENT
785 cpy (STRLEN (f_wkday), f_wkday);
786 break;
787 #else
788 goto underlying_strftime;
789 #endif
790
791 case L_('b'):
792 case L_('h'):
793 if (change_case)
794 {
795 to_uppcase = true;
796 to_lowcase = false;
797 }
798 if (modifier == L_('E'))
799 goto bad_format;
800 #ifdef _NL_CURRENT
801 if (modifier == L_('O'))
802 cpy (aam_len, a_altmonth);
803 else
804 cpy (am_len, a_month);
805 break;
806 #else
807 goto underlying_strftime;
808 #endif
809
810 case L_('B'):
811 if (modifier == L_('E'))
812 goto bad_format;
813 if (change_case)
814 {
815 to_uppcase = true;
816 to_lowcase = false;
817 }
818 #ifdef _NL_CURRENT
819 if (modifier == L_('O'))
820 cpy (STRLEN (f_altmonth), f_altmonth);
821 else
822 cpy (STRLEN (f_month), f_month);
823 break;
824 #else
825 goto underlying_strftime;
826 #endif
827
828 case L_('c'):
829 if (modifier == L_('O'))
830 goto bad_format;
831 #ifdef _NL_CURRENT
832 if (! (modifier == L_('E')
833 && (*(subfmt =
834 (const CHAR_T *) _NL_CURRENT (LC_TIME,
835 NLW(ERA_D_T_FMT)))
836 != '\0')))
837 subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
838 #else
839 goto underlying_strftime;
840 #endif
841
842 subformat:
843 subwidth = -1;
844 subformat_width:
845 {
846 size_t len = __strftime_internal (NULL, STRFTIME_ARG ((size_t) -1)
847 subfmt, tp, to_uppcase,
848 pad, subwidth, tzset_called
849 extra_args LOCALE_ARG);
850 add (len, __strftime_internal (p,
851 STRFTIME_ARG (maxsize - i)
852 subfmt, tp, to_uppcase,
853 pad, subwidth, tzset_called
854 extra_args LOCALE_ARG));
855 }
856 break;
857
858 #if !(defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
859 underlying_strftime:
860 {
861
862
863 char ufmt[5];
864 char *u = ufmt;
865 char ubuf[1024];
866 size_t len;
867
868
869
870 # ifdef strftime
871 # undef strftime
872 size_t strftime ();
873 # endif
874
875
876
877 *u++ = ' ';
878 *u++ = '%';
879 if (modifier != 0)
880 *u++ = modifier;
881 *u++ = format_char;
882 *u = '\0';
883 len = strftime (ubuf, sizeof ubuf, ufmt, tp);
884 if (len != 0)
885 cpy (len - 1, ubuf + 1);
886 }
887 break;
888 #endif
889
890 case L_('C'):
891 if (modifier == L_('E'))
892 {
893 #if HAVE_STRUCT_ERA_ENTRY
894 struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
895 if (era)
896 {
897 # ifdef COMPILE_WIDE
898 size_t len = __wcslen (era->era_wname);
899 cpy (len, era->era_wname);
900 # else
901 size_t len = strlen (era->era_name);
902 cpy (len, era->era_name);
903 # endif
904 break;
905 }
906 #else
907 goto underlying_strftime;
908 #endif
909 }
910
911 {
912 bool negative_year = tp->tm_year < - TM_YEAR_BASE;
913 bool zero_thru_1899 = !negative_year & (tp->tm_year < 0);
914 int century = ((tp->tm_year - 99 * zero_thru_1899) / 100
915 + TM_YEAR_BASE / 100);
916 DO_YEARISH (2, negative_year, century);
917 }
918
919 case L_('x'):
920 if (modifier == L_('O'))
921 goto bad_format;
922 #ifdef _NL_CURRENT
923 if (! (modifier == L_('E')
924 && (*(subfmt =
925 (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
926 != L_('\0'))))
927 subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
928 goto subformat;
929 #else
930 goto underlying_strftime;
931 #endif
932 case L_('D'):
933 if (modifier != 0)
934 goto bad_format;
935 subfmt = L_("%m/%d/%y");
936 goto subformat;
937
938 case L_('d'):
939 if (modifier == L_('E'))
940 goto bad_format;
941
942 DO_NUMBER (2, tp->tm_mday);
943
944 case L_('e'):
945 if (modifier == L_('E'))
946 goto bad_format;
947
948 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
949
950
951
952
953 do_tz_offset:
954 always_output_a_sign = true;
955 goto do_number_body;
956
957 do_yearish:
958 if (pad == 0)
959 pad = yr_spec;
960 always_output_a_sign
961 = (pad == L_('+')
962 && ((digits == 2 ? 99 : 9999) < u_number_value
963 || digits < width));
964 goto do_maybe_signed_number;
965
966 do_number_spacepad:
967 if (pad == 0)
968 pad = L_('_');
969
970 do_number:
971
972 negative_number = number_value < 0;
973 u_number_value = number_value;
974
975 do_signed_number:
976 always_output_a_sign = false;
977
978 do_maybe_signed_number:
979 tz_colon_mask = 0;
980
981 do_number_body:
982
983
984
985
986
987 if (modifier == L_('O') && !negative_number)
988 {
989 #ifdef _NL_CURRENT
990
991
992 const CHAR_T *cp = nl_get_alt_digit (u_number_value
993 HELPER_LOCALE_ARG);
994
995 if (cp != NULL)
996 {
997 size_t digitlen = STRLEN (cp);
998 if (digitlen != 0)
999 {
1000 cpy (digitlen, cp);
1001 break;
1002 }
1003 }
1004 #else
1005 goto underlying_strftime;
1006 #endif
1007 }
1008
1009 bufp = buf + sizeof (buf) / sizeof (buf[0]);
1010
1011 if (negative_number)
1012 u_number_value = - u_number_value;
1013
1014 do
1015 {
1016 if (tz_colon_mask & 1)
1017 *--bufp = ':';
1018 tz_colon_mask >>= 1;
1019 *--bufp = u_number_value % 10 + L_('0');
1020 u_number_value /= 10;
1021 }
1022 while (u_number_value != 0 || tz_colon_mask != 0);
1023
1024 do_number_sign_and_padding:
1025 if (pad == 0)
1026 pad = L_('0');
1027 if (width < 0)
1028 width = digits;
1029
1030 {
1031 CHAR_T sign_char = (negative_number ? L_('-')
1032 : always_output_a_sign ? L_('+')
1033 : 0);
1034 int numlen = buf + sizeof buf / sizeof buf[0] - bufp;
1035 int shortage = width - !!sign_char - numlen;
1036 int padding = pad == L_('-') || shortage <= 0 ? 0 : shortage;
1037
1038 if (sign_char)
1039 {
1040 if (pad == L_('_'))
1041 {
1042 if (p)
1043 memset_space (p, padding);
1044 i += padding;
1045 width -= padding;
1046 }
1047 width_add1 (0, sign_char);
1048 width--;
1049 }
1050
1051 cpy (numlen, bufp);
1052 }
1053 break;
1054
1055 case L_('F'):
1056 if (modifier != 0)
1057 goto bad_format;
1058 if (pad == 0 && width < 0)
1059 {
1060 pad = L_('+');
1061 subwidth = 4;
1062 }
1063 else
1064 {
1065 subwidth = width - 6;
1066 if (subwidth < 0)
1067 subwidth = 0;
1068 }
1069 subfmt = L_("%Y-%m-%d");
1070 goto subformat_width;
1071
1072 case L_('H'):
1073 if (modifier == L_('E'))
1074 goto bad_format;
1075
1076 DO_NUMBER (2, tp->tm_hour);
1077
1078 case L_('I'):
1079 if (modifier == L_('E'))
1080 goto bad_format;
1081
1082 DO_NUMBER (2, hour12);
1083
1084 case L_('k'):
1085 if (modifier == L_('E'))
1086 goto bad_format;
1087
1088 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
1089
1090 case L_('l'):
1091 if (modifier == L_('E'))
1092 goto bad_format;
1093
1094 DO_NUMBER_SPACEPAD (2, hour12);
1095
1096 case L_('j'):
1097 if (modifier == L_('E'))
1098 goto bad_format;
1099
1100 DO_SIGNED_NUMBER (3, tp->tm_yday < -1, tp->tm_yday + 1U);
1101
1102 case L_('M'):
1103 if (modifier == L_('E'))
1104 goto bad_format;
1105
1106 DO_NUMBER (2, tp->tm_min);
1107
1108 case L_('m'):
1109 if (modifier == L_('E'))
1110 goto bad_format;
1111
1112 DO_SIGNED_NUMBER (2, tp->tm_mon < -1, tp->tm_mon + 1U);
1113
1114 #ifndef _LIBC
1115 case L_('N'):
1116 if (modifier == L_('E'))
1117 goto bad_format;
1118 {
1119 int n = ns, ns_digits = 9;
1120 if (width <= 0)
1121 width = ns_digits;
1122 int ndigs = ns_digits;
1123 while (width < ndigs || (1 < ndigs && n % 10 == 0))
1124 ndigs--, n /= 10;
1125 for (int j = ndigs; 0 < j; j--)
1126 buf[j - 1] = n % 10 + L_('0'), n /= 10;
1127 if (!pad)
1128 pad = L_('0');
1129 width_cpy (0, ndigs, buf);
1130 width_add (width - ndigs, 0, (void) 0);
1131 }
1132 break;
1133 #endif
1134
1135 case L_('n'):
1136 add1 (L_('\n'));
1137 break;
1138
1139 case L_('P'):
1140 to_lowcase = true;
1141 #ifndef _NL_CURRENT
1142 format_char = L_('p');
1143 #endif
1144 FALLTHROUGH;
1145 case L_('p'):
1146 if (change_case)
1147 {
1148 to_uppcase = false;
1149 to_lowcase = true;
1150 }
1151 #ifdef _NL_CURRENT
1152 cpy (ap_len, ampm);
1153 break;
1154 #else
1155 goto underlying_strftime;
1156 #endif
1157
1158 case L_('q'):
1159 DO_SIGNED_NUMBER (1, false, ((tp->tm_mon * 11) >> 5) + 1);
1160
1161 case L_('R'):
1162 subfmt = L_("%H:%M");
1163 goto subformat;
1164
1165 case L_('r'):
1166 #ifdef _NL_CURRENT
1167 if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
1168 NLW(T_FMT_AMPM)))
1169 == L_('\0'))
1170 subfmt = L_("%I:%M:%S %p");
1171 goto subformat;
1172 #else
1173 goto underlying_strftime;
1174 #endif
1175
1176 case L_('S'):
1177 if (modifier == L_('E'))
1178 goto bad_format;
1179
1180 DO_NUMBER (2, tp->tm_sec);
1181
1182 case L_('s'):
1183 {
1184 struct tm ltm;
1185 time_t t;
1186
1187 ltm = *tp;
1188 ltm.tm_yday = -1;
1189 t = mktime_z (tz, <m);
1190 if (ltm.tm_yday < 0)
1191 {
1192 errno = EOVERFLOW;
1193 return 0;
1194 }
1195
1196
1197
1198
1199 bufp = buf + sizeof (buf) / sizeof (buf[0]);
1200 negative_number = t < 0;
1201
1202 do
1203 {
1204 int d = t % 10;
1205 t /= 10;
1206 *--bufp = (negative_number ? -d : d) + L_('0');
1207 }
1208 while (t != 0);
1209
1210 digits = 1;
1211 always_output_a_sign = false;
1212 goto do_number_sign_and_padding;
1213 }
1214
1215 case L_('X'):
1216 if (modifier == L_('O'))
1217 goto bad_format;
1218 #ifdef _NL_CURRENT
1219 if (! (modifier == L_('E')
1220 && (*(subfmt =
1221 (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
1222 != L_('\0'))))
1223 subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
1224 goto subformat;
1225 #else
1226 goto underlying_strftime;
1227 #endif
1228 case L_('T'):
1229 subfmt = L_("%H:%M:%S");
1230 goto subformat;
1231
1232 case L_('t'):
1233 add1 (L_('\t'));
1234 break;
1235
1236 case L_('u'):
1237 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1238
1239 case L_('U'):
1240 if (modifier == L_('E'))
1241 goto bad_format;
1242
1243 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1244
1245 case L_('V'):
1246 case L_('g'):
1247 case L_('G'):
1248 if (modifier == L_('E'))
1249 goto bad_format;
1250 {
1251
1252
1253
1254
1255 int year = (tp->tm_year
1256 + (tp->tm_year < 0
1257 ? TM_YEAR_BASE % 400
1258 : TM_YEAR_BASE % 400 - 400));
1259 int year_adjust = 0;
1260 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1261
1262 if (days < 0)
1263 {
1264
1265 year_adjust = -1;
1266 days = iso_week_days (tp->tm_yday + (365 + __isleap (year - 1)),
1267 tp->tm_wday);
1268 }
1269 else
1270 {
1271 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1272 tp->tm_wday);
1273 if (0 <= d)
1274 {
1275
1276 year_adjust = 1;
1277 days = d;
1278 }
1279 }
1280
1281 switch (*f)
1282 {
1283 case L_('g'):
1284 {
1285 int yy = (tp->tm_year % 100 + year_adjust) % 100;
1286 DO_YEARISH (2, false,
1287 (0 <= yy
1288 ? yy
1289 : tp->tm_year < -TM_YEAR_BASE - year_adjust
1290 ? -yy
1291 : yy + 100));
1292 }
1293
1294 case L_('G'):
1295 DO_YEARISH (4, tp->tm_year < -TM_YEAR_BASE - year_adjust,
1296 (tp->tm_year + (unsigned int) TM_YEAR_BASE
1297 + year_adjust));
1298
1299 default:
1300 DO_NUMBER (2, days / 7 + 1);
1301 }
1302 }
1303
1304 case L_('W'):
1305 if (modifier == L_('E'))
1306 goto bad_format;
1307
1308 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1309
1310 case L_('w'):
1311 if (modifier == L_('E'))
1312 goto bad_format;
1313
1314 DO_NUMBER (1, tp->tm_wday);
1315
1316 case L_('Y'):
1317 if (modifier == L_('E'))
1318 {
1319 #if HAVE_STRUCT_ERA_ENTRY
1320 struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1321 if (era)
1322 {
1323 # ifdef COMPILE_WIDE
1324 subfmt = era->era_wformat;
1325 # else
1326 subfmt = era->era_format;
1327 # endif
1328 if (pad == 0)
1329 pad = yr_spec;
1330 goto subformat;
1331 }
1332 #else
1333 goto underlying_strftime;
1334 #endif
1335 }
1336 if (modifier == L_('O'))
1337 goto bad_format;
1338
1339 DO_YEARISH (4, tp->tm_year < -TM_YEAR_BASE,
1340 tp->tm_year + (unsigned int) TM_YEAR_BASE);
1341
1342 case L_('y'):
1343 if (modifier == L_('E'))
1344 {
1345 #if HAVE_STRUCT_ERA_ENTRY
1346 struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1347 if (era)
1348 {
1349 int delta = tp->tm_year - era->start_date[0];
1350 if (pad == 0)
1351 pad = yr_spec;
1352 DO_NUMBER (2, (era->offset
1353 + delta * era->absolute_direction));
1354 }
1355 #else
1356 goto underlying_strftime;
1357 #endif
1358 }
1359
1360 {
1361 int yy = tp->tm_year % 100;
1362 if (yy < 0)
1363 yy = tp->tm_year < - TM_YEAR_BASE ? -yy : yy + 100;
1364 DO_YEARISH (2, false, yy);
1365 }
1366
1367 case L_('Z'):
1368 if (change_case)
1369 {
1370 to_uppcase = false;
1371 to_lowcase = true;
1372 }
1373
1374 #ifdef COMPILE_WIDE
1375 {
1376
1377
1378 size_t w = pad == L_('-') || width < 0 ? 0 : width;
1379 char const *z = zone;
1380 mbstate_t st = {0};
1381 size_t len = __mbsrtowcs_l (p, &z, maxsize - i, &st, loc);
1382 if (len == (size_t) -1)
1383 return 0;
1384 size_t incr = len < w ? w : len;
1385 if (incr >= maxsize - i)
1386 {
1387 errno = ERANGE;
1388 return 0;
1389 }
1390 if (p)
1391 {
1392 if (len < w)
1393 {
1394 size_t delta = w - len;
1395 __wmemmove (p + delta, p, len);
1396 wchar_t wc = pad == L_('0') || pad == L_('+') ? L'0' : L' ';
1397 wmemset (p, wc, delta);
1398 }
1399 p += incr;
1400 }
1401 i += incr;
1402 }
1403 #else
1404 cpy (strlen (zone), zone);
1405 #endif
1406 break;
1407
1408 case L_(':'):
1409
1410
1411 for (colons = 1; f[colons] == L_(':'); colons++)
1412 continue;
1413 if (f[colons] != L_('z'))
1414 goto bad_format;
1415 f += colons;
1416 goto do_z_conversion;
1417
1418 case L_('z'):
1419 colons = 0;
1420
1421 do_z_conversion:
1422 if (tp->tm_isdst < 0)
1423 break;
1424
1425 {
1426 int diff;
1427 int hour_diff;
1428 int min_diff;
1429 int sec_diff;
1430 #if HAVE_TM_GMTOFF
1431 diff = tp->tm_gmtoff;
1432 #else
1433 if (!tz)
1434 diff = 0;
1435 else
1436 {
1437 struct tm gtm;
1438 struct tm ltm;
1439 time_t lt;
1440
1441
1442
1443 # ifndef my_strftime
1444 if (!*tzset_called)
1445 {
1446 tzset ();
1447 *tzset_called = true;
1448 }
1449 # endif
1450
1451 ltm = *tp;
1452 ltm.tm_wday = -1;
1453 lt = mktime_z (tz, <m);
1454 if (ltm.tm_wday < 0 || ! localtime_rz (0, <, >m))
1455 break;
1456 diff = tm_diff (<m, >m);
1457 }
1458 #endif
1459
1460 negative_number = diff < 0 || (diff == 0 && *zone == '-');
1461 hour_diff = diff / 60 / 60;
1462 min_diff = diff / 60 % 60;
1463 sec_diff = diff % 60;
1464
1465 switch (colons)
1466 {
1467 case 0:
1468 DO_TZ_OFFSET (5, 0, hour_diff * 100 + min_diff);
1469
1470 case 1: tz_hh_mm:
1471 DO_TZ_OFFSET (6, 04, hour_diff * 100 + min_diff);
1472
1473 case 2: tz_hh_mm_ss:
1474 DO_TZ_OFFSET (9, 024,
1475 hour_diff * 10000 + min_diff * 100 + sec_diff);
1476
1477 case 3:
1478 if (sec_diff != 0)
1479 goto tz_hh_mm_ss;
1480 if (min_diff != 0)
1481 goto tz_hh_mm;
1482 DO_TZ_OFFSET (3, 0, hour_diff);
1483
1484 default:
1485 goto bad_format;
1486 }
1487 }
1488
1489 case L_('\0'):
1490 bad_percent:
1491 --f;
1492 FALLTHROUGH;
1493 default:
1494
1495
1496
1497 bad_format:
1498 cpy (f - percent + 1, percent);
1499 break;
1500 }
1501 }
1502
1503 #if ! FPRINTFTIME
1504 if (p && maxsize != 0)
1505 *p = L_('\0');
1506 #endif
1507
1508 errno = saved_errno;
1509 return i;
1510 }