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
107 #define TYPE_SIGNED(t) ((t) -1 < 0)
109 /* Bound on length of the string representing an integer value of type t.
110 Subtract one for the sign bit if t is signed;
111 302 / 1000 is log10 (2) rounded up;
112 add one for integer division truncation;
113 add one more for a minus sign if t is signed. */
114 #define INT_STRLEN_BOUND(t) \
115 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
117 #define TM_YEAR_BASE 1900
120 /* Nonzero if YEAR is a leap year (every 4 years,
121 except every 100th isn't, and every 400th is). */
122 #define __isleap(year) \
123 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
128 # define gmtime_r __gmtime_r
129 # define localtime_r __localtime_r
130 extern int __tz_compute
__P ((time_t timer
, const struct tm
*tm
));
131 # define tzname __tzname
132 # define tzset __tzset
134 # if ! HAVE_LOCALTIME_R
135 # if ! HAVE_TM_GMTOFF
136 /* Approximate gmtime_r as best we can in its absence. */
137 #define gmtime_r my_gmtime_r
138 static struct tm
*gmtime_r
__P ((const time_t *, struct tm
*));
144 struct tm
*l
= gmtime (t
);
150 # endif /* ! HAVE_TM_GMTOFF */
152 /* Approximate localtime_r as best we can in its absence. */
153 #define localtime_r my_localtime_r
154 static struct tm
*localtime_r
__P ((const time_t *, struct tm
*));
160 struct tm
*l
= localtime (t
);
166 # endif /* ! HAVE_LOCALTIME_R */
167 #endif /* ! defined (_LIBC) */
170 #if !defined (memset) && !defined (HAVE_MEMSET) && !defined (_LIBC)
171 /* Some systems lack the `memset' function and we don't want to
172 introduce additional dependencies. */
173 static const char spaces
[16] = " ";
175 # define memset_space(P, Len) \
181 int _this = _len > 16 ? 16 : _len; \
182 memcpy ((P), spaces, _this); \
189 # define memset_space(P, Len) memset ((P), ' ', (Len))
196 int _delta = width - _n; \
197 i += _n + (_delta > 0 ? _delta : 0); \
204 memset_space (p, _delta); \
213 memcpy_lowcase (p, (s), _n); \
215 memcpy ((PTR) p, (PTR) (s), _n))
220 # define TOUPPER(Ch) toupper (Ch)
221 # define TOLOWER(Ch) tolower (Ch)
223 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
224 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
227 static char *memcpy_lowcase
__P ((char *dest
, const char *src
, size_t len
));
230 memcpy_lowcase (dest
, src
, len
)
236 dest
[len
] = TOLOWER (src
[len
]);
241 /* Yield the difference between *A and *B,
242 measured in seconds, ignoring leap seconds. */
243 static int tm_diff
__P ((const struct tm
*, const struct tm
*));
249 /* Compute intervening leap days correctly even if year is negative.
250 Take care to avoid int overflow in leap day calculations,
251 but it's OK to assume that A and B are close to each other. */
252 int a4
= (a
->tm_year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (a
->tm_year
& 3);
253 int b4
= (b
->tm_year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (b
->tm_year
& 3);
254 int a100
= a4
/ 25 - (a4
% 25 < 0);
255 int b100
= b4
/ 25 - (b4
% 25 < 0);
256 int a400
= a100
>> 2;
257 int b400
= b100
>> 2;
258 int intervening_leap_days
= (a4
- b4
) - (a100
- b100
) + (a400
- b400
);
259 int years
= a
->tm_year
- b
->tm_year
;
260 int days
= (365 * years
+ intervening_leap_days
261 + (a
->tm_yday
- b
->tm_yday
));
262 return (60 * (60 * (24 * days
+ (a
->tm_hour
- b
->tm_hour
))
263 + (a
->tm_min
- b
->tm_min
))
264 + (a
->tm_sec
- b
->tm_sec
));
266 #endif /* ! HAVE_TM_GMTOFF */
270 /* The number of days from the first day of the first ISO week of this
271 year to the year day YDAY with week day WDAY. ISO weeks start on
272 Monday; the first ISO week has the year's first Thursday. YDAY may
273 be as small as YDAY_MINIMUM. */
274 #define ISO_WEEK_START_WDAY 1 /* Monday */
275 #define ISO_WEEK1_WDAY 4 /* Thursday */
276 #define YDAY_MINIMUM (-366)
277 static int iso_week_days
__P ((int, int));
282 iso_week_days (yday
, wday
)
286 /* Add enough to the first operand of % to make it nonnegative. */
287 int big_enough_multiple_of_7
= (-YDAY_MINIMUM
/ 7 + 2) * 7;
289 - (yday
- wday
+ ISO_WEEK1_WDAY
+ big_enough_multiple_of_7
) % 7
290 + ISO_WEEK1_WDAY
- ISO_WEEK_START_WDAY
);
295 static char const weekday_name
[][10] =
297 "Sunday", "Monday", "Tuesday", "Wednesday",
298 "Thursday", "Friday", "Saturday"
300 static char const month_name
[][10] =
302 "January", "February", "March", "April", "May", "June",
303 "July", "August", "September", "October", "November", "December"
307 /* Write information from TP into S according to the format
308 string FORMAT, writing no more that MAXSIZE characters
309 (including the terminating '\0') and returning number of
310 characters written. If S is NULL, nothing will be written
311 anywhere, so to determine how many characters would be
312 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
314 strftime (s
, maxsize
, format
, tp
)
320 int hour12
= tp
->tm_hour
;
322 const char *const a_wkday
= _NL_CURRENT (LC_TIME
, ABDAY_1
+ tp
->tm_wday
);
323 const char *const f_wkday
= _NL_CURRENT (LC_TIME
, DAY_1
+ tp
->tm_wday
);
324 const char *const a_month
= _NL_CURRENT (LC_TIME
, ABMON_1
+ tp
->tm_mon
);
325 const char *const f_month
= _NL_CURRENT (LC_TIME
, MON_1
+ tp
->tm_mon
);
326 const char *const ampm
= _NL_CURRENT (LC_TIME
,
327 hour12
> 11 ? PM_STR
: AM_STR
);
328 size_t aw_len
= strlen (a_wkday
);
329 size_t am_len
= strlen (a_month
);
330 size_t ap_len
= strlen (ampm
);
332 const char *const f_wkday
= weekday_name
[tp
->tm_wday
];
333 const char *const f_month
= month_name
[tp
->tm_mon
];
334 const char *const a_wkday
= f_wkday
;
335 const char *const a_month
= f_month
;
336 const char *const ampm
= "AMPM" + 2 * (hour12
> 11);
341 size_t wkday_len
= strlen (f_wkday
);
342 size_t month_len
= strlen (f_month
);
350 #if !defined _LIBC && HAVE_TM_ZONE
351 /* XXX We have some problems here. First, the string pointed to by
352 tm_zone is dynamically allocated while loading the zone data. But
353 when another zone is loaded since the information in TP were
354 computed this would be a stale pointer.
355 The second problem is the POSIX test suite which assumes setting
356 the environment variable TZ to a new value before calling strftime()
357 will influence the result (the %Z format) even if the information in
358 TP is computed with a totally different time zone. --drepper@gnu */
359 zone
= (const char *) tp
->tm_zone
;
362 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
363 time zone names contained in the external variable `tzname' shall
364 be set as if the tzset() function had been called. */
369 if (!(zone
&& *zone
) && tp
->tm_isdst
>= 0)
370 zone
= tzname
[tp
->tm_isdst
];
373 zone
= ""; /* POSIX.2 requires the empty string here. */
375 zonelen
= strlen (zone
);
380 if (hour12
== 0) hour12
= 12;
382 for (f
= format
; *f
!= '\0'; ++f
)
384 int pad
; /* Padding for number ('-', '_', or 0). */
385 int modifier
; /* Field modifier ('E', 'O', or 0). */
386 int digits
; /* Max digits for numeric format. */
387 int number_value
; /* Numeric value to be printed. */
388 int negative_number
; /* 1 if the number is negative. */
391 char buf
[1 + (sizeof (int) < sizeof (time_t)
392 ? INT_STRLEN_BOUND (time_t)
393 : INT_STRLEN_BOUND (int))];
404 case '\a': case '\b': case '\t': case '\n':
405 case '\v': case '\f': case '\r':
406 case ' ': case '!': case '"': case '#': case '&': case'\'':
407 case '(': case ')': case '*': case '+': case ',': case '-':
408 case '.': case '/': case '0': case '1': case '2': case '3':
409 case '4': case '5': case '6': case '7': case '8': case '9':
410 case ':': case ';': case '<': case '=': case '>': case '?':
411 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
412 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
413 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
414 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
415 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
416 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
417 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
418 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
419 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
420 case 'x': case 'y': case 'z': case '{': case '|': case '}':
422 /* The C Standard requires these 98 characters (plus '%') to
423 be in the basic execution character set. None of these
424 characters can start a multibyte sequence, so they need
425 not be analyzed further. */
430 /* Copy this multibyte sequence until we reach its end, find
431 an error, or come back to the initial shift state. */
433 mbstate_t mbstate
= mbstate_zero
;
438 size_t bytes
= mbrlen (f
+ len
, (size_t) -1, &mbstate
);
443 if (bytes
== (size_t) -2 || bytes
== (size_t) -1)
451 while (! mbsinit (&mbstate
));
458 #else /* ! DO_MULTIBYTE */
460 /* Either multibyte encodings are not supported, or they are
461 safe for formats, so any non-'%' byte can be copied through. */
468 #endif /* ! DO_MULTIBYTE */
470 /* Check for flags that can modify a number format. */
489 /* As a GNU extension we allow to specify the field width. */
498 while (isdigit (*++f
));
501 /* Check for modifiers. */
514 /* Now do the specified format. */
517 #define DO_NUMBER(d, v) \
518 digits = d; number_value = v; goto do_number
519 #define DO_NUMBER_SPACEPAD(d, v) \
520 digits = d; number_value = v; goto do_number_spacepad
531 cpy (aw_len
, a_wkday
);
537 cpy (wkday_len
, f_wkday
);
541 case 'h': /* POSIX.2 extension. */
544 cpy (am_len
, a_month
);
550 cpy (month_len
, f_month
);
557 if (! (modifier
== 'E'
558 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_D_T_FMT
)) != '\0'))
559 subfmt
= _NL_CURRENT (LC_TIME
, D_T_FMT
);
561 subfmt
= "%a %b %e %H:%M:%S %Y";
566 size_t len
= strftime (NULL
, maxsize
- i
, subfmt
, tp
);
567 if (len
== 0 && *subfmt
)
569 add (len
, strftime (p
, maxsize
- i
, subfmt
, tp
));
573 case 'C': /* POSIX.2 extension. */
576 #if HAVE_STRUCT_ERA_ENTRY
579 struct era_entry
*era
= _nl_get_era_entry (tp
);
582 size_t len
= strlen (era
->name_fmt
);
583 cpy (len
, era
->name_fmt
);
589 int year
= tp
->tm_year
+ TM_YEAR_BASE
;
590 DO_NUMBER (1, year
/ 100 - (year
% 100 < 0));
597 if (! (modifier
== 'E'
598 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_D_FMT
)) != '\0'))
599 subfmt
= _NL_CURRENT (LC_TIME
, D_FMT
);
603 case 'D': /* POSIX.2 extension. */
613 DO_NUMBER (2, tp
->tm_mday
);
615 case 'e': /* POSIX.2 extension. */
619 DO_NUMBER_SPACEPAD (2, tp
->tm_mday
);
621 /* All numeric formats set DIGITS and NUMBER_VALUE and then
622 jump to one of these two labels. */
625 /* Force `_' flag unless overwritten by `0' flag. */
630 /* Format the number according to the MODIFIER flag. */
633 if (modifier
== 'O' && 0 <= number_value
)
635 /* Get the locale specific alternate representation of
636 the number NUMBER_VALUE. If none exist NULL is returned. */
637 const char *cp
= _nl_get_alt_digit (number_value
);
641 size_t digitlen
= strlen (cp
);
651 unsigned int u
= number_value
;
653 bufp
= buf
+ sizeof (buf
);
654 negative_number
= number_value
< 0;
660 *--bufp
= u
% 10 + '0';
661 while ((u
/= 10) != 0);
664 do_number_sign_and_padding
:
670 int padding
= digits
- (buf
+ sizeof (buf
) - bufp
);
674 while (0 < padding
--)
679 bufp
+= negative_number
;
680 while (0 < padding
--)
687 cpy (buf
+ sizeof (buf
) - bufp
, bufp
);
695 DO_NUMBER (2, tp
->tm_hour
);
701 DO_NUMBER (2, hour12
);
703 case 'k': /* GNU extension. */
707 DO_NUMBER_SPACEPAD (2, tp
->tm_hour
);
709 case 'l': /* GNU extension. */
713 DO_NUMBER_SPACEPAD (2, hour12
);
719 DO_NUMBER (3, 1 + tp
->tm_yday
);
725 DO_NUMBER (2, tp
->tm_min
);
731 DO_NUMBER (2, tp
->tm_mon
+ 1);
733 case 'n': /* POSIX.2 extension. */
745 case 'R': /* GNU extension. */
749 case 'r': /* POSIX.2 extension. */
751 if (*(subfmt
= _NL_CURRENT (LC_TIME
, T_FMT_AMPM
)) == '\0')
753 subfmt
= "%I:%M:%S %p";
760 DO_NUMBER (2, tp
->tm_sec
);
762 case 's': /* GNU extension. */
770 /* Generate string value for T using time_t arithmetic;
771 this works even if sizeof (long) < sizeof (time_t). */
773 bufp
= buf
+ sizeof (buf
);
774 negative_number
= t
< 0;
785 /* Adjust if division truncates to minus infinity. */
786 if (0 < -1 % 10 && d
< 0)
798 goto do_number_sign_and_padding
;
805 if (! (modifier
== 'E'
806 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_T_FMT
)) != '\0'))
807 subfmt
= _NL_CURRENT (LC_TIME
, T_FMT
);
811 case 'T': /* POSIX.2 extension. */
815 case 't': /* POSIX.2 extension. */
819 case 'u': /* POSIX.2 extension. */
820 DO_NUMBER (1, (tp
->tm_wday
- 1 + 7) % 7 + 1);
826 DO_NUMBER (2, (tp
->tm_yday
- tp
->tm_wday
+ 7) / 7);
829 case 'g': /* GNU extension. */
830 case 'G': /* GNU extension. */
834 int year
= tp
->tm_year
+ TM_YEAR_BASE
;
835 int days
= iso_week_days (tp
->tm_yday
, tp
->tm_wday
);
839 /* This ISO week belongs to the previous year. */
841 days
= iso_week_days (tp
->tm_yday
+ (365 + __isleap (year
)),
846 int d
= iso_week_days (tp
->tm_yday
- (365 + __isleap (year
)),
850 /* This ISO week belongs to the next year. */
859 DO_NUMBER (2, (year
% 100 + 100) % 100);
865 DO_NUMBER (2, days
/ 7 + 1);
873 DO_NUMBER (2, (tp
->tm_yday
- (tp
->tm_wday
- 1 + 7) % 7 + 7) / 7);
879 DO_NUMBER (1, tp
->tm_wday
);
882 #if HAVE_STRUCT_ERA_ENTRY
885 struct era_entry
*era
= _nl_get_era_entry (tp
);
888 subfmt
= strchr (era
->name_fmt
, '\0') + 1;
896 DO_NUMBER (1, tp
->tm_year
+ TM_YEAR_BASE
);
899 #if HAVE_STRUCT_ERA_ENTRY
902 struct era_entry
*era
= _nl_get_era_entry (tp
);
905 int delta
= tp
->tm_year
- era
->start_date
[0];
906 DO_NUMBER (1, (era
->offset
907 + (era
->direction
== '-' ? -delta
: delta
)));
911 DO_NUMBER (2, (tp
->tm_year
% 100 + 100) % 100);
917 case 'z': /* GNU extension. */
918 if (tp
->tm_isdst
< 0)
924 diff
= tp
->tm_gmtoff
;
933 if (lt
== (time_t) -1)
935 /* mktime returns -1 for errors, but -1 is also a
936 valid time_t value. Check whether an error really
939 localtime_r (<
, &tm
);
941 if ((ltm
.tm_sec
^ tm
.tm_sec
)
942 | (ltm
.tm_min
^ tm
.tm_min
)
943 | (ltm
.tm_hour
^ tm
.tm_hour
)
944 | (ltm
.tm_mday
^ tm
.tm_mday
)
945 | (ltm
.tm_mon
^ tm
.tm_mon
)
946 | (ltm
.tm_year
^ tm
.tm_year
))
950 if (! gmtime_r (<
, >m
))
953 diff
= tm_diff (<m
, >m
);
965 DO_NUMBER (4, (diff
/ 60) * 100 + diff
% 60);
968 case '\0': /* GNU extension: % at end of format. */
972 /* Unknown format; output the format, including the '%',
973 since this is most likely the right thing to do if a
974 multibyte string has been misparsed. */
978 for (flen
= 1; f
[1 - flen
] != '%'; flen
++)
980 cpy (flen
, &f
[1 - flen
]);