/* tzset.c (emx+gcc) -- Copyright (c) 1992-1996 by Kai Uwe Rommel */
/*                      Copyright (c) 1996 by Eberhard Mattes */

#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/timeb.h>
#include <emx/time.h>
#include <emx/syscalls.h>

int _daylight = 0;
long _timezone = 0;
char *_tzname[2] = {"GMT", ""};

struct _tzinfo _tzi = {"GMT", "", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};


/* Parse a decimal number.  Return a non-zero value if successful,
   zero on error. */

static int dnum (int *dst, char **pp, int min, int max, int opt_sign,
                 int delim)
{
  char *p;
  int n, sign, amax;

  p = *pp; n = 0; sign = 1;

  /* Optional sign. */

  if (opt_sign)
    {
      if (*p == '+')
        ++p;
      else if (*p == '-')
        sign = -1, ++p;
    }

  /* There must be at least one digit. */

  if (!(*p >= '0' && *p <= '9'))
    return 0;

  /* Compute the maximum absolute value of the number.  This is used
     to detect overflow. */

  amax = max;
  if (-min > amax) amax = -min;
  do
    {
      n = n * 10 + *p - '0';
      if (n > amax) return 0;   /* Overflow */
      ++p;
    } while (*p >= '0' && *p <= '9');

  /* Check the delimiter if DELIM is not -1. */

  if (delim != -1 && *p++ != delim)
    return 0;

  /* Apply the sign. */

  if (sign == -1)
    n = -n;

  /* Check the range. */

  if (n < min || n > max)
    return 0;

  /* Return the result. */

  *dst = n;
  *pp = p;
  return 1;
}


/* Copy a timezone name.  Return a non-zero value if successful, zero
   on error. */

static int copy_tzname (char *dst, char **pp)
{
  char *p;
  int i;

  p = *pp;

  /* Check the supposed timezone name for validity.  See ISO 9945-1,
     8.1.1 for details. */

  if (*p == ':' || (*p >= '0' && *p <= '9'))
    return 0;
  for (i = 0; i < 3; ++i)
    if (p[i] == 0 || p[i] == ',' || p[i] == '-' || p[i] == '+')
      return 0;

  /* The timezone name is valid. */

  memcpy (dst, p, 3);
  dst[3] = 0;
  *pp = p + 3;
  return 1;
}


void _tzset (void)
{
  struct _tzinfo ntz;
  struct timeb tb;
  char *p;
  int sign, offset, temp;
  time_t t_loc;

  p = getenv ("TZ");
  if (p == NULL)
    p = "GMT0";                 /* Our best approximation :-) */
  if (*p == 0)
    p = "GMT0";

  if (!copy_tzname (ntz.tzname, &p))
    return;

  if (*p == 0)
    offset = sign = 0;          /* TZ=XYZ is valid (in contrast to POSIX.1) */
  else
    {
      if (!dnum (&offset, &p, -24, 24, 1, -1))
        return;
      if (offset < 0)
        sign = -1, offset = -offset;
      else
        sign = 1;

      offset *= 60;
      if (*p == ':')            /* Minutes specified? */
        {
          ++p;
          if (!dnum (&temp, &p, 0, 59, 0, -1))
            return;
          offset += temp;
        }

      offset *= 60;
      if (*p == ':')            /* Seconds specified? */
        {
          ++p;
          if (!dnum (&temp, &p, 0, 59, 0, -1))
            return;
          offset += temp;
        }
    }

  ntz.tz = sign > 0 ? offset : -offset;

  ntz.dst = 0;
  ntz.dstzname[0] = 0;

  if (*p != 0)
    {
      ntz.dst = 1;
      if (!copy_tzname (ntz.dstzname, &p))
        return ;
      if (*p == ',')
        {
          ++p;
          if (!dnum (&ntz.sm, &p, 1, 12, 0, ',')
              || !dnum (&ntz.sw, &p, -4, 4, 1, ',')
              || !dnum (&ntz.sd, &p, ntz.sw ? 0 : 1, ntz.sw ? 6 : 31, 0, ',')
              || !dnum (&ntz.st, &p, 0, 86399, 0, ',')
              || !dnum (&ntz.em, &p, 1, 12, 0, ',')
              || !dnum (&ntz.ew, &p, -4, 4, 1, ',')
              || !dnum (&ntz.ed, &p, ntz.ew ? 0 : 1, ntz.ew ? 6 : 31, 0, ',')
              || !dnum (&ntz.et, &p, 0, 86399, 0, ',')
              || !dnum (&ntz.shift, &p, 0, 86400, 0, 0))
            return;
        }
      else if (*p == 0)
        {
          /* VAC++ default values */

          ntz.sm = 4;  ntz.sw =  1; ntz.sd = 0; ntz.st = 3600;
          ntz.em = 10; ntz.ew = -1; ntz.ed = 0; ntz.et = 7200;
          ntz.shift = 3600;
        }
      else
        {
          /* TODO: POSIX.1 */
          return;
        }
    }

  /* TODO: Make this thread-safe! */
  _tzi = ntz;
  _tzname[0] = _tzi.tzname;
  _tzname[1] = _tzi.dstzname;
  _compute_dst_table ();

  __ftime (&tb);
  t_loc = tb.time;
  _daylight = _loc2gmt (&tb.time, -1);
  _timezone = (int)(tb.time - t_loc);

  _tzset_flag = 1;
}
