Line data Source code
1 : /*
2 : * Copyright (c) 1999 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : *
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : *
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * 3. Neither the name of the Institute nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 : /*
35 : * Timeval stuff
36 : */
37 :
38 : #include <config.h>
39 :
40 : #include "roken.h"
41 :
42 : ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL
43 690552 : rk_time_add(time_t t, time_t delta)
44 : {
45 690552 : if (delta == 0)
46 196990 : return t;
47 :
48 : #ifdef TIME_T_SIGNED
49 : /* Signed overflow is UB in C */
50 : #if SIZEOF_TIME_T == 4
51 : if (t >= 0 && delta > 0 && INT32_MAX - t < delta)
52 : /* Time left to hit INT32_MAX is less than what we want to add */
53 : return INT32_MAX;
54 : else if (t == INT32_MIN && delta < 0)
55 : /* Avoid computing -t when t == INT32_MIN! */
56 : return INT32_MIN;
57 : else if (t < 0 && delta < 0 && INT32_MIN + (-t) > delta)
58 : /* Time left to hit INT32_MIN is less than what we want to subtract */
59 : return INT32_MIN;
60 : else
61 : return t + delta;
62 : #elif SIZEOF_TIME_T == 8
63 485589 : if (t >= 0 && delta > 0 && INT64_MAX - t < delta)
64 0 : return INT64_MAX;
65 485589 : else if (t == INT64_MIN && delta < 0)
66 : /* Avoid computing -t when t == INT64_MIN! */
67 0 : return INT64_MIN;
68 485589 : else if (t < 0 && delta < 0 && INT64_MIN + (-t) > delta)
69 0 : return INT64_MIN;
70 : else
71 485589 : return t + delta;
72 : #else
73 : #error "Unexpected sizeof(time_t)"
74 : #endif
75 : #else
76 :
77 : /* Unsigned overflow is defined in C */
78 : #if SIZEOF_TIME_T == 4
79 : if (t + delta < t)
80 : return UINT32_MAX;
81 : #elif SIZEOF_TIME_T == 8
82 : if (t + delta < t)
83 : return UINT64_MAX;
84 : #else
85 : #error "Unexpected sizeof(time_t)"
86 : #endif
87 : return t + delta;
88 : #endif
89 : }
90 :
91 : ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL
92 413885 : rk_time_sub(time_t t, time_t delta)
93 : {
94 413885 : if (delta == 0)
95 0 : return t;
96 : #ifdef TIME_T_SIGNED
97 413885 : if (delta > 0)
98 413885 : return rk_time_add(t, -delta);
99 : #if SIZEOF_TIME_T == 4
100 : if (delta == INT32_MIN) {
101 : if (t < 0) {
102 : t = t + INT32_MAX;
103 : return t + 1;
104 : }
105 : return INT32_MAX;
106 : }
107 : /* Safe to compute -delta, so use rk_time_add() to add -delta */
108 : return rk_time_add(t, -delta);
109 : #elif SIZEOF_TIME_T == 8
110 0 : if (delta == INT64_MIN) {
111 0 : if (t < 0) {
112 0 : t = t + INT64_MAX;
113 0 : return t + 1;
114 : }
115 0 : return INT64_MAX;
116 : }
117 0 : return rk_time_add(t, -delta);
118 : #else
119 : #error "Unexpected sizeof(time_t)"
120 : #endif
121 : #else
122 : /* Both t and delta are non-negative. */
123 : if (delta > t)
124 : return 0;
125 : return t - delta;
126 : #endif
127 : }
128 :
129 : /*
130 : * Make `t1' consistent.
131 : */
132 :
133 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
134 499189 : timevalfix(struct timeval *t1)
135 : {
136 499189 : if (t1->tv_usec < 0) {
137 2373 : t1->tv_sec = rk_time_sub(t1->tv_sec, 1);
138 2373 : t1->tv_usec = 1000000;
139 : }
140 499189 : if (t1->tv_usec >= 1000000) {
141 2373 : t1->tv_sec = rk_time_add(t1->tv_sec, 1);
142 2373 : t1->tv_usec -= 1000000;
143 : }
144 499189 : }
145 :
146 : /*
147 : * t1 += t2
148 : */
149 :
150 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
151 206417 : timevaladd(struct timeval *t1, const struct timeval *t2)
152 : {
153 206417 : t1->tv_sec = rk_time_add(t1->tv_sec, t2->tv_sec);
154 206417 : t1->tv_usec += t2->tv_usec;
155 206417 : timevalfix(t1);
156 206417 : }
157 :
158 : /*
159 : * t1 -= t2
160 : */
161 :
162 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
163 292772 : timevalsub(struct timeval *t1, const struct timeval *t2)
164 : {
165 292772 : t1->tv_sec = rk_time_sub(t1->tv_sec, t2->tv_sec);
166 292772 : t1->tv_usec -= t2->tv_usec;
167 292772 : timevalfix(t1);
168 292772 : }
169 :
170 : #ifdef TEST
171 : int
172 : main(int argc, char **argv)
173 : {
174 : time_t t, delta, r;
175 : int e = 0;
176 :
177 : if (argc == 0)
178 : return 0; /* Apparently POSIX and Linux allow this case */
179 :
180 : argc--;
181 : argv++;
182 :
183 : while (argc > 0) {
184 : int64_t n;
185 : time_t a;
186 : char *ends;
187 :
188 : if (argc < 3)
189 : errx(1, "Usage: [TIME +|- DELTA [== TIME]]");
190 :
191 : errno = 0;
192 : n = strtoll(argv[0], &ends, 0);
193 : if (errno)
194 : err(1, "Time value is invalid");
195 : if (*ends != '\0')
196 : errx(1, "Time value is invalid");
197 : t = n;
198 :
199 : n = strtoll(argv[2], &ends, 0);
200 : if (errno)
201 : err(1, "Delta value is invalid");
202 : if (*ends != '\0')
203 : errx(1, "Delta value is invalid");
204 : delta = n;
205 :
206 : if (argv[1][0] == '+' && argv[1][1] == '\0')
207 : r = rk_time_add(t, delta);
208 : else if (argv[1][0] == '-' && argv[1][1] == '\0')
209 : r = rk_time_sub(t, delta);
210 : else
211 : errx(1, "Operator must be a + or a - arithmetic operator");
212 :
213 : if (delta == 0 && r != t) {
214 : warnx("%s %s %s != %s!", argv[0], argv[1], argv[2], argv[0]);
215 : e = 1;
216 : }
217 : if (t == 0 && r != delta) {
218 : warnx("%s %s %s != %s!", argv[0], argv[1], argv[2], argv[2]);
219 : e = 1;
220 : }
221 :
222 : if (argc > 4 && strcmp(argv[3], "==") == 0) {
223 : n = strtoll(argv[4], &ends, 0);
224 : if (errno)
225 : err(1, "Time value is invalid");
226 : if (*ends != '\0')
227 : errx(1, "Time value is invalid");
228 : a = n;
229 : if (a != r) {
230 : warnx("%s %s %s != %s!", argv[0], argv[1], argv[2], argv[4]);
231 : e = 1;
232 : }
233 : argc -= 5;
234 : argv += 5;
235 : } else {
236 : #ifdef TIME_T_SIGNED
237 : printf("%s %s %s == %lld\n", argv[0], argv[1], argv[2],
238 : (long long)r);
239 : #else
240 : printf("%s %s %s == %llu\n", argv[0], argv[1], argv[2],
241 : (unsigned long long)r);
242 : #endif
243 : argc -= 3;
244 : argv += 3;
245 : }
246 : }
247 :
248 : #define CHECK(e) do { if (!(e)) errx(1, "Expression not true: " #e "!"); } while (0)
249 : #ifdef TIME_T_SIGNED
250 : #if SIZEOF_TIME_T == 4
251 : CHECK(rk_time_add(INT32_MIN, -1) == INT32_MIN);
252 : CHECK(rk_time_sub(INT32_MIN, 1) == INT32_MIN);
253 : CHECK(rk_time_sub(-1, INT32_MAX) == INT32_MIN);
254 : CHECK(rk_time_add(INT32_MAX, 0) == INT32_MAX);
255 : CHECK(rk_time_add(INT32_MAX, 1) == INT32_MAX);
256 : CHECK(rk_time_add(1, INT32_MAX) == INT32_MAX);
257 : CHECK(rk_time_add(0, INT32_MAX) == INT32_MAX);
258 : #elif SIZEOF_TIME_T == 8
259 : CHECK(rk_time_add(INT64_MIN, -1) == INT64_MIN);
260 : CHECK(rk_time_sub(INT64_MIN, 1) == INT64_MIN);
261 : CHECK(rk_time_sub(-1, INT64_MAX) == INT64_MIN);
262 : CHECK(rk_time_add(INT64_MAX, 0) == INT64_MAX);
263 : CHECK(rk_time_add(INT64_MAX, 1) == INT64_MAX);
264 : CHECK(rk_time_add(1, INT64_MAX) == INT64_MAX);
265 : CHECK(rk_time_add(0, INT64_MAX) == INT64_MAX);
266 : #endif
267 : CHECK(rk_time_add(0, -1) == -1);
268 : CHECK(rk_time_sub(0, 1) == -1);
269 : #else
270 : #if SIZEOF_TIME_T == 4
271 : CHECK(rk_time_add(UINT32_MAX, 0) == UINT32_MAX);
272 : CHECK(rk_time_add(UINT32_MAX, 1) == UINT32_MAX);
273 : CHECK(rk_time_add(1, UINT32_MAX) == UINT32_MAX);
274 : CHECK(rk_time_add(0, UINT32_MAX) == UINT32_MAX);
275 : #elif SIZEOF_TIME_T == 8
276 : CHECK(rk_time_add(UINT64_MAX, 0) == UINT64_MAX);
277 : CHECK(rk_time_add(UINT64_MAX, 1) == UINT64_MAX);
278 : CHECK(rk_time_add(1, UINT64_MAX) == UINT64_MAX);
279 : CHECK(rk_time_add(0, UINT64_MAX) == UINT64_MAX);
280 : #endif
281 : #endif
282 : CHECK(rk_time_add(0, 1) == 1);
283 : CHECK(rk_time_add(1, 0) == 1);
284 : return e;
285 : }
286 : #endif
|