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