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 not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
24 # define HAVE_LIMITS_H 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 MULTIBYTE_IS_FORMAT_SAFE 1
31 # define STDC_HEADERS 1
32 # include <ansidecl.h>
33 # include "../locale/localeinfo.h"
36 #include <sys/types.h> /* Some systems define `time_t' here. */
38 #ifdef TIME_WITH_SYS_TIME
39 # include <sys/time.h>
42 # ifdef HAVE_SYS_TIME_H
43 # include <sys/time.h>
49 extern char *tzname[];
52 /* Do multibyte processing if multibytes are supported, unless
53 multibyte sequences are safe in formats. Multibyte sequences are
54 safe if they cannot contain byte sequences that look like format
55 conversion specifications. The GNU C Library uses UTF8 multibyte
56 encoding, which is safe for formats, but strftime.c can be used
57 with other C libraries that use unsafe encodings. */
58 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
64 /* Simulate mbrlen with mblen as best we can. */
65 # define mbstate_t int
66 # define mbrlen(s, n, ps) mblen (s, n)
67 # define mbsinit(ps) (*(ps) == 0)
69 static const mbstate_t mbstate_zero;
81 # define memcpy(d, s, n) bcopy (s, d, n)
85 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
86 #define __P(args) args
104 #define TYPE_SIGNED(t) ((t) -1 < 0)
106 /* Bound on length of the string representing an integer value of type t.
107 Subtract one for the sign bit if t is signed;
108 302 / 1000 is log10 (2) rounded up;
109 add one for integer division truncation;
110 add one more for a minus sign if t is signed. */
111 #define INT_STRLEN_BOUND(t) \
112 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
114 #define TM_YEAR_BASE 1900
117 /* Nonzero if YEAR is a leap year (every 4 years,
118 except every 100th isn't, and every 400th is). */
119 #define __isleap(year) \
120 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
125 # define gmtime_r __gmtime_r
126 # define localtime_r __localtime_r
128 # if ! HAVE_LOCALTIME_R
129 # if ! HAVE_TM_GMTOFF
130 /* Approximate gmtime_r as best we can in its absence. */
131 #define gmtime_r my_gmtime_r
132 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
138 struct tm *l = gmtime (t);
144 # endif /* ! HAVE_TM_GMTOFF */
146 /* Approximate localtime_r as best we can in its absence. */
147 #define localtime_r my_localtime_r
148 static struct tm *localtime_r __P ((const time_t *, struct tm *));
154 struct tm *l = localtime (t);
160 # endif /* ! HAVE_LOCALTIME_R */
161 #endif /* ! defined (_LIBC) */
177 #define cpy(n, s) add ((n), memcpy((PTR) p, (PTR) (s), (n)))
180 /* Yield the difference between *A and *B,
181 measured in seconds, ignoring leap seconds. */
182 static int tm_diff __P ((const struct tm *, const struct tm *));
188 /* Compute intervening leap days correctly even if year is negative.
189 Take care to avoid int overflow in leap day calculations,
190 but it's OK to assume that A and B are close to each other. */
191 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
192 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
193 int a100 = a4 / 25 - (a4 % 25 < 0);
194 int b100 = b4 / 25 - (b4 % 25 < 0);
195 int a400 = a100 >> 2;
196 int b400 = b100 >> 2;
197 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
198 int years = a->tm_year - b->tm_year;
199 int days = (365 * years + intervening_leap_days
200 + (a->tm_yday - b->tm_yday));
201 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
202 + (a->tm_min - b->tm_min))
203 + (a->tm_sec - b->tm_sec));
205 #endif /* ! HAVE_TM_GMTOFF */
209 /* The number of days from the first day of the first ISO week of this
210 year to the year day YDAY with week day WDAY. ISO weeks start on
211 Monday; the first ISO week has the year's first Thursday. YDAY may
212 be as small as YDAY_MINIMUM. */
213 #define ISO_WEEK_START_WDAY 1 /* Monday */
214 #define ISO_WEEK1_WDAY 4 /* Thursday */
215 #define YDAY_MINIMUM (-366)
216 static int iso_week_days __P ((int, int));
221 iso_week_days (yday, wday)
225 /* Add enough to the first operand of % to make it nonnegative. */
226 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
228 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
229 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
234 static char const weekday_name[][10] =
236 "Sunday", "Monday", "Tuesday", "Wednesday",
237 "Thursday", "Friday", "Saturday"
239 static char const month_name[][10] =
241 "January", "February", "March", "April", "May", "June",
242 "July", "August", "September", "October", "November", "December"
246 /* Write information from TP into S according to the format
247 string FORMAT, writing no more that MAXSIZE characters
248 (including the terminating '\0') and returning number of
249 characters written. If S is NULL, nothing will be written
250 anywhere, so to determine how many characters would be
251 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
253 strftime (s, maxsize, format, tp)
257 register const struct tm *tp;
259 int hour12 = tp->tm_hour;
261 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
262 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
263 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
264 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
265 const char *const ampm = _NL_CURRENT (LC_TIME,
266 hour12 > 11 ? PM_STR : AM_STR);
267 size_t aw_len = strlen (a_wkday);
268 size_t am_len = strlen (a_month);
269 size_t ap_len = strlen (ampm);
271 const char *const f_wkday = weekday_name[tp->tm_wday];
272 const char *const f_month = month_name[tp->tm_mon];
273 const char *const a_wkday = f_wkday;
274 const char *const a_month = f_month;
275 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
280 size_t wkday_len = strlen (f_wkday);
281 size_t month_len = strlen (f_month);
284 register size_t i = 0;
285 register char *p = s;
286 register const char *f;
290 zone = (const char *) tp->tm_zone;
293 if (!(zone && *zone) && tp->tm_isdst >= 0)
294 zone = tzname[tp->tm_isdst];
297 zone = ""; /* POSIX.2 requires the empty string here. */
299 zonelen = strlen (zone);
304 if (hour12 == 0) hour12 = 12;
306 for (f = format; *f != '\0'; ++f)
308 int pad; /* Padding for number ('-', '_', or 0). */
309 int modifier; /* Field modifier ('E', 'O', or 0). */
310 int digits; /* Max digits for numeric format. */
311 int number_value; /* Numeric value to be printed. */
312 int negative_number; /* 1 if the number is negative. */
315 char buf[1 + (sizeof (int) < sizeof (time_t)
316 ? INT_STRLEN_BOUND (time_t)
317 : INT_STRLEN_BOUND (int))];
326 case '\a': case '\b': case '\t': case '\n':
327 case '\v': case '\f': case '\r':
328 case ' ': case '!': case '"': case '#': case '&': case'\'':
329 case '(': case ')': case '*': case '+': case ',': case '-':
330 case '.': case '/': case '0': case '1': case '2': case '3':
331 case '4': case '5': case '6': case '7': case '8': case '9':
332 case ':': case ';': case '<': case '=': case '>': case '?':
333 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
334 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
335 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
336 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
337 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
338 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
339 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
340 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
341 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
342 case 'x': case 'y': case 'z': case '{': case '|': case '}':
344 /* The C Standard requires these 98 characters (plus '%') to
345 be in the basic execution character set. None of these
346 characters can start a multibyte sequence, so they need
347 not be analyzed further. */
352 /* Copy this multibyte sequence until we reach its end, find
353 an error, or come back to the initial shift state. */
355 mbstate_t mbstate = mbstate_zero;
360 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
365 if (bytes == (size_t) -2 || bytes == (size_t) -1)
373 while (! mbsinit (&mbstate));
380 #else /* ! DO_MULTIBYTE */
382 /* Either multibyte encodings are not supported, or they are
383 safe for formats, so any non-'%' byte can be copied through. */
390 #endif /* ! DO_MULTIBYTE */
392 /* Check for flags that can modify a number format. */
406 /* Check for modifiers. */
419 /* Now do the specified format. */
422 #define DO_NUMBER(d, v) \
423 digits = d; number_value = v; goto do_number
424 #define DO_NUMBER_SPACEPAD(d, v) \
425 digits = d; number_value = v; goto do_number_spacepad
436 cpy (aw_len, a_wkday);
442 cpy (wkday_len, f_wkday);
446 case 'h': /* POSIX.2 extension. */
449 cpy (am_len, a_month);
455 cpy (month_len, f_month);
462 if (! (modifier == 'E'
463 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
464 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
466 subfmt = "%a %b %e %H:%M:%S %Y";
471 size_t len = strftime (p, maxsize - i, subfmt, tp);
472 if (len == 0 && *subfmt)
478 case 'C': /* POSIX.2 extension. */
481 #if HAVE_STRUCT_ERA_ENTRY
484 struct era_entry *era = _nl_get_era_entry (tp);
487 size_t len = strlen (era->name_fmt);
488 cpy (len, era->name_fmt);
494 int year = tp->tm_year + TM_YEAR_BASE;
495 DO_NUMBER (1, year / 100 - (year % 100 < 0));
502 if (! (modifier == 'E'
503 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
504 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
508 case 'D': /* POSIX.2 extension. */
518 DO_NUMBER (2, tp->tm_mday);
520 case 'e': /* POSIX.2 extension. */
524 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
526 /* All numeric formats set DIGITS and NUMBER_VALUE and then
527 jump to one of these two labels. */
530 /* Force `_' flag. */
534 /* Format the number according to the MODIFIER flag. */
537 if (modifier == 'O' && 0 <= number_value)
539 /* Get the locale specific alternate representation of
540 the number NUMBER_VALUE. If none exist NULL is returned. */
541 const char *cp = _nl_get_alt_digit (number_value);
545 size_t digitlen = strlen (cp);
555 unsigned int u = number_value;
557 bufp = buf + sizeof (buf);
558 negative_number = number_value < 0;
564 *--bufp = u % 10 + '0';
565 while ((u /= 10) != 0);
568 do_number_sign_and_padding:
574 int padding = digits - (buf + sizeof (buf) - bufp);
578 while (0 < padding--)
583 bufp += negative_number;
584 while (0 < padding--)
591 cpy (buf + sizeof (buf) - bufp, bufp);
599 DO_NUMBER (2, tp->tm_hour);
605 DO_NUMBER (2, hour12);
607 case 'k': /* GNU extension. */
611 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
613 case 'l': /* GNU extension. */
617 DO_NUMBER_SPACEPAD (2, hour12);
623 DO_NUMBER (3, 1 + tp->tm_yday);
629 DO_NUMBER (2, tp->tm_min);
635 DO_NUMBER (2, tp->tm_mon + 1);
637 case 'n': /* POSIX.2 extension. */
645 case 'R': /* GNU extension. */
649 case 'r': /* POSIX.2 extension. */
651 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
653 subfmt = "%I:%M:%S %p";
660 DO_NUMBER (2, tp->tm_sec);
662 case 's': /* GNU extension. */
670 /* Generate string value for T using time_t arithmetic;
671 this works even if sizeof (long) < sizeof (time_t). */
673 bufp = buf + sizeof (buf);
674 negative_number = t < 0;
685 /* Adjust if division truncates to minus infinity. */
686 if (0 < -1 % 10 && d < 0)
698 goto do_number_sign_and_padding;
705 if (! (modifier == 'E'
706 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
707 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
711 case 'T': /* POSIX.2 extension. */
715 case 't': /* POSIX.2 extension. */
719 case 'u': /* POSIX.2 extension. */
720 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
726 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
729 case 'g': /* GNU extension. */
730 case 'G': /* GNU extension. */
734 int year = tp->tm_year + TM_YEAR_BASE;
735 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
739 /* This ISO week belongs to the previous year. */
741 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
746 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
750 /* This ISO week belongs to the next year. */
759 DO_NUMBER (2, (year % 100 + 100) % 100);
765 DO_NUMBER (2, days / 7 + 1);
773 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
779 DO_NUMBER (1, tp->tm_wday);
782 #if HAVE_STRUCT_ERA_ENTRY
785 struct era_entry *era = _nl_get_era_entry (tp);
788 subfmt = strchr (era->name_fmt, '\0') + 1;
796 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
799 #if HAVE_STRUCT_ERA_ENTRY
802 struct era_entry *era = _nl_get_era_entry (tp);
805 int delta = tp->tm_year - era->start_date[0];
806 DO_NUMBER (1, (era->offset
807 + (era->direction == '-' ? -delta : delta)));
811 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
817 case 'z': /* GNU extension. */
818 if (tp->tm_isdst < 0)
824 diff = tp->tm_gmtoff;
833 if (lt == (time_t) -1)
835 /* mktime returns -1 for errors, but -1 is also a
836 valid time_t value. Check whether an error really
839 localtime_r (<, &tm);
841 if ((ltm.tm_sec ^ tm.tm_sec)
842 | (ltm.tm_min ^ tm.tm_min)
843 | (ltm.tm_hour ^ tm.tm_hour)
844 | (ltm.tm_mday ^ tm.tm_mday)
845 | (ltm.tm_mon ^ tm.tm_mon)
846 | (ltm.tm_year ^ tm.tm_year))
850 if (! gmtime_r (<, >m))
853 diff = tm_diff (<m, >m);
865 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
868 case '\0': /* GNU extension: % at end of format. */
872 /* Unknown format; output the format, including the '%',
873 since this is most likely the right thing to do if a
874 multibyte string has been misparsed. */
878 for (flen = 1; f[1 - flen] != '%'; flen++)
880 cpy (flen, &f[1 - flen]);