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