/*---------------------------------------------------------------------------
 *		
 * MODULE NAME:	timeval
 *
 * DESCRIPTION:	Routines to perform simple arithmetic operations on
 *		Berkeley UNIX 'timeval' structures.
 *
 *		These routines were written because the support routine
 *		rciWallclock() returns a 'struct timeval' and it is useful to
 *		have a few primitives for manipulating this data type.
 *
 *		Note the some primitives are already defined by <sys/time.h>.
 * 
 * CAVEATS:	These routines pass their information by value, rather than by
 *		reference.
 *
 * AUTHOR/DATE:	John Lloyd, Summer 1989.
 *
 * MODIFICATION HISTORY:
 *
 *--------------------------------------------------------------------------*/

/*#include <stdio.h>*/
#include "../h/cdefs.h"
#include "../h/timeval.h"

struct timeval addTimeval(tv1, tv2)
struct timeval tv1, tv2;
{
	/* Return tv1 + tv2 */

	struct timeval tvr;
	int carry = 0;

	tvr.tv_usec = tv1.tv_usec + tv2.tv_usec;
	if (tvr.tv_usec >= 1000000)
	 { tvr.tv_usec -= 1000000;
	   carry = 1;
	 }
	else if (tvr.tv_usec < 0)
	 { tvr.tv_usec += 1000000;
	   carry = -1;
	 }
	tvr.tv_sec = tv1.tv_sec + tv2.tv_sec + carry;
	if (tvr.tv_sec < 0 && tvr.tv_usec > 0)
	 { tvr.tv_sec += 1;
	   tvr.tv_usec -= 1000000;
	 }
	return (tvr);
}

struct timeval negateTimeval(tv1)
struct timeval tv1;
{
	/* Return -tv1 */

	struct timeval tvr;
	tvr.tv_sec = -tv1.tv_sec;
	tvr.tv_usec = -tv1.tv_usec;
	return (tvr);
}

struct timeval diffTimeval(tv1, tv2)
struct timeval tv1, tv2;
{
	/* Return tv1 - tv2 */

	return (addTimeval (tv1, negateTimeval (tv2)));
}

struct timeval doubleToTimeval(d)
double d;
{
	/* Convert a 'double' into a 'struct timeval' */

	struct timeval tvr;
	tvr.tv_sec = d;
	tvr.tv_usec = ((int)(d*1000000))%1000000;
	return (tvr);
}

double timevalToDouble(tv)
struct timeval tv;
{
	/* Convert 'struct timeval' into a 'double' */

	double d;
	d = tv.tv_sec + tv.tv_usec/1000000.0;
	return (d);
}

#ifdef TEST

#include "../h/ctree.h"
char key_buf[256];

main()
{
	char *keytree;
	struct timeval tv1, tv2, tvr;
	float f1, f2;
	double d1, d2, dr;

	keytree = tree_match_parse("					\
(	quit								\
	[add diff]							\
	 (%f", &f1, ",,,	\"first time\"				\
	   (%f", &f2, ",,,	\"second time\"))			\
	negate								\
	 (%f", &f1, ",,,	\"time value\")				\
)",0);
	if (keytree == 0)
	 { printf ("ERROR/Parse error at %.30s\n", tree_match_err_at());
	   exit (-1);
	 }
	do
 	 { tree_match (keytree, "TVTEST> ", key_buf);
	   if (COMMAND ("add"))
	    { d1 = f1; 
	      d2 = f2;
	      tv1 = doubleToTimeval(d1);
	      tv2 = doubleToTimeval(d2);
	      tvr = addTimeval(tv1, tv2);
	      printf ("%d.%06d + %d.%06d = %d.%06d\n", 
		       tv1.tv_sec, tv1.tv_usec,
		       tv2.tv_sec, tv2.tv_usec,
		       tvr.tv_sec, tvr.tv_usec);
	    }
	   else if (COMMAND ("negate"))
	    { d1 = f1;
	      tv1 = doubleToTimeval(d1);
	      tvr = negateTimeval(tv1);
	      printf ("-%d.%06d = %d.%06d\n",
		       tv1.tv_sec, tv1.tv_usec,
		       tvr.tv_sec, tvr.tv_usec);
	    }
	   else if (COMMAND ("diff"))
	    { d1 = f1; 
	      d2 = f2;
	      tv1 = doubleToTimeval(d1);
	      tv2 = doubleToTimeval(d2);
	      tvr = diffTimeval (tv1, tv2);
	      printf ("%d.%06d - %d.%06d = %d.%06d\n", 
		       tv1.tv_sec, tv1.tv_usec,
		       tv2.tv_sec, tv2.tv_usec,
		       tvr.tv_sec, tvr.tv_usec);
	    }
	 }
	while (!(COMMAND("quit")));
}

#endif
