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