Blame time/strftime_l.c

Packit 6c4009
/* Copyright (C) 2002-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#ifdef HAVE_CONFIG_H
Packit 6c4009
# include <config.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
# define USE_IN_EXTENDED_LOCALE_MODEL 1
Packit 6c4009
# define HAVE_LIMITS_H 1
Packit 6c4009
# define HAVE_MBLEN 1
Packit 6c4009
# define HAVE_MBRLEN 1
Packit 6c4009
# define HAVE_STRUCT_ERA_ENTRY 1
Packit 6c4009
# define HAVE_TM_GMTOFF 1
Packit 6c4009
# define HAVE_TM_ZONE 1
Packit 6c4009
# define HAVE_TZNAME 1
Packit 6c4009
# define HAVE_TZSET 1
Packit 6c4009
# define HAVE_STRFTIME 0
Packit 6c4009
# define MULTIBYTE_IS_FORMAT_SAFE 1
Packit 6c4009
# define STDC_HEADERS 1
Packit 6c4009
# include "../locale/localeinfo.h"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if defined emacs && !defined HAVE_BCOPY
Packit 6c4009
# define HAVE_MEMCPY 1
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include <ctype.h>
Packit 6c4009
#include <sys/types.h>		/* Some systems define `time_t' here.  */
Packit 6c4009
Packit 6c4009
#ifdef TIME_WITH_SYS_TIME
Packit 6c4009
# include <sys/time.h>
Packit 6c4009
# include <time.h>
Packit 6c4009
#else
Packit 6c4009
# ifdef HAVE_SYS_TIME_H
Packit 6c4009
#  include <sys/time.h>
Packit 6c4009
# else
Packit 6c4009
#  include <time.h>
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
#if HAVE_TZNAME
Packit 6c4009
extern char *tzname[];
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Do multibyte processing if multibytes are supported, unless
Packit 6c4009
   multibyte sequences are safe in formats.  Multibyte sequences are
Packit 6c4009
   safe if they cannot contain byte sequences that look like format
Packit 6c4009
   conversion specifications.  The GNU C Library uses UTF8 multibyte
Packit 6c4009
   encoding, which is safe for formats, but strftime.c can be used
Packit 6c4009
   with other C libraries that use unsafe encodings.  */
Packit 6c4009
#define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
Packit 6c4009
Packit 6c4009
#if DO_MULTIBYTE
Packit 6c4009
# if HAVE_MBRLEN
Packit 6c4009
#  include <wchar.h>
Packit 6c4009
# else
Packit 6c4009
   /* Simulate mbrlen with mblen as best we can.  */
Packit 6c4009
#  define mbstate_t int
Packit 6c4009
#  define mbrlen(s, n, ps) mblen (s, n)
Packit 6c4009
#  define mbsinit(ps) (*(ps) == 0)
Packit 6c4009
# endif
Packit 6c4009
  static const mbstate_t mbstate_zero;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if HAVE_LIMITS_H
Packit 6c4009
# include <limits.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if STDC_HEADERS
Packit 6c4009
# include <stddef.h>
Packit 6c4009
# include <stdlib.h>
Packit 6c4009
# include <string.h>
Packit 6c4009
# include <stdbool.h>
Packit 6c4009
#else
Packit 6c4009
# ifndef HAVE_MEMCPY
Packit 6c4009
#  define memcpy(d, s, n) bcopy ((s), (d), (n))
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef COMPILE_WIDE
Packit 6c4009
# include <endian.h>
Packit 6c4009
# define CHAR_T wchar_t
Packit 6c4009
# define UCHAR_T unsigned int
Packit 6c4009
# define L_(Str) L##Str
Packit 6c4009
# define NLW(Sym) _NL_W##Sym
Packit 6c4009
Packit 6c4009
# define MEMCPY(d, s, n) __wmemcpy (d, s, n)
Packit 6c4009
# define STRLEN(s) __wcslen (s)
Packit 6c4009
Packit 6c4009
#else
Packit 6c4009
# define CHAR_T char
Packit 6c4009
# define UCHAR_T unsigned char
Packit 6c4009
# define L_(Str) Str
Packit 6c4009
# define NLW(Sym) Sym
Packit 6c4009
# define ABALTMON_1 _NL_ABALTMON_1
Packit 6c4009
Packit 6c4009
# if !defined STDC_HEADERS && !defined HAVE_MEMCPY
Packit 6c4009
#  define MEMCPY(d, s, n) bcopy ((s), (d), (n))
Packit 6c4009
# else
Packit 6c4009
#  define MEMCPY(d, s, n) memcpy ((d), (s), (n))
Packit 6c4009
# endif
Packit 6c4009
# define STRLEN(s) strlen (s)
Packit 6c4009
Packit 6c4009
# ifdef _LIBC
Packit 6c4009
#  define MEMPCPY(d, s, n) __mempcpy (d, s, n)
Packit 6c4009
# else
Packit 6c4009
#  ifndef HAVE_MEMPCPY
Packit 6c4009
#   define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
Packit 6c4009
#  endif
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef PTR
Packit 6c4009
# define PTR void *
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef CHAR_BIT
Packit 6c4009
# define CHAR_BIT 8
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef NULL
Packit 6c4009
# define NULL 0
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define TYPE_SIGNED(t) ((t) -1 < 0)
Packit 6c4009
Packit 6c4009
/* Bound on length of the string representing an integer value of type t.
Packit 6c4009
   Subtract one for the sign bit if t is signed;
Packit 6c4009
   302 / 1000 is log10 (2) rounded up;
Packit 6c4009
   add one for integer division truncation;
Packit 6c4009
   add one more for a minus sign if t is signed.  */
Packit 6c4009
#define INT_STRLEN_BOUND(t) \
Packit 6c4009
 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t))
Packit 6c4009
Packit 6c4009
#define TM_YEAR_BASE 1900
Packit 6c4009
Packit 6c4009
#ifndef __isleap
Packit 6c4009
/* Nonzero if YEAR is a leap year (every 4 years,
Packit 6c4009
   except every 100th isn't, and every 400th is).  */
Packit 6c4009
# define __isleap(year)	\
Packit 6c4009
  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
# define tzname __tzname
Packit 6c4009
# define tzset __tzset
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if !HAVE_TM_GMTOFF
Packit 6c4009
/* Portable standalone applications should supply a "time_r.h" that
Packit 6c4009
   declares a POSIX-compliant localtime_r, for the benefit of older
Packit 6c4009
   implementations that lack localtime_r or have a nonstandard one.
Packit 6c4009
   Similarly for gmtime_r.  See the gnulib time_r module for one way
Packit 6c4009
   to implement this.  */
Packit 6c4009
# include "time_r.h"
Packit 6c4009
# undef __gmtime_r
Packit 6c4009
# undef __localtime_r
Packit 6c4009
# define __gmtime_r gmtime_r
Packit 6c4009
# define __localtime_r localtime_r
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
#if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
Packit 6c4009
/* Some systems lack the `memset' function and we don't want to
Packit 6c4009
   introduce additional dependencies.  */
Packit 6c4009
/* The SGI compiler reportedly barfs on the trailing null
Packit 6c4009
   if we use a string constant as the initializer.  28 June 1997, rms.  */
Packit 6c4009
static const CHAR_T spaces[16] = /* "                " */
Packit 6c4009
{
Packit 6c4009
  L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),
Packit 6c4009
  L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' ')
Packit 6c4009
};
Packit 6c4009
static const CHAR_T zeroes[16] = /* "0000000000000000" */
Packit 6c4009
{
Packit 6c4009
  L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),
Packit 6c4009
  L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0')
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
# define memset_space(P, Len) \
Packit 6c4009
  do {									      \
Packit 6c4009
    int _len = (Len);							      \
Packit 6c4009
									      \
Packit 6c4009
    do									      \
Packit 6c4009
      {									      \
Packit 6c4009
	int _this = _len > 16 ? 16 : _len;				      \
Packit 6c4009
	(P) = MEMPCPY ((P), spaces, _this * sizeof (CHAR_T));		      \
Packit 6c4009
	_len -= _this;							      \
Packit 6c4009
      }									      \
Packit 6c4009
    while (_len > 0);							      \
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
# define memset_zero(P, Len) \
Packit 6c4009
  do {									      \
Packit 6c4009
    int _len = (Len);							      \
Packit 6c4009
									      \
Packit 6c4009
    do									      \
Packit 6c4009
      {									      \
Packit 6c4009
	int _this = _len > 16 ? 16 : _len;				      \
Packit 6c4009
	(P) = MEMPCPY ((P), zeroes, _this * sizeof (CHAR_T));		      \
Packit 6c4009
	_len -= _this;							      \
Packit 6c4009
      }									      \
Packit 6c4009
    while (_len > 0);							      \
Packit 6c4009
  } while (0)
Packit 6c4009
#else
Packit 6c4009
# ifdef COMPILE_WIDE
Packit 6c4009
#  define memset_space(P, Len) (wmemset ((P), L' ', (Len)), (P) += (Len))
Packit 6c4009
#  define memset_zero(P, Len) (wmemset ((P), L'0', (Len)), (P) += (Len))
Packit 6c4009
# else
Packit 6c4009
#  define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
Packit 6c4009
#  define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define add(n, f)							      \
Packit 6c4009
  do									      \
Packit 6c4009
    {									      \
Packit 6c4009
      int _n = (n);							      \
Packit 6c4009
      int _delta = width - _n;						      \
Packit 6c4009
      int _incr = _n + (_delta > 0 ? _delta : 0);			      \
Packit 6c4009
      if ((size_t) _incr >= maxsize - i)				      \
Packit 6c4009
	return 0;							      \
Packit 6c4009
      if (p)								      \
Packit 6c4009
	{								      \
Packit 6c4009
	  if (_delta > 0)						      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      if (pad == L_('0'))					      \
Packit 6c4009
		memset_zero (p, _delta);				      \
Packit 6c4009
	      else							      \
Packit 6c4009
		memset_space (p, _delta);				      \
Packit 6c4009
	    }								      \
Packit 6c4009
	  f;								      \
Packit 6c4009
	  p += _n;							      \
Packit 6c4009
	}								      \
Packit 6c4009
      i += _incr;							      \
Packit 6c4009
    } while (0)
Packit 6c4009
Packit 6c4009
#define cpy(n, s) \
Packit 6c4009
    add ((n),								      \
Packit 6c4009
	 if (to_lowcase)						      \
Packit 6c4009
	   memcpy_lowcase (p, (s), _n LOCALE_ARG);			      \
Packit 6c4009
	 else if (to_uppcase)						      \
Packit 6c4009
	   memcpy_uppcase (p, (s), _n LOCALE_ARG);			      \
Packit 6c4009
	 else								      \
Packit 6c4009
	   MEMCPY ((PTR) p, (const PTR) (s), _n))
Packit 6c4009
Packit 6c4009
#ifdef COMPILE_WIDE
Packit 6c4009
# ifndef USE_IN_EXTENDED_LOCALE_MODEL
Packit 6c4009
#  undef __mbsrtowcs_l
Packit 6c4009
#  define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
Packit 6c4009
# endif
Packit 6c4009
# define widen(os, ws, l) \
Packit 6c4009
  {									      \
Packit 6c4009
    mbstate_t __st;							      \
Packit 6c4009
    const char *__s = os;						      \
Packit 6c4009
    memset (&__st, '\0', sizeof (__st));				      \
Packit 6c4009
    l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc);			      \
Packit 6c4009
    ws = alloca ((l + 1) * sizeof (wchar_t));				      \
Packit 6c4009
    (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc);			      \
Packit 6c4009
  }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
Packit 6c4009
/* We use this code also for the extended locale handling where the
Packit 6c4009
   function gets as an additional argument the locale which has to be
Packit 6c4009
   used.  To access the values we have to redefine the _NL_CURRENT
Packit 6c4009
   macro.  */
Packit 6c4009
# define strftime		__strftime_l
Packit 6c4009
# define wcsftime		__wcsftime_l
Packit 6c4009
# undef _NL_CURRENT
Packit 6c4009
# define _NL_CURRENT(category, item) \
Packit 6c4009
  (current->values[_NL_ITEM_INDEX (item)].string)
Packit 6c4009
# define LOCALE_PARAM , locale_t loc
Packit 6c4009
# define LOCALE_ARG , loc
Packit 6c4009
# define HELPER_LOCALE_ARG  , current
Packit 6c4009
#else
Packit 6c4009
# define LOCALE_PARAM
Packit 6c4009
# define LOCALE_ARG
Packit 6c4009
# ifdef _LIBC
Packit 6c4009
#  define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
Packit 6c4009
# else
Packit 6c4009
#  define HELPER_LOCALE_ARG
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef COMPILE_WIDE
Packit 6c4009
# ifdef USE_IN_EXTENDED_LOCALE_MODEL
Packit 6c4009
#  define TOUPPER(Ch, L) __towupper_l (Ch, L)
Packit 6c4009
#  define TOLOWER(Ch, L) __towlower_l (Ch, L)
Packit 6c4009
# else
Packit 6c4009
#  define TOUPPER(Ch, L) towupper (Ch)
Packit 6c4009
#  define TOLOWER(Ch, L) towlower (Ch)
Packit 6c4009
# endif
Packit 6c4009
#else
Packit 6c4009
# ifdef _LIBC
Packit 6c4009
#  ifdef USE_IN_EXTENDED_LOCALE_MODEL
Packit 6c4009
#   define TOUPPER(Ch, L) __toupper_l (Ch, L)
Packit 6c4009
#   define TOLOWER(Ch, L) __tolower_l (Ch, L)
Packit 6c4009
#  else
Packit 6c4009
#   define TOUPPER(Ch, L) toupper (Ch)
Packit 6c4009
#   define TOLOWER(Ch, L) tolower (Ch)
Packit 6c4009
#  endif
Packit 6c4009
# else
Packit 6c4009
#  define TOUPPER(Ch, L) (islower (Ch) ? toupper (Ch) : (Ch))
Packit 6c4009
#  define TOLOWER(Ch, L) (isupper (Ch) ? tolower (Ch) : (Ch))
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
/* We don't use `isdigit' here since the locale dependent
Packit 6c4009
   interpretation is not what we want here.  We only need to accept
Packit 6c4009
   the arabic digits in the ASCII range.  One day there is perhaps a
Packit 6c4009
   more reliable way to accept other sets of digits.  */
Packit 6c4009
#define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
Packit 6c4009
Packit 6c4009
static CHAR_T *memcpy_lowcase (CHAR_T *dest, const CHAR_T *src,
Packit 6c4009
			       size_t len LOCALE_PARAM) __THROW;
Packit 6c4009
Packit 6c4009
static CHAR_T *
Packit 6c4009
memcpy_lowcase (CHAR_T *dest, const CHAR_T *src, size_t len LOCALE_PARAM)
Packit 6c4009
{
Packit 6c4009
  while (len-- > 0)
Packit 6c4009
    dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
Packit 6c4009
  return dest;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static CHAR_T *memcpy_uppcase (CHAR_T *dest, const CHAR_T *src,
Packit 6c4009
			       size_t len LOCALE_PARAM) __THROW;
Packit 6c4009
Packit 6c4009
static CHAR_T *
Packit 6c4009
memcpy_uppcase (CHAR_T *dest, const CHAR_T *src, size_t len LOCALE_PARAM)
Packit 6c4009
{
Packit 6c4009
  while (len-- > 0)
Packit 6c4009
    dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
Packit 6c4009
  return dest;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
#if ! HAVE_TM_GMTOFF
Packit 6c4009
/* Yield the difference between *A and *B,
Packit 6c4009
   measured in seconds, ignoring leap seconds.  */
Packit 6c4009
# define tm_diff ftime_tm_diff
Packit 6c4009
static int tm_diff (const struct tm *, const struct tm *) __THROW;
Packit 6c4009
static int
Packit 6c4009
tm_diff (const struct tm *a, const struct tm *b)
Packit 6c4009
{
Packit 6c4009
  /* Compute intervening leap days correctly even if year is negative.
Packit 6c4009
     Take care to avoid int overflow in leap day calculations,
Packit 6c4009
     but it's OK to assume that A and B are close to each other.  */
Packit 6c4009
  int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
Packit 6c4009
  int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
Packit 6c4009
  int a100 = a4 / 25 - (a4 % 25 < 0);
Packit 6c4009
  int b100 = b4 / 25 - (b4 % 25 < 0);
Packit 6c4009
  int a400 = a100 >> 2;
Packit 6c4009
  int b400 = b100 >> 2;
Packit 6c4009
  int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
Packit 6c4009
  int years = a->tm_year - b->tm_year;
Packit 6c4009
  int days = (365 * years + intervening_leap_days
Packit 6c4009
	      + (a->tm_yday - b->tm_yday));
Packit 6c4009
  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
Packit 6c4009
		+ (a->tm_min - b->tm_min))
Packit 6c4009
	  + (a->tm_sec - b->tm_sec));
Packit 6c4009
}
Packit 6c4009
#endif /* ! HAVE_TM_GMTOFF */
Packit 6c4009
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* The number of days from the first day of the first ISO week of this
Packit 6c4009
   year to the year day YDAY with week day WDAY.  ISO weeks start on
Packit 6c4009
   Monday; the first ISO week has the year's first Thursday.  YDAY may
Packit 6c4009
   be as small as YDAY_MINIMUM.  */
Packit 6c4009
#define ISO_WEEK_START_WDAY 1 /* Monday */
Packit 6c4009
#define ISO_WEEK1_WDAY 4 /* Thursday */
Packit 6c4009
#define YDAY_MINIMUM (-366)
Packit 6c4009
static int iso_week_days (int, int) __THROW;
Packit 6c4009
#ifdef __GNUC__
Packit 6c4009
__inline__
Packit 6c4009
#endif
Packit 6c4009
static int
Packit 6c4009
iso_week_days (int yday, int wday)
Packit 6c4009
{
Packit 6c4009
  /* Add enough to the first operand of % to make it nonnegative.  */
Packit 6c4009
  int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
Packit 6c4009
  return (yday
Packit 6c4009
	  - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
Packit 6c4009
	  + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
#if !(defined _NL_CURRENT || HAVE_STRFTIME)
Packit 6c4009
static CHAR_T const weekday_name[][10] =
Packit 6c4009
  {
Packit 6c4009
    L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
Packit 6c4009
    L_("Thursday"), L_("Friday"), L_("Saturday")
Packit 6c4009
  };
Packit 6c4009
static CHAR_T const month_name[][10] =
Packit 6c4009
  {
Packit 6c4009
    L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
Packit 6c4009
    L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
Packit 6c4009
    L_("November"), L_("December")
Packit 6c4009
  };
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef emacs
Packit 6c4009
# define my_strftime emacs_strftimeu
Packit 6c4009
# define ut_argument , ut
Packit 6c4009
# define ut_argument_spec , int ut
Packit 6c4009
#else
Packit 6c4009
# ifdef COMPILE_WIDE
Packit 6c4009
#  define my_strftime wcsftime
Packit 6c4009
#  define nl_get_alt_digit _nl_get_walt_digit
Packit 6c4009
# else
Packit 6c4009
#  define my_strftime strftime
Packit 6c4009
#  define nl_get_alt_digit _nl_get_alt_digit
Packit 6c4009
# endif
Packit 6c4009
# define ut_argument
Packit 6c4009
# define ut_argument_spec
Packit 6c4009
/* We don't have this information in general.  */
Packit 6c4009
# define ut 0
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
static size_t __strftime_internal (CHAR_T *, size_t, const CHAR_T *,
Packit 6c4009
				   const struct tm *, bool *
Packit 6c4009
				   ut_argument_spec
Packit 6c4009
				   LOCALE_PARAM) __THROW;
Packit 6c4009
Packit 6c4009
/* Write information from TP into S according to the format
Packit 6c4009
   string FORMAT, writing no more that MAXSIZE characters
Packit 6c4009
   (including the terminating '\0') and returning number of
Packit 6c4009
   characters written.  If S is NULL, nothing will be written
Packit 6c4009
   anywhere, so to determine how many characters would be
Packit 6c4009
   written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */
Packit 6c4009
Packit 6c4009
size_t
Packit 6c4009
my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
Packit 6c4009
	     const struct tm *tp ut_argument_spec LOCALE_PARAM)
Packit 6c4009
{
Packit 6c4009
#if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
Packit 6c4009
  /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
Packit 6c4009
     Work around this bug by copying *tp before it might be munged.  */
Packit 6c4009
  struct tm tmcopy;
Packit 6c4009
  tmcopy = *tp;
Packit 6c4009
  tp = &tmcopy;
Packit 6c4009
#endif
Packit 6c4009
  bool tzset_called = false;
Packit 6c4009
  return __strftime_internal (s, maxsize, format, tp, &tzset_called
Packit 6c4009
			      ut_argument LOCALE_ARG);
Packit 6c4009
}
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
libc_hidden_def (my_strftime)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
__strftime_internal (CHAR_T *s, size_t maxsize, const CHAR_T *format,
Packit 6c4009
		     const struct tm *tp, bool *tzset_called
Packit 6c4009
		     ut_argument_spec LOCALE_PARAM)
Packit 6c4009
{
Packit 6c4009
#if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
Packit 6c4009
  struct __locale_data *const current = loc->__locales[LC_TIME];
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  int hour12 = tp->tm_hour;
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
  /* We cannot make the following values variables since we must delay
Packit 6c4009
     the evaluation of these values until really needed since some
Packit 6c4009
     expressions might not be valid in every situation.  The `struct tm'
Packit 6c4009
     might be generated by a strptime() call that initialized
Packit 6c4009
     only a few elements.  Dereference the pointers only if the format
Packit 6c4009
     requires this.  Then it is ok to fail if the pointers are invalid.  */
Packit 6c4009
# define a_wkday \
Packit 6c4009
  ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6			     \
Packit 6c4009
		     ? "?" : _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday)))
Packit 6c4009
# define f_wkday \
Packit 6c4009
  ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6			     \
Packit 6c4009
		     ? "?" : _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday)))
Packit 6c4009
# define a_month \
Packit 6c4009
  ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11			     \
Packit 6c4009
		     ? "?" : _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon)))
Packit 6c4009
# define f_month \
Packit 6c4009
  ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11			     \
Packit 6c4009
		     ? "?" : _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon)))
Packit 6c4009
# define a_altmonth \
Packit 6c4009
  ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11			     \
Packit 6c4009
		     ? "?" : _NL_CURRENT (LC_TIME, NLW(ABALTMON_1) + tp->tm_mon)))
Packit 6c4009
# define f_altmonth \
Packit 6c4009
  ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11			     \
Packit 6c4009
		     ? "?" : _NL_CURRENT (LC_TIME, NLW(ALTMON_1) + tp->tm_mon)))
Packit 6c4009
# define ampm \
Packit 6c4009
  ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11		      \
Packit 6c4009
				 ? NLW(PM_STR) : NLW(AM_STR)))
Packit 6c4009
Packit 6c4009
# define aw_len STRLEN (a_wkday)
Packit 6c4009
# define am_len STRLEN (a_month)
Packit 6c4009
# define aam_len STRLEN (a_altmonth)
Packit 6c4009
# define ap_len STRLEN (ampm)
Packit 6c4009
#else
Packit 6c4009
# if !HAVE_STRFTIME
Packit 6c4009
#  define f_wkday (tp->tm_wday < 0 || tp->tm_wday > 6	\
Packit 6c4009
		   ? "?" : weekday_name[tp->tm_wday])
Packit 6c4009
#  define f_month (tp->tm_mon < 0 || tp->tm_mon > 11	\
Packit 6c4009
		   ? "?" : month_name[tp->tm_mon])
Packit 6c4009
#  define a_wkday f_wkday
Packit 6c4009
#  define a_month f_month
Packit 6c4009
#  define a_altmonth a_month
Packit 6c4009
#  define f_altmonth f_month
Packit 6c4009
#  define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
Packit 6c4009
Packit 6c4009
  size_t aw_len = 3;
Packit 6c4009
  size_t am_len = 3;
Packit 6c4009
  size_t aam_len = 3;
Packit 6c4009
  size_t ap_len = 2;
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
  const char *zone;
Packit 6c4009
  size_t i = 0;
Packit 6c4009
  CHAR_T *p = s;
Packit 6c4009
  const CHAR_T *f;
Packit 6c4009
#if DO_MULTIBYTE && !defined COMPILE_WIDE
Packit 6c4009
  const char *format_end = NULL;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  zone = NULL;
Packit 6c4009
#if HAVE_TM_ZONE
Packit 6c4009
  /* The POSIX test suite assumes that setting
Packit 6c4009
     the environment variable TZ to a new value before calling strftime()
Packit 6c4009
     will influence the result (the %Z format) even if the information in
Packit 6c4009
     TP is computed with a totally different time zone.
Packit 6c4009
     This is bogus: though POSIX allows bad behavior like this,
Packit 6c4009
     POSIX does not require it.  Do the right thing instead.  */
Packit 6c4009
  zone = (const char *) tp->tm_zone;
Packit 6c4009
#endif
Packit 6c4009
#if HAVE_TZNAME
Packit 6c4009
  if (ut)
Packit 6c4009
    {
Packit 6c4009
      if (! (zone && *zone))
Packit 6c4009
	zone = "GMT";
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  if (hour12 > 12)
Packit 6c4009
    hour12 -= 12;
Packit 6c4009
  else
Packit 6c4009
    if (hour12 == 0)
Packit 6c4009
      hour12 = 12;
Packit 6c4009
Packit 6c4009
  for (f = format; *f != '\0'; ++f)
Packit 6c4009
    {
Packit 6c4009
      int pad = 0;		/* Padding for number ('-', '_', or 0).  */
Packit 6c4009
      int modifier;		/* Field modifier ('E', 'O', or 0).  */
Packit 6c4009
      int digits;		/* Max digits for numeric format.  */
Packit 6c4009
      int number_value; 	/* Numeric value to be printed.  */
Packit 6c4009
      int negative_number;	/* 1 if the number is negative.  */
Packit 6c4009
      const CHAR_T *subfmt;
Packit 6c4009
      CHAR_T *bufp;
Packit 6c4009
      CHAR_T buf[1 + (sizeof (int) < sizeof (time_t)
Packit 6c4009
		      ? INT_STRLEN_BOUND (time_t)
Packit 6c4009
		      : INT_STRLEN_BOUND (int))];
Packit 6c4009
      int width = -1;
Packit 6c4009
      int to_lowcase = 0;
Packit 6c4009
      int to_uppcase = 0;
Packit 6c4009
      int change_case = 0;
Packit 6c4009
      int format_char;
Packit 6c4009
Packit 6c4009
#if DO_MULTIBYTE && !defined COMPILE_WIDE
Packit 6c4009
      switch (*f)
Packit 6c4009
	{
Packit 6c4009
	case L_('%'):
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case L_('\b'): case L_('\t'): case L_('\n'):
Packit 6c4009
	case L_('\v'): case L_('\f'): case L_('\r'):
Packit 6c4009
	case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
Packit 6c4009
	case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
Packit 6c4009
	case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
Packit 6c4009
	case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
Packit 6c4009
	case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
Packit 6c4009
	case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
Packit 6c4009
	case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
Packit 6c4009
	case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
Packit 6c4009
	case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
Packit 6c4009
	case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
Packit 6c4009
	case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
Packit 6c4009
	case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
Packit 6c4009
	case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
Packit 6c4009
	case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
Packit 6c4009
	case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
Packit 6c4009
	case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
Packit 6c4009
	case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
Packit 6c4009
	case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
Packit 6c4009
	case L_('~'):
Packit 6c4009
	  /* The C Standard requires these 98 characters (plus '%') to
Packit 6c4009
	     be in the basic execution character set.  None of these
Packit 6c4009
	     characters can start a multibyte sequence, so they need
Packit 6c4009
	     not be analyzed further.  */
Packit 6c4009
	  add (1, *p = *f);
Packit 6c4009
	  continue;
Packit 6c4009
Packit 6c4009
	default:
Packit 6c4009
	  /* Copy this multibyte sequence until we reach its end, find
Packit 6c4009
	     an error, or come back to the initial shift state.  */
Packit 6c4009
	  {
Packit 6c4009
	    mbstate_t mbstate = mbstate_zero;
Packit 6c4009
	    size_t len = 0;
Packit 6c4009
	    size_t fsize;
Packit 6c4009
Packit 6c4009
	    if (! format_end)
Packit 6c4009
	      format_end = f + strlen (f) + 1;
Packit 6c4009
	    fsize = format_end - f;
Packit 6c4009
Packit 6c4009
	    do
Packit 6c4009
	      {
Packit 6c4009
		size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
Packit 6c4009
Packit 6c4009
		if (bytes == 0)
Packit 6c4009
		  break;
Packit 6c4009
Packit 6c4009
		if (bytes == (size_t) -2)
Packit 6c4009
		  {
Packit 6c4009
		    len += strlen (f + len);
Packit 6c4009
		    break;
Packit 6c4009
		  }
Packit 6c4009
Packit 6c4009
		if (bytes == (size_t) -1)
Packit 6c4009
		  {
Packit 6c4009
		    len++;
Packit 6c4009
		    break;
Packit 6c4009
		  }
Packit 6c4009
Packit 6c4009
		len += bytes;
Packit 6c4009
	      }
Packit 6c4009
	    while (! mbsinit (&mbstate));
Packit 6c4009
Packit 6c4009
	    cpy (len, f);
Packit 6c4009
	    f += len - 1;
Packit 6c4009
	    continue;
Packit 6c4009
	  }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
#else /* ! DO_MULTIBYTE */
Packit 6c4009
Packit 6c4009
      /* Either multibyte encodings are not supported, they are
Packit 6c4009
	 safe for formats, so any non-'%' byte can be copied through,
Packit 6c4009
	 or this is the wide character version.  */
Packit 6c4009
      if (*f != L_('%'))
Packit 6c4009
	{
Packit 6c4009
	  add (1, *p = *f);
Packit 6c4009
	  continue;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
#endif /* ! DO_MULTIBYTE */
Packit 6c4009
Packit 6c4009
      /* Check for flags that can modify a format.  */
Packit 6c4009
      while (1)
Packit 6c4009
	{
Packit 6c4009
	  switch (*++f)
Packit 6c4009
	    {
Packit 6c4009
	      /* This influences the number formats.  */
Packit 6c4009
	    case L_('_'):
Packit 6c4009
	    case L_('-'):
Packit 6c4009
	    case L_('0'):
Packit 6c4009
	      pad = *f;
Packit 6c4009
	      continue;
Packit 6c4009
Packit 6c4009
	      /* This changes textual output.  */
Packit 6c4009
	    case L_('^'):
Packit 6c4009
	      to_uppcase = 1;
Packit 6c4009
	      continue;
Packit 6c4009
	    case L_('#'):
Packit 6c4009
	      change_case = 1;
Packit 6c4009
	      continue;
Packit 6c4009
Packit 6c4009
	    default:
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* As a GNU extension we allow to specify the field width.  */
Packit 6c4009
      if (ISDIGIT (*f))
Packit 6c4009
	{
Packit 6c4009
	  width = 0;
Packit 6c4009
	  do
Packit 6c4009
	    {
Packit 6c4009
	      if (width > INT_MAX / 10
Packit 6c4009
		  || (width == INT_MAX / 10 && *f - L_('0') > INT_MAX % 10))
Packit 6c4009
		/* Avoid overflow.  */
Packit 6c4009
		width = INT_MAX;
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  width *= 10;
Packit 6c4009
		  width += *f - L_('0');
Packit 6c4009
		}
Packit 6c4009
	      ++f;
Packit 6c4009
	    }
Packit 6c4009
	  while (ISDIGIT (*f));
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Check for modifiers.  */
Packit 6c4009
      switch (*f)
Packit 6c4009
	{
Packit 6c4009
	case L_('E'):
Packit 6c4009
	case L_('O'):
Packit 6c4009
	  modifier = *f++;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	default:
Packit 6c4009
	  modifier = 0;
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Now do the specified format.  */
Packit 6c4009
      format_char = *f;
Packit 6c4009
      switch (format_char)
Packit 6c4009
	{
Packit 6c4009
#define DO_NUMBER(d, v)				\
Packit 6c4009
	  do					\
Packit 6c4009
	    {					\
Packit 6c4009
	      digits = d > width ? d : width;	\
Packit 6c4009
	      number_value = v;			\
Packit 6c4009
	      goto do_number;			\
Packit 6c4009
	    }					\
Packit 6c4009
	  while (0)
Packit 6c4009
#define DO_NUMBER_SPACEPAD(d, v)		\
Packit 6c4009
	  do					\
Packit 6c4009
	    {					\
Packit 6c4009
	      digits = d > width ? d : width;	\
Packit 6c4009
	      number_value = v;			\
Packit 6c4009
	      goto do_number_spacepad;		\
Packit 6c4009
	    }					\
Packit 6c4009
	  while (0)
Packit 6c4009
Packit 6c4009
	case L_('%'):
Packit 6c4009
	  if (modifier != 0)
Packit 6c4009
	    goto bad_format;
Packit 6c4009
	  add (1, *p = *f);
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case L_('a'):
Packit 6c4009
	  if (modifier != 0)
Packit 6c4009
	    goto bad_format;
Packit 6c4009
	  if (change_case)
Packit 6c4009
	    {
Packit 6c4009
	      to_uppcase = 1;
Packit 6c4009
	      to_lowcase = 0;
Packit 6c4009
	    }
Packit 6c4009
#if defined _NL_CURRENT || !HAVE_STRFTIME
Packit 6c4009
	  cpy (aw_len, a_wkday);
Packit 6c4009
	  break;
Packit 6c4009
#else
Packit 6c4009
	  goto underlying_strftime;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	case 'A':
Packit 6c4009
	  if (modifier != 0)
Packit 6c4009
	    goto bad_format;
Packit 6c4009
	  if (change_case)
Packit 6c4009
	    {
Packit 6c4009
	      to_uppcase = 1;
Packit 6c4009
	      to_lowcase = 0;
Packit 6c4009
	    }
Packit 6c4009
#if defined _NL_CURRENT || !HAVE_STRFTIME
Packit 6c4009
	  cpy (STRLEN (f_wkday), f_wkday);
Packit 6c4009
	  break;
Packit 6c4009
#else
Packit 6c4009
	  goto underlying_strftime;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	case L_('b'):
Packit 6c4009
	case L_('h'):
Packit 6c4009
	  if (change_case)
Packit 6c4009
	    {
Packit 6c4009
	      to_uppcase = 1;
Packit 6c4009
	      to_lowcase = 0;
Packit 6c4009
	    }
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
#if defined _NL_CURRENT || !HAVE_STRFTIME
Packit 6c4009
	  if (modifier == L_('O'))
Packit 6c4009
	    cpy (aam_len, a_altmonth);
Packit 6c4009
	  else
Packit 6c4009
	    cpy (am_len, a_month);
Packit 6c4009
	  break;
Packit 6c4009
#else
Packit 6c4009
	  goto underlying_strftime;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	case L_('B'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
	  if (change_case)
Packit 6c4009
	    {
Packit 6c4009
	      to_uppcase = 1;
Packit 6c4009
	      to_lowcase = 0;
Packit 6c4009
	    }
Packit 6c4009
#if defined _NL_CURRENT || !HAVE_STRFTIME
Packit 6c4009
	  if (modifier == L_('O'))
Packit 6c4009
	    cpy (STRLEN (f_altmonth), f_altmonth);
Packit 6c4009
	  else
Packit 6c4009
	    cpy (STRLEN (f_month), f_month);
Packit 6c4009
	  break;
Packit 6c4009
#else
Packit 6c4009
	  goto underlying_strftime;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	case L_('c'):
Packit 6c4009
	  if (modifier == L_('O'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
	  if (! (modifier == 'E'
Packit 6c4009
		 && (*(subfmt =
Packit 6c4009
		       (const CHAR_T *) _NL_CURRENT (LC_TIME,
Packit 6c4009
						     NLW(ERA_D_T_FMT)))
Packit 6c4009
		     != '\0')))
Packit 6c4009
	    subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
Packit 6c4009
#else
Packit 6c4009
# if HAVE_STRFTIME
Packit 6c4009
	  goto underlying_strftime;
Packit 6c4009
# else
Packit 6c4009
	  subfmt = L_("%a %b %e %H:%M:%S %Y");
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	subformat:
Packit 6c4009
	  {
Packit 6c4009
	    CHAR_T *old_start = p;
Packit 6c4009
	    size_t len = __strftime_internal (NULL, (size_t) -1, subfmt,
Packit 6c4009
					      tp, tzset_called ut_argument
Packit 6c4009
					      LOCALE_ARG);
Packit 6c4009
	    add (len, __strftime_internal (p, maxsize - i, subfmt,
Packit 6c4009
					   tp, tzset_called ut_argument
Packit 6c4009
					   LOCALE_ARG));
Packit 6c4009
Packit 6c4009
	    if (to_uppcase)
Packit 6c4009
	      while (old_start < p)
Packit 6c4009
		{
Packit 6c4009
		  *old_start = TOUPPER ((UCHAR_T) *old_start, loc);
Packit 6c4009
		  ++old_start;
Packit 6c4009
		}
Packit 6c4009
	  }
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
#if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
Packit 6c4009
	underlying_strftime:
Packit 6c4009
	  {
Packit 6c4009
	    /* The relevant information is available only via the
Packit 6c4009
	       underlying strftime implementation, so use that.  */
Packit 6c4009
	    char ufmt[4];
Packit 6c4009
	    char *u = ufmt;
Packit 6c4009
	    char ubuf[1024]; /* enough for any single format in practice */
Packit 6c4009
	    size_t len;
Packit 6c4009
	    /* Make sure we're calling the actual underlying strftime.
Packit 6c4009
	       In some cases, config.h contains something like
Packit 6c4009
	       "#define strftime rpl_strftime".  */
Packit 6c4009
# ifdef strftime
Packit 6c4009
#  undef strftime
Packit 6c4009
	    size_t strftime ();
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
	    *u++ = '%';
Packit 6c4009
	    if (modifier != 0)
Packit 6c4009
	      *u++ = modifier;
Packit 6c4009
	    *u++ = format_char;
Packit 6c4009
	    *u = '\0';
Packit 6c4009
	    len = strftime (ubuf, sizeof ubuf, ufmt, tp);
Packit 6c4009
	    if (len == 0 && ubuf[0] != '\0')
Packit 6c4009
	      return 0;
Packit 6c4009
	    cpy (len, ubuf);
Packit 6c4009
	  }
Packit 6c4009
	  break;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	case L_('C'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    {
Packit 6c4009
#if HAVE_STRUCT_ERA_ENTRY
Packit 6c4009
	      struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
Packit 6c4009
	      if (era)
Packit 6c4009
		{
Packit 6c4009
# ifdef COMPILE_WIDE
Packit 6c4009
		  size_t len = __wcslen (era->era_wname);
Packit 6c4009
		  cpy (len, era->era_wname);
Packit 6c4009
# else
Packit 6c4009
		  size_t len = strlen (era->era_name);
Packit 6c4009
		  cpy (len, era->era_name);
Packit 6c4009
# endif
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
#else
Packit 6c4009
# if HAVE_STRFTIME
Packit 6c4009
	      goto underlying_strftime;
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  {
Packit 6c4009
	    int year = tp->tm_year + TM_YEAR_BASE;
Packit 6c4009
	    DO_NUMBER (1, year / 100 - (year % 100 < 0));
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	case L_('x'):
Packit 6c4009
	  if (modifier == L_('O'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
	  if (! (modifier == L_('E')
Packit 6c4009
		 && (*(subfmt =
Packit 6c4009
		       (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
Packit 6c4009
		     != L_('\0'))))
Packit 6c4009
	    subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
Packit 6c4009
	  goto subformat;
Packit 6c4009
#else
Packit 6c4009
# if HAVE_STRFTIME
Packit 6c4009
	  goto underlying_strftime;
Packit 6c4009
# else
Packit 6c4009
	  /* Fall through.  */
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
	case L_('D'):
Packit 6c4009
	  if (modifier != 0)
Packit 6c4009
	    goto bad_format;
Packit 6c4009
	  subfmt = L_("%m/%d/%y");
Packit 6c4009
	  goto subformat;
Packit 6c4009
Packit 6c4009
	case L_('d'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
Packit 6c4009
	  DO_NUMBER (2, tp->tm_mday);
Packit 6c4009
Packit 6c4009
	case L_('e'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
Packit 6c4009
	  DO_NUMBER_SPACEPAD (2, tp->tm_mday);
Packit 6c4009
Packit 6c4009
	  /* All numeric formats set DIGITS and NUMBER_VALUE and then
Packit 6c4009
	     jump to one of these two labels.  */
Packit 6c4009
Packit 6c4009
	do_number_spacepad:
Packit 6c4009
	  /* Force `_' flag unless overwritten by `0' or '-' flag.  */
Packit 6c4009
	  if (pad != L_('0') && pad != L_('-'))
Packit 6c4009
	    pad = L_('_');
Packit 6c4009
Packit 6c4009
	do_number:
Packit 6c4009
	  /* Format the number according to the MODIFIER flag.  */
Packit 6c4009
Packit 6c4009
	  if (modifier == L_('O') && 0 <= number_value)
Packit 6c4009
	    {
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
	      /* Get the locale specific alternate representation of
Packit 6c4009
		 the number NUMBER_VALUE.  If none exist NULL is returned.  */
Packit 6c4009
	      const CHAR_T *cp = nl_get_alt_digit (number_value
Packit 6c4009
						   HELPER_LOCALE_ARG);
Packit 6c4009
Packit 6c4009
	      if (cp != NULL)
Packit 6c4009
		{
Packit 6c4009
		  size_t digitlen = STRLEN (cp);
Packit 6c4009
		  if (digitlen != 0)
Packit 6c4009
		    {
Packit 6c4009
		      cpy (digitlen, cp);
Packit 6c4009
		      break;
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
#else
Packit 6c4009
# if HAVE_STRFTIME
Packit 6c4009
	      goto underlying_strftime;
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
	    }
Packit 6c4009
	  {
Packit 6c4009
	    unsigned int u = number_value;
Packit 6c4009
Packit 6c4009
	    bufp = buf + sizeof (buf) / sizeof (buf[0]);
Packit 6c4009
	    negative_number = number_value < 0;
Packit 6c4009
Packit 6c4009
	    if (negative_number)
Packit 6c4009
	      u = -u;
Packit 6c4009
Packit 6c4009
	    do
Packit 6c4009
	      *--bufp = u % 10 + L_('0');
Packit 6c4009
	    while ((u /= 10) != 0);
Packit 6c4009
  	  }
Packit 6c4009
Packit 6c4009
	do_number_sign_and_padding:
Packit 6c4009
	  if (negative_number)
Packit 6c4009
	    *--bufp = L_('-');
Packit 6c4009
Packit 6c4009
	  if (pad != L_('-'))
Packit 6c4009
	    {
Packit 6c4009
	      int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
Packit 6c4009
				      - bufp);
Packit 6c4009
Packit 6c4009
	      if (padding > 0)
Packit 6c4009
		{
Packit 6c4009
		  if (pad == L_('_'))
Packit 6c4009
		    {
Packit 6c4009
		      if ((size_t) padding >= maxsize - i)
Packit 6c4009
			return 0;
Packit 6c4009
Packit 6c4009
		      if (p)
Packit 6c4009
			memset_space (p, padding);
Packit 6c4009
		      i += padding;
Packit 6c4009
		      width = width > padding ? width - padding : 0;
Packit 6c4009
		    }
Packit 6c4009
		  else
Packit 6c4009
		    {
Packit 6c4009
		      if ((size_t) digits >= maxsize - i)
Packit 6c4009
			return 0;
Packit 6c4009
Packit 6c4009
		      if (negative_number)
Packit 6c4009
			{
Packit 6c4009
			  ++bufp;
Packit 6c4009
Packit 6c4009
			  if (p)
Packit 6c4009
			    *p++ = L_('-');
Packit 6c4009
			  ++i;
Packit 6c4009
			}
Packit 6c4009
Packit 6c4009
		      if (p)
Packit 6c4009
			memset_zero (p, padding);
Packit 6c4009
		      i += padding;
Packit 6c4009
		      width = 0;
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case L_('F'):
Packit 6c4009
	  if (modifier != 0)
Packit 6c4009
	    goto bad_format;
Packit 6c4009
	  subfmt = L_("%Y-%m-%d");
Packit 6c4009
	  goto subformat;
Packit 6c4009
Packit 6c4009
	case L_('H'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
Packit 6c4009
	  DO_NUMBER (2, tp->tm_hour);
Packit 6c4009
Packit 6c4009
	case L_('I'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
Packit 6c4009
	  DO_NUMBER (2, hour12);
Packit 6c4009
Packit 6c4009
	case L_('k'):		/* GNU extension.  */
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
Packit 6c4009
	  DO_NUMBER_SPACEPAD (2, tp->tm_hour);
Packit 6c4009
Packit 6c4009
	case L_('l'):		/* GNU extension.  */
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
Packit 6c4009
	  DO_NUMBER_SPACEPAD (2, hour12);
Packit 6c4009
Packit 6c4009
	case L_('j'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
Packit 6c4009
	  DO_NUMBER (3, 1 + tp->tm_yday);
Packit 6c4009
Packit 6c4009
	case L_('M'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
Packit 6c4009
	  DO_NUMBER (2, tp->tm_min);
Packit 6c4009
Packit 6c4009
	case L_('m'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
Packit 6c4009
	  DO_NUMBER (2, tp->tm_mon + 1);
Packit 6c4009
Packit 6c4009
	case L_('n'):
Packit 6c4009
	  add (1, *p = L_('\n'));
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case L_('P'):
Packit 6c4009
	  to_lowcase = 1;
Packit 6c4009
#if !defined _NL_CURRENT && HAVE_STRFTIME
Packit 6c4009
	  format_char = L_('p');
Packit 6c4009
#endif
Packit 6c4009
	  /* FALLTHROUGH */
Packit 6c4009
Packit 6c4009
	case L_('p'):
Packit 6c4009
	  if (change_case)
Packit 6c4009
	    {
Packit 6c4009
	      to_uppcase = 0;
Packit 6c4009
	      to_lowcase = 1;
Packit 6c4009
	    }
Packit 6c4009
#if defined _NL_CURRENT || !HAVE_STRFTIME
Packit 6c4009
	  cpy (ap_len, ampm);
Packit 6c4009
	  break;
Packit 6c4009
#else
Packit 6c4009
	  goto underlying_strftime;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	case L_('R'):
Packit 6c4009
	  subfmt = L_("%H:%M");
Packit 6c4009
	  goto subformat;
Packit 6c4009
Packit 6c4009
	case L_('r'):
Packit 6c4009
#if !defined _NL_CURRENT && HAVE_STRFTIME
Packit 6c4009
	  goto underlying_strftime;
Packit 6c4009
#else
Packit 6c4009
# ifdef _NL_CURRENT
Packit 6c4009
	  if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
Packit 6c4009
						       NLW(T_FMT_AMPM)))
Packit 6c4009
	      == L_('\0'))
Packit 6c4009
# endif
Packit 6c4009
	    subfmt = L_("%I:%M:%S %p");
Packit 6c4009
	  goto subformat;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	case L_('S'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
Packit 6c4009
	  DO_NUMBER (2, tp->tm_sec);
Packit 6c4009
Packit 6c4009
	case L_('s'):		/* GNU extension.  */
Packit 6c4009
  	  {
Packit 6c4009
	    struct tm ltm;
Packit 6c4009
	    time_t t;
Packit 6c4009
Packit 6c4009
	    ltm = *tp;
Packit 6c4009
	    t = mktime (<m;;
Packit 6c4009
Packit 6c4009
	    /* Generate string value for T using time_t arithmetic;
Packit 6c4009
	       this works even if sizeof (long) < sizeof (time_t).  */
Packit 6c4009
Packit 6c4009
	    bufp = buf + sizeof (buf) / sizeof (buf[0]);
Packit 6c4009
	    negative_number = t < 0;
Packit 6c4009
Packit 6c4009
	    do
Packit 6c4009
	      {
Packit 6c4009
		int d = t % 10;
Packit 6c4009
		t /= 10;
Packit 6c4009
Packit 6c4009
		if (negative_number)
Packit 6c4009
		  {
Packit 6c4009
		    d = -d;
Packit 6c4009
Packit 6c4009
		    /* Adjust if division truncates to minus infinity.  */
Packit 6c4009
		    if (0 < -1 % 10 && d < 0)
Packit 6c4009
		      {
Packit 6c4009
			t++;
Packit 6c4009
			d += 10;
Packit 6c4009
		      }
Packit 6c4009
		  }
Packit 6c4009
Packit 6c4009
		*--bufp = d + L_('0');
Packit 6c4009
	      }
Packit 6c4009
	    while (t != 0);
Packit 6c4009
Packit 6c4009
	    digits = 1;
Packit 6c4009
	    goto do_number_sign_and_padding;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	case L_('X'):
Packit 6c4009
	  if (modifier == L_('O'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
	  if (! (modifier == L_('E')
Packit 6c4009
		 && (*(subfmt =
Packit 6c4009
		       (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
Packit 6c4009
		     != L_('\0'))))
Packit 6c4009
	    subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
Packit 6c4009
	  goto subformat;
Packit 6c4009
#else
Packit 6c4009
# if HAVE_STRFTIME
Packit 6c4009
	  goto underlying_strftime;
Packit 6c4009
# else
Packit 6c4009
	  /* Fall through.  */
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
	case L_('T'):
Packit 6c4009
	  subfmt = L_("%H:%M:%S");
Packit 6c4009
	  goto subformat;
Packit 6c4009
Packit 6c4009
	case L_('t'):
Packit 6c4009
	  add (1, *p = L_('\t'));
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case L_('u'):
Packit 6c4009
	  DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
Packit 6c4009
Packit 6c4009
	case L_('U'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
Packit 6c4009
	  DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
Packit 6c4009
Packit 6c4009
	case L_('V'):
Packit 6c4009
	case L_('g'):
Packit 6c4009
	case L_('G'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
	  {
Packit 6c4009
	    int year = tp->tm_year + TM_YEAR_BASE;
Packit 6c4009
	    int days = iso_week_days (tp->tm_yday, tp->tm_wday);
Packit 6c4009
Packit 6c4009
	    if (days < 0)
Packit 6c4009
	      {
Packit 6c4009
		/* This ISO week belongs to the previous year.  */
Packit 6c4009
		year--;
Packit 6c4009
		days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
Packit 6c4009
				      tp->tm_wday);
Packit 6c4009
	      }
Packit 6c4009
	    else
Packit 6c4009
	      {
Packit 6c4009
		int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
Packit 6c4009
				       tp->tm_wday);
Packit 6c4009
		if (0 <= d)
Packit 6c4009
		  {
Packit 6c4009
		    /* This ISO week belongs to the next year.  */
Packit 6c4009
		    year++;
Packit 6c4009
		    days = d;
Packit 6c4009
		  }
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    switch (*f)
Packit 6c4009
	      {
Packit 6c4009
	      case L_('g'):
Packit 6c4009
		DO_NUMBER (2, (year % 100 + 100) % 100);
Packit 6c4009
Packit 6c4009
	      case L_('G'):
Packit 6c4009
		DO_NUMBER (1, year);
Packit 6c4009
Packit 6c4009
	      default:
Packit 6c4009
		DO_NUMBER (2, days / 7 + 1);
Packit 6c4009
	      }
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	case L_('W'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
Packit 6c4009
	  DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
Packit 6c4009
Packit 6c4009
	case L_('w'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
Packit 6c4009
	  DO_NUMBER (1, tp->tm_wday);
Packit 6c4009
Packit 6c4009
	case L_('Y'):
Packit 6c4009
	  if (modifier == 'E')
Packit 6c4009
	    {
Packit 6c4009
#if HAVE_STRUCT_ERA_ENTRY
Packit 6c4009
	      struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
Packit 6c4009
	      if (era)
Packit 6c4009
		{
Packit 6c4009
# ifdef COMPILE_WIDE
Packit 6c4009
		  subfmt = era->era_wformat;
Packit 6c4009
# else
Packit 6c4009
		  subfmt = era->era_format;
Packit 6c4009
# endif
Packit 6c4009
		  goto subformat;
Packit 6c4009
		}
Packit 6c4009
#else
Packit 6c4009
# if HAVE_STRFTIME
Packit 6c4009
	      goto underlying_strftime;
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
	    }
Packit 6c4009
	  if (modifier == L_('O'))
Packit 6c4009
	    goto bad_format;
Packit 6c4009
	  else
Packit 6c4009
	    DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
Packit 6c4009
Packit 6c4009
	case L_('y'):
Packit 6c4009
	  if (modifier == L_('E'))
Packit 6c4009
	    {
Packit 6c4009
#if HAVE_STRUCT_ERA_ENTRY
Packit 6c4009
	      struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
Packit 6c4009
	      if (era)
Packit 6c4009
		{
Packit 6c4009
		  int delta = tp->tm_year - era->start_date[0];
Packit 6c4009
		  DO_NUMBER (1, (era->offset
Packit 6c4009
				 + delta * era->absolute_direction));
Packit 6c4009
		}
Packit 6c4009
#else
Packit 6c4009
# if HAVE_STRFTIME
Packit 6c4009
	      goto underlying_strftime;
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
	    }
Packit 6c4009
	  DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
Packit 6c4009
Packit 6c4009
	case L_('Z'):
Packit 6c4009
	  if (change_case)
Packit 6c4009
	    {
Packit 6c4009
	      to_uppcase = 0;
Packit 6c4009
	      to_lowcase = 1;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
#if HAVE_TZNAME
Packit 6c4009
	  /* The tzset() call might have changed the value.  */
Packit 6c4009
	  if (!(zone && *zone) && tp->tm_isdst >= 0)
Packit 6c4009
	    {
Packit 6c4009
	      /* POSIX.1 requires that local time zone information is used as
Packit 6c4009
		 though strftime called tzset.  */
Packit 6c4009
# if HAVE_TZSET
Packit 6c4009
	      if (!*tzset_called)
Packit 6c4009
		{
Packit 6c4009
		  tzset ();
Packit 6c4009
		  *tzset_called = true;
Packit 6c4009
		}
Packit 6c4009
# endif
Packit 6c4009
	      zone = tp->tm_isdst <= 1 ? tzname[tp->tm_isdst] : "?";
Packit 6c4009
	    }
Packit 6c4009
#endif
Packit 6c4009
	  if (! zone)
Packit 6c4009
	    zone = "";
Packit 6c4009
Packit 6c4009
#ifdef COMPILE_WIDE
Packit 6c4009
	  {
Packit 6c4009
	    /* The zone string is always given in multibyte form.  We have
Packit 6c4009
	       to transform it first.  */
Packit 6c4009
	    wchar_t *wczone;
Packit 6c4009
	    size_t len;
Packit 6c4009
	    widen (zone, wczone, len);
Packit 6c4009
	    cpy (len, wczone);
Packit 6c4009
	  }
Packit 6c4009
#else
Packit 6c4009
	  cpy (strlen (zone), zone);
Packit 6c4009
#endif
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case L_('z'):
Packit 6c4009
	  if (tp->tm_isdst < 0)
Packit 6c4009
	    break;
Packit 6c4009
Packit 6c4009
	  {
Packit 6c4009
	    int diff;
Packit 6c4009
#if HAVE_TM_GMTOFF
Packit 6c4009
	    diff = tp->tm_gmtoff;
Packit 6c4009
#else
Packit 6c4009
	    if (ut)
Packit 6c4009
	      diff = 0;
Packit 6c4009
	    else
Packit 6c4009
	      {
Packit 6c4009
		struct tm gtm;
Packit 6c4009
		struct tm ltm;
Packit 6c4009
		time_t lt;
Packit 6c4009
Packit 6c4009
		/* POSIX.1 requires that local time zone information is used as
Packit 6c4009
		   though strftime called tzset.  */
Packit 6c4009
# if HAVE_TZSET
Packit 6c4009
		if (!*tzset_called)
Packit 6c4009
		  {
Packit 6c4009
		    tzset ();
Packit 6c4009
		    *tzset_called = true;
Packit 6c4009
		  }
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
		ltm = *tp;
Packit 6c4009
		lt = mktime (<m;;
Packit 6c4009
Packit 6c4009
		if (lt == (time_t) -1)
Packit 6c4009
		  {
Packit 6c4009
		    /* mktime returns -1 for errors, but -1 is also a
Packit 6c4009
		       valid time_t value.  Check whether an error really
Packit 6c4009
		       occurred.  */
Packit 6c4009
		    struct tm tm;
Packit 6c4009
Packit 6c4009
		    if (! __localtime_r (&lt, &tm)
Packit 6c4009
			|| ((ltm.tm_sec ^ tm.tm_sec)
Packit 6c4009
			    | (ltm.tm_min ^ tm.tm_min)
Packit 6c4009
			    | (ltm.tm_hour ^ tm.tm_hour)
Packit 6c4009
			    | (ltm.tm_mday ^ tm.tm_mday)
Packit 6c4009
			    | (ltm.tm_mon ^ tm.tm_mon)
Packit 6c4009
			    | (ltm.tm_year ^ tm.tm_year)))
Packit 6c4009
		      break;
Packit 6c4009
		  }
Packit 6c4009
Packit 6c4009
		if (! __gmtime_r (&lt, &gtm))
Packit 6c4009
		  break;
Packit 6c4009
Packit 6c4009
		diff = tm_diff (&ltm, >m;;
Packit 6c4009
	      }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	    if (diff < 0)
Packit 6c4009
	      {
Packit 6c4009
		add (1, *p = L_('-'));
Packit 6c4009
		diff = -diff;
Packit 6c4009
	      }
Packit 6c4009
	    else
Packit 6c4009
	      add (1, *p = L_('+'));
Packit 6c4009
Packit 6c4009
	    diff /= 60;
Packit 6c4009
	    DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	case L_('\0'):		/* GNU extension: % at end of format.  */
Packit 6c4009
	    --f;
Packit 6c4009
	    /* Fall through.  */
Packit 6c4009
	default:
Packit 6c4009
	  /* Unknown format; output the format, including the '%',
Packit 6c4009
	     since this is most likely the right thing to do if a
Packit 6c4009
	     multibyte string has been misparsed.  */
Packit 6c4009
	bad_format:
Packit 6c4009
	  {
Packit 6c4009
	    int flen;
Packit 6c4009
	    for (flen = 1; f[1 - flen] != L_('%'); flen++)
Packit 6c4009
	      continue;
Packit 6c4009
	    cpy (flen, &f[1 - flen]);
Packit 6c4009
	  }
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (p && maxsize != 0)
Packit 6c4009
    *p = L_('\0');
Packit 6c4009
  return i;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef emacs
Packit 6c4009
/* For Emacs we have a separate interface which corresponds to the normal
Packit 6c4009
   strftime function and does not have the extra information whether the
Packit 6c4009
   TP arguments comes from a `gmtime' call or not.  */
Packit 6c4009
size_t
Packit 6c4009
emacs_strftime (char *s, size_t maxsize, const char *format,
Packit 6c4009
		const struct tm *tp)
Packit 6c4009
{
Packit 6c4009
  return my_strftime (s, maxsize, format, tp, 0);
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if defined _LIBC && !defined COMPILE_WIDE
Packit 6c4009
weak_alias (__strftime_l, strftime_l)
Packit 6c4009
#endif