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