Blame lib/strftime.c

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