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