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