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

source code of glibc/time/strftime_l.c