/* 
 * Copyright distributed.net 1997-1998 - All Rights Reserved
 * For use in distributed.net projects only.
 * Any other distribution or use of this source violates copyright.
 * 
 * Written by Cyrus Patel <cyp@fb14.uni-mainz.de>
 *
 * ------------------------------------------------------------------
 * POSIX gettimeofday() and significantly more accurate than ftime()
 * caveat: the timezone.tz_dsttime member is not accurate. There is no
 * way to translate the ANSI timezone variable to the dsttime DST_* code.
 * ------------------------------------------------------------------
 *
*/
const char *cdostime_cpp(void) {
return "@(#)$Id: cdostime.cpp,v 1.1.2.1 1999/07/14 22:51:44 cyp Exp $"; }

#include <time.h>
#include <sys/timeb.h>
#include "cdostime.h" /* keep prototypes in sync */

#undef timezone
extern long timezone;


int gettimeofday( struct timeval *tvp, struct __timezone *tzp )
{
  if (tvp)
  {
    #if 1
    struct timeb tb;
    ftime(&tb);
    tvp->tv_sec = tb.time;
    tvp->tv_usec = tb.millitm*1000;
    #else
    time_t t;
    unsigned long ticks,uticks;
    unsigned long secs,usecs;
    _asm 
    {
      push es
      mov  ax,40h
      mov  es,ax
      reread:
      mov  ecx,dword ptr es:[6Ch]
      xor  eax,eax
      out  043h,al
      in   al,040h
      mov  ah,al
      in   al,040h
      mov  edx,dword ptr es:[6Ch]
      cmp  edx,ecx
      jnz  reread
      pop  es
      xchg ah,al
      not  ax           /* timer counts down from 65535 so we flip it */
      mov  ticks,ecx
      mov  uticks,eax
    }
    t = time(NULL);

    ticks%= 65543ul;    /* make sure we only have ticks in the last hour */
                        /* max divisor is 78196 */
    ticks*= 54925;      /* 54935 == micro sec per BIOS clock tick. */

    secs   = t-(t % 3600ul); /* time - secs in last hour */
    usecs  = ( ticks + (( (uticks * 8381ul) + (ticks % 1000) ) / 1000) );
    secs  += usecs/1000000ul;
    usecs %= 1000000ul;

    tvp->tv_sec = secs;
    tvp->tv_usec = usecs;

    /*    
    printf("time() %u calctime() %u.%u %d %.3f\n", t, secs, usecs,
                  t-secs, (((double)t)-((double)secs))/54.925 );
    printf("%s", ctime(&t));
    printf("  %s ", ctime(&secs));
    printf("minwest: %d\n", -(timezone/60) );
    */
    #endif
  }
  if (tzp)
  {
    #if 0
    static int precalced_minuteswest = -12345;
    int minwest = precalced_minuteswest;
    if (minwest == -12345)
    {
      time_t timenow; int haveutctime, haveloctime;
      struct tm * tmP; struct tm loctime, utctime;
      tzset();
      timenow = time(NULL);
      tmP = localtime( (const time_t *) &timenow);
      if ((haveloctime = (tmP != NULL))!=0)
        memcpy( &loctime, tmP, sizeof( struct tm ));
      tmP = gmtime( (const time_t *) &timenow);
      if ((haveutctime = (tmP != NULL))!=0)
        memcpy( &utctime, tmP, sizeof( struct tm ));
      if (!haveutctime || !haveloctime)
        minwest = 0;
      else
      {
        minwest =  ((loctime.tm_min  - utctime.tm_min) )
                  +((loctime.tm_hour - utctime.tm_hour)*60 );
        /* last two are when the time is on a year boundary */
        if      (loctime.tm_yday == utctime.tm_yday)     { ;/* no change */ }
        else if (loctime.tm_yday == utctime.tm_yday + 1) { minwest += 1440; }
        else if (loctime.tm_yday == utctime.tm_yday - 1) { minwest -= 1440; }
        else if (loctime.tm_yday <  utctime.tm_yday)     { minwest += 1440; }
        else                                             { minwest -= 1440; }
        if (utctime.tm_isdst>0)  
          minwest-=60;
        if (minwest < -(12*60)) 
          minwest = -(12*60); 
        else if (minwest > +(12*60)) 
          minwest = +(12*60);
        minwest = -minwest;
        precalced_minuteswest = minwest;

        /* timezone = (-timezone)*60; */
      }
    }
    #endif
    tzp->tz_minuteswest = -(timezone/60);
    tzp->tz_dsttime = (daylight == 0) ? 0 : DST_MET; /* coz thats where I am */
  }
  return 0;
}  
