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