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