1 /* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
3 NOTE: The canonical source of this file is maintained with the GNU C
4 Library. 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
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 Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
25 # define HAVE_LIMITS_H 1
27 # define HAVE_MBRLEN 1
28 # define HAVE_STRUCT_ERA_ENTRY 1
29 # define HAVE_TM_GMTOFF 1
30 # define HAVE_TM_ZONE 1
31 # define MULTIBYTE_IS_FORMAT_SAFE 1
32 # define STDC_HEADERS 1
33 # include <ansidecl.h>
34 # include "../locale/localeinfo.h"
37 #include <sys/types.h> /* Some systems define `time_t' here. */
39 #ifdef TIME_WITH_SYS_TIME
40 # include <sys/time.h>
43 # ifdef HAVE_SYS_TIME_H
44 # include <sys/time.h>
51 extern char *tzname[];
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)
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)
71 static const mbstate_t mbstate_zero;
83 # define memcpy(d, s, n) bcopy (s, d, n)
87 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
88 #define __P(args) args
106 #define TYPE_SIGNED(t) ((t) -1 < 0)
108 /* Bound on length of the string representing an integer value of type t.
109 Subtract one for the sign bit if t is signed;
110 302 / 1000 is log10 (2) rounded up;
111 add one for integer division truncation;
112 add one more for a minus sign if t is signed. */
113 #define INT_STRLEN_BOUND(t) \
114 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
116 #define TM_YEAR_BASE 1900
119 /* Nonzero if YEAR is a leap year (every 4 years,
120 except every 100th isn't, and every 400th is). */
121 #define __isleap(year) \
122 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
127 # define gmtime_r __gmtime_r
128 # define localtime_r __localtime_r
130 # if ! HAVE_LOCALTIME_R
131 # if ! HAVE_TM_GMTOFF
132 /* Approximate gmtime_r as best we can in its absence. */
133 #define gmtime_r my_gmtime_r
134 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
140 struct tm *l = gmtime (t);
146 # endif /* ! HAVE_TM_GMTOFF */
148 /* Approximate localtime_r as best we can in its absence. */
149 #define localtime_r my_localtime_r
150 static struct tm *localtime_r __P ((const time_t *, struct tm *));
156 struct tm *l = localtime (t);
162 # endif /* ! HAVE_LOCALTIME_R */
163 #endif /* ! defined (_LIBC) */
179 #define cpy(n, s) add ((n), memcpy((PTR) p, (PTR) (s), (n)))
182 /* Yield the difference between *A and *B,
183 measured in seconds, ignoring leap seconds. */
184 static int tm_diff __P ((const struct tm *, const struct tm *));
190 /* Compute intervening leap days correctly even if year is negative.
191 Take care to avoid int overflow in leap day calculations,
192 but it's OK to assume that A and B are close to each other. */
193 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
194 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
195 int a100 = a4 / 25 - (a4 % 25 < 0);
196 int b100 = b4 / 25 - (b4 % 25 < 0);
197 int a400 = a100 >> 2;
198 int b400 = b100 >> 2;
199 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
200 int years = a->tm_year - b->tm_year;
201 int days = (365 * years + intervening_leap_days
202 + (a->tm_yday - b->tm_yday));
203 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
204 + (a->tm_min - b->tm_min))
205 + (a->tm_sec - b->tm_sec));
207 #endif /* ! HAVE_TM_GMTOFF */
211 /* The number of days from the first day of the first ISO week of this
212 year to the year day YDAY with week day WDAY. ISO weeks start on
213 Monday; the first ISO week has the year's first Thursday. YDAY may
214 be as small as YDAY_MINIMUM. */
215 #define ISO_WEEK_START_WDAY 1 /* Monday */
216 #define ISO_WEEK1_WDAY 4 /* Thursday */
217 #define YDAY_MINIMUM (-366)
218 static int iso_week_days __P ((int, int));
223 iso_week_days (yday, wday)
227 /* Add enough to the first operand of % to make it nonnegative. */
228 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
230 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
231 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
236 static char const weekday_name[][10] =
238 "Sunday", "Monday", "Tuesday", "Wednesday",
239 "Thursday", "Friday", "Saturday"
241 static char const month_name[][10] =
243 "January", "February", "March", "April", "May", "June",
244 "July", "August", "September", "October", "November", "December"
248 /* Write information from TP into S according to the format
249 string FORMAT, writing no more that MAXSIZE characters
250 (including the terminating '\0') and returning number of
251 characters written. If S is NULL, nothing will be written
252 anywhere, so to determine how many characters would be
253 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
255 strftime (s, maxsize, format, tp)
259 register const struct tm *tp;
261 int hour12 = tp->tm_hour;
263 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
264 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
265 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
266 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
267 const char *const ampm = _NL_CURRENT (LC_TIME,
268 hour12 > 11 ? PM_STR : AM_STR);
269 size_t aw_len = strlen (a_wkday);
270 size_t am_len = strlen (a_month);
271 size_t ap_len = strlen (ampm);
273 const char *const f_wkday = weekday_name[tp->tm_wday];
274 const char *const f_month = month_name[tp->tm_mon];
275 const char *const a_wkday = f_wkday;
276 const char *const a_month = f_month;
277 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
282 size_t wkday_len = strlen (f_wkday);
283 size_t month_len = strlen (f_month);
286 register size_t i = 0;
287 register char *p = s;
288 register const char *f;
292 zone = (const char *) tp->tm_zone;
295 if (!(zone && *zone) && tp->tm_isdst >= 0)
296 zone = tzname[tp->tm_isdst];
299 zone = ""; /* POSIX.2 requires the empty string here. */
301 zonelen = strlen (zone);
306 if (hour12 == 0) hour12 = 12;
308 for (f = format; *f != '\0'; ++f)
310 int pad; /* Padding for number ('-', '_', or 0). */
311 int modifier; /* Field modifier ('E', 'O', or 0). */
312 int digits; /* Max digits for numeric format. */
313 int number_value; /* Numeric value to be printed. */
314 int negative_number; /* 1 if the number is negative. */
317 char buf[1 + (sizeof (int) < sizeof (time_t)
318 ? INT_STRLEN_BOUND (time_t)
319 : INT_STRLEN_BOUND (int))];
328 case '\a': case '\b': case '\t': case '\n':
329 case '\v': case '\f': case '\r':
330 case ' ': case '!': case '"': case '#': case '&': case'\'':
331 case '(': case ')': case '*': case '+': case ',': case '-':
332 case '.': case '/': case '0': case '1': case '2': case '3':
333 case '4': case '5': case '6': case '7': case '8': case '9':
334 case ':': case ';': case '<': case '=': case '>': case '?':
335 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
336 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
337 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
338 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
339 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
340 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
341 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
342 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
343 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
344 case 'x': case 'y': case 'z': case '{': case '|': case '}':
346 /* The C Standard requires these 98 characters (plus '%') to
347 be in the basic execution character set. None of these
348 characters can start a multibyte sequence, so they need
349 not be analyzed further. */
354 /* Copy this multibyte sequence until we reach its end, find
355 an error, or come back to the initial shift state. */
357 mbstate_t mbstate = mbstate_zero;
362 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
367 if (bytes == (size_t) -2 || bytes == (size_t) -1)
375 while (! mbsinit (&mbstate));
382 #else /* ! DO_MULTIBYTE */
384 /* Either multibyte encodings are not supported, or they are
385 safe for formats, so any non-'%' byte can be copied through. */
392 #endif /* ! DO_MULTIBYTE */
394 /* Check for flags that can modify a number format. */
408 /* Check for modifiers. */
421 /* Now do the specified format. */
424 #define DO_NUMBER(d, v) \
425 digits = d; number_value = v; goto do_number
426 #define DO_NUMBER_SPACEPAD(d, v) \
427 digits = d; number_value = v; goto do_number_spacepad
438 cpy (aw_len, a_wkday);
444 cpy (wkday_len, f_wkday);
448 case 'h': /* POSIX.2 extension. */
451 cpy (am_len, a_month);
457 cpy (month_len, f_month);
464 if (! (modifier == 'E'
465 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
466 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
468 subfmt = "%a %b %e %H:%M:%S %Y";
473 size_t len = strftime (p, maxsize - i, subfmt, tp);
474 if (len == 0 && *subfmt)
480 case 'C': /* POSIX.2 extension. */
483 #if HAVE_STRUCT_ERA_ENTRY
486 struct era_entry *era = _nl_get_era_entry (tp);
489 size_t len = strlen (era->name_fmt);
490 cpy (len, era->name_fmt);
496 int year = tp->tm_year + TM_YEAR_BASE;
497 DO_NUMBER (1, year / 100 - (year % 100 < 0));
504 if (! (modifier == 'E'
505 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
506 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
510 case 'D': /* POSIX.2 extension. */
520 DO_NUMBER (2, tp->tm_mday);
522 case 'e': /* POSIX.2 extension. */
526 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
528 /* All numeric formats set DIGITS and NUMBER_VALUE and then
529 jump to one of these two labels. */
532 /* Force `_' flag. */
536 /* Format the number according to the MODIFIER flag. */
539 if (modifier == 'O' && 0 <= number_value)
541 /* Get the locale specific alternate representation of
542 the number NUMBER_VALUE. If none exist NULL is returned. */
543 const char *cp = _nl_get_alt_digit (number_value);
547 size_t digitlen = strlen (cp);
557 unsigned int u = number_value;
559 bufp = buf + sizeof (buf);
560 negative_number = number_value < 0;
566 *--bufp = u % 10 + '0';
567 while ((u /= 10) != 0);
570 do_number_sign_and_padding:
576 int padding = digits - (buf + sizeof (buf) - bufp);
580 while (0 < padding--)
585 bufp += negative_number;
586 while (0 < padding--)
593 cpy (buf + sizeof (buf) - bufp, bufp);
601 DO_NUMBER (2, tp->tm_hour);
607 DO_NUMBER (2, hour12);
609 case 'k': /* GNU extension. */
613 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
615 case 'l': /* GNU extension. */
619 DO_NUMBER_SPACEPAD (2, hour12);
625 DO_NUMBER (3, 1 + tp->tm_yday);
631 DO_NUMBER (2, tp->tm_min);
637 DO_NUMBER (2, tp->tm_mon + 1);
639 case 'n': /* POSIX.2 extension. */
647 case 'R': /* GNU extension. */
651 case 'r': /* POSIX.2 extension. */
653 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
655 subfmt = "%I:%M:%S %p";
662 DO_NUMBER (2, tp->tm_sec);
664 case 's': /* GNU extension. */
672 /* Generate string value for T using time_t arithmetic;
673 this works even if sizeof (long) < sizeof (time_t). */
675 bufp = buf + sizeof (buf);
676 negative_number = t < 0;
687 /* Adjust if division truncates to minus infinity. */
688 if (0 < -1 % 10 && d < 0)
700 goto do_number_sign_and_padding;
707 if (! (modifier == 'E'
708 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
709 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
713 case 'T': /* POSIX.2 extension. */
717 case 't': /* POSIX.2 extension. */
721 case 'u': /* POSIX.2 extension. */
722 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
728 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
731 case 'g': /* GNU extension. */
732 case 'G': /* GNU extension. */
736 int year = tp->tm_year + TM_YEAR_BASE;
737 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
741 /* This ISO week belongs to the previous year. */
743 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
748 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
752 /* This ISO week belongs to the next year. */
761 DO_NUMBER (2, (year % 100 + 100) % 100);
767 DO_NUMBER (2, days / 7 + 1);
775 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
781 DO_NUMBER (1, tp->tm_wday);
784 #if HAVE_STRUCT_ERA_ENTRY
787 struct era_entry *era = _nl_get_era_entry (tp);
790 subfmt = strchr (era->name_fmt, '\0') + 1;
798 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
801 #if HAVE_STRUCT_ERA_ENTRY
804 struct era_entry *era = _nl_get_era_entry (tp);
807 int delta = tp->tm_year - era->start_date[0];
808 DO_NUMBER (1, (era->offset
809 + (era->direction == '-' ? -delta : delta)));
813 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
819 case 'z': /* GNU extension. */
820 if (tp->tm_isdst < 0)
826 diff = tp->tm_gmtoff;
835 if (lt == (time_t) -1)
837 /* mktime returns -1 for errors, but -1 is also a
838 valid time_t value. Check whether an error really
841 localtime_r (<, &tm);
843 if ((ltm.tm_sec ^ tm.tm_sec)
844 | (ltm.tm_min ^ tm.tm_min)
845 | (ltm.tm_hour ^ tm.tm_hour)
846 | (ltm.tm_mday ^ tm.tm_mday)
847 | (ltm.tm_mon ^ tm.tm_mon)
848 | (ltm.tm_year ^ tm.tm_year))
852 if (! gmtime_r (<, >m))
855 diff = tm_diff (<m, >m);
867 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
870 case '\0': /* GNU extension: % at end of format. */
874 /* Unknown format; output the format, including the '%',
875 since this is most likely the right thing to do if a
876 multibyte string has been misparsed. */
880 for (flen = 1; f[1 - flen] != '%'; flen++)
882 cpy (flen, &f[1 - flen]);