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 HAVE_TZNAME 1
32 # define MULTIBYTE_IS_FORMAT_SAFE 1
33 # define STDC_HEADERS 1
34 # include <ansidecl.h>
35 # include "../locale/localeinfo.h"
39 #include <sys/types.h> /* Some systems define `time_t' here. */
41 #ifdef TIME_WITH_SYS_TIME
42 # include <sys/time.h>
45 # ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
52 extern char *tzname[];
55 /* Do multibyte processing if multibytes are supported, unless
56 multibyte sequences are safe in formats. Multibyte sequences are
57 safe if they cannot contain byte sequences that look like format
58 conversion specifications. The GNU C Library uses UTF8 multibyte
59 encoding, which is safe for formats, but strftime.c can be used
60 with other C libraries that use unsafe encodings. */
61 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
67 /* Simulate mbrlen with mblen as best we can. */
68 # define mbstate_t int
69 # define mbrlen(s, n, ps) mblen (s, n)
70 # define mbsinit(ps) (*(ps) == 0)
72 static const mbstate_t mbstate_zero;
84 # define memcpy(d, s, n) bcopy ((s), (d), (n))
88 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
89 # define __P(args) args
111 #define TYPE_SIGNED(t) ((t) -1 < 0)
113 /* Bound on length of the string representing an integer value of type t.
114 Subtract one for the sign bit if t is signed;
115 302 / 1000 is log10 (2) rounded up;
116 add one for integer division truncation;
117 add one more for a minus sign if t is signed. */
118 #define INT_STRLEN_BOUND(t) \
119 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
121 #define TM_YEAR_BASE 1900
124 /* Nonzero if YEAR is a leap year (every 4 years,
125 except every 100th isn't, and every 400th is). */
126 # define __isleap(year) \
127 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
132 # define gmtime_r __gmtime_r
133 # define localtime_r __localtime_r
134 extern int __tz_compute __P ((time_t timer, const struct tm *tm));
135 # define tzname __tzname
136 # define tzset __tzset
138 # if ! HAVE_LOCALTIME_R
139 # if ! HAVE_TM_GMTOFF
140 /* Approximate gmtime_r as best we can in its absence. */
141 # define gmtime_r my_gmtime_r
142 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
148 struct tm *l = gmtime (t);
154 # endif /* ! HAVE_TM_GMTOFF */
156 /* Approximate localtime_r as best we can in its absence. */
157 # define localtime_r my_localtime_r
158 static struct tm *localtime_r __P ((const time_t *, struct tm *));
164 struct tm *l = localtime (t);
170 # endif /* ! HAVE_LOCALTIME_R */
171 #endif /* ! defined (_LIBC) */
174 #if !defined (memset) && !defined (HAVE_MEMSET) && !defined (_LIBC)
175 /* Some systems lack the `memset' function and we don't want to
176 introduce additional dependencies. */
177 static const char spaces[16] = " ";
179 # define memset_space(P, Len) \
185 int _this = _len > 16 ? 16 : _len; \
186 memcpy ((P), spaces, _this); \
193 # define memset_space(P, Len) memset ((P), ' ', (Len))
200 int _delta = width - _n; \
201 int _incr = _n + (_delta > 0 ? _delta : 0); \
202 if (i + _incr >= maxsize) \
207 memset_space (p, _delta); \
217 memcpy_lowcase (p, (s), _n); \
218 else if (to_uppcase) \
219 memcpy_uppcase (p, (s), _n); \
221 memcpy ((PTR) p, (PTR) (s), _n))
226 # define TOUPPER(Ch) toupper (Ch)
227 # define TOLOWER(Ch) tolower (Ch)
229 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
230 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
233 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
236 memcpy_lowcase (dest, src, len)
242 dest[len] = TOLOWER (src[len]);
246 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
249 memcpy_uppcase (dest, src, len)
255 dest[len] = TOUPPER (src[len]);
260 /* Yield the difference between *A and *B,
261 measured in seconds, ignoring leap seconds. */
262 static int tm_diff __P ((const struct tm *, const struct tm *));
268 /* Compute intervening leap days correctly even if year is negative.
269 Take care to avoid int overflow in leap day calculations,
270 but it's OK to assume that A and B are close to each other. */
271 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
272 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
273 int a100 = a4 / 25 - (a4 % 25 < 0);
274 int b100 = b4 / 25 - (b4 % 25 < 0);
275 int a400 = a100 >> 2;
276 int b400 = b100 >> 2;
277 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
278 int years = a->tm_year - b->tm_year;
279 int days = (365 * years + intervening_leap_days
280 + (a->tm_yday - b->tm_yday));
281 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
282 + (a->tm_min - b->tm_min))
283 + (a->tm_sec - b->tm_sec));
285 #endif /* ! HAVE_TM_GMTOFF */
289 /* The number of days from the first day of the first ISO week of this
290 year to the year day YDAY with week day WDAY. ISO weeks start on
291 Monday; the first ISO week has the year's first Thursday. YDAY may
292 be as small as YDAY_MINIMUM. */
293 #define ISO_WEEK_START_WDAY 1 /* Monday */
294 #define ISO_WEEK1_WDAY 4 /* Thursday */
295 #define YDAY_MINIMUM (-366)
296 static int iso_week_days __P ((int, int));
301 iso_week_days (yday, wday)
305 /* Add enough to the first operand of % to make it nonnegative. */
306 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
308 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
309 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
314 static char const weekday_name[][10] =
316 "Sunday", "Monday", "Tuesday", "Wednesday",
317 "Thursday", "Friday", "Saturday"
319 static char const month_name[][10] =
321 "January", "February", "March", "April", "May", "June",
322 "July", "August", "September", "October", "November", "December"
326 /* Write information from TP into S according to the format
327 string FORMAT, writing no more that MAXSIZE characters
328 (including the terminating '\0') and returning number of
329 characters written. If S is NULL, nothing will be written
330 anywhere, so to determine how many characters would be
331 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
333 strftime (s, maxsize, format, tp)
339 int hour12 = tp->tm_hour;
341 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
342 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
343 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
344 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
345 const char *const ampm = _NL_CURRENT (LC_TIME,
346 hour12 > 11 ? PM_STR : AM_STR);
347 size_t aw_len = strlen (a_wkday);
348 size_t am_len = strlen (a_month);
349 size_t ap_len = strlen (ampm);
351 const char *const f_wkday = weekday_name[tp->tm_wday];
352 const char *const f_month = month_name[tp->tm_mon];
353 const char *const a_wkday = f_wkday;
354 const char *const a_month = f_month;
355 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
360 size_t wkday_len = strlen (f_wkday);
361 size_t month_len = strlen (f_month);
369 #if !defined _LIBC && HAVE_TM_ZONE
370 /* XXX We have some problems here. First, the string pointed to by
371 tm_zone is dynamically allocated while loading the zone data. But
372 when another zone is loaded since the information in TP were
373 computed this would be a stale pointer.
374 The second problem is the POSIX test suite which assumes setting
375 the environment variable TZ to a new value before calling strftime()
376 will influence the result (the %Z format) even if the information in
377 TP is computed with a totally different time zone. --drepper@gnu */
378 zone = (const char *) tp->tm_zone;
381 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
382 time zone names contained in the external variable `tzname' shall
383 be set as if the tzset() function had been called. */
388 if (!(zone && *zone) && tp->tm_isdst >= 0)
389 zone = tzname[tp->tm_isdst];
392 zone = ""; /* POSIX.2 requires the empty string here. */
394 zonelen = strlen (zone);
399 if (hour12 == 0) hour12 = 12;
401 for (f = format; *f != '\0'; ++f)
403 int pad; /* Padding for number ('-', '_', or 0). */
404 int modifier; /* Field modifier ('E', 'O', or 0). */
405 int digits; /* Max digits for numeric format. */
406 int number_value; /* Numeric value to be printed. */
407 int negative_number; /* 1 if the number is negative. */
410 char buf[1 + (sizeof (int) < sizeof (time_t)
411 ? INT_STRLEN_BOUND (time_t)
412 : INT_STRLEN_BOUND (int))];
424 case '\a': case '\b': case '\t': case '\n':
425 case '\v': case '\f': case '\r':
426 case ' ': case '!': case '"': case '#': case '&': case'\'':
427 case '(': case ')': case '*': case '+': case ',': case '-':
428 case '.': case '/': case '0': case '1': case '2': case '3':
429 case '4': case '5': case '6': case '7': case '8': case '9':
430 case ':': case ';': case '<': case '=': case '>': case '?':
431 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
432 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
433 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
434 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
435 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
436 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
437 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
438 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
439 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
440 case 'x': case 'y': case 'z': case '{': case '|': case '}':
442 /* The C Standard requires these 98 characters (plus '%') to
443 be in the basic execution character set. None of these
444 characters can start a multibyte sequence, so they need
445 not be analyzed further. */
450 /* Copy this multibyte sequence until we reach its end, find
451 an error, or come back to the initial shift state. */
453 mbstate_t mbstate = mbstate_zero;
458 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
463 if (bytes == (size_t) -2 || bytes == (size_t) -1)
471 while (! mbsinit (&mbstate));
478 #else /* ! DO_MULTIBYTE */
480 /* Either multibyte encodings are not supported, or they are
481 safe for formats, so any non-'%' byte can be copied through. */
488 #endif /* ! DO_MULTIBYTE */
490 /* Check for flags that can modify a number format. */
512 /* As a GNU extension we allow to specify the field width. */
521 while (isdigit (*++f));
524 /* Check for modifiers. */
537 /* Now do the specified format. */
540 #define DO_NUMBER(d, v) \
541 digits = d; number_value = v; goto do_number
542 #define DO_NUMBER_SPACEPAD(d, v) \
543 digits = d; number_value = v; goto do_number_spacepad
554 cpy (aw_len, a_wkday);
560 cpy (wkday_len, f_wkday);
564 case 'h': /* POSIX.2 extension. */
567 cpy (am_len, a_month);
573 cpy (month_len, f_month);
580 if (! (modifier == 'E'
581 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
582 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
584 subfmt = "%a %b %e %H:%M:%S %Y";
590 size_t len = strftime (NULL, maxsize - i, subfmt, tp);
591 if (len == 0 && *subfmt)
593 add (len, strftime (p, maxsize - i, subfmt, tp));
596 while (old_start < p)
598 *old_start = TOUPPER (*old_start);
604 case 'C': /* POSIX.2 extension. */
607 #if HAVE_STRUCT_ERA_ENTRY
610 struct era_entry *era = _nl_get_era_entry (tp);
613 size_t len = strlen (era->name_fmt);
614 cpy (len, era->name_fmt);
620 int year = tp->tm_year + TM_YEAR_BASE;
621 DO_NUMBER (1, year / 100 - (year % 100 < 0));
628 if (! (modifier == 'E'
629 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
630 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
634 case 'D': /* POSIX.2 extension. */
644 DO_NUMBER (2, tp->tm_mday);
646 case 'e': /* POSIX.2 extension. */
650 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
652 /* All numeric formats set DIGITS and NUMBER_VALUE and then
653 jump to one of these two labels. */
656 /* Force `_' flag unless overwritten by `0' flag. */
661 /* Format the number according to the MODIFIER flag. */
664 if (modifier == 'O' && 0 <= number_value)
666 /* Get the locale specific alternate representation of
667 the number NUMBER_VALUE. If none exist NULL is returned. */
668 const char *cp = _nl_get_alt_digit (number_value);
672 size_t digitlen = strlen (cp);
682 unsigned int u = number_value;
684 bufp = buf + sizeof (buf);
685 negative_number = number_value < 0;
691 *--bufp = u % 10 + '0';
692 while ((u /= 10) != 0);
695 do_number_sign_and_padding:
701 int padding = digits - (buf + sizeof (buf) - bufp);
705 while (0 < padding--)
710 bufp += negative_number;
711 while (0 < padding--)
718 cpy (buf + sizeof (buf) - bufp, bufp);
726 DO_NUMBER (2, tp->tm_hour);
732 DO_NUMBER (2, hour12);
734 case 'k': /* GNU extension. */
738 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
740 case 'l': /* GNU extension. */
744 DO_NUMBER_SPACEPAD (2, hour12);
750 DO_NUMBER (3, 1 + tp->tm_yday);
756 DO_NUMBER (2, tp->tm_min);
762 DO_NUMBER (2, tp->tm_mon + 1);
764 case 'n': /* POSIX.2 extension. */
776 case 'R': /* GNU extension. */
780 case 'r': /* POSIX.2 extension. */
782 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
784 subfmt = "%I:%M:%S %p";
791 DO_NUMBER (2, tp->tm_sec);
793 case 's': /* GNU extension. */
801 /* Generate string value for T using time_t arithmetic;
802 this works even if sizeof (long) < sizeof (time_t). */
804 bufp = buf + sizeof (buf);
805 negative_number = t < 0;
816 /* Adjust if division truncates to minus infinity. */
817 if (0 < -1 % 10 && d < 0)
829 goto do_number_sign_and_padding;
836 if (! (modifier == 'E'
837 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
838 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
842 case 'T': /* POSIX.2 extension. */
846 case 't': /* POSIX.2 extension. */
850 case 'u': /* POSIX.2 extension. */
851 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
857 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
860 case 'g': /* GNU extension. */
861 case 'G': /* GNU extension. */
865 int year = tp->tm_year + TM_YEAR_BASE;
866 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
870 /* This ISO week belongs to the previous year. */
872 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
877 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
881 /* This ISO week belongs to the next year. */
890 DO_NUMBER (2, (year % 100 + 100) % 100);
896 DO_NUMBER (2, days / 7 + 1);
904 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
910 DO_NUMBER (1, tp->tm_wday);
913 #if HAVE_STRUCT_ERA_ENTRY
916 struct era_entry *era = _nl_get_era_entry (tp);
919 subfmt = strchr (era->name_fmt, '\0') + 1;
927 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
930 #if HAVE_STRUCT_ERA_ENTRY
933 struct era_entry *era = _nl_get_era_entry (tp);
936 int delta = tp->tm_year - era->start_date[0];
937 DO_NUMBER (1, (era->offset
938 + (era->direction == '-' ? -delta : delta)));
942 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
948 case 'z': /* GNU extension. */
949 if (tp->tm_isdst < 0)
955 diff = tp->tm_gmtoff;
964 if (lt == (time_t) -1)
966 /* mktime returns -1 for errors, but -1 is also a
967 valid time_t value. Check whether an error really
970 localtime_r (<, &tm);
972 if ((ltm.tm_sec ^ tm.tm_sec)
973 | (ltm.tm_min ^ tm.tm_min)
974 | (ltm.tm_hour ^ tm.tm_hour)
975 | (ltm.tm_mday ^ tm.tm_mday)
976 | (ltm.tm_mon ^ tm.tm_mon)
977 | (ltm.tm_year ^ tm.tm_year))
981 if (! gmtime_r (<, >m))
984 diff = tm_diff (<m, >m);
996 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
999 case '\0': /* GNU extension: % at end of format. */
1003 /* Unknown format; output the format, including the '%',
1004 since this is most likely the right thing to do if a
1005 multibyte string has been misparsed. */
1009 for (flen = 1; f[1 - flen] != '%'; flen++)
1011 cpy (flen, &f[1 - flen]);