new version
[emacs.git] / src / strftime.c
blobfea7c7409679aa02df41efa9d66ed55a62166c71
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
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.
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.
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.
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. */
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
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
39 #include <ctype.h>
40 #include <sys/types.h> /* Some systems define `time_t' here. */
42 #ifdef TIME_WITH_SYS_TIME
43 # include <sys/time.h>
44 # include <time.h>
45 #else
46 # ifdef HAVE_SYS_TIME_H
47 # include <sys/time.h>
48 # else
49 # include <time.h>
50 # endif
51 #endif
52 #if HAVE_TZNAME
53 extern char *tzname[];
54 #endif
56 /* Do multibyte processing if multibytes are supported, unless
57 multibyte sequences are safe in formats. Multibyte sequences are
58 safe if they cannot contain byte sequences that look like format
59 conversion specifications. The GNU C Library uses UTF8 multibyte
60 encoding, which is safe for formats, but strftime.c can be used
61 with other C libraries that use unsafe encodings. */
62 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
64 #if DO_MULTIBYTE
65 # if HAVE_MBRLEN
66 # include <wchar.h>
67 # else
68 /* Simulate mbrlen with mblen as best we can. */
69 # define mbstate_t int
70 # define mbrlen(s, n, ps) mblen (s, n)
71 # define mbsinit(ps) (*(ps) == 0)
72 # endif
73 static const mbstate_t mbstate_zero;
74 #endif
76 #if HAVE_LIMITS_H
77 # include <limits.h>
78 #endif
80 #if STDC_HEADERS
81 # include <stddef.h>
82 # include <stdlib.h>
83 # include <string.h>
84 #else
85 # ifndef HAVE_MEMCPY
86 # define memcpy(d, s, n) bcopy ((s), (d), (n))
87 # endif
88 #endif
90 #ifndef __P
91 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
92 # define __P(args) args
93 # else
94 # define __P(args) ()
95 # endif /* GCC. */
96 #endif /* Not __P. */
98 #ifndef PTR
99 # ifdef __STDC__
100 # define PTR void *
101 # else
102 # define PTR char *
103 # endif
104 #endif
106 #ifndef CHAR_BIT
107 # define CHAR_BIT 8
108 #endif
110 #ifndef NULL
111 # define NULL 0
112 #endif
114 #define TYPE_SIGNED(t) ((t) -1 < 0)
116 /* Bound on length of the string representing an integer value of type t.
117 Subtract one for the sign bit if t is signed;
118 302 / 1000 is log10 (2) rounded up;
119 add one for integer division truncation;
120 add one more for a minus sign if t is signed. */
121 #define INT_STRLEN_BOUND(t) \
122 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
124 #define TM_YEAR_BASE 1900
126 #ifndef __isleap
127 /* Nonzero if YEAR is a leap year (every 4 years,
128 except every 100th isn't, and every 400th is). */
129 # define __isleap(year) \
130 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
131 #endif
134 #ifdef _LIBC
135 # define gmtime_r __gmtime_r
136 # define localtime_r __localtime_r
137 extern int __tz_compute __P ((time_t timer, const struct tm *tm));
138 # define tzname __tzname
139 # define tzset __tzset
140 #else
141 # if ! HAVE_LOCALTIME_R
142 # if ! HAVE_TM_GMTOFF
143 /* Approximate gmtime_r as best we can in its absence. */
144 # define gmtime_r my_gmtime_r
145 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
146 static struct tm *
147 gmtime_r (t, tp)
148 const time_t *t;
149 struct tm *tp;
151 struct tm *l = gmtime (t);
152 if (! l)
153 return 0;
154 *tp = *l;
155 return tp;
157 # endif /* ! HAVE_TM_GMTOFF */
159 /* Approximate localtime_r as best we can in its absence. */
160 # define localtime_r my_ftime_localtime_r
161 static struct tm *localtime_r __P ((const time_t *, struct tm *));
162 static struct tm *
163 localtime_r (t, tp)
164 const time_t *t;
165 struct tm *tp;
167 struct tm *l = localtime (t);
168 if (! l)
169 return 0;
170 *tp = *l;
171 return tp;
173 # endif /* ! HAVE_LOCALTIME_R */
174 #endif /* ! defined (_LIBC) */
177 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
178 /* Some systems lack the `memset' function and we don't want to
179 introduce additional dependencies. */
180 /* The SGI compiler reportedly barfs on the trailing null
181 if we use a string constant as the initializer. 28 June 1997, rms. */
182 static const char spaces[16] = /* " " */
183 { ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
184 static const char zeroes[16] = /* "0000000000000000" */
185 { '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' };
187 # define memset_space(P, Len) \
188 do { \
189 int _len = (Len); \
191 do \
193 int _this = _len > 16 ? 16 : _len; \
194 memcpy ((P), spaces, _this); \
195 (P) += _this; \
196 _len -= _this; \
198 while (_len > 0); \
199 } while (0)
201 # define memset_zero(P, Len) \
202 do { \
203 int _len = (Len); \
205 do \
207 int _this = _len > 16 ? 16 : _len; \
208 memcpy ((P), zeroes, _this); \
209 (P) += _this; \
210 _len -= _this; \
212 while (_len > 0); \
213 } while (0)
214 #else
215 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
216 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
217 #endif
219 #define add(n, f) \
220 do \
222 int _n = (n); \
223 int _delta = width - _n; \
224 int _incr = _n + (_delta > 0 ? _delta : 0); \
225 if (i + _incr >= maxsize) \
226 return 0; \
227 if (p) \
229 if (_delta > 0) \
231 if (pad == '0') \
232 memset_zero (p, _delta); \
233 else \
234 memset_space (p, _delta); \
236 f; \
237 p += _n; \
239 i += _incr; \
240 } while (0)
242 #define cpy(n, s) \
243 add ((n), \
244 if (to_lowcase) \
245 memcpy_lowcase (p, (s), _n); \
246 else if (to_uppcase) \
247 memcpy_uppcase (p, (s), _n); \
248 else \
249 memcpy ((PTR) p, (PTR) (s), _n))
253 #ifdef _LIBC
254 # define TOUPPER(Ch) toupper (Ch)
255 # define TOLOWER(Ch) tolower (Ch)
256 #else
257 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
258 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
259 #endif
260 /* We don't use `isdigit' here since the locale dependent
261 interpretation is not what we want here. We only need to accept
262 the arabic digits in the ASCII range. One day there is perhaps a
263 more reliable way to accept other sets of digits. */
264 #define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
266 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
268 static char *
269 memcpy_lowcase (dest, src, len)
270 char *dest;
271 const char *src;
272 size_t len;
274 while (len-- > 0)
275 dest[len] = TOLOWER (src[len]);
276 return dest;
279 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
281 static char *
282 memcpy_uppcase (dest, src, len)
283 char *dest;
284 const char *src;
285 size_t len;
287 while (len-- > 0)
288 dest[len] = TOUPPER (src[len]);
289 return dest;
293 #if ! HAVE_TM_GMTOFF
294 /* Yield the difference between *A and *B,
295 measured in seconds, ignoring leap seconds. */
296 # define tm_diff ftime_tm_diff
297 static int tm_diff __P ((const struct tm *, const struct tm *));
298 static int
299 tm_diff (a, b)
300 const struct tm *a;
301 const struct tm *b;
303 /* Compute intervening leap days correctly even if year is negative.
304 Take care to avoid int overflow in leap day calculations,
305 but it's OK to assume that A and B are close to each other. */
306 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
307 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
308 int a100 = a4 / 25 - (a4 % 25 < 0);
309 int b100 = b4 / 25 - (b4 % 25 < 0);
310 int a400 = a100 >> 2;
311 int b400 = b100 >> 2;
312 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
313 int years = a->tm_year - b->tm_year;
314 int days = (365 * years + intervening_leap_days
315 + (a->tm_yday - b->tm_yday));
316 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
317 + (a->tm_min - b->tm_min))
318 + (a->tm_sec - b->tm_sec));
320 #endif /* ! HAVE_TM_GMTOFF */
324 /* The number of days from the first day of the first ISO week of this
325 year to the year day YDAY with week day WDAY. ISO weeks start on
326 Monday; the first ISO week has the year's first Thursday. YDAY may
327 be as small as YDAY_MINIMUM. */
328 #define ISO_WEEK_START_WDAY 1 /* Monday */
329 #define ISO_WEEK1_WDAY 4 /* Thursday */
330 #define YDAY_MINIMUM (-366)
331 static int iso_week_days __P ((int, int));
332 #ifdef __GNUC__
333 inline
334 #endif
335 static int
336 iso_week_days (yday, wday)
337 int yday;
338 int wday;
340 /* Add enough to the first operand of % to make it nonnegative. */
341 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
342 return (yday
343 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
344 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
348 #ifndef _NL_CURRENT
349 static char const weekday_name[][10] =
351 "Sunday", "Monday", "Tuesday", "Wednesday",
352 "Thursday", "Friday", "Saturday"
354 static char const month_name[][10] =
356 "January", "February", "March", "April", "May", "June",
357 "July", "August", "September", "October", "November", "December"
359 #endif
362 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
363 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
364 Work around this bug by copying *tp before it might be munged. */
365 size_t _strftime_copytm __P ((char *, size_t, const char *,
366 const struct tm *));
367 size_t
368 strftime (s, maxsize, format, tp)
369 char *s;
370 size_t maxsize;
371 const char *format;
372 const struct tm *tp;
374 struct tm tmcopy;
375 tmcopy = *tp;
376 return _strftime_copytm (s, maxsize, format, &tmcopy);
378 # ifdef strftime
379 # undef strftime
380 # endif
381 # define strftime(S, Maxsize, Format, Tp) \
382 _strftime_copytm (S, Maxsize, Format, Tp)
383 #endif
386 /* Write information from TP into S according to the format
387 string FORMAT, writing no more that MAXSIZE characters
388 (including the terminating '\0') and returning number of
389 characters written. If S is NULL, nothing will be written
390 anywhere, so to determine how many characters would be
391 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
392 size_t
393 strftime (s, maxsize, format, tp)
394 char *s;
395 size_t maxsize;
396 const char *format;
397 const struct tm *tp;
399 int hour12 = tp->tm_hour;
400 #ifdef _NL_CURRENT
401 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
402 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
403 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
404 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
405 const char *const ampm = _NL_CURRENT (LC_TIME,
406 hour12 > 11 ? PM_STR : AM_STR);
407 size_t aw_len = strlen (a_wkday);
408 size_t am_len = strlen (a_month);
409 size_t ap_len = strlen (ampm);
410 #else
411 const char *const f_wkday = weekday_name[tp->tm_wday];
412 const char *const f_month = month_name[tp->tm_mon];
413 const char *const a_wkday = f_wkday;
414 const char *const a_month = f_month;
415 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
416 size_t aw_len = 3;
417 size_t am_len = 3;
418 size_t ap_len = 2;
419 #endif
420 size_t wkday_len = strlen (f_wkday);
421 size_t month_len = strlen (f_month);
422 const char *zone;
423 size_t zonelen;
424 size_t i = 0;
425 char *p = s;
426 const char *f;
428 zone = NULL;
429 #if HAVE_TM_ZONE
430 /* The POSIX test suite assumes that setting
431 the environment variable TZ to a new value before calling strftime()
432 will influence the result (the %Z format) even if the information in
433 TP is computed with a totally different time zone.
434 This is bogus: though POSIX allows bad behavior like this,
435 POSIX does not require it. Do the right thing instead. */
436 zone = (const char *) tp->tm_zone;
437 #endif
438 #if HAVE_TZNAME
439 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
440 time zone names contained in the external variable `tzname' shall
441 be set as if the tzset() function had been called. */
442 # if HAVE_TZSET
443 tzset ();
444 # endif
446 if (!(zone && *zone) && tp->tm_isdst >= 0)
447 zone = tzname[tp->tm_isdst];
448 #endif
449 if (! zone)
450 zone = ""; /* POSIX.2 requires the empty string here. */
452 zonelen = strlen (zone);
454 if (hour12 > 12)
455 hour12 -= 12;
456 else
457 if (hour12 == 0) hour12 = 12;
459 for (f = format; *f != '\0'; ++f)
461 int pad; /* Padding for number ('-', '_', or 0). */
462 int modifier; /* Field modifier ('E', 'O', or 0). */
463 int digits; /* Max digits for numeric format. */
464 int number_value; /* Numeric value to be printed. */
465 int negative_number; /* 1 if the number is negative. */
466 const char *subfmt;
467 char *bufp;
468 char buf[1 + (sizeof (int) < sizeof (time_t)
469 ? INT_STRLEN_BOUND (time_t)
470 : INT_STRLEN_BOUND (int))];
471 int width = -1;
472 int to_lowcase = 0;
473 int to_uppcase = 0;
474 int change_case = 0;
476 #if DO_MULTIBYTE
478 switch (*f)
480 case '%':
481 break;
483 case '\a': case '\b': case '\t': case '\n':
484 case '\v': case '\f': case '\r':
485 case ' ': case '!': case '"': case '#': case '&': case'\'':
486 case '(': case ')': case '*': case '+': case ',': case '-':
487 case '.': case '/': case '0': case '1': case '2': case '3':
488 case '4': case '5': case '6': case '7': case '8': case '9':
489 case ':': case ';': case '<': case '=': case '>': case '?':
490 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
491 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
492 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
493 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
494 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
495 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
496 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
497 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
498 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
499 case 'x': case 'y': case 'z': case '{': case '|': case '}':
500 case '~':
501 /* The C Standard requires these 98 characters (plus '%') to
502 be in the basic execution character set. None of these
503 characters can start a multibyte sequence, so they need
504 not be analyzed further. */
505 add (1, *p = *f);
506 continue;
508 default:
509 /* Copy this multibyte sequence until we reach its end, find
510 an error, or come back to the initial shift state. */
512 mbstate_t mbstate = mbstate_zero;
513 size_t len = 0;
517 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
519 if (bytes == 0)
520 break;
522 if (bytes == (size_t) -2 || bytes == (size_t) -1)
524 len++;
525 break;
528 len += bytes;
530 while (! mbsinit (&mbstate));
532 cpy (len, f);
533 continue;
537 #else /* ! DO_MULTIBYTE */
539 /* Either multibyte encodings are not supported, or they are
540 safe for formats, so any non-'%' byte can be copied through. */
541 if (*f != '%')
543 add (1, *p = *f);
544 continue;
547 #endif /* ! DO_MULTIBYTE */
549 /* Check for flags that can modify a format. */
550 pad = 0;
551 while (1)
553 switch (*++f)
555 /* This influences the number formats. */
556 case '_':
557 case '-':
558 case '0':
559 pad = *f;
560 continue;
562 /* This changes textual output. */
563 case '^':
564 to_uppcase = 1;
565 continue;
566 case '#':
567 change_case = 1;
568 continue;
570 default:
571 break;
573 break;
576 /* As a GNU extension we allow to specify the field width. */
577 if (ISDIGIT (*f))
579 width = 0;
582 width *= 10;
583 width += *f - '0';
584 ++f;
586 while (ISDIGIT (*f));
589 /* Check for modifiers. */
590 switch (*f)
592 case 'E':
593 case 'O':
594 modifier = *f++;
595 break;
597 default:
598 modifier = 0;
599 break;
602 /* Now do the specified format. */
603 switch (*f)
605 #define DO_NUMBER(d, v) \
606 digits = width == -1 ? d : width; \
607 number_value = v; goto do_number
608 #define DO_NUMBER_SPACEPAD(d, v) \
609 digits = width == -1 ? d : width; \
610 number_value = v; goto do_number_spacepad
612 case '%':
613 if (modifier != 0)
614 goto bad_format;
615 add (1, *p = *f);
616 break;
618 case 'a':
619 if (modifier != 0)
620 goto bad_format;
621 if (change_case)
623 to_uppcase = 1;
624 to_lowcase = 0;
626 cpy (aw_len, a_wkday);
627 break;
629 case 'A':
630 if (modifier != 0)
631 goto bad_format;
632 if (change_case)
634 to_uppcase = 1;
635 to_lowcase = 0;
637 cpy (wkday_len, f_wkday);
638 break;
640 case 'b':
641 case 'h': /* POSIX.2 extension. */
642 if (modifier != 0)
643 goto bad_format;
644 cpy (am_len, a_month);
645 break;
647 case 'B':
648 if (modifier != 0)
649 goto bad_format;
650 if (change_case)
652 to_uppcase = 1;
653 to_lowcase = 0;
655 cpy (month_len, f_month);
656 break;
658 case 'c':
659 if (modifier == 'O')
660 goto bad_format;
661 #ifdef _NL_CURRENT
662 if (! (modifier == 'E'
663 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
664 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
665 #else
666 subfmt = "%a %b %e %H:%M:%S %Y";
667 #endif
669 subformat:
671 char *old_start = p;
672 size_t len = strftime (NULL, maxsize - i, subfmt, tp);
673 if (len == 0 && *subfmt)
674 return 0;
675 add (len, strftime (p, maxsize - i, subfmt, tp));
677 if (to_uppcase)
678 while (old_start < p)
680 *old_start = TOUPPER (*old_start);
681 ++old_start;
684 break;
686 case 'C': /* POSIX.2 extension. */
687 if (modifier == 'O')
688 goto bad_format;
689 #if HAVE_STRUCT_ERA_ENTRY
690 if (modifier == 'E')
692 struct era_entry *era = _nl_get_era_entry (tp);
693 if (era)
695 size_t len = strlen (era->name_fmt);
696 cpy (len, era->name_fmt);
697 break;
700 #endif
702 int year = tp->tm_year + TM_YEAR_BASE;
703 DO_NUMBER (1, year / 100 - (year % 100 < 0));
706 case 'x':
707 if (modifier == 'O')
708 goto bad_format;
709 #ifdef _NL_CURRENT
710 if (! (modifier == 'E'
711 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
712 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
713 goto subformat;
714 #endif
715 /* Fall through. */
716 case 'D': /* POSIX.2 extension. */
717 if (modifier != 0)
718 goto bad_format;
719 subfmt = "%m/%d/%y";
720 goto subformat;
722 case 'd':
723 if (modifier == 'E')
724 goto bad_format;
726 DO_NUMBER (2, tp->tm_mday);
728 case 'e': /* POSIX.2 extension. */
729 if (modifier == 'E')
730 goto bad_format;
732 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
734 /* All numeric formats set DIGITS and NUMBER_VALUE and then
735 jump to one of these two labels. */
737 do_number_spacepad:
738 /* Force `_' flag unless overwritten by `0' flag. */
739 if (pad != '0')
740 pad = '_';
742 do_number:
743 /* Format the number according to the MODIFIER flag. */
745 #ifdef _NL_CURRENT
746 if (modifier == 'O' && 0 <= number_value)
748 /* Get the locale specific alternate representation of
749 the number NUMBER_VALUE. If none exist NULL is returned. */
750 const char *cp = _nl_get_alt_digit (number_value);
752 if (cp != NULL)
754 size_t digitlen = strlen (cp);
755 if (digitlen != 0)
757 cpy (digitlen, cp);
758 break;
762 #endif
764 unsigned int u = number_value;
766 bufp = buf + sizeof (buf);
767 negative_number = number_value < 0;
769 if (negative_number)
770 u = -u;
773 *--bufp = u % 10 + '0';
774 while ((u /= 10) != 0);
777 do_number_sign_and_padding:
778 if (negative_number)
779 *--bufp = '-';
781 if (pad != '-')
783 int padding = digits - (buf + sizeof (buf) - bufp);
785 if (pad == '_')
787 while (0 < padding--)
788 *--bufp = ' ';
790 else
792 bufp += negative_number;
793 while (0 < padding--)
794 *--bufp = '0';
795 if (negative_number)
796 *--bufp = '-';
800 cpy (buf + sizeof (buf) - bufp, bufp);
801 break;
804 case 'H':
805 if (modifier == 'E')
806 goto bad_format;
808 DO_NUMBER (2, tp->tm_hour);
810 case 'I':
811 if (modifier == 'E')
812 goto bad_format;
814 DO_NUMBER (2, hour12);
816 case 'k': /* GNU extension. */
817 if (modifier == 'E')
818 goto bad_format;
820 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
822 case 'l': /* GNU extension. */
823 if (modifier == 'E')
824 goto bad_format;
826 DO_NUMBER_SPACEPAD (2, hour12);
828 case 'j':
829 if (modifier == 'E')
830 goto bad_format;
832 DO_NUMBER (3, 1 + tp->tm_yday);
834 case 'M':
835 if (modifier == 'E')
836 goto bad_format;
838 DO_NUMBER (2, tp->tm_min);
840 case 'm':
841 if (modifier == 'E')
842 goto bad_format;
844 DO_NUMBER (2, tp->tm_mon + 1);
846 case 'n': /* POSIX.2 extension. */
847 add (1, *p = '\n');
848 break;
850 case 'P':
851 to_lowcase = 1;
852 /* FALLTHROUGH */
854 case 'p':
855 if (change_case)
857 to_uppcase = 0;
858 to_lowcase = 1;
860 cpy (ap_len, ampm);
861 break;
863 case 'R': /* GNU extension. */
864 subfmt = "%H:%M";
865 goto subformat;
867 case 'r': /* POSIX.2 extension. */
868 #ifdef _NL_CURRENT
869 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
870 #endif
871 subfmt = "%I:%M:%S %p";
872 goto subformat;
874 case 'S':
875 if (modifier == 'E')
876 goto bad_format;
878 DO_NUMBER (2, tp->tm_sec);
880 case 's': /* GNU extension. */
882 struct tm ltm;
883 time_t t;
885 ltm = *tp;
886 t = mktime (&ltm);
888 /* Generate string value for T using time_t arithmetic;
889 this works even if sizeof (long) < sizeof (time_t). */
891 bufp = buf + sizeof (buf);
892 negative_number = t < 0;
896 int d = t % 10;
897 t /= 10;
899 if (negative_number)
901 d = -d;
903 /* Adjust if division truncates to minus infinity. */
904 if (0 < -1 % 10 && d < 0)
906 t++;
907 d += 10;
911 *--bufp = d + '0';
913 while (t != 0);
915 digits = 1;
916 goto do_number_sign_and_padding;
919 case 'X':
920 if (modifier == 'O')
921 goto bad_format;
922 #ifdef _NL_CURRENT
923 if (! (modifier == 'E'
924 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
925 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
926 goto subformat;
927 #endif
928 /* Fall through. */
929 case 'T': /* POSIX.2 extension. */
930 subfmt = "%H:%M:%S";
931 goto subformat;
933 case 't': /* POSIX.2 extension. */
934 add (1, *p = '\t');
935 break;
937 case 'u': /* POSIX.2 extension. */
938 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
940 case 'U':
941 if (modifier == 'E')
942 goto bad_format;
944 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
946 case 'V':
947 case 'g': /* GNU extension. */
948 case 'G': /* GNU extension. */
949 if (modifier == 'E')
950 goto bad_format;
952 int year = tp->tm_year + TM_YEAR_BASE;
953 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
955 if (days < 0)
957 /* This ISO week belongs to the previous year. */
958 year--;
959 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
960 tp->tm_wday);
962 else
964 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
965 tp->tm_wday);
966 if (0 <= d)
968 /* This ISO week belongs to the next year. */
969 year++;
970 days = d;
974 switch (*f)
976 case 'g':
977 DO_NUMBER (2, (year % 100 + 100) % 100);
979 case 'G':
980 DO_NUMBER (1, year);
982 default:
983 DO_NUMBER (2, days / 7 + 1);
987 case 'W':
988 if (modifier == 'E')
989 goto bad_format;
991 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
993 case 'w':
994 if (modifier == 'E')
995 goto bad_format;
997 DO_NUMBER (1, tp->tm_wday);
999 case 'Y':
1000 #if HAVE_STRUCT_ERA_ENTRY
1001 if (modifier == 'E')
1003 struct era_entry *era = _nl_get_era_entry (tp);
1004 if (era)
1006 subfmt = strchr (era->name_fmt, '\0') + 1;
1007 goto subformat;
1010 #endif
1011 if (modifier == 'O')
1012 goto bad_format;
1013 else
1014 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1016 case 'y':
1017 #if HAVE_STRUCT_ERA_ENTRY
1018 if (modifier == 'E')
1020 struct era_entry *era = _nl_get_era_entry (tp);
1021 if (era)
1023 int delta = tp->tm_year - era->start_date[0];
1024 DO_NUMBER (1, (era->offset
1025 + (era->direction == '-' ? -delta : delta)));
1028 #endif
1029 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1031 case 'Z':
1032 if (change_case)
1034 to_uppcase = 0;
1035 to_lowcase = 1;
1037 cpy (zonelen, zone);
1038 break;
1040 case 'z': /* GNU extension. */
1041 if (tp->tm_isdst < 0)
1042 break;
1045 int diff;
1046 #if HAVE_TM_GMTOFF
1047 diff = tp->tm_gmtoff;
1048 #else
1049 struct tm gtm;
1050 struct tm ltm;
1051 time_t lt;
1053 ltm = *tp;
1054 lt = mktime (&ltm);
1056 if (lt == (time_t) -1)
1058 /* mktime returns -1 for errors, but -1 is also a
1059 valid time_t value. Check whether an error really
1060 occurred. */
1061 struct tm tm;
1062 localtime_r (&lt, &tm);
1064 if ((ltm.tm_sec ^ tm.tm_sec)
1065 | (ltm.tm_min ^ tm.tm_min)
1066 | (ltm.tm_hour ^ tm.tm_hour)
1067 | (ltm.tm_mday ^ tm.tm_mday)
1068 | (ltm.tm_mon ^ tm.tm_mon)
1069 | (ltm.tm_year ^ tm.tm_year))
1070 break;
1073 if (! gmtime_r (&lt, &gtm))
1074 break;
1076 diff = tm_diff (&ltm, &gtm);
1077 #endif
1079 if (diff < 0)
1081 add (1, *p = '-');
1082 diff = -diff;
1084 else
1085 add (1, *p = '+');
1087 diff /= 60;
1088 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1091 case '\0': /* GNU extension: % at end of format. */
1092 --f;
1093 /* Fall through. */
1094 default:
1095 /* Unknown format; output the format, including the '%',
1096 since this is most likely the right thing to do if a
1097 multibyte string has been misparsed. */
1098 bad_format:
1100 int flen;
1101 for (flen = 1; f[1 - flen] != '%'; flen++)
1102 continue;
1103 cpy (flen, &f[1 - flen]);
1105 break;
1109 if (p)
1110 *p = '\0';
1111 return i;