aboutsummaryrefslogtreecommitdiffstats
path: root/multimespec.c
blob: ec60c1eb269681e6586ea14b930ebe590b2361df (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/* See LICENSE file for copyright and license details. */
#include "libsimple.h"


int
libsimple_multimespec(struct timespec *prod, const struct timespec *multiplicand, int multiplier) /* TODO test */
{
	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;
}