fix typos
[coreutils.git] / lib / strftime.c
blob45173dce35b7d3a0fa7e9fb04850f7743b16b7cc
1 /* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
3 NOTE: The canonical source of this file is maintained with the GNU C Library.
4 Bugs can be reported to bug-glibc@prep.ai.mit.edu.
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 USA. */
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
25 #ifdef _LIBC
26 # define HAVE_LIMITS_H 1
27 # define HAVE_MBLEN 1
28 # define HAVE_MBRLEN 1
29 # define HAVE_STRUCT_ERA_ENTRY 1
30 # define HAVE_TM_GMTOFF 1
31 # define HAVE_TM_ZONE 1
32 # define HAVE_TZNAME 1
33 # define HAVE_TZSET 1
34 # define MULTIBYTE_IS_FORMAT_SAFE 1
35 # define STDC_HEADERS 1
36 # include "../locale/localeinfo.h"
37 #endif
39 #if defined emacs && !defined HAVE_BCOPY
40 # define HAVE_MEMCPY 1
41 #endif
43 #include <ctype.h>
44 #include <sys/types.h> /* Some systems define `time_t' here. */
46 #ifdef TIME_WITH_SYS_TIME
47 # include <sys/time.h>
48 # include <time.h>
49 #else
50 # ifdef HAVE_SYS_TIME_H
51 # include <sys/time.h>
52 # else
53 # include <time.h>
54 # endif
55 #endif
56 #if HAVE_TZNAME
57 extern char *tzname[];
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 __GNUC__ || (defined __STDC__ && __STDC__)
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 (const time_t *t, struct tm *tp)
162 struct tm *l = gmtime (t);
163 if (! l)
164 return 0;
165 *tp = *l;
166 return tp;
168 # endif /* ! HAVE_TM_GMTOFF */
170 static struct tm *my_strftime_localtime_r __P ((const time_t *, struct tm *));
171 static struct tm *
172 my_strftime_localtime_r (const time_t *t, struct tm *tp)
174 struct tm *l = localtime (t);
175 if (! l)
176 return 0;
177 *tp = *l;
178 return tp;
180 #endif /* ! defined _LIBC */
183 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
184 /* Some systems lack the `memset' function and we don't want to
185 introduce additional dependencies. */
186 /* The SGI compiler reportedly barfs on the trailing null
187 if we use a string constant as the initializer. 28 June 1997, rms. */
188 static const char spaces[16] = /* " " */
189 { ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
190 static const char zeroes[16] = /* "0000000000000000" */
191 { '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' };
193 # define memset_space(P, Len) \
194 do { \
195 int _len = (Len); \
197 do \
199 int _this = _len > 16 ? 16 : _len; \
200 (P) = MEMPCPY ((P), spaces, _this); \
201 _len -= _this; \
203 while (_len > 0); \
204 } while (0)
206 # define memset_zero(P, Len) \
207 do { \
208 int _len = (Len); \
210 do \
212 int _this = _len > 16 ? 16 : _len; \
213 (P) = MEMPCPY ((P), zeroes, _this); \
214 _len -= _this; \
216 while (_len > 0); \
217 } while (0)
218 #else
219 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
220 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
221 #endif
223 #define add(n, f) \
224 do \
226 int _n = (n); \
227 int _delta = width - _n; \
228 int _incr = _n + (_delta > 0 ? _delta : 0); \
229 if (i + _incr >= maxsize) \
230 return 0; \
231 if (p) \
233 if (_delta > 0) \
235 if (pad == '0') \
236 memset_zero (p, _delta); \
237 else \
238 memset_space (p, _delta); \
240 f; \
241 p += _n; \
243 i += _incr; \
244 } while (0)
246 #define cpy(n, s) \
247 add ((n), \
248 if (to_lowcase) \
249 memcpy_lowcase (p, (s), _n); \
250 else if (to_uppcase) \
251 memcpy_uppcase (p, (s), _n); \
252 else \
253 memcpy ((PTR) p, (PTR) (s), _n))
257 #ifdef _LIBC
258 # define TOUPPER(Ch) toupper (Ch)
259 # define TOLOWER(Ch) tolower (Ch)
260 #else
261 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
262 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
263 #endif
264 /* We don't use `isdigit' here since the locale dependent
265 interpretation is not what we want here. We only need to accept
266 the arabic digits in the ASCII range. One day there is perhaps a
267 more reliable way to accept other sets of digits. */
268 #define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
270 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
272 static char *
273 memcpy_lowcase (char *dest, const char *src, size_t len)
275 while (len-- > 0)
276 dest[len] = TOLOWER ((unsigned char) src[len]);
277 return dest;
280 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
282 static char *
283 memcpy_uppcase (char *dest, const char *src, size_t len)
285 while (len-- > 0)
286 dest[len] = TOUPPER ((unsigned char) src[len]);
287 return dest;
291 #if ! HAVE_TM_GMTOFF
292 /* Yield the difference between *A and *B,
293 measured in seconds, ignoring leap seconds. */
294 # define tm_diff ftime_tm_diff
295 static int tm_diff __P ((const struct tm *, const struct tm *));
296 static int
297 tm_diff (const struct tm *a, const struct tm *b)
299 /* Compute intervening leap days correctly even if year is negative.
300 Take care to avoid int overflow in leap day calculations,
301 but it's OK to assume that A and B are close to each other. */
302 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
303 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
304 int a100 = a4 / 25 - (a4 % 25 < 0);
305 int b100 = b4 / 25 - (b4 % 25 < 0);
306 int a400 = a100 >> 2;
307 int b400 = b100 >> 2;
308 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
309 int years = a->tm_year - b->tm_year;
310 int days = (365 * years + intervening_leap_days
311 + (a->tm_yday - b->tm_yday));
312 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
313 + (a->tm_min - b->tm_min))
314 + (a->tm_sec - b->tm_sec));
316 #endif /* ! HAVE_TM_GMTOFF */
320 /* The number of days from the first day of the first ISO week of this
321 year to the year day YDAY with week day WDAY. ISO weeks start on
322 Monday; the first ISO week has the year's first Thursday. YDAY may
323 be as small as YDAY_MINIMUM. */
324 #define ISO_WEEK_START_WDAY 1 /* Monday */
325 #define ISO_WEEK1_WDAY 4 /* Thursday */
326 #define YDAY_MINIMUM (-366)
327 static int iso_week_days __P ((int, int));
328 #ifdef __GNUC__
329 __inline__
330 #endif
331 static int
332 iso_week_days (int yday, int wday)
334 /* Add enough to the first operand of % to make it nonnegative. */
335 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
336 return (yday
337 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
338 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
342 #if !(defined _NL_CURRENT || HAVE_STRFTIME)
343 static char const weekday_name[][10] =
345 "Sunday", "Monday", "Tuesday", "Wednesday",
346 "Thursday", "Friday", "Saturday"
348 static char const month_name[][10] =
350 "January", "February", "March", "April", "May", "June",
351 "July", "August", "September", "October", "November", "December"
353 #endif
356 #ifdef emacs
357 # define my_strftime emacs_strftimeu
358 # define ut_argument , ut
359 # define ut_argument_spec int ut;
360 # define ut_argument_spec_iso , int ut
361 #else
362 # define my_strftime strftime
363 # define ut_argument
364 # define ut_argument_spec
365 # define ut_argument_spec_iso
366 /* We don't have this information in general. */
367 # define ut 0
368 #endif
370 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
371 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
372 Work around this bug by copying *tp before it might be munged. */
373 size_t _strftime_copytm __P ((char *, size_t, const char *,
374 const struct tm * ut_argument_spec_iso));
375 size_t
376 my_strftime (s, maxsize, format, tp ut_argument)
377 char *s;
378 size_t maxsize;
379 const char *format;
380 const struct tm *tp;
381 ut_argument_spec
383 struct tm tmcopy;
384 tmcopy = *tp;
385 return _strftime_copytm (s, maxsize, format, &tmcopy ut_argument);
387 # undef my_strftime
388 # define my_strftime(S, Maxsize, Format, Tp) \
389 _strftime_copytm (S, Maxsize, Format, Tp)
390 #endif
393 /* Write information from TP into S according to the format
394 string FORMAT, writing no more that MAXSIZE characters
395 (including the terminating '\0') and returning number of
396 characters written. If S is NULL, nothing will be written
397 anywhere, so to determine how many characters would be
398 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
399 size_t
400 my_strftime (char *s, size_t maxsize, const char *format, const struct tm *tp
401 ut_argument_spec)
403 int hour12 = tp->tm_hour;
404 #ifdef _NL_CURRENT
405 /* We cannot make the following values variables since we must delay
406 the evaluation of these values until really needed since some
407 expressions might not be valid in every situation. The `struct tm'
408 might be generated by a strptime() call that initialized
409 only a few elements. Dereference the pointers only if the format
410 requires this. Then it is ok to fail if the pointers are invalid. */
411 # define a_wkday _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday)
412 # define f_wkday _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday)
413 # define a_month _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon)
414 # define f_month _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon)
415 # define ampm _NL_CURRENT (LC_TIME, tp->tm_hour > 11 ? PM_STR : AM_STR)
417 # define aw_len strlen (a_wkday)
418 # define am_len strlen (a_month)
419 # define ap_len strlen (ampm)
420 #else
421 # if !HAVE_STRFTIME
422 # define f_wkday (weekday_name[tp->tm_wday])
423 # define f_month (month_name[tp->tm_mon])
424 # define a_wkday f_wkday
425 # define a_month f_month
426 # define ampm ("AMPM" + 2 * (tp->tm_hour > 11))
428 size_t aw_len = 3;
429 size_t am_len = 3;
430 size_t ap_len = 2;
431 # endif
432 #endif
433 const char *zone;
434 size_t i = 0;
435 char *p = s;
436 const char *f;
438 zone = NULL;
439 #if HAVE_TM_ZONE
440 /* The POSIX test suite assumes that setting
441 the environment variable TZ to a new value before calling strftime()
442 will influence the result (the %Z format) even if the information in
443 TP is computed with a totally different time zone.
444 This is bogus: though POSIX allows bad behavior like this,
445 POSIX does not require it. Do the right thing instead. */
446 zone = (const char *) tp->tm_zone;
447 #endif
448 #if HAVE_TZNAME
449 if (ut)
451 if (! (zone && *zone))
452 zone = "GMT";
454 else
456 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
457 time zone names contained in the external variable `tzname' shall
458 be set as if the tzset() function had been called. */
459 # if HAVE_TZSET
460 tzset ();
461 # endif
463 #endif
465 if (hour12 > 12)
466 hour12 -= 12;
467 else
468 if (hour12 == 0)
469 hour12 = 12;
471 for (f = format; *f != '\0'; ++f)
473 int pad = 0; /* Padding for number ('-', '_', or 0). */
474 int modifier; /* Field modifier ('E', 'O', or 0). */
475 int digits; /* Max digits for numeric format. */
476 int number_value; /* Numeric value to be printed. */
477 int negative_number; /* 1 if the number is negative. */
478 const char *subfmt;
479 char *bufp;
480 char buf[1 + (sizeof (int) < sizeof (time_t)
481 ? INT_STRLEN_BOUND (time_t)
482 : INT_STRLEN_BOUND (int))];
483 int width = -1;
484 int to_lowcase = 0;
485 int to_uppcase = 0;
486 int change_case = 0;
487 int format_char;
489 #if DO_MULTIBYTE
491 switch (*f)
493 case '%':
494 break;
496 case '\a': case '\b': case '\t': case '\n':
497 case '\v': case '\f': case '\r':
498 case ' ': case '!': case '"': case '#': case '&': case'\'':
499 case '(': case ')': case '*': case '+': case ',': case '-':
500 case '.': case '/': case '0': case '1': case '2': case '3':
501 case '4': case '5': case '6': case '7': case '8': case '9':
502 case ':': case ';': case '<': case '=': case '>': case '?':
503 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
504 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
505 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
506 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
507 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
508 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
509 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
510 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
511 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
512 case 'x': case 'y': case 'z': case '{': case '|': case '}':
513 case '~':
514 /* The C Standard requires these 98 characters (plus '%') to
515 be in the basic execution character set. None of these
516 characters can start a multibyte sequence, so they need
517 not be analyzed further. */
518 add (1, *p = *f);
519 continue;
521 default:
522 /* Copy this multibyte sequence until we reach its end, find
523 an error, or come back to the initial shift state. */
525 mbstate_t mbstate = mbstate_zero;
526 size_t len = 0;
530 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
532 if (bytes == 0)
533 break;
535 if (bytes == (size_t) -2)
537 len += strlen (f + len);
538 break;
541 if (bytes == (size_t) -1)
543 len++;
544 break;
547 len += bytes;
549 while (! mbsinit (&mbstate));
551 cpy (len, f);
552 f += len - 1;
553 continue;
557 #else /* ! DO_MULTIBYTE */
559 /* Either multibyte encodings are not supported, or they are
560 safe for formats, so any non-'%' byte can be copied through. */
561 if (*f != '%')
563 add (1, *p = *f);
564 continue;
567 #endif /* ! DO_MULTIBYTE */
569 /* Check for flags that can modify a format. */
570 while (1)
572 switch (*++f)
574 /* This influences the number formats. */
575 case '_':
576 case '-':
577 case '0':
578 pad = *f;
579 continue;
581 /* This changes textual output. */
582 case '^':
583 to_uppcase = 1;
584 continue;
585 case '#':
586 change_case = 1;
587 continue;
589 default:
590 break;
592 break;
595 /* As a GNU extension we allow to specify the field width. */
596 if (ISDIGIT (*f))
598 width = 0;
601 width *= 10;
602 width += *f - '0';
603 ++f;
605 while (ISDIGIT (*f));
608 /* Check for modifiers. */
609 switch (*f)
611 case 'E':
612 case 'O':
613 modifier = *f++;
614 break;
616 default:
617 modifier = 0;
618 break;
621 /* Now do the specified format. */
622 format_char = *f;
623 switch (format_char)
625 #define DO_NUMBER(d, v) \
626 digits = width == -1 ? d : width; \
627 number_value = v; goto do_number
628 #define DO_NUMBER_SPACEPAD(d, v) \
629 digits = width == -1 ? d : width; \
630 number_value = v; goto do_number_spacepad
632 case '%':
633 if (modifier != 0)
634 goto bad_format;
635 add (1, *p = *f);
636 break;
638 case 'a':
639 if (modifier != 0)
640 goto bad_format;
641 if (change_case)
643 to_uppcase = 1;
644 to_lowcase = 0;
646 #if defined _NL_CURRENT || !HAVE_STRFTIME
647 cpy (aw_len, a_wkday);
648 break;
649 #else
650 goto underlying_strftime;
651 #endif
653 case 'A':
654 if (modifier != 0)
655 goto bad_format;
656 if (change_case)
658 to_uppcase = 1;
659 to_lowcase = 0;
661 #if defined _NL_CURRENT || !HAVE_STRFTIME
662 cpy (strlen (f_wkday), f_wkday);
663 break;
664 #else
665 goto underlying_strftime;
666 #endif
668 case 'b':
669 case 'h': /* POSIX.2 extension. */
670 if (modifier != 0)
671 goto bad_format;
672 #if defined _NL_CURRENT || !HAVE_STRFTIME
673 cpy (am_len, a_month);
674 break;
675 #else
676 goto underlying_strftime;
677 #endif
679 case 'B':
680 if (modifier != 0)
681 goto bad_format;
682 if (change_case)
684 to_uppcase = 1;
685 to_lowcase = 0;
687 #if defined _NL_CURRENT || !HAVE_STRFTIME
688 cpy (strlen (f_month), f_month);
689 break;
690 #else
691 goto underlying_strftime;
692 #endif
694 case 'c':
695 if (modifier == 'O')
696 goto bad_format;
697 #ifdef _NL_CURRENT
698 if (! (modifier == 'E'
699 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
700 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
701 #else
702 # if HAVE_STRFTIME
703 goto underlying_strftime;
704 # else
705 subfmt = "%a %b %e %H:%M:%S %Y";
706 # endif
707 #endif
709 subformat:
711 char *old_start = p;
712 size_t len = my_strftime (NULL, (size_t) -1, subfmt, tp);
713 add (len, my_strftime (p, maxsize - i, subfmt, tp));
715 if (to_uppcase)
716 while (old_start < p)
718 *old_start = TOUPPER ((unsigned char) *old_start);
719 ++old_start;
722 break;
724 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
725 underlying_strftime:
727 /* The relevant information is available only via the
728 underlying strftime implementation, so use that. */
729 char ufmt[4];
730 char *u = ufmt;
731 char ubuf[1024]; /* enough for any single format in practice */
732 size_t len;
733 *u++ = '%';
734 if (modifier != 0)
735 *u++ = modifier;
736 *u++ = format_char;
737 *u = '\0';
738 len = strftime (ubuf, sizeof ubuf, ufmt, tp);
739 if (len == 0 && ubuf[0] != '\0')
740 return 0;
741 cpy (len, ubuf);
743 break;
744 #endif
746 case 'C': /* POSIX.2 extension. */
747 if (modifier == 'O')
748 goto bad_format;
749 if (modifier == 'E')
751 #if HAVE_STRUCT_ERA_ENTRY
752 struct era_entry *era = _nl_get_era_entry (tp);
753 if (era)
755 size_t len = strlen (era->name_fmt);
756 cpy (len, era->name_fmt);
757 break;
759 #else
760 # if HAVE_STRFTIME
761 goto underlying_strftime;
762 # endif
763 #endif
767 int year = tp->tm_year + TM_YEAR_BASE;
768 DO_NUMBER (1, year / 100 - (year % 100 < 0));
771 case 'x':
772 if (modifier == 'O')
773 goto bad_format;
774 #ifdef _NL_CURRENT
775 if (! (modifier == 'E'
776 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
777 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
778 goto subformat;
779 #else
780 # if HAVE_STRFTIME
781 goto underlying_strftime;
782 # else
783 /* Fall through. */
784 # endif
785 #endif
786 case 'D': /* POSIX.2 extension. */
787 if (modifier != 0)
788 goto bad_format;
789 subfmt = "%m/%d/%y";
790 goto subformat;
792 case 'd':
793 if (modifier == 'E')
794 goto bad_format;
796 DO_NUMBER (2, tp->tm_mday);
798 case 'e': /* POSIX.2 extension. */
799 if (modifier == 'E')
800 goto bad_format;
802 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
804 /* All numeric formats set DIGITS and NUMBER_VALUE and then
805 jump to one of these two labels. */
807 do_number_spacepad:
808 /* Force `_' flag unless overwritten by `0' flag. */
809 if (pad != '0')
810 pad = '_';
812 do_number:
813 /* Format the number according to the MODIFIER flag. */
815 if (modifier == 'O' && 0 <= number_value)
817 #ifdef _NL_CURRENT
818 /* Get the locale specific alternate representation of
819 the number NUMBER_VALUE. If none exist NULL is returned. */
820 const char *cp = _nl_get_alt_digit (number_value);
822 if (cp != NULL)
824 size_t digitlen = strlen (cp);
825 if (digitlen != 0)
827 cpy (digitlen, cp);
828 break;
831 #else
832 # if HAVE_STRFTIME
833 goto underlying_strftime;
834 # endif
835 #endif
838 unsigned int u = number_value;
840 bufp = buf + sizeof (buf);
841 negative_number = number_value < 0;
843 if (negative_number)
844 u = -u;
847 *--bufp = u % 10 + '0';
848 while ((u /= 10) != 0);
851 do_number_sign_and_padding:
852 if (negative_number)
853 *--bufp = '-';
855 if (pad != '-')
857 int padding = digits - (buf + sizeof (buf) - bufp);
859 if (pad == '_')
861 while (0 < padding--)
862 *--bufp = ' ';
864 else
866 bufp += negative_number;
867 while (0 < padding--)
868 *--bufp = '0';
869 if (negative_number)
870 *--bufp = '-';
874 cpy (buf + sizeof (buf) - bufp, bufp);
875 break;
877 case 'F':
878 if (modifier != 0)
879 goto bad_format;
880 subfmt = "%Y-%m-%d";
881 goto subformat;
883 case 'H':
884 if (modifier == 'E')
885 goto bad_format;
887 DO_NUMBER (2, tp->tm_hour);
889 case 'I':
890 if (modifier == 'E')
891 goto bad_format;
893 DO_NUMBER (2, hour12);
895 case 'k': /* GNU extension. */
896 if (modifier == 'E')
897 goto bad_format;
899 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
901 case 'l': /* GNU extension. */
902 if (modifier == 'E')
903 goto bad_format;
905 DO_NUMBER_SPACEPAD (2, hour12);
907 case 'j':
908 if (modifier == 'E')
909 goto bad_format;
911 DO_NUMBER (3, 1 + tp->tm_yday);
913 case 'M':
914 if (modifier == 'E')
915 goto bad_format;
917 DO_NUMBER (2, tp->tm_min);
919 case 'm':
920 if (modifier == 'E')
921 goto bad_format;
923 DO_NUMBER (2, tp->tm_mon + 1);
925 case 'n': /* POSIX.2 extension. */
926 add (1, *p = '\n');
927 break;
929 case 'P':
930 to_lowcase = 1;
931 #if !defined _NL_CURRENT && HAVE_STRFTIME
932 format_char = 'p';
933 #endif
934 /* FALLTHROUGH */
936 case 'p':
937 if (change_case)
939 to_uppcase = 0;
940 to_lowcase = 1;
942 #if defined _NL_CURRENT || !HAVE_STRFTIME
943 cpy (ap_len, ampm);
944 break;
945 #else
946 goto underlying_strftime;
947 #endif
949 case 'R': /* GNU extension. */
950 subfmt = "%H:%M";
951 goto subformat;
953 case 'r': /* POSIX.2 extension. */
954 #ifdef _NL_CURRENT
955 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
956 #endif
957 subfmt = "%I:%M:%S %p";
958 goto subformat;
960 case 'S':
961 if (modifier == 'E')
962 goto bad_format;
964 DO_NUMBER (2, tp->tm_sec);
966 case 's': /* GNU extension. */
968 struct tm ltm;
969 time_t t;
971 ltm = *tp;
972 t = mktime (&ltm);
974 /* Generate string value for T using time_t arithmetic;
975 this works even if sizeof (long) < sizeof (time_t). */
977 bufp = buf + sizeof (buf);
978 negative_number = t < 0;
982 int d = t % 10;
983 t /= 10;
985 if (negative_number)
987 d = -d;
989 /* Adjust if division truncates to minus infinity. */
990 if (0 < -1 % 10 && d < 0)
992 t++;
993 d += 10;
997 *--bufp = d + '0';
999 while (t != 0);
1001 digits = 1;
1002 goto do_number_sign_and_padding;
1005 case 'X':
1006 if (modifier == 'O')
1007 goto bad_format;
1008 #ifdef _NL_CURRENT
1009 if (! (modifier == 'E'
1010 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
1011 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
1012 goto subformat;
1013 #else
1014 # if HAVE_STRFTIME
1015 goto underlying_strftime;
1016 # else
1017 /* Fall through. */
1018 # endif
1019 #endif
1020 case 'T': /* POSIX.2 extension. */
1021 subfmt = "%H:%M:%S";
1022 goto subformat;
1024 case 't': /* POSIX.2 extension. */
1025 add (1, *p = '\t');
1026 break;
1028 case 'u': /* POSIX.2 extension. */
1029 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1031 case 'U':
1032 if (modifier == 'E')
1033 goto bad_format;
1035 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1037 case 'V':
1038 case 'g': /* GNU extension. */
1039 case 'G': /* GNU extension. */
1040 if (modifier == 'E')
1041 goto bad_format;
1043 int year = tp->tm_year + TM_YEAR_BASE;
1044 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1046 if (days < 0)
1048 /* This ISO week belongs to the previous year. */
1049 year--;
1050 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
1051 tp->tm_wday);
1053 else
1055 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1056 tp->tm_wday);
1057 if (0 <= d)
1059 /* This ISO week belongs to the next year. */
1060 year++;
1061 days = d;
1065 switch (*f)
1067 case 'g':
1068 DO_NUMBER (2, (year % 100 + 100) % 100);
1070 case 'G':
1071 DO_NUMBER (1, year);
1073 default:
1074 DO_NUMBER (2, days / 7 + 1);
1078 case 'W':
1079 if (modifier == 'E')
1080 goto bad_format;
1082 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1084 case 'w':
1085 if (modifier == 'E')
1086 goto bad_format;
1088 DO_NUMBER (1, tp->tm_wday);
1090 case 'Y':
1091 if (modifier == 'E')
1093 #if HAVE_STRUCT_ERA_ENTRY
1094 struct era_entry *era = _nl_get_era_entry (tp);
1095 if (era)
1097 subfmt = strchr (era->name_fmt, '\0') + 1;
1098 goto subformat;
1100 #else
1101 # if HAVE_STRFTIME
1102 goto underlying_strftime;
1103 # endif
1104 #endif
1106 if (modifier == 'O')
1107 goto bad_format;
1108 else
1109 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1111 case 'y':
1112 if (modifier == 'E')
1114 #if HAVE_STRUCT_ERA_ENTRY
1115 struct era_entry *era = _nl_get_era_entry (tp);
1116 if (era)
1118 int delta = tp->tm_year - era->start_date[0];
1119 DO_NUMBER (1, (era->offset
1120 + (era->direction == '-' ? -delta : delta)));
1122 #else
1123 # if HAVE_STRFTIME
1124 goto underlying_strftime;
1125 # endif
1126 #endif
1128 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1130 case 'Z':
1131 if (change_case)
1133 to_uppcase = 0;
1134 to_lowcase = 1;
1137 #if HAVE_TZNAME
1138 /* The tzset() call might have changed the value. */
1139 if (!(zone && *zone) && tp->tm_isdst >= 0)
1140 zone = tzname[tp->tm_isdst];
1141 #endif
1142 if (! zone)
1143 zone = ""; /* POSIX.2 requires the empty string here. */
1145 cpy (strlen (zone), zone);
1146 break;
1148 case 'z': /* GNU extension. */
1149 if (tp->tm_isdst < 0)
1150 break;
1153 int diff;
1154 #if HAVE_TM_GMTOFF
1155 diff = tp->tm_gmtoff;
1156 #else
1157 if (ut)
1158 diff = 0;
1159 else
1161 struct tm gtm;
1162 struct tm ltm;
1163 time_t lt;
1165 ltm = *tp;
1166 lt = mktime (&ltm);
1168 if (lt == (time_t) -1)
1170 /* mktime returns -1 for errors, but -1 is also a
1171 valid time_t value. Check whether an error really
1172 occurred. */
1173 struct tm tm;
1175 if (! my_strftime_localtime_r (&lt, &tm)
1176 || ((ltm.tm_sec ^ tm.tm_sec)
1177 | (ltm.tm_min ^ tm.tm_min)
1178 | (ltm.tm_hour ^ tm.tm_hour)
1179 | (ltm.tm_mday ^ tm.tm_mday)
1180 | (ltm.tm_mon ^ tm.tm_mon)
1181 | (ltm.tm_year ^ tm.tm_year)))
1182 break;
1185 if (! my_strftime_gmtime_r (&lt, &gtm))
1186 break;
1188 diff = tm_diff (&ltm, &gtm);
1190 #endif
1192 if (diff < 0)
1194 add (1, *p = '-');
1195 diff = -diff;
1197 else
1198 add (1, *p = '+');
1200 diff /= 60;
1201 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1204 case '\0': /* GNU extension: % at end of format. */
1205 --f;
1206 /* Fall through. */
1207 default:
1208 /* Unknown format; output the format, including the '%',
1209 since this is most likely the right thing to do if a
1210 multibyte string has been misparsed. */
1211 bad_format:
1213 int flen;
1214 for (flen = 1; f[1 - flen] != '%'; flen++)
1215 continue;
1216 cpy (flen, &f[1 - flen]);
1218 break;
1222 if (p && maxsize != 0)
1223 *p = '\0';
1224 return i;
1228 #ifdef emacs
1229 /* For Emacs we have a separate interface which corresponds to the normal
1230 strftime function and does not have the extra information whether the
1231 TP arguments comes from a `gmtime' call or not. */
1232 size_t
1233 emacs_strftime (s, maxsize, format, tp)
1234 char *s;
1235 size_t maxsize;
1236 const char *format;
1237 const struct tm *tp;
1239 return my_strftime (s, maxsize, format, tp, 0);
1241 #endif