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