Blame locale/programs/ld-time.c

Packit 6c4009
/* Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@gnu.org>, 1995.
Packit 6c4009
Packit 6c4009
   This program is free software; you can redistribute it and/or modify
Packit 6c4009
   it under the terms of the GNU General Public License as published
Packit 6c4009
   by the Free Software Foundation; version 2 of the License, or
Packit 6c4009
   (at your option) any later version.
Packit 6c4009
Packit 6c4009
   This program 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
Packit 6c4009
   GNU General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU General Public License
Packit 6c4009
   along with this program; if not, see <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 <byteswap.h>
Packit 6c4009
#include <langinfo.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <wchar.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <sys/uio.h>
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
Packit 6c4009
#include "localedef.h"
Packit 6c4009
#include "linereader.h"
Packit 6c4009
#include "localeinfo.h"
Packit 6c4009
#include "locfile.h"
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Entry describing an entry of the era specification.  */
Packit 6c4009
struct era_data
Packit 6c4009
{
Packit 6c4009
  int32_t direction;
Packit 6c4009
  int32_t offset;
Packit 6c4009
  int32_t start_date[3];
Packit 6c4009
  int32_t stop_date[3];
Packit 6c4009
  const char *name;
Packit 6c4009
  const char *format;
Packit 6c4009
  uint32_t *wname;
Packit 6c4009
  uint32_t *wformat;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* The real definition of the struct for the LC_TIME locale.  */
Packit 6c4009
struct locale_time_t
Packit 6c4009
{
Packit 6c4009
  const char *abday[7];
Packit 6c4009
  const uint32_t *wabday[7];
Packit 6c4009
  int abday_defined;
Packit 6c4009
  const char *day[7];
Packit 6c4009
  const uint32_t *wday[7];
Packit 6c4009
  int day_defined;
Packit 6c4009
  const char *abmon[12];
Packit 6c4009
  const uint32_t *wabmon[12];
Packit 6c4009
  int abmon_defined;
Packit 6c4009
  const char *mon[12];
Packit 6c4009
  const uint32_t *wmon[12];
Packit 6c4009
  int mon_defined;
Packit 6c4009
  const char *am_pm[2];
Packit 6c4009
  const uint32_t *wam_pm[2];
Packit 6c4009
  int am_pm_defined;
Packit 6c4009
  const char *d_t_fmt;
Packit 6c4009
  const uint32_t *wd_t_fmt;
Packit 6c4009
  const char *d_fmt;
Packit 6c4009
  const uint32_t *wd_fmt;
Packit 6c4009
  const char *t_fmt;
Packit 6c4009
  const uint32_t *wt_fmt;
Packit 6c4009
  const char *t_fmt_ampm;
Packit 6c4009
  const uint32_t *wt_fmt_ampm;
Packit 6c4009
  const char **era;
Packit 6c4009
  const uint32_t **wera;
Packit 6c4009
  uint32_t num_era;
Packit 6c4009
  const char *era_year;
Packit 6c4009
  const uint32_t *wera_year;
Packit 6c4009
  const char *era_d_t_fmt;
Packit 6c4009
  const uint32_t *wera_d_t_fmt;
Packit 6c4009
  const char *era_t_fmt;
Packit 6c4009
  const uint32_t *wera_t_fmt;
Packit 6c4009
  const char *era_d_fmt;
Packit 6c4009
  const uint32_t *wera_d_fmt;
Packit 6c4009
  const char *alt_digits[100];
Packit 6c4009
  const uint32_t *walt_digits[100];
Packit 6c4009
  const char *date_fmt;
Packit 6c4009
  const uint32_t *wdate_fmt;
Packit 6c4009
  int alt_digits_defined;
Packit 6c4009
  const char *alt_mon[12];
Packit 6c4009
  const uint32_t *walt_mon[12];
Packit 6c4009
  int alt_mon_defined;
Packit 6c4009
  const char *ab_alt_mon[12];
Packit 6c4009
  const uint32_t *wab_alt_mon[12];
Packit 6c4009
  int ab_alt_mon_defined;
Packit 6c4009
  unsigned char week_ndays;
Packit 6c4009
  uint32_t week_1stday;
Packit 6c4009
  unsigned char week_1stweek;
Packit 6c4009
  unsigned char first_weekday;
Packit 6c4009
  unsigned char first_workday;
Packit 6c4009
  unsigned char cal_direction;
Packit 6c4009
  const char *timezone;
Packit 6c4009
  const uint32_t *wtimezone;
Packit 6c4009
Packit 6c4009
  struct era_data *era_entries;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* This constant is used to represent an empty wide character string.  */
Packit 6c4009
static const uint32_t empty_wstr[1] = { 0 };
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
time_startup (struct linereader *lr, struct localedef_t *locale,
Packit 6c4009
	      int ignore_content)
Packit 6c4009
{
Packit 6c4009
  if (!ignore_content)
Packit 6c4009
    locale->categories[LC_TIME].time =
Packit 6c4009
      (struct locale_time_t *) xcalloc (1, sizeof (struct locale_time_t));
Packit 6c4009
Packit 6c4009
  if (lr != NULL)
Packit 6c4009
    {
Packit 6c4009
      lr->translate_strings = 1;
Packit 6c4009
      lr->return_widestr = 1;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
time_finish (struct localedef_t *locale, const struct charmap_t *charmap)
Packit 6c4009
{
Packit 6c4009
  struct locale_time_t *time = locale->categories[LC_TIME].time;
Packit 6c4009
  int nothing = 0;
Packit 6c4009
Packit 6c4009
  /* Now resolve copying and also handle completely missing definitions.  */
Packit 6c4009
  if (time == NULL)
Packit 6c4009
    {
Packit 6c4009
      /* First see whether we were supposed to copy.  If yes, find the
Packit 6c4009
	 actual definition.  */
Packit 6c4009
      if (locale->copy_name[LC_TIME] != NULL)
Packit 6c4009
	{
Packit 6c4009
	  /* Find the copying locale.  This has to happen transitively since
Packit 6c4009
	     the locale we are copying from might also copying another one.  */
Packit 6c4009
	  struct localedef_t *from = locale;
Packit 6c4009
Packit 6c4009
	  do
Packit 6c4009
	    from = find_locale (LC_TIME, from->copy_name[LC_TIME],
Packit 6c4009
				from->repertoire_name, charmap);
Packit 6c4009
	  while (from->categories[LC_TIME].time == NULL
Packit 6c4009
		 && from->copy_name[LC_TIME] != NULL);
Packit 6c4009
Packit 6c4009
	  time = locale->categories[LC_TIME].time
Packit 6c4009
	    = from->categories[LC_TIME].time;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* If there is still no definition issue an warning and create an
Packit 6c4009
	 empty one.  */
Packit 6c4009
      if (time == NULL)
Packit 6c4009
	{
Packit 6c4009
	  record_warning (_("\
Packit 6c4009
No definition for %s category found"), "LC_TIME");
Packit 6c4009
	  time_startup (NULL, locale, 0);
Packit 6c4009
	  time = locale->categories[LC_TIME].time;
Packit 6c4009
	  nothing = 1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#define noparen(arg1, argn...) arg1, ##argn
Packit 6c4009
#define TESTARR_ELEM(cat, val) \
Packit 6c4009
  if (!time->cat##_defined)						      \
Packit 6c4009
    {									      \
Packit 6c4009
      const char *initval[] = { noparen val };				      \
Packit 6c4009
      unsigned int i;							      \
Packit 6c4009
									      \
Packit 6c4009
      if (! nothing)					    		      \
Packit 6c4009
	record_error (0, 0, _("%s: field `%s' not defined"),	      	      \
Packit 6c4009
		      "LC_TIME", #cat);          			      \
Packit 6c4009
									      \
Packit 6c4009
      for (i = 0; i < sizeof (initval) / sizeof (initval[0]); ++i)	      \
Packit 6c4009
	time->cat[i] = initval[i];					      \
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  TESTARR_ELEM (abday, ( "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ));
Packit 6c4009
  TESTARR_ELEM (day, ( "Sunday", "Monday", "Tuesday", "Wednesday",
Packit 6c4009
		        "Thursday", "Friday", "Saturday" ));
Packit 6c4009
  TESTARR_ELEM (abmon, ( "Jan", "Feb", "Mar", "Apr", "May", "Jun",
Packit 6c4009
			  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ));
Packit 6c4009
  TESTARR_ELEM (mon, ( "January", "February", "March", "April",
Packit 6c4009
			"May", "June", "July", "August",
Packit 6c4009
			"September", "October", "November", "December" ));
Packit 6c4009
  TESTARR_ELEM (am_pm, ( "AM", "PM" ));
Packit 6c4009
Packit 6c4009
#define TEST_ELEM(cat, initval) \
Packit 6c4009
  if (time->cat == NULL)						      \
Packit 6c4009
    {									      \
Packit 6c4009
      if (! nothing)							      \
Packit 6c4009
	record_error (0, 0, _("%s: field `%s' not defined"),		      \
Packit 6c4009
		      "LC_TIME", #cat);          			      \
Packit 6c4009
									      \
Packit 6c4009
      time->cat = initval;						      \
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  TEST_ELEM (d_t_fmt, "%a %b %e %H:%M:%S %Y");
Packit 6c4009
  TEST_ELEM (d_fmt, "%m/%d/%y");
Packit 6c4009
  TEST_ELEM (t_fmt, "%H:%M:%S");
Packit 6c4009
Packit 6c4009
  /* According to C.Y.Alexis Cheng <alexis@vnet.ibm.com> the T_FMT_AMPM
Packit 6c4009
     field is optional.  */
Packit 6c4009
  if (time->t_fmt_ampm == NULL)
Packit 6c4009
    {
Packit 6c4009
      if (time->am_pm[0][0] == '\0' && time->am_pm[1][0] == '\0')
Packit 6c4009
	{
Packit 6c4009
	  /* No AM/PM strings defined, use the 24h format as default.  */
Packit 6c4009
	  time->t_fmt_ampm = time->t_fmt;
Packit 6c4009
	  time->wt_fmt_ampm = time->wt_fmt;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  time->t_fmt_ampm = "%I:%M:%S %p";
Packit 6c4009
	  time->wt_fmt_ampm = (const uint32_t *) L"%I:%M:%S %p";
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Now process the era entries.  */
Packit 6c4009
  if (time->num_era != 0)
Packit 6c4009
    {
Packit 6c4009
      const int days_per_month[12] = { 31, 29, 31, 30, 31, 30,
Packit 6c4009
				       31, 31, 30, 31 ,30, 31 };
Packit 6c4009
      size_t idx;
Packit 6c4009
      wchar_t *wstr;
Packit 6c4009
Packit 6c4009
      time->era_entries =
Packit 6c4009
	(struct era_data *) xmalloc (time->num_era
Packit 6c4009
				     * sizeof (struct era_data));
Packit 6c4009
Packit 6c4009
      for (idx = 0; idx < time->num_era; ++idx)
Packit 6c4009
	{
Packit 6c4009
	  size_t era_len = strlen (time->era[idx]);
Packit 6c4009
	  char *str = xmalloc ((era_len + 1 + 3) & ~3);
Packit 6c4009
	  char *endp;
Packit 6c4009
Packit 6c4009
	  memcpy (str, time->era[idx], era_len + 1);
Packit 6c4009
Packit 6c4009
	  /* First character must be + or - for the direction.  */
Packit 6c4009
	  if (*str != '+' && *str != '-')
Packit 6c4009
	    {
Packit 6c4009
	      record_error (0, 0, _("\
Packit 6c4009
%s: direction flag in string %Zd in `era' field is not '+' nor '-'"),
Packit 6c4009
			    "LC_TIME", idx + 1);
Packit 6c4009
	      /* Default arbitrarily to '+'.  */
Packit 6c4009
	      time->era_entries[idx].direction = '+';
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    time->era_entries[idx].direction = *str;
Packit 6c4009
	  if (*++str != ':')
Packit 6c4009
	    {
Packit 6c4009
	      record_error (0, 0, _("\
Packit 6c4009
%s: direction flag in string %Zd in `era' field is not a single character"),
Packit 6c4009
			    "LC_TIME", idx + 1);
Packit 6c4009
	      (void) strsep (&str, ":");
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    ++str;
Packit 6c4009
Packit 6c4009
	  /* Now the offset year.  */
Packit 6c4009
	  time->era_entries[idx].offset = strtol (str, &endp, 10);
Packit 6c4009
	  if (endp == str)
Packit 6c4009
	    {
Packit 6c4009
	      record_error (0, 0, _("\
Packit 6c4009
%s: invalid number for offset in string %Zd in `era' field"),
Packit 6c4009
			    "LC_TIME", idx + 1);
Packit 6c4009
	      (void) strsep (&str, ":");
Packit 6c4009
	    }
Packit 6c4009
	  else if (*endp != ':')
Packit 6c4009
	    {
Packit 6c4009
	      record_error (0, 0, _("\
Packit 6c4009
%s: garbage at end of offset value in string %Zd in `era' field"),
Packit 6c4009
			    "LC_TIME", idx + 1);
Packit 6c4009
	      (void) strsep (&str, ":");
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    str = endp + 1;
Packit 6c4009
Packit 6c4009
	  /* Next is the starting date in ISO format.  */
Packit 6c4009
	  if (strncmp (str, "-*", 2) == 0)
Packit 6c4009
	    {
Packit 6c4009
	      time->era_entries[idx].start_date[0] =
Packit 6c4009
		time->era_entries[idx].start_date[1] =
Packit 6c4009
		time->era_entries[idx].start_date[2] = 0x80000000;
Packit 6c4009
	      if (str[2] != ':')
Packit 6c4009
		goto garbage_start_date;
Packit 6c4009
	      str += 3;
Packit 6c4009
	    }
Packit 6c4009
	  else if (strncmp (str, "+*", 2) == 0)
Packit 6c4009
	    {
Packit 6c4009
	      time->era_entries[idx].start_date[0] =
Packit 6c4009
		time->era_entries[idx].start_date[1] =
Packit 6c4009
		time->era_entries[idx].start_date[2] = 0x7fffffff;
Packit 6c4009
	      if (str[2] != ':')
Packit 6c4009
		goto garbage_start_date;
Packit 6c4009
	      str += 3;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      time->era_entries[idx].start_date[0] = strtol (str, &endp, 10);
Packit 6c4009
	      if (endp == str || *endp != '/')
Packit 6c4009
		goto invalid_start_date;
Packit 6c4009
	      else
Packit 6c4009
		str = endp + 1;
Packit 6c4009
	      time->era_entries[idx].start_date[0] -= 1900;
Packit 6c4009
	      /* year -1 represent 1 B.C. (not -1 A.D.) */
Packit 6c4009
	      if (time->era_entries[idx].start_date[0] < -1900)
Packit 6c4009
		++time->era_entries[idx].start_date[0];
Packit 6c4009
Packit 6c4009
	      time->era_entries[idx].start_date[1] = strtol (str, &endp, 10);
Packit 6c4009
	      if (endp == str || *endp != '/')
Packit 6c4009
		goto invalid_start_date;
Packit 6c4009
	      else
Packit 6c4009
		str = endp + 1;
Packit 6c4009
	      time->era_entries[idx].start_date[1] -= 1;
Packit 6c4009
Packit 6c4009
	      time->era_entries[idx].start_date[2] = strtol (str, &endp, 10);
Packit 6c4009
	      if (endp == str)
Packit 6c4009
		{
Packit 6c4009
		invalid_start_date:
Packit 6c4009
		  record_error (0, 0, _("\
Packit 6c4009
%s: invalid starting date in string %Zd in `era' field"),
Packit 6c4009
				"LC_TIME", idx + 1);
Packit 6c4009
		  (void) strsep (&str, ":");
Packit 6c4009
		}
Packit 6c4009
	      else if (*endp != ':')
Packit 6c4009
		{
Packit 6c4009
		garbage_start_date:
Packit 6c4009
		  record_error (0, 0, _("\
Packit 6c4009
%s: garbage at end of starting date in string %Zd in `era' field "),
Packit 6c4009
				"LC_TIME", idx + 1);
Packit 6c4009
		  (void) strsep (&str, ":");
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  str = endp + 1;
Packit 6c4009
Packit 6c4009
		  /* Check for valid value.  */
Packit 6c4009
		  if ((time->era_entries[idx].start_date[1] < 0
Packit 6c4009
		       || time->era_entries[idx].start_date[1] >= 12
Packit 6c4009
		       || time->era_entries[idx].start_date[2] < 0
Packit 6c4009
		       || (time->era_entries[idx].start_date[2]
Packit 6c4009
			   > days_per_month[time->era_entries[idx].start_date[1]])
Packit 6c4009
		       || (time->era_entries[idx].start_date[1] == 2
Packit 6c4009
			   && time->era_entries[idx].start_date[2] == 29
Packit 6c4009
			   && !__isleap (time->era_entries[idx].start_date[0]))))
Packit 6c4009
		    record_error (0, 0, _("\
Packit 6c4009
%s: starting date is invalid in string %Zd in `era' field"),
Packit 6c4009
				  "LC_TIME", idx + 1);
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Next is the stopping date in ISO format.  */
Packit 6c4009
	  if (strncmp (str, "-*", 2) == 0)
Packit 6c4009
	    {
Packit 6c4009
	      time->era_entries[idx].stop_date[0] =
Packit 6c4009
		time->era_entries[idx].stop_date[1] =
Packit 6c4009
		time->era_entries[idx].stop_date[2] = 0x80000000;
Packit 6c4009
	      if (str[2] != ':')
Packit 6c4009
		goto garbage_stop_date;
Packit 6c4009
	      str += 3;
Packit 6c4009
	    }
Packit 6c4009
	  else if (strncmp (str, "+*", 2) == 0)
Packit 6c4009
	    {
Packit 6c4009
	      time->era_entries[idx].stop_date[0] =
Packit 6c4009
		time->era_entries[idx].stop_date[1] =
Packit 6c4009
		time->era_entries[idx].stop_date[2] = 0x7fffffff;
Packit 6c4009
	      if (str[2] != ':')
Packit 6c4009
		goto garbage_stop_date;
Packit 6c4009
	      str += 3;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      time->era_entries[idx].stop_date[0] = strtol (str, &endp, 10);
Packit 6c4009
	      if (endp == str || *endp != '/')
Packit 6c4009
		goto invalid_stop_date;
Packit 6c4009
	      else
Packit 6c4009
		str = endp + 1;
Packit 6c4009
	      time->era_entries[idx].stop_date[0] -= 1900;
Packit 6c4009
	      /* year -1 represent 1 B.C. (not -1 A.D.) */
Packit 6c4009
	      if (time->era_entries[idx].stop_date[0] < -1900)
Packit 6c4009
		++time->era_entries[idx].stop_date[0];
Packit 6c4009
Packit 6c4009
	      time->era_entries[idx].stop_date[1] = strtol (str, &endp, 10);
Packit 6c4009
	      if (endp == str || *endp != '/')
Packit 6c4009
		goto invalid_stop_date;
Packit 6c4009
	      else
Packit 6c4009
		str = endp + 1;
Packit 6c4009
	      time->era_entries[idx].stop_date[1] -= 1;
Packit 6c4009
Packit 6c4009
	      time->era_entries[idx].stop_date[2] = strtol (str, &endp, 10);
Packit 6c4009
	      if (endp == str)
Packit 6c4009
		{
Packit 6c4009
		invalid_stop_date:
Packit 6c4009
		  record_error (0, 0, _("\
Packit 6c4009
%s: invalid stopping date in string %Zd in `era' field"),
Packit 6c4009
				"LC_TIME", idx + 1);
Packit 6c4009
		  (void) strsep (&str, ":");
Packit 6c4009
		}
Packit 6c4009
	      else if (*endp != ':')
Packit 6c4009
		{
Packit 6c4009
		garbage_stop_date:
Packit 6c4009
		  record_error (0, 0, _("\
Packit 6c4009
%s: garbage at end of stopping date in string %Zd in `era' field"),
Packit 6c4009
				"LC_TIME", idx + 1);
Packit 6c4009
		  (void) strsep (&str, ":");
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  str = endp + 1;
Packit 6c4009
Packit 6c4009
		  /* Check for valid value.  */
Packit 6c4009
		  if ((time->era_entries[idx].stop_date[1] < 0
Packit 6c4009
		       || time->era_entries[idx].stop_date[1] >= 12
Packit 6c4009
		       || time->era_entries[idx].stop_date[2] < 0
Packit 6c4009
		       || (time->era_entries[idx].stop_date[2]
Packit 6c4009
			   > days_per_month[time->era_entries[idx].stop_date[1]])
Packit 6c4009
		       || (time->era_entries[idx].stop_date[1] == 2
Packit 6c4009
			   && time->era_entries[idx].stop_date[2] == 29
Packit 6c4009
			   && !__isleap (time->era_entries[idx].stop_date[0]))))
Packit 6c4009
		    record_error (0, 0, _("\
Packit 6c4009
%s: invalid stopping date in string %Zd in `era' field"),
Packit 6c4009
				  "LC_TIME", idx + 1);
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (str == NULL || *str == '\0')
Packit 6c4009
	    {
Packit 6c4009
	      record_error (0, 0, _("\
Packit 6c4009
%s: missing era name in string %Zd in `era' field"), "LC_TIME", idx + 1);
Packit 6c4009
	      time->era_entries[idx].name =
Packit 6c4009
		time->era_entries[idx].format = "";
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      time->era_entries[idx].name = strsep (&str, ":");
Packit 6c4009
Packit 6c4009
	      if (str == NULL || *str == '\0')
Packit 6c4009
		{
Packit 6c4009
		  record_error (0, 0, _("\
Packit 6c4009
%s: missing era format in string %Zd in `era' field"),
Packit 6c4009
				"LC_TIME", idx + 1);
Packit 6c4009
		  time->era_entries[idx].name =
Packit 6c4009
		    time->era_entries[idx].format = "";
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		time->era_entries[idx].format = str;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Now generate the wide character name and format.  */
Packit 6c4009
	  wstr = wcschr ((wchar_t *) time->wera[idx], L':');/* end direction */
Packit 6c4009
	  wstr = wstr ? wcschr (wstr + 1, L':') : NULL;	/* end offset */
Packit 6c4009
	  wstr = wstr ? wcschr (wstr + 1, L':') : NULL;	/* end start */
Packit 6c4009
	  wstr = wstr ? wcschr (wstr + 1, L':') : NULL;	/* end end */
Packit 6c4009
	  if (wstr != NULL)
Packit 6c4009
	    {
Packit 6c4009
	      time->era_entries[idx].wname = (uint32_t *) wstr + 1;
Packit 6c4009
	      wstr = wcschr (wstr + 1, L':');	/* end name */
Packit 6c4009
	      if (wstr != NULL)
Packit 6c4009
		{
Packit 6c4009
		  *wstr = L'\0';
Packit 6c4009
		  time->era_entries[idx].wformat = (uint32_t *) wstr + 1;
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		time->era_entries[idx].wname =
Packit 6c4009
		  time->era_entries[idx].wformat = (uint32_t *) L"";
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    time->era_entries[idx].wname =
Packit 6c4009
	      time->era_entries[idx].wformat = (uint32_t *) L"";
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Set up defaults based on ISO 30112 WD10 [2014].  */
Packit 6c4009
  if (time->week_ndays == 0)
Packit 6c4009
    time->week_ndays = 7;
Packit 6c4009
Packit 6c4009
  if (time->week_1stday == 0)
Packit 6c4009
    time->week_1stday = 19971130;
Packit 6c4009
Packit 6c4009
  if (time->week_1stweek == 0)
Packit 6c4009
    time->week_1stweek = 7;
Packit 6c4009
Packit 6c4009
  if (time->week_1stweek > time->week_ndays)
Packit 6c4009
    record_error (0, 0, _("\
Packit 6c4009
%s: third operand for value of field `%s' must not be larger than %d"),
Packit 6c4009
		  "LC_TIME", "week", 7);
Packit 6c4009
Packit 6c4009
  if (time->first_weekday == '\0')
Packit 6c4009
    /* The definition does not specify this so the default is used.  */
Packit 6c4009
    time->first_weekday = 1;
Packit 6c4009
  else if (time->first_weekday > time->week_ndays)
Packit 6c4009
    record_error (0, 0, _("\
Packit 6c4009
%s: values for field `%s' must not be larger than %d"),
Packit 6c4009
		  "LC_TIME", "first_weekday", 7);
Packit 6c4009
Packit 6c4009
  if (time->first_workday == '\0')
Packit 6c4009
    /* The definition does not specify this so the default is used.  */
Packit 6c4009
    time->first_workday = 2;
Packit 6c4009
  else if (time->first_workday > time->week_ndays)
Packit 6c4009
    record_error (0, 0, _("\
Packit 6c4009
%s: values for field `%s' must not be larger than %d"),
Packit 6c4009
		  "LC_TIME", "first_workday", 7);
Packit 6c4009
Packit 6c4009
  if (time->cal_direction == '\0')
Packit 6c4009
    /* The definition does not specify this so the default is used.  */
Packit 6c4009
    time->cal_direction = 1;
Packit 6c4009
  else if (time->cal_direction > 3)
Packit 6c4009
    record_error (0, 0, _("\
Packit 6c4009
%s: values for field `%s' must not be larger than %d"),
Packit 6c4009
		  "LC_TIME", "cal_direction", 3);
Packit 6c4009
Packit 6c4009
  /* XXX We don't perform any tests on the timezone value since this is
Packit 6c4009
     simply useless, stupid $&$!@...  */
Packit 6c4009
  if (time->timezone == NULL)
Packit 6c4009
    time->timezone = "";
Packit 6c4009
Packit 6c4009
  if (time->date_fmt == NULL)
Packit 6c4009
    time->date_fmt = "%a %b %e %H:%M:%S %Z %Y";
Packit 6c4009
  if (time->wdate_fmt == NULL)
Packit 6c4009
    time->wdate_fmt = (const uint32_t *) L"%a %b %e %H:%M:%S %Z %Y";
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
time_output (struct localedef_t *locale, const struct charmap_t *charmap,
Packit 6c4009
	     const char *output_path)
Packit 6c4009
{
Packit 6c4009
  struct locale_time_t *time = locale->categories[LC_TIME].time;
Packit 6c4009
  struct locale_file file;
Packit 6c4009
  size_t num, n;
Packit 6c4009
Packit 6c4009
  init_locale_data (&file, _NL_ITEM_INDEX (_NL_NUM_LC_TIME));
Packit 6c4009
Packit 6c4009
  /* The ab'days.  */
Packit 6c4009
  for (n = 0; n < 7; ++n)
Packit 6c4009
    add_locale_string (&file, time->abday[n] ?: "");
Packit 6c4009
Packit 6c4009
  /* The days.  */
Packit 6c4009
  for (n = 0; n < 7; ++n)
Packit 6c4009
    add_locale_string (&file, time->day[n] ?: "");
Packit 6c4009
Packit 6c4009
  /* The ab'mons.  */
Packit 6c4009
  for (n = 0; n < 12; ++n)
Packit 6c4009
    add_locale_string (&file, time->abmon[n] ?: "");
Packit 6c4009
Packit 6c4009
  /* The mons.  */
Packit 6c4009
  for (n = 0; n < 12; ++n)
Packit 6c4009
    add_locale_string (&file, time->mon[n] ?: "");
Packit 6c4009
Packit 6c4009
  /* AM/PM.  */
Packit 6c4009
  for (n = 0; n < 2; ++n)
Packit 6c4009
    add_locale_string (&file, time->am_pm[n]);
Packit 6c4009
Packit 6c4009
  add_locale_string (&file, time->d_t_fmt ?: "");
Packit 6c4009
  add_locale_string (&file, time->d_fmt ?: "");
Packit 6c4009
  add_locale_string (&file, time->t_fmt ?: "");
Packit 6c4009
  add_locale_string (&file, time->t_fmt_ampm ?: "");
Packit 6c4009
Packit 6c4009
  start_locale_structure (&file;;
Packit 6c4009
  for (num = 0; num < time->num_era; ++num)
Packit 6c4009
    add_locale_string (&file, time->era[num]);
Packit 6c4009
  end_locale_structure (&file;;
Packit 6c4009
Packit 6c4009
  add_locale_string (&file, time->era_year ?: "");
Packit 6c4009
  add_locale_string (&file, time->era_d_fmt ?: "");
Packit 6c4009
Packit 6c4009
  start_locale_structure (&file;;
Packit 6c4009
  for (num = 0; num < 100; ++num)
Packit 6c4009
    add_locale_string (&file, time->alt_digits[num] ?: "");
Packit 6c4009
  end_locale_structure (&file;;
Packit 6c4009
Packit 6c4009
  add_locale_string (&file, time->era_d_t_fmt ?: "");
Packit 6c4009
  add_locale_string (&file, time->era_t_fmt ?: "");
Packit 6c4009
  add_locale_uint32 (&file, time->num_era);
Packit 6c4009
Packit 6c4009
  start_locale_structure (&file;;
Packit 6c4009
  for (num = 0; num < time->num_era; ++num)
Packit 6c4009
    {
Packit 6c4009
      add_locale_uint32 (&file, time->era_entries[num].direction);
Packit 6c4009
      add_locale_uint32 (&file, time->era_entries[num].offset);
Packit 6c4009
      add_locale_uint32 (&file, time->era_entries[num].start_date[0]);
Packit 6c4009
      add_locale_uint32 (&file, time->era_entries[num].start_date[1]);
Packit 6c4009
      add_locale_uint32 (&file, time->era_entries[num].start_date[2]);
Packit 6c4009
      add_locale_uint32 (&file, time->era_entries[num].stop_date[0]);
Packit 6c4009
      add_locale_uint32 (&file, time->era_entries[num].stop_date[1]);
Packit 6c4009
      add_locale_uint32 (&file, time->era_entries[num].stop_date[2]);
Packit 6c4009
      add_locale_string (&file, time->era_entries[num].name);
Packit 6c4009
      add_locale_string (&file, time->era_entries[num].format);
Packit 6c4009
      add_locale_wstring (&file, time->era_entries[num].wname);
Packit 6c4009
      add_locale_wstring (&file, time->era_entries[num].wformat);
Packit 6c4009
    }
Packit 6c4009
  end_locale_structure (&file;;
Packit 6c4009
Packit 6c4009
  /* The wide character ab'days.  */
Packit 6c4009
  for (n = 0; n < 7; ++n)
Packit 6c4009
    add_locale_wstring (&file, time->wabday[n] ?: empty_wstr);
Packit 6c4009
Packit 6c4009
  /* The wide character days.  */
Packit 6c4009
  for (n = 0; n < 7; ++n)
Packit 6c4009
    add_locale_wstring (&file, time->wday[n] ?: empty_wstr);
Packit 6c4009
Packit 6c4009
  /* The wide character ab'mons.  */
Packit 6c4009
  for (n = 0; n < 12; ++n)
Packit 6c4009
    add_locale_wstring (&file, time->wabmon[n] ?: empty_wstr);
Packit 6c4009
Packit 6c4009
  /* The wide character mons.  */
Packit 6c4009
  for (n = 0; n < 12; ++n)
Packit 6c4009
    add_locale_wstring (&file, time->wmon[n] ?: empty_wstr);
Packit 6c4009
Packit 6c4009
  /* Wide character AM/PM.  */
Packit 6c4009
  for (n = 0; n < 2; ++n)
Packit 6c4009
    add_locale_wstring (&file, time->wam_pm[n] ?: empty_wstr);
Packit 6c4009
Packit 6c4009
  add_locale_wstring (&file, time->wd_t_fmt ?: empty_wstr);
Packit 6c4009
  add_locale_wstring (&file, time->wd_fmt ?: empty_wstr);
Packit 6c4009
  add_locale_wstring (&file, time->wt_fmt ?: empty_wstr);
Packit 6c4009
  add_locale_wstring (&file, time->wt_fmt_ampm ?: empty_wstr);
Packit 6c4009
  add_locale_wstring (&file, time->wera_year ?: empty_wstr);
Packit 6c4009
  add_locale_wstring (&file, time->wera_d_fmt ?: empty_wstr);
Packit 6c4009
Packit 6c4009
  start_locale_structure (&file;;
Packit 6c4009
  for (num = 0; num < 100; ++num)
Packit 6c4009
    add_locale_wstring (&file, time->walt_digits[num] ?: empty_wstr);
Packit 6c4009
  end_locale_structure (&file;;
Packit 6c4009
Packit 6c4009
  add_locale_wstring (&file, time->wera_d_t_fmt ?: empty_wstr);
Packit 6c4009
  add_locale_wstring (&file, time->wera_t_fmt ?: empty_wstr);
Packit 6c4009
  add_locale_char (&file, time->week_ndays);
Packit 6c4009
  add_locale_uint32 (&file, time->week_1stday);
Packit 6c4009
  add_locale_char (&file, time->week_1stweek);
Packit 6c4009
  add_locale_char (&file, time->first_weekday);
Packit 6c4009
  add_locale_char (&file, time->first_workday);
Packit 6c4009
  add_locale_char (&file, time->cal_direction);
Packit 6c4009
  add_locale_string (&file, time->timezone);
Packit 6c4009
  add_locale_string (&file, time->date_fmt);
Packit 6c4009
  add_locale_wstring (&file, time->wdate_fmt);
Packit 6c4009
  add_locale_string (&file, charmap->code_set_name);
Packit 6c4009
Packit 6c4009
  /* The alt'mons.  */
Packit 6c4009
  for (n = 0; n < 12; ++n)
Packit 6c4009
    add_locale_string (&file, time->alt_mon[n] ?: "");
Packit 6c4009
Packit 6c4009
  /* The wide character alt'mons.  */
Packit 6c4009
  for (n = 0; n < 12; ++n)
Packit 6c4009
    add_locale_wstring (&file, time->walt_mon[n] ?: empty_wstr);
Packit 6c4009
Packit 6c4009
  /* The ab'alt'mons.  */
Packit 6c4009
  for (n = 0; n < 12; ++n)
Packit 6c4009
    add_locale_string (&file, time->ab_alt_mon[n] ?: "");
Packit 6c4009
Packit 6c4009
  /* The wide character ab'alt'mons.  */
Packit 6c4009
  for (n = 0; n < 12; ++n)
Packit 6c4009
    add_locale_wstring (&file, time->wab_alt_mon[n] ?: empty_wstr);
Packit 6c4009
Packit 6c4009
  write_locale_data (output_path, LC_TIME, "LC_TIME", &file;;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* The parser for the LC_TIME section of the locale definition.  */
Packit 6c4009
void
Packit 6c4009
time_read (struct linereader *ldfile, struct localedef_t *result,
Packit 6c4009
	   const struct charmap_t *charmap, const char *repertoire_name,
Packit 6c4009
	   int ignore_content)
Packit 6c4009
{
Packit 6c4009
  struct repertoire_t *repertoire = NULL;
Packit 6c4009
  struct locale_time_t *time;
Packit 6c4009
  struct token *now;
Packit 6c4009
  enum token_t nowtok;
Packit 6c4009
  size_t cnt;
Packit 6c4009
Packit 6c4009
  /* Get the repertoire we have to use.  */
Packit 6c4009
  if (repertoire_name != NULL)
Packit 6c4009
    repertoire = repertoire_read (repertoire_name);
Packit 6c4009
Packit 6c4009
  /* The rest of the line containing `LC_TIME' must be free.  */
Packit 6c4009
  lr_ignore_rest (ldfile, 1);
Packit 6c4009
Packit 6c4009
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      now = lr_token (ldfile, charmap, result, repertoire, verbose);
Packit 6c4009
      nowtok = now->tok;
Packit 6c4009
    }
Packit 6c4009
  while (nowtok == tok_eol);
Packit 6c4009
Packit 6c4009
  /* If we see `copy' now we are almost done.  */
Packit 6c4009
  if (nowtok == tok_copy)
Packit 6c4009
    {
Packit 6c4009
      handle_copy (ldfile, charmap, repertoire_name, result, tok_lc_time,
Packit 6c4009
		   LC_TIME, "LC_TIME", ignore_content);
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Prepare the data structures.  */
Packit 6c4009
  time_startup (ldfile, result, ignore_content);
Packit 6c4009
  time = result->categories[LC_TIME].time;
Packit 6c4009
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit 6c4009
      /* Of course we don't proceed beyond the end of file.  */
Packit 6c4009
      if (nowtok == tok_eof)
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      /* Ingore empty lines.  */
Packit 6c4009
      if (nowtok == tok_eol)
Packit 6c4009
	{
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, repertoire, verbose);
Packit 6c4009
	  nowtok = now->tok;
Packit 6c4009
	  continue;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      switch (nowtok)
Packit 6c4009
	{
Packit 6c4009
#define STRARR_ELEM(cat, min, max) \
Packit 6c4009
	case tok_##cat:							      \
Packit 6c4009
	  /* Ignore the rest of the line if we don't need the input of	      \
Packit 6c4009
	     this line.  */						      \
Packit 6c4009
	  if (ignore_content)						      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      lr_ignore_rest (ldfile, 0);				      \
Packit 6c4009
	      break;							      \
Packit 6c4009
	    }								      \
Packit 6c4009
									      \
Packit 6c4009
	  for (cnt = 0; cnt < max; ++cnt)				      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      now = lr_token (ldfile, charmap, result, repertoire, verbose);  \
Packit 6c4009
	      if (now->tok == tok_eol)					      \
Packit 6c4009
		{							      \
Packit 6c4009
		  if (cnt < min)					      \
Packit 6c4009
		    lr_error (ldfile, _("%s: too few values for field `%s'"), \
Packit 6c4009
			      "LC_TIME", #cat);				      \
Packit 6c4009
		  if (!ignore_content)					      \
Packit 6c4009
		    do							      \
Packit 6c4009
		      {							      \
Packit 6c4009
			time->cat[cnt] = "";				      \
Packit 6c4009
			time->w##cat[cnt] = empty_wstr;			      \
Packit 6c4009
		      }							      \
Packit 6c4009
		    while (++cnt < max);				      \
Packit 6c4009
		  break;						      \
Packit 6c4009
		}							      \
Packit 6c4009
	      else if (now->tok != tok_string)				      \
Packit 6c4009
		goto err_label;						      \
Packit 6c4009
	      else if (!ignore_content && (now->val.str.startmb == NULL	      \
Packit 6c4009
					   || now->val.str.startwc == NULL))  \
Packit 6c4009
		{							      \
Packit 6c4009
		  lr_error (ldfile, _("%s: unknown character in field `%s'"), \
Packit 6c4009
			    "LC_TIME", #cat);				      \
Packit 6c4009
		  time->cat[cnt] = "";					      \
Packit 6c4009
		  time->w##cat[cnt] = empty_wstr;			      \
Packit 6c4009
		}							      \
Packit 6c4009
	      else if (!ignore_content)					      \
Packit 6c4009
		{							      \
Packit 6c4009
		  time->cat[cnt] = now->val.str.startmb;		      \
Packit 6c4009
		  time->w##cat[cnt] = now->val.str.startwc;		      \
Packit 6c4009
		}							      \
Packit 6c4009
									      \
Packit 6c4009
	      /* Match the semicolon.  */				      \
Packit 6c4009
	      now = lr_token (ldfile, charmap, result, repertoire, verbose);  \
Packit 6c4009
	      if (now->tok != tok_semicolon && now->tok != tok_eol)	      \
Packit 6c4009
		break;							      \
Packit 6c4009
	    }								      \
Packit 6c4009
	  if (now->tok != tok_eol)					      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      while (!ignore_content && cnt < min)			      \
Packit 6c4009
		{							      \
Packit 6c4009
		  time->cat[cnt] = "";					      \
Packit 6c4009
		  time->w##cat[cnt++] = empty_wstr;			      \
Packit 6c4009
		}							      \
Packit 6c4009
									      \
Packit 6c4009
	      if (now->tok == tok_semicolon)				      \
Packit 6c4009
		{							      \
Packit 6c4009
		  now = lr_token (ldfile, charmap, result, repertoire,	      \
Packit 6c4009
				  verbose);				      \
Packit 6c4009
		  if (now->tok == tok_eol)				      \
Packit 6c4009
		    lr_error (ldfile, _("extra trailing semicolon"));	      \
Packit 6c4009
		  else if (now->tok == tok_string)			      \
Packit 6c4009
		    {							      \
Packit 6c4009
		      lr_error (ldfile, _("\
Packit 6c4009
%s: too many values for field `%s'"),					      \
Packit 6c4009
				"LC_TIME", #cat);			      \
Packit 6c4009
		      lr_ignore_rest (ldfile, 0);			      \
Packit 6c4009
		    }							      \
Packit 6c4009
		  else							      \
Packit 6c4009
		    goto err_label;					      \
Packit 6c4009
		}							      \
Packit 6c4009
	      else							      \
Packit 6c4009
		goto err_label;						      \
Packit 6c4009
	    }								      \
Packit 6c4009
	  time->cat##_defined = 1;					      \
Packit 6c4009
	  break
Packit 6c4009
Packit 6c4009
	  STRARR_ELEM (abday, 7, 7);
Packit 6c4009
	  STRARR_ELEM (day, 7, 7);
Packit 6c4009
	  STRARR_ELEM (abmon, 12, 12);
Packit 6c4009
	  STRARR_ELEM (mon, 12, 12);
Packit 6c4009
	  STRARR_ELEM (am_pm, 2, 2);
Packit 6c4009
	  STRARR_ELEM (alt_digits, 0, 100);
Packit 6c4009
	  STRARR_ELEM (alt_mon, 12, 12);
Packit 6c4009
	  STRARR_ELEM (ab_alt_mon, 12, 12);
Packit 6c4009
Packit 6c4009
	case tok_era:
Packit 6c4009
	  /* Ignore the rest of the line if we don't need the input of
Packit 6c4009
	     this line.  */
Packit 6c4009
	  if (ignore_content)
Packit 6c4009
	    {
Packit 6c4009
	      lr_ignore_rest (ldfile, 0);
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	  do
Packit 6c4009
	    {
Packit 6c4009
	      now = lr_token (ldfile, charmap, result, repertoire, verbose);
Packit 6c4009
	      if (now->tok != tok_string)
Packit 6c4009
		goto err_label;
Packit 6c4009
	      if (!ignore_content && (now->val.str.startmb == NULL
Packit 6c4009
				      || now->val.str.startwc == NULL))
Packit 6c4009
		{
Packit 6c4009
		  lr_error (ldfile, _("%s: unknown character in field `%s'"),
Packit 6c4009
			    "LC_TIME", "era");
Packit 6c4009
		  lr_ignore_rest (ldfile, 0);
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
	      if (!ignore_content)
Packit 6c4009
		{
Packit 6c4009
		  time->era = xrealloc (time->era,
Packit 6c4009
					(time->num_era + 1) * sizeof (char *));
Packit 6c4009
		  time->era[time->num_era] = now->val.str.startmb;
Packit 6c4009
Packit 6c4009
		  time->wera = xrealloc (time->wera,
Packit 6c4009
					 (time->num_era + 1)
Packit 6c4009
					 * sizeof (char *));
Packit 6c4009
		  time->wera[time->num_era++] = now->val.str.startwc;
Packit 6c4009
		}
Packit 6c4009
	      now = lr_token (ldfile, charmap, result, repertoire, verbose);
Packit 6c4009
	      if (now->tok != tok_eol && now->tok != tok_semicolon)
Packit 6c4009
		goto err_label;
Packit 6c4009
	    }
Packit 6c4009
	  while (now->tok == tok_semicolon);
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
#define STR_ELEM(cat) \
Packit 6c4009
	case tok_##cat:							      \
Packit 6c4009
	  /* Ignore the rest of the line if we don't need the input of	      \
Packit 6c4009
	     this line.  */						      \
Packit 6c4009
	  if (ignore_content)						      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      lr_ignore_rest (ldfile, 0);				      \
Packit 6c4009
	      break;							      \
Packit 6c4009
	    }								      \
Packit 6c4009
									      \
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, repertoire, verbose);      \
Packit 6c4009
	  if (now->tok != tok_string)					      \
Packit 6c4009
	    goto err_label;						      \
Packit 6c4009
	  else if (time->cat != NULL)					      \
Packit 6c4009
	    lr_error (ldfile, _("\
Packit 6c4009
%s: field `%s' declared more than once"), "LC_TIME", #cat);		      \
Packit 6c4009
	  else if (!ignore_content && (now->val.str.startmb == NULL	      \
Packit 6c4009
				       || now->val.str.startwc == NULL))      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      lr_error (ldfile, _("%s: unknown character in field `%s'"),     \
Packit 6c4009
			"LC_TIME", #cat);				      \
Packit 6c4009
	      time->cat = "";						      \
Packit 6c4009
	      time->w##cat = empty_wstr;				      \
Packit 6c4009
	    }								      \
Packit 6c4009
	  else if (!ignore_content)					      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      time->cat = now->val.str.startmb;				      \
Packit 6c4009
	      time->w##cat = now->val.str.startwc;			      \
Packit 6c4009
	    }								      \
Packit 6c4009
	  break
Packit 6c4009
Packit 6c4009
	  STR_ELEM (d_t_fmt);
Packit 6c4009
	  STR_ELEM (d_fmt);
Packit 6c4009
	  STR_ELEM (t_fmt);
Packit 6c4009
	  STR_ELEM (t_fmt_ampm);
Packit 6c4009
	  STR_ELEM (era_year);
Packit 6c4009
	  STR_ELEM (era_d_t_fmt);
Packit 6c4009
	  STR_ELEM (era_d_fmt);
Packit 6c4009
	  STR_ELEM (era_t_fmt);
Packit 6c4009
	  STR_ELEM (timezone);
Packit 6c4009
	  STR_ELEM (date_fmt);
Packit 6c4009
Packit 6c4009
#define INT_ELEM(cat) \
Packit 6c4009
	case tok_##cat:							      \
Packit 6c4009
	  /* Ignore the rest of the line if we don't need the input of	      \
Packit 6c4009
	     this line.  */						      \
Packit 6c4009
	  if (ignore_content)						      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      lr_ignore_rest (ldfile, 0);				      \
Packit 6c4009
	      break;							      \
Packit 6c4009
	    }								      \
Packit 6c4009
									      \
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, repertoire, verbose);      \
Packit 6c4009
	  if (now->tok != tok_number)					      \
Packit 6c4009
	    goto err_label;						      \
Packit 6c4009
	  else if (time->cat != 0)					      \
Packit 6c4009
	    lr_error (ldfile, _("%s: field `%s' declared more than once"),    \
Packit 6c4009
		      "LC_TIME", #cat);					      \
Packit 6c4009
	  else if (!ignore_content)					      \
Packit 6c4009
	    time->cat = now->val.num;					      \
Packit 6c4009
	  break
Packit 6c4009
Packit 6c4009
	  INT_ELEM (first_weekday);
Packit 6c4009
	  INT_ELEM (first_workday);
Packit 6c4009
	  INT_ELEM (cal_direction);
Packit 6c4009
Packit 6c4009
	case tok_week:
Packit 6c4009
	  /* Ignore the rest of the line if we don't need the input of
Packit 6c4009
	     this line.  */
Packit 6c4009
	  if (ignore_content)
Packit 6c4009
	    {
Packit 6c4009
	      lr_ignore_rest (ldfile, 0);
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, repertoire, verbose);
Packit 6c4009
	  if (now->tok != tok_number)
Packit 6c4009
	    goto err_label;
Packit 6c4009
	  time->week_ndays = now->val.num;
Packit 6c4009
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, repertoire, verbose);
Packit 6c4009
	  if (now->tok != tok_semicolon)
Packit 6c4009
	    goto err_label;
Packit 6c4009
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, repertoire, verbose);
Packit 6c4009
	  if (now->tok != tok_number)
Packit 6c4009
	    goto err_label;
Packit 6c4009
	  time->week_1stday = now->val.num;
Packit 6c4009
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, repertoire, verbose);
Packit 6c4009
	  if (now->tok != tok_semicolon)
Packit 6c4009
	    goto err_label;
Packit 6c4009
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, repertoire, verbose);
Packit 6c4009
	  if (now->tok != tok_number)
Packit 6c4009
	    goto err_label;
Packit 6c4009
	  time->week_1stweek = now->val.num;
Packit 6c4009
Packit 6c4009
	  lr_ignore_rest (ldfile,  1);
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case tok_end:
Packit 6c4009
	  /* Next we assume `LC_TIME'.  */
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, repertoire, verbose);
Packit 6c4009
	  if (now->tok == tok_eof)
Packit 6c4009
	    break;
Packit 6c4009
	  if (now->tok == tok_eol)
Packit 6c4009
	    lr_error (ldfile, _("%s: incomplete `END' line"), "LC_TIME");
Packit 6c4009
	  else if (now->tok != tok_lc_time)
Packit 6c4009
	    lr_error (ldfile, _("\
Packit 6c4009
%1$s: definition does not end with `END %1$s'"), "LC_TIME");
Packit 6c4009
	  lr_ignore_rest (ldfile, now->tok == tok_lc_time);
Packit 6c4009
Packit 6c4009
	  /* If alt_mon was not specified, make it a copy of mon.  */
Packit 6c4009
	  if (!ignore_content && !time->alt_mon_defined)
Packit 6c4009
	    {
Packit 6c4009
	      memcpy (time->alt_mon, time->mon, sizeof (time->mon));
Packit 6c4009
	      memcpy (time->walt_mon, time->wmon, sizeof (time->wmon));
Packit 6c4009
	      time->alt_mon_defined = 1;
Packit 6c4009
	    }
Packit 6c4009
	  /* The same for abbreviated versions.  */
Packit 6c4009
	  if (!ignore_content && !time->ab_alt_mon_defined)
Packit 6c4009
	    {
Packit 6c4009
	      memcpy (time->ab_alt_mon, time->abmon, sizeof (time->abmon));
Packit 6c4009
	      memcpy (time->wab_alt_mon, time->wabmon, sizeof (time->wabmon));
Packit 6c4009
	      time->ab_alt_mon_defined = 1;
Packit 6c4009
	    }
Packit 6c4009
	  return;
Packit 6c4009
Packit 6c4009
	default:
Packit 6c4009
	err_label:
Packit 6c4009
	  SYNTAX_ERROR (_("%s: syntax error"), "LC_TIME");
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Prepare for the next round.  */
Packit 6c4009
      now = lr_token (ldfile, charmap, result, repertoire, verbose);
Packit 6c4009
      nowtok = now->tok;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* When we come here we reached the end of the file.  */
Packit 6c4009
  lr_error (ldfile, _("%s: premature end of file"), "LC_TIME");
Packit 6c4009
}