]> git.ipfire.org Git - thirdparty/glibc.git/blob - time/strftime.c
Update.
[thirdparty/glibc.git] / time / strftime.c
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
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.
8
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.
13
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. */
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 extern char *tzname[];
56 #endif
57
58 /* Do multibyte processing if multibytes are supported, unless
59 multibyte sequences are safe in formats. Multibyte sequences are
60 safe if they cannot contain byte sequences that look like format
61 conversion specifications. The GNU C Library uses UTF8 multibyte
62 encoding, which is safe for formats, but strftime.c can be used
63 with other C libraries that use unsafe encodings. */
64 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
65
66 #if DO_MULTIBYTE
67 # if HAVE_MBRLEN
68 # include <wchar.h>
69 # else
70 /* Simulate mbrlen with mblen as best we can. */
71 # define mbstate_t int
72 # define mbrlen(s, n, ps) mblen (s, n)
73 # define mbsinit(ps) (*(ps) == 0)
74 # endif
75 static const mbstate_t mbstate_zero;
76 #endif
77
78 #if HAVE_LIMITS_H
79 # include <limits.h>
80 #endif
81
82 #if STDC_HEADERS
83 # include <stddef.h>
84 # include <stdlib.h>
85 # include <string.h>
86 #else
87 # ifndef HAVE_MEMCPY
88 # define memcpy(d, s, n) bcopy ((s), (d), (n))
89 # endif
90 #endif
91
92 #ifndef __P
93 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
94 # define __P(args) args
95 # else
96 # define __P(args) ()
97 # endif /* GCC. */
98 #endif /* Not __P. */
99
100 #ifndef PTR
101 # ifdef __STDC__
102 # define PTR void *
103 # else
104 # define PTR char *
105 # endif
106 #endif
107
108 #ifndef CHAR_BIT
109 # define CHAR_BIT 8
110 #endif
111
112 #ifndef NULL
113 # define NULL 0
114 #endif
115
116 #define TYPE_SIGNED(t) ((t) -1 < 0)
117
118 /* Bound on length of the string representing an integer value of type t.
119 Subtract one for the sign bit if t is signed;
120 302 / 1000 is log10 (2) rounded up;
121 add one for integer division truncation;
122 add one more for a minus sign if t is signed. */
123 #define INT_STRLEN_BOUND(t) \
124 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
125
126 #define TM_YEAR_BASE 1900
127
128 #ifndef __isleap
129 /* Nonzero if YEAR is a leap year (every 4 years,
130 except every 100th isn't, and every 400th is). */
131 # define __isleap(year) \
132 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
133 #endif
134
135
136 #ifdef _LIBC
137 # define gmtime_r __gmtime_r
138 # define localtime_r __localtime_r
139 # define tzname __tzname
140 # define tzset __tzset
141 #else
142 # if ! HAVE_LOCALTIME_R
143 # if ! HAVE_TM_GMTOFF
144 /* Approximate gmtime_r as best we can in its absence. */
145 # undef gmtime_r
146 # define gmtime_r my_gmtime_r
147 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
148 static struct tm *
149 gmtime_r (t, tp)
150 const time_t *t;
151 struct tm *tp;
152 {
153 struct tm *l = gmtime (t);
154 if (! l)
155 return 0;
156 *tp = *l;
157 return tp;
158 }
159 # endif /* ! HAVE_TM_GMTOFF */
160
161 /* Approximate localtime_r as best we can in its absence. */
162 # undef localtime_r
163 # define localtime_r my_ftime_localtime_r
164 static struct tm *localtime_r __P ((const time_t *, struct tm *));
165 static struct tm *
166 localtime_r (t, tp)
167 const time_t *t;
168 struct tm *tp;
169 {
170 struct tm *l = localtime (t);
171 if (! l)
172 return 0;
173 *tp = *l;
174 return tp;
175 }
176 # endif /* ! HAVE_LOCALTIME_R */
177 #endif /* ! defined (_LIBC) */
178
179
180 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
181 /* Some systems lack the `memset' function and we don't want to
182 introduce additional dependencies. */
183 /* The SGI compiler reportedly barfs on the trailing null
184 if we use a string constant as the initializer. 28 June 1997, rms. */
185 static const char spaces[16] = /* " " */
186 { ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
187 static const char zeroes[16] = /* "0000000000000000" */
188 { '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' };
189
190 # define memset_space(P, Len) \
191 do { \
192 int _len = (Len); \
193 \
194 do \
195 { \
196 int _this = _len > 16 ? 16 : _len; \
197 memcpy ((P), spaces, _this); \
198 (P) += _this; \
199 _len -= _this; \
200 } \
201 while (_len > 0); \
202 } while (0)
203
204 # define memset_zero(P, Len) \
205 do { \
206 int _len = (Len); \
207 \
208 do \
209 { \
210 int _this = _len > 16 ? 16 : _len; \
211 memcpy ((P), zeroes, _this); \
212 (P) += _this; \
213 _len -= _this; \
214 } \
215 while (_len > 0); \
216 } while (0)
217 #else
218 # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
219 # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
220 #endif
221
222 #define add(n, f) \
223 do \
224 { \
225 int _n = (n); \
226 int _delta = width - _n; \
227 int _incr = _n + (_delta > 0 ? _delta : 0); \
228 if (i + _incr >= maxsize) \
229 return 0; \
230 if (p) \
231 { \
232 if (_delta > 0) \
233 { \
234 if (pad == '0') \
235 memset_zero (p, _delta); \
236 else \
237 memset_space (p, _delta); \
238 } \
239 f; \
240 p += _n; \
241 } \
242 i += _incr; \
243 } while (0)
244
245 #define cpy(n, s) \
246 add ((n), \
247 if (to_lowcase) \
248 memcpy_lowcase (p, (s), _n); \
249 else if (to_uppcase) \
250 memcpy_uppcase (p, (s), _n); \
251 else \
252 memcpy ((PTR) p, (PTR) (s), _n))
253
254
255
256 #ifdef _LIBC
257 # define TOUPPER(Ch) toupper (Ch)
258 # define TOLOWER(Ch) tolower (Ch)
259 #else
260 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
261 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
262 #endif
263 /* We don't use `isdigit' here since the locale dependent
264 interpretation is not what we want here. We only need to accept
265 the arabic digits in the ASCII range. One day there is perhaps a
266 more reliable way to accept other sets of digits. */
267 #define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
268
269 static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
270
271 static char *
272 memcpy_lowcase (dest, src, len)
273 char *dest;
274 const char *src;
275 size_t len;
276 {
277 while (len-- > 0)
278 dest[len] = TOLOWER ((unsigned char) src[len]);
279 return dest;
280 }
281
282 static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
283
284 static char *
285 memcpy_uppcase (dest, src, len)
286 char *dest;
287 const char *src;
288 size_t len;
289 {
290 while (len-- > 0)
291 dest[len] = TOUPPER ((unsigned char) src[len]);
292 return dest;
293 }
294
295
296 #if ! HAVE_TM_GMTOFF
297 /* Yield the difference between *A and *B,
298 measured in seconds, ignoring leap seconds. */
299 # define tm_diff ftime_tm_diff
300 static int tm_diff __P ((const struct tm *, const struct tm *));
301 static int
302 tm_diff (a, b)
303 const struct tm *a;
304 const struct tm *b;
305 {
306 /* Compute intervening leap days correctly even if year is negative.
307 Take care to avoid int overflow in leap day calculations,
308 but it's OK to assume that A and B are close to each other. */
309 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
310 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
311 int a100 = a4 / 25 - (a4 % 25 < 0);
312 int b100 = b4 / 25 - (b4 % 25 < 0);
313 int a400 = a100 >> 2;
314 int b400 = b100 >> 2;
315 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
316 int years = a->tm_year - b->tm_year;
317 int days = (365 * years + intervening_leap_days
318 + (a->tm_yday - b->tm_yday));
319 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
320 + (a->tm_min - b->tm_min))
321 + (a->tm_sec - b->tm_sec));
322 }
323 #endif /* ! HAVE_TM_GMTOFF */
324
325
326
327 /* The number of days from the first day of the first ISO week of this
328 year to the year day YDAY with week day WDAY. ISO weeks start on
329 Monday; the first ISO week has the year's first Thursday. YDAY may
330 be as small as YDAY_MINIMUM. */
331 #define ISO_WEEK_START_WDAY 1 /* Monday */
332 #define ISO_WEEK1_WDAY 4 /* Thursday */
333 #define YDAY_MINIMUM (-366)
334 static int iso_week_days __P ((int, int));
335 #ifdef __GNUC__
336 __inline__
337 #endif
338 static int
339 iso_week_days (yday, wday)
340 int yday;
341 int wday;
342 {
343 /* Add enough to the first operand of % to make it nonnegative. */
344 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
345 return (yday
346 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
347 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
348 }
349
350
351 #if !(defined _NL_CURRENT || HAVE_STRFTIME)
352 static char const weekday_name[][10] =
353 {
354 "Sunday", "Monday", "Tuesday", "Wednesday",
355 "Thursday", "Friday", "Saturday"
356 };
357 static char const month_name[][10] =
358 {
359 "January", "February", "March", "April", "May", "June",
360 "July", "August", "September", "October", "November", "December"
361 };
362 #endif
363
364
365 #ifdef emacs
366 # define my_strftime emacs_strftime
367 /* Emacs 20.2 uses `-Dstrftime=emacs_strftime' when compiling,
368 because that's how strftime used to be configured.
369 Undo this, since it gets in the way of accessing the underlying strftime,
370 which is needed for things like %Ec in Solaris.
371 The following two lines can be removed once Emacs stops compiling with
372 `-Dstrftime=emacs_strftime'. */
373 # undef strftime
374 size_t strftime __P ((char *, size_t, const char *, const struct tm *));
375 #else
376 # define my_strftime strftime
377 #endif
378
379 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
380 /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
381 Work around this bug by copying *tp before it might be munged. */
382 size_t _strftime_copytm __P ((char *, size_t, const char *,
383 const struct tm *));
384 size_t
385 my_strftime (s, maxsize, format, tp)
386 char *s;
387 size_t maxsize;
388 const char *format;
389 const struct tm *tp;
390 {
391 struct tm tmcopy;
392 tmcopy = *tp;
393 return _strftime_copytm (s, maxsize, format, &tmcopy);
394 }
395 # undef my_strftime
396 # define my_strftime(S, Maxsize, Format, Tp) \
397 _strftime_copytm (S, Maxsize, Format, Tp)
398 #endif
399
400
401 /* Write information from TP into S according to the format
402 string FORMAT, writing no more that MAXSIZE characters
403 (including the terminating '\0') and returning number of
404 characters written. If S is NULL, nothing will be written
405 anywhere, so to determine how many characters would be
406 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
407 size_t
408 my_strftime (s, maxsize, format, tp)
409 char *s;
410 size_t maxsize;
411 const char *format;
412 const struct tm *tp;
413 {
414 int hour12 = tp->tm_hour;
415 #ifdef _NL_CURRENT
416 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
417 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
418 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
419 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
420 const char *const ampm = _NL_CURRENT (LC_TIME,
421 hour12 > 11 ? PM_STR : AM_STR);
422 size_t aw_len = strlen (a_wkday);
423 size_t am_len = strlen (a_month);
424 size_t ap_len = strlen (ampm);
425 #else
426 # if !HAVE_STRFTIME
427 const char *const f_wkday = weekday_name[tp->tm_wday];
428 const char *const f_month = month_name[tp->tm_mon];
429 const char *const a_wkday = f_wkday;
430 const char *const a_month = f_month;
431 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
432 size_t aw_len = 3;
433 size_t am_len = 3;
434 size_t ap_len = 2;
435 # endif
436 #endif
437 #if defined _NL_CURRENT || !HAVE_STRFTIME
438 size_t wkday_len = strlen (f_wkday);
439 size_t month_len = strlen (f_month);
440 #endif
441 const char *zone;
442 size_t zonelen;
443 size_t i = 0;
444 char *p = s;
445 const char *f;
446
447 zone = NULL;
448 #if HAVE_TM_ZONE
449 /* The POSIX test suite assumes that setting
450 the environment variable TZ to a new value before calling strftime()
451 will influence the result (the %Z format) even if the information in
452 TP is computed with a totally different time zone.
453 This is bogus: though POSIX allows bad behavior like this,
454 POSIX does not require it. Do the right thing instead. */
455 zone = (const char *) tp->tm_zone;
456 #endif
457 #if HAVE_TZNAME
458 /* POSIX.1 8.1.1 requires that whenever strftime() is called, the
459 time zone names contained in the external variable `tzname' shall
460 be set as if the tzset() function had been called. */
461 # if HAVE_TZSET
462 tzset ();
463 # endif
464
465 if (!(zone && *zone) && tp->tm_isdst >= 0)
466 zone = tzname[tp->tm_isdst];
467 #endif
468 if (! zone)
469 zone = ""; /* POSIX.2 requires the empty string here. */
470
471 zonelen = strlen (zone);
472
473 if (hour12 > 12)
474 hour12 -= 12;
475 else
476 if (hour12 == 0) hour12 = 12;
477
478 for (f = format; *f != '\0'; ++f)
479 {
480 int pad; /* Padding for number ('-', '_', or 0). */
481 int modifier; /* Field modifier ('E', 'O', or 0). */
482 int digits; /* Max digits for numeric format. */
483 int number_value; /* Numeric value to be printed. */
484 int negative_number; /* 1 if the number is negative. */
485 const char *subfmt;
486 char *bufp;
487 char buf[1 + (sizeof (int) < sizeof (time_t)
488 ? INT_STRLEN_BOUND (time_t)
489 : INT_STRLEN_BOUND (int))];
490 int width = -1;
491 int to_lowcase = 0;
492 int to_uppcase = 0;
493 int change_case = 0;
494 int format_char;
495
496 #if DO_MULTIBYTE
497
498 switch (*f)
499 {
500 case '%':
501 break;
502
503 case '\a': case '\b': case '\t': case '\n':
504 case '\v': case '\f': case '\r':
505 case ' ': case '!': case '"': case '#': case '&': case'\'':
506 case '(': case ')': case '*': case '+': case ',': case '-':
507 case '.': case '/': case '0': case '1': case '2': case '3':
508 case '4': case '5': case '6': case '7': case '8': case '9':
509 case ':': case ';': case '<': case '=': case '>': case '?':
510 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
511 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
512 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
513 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
514 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
515 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
516 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
517 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
518 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
519 case 'x': case 'y': case 'z': case '{': case '|': case '}':
520 case '~':
521 /* The C Standard requires these 98 characters (plus '%') to
522 be in the basic execution character set. None of these
523 characters can start a multibyte sequence, so they need
524 not be analyzed further. */
525 add (1, *p = *f);
526 continue;
527
528 default:
529 /* Copy this multibyte sequence until we reach its end, find
530 an error, or come back to the initial shift state. */
531 {
532 mbstate_t mbstate = mbstate_zero;
533 size_t len = 0;
534
535 do
536 {
537 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
538
539 if (bytes == 0)
540 break;
541
542 if (bytes == (size_t) -2 || bytes == (size_t) -1)
543 {
544 len++;
545 break;
546 }
547
548 len += bytes;
549 }
550 while (! mbsinit (&mbstate));
551
552 cpy (len, f);
553 continue;
554 }
555 }
556
557 #else /* ! DO_MULTIBYTE */
558
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 != '%')
562 {
563 add (1, *p = *f);
564 continue;
565 }
566
567 #endif /* ! DO_MULTIBYTE */
568
569 /* Check for flags that can modify a format. */
570 pad = 0;
571 while (1)
572 {
573 switch (*++f)
574 {
575 /* This influences the number formats. */
576 case '_':
577 case '-':
578 case '0':
579 pad = *f;
580 continue;
581
582 /* This changes textual output. */
583 case '^':
584 to_uppcase = 1;
585 continue;
586 case '#':
587 change_case = 1;
588 continue;
589
590 default:
591 break;
592 }
593 break;
594 }
595
596 /* As a GNU extension we allow to specify the field width. */
597 if (ISDIGIT (*f))
598 {
599 width = 0;
600 do
601 {
602 width *= 10;
603 width += *f - '0';
604 ++f;
605 }
606 while (ISDIGIT (*f));
607 }
608
609 /* Check for modifiers. */
610 switch (*f)
611 {
612 case 'E':
613 case 'O':
614 modifier = *f++;
615 break;
616
617 default:
618 modifier = 0;
619 break;
620 }
621
622 /* Now do the specified format. */
623 format_char = *f;
624 switch (format_char)
625 {
626 #define DO_NUMBER(d, v) \
627 digits = width == -1 ? d : width; \
628 number_value = v; goto do_number
629 #define DO_NUMBER_SPACEPAD(d, v) \
630 digits = width == -1 ? d : width; \
631 number_value = v; goto do_number_spacepad
632
633 case '%':
634 if (modifier != 0)
635 goto bad_format;
636 add (1, *p = *f);
637 break;
638
639 case 'a':
640 if (modifier != 0)
641 goto bad_format;
642 if (change_case)
643 {
644 to_uppcase = 1;
645 to_lowcase = 0;
646 }
647 #if defined _NL_CURRENT || !HAVE_STRFTIME
648 cpy (aw_len, a_wkday);
649 break;
650 #else
651 goto underlying_strftime;
652 #endif
653
654 case 'A':
655 if (modifier != 0)
656 goto bad_format;
657 if (change_case)
658 {
659 to_uppcase = 1;
660 to_lowcase = 0;
661 }
662 #if defined _NL_CURRENT || !HAVE_STRFTIME
663 cpy (wkday_len, f_wkday);
664 break;
665 #else
666 goto underlying_strftime;
667 #endif
668
669 case 'b':
670 case 'h': /* POSIX.2 extension. */
671 if (modifier != 0)
672 goto bad_format;
673 #if defined _NL_CURRENT || !HAVE_STRFTIME
674 cpy (am_len, a_month);
675 break;
676 #else
677 goto underlying_strftime;
678 #endif
679
680 case 'B':
681 if (modifier != 0)
682 goto bad_format;
683 if (change_case)
684 {
685 to_uppcase = 1;
686 to_lowcase = 0;
687 }
688 #if defined _NL_CURRENT || !HAVE_STRFTIME
689 cpy (month_len, f_month);
690 break;
691 #else
692 goto underlying_strftime;
693 #endif
694
695 case 'c':
696 if (modifier == 'O')
697 goto bad_format;
698 #ifdef _NL_CURRENT
699 if (! (modifier == 'E'
700 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
701 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
702 #else
703 # if HAVE_STRFTIME
704 goto underlying_strftime;
705 # else
706 subfmt = "%a %b %e %H:%M:%S %Y";
707 # endif
708 #endif
709
710 subformat:
711 {
712 char *old_start = p;
713 size_t len = my_strftime (NULL, maxsize - i, subfmt, tp);
714 if (len == 0 && *subfmt)
715 return 0;
716 add (len, my_strftime (p, maxsize - i, subfmt, tp));
717
718 if (to_uppcase)
719 while (old_start < p)
720 {
721 *old_start = TOUPPER ((unsigned char) *old_start);
722 ++old_start;
723 }
724 }
725 break;
726
727 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
728 underlying_strftime:
729 {
730 /* The relevant information is available only via the
731 underlying strftime implementation, so use that. */
732 char ufmt[4];
733 char *u = ufmt;
734 char ubuf[1024]; /* enough for any single format in practice */
735 size_t len;
736 *u++ = '%';
737 if (modifier != 0)
738 *u++ = modifier;
739 *u++ = format_char;
740 *u = '\0';
741 len = strftime (ubuf, sizeof ubuf, ufmt, tp);
742 if (len == 0)
743 return 0;
744 cpy (len, ubuf);
745 }
746 break;
747 #endif
748
749 case 'C': /* POSIX.2 extension. */
750 if (modifier == 'O')
751 goto bad_format;
752 if (modifier == 'E')
753 {
754 #if HAVE_STRUCT_ERA_ENTRY
755 struct era_entry *era = _nl_get_era_entry (tp);
756 if (era)
757 {
758 size_t len = strlen (era->name_fmt);
759 cpy (len, era->name_fmt);
760 break;
761 }
762 #else
763 # if HAVE_STRFTIME
764 goto underlying_strftime;
765 # endif
766 #endif
767 }
768
769 {
770 int year = tp->tm_year + TM_YEAR_BASE;
771 DO_NUMBER (1, year / 100 - (year % 100 < 0));
772 }
773
774 case 'x':
775 if (modifier == 'O')
776 goto bad_format;
777 #ifdef _NL_CURRENT
778 if (! (modifier == 'E'
779 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
780 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
781 goto subformat;
782 #else
783 # if HAVE_STRFTIME
784 goto underlying_strftime;
785 # else
786 /* Fall through. */
787 # endif
788 #endif
789 case 'D': /* POSIX.2 extension. */
790 if (modifier != 0)
791 goto bad_format;
792 subfmt = "%m/%d/%y";
793 goto subformat;
794
795 case 'd':
796 if (modifier == 'E')
797 goto bad_format;
798
799 DO_NUMBER (2, tp->tm_mday);
800
801 case 'e': /* POSIX.2 extension. */
802 if (modifier == 'E')
803 goto bad_format;
804
805 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
806
807 /* All numeric formats set DIGITS and NUMBER_VALUE and then
808 jump to one of these two labels. */
809
810 do_number_spacepad:
811 /* Force `_' flag unless overwritten by `0' flag. */
812 if (pad != '0')
813 pad = '_';
814
815 do_number:
816 /* Format the number according to the MODIFIER flag. */
817
818 if (modifier == 'O' && 0 <= number_value)
819 {
820 #ifdef _NL_CURRENT
821 /* Get the locale specific alternate representation of
822 the number NUMBER_VALUE. If none exist NULL is returned. */
823 const char *cp = _nl_get_alt_digit (number_value);
824
825 if (cp != NULL)
826 {
827 size_t digitlen = strlen (cp);
828 if (digitlen != 0)
829 {
830 cpy (digitlen, cp);
831 break;
832 }
833 }
834 #else
835 # if HAVE_STRFTIME
836 goto underlying_strftime;
837 # endif
838 #endif
839 }
840 {
841 unsigned int u = number_value;
842
843 bufp = buf + sizeof (buf);
844 negative_number = number_value < 0;
845
846 if (negative_number)
847 u = -u;
848
849 do
850 *--bufp = u % 10 + '0';
851 while ((u /= 10) != 0);
852 }
853
854 do_number_sign_and_padding:
855 if (negative_number)
856 *--bufp = '-';
857
858 if (pad != '-')
859 {
860 int padding = digits - (buf + sizeof (buf) - bufp);
861
862 if (pad == '_')
863 {
864 while (0 < padding--)
865 *--bufp = ' ';
866 }
867 else
868 {
869 bufp += negative_number;
870 while (0 < padding--)
871 *--bufp = '0';
872 if (negative_number)
873 *--bufp = '-';
874 }
875 }
876
877 cpy (buf + sizeof (buf) - bufp, bufp);
878 break;
879
880
881 case 'H':
882 if (modifier == 'E')
883 goto bad_format;
884
885 DO_NUMBER (2, tp->tm_hour);
886
887 case 'I':
888 if (modifier == 'E')
889 goto bad_format;
890
891 DO_NUMBER (2, hour12);
892
893 case 'k': /* GNU extension. */
894 if (modifier == 'E')
895 goto bad_format;
896
897 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
898
899 case 'l': /* GNU extension. */
900 if (modifier == 'E')
901 goto bad_format;
902
903 DO_NUMBER_SPACEPAD (2, hour12);
904
905 case 'j':
906 if (modifier == 'E')
907 goto bad_format;
908
909 DO_NUMBER (3, 1 + tp->tm_yday);
910
911 case 'M':
912 if (modifier == 'E')
913 goto bad_format;
914
915 DO_NUMBER (2, tp->tm_min);
916
917 case 'm':
918 if (modifier == 'E')
919 goto bad_format;
920
921 DO_NUMBER (2, tp->tm_mon + 1);
922
923 case 'n': /* POSIX.2 extension. */
924 add (1, *p = '\n');
925 break;
926
927 case 'P':
928 to_lowcase = 1;
929 #if !defined _NL_CURRENT && HAVE_STRFTIME
930 format_char = 'p';
931 #endif
932 /* FALLTHROUGH */
933
934 case 'p':
935 if (change_case)
936 {
937 to_uppcase = 0;
938 to_lowcase = 1;
939 }
940 #if defined _NL_CURRENT || !HAVE_STRFTIME
941 cpy (ap_len, ampm);
942 break;
943 #else
944 goto underlying_strftime;
945 #endif
946
947 case 'R': /* GNU extension. */
948 subfmt = "%H:%M";
949 goto subformat;
950
951 case 'r': /* POSIX.2 extension. */
952 #ifdef _NL_CURRENT
953 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
954 #endif
955 subfmt = "%I:%M:%S %p";
956 goto subformat;
957
958 case 'S':
959 if (modifier == 'E')
960 goto bad_format;
961
962 DO_NUMBER (2, tp->tm_sec);
963
964 case 's': /* GNU extension. */
965 {
966 struct tm ltm;
967 time_t t;
968
969 ltm = *tp;
970 t = mktime (&ltm);
971
972 /* Generate string value for T using time_t arithmetic;
973 this works even if sizeof (long) < sizeof (time_t). */
974
975 bufp = buf + sizeof (buf);
976 negative_number = t < 0;
977
978 do
979 {
980 int d = t % 10;
981 t /= 10;
982
983 if (negative_number)
984 {
985 d = -d;
986
987 /* Adjust if division truncates to minus infinity. */
988 if (0 < -1 % 10 && d < 0)
989 {
990 t++;
991 d += 10;
992 }
993 }
994
995 *--bufp = d + '0';
996 }
997 while (t != 0);
998
999 digits = 1;
1000 goto do_number_sign_and_padding;
1001 }
1002
1003 case 'X':
1004 if (modifier == 'O')
1005 goto bad_format;
1006 #ifdef _NL_CURRENT
1007 if (! (modifier == 'E'
1008 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
1009 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
1010 goto subformat;
1011 #else
1012 # if HAVE_STRFTIME
1013 goto underlying_strftime;
1014 # else
1015 /* Fall through. */
1016 # endif
1017 #endif
1018 case 'T': /* POSIX.2 extension. */
1019 subfmt = "%H:%M:%S";
1020 goto subformat;
1021
1022 case 't': /* POSIX.2 extension. */
1023 add (1, *p = '\t');
1024 break;
1025
1026 case 'u': /* POSIX.2 extension. */
1027 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1028
1029 case 'U':
1030 if (modifier == 'E')
1031 goto bad_format;
1032
1033 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1034
1035 case 'V':
1036 case 'g': /* GNU extension. */
1037 case 'G': /* GNU extension. */
1038 if (modifier == 'E')
1039 goto bad_format;
1040 {
1041 int year = tp->tm_year + TM_YEAR_BASE;
1042 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1043
1044 if (days < 0)
1045 {
1046 /* This ISO week belongs to the previous year. */
1047 year--;
1048 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
1049 tp->tm_wday);
1050 }
1051 else
1052 {
1053 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1054 tp->tm_wday);
1055 if (0 <= d)
1056 {
1057 /* This ISO week belongs to the next year. */
1058 year++;
1059 days = d;
1060 }
1061 }
1062
1063 switch (*f)
1064 {
1065 case 'g':
1066 DO_NUMBER (2, (year % 100 + 100) % 100);
1067
1068 case 'G':
1069 DO_NUMBER (1, year);
1070
1071 default:
1072 DO_NUMBER (2, days / 7 + 1);
1073 }
1074 }
1075
1076 case 'W':
1077 if (modifier == 'E')
1078 goto bad_format;
1079
1080 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1081
1082 case 'w':
1083 if (modifier == 'E')
1084 goto bad_format;
1085
1086 DO_NUMBER (1, tp->tm_wday);
1087
1088 case 'Y':
1089 if (modifier == 'E')
1090 {
1091 #if HAVE_STRUCT_ERA_ENTRY
1092 struct era_entry *era = _nl_get_era_entry (tp);
1093 if (era)
1094 {
1095 subfmt = strchr (era->name_fmt, '\0') + 1;
1096 goto subformat;
1097 }
1098 #else
1099 # if HAVE_STRFTIME
1100 goto underlying_strftime;
1101 # endif
1102 #endif
1103 }
1104 if (modifier == 'O')
1105 goto bad_format;
1106 else
1107 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
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 int delta = tp->tm_year - era->start_date[0];
1117 DO_NUMBER (1, (era->offset
1118 + (era->direction == '-' ? -delta : delta)));
1119 }
1120 #else
1121 # if HAVE_STRFTIME
1122 goto underlying_strftime;
1123 # endif
1124 #endif
1125 }
1126 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1127
1128 case 'Z':
1129 if (change_case)
1130 {
1131 to_uppcase = 0;
1132 to_lowcase = 1;
1133 }
1134 cpy (zonelen, zone);
1135 break;
1136
1137 case 'z': /* GNU extension. */
1138 if (tp->tm_isdst < 0)
1139 break;
1140
1141 {
1142 int diff;
1143 #if HAVE_TM_GMTOFF
1144 diff = tp->tm_gmtoff;
1145 #else
1146 struct tm gtm;
1147 struct tm ltm;
1148 time_t lt;
1149
1150 ltm = *tp;
1151 lt = mktime (&ltm);
1152
1153 if (lt == (time_t) -1)
1154 {
1155 /* mktime returns -1 for errors, but -1 is also a
1156 valid time_t value. Check whether an error really
1157 occurred. */
1158 struct tm tm;
1159 localtime_r (&lt, &tm);
1160
1161 if ((ltm.tm_sec ^ tm.tm_sec)
1162 | (ltm.tm_min ^ tm.tm_min)
1163 | (ltm.tm_hour ^ tm.tm_hour)
1164 | (ltm.tm_mday ^ tm.tm_mday)
1165 | (ltm.tm_mon ^ tm.tm_mon)
1166 | (ltm.tm_year ^ tm.tm_year))
1167 break;
1168 }
1169
1170 if (! gmtime_r (&lt, &gtm))
1171 break;
1172
1173 diff = tm_diff (&ltm, &gtm);
1174 #endif
1175
1176 if (diff < 0)
1177 {
1178 add (1, *p = '-');
1179 diff = -diff;
1180 }
1181 else
1182 add (1, *p = '+');
1183
1184 diff /= 60;
1185 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1186 }
1187
1188 case '\0': /* GNU extension: % at end of format. */
1189 --f;
1190 /* Fall through. */
1191 default:
1192 /* Unknown format; output the format, including the '%',
1193 since this is most likely the right thing to do if a
1194 multibyte string has been misparsed. */
1195 bad_format:
1196 {
1197 int flen;
1198 for (flen = 1; f[1 - flen] != '%'; flen++)
1199 continue;
1200 cpy (flen, &f[1 - flen]);
1201 }
1202 break;
1203 }
1204 }
1205
1206 if (p)
1207 *p = '\0';
1208 return i;
1209 }