1/* Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
2                 2001, 2002, 2003, 2004, 2005, 2006, 2007
3                 Free Software Foundation, Inc.
4
5   NOTE: The canonical source of this file is maintained with gnulib.
6   Bugs can be reported to bug-gnulib@gnu.org.
7
8   This file is part of the GNU Emacs.
9
10   This program is free software; you can redistribute it and/or
11   modify it under the terms of the GNU General Public License
12   as published by the Free Software Foundation; either version 2, or
13   (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18   General Public License for more details.
19
20   You should have received a copy of the GNU General Public
21   License along with the GNU C Library; see the file COPYING.  If not,
22   write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23   Boston, MA 02110-1301, USA.  */
24
25#ifdef HAVE_CONFIG_H
26# include <config.h>
27#endif
28
29#ifdef _LIBC
30# define HAVE_LIMITS_H 1
31# define HAVE_MBLEN 1
32# define HAVE_MBRLEN 1
33# define HAVE_STRUCT_ERA_ENTRY 1
34# define HAVE_TM_GMTOFF 1
35# define HAVE_TM_ZONE 1
36# define HAVE_TZNAME 1
37# define HAVE_TZSET 1
38# define MULTIBYTE_IS_FORMAT_SAFE 1
39# define STDC_HEADERS 1
40# include "../locale/localeinfo.h"
41#endif
42
43#include <ctype.h>
44#include <sys/types.h>		/* Some systems define `time_t' here.  */
45
46#ifdef TIME_WITH_SYS_TIME
47# include <sys/time.h>
48# include <time.h>
49#else
50# ifdef HAVE_SYS_TIME_H
51#  include <sys/time.h>
52# else
53#  include <time.h>
54# endif
55#endif
56#if HAVE_TZNAME
57#ifndef USE_CRT_DLL
58extern char *tzname[];
59#endif
60#endif
61
62/* Do multibyte processing if multibytes are supported, unless
63   multibyte sequences are safe in formats.  Multibyte sequences are
64   safe if they cannot contain byte sequences that look like format
65   conversion specifications.  The GNU C Library uses UTF8 multibyte
66   encoding, which is safe for formats, but strftime.c can be used
67   with other C libraries that use unsafe encodings.  */
68#define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
69
70#if DO_MULTIBYTE
71# if HAVE_MBRLEN
72#  include <wchar.h>
73#  ifdef HAVE_SYS__MBSTATE_T_H       /* previously tested __hpux */
74#   include <sys/_mbstate_t.h>
75#  endif
76#  if !defined (mbsinit) && !defined (HAVE_MBSINIT)
77#   define mbsinit(ps) 1
78#  endif /* !defined (mbsinit) && !defined (HAVE_MBSINIT) */
79# else
80   /* Simulate mbrlen with mblen as best we can.  */
81#  define mbstate_t int
82#  define mbrlen(s, n, ps) mblen (s, n)
83#  define mbsinit(ps) (*(ps) == 0)
84# endif
85  static const mbstate_t mbstate_zero;
86#endif
87
88#ifdef HAVE_LIMITS_H
89# include <limits.h>
90#endif
91
92#ifdef STDC_HEADERS
93# include <stddef.h>
94# include <stdlib.h>
95# include <string.h>
96#else
97# ifndef HAVE_MEMCPY
98#  define memcpy(d, s, n) bcopy ((s), (d), (n))
99# endif
100#endif
101
102#ifdef COMPILE_WIDE
103# include <endian.h>
104# define CHAR_T wchar_t
105# define UCHAR_T unsigned int
106# define L_(Str) L##Str
107# define NLW(Sym) _NL_W##Sym
108
109# define MEMCPY(d, s, n) __wmemcpy (d, s, n)
110# define STRLEN(s) __wcslen (s)
111
112#else
113# define CHAR_T char
114# define UCHAR_T unsigned char
115# define L_(Str) Str
116# define NLW(Sym) Sym
117
118# if !defined STDC_HEADERS && !defined HAVE_MEMCPY
119#  define MEMCPY(d, s, n) bcopy ((s), (d), (n))
120# else
121#  define MEMCPY(d, s, n) memcpy ((d), (s), (n))
122# endif
123# define STRLEN(s) strlen (s)
124
125# ifdef _LIBC
126#  define MEMPCPY(d, s, n) __mempcpy (d, s, n)
127# else
128#  ifndef HAVE_MEMPCPY
129#   define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
130#  endif
131# endif
132#endif
133
134#ifndef __P
135# if defined __GNUC__ || (defined __STDC__ && __STDC__) || defined (PROTOTYPES)
136#  define __P(args) args
137# else
138#  define __P(args) ()
139# endif  /* GCC.  */
140#endif  /* Not __P.  */
141
142#ifndef PTR
143# ifdef __STDC__
144#  define PTR void *
145# else
146#  define PTR char *
147# endif
148#endif
149
150#ifndef CHAR_BIT
151# define CHAR_BIT 8
152#endif
153
154#ifndef NULL
155# define NULL 0
156#endif
157
158#define TYPE_SIGNED(t) ((t) -1 < 0)
159
160/* Bound on length of the string representing an integer value of type t.
161   Subtract one for the sign bit if t is signed;
162   302 / 1000 is log10 (2) rounded up;
163   add one for integer division truncation;
164   add one more for a minus sign if t is signed.  */
165#define INT_STRLEN_BOUND(t) \
166 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t))
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
203static struct tm *my_strftime_localtime_r __P ((const time_t *, struct tm *));
204static struct tm *
205my_strftime_localtime_r (t, tp)
206     const time_t *t;
207     struct tm *tp;
208{
209  struct tm *l = localtime (t);
210  if (! l)
211    return 0;
212  *tp = *l;
213  return tp;
214}
215# endif /* ! HAVE_TM_GMTOFF */
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 = (wchar_t *) alloca ((l + 1) * sizeof (wchar_t));		      \
314    (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc);			      \
315  }
316#endif
317
318
319#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
320/* We use this code also for the extended locale handling where the
321   function gets as an additional argument the locale which has to be
322   used.  To access the values we have to redefine the _NL_CURRENT
323   macro.  */
324# define strftime		__strftime_l
325# define wcsftime		__wcsftime_l
326# undef _NL_CURRENT
327# define _NL_CURRENT(category, item) \
328  (current->values[_NL_ITEM_INDEX (item)].string)
329# define LOCALE_PARAM , loc
330# define LOCALE_ARG , loc
331# define LOCALE_PARAM_DECL  __locale_t loc;
332# define LOCALE_PARAM_PROTO , __locale_t loc
333# define HELPER_LOCALE_ARG  , current
334#else
335# define LOCALE_PARAM
336# define LOCALE_PARAM_PROTO
337# define LOCALE_ARG
338# define LOCALE_PARAM_DECL
339# ifdef _LIBC
340#  define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
341# else
342#  define HELPER_LOCALE_ARG
343# endif
344#endif
345
346#ifdef COMPILE_WIDE
347# ifdef USE_IN_EXTENDED_LOCALE_MODEL
348#  define TOUPPER(Ch, L) __towupper_l (Ch, L)
349#  define TOLOWER(Ch, L) __towlower_l (Ch, L)
350# else
351#  define TOUPPER(Ch, L) towupper (Ch)
352#  define TOLOWER(Ch, L) towlower (Ch)
353# endif
354#else
355# ifdef _LIBC
356#  ifdef USE_IN_EXTENDED_LOCALE_MODEL
357#   define TOUPPER(Ch, L) __toupper_l (Ch, L)
358#   define TOLOWER(Ch, L) __tolower_l (Ch, L)
359#  else
360#   define TOUPPER(Ch, L) toupper (Ch)
361#   define TOLOWER(Ch, L) tolower (Ch)
362#  endif
363# else
364#  define TOUPPER(Ch, L) (islower (Ch) ? toupper (Ch) : (Ch))
365#  define TOLOWER(Ch, L) (isupper (Ch) ? tolower (Ch) : (Ch))
366# endif
367#endif
368/* We don't use `isdigit' here since the locale dependent
369   interpretation is not what we want here.  We only need to accept
370   the arabic digits in the ASCII range.  One day there is perhaps a
371   more reliable way to accept other sets of digits.  */
372#define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
373
374static CHAR_T *memcpy_lowcase __P ((CHAR_T *dest, const CHAR_T *src,
375				    size_t len LOCALE_PARAM_PROTO));
376
377static CHAR_T *
378memcpy_lowcase (dest, src, len LOCALE_PARAM)
379     CHAR_T *dest;
380     const CHAR_T *src;
381     size_t len;
382     LOCALE_PARAM_DECL
383{
384  while (len-- > 0)
385    dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
386  return dest;
387}
388
389static CHAR_T *memcpy_uppcase __P ((CHAR_T *dest, const CHAR_T *src,
390				    size_t len LOCALE_PARAM_PROTO));
391
392static CHAR_T *
393memcpy_uppcase (dest, src, len LOCALE_PARAM)
394     CHAR_T *dest;
395     const CHAR_T *src;
396     size_t len;
397     LOCALE_PARAM_DECL
398{
399  while (len-- > 0)
400    dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
401  return dest;
402}
403
404
405#if ! HAVE_TM_GMTOFF
406/* Yield the difference between *A and *B,
407   measured in seconds, ignoring leap seconds.  */
408# define tm_diff ftime_tm_diff
409static int tm_diff __P ((const struct tm *, const struct tm *));
410static int
411tm_diff (a, b)
412     const struct tm *a;
413     const struct tm *b;
414{
415  /* Compute intervening leap days correctly even if year is negative.
416     Take care to avoid int overflow in leap day calculations,
417     but it's OK to assume that A and B are close to each other.  */
418  int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
419  int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
420  int a100 = a4 / 25 - (a4 % 25 < 0);
421  int b100 = b4 / 25 - (b4 % 25 < 0);
422  int a400 = a100 >> 2;
423  int b400 = b100 >> 2;
424  int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
425  int years = a->tm_year - b->tm_year;
426  int days = (365 * years + intervening_leap_days
427	      + (a->tm_yday - b->tm_yday));
428  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
429		+ (a->tm_min - b->tm_min))
430	  + (a->tm_sec - b->tm_sec));
431}
432#endif /* ! HAVE_TM_GMTOFF */
433
434
435
436/* The number of days from the first day of the first ISO week of this
437   year to the year day YDAY with week day WDAY.  ISO weeks start on
438   Monday; the first ISO week has the year's first Thursday.  YDAY may
439   be as small as YDAY_MINIMUM.  */
440#define ISO_WEEK_START_WDAY 1 /* Monday */
441#define ISO_WEEK1_WDAY 4 /* Thursday */
442#define YDAY_MINIMUM (-366)
443static int iso_week_days __P ((int, int));
444#ifdef __GNUC__
445__inline__
446#endif
447static int
448iso_week_days (yday, wday)
449     int yday;
450     int wday;
451{
452  /* Add enough to the first operand of % to make it nonnegative.  */
453  int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
454  return (yday
455	  - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
456	  + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
457}
458
459
460#if !(defined _NL_CURRENT || HAVE_STRFTIME)
461static CHAR_T const weekday_name[][10] =
462  {
463    L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
464    L_("Thursday"), L_("Friday"), L_("Saturday")
465  };
466static CHAR_T const month_name[][10] =
467  {
468    L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
469    L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
470    L_("November"), L_("December")
471  };
472#endif
473
474
475/* When compiling this file, GNU applications can #define my_strftime
476   to a symbol (typically nstrftime) to get an extended strftime with
477   extra arguments UT and NS.  */
478
479#ifdef my_strftime
480# define extra_args , ut, ns
481# define extra_args_spec int ut; int ns;
482# define extra_args_spec_iso , int ut, int ns
483#else
484# ifdef COMPILE_WIDE
485#  define my_strftime wcsftime
486#  define nl_get_alt_digit _nl_get_walt_digit
487# else
488#  define my_strftime strftime
489#  define nl_get_alt_digit _nl_get_alt_digit
490# endif
491# define extra_args
492# define extra_args_spec
493# define extra_args_spec_iso
494/* We don't have this information in general.  */
495# define ut 0
496# define ns 0
497#endif
498
499#if !defined _LIBC && !defined(WINDOWSNT) && 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 * extra_args_spec_iso));
504  size_t
505  my_strftime (s, maxsize, format, tp extra_args)
506      CHAR_T *s;
507      size_t maxsize;
508      const CHAR_T *format;
509      const struct tm *tp;
510      extra_args_spec
511  {
512    struct tm tmcopy;
513    tmcopy = *tp;
514    return _strftime_copytm (s, maxsize, format, &tmcopy extra_args);
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 extra_args LOCALE_PARAM)
529      CHAR_T *s;
530      size_t maxsize;
531      const CHAR_T *format;
532      const struct tm *tp;
533      extra_args_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 be 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 extra_args LOCALE_ARG);
882	    add (len, my_strftime (p, maxsize - i, subfmt,
883				   tp extra_args 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#ifdef STRFTIME_NO_POSIX2
912	    /* Some system libraries do not support the POSIX.2 extensions.
913	       In those cases, convert %h to %b, and strip modifiers.  */
914	    modifier = 0;
915	    if (format_char == 'h')
916	      format_char = 'b';
917#endif
918            *u++ = '%';
919            if (modifier != 0)
920              *u++ = modifier;
921            *u++ = format_char;
922            *u = '\0';
923            len = strftime (ubuf, sizeof ubuf, ufmt, tp);
924            if (len == 0 && ubuf[0] != '\0')
925              return 0;
926            cpy (len, ubuf);
927          }
928          break;
929#endif
930
931        case L_('C'):
932          if (modifier == L_('O'))
933            goto bad_format;
934          if (modifier == L_('E'))
935            {
936#if HAVE_STRUCT_ERA_ENTRY
937	      struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
938	      if (era)
939		{
940# ifdef COMPILE_WIDE
941		  size_t len = __wcslen (era->era_wname);
942		  cpy (len, era->era_wname);
943# else
944		  size_t len = strlen (era->era_name);
945		  cpy (len, era->era_name);
946# endif
947		  break;
948		}
949#else
950# if HAVE_STRFTIME
951	      goto underlying_strftime;
952# endif
953#endif
954	    }
955
956	  {
957	    int year = tp->tm_year + TM_YEAR_BASE;
958	    DO_NUMBER (1, year / 100 - (year % 100 < 0));
959	  }
960
961	case L_('x'):
962	  if (modifier == L_('O'))
963	    goto bad_format;
964#ifdef _NL_CURRENT
965	  if (! (modifier == L_('E')
966		 && (*(subfmt =
967		       (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
968		     != L_('\0'))))
969	    subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
970	  goto subformat;
971#else
972# if HAVE_STRFTIME
973	  goto underlying_strftime;
974# else
975	  /* Fall through.  */
976# endif
977#endif
978	case L_('D'):
979	  if (modifier != 0)
980	    goto bad_format;
981	  subfmt = L_("%m/%d/%y");
982	  goto subformat;
983
984	case L_('d'):
985	  if (modifier == L_('E'))
986	    goto bad_format;
987
988	  DO_NUMBER (2, tp->tm_mday);
989
990	case L_('e'):
991	  if (modifier == L_('E'))
992	    goto bad_format;
993
994	  DO_NUMBER_SPACEPAD (2, tp->tm_mday);
995
996	  /* All numeric formats set DIGITS and NUMBER_VALUE and then
997	     jump to one of these two labels.  */
998
999	do_number_spacepad:
1000	  /* Force `_' flag unless overridden by `0' or `-' flag.  */
1001	  if (pad != L_('0') && pad != L_('-'))
1002	    pad = L_('_');
1003
1004	do_number:
1005	  /* Format the number according to the MODIFIER flag.  */
1006
1007	  if (modifier == L_('O') && 0 <= number_value)
1008	    {
1009#ifdef _NL_CURRENT
1010	      /* Get the locale specific alternate representation of
1011		 the number NUMBER_VALUE.  If none exist NULL is returned.  */
1012	      const CHAR_T *cp = nl_get_alt_digit (number_value
1013						   HELPER_LOCALE_ARG);
1014
1015	      if (cp != NULL)
1016		{
1017		  size_t digitlen = STRLEN (cp);
1018		  if (digitlen != 0)
1019		    {
1020		      cpy (digitlen, cp);
1021		      break;
1022		    }
1023		}
1024#else
1025# if HAVE_STRFTIME
1026	      goto underlying_strftime;
1027# endif
1028#endif
1029	    }
1030	  {
1031	    unsigned int u = number_value;
1032
1033	    bufp = buf + sizeof (buf) / sizeof (buf[0]);
1034	    negative_number = number_value < 0;
1035
1036	    if (negative_number)
1037	      u = -u;
1038
1039	    do
1040	      *--bufp = u % 10 + L_('0');
1041	    while ((u /= 10) != 0);
1042  	  }
1043
1044	do_number_sign_and_padding:
1045	  if (negative_number)
1046	    *--bufp = L_('-');
1047
1048	  if (pad != L_('-'))
1049	    {
1050	      int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
1051				      - bufp);
1052
1053	      if (padding > 0)
1054		{
1055		  if (pad == L_('_'))
1056		    {
1057		      if ((size_t) padding >= maxsize - i)
1058			return 0;
1059
1060		      if (p)
1061			memset_space (p, padding);
1062		      i += padding;
1063		      width = width > padding ? width - padding : 0;
1064		    }
1065		  else
1066		    {
1067		      if ((size_t) digits >= maxsize - i)
1068			return 0;
1069
1070		      if (negative_number)
1071			{
1072			  ++bufp;
1073
1074			  if (p)
1075			    *p++ = L_('-');
1076			  ++i;
1077			}
1078
1079		      if (p)
1080			memset_zero (p, padding);
1081		      i += padding;
1082		      width = 0;
1083		    }
1084		}
1085	    }
1086
1087	  cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);
1088	  break;
1089
1090	case L_('F'):
1091	  if (modifier != 0)
1092	    goto bad_format;
1093	  subfmt = L_("%Y-%m-%d");
1094	  goto subformat;
1095
1096	case L_('H'):
1097	  if (modifier == L_('E'))
1098	    goto bad_format;
1099
1100	  DO_NUMBER (2, tp->tm_hour);
1101
1102	case L_('I'):
1103	  if (modifier == L_('E'))
1104	    goto bad_format;
1105
1106	  DO_NUMBER (2, hour12);
1107
1108	case L_('k'):		/* GNU extension.  */
1109	  if (modifier == L_('E'))
1110	    goto bad_format;
1111
1112	  DO_NUMBER_SPACEPAD (2, tp->tm_hour);
1113
1114	case L_('l'):		/* GNU extension.  */
1115	  if (modifier == L_('E'))
1116	    goto bad_format;
1117
1118	  DO_NUMBER_SPACEPAD (2, hour12);
1119
1120	case L_('j'):
1121	  if (modifier == L_('E'))
1122	    goto bad_format;
1123
1124	  DO_NUMBER (3, 1 + tp->tm_yday);
1125
1126	case L_('M'):
1127	  if (modifier == L_('E'))
1128	    goto bad_format;
1129
1130	  DO_NUMBER (2, tp->tm_min);
1131
1132	case L_('m'):
1133	  if (modifier == L_('E'))
1134	    goto bad_format;
1135
1136	  DO_NUMBER (2, tp->tm_mon + 1);
1137
1138#ifndef _LIBC
1139	case L_('N'):		/* GNU extension.  */
1140	  if (modifier == L_('E'))
1141	    goto bad_format;
1142
1143	  number_value = ns;
1144	  if (width != -1)
1145	    {
1146	      /* Take an explicit width less than 9 as a precision.  */
1147	      int j;
1148	      for (j = width; j < 9; j++)
1149		number_value /= 10;
1150	    }
1151
1152	  DO_NUMBER (9, number_value);
1153#endif
1154
1155	case L_('n'):
1156	  add (1, *p = L_('\n'));
1157	  break;
1158
1159	case L_('P'):
1160	  to_lowcase = 1;
1161#if !defined _NL_CURRENT && HAVE_STRFTIME
1162	  format_char = L_('p');
1163#endif
1164	  /* FALLTHROUGH */
1165
1166	case L_('p'):
1167	  if (change_case)
1168	    {
1169	      to_uppcase = 0;
1170	      to_lowcase = 1;
1171	    }
1172#if defined _NL_CURRENT || !HAVE_STRFTIME
1173	  cpy (ap_len, ampm);
1174	  break;
1175#else
1176	  goto underlying_strftime;
1177#endif
1178
1179	case L_('R'):
1180	  subfmt = L_("%H:%M");
1181	  goto subformat;
1182
1183	case L_('r'):
1184#ifdef _NL_CURRENT
1185	  if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
1186						       NLW(T_FMT_AMPM)))
1187	      == L_('\0'))
1188#endif
1189	    subfmt = L_("%I:%M:%S %p");
1190	  goto subformat;
1191
1192	case L_('S'):
1193	  if (modifier == L_('E'))
1194	    goto bad_format;
1195
1196	  DO_NUMBER (2, tp->tm_sec);
1197
1198	case L_('s'):		/* GNU extension.  */
1199  	  {
1200	    struct tm ltm;
1201	    time_t t;
1202
1203	    ltm = *tp;
1204	    t = mktime (&ltm);
1205
1206	    /* Generate string value for T using time_t arithmetic;
1207	       this works even if sizeof (long) < sizeof (time_t).  */
1208
1209	    bufp = buf + sizeof (buf) / sizeof (buf[0]);
1210	    negative_number = t < 0;
1211
1212	    do
1213	      {
1214		int d = t % 10;
1215		t /= 10;
1216
1217		if (negative_number)
1218		  {
1219		    d = -d;
1220
1221		    /* Adjust if division truncates to minus infinity.  */
1222		    if (0 < -1 % 10 && d < 0)
1223		      {
1224			t++;
1225			d += 10;
1226		      }
1227		  }
1228
1229		*--bufp = d + L_('0');
1230	      }
1231	    while (t != 0);
1232
1233	    digits = 1;
1234	    goto do_number_sign_and_padding;
1235	  }
1236
1237	case L_('X'):
1238	  if (modifier == L_('O'))
1239	    goto bad_format;
1240#ifdef _NL_CURRENT
1241	  if (! (modifier == L_('E')
1242		 && (*(subfmt =
1243		       (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
1244		     != L_('\0'))))
1245	    subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
1246	  goto subformat;
1247#else
1248# if HAVE_STRFTIME
1249	  goto underlying_strftime;
1250# else
1251	  /* Fall through.  */
1252# endif
1253#endif
1254	case L_('T'):
1255	  subfmt = L_("%H:%M:%S");
1256	  goto subformat;
1257
1258	case L_('t'):
1259	  add (1, *p = L_('\t'));
1260	  break;
1261
1262	case L_('u'):
1263	  DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1264
1265	case L_('U'):
1266	  if (modifier == L_('E'))
1267	    goto bad_format;
1268
1269	  DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1270
1271	case L_('V'):
1272	case L_('g'):
1273	case L_('G'):
1274	  if (modifier == L_('E'))
1275	    goto bad_format;
1276	  {
1277	    int year = tp->tm_year + TM_YEAR_BASE;
1278	    int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1279
1280	    if (days < 0)
1281	      {
1282		/* This ISO week belongs to the previous year.  */
1283		year--;
1284		days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
1285				      tp->tm_wday);
1286	      }
1287	    else
1288	      {
1289		int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1290				       tp->tm_wday);
1291		if (0 <= d)
1292		  {
1293		    /* This ISO week belongs to the next year.  */
1294		    year++;
1295		    days = d;
1296		  }
1297	      }
1298
1299	    switch (*f)
1300	      {
1301	      case L_('g'):
1302		DO_NUMBER (2, (year % 100 + 100) % 100);
1303
1304	      case L_('G'):
1305		DO_NUMBER (1, year);
1306
1307	      default:
1308		DO_NUMBER (2, days / 7 + 1);
1309	      }
1310	  }
1311
1312	case L_('W'):
1313	  if (modifier == L_('E'))
1314	    goto bad_format;
1315
1316	  DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1317
1318	case L_('w'):
1319	  if (modifier == L_('E'))
1320	    goto bad_format;
1321
1322	  DO_NUMBER (1, tp->tm_wday);
1323
1324	case L_('Y'):
1325	  if (modifier == 'E')
1326	    {
1327#if HAVE_STRUCT_ERA_ENTRY
1328	      struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1329	      if (era)
1330		{
1331# ifdef COMPILE_WIDE
1332		  subfmt = era->era_wformat;
1333# else
1334		  subfmt = era->era_format;
1335# endif
1336		  goto subformat;
1337		}
1338#else
1339# if HAVE_STRFTIME
1340	      goto underlying_strftime;
1341# endif
1342#endif
1343	    }
1344	  if (modifier == L_('O'))
1345	    goto bad_format;
1346	  else
1347	    DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1348
1349	case L_('y'):
1350	  if (modifier == L_('E'))
1351	    {
1352#if HAVE_STRUCT_ERA_ENTRY
1353	      struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1354	      if (era)
1355		{
1356		  int delta = tp->tm_year - era->start_date[0];
1357		  DO_NUMBER (1, (era->offset
1358				 + delta * era->absolute_direction));
1359		}
1360#else
1361# if HAVE_STRFTIME
1362	      goto underlying_strftime;
1363# endif
1364#endif
1365	    }
1366	  DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1367
1368	case L_('Z'):
1369	  if (change_case)
1370	    {
1371	      to_uppcase = 0;
1372	      to_lowcase = 1;
1373	    }
1374
1375#if HAVE_TZNAME
1376	  /* The tzset() call might have changed the value.  */
1377	  if (!(zone && *zone) && tp->tm_isdst >= 0)
1378	    zone = tzname[tp->tm_isdst];
1379#endif
1380	  if (! zone)
1381	    zone = "";
1382
1383#ifdef COMPILE_WIDE
1384	  {
1385	    /* The zone string is always given in multibyte form.  We have
1386	       to transform it first.  */
1387	    wchar_t *wczone;
1388	    size_t len;
1389	    widen (zone, wczone, len);
1390	    cpy (len, wczone);
1391	  }
1392#else
1393	  cpy (strlen (zone), zone);
1394#endif
1395	  break;
1396
1397	case L_('z'):
1398	  if (tp->tm_isdst < 0)
1399	    break;
1400
1401	  {
1402	    int diff;
1403#if HAVE_TM_GMTOFF
1404	    diff = tp->tm_gmtoff;
1405#else
1406	    if (ut)
1407	      diff = 0;
1408	    else
1409	      {
1410		struct tm gtm;
1411		struct tm ltm;
1412		time_t lt;
1413
1414		ltm = *tp;
1415		lt = mktime (&ltm);
1416
1417		if (lt == (time_t) -1)
1418		  {
1419		    /* mktime returns -1 for errors, but -1 is also a
1420		       valid time_t value.  Check whether an error really
1421		       occurred.  */
1422		    struct tm tm;
1423
1424		    if (! my_strftime_localtime_r (&lt, &tm)
1425			|| ((ltm.tm_sec ^ tm.tm_sec)
1426			    | (ltm.tm_min ^ tm.tm_min)
1427			    | (ltm.tm_hour ^ tm.tm_hour)
1428			    | (ltm.tm_mday ^ tm.tm_mday)
1429			    | (ltm.tm_mon ^ tm.tm_mon)
1430			    | (ltm.tm_year ^ tm.tm_year)))
1431		      break;
1432		  }
1433
1434		if (! my_strftime_gmtime_r (&lt, &gtm))
1435		  break;
1436
1437		diff = tm_diff (&ltm, &gtm);
1438	      }
1439#endif
1440
1441	    if (diff < 0)
1442	      {
1443		add (1, *p = L_('-'));
1444		diff = -diff;
1445	      }
1446	    else
1447	      add (1, *p = L_('+'));
1448
1449	    diff /= 60;
1450	    DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1451	  }
1452
1453	case L_('\0'):		/* GNU extension: % at end of format.  */
1454	    --f;
1455	    /* Fall through.  */
1456	default:
1457	  /* Unknown format; output the format, including the '%',
1458	     since this is most likely the right thing to do if a
1459	     multibyte string has been misparsed.  */
1460	bad_format:
1461	  {
1462	    int flen;
1463	    for (flen = 1; f[1 - flen] != L_('%'); flen++)
1464	      continue;
1465	    cpy (flen, &f[1 - flen]);
1466	  }
1467	  break;
1468	}
1469    }
1470
1471  if (p && maxsize != 0)
1472    *p = L_('\0');
1473  return i;
1474}
1475#ifdef _LIBC
1476libc_hidden_def (my_strftime)
1477#endif
1478
1479
1480#ifdef emacs
1481#undef ut
1482/* For Emacs we have a separate interface which corresponds to the normal
1483   strftime function plus the ut argument, but without the ns argument.  */
1484size_t
1485emacs_strftimeu (s, maxsize, format, tp, ut)
1486      char *s;
1487      size_t maxsize;
1488      const char *format;
1489      const struct tm *tp;
1490      int ut;
1491{
1492  return my_strftime (s, maxsize, format, tp, ut, 0);
1493}
1494#endif
1495
1496/* arch-tag: 662bc9c4-f8e2-41b6-bf96-b8346d0ce0d8
1497   (do not change this comment) */
1498