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