/*
 * ANSI/POSIX functions not available (or poorly implemented) for NetWare
 * Written by Cyrus Patel <cyp@fb14.uni-mainz.de>
 *
 * Includes:
 *   ftime(2)  [ANSI/SYS V]
 *             NB: ftime() is a deprecated function most places and is 
 *             usually implemented as a wrapper to POSIX' gettimeofday().
 *   usleep(2) [BSD 4.3]
 *   sleep(3)  [POSIX 1]
 *
*/

#include <time.h>                       /* time_t and time(time_t *) */

#pragma pack(1)                         
struct timeb {                          /* from <sys/timeb.h> */
        time_t  time;                   /* seconds since the Epoch */
        unsigned short millitm;         /* + milliseconds since the Epoch */
        short   timezone;               /* minutes west of CUT */
        short   dstflag;                /* DST == non-zero */
};
#pragma pack()

#ifdef __cplusplus   /* avoid pulling in *any* non-standard headers */
extern "C" {
#endif
extern unsigned long GetCurrentTicks(void);
extern void delay(unsigned int);

extern int timezone; /* declared in nwtime.h as macros to functions */
extern int daylight; /* but they're only on 4.x and bad decls anyway */
                     /* eg timezone is declared as (unsigned) time_t! */

int ftime(struct timeb *tb); /* this is us */
unsigned int sleep(unsigned int);
void usleep(unsigned long);

#ifdef __cplusplus
}
#endif

int ftime(struct timeb *tb)
{
  if (tb)
  {
    static unsigned int last_hsecs = 999;
    static time_t last_secs;
    unsigned long hsecs;
    time_t secs;
    
    /* this section is equivalent to clock(); */
    {
      static unsigned long base_ticks = 0xfffffffful;
      unsigned long ticks = GetCurrentTicks();
      if (base_ticks == 0xfffffffful || base_ticks > ticks)
        base_ticks = ticks; /* just some number <= ticks */
      hsecs = (((ticks - base_ticks) * 11UL) >> 1);
      hsecs -= (hsecs / 738UL);
    }
    
    secs = time(NULL);
    hsecs %= 100; /* we only want the fraction */
    if (last_hsecs != 999)
    {
      if ((secs < last_secs) || (secs == last_secs && hsecs < last_hsecs))
      {
        secs = last_secs;
        hsecs = last_hsecs;
      } 
    }
    last_secs = secs;
    last_hsecs = hsecs;
  
    tb->time = secs;                          /* seconds since the Epoch */
    tb->millitm = (unsigned short)(hsecs*10); /* + millisecs since the Epoch */
    tb->timezone = (short)(-(((int)timezone)/60)); /* minutes west of CUT */
    tb->dstflag = (daylight != 0);
  }
  return 0;
} 

/* ===================================================================== */

#if 0
  /* timezone is "bug compatible" with the SDK - *VERY* stupid mistake. */
  #ifndef _TIME_T
  # define _TIME_T 
  typedef unsigned long time_t; /* BAD BAD BAD BAD BAD */
  #endif
  #ifndef timezone
  extern time_t timezone;       /* SEE! SEE! SEE! SEE! SEE! :) */
  #endif
  #ifndef daylight
  extern int    daylight;
  #endif
  extern int    *__get_daylight( void ); 
  extern time_t *__get_timezone( void ); /* YUCK! */
  extern char  **__get_tzname( void );
#endif

/* We support these here just in case <nwtime.h> got included somewhere */
int     *__get_daylight( void )   { return &daylight;  }
time_t  *__get_timezone( void )   { return ((time_t *)&timezone);  }
/* we could support this but we don't because of the tzname redef in time.h */
#if 0
char   **__get_tzname( void )     { return &tzname[0]; }
#endif
/* unsupported novell'isms */
#if 0
time_t  *__get_altzone( void );
time_t  *__get_daylightOffset( void );
int     *__get_daylightOnOff( void );
#endif

/* ===================================================================== */

static unsigned int _xsleep(register unsigned int secs, 
                            register unsigned long usecs )
{
  unsigned int remainder = 0;
  if (secs == 0 && usecs < 10000)
    ThreadSwitchLowPriority();
  else if (secs == 0 && usecs <= 55000)
    delay(0);
  else      
  {  
    unsigned int interval = ((secs*1000)+((usecs+500)/1000));
    unsigned long sleptfor, t1 = GetCurrentTicks();
    delay( interval );
    sleptfor = GetCurrentTicks();
    if (sleptfor < t1)
    {
      sleptfor += ~t1;
      t1 = 0;
    }
    if (( sleptfor = (((sleptfor - t1)*182)/10) ) < interval )
      remainder = (interval - sleptfor);
  }
  return remainder;
}  

void usleep(unsigned long usec)       { _xsleep(0,usec);return; }
unsigned int sleep(unsigned int secs) { return _xsleep(secs,0); }

