new version
[emacs.git] / src / strftime.c
blobfc0c539c669db9064a27a723705ad4ec0faee0fd
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 # define tzname __tzname
138 # define tzset __tzset
139 #else
140 # if ! HAVE_LOCALTIME_R
141 # if ! HAVE_TM_GMTOFF
142 /* Approximate gmtime_r as best we can in its absence. */
143 # define gmtime_r my_gmtime_r
144 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
145 static struct tm *
146 gmtime_r (t, tp)
147 const time_t *t;
148 struct tm *tp;
150 struct tm *l = gmtime (t);
151 if (! l)
152 return 0;
153 *tp = *l;
154 return tp;
156 # endif /* ! HAVE_TM_GMTOFF */
158 /* Approximate localtime_r as best we can in its absence. */
159 # define localtime_r my_ftime_localtime_r
160 static struct tm *localtime_r __P ((const time_t *, struct tm *));
161 static struct tm *
162 localtime_r (t, tp)
163 const time_t *t;
164 struct tm *tp;
166 struct tm *l = localtime (t);
167 if (! l)
168 return 0;
169 *tp = *l;
170 return tp;
172 # endif /* ! HAVE_LOCALTIME_R */
173 #endif /* ! defined (_LIBC) */
176 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
177 /* Some systems lack the `memset' function and we don't want to
178 introduce additional dependencies. */
179 /* The SGI compiler reportedly barfs on the trailing null
180 if we use a string constant as the initializer. 28 June 1997, rms. */
181 static const char spaces[16] = /* " " */
182 { ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
183 static const char zeroes[16] = /* "0000000000000000" */
184 { '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' };
186 # define memset_space(P, Len) \
187 do { \
188 int _len = (Len); \
190 do \
192 int _this = _len > 16 ? 16 : _len; \
193 memcpy ((P), spaces, _this); \
194 (P) += _this; \
195 _len -= _this; \
197 while (_len > 0); \
198 } while (0)
200 # define memset_zero(P, Len) \
201 do { \
202 int _len = (Len); \
204 do \
206 int _this = _len > 16 ? 16 : _len; \
207 memcpy ((P), zeroes, _this); \
208 (P) += _this; \
209 _len -= _this; \
211 while (_len > 0); \
212 } while (0)
213 #else
214 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
215 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
216 #endif
218 #define add(n, f) \
219 do \
221 int _n = (n); \
222 int _delta = width - _n; \
223 int _incr = _n + (_delta > 0 ? _delta : 0); \
224 if (i + _incr >= maxsize) \
225 return 0; \
226 if (p) \
228 if (_delta > 0) \
230 if (pad == '0') \
231 memset_zero (p, _delta); \
232 else \
233 memset_space (p, _delta); \
235 f; \
236 p += _n; \
238 i += _incr; \
239 } while (0)
241 #define cpy(n, s) \
242 add ((n), \
243 if (to_lowcase) \
244 memcpy_lowcase (p, (s), _n); \
245 else if (to_uppcase) \
246 memcpy_uppcase (p, (s), _n); \
247 else \
248 memcpy ((PTR) p, (PTR) (s), _n))
252 #ifdef _LIBC
253 # define TOUPPER(Ch) toupper (Ch)
254 # define TOLOWER(Ch) tolower (Ch)
255 #else
256 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
257 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
258 #endif
259 /* We don't use `isdigit' here since the locale dependent
260 interpretation is not what we want here. We only need to accept
261 the arabic digits in the ASCII range. One day there is perhaps a
262 more reliable way to accept other sets of digits. */
263 #define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
265 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
267 static char *
268 memcpy_lowcase (dest, src, len)
269 char *dest;
270 const char *src;
271 size_t len;
273 while (len-- > 0)
274 dest[len] = TOLOWER (src[len]);
275 return dest;
278 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
280 static char *
281 memcpy_uppcase (dest, src, len)
282 char *dest;
283 const char *src;
284 size_t len;
286 while (len-- > 0)
287 dest[len] = TOUPPER (src[len]);
288 return dest;
292 #if ! HAVE_TM_GMTOFF
293 /* Yield the difference between *A and *B,
294 measured in seconds, ignoring leap seconds. */
295 # define tm_diff ftime_tm_diff
296 static int tm_diff __P ((const struct tm *, const struct tm *));
297 static int
298 tm_diff (a, b)
299 const struct tm *a;
300 const struct tm *b;
302 /* Compute intervening leap days correctly even if year is negative.
303 Take care to avoid int overflow in leap day calculations,
304 but it's OK to assume that A and B are close to each other. */
305 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
306 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
307 int a100 = a4 / 25 - (a4 % 25 < 0);
308 int b100 = b4 / 25 - (b4 % 25 < 0);
309 int a400 = a100 >> 2;
310 int b400 = b100 >> 2;
311 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
312 int years = a->tm_year - b->tm_year;
313 int days = (365 * years + intervening_leap_days
314 + (a->tm_yday - b->tm_yday));
315 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
316 + (a->tm_min - b->tm_min))
317 + (a->tm_sec - b->tm_sec));
319 #endif /* ! HAVE_TM_GMTOFF */
323 /* The number of days from the first day of the first ISO week of this
324 year to the year day YDAY with week day WDAY. ISO weeks start on
325 Monday; the first ISO week has the year's first Thursday. YDAY may
326 be as small as YDAY_MINIMUM. */
327 #define ISO_WEEK_START_WDAY 1 /* Monday */
328 #define ISO_WEEK1_WDAY 4 /* Thursday */
329 #define YDAY_MINIMUM (-366)
330 static int iso_week_days __P ((int, int));
331 #ifdef __GNUC__
332 inline
333 #endif
334 static int
335 iso_week_days (yday, wday)
336 int yday;
337 int wday;
339 /* Add enough to the first operand of % to make it nonnegative. */
340 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
341 return (yday
342 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
343 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
347 #ifndef _NL_CURRENT
348 static char const weekday_name[][10] =
350 "Sunday", "Monday", "Tuesday", "Wednesday",
351 "Thursday", "Friday", "Saturday"
353 static char const month_name[][10] =
355 "January", "February", "March", "April", "May", "June",
356 "July", "August", "September", "October", "November", "December"
358 #endif
361 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
362 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
363 Work around this bug by copying *tp before it might be munged. */
364 size_t _strftime_copytm __P ((char *, size_t, const char *,
365 const struct tm *));
366 size_t
367 strftime (s, maxsize, format, tp)
368 char *s;
369 size_t maxsize;
370 const char *format;
371 const struct tm *tp;
373 struct tm tmcopy;
374 tmcopy = *tp;
375 return _strftime_copytm (s, maxsize, format, &tmcopy);
377 # ifdef strftime
378 # undef strftime
379 # endif
380 # define strftime(S, Maxsize, Format, Tp) \
381 _strftime_copytm (S, Maxsize, Format, Tp)
382 #endif
385 /* Write information from TP into S according to the format
386 string FORMAT, writing no more that MAXSIZE characters
387 (including the terminating '\0') and returning number of
388 characters written. If S is NULL, nothing will be written
389 anywhere, so to determine how many characters would be
390 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
391 size_t
392 strftime (s, maxsize, format, tp)
393 char *s;
394 size_t maxsize;
395 const char *format;
396 const struct tm *tp;
398 int hour12 = tp->tm_hour;
399 #ifdef _NL_CURRENT
400 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
401 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
402 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
403 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
404 const char *const ampm = _NL_CURRENT (LC_TIME,
405 hour12 > 11 ? PM_STR : AM_STR);
406 size_t aw_len = strlen (a_wkday);
407 size_t am_len = strlen (a_month);
408 size_t ap_len = strlen (ampm);
409 #else
410 const char *const f_wkday = weekday_name[tp->tm_wday];
411 const char *const f_month = month_name[tp->tm_mon];
412 const char *const a_wkday = f_wkday;
413 const char *const a_month = f_month;
414 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
415 size_t aw_len = 3;
416 size_t am_len = 3;
417 size_t ap_len = 2;
418 #endif
419 size_t wkday_len = strlen (f_wkday);
420 size_t month_len = strlen (f_month);
421 const char *zone;
422 size_t zonelen;
423 size_t i = 0;
424 char *p = s;
425 const char *f;
427 zone = NULL;
428 #if HAVE_TM_ZONE
429 /* The POSIX test suite assumes that setting
430 the environment variable TZ to a new value before calling strftime()
431 will influence the result (the %Z format) even if the information in
432 TP is computed with a totally different time zone.
433 This is bogus: though POSIX allows bad behavior like this,
434 POSIX does not require it. Do the right thing instead. */
435 zone = (const char *) tp->tm_zone;
436 #endif
437 #if HAVE_TZNAME
438 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
439 time zone names contained in the external variable `tzname' shall
440 be set as if the tzset() function had been called. */
441 # if HAVE_TZSET
442 tzset ();
443 # endif
445 if (!(zone && *zone) && tp->tm_isdst >= 0)
446 zone = tzname[tp->tm_isdst];
447 #endif
448 if (! zone)
449 zone = ""; /* POSIX.2 requires the empty string here. */
451 zonelen = strlen (zone);
453 if (hour12 > 12)
454 hour12 -= 12;
455 else
456 if (hour12 == 0) hour12 = 12;
458 for (f = format; *f != '\0'; ++f)
460 int pad; /* Padding for number ('-', '_', or 0). */
461 int modifier; /* Field modifier ('E', 'O', or 0). */
462 int digits; /* Max digits for numeric format. */
463 int number_value; /* Numeric value to be printed. */
464 int negative_number; /* 1 if the number is negative. */
465 const char *subfmt;
466 char *bufp;
467 char buf[1 + (sizeof (int) < sizeof (time_t)
468 ? INT_STRLEN_BOUND (time_t)
469 : INT_STRLEN_BOUND (int))];
470 int width = -1;
471 int to_lowcase = 0;
472 int to_uppcase = 0;
473 int change_case = 0;
475 #if DO_MULTIBYTE
477 switch (*f)
479 case '%':
480 break;
482 case '\a': case '\b': case '\t': case '\n':
483 case '\v': case '\f': case '\r':
484 case ' ': case '!': case '"': case '#': case '&': case'\'':
485 case '(': case ')': case '*': case '+': case ',': case '-':
486 case '.': case '/': case '0': case '1': case '2': case '3':
487 case '4': case '5': case '6': case '7': case '8': case '9':
488 case ':': case ';': case '<': case '=': case '>': case '?':
489 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
490 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
491 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
492 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
493 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
494 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
495 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
496 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
497 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
498 case 'x': case 'y': case 'z': case '{': case '|': case '}':
499 case '~':
500 /* The C Standard requires these 98 characters (plus '%') to
501 be in the basic execution character set. None of these
502 characters can start a multibyte sequence, so they need
503 not be analyzed further. */
504 add (1, *p = *f);
505 continue;
507 default:
508 /* Copy this multibyte sequence until we reach its end, find
509 an error, or come back to the initial shift state. */
511 mbstate_t mbstate = mbstate_zero;
512 size_t len = 0;
516 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
518 if (bytes == 0)
519 break;
521 if (bytes == (size_t) -2 || bytes == (size_t) -1)
523 len++;
524 break;
527 len += bytes;
529 while (! mbsinit (&mbstate));
531 cpy (len, f);
532 continue;
536 #else /* ! DO_MULTIBYTE */
538 /* Either multibyte encodings are not supported, or they are
539 safe for formats, so any non-'%' byte can be copied through. */
540 if (*f != '%')
542 add (1, *p = *f);
543 continue;
546 #endif /* ! DO_MULTIBYTE */
548 /* Check for flags that can modify a format. */
549 pad = 0;
550 while (1)
552 switch (*++f)
554 /* This influences the number formats. */
555 case '_':
556 case '-':
557 case '0':
558 pad = *f;
559 continue;
561 /* This changes textual output. */
562 case '^':
563 to_uppcase = 1;
564 continue;
565 case '#':
566 change_case = 1;
567 continue;
569 default:
570 break;
572 break;
575 /* As a GNU extension we allow to specify the field width. */
576 if (ISDIGIT (*f))
578 width = 0;
581 width *= 10;
582 width += *f - '0';
583 ++f;
585 while (ISDIGIT (*f));
588 /* Check for modifiers. */
589 switch (*f)
591 case 'E':
592 case 'O':
593 modifier = *f++;
594 break;
596 default:
597 modifier = 0;
598 break;
601 /* Now do the specified format. */
602 switch (*f)
604 #define DO_NUMBER(d, v) \
605 digits = width == -1 ? d : width; \
606 number_value = v; goto do_number
607 #define DO_NUMBER_SPACEPAD(d, v) \
608 digits = width == -1 ? d : width; \
609 number_value = v; goto do_number_spacepad
611 case '%':
612 if (modifier != 0)
613 goto bad_format;
614 add (1, *p = *f);
615 break;
617 case 'a':
618 if (modifier != 0)
619 goto bad_format;
620 if (change_case)
622 to_uppcase = 1;
623 to_lowcase = 0;
625 cpy (aw_len, a_wkday);
626 break;
628 case 'A':
629 if (modifier != 0)
630 goto bad_format;
631 if (change_case)
633 to_uppcase = 1;
634 to_lowcase = 0;
636 cpy (wkday_len, f_wkday);
637 break;
639 case 'b':
640 case 'h': /* POSIX.2 extension. */
641 if (modifier != 0)
642 goto bad_format;
643 cpy (am_len, a_month);
644 break;
646 case 'B':
647 if (modifier != 0)
648 goto bad_format;
649 if (change_case)
651 to_uppcase = 1;
652 to_lowcase = 0;
654 cpy (month_len, f_month);
655 break;
657 case 'c':
658 if (modifier == 'O')
659 goto bad_format;
660 #ifdef _NL_CURRENT
661 if (! (modifier == 'E'
662 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
663 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
664 #else
665 subfmt = "%a %b %e %H:%M:%S %Y";
666 #endif
668 subformat:
670 char *old_start = p;
671 size_t len = strftime (NULL, maxsize - i, subfmt, tp);
672 if (len == 0 && *subfmt)
673 return 0;
674 add (len, strftime (p, maxsize - i, subfmt, tp));
676 if (to_uppcase)
677 while (old_start < p)
679 *old_start = TOUPPER (*old_start);
680 ++old_start;
683 break;
685 case 'C': /* POSIX.2 extension. */
686 if (modifier == 'O')
687 goto bad_format;
688 #if HAVE_STRUCT_ERA_ENTRY
689 if (modifier == 'E')
691 struct era_entry *era = _nl_get_era_entry (tp);
692 if (era)
694 size_t len = strlen (era->name_fmt);
695 cpy (len, era->name_fmt);
696 break;
699 #endif
701 int year = tp->tm_year + TM_YEAR_BASE;
702 DO_NUMBER (1, year / 100 - (year % 100 < 0));
705 case 'x':
706 if (modifier == 'O')
707 goto bad_format;
708 #ifdef _NL_CURRENT
709 if (! (modifier == 'E'
710 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
711 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
712 goto subformat;
713 #endif
714 /* Fall through. */
715 case 'D': /* POSIX.2 extension. */
716 if (modifier != 0)
717 goto bad_format;
718 subfmt = "%m/%d/%y";
719 goto subformat;
721 case 'd':
722 if (modifier == 'E')
723 goto bad_format;
725 DO_NUMBER (2, tp->tm_mday);
727 case 'e': /* POSIX.2 extension. */
728 if (modifier == 'E')
729 goto bad_format;
731 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
733 /* All numeric formats set DIGITS and NUMBER_VALUE and then
734 jump to one of these two labels. */
736 do_number_spacepad:
737 /* Force `_' flag unless overwritten by `0' flag. */
738 if (pad != '0')
739 pad = '_';
741 do_number:
742 /* Format the number according to the MODIFIER flag. */
744 #ifdef _NL_CURRENT
745 if (modifier == 'O' && 0 <= number_value)
747 /* Get the locale specific alternate representation of
748 the number NUMBER_VALUE. If none exist NULL is returned. */
749 const char *cp = _nl_get_alt_digit (number_value);
751 if (cp != NULL)
753 size_t digitlen = strlen (cp);
754 if (digitlen != 0)
756 cpy (digitlen, cp);
757 break;
761 #endif
763 unsigned int u = number_value;
765 bufp = buf + sizeof (buf);
766 negative_number = number_value < 0;
768 if (negative_number)
769 u = -u;
772 *--bufp = u % 10 + '0';
773 while ((u /= 10) != 0);
776 do_number_sign_and_padding:
777 if (negative_number)
778 *--bufp = '-';
780 if (pad != '-')
782 int padding = digits - (buf + sizeof (buf) - bufp);
784 if (pad == '_')
786 while (0 < padding--)
787 *--bufp = ' ';
789 else
791 bufp += negative_number;
792 while (0 < padding--)
793 *--bufp = '0';
794 if (negative_number)
795 *--bufp = '-';
799 cpy (buf + sizeof (buf) - bufp, bufp);
800 break;
803 case 'H':
804 if (modifier == 'E')
805 goto bad_format;
807 DO_NUMBER (2, tp->tm_hour);
809 case 'I':
810 if (modifier == 'E')
811 goto bad_format;
813 DO_NUMBER (2, hour12);
815 case 'k': /* GNU extension. */
816 if (modifier == 'E')
817 goto bad_format;
819 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
821 case 'l': /* GNU extension. */
822 if (modifier == 'E')
823 goto bad_format;
825 DO_NUMBER_SPACEPAD (2, hour12);
827 case 'j':
828 if (modifier == 'E')
829 goto bad_format;
831 DO_NUMBER (3, 1 + tp->tm_yday);
833 case 'M':
834 if (modifier == 'E')
835 goto bad_format;
837 DO_NUMBER (2, tp->tm_min);
839 case 'm':
840 if (modifier == 'E')
841 goto bad_format;
843 DO_NUMBER (2, tp->tm_mon + 1);
845 case 'n': /* POSIX.2 extension. */
846 add (1, *p = '\n');
847 break;
849 case 'P':
850 to_lowcase = 1;
851 /* FALLTHROUGH */
853 case 'p':
854 if (change_case)
856 to_uppcase = 0;
857 to_lowcase = 1;
859 cpy (ap_len, ampm);
860 break;
862 case 'R': /* GNU extension. */
863 subfmt = "%H:%M";
864 goto subformat;
866 case 'r': /* POSIX.2 extension. */
867 #ifdef _NL_CURRENT
868 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
869 #endif
870 subfmt = "%I:%M:%S %p";
871 goto subformat;
873 case 'S':
874 if (modifier == 'E')
875 goto bad_format;
877 DO_NUMBER (2, tp->tm_sec);
879 case 's': /* GNU extension. */
881 struct tm ltm;
882 time_t t;
884 ltm = *tp;
885 t = mktime (&ltm);
887 /* Generate string value for T using time_t arithmetic;
888 this works even if sizeof (long) < sizeof (time_t). */
890 bufp = buf + sizeof (buf);
891 negative_number = t < 0;
895 int d = t % 10;
896 t /= 10;
898 if (negative_number)
900 d = -d;
902 /* Adjust if division truncates to minus infinity. */
903 if (0 < -1 % 10 && d < 0)
905 t++;
906 d += 10;
910 *--bufp = d + '0';
912 while (t != 0);
914 digits = 1;
915 goto do_number_sign_and_padding;
918 case 'X':
919 if (modifier == 'O')
920 goto bad_format;
921 #ifdef _NL_CURRENT
922 if (! (modifier == 'E'
923 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
924 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
925 goto subformat;
926 #endif
927 /* Fall through. */
928 case 'T': /* POSIX.2 extension. */
929 subfmt = "%H:%M:%S";
930 goto subformat;
932 case 't': /* POSIX.2 extension. */
933 add (1, *p = '\t');
934 break;
936 case 'u': /* POSIX.2 extension. */
937 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
939 case 'U':
940 if (modifier == 'E')
941 goto bad_format;
943 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
945 case 'V':
946 case 'g': /* GNU extension. */
947 case 'G': /* GNU extension. */
948 if (modifier == 'E')
949 goto bad_format;
951 int year = tp->tm_year + TM_YEAR_BASE;
952 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
954 if (days < 0)
956 /* This ISO week belongs to the previous year. */
957 year--;
958 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
959 tp->tm_wday);
961 else
963 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
964 tp->tm_wday);
965 if (0 <= d)
967 /* This ISO week belongs to the next year. */
968 year++;
969 days = d;
973 switch (*f)
975 case 'g':
976 DO_NUMBER (2, (year % 100 + 100) % 100);
978 case 'G':
979 DO_NUMBER (1, year);
981 default:
982 DO_NUMBER (2, days / 7 + 1);
986 case 'W':
987 if (modifier == 'E')
988 goto bad_format;
990 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
992 case 'w':
993 if (modifier == 'E')
994 goto bad_format;
996 DO_NUMBER (1, tp->tm_wday);
998 case 'Y':
999 #if HAVE_STRUCT_ERA_ENTRY
1000 if (modifier == 'E')
1002 struct era_entry *era = _nl_get_era_entry (tp);
1003 if (era)
1005 subfmt = strchr (era->name_fmt, '\0') + 1;
1006 goto subformat;
1009 #endif
1010 if (modifier == 'O')
1011 goto bad_format;
1012 else
1013 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1015 case 'y':
1016 #if HAVE_STRUCT_ERA_ENTRY
1017 if (modifier == 'E')
1019 struct era_entry *era = _nl_get_era_entry (tp);
1020 if (era)
1022 int delta = tp->tm_year - era->start_date[0];
1023 DO_NUMBER (1, (era->offset
1024 + (era->direction == '-' ? -delta : delta)));
1027 #endif
1028 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1030 case 'Z':
1031 if (change_case)
1033 to_uppcase = 0;
1034 to_lowcase = 1;
1036 cpy (zonelen, zone);
1037 break;
1039 case 'z': /* GNU extension. */
1040 if (tp->tm_isdst < 0)
1041 break;
1044 int diff;
1045 #if HAVE_TM_GMTOFF
1046 diff = tp->tm_gmtoff;
1047 #else
1048 struct tm gtm;
1049 struct tm ltm;
1050 time_t lt;
1052 ltm = *tp;
1053 lt = mktime (&ltm);
1055 if (lt == (time_t) -1)
1057 /* mktime returns -1 for errors, but -1 is also a
1058 valid time_t value. Check whether an error really
1059 occurred. */
1060 struct tm tm;
1061 localtime_r (&lt, &tm);
1063 if ((ltm.tm_sec ^ tm.tm_sec)
1064 | (ltm.tm_min ^ tm.tm_min)
1065 | (ltm.tm_hour ^ tm.tm_hour)
1066 | (ltm.tm_mday ^ tm.tm_mday)
1067 | (ltm.tm_mon ^ tm.tm_mon)
1068 | (ltm.tm_year ^ tm.tm_year))
1069 break;
1072 if (! gmtime_r (&lt, &gtm))
1073 break;
1075 diff = tm_diff (&ltm, &gtm);
1076 #endif
1078 if (diff < 0)
1080 add (1, *p = '-');
1081 diff = -diff;
1083 else
1084 add (1, *p = '+');
1086 diff /= 60;
1087 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1090 case '\0': /* GNU extension: % at end of format. */
1091 --f;
1092 /* Fall through. */
1093 default:
1094 /* Unknown format; output the format, including the '%',
1095 since this is most likely the right thing to do if a
1096 multibyte string has been misparsed. */
1097 bad_format:
1099 int flen;
1100 for (flen = 1; f[1 - flen] != '%'; flen++)
1101 continue;
1102 cpy (flen, &f[1 - flen]);
1104 break;
1108 if (p)
1109 *p = '\0';
1110 return i;