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