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