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