(res_querydomain): Avoid potential buffer overrun.
[glibc.git] / time / strftime.c
blob4ecbc5a51983760f65daf99eb8a66b584624bce2
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 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 #ifdef _LIBC
24 # define HAVE_LIMITS_H 1
25 # define HAVE_MBLEN 1
26 # define HAVE_MBRLEN 1
27 # define HAVE_STRUCT_ERA_ENTRY 1
28 # define HAVE_TM_GMTOFF 1
29 # define HAVE_TM_ZONE 1
30 # define HAVE_TZNAME 1
31 # define HAVE_TZSET 1
32 # define MULTIBYTE_IS_FORMAT_SAFE 1
33 # define STDC_HEADERS 1
34 # include "../locale/localeinfo.h"
35 #endif
37 #include <ctype.h>
38 #include <sys/types.h> /* Some systems define `time_t' here. */
40 #ifdef TIME_WITH_SYS_TIME
41 # include <sys/time.h>
42 # include <time.h>
43 #else
44 # ifdef HAVE_SYS_TIME_H
45 # include <sys/time.h>
46 # else
47 # include <time.h>
48 # endif
49 #endif
50 #if HAVE_TZNAME
51 extern char *tzname[];
52 #endif
54 /* Do multibyte processing if multibytes are supported, unless
55 multibyte sequences are safe in formats. Multibyte sequences are
56 safe if they cannot contain byte sequences that look like format
57 conversion specifications. The GNU C Library uses UTF8 multibyte
58 encoding, which is safe for formats, but strftime.c can be used
59 with other C libraries that use unsafe encodings. */
60 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
62 #if DO_MULTIBYTE
63 # if HAVE_MBRLEN
64 # include <wchar.h>
65 # else
66 /* Simulate mbrlen with mblen as best we can. */
67 # define mbstate_t int
68 # define mbrlen(s, n, ps) mblen (s, n)
69 # define mbsinit(ps) (*(ps) == 0)
70 # endif
71 static const mbstate_t mbstate_zero;
72 #endif
74 #if HAVE_LIMITS_H
75 # include <limits.h>
76 #endif
78 #if STDC_HEADERS
79 # include <stddef.h>
80 # include <stdlib.h>
81 # include <string.h>
82 #else
83 # ifndef HAVE_MEMCPY
84 # define memcpy(d, s, n) bcopy ((s), (d), (n))
85 # endif
86 #endif
88 #ifndef __P
89 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
90 # define __P(args) args
91 # else
92 # define __P(args) ()
93 # endif /* GCC. */
94 #endif /* Not __P. */
96 #ifndef PTR
97 # ifdef __STDC__
98 # define PTR void *
99 # else
100 # define PTR char *
101 # endif
102 #endif
104 #ifndef CHAR_BIT
105 # define CHAR_BIT 8
106 #endif
108 #ifndef NULL
109 # define NULL 0
110 #endif
112 #define TYPE_SIGNED(t) ((t) -1 < 0)
114 /* Bound on length of the string representing an integer value of type t.
115 Subtract one for the sign bit if t is signed;
116 302 / 1000 is log10 (2) rounded up;
117 add one for integer division truncation;
118 add one more for a minus sign if t is signed. */
119 #define INT_STRLEN_BOUND(t) \
120 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
122 #define TM_YEAR_BASE 1900
124 #ifndef __isleap
125 /* Nonzero if YEAR is a leap year (every 4 years,
126 except every 100th isn't, and every 400th is). */
127 # define __isleap(year) \
128 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
129 #endif
132 #ifdef _LIBC
133 # define gmtime_r __gmtime_r
134 # define localtime_r __localtime_r
135 # define tzname __tzname
136 # define tzset __tzset
137 #else
138 # if ! HAVE_LOCALTIME_R
139 # if ! HAVE_TM_GMTOFF
140 /* Approximate gmtime_r as best we can in its absence. */
141 # define gmtime_r my_gmtime_r
142 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
143 static struct tm *
144 gmtime_r (t, tp)
145 const time_t *t;
146 struct tm *tp;
148 struct tm *l = gmtime (t);
149 if (! l)
150 return 0;
151 *tp = *l;
152 return tp;
154 # endif /* ! HAVE_TM_GMTOFF */
156 /* Approximate localtime_r as best we can in its absence. */
157 # define localtime_r my_ftime_localtime_r
158 static struct tm *localtime_r __P ((const time_t *, struct tm *));
159 static struct tm *
160 localtime_r (t, tp)
161 const time_t *t;
162 struct tm *tp;
164 struct tm *l = localtime (t);
165 if (! l)
166 return 0;
167 *tp = *l;
168 return tp;
170 # endif /* ! HAVE_LOCALTIME_R */
171 #endif /* ! defined (_LIBC) */
174 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
175 /* Some systems lack the `memset' function and we don't want to
176 introduce additional dependencies. */
177 /* The SGI compiler reportedly barfs on the trailing null
178 if we use a string constant as the initializer. 28 June 1997, rms. */
179 static const char spaces[16] = /* " " */
180 { ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
181 static const char zeroes[16] = /* "0000000000000000" */
182 { '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' };
184 # define memset_space(P, Len) \
185 do { \
186 int _len = (Len); \
188 do \
190 int _this = _len > 16 ? 16 : _len; \
191 memcpy ((P), spaces, _this); \
192 (P) += _this; \
193 _len -= _this; \
195 while (_len > 0); \
196 } while (0)
198 # define memset_zero(P, Len) \
199 do { \
200 int _len = (Len); \
202 do \
204 int _this = _len > 16 ? 16 : _len; \
205 memcpy ((P), zeroes, _this); \
206 (P) += _this; \
207 _len -= _this; \
209 while (_len > 0); \
210 } while (0)
211 #else
212 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
213 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
214 #endif
216 #define add(n, f) \
217 do \
219 int _n = (n); \
220 int _delta = width - _n; \
221 int _incr = _n + (_delta > 0 ? _delta : 0); \
222 if (i + _incr >= maxsize) \
223 return 0; \
224 if (p) \
226 if (_delta > 0) \
228 if (pad == '0') \
229 memset_zero (p, _delta); \
230 else \
231 memset_space (p, _delta); \
233 f; \
234 p += _n; \
236 i += _incr; \
237 } while (0)
239 #define cpy(n, s) \
240 add ((n), \
241 if (to_lowcase) \
242 memcpy_lowcase (p, (s), _n); \
243 else if (to_uppcase) \
244 memcpy_uppcase (p, (s), _n); \
245 else \
246 memcpy ((PTR) p, (PTR) (s), _n))
250 #ifdef _LIBC
251 # define TOUPPER(Ch) toupper (Ch)
252 # define TOLOWER(Ch) tolower (Ch)
253 #else
254 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
255 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
256 #endif
257 /* We don't use `isdigit' here since the locale dependent
258 interpretation is not what we want here. We only need to accept
259 the arabic digits in the ASCII range. One day there is perhaps a
260 more reliable way to accept other sets of digits. */
261 #define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
263 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
265 static char *
266 memcpy_lowcase (dest, src, len)
267 char *dest;
268 const char *src;
269 size_t len;
271 while (len-- > 0)
272 dest[len] = TOLOWER (src[len]);
273 return dest;
276 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
278 static char *
279 memcpy_uppcase (dest, src, len)
280 char *dest;
281 const char *src;
282 size_t len;
284 while (len-- > 0)
285 dest[len] = TOUPPER (src[len]);
286 return dest;
290 #if ! HAVE_TM_GMTOFF
291 /* Yield the difference between *A and *B,
292 measured in seconds, ignoring leap seconds. */
293 # define tm_diff ftime_tm_diff
294 static int tm_diff __P ((const struct tm *, const struct tm *));
295 static int
296 tm_diff (a, b)
297 const struct tm *a;
298 const struct tm *b;
300 /* Compute intervening leap days correctly even if year is negative.
301 Take care to avoid int overflow in leap day calculations,
302 but it's OK to assume that A and B are close to each other. */
303 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
304 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
305 int a100 = a4 / 25 - (a4 % 25 < 0);
306 int b100 = b4 / 25 - (b4 % 25 < 0);
307 int a400 = a100 >> 2;
308 int b400 = b100 >> 2;
309 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
310 int years = a->tm_year - b->tm_year;
311 int days = (365 * years + intervening_leap_days
312 + (a->tm_yday - b->tm_yday));
313 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
314 + (a->tm_min - b->tm_min))
315 + (a->tm_sec - b->tm_sec));
317 #endif /* ! HAVE_TM_GMTOFF */
321 /* The number of days from the first day of the first ISO week of this
322 year to the year day YDAY with week day WDAY. ISO weeks start on
323 Monday; the first ISO week has the year's first Thursday. YDAY may
324 be as small as YDAY_MINIMUM. */
325 #define ISO_WEEK_START_WDAY 1 /* Monday */
326 #define ISO_WEEK1_WDAY 4 /* Thursday */
327 #define YDAY_MINIMUM (-366)
328 static int iso_week_days __P ((int, int));
329 #ifdef __GNUC__
330 inline
331 #endif
332 static int
333 iso_week_days (yday, wday)
334 int yday;
335 int wday;
337 /* Add enough to the first operand of % to make it nonnegative. */
338 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
339 return (yday
340 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
341 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
345 #ifndef _NL_CURRENT
346 static char const weekday_name[][10] =
348 "Sunday", "Monday", "Tuesday", "Wednesday",
349 "Thursday", "Friday", "Saturday"
351 static char const month_name[][10] =
353 "January", "February", "March", "April", "May", "June",
354 "July", "August", "September", "October", "November", "December"
356 #endif
359 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
360 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
361 Work around this bug by copying *tp before it might be munged. */
362 size_t _strftime_copytm __P ((char *, size_t, const char *,
363 const struct tm *));
364 size_t
365 strftime (s, maxsize, format, tp)
366 char *s;
367 size_t maxsize;
368 const char *format;
369 const struct tm *tp;
371 struct tm tmcopy;
372 tmcopy = *tp;
373 return _strftime_copytm (s, maxsize, format, &tmcopy);
375 # ifdef strftime
376 # undef strftime
377 # endif
378 # define strftime(S, Maxsize, Format, Tp) \
379 _strftime_copytm (S, Maxsize, Format, Tp)
380 #endif
383 /* Write information from TP into S according to the format
384 string FORMAT, writing no more that MAXSIZE characters
385 (including the terminating '\0') and returning number of
386 characters written. If S is NULL, nothing will be written
387 anywhere, so to determine how many characters would be
388 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
389 size_t
390 strftime (s, maxsize, format, tp)
391 char *s;
392 size_t maxsize;
393 const char *format;
394 const struct tm *tp;
396 int hour12 = tp->tm_hour;
397 #ifdef _NL_CURRENT
398 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
399 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
400 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
401 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
402 const char *const ampm = _NL_CURRENT (LC_TIME,
403 hour12 > 11 ? PM_STR : AM_STR);
404 size_t aw_len = strlen (a_wkday);
405 size_t am_len = strlen (a_month);
406 size_t ap_len = strlen (ampm);
407 #else
408 const char *const f_wkday = weekday_name[tp->tm_wday];
409 const char *const f_month = month_name[tp->tm_mon];
410 const char *const a_wkday = f_wkday;
411 const char *const a_month = f_month;
412 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
413 size_t aw_len = 3;
414 size_t am_len = 3;
415 size_t ap_len = 2;
416 #endif
417 size_t wkday_len = strlen (f_wkday);
418 size_t month_len = strlen (f_month);
419 const char *zone;
420 size_t zonelen;
421 size_t i = 0;
422 char *p = s;
423 const char *f;
425 zone = NULL;
426 #if HAVE_TM_ZONE
427 /* The POSIX test suite assumes that setting
428 the environment variable TZ to a new value before calling strftime()
429 will influence the result (the %Z format) even if the information in
430 TP is computed with a totally different time zone.
431 This is bogus: though POSIX allows bad behavior like this,
432 POSIX does not require it. Do the right thing instead. */
433 zone = (const char *) tp->tm_zone;
434 #endif
435 #if HAVE_TZNAME
436 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
437 time zone names contained in the external variable `tzname' shall
438 be set as if the tzset() function had been called. */
439 # if HAVE_TZSET
440 tzset ();
441 # endif
443 if (!(zone && *zone) && tp->tm_isdst >= 0)
444 zone = tzname[tp->tm_isdst];
445 #endif
446 if (! zone)
447 zone = ""; /* POSIX.2 requires the empty string here. */
449 zonelen = strlen (zone);
451 if (hour12 > 12)
452 hour12 -= 12;
453 else
454 if (hour12 == 0) hour12 = 12;
456 for (f = format; *f != '\0'; ++f)
458 int pad; /* Padding for number ('-', '_', or 0). */
459 int modifier; /* Field modifier ('E', 'O', or 0). */
460 int digits; /* Max digits for numeric format. */
461 int number_value; /* Numeric value to be printed. */
462 int negative_number; /* 1 if the number is negative. */
463 const char *subfmt;
464 char *bufp;
465 char buf[1 + (sizeof (int) < sizeof (time_t)
466 ? INT_STRLEN_BOUND (time_t)
467 : INT_STRLEN_BOUND (int))];
468 int width = -1;
469 int to_lowcase = 0;
470 int to_uppcase = 0;
471 int change_case = 0;
473 #if DO_MULTIBYTE
475 switch (*f)
477 case '%':
478 break;
480 case '\a': case '\b': case '\t': case '\n':
481 case '\v': case '\f': case '\r':
482 case ' ': case '!': case '"': case '#': case '&': case'\'':
483 case '(': case ')': case '*': case '+': case ',': case '-':
484 case '.': case '/': case '0': case '1': case '2': case '3':
485 case '4': case '5': case '6': case '7': case '8': case '9':
486 case ':': case ';': case '<': case '=': case '>': case '?':
487 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
488 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
489 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
490 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
491 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
492 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
493 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
494 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
495 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
496 case 'x': case 'y': case 'z': case '{': case '|': case '}':
497 case '~':
498 /* The C Standard requires these 98 characters (plus '%') to
499 be in the basic execution character set. None of these
500 characters can start a multibyte sequence, so they need
501 not be analyzed further. */
502 add (1, *p = *f);
503 continue;
505 default:
506 /* Copy this multibyte sequence until we reach its end, find
507 an error, or come back to the initial shift state. */
509 mbstate_t mbstate = mbstate_zero;
510 size_t len = 0;
514 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
516 if (bytes == 0)
517 break;
519 if (bytes == (size_t) -2 || bytes == (size_t) -1)
521 len++;
522 break;
525 len += bytes;
527 while (! mbsinit (&mbstate));
529 cpy (len, f);
530 continue;
534 #else /* ! DO_MULTIBYTE */
536 /* Either multibyte encodings are not supported, or they are
537 safe for formats, so any non-'%' byte can be copied through. */
538 if (*f != '%')
540 add (1, *p = *f);
541 continue;
544 #endif /* ! DO_MULTIBYTE */
546 /* Check for flags that can modify a format. */
547 pad = 0;
548 while (1)
550 switch (*++f)
552 /* This influences the number formats. */
553 case '_':
554 case '-':
555 case '0':
556 pad = *f;
557 continue;
559 /* This changes textual output. */
560 case '^':
561 to_uppcase = 1;
562 continue;
563 case '#':
564 change_case = 1;
565 continue;
567 default:
568 break;
570 break;
573 /* As a GNU extension we allow to specify the field width. */
574 if (ISDIGIT (*f))
576 width = 0;
579 width *= 10;
580 width += *f - '0';
581 ++f;
583 while (ISDIGIT (*f));
586 /* Check for modifiers. */
587 switch (*f)
589 case 'E':
590 case 'O':
591 modifier = *f++;
592 break;
594 default:
595 modifier = 0;
596 break;
599 /* Now do the specified format. */
600 switch (*f)
602 #define DO_NUMBER(d, v) \
603 digits = width == -1 ? d : width; \
604 number_value = v; goto do_number
605 #define DO_NUMBER_SPACEPAD(d, v) \
606 digits = width == -1 ? d : width; \
607 number_value = v; goto do_number_spacepad
609 case '%':
610 if (modifier != 0)
611 goto bad_format;
612 add (1, *p = *f);
613 break;
615 case 'a':
616 if (modifier != 0)
617 goto bad_format;
618 if (change_case)
620 to_uppcase = 1;
621 to_lowcase = 0;
623 cpy (aw_len, a_wkday);
624 break;
626 case 'A':
627 if (modifier != 0)
628 goto bad_format;
629 if (change_case)
631 to_uppcase = 1;
632 to_lowcase = 0;
634 cpy (wkday_len, f_wkday);
635 break;
637 case 'b':
638 case 'h': /* POSIX.2 extension. */
639 if (modifier != 0)
640 goto bad_format;
641 cpy (am_len, a_month);
642 break;
644 case 'B':
645 if (modifier != 0)
646 goto bad_format;
647 if (change_case)
649 to_uppcase = 1;
650 to_lowcase = 0;
652 cpy (month_len, f_month);
653 break;
655 case 'c':
656 if (modifier == 'O')
657 goto bad_format;
658 #ifdef _NL_CURRENT
659 if (! (modifier == 'E'
660 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
661 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
662 #else
663 subfmt = "%a %b %e %H:%M:%S %Y";
664 #endif
666 subformat:
668 char *old_start = p;
669 size_t len = strftime (NULL, maxsize - i, subfmt, tp);
670 if (len == 0 && *subfmt)
671 return 0;
672 add (len, strftime (p, maxsize - i, subfmt, tp));
674 if (to_uppcase)
675 while (old_start < p)
677 *old_start = TOUPPER (*old_start);
678 ++old_start;
681 break;
683 case 'C': /* POSIX.2 extension. */
684 if (modifier == 'O')
685 goto bad_format;
686 #if HAVE_STRUCT_ERA_ENTRY
687 if (modifier == 'E')
689 struct era_entry *era = _nl_get_era_entry (tp);
690 if (era)
692 size_t len = strlen (era->name_fmt);
693 cpy (len, era->name_fmt);
694 break;
697 #endif
699 int year = tp->tm_year + TM_YEAR_BASE;
700 DO_NUMBER (1, year / 100 - (year % 100 < 0));
703 case 'x':
704 if (modifier == 'O')
705 goto bad_format;
706 #ifdef _NL_CURRENT
707 if (! (modifier == 'E'
708 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
709 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
710 goto subformat;
711 #endif
712 /* Fall through. */
713 case 'D': /* POSIX.2 extension. */
714 if (modifier != 0)
715 goto bad_format;
716 subfmt = "%m/%d/%y";
717 goto subformat;
719 case 'd':
720 if (modifier == 'E')
721 goto bad_format;
723 DO_NUMBER (2, tp->tm_mday);
725 case 'e': /* POSIX.2 extension. */
726 if (modifier == 'E')
727 goto bad_format;
729 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
731 /* All numeric formats set DIGITS and NUMBER_VALUE and then
732 jump to one of these two labels. */
734 do_number_spacepad:
735 /* Force `_' flag unless overwritten by `0' flag. */
736 if (pad != '0')
737 pad = '_';
739 do_number:
740 /* Format the number according to the MODIFIER flag. */
742 #ifdef _NL_CURRENT
743 if (modifier == 'O' && 0 <= number_value)
745 /* Get the locale specific alternate representation of
746 the number NUMBER_VALUE. If none exist NULL is returned. */
747 const char *cp = _nl_get_alt_digit (number_value);
749 if (cp != NULL)
751 size_t digitlen = strlen (cp);
752 if (digitlen != 0)
754 cpy (digitlen, cp);
755 break;
759 #endif
761 unsigned int u = number_value;
763 bufp = buf + sizeof (buf);
764 negative_number = number_value < 0;
766 if (negative_number)
767 u = -u;
770 *--bufp = u % 10 + '0';
771 while ((u /= 10) != 0);
774 do_number_sign_and_padding:
775 if (negative_number)
776 *--bufp = '-';
778 if (pad != '-')
780 int padding = digits - (buf + sizeof (buf) - bufp);
782 if (pad == '_')
784 while (0 < padding--)
785 *--bufp = ' ';
787 else
789 bufp += negative_number;
790 while (0 < padding--)
791 *--bufp = '0';
792 if (negative_number)
793 *--bufp = '-';
797 cpy (buf + sizeof (buf) - bufp, bufp);
798 break;
801 case 'H':
802 if (modifier == 'E')
803 goto bad_format;
805 DO_NUMBER (2, tp->tm_hour);
807 case 'I':
808 if (modifier == 'E')
809 goto bad_format;
811 DO_NUMBER (2, hour12);
813 case 'k': /* GNU extension. */
814 if (modifier == 'E')
815 goto bad_format;
817 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
819 case 'l': /* GNU extension. */
820 if (modifier == 'E')
821 goto bad_format;
823 DO_NUMBER_SPACEPAD (2, hour12);
825 case 'j':
826 if (modifier == 'E')
827 goto bad_format;
829 DO_NUMBER (3, 1 + tp->tm_yday);
831 case 'M':
832 if (modifier == 'E')
833 goto bad_format;
835 DO_NUMBER (2, tp->tm_min);
837 case 'm':
838 if (modifier == 'E')
839 goto bad_format;
841 DO_NUMBER (2, tp->tm_mon + 1);
843 case 'n': /* POSIX.2 extension. */
844 add (1, *p = '\n');
845 break;
847 case 'P':
848 to_lowcase = 1;
849 /* FALLTHROUGH */
851 case 'p':
852 if (change_case)
854 to_uppcase = 0;
855 to_lowcase = 1;
857 cpy (ap_len, ampm);
858 break;
860 case 'R': /* GNU extension. */
861 subfmt = "%H:%M";
862 goto subformat;
864 case 'r': /* POSIX.2 extension. */
865 #ifdef _NL_CURRENT
866 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
867 #endif
868 subfmt = "%I:%M:%S %p";
869 goto subformat;
871 case 'S':
872 if (modifier == 'E')
873 goto bad_format;
875 DO_NUMBER (2, tp->tm_sec);
877 case 's': /* GNU extension. */
879 struct tm ltm;
880 time_t t;
882 ltm = *tp;
883 t = mktime (&ltm);
885 /* Generate string value for T using time_t arithmetic;
886 this works even if sizeof (long) < sizeof (time_t). */
888 bufp = buf + sizeof (buf);
889 negative_number = t < 0;
893 int d = t % 10;
894 t /= 10;
896 if (negative_number)
898 d = -d;
900 /* Adjust if division truncates to minus infinity. */
901 if (0 < -1 % 10 && d < 0)
903 t++;
904 d += 10;
908 *--bufp = d + '0';
910 while (t != 0);
912 digits = 1;
913 goto do_number_sign_and_padding;
916 case 'X':
917 if (modifier == 'O')
918 goto bad_format;
919 #ifdef _NL_CURRENT
920 if (! (modifier == 'E'
921 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
922 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
923 goto subformat;
924 #endif
925 /* Fall through. */
926 case 'T': /* POSIX.2 extension. */
927 subfmt = "%H:%M:%S";
928 goto subformat;
930 case 't': /* POSIX.2 extension. */
931 add (1, *p = '\t');
932 break;
934 case 'u': /* POSIX.2 extension. */
935 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
937 case 'U':
938 if (modifier == 'E')
939 goto bad_format;
941 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
943 case 'V':
944 case 'g': /* GNU extension. */
945 case 'G': /* GNU extension. */
946 if (modifier == 'E')
947 goto bad_format;
949 int year = tp->tm_year + TM_YEAR_BASE;
950 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
952 if (days < 0)
954 /* This ISO week belongs to the previous year. */
955 year--;
956 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
957 tp->tm_wday);
959 else
961 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
962 tp->tm_wday);
963 if (0 <= d)
965 /* This ISO week belongs to the next year. */
966 year++;
967 days = d;
971 switch (*f)
973 case 'g':
974 DO_NUMBER (2, (year % 100 + 100) % 100);
976 case 'G':
977 DO_NUMBER (1, year);
979 default:
980 DO_NUMBER (2, days / 7 + 1);
984 case 'W':
985 if (modifier == 'E')
986 goto bad_format;
988 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
990 case 'w':
991 if (modifier == 'E')
992 goto bad_format;
994 DO_NUMBER (1, tp->tm_wday);
996 case 'Y':
997 #if HAVE_STRUCT_ERA_ENTRY
998 if (modifier == 'E')
1000 struct era_entry *era = _nl_get_era_entry (tp);
1001 if (era)
1003 subfmt = strchr (era->name_fmt, '\0') + 1;
1004 goto subformat;
1007 #endif
1008 if (modifier == 'O')
1009 goto bad_format;
1010 else
1011 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1013 case 'y':
1014 #if HAVE_STRUCT_ERA_ENTRY
1015 if (modifier == 'E')
1017 struct era_entry *era = _nl_get_era_entry (tp);
1018 if (era)
1020 int delta = tp->tm_year - era->start_date[0];
1021 DO_NUMBER (1, (era->offset
1022 + (era->direction == '-' ? -delta : delta)));
1025 #endif
1026 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1028 case 'Z':
1029 if (change_case)
1031 to_uppcase = 0;
1032 to_lowcase = 1;
1034 cpy (zonelen, zone);
1035 break;
1037 case 'z': /* GNU extension. */
1038 if (tp->tm_isdst < 0)
1039 break;
1042 int diff;
1043 #if HAVE_TM_GMTOFF
1044 diff = tp->tm_gmtoff;
1045 #else
1046 struct tm gtm;
1047 struct tm ltm;
1048 time_t lt;
1050 ltm = *tp;
1051 lt = mktime (&ltm);
1053 if (lt == (time_t) -1)
1055 /* mktime returns -1 for errors, but -1 is also a
1056 valid time_t value. Check whether an error really
1057 occurred. */
1058 struct tm tm;
1059 localtime_r (&lt, &tm);
1061 if ((ltm.tm_sec ^ tm.tm_sec)
1062 | (ltm.tm_min ^ tm.tm_min)
1063 | (ltm.tm_hour ^ tm.tm_hour)
1064 | (ltm.tm_mday ^ tm.tm_mday)
1065 | (ltm.tm_mon ^ tm.tm_mon)
1066 | (ltm.tm_year ^ tm.tm_year))
1067 break;
1070 if (! gmtime_r (&lt, &gtm))
1071 break;
1073 diff = tm_diff (&ltm, &gtm);
1074 #endif
1076 if (diff < 0)
1078 add (1, *p = '-');
1079 diff = -diff;
1081 else
1082 add (1, *p = '+');
1084 diff /= 60;
1085 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1088 case '\0': /* GNU extension: % at end of format. */
1089 --f;
1090 /* Fall through. */
1091 default:
1092 /* Unknown format; output the format, including the '%',
1093 since this is most likely the right thing to do if a
1094 multibyte string has been misparsed. */
1095 bad_format:
1097 int flen;
1098 for (flen = 1; f[1 - flen] != '%'; flen++)
1099 continue;
1100 cpy (flen, &f[1 - flen]);
1102 break;
1106 if (p)
1107 *p = '\0';
1108 return i;