root/maint/gnulib/lib/nstrftime.c

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

/* [previous][next][first][last][top][bottom][index][help] */