#include <sys/syscall.h>
#include <sys/time.h>
#include <errno.h>
#include <linux/timex.h>

inline static
_syscall1(int, adjtimex, struct timex *, ntx);

#define SIMPLE_ADJTIME

int
__adjtime(struct timeval * itv, struct timeval * otv)
{
  struct timex tntx;

#ifdef SIMPLE_ADJTIME
  if (itv)
  {
    /* This is too big. */
    if (itv->tv_sec || itv->tv_usec <= -(1 << (31 - SHIFT_UPDATE))
	|| itv->tv_usec >= (1 << (31 - SHIFT_UPDATE)))
    {
      errno = EINVAL;
      return -1;
    }

    tntx.offset = itv->tv_usec;
    tntx.mode = ADJ_OFFSET_SINGLESHOT;
  }
  else
  {
    tntx.mode = 0;
  }
  if (adjtimex(&tntx) < 0) return -1;
#else
#define SLEEP_SEC	0
#define SLEEP_USEC	200000

  if (itv)
  {
    int offset, i, step;
    struct timeval tmp = *itv, timeout; 

    /* This is too big. */
    if (tmp.tv_sec)
    {
      step = (tmp.tv_sec > 0) ? 1 : -1;
      offset = (step > 0) ? 100000 : -100000;
      do {
	for (i = 0; i < 10; i++)
	{
	  tntx.mode = ADJ_OFFSET_SINGLESHOT;
	  tntx.offset = offset;
	  if (adjtimex(&tntx) < 0) return -1;

	  do
	  {
	    /* We have to sleep for a while. */
	    timeout.tv_sec = SLEEP_SEC;
	    timeout.tv_usec = SLEEP_USEC;
	    printf ("Sleep: sec: %d usec: %d\n",
	    	timeout.tv_sec, timeout.tv_usec);
	    select(1, NULL, NULL, NULL, &timeout);
	    tntx.mode = 0;
	    if (adjtimex(&tntx) < 0) return -1;
	    printf ("After sleep: to do: usec: %d\n", tntx.offset); 
	  } while (tntx.offset != 0); 
	}
        tmp.tv_sec -= step;
      } while (tmp.tv_sec);
    }

    /* This one is too. */
    if (tmp.tv_usec <= -(1 << (31 - SHIFT_UPDATE))
	|| tmp.tv_usec >= (1 << (31 - SHIFT_UPDATE)))
    {
      offset = (tmp.tv_usec > 0) ? 100000 : -100000;
      do {
	tntx.mode = ADJ_OFFSET_SINGLESHOT;
	tntx.offset = offset;
	if (adjtimex(&tntx) < 0) return -1;
	do
	{
	  /* We have to sleep for a while. */
	  timeout.tv_sec = SLEEP_SEC;
	  timeout.tv_usec = SLEEP_USEC;
	  printf ("Sleep: sec: %d usec: %d\n",
	    	timeout.tv_sec, timeout.tv_usec);
	  select(1, NULL, NULL, NULL, &timeout);
	  tntx.mode = 0;
	  if (adjtimex(&tntx) < 0) return -1;
	  printf ("After sleep: to do: usec: %d\n", tntx.offset); 
	} while (tntx.offset != 0); 
        tmp.tv_usec -= offset;
      } while (tmp.tv_usec <= -(1 << (31 - SHIFT_UPDATE))
	|| tmp.tv_usec >= (1 << (31 - SHIFT_UPDATE)));
    }

    /* Well, we can handle that. */
    tntx.mode = ADJ_OFFSET_SINGLESHOT;
    tntx.offset = tmp.tv_usec;
  }
  else
  {
    tntx.mode = 0;
  }
  if (adjtimex(&tntx) < 0) return -1;
#endif
  if (otv)
  {
    otv->tv_usec = tntx.offset;
    otv->tv_sec = 0;
  }
  return 0;
}
