TinyMAZE/
TinyMAZE/config/
TinyMAZE/doc/
TinyMAZE/run/msgs/
TinyMAZE/src/
TinyMAZE/src/db/
TinyMAZE/src/ident/
TinyMAZE/src/io/
TinyMAZE/src/prog/
TinyMAZE/src/softcode/
TinyMAZE/src/util/
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#include <ctype.h>
#include <string.h>
#include "externs.h"
#include "db.h"
#include "config.h"
#include "gametime.h"

static long get_timezone()
{
  struct timeval tv;
  struct timezone tz;

  gettimeofday(&tv, &tz);
  return(tz.tz_minuteswest*60);
}

static void get_tz(char *tz, char **tzp, int *lyp)
{
  char *s;

  *lyp = 0;
  *tzp = tz;
  if(*tzp != NULL)
    if(**tzp != '\0')
      if((s = strchr(*tzp, ':')) != NULL)
      {
	++s;
        if(*s == 'Y' || *s == 'y')
          *lyp = 1;
      }
}

static void get_thing_tz(OBJ *thing, char **tzp, int *lyp)
{
  char *s;

  *tzp = atr_get(thing, "TZ");
  if(**tzp == '\0')
    *tzp = atr_get(thing->owner, "TZ");

  if(**tzp == '\0')
    *lyp = 0;
  else
  {
    if((s = strchr(*tzp, ':')) == NULL)
      *lyp = 0;
    else
    {
      ++s;
      if(*s == 'Y' || *s == 'y')
      *lyp = 1;
    }
  }
}

char *mktm(time_t cl, char *tz, OBJ *thing)
{
  int ly;
  char *s;
  struct tm *tmp;
  long adjust, utcdiff;

  if(tz == NULL)
    tz = "";
  if(*tz == 'D' || *tz == '\0')
    get_thing_tz(thing, &tz, &ly);
  else if(*tz != 'N')
    get_tz(tz, &tz, &ly);

/* Determine time diff between gmt and local standard time */
  utcdiff = get_timezone();
  tmp = localtime(&cl);
  if(tmp)
    if(tmp->tm_isdst)
      utcdiff -= 3600L;

/* Get or calculate timezone adjustment */
  if(*tz == '\0')
    adjust = utcdiff;
  else
  {
    adjust = 0L - atol(tz) * 3600L;
    if(ly && tmp->tm_isdst > 0)
      adjust -= 3600L;
  }

/* Adjust for timezone */
  cl += (utcdiff - adjust);

/* Generate ascii string */
  s = ctime(&cl);
  *(s+strlen(s)-1) = '\0';
  return(s);
}

/* this routine is designed to interpret a wide variety of time string
   formats converting them all to a longint x-value time representation */
long mkxtime(char *s, OBJ *thing, char *tz)
{
  int i, j, ly;
  long cl, adjust, utcdiff;
  char *p, *q = s, *dayp, *yearp = NULL;
  int seconds, minutes, hours, day, month, year;
  struct tm tmbuf;
  static int tadjust[] = {
       0,    -4,    -5,    -5,    -6,    -6,    -7,    -7,    -8
  };
  static char *tname[] = {
    "gmt", "edt", "est", "cdt", "cst", "mdt", "mst", "pdt", "pst", NULL
  };
  static char *mname[] = {
    "jan", "feb", "mar", "apr", "may", "jun",
    "jul", "aug", "sep", "oct", "nov", "dec", NULL
  };

/* Locate month if present */
  month = -1;
  for(p = s;month < 0 && *p;p++)
  {
    if(isalpha(*p))
      for(i = 0;mname[i];i++)
      {
        j = 0, q = p;
        while(mname[i][j] && mname[i][j] == tolower(*q))
          ++j, ++q;
        if(!mname[i][j])
        {
	  month = i;
	  break;
	}
      }
  }
  if(month < 0)
    return(-1L);

 /* Skip remaining string and whitespace */
  for(p = q;isalpha(*p);p++);
  for(;isspace(*p);p++);

/* Get day */
  day = -1;
  if(isdigit(*p))
    day = atoi(p);
  if(day < 1 || day > 31)
    return(-1L);
  dayp = p;

 /* Get year */
  year = -1;
  for(p = s;*p;p++)
    if(isdigit(*p))
    {
      year = atoi(p);
      if(year < 1900)
      {
        year = -1;
        for(;isdigit(*p);p++);
	continue;
      }
      yearp = p;
      break;
    }
  if(year < 0)
    return(-1L);

/* Get hours */
  hours = -1;
  for(p = s;*p;p++)
    if(isdigit(*p))
    {
      hours = atoi(p);
      if(p == dayp || p == yearp || hours < 0 || hours > 59)
      {
        hours = -1;
        for(;isdigit(*p);p++);
        continue;
      }
      break;
    }
  if(hours < 0)
    return(-1L);
  for(;isdigit(*p);p++);

/* Get minutes */
  minutes = -1;
  if(*p == ':')
    minutes = atoi(++p);
  if(minutes < 0 || minutes > 59)
    return(-1L);
  for(;isdigit(*p);p++);

/* Get seconds */
  seconds = -1;
  if(*p == ':')
    seconds = atoi(++p);
  if(seconds < 0 || seconds > 59)
    return(-1L);

  tmbuf.tm_sec   = seconds;
  tmbuf.tm_min   = minutes;
  tmbuf.tm_hour  = hours;
  tmbuf.tm_mday  = day;
  tmbuf.tm_mon   = month;
  tmbuf.tm_year  = year - 1900;
  tmbuf.tm_isdst = -1;
  cl = mktime(&tmbuf);

/* Determine time diff between gmt and local standard time */
/* (for the time calculated) */
  utcdiff = (tmbuf.tm_isdst > 0)?get_timezone() - 3600L:get_timezone();

/* Calculate timezone adjustment */
  if(!tz)
    tz = "";
  if(*tz == 'D' || !*tz)
    get_thing_tz(thing, &tz, &ly);
  else
    get_tz(tz, &tz, &ly);
  if(!*tz)
    adjust = utcdiff;
  else
  {
    adjust = 0L - atol(tz) * 3600L;
    if(ly && tmbuf.tm_isdst > 0)
      adjust -= 3600L;
  }

/* Check for timezone override in string specification */
  for(p = s;*p;p++)
    if(isalpha(*p))
    {
      for(i = 0;tname[i];i++)
      {
        j = 0; q = p;
        while(tname[i][j] && tname[i][j] == tolower(*q))
          ++j, ++q;
        if(!tname[i][j])
        {
	  adjust = 0L - (3600L * (long) (tadjust[i]));
	  goto OUT;
	}
      }
    }
OUT:

  cl += (adjust - utcdiff);
  return(cl);
}

char *make_human_time(int seconds)
{
  char buf[4096];
  const long sec_per_year = 31104000L;
  const long sec_per_month = 2592000L;
  const long sec_per_day = 86400L;

  if(seconds >= sec_per_year)
    sprintf(buf, "%ld year%s", seconds/sec_per_year,
      check_plural(seconds/sec_per_year, "", "s"));
  else if(seconds >= sec_per_month)
    sprintf(buf, "%ld month%s", seconds/sec_per_month,
      check_plural(seconds/sec_per_month, "", "s"));
  else
    sprintf(buf, "%ld day%s", seconds/sec_per_day,
      check_plural(seconds/sec_per_day, "", "s"));

  return(stack_string_alloc(buf, 0));
}

char *time_format(time_t ticks, int num_fields)
{
  struct
  {
    char suffix;
    time_t length;
    int amount;
  } data[6] =
  {
    { 'y', SEC_PER_YEAR, 0 },
    { 'w', SEC_PER_WEEK, 0 },
    { 'd', SEC_PER_DAY, 0 },
    { 'h', SEC_PER_HOUR, 0 },
    { 'm', SEC_PER_MINUTE, 0 },
    { 's', 1, 0 },
  };
  char buf[4096] = "";
  int i, j, first = 0;

  for(i = 0;i < 6;++i)
  {
    data[i].amount = ticks / data[i].length;
    ticks -= data[i].amount * data[i].length;
  }

  for(i = 0;i < 5;++i)     /* Don't pass seconds up */
    if(data[i].amount)
      break;

  for(j = 0;j < num_fields && i < 6;++j, ++i)
  {
    if(!first++)
      sprintf(buf+strlen(buf), "%d%c", data[i].amount, data[i].suffix);
    else
      sprintf(buf+strlen(buf), " %2d%c", data[i].amount, data[i].suffix);
  }

  return(stack_string_alloc(buf, 0));
}

unsigned int my_rand(void)
{
#ifdef USE_DEV_URANDOM
  static unsigned int num_list[URANDOM_BURST], offset = -1;
  static int disable = 0;
  extern int rand_fd;
#endif /* USE_DEV_URANDOM */

#ifndef USE_DEV_URANDOM
  return(rand());
#else
  if(disable)
    return(rand());

  if(offset < 0 || offset >= URANDOM_BURST)
  {
    if(read(rand_fd, num_list, sizeof(int)*URANDOM_BURST) == -1)
    {
      log_error("Couldn't read from /dev/urandom. Disabling.");
      disable = 1;
      return(rand());
    }
    offset = 0;
  }

  return(num_list[offset++]);
#endif /* USE_DEV_URANDOM */
}