Update.
[glibc.git] / time / strftime.c
blob594cbbfe169ee9b41ddae55447ea608966346a7e
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.
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.
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.
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. */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 /* Some hosts need this in order to declare localtime_r properly. */
24 #ifndef __EXTENSIONS__
25 # define __EXTENSIONS__ 1
26 #endif
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
42 #if defined emacs && !defined HAVE_BCOPY
43 # define HAVE_MEMCPY 1
44 #endif
46 #include <ctype.h>
47 #include <sys/types.h> /* Some systems define `time_t' here. */
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
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)
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
83 #if HAVE_LIMITS_H
84 # include <limits.h>
85 #endif
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
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
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. */
113 #ifndef PTR
114 # ifdef __STDC__
115 # define PTR void *
116 # else
117 # define PTR char *
118 # endif
119 #endif
121 #ifndef CHAR_BIT
122 # define CHAR_BIT 8
123 #endif
125 #ifndef NULL
126 # define NULL 0
127 #endif
129 #define TYPE_SIGNED(t) ((t) -1 < 0)
131 /* Bound on length of the string representing an integer value of type t.
132 Subtract one for the sign bit if t is signed;
133 302 / 1000 is log10 (2) rounded up;
134 add one for integer division truncation;
135 add one more for a minus sign if t is signed. */
136 #define INT_STRLEN_BOUND(t) \
137 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
139 #define TM_YEAR_BASE 1900
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
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;
166 struct tm *l = gmtime (t);
167 if (! l)
168 return 0;
169 *tp = *l;
170 return tp;
172 # endif /* ! HAVE_TM_GMTOFF */
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;
183 struct tm *l = localtime (t);
184 if (! l)
185 return 0;
186 *tp = *l;
187 return tp;
189 # endif /* ! HAVE_LOCALTIME_R */
190 #endif /* ! defined _LIBC */
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' };
203 # define memset_space(P, Len) \
204 do { \
205 int _len = (Len); \
207 do \
209 int _this = _len > 16 ? 16 : _len; \
210 (P) = MEMPCPY ((P), spaces, _this); \
211 _len -= _this; \
213 while (_len > 0); \
214 } while (0)
216 # define memset_zero(P, Len) \
217 do { \
218 int _len = (Len); \
220 do \
222 int _this = _len > 16 ? 16 : _len; \
223 (P) = MEMPCPY ((P), zeroes, _this); \
224 _len -= _this; \
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
233 #define add(n, f) \
234 do \
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) \
243 if (_delta > 0) \
245 if (pad == '0') \
246 memset_zero (p, _delta); \
247 else \
248 memset_space (p, _delta); \
250 f; \
251 p += _n; \
253 i += _incr; \
254 } while (0)
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))
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)
280 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
282 static char *
283 memcpy_lowcase (dest, src, len)
284 char *dest;
285 const char *src;
286 size_t len;
288 while (len-- > 0)
289 dest[len] = TOLOWER ((unsigned char) src[len]);
290 return dest;
293 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
295 static char *
296 memcpy_uppcase (dest, src, len)
297 char *dest;
298 const char *src;
299 size_t len;
301 while (len-- > 0)
302 dest[len] = TOUPPER ((unsigned char) src[len]);
303 return dest;
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;
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));
334 #endif /* ! HAVE_TM_GMTOFF */
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;
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);
362 #if !(defined _NL_CURRENT || HAVE_STRFTIME)
363 static char const weekday_name[][10] =
365 "Sunday", "Monday", "Tuesday", "Wednesday",
366 "Thursday", "Friday", "Saturday"
368 static char const month_name[][10] =
370 "January", "February", "March", "April", "May", "June",
371 "July", "August", "September", "October", "November", "December"
373 #endif
376 #ifdef emacs
377 # define my_strftime emacs_strftime
378 #else
379 # define my_strftime strftime
380 #endif
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;
394 struct tm tmcopy;
395 tmcopy = *tp;
396 return _strftime_copytm (s, maxsize, format, &tmcopy);
398 # undef my_strftime
399 # define my_strftime(S, Maxsize, Format, Tp) \
400 _strftime_copytm (S, Maxsize, Format, Tp)
401 #endif
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;
417 int hour12 = tp->tm_hour;
418 #ifdef _NL_CURRENT
419 /* We cannot make the following values variables since we must dealy
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 and therefore 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 f_wkday _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday)
428 # define a_month _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon)
429 # define f_month _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon)
430 # define ampm _NL_CURRENT (LC_TIME, hour12 > 11 ? PM_STR : AM_STR)
432 # define aw_len strlen (a_wkday)
433 # define am_len strlen (a_month)
434 # define ap_len strlen (ampm)
436 # define wkday_len strlen (f_wkday)
437 # define month_len strlen (f_month)
438 #else
439 # if !HAVE_STRFTIME
440 const char *const f_wkday = weekday_name[tp->tm_wday];
441 const char *const f_month = month_name[tp->tm_mon];
442 const char *const a_wkday = f_wkday;
443 const char *const a_month = f_month;
444 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
445 size_t aw_len = 3;
446 size_t am_len = 3;
447 size_t ap_len = 2;
449 size_t wkday_len = strlen (f_wkday);
450 size_t month_len = strlen (f_month);
451 # endif
452 #endif
453 const char *zone;
454 size_t i = 0;
455 char *p = s;
456 const char *f;
458 zone = NULL;
459 #if HAVE_TM_ZONE
460 /* The POSIX test suite assumes that setting
461 the environment variable TZ to a new value before calling strftime()
462 will influence the result (the %Z format) even if the information in
463 TP is computed with a totally different time zone.
464 This is bogus: though POSIX allows bad behavior like this,
465 POSIX does not require it. Do the right thing instead. */
466 zone = (const char *) tp->tm_zone;
467 #endif
468 #if HAVE_TZNAME && HAVE_TZSET
469 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
470 time zone names contained in the external variable `tzname' shall
471 be set as if the tzset() function had been called. */
472 tzset ();
473 #endif
475 if (hour12 > 12)
476 hour12 -= 12;
477 else
478 if (hour12 == 0) hour12 = 12;
480 for (f = format; *f != '\0'; ++f)
482 int pad = 0; /* Padding for number ('-', '_', or 0). */
483 int modifier; /* Field modifier ('E', 'O', or 0). */
484 int digits; /* Max digits for numeric format. */
485 int number_value; /* Numeric value to be printed. */
486 int negative_number; /* 1 if the number is negative. */
487 const char *subfmt;
488 char *bufp;
489 char buf[1 + (sizeof (int) < sizeof (time_t)
490 ? INT_STRLEN_BOUND (time_t)
491 : INT_STRLEN_BOUND (int))];
492 int width = -1;
493 int to_lowcase = 0;
494 int to_uppcase = 0;
495 int change_case = 0;
496 int format_char;
498 #if DO_MULTIBYTE
500 switch (*f)
502 case '%':
503 break;
505 case '\a': case '\b': case '\t': case '\n':
506 case '\v': case '\f': case '\r':
507 case ' ': case '!': case '"': case '#': case '&': case'\'':
508 case '(': case ')': case '*': case '+': case ',': case '-':
509 case '.': case '/': case '0': case '1': case '2': case '3':
510 case '4': case '5': case '6': case '7': case '8': case '9':
511 case ':': case ';': case '<': case '=': case '>': case '?':
512 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
513 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
514 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
515 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
516 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
517 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
518 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
519 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
520 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
521 case 'x': case 'y': case 'z': case '{': case '|': case '}':
522 case '~':
523 /* The C Standard requires these 98 characters (plus '%') to
524 be in the basic execution character set. None of these
525 characters can start a multibyte sequence, so they need
526 not be analyzed further. */
527 add (1, *p = *f);
528 continue;
530 default:
531 /* Copy this multibyte sequence until we reach its end, find
532 an error, or come back to the initial shift state. */
534 mbstate_t mbstate = mbstate_zero;
535 size_t len = 0;
539 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
541 if (bytes == 0)
542 break;
544 if (bytes == (size_t) -2)
546 len += strlen (f + len);
547 break;
550 if (bytes == (size_t) -1)
552 len++;
553 break;
556 len += bytes;
558 while (! mbsinit (&mbstate));
560 cpy (len, f);
561 f += len - 1;
562 continue;
566 #else /* ! DO_MULTIBYTE */
568 /* Either multibyte encodings are not supported, or they are
569 safe for formats, so any non-'%' byte can be copied through. */
570 if (*f != '%')
572 add (1, *p = *f);
573 continue;
576 #endif /* ! DO_MULTIBYTE */
578 /* Check for flags that can modify a format. */
579 while (1)
581 switch (*++f)
583 /* This influences the number formats. */
584 case '_':
585 case '-':
586 case '0':
587 pad = *f;
588 continue;
590 /* This changes textual output. */
591 case '^':
592 to_uppcase = 1;
593 continue;
594 case '#':
595 change_case = 1;
596 continue;
598 default:
599 break;
601 break;
604 /* As a GNU extension we allow to specify the field width. */
605 if (ISDIGIT (*f))
607 width = 0;
610 width *= 10;
611 width += *f - '0';
612 ++f;
614 while (ISDIGIT (*f));
617 /* Check for modifiers. */
618 switch (*f)
620 case 'E':
621 case 'O':
622 modifier = *f++;
623 break;
625 default:
626 modifier = 0;
627 break;
630 /* Now do the specified format. */
631 format_char = *f;
632 switch (format_char)
634 #define DO_NUMBER(d, v) \
635 digits = width == -1 ? d : width; \
636 number_value = v; goto do_number
637 #define DO_NUMBER_SPACEPAD(d, v) \
638 digits = width == -1 ? d : width; \
639 number_value = v; goto do_number_spacepad
641 case '%':
642 if (modifier != 0)
643 goto bad_format;
644 add (1, *p = *f);
645 break;
647 case 'a':
648 if (modifier != 0)
649 goto bad_format;
650 if (change_case)
652 to_uppcase = 1;
653 to_lowcase = 0;
655 #if defined _NL_CURRENT || !HAVE_STRFTIME
656 cpy (aw_len, a_wkday);
657 break;
658 #else
659 goto underlying_strftime;
660 #endif
662 case 'A':
663 if (modifier != 0)
664 goto bad_format;
665 if (change_case)
667 to_uppcase = 1;
668 to_lowcase = 0;
670 #if defined _NL_CURRENT || !HAVE_STRFTIME
671 cpy (wkday_len, f_wkday);
672 break;
673 #else
674 goto underlying_strftime;
675 #endif
677 case 'b':
678 case 'h': /* POSIX.2 extension. */
679 if (modifier != 0)
680 goto bad_format;
681 #if defined _NL_CURRENT || !HAVE_STRFTIME
682 cpy (am_len, a_month);
683 break;
684 #else
685 goto underlying_strftime;
686 #endif
688 case 'B':
689 if (modifier != 0)
690 goto bad_format;
691 if (change_case)
693 to_uppcase = 1;
694 to_lowcase = 0;
696 #if defined _NL_CURRENT || !HAVE_STRFTIME
697 cpy (month_len, f_month);
698 break;
699 #else
700 goto underlying_strftime;
701 #endif
703 case 'c':
704 if (modifier == 'O')
705 goto bad_format;
706 #ifdef _NL_CURRENT
707 if (! (modifier == 'E'
708 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
709 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
710 #else
711 # if HAVE_STRFTIME
712 goto underlying_strftime;
713 # else
714 subfmt = "%a %b %e %H:%M:%S %Y";
715 # endif
716 #endif
718 subformat:
720 char *old_start = p;
721 size_t len = my_strftime (NULL, maxsize - i, subfmt, tp);
722 if (len == 0 && *subfmt)
723 return 0;
724 add (len, my_strftime (p, maxsize - i, subfmt, tp));
726 if (to_uppcase)
727 while (old_start < p)
729 *old_start = TOUPPER ((unsigned char) *old_start);
730 ++old_start;
733 break;
735 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
736 underlying_strftime:
738 /* The relevant information is available only via the
739 underlying strftime implementation, so use that. */
740 char ufmt[4];
741 char *u = ufmt;
742 char ubuf[1024]; /* enough for any single format in practice */
743 size_t len;
744 *u++ = '%';
745 if (modifier != 0)
746 *u++ = modifier;
747 *u++ = format_char;
748 *u = '\0';
749 len = strftime (ubuf, sizeof ubuf, ufmt, tp);
750 if (len == 0)
751 return 0;
752 cpy (len, ubuf);
754 break;
755 #endif
757 case 'C': /* POSIX.2 extension. */
758 if (modifier == 'O')
759 goto bad_format;
760 if (modifier == 'E')
762 #if HAVE_STRUCT_ERA_ENTRY
763 struct era_entry *era = _nl_get_era_entry (tp);
764 if (era)
766 size_t len = strlen (era->name_fmt);
767 cpy (len, era->name_fmt);
768 break;
770 #else
771 # if HAVE_STRFTIME
772 goto underlying_strftime;
773 # endif
774 #endif
778 int year = tp->tm_year + TM_YEAR_BASE;
779 DO_NUMBER (1, year / 100 - (year % 100 < 0));
782 case 'x':
783 if (modifier == 'O')
784 goto bad_format;
785 #ifdef _NL_CURRENT
786 if (! (modifier == 'E'
787 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
788 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
789 goto subformat;
790 #else
791 # if HAVE_STRFTIME
792 goto underlying_strftime;
793 # else
794 /* Fall through. */
795 # endif
796 #endif
797 case 'D': /* POSIX.2 extension. */
798 if (modifier != 0)
799 goto bad_format;
800 subfmt = "%m/%d/%y";
801 goto subformat;
803 case 'd':
804 if (modifier == 'E')
805 goto bad_format;
807 DO_NUMBER (2, tp->tm_mday);
809 case 'e': /* POSIX.2 extension. */
810 if (modifier == 'E')
811 goto bad_format;
813 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
815 /* All numeric formats set DIGITS and NUMBER_VALUE and then
816 jump to one of these two labels. */
818 do_number_spacepad:
819 /* Force `_' flag unless overwritten by `0' flag. */
820 if (pad != '0')
821 pad = '_';
823 do_number:
824 /* Format the number according to the MODIFIER flag. */
826 if (modifier == 'O' && 0 <= number_value)
828 #ifdef _NL_CURRENT
829 /* Get the locale specific alternate representation of
830 the number NUMBER_VALUE. If none exist NULL is returned. */
831 const char *cp = _nl_get_alt_digit (number_value);
833 if (cp != NULL)
835 size_t digitlen = strlen (cp);
836 if (digitlen != 0)
838 cpy (digitlen, cp);
839 break;
842 #else
843 # if HAVE_STRFTIME
844 goto underlying_strftime;
845 # endif
846 #endif
849 unsigned int u = number_value;
851 bufp = buf + sizeof (buf);
852 negative_number = number_value < 0;
854 if (negative_number)
855 u = -u;
858 *--bufp = u % 10 + '0';
859 while ((u /= 10) != 0);
862 do_number_sign_and_padding:
863 if (negative_number)
864 *--bufp = '-';
866 if (pad != '-')
868 int padding = digits - (buf + sizeof (buf) - bufp);
870 if (pad == '_')
872 while (0 < padding--)
873 *--bufp = ' ';
875 else
877 bufp += negative_number;
878 while (0 < padding--)
879 *--bufp = '0';
880 if (negative_number)
881 *--bufp = '-';
885 cpy (buf + sizeof (buf) - bufp, bufp);
886 break;
888 case 'F':
889 if (modifier != 0)
890 goto bad_format;
891 subfmt = "%Y-%m-%d";
892 goto subformat;
894 case 'H':
895 if (modifier == 'E')
896 goto bad_format;
898 DO_NUMBER (2, tp->tm_hour);
900 case 'I':
901 if (modifier == 'E')
902 goto bad_format;
904 DO_NUMBER (2, hour12);
906 case 'k': /* GNU extension. */
907 if (modifier == 'E')
908 goto bad_format;
910 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
912 case 'l': /* GNU extension. */
913 if (modifier == 'E')
914 goto bad_format;
916 DO_NUMBER_SPACEPAD (2, hour12);
918 case 'j':
919 if (modifier == 'E')
920 goto bad_format;
922 DO_NUMBER (3, 1 + tp->tm_yday);
924 case 'M':
925 if (modifier == 'E')
926 goto bad_format;
928 DO_NUMBER (2, tp->tm_min);
930 case 'm':
931 if (modifier == 'E')
932 goto bad_format;
934 DO_NUMBER (2, tp->tm_mon + 1);
936 case 'n': /* POSIX.2 extension. */
937 add (1, *p = '\n');
938 break;
940 case 'P':
941 to_lowcase = 1;
942 #if !defined _NL_CURRENT && HAVE_STRFTIME
943 format_char = 'p';
944 #endif
945 /* FALLTHROUGH */
947 case 'p':
948 if (change_case)
950 to_uppcase = 0;
951 to_lowcase = 1;
953 #if defined _NL_CURRENT || !HAVE_STRFTIME
954 cpy (ap_len, ampm);
955 break;
956 #else
957 goto underlying_strftime;
958 #endif
960 case 'R': /* GNU extension. */
961 subfmt = "%H:%M";
962 goto subformat;
964 case 'r': /* POSIX.2 extension. */
965 #ifdef _NL_CURRENT
966 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
967 #endif
968 subfmt = "%I:%M:%S %p";
969 goto subformat;
971 case 'S':
972 if (modifier == 'E')
973 goto bad_format;
975 DO_NUMBER (2, tp->tm_sec);
977 case 's': /* GNU extension. */
979 struct tm ltm;
980 time_t t;
982 ltm = *tp;
983 t = mktime (&ltm);
985 /* Generate string value for T using time_t arithmetic;
986 this works even if sizeof (long) < sizeof (time_t). */
988 bufp = buf + sizeof (buf);
989 negative_number = t < 0;
993 int d = t % 10;
994 t /= 10;
996 if (negative_number)
998 d = -d;
1000 /* Adjust if division truncates to minus infinity. */
1001 if (0 < -1 % 10 && d < 0)
1003 t++;
1004 d += 10;
1008 *--bufp = d + '0';
1010 while (t != 0);
1012 digits = 1;
1013 goto do_number_sign_and_padding;
1016 case 'X':
1017 if (modifier == 'O')
1018 goto bad_format;
1019 #ifdef _NL_CURRENT
1020 if (! (modifier == 'E'
1021 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
1022 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
1023 goto subformat;
1024 #else
1025 # if HAVE_STRFTIME
1026 goto underlying_strftime;
1027 # else
1028 /* Fall through. */
1029 # endif
1030 #endif
1031 case 'T': /* POSIX.2 extension. */
1032 subfmt = "%H:%M:%S";
1033 goto subformat;
1035 case 't': /* POSIX.2 extension. */
1036 add (1, *p = '\t');
1037 break;
1039 case 'f':
1040 case 'u': /* POSIX.2 extension. */
1041 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1043 case 'U':
1044 if (modifier == 'E')
1045 goto bad_format;
1047 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1049 case 'V':
1050 case 'g': /* GNU extension. */
1051 case 'G': /* GNU extension. */
1052 if (modifier == 'E')
1053 goto bad_format;
1055 int year = tp->tm_year + TM_YEAR_BASE;
1056 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1058 if (days < 0)
1060 /* This ISO week belongs to the previous year. */
1061 year--;
1062 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
1063 tp->tm_wday);
1065 else
1067 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1068 tp->tm_wday);
1069 if (0 <= d)
1071 /* This ISO week belongs to the next year. */
1072 year++;
1073 days = d;
1077 switch (*f)
1079 case 'g':
1080 DO_NUMBER (2, (year % 100 + 100) % 100);
1082 case 'G':
1083 DO_NUMBER (1, year);
1085 default:
1086 DO_NUMBER (2, days / 7 + 1);
1090 case 'W':
1091 if (modifier == 'E')
1092 goto bad_format;
1094 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1096 case 'w':
1097 if (modifier == 'E')
1098 goto bad_format;
1100 DO_NUMBER (1, tp->tm_wday);
1102 case 'Y':
1103 if (modifier == 'E')
1105 #if HAVE_STRUCT_ERA_ENTRY
1106 struct era_entry *era = _nl_get_era_entry (tp);
1107 if (era)
1109 subfmt = strchr (era->name_fmt, '\0') + 1;
1110 goto subformat;
1112 #else
1113 # if HAVE_STRFTIME
1114 goto underlying_strftime;
1115 # endif
1116 #endif
1118 if (modifier == 'O')
1119 goto bad_format;
1120 else
1121 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1123 case 'y':
1124 if (modifier == 'E')
1126 #if HAVE_STRUCT_ERA_ENTRY
1127 struct era_entry *era = _nl_get_era_entry (tp);
1128 if (era)
1130 int delta = tp->tm_year - era->start_date[0];
1131 DO_NUMBER (1, (era->offset
1132 + (era->direction == '-' ? -delta : delta)));
1134 #else
1135 # if HAVE_STRFTIME
1136 goto underlying_strftime;
1137 # endif
1138 #endif
1140 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1142 case 'Z':
1143 if (change_case)
1145 to_uppcase = 0;
1146 to_lowcase = 1;
1149 #if HAVE_TZNAME
1150 /* The tzset() call might have changed the value. */
1151 if (!(zone && *zone) && tp->tm_isdst >= 0)
1152 zone = tzname[tp->tm_isdst];
1153 #endif
1154 if (! zone)
1155 zone = ""; /* POSIX.2 requires the empty string here. */
1157 cpy (strlen (zone), zone);
1158 break;
1160 case 'z': /* GNU extension. */
1161 if (tp->tm_isdst < 0)
1162 break;
1165 int diff;
1166 #if HAVE_TM_GMTOFF
1167 diff = tp->tm_gmtoff;
1168 #else
1169 struct tm gtm;
1170 struct tm ltm;
1171 time_t lt;
1173 ltm = *tp;
1174 lt = mktime (&ltm);
1176 if (lt == (time_t) -1)
1178 /* mktime returns -1 for errors, but -1 is also a
1179 valid time_t value. Check whether an error really
1180 occurred. */
1181 struct tm tm;
1183 if (! localtime_r (&lt, &tm)
1184 || ((ltm.tm_sec ^ tm.tm_sec)
1185 | (ltm.tm_min ^ tm.tm_min)
1186 | (ltm.tm_hour ^ tm.tm_hour)
1187 | (ltm.tm_mday ^ tm.tm_mday)
1188 | (ltm.tm_mon ^ tm.tm_mon)
1189 | (ltm.tm_year ^ tm.tm_year)))
1190 break;
1193 if (! gmtime_r (&lt, &gtm))
1194 break;
1196 diff = tm_diff (&ltm, &gtm);
1197 #endif
1199 if (diff < 0)
1201 add (1, *p = '-');
1202 diff = -diff;
1204 else
1205 add (1, *p = '+');
1207 diff /= 60;
1208 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1211 case '\0': /* GNU extension: % at end of format. */
1212 --f;
1213 /* Fall through. */
1214 default:
1215 /* Unknown format; output the format, including the '%',
1216 since this is most likely the right thing to do if a
1217 multibyte string has been misparsed. */
1218 bad_format:
1220 int flen;
1221 for (flen = 1; f[1 - flen] != '%'; flen++)
1222 continue;
1223 cpy (flen, &f[1 - flen]);
1225 break;
1229 if (p)
1230 *p = '\0';
1231 return i;