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