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