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