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