Declare localtime_r if necessary.
[gnulib.git] / lib / strftime.c
1 /* Copyright (C) 1991,92,93,94,95,96,97,98 Free Software Foundation, Inc.
2
3    NOTE: The canonical source of this file is maintained with the GNU C Library.
4    Bugs can be reported to bug-glibc@prep.ai.mit.edu.
5
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19    USA.  */
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 /* Some systems need this in order to declare localtime_r properly.  */
26 #ifndef _REENTRANT
27 # define _REENTRANT 1
28 #endif
29
30 #ifdef _LIBC
31 # define HAVE_LIMITS_H 1
32 # define HAVE_MBLEN 1
33 # define HAVE_MBRLEN 1
34 # define HAVE_STRUCT_ERA_ENTRY 1
35 # define HAVE_TM_GMTOFF 1
36 # define HAVE_TM_ZONE 1
37 # define HAVE_TZNAME 1
38 # define HAVE_TZSET 1
39 # define MULTIBYTE_IS_FORMAT_SAFE 1
40 # define STDC_HEADERS 1
41 # include "../locale/localeinfo.h"
42 #endif
43
44 #if defined emacs && !defined HAVE_BCOPY
45 # define HAVE_MEMCPY 1
46 #endif
47
48 #include <ctype.h>
49 #include <sys/types.h>          /* Some systems define `time_t' here.  */
50
51 /* Provide a declaration of localtime_r on systems that lack it.  */
52 #if ! defined HAVE_DECL_LOCALTIME_R
53 extern struct tm* localtime_r ();
54 #endif
55
56 #ifdef TIME_WITH_SYS_TIME
57 # include <sys/time.h>
58 # include <time.h>
59 #else
60 # ifdef HAVE_SYS_TIME_H
61 #  include <sys/time.h>
62 # else
63 #  include <time.h>
64 # endif
65 #endif
66 #if HAVE_TZNAME
67 extern char *tzname[];
68 #endif
69
70 /* Do multibyte processing if multibytes are supported, unless
71    multibyte sequences are safe in formats.  Multibyte sequences are
72    safe if they cannot contain byte sequences that look like format
73    conversion specifications.  The GNU C Library uses UTF8 multibyte
74    encoding, which is safe for formats, but strftime.c can be used
75    with other C libraries that use unsafe encodings.  */
76 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
77
78 #if DO_MULTIBYTE
79 # if HAVE_MBRLEN
80 #  include <wchar.h>
81 # else
82    /* Simulate mbrlen with mblen as best we can.  */
83 #  define mbstate_t int
84 #  define mbrlen(s, n, ps) mblen (s, n)
85 #  define mbsinit(ps) (*(ps) == 0)
86 # endif
87   static const mbstate_t mbstate_zero;
88 #endif
89
90 #if HAVE_LIMITS_H
91 # include <limits.h>
92 #endif
93
94 #if STDC_HEADERS
95 # include <stddef.h>
96 # include <stdlib.h>
97 # include <string.h>
98 #else
99 # ifndef HAVE_MEMCPY
100 #  define memcpy(d, s, n) bcopy ((s), (d), (n))
101 # endif
102 #endif
103
104 #ifdef _LIBC
105 # define MEMPCPY(d, s, n) __mempcpy (d, s, n)
106 #else
107 # ifndef HAVE_MEMPCPY
108 #  define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
109 # endif
110 #endif
111
112 #ifndef __P
113 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
114 #  define __P(args) args
115 # else
116 #  define __P(args) ()
117 # endif  /* GCC.  */
118 #endif  /* Not __P.  */
119
120 #ifndef PTR
121 # ifdef __STDC__
122 #  define PTR void *
123 # else
124 #  define PTR char *
125 # endif
126 #endif
127
128 #ifndef CHAR_BIT
129 # define CHAR_BIT 8
130 #endif
131
132 #ifndef NULL
133 # define NULL 0
134 #endif
135
136 #define TYPE_SIGNED(t) ((t) -1 < 0)
137
138 /* Bound on length of the string representing an integer value of type t.
139    Subtract one for the sign bit if t is signed;
140    302 / 1000 is log10 (2) rounded up;
141    add one for integer division truncation;
142    add one more for a minus sign if t is signed.  */
143 #define INT_STRLEN_BOUND(t) \
144   ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
145
146 #define TM_YEAR_BASE 1900
147
148 #ifndef __isleap
149 /* Nonzero if YEAR is a leap year (every 4 years,
150    except every 100th isn't, and every 400th is).  */
151 # define __isleap(year) \
152   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
153 #endif
154
155
156 #ifdef _LIBC
157 # define gmtime_r __gmtime_r
158 # define localtime_r __localtime_r
159 # define tzname __tzname
160 # define tzset __tzset
161 #else
162 # if ! HAVE_LOCALTIME_R
163 #  if ! HAVE_TM_GMTOFF
164 /* Approximate gmtime_r as best we can in its absence.  */
165 #   undef gmtime_r
166 #   define gmtime_r my_gmtime_r
167 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
168 static struct tm *
169 gmtime_r (t, tp)
170      const time_t *t;
171      struct tm *tp;
172 {
173   struct tm *l = gmtime (t);
174   if (! l)
175     return 0;
176   *tp = *l;
177   return tp;
178 }
179 #  endif /* ! HAVE_TM_GMTOFF */
180
181 /* Approximate localtime_r as best we can in its absence.  */
182 #  undef localtime_r
183 #  define localtime_r my_ftime_localtime_r
184 static struct tm *localtime_r __P ((const time_t *, struct tm *));
185 static struct tm *
186 localtime_r (t, tp)
187      const time_t *t;
188      struct tm *tp;
189 {
190   struct tm *l = localtime (t);
191   if (! l)
192     return 0;
193   *tp = *l;
194   return tp;
195 }
196 # endif /* ! HAVE_LOCALTIME_R */
197 #endif /* ! defined _LIBC */
198
199
200 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
201 /* Some systems lack the `memset' function and we don't want to
202    introduce additional dependencies.  */
203 /* The SGI compiler reportedly barfs on the trailing null
204    if we use a string constant as the initializer.  28 June 1997, rms.  */
205 static const char spaces[16] = /* "                " */
206   { ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
207 static const char zeroes[16] = /* "0000000000000000" */
208   { '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' };
209
210 # define memset_space(P, Len) \
211   do {                                                                        \
212     int _len = (Len);                                                         \
213                                                                               \
214     do                                                                        \
215       {                                                                       \
216         int _this = _len > 16 ? 16 : _len;                                    \
217         (P) = MEMPCPY ((P), spaces, _this);                                   \
218         _len -= _this;                                                        \
219       }                                                                       \
220     while (_len > 0);                                                         \
221   } while (0)
222
223 # define memset_zero(P, Len) \
224   do {                                                                        \
225     int _len = (Len);                                                         \
226                                                                               \
227     do                                                                        \
228       {                                                                       \
229         int _this = _len > 16 ? 16 : _len;                                    \
230         (P) = MEMPCPY ((P), zeroes, _this);                                   \
231         _len -= _this;                                                        \
232       }                                                                       \
233     while (_len > 0);                                                         \
234   } while (0)
235 #else
236 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
237 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
238 #endif
239
240 #define add(n, f)                                                             \
241   do                                                                          \
242     {                                                                         \
243       int _n = (n);                                                           \
244       int _delta = width - _n;                                                \
245       int _incr = _n + (_delta > 0 ? _delta : 0);                             \
246       if (i + _incr >= maxsize)                                               \
247         return 0;                                                             \
248       if (p)                                                                  \
249         {                                                                     \
250           if (_delta > 0)                                                     \
251             {                                                                 \
252               if (pad == '0')                                                 \
253                 memset_zero (p, _delta);                                      \
254               else                                                            \
255                 memset_space (p, _delta);                                     \
256             }                                                                 \
257           f;                                                                  \
258           p += _n;                                                            \
259         }                                                                     \
260       i += _incr;                                                             \
261     } while (0)
262
263 #define cpy(n, s) \
264     add ((n),                                                                 \
265          if (to_lowcase)                                                      \
266            memcpy_lowcase (p, (s), _n);                                       \
267          else if (to_uppcase)                                                 \
268            memcpy_uppcase (p, (s), _n);                                       \
269          else                                                                 \
270            memcpy ((PTR) p, (PTR) (s), _n))
271
272
273
274 #ifdef _LIBC
275 # define TOUPPER(Ch) toupper (Ch)
276 # define TOLOWER(Ch) tolower (Ch)
277 #else
278 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
279 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
280 #endif
281 /* We don't use `isdigit' here since the locale dependent
282    interpretation is not what we want here.  We only need to accept
283    the arabic digits in the ASCII range.  One day there is perhaps a
284    more reliable way to accept other sets of digits.  */
285 #define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
286
287 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
288
289 static char *
290 memcpy_lowcase (dest, src, len)
291      char *dest;
292      const char *src;
293      size_t len;
294 {
295   while (len-- > 0)
296     dest[len] = TOLOWER ((unsigned char) src[len]);
297   return dest;
298 }
299
300 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
301
302 static char *
303 memcpy_uppcase (dest, src, len)
304      char *dest;
305      const char *src;
306      size_t len;
307 {
308   while (len-- > 0)
309     dest[len] = TOUPPER ((unsigned char) src[len]);
310   return dest;
311 }
312
313
314 #if ! HAVE_TM_GMTOFF
315 /* Yield the difference between *A and *B,
316    measured in seconds, ignoring leap seconds.  */
317 # define tm_diff ftime_tm_diff
318 static int tm_diff __P ((const struct tm *, const struct tm *));
319 static int
320 tm_diff (a, b)
321      const struct tm *a;
322      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 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
328   int b4 = (b->tm_year >> 2) + (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 = a100 >> 2;
332   int b400 = 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 static int iso_week_days __P ((int, int));
353 #ifdef __GNUC__
354 __inline__
355 #endif
356 static int
357 iso_week_days (yday, wday)
358      int yday;
359      int wday;
360 {
361   /* Add enough to the first operand of % to make it nonnegative.  */
362   int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
363   return (yday
364           - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
365           + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
366 }
367
368
369 #if !(defined _NL_CURRENT || HAVE_STRFTIME)
370 static char const weekday_name[][10] =
371   {
372     "Sunday", "Monday", "Tuesday", "Wednesday",
373     "Thursday", "Friday", "Saturday"
374   };
375 static char const month_name[][10] =
376   {
377     "January", "February", "March", "April", "May", "June",
378     "July", "August", "September", "October", "November", "December"
379   };
380 #endif
381
382
383 #ifdef emacs
384 # define my_strftime emacs_strftime
385  /* Emacs 20.2 uses `-Dstrftime=emacs_strftime' when compiling,
386     because that's how strftime used to be configured.
387     Undo this, since it gets in the way of accessing the underlying strftime,
388     which is needed for things like %Ec in Solaris.
389     The following two lines can be removed once Emacs stops compiling with
390     `-Dstrftime=emacs_strftime'.  */
391 # undef strftime
392 size_t strftime __P ((char *, size_t, const char *, const struct tm *));
393 #else
394 # define my_strftime strftime
395 #endif
396
397 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
398   /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
399      Work around this bug by copying *tp before it might be munged.  */
400   size_t _strftime_copytm __P ((char *, size_t, const char *,
401                                 const struct tm *));
402   size_t
403   my_strftime (s, maxsize, format, tp)
404       char *s;
405       size_t maxsize;
406       const char *format;
407       const struct tm *tp;
408   {
409     struct tm tmcopy;
410     tmcopy = *tp;
411     return _strftime_copytm (s, maxsize, format, &tmcopy);
412   }
413 # undef my_strftime
414 # define my_strftime(S, Maxsize, Format, Tp) \
415   _strftime_copytm (S, Maxsize, Format, Tp)
416 #endif
417
418
419 /* Write information from TP into S according to the format
420    string FORMAT, writing no more that MAXSIZE characters
421    (including the terminating '\0') and returning number of
422    characters written.  If S is NULL, nothing will be written
423    anywhere, so to determine how many characters would be
424    written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */
425 size_t
426 my_strftime (s, maxsize, format, tp)
427       char *s;
428       size_t maxsize;
429       const char *format;
430       const struct tm *tp;
431 {
432   int hour12 = tp->tm_hour;
433 #ifdef _NL_CURRENT
434   const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
435   const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
436   const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
437   const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
438   const char *const ampm = _NL_CURRENT (LC_TIME,
439                                         hour12 > 11 ? PM_STR : AM_STR);
440   size_t aw_len = strlen (a_wkday);
441   size_t am_len = strlen (a_month);
442   size_t ap_len = strlen (ampm);
443 #else
444 # if !HAVE_STRFTIME
445   const char *const f_wkday = weekday_name[tp->tm_wday];
446   const char *const f_month = month_name[tp->tm_mon];
447   const char *const a_wkday = f_wkday;
448   const char *const a_month = f_month;
449   const char *const ampm = "AMPM" + 2 * (hour12 > 11);
450   size_t aw_len = 3;
451   size_t am_len = 3;
452   size_t ap_len = 2;
453 # endif
454 #endif
455 #if defined _NL_CURRENT || !HAVE_STRFTIME
456   size_t wkday_len = strlen (f_wkday);
457   size_t month_len = strlen (f_month);
458 #endif
459   const char *zone;
460   size_t zonelen;
461   size_t i = 0;
462   char *p = s;
463   const char *f;
464
465   zone = NULL;
466 #if HAVE_TM_ZONE
467   /* The POSIX test suite assumes that setting
468      the environment variable TZ to a new value before calling strftime()
469      will influence the result (the %Z format) even if the information in
470      TP is computed with a totally different time zone.
471      This is bogus: though POSIX allows bad behavior like this,
472      POSIX does not require it.  Do the right thing instead.  */
473   zone = (const char *) tp->tm_zone;
474 #endif
475 #if HAVE_TZNAME
476   /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
477      time zone names contained in the external variable `tzname' shall
478      be set as if the tzset() function had been called.  */
479 # if HAVE_TZSET
480   tzset ();
481 # endif
482
483   if (!(zone && *zone) && tp->tm_isdst >= 0)
484     zone = tzname[tp->tm_isdst];
485 #endif
486   if (! zone)
487     zone = "";          /* POSIX.2 requires the empty string here.  */
488
489   zonelen = strlen (zone);
490
491   if (hour12 > 12)
492     hour12 -= 12;
493   else
494     if (hour12 == 0) hour12 = 12;
495
496   for (f = format; *f != '\0'; ++f)
497     {
498       int pad = 0;              /* Padding for number ('-', '_', or 0).  */
499       int modifier;             /* Field modifier ('E', 'O', or 0).  */
500       int digits;               /* Max digits for numeric format.  */
501       int number_value;         /* Numeric value to be printed.  */
502       int negative_number;      /* 1 if the number is negative.  */
503       const char *subfmt;
504       char *bufp;
505       char buf[1 + (sizeof (int) < sizeof (time_t)
506                     ? INT_STRLEN_BOUND (time_t)
507                     : INT_STRLEN_BOUND (int))];
508       int width = -1;
509       int to_lowcase = 0;
510       int to_uppcase = 0;
511       int change_case = 0;
512       int format_char;
513
514 #if DO_MULTIBYTE
515
516        switch (*f)
517         {
518         case '%':
519           break;
520
521         case '\a': case '\b': case '\t': case '\n':
522         case '\v': case '\f': case '\r':
523         case ' ': case '!': case '"': case '#': case '&': case'\'':
524         case '(': case ')': case '*': case '+': case ',': case '-':
525         case '.': case '/': case '0': case '1': case '2': case '3':
526         case '4': case '5': case '6': case '7': case '8': case '9':
527         case ':': case ';': case '<': case '=': case '>': case '?':
528         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
529         case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
530         case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
531         case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
532         case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
533         case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
534         case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
535         case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
536         case 'r': case 's': case 't': case 'u': case 'v': case 'w':
537         case 'x': case 'y': case 'z': case '{': case '|': case '}':
538         case '~':
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           add (1, *p = *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
553             do
554               {
555                 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
556
557                 if (bytes == 0)
558                   break;
559
560                 if (bytes == (size_t) -2 || bytes == (size_t) -1)
561                   {
562                     len++;
563                     break;
564                   }
565
566                 len += bytes;
567               }
568             while (! mbsinit (&mbstate));
569
570             cpy (len, f);
571             continue;
572           }
573         }
574
575 #else /* ! DO_MULTIBYTE */
576
577       /* Either multibyte encodings are not supported, or they are
578          safe for formats, so any non-'%' byte can be copied through.  */
579       if (*f != '%')
580         {
581           add (1, *p = *f);
582           continue;
583         }
584
585 #endif /* ! DO_MULTIBYTE */
586
587       /* Check for flags that can modify a format.  */
588       while (1)
589         {
590           switch (*++f)
591             {
592               /* This influences the number formats.  */
593             case '_':
594             case '-':
595             case '0':
596               pad = *f;
597               continue;
598
599               /* This changes textual output.  */
600             case '^':
601               to_uppcase = 1;
602               continue;
603             case '#':
604               change_case = 1;
605               continue;
606
607             default:
608               break;
609             }
610           break;
611         }
612
613       /* As a GNU extension we allow to specify the field width.  */
614       if (ISDIGIT (*f))
615         {
616           width = 0;
617           do
618             {
619               width *= 10;
620               width += *f - '0';
621               ++f;
622             }
623           while (ISDIGIT (*f));
624         }
625
626       /* Check for modifiers.  */
627       switch (*f)
628         {
629         case 'E':
630         case 'O':
631           modifier = *f++;
632           break;
633
634         default:
635           modifier = 0;
636           break;
637         }
638
639       /* Now do the specified format.  */
640       format_char = *f;
641       switch (format_char)
642         {
643 #define DO_NUMBER(d, v) \
644           digits = width == -1 ? d : width;                                   \
645           number_value = v; goto do_number
646 #define DO_NUMBER_SPACEPAD(d, v) \
647           digits = width == -1 ? d : width;                                   \
648           number_value = v; goto do_number_spacepad
649
650         case '%':
651           if (modifier != 0)
652             goto bad_format;
653           add (1, *p = *f);
654           break;
655
656         case 'a':
657           if (modifier != 0)
658             goto bad_format;
659           if (change_case)
660             {
661               to_uppcase = 1;
662               to_lowcase = 0;
663             }
664 #if defined _NL_CURRENT || !HAVE_STRFTIME
665           cpy (aw_len, a_wkday);
666           break;
667 #else
668           goto underlying_strftime;
669 #endif
670
671         case 'A':
672           if (modifier != 0)
673             goto bad_format;
674           if (change_case)
675             {
676               to_uppcase = 1;
677               to_lowcase = 0;
678             }
679 #if defined _NL_CURRENT || !HAVE_STRFTIME
680           cpy (wkday_len, f_wkday);
681           break;
682 #else
683           goto underlying_strftime;
684 #endif
685
686         case 'b':
687         case 'h':               /* POSIX.2 extension.  */
688           if (modifier != 0)
689             goto bad_format;
690 #if defined _NL_CURRENT || !HAVE_STRFTIME
691           cpy (am_len, a_month);
692           break;
693 #else
694           goto underlying_strftime;
695 #endif
696
697         case 'B':
698           if (modifier != 0)
699             goto bad_format;
700           if (change_case)
701             {
702               to_uppcase = 1;
703               to_lowcase = 0;
704             }
705 #if defined _NL_CURRENT || !HAVE_STRFTIME
706           cpy (month_len, f_month);
707           break;
708 #else
709           goto underlying_strftime;
710 #endif
711
712         case 'c':
713           if (modifier == 'O')
714             goto bad_format;
715 #ifdef _NL_CURRENT
716           if (! (modifier == 'E'
717                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
718             subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
719 #else
720 # if HAVE_STRFTIME
721           goto underlying_strftime;
722 # else
723           subfmt = "%a %b %e %H:%M:%S %Y";
724 # endif
725 #endif
726
727         subformat:
728           {
729             char *old_start = p;
730             size_t len = my_strftime (NULL, maxsize - i, subfmt, tp);
731             if (len == 0 && *subfmt)
732               return 0;
733             add (len, my_strftime (p, maxsize - i, subfmt, tp));
734
735             if (to_uppcase)
736               while (old_start < p)
737                 {
738                   *old_start = TOUPPER ((unsigned char) *old_start);
739                   ++old_start;
740                 }
741           }
742           break;
743
744 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
745         underlying_strftime:
746           {
747             /* The relevant information is available only via the
748                underlying strftime implementation, so use that.  */
749             char ufmt[4];
750             char *u = ufmt;
751             char ubuf[1024]; /* enough for any single format in practice */
752             size_t len;
753             *u++ = '%';
754             if (modifier != 0)
755               *u++ = modifier;
756             *u++ = format_char;
757             *u = '\0';
758             ubuf[0] = '\1';
759             len = strftime (ubuf, sizeof ubuf, ufmt, tp);
760             if (len == 0 && ubuf[0] != '\0')
761               return 0;
762             cpy (len, ubuf);
763           }
764           break;
765 #endif
766
767         case 'C':               /* POSIX.2 extension.  */
768           if (modifier == 'O')
769             goto bad_format;
770           if (modifier == 'E')
771             {
772 #if HAVE_STRUCT_ERA_ENTRY
773               struct era_entry *era = _nl_get_era_entry (tp);
774               if (era)
775                 {
776                   size_t len = strlen (era->name_fmt);
777                   cpy (len, era->name_fmt);
778                   break;
779                 }
780 #else
781 # if HAVE_STRFTIME
782               goto underlying_strftime;
783 # endif
784 #endif
785             }
786
787           {
788             int year = tp->tm_year + TM_YEAR_BASE;
789             DO_NUMBER (1, year / 100 - (year % 100 < 0));
790           }
791
792         case 'x':
793           if (modifier == 'O')
794             goto bad_format;
795 #ifdef _NL_CURRENT
796           if (! (modifier == 'E'
797                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
798             subfmt = _NL_CURRENT (LC_TIME, D_FMT);
799           goto subformat;
800 #else
801 # if HAVE_STRFTIME
802           goto underlying_strftime;
803 # else
804           /* Fall through.  */
805 # endif
806 #endif
807         case 'D':               /* POSIX.2 extension.  */
808           if (modifier != 0)
809             goto bad_format;
810           subfmt = "%m/%d/%y";
811           goto subformat;
812
813         case 'd':
814           if (modifier == 'E')
815             goto bad_format;
816
817           DO_NUMBER (2, tp->tm_mday);
818
819         case 'e':               /* POSIX.2 extension.  */
820           if (modifier == 'E')
821             goto bad_format;
822
823           DO_NUMBER_SPACEPAD (2, tp->tm_mday);
824
825           /* All numeric formats set DIGITS and NUMBER_VALUE and then
826              jump to one of these two labels.  */
827
828         do_number_spacepad:
829           /* Force `_' flag unless overwritten by `0' flag.  */
830           if (pad != '0')
831             pad = '_';
832
833         do_number:
834           /* Format the number according to the MODIFIER flag.  */
835
836           if (modifier == 'O' && 0 <= number_value)
837             {
838 #ifdef _NL_CURRENT
839               /* Get the locale specific alternate representation of
840                  the number NUMBER_VALUE.  If none exist NULL is returned.  */
841               const char *cp = _nl_get_alt_digit (number_value);
842
843               if (cp != NULL)
844                 {
845                   size_t digitlen = strlen (cp);
846                   if (digitlen != 0)
847                     {
848                       cpy (digitlen, cp);
849                       break;
850                     }
851                 }
852 #else
853 # if HAVE_STRFTIME
854               goto underlying_strftime;
855 # endif
856 #endif
857             }
858           {
859             unsigned int u = number_value;
860
861             bufp = buf + sizeof (buf);
862             negative_number = number_value < 0;
863
864             if (negative_number)
865               u = -u;
866
867             do
868               *--bufp = u % 10 + '0';
869             while ((u /= 10) != 0);
870           }
871
872         do_number_sign_and_padding:
873           if (negative_number)
874             *--bufp = '-';
875
876           if (pad != '-')
877             {
878               int padding = digits - (buf + sizeof (buf) - bufp);
879
880               if (pad == '_')
881                 {
882                   while (0 < padding--)
883                     *--bufp = ' ';
884                 }
885               else
886                 {
887                   bufp += negative_number;
888                   while (0 < padding--)
889                     *--bufp = '0';
890                   if (negative_number)
891                     *--bufp = '-';
892                 }
893             }
894
895           cpy (buf + sizeof (buf) - bufp, bufp);
896           break;
897
898         case 'F':
899           if (modifier != 0)
900             goto bad_format;
901           subfmt = "%Y-%m-%d";
902           goto subformat;
903
904         case 'H':
905           if (modifier == 'E')
906             goto bad_format;
907
908           DO_NUMBER (2, tp->tm_hour);
909
910         case 'I':
911           if (modifier == 'E')
912             goto bad_format;
913
914           DO_NUMBER (2, hour12);
915
916         case 'k':               /* GNU extension.  */
917           if (modifier == 'E')
918             goto bad_format;
919
920           DO_NUMBER_SPACEPAD (2, tp->tm_hour);
921
922         case 'l':               /* GNU extension.  */
923           if (modifier == 'E')
924             goto bad_format;
925
926           DO_NUMBER_SPACEPAD (2, hour12);
927
928         case 'j':
929           if (modifier == 'E')
930             goto bad_format;
931
932           DO_NUMBER (3, 1 + tp->tm_yday);
933
934         case 'M':
935           if (modifier == 'E')
936             goto bad_format;
937
938           DO_NUMBER (2, tp->tm_min);
939
940         case 'm':
941           if (modifier == 'E')
942             goto bad_format;
943
944           DO_NUMBER (2, tp->tm_mon + 1);
945
946         case 'n':               /* POSIX.2 extension.  */
947           add (1, *p = '\n');
948           break;
949
950         case 'P':
951           to_lowcase = 1;
952 #if !defined _NL_CURRENT && HAVE_STRFTIME
953           format_char = 'p';
954 #endif
955           /* FALLTHROUGH */
956
957         case 'p':
958           if (change_case)
959             {
960               to_uppcase = 0;
961               to_lowcase = 1;
962             }
963 #if defined _NL_CURRENT || !HAVE_STRFTIME
964           cpy (ap_len, ampm);
965           break;
966 #else
967           goto underlying_strftime;
968 #endif
969
970         case 'R':               /* GNU extension.  */
971           subfmt = "%H:%M";
972           goto subformat;
973
974         case 'r':               /* POSIX.2 extension.  */
975 #ifdef _NL_CURRENT
976           if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
977 #endif
978             subfmt = "%I:%M:%S %p";
979           goto subformat;
980
981         case 'S':
982           if (modifier == 'E')
983             goto bad_format;
984
985           DO_NUMBER (2, tp->tm_sec);
986
987         case 's':               /* GNU extension.  */
988           {
989             struct tm ltm;
990             time_t t;
991
992             ltm = *tp;
993             t = mktime (&ltm);
994
995             /* Generate string value for T using time_t arithmetic;
996                this works even if sizeof (long) < sizeof (time_t).  */
997
998             bufp = buf + sizeof (buf);
999             negative_number = t < 0;
1000
1001             do
1002               {
1003                 int d = t % 10;
1004                 t /= 10;
1005
1006                 if (negative_number)
1007                   {
1008                     d = -d;
1009
1010                     /* Adjust if division truncates to minus infinity.  */
1011                     if (0 < -1 % 10 && d < 0)
1012                       {
1013                         t++;
1014                         d += 10;
1015                       }
1016                   }
1017
1018                 *--bufp = d + '0';
1019               }
1020             while (t != 0);
1021
1022             digits = 1;
1023             goto do_number_sign_and_padding;
1024           }
1025
1026         case 'X':
1027           if (modifier == 'O')
1028             goto bad_format;
1029 #ifdef _NL_CURRENT
1030           if (! (modifier == 'E'
1031                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
1032             subfmt = _NL_CURRENT (LC_TIME, T_FMT);
1033           goto subformat;
1034 #else
1035 # if HAVE_STRFTIME
1036           goto underlying_strftime;
1037 # else
1038           /* Fall through.  */
1039 # endif
1040 #endif
1041         case 'T':               /* POSIX.2 extension.  */
1042           subfmt = "%H:%M:%S";
1043           goto subformat;
1044
1045         case 't':               /* POSIX.2 extension.  */
1046           add (1, *p = '\t');
1047           break;
1048
1049         case 'f':
1050         case 'u':               /* POSIX.2 extension.  */
1051           DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1052
1053         case 'U':
1054           if (modifier == 'E')
1055             goto bad_format;
1056
1057           DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1058
1059         case 'V':
1060         case 'g':               /* GNU extension.  */
1061         case 'G':               /* GNU extension.  */
1062           if (modifier == 'E')
1063             goto bad_format;
1064           {
1065             int year = tp->tm_year + TM_YEAR_BASE;
1066             int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1067
1068             if (days < 0)
1069               {
1070                 /* This ISO week belongs to the previous year.  */
1071                 year--;
1072                 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
1073                                       tp->tm_wday);
1074               }
1075             else
1076               {
1077                 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1078                                        tp->tm_wday);
1079                 if (0 <= d)
1080                   {
1081                     /* This ISO week belongs to the next year.  */
1082                     year++;
1083                     days = d;
1084                   }
1085               }
1086
1087             switch (*f)
1088               {
1089               case 'g':
1090                 DO_NUMBER (2, (year % 100 + 100) % 100);
1091
1092               case 'G':
1093                 DO_NUMBER (1, year);
1094
1095               default:
1096                 DO_NUMBER (2, days / 7 + 1);
1097               }
1098           }
1099
1100         case 'W':
1101           if (modifier == 'E')
1102             goto bad_format;
1103
1104           DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1105
1106         case 'w':
1107           if (modifier == 'E')
1108             goto bad_format;
1109
1110           DO_NUMBER (1, tp->tm_wday);
1111
1112         case 'Y':
1113           if (modifier == 'E')
1114             {
1115 #if HAVE_STRUCT_ERA_ENTRY
1116               struct era_entry *era = _nl_get_era_entry (tp);
1117               if (era)
1118                 {
1119                   subfmt = strchr (era->name_fmt, '\0') + 1;
1120                   goto subformat;
1121                 }
1122 #else
1123 # if HAVE_STRFTIME
1124               goto underlying_strftime;
1125 # endif
1126 #endif
1127             }
1128           if (modifier == 'O')
1129             goto bad_format;
1130           else
1131             DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1132
1133         case 'y':
1134           if (modifier == 'E')
1135             {
1136 #if HAVE_STRUCT_ERA_ENTRY
1137               struct era_entry *era = _nl_get_era_entry (tp);
1138               if (era)
1139                 {
1140                   int delta = tp->tm_year - era->start_date[0];
1141                   DO_NUMBER (1, (era->offset
1142                                  + (era->direction == '-' ? -delta : delta)));
1143                 }
1144 #else
1145 # if HAVE_STRFTIME
1146               goto underlying_strftime;
1147 # endif
1148 #endif
1149             }
1150           DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1151
1152         case 'Z':
1153           if (change_case)
1154             {
1155               to_uppcase = 0;
1156               to_lowcase = 1;
1157             }
1158           cpy (zonelen, zone);
1159           break;
1160
1161         case 'z':               /* GNU extension.  */
1162           if (tp->tm_isdst < 0)
1163             break;
1164
1165           {
1166             int diff;
1167 #if HAVE_TM_GMTOFF
1168             diff = tp->tm_gmtoff;
1169 #else
1170             struct tm gtm;
1171             struct tm ltm;
1172             time_t lt;
1173
1174             ltm = *tp;
1175             lt = mktime (&ltm);
1176
1177             if (lt == (time_t) -1)
1178               {
1179                 /* mktime returns -1 for errors, but -1 is also a
1180                    valid time_t value.  Check whether an error really
1181                    occurred.  */
1182                 struct tm tm;
1183                 localtime_r (&lt, &tm);
1184
1185                 if ((ltm.tm_sec ^ tm.tm_sec)
1186                     | (ltm.tm_min ^ tm.tm_min)
1187                     | (ltm.tm_hour ^ tm.tm_hour)
1188                     | (ltm.tm_mday ^ tm.tm_mday)
1189                     | (ltm.tm_mon ^ tm.tm_mon)
1190                     | (ltm.tm_year ^ tm.tm_year))
1191                   break;
1192               }
1193
1194             if (! gmtime_r (&lt, &gtm))
1195               break;
1196
1197             diff = tm_diff (&ltm, &gtm);
1198 #endif
1199
1200             if (diff < 0)
1201               {
1202                 add (1, *p = '-');
1203                 diff = -diff;
1204               }
1205             else
1206               add (1, *p = '+');
1207
1208             diff /= 60;
1209             DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1210           }
1211
1212         case '\0':              /* GNU extension: % at end of format.  */
1213             --f;
1214             /* Fall through.  */
1215         default:
1216           /* Unknown format; output the format, including the '%',
1217              since this is most likely the right thing to do if a
1218              multibyte string has been misparsed.  */
1219         bad_format:
1220           {
1221             int flen;
1222             for (flen = 1; f[1 - flen] != '%'; flen++)
1223               continue;
1224             cpy (flen, &f[1 - flen]);
1225           }
1226           break;
1227         }
1228     }
1229
1230   if (p)
1231     *p = '\0';
1232   return i;
1233 }