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