automatically generated from GPLed version
[emacs.git] / src / strftime.c
blob711529e72b3418a0a12caa23823bd83cfa733ff0
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 #if defined emacs && !defined HAVE_BCOPY
40 # define HAVE_MEMCPY 1
41 #endif
43 #include <ctype.h>
44 #include <sys/types.h> /* Some systems define `time_t' here. */
46 #ifdef TIME_WITH_SYS_TIME
47 # include <sys/time.h>
48 # include <time.h>
49 #else
50 # ifdef HAVE_SYS_TIME_H
51 # include <sys/time.h>
52 # else
53 # include <time.h>
54 # endif
55 #endif
56 #if HAVE_TZNAME
57 extern char *tzname[];
58 #endif
60 /* Do multibyte processing if multibytes are supported, unless
61 multibyte sequences are safe in formats. Multibyte sequences are
62 safe if they cannot contain byte sequences that look like format
63 conversion specifications. The GNU C Library uses UTF8 multibyte
64 encoding, which is safe for formats, but strftime.c can be used
65 with other C libraries that use unsafe encodings. */
66 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
68 #if DO_MULTIBYTE
69 # if HAVE_MBRLEN
70 # include <wchar.h>
71 # else
72 /* Simulate mbrlen with mblen as best we can. */
73 # define mbstate_t int
74 # define mbrlen(s, n, ps) mblen (s, n)
75 # define mbsinit(ps) (*(ps) == 0)
76 # endif
77 static const mbstate_t mbstate_zero;
78 #endif
80 #if HAVE_LIMITS_H
81 # include <limits.h>
82 #endif
84 #if STDC_HEADERS
85 # include <stddef.h>
86 # include <stdlib.h>
87 # include <string.h>
88 #else
89 # ifndef HAVE_MEMCPY
90 # define memcpy(d, s, n) bcopy ((s), (d), (n))
91 # endif
92 #endif
94 #ifndef __P
95 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
96 # define __P(args) args
97 # else
98 # define __P(args) ()
99 # endif /* GCC. */
100 #endif /* Not __P. */
102 #ifndef PTR
103 # ifdef __STDC__
104 # define PTR void *
105 # else
106 # define PTR char *
107 # endif
108 #endif
110 #ifndef CHAR_BIT
111 # define CHAR_BIT 8
112 #endif
114 #ifndef NULL
115 # define NULL 0
116 #endif
118 #define TYPE_SIGNED(t) ((t) -1 < 0)
120 /* Bound on length of the string representing an integer value of type t.
121 Subtract one for the sign bit if t is signed;
122 302 / 1000 is log10 (2) rounded up;
123 add one for integer division truncation;
124 add one more for a minus sign if t is signed. */
125 #define INT_STRLEN_BOUND(t) \
126 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
128 #define TM_YEAR_BASE 1900
130 #ifndef __isleap
131 /* Nonzero if YEAR is a leap year (every 4 years,
132 except every 100th isn't, and every 400th is). */
133 # define __isleap(year) \
134 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
135 #endif
138 #ifdef _LIBC
139 # define gmtime_r __gmtime_r
140 # define localtime_r __localtime_r
141 # define tzname __tzname
142 # define tzset __tzset
143 #else
144 # if ! HAVE_LOCALTIME_R
145 # if ! HAVE_TM_GMTOFF
146 /* Approximate gmtime_r as best we can in its absence. */
147 # undef gmtime_r
148 # define gmtime_r my_gmtime_r
149 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
150 static struct tm *
151 gmtime_r (t, tp)
152 const time_t *t;
153 struct tm *tp;
155 struct tm *l = gmtime (t);
156 if (! l)
157 return 0;
158 *tp = *l;
159 return tp;
161 # endif /* ! HAVE_TM_GMTOFF */
163 /* Approximate localtime_r as best we can in its absence. */
164 # undef localtime_r
165 # define localtime_r my_ftime_localtime_r
166 static struct tm *localtime_r __P ((const time_t *, struct tm *));
167 static struct tm *
168 localtime_r (t, tp)
169 const time_t *t;
170 struct tm *tp;
172 struct tm *l = localtime (t);
173 if (! l)
174 return 0;
175 *tp = *l;
176 return tp;
178 # endif /* ! HAVE_LOCALTIME_R */
179 #endif /* ! defined (_LIBC) */
182 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
183 /* Some systems lack the `memset' function and we don't want to
184 introduce additional dependencies. */
185 /* The SGI compiler reportedly barfs on the trailing null
186 if we use a string constant as the initializer. 28 June 1997, rms. */
187 static const char spaces[16] = /* " " */
188 { ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
189 static const char zeroes[16] = /* "0000000000000000" */
190 { '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' };
192 # define memset_space(P, Len) \
193 do { \
194 int _len = (Len); \
196 do \
198 int _this = _len > 16 ? 16 : _len; \
199 memcpy ((P), spaces, _this); \
200 (P) += _this; \
201 _len -= _this; \
203 while (_len > 0); \
204 } while (0)
206 # define memset_zero(P, Len) \
207 do { \
208 int _len = (Len); \
210 do \
212 int _this = _len > 16 ? 16 : _len; \
213 memcpy ((P), zeroes, _this); \
214 (P) += _this; \
215 _len -= _this; \
217 while (_len > 0); \
218 } while (0)
219 #else
220 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
221 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
222 #endif
224 #define add(n, f) \
225 do \
227 int _n = (n); \
228 int _delta = width - _n; \
229 int _incr = _n + (_delta > 0 ? _delta : 0); \
230 if (i + _incr >= maxsize) \
231 return 0; \
232 if (p) \
234 if (_delta > 0) \
236 if (pad == '0') \
237 memset_zero (p, _delta); \
238 else \
239 memset_space (p, _delta); \
241 f; \
242 p += _n; \
244 i += _incr; \
245 } while (0)
247 #define cpy(n, s) \
248 add ((n), \
249 if (to_lowcase) \
250 memcpy_lowcase (p, (s), _n); \
251 else if (to_uppcase) \
252 memcpy_uppcase (p, (s), _n); \
253 else \
254 memcpy ((PTR) p, (PTR) (s), _n))
258 #ifdef _LIBC
259 # define TOUPPER(Ch) toupper (Ch)
260 # define TOLOWER(Ch) tolower (Ch)
261 #else
262 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
263 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
264 #endif
265 /* We don't use `isdigit' here since the locale dependent
266 interpretation is not what we want here. We only need to accept
267 the arabic digits in the ASCII range. One day there is perhaps a
268 more reliable way to accept other sets of digits. */
269 #define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
271 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
273 static char *
274 memcpy_lowcase (dest, src, len)
275 char *dest;
276 const char *src;
277 size_t len;
279 while (len-- > 0)
280 dest[len] = TOLOWER (src[len]);
281 return dest;
284 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
286 static char *
287 memcpy_uppcase (dest, src, len)
288 char *dest;
289 const char *src;
290 size_t len;
292 while (len-- > 0)
293 dest[len] = TOUPPER (src[len]);
294 return dest;
298 #if ! HAVE_TM_GMTOFF
299 /* Yield the difference between *A and *B,
300 measured in seconds, ignoring leap seconds. */
301 # define tm_diff ftime_tm_diff
302 static int tm_diff __P ((const struct tm *, const struct tm *));
303 static int
304 tm_diff (a, b)
305 const struct tm *a;
306 const struct tm *b;
308 /* Compute intervening leap days correctly even if year is negative.
309 Take care to avoid int overflow in leap day calculations,
310 but it's OK to assume that A and B are close to each other. */
311 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
312 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
313 int a100 = a4 / 25 - (a4 % 25 < 0);
314 int b100 = b4 / 25 - (b4 % 25 < 0);
315 int a400 = a100 >> 2;
316 int b400 = b100 >> 2;
317 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
318 int years = a->tm_year - b->tm_year;
319 int days = (365 * years + intervening_leap_days
320 + (a->tm_yday - b->tm_yday));
321 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
322 + (a->tm_min - b->tm_min))
323 + (a->tm_sec - b->tm_sec));
325 #endif /* ! HAVE_TM_GMTOFF */
329 /* The number of days from the first day of the first ISO week of this
330 year to the year day YDAY with week day WDAY. ISO weeks start on
331 Monday; the first ISO week has the year's first Thursday. YDAY may
332 be as small as YDAY_MINIMUM. */
333 #define ISO_WEEK_START_WDAY 1 /* Monday */
334 #define ISO_WEEK1_WDAY 4 /* Thursday */
335 #define YDAY_MINIMUM (-366)
336 static int iso_week_days __P ((int, int));
337 #ifdef __GNUC__
338 __inline__
339 #endif
340 static int
341 iso_week_days (yday, wday)
342 int yday;
343 int wday;
345 /* Add enough to the first operand of % to make it nonnegative. */
346 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
347 return (yday
348 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
349 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
353 #ifndef _NL_CURRENT
354 static char const weekday_name[][10] =
356 "Sunday", "Monday", "Tuesday", "Wednesday",
357 "Thursday", "Friday", "Saturday"
359 static char const month_name[][10] =
361 "January", "February", "March", "April", "May", "June",
362 "July", "August", "September", "October", "November", "December"
364 #endif
367 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
368 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
369 Work around this bug by copying *tp before it might be munged. */
370 size_t _strftime_copytm __P ((char *, size_t, const char *,
371 const struct tm *));
372 size_t
373 strftime (s, maxsize, format, tp)
374 char *s;
375 size_t maxsize;
376 const char *format;
377 const struct tm *tp;
379 struct tm tmcopy;
380 tmcopy = *tp;
381 return _strftime_copytm (s, maxsize, format, &tmcopy);
383 # ifdef strftime
384 # undef strftime
385 # endif
386 # define strftime(S, Maxsize, Format, Tp) \
387 _strftime_copytm (S, Maxsize, Format, Tp)
388 #endif
391 /* Write information from TP into S according to the format
392 string FORMAT, writing no more that MAXSIZE characters
393 (including the terminating '\0') and returning number of
394 characters written. If S is NULL, nothing will be written
395 anywhere, so to determine how many characters would be
396 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
397 size_t
398 strftime (s, maxsize, format, tp)
399 char *s;
400 size_t maxsize;
401 const char *format;
402 const struct tm *tp;
404 int hour12 = tp->tm_hour;
405 #ifdef _NL_CURRENT
406 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
407 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
408 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
409 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
410 const char *const ampm = _NL_CURRENT (LC_TIME,
411 hour12 > 11 ? PM_STR : AM_STR);
412 size_t aw_len = strlen (a_wkday);
413 size_t am_len = strlen (a_month);
414 size_t ap_len = strlen (ampm);
415 #else
416 const char *const f_wkday = weekday_name[tp->tm_wday];
417 const char *const f_month = month_name[tp->tm_mon];
418 const char *const a_wkday = f_wkday;
419 const char *const a_month = f_month;
420 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
421 size_t aw_len = 3;
422 size_t am_len = 3;
423 size_t ap_len = 2;
424 #endif
425 size_t wkday_len = strlen (f_wkday);
426 size_t month_len = strlen (f_month);
427 const char *zone;
428 size_t zonelen;
429 size_t i = 0;
430 char *p = s;
431 const char *f;
433 zone = NULL;
434 #if HAVE_TM_ZONE
435 /* The POSIX test suite assumes that setting
436 the environment variable TZ to a new value before calling strftime()
437 will influence the result (the %Z format) even if the information in
438 TP is computed with a totally different time zone.
439 This is bogus: though POSIX allows bad behavior like this,
440 POSIX does not require it. Do the right thing instead. */
441 zone = (const char *) tp->tm_zone;
442 #endif
443 #if HAVE_TZNAME
444 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
445 time zone names contained in the external variable `tzname' shall
446 be set as if the tzset() function had been called. */
447 # if HAVE_TZSET
448 tzset ();
449 # endif
451 if (!(zone && *zone) && tp->tm_isdst >= 0)
452 zone = tzname[tp->tm_isdst];
453 #endif
454 if (! zone)
455 zone = ""; /* POSIX.2 requires the empty string here. */
457 zonelen = strlen (zone);
459 if (hour12 > 12)
460 hour12 -= 12;
461 else
462 if (hour12 == 0) hour12 = 12;
464 for (f = format; *f != '\0'; ++f)
466 int pad; /* Padding for number ('-', '_', or 0). */
467 int modifier; /* Field modifier ('E', 'O', or 0). */
468 int digits; /* Max digits for numeric format. */
469 int number_value; /* Numeric value to be printed. */
470 int negative_number; /* 1 if the number is negative. */
471 const char *subfmt;
472 char *bufp;
473 char buf[1 + (sizeof (int) < sizeof (time_t)
474 ? INT_STRLEN_BOUND (time_t)
475 : INT_STRLEN_BOUND (int))];
476 int width = -1;
477 int to_lowcase = 0;
478 int to_uppcase = 0;
479 int change_case = 0;
481 #if DO_MULTIBYTE
483 switch (*f)
485 case '%':
486 break;
488 case '\a': case '\b': case '\t': case '\n':
489 case '\v': case '\f': case '\r':
490 case ' ': case '!': case '"': case '#': case '&': case'\'':
491 case '(': case ')': case '*': case '+': case ',': case '-':
492 case '.': case '/': case '0': case '1': case '2': case '3':
493 case '4': case '5': case '6': case '7': case '8': case '9':
494 case ':': case ';': case '<': case '=': case '>': case '?':
495 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
496 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
497 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
498 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
499 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
500 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
501 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
502 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
503 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
504 case 'x': case 'y': case 'z': case '{': case '|': case '}':
505 case '~':
506 /* The C Standard requires these 98 characters (plus '%') to
507 be in the basic execution character set. None of these
508 characters can start a multibyte sequence, so they need
509 not be analyzed further. */
510 add (1, *p = *f);
511 continue;
513 default:
514 /* Copy this multibyte sequence until we reach its end, find
515 an error, or come back to the initial shift state. */
517 mbstate_t mbstate = mbstate_zero;
518 size_t len = 0;
522 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
524 if (bytes == 0)
525 break;
527 if (bytes == (size_t) -2 || bytes == (size_t) -1)
529 len++;
530 break;
533 len += bytes;
535 while (! mbsinit (&mbstate));
537 cpy (len, f);
538 continue;
542 #else /* ! DO_MULTIBYTE */
544 /* Either multibyte encodings are not supported, or they are
545 safe for formats, so any non-'%' byte can be copied through. */
546 if (*f != '%')
548 add (1, *p = *f);
549 continue;
552 #endif /* ! DO_MULTIBYTE */
554 /* Check for flags that can modify a format. */
555 pad = 0;
556 while (1)
558 switch (*++f)
560 /* This influences the number formats. */
561 case '_':
562 case '-':
563 case '0':
564 pad = *f;
565 continue;
567 /* This changes textual output. */
568 case '^':
569 to_uppcase = 1;
570 continue;
571 case '#':
572 change_case = 1;
573 continue;
575 default:
576 break;
578 break;
581 /* As a GNU extension we allow to specify the field width. */
582 if (ISDIGIT (*f))
584 width = 0;
587 width *= 10;
588 width += *f - '0';
589 ++f;
591 while (ISDIGIT (*f));
594 /* Check for modifiers. */
595 switch (*f)
597 case 'E':
598 case 'O':
599 modifier = *f++;
600 break;
602 default:
603 modifier = 0;
604 break;
607 /* Now do the specified format. */
608 switch (*f)
610 #define DO_NUMBER(d, v) \
611 digits = width == -1 ? d : width; \
612 number_value = v; goto do_number
613 #define DO_NUMBER_SPACEPAD(d, v) \
614 digits = width == -1 ? d : width; \
615 number_value = v; goto do_number_spacepad
617 case '%':
618 if (modifier != 0)
619 goto bad_format;
620 add (1, *p = *f);
621 break;
623 case 'a':
624 if (modifier != 0)
625 goto bad_format;
626 if (change_case)
628 to_uppcase = 1;
629 to_lowcase = 0;
631 cpy (aw_len, a_wkday);
632 break;
634 case 'A':
635 if (modifier != 0)
636 goto bad_format;
637 if (change_case)
639 to_uppcase = 1;
640 to_lowcase = 0;
642 cpy (wkday_len, f_wkday);
643 break;
645 case 'b':
646 case 'h': /* POSIX.2 extension. */
647 if (modifier != 0)
648 goto bad_format;
649 cpy (am_len, a_month);
650 break;
652 case 'B':
653 if (modifier != 0)
654 goto bad_format;
655 if (change_case)
657 to_uppcase = 1;
658 to_lowcase = 0;
660 cpy (month_len, f_month);
661 break;
663 case 'c':
664 if (modifier == 'O')
665 goto bad_format;
666 #ifdef _NL_CURRENT
667 if (! (modifier == 'E'
668 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
669 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
670 #else
671 subfmt = "%a %b %e %H:%M:%S %Y";
672 #endif
674 subformat:
676 char *old_start = p;
677 size_t len = strftime (NULL, maxsize - i, subfmt, tp);
678 if (len == 0 && *subfmt)
679 return 0;
680 add (len, strftime (p, maxsize - i, subfmt, tp));
682 if (to_uppcase)
683 while (old_start < p)
685 *old_start = TOUPPER (*old_start);
686 ++old_start;
689 break;
691 case 'C': /* POSIX.2 extension. */
692 if (modifier == 'O')
693 goto bad_format;
694 #if HAVE_STRUCT_ERA_ENTRY
695 if (modifier == 'E')
697 struct era_entry *era = _nl_get_era_entry (tp);
698 if (era)
700 size_t len = strlen (era->name_fmt);
701 cpy (len, era->name_fmt);
702 break;
705 #endif
707 int year = tp->tm_year + TM_YEAR_BASE;
708 DO_NUMBER (1, year / 100 - (year % 100 < 0));
711 case 'x':
712 if (modifier == 'O')
713 goto bad_format;
714 #ifdef _NL_CURRENT
715 if (! (modifier == 'E'
716 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
717 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
718 goto subformat;
719 #endif
720 /* Fall through. */
721 case 'D': /* POSIX.2 extension. */
722 if (modifier != 0)
723 goto bad_format;
724 subfmt = "%m/%d/%y";
725 goto subformat;
727 case 'd':
728 if (modifier == 'E')
729 goto bad_format;
731 DO_NUMBER (2, tp->tm_mday);
733 case 'e': /* POSIX.2 extension. */
734 if (modifier == 'E')
735 goto bad_format;
737 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
739 /* All numeric formats set DIGITS and NUMBER_VALUE and then
740 jump to one of these two labels. */
742 do_number_spacepad:
743 /* Force `_' flag unless overwritten by `0' flag. */
744 if (pad != '0')
745 pad = '_';
747 do_number:
748 /* Format the number according to the MODIFIER flag. */
750 #ifdef _NL_CURRENT
751 if (modifier == 'O' && 0 <= number_value)
753 /* Get the locale specific alternate representation of
754 the number NUMBER_VALUE. If none exist NULL is returned. */
755 const char *cp = _nl_get_alt_digit (number_value);
757 if (cp != NULL)
759 size_t digitlen = strlen (cp);
760 if (digitlen != 0)
762 cpy (digitlen, cp);
763 break;
767 #endif
769 unsigned int u = number_value;
771 bufp = buf + sizeof (buf);
772 negative_number = number_value < 0;
774 if (negative_number)
775 u = -u;
778 *--bufp = u % 10 + '0';
779 while ((u /= 10) != 0);
782 do_number_sign_and_padding:
783 if (negative_number)
784 *--bufp = '-';
786 if (pad != '-')
788 int padding = digits - (buf + sizeof (buf) - bufp);
790 if (pad == '_')
792 while (0 < padding--)
793 *--bufp = ' ';
795 else
797 bufp += negative_number;
798 while (0 < padding--)
799 *--bufp = '0';
800 if (negative_number)
801 *--bufp = '-';
805 cpy (buf + sizeof (buf) - bufp, bufp);
806 break;
809 case 'H':
810 if (modifier == 'E')
811 goto bad_format;
813 DO_NUMBER (2, tp->tm_hour);
815 case 'I':
816 if (modifier == 'E')
817 goto bad_format;
819 DO_NUMBER (2, hour12);
821 case 'k': /* GNU extension. */
822 if (modifier == 'E')
823 goto bad_format;
825 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
827 case 'l': /* GNU extension. */
828 if (modifier == 'E')
829 goto bad_format;
831 DO_NUMBER_SPACEPAD (2, hour12);
833 case 'j':
834 if (modifier == 'E')
835 goto bad_format;
837 DO_NUMBER (3, 1 + tp->tm_yday);
839 case 'M':
840 if (modifier == 'E')
841 goto bad_format;
843 DO_NUMBER (2, tp->tm_min);
845 case 'm':
846 if (modifier == 'E')
847 goto bad_format;
849 DO_NUMBER (2, tp->tm_mon + 1);
851 case 'n': /* POSIX.2 extension. */
852 add (1, *p = '\n');
853 break;
855 case 'P':
856 to_lowcase = 1;
857 /* FALLTHROUGH */
859 case 'p':
860 if (change_case)
862 to_uppcase = 0;
863 to_lowcase = 1;
865 cpy (ap_len, ampm);
866 break;
868 case 'R': /* GNU extension. */
869 subfmt = "%H:%M";
870 goto subformat;
872 case 'r': /* POSIX.2 extension. */
873 #ifdef _NL_CURRENT
874 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
875 #endif
876 subfmt = "%I:%M:%S %p";
877 goto subformat;
879 case 'S':
880 if (modifier == 'E')
881 goto bad_format;
883 DO_NUMBER (2, tp->tm_sec);
885 case 's': /* GNU extension. */
887 struct tm ltm;
888 time_t t;
890 ltm = *tp;
891 t = mktime (&ltm);
893 /* Generate string value for T using time_t arithmetic;
894 this works even if sizeof (long) < sizeof (time_t). */
896 bufp = buf + sizeof (buf);
897 negative_number = t < 0;
901 int d = t % 10;
902 t /= 10;
904 if (negative_number)
906 d = -d;
908 /* Adjust if division truncates to minus infinity. */
909 if (0 < -1 % 10 && d < 0)
911 t++;
912 d += 10;
916 *--bufp = d + '0';
918 while (t != 0);
920 digits = 1;
921 goto do_number_sign_and_padding;
924 case 'X':
925 if (modifier == 'O')
926 goto bad_format;
927 #ifdef _NL_CURRENT
928 if (! (modifier == 'E'
929 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
930 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
931 goto subformat;
932 #endif
933 /* Fall through. */
934 case 'T': /* POSIX.2 extension. */
935 subfmt = "%H:%M:%S";
936 goto subformat;
938 case 't': /* POSIX.2 extension. */
939 add (1, *p = '\t');
940 break;
942 case 'u': /* POSIX.2 extension. */
943 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
945 case 'U':
946 if (modifier == 'E')
947 goto bad_format;
949 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
951 case 'V':
952 case 'g': /* GNU extension. */
953 case 'G': /* GNU extension. */
954 if (modifier == 'E')
955 goto bad_format;
957 int year = tp->tm_year + TM_YEAR_BASE;
958 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
960 if (days < 0)
962 /* This ISO week belongs to the previous year. */
963 year--;
964 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
965 tp->tm_wday);
967 else
969 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
970 tp->tm_wday);
971 if (0 <= d)
973 /* This ISO week belongs to the next year. */
974 year++;
975 days = d;
979 switch (*f)
981 case 'g':
982 DO_NUMBER (2, (year % 100 + 100) % 100);
984 case 'G':
985 DO_NUMBER (1, year);
987 default:
988 DO_NUMBER (2, days / 7 + 1);
992 case 'W':
993 if (modifier == 'E')
994 goto bad_format;
996 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
998 case 'w':
999 if (modifier == 'E')
1000 goto bad_format;
1002 DO_NUMBER (1, tp->tm_wday);
1004 case 'Y':
1005 #if HAVE_STRUCT_ERA_ENTRY
1006 if (modifier == 'E')
1008 struct era_entry *era = _nl_get_era_entry (tp);
1009 if (era)
1011 subfmt = strchr (era->name_fmt, '\0') + 1;
1012 goto subformat;
1015 #endif
1016 if (modifier == 'O')
1017 goto bad_format;
1018 else
1019 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1021 case 'y':
1022 #if HAVE_STRUCT_ERA_ENTRY
1023 if (modifier == 'E')
1025 struct era_entry *era = _nl_get_era_entry (tp);
1026 if (era)
1028 int delta = tp->tm_year - era->start_date[0];
1029 DO_NUMBER (1, (era->offset
1030 + (era->direction == '-' ? -delta : delta)));
1033 #endif
1034 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1036 case 'Z':
1037 if (change_case)
1039 to_uppcase = 0;
1040 to_lowcase = 1;
1042 cpy (zonelen, zone);
1043 break;
1045 case 'z': /* GNU extension. */
1046 if (tp->tm_isdst < 0)
1047 break;
1050 int diff;
1051 #if HAVE_TM_GMTOFF
1052 diff = tp->tm_gmtoff;
1053 #else
1054 struct tm gtm;
1055 struct tm ltm;
1056 time_t lt;
1058 ltm = *tp;
1059 lt = mktime (&ltm);
1061 if (lt == (time_t) -1)
1063 /* mktime returns -1 for errors, but -1 is also a
1064 valid time_t value. Check whether an error really
1065 occurred. */
1066 struct tm tm;
1067 localtime_r (&lt, &tm);
1069 if ((ltm.tm_sec ^ tm.tm_sec)
1070 | (ltm.tm_min ^ tm.tm_min)
1071 | (ltm.tm_hour ^ tm.tm_hour)
1072 | (ltm.tm_mday ^ tm.tm_mday)
1073 | (ltm.tm_mon ^ tm.tm_mon)
1074 | (ltm.tm_year ^ tm.tm_year))
1075 break;
1078 if (! gmtime_r (&lt, &gtm))
1079 break;
1081 diff = tm_diff (&ltm, &gtm);
1082 #endif
1084 if (diff < 0)
1086 add (1, *p = '-');
1087 diff = -diff;
1089 else
1090 add (1, *p = '+');
1092 diff /= 60;
1093 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1096 case '\0': /* GNU extension: % at end of format. */
1097 --f;
1098 /* Fall through. */
1099 default:
1100 /* Unknown format; output the format, including the '%',
1101 since this is most likely the right thing to do if a
1102 multibyte string has been misparsed. */
1103 bad_format:
1105 int flen;
1106 for (flen = 1; f[1 - flen] != '%'; flen++)
1107 continue;
1108 cpy (flen, &f[1 - flen]);
1110 break;
1114 if (p)
1115 *p = '\0';
1116 return i;