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