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