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