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 */ 26static inline void* 27noconst( 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 41vint64 42strtouv64( 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 127int 128icmpv64( 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 151int 152ucmpv64( 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 174vint64 175addv64( 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 193vint64 194subv64( 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 212vint64 213addv64i32( 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 231vint64 232subv64i32( 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 250vint64 251addv64u32( 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 269vint64 270subv64u32( 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