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 <stddef.h>
    66 #include <stdlib.h>
    67 #include <string.h>
    68 
    69 #include "attribute.h"
    70 #include <intprops.h>
    71 
    72 #ifdef COMPILE_WIDE
    73 # include <endian.h>
    74 # define CHAR_T wchar_t
    75 # define UCHAR_T unsigned int
    76 # define L_(Str) L##Str
    77 # define NLW(Sym) _NL_W##Sym
    78 
    79 # define MEMCPY(d, s, n) __wmemcpy (d, s, n)
    80 # define STRLEN(s) __wcslen (s)
    81 
    82 #else
    83 # define CHAR_T char
    84 # define UCHAR_T unsigned char
    85 # define L_(Str) Str
    86 # define NLW(Sym) Sym
    87 # define ABALTMON_1 _NL_ABALTMON_1
    88 
    89 # define MEMCPY(d, s, n) memcpy (d, s, n)
    90 # define STRLEN(s) strlen (s)
    91 
    92 #endif
    93 
    94 /* Shift A right by B bits portably, by dividing A by 2**B and
    95    truncating towards minus infinity.  A and B should be free of side
    96    effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
    97    INT_BITS is the number of useful bits in an int.  GNU code can
    98    assume that INT_BITS is at least 32.
    99 
   100    ISO C99 says that A >> B is implementation-defined if A < 0.  Some
   101    implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
   102    right in the usual way when A < 0, so SHR falls back on division if
   103    ordinary A >> B doesn't seem to be the usual signed shift.  */
   104 #define SHR(a, b)       \
   105   (-1 >> 1 == -1        \
   106    ? (a) >> (b)         \
   107    : ((a) + ((a) < 0)) / (1 << (b)) - ((a) < 0))
   108 
   109 #define TM_YEAR_BASE 1900
   110 
   111 #ifndef __isleap
   112 /* Nonzero if YEAR is a leap year (every 4 years,
   113    except every 100th isn't, and every 400th is).  */
   114 # define __isleap(year) \
   115   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
   116 #endif
   117 
   118 
   119 #ifdef _LIBC
   120 # define mktime_z(tz, tm) mktime (tm)
   121 # define tzname __tzname
   122 # define tzset __tzset
   123 #endif
   124 
   125 #ifndef FPRINTFTIME
   126 # define FPRINTFTIME 0
   127 #endif
   128 
   129 #if FPRINTFTIME
   130 # define STREAM_OR_CHAR_T FILE
   131 # define STRFTIME_ARG(x) /* empty */
   132 #else
   133 # define STREAM_OR_CHAR_T CHAR_T
   134 # define STRFTIME_ARG(x) x,
   135 #endif
   136 
   137 #if FPRINTFTIME
   138 # define memset_byte(P, Len, Byte) \
   139   do { size_t _i; for (_i = 0; _i < Len; _i++) fputc (Byte, P); } while (0)
   140 # define memset_space(P, Len) memset_byte (P, Len, ' ')
   141 # define memset_zero(P, Len) memset_byte (P, Len, '0')
   142 #elif defined COMPILE_WIDE
   143 # define memset_space(P, Len) (wmemset (P, L' ', Len), (P) += (Len))
   144 # define memset_zero(P, Len) (wmemset (P, L'0', Len), (P) += (Len))
   145 #else
   146 # define memset_space(P, Len) (memset (P, ' ', Len), (P) += (Len))
   147 # define memset_zero(P, Len) (memset (P, '0', Len), (P) += (Len))
   148 #endif
   149 
   150 #if FPRINTFTIME
   151 # define advance(P, N)
   152 #else
   153 # define advance(P, N) ((P) += (N))
   154 #endif
   155 
   156 #define add(n, f) width_add (width, n, f)
   157 #define width_add(width, n, f)                                                \
   158   do                                                                          \
   159     {                                                                         \
   160       size_t _n = (n);                                                        \
   161       size_t _w = pad == L_('-') || width < 0 ? 0 : width;                    \
   162       size_t _incr = _n < _w ? _w : _n;                                       \
   163       if (_incr >= maxsize - i)                                               \
   164         {                                                                     \
   165           errno = ERANGE;                                                     \
   166           return 0;                                                           \
   167         }                                                                     \
   168       if (p)                                                                  \
   169         {                                                                     \
   170           if (_n < _w)                                                        \
   171             {                                                                 \
   172               size_t _delta = _w - _n;                                        \
   173               if (pad == L_('0') || pad == L_('+'))                           \
   174                 memset_zero (p, _delta);                                      \
   175               else                                                            \
   176                 memset_space (p, _delta);                                     \
   177             }                                                                 \
   178           f;                                                                  \
   179           advance (p, _n);                                                    \
   180         }                                                                     \
   181       i += _incr;                                                             \
   182     } while (0)
   183 
   184 #define add1(c) width_add1 (width, c)
   185 #if FPRINTFTIME
   186 # define width_add1(width, c) width_add (width, 1, fputc (c, p))
   187 #else
   188 # define width_add1(width, c) width_add (width, 1, *p = c)
   189 #endif
   190 
   191 #define cpy(n, s) width_cpy (width, n, s)
   192 #if FPRINTFTIME
   193 # define width_cpy(width, n, s)                                               \
   194     width_add (width, n,                                                      \
   195      do                                                                       \
   196        {                                                                      \
   197          if (to_lowcase)                                                      \
   198            fwrite_lowcase (p, (s), _n);                                       \
   199          else if (to_uppcase)                                                 \
   200            fwrite_uppcase (p, (s), _n);                                       \
   201          else                                                                 \
   202            {                                                                  \
   203              /* Ignore the value of fwrite.  The caller can determine whether \
   204                 an error occurred by inspecting ferror (P).  All known fwrite \
   205                 implementations set the stream's error indicator when they    \
   206                 fail due to ENOMEM etc., even though C11 and POSIX.1-2008 do  \
   207                 not require this.  */                                         \
   208              fwrite (s, _n, 1, p);                                            \
   209            }                                                                  \
   210        }                                                                      \
   211      while (0)                                                                \
   212     )
   213 #else
   214 # define width_cpy(width, n, s)                                               \
   215     width_add (width, n,                                                      \
   216          if (to_lowcase)                                                      \
   217            memcpy_lowcase (p, (s), _n LOCALE_ARG);                            \
   218          else if (to_uppcase)                                                 \
   219            memcpy_uppcase (p, (s), _n LOCALE_ARG);                            \
   220          else                                                                 \
   221            MEMCPY ((void *) p, (void const *) (s), _n))
   222 #endif
   223 
   224 #ifdef COMPILE_WIDE
   225 # ifndef USE_IN_EXTENDED_LOCALE_MODEL
   226 #  undef __mbsrtowcs_l
   227 #  define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
   228 # endif
   229 # define widen(os, ws, l) \
   230   {                                                                           \
   231     mbstate_t __st;                                                           \
   232     const char *__s = os;                                                     \
   233     memset (&__st, '\0', sizeof (__st));                                      \
   234     l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc);                            \
   235     ws = (wchar_t *) alloca ((l + 1) * sizeof (wchar_t));                     \
   236     (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc);                           \
   237   }
   238 #endif
   239 
   240 
   241 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
   242 /* We use this code also for the extended locale handling where the
   243    function gets as an additional argument the locale which has to be
   244    used.  To access the values we have to redefine the _NL_CURRENT
   245    macro.  */
   246 # define strftime               __strftime_l
   247 # define wcsftime               __wcsftime_l
   248 # undef _NL_CURRENT
   249 # define _NL_CURRENT(category, item) \
   250   (current->values[_NL_ITEM_INDEX (item)].string)
   251 # define LOCALE_PARAM , locale_t loc
   252 # define LOCALE_ARG , loc
   253 # define HELPER_LOCALE_ARG  , current
   254 #else
   255 # define LOCALE_PARAM
   256 # define LOCALE_ARG
   257 # ifdef _LIBC
   258 #  define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
   259 # else
   260 #  define HELPER_LOCALE_ARG
   261 # endif
   262 #endif
   263 
   264 #ifdef COMPILE_WIDE
   265 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
   266 #  define TOUPPER(Ch, L) __towupper_l (Ch, L)
   267 #  define TOLOWER(Ch, L) __towlower_l (Ch, L)
   268 # else
   269 #  define TOUPPER(Ch, L) towupper (Ch)
   270 #  define TOLOWER(Ch, L) towlower (Ch)
   271 # endif
   272 #else
   273 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
   274 #  define TOUPPER(Ch, L) __toupper_l (Ch, L)
   275 #  define TOLOWER(Ch, L) __tolower_l (Ch, L)
   276 # else
   277 #  define TOUPPER(Ch, L) toupper (Ch)
   278 #  define TOLOWER(Ch, L) tolower (Ch)
   279 # endif
   280 #endif
   281 /* We don't use 'isdigit' here since the locale dependent
   282    interpretation is not what we want here.  We only need to accept
   283    the arabic digits in the ASCII range.  One day there is perhaps a
   284    more reliable way to accept other sets of digits.  */
   285 #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
   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 (INT_MULTIPLY_WRAPV (width, 10, &width)
   688                   || INT_ADD_WRAPV (width, *f - L_('0'), &width))
   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 transform it first.  */
  1378             wchar_t *wczone;
  1379             size_t len;
  1380             widen (zone, wczone, len);
  1381             cpy (len, wczone);
  1382           }
  1383 #else
  1384           cpy (strlen (zone), zone);
  1385 #endif
  1386           break;
  1387 
  1388         case L_(':'):
  1389           /* :, ::, and ::: are valid only just before 'z'.
  1390              :::: etc. are rejected later.  */
  1391           for (colons = 1; f[colons] == L_(':'); colons++)
  1392             continue;
  1393           if (f[colons] != L_('z'))
  1394             goto bad_format;
  1395           f += colons;
  1396           goto do_z_conversion;
  1397 
  1398         case L_('z'):
  1399           colons = 0;
  1400 
  1401         do_z_conversion:
  1402           if (tp->tm_isdst < 0)
  1403             break;
  1404 
  1405           {
  1406             int diff;
  1407             int hour_diff;
  1408             int min_diff;
  1409             int sec_diff;
  1410 #if HAVE_TM_GMTOFF
  1411             diff = tp->tm_gmtoff;
  1412 #else
  1413             if (!tz)
  1414               diff = 0;
  1415             else
  1416               {
  1417                 struct tm gtm;
  1418                 struct tm ltm;
  1419                 time_t lt;
  1420 
  1421                 /* POSIX.1 requires that local time zone information be used as
  1422                    though strftime called tzset.  */
  1423 # ifndef my_strftime
  1424                 if (!*tzset_called)
  1425                   {
  1426                     tzset ();
  1427                     *tzset_called = true;
  1428                   }
  1429 # endif
  1430 
  1431                 ltm = *tp;
  1432                 ltm.tm_wday = -1;
  1433                 lt = mktime_z (tz, &ltm);
  1434                 if (ltm.tm_wday < 0 || ! localtime_rz (0, &lt, &gtm))
  1435                   break;
  1436                 diff = tm_diff (&ltm, &gtm);
  1437               }
  1438 #endif
  1439 
  1440             negative_number = diff < 0 || (diff == 0 && *zone == '-');
  1441             hour_diff = diff / 60 / 60;
  1442             min_diff = diff / 60 % 60;
  1443             sec_diff = diff % 60;
  1444 
  1445             switch (colons)
  1446               {
  1447               case 0: /* +hhmm */
  1448                 DO_TZ_OFFSET (5, 0, hour_diff * 100 + min_diff);
  1449 
  1450               case 1: tz_hh_mm: /* +hh:mm */
  1451                 DO_TZ_OFFSET (6, 04, hour_diff * 100 + min_diff);
  1452 
  1453               case 2: tz_hh_mm_ss: /* +hh:mm:ss */
  1454                 DO_TZ_OFFSET (9, 024,
  1455                               hour_diff * 10000 + min_diff * 100 + sec_diff);
  1456 
  1457               case 3: /* +hh if possible, else +hh:mm, else +hh:mm:ss */
  1458                 if (sec_diff != 0)
  1459                   goto tz_hh_mm_ss;
  1460                 if (min_diff != 0)
  1461                   goto tz_hh_mm;
  1462                 DO_TZ_OFFSET (3, 0, hour_diff);
  1463 
  1464               default:
  1465                 goto bad_format;
  1466               }
  1467           }
  1468 
  1469         case L_('\0'):          /* GNU extension: % at end of format.  */
  1470         bad_percent:
  1471             --f;
  1472             FALLTHROUGH;
  1473         default:
  1474           /* Unknown format; output the format, including the '%',
  1475              since this is most likely the right thing to do if a
  1476              multibyte string has been misparsed.  */
  1477         bad_format:
  1478           cpy (f - percent + 1, percent);
  1479           break;
  1480         }
  1481     }
  1482 
  1483 #if ! FPRINTFTIME
  1484   if (p && maxsize != 0)
  1485     *p = L_('\0');
  1486 #endif
  1487 
  1488   errno = saved_errno;
  1489   return i;
  1490 }

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