*** empty log message ***
[emacs.git] / src / strftime.c
blob462e8a2a6c292ad93695fe6173a7d60f6c769997
1 /* Copyright (C) 1991,92,93,94,95,96,97,98 Free Software Foundation, Inc.
2 NOTE: The canonical source of this file is maintained with the GNU C Library.
3 Bugs can be reported to bug-glibc@gnu.org.
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any
8 later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, 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 # else
72 /* Simulate mbrlen with mblen as best we can. */
73 # define mbstate_t int
74 # define mbrlen(s, n, ps) mblen (s, n)
75 # define mbsinit(ps) (*(ps) == 0)
76 # endif
77 static const mbstate_t mbstate_zero;
78 #endif
80 #if HAVE_LIMITS_H
81 # include <limits.h>
82 #endif
84 #if STDC_HEADERS
85 # include <stddef.h>
86 # include <stdlib.h>
87 # include <string.h>
88 #else
89 # ifndef HAVE_MEMCPY
90 # define memcpy(d, s, n) bcopy ((s), (d), (n))
91 # endif
92 #endif
94 #ifdef _LIBC
95 # define MEMPCPY(d, s, n) __mempcpy (d, s, n)
96 #else
97 # ifndef HAVE_MEMPCPY
98 # define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
99 # endif
100 #endif
102 #ifndef __P
103 # if defined (PROTOTYPES)
104 # define __P(args) args
105 # else
106 # define __P(args) ()
107 # endif /* GCC. */
108 #endif /* Not __P. */
110 #ifndef PTR
111 # ifdef __STDC__
112 # define PTR void *
113 # else
114 # define PTR char *
115 # endif
116 #endif
118 #ifndef CHAR_BIT
119 # define CHAR_BIT 8
120 #endif
122 #ifndef NULL
123 # define NULL 0
124 #endif
126 #define TYPE_SIGNED(t) ((t) -1 < 0)
128 /* Bound on length of the string representing an integer value of type t.
129 Subtract one for the sign bit if t is signed;
130 302 / 1000 is log10 (2) rounded up;
131 add one for integer division truncation;
132 add one more for a minus sign if t is signed. */
133 #define INT_STRLEN_BOUND(t) \
134 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t))
136 #define TM_YEAR_BASE 1900
138 #ifndef __isleap
139 /* Nonzero if YEAR is a leap year (every 4 years,
140 except every 100th isn't, and every 400th is). */
141 # define __isleap(year) \
142 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
143 #endif
146 #ifdef _LIBC
147 # define my_strftime_gmtime_r __gmtime_r
148 # define my_strftime_localtime_r __localtime_r
149 # define tzname __tzname
150 # define tzset __tzset
151 #else
153 /* If we're a strftime substitute in a GNU program, then prefer gmtime
154 to gmtime_r, since many gmtime_r implementations are buggy.
155 Similarly for localtime_r. */
157 # if ! HAVE_TM_GMTOFF
158 static struct tm *my_strftime_gmtime_r __P ((const time_t *, struct tm *));
159 static struct tm *
160 my_strftime_gmtime_r (t, tp)
161 const time_t *t;
162 struct tm *tp;
164 struct tm *l = gmtime (t);
165 if (! l)
166 return 0;
167 *tp = *l;
168 return tp;
170 # endif /* ! HAVE_TM_GMTOFF */
172 static struct tm *my_strftime_localtime_r __P ((const time_t *, struct tm *));
173 static struct tm *
174 my_strftime_localtime_r (t, tp)
175 const time_t *t;
176 struct tm *tp;
178 struct tm *l = localtime (t);
179 if (! l)
180 return 0;
181 *tp = *l;
182 return tp;
184 #endif /* ! defined _LIBC */
187 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
188 /* Some systems lack the `memset' function and we don't want to
189 introduce additional dependencies. */
190 /* The SGI compiler reportedly barfs on the trailing null
191 if we use a string constant as the initializer. 28 June 1997, rms. */
192 static const char spaces[16] = /* " " */
193 { ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
194 static const char zeroes[16] = /* "0000000000000000" */
195 { '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' };
197 # define memset_space(P, Len) \
198 do { \
199 int _len = (Len); \
201 do \
203 int _this = _len > 16 ? 16 : _len; \
204 (P) = MEMPCPY ((P), spaces, _this); \
205 _len -= _this; \
207 while (_len > 0); \
208 } while (0)
210 # define memset_zero(P, Len) \
211 do { \
212 int _len = (Len); \
214 do \
216 int _this = _len > 16 ? 16 : _len; \
217 (P) = MEMPCPY ((P), zeroes, _this); \
218 _len -= _this; \
220 while (_len > 0); \
221 } while (0)
222 #else
223 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
224 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
225 #endif
227 #define add(n, f) \
228 do \
230 int _n = (n); \
231 int _delta = width - _n; \
232 int _incr = _n + (_delta > 0 ? _delta : 0); \
233 if (i + _incr >= maxsize) \
234 return 0; \
235 if (p) \
237 if (_delta > 0) \
239 if (pad == '0') \
240 memset_zero (p, _delta); \
241 else \
242 memset_space (p, _delta); \
244 f; \
245 p += _n; \
247 i += _incr; \
248 } while (0)
250 #define cpy(n, s) \
251 add ((n), \
252 if (to_lowcase) \
253 memcpy_lowcase (p, (s), _n); \
254 else if (to_uppcase) \
255 memcpy_uppcase (p, (s), _n); \
256 else \
257 memcpy ((PTR) p, (PTR) (s), _n))
261 #ifdef _LIBC
262 # define TOUPPER(Ch) toupper (Ch)
263 # define TOLOWER(Ch) tolower (Ch)
264 #else
265 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
266 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
267 #endif
268 /* We don't use `isdigit' here since the locale dependent
269 interpretation is not what we want here. We only need to accept
270 the arabic digits in the ASCII range. One day there is perhaps a
271 more reliable way to accept other sets of digits. */
272 #define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
274 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
276 static char *
277 memcpy_lowcase (dest, src, len)
278 char *dest;
279 const char *src;
280 size_t len;
282 while (len-- > 0)
283 dest[len] = TOLOWER ((unsigned char) src[len]);
284 return dest;
287 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
289 static char *
290 memcpy_uppcase (dest, src, len)
291 char *dest;
292 const char *src;
293 size_t len;
295 while (len-- > 0)
296 dest[len] = TOUPPER ((unsigned char) src[len]);
297 return dest;
301 #if ! HAVE_TM_GMTOFF
302 /* Yield the difference between *A and *B,
303 measured in seconds, ignoring leap seconds. */
304 # define tm_diff ftime_tm_diff
305 static int tm_diff __P ((const struct tm *, const struct tm *));
306 static int
307 tm_diff (a, b)
308 const struct tm *a;
309 const struct tm *b;
311 /* Compute intervening leap days correctly even if year is negative.
312 Take care to avoid int overflow in leap day calculations,
313 but it's OK to assume that A and B are close to each other. */
314 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
315 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
316 int a100 = a4 / 25 - (a4 % 25 < 0);
317 int b100 = b4 / 25 - (b4 % 25 < 0);
318 int a400 = a100 >> 2;
319 int b400 = b100 >> 2;
320 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
321 int years = a->tm_year - b->tm_year;
322 int days = (365 * years + intervening_leap_days
323 + (a->tm_yday - b->tm_yday));
324 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
325 + (a->tm_min - b->tm_min))
326 + (a->tm_sec - b->tm_sec));
328 #endif /* ! HAVE_TM_GMTOFF */
332 /* The number of days from the first day of the first ISO week of this
333 year to the year day YDAY with week day WDAY. ISO weeks start on
334 Monday; the first ISO week has the year's first Thursday. YDAY may
335 be as small as YDAY_MINIMUM. */
336 #define ISO_WEEK_START_WDAY 1 /* Monday */
337 #define ISO_WEEK1_WDAY 4 /* Thursday */
338 #define YDAY_MINIMUM (-366)
339 static int iso_week_days __P ((int, int));
340 #ifdef __GNUC__
341 __inline__
342 #endif
343 static int
344 iso_week_days (yday, wday)
345 int yday;
346 int wday;
348 /* Add enough to the first operand of % to make it nonnegative. */
349 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
350 return (yday
351 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
352 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
356 #if !(defined _NL_CURRENT || HAVE_STRFTIME)
357 static char const weekday_name[][10] =
359 "Sunday", "Monday", "Tuesday", "Wednesday",
360 "Thursday", "Friday", "Saturday"
362 static char const month_name[][10] =
364 "January", "February", "March", "April", "May", "June",
365 "July", "August", "September", "October", "November", "December"
367 #endif
370 #ifdef emacs
371 # define my_strftime emacs_strftimeu
372 # define ut_argument , ut
373 # define ut_argument_spec int ut;
374 # define ut_argument_spec_iso , int ut
375 #else
376 # define my_strftime strftime
377 # define ut_argument
378 # define ut_argument_spec
379 # define ut_argument_spec_iso
380 /* We don't have this information in general. */
381 # define ut 0
382 #endif
384 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
385 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
386 Work around this bug by copying *tp before it might be munged. */
387 size_t _strftime_copytm __P ((char *, size_t, const char *,
388 const struct tm * ut_argument_spec_iso));
389 size_t
390 my_strftime (s, maxsize, format, tp ut_argument)
391 char *s;
392 size_t maxsize;
393 const char *format;
394 const struct tm *tp;
395 ut_argument_spec
397 struct tm tmcopy;
398 tmcopy = *tp;
399 return _strftime_copytm (s, maxsize, format, &tmcopy ut_argument);
401 # undef my_strftime
402 # define my_strftime _strftime_copytm
403 #endif
406 /* Write information from TP into S according to the format
407 string FORMAT, writing no more that MAXSIZE characters
408 (including the terminating '\0') and returning number of
409 characters written. If S is NULL, nothing will be written
410 anywhere, so to determine how many characters would be
411 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
412 size_t
413 my_strftime (s, maxsize, format, tp ut_argument)
414 char *s;
415 size_t maxsize;
416 const char *format;
417 const struct tm *tp;
418 ut_argument_spec
420 int hour12 = tp->tm_hour;
421 #ifdef _NL_CURRENT
422 /* We cannot make the following values variables since we must delay
423 the evaluation of these values until really needed since some
424 expressions might not be valid in every situation. The `struct tm'
425 might be generated by a strptime() call that initialized
426 only a few elements. Dereference the pointers only if the format
427 requires this. Then it is ok to fail if the pointers are invalid. */
428 # define a_wkday _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday)
429 # define f_wkday _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday)
430 # define a_month _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon)
431 # define f_month _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon)
432 # define ampm _NL_CURRENT (LC_TIME, tp->tm_hour > 11 ? PM_STR : AM_STR)
434 # define aw_len strlen (a_wkday)
435 # define am_len strlen (a_month)
436 # define ap_len strlen (ampm)
437 #else
438 # if !HAVE_STRFTIME
439 # define f_wkday (weekday_name[tp->tm_wday])
440 # define f_month (month_name[tp->tm_mon])
441 # define a_wkday f_wkday
442 # define a_month f_month
443 # define ampm ("AMPM" + 2 * (tp->tm_hour > 11))
445 size_t aw_len = 3;
446 size_t am_len = 3;
447 size_t ap_len = 2;
448 # endif
449 #endif
450 const char *zone;
451 size_t i = 0;
452 char *p = s;
453 const char *f;
455 zone = NULL;
456 #if HAVE_TM_ZONE
457 /* The POSIX test suite assumes that setting
458 the environment variable TZ to a new value before calling strftime()
459 will influence the result (the %Z format) even if the information in
460 TP is computed with a totally different time zone.
461 This is bogus: though POSIX allows bad behavior like this,
462 POSIX does not require it. Do the right thing instead. */
463 zone = (const char *) tp->tm_zone;
464 #endif
465 #if HAVE_TZNAME
466 if (ut)
468 if (! (zone && *zone))
469 zone = "GMT";
471 else
473 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
474 time zone names contained in the external variable `tzname' shall
475 be set as if the tzset() function had been called. */
476 # if HAVE_TZSET
477 tzset ();
478 # endif
480 #endif
482 if (hour12 > 12)
483 hour12 -= 12;
484 else
485 if (hour12 == 0)
486 hour12 = 12;
488 for (f = format; *f != '\0'; ++f)
490 int pad = 0; /* Padding for number ('-', '_', or 0). */
491 int modifier; /* Field modifier ('E', 'O', or 0). */
492 int digits; /* Max digits for numeric format. */
493 int number_value; /* Numeric value to be printed. */
494 int negative_number; /* 1 if the number is negative. */
495 const char *subfmt;
496 char *bufp;
497 char buf[1 + (sizeof (int) < sizeof (time_t)
498 ? INT_STRLEN_BOUND (time_t)
499 : INT_STRLEN_BOUND (int))];
500 int width = -1;
501 int to_lowcase = 0;
502 int to_uppcase = 0;
503 int change_case = 0;
504 int format_char;
506 #if DO_MULTIBYTE
508 switch (*f)
510 case '%':
511 break;
513 case '\b': case '\t': case '\n':
514 case '\v': case '\f': case '\r':
515 case ' ': case '!': case '"': case '#': case '&': case'\'':
516 case '(': case ')': case '*': case '+': case ',': case '-':
517 case '.': case '/': case '0': case '1': case '2': case '3':
518 case '4': case '5': case '6': case '7': case '8': case '9':
519 case ':': case ';': case '<': case '=': case '>': case '?':
520 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
521 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
522 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
523 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
524 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
525 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
526 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
527 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
528 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
529 case 'x': case 'y': case 'z': case '{': case '|': case '}':
530 case '~':
531 /* The C Standard requires these 97 characters (plus '%', '\a') to
532 be in the basic execution character set. None of these
533 characters can start a multibyte sequence, so they need
534 not be analyzed further. Some old compilers object to
535 '\a', so don't bother optimizing for it. */
536 add (1, *p = *f);
537 continue;
539 default:
540 /* Copy this multibyte sequence until we reach its end, find
541 an error, or come back to the initial shift state. */
543 mbstate_t mbstate = mbstate_zero;
544 size_t len = 0;
548 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
550 if (bytes == 0)
551 break;
553 if (bytes == (size_t) -2)
555 len += strlen (f + len);
556 break;
559 if (bytes == (size_t) -1)
561 len++;
562 break;
565 len += bytes;
567 while (! mbsinit (&mbstate));
569 cpy (len, f);
570 f += len - 1;
571 continue;
575 #else /* ! DO_MULTIBYTE */
577 /* Either multibyte encodings are not supported, or they are
578 safe for formats, so any non-'%' byte can be copied through. */
579 if (*f != '%')
581 add (1, *p = *f);
582 continue;
585 #endif /* ! DO_MULTIBYTE */
587 /* Check for flags that can modify a format. */
588 while (1)
590 switch (*++f)
592 /* This influences the number formats. */
593 case '_':
594 case '-':
595 case '0':
596 pad = *f;
597 continue;
599 /* This changes textual output. */
600 case '^':
601 to_uppcase = 1;
602 continue;
603 case '#':
604 change_case = 1;
605 continue;
607 default:
608 break;
610 break;
613 /* As a GNU extension we allow to specify the field width. */
614 if (ISDIGIT (*f))
616 width = 0;
619 width *= 10;
620 width += *f - '0';
621 ++f;
623 while (ISDIGIT (*f));
626 /* Check for modifiers. */
627 switch (*f)
629 case 'E':
630 case 'O':
631 modifier = *f++;
632 break;
634 default:
635 modifier = 0;
636 break;
639 /* Now do the specified format. */
640 format_char = *f;
641 switch (format_char)
643 #define DO_NUMBER(d, v) \
644 digits = width == -1 ? d : width; \
645 number_value = v; goto do_number
646 #define DO_NUMBER_SPACEPAD(d, v) \
647 digits = width == -1 ? d : width; \
648 number_value = v; goto do_number_spacepad
650 case '%':
651 if (modifier != 0)
652 goto bad_format;
653 add (1, *p = *f);
654 break;
656 case 'a':
657 if (modifier != 0)
658 goto bad_format;
659 if (change_case)
661 to_uppcase = 1;
662 to_lowcase = 0;
664 #if defined _NL_CURRENT || !HAVE_STRFTIME
665 cpy (aw_len, a_wkday);
666 break;
667 #else
668 goto underlying_strftime;
669 #endif
671 case 'A':
672 if (modifier != 0)
673 goto bad_format;
674 if (change_case)
676 to_uppcase = 1;
677 to_lowcase = 0;
679 #if defined _NL_CURRENT || !HAVE_STRFTIME
680 cpy (strlen (f_wkday), f_wkday);
681 break;
682 #else
683 goto underlying_strftime;
684 #endif
686 case 'b':
687 case 'h': /* POSIX.2 extension. */
688 if (modifier != 0)
689 goto bad_format;
690 #if defined _NL_CURRENT || !HAVE_STRFTIME
691 cpy (am_len, a_month);
692 break;
693 #else
694 goto underlying_strftime;
695 #endif
697 case 'B':
698 if (modifier != 0)
699 goto bad_format;
700 if (change_case)
702 to_uppcase = 1;
703 to_lowcase = 0;
705 #if defined _NL_CURRENT || !HAVE_STRFTIME
706 cpy (strlen (f_month), f_month);
707 break;
708 #else
709 goto underlying_strftime;
710 #endif
712 case 'c':
713 if (modifier == 'O')
714 goto bad_format;
715 #ifdef _NL_CURRENT
716 if (! (modifier == 'E'
717 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
718 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
719 #else
720 # if HAVE_STRFTIME
721 goto underlying_strftime;
722 # else
723 subfmt = "%a %b %e %H:%M:%S %Y";
724 # endif
725 #endif
727 subformat:
729 char *old_start = p;
730 size_t len = my_strftime (NULL, (size_t) -1, subfmt,
731 tp ut_argument);
732 add (len, my_strftime (p, maxsize - i, subfmt, tp ut_argument));
734 if (to_uppcase)
735 while (old_start < p)
737 *old_start = TOUPPER ((unsigned char) *old_start);
738 ++old_start;
741 break;
743 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
744 underlying_strftime:
746 /* The relevant information is available only via the
747 underlying strftime implementation, so use that. */
748 char ufmt[4];
749 char *u = ufmt;
750 char ubuf[1024]; /* enough for any single format in practice */
751 size_t len;
752 *u++ = '%';
753 if (modifier != 0)
754 *u++ = modifier;
755 *u++ = format_char;
756 *u = '\0';
757 len = strftime (ubuf, sizeof ubuf, ufmt, tp);
758 if (len == 0 && ubuf[0] != '\0')
759 return 0;
760 cpy (len, ubuf);
762 break;
763 #endif
765 case 'C': /* POSIX.2 extension. */
766 if (modifier == 'O')
767 goto bad_format;
768 if (modifier == 'E')
770 #if HAVE_STRUCT_ERA_ENTRY
771 struct era_entry *era = _nl_get_era_entry (tp);
772 if (era)
774 size_t len = strlen (era->name_fmt);
775 cpy (len, era->name_fmt);
776 break;
778 #else
779 # if HAVE_STRFTIME
780 goto underlying_strftime;
781 # endif
782 #endif
786 int year = tp->tm_year + TM_YEAR_BASE;
787 DO_NUMBER (1, year / 100 - (year % 100 < 0));
790 case 'x':
791 if (modifier == 'O')
792 goto bad_format;
793 #ifdef _NL_CURRENT
794 if (! (modifier == 'E'
795 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
796 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
797 goto subformat;
798 #else
799 # if HAVE_STRFTIME
800 goto underlying_strftime;
801 # else
802 /* Fall through. */
803 # endif
804 #endif
805 case 'D': /* POSIX.2 extension. */
806 if (modifier != 0)
807 goto bad_format;
808 subfmt = "%m/%d/%y";
809 goto subformat;
811 case 'd':
812 if (modifier == 'E')
813 goto bad_format;
815 DO_NUMBER (2, tp->tm_mday);
817 case 'e': /* POSIX.2 extension. */
818 if (modifier == 'E')
819 goto bad_format;
821 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
823 /* All numeric formats set DIGITS and NUMBER_VALUE and then
824 jump to one of these two labels. */
826 do_number_spacepad:
827 /* Force `_' flag unless overwritten by `0' flag. */
828 if (pad != '0')
829 pad = '_';
831 do_number:
832 /* Format the number according to the MODIFIER flag. */
834 if (modifier == 'O' && 0 <= number_value)
836 #ifdef _NL_CURRENT
837 /* Get the locale specific alternate representation of
838 the number NUMBER_VALUE. If none exist NULL is returned. */
839 const char *cp = _nl_get_alt_digit (number_value);
841 if (cp != NULL)
843 size_t digitlen = strlen (cp);
844 if (digitlen != 0)
846 cpy (digitlen, cp);
847 break;
850 #else
851 # if HAVE_STRFTIME
852 goto underlying_strftime;
853 # endif
854 #endif
857 unsigned int u = number_value;
859 bufp = buf + sizeof (buf);
860 negative_number = number_value < 0;
862 if (negative_number)
863 u = -u;
866 *--bufp = u % 10 + '0';
867 while ((u /= 10) != 0);
870 do_number_sign_and_padding:
871 if (negative_number)
872 *--bufp = '-';
874 if (pad != '-')
876 int padding = digits - (buf + sizeof (buf) - bufp);
878 if (pad == '_')
880 while (0 < padding--)
881 *--bufp = ' ';
883 else
885 bufp += negative_number;
886 while (0 < padding--)
887 *--bufp = '0';
888 if (negative_number)
889 *--bufp = '-';
893 cpy (buf + sizeof (buf) - bufp, bufp);
894 break;
896 case 'F':
897 if (modifier != 0)
898 goto bad_format;
899 subfmt = "%Y-%m-%d";
900 goto subformat;
902 case 'H':
903 if (modifier == 'E')
904 goto bad_format;
906 DO_NUMBER (2, tp->tm_hour);
908 case 'I':
909 if (modifier == 'E')
910 goto bad_format;
912 DO_NUMBER (2, hour12);
914 case 'k': /* GNU extension. */
915 if (modifier == 'E')
916 goto bad_format;
918 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
920 case 'l': /* GNU extension. */
921 if (modifier == 'E')
922 goto bad_format;
924 DO_NUMBER_SPACEPAD (2, hour12);
926 case 'j':
927 if (modifier == 'E')
928 goto bad_format;
930 DO_NUMBER (3, 1 + tp->tm_yday);
932 case 'M':
933 if (modifier == 'E')
934 goto bad_format;
936 DO_NUMBER (2, tp->tm_min);
938 case 'm':
939 if (modifier == 'E')
940 goto bad_format;
942 DO_NUMBER (2, tp->tm_mon + 1);
944 case 'n': /* POSIX.2 extension. */
945 add (1, *p = '\n');
946 break;
948 case 'P':
949 to_lowcase = 1;
950 #if !defined _NL_CURRENT && HAVE_STRFTIME
951 format_char = 'p';
952 #endif
953 /* FALLTHROUGH */
955 case 'p':
956 if (change_case)
958 to_uppcase = 0;
959 to_lowcase = 1;
961 #if defined _NL_CURRENT || !HAVE_STRFTIME
962 cpy (ap_len, ampm);
963 break;
964 #else
965 goto underlying_strftime;
966 #endif
968 case 'R': /* GNU extension. */
969 subfmt = "%H:%M";
970 goto subformat;
972 case 'r': /* POSIX.2 extension. */
973 #ifdef _NL_CURRENT
974 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
975 #endif
976 subfmt = "%I:%M:%S %p";
977 goto subformat;
979 case 'S':
980 if (modifier == 'E')
981 goto bad_format;
983 DO_NUMBER (2, tp->tm_sec);
985 case 's': /* GNU extension. */
987 struct tm ltm;
988 time_t t;
990 ltm = *tp;
991 t = mktime (&ltm);
993 /* Generate string value for T using time_t arithmetic;
994 this works even if sizeof (long) < sizeof (time_t). */
996 bufp = buf + sizeof (buf);
997 negative_number = t < 0;
1001 int d = t % 10;
1002 t /= 10;
1004 if (negative_number)
1006 d = -d;
1008 /* Adjust if division truncates to minus infinity. */
1009 if (0 < -1 % 10 && d < 0)
1011 t++;
1012 d += 10;
1016 *--bufp = d + '0';
1018 while (t != 0);
1020 digits = 1;
1021 goto do_number_sign_and_padding;
1024 case 'X':
1025 if (modifier == 'O')
1026 goto bad_format;
1027 #ifdef _NL_CURRENT
1028 if (! (modifier == 'E'
1029 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
1030 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
1031 goto subformat;
1032 #else
1033 # if HAVE_STRFTIME
1034 goto underlying_strftime;
1035 # else
1036 /* Fall through. */
1037 # endif
1038 #endif
1039 case 'T': /* POSIX.2 extension. */
1040 subfmt = "%H:%M:%S";
1041 goto subformat;
1043 case 't': /* POSIX.2 extension. */
1044 add (1, *p = '\t');
1045 break;
1047 case 'u': /* POSIX.2 extension. */
1048 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1050 case 'U':
1051 if (modifier == 'E')
1052 goto bad_format;
1054 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1056 case 'V':
1057 case 'g': /* GNU extension. */
1058 case 'G': /* GNU extension. */
1059 if (modifier == 'E')
1060 goto bad_format;
1062 int year = tp->tm_year + TM_YEAR_BASE;
1063 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1065 if (days < 0)
1067 /* This ISO week belongs to the previous year. */
1068 year--;
1069 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
1070 tp->tm_wday);
1072 else
1074 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1075 tp->tm_wday);
1076 if (0 <= d)
1078 /* This ISO week belongs to the next year. */
1079 year++;
1080 days = d;
1084 switch (*f)
1086 case 'g':
1087 DO_NUMBER (2, (year % 100 + 100) % 100);
1089 case 'G':
1090 DO_NUMBER (1, year);
1092 default:
1093 DO_NUMBER (2, days / 7 + 1);
1097 case 'W':
1098 if (modifier == 'E')
1099 goto bad_format;
1101 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1103 case 'w':
1104 if (modifier == 'E')
1105 goto bad_format;
1107 DO_NUMBER (1, tp->tm_wday);
1109 case 'Y':
1110 if (modifier == 'E')
1112 #if HAVE_STRUCT_ERA_ENTRY
1113 struct era_entry *era = _nl_get_era_entry (tp);
1114 if (era)
1116 subfmt = strchr (era->name_fmt, '\0') + 1;
1117 goto subformat;
1119 #else
1120 # if HAVE_STRFTIME
1121 goto underlying_strftime;
1122 # endif
1123 #endif
1125 if (modifier == 'O')
1126 goto bad_format;
1127 else
1128 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1130 case 'y':
1131 if (modifier == 'E')
1133 #if HAVE_STRUCT_ERA_ENTRY
1134 struct era_entry *era = _nl_get_era_entry (tp);
1135 if (era)
1137 int delta = tp->tm_year - era->start_date[0];
1138 DO_NUMBER (1, (era->offset
1139 + (era->direction == '-' ? -delta : delta)));
1141 #else
1142 # if HAVE_STRFTIME
1143 goto underlying_strftime;
1144 # endif
1145 #endif
1147 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1149 case 'Z':
1150 if (change_case)
1152 to_uppcase = 0;
1153 to_lowcase = 1;
1156 #if HAVE_TZNAME
1157 /* The tzset() call might have changed the value. */
1158 if (!(zone && *zone) && tp->tm_isdst >= 0)
1159 zone = tzname[tp->tm_isdst];
1160 #endif
1161 if (! zone)
1162 zone = ""; /* POSIX.2 requires the empty string here. */
1164 cpy (strlen (zone), zone);
1165 break;
1167 case 'z': /* GNU extension. */
1168 if (tp->tm_isdst < 0)
1169 break;
1172 int diff;
1173 #if HAVE_TM_GMTOFF
1174 diff = tp->tm_gmtoff;
1175 #else
1176 if (ut)
1177 diff = 0;
1178 else
1180 struct tm gtm;
1181 struct tm ltm;
1182 time_t lt;
1184 ltm = *tp;
1185 lt = mktime (&ltm);
1187 if (lt == (time_t) -1)
1189 /* mktime returns -1 for errors, but -1 is also a
1190 valid time_t value. Check whether an error really
1191 occurred. */
1192 struct tm tm;
1194 if (! my_strftime_localtime_r (&lt, &tm)
1195 || ((ltm.tm_sec ^ tm.tm_sec)
1196 | (ltm.tm_min ^ tm.tm_min)
1197 | (ltm.tm_hour ^ tm.tm_hour)
1198 | (ltm.tm_mday ^ tm.tm_mday)
1199 | (ltm.tm_mon ^ tm.tm_mon)
1200 | (ltm.tm_year ^ tm.tm_year)))
1201 break;
1204 if (! my_strftime_gmtime_r (&lt, &gtm))
1205 break;
1207 diff = tm_diff (&ltm, &gtm);
1209 #endif
1211 if (diff < 0)
1213 add (1, *p = '-');
1214 diff = -diff;
1216 else
1217 add (1, *p = '+');
1219 diff /= 60;
1220 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1223 case '\0': /* GNU extension: % at end of format. */
1224 --f;
1225 /* Fall through. */
1226 default:
1227 /* Unknown format; output the format, including the '%',
1228 since this is most likely the right thing to do if a
1229 multibyte string has been misparsed. */
1230 bad_format:
1232 int flen;
1233 for (flen = 1; f[1 - flen] != '%'; flen++)
1234 continue;
1235 cpy (flen, &f[1 - flen]);
1237 break;
1241 if (p && maxsize != 0)
1242 *p = '\0';
1243 return i;