Blame time/tzset.c

Packit 6c4009
/* Copyright (C) 1991-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
#include <ctype.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <libc-lock.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stddef.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <time.h>
Packit 6c4009
Packit 6c4009
#include <timezone/tzfile.h>
Packit 6c4009
Packit 6c4009
#define SECSPERDAY ((time_t) 86400)
Packit 6c4009
Packit 6c4009
char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
Packit 6c4009
int __daylight = 0;
Packit 6c4009
long int __timezone = 0L;
Packit 6c4009
Packit 6c4009
weak_alias (__tzname, tzname)
Packit 6c4009
weak_alias (__daylight, daylight)
Packit 6c4009
weak_alias (__timezone, timezone)
Packit 6c4009
Packit 6c4009
/* This locks all the state variables in tzfile.c and this file.  */
Packit 6c4009
__libc_lock_define_initialized (static, tzset_lock)
Packit 6c4009
Packit 6c4009
/* This structure contains all the information about a
Packit 6c4009
   timezone given in the POSIX standard TZ envariable.  */
Packit 6c4009
typedef struct
Packit 6c4009
  {
Packit 6c4009
    const char *name;
Packit 6c4009
Packit 6c4009
    /* When to change.  */
Packit 6c4009
    enum { J0, J1, M } type;	/* Interpretation of:  */
Packit 6c4009
    unsigned short int m, n, d;	/* Month, week, day.  */
Packit 6c4009
    int secs;			/* Time of day.  */
Packit 6c4009
Packit 6c4009
    long int offset;		/* Seconds east of GMT (west if < 0).  */
Packit 6c4009
Packit 6c4009
    /* We cache the computed time of change for a
Packit 6c4009
       given year so we don't have to recompute it.  */
Packit 6c4009
    time_t change;	/* When to change to this zone.  */
Packit 6c4009
    int computed_for;	/* Year above is computed for.  */
Packit 6c4009
  } tz_rule;
Packit 6c4009
Packit 6c4009
/* tz_rules[0] is standard, tz_rules[1] is daylight.  */
Packit 6c4009
static tz_rule tz_rules[2];
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void compute_change (tz_rule *rule, int year) __THROW;
Packit 6c4009
static void tzset_internal (int always);
Packit 6c4009

Packit 6c4009
/* List of buffers containing time zone strings. */
Packit 6c4009
struct tzstring_l
Packit 6c4009
{
Packit 6c4009
  struct tzstring_l *next;
Packit 6c4009
  size_t len;  /* strlen(data) - doesn't count terminating NUL! */
Packit 6c4009
  char data[0];
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static struct tzstring_l *tzstring_list;
Packit 6c4009
Packit 6c4009
/* Allocate a permanent home for the first LEN characters of S.  It
Packit 6c4009
   will never be moved or deallocated, but may share space with other
Packit 6c4009
   strings.  Don't modify the returned string. */
Packit 6c4009
static char *
Packit 6c4009
__tzstring_len (const char *s, size_t len)
Packit 6c4009
{
Packit 6c4009
  char *p;
Packit 6c4009
  struct tzstring_l *t, *u, *new;
Packit 6c4009
Packit 6c4009
  /* Walk the list and look for a match.  If this string is the same
Packit 6c4009
     as the end of an already-allocated string, it can share space. */
Packit 6c4009
  for (u = t = tzstring_list; t; u = t, t = t->next)
Packit 6c4009
    if (len <= t->len)
Packit 6c4009
      {
Packit 6c4009
	p = &t->data[t->len - len];
Packit 6c4009
	if (memcmp (s, p, len) == 0)
Packit 6c4009
	  return p;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  /* Not found; allocate a new buffer. */
Packit 6c4009
  new = malloc (sizeof (struct tzstring_l) + len + 1);
Packit 6c4009
  if (!new)
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  new->next = NULL;
Packit 6c4009
  new->len = len;
Packit 6c4009
  memcpy (new->data, s, len);
Packit 6c4009
  new->data[len] = '\0';
Packit 6c4009
Packit 6c4009
  if (u)
Packit 6c4009
    u->next = new;
Packit 6c4009
  else
Packit 6c4009
    tzstring_list = new;
Packit 6c4009
Packit 6c4009
  return new->data;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Allocate a permanent home for S.  It will never be moved or
Packit 6c4009
   deallocated, but may share space with other strings.  Don't modify
Packit 6c4009
   the returned string. */
Packit 6c4009
char *
Packit 6c4009
__tzstring (const char *s)
Packit 6c4009
{
Packit 6c4009
  return __tzstring_len (s, strlen (s));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static char *old_tz;
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
update_vars (void)
Packit 6c4009
{
Packit 6c4009
  __daylight = tz_rules[0].offset != tz_rules[1].offset;
Packit 6c4009
  __timezone = -tz_rules[0].offset;
Packit 6c4009
  __tzname[0] = (char *) tz_rules[0].name;
Packit 6c4009
  __tzname[1] = (char *) tz_rules[1].name;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static unsigned int
Packit 6c4009
compute_offset (unsigned int ss, unsigned int mm, unsigned int hh)
Packit 6c4009
{
Packit 6c4009
  if (ss > 59)
Packit 6c4009
    ss = 59;
Packit 6c4009
  if (mm > 59)
Packit 6c4009
    mm = 59;
Packit 6c4009
  if (hh > 24)
Packit 6c4009
    hh = 24;
Packit 6c4009
  return ss + mm * 60 + hh * 60 * 60;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Parses the time zone name at *TZP, and writes a pointer to an
Packit 6c4009
   interned string to tz_rules[WHICHRULE].name.  On success, advances
Packit 6c4009
   *TZP, and returns true.  Returns false otherwise.  */
Packit 6c4009
static bool
Packit 6c4009
parse_tzname (const char **tzp, int whichrule)
Packit 6c4009
{
Packit 6c4009
  const char *start = *tzp;
Packit 6c4009
  const char *p = start;
Packit 6c4009
  while (('a' <= *p && *p <= 'z')
Packit 6c4009
	 || ('A' <= *p && *p <= 'Z'))
Packit 6c4009
      ++p;
Packit 6c4009
  size_t len = p - start;
Packit 6c4009
  if (len < 3)
Packit 6c4009
    {
Packit 6c4009
      p = *tzp;
Packit 6c4009
      if (__glibc_unlikely (*p++ != '<'))
Packit 6c4009
	return false;
Packit 6c4009
      start = p;
Packit 6c4009
      while (('a' <= *p && *p <= 'z')
Packit 6c4009
	     || ('A' <= *p && *p <= 'Z')
Packit 6c4009
	     || ('0' <= *p && *p <= '9')
Packit 6c4009
	     || *p == '+' || *p == '-')
Packit 6c4009
	++p;
Packit 6c4009
      len = p - start;
Packit 6c4009
      if (*p++ != '>' || len < 3)
Packit 6c4009
	return false;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  const char *name = __tzstring_len (start, len);
Packit 6c4009
  if (name == NULL)
Packit 6c4009
    return false;
Packit 6c4009
  tz_rules[whichrule].name = name;
Packit 6c4009
Packit 6c4009
  *tzp = p;
Packit 6c4009
  return true;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Parses the time zone offset at *TZP, and writes it to
Packit 6c4009
   tz_rules[WHICHRULE].offset.  Returns true if the parse was
Packit 6c4009
   successful.  */
Packit 6c4009
static bool
Packit 6c4009
parse_offset (const char **tzp, int whichrule)
Packit 6c4009
{
Packit 6c4009
  const char *tz = *tzp;
Packit 6c4009
  if (whichrule == 0
Packit 6c4009
      && (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz))))
Packit 6c4009
    return false;
Packit 6c4009
Packit 6c4009
  long sign;
Packit 6c4009
  if (*tz == '-' || *tz == '+')
Packit 6c4009
    sign = *tz++ == '-' ? 1L : -1L;
Packit 6c4009
  else
Packit 6c4009
    sign = -1L;
Packit 6c4009
  *tzp = tz;
Packit 6c4009
Packit 6c4009
  unsigned short int hh;
Packit 6c4009
  unsigned short mm = 0;
Packit 6c4009
  unsigned short ss = 0;
Packit 6c4009
  int consumed = 0;
Packit 6c4009
  if (sscanf (tz, "%hu%n:%hu%n:%hu%n",
Packit 6c4009
	      &hh, &consumed, &mm, &consumed, &ss, &consumed) > 0)
Packit 6c4009
    tz_rules[whichrule].offset = sign * compute_offset (ss, mm, hh);
Packit 6c4009
  else
Packit 6c4009
    /* Nothing could be parsed. */
Packit 6c4009
    if (whichrule == 0)
Packit 6c4009
      {
Packit 6c4009
	/* Standard time defaults to offset zero.  */
Packit 6c4009
	tz_rules[0].offset = 0;
Packit 6c4009
	return false;
Packit 6c4009
      }
Packit 6c4009
      else
Packit 6c4009
	/* DST defaults to one hour later than standard time.  */
Packit 6c4009
	tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
Packit 6c4009
  *tzp = tz + consumed;
Packit 6c4009
  return true;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Parses the standard <-> DST rules at *TZP.  Updates
Packit 6c4009
   tz_rule[WHICHRULE].  On success, advances *TZP and returns true.
Packit 6c4009
   Otherwise, returns false.  */
Packit 6c4009
static bool
Packit 6c4009
parse_rule (const char **tzp, int whichrule)
Packit 6c4009
{
Packit 6c4009
  const char *tz = *tzp;
Packit 6c4009
  tz_rule *tzr = &tz_rules[whichrule];
Packit 6c4009
Packit 6c4009
  /* Ignore comma to support string following the incorrect
Packit 6c4009
     specification in early POSIX.1 printings.  */
Packit 6c4009
  tz += *tz == ',';
Packit 6c4009
Packit 6c4009
  /* Get the date of the change.  */
Packit 6c4009
  if (*tz == 'J' || isdigit (*tz))
Packit 6c4009
    {
Packit 6c4009
      char *end;
Packit 6c4009
      tzr->type = *tz == 'J' ? J1 : J0;
Packit 6c4009
      if (tzr->type == J1 && !isdigit (*++tz))
Packit 6c4009
	return false;
Packit 6c4009
      unsigned long int d = strtoul (tz, &end, 10);
Packit 6c4009
      if (end == tz || d > 365)
Packit 6c4009
	return false;
Packit 6c4009
      if (tzr->type == J1 && d == 0)
Packit 6c4009
	return false;
Packit 6c4009
      tzr->d = d;
Packit 6c4009
      tz = end;
Packit 6c4009
    }
Packit 6c4009
  else if (*tz == 'M')
Packit 6c4009
    {
Packit 6c4009
      tzr->type = M;
Packit 6c4009
      int consumed;
Packit 6c4009
      if (sscanf (tz, "M%hu.%hu.%hu%n",
Packit 6c4009
		  &tzr->m, &tzr->n, &tzr->d, &consumed) != 3
Packit 6c4009
	  || tzr->m < 1 || tzr->m > 12
Packit 6c4009
	  || tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
Packit 6c4009
	return false;
Packit 6c4009
      tz += consumed;
Packit 6c4009
    }
Packit 6c4009
  else if (*tz == '\0')
Packit 6c4009
    {
Packit 6c4009
      /* Daylight time rules in the U.S. are defined in the U.S. Code,
Packit 6c4009
	 Title 15, Chapter 6, Subchapter IX - Standard Time.  These
Packit 6c4009
	 dates were established by Congress in the Energy Policy Act
Packit 6c4009
	 of 2005 [Pub. L. no. 109-58, 119 Stat 594 (2005)].
Packit 6c4009
	 Below is the equivalent of "M3.2.0,M11.1.0" [/2 not needed
Packit 6c4009
	 since 2:00AM is the default].  */
Packit 6c4009
      tzr->type = M;
Packit 6c4009
      if (tzr == &tz_rules[0])
Packit 6c4009
	{
Packit 6c4009
	  tzr->m = 3;
Packit 6c4009
	  tzr->n = 2;
Packit 6c4009
	  tzr->d = 0;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  tzr->m = 11;
Packit 6c4009
	  tzr->n = 1;
Packit 6c4009
	  tzr->d = 0;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    return false;
Packit 6c4009
Packit 6c4009
  if (*tz != '\0' && *tz != '/' && *tz != ',')
Packit 6c4009
    return false;
Packit 6c4009
  else if (*tz == '/')
Packit 6c4009
    {
Packit 6c4009
      /* Get the time of day of the change.  */
Packit 6c4009
      int negative;
Packit 6c4009
      ++tz;
Packit 6c4009
      if (*tz == '\0')
Packit 6c4009
	return false;
Packit 6c4009
      negative = *tz == '-';
Packit 6c4009
      tz += negative;
Packit 6c4009
      /* Default to 2:00 AM.  */
Packit 6c4009
      unsigned short hh = 2;
Packit 6c4009
      unsigned short mm = 0;
Packit 6c4009
      unsigned short ss = 0;
Packit 6c4009
      int consumed = 0;
Packit 6c4009
      sscanf (tz, "%hu%n:%hu%n:%hu%n",
Packit 6c4009
	      &hh, &consumed, &mm, &consumed, &ss, &consumed);;
Packit 6c4009
      tz += consumed;
Packit 6c4009
      tzr->secs = (negative ? -1 : 1) * ((hh * 60 * 60) + (mm * 60) + ss);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    /* Default to 2:00 AM.  */
Packit 6c4009
    tzr->secs = 2 * 60 * 60;
Packit 6c4009
Packit 6c4009
  tzr->computed_for = -1;
Packit 6c4009
  *tzp = tz;
Packit 6c4009
  return true;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Parse the POSIX TZ-style string.  */
Packit 6c4009
void
Packit 6c4009
__tzset_parse_tz (const char *tz)
Packit 6c4009
{
Packit 6c4009
  /* Clear out old state and reset to unnamed UTC.  */
Packit 6c4009
  memset (tz_rules, '\0', sizeof tz_rules);
Packit 6c4009
  tz_rules[0].name = tz_rules[1].name = "";
Packit 6c4009
Packit 6c4009
  /* Get the standard timezone name.  */
Packit 6c4009
  if (parse_tzname (&tz, 0) && parse_offset (&tz, 0))
Packit 6c4009
    {
Packit 6c4009
      /* Get the DST timezone name (if any).  */
Packit 6c4009
      if (*tz != '\0')
Packit 6c4009
	{
Packit 6c4009
	  if (parse_tzname (&tz, 1))
Packit 6c4009
	    {
Packit 6c4009
	      parse_offset (&tz, 1);
Packit 6c4009
	      if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
Packit 6c4009
		{
Packit 6c4009
		  /* There is no rule.  See if there is a default rule
Packit 6c4009
		     file.  */
Packit 6c4009
		  __tzfile_default (tz_rules[0].name, tz_rules[1].name,
Packit 6c4009
				    tz_rules[0].offset, tz_rules[1].offset);
Packit 6c4009
		  if (__use_tzfile)
Packit 6c4009
		    {
Packit 6c4009
		      free (old_tz);
Packit 6c4009
		      old_tz = NULL;
Packit 6c4009
		      return;
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	  /* Figure out the standard <-> DST rules.  */
Packit 6c4009
	  if (parse_rule (&tz, 0))
Packit 6c4009
	    parse_rule (&tz, 1);
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  /* There is no DST.  */
Packit 6c4009
	  tz_rules[1].name = tz_rules[0].name;
Packit 6c4009
	  tz_rules[1].offset = tz_rules[0].offset;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  update_vars ();
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Interpret the TZ envariable.  */
Packit 6c4009
static void
Packit 6c4009
tzset_internal (int always)
Packit 6c4009
{
Packit 6c4009
  static int is_initialized;
Packit 6c4009
  const char *tz;
Packit 6c4009
Packit 6c4009
  if (is_initialized && !always)
Packit 6c4009
    return;
Packit 6c4009
  is_initialized = 1;
Packit 6c4009
Packit 6c4009
  /* Examine the TZ environment variable.  */
Packit 6c4009
  tz = getenv ("TZ");
Packit 6c4009
  if (tz && *tz == '\0')
Packit 6c4009
    /* User specified the empty string; use UTC explicitly.  */
Packit 6c4009
    tz = "Universal";
Packit 6c4009
Packit 6c4009
  /* A leading colon means "implementation defined syntax".
Packit 6c4009
     We ignore the colon and always use the same algorithm:
Packit 6c4009
     try a data file, and if none exists parse the 1003.1 syntax.  */
Packit 6c4009
  if (tz && *tz == ':')
Packit 6c4009
    ++tz;
Packit 6c4009
Packit 6c4009
  /* Check whether the value changed since the last run.  */
Packit 6c4009
  if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0)
Packit 6c4009
    /* No change, simply return.  */
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  if (tz == NULL)
Packit 6c4009
    /* No user specification; use the site-wide default.  */
Packit 6c4009
    tz = TZDEFAULT;
Packit 6c4009
Packit 6c4009
  tz_rules[0].name = NULL;
Packit 6c4009
  tz_rules[1].name = NULL;
Packit 6c4009
Packit 6c4009
  /* Save the value of `tz'.  */
Packit 6c4009
  free (old_tz);
Packit 6c4009
  old_tz = tz ? __strdup (tz) : NULL;
Packit 6c4009
Packit 6c4009
  /* Try to read a data file.  */
Packit 6c4009
  __tzfile_read (tz, 0, NULL);
Packit 6c4009
  if (__use_tzfile)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  /* No data file found.  Default to UTC if nothing specified.  */
Packit 6c4009
Packit 6c4009
  if (tz == NULL || *tz == '\0'
Packit 6c4009
      || (TZDEFAULT != NULL && strcmp (tz, TZDEFAULT) == 0))
Packit 6c4009
    {
Packit 6c4009
      memset (tz_rules, '\0', sizeof tz_rules);
Packit 6c4009
      tz_rules[0].name = tz_rules[1].name = "UTC";
Packit 6c4009
      if (J0 != 0)
Packit 6c4009
	tz_rules[0].type = tz_rules[1].type = J0;
Packit 6c4009
      tz_rules[0].change = tz_rules[1].change = (time_t) -1;
Packit 6c4009
      update_vars ();
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __tzset_parse_tz (tz);
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Figure out the exact time (as a time_t) in YEAR
Packit 6c4009
   when the change described by RULE will occur and
Packit 6c4009
   put it in RULE->change, saving YEAR in RULE->computed_for.  */
Packit 6c4009
static void
Packit 6c4009
compute_change (tz_rule *rule, int year)
Packit 6c4009
{
Packit 6c4009
  time_t t;
Packit 6c4009
Packit 6c4009
  if (year != -1 && rule->computed_for == year)
Packit 6c4009
    /* Operations on times in 2 BC will be slower.  Oh well.  */
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  /* First set T to January 1st, 0:00:00 GMT in YEAR.  */
Packit 6c4009
  if (year > 1970)
Packit 6c4009
    t = ((year - 1970) * 365
Packit 6c4009
	 + /* Compute the number of leapdays between 1970 and YEAR
Packit 6c4009
	      (exclusive).  There is a leapday every 4th year ...  */
Packit 6c4009
	 + ((year - 1) / 4 - 1970 / 4)
Packit 6c4009
	 /* ... except every 100th year ... */
Packit 6c4009
	 - ((year - 1) / 100 - 1970 / 100)
Packit 6c4009
	 /* ... but still every 400th year.  */
Packit 6c4009
	 + ((year - 1) / 400 - 1970 / 400)) * SECSPERDAY;
Packit 6c4009
  else
Packit 6c4009
    t = 0;
Packit 6c4009
Packit 6c4009
  switch (rule->type)
Packit 6c4009
    {
Packit 6c4009
    case J1:
Packit 6c4009
      /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
Packit 6c4009
	 In non-leap years, or if the day number is 59 or less, just
Packit 6c4009
	 add SECSPERDAY times the day number-1 to the time of
Packit 6c4009
	 January 1, midnight, to get the day.  */
Packit 6c4009
      t += (rule->d - 1) * SECSPERDAY;
Packit 6c4009
      if (rule->d >= 60 && __isleap (year))
Packit 6c4009
	t += SECSPERDAY;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case J0:
Packit 6c4009
      /* n - Day of year.
Packit 6c4009
	 Just add SECSPERDAY times the day number to the time of Jan 1st.  */
Packit 6c4009
      t += rule->d * SECSPERDAY;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case M:
Packit 6c4009
      /* Mm.n.d - Nth "Dth day" of month M.  */
Packit 6c4009
      {
Packit 6c4009
	unsigned int i;
Packit 6c4009
	int d, m1, yy0, yy1, yy2, dow;
Packit 6c4009
	const unsigned short int *myday =
Packit 6c4009
	  &__mon_yday[__isleap (year)][rule->m];
Packit 6c4009
Packit 6c4009
	/* First add SECSPERDAY for each day in months before M.  */
Packit 6c4009
	t += myday[-1] * SECSPERDAY;
Packit 6c4009
Packit 6c4009
	/* Use Zeller's Congruence to get day-of-week of first day of month. */
Packit 6c4009
	m1 = (rule->m + 9) % 12 + 1;
Packit 6c4009
	yy0 = (rule->m <= 2) ? (year - 1) : year;
Packit 6c4009
	yy1 = yy0 / 100;
Packit 6c4009
	yy2 = yy0 % 100;
Packit 6c4009
	dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
Packit 6c4009
	if (dow < 0)
Packit 6c4009
	  dow += 7;
Packit 6c4009
Packit 6c4009
	/* DOW is the day-of-week of the first day of the month.  Get the
Packit 6c4009
	   day-of-month (zero-origin) of the first DOW day of the month.  */
Packit 6c4009
	d = rule->d - dow;
Packit 6c4009
	if (d < 0)
Packit 6c4009
	  d += 7;
Packit 6c4009
	for (i = 1; i < rule->n; ++i)
Packit 6c4009
	  {
Packit 6c4009
	    if (d + 7 >= (int) myday[0] - myday[-1])
Packit 6c4009
	      break;
Packit 6c4009
	    d += 7;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	/* D is the day-of-month (zero-origin) of the day we want.  */
Packit 6c4009
	t += d * SECSPERDAY;
Packit 6c4009
      }
Packit 6c4009
      break;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
Packit 6c4009
     Just add the time of day and local offset from GMT, and we're done.  */
Packit 6c4009
Packit 6c4009
  rule->change = t - rule->offset + rule->secs;
Packit 6c4009
  rule->computed_for = year;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Figure out the correct timezone for TM and set `__tzname',
Packit 6c4009
   `__timezone', and `__daylight' accordingly.  */
Packit 6c4009
void
Packit 6c4009
__tz_compute (time_t timer, struct tm *tm, int use_localtime)
Packit 6c4009
{
Packit 6c4009
  compute_change (&tz_rules[0], 1900 + tm->tm_year);
Packit 6c4009
  compute_change (&tz_rules[1], 1900 + tm->tm_year);
Packit 6c4009
Packit 6c4009
  if (use_localtime)
Packit 6c4009
    {
Packit 6c4009
      int isdst;
Packit 6c4009
Packit 6c4009
      /* We have to distinguish between northern and southern
Packit 6c4009
	 hemisphere.  For the latter the daylight saving time
Packit 6c4009
	 ends in the next year.  */
Packit 6c4009
      if (__builtin_expect (tz_rules[0].change
Packit 6c4009
			    > tz_rules[1].change, 0))
Packit 6c4009
	isdst = (timer < tz_rules[1].change
Packit 6c4009
		 || timer >= tz_rules[0].change);
Packit 6c4009
      else
Packit 6c4009
	isdst = (timer >= tz_rules[0].change
Packit 6c4009
		 && timer < tz_rules[1].change);
Packit 6c4009
      tm->tm_isdst = isdst;
Packit 6c4009
      tm->tm_zone = __tzname[isdst];
Packit 6c4009
      tm->tm_gmtoff = tz_rules[isdst].offset;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Reinterpret the TZ environment variable and set `tzname'.  */
Packit 6c4009
#undef tzset
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__tzset (void)
Packit 6c4009
{
Packit 6c4009
  __libc_lock_lock (tzset_lock);
Packit 6c4009
Packit 6c4009
  tzset_internal (1);
Packit 6c4009
Packit 6c4009
  if (!__use_tzfile)
Packit 6c4009
    {
Packit 6c4009
      /* Set `tzname'.  */
Packit 6c4009
      __tzname[0] = (char *) tz_rules[0].name;
Packit 6c4009
      __tzname[1] = (char *) tz_rules[1].name;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __libc_lock_unlock (tzset_lock);
Packit 6c4009
}
Packit 6c4009
weak_alias (__tzset, tzset)
Packit 6c4009

Packit 6c4009
/* Return the `struct tm' representation of *TIMER in the local timezone.
Packit 6c4009
   Use local time if USE_LOCALTIME is nonzero, UTC otherwise.  */
Packit 6c4009
struct tm *
Packit 6c4009
__tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
Packit 6c4009
{
Packit 6c4009
  long int leap_correction;
Packit 6c4009
  int leap_extra_secs;
Packit 6c4009
Packit 6c4009
  if (timer == NULL)
Packit 6c4009
    {
Packit 6c4009
      __set_errno (EINVAL);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __libc_lock_lock (tzset_lock);
Packit 6c4009
Packit 6c4009
  /* Update internal database according to current TZ setting.
Packit 6c4009
     POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
Packit 6c4009
     This is a good idea since this allows at least a bit more parallelism.  */
Packit 6c4009
  tzset_internal (tp == &_tmbuf && use_localtime);
Packit 6c4009
Packit 6c4009
  if (__use_tzfile)
Packit 6c4009
    __tzfile_compute (*timer, use_localtime, &leap_correction,
Packit 6c4009
		      &leap_extra_secs, tp);
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      if (! __offtime (timer, 0, tp))
Packit 6c4009
	tp = NULL;
Packit 6c4009
      else
Packit 6c4009
	__tz_compute (*timer, tp, use_localtime);
Packit 6c4009
      leap_correction = 0L;
Packit 6c4009
      leap_extra_secs = 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __libc_lock_unlock (tzset_lock);
Packit 6c4009
Packit 6c4009
  if (tp)
Packit 6c4009
    {
Packit 6c4009
      if (! use_localtime)
Packit 6c4009
	{
Packit 6c4009
	  tp->tm_isdst = 0;
Packit 6c4009
	  tp->tm_zone = "GMT";
Packit 6c4009
	  tp->tm_gmtoff = 0L;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
Packit 6c4009
        tp->tm_sec += leap_extra_secs;
Packit 6c4009
      else
Packit 6c4009
	tp = NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return tp;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
libc_freeres_fn (free_mem)
Packit 6c4009
{
Packit 6c4009
  while (tzstring_list != NULL)
Packit 6c4009
    {
Packit 6c4009
      struct tzstring_l *old = tzstring_list;
Packit 6c4009
Packit 6c4009
      tzstring_list = tzstring_list->next;
Packit 6c4009
      free (old);
Packit 6c4009
    }
Packit 6c4009
  free (old_tz);
Packit 6c4009
  old_tz = NULL;
Packit 6c4009
}