1 /* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
3 NOTE: The canonical source of this file is maintained with the GNU C Library.
4 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
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
26 # define HAVE_LIMITS_H 1
28 # define HAVE_MBRLEN 1
29 # define HAVE_STRUCT_ERA_ENTRY 1
30 # define HAVE_TM_GMTOFF 1
31 # define HAVE_TM_ZONE 1
32 # define HAVE_TZNAME 1
34 # define MULTIBYTE_IS_FORMAT_SAFE 1
35 # define STDC_HEADERS 1
36 # include "../locale/localeinfo.h"
39 #if defined emacs && !defined HAVE_BCOPY
40 # define HAVE_MEMCPY 1
44 #include <sys/types.h> /* Some systems define `time_t' here. */
46 #ifdef TIME_WITH_SYS_TIME
47 # include <sys/time.h>
50 # ifdef HAVE_SYS_TIME_H
51 # include <sys/time.h>
57 extern char *tzname
[];
60 /* Do multibyte processing if multibytes are supported, unless
61 multibyte sequences are safe in formats. Multibyte sequences are
62 safe if they cannot contain byte sequences that look like format
63 conversion specifications. The GNU C Library uses UTF8 multibyte
64 encoding, which is safe for formats, but strftime.c can be used
65 with other C libraries that use unsafe encodings. */
66 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
72 /* Simulate mbrlen with mblen as best we can. */
73 # define mbstate_t int
74 # define mbrlen(s, n, ps) mblen (s, n)
75 # define mbsinit(ps) (*(ps) == 0)
77 static const mbstate_t mbstate_zero
;
90 # define memcpy(d, s, n) bcopy ((s), (d), (n))
95 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
96 # define __P(args) args
100 #endif /* Not __P. */
118 #define TYPE_SIGNED(t) ((t) -1 < 0)
120 /* Bound on length of the string representing an integer value of type t.
121 Subtract one for the sign bit if t is signed;
122 302 / 1000 is log10 (2) rounded up;
123 add one for integer division truncation;
124 add one more for a minus sign if t is signed. */
125 #define INT_STRLEN_BOUND(t) \
126 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
128 #define TM_YEAR_BASE 1900
131 /* Nonzero if YEAR is a leap year (every 4 years,
132 except every 100th isn't, and every 400th is). */
133 # define __isleap(year) \
134 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
139 # define gmtime_r __gmtime_r
140 # define localtime_r __localtime_r
141 # define tzname __tzname
142 # define tzset __tzset
144 # if ! HAVE_LOCALTIME_R
145 # if ! HAVE_TM_GMTOFF
146 /* Approximate gmtime_r as best we can in its absence. */
148 # define gmtime_r my_gmtime_r
149 static struct tm
*gmtime_r
__P ((const time_t *, struct tm
*));
155 struct tm
*l
= gmtime (t
);
161 # endif /* ! HAVE_TM_GMTOFF */
163 /* Approximate localtime_r as best we can in its absence. */
165 # define localtime_r my_ftime_localtime_r
166 static struct tm
*localtime_r
__P ((const time_t *, struct tm
*));
172 struct tm
*l
= localtime (t
);
178 # endif /* ! HAVE_LOCALTIME_R */
179 #endif /* ! defined (_LIBC) */
182 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
183 /* Some systems lack the `memset' function and we don't want to
184 introduce additional dependencies. */
185 /* The SGI compiler reportedly barfs on the trailing null
186 if we use a string constant as the initializer. 28 June 1997, rms. */
187 static const char spaces
[16] = /* " " */
188 { ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
189 static const char zeroes
[16] = /* "0000000000000000" */
190 { '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' };
192 # define memset_space(P, Len) \
198 int _this = _len > 16 ? 16 : _len; \
199 memcpy ((P), spaces, _this); \
206 # define memset_zero(P, Len) \
212 int _this = _len > 16 ? 16 : _len; \
213 memcpy ((P), zeroes, _this); \
220 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
221 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
228 int _delta = width - _n; \
229 int _incr = _n + (_delta > 0 ? _delta : 0); \
230 if (i + _incr >= maxsize) \
237 memset_zero (p, _delta); \
239 memset_space (p, _delta); \
250 memcpy_lowcase (p, (s), _n); \
251 else if (to_uppcase) \
252 memcpy_uppcase (p, (s), _n); \
254 memcpy ((PTR) p, (PTR) (s), _n))
259 # define TOUPPER(Ch) toupper (Ch)
260 # define TOLOWER(Ch) tolower (Ch)
262 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
263 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
265 /* We don't use `isdigit' here since the locale dependent
266 interpretation is not what we want here. We only need to accept
267 the arabic digits in the ASCII range. One day there is perhaps a
268 more reliable way to accept other sets of digits. */
269 #define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
271 static char *memcpy_lowcase
__P ((char *dest
, const char *src
, size_t len
));
274 memcpy_lowcase (dest
, src
, len
)
280 dest
[len
] = TOLOWER (src
[len
]);
284 static char *memcpy_uppcase
__P ((char *dest
, const char *src
, size_t len
));
287 memcpy_uppcase (dest
, src
, len
)
293 dest
[len
] = TOUPPER (src
[len
]);
299 /* Yield the difference between *A and *B,
300 measured in seconds, ignoring leap seconds. */
301 # define tm_diff ftime_tm_diff
302 static int tm_diff
__P ((const struct tm
*, const struct tm
*));
308 /* Compute intervening leap days correctly even if year is negative.
309 Take care to avoid int overflow in leap day calculations,
310 but it's OK to assume that A and B are close to each other. */
311 int a4
= (a
->tm_year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (a
->tm_year
& 3);
312 int b4
= (b
->tm_year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (b
->tm_year
& 3);
313 int a100
= a4
/ 25 - (a4
% 25 < 0);
314 int b100
= b4
/ 25 - (b4
% 25 < 0);
315 int a400
= a100
>> 2;
316 int b400
= b100
>> 2;
317 int intervening_leap_days
= (a4
- b4
) - (a100
- b100
) + (a400
- b400
);
318 int years
= a
->tm_year
- b
->tm_year
;
319 int days
= (365 * years
+ intervening_leap_days
320 + (a
->tm_yday
- b
->tm_yday
));
321 return (60 * (60 * (24 * days
+ (a
->tm_hour
- b
->tm_hour
))
322 + (a
->tm_min
- b
->tm_min
))
323 + (a
->tm_sec
- b
->tm_sec
));
325 #endif /* ! HAVE_TM_GMTOFF */
329 /* The number of days from the first day of the first ISO week of this
330 year to the year day YDAY with week day WDAY. ISO weeks start on
331 Monday; the first ISO week has the year's first Thursday. YDAY may
332 be as small as YDAY_MINIMUM. */
333 #define ISO_WEEK_START_WDAY 1 /* Monday */
334 #define ISO_WEEK1_WDAY 4 /* Thursday */
335 #define YDAY_MINIMUM (-366)
336 static int iso_week_days
__P ((int, int));
341 iso_week_days (yday
, wday
)
345 /* Add enough to the first operand of % to make it nonnegative. */
346 int big_enough_multiple_of_7
= (-YDAY_MINIMUM
/ 7 + 2) * 7;
348 - (yday
- wday
+ ISO_WEEK1_WDAY
+ big_enough_multiple_of_7
) % 7
349 + ISO_WEEK1_WDAY
- ISO_WEEK_START_WDAY
);
354 static char const weekday_name
[][10] =
356 "Sunday", "Monday", "Tuesday", "Wednesday",
357 "Thursday", "Friday", "Saturday"
359 static char const month_name
[][10] =
361 "January", "February", "March", "April", "May", "June",
362 "July", "August", "September", "October", "November", "December"
367 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
368 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
369 Work around this bug by copying *tp before it might be munged. */
370 size_t _strftime_copytm
__P ((char *, size_t, const char *,
373 strftime (s
, maxsize
, format
, tp
)
381 return _strftime_copytm (s
, maxsize
, format
, &tmcopy
);
386 # define strftime(S, Maxsize, Format, Tp) \
387 _strftime_copytm (S, Maxsize, Format, Tp)
391 /* Write information from TP into S according to the format
392 string FORMAT, writing no more that MAXSIZE characters
393 (including the terminating '\0') and returning number of
394 characters written. If S is NULL, nothing will be written
395 anywhere, so to determine how many characters would be
396 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
398 strftime (s
, maxsize
, format
, tp
)
404 int hour12
= tp
->tm_hour
;
406 const char *const a_wkday
= _NL_CURRENT (LC_TIME
, ABDAY_1
+ tp
->tm_wday
);
407 const char *const f_wkday
= _NL_CURRENT (LC_TIME
, DAY_1
+ tp
->tm_wday
);
408 const char *const a_month
= _NL_CURRENT (LC_TIME
, ABMON_1
+ tp
->tm_mon
);
409 const char *const f_month
= _NL_CURRENT (LC_TIME
, MON_1
+ tp
->tm_mon
);
410 const char *const ampm
= _NL_CURRENT (LC_TIME
,
411 hour12
> 11 ? PM_STR
: AM_STR
);
412 size_t aw_len
= strlen (a_wkday
);
413 size_t am_len
= strlen (a_month
);
414 size_t ap_len
= strlen (ampm
);
416 const char *const f_wkday
= weekday_name
[tp
->tm_wday
];
417 const char *const f_month
= month_name
[tp
->tm_mon
];
418 const char *const a_wkday
= f_wkday
;
419 const char *const a_month
= f_month
;
420 const char *const ampm
= "AMPM" + 2 * (hour12
> 11);
425 size_t wkday_len
= strlen (f_wkday
);
426 size_t month_len
= strlen (f_month
);
435 /* The POSIX test suite assumes that setting
436 the environment variable TZ to a new value before calling strftime()
437 will influence the result (the %Z format) even if the information in
438 TP is computed with a totally different time zone.
439 This is bogus: though POSIX allows bad behavior like this,
440 POSIX does not require it. Do the right thing instead. */
441 zone
= (const char *) tp
->tm_zone
;
444 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
445 time zone names contained in the external variable `tzname' shall
446 be set as if the tzset() function had been called. */
451 if (!(zone
&& *zone
) && tp
->tm_isdst
>= 0)
452 zone
= tzname
[tp
->tm_isdst
];
455 zone
= ""; /* POSIX.2 requires the empty string here. */
457 zonelen
= strlen (zone
);
462 if (hour12
== 0) hour12
= 12;
464 for (f
= format
; *f
!= '\0'; ++f
)
466 int pad
; /* Padding for number ('-', '_', or 0). */
467 int modifier
; /* Field modifier ('E', 'O', or 0). */
468 int digits
; /* Max digits for numeric format. */
469 int number_value
; /* Numeric value to be printed. */
470 int negative_number
; /* 1 if the number is negative. */
473 char buf
[1 + (sizeof (int) < sizeof (time_t)
474 ? INT_STRLEN_BOUND (time_t)
475 : INT_STRLEN_BOUND (int))];
488 case '\a': case '\b': case '\t': case '\n':
489 case '\v': case '\f': case '\r':
490 case ' ': case '!': case '"': case '#': case '&': case'\'':
491 case '(': case ')': case '*': case '+': case ',': case '-':
492 case '.': case '/': case '0': case '1': case '2': case '3':
493 case '4': case '5': case '6': case '7': case '8': case '9':
494 case ':': case ';': case '<': case '=': case '>': case '?':
495 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
496 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
497 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
498 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
499 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
500 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
501 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
502 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
503 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
504 case 'x': case 'y': case 'z': case '{': case '|': case '}':
506 /* The C Standard requires these 98 characters (plus '%') to
507 be in the basic execution character set. None of these
508 characters can start a multibyte sequence, so they need
509 not be analyzed further. */
514 /* Copy this multibyte sequence until we reach its end, find
515 an error, or come back to the initial shift state. */
517 mbstate_t mbstate
= mbstate_zero
;
522 size_t bytes
= mbrlen (f
+ len
, (size_t) -1, &mbstate
);
527 if (bytes
== (size_t) -2 || bytes
== (size_t) -1)
535 while (! mbsinit (&mbstate
));
542 #else /* ! DO_MULTIBYTE */
544 /* Either multibyte encodings are not supported, or they are
545 safe for formats, so any non-'%' byte can be copied through. */
552 #endif /* ! DO_MULTIBYTE */
554 /* Check for flags that can modify a format. */
560 /* This influences the number formats. */
567 /* This changes textual output. */
581 /* As a GNU extension we allow to specify the field width. */
591 while (ISDIGIT (*f
));
594 /* Check for modifiers. */
607 /* Now do the specified format. */
610 #define DO_NUMBER(d, v) \
611 digits = width == -1 ? d : width; \
612 number_value = v; goto do_number
613 #define DO_NUMBER_SPACEPAD(d, v) \
614 digits = width == -1 ? d : width; \
615 number_value = v; goto do_number_spacepad
631 cpy (aw_len
, a_wkday
);
642 cpy (wkday_len
, f_wkday
);
646 case 'h': /* POSIX.2 extension. */
649 cpy (am_len
, a_month
);
660 cpy (month_len
, f_month
);
667 if (! (modifier
== 'E'
668 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_D_T_FMT
)) != '\0'))
669 subfmt
= _NL_CURRENT (LC_TIME
, D_T_FMT
);
671 subfmt
= "%a %b %e %H:%M:%S %Y";
677 size_t len
= strftime (NULL
, maxsize
- i
, subfmt
, tp
);
678 if (len
== 0 && *subfmt
)
680 add (len
, strftime (p
, maxsize
- i
, subfmt
, tp
));
683 while (old_start
< p
)
685 *old_start
= TOUPPER (*old_start
);
691 case 'C': /* POSIX.2 extension. */
694 #if HAVE_STRUCT_ERA_ENTRY
697 struct era_entry
*era
= _nl_get_era_entry (tp
);
700 size_t len
= strlen (era
->name_fmt
);
701 cpy (len
, era
->name_fmt
);
707 int year
= tp
->tm_year
+ TM_YEAR_BASE
;
708 DO_NUMBER (1, year
/ 100 - (year
% 100 < 0));
715 if (! (modifier
== 'E'
716 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_D_FMT
)) != '\0'))
717 subfmt
= _NL_CURRENT (LC_TIME
, D_FMT
);
721 case 'D': /* POSIX.2 extension. */
731 DO_NUMBER (2, tp
->tm_mday
);
733 case 'e': /* POSIX.2 extension. */
737 DO_NUMBER_SPACEPAD (2, tp
->tm_mday
);
739 /* All numeric formats set DIGITS and NUMBER_VALUE and then
740 jump to one of these two labels. */
743 /* Force `_' flag unless overwritten by `0' flag. */
748 /* Format the number according to the MODIFIER flag. */
751 if (modifier
== 'O' && 0 <= number_value
)
753 /* Get the locale specific alternate representation of
754 the number NUMBER_VALUE. If none exist NULL is returned. */
755 const char *cp
= _nl_get_alt_digit (number_value
);
759 size_t digitlen
= strlen (cp
);
769 unsigned int u
= number_value
;
771 bufp
= buf
+ sizeof (buf
);
772 negative_number
= number_value
< 0;
778 *--bufp
= u
% 10 + '0';
779 while ((u
/= 10) != 0);
782 do_number_sign_and_padding
:
788 int padding
= digits
- (buf
+ sizeof (buf
) - bufp
);
792 while (0 < padding
--)
797 bufp
+= negative_number
;
798 while (0 < padding
--)
805 cpy (buf
+ sizeof (buf
) - bufp
, bufp
);
813 DO_NUMBER (2, tp
->tm_hour
);
819 DO_NUMBER (2, hour12
);
821 case 'k': /* GNU extension. */
825 DO_NUMBER_SPACEPAD (2, tp
->tm_hour
);
827 case 'l': /* GNU extension. */
831 DO_NUMBER_SPACEPAD (2, hour12
);
837 DO_NUMBER (3, 1 + tp
->tm_yday
);
843 DO_NUMBER (2, tp
->tm_min
);
849 DO_NUMBER (2, tp
->tm_mon
+ 1);
851 case 'n': /* POSIX.2 extension. */
868 case 'R': /* GNU extension. */
872 case 'r': /* POSIX.2 extension. */
874 if (*(subfmt
= _NL_CURRENT (LC_TIME
, T_FMT_AMPM
)) == '\0')
876 subfmt
= "%I:%M:%S %p";
883 DO_NUMBER (2, tp
->tm_sec
);
885 case 's': /* GNU extension. */
893 /* Generate string value for T using time_t arithmetic;
894 this works even if sizeof (long) < sizeof (time_t). */
896 bufp
= buf
+ sizeof (buf
);
897 negative_number
= t
< 0;
908 /* Adjust if division truncates to minus infinity. */
909 if (0 < -1 % 10 && d
< 0)
921 goto do_number_sign_and_padding
;
928 if (! (modifier
== 'E'
929 && *(subfmt
= _NL_CURRENT (LC_TIME
, ERA_T_FMT
)) != '\0'))
930 subfmt
= _NL_CURRENT (LC_TIME
, T_FMT
);
934 case 'T': /* POSIX.2 extension. */
938 case 't': /* POSIX.2 extension. */
942 case 'u': /* POSIX.2 extension. */
943 DO_NUMBER (1, (tp
->tm_wday
- 1 + 7) % 7 + 1);
949 DO_NUMBER (2, (tp
->tm_yday
- tp
->tm_wday
+ 7) / 7);
952 case 'g': /* GNU extension. */
953 case 'G': /* GNU extension. */
957 int year
= tp
->tm_year
+ TM_YEAR_BASE
;
958 int days
= iso_week_days (tp
->tm_yday
, tp
->tm_wday
);
962 /* This ISO week belongs to the previous year. */
964 days
= iso_week_days (tp
->tm_yday
+ (365 + __isleap (year
)),
969 int d
= iso_week_days (tp
->tm_yday
- (365 + __isleap (year
)),
973 /* This ISO week belongs to the next year. */
982 DO_NUMBER (2, (year
% 100 + 100) % 100);
988 DO_NUMBER (2, days
/ 7 + 1);
996 DO_NUMBER (2, (tp
->tm_yday
- (tp
->tm_wday
- 1 + 7) % 7 + 7) / 7);
1002 DO_NUMBER (1, tp
->tm_wday
);
1005 #if HAVE_STRUCT_ERA_ENTRY
1006 if (modifier
== 'E')
1008 struct era_entry
*era
= _nl_get_era_entry (tp
);
1011 subfmt
= strchr (era
->name_fmt
, '\0') + 1;
1016 if (modifier
== 'O')
1019 DO_NUMBER (1, tp
->tm_year
+ TM_YEAR_BASE
);
1022 #if HAVE_STRUCT_ERA_ENTRY
1023 if (modifier
== 'E')
1025 struct era_entry
*era
= _nl_get_era_entry (tp
);
1028 int delta
= tp
->tm_year
- era
->start_date
[0];
1029 DO_NUMBER (1, (era
->offset
1030 + (era
->direction
== '-' ? -delta
: delta
)));
1034 DO_NUMBER (2, (tp
->tm_year
% 100 + 100) % 100);
1042 cpy (zonelen
, zone
);
1045 case 'z': /* GNU extension. */
1046 if (tp
->tm_isdst
< 0)
1052 diff
= tp
->tm_gmtoff
;
1061 if (lt
== (time_t) -1)
1063 /* mktime returns -1 for errors, but -1 is also a
1064 valid time_t value. Check whether an error really
1067 localtime_r (<
, &tm
);
1069 if ((ltm
.tm_sec
^ tm
.tm_sec
)
1070 | (ltm
.tm_min
^ tm
.tm_min
)
1071 | (ltm
.tm_hour
^ tm
.tm_hour
)
1072 | (ltm
.tm_mday
^ tm
.tm_mday
)
1073 | (ltm
.tm_mon
^ tm
.tm_mon
)
1074 | (ltm
.tm_year
^ tm
.tm_year
))
1078 if (! gmtime_r (<
, >m
))
1081 diff
= tm_diff (<m
, >m
);
1093 DO_NUMBER (4, (diff
/ 60) * 100 + diff
% 60);
1096 case '\0': /* GNU extension: % at end of format. */
1100 /* Unknown format; output the format, including the '%',
1101 since this is most likely the right thing to do if a
1102 multibyte string has been misparsed. */
1106 for (flen
= 1; f
[1 - flen
] != '%'; flen
++)
1108 cpy (flen
, &f
[1 - flen
]);