xref: /freebsd/contrib/ntp/libntp/vint64ops.c (revision d6b92ffa)
1 /*
2  * vint64ops.c - operations on 'vint64' values
3  *
4  * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
5  * The contents of 'html/copyright.html' apply.
6  * ----------------------------------------------------------------------
7  * This is an attempt to get the vint64 calculations stuff centralised.
8  */
9 
10 #include <config.h>
11 #include <stdlib.h>
12 #include <ctype.h>
13 #include <string.h>
14 #include <errno.h>
15 
16 #include "ntp_types.h"
17 #include "ntp_fp.h"
18 #include "vint64ops.h"
19 
20 /* ---------------------------------------------------------------------
21  * GCC is rather sticky with its 'const' attribute. We have to do it more
22  * explicit than with a cast if we want to get rid of a CONST qualifier.
23  * Greetings from the PASCAL world, where casting was only possible via
24  * untagged unions...
25  */
26 static inline void*
27 noconst(
28 	const void* ptr
29 	)
30 {
31 	union {
32 		const void * cp;
33 		void *       vp;
34 	} tmp;
35 	tmp.cp = ptr;
36 	return tmp.vp;
37 }
38 
39 /* -------------------------------------------------------------------------*/
40 
41 vint64
42 strtouv64(
43 	const char * begp,
44 	char **      endp,
45 	int          base
46 	)
47 {
48 	vint64  res;
49 	u_char  digit;
50 	int     sig, num;
51 	const u_char *src;
52 
53 	num = sig = 0;
54 	src = (const u_char*)begp;
55 	while (isspace(*src))
56 		src++;
57 
58 	if (*src == '-') {
59 		src++;
60 		sig = 1;
61 	} else  if (*src == '+') {
62 		src++;
63 	}
64 
65 	if (base == 0) {
66 		base = 10;
67 		if (*src == '0') {
68 			base = 8;
69 			if (toupper(*++src) == 'X') {
70 				src++;
71 				base = 16;
72 			}
73 		}
74 	} else if (base == 16) { /* remove optional leading '0x' or '0X' */
75 		if (src[0] == '0' && toupper(src[1]) == 'X')
76 			src += 2;
77 	} else if (base <= 2 || base > 36) {
78 		memset(&res, 0xFF, sizeof(res));
79 		errno = ERANGE;
80 		return res;
81 	}
82 
83 	memset(&res, 0, sizeof(res));
84 	while (*src) {
85 		if (isdigit(*src))
86 			digit = *src - '0';
87 		else if (isupper(*src))
88 			digit = *src - 'A' + 10;
89 		else if (islower(*src))
90 			digit = *src - 'a' + 10;
91 		else
92 			break;
93 		if (digit >= base)
94 			break;
95 		num = 1;
96 #if defined(HAVE_INT64)
97 		res.Q_s = res.Q_s * base + digit;
98 #else
99 		/* res *= base, using 16x16->32 bit
100 		 * multiplication. Slow but portable.
101 		 */
102 		{
103 			uint32_t accu;
104 			accu       = (uint32_t)res.W_s.ll * base;
105 			res.W_s.ll = (uint16_t)accu;
106 			accu       = (accu >> 16)
107 			           + (uint32_t)res.W_s.lh * base;
108 			res.W_s.lh = (uint16_t)accu;
109 			/* the upper bits can be done in one step: */
110 			res.D_s.hi = res.D_s.hi * base + (accu >> 16);
111 		}
112 		M_ADD(res.D_s.hi, res.D_s.lo, 0, digit);
113 #endif
114 		src++;
115 	}
116 	if (!num)
117 		errno = EINVAL;
118 	if (endp)
119 		*endp = (char*)noconst(src);
120 	if (sig)
121 		M_NEG(res.D_s.hi, res.D_s.lo);
122 	return res;
123 }
124 
125 /* -------------------------------------------------------------------------*/
126 
127 int
128 icmpv64(
129 	const vint64 * lhs,
130 	const vint64 * rhs
131 	)
132 {
133 	int res;
134 
135 #if defined(HAVE_INT64)
136 	res = (lhs->q_s > rhs->q_s)
137 	    - (lhs->q_s < rhs->q_s);
138 #else
139 	res = (lhs->d_s.hi > rhs->d_s.hi)
140 	    - (lhs->d_s.hi < rhs->d_s.hi);
141 	if ( ! res )
142 		res = (lhs->D_s.lo > rhs->D_s.lo)
143 		    - (lhs->D_s.lo < rhs->D_s.lo);
144 #endif
145 
146 	return res;
147 }
148 
149 /* -------------------------------------------------------------------------*/
150 
151 int
152 ucmpv64(
153 	const vint64 * lhs,
154 	const vint64 * rhs
155 	)
156 {
157 	int res;
158 
159 #if defined(HAVE_INT64)
160 	res = (lhs->Q_s > rhs->Q_s)
161 	    - (lhs->Q_s < rhs->Q_s);
162 #else
163 	res = (lhs->D_s.hi > rhs->D_s.hi)
164 	    - (lhs->D_s.hi < rhs->D_s.hi);
165 	if ( ! res )
166 		res = (lhs->D_s.lo > rhs->D_s.lo)
167 		    - (lhs->D_s.lo < rhs->D_s.lo);
168 #endif
169 	return res;
170 }
171 
172 /* -------------------------------------------------------------------------*/
173 
174 vint64
175 addv64(
176 	const vint64 *lhs,
177 	const vint64 *rhs
178 	)
179 {
180 	vint64 res;
181 
182 #if defined(HAVE_INT64)
183 	res.Q_s = lhs->Q_s + rhs->Q_s;
184 #else
185 	res = *lhs;
186 	M_ADD(res.D_s.hi, res.D_s.lo, rhs->D_s.hi, rhs->D_s.lo);
187 #endif
188 	return res;
189 }
190 
191 /* -------------------------------------------------------------------------*/
192 
193 vint64
194 subv64(
195 	const vint64 *lhs,
196 	const vint64 *rhs
197 	)
198 {
199 	vint64 res;
200 
201 #if defined(HAVE_INT64)
202 	res.Q_s = lhs->Q_s - rhs->Q_s;
203 #else
204 	res = *lhs;
205 	M_SUB(res.D_s.hi, res.D_s.lo, rhs->D_s.hi, rhs->D_s.lo);
206 #endif
207 	return res;
208 }
209 
210 /* -------------------------------------------------------------------------*/
211 
212 vint64
213 addv64i32(
214 	const vint64 * lhs,
215 	int32_t        rhs
216 	)
217 {
218 	vint64 res;
219 
220 	res = *lhs;
221 #if defined(HAVE_INT64)
222 	res.q_s += rhs;
223 #else
224 	M_ADD(res.D_s.hi, res.D_s.lo,  -(rhs < 0), rhs);
225 #endif
226 	return res;
227 }
228 
229 /* -------------------------------------------------------------------------*/
230 
231 vint64
232 subv64i32(
233 	const vint64 * lhs,
234 	int32_t        rhs
235 	)
236 {
237 	vint64 res;
238 
239 	res = *lhs;
240 #if defined(HAVE_INT64)
241 	res.q_s -= rhs;
242 #else
243 	M_SUB(res.D_s.hi, res.D_s.lo,  -(rhs < 0), rhs);
244 #endif
245 	return res;
246 }
247 
248 /* -------------------------------------------------------------------------*/
249 
250 vint64
251 addv64u32(
252 	const vint64 * lhs,
253 	uint32_t       rhs
254 	)
255 {
256 	vint64 res;
257 
258 	res = *lhs;
259 #if defined(HAVE_INT64)
260 	res.Q_s += rhs;
261 #else
262 	M_ADD(res.D_s.hi, res.D_s.lo, 0, rhs);
263 #endif
264 	return res;
265 }
266 
267 /* -------------------------------------------------------------------------*/
268 
269 vint64
270 subv64u32(
271 	const vint64 * lhs,
272 	uint32_t       rhs
273 	)
274 {
275 	vint64 res;
276 
277 	res = *lhs;
278 #if defined(HAVE_INT64)
279 	res.Q_s -= rhs;
280 #else
281 	M_SUB(res.D_s.hi, res.D_s.lo, 0, rhs);
282 #endif
283 	return res;
284 }
285