Blame time/strptime_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
#include <assert.h>
Packit 6c4009
#include <ctype.h>
Packit 6c4009
#include <langinfo.h>
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <time.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
# define HAVE_LOCALTIME_R 0
Packit 6c4009
# include "../locale/localeinfo.h"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
#if ! HAVE_LOCALTIME_R && ! defined localtime_r
Packit 6c4009
# ifdef _LIBC
Packit 6c4009
#  define localtime_r __localtime_r
Packit 6c4009
# else
Packit 6c4009
/* Approximate localtime_r as best we can in its absence.  */
Packit 6c4009
#  define localtime_r my_localtime_r
Packit 6c4009
static struct tm *localtime_r (const time_t *, struct tm *);
Packit 6c4009
static struct tm *
Packit 6c4009
localtime_r (const time_t *t, struct tm *tp)
Packit 6c4009
{
Packit 6c4009
  struct tm *l = localtime (t);
Packit 6c4009
  if (! l)
Packit 6c4009
    return 0;
Packit 6c4009
  *tp = *l;
Packit 6c4009
  return tp;
Packit 6c4009
}
Packit 6c4009
# endif /* ! _LIBC */
Packit 6c4009
#endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define match_char(ch1, ch2) if (ch1 != ch2) return NULL
Packit 6c4009
#if defined __GNUC__ && __GNUC__ >= 2
Packit 6c4009
# define match_string(cs1, s2) \
Packit 6c4009
  ({ size_t len = strlen (cs1);						      \
Packit 6c4009
     int result = __strncasecmp_l ((cs1), (s2), len, locale) == 0;	      \
Packit 6c4009
     if (result) (s2) += len;						      \
Packit 6c4009
     result; })
Packit 6c4009
#else
Packit 6c4009
/* Oh come on.  Get a reasonable compiler.  */
Packit 6c4009
# define match_string(cs1, s2) \
Packit 6c4009
  (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
Packit 6c4009
#endif
Packit 6c4009
/* We intentionally do not use isdigit() for testing because this will
Packit 6c4009
   lead to problems with the wide character version.  */
Packit 6c4009
#define get_number(from, to, n) \
Packit 6c4009
  do {									      \
Packit 6c4009
    int __n = n;							      \
Packit 6c4009
    val = 0;								      \
Packit 6c4009
    while (ISSPACE (*rp))						      \
Packit 6c4009
      ++rp;								      \
Packit 6c4009
    if (*rp < '0' || *rp > '9')						      \
Packit 6c4009
      return NULL;							      \
Packit 6c4009
    do {								      \
Packit 6c4009
      val *= 10;							      \
Packit 6c4009
      val += *rp++ - '0';						      \
Packit 6c4009
    } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9');	      \
Packit 6c4009
    if (val < from || val > to)						      \
Packit 6c4009
      return NULL;							      \
Packit 6c4009
  } while (0)
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
# define get_alt_number(from, to, n) \
Packit 6c4009
  ({									      \
Packit 6c4009
     __label__ do_normal;						      \
Packit 6c4009
									      \
Packit 6c4009
     if (s.decided != raw)						      \
Packit 6c4009
       {								      \
Packit 6c4009
	 val = _nl_parse_alt_digit (&rp HELPER_LOCALE_ARG);		      \
Packit 6c4009
	 if (val == -1 && s.decided != loc)				      \
Packit 6c4009
	   {								      \
Packit 6c4009
	     s.decided = loc;						      \
Packit 6c4009
	     goto do_normal;						      \
Packit 6c4009
	   }								      \
Packit 6c4009
	if (val < from || val > to)					      \
Packit 6c4009
	  return NULL;							      \
Packit 6c4009
       }								      \
Packit 6c4009
     else								      \
Packit 6c4009
       {								      \
Packit 6c4009
       do_normal:							      \
Packit 6c4009
	 get_number (from, to, n);					      \
Packit 6c4009
       }								      \
Packit 6c4009
    0;									      \
Packit 6c4009
  })
Packit 6c4009
#else
Packit 6c4009
# define get_alt_number(from, to, n) \
Packit 6c4009
  /* We don't have the alternate representation.  */			      \
Packit 6c4009
  get_number(from, to, n)
Packit 6c4009
#endif
Packit 6c4009
#define recursive(new_fmt) \
Packit 6c4009
  (*(new_fmt) != '\0'							      \
Packit 6c4009
   && (rp = __strptime_internal (rp, (new_fmt), tm, &s LOCALE_ARG)) != NULL)
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
/* This is defined in locale/C-time.c in the GNU libc.  */
Packit 6c4009
extern const struct __locale_data _nl_C_LC_TIME attribute_hidden;
Packit 6c4009
Packit 6c4009
# define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
Packit 6c4009
# define ab_weekday_name \
Packit 6c4009
  (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
Packit 6c4009
# define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
Packit 6c4009
# define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
Packit 6c4009
# define alt_month_name \
Packit 6c4009
  (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ALTMON_1)].string)
Packit 6c4009
# define ab_alt_month_name \
Packit 6c4009
  (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (_NL_ABALTMON_1)].string)
Packit 6c4009
# define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
Packit 6c4009
# define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
Packit 6c4009
# define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
Packit 6c4009
# define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
Packit 6c4009
# define HERE_T_FMT_AMPM \
Packit 6c4009
  (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
Packit 6c4009
# define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
Packit 6c4009
Packit 6c4009
# define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
Packit 6c4009
#else
Packit 6c4009
static char const weekday_name[][10] =
Packit 6c4009
  {
Packit 6c4009
    "Sunday", "Monday", "Tuesday", "Wednesday",
Packit 6c4009
    "Thursday", "Friday", "Saturday"
Packit 6c4009
  };
Packit 6c4009
static char const ab_weekday_name[][4] =
Packit 6c4009
  {
Packit 6c4009
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
Packit 6c4009
  };
Packit 6c4009
static char const month_name[][10] =
Packit 6c4009
  {
Packit 6c4009
    "January", "February", "March", "April", "May", "June",
Packit 6c4009
    "July", "August", "September", "October", "November", "December"
Packit 6c4009
  };
Packit 6c4009
static char const ab_month_name[][4] =
Packit 6c4009
  {
Packit 6c4009
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
Packit 6c4009
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
Packit 6c4009
  };
Packit 6c4009
# define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
Packit 6c4009
# define HERE_D_FMT "%m/%d/%y"
Packit 6c4009
# define HERE_AM_STR "AM"
Packit 6c4009
# define HERE_PM_STR "PM"
Packit 6c4009
# define HERE_T_FMT_AMPM "%I:%M:%S %p"
Packit 6c4009
# define HERE_T_FMT "%H:%M:%S"
Packit 6c4009
Packit 6c4009
static const unsigned short int __mon_yday[2][13] =
Packit 6c4009
  {
Packit 6c4009
    /* Normal years.  */
Packit 6c4009
    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
Packit 6c4009
    /* Leap years.  */
Packit 6c4009
    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
Packit 6c4009
  };
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if defined _LIBC
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 strptime		__strptime_l
Packit 6c4009
# undef _NL_CURRENT
Packit 6c4009
# define _NL_CURRENT(category, item) \
Packit 6c4009
  (current->values[_NL_ITEM_INDEX (item)].string)
Packit 6c4009
# undef _NL_CURRENT_WORD
Packit 6c4009
# define _NL_CURRENT_WORD(category, item) \
Packit 6c4009
  (current->values[_NL_ITEM_INDEX (item)].word)
Packit 6c4009
# define LOCALE_PARAM , locale_t locale
Packit 6c4009
# define LOCALE_ARG , locale
Packit 6c4009
# define HELPER_LOCALE_ARG , current
Packit 6c4009
# define ISSPACE(Ch) __isspace_l (Ch, locale)
Packit 6c4009
#else
Packit 6c4009
# define LOCALE_PARAM
Packit 6c4009
# define LOCALE_ARG
Packit 6c4009
# define HELPER_LOCALE_ARG
Packit 6c4009
# define ISSPACE(Ch) isspace (Ch)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
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
/* Compute the day of the week.  */
Packit 6c4009
static void
Packit 6c4009
day_of_the_week (struct tm *tm)
Packit 6c4009
{
Packit 6c4009
  /* We know that January 1st 1970 was a Thursday (= 4).  Compute the
Packit 6c4009
     difference between this data in the one on TM and so determine
Packit 6c4009
     the weekday.  */
Packit 6c4009
  int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
Packit 6c4009
  int wday = (-473
Packit 6c4009
	      + (365 * (tm->tm_year - 70))
Packit 6c4009
	      + (corr_year / 4)
Packit 6c4009
	      - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
Packit 6c4009
	      + (((corr_year / 4) / 25) / 4)
Packit 6c4009
	      + __mon_yday[0][tm->tm_mon]
Packit 6c4009
	      + tm->tm_mday - 1);
Packit 6c4009
  tm->tm_wday = ((wday % 7) + 7) % 7;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Compute the day of the year.  */
Packit 6c4009
static void
Packit 6c4009
day_of_the_year (struct tm *tm)
Packit 6c4009
{
Packit 6c4009
  tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
Packit 6c4009
		 + (tm->tm_mday - 1));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
char *
Packit 6c4009
#else
Packit 6c4009
static char *
Packit 6c4009
#endif
Packit 6c4009
__strptime_internal (const char *rp, const char *fmt, struct tm *tmp,
Packit 6c4009
		     void *statep LOCALE_PARAM)
Packit 6c4009
{
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
  struct __locale_data *const current = locale->__locales[LC_TIME];
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  const char *rp_backup;
Packit 6c4009
  const char *rp_longest;
Packit 6c4009
  int cnt;
Packit 6c4009
  int cnt_longest;
Packit 6c4009
  size_t val;
Packit 6c4009
  size_t num_eras;
Packit 6c4009
  struct era_entry *era = NULL;
Packit 6c4009
  enum ptime_locale_status { not, loc, raw } decided_longest;
Packit 6c4009
  struct __strptime_state
Packit 6c4009
  {
Packit 6c4009
    unsigned int have_I : 1;
Packit 6c4009
    unsigned int have_wday : 1;
Packit 6c4009
    unsigned int have_yday : 1;
Packit 6c4009
    unsigned int have_mon : 1;
Packit 6c4009
    unsigned int have_mday : 1;
Packit 6c4009
    unsigned int have_uweek : 1;
Packit 6c4009
    unsigned int have_wweek : 1;
Packit 6c4009
    unsigned int is_pm : 1;
Packit 6c4009
    unsigned int want_century : 1;
Packit 6c4009
    unsigned int want_era : 1;
Packit 6c4009
    unsigned int want_xday : 1;
Packit 6c4009
    enum ptime_locale_status decided : 2;
Packit 6c4009
    signed char week_no;
Packit 6c4009
    signed char century;
Packit 6c4009
    int era_cnt;
Packit 6c4009
  } s;
Packit 6c4009
  struct tm tmb;
Packit 6c4009
  struct tm *tm;
Packit 6c4009
Packit 6c4009
  if (statep == NULL)
Packit 6c4009
    {
Packit 6c4009
      memset (&s, 0, sizeof (s));
Packit 6c4009
      s.century = -1;
Packit 6c4009
      s.era_cnt = -1;
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
      s.decided = not;
Packit 6c4009
#else
Packit 6c4009
      s.decided = raw;
Packit 6c4009
#endif
Packit 6c4009
      tm = tmp;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      s = *(struct __strptime_state *) statep;
Packit 6c4009
      tmb = *tmp;
Packit 6c4009
      tm = &tm;;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  while (*fmt != '\0')
Packit 6c4009
    {
Packit 6c4009
      /* A white space in the format string matches 0 more or white
Packit 6c4009
	 space in the input string.  */
Packit 6c4009
      if (ISSPACE (*fmt))
Packit 6c4009
	{
Packit 6c4009
	  while (ISSPACE (*rp))
Packit 6c4009
	    ++rp;
Packit 6c4009
	  ++fmt;
Packit 6c4009
	  continue;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Any character but `%' must be matched by the same character
Packit 6c4009
	 in the iput string.  */
Packit 6c4009
      if (*fmt != '%')
Packit 6c4009
	{
Packit 6c4009
	  match_char (*fmt++, *rp++);
Packit 6c4009
	  continue;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      ++fmt;
Packit 6c4009
      /* We discard strftime modifiers.  */
Packit 6c4009
      while (*fmt == '-' || *fmt == '_' || *fmt == '0'
Packit 6c4009
	     || *fmt == '^' || *fmt == '#')
Packit 6c4009
	++fmt;
Packit 6c4009
Packit 6c4009
      /* And field width.  */
Packit 6c4009
      while (*fmt >= '0' && *fmt <= '9')
Packit 6c4009
	++fmt;
Packit 6c4009
Packit 6c4009
      /* In some cases, modifiers are handled by adjusting state and
Packit 6c4009
         then restarting the switch statement below.  */
Packit 6c4009
    start_over:
Packit 6c4009
Packit 6c4009
      /* Make back up of current processing pointer.  */
Packit 6c4009
      rp_backup = rp;
Packit 6c4009
Packit 6c4009
      switch (*fmt++)
Packit 6c4009
	{
Packit 6c4009
	case '%':
Packit 6c4009
	  /* Match the `%' character itself.  */
Packit 6c4009
	  match_char ('%', *rp++);
Packit 6c4009
	  break;
Packit 6c4009
	case 'a':
Packit 6c4009
	case 'A':
Packit 6c4009
	  /* Match day of week.  */
Packit 6c4009
	  rp_longest = NULL;
Packit 6c4009
	  decided_longest = s.decided;
Packit 6c4009
	  cnt_longest = -1;
Packit 6c4009
	  for (cnt = 0; cnt < 7; ++cnt)
Packit 6c4009
	    {
Packit 6c4009
	      const char *trp;
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
	      if (s.decided !=raw)
Packit 6c4009
		{
Packit 6c4009
		  trp = rp;
Packit 6c4009
		  if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), trp)
Packit 6c4009
		      && trp > rp_longest)
Packit 6c4009
		    {
Packit 6c4009
		      rp_longest = trp;
Packit 6c4009
		      cnt_longest = cnt;
Packit 6c4009
		      if (s.decided == not
Packit 6c4009
			  && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
Packit 6c4009
				     weekday_name[cnt]))
Packit 6c4009
			decided_longest = loc;
Packit 6c4009
		    }
Packit 6c4009
		  trp = rp;
Packit 6c4009
		  if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), trp)
Packit 6c4009
		      && trp > rp_longest)
Packit 6c4009
		    {
Packit 6c4009
		      rp_longest = trp;
Packit 6c4009
		      cnt_longest = cnt;
Packit 6c4009
		      if (s.decided == not
Packit 6c4009
			  && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
Packit 6c4009
				     ab_weekday_name[cnt]))
Packit 6c4009
			decided_longest = loc;
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
#endif
Packit 6c4009
	      if (s.decided != loc
Packit 6c4009
		  && (((trp = rp, match_string (weekday_name[cnt], trp))
Packit 6c4009
		       && trp > rp_longest)
Packit 6c4009
		      || ((trp = rp, match_string (ab_weekday_name[cnt], rp))
Packit 6c4009
			  && trp > rp_longest)))
Packit 6c4009
		{
Packit 6c4009
		  rp_longest = trp;
Packit 6c4009
		  cnt_longest = cnt;
Packit 6c4009
		  decided_longest = raw;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	  if (rp_longest == NULL)
Packit 6c4009
	    /* Does not match a weekday name.  */
Packit 6c4009
	    return NULL;
Packit 6c4009
	  rp = rp_longest;
Packit 6c4009
	  s.decided = decided_longest;
Packit 6c4009
	  tm->tm_wday = cnt_longest;
Packit 6c4009
	  s.have_wday = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'b':
Packit 6c4009
	case 'B':
Packit 6c4009
	case 'h':
Packit 6c4009
	  /* Match month name.  */
Packit 6c4009
	  rp_longest = NULL;
Packit 6c4009
	  decided_longest = s.decided;
Packit 6c4009
	  cnt_longest = -1;
Packit 6c4009
	  for (cnt = 0; cnt < 12; ++cnt)
Packit 6c4009
	    {
Packit 6c4009
	      const char *trp;
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
	      if (s.decided !=raw)
Packit 6c4009
		{
Packit 6c4009
		  trp = rp;
Packit 6c4009
		  if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), trp)
Packit 6c4009
		      && trp > rp_longest)
Packit 6c4009
		    {
Packit 6c4009
		      rp_longest = trp;
Packit 6c4009
		      cnt_longest = cnt;
Packit 6c4009
		      if (s.decided == not
Packit 6c4009
			  && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
Packit 6c4009
				     month_name[cnt]))
Packit 6c4009
			decided_longest = loc;
Packit 6c4009
		    }
Packit 6c4009
		  trp = rp;
Packit 6c4009
		  if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), trp)
Packit 6c4009
		      && trp > rp_longest)
Packit 6c4009
		    {
Packit 6c4009
		      rp_longest = trp;
Packit 6c4009
		      cnt_longest = cnt;
Packit 6c4009
		      if (s.decided == not
Packit 6c4009
			  && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
Packit 6c4009
				     ab_month_name[cnt]))
Packit 6c4009
			decided_longest = loc;
Packit 6c4009
		    }
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
		  /* Now check the alt month.  */
Packit 6c4009
		  trp = rp;
Packit 6c4009
		  if (match_string (_NL_CURRENT (LC_TIME, ALTMON_1 + cnt), trp)
Packit 6c4009
		      && trp > rp_longest)
Packit 6c4009
		    {
Packit 6c4009
		      rp_longest = trp;
Packit 6c4009
		      cnt_longest = cnt;
Packit 6c4009
		      if (s.decided == not
Packit 6c4009
			  && strcmp (_NL_CURRENT (LC_TIME, ALTMON_1 + cnt),
Packit 6c4009
				     alt_month_name[cnt]))
Packit 6c4009
			decided_longest = loc;
Packit 6c4009
		    }
Packit 6c4009
		  trp = rp;
Packit 6c4009
		  if (match_string (_NL_CURRENT (LC_TIME, _NL_ABALTMON_1 + cnt),
Packit 6c4009
				    trp)
Packit 6c4009
		      && trp > rp_longest)
Packit 6c4009
		    {
Packit 6c4009
		      rp_longest = trp;
Packit 6c4009
		      cnt_longest = cnt;
Packit 6c4009
		      if (s.decided == not
Packit 6c4009
			  && strcmp (_NL_CURRENT (LC_TIME, _NL_ABALTMON_1 + cnt),
Packit 6c4009
				     alt_month_name[cnt]))
Packit 6c4009
			decided_longest = loc;
Packit 6c4009
		    }
Packit 6c4009
#endif
Packit 6c4009
		}
Packit 6c4009
#endif
Packit 6c4009
	      if (s.decided != loc
Packit 6c4009
		  && (((trp = rp, match_string (month_name[cnt], trp))
Packit 6c4009
		       && trp > rp_longest)
Packit 6c4009
		      || ((trp = rp, match_string (ab_month_name[cnt], trp))
Packit 6c4009
			  && trp > rp_longest)
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
		      || ((trp = rp, match_string (alt_month_name[cnt], trp))
Packit 6c4009
			  && trp > rp_longest)
Packit 6c4009
		      || ((trp = rp, match_string (ab_alt_month_name[cnt], trp))
Packit 6c4009
			  && trp > rp_longest)
Packit 6c4009
#endif
Packit 6c4009
	      ))
Packit 6c4009
		{
Packit 6c4009
		  rp_longest = trp;
Packit 6c4009
		  cnt_longest = cnt;
Packit 6c4009
		  decided_longest = raw;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	  if (rp_longest == NULL)
Packit 6c4009
	    /* Does not match a month name.  */
Packit 6c4009
	    return NULL;
Packit 6c4009
	  rp = rp_longest;
Packit 6c4009
	  s.decided = decided_longest;
Packit 6c4009
	  tm->tm_mon = cnt_longest;
Packit 6c4009
	  s.have_mon = 1;
Packit 6c4009
	  s.want_xday = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'c':
Packit 6c4009
	  /* Match locale's date and time format.  */
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
	  if (s.decided != raw)
Packit 6c4009
	    {
Packit 6c4009
	      if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
Packit 6c4009
		{
Packit 6c4009
		  if (s.decided == loc)
Packit 6c4009
		    return NULL;
Packit 6c4009
		  else
Packit 6c4009
		    rp = rp_backup;
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  if (s.decided == not &&
Packit 6c4009
		      strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
Packit 6c4009
		    s.decided = loc;
Packit 6c4009
		  s.want_xday = 1;
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
	      s.decided = raw;
Packit 6c4009
	    }
Packit 6c4009
#endif
Packit 6c4009
	  if (!recursive (HERE_D_T_FMT))
Packit 6c4009
	    return NULL;
Packit 6c4009
	  s.want_xday = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'C':
Packit 6c4009
	  /* Match century number.  */
Packit 6c4009
	match_century:
Packit 6c4009
	  get_number (0, 99, 2);
Packit 6c4009
	  s.century = val;
Packit 6c4009
	  s.want_xday = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'd':
Packit 6c4009
	case 'e':
Packit 6c4009
	  /* Match day of month.  */
Packit 6c4009
	  get_number (1, 31, 2);
Packit 6c4009
	  tm->tm_mday = val;
Packit 6c4009
	  s.have_mday = 1;
Packit 6c4009
	  s.want_xday = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'F':
Packit 6c4009
	  if (!recursive ("%Y-%m-%d"))
Packit 6c4009
	    return NULL;
Packit 6c4009
	  s.want_xday = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'x':
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
	  if (s.decided != raw)
Packit 6c4009
	    {
Packit 6c4009
	      if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
Packit 6c4009
		{
Packit 6c4009
		  if (s.decided == loc)
Packit 6c4009
		    return NULL;
Packit 6c4009
		  else
Packit 6c4009
		    rp = rp_backup;
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  if (s.decided == not
Packit 6c4009
		      && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
Packit 6c4009
		    s.decided = loc;
Packit 6c4009
		  s.want_xday = 1;
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
	      s.decided = raw;
Packit 6c4009
	    }
Packit 6c4009
#endif
Packit 6c4009
	  /* Fall through.  */
Packit 6c4009
	case 'D':
Packit 6c4009
	  /* Match standard day format.  */
Packit 6c4009
	  if (!recursive (HERE_D_FMT))
Packit 6c4009
	    return NULL;
Packit 6c4009
	  s.want_xday = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'k':
Packit 6c4009
	case 'H':
Packit 6c4009
	  /* Match hour in 24-hour clock.  */
Packit 6c4009
	  get_number (0, 23, 2);
Packit 6c4009
	  tm->tm_hour = val;
Packit 6c4009
	  s.have_I = 0;
Packit 6c4009
	  break;
Packit 6c4009
	case 'l':
Packit 6c4009
	  /* Match hour in 12-hour clock.  GNU extension.  */
Packit 6c4009
	case 'I':
Packit 6c4009
	  /* Match hour in 12-hour clock.  */
Packit 6c4009
	  get_number (1, 12, 2);
Packit 6c4009
	  tm->tm_hour = val % 12;
Packit 6c4009
	  s.have_I = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'j':
Packit 6c4009
	  /* Match day number of year.  */
Packit 6c4009
	  get_number (1, 366, 3);
Packit 6c4009
	  tm->tm_yday = val - 1;
Packit 6c4009
	  s.have_yday = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'm':
Packit 6c4009
	  /* Match number of month.  */
Packit 6c4009
	  get_number (1, 12, 2);
Packit 6c4009
	  tm->tm_mon = val - 1;
Packit 6c4009
	  s.have_mon = 1;
Packit 6c4009
	  s.want_xday = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'M':
Packit 6c4009
	  /* Match minute.  */
Packit 6c4009
	  get_number (0, 59, 2);
Packit 6c4009
	  tm->tm_min = val;
Packit 6c4009
	  break;
Packit 6c4009
	case 'n':
Packit 6c4009
	case 't':
Packit 6c4009
	  /* Match any white space.  */
Packit 6c4009
	  while (ISSPACE (*rp))
Packit 6c4009
	    ++rp;
Packit 6c4009
	  break;
Packit 6c4009
	case 'p':
Packit 6c4009
	  /* Match locale's equivalent of AM/PM.  */
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
	  if (s.decided != raw)
Packit 6c4009
	    {
Packit 6c4009
	      if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
Packit 6c4009
		{
Packit 6c4009
		  if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
Packit 6c4009
		    s.decided = loc;
Packit 6c4009
		  s.is_pm = 0;
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
	      if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
Packit 6c4009
		{
Packit 6c4009
		  if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
Packit 6c4009
		    s.decided = loc;
Packit 6c4009
		  s.is_pm = 1;
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
	      s.decided = raw;
Packit 6c4009
	    }
Packit 6c4009
#endif
Packit 6c4009
	  if (!match_string (HERE_AM_STR, rp))
Packit 6c4009
	    {
Packit 6c4009
	      if (match_string (HERE_PM_STR, rp))
Packit 6c4009
		s.is_pm = 1;
Packit 6c4009
	      else
Packit 6c4009
		return NULL;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    s.is_pm = 0;
Packit 6c4009
	  break;
Packit 6c4009
	case 'r':
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
	  if (s.decided != raw)
Packit 6c4009
	    {
Packit 6c4009
	      if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
Packit 6c4009
		{
Packit 6c4009
		  if (s.decided == loc)
Packit 6c4009
		    return NULL;
Packit 6c4009
		  else
Packit 6c4009
		    rp = rp_backup;
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  if (s.decided == not &&
Packit 6c4009
		      strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
Packit 6c4009
			      HERE_T_FMT_AMPM))
Packit 6c4009
		    s.decided = loc;
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
	      s.decided = raw;
Packit 6c4009
	    }
Packit 6c4009
#endif
Packit 6c4009
	  if (!recursive (HERE_T_FMT_AMPM))
Packit 6c4009
	    return NULL;
Packit 6c4009
	  break;
Packit 6c4009
	case 'R':
Packit 6c4009
	  if (!recursive ("%H:%M"))
Packit 6c4009
	    return NULL;
Packit 6c4009
	  break;
Packit 6c4009
	case 's':
Packit 6c4009
	  {
Packit 6c4009
	    /* The number of seconds may be very high so we cannot use
Packit 6c4009
	       the `get_number' macro.  Instead read the number
Packit 6c4009
	       character for character and construct the result while
Packit 6c4009
	       doing this.  */
Packit 6c4009
	    time_t secs = 0;
Packit 6c4009
	    if (*rp < '0' || *rp > '9')
Packit 6c4009
	      /* We need at least one digit.  */
Packit 6c4009
	      return NULL;
Packit 6c4009
Packit 6c4009
	    do
Packit 6c4009
	      {
Packit 6c4009
		secs *= 10;
Packit 6c4009
		secs += *rp++ - '0';
Packit 6c4009
	      }
Packit 6c4009
	    while (*rp >= '0' && *rp <= '9');
Packit 6c4009
Packit 6c4009
	    if (localtime_r (&secs, tm) == NULL)
Packit 6c4009
	      /* Error in function.  */
Packit 6c4009
	      return NULL;
Packit 6c4009
	  }
Packit 6c4009
	  break;
Packit 6c4009
	case 'S':
Packit 6c4009
	  get_number (0, 61, 2);
Packit 6c4009
	  tm->tm_sec = val;
Packit 6c4009
	  break;
Packit 6c4009
	case 'X':
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
	  if (s.decided != raw)
Packit 6c4009
	    {
Packit 6c4009
	      if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
Packit 6c4009
		{
Packit 6c4009
		  if (s.decided == loc)
Packit 6c4009
		    return NULL;
Packit 6c4009
		  else
Packit 6c4009
		    rp = rp_backup;
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
Packit 6c4009
		    s.decided = loc;
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
	      s.decided = raw;
Packit 6c4009
	    }
Packit 6c4009
#endif
Packit 6c4009
	  /* Fall through.  */
Packit 6c4009
	case 'T':
Packit 6c4009
	  if (!recursive (HERE_T_FMT))
Packit 6c4009
	    return NULL;
Packit 6c4009
	  break;
Packit 6c4009
	case 'u':
Packit 6c4009
	  get_number (1, 7, 1);
Packit 6c4009
	  tm->tm_wday = val % 7;
Packit 6c4009
	  s.have_wday = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'g':
Packit 6c4009
	  get_number (0, 99, 2);
Packit 6c4009
	  /* XXX This cannot determine any field in TM.  */
Packit 6c4009
	  break;
Packit 6c4009
	case 'G':
Packit 6c4009
	  if (*rp < '0' || *rp > '9')
Packit 6c4009
	    return NULL;
Packit 6c4009
	  /* XXX Ignore the number since we would need some more
Packit 6c4009
	     information to compute a real date.  */
Packit 6c4009
	  do
Packit 6c4009
	    ++rp;
Packit 6c4009
	  while (*rp >= '0' && *rp <= '9');
Packit 6c4009
	  break;
Packit 6c4009
	case 'U':
Packit 6c4009
	  get_number (0, 53, 2);
Packit 6c4009
	  s.week_no = val;
Packit 6c4009
	  s.have_uweek = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'W':
Packit 6c4009
	  get_number (0, 53, 2);
Packit 6c4009
	  s.week_no = val;
Packit 6c4009
	  s.have_wweek = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'V':
Packit 6c4009
	  get_number (0, 53, 2);
Packit 6c4009
	  /* XXX This cannot determine any field in TM without some
Packit 6c4009
	     information.  */
Packit 6c4009
	  break;
Packit 6c4009
	case 'w':
Packit 6c4009
	  /* Match number of weekday.  */
Packit 6c4009
	  get_number (0, 6, 1);
Packit 6c4009
	  tm->tm_wday = val;
Packit 6c4009
	  s.have_wday = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'y':
Packit 6c4009
	match_year_in_century:
Packit 6c4009
	  /* Match year within century.  */
Packit 6c4009
	  get_number (0, 99, 2);
Packit 6c4009
	  /* The "Year 2000: The Millennium Rollover" paper suggests that
Packit 6c4009
	     values in the range 69-99 refer to the twentieth century.  */
Packit 6c4009
	  tm->tm_year = val >= 69 ? val : val + 100;
Packit 6c4009
	  /* Indicate that we want to use the century, if specified.  */
Packit 6c4009
	  s.want_century = 1;
Packit 6c4009
	  s.want_xday = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'Y':
Packit 6c4009
	  /* Match year including century number.  */
Packit 6c4009
	  get_number (0, 9999, 4);
Packit 6c4009
	  tm->tm_year = val - 1900;
Packit 6c4009
	  s.want_century = 0;
Packit 6c4009
	  s.want_xday = 1;
Packit 6c4009
	  break;
Packit 6c4009
	case 'Z':
Packit 6c4009
	  /* Read timezone but perform no conversion.  */
Packit 6c4009
	  while (ISSPACE (*rp))
Packit 6c4009
	    rp++;
Packit 6c4009
	  while (!ISSPACE (*rp) && *rp != '\0')
Packit 6c4009
	    rp++;
Packit 6c4009
	  break;
Packit 6c4009
	case 'z':
Packit 6c4009
	  /* We recognize four formats:
Packit 6c4009
	     1. Two digits specify hours.
Packit 6c4009
	     2. Four digits specify hours and minutes.
Packit 6c4009
	     3. Two digits, ':', and two digits specify hours and minutes.
Packit 6c4009
	     4. 'Z' is equivalent to +0000.  */
Packit 6c4009
	  {
Packit 6c4009
	    val = 0;
Packit 6c4009
	    while (ISSPACE (*rp))
Packit 6c4009
	      ++rp;
Packit 6c4009
	    if (*rp == 'Z')
Packit 6c4009
	      {
Packit 6c4009
		++rp;
Packit 6c4009
		tm->tm_gmtoff = 0;
Packit 6c4009
		break;
Packit 6c4009
	      }
Packit 6c4009
	    if (*rp != '+' && *rp != '-')
Packit 6c4009
	      return NULL;
Packit 6c4009
	    bool neg = *rp++ == '-';
Packit 6c4009
	    int n = 0;
Packit 6c4009
	    while (n < 4 && *rp >= '0' && *rp <= '9')
Packit 6c4009
	      {
Packit 6c4009
		val = val * 10 + *rp++ - '0';
Packit 6c4009
		++n;
Packit 6c4009
		if (*rp == ':' && n == 2 && isdigit (*(rp + 1)))
Packit 6c4009
		  ++rp;
Packit 6c4009
	      }
Packit 6c4009
	    if (n == 2)
Packit 6c4009
	      val *= 100;
Packit 6c4009
	    else if (n != 4)
Packit 6c4009
	      /* Only two or four digits recognized.  */
Packit 6c4009
	      return NULL;
Packit 6c4009
	    else if (val % 100 >= 60)
Packit 6c4009
	      /* Minutes valid range is 0 through 59.  */
Packit 6c4009
	      return NULL;
Packit 6c4009
	    tm->tm_gmtoff = (val / 100) * 3600 + (val % 100) * 60;
Packit 6c4009
	    if (neg)
Packit 6c4009
	      tm->tm_gmtoff = -tm->tm_gmtoff;
Packit 6c4009
	  }
Packit 6c4009
	  break;
Packit 6c4009
	case 'E':
Packit 6c4009
#ifdef _NL_CURRENT
Packit 6c4009
	  switch (*fmt++)
Packit 6c4009
	    {
Packit 6c4009
	    case 'c':
Packit 6c4009
	      /* Match locale's alternate date and time format.  */
Packit 6c4009
	      if (s.decided != raw)
Packit 6c4009
		{
Packit 6c4009
		  const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
Packit 6c4009
Packit 6c4009
		  if (*fmt == '\0')
Packit 6c4009
		    fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
Packit 6c4009
Packit 6c4009
		  if (!recursive (fmt))
Packit 6c4009
		    {
Packit 6c4009
		      if (s.decided == loc)
Packit 6c4009
			return NULL;
Packit 6c4009
		      else
Packit 6c4009
			rp = rp_backup;
Packit 6c4009
		    }
Packit 6c4009
		  else
Packit 6c4009
		    {
Packit 6c4009
		      if (strcmp (fmt, HERE_D_T_FMT))
Packit 6c4009
			s.decided = loc;
Packit 6c4009
		      s.want_xday = 1;
Packit 6c4009
		      break;
Packit 6c4009
		    }
Packit 6c4009
		  s.decided = raw;
Packit 6c4009
		}
Packit 6c4009
	      /* The C locale has no era information, so use the
Packit 6c4009
		 normal representation.  */
Packit 6c4009
	      if (!recursive (HERE_D_T_FMT))
Packit 6c4009
		return NULL;
Packit 6c4009
	      s.want_xday = 1;
Packit 6c4009
	      break;
Packit 6c4009
	    case 'C':
Packit 6c4009
	      if (s.decided != raw)
Packit 6c4009
		{
Packit 6c4009
		  if (s.era_cnt >= 0)
Packit 6c4009
		    {
Packit 6c4009
		      era = _nl_select_era_entry (s.era_cnt HELPER_LOCALE_ARG);
Packit 6c4009
		      if (era != NULL && match_string (era->era_name, rp))
Packit 6c4009
			{
Packit 6c4009
			  s.decided = loc;
Packit 6c4009
			  break;
Packit 6c4009
			}
Packit 6c4009
		      else
Packit 6c4009
			return NULL;
Packit 6c4009
		    }
Packit 6c4009
Packit 6c4009
		  num_eras = _NL_CURRENT_WORD (LC_TIME,
Packit 6c4009
					       _NL_TIME_ERA_NUM_ENTRIES);
Packit 6c4009
		  for (s.era_cnt = 0; s.era_cnt < (int) num_eras;
Packit 6c4009
		       ++s.era_cnt, rp = rp_backup)
Packit 6c4009
		    {
Packit 6c4009
		      era = _nl_select_era_entry (s.era_cnt
Packit 6c4009
						  HELPER_LOCALE_ARG);
Packit 6c4009
		      if (era != NULL && match_string (era->era_name, rp))
Packit 6c4009
			{
Packit 6c4009
			  s.decided = loc;
Packit 6c4009
			  break;
Packit 6c4009
			}
Packit 6c4009
		    }
Packit 6c4009
		  if (s.era_cnt != (int) num_eras)
Packit 6c4009
		    break;
Packit 6c4009
Packit 6c4009
		  s.era_cnt = -1;
Packit 6c4009
		  if (s.decided == loc)
Packit 6c4009
		    return NULL;
Packit 6c4009
Packit 6c4009
		  s.decided = raw;
Packit 6c4009
		}
Packit 6c4009
	      /* The C locale has no era information, so use the
Packit 6c4009
		 normal representation.  */
Packit 6c4009
	      goto match_century;
Packit 6c4009
 	    case 'y':
Packit 6c4009
	      if (s.decided != raw)
Packit 6c4009
		{
Packit 6c4009
		  get_number(0, 9999, 4);
Packit 6c4009
		  tm->tm_year = val;
Packit 6c4009
		  s.want_era = 1;
Packit 6c4009
		  s.want_xday = 1;
Packit 6c4009
		  s.want_century = 1;
Packit 6c4009
Packit 6c4009
		  if (s.era_cnt >= 0)
Packit 6c4009
		    {
Packit 6c4009
		      assert (s.decided == loc);
Packit 6c4009
Packit 6c4009
		      era = _nl_select_era_entry (s.era_cnt HELPER_LOCALE_ARG);
Packit 6c4009
		      bool match = false;
Packit 6c4009
		      if (era != NULL)
Packit 6c4009
			{
Packit 6c4009
			  int delta = ((tm->tm_year - era->offset)
Packit 6c4009
				       * era->absolute_direction);
Packit 6c4009
			  match = (delta >= 0
Packit 6c4009
				   && delta < (((int64_t) era->stop_date[0]
Packit 6c4009
						- (int64_t) era->start_date[0])
Packit 6c4009
					       * era->absolute_direction));
Packit 6c4009
			}
Packit 6c4009
		      if (! match)
Packit 6c4009
			return NULL;
Packit 6c4009
Packit 6c4009
		      break;
Packit 6c4009
		    }
Packit 6c4009
Packit 6c4009
		  num_eras = _NL_CURRENT_WORD (LC_TIME,
Packit 6c4009
					       _NL_TIME_ERA_NUM_ENTRIES);
Packit 6c4009
		  for (s.era_cnt = 0; s.era_cnt < (int) num_eras; ++s.era_cnt)
Packit 6c4009
		    {
Packit 6c4009
		      era = _nl_select_era_entry (s.era_cnt
Packit 6c4009
						  HELPER_LOCALE_ARG);
Packit 6c4009
		      if (era != NULL)
Packit 6c4009
			{
Packit 6c4009
			  int delta = ((tm->tm_year - era->offset)
Packit 6c4009
				       * era->absolute_direction);
Packit 6c4009
			  if (delta >= 0
Packit 6c4009
			      && delta < (((int64_t) era->stop_date[0]
Packit 6c4009
					   - (int64_t) era->start_date[0])
Packit 6c4009
					  * era->absolute_direction))
Packit 6c4009
			    {
Packit 6c4009
			      s.decided = loc;
Packit 6c4009
			      break;
Packit 6c4009
			    }
Packit 6c4009
			}
Packit 6c4009
		    }
Packit 6c4009
		  if (s.era_cnt != (int) num_eras)
Packit 6c4009
		    break;
Packit 6c4009
Packit 6c4009
		  s.era_cnt = -1;
Packit 6c4009
		  if (s.decided == loc)
Packit 6c4009
		    return NULL;
Packit 6c4009
Packit 6c4009
		  s.decided = raw;
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      goto match_year_in_century;
Packit 6c4009
	    case 'Y':
Packit 6c4009
	      if (s.decided != raw)
Packit 6c4009
		{
Packit 6c4009
		  num_eras = _NL_CURRENT_WORD (LC_TIME,
Packit 6c4009
					       _NL_TIME_ERA_NUM_ENTRIES);
Packit 6c4009
		  for (s.era_cnt = 0; s.era_cnt < (int) num_eras;
Packit 6c4009
		       ++s.era_cnt, rp = rp_backup)
Packit 6c4009
		    {
Packit 6c4009
		      era = _nl_select_era_entry (s.era_cnt HELPER_LOCALE_ARG);
Packit 6c4009
		      if (era != NULL && recursive (era->era_format))
Packit 6c4009
			break;
Packit 6c4009
		    }
Packit 6c4009
		  if (s.era_cnt == (int) num_eras)
Packit 6c4009
		    {
Packit 6c4009
		      s.era_cnt = -1;
Packit 6c4009
		      if (s.decided == loc)
Packit 6c4009
			return NULL;
Packit 6c4009
		      else
Packit 6c4009
			rp = rp_backup;
Packit 6c4009
		    }
Packit 6c4009
		  else
Packit 6c4009
		    {
Packit 6c4009
		      s.decided = loc;
Packit 6c4009
		      break;
Packit 6c4009
		    }
Packit 6c4009
Packit 6c4009
		  s.decided = raw;
Packit 6c4009
		}
Packit 6c4009
	      get_number (0, 9999, 4);
Packit 6c4009
	      tm->tm_year = val - 1900;
Packit 6c4009
	      s.want_century = 0;
Packit 6c4009
	      s.want_xday = 1;
Packit 6c4009
	      break;
Packit 6c4009
	    case 'x':
Packit 6c4009
	      if (s.decided != raw)
Packit 6c4009
		{
Packit 6c4009
		  const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
Packit 6c4009
Packit 6c4009
		  if (*fmt == '\0')
Packit 6c4009
		    fmt = _NL_CURRENT (LC_TIME, D_FMT);
Packit 6c4009
Packit 6c4009
		  if (!recursive (fmt))
Packit 6c4009
		    {
Packit 6c4009
		      if (s.decided == loc)
Packit 6c4009
			return NULL;
Packit 6c4009
		      else
Packit 6c4009
			rp = rp_backup;
Packit 6c4009
		    }
Packit 6c4009
		  else
Packit 6c4009
		    {
Packit 6c4009
		      if (strcmp (fmt, HERE_D_FMT))
Packit 6c4009
			s.decided = loc;
Packit 6c4009
		      break;
Packit 6c4009
		    }
Packit 6c4009
		  s.decided = raw;
Packit 6c4009
		}
Packit 6c4009
	      if (!recursive (HERE_D_FMT))
Packit 6c4009
		return NULL;
Packit 6c4009
	      break;
Packit 6c4009
	    case 'X':
Packit 6c4009
	      if (s.decided != raw)
Packit 6c4009
		{
Packit 6c4009
		  const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
Packit 6c4009
Packit 6c4009
		  if (*fmt == '\0')
Packit 6c4009
		    fmt = _NL_CURRENT (LC_TIME, T_FMT);
Packit 6c4009
Packit 6c4009
		  if (!recursive (fmt))
Packit 6c4009
		    {
Packit 6c4009
		      if (s.decided == loc)
Packit 6c4009
			return NULL;
Packit 6c4009
		      else
Packit 6c4009
			rp = rp_backup;
Packit 6c4009
		    }
Packit 6c4009
		  else
Packit 6c4009
		    {
Packit 6c4009
		      if (strcmp (fmt, HERE_T_FMT))
Packit 6c4009
			s.decided = loc;
Packit 6c4009
		      break;
Packit 6c4009
		    }
Packit 6c4009
		  s.decided = raw;
Packit 6c4009
		}
Packit 6c4009
	      if (!recursive (HERE_T_FMT))
Packit 6c4009
		return NULL;
Packit 6c4009
	      break;
Packit 6c4009
	    default:
Packit 6c4009
	      return NULL;
Packit 6c4009
	    }
Packit 6c4009
	  break;
Packit 6c4009
#else
Packit 6c4009
	  /* We have no information about the era format.  Just use
Packit 6c4009
	     the normal format.  */
Packit 6c4009
	  if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
Packit 6c4009
	      && *fmt != 'x' && *fmt != 'X')
Packit 6c4009
	    /* This is an illegal format.  */
Packit 6c4009
	    return NULL;
Packit 6c4009
Packit 6c4009
	  goto start_over;
Packit 6c4009
#endif
Packit 6c4009
	case 'O':
Packit 6c4009
	  switch (*fmt++)
Packit 6c4009
	    {
Packit 6c4009
	    case 'b':
Packit 6c4009
	    case 'B':
Packit 6c4009
	    case 'h':
Packit 6c4009
	      /* Match month name.  Reprocess as plain 'B'.  */
Packit 6c4009
	      fmt--;
Packit 6c4009
	      goto start_over;
Packit 6c4009
	    case 'd':
Packit 6c4009
	    case 'e':
Packit 6c4009
	      /* Match day of month using alternate numeric symbols.  */
Packit 6c4009
	      get_alt_number (1, 31, 2);
Packit 6c4009
	      tm->tm_mday = val;
Packit 6c4009
	      s.have_mday = 1;
Packit 6c4009
	      s.want_xday = 1;
Packit 6c4009
	      break;
Packit 6c4009
	    case 'H':
Packit 6c4009
	      /* Match hour in 24-hour clock using alternate numeric
Packit 6c4009
		 symbols.  */
Packit 6c4009
	      get_alt_number (0, 23, 2);
Packit 6c4009
	      tm->tm_hour = val;
Packit 6c4009
	      s.have_I = 0;
Packit 6c4009
	      break;
Packit 6c4009
	    case 'I':
Packit 6c4009
	      /* Match hour in 12-hour clock using alternate numeric
Packit 6c4009
		 symbols.  */
Packit 6c4009
	      get_alt_number (1, 12, 2);
Packit 6c4009
	      tm->tm_hour = val % 12;
Packit 6c4009
	      s.have_I = 1;
Packit 6c4009
	      break;
Packit 6c4009
	    case 'm':
Packit 6c4009
	      /* Match month using alternate numeric symbols.  */
Packit 6c4009
	      get_alt_number (1, 12, 2);
Packit 6c4009
	      tm->tm_mon = val - 1;
Packit 6c4009
	      s.have_mon = 1;
Packit 6c4009
	      s.want_xday = 1;
Packit 6c4009
	      break;
Packit 6c4009
	    case 'M':
Packit 6c4009
	      /* Match minutes using alternate numeric symbols.  */
Packit 6c4009
	      get_alt_number (0, 59, 2);
Packit 6c4009
	      tm->tm_min = val;
Packit 6c4009
	      break;
Packit 6c4009
	    case 'S':
Packit 6c4009
	      /* Match seconds using alternate numeric symbols.  */
Packit 6c4009
	      get_alt_number (0, 61, 2);
Packit 6c4009
	      tm->tm_sec = val;
Packit 6c4009
	      break;
Packit 6c4009
	    case 'U':
Packit 6c4009
	      get_alt_number (0, 53, 2);
Packit 6c4009
	      s.week_no = val;
Packit 6c4009
	      s.have_uweek = 1;
Packit 6c4009
	      break;
Packit 6c4009
	    case 'W':
Packit 6c4009
	      get_alt_number (0, 53, 2);
Packit 6c4009
	      s.week_no = val;
Packit 6c4009
	      s.have_wweek = 1;
Packit 6c4009
	      break;
Packit 6c4009
	    case 'V':
Packit 6c4009
	      get_alt_number (0, 53, 2);
Packit 6c4009
	      /* XXX This cannot determine any field in TM without
Packit 6c4009
		 further information.  */
Packit 6c4009
	      break;
Packit 6c4009
	    case 'w':
Packit 6c4009
	      /* Match number of weekday using alternate numeric symbols.  */
Packit 6c4009
	      get_alt_number (0, 6, 1);
Packit 6c4009
	      tm->tm_wday = val;
Packit 6c4009
	      s.have_wday = 1;
Packit 6c4009
	      break;
Packit 6c4009
	    case 'y':
Packit 6c4009
	      /* Match year within century using alternate numeric symbols.  */
Packit 6c4009
	      get_alt_number (0, 99, 2);
Packit 6c4009
	      tm->tm_year = val >= 69 ? val : val + 100;
Packit 6c4009
	      s.want_xday = 1;
Packit 6c4009
	      break;
Packit 6c4009
	    default:
Packit 6c4009
	      return NULL;
Packit 6c4009
	    }
Packit 6c4009
	  break;
Packit 6c4009
	default:
Packit 6c4009
	  return NULL;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (statep != NULL)
Packit 6c4009
    {
Packit 6c4009
      /* Recursive invocation, returning success, so
Packit 6c4009
	 update parent's struct tm and state.  */
Packit 6c4009
      *(struct __strptime_state *) statep = s;
Packit 6c4009
      *tmp = tmb;
Packit 6c4009
      return (char *) rp;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (s.have_I && s.is_pm)
Packit 6c4009
    tm->tm_hour += 12;
Packit 6c4009
Packit 6c4009
  if (s.century != -1)
Packit 6c4009
    {
Packit 6c4009
      if (s.want_century)
Packit 6c4009
	tm->tm_year = tm->tm_year % 100 + (s.century - 19) * 100;
Packit 6c4009
      else
Packit 6c4009
	/* Only the century, but not the year.  Strange, but so be it.  */
Packit 6c4009
	tm->tm_year = (s.century - 19) * 100;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (s.era_cnt != -1)
Packit 6c4009
    {
Packit 6c4009
      era = _nl_select_era_entry (s.era_cnt HELPER_LOCALE_ARG);
Packit 6c4009
      if (era == NULL)
Packit 6c4009
	return NULL;
Packit 6c4009
      if (s.want_era)
Packit 6c4009
	tm->tm_year = (era->start_date[0]
Packit 6c4009
		       + ((tm->tm_year - era->offset)
Packit 6c4009
			  * era->absolute_direction));
Packit 6c4009
      else
Packit 6c4009
	/* Era start year assumed.  */
Packit 6c4009
	tm->tm_year = era->start_date[0];
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    if (s.want_era)
Packit 6c4009
      {
Packit 6c4009
	/* No era found but we have seen an E modifier.  Rectify some
Packit 6c4009
	   values.  */
Packit 6c4009
	if (s.want_century && s.century == -1 && tm->tm_year < 69)
Packit 6c4009
	  tm->tm_year += 100;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  if (s.want_xday && !s.have_wday)
Packit 6c4009
    {
Packit 6c4009
      if ( !(s.have_mon && s.have_mday) && s.have_yday)
Packit 6c4009
	{
Packit 6c4009
	  /* We don't have tm_mon and/or tm_mday, compute them.  */
Packit 6c4009
	  int t_mon = 0;
Packit 6c4009
	  while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
Packit 6c4009
	      t_mon++;
Packit 6c4009
	  if (!s.have_mon)
Packit 6c4009
	      tm->tm_mon = t_mon - 1;
Packit 6c4009
	  if (!s.have_mday)
Packit 6c4009
	      tm->tm_mday =
Packit 6c4009
		(tm->tm_yday
Packit 6c4009
		 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
Packit 6c4009
	  s.have_mon = 1;
Packit 6c4009
	  s.have_mday = 1;
Packit 6c4009
	}
Packit 6c4009
      /* Don't crash in day_of_the_week if tm_mon is uninitialized.  */
Packit 6c4009
      if (s.have_mon || (unsigned) tm->tm_mon <= 11)
Packit 6c4009
	day_of_the_week (tm);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (s.want_xday && !s.have_yday && (s.have_mon || (unsigned) tm->tm_mon <= 11))
Packit 6c4009
    day_of_the_year (tm);
Packit 6c4009
Packit 6c4009
  if ((s.have_uweek || s.have_wweek) && s.have_wday)
Packit 6c4009
    {
Packit 6c4009
      int save_wday = tm->tm_wday;
Packit 6c4009
      int save_mday = tm->tm_mday;
Packit 6c4009
      int save_mon = tm->tm_mon;
Packit 6c4009
      int w_offset = s.have_uweek ? 0 : 1;
Packit 6c4009
Packit 6c4009
      tm->tm_mday = 1;
Packit 6c4009
      tm->tm_mon = 0;
Packit 6c4009
      day_of_the_week (tm);
Packit 6c4009
      if (s.have_mday)
Packit 6c4009
	tm->tm_mday = save_mday;
Packit 6c4009
      if (s.have_mon)
Packit 6c4009
	tm->tm_mon = save_mon;
Packit 6c4009
Packit 6c4009
      if (!s.have_yday)
Packit 6c4009
	tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7
Packit 6c4009
		       + (s.week_no - 1) * 7
Packit 6c4009
		       + (save_wday - w_offset + 7) % 7);
Packit 6c4009
Packit 6c4009
      if (!s.have_mday || !s.have_mon)
Packit 6c4009
	{
Packit 6c4009
	  int t_mon = 0;
Packit 6c4009
	  while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon]
Packit 6c4009
		 <= tm->tm_yday)
Packit 6c4009
	    t_mon++;
Packit 6c4009
	  if (!s.have_mon)
Packit 6c4009
	    tm->tm_mon = t_mon - 1;
Packit 6c4009
	  if (!s.have_mday)
Packit 6c4009
	      tm->tm_mday =
Packit 6c4009
		(tm->tm_yday
Packit 6c4009
		 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      tm->tm_wday = save_wday;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return (char *) rp;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
char *
Packit 6c4009
strptime (const char *buf, const char *format, struct tm *tm LOCALE_PARAM)
Packit 6c4009
{
Packit 6c4009
  return __strptime_internal (buf, format, tm, NULL LOCALE_ARG);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
weak_alias (__strptime_l, strptime_l)
Packit 6c4009
#endif