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