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