(post-read-decode-hz)
[emacs.git] / src / strftime.c
blob789e7ae8e91ef17dafa583366df2e6c07af0ef87
1 /* Copyright (C) 1991,92,93,94,95,96,97,98,99,2000 Free Software Foundation, Inc.
2 This file is part of the GNU Emacs.
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. */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #ifdef _LIBC
24 # define HAVE_LIMITS_H 1
25 # define HAVE_MBLEN 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 HAVE_TZNAME 1
31 # define HAVE_TZSET 1
32 # define MULTIBYTE_IS_FORMAT_SAFE 1
33 # define STDC_HEADERS 1
34 # include "../locale/localeinfo.h"
35 #endif
37 #if defined emacs && !defined HAVE_BCOPY
38 # define HAVE_MEMCPY 1
39 #endif
41 #include <ctype.h>
42 #include <sys/types.h> /* Some systems define `time_t' here. */
44 #ifdef TIME_WITH_SYS_TIME
45 # include <sys/time.h>
46 # include <time.h>
47 #else
48 # ifdef HAVE_SYS_TIME_H
49 # include <sys/time.h>
50 # else
51 # include <time.h>
52 # endif
53 #endif
54 #if HAVE_TZNAME
55 #ifndef USE_CRT_DLL
56 extern char *tzname[];
57 #endif
58 #endif
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)
68 #if DO_MULTIBYTE
69 # if HAVE_MBRLEN
70 # include <wchar.h>
71 # if !defined (mbsinit) && !defined (HAVE_MBSINIT)
72 # define mbsinit(ps) 1
73 # endif /* !defined (mbsinit) && !defined (HAVE_MBSINIT) */
74 # else
75 /* Simulate mbrlen with mblen as best we can. */
76 # define mbstate_t int
77 # define mbrlen(s, n, ps) mblen (s, n)
78 # define mbsinit(ps) (*(ps) == 0)
79 # endif
80 static const mbstate_t mbstate_zero;
81 #endif
83 #ifdef HAVE_LIMITS_H
84 # include <limits.h>
85 #endif
87 #ifdef STDC_HEADERS
88 # include <stddef.h>
89 # include <stdlib.h>
90 #else
91 # ifndef HAVE_MEMCPY
92 # define memcpy(d, s, n) bcopy ((s), (d), (n))
93 # endif
94 #endif
96 #ifdef COMPILE_WIDE
97 # include <endian.h>
98 # define CHAR_T wchar_t
99 # define UCHAR_T unsigned int
100 # define L_(Str) L##Str
101 # define NLW(Sym) _NL_W##Sym
103 # define MEMCPY(d, s, n) __wmemcpy (d, s, n)
104 # define STRLEN(s) __wcslen (s)
106 #else
107 # define CHAR_T char
108 # define UCHAR_T unsigned char
109 # define L_(Str) Str
110 # define NLW(Sym) Sym
112 # if !defined STDC_HEADERS && !defined HAVE_MEMCPY
113 # define MEMCPY(d, s, n) bcopy ((s), (d), (n))
114 # else
115 # define MEMCPY(d, s, n) memcpy ((d), (s), (n))
116 # endif
117 # define STRLEN(s) strlen (s)
119 # ifdef _LIBC
120 # define MEMPCPY(d, s, n) __mempcpy (d, s, n)
121 # else
122 # ifndef HAVE_MEMPCPY
123 # define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
124 # endif
125 # endif
126 #endif
128 #ifndef __P
129 # if defined emacs && defined PROTOTYPES
130 # define __P(args) args
131 # elif defined __GNUC__ || (defined __STDC__ && __STDC__)
132 # define __P(args) args
133 # else
134 # define __P(args) ()
135 # endif /* GCC. */
136 #endif /* Not __P. */
138 #ifndef PTR
139 # ifdef __STDC__
140 # define PTR void *
141 # else
142 # define PTR char *
143 # endif
144 #endif
146 #ifndef CHAR_BIT
147 # define CHAR_BIT 8
148 #endif
150 #ifndef NULL
151 # define NULL 0
152 #endif
154 #define TYPE_SIGNED(t) ((t) -1 < 0)
156 /* Bound on length of the string representing an integer value of type t.
157 Subtract one for the sign bit if t is signed;
158 302 / 1000 is log10 (2) rounded up;
159 add one for integer division truncation;
160 add one more for a minus sign if t is signed. */
161 #define INT_STRLEN_BOUND(t) \
162 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t))
164 #define TM_YEAR_BASE 1900
166 #ifndef __isleap
167 /* Nonzero if YEAR is a leap year (every 4 years,
168 except every 100th isn't, and every 400th is). */
169 # define __isleap(year) \
170 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
171 #endif
174 #ifdef _LIBC
175 # define my_strftime_gmtime_r __gmtime_r
176 # define my_strftime_localtime_r __localtime_r
177 # define tzname __tzname
178 # define tzset __tzset
179 #else
181 /* If we're a strftime substitute in a GNU program, then prefer gmtime
182 to gmtime_r, since many gmtime_r implementations are buggy.
183 Similarly for localtime_r. */
185 # if ! HAVE_TM_GMTOFF
186 static struct tm *my_strftime_gmtime_r __P ((const time_t *, struct tm *));
187 static struct tm *
188 my_strftime_gmtime_r (t, tp)
189 const time_t *t;
190 struct tm *tp;
192 struct tm *l = gmtime (t);
193 if (! l)
194 return 0;
195 *tp = *l;
196 return tp;
198 # endif /* ! HAVE_TM_GMTOFF */
200 static struct tm *my_strftime_localtime_r __P ((const time_t *, struct tm *));
201 static struct tm *
202 my_strftime_localtime_r (t, tp)
203 const time_t *t;
204 struct tm *tp;
206 struct tm *l = localtime (t);
207 if (! l)
208 return 0;
209 *tp = *l;
210 return tp;
212 #endif /* ! defined _LIBC */
215 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
216 /* Some systems lack the `memset' function and we don't want to
217 introduce additional dependencies. */
218 /* The SGI compiler reportedly barfs on the trailing null
219 if we use a string constant as the initializer. 28 June 1997, rms. */
220 static const CHAR_T spaces[16] = /* " " */
222 L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),
223 L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' ')
225 static const CHAR_T zeroes[16] = /* "0000000000000000" */
227 L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),
228 L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0')
231 # define memset_space(P, Len) \
232 do { \
233 int _len = (Len); \
235 do \
237 int _this = _len > 16 ? 16 : _len; \
238 (P) = MEMPCPY ((P), spaces, _this * sizeof (CHAR_T)); \
239 _len -= _this; \
241 while (_len > 0); \
242 } while (0)
244 # define memset_zero(P, Len) \
245 do { \
246 int _len = (Len); \
248 do \
250 int _this = _len > 16 ? 16 : _len; \
251 (P) = MEMPCPY ((P), zeroes, _this * sizeof (CHAR_T)); \
252 _len -= _this; \
254 while (_len > 0); \
255 } while (0)
256 #else
257 # ifdef COMPILE_WIDE
258 # define memset_space(P, Len) (wmemset ((P), L' ', (Len)), (P) += (Len))
259 # define memset_zero(P, Len) (wmemset ((P), L'0', (Len)), (P) += (Len))
260 # else
261 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
262 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
263 # endif
264 #endif
266 #define add(n, f) \
267 do \
269 int _n = (n); \
270 int _delta = width - _n; \
271 int _incr = _n + (_delta > 0 ? _delta : 0); \
272 if (i + _incr >= maxsize) \
273 return 0; \
274 if (p) \
276 if (_delta > 0) \
278 if (pad == L_('0')) \
279 memset_zero (p, _delta); \
280 else \
281 memset_space (p, _delta); \
283 f; \
284 p += _n; \
286 i += _incr; \
287 } while (0)
289 #define cpy(n, s) \
290 add ((n), \
291 if (to_lowcase) \
292 memcpy_lowcase (p, (s), _n); \
293 else if (to_uppcase) \
294 memcpy_uppcase (p, (s), _n); \
295 else \
296 MEMCPY ((PTR) p, (PTR) (s), _n))
298 #ifdef COMPILE_WIDE
299 # define widen(os, ws, l) \
301 mbstate_t __st; \
302 const char *__s = os; \
303 memset (&__st, '\0', sizeof (__st)); \
304 l = __mbsrtowcs (NULL, &__s, 0, &__st); \
305 ws = alloca ((l + 1) * sizeof (wchar_t)); \
306 (void) __mbsrtowcs (ws, &__s, l, &__st); \
308 #endif
311 #ifdef COMPILE_WIDE
312 # define TOUPPER(Ch) towupper (Ch)
313 # define TOLOWER(Ch) towlower (Ch)
314 #else
315 # ifdef _LIBC
316 # define TOUPPER(Ch) toupper (Ch)
317 # define TOLOWER(Ch) tolower (Ch)
318 # else
319 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
320 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
321 # endif
322 #endif
323 /* We don't use `isdigit' here since the locale dependent
324 interpretation is not what we want here. We only need to accept
325 the arabic digits in the ASCII range. One day there is perhaps a
326 more reliable way to accept other sets of digits. */
327 #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
329 static CHAR_T *memcpy_lowcase __P ((CHAR_T *dest, const CHAR_T *src,
330 size_t len));
332 static CHAR_T *
333 memcpy_lowcase (dest, src, len)
334 CHAR_T *dest;
335 const CHAR_T *src;
336 size_t len;
338 while (len-- > 0)
339 dest[len] = TOLOWER ((UCHAR_T) src[len]);
340 return dest;
343 static CHAR_T *memcpy_uppcase __P ((CHAR_T *dest, const CHAR_T *src,
344 size_t len));
346 static CHAR_T *
347 memcpy_uppcase (dest, src, len)
348 CHAR_T *dest;
349 const CHAR_T *src;
350 size_t len;
352 while (len-- > 0)
353 dest[len] = TOUPPER ((UCHAR_T) src[len]);
354 return dest;
358 #if ! HAVE_TM_GMTOFF
359 /* Yield the difference between *A and *B,
360 measured in seconds, ignoring leap seconds. */
361 # define tm_diff ftime_tm_diff
362 static int tm_diff __P ((const struct tm *, const struct tm *));
363 static int
364 tm_diff (a, b)
365 const struct tm *a;
366 const struct tm *b;
368 /* Compute intervening leap days correctly even if year is negative.
369 Take care to avoid int overflow in leap day calculations,
370 but it's OK to assume that A and B are close to each other. */
371 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
372 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
373 int a100 = a4 / 25 - (a4 % 25 < 0);
374 int b100 = b4 / 25 - (b4 % 25 < 0);
375 int a400 = a100 >> 2;
376 int b400 = b100 >> 2;
377 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
378 int years = a->tm_year - b->tm_year;
379 int days = (365 * years + intervening_leap_days
380 + (a->tm_yday - b->tm_yday));
381 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
382 + (a->tm_min - b->tm_min))
383 + (a->tm_sec - b->tm_sec));
385 #endif /* ! HAVE_TM_GMTOFF */
389 /* The number of days from the first day of the first ISO week of this
390 year to the year day YDAY with week day WDAY. ISO weeks start on
391 Monday; the first ISO week has the year's first Thursday. YDAY may
392 be as small as YDAY_MINIMUM. */
393 #define ISO_WEEK_START_WDAY 1 /* Monday */
394 #define ISO_WEEK1_WDAY 4 /* Thursday */
395 #define YDAY_MINIMUM (-366)
396 static int iso_week_days __P ((int, int));
397 #ifdef __GNUC__
398 __inline__
399 #endif
400 static int
401 iso_week_days (yday, wday)
402 int yday;
403 int wday;
405 /* Add enough to the first operand of % to make it nonnegative. */
406 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
407 return (yday
408 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
409 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
413 #if !(defined _NL_CURRENT || HAVE_STRFTIME)
414 static CHAR_T const weekday_name[][10] =
416 L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
417 L_("Thursday"), L_("Friday"), L_("Saturday")
419 static CHAR_T const month_name[][10] =
421 L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
422 L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
423 L_("November"), L_("December")
425 #endif
428 #ifdef emacs
429 # define my_strftime emacs_strftimeu
430 # define ut_argument , ut
431 # define ut_argument_spec int ut;
432 # define ut_argument_spec_iso , int ut
433 #else
434 # ifdef COMPILE_WIDE
435 # define my_strftime wcsftime
436 # else
437 # define my_strftime strftime
438 # endif
439 # define ut_argument
440 # define ut_argument_spec
441 # define ut_argument_spec_iso
442 /* We don't have this information in general. */
443 # define ut 0
444 #endif
446 #if !defined _LIBC && !defined(WINDOWSNT) && HAVE_TZNAME && HAVE_TZSET
447 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
448 Work around this bug by copying *tp before it might be munged. */
449 size_t _strftime_copytm __P ((char *, size_t, const char *,
450 const struct tm * ut_argument_spec_iso));
451 size_t
452 my_strftime (s, maxsize, format, tp ut_argument)
453 CHAR_T *s;
454 size_t maxsize;
455 const CHAR_T *format;
456 const struct tm *tp;
457 ut_argument_spec
459 struct tm tmcopy;
460 tmcopy = *tp;
461 return _strftime_copytm (s, maxsize, format, &tmcopy ut_argument);
463 # undef my_strftime
464 # define my_strftime _strftime_copytm
465 #endif
468 /* Write information from TP into S according to the format
469 string FORMAT, writing no more that MAXSIZE characters
470 (including the terminating '\0') and returning number of
471 characters written. If S is NULL, nothing will be written
472 anywhere, so to determine how many characters would be
473 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
474 size_t
475 my_strftime (s, maxsize, format, tp ut_argument)
476 CHAR_T *s;
477 size_t maxsize;
478 const CHAR_T *format;
479 const struct tm *tp;
480 ut_argument_spec
482 int hour12 = tp->tm_hour;
483 #ifdef _NL_CURRENT
484 /* We cannot make the following values variables since we must delay
485 the evaluation of these values until really needed since some
486 expressions might not be valid in every situation. The `struct tm'
487 might be generated by a strptime() call that initialized
488 only a few elements. Dereference the pointers only if the format
489 requires this. Then it is ok to fail if the pointers are invalid. */
490 # define a_wkday \
491 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
492 # define f_wkday \
493 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
494 # define a_month \
495 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
496 # define f_month \
497 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
498 # define ampm \
499 ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
500 ? NLW(PM_STR) : NLW(AM_STR)))
502 # define aw_len STRLEN (a_wkday)
503 # define am_len STRLEN (a_month)
504 # define ap_len STRLEN (ampm)
505 #else
506 # if !HAVE_STRFTIME
507 # define f_wkday (weekday_name[tp->tm_wday])
508 # define f_month (month_name[tp->tm_mon])
509 # define a_wkday f_wkday
510 # define a_month f_month
511 # define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
513 size_t aw_len = 3;
514 size_t am_len = 3;
515 size_t ap_len = 2;
516 # endif
517 #endif
518 const char *zone;
519 size_t i = 0;
520 CHAR_T *p = s;
521 const CHAR_T *f;
523 zone = NULL;
524 #if HAVE_TM_ZONE
525 /* The POSIX test suite assumes that setting
526 the environment variable TZ to a new value before calling strftime()
527 will influence the result (the %Z format) even if the information in
528 TP is computed with a totally different time zone.
529 This is bogus: though POSIX allows bad behavior like this,
530 POSIX does not require it. Do the right thing instead. */
531 zone = (const char *) tp->tm_zone;
532 #endif
533 #if HAVE_TZNAME
534 if (ut)
536 if (! (zone && *zone))
537 zone = "UTC";
539 else
541 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
542 time zone names contained in the external variable `tzname' shall
543 be set as if the tzset() function had been called. */
544 # if HAVE_TZSET
545 tzset ();
546 # endif
548 #endif
550 if (hour12 > 12)
551 hour12 -= 12;
552 else
553 if (hour12 == 0)
554 hour12 = 12;
556 for (f = format; *f != '\0'; ++f)
558 int pad = 0; /* Padding for number ('-', '_', or 0). */
559 int modifier; /* Field modifier ('E', 'O', or 0). */
560 int digits; /* Max digits for numeric format. */
561 int number_value; /* Numeric value to be printed. */
562 int negative_number; /* 1 if the number is negative. */
563 const CHAR_T *subfmt;
564 CHAR_T *bufp;
565 CHAR_T buf[1 + (sizeof (int) < sizeof (time_t)
566 ? INT_STRLEN_BOUND (time_t)
567 : INT_STRLEN_BOUND (int))];
568 int width = -1;
569 int to_lowcase = 0;
570 int to_uppcase = 0;
571 int change_case = 0;
572 int format_char;
574 #if DO_MULTIBYTE && !defined COMPILE_WIDE
575 switch (*f)
577 case L_('%'):
578 break;
580 case L_('\b'): case L_('\t'): case L_('\n'):
581 case L_('\v'): case L_('\f'): case L_('\r'):
582 case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
583 case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
584 case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
585 case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
586 case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
587 case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
588 case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
589 case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
590 case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
591 case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
592 case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
593 case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
594 case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
595 case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
596 case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
597 case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
598 case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
599 case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
600 case L_('~'):
601 /* The C Standard requires these 97 characters (plus '%', `\a') to
602 be in the basic execution character set. None of these
603 characters can start a multibyte sequence, so they need
604 not be analyzed further. Some old compilers object to
605 `\a', so don't bother optimizing for it. */
606 add (1, *p = *f);
607 continue;
609 default:
610 /* Copy this multibyte sequence until we reach its end, find
611 an error, or come back to the initial shift state. */
613 mbstate_t mbstate = mbstate_zero;
614 size_t len = 0;
618 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
620 if (bytes == 0)
621 break;
623 if (bytes == (size_t) -2)
625 len += strlen (f + len);
626 break;
629 if (bytes == (size_t) -1)
631 len++;
632 break;
635 len += bytes;
637 while (! mbsinit (&mbstate));
639 cpy (len, f);
640 f += len - 1;
641 continue;
645 #else /* ! DO_MULTIBYTE */
647 /* Either multibyte encodings are not supported, they are
648 safe for formats, so any non-'%' byte can be copied through,
649 or this is the wide character version. */
650 if (*f != L_('%'))
652 add (1, *p = *f);
653 continue;
656 #endif /* ! DO_MULTIBYTE */
658 /* Check for flags that can modify a format. */
659 while (1)
661 switch (*++f)
663 /* This influences the number formats. */
664 case L_('_'):
665 case L_('-'):
666 case L_('0'):
667 pad = *f;
668 continue;
670 /* This changes textual output. */
671 case L_('^'):
672 to_uppcase = 1;
673 continue;
674 case L_('#'):
675 change_case = 1;
676 continue;
678 default:
679 break;
681 break;
684 /* As a GNU extension we allow to specify the field width. */
685 if (ISDIGIT (*f))
687 width = 0;
690 width *= 10;
691 width += *f - L_('0');
692 ++f;
694 while (ISDIGIT (*f));
697 /* Check for modifiers. */
698 switch (*f)
700 case L_('E'):
701 case L_('O'):
702 modifier = *f++;
703 break;
705 default:
706 modifier = 0;
707 break;
710 /* Now do the specified format. */
711 format_char = *f;
712 switch (format_char)
714 #define DO_NUMBER(d, v) \
715 digits = width == -1 ? d : width; \
716 number_value = v; goto do_number
717 #define DO_NUMBER_SPACEPAD(d, v) \
718 digits = width == -1 ? d : width; \
719 number_value = v; goto do_number_spacepad
721 case L_('%'):
722 if (modifier != 0)
723 goto bad_format;
724 add (1, *p = *f);
725 break;
727 case L_('a'):
728 if (modifier != 0)
729 goto bad_format;
730 if (change_case)
732 to_uppcase = 1;
733 to_lowcase = 0;
735 #if defined _NL_CURRENT || !HAVE_STRFTIME
736 cpy (aw_len, a_wkday);
737 break;
738 #else
739 goto underlying_strftime;
740 #endif
742 case 'A':
743 if (modifier != 0)
744 goto bad_format;
745 if (change_case)
747 to_uppcase = 1;
748 to_lowcase = 0;
750 #if defined _NL_CURRENT || !HAVE_STRFTIME
751 cpy (STRLEN (f_wkday), f_wkday);
752 break;
753 #else
754 goto underlying_strftime;
755 #endif
757 case L_('b'):
758 case L_('h'): /* POSIX.2 extension. */
759 if (change_case)
761 to_uppcase = 1;
762 to_lowcase = 0;
764 if (modifier != 0)
765 goto bad_format;
766 #if defined _NL_CURRENT || !HAVE_STRFTIME
767 cpy (am_len, a_month);
768 break;
769 #else
770 goto underlying_strftime;
771 #endif
773 case L_('B'):
774 if (modifier != 0)
775 goto bad_format;
776 if (change_case)
778 to_uppcase = 1;
779 to_lowcase = 0;
781 #if defined _NL_CURRENT || !HAVE_STRFTIME
782 cpy (STRLEN (f_month), f_month);
783 break;
784 #else
785 goto underlying_strftime;
786 #endif
788 case L_('c'):
789 if (modifier == L_('O'))
790 goto bad_format;
791 #ifdef _NL_CURRENT
792 if (! (modifier == 'E'
793 && (*(subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME,
794 NLW(ERA_D_T_FMT)))
795 != '\0')))
796 subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
797 #else
798 # if HAVE_STRFTIME
799 goto underlying_strftime;
800 # else
801 subfmt = L_("%a %b %e %H:%M:%S %Y");
802 # endif
803 #endif
805 subformat:
807 CHAR_T *old_start = p;
808 size_t len = my_strftime (NULL, (size_t) -1, subfmt, tp, 0);
809 add (len, my_strftime (p, maxsize - i, subfmt, tp, 0));
811 if (to_uppcase)
812 while (old_start < p)
814 *old_start = TOUPPER ((UCHAR_T) *old_start);
815 ++old_start;
818 break;
820 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
821 underlying_strftime:
823 /* The relevant information is available only via the
824 underlying strftime implementation, so use that. */
825 char ufmt[4];
826 char *u = ufmt;
827 char ubuf[1024]; /* enough for any single format in practice */
828 size_t len;
829 /* Make sure we're calling the actual underlying strftime.
830 In some cases, config.h contains something like
831 "#define strftime rpl_strftime". */
832 # ifdef strftime
833 # undef strftime
834 size_t strftime ();
835 # endif
837 *u++ = '%';
838 if (modifier != 0)
839 *u++ = modifier;
840 *u++ = format_char;
841 *u = '\0';
842 len = strftime (ubuf, sizeof ubuf, ufmt, tp);
843 if (len == 0 && ubuf[0] != '\0')
844 return 0;
845 cpy (len, ubuf);
847 break;
848 #endif
850 case L_('C'): /* POSIX.2 extension. */
851 if (modifier == L_('O'))
852 goto bad_format;
853 if (modifier == L_('E'))
855 #if HAVE_STRUCT_ERA_ENTRY
856 struct era_entry *era = _nl_get_era_entry (tp);
857 if (era)
859 # ifdef COMPILE_WIDE
860 size_t len = __wcslen (era->era_wname);
861 cpy (len, era->era_wname);
862 # else
863 size_t len = strlen (era->era_name);
864 cpy (len, era->era_name);
865 # endif
866 break;
868 #else
869 # if HAVE_STRFTIME
870 goto underlying_strftime;
871 # endif
872 #endif
876 int year = tp->tm_year + TM_YEAR_BASE;
877 DO_NUMBER (1, year / 100 - (year % 100 < 0));
880 case L_('x'):
881 if (modifier == L_('O'))
882 goto bad_format;
883 #ifdef _NL_CURRENT
884 if (! (modifier == L_('E')
885 && (*(subfmt = (CHAR_T *)_NL_CURRENT (LC_TIME,
886 NLW(ERA_D_FMT)))
887 != L_('\0'))))
888 subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
889 goto subformat;
890 #else
891 # if HAVE_STRFTIME
892 goto underlying_strftime;
893 # else
894 /* Fall through. */
895 # endif
896 #endif
897 case L_('D'): /* POSIX.2 extension. */
898 if (modifier != 0)
899 goto bad_format;
900 subfmt = L_("%m/%d/%y");
901 goto subformat;
903 case L_('d'):
904 if (modifier == L_('E'))
905 goto bad_format;
907 DO_NUMBER (2, tp->tm_mday);
909 case L_('e'): /* POSIX.2 extension. */
910 if (modifier == L_('E'))
911 goto bad_format;
913 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
915 /* All numeric formats set DIGITS and NUMBER_VALUE and then
916 jump to one of these two labels. */
918 do_number_spacepad:
919 /* Force `_' flag unless overwritten by `0' flag. */
920 if (pad != L_('0'))
921 pad = L_('_');
923 do_number:
924 /* Format the number according to the MODIFIER flag. */
926 if (modifier == L_('O') && 0 <= number_value)
928 #ifdef _NL_CURRENT
929 /* Get the locale specific alternate representation of
930 the number NUMBER_VALUE. If none exist NULL is returned. */
931 # ifdef COMPILE_WIDE
932 const wchar_t *cp = _nl_get_walt_digit (number_value);
933 # else
934 const char *cp = _nl_get_alt_digit (number_value);
935 # endif
937 if (cp != NULL)
939 size_t digitlen = STRLEN (cp);
940 if (digitlen != 0)
942 cpy (digitlen, cp);
943 break;
946 #else
947 # if HAVE_STRFTIME
948 goto underlying_strftime;
949 # endif
950 #endif
953 unsigned int u = number_value;
955 bufp = buf + sizeof (buf) / sizeof (buf[0]);
956 negative_number = number_value < 0;
958 if (negative_number)
959 u = -u;
962 *--bufp = u % 10 + L_('0');
963 while ((u /= 10) != 0);
966 do_number_sign_and_padding:
967 if (negative_number)
968 *--bufp = L_('-');
970 if (pad != L_('-'))
972 int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
973 - bufp);
975 if (pad == L_('_'))
977 while (0 < padding--)
978 *--bufp = L_(' ');
980 else
982 bufp += negative_number;
983 while (0 < padding--)
984 *--bufp = L_('0');
985 if (negative_number)
986 *--bufp = L_('-');
990 cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);
991 break;
993 case L_('F'):
994 if (modifier != 0)
995 goto bad_format;
996 subfmt = L_("%Y-%m-%d");
997 goto subformat;
999 case L_('H'):
1000 if (modifier == L_('E'))
1001 goto bad_format;
1003 DO_NUMBER (2, tp->tm_hour);
1005 case L_('I'):
1006 if (modifier == L_('E'))
1007 goto bad_format;
1009 DO_NUMBER (2, hour12);
1011 case L_('k'): /* GNU extension. */
1012 if (modifier == L_('E'))
1013 goto bad_format;
1015 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
1017 case L_('l'): /* GNU extension. */
1018 if (modifier == L_('E'))
1019 goto bad_format;
1021 DO_NUMBER_SPACEPAD (2, hour12);
1023 case L_('j'):
1024 if (modifier == L_('E'))
1025 goto bad_format;
1027 DO_NUMBER (3, 1 + tp->tm_yday);
1029 case L_('M'):
1030 if (modifier == L_('E'))
1031 goto bad_format;
1033 DO_NUMBER (2, tp->tm_min);
1035 case L_('m'):
1036 if (modifier == L_('E'))
1037 goto bad_format;
1039 DO_NUMBER (2, tp->tm_mon + 1);
1041 case L_('n'): /* POSIX.2 extension. */
1042 add (1, *p = L_('\n'));
1043 break;
1045 case L_('P'):
1046 to_lowcase = 1;
1047 #if !defined _NL_CURRENT && HAVE_STRFTIME
1048 format_char = L_('p');
1049 #endif
1050 /* FALLTHROUGH */
1052 case L_('p'):
1053 if (change_case)
1055 to_uppcase = 0;
1056 to_lowcase = 1;
1058 #if defined _NL_CURRENT || !HAVE_STRFTIME
1059 cpy (ap_len, ampm);
1060 break;
1061 #else
1062 goto underlying_strftime;
1063 #endif
1065 case L_('R'): /* GNU extension. */
1066 subfmt = L_("%H:%M");
1067 goto subformat;
1069 case L_('r'): /* POSIX.2 extension. */
1070 #ifdef _NL_CURRENT
1071 if (*(subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME,
1072 NLW(T_FMT_AMPM))) == L_('\0'))
1073 #endif
1074 subfmt = L_("%I:%M:%S %p");
1075 goto subformat;
1077 case L_('S'):
1078 if (modifier == L_('E'))
1079 goto bad_format;
1081 DO_NUMBER (2, tp->tm_sec);
1083 case L_('s'): /* GNU extension. */
1085 struct tm ltm;
1086 time_t t;
1088 ltm = *tp;
1089 t = mktime (&ltm);
1091 /* Generate string value for T using time_t arithmetic;
1092 this works even if sizeof (long) < sizeof (time_t). */
1094 bufp = buf + sizeof (buf) / sizeof (buf[0]);
1095 negative_number = t < 0;
1099 int d = t % 10;
1100 t /= 10;
1102 if (negative_number)
1104 d = -d;
1106 /* Adjust if division truncates to minus infinity. */
1107 if (0 < -1 % 10 && d < 0)
1109 t++;
1110 d += 10;
1114 *--bufp = d + L_('0');
1116 while (t != 0);
1118 digits = 1;
1119 goto do_number_sign_and_padding;
1122 case L_('X'):
1123 if (modifier == L_('O'))
1124 goto bad_format;
1125 #ifdef _NL_CURRENT
1126 if (! (modifier == L_('E')
1127 && (*(subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME,
1128 NLW(ERA_T_FMT)))
1129 != L_('\0'))))
1130 subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
1131 goto subformat;
1132 #else
1133 # if HAVE_STRFTIME
1134 goto underlying_strftime;
1135 # else
1136 /* Fall through. */
1137 # endif
1138 #endif
1139 case L_('T'): /* POSIX.2 extension. */
1140 subfmt = L_("%H:%M:%S");
1141 goto subformat;
1143 case L_('t'): /* POSIX.2 extension. */
1144 add (1, *p = L_('\t'));
1145 break;
1147 case L_('u'): /* POSIX.2 extension. */
1148 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1150 case L_('U'):
1151 if (modifier == L_('E'))
1152 goto bad_format;
1154 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1156 case L_('V'):
1157 case L_('g'): /* GNU extension. */
1158 case L_('G'): /* GNU extension. */
1159 if (modifier == L_('E'))
1160 goto bad_format;
1162 int year = tp->tm_year + TM_YEAR_BASE;
1163 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1165 if (days < 0)
1167 /* This ISO week belongs to the previous year. */
1168 year--;
1169 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
1170 tp->tm_wday);
1172 else
1174 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1175 tp->tm_wday);
1176 if (0 <= d)
1178 /* This ISO week belongs to the next year. */
1179 year++;
1180 days = d;
1184 switch (*f)
1186 case L_('g'):
1187 DO_NUMBER (2, (year % 100 + 100) % 100);
1189 case L_('G'):
1190 DO_NUMBER (1, year);
1192 default:
1193 DO_NUMBER (2, days / 7 + 1);
1197 case L_('W'):
1198 if (modifier == L_('E'))
1199 goto bad_format;
1201 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1203 case L_('w'):
1204 if (modifier == L_('E'))
1205 goto bad_format;
1207 DO_NUMBER (1, tp->tm_wday);
1209 case L_('Y'):
1210 if (modifier == 'E')
1212 #if HAVE_STRUCT_ERA_ENTRY
1213 struct era_entry *era = _nl_get_era_entry (tp);
1214 if (era)
1216 # ifdef COMPILE_WIDE
1217 subfmt = era->era_wformat;
1218 # else
1219 subfmt = era->era_format;
1220 # endif
1221 goto subformat;
1223 #else
1224 # if HAVE_STRFTIME
1225 goto underlying_strftime;
1226 # endif
1227 #endif
1229 if (modifier == L_('O'))
1230 goto bad_format;
1231 else
1232 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1234 case L_('y'):
1235 if (modifier == L_('E'))
1237 #if HAVE_STRUCT_ERA_ENTRY
1238 struct era_entry *era = _nl_get_era_entry (tp);
1239 if (era)
1241 int delta = tp->tm_year - era->start_date[0];
1242 DO_NUMBER (1, (era->offset
1243 + delta * era->absolute_direction));
1245 #else
1246 # if HAVE_STRFTIME
1247 goto underlying_strftime;
1248 # endif
1249 #endif
1251 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1253 case L_('Z'):
1254 if (change_case)
1256 to_uppcase = 0;
1257 to_lowcase = 1;
1260 #if HAVE_TZNAME
1261 /* The tzset() call might have changed the value. */
1262 if (!(zone && *zone) && tp->tm_isdst >= 0)
1263 zone = tzname[tp->tm_isdst];
1264 #endif
1265 if (! zone)
1266 zone = ""; /* POSIX.2 requires the empty string here. */
1268 #ifdef COMPILE_WIDE
1270 /* The zone string is always given in multibyte form. We have
1271 to transform it first. */
1272 wchar_t *wczone;
1273 size_t len;
1274 widen (zone, wczone, len);
1275 cpy (len, wczone);
1277 #else
1278 cpy (strlen (zone), zone);
1279 #endif
1280 break;
1282 case L_('z'): /* GNU extension. */
1283 if (tp->tm_isdst < 0)
1284 break;
1287 int diff;
1288 #if HAVE_TM_GMTOFF
1289 diff = tp->tm_gmtoff;
1290 #else
1291 if (ut)
1292 diff = 0;
1293 else
1295 struct tm gtm;
1296 struct tm ltm;
1297 time_t lt;
1299 ltm = *tp;
1300 lt = mktime (&ltm);
1302 if (lt == (time_t) -1)
1304 /* mktime returns -1 for errors, but -1 is also a
1305 valid time_t value. Check whether an error really
1306 occurred. */
1307 struct tm tm;
1309 if (! my_strftime_localtime_r (&lt, &tm)
1310 || ((ltm.tm_sec ^ tm.tm_sec)
1311 | (ltm.tm_min ^ tm.tm_min)
1312 | (ltm.tm_hour ^ tm.tm_hour)
1313 | (ltm.tm_mday ^ tm.tm_mday)
1314 | (ltm.tm_mon ^ tm.tm_mon)
1315 | (ltm.tm_year ^ tm.tm_year)))
1316 break;
1319 if (! my_strftime_gmtime_r (&lt, &gtm))
1320 break;
1322 diff = tm_diff (&ltm, &gtm);
1324 #endif
1326 if (diff < 0)
1328 add (1, *p = L_('-'));
1329 diff = -diff;
1331 else
1332 add (1, *p = L_('+'));
1334 diff /= 60;
1335 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1338 case L_('\0'): /* GNU extension: % at end of format. */
1339 --f;
1340 /* Fall through. */
1341 default:
1342 /* Unknown format; output the format, including the '%',
1343 since this is most likely the right thing to do if a
1344 multibyte string has been misparsed. */
1345 bad_format:
1347 int flen;
1348 for (flen = 1; f[1 - flen] != L_('%'); flen++)
1349 continue;
1350 cpy (flen, &f[1 - flen]);
1352 break;
1356 if (p && maxsize != 0)
1357 *p = L_('\0');
1358 return i;
1362 #ifdef emacs
1363 /* For Emacs we have a separate interface which corresponds to the normal
1364 strftime function and does not have the extra information whether the
1365 TP arguments comes from a `gmtime' call or not. */
1366 size_t
1367 emacs_strftime (s, maxsize, format, tp)
1368 char *s;
1369 size_t maxsize;
1370 const char *format;
1371 const struct tm *tp;
1373 return my_strftime (s, maxsize, format, tp, 0);
1375 #endif