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