1 /* Copyright (C) 1991-2021 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public
6    License as published by the Free Software Foundation; either
7    version 3 of the License, or (at your option) any later version.
8 
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    General Public License for more details.
13 
14    You should have received a copy of the GNU General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #ifdef _LIBC
19 # define USE_IN_EXTENDED_LOCALE_MODEL 1
20 # define HAVE_STRUCT_ERA_ENTRY 1
21 # define HAVE_TM_GMTOFF 1
22 # define HAVE_STRUCT_TM_TM_ZONE 1
23 # define HAVE_TZNAME 1
24 # include "../locale/localeinfo.h"
25 #else
26 # include <config.h>
27 # if FPRINTFTIME
28 #  include "fprintftime.h"
29 # else
30 #  include "strftime.h"
31 # endif
32 # include "time-internal.h"
33 #endif
34 
35 #include <ctype.h>
36 #include <errno.h>
37 #include <time.h>
38 
39 #if HAVE_TZNAME && !HAVE_DECL_TZNAME
40 extern char *tzname[];
41 #endif
42 
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.
51 
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
54    it.  */
55 #if !(defined __osf__ && 0)
56 # define MULTIBYTE_IS_FORMAT_SAFE 1
57 #endif
58 #define DO_MULTIBYTE (! MULTIBYTE_IS_FORMAT_SAFE)
59 
60 #if DO_MULTIBYTE
61 # include <wchar.h>
62   static const mbstate_t mbstate_zero;
63 #endif
64 
65 #include <limits.h>
66 #include <stddef.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <stdbool.h>
70 
71 #include "attribute.h"
72 #include <intprops.h>
73 
74 #ifdef COMPILE_WIDE
75 # include <endian.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
80 
81 # define MEMCPY(d, s, n) __wmemcpy (d, s, n)
82 # define STRLEN(s) __wcslen (s)
83 
84 #else
85 # define CHAR_T char
86 # define UCHAR_T unsigned char
87 # define L_(Str) Str
88 # define NLW(Sym) Sym
89 # define ABALTMON_1 _NL_ABALTMON_1
90 
91 # define MEMCPY(d, s, n) memcpy (d, s, n)
92 # define STRLEN(s) strlen (s)
93 
94 #endif
95 
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.
101 
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.  */
106 #define SHR(a, b)       \
107   (-1 >> 1 == -1        \
108    ? (a) >> (b)         \
109    : ((a) + ((a) < 0)) / (1 << (b)) - ((a) < 0))
110 
111 #define TM_YEAR_BASE 1900
112 
113 #ifndef __isleap
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))
118 #endif
119 
120 
121 #ifdef _LIBC
122 # define mktime_z(tz, tm) mktime (tm)
123 # define tzname __tzname
124 # define tzset __tzset
125 #endif
126 
127 #ifndef FPRINTFTIME
128 # define FPRINTFTIME 0
129 #endif
130 
131 #if FPRINTFTIME
132 # define STREAM_OR_CHAR_T FILE
133 # define STRFTIME_ARG(x) /* empty */
134 #else
135 # define STREAM_OR_CHAR_T CHAR_T
136 # define STRFTIME_ARG(x) x,
137 #endif
138 
139 #if FPRINTFTIME
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))
147 #else
148 # define memset_space(P, Len) (memset (P, ' ', Len), (P) += (Len))
149 # define memset_zero(P, Len) (memset (P, '0', Len), (P) += (Len))
150 #endif
151 
152 #if FPRINTFTIME
153 # define advance(P, N)
154 #else
155 # define advance(P, N) ((P) += (N))
156 #endif
157 
158 #define add(n, f) width_add (width, n, f)
159 #define width_add(width, n, f)                                                \
160   do                                                                          \
161     {                                                                         \
162       size_t _n = (n);                                                        \
163       size_t _w = pad == L_('-') || width < 0 ? 0 : width;                    \
164       size_t _incr = _n < _w ? _w : _n;                                       \
165       if (_incr >= maxsize - i)                                               \
166         {                                                                     \
167           errno = ERANGE;                                                     \
168           return 0;                                                           \
169         }                                                                     \
170       if (p)                                                                  \
171         {                                                                     \
172           if (_n < _w)                                                        \
173             {                                                                 \
174               size_t _delta = _w - _n;                                        \
175               if (pad == L_('0') || pad == L_('+'))                           \
176                 memset_zero (p, _delta);                                      \
177               else                                                            \
178                 memset_space (p, _delta);                                     \
179             }                                                                 \
180           f;                                                                  \
181           advance (p, _n);                                                    \
182         }                                                                     \
183       i += _incr;                                                             \
184     } while (0)
185 
186 #define add1(c) width_add1 (width, c)
187 #if FPRINTFTIME
188 # define width_add1(width, c) width_add (width, 1, fputc (c, p))
189 #else
190 # define width_add1(width, c) width_add (width, 1, *p = c)
191 #endif
192 
193 #define cpy(n, s) width_cpy (width, n, s)
194 #if FPRINTFTIME
195 # define width_cpy(width, n, s)                                               \
196     width_add (width, n,                                                      \
197      do                                                                       \
198        {                                                                      \
199          if (to_lowcase)                                                      \
200            fwrite_lowcase (p, (s), _n);                                       \
201          else if (to_uppcase)                                                 \
202            fwrite_uppcase (p, (s), _n);                                       \
203          else                                                                 \
204            {                                                                  \
205              /* Ignore the value of fwrite.  The caller can determine whether \
206                 an error occurred by inspecting ferror (P).  All known fwrite \
207                 implementations set the stream's error indicator when they    \
208                 fail due to ENOMEM etc., even though C11 and POSIX.1-2008 do  \
209                 not require this.  */                                         \
210              fwrite (s, _n, 1, p);                                            \
211            }                                                                  \
212        }                                                                      \
213      while (0)                                                                \
214     )
215 #else
216 # define width_cpy(width, n, s)                                               \
217     width_add (width, n,                                                      \
218          if (to_lowcase)                                                      \
219            memcpy_lowcase (p, (s), _n LOCALE_ARG);                            \
220          else if (to_uppcase)                                                 \
221            memcpy_uppcase (p, (s), _n LOCALE_ARG);                            \
222          else                                                                 \
223            MEMCPY ((void *) p, (void const *) (s), _n))
224 #endif
225 
226 #ifdef COMPILE_WIDE
227 # ifndef USE_IN_EXTENDED_LOCALE_MODEL
228 #  undef __mbsrtowcs_l
229 #  define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
230 # endif
231 # define widen(os, ws, l) \
232   {                                                                           \
233     mbstate_t __st;                                                           \
234     const char *__s = os;                                                     \
235     memset (&__st, '\0', sizeof (__st));                                      \
236     l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc);                            \
237     ws = (wchar_t *) alloca ((l + 1) * sizeof (wchar_t));                     \
238     (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc);                           \
239   }
240 #endif
241 
242 
243 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
244 /* We use this code also for the extended locale handling where the
245    function gets as an additional argument the locale which has to be
246    used.  To access the values we have to redefine the _NL_CURRENT
247    macro.  */
248 # define strftime               __strftime_l
249 # define wcsftime               __wcsftime_l
250 # undef _NL_CURRENT
251 # define _NL_CURRENT(category, item) \
252   (current->values[_NL_ITEM_INDEX (item)].string)
253 # define LOCALE_PARAM , locale_t loc
254 # define LOCALE_ARG , loc
255 # define HELPER_LOCALE_ARG  , current
256 #else
257 # define LOCALE_PARAM
258 # define LOCALE_ARG
259 # ifdef _LIBC
260 #  define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
261 # else
262 #  define HELPER_LOCALE_ARG
263 # endif
264 #endif
265 
266 #ifdef COMPILE_WIDE
267 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
268 #  define TOUPPER(Ch, L) __towupper_l (Ch, L)
269 #  define TOLOWER(Ch, L) __towlower_l (Ch, L)
270 # else
271 #  define TOUPPER(Ch, L) towupper (Ch)
272 #  define TOLOWER(Ch, L) towlower (Ch)
273 # endif
274 #else
275 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
276 #  define TOUPPER(Ch, L) __toupper_l (Ch, L)
277 #  define TOLOWER(Ch, L) __tolower_l (Ch, L)
278 # else
279 #  define TOUPPER(Ch, L) toupper (Ch)
280 #  define TOLOWER(Ch, L) tolower (Ch)
281 # endif
282 #endif
283 /* We don't use 'isdigit' here since the locale dependent
284    interpretation is not what we want here.  We only need to accept
285    the arabic digits in the ASCII range.  One day there is perhaps a
286    more reliable way to accept other sets of digits.  */
287 #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
288 
289 #if FPRINTFTIME
290 static void
fwrite_lowcase(FILE * fp,const CHAR_T * src,size_t len)291 fwrite_lowcase (FILE *fp, const CHAR_T *src, size_t len)
292 {
293   while (len-- > 0)
294     {
295       fputc (TOLOWER ((UCHAR_T) *src, loc), fp);
296       ++src;
297     }
298 }
299 
300 static void
fwrite_uppcase(FILE * fp,const CHAR_T * src,size_t len)301 fwrite_uppcase (FILE *fp, const CHAR_T *src, size_t len)
302 {
303   while (len-- > 0)
304     {
305       fputc (TOUPPER ((UCHAR_T) *src, loc), fp);
306       ++src;
307     }
308 }
309 #else
310 static CHAR_T *memcpy_lowcase (CHAR_T *dest, const CHAR_T *src,
311                                size_t len LOCALE_PARAM);
312 
313 static CHAR_T *
memcpy_lowcase(CHAR_T * dest,const CHAR_T * src,size_t len LOCALE_PARAM)314 memcpy_lowcase (CHAR_T *dest, const CHAR_T *src, size_t len LOCALE_PARAM)
315 {
316   while (len-- > 0)
317     dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
318   return dest;
319 }
320 
321 static CHAR_T *memcpy_uppcase (CHAR_T *dest, const CHAR_T *src,
322                                size_t len LOCALE_PARAM);
323 
324 static CHAR_T *
memcpy_uppcase(CHAR_T * dest,const CHAR_T * src,size_t len LOCALE_PARAM)325 memcpy_uppcase (CHAR_T *dest, const CHAR_T *src, size_t len LOCALE_PARAM)
326 {
327   while (len-- > 0)
328     dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
329   return dest;
330 }
331 #endif
332 
333 
334 #if ! HAVE_TM_GMTOFF
335 /* Yield the difference between *A and *B,
336    measured in seconds, ignoring leap seconds.  */
337 # define tm_diff ftime_tm_diff
338 static int tm_diff (const struct tm *, const struct tm *);
339 static int
tm_diff(const struct tm * a,const struct tm * b)340 tm_diff (const struct tm *a, const struct tm *b)
341 {
342   /* Compute intervening leap days correctly even if year is negative.
343      Take care to avoid int overflow in leap day calculations,
344      but it's OK to assume that A and B are close to each other.  */
345   int a4 = SHR (a->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (a->tm_year & 3);
346   int b4 = SHR (b->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (b->tm_year & 3);
347   int a100 = (a4 + (a4 < 0)) / 25 - (a4 < 0);
348   int b100 = (b4 + (b4 < 0)) / 25 - (b4 < 0);
349   int a400 = SHR (a100, 2);
350   int b400 = SHR (b100, 2);
351   int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
352   int years = a->tm_year - b->tm_year;
353   int days = (365 * years + intervening_leap_days
354               + (a->tm_yday - b->tm_yday));
355   return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
356                 + (a->tm_min - b->tm_min))
357           + (a->tm_sec - b->tm_sec));
358 }
359 #endif /* ! HAVE_TM_GMTOFF */
360 
361 
362 
363 /* The number of days from the first day of the first ISO week of this
364    year to the year day YDAY with week day WDAY.  ISO weeks start on
365    Monday; the first ISO week has the year's first Thursday.  YDAY may
366    be as small as YDAY_MINIMUM.  */
367 #define ISO_WEEK_START_WDAY 1 /* Monday */
368 #define ISO_WEEK1_WDAY 4 /* Thursday */
369 #define YDAY_MINIMUM (-366)
370 static int iso_week_days (int, int);
371 #if defined __GNUC__ || defined __clang__
372 __inline__
373 #endif
374 static int
iso_week_days(int yday,int wday)375 iso_week_days (int yday, int wday)
376 {
377   /* Add enough to the first operand of % to make it nonnegative.  */
378   int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
379   return (yday
380           - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
381           + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
382 }
383 
384 
385 /* When compiling this file, GNU applications can #define my_strftime
386    to a symbol (typically nstrftime) to get an extended strftime with
387    extra arguments TZ and NS.  */
388 
389 #if FPRINTFTIME
390 # undef my_strftime
391 # define my_strftime fprintftime
392 #endif
393 
394 #ifdef my_strftime
395 # define extra_args , tz, ns
396 # define extra_args_spec , timezone_t tz, int ns
397 #else
398 # if defined COMPILE_WIDE
399 #  define my_strftime wcsftime
400 #  define nl_get_alt_digit _nl_get_walt_digit
401 # else
402 #  define my_strftime strftime
403 #  define nl_get_alt_digit _nl_get_alt_digit
404 # endif
405 # define extra_args
406 # define extra_args_spec
407 /* We don't have this information in general.  */
408 # define tz 1
409 # define ns 0
410 #endif
411 
412 static size_t __strftime_internal (STREAM_OR_CHAR_T *, STRFTIME_ARG (size_t)
413                                    const CHAR_T *, const struct tm *,
414                                    bool, int, int, bool *
415                                    extra_args_spec LOCALE_PARAM);
416 
417 /* Write information from TP into S according to the format
418    string FORMAT, writing no more that MAXSIZE characters
419    (including the terminating '\0') and returning number of
420    characters written.  If S is NULL, nothing will be written
421    anywhere, so to determine how many characters would be
422    written, use NULL for S and (size_t) -1 for MAXSIZE.  */
423 size_t
my_strftime(STREAM_OR_CHAR_T * s,STRFTIME_ARG (size_t maxsize)const CHAR_T * format,const struct tm * tp extra_args_spec LOCALE_PARAM)424 my_strftime (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
425              const CHAR_T *format,
426              const struct tm *tp extra_args_spec LOCALE_PARAM)
427 {
428   bool tzset_called = false;
429   return __strftime_internal (s, STRFTIME_ARG (maxsize) format, tp, false,
430                               0, -1, &tzset_called extra_args LOCALE_ARG);
431 }
432 #if defined _LIBC && ! FPRINTFTIME
libc_hidden_def(my_strftime)433 libc_hidden_def (my_strftime)
434 #endif
435 
436 /* Just like my_strftime, above, but with more parameters.
437    UPCASE indicates that the result should be converted to upper case.
438    YR_SPEC and WIDTH specify the padding and width for the year.
439    *TZSET_CALLED indicates whether tzset has been called here.  */
440 static size_t
441 __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
442                      const CHAR_T *format,
443                      const struct tm *tp, bool upcase,
444                      int yr_spec, int width, bool *tzset_called
445                      extra_args_spec LOCALE_PARAM)
446 {
447 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
448   struct __locale_data *const current = loc->__locales[LC_TIME];
449 #endif
450 #if FPRINTFTIME
451   size_t maxsize = (size_t) -1;
452 #endif
453 
454   int saved_errno = errno;
455   int hour12 = tp->tm_hour;
456 #ifdef _NL_CURRENT
457   /* We cannot make the following values variables since we must delay
458      the evaluation of these values until really needed since some
459      expressions might not be valid in every situation.  The 'struct tm'
460      might be generated by a strptime() call that initialized
461      only a few elements.  Dereference the pointers only if the format
462      requires this.  Then it is ok to fail if the pointers are invalid.  */
463 # define a_wkday \
464   ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6                      \
465                      ? "?" : _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday)))
466 # define f_wkday \
467   ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6                      \
468                      ? "?" : _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday)))
469 # define a_month \
470   ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11                       \
471                      ? "?" : _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon)))
472 # define f_month \
473   ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11                       \
474                      ? "?" : _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon)))
475 # define a_altmonth \
476   ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11                       \
477                      ? "?" : _NL_CURRENT (LC_TIME, NLW(ABALTMON_1) + tp->tm_mon)))
478 # define f_altmonth \
479   ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11                       \
480                      ? "?" : _NL_CURRENT (LC_TIME, NLW(ALTMON_1) + tp->tm_mon)))
481 # define ampm \
482   ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11                    \
483                                  ? NLW(PM_STR) : NLW(AM_STR)))
484 
485 # define aw_len STRLEN (a_wkday)
486 # define am_len STRLEN (a_month)
487 # define aam_len STRLEN (a_altmonth)
488 # define ap_len STRLEN (ampm)
489 #endif
490 #if HAVE_TZNAME
491   char **tzname_vec = tzname;
492 #endif
493   const char *zone;
494   size_t i = 0;
495   STREAM_OR_CHAR_T *p = s;
496   const CHAR_T *f;
497 #if DO_MULTIBYTE && !defined COMPILE_WIDE
498   const char *format_end = NULL;
499 #endif
500 
501   zone = NULL;
502 #if HAVE_STRUCT_TM_TM_ZONE
503   /* The POSIX test suite assumes that setting
504      the environment variable TZ to a new value before calling strftime()
505      will influence the result (the %Z format) even if the information in
506      TP is computed with a totally different time zone.
507      This is bogus: though POSIX allows bad behavior like this,
508      POSIX does not require it.  Do the right thing instead.  */
509   zone = (const char *) tp->tm_zone;
510 #endif
511 #if HAVE_TZNAME
512   if (!tz)
513     {
514       if (! (zone && *zone))
515         zone = "GMT";
516     }
517   else
518     {
519 # if !HAVE_STRUCT_TM_TM_ZONE
520       /* Infer the zone name from *TZ instead of from TZNAME.  */
521       tzname_vec = tz->tzname_copy;
522 # endif
523     }
524   /* The tzset() call might have changed the value.  */
525   if (!(zone && *zone) && tp->tm_isdst >= 0)
526     {
527       /* POSIX.1 requires that local time zone information be used as
528          though strftime called tzset.  */
529 # ifndef my_strftime
530       if (!*tzset_called)
531         {
532           tzset ();
533           *tzset_called = true;
534         }
535 # endif
536       zone = tzname_vec[tp->tm_isdst != 0];
537     }
538 #endif
539   if (! zone)
540     zone = "";
541 
542   if (hour12 > 12)
543     hour12 -= 12;
544   else
545     if (hour12 == 0)
546       hour12 = 12;
547 
548   for (f = format; *f != '\0'; width = -1, f++)
549     {
550       int pad = 0;  /* Padding for number ('_', '-', '+', '0', or 0).  */
551       int modifier;             /* Field modifier ('E', 'O', or 0).  */
552       int digits = 0;           /* Max digits for numeric format.  */
553       int number_value;         /* Numeric value to be printed.  */
554       unsigned int u_number_value; /* (unsigned int) number_value.  */
555       bool negative_number;     /* The number is negative.  */
556       bool always_output_a_sign; /* +/- should always be output.  */
557       int tz_colon_mask;        /* Bitmask of where ':' should appear.  */
558       const CHAR_T *subfmt;
559       CHAR_T *bufp;
560       CHAR_T buf[1
561                  + 2 /* for the two colons in a %::z or %:::z time zone */
562                  + (sizeof (int) < sizeof (time_t)
563                     ? INT_STRLEN_BOUND (time_t)
564                     : INT_STRLEN_BOUND (int))];
565       bool to_lowcase = false;
566       bool to_uppcase = upcase;
567       size_t colons;
568       bool change_case = false;
569       int format_char;
570       int subwidth;
571 
572 #if DO_MULTIBYTE && !defined COMPILE_WIDE
573       switch (*f)
574         {
575         case L_('%'):
576           break;
577 
578         case L_('\b'): case L_('\t'): case L_('\n'):
579         case L_('\v'): case L_('\f'): case L_('\r'):
580         case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
581         case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
582         case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
583         case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
584         case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
585         case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
586         case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
587         case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
588         case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
589         case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
590         case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
591         case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
592         case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
593         case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
594         case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
595         case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
596         case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
597         case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
598         case L_('~'):
599           /* The C Standard requires these 98 characters (plus '%') to
600              be in the basic execution character set.  None of these
601              characters can start a multibyte sequence, so they need
602              not be analyzed further.  */
603           add1 (*f);
604           continue;
605 
606         default:
607           /* Copy this multibyte sequence until we reach its end, find
608              an error, or come back to the initial shift state.  */
609           {
610             mbstate_t mbstate = mbstate_zero;
611             size_t len = 0;
612             size_t fsize;
613 
614             if (! format_end)
615               format_end = f + strlen (f) + 1;
616             fsize = format_end - f;
617 
618             do
619               {
620                 size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
621 
622                 if (bytes == 0)
623                   break;
624 
625                 if (bytes == (size_t) -2)
626                   {
627                     len += strlen (f + len);
628                     break;
629                   }
630 
631                 if (bytes == (size_t) -1)
632                   {
633                     len++;
634                     break;
635                   }
636 
637                 len += bytes;
638               }
639             while (! mbsinit (&mbstate));
640 
641             cpy (len, f);
642             f += len - 1;
643             continue;
644           }
645         }
646 
647 #else /* ! DO_MULTIBYTE */
648 
649       /* Either multibyte encodings are not supported, they are
650          safe for formats, so any non-'%' byte can be copied through,
651          or this is the wide character version.  */
652       if (*f != L_('%'))
653         {
654           add1 (*f);
655           continue;
656         }
657 
658 #endif /* ! DO_MULTIBYTE */
659 
660       /* Check for flags that can modify a format.  */
661       while (1)
662         {
663           switch (*++f)
664             {
665               /* This influences the number formats.  */
666             case L_('_'):
667             case L_('-'):
668             case L_('+'):
669             case L_('0'):
670               pad = *f;
671               continue;
672 
673               /* This changes textual output.  */
674             case L_('^'):
675               to_uppcase = true;
676               continue;
677             case L_('#'):
678               change_case = true;
679               continue;
680 
681             default:
682               break;
683             }
684           break;
685         }
686 
687       if (ISDIGIT (*f))
688         {
689           width = 0;
690           do
691             {
692               if (INT_MULTIPLY_WRAPV (width, 10, &width)
693                   || INT_ADD_WRAPV (width, *f - L_('0'), &width))
694                 width = INT_MAX;
695               ++f;
696             }
697           while (ISDIGIT (*f));
698         }
699 
700       /* Check for modifiers.  */
701       switch (*f)
702         {
703         case L_('E'):
704         case L_('O'):
705           modifier = *f++;
706           break;
707 
708         default:
709           modifier = 0;
710           break;
711         }
712 
713       /* Now do the specified format.  */
714       format_char = *f;
715       switch (format_char)
716         {
717 #define DO_NUMBER(d, v) \
718           do                                                                  \
719             {                                                                 \
720               digits = d;                                                     \
721               number_value = v;                                               \
722               goto do_number;                                                 \
723             }                                                                 \
724           while (0)
725 #define DO_SIGNED_NUMBER(d, negative, v) \
726           DO_MAYBE_SIGNED_NUMBER (d, negative, v, do_signed_number)
727 #define DO_YEARISH(d, negative, v) \
728           DO_MAYBE_SIGNED_NUMBER (d, negative, v, do_yearish)
729 #define DO_MAYBE_SIGNED_NUMBER(d, negative, v, label) \
730           do                                                                  \
731             {                                                                 \
732               digits = d;                                                     \
733               negative_number = negative;                                     \
734               u_number_value = v;                                             \
735               goto label;                                                     \
736             }                                                                 \
737           while (0)
738 
739           /* The mask is not what you might think.
740              When the ordinal i'th bit is set, insert a colon
741              before the i'th digit of the time zone representation.  */
742 #define DO_TZ_OFFSET(d, mask, v) \
743           do                                                                  \
744             {                                                                 \
745               digits = d;                                                     \
746               tz_colon_mask = mask;                                           \
747               u_number_value = v;                                             \
748               goto do_tz_offset;                                              \
749             }                                                                 \
750           while (0)
751 #define DO_NUMBER_SPACEPAD(d, v) \
752           do                                                                  \
753             {                                                                 \
754               digits = d;                                                     \
755               number_value = v;                                               \
756               goto do_number_spacepad;                                        \
757             }                                                                 \
758           while (0)
759 
760         case L_('%'):
761           if (modifier != 0)
762             goto bad_format;
763           add1 (*f);
764           break;
765 
766         case L_('a'):
767           if (modifier != 0)
768             goto bad_format;
769           if (change_case)
770             {
771               to_uppcase = true;
772               to_lowcase = false;
773             }
774 #ifdef _NL_CURRENT
775           cpy (aw_len, a_wkday);
776           break;
777 #else
778           goto underlying_strftime;
779 #endif
780 
781         case 'A':
782           if (modifier != 0)
783             goto bad_format;
784           if (change_case)
785             {
786               to_uppcase = true;
787               to_lowcase = false;
788             }
789 #ifdef _NL_CURRENT
790           cpy (STRLEN (f_wkday), f_wkday);
791           break;
792 #else
793           goto underlying_strftime;
794 #endif
795 
796         case L_('b'):
797         case L_('h'):
798           if (change_case)
799             {
800               to_uppcase = true;
801               to_lowcase = false;
802             }
803           if (modifier == L_('E'))
804             goto bad_format;
805 #ifdef _NL_CURRENT
806           if (modifier == L_('O'))
807             cpy (aam_len, a_altmonth);
808           else
809             cpy (am_len, a_month);
810           break;
811 #else
812           goto underlying_strftime;
813 #endif
814 
815         case L_('B'):
816           if (modifier == L_('E'))
817             goto bad_format;
818           if (change_case)
819             {
820               to_uppcase = true;
821               to_lowcase = false;
822             }
823 #ifdef _NL_CURRENT
824           if (modifier == L_('O'))
825             cpy (STRLEN (f_altmonth), f_altmonth);
826           else
827             cpy (STRLEN (f_month), f_month);
828           break;
829 #else
830           goto underlying_strftime;
831 #endif
832 
833         case L_('c'):
834           if (modifier == L_('O'))
835             goto bad_format;
836 #ifdef _NL_CURRENT
837           if (! (modifier == L_('E')
838                  && (*(subfmt =
839                        (const CHAR_T *) _NL_CURRENT (LC_TIME,
840                                                      NLW(ERA_D_T_FMT)))
841                      != '\0')))
842             subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
843 #else
844           goto underlying_strftime;
845 #endif
846 
847         subformat:
848           subwidth = -1;
849         subformat_width:
850           {
851             size_t len = __strftime_internal (NULL, STRFTIME_ARG ((size_t) -1)
852                                               subfmt, tp, to_uppcase,
853                                               pad, subwidth, tzset_called
854                                               extra_args LOCALE_ARG);
855             add (len, __strftime_internal (p,
856                                            STRFTIME_ARG (maxsize - i)
857                                            subfmt, tp, to_uppcase,
858                                            pad, subwidth, tzset_called
859                                            extra_args LOCALE_ARG));
860           }
861           break;
862 
863 #if !(defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
864         underlying_strftime:
865           {
866             /* The relevant information is available only via the
867                underlying strftime implementation, so use that.  */
868             char ufmt[5];
869             char *u = ufmt;
870             char ubuf[1024]; /* enough for any single format in practice */
871             size_t len;
872             /* Make sure we're calling the actual underlying strftime.
873                In some cases, config.h contains something like
874                "#define strftime rpl_strftime".  */
875 # ifdef strftime
876 #  undef strftime
877             size_t strftime ();
878 # endif
879 
880             /* The space helps distinguish strftime failure from empty
881                output.  */
882             *u++ = ' ';
883             *u++ = '%';
884             if (modifier != 0)
885               *u++ = modifier;
886             *u++ = format_char;
887             *u = '\0';
888             len = strftime (ubuf, sizeof ubuf, ufmt, tp);
889             if (len != 0)
890               cpy (len - 1, ubuf + 1);
891           }
892           break;
893 #endif
894 
895         case L_('C'):
896           if (modifier == L_('E'))
897             {
898 #if HAVE_STRUCT_ERA_ENTRY
899               struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
900               if (era)
901                 {
902 # ifdef COMPILE_WIDE
903                   size_t len = __wcslen (era->era_wname);
904                   cpy (len, era->era_wname);
905 # else
906                   size_t len = strlen (era->era_name);
907                   cpy (len, era->era_name);
908 # endif
909                   break;
910                 }
911 #else
912               goto underlying_strftime;
913 #endif
914             }
915 
916           {
917             bool negative_year = tp->tm_year < - TM_YEAR_BASE;
918             bool zero_thru_1899 = !negative_year & (tp->tm_year < 0);
919             int century = ((tp->tm_year - 99 * zero_thru_1899) / 100
920                            + TM_YEAR_BASE / 100);
921             DO_YEARISH (2, negative_year, century);
922           }
923 
924         case L_('x'):
925           if (modifier == L_('O'))
926             goto bad_format;
927 #ifdef _NL_CURRENT
928           if (! (modifier == L_('E')
929                  && (*(subfmt =
930                        (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
931                      != L_('\0'))))
932             subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
933           goto subformat;
934 #else
935           goto underlying_strftime;
936 #endif
937         case L_('D'):
938           if (modifier != 0)
939             goto bad_format;
940           subfmt = L_("%m/%d/%y");
941           goto subformat;
942 
943         case L_('d'):
944           if (modifier == L_('E'))
945             goto bad_format;
946 
947           DO_NUMBER (2, tp->tm_mday);
948 
949         case L_('e'):
950           if (modifier == L_('E'))
951             goto bad_format;
952 
953           DO_NUMBER_SPACEPAD (2, tp->tm_mday);
954 
955           /* All numeric formats set DIGITS and NUMBER_VALUE (or U_NUMBER_VALUE)
956              and then jump to one of these labels.  */
957 
958         do_tz_offset:
959           always_output_a_sign = true;
960           goto do_number_body;
961 
962         do_yearish:
963           if (pad == 0)
964             pad = yr_spec;
965           always_output_a_sign
966             = (pad == L_('+')
967                && ((digits == 2 ? 99 : 9999) < u_number_value
968                    || digits < width));
969           goto do_maybe_signed_number;
970 
971         do_number_spacepad:
972           if (pad == 0)
973             pad = L_('_');
974 
975         do_number:
976           /* Format NUMBER_VALUE according to the MODIFIER flag.  */
977           negative_number = number_value < 0;
978           u_number_value = number_value;
979 
980         do_signed_number:
981           always_output_a_sign = false;
982 
983         do_maybe_signed_number:
984           tz_colon_mask = 0;
985 
986         do_number_body:
987           /* Format U_NUMBER_VALUE according to the MODIFIER flag.
988              NEGATIVE_NUMBER is nonzero if the original number was
989              negative; in this case it was converted directly to
990              unsigned int (i.e., modulo (UINT_MAX + 1)) without
991              negating it.  */
992           if (modifier == L_('O') && !negative_number)
993             {
994 #ifdef _NL_CURRENT
995               /* Get the locale specific alternate representation of
996                  the number.  If none exist NULL is returned.  */
997               const CHAR_T *cp = nl_get_alt_digit (u_number_value
998                                                    HELPER_LOCALE_ARG);
999 
1000               if (cp != NULL)
1001                 {
1002                   size_t digitlen = STRLEN (cp);
1003                   if (digitlen != 0)
1004                     {
1005                       cpy (digitlen, cp);
1006                       break;
1007                     }
1008                 }
1009 #else
1010               goto underlying_strftime;
1011 #endif
1012             }
1013 
1014           bufp = buf + sizeof (buf) / sizeof (buf[0]);
1015 
1016           if (negative_number)
1017             u_number_value = - u_number_value;
1018 
1019           do
1020             {
1021               if (tz_colon_mask & 1)
1022                 *--bufp = ':';
1023               tz_colon_mask >>= 1;
1024               *--bufp = u_number_value % 10 + L_('0');
1025               u_number_value /= 10;
1026             }
1027           while (u_number_value != 0 || tz_colon_mask != 0);
1028 
1029         do_number_sign_and_padding:
1030           if (pad == 0)
1031             pad = L_('0');
1032           if (width < 0)
1033             width = digits;
1034 
1035           {
1036             CHAR_T sign_char = (negative_number ? L_('-')
1037                                 : always_output_a_sign ? L_('+')
1038                                 : 0);
1039             int numlen = buf + sizeof buf / sizeof buf[0] - bufp;
1040             int shortage = width - !!sign_char - numlen;
1041             int padding = pad == L_('-') || shortage <= 0 ? 0 : shortage;
1042 
1043             if (sign_char)
1044               {
1045                 if (pad == L_('_'))
1046                   {
1047                     if (p)
1048                       memset_space (p, padding);
1049                     i += padding;
1050                     width -= padding;
1051                   }
1052                 width_add1 (0, sign_char);
1053                 width--;
1054               }
1055 
1056             cpy (numlen, bufp);
1057           }
1058           break;
1059 
1060         case L_('F'):
1061           if (modifier != 0)
1062             goto bad_format;
1063           if (pad == 0 && width < 0)
1064             {
1065               pad = L_('+');
1066               subwidth = 4;
1067             }
1068           else
1069             {
1070               subwidth = width - 6;
1071               if (subwidth < 0)
1072                 subwidth = 0;
1073             }
1074           subfmt = L_("%Y-%m-%d");
1075           goto subformat_width;
1076 
1077         case L_('H'):
1078           if (modifier == L_('E'))
1079             goto bad_format;
1080 
1081           DO_NUMBER (2, tp->tm_hour);
1082 
1083         case L_('I'):
1084           if (modifier == L_('E'))
1085             goto bad_format;
1086 
1087           DO_NUMBER (2, hour12);
1088 
1089         case L_('k'):           /* GNU extension.  */
1090           if (modifier == L_('E'))
1091             goto bad_format;
1092 
1093           DO_NUMBER_SPACEPAD (2, tp->tm_hour);
1094 
1095         case L_('l'):           /* GNU extension.  */
1096           if (modifier == L_('E'))
1097             goto bad_format;
1098 
1099           DO_NUMBER_SPACEPAD (2, hour12);
1100 
1101         case L_('j'):
1102           if (modifier == L_('E'))
1103             goto bad_format;
1104 
1105           DO_SIGNED_NUMBER (3, tp->tm_yday < -1, tp->tm_yday + 1U);
1106 
1107         case L_('M'):
1108           if (modifier == L_('E'))
1109             goto bad_format;
1110 
1111           DO_NUMBER (2, tp->tm_min);
1112 
1113         case L_('m'):
1114           if (modifier == L_('E'))
1115             goto bad_format;
1116 
1117           DO_SIGNED_NUMBER (2, tp->tm_mon < -1, tp->tm_mon + 1U);
1118 
1119 #ifndef _LIBC
1120         case L_('N'):           /* GNU extension.  */
1121           if (modifier == L_('E'))
1122             goto bad_format;
1123           {
1124             int n = ns, ns_digits = 9;
1125             if (width <= 0)
1126               width = ns_digits;
1127             int ndigs = ns_digits;
1128             while (width < ndigs || (1 < ndigs && n % 10 == 0))
1129               ndigs--, n /= 10;
1130             for (int j = ndigs; 0 < j; j--)
1131               buf[j - 1] = n % 10 + L_('0'), n /= 10;
1132             if (!pad)
1133               pad = L_('0');
1134             width_cpy (0, ndigs, buf);
1135             width_add (width - ndigs, 0, (void) 0);
1136           }
1137           break;
1138 #endif
1139 
1140         case L_('n'):
1141           add1 (L_('\n'));
1142           break;
1143 
1144         case L_('P'):
1145           to_lowcase = true;
1146 #ifndef _NL_CURRENT
1147           format_char = L_('p');
1148 #endif
1149           FALLTHROUGH;
1150         case L_('p'):
1151           if (change_case)
1152             {
1153               to_uppcase = false;
1154               to_lowcase = true;
1155             }
1156 #ifdef _NL_CURRENT
1157           cpy (ap_len, ampm);
1158           break;
1159 #else
1160           goto underlying_strftime;
1161 #endif
1162 
1163         case L_('q'):           /* GNU extension.  */
1164           DO_SIGNED_NUMBER (1, false, ((tp->tm_mon * 11) >> 5) + 1);
1165           break;
1166 
1167         case L_('R'):
1168           subfmt = L_("%H:%M");
1169           goto subformat;
1170 
1171         case L_('r'):
1172 #ifdef _NL_CURRENT
1173           if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
1174                                                        NLW(T_FMT_AMPM)))
1175               == L_('\0'))
1176             subfmt = L_("%I:%M:%S %p");
1177           goto subformat;
1178 #else
1179           goto underlying_strftime;
1180 #endif
1181 
1182         case L_('S'):
1183           if (modifier == L_('E'))
1184             goto bad_format;
1185 
1186           DO_NUMBER (2, tp->tm_sec);
1187 
1188         case L_('s'):           /* GNU extension.  */
1189           {
1190             struct tm ltm;
1191             time_t t;
1192 
1193             ltm = *tp;
1194             ltm.tm_yday = -1;
1195             t = mktime_z (tz, &ltm);
1196             if (ltm.tm_yday < 0)
1197               {
1198                 errno = EOVERFLOW;
1199                 return 0;
1200               }
1201 
1202             /* Generate string value for T using time_t arithmetic;
1203                this works even if sizeof (long) < sizeof (time_t).  */
1204 
1205             bufp = buf + sizeof (buf) / sizeof (buf[0]);
1206             negative_number = t < 0;
1207 
1208             do
1209               {
1210                 int d = t % 10;
1211                 t /= 10;
1212                 *--bufp = (negative_number ? -d : d) + L_('0');
1213               }
1214             while (t != 0);
1215 
1216             digits = 1;
1217             always_output_a_sign = false;
1218             goto do_number_sign_and_padding;
1219           }
1220 
1221         case L_('X'):
1222           if (modifier == L_('O'))
1223             goto bad_format;
1224 #ifdef _NL_CURRENT
1225           if (! (modifier == L_('E')
1226                  && (*(subfmt =
1227                        (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
1228                      != L_('\0'))))
1229             subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
1230           goto subformat;
1231 #else
1232           goto underlying_strftime;
1233 #endif
1234         case L_('T'):
1235           subfmt = L_("%H:%M:%S");
1236           goto subformat;
1237 
1238         case L_('t'):
1239           add1 (L_('\t'));
1240           break;
1241 
1242         case L_('u'):
1243           DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1244 
1245         case L_('U'):
1246           if (modifier == L_('E'))
1247             goto bad_format;
1248 
1249           DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1250 
1251         case L_('V'):
1252         case L_('g'):
1253         case L_('G'):
1254           if (modifier == L_('E'))
1255             goto bad_format;
1256           {
1257             /* YEAR is a leap year if and only if (tp->tm_year + TM_YEAR_BASE)
1258                is a leap year, except that YEAR and YEAR - 1 both work
1259                correctly even when (tp->tm_year + TM_YEAR_BASE) would
1260                overflow.  */
1261             int year = (tp->tm_year
1262                         + (tp->tm_year < 0
1263                            ? TM_YEAR_BASE % 400
1264                            : TM_YEAR_BASE % 400 - 400));
1265             int year_adjust = 0;
1266             int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1267 
1268             if (days < 0)
1269               {
1270                 /* This ISO week belongs to the previous year.  */
1271                 year_adjust = -1;
1272                 days = iso_week_days (tp->tm_yday + (365 + __isleap (year - 1)),
1273                                       tp->tm_wday);
1274               }
1275             else
1276               {
1277                 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1278                                        tp->tm_wday);
1279                 if (0 <= d)
1280                   {
1281                     /* This ISO week belongs to the next year.  */
1282                     year_adjust = 1;
1283                     days = d;
1284                   }
1285               }
1286 
1287             switch (*f)
1288               {
1289               case L_('g'):
1290                 {
1291                   int yy = (tp->tm_year % 100 + year_adjust) % 100;
1292                   DO_YEARISH (2, false,
1293                               (0 <= yy
1294                                ? yy
1295                                : tp->tm_year < -TM_YEAR_BASE - year_adjust
1296                                ? -yy
1297                                : yy + 100));
1298                 }
1299 
1300               case L_('G'):
1301                 DO_YEARISH (4, tp->tm_year < -TM_YEAR_BASE - year_adjust,
1302                             (tp->tm_year + (unsigned int) TM_YEAR_BASE
1303                              + year_adjust));
1304 
1305               default:
1306                 DO_NUMBER (2, days / 7 + 1);
1307               }
1308           }
1309 
1310         case L_('W'):
1311           if (modifier == L_('E'))
1312             goto bad_format;
1313 
1314           DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1315 
1316         case L_('w'):
1317           if (modifier == L_('E'))
1318             goto bad_format;
1319 
1320           DO_NUMBER (1, tp->tm_wday);
1321 
1322         case L_('Y'):
1323           if (modifier == L_('E'))
1324             {
1325 #if HAVE_STRUCT_ERA_ENTRY
1326               struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1327               if (era)
1328                 {
1329 # ifdef COMPILE_WIDE
1330                   subfmt = era->era_wformat;
1331 # else
1332                   subfmt = era->era_format;
1333 # endif
1334                   if (pad == 0)
1335                     pad = yr_spec;
1336                   goto subformat;
1337                 }
1338 #else
1339               goto underlying_strftime;
1340 #endif
1341             }
1342           if (modifier == L_('O'))
1343             goto bad_format;
1344 
1345           DO_YEARISH (4, tp->tm_year < -TM_YEAR_BASE,
1346                       tp->tm_year + (unsigned int) TM_YEAR_BASE);
1347 
1348         case L_('y'):
1349           if (modifier == L_('E'))
1350             {
1351 #if HAVE_STRUCT_ERA_ENTRY
1352               struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1353               if (era)
1354                 {
1355                   int delta = tp->tm_year - era->start_date[0];
1356                   if (pad == 0)
1357                     pad = yr_spec;
1358                   DO_NUMBER (2, (era->offset
1359                                  + delta * era->absolute_direction));
1360                 }
1361 #else
1362               goto underlying_strftime;
1363 #endif
1364             }
1365 
1366           {
1367             int yy = tp->tm_year % 100;
1368             if (yy < 0)
1369               yy = tp->tm_year < - TM_YEAR_BASE ? -yy : yy + 100;
1370             DO_YEARISH (2, false, yy);
1371           }
1372 
1373         case L_('Z'):
1374           if (change_case)
1375             {
1376               to_uppcase = false;
1377               to_lowcase = true;
1378             }
1379 
1380 #ifdef COMPILE_WIDE
1381           {
1382             /* The zone string is always given in multibyte form.  We have
1383                to transform it first.  */
1384             wchar_t *wczone;
1385             size_t len;
1386             widen (zone, wczone, len);
1387             cpy (len, wczone);
1388           }
1389 #else
1390           cpy (strlen (zone), zone);
1391 #endif
1392           break;
1393 
1394         case L_(':'):
1395           /* :, ::, and ::: are valid only just before 'z'.
1396              :::: etc. are rejected later.  */
1397           for (colons = 1; f[colons] == L_(':'); colons++)
1398             continue;
1399           if (f[colons] != L_('z'))
1400             goto bad_format;
1401           f += colons;
1402           goto do_z_conversion;
1403 
1404         case L_('z'):
1405           colons = 0;
1406 
1407         do_z_conversion:
1408           if (tp->tm_isdst < 0)
1409             break;
1410 
1411           {
1412             int diff;
1413             int hour_diff;
1414             int min_diff;
1415             int sec_diff;
1416 #if HAVE_TM_GMTOFF
1417             diff = tp->tm_gmtoff;
1418 #else
1419             if (!tz)
1420               diff = 0;
1421             else
1422               {
1423                 struct tm gtm;
1424                 struct tm ltm;
1425                 time_t lt;
1426 
1427                 /* POSIX.1 requires that local time zone information be used as
1428                    though strftime called tzset.  */
1429 # ifndef my_strftime
1430                 if (!*tzset_called)
1431                   {
1432                     tzset ();
1433                     *tzset_called = true;
1434                   }
1435 # endif
1436 
1437                 ltm = *tp;
1438                 ltm.tm_wday = -1;
1439                 lt = mktime_z (tz, &ltm);
1440                 if (ltm.tm_wday < 0 || ! localtime_rz (0, &lt, &gtm))
1441                   break;
1442                 diff = tm_diff (&ltm, &gtm);
1443               }
1444 #endif
1445 
1446             negative_number = diff < 0 || (diff == 0 && *zone == '-');
1447             hour_diff = diff / 60 / 60;
1448             min_diff = diff / 60 % 60;
1449             sec_diff = diff % 60;
1450 
1451             switch (colons)
1452               {
1453               case 0: /* +hhmm */
1454                 DO_TZ_OFFSET (5, 0, hour_diff * 100 + min_diff);
1455 
1456               case 1: tz_hh_mm: /* +hh:mm */
1457                 DO_TZ_OFFSET (6, 04, hour_diff * 100 + min_diff);
1458 
1459               case 2: tz_hh_mm_ss: /* +hh:mm:ss */
1460                 DO_TZ_OFFSET (9, 024,
1461                               hour_diff * 10000 + min_diff * 100 + sec_diff);
1462 
1463               case 3: /* +hh if possible, else +hh:mm, else +hh:mm:ss */
1464                 if (sec_diff != 0)
1465                   goto tz_hh_mm_ss;
1466                 if (min_diff != 0)
1467                   goto tz_hh_mm;
1468                 DO_TZ_OFFSET (3, 0, hour_diff);
1469 
1470               default:
1471                 goto bad_format;
1472               }
1473           }
1474 
1475         case L_('\0'):          /* GNU extension: % at end of format.  */
1476             --f;
1477             FALLTHROUGH;
1478         default:
1479           /* Unknown format; output the format, including the '%',
1480              since this is most likely the right thing to do if a
1481              multibyte string has been misparsed.  */
1482         bad_format:
1483           {
1484             int flen;
1485             for (flen = 1; f[1 - flen] != L_('%'); flen++)
1486               continue;
1487             cpy (flen, &f[1 - flen]);
1488           }
1489           break;
1490         }
1491     }
1492 
1493 #if ! FPRINTFTIME
1494   if (p && maxsize != 0)
1495     *p = L_('\0');
1496 #endif
1497 
1498   errno = saved_errno;
1499   return i;
1500 }
1501