(f_wkday): Remove duplicate definition.
[kopensolaris-gnu/glibc.git] / time / strftime.c
1 /* Copyright (C) 1991,92,93,94,95,96,97,98 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 __EXTENSIONS__
25 # define __EXTENSIONS__ 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 / 1000 + 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 #else
379 # define my_strftime strftime
380 #endif
381
382 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
383   /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
384      Work around this bug by copying *tp before it might be munged.  */
385   size_t _strftime_copytm __P ((char *, size_t, const char *,
386                                 const struct tm *));
387   size_t
388   my_strftime (s, maxsize, format, tp)
389       char *s;
390       size_t maxsize;
391       const char *format;
392       const struct tm *tp;
393   {
394     struct tm tmcopy;
395     tmcopy = *tp;
396     return _strftime_copytm (s, maxsize, format, &tmcopy);
397   }
398 # undef my_strftime
399 # define my_strftime(S, Maxsize, Format, Tp) \
400   _strftime_copytm (S, Maxsize, Format, Tp)
401 #endif
402
403
404 /* Write information from TP into S according to the format
405    string FORMAT, writing no more that MAXSIZE characters
406    (including the terminating '\0') and returning number of
407    characters written.  If S is NULL, nothing will be written
408    anywhere, so to determine how many characters would be
409    written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */
410 size_t
411 my_strftime (s, maxsize, format, tp)
412       char *s;
413       size_t maxsize;
414       const char *format;
415       const struct tm *tp;
416 {
417   int hour12 = tp->tm_hour;
418 #ifdef _NL_CURRENT
419   /* We cannot make the following values variables since we must delay
420      the evaluation of these values until really needed since some
421      expressions might not be valid in every situation.  The `struct tm'
422      might be generated by a strptime() call that initialized
423      only a few elements.  Dereference the pointers only if the format
424      requires this.  Then it is ok to fail if the pointers are invalid.  */
425 # define a_wkday _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday)
426 # define f_wkday _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday)
427 # define a_month _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon)
428 # define f_month _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon)
429 # define ampm _NL_CURRENT (LC_TIME, tp->tm_hour > 11 ? PM_STR : AM_STR)
430
431 # define aw_len strlen (a_wkday)
432 # define am_len strlen (a_month)
433 # define ap_len strlen (ampm)
434 #else
435 # if !HAVE_STRFTIME
436 # define f_wkday (weekday_name[tp->tm_wday])
437 # define f_month (month_name[tp->tm_mon])
438 # define a_wkday f_wkday
439 # define a_month f_month
440 # define ampm ("AMPM" + 2 * (tp->tm_hour > 11))
441
442   size_t aw_len = 3;
443   size_t am_len = 3;
444   size_t ap_len = 2;
445 # endif
446 #endif
447   const char *zone;
448   size_t i = 0;
449   char *p = s;
450   const char *f;
451
452   zone = NULL;
453 #if HAVE_TM_ZONE
454   /* The POSIX test suite assumes that setting
455      the environment variable TZ to a new value before calling strftime()
456      will influence the result (the %Z format) even if the information in
457      TP is computed with a totally different time zone.
458      This is bogus: though POSIX allows bad behavior like this,
459      POSIX does not require it.  Do the right thing instead.  */
460   zone = (const char *) tp->tm_zone;
461 #endif
462 #if HAVE_TZNAME && HAVE_TZSET
463   /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
464      time zone names contained in the external variable `tzname' shall
465      be set as if the tzset() function had been called.  */
466   tzset ();
467 #endif
468
469   if (hour12 > 12)
470     hour12 -= 12;
471   else
472     if (hour12 == 0)
473       hour12 = 12;
474
475   for (f = format; *f != '\0'; ++f)
476     {
477       int pad = 0;              /* Padding for number ('-', '_', or 0).  */
478       int modifier;             /* Field modifier ('E', 'O', or 0).  */
479       int digits;               /* Max digits for numeric format.  */
480       int number_value;         /* Numeric value to be printed.  */
481       int negative_number;      /* 1 if the number is negative.  */
482       const char *subfmt;
483       char *bufp;
484       char buf[1 + (sizeof (int) < sizeof (time_t)
485                     ? INT_STRLEN_BOUND (time_t)
486                     : INT_STRLEN_BOUND (int))];
487       int width = -1;
488       int to_lowcase = 0;
489       int to_uppcase = 0;
490       int change_case = 0;
491       int format_char;
492
493 #if DO_MULTIBYTE
494
495        switch (*f)
496         {
497         case '%':
498           break;
499
500         case '\a': case '\b': case '\t': case '\n':
501         case '\v': case '\f': case '\r':
502         case ' ': case '!': case '"': case '#': case '&': case'\'':
503         case '(': case ')': case '*': case '+': case ',': case '-':
504         case '.': case '/': case '0': case '1': case '2': case '3':
505         case '4': case '5': case '6': case '7': case '8': case '9':
506         case ':': case ';': case '<': case '=': case '>': case '?':
507         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
508         case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
509         case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
510         case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
511         case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
512         case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
513         case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
514         case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
515         case 'r': case 's': case 't': case 'u': case 'v': case 'w':
516         case 'x': case 'y': case 'z': case '{': case '|': case '}':
517         case '~':
518           /* The C Standard requires these 98 characters (plus '%') to
519              be in the basic execution character set.  None of these
520              characters can start a multibyte sequence, so they need
521              not be analyzed further.  */
522           add (1, *p = *f);
523           continue;
524
525         default:
526           /* Copy this multibyte sequence until we reach its end, find
527              an error, or come back to the initial shift state.  */
528           {
529             mbstate_t mbstate = mbstate_zero;
530             size_t len = 0;
531
532             do
533               {
534                 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
535
536                 if (bytes == 0)
537                   break;
538
539                 if (bytes == (size_t) -2)
540                   {
541                     len += strlen (f + len);
542                     break;
543                   }
544
545                 if (bytes == (size_t) -1)
546                   {
547                     len++;
548                     break;
549                   }
550
551                 len += bytes;
552               }
553             while (! mbsinit (&mbstate));
554
555             cpy (len, f);
556             f += len - 1;
557             continue;
558           }
559         }
560
561 #else /* ! DO_MULTIBYTE */
562
563       /* Either multibyte encodings are not supported, or they are
564          safe for formats, so any non-'%' byte can be copied through.  */
565       if (*f != '%')
566         {
567           add (1, *p = *f);
568           continue;
569         }
570
571 #endif /* ! DO_MULTIBYTE */
572
573       /* Check for flags that can modify a format.  */
574       while (1)
575         {
576           switch (*++f)
577             {
578               /* This influences the number formats.  */
579             case '_':
580             case '-':
581             case '0':
582               pad = *f;
583               continue;
584
585               /* This changes textual output.  */
586             case '^':
587               to_uppcase = 1;
588               continue;
589             case '#':
590               change_case = 1;
591               continue;
592
593             default:
594               break;
595             }
596           break;
597         }
598
599       /* As a GNU extension we allow to specify the field width.  */
600       if (ISDIGIT (*f))
601         {
602           width = 0;
603           do
604             {
605               width *= 10;
606               width += *f - '0';
607               ++f;
608             }
609           while (ISDIGIT (*f));
610         }
611
612       /* Check for modifiers.  */
613       switch (*f)
614         {
615         case 'E':
616         case 'O':
617           modifier = *f++;
618           break;
619
620         default:
621           modifier = 0;
622           break;
623         }
624
625       /* Now do the specified format.  */
626       format_char = *f;
627       switch (format_char)
628         {
629 #define DO_NUMBER(d, v) \
630           digits = width == -1 ? d : width;                                   \
631           number_value = v; goto do_number
632 #define DO_NUMBER_SPACEPAD(d, v) \
633           digits = width == -1 ? d : width;                                   \
634           number_value = v; goto do_number_spacepad
635
636         case '%':
637           if (modifier != 0)
638             goto bad_format;
639           add (1, *p = *f);
640           break;
641
642         case 'a':
643           if (modifier != 0)
644             goto bad_format;
645           if (change_case)
646             {
647               to_uppcase = 1;
648               to_lowcase = 0;
649             }
650 #if defined _NL_CURRENT || !HAVE_STRFTIME
651           cpy (aw_len, a_wkday);
652           break;
653 #else
654           goto underlying_strftime;
655 #endif
656
657         case 'A':
658           if (modifier != 0)
659             goto bad_format;
660           if (change_case)
661             {
662               to_uppcase = 1;
663               to_lowcase = 0;
664             }
665 #if defined _NL_CURRENT || !HAVE_STRFTIME
666           cpy (strlen (f_wkday), f_wkday);
667           break;
668 #else
669           goto underlying_strftime;
670 #endif
671
672         case 'b':
673         case 'h':               /* POSIX.2 extension.  */
674           if (modifier != 0)
675             goto bad_format;
676 #if defined _NL_CURRENT || !HAVE_STRFTIME
677           cpy (am_len, a_month);
678           break;
679 #else
680           goto underlying_strftime;
681 #endif
682
683         case 'B':
684           if (modifier != 0)
685             goto bad_format;
686           if (change_case)
687             {
688               to_uppcase = 1;
689               to_lowcase = 0;
690             }
691 #if defined _NL_CURRENT || !HAVE_STRFTIME
692           cpy (strlen (f_month), f_month);
693           break;
694 #else
695           goto underlying_strftime;
696 #endif
697
698         case 'c':
699           if (modifier == 'O')
700             goto bad_format;
701 #ifdef _NL_CURRENT
702           if (! (modifier == 'E'
703                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
704             subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
705 #else
706 # if HAVE_STRFTIME
707           goto underlying_strftime;
708 # else
709           subfmt = "%a %b %e %H:%M:%S %Y";
710 # endif
711 #endif
712
713         subformat:
714           {
715             char *old_start = p;
716             size_t len = my_strftime (NULL, maxsize - i, subfmt, tp);
717             if (len == 0 && *subfmt)
718               return 0;
719             add (len, my_strftime (p, maxsize - i, subfmt, tp));
720
721             if (to_uppcase)
722               while (old_start < p)
723                 {
724                   *old_start = TOUPPER ((unsigned char) *old_start);
725                   ++old_start;
726                 }
727           }
728           break;
729
730 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
731         underlying_strftime:
732           {
733             /* The relevant information is available only via the
734                underlying strftime implementation, so use that.  */
735             char ufmt[4];
736             char *u = ufmt;
737             char ubuf[1024]; /* enough for any single format in practice */
738             size_t len;
739             *u++ = '%';
740             if (modifier != 0)
741               *u++ = modifier;
742             *u++ = format_char;
743             *u = '\0';
744             len = strftime (ubuf, sizeof ubuf, ufmt, tp);
745             if (len == 0 && ubuf[0] != '\0')
746               return 0;
747             cpy (len, ubuf);
748           }
749           break;
750 #endif
751
752         case 'C':               /* POSIX.2 extension.  */
753           if (modifier == 'O')
754             goto bad_format;
755           if (modifier == 'E')
756             {
757 #if HAVE_STRUCT_ERA_ENTRY
758               struct era_entry *era = _nl_get_era_entry (tp);
759               if (era)
760                 {
761                   size_t len = strlen (era->name_fmt);
762                   cpy (len, era->name_fmt);
763                   break;
764                 }
765 #else
766 # if HAVE_STRFTIME
767               goto underlying_strftime;
768 # endif
769 #endif
770             }
771
772           {
773             int year = tp->tm_year + TM_YEAR_BASE;
774             DO_NUMBER (1, year / 100 - (year % 100 < 0));
775           }
776
777         case 'x':
778           if (modifier == 'O')
779             goto bad_format;
780 #ifdef _NL_CURRENT
781           if (! (modifier == 'E'
782                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
783             subfmt = _NL_CURRENT (LC_TIME, D_FMT);
784           goto subformat;
785 #else
786 # if HAVE_STRFTIME
787           goto underlying_strftime;
788 # else
789           /* Fall through.  */
790 # endif
791 #endif
792         case 'D':               /* POSIX.2 extension.  */
793           if (modifier != 0)
794             goto bad_format;
795           subfmt = "%m/%d/%y";
796           goto subformat;
797
798         case 'd':
799           if (modifier == 'E')
800             goto bad_format;
801
802           DO_NUMBER (2, tp->tm_mday);
803
804         case 'e':               /* POSIX.2 extension.  */
805           if (modifier == 'E')
806             goto bad_format;
807
808           DO_NUMBER_SPACEPAD (2, tp->tm_mday);
809
810           /* All numeric formats set DIGITS and NUMBER_VALUE and then
811              jump to one of these two labels.  */
812
813         do_number_spacepad:
814           /* Force `_' flag unless overwritten by `0' flag.  */
815           if (pad != '0')
816             pad = '_';
817
818         do_number:
819           /* Format the number according to the MODIFIER flag.  */
820
821           if (modifier == 'O' && 0 <= number_value)
822             {
823 #ifdef _NL_CURRENT
824               /* Get the locale specific alternate representation of
825                  the number NUMBER_VALUE.  If none exist NULL is returned.  */
826               const char *cp = _nl_get_alt_digit (number_value);
827
828               if (cp != NULL)
829                 {
830                   size_t digitlen = strlen (cp);
831                   if (digitlen != 0)
832                     {
833                       cpy (digitlen, cp);
834                       break;
835                     }
836                 }
837 #else
838 # if HAVE_STRFTIME
839               goto underlying_strftime;
840 # endif
841 #endif
842             }
843           {
844             unsigned int u = number_value;
845
846             bufp = buf + sizeof (buf);
847             negative_number = number_value < 0;
848
849             if (negative_number)
850               u = -u;
851
852             do
853               *--bufp = u % 10 + '0';
854             while ((u /= 10) != 0);
855           }
856
857         do_number_sign_and_padding:
858           if (negative_number)
859             *--bufp = '-';
860
861           if (pad != '-')
862             {
863               int padding = digits - (buf + sizeof (buf) - bufp);
864
865               if (pad == '_')
866                 {
867                   while (0 < padding--)
868                     *--bufp = ' ';
869                 }
870               else
871                 {
872                   bufp += negative_number;
873                   while (0 < padding--)
874                     *--bufp = '0';
875                   if (negative_number)
876                     *--bufp = '-';
877                 }
878             }
879
880           cpy (buf + sizeof (buf) - bufp, bufp);
881           break;
882
883         case 'F':
884           if (modifier != 0)
885             goto bad_format;
886           subfmt = "%Y-%m-%d";
887           goto subformat;
888
889         case 'H':
890           if (modifier == 'E')
891             goto bad_format;
892
893           DO_NUMBER (2, tp->tm_hour);
894
895         case 'I':
896           if (modifier == 'E')
897             goto bad_format;
898
899           DO_NUMBER (2, hour12);
900
901         case 'k':               /* GNU extension.  */
902           if (modifier == 'E')
903             goto bad_format;
904
905           DO_NUMBER_SPACEPAD (2, tp->tm_hour);
906
907         case 'l':               /* GNU extension.  */
908           if (modifier == 'E')
909             goto bad_format;
910
911           DO_NUMBER_SPACEPAD (2, hour12);
912
913         case 'j':
914           if (modifier == 'E')
915             goto bad_format;
916
917           DO_NUMBER (3, 1 + tp->tm_yday);
918
919         case 'M':
920           if (modifier == 'E')
921             goto bad_format;
922
923           DO_NUMBER (2, tp->tm_min);
924
925         case 'm':
926           if (modifier == 'E')
927             goto bad_format;
928
929           DO_NUMBER (2, tp->tm_mon + 1);
930
931         case 'n':               /* POSIX.2 extension.  */
932           add (1, *p = '\n');
933           break;
934
935         case 'P':
936           to_lowcase = 1;
937 #if !defined _NL_CURRENT && HAVE_STRFTIME
938           format_char = 'p';
939 #endif
940           /* FALLTHROUGH */
941
942         case 'p':
943           if (change_case)
944             {
945               to_uppcase = 0;
946               to_lowcase = 1;
947             }
948 #if defined _NL_CURRENT || !HAVE_STRFTIME
949           cpy (ap_len, ampm);
950           break;
951 #else
952           goto underlying_strftime;
953 #endif
954
955         case 'R':               /* GNU extension.  */
956           subfmt = "%H:%M";
957           goto subformat;
958
959         case 'r':               /* POSIX.2 extension.  */
960 #ifdef _NL_CURRENT
961           if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
962 #endif
963             subfmt = "%I:%M:%S %p";
964           goto subformat;
965
966         case 'S':
967           if (modifier == 'E')
968             goto bad_format;
969
970           DO_NUMBER (2, tp->tm_sec);
971
972         case 's':               /* GNU extension.  */
973           {
974             struct tm ltm;
975             time_t t;
976
977             ltm = *tp;
978             t = mktime (&ltm);
979
980             /* Generate string value for T using time_t arithmetic;
981                this works even if sizeof (long) < sizeof (time_t).  */
982
983             bufp = buf + sizeof (buf);
984             negative_number = t < 0;
985
986             do
987               {
988                 int d = t % 10;
989                 t /= 10;
990
991                 if (negative_number)
992                   {
993                     d = -d;
994
995                     /* Adjust if division truncates to minus infinity.  */
996                     if (0 < -1 % 10 && d < 0)
997                       {
998                         t++;
999                         d += 10;
1000                       }
1001                   }
1002
1003                 *--bufp = d + '0';
1004               }
1005             while (t != 0);
1006
1007             digits = 1;
1008             goto do_number_sign_and_padding;
1009           }
1010
1011         case 'X':
1012           if (modifier == 'O')
1013             goto bad_format;
1014 #ifdef _NL_CURRENT
1015           if (! (modifier == 'E'
1016                  && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
1017             subfmt = _NL_CURRENT (LC_TIME, T_FMT);
1018           goto subformat;
1019 #else
1020 # if HAVE_STRFTIME
1021           goto underlying_strftime;
1022 # else
1023           /* Fall through.  */
1024 # endif
1025 #endif
1026         case 'T':               /* POSIX.2 extension.  */
1027           subfmt = "%H:%M:%S";
1028           goto subformat;
1029
1030         case 't':               /* POSIX.2 extension.  */
1031           add (1, *p = '\t');
1032           break;
1033
1034         case 'f':
1035         case 'u':               /* POSIX.2 extension.  */
1036           DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1037
1038         case 'U':
1039           if (modifier == 'E')
1040             goto bad_format;
1041
1042           DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1043
1044         case 'V':
1045         case 'g':               /* GNU extension.  */
1046         case 'G':               /* GNU extension.  */
1047           if (modifier == 'E')
1048             goto bad_format;
1049           {
1050             int year = tp->tm_year + TM_YEAR_BASE;
1051             int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1052
1053             if (days < 0)
1054               {
1055                 /* This ISO week belongs to the previous year.  */
1056                 year--;
1057                 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
1058                                       tp->tm_wday);
1059               }
1060             else
1061               {
1062                 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1063                                        tp->tm_wday);
1064                 if (0 <= d)
1065                   {
1066                     /* This ISO week belongs to the next year.  */
1067                     year++;
1068                     days = d;
1069                   }
1070               }
1071
1072             switch (*f)
1073               {
1074               case 'g':
1075                 DO_NUMBER (2, (year % 100 + 100) % 100);
1076
1077               case 'G':
1078                 DO_NUMBER (1, year);
1079
1080               default:
1081                 DO_NUMBER (2, days / 7 + 1);
1082               }
1083           }
1084
1085         case 'W':
1086           if (modifier == 'E')
1087             goto bad_format;
1088
1089           DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1090
1091         case 'w':
1092           if (modifier == 'E')
1093             goto bad_format;
1094
1095           DO_NUMBER (1, tp->tm_wday);
1096
1097         case 'Y':
1098           if (modifier == 'E')
1099             {
1100 #if HAVE_STRUCT_ERA_ENTRY
1101               struct era_entry *era = _nl_get_era_entry (tp);
1102               if (era)
1103                 {
1104                   subfmt = strchr (era->name_fmt, '\0') + 1;
1105                   goto subformat;
1106                 }
1107 #else
1108 # if HAVE_STRFTIME
1109               goto underlying_strftime;
1110 # endif
1111 #endif
1112             }
1113           if (modifier == 'O')
1114             goto bad_format;
1115           else
1116             DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1117
1118         case 'y':
1119           if (modifier == 'E')
1120             {
1121 #if HAVE_STRUCT_ERA_ENTRY
1122               struct era_entry *era = _nl_get_era_entry (tp);
1123               if (era)
1124                 {
1125                   int delta = tp->tm_year - era->start_date[0];
1126                   DO_NUMBER (1, (era->offset
1127                                  + (era->direction == '-' ? -delta : delta)));
1128                 }
1129 #else
1130 # if HAVE_STRFTIME
1131               goto underlying_strftime;
1132 # endif
1133 #endif
1134             }
1135           DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1136
1137         case 'Z':
1138           if (change_case)
1139             {
1140               to_uppcase = 0;
1141               to_lowcase = 1;
1142             }
1143
1144 #if HAVE_TZNAME
1145           /* The tzset() call might have changed the value.  */
1146           if (!(zone && *zone) && tp->tm_isdst >= 0)
1147             zone = tzname[tp->tm_isdst];
1148 #endif
1149           if (! zone)
1150             zone = "";          /* POSIX.2 requires the empty string here.  */
1151
1152           cpy (strlen (zone), zone);
1153           break;
1154
1155         case 'z':               /* GNU extension.  */
1156           if (tp->tm_isdst < 0)
1157             break;
1158
1159           {
1160             int diff;
1161 #if HAVE_TM_GMTOFF
1162             diff = tp->tm_gmtoff;
1163 #else
1164             struct tm gtm;
1165             struct tm ltm;
1166             time_t lt;
1167
1168             ltm = *tp;
1169             lt = mktime (&ltm);
1170
1171             if (lt == (time_t) -1)
1172               {
1173                 /* mktime returns -1 for errors, but -1 is also a
1174                    valid time_t value.  Check whether an error really
1175                    occurred.  */
1176                 struct tm tm;
1177
1178                 if (! localtime_r (&lt, &tm)
1179                     || ((ltm.tm_sec ^ tm.tm_sec)
1180                         | (ltm.tm_min ^ tm.tm_min)
1181                         | (ltm.tm_hour ^ tm.tm_hour)
1182                         | (ltm.tm_mday ^ tm.tm_mday)
1183                         | (ltm.tm_mon ^ tm.tm_mon)
1184                         | (ltm.tm_year ^ tm.tm_year)))
1185                   break;
1186               }
1187
1188             if (! gmtime_r (&lt, &gtm))
1189               break;
1190
1191             diff = tm_diff (&ltm, &gtm);
1192 #endif
1193
1194             if (diff < 0)
1195               {
1196                 add (1, *p = '-');
1197                 diff = -diff;
1198               }
1199             else
1200               add (1, *p = '+');
1201
1202             diff /= 60;
1203             DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1204           }
1205
1206         case '\0':              /* GNU extension: % at end of format.  */
1207             --f;
1208             /* Fall through.  */
1209         default:
1210           /* Unknown format; output the format, including the '%',
1211              since this is most likely the right thing to do if a
1212              multibyte string has been misparsed.  */
1213         bad_format:
1214           {
1215             int flen;
1216             for (flen = 1; f[1 - flen] != '%'; flen++)
1217               continue;
1218             cpy (flen, &f[1 - flen]);
1219           }
1220           break;
1221         }
1222     }
1223
1224   if (p && i < maxsize)
1225     *p = '\0';
1226   return i;
1227 }