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