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