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