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