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