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