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