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