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