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