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