1 /* Copyright (C) 1991,92,93,94,95,96,97,98,99,2000,2003
2 Free Software Foundation, Inc.
4 NOTE: The canonical source of this file is maintained with gnulib.
5 Bugs can be reported to bug-gnulib@gnu.org.
7 This file is part of the GNU Emacs.
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public License
11 as published by the Free Software Foundation; either version 2, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Library General Public License for more details.
19 You should have received a copy of the GNU Library General Public
20 License along with the GNU C Library; see the file COPYING.LIB. If not,
21 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
29 # define HAVE_LIMITS_H 1
31 # define HAVE_MBRLEN 1
32 # define HAVE_STRUCT_ERA_ENTRY 1
33 # define HAVE_TM_GMTOFF 1
34 # define HAVE_TM_ZONE 1
35 # define HAVE_TZNAME 1
37 # define MULTIBYTE_IS_FORMAT_SAFE 1
38 # define STDC_HEADERS 1
39 # include "../locale/localeinfo.h"
43 #include <sys/types.h> /* Some systems define `time_t' here. */
45 #ifdef TIME_WITH_SYS_TIME
46 # include <sys/time.h>
49 # ifdef HAVE_SYS_TIME_H
50 # include <sys/time.h>
57 extern char *tzname
[];
61 /* Do multibyte processing if multibytes are supported, unless
62 multibyte sequences are safe in formats. Multibyte sequences are
63 safe if they cannot contain byte sequences that look like format
64 conversion specifications. The GNU C Library uses UTF8 multibyte
65 encoding, which is safe for formats, but strftime.c can be used
66 with other C libraries that use unsafe encodings. */
67 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
72 # ifdef HAVE_SYS__MBSTATE_H /* previously tested __hpux */
73 # include <sys/_mbstate_t.h>
75 # if !defined (mbsinit) && !defined (HAVE_MBSINIT)
76 # define mbsinit(ps) 1
77 # endif /* !defined (mbsinit) && !defined (HAVE_MBSINIT) */
79 /* Simulate mbrlen with mblen as best we can. */
80 # define mbstate_t int
81 # define mbrlen(s, n, ps) mblen (s, n)
82 # define mbsinit(ps) (*(ps) == 0)
84 static const mbstate_t mbstate_zero
;
97 # define memcpy(d, s, n) bcopy ((s), (d), (n))
103 # define CHAR_T wchar_t
104 # define UCHAR_T unsigned int
105 # define L_(Str) L##Str
106 # define NLW(Sym) _NL_W##Sym
108 # define MEMCPY(d, s, n) __wmemcpy (d, s, n)
109 # define STRLEN(s) __wcslen (s)
113 # define UCHAR_T unsigned char
115 # define NLW(Sym) Sym
117 # if !defined STDC_HEADERS && !defined HAVE_MEMCPY
118 # define MEMCPY(d, s, n) bcopy ((s), (d), (n))
120 # define MEMCPY(d, s, n) memcpy ((d), (s), (n))
122 # define STRLEN(s) strlen (s)
125 # define MEMPCPY(d, s, n) __mempcpy (d, s, n)
127 # ifndef HAVE_MEMPCPY
128 # define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
134 # if defined __GNUC__ || (defined __STDC__ && __STDC__) || defined (PROTOTYPES)
135 # define __P(args) args
137 # define __P(args) ()
139 #endif /* Not __P. */
157 #define TYPE_SIGNED(t) ((t) -1 < 0)
159 /* Bound on length of the string representing an integer value of type t.
160 Subtract one for the sign bit if t is signed;
161 302 / 1000 is log10 (2) rounded up;
162 add one for integer division truncation;
163 add one more for a minus sign if t is signed. */
164 #define INT_STRLEN_BOUND(t) \
165 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t))
167 #define TM_YEAR_BASE 1900
170 /* Nonzero if YEAR is a leap year (every 4 years,
171 except every 100th isn't, and every 400th is). */
172 # define __isleap(year) \
173 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
178 # define my_strftime_gmtime_r __gmtime_r
179 # define my_strftime_localtime_r __localtime_r
180 # define tzname __tzname
181 # define tzset __tzset
184 /* If we're a strftime substitute in a GNU program, then prefer gmtime
185 to gmtime_r, since many gmtime_r implementations are buggy.
186 Similarly for localtime_r. */
188 # if ! HAVE_TM_GMTOFF
189 static struct tm
*my_strftime_gmtime_r
__P ((const time_t *, struct tm
*));
191 my_strftime_gmtime_r (t
, tp
)
195 struct tm
*l
= gmtime (t
);
202 static struct tm
*my_strftime_localtime_r
__P ((const time_t *, struct tm
*));
204 my_strftime_localtime_r (t
, tp
)
208 struct tm
*l
= localtime (t
);
214 # endif /* ! HAVE_TM_GMTOFF */
215 #endif /* ! defined _LIBC */
218 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
219 /* Some systems lack the `memset' function and we don't want to
220 introduce additional dependencies. */
221 /* The SGI compiler reportedly barfs on the trailing null
222 if we use a string constant as the initializer. 28 June 1997, rms. */
223 static const CHAR_T spaces
[16] = /* " " */
225 L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),
226 L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' ')
228 static const CHAR_T zeroes
[16] = /* "0000000000000000" */
230 L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),
231 L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0')
234 # define memset_space(P, Len) \
240 int _this = _len > 16 ? 16 : _len; \
241 (P) = MEMPCPY ((P), spaces, _this * sizeof (CHAR_T)); \
247 # define memset_zero(P, Len) \
253 int _this = _len > 16 ? 16 : _len; \
254 (P) = MEMPCPY ((P), zeroes, _this * sizeof (CHAR_T)); \
261 # define memset_space(P, Len) (wmemset ((P), L' ', (Len)), (P) += (Len))
262 # define memset_zero(P, Len) (wmemset ((P), L'0', (Len)), (P) += (Len))
264 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
265 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
273 int _delta = width - _n; \
274 int _incr = _n + (_delta > 0 ? _delta : 0); \
275 if ((size_t) _incr >= maxsize - i) \
281 if (pad == L_('0')) \
282 memset_zero (p, _delta); \
284 memset_space (p, _delta); \
295 memcpy_lowcase (p, (s), _n LOCALE_ARG); \
296 else if (to_uppcase) \
297 memcpy_uppcase (p, (s), _n LOCALE_ARG); \
299 MEMCPY ((PTR) p, (const PTR) (s), _n))
302 # ifndef USE_IN_EXTENDED_LOCALE_MODEL
303 # undef __mbsrtowcs_l
304 # define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
306 # define widen(os, ws, l) \
309 const char *__s = os; \
310 memset (&__st, '\0', sizeof (__st)); \
311 l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc); \
312 ws = (wchar_t *) alloca ((l + 1) * sizeof (wchar_t)); \
313 (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc); \
318 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
319 /* We use this code also for the extended locale handling where the
320 function gets as an additional argument the locale which has to be
321 used. To access the values we have to redefine the _NL_CURRENT
323 # define strftime __strftime_l
324 # define wcsftime __wcsftime_l
326 # define _NL_CURRENT(category, item) \
327 (current->values[_NL_ITEM_INDEX (item)].string)
328 # define LOCALE_PARAM , loc
329 # define LOCALE_ARG , loc
330 # define LOCALE_PARAM_DECL __locale_t loc;
331 # define LOCALE_PARAM_PROTO , __locale_t loc
332 # define HELPER_LOCALE_ARG , current
334 # define LOCALE_PARAM
335 # define LOCALE_PARAM_PROTO
337 # define LOCALE_PARAM_DECL
339 # define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
341 # define HELPER_LOCALE_ARG
346 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
347 # define TOUPPER(Ch, L) __towupper_l (Ch, L)
348 # define TOLOWER(Ch, L) __towlower_l (Ch, L)
350 # define TOUPPER(Ch, L) towupper (Ch)
351 # define TOLOWER(Ch, L) towlower (Ch)
355 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
356 # define TOUPPER(Ch, L) __toupper_l (Ch, L)
357 # define TOLOWER(Ch, L) __tolower_l (Ch, L)
359 # define TOUPPER(Ch, L) toupper (Ch)
360 # define TOLOWER(Ch, L) tolower (Ch)
363 # define TOUPPER(Ch, L) (islower (Ch) ? toupper (Ch) : (Ch))
364 # define TOLOWER(Ch, L) (isupper (Ch) ? tolower (Ch) : (Ch))
367 /* We don't use `isdigit' here since the locale dependent
368 interpretation is not what we want here. We only need to accept
369 the arabic digits in the ASCII range. One day there is perhaps a
370 more reliable way to accept other sets of digits. */
371 #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
373 static CHAR_T
*memcpy_lowcase
__P ((CHAR_T
*dest
, const CHAR_T
*src
,
374 size_t len LOCALE_PARAM_PROTO
));
377 memcpy_lowcase (dest
, src
, len LOCALE_PARAM
)
384 dest
[len
] = TOLOWER ((UCHAR_T
) src
[len
], loc
);
388 static CHAR_T
*memcpy_uppcase
__P ((CHAR_T
*dest
, const CHAR_T
*src
,
389 size_t len LOCALE_PARAM_PROTO
));
392 memcpy_uppcase (dest
, src
, len LOCALE_PARAM
)
399 dest
[len
] = TOUPPER ((UCHAR_T
) src
[len
], loc
);
405 /* Yield the difference between *A and *B,
406 measured in seconds, ignoring leap seconds. */
407 # define tm_diff ftime_tm_diff
408 static int tm_diff
__P ((const struct tm
*, const struct tm
*));
414 /* Compute intervening leap days correctly even if year is negative.
415 Take care to avoid int overflow in leap day calculations,
416 but it's OK to assume that A and B are close to each other. */
417 int a4
= (a
->tm_year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (a
->tm_year
& 3);
418 int b4
= (b
->tm_year
>> 2) + (TM_YEAR_BASE
>> 2) - ! (b
->tm_year
& 3);
419 int a100
= a4
/ 25 - (a4
% 25 < 0);
420 int b100
= b4
/ 25 - (b4
% 25 < 0);
421 int a400
= a100
>> 2;
422 int b400
= b100
>> 2;
423 int intervening_leap_days
= (a4
- b4
) - (a100
- b100
) + (a400
- b400
);
424 int years
= a
->tm_year
- b
->tm_year
;
425 int days
= (365 * years
+ intervening_leap_days
426 + (a
->tm_yday
- b
->tm_yday
));
427 return (60 * (60 * (24 * days
+ (a
->tm_hour
- b
->tm_hour
))
428 + (a
->tm_min
- b
->tm_min
))
429 + (a
->tm_sec
- b
->tm_sec
));
431 #endif /* ! HAVE_TM_GMTOFF */
435 /* The number of days from the first day of the first ISO week of this
436 year to the year day YDAY with week day WDAY. ISO weeks start on
437 Monday; the first ISO week has the year's first Thursday. YDAY may
438 be as small as YDAY_MINIMUM. */
439 #define ISO_WEEK_START_WDAY 1 /* Monday */
440 #define ISO_WEEK1_WDAY 4 /* Thursday */
441 #define YDAY_MINIMUM (-366)
442 static int iso_week_days
__P ((int, int));
447 iso_week_days (yday
, wday
)
451 /* Add enough to the first operand of % to make it nonnegative. */
452 int big_enough_multiple_of_7
= (-YDAY_MINIMUM
/ 7 + 2) * 7;
454 - (yday
- wday
+ ISO_WEEK1_WDAY
+ big_enough_multiple_of_7
) % 7
455 + ISO_WEEK1_WDAY
- ISO_WEEK_START_WDAY
);
459 #if !(defined _NL_CURRENT || HAVE_STRFTIME)
460 static CHAR_T
const weekday_name
[][10] =
462 L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
463 L_("Thursday"), L_("Friday"), L_("Saturday")
465 static CHAR_T
const month_name
[][10] =
467 L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
468 L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
469 L_("November"), L_("December")
474 /* When compiling this file, GNU applications can #define my_strftime
475 to a symbol (typically nstrftime) to get an extended strftime with
476 extra arguments UT and NS. */
479 # define extra_args , ut, ns
480 # define extra_args_spec int ut; int ns;
481 # define extra_args_spec_iso , int ut, int ns
484 # define my_strftime wcsftime
485 # define nl_get_alt_digit _nl_get_walt_digit
487 # define my_strftime strftime
488 # define nl_get_alt_digit _nl_get_alt_digit
491 # define extra_args_spec
492 # define extra_args_spec_iso
493 /* We don't have this information in general. */
498 #if !defined _LIBC && !defined(WINDOWSNT) && HAVE_TZNAME && HAVE_TZSET
499 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
500 Work around this bug by copying *tp before it might be munged. */
501 size_t _strftime_copytm
__P ((char *, size_t, const char *,
502 const struct tm
* extra_args_spec_iso
));
504 my_strftime (s
, maxsize
, format
, tp extra_args
)
507 const CHAR_T
*format
;
513 return _strftime_copytm (s
, maxsize
, format
, &tmcopy extra_args
);
516 # define my_strftime _strftime_copytm
520 /* Write information from TP into S according to the format
521 string FORMAT, writing no more that MAXSIZE characters
522 (including the terminating '\0') and returning number of
523 characters written. If S is NULL, nothing will be written
524 anywhere, so to determine how many characters would be
525 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
527 my_strftime (s
, maxsize
, format
, tp extra_args LOCALE_PARAM
)
530 const CHAR_T
*format
;
535 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
536 struct locale_data
*const current
= loc
->__locales
[LC_TIME
];
539 int hour12
= tp
->tm_hour
;
541 /* We cannot make the following values variables since we must delay
542 the evaluation of these values until really needed since some
543 expressions might not be valid in every situation. The `struct tm'
544 might be generated by a strptime() call that initialized
545 only a few elements. Dereference the pointers only if the format
546 requires this. Then it is ok to fail if the pointers are invalid. */
548 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
550 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
552 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
554 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
556 ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
557 ? NLW(PM_STR) : NLW(AM_STR)))
559 # define aw_len STRLEN (a_wkday)
560 # define am_len STRLEN (a_month)
561 # define ap_len STRLEN (ampm)
564 # define f_wkday (weekday_name[tp->tm_wday])
565 # define f_month (month_name[tp->tm_mon])
566 # define a_wkday f_wkday
567 # define a_month f_month
568 # define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
579 #if DO_MULTIBYTE && !defined COMPILE_WIDE
580 const char *format_end
= NULL
;
585 /* The POSIX test suite assumes that setting
586 the environment variable TZ to a new value before calling strftime()
587 will influence the result (the %Z format) even if the information in
588 TP is computed with a totally different time zone.
589 This is bogus: though POSIX allows bad behavior like this,
590 POSIX does not require it. Do the right thing instead. */
591 zone
= (const char *) tp
->tm_zone
;
596 if (! (zone
&& *zone
))
601 /* POSIX.1 requires that local time zone information be used as
602 though strftime called tzset. */
615 for (f
= format
; *f
!= '\0'; ++f
)
617 int pad
= 0; /* Padding for number ('-', '_', or 0). */
618 int modifier
; /* Field modifier ('E', 'O', or 0). */
619 int digits
; /* Max digits for numeric format. */
620 int number_value
; /* Numeric value to be printed. */
621 int negative_number
; /* 1 if the number is negative. */
622 const CHAR_T
*subfmt
;
624 CHAR_T buf
[1 + (sizeof (int) < sizeof (time_t)
625 ? INT_STRLEN_BOUND (time_t)
626 : INT_STRLEN_BOUND (int))];
633 #if DO_MULTIBYTE && !defined COMPILE_WIDE
639 case L_('\b'): case L_('\t'): case L_('\n'):
640 case L_('\v'): case L_('\f'): case L_('\r'):
641 case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
642 case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
643 case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
644 case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
645 case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
646 case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
647 case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
648 case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
649 case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
650 case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
651 case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
652 case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
653 case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
654 case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
655 case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
656 case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
657 case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
658 case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
660 /* The C Standard requires these 98 characters (plus '%') to
661 be in the basic execution character set. None of these
662 characters can start a multibyte sequence, so they need
663 not be analyzed further. */
668 /* Copy this multibyte sequence until we reach its end, find
669 an error, or come back to the initial shift state. */
671 mbstate_t mbstate
= mbstate_zero
;
676 format_end
= f
+ strlen (f
) + 1;
677 fsize
= format_end
- f
;
681 size_t bytes
= mbrlen (f
+ len
, fsize
- len
, &mbstate
);
686 if (bytes
== (size_t) -2)
688 len
+= strlen (f
+ len
);
692 if (bytes
== (size_t) -1)
700 while (! mbsinit (&mbstate
));
708 #else /* ! DO_MULTIBYTE */
710 /* Either multibyte encodings are not supported, they are
711 safe for formats, so any non-'%' byte can be copied through,
712 or this is the wide character version. */
719 #endif /* ! DO_MULTIBYTE */
721 /* Check for flags that can modify a format. */
726 /* This influences the number formats. */
733 /* This changes textual output. */
747 /* As a GNU extension we allow to specify the field width. */
753 if (width
> INT_MAX
/ 10
754 || (width
== INT_MAX
/ 10 && *f
- L_('0') > INT_MAX
% 10))
755 /* Avoid overflow. */
760 width
+= *f
- L_('0');
764 while (ISDIGIT (*f
));
767 /* Check for modifiers. */
780 /* Now do the specified format. */
784 #define DO_NUMBER(d, v) \
785 digits = d > width ? d : width; \
786 number_value = v; goto do_number
787 #define DO_NUMBER_SPACEPAD(d, v) \
788 digits = d > width ? d : width; \
789 number_value = v; goto do_number_spacepad
805 #if defined _NL_CURRENT || !HAVE_STRFTIME
806 cpy (aw_len
, a_wkday
);
809 goto underlying_strftime
;
820 #if defined _NL_CURRENT || !HAVE_STRFTIME
821 cpy (STRLEN (f_wkday
), f_wkday
);
824 goto underlying_strftime
;
836 #if defined _NL_CURRENT || !HAVE_STRFTIME
837 cpy (am_len
, a_month
);
840 goto underlying_strftime
;
851 #if defined _NL_CURRENT || !HAVE_STRFTIME
852 cpy (STRLEN (f_month
), f_month
);
855 goto underlying_strftime
;
859 if (modifier
== L_('O'))
862 if (! (modifier
== 'E'
864 (const CHAR_T
*) _NL_CURRENT (LC_TIME
,
867 subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(D_T_FMT
));
870 goto underlying_strftime
;
872 subfmt
= L_("%a %b %e %H:%M:%S %Y");
878 CHAR_T
*old_start
= p
;
879 size_t len
= my_strftime (NULL
, (size_t) -1, subfmt
,
880 tp extra_args LOCALE_ARG
);
881 add (len
, my_strftime (p
, maxsize
- i
, subfmt
,
882 tp extra_args LOCALE_ARG
));
885 while (old_start
< p
)
887 *old_start
= TOUPPER ((UCHAR_T
) *old_start
, loc
);
893 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
896 /* The relevant information is available only via the
897 underlying strftime implementation, so use that. */
900 char ubuf
[1024]; /* enough for any single format in practice */
902 /* Make sure we're calling the actual underlying strftime.
903 In some cases, config.h contains something like
904 "#define strftime rpl_strftime". */
910 #ifdef STRFTIME_NO_POSIX2
911 /* Some system libraries do not support the POSIX.2 extensions.
912 In those cases, convert %h to %b, and strip modifiers. */
914 if (format_char
== 'h')
922 len
= strftime (ubuf
, sizeof ubuf
, ufmt
, tp
);
923 if (len
== 0 && ubuf
[0] != '\0')
931 if (modifier
== L_('O'))
933 if (modifier
== L_('E'))
935 #if HAVE_STRUCT_ERA_ENTRY
936 struct era_entry
*era
= _nl_get_era_entry (tp HELPER_LOCALE_ARG
);
940 size_t len
= __wcslen (era
->era_wname
);
941 cpy (len
, era
->era_wname
);
943 size_t len
= strlen (era
->era_name
);
944 cpy (len
, era
->era_name
);
950 goto underlying_strftime
;
956 int year
= tp
->tm_year
+ TM_YEAR_BASE
;
957 DO_NUMBER (1, year
/ 100 - (year
% 100 < 0));
961 if (modifier
== L_('O'))
964 if (! (modifier
== L_('E')
966 (const CHAR_T
*)_NL_CURRENT (LC_TIME
, NLW(ERA_D_FMT
)))
968 subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(D_FMT
));
972 goto underlying_strftime
;
980 subfmt
= L_("%m/%d/%y");
984 if (modifier
== L_('E'))
987 DO_NUMBER (2, tp
->tm_mday
);
990 if (modifier
== L_('E'))
993 DO_NUMBER_SPACEPAD (2, tp
->tm_mday
);
995 /* All numeric formats set DIGITS and NUMBER_VALUE and then
996 jump to one of these two labels. */
999 /* Force `_' flag unless overridden by `0' or `-' flag. */
1000 if (pad
!= L_('0') && pad
!= L_('-'))
1004 /* Format the number according to the MODIFIER flag. */
1006 if (modifier
== L_('O') && 0 <= number_value
)
1009 /* Get the locale specific alternate representation of
1010 the number NUMBER_VALUE. If none exist NULL is returned. */
1011 const CHAR_T
*cp
= nl_get_alt_digit (number_value
1016 size_t digitlen
= STRLEN (cp
);
1025 goto underlying_strftime
;
1030 unsigned int u
= number_value
;
1032 bufp
= buf
+ sizeof (buf
) / sizeof (buf
[0]);
1033 negative_number
= number_value
< 0;
1035 if (negative_number
)
1039 *--bufp
= u
% 10 + L_('0');
1040 while ((u
/= 10) != 0);
1043 do_number_sign_and_padding
:
1044 if (negative_number
)
1049 int padding
= digits
- (buf
+ (sizeof (buf
) / sizeof (buf
[0]))
1056 if ((size_t) padding
>= maxsize
- i
)
1060 memset_space (p
, padding
);
1062 width
= width
> padding
? width
- padding
: 0;
1066 if ((size_t) digits
>= maxsize
- i
)
1069 if (negative_number
)
1079 memset_zero (p
, padding
);
1086 cpy (buf
+ sizeof (buf
) / sizeof (buf
[0]) - bufp
, bufp
);
1092 subfmt
= L_("%Y-%m-%d");
1096 if (modifier
== L_('E'))
1099 DO_NUMBER (2, tp
->tm_hour
);
1102 if (modifier
== L_('E'))
1105 DO_NUMBER (2, hour12
);
1107 case L_('k'): /* GNU extension. */
1108 if (modifier
== L_('E'))
1111 DO_NUMBER_SPACEPAD (2, tp
->tm_hour
);
1113 case L_('l'): /* GNU extension. */
1114 if (modifier
== L_('E'))
1117 DO_NUMBER_SPACEPAD (2, hour12
);
1120 if (modifier
== L_('E'))
1123 DO_NUMBER (3, 1 + tp
->tm_yday
);
1126 if (modifier
== L_('E'))
1129 DO_NUMBER (2, tp
->tm_min
);
1132 if (modifier
== L_('E'))
1135 DO_NUMBER (2, tp
->tm_mon
+ 1);
1138 case L_('N'): /* GNU extension. */
1139 if (modifier
== L_('E'))
1145 /* Take an explicit width less than 9 as a precision. */
1147 for (j
= width
; j
< 9; j
++)
1151 DO_NUMBER (9, number_value
);
1155 add (1, *p
= L_('\n'));
1160 #if !defined _NL_CURRENT && HAVE_STRFTIME
1161 format_char
= L_('p');
1171 #if defined _NL_CURRENT || !HAVE_STRFTIME
1175 goto underlying_strftime
;
1179 subfmt
= L_("%H:%M");
1184 if (*(subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
,
1188 subfmt
= L_("%I:%M:%S %p");
1192 if (modifier
== L_('E'))
1195 DO_NUMBER (2, tp
->tm_sec
);
1197 case L_('s'): /* GNU extension. */
1205 /* Generate string value for T using time_t arithmetic;
1206 this works even if sizeof (long) < sizeof (time_t). */
1208 bufp
= buf
+ sizeof (buf
) / sizeof (buf
[0]);
1209 negative_number
= t
< 0;
1216 if (negative_number
)
1220 /* Adjust if division truncates to minus infinity. */
1221 if (0 < -1 % 10 && d
< 0)
1228 *--bufp
= d
+ L_('0');
1233 goto do_number_sign_and_padding
;
1237 if (modifier
== L_('O'))
1240 if (! (modifier
== L_('E')
1242 (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(ERA_T_FMT
)))
1244 subfmt
= (const CHAR_T
*) _NL_CURRENT (LC_TIME
, NLW(T_FMT
));
1248 goto underlying_strftime
;
1254 subfmt
= L_("%H:%M:%S");
1258 add (1, *p
= L_('\t'));
1262 DO_NUMBER (1, (tp
->tm_wday
- 1 + 7) % 7 + 1);
1265 if (modifier
== L_('E'))
1268 DO_NUMBER (2, (tp
->tm_yday
- tp
->tm_wday
+ 7) / 7);
1273 if (modifier
== L_('E'))
1276 int year
= tp
->tm_year
+ TM_YEAR_BASE
;
1277 int days
= iso_week_days (tp
->tm_yday
, tp
->tm_wday
);
1281 /* This ISO week belongs to the previous year. */
1283 days
= iso_week_days (tp
->tm_yday
+ (365 + __isleap (year
)),
1288 int d
= iso_week_days (tp
->tm_yday
- (365 + __isleap (year
)),
1292 /* This ISO week belongs to the next year. */
1301 DO_NUMBER (2, (year
% 100 + 100) % 100);
1304 DO_NUMBER (1, year
);
1307 DO_NUMBER (2, days
/ 7 + 1);
1312 if (modifier
== L_('E'))
1315 DO_NUMBER (2, (tp
->tm_yday
- (tp
->tm_wday
- 1 + 7) % 7 + 7) / 7);
1318 if (modifier
== L_('E'))
1321 DO_NUMBER (1, tp
->tm_wday
);
1324 if (modifier
== 'E')
1326 #if HAVE_STRUCT_ERA_ENTRY
1327 struct era_entry
*era
= _nl_get_era_entry (tp HELPER_LOCALE_ARG
);
1330 # ifdef COMPILE_WIDE
1331 subfmt
= era
->era_wformat
;
1333 subfmt
= era
->era_format
;
1339 goto underlying_strftime
;
1343 if (modifier
== L_('O'))
1346 DO_NUMBER (1, tp
->tm_year
+ TM_YEAR_BASE
);
1349 if (modifier
== L_('E'))
1351 #if HAVE_STRUCT_ERA_ENTRY
1352 struct era_entry
*era
= _nl_get_era_entry (tp HELPER_LOCALE_ARG
);
1355 int delta
= tp
->tm_year
- era
->start_date
[0];
1356 DO_NUMBER (1, (era
->offset
1357 + delta
* era
->absolute_direction
));
1361 goto underlying_strftime
;
1365 DO_NUMBER (2, (tp
->tm_year
% 100 + 100) % 100);
1375 /* The tzset() call might have changed the value. */
1376 if (!(zone
&& *zone
) && tp
->tm_isdst
>= 0)
1377 zone
= tzname
[tp
->tm_isdst
];
1384 /* The zone string is always given in multibyte form. We have
1385 to transform it first. */
1388 widen (zone
, wczone
, len
);
1392 cpy (strlen (zone
), zone
);
1397 if (tp
->tm_isdst
< 0)
1403 diff
= tp
->tm_gmtoff
;
1416 if (lt
== (time_t) -1)
1418 /* mktime returns -1 for errors, but -1 is also a
1419 valid time_t value. Check whether an error really
1423 if (! my_strftime_localtime_r (<
, &tm
)
1424 || ((ltm
.tm_sec
^ tm
.tm_sec
)
1425 | (ltm
.tm_min
^ tm
.tm_min
)
1426 | (ltm
.tm_hour
^ tm
.tm_hour
)
1427 | (ltm
.tm_mday
^ tm
.tm_mday
)
1428 | (ltm
.tm_mon
^ tm
.tm_mon
)
1429 | (ltm
.tm_year
^ tm
.tm_year
)))
1433 if (! my_strftime_gmtime_r (<
, >m
))
1436 diff
= tm_diff (<m
, >m
);
1442 add (1, *p
= L_('-'));
1446 add (1, *p
= L_('+'));
1449 DO_NUMBER (4, (diff
/ 60) * 100 + diff
% 60);
1452 case L_('\0'): /* GNU extension: % at end of format. */
1456 /* Unknown format; output the format, including the '%',
1457 since this is most likely the right thing to do if a
1458 multibyte string has been misparsed. */
1462 for (flen
= 1; f
[1 - flen
] != L_('%'); flen
++)
1464 cpy (flen
, &f
[1 - flen
]);
1470 if (p
&& maxsize
!= 0)
1475 libc_hidden_def (my_strftime
)
1481 /* For Emacs we have a separate interface which corresponds to the normal
1482 strftime function plus the ut argument, but without the ns argument. */
1484 emacs_strftimeu (s
, maxsize
, format
, tp
, ut
)
1488 const struct tm
*tp
;
1491 return my_strftime (s
, maxsize
, format
, tp
, ut
, 0);
1495 /* arch-tag: 662bc9c4-f8e2-41b6-bf96-b8346d0ce0d8
1496 (do not change this comment) */