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
strtouv64(char * begp,char ** endp,int base)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
icmpv64(const vint64 * lhs,const vint64 * rhs)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
ucmpv64(const vint64 * lhs,const vint64 * rhs)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
addv64(const vint64 * lhs,const vint64 * rhs)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
subv64(const vint64 * lhs,const vint64 * rhs)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
addv64i32(const vint64 * lhs,int32_t rhs)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
subv64i32(const vint64 * lhs,int32_t rhs)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
addv64u32(const vint64 * lhs,uint32_t rhs)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
subv64u32(const vint64 * lhs,uint32_t rhs)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