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 } 285