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