{ Copyright (C) 2005 Bas Steendijk and Peter Green
  For conditions of distribution and use, see copyright notice in zlib_license.txt
  which is included in the package
  ----------------------------------------------------------------------------- }

{$ifdef fpc}
  {$mode delphi}
{$endif}

unit ltimevalstuff;
interface


{$ifdef CONDITIONALEXPRESSIONS}{$define support_int64}{$endif}    //delphi 6 or later
{$ifdef fpc}{$define support_int64}{$endif}

{$ifdef mswindows}
  type
    ttimeval = record
      {$IFDEF support_int64}
      tv_sec : int64;
      {$ELSE}
      tv_sec : longint;
      {$ENDIF}
      tv_usec : longint;
    end;
{$else}
  {$ifdef ver1_0}
    uses linux;
  {$else}
    uses 
      {$ifdef linux}linux,{$endif} //for clock_gettime
      {$ifdef freebsd}freebsd,{$endif} //for clock_gettime      
      baseunix,unix,unixutil,sockets;
  {$endif}
{$endif}
                                

procedure tv_add(var tv:ttimeval;msec:integer);
function tv_compare(const tv1,tv2:ttimeval):boolean;
procedure tv_subtract(var tv:ttimeval;const tv2:ttimeval);
procedure msectotimeval(var tv:ttimeval;msec:integer);

{$ifdef unix}
//for internal use by lcore as a replacement for gettimeofday -beware
procedure gettimemonotonic(var tv:ttimeval);
{$endif}

//tv_invalidtimebig will always compare as greater than any valid timeval
//unfortunately unixstuff.inc hasn't worked it's magic yet so we
//have to ifdef this manually.
const
  {$ifdef ver1_0}
    tv_invalidtimebig : ttimeval = (sec:maxlongint;usec:maxlongint);
  {$else}
    tv_invalidtimebig : ttimeval = (tv_sec:maxlongint;tv_usec:maxlongint);
  {$endif}
implementation

{$i unixstuff.inc}

{add nn msec to tv}
procedure tv_add(var tv:ttimeval;msec:integer);
begin
  inc(tv.tv_usec,msec*1000);
  inc(tv.tv_sec,tv.tv_usec div 1000000);
  tv.tv_usec := tv.tv_usec mod 1000000;
end;

{tv1 >= tv2}
function tv_compare(const tv1,tv2:ttimeval):boolean;
begin
  if tv1.tv_sec = tv2.tv_sec then begin
    result := tv1.tv_usec >= tv2.tv_usec;
  end else result := tv1.tv_sec > tv2.tv_sec;
end;

procedure tv_subtract(var tv:ttimeval;const tv2:ttimeval);
begin
  dec(tv.tv_usec,tv2.tv_usec);
  if tv.tv_usec < 0 then begin
    inc(tv.tv_usec,1000000);
    dec(tv.tv_sec)
  end;
  dec(tv.tv_sec,tv2.tv_sec);
end;

procedure msectotimeval(var tv:ttimeval;msec:integer);
begin
  tv.tv_sec := msec div 1000;
  tv.tv_usec := (msec mod 1000)*1000;
end;


{$ifdef unix}
{$ifdef linux}{$define have_clock_gettime}{$endif}
{$ifdef freebsd}{$define have_clock_gettime}{$endif}

procedure gettimemonotonic(var tv:ttimeval);
var
  ts:ttimespec;
begin
  {$ifdef have_clock_gettime}
  if (clock_gettime(CLOCK_MONOTONIC, @ts) = 0) then begin
    tv.tv_sec := ts.tv_sec;
    tv.tv_usec := ts.tv_nsec div 1000;
    exit;
  end;
  {$endif}
  gettimeofday(tv);
end;
{$endif}

end.
