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