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