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