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