Update.
[platform/upstream/linaro-glibc.git] / time / strftime.c
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with the GNU C Library; see the file COPYING.LIB.  If not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #ifdef _LIBC
24 # define HAVE_LIMITS_H 1
25 # define HAVE_MBLEN 1
26 # define HAVE_MBRLEN 1
27 # define HAVE_STRUCT_ERA_ENTRY 1
28 # define HAVE_TM_GMTOFF 1
29 # define HAVE_TM_ZONE 1
30 # define HAVE_TZNAME 1
31 # define HAVE_TZSET 1
32 # define MULTIBYTE_IS_FORMAT_SAFE 1
33 # define STDC_HEADERS 1
34 # include "../locale/localeinfo.h"
35 #endif
36
37 #if defined emacs && !defined HAVE_BCOPY
38 # define HAVE_MEMCPY 1
39 #endif
40
41 #include <ctype.h>
42 #include <sys/types.h>          /* Some systems define `time_t' here.  */
43
44 #ifdef TIME_WITH_SYS_TIME
45 # include <sys/time.h>
46 # include <time.h>
47 #else
48 # ifdef HAVE_SYS_TIME_H
49 #  include <sys/time.h>
50 # else
51 #  include <time.h>
52 # endif
53 #endif
54 #if HAVE_TZNAME
55 extern char *tzname[];
56 #endif
57
58 /* Do multibyte processing if multibytes are supported, unless
59    multibyte sequences are safe in formats.  Multibyte sequences are
60    safe if they cannot contain byte sequences that look like format
61    conversion specifications.  The GNU C Library uses UTF8 multibyte
62    encoding, which is safe for formats, but strftime.c can be used
63    with other C libraries that use unsafe encodings.  */
64 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
65
66 #if DO_MULTIBYTE
67 # if HAVE_MBRLEN
68 #  include <wchar.h>
69 # else
70    /* Simulate mbrlen with mblen as best we can.  */
71 #  define mbstate_t int
72 #  define mbrlen(s, n, ps) mblen (s, n)
73 #  define mbsinit(ps) (*(ps) == 0)
74 # endif
75   static const mbstate_t mbstate_zero;
76 #endif
77
78 #if HAVE_LIMITS_H
79 # include <limits.h>
80 #endif
81
82 #if STDC_HEADERS
83 # include <stddef.h>
84 # include <stdlib.h>
85 # include <string.h>
86 #else
87 # ifndef HAVE_MEMCPY
88 #  define memcpy(d, s, n) bcopy ((s), (d), (n))
89 # endif
90 #endif
91
92 #ifndef __P
93 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
94 #  define __P(args) args
95 # else
96 #  define __P(args) ()
97 # endif  /* GCC.  */
98 #endif  /* Not __P.  */
99
100 #ifndef PTR
101 # ifdef __STDC__
102 #  define PTR void *
103 # else
104 #  define PTR char *
105 # endif
106 #endif
107
108 #ifndef CHAR_BIT
109 # define CHAR_BIT 8
110 #endif
111
112 #ifndef NULL
113 # define NULL 0
114 #endif
115
116 #define TYPE_SIGNED(t) ((t) -1 < 0)
117
118 /* Bound on length of the string representing an integer value of type t.
119    Subtract one for the sign bit if t is signed;
120    302 / 1000 is log10 (2) rounded up;
121    add one for integer division truncation;
122    add one more for a minus sign if t is signed.  */
123 #define INT_STRLEN_BOUND(t) \
124   ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
125
126 #define TM_YEAR_BASE 1900
127
128 #ifndef __isleap
129 /* Nonzero if YEAR is a leap year (every 4 years,
130    except every 100th isn't, and every 400th is).  */
131 # define __isleap(year) \
132   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
133 #endif
134
135
136 #ifdef _LIBC
137 # define gmtime_r __gmtime_r
138 # define localtime_r __localtime_r
139 # define tzname __tzname
140 # define tzset __tzset
141 #else
142 # if ! HAVE_LOCALTIME_R
143 #  if ! HAVE_TM_GMTOFF
144 /* Approximate gmtime_r as best we can in its absence.  */
145 #   undef gmtime_r
146 #   define gmtime_r my_gmtime_r
147 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
148 static struct tm *
149 gmtime_r (t, tp)
150      const time_t *t;
151      struct tm *tp;
152 {
153   struct tm *l = gmtime (t);
154   if (! l)
155     return 0;
156   *tp = *l;
157   return tp;
158 }
159 #  endif /* ! HAVE_TM_GMTOFF */
160
161 /* Approximate localtime_r as best we can in its absence.  */
162 #  undef localtime_r
163 #  define localtime_r my_ftime_localtime_r
164 static struct tm *localtime_r __P ((const time_t *, struct tm *));
165 static struct tm *
166 localtime_r (t, tp)
167      const time_t *t;
168      struct tm *tp;
169 {
170   struct tm *l = localtime (t);
171   if (! l)
172     return 0;
173   *tp = *l;
174   return tp;
175 }
176 # endif /* ! HAVE_LOCALTIME_R */
177 #endif /* ! defined (_LIBC) */
178
179
180 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
181 /* Some systems lack the `memset' function and we don't want to
182    introduce additional dependencies.  */
183 /* The SGI compiler reportedly barfs on the trailing null
184    if we use a string constant as the initializer.  28 June 1997, rms.  */
185 static const char spaces[16] = /* "                " */
186   { ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
187 static const char zeroes[16] = /* "0000000000000000" */
188   { '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' };
189
190 # define memset_space(P, Len) \
191   do {                                                                        \
192     int _len = (Len);                                                         \
193                                                                               \
194     do                                                                        \
195       {                                                                       \
196         int _this = _len > 16 ? 16 : _len;                                    \
197         memcpy ((P), spaces, _this);                                          \
198         (P) += _this;                                                         \
199         _len -= _this;                                                        \
200       }                                                                       \
201     while (_len > 0);                                                         \
202   } while (0)
203
204 # define memset_zero(P, Len) \
205   do {                                                                        \
206     int _len = (Len);                                                         \
207                                                                               \
208     do                                                                        \
209       {                                                                       \
210         int _this = _len > 16 ? 16 : _len;                                    \
211         memcpy ((P), zeroes, _this);                                          \
212         (P) += _this;                                                         \
213         _len -= _this;                                                        \
214       }                                                                       \
215     while (_len > 0);                                                         \
216   } while (0)
217 #else
218 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
219 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
220 #endif
221
222 #define add(n, f)                                                             \
223   do                                                                          \
224     {                                                                         \
225       int _n = (n);                                                           \
226       int _delta = width - _n;                                                \
227       int _incr = _n + (_delta > 0 ? _delta : 0);                             \
228       if (i + _incr >= maxsize)                                               \
229         return 0;                                                             \
230       if (p)                                                                  \
231         {                                                                     \
232           if (_delta > 0)                                                     \
233             {                                                                 \
234               if (pad == '0')                                                 \
235                 memset_zero (p, _delta);                                      \
236               else                                                            \
237                 memset_space (p, _delta);                                     \
238             }                                                                 \
239           f;                                                                  \
240           p += _n;                                                            \
241         }                                                                     \
242       i += _incr;                                                             \
243     } while (0)
244
245 #define cpy(n, s) \
246     add ((n),                                                                 \
247          if (to_lowcase)                                                      \
248            memcpy_lowcase (p, (s), _n);                                       \
249          else if (to_uppcase)                                                 \
250            memcpy_uppcase (p, (s), _n);                                       \
251          else                                                                 \
252            memcpy ((PTR) p, (PTR) (s), _n))
253
254
255
256 #ifdef _LIBC
257 # define TOUPPER(Ch) toupper (Ch)
258 # define TOLOWER(Ch) tolower (Ch)
259 #else
260 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
261 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
262 #endif
263 /* We don't use `isdigit' here since the locale dependent
264    interpretation is not what we want here.  We only need to accept
265    the arabic digits in the ASCII range.  One day there is perhaps a
266    more reliable way to accept other sets of digits.  */
267 #define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
268
269 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
270
271 static char *
272 memcpy_lowcase (dest, src, len)
273      char *dest;
274      const char *src;
275      size_t len;
276 {
277   while (len-- > 0)
278     dest[len] = TOLOWER ((unsigned char) src[len]);
279   return dest;
280 }
281
282 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
283
284 static char *
285 memcpy_uppcase (dest, src, len)
286      char *dest;
287      const char *src;
288      size_t len;
289 {
290   while (len-- > 0)
291     dest[len] = TOUPPER ((unsigned char) src[len]);
292   return dest;
293 }
294
295
296 #if ! HAVE_TM_GMTOFF
297 /* Yield the difference between *A and *B,
298    measured in seconds, ignoring leap seconds.  */
299 # define tm_diff ftime_tm_diff
300 static int tm_diff __P ((const struct tm *, const struct tm *));
301 static int
302 tm_diff (a, b)
303      const struct tm *a;
304      const struct tm *b;
305 {
306   /* Compute intervening leap days correctly even if year is negative.
307      Take care to avoid int overflow in leap day calculations,
308      but it's OK to assume that A and B are close to each other.  */
309   int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
310   int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
311   int a100 = a4 / 25 - (a4 % 25 < 0);
312   int b100 = b4 / 25 - (b4 % 25 < 0);
313   int a400 = a100 >> 2;
314   int b400 = b100 >> 2;
315   int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
316   int years = a->tm_year - b->tm_year;
317   int days = (365 * years + intervening_leap_days
318               + (a->tm_yday - b->tm_yday));
319   return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
320                 + (a->tm_min - b->tm_min))
321           + (a->tm_sec - b->tm_sec));
322 }
323 #endif /* ! HAVE_TM_GMTOFF */
324
325
326
327 /* The number of days from the first day of the first ISO week of this
328    year to the year day YDAY with week day WDAY.  ISO weeks start on
329    Monday; the first ISO week has the year's first Thursday.  YDAY may
330    be as small as YDAY_MINIMUM.  */
331 #define ISO_WEEK_START_WDAY 1 /* Monday */
332 #define ISO_WEEK1_WDAY 4 /* Thursday */
333 #define YDAY_MINIMUM (-366)
334 static int iso_week_days __P ((int, int));
335 #ifdef __GNUC__
336 __inline__
337 #endif
338 static int
339 iso_week_days (yday, wday)
340      int yday;
341      int wday;
342 {
343   /* Add enough to the first operand of % to make it nonnegative.  */
344   int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
345   return (yday
346           - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
347           + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
348 }
349
350
351 #if !(defined _NL_CURRENT || HAVE_STRFTIME)
352 static char const weekday_name[][10] =
353   {
354     "Sunday", "Monday", "Tuesday", "Wednesday",
355     "Thursday", "Friday", "Saturday"
356   };
357 static char const month_name[][10] =
358   {
359     "January", "February", "March", "April", "May", "June",
360     "July", "August", "September", "October", "November", "December"
361   };
362 #endif
363
364
365 #ifdef emacs
366 # define my_strftime emacs_strftime
367  /* Emacs 20.2 uses `-Dstrftime=emacs_strftime' when compiling,
368     because that's how strftime used to be configured.
369     Undo this, since it gets in the way of accessing the underlying strftime,
370     which is needed for things like %Ec in Solaris.
371     The following two lines can be removed once Emacs stops compiling with
372     `-Dstrftime=emacs_strftime'.  */
373 # undef strftime
374 size_t strftime __P ((char *, size_t, const char *, const struct tm *));
375 #else
376 # define my_strftime strftime
377 #endif
378
379 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
380   /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
381      Work around this bug by copying *tp before it might be munged.  */
382   size_t _strftime_copytm __P ((char *, size_t, const char *,
383                                 const struct tm *));
384   size_t
385   my_strftime (s, maxsize, format, tp)
386       char *s;
387       size_t maxsize;
388       const char *format;
389       const struct tm *tp;
390   {
391     struct tm tmcopy;
392     tmcopy = *tp;
393     return _strftime_copytm (s, maxsize, format, &tmcopy);
394   }
395 # undef my_strftime
396 # define my_strftime(S, Maxsize, Format, Tp) \
397   _strftime_copytm (S, Maxsize, Format, Tp)
398 #endif
399
400
401 /* Write information from TP into S according to the format
402    string FORMAT, writing no more that MAXSIZE characters
403    (including the terminating '\0') and returning number of
404    characters written.  If S is NULL, nothing will be written
405    anywhere, so to determine how many characters would be
406    written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */
407 size_t
408 my_strftime (s, maxsize, format, tp)
409       char *s;
410       size_t maxsize;
411       const char *format;
412       const struct tm *tp;
413 {
414   int hour12 = tp->tm_hour;
415 #ifdef _NL_CURRENT
416   const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
417   const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
418   const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
419   const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
420   const char *const ampm = _NL_CURRENT (LC_TIME,
421                                         hour12 > 11 ? PM_STR : AM_STR);
422   size_t aw_len = strlen (a_wkday);
423   size_t am_len = strlen (a_month);
424   size_t ap_len = strlen (ampm);
425 #else
426 # if !HAVE_STRFTIME
427   const char *const f_wkday = weekday_name[tp->tm_wday];
428   const char *const f_month = month_name[tp->tm_mon];
429   const char *const a_wkday = f_wkday;
430   const char *const a_month = f_month;
431   const char *const ampm = "AMPM" + 2 * (hour12 > 11);
432   size_t aw_len = 3;
433   size_t am_len = 3;
434   size_t ap_len = 2;
435 # endif
436 #endif
437 #if defined _NL_CURRENT || !HAVE_STRFTIME
438   size_t wkday_len = strlen (f_wkday);
439   size_t month_len = strlen (f_month);
440 #endif
441   const char *zone;
442   size_t zonelen;
443   size_t i = 0;
444   char *p = s;
445   const char *f;
446
447   zone = NULL;
448 #if HAVE_TM_ZONE
449   /* The POSIX test suite assumes that setting
450      the environment variable TZ to a new value before calling strftime()
451      will influence the result (the %Z format) even if the information in
452      TP is computed with a totally different time zone.
453      This is bogus: though POSIX allows bad behavior like this,
454      POSIX does not require it.  Do the right thing instead.  */
455   zone = (const char *) tp->tm_zone;
456 #endif
457 #if HAVE_TZNAME
458   /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
459      time zone names contained in the external variable `tzname' shall
460      be set as if the tzset() function had been called.  */
461 # if HAVE_TZSET
462   tzset ();
463 # endif
464
465   if (!(zone && *zone) && tp->tm_isdst >= 0)
466     zone = tzname[tp->tm_isdst];
467 #endif
468   if (! zone)
469     zone = "";          /* POSIX.2 requires the empty string here.  */
470
471   zonelen = strlen (zone);
472
473   if (hour12 > 12)
474     hour12 -= 12;
475   else
476     if (hour12 == 0) hour12 = 12;
477
478   for (f = format; *f != '\0'; ++f)
479     {
480       int pad;                  /* Padding for number ('-', '_', or 0).  */
481       int modifier;             /* Field modifier ('E', 'O', or 0).  */
482       int digits;               /* Max digits for numeric format.  */
483       int number_value;         /* Numeric value to be printed.  */
484       int negative_number;      /* 1 if the number is negative.  */
485       const char *subfmt;
486       char *bufp;
487       char buf[1 + (sizeof (int) < sizeof (time_t)
488                     ? INT_STRLEN_BOUND (time_t)
489                     : INT_STRLEN_BOUND (int))];
490       int width = -1;
491       int to_lowcase = 0;
492       int to_uppcase = 0;
493       int change_case = 0;
494       int format_char;
495
496 #if DO_MULTIBYTE
497
498        switch (*f)
499         {
500         case '%':
501           break;
502
503         case '\a': case '\b': case '\t': case '\n':
504         case '\v': case '\f': case '\r':
505         case ' ': case '!': case '"': case '#': case '&': case'\'':
506         case '(': case ')': case '*': case '+': case ',': case '-':
507         case '.': case '/': case '0': case '1': case '2': case '3':
508         case '4': case '5': case '6': case '7': case '8': case '9':
509         case ':': case ';': case '<': case '=': case '>': case '?':
510         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
511         case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
512         case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
513         case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
514         case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
515         case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
516         case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
517         case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
518         case 'r': case 's': case 't': case 'u': case 'v': case 'w':
519         case 'x': case 'y': case 'z': case '{': case '|': case '}':
520         case '~':
521           /* The C Standard requires these 98 characters (plus '%') to
522              be in the basic execution character set.  None of these
523              characters can start a multibyte sequence, so they need
524              not be analyzed further.  */
525           add (1, *p = *f);
526           continue;
527
528         default:
529           /* Copy this multibyte sequence until we reach its end, find
530              an error, or come back to the initial shift state.  */
531           {
532             mbstate_t mbstate = mbstate_zero;
533             size_t len = 0;
534
535             do
536               {
537                 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
538
539                 if (bytes == 0)
540                   break;
541
542                 if (bytes == (size_t) -2 || bytes == (size_t) -1)
543                   {
544                     len++;
545                     break;
546                   }
547
548                 len += bytes;
549               }
550             while (! mbsinit (&mbstate));
551
552             cpy (len, f);
553             continue;
554           }
555         }
556
557 #else /* ! DO_MULTIBYTE */
558
559       /* Either multibyte encodings are not supported, or they are
560          safe for formats, so any non-'%' byte can be copied through.  */
561       if (*f != '%')
562         {
563           add (1, *p = *f);
564           continue;
565         }
566
567 #endif /* ! DO_MULTIBYTE */
568
569       /* Check for flags that can modify a format.  */
570       pad = 0;
571       while (1)
572         {
573           switch (*++f)
574             {
575               /* This influences the number formats.  */
576             case '_':
577             case '-':
578             case '0':
579               pad = *f;
580               continue;
581
582               /* This changes textual output.  */
583             case '^':
584               to_uppcase = 1;
585               continue;
586             case '#':
587               change_case = 1;
588               continue;
589
590             default:
591               break;
592             }
593           break;
594         }
595
596       /* As a GNU extension we allow to specify the field width.  */
597       if (ISDIGIT (*f))
598         {
599           width = 0;
600           do
601             {
602               width *= 10;
603               width += *f - '0';
604               ++f;
605             }
606           while (ISDIGIT (*f));
607         }
608
609       /* Check for modifiers.  */
610       switch (*f)
611         {
612         case 'E':
613         case 'O':
614           modifier = *f++;
615           break;
616
617         default:
618           modifier = 0;
619           break;
620         }
621
622       /* Now do the specified format.  */
623       format_char = *f;
624       switch (format_char)
625         {
626 #define DO_NUMBER(d, v) \
627           digits = width == -1 ? d : width;                                   \
628           number_value = v; goto do_number
629 #define DO_NUMBER_SPACEPAD(d, v) \
630           digits = width == -1 ? d : width;                                   \
631           number_value = v; goto do_number_spacepad
632
633         case '%':
634           if (modifier != 0)
635             goto bad_format;
636           add (1, *p = *f);
637           break;
638
639         case 'a':
640           if (modifier != 0)
641             goto bad_format;
642           if (change_case)
643             {
644               to_uppcase = 1;
645               to_lowcase = 0;
646             }
647 #if defined _NL_CURRENT || !HAVE_STRFTIME
648           cpy (aw_len, a_wkday);
649           break;
650 #else
651           goto underlying_strftime;
652 #endif
653
654         case 'A':
655           if (modifier != 0)
656             goto bad_format;
657           if (change_case)
658             {
659               to_uppcase = 1;
660               to_lowcase = 0;
661             }
662 #if defined _NL_CURRENT || !HAVE_STRFTIME
663           cpy (wkday_len, f_wkday);
664           break;
665 #else
666           goto underlying_strftime;
667 #endif
668
669         case 'b':
670         case 'h':               /* POSIX.2 extension.  */
671           if (modifier != 0)
672             goto bad_format;
673 #if defined _NL_CURRENT || !HAVE_STRFTIME
674           cpy (am_len, a_month);
675           break;
676 #else
677           goto underlying_strftime;
678 #endif
679
680         case 'B':
681           if (modifier != 0)
682             goto bad_format;
683           if (change_case)
684             {
685               to_uppcase = 1;
686               to_lowcase = 0;
687             }
688 #if defined _NL_CURRENT || !HAVE_STRFTIME
689           cpy (month_len, f_month);
690           break;
691 #else
692           goto underlying_strftime;
693 #endif
694
695         case 'c':
696           if (modifier == 'O')
697             goto bad_format;
698 #ifdef _NL_CURRENT
699           if (! (modifier == 'E'
700                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
701             subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
702 #else
703 # if HAVE_STRFTIME
704           goto underlying_strftime;
705 # else
706           subfmt = "%a %b %e %H:%M:%S %Y";
707 # endif
708 #endif
709
710         subformat:
711           {
712             char *old_start = p;
713             size_t len = my_strftime (NULL, maxsize - i, subfmt, tp);
714             if (len == 0 && *subfmt)
715               return 0;
716             add (len, my_strftime (p, maxsize - i, subfmt, tp));
717
718             if (to_uppcase)
719               while (old_start < p)
720                 {
721                   *old_start = TOUPPER ((unsigned char) *old_start);
722                   ++old_start;
723                 }
724           }
725           break;
726
727 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
728         underlying_strftime:
729           {
730             /* The relevant information is available only via the
731                underlying strftime implementation, so use that.  */
732             char ufmt[4];
733             char *u = ufmt;
734             char ubuf[1024]; /* enough for any single format in practice */
735             size_t len;
736             *u++ = '%';
737             if (modifier != 0)
738               *u++ = modifier;
739             *u++ = format_char;
740             *u = '\0';
741             len = strftime (ubuf, sizeof ubuf, ufmt, tp);
742             if (len == 0)
743               return 0;
744             cpy (len, ubuf);
745           }
746           break;
747 #endif
748
749         case 'C':               /* POSIX.2 extension.  */
750           if (modifier == 'O')
751             goto bad_format;
752           if (modifier == 'E')
753             {
754 #if HAVE_STRUCT_ERA_ENTRY
755               struct era_entry *era = _nl_get_era_entry (tp);
756               if (era)
757                 {
758                   size_t len = strlen (era->name_fmt);
759                   cpy (len, era->name_fmt);
760                   break;
761                 }
762 #else
763 # if HAVE_STRFTIME
764               goto underlying_strftime;
765 # endif
766 #endif
767             }
768
769           {
770             int year = tp->tm_year + TM_YEAR_BASE;
771             DO_NUMBER (1, year / 100 - (year % 100 < 0));
772           }
773
774         case 'x':
775           if (modifier == 'O')
776             goto bad_format;
777 #ifdef _NL_CURRENT
778           if (! (modifier == 'E'
779                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
780             subfmt = _NL_CURRENT (LC_TIME, D_FMT);
781           goto subformat;
782 #else
783 # if HAVE_STRFTIME
784           goto underlying_strftime;
785 # else
786           /* Fall through.  */
787 # endif
788 #endif
789         case 'D':               /* POSIX.2 extension.  */
790           if (modifier != 0)
791             goto bad_format;
792           subfmt = "%m/%d/%y";
793           goto subformat;
794
795         case 'd':
796           if (modifier == 'E')
797             goto bad_format;
798
799           DO_NUMBER (2, tp->tm_mday);
800
801         case 'e':               /* POSIX.2 extension.  */
802           if (modifier == 'E')
803             goto bad_format;
804
805           DO_NUMBER_SPACEPAD (2, tp->tm_mday);
806
807           /* All numeric formats set DIGITS and NUMBER_VALUE and then
808              jump to one of these two labels.  */
809
810         do_number_spacepad:
811           /* Force `_' flag unless overwritten by `0' flag.  */
812           if (pad != '0')
813             pad = '_';
814
815         do_number:
816           /* Format the number according to the MODIFIER flag.  */
817
818           if (modifier == 'O' && 0 <= number_value)
819             {
820 #ifdef _NL_CURRENT
821               /* Get the locale specific alternate representation of
822                  the number NUMBER_VALUE.  If none exist NULL is returned.  */
823               const char *cp = _nl_get_alt_digit (number_value);
824
825               if (cp != NULL)
826                 {
827                   size_t digitlen = strlen (cp);
828                   if (digitlen != 0)
829                     {
830                       cpy (digitlen, cp);
831                       break;
832                     }
833                 }
834 #else
835 # if HAVE_STRFTIME
836               goto underlying_strftime;
837 # endif
838 #endif
839             }
840           {
841             unsigned int u = number_value;
842
843             bufp = buf + sizeof (buf);
844             negative_number = number_value < 0;
845
846             if (negative_number)
847               u = -u;
848
849             do
850               *--bufp = u % 10 + '0';
851             while ((u /= 10) != 0);
852           }
853
854         do_number_sign_and_padding:
855           if (negative_number)
856             *--bufp = '-';
857
858           if (pad != '-')
859             {
860               int padding = digits - (buf + sizeof (buf) - bufp);
861
862               if (pad == '_')
863                 {
864                   while (0 < padding--)
865                     *--bufp = ' ';
866                 }
867               else
868                 {
869                   bufp += negative_number;
870                   while (0 < padding--)
871                     *--bufp = '0';
872                   if (negative_number)
873                     *--bufp = '-';
874                 }
875             }
876
877           cpy (buf + sizeof (buf) - bufp, bufp);
878           break;
879
880
881         case 'H':
882           if (modifier == 'E')
883             goto bad_format;
884
885           DO_NUMBER (2, tp->tm_hour);
886
887         case 'I':
888           if (modifier == 'E')
889             goto bad_format;
890
891           DO_NUMBER (2, hour12);
892
893         case 'k':               /* GNU extension.  */
894           if (modifier == 'E')
895             goto bad_format;
896
897           DO_NUMBER_SPACEPAD (2, tp->tm_hour);
898
899         case 'l':               /* GNU extension.  */
900           if (modifier == 'E')
901             goto bad_format;
902
903           DO_NUMBER_SPACEPAD (2, hour12);
904
905         case 'j':
906           if (modifier == 'E')
907             goto bad_format;
908
909           DO_NUMBER (3, 1 + tp->tm_yday);
910
911         case 'M':
912           if (modifier == 'E')
913             goto bad_format;
914
915           DO_NUMBER (2, tp->tm_min);
916
917         case 'm':
918           if (modifier == 'E')
919             goto bad_format;
920
921           DO_NUMBER (2, tp->tm_mon + 1);
922
923         case 'n':               /* POSIX.2 extension.  */
924           add (1, *p = '\n');
925           break;
926
927         case 'P':
928           to_lowcase = 1;
929 #if !defined _NL_CURRENT && HAVE_STRFTIME
930           format_char = 'p';
931 #endif
932           /* FALLTHROUGH */
933
934         case 'p':
935           if (change_case)
936             {
937               to_uppcase = 0;
938               to_lowcase = 1;
939             }
940 #if defined _NL_CURRENT || !HAVE_STRFTIME
941           cpy (ap_len, ampm);
942           break;
943 #else
944           goto underlying_strftime;
945 #endif
946
947         case 'R':               /* GNU extension.  */
948           subfmt = "%H:%M";
949           goto subformat;
950
951         case 'r':               /* POSIX.2 extension.  */
952 #ifdef _NL_CURRENT
953           if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
954 #endif
955             subfmt = "%I:%M:%S %p";
956           goto subformat;
957
958         case 'S':
959           if (modifier == 'E')
960             goto bad_format;
961
962           DO_NUMBER (2, tp->tm_sec);
963
964         case 's':               /* GNU extension.  */
965           {
966             struct tm ltm;
967             time_t t;
968
969             ltm = *tp;
970             t = mktime (&ltm);
971
972             /* Generate string value for T using time_t arithmetic;
973                this works even if sizeof (long) < sizeof (time_t).  */
974
975             bufp = buf + sizeof (buf);
976             negative_number = t < 0;
977
978             do
979               {
980                 int d = t % 10;
981                 t /= 10;
982
983                 if (negative_number)
984                   {
985                     d = -d;
986
987                     /* Adjust if division truncates to minus infinity.  */
988                     if (0 < -1 % 10 && d < 0)
989                       {
990                         t++;
991                         d += 10;
992                       }
993                   }
994
995                 *--bufp = d + '0';
996               }
997             while (t != 0);
998
999             digits = 1;
1000             goto do_number_sign_and_padding;
1001           }
1002
1003         case 'X':
1004           if (modifier == 'O')
1005             goto bad_format;
1006 #ifdef _NL_CURRENT
1007           if (! (modifier == 'E'
1008                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
1009             subfmt = _NL_CURRENT (LC_TIME, T_FMT);
1010           goto subformat;
1011 #else
1012 # if HAVE_STRFTIME
1013           goto underlying_strftime;
1014 # else
1015           /* Fall through.  */
1016 # endif
1017 #endif
1018         case 'T':               /* POSIX.2 extension.  */
1019           subfmt = "%H:%M:%S";
1020           goto subformat;
1021
1022         case 't':               /* POSIX.2 extension.  */
1023           add (1, *p = '\t');
1024           break;
1025
1026         case 'u':               /* POSIX.2 extension.  */
1027           DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1028
1029         case 'U':
1030           if (modifier == 'E')
1031             goto bad_format;
1032
1033           DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1034
1035         case 'V':
1036         case 'g':               /* GNU extension.  */
1037         case 'G':               /* GNU extension.  */
1038           if (modifier == 'E')
1039             goto bad_format;
1040           {
1041             int year = tp->tm_year + TM_YEAR_BASE;
1042             int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1043
1044             if (days < 0)
1045               {
1046                 /* This ISO week belongs to the previous year.  */
1047                 year--;
1048                 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
1049                                       tp->tm_wday);
1050               }
1051             else
1052               {
1053                 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1054                                        tp->tm_wday);
1055                 if (0 <= d)
1056                   {
1057                     /* This ISO week belongs to the next year.  */
1058                     year++;
1059                     days = d;
1060                   }
1061               }
1062
1063             switch (*f)
1064               {
1065               case 'g':
1066                 DO_NUMBER (2, (year % 100 + 100) % 100);
1067
1068               case 'G':
1069                 DO_NUMBER (1, year);
1070
1071               default:
1072                 DO_NUMBER (2, days / 7 + 1);
1073               }
1074           }
1075
1076         case 'W':
1077           if (modifier == 'E')
1078             goto bad_format;
1079
1080           DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1081
1082         case 'w':
1083           if (modifier == 'E')
1084             goto bad_format;
1085
1086           DO_NUMBER (1, tp->tm_wday);
1087
1088         case 'Y':
1089           if (modifier == 'E')
1090             {
1091 #if HAVE_STRUCT_ERA_ENTRY
1092               struct era_entry *era = _nl_get_era_entry (tp);
1093               if (era)
1094                 {
1095                   subfmt = strchr (era->name_fmt, '\0') + 1;
1096                   goto subformat;
1097                 }
1098 #else
1099 # if HAVE_STRFTIME
1100               goto underlying_strftime;
1101 # endif
1102 #endif
1103             }
1104           if (modifier == 'O')
1105             goto bad_format;
1106           else
1107             DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1108
1109         case 'y':
1110           if (modifier == 'E')
1111             {
1112 #if HAVE_STRUCT_ERA_ENTRY
1113               struct era_entry *era = _nl_get_era_entry (tp);
1114               if (era)
1115                 {
1116                   int delta = tp->tm_year - era->start_date[0];
1117                   DO_NUMBER (1, (era->offset
1118                                  + (era->direction == '-' ? -delta : delta)));
1119                 }
1120 #else
1121 # if HAVE_STRFTIME
1122               goto underlying_strftime;
1123 # endif
1124 #endif
1125             }
1126           DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1127
1128         case 'Z':
1129           if (change_case)
1130             {
1131               to_uppcase = 0;
1132               to_lowcase = 1;
1133             }
1134           cpy (zonelen, zone);
1135           break;
1136
1137         case 'z':               /* GNU extension.  */
1138           if (tp->tm_isdst < 0)
1139             break;
1140
1141           {
1142             int diff;
1143 #if HAVE_TM_GMTOFF
1144             diff = tp->tm_gmtoff;
1145 #else
1146             struct tm gtm;
1147             struct tm ltm;
1148             time_t lt;
1149
1150             ltm = *tp;
1151             lt = mktime (&ltm);
1152
1153             if (lt == (time_t) -1)
1154               {
1155                 /* mktime returns -1 for errors, but -1 is also a
1156                    valid time_t value.  Check whether an error really
1157                    occurred.  */
1158                 struct tm tm;
1159                 localtime_r (&lt, &tm);
1160
1161                 if ((ltm.tm_sec ^ tm.tm_sec)
1162                     | (ltm.tm_min ^ tm.tm_min)
1163                     | (ltm.tm_hour ^ tm.tm_hour)
1164                     | (ltm.tm_mday ^ tm.tm_mday)
1165                     | (ltm.tm_mon ^ tm.tm_mon)
1166                     | (ltm.tm_year ^ tm.tm_year))
1167                   break;
1168               }
1169
1170             if (! gmtime_r (&lt, &gtm))
1171               break;
1172
1173             diff = tm_diff (&ltm, &gtm);
1174 #endif
1175
1176             if (diff < 0)
1177               {
1178                 add (1, *p = '-');
1179                 diff = -diff;
1180               }
1181             else
1182               add (1, *p = '+');
1183
1184             diff /= 60;
1185             DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1186           }
1187
1188         case '\0':              /* GNU extension: % at end of format.  */
1189             --f;
1190             /* Fall through.  */
1191         default:
1192           /* Unknown format; output the format, including the '%',
1193              since this is most likely the right thing to do if a
1194              multibyte string has been misparsed.  */
1195         bad_format:
1196           {
1197             int flen;
1198             for (flen = 1; f[1 - flen] != '%'; flen++)
1199               continue;
1200             cpy (flen, &f[1 - flen]);
1201           }
1202           break;
1203         }
1204     }
1205
1206   if (p)
1207     *p = '\0';
1208   return i;
1209 }