LCOV - code coverage report
Current view: top level - lib - strftime.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 371 416 89.2 %
Date: 2018-01-30 Functions: 6 8 75.0 %

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

Generated by: LCOV version 1.10