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