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