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