(human_readable): Fix bug that rounded 10501 to 10k.
[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
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any 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
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License along
17    with this program; if not, write to the Free Software Foundation,
18    Inc., 59 Temple Place - Suite 330, Boston, MA 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
194 static struct tm *my_strftime_localtime_r __P ((const time_t *, struct tm *));
195 static struct tm *
196 my_strftime_localtime_r (t, tp)
197      const time_t *t;
198      struct tm *tp;
199 {
200   struct tm *l = localtime (t);
201   if (! l)
202     return 0;
203   *tp = *l;
204   return tp;
205 }
206 # endif /* ! HAVE_TM_GMTOFF */
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 # ifndef USE_IN_EXTENDED_LOCALE_MODEL
295 #  undef __mbsrtowcs_l
296 #  define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
297 # endif
298 # define widen(os, ws, l) \
299   {                                                                           \
300     mbstate_t __st;                                                           \
301     const char *__s = os;                                                     \
302     memset (&__st, '\0', sizeof (__st));                                      \
303     l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc);                            \
304     ws = (wchar_t *) alloca ((l + 1) * sizeof (wchar_t));                     \
305     (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc);                           \
306   }
307 #endif
308
309
310 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
311 /* We use this code also for the extended locale handling where the
312    function gets as an additional argument the locale which has to be
313    used.  To access the values we have to redefine the _NL_CURRENT
314    macro.  */
315 # define strftime               __strftime_l
316 # define wcsftime               __wcsftime_l
317 # undef _NL_CURRENT
318 # define _NL_CURRENT(category, item) \
319   (current->values[_NL_ITEM_INDEX (item)].string)
320 # define LOCALE_PARAM , loc
321 # define LOCALE_ARG , loc
322 # define LOCALE_PARAM_DECL  __locale_t loc;
323 # define LOCALE_PARAM_PROTO , __locale_t loc
324 # define HELPER_LOCALE_ARG  , current
325 #else
326 # define LOCALE_PARAM
327 # define LOCALE_PARAM_PROTO
328 # define LOCALE_ARG
329 # define LOCALE_PARAM_DECL
330 # ifdef _LIBC
331 #  define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
332 # else
333 #  define HELPER_LOCALE_ARG
334 # endif
335 #endif
336
337 #ifdef COMPILE_WIDE
338 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
339 #  define TOUPPER(Ch, L) __towupper_l (Ch, L)
340 #  define TOLOWER(Ch, L) __towlower_l (Ch, L)
341 # else
342 #  define TOUPPER(Ch, L) towupper (Ch)
343 #  define TOLOWER(Ch, L) towlower (Ch)
344 # endif
345 #else
346 # ifdef _LIBC
347 #  ifdef USE_IN_EXTENDED_LOCALE_MODEL
348 #   define TOUPPER(Ch, L) __toupper_l (Ch, L)
349 #   define TOLOWER(Ch, L) __tolower_l (Ch, L)
350 #  else
351 #   define TOUPPER(Ch, L) toupper (Ch)
352 #   define TOLOWER(Ch, L) tolower (Ch)
353 #  endif
354 # else
355 #  define TOUPPER(Ch, L) (islower (Ch) ? toupper (Ch) : (Ch))
356 #  define TOLOWER(Ch, L) (isupper (Ch) ? tolower (Ch) : (Ch))
357 # endif
358 #endif
359 /* We don't use `isdigit' here since the locale dependent
360    interpretation is not what we want here.  We only need to accept
361    the arabic digits in the ASCII range.  One day there is perhaps a
362    more reliable way to accept other sets of digits.  */
363 #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
364
365 static CHAR_T *memcpy_lowcase __P ((CHAR_T *dest, const CHAR_T *src,
366                                     size_t len LOCALE_PARAM_PROTO));
367
368 static CHAR_T *
369 memcpy_lowcase (dest, src, len LOCALE_PARAM)
370      CHAR_T *dest;
371      const CHAR_T *src;
372      size_t len;
373      LOCALE_PARAM_DECL
374 {
375   while (len-- > 0)
376     dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
377   return dest;
378 }
379
380 static CHAR_T *memcpy_uppcase __P ((CHAR_T *dest, const CHAR_T *src,
381                                     size_t len LOCALE_PARAM_PROTO));
382
383 static CHAR_T *
384 memcpy_uppcase (dest, src, len LOCALE_PARAM)
385      CHAR_T *dest;
386      const CHAR_T *src;
387      size_t len;
388      LOCALE_PARAM_DECL
389 {
390   while (len-- > 0)
391     dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
392   return dest;
393 }
394
395
396 #if ! HAVE_TM_GMTOFF
397 /* Yield the difference between *A and *B,
398    measured in seconds, ignoring leap seconds.  */
399 # define tm_diff ftime_tm_diff
400 static int tm_diff __P ((const struct tm *, const struct tm *));
401 static int
402 tm_diff (a, b)
403      const struct tm *a;
404      const struct tm *b;
405 {
406   /* Compute intervening leap days correctly even if year is negative.
407      Take care to avoid int overflow in leap day calculations,
408      but it's OK to assume that A and B are close to each other.  */
409   int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
410   int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
411   int a100 = a4 / 25 - (a4 % 25 < 0);
412   int b100 = b4 / 25 - (b4 % 25 < 0);
413   int a400 = a100 >> 2;
414   int b400 = b100 >> 2;
415   int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
416   int years = a->tm_year - b->tm_year;
417   int days = (365 * years + intervening_leap_days
418               + (a->tm_yday - b->tm_yday));
419   return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
420                 + (a->tm_min - b->tm_min))
421           + (a->tm_sec - b->tm_sec));
422 }
423 #endif /* ! HAVE_TM_GMTOFF */
424
425
426
427 /* The number of days from the first day of the first ISO week of this
428    year to the year day YDAY with week day WDAY.  ISO weeks start on
429    Monday; the first ISO week has the year's first Thursday.  YDAY may
430    be as small as YDAY_MINIMUM.  */
431 #define ISO_WEEK_START_WDAY 1 /* Monday */
432 #define ISO_WEEK1_WDAY 4 /* Thursday */
433 #define YDAY_MINIMUM (-366)
434 static int iso_week_days __P ((int, int));
435 #ifdef __GNUC__
436 __inline__
437 #endif
438 static int
439 iso_week_days (yday, wday)
440      int yday;
441      int wday;
442 {
443   /* Add enough to the first operand of % to make it nonnegative.  */
444   int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
445   return (yday
446           - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
447           + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
448 }
449
450
451 #if !(defined _NL_CURRENT || HAVE_STRFTIME)
452 static CHAR_T const weekday_name[][10] =
453   {
454     L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
455     L_("Thursday"), L_("Friday"), L_("Saturday")
456   };
457 static CHAR_T const month_name[][10] =
458   {
459     L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
460     L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
461     L_("November"), L_("December")
462   };
463 #endif
464
465
466 /* When compiling this file, GNU applications can #define my_strftime
467    to a symbol (typically nstrftime) to get an extended strftime with
468    extra arguments UT and NS.  Emacs is a special case for now, but
469    this Emacs-specific code can be removed once Emacs's config.h
470    defines my_strftime.  */
471 #if defined emacs && !defined my_strftime
472 # define my_strftime nstrftime
473 #endif
474
475 #ifdef my_strftime
476 # define extra_args , ut, ns
477 # define extra_args_spec int ut; int ns;
478 # define extra_args_spec_iso , int ut, int ns
479 #else
480 # ifdef COMPILE_WIDE
481 #  define my_strftime wcsftime
482 #  define nl_get_alt_digit _nl_get_walt_digit
483 # else
484 #  define my_strftime strftime
485 #  define nl_get_alt_digit _nl_get_alt_digit
486 # endif
487 # define extra_args
488 # define extra_args_spec
489 # define extra_args_spec_iso
490 /* We don't have this information in general.  */
491 # define ut 0
492 # define ns 0
493 #endif
494
495 #if ! defined _LIBC && ! HAVE_RUN_TZSET_TEST
496 /* Solaris 2.5.x and 2.6 tzset sometimes modify the storage returned
497    by localtime.  On such systems, we must use the tzset and localtime
498    wrappers to work around the bug.  */
499 "you must run the autoconf test for a working tzset function"
500 #endif
501
502
503 /* Write information from TP into S according to the format
504    string FORMAT, writing no more that MAXSIZE characters
505    (including the terminating '\0') and returning number of
506    characters written.  If S is NULL, nothing will be written
507    anywhere, so to determine how many characters would be
508    written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */
509 size_t
510 my_strftime (s, maxsize, format, tp extra_args LOCALE_PARAM)
511       CHAR_T *s;
512       size_t maxsize;
513       const CHAR_T *format;
514       const struct tm *tp;
515       extra_args_spec
516       LOCALE_PARAM_DECL
517 {
518 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
519   struct locale_data *const current = loc->__locales[LC_TIME];
520 #endif
521
522   int hour12 = tp->tm_hour;
523 #ifdef _NL_CURRENT
524   /* We cannot make the following values variables since we must delay
525      the evaluation of these values until really needed since some
526      expressions might not be valid in every situation.  The `struct tm'
527      might be generated by a strptime() call that initialized
528      only a few elements.  Dereference the pointers only if the format
529      requires this.  Then it is ok to fail if the pointers are invalid.  */
530 # define a_wkday \
531   ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
532 # define f_wkday \
533   ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
534 # define a_month \
535   ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
536 # define f_month \
537   ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
538 # define ampm \
539   ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11                    \
540                                  ? NLW(PM_STR) : NLW(AM_STR)))
541
542 # define aw_len STRLEN (a_wkday)
543 # define am_len STRLEN (a_month)
544 # define ap_len STRLEN (ampm)
545 #else
546 # if !HAVE_STRFTIME
547 #  define f_wkday (weekday_name[tp->tm_wday])
548 #  define f_month (month_name[tp->tm_mon])
549 #  define a_wkday f_wkday
550 #  define a_month f_month
551 #  define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
552
553   size_t aw_len = 3;
554   size_t am_len = 3;
555   size_t ap_len = 2;
556 # endif
557 #endif
558   const char *zone;
559   size_t i = 0;
560   CHAR_T *p = s;
561   const CHAR_T *f;
562 #if DO_MULTIBYTE && !defined COMPILE_WIDE
563   const char *format_end = NULL;
564 #endif
565
566   zone = NULL;
567 #if HAVE_TM_ZONE
568   /* The POSIX test suite assumes that setting
569      the environment variable TZ to a new value before calling strftime()
570      will influence the result (the %Z format) even if the information in
571      TP is computed with a totally different time zone.
572      This is bogus: though POSIX allows bad behavior like this,
573      POSIX does not require it.  Do the right thing instead.  */
574   zone = (const char *) tp->tm_zone;
575 #endif
576 #if HAVE_TZNAME
577   if (ut)
578     {
579       if (! (zone && *zone))
580         zone = "GMT";
581     }
582   else
583     {
584       /* POSIX.1 requires that local time zone information be used as
585          though strftime called tzset.  */
586 # if HAVE_TZSET
587       tzset ();
588 # endif
589     }
590 #endif
591
592   if (hour12 > 12)
593     hour12 -= 12;
594   else
595     if (hour12 == 0)
596       hour12 = 12;
597
598   for (f = format; *f != '\0'; ++f)
599     {
600       int pad = 0;              /* Padding for number ('-', '_', or 0).  */
601       int modifier;             /* Field modifier ('E', 'O', or 0).  */
602       int digits;               /* Max digits for numeric format.  */
603       int number_value;         /* Numeric value to be printed.  */
604       int negative_number;      /* 1 if the number is negative.  */
605       const CHAR_T *subfmt;
606       CHAR_T *bufp;
607       CHAR_T buf[1 + (sizeof (int) < sizeof (time_t)
608                       ? INT_STRLEN_BOUND (time_t)
609                       : INT_STRLEN_BOUND (int))];
610       int width = -1;
611       int to_lowcase = 0;
612       int to_uppcase = 0;
613       int change_case = 0;
614       int format_char;
615
616 #if DO_MULTIBYTE && !defined COMPILE_WIDE
617       switch (*f)
618         {
619         case L_('%'):
620           break;
621
622         case L_('\b'): case L_('\t'): case L_('\n'):
623         case L_('\v'): case L_('\f'): case L_('\r'):
624         case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
625         case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
626         case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
627         case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
628         case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
629         case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
630         case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
631         case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
632         case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
633         case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
634         case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
635         case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
636         case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
637         case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
638         case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
639         case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
640         case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
641         case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
642         case L_('~'):
643           /* The C Standard requires these 98 characters (plus '%') to
644              be in the basic execution character set.  None of these
645              characters can start a multibyte sequence, so they need
646              not be analyzed further.  */
647           add (1, *p = *f);
648           continue;
649
650         default:
651           /* Copy this multibyte sequence until we reach its end, find
652              an error, or come back to the initial shift state.  */
653           {
654             mbstate_t mbstate = mbstate_zero;
655             size_t len = 0;
656             size_t fsize;
657
658             if (! format_end)
659               format_end = f + strlen (f) + 1;
660             fsize = format_end - f;
661
662             do
663               {
664                 size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
665
666                 if (bytes == 0)
667                   break;
668
669                 if (bytes == (size_t) -2)
670                   {
671                     len += strlen (f + len);
672                     break;
673                   }
674
675                 if (bytes == (size_t) -1)
676                   {
677                     len++;
678                     break;
679                   }
680
681                 len += bytes;
682               }
683             while (! mbsinit (&mbstate));
684
685             cpy (len, f);
686             f += len - 1;
687             continue;
688           }
689         }
690
691 #else /* ! DO_MULTIBYTE */
692
693       /* Either multibyte encodings are not supported, they are
694          safe for formats, so any non-'%' byte can be copied through,
695          or this is the wide character version.  */
696       if (*f != L_('%'))
697         {
698           add (1, *p = *f);
699           continue;
700         }
701
702 #endif /* ! DO_MULTIBYTE */
703
704       /* Check for flags that can modify a format.  */
705       while (1)
706         {
707           switch (*++f)
708             {
709               /* This influences the number formats.  */
710             case L_('_'):
711             case L_('-'):
712             case L_('0'):
713               pad = *f;
714               continue;
715
716               /* This changes textual output.  */
717             case L_('^'):
718               to_uppcase = 1;
719               continue;
720             case L_('#'):
721               change_case = 1;
722               continue;
723
724             default:
725               break;
726             }
727           break;
728         }
729
730       /* As a GNU extension we allow to specify the field width.  */
731       if (ISDIGIT (*f))
732         {
733           width = 0;
734           do
735             {
736               if (width > INT_MAX / 10
737                   || (width == INT_MAX / 10 && *f - L_('0') > INT_MAX % 10))
738                 /* Avoid overflow.  */
739                 width = INT_MAX;
740               else
741                 {
742                   width *= 10;
743                   width += *f - L_('0');
744                 }
745               ++f;
746             }
747           while (ISDIGIT (*f));
748         }
749
750       /* Check for modifiers.  */
751       switch (*f)
752         {
753         case L_('E'):
754         case L_('O'):
755           modifier = *f++;
756           break;
757
758         default:
759           modifier = 0;
760           break;
761         }
762
763       /* Now do the specified format.  */
764       format_char = *f;
765       switch (format_char)
766         {
767 #define DO_NUMBER(d, v) \
768           digits = d > width ? d : width;                                     \
769           number_value = v; goto do_number
770 #define DO_NUMBER_SPACEPAD(d, v) \
771           digits = d > width ? d : width;                                     \
772           number_value = v; goto do_number_spacepad
773
774         case L_('%'):
775           if (modifier != 0)
776             goto bad_format;
777           add (1, *p = *f);
778           break;
779
780         case L_('a'):
781           if (modifier != 0)
782             goto bad_format;
783           if (change_case)
784             {
785               to_uppcase = 1;
786               to_lowcase = 0;
787             }
788 #if defined _NL_CURRENT || !HAVE_STRFTIME
789           cpy (aw_len, a_wkday);
790           break;
791 #else
792           goto underlying_strftime;
793 #endif
794
795         case 'A':
796           if (modifier != 0)
797             goto bad_format;
798           if (change_case)
799             {
800               to_uppcase = 1;
801               to_lowcase = 0;
802             }
803 #if defined _NL_CURRENT || !HAVE_STRFTIME
804           cpy (STRLEN (f_wkday), f_wkday);
805           break;
806 #else
807           goto underlying_strftime;
808 #endif
809
810         case L_('b'):
811         case L_('h'):
812           if (change_case)
813             {
814               to_uppcase = 1;
815               to_lowcase = 0;
816             }
817           if (modifier != 0)
818             goto bad_format;
819 #if defined _NL_CURRENT || !HAVE_STRFTIME
820           cpy (am_len, a_month);
821           break;
822 #else
823           goto underlying_strftime;
824 #endif
825
826         case L_('B'):
827           if (modifier != 0)
828             goto bad_format;
829           if (change_case)
830             {
831               to_uppcase = 1;
832               to_lowcase = 0;
833             }
834 #if defined _NL_CURRENT || !HAVE_STRFTIME
835           cpy (STRLEN (f_month), f_month);
836           break;
837 #else
838           goto underlying_strftime;
839 #endif
840
841         case L_('c'):
842           if (modifier == L_('O'))
843             goto bad_format;
844 #ifdef _NL_CURRENT
845           if (! (modifier == 'E'
846                  && (*(subfmt =
847                        (const CHAR_T *) _NL_CURRENT (LC_TIME,
848                                                      NLW(ERA_D_T_FMT)))
849                      != '\0')))
850             subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
851 #else
852 # if HAVE_STRFTIME
853           goto underlying_strftime;
854 # else
855           subfmt = L_("%a %b %e %H:%M:%S %Y");
856 # endif
857 #endif
858
859         subformat:
860           {
861             CHAR_T *old_start = p;
862             size_t len = my_strftime (NULL, (size_t) -1, subfmt,
863                                       tp extra_args LOCALE_ARG);
864             add (len, my_strftime (p, maxsize - i, subfmt,
865                                    tp extra_args LOCALE_ARG));
866
867             if (to_uppcase)
868               while (old_start < p)
869                 {
870                   *old_start = TOUPPER ((UCHAR_T) *old_start, loc);
871                   ++old_start;
872                 }
873           }
874           break;
875
876 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
877         underlying_strftime:
878           {
879             /* The relevant information is available only via the
880                underlying strftime implementation, so use that.  */
881             char ufmt[4];
882             char *u = ufmt;
883             char ubuf[1024]; /* enough for any single format in practice */
884             size_t len;
885             /* Make sure we're calling the actual underlying strftime.
886                In some cases, config.h contains something like
887                "#define strftime rpl_strftime".  */
888 # ifdef strftime
889 #  undef strftime
890             size_t strftime ();
891 # endif
892
893             *u++ = '%';
894             if (modifier != 0)
895               *u++ = modifier;
896             *u++ = format_char;
897             *u = '\0';
898             len = strftime (ubuf, sizeof ubuf, ufmt, tp);
899             if (len == 0 && ubuf[0] != '\0')
900               return 0;
901             cpy (len, ubuf);
902           }
903           break;
904 #endif
905
906         case L_('C'):
907           if (modifier == L_('O'))
908             goto bad_format;
909           if (modifier == L_('E'))
910             {
911 #if HAVE_STRUCT_ERA_ENTRY
912               struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
913               if (era)
914                 {
915 # ifdef COMPILE_WIDE
916                   size_t len = __wcslen (era->era_wname);
917                   cpy (len, era->era_wname);
918 # else
919                   size_t len = strlen (era->era_name);
920                   cpy (len, era->era_name);
921 # endif
922                   break;
923                 }
924 #else
925 # if HAVE_STRFTIME
926               goto underlying_strftime;
927 # endif
928 #endif
929             }
930
931           {
932             int year = tp->tm_year + TM_YEAR_BASE;
933             DO_NUMBER (1, year / 100 - (year % 100 < 0));
934           }
935
936         case L_('x'):
937           if (modifier == L_('O'))
938             goto bad_format;
939 #ifdef _NL_CURRENT
940           if (! (modifier == L_('E')
941                  && (*(subfmt =
942                        (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
943                      != L_('\0'))))
944             subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
945           goto subformat;
946 #else
947 # if HAVE_STRFTIME
948           goto underlying_strftime;
949 # else
950           /* Fall through.  */
951 # endif
952 #endif
953         case L_('D'):
954           if (modifier != 0)
955             goto bad_format;
956           subfmt = L_("%m/%d/%y");
957           goto subformat;
958
959         case L_('d'):
960           if (modifier == L_('E'))
961             goto bad_format;
962
963           DO_NUMBER (2, tp->tm_mday);
964
965         case L_('e'):
966           if (modifier == L_('E'))
967             goto bad_format;
968
969           DO_NUMBER_SPACEPAD (2, tp->tm_mday);
970
971           /* All numeric formats set DIGITS and NUMBER_VALUE and then
972              jump to one of these two labels.  */
973
974         do_number_spacepad:
975           /* Force `_' flag unless overridden by `0' or `-' flag.  */
976           if (pad != L_('0') && pad != L_('-'))
977             pad = L_('_');
978
979         do_number:
980           /* Format the number according to the MODIFIER flag.  */
981
982           if (modifier == L_('O') && 0 <= number_value)
983             {
984 #ifdef _NL_CURRENT
985               /* Get the locale specific alternate representation of
986                  the number NUMBER_VALUE.  If none exist NULL is returned.  */
987               const CHAR_T *cp = nl_get_alt_digit (number_value
988                                                    HELPER_LOCALE_ARG);
989
990               if (cp != NULL)
991                 {
992                   size_t digitlen = STRLEN (cp);
993                   if (digitlen != 0)
994                     {
995                       cpy (digitlen, cp);
996                       break;
997                     }
998                 }
999 #else
1000 # if HAVE_STRFTIME
1001               goto underlying_strftime;
1002 # endif
1003 #endif
1004             }
1005           {
1006             unsigned int u = number_value;
1007
1008             bufp = buf + sizeof (buf) / sizeof (buf[0]);
1009             negative_number = number_value < 0;
1010
1011             if (negative_number)
1012               u = -u;
1013
1014             do
1015               *--bufp = u % 10 + L_('0');
1016             while ((u /= 10) != 0);
1017           }
1018
1019         do_number_sign_and_padding:
1020           if (negative_number)
1021             *--bufp = L_('-');
1022
1023           if (pad != L_('-'))
1024             {
1025               int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
1026                                       - bufp);
1027
1028               if (padding > 0)
1029                 {
1030                   if (pad == L_('_'))
1031                     {
1032                       if ((size_t) padding >= maxsize - i)
1033                         return 0;
1034
1035                       if (p)
1036                         memset_space (p, padding);
1037                       i += padding;
1038                       width = width > padding ? width - padding : 0;
1039                     }
1040                   else
1041                     {
1042                       if ((size_t) digits >= maxsize - i)
1043                         return 0;
1044
1045                       if (negative_number)
1046                         {
1047                           ++bufp;
1048
1049                           if (p)
1050                             *p++ = L_('-');
1051                           ++i;
1052                         }
1053
1054                       if (p)
1055                         memset_zero (p, padding);
1056                       i += padding;
1057                       width = 0;
1058                     }
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 #if !defined _NL_CURRENT && HAVE_STRFTIME
1160           goto underlying_strftime;
1161 #else
1162 # ifdef _NL_CURRENT
1163           if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
1164                                                        NLW(T_FMT_AMPM)))
1165               == L_('\0'))
1166 # endif
1167             subfmt = L_("%I:%M:%S %p");
1168           goto subformat;
1169 #endif
1170
1171         case L_('S'):
1172           if (modifier == L_('E'))
1173             goto bad_format;
1174
1175           DO_NUMBER (2, tp->tm_sec);
1176
1177         case L_('s'):           /* GNU extension.  */
1178           {
1179             struct tm ltm;
1180             time_t t;
1181
1182             ltm = *tp;
1183             t = mktime (&ltm);
1184
1185             /* Generate string value for T using time_t arithmetic;
1186                this works even if sizeof (long) < sizeof (time_t).  */
1187
1188             bufp = buf + sizeof (buf) / sizeof (buf[0]);
1189             negative_number = t < 0;
1190
1191             do
1192               {
1193                 int d = t % 10;
1194                 t /= 10;
1195
1196                 if (negative_number)
1197                   {
1198                     d = -d;
1199
1200                     /* Adjust if division truncates to minus infinity.  */
1201                     if (0 < -1 % 10 && d < 0)
1202                       {
1203                         t++;
1204                         d += 10;
1205                       }
1206                   }
1207
1208                 *--bufp = d + L_('0');
1209               }
1210             while (t != 0);
1211
1212             digits = 1;
1213             goto do_number_sign_and_padding;
1214           }
1215
1216         case L_('X'):
1217           if (modifier == L_('O'))
1218             goto bad_format;
1219 #ifdef _NL_CURRENT
1220           if (! (modifier == L_('E')
1221                  && (*(subfmt =
1222                        (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
1223                      != L_('\0'))))
1224             subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
1225           goto subformat;
1226 #else
1227 # if HAVE_STRFTIME
1228           goto underlying_strftime;
1229 # else
1230           /* Fall through.  */
1231 # endif
1232 #endif
1233         case L_('T'):
1234           subfmt = L_("%H:%M:%S");
1235           goto subformat;
1236
1237         case L_('t'):
1238           add (1, *p = L_('\t'));
1239           break;
1240
1241         case L_('u'):
1242           DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1243
1244         case L_('U'):
1245           if (modifier == L_('E'))
1246             goto bad_format;
1247
1248           DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1249
1250         case L_('V'):
1251         case L_('g'):
1252         case L_('G'):
1253           if (modifier == L_('E'))
1254             goto bad_format;
1255           {
1256             int year = tp->tm_year + TM_YEAR_BASE;
1257             int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1258
1259             if (days < 0)
1260               {
1261                 /* This ISO week belongs to the previous year.  */
1262                 year--;
1263                 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
1264                                       tp->tm_wday);
1265               }
1266             else
1267               {
1268                 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1269                                        tp->tm_wday);
1270                 if (0 <= d)
1271                   {
1272                     /* This ISO week belongs to the next year.  */
1273                     year++;
1274                     days = d;
1275                   }
1276               }
1277
1278             switch (*f)
1279               {
1280               case L_('g'):
1281                 DO_NUMBER (2, (year % 100 + 100) % 100);
1282
1283               case L_('G'):
1284                 DO_NUMBER (1, year);
1285
1286               default:
1287                 DO_NUMBER (2, days / 7 + 1);
1288               }
1289           }
1290
1291         case L_('W'):
1292           if (modifier == L_('E'))
1293             goto bad_format;
1294
1295           DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1296
1297         case L_('w'):
1298           if (modifier == L_('E'))
1299             goto bad_format;
1300
1301           DO_NUMBER (1, tp->tm_wday);
1302
1303         case L_('Y'):
1304           if (modifier == 'E')
1305             {
1306 #if HAVE_STRUCT_ERA_ENTRY
1307               struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1308               if (era)
1309                 {
1310 # ifdef COMPILE_WIDE
1311                   subfmt = era->era_wformat;
1312 # else
1313                   subfmt = era->era_format;
1314 # endif
1315                   goto subformat;
1316                 }
1317 #else
1318 # if HAVE_STRFTIME
1319               goto underlying_strftime;
1320 # endif
1321 #endif
1322             }
1323           if (modifier == L_('O'))
1324             goto bad_format;
1325           else
1326             DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1327
1328         case L_('y'):
1329           if (modifier == L_('E'))
1330             {
1331 #if HAVE_STRUCT_ERA_ENTRY
1332               struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1333               if (era)
1334                 {
1335                   int delta = tp->tm_year - era->start_date[0];
1336                   DO_NUMBER (1, (era->offset
1337                                  + delta * era->absolute_direction));
1338                 }
1339 #else
1340 # if HAVE_STRFTIME
1341               goto underlying_strftime;
1342 # endif
1343 #endif
1344             }
1345           DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1346
1347         case L_('Z'):
1348           if (change_case)
1349             {
1350               to_uppcase = 0;
1351               to_lowcase = 1;
1352             }
1353
1354 #if HAVE_TZNAME
1355           /* The tzset() call might have changed the value.  */
1356           if (!(zone && *zone) && tp->tm_isdst >= 0)
1357             zone = tzname[tp->tm_isdst];
1358 #endif
1359           if (! zone)
1360             zone = "";
1361
1362 #ifdef COMPILE_WIDE
1363           {
1364             /* The zone string is always given in multibyte form.  We have
1365                to transform it first.  */
1366             wchar_t *wczone;
1367             size_t len;
1368             widen (zone, wczone, len);
1369             cpy (len, wczone);
1370           }
1371 #else
1372           cpy (strlen (zone), zone);
1373 #endif
1374           break;
1375
1376         case L_('z'):
1377           if (tp->tm_isdst < 0)
1378             break;
1379
1380           {
1381             int diff;
1382 #if HAVE_TM_GMTOFF
1383             diff = tp->tm_gmtoff;
1384 #else
1385             if (ut)
1386               diff = 0;
1387             else
1388               {
1389                 struct tm gtm;
1390                 struct tm ltm;
1391                 time_t lt;
1392
1393                 ltm = *tp;
1394                 lt = mktime (&ltm);
1395
1396                 if (lt == (time_t) -1)
1397                   {
1398                     /* mktime returns -1 for errors, but -1 is also a
1399                        valid time_t value.  Check whether an error really
1400                        occurred.  */
1401                     struct tm tm;
1402
1403                     if (! my_strftime_localtime_r (&lt, &tm)
1404                         || ((ltm.tm_sec ^ tm.tm_sec)
1405                             | (ltm.tm_min ^ tm.tm_min)
1406                             | (ltm.tm_hour ^ tm.tm_hour)
1407                             | (ltm.tm_mday ^ tm.tm_mday)
1408                             | (ltm.tm_mon ^ tm.tm_mon)
1409                             | (ltm.tm_year ^ tm.tm_year)))
1410                       break;
1411                   }
1412
1413                 if (! my_strftime_gmtime_r (&lt, &gtm))
1414                   break;
1415
1416                 diff = tm_diff (&ltm, &gtm);
1417               }
1418 #endif
1419
1420             if (diff < 0)
1421               {
1422                 add (1, *p = L_('-'));
1423                 diff = -diff;
1424               }
1425             else
1426               add (1, *p = L_('+'));
1427
1428             diff /= 60;
1429             DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1430           }
1431
1432         case L_('\0'):          /* GNU extension: % at end of format.  */
1433             --f;
1434             /* Fall through.  */
1435         default:
1436           /* Unknown format; output the format, including the '%',
1437              since this is most likely the right thing to do if a
1438              multibyte string has been misparsed.  */
1439         bad_format:
1440           {
1441             int flen;
1442             for (flen = 1; f[1 - flen] != L_('%'); flen++)
1443               continue;
1444             cpy (flen, &f[1 - flen]);
1445           }
1446           break;
1447         }
1448     }
1449
1450   if (p && maxsize != 0)
1451     *p = L_('\0');
1452   return i;
1453 }
1454 #ifdef _LIBC
1455 libc_hidden_def (my_strftime)
1456 #endif
1457
1458
1459 #ifdef emacs
1460 /* For Emacs we have a separate interface which corresponds to the normal
1461    strftime function plus the ut argument, but without the ns argument.  */
1462 size_t
1463 emacs_strftimeu (s, maxsize, format, tp, ut)
1464       char *s;
1465       size_t maxsize;
1466       const char *format;
1467       const struct tm *tp;
1468       int ut;
1469 {
1470   return my_strftime (s, maxsize, format, tp, ut, 0);
1471 }
1472 #endif