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