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