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