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