update from automake-1.1o
[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 _strftime_copytm
353 #endif
354
355
356
357 /* Write information from TP into S according to the format
358    string FORMAT, writing no more that MAXSIZE characters
359    (including the terminating '\0') and returning number of
360    characters written.  If S is NULL, nothing will be written
361    anywhere, so to determine how many characters would be
362    written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */
363 size_t
364 strftime (s, maxsize, format, tp)
365       char *s;
366       size_t maxsize;
367       const char *format;
368       const struct tm *tp;
369 {
370   int hour12 = tp->tm_hour;
371 #ifdef _NL_CURRENT
372   const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
373   const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
374   const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
375   const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
376   const char *const ampm = _NL_CURRENT (LC_TIME,
377                                         hour12 > 11 ? PM_STR : AM_STR);
378   size_t aw_len = strlen (a_wkday);
379   size_t am_len = strlen (a_month);
380   size_t ap_len = strlen (ampm);
381 #else
382   const char *const f_wkday = weekday_name[tp->tm_wday];
383   const char *const f_month = month_name[tp->tm_mon];
384   const char *const a_wkday = f_wkday;
385   const char *const a_month = f_month;
386   const char *const ampm = "AMPM" + 2 * (hour12 > 11);
387   size_t aw_len = 3;
388   size_t am_len = 3;
389   size_t ap_len = 2;
390 #endif
391   size_t wkday_len = strlen (f_wkday);
392   size_t month_len = strlen (f_month);
393   const char *zone;
394   size_t zonelen;
395   size_t i = 0;
396   char *p = s;
397   const char *f;
398
399   zone = NULL;
400 #if !defined _LIBC && HAVE_TM_ZONE
401   /* XXX We have some problems here.  First, the string pointed to by
402      tm_zone is dynamically allocated while loading the zone data.  But
403      when another zone is loaded since the information in TP were
404      computed this would be a stale pointer.
405      The second problem is the POSIX test suite which assumes setting
406      the environment variable TZ to a new value before calling strftime()
407      will influence the result (the %Z format) even if the information in
408      TP is computed with a totally different time zone.  --drepper@gnu  */
409   zone = (const char *) tp->tm_zone;
410 #endif
411 #if HAVE_TZNAME
412   /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
413      time zone names contained in the external variable `tzname' shall
414      be set as if the tzset() function had been called.  */
415 # if HAVE_TZSET
416   tzset ();
417 # endif
418
419   if (!(zone && *zone) && tp->tm_isdst >= 0)
420     zone = tzname[tp->tm_isdst];
421 #endif
422   if (! zone)
423     zone = "";          /* POSIX.2 requires the empty string here.  */
424
425   zonelen = strlen (zone);
426
427   if (hour12 > 12)
428     hour12 -= 12;
429   else
430     if (hour12 == 0) hour12 = 12;
431
432   for (f = format; *f != '\0'; ++f)
433     {
434       int pad;                  /* Padding for number ('-', '_', or 0).  */
435       int modifier;             /* Field modifier ('E', 'O', or 0).  */
436       int digits;               /* Max digits for numeric format.  */
437       int number_value;         /* Numeric value to be printed.  */
438       int negative_number;      /* 1 if the number is negative.  */
439       const char *subfmt;
440       char *bufp;
441       char buf[1 + (sizeof (int) < sizeof (time_t)
442                     ? INT_STRLEN_BOUND (time_t)
443                     : INT_STRLEN_BOUND (int))];
444       int width = -1;
445       int to_lowcase = 0;
446       int to_uppcase = 0;
447
448 #if DO_MULTIBYTE
449
450        switch (*f)
451         {
452         case '%':
453           break;
454
455         case '\a': case '\b': case '\t': case '\n':
456         case '\v': case '\f': case '\r':
457         case ' ': case '!': case '"': case '#': case '&': case'\'':
458         case '(': case ')': case '*': case '+': case ',': case '-':
459         case '.': case '/': case '0': case '1': case '2': case '3':
460         case '4': case '5': case '6': case '7': case '8': case '9':
461         case ':': case ';': case '<': case '=': case '>': case '?':
462         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
463         case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
464         case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
465         case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
466         case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
467         case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
468         case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
469         case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
470         case 'r': case 's': case 't': case 'u': case 'v': case 'w':
471         case 'x': case 'y': case 'z': case '{': case '|': case '}':
472         case '~':
473           /* The C Standard requires these 98 characters (plus '%') to
474              be in the basic execution character set.  None of these
475              characters can start a multibyte sequence, so they need
476              not be analyzed further.  */
477           add (1, *p = *f);
478           continue;
479
480         default:
481           /* Copy this multibyte sequence until we reach its end, find
482              an error, or come back to the initial shift state.  */
483           {
484             mbstate_t mbstate = mbstate_zero;
485             size_t len = 0;
486
487             do
488               {
489                 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
490
491                 if (bytes == 0)
492                   break;
493
494                 if (bytes == (size_t) -2 || bytes == (size_t) -1)
495                   {
496                     len++;
497                     break;
498                   }
499
500                 len += bytes;
501               }
502             while (! mbsinit (&mbstate));
503
504             cpy (len, f);
505             continue;
506           }
507         }
508
509 #else /* ! DO_MULTIBYTE */
510
511       /* Either multibyte encodings are not supported, or they are
512          safe for formats, so any non-'%' byte can be copied through.  */
513       if (*f != '%')
514         {
515           add (1, *p = *f);
516           continue;
517         }
518
519 #endif /* ! DO_MULTIBYTE */
520
521       /* Check for flags that can modify a format.  */
522       pad = 0;
523       while (1)
524         {
525           switch (*++f)
526             {
527               /* This influences the number formats.  */
528             case '_':
529             case '-':
530             case '0':
531               pad = *f;
532               continue;
533
534               /* This changes textual output.  */
535             case '^':
536               to_uppcase = 1;
537               continue;
538
539             default:
540               break;
541             }
542           break;
543         }
544
545       /* As a GNU extension we allow to specify the field width.  */
546       if (ISDIGIT (*f))
547         {
548           width = 0;
549           do
550             {
551               width *= 10;
552               width += *f - '0';
553               ++f;
554             }
555           while (ISDIGIT (*f));
556         }
557
558       /* Check for modifiers.  */
559       switch (*f)
560         {
561         case 'E':
562         case 'O':
563           modifier = *f++;
564           break;
565
566         default:
567           modifier = 0;
568           break;
569         }
570
571       /* Now do the specified format.  */
572       switch (*f)
573         {
574 #define DO_NUMBER(d, v) \
575           digits = d; number_value = v; goto do_number
576 #define DO_NUMBER_SPACEPAD(d, v) \
577           digits = d; number_value = v; goto do_number_spacepad
578
579         case '%':
580           if (modifier != 0)
581             goto bad_format;
582           add (1, *p = *f);
583           break;
584
585         case 'a':
586           if (modifier != 0)
587             goto bad_format;
588           cpy (aw_len, a_wkday);
589           break;
590
591         case 'A':
592           if (modifier != 0)
593             goto bad_format;
594           cpy (wkday_len, f_wkday);
595           break;
596
597         case 'b':
598         case 'h':               /* POSIX.2 extension.  */
599           if (modifier != 0)
600             goto bad_format;
601           cpy (am_len, a_month);
602           break;
603
604         case 'B':
605           if (modifier != 0)
606             goto bad_format;
607           cpy (month_len, f_month);
608           break;
609
610         case 'c':
611           if (modifier == 'O')
612             goto bad_format;
613 #ifdef _NL_CURRENT
614           if (! (modifier == 'E'
615                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
616             subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
617 #else
618           subfmt = "%a %b %e %H:%M:%S %Y";
619 #endif
620
621         subformat:
622           {
623             char *old_start = p;
624             size_t len = strftime (NULL, maxsize - i, subfmt, tp);
625             if (len == 0 && *subfmt)
626               return 0;
627             add (len, strftime (p, maxsize - i, subfmt, tp));
628
629             if (to_uppcase)
630               while (old_start < p)
631                 {
632                   *old_start = TOUPPER (*old_start);
633                   ++old_start;
634                 }
635           }
636           break;
637
638         case 'C':               /* POSIX.2 extension.  */
639           if (modifier == 'O')
640             goto bad_format;
641 #if HAVE_STRUCT_ERA_ENTRY
642           if (modifier == 'E')
643             {
644               struct era_entry *era = _nl_get_era_entry (tp);
645               if (era)
646                 {
647                   size_t len = strlen (era->name_fmt);
648                   cpy (len, era->name_fmt);
649                   break;
650                 }
651             }
652 #endif
653           {
654             int year = tp->tm_year + TM_YEAR_BASE;
655             DO_NUMBER (1, year / 100 - (year % 100 < 0));
656           }
657
658         case 'x':
659           if (modifier == 'O')
660             goto bad_format;
661 #ifdef _NL_CURRENT
662           if (! (modifier == 'E'
663                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
664             subfmt = _NL_CURRENT (LC_TIME, D_FMT);
665           goto subformat;
666 #endif
667           /* Fall through.  */
668         case 'D':               /* POSIX.2 extension.  */
669           if (modifier != 0)
670             goto bad_format;
671           subfmt = "%m/%d/%y";
672           goto subformat;
673
674         case 'd':
675           if (modifier == 'E')
676             goto bad_format;
677
678           DO_NUMBER (2, tp->tm_mday);
679
680         case 'e':               /* POSIX.2 extension.  */
681           if (modifier == 'E')
682             goto bad_format;
683
684           DO_NUMBER_SPACEPAD (2, tp->tm_mday);
685
686           /* All numeric formats set DIGITS and NUMBER_VALUE and then
687              jump to one of these two labels.  */
688
689         do_number_spacepad:
690           /* Force `_' flag unless overwritten by `0' flag.  */
691           if (pad != '0')
692             pad = '_';
693
694         do_number:
695           /* Format the number according to the MODIFIER flag.  */
696
697 #ifdef _NL_CURRENT
698           if (modifier == 'O' && 0 <= number_value)
699             {
700               /* Get the locale specific alternate representation of
701                  the number NUMBER_VALUE.  If none exist NULL is returned.  */
702               const char *cp = _nl_get_alt_digit (number_value);
703
704               if (cp != NULL)
705                 {
706                   size_t digitlen = strlen (cp);
707                   if (digitlen != 0)
708                     {
709                       cpy (digitlen, cp);
710                       break;
711                     }
712                 }
713             }
714 #endif
715           {
716             unsigned int u = number_value;
717
718             bufp = buf + sizeof (buf);
719             negative_number = number_value < 0;
720
721             if (negative_number)
722               u = -u;
723
724             do
725               *--bufp = u % 10 + '0';
726             while ((u /= 10) != 0);
727           }
728
729         do_number_sign_and_padding:
730           if (negative_number)
731             *--bufp = '-';
732
733           if (pad != '-')
734             {
735               int padding = digits - (buf + sizeof (buf) - bufp);
736
737               if (pad == '_')
738                 {
739                   while (0 < padding--)
740                     *--bufp = ' ';
741                 }
742               else
743                 {
744                   bufp += negative_number;
745                   while (0 < padding--)
746                     *--bufp = '0';
747                   if (negative_number)
748                     *--bufp = '-';
749                 }
750             }
751
752           cpy (buf + sizeof (buf) - bufp, bufp);
753           break;
754
755
756         case 'H':
757           if (modifier == 'E')
758             goto bad_format;
759
760           DO_NUMBER (2, tp->tm_hour);
761
762         case 'I':
763           if (modifier == 'E')
764             goto bad_format;
765
766           DO_NUMBER (2, hour12);
767
768         case 'k':               /* GNU extension.  */
769           if (modifier == 'E')
770             goto bad_format;
771
772           DO_NUMBER_SPACEPAD (2, tp->tm_hour);
773
774         case 'l':               /* GNU extension.  */
775           if (modifier == 'E')
776             goto bad_format;
777
778           DO_NUMBER_SPACEPAD (2, hour12);
779
780         case 'j':
781           if (modifier == 'E')
782             goto bad_format;
783
784           DO_NUMBER (3, 1 + tp->tm_yday);
785
786         case 'M':
787           if (modifier == 'E')
788             goto bad_format;
789
790           DO_NUMBER (2, tp->tm_min);
791
792         case 'm':
793           if (modifier == 'E')
794             goto bad_format;
795
796           DO_NUMBER (2, tp->tm_mon + 1);
797
798         case 'n':               /* POSIX.2 extension.  */
799           add (1, *p = '\n');
800           break;
801
802         case 'P':
803           to_lowcase = 1;
804           /* FALLTHROUGH */
805
806         case 'p':
807           cpy (ap_len, ampm);
808           break;
809
810         case 'R':               /* GNU extension.  */
811           subfmt = "%H:%M";
812           goto subformat;
813
814         case 'r':               /* POSIX.2 extension.  */
815 #ifdef _NL_CURRENT
816           if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
817 #endif
818             subfmt = "%I:%M:%S %p";
819           goto subformat;
820
821         case 'S':
822           if (modifier == 'E')
823             goto bad_format;
824
825           DO_NUMBER (2, tp->tm_sec);
826
827         case 's':               /* GNU extension.  */
828           {
829             struct tm ltm;
830             time_t t;
831
832             ltm = *tp;
833             t = mktime (&ltm);
834
835             /* Generate string value for T using time_t arithmetic;
836                this works even if sizeof (long) < sizeof (time_t).  */
837
838             bufp = buf + sizeof (buf);
839             negative_number = t < 0;
840
841             do
842               {
843                 int d = t % 10;
844                 t /= 10;
845
846                 if (negative_number)
847                   {
848                     d = -d;
849
850                     /* Adjust if division truncates to minus infinity.  */
851                     if (0 < -1 % 10 && d < 0)
852                       {
853                         t++;
854                         d += 10;
855                       }
856                   }
857
858                 *--bufp = d + '0';
859               }
860             while (t != 0);
861
862             digits = 1;
863             goto do_number_sign_and_padding;
864           }
865
866         case 'X':
867           if (modifier == 'O')
868             goto bad_format;
869 #ifdef _NL_CURRENT
870           if (! (modifier == 'E'
871                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
872             subfmt = _NL_CURRENT (LC_TIME, T_FMT);
873           goto subformat;
874 #endif
875           /* Fall through.  */
876         case 'T':               /* POSIX.2 extension.  */
877           subfmt = "%H:%M:%S";
878           goto subformat;
879
880         case 't':               /* POSIX.2 extension.  */
881           add (1, *p = '\t');
882           break;
883
884         case 'u':               /* POSIX.2 extension.  */
885           DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
886
887         case 'U':
888           if (modifier == 'E')
889             goto bad_format;
890
891           DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
892
893         case 'V':
894         case 'g':               /* GNU extension.  */
895         case 'G':               /* GNU extension.  */
896           if (modifier == 'E')
897             goto bad_format;
898           {
899             int year = tp->tm_year + TM_YEAR_BASE;
900             int days = iso_week_days (tp->tm_yday, tp->tm_wday);
901
902             if (days < 0)
903               {
904                 /* This ISO week belongs to the previous year.  */
905                 year--;
906                 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
907                                       tp->tm_wday);
908               }
909             else
910               {
911                 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
912                                        tp->tm_wday);
913                 if (0 <= d)
914                   {
915                     /* This ISO week belongs to the next year.  */
916                     year++;
917                     days = d;
918                   }
919               }
920
921             switch (*f)
922               {
923               case 'g':
924                 DO_NUMBER (2, (year % 100 + 100) % 100);
925
926               case 'G':
927                 DO_NUMBER (1, year);
928
929               default:
930                 DO_NUMBER (2, days / 7 + 1);
931               }
932           }
933
934         case 'W':
935           if (modifier == 'E')
936             goto bad_format;
937
938           DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
939
940         case 'w':
941           if (modifier == 'E')
942             goto bad_format;
943
944           DO_NUMBER (1, tp->tm_wday);
945
946         case 'Y':
947 #if HAVE_STRUCT_ERA_ENTRY
948           if (modifier == 'E')
949             {
950               struct era_entry *era = _nl_get_era_entry (tp);
951               if (era)
952                 {
953                   subfmt = strchr (era->name_fmt, '\0') + 1;
954                   goto subformat;
955                 }
956             }
957 #endif
958           if (modifier == 'O')
959             goto bad_format;
960           else
961             DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
962
963         case 'y':
964 #if HAVE_STRUCT_ERA_ENTRY
965           if (modifier == 'E')
966             {
967               struct era_entry *era = _nl_get_era_entry (tp);
968               if (era)
969                 {
970                   int delta = tp->tm_year - era->start_date[0];
971                   DO_NUMBER (1, (era->offset
972                                  + (era->direction == '-' ? -delta : delta)));
973                 }
974             }
975 #endif
976           DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
977
978         case 'Z':
979           cpy (zonelen, zone);
980           break;
981
982         case 'z':               /* GNU extension.  */
983           if (tp->tm_isdst < 0)
984             break;
985
986           {
987             int diff;
988 #if HAVE_TM_GMTOFF
989             diff = tp->tm_gmtoff;
990 #else
991             struct tm gtm;
992             struct tm ltm;
993             time_t lt;
994
995             ltm = *tp;
996             lt = mktime (&ltm);
997
998             if (lt == (time_t) -1)
999               {
1000                 /* mktime returns -1 for errors, but -1 is also a
1001                    valid time_t value.  Check whether an error really
1002                    occurred.  */
1003                 struct tm tm;
1004                 localtime_r (&lt, &tm);
1005
1006                 if ((ltm.tm_sec ^ tm.tm_sec)
1007                     | (ltm.tm_min ^ tm.tm_min)
1008                     | (ltm.tm_hour ^ tm.tm_hour)
1009                     | (ltm.tm_mday ^ tm.tm_mday)
1010                     | (ltm.tm_mon ^ tm.tm_mon)
1011                     | (ltm.tm_year ^ tm.tm_year))
1012                   break;
1013               }
1014
1015             if (! gmtime_r (&lt, &gtm))
1016               break;
1017
1018             diff = tm_diff (&ltm, &gtm);
1019 #endif
1020
1021             if (diff < 0)
1022               {
1023                 add (1, *p = '-');
1024                 diff = -diff;
1025               }
1026             else
1027               add (1, *p = '+');
1028
1029             diff /= 60;
1030             DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1031           }
1032
1033         case '\0':              /* GNU extension: % at end of format.  */
1034             --f;
1035             /* Fall through.  */
1036         default:
1037           /* Unknown format; output the format, including the '%',
1038              since this is most likely the right thing to do if a
1039              multibyte string has been misparsed.  */
1040         bad_format:
1041           {
1042             int flen;
1043             for (flen = 1; f[1 - flen] != '%'; flen++)
1044               continue;
1045             cpy (flen, &f[1 - flen]);
1046           }
1047           break;
1048         }
1049     }
1050
1051   if (p)
1052     *p = '\0';
1053   return i;
1054 }