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 MULTIBYTE_IS_FORMAT_SAFE 1
31 # define STDC_HEADERS 1
32 # include <ansidecl.h>
33 # include "../locale/localeinfo.h"
36 #include <sys/types.h> /* Some systems define `time_t' here. */
38 #ifdef TIME_WITH_SYS_TIME
39 # include <sys/time.h>
42 # ifdef HAVE_SYS_TIME_H
43 # include <sys/time.h>
49 /* Do multibyte processing if multibytes are supported, unless
50 multibyte sequences are safe in formats. Multibyte sequences are
51 safe if they cannot contain byte sequences that look like format
52 conversion specifications. The GNU C Library uses UTF8 multibyte
53 encoding, which is safe for formats, but strftime.c can be used
54 with other C libraries that use unsafe encodings. */
55 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
61 /* Simulate mbrlen with mblen as best we can. */
62 # define mbstate_t int
63 # define mbrlen(s, n, ps) mblen (s, n)
64 # define mbsinit(ps) (*(ps) == 0)
66 static const mbstate_t mbstate_zero
;
78 # define memcpy(d, s, n) bcopy (s, d, n)
82 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
83 #define __P(args) args
101 #define TYPE_SIGNED(t) ((t) -1 < 0)
103 /* Bound on length of the string representing an integer value of type t.
104 Subtract one for the sign bit if t is signed;
105 302 / 1000 is log10 (2) rounded up;
106 add one for integer division truncation;
107 add one more for a minus sign if t is signed. */
108 #define INT_STRLEN_BOUND(t) \
109 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
111 #define TM_YEAR_BASE 1900
114 /* Nonzero if YEAR is a leap year (every 4 years,
115 except every 100th isn't, and every 400th is). */
116 #define __isleap(year) \
117 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
122 # define gmtime_r __gmtime_r
123 # define localtime_r __localtime_r
125 # if ! HAVE_LOCALTIME_R
126 # if ! HAVE_TM_GMTOFF
127 /* Approximate gmtime_r as best we can in its absence. */
128 #define gmtime_r my_gmtime_r
129 static struct tm
*gmtime_r
__P ((const time_t *, struct tm
*));
135 struct tm
*l
= gmtime (t
);
141 # endif /* ! HAVE_TM_GMTOFF */
143 /* Approximate localtime_r as best we can in its absence. */
144 #define localtime_r my_localtime_r
145 static struct tm
*localtime_r
__P ((const time_t *, struct tm
*));
151 struct tm
*l
= localtime (t
);
157 # endif /* ! HAVE_LOCALTIME_R */
158 #endif /* ! defined (_LIBC) */
174 #define cpy(n, s) add ((n), memcpy((PTR) p, (PTR) (s), (n)))
177 /* Yield the difference between *A and *B,
178 measured in seconds, ignoring leap seconds. */
179 static int tm_diff
__P ((const struct tm
*, const struct tm
*));
185 /* Compute intervening leap days correctly even if year is negative.
186 Take care to avoid int overflow in leap day calculations,
187 but it's OK to assume that A and B are close to each other. */
188 int a4
= (a
->tm_year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (a
->tm_year
& 3);
189 int b4
= (b
->tm_year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (b
->tm_year
& 3);
190 int a100
= a4
/ 25 - (a4
% 25 < 0);
191 int b100
= b4
/ 25 - (b4
% 25 < 0);
192 int a400
= a100
>> 2;
193 int b400
= b100
>> 2;
194 int intervening_leap_days
= (a4
- b4
) - (a100
- b100
) + (a400
- b400
);
195 int years
= a
->tm_year
- b
->tm_year
;
196 int days
= (365 * years
+ intervening_leap_days
197 + (a
->tm_yday
- b
->tm_yday
));
198 return (60 * (60 * (24 * days
+ (a
->tm_hour
- b
->tm_hour
))
199 + (a
->tm_min
- b
->tm_min
))
200 + (a
->tm_sec
- b
->tm_sec
));
202 #endif /* ! HAVE_TM_GMTOFF */
206 /* The number of days from the first day of the first ISO week of this
207 year to the year day YDAY with week day WDAY. ISO weeks start on
208 Monday; the first ISO week has the year's first Thursday. YDAY may
209 be as small as YDAY_MINIMUM. */
210 #define ISO_WEEK_START_WDAY 1 /* Monday */
211 #define ISO_WEEK1_WDAY 4 /* Thursday */
212 #define YDAY_MINIMUM (-366)
213 static int iso_week_days
__P ((int, int));
218 iso_week_days (yday
, wday
)
222 /* Add enough to the first operand of % to make it nonnegative. */
223 int big_enough_multiple_of_7
= (-YDAY_MINIMUM
/ 7 + 2) * 7;
225 - (yday
- wday
+ ISO_WEEK1_WDAY
+ big_enough_multiple_of_7
) % 7
226 + ISO_WEEK1_WDAY
- ISO_WEEK_START_WDAY
);
231 static char const weekday_name
[][10] =
233 "Sunday", "Monday", "Tuesday", "Wednesday",
234 "Thursday", "Friday", "Saturday"
236 static char const month_name
[][10] =
238 "January", "February", "March", "April", "May", "June",
239 "July", "August", "September", "October", "November", "December"
243 /* Write information from TP into S according to the format
244 string FORMAT, writing no more that MAXSIZE characters
245 (including the terminating '\0') and returning number of
246 characters written. If S is NULL, nothing will be written
247 anywhere, so to determine how many characters would be
248 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
250 strftime (s
, maxsize
, format
, tp
)
254 register const struct tm
*tp
;
256 int hour12
= tp
->tm_hour
;
258 const char *const a_wkday
= _NL_CURRENT (LC_TIME
, ABDAY_1
+ tp
->tm_wday
);
259 const char *const f_wkday
= _NL_CURRENT (LC_TIME
, DAY_1
+ tp
->tm_wday
);
260 const char *const a_month
= _NL_CURRENT (LC_TIME
, ABMON_1
+ tp
->tm_mon
);
261 const char *const f_month
= _NL_CURRENT (LC_TIME
, MON_1
+ tp
->tm_mon
);
262 const char *const ampm
= _NL_CURRENT (LC_TIME
,
263 hour12
> 11 ? PM_STR
: AM_STR
);
264 size_t aw_len
= strlen (a_wkday
);
265 size_t am_len
= strlen (a_month
);
266 size_t ap_len
= strlen (ampm
);
268 const char *const f_wkday
= weekday_name
[tp
->tm_wday
];
269 const char *const f_month
= month_name
[tp
->tm_mon
];
270 const char *const a_wkday
= f_wkday
;
271 const char *const a_month
= f_month
;
272 const char *const ampm
= "AMPM" + 2 * (hour12
> 11);
277 size_t wkday_len
= strlen (f_wkday
);
278 size_t month_len
= strlen (f_month
);
281 register size_t i
= 0;
282 register char *p
= s
;
283 register const char *f
;
287 zone
= (const char *) tp
->tm_zone
;
290 if (!(zone
&& *zone
) && tp
->tm_isdst
>= 0)
291 zone
= tzname
[tp
->tm_isdst
];
294 zone
= ""; /* POSIX.2 requires the empty string here. */
296 zonelen
= strlen (zone
);
301 if (hour12
== 0) hour12
= 12;
303 for (f
= format
; *f
!= '\0'; ++f
)
305 int pad
; /* Padding for number ('-', '_', or 0). */
306 int modifier
; /* Field modifier ('E', 'O', or 0). */
307 int digits
; /* Max digits for numeric format. */
308 int number_value
; /* Numeric value to be printed. */
309 int negative_number
; /* 1 if the number is negative. */
312 char buf
[1 + (sizeof (int) < sizeof (time_t)
313 ? INT_STRLEN_BOUND (time_t)
314 : INT_STRLEN_BOUND (int))];
323 case '\a': case '\b': case '\t': case '\n':
324 case '\v': case '\f': case '\r':
325 case ' ': case '!': case '"': case '#': case '&': case'\'':
326 case '(': case ')': case '*': case '+': case ',': case '-':
327 case '.': case '/': case '0': case '1': case '2': case '3':
328 case '4': case '5': case '6': case '7': case '8': case '9':
329 case ':': case ';': case '<': case '=': case '>': case '?':
330 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
331 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
332 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
333 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
334 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
335 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
336 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
337 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
338 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
339 case 'x': case 'y': case 'z': case '{': case '|': case '}':
341 /* The C Standard requires these 98 characters (plus '%') to
342 be in the basic execution character set. None of these
343 characters can start a multibyte sequence, so they need
344 not be analyzed further. */
349 /* Copy this multibyte sequence until we reach its end, find
350 an error, or come back to the initial shift state. */
352 mbstate_t mbstate
= mbstate_zero
;
357 size_t bytes
= mbrlen (f
+ len
, (size_t) -1, &mbstate
);
362 if (bytes
== (size_t) -2 || bytes
== (size_t) -1)
370 while (! mbsinit (&mbstate
));
377 #else /* ! DO_MULTIBYTE */
379 /* Either multibyte encodings are not supported, or they are
380 safe for formats, so any non-'%' byte can be copied through. */
387 #endif /* ! DO_MULTIBYTE */
389 /* Check for flags that can modify a number format. */
403 /* Check for modifiers. */
416 /* Now do the specified format. */
419 #define DO_NUMBER(d, v) \
420 digits = d; number_value = v; goto do_number
421 #define DO_NUMBER_SPACEPAD(d, v) \
422 digits = d; number_value = v; goto do_number_spacepad
433 cpy (aw_len
, a_wkday
);
439 cpy (wkday_len
, f_wkday
);
443 case 'h': /* POSIX.2 extension. */
446 cpy (am_len
, a_month
);
452 cpy (month_len
, f_month
);
459 if (! (modifier
== 'E'
460 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_D_T_FMT
)) != '\0'))
461 subfmt
= _NL_CURRENT (LC_TIME
, D_T_FMT
);
463 subfmt
= "%a %b %e %H:%M:%S %Z %Y";
468 size_t len
= strftime (p
, maxsize
- i
, subfmt
, tp
);
469 if (len
== 0 && *subfmt
)
475 case 'C': /* POSIX.2 extension. */
478 #if HAVE_STRUCT_ERA_ENTRY
481 struct era_entry
*era
= _nl_get_era_entry (tp
);
484 size_t len
= strlen (era
->name_fmt
);
485 cpy (len
, era
->name_fmt
);
491 int year
= tp
->tm_year
+ TM_YEAR_BASE
;
492 DO_NUMBER (1, year
/ 100 - (year
% 100 < 0));
499 if (! (modifier
== 'E'
500 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_D_FMT
)) != '\0'))
501 subfmt
= _NL_CURRENT (LC_TIME
, D_FMT
);
505 case 'D': /* POSIX.2 extension. */
515 DO_NUMBER (2, tp
->tm_mday
);
517 case 'e': /* POSIX.2 extension. */
521 DO_NUMBER_SPACEPAD (2, tp
->tm_mday
);
523 /* All numeric formats set DIGITS and NUMBER_VALUE and then
524 jump to one of these two labels. */
527 /* Force `_' flag. */
531 /* Format the number according to the MODIFIER flag. */
534 if (modifier
== 'O' && 0 <= number_value
)
536 /* Get the locale specific alternate representation of
537 the number NUMBER_VALUE. If none exist NULL is returned. */
538 const char *cp
= _nl_get_alt_digit (number_value
);
542 size_t digitlen
= strlen (cp
);
552 unsigned int u
= number_value
;
554 bufp
= buf
+ sizeof (buf
);
555 negative_number
= number_value
< 0;
561 *--bufp
= u
% 10 + '0';
562 while ((u
/= 10) != 0);
565 do_number_sign_and_padding
:
571 int padding
= digits
- (buf
+ sizeof (buf
) - bufp
);
575 while (0 < padding
--)
580 bufp
+= negative_number
;
581 while (0 < padding
--)
588 cpy (buf
+ sizeof (buf
) - bufp
, bufp
);
596 DO_NUMBER (2, tp
->tm_hour
);
602 DO_NUMBER (2, hour12
);
604 case 'k': /* GNU extension. */
608 DO_NUMBER_SPACEPAD (2, tp
->tm_hour
);
610 case 'l': /* GNU extension. */
614 DO_NUMBER_SPACEPAD (2, hour12
);
620 DO_NUMBER (3, 1 + tp
->tm_yday
);
626 DO_NUMBER (2, tp
->tm_min
);
632 DO_NUMBER (2, tp
->tm_mon
+ 1);
634 case 'n': /* POSIX.2 extension. */
642 case 'R': /* GNU extension. */
646 case 'r': /* POSIX.2 extension. */
648 if (*(subfmt
= _NL_CURRENT (LC_TIME
, T_FMT_AMPM
)) == '\0')
650 subfmt
= "%I:%M:%S %p";
657 DO_NUMBER (2, tp
->tm_sec
);
659 case 's': /* GNU extension. */
667 /* Generate string value for T using time_t arithmetic;
668 this works even if sizeof (long) < sizeof (time_t). */
670 bufp
= buf
+ sizeof (buf
);
671 negative_number
= t
< 0;
682 /* Adjust if division truncates to minus infinity. */
683 if (0 < -1 % 10 && d
< 0)
695 goto do_number_sign_and_padding
;
702 if (! (modifier
== 'E'
703 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_T_FMT
)) != '\0'))
704 subfmt
= _NL_CURRENT (LC_TIME
, T_FMT
);
708 case 'T': /* POSIX.2 extension. */
712 case 't': /* POSIX.2 extension. */
716 case 'u': /* POSIX.2 extension. */
717 DO_NUMBER (1, (tp
->tm_wday
- 1 + 7) % 7 + 1);
723 DO_NUMBER (2, (tp
->tm_yday
- tp
->tm_wday
+ 7) / 7);
726 case 'g': /* GNU extension. */
727 case 'G': /* GNU extension. */
731 int year
= tp
->tm_year
+ TM_YEAR_BASE
;
732 int days
= iso_week_days (tp
->tm_yday
, tp
->tm_wday
);
736 /* This ISO week belongs to the previous year. */
738 days
= iso_week_days (tp
->tm_yday
+ (365 + __isleap (year
)),
743 int d
= iso_week_days (tp
->tm_yday
- (365 + __isleap (year
)),
747 /* This ISO week belongs to the next year. */
756 DO_NUMBER (2, (year
% 100 + 100) % 100);
762 DO_NUMBER (2, days
/ 7 + 1);
770 DO_NUMBER (2, (tp
->tm_yday
- (tp
->tm_wday
- 1 + 7) % 7 + 7) / 7);
776 DO_NUMBER (1, tp
->tm_wday
);
779 #if HAVE_STRUCT_ERA_ENTRY
782 struct era_entry
*era
= _nl_get_era_entry (tp
);
785 subfmt
= strchr (era
->name_fmt
, '\0') + 1;
793 DO_NUMBER (1, tp
->tm_year
+ TM_YEAR_BASE
);
796 #if HAVE_STRUCT_ERA_ENTRY
799 struct era_entry
*era
= _nl_get_era_entry (tp
);
802 int delta
= tp
->tm_year
- era
->start_date
[0];
803 DO_NUMBER (1, (era
->offset
804 + (era
->direction
== '-' ? -delta
: delta
)));
808 DO_NUMBER (2, (tp
->tm_year
% 100 + 100) % 100);
814 case 'z': /* GNU extension. */
815 if (tp
->tm_isdst
< 0)
821 diff
= tp
->tm_gmtoff
;
830 if (lt
== (time_t) -1)
832 /* mktime returns -1 for errors, but -1 is also a
833 valid time_t value. Check whether an error really
836 localtime_r (<
, &tm
);
838 if ((ltm
.tm_sec
^ tm
.tm_sec
)
839 | (ltm
.tm_min
^ tm
.tm_min
)
840 | (ltm
.tm_hour
^ tm
.tm_hour
)
841 | (ltm
.tm_mday
^ tm
.tm_mday
)
842 | (ltm
.tm_mon
^ tm
.tm_mon
)
843 | (ltm
.tm_year
^ tm
.tm_year
))
847 if (! gmtime_r (<
, >m
))
850 diff
= tm_diff (<m
, >m
);
862 DO_NUMBER (4, (diff
/ 60) * 100 + diff
% 60);
865 case '\0': /* GNU extension: % at end of format. */
869 /* Unknown format; output the format, including the '%',
870 since this is most likely the right thing to do if a
871 multibyte string has been misparsed. */
875 for (flen
= 1; f
[1 - flen
] != '%'; flen
++)
877 cpy (flen
, &f
[1 - flen
]);