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