update from main archive 961217
[platform/upstream/linaro-glibc.git] / time / strftime.c
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96 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 #ifdef _LIBC
24 # define HAVE_LIMITS_H 1
25 # define HAVE_MBLEN 1
26 # define HAVE_MBRLEN 1
27 # define HAVE_STRUCT_ERA_ENTRY 1
28 # define HAVE_TM_GMTOFF 1
29 # define HAVE_TM_ZONE 1
30 # define HAVE_TZNAME 1
31 # define HAVE_TZSET 1
32 # define MULTIBYTE_IS_FORMAT_SAFE 1
33 # define STDC_HEADERS 1
34 # include <ansidecl.h>
35 # include "../locale/localeinfo.h"
36 #endif
37
38 #include <ctype.h>
39 #include <sys/types.h>          /* Some systems define `time_t' here.  */
40
41 #ifdef TIME_WITH_SYS_TIME
42 # include <sys/time.h>
43 # include <time.h>
44 #else
45 # ifdef HAVE_SYS_TIME_H
46 #  include <sys/time.h>
47 # else
48 #  include <time.h>
49 # endif
50 #endif
51 #if HAVE_TZNAME
52 extern char *tzname[];
53 #endif
54
55 /* Do multibyte processing if multibytes are supported, unless
56    multibyte sequences are safe in formats.  Multibyte sequences are
57    safe if they cannot contain byte sequences that look like format
58    conversion specifications.  The GNU C Library uses UTF8 multibyte
59    encoding, which is safe for formats, but strftime.c can be used
60    with other C libraries that use unsafe encodings.  */
61 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
62
63 #if DO_MULTIBYTE
64 # if HAVE_MBRLEN
65 #  include <wchar.h>
66 # else
67    /* Simulate mbrlen with mblen as best we can.  */
68 #  define mbstate_t int
69 #  define mbrlen(s, n, ps) mblen (s, n)
70 #  define mbsinit(ps) (*(ps) == 0)
71 # endif
72   static const mbstate_t mbstate_zero;
73 #endif
74
75 #if HAVE_LIMITS_H
76 # include <limits.h>
77 #endif
78
79 #if STDC_HEADERS
80 # include <stddef.h>
81 # include <stdlib.h>
82 # include <string.h>
83 #else
84 # define memcpy(d, s, n) bcopy ((s), (d), (n))
85 #endif
86
87 #ifndef __P
88 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
89 #define __P(args) args
90 #else
91 #define __P(args) ()
92 #endif  /* GCC.  */
93 #endif  /* Not __P.  */
94
95 #ifndef PTR
96 #ifdef __STDC__
97 #define PTR void *
98 #else
99 #define PTR char *
100 #endif
101 #endif
102
103 #ifndef CHAR_BIT
104 #define CHAR_BIT 8
105 #endif
106
107 #define TYPE_SIGNED(t) ((t) -1 < 0)
108
109 /* Bound on length of the string representing an integer value of type t.
110    Subtract one for the sign bit if t is signed;
111    302 / 1000 is log10 (2) rounded up;
112    add one for integer division truncation;
113    add one more for a minus sign if t is signed.  */
114 #define INT_STRLEN_BOUND(t) \
115   ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
116
117 #define TM_YEAR_BASE 1900
118
119 #ifndef __isleap
120 /* Nonzero if YEAR is a leap year (every 4 years,
121    except every 100th isn't, and every 400th is).  */
122 #define __isleap(year)  \
123   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
124 #endif
125
126
127 #ifdef _LIBC
128 # define gmtime_r __gmtime_r
129 # define localtime_r __localtime_r
130 extern int __tz_compute __P ((time_t timer, const struct tm *tm));
131 # define tzname __tzname
132 # define tzset __tzset
133 #else
134 # if ! HAVE_LOCALTIME_R
135 #  if ! HAVE_TM_GMTOFF
136 /* Approximate gmtime_r as best we can in its absence.  */
137 #define gmtime_r my_gmtime_r
138 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
139 static struct tm *
140 gmtime_r (t, tp)
141      const time_t *t;
142      struct tm *tp;
143 {
144   struct tm *l = gmtime (t);
145   if (! l)
146     return 0;
147   *tp = *l;
148   return tp;
149 }
150 #  endif /* ! HAVE_TM_GMTOFF */
151
152 /* Approximate localtime_r as best we can in its absence.  */
153 #define localtime_r my_localtime_r
154 static struct tm *localtime_r __P ((const time_t *, struct tm *));
155 static struct tm *
156 localtime_r (t, tp)
157      const time_t *t;
158      struct tm *tp;
159 {
160   struct tm *l = localtime (t);
161   if (! l)
162     return 0;
163   *tp = *l;
164   return tp;
165 }
166 # endif /* ! HAVE_LOCALTIME_R */
167 #endif /* ! defined (_LIBC) */
168
169
170 #if !defined (memset) && !defined (HAVE_MEMSET) && !defined (_LIBC)
171 /* Some systems lack the `memset' function and we don't want to
172    introduce additional dependencies.  */
173 static const char spaces[16] = "                ";
174
175 # define memset_space(P, Len) \
176   do {                                                                        \
177     int _len = (Len);                                                         \
178                                                                               \
179     do                                                                        \
180       {                                                                       \
181         int _this = _len > 16 ? 16 : _len;                                    \
182         memcpy ((P), spaces, _this);                                          \
183         (P) += _this;                                                         \
184         _len -= _this;                                                        \
185       }                                                                       \
186     while (_len > 0);                                                         \
187   } while (0)
188 #else
189 # define memset_space(P, Len) memset ((P), ' ', (Len))
190 #endif
191
192 #define add(n, f) \
193   do                                                                          \
194     {                                                                         \
195       int _n = (n);                                                           \
196       int _delta = width - _n;                                                \
197       i += _n + (_delta > 0 ? _delta : 0);                                    \
198       if (i >= maxsize)                                                       \
199         return 0;                                                             \
200       else                                                                    \
201         if (p)                                                                \
202           {                                                                   \
203             if (_delta > 0)                                                   \
204               memset_space (p, _delta);                                       \
205             f;                                                                \
206             p += _n;                                                          \
207           }                                                                   \
208     } while (0)
209
210 #define cpy(n, s) \
211     add ((n),                                                                 \
212          if (to_lowcase)                                                      \
213            memcpy_lowcase (p, (s), _n);                                       \
214          else                                                                 \
215            memcpy ((PTR) p, (PTR) (s), _n))
216
217
218
219 #ifdef _LIBC
220 # define TOUPPER(Ch) toupper (Ch)
221 # define TOLOWER(Ch) tolower (Ch)
222 #else
223 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
224 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
225 #endif
226
227 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
228
229 static char *
230 memcpy_lowcase (dest, src, len)
231      char *dest;
232      const char *src;
233      size_t len;
234 {
235   while (len-- > 0)
236     dest[len] = TOLOWER (src[len]);
237   return dest;
238 }
239
240 #if ! HAVE_TM_GMTOFF
241 /* Yield the difference between *A and *B,
242    measured in seconds, ignoring leap seconds.  */
243 static int tm_diff __P ((const struct tm *, const struct tm *));
244 static int
245 tm_diff (a, b)
246      const struct tm *a;
247      const struct tm *b;
248 {
249   /* Compute intervening leap days correctly even if year is negative.
250      Take care to avoid int overflow in leap day calculations,
251      but it's OK to assume that A and B are close to each other.  */
252   int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
253   int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
254   int a100 = a4 / 25 - (a4 % 25 < 0);
255   int b100 = b4 / 25 - (b4 % 25 < 0);
256   int a400 = a100 >> 2;
257   int b400 = b100 >> 2;
258   int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
259   int years = a->tm_year - b->tm_year;
260   int days = (365 * years + intervening_leap_days
261               + (a->tm_yday - b->tm_yday));
262   return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
263                 + (a->tm_min - b->tm_min))
264           + (a->tm_sec - b->tm_sec));
265 }
266 #endif /* ! HAVE_TM_GMTOFF */
267
268
269
270 /* The number of days from the first day of the first ISO week of this
271    year to the year day YDAY with week day WDAY.  ISO weeks start on
272    Monday; the first ISO week has the year's first Thursday.  YDAY may
273    be as small as YDAY_MINIMUM.  */
274 #define ISO_WEEK_START_WDAY 1 /* Monday */
275 #define ISO_WEEK1_WDAY 4 /* Thursday */
276 #define YDAY_MINIMUM (-366)
277 static int iso_week_days __P ((int, int));
278 #ifdef __GNUC__
279 inline
280 #endif
281 static int
282 iso_week_days (yday, wday)
283      int yday;
284      int wday;
285 {
286   /* Add enough to the first operand of % to make it nonnegative.  */
287   int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
288   return (yday
289           - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
290           + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
291 }
292
293
294 #ifndef _NL_CURRENT
295 static char const weekday_name[][10] =
296   {
297     "Sunday", "Monday", "Tuesday", "Wednesday",
298     "Thursday", "Friday", "Saturday"
299   };
300 static char const month_name[][10] =
301   {
302     "January", "February", "March", "April", "May", "June",
303     "July", "August", "September", "October", "November", "December"
304   };
305 #endif
306
307 /* Write information from TP into S according to the format
308    string FORMAT, writing no more that MAXSIZE characters
309    (including the terminating '\0') and returning number of
310    characters written.  If S is NULL, nothing will be written
311    anywhere, so to determine how many characters would be
312    written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */
313 size_t
314 strftime (s, maxsize, format, tp)
315       char *s;
316       size_t maxsize;
317       const char *format;
318       const struct tm *tp;
319 {
320   int hour12 = tp->tm_hour;
321 #ifdef _NL_CURRENT
322   const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
323   const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
324   const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
325   const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
326   const char *const ampm = _NL_CURRENT (LC_TIME,
327                                         hour12 > 11 ? PM_STR : AM_STR);
328   size_t aw_len = strlen (a_wkday);
329   size_t am_len = strlen (a_month);
330   size_t ap_len = strlen (ampm);
331 #else
332   const char *const f_wkday = weekday_name[tp->tm_wday];
333   const char *const f_month = month_name[tp->tm_mon];
334   const char *const a_wkday = f_wkday;
335   const char *const a_month = f_month;
336   const char *const ampm = "AMPM" + 2 * (hour12 > 11);
337   size_t aw_len = 3;
338   size_t am_len = 3;
339   size_t ap_len = 2;
340 #endif
341   size_t wkday_len = strlen (f_wkday);
342   size_t month_len = strlen (f_month);
343   const char *zone;
344   size_t zonelen;
345   size_t i = 0;
346   char *p = s;
347   const char *f;
348
349   zone = NULL;
350 #if !defined _LIBC && HAVE_TM_ZONE
351   /* XXX We have some problems here.  First, the string pointed to by
352      tm_zone is dynamically allocated while loading the zone data.  But
353      when another zone is loaded since the information in TP were
354      computed this would be a stale pointer.
355      The second problem is the POSIX test suite which assumes setting
356      the environment variable TZ to a new value before calling strftime()
357      will influence the result (the %Z format) even if the information in
358      TP is computed with a totally different time zone.  --drepper@gnu  */
359   zone = (const char *) tp->tm_zone;
360 #endif
361 #if HAVE_TZNAME
362   /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
363      time zone names contained in the external variable `tzname' shall
364      be set as if the tzset() function had been called.  */
365 # if HAVE_TZSET
366   tzset ();
367 # endif
368
369   if (!(zone && *zone) && tp->tm_isdst >= 0)
370     zone = tzname[tp->tm_isdst];
371 #endif
372   if (! zone)
373     zone = "";          /* POSIX.2 requires the empty string here.  */
374
375   zonelen = strlen (zone);
376
377   if (hour12 > 12)
378     hour12 -= 12;
379   else
380     if (hour12 == 0) hour12 = 12;
381
382   for (f = format; *f != '\0'; ++f)
383     {
384       int pad;                  /* Padding for number ('-', '_', or 0).  */
385       int modifier;             /* Field modifier ('E', 'O', or 0).  */
386       int digits;               /* Max digits for numeric format.  */
387       int number_value;         /* Numeric value to be printed.  */
388       int negative_number;      /* 1 if the number is negative.  */
389       const char *subfmt;
390       char *bufp;
391       char buf[1 + (sizeof (int) < sizeof (time_t)
392                     ? INT_STRLEN_BOUND (time_t)
393                     : INT_STRLEN_BOUND (int))];
394       int width = -1;
395       int to_lowcase = 0;
396
397 #if DO_MULTIBYTE
398
399        switch (*f)
400         {
401         case '%':
402           break;
403
404         case '\a': case '\b': case '\t': case '\n':
405         case '\v': case '\f': case '\r':
406         case ' ': case '!': case '"': case '#': case '&': case'\'':
407         case '(': case ')': case '*': case '+': case ',': case '-':
408         case '.': case '/': case '0': case '1': case '2': case '3':
409         case '4': case '5': case '6': case '7': case '8': case '9':
410         case ':': case ';': case '<': case '=': case '>': case '?':
411         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
412         case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
413         case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
414         case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
415         case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
416         case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
417         case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
418         case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
419         case 'r': case 's': case 't': case 'u': case 'v': case 'w':
420         case 'x': case 'y': case 'z': case '{': case '|': case '}':
421         case '~':
422           /* The C Standard requires these 98 characters (plus '%') to
423              be in the basic execution character set.  None of these
424              characters can start a multibyte sequence, so they need
425              not be analyzed further.  */
426           add (1, *p = *f);
427           continue;
428
429         default:
430           /* Copy this multibyte sequence until we reach its end, find
431              an error, or come back to the initial shift state.  */
432           {
433             mbstate_t mbstate = mbstate_zero;
434             size_t len = 0;
435
436             do
437               {
438                 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
439
440                 if (bytes == 0)
441                   break;
442
443                 if (bytes == (size_t) -2 || bytes == (size_t) -1)
444                   {
445                     len++;
446                     break;
447                   }
448
449                 len += bytes;
450               }
451             while (! mbsinit (&mbstate));
452
453             cpy (len, f);
454             continue;
455           }
456         }
457
458 #else /* ! DO_MULTIBYTE */
459
460       /* Either multibyte encodings are not supported, or they are
461          safe for formats, so any non-'%' byte can be copied through.  */
462       if (*f != '%')
463         {
464           add (1, *p = *f);
465           continue;
466         }
467
468 #endif /* ! DO_MULTIBYTE */
469
470       /* Check for flags that can modify a number format.  */
471       ++f;
472       while (1)
473         {
474           switch (*f)
475             {
476             case '_':
477             case '-':
478             case '0':
479               pad = *f++;
480               break;
481
482             default:
483               pad = 0;
484               break;
485             }
486           break;
487         }
488
489       /* As a GNU extension we allow to specify the field width.  */
490       if (isdigit (*f))
491         {
492           width = 0;
493           do
494             {
495               width *= 10;
496               width += *f - '0';
497             }
498           while (isdigit (*++f));
499         }
500
501       /* Check for modifiers.  */
502       switch (*f)
503         {
504         case 'E':
505         case 'O':
506           modifier = *f++;
507           break;
508
509         default:
510           modifier = 0;
511           break;
512         }
513
514       /* Now do the specified format.  */
515       switch (*f)
516         {
517 #define DO_NUMBER(d, v) \
518           digits = d; number_value = v; goto do_number
519 #define DO_NUMBER_SPACEPAD(d, v) \
520           digits = d; number_value = v; goto do_number_spacepad
521
522         case '%':
523           if (modifier != 0)
524             goto bad_format;
525           add (1, *p = *f);
526           break;
527
528         case 'a':
529           if (modifier != 0)
530             goto bad_format;
531           cpy (aw_len, a_wkday);
532           break;
533
534         case 'A':
535           if (modifier != 0)
536             goto bad_format;
537           cpy (wkday_len, f_wkday);
538           break;
539
540         case 'b':
541         case 'h':               /* POSIX.2 extension.  */
542           if (modifier != 0)
543             goto bad_format;
544           cpy (am_len, a_month);
545           break;
546
547         case 'B':
548           if (modifier != 0)
549             goto bad_format;
550           cpy (month_len, f_month);
551           break;
552
553         case 'c':
554           if (modifier == 'O')
555             goto bad_format;
556 #ifdef _NL_CURRENT
557           if (! (modifier == 'E'
558                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
559             subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
560 #else
561           subfmt = "%a %b %e %H:%M:%S %Y";
562 #endif
563
564         subformat:
565           {
566             size_t len = strftime (NULL, maxsize - i, subfmt, tp);
567             if (len == 0 && *subfmt)
568               return 0;
569             add (len, strftime (p, maxsize - i, subfmt, tp));
570           }
571           break;
572
573         case 'C':               /* POSIX.2 extension.  */
574           if (modifier == 'O')
575             goto bad_format;
576 #if HAVE_STRUCT_ERA_ENTRY
577           if (modifier == 'E')
578             {
579               struct era_entry *era = _nl_get_era_entry (tp);
580               if (era)
581                 {
582                   size_t len = strlen (era->name_fmt);
583                   cpy (len, era->name_fmt);
584                   break;
585                 }
586             }
587 #endif
588           {
589             int year = tp->tm_year + TM_YEAR_BASE;
590             DO_NUMBER (1, year / 100 - (year % 100 < 0));
591           }
592
593         case 'x':
594           if (modifier == 'O')
595             goto bad_format;
596 #ifdef _NL_CURRENT
597           if (! (modifier == 'E'
598                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
599             subfmt = _NL_CURRENT (LC_TIME, D_FMT);
600           goto subformat;
601 #endif
602           /* Fall through.  */
603         case 'D':               /* POSIX.2 extension.  */
604           if (modifier != 0)
605             goto bad_format;
606           subfmt = "%m/%d/%y";
607           goto subformat;
608
609         case 'd':
610           if (modifier == 'E')
611             goto bad_format;
612
613           DO_NUMBER (2, tp->tm_mday);
614
615         case 'e':               /* POSIX.2 extension.  */
616           if (modifier == 'E')
617             goto bad_format;
618
619           DO_NUMBER_SPACEPAD (2, tp->tm_mday);
620
621           /* All numeric formats set DIGITS and NUMBER_VALUE and then
622              jump to one of these two labels.  */
623
624         do_number_spacepad:
625           /* Force `_' flag unless overwritten by `0' flag.  */
626           if (pad != '0')
627             pad = '_';
628
629         do_number:
630           /* Format the number according to the MODIFIER flag.  */
631
632 #ifdef _NL_CURRENT
633           if (modifier == 'O' && 0 <= number_value)
634             {
635               /* Get the locale specific alternate representation of
636                  the number NUMBER_VALUE.  If none exist NULL is returned.  */
637               const char *cp = _nl_get_alt_digit (number_value);
638
639               if (cp != NULL)
640                 {
641                   size_t digitlen = strlen (cp);
642                   if (digitlen != 0)
643                     {
644                       cpy (digitlen, cp);
645                       break;
646                     }
647                 }
648             }
649 #endif
650           {
651             unsigned int u = number_value;
652
653             bufp = buf + sizeof (buf);
654             negative_number = number_value < 0;
655
656             if (negative_number)
657               u = -u;
658
659             do
660               *--bufp = u % 10 + '0';
661             while ((u /= 10) != 0);
662           }
663
664         do_number_sign_and_padding:
665           if (negative_number)
666             *--bufp = '-';
667
668           if (pad != '-')
669             {
670               int padding = digits - (buf + sizeof (buf) - bufp);
671
672               if (pad == '_')
673                 {
674                   while (0 < padding--)
675                     *--bufp = ' ';
676                 }
677               else
678                 {
679                   bufp += negative_number;
680                   while (0 < padding--)
681                     *--bufp = '0';
682                   if (negative_number)
683                     *--bufp = '-';
684                 }
685             }
686
687           cpy (buf + sizeof (buf) - bufp, bufp);
688           break;
689
690
691         case 'H':
692           if (modifier == 'E')
693             goto bad_format;
694
695           DO_NUMBER (2, tp->tm_hour);
696
697         case 'I':
698           if (modifier == 'E')
699             goto bad_format;
700
701           DO_NUMBER (2, hour12);
702
703         case 'k':               /* GNU extension.  */
704           if (modifier == 'E')
705             goto bad_format;
706
707           DO_NUMBER_SPACEPAD (2, tp->tm_hour);
708
709         case 'l':               /* GNU extension.  */
710           if (modifier == 'E')
711             goto bad_format;
712
713           DO_NUMBER_SPACEPAD (2, hour12);
714
715         case 'j':
716           if (modifier == 'E')
717             goto bad_format;
718
719           DO_NUMBER (3, 1 + tp->tm_yday);
720
721         case 'M':
722           if (modifier == 'E')
723             goto bad_format;
724
725           DO_NUMBER (2, tp->tm_min);
726
727         case 'm':
728           if (modifier == 'E')
729             goto bad_format;
730
731           DO_NUMBER (2, tp->tm_mon + 1);
732
733         case 'n':               /* POSIX.2 extension.  */
734           add (1, *p = '\n');
735           break;
736
737         case 'P':
738           to_lowcase = 1;
739           /* FALLTHROUGH */
740
741         case 'p':
742           cpy (ap_len, ampm);
743           break;
744
745         case 'R':               /* GNU extension.  */
746           subfmt = "%H:%M";
747           goto subformat;
748
749         case 'r':               /* POSIX.2 extension.  */
750 #ifdef _NL_CURRENT
751           if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
752 #endif
753             subfmt = "%I:%M:%S %p";
754           goto subformat;
755
756         case 'S':
757           if (modifier == 'E')
758             goto bad_format;
759
760           DO_NUMBER (2, tp->tm_sec);
761
762         case 's':               /* GNU extension.  */
763           {
764             struct tm ltm;
765             time_t t;
766
767             ltm = *tp;
768             t = mktime (&ltm);
769
770             /* Generate string value for T using time_t arithmetic;
771                this works even if sizeof (long) < sizeof (time_t).  */
772
773             bufp = buf + sizeof (buf);
774             negative_number = t < 0;
775
776             do
777               {
778                 int d = t % 10;
779                 t /= 10;
780
781                 if (negative_number)
782                   {
783                     d = -d;
784
785                     /* Adjust if division truncates to minus infinity.  */
786                     if (0 < -1 % 10 && d < 0)
787                       {
788                         t++;
789                         d += 10;
790                       }
791                   }
792
793                 *--bufp = d + '0';
794               }
795             while (t != 0);
796
797             digits = 1;
798             goto do_number_sign_and_padding;
799           }
800
801         case 'X':
802           if (modifier == 'O')
803             goto bad_format;
804 #ifdef _NL_CURRENT
805           if (! (modifier == 'E'
806                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
807             subfmt = _NL_CURRENT (LC_TIME, T_FMT);
808           goto subformat;
809 #endif
810           /* Fall through.  */
811         case 'T':               /* POSIX.2 extension.  */
812           subfmt = "%H:%M:%S";
813           goto subformat;
814
815         case 't':               /* POSIX.2 extension.  */
816           add (1, *p = '\t');
817           break;
818
819         case 'u':               /* POSIX.2 extension.  */
820           DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
821
822         case 'U':
823           if (modifier == 'E')
824             goto bad_format;
825
826           DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
827
828         case 'V':
829         case 'g':               /* GNU extension.  */
830         case 'G':               /* GNU extension.  */
831           if (modifier == 'E')
832             goto bad_format;
833           {
834             int year = tp->tm_year + TM_YEAR_BASE;
835             int days = iso_week_days (tp->tm_yday, tp->tm_wday);
836
837             if (days < 0)
838               {
839                 /* This ISO week belongs to the previous year.  */
840                 year--;
841                 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
842                                       tp->tm_wday);
843               }
844             else
845               {
846                 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
847                                        tp->tm_wday);
848                 if (0 <= d)
849                   {
850                     /* This ISO week belongs to the next year.  */
851                     year++;
852                     days = d;
853                   }
854               }
855
856             switch (*f)
857               {
858               case 'g':
859                 DO_NUMBER (2, (year % 100 + 100) % 100);
860
861               case 'G':
862                 DO_NUMBER (1, year);
863
864               default:
865                 DO_NUMBER (2, days / 7 + 1);
866               }
867           }
868
869         case 'W':
870           if (modifier == 'E')
871             goto bad_format;
872
873           DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
874
875         case 'w':
876           if (modifier == 'E')
877             goto bad_format;
878
879           DO_NUMBER (1, tp->tm_wday);
880
881         case 'Y':
882 #if HAVE_STRUCT_ERA_ENTRY
883           if (modifier == 'E')
884             {
885               struct era_entry *era = _nl_get_era_entry (tp);
886               if (era)
887                 {
888                   subfmt = strchr (era->name_fmt, '\0') + 1;
889                   goto subformat;
890                 }
891             }
892 #endif
893           if (modifier == 'O')
894             goto bad_format;
895           else
896             DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
897
898         case 'y':
899 #if HAVE_STRUCT_ERA_ENTRY
900           if (modifier == 'E')
901             {
902               struct era_entry *era = _nl_get_era_entry (tp);
903               if (era)
904                 {
905                   int delta = tp->tm_year - era->start_date[0];
906                   DO_NUMBER (1, (era->offset
907                                  + (era->direction == '-' ? -delta : delta)));
908                 }
909             }
910 #endif
911           DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
912
913         case 'Z':
914           cpy (zonelen, zone);
915           break;
916
917         case 'z':               /* GNU extension.  */
918           if (tp->tm_isdst < 0)
919             break;
920
921           {
922             int diff;
923 #if HAVE_TM_GMTOFF
924             diff = tp->tm_gmtoff;
925 #else
926             struct tm gtm;
927             struct tm ltm;
928             time_t lt;
929
930             ltm = *tp;
931             lt = mktime (&ltm);
932
933             if (lt == (time_t) -1)
934               {
935                 /* mktime returns -1 for errors, but -1 is also a
936                    valid time_t value.  Check whether an error really
937                    occurred.  */
938                 struct tm tm;
939                 localtime_r (&lt, &tm);
940
941                 if ((ltm.tm_sec ^ tm.tm_sec)
942                     | (ltm.tm_min ^ tm.tm_min)
943                     | (ltm.tm_hour ^ tm.tm_hour)
944                     | (ltm.tm_mday ^ tm.tm_mday)
945                     | (ltm.tm_mon ^ tm.tm_mon)
946                     | (ltm.tm_year ^ tm.tm_year))
947                   break;
948               }
949
950             if (! gmtime_r (&lt, &gtm))
951               break;
952
953             diff = tm_diff (&ltm, &gtm);
954 #endif
955
956             if (diff < 0)
957               {
958                 add (1, *p = '-');
959                 diff = -diff;
960               }
961             else
962               add (1, *p = '+');
963
964             diff /= 60;
965             DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
966           }
967
968         case '\0':              /* GNU extension: % at end of format.  */
969             --f;
970             /* Fall through.  */
971         default:
972           /* Unknown format; output the format, including the '%',
973              since this is most likely the right thing to do if a
974              multibyte string has been misparsed.  */
975         bad_format:
976           {
977             int flen;
978             for (flen = 1; f[1 - flen] != '%'; flen++)
979               continue;
980             cpy (flen, &f[1 - flen]);
981           }
982           break;
983         }
984     }
985
986   if (p)
987     *p = '\0';
988   return i;
989 }