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