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