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
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA. */
24 # define HAVE_LIMITS_H 1
26 # define HAVE_MBRLEN 1
27 # define HAVE_TM_GMTOFF 1
28 # define HAVE_TM_ZONE 1
29 # define MULTIBYTE_IS_FORMAT_SAFE 1
30 # define STDC_HEADERS 1
31 # include <ansidecl.h>
32 # include "../locale/localeinfo.h"
35 #include <sys/types.h> /* Some systems define `time_t' here. */
37 #ifdef TIME_WITH_SYS_TIME
38 # include <sys/time.h>
41 # ifdef HAVE_SYS_TIME_H
42 # include <sys/time.h>
48 /* Do multibyte processing if multibytes are supported, unless
49 multibyte sequences are safe in formats. Multibyte sequences are
50 safe if they cannot contain byte sequences that look like format
51 conversion specifications. The GNU C Library uses UTF8 multibyte
52 encoding, which is safe for formats, but strftime.c can be used
53 with other C libraries that use unsafe encodings. */
54 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
60 /* Simulate mbrlen with mblen as best we can. */
61 # define mbstate_t int
62 # define mbrlen(s, n, ps) mblen (s, n)
63 # define mbsinit(ps) (*(ps) == 0)
65 static const mbstate_t mbstate_zero
;
77 # define memcpy(d, s, n) bcopy (s, d, n)
81 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
82 #define __P(args) args
100 #define TYPE_SIGNED(t) ((t) -1 < 0)
102 /* Bound on length of the string representing an integer value of type t.
103 Subtract one for the sign bit if t is signed;
104 302 / 1000 is log10 (2) rounded up;
105 add one for integer division truncation;
106 add one more for a minus sign if t is signed. */
107 #define INT_STRLEN_BOUND(t) \
108 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
110 #define TM_YEAR_BASE 1900
113 /* Nonzero if YEAR is a leap year (every 4 years,
114 except every 100th isn't, and every 400th is). */
115 #define __isleap(year) \
116 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
121 # define gmtime_r __gmtime_r
122 # define localtime_r __localtime_r
124 # if ! HAVE_LOCALTIME_R
125 # if ! HAVE_TM_GMTOFF
126 /* Approximate gmtime_r as best we can in its absence. */
127 #define gmtime_r my_gmtime_r
128 static struct tm
*gmtime_r
__P ((const time_t *, struct tm
*));
134 struct tm
*l
= gmtime (t
);
140 # endif /* ! HAVE_TM_GMTOFF */
142 /* Approximate localtime_r as best we can in its absence. */
143 #define localtime_r my_localtime_r
144 static struct tm
*localtime_r
__P ((const time_t *, struct tm
*));
150 struct tm
*l
= localtime (t
);
156 # endif /* ! HAVE_LOCALTIME_R */
157 #endif /* ! defined (_LIBC) */
173 #define cpy(n, s) add ((n), memcpy((PTR) p, (PTR) (s), (n)))
176 /* Yield the difference between *A and *B,
177 measured in seconds, ignoring leap seconds. */
178 static int tm_diff
__P ((const struct tm
*, const struct tm
*));
184 /* Compute intervening leap days correctly even if year is negative.
185 Take care to avoid int overflow in leap day calculations,
186 but it's OK to assume that A and B are close to each other. */
187 int a4
= (a
->tm_year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (a
->tm_year
& 3);
188 int b4
= (b
->tm_year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (b
->tm_year
& 3);
189 int a100
= a4
/ 25 - (a4
% 25 < 0);
190 int b100
= b4
/ 25 - (b4
% 25 < 0);
191 int a400
= a100
>> 2;
192 int b400
= b100
>> 2;
193 int intervening_leap_days
= (a4
- b4
) - (a100
- b100
) + (a400
- b400
);
194 int years
= a
->tm_year
- b
->tm_year
;
195 int days
= (365 * years
+ intervening_leap_days
196 + (a
->tm_yday
- b
->tm_yday
));
197 return (60 * (60 * (24 * days
+ (a
->tm_hour
- b
->tm_hour
))
198 + (a
->tm_min
- b
->tm_min
))
199 + (a
->tm_sec
- b
->tm_sec
));
201 #endif /* ! HAVE_TM_GMTOFF */
205 /* The number of days from the first day of the first ISO week of this
206 year to the year day YDAY with week day WDAY. ISO weeks start on
207 Monday; the first ISO week has the year's first Thursday. YDAY may
208 be as small as YDAY_MINIMUM. */
209 #define ISO_WEEK_START_WDAY 1 /* Monday */
210 #define ISO_WEEK1_WDAY 4 /* Thursday */
211 #define YDAY_MINIMUM (-366)
212 static int iso_week_days
__P ((int, int));
217 iso_week_days (yday
, wday
)
221 /* Add enough to the first operand of % to make it nonnegative. */
222 int big_enough_multiple_of_7
= (-YDAY_MINIMUM
/ 7 + 2) * 7;
224 - (yday
- wday
+ ISO_WEEK1_WDAY
+ big_enough_multiple_of_7
) % 7
225 + ISO_WEEK1_WDAY
- ISO_WEEK_START_WDAY
);
230 static char const weekday_name
[][10] =
232 "Sunday", "Monday", "Tuesday", "Wednesday",
233 "Thursday", "Friday", "Saturday"
235 static char const month_name
[][10] =
237 "January", "February", "March", "April", "May", "June",
238 "July", "August", "September", "October", "November", "December"
242 /* Write information from TP into S according to the format
243 string FORMAT, writing no more that MAXSIZE characters
244 (including the terminating '\0') and returning number of
245 characters written. If S is NULL, nothing will be written
246 anywhere, so to determine how many characters would be
247 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
249 strftime (s
, maxsize
, format
, tp
)
253 register const struct tm
*tp
;
255 int hour12
= tp
->tm_hour
;
257 const char *const a_wkday
= _NL_CURRENT (LC_TIME
, ABDAY_1
+ tp
->tm_wday
);
258 const char *const f_wkday
= _NL_CURRENT (LC_TIME
, DAY_1
+ tp
->tm_wday
);
259 const char *const a_month
= _NL_CURRENT (LC_TIME
, ABMON_1
+ tp
->tm_mon
);
260 const char *const f_month
= _NL_CURRENT (LC_TIME
, MON_1
+ tp
->tm_mon
);
261 const char *const ampm
= _NL_CURRENT (LC_TIME
,
262 hour12
> 11 ? PM_STR
: AM_STR
);
263 size_t aw_len
= strlen(a_wkday
);
264 size_t am_len
= strlen(a_month
);
265 size_t ap_len
= strlen (ampm
);
267 const char *alt_digits
= _NL_CURRENT (LC_TIME
, ALT_DIGITS
);
268 const char *end_alt_digits
= _NL_CURRENT (LC_TIME
, ALT_DIGITS
+ 1);
270 const char *const f_wkday
= weekday_name
[tp
->tm_wday
];
271 const char *const f_month
= month_name
[tp
->tm_mon
];
272 const char *const a_wkday
= f_wkday
;
273 const char *const a_month
= f_month
;
274 const char *const ampm
= "AMPM" + 2 * (hour12
> 11);
279 size_t wkday_len
= strlen (f_wkday
);
280 size_t month_len
= strlen (f_month
);
283 register size_t i
= 0;
284 register char *p
= s
;
285 register const char *f
;
289 zone
= (const char *) tp
->tm_zone
;
292 if (!(zone
&& *zone
) && tp
->tm_isdst
>= 0)
293 zone
= tzname
[tp
->tm_isdst
];
296 zone
= ""; /* POSIX.2 requires the empty string here. */
298 zonelen
= strlen (zone
);
303 if (hour12
== 0) hour12
= 12;
305 for (f
= format
; *f
!= '\0'; ++f
)
307 int pad
; /* Padding for number ('-', '_', or 0). */
308 int modifier
; /* Field modifier ('E', 'O', or 0). */
309 int digits
; /* Max digits for numeric format. */
310 int number_value
; /* Numeric value to be printed. */
311 int negative_number
; /* 1 if the number is negative. */
314 char buf
[1 + (sizeof (int) < sizeof (time_t)
315 ? INT_STRLEN_BOUND (time_t)
316 : INT_STRLEN_BOUND (int))];
325 case '\a': case '\b': case '\t': case '\n':
326 case '\v': case '\f': case '\r':
327 case ' ': case '!': case '"': case '#': case '&': case'\'':
328 case '(': case ')': case '*': case '+': case ',': case '-':
329 case '.': case '/': case '0': case '1': case '2': case '3':
330 case '4': case '5': case '6': case '7': case '8': case '9':
331 case ':': case ';': case '<': case '=': case '>': case '?':
332 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
333 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
334 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
335 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
336 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
337 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
338 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
339 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
340 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
341 case 'x': case 'y': case 'z': case '{': case '|': case '}':
343 /* The C Standard requires these 98 characters (plus '%') to
344 be in the basic execution character set. None of these
345 characters can start a multibyte sequence, so they need
346 not be analyzed further. */
351 /* Copy this multibyte sequence until we reach its end, find
352 an error, or come back to the initial shift state. */
354 mbstate_t mbstate
= mbstate_zero
;
359 size_t bytes
= mbrlen (f
+ len
, (size_t) -1, &mbstate
);
364 if (bytes
== (size_t) -2 || bytes
== (size_t) -1)
372 while (! mbsinit (&mbstate
));
379 #else /* ! DO_MULTIBYTE */
381 /* Either multibyte encodings are not supported, or they are
382 safe for formats, so any non-'%' byte can be copied through. */
389 #endif /* ! DO_MULTIBYTE */
391 /* Check for flags that can modify a number format. */
405 /* Check for modifiers. */
418 /* Now do the specified format. */
421 #define DO_NUMBER(d, v) \
422 digits = d; number_value = v; goto do_number
423 #define DO_NUMBER_SPACEPAD(d, v) \
424 digits = d; number_value = v; goto do_number_spacepad
426 case '\0': /* GNU extension: % at end of format. */
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 %Z %Y";
473 size_t len
= strftime (p
, maxsize
- i
, subfmt
, tp
);
474 if (len
== 0 && *subfmt
)
480 case 'C': /* POSIX.2 extension. */
484 /* XXX %EC is not implemented yet. */
487 int year
= tp
->tm_year
+ TM_YEAR_BASE
;
488 DO_NUMBER (1, year
/ 100 - (year
% 100 < 0));
495 if (! (modifier
== 'E'
496 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_D_FMT
)) != '\0'))
497 subfmt
= _NL_CURRENT (LC_TIME
, D_FMT
);
501 case 'D': /* POSIX.2 extension. */
511 DO_NUMBER (2, tp
->tm_mday
);
513 case 'e': /* POSIX.2 extension. */
517 DO_NUMBER_SPACEPAD (2, tp
->tm_mday
);
519 /* All numeric formats set DIGITS and NUMBER_VALUE and then
520 jump to one of these two labels. */
523 /* Force `_' flag. */
527 /* Format the number according to the MODIFIER flag. */
530 if (modifier
== 'O' && 0 <= number_value
)
532 /* ALT_DIGITS is the first entry in an array with
533 alternative digit symbols. We have to find string
534 number NUMBER_VALUE, but must not look beyond
536 int run
= number_value
;
537 const char *cp
= alt_digits
;
539 while (run
-- > 0 && cp
< end_alt_digits
)
540 cp
= strchr (cp
, '\0') + 1;
542 if (cp
< end_alt_digits
)
544 size_t digitlen
= strlen (cp
);
554 unsigned int u
= number_value
;
556 bufp
= buf
+ sizeof (buf
);
557 negative_number
= number_value
< 0;
563 *--bufp
= u
% 10 + '0';
564 while ((u
/= 10) != 0);
567 do_number_sign_and_padding
:
573 int padding
= digits
- (buf
+ sizeof (buf
) - bufp
);
577 while (0 < padding
--)
582 bufp
+= negative_number
;
583 while (0 < padding
--)
590 cpy (buf
+ sizeof (buf
) - bufp
, bufp
);
598 DO_NUMBER (2, tp
->tm_hour
);
604 DO_NUMBER (2, hour12
);
606 case 'k': /* GNU extension. */
610 DO_NUMBER_SPACEPAD (2, tp
->tm_hour
);
612 case 'l': /* GNU extension. */
616 DO_NUMBER_SPACEPAD (2, hour12
);
622 DO_NUMBER (3, 1 + tp
->tm_yday
);
628 DO_NUMBER (2, tp
->tm_min
);
634 DO_NUMBER (2, tp
->tm_mon
+ 1);
636 case 'n': /* POSIX.2 extension. */
644 case 'R': /* GNU extension. */
648 case 'r': /* POSIX.2 extension. */
650 if (*(subfmt
= _NL_CURRENT (LC_TIME
, T_FMT_AMPM
)) == '\0')
652 subfmt
= "%I:%M:%S %p";
659 DO_NUMBER (2, tp
->tm_sec
);
661 case 's': /* GNU extension. */
664 time_t t
= mktime (<m
);
666 /* Generate string value for T using time_t arithmetic;
667 this works even if sizeof (long) < sizeof (time_t). */
669 bufp
= buf
+ sizeof (buf
);
670 negative_number
= t
< 0;
681 /* Adjust if division truncates to minus infinity. */
682 if (0 < -1 % 10 && d
< 0)
694 goto do_number_sign_and_padding
;
701 if (! (modifier
== 'E'
702 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_T_FMT
)) != '\0'))
703 subfmt
= _NL_CURRENT (LC_TIME
, T_FMT
);
707 case 'T': /* POSIX.2 extension. */
711 case 't': /* POSIX.2 extension. */
715 case 'u': /* POSIX.2 extension. */
716 DO_NUMBER (1, (tp
->tm_wday
- 1 + 7) % 7 + 1);
722 DO_NUMBER (2, (tp
->tm_yday
- tp
->tm_wday
+ 7) / 7);
725 case 'g': /* GNU extension. */
726 case 'G': /* GNU extension. */
730 int year
= tp
->tm_year
+ TM_YEAR_BASE
;
731 int days
= iso_week_days (tp
->tm_yday
, tp
->tm_wday
);
735 /* This ISO week belongs to the previous year. */
737 days
= iso_week_days (tp
->tm_yday
+ (365 + __isleap (year
)),
742 int d
= iso_week_days (tp
->tm_yday
- (365 + __isleap (year
)),
746 /* This ISO week belongs to the next year. */
755 DO_NUMBER (2, (year
% 100 + 100) % 100);
761 DO_NUMBER (2, days
/ 7 + 1);
769 DO_NUMBER (2, (tp
->tm_yday
- (tp
->tm_wday
- 1 + 7) % 7 + 7) / 7);
775 DO_NUMBER (1, tp
->tm_wday
);
780 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_YEAR
)) != '\0')
786 DO_NUMBER (1, tp
->tm_year
+ TM_YEAR_BASE
);
790 /* XXX %Ey is not implemented yet. */
792 DO_NUMBER (2, (tp
->tm_year
% 100 + 100) % 100);
798 case 'z': /* GNU extension. */
799 if (tp
->tm_isdst
< 0)
805 diff
= tp
->tm_gmtoff
;
809 time_t lt
= mktime (<m
);
811 if (lt
== (time_t) -1)
813 /* mktime returns -1 for errors, but -1 is also a
814 valid time_t value. Check whether an error really
817 localtime_r (<
, &tm
);
819 if ((ltm
.tm_sec
^ tm
.tm_sec
)
820 | (ltm
.tm_min
^ tm
.tm_min
)
821 | (ltm
.tm_hour
^ tm
.tm_hour
)
822 | (ltm
.tm_mday
^ tm
.tm_mday
)
823 | (ltm
.tm_mon
^ tm
.tm_mon
)
824 | (ltm
.tm_year
^ tm
.tm_year
))
828 if (! gmtime_r (<
, >m
))
831 diff
= tm_diff (<m
, >m
);
843 DO_NUMBER (4, (diff
/ 60) * 100 + diff
% 60);
847 /* Unknown format; output the format, including the '%',
848 since this is most likely the right thing to do if a
849 multibyte string has been misparsed. */
853 for (flen
= 2; f
[1 - flen
] != '%'; flen
++)
855 cpy (flen
, &f
[1 - flen
]);