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