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