file tst-timer.c was initially added on branch fedora-branch.
[glibc/history.git] / time / strftime_l.c
blob0fd3f7764fe344708e4bc54e550902f7aaa124ff
1 /* Copyright (C) 2002, 2004 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 Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the 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 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307 USA. */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #ifdef _LIBC
24 # define USE_IN_EXTENDED_LOCALE_MODEL 1
25 # define HAVE_LIMITS_H 1
26 # define HAVE_MBLEN 1
27 # define HAVE_MBRLEN 1
28 # define HAVE_STRUCT_ERA_ENTRY 1
29 # define HAVE_TM_GMTOFF 1
30 # define HAVE_TM_ZONE 1
31 # define HAVE_TZNAME 1
32 # define HAVE_TZSET 1
33 # define MULTIBYTE_IS_FORMAT_SAFE 1
34 # define STDC_HEADERS 1
35 # include "../locale/localeinfo.h"
36 #endif
38 #if defined emacs && !defined HAVE_BCOPY
39 # define HAVE_MEMCPY 1
40 #endif
42 #include <ctype.h>
43 #include <sys/types.h> /* Some systems define `time_t' here. */
45 #ifdef TIME_WITH_SYS_TIME
46 # include <sys/time.h>
47 # include <time.h>
48 #else
49 # ifdef HAVE_SYS_TIME_H
50 # include <sys/time.h>
51 # else
52 # include <time.h>
53 # endif
54 #endif
55 #if HAVE_TZNAME
56 extern char *tzname[];
57 #endif
59 /* Do multibyte processing if multibytes are supported, unless
60 multibyte sequences are safe in formats. Multibyte sequences are
61 safe if they cannot contain byte sequences that look like format
62 conversion specifications. The GNU C Library uses UTF8 multibyte
63 encoding, which is safe for formats, but strftime.c can be used
64 with other C libraries that use unsafe encodings. */
65 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
67 #if DO_MULTIBYTE
68 # if HAVE_MBRLEN
69 # include <wchar.h>
70 # else
71 /* Simulate mbrlen with mblen as best we can. */
72 # define mbstate_t int
73 # define mbrlen(s, n, ps) mblen (s, n)
74 # define mbsinit(ps) (*(ps) == 0)
75 # endif
76 static const mbstate_t mbstate_zero;
77 #endif
79 #if HAVE_LIMITS_H
80 # include <limits.h>
81 #endif
83 #if STDC_HEADERS
84 # include <stddef.h>
85 # include <stdlib.h>
86 # include <string.h>
87 #else
88 # ifndef HAVE_MEMCPY
89 # define memcpy(d, s, n) bcopy ((s), (d), (n))
90 # endif
91 #endif
93 #ifdef COMPILE_WIDE
94 # include <endian.h>
95 # define CHAR_T wchar_t
96 # define UCHAR_T unsigned int
97 # define L_(Str) L##Str
98 # define NLW(Sym) _NL_W##Sym
100 # define MEMCPY(d, s, n) __wmemcpy (d, s, n)
101 # define STRLEN(s) __wcslen (s)
103 #else
104 # define CHAR_T char
105 # define UCHAR_T unsigned char
106 # define L_(Str) Str
107 # define NLW(Sym) Sym
109 # if !defined STDC_HEADERS && !defined HAVE_MEMCPY
110 # define MEMCPY(d, s, n) bcopy ((s), (d), (n))
111 # else
112 # define MEMCPY(d, s, n) memcpy ((d), (s), (n))
113 # endif
114 # define STRLEN(s) strlen (s)
116 # ifdef _LIBC
117 # define MEMPCPY(d, s, n) __mempcpy (d, s, n)
118 # else
119 # ifndef HAVE_MEMPCPY
120 # define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
121 # endif
122 # endif
123 #endif
125 #ifndef PTR
126 # ifdef __STDC__
127 # define PTR void *
128 # else
129 # define PTR char *
130 # endif
131 #endif
133 #ifndef CHAR_BIT
134 # define CHAR_BIT 8
135 #endif
137 #ifndef NULL
138 # define NULL 0
139 #endif
141 #define TYPE_SIGNED(t) ((t) -1 < 0)
143 /* Bound on length of the string representing an integer value of type t.
144 Subtract one for the sign bit if t is signed;
145 302 / 1000 is log10 (2) rounded up;
146 add one for integer division truncation;
147 add one more for a minus sign if t is signed. */
148 #define INT_STRLEN_BOUND(t) \
149 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t))
151 #define TM_YEAR_BASE 1900
153 #ifndef __isleap
154 /* Nonzero if YEAR is a leap year (every 4 years,
155 except every 100th isn't, and every 400th is). */
156 # define __isleap(year) \
157 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
158 #endif
161 #ifdef _LIBC
162 # define tzname __tzname
163 # define tzset __tzset
164 #endif
166 #if !HAVE_TM_GMTOFF
167 /* Portable standalone applications should supply a "time_r.h" that
168 declares a POSIX-compliant localtime_r, for the benefit of older
169 implementations that lack localtime_r or have a nonstandard one.
170 Similarly for gmtime_r. See the gnulib time_r module for one way
171 to implement this. */
172 # include "time_r.h"
173 # undef __gmtime_r
174 # undef __localtime_r
175 # define __gmtime_r gmtime_r
176 # define __localtime_r localtime_r
177 #endif
180 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
181 /* Some systems lack the `memset' function and we don't want to
182 introduce additional dependencies. */
183 /* The SGI compiler reportedly barfs on the trailing null
184 if we use a string constant as the initializer. 28 June 1997, rms. */
185 static const CHAR_T spaces[16] = /* " " */
187 L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),
188 L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' ')
190 static const CHAR_T zeroes[16] = /* "0000000000000000" */
192 L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),
193 L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0')
196 # define memset_space(P, Len) \
197 do { \
198 int _len = (Len); \
200 do \
202 int _this = _len > 16 ? 16 : _len; \
203 (P) = MEMPCPY ((P), spaces, _this * sizeof (CHAR_T)); \
204 _len -= _this; \
206 while (_len > 0); \
207 } while (0)
209 # define memset_zero(P, Len) \
210 do { \
211 int _len = (Len); \
213 do \
215 int _this = _len > 16 ? 16 : _len; \
216 (P) = MEMPCPY ((P), zeroes, _this * sizeof (CHAR_T)); \
217 _len -= _this; \
219 while (_len > 0); \
220 } while (0)
221 #else
222 # ifdef COMPILE_WIDE
223 # define memset_space(P, Len) (wmemset ((P), L' ', (Len)), (P) += (Len))
224 # define memset_zero(P, Len) (wmemset ((P), L'0', (Len)), (P) += (Len))
225 # else
226 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
227 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
228 # endif
229 #endif
231 #define add(n, f) \
232 do \
234 int _n = (n); \
235 int _delta = width - _n; \
236 int _incr = _n + (_delta > 0 ? _delta : 0); \
237 if ((size_t) _incr >= maxsize - i) \
238 return 0; \
239 if (p) \
241 if (_delta > 0) \
243 if (pad == L_('0')) \
244 memset_zero (p, _delta); \
245 else \
246 memset_space (p, _delta); \
248 f; \
249 p += _n; \
251 i += _incr; \
252 } while (0)
254 #define cpy(n, s) \
255 add ((n), \
256 if (to_lowcase) \
257 memcpy_lowcase (p, (s), _n LOCALE_ARG); \
258 else if (to_uppcase) \
259 memcpy_uppcase (p, (s), _n LOCALE_ARG); \
260 else \
261 MEMCPY ((PTR) p, (const PTR) (s), _n))
263 #ifdef COMPILE_WIDE
264 # ifndef USE_IN_EXTENDED_LOCALE_MODEL
265 # undef __mbsrtowcs_l
266 # define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
267 # endif
268 # define widen(os, ws, l) \
270 mbstate_t __st; \
271 const char *__s = os; \
272 memset (&__st, '\0', sizeof (__st)); \
273 l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc); \
274 ws = alloca ((l + 1) * sizeof (wchar_t)); \
275 (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc); \
277 #endif
280 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
281 /* We use this code also for the extended locale handling where the
282 function gets as an additional argument the locale which has to be
283 used. To access the values we have to redefine the _NL_CURRENT
284 macro. */
285 # define strftime __strftime_l
286 # define wcsftime __wcsftime_l
287 # undef _NL_CURRENT
288 # define _NL_CURRENT(category, item) \
289 (current->values[_NL_ITEM_INDEX (item)].string)
290 # define LOCALE_PARAM , loc
291 # define LOCALE_ARG , loc
292 # define LOCALE_PARAM_DECL __locale_t loc;
293 # define LOCALE_PARAM_PROTO , __locale_t loc
294 # define HELPER_LOCALE_ARG , current
295 #else
296 # define LOCALE_PARAM
297 # define LOCALE_PARAM_PROTO
298 # define LOCALE_ARG
299 # define LOCALE_PARAM_DECL
300 # ifdef _LIBC
301 # define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
302 # else
303 # define HELPER_LOCALE_ARG
304 # endif
305 #endif
307 #ifdef COMPILE_WIDE
308 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
309 # define TOUPPER(Ch, L) __towupper_l (Ch, L)
310 # define TOLOWER(Ch, L) __towlower_l (Ch, L)
311 # else
312 # define TOUPPER(Ch, L) towupper (Ch)
313 # define TOLOWER(Ch, L) towlower (Ch)
314 # endif
315 #else
316 # ifdef _LIBC
317 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
318 # define TOUPPER(Ch, L) __toupper_l (Ch, L)
319 # define TOLOWER(Ch, L) __tolower_l (Ch, L)
320 # else
321 # define TOUPPER(Ch, L) toupper (Ch)
322 # define TOLOWER(Ch, L) tolower (Ch)
323 # endif
324 # else
325 # define TOUPPER(Ch, L) (islower (Ch) ? toupper (Ch) : (Ch))
326 # define TOLOWER(Ch, L) (isupper (Ch) ? tolower (Ch) : (Ch))
327 # endif
328 #endif
329 /* We don't use `isdigit' here since the locale dependent
330 interpretation is not what we want here. We only need to accept
331 the arabic digits in the ASCII range. One day there is perhaps a
332 more reliable way to accept other sets of digits. */
333 #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
335 static CHAR_T *memcpy_lowcase (CHAR_T *dest, const CHAR_T *src,
336 size_t len LOCALE_PARAM_PROTO) __THROW;
338 static CHAR_T *
339 memcpy_lowcase (dest, src, len LOCALE_PARAM)
340 CHAR_T *dest;
341 const CHAR_T *src;
342 size_t len;
343 LOCALE_PARAM_DECL
345 while (len-- > 0)
346 dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
347 return dest;
350 static CHAR_T *memcpy_uppcase (CHAR_T *dest, const CHAR_T *src,
351 size_t len LOCALE_PARAM_PROTO) __THROW;
353 static CHAR_T *
354 memcpy_uppcase (dest, src, len LOCALE_PARAM)
355 CHAR_T *dest;
356 const CHAR_T *src;
357 size_t len;
358 LOCALE_PARAM_DECL
360 while (len-- > 0)
361 dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
362 return dest;
366 #if ! HAVE_TM_GMTOFF
367 /* Yield the difference between *A and *B,
368 measured in seconds, ignoring leap seconds. */
369 # define tm_diff ftime_tm_diff
370 static int tm_diff (const struct tm *, const struct tm *) __THROW;
371 static int
372 tm_diff (a, b)
373 const struct tm *a;
374 const struct tm *b;
376 /* Compute intervening leap days correctly even if year is negative.
377 Take care to avoid int overflow in leap day calculations,
378 but it's OK to assume that A and B are close to each other. */
379 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
380 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
381 int a100 = a4 / 25 - (a4 % 25 < 0);
382 int b100 = b4 / 25 - (b4 % 25 < 0);
383 int a400 = a100 >> 2;
384 int b400 = b100 >> 2;
385 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
386 int years = a->tm_year - b->tm_year;
387 int days = (365 * years + intervening_leap_days
388 + (a->tm_yday - b->tm_yday));
389 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
390 + (a->tm_min - b->tm_min))
391 + (a->tm_sec - b->tm_sec));
393 #endif /* ! HAVE_TM_GMTOFF */
397 /* The number of days from the first day of the first ISO week of this
398 year to the year day YDAY with week day WDAY. ISO weeks start on
399 Monday; the first ISO week has the year's first Thursday. YDAY may
400 be as small as YDAY_MINIMUM. */
401 #define ISO_WEEK_START_WDAY 1 /* Monday */
402 #define ISO_WEEK1_WDAY 4 /* Thursday */
403 #define YDAY_MINIMUM (-366)
404 static int iso_week_days (int, int) __THROW;
405 #ifdef __GNUC__
406 __inline__
407 #endif
408 static int
409 iso_week_days (yday, wday)
410 int yday;
411 int wday;
413 /* Add enough to the first operand of % to make it nonnegative. */
414 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
415 return (yday
416 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
417 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
421 #if !(defined _NL_CURRENT || HAVE_STRFTIME)
422 static CHAR_T const weekday_name[][10] =
424 L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
425 L_("Thursday"), L_("Friday"), L_("Saturday")
427 static CHAR_T const month_name[][10] =
429 L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
430 L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
431 L_("November"), L_("December")
433 #endif
436 #ifdef emacs
437 # define my_strftime emacs_strftimeu
438 # define ut_argument , ut
439 # define ut_argument_spec int ut;
440 # define ut_argument_spec_iso , int ut
441 #else
442 # ifdef COMPILE_WIDE
443 # define my_strftime wcsftime
444 # define nl_get_alt_digit _nl_get_walt_digit
445 # else
446 # define my_strftime strftime
447 # define nl_get_alt_digit _nl_get_alt_digit
448 # endif
449 # define ut_argument
450 # define ut_argument_spec
451 # define ut_argument_spec_iso
452 /* We don't have this information in general. */
453 # define ut 0
454 #endif
456 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
457 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
458 Work around this bug by copying *tp before it might be munged. */
459 size_t _strftime_copytm (char *, size_t, const char *,
460 const struct tm * ut_argument_spec_iso) __THROW;
461 size_t
462 my_strftime (s, maxsize, format, tp ut_argument)
463 CHAR_T *s;
464 size_t maxsize;
465 const CHAR_T *format;
466 const struct tm *tp;
467 ut_argument_spec
469 struct tm tmcopy;
470 tmcopy = *tp;
471 return _strftime_copytm (s, maxsize, format, &tmcopy ut_argument);
473 # undef my_strftime
474 # define my_strftime _strftime_copytm
475 #endif
478 /* Write information from TP into S according to the format
479 string FORMAT, writing no more that MAXSIZE characters
480 (including the terminating '\0') and returning number of
481 characters written. If S is NULL, nothing will be written
482 anywhere, so to determine how many characters would be
483 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
484 size_t
485 my_strftime (s, maxsize, format, tp ut_argument LOCALE_PARAM)
486 CHAR_T *s;
487 size_t maxsize;
488 const CHAR_T *format;
489 const struct tm *tp;
490 ut_argument_spec
491 LOCALE_PARAM_DECL
493 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
494 struct locale_data *const current = loc->__locales[LC_TIME];
495 #endif
497 int hour12 = tp->tm_hour;
498 #ifdef _NL_CURRENT
499 /* We cannot make the following values variables since we must delay
500 the evaluation of these values until really needed since some
501 expressions might not be valid in every situation. The `struct tm'
502 might be generated by a strptime() call that initialized
503 only a few elements. Dereference the pointers only if the format
504 requires this. Then it is ok to fail if the pointers are invalid. */
505 # define a_wkday \
506 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
507 # define f_wkday \
508 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
509 # define a_month \
510 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
511 # define f_month \
512 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
513 # define ampm \
514 ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
515 ? NLW(PM_STR) : NLW(AM_STR)))
517 # define aw_len STRLEN (a_wkday)
518 # define am_len STRLEN (a_month)
519 # define ap_len STRLEN (ampm)
520 #else
521 # if !HAVE_STRFTIME
522 # define f_wkday (weekday_name[tp->tm_wday])
523 # define f_month (month_name[tp->tm_mon])
524 # define a_wkday f_wkday
525 # define a_month f_month
526 # define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
528 size_t aw_len = 3;
529 size_t am_len = 3;
530 size_t ap_len = 2;
531 # endif
532 #endif
533 const char *zone;
534 size_t i = 0;
535 CHAR_T *p = s;
536 const CHAR_T *f;
537 #if DO_MULTIBYTE && !defined COMPILE_WIDE
538 const char *format_end = NULL;
539 #endif
541 zone = NULL;
542 #if HAVE_TM_ZONE
543 /* The POSIX test suite assumes that setting
544 the environment variable TZ to a new value before calling strftime()
545 will influence the result (the %Z format) even if the information in
546 TP is computed with a totally different time zone.
547 This is bogus: though POSIX allows bad behavior like this,
548 POSIX does not require it. Do the right thing instead. */
549 zone = (const char *) tp->tm_zone;
550 #endif
551 #if HAVE_TZNAME
552 if (ut)
554 if (! (zone && *zone))
555 zone = "GMT";
557 else
559 /* POSIX.1 requires that local time zone information is used as
560 though strftime called tzset. */
561 # if HAVE_TZSET
562 tzset ();
563 # endif
565 #endif
567 if (hour12 > 12)
568 hour12 -= 12;
569 else
570 if (hour12 == 0)
571 hour12 = 12;
573 for (f = format; *f != '\0'; ++f)
575 int pad = 0; /* Padding for number ('-', '_', or 0). */
576 int modifier; /* Field modifier ('E', 'O', or 0). */
577 int digits; /* Max digits for numeric format. */
578 int number_value; /* Numeric value to be printed. */
579 int negative_number; /* 1 if the number is negative. */
580 const CHAR_T *subfmt;
581 CHAR_T *bufp;
582 CHAR_T buf[1 + (sizeof (int) < sizeof (time_t)
583 ? INT_STRLEN_BOUND (time_t)
584 : INT_STRLEN_BOUND (int))];
585 int width = -1;
586 int to_lowcase = 0;
587 int to_uppcase = 0;
588 int change_case = 0;
589 int format_char;
591 #if DO_MULTIBYTE && !defined COMPILE_WIDE
592 switch (*f)
594 case L_('%'):
595 break;
597 case L_('\b'): case L_('\t'): case L_('\n'):
598 case L_('\v'): case L_('\f'): case L_('\r'):
599 case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
600 case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
601 case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
602 case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
603 case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
604 case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
605 case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
606 case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
607 case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
608 case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
609 case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
610 case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
611 case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
612 case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
613 case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
614 case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
615 case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
616 case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
617 case L_('~'):
618 /* The C Standard requires these 98 characters (plus '%') to
619 be in the basic execution character set. None of these
620 characters can start a multibyte sequence, so they need
621 not be analyzed further. */
622 add (1, *p = *f);
623 continue;
625 default:
626 /* Copy this multibyte sequence until we reach its end, find
627 an error, or come back to the initial shift state. */
629 mbstate_t mbstate = mbstate_zero;
630 size_t len = 0;
631 size_t fsize;
633 if (! format_end)
634 format_end = f + strlen (f) + 1;
635 fsize = format_end - f;
639 size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
641 if (bytes == 0)
642 break;
644 if (bytes == (size_t) -2)
646 len += strlen (f + len);
647 break;
650 if (bytes == (size_t) -1)
652 len++;
653 break;
656 len += bytes;
658 while (! mbsinit (&mbstate));
660 cpy (len, f);
661 f += len - 1;
662 continue;
666 #else /* ! DO_MULTIBYTE */
668 /* Either multibyte encodings are not supported, they are
669 safe for formats, so any non-'%' byte can be copied through,
670 or this is the wide character version. */
671 if (*f != L_('%'))
673 add (1, *p = *f);
674 continue;
677 #endif /* ! DO_MULTIBYTE */
679 /* Check for flags that can modify a format. */
680 while (1)
682 switch (*++f)
684 /* This influences the number formats. */
685 case L_('_'):
686 case L_('-'):
687 case L_('0'):
688 pad = *f;
689 continue;
691 /* This changes textual output. */
692 case L_('^'):
693 to_uppcase = 1;
694 continue;
695 case L_('#'):
696 change_case = 1;
697 continue;
699 default:
700 break;
702 break;
705 /* As a GNU extension we allow to specify the field width. */
706 if (ISDIGIT (*f))
708 width = 0;
711 if (width > INT_MAX / 10
712 || (width == INT_MAX / 10 && *f - L_('0') > INT_MAX % 10))
713 /* Avoid overflow. */
714 width = INT_MAX;
715 else
717 width *= 10;
718 width += *f - L_('0');
720 ++f;
722 while (ISDIGIT (*f));
725 /* Check for modifiers. */
726 switch (*f)
728 case L_('E'):
729 case L_('O'):
730 modifier = *f++;
731 break;
733 default:
734 modifier = 0;
735 break;
738 /* Now do the specified format. */
739 format_char = *f;
740 switch (format_char)
742 #define DO_NUMBER(d, v) \
743 digits = d > width ? d : width; \
744 number_value = v; goto do_number
745 #define DO_NUMBER_SPACEPAD(d, v) \
746 digits = d > width ? d : width; \
747 number_value = v; goto do_number_spacepad
749 case L_('%'):
750 if (modifier != 0)
751 goto bad_format;
752 add (1, *p = *f);
753 break;
755 case L_('a'):
756 if (modifier != 0)
757 goto bad_format;
758 if (change_case)
760 to_uppcase = 1;
761 to_lowcase = 0;
763 #if defined _NL_CURRENT || !HAVE_STRFTIME
764 cpy (aw_len, a_wkday);
765 break;
766 #else
767 goto underlying_strftime;
768 #endif
770 case 'A':
771 if (modifier != 0)
772 goto bad_format;
773 if (change_case)
775 to_uppcase = 1;
776 to_lowcase = 0;
778 #if defined _NL_CURRENT || !HAVE_STRFTIME
779 cpy (STRLEN (f_wkday), f_wkday);
780 break;
781 #else
782 goto underlying_strftime;
783 #endif
785 case L_('b'):
786 case L_('h'):
787 if (change_case)
789 to_uppcase = 1;
790 to_lowcase = 0;
792 if (modifier != 0)
793 goto bad_format;
794 #if defined _NL_CURRENT || !HAVE_STRFTIME
795 cpy (am_len, a_month);
796 break;
797 #else
798 goto underlying_strftime;
799 #endif
801 case L_('B'):
802 if (modifier != 0)
803 goto bad_format;
804 if (change_case)
806 to_uppcase = 1;
807 to_lowcase = 0;
809 #if defined _NL_CURRENT || !HAVE_STRFTIME
810 cpy (STRLEN (f_month), f_month);
811 break;
812 #else
813 goto underlying_strftime;
814 #endif
816 case L_('c'):
817 if (modifier == L_('O'))
818 goto bad_format;
819 #ifdef _NL_CURRENT
820 if (! (modifier == 'E'
821 && (*(subfmt =
822 (const CHAR_T *) _NL_CURRENT (LC_TIME,
823 NLW(ERA_D_T_FMT)))
824 != '\0')))
825 subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
826 #else
827 # if HAVE_STRFTIME
828 goto underlying_strftime;
829 # else
830 subfmt = L_("%a %b %e %H:%M:%S %Y");
831 # endif
832 #endif
834 subformat:
836 CHAR_T *old_start = p;
837 size_t len = my_strftime (NULL, (size_t) -1, subfmt,
838 tp ut_argument LOCALE_ARG);
839 add (len, my_strftime (p, maxsize - i, subfmt,
840 tp ut_argument LOCALE_ARG));
842 if (to_uppcase)
843 while (old_start < p)
845 *old_start = TOUPPER ((UCHAR_T) *old_start, loc);
846 ++old_start;
849 break;
851 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
852 underlying_strftime:
854 /* The relevant information is available only via the
855 underlying strftime implementation, so use that. */
856 char ufmt[4];
857 char *u = ufmt;
858 char ubuf[1024]; /* enough for any single format in practice */
859 size_t len;
860 /* Make sure we're calling the actual underlying strftime.
861 In some cases, config.h contains something like
862 "#define strftime rpl_strftime". */
863 # ifdef strftime
864 # undef strftime
865 size_t strftime ();
866 # endif
868 *u++ = '%';
869 if (modifier != 0)
870 *u++ = modifier;
871 *u++ = format_char;
872 *u = '\0';
873 len = strftime (ubuf, sizeof ubuf, ufmt, tp);
874 if (len == 0 && ubuf[0] != '\0')
875 return 0;
876 cpy (len, ubuf);
878 break;
879 #endif
881 case L_('C'):
882 if (modifier == L_('O'))
883 goto bad_format;
884 if (modifier == L_('E'))
886 #if HAVE_STRUCT_ERA_ENTRY
887 struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
888 if (era)
890 # ifdef COMPILE_WIDE
891 size_t len = __wcslen (era->era_wname);
892 cpy (len, era->era_wname);
893 # else
894 size_t len = strlen (era->era_name);
895 cpy (len, era->era_name);
896 # endif
897 break;
899 #else
900 # if HAVE_STRFTIME
901 goto underlying_strftime;
902 # endif
903 #endif
907 int year = tp->tm_year + TM_YEAR_BASE;
908 DO_NUMBER (1, year / 100 - (year % 100 < 0));
911 case L_('x'):
912 if (modifier == L_('O'))
913 goto bad_format;
914 #ifdef _NL_CURRENT
915 if (! (modifier == L_('E')
916 && (*(subfmt =
917 (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
918 != L_('\0'))))
919 subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
920 goto subformat;
921 #else
922 # if HAVE_STRFTIME
923 goto underlying_strftime;
924 # else
925 /* Fall through. */
926 # endif
927 #endif
928 case L_('D'):
929 if (modifier != 0)
930 goto bad_format;
931 subfmt = L_("%m/%d/%y");
932 goto subformat;
934 case L_('d'):
935 if (modifier == L_('E'))
936 goto bad_format;
938 DO_NUMBER (2, tp->tm_mday);
940 case L_('e'):
941 if (modifier == L_('E'))
942 goto bad_format;
944 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
946 /* All numeric formats set DIGITS and NUMBER_VALUE and then
947 jump to one of these two labels. */
949 do_number_spacepad:
950 /* Force `_' flag unless overwritten by `0' or '-' flag. */
951 if (pad != L_('0') && pad != L_('-'))
952 pad = L_('_');
954 do_number:
955 /* Format the number according to the MODIFIER flag. */
957 if (modifier == L_('O') && 0 <= number_value)
959 #ifdef _NL_CURRENT
960 /* Get the locale specific alternate representation of
961 the number NUMBER_VALUE. If none exist NULL is returned. */
962 const CHAR_T *cp = nl_get_alt_digit (number_value
963 HELPER_LOCALE_ARG);
965 if (cp != NULL)
967 size_t digitlen = STRLEN (cp);
968 if (digitlen != 0)
970 cpy (digitlen, cp);
971 break;
974 #else
975 # if HAVE_STRFTIME
976 goto underlying_strftime;
977 # endif
978 #endif
981 unsigned int u = number_value;
983 bufp = buf + sizeof (buf) / sizeof (buf[0]);
984 negative_number = number_value < 0;
986 if (negative_number)
987 u = -u;
990 *--bufp = u % 10 + L_('0');
991 while ((u /= 10) != 0);
994 do_number_sign_and_padding:
995 if (negative_number)
996 *--bufp = L_('-');
998 if (pad != L_('-'))
1000 int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
1001 - bufp);
1003 if (padding > 0)
1005 if (pad == L_('_'))
1007 if ((size_t) padding >= maxsize - i)
1008 return 0;
1010 if (p)
1011 memset_space (p, padding);
1012 i += padding;
1013 width = width > padding ? width - padding : 0;
1015 else
1017 if ((size_t) digits >= maxsize - i)
1018 return 0;
1020 if (negative_number)
1022 ++bufp;
1024 if (p)
1025 *p++ = L_('-');
1026 ++i;
1029 if (p)
1030 memset_zero (p, padding);
1031 i += padding;
1032 width = 0;
1037 cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);
1038 break;
1040 case L_('F'):
1041 if (modifier != 0)
1042 goto bad_format;
1043 subfmt = L_("%Y-%m-%d");
1044 goto subformat;
1046 case L_('H'):
1047 if (modifier == L_('E'))
1048 goto bad_format;
1050 DO_NUMBER (2, tp->tm_hour);
1052 case L_('I'):
1053 if (modifier == L_('E'))
1054 goto bad_format;
1056 DO_NUMBER (2, hour12);
1058 case L_('k'): /* GNU extension. */
1059 if (modifier == L_('E'))
1060 goto bad_format;
1062 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
1064 case L_('l'): /* GNU extension. */
1065 if (modifier == L_('E'))
1066 goto bad_format;
1068 DO_NUMBER_SPACEPAD (2, hour12);
1070 case L_('j'):
1071 if (modifier == L_('E'))
1072 goto bad_format;
1074 DO_NUMBER (3, 1 + tp->tm_yday);
1076 case L_('M'):
1077 if (modifier == L_('E'))
1078 goto bad_format;
1080 DO_NUMBER (2, tp->tm_min);
1082 case L_('m'):
1083 if (modifier == L_('E'))
1084 goto bad_format;
1086 DO_NUMBER (2, tp->tm_mon + 1);
1088 case L_('n'):
1089 add (1, *p = L_('\n'));
1090 break;
1092 case L_('P'):
1093 to_lowcase = 1;
1094 #if !defined _NL_CURRENT && HAVE_STRFTIME
1095 format_char = L_('p');
1096 #endif
1097 /* FALLTHROUGH */
1099 case L_('p'):
1100 if (change_case)
1102 to_uppcase = 0;
1103 to_lowcase = 1;
1105 #if defined _NL_CURRENT || !HAVE_STRFTIME
1106 cpy (ap_len, ampm);
1107 break;
1108 #else
1109 goto underlying_strftime;
1110 #endif
1112 case L_('R'):
1113 subfmt = L_("%H:%M");
1114 goto subformat;
1116 case L_('r'):
1117 #if !defined _NL_CURRENT && HAVE_STRFTIME
1118 goto underlying_strftime;
1119 #else
1120 # ifdef _NL_CURRENT
1121 if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
1122 NLW(T_FMT_AMPM)))
1123 == L_('\0'))
1124 # endif
1125 subfmt = L_("%I:%M:%S %p");
1126 goto subformat;
1127 #endif
1129 case L_('S'):
1130 if (modifier == L_('E'))
1131 goto bad_format;
1133 DO_NUMBER (2, tp->tm_sec);
1135 case L_('s'): /* GNU extension. */
1137 struct tm ltm;
1138 time_t t;
1140 ltm = *tp;
1141 t = mktime (&ltm);
1143 /* Generate string value for T using time_t arithmetic;
1144 this works even if sizeof (long) < sizeof (time_t). */
1146 bufp = buf + sizeof (buf) / sizeof (buf[0]);
1147 negative_number = t < 0;
1151 int d = t % 10;
1152 t /= 10;
1154 if (negative_number)
1156 d = -d;
1158 /* Adjust if division truncates to minus infinity. */
1159 if (0 < -1 % 10 && d < 0)
1161 t++;
1162 d += 10;
1166 *--bufp = d + L_('0');
1168 while (t != 0);
1170 digits = 1;
1171 goto do_number_sign_and_padding;
1174 case L_('X'):
1175 if (modifier == L_('O'))
1176 goto bad_format;
1177 #ifdef _NL_CURRENT
1178 if (! (modifier == L_('E')
1179 && (*(subfmt =
1180 (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
1181 != L_('\0'))))
1182 subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
1183 goto subformat;
1184 #else
1185 # if HAVE_STRFTIME
1186 goto underlying_strftime;
1187 # else
1188 /* Fall through. */
1189 # endif
1190 #endif
1191 case L_('T'):
1192 subfmt = L_("%H:%M:%S");
1193 goto subformat;
1195 case L_('t'):
1196 add (1, *p = L_('\t'));
1197 break;
1199 case L_('u'):
1200 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1202 case L_('U'):
1203 if (modifier == L_('E'))
1204 goto bad_format;
1206 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1208 case L_('V'):
1209 case L_('g'):
1210 case L_('G'):
1211 if (modifier == L_('E'))
1212 goto bad_format;
1214 int year = tp->tm_year + TM_YEAR_BASE;
1215 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1217 if (days < 0)
1219 /* This ISO week belongs to the previous year. */
1220 year--;
1221 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
1222 tp->tm_wday);
1224 else
1226 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1227 tp->tm_wday);
1228 if (0 <= d)
1230 /* This ISO week belongs to the next year. */
1231 year++;
1232 days = d;
1236 switch (*f)
1238 case L_('g'):
1239 DO_NUMBER (2, (year % 100 + 100) % 100);
1241 case L_('G'):
1242 DO_NUMBER (1, year);
1244 default:
1245 DO_NUMBER (2, days / 7 + 1);
1249 case L_('W'):
1250 if (modifier == L_('E'))
1251 goto bad_format;
1253 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1255 case L_('w'):
1256 if (modifier == L_('E'))
1257 goto bad_format;
1259 DO_NUMBER (1, tp->tm_wday);
1261 case L_('Y'):
1262 if (modifier == 'E')
1264 #if HAVE_STRUCT_ERA_ENTRY
1265 struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1266 if (era)
1268 # ifdef COMPILE_WIDE
1269 subfmt = era->era_wformat;
1270 # else
1271 subfmt = era->era_format;
1272 # endif
1273 goto subformat;
1275 #else
1276 # if HAVE_STRFTIME
1277 goto underlying_strftime;
1278 # endif
1279 #endif
1281 if (modifier == L_('O'))
1282 goto bad_format;
1283 else
1284 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1286 case L_('y'):
1287 if (modifier == L_('E'))
1289 #if HAVE_STRUCT_ERA_ENTRY
1290 struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1291 if (era)
1293 int delta = tp->tm_year - era->start_date[0];
1294 DO_NUMBER (1, (era->offset
1295 + delta * era->absolute_direction));
1297 #else
1298 # if HAVE_STRFTIME
1299 goto underlying_strftime;
1300 # endif
1301 #endif
1303 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1305 case L_('Z'):
1306 if (change_case)
1308 to_uppcase = 0;
1309 to_lowcase = 1;
1312 #if HAVE_TZNAME
1313 /* The tzset() call might have changed the value. */
1314 if (!(zone && *zone) && tp->tm_isdst >= 0)
1315 zone = tzname[tp->tm_isdst];
1316 #endif
1317 if (! zone)
1318 zone = "";
1320 #ifdef COMPILE_WIDE
1322 /* The zone string is always given in multibyte form. We have
1323 to transform it first. */
1324 wchar_t *wczone;
1325 size_t len;
1326 widen (zone, wczone, len);
1327 cpy (len, wczone);
1329 #else
1330 cpy (strlen (zone), zone);
1331 #endif
1332 break;
1334 case L_('z'):
1335 if (tp->tm_isdst < 0)
1336 break;
1339 int diff;
1340 #if HAVE_TM_GMTOFF
1341 diff = tp->tm_gmtoff;
1342 #else
1343 if (ut)
1344 diff = 0;
1345 else
1347 struct tm gtm;
1348 struct tm ltm;
1349 time_t lt;
1351 ltm = *tp;
1352 lt = mktime (&ltm);
1354 if (lt == (time_t) -1)
1356 /* mktime returns -1 for errors, but -1 is also a
1357 valid time_t value. Check whether an error really
1358 occurred. */
1359 struct tm tm;
1361 if (! __localtime_r (&lt, &tm)
1362 || ((ltm.tm_sec ^ tm.tm_sec)
1363 | (ltm.tm_min ^ tm.tm_min)
1364 | (ltm.tm_hour ^ tm.tm_hour)
1365 | (ltm.tm_mday ^ tm.tm_mday)
1366 | (ltm.tm_mon ^ tm.tm_mon)
1367 | (ltm.tm_year ^ tm.tm_year)))
1368 break;
1371 if (! __gmtime_r (&lt, &gtm))
1372 break;
1374 diff = tm_diff (&ltm, &gtm);
1376 #endif
1378 if (diff < 0)
1380 add (1, *p = L_('-'));
1381 diff = -diff;
1383 else
1384 add (1, *p = L_('+'));
1386 diff /= 60;
1387 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1390 case L_('\0'): /* GNU extension: % at end of format. */
1391 --f;
1392 /* Fall through. */
1393 default:
1394 /* Unknown format; output the format, including the '%',
1395 since this is most likely the right thing to do if a
1396 multibyte string has been misparsed. */
1397 bad_format:
1399 int flen;
1400 for (flen = 1; f[1 - flen] != L_('%'); flen++)
1401 continue;
1402 cpy (flen, &f[1 - flen]);
1404 break;
1408 if (p && maxsize != 0)
1409 *p = L_('\0');
1410 return i;
1412 #ifdef _LIBC
1413 libc_hidden_def (my_strftime)
1414 #endif
1417 #ifdef emacs
1418 /* For Emacs we have a separate interface which corresponds to the normal
1419 strftime function and does not have the extra information whether the
1420 TP arguments comes from a `gmtime' call or not. */
1421 size_t
1422 emacs_strftime (s, maxsize, format, tp)
1423 char *s;
1424 size_t maxsize;
1425 const char *format;
1426 const struct tm *tp;
1428 return my_strftime (s, maxsize, format, tp, 0);
1430 #endif
1432 #if defined _LIBC && !defined COMPILE_WIDE
1433 weak_alias (__strftime_l, strftime_l)
1434 #endif