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