xref: /netbsd-src/external/gpl2/diffutils/dist/lib/strftime.c (revision 75f6d617e282811cb173c2ccfbf5df0dd71f7045)
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 (&ltm);
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 (&ltm);
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 (&lt, &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 (&lt, &gtm))
1353*75f6d617Schristos 		  break;
1354*75f6d617Schristos 
1355*75f6d617Schristos 		diff = tm_diff (&ltm, &gtm);
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