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