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