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>
50 /* Do multibyte processing if multibytes are supported, unless
51 multibyte sequences are safe in formats. Multibyte sequences are
52 safe if they cannot contain byte sequences that look like format
53 conversion specifications. The GNU C Library uses UTF8 multibyte
54 encoding, which is safe for formats, but strftime.c can be used
55 with other C libraries that use unsafe encodings. */
56 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
62 /* Simulate mbrlen with mblen as best we can. */
63 # define mbstate_t int
64 # define mbrlen(s, n, ps) mblen (s, n)
65 # define mbsinit(ps) (*(ps) == 0)
67 static const mbstate_t mbstate_zero;
79 # define memcpy(d, s, n) bcopy (s, d, n)
83 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
84 #define __P(args) args
102 #define TYPE_SIGNED(t) ((t) -1 < 0)
104 /* Bound on length of the string representing an integer value of type t.
105 Subtract one for the sign bit if t is signed;
106 302 / 1000 is log10 (2) rounded up;
107 add one for integer division truncation;
108 add one more for a minus sign if t is signed. */
109 #define INT_STRLEN_BOUND(t) \
110 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
112 #define TM_YEAR_BASE 1900
115 /* Nonzero if YEAR is a leap year (every 4 years,
116 except every 100th isn't, and every 400th is). */
117 #define __isleap(year) \
118 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
123 # define gmtime_r __gmtime_r
124 # define localtime_r __localtime_r
126 # if ! HAVE_LOCALTIME_R
127 # if ! HAVE_TM_GMTOFF
128 /* Approximate gmtime_r as best we can in its absence. */
129 #define gmtime_r my_gmtime_r
130 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
136 struct tm *l = gmtime (t);
142 # endif /* ! HAVE_TM_GMTOFF */
144 /* Approximate localtime_r as best we can in its absence. */
145 #define localtime_r my_localtime_r
146 static struct tm *localtime_r __P ((const time_t *, struct tm *));
152 struct tm *l = localtime (t);
158 # endif /* ! HAVE_LOCALTIME_R */
159 #endif /* ! defined (_LIBC) */
175 #define cpy(n, s) add ((n), memcpy((PTR) p, (PTR) (s), (n)))
178 /* Yield the difference between *A and *B,
179 measured in seconds, ignoring leap seconds. */
180 static int tm_diff __P ((const struct tm *, const struct tm *));
186 /* Compute intervening leap days correctly even if year is negative.
187 Take care to avoid int overflow in leap day calculations,
188 but it's OK to assume that A and B are close to each other. */
189 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
190 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
191 int a100 = a4 / 25 - (a4 % 25 < 0);
192 int b100 = b4 / 25 - (b4 % 25 < 0);
193 int a400 = a100 >> 2;
194 int b400 = b100 >> 2;
195 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
196 int years = a->tm_year - b->tm_year;
197 int days = (365 * years + intervening_leap_days
198 + (a->tm_yday - b->tm_yday));
199 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
200 + (a->tm_min - b->tm_min))
201 + (a->tm_sec - b->tm_sec));
203 #endif /* ! HAVE_TM_GMTOFF */
207 /* The number of days from the first day of the first ISO week of this
208 year to the year day YDAY with week day WDAY. ISO weeks start on
209 Monday; the first ISO week has the year's first Thursday. YDAY may
210 be as small as YDAY_MINIMUM. */
211 #define ISO_WEEK_START_WDAY 1 /* Monday */
212 #define ISO_WEEK1_WDAY 4 /* Thursday */
213 #define YDAY_MINIMUM (-366)
214 static int iso_week_days __P ((int, int));
219 iso_week_days (yday, wday)
223 /* Add enough to the first operand of % to make it nonnegative. */
224 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
226 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
227 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
232 static char const weekday_name[][10] =
234 "Sunday", "Monday", "Tuesday", "Wednesday",
235 "Thursday", "Friday", "Saturday"
237 static char const month_name[][10] =
239 "January", "February", "March", "April", "May", "June",
240 "July", "August", "September", "October", "November", "December"
244 /* Write information from TP into S according to the format
245 string FORMAT, writing no more that MAXSIZE characters
246 (including the terminating '\0') and returning number of
247 characters written. If S is NULL, nothing will be written
248 anywhere, so to determine how many characters would be
249 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
251 strftime (s, maxsize, format, tp)
255 register const struct tm *tp;
257 int hour12 = tp->tm_hour;
259 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
260 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
261 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
262 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
263 const char *const ampm = _NL_CURRENT (LC_TIME,
264 hour12 > 11 ? PM_STR : AM_STR);
265 size_t aw_len = strlen (a_wkday);
266 size_t am_len = strlen (a_month);
267 size_t ap_len = strlen (ampm);
269 const char *const f_wkday = weekday_name[tp->tm_wday];
270 const char *const f_month = month_name[tp->tm_mon];
271 const char *const a_wkday = f_wkday;
272 const char *const a_month = f_month;
273 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
278 size_t wkday_len = strlen (f_wkday);
279 size_t month_len = strlen (f_month);
282 register size_t i = 0;
283 register char *p = s;
284 register const char *f;
288 zone = (const char *) tp->tm_zone;
291 if (!(zone && *zone) && tp->tm_isdst >= 0)
292 zone = tzname[tp->tm_isdst];
295 zone = ""; /* POSIX.2 requires the empty string here. */
297 zonelen = strlen (zone);
302 if (hour12 == 0) hour12 = 12;
304 for (f = format; *f != '\0'; ++f)
306 int pad; /* Padding for number ('-', '_', or 0). */
307 int modifier; /* Field modifier ('E', 'O', or 0). */
308 int digits; /* Max digits for numeric format. */
309 int number_value; /* Numeric value to be printed. */
310 int negative_number; /* 1 if the number is negative. */
313 char buf[1 + (sizeof (int) < sizeof (time_t)
314 ? INT_STRLEN_BOUND (time_t)
315 : INT_STRLEN_BOUND (int))];
324 case '\a': case '\b': case '\t': case '\n':
325 case '\v': case '\f': case '\r':
326 case ' ': case '!': case '"': case '#': case '&': case'\'':
327 case '(': case ')': case '*': case '+': case ',': case '-':
328 case '.': case '/': case '0': case '1': case '2': case '3':
329 case '4': case '5': case '6': case '7': case '8': case '9':
330 case ':': case ';': case '<': case '=': case '>': case '?':
331 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
332 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
333 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
334 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
335 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
336 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
337 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
338 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
339 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
340 case 'x': case 'y': case 'z': case '{': case '|': case '}':
342 /* The C Standard requires these 98 characters (plus '%') to
343 be in the basic execution character set. None of these
344 characters can start a multibyte sequence, so they need
345 not be analyzed further. */
350 /* Copy this multibyte sequence until we reach its end, find
351 an error, or come back to the initial shift state. */
353 mbstate_t mbstate = mbstate_zero;
358 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
363 if (bytes == (size_t) -2 || bytes == (size_t) -1)
371 while (! mbsinit (&mbstate));
378 #else /* ! DO_MULTIBYTE */
380 /* Either multibyte encodings are not supported, or they are
381 safe for formats, so any non-'%' byte can be copied through. */
388 #endif /* ! DO_MULTIBYTE */
390 /* Check for flags that can modify a number format. */
404 /* Check for modifiers. */
417 /* Now do the specified format. */
420 #define DO_NUMBER(d, v) \
421 digits = d; number_value = v; goto do_number
422 #define DO_NUMBER_SPACEPAD(d, v) \
423 digits = d; number_value = v; goto do_number_spacepad
434 cpy (aw_len, a_wkday);
440 cpy (wkday_len, f_wkday);
444 case 'h': /* POSIX.2 extension. */
447 cpy (am_len, a_month);
453 cpy (month_len, f_month);
460 if (! (modifier == 'E'
461 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
462 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
464 subfmt = "%a %b %e %H:%M:%S %Y";
469 size_t len = strftime (p, maxsize - i, subfmt, tp);
470 if (len == 0 && *subfmt)
476 case 'C': /* POSIX.2 extension. */
479 #if HAVE_STRUCT_ERA_ENTRY
482 struct era_entry *era = _nl_get_era_entry (tp);
485 size_t len = strlen (era->name_fmt);
486 cpy (len, era->name_fmt);
492 int year = tp->tm_year + TM_YEAR_BASE;
493 DO_NUMBER (1, year / 100 - (year % 100 < 0));
500 if (! (modifier == 'E'
501 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
502 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
506 case 'D': /* POSIX.2 extension. */
516 DO_NUMBER (2, tp->tm_mday);
518 case 'e': /* POSIX.2 extension. */
522 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
524 /* All numeric formats set DIGITS and NUMBER_VALUE and then
525 jump to one of these two labels. */
528 /* Force `_' flag. */
532 /* Format the number according to the MODIFIER flag. */
535 if (modifier == 'O' && 0 <= number_value)
537 /* Get the locale specific alternate representation of
538 the number NUMBER_VALUE. If none exist NULL is returned. */
539 const char *cp = _nl_get_alt_digit (number_value);
543 size_t digitlen = strlen (cp);
553 unsigned int u = number_value;
555 bufp = buf + sizeof (buf);
556 negative_number = number_value < 0;
562 *--bufp = u % 10 + '0';
563 while ((u /= 10) != 0);
566 do_number_sign_and_padding:
572 int padding = digits - (buf + sizeof (buf) - bufp);
576 while (0 < padding--)
581 bufp += negative_number;
582 while (0 < padding--)
589 cpy (buf + sizeof (buf) - bufp, bufp);
597 DO_NUMBER (2, tp->tm_hour);
603 DO_NUMBER (2, hour12);
605 case 'k': /* GNU extension. */
609 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
611 case 'l': /* GNU extension. */
615 DO_NUMBER_SPACEPAD (2, hour12);
621 DO_NUMBER (3, 1 + tp->tm_yday);
627 DO_NUMBER (2, tp->tm_min);
633 DO_NUMBER (2, tp->tm_mon + 1);
635 case 'n': /* POSIX.2 extension. */
643 case 'R': /* GNU extension. */
647 case 'r': /* POSIX.2 extension. */
649 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
651 subfmt = "%I:%M:%S %p";
658 DO_NUMBER (2, tp->tm_sec);
660 case 's': /* GNU extension. */
668 /* Generate string value for T using time_t arithmetic;
669 this works even if sizeof (long) < sizeof (time_t). */
671 bufp = buf + sizeof (buf);
672 negative_number = t < 0;
683 /* Adjust if division truncates to minus infinity. */
684 if (0 < -1 % 10 && d < 0)
696 goto do_number_sign_and_padding;
703 if (! (modifier == 'E'
704 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
705 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
709 case 'T': /* POSIX.2 extension. */
713 case 't': /* POSIX.2 extension. */
717 case 'u': /* POSIX.2 extension. */
718 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
724 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
727 case 'g': /* GNU extension. */
728 case 'G': /* GNU extension. */
732 int year = tp->tm_year + TM_YEAR_BASE;
733 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
737 /* This ISO week belongs to the previous year. */
739 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
744 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
748 /* This ISO week belongs to the next year. */
757 DO_NUMBER (2, (year % 100 + 100) % 100);
763 DO_NUMBER (2, days / 7 + 1);
771 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
777 DO_NUMBER (1, tp->tm_wday);
780 #if HAVE_STRUCT_ERA_ENTRY
783 struct era_entry *era = _nl_get_era_entry (tp);
786 subfmt = strchr (era->name_fmt, '\0') + 1;
794 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
797 #if HAVE_STRUCT_ERA_ENTRY
800 struct era_entry *era = _nl_get_era_entry (tp);
803 int delta = tp->tm_year - era->start_date[0];
804 DO_NUMBER (1, (era->offset
805 + (era->direction == '-' ? -delta : delta)));
809 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
815 case 'z': /* GNU extension. */
816 if (tp->tm_isdst < 0)
822 diff = tp->tm_gmtoff;
831 if (lt == (time_t) -1)
833 /* mktime returns -1 for errors, but -1 is also a
834 valid time_t value. Check whether an error really
837 localtime_r (<, &tm);
839 if ((ltm.tm_sec ^ tm.tm_sec)
840 | (ltm.tm_min ^ tm.tm_min)
841 | (ltm.tm_hour ^ tm.tm_hour)
842 | (ltm.tm_mday ^ tm.tm_mday)
843 | (ltm.tm_mon ^ tm.tm_mon)
844 | (ltm.tm_year ^ tm.tm_year))
848 if (! gmtime_r (<, >m))
851 diff = tm_diff (<m, >m);
863 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
866 case '\0': /* GNU extension: % at end of format. */
870 /* Unknown format; output the format, including the '%',
871 since this is most likely the right thing to do if a
872 multibyte string has been misparsed. */
876 for (flen = 1; f[1 - flen] != '%'; flen++)
878 cpy (flen, &f[1 - flen]);