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