packaging: Add support for configure-dumper
[platform/upstream/glibc.git] / time / strftime_l.c
1 /* Copyright (C) 2002-2023 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 *
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 *
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
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
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
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
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
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