+* added timespecops.{c,h} and tievalops.{c.h} to libntp and include
+ added tspecops.cpp to tests/libntp
(4.2.7p118) 2011/01/15 Released by Harlan Stenn <stenn@ntp.org>
* Simplify the built-sources stuff in sntp/ .
* Fix check for -lipv6 on HP-UX 11.
--- /dev/null
+/*
+ * timespecops.h -- calculations on 'struct timespec' values
+ *
+ * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
+ * The contents of 'html/copyright.html' apply.
+ *
+ * Rationale
+ * ---------
+ *
+ * Doing basic arithmetic on a 'struct timespec' is not exceedingly
+ * hard, but it requires tedious and repetitive code to keep the result
+ * normalised. We consider a timespec normalised when the nanosecond
+ * fraction is in the interval [0 .. 10^9[ ; there are multiple value
+ * pairs of seconds and nanoseconds that denote the same time interval,
+ * but the normalised representation is unique. No two different
+ * intervals can have the same normalised representation.
+ *
+ * Another topic is the representation of negative time intervals.
+ * There's more than one way to this, since both the seconds and the
+ * nanoseconds of a timespec are signed values. IMHO, the easiest way is
+ * to use a complement representation where the nanoseconds are still
+ * normalised, no matter what the sign of the seconds value. This makes
+ * normalisation easier, since the sign of the integer part is
+ * irrelevant, and it removes several sign decision cases during the
+ * calculations.
+ *
+ * As long as no signed integer overflow can occur with the nanosecond
+ * part of the operands, all operations work as expected and produce a
+ * normalised result.
+ *
+ * The exception to this are functions fix a '_fast' suffix, which do no
+ * normalisation on input data and therefore expect the input data to be
+ * normalised.
+ */
+#ifndef TIMPESPECOPS_H
+#define TIMPESPECOPS_H
+
+#include <config.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include "ntp_unixtime.h"
+#include "ntp_fp.h"
+
+
+/*
+ * We avoid to use/define NANOSECONDS here, as it is also defined in
+ * some other files and we don't want to resolve the possible clashes
+ * here.
+ */
+
+/* predicate: returns TRUE if the nanoseconds are out-of-bounds */
+#define timespec_isdenormal(x) \
+ ((u_long)(x)->tv_nsec >= 1000000000)
+
+/* predicate: returns TRUE if the nanoseconds are in nominal range */
+#define timespec_isnormal(x) \
+ ((u_long)(x)->tv_nsec < 1000000000)
+
+
+/*make sure nanoseconds are in nominal range */
+extern void timespec_norm(struct timespec *x);
+
+/* x = a, normlised */
+extern void timespec_copy(struct timespec *x, const struct timespec *a);
+
+/* x = a + b */
+extern void timespec_add(struct timespec *x, const struct timespec *a,
+ const struct timespec *b);
+
+/* x = a + b, b is fraction only */
+extern void timespec_addns(struct timespec *x, const struct timespec *a,
+ long b);
+
+/* x = a + b */
+extern void timespec_sub(struct timespec *x, const struct timespec *a,
+ const struct timespec *b);
+
+/* x = a - b, b is fraction only */
+extern void timespec_subns(struct timespec *x, const struct timespec *a,
+ long b);
+
+/* x = -a */
+extern void timespec_neg(struct timespec *x, const struct timespec *a);
+
+/* x = ( a < 0) ? -a : a
+ * return if negation was needed
+ */
+extern int timespec_abs(struct timespec *x, const struct timespec *a);
+
+/* compare a <--> b
+ * return 1 / 0 / -1 if a < / == / > b
+ */
+extern int timespec_cmp_fast(const struct timespec *a,
+ const struct timespec *b);
+
+extern int timespec_cmp(const struct timespec *a,
+ const struct timespec *b);
+
+/* test a
+ * return 1 / 0 / -1 if a < / == / > 0
+ */
+extern int timespec_test_fast(const struct timespec *a);
+extern int timespec_test(const struct timespec *a);
+
+/* return LIB buffer ptr to string rep */
+extern const char* timespec_tostr(const struct timespec *x);
+
+/*
+ convert to l_fp type, relative and absolute
+*/
+
+/* convert from duration to duration */
+extern void timespec_reltolfp(l_fp *y, const struct timespec *x);
+
+/* 'x' must be UN*X epoch, output will be in NTP epoch */
+extern void timespec_abstolfp(l_fp *y, const struct timespec *x);
+
+/*
+ convert to l_fp type, relative signed/unsigned and absolute
+*/
+extern void timespec_relfromlfp(struct timespec *y, const l_fp *x);
+extern void timespec_urelfromlfp(struct timespec *y, const l_fp *x);
+
+/* absolute (timestamp) conversion. Input is time in NTP epoch, output
+ * is in UN*X epoch. The NTP time stamp will be expanded the pivot time
+ * '*' or the current time, if 'p' is NULL.
+ */
+extern void timespec_absfromlfp(struct timespec *y, const l_fp *x,
+ const time_t *p);
+#endif
+/* -*- EOF -*- */
--- /dev/null
+/*
+ * timevalops.h -- calculations on 'struct timeval' values
+ *
+ * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
+ * The contents of 'html/copyright.html' apply.
+ *
+ * For a rationale look at 'timespecops.h'; we do the same here, but the
+ * normalisation keeps the microseconds in [0 .. 10^6[, of course.
+ */
+#ifndef TIMPEVALOPS_H
+#define TIMPEVALOPS_H
+
+#include <config.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include "ntp_unixtime.h"
+#include "ntp_fp.h"
+
+/*
+ * We avoid to use/define MICROSECONDS here, as it is also possibly
+ * Defined in some other files and we don't want to resolve the possible
+ * clashes here.
+ */
+
+/* predicate: returns TRUE if the microseconds are out-of-bounds */
+/* use like: int timeval_isdenormal(const struct timeval *x) */
+#define timeval_isdenormal(x) \
+ ((u_long)(x)->tv_usec >= 1000000)
+
+/* predicate: returns TRUE if the microseconds are in nominal range */
+/* use like: int timeval_isnormal(const struct timeval *x) */
+#define timeval_isnormal(x) \
+ ((u_long)(x)->tv_usec < 1000000)
+
+
+/*make sure microseconds are in nominal range */
+extern void timeval_norm(struct timeval *x);
+
+/* x = a, normlised */
+extern void timeval_copy(struct timeval *x, const struct timeval *a);
+
+/* x = a + b */
+extern void timeval_add(struct timeval *x, const struct timeval *a,
+ const struct timeval *b);
+
+/* x = a + b, b is fraction only */
+extern void timeval_addus(struct timeval *x, const struct timeval *a,
+ long b);
+
+/* x = a + b */
+extern void timeval_sub(struct timeval *x, const struct timeval *a,
+ const struct timeval *b);
+
+/* x = a - b, b is fraction only */
+extern void timeval_subus(struct timeval *x, const struct timeval *a,
+ long b);
+
+/* x = -a */
+extern void timeval_neg(struct timeval *x, const struct timeval *a);
+
+/* x = ( a < 0) ? -a : a
+ * return if negation was needed
+ */
+extern int timeval_abs(struct timeval *x, const struct timeval *a);
+
+/* compare a <--> b
+ * return 1 / 0 / -1 if a < / == / > b
+ */
+extern int timeval_cmp_fast(const struct timeval *a,
+ const struct timeval *b);
+
+extern int timeval_cmp(const struct timeval *a,
+ const struct timeval *b);
+
+/* test a
+ * return 1 / 0 / -1 if a < / == / > 0
+ */
+extern int timeval_test_fast(const struct timeval *a);
+extern int timeval_test(const struct timeval *a);
+
+/* return LIB buffer ptr to string rep */
+extern const char* timeval_tostr(const struct timeval *x);
+
+/*
+ convert to l_fp type, relative and absolute
+*/
+
+/* convert from duration to duration */
+extern void timeval_reltolfp(l_fp *y, const struct timeval *x);
+
+/* 'x' must be UN*X epoch, output will be in NTP epoch */
+extern void timeval_abstolfp(l_fp *y, const struct timeval *x);
+
+/*
+ convert to l_fp type, relative signed/unsigned and absolute
+*/
+extern void timeval_relfromlfp(struct timeval *y, const l_fp *x);
+extern void timeval_urelfromlfp(struct timeval *y, const l_fp *x);
+
+/* absolute (timestamp) conversion. Input is time in NTP epoch, output
+ * is in UN*X epoch. The NTP time stamp will be expanded the pivot time
+ * '*' or the current time, if 'p' is NULL.
+ */
+extern void timeval_absfromlfp(struct timeval *y, const l_fp *x,
+ const time_t *p);
+
+#endif
+/* -*- EOF -*- */
statestr.c \
strdup.c \
syssignal.c \
+ timespecops.c \
+ timevalops.c \
tsftomsu.c \
tstotv.c \
tvtots.c \
--- /dev/null
+/*
+ * timespecops.c -- calculations on 'struct timespec' values
+ *
+ * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
+ * The contents of 'html/copyright.html' apply.
+ */
+
+#include <config.h>
+#include <math.h>
+
+#include "lib_strbuf.h"
+#include "ntp_calendar.h"
+
+#include "timespecops.h"
+
+#undef NANOSECONDS
+#define NANOSECONDS 1000000000
+
+#if SIZEOF_LONG >= 8
+# define MYFTOTVN(tsf,tvu) \
+ (tvu) = (int32)(((u_long)(tsf) * NANOSECONDS + 0x80000000) >> 32)
+# define MYTVNTOF(tvu,tsf) \
+ (tsf) = (u_int32)((((u_long)(tvu)<<32)+NANOSECONDS/2) / NANOSECONDS)
+#else
+# define MYFTOTVN(tsf,tvu) \
+ (tvu) = (int32)floor((tsf) / 4.294967296 + 0.5)
+# define MYTVNTOF(tvu,tsf) \
+ (tsf) = (u_int32)floor((tvu) * 4.294967296 + 0.5)
+#endif
+
+#define COPYNORM(dst,src) \
+ do { *(dst) = *(src); \
+ if (timespec_isdenormal((dst))) \
+ timespec_norm((dst)); \
+ } while (0)
+
+
+void
+timespec_norm(
+ struct timespec *x
+ )
+{
+#if SIZEOF_LONG > 4
+ /* tv_nsec is of type 'long', and on a 64 bit machine
+ * normalisation by loop becomes prohibitive, once the upper 32
+ * bits become involved. On the other hand, division by constant
+ * should be fast enough; so we do a division of the nanoseconds
+ * if the high dword becomes involved. The floor adjustment step
+ * follows with the standard normalisation loops. */
+ long z;
+
+ z = (x->tv_nsec < 0) ? -x->tv_nsec : x->tv_nsec;
+ if (z >> 32) {
+ z = x->tv_nsec / NANOSECONDS;
+ x->tv_nsec -= z * NANOSECONDS;
+ x->tv_sec += z;
+ }
+#endif
+
+ /* since 10**9 is close to 2**32, we don't divide but do a
+ * normalisation in a loop; this takes 3 steps max, and should
+ * outperform a division even if the mul-by-inverse trick is
+ * employed. */
+ if (x->tv_nsec < 0)
+ do {
+ x->tv_nsec += NANOSECONDS;
+ x->tv_sec -= 1;
+ } while (x->tv_nsec < 0);
+ else if (x->tv_nsec >= NANOSECONDS)
+ do {
+ x->tv_nsec -= NANOSECONDS;
+ x->tv_sec += 1;
+ } while (x->tv_nsec >= NANOSECONDS);
+}
+
+/* x = a, normlised */
+void
+timespec_copy(
+ struct timespec *x,
+ const struct timespec *a
+ )
+{
+ COPYNORM(x,a);
+}
+
+/* x = a + b */
+void
+timespec_add(
+ struct timespec *x,
+ const struct timespec *a,
+ const struct timespec *b
+ )
+{
+ struct timespec c;
+
+ c.tv_sec = a->tv_sec + b->tv_sec;
+ c.tv_nsec = a->tv_nsec + b->tv_nsec;
+ COPYNORM(x, &c);
+}
+
+/* x = a + b, b is fraction only */
+void
+timespec_addns(
+ struct timespec *x,
+ const struct timespec *a,
+ long b
+ )
+{
+ struct timespec c;
+
+ c.tv_sec = a->tv_sec;
+ c.tv_nsec = a->tv_nsec + b;
+ COPYNORM(x, &c);
+}
+
+/* x = a + b */
+void
+timespec_sub(
+ struct timespec *x,
+ const struct timespec *a,
+ const struct timespec *b
+ )
+{
+ struct timespec c;
+
+ c.tv_sec = a->tv_sec - b->tv_sec;
+ c.tv_nsec = a->tv_nsec - b->tv_nsec;
+ COPYNORM(x, &c);
+}
+
+/* x = a - b, b is fraction only */
+void
+timespec_subns(
+ struct timespec *x,
+ const struct timespec *a,
+ long b
+ )
+{
+ struct timespec c;
+
+ c.tv_sec = a->tv_sec;
+ c.tv_nsec = a->tv_nsec - b;
+ COPYNORM(x, &c);
+}
+
+/* x = -a */
+void
+timespec_neg(
+ struct timespec *x,
+ const struct timespec *a
+ )
+{
+ struct timespec c;
+
+ c.tv_sec = - a->tv_sec;
+ c.tv_nsec = - a->tv_nsec;
+ COPYNORM(x, &c);
+}
+
+/* x = ( a < 0) ? -a : a
+ * return if negation was needed
+ */
+int
+timespec_abs(
+ struct timespec *x,
+ const struct timespec *a
+ )
+{
+ struct timespec c;
+ int r;
+
+ COPYNORM(&c, a);
+ if ((r = (c.tv_sec < 0)) != 0) {
+ c.tv_sec = - c.tv_sec;
+ c.tv_nsec = - c.tv_nsec;
+ if (c.tv_nsec < 0) {
+ c.tv_sec -= 1;
+ c.tv_nsec += NANOSECONDS;
+ }
+ }
+ *x = c;
+
+ return r;
+}
+
+/* compare a <--> b
+ * return 1 / 0 / -1 if a < / == / > b
+ */
+int
+timespec_cmp_fast(
+ const struct timespec *a,
+ const struct timespec *b
+ )
+{
+ int r;
+
+ r = (a->tv_sec > b->tv_sec)
+ - (a->tv_sec < b->tv_sec);
+ if (r == 0)
+ r = (a->tv_nsec > b->tv_nsec)
+ - (a->tv_nsec < b->tv_nsec);
+
+ return r;
+}
+
+int
+timespec_cmp(
+ const struct timespec *a,
+ const struct timespec *b
+ )
+{
+ struct timespec A;
+ struct timespec B;
+
+ COPYNORM(&A, a);
+ COPYNORM(&B, b);
+ return timespec_cmp_fast(&A, &B);
+}
+
+/* test a
+ * return 1 / 0 / -1 if a < / == / > 0
+ */
+int
+timespec_test_fast(
+ const struct timespec *a
+ )
+{
+ int r;
+
+ r = (a->tv_sec > 0) - (a->tv_sec < 0);
+ if (r == 0)
+ r = (a->tv_nsec > 0);
+
+ return r;
+}
+
+int
+timespec_test(
+ const struct timespec *a
+ )
+{
+ struct timespec A;
+
+ COPYNORM(&A, a);
+ return timespec_test_fast(&A);
+}
+
+const char*
+timespec_tostr(
+ const struct timespec *x
+ )
+{
+ struct timespec v;
+ int s;
+ char *cp;
+
+ LIB_GETBUF(cp);
+ s = timespec_abs(&v, x);
+ if (v.tv_sec >= 0)
+ snprintf(cp, LIB_BUFLENGTH, "%s%ld.%09ld",
+ "-"+(s==0), (long)v.tv_sec, (long)v.tv_nsec);
+ else if (v.tv_nsec == 0)
+ snprintf(cp, LIB_BUFLENGTH, "%ld.000000000",
+ (long)v.tv_sec);
+ else
+ cp = "#OVERFLOW#";
+
+ return cp;
+}
+
+void
+timespec_abstolfp(
+ l_fp *y,
+ const struct timespec *x
+ )
+{
+ struct timespec v;
+
+ COPYNORM(&v, x);
+ MYTVNTOF(v.tv_nsec, y->l_uf);
+ y->l_ui = (u_int32)v.tv_sec + JAN_1970;
+}
+
+void
+timespec_reltolfp(
+ l_fp *y,
+ const struct timespec *x
+ )
+{
+ struct timespec v;
+
+ COPYNORM(&v, x);
+ MYTVNTOF(v.tv_nsec, y->l_uf);
+ y->l_i = (int32)v.tv_sec;
+
+}
+
+
+void
+timespec_relfromlfp(
+ struct timespec *y,
+ const l_fp *x)
+{
+ struct timespec out;
+
+ MYFTOTVN(x->l_uf, out.tv_nsec);
+ out.tv_sec = x->l_i;
+ COPYNORM(y, &out);
+}
+
+void
+timespec_urelfromlfp(
+ struct timespec *y,
+ const l_fp *x)
+{
+ struct timespec out;
+
+ MYFTOTVN(x->l_uf, out.tv_nsec);
+ out.tv_sec = x->l_ui;
+ COPYNORM(y, &out);
+}
+
+void
+timespec_absfromlfp(
+ struct timespec *y,
+ const l_fp *x,
+ const time_t *p
+ )
+{
+ struct timespec out;
+ vint64 sec;
+
+ sec = ntpcal_ntp_to_time(x->l_ui, p);
+ MYFTOTVN(x->l_uf, out.tv_nsec);
+
+ /* copying a vint64 to a time_t needs some care... */
+# ifdef HAVE_INT64
+ out.tv_sec = (time_t)sec.q_s;
+# elif SIZEOF_TIME_T > 4
+ out.tv_sec = ((time_t)sec.d_s.hi << 32) + sec.d_s.lo;
+# else
+ out.tv_sec = (time_t)sec.d_s.lo;
+# endif
+
+ COPYNORM(y, &out);
+}
+/* -*- EOF -*- */
--- /dev/null
+/*
+ * timevalops.c -- calculations on 'struct timeval' values
+ *
+ * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
+ * The contents of 'html/copyright.html' apply.
+ */
+
+#include <config.h>
+#include <math.h>
+
+#include "lib_strbuf.h"
+#include "ntp_calendar.h"
+
+#include "timevalops.h"
+
+#undef MICROSECONDS
+#define MICROSECONDS 1000000
+
+#if SIZEOF_LONG >= 8
+# define MYFTOTVU(tsf,tvu) \
+ (tvu) = (int32)(((u_long)(tsf) * MICROSECONDS + 0x80000000) >> 32)
+# define MYTVUTOF(tvu,tsf) \
+ (tsf) = (u_int32)((((u_long)(tvu)<<32)+MICROSECONDS/2) / MICROSECONDS)
+#else
+# define MYFTOTVU(tsf,tvu) TSFTOTVU(tsf, tvu)
+# define MYTVUTOF(tvu,tsf) TVUTOTSF(tvu, tsf)
+#endif
+
+#define COPYNORM(dst,src) \
+ do { *(dst) = *(src); \
+ if (timeval_isdenormal((dst))) \
+ timeval_norm((dst)); \
+ } while (0)
+
+
+void
+timeval_norm(
+ struct timeval *x
+ )
+{
+ /* If the fraction becomes excessive denormal, we use division
+ * to do first partial normalisation. The normalisation loops
+ * following will do the remaining cleanup.
+ */
+ if (abs(x->tv_usec) >= 4*MICROSECONDS) {
+ long z;
+ z = x->tv_usec / MICROSECONDS;
+ x->tv_usec -= z * MICROSECONDS;
+ x->tv_sec += z;
+ }
+
+ /* since 10**9 is close to 2**32, we don't divide but do a
+ * normalisation in a loop; this takes 3 steps max, and should
+ * outperform a division even if the mul-by-inverse trick is
+ * employed. */
+ if (x->tv_usec < 0)
+ do {
+ x->tv_usec += MICROSECONDS;
+ x->tv_sec -= 1;
+ } while (x->tv_usec < 0);
+ else if (x->tv_usec >= MICROSECONDS)
+ do {
+ x->tv_usec -= MICROSECONDS;
+ x->tv_sec += 1;
+ } while (x->tv_usec >= MICROSECONDS);
+}
+
+/* x = a, normlised */
+void
+timeval_copy(
+ struct timeval *x,
+ const struct timeval *a
+ )
+{
+ COPYNORM(x,a);
+}
+
+/* x = a + b */
+void
+timeval_add(
+ struct timeval *x,
+ const struct timeval *a,
+ const struct timeval *b
+ )
+{
+ struct timeval c;
+
+ c.tv_sec = a->tv_sec + b->tv_sec;
+ c.tv_usec = a->tv_usec + b->tv_usec;
+ COPYNORM(x, &c);
+}
+
+/* x = a + b, b is fraction only */
+void
+timeval_addus(
+ struct timeval *x,
+ const struct timeval *a,
+ long b
+ )
+{
+ struct timeval c;
+
+ c.tv_sec = a->tv_sec;
+ c.tv_usec = a->tv_usec + b;
+ COPYNORM(x, &c);
+}
+
+/* x = a + b */
+void
+timeval_sub(
+ struct timeval *x,
+ const struct timeval *a,
+ const struct timeval *b
+ )
+{
+ struct timeval c;
+
+ c.tv_sec = a->tv_sec - b->tv_sec;
+ c.tv_usec = a->tv_usec - b->tv_usec;
+ COPYNORM(x, &c);
+}
+
+/* x = a - b, b is fraction only */
+void
+timeval_subus(
+ struct timeval *x,
+ const struct timeval *a,
+ long b
+ )
+{
+ struct timeval c;
+
+ c.tv_sec = a->tv_sec;
+ c.tv_usec = a->tv_usec - b;
+ COPYNORM(x, &c);
+}
+
+/* x = -a */
+void
+timeval_neg(
+ struct timeval *x,
+ const struct timeval *a
+ )
+{
+ struct timeval c;
+
+ c.tv_sec = - a->tv_sec;
+ c.tv_usec = - a->tv_usec;
+ COPYNORM(x, &c);
+}
+
+/* x = ( a < 0) ? -a : a
+ * return if negation was needed
+ */
+int
+timeval_abs(
+ struct timeval *x,
+ const struct timeval *a
+ )
+{
+ struct timeval c;
+ int r;
+
+ COPYNORM(&c, a);
+ if ((r = (c.tv_sec < 0)) != 0) {
+ c.tv_sec = - c.tv_sec;
+ c.tv_usec = - c.tv_usec;
+ if (c.tv_usec < 0) {
+ c.tv_sec -= 1;
+ c.tv_usec += MICROSECONDS;
+ }
+ }
+ *x = c;
+
+ return r;
+}
+
+/* compare a <--> b
+ * return 1 / 0 / -1 if a < / == / > b
+ */
+int
+timeval_cmp_fast(
+ const struct timeval *a,
+ const struct timeval *b
+ )
+{
+ int r;
+
+ r = (a->tv_sec > b->tv_sec)
+ - (a->tv_sec < b->tv_sec);
+ if (r == 0)
+ r = (a->tv_usec > b->tv_usec)
+ - (a->tv_usec < b->tv_usec);
+
+ return r;
+}
+
+int
+timeval_cmp(
+ const struct timeval *a,
+ const struct timeval *b
+ )
+{
+ struct timeval A;
+ struct timeval B;
+
+ COPYNORM(&A, a);
+ COPYNORM(&B, b);
+ return timeval_cmp_fast(&A, &B);
+}
+
+/* test a
+ * return 1 / 0 / -1 if a < / == / > 0
+ */
+int
+timeval_test_fast(
+ const struct timeval *a
+ )
+{
+ int r;
+
+ r = (a->tv_sec > 0) - (a->tv_sec < 0);
+ if (r == 0)
+ r = (a->tv_usec > 0);
+
+ return r;
+}
+
+int
+timeval_test(
+ const struct timeval *a
+ )
+{
+ struct timeval A;
+ int r;
+
+ COPYNORM(&A, a);
+ r = (A.tv_sec > 0) - (A.tv_sec < 0);
+ if (r == 0)
+ r = (A.tv_usec > 0);
+
+ return r;
+}
+
+/* return LIB buffer ptr to string rep */
+const char*
+timeval_tostr(
+ const struct timeval *x
+ )
+{
+ struct timeval v;
+ int s;
+ char *cp;
+
+ LIB_GETBUF(cp);
+ s = timeval_abs(&v, x);
+ if (v.tv_sec >= 0)
+ snprintf(cp, LIB_BUFLENGTH, "%s%ld.%06ld",
+ "-"+(s==0), (long)v.tv_sec, (long)v.tv_usec);
+ else if (v.tv_usec == 0)
+ snprintf(cp, LIB_BUFLENGTH, "%ld.000000",
+ (long)v.tv_sec);
+ else
+ cp = "#OVERFLOW#";
+
+ return cp;
+}
+
+void
+timeval_abstolfp(
+ l_fp *y,
+ const struct timeval *x
+ )
+{
+ struct timeval v;
+
+ COPYNORM(&v, x);
+ MYTVUTOF(v.tv_usec, y->l_uf);
+ y->l_ui = (u_int32)v.tv_sec + JAN_1970;
+}
+
+void
+timeval_reltolfp(
+ l_fp *y,
+ const struct timeval *x
+ )
+{
+ struct timeval v;
+
+ COPYNORM(&v, x);
+ MYTVUTOF(v.tv_usec, y->l_uf);
+ y->l_i = (int32)v.tv_sec;
+
+}
+
+
+void
+timeval_relfromlfp(
+ struct timeval *y,
+ const l_fp *x)
+{
+ struct timeval out;
+
+ MYFTOTVU(x->l_uf, out.tv_usec);
+ out.tv_sec = x->l_i;
+ COPYNORM(y, &out);
+}
+
+void
+timeval_urelfromlfp(
+ struct timeval *y,
+ const l_fp *x)
+{
+ struct timeval out;
+
+ MYFTOTVU(x->l_uf, out.tv_usec);
+ out.tv_sec = x->l_ui;
+ COPYNORM(y, &out);
+}
+
+void
+timeval_absfromlfp(
+ struct timeval *y,
+ const l_fp *x,
+ const time_t *p
+ )
+{
+ struct timeval out;
+ vint64 sec;
+
+ sec = ntpcal_ntp_to_time(x->l_ui, p);
+ MYFTOTVU(x->l_uf, out.tv_usec);
+
+ /* copying a vint64 to a time_t needs some care... */
+# ifdef HAVE_INT64
+ out.tv_sec = (time_t)sec.q_s;
+# elif SIZEOF_TIME_T > 4
+ out.tv_sec = ((time_t)sec.d_s.hi << 32) + sec.d_s.lo;
+# else
+ out.tv_sec = (time_t)sec.d_s.lo;
+# endif
+
+ COPYNORM(y, &out);
+}
+
+/* -*- EOF -*- */
@GTEST_LDFLAGS@ \
@GTEST_LIBS@ \
$(NULL)
-
+
AM_CFLAGS = @CFLAGS_NTP@
AM_CXXFLAGS = @GTEST_CXXFLAGS@
AM_CPPFLAGS = @GTEST_CPPFLAGS@ @CPPFLAGS_NTP@
ssl_init.cpp \
statestr.cpp \
strtolfp.cpp \
+ tspecops.cpp \
tsftomsu.cpp \
tstotv.cpp \
tvtots.cpp \
--- /dev/null
+#include "libntptest.h"
+
+extern "C" {
+#include "timespecops.h"
+}
+
+#include <string>
+#include <sstream>
+
+class timespecTest : public libntptest {
+protected:
+ static const long NANOSECONDS;
+ // that's it...
+};
+const long timespecTest::NANOSECONDS = 1000000000;
+
+
+struct TSPEC{
+ struct timespec V;
+
+ TSPEC()
+ { ZERO(V); }
+ TSPEC(time_t hi, long lo)
+ { V.tv_sec = hi; V.tv_nsec = lo; }
+ bool operator == (const TSPEC &rhs) const
+ { return timespec_cmp(&V, &rhs.V) == 0; }
+ bool valid() const
+ { return timespec_isnormal(&V); }
+ operator struct timespec* ()
+ { return &V; }
+ operator struct timespec& ()
+ { return V; }
+ TSPEC &operator=(const TSPEC &rhs)
+ { V = rhs.V; return *this; }
+ TSPEC &operator=(const struct timespec &rhs)
+ { V = rhs; return *this; }
+};
+
+std::ostream&
+operator << (std::ostream& os, const TSPEC &val)
+{
+ os << timespec_tostr(&val.V);
+ return os;
+}
+
+
+struct LFP {
+ l_fp V;
+
+ LFP()
+ { ZERO(V); }
+ LFP(u_int32 hi, u_int32 lo)
+ { V.l_ui = hi; V.l_uf = lo; }
+ bool operator == (const LFP &rhs) const
+ { return L_ISEQU(&V, &rhs.V); }
+ operator l_fp* ()
+ { return &V; }
+ operator l_fp& ()
+ { return V; }
+ LFP &operator=(const LFP &rhs)
+ { V = rhs.V; return *this; }
+ LFP &operator=(const l_fp &rhs)
+ { V = rhs; return *this; }
+};
+
+std::ostream&
+operator << (std::ostream& os, const LFP &val)
+{
+ os << ulfptoa(&val.V, 10);
+ return os;
+}
+
+
+// ---------------------------------------------------------------------
+// test support stuff
+// ---------------------------------------------------------------------
+
+TEST_F(timespecTest, Normalise) {
+ for (long ns = -2000000000; ns <= 2000000000; ns += 10000000) {
+ TSPEC x(0, ns);
+ timespec_norm(x);
+ ASSERT_TRUE(x.valid());
+ }
+}
+
+TEST_F(timespecTest, SignNoFrac) {
+ // sign test, no fraction
+ for (int i = -4; i <= 4; ++i) {
+ TSPEC a(i, 0);
+ int E = (i>0) - (i<0);
+ int r = timespec_test(a);
+ ASSERT_EQ(E, r);
+ }
+}
+
+TEST_F(timespecTest, SignWithFrac) {
+ // sign test, with fraction
+ for (int i = -4; i <= 4; ++i) {
+ TSPEC a(i, 10);
+ int E = (i>=0) - (i<0);
+ int r = timespec_test(a);
+ ASSERT_EQ(E, r);
+ }
+}
+
+// test compare
+TEST_F(timespecTest, CmpFracEQ) {
+ // fractions are equal
+ for (int i = -4; i <= 4; ++i)
+ for (int j = -4; j <= 4; ++j) {
+ TSPEC a( i , 200);
+ TSPEC b( j , 200);
+ int E = (i > j) - (i < j);
+ int r = timespec_cmp(a, b);
+ ASSERT_EQ(E, r);
+ }
+}
+
+TEST_F(timespecTest, CmpFracGT) {
+ // fraction a bigger fraction b
+ for (int i = -4; i <= 4; ++i)
+ for (int j = -4; j <= 4; ++j) {
+ TSPEC a( i , 999999800);
+ TSPEC b( j , 200);
+ int E = (i >= j) - (i < j);
+ int r = timespec_cmp(a, b);
+ ASSERT_EQ(E, r);
+ }
+}
+
+TEST_F(timespecTest, CmpFracLT) {
+ // fraction a less fraction b
+ for (int i = -4; i <= 4; ++i)
+ for (int j = -4; j <= 4; ++j) {
+ TSPEC a( i , 200);
+ TSPEC b( j , 999999800);
+ int E = (i > j) - (i <= j);
+ int r = timespec_cmp(a, b);
+ ASSERT_EQ(E, r);
+ }
+}
+
+// Test addition (sum)
+TEST_F(timespecTest, AddFullNorm) {
+ for (int i = -4; i <= 4; ++i)
+ for (int j = -4; j <= 4; ++j) {
+ TSPEC a( i , 200);
+ TSPEC b( j , 400);
+ TSPEC E(i+j, 600);
+ TSPEC c;
+ timespec_add(c, a, b);
+ ASSERT_EQ(E, c);
+ }
+}
+
+TEST_F(timespecTest, AddFullOflow1) {
+ for (int i = -4; i <= 4; ++i)
+ for (int j = -4; j <= 4; ++j) {
+ TSPEC a( i , 200);
+ TSPEC b( j , 999999900);
+ TSPEC E(i+j+1, 100);
+ TSPEC c;
+ timespec_add(c, a, b);
+ ASSERT_EQ(E, c);
+ }
+}
+
+TEST_F(timespecTest, AddNsecNorm) {
+ for (int i = -4; i <= 4; ++i) {
+ TSPEC a(i, 200);
+ TSPEC E(i, 600);
+ TSPEC c;
+ timespec_addns(c, a, 400);
+ ASSERT_EQ(E, c);
+ }
+}
+
+TEST_F(timespecTest, AddNsecOflow1) {
+ for (int i = -4; i <= 4; ++i) {
+ TSPEC a( i , 200);
+ TSPEC E(i+1, 100);
+ TSPEC c;
+ timespec_addns(c, a, NANOSECONDS - 100);
+ ASSERT_EQ(E, c);
+ }
+}
+
+// test subtraction (difference)
+TEST_F(timespecTest, SubFullNorm) {
+ for (int i = -4; i <= 4; ++i)
+ for (int j = -4; j <= 4; ++j) {
+ TSPEC a( i , 600);
+ TSPEC b( j , 400);
+ TSPEC E(i-j, 200);
+ TSPEC c;
+ timespec_sub(c, a, b);
+ ASSERT_EQ(E, c);
+ }
+}
+
+TEST_F(timespecTest, SubFullOflow) {
+ for (int i = -4; i <= 4; ++i)
+ for (int j = -4; j <= 4; ++j) {
+ TSPEC a( i , 100);
+ TSPEC b( j , 999999900);
+ TSPEC E(i-j-1, 200);
+ TSPEC c;
+ timespec_sub(c, a, b);
+ ASSERT_EQ(E, c);
+ }
+}
+
+TEST_F(timespecTest, SubNsecNorm) {
+ for (int i = -4; i <= 4; ++i) {
+ TSPEC a(i, 600);
+ TSPEC E(i, 200);
+ TSPEC c;
+ timespec_subns(c, a, 400);
+ ASSERT_EQ(E, c);
+ }
+}
+
+TEST_F(timespecTest, SubNsecOflow) {
+ for (int i = -4; i <= 4; ++i) {
+ TSPEC a( i , 100);
+ TSPEC E(i-1, 200);
+ TSPEC c;
+ timespec_subns(c, a, NANOSECONDS - 100);
+ ASSERT_EQ(E, c);
+ }
+}
+
+// test negation
+TEST_F(timespecTest, Neg) {
+ for (int i = -4; i <= 4; ++i) {
+ TSPEC a( i , 100);
+ TSPEC b;
+ TSPEC c;
+ timespec_neg(b, a);
+ timespec_add(c, a, b);
+ ASSERT_EQ(0, timespec_test(c));
+ }
+}
+
+// test abs value
+TEST_F(timespecTest, AbsNoFrac) {
+ for (int i = -4; i <= 4; ++i) {
+ TSPEC a(i , 0);
+ TSPEC b;
+ int c;
+ c = timespec_abs(b, a);
+ ASSERT_EQ((i < 0), c);
+ ASSERT_EQ((i != 0), timespec_test(b));
+ }
+}
+
+TEST_F(timespecTest, AbsWithFrac) {
+ for (int i = -4; i <= 4; ++i) {
+ TSPEC a(i , 100);
+ TSPEC b;
+ int c;
+ c = timespec_abs(b, a);
+ ASSERT_EQ((i < 0), c);
+ ASSERT_EQ(1, timespec_test(b));
+ }
+}
+
+// conversion to l_fp
+TEST_F(timespecTest, ToLFPrel) {
+ static const struct {
+ long nsec;
+ u_int32 frac;
+ } data [] = {
+ { 0, 0x00000000 }, { 2218896, 0x00916ae6 },
+ { 16408100, 0x0433523d }, { 125000000, 0x20000000 },
+ { 250000000, 0x40000000 }, { 287455871, 0x4996b53d },
+ { 375000000, 0x60000000 }, { 500000000, 0x80000000 },
+ { 518978897, 0x84dbcd0e }, { 563730222, 0x90509fb3 },
+ { 563788007, 0x9054692c }, { 583289882, 0x95527c57 },
+ { 607074509, 0x9b693c2a }, { 625000000, 0xa0000000 },
+ { 645184059, 0xa52ac851 }, { 676497788, 0xad2ef583 },
+ { 678910895, 0xadcd1abb }, { 679569625, 0xadf84663 },
+ { 690926741, 0xb0e0932d }, { 705656483, 0xb4a5e73d },
+ { 723553854, 0xb93ad34c }, { 750000000, 0xc0000000 },
+ { 763550253, 0xc3780785 }, { 775284917, 0xc6791284 },
+ { 826190764, 0xd3813ce8 }, { 875000000, 0xe0000000 },
+ { 956805507, 0xf4f134a9 }, { 982570733, 0xfb89c16c }
+ };
+ for (int i = 0; i < sizeof(data)/sizeof(*data); ++i) {
+ TSPEC a(1, data[i].nsec);
+ LFP E(1, data[i].frac);
+ LFP r;
+ timespec_reltolfp(r, a);
+ ASSERT_EQ(E, r);
+ }
+}
+
+TEST_F(timespecTest, ToLFPabs) {
+ static const struct {
+ long nsec;
+ u_int32 frac;
+ } data [] = {
+ { 0, 0x00000000 }, { 2218896, 0x00916ae6 },
+ { 16408100, 0x0433523d }, { 125000000, 0x20000000 },
+ { 250000000, 0x40000000 }, { 287455871, 0x4996b53d },
+ { 375000000, 0x60000000 }, { 500000000, 0x80000000 },
+ { 518978897, 0x84dbcd0e }, { 563730222, 0x90509fb3 },
+ { 563788007, 0x9054692c }, { 583289882, 0x95527c57 },
+ { 607074509, 0x9b693c2a }, { 625000000, 0xa0000000 },
+ { 645184059, 0xa52ac851 }, { 676497788, 0xad2ef583 },
+ { 678910895, 0xadcd1abb }, { 679569625, 0xadf84663 },
+ { 690926741, 0xb0e0932d }, { 705656483, 0xb4a5e73d },
+ { 723553854, 0xb93ad34c }, { 750000000, 0xc0000000 },
+ { 763550253, 0xc3780785 }, { 775284917, 0xc6791284 },
+ { 826190764, 0xd3813ce8 }, { 875000000, 0xe0000000 },
+ { 956805507, 0xf4f134a9 }, { 982570733, 0xfb89c16c }
+ };
+ for (int i = 0; i < sizeof(data)/sizeof(*data); ++i) {
+ TSPEC a(1 , data[i].nsec);
+ LFP E(1+JAN_1970, data[i].frac);
+ LFP r;
+ timespec_abstolfp(r, a);
+ ASSERT_EQ(E, r);
+ }
+}
+
+// -*- EOF -*-