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

source code of glibc/time/strftime_l.c