openat: don’t close (-1)
[gnulib.git] / lib / strftime.c
blob4ddbec04269e4abcc04d016d7f267a820a923336
1 /* Copyright (C) 1991-2024 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation, either version 3 of the
7 License, or (at your option) any later version.
9 This file 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
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 #ifndef FPRINTFTIME
18 # define FPRINTFTIME 0
19 #endif
21 #ifndef USE_C_LOCALE
22 # define USE_C_LOCALE 0
23 #endif
25 #ifdef _LIBC
26 # define USE_IN_EXTENDED_LOCALE_MODEL 1
27 # define HAVE_STRUCT_ERA_ENTRY 1
28 # define HAVE_STRUCT_TM_TM_GMTOFF 1
29 # define HAVE_STRUCT_TM_TM_ZONE 1
30 # include "../locale/localeinfo.h"
31 #else
32 # include <libc-config.h>
33 # if FPRINTFTIME
34 # include "fprintftime.h"
35 # else
36 # include "strftime.h"
37 # endif
38 # include "time-internal.h"
39 #endif
41 /* Whether to require GNU behavior for AM and PM indicators, even on
42 other platforms. This matters only in non-C locales.
43 The default is to require it; you can override this via
44 AC_DEFINE([REQUIRE_GNUISH_STRFTIME_AM_PM], 1) and if you do that
45 you may be able to omit Gnulib's localename module and its dependencies. */
46 #ifndef REQUIRE_GNUISH_STRFTIME_AM_PM
47 # define REQUIRE_GNUISH_STRFTIME_AM_PM true
48 #endif
49 #if USE_C_LOCALE
50 # undef REQUIRE_GNUISH_STRFTIME_AM_PM
51 # define REQUIRE_GNUISH_STRFTIME_AM_PM false
52 #endif
54 #if USE_C_LOCALE
55 # include "c-ctype.h"
56 #else
57 # include <ctype.h>
58 #endif
59 #include <errno.h>
60 #include <time.h>
62 /* Do multibyte processing if multibyte encodings are supported, unless
63 multibyte sequences are safe in formats. Multibyte sequences are
64 safe if they cannot contain byte sequences that look like format
65 conversion specifications. The multibyte encodings used by the
66 C library on the various platforms (UTF-8, GB2312, GBK, CP936,
67 GB18030, EUC-TW, BIG5, BIG5-HKSCS, CP950, EUC-JP, EUC-KR, CP949,
68 SHIFT_JIS, CP932, JOHAB) are safe for formats, because the byte '%'
69 cannot occur in a multibyte character except in the first byte.
71 The DEC-HANYU encoding used on OSF/1 is not safe for formats, but
72 this encoding has never been seen in real-life use, so we ignore
73 it. */
74 #if !(defined __osf__ && 0)
75 # define MULTIBYTE_IS_FORMAT_SAFE 1
76 #endif
77 #define DO_MULTIBYTE (! MULTIBYTE_IS_FORMAT_SAFE)
79 #if DO_MULTIBYTE
80 # include <wchar.h>
81 static const mbstate_t mbstate_zero;
82 #endif
84 #include <limits.h>
85 #include <locale.h>
86 #include <stdckdint.h>
87 #include <stddef.h>
88 #include <stdlib.h>
89 #include <string.h>
91 #if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM
92 # include "localename.h"
93 #elif defined _WIN32 && !defined __CYGWIN__
94 # include <wchar.h>
95 #endif
97 #include "attribute.h"
98 #include <intprops.h>
100 #ifdef COMPILE_WIDE
101 # include <endian.h>
102 # define CHAR_T wchar_t
103 # define UCHAR_T unsigned int
104 # define L_(Str) L##Str
105 # define NLW(Sym) _NL_W##Sym
107 # define MEMCPY(d, s, n) __wmemcpy (d, s, n)
108 # define STRLEN(s) __wcslen (s)
110 #else
111 # define CHAR_T char
112 # define UCHAR_T unsigned char
113 # define L_(Str) Str
114 # define NLW(Sym) Sym
115 # define ABALTMON_1 _NL_ABALTMON_1
117 # define MEMCPY(d, s, n) memcpy (d, s, n)
118 # define STRLEN(s) strlen (s)
120 #endif
122 /* Shift A right by B bits portably, by dividing A by 2**B and
123 truncating towards minus infinity. A and B should be free of side
124 effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
125 INT_BITS is the number of useful bits in an int. GNU code can
126 assume that INT_BITS is at least 32.
128 ISO C99 says that A >> B is implementation-defined if A < 0. Some
129 implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
130 right in the usual way when A < 0, so SHR falls back on division if
131 ordinary A >> B doesn't seem to be the usual signed shift. */
132 #define SHR(a, b) \
133 (-1 >> 1 == -1 \
134 ? (a) >> (b) \
135 : ((a) + ((a) < 0)) / (1 << (b)) - ((a) < 0))
137 enum pad_style
139 ZERO_PAD, /* (default) Pad with 0 unless format says otherwise. */
140 ALWAYS_ZERO_PAD, /* '0' Always pad with 0. */
141 SIGN_PAD, /* '+' Always output a sign. */
142 SPACE_PAD, /* '_' Pad with space. */
143 NO_PAD /* '-' Do not pad. */
146 #define TM_YEAR_BASE 1900
148 #ifndef __isleap
149 /* Nonzero if YEAR is a leap year (every 4 years,
150 except every 100th isn't, and every 400th is). */
151 # define __isleap(year) \
152 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
153 #endif
156 #ifdef _LIBC
157 # define mktime_z(tz, tm) mktime (tm)
158 # define tzname __tzname
159 # define tzset __tzset
161 # define time_t __time64_t
162 # define __gmtime_r(t, tp) __gmtime64_r (t, tp)
163 # define mktime(tp) __mktime64 (tp)
164 #endif
166 #if FPRINTFTIME
167 # define STREAM_OR_CHAR_T FILE
168 # define STRFTIME_ARG(x) /* empty */
169 #else
170 # define STREAM_OR_CHAR_T CHAR_T
171 # define STRFTIME_ARG(x) x,
172 #endif
174 #if FPRINTFTIME
175 # define memset_byte(P, Len, Byte) \
176 do { size_t _i; for (_i = 0; _i < Len; _i++) fputc (Byte, P); } while (0)
177 # define memset_space(P, Len) memset_byte (P, Len, ' ')
178 # define memset_zero(P, Len) memset_byte (P, Len, '0')
179 #elif defined COMPILE_WIDE
180 # define memset_space(P, Len) (wmemset (P, L' ', Len), (P) += (Len))
181 # define memset_zero(P, Len) (wmemset (P, L'0', Len), (P) += (Len))
182 #else
183 # define memset_space(P, Len) (memset (P, ' ', Len), (P) += (Len))
184 # define memset_zero(P, Len) (memset (P, '0', Len), (P) += (Len))
185 #endif
187 #if FPRINTFTIME
188 # define advance(P, N)
189 #else
190 # define advance(P, N) ((P) += (N))
191 #endif
193 #define add(n, f) width_add (width, n, f)
194 #define width_add(width, n, f) \
195 do \
197 size_t _n = (n); \
198 size_t _w = pad == NO_PAD || width < 0 ? 0 : width; \
199 size_t _incr = _n < _w ? _w : _n; \
200 if (_incr >= maxsize - i) \
202 errno = ERANGE; \
203 return 0; \
205 if (p) \
207 if (_n < _w) \
209 size_t _delta = _w - _n; \
210 if (pad == ALWAYS_ZERO_PAD || pad == SIGN_PAD) \
211 memset_zero (p, _delta); \
212 else \
213 memset_space (p, _delta); \
215 f; \
216 advance (p, _n); \
218 i += _incr; \
219 } while (0)
221 #define add1(c) width_add1 (width, c)
222 #if FPRINTFTIME
223 # define width_add1(width, c) width_add (width, 1, fputc (c, p))
224 #else
225 # define width_add1(width, c) width_add (width, 1, *p = c)
226 #endif
228 #define cpy(n, s) width_cpy (width, n, s)
229 #if FPRINTFTIME
230 # define width_cpy(width, n, s) \
231 width_add (width, n, \
232 do \
234 if (to_lowcase) \
235 fwrite_lowcase (p, (s), _n); \
236 else if (to_uppcase) \
237 fwrite_uppcase (p, (s), _n); \
238 else \
240 /* Ignore the value of fwrite. The caller can determine whether \
241 an error occurred by inspecting ferror (P). All known fwrite \
242 implementations set the stream's error indicator when they \
243 fail due to ENOMEM etc., even though C11 and POSIX.1-2008 do \
244 not require this. */ \
245 fwrite (s, _n, 1, p); \
248 while (0) \
250 #else
251 # define width_cpy(width, n, s) \
252 width_add (width, n, \
253 if (to_lowcase) \
254 memcpy_lowcase (p, (s), _n LOCALE_ARG); \
255 else if (to_uppcase) \
256 memcpy_uppcase (p, (s), _n LOCALE_ARG); \
257 else \
258 MEMCPY ((void *) p, (void const *) (s), _n))
259 #endif
261 #ifdef COMPILE_WIDE
262 # ifndef USE_IN_EXTENDED_LOCALE_MODEL
263 # undef __mbsrtowcs_l
264 # define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
265 # endif
266 #endif
269 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
270 /* We use this code also for the extended locale handling where the
271 function gets as an additional argument the locale which has to be
272 used. To access the values we have to redefine the _NL_CURRENT
273 macro. */
274 # define strftime __strftime_l
275 # define wcsftime __wcsftime_l
276 # undef _NL_CURRENT
277 # define _NL_CURRENT(category, item) \
278 (current->values[_NL_ITEM_INDEX (item)].string)
279 # define LOCALE_PARAM , locale_t loc
280 # define LOCALE_ARG , loc
281 # define HELPER_LOCALE_ARG , current
282 #else
283 # define LOCALE_PARAM
284 # define LOCALE_ARG
285 # ifdef _LIBC
286 # define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
287 # else
288 # define HELPER_LOCALE_ARG
289 # endif
290 #endif
292 #ifdef COMPILE_WIDE
293 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
294 # define TOUPPER(Ch, L) __towupper_l (Ch, L)
295 # define TOLOWER(Ch, L) __towlower_l (Ch, L)
296 # else
297 # define TOUPPER(Ch, L) towupper (Ch)
298 # define TOLOWER(Ch, L) towlower (Ch)
299 # endif
300 #else
301 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
302 # define TOUPPER(Ch, L) __toupper_l (Ch, L)
303 # define TOLOWER(Ch, L) __tolower_l (Ch, L)
304 # else
305 # if USE_C_LOCALE
306 # define TOUPPER(Ch, L) c_toupper (Ch)
307 # define TOLOWER(Ch, L) c_tolower (Ch)
308 # else
309 # define TOUPPER(Ch, L) toupper (Ch)
310 # define TOLOWER(Ch, L) tolower (Ch)
311 # endif
312 # endif
313 #endif
314 /* We don't use 'isdigit' here since the locale dependent
315 interpretation is not what we want here. We only need to accept
316 the arabic digits in the ASCII range. One day there is perhaps a
317 more reliable way to accept other sets of digits. */
318 #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
320 /* Avoid false GCC warning "'memset' specified size 18446744073709551615 exceeds
321 maximum object size 9223372036854775807", caused by insufficient data flow
322 analysis and value propagation of the 'width_add' expansion when GCC is not
323 optimizing. Cf. <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88443>. */
324 #if _GL_GNUC_PREREQ (7, 0) && !__OPTIMIZE__
325 # pragma GCC diagnostic ignored "-Wstringop-overflow"
326 #endif
328 #if FPRINTFTIME
329 static void
330 fwrite_lowcase (FILE *fp, const CHAR_T *src, size_t len)
332 while (len-- > 0)
334 fputc (TOLOWER ((UCHAR_T) *src, loc), fp);
335 ++src;
339 static void
340 fwrite_uppcase (FILE *fp, const CHAR_T *src, size_t len)
342 while (len-- > 0)
344 fputc (TOUPPER ((UCHAR_T) *src, loc), fp);
345 ++src;
348 #else
349 static CHAR_T *memcpy_lowcase (CHAR_T *dest, const CHAR_T *src,
350 size_t len LOCALE_PARAM);
352 static CHAR_T *
353 memcpy_lowcase (CHAR_T *dest, const CHAR_T *src, size_t len LOCALE_PARAM)
355 while (len-- > 0)
356 dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
357 return dest;
360 static CHAR_T *memcpy_uppcase (CHAR_T *dest, const CHAR_T *src,
361 size_t len LOCALE_PARAM);
363 static CHAR_T *
364 memcpy_uppcase (CHAR_T *dest, const CHAR_T *src, size_t len LOCALE_PARAM)
366 while (len-- > 0)
367 dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
368 return dest;
370 #endif
373 /* Note: We assume that HAVE_STRFTIME_LZ implies HAVE_STRFTIME_L.
374 Otherwise, we would have to write (HAVE_STRFTIME_L || HAVE_STRFTIME_LZ)
375 instead of HAVE_STRFTIME_L everywhere. */
377 /* Define to 1 if we can use the system's native functions that takes a
378 timezone_t argument. As of 2024, this is only true on NetBSD. */
379 #define HAVE_NATIVE_TIME_Z \
380 (USE_C_LOCALE && HAVE_STRFTIME_L ? HAVE_STRFTIME_LZ : HAVE_STRFTIME_Z)
382 #if USE_C_LOCALE && HAVE_STRFTIME_L
384 /* Cache for the C locale object.
385 Marked volatile so that different threads see the same value
386 (avoids locking). */
387 static volatile locale_t c_locale_cache;
389 /* Return the C locale object, or (locale_t) 0 with errno set
390 if it cannot be created. */
391 static locale_t
392 c_locale (void)
394 if (!c_locale_cache)
395 c_locale_cache = newlocale (LC_ALL_MASK, "C", (locale_t) 0);
396 return c_locale_cache;
399 #endif
401 #if HAVE_NATIVE_TIME_Z
403 /* On NetBSD a null tz has undefined behavior, so use a non-null tz.
404 Cache the UTC time zone object in a volatile variable for improved
405 thread safety. This is good enough in practice, although in theory
406 stdatomic.h should be used. */
407 static volatile timezone_t utc_timezone_cache;
409 /* Return the UTC time zone object, or (timezone_t) 0 with errno set
410 if it cannot be created. */
411 static timezone_t
412 utc_timezone (void)
414 timezone_t tz = utc_timezone_cache;
415 if (!tz)
416 utc_timezone_cache = tz = tzalloc ("UTC0");
417 return tz;
420 #endif
423 #if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM
425 /* Return true if an AM/PM indicator should be removed. */
426 static bool
427 should_remove_ampm (void)
429 /* According to glibc's 'am_pm' attribute in the locale database, an AM/PM
430 indicator should be absent in the locales for the following languages:
431 ab an ast az be ber bg br bs ce cs csb cv da de dsb eo et eu fa fi fo fr
432 fur fy ga gl gv hr hsb ht hu hy it ka kk kl ku kv kw ky lb lg li lij ln
433 lt lv mg mhr mi mk mn ms mt nb nds nhn nl nn nr nso oc os pap pl pt ro
434 ru rw sah sc se sgs sk sl sm sr ss st su sv szl tg tk tn ts tt ug uk unm
435 uz ve wae wo xh zu */
436 const char *loc = gl_locale_name_unsafe (LC_TIME, "LC_TIME");
437 bool remove_ampm = false;
438 switch (loc[0])
440 case 'a':
441 switch (loc[1])
443 case 'b': case 'n': case 'z':
444 if (loc[2] == '\0' || loc[2] == '_')
445 remove_ampm = true;
446 break;
447 case 's':
448 if (loc[2] == 't' && (loc[3] == '\0' || loc[3] == '_'))
449 remove_ampm = true;
450 break;
451 default:
452 break;
454 break;
455 case 'b':
456 switch (loc[1])
458 case 'e':
459 if (loc[2] == '\0' || loc[2] == '_'
460 || (loc[2] == 'r' && (loc[3] == '\0' || loc[3] == '_')))
461 remove_ampm = true;
462 break;
463 case 'g': case 'r': case 's':
464 if (loc[2] == '\0' || loc[2] == '_')
465 remove_ampm = true;
466 break;
467 default:
468 break;
470 break;
471 case 'c':
472 switch (loc[1])
474 case 'e': case 'v':
475 if (loc[2] == '\0' || loc[2] == '_')
476 remove_ampm = true;
477 break;
478 case 's':
479 if (loc[2] == '\0' || loc[2] == '_'
480 || (loc[2] == 'b' && (loc[3] == '\0' || loc[3] == '_')))
481 remove_ampm = true;
482 break;
483 default:
484 break;
486 break;
487 case 'd':
488 switch (loc[1])
490 case 'a': case 'e':
491 if (loc[2] == '\0' || loc[2] == '_')
492 remove_ampm = true;
493 break;
494 case 's':
495 if (loc[2] == 'b' && (loc[3] == '\0' || loc[3] == '_'))
496 remove_ampm = true;
497 break;
498 default:
499 break;
501 break;
502 case 'e':
503 switch (loc[1])
505 case 'o': case 't': case 'u':
506 if (loc[2] == '\0' || loc[2] == '_')
507 remove_ampm = true;
508 break;
509 default:
510 break;
512 break;
513 case 'f':
514 switch (loc[1])
516 case 'a': case 'i': case 'o': case 'r': case 'y':
517 if (loc[2] == '\0' || loc[2] == '_')
518 remove_ampm = true;
519 break;
520 case 'u':
521 if (loc[2] == 'r' && (loc[3] == '\0' || loc[3] == '_'))
522 remove_ampm = true;
523 break;
524 default:
525 break;
527 break;
528 case 'g':
529 switch (loc[1])
531 case 'a': case 'l': case 'v':
532 if (loc[2] == '\0' || loc[2] == '_')
533 remove_ampm = true;
534 break;
535 default:
536 break;
538 break;
539 case 'h':
540 switch (loc[1])
542 case 'r': case 't': case 'u': case 'y':
543 if (loc[2] == '\0' || loc[2] == '_')
544 remove_ampm = true;
545 break;
546 case 's':
547 if (loc[2] == 'b' && (loc[3] == '\0' || loc[3] == '_'))
548 remove_ampm = true;
549 break;
550 default:
551 break;
553 break;
554 case 'i':
555 switch (loc[1])
557 case 't':
558 if (loc[2] == '\0' || loc[2] == '_')
559 remove_ampm = true;
560 break;
561 default:
562 break;
564 break;
565 case 'k':
566 switch (loc[1])
568 case 'a': case 'k': case 'l': case 'u': case 'v': case 'w': case 'y':
569 if (loc[2] == '\0' || loc[2] == '_')
570 remove_ampm = true;
571 break;
572 default:
573 break;
575 break;
576 case 'l':
577 switch (loc[1])
579 case 'b': case 'g': case 'n': case 't': case 'v':
580 if (loc[2] == '\0' || loc[2] == '_')
581 remove_ampm = true;
582 break;
583 case 'i':
584 if (loc[2] == 'j' && (loc[3] == '\0' || loc[3] == '_'))
585 remove_ampm = true;
586 break;
587 default:
588 break;
590 break;
591 case 'm':
592 switch (loc[1])
594 case 'g': case 'i': case 'k': case 'n': case 's': case 't':
595 if (loc[2] == '\0' || loc[2] == '_')
596 remove_ampm = true;
597 break;
598 case 'h':
599 if (loc[2] == 'r' && (loc[3] == '\0' || loc[3] == '_'))
600 remove_ampm = true;
601 break;
602 default:
603 break;
605 break;
606 case 'n':
607 switch (loc[1])
609 case 'b': case 'l': case 'n': case 'r':
610 if (loc[2] == '\0' || loc[2] == '_')
611 remove_ampm = true;
612 break;
613 case 'd':
614 if (loc[2] == 's' && (loc[3] == '\0' || loc[3] == '_'))
615 remove_ampm = true;
616 break;
617 case 'h':
618 if (loc[2] == 'n' && (loc[3] == '\0' || loc[3] == '_'))
619 remove_ampm = true;
620 break;
621 case 's':
622 if (loc[2] == 'o' && (loc[3] == '\0' || loc[3] == '_'))
623 remove_ampm = true;
624 break;
625 default:
626 break;
628 break;
629 case 'o':
630 switch (loc[1])
632 case 'c': case 's':
633 if (loc[2] == '\0' || loc[2] == '_')
634 remove_ampm = true;
635 break;
636 default:
637 break;
639 break;
640 case 'p':
641 switch (loc[1])
643 case 'l': case 't':
644 if (loc[2] == '\0' || loc[2] == '_')
645 remove_ampm = true;
646 break;
647 case 'a':
648 if (loc[2] == 'p' && (loc[3] == '\0' || loc[3] == '_'))
649 remove_ampm = true;
650 break;
651 default:
652 break;
654 break;
655 case 'r':
656 switch (loc[1])
658 case 'o': case 'u': case 'w':
659 if (loc[2] == '\0' || loc[2] == '_')
660 remove_ampm = true;
661 break;
662 default:
663 break;
665 break;
666 case 's':
667 switch (loc[1])
669 case 'c': case 'e': case 'k': case 'l': case 'm': case 'r': case 's':
670 case 't': case 'u': case 'v':
671 if (loc[2] == '\0' || loc[2] == '_')
672 remove_ampm = true;
673 break;
674 case 'a':
675 if (loc[2] == 'h' && (loc[3] == '\0' || loc[3] == '_'))
676 remove_ampm = true;
677 break;
678 case 'g':
679 if (loc[2] == 's' && (loc[3] == '\0' || loc[3] == '_'))
680 remove_ampm = true;
681 break;
682 case 'z':
683 if (loc[2] == 'l' && (loc[3] == '\0' || loc[3] == '_'))
684 remove_ampm = true;
685 break;
686 default:
687 break;
689 break;
690 case 't':
691 switch (loc[1])
693 case 'g': case 'k': case 'n': case 's': case 't':
694 if (loc[2] == '\0' || loc[2] == '_')
695 remove_ampm = true;
696 break;
697 default:
698 break;
700 break;
701 case 'u':
702 switch (loc[1])
704 case 'g': case 'k': case 'z':
705 if (loc[2] == '\0' || loc[2] == '_')
706 remove_ampm = true;
707 break;
708 case 'n':
709 if (loc[2] == 'm'&& (loc[3] == '\0' || loc[3] == '_'))
710 remove_ampm = true;
711 break;
712 default:
713 break;
715 break;
716 case 'v':
717 switch (loc[1])
719 case 'e':
720 if (loc[2] == '\0' || loc[2] == '_')
721 remove_ampm = true;
722 break;
723 default:
724 break;
726 break;
727 case 'w':
728 switch (loc[1])
730 case 'a':
731 if (loc[2] == 'e' && (loc[3] == '\0' || loc[3] == '_'))
732 remove_ampm = true;
733 break;
734 case 'o':
735 if (loc[2] == '\0' || loc[2] == '_')
736 remove_ampm = true;
737 break;
738 default:
739 break;
741 break;
742 case 'x':
743 switch (loc[1])
745 case 'h':
746 if (loc[2] == '\0' || loc[2] == '_')
747 remove_ampm = true;
748 break;
749 default:
750 break;
752 break;
753 case 'z':
754 switch (loc[1])
756 case 'u':
757 if (loc[2] == '\0' || loc[2] == '_')
758 remove_ampm = true;
759 break;
760 default:
761 break;
763 break;
764 default:
765 break;
767 return remove_ampm;
770 #endif
773 #if ! HAVE_STRUCT_TM_TM_GMTOFF
774 /* Yield the difference between *A and *B,
775 measured in seconds, ignoring leap seconds. */
776 # define tm_diff ftime_tm_diff
777 static int tm_diff (const struct tm *, const struct tm *);
778 static int
779 tm_diff (const struct tm *a, const struct tm *b)
781 /* Compute intervening leap days correctly even if year is negative.
782 Take care to avoid int overflow in leap day calculations,
783 but it's OK to assume that A and B are close to each other. */
784 int a4 = SHR (a->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (a->tm_year & 3);
785 int b4 = SHR (b->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (b->tm_year & 3);
786 int a100 = (a4 + (a4 < 0)) / 25 - (a4 < 0);
787 int b100 = (b4 + (b4 < 0)) / 25 - (b4 < 0);
788 int a400 = SHR (a100, 2);
789 int b400 = SHR (b100, 2);
790 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
791 int years = a->tm_year - b->tm_year;
792 int days = (365 * years + intervening_leap_days
793 + (a->tm_yday - b->tm_yday));
794 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
795 + (a->tm_min - b->tm_min))
796 + (a->tm_sec - b->tm_sec));
798 #endif
802 /* The number of days from the first day of the first ISO week of this
803 year to the year day YDAY with week day WDAY. ISO weeks start on
804 Monday; the first ISO week has the year's first Thursday. YDAY may
805 be as small as YDAY_MINIMUM. */
806 #define ISO_WEEK_START_WDAY 1 /* Monday */
807 #define ISO_WEEK1_WDAY 4 /* Thursday */
808 #define YDAY_MINIMUM (-366)
809 static int iso_week_days (int, int);
810 static __inline int
811 iso_week_days (int yday, int wday)
813 /* Add enough to the first operand of % to make it nonnegative. */
814 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
815 return (yday
816 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
817 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
821 #if !defined _NL_CURRENT && (USE_C_LOCALE && !HAVE_STRFTIME_L)
822 static CHAR_T const c_weekday_names[][sizeof "Wednesday"] =
824 L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
825 L_("Thursday"), L_("Friday"), L_("Saturday")
827 static CHAR_T const c_month_names[][sizeof "September"] =
829 L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
830 L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
831 L_("November"), L_("December")
833 #endif
836 /* When compiling this file, Gnulib-using applications should #define
837 my_strftime to a symbol (typically nstrftime) to name their
838 extended strftime with extra arguments TZ and NS. */
840 #ifdef my_strftime
841 # define extra_args , tz, ns
842 # define extra_args_spec , timezone_t tz, int ns
843 #else
844 # if defined COMPILE_WIDE
845 # define my_strftime wcsftime
846 # define nl_get_alt_digit _nl_get_walt_digit
847 # else
848 # define my_strftime strftime
849 # define nl_get_alt_digit _nl_get_alt_digit
850 # endif
851 # define extra_args
852 # define extra_args_spec
853 /* We don't have this information in general. */
854 # define tz 1
855 # define ns 0
856 #endif
858 static size_t __strftime_internal (STREAM_OR_CHAR_T *, STRFTIME_ARG (size_t)
859 const CHAR_T *, const struct tm *,
860 bool, enum pad_style, int, bool *
861 extra_args_spec LOCALE_PARAM);
863 #if !defined _LIBC \
864 && (!(USE_C_LOCALE && !HAVE_STRFTIME_L) || !HAVE_STRUCT_TM_TM_ZONE)
866 /* Make sure we're calling the actual underlying strftime.
867 In some cases, time.h contains something like
868 "#define strftime rpl_strftime". */
869 # ifdef strftime
870 # undef strftime
871 # endif
873 /* Assuming the time zone is TZ, store into UBUF, of size UBUFSIZE, a
874 ' ' followed by the result of calling strftime with the format
875 "%MF" where M is MODIFIER (or is omitted if !MODIFIER) and F is
876 FORMAT_CHAR, along with the time information specified by *TP.
877 Return the number of bytes stored if successful, zero otherwise. */
878 static size_t
879 underlying_strftime (timezone_t tz, char *ubuf, size_t ubufsize,
880 char modifier, char format_char, struct tm const *tp)
882 /* The relevant information is available only via the
883 underlying strftime implementation, so use that. */
884 char ufmt[5];
885 char *u = ufmt;
887 /* The space helps distinguish strftime failure from empty
888 output. */
889 *u++ = ' ';
890 *u++ = '%';
891 *u = modifier;
892 u += !!modifier;
893 *u++ = format_char;
894 *u = '\0';
896 # if HAVE_NATIVE_TIME_Z
897 if (!tz)
899 tz = utc_timezone ();
900 if (!tz)
901 return 0; /* errno is set here */
903 # endif
905 # if !HAVE_NATIVE_TIME_Z
906 if (tz && tz != local_tz)
908 tz = set_tz (tz);
909 if (!tz)
910 return 0;
912 # endif
914 size_t len;
915 # if USE_C_LOCALE && HAVE_STRFTIME_L
916 locale_t locale = c_locale ();
917 if (!locale)
918 return 0; /* errno is set here */
919 # if HAVE_STRFTIME_LZ
920 len = strftime_lz (tz, ubuf, ubufsize, ufmt, tp, locale);
921 # else
922 len = strftime_l (ubuf, ubufsize, ufmt, tp, locale);
923 # endif
924 # else
925 # if HAVE_STRFTIME_Z
926 len = strftime_z (tz, ubuf, ubufsize, ufmt, tp);
927 # else
928 len = strftime (ubuf, ubufsize, ufmt, tp);
929 # endif
930 # endif
932 # if !HAVE_NATIVE_TIME_Z
933 if (tz && !revert_tz (tz))
934 return 0;
935 # endif
937 if (len != 0)
939 # if ((__GLIBC__ == 2 && __GLIBC_MINOR__ < 31) \
940 || defined __NetBSD__ || defined __sun)
941 /* glibc < 2.31, NetBSD, Solaris */
942 if (format_char == 'c')
944 /* The output of the strftime %c directive consists of the
945 date, the time, and the time zone. But the time zone is
946 wrong, since neither TZ nor ZONE was passed as argument.
947 Therefore, remove the the last space-delimited word.
948 In order not to accidentally remove a date or a year
949 (that contains no letter) or an AM/PM indicator (that has
950 length 2), remove that last word only if it contains a
951 letter and has length >= 3. */
952 char *space;
953 for (space = ubuf + len - 1; *space != ' '; space--)
954 continue;
955 if (space > ubuf)
957 /* Found a space. */
958 if (strlen (space + 1) >= 3)
960 /* The last word has length >= 3. */
961 bool found_letter = false;
962 const char *p;
963 for (p = space + 1; *p != '\0'; p++)
964 if ((*p >= 'A' && *p <= 'Z')
965 || (*p >= 'a' && *p <= 'z'))
967 found_letter = true;
968 break;
970 if (found_letter)
972 /* The last word contains a letter. */
973 *space = '\0';
974 len = space - ubuf;
979 # if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM
980 /* The output of the strftime %p and %r directives contains
981 an AM/PM indicator even for locales where it is not
982 suitable, such as French. Remove this indicator. */
983 if (format_char == 'p')
985 bool found_ampm = (len > 1);
986 if (found_ampm && should_remove_ampm ())
988 ubuf[1] = '\0';
989 len = 1;
992 else if (format_char == 'r')
994 char last_char = ubuf[len - 1];
995 bool found_ampm = !(last_char >= '0' && last_char <= '9');
996 if (found_ampm && should_remove_ampm ())
998 char *space;
999 for (space = ubuf + len - 1; *space != ' '; space--)
1000 continue;
1001 if (space > ubuf)
1003 *space = '\0';
1004 len = space - ubuf;
1008 # endif
1009 # endif
1011 return len;
1013 #endif
1015 /* Return a time zone abbreviation for TZ. Use BUF, of size BUFSIZE,
1016 to store it if needed. If MODIFIER use the strftime format
1017 "%mZ" to format it, where m is the MODIFIER; otherwise
1018 use plain "%Z". Format an abbreviation appropriate for
1019 TP and EXTRA_ARGS_SPEC. Return the empty string on failure. */
1020 static char const *
1021 get_tm_zone (timezone_t tz, char *ubuf, int ubufsize, int modifier,
1022 struct tm const *tp)
1024 #if HAVE_STRUCT_TM_TM_ZONE
1025 /* The POSIX test suite assumes that setting
1026 the environment variable TZ to a new value before calling strftime()
1027 will influence the result (the %Z format) even if the information in
1028 *TP is computed with a totally different time zone.
1029 This is bogus: though POSIX allows bad behavior like this,
1030 POSIX does not require it. Do the right thing instead. */
1031 return tp->tm_zone;
1032 #else
1033 if (!tz)
1034 return "UTC";
1036 # if !HAVE_NATIVE_TIME_Z
1037 timezone_t old_tz = tz;
1038 if (tz != local_tz)
1040 old_tz = set_tz (tz);
1041 if (!old_tz)
1042 return "";
1044 # endif
1046 int zsize = underlying_strftime (tz, ubuf, ubufsize, 0, 'Z', tp);
1048 # if !HAVE_NATIVE_TIME_Z
1049 if (!revert_tz (old_tz))
1050 return "";
1051 # endif
1053 return zsize ? ubuf + 1 : "";
1054 #endif
1057 /* Write information from TP into S according to the format
1058 string FORMAT, writing no more that MAXSIZE characters
1059 (including the terminating '\0') and returning number of
1060 characters written. If S is NULL, nothing will be written
1061 anywhere, so to determine how many characters would be
1062 written, use NULL for S and (size_t) -1 for MAXSIZE. */
1063 size_t
1064 my_strftime (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
1065 const CHAR_T *format,
1066 const struct tm *tp extra_args_spec LOCALE_PARAM)
1068 bool tzset_called = false;
1069 return __strftime_internal (s, STRFTIME_ARG (maxsize) format, tp, false,
1070 ZERO_PAD, -1,
1071 &tzset_called extra_args LOCALE_ARG);
1073 libc_hidden_def (my_strftime)
1075 /* Just like my_strftime, above, but with more parameters.
1076 UPCASE indicates that the result should be converted to upper case.
1077 YR_SPEC and WIDTH specify the padding and width for the year.
1078 *TZSET_CALLED indicates whether tzset has been called here. */
1079 static size_t
1080 __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
1081 const CHAR_T *format,
1082 const struct tm *tp, bool upcase,
1083 enum pad_style yr_spec, int width, bool *tzset_called
1084 extra_args_spec LOCALE_PARAM)
1086 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
1087 struct __locale_data *const current = loc->__locales[LC_TIME];
1088 #endif
1089 #if FPRINTFTIME
1090 size_t maxsize = (size_t) -1;
1091 #endif
1093 int saved_errno = errno;
1094 int hour12 = tp->tm_hour;
1095 #ifdef _NL_CURRENT
1096 /* We cannot make the following values variables since we must delay
1097 the evaluation of these values until really needed since some
1098 expressions might not be valid in every situation. The 'struct tm'
1099 might be generated by a strptime() call that initialized
1100 only a few elements. Dereference the pointers only if the format
1101 requires this. Then it is ok to fail if the pointers are invalid. */
1102 # define a_wkday \
1103 ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6 \
1104 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday)))
1105 # define f_wkday \
1106 ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6 \
1107 ? "?" : _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday)))
1108 # define a_month \
1109 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
1110 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon)))
1111 # define f_month \
1112 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
1113 ? "?" : _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon)))
1114 # define a_altmonth \
1115 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
1116 ? "?" : _NL_CURRENT (LC_TIME, NLW(ABALTMON_1) + tp->tm_mon)))
1117 # define f_altmonth \
1118 ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
1119 ? "?" : _NL_CURRENT (LC_TIME, NLW(ALTMON_1) + tp->tm_mon)))
1120 # define ampm \
1121 ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
1122 ? NLW(PM_STR) : NLW(AM_STR)))
1124 # define aw_len STRLEN (a_wkday)
1125 # define am_len STRLEN (a_month)
1126 # define aam_len STRLEN (a_altmonth)
1127 # define ap_len STRLEN (ampm)
1128 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1129 /* The English abbreviated weekday names are just the first 3 characters of the
1130 English full weekday names. */
1131 # define a_wkday \
1132 (tp->tm_wday < 0 || tp->tm_wday > 6 ? L_("?") : c_weekday_names[tp->tm_wday])
1133 # define aw_len 3
1134 # define f_wkday \
1135 (tp->tm_wday < 0 || tp->tm_wday > 6 ? L_("?") : c_weekday_names[tp->tm_wday])
1136 /* The English abbreviated month names are just the first 3 characters of the
1137 English full month names. */
1138 # define a_month \
1139 (tp->tm_mon < 0 || tp->tm_mon > 11 ? L_("?") : c_month_names[tp->tm_mon])
1140 # define am_len 3
1141 # define f_month \
1142 (tp->tm_mon < 0 || tp->tm_mon > 11 ? L_("?") : c_month_names[tp->tm_mon])
1143 /* The English AM/PM strings happen to have the same length, namely 2. */
1144 # define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
1145 # define ap_len 2
1146 #endif
1147 size_t i = 0;
1148 STREAM_OR_CHAR_T *p = s;
1149 const CHAR_T *f;
1150 #if DO_MULTIBYTE && !defined COMPILE_WIDE
1151 const char *format_end = NULL;
1152 #endif
1154 if (hour12 > 12)
1155 hour12 -= 12;
1156 else
1157 if (hour12 == 0)
1158 hour12 = 12;
1160 for (f = format; *f != '\0'; width = -1, f++)
1162 enum pad_style pad = ZERO_PAD;
1163 int modifier; /* Field modifier ('E', 'O', or 0). */
1164 int digits = 0; /* Max digits for numeric format. */
1165 int number_value; /* Numeric value to be printed. */
1166 unsigned int u_number_value; /* (unsigned int) number_value. */
1167 bool negative_number; /* The number is negative. */
1168 bool always_output_a_sign; /* +/- should always be output. */
1169 int tz_colon_mask; /* Bitmask of where ':' should appear. */
1170 const CHAR_T *subfmt;
1171 CHAR_T *bufp;
1172 CHAR_T buf[1
1173 + 2 /* for the two colons in a %::z or %:::z time zone */
1174 + (sizeof (int) < sizeof (time_t)
1175 ? INT_STRLEN_BOUND (time_t)
1176 : INT_STRLEN_BOUND (int))];
1177 bool to_lowcase = false;
1178 bool to_uppcase = upcase;
1179 size_t colons;
1180 bool change_case = false;
1181 int format_char;
1182 int subwidth;
1184 #if DO_MULTIBYTE && !defined COMPILE_WIDE
1185 switch (*f)
1187 case L_('%'):
1188 break;
1190 case L_('\b'): case L_('\t'): case L_('\n'):
1191 case L_('\v'): case L_('\f'): case L_('\r'):
1192 case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
1193 case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
1194 case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
1195 case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
1196 case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
1197 case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
1198 case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
1199 case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
1200 case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
1201 case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
1202 case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
1203 case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
1204 case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
1205 case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
1206 case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
1207 case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
1208 case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
1209 case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
1210 case L_('~'):
1211 /* The C Standard requires these 98 characters (plus '%') to
1212 be in the basic execution character set. None of these
1213 characters can start a multibyte sequence, so they need
1214 not be analyzed further. */
1215 add1 (*f);
1216 continue;
1218 default:
1219 /* Copy this multibyte sequence until we reach its end, find
1220 an error, or come back to the initial shift state. */
1222 mbstate_t mbstate = mbstate_zero;
1223 size_t len = 0;
1224 size_t fsize;
1226 if (! format_end)
1227 format_end = f + strlen (f) + 1;
1228 fsize = format_end - f;
1232 size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
1234 if (bytes == 0)
1235 break;
1237 if (bytes == (size_t) -2)
1239 len += strlen (f + len);
1240 break;
1243 if (bytes == (size_t) -1)
1245 len++;
1246 break;
1249 len += bytes;
1251 while (! mbsinit (&mbstate));
1253 cpy (len, f);
1254 f += len - 1;
1255 continue;
1259 #else /* ! DO_MULTIBYTE */
1261 /* Either multibyte encodings are not supported, they are
1262 safe for formats, so any non-'%' byte can be copied through,
1263 or this is the wide character version. */
1264 if (*f != L_('%'))
1266 add1 (*f);
1267 continue;
1270 #endif /* ! DO_MULTIBYTE */
1272 char const *percent = f;
1274 /* Check for flags that can modify a format. */
1275 while (1)
1277 switch (*++f)
1279 /* This influences the number formats. */
1280 case L_('_'): pad = SPACE_PAD; continue;
1281 case L_('-'): pad = NO_PAD; continue;
1282 case L_('+'): pad = SIGN_PAD; continue;
1283 case L_('0'): pad = ALWAYS_ZERO_PAD; continue;
1285 /* This changes textual output. */
1286 case L_('^'):
1287 to_uppcase = true;
1288 continue;
1289 case L_('#'):
1290 change_case = true;
1291 continue;
1293 default:
1294 break;
1296 break;
1299 if (ISDIGIT (*f))
1301 width = 0;
1304 if (ckd_mul (&width, width, 10)
1305 || ckd_add (&width, width, *f - L_('0')))
1306 width = INT_MAX;
1307 ++f;
1309 while (ISDIGIT (*f));
1312 /* Check for modifiers. */
1313 switch (*f)
1315 case L_('E'):
1316 case L_('O'):
1317 modifier = *f++;
1318 break;
1320 default:
1321 modifier = 0;
1322 break;
1325 /* Now do the specified format. */
1326 format_char = *f;
1327 switch (format_char)
1329 #define DO_NUMBER(d, v) \
1330 do \
1332 digits = d; \
1333 number_value = v; \
1334 goto do_number; \
1336 while (0)
1337 #define DO_SIGNED_NUMBER(d, negative, v) \
1338 DO_MAYBE_SIGNED_NUMBER (d, negative, v, do_signed_number)
1339 #define DO_YEARISH(d, negative, v) \
1340 DO_MAYBE_SIGNED_NUMBER (d, negative, v, do_yearish)
1341 #define DO_MAYBE_SIGNED_NUMBER(d, negative, v, label) \
1342 do \
1344 digits = d; \
1345 negative_number = negative; \
1346 u_number_value = v; \
1347 goto label; \
1349 while (0)
1351 /* The mask is not what you might think.
1352 When the ordinal i'th bit is set, insert a colon
1353 before the i'th digit of the time zone representation. */
1354 #define DO_TZ_OFFSET(d, mask, v) \
1355 do \
1357 digits = d; \
1358 tz_colon_mask = mask; \
1359 u_number_value = v; \
1360 goto do_tz_offset; \
1362 while (0)
1363 #define DO_NUMBER_SPACEPAD(d, v) \
1364 do \
1366 digits = d; \
1367 number_value = v; \
1368 goto do_number_spacepad; \
1370 while (0)
1372 case L_('%'):
1373 if (f - 1 != percent)
1374 goto bad_percent;
1375 add1 (*f);
1376 break;
1378 case L_('a'):
1379 if (modifier != 0)
1380 goto bad_format;
1381 if (change_case)
1383 to_uppcase = true;
1384 to_lowcase = false;
1386 #if defined _NL_CURRENT || (USE_C_LOCALE && !HAVE_STRFTIME_L)
1387 cpy (aw_len, a_wkday);
1388 break;
1389 #else
1390 goto underlying_strftime;
1391 #endif
1393 case 'A':
1394 if (modifier != 0)
1395 goto bad_format;
1396 if (change_case)
1398 to_uppcase = true;
1399 to_lowcase = false;
1401 #if defined _NL_CURRENT || (USE_C_LOCALE && !HAVE_STRFTIME_L)
1402 cpy (STRLEN (f_wkday), f_wkday);
1403 break;
1404 #else
1405 goto underlying_strftime;
1406 #endif
1408 case L_('b'):
1409 case L_('h'):
1410 if (change_case)
1412 to_uppcase = true;
1413 to_lowcase = false;
1415 if (modifier == L_('E'))
1416 goto bad_format;
1417 #ifdef _NL_CURRENT
1418 if (modifier == L_('O'))
1419 cpy (aam_len, a_altmonth);
1420 else
1421 cpy (am_len, a_month);
1422 break;
1423 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1424 cpy (am_len, a_month);
1425 break;
1426 #else
1427 # if defined _WIN32 && !defined __CYGWIN__
1428 format_char = L_('b');
1429 # endif
1430 goto underlying_strftime;
1431 #endif
1433 case L_('B'):
1434 if (modifier == L_('E'))
1435 goto bad_format;
1436 if (change_case)
1438 to_uppcase = true;
1439 to_lowcase = false;
1441 #ifdef _NL_CURRENT
1442 if (modifier == L_('O'))
1443 cpy (STRLEN (f_altmonth), f_altmonth);
1444 else
1445 cpy (STRLEN (f_month), f_month);
1446 break;
1447 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1448 cpy (STRLEN (f_month), f_month);
1449 break;
1450 #else
1451 goto underlying_strftime;
1452 #endif
1454 case L_('c'):
1455 if (modifier == L_('O'))
1456 goto bad_format;
1457 #ifdef _NL_CURRENT
1458 if (! (modifier == L_('E')
1459 && (*(subfmt =
1460 (const CHAR_T *) _NL_CURRENT (LC_TIME,
1461 NLW(ERA_D_T_FMT)))
1462 != '\0')))
1463 subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
1464 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1465 subfmt = L_("%a %b %e %H:%M:%S %Y");
1466 #elif defined _WIN32 && !defined __CYGWIN__
1467 /* On native Windows, "%c" is "%d/%m/%Y %H:%M:%S" by default. */
1468 bool is_c_locale;
1469 /* This code is equivalent to is_c_locale = !hard_locale (LC_TIME). */
1470 # if defined _MSC_VER
1471 const wchar_t *locale = _wsetlocale (LC_TIME, NULL);
1472 is_c_locale =
1473 (wcscmp (locale, L"C") == 0 || wcscmp (locale, L"POSIX") == 0);
1474 # else
1475 const char *locale = setlocale (LC_TIME, NULL);
1476 is_c_locale =
1477 (strcmp (locale, "C") == 0 || strcmp (locale, "POSIX") == 0);
1478 # endif
1479 if (is_c_locale)
1480 subfmt = L_("%a %b %e %H:%M:%S %Y");
1481 else
1482 subfmt = L_("%a %e %b %Y %H:%M:%S");
1483 #else
1484 goto underlying_strftime;
1485 #endif
1487 subformat:
1488 subwidth = -1;
1489 subformat_width:
1491 size_t len = __strftime_internal (NULL, STRFTIME_ARG ((size_t) -1)
1492 subfmt, tp, to_uppcase,
1493 pad, subwidth, tzset_called
1494 extra_args LOCALE_ARG);
1495 add (len, __strftime_internal (p,
1496 STRFTIME_ARG (maxsize - i)
1497 subfmt, tp, to_uppcase,
1498 pad, subwidth, tzset_called
1499 extra_args LOCALE_ARG));
1501 break;
1503 #if !defined _LIBC && !(USE_C_LOCALE && !HAVE_STRFTIME_L)
1504 underlying_strftime:
1506 char ubuf[1024]; /* enough for any single format in practice */
1507 size_t len;
1508 len = underlying_strftime (tz, ubuf, sizeof ubuf,
1509 modifier, format_char, tp);
1510 if (len != 0)
1512 # if (__GLIBC__ == 2 && __GLIBC_MINOR__ < 31) || defined __NetBSD__ || defined __sun /* glibc < 2.31, NetBSD, Solaris */
1513 if (format_char == L_('c'))
1515 /* The output of the strftime %c directive consists of the
1516 date, the time, and the time zone. But the time zone is
1517 wrong, since neither TZ nor ZONE was passed as argument.
1518 Therefore, remove the the last space-delimited word.
1519 In order not to accidentally remove a date or a year
1520 (that contains no letter) or an AM/PM indicator (that has
1521 length 2), remove that last word only if it contains a
1522 letter and has length >= 3. */
1523 char *space;
1524 for (space = ubuf + len - 1; *space != ' '; space--)
1526 if (space > ubuf)
1528 /* Found a space. */
1529 if (strlen (space + 1) >= 3)
1531 /* The last word has length >= 3. */
1532 bool found_letter = false;
1533 const char *p;
1534 for (p = space + 1; *p != '\0'; p++)
1535 if ((*p >= 'A' && *p <= 'Z')
1536 || (*p >= 'a' && *p <= 'z'))
1538 found_letter = true;
1539 break;
1541 if (found_letter)
1543 /* The last word contains a letter. */
1544 *space = '\0';
1545 len = space - ubuf;
1550 # if (defined __NetBSD__ || defined __sun) && REQUIRE_GNUISH_STRFTIME_AM_PM
1551 /* The output of the strftime %p and %r directives contains
1552 an AM/PM indicator even for locales where it is not
1553 suitable, such as French. Remove this indicator. */
1554 else if (format_char == L_('p'))
1556 bool found_ampm = (len > 1);
1557 if (found_ampm && should_remove_ampm ())
1559 ubuf[1] = '\0';
1560 len = 1;
1563 else if (format_char == L_('r'))
1565 char last_char = ubuf[len - 1];
1566 bool found_ampm = !(last_char >= '0' && last_char <= '9');
1567 if (found_ampm && should_remove_ampm ())
1569 char *space;
1570 for (space = ubuf + len - 1; *space != ' '; space--)
1572 if (space > ubuf)
1574 *space = '\0';
1575 len = space - ubuf;
1579 # endif
1580 # endif
1581 cpy (len - 1, ubuf + 1);
1584 break;
1585 #endif
1587 case L_('C'):
1588 if (modifier == L_('E'))
1590 #if HAVE_STRUCT_ERA_ENTRY
1591 struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1592 if (era)
1594 # ifdef COMPILE_WIDE
1595 size_t len = __wcslen (era->era_wname);
1596 cpy (len, era->era_wname);
1597 # else
1598 size_t len = strlen (era->era_name);
1599 cpy (len, era->era_name);
1600 # endif
1601 break;
1603 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1604 #else
1605 goto underlying_strftime;
1606 #endif
1610 bool negative_year = tp->tm_year < - TM_YEAR_BASE;
1611 bool zero_thru_1899 = !negative_year & (tp->tm_year < 0);
1612 int century = ((tp->tm_year - 99 * zero_thru_1899) / 100
1613 + TM_YEAR_BASE / 100);
1614 DO_YEARISH (2, negative_year, century);
1617 case L_('x'):
1618 if (modifier == L_('O'))
1619 goto bad_format;
1620 #ifdef _NL_CURRENT
1621 if (! (modifier == L_('E')
1622 && (*(subfmt =
1623 (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
1624 != L_('\0'))))
1625 subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
1626 goto subformat;
1627 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1628 subfmt = L_("%m/%d/%y");
1629 goto subformat;
1630 #else
1631 goto underlying_strftime;
1632 #endif
1633 case L_('D'):
1634 if (modifier != 0)
1635 goto bad_format;
1636 subfmt = L_("%m/%d/%y");
1637 goto subformat;
1639 case L_('d'):
1640 if (modifier == L_('E'))
1641 goto bad_format;
1643 DO_NUMBER (2, tp->tm_mday);
1645 case L_('e'):
1646 if (modifier == L_('E'))
1647 goto bad_format;
1649 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
1651 /* All numeric formats set DIGITS and NUMBER_VALUE (or U_NUMBER_VALUE)
1652 and then jump to one of these labels. */
1654 do_tz_offset:
1655 always_output_a_sign = true;
1656 goto do_number_body;
1658 do_yearish:
1659 if (pad == ZERO_PAD)
1660 pad = yr_spec;
1661 always_output_a_sign
1662 = (pad == SIGN_PAD
1663 && ((digits == 2 ? 99 : 9999) < u_number_value
1664 || digits < width));
1665 goto do_maybe_signed_number;
1667 do_number_spacepad:
1668 if (pad == ZERO_PAD)
1669 pad = SPACE_PAD;
1671 do_number:
1672 /* Format NUMBER_VALUE according to the MODIFIER flag. */
1673 negative_number = number_value < 0;
1674 u_number_value = number_value;
1676 do_signed_number:
1677 always_output_a_sign = false;
1679 do_maybe_signed_number:
1680 tz_colon_mask = 0;
1682 do_number_body:
1683 /* Format U_NUMBER_VALUE according to the MODIFIER flag.
1684 NEGATIVE_NUMBER is nonzero if the original number was
1685 negative; in this case it was converted directly to
1686 unsigned int (i.e., modulo (UINT_MAX + 1)) without
1687 negating it. */
1688 if (modifier == L_('O') && !negative_number)
1690 #ifdef _NL_CURRENT
1691 /* Get the locale specific alternate representation of
1692 the number. If none exist NULL is returned. */
1693 const CHAR_T *cp = nl_get_alt_digit (u_number_value
1694 HELPER_LOCALE_ARG);
1696 if (cp != NULL)
1698 size_t digitlen = STRLEN (cp);
1699 if (digitlen != 0)
1701 cpy (digitlen, cp);
1702 break;
1705 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1706 #else
1707 goto underlying_strftime;
1708 #endif
1711 bufp = buf + sizeof (buf) / sizeof (buf[0]);
1713 if (negative_number)
1714 u_number_value = - u_number_value;
1718 if (tz_colon_mask & 1)
1719 *--bufp = ':';
1720 tz_colon_mask >>= 1;
1721 *--bufp = u_number_value % 10 + L_('0');
1722 u_number_value /= 10;
1724 while (u_number_value != 0 || tz_colon_mask != 0);
1726 do_number_sign_and_padding:
1727 if (pad == ZERO_PAD)
1728 pad = ALWAYS_ZERO_PAD;
1729 if (width < 0)
1730 width = digits;
1733 CHAR_T sign_char = (negative_number ? L_('-')
1734 : always_output_a_sign ? L_('+')
1735 : 0);
1736 int numlen = buf + sizeof buf / sizeof buf[0] - bufp;
1737 int shortage = width - !!sign_char - numlen;
1738 int padding = pad == NO_PAD || shortage <= 0 ? 0 : shortage;
1740 if (sign_char)
1742 if (pad == SPACE_PAD)
1744 if (p)
1745 memset_space (p, padding);
1746 i += padding;
1747 width -= padding;
1749 width_add1 (0, sign_char);
1750 width--;
1753 cpy (numlen, bufp);
1755 break;
1757 case L_('F'):
1758 if (modifier != 0)
1759 goto bad_format;
1760 if (pad == ZERO_PAD && width < 0)
1762 pad = SIGN_PAD;
1763 subwidth = 4;
1765 else
1767 subwidth = width - 6;
1768 if (subwidth < 0)
1769 subwidth = 0;
1771 subfmt = L_("%Y-%m-%d");
1772 goto subformat_width;
1774 case L_('H'):
1775 if (modifier == L_('E'))
1776 goto bad_format;
1778 DO_NUMBER (2, tp->tm_hour);
1780 case L_('I'):
1781 if (modifier == L_('E'))
1782 goto bad_format;
1784 DO_NUMBER (2, hour12);
1786 case L_('k'): /* GNU extension. */
1787 if (modifier == L_('E'))
1788 goto bad_format;
1790 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
1792 case L_('l'): /* GNU extension. */
1793 if (modifier == L_('E'))
1794 goto bad_format;
1796 DO_NUMBER_SPACEPAD (2, hour12);
1798 case L_('j'):
1799 if (modifier == L_('E'))
1800 goto bad_format;
1802 DO_SIGNED_NUMBER (3, tp->tm_yday < -1, tp->tm_yday + 1U);
1804 case L_('M'):
1805 if (modifier == L_('E'))
1806 goto bad_format;
1808 DO_NUMBER (2, tp->tm_min);
1810 case L_('m'):
1811 if (modifier == L_('E'))
1812 goto bad_format;
1814 DO_SIGNED_NUMBER (2, tp->tm_mon < -1, tp->tm_mon + 1U);
1816 #ifndef _LIBC
1817 case L_('N'): /* GNU extension. */
1818 if (modifier == L_('E'))
1819 goto bad_format;
1821 int n = ns, ns_digits = 9;
1822 if (width <= 0)
1823 width = ns_digits;
1824 int ndigs = ns_digits;
1825 while (width < ndigs || (1 < ndigs && n % 10 == 0))
1826 ndigs--, n /= 10;
1827 for (int j = ndigs; 0 < j; j--)
1828 buf[j - 1] = n % 10 + L_('0'), n /= 10;
1829 if (pad == ZERO_PAD)
1830 pad = ALWAYS_ZERO_PAD;
1831 width_cpy (0, ndigs, buf);
1832 width_add (width - ndigs, 0, (void) 0);
1834 break;
1835 #endif
1837 case L_('n'):
1838 add1 (L_('\n'));
1839 break;
1841 case L_('P'):
1842 to_lowcase = true;
1843 #ifndef _NL_CURRENT
1844 format_char = L_('p');
1845 #endif
1846 FALLTHROUGH;
1847 case L_('p'):
1848 if (change_case)
1850 to_uppcase = false;
1851 to_lowcase = true;
1853 #if defined _NL_CURRENT || (USE_C_LOCALE && !HAVE_STRFTIME_L)
1854 cpy (ap_len, ampm);
1855 break;
1856 #else
1857 goto underlying_strftime;
1858 #endif
1860 case L_('q'): /* GNU extension. */
1861 DO_SIGNED_NUMBER (1, false, ((tp->tm_mon * 11) >> 5) + 1);
1863 case L_('R'):
1864 subfmt = L_("%H:%M");
1865 goto subformat;
1867 case L_('r'):
1868 #ifdef _NL_CURRENT
1869 if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
1870 NLW(T_FMT_AMPM)))
1871 == L_('\0'))
1872 subfmt = L_("%I:%M:%S %p");
1873 goto subformat;
1874 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1875 subfmt = L_("%I:%M:%S %p");
1876 goto subformat;
1877 #elif ((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ \
1878 || (defined _WIN32 && !defined __CYGWIN__))
1879 /* macOS, FreeBSD, native Windows strftime() may produce empty output
1880 for "%r". */
1881 subfmt = L_("%I:%M:%S %p");
1882 goto subformat;
1883 #else
1884 goto underlying_strftime;
1885 #endif
1887 case L_('S'):
1888 if (modifier == L_('E'))
1889 goto bad_format;
1891 DO_NUMBER (2, tp->tm_sec);
1893 case L_('s'): /* GNU extension. */
1895 struct tm ltm;
1896 time_t t;
1898 ltm = *tp;
1899 ltm.tm_yday = -1;
1900 t = mktime_z (tz, &ltm);
1901 if (ltm.tm_yday < 0)
1903 errno = EOVERFLOW;
1904 return 0;
1907 /* Generate string value for T using time_t arithmetic;
1908 this works even if sizeof (long) < sizeof (time_t). */
1910 bufp = buf + sizeof (buf) / sizeof (buf[0]);
1911 negative_number = t < 0;
1915 int d = t % 10;
1916 t /= 10;
1917 *--bufp = (negative_number ? -d : d) + L_('0');
1919 while (t != 0);
1921 digits = 1;
1922 always_output_a_sign = false;
1923 goto do_number_sign_and_padding;
1926 case L_('X'):
1927 if (modifier == L_('O'))
1928 goto bad_format;
1929 #ifdef _NL_CURRENT
1930 if (! (modifier == L_('E')
1931 && (*(subfmt =
1932 (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
1933 != L_('\0'))))
1934 subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
1935 goto subformat;
1936 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
1937 subfmt = L_("%H:%M:%S");
1938 goto subformat;
1939 #else
1940 goto underlying_strftime;
1941 #endif
1942 case L_('T'):
1943 subfmt = L_("%H:%M:%S");
1944 goto subformat;
1946 case L_('t'):
1947 add1 (L_('\t'));
1948 break;
1950 case L_('u'):
1951 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1953 case L_('U'):
1954 if (modifier == L_('E'))
1955 goto bad_format;
1957 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1959 case L_('V'):
1960 case L_('g'):
1961 case L_('G'):
1962 if (modifier == L_('E'))
1963 goto bad_format;
1965 /* YEAR is a leap year if and only if (tp->tm_year + TM_YEAR_BASE)
1966 is a leap year, except that YEAR and YEAR - 1 both work
1967 correctly even when (tp->tm_year + TM_YEAR_BASE) would
1968 overflow. */
1969 int year = (tp->tm_year
1970 + (tp->tm_year < 0
1971 ? TM_YEAR_BASE % 400
1972 : TM_YEAR_BASE % 400 - 400));
1973 int year_adjust = 0;
1974 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1976 if (days < 0)
1978 /* This ISO week belongs to the previous year. */
1979 year_adjust = -1;
1980 days = iso_week_days (tp->tm_yday + (365 + __isleap (year - 1)),
1981 tp->tm_wday);
1983 else
1985 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1986 tp->tm_wday);
1987 if (0 <= d)
1989 /* This ISO week belongs to the next year. */
1990 year_adjust = 1;
1991 days = d;
1995 switch (*f)
1997 case L_('g'):
1999 int yy = (tp->tm_year % 100 + year_adjust) % 100;
2000 DO_YEARISH (2, false,
2001 (0 <= yy
2002 ? yy
2003 : tp->tm_year < -TM_YEAR_BASE - year_adjust
2004 ? -yy
2005 : yy + 100));
2008 case L_('G'):
2009 DO_YEARISH (4, tp->tm_year < -TM_YEAR_BASE - year_adjust,
2010 (tp->tm_year + (unsigned int) TM_YEAR_BASE
2011 + year_adjust));
2013 default:
2014 DO_NUMBER (2, days / 7 + 1);
2018 case L_('W'):
2019 if (modifier == L_('E'))
2020 goto bad_format;
2022 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
2024 case L_('w'):
2025 if (modifier == L_('E'))
2026 goto bad_format;
2028 DO_NUMBER (1, tp->tm_wday);
2030 case L_('Y'):
2031 if (modifier == L_('E'))
2033 #if HAVE_STRUCT_ERA_ENTRY
2034 struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
2035 if (era)
2037 # ifdef COMPILE_WIDE
2038 subfmt = era->era_wformat;
2039 # else
2040 subfmt = era->era_format;
2041 # endif
2042 if (pad == ZERO_PAD)
2043 pad = yr_spec;
2044 goto subformat;
2046 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
2047 #else
2048 goto underlying_strftime;
2049 #endif
2051 if (modifier == L_('O'))
2052 goto bad_format;
2054 DO_YEARISH (4, tp->tm_year < -TM_YEAR_BASE,
2055 tp->tm_year + (unsigned int) TM_YEAR_BASE);
2057 case L_('y'):
2058 if (modifier == L_('E'))
2060 #if HAVE_STRUCT_ERA_ENTRY
2061 struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
2062 if (era)
2064 int delta = tp->tm_year - era->start_date[0];
2065 if (pad == ZERO_PAD)
2066 pad = yr_spec;
2067 DO_NUMBER (2, (era->offset
2068 + delta * era->absolute_direction));
2070 #elif USE_C_LOCALE && !HAVE_STRFTIME_L
2071 #else
2072 goto underlying_strftime;
2073 #endif
2077 int yy = tp->tm_year % 100;
2078 if (yy < 0)
2079 yy = tp->tm_year < - TM_YEAR_BASE ? -yy : yy + 100;
2080 DO_YEARISH (2, false, yy);
2083 case L_('Z'):
2084 if (change_case)
2086 to_uppcase = false;
2087 to_lowcase = true;
2091 char const *zone;
2092 #ifdef _LIBC
2093 zone = tp->tm_zone;
2094 /* The tzset() call might have changed the value. */
2095 if (!(zone && *zone) && tp->tm_isdst >= 0)
2097 /* POSIX.1 requires that local time zone information be used as
2098 though strftime called tzset. */
2099 if (!*tzset_called)
2101 tzset ();
2102 *tzset_called = true;
2104 zone = tp->tm_isdst <= 1 ? tzname[tp->tm_isdst] : "?";
2106 if (! zone)
2107 zone = "";
2108 #else
2109 char zonebuf[128]; /* Enough for any time zone abbreviation. */
2110 zone = get_tm_zone (tz, zonebuf, sizeof zonebuf, modifier, tp);
2111 #endif
2113 #ifdef COMPILE_WIDE
2114 /* The zone string is always given in multibyte form. We have
2115 to convert it to wide character. */
2116 size_t w = pad == NO_PAD || width < 0 ? 0 : width;
2117 char const *z = zone;
2118 mbstate_t st = {0};
2119 size_t len = __mbsrtowcs_l (p, &z, maxsize - i, &st, loc);
2120 if (len == (size_t) -1)
2121 return 0;
2122 size_t incr = len < w ? w : len;
2123 if (incr >= maxsize - i)
2125 errno = ERANGE;
2126 return 0;
2128 if (p)
2130 if (len < w)
2132 size_t delta = w - len;
2133 __wmemmove (p + delta, p, len);
2134 wchar_t wc = (pad == ALWAYS_ZERO_PAD || pad == SIGN_PAD
2135 ? L'0' : L' ');
2136 wmemset (p, wc, delta);
2138 p += incr;
2140 i += incr;
2141 #else
2142 cpy (strlen (zone), zone);
2143 #endif
2145 break;
2147 case L_(':'):
2148 /* :, ::, and ::: are valid only just before 'z'.
2149 :::: etc. are rejected later. */
2150 for (colons = 1; f[colons] == L_(':'); colons++)
2151 continue;
2152 if (f[colons] != L_('z'))
2153 goto bad_format;
2154 f += colons;
2155 goto do_z_conversion;
2157 case L_('z'):
2158 colons = 0;
2160 do_z_conversion:
2161 if (tp->tm_isdst < 0)
2162 break;
2165 int diff;
2166 int hour_diff;
2167 int min_diff;
2168 int sec_diff;
2169 #if HAVE_STRUCT_TM_TM_GMTOFF
2170 diff = tp->tm_gmtoff;
2171 #else
2172 if (!tz)
2173 diff = 0;
2174 else
2176 struct tm gtm;
2177 struct tm ltm;
2178 time_t lt;
2180 ltm = *tp;
2181 ltm.tm_wday = -1;
2182 lt = mktime_z (tz, &ltm);
2183 if (ltm.tm_wday < 0 || ! localtime_rz (0, &lt, &gtm))
2184 break;
2185 diff = tm_diff (&ltm, &gtm);
2187 #endif
2189 negative_number = diff < 0;
2190 if (diff == 0)
2192 char zonebuf[128]; /* Enough for any time zone abbreviation. */
2193 negative_number = (*get_tm_zone (tz, zonebuf, sizeof zonebuf,
2194 0, tp)
2195 == '-');
2197 hour_diff = diff / 60 / 60;
2198 min_diff = diff / 60 % 60;
2199 sec_diff = diff % 60;
2201 switch (colons)
2203 case 0: /* +hhmm */
2204 DO_TZ_OFFSET (5, 0, hour_diff * 100 + min_diff);
2206 case 1: tz_hh_mm: /* +hh:mm */
2207 DO_TZ_OFFSET (6, 04, hour_diff * 100 + min_diff);
2209 case 2: tz_hh_mm_ss: /* +hh:mm:ss */
2210 DO_TZ_OFFSET (9, 024,
2211 hour_diff * 10000 + min_diff * 100 + sec_diff);
2213 case 3: /* +hh if possible, else +hh:mm, else +hh:mm:ss */
2214 if (sec_diff != 0)
2215 goto tz_hh_mm_ss;
2216 if (min_diff != 0)
2217 goto tz_hh_mm;
2218 DO_TZ_OFFSET (3, 0, hour_diff);
2220 default:
2221 goto bad_format;
2225 case L_('\0'): /* GNU extension: % at end of format. */
2226 bad_percent:
2227 --f;
2228 FALLTHROUGH;
2229 default:
2230 /* Unknown format; output the format, including the '%',
2231 since this is most likely the right thing to do if a
2232 multibyte string has been misparsed. */
2233 bad_format:
2234 cpy (f - percent + 1, percent);
2235 break;
2239 #if ! FPRINTFTIME
2240 if (p && maxsize != 0)
2241 *p = L_('\0');
2242 #endif
2244 errno = saved_errno;
2245 return i;