Blame lib/nstrftime.c

Packit 8f70b4
/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit 8f70b4
   This file is part of the GNU C Library.
Packit 8f70b4
Packit 8f70b4
   The GNU C Library is free software; you can redistribute it and/or
Packit 8f70b4
   modify it under the terms of the GNU General Public
Packit 8f70b4
   License as published by the Free Software Foundation; either
Packit 8f70b4
   version 3 of the License, or (at your option) any later version.
Packit 8f70b4
Packit 8f70b4
   The GNU C Library is distributed in the hope that it will be useful,
Packit 8f70b4
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8f70b4
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 8f70b4
   General Public License for more details.
Packit 8f70b4
Packit 8f70b4
   You should have received a copy of the GNU General Public
Packit 8f70b4
   License along with the GNU C Library; if not, see
Packit 8f70b4
   <https://www.gnu.org/licenses/>.  */
Packit 8f70b4
Packit 8f70b4
#ifdef _LIBC
Packit 8f70b4
# define USE_IN_EXTENDED_LOCALE_MODEL 1
Packit 8f70b4
# define HAVE_STRUCT_ERA_ENTRY 1
Packit 8f70b4
# define HAVE_TM_GMTOFF 1
Packit 8f70b4
# define HAVE_TM_ZONE 1
Packit 8f70b4
# define HAVE_TZNAME 1
Packit 8f70b4
# define HAVE_TZSET 1
Packit 8f70b4
# include "../locale/localeinfo.h"
Packit 8f70b4
#else
Packit 8f70b4
# include <config.h>
Packit 8f70b4
# if FPRINTFTIME
Packit 8f70b4
#  include "fprintftime.h"
Packit 8f70b4
# else
Packit 8f70b4
#  include "strftime.h"
Packit 8f70b4
# endif
Packit 8f70b4
# include "time-internal.h"
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#include <ctype.h>
Packit 8f70b4
#include <time.h>
Packit 8f70b4
Packit 8f70b4
#if HAVE_TZNAME && !HAVE_DECL_TZNAME
Packit 8f70b4
extern char *tzname[];
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
/* Do multibyte processing if multibyte encodings are supported, unless
Packit 8f70b4
   multibyte sequences are safe in formats.  Multibyte sequences are
Packit 8f70b4
   safe if they cannot contain byte sequences that look like format
Packit 8f70b4
   conversion specifications.  The multibyte encodings used by the
Packit 8f70b4
   C library on the various platforms (UTF-8, GB2312, GBK, CP936,
Packit 8f70b4
   GB18030, EUC-TW, BIG5, BIG5-HKSCS, CP950, EUC-JP, EUC-KR, CP949,
Packit 8f70b4
   SHIFT_JIS, CP932, JOHAB) are safe for formats, because the byte '%'
Packit 8f70b4
   cannot occur in a multibyte character except in the first byte.
Packit 8f70b4
Packit 8f70b4
   The DEC-HANYU encoding used on OSF/1 is not safe for formats, but
Packit 8f70b4
   this encoding has never been seen in real-life use, so we ignore
Packit 8f70b4
   it.  */
Packit 8f70b4
#if !(defined __osf__ && 0)
Packit 8f70b4
# define MULTIBYTE_IS_FORMAT_SAFE 1
Packit 8f70b4
#endif
Packit 8f70b4
#define DO_MULTIBYTE (! MULTIBYTE_IS_FORMAT_SAFE)
Packit 8f70b4
Packit 8f70b4
#if DO_MULTIBYTE
Packit 8f70b4
# include <wchar.h>
Packit 8f70b4
  static const mbstate_t mbstate_zero;
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#include <limits.h>
Packit 8f70b4
#include <stddef.h>
Packit 8f70b4
#include <stdlib.h>
Packit 8f70b4
#include <string.h>
Packit 8f70b4
#include <stdbool.h>
Packit 8f70b4
Packit 8f70b4
#ifndef FALLTHROUGH
Packit 8f70b4
# if __GNUC__ < 7
Packit 8f70b4
#  define FALLTHROUGH ((void) 0)
Packit 8f70b4
# else
Packit 8f70b4
#  define FALLTHROUGH __attribute__ ((__fallthrough__))
Packit 8f70b4
# endif
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#ifdef COMPILE_WIDE
Packit 8f70b4
# include <endian.h>
Packit 8f70b4
# define CHAR_T wchar_t
Packit 8f70b4
# define UCHAR_T unsigned int
Packit 8f70b4
# define L_(Str) L##Str
Packit 8f70b4
# define NLW(Sym) _NL_W##Sym
Packit 8f70b4
Packit 8f70b4
# define MEMCPY(d, s, n) __wmemcpy (d, s, n)
Packit 8f70b4
# define STRLEN(s) __wcslen (s)
Packit 8f70b4
Packit 8f70b4
#else
Packit 8f70b4
# define CHAR_T char
Packit 8f70b4
# define UCHAR_T unsigned char
Packit 8f70b4
# define L_(Str) Str
Packit 8f70b4
# define NLW(Sym) Sym
Packit 8f70b4
# define ABALTMON_1 _NL_ABALTMON_1
Packit 8f70b4
Packit 8f70b4
# define MEMCPY(d, s, n) memcpy (d, s, n)
Packit 8f70b4
# define STRLEN(s) strlen (s)
Packit 8f70b4
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
/* Shift A right by B bits portably, by dividing A by 2**B and
Packit 8f70b4
   truncating towards minus infinity.  A and B should be free of side
Packit 8f70b4
   effects, and B should be in the range 0 <= B <= INT_BITS - 2, where
Packit 8f70b4
   INT_BITS is the number of useful bits in an int.  GNU code can
Packit 8f70b4
   assume that INT_BITS is at least 32.
Packit 8f70b4
Packit 8f70b4
   ISO C99 says that A >> B is implementation-defined if A < 0.  Some
Packit 8f70b4
   implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift
Packit 8f70b4
   right in the usual way when A < 0, so SHR falls back on division if
Packit 8f70b4
   ordinary A >> B doesn't seem to be the usual signed shift.  */
Packit 8f70b4
#define SHR(a, b)       \
Packit 8f70b4
  (-1 >> 1 == -1        \
Packit 8f70b4
   ? (a) >> (b)         \
Packit 8f70b4
   : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
Packit 8f70b4
Packit 8f70b4
/* Bound on length of the string representing an integer type or expression T.
Packit 8f70b4
   Subtract 1 for the sign bit if t is signed; log10 (2.0) < 146/485;
Packit 8f70b4
   add 1 for integer division truncation; add 1 more for a minus sign
Packit 8f70b4
   if needed.  */
Packit 8f70b4
#define INT_STRLEN_BOUND(t) \
Packit 8f70b4
  ((sizeof (t) * CHAR_BIT - 1) * 146 / 485 + 2)
Packit 8f70b4
Packit 8f70b4
#define TM_YEAR_BASE 1900
Packit 8f70b4
Packit 8f70b4
#ifndef __isleap
Packit 8f70b4
/* Nonzero if YEAR is a leap year (every 4 years,
Packit 8f70b4
   except every 100th isn't, and every 400th is).  */
Packit 8f70b4
# define __isleap(year) \
Packit 8f70b4
  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
#ifdef _LIBC
Packit 8f70b4
# define mktime_z(tz, tm) mktime (tm)
Packit 8f70b4
# define tzname __tzname
Packit 8f70b4
# define tzset __tzset
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#ifndef FPRINTFTIME
Packit 8f70b4
# define FPRINTFTIME 0
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#if FPRINTFTIME
Packit 8f70b4
# define STREAM_OR_CHAR_T FILE
Packit 8f70b4
# define STRFTIME_ARG(x) /* empty */
Packit 8f70b4
#else
Packit 8f70b4
# define STREAM_OR_CHAR_T CHAR_T
Packit 8f70b4
# define STRFTIME_ARG(x) x,
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#if FPRINTFTIME
Packit 8f70b4
# define memset_byte(P, Len, Byte) \
Packit 8f70b4
  do { size_t _i; for (_i = 0; _i < Len; _i++) fputc (Byte, P); } while (0)
Packit 8f70b4
# define memset_space(P, Len) memset_byte (P, Len, ' ')
Packit 8f70b4
# define memset_zero(P, Len) memset_byte (P, Len, '0')
Packit 8f70b4
#elif defined COMPILE_WIDE
Packit 8f70b4
# define memset_space(P, Len) (wmemset (P, L' ', Len), (P) += (Len))
Packit 8f70b4
# define memset_zero(P, Len) (wmemset (P, L'0', Len), (P) += (Len))
Packit 8f70b4
#else
Packit 8f70b4
# define memset_space(P, Len) (memset (P, ' ', Len), (P) += (Len))
Packit 8f70b4
# define memset_zero(P, Len) (memset (P, '0', Len), (P) += (Len))
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#if FPRINTFTIME
Packit 8f70b4
# define advance(P, N)
Packit 8f70b4
#else
Packit 8f70b4
# define advance(P, N) ((P) += (N))
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#define add(n, f)                                                             \
Packit 8f70b4
  do                                                                          \
Packit 8f70b4
    {                                                                         \
Packit 8f70b4
      size_t _n = (n);                                                        \
Packit 8f70b4
      size_t _w = (width < 0 ? 0 : width);                                    \
Packit 8f70b4
      size_t _incr = _n < _w ? _w : _n;                                       \
Packit 8f70b4
      if (_incr >= maxsize - i)                                               \
Packit 8f70b4
        return 0;                                                             \
Packit 8f70b4
      if (p)                                                                  \
Packit 8f70b4
        {                                                                     \
Packit 8f70b4
          if (digits == 0 && _n < _w)                                         \
Packit 8f70b4
            {                                                                 \
Packit 8f70b4
              size_t _delta = width - _n;                                     \
Packit 8f70b4
              if (pad == L_('0'))                                             \
Packit 8f70b4
                memset_zero (p, _delta);                                      \
Packit 8f70b4
              else                                                            \
Packit 8f70b4
                memset_space (p, _delta);                                     \
Packit 8f70b4
            }                                                                 \
Packit 8f70b4
          f;                                                                  \
Packit 8f70b4
          advance (p, _n);                                                    \
Packit 8f70b4
        }                                                                     \
Packit 8f70b4
      i += _incr;                                                             \
Packit 8f70b4
    } while (0)
Packit 8f70b4
Packit 8f70b4
#if FPRINTFTIME
Packit 8f70b4
# define add1(C) add (1, fputc (C, p))
Packit 8f70b4
#else
Packit 8f70b4
# define add1(C) add (1, *p = C)
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#if FPRINTFTIME
Packit 8f70b4
# define cpy(n, s) \
Packit 8f70b4
    add ((n),                                                                 \
Packit 8f70b4
     do                                                                       \
Packit 8f70b4
       {                                                                      \
Packit 8f70b4
         if (to_lowcase)                                                      \
Packit 8f70b4
           fwrite_lowcase (p, (s), _n);                                       \
Packit 8f70b4
         else if (to_uppcase)                                                 \
Packit 8f70b4
           fwrite_uppcase (p, (s), _n);                                       \
Packit 8f70b4
         else                                                                 \
Packit 8f70b4
           {                                                                  \
Packit 8f70b4
             /* Ignore the value of fwrite.  The caller can determine whether \
Packit 8f70b4
                an error occurred by inspecting ferror (P).  All known fwrite \
Packit 8f70b4
                implementations set the stream's error indicator when they    \
Packit 8f70b4
                fail due to ENOMEM etc., even though C11 and POSIX.1-2008 do  \
Packit 8f70b4
                not require this.  */                                         \
Packit 8f70b4
             fwrite (s, _n, 1, p);                                            \
Packit 8f70b4
           }                                                                  \
Packit 8f70b4
       }                                                                      \
Packit 8f70b4
     while (0)                                                                \
Packit 8f70b4
    )
Packit 8f70b4
#else
Packit 8f70b4
# define cpy(n, s)                                                            \
Packit 8f70b4
    add ((n),                                                                 \
Packit 8f70b4
         if (to_lowcase)                                                      \
Packit 8f70b4
           memcpy_lowcase (p, (s), _n LOCALE_ARG);                            \
Packit 8f70b4
         else if (to_uppcase)                                                 \
Packit 8f70b4
           memcpy_uppcase (p, (s), _n LOCALE_ARG);                            \
Packit 8f70b4
         else                                                                 \
Packit 8f70b4
           MEMCPY ((void *) p, (void const *) (s), _n))
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#ifdef COMPILE_WIDE
Packit 8f70b4
# ifndef USE_IN_EXTENDED_LOCALE_MODEL
Packit 8f70b4
#  undef __mbsrtowcs_l
Packit 8f70b4
#  define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
Packit 8f70b4
# endif
Packit 8f70b4
# define widen(os, ws, l) \
Packit 8f70b4
  {                                                                           \
Packit 8f70b4
    mbstate_t __st;                                                           \
Packit 8f70b4
    const char *__s = os;                                                     \
Packit 8f70b4
    memset (&__st, '\0', sizeof (__st));                                      \
Packit 8f70b4
    l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc);                            \
Packit 8f70b4
    ws = (wchar_t *) alloca ((l + 1) * sizeof (wchar_t));                     \
Packit 8f70b4
    (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc);                           \
Packit 8f70b4
  }
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
Packit 8f70b4
/* We use this code also for the extended locale handling where the
Packit 8f70b4
   function gets as an additional argument the locale which has to be
Packit 8f70b4
   used.  To access the values we have to redefine the _NL_CURRENT
Packit 8f70b4
   macro.  */
Packit 8f70b4
# define strftime               __strftime_l
Packit 8f70b4
# define wcsftime               __wcsftime_l
Packit 8f70b4
# undef _NL_CURRENT
Packit 8f70b4
# define _NL_CURRENT(category, item) \
Packit 8f70b4
  (current->values[_NL_ITEM_INDEX (item)].string)
Packit 8f70b4
# define LOCALE_PARAM , locale_t loc
Packit 8f70b4
# define LOCALE_ARG , loc
Packit 8f70b4
# define HELPER_LOCALE_ARG  , current
Packit 8f70b4
#else
Packit 8f70b4
# define LOCALE_PARAM
Packit 8f70b4
# define LOCALE_ARG
Packit 8f70b4
# ifdef _LIBC
Packit 8f70b4
#  define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
Packit 8f70b4
# else
Packit 8f70b4
#  define HELPER_LOCALE_ARG
Packit 8f70b4
# endif
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#ifdef COMPILE_WIDE
Packit 8f70b4
# ifdef USE_IN_EXTENDED_LOCALE_MODEL
Packit 8f70b4
#  define TOUPPER(Ch, L) __towupper_l (Ch, L)
Packit 8f70b4
#  define TOLOWER(Ch, L) __towlower_l (Ch, L)
Packit 8f70b4
# else
Packit 8f70b4
#  define TOUPPER(Ch, L) towupper (Ch)
Packit 8f70b4
#  define TOLOWER(Ch, L) towlower (Ch)
Packit 8f70b4
# endif
Packit 8f70b4
#else
Packit 8f70b4
# ifdef USE_IN_EXTENDED_LOCALE_MODEL
Packit 8f70b4
#  define TOUPPER(Ch, L) __toupper_l (Ch, L)
Packit 8f70b4
#  define TOLOWER(Ch, L) __tolower_l (Ch, L)
Packit 8f70b4
# else
Packit 8f70b4
#  define TOUPPER(Ch, L) toupper (Ch)
Packit 8f70b4
#  define TOLOWER(Ch, L) tolower (Ch)
Packit 8f70b4
# endif
Packit 8f70b4
#endif
Packit 8f70b4
/* We don't use 'isdigit' here since the locale dependent
Packit 8f70b4
   interpretation is not what we want here.  We only need to accept
Packit 8f70b4
   the arabic digits in the ASCII range.  One day there is perhaps a
Packit 8f70b4
   more reliable way to accept other sets of digits.  */
Packit 8f70b4
#define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
Packit 8f70b4
Packit 8f70b4
#if FPRINTFTIME
Packit 8f70b4
static void
Packit 8f70b4
fwrite_lowcase (FILE *fp, const CHAR_T *src, size_t len)
Packit 8f70b4
{
Packit 8f70b4
  while (len-- > 0)
Packit 8f70b4
    {
Packit 8f70b4
      fputc (TOLOWER ((UCHAR_T) *src, loc), fp);
Packit 8f70b4
      ++src;
Packit 8f70b4
    }
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
static void
Packit 8f70b4
fwrite_uppcase (FILE *fp, const CHAR_T *src, size_t len)
Packit 8f70b4
{
Packit 8f70b4
  while (len-- > 0)
Packit 8f70b4
    {
Packit 8f70b4
      fputc (TOUPPER ((UCHAR_T) *src, loc), fp);
Packit 8f70b4
      ++src;
Packit 8f70b4
    }
Packit 8f70b4
}
Packit 8f70b4
#else
Packit 8f70b4
static CHAR_T *memcpy_lowcase (CHAR_T *dest, const CHAR_T *src,
Packit 8f70b4
                               size_t len LOCALE_PARAM);
Packit 8f70b4
Packit 8f70b4
static CHAR_T *
Packit 8f70b4
memcpy_lowcase (CHAR_T *dest, const CHAR_T *src, size_t len LOCALE_PARAM)
Packit 8f70b4
{
Packit 8f70b4
  while (len-- > 0)
Packit 8f70b4
    dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
Packit 8f70b4
  return dest;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
static CHAR_T *memcpy_uppcase (CHAR_T *dest, const CHAR_T *src,
Packit 8f70b4
                               size_t len LOCALE_PARAM);
Packit 8f70b4
Packit 8f70b4
static CHAR_T *
Packit 8f70b4
memcpy_uppcase (CHAR_T *dest, const CHAR_T *src, size_t len LOCALE_PARAM)
Packit 8f70b4
{
Packit 8f70b4
  while (len-- > 0)
Packit 8f70b4
    dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
Packit 8f70b4
  return dest;
Packit 8f70b4
}
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
#if ! HAVE_TM_GMTOFF
Packit 8f70b4
/* Yield the difference between *A and *B,
Packit 8f70b4
   measured in seconds, ignoring leap seconds.  */
Packit 8f70b4
# define tm_diff ftime_tm_diff
Packit 8f70b4
static int tm_diff (const struct tm *, const struct tm *);
Packit 8f70b4
static int
Packit 8f70b4
tm_diff (const struct tm *a, const struct tm *b)
Packit 8f70b4
{
Packit 8f70b4
  /* Compute intervening leap days correctly even if year is negative.
Packit 8f70b4
     Take care to avoid int overflow in leap day calculations,
Packit 8f70b4
     but it's OK to assume that A and B are close to each other.  */
Packit 8f70b4
  int a4 = SHR (a->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (a->tm_year & 3);
Packit 8f70b4
  int b4 = SHR (b->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (b->tm_year & 3);
Packit 8f70b4
  int a100 = a4 / 25 - (a4 % 25 < 0);
Packit 8f70b4
  int b100 = b4 / 25 - (b4 % 25 < 0);
Packit 8f70b4
  int a400 = SHR (a100, 2);
Packit 8f70b4
  int b400 = SHR (b100, 2);
Packit 8f70b4
  int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
Packit 8f70b4
  int years = a->tm_year - b->tm_year;
Packit 8f70b4
  int days = (365 * years + intervening_leap_days
Packit 8f70b4
              + (a->tm_yday - b->tm_yday));
Packit 8f70b4
  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
Packit 8f70b4
                + (a->tm_min - b->tm_min))
Packit 8f70b4
          + (a->tm_sec - b->tm_sec));
Packit 8f70b4
}
Packit 8f70b4
#endif /* ! HAVE_TM_GMTOFF */
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
/* The number of days from the first day of the first ISO week of this
Packit 8f70b4
   year to the year day YDAY with week day WDAY.  ISO weeks start on
Packit 8f70b4
   Monday; the first ISO week has the year's first Thursday.  YDAY may
Packit 8f70b4
   be as small as YDAY_MINIMUM.  */
Packit 8f70b4
#define ISO_WEEK_START_WDAY 1 /* Monday */
Packit 8f70b4
#define ISO_WEEK1_WDAY 4 /* Thursday */
Packit 8f70b4
#define YDAY_MINIMUM (-366)
Packit 8f70b4
static int iso_week_days (int, int);
Packit 8f70b4
#ifdef __GNUC__
Packit 8f70b4
__inline__
Packit 8f70b4
#endif
Packit 8f70b4
static int
Packit 8f70b4
iso_week_days (int yday, int wday)
Packit 8f70b4
{
Packit 8f70b4
  /* Add enough to the first operand of % to make it nonnegative.  */
Packit 8f70b4
  int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
Packit 8f70b4
  return (yday
Packit 8f70b4
          - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
Packit 8f70b4
          + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Packit 8f70b4
/* When compiling this file, GNU applications can #define my_strftime
Packit 8f70b4
   to a symbol (typically nstrftime) to get an extended strftime with
Packit 8f70b4
   extra arguments TZ and NS.  */
Packit 8f70b4
Packit 8f70b4
#if FPRINTFTIME
Packit 8f70b4
# undef my_strftime
Packit 8f70b4
# define my_strftime fprintftime
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#ifdef my_strftime
Packit 8f70b4
# undef HAVE_TZSET
Packit 8f70b4
# define extra_args , tz, ns
Packit 8f70b4
# define extra_args_spec , timezone_t tz, int ns
Packit 8f70b4
#else
Packit 8f70b4
# if defined COMPILE_WIDE
Packit 8f70b4
#  define my_strftime wcsftime
Packit 8f70b4
#  define nl_get_alt_digit _nl_get_walt_digit
Packit 8f70b4
# else
Packit 8f70b4
#  define my_strftime strftime
Packit 8f70b4
#  define nl_get_alt_digit _nl_get_alt_digit
Packit 8f70b4
# endif
Packit 8f70b4
# define extra_args
Packit 8f70b4
# define extra_args_spec
Packit 8f70b4
/* We don't have this information in general.  */
Packit 8f70b4
# define tz 1
Packit 8f70b4
# define ns 0
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
static size_t __strftime_internal (STREAM_OR_CHAR_T *, STRFTIME_ARG (size_t)
Packit 8f70b4
                                   const CHAR_T *, const struct tm *,
Packit 8f70b4
                                   bool, bool *
Packit 8f70b4
                                   extra_args_spec LOCALE_PARAM);
Packit 8f70b4
Packit 8f70b4
/* Write information from TP into S according to the format
Packit 8f70b4
   string FORMAT, writing no more that MAXSIZE characters
Packit 8f70b4
   (including the terminating '\0') and returning number of
Packit 8f70b4
   characters written.  If S is NULL, nothing will be written
Packit 8f70b4
   anywhere, so to determine how many characters would be
Packit 8f70b4
   written, use NULL for S and (size_t) -1 for MAXSIZE.  */
Packit 8f70b4
size_t
Packit 8f70b4
my_strftime (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
Packit 8f70b4
             const CHAR_T *format,
Packit 8f70b4
             const struct tm *tp extra_args_spec LOCALE_PARAM)
Packit 8f70b4
{
Packit 8f70b4
  bool tzset_called = false;
Packit 8f70b4
  return __strftime_internal (s, STRFTIME_ARG (maxsize) format, tp,
Packit 8f70b4
                              false, &tzset_called extra_args LOCALE_ARG);
Packit 8f70b4
}
Packit 8f70b4
#if defined _LIBC && ! FPRINTFTIME
Packit 8f70b4
libc_hidden_def (my_strftime)
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
/* Just like my_strftime, above, but with two more parameters.
Packit 8f70b4
   UPCASE indicate that the result should be converted to upper case,
Packit 8f70b4
   and *TZSET_CALLED indicates whether tzset has been called here.  */
Packit 8f70b4
static size_t
Packit 8f70b4
__strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
Packit 8f70b4
                     const CHAR_T *format,
Packit 8f70b4
                     const struct tm *tp, bool upcase, bool *tzset_called
Packit 8f70b4
                     extra_args_spec LOCALE_PARAM)
Packit 8f70b4
{
Packit 8f70b4
#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
Packit 8f70b4
  struct __locale_data *const current = loc->__locales[LC_TIME];
Packit 8f70b4
#endif
Packit 8f70b4
#if FPRINTFTIME
Packit 8f70b4
  size_t maxsize = (size_t) -1;
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
  int hour12 = tp->tm_hour;
Packit 8f70b4
#ifdef _NL_CURRENT
Packit 8f70b4
  /* We cannot make the following values variables since we must delay
Packit 8f70b4
     the evaluation of these values until really needed since some
Packit 8f70b4
     expressions might not be valid in every situation.  The 'struct tm'
Packit 8f70b4
     might be generated by a strptime() call that initialized
Packit 8f70b4
     only a few elements.  Dereference the pointers only if the format
Packit 8f70b4
     requires this.  Then it is ok to fail if the pointers are invalid.  */
Packit 8f70b4
# define a_wkday \
Packit 8f70b4
  ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6                      \
Packit 8f70b4
                     ? "?" : _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday)))
Packit 8f70b4
# define f_wkday \
Packit 8f70b4
  ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6                      \
Packit 8f70b4
                     ? "?" : _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday)))
Packit 8f70b4
# define a_month \
Packit 8f70b4
  ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11                       \
Packit 8f70b4
                     ? "?" : _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon)))
Packit 8f70b4
# define f_month \
Packit 8f70b4
  ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11                       \
Packit 8f70b4
                     ? "?" : _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon)))
Packit 8f70b4
# define a_altmonth \
Packit 8f70b4
  ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11                       \
Packit 8f70b4
                     ? "?" : _NL_CURRENT (LC_TIME, NLW(ABALTMON_1) + tp->tm_mon)))
Packit 8f70b4
# define f_altmonth \
Packit 8f70b4
  ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11                       \
Packit 8f70b4
                     ? "?" : _NL_CURRENT (LC_TIME, NLW(ALTMON_1) + tp->tm_mon)))
Packit 8f70b4
# define ampm \
Packit 8f70b4
  ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11                    \
Packit 8f70b4
                                 ? NLW(PM_STR) : NLW(AM_STR)))
Packit 8f70b4
Packit 8f70b4
# define aw_len STRLEN (a_wkday)
Packit 8f70b4
# define am_len STRLEN (a_month)
Packit 8f70b4
# define aam_len STRLEN (a_altmonth)
Packit 8f70b4
# define ap_len STRLEN (ampm)
Packit 8f70b4
#endif
Packit 8f70b4
#if HAVE_TZNAME
Packit 8f70b4
  char **tzname_vec = tzname;
Packit 8f70b4
#endif
Packit 8f70b4
  const char *zone;
Packit 8f70b4
  size_t i = 0;
Packit 8f70b4
  STREAM_OR_CHAR_T *p = s;
Packit 8f70b4
  const CHAR_T *f;
Packit 8f70b4
#if DO_MULTIBYTE && !defined COMPILE_WIDE
Packit 8f70b4
  const char *format_end = NULL;
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
#if ! defined _LIBC && ! HAVE_RUN_TZSET_TEST
Packit 8f70b4
  /* Solaris 2.5.x and 2.6 tzset sometimes modify the storage returned
Packit 8f70b4
     by localtime.  On such systems, we must either use the tzset and
Packit 8f70b4
     localtime wrappers to work around the bug (which sets
Packit 8f70b4
     HAVE_RUN_TZSET_TEST) or make a copy of the structure.  */
Packit 8f70b4
  struct tm copy = *tp;
Packit 8f70b4
  tp = ©
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
  zone = NULL;
Packit 8f70b4
#if HAVE_TM_ZONE
Packit 8f70b4
  /* The POSIX test suite assumes that setting
Packit 8f70b4
     the environment variable TZ to a new value before calling strftime()
Packit 8f70b4
     will influence the result (the %Z format) even if the information in
Packit 8f70b4
     TP is computed with a totally different time zone.
Packit 8f70b4
     This is bogus: though POSIX allows bad behavior like this,
Packit 8f70b4
     POSIX does not require it.  Do the right thing instead.  */
Packit 8f70b4
  zone = (const char *) tp->tm_zone;
Packit 8f70b4
#endif
Packit 8f70b4
#if HAVE_TZNAME
Packit 8f70b4
  if (!tz)
Packit 8f70b4
    {
Packit 8f70b4
      if (! (zone && *zone))
Packit 8f70b4
        zone = "GMT";
Packit 8f70b4
    }
Packit 8f70b4
  else
Packit 8f70b4
    {
Packit 8f70b4
# if !HAVE_TM_ZONE
Packit 8f70b4
      /* Infer the zone name from *TZ instead of from TZNAME.  */
Packit 8f70b4
      tzname_vec = tz->tzname_copy;
Packit 8f70b4
# endif
Packit 8f70b4
    }
Packit 8f70b4
  /* The tzset() call might have changed the value.  */
Packit 8f70b4
  if (!(zone && *zone) && tp->tm_isdst >= 0)
Packit 8f70b4
    {
Packit 8f70b4
      /* POSIX.1 requires that local time zone information be used as
Packit 8f70b4
         though strftime called tzset.  */
Packit 8f70b4
# if HAVE_TZSET
Packit 8f70b4
      if (!*tzset_called)
Packit 8f70b4
        {
Packit 8f70b4
          tzset ();
Packit 8f70b4
          *tzset_called = true;
Packit 8f70b4
        }
Packit 8f70b4
# endif
Packit 8f70b4
      zone = tzname_vec[tp->tm_isdst != 0];
Packit 8f70b4
    }
Packit 8f70b4
#endif
Packit 8f70b4
  if (! zone)
Packit 8f70b4
    zone = "";
Packit 8f70b4
Packit 8f70b4
  if (hour12 > 12)
Packit 8f70b4
    hour12 -= 12;
Packit 8f70b4
  else
Packit 8f70b4
    if (hour12 == 0)
Packit 8f70b4
      hour12 = 12;
Packit 8f70b4
Packit 8f70b4
  for (f = format; *f != '\0'; ++f)
Packit 8f70b4
    {
Packit 8f70b4
      int pad = 0;              /* Padding for number ('-', '_', or 0).  */
Packit 8f70b4
      int modifier;             /* Field modifier ('E', 'O', or 0).  */
Packit 8f70b4
      int digits = 0;           /* Max digits for numeric format.  */
Packit 8f70b4
      int number_value;         /* Numeric value to be printed.  */
Packit 8f70b4
      unsigned int u_number_value; /* (unsigned int) number_value.  */
Packit 8f70b4
      bool negative_number;     /* The number is negative.  */
Packit 8f70b4
      bool always_output_a_sign; /* +/- should always be output.  */
Packit 8f70b4
      int tz_colon_mask;        /* Bitmask of where ':' should appear.  */
Packit 8f70b4
      const CHAR_T *subfmt;
Packit 8f70b4
      CHAR_T sign_char;
Packit 8f70b4
      CHAR_T *bufp;
Packit 8f70b4
      CHAR_T buf[1
Packit 8f70b4
                 + 2 /* for the two colons in a %::z or %:::z time zone */
Packit 8f70b4
                 + (sizeof (int) < sizeof (time_t)
Packit 8f70b4
                    ? INT_STRLEN_BOUND (time_t)
Packit 8f70b4
                    : INT_STRLEN_BOUND (int))];
Packit 8f70b4
      int width = -1;
Packit 8f70b4
      bool to_lowcase = false;
Packit 8f70b4
      bool to_uppcase = upcase;
Packit 8f70b4
      size_t colons;
Packit 8f70b4
      bool change_case = false;
Packit 8f70b4
      int format_char;
Packit 8f70b4
Packit 8f70b4
#if DO_MULTIBYTE && !defined COMPILE_WIDE
Packit 8f70b4
      switch (*f)
Packit 8f70b4
        {
Packit 8f70b4
        case L_('%'):
Packit 8f70b4
          break;
Packit 8f70b4
Packit 8f70b4
        case L_('\b'): case L_('\t'): case L_('\n'):
Packit 8f70b4
        case L_('\v'): case L_('\f'): case L_('\r'):
Packit 8f70b4
        case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
Packit 8f70b4
        case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
Packit 8f70b4
        case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
Packit 8f70b4
        case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
Packit 8f70b4
        case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
Packit 8f70b4
        case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
Packit 8f70b4
        case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
Packit 8f70b4
        case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
Packit 8f70b4
        case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
Packit 8f70b4
        case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
Packit 8f70b4
        case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
Packit 8f70b4
        case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
Packit 8f70b4
        case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
Packit 8f70b4
        case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
Packit 8f70b4
        case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
Packit 8f70b4
        case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
Packit 8f70b4
        case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
Packit 8f70b4
        case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
Packit 8f70b4
        case L_('~'):
Packit 8f70b4
          /* The C Standard requires these 98 characters (plus '%') to
Packit 8f70b4
             be in the basic execution character set.  None of these
Packit 8f70b4
             characters can start a multibyte sequence, so they need
Packit 8f70b4
             not be analyzed further.  */
Packit 8f70b4
          add1 (*f);
Packit 8f70b4
          continue;
Packit 8f70b4
Packit 8f70b4
        default:
Packit 8f70b4
          /* Copy this multibyte sequence until we reach its end, find
Packit 8f70b4
             an error, or come back to the initial shift state.  */
Packit 8f70b4
          {
Packit 8f70b4
            mbstate_t mbstate = mbstate_zero;
Packit 8f70b4
            size_t len = 0;
Packit 8f70b4
            size_t fsize;
Packit 8f70b4
Packit 8f70b4
            if (! format_end)
Packit 8f70b4
              format_end = f + strlen (f) + 1;
Packit 8f70b4
            fsize = format_end - f;
Packit 8f70b4
Packit 8f70b4
            do
Packit 8f70b4
              {
Packit 8f70b4
                size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
Packit 8f70b4
Packit 8f70b4
                if (bytes == 0)
Packit 8f70b4
                  break;
Packit 8f70b4
Packit 8f70b4
                if (bytes == (size_t) -2)
Packit 8f70b4
                  {
Packit 8f70b4
                    len += strlen (f + len);
Packit 8f70b4
                    break;
Packit 8f70b4
                  }
Packit 8f70b4
Packit 8f70b4
                if (bytes == (size_t) -1)
Packit 8f70b4
                  {
Packit 8f70b4
                    len++;
Packit 8f70b4
                    break;
Packit 8f70b4
                  }
Packit 8f70b4
Packit 8f70b4
                len += bytes;
Packit 8f70b4
              }
Packit 8f70b4
            while (! mbsinit (&mbstate));
Packit 8f70b4
Packit 8f70b4
            cpy (len, f);
Packit 8f70b4
            f += len - 1;
Packit 8f70b4
            continue;
Packit 8f70b4
          }
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
#else /* ! DO_MULTIBYTE */
Packit 8f70b4
Packit 8f70b4
      /* Either multibyte encodings are not supported, they are
Packit 8f70b4
         safe for formats, so any non-'%' byte can be copied through,
Packit 8f70b4
         or this is the wide character version.  */
Packit 8f70b4
      if (*f != L_('%'))
Packit 8f70b4
        {
Packit 8f70b4
          add1 (*f);
Packit 8f70b4
          continue;
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
#endif /* ! DO_MULTIBYTE */
Packit 8f70b4
Packit 8f70b4
      /* Check for flags that can modify a format.  */
Packit 8f70b4
      while (1)
Packit 8f70b4
        {
Packit 8f70b4
          switch (*++f)
Packit 8f70b4
            {
Packit 8f70b4
              /* This influences the number formats.  */
Packit 8f70b4
            case L_('_'):
Packit 8f70b4
            case L_('-'):
Packit 8f70b4
            case L_('0'):
Packit 8f70b4
              pad = *f;
Packit 8f70b4
              continue;
Packit 8f70b4
Packit 8f70b4
              /* This changes textual output.  */
Packit 8f70b4
            case L_('^'):
Packit 8f70b4
              to_uppcase = true;
Packit 8f70b4
              continue;
Packit 8f70b4
            case L_('#'):
Packit 8f70b4
              change_case = true;
Packit 8f70b4
              continue;
Packit 8f70b4
Packit 8f70b4
            default:
Packit 8f70b4
              break;
Packit 8f70b4
            }
Packit 8f70b4
          break;
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      /* As a GNU extension we allow the field width to be specified.  */
Packit 8f70b4
      if (ISDIGIT (*f))
Packit 8f70b4
        {
Packit 8f70b4
          width = 0;
Packit 8f70b4
          do
Packit 8f70b4
            {
Packit 8f70b4
              if (width > INT_MAX / 10
Packit 8f70b4
                  || (width == INT_MAX / 10 && *f - L_('0') > INT_MAX % 10))
Packit 8f70b4
                /* Avoid overflow.  */
Packit 8f70b4
                width = INT_MAX;
Packit 8f70b4
              else
Packit 8f70b4
                {
Packit 8f70b4
                  width *= 10;
Packit 8f70b4
                  width += *f - L_('0');
Packit 8f70b4
                }
Packit 8f70b4
              ++f;
Packit 8f70b4
            }
Packit 8f70b4
          while (ISDIGIT (*f));
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      /* Check for modifiers.  */
Packit 8f70b4
      switch (*f)
Packit 8f70b4
        {
Packit 8f70b4
        case L_('E'):
Packit 8f70b4
        case L_('O'):
Packit 8f70b4
          modifier = *f++;
Packit 8f70b4
          break;
Packit 8f70b4
Packit 8f70b4
        default:
Packit 8f70b4
          modifier = 0;
Packit 8f70b4
          break;
Packit 8f70b4
        }
Packit 8f70b4
Packit 8f70b4
      /* Now do the specified format.  */
Packit 8f70b4
      format_char = *f;
Packit 8f70b4
      switch (format_char)
Packit 8f70b4
        {
Packit 8f70b4
#define DO_NUMBER(d, v) \
Packit 8f70b4
          do                                                                  \
Packit 8f70b4
            {                                                                 \
Packit 8f70b4
              digits = d;                                                     \
Packit 8f70b4
              number_value = v;                                               \
Packit 8f70b4
              goto do_number;                                                 \
Packit 8f70b4
            }                                                                 \
Packit 8f70b4
          while (0)
Packit 8f70b4
#define DO_SIGNED_NUMBER(d, negative, v) \
Packit 8f70b4
          do                                                                  \
Packit 8f70b4
            {                                                                 \
Packit 8f70b4
              digits = d;                                                     \
Packit 8f70b4
              negative_number = negative;                                     \
Packit 8f70b4
              u_number_value = v;                                             \
Packit 8f70b4
              goto do_signed_number;                                          \
Packit 8f70b4
            }                                                                 \
Packit 8f70b4
          while (0)
Packit 8f70b4
Packit 8f70b4
          /* The mask is not what you might think.
Packit 8f70b4
             When the ordinal i'th bit is set, insert a colon
Packit 8f70b4
             before the i'th digit of the time zone representation.  */
Packit 8f70b4
#define DO_TZ_OFFSET(d, mask, v) \
Packit 8f70b4
          do                                                                  \
Packit 8f70b4
            {                                                                 \
Packit 8f70b4
              digits = d;                                                     \
Packit 8f70b4
              tz_colon_mask = mask;                                           \
Packit 8f70b4
              u_number_value = v;                                             \
Packit 8f70b4
              goto do_tz_offset;                                              \
Packit 8f70b4
            }                                                                 \
Packit 8f70b4
          while (0)
Packit 8f70b4
#define DO_NUMBER_SPACEPAD(d, v) \
Packit 8f70b4
          do                                                                  \
Packit 8f70b4
            {                                                                 \
Packit 8f70b4
              digits = d;                                                     \
Packit 8f70b4
              number_value = v;                                               \
Packit 8f70b4
              goto do_number_spacepad;                                        \
Packit 8f70b4
            }                                                                 \
Packit 8f70b4
          while (0)
Packit 8f70b4
Packit 8f70b4
        case L_('%'):
Packit 8f70b4
          if (modifier != 0)
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
          add1 (*f);
Packit 8f70b4
          break;
Packit 8f70b4
Packit 8f70b4
        case L_('a'):
Packit 8f70b4
          if (modifier != 0)
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
          if (change_case)
Packit 8f70b4
            {
Packit 8f70b4
              to_uppcase = true;
Packit 8f70b4
              to_lowcase = false;
Packit 8f70b4
            }
Packit 8f70b4
#ifdef _NL_CURRENT
Packit 8f70b4
          cpy (aw_len, a_wkday);
Packit 8f70b4
          break;
Packit 8f70b4
#else
Packit 8f70b4
          goto underlying_strftime;
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
        case 'A':
Packit 8f70b4
          if (modifier != 0)
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
          if (change_case)
Packit 8f70b4
            {
Packit 8f70b4
              to_uppcase = true;
Packit 8f70b4
              to_lowcase = false;
Packit 8f70b4
            }
Packit 8f70b4
#ifdef _NL_CURRENT
Packit 8f70b4
          cpy (STRLEN (f_wkday), f_wkday);
Packit 8f70b4
          break;
Packit 8f70b4
#else
Packit 8f70b4
          goto underlying_strftime;
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
        case L_('b'):
Packit 8f70b4
        case L_('h'):
Packit 8f70b4
          if (change_case)
Packit 8f70b4
            {
Packit 8f70b4
              to_uppcase = true;
Packit 8f70b4
              to_lowcase = false;
Packit 8f70b4
            }
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
#ifdef _NL_CURRENT
Packit 8f70b4
          if (modifier == L_('O'))
Packit 8f70b4
            cpy (aam_len, a_altmonth);
Packit 8f70b4
          else
Packit 8f70b4
            cpy (am_len, a_month);
Packit 8f70b4
          break;
Packit 8f70b4
#else
Packit 8f70b4
          goto underlying_strftime;
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
        case L_('B'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
          if (change_case)
Packit 8f70b4
            {
Packit 8f70b4
              to_uppcase = true;
Packit 8f70b4
              to_lowcase = false;
Packit 8f70b4
            }
Packit 8f70b4
#ifdef _NL_CURRENT
Packit 8f70b4
          if (modifier == L_('O'))
Packit 8f70b4
            cpy (STRLEN (f_altmonth), f_altmonth);
Packit 8f70b4
          else
Packit 8f70b4
            cpy (STRLEN (f_month), f_month);
Packit 8f70b4
          break;
Packit 8f70b4
#else
Packit 8f70b4
          goto underlying_strftime;
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
        case L_('c'):
Packit 8f70b4
          if (modifier == L_('O'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
#ifdef _NL_CURRENT
Packit 8f70b4
          if (! (modifier == 'E'
Packit 8f70b4
                 && (*(subfmt =
Packit 8f70b4
                       (const CHAR_T *) _NL_CURRENT (LC_TIME,
Packit 8f70b4
                                                     NLW(ERA_D_T_FMT)))
Packit 8f70b4
                     != '\0')))
Packit 8f70b4
            subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
Packit 8f70b4
#else
Packit 8f70b4
          goto underlying_strftime;
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
        subformat:
Packit 8f70b4
          {
Packit 8f70b4
            size_t len = __strftime_internal (NULL, STRFTIME_ARG ((size_t) -1)
Packit 8f70b4
                                              subfmt,
Packit 8f70b4
                                              tp, to_uppcase, tzset_called
Packit 8f70b4
                                              extra_args LOCALE_ARG);
Packit 8f70b4
            add (len, __strftime_internal (p,
Packit 8f70b4
                                           STRFTIME_ARG (maxsize - i)
Packit 8f70b4
                                           subfmt,
Packit 8f70b4
                                           tp, to_uppcase, tzset_called
Packit 8f70b4
                                           extra_args LOCALE_ARG));
Packit 8f70b4
          }
Packit 8f70b4
          break;
Packit 8f70b4
Packit 8f70b4
#if !(defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
Packit 8f70b4
        underlying_strftime:
Packit 8f70b4
          {
Packit 8f70b4
            /* The relevant information is available only via the
Packit 8f70b4
               underlying strftime implementation, so use that.  */
Packit 8f70b4
            char ufmt[5];
Packit 8f70b4
            char *u = ufmt;
Packit 8f70b4
            char ubuf[1024]; /* enough for any single format in practice */
Packit 8f70b4
            size_t len;
Packit 8f70b4
            /* Make sure we're calling the actual underlying strftime.
Packit 8f70b4
               In some cases, config.h contains something like
Packit 8f70b4
               "#define strftime rpl_strftime".  */
Packit 8f70b4
# ifdef strftime
Packit 8f70b4
#  undef strftime
Packit 8f70b4
            size_t strftime ();
Packit 8f70b4
# endif
Packit 8f70b4
Packit 8f70b4
            /* The space helps distinguish strftime failure from empty
Packit 8f70b4
               output.  */
Packit 8f70b4
            *u++ = ' ';
Packit 8f70b4
            *u++ = '%';
Packit 8f70b4
            if (modifier != 0)
Packit 8f70b4
              *u++ = modifier;
Packit 8f70b4
            *u++ = format_char;
Packit 8f70b4
            *u = '\0';
Packit 8f70b4
            len = strftime (ubuf, sizeof ubuf, ufmt, tp);
Packit 8f70b4
            if (len != 0)
Packit 8f70b4
              cpy (len - 1, ubuf + 1);
Packit 8f70b4
          }
Packit 8f70b4
          break;
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
        case L_('C'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            {
Packit 8f70b4
#if HAVE_STRUCT_ERA_ENTRY
Packit 8f70b4
              struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
Packit 8f70b4
              if (era)
Packit 8f70b4
                {
Packit 8f70b4
# ifdef COMPILE_WIDE
Packit 8f70b4
                  size_t len = __wcslen (era->era_wname);
Packit 8f70b4
                  cpy (len, era->era_wname);
Packit 8f70b4
# else
Packit 8f70b4
                  size_t len = strlen (era->era_name);
Packit 8f70b4
                  cpy (len, era->era_name);
Packit 8f70b4
# endif
Packit 8f70b4
                  break;
Packit 8f70b4
                }
Packit 8f70b4
#else
Packit 8f70b4
              goto underlying_strftime;
Packit 8f70b4
#endif
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          {
Packit 8f70b4
            int century = tp->tm_year / 100 + TM_YEAR_BASE / 100;
Packit 8f70b4
            century -= tp->tm_year % 100 < 0 && 0 < century;
Packit 8f70b4
            DO_SIGNED_NUMBER (2, tp->tm_year < - TM_YEAR_BASE, century);
Packit 8f70b4
          }
Packit 8f70b4
Packit 8f70b4
        case L_('x'):
Packit 8f70b4
          if (modifier == L_('O'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
#ifdef _NL_CURRENT
Packit 8f70b4
          if (! (modifier == L_('E')
Packit 8f70b4
                 && (*(subfmt =
Packit 8f70b4
                       (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
Packit 8f70b4
                     != L_('\0'))))
Packit 8f70b4
            subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
Packit 8f70b4
          goto subformat;
Packit 8f70b4
#else
Packit 8f70b4
          goto underlying_strftime;
Packit 8f70b4
#endif
Packit 8f70b4
        case L_('D'):
Packit 8f70b4
          if (modifier != 0)
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
          subfmt = L_("%m/%d/%y");
Packit 8f70b4
          goto subformat;
Packit 8f70b4
Packit 8f70b4
        case L_('d'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          DO_NUMBER (2, tp->tm_mday);
Packit 8f70b4
Packit 8f70b4
        case L_('e'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          DO_NUMBER_SPACEPAD (2, tp->tm_mday);
Packit 8f70b4
Packit 8f70b4
          /* All numeric formats set DIGITS and NUMBER_VALUE (or U_NUMBER_VALUE)
Packit 8f70b4
             and then jump to one of these labels.  */
Packit 8f70b4
Packit 8f70b4
        do_tz_offset:
Packit 8f70b4
          always_output_a_sign = true;
Packit 8f70b4
          goto do_number_body;
Packit 8f70b4
Packit 8f70b4
        do_number_spacepad:
Packit 8f70b4
          /* Force '_' flag unless overridden by '0' or '-' flag.  */
Packit 8f70b4
          if (pad != L_('0') && pad != L_('-'))
Packit 8f70b4
            pad = L_('_');
Packit 8f70b4
Packit 8f70b4
        do_number:
Packit 8f70b4
          /* Format NUMBER_VALUE according to the MODIFIER flag.  */
Packit 8f70b4
          negative_number = number_value < 0;
Packit 8f70b4
          u_number_value = number_value;
Packit 8f70b4
Packit 8f70b4
        do_signed_number:
Packit 8f70b4
          always_output_a_sign = false;
Packit 8f70b4
          tz_colon_mask = 0;
Packit 8f70b4
Packit 8f70b4
        do_number_body:
Packit 8f70b4
          /* Format U_NUMBER_VALUE according to the MODIFIER flag.
Packit 8f70b4
             NEGATIVE_NUMBER is nonzero if the original number was
Packit 8f70b4
             negative; in this case it was converted directly to
Packit 8f70b4
             unsigned int (i.e., modulo (UINT_MAX + 1)) without
Packit 8f70b4
             negating it.  */
Packit 8f70b4
          if (modifier == L_('O') && !negative_number)
Packit 8f70b4
            {
Packit 8f70b4
#ifdef _NL_CURRENT
Packit 8f70b4
              /* Get the locale specific alternate representation of
Packit 8f70b4
                 the number.  If none exist NULL is returned.  */
Packit 8f70b4
              const CHAR_T *cp = nl_get_alt_digit (u_number_value
Packit 8f70b4
                                                   HELPER_LOCALE_ARG);
Packit 8f70b4
Packit 8f70b4
              if (cp != NULL)
Packit 8f70b4
                {
Packit 8f70b4
                  size_t digitlen = STRLEN (cp);
Packit 8f70b4
                  if (digitlen != 0)
Packit 8f70b4
                    {
Packit 8f70b4
                      cpy (digitlen, cp);
Packit 8f70b4
                      break;
Packit 8f70b4
                    }
Packit 8f70b4
                }
Packit 8f70b4
#else
Packit 8f70b4
              goto underlying_strftime;
Packit 8f70b4
#endif
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          bufp = buf + sizeof (buf) / sizeof (buf[0]);
Packit 8f70b4
Packit 8f70b4
          if (negative_number)
Packit 8f70b4
            u_number_value = - u_number_value;
Packit 8f70b4
Packit 8f70b4
          do
Packit 8f70b4
            {
Packit 8f70b4
              if (tz_colon_mask & 1)
Packit 8f70b4
                *--bufp = ':';
Packit 8f70b4
              tz_colon_mask >>= 1;
Packit 8f70b4
              *--bufp = u_number_value % 10 + L_('0');
Packit 8f70b4
              u_number_value /= 10;
Packit 8f70b4
            }
Packit 8f70b4
          while (u_number_value != 0 || tz_colon_mask != 0);
Packit 8f70b4
Packit 8f70b4
        do_number_sign_and_padding:
Packit 8f70b4
          if (digits < width)
Packit 8f70b4
            digits = width;
Packit 8f70b4
Packit 8f70b4
          sign_char = (negative_number ? L_('-')
Packit 8f70b4
                       : always_output_a_sign ? L_('+')
Packit 8f70b4
                       : 0);
Packit 8f70b4
Packit 8f70b4
          if (pad == L_('-'))
Packit 8f70b4
            {
Packit 8f70b4
              if (sign_char)
Packit 8f70b4
                add1 (sign_char);
Packit 8f70b4
            }
Packit 8f70b4
          else
Packit 8f70b4
            {
Packit 8f70b4
              int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
Packit 8f70b4
                                      - bufp) - !!sign_char;
Packit 8f70b4
Packit 8f70b4
              if (padding > 0)
Packit 8f70b4
                {
Packit 8f70b4
                  if (pad == L_('_'))
Packit 8f70b4
                    {
Packit 8f70b4
                      if ((size_t) padding >= maxsize - i)
Packit 8f70b4
                        return 0;
Packit 8f70b4
Packit 8f70b4
                      if (p)
Packit 8f70b4
                        memset_space (p, padding);
Packit 8f70b4
                      i += padding;
Packit 8f70b4
                      width = width > padding ? width - padding : 0;
Packit 8f70b4
                      if (sign_char)
Packit 8f70b4
                        add1 (sign_char);
Packit 8f70b4
                    }
Packit 8f70b4
                  else
Packit 8f70b4
                    {
Packit 8f70b4
                      if ((size_t) digits >= maxsize - i)
Packit 8f70b4
                        return 0;
Packit 8f70b4
Packit 8f70b4
                      if (sign_char)
Packit 8f70b4
                        add1 (sign_char);
Packit 8f70b4
Packit 8f70b4
                      if (p)
Packit 8f70b4
                        memset_zero (p, padding);
Packit 8f70b4
                      i += padding;
Packit 8f70b4
                      width = 0;
Packit 8f70b4
                    }
Packit 8f70b4
                }
Packit 8f70b4
              else
Packit 8f70b4
                {
Packit 8f70b4
                  if (sign_char)
Packit 8f70b4
                    add1 (sign_char);
Packit 8f70b4
                }
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);
Packit 8f70b4
          break;
Packit 8f70b4
Packit 8f70b4
        case L_('F'):
Packit 8f70b4
          if (modifier != 0)
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
          subfmt = L_("%Y-%m-%d");
Packit 8f70b4
          goto subformat;
Packit 8f70b4
Packit 8f70b4
        case L_('H'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          DO_NUMBER (2, tp->tm_hour);
Packit 8f70b4
Packit 8f70b4
        case L_('I'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          DO_NUMBER (2, hour12);
Packit 8f70b4
Packit 8f70b4
        case L_('k'):           /* GNU extension.  */
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          DO_NUMBER_SPACEPAD (2, tp->tm_hour);
Packit 8f70b4
Packit 8f70b4
        case L_('l'):           /* GNU extension.  */
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          DO_NUMBER_SPACEPAD (2, hour12);
Packit 8f70b4
Packit 8f70b4
        case L_('j'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          DO_SIGNED_NUMBER (3, tp->tm_yday < -1, tp->tm_yday + 1U);
Packit 8f70b4
Packit 8f70b4
        case L_('M'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          DO_NUMBER (2, tp->tm_min);
Packit 8f70b4
Packit 8f70b4
        case L_('m'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          DO_SIGNED_NUMBER (2, tp->tm_mon < -1, tp->tm_mon + 1U);
Packit 8f70b4
Packit 8f70b4
#ifndef _LIBC
Packit 8f70b4
        case L_('N'):           /* GNU extension.  */
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          number_value = ns;
Packit 8f70b4
          if (width == -1)
Packit 8f70b4
            width = 9;
Packit 8f70b4
          else
Packit 8f70b4
            {
Packit 8f70b4
              /* Take an explicit width less than 9 as a precision.  */
Packit 8f70b4
              int j;
Packit 8f70b4
              for (j = width; j < 9; j++)
Packit 8f70b4
                number_value /= 10;
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          DO_NUMBER (width, number_value);
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
        case L_('n'):
Packit 8f70b4
          add1 (L_('\n'));
Packit 8f70b4
          break;
Packit 8f70b4
Packit 8f70b4
        case L_('P'):
Packit 8f70b4
          to_lowcase = true;
Packit 8f70b4
#ifndef _NL_CURRENT
Packit 8f70b4
          format_char = L_('p');
Packit 8f70b4
#endif
Packit 8f70b4
          FALLTHROUGH;
Packit 8f70b4
        case L_('p'):
Packit 8f70b4
          if (change_case)
Packit 8f70b4
            {
Packit 8f70b4
              to_uppcase = false;
Packit 8f70b4
              to_lowcase = true;
Packit 8f70b4
            }
Packit 8f70b4
#ifdef _NL_CURRENT
Packit 8f70b4
          cpy (ap_len, ampm);
Packit 8f70b4
          break;
Packit 8f70b4
#else
Packit 8f70b4
          goto underlying_strftime;
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
        case L_('q'):           /* GNU extension.  */
Packit 8f70b4
          DO_SIGNED_NUMBER (1, false, ((tp->tm_mon * 11) >> 5) + 1);
Packit 8f70b4
          break;
Packit 8f70b4
Packit 8f70b4
        case L_('R'):
Packit 8f70b4
          subfmt = L_("%H:%M");
Packit 8f70b4
          goto subformat;
Packit 8f70b4
Packit 8f70b4
        case L_('r'):
Packit 8f70b4
#ifdef _NL_CURRENT
Packit 8f70b4
          if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
Packit 8f70b4
                                                       NLW(T_FMT_AMPM)))
Packit 8f70b4
              == L_('\0'))
Packit 8f70b4
            subfmt = L_("%I:%M:%S %p");
Packit 8f70b4
          goto subformat;
Packit 8f70b4
#else
Packit 8f70b4
          goto underlying_strftime;
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
        case L_('S'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          DO_NUMBER (2, tp->tm_sec);
Packit 8f70b4
Packit 8f70b4
        case L_('s'):           /* GNU extension.  */
Packit 8f70b4
          {
Packit 8f70b4
            struct tm ltm;
Packit 8f70b4
            time_t t;
Packit 8f70b4
Packit 8f70b4
            ltm = *tp;
Packit 8f70b4
            t = mktime_z (tz, <m;;
Packit 8f70b4
Packit 8f70b4
            /* Generate string value for T using time_t arithmetic;
Packit 8f70b4
               this works even if sizeof (long) < sizeof (time_t).  */
Packit 8f70b4
Packit 8f70b4
            bufp = buf + sizeof (buf) / sizeof (buf[0]);
Packit 8f70b4
            negative_number = t < 0;
Packit 8f70b4
Packit 8f70b4
            do
Packit 8f70b4
              {
Packit 8f70b4
                int d = t % 10;
Packit 8f70b4
                t /= 10;
Packit 8f70b4
                *--bufp = (negative_number ? -d : d) + L_('0');
Packit 8f70b4
              }
Packit 8f70b4
            while (t != 0);
Packit 8f70b4
Packit 8f70b4
            digits = 1;
Packit 8f70b4
            always_output_a_sign = false;
Packit 8f70b4
            goto do_number_sign_and_padding;
Packit 8f70b4
          }
Packit 8f70b4
Packit 8f70b4
        case L_('X'):
Packit 8f70b4
          if (modifier == L_('O'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
#ifdef _NL_CURRENT
Packit 8f70b4
          if (! (modifier == L_('E')
Packit 8f70b4
                 && (*(subfmt =
Packit 8f70b4
                       (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
Packit 8f70b4
                     != L_('\0'))))
Packit 8f70b4
            subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
Packit 8f70b4
          goto subformat;
Packit 8f70b4
#else
Packit 8f70b4
          goto underlying_strftime;
Packit 8f70b4
#endif
Packit 8f70b4
        case L_('T'):
Packit 8f70b4
          subfmt = L_("%H:%M:%S");
Packit 8f70b4
          goto subformat;
Packit 8f70b4
Packit 8f70b4
        case L_('t'):
Packit 8f70b4
          add1 (L_('\t'));
Packit 8f70b4
          break;
Packit 8f70b4
Packit 8f70b4
        case L_('u'):
Packit 8f70b4
          DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
Packit 8f70b4
Packit 8f70b4
        case L_('U'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
Packit 8f70b4
Packit 8f70b4
        case L_('V'):
Packit 8f70b4
        case L_('g'):
Packit 8f70b4
        case L_('G'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
          {
Packit 8f70b4
            /* YEAR is a leap year if and only if (tp->tm_year + TM_YEAR_BASE)
Packit 8f70b4
               is a leap year, except that YEAR and YEAR - 1 both work
Packit 8f70b4
               correctly even when (tp->tm_year + TM_YEAR_BASE) would
Packit 8f70b4
               overflow.  */
Packit 8f70b4
            int year = (tp->tm_year
Packit 8f70b4
                        + (tp->tm_year < 0
Packit 8f70b4
                           ? TM_YEAR_BASE % 400
Packit 8f70b4
                           : TM_YEAR_BASE % 400 - 400));
Packit 8f70b4
            int year_adjust = 0;
Packit 8f70b4
            int days = iso_week_days (tp->tm_yday, tp->tm_wday);
Packit 8f70b4
Packit 8f70b4
            if (days < 0)
Packit 8f70b4
              {
Packit 8f70b4
                /* This ISO week belongs to the previous year.  */
Packit 8f70b4
                year_adjust = -1;
Packit 8f70b4
                days = iso_week_days (tp->tm_yday + (365 + __isleap (year - 1)),
Packit 8f70b4
                                      tp->tm_wday);
Packit 8f70b4
              }
Packit 8f70b4
            else
Packit 8f70b4
              {
Packit 8f70b4
                int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
Packit 8f70b4
                                       tp->tm_wday);
Packit 8f70b4
                if (0 <= d)
Packit 8f70b4
                  {
Packit 8f70b4
                    /* This ISO week belongs to the next year.  */
Packit 8f70b4
                    year_adjust = 1;
Packit 8f70b4
                    days = d;
Packit 8f70b4
                  }
Packit 8f70b4
              }
Packit 8f70b4
Packit 8f70b4
            switch (*f)
Packit 8f70b4
              {
Packit 8f70b4
              case L_('g'):
Packit 8f70b4
                {
Packit 8f70b4
                  int yy = (tp->tm_year % 100 + year_adjust) % 100;
Packit 8f70b4
                  DO_NUMBER (2, (0 <= yy
Packit 8f70b4
                                 ? yy
Packit 8f70b4
                                 : tp->tm_year < -TM_YEAR_BASE - year_adjust
Packit 8f70b4
                                 ? -yy
Packit 8f70b4
                                 : yy + 100));
Packit 8f70b4
                }
Packit 8f70b4
Packit 8f70b4
              case L_('G'):
Packit 8f70b4
                DO_SIGNED_NUMBER (4, tp->tm_year < -TM_YEAR_BASE - year_adjust,
Packit 8f70b4
                                  (tp->tm_year + (unsigned int) TM_YEAR_BASE
Packit 8f70b4
                                   + year_adjust));
Packit 8f70b4
Packit 8f70b4
              default:
Packit 8f70b4
                DO_NUMBER (2, days / 7 + 1);
Packit 8f70b4
              }
Packit 8f70b4
          }
Packit 8f70b4
Packit 8f70b4
        case L_('W'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
Packit 8f70b4
Packit 8f70b4
        case L_('w'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          DO_NUMBER (1, tp->tm_wday);
Packit 8f70b4
Packit 8f70b4
        case L_('Y'):
Packit 8f70b4
          if (modifier == 'E')
Packit 8f70b4
            {
Packit 8f70b4
#if HAVE_STRUCT_ERA_ENTRY
Packit 8f70b4
              struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
Packit 8f70b4
              if (era)
Packit 8f70b4
                {
Packit 8f70b4
# ifdef COMPILE_WIDE
Packit 8f70b4
                  subfmt = era->era_wformat;
Packit 8f70b4
# else
Packit 8f70b4
                  subfmt = era->era_format;
Packit 8f70b4
# endif
Packit 8f70b4
                  goto subformat;
Packit 8f70b4
                }
Packit 8f70b4
#else
Packit 8f70b4
              goto underlying_strftime;
Packit 8f70b4
#endif
Packit 8f70b4
            }
Packit 8f70b4
          if (modifier == L_('O'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
Packit 8f70b4
          DO_SIGNED_NUMBER (4, tp->tm_year < -TM_YEAR_BASE,
Packit 8f70b4
                            tp->tm_year + (unsigned int) TM_YEAR_BASE);
Packit 8f70b4
Packit 8f70b4
        case L_('y'):
Packit 8f70b4
          if (modifier == L_('E'))
Packit 8f70b4
            {
Packit 8f70b4
#if HAVE_STRUCT_ERA_ENTRY
Packit 8f70b4
              struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
Packit 8f70b4
              if (era)
Packit 8f70b4
                {
Packit 8f70b4
                  int delta = tp->tm_year - era->start_date[0];
Packit 8f70b4
                  DO_NUMBER (1, (era->offset
Packit 8f70b4
                                 + delta * era->absolute_direction));
Packit 8f70b4
                }
Packit 8f70b4
#else
Packit 8f70b4
              goto underlying_strftime;
Packit 8f70b4
#endif
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
          {
Packit 8f70b4
            int yy = tp->tm_year % 100;
Packit 8f70b4
            if (yy < 0)
Packit 8f70b4
              yy = tp->tm_year < - TM_YEAR_BASE ? -yy : yy + 100;
Packit 8f70b4
            DO_NUMBER (2, yy);
Packit 8f70b4
          }
Packit 8f70b4
Packit 8f70b4
        case L_('Z'):
Packit 8f70b4
          if (change_case)
Packit 8f70b4
            {
Packit 8f70b4
              to_uppcase = false;
Packit 8f70b4
              to_lowcase = true;
Packit 8f70b4
            }
Packit 8f70b4
Packit 8f70b4
#ifdef COMPILE_WIDE
Packit 8f70b4
          {
Packit 8f70b4
            /* The zone string is always given in multibyte form.  We have
Packit 8f70b4
               to transform it first.  */
Packit 8f70b4
            wchar_t *wczone;
Packit 8f70b4
            size_t len;
Packit 8f70b4
            widen (zone, wczone, len);
Packit 8f70b4
            cpy (len, wczone);
Packit 8f70b4
          }
Packit 8f70b4
#else
Packit 8f70b4
          cpy (strlen (zone), zone);
Packit 8f70b4
#endif
Packit 8f70b4
          break;
Packit 8f70b4
Packit 8f70b4
        case L_(':'):
Packit 8f70b4
          /* :, ::, and ::: are valid only just before 'z'.
Packit 8f70b4
             :::: etc. are rejected later.  */
Packit 8f70b4
          for (colons = 1; f[colons] == L_(':'); colons++)
Packit 8f70b4
            continue;
Packit 8f70b4
          if (f[colons] != L_('z'))
Packit 8f70b4
            goto bad_format;
Packit 8f70b4
          f += colons;
Packit 8f70b4
          goto do_z_conversion;
Packit 8f70b4
Packit 8f70b4
        case L_('z'):
Packit 8f70b4
          colons = 0;
Packit 8f70b4
Packit 8f70b4
        do_z_conversion:
Packit 8f70b4
          if (tp->tm_isdst < 0)
Packit 8f70b4
            break;
Packit 8f70b4
Packit 8f70b4
          {
Packit 8f70b4
            int diff;
Packit 8f70b4
            int hour_diff;
Packit 8f70b4
            int min_diff;
Packit 8f70b4
            int sec_diff;
Packit 8f70b4
#if HAVE_TM_GMTOFF
Packit 8f70b4
            diff = tp->tm_gmtoff;
Packit 8f70b4
#else
Packit 8f70b4
            if (!tz)
Packit 8f70b4
              diff = 0;
Packit 8f70b4
            else
Packit 8f70b4
              {
Packit 8f70b4
                struct tm gtm;
Packit 8f70b4
                struct tm ltm;
Packit 8f70b4
                time_t lt;
Packit 8f70b4
Packit 8f70b4
                /* POSIX.1 requires that local time zone information be used as
Packit 8f70b4
                   though strftime called tzset.  */
Packit 8f70b4
# if HAVE_TZSET
Packit 8f70b4
                if (!*tzset_called)
Packit 8f70b4
                  {
Packit 8f70b4
                    tzset ();
Packit 8f70b4
                    *tzset_called = true;
Packit 8f70b4
                  }
Packit 8f70b4
# endif
Packit 8f70b4
Packit 8f70b4
                ltm = *tp;
Packit 8f70b4
                lt = mktime_z (tz, <m;;
Packit 8f70b4
Packit 8f70b4
                if (lt == (time_t) -1)
Packit 8f70b4
                  {
Packit 8f70b4
                    /* mktime returns -1 for errors, but -1 is also a
Packit 8f70b4
                       valid time_t value.  Check whether an error really
Packit 8f70b4
                       occurred.  */
Packit 8f70b4
                    struct tm tm;
Packit 8f70b4
Packit 8f70b4
                    if (! localtime_rz (tz, &lt, &tm)
Packit 8f70b4
                        || ((ltm.tm_sec ^ tm.tm_sec)
Packit 8f70b4
                            | (ltm.tm_min ^ tm.tm_min)
Packit 8f70b4
                            | (ltm.tm_hour ^ tm.tm_hour)
Packit 8f70b4
                            | (ltm.tm_mday ^ tm.tm_mday)
Packit 8f70b4
                            | (ltm.tm_mon ^ tm.tm_mon)
Packit 8f70b4
                            | (ltm.tm_year ^ tm.tm_year)))
Packit 8f70b4
                      break;
Packit 8f70b4
                  }
Packit 8f70b4
Packit 8f70b4
                if (! localtime_rz (0, &lt, &gtm))
Packit 8f70b4
                  break;
Packit 8f70b4
Packit 8f70b4
                diff = tm_diff (&ltm, >m;;
Packit 8f70b4
              }
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
            negative_number = diff < 0 || (diff == 0 && *zone == '-');
Packit 8f70b4
            hour_diff = diff / 60 / 60;
Packit 8f70b4
            min_diff = diff / 60 % 60;
Packit 8f70b4
            sec_diff = diff % 60;
Packit 8f70b4
Packit 8f70b4
            switch (colons)
Packit 8f70b4
              {
Packit 8f70b4
              case 0: /* +hhmm */
Packit 8f70b4
                DO_TZ_OFFSET (5, 0, hour_diff * 100 + min_diff);
Packit 8f70b4
Packit 8f70b4
              case 1: tz_hh_mm: /* +hh:mm */
Packit 8f70b4
                DO_TZ_OFFSET (6, 04, hour_diff * 100 + min_diff);
Packit 8f70b4
Packit 8f70b4
              case 2: tz_hh_mm_ss: /* +hh:mm:ss */
Packit 8f70b4
                DO_TZ_OFFSET (9, 024,
Packit 8f70b4
                              hour_diff * 10000 + min_diff * 100 + sec_diff);
Packit 8f70b4
Packit 8f70b4
              case 3: /* +hh if possible, else +hh:mm, else +hh:mm:ss */
Packit 8f70b4
                if (sec_diff != 0)
Packit 8f70b4
                  goto tz_hh_mm_ss;
Packit 8f70b4
                if (min_diff != 0)
Packit 8f70b4
                  goto tz_hh_mm;
Packit 8f70b4
                DO_TZ_OFFSET (3, 0, hour_diff);
Packit 8f70b4
Packit 8f70b4
              default:
Packit 8f70b4
                goto bad_format;
Packit 8f70b4
              }
Packit 8f70b4
          }
Packit 8f70b4
Packit 8f70b4
        case L_('\0'):          /* GNU extension: % at end of format.  */
Packit 8f70b4
            --f;
Packit 8f70b4
            FALLTHROUGH;
Packit 8f70b4
        default:
Packit 8f70b4
          /* Unknown format; output the format, including the '%',
Packit 8f70b4
             since this is most likely the right thing to do if a
Packit 8f70b4
             multibyte string has been misparsed.  */
Packit 8f70b4
        bad_format:
Packit 8f70b4
          {
Packit 8f70b4
            int flen;
Packit 8f70b4
            for (flen = 1; f[1 - flen] != L_('%'); flen++)
Packit 8f70b4
              continue;
Packit 8f70b4
            cpy (flen, &f[1 - flen]);
Packit 8f70b4
          }
Packit 8f70b4
          break;
Packit 8f70b4
        }
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
#if ! FPRINTFTIME
Packit 8f70b4
  if (p && maxsize != 0)
Packit 8f70b4
    *p = L_('\0');
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
  return i;
Packit 8f70b4
}