1 /* Copyright (C) 1991, 92, 93, 94, 95, 96 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
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA. */
24 # define HAVE_LIMITS_H 1
26 # define HAVE_MBRLEN 1
27 # define HAVE_TM_GMTOFF 1
28 # define HAVE_TM_ZONE 1
29 # define MULTIBYTE_IS_FORMAT_SAFE 1
30 # define STDC_HEADERS 1
31 # include <ansidecl.h>
32 # include "../locale/localeinfo.h"
35 #include <sys/types.h> /* Some systems define `time_t' here. */
37 #ifdef TIME_WITH_SYS_TIME
38 # include <sys/time.h>
41 # ifdef HAVE_SYS_TIME_H
42 # include <sys/time.h>
48 /* Do multibyte processing if multibytes are supported, unless
49 multibyte sequences are safe in formats. Multibyte sequences are
50 safe if they cannot contain byte sequences that look like format
51 conversion specifications. The GNU C Library uses UTF8 multibyte
52 encoding, which is safe for formats, but strftime.c can be used
53 with other C libraries that use unsafe encodings. */
54 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
60 /* Simulate mbrlen with mblen as best we can. */
61 # define mbstate_t int
62 # define mbrlen(s, n, ps) mblen (s, n)
63 # define mbsinit(ps) (*(ps) == 0)
65 static const mbstate_t mbstate_zero;
77 # define memcpy(d, s, n) bcopy (s, d, n)
81 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
82 #define __P(args) args
100 #define TYPE_SIGNED(t) ((t) -1 < 0)
102 /* Bound on length of the string representing an integer value of type t.
103 Subtract one for the sign bit if t is signed;
104 302 / 1000 is log10 (2) rounded up;
105 add one for integer division truncation;
106 add one more for a minus sign if t is signed. */
107 #define INT_STRLEN_BOUND(t) \
108 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
110 #define TM_YEAR_BASE 1900
113 /* Nonzero if YEAR is a leap year (every 4 years,
114 except every 100th isn't, and every 400th is). */
115 #define __isleap(year) \
116 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
121 # define gmtime_r __gmtime_r
122 # define localtime_r __localtime_r
124 # if ! HAVE_LOCALTIME_R
125 # if ! HAVE_TM_GMTOFF
126 /* Approximate gmtime_r as best we can in its absence. */
127 #define gmtime_r my_gmtime_r
128 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
134 struct tm *l = gmtime (t);
140 # endif /* ! HAVE_TM_GMTOFF */
142 /* Approximate localtime_r as best we can in its absence. */
143 #define localtime_r my_localtime_r
144 static struct tm *localtime_r __P ((const time_t *, struct tm *));
150 struct tm *l = localtime (t);
156 # endif /* ! HAVE_LOCALTIME_R */
157 #endif /* ! defined (_LIBC) */
173 #define cpy(n, s) add ((n), memcpy((PTR) p, (PTR) (s), (n)))
176 /* Yield the difference between *A and *B,
177 measured in seconds, ignoring leap seconds. */
178 static int tm_diff __P ((const struct tm *, const struct tm *));
184 int ay = a->tm_year + TM_YEAR_BASE - 1;
185 int by = b->tm_year + TM_YEAR_BASE - 1;
186 /* Divide years by 100, rounding towards minus infinity. */
187 int ac = ay / 100 - (ay % 100 < 0);
188 int bc = by / 100 - (by % 100 < 0);
189 int intervening_leap_days =
190 ((ay >> 2) - (by >> 2)) - (ac - bc) + ((ac >> 2) - (bc >> 2));
192 int days = (365 * years + intervening_leap_days
193 + (a->tm_yday - b->tm_yday));
194 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
195 + (a->tm_min - b->tm_min))
196 + (a->tm_sec - b->tm_sec));
198 #endif /* ! HAVE_TM_GMTOFF */
202 /* The number of days from the first day of the first ISO week of this
203 year to the year day YDAY with week day WDAY. ISO weeks start on
204 Monday; the first ISO week has the year's first Thursday. YDAY may
205 be as small as YDAY_MINIMUM. */
206 #define ISO_WEEK_START_WDAY 1 /* Monday */
207 #define ISO_WEEK1_WDAY 4 /* Thursday */
208 #define YDAY_MINIMUM (-366)
209 static int iso_week_days __P ((int, int));
214 iso_week_days (yday, wday)
218 /* Add enough to the first operand of % to make it nonnegative. */
219 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
221 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
222 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
227 static char const weekday_name[][10] =
229 "Sunday", "Monday", "Tuesday", "Wednesday",
230 "Thursday", "Friday", "Saturday"
232 static char const month_name[][10] =
234 "January", "February", "March", "April", "May", "June",
235 "July", "August", "September", "October", "November", "December"
239 /* Write information from TP into S according to the format
240 string FORMAT, writing no more that MAXSIZE characters
241 (including the terminating '\0') and returning number of
242 characters written. If S is NULL, nothing will be written
243 anywhere, so to determine how many characters would be
244 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
246 strftime (s, maxsize, format, tp)
250 register const struct tm *tp;
252 int hour12 = tp->tm_hour;
254 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
255 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
256 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
257 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
258 const char *const ampm = _NL_CURRENT (LC_TIME,
259 hour12 > 11 ? PM_STR : AM_STR);
260 size_t aw_len = strlen(a_wkday);
261 size_t am_len = strlen(a_month);
262 size_t ap_len = strlen (ampm);
264 const char *alt_digits = _NL_CURRENT (LC_TIME, ALT_DIGITS);
265 const char *end_alt_digits = _NL_CURRENT (LC_TIME, ALT_DIGITS + 1);
267 const char *const f_wkday = weekday_name[tp->tm_wday];
268 const char *const f_month = month_name[tp->tm_mon];
269 const char *const a_wkday = f_wkday;
270 const char *const a_month = f_month;
271 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
276 size_t wkday_len = strlen (f_wkday);
277 size_t month_len = strlen (f_month);
280 register size_t i = 0;
281 register char *p = s;
282 register const char *f;
286 zone = (const char *) tp->tm_zone;
289 if (!(zone && *zone) && tp->tm_isdst >= 0)
290 zone = tzname[tp->tm_isdst];
293 zone = ""; /* POSIX.2 requires the empty string here. */
295 zonelen = strlen (zone);
300 if (hour12 == 0) hour12 = 12;
302 for (f = format; *f != '\0'; ++f)
304 int pad; /* Padding for number ('-', '_', or 0). */
305 int modifier; /* Field modifier ('E', 'O', or 0). */
306 int digits; /* Max digits for numeric format. */
307 int number_value; /* Numeric value to be printed. */
308 int negative_number; /* 1 if the number is negative. */
311 char buf[1 + (sizeof (int) < sizeof (time_t)
312 ? INT_STRLEN_BOUND (time_t)
313 : INT_STRLEN_BOUND (int))];
322 case '\a': case '\b': case '\t': case '\n':
323 case '\v': case '\f': case '\r':
324 case ' ': case '!': case '"': case '#': case '&': case'\'':
325 case '(': case ')': case '*': case '+': case ',': case '-':
326 case '.': case '/': case '0': case '1': case '2': case '3':
327 case '4': case '5': case '6': case '7': case '8': case '9':
328 case ':': case ';': case '<': case '=': case '>': case '?':
329 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
330 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
331 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
332 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
333 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
334 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
335 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
336 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
337 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
338 case 'x': case 'y': case 'z': case '{': case '|': case '}':
340 /* The C Standard requires these 98 characters (plus '%') to
341 be in the basic execution character set. None of these
342 characters can start a multibyte sequence, so they need
343 not be analyzed further. */
348 /* Copy this multibyte sequence until we reach its end, find
349 an error, or come back to the initial shift state. */
351 mbstate_t mbstate = mbstate_zero;
356 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
361 if (bytes == (size_t) -2 || bytes == (size_t) -1)
369 while (! mbsinit (&mbstate));
376 #else /* ! DO_MULTIBYTE */
378 /* Either multibyte encodings are not supported, or they are
379 safe for formats, so any non-'%' byte can be copied through. */
386 #endif /* ! DO_MULTIBYTE */
388 /* Check for flags that can modify a number format. */
402 /* Check for modifiers. */
415 /* Now do the specified format. */
418 #define DO_NUMBER(d, v) \
419 digits = d; number_value = v; goto do_number
420 #define DO_NUMBER_SPACEPAD(d, v) \
421 digits = d; number_value = v; goto do_number_spacepad
423 case '\0': /* GNU extension: % at end of format. */
435 cpy (aw_len, a_wkday);
441 cpy (wkday_len, f_wkday);
445 case 'h': /* POSIX.2 extension. */
448 cpy (am_len, a_month);
454 cpy (month_len, f_month);
461 if (! (modifier == 'E'
462 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
463 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
465 subfmt = "%a %b %e %H:%M:%S %Z %Y";
470 size_t len = strftime (p, maxsize - i, subfmt, tp);
471 if (len == 0 && *subfmt)
477 case 'C': /* POSIX.2 extension. */
481 /* XXX %EC is not implemented yet. */
484 int year = tp->tm_year + TM_YEAR_BASE;
485 DO_NUMBER (1, year / 100 - (year % 100 < 0));
492 if (! (modifier == 'E'
493 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
494 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
498 case 'D': /* POSIX.2 extension. */
508 DO_NUMBER (2, tp->tm_mday);
510 case 'e': /* POSIX.2 extension. */
514 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
516 /* All numeric formats set DIGITS and NUMBER_VALUE and then
517 jump to one of these two labels. */
520 /* Force `_' flag. */
524 /* Format the number according to the MODIFIER flag. */
529 /* ALT_DIGITS is the first entry in an array with
530 alternative digit symbols. We have to find string
531 number NUMBER_VALUE, but must not look beyond
533 int run = number_value;
534 const char *cp = alt_digits;
536 while (run > 0 && cp < end_alt_digits)
537 cp = strchr (cp, '\0') + 1;
539 if (cp < end_alt_digits)
541 size_t digitlen = strlen (cp);
551 unsigned int u = number_value;
553 bufp = buf + sizeof (buf);
554 negative_number = number_value < 0;
560 *--bufp = u % 10 + '0';
561 while ((u /= 10) != 0);
564 do_number_sign_and_padding:
570 int padding = digits - (buf + sizeof (buf) - bufp);
574 while (0 < padding--)
579 bufp += negative_number;
580 while (0 < padding--)
587 cpy (buf + sizeof (buf) - bufp, bufp);
595 DO_NUMBER (2, tp->tm_hour);
601 DO_NUMBER (2, hour12);
603 case 'k': /* GNU extension. */
607 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
609 case 'l': /* GNU extension. */
613 DO_NUMBER_SPACEPAD (2, hour12);
619 DO_NUMBER (3, 1 + tp->tm_yday);
625 DO_NUMBER (2, tp->tm_min);
631 DO_NUMBER (2, tp->tm_mon + 1);
633 case 'n': /* POSIX.2 extension. */
641 case 'R': /* GNU extension. */
645 case 'r': /* POSIX.2 extension. */
647 subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM);
649 subfmt = "%I:%M:%S %p";
657 DO_NUMBER (2, tp->tm_sec);
659 case 's': /* GNU extension. */
667 /* Generate string value for T using time_t arithmetic;
668 this works even if sizeof (long) < sizeof (time_t). */
670 bufp = buf + sizeof (buf);
671 negative_number = t < 0;
682 /* Adjust if division truncates to minus infinity. */
683 if (0 < -1 % 10 && d < 0)
695 goto do_number_sign_and_padding;
702 if (! (modifier == 'E'
703 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
704 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
708 case 'T': /* POSIX.2 extension. */
712 case 't': /* POSIX.2 extension. */
716 case 'u': /* POSIX.2 extension. */
717 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
723 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
726 case 'g': /* GNU extension. */
727 case 'G': /* GNU extension. */
731 int year = tp->tm_year + TM_YEAR_BASE;
732 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
736 /* This ISO week belongs to the previous year. */
738 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
743 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
747 /* This ISO week belongs to the next year. */
756 DO_NUMBER (2, (year % 100 + 100) % 100);
762 DO_NUMBER (2, days / 7 + 1);
770 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
776 DO_NUMBER (1, tp->tm_wday);
781 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_YEAR)) != '\0')
787 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
791 /* XXX %Ey is not implemented yet. */
793 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
799 case 'z': /* GNU extension. */
800 if (tp->tm_isdst < 0)
806 diff = tp->tm_gmtoff;
815 if (lt == (time_t) -1)
817 /* mktime returns -1 for errors, but -1 is also a
818 valid time_t value. Check whether an error really
821 localtime_r (<, &tm);
823 if ((ltm.tm_sec ^ tm.tm_sec)
824 | (ltm.tm_min ^ tm.tm_min)
825 | (ltm.tm_hour ^ tm.tm_hour)
826 | (ltm.tm_mday ^ tm.tm_mday)
827 | (ltm.tm_mon ^ tm.tm_mon)
828 | (ltm.tm_year ^ tm.tm_year))
832 if (! gmtime_r (<, >m))
835 diff = tm_diff (<m, >m);
847 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
851 /* Unknown format; output the format, including the '%',
852 since this is most likely the right thing to do if a
853 multibyte string has been misparsed. */
857 for (flen = 2; f[1 - flen] != '%'; flen++)
859 cpy (flen, &f[1 - flen]);