roken: Add time_add()/time_sub() with overflow prot.
[heimdal.git] / lib / roken / timeval.c
blobac7fb2404cd8f339383827254df4a2adee6373ed
1 /*
2 * Copyright (c) 1999 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
35 * Timeval stuff
38 #include <config.h>
40 #include "roken.h"
42 ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL
43 rk_time_add(time_t t, time_t delta)
45 if (delta == 0)
46 return t;
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 < 0 && delta == INT32_MIN)
55 /* Avoid computing -delta when t == INT32_MIN! */
56 return INT32_MIN;
57 else if (t == INT32_MIN && delta < 0)
58 /* Avoid computing -t when t == INT32_MIN! */
59 return INT32_MIN;
60 else if (t < 0 && delta < 0 && INT32_MIN + (-t) < (-delta))
61 /* Time left to hit INT32_MIN is less than what we want to subtract */
62 return INT32_MIN;
63 else
64 return t + delta;
65 #elif SIZEOF_TIME_T == 8
66 if (t >= 0 && delta > 0 && INT64_MAX - t < delta)
67 return INT64_MAX;
68 else if (t < 0 && delta == INT64_MIN)
69 /* Avoid computing -delta when t == INT64_MIN! */
70 return INT64_MIN;
71 else if (t == INT64_MIN && delta < 0)
72 /* Avoid computing -t when t == INT64_MIN! */
73 return INT64_MIN;
74 else if (t < 0 && delta < 0 && INT64_MIN + (-t) < (-delta))
75 return INT64_MIN;
76 else
77 return t + delta;
78 #else
79 #error "Unexpected sizeof(time_t)"
80 #endif
81 #else
83 /* Unsigned overflow is defined in C */
84 #if SIZEOF_TIME_T == 4
85 if (t + delta < t)
86 return UINT32_MAX;
87 #elif SIZEOF_TIME_T == 8
88 if (t + delta < t)
89 return UINT64_MAX;
90 #else
91 #error "Unexpected sizeof(time_t)"
92 #endif
93 #endif
94 return t + delta;
97 ROKEN_LIB_FUNCTION time_t ROKEN_LIB_CALL
98 rk_time_sub(time_t t, time_t delta)
100 if (delta == 0)
101 return t;
102 #ifdef TIME_T_SIGNED
103 if (delta > 0)
104 return time_add(t, -delta);
105 #if SIZEOF_TIME_T == 4
106 if (delta == INT32_MIN) {
107 if (t < 0) {
108 t = t + INT32_MAX;
109 return t + 1;
111 return INT32_MAX;
113 /* Safe to compute -delta, so use time_add() to add -delta */
114 return time_add(t, -delta);
115 #elif SIZEOF_TIME_T == 8
116 if (delta == INT64_MIN) {
117 if (t < 0) {
118 t = t + INT64_MAX;
119 return t + 1;
121 return INT64_MAX;
123 return time_add(t, -delta);
124 #else
125 #error "Unexpected sizeof(time_t)"
126 #endif
127 #else
128 /* Both t and delta are non-negative. */
129 if (delta > t)
130 return 0;
131 #endif
132 return t - delta;
136 * Make `t1' consistent.
139 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
140 timevalfix(struct timeval *t1)
142 if (t1->tv_usec < 0) {
143 t1->tv_sec--;
144 t1->tv_usec += 1000000;
146 if (t1->tv_usec >= 1000000) {
147 t1->tv_sec++;
148 t1->tv_usec -= 1000000;
153 * t1 += t2
156 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
157 timevaladd(struct timeval *t1, const struct timeval *t2)
159 t1->tv_sec += t2->tv_sec;
160 t1->tv_usec += t2->tv_usec;
161 timevalfix(t1);
165 * t1 -= t2
168 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
169 timevalsub(struct timeval *t1, const struct timeval *t2)
171 t1->tv_sec -= t2->tv_sec;
172 t1->tv_usec -= t2->tv_usec;
173 timevalfix(t1);