]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/libntp/vint64ops.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ntp / libntp / vint64ops.c
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*
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
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
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
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
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
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
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
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
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
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 }