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