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 HAVE_TZNAME 1
33 # define MULTIBYTE_IS_FORMAT_SAFE 1
34 # define STDC_HEADERS 1
35 # include <ansidecl.h>
36 # include "../locale/localeinfo.h"
40 #include <sys/types.h> /* Some systems define `time_t' here. */
42 #ifdef TIME_WITH_SYS_TIME
43 # include <sys/time.h>
46 # ifdef HAVE_SYS_TIME_H
47 # include <sys/time.h>
53 extern char *tzname[];
56 /* Do multibyte processing if multibytes are supported, unless
57 multibyte sequences are safe in formats. Multibyte sequences are
58 safe if they cannot contain byte sequences that look like format
59 conversion specifications. The GNU C Library uses UTF8 multibyte
60 encoding, which is safe for formats, but strftime.c can be used
61 with other C libraries that use unsafe encodings. */
62 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
68 /* Simulate mbrlen with mblen as best we can. */
69 # define mbstate_t int
70 # define mbrlen(s, n, ps) mblen (s, n)
71 # define mbsinit(ps) (*(ps) == 0)
73 static const mbstate_t mbstate_zero;
85 # define memcpy(d, s, n) bcopy ((s), (d), (n))
89 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
90 # define __P(args) args
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
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))
133 # define gmtime_r __gmtime_r
134 # define localtime_r __localtime_r
135 extern int __tz_compute __P ((time_t timer, const struct tm *tm));
136 # define tzname __tzname
137 # define tzset __tzset
139 # if ! HAVE_LOCALTIME_R
140 # if ! HAVE_TM_GMTOFF
141 /* Approximate gmtime_r as best we can in its absence. */
142 # define gmtime_r my_gmtime_r
143 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
149 struct tm *l = gmtime (t);
155 # endif /* ! HAVE_TM_GMTOFF */
157 /* Approximate localtime_r as best we can in its absence. */
158 # define localtime_r my_localtime_r
159 static struct tm *localtime_r __P ((const time_t *, struct tm *));
165 struct tm *l = localtime (t);
171 # endif /* ! HAVE_LOCALTIME_R */
172 #endif /* ! defined (_LIBC) */
175 #if !defined (memset) && !defined (HAVE_MEMSET) && !defined (_LIBC)
176 /* Some systems lack the `memset' function and we don't want to
177 introduce additional dependencies. */
178 static const char spaces[16] = " ";
180 # define memset_space(P, Len) \
186 int _this = _len > 16 ? 16 : _len; \
187 memcpy ((P), spaces, _this); \
194 # define memset_space(P, Len) memset ((P), ' ', (Len))
201 int _delta = width - _n; \
202 int _incr = _n + (_delta > 0 ? _delta : 0); \
203 if (i + _incr >= maxsize) \
208 memset_space (p, _delta); \
218 memcpy_lowcase (p, (s), _n); \
219 else if (to_uppcase) \
220 memcpy_uppcase (p, (s), _n); \
222 memcpy ((PTR) p, (PTR) (s), _n))
227 # define TOUPPER(Ch) toupper (Ch)
228 # define TOLOWER(Ch) tolower (Ch)
230 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
231 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
234 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
237 memcpy_lowcase (dest, src, len)
243 dest[len] = TOLOWER (src[len]);
247 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
250 memcpy_uppcase (dest, src, len)
256 dest[len] = TOUPPER (src[len]);
261 /* Yield the difference between *A and *B,
262 measured in seconds, ignoring leap seconds. */
263 static int tm_diff __P ((const struct tm *, const struct tm *));
269 /* Compute intervening leap days correctly even if year is negative.
270 Take care to avoid int overflow in leap day calculations,
271 but it's OK to assume that A and B are close to each other. */
272 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
273 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
274 int a100 = a4 / 25 - (a4 % 25 < 0);
275 int b100 = b4 / 25 - (b4 % 25 < 0);
276 int a400 = a100 >> 2;
277 int b400 = b100 >> 2;
278 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
279 int years = a->tm_year - b->tm_year;
280 int days = (365 * years + intervening_leap_days
281 + (a->tm_yday - b->tm_yday));
282 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
283 + (a->tm_min - b->tm_min))
284 + (a->tm_sec - b->tm_sec));
286 #endif /* ! HAVE_TM_GMTOFF */
290 /* The number of days from the first day of the first ISO week of this
291 year to the year day YDAY with week day WDAY. ISO weeks start on
292 Monday; the first ISO week has the year's first Thursday. YDAY may
293 be as small as YDAY_MINIMUM. */
294 #define ISO_WEEK_START_WDAY 1 /* Monday */
295 #define ISO_WEEK1_WDAY 4 /* Thursday */
296 #define YDAY_MINIMUM (-366)
297 static int iso_week_days __P ((int, int));
302 iso_week_days (yday, wday)
306 /* Add enough to the first operand of % to make it nonnegative. */
307 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
309 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
310 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
315 static char const weekday_name[][10] =
317 "Sunday", "Monday", "Tuesday", "Wednesday",
318 "Thursday", "Friday", "Saturday"
320 static char const month_name[][10] =
322 "January", "February", "March", "April", "May", "June",
323 "July", "August", "September", "October", "November", "December"
327 /* Write information from TP into S according to the format
328 string FORMAT, writing no more that MAXSIZE characters
329 (including the terminating '\0') and returning number of
330 characters written. If S is NULL, nothing will be written
331 anywhere, so to determine how many characters would be
332 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
334 strftime (s, maxsize, format, tp)
340 int hour12 = tp->tm_hour;
342 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
343 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
344 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
345 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
346 const char *const ampm = _NL_CURRENT (LC_TIME,
347 hour12 > 11 ? PM_STR : AM_STR);
348 size_t aw_len = strlen (a_wkday);
349 size_t am_len = strlen (a_month);
350 size_t ap_len = strlen (ampm);
352 const char *const f_wkday = weekday_name[tp->tm_wday];
353 const char *const f_month = month_name[tp->tm_mon];
354 const char *const a_wkday = f_wkday;
355 const char *const a_month = f_month;
356 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
361 size_t wkday_len = strlen (f_wkday);
362 size_t month_len = strlen (f_month);
370 #if !defined _LIBC && HAVE_TM_ZONE
371 /* XXX We have some problems here. First, the string pointed to by
372 tm_zone is dynamically allocated while loading the zone data. But
373 when another zone is loaded since the information in TP were
374 computed this would be a stale pointer.
375 The second problem is the POSIX test suite which assumes setting
376 the environment variable TZ to a new value before calling strftime()
377 will influence the result (the %Z format) even if the information in
378 TP is computed with a totally different time zone. --drepper@gnu */
379 zone = (const char *) tp->tm_zone;
382 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
383 time zone names contained in the external variable `tzname' shall
384 be set as if the tzset() function had been called. */
389 if (!(zone && *zone) && tp->tm_isdst >= 0)
390 zone = tzname[tp->tm_isdst];
393 zone = ""; /* POSIX.2 requires the empty string here. */
395 zonelen = strlen (zone);
400 if (hour12 == 0) hour12 = 12;
402 for (f = format; *f != '\0'; ++f)
404 int pad; /* Padding for number ('-', '_', or 0). */
405 int modifier; /* Field modifier ('E', 'O', or 0). */
406 int digits; /* Max digits for numeric format. */
407 int number_value; /* Numeric value to be printed. */
408 int negative_number; /* 1 if the number is negative. */
411 char buf[1 + (sizeof (int) < sizeof (time_t)
412 ? INT_STRLEN_BOUND (time_t)
413 : INT_STRLEN_BOUND (int))];
425 case '\a': case '\b': case '\t': case '\n':
426 case '\v': case '\f': case '\r':
427 case ' ': case '!': case '"': case '#': case '&': case'\'':
428 case '(': case ')': case '*': case '+': case ',': case '-':
429 case '.': case '/': case '0': case '1': case '2': case '3':
430 case '4': case '5': case '6': case '7': case '8': case '9':
431 case ':': case ';': case '<': case '=': case '>': case '?':
432 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
433 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
434 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
435 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
436 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
437 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
438 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
439 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
440 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
441 case 'x': case 'y': case 'z': case '{': case '|': case '}':
443 /* The C Standard requires these 98 characters (plus '%') to
444 be in the basic execution character set. None of these
445 characters can start a multibyte sequence, so they need
446 not be analyzed further. */
451 /* Copy this multibyte sequence until we reach its end, find
452 an error, or come back to the initial shift state. */
454 mbstate_t mbstate = mbstate_zero;
459 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
464 if (bytes == (size_t) -2 || bytes == (size_t) -1)
472 while (! mbsinit (&mbstate));
479 #else /* ! DO_MULTIBYTE */
481 /* Either multibyte encodings are not supported, or they are
482 safe for formats, so any non-'%' byte can be copied through. */
489 #endif /* ! DO_MULTIBYTE */
491 /* Check for flags that can modify a number format. */
513 /* As a GNU extension we allow to specify the field width. */
522 while (isdigit (*++f));
525 /* Check for modifiers. */
538 /* Now do the specified format. */
541 #define DO_NUMBER(d, v) \
542 digits = d; number_value = v; goto do_number
543 #define DO_NUMBER_SPACEPAD(d, v) \
544 digits = d; number_value = v; goto do_number_spacepad
555 cpy (aw_len, a_wkday);
561 cpy (wkday_len, f_wkday);
565 case 'h': /* POSIX.2 extension. */
568 cpy (am_len, a_month);
574 cpy (month_len, f_month);
581 if (! (modifier == 'E'
582 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
583 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
585 subfmt = "%a %b %e %H:%M:%S %Y";
591 size_t len = strftime (NULL, maxsize - i, subfmt, tp);
592 if (len == 0 && *subfmt)
594 add (len, strftime (p, maxsize - i, subfmt, tp));
597 while (old_start < p)
599 *old_start = TOUPPER (*old_start);
605 case 'C': /* POSIX.2 extension. */
608 #if HAVE_STRUCT_ERA_ENTRY
611 struct era_entry *era = _nl_get_era_entry (tp);
614 size_t len = strlen (era->name_fmt);
615 cpy (len, era->name_fmt);
621 int year = tp->tm_year + TM_YEAR_BASE;
622 DO_NUMBER (1, year / 100 - (year % 100 < 0));
629 if (! (modifier == 'E'
630 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
631 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
635 case 'D': /* POSIX.2 extension. */
645 DO_NUMBER (2, tp->tm_mday);
647 case 'e': /* POSIX.2 extension. */
651 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
653 /* All numeric formats set DIGITS and NUMBER_VALUE and then
654 jump to one of these two labels. */
657 /* Force `_' flag unless overwritten by `0' flag. */
662 /* Format the number according to the MODIFIER flag. */
665 if (modifier == 'O' && 0 <= number_value)
667 /* Get the locale specific alternate representation of
668 the number NUMBER_VALUE. If none exist NULL is returned. */
669 const char *cp = _nl_get_alt_digit (number_value);
673 size_t digitlen = strlen (cp);
683 unsigned int u = number_value;
685 bufp = buf + sizeof (buf);
686 negative_number = number_value < 0;
692 *--bufp = u % 10 + '0';
693 while ((u /= 10) != 0);
696 do_number_sign_and_padding:
702 int padding = digits - (buf + sizeof (buf) - bufp);
706 while (0 < padding--)
711 bufp += negative_number;
712 while (0 < padding--)
719 cpy (buf + sizeof (buf) - bufp, bufp);
727 DO_NUMBER (2, tp->tm_hour);
733 DO_NUMBER (2, hour12);
735 case 'k': /* GNU extension. */
739 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
741 case 'l': /* GNU extension. */
745 DO_NUMBER_SPACEPAD (2, hour12);
751 DO_NUMBER (3, 1 + tp->tm_yday);
757 DO_NUMBER (2, tp->tm_min);
763 DO_NUMBER (2, tp->tm_mon + 1);
765 case 'n': /* POSIX.2 extension. */
777 case 'R': /* GNU extension. */
781 case 'r': /* POSIX.2 extension. */
783 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
785 subfmt = "%I:%M:%S %p";
792 DO_NUMBER (2, tp->tm_sec);
794 case 's': /* GNU extension. */
802 /* Generate string value for T using time_t arithmetic;
803 this works even if sizeof (long) < sizeof (time_t). */
805 bufp = buf + sizeof (buf);
806 negative_number = t < 0;
817 /* Adjust if division truncates to minus infinity. */
818 if (0 < -1 % 10 && d < 0)
830 goto do_number_sign_and_padding;
837 if (! (modifier == 'E'
838 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
839 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
843 case 'T': /* POSIX.2 extension. */
847 case 't': /* POSIX.2 extension. */
851 case 'u': /* POSIX.2 extension. */
852 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
858 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
861 case 'g': /* GNU extension. */
862 case 'G': /* GNU extension. */
866 int year = tp->tm_year + TM_YEAR_BASE;
867 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
871 /* This ISO week belongs to the previous year. */
873 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
878 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
882 /* This ISO week belongs to the next year. */
891 DO_NUMBER (2, (year % 100 + 100) % 100);
897 DO_NUMBER (2, days / 7 + 1);
905 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
911 DO_NUMBER (1, tp->tm_wday);
914 #if HAVE_STRUCT_ERA_ENTRY
917 struct era_entry *era = _nl_get_era_entry (tp);
920 subfmt = strchr (era->name_fmt, '\0') + 1;
928 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
931 #if HAVE_STRUCT_ERA_ENTRY
934 struct era_entry *era = _nl_get_era_entry (tp);
937 int delta = tp->tm_year - era->start_date[0];
938 DO_NUMBER (1, (era->offset
939 + (era->direction == '-' ? -delta : delta)));
943 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
949 case 'z': /* GNU extension. */
950 if (tp->tm_isdst < 0)
956 diff = tp->tm_gmtoff;
965 if (lt == (time_t) -1)
967 /* mktime returns -1 for errors, but -1 is also a
968 valid time_t value. Check whether an error really
971 localtime_r (<, &tm);
973 if ((ltm.tm_sec ^ tm.tm_sec)
974 | (ltm.tm_min ^ tm.tm_min)
975 | (ltm.tm_hour ^ tm.tm_hour)
976 | (ltm.tm_mday ^ tm.tm_mday)
977 | (ltm.tm_mon ^ tm.tm_mon)
978 | (ltm.tm_year ^ tm.tm_year))
982 if (! gmtime_r (<, >m))
985 diff = tm_diff (<m, >m);
997 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1000 case '\0': /* GNU extension: % at end of format. */
1004 /* Unknown format; output the format, including the '%',
1005 since this is most likely the right thing to do if a
1006 multibyte string has been misparsed. */
1010 for (flen = 1; f[1 - flen] != '%'; flen++)
1012 cpy (flen, &f[1 - flen]);