aboutsummaryrefslogtreecommitdiffstats
path: root/multimespec.c
diff options
context:
space:
mode:
Diffstat (limited to 'multimespec.c')
-rw-r--r--multimespec.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/multimespec.c b/multimespec.c
new file mode 100644
index 0000000..2e1c2a9
--- /dev/null
+++ b/multimespec.c
@@ -0,0 +1,65 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+
+
+int
+libsimple_multimespec(struct timespec *prod, const struct timespec *multiplicand, int multiplier)
+{
+ time_t s = multiplicand->tv_sec;
+ long long int ns = (long long int)(multiplicand->tv_nsec);
+ long long int xs;
+ int neg = (s < 0) ^ (multiplier < 0);
+
+ if (multiplier == 0 || multiplier == 1) {
+ prod->tv_sec = multiplier * multiplicand->tv_sec;
+ prod->tv_nsec = multiplier * multiplicand->tv_nsec;
+ return 0;
+ }
+
+ if (s < 0) {
+ if (TIME_MIN != -TIME_MAX && s == TIME_MIN)
+ goto overflow;
+ s = -s;
+ if (ns)
+ ns = 1000000000L - ns;
+ }
+ if (multiplier < 0)
+ multiplier = -multiplier;
+
+ ns *= multiplier;
+ xs = ns / 1000000000L;
+ ns %= 1000000000L;
+
+ if (s > TIME_MAX / multiplier)
+ goto overflow;
+ s *= multiplier;
+
+ if (s > TIME_MAX - (time_t)xs)
+ goto overflow;
+ s += (time_t)xs;
+
+ if (neg) {
+ s = -s;
+ if (ns) {
+ if (s == TIME_MIN)
+ goto overflow;
+ ns = 1000000000L - ns;
+ s -= 1;
+ }
+ }
+
+ prod->tv_sec = s;
+ prod->tv_nsec = ns;
+ return 0;
+
+overflow:
+ if (neg) {
+ prod->tv_sec = TIME_MIN;
+ prod->tv_nsec = 0;
+ } else {
+ prod->tv_sec = TIME_MAX;
+ prod->tv_nsec = 999999999L;
+ }
+ errno = ERANGE;
+ return -1;
+}