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