*** empty log message ***
[bpt/emacs.git] / src / strftime.c
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.
4
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.
9
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.
14
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. */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
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
36
37 #if defined emacs && !defined HAVE_BCOPY
38 # define HAVE_MEMCPY 1
39 #endif
40
41 #include <ctype.h>
42 #include <sys/types.h> /* Some systems define `time_t' here. */
43
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
59
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)
67
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
79
80 #if HAVE_LIMITS_H
81 # include <limits.h>
82 #endif
83
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
93
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
101
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. */
109
110 #ifndef PTR
111 # ifdef __STDC__
112 # define PTR void *
113 # else
114 # define PTR char *
115 # endif
116 #endif
117
118 #ifndef CHAR_BIT
119 # define CHAR_BIT 8
120 #endif
121
122 #ifndef NULL
123 # define NULL 0
124 #endif
125
126 #define TYPE_SIGNED(t) ((t) -1 < 0)
127
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))
135
136 #define TM_YEAR_BASE 1900
137
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
144
145
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
152
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. */
156
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;
163 {
164 struct tm *l = gmtime (t);
165 if (! l)
166 return 0;
167 *tp = *l;
168 return tp;
169 }
170 # endif /* ! HAVE_TM_GMTOFF */
171
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;
177 {
178 struct tm *l = localtime (t);
179 if (! l)
180 return 0;
181 *tp = *l;
182 return tp;
183 }
184 #endif /* ! defined _LIBC */
185
186
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' };
196
197 # define memset_space(P, Len) \
198 do { \
199 int _len = (Len); \
200 \
201 do \
202 { \
203 int _this = _len > 16 ? 16 : _len; \
204 (P) = MEMPCPY ((P), spaces, _this); \
205 _len -= _this; \
206 } \
207 while (_len > 0); \
208 } while (0)
209
210 # define memset_zero(P, Len) \
211 do { \
212 int _len = (Len); \
213 \
214 do \
215 { \
216 int _this = _len > 16 ? 16 : _len; \
217 (P) = MEMPCPY ((P), zeroes, _this); \
218 _len -= _this; \
219 } \
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
226
227 #define add(n, f) \
228 do \
229 { \
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) \
236 { \
237 if (_delta > 0) \
238 { \
239 if (pad == '0') \
240 memset_zero (p, _delta); \
241 else \
242 memset_space (p, _delta); \
243 } \
244 f; \
245 p += _n; \
246 } \
247 i += _incr; \
248 } while (0)
249
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))
258
259
260
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)
273
274 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
275
276 static char *
277 memcpy_lowcase (dest, src, len)
278 char *dest;
279 const char *src;
280 size_t len;
281 {
282 while (len-- > 0)
283 dest[len] = TOLOWER ((unsigned char) src[len]);
284 return dest;
285 }
286
287 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
288
289 static char *
290 memcpy_uppcase (dest, src, len)
291 char *dest;
292 const char *src;
293 size_t len;
294 {
295 while (len-- > 0)
296 dest[len] = TOUPPER ((unsigned char) src[len]);
297 return dest;
298 }
299
300
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;
310 {
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));
327 }
328 #endif /* ! HAVE_TM_GMTOFF */
329
330
331
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;
347 {
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);
353 }
354
355
356 #if !(defined _NL_CURRENT || HAVE_STRFTIME)
357 static char const weekday_name[][10] =
358 {
359 "Sunday", "Monday", "Tuesday", "Wednesday",
360 "Thursday", "Friday", "Saturday"
361 };
362 static char const month_name[][10] =
363 {
364 "January", "February", "March", "April", "May", "June",
365 "July", "August", "September", "October", "November", "December"
366 };
367 #endif
368
369
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
383
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
396 {
397 struct tm tmcopy;
398 tmcopy = *tp;
399 return _strftime_copytm (s, maxsize, format, &tmcopy ut_argument);
400 }
401 # undef my_strftime
402 # define my_strftime _strftime_copytm
403 #endif
404
405
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
419 {
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)
433
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))
444
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;
454
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)
467 {
468 if (! (zone && *zone))
469 zone = "GMT";
470 }
471 else
472 {
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
479 }
480 #endif
481
482 if (hour12 > 12)
483 hour12 -= 12;
484 else
485 if (hour12 == 0)
486 hour12 = 12;
487
488 for (f = format; *f != '\0'; ++f)
489 {
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;
505
506 #if DO_MULTIBYTE
507
508 switch (*f)
509 {
510 case '%':
511 break;
512
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;
538
539 default:
540 /* Copy this multibyte sequence until we reach its end, find
541 an error, or come back to the initial shift state. */
542 {
543 mbstate_t mbstate = mbstate_zero;
544 size_t len = 0;
545
546 do
547 {
548 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
549
550 if (bytes == 0)
551 break;
552
553 if (bytes == (size_t) -2)
554 {
555 len += strlen (f + len);
556 break;
557 }
558
559 if (bytes == (size_t) -1)
560 {
561 len++;
562 break;
563 }
564
565 len += bytes;
566 }
567 while (! mbsinit (&mbstate));
568
569 cpy (len, f);
570 f += len - 1;
571 continue;
572 }
573 }
574
575 #else /* ! DO_MULTIBYTE */
576
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 != '%')
580 {
581 add (1, *p = *f);
582 continue;
583 }
584
585 #endif /* ! DO_MULTIBYTE */
586
587 /* Check for flags that can modify a format. */
588 while (1)
589 {
590 switch (*++f)
591 {
592 /* This influences the number formats. */
593 case '_':
594 case '-':
595 case '0':
596 pad = *f;
597 continue;
598
599 /* This changes textual output. */
600 case '^':
601 to_uppcase = 1;
602 continue;
603 case '#':
604 change_case = 1;
605 continue;
606
607 default:
608 break;
609 }
610 break;
611 }
612
613 /* As a GNU extension we allow to specify the field width. */
614 if (ISDIGIT (*f))
615 {
616 width = 0;
617 do
618 {
619 width *= 10;
620 width += *f - '0';
621 ++f;
622 }
623 while (ISDIGIT (*f));
624 }
625
626 /* Check for modifiers. */
627 switch (*f)
628 {
629 case 'E':
630 case 'O':
631 modifier = *f++;
632 break;
633
634 default:
635 modifier = 0;
636 break;
637 }
638
639 /* Now do the specified format. */
640 format_char = *f;
641 switch (format_char)
642 {
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
649
650 case '%':
651 if (modifier != 0)
652 goto bad_format;
653 add (1, *p = *f);
654 break;
655
656 case 'a':
657 if (modifier != 0)
658 goto bad_format;
659 if (change_case)
660 {
661 to_uppcase = 1;
662 to_lowcase = 0;
663 }
664 #if defined _NL_CURRENT || !HAVE_STRFTIME
665 cpy (aw_len, a_wkday);
666 break;
667 #else
668 goto underlying_strftime;
669 #endif
670
671 case 'A':
672 if (modifier != 0)
673 goto bad_format;
674 if (change_case)
675 {
676 to_uppcase = 1;
677 to_lowcase = 0;
678 }
679 #if defined _NL_CURRENT || !HAVE_STRFTIME
680 cpy (strlen (f_wkday), f_wkday);
681 break;
682 #else
683 goto underlying_strftime;
684 #endif
685
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
696
697 case 'B':
698 if (modifier != 0)
699 goto bad_format;
700 if (change_case)
701 {
702 to_uppcase = 1;
703 to_lowcase = 0;
704 }
705 #if defined _NL_CURRENT || !HAVE_STRFTIME
706 cpy (strlen (f_month), f_month);
707 break;
708 #else
709 goto underlying_strftime;
710 #endif
711
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
726
727 subformat:
728 {
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));
733
734 if (to_uppcase)
735 while (old_start < p)
736 {
737 *old_start = TOUPPER ((unsigned char) *old_start);
738 ++old_start;
739 }
740 }
741 break;
742
743 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
744 underlying_strftime:
745 {
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);
761 }
762 break;
763 #endif
764
765 case 'C': /* POSIX.2 extension. */
766 if (modifier == 'O')
767 goto bad_format;
768 if (modifier == 'E')
769 {
770 #if HAVE_STRUCT_ERA_ENTRY
771 struct era_entry *era = _nl_get_era_entry (tp);
772 if (era)
773 {
774 size_t len = strlen (era->name_fmt);
775 cpy (len, era->name_fmt);
776 break;
777 }
778 #else
779 # if HAVE_STRFTIME
780 goto underlying_strftime;
781 # endif
782 #endif
783 }
784
785 {
786 int year = tp->tm_year + TM_YEAR_BASE;
787 DO_NUMBER (1, year / 100 - (year % 100 < 0));
788 }
789
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;
810
811 case 'd':
812 if (modifier == 'E')
813 goto bad_format;
814
815 DO_NUMBER (2, tp->tm_mday);
816
817 case 'e': /* POSIX.2 extension. */
818 if (modifier == 'E')
819 goto bad_format;
820
821 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
822
823 /* All numeric formats set DIGITS and NUMBER_VALUE and then
824 jump to one of these two labels. */
825
826 do_number_spacepad:
827 /* Force `_' flag unless overwritten by `0' flag. */
828 if (pad != '0')
829 pad = '_';
830
831 do_number:
832 /* Format the number according to the MODIFIER flag. */
833
834 if (modifier == 'O' && 0 <= number_value)
835 {
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);
840
841 if (cp != NULL)
842 {
843 size_t digitlen = strlen (cp);
844 if (digitlen != 0)
845 {
846 cpy (digitlen, cp);
847 break;
848 }
849 }
850 #else
851 # if HAVE_STRFTIME
852 goto underlying_strftime;
853 # endif
854 #endif
855 }
856 {
857 unsigned int u = number_value;
858
859 bufp = buf + sizeof (buf);
860 negative_number = number_value < 0;
861
862 if (negative_number)
863 u = -u;
864
865 do
866 *--bufp = u % 10 + '0';
867 while ((u /= 10) != 0);
868 }
869
870 do_number_sign_and_padding:
871 if (negative_number)
872 *--bufp = '-';
873
874 if (pad != '-')
875 {
876 int padding = digits - (buf + sizeof (buf) - bufp);
877
878 if (pad == '_')
879 {
880 while (0 < padding--)
881 *--bufp = ' ';
882 }
883 else
884 {
885 bufp += negative_number;
886 while (0 < padding--)
887 *--bufp = '0';
888 if (negative_number)
889 *--bufp = '-';
890 }
891 }
892
893 cpy (buf + sizeof (buf) - bufp, bufp);
894 break;
895
896 case 'F':
897 if (modifier != 0)
898 goto bad_format;
899 subfmt = "%Y-%m-%d";
900 goto subformat;
901
902 case 'H':
903 if (modifier == 'E')
904 goto bad_format;
905
906 DO_NUMBER (2, tp->tm_hour);
907
908 case 'I':
909 if (modifier == 'E')
910 goto bad_format;
911
912 DO_NUMBER (2, hour12);
913
914 case 'k': /* GNU extension. */
915 if (modifier == 'E')
916 goto bad_format;
917
918 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
919
920 case 'l': /* GNU extension. */
921 if (modifier == 'E')
922 goto bad_format;
923
924 DO_NUMBER_SPACEPAD (2, hour12);
925
926 case 'j':
927 if (modifier == 'E')
928 goto bad_format;
929
930 DO_NUMBER (3, 1 + tp->tm_yday);
931
932 case 'M':
933 if (modifier == 'E')
934 goto bad_format;
935
936 DO_NUMBER (2, tp->tm_min);
937
938 case 'm':
939 if (modifier == 'E')
940 goto bad_format;
941
942 DO_NUMBER (2, tp->tm_mon + 1);
943
944 case 'n': /* POSIX.2 extension. */
945 add (1, *p = '\n');
946 break;
947
948 case 'P':
949 to_lowcase = 1;
950 #if !defined _NL_CURRENT && HAVE_STRFTIME
951 format_char = 'p';
952 #endif
953 /* FALLTHROUGH */
954
955 case 'p':
956 if (change_case)
957 {
958 to_uppcase = 0;
959 to_lowcase = 1;
960 }
961 #if defined _NL_CURRENT || !HAVE_STRFTIME
962 cpy (ap_len, ampm);
963 break;
964 #else
965 goto underlying_strftime;
966 #endif
967
968 case 'R': /* GNU extension. */
969 subfmt = "%H:%M";
970 goto subformat;
971
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;
978
979 case 'S':
980 if (modifier == 'E')
981 goto bad_format;
982
983 DO_NUMBER (2, tp->tm_sec);
984
985 case 's': /* GNU extension. */
986 {
987 struct tm ltm;
988 time_t t;
989
990 ltm = *tp;
991 t = mktime (&ltm);
992
993 /* Generate string value for T using time_t arithmetic;
994 this works even if sizeof (long) < sizeof (time_t). */
995
996 bufp = buf + sizeof (buf);
997 negative_number = t < 0;
998
999 do
1000 {
1001 int d = t % 10;
1002 t /= 10;
1003
1004 if (negative_number)
1005 {
1006 d = -d;
1007
1008 /* Adjust if division truncates to minus infinity. */
1009 if (0 < -1 % 10 && d < 0)
1010 {
1011 t++;
1012 d += 10;
1013 }
1014 }
1015
1016 *--bufp = d + '0';
1017 }
1018 while (t != 0);
1019
1020 digits = 1;
1021 goto do_number_sign_and_padding;
1022 }
1023
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;
1042
1043 case 't': /* POSIX.2 extension. */
1044 add (1, *p = '\t');
1045 break;
1046
1047 case 'u': /* POSIX.2 extension. */
1048 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1049
1050 case 'U':
1051 if (modifier == 'E')
1052 goto bad_format;
1053
1054 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1055
1056 case 'V':
1057 case 'g': /* GNU extension. */
1058 case 'G': /* GNU extension. */
1059 if (modifier == 'E')
1060 goto bad_format;
1061 {
1062 int year = tp->tm_year + TM_YEAR_BASE;
1063 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1064
1065 if (days < 0)
1066 {
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);
1071 }
1072 else
1073 {
1074 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1075 tp->tm_wday);
1076 if (0 <= d)
1077 {
1078 /* This ISO week belongs to the next year. */
1079 year++;
1080 days = d;
1081 }
1082 }
1083
1084 switch (*f)
1085 {
1086 case 'g':
1087 DO_NUMBER (2, (year % 100 + 100) % 100);
1088
1089 case 'G':
1090 DO_NUMBER (1, year);
1091
1092 default:
1093 DO_NUMBER (2, days / 7 + 1);
1094 }
1095 }
1096
1097 case 'W':
1098 if (modifier == 'E')
1099 goto bad_format;
1100
1101 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1102
1103 case 'w':
1104 if (modifier == 'E')
1105 goto bad_format;
1106
1107 DO_NUMBER (1, tp->tm_wday);
1108
1109 case 'Y':
1110 if (modifier == 'E')
1111 {
1112 #if HAVE_STRUCT_ERA_ENTRY
1113 struct era_entry *era = _nl_get_era_entry (tp);
1114 if (era)
1115 {
1116 subfmt = strchr (era->name_fmt, '\0') + 1;
1117 goto subformat;
1118 }
1119 #else
1120 # if HAVE_STRFTIME
1121 goto underlying_strftime;
1122 # endif
1123 #endif
1124 }
1125 if (modifier == 'O')
1126 goto bad_format;
1127 else
1128 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1129
1130 case 'y':
1131 if (modifier == 'E')
1132 {
1133 #if HAVE_STRUCT_ERA_ENTRY
1134 struct era_entry *era = _nl_get_era_entry (tp);
1135 if (era)
1136 {
1137 int delta = tp->tm_year - era->start_date[0];
1138 DO_NUMBER (1, (era->offset
1139 + (era->direction == '-' ? -delta : delta)));
1140 }
1141 #else
1142 # if HAVE_STRFTIME
1143 goto underlying_strftime;
1144 # endif
1145 #endif
1146 }
1147 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1148
1149 case 'Z':
1150 if (change_case)
1151 {
1152 to_uppcase = 0;
1153 to_lowcase = 1;
1154 }
1155
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. */
1163
1164 cpy (strlen (zone), zone);
1165 break;
1166
1167 case 'z': /* GNU extension. */
1168 if (tp->tm_isdst < 0)
1169 break;
1170
1171 {
1172 int diff;
1173 #if HAVE_TM_GMTOFF
1174 diff = tp->tm_gmtoff;
1175 #else
1176 if (ut)
1177 diff = 0;
1178 else
1179 {
1180 struct tm gtm;
1181 struct tm ltm;
1182 time_t lt;
1183
1184 ltm = *tp;
1185 lt = mktime (&ltm);
1186
1187 if (lt == (time_t) -1)
1188 {
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;
1193
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;
1202 }
1203
1204 if (! my_strftime_gmtime_r (&lt, &gtm))
1205 break;
1206
1207 diff = tm_diff (&ltm, &gtm);
1208 }
1209 #endif
1210
1211 if (diff < 0)
1212 {
1213 add (1, *p = '-');
1214 diff = -diff;
1215 }
1216 else
1217 add (1, *p = '+');
1218
1219 diff /= 60;
1220 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1221 }
1222
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:
1231 {
1232 int flen;
1233 for (flen = 1; f[1 - flen] != '%'; flen++)
1234 continue;
1235 cpy (flen, &f[1 - flen]);
1236 }
1237 break;
1238 }
1239 }
1240
1241 if (p && maxsize != 0)
1242 *p = '\0';
1243 return i;
1244 }