1 /* Copyright (C) 1991-2020 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
19 # define USE_IN_EXTENDED_LOCALE_MODEL 1
20 # define HAVE_STRUCT_ERA_ENTRY 1
21 # define HAVE_TM_GMTOFF 1
22 # define HAVE_TM_ZONE 1
23 # define HAVE_TZNAME 1
25 # include "../locale/localeinfo.h"
29 # include "fprintftime.h"
31 # include "strftime.h"
33 # include "time-internal.h"
39 #if HAVE_TZNAME && !HAVE_DECL_TZNAME
40 extern char *tzname
[];
43 /* Do multibyte processing if multibyte encodings are supported, unless
44 multibyte sequences are safe in formats. Multibyte sequences are
45 safe if they cannot contain byte sequences that look like format
46 conversion specifications. The multibyte encodings used by the
47 C library on the various platforms (UTF-8, GB2312, GBK, CP936,
48 GB18030, EUC-TW, BIG5, BIG5-HKSCS, CP950, EUC-JP, EUC-KR, CP949,
49 SHIFT_JIS, CP932, JOHAB) are safe for formats, because the byte '%'
50 cannot occur in a multibyte character except in the first byte.
52 The DEC-HANYU encoding used on OSF/1 is not safe for formats, but
53 this encoding has never been seen in real-life use, so we ignore
55 #if !(defined __osf__ && 0)
56 # define MULTIBYTE_IS_FORMAT_SAFE 1
58 #define DO_MULTIBYTE (! MULTIBYTE_IS_FORMAT_SAFE)
62 static const mbstate_t mbstate_zero
;
71 #include "attribute.h"
76 # define CHAR_T wchar_t
77 # define UCHAR_T unsigned int
78 # define L_(Str) L##Str
79 # define NLW(Sym) _NL_W##Sym
81 # define MEMCPY(d, s, n) __wmemcpy (d, s, n)
82 # define STRLEN(s) __wcslen (s)
86 # define UCHAR_T unsigned char
89 # define ABALTMON_1 _NL_ABALTMON_1
91 # define MEMCPY(d, s, n) memcpy (d, s, n)
92 # define STRLEN(s) strlen (s)
96 /* Shift A right by B bits portably, by dividing A by 2**B and
97 truncating towards minus infinity. A and B should be free of side
98 effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
99 INT_BITS is the number of useful bits in an int. GNU code can
100 assume that INT_BITS is at least 32.
102 ISO C99 says that A >> B is implementation-defined if A < 0. Some
103 implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
104 right in the usual way when A < 0, so SHR falls back on division if
105 ordinary A >> B doesn't seem to be the usual signed shift. */
109 : ((a) + ((a) < 0)) / (1 << (b)) - ((a) < 0))
111 #define TM_YEAR_BASE 1900
114 /* Nonzero if YEAR is a leap year (every 4 years,
115 except every 100th isn't, and every 400th is). */
116 # define __isleap(year) \
117 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
122 # define mktime_z(tz, tm) mktime (tm)
123 # define tzname __tzname
124 # define tzset __tzset
128 # define FPRINTFTIME 0
132 # define STREAM_OR_CHAR_T FILE
133 # define STRFTIME_ARG(x) /* empty */
135 # define STREAM_OR_CHAR_T CHAR_T
136 # define STRFTIME_ARG(x) x,
140 # define memset_byte(P, Len, Byte) \
141 do { size_t _i; for (_i = 0; _i < Len; _i++) fputc (Byte, P); } while (0)
142 # define memset_space(P, Len) memset_byte (P, Len, ' ')
143 # define memset_zero(P, Len) memset_byte (P, Len, '0')
144 #elif defined COMPILE_WIDE
145 # define memset_space(P, Len) (wmemset (P, L' ', Len), (P) += (Len))
146 # define memset_zero(P, Len) (wmemset (P, L'0', Len), (P) += (Len))
148 # define memset_space(P, Len) (memset (P, ' ', Len), (P) += (Len))
149 # define memset_zero(P, Len) (memset (P, '0', Len), (P) += (Len))
153 # define advance(P, N)
155 # define advance(P, N) ((P) += (N))
158 #define add(n, f) width_add (width, n, f)
159 #define width_add(width, n, f) \
163 size_t _w = pad == L_('-') || width < 0 ? 0 : width; \
164 size_t _incr = _n < _w ? _w : _n; \
165 if (_incr >= maxsize - i) \
171 size_t _delta = _w - _n; \
172 if (pad == L_('0') || pad == L_('+')) \
173 memset_zero (p, _delta); \
175 memset_space (p, _delta); \
183 #define add1(c) width_add1 (width, c)
185 # define width_add1(width, c) width_add (width, 1, fputc (c, p))
187 # define width_add1(width, c) width_add (width, 1, *p = c)
190 #define cpy(n, s) width_cpy (width, n, s)
192 # define width_cpy(width, n, s) \
193 width_add (width, n, \
197 fwrite_lowcase (p, (s), _n); \
198 else if (to_uppcase) \
199 fwrite_uppcase (p, (s), _n); \
202 /* Ignore the value of fwrite. The caller can determine whether \
203 an error occurred by inspecting ferror (P). All known fwrite \
204 implementations set the stream's error indicator when they \
205 fail due to ENOMEM etc., even though C11 and POSIX.1-2008 do \
206 not require this. */ \
207 fwrite (s, _n, 1, p); \
213 # define width_cpy(width, n, s) \
214 width_add (width, n, \
216 memcpy_lowcase (p, (s), _n LOCALE_ARG); \
217 else if (to_uppcase) \
218 memcpy_uppcase (p, (s), _n LOCALE_ARG); \
220 MEMCPY ((void *) p, (void const *) (s), _n))
224 # ifndef USE_IN_EXTENDED_LOCALE_MODEL
225 # undef __mbsrtowcs_l
226 # define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
228 # define widen(os, ws, l) \
231 const char *__s = os; \
232 memset (&__st, '\0', sizeof (__st)); \
233 l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc); \
234 ws = (wchar_t *) alloca ((l + 1) * sizeof (wchar_t)); \
235 (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc); \
240 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
241 /* We use this code also for the extended locale handling where the
242 function gets as an additional argument the locale which has to be
243 used. To access the values we have to redefine the _NL_CURRENT
245 # define strftime __strftime_l
246 # define wcsftime __wcsftime_l
248 # define _NL_CURRENT(category, item) \
249 (current->values[_NL_ITEM_INDEX (item)].string)
250 # define LOCALE_PARAM , locale_t loc
251 # define LOCALE_ARG , loc
252 # define HELPER_LOCALE_ARG , current
254 # define LOCALE_PARAM
257 # define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
259 # define HELPER_LOCALE_ARG
264 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
265 # define TOUPPER(Ch, L) __towupper_l (Ch, L)
266 # define TOLOWER(Ch, L) __towlower_l (Ch, L)
268 # define TOUPPER(Ch, L) towupper (Ch)
269 # define TOLOWER(Ch, L) towlower (Ch)
272 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
273 # define TOUPPER(Ch, L) __toupper_l (Ch, L)
274 # define TOLOWER(Ch, L) __tolower_l (Ch, L)
276 # define TOUPPER(Ch, L) toupper (Ch)
277 # define TOLOWER(Ch, L) tolower (Ch)
280 /* We don't use 'isdigit' here since the locale dependent
281 interpretation is not what we want here. We only need to accept
282 the arabic digits in the ASCII range. One day there is perhaps a
283 more reliable way to accept other sets of digits. */
284 #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
288 fwrite_lowcase (FILE *fp
, const CHAR_T
*src
, size_t len
)
292 fputc (TOLOWER ((UCHAR_T
) *src
, loc
), fp
);
298 fwrite_uppcase (FILE *fp
, const CHAR_T
*src
, size_t len
)
302 fputc (TOUPPER ((UCHAR_T
) *src
, loc
), fp
);
307 static CHAR_T
*memcpy_lowcase (CHAR_T
*dest
, const CHAR_T
*src
,
308 size_t len LOCALE_PARAM
);
311 memcpy_lowcase (CHAR_T
*dest
, const CHAR_T
*src
, size_t len LOCALE_PARAM
)
314 dest
[len
] = TOLOWER ((UCHAR_T
) src
[len
], loc
);
318 static CHAR_T
*memcpy_uppcase (CHAR_T
*dest
, const CHAR_T
*src
,
319 size_t len LOCALE_PARAM
);
322 memcpy_uppcase (CHAR_T
*dest
, const CHAR_T
*src
, size_t len LOCALE_PARAM
)
325 dest
[len
] = TOUPPER ((UCHAR_T
) src
[len
], loc
);
332 /* Yield the difference between *A and *B,
333 measured in seconds, ignoring leap seconds. */
334 # define tm_diff ftime_tm_diff
335 static int tm_diff (const struct tm
*, const struct tm
*);
337 tm_diff (const struct tm
*a
, const struct tm
*b
)
339 /* Compute intervening leap days correctly even if year is negative.
340 Take care to avoid int overflow in leap day calculations,
341 but it's OK to assume that A and B are close to each other. */
342 int a4
= SHR (a
->tm_year
, 2) + SHR (TM_YEAR_BASE
, 2) - ! (a
->tm_year
& 3);
343 int b4
= SHR (b
->tm_year
, 2) + SHR (TM_YEAR_BASE
, 2) - ! (b
->tm_year
& 3);
344 int a100
= (a4
+ (a4
< 0)) / 25 - (a4
< 0);
345 int b100
= (b4
+ (b4
< 0)) / 25 - (b4
< 0);
346 int a400
= SHR (a100
, 2);
347 int b400
= SHR (b100
, 2);
348 int intervening_leap_days
= (a4
- b4
) - (a100
- b100
) + (a400
- b400
);
349 int years
= a
->tm_year
- b
->tm_year
;
350 int days
= (365 * years
+ intervening_leap_days
351 + (a
->tm_yday
- b
->tm_yday
));
352 return (60 * (60 * (24 * days
+ (a
->tm_hour
- b
->tm_hour
))
353 + (a
->tm_min
- b
->tm_min
))
354 + (a
->tm_sec
- b
->tm_sec
));
356 #endif /* ! HAVE_TM_GMTOFF */
360 /* The number of days from the first day of the first ISO week of this
361 year to the year day YDAY with week day WDAY. ISO weeks start on
362 Monday; the first ISO week has the year's first Thursday. YDAY may
363 be as small as YDAY_MINIMUM. */
364 #define ISO_WEEK_START_WDAY 1 /* Monday */
365 #define ISO_WEEK1_WDAY 4 /* Thursday */
366 #define YDAY_MINIMUM (-366)
367 static int iso_week_days (int, int);
372 iso_week_days (int yday
, int wday
)
374 /* Add enough to the first operand of % to make it nonnegative. */
375 int big_enough_multiple_of_7
= (-YDAY_MINIMUM
/ 7 + 2) * 7;
377 - (yday
- wday
+ ISO_WEEK1_WDAY
+ big_enough_multiple_of_7
) % 7
378 + ISO_WEEK1_WDAY
- ISO_WEEK_START_WDAY
);
382 /* When compiling this file, GNU applications can #define my_strftime
383 to a symbol (typically nstrftime) to get an extended strftime with
384 extra arguments TZ and NS. */
388 # define my_strftime fprintftime
393 # define extra_args , tz, ns
394 # define extra_args_spec , timezone_t tz, int ns
396 # if defined COMPILE_WIDE
397 # define my_strftime wcsftime
398 # define nl_get_alt_digit _nl_get_walt_digit
400 # define my_strftime strftime
401 # define nl_get_alt_digit _nl_get_alt_digit
404 # define extra_args_spec
405 /* We don't have this information in general. */
410 static size_t __strftime_internal (STREAM_OR_CHAR_T
*, STRFTIME_ARG (size_t)
411 const CHAR_T
*, const struct tm
*,
412 bool, int, int, bool *
413 extra_args_spec LOCALE_PARAM
);
415 /* Write information from TP into S according to the format
416 string FORMAT, writing no more that MAXSIZE characters
417 (including the terminating '\0') and returning number of
418 characters written. If S is NULL, nothing will be written
419 anywhere, so to determine how many characters would be
420 written, use NULL for S and (size_t) -1 for MAXSIZE. */
422 my_strftime (STREAM_OR_CHAR_T
*s
, STRFTIME_ARG (size_t maxsize
)
423 const CHAR_T
*format
,
424 const struct tm
*tp extra_args_spec LOCALE_PARAM
)
426 bool tzset_called
= false;
427 return __strftime_internal (s
, STRFTIME_ARG (maxsize
) format
, tp
, false,
428 0, -1, &tzset_called extra_args LOCALE_ARG
);
430 #if defined _LIBC && ! FPRINTFTIME
431 libc_hidden_def (my_strftime
)
434 /* Just like my_strftime, above, but with more parameters.
435 UPCASE indicates that the result should be converted to upper case.
436 YR_SPEC and WIDTH specify the padding and width for the year.
437 *TZSET_CALLED indicates whether tzset has been called here. */
439 __strftime_internal (STREAM_OR_CHAR_T
*s
, STRFTIME_ARG (size_t maxsize
)
440 const CHAR_T
*format
,
441 const struct tm
*tp
, bool upcase
,
442 int yr_spec
, int width
, bool *tzset_called
443 extra_args_spec LOCALE_PARAM
)
445 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
446 struct __locale_data
*const current
= loc
->__locales
[LC_TIME
];
449 size_t maxsize
= (size_t) -1;
452 int hour12
= tp
->tm_hour
;
454 /* We cannot make the following values variables since we must delay
455 the evaluation of these values until really needed since some
456 expressions might not be valid in every situation. The 'struct tm'
457 might be generated by a strptime() call that initialized
458 only a few elements. Dereference the pointers only if the format
459 requires this. Then it is ok to fail if the pointers are invalid. */
461 ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6 \
462 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday)))
464 ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6 \
465 ? "?" : _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday)))
467 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
468 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon)))
470 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
471 ? "?" : _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon)))
472 # define a_altmonth \
473 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
474 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABALTMON_1) + tp->tm_mon)))
475 # define f_altmonth \
476 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
477 ? "?" : _NL_CURRENT (LC_TIME, NLW(ALTMON_1) + tp->tm_mon)))
479 ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
480 ? NLW(PM_STR) : NLW(AM_STR)))
482 # define aw_len STRLEN (a_wkday)
483 # define am_len STRLEN (a_month)
484 # define aam_len STRLEN (a_altmonth)
485 # define ap_len STRLEN (ampm)
488 char **tzname_vec
= tzname
;
492 STREAM_OR_CHAR_T
*p
= s
;
494 #if DO_MULTIBYTE && !defined COMPILE_WIDE
495 const char *format_end
= NULL
;
500 /* The POSIX test suite assumes that setting
501 the environment variable TZ to a new value before calling strftime()
502 will influence the result (the %Z format) even if the information in
503 TP is computed with a totally different time zone.
504 This is bogus: though POSIX allows bad behavior like this,
505 POSIX does not require it. Do the right thing instead. */
506 zone
= (const char *) tp
->tm_zone
;
511 if (! (zone
&& *zone
))
517 /* Infer the zone name from *TZ instead of from TZNAME. */
518 tzname_vec
= tz
->tzname_copy
;
521 /* The tzset() call might have changed the value. */
522 if (!(zone
&& *zone
) && tp
->tm_isdst
>= 0)
524 /* POSIX.1 requires that local time zone information be used as
525 though strftime called tzset. */
530 *tzset_called
= true;
533 zone
= tzname_vec
[tp
->tm_isdst
!= 0];
545 for (f
= format
; *f
!= '\0'; width
= -1, f
++)
547 int pad
= 0; /* Padding for number ('_', '-', '+', '0', or 0). */
548 int modifier
; /* Field modifier ('E', 'O', or 0). */
549 int digits
= 0; /* Max digits for numeric format. */
550 int number_value
; /* Numeric value to be printed. */
551 unsigned int u_number_value
; /* (unsigned int) number_value. */
552 bool negative_number
; /* The number is negative. */
553 bool always_output_a_sign
; /* +/- should always be output. */
554 int tz_colon_mask
; /* Bitmask of where ':' should appear. */
555 const CHAR_T
*subfmt
;
558 + 2 /* for the two colons in a %::z or %:::z time zone */
559 + (sizeof (int) < sizeof (time_t)
560 ? INT_STRLEN_BOUND (time_t)
561 : INT_STRLEN_BOUND (int))];
562 bool to_lowcase
= false;
563 bool to_uppcase
= upcase
;
565 bool change_case
= false;
569 #if DO_MULTIBYTE && !defined COMPILE_WIDE
575 case L_('\b'): case L_('\t'): case L_('\n'):
576 case L_('\v'): case L_('\f'): case L_('\r'):
577 case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
578 case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
579 case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
580 case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
581 case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
582 case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
583 case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
584 case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
585 case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
586 case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
587 case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
588 case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
589 case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
590 case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
591 case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
592 case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
593 case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
594 case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
596 /* The C Standard requires these 98 characters (plus '%') to
597 be in the basic execution character set. None of these
598 characters can start a multibyte sequence, so they need
599 not be analyzed further. */
604 /* Copy this multibyte sequence until we reach its end, find
605 an error, or come back to the initial shift state. */
607 mbstate_t mbstate
= mbstate_zero
;
612 format_end
= f
+ strlen (f
) + 1;
613 fsize
= format_end
- f
;
617 size_t bytes
= mbrlen (f
+ len
, fsize
- len
, &mbstate
);
622 if (bytes
== (size_t) -2)
624 len
+= strlen (f
+ len
);
628 if (bytes
== (size_t) -1)
636 while (! mbsinit (&mbstate
));
644 #else /* ! DO_MULTIBYTE */
646 /* Either multibyte encodings are not supported, they are
647 safe for formats, so any non-'%' byte can be copied through,
648 or this is the wide character version. */
655 #endif /* ! DO_MULTIBYTE */
657 /* Check for flags that can modify a format. */
662 /* This influences the number formats. */
670 /* This changes textual output. */
689 if (INT_MULTIPLY_WRAPV (width
, 10, &width
)
690 || INT_ADD_WRAPV (width
, *f
- L_('0'), &width
))
694 while (ISDIGIT (*f
));
697 /* Check for modifiers. */
710 /* Now do the specified format. */
714 #define DO_NUMBER(d, v) \
722 #define DO_SIGNED_NUMBER(d, negative, v) \
723 DO_MAYBE_SIGNED_NUMBER (d, negative, v, do_signed_number)
724 #define DO_YEARISH(d, negative, v) \
725 DO_MAYBE_SIGNED_NUMBER (d, negative, v, do_yearish)
726 #define DO_MAYBE_SIGNED_NUMBER(d, negative, v, label) \
730 negative_number = negative; \
731 u_number_value = v; \
736 /* The mask is not what you might think.
737 When the ordinal i'th bit is set, insert a colon
738 before the i'th digit of the time zone representation. */
739 #define DO_TZ_OFFSET(d, mask, v) \
743 tz_colon_mask = mask; \
744 u_number_value = v; \
748 #define DO_NUMBER_SPACEPAD(d, v) \
753 goto do_number_spacepad; \
772 cpy (aw_len
, a_wkday
);
775 goto underlying_strftime
;
787 cpy (STRLEN (f_wkday
), f_wkday
);
790 goto underlying_strftime
;
800 if (modifier
== L_('E'))
803 if (modifier
== L_('O'))
804 cpy (aam_len
, a_altmonth
);
806 cpy (am_len
, a_month
);
809 goto underlying_strftime
;
813 if (modifier
== L_('E'))
821 if (modifier
== L_('O'))
822 cpy (STRLEN (f_altmonth
), f_altmonth
);
824 cpy (STRLEN (f_month
), f_month
);
827 goto underlying_strftime
;
831 if (modifier
== L_('O'))
834 if (! (modifier
== L_('E')
836 (const CHAR_T
*) _NL_CURRENT (LC_TIME
,
839 subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(D_T_FMT
));
841 goto underlying_strftime
;
848 size_t len
= __strftime_internal (NULL
, STRFTIME_ARG ((size_t) -1)
849 subfmt
, tp
, to_uppcase
,
850 pad
, subwidth
, tzset_called
851 extra_args LOCALE_ARG
);
852 add (len
, __strftime_internal (p
,
853 STRFTIME_ARG (maxsize
- i
)
854 subfmt
, tp
, to_uppcase
,
855 pad
, subwidth
, tzset_called
856 extra_args LOCALE_ARG
));
860 #if !(defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
863 /* The relevant information is available only via the
864 underlying strftime implementation, so use that. */
867 char ubuf
[1024]; /* enough for any single format in practice */
869 /* Make sure we're calling the actual underlying strftime.
870 In some cases, config.h contains something like
871 "#define strftime rpl_strftime". */
877 /* The space helps distinguish strftime failure from empty
885 len
= strftime (ubuf
, sizeof ubuf
, ufmt
, tp
);
887 cpy (len
- 1, ubuf
+ 1);
893 if (modifier
== L_('E'))
895 #if HAVE_STRUCT_ERA_ENTRY
896 struct era_entry
*era
= _nl_get_era_entry (tp HELPER_LOCALE_ARG
);
900 size_t len
= __wcslen (era
->era_wname
);
901 cpy (len
, era
->era_wname
);
903 size_t len
= strlen (era
->era_name
);
904 cpy (len
, era
->era_name
);
909 goto underlying_strftime
;
914 bool negative_year
= tp
->tm_year
< - TM_YEAR_BASE
;
915 bool zero_thru_1899
= !negative_year
& (tp
->tm_year
< 0);
916 int century
= ((tp
->tm_year
- 99 * zero_thru_1899
) / 100
917 + TM_YEAR_BASE
/ 100);
918 DO_YEARISH (2, negative_year
, century
);
922 if (modifier
== L_('O'))
925 if (! (modifier
== L_('E')
927 (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(ERA_D_FMT
)))
929 subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(D_FMT
));
932 goto underlying_strftime
;
937 subfmt
= L_("%m/%d/%y");
941 if (modifier
== L_('E'))
944 DO_NUMBER (2, tp
->tm_mday
);
947 if (modifier
== L_('E'))
950 DO_NUMBER_SPACEPAD (2, tp
->tm_mday
);
952 /* All numeric formats set DIGITS and NUMBER_VALUE (or U_NUMBER_VALUE)
953 and then jump to one of these labels. */
956 always_output_a_sign
= true;
964 && ((digits
== 2 ? 99 : 9999) < u_number_value
966 goto do_maybe_signed_number
;
973 /* Format NUMBER_VALUE according to the MODIFIER flag. */
974 negative_number
= number_value
< 0;
975 u_number_value
= number_value
;
978 always_output_a_sign
= false;
980 do_maybe_signed_number
:
984 /* Format U_NUMBER_VALUE according to the MODIFIER flag.
985 NEGATIVE_NUMBER is nonzero if the original number was
986 negative; in this case it was converted directly to
987 unsigned int (i.e., modulo (UINT_MAX + 1)) without
989 if (modifier
== L_('O') && !negative_number
)
992 /* Get the locale specific alternate representation of
993 the number. If none exist NULL is returned. */
994 const CHAR_T
*cp
= nl_get_alt_digit (u_number_value
999 size_t digitlen
= STRLEN (cp
);
1007 goto underlying_strftime
;
1011 bufp
= buf
+ sizeof (buf
) / sizeof (buf
[0]);
1013 if (negative_number
)
1014 u_number_value
= - u_number_value
;
1018 if (tz_colon_mask
& 1)
1020 tz_colon_mask
>>= 1;
1021 *--bufp
= u_number_value
% 10 + L_('0');
1022 u_number_value
/= 10;
1024 while (u_number_value
!= 0 || tz_colon_mask
!= 0);
1026 do_number_sign_and_padding
:
1033 CHAR_T sign_char
= (negative_number
? L_('-')
1034 : always_output_a_sign
? L_('+')
1036 int numlen
= buf
+ sizeof buf
/ sizeof buf
[0] - bufp
;
1037 int shortage
= width
- !!sign_char
- numlen
;
1038 int padding
= pad
== L_('-') || shortage
<= 0 ? 0 : shortage
;
1045 memset_space (p
, padding
);
1049 width_add1 (0, sign_char
);
1060 if (pad
== 0 && width
< 0)
1067 subwidth
= width
- 6;
1071 subfmt
= L_("%Y-%m-%d");
1072 goto subformat_width
;
1075 if (modifier
== L_('E'))
1078 DO_NUMBER (2, tp
->tm_hour
);
1081 if (modifier
== L_('E'))
1084 DO_NUMBER (2, hour12
);
1086 case L_('k'): /* GNU extension. */
1087 if (modifier
== L_('E'))
1090 DO_NUMBER_SPACEPAD (2, tp
->tm_hour
);
1092 case L_('l'): /* GNU extension. */
1093 if (modifier
== L_('E'))
1096 DO_NUMBER_SPACEPAD (2, hour12
);
1099 if (modifier
== L_('E'))
1102 DO_SIGNED_NUMBER (3, tp
->tm_yday
< -1, tp
->tm_yday
+ 1U);
1105 if (modifier
== L_('E'))
1108 DO_NUMBER (2, tp
->tm_min
);
1111 if (modifier
== L_('E'))
1114 DO_SIGNED_NUMBER (2, tp
->tm_mon
< -1, tp
->tm_mon
+ 1U);
1117 case L_('N'): /* GNU extension. */
1118 if (modifier
== L_('E'))
1121 int n
= ns
, ns_digits
= 9;
1124 int ndigs
= ns_digits
;
1125 while (width
< ndigs
|| (1 < ndigs
&& n
% 10 == 0))
1127 for (int j
= ndigs
; 0 < j
; j
--)
1128 buf
[j
- 1] = n
% 10 + L_('0'), n
/= 10;
1131 width_cpy (0, ndigs
, buf
);
1132 width_add (width
- ndigs
, 0, (void) 0);
1144 format_char
= L_('p');
1157 goto underlying_strftime
;
1160 case L_('q'): /* GNU extension. */
1161 DO_SIGNED_NUMBER (1, false, ((tp
->tm_mon
* 11) >> 5) + 1);
1165 subfmt
= L_("%H:%M");
1170 if (*(subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
,
1173 subfmt
= L_("%I:%M:%S %p");
1176 goto underlying_strftime
;
1180 if (modifier
== L_('E'))
1183 DO_NUMBER (2, tp
->tm_sec
);
1185 case L_('s'): /* GNU extension. */
1191 t
= mktime_z (tz
, <m
);
1193 /* Generate string value for T using time_t arithmetic;
1194 this works even if sizeof (long) < sizeof (time_t). */
1196 bufp
= buf
+ sizeof (buf
) / sizeof (buf
[0]);
1197 negative_number
= t
< 0;
1203 *--bufp
= (negative_number
? -d
: d
) + L_('0');
1208 always_output_a_sign
= false;
1209 goto do_number_sign_and_padding
;
1213 if (modifier
== L_('O'))
1216 if (! (modifier
== L_('E')
1218 (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(ERA_T_FMT
)))
1220 subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(T_FMT
));
1223 goto underlying_strftime
;
1226 subfmt
= L_("%H:%M:%S");
1234 DO_NUMBER (1, (tp
->tm_wday
- 1 + 7) % 7 + 1);
1237 if (modifier
== L_('E'))
1240 DO_NUMBER (2, (tp
->tm_yday
- tp
->tm_wday
+ 7) / 7);
1245 if (modifier
== L_('E'))
1248 /* YEAR is a leap year if and only if (tp->tm_year + TM_YEAR_BASE)
1249 is a leap year, except that YEAR and YEAR - 1 both work
1250 correctly even when (tp->tm_year + TM_YEAR_BASE) would
1252 int year
= (tp
->tm_year
1254 ? TM_YEAR_BASE
% 400
1255 : TM_YEAR_BASE
% 400 - 400));
1256 int year_adjust
= 0;
1257 int days
= iso_week_days (tp
->tm_yday
, tp
->tm_wday
);
1261 /* This ISO week belongs to the previous year. */
1263 days
= iso_week_days (tp
->tm_yday
+ (365 + __isleap (year
- 1)),
1268 int d
= iso_week_days (tp
->tm_yday
- (365 + __isleap (year
)),
1272 /* This ISO week belongs to the next year. */
1282 int yy
= (tp
->tm_year
% 100 + year_adjust
) % 100;
1283 DO_YEARISH (2, false,
1286 : tp
->tm_year
< -TM_YEAR_BASE
- year_adjust
1292 DO_YEARISH (4, tp
->tm_year
< -TM_YEAR_BASE
- year_adjust
,
1293 (tp
->tm_year
+ (unsigned int) TM_YEAR_BASE
1297 DO_NUMBER (2, days
/ 7 + 1);
1302 if (modifier
== L_('E'))
1305 DO_NUMBER (2, (tp
->tm_yday
- (tp
->tm_wday
- 1 + 7) % 7 + 7) / 7);
1308 if (modifier
== L_('E'))
1311 DO_NUMBER (1, tp
->tm_wday
);
1314 if (modifier
== L_('E'))
1316 #if HAVE_STRUCT_ERA_ENTRY
1317 struct era_entry
*era
= _nl_get_era_entry (tp HELPER_LOCALE_ARG
);
1320 # ifdef COMPILE_WIDE
1321 subfmt
= era
->era_wformat
;
1323 subfmt
= era
->era_format
;
1330 goto underlying_strftime
;
1333 if (modifier
== L_('O'))
1336 DO_YEARISH (4, tp
->tm_year
< -TM_YEAR_BASE
,
1337 tp
->tm_year
+ (unsigned int) TM_YEAR_BASE
);
1340 if (modifier
== L_('E'))
1342 #if HAVE_STRUCT_ERA_ENTRY
1343 struct era_entry
*era
= _nl_get_era_entry (tp HELPER_LOCALE_ARG
);
1346 int delta
= tp
->tm_year
- era
->start_date
[0];
1349 DO_NUMBER (2, (era
->offset
1350 + delta
* era
->absolute_direction
));
1353 goto underlying_strftime
;
1358 int yy
= tp
->tm_year
% 100;
1360 yy
= tp
->tm_year
< - TM_YEAR_BASE
? -yy
: yy
+ 100;
1361 DO_YEARISH (2, false, yy
);
1373 /* The zone string is always given in multibyte form. We have
1374 to transform it first. */
1377 widen (zone
, wczone
, len
);
1381 cpy (strlen (zone
), zone
);
1386 /* :, ::, and ::: are valid only just before 'z'.
1387 :::: etc. are rejected later. */
1388 for (colons
= 1; f
[colons
] == L_(':'); colons
++)
1390 if (f
[colons
] != L_('z'))
1393 goto do_z_conversion
;
1399 if (tp
->tm_isdst
< 0)
1408 diff
= tp
->tm_gmtoff
;
1418 /* POSIX.1 requires that local time zone information be used as
1419 though strftime called tzset. */
1424 *tzset_called
= true;
1430 lt
= mktime_z (tz
, <m
);
1431 if (ltm
.tm_wday
< 0 || ! localtime_rz (0, <
, >m
))
1433 diff
= tm_diff (<m
, >m
);
1437 negative_number
= diff
< 0 || (diff
== 0 && *zone
== '-');
1438 hour_diff
= diff
/ 60 / 60;
1439 min_diff
= diff
/ 60 % 60;
1440 sec_diff
= diff
% 60;
1445 DO_TZ_OFFSET (5, 0, hour_diff
* 100 + min_diff
);
1447 case 1: tz_hh_mm
: /* +hh:mm */
1448 DO_TZ_OFFSET (6, 04, hour_diff
* 100 + min_diff
);
1450 case 2: tz_hh_mm_ss
: /* +hh:mm:ss */
1451 DO_TZ_OFFSET (9, 024,
1452 hour_diff
* 10000 + min_diff
* 100 + sec_diff
);
1454 case 3: /* +hh if possible, else +hh:mm, else +hh:mm:ss */
1459 DO_TZ_OFFSET (3, 0, hour_diff
);
1466 case L_('\0'): /* GNU extension: % at end of format. */
1470 /* Unknown format; output the format, including the '%',
1471 since this is most likely the right thing to do if a
1472 multibyte string has been misparsed. */
1476 for (flen
= 1; f
[1 - flen
] != L_('%'); flen
++)
1478 cpy (flen
, &f
[1 - flen
]);
1485 if (p
&& maxsize
!= 0)