summaryrefslogtreecommitdiffstats
path: root/third_party/heimdal/lib/roken/timeval.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/heimdal/lib/roken/timeval.c')
-rw-r--r--third_party/heimdal/lib/roken/timeval.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/roken/timeval.c b/third_party/heimdal/lib/roken/timeval.c
new file mode 100644
index 0000000..71fdd00
--- /dev/null
+++ b/third_party/heimdal/lib/roken/timeval.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Timeval stuff
+ */
+
+#include <config.h>
+
+#include "roken.h"
+
+ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL
+rk_time_add(time_t t, time_t delta)
+{
+ if (delta == 0)
+ return t;
+
+#ifdef TIME_T_SIGNED
+ /* Signed overflow is UB in C */
+#if SIZEOF_TIME_T == 4
+ if (t >= 0 && delta > 0 && INT32_MAX - t < delta)
+ /* Time left to hit INT32_MAX is less than what we want to add */
+ return INT32_MAX;
+ else if (t == INT32_MIN && delta < 0)
+ /* Avoid computing -t when t == INT32_MIN! */
+ return INT32_MIN;
+ else if (t < 0 && delta < 0 && INT32_MIN + (-t) > delta)
+ /* Time left to hit INT32_MIN is less than what we want to subtract */
+ return INT32_MIN;
+ else
+ return t + delta;
+#elif SIZEOF_TIME_T == 8
+ if (t >= 0 && delta > 0 && INT64_MAX - t < delta)
+ return INT64_MAX;
+ else if (t == INT64_MIN && delta < 0)
+ /* Avoid computing -t when t == INT64_MIN! */
+ return INT64_MIN;
+ else if (t < 0 && delta < 0 && INT64_MIN + (-t) > delta)
+ return INT64_MIN;
+ else
+ return t + delta;
+#else
+#error "Unexpected sizeof(time_t)"
+#endif
+#else
+
+ /* Unsigned overflow is defined in C */
+#if SIZEOF_TIME_T == 4
+ if (t + delta < t)
+ return UINT32_MAX;
+#elif SIZEOF_TIME_T == 8
+ if (t + delta < t)
+ return UINT64_MAX;
+#else
+#error "Unexpected sizeof(time_t)"
+#endif
+ return t + delta;
+#endif
+}
+
+ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL
+rk_time_sub(time_t t, time_t delta)
+{
+ if (delta == 0)
+ return t;
+#ifdef TIME_T_SIGNED
+ if (delta > 0)
+ return rk_time_add(t, -delta);
+#if SIZEOF_TIME_T == 4
+ if (delta == INT32_MIN) {
+ if (t < 0) {
+ t = t + INT32_MAX;
+ return t + 1;
+ }
+ return INT32_MAX;
+ }
+ /* Safe to compute -delta, so use rk_time_add() to add -delta */
+ return rk_time_add(t, -delta);
+#elif SIZEOF_TIME_T == 8
+ if (delta == INT64_MIN) {
+ if (t < 0) {
+ t = t + INT64_MAX;
+ return t + 1;
+ }
+ return INT64_MAX;
+ }
+ return rk_time_add(t, -delta);
+#else
+#error "Unexpected sizeof(time_t)"
+#endif
+#else
+ /* Both t and delta are non-negative. */
+ if (delta > t)
+ return 0;
+ return t - delta;
+#endif
+}
+
+/*
+ * Make `t1' consistent.
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+timevalfix(struct timeval *t1)
+{
+ if (t1->tv_usec < 0) {
+ t1->tv_sec = rk_time_sub(t1->tv_sec, 1);
+ t1->tv_usec = 1000000;
+ }
+ if (t1->tv_usec >= 1000000) {
+ t1->tv_sec = rk_time_add(t1->tv_sec, 1);
+ t1->tv_usec -= 1000000;
+ }
+}
+
+/*
+ * t1 += t2
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+timevaladd(struct timeval *t1, const struct timeval *t2)
+{
+ t1->tv_sec = rk_time_add(t1->tv_sec, t2->tv_sec);
+ t1->tv_usec += t2->tv_usec;
+ timevalfix(t1);
+}
+
+/*
+ * t1 -= t2
+ */
+
+ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
+timevalsub(struct timeval *t1, const struct timeval *t2)
+{
+ t1->tv_sec = rk_time_sub(t1->tv_sec, t2->tv_sec);
+ t1->tv_usec -= t2->tv_usec;
+ timevalfix(t1);
+}
+
+#ifdef TEST
+int
+main(int argc, char **argv)
+{
+ time_t t, delta, r;
+ int e = 0;
+
+ if (argc == 0)
+ return 0; /* Apparently POSIX and Linux allow this case */
+
+ argc--;
+ argv++;
+
+ while (argc > 0) {
+ int64_t n;
+ time_t a;
+ char *ends;
+
+ if (argc < 3)
+ errx(1, "Usage: [TIME +|- DELTA [== TIME]]");
+
+ errno = 0;
+ n = strtoll(argv[0], &ends, 0);
+ if (errno)
+ err(1, "Time value is invalid");
+ if (*ends != '\0')
+ errx(1, "Time value is invalid");
+ t = n;
+
+ n = strtoll(argv[2], &ends, 0);
+ if (errno)
+ err(1, "Delta value is invalid");
+ if (*ends != '\0')
+ errx(1, "Delta value is invalid");
+ delta = n;
+
+ if (argv[1][0] == '+' && argv[1][1] == '\0')
+ r = rk_time_add(t, delta);
+ else if (argv[1][0] == '-' && argv[1][1] == '\0')
+ r = rk_time_sub(t, delta);
+ else
+ errx(1, "Operator must be a + or a - arithmetic operator");
+
+ if (delta == 0 && r != t) {
+ warnx("%s %s %s != %s!", argv[0], argv[1], argv[2], argv[0]);
+ e = 1;
+ }
+ if (t == 0 && r != delta) {
+ warnx("%s %s %s != %s!", argv[0], argv[1], argv[2], argv[2]);
+ e = 1;
+ }
+
+ if (argc > 4 && strcmp(argv[3], "==") == 0) {
+ n = strtoll(argv[4], &ends, 0);
+ if (errno)
+ err(1, "Time value is invalid");
+ if (*ends != '\0')
+ errx(1, "Time value is invalid");
+ a = n;
+ if (a != r) {
+ warnx("%s %s %s != %s!", argv[0], argv[1], argv[2], argv[4]);
+ e = 1;
+ }
+ argc -= 5;
+ argv += 5;
+ } else {
+#ifdef TIME_T_SIGNED
+ printf("%s %s %s == %lld\n", argv[0], argv[1], argv[2],
+ (long long)r);
+#else
+ printf("%s %s %s == %llu\n", argv[0], argv[1], argv[2],
+ (unsigned long long)r);
+#endif
+ argc -= 3;
+ argv += 3;
+ }
+ }
+
+#define CHECK(e) do { if (!(e)) errx(1, "Expression not true: " #e "!"); } while (0)
+#ifdef TIME_T_SIGNED
+#if SIZEOF_TIME_T == 4
+ CHECK(rk_time_add(INT32_MIN, -1) == INT32_MIN);
+ CHECK(rk_time_sub(INT32_MIN, 1) == INT32_MIN);
+ CHECK(rk_time_sub(-1, INT32_MAX) == INT32_MIN);
+ CHECK(rk_time_add(INT32_MAX, 0) == INT32_MAX);
+ CHECK(rk_time_add(INT32_MAX, 1) == INT32_MAX);
+ CHECK(rk_time_add(1, INT32_MAX) == INT32_MAX);
+ CHECK(rk_time_add(0, INT32_MAX) == INT32_MAX);
+#elif SIZEOF_TIME_T == 8
+ CHECK(rk_time_add(INT64_MIN, -1) == INT64_MIN);
+ CHECK(rk_time_sub(INT64_MIN, 1) == INT64_MIN);
+ CHECK(rk_time_sub(-1, INT64_MAX) == INT64_MIN);
+ CHECK(rk_time_add(INT64_MAX, 0) == INT64_MAX);
+ CHECK(rk_time_add(INT64_MAX, 1) == INT64_MAX);
+ CHECK(rk_time_add(1, INT64_MAX) == INT64_MAX);
+ CHECK(rk_time_add(0, INT64_MAX) == INT64_MAX);
+#endif
+ CHECK(rk_time_add(0, -1) == -1);
+ CHECK(rk_time_sub(0, 1) == -1);
+#else
+#if SIZEOF_TIME_T == 4
+ CHECK(rk_time_add(UINT32_MAX, 0) == UINT32_MAX);
+ CHECK(rk_time_add(UINT32_MAX, 1) == UINT32_MAX);
+ CHECK(rk_time_add(1, UINT32_MAX) == UINT32_MAX);
+ CHECK(rk_time_add(0, UINT32_MAX) == UINT32_MAX);
+#elif SIZEOF_TIME_T == 8
+ CHECK(rk_time_add(UINT64_MAX, 0) == UINT64_MAX);
+ CHECK(rk_time_add(UINT64_MAX, 1) == UINT64_MAX);
+ CHECK(rk_time_add(1, UINT64_MAX) == UINT64_MAX);
+ CHECK(rk_time_add(0, UINT64_MAX) == UINT64_MAX);
+#endif
+#endif
+ CHECK(rk_time_add(0, 1) == 1);
+ CHECK(rk_time_add(1, 0) == 1);
+ return e;
+}
+#endif