1 /* Copyright (C) 1991-1999, 2000, 2001, 2003 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
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any 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 along
17 with this program; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #ifdef _LIBC
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 # include "../locale/localeinfo.h"
34 #endif
35
36 #include <ctype.h>
37 #include <sys/types.h> /* Some systems define `time_t' here. */
38
39 #ifdef TIME_WITH_SYS_TIME
40 # include <sys/time.h>
41 # include <time.h>
42 #else
43 # ifdef HAVE_SYS_TIME_H
44 # include <sys/time.h>
45 # else
46 # include <time.h>
47 # endif
48 #endif
49 #if HAVE_TZNAME
50 extern char *tzname[];
51 #endif
52
53 /* Do multibyte processing if multibytes are supported, unless
54 multibyte sequences are safe in formats. Multibyte sequences are
55 safe if they cannot contain byte sequences that look like format
56 conversion specifications. The GNU C Library uses UTF8 multibyte
57 encoding, which is safe for formats, but strftime.c can be used
58 with other C libraries that use unsafe encodings. */
59 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
60
61 #if DO_MULTIBYTE
62 # if HAVE_MBRLEN
63 # include <wchar.h>
64 # else
65 /* Simulate mbrlen with mblen as best we can. */
66 # define mbstate_t int
67 # define mbrlen(s, n, ps) mblen (s, n)
68 # define mbsinit(ps) (*(ps) == 0)
69 # endif
70 static const mbstate_t mbstate_zero;
71 #endif
72
73 #include <limits.h>
74 #include <stddef.h>
75 #include <stdlib.h>
76 #include <string.h>
77
78 #ifdef COMPILE_WIDE
79 # include <endian.h>
80 # define CHAR_T wchar_t
81 # define UCHAR_T unsigned int
82 # define L_(Str) L##Str
83 # define NLW(Sym) _NL_W##Sym
84
85 # define MEMCPY(d, s, n) __wmemcpy (d, s, n)
86 # define STRLEN(s) __wcslen (s)
87
88 #else
89 # define CHAR_T char
90 # define UCHAR_T unsigned char
91 # define L_(Str) Str
92 # define NLW(Sym) Sym
93
94 # define MEMCPY(d, s, n) memcpy (d, s, n)
95 # define STRLEN(s) strlen (s)
96
97 # ifdef _LIBC
98 # define MEMPCPY(d, s, n) __mempcpy (d, s, n)
99 # else
100 # ifndef HAVE_MEMPCPY
101 # define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
102 # endif
103 # endif
104 #endif
105
106 #define TYPE_SIGNED(t) ((t) -1 < 0)
107
108 /* Bound on length of the string representing an integer value of type t.
109 Subtract one for the sign bit if t is signed;
110 302 / 1000 is log10 (2) rounded up;
111 add one for integer division truncation;
112 add one more for a minus sign if t is signed. */
113 #define INT_STRLEN_BOUND(t) \
114 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t))
115
116 #define TM_YEAR_BASE 1900
117
118 #ifndef __isleap
119 /* Nonzero if YEAR is a leap year (every 4 years,
120 except every 100th isn't, and every 400th is). */
121 # define __isleap(year) \
122 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
123 #endif
124
125
126 #ifdef _LIBC
127 # define tzname __tzname
128 # define tzset __tzset
129 #endif
130
131 #if !HAVE_TM_GMTOFF
132 /* Portable standalone applications should supply a "time_r.h" that
133 declares a POSIX-compliant localtime_r, for the benefit of older
134 implementations that lack localtime_r or have a nonstandard one.
135 See the gnulib time_r module for one way to implement this. */
136 # include "time_r.h"
137 # undef __gmtime_r
138 # undef __localtime_r
139 # define __gmtime_r gmtime_r
140 # define __localtime_r localtime_r
141 #endif
142
143
144 #ifdef COMPILE_WIDE
145 # define memset_space(P, Len) (wmemset (P, L' ', Len), (P) += (Len))
146 # define memset_zero(P, Len) (wmemset (P, L'0', Len), (P) += (Len))
147 #else
148 # define memset_space(P, Len) (memset (P, ' ', Len), (P) += (Len))
149 # define memset_zero(P, Len) (memset (P, '0', Len), (P) += (Len))
150 #endif
151
152 #define add(n, f) \
153 do \
154 { \
155 int _n = (n); \
156 int _delta = width - _n; \
157 int _incr = _n + (_delta > 0 ? _delta : 0); \
158 if ((size_t) _incr >= maxsize - i) \
159 return 0; \
160 if (p) \
161 { \
162 if (_delta > 0) \
163 { \
164 if (pad == L_('0')) \
165 memset_zero (p, _delta); \
166 else \
167 memset_space (p, _delta); \
168 } \
169 f; \
170 p += _n; \
171 } \
172 i += _incr; \
173 } while (0)
174
175 #define cpy(n, s) \
176 add ((n), \
177 if (to_lowcase) \
178 memcpy_lowcase (p, (s), _n LOCALE_ARG); \
179 else if (to_uppcase) \
180 memcpy_uppcase (p, (s), _n LOCALE_ARG); \
181 else \
182 MEMCPY ((void *) p, (void const *) (s), _n))
183
184 #ifdef COMPILE_WIDE
185 # ifndef USE_IN_EXTENDED_LOCALE_MODEL
186 # undef __mbsrtowcs_l
187 # define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
188 # endif
189 # define widen(os, ws, l) \
190 { \
191 mbstate_t __st; \
192 const char *__s = os; \
193 memset (&__st, '\0', sizeof (__st)); \
194 l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc); \
195 ws = (wchar_t *) alloca ((l + 1) * sizeof (wchar_t)); \
196 (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc); \
197 }
198 #endif
199
200
201 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
202 /* We use this code also for the extended locale handling where the
203 function gets as an additional argument the locale which has to be
204 used. To access the values we have to redefine the _NL_CURRENT
205 macro. */
206 # define strftime __strftime_l
207 # define wcsftime __wcsftime_l
208 # undef _NL_CURRENT
209 # define _NL_CURRENT(category, item) \
210 (current->values[_NL_ITEM_INDEX (item)].string)
211 # define LOCALE_ARG , loc
212 # define LOCALE_PARAM_PROTO , __locale_t loc
213 # define HELPER_LOCALE_ARG , current
214 #else
215 # define LOCALE_PARAM_PROTO
216 # define LOCALE_ARG
217 # ifdef _LIBC
218 # define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
219 # else
220 # define HELPER_LOCALE_ARG
221 # endif
222 #endif
223
224 #ifdef COMPILE_WIDE
225 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
226 # define TOUPPER(Ch, L) __towupper_l (Ch, L)
227 # define TOLOWER(Ch, L) __towlower_l (Ch, L)
228 # else
229 # define TOUPPER(Ch, L) towupper (Ch)
230 # define TOLOWER(Ch, L) towlower (Ch)
231 # endif
232 #else
233 # ifdef _LIBC
234 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
235 # define TOUPPER(Ch, L) __toupper_l (Ch, L)
236 # define TOLOWER(Ch, L) __tolower_l (Ch, L)
237 # else
238 # define TOUPPER(Ch, L) toupper (Ch)
239 # define TOLOWER(Ch, L) tolower (Ch)
240 # endif
241 # else
242 # define TOUPPER(Ch, L) (islower (Ch) ? toupper (Ch) : (Ch))
243 # define TOLOWER(Ch, L) (isupper (Ch) ? tolower (Ch) : (Ch))
244 # endif
245 #endif
246 /* We don't use `isdigit' here since the locale dependent
247 interpretation is not what we want here. We only need to accept
248 the arabic digits in the ASCII range. One day there is perhaps a
249 more reliable way to accept other sets of digits. */
250 #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
251
252 static CHAR_T *
memcpy_lowcase(CHAR_T * dest,const CHAR_T * src,size_t len LOCALE_PARAM_PROTO)253 memcpy_lowcase (CHAR_T *dest, const CHAR_T *src,
254 size_t len LOCALE_PARAM_PROTO)
255 {
256 while (len-- > 0)
257 dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
258 return dest;
259 }
260
261 static CHAR_T *
memcpy_uppcase(CHAR_T * dest,const CHAR_T * src,size_t len LOCALE_PARAM_PROTO)262 memcpy_uppcase (CHAR_T *dest, const CHAR_T *src,
263 size_t len LOCALE_PARAM_PROTO)
264 {
265 while (len-- > 0)
266 dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
267 return dest;
268 }
269
270
271 #if ! HAVE_TM_GMTOFF
272 /* Yield the difference between *A and *B,
273 measured in seconds, ignoring leap seconds. */
274 # define tm_diff ftime_tm_diff
275 static int
tm_diff(const struct tm * a,const struct tm * b)276 tm_diff (const struct tm *a, const struct tm *b)
277 {
278 /* Compute intervening leap days correctly even if year is negative.
279 Take care to avoid int overflow in leap day calculations,
280 but it's OK to assume that A and B are close to each other. */
281 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
282 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
283 int a100 = a4 / 25 - (a4 % 25 < 0);
284 int b100 = b4 / 25 - (b4 % 25 < 0);
285 int a400 = a100 >> 2;
286 int b400 = b100 >> 2;
287 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
288 int years = a->tm_year - b->tm_year;
289 int days = (365 * years + intervening_leap_days
290 + (a->tm_yday - b->tm_yday));
291 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
292 + (a->tm_min - b->tm_min))
293 + (a->tm_sec - b->tm_sec));
294 }
295 #endif /* ! HAVE_TM_GMTOFF */
296
297
298
299 /* The number of days from the first day of the first ISO week of this
300 year to the year day YDAY with week day WDAY. ISO weeks start on
301 Monday; the first ISO week has the year's first Thursday. YDAY may
302 be as small as YDAY_MINIMUM. */
303 #define ISO_WEEK_START_WDAY 1 /* Monday */
304 #define ISO_WEEK1_WDAY 4 /* Thursday */
305 #define YDAY_MINIMUM (-366)
306 #ifdef __GNUC__
307 __inline__
308 #endif
309 static int
iso_week_days(int yday,int wday)310 iso_week_days (int yday, int wday)
311 {
312 /* Add enough to the first operand of % to make it nonnegative. */
313 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
314 return (yday
315 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
316 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
317 }
318
319
320 #if !(defined _NL_CURRENT || HAVE_STRFTIME)
321 static CHAR_T const weekday_name[][10] =
322 {
323 L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
324 L_("Thursday"), L_("Friday"), L_("Saturday")
325 };
326 static CHAR_T const month_name[][10] =
327 {
328 L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
329 L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
330 L_("November"), L_("December")
331 };
332 #endif
333
334
335 /* When compiling this file, GNU applications can #define my_strftime
336 to a symbol (typically nstrftime) to get an extended strftime with
337 extra arguments UT and NS. Emacs is a special case for now, but
338 this Emacs-specific code can be removed once Emacs's config.h
339 defines my_strftime. */
340 #if defined emacs && !defined my_strftime
341 # define my_strftime nstrftime
342 #endif
343
344 #ifdef my_strftime
345 # define extra_args , ut, ns
346 # define extra_args_spec , int ut, int ns
347 #else
348 # ifdef COMPILE_WIDE
349 # define my_strftime wcsftime
350 # define nl_get_alt_digit _nl_get_walt_digit
351 # else
352 # define my_strftime strftime
353 # define nl_get_alt_digit _nl_get_alt_digit
354 # endif
355 # define extra_args
356 # define extra_args_spec
357 /* We don't have this information in general. */
358 # define ut 0
359 # define ns 0
360 #endif
361
362 #if ! defined _LIBC && ! HAVE_RUN_TZSET_TEST
363 /* Solaris 2.5.x and 2.6 tzset sometimes modify the storage returned
364 by localtime. On such systems, we must use the tzset and localtime
365 wrappers to work around the bug. */
366 "you must run the autoconf test for a working tzset function"
367 #endif
368
369
370 /* Write information from TP into S according to the format
371 string FORMAT, writing no more that MAXSIZE characters
372 (including the terminating '\0') and returning number of
373 characters written. If S is NULL, nothing will be written
374 anywhere, so to determine how many characters would be
375 written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
376 size_t
377 my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
378 const struct tm *tp extra_args_spec LOCALE_PARAM_PROTO)
379 {
380 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
381 struct locale_data *const current = loc->__locales[LC_TIME];
382 #endif
383
384 int hour12 = tp->tm_hour;
385 #ifdef _NL_CURRENT
386 /* We cannot make the following values variables since we must delay
387 the evaluation of these values until really needed since some
388 expressions might not be valid in every situation. The `struct tm'
389 might be generated by a strptime() call that initialized
390 only a few elements. Dereference the pointers only if the format
391 requires this. Then it is ok to fail if the pointers are invalid. */
392 # define a_wkday \
393 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
394 # define f_wkday \
395 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
396 # define a_month \
397 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
398 # define f_month \
399 ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
400 # define ampm \
401 ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
402 ? NLW(PM_STR) : NLW(AM_STR)))
403
404 # define aw_len STRLEN (a_wkday)
405 # define am_len STRLEN (a_month)
406 # define ap_len STRLEN (ampm)
407 #else
408 # if !HAVE_STRFTIME
409 # define f_wkday (weekday_name[tp->tm_wday])
410 # define f_month (month_name[tp->tm_mon])
411 # define a_wkday f_wkday
412 # define a_month f_month
413 # define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
414
415 size_t aw_len = 3;
416 size_t am_len = 3;
417 size_t ap_len = 2;
418 # endif
419 #endif
420 const char *zone;
421 size_t i = 0;
422 CHAR_T *p = s;
423 const CHAR_T *f;
424 #if DO_MULTIBYTE && !defined COMPILE_WIDE
425 const char *format_end = NULL;
426 #endif
427
428 zone = NULL;
429 #if HAVE_TM_ZONE
430 /* The POSIX test suite assumes that setting
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
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. */
436 zone = (const char *) tp->tm_zone;
437 #endif
438 #if HAVE_TZNAME
439 if (ut)
440 {
441 if (! (zone && *zone))
442 zone = "GMT";
443 }
444 else
445 {
446 /* POSIX.1 requires that local time zone information be used as
447 though strftime called tzset. */
448 # if HAVE_TZSET
449 tzset ();
450 # endif
451 }
452 #endif
453
454 if (hour12 > 12)
455 hour12 -= 12;
456 else
457 if (hour12 == 0)
458 hour12 = 12;
459
460 for (f = format; *f != '\0'; ++f)
461 {
462 int pad = 0; /* Padding for number ('-', '_', or 0). */
463 int modifier; /* Field modifier ('E', 'O', or 0). */
464 int digits; /* Max digits for numeric format. */
465 int number_value; /* Numeric value to be printed. */
466 int negative_number; /* 1 if the number is negative. */
467 const CHAR_T *subfmt;
468 CHAR_T *bufp;
469 CHAR_T buf[1 + (sizeof (int) < sizeof (time_t)
470 ? INT_STRLEN_BOUND (time_t)
471 : INT_STRLEN_BOUND (int))];
472 int width = -1;
473 int to_lowcase = 0;
474 int to_uppcase = 0;
475 int change_case = 0;
476 int format_char;
477
478 #if DO_MULTIBYTE && !defined COMPILE_WIDE
479 switch (*f)
480 {
481 case L_('%'):
482 break;
483
484 case L_('\b'): case L_('\t'): case L_('\n'):
485 case L_('\v'): case L_('\f'): case L_('\r'):
486 case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
487 case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
488 case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
489 case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
490 case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
491 case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
492 case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
493 case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
494 case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
495 case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
496 case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
497 case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
498 case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
499 case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
500 case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
501 case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
502 case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
503 case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
504 case L_('~'):
505 /* The C Standard requires these 98 characters (plus '%') to
506 be in the basic execution character set. None of these
507 characters can start a multibyte sequence, so they need
508 not be analyzed further. */
509 add (1, *p = *f);
510 continue;
511
512 default:
513 /* Copy this multibyte sequence until we reach its end, find
514 an error, or come back to the initial shift state. */
515 {
516 mbstate_t mbstate = mbstate_zero;
517 size_t len = 0;
518 size_t fsize;
519
520 if (! format_end)
521 format_end = f + strlen (f) + 1;
522 fsize = format_end - f;
523
524 do
525 {
526 size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
527
528 if (bytes == 0)
529 break;
530
531 if (bytes == (size_t) -2)
532 {
533 len += strlen (f + len);
534 break;
535 }
536
537 if (bytes == (size_t) -1)
538 {
539 len++;
540 break;
541 }
542
543 len += bytes;
544 }
545 while (! mbsinit (&mbstate));
546
547 cpy (len, f);
548 f += len - 1;
549 continue;
550 }
551 }
552
553 #else /* ! DO_MULTIBYTE */
554
555 /* Either multibyte encodings are not supported, they are
556 safe for formats, so any non-'%' byte can be copied through,
557 or this is the wide character version. */
558 if (*f != L_('%'))
559 {
560 add (1, *p = *f);
561 continue;
562 }
563
564 #endif /* ! DO_MULTIBYTE */
565
566 /* Check for flags that can modify a format. */
567 while (1)
568 {
569 switch (*++f)
570 {
571 /* This influences the number formats. */
572 case L_('_'):
573 case L_('-'):
574 case L_('0'):
575 pad = *f;
576 continue;
577
578 /* This changes textual output. */
579 case L_('^'):
580 to_uppcase = 1;
581 continue;
582 case L_('#'):
583 change_case = 1;
584 continue;
585
586 default:
587 break;
588 }
589 break;
590 }
591
592 /* As a GNU extension we allow to specify the field width. */
593 if (ISDIGIT (*f))
594 {
595 width = 0;
596 do
597 {
598 if (width > INT_MAX / 10
599 || (width == INT_MAX / 10 && *f - L_('0') > INT_MAX % 10))
600 /* Avoid overflow. */
601 width = INT_MAX;
602 else
603 {
604 width *= 10;
605 width += *f - L_('0');
606 }
607 ++f;
608 }
609 while (ISDIGIT (*f));
610 }
611
612 /* Check for modifiers. */
613 switch (*f)
614 {
615 case L_('E'):
616 case L_('O'):
617 modifier = *f++;
618 break;
619
620 default:
621 modifier = 0;
622 break;
623 }
624
625 /* Now do the specified format. */
626 format_char = *f;
627 switch (format_char)
628 {
629 #define DO_NUMBER(d, v) \
630 digits = d > width ? d : width; \
631 number_value = v; goto do_number
632 #define DO_NUMBER_SPACEPAD(d, v) \
633 digits = d > width ? d : width; \
634 number_value = v; goto do_number_spacepad
635
636 case L_('%'):
637 if (modifier != 0)
638 goto bad_format;
639 add (1, *p = *f);
640 break;
641
642 case L_('a'):
643 if (modifier != 0)
644 goto bad_format;
645 if (change_case)
646 {
647 to_uppcase = 1;
648 to_lowcase = 0;
649 }
650 #if defined _NL_CURRENT || !HAVE_STRFTIME
651 cpy (aw_len, a_wkday);
652 break;
653 #else
654 goto underlying_strftime;
655 #endif
656
657 case 'A':
658 if (modifier != 0)
659 goto bad_format;
660 if (change_case)
661 {
662 to_uppcase = 1;
663 to_lowcase = 0;
664 }
665 #if defined _NL_CURRENT || !HAVE_STRFTIME
666 cpy (STRLEN (f_wkday), f_wkday);
667 break;
668 #else
669 goto underlying_strftime;
670 #endif
671
672 case L_('b'):
673 case L_('h'):
674 if (change_case)
675 {
676 to_uppcase = 1;
677 to_lowcase = 0;
678 }
679 if (modifier != 0)
680 goto bad_format;
681 #if defined _NL_CURRENT || !HAVE_STRFTIME
682 cpy (am_len, a_month);
683 break;
684 #else
685 goto underlying_strftime;
686 #endif
687
688 case L_('B'):
689 if (modifier != 0)
690 goto bad_format;
691 if (change_case)
692 {
693 to_uppcase = 1;
694 to_lowcase = 0;
695 }
696 #if defined _NL_CURRENT || !HAVE_STRFTIME
697 cpy (STRLEN (f_month), f_month);
698 break;
699 #else
700 goto underlying_strftime;
701 #endif
702
703 case L_('c'):
704 if (modifier == L_('O'))
705 goto bad_format;
706 #ifdef _NL_CURRENT
707 if (! (modifier == 'E'
708 && (*(subfmt =
709 (const CHAR_T *) _NL_CURRENT (LC_TIME,
710 NLW(ERA_D_T_FMT)))
711 != '\0')))
712 subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
713 #else
714 # if HAVE_STRFTIME
715 goto underlying_strftime;
716 # else
717 subfmt = L_("%a %b %e %H:%M:%S %Y");
718 # endif
719 #endif
720
721 subformat:
722 {
723 CHAR_T *old_start = p;
724 size_t len = my_strftime (NULL, (size_t) -1, subfmt,
725 tp extra_args LOCALE_ARG);
726 add (len, my_strftime (p, maxsize - i, subfmt,
727 tp extra_args LOCALE_ARG));
728
729 if (to_uppcase)
730 while (old_start < p)
731 {
732 *old_start = TOUPPER ((UCHAR_T) *old_start, loc);
733 ++old_start;
734 }
735 }
736 break;
737
738 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
739 underlying_strftime:
740 {
741 /* The relevant information is available only via the
742 underlying strftime implementation, so use that. */
743 char ufmt[4];
744 char *u = ufmt;
745 char ubuf[1024]; /* enough for any single format in practice */
746 size_t len;
747 /* Make sure we're calling the actual underlying strftime.
748 In some cases, config.h contains something like
749 "#define strftime rpl_strftime". */
750 # ifdef strftime
751 # undef strftime
752 size_t strftime ();
753 # endif
754
755 *u++ = '%';
756 if (modifier != 0)
757 *u++ = modifier;
758 *u++ = format_char;
759 *u = '\0';
760 len = strftime (ubuf, sizeof ubuf, ufmt, tp);
761 if (len == 0 && ubuf[0] != '\0')
762 return 0;
763 cpy (len, ubuf);
764 }
765 break;
766 #endif
767
768 case L_('C'):
769 if (modifier == L_('O'))
770 goto bad_format;
771 if (modifier == L_('E'))
772 {
773 #if HAVE_STRUCT_ERA_ENTRY
774 struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
775 if (era)
776 {
777 # ifdef COMPILE_WIDE
778 size_t len = __wcslen (era->era_wname);
779 cpy (len, era->era_wname);
780 # else
781 size_t len = strlen (era->era_name);
782 cpy (len, era->era_name);
783 # endif
784 break;
785 }
786 #else
787 # if HAVE_STRFTIME
788 goto underlying_strftime;
789 # endif
790 #endif
791 }
792
793 {
794 int year = tp->tm_year + TM_YEAR_BASE;
795 DO_NUMBER (1, year / 100 - (year % 100 < 0));
796 }
797
798 case L_('x'):
799 if (modifier == L_('O'))
800 goto bad_format;
801 #ifdef _NL_CURRENT
802 if (! (modifier == L_('E')
803 && (*(subfmt =
804 (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
805 != L_('\0'))))
806 subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
807 goto subformat;
808 #else
809 # if HAVE_STRFTIME
810 goto underlying_strftime;
811 # else
812 /* Fall through. */
813 # endif
814 #endif
815 case L_('D'):
816 if (modifier != 0)
817 goto bad_format;
818 subfmt = L_("%m/%d/%y");
819 goto subformat;
820
821 case L_('d'):
822 if (modifier == L_('E'))
823 goto bad_format;
824
825 DO_NUMBER (2, tp->tm_mday);
826
827 case L_('e'):
828 if (modifier == L_('E'))
829 goto bad_format;
830
831 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
832
833 /* All numeric formats set DIGITS and NUMBER_VALUE and then
834 jump to one of these two labels. */
835
836 do_number_spacepad:
837 /* Force `_' flag unless overridden by `0' or `-' flag. */
838 if (pad != L_('0') && pad != L_('-'))
839 pad = L_('_');
840
841 do_number:
842 /* Format the number according to the MODIFIER flag. */
843
844 if (modifier == L_('O') && 0 <= number_value)
845 {
846 #ifdef _NL_CURRENT
847 /* Get the locale specific alternate representation of
848 the number NUMBER_VALUE. If none exist NULL is returned. */
849 const CHAR_T *cp = nl_get_alt_digit (number_value
850 HELPER_LOCALE_ARG);
851
852 if (cp != NULL)
853 {
854 size_t digitlen = STRLEN (cp);
855 if (digitlen != 0)
856 {
857 cpy (digitlen, cp);
858 break;
859 }
860 }
861 #else
862 # if HAVE_STRFTIME
863 goto underlying_strftime;
864 # endif
865 #endif
866 }
867 {
868 unsigned int u = number_value;
869
870 bufp = buf + sizeof (buf) / sizeof (buf[0]);
871 negative_number = number_value < 0;
872
873 if (negative_number)
874 u = -u;
875
876 do
877 *--bufp = u % 10 + L_('0');
878 while ((u /= 10) != 0);
879 }
880
881 do_number_sign_and_padding:
882 if (negative_number)
883 *--bufp = L_('-');
884
885 if (pad != L_('-'))
886 {
887 int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
888 - bufp);
889
890 if (padding > 0)
891 {
892 if (pad == L_('_'))
893 {
894 if ((size_t) padding >= maxsize - i)
895 return 0;
896
897 if (p)
898 memset_space (p, padding);
899 i += padding;
900 width = width > padding ? width - padding : 0;
901 }
902 else
903 {
904 if ((size_t) digits >= maxsize - i)
905 return 0;
906
907 if (negative_number)
908 {
909 ++bufp;
910
911 if (p)
912 *p++ = L_('-');
913 ++i;
914 }
915
916 if (p)
917 memset_zero (p, padding);
918 i += padding;
919 width = 0;
920 }
921 }
922 }
923
924 cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);
925 break;
926
927 case L_('F'):
928 if (modifier != 0)
929 goto bad_format;
930 subfmt = L_("%Y-%m-%d");
931 goto subformat;
932
933 case L_('H'):
934 if (modifier == L_('E'))
935 goto bad_format;
936
937 DO_NUMBER (2, tp->tm_hour);
938
939 case L_('I'):
940 if (modifier == L_('E'))
941 goto bad_format;
942
943 DO_NUMBER (2, hour12);
944
945 case L_('k'): /* GNU extension. */
946 if (modifier == L_('E'))
947 goto bad_format;
948
949 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
950
951 case L_('l'): /* GNU extension. */
952 if (modifier == L_('E'))
953 goto bad_format;
954
955 DO_NUMBER_SPACEPAD (2, hour12);
956
957 case L_('j'):
958 if (modifier == L_('E'))
959 goto bad_format;
960
961 DO_NUMBER (3, 1 + tp->tm_yday);
962
963 case L_('M'):
964 if (modifier == L_('E'))
965 goto bad_format;
966
967 DO_NUMBER (2, tp->tm_min);
968
969 case L_('m'):
970 if (modifier == L_('E'))
971 goto bad_format;
972
973 DO_NUMBER (2, tp->tm_mon + 1);
974
975 #ifndef _LIBC
976 case L_('N'): /* GNU extension. */
977 if (modifier == L_('E'))
978 goto bad_format;
979
980 number_value = ns;
981 if (width != -1)
982 {
983 /* Take an explicit width less than 9 as a precision. */
984 int j;
985 for (j = width; j < 9; j++)
986 number_value /= 10;
987 }
988
989 DO_NUMBER (9, number_value);
990 #endif
991
992 case L_('n'):
993 add (1, *p = L_('\n'));
994 break;
995
996 case L_('P'):
997 to_lowcase = 1;
998 #if !defined _NL_CURRENT && HAVE_STRFTIME
999 format_char = L_('p');
1000 #endif
1001 /* FALLTHROUGH */
1002
1003 case L_('p'):
1004 if (change_case)
1005 {
1006 to_uppcase = 0;
1007 to_lowcase = 1;
1008 }
1009 #if defined _NL_CURRENT || !HAVE_STRFTIME
1010 cpy (ap_len, ampm);
1011 break;
1012 #else
1013 goto underlying_strftime;
1014 #endif
1015
1016 case L_('R'):
1017 subfmt = L_("%H:%M");
1018 goto subformat;
1019
1020 case L_('r'):
1021 #if !defined _NL_CURRENT && HAVE_STRFTIME
1022 goto underlying_strftime;
1023 #else
1024 # ifdef _NL_CURRENT
1025 if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
1026 NLW(T_FMT_AMPM)))
1027 == L_('\0'))
1028 # endif
1029 subfmt = L_("%I:%M:%S %p");
1030 goto subformat;
1031 #endif
1032
1033 case L_('S'):
1034 if (modifier == L_('E'))
1035 goto bad_format;
1036
1037 DO_NUMBER (2, tp->tm_sec);
1038
1039 case L_('s'): /* GNU extension. */
1040 {
1041 struct tm ltm;
1042 time_t t;
1043
1044 ltm = *tp;
1045 t = mktime (<m);
1046
1047 /* Generate string value for T using time_t arithmetic;
1048 this works even if sizeof (long) < sizeof (time_t). */
1049
1050 bufp = buf + sizeof (buf) / sizeof (buf[0]);
1051 negative_number = t < 0;
1052
1053 do
1054 {
1055 int d = t % 10;
1056 t /= 10;
1057
1058 if (negative_number)
1059 {
1060 d = -d;
1061
1062 /* Adjust if division truncates to minus infinity. */
1063 if (0 < -1 % 10 && d < 0)
1064 {
1065 t++;
1066 d += 10;
1067 }
1068 }
1069
1070 *--bufp = d + L_('0');
1071 }
1072 while (t != 0);
1073
1074 digits = 1;
1075 goto do_number_sign_and_padding;
1076 }
1077
1078 case L_('X'):
1079 if (modifier == L_('O'))
1080 goto bad_format;
1081 #ifdef _NL_CURRENT
1082 if (! (modifier == L_('E')
1083 && (*(subfmt =
1084 (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
1085 != L_('\0'))))
1086 subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
1087 goto subformat;
1088 #else
1089 # if HAVE_STRFTIME
1090 goto underlying_strftime;
1091 # else
1092 /* Fall through. */
1093 # endif
1094 #endif
1095 case L_('T'):
1096 subfmt = L_("%H:%M:%S");
1097 goto subformat;
1098
1099 case L_('t'):
1100 add (1, *p = L_('\t'));
1101 break;
1102
1103 case L_('u'):
1104 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
1105
1106 case L_('U'):
1107 if (modifier == L_('E'))
1108 goto bad_format;
1109
1110 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
1111
1112 case L_('V'):
1113 case L_('g'):
1114 case L_('G'):
1115 if (modifier == L_('E'))
1116 goto bad_format;
1117 {
1118 int year = tp->tm_year + TM_YEAR_BASE;
1119 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
1120
1121 if (days < 0)
1122 {
1123 /* This ISO week belongs to the previous year. */
1124 year--;
1125 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
1126 tp->tm_wday);
1127 }
1128 else
1129 {
1130 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
1131 tp->tm_wday);
1132 if (0 <= d)
1133 {
1134 /* This ISO week belongs to the next year. */
1135 year++;
1136 days = d;
1137 }
1138 }
1139
1140 switch (*f)
1141 {
1142 case L_('g'):
1143 DO_NUMBER (2, (year % 100 + 100) % 100);
1144
1145 case L_('G'):
1146 DO_NUMBER (1, year);
1147
1148 default:
1149 DO_NUMBER (2, days / 7 + 1);
1150 }
1151 }
1152
1153 case L_('W'):
1154 if (modifier == L_('E'))
1155 goto bad_format;
1156
1157 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
1158
1159 case L_('w'):
1160 if (modifier == L_('E'))
1161 goto bad_format;
1162
1163 DO_NUMBER (1, tp->tm_wday);
1164
1165 case L_('Y'):
1166 if (modifier == 'E')
1167 {
1168 #if HAVE_STRUCT_ERA_ENTRY
1169 struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1170 if (era)
1171 {
1172 # ifdef COMPILE_WIDE
1173 subfmt = era->era_wformat;
1174 # else
1175 subfmt = era->era_format;
1176 # endif
1177 goto subformat;
1178 }
1179 #else
1180 # if HAVE_STRFTIME
1181 goto underlying_strftime;
1182 # endif
1183 #endif
1184 }
1185 if (modifier == L_('O'))
1186 goto bad_format;
1187 else
1188 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
1189
1190 case L_('y'):
1191 if (modifier == L_('E'))
1192 {
1193 #if HAVE_STRUCT_ERA_ENTRY
1194 struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
1195 if (era)
1196 {
1197 int delta = tp->tm_year - era->start_date[0];
1198 DO_NUMBER (1, (era->offset
1199 + delta * era->absolute_direction));
1200 }
1201 #else
1202 # if HAVE_STRFTIME
1203 goto underlying_strftime;
1204 # endif
1205 #endif
1206 }
1207 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
1208
1209 case L_('Z'):
1210 if (change_case)
1211 {
1212 to_uppcase = 0;
1213 to_lowcase = 1;
1214 }
1215
1216 #if HAVE_TZNAME
1217 /* The tzset() call might have changed the value. */
1218 if (!(zone && *zone) && tp->tm_isdst >= 0)
1219 zone = tzname[tp->tm_isdst];
1220 #endif
1221 if (! zone)
1222 zone = "";
1223
1224 #ifdef COMPILE_WIDE
1225 {
1226 /* The zone string is always given in multibyte form. We have
1227 to transform it first. */
1228 wchar_t *wczone;
1229 size_t len;
1230 widen (zone, wczone, len);
1231 cpy (len, wczone);
1232 }
1233 #else
1234 cpy (strlen (zone), zone);
1235 #endif
1236 break;
1237
1238 case L_('z'):
1239 if (tp->tm_isdst < 0)
1240 break;
1241
1242 {
1243 int diff;
1244 #if HAVE_TM_GMTOFF
1245 diff = tp->tm_gmtoff;
1246 #else
1247 if (ut)
1248 diff = 0;
1249 else
1250 {
1251 struct tm gtm;
1252 struct tm ltm;
1253 time_t lt;
1254
1255 ltm = *tp;
1256 lt = mktime (<m);
1257
1258 if (lt == (time_t) -1)
1259 {
1260 /* mktime returns -1 for errors, but -1 is also a
1261 valid time_t value. Check whether an error really
1262 occurred. */
1263 struct tm tm;
1264
1265 if (! __localtime_r (<, &tm)
1266 || ((ltm.tm_sec ^ tm.tm_sec)
1267 | (ltm.tm_min ^ tm.tm_min)
1268 | (ltm.tm_hour ^ tm.tm_hour)
1269 | (ltm.tm_mday ^ tm.tm_mday)
1270 | (ltm.tm_mon ^ tm.tm_mon)
1271 | (ltm.tm_year ^ tm.tm_year)))
1272 break;
1273 }
1274
1275 if (! __gmtime_r (<, >m))
1276 break;
1277
1278 diff = tm_diff (<m, >m);
1279 }
1280 #endif
1281
1282 if (diff < 0)
1283 {
1284 add (1, *p = L_('-'));
1285 diff = -diff;
1286 }
1287 else
1288 add (1, *p = L_('+'));
1289
1290 diff /= 60;
1291 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
1292 }
1293
1294 case L_('\0'): /* GNU extension: % at end of format. */
1295 --f;
1296 /* Fall through. */
1297 default:
1298 /* Unknown format; output the format, including the '%',
1299 since this is most likely the right thing to do if a
1300 multibyte string has been misparsed. */
1301 bad_format:
1302 {
1303 int flen;
1304 for (flen = 1; f[1 - flen] != L_('%'); flen++)
1305 continue;
1306 cpy (flen, &f[1 - flen]);
1307 }
1308 break;
1309 }
1310 }
1311
1312 if (p && maxsize != 0)
1313 *p = L_('\0');
1314 return i;
1315 }
1316 #ifdef _LIBC
libc_hidden_def(my_strftime)1317 libc_hidden_def (my_strftime)
1318 #endif
1319
1320
1321 #ifdef emacs
1322 /* For Emacs we have a separate interface which corresponds to the normal
1323 strftime function plus the ut argument, but without the ns argument. */
1324 size_t
1325 emacs_strftimeu (char *s, size_t maxsize, const char *format,
1326 const struct tm *tp, int ut)
1327 {
1328 return my_strftime (s, maxsize, format, tp, ut, 0);
1329 }
1330 #endif
1331