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