root/lib/nstrftime.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fwrite_lowcase
  2. fwrite_uppcase
  3. memcpy_lowcase
  4. memcpy_uppcase
  5. tm_diff
  6. iso_week_days
  7. my_strftime
  8. libc_hidden_def

     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 }

/* [<][>][^][v][top][bottom][index][help] */