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