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 "ntp_malloc.h" 19 #include "vint64ops.h" 20 21 /* -------------------------------------------------------------------------*/ 22 23 vint64 24 strtouv64( 25 char * begp, 26 char ** endp, 27 int base 28 ) 29 { 30 vint64 res; 31 u_char digit; 32 int sig, num; 33 u_char *src; 34 35 num = sig = 0; 36 src = (u_char *)begp; 37 while (isspace(*src)) 38 src++; 39 40 if (*src == '-') { 41 src++; 42 sig = 1; 43 } else if (*src == '+') { 44 src++; 45 } 46 47 if (base == 0) { 48 base = 10; 49 if (*src == '0') { 50 base = 8; 51 if (toupper(*++src) == 'X') { 52 src++; 53 base = 16; 54 } 55 } 56 } else if (base == 16) { /* remove optional leading '0x' or '0X' */ 57 if (src[0] == '0' && toupper(src[1]) == 'X') 58 src += 2; 59 } else if (base <= 2 || base > 36) { 60 memset(&res, 0xFF, sizeof(res)); 61 errno = ERANGE; 62 return res; 63 } 64 65 ZERO(res); 66 while (*src) { 67 if (isdigit(*src)) 68 digit = *src - '0'; 69 else if (isupper(*src)) 70 digit = *src - 'A' + 10; 71 else if (islower(*src)) 72 digit = *src - 'a' + 10; 73 else 74 break; 75 if (digit >= base) 76 break; 77 num = 1; 78 #if defined(HAVE_INT64) 79 res.Q_s = res.Q_s * base + digit; 80 #else 81 /* res *= base, using 16x16->32 bit 82 * multiplication. Slow but portable. 83 */ 84 { 85 uint32_t accu; 86 accu = (uint32_t)res.W_s.ll * base; 87 res.W_s.ll = (uint16_t)accu; 88 accu = (accu >> 16) 89 + (uint32_t)res.W_s.lh * base; 90 res.W_s.lh = (uint16_t)accu; 91 /* the upper bits can be done in one step: */ 92 res.D_s.hi = res.D_s.hi * base + (accu >> 16); 93 } 94 M_ADD(res.D_s.hi, res.D_s.lo, 0, digit); 95 #endif 96 src++; 97 } 98 if (!num) 99 errno = EINVAL; 100 if (endp) 101 *endp = (char *)src; 102 if (sig) 103 M_NEG(res.D_s.hi, res.D_s.lo); 104 return res; 105 } 106 107 /* -------------------------------------------------------------------------*/ 108 109 int 110 icmpv64( 111 const vint64 * lhs, 112 const vint64 * rhs 113 ) 114 { 115 int res; 116 117 #if defined(HAVE_INT64) 118 res = (lhs->q_s > rhs->q_s) 119 - (lhs->q_s < rhs->q_s); 120 #else 121 res = (lhs->d_s.hi > rhs->d_s.hi) 122 - (lhs->d_s.hi < rhs->d_s.hi); 123 if ( ! res ) 124 res = (lhs->D_s.lo > rhs->D_s.lo) 125 - (lhs->D_s.lo < rhs->D_s.lo); 126 #endif 127 128 return res; 129 } 130 131 /* -------------------------------------------------------------------------*/ 132 133 int 134 ucmpv64( 135 const vint64 * lhs, 136 const vint64 * rhs 137 ) 138 { 139 int res; 140 141 #if defined(HAVE_INT64) 142 res = (lhs->Q_s > rhs->Q_s) 143 - (lhs->Q_s < rhs->Q_s); 144 #else 145 res = (lhs->D_s.hi > rhs->D_s.hi) 146 - (lhs->D_s.hi < rhs->D_s.hi); 147 if ( ! res ) 148 res = (lhs->D_s.lo > rhs->D_s.lo) 149 - (lhs->D_s.lo < rhs->D_s.lo); 150 #endif 151 return res; 152 } 153 154 /* -------------------------------------------------------------------------*/ 155 156 vint64 157 addv64( 158 const vint64 *lhs, 159 const vint64 *rhs 160 ) 161 { 162 vint64 res; 163 164 #if defined(HAVE_INT64) 165 res.Q_s = lhs->Q_s + rhs->Q_s; 166 #else 167 res = *lhs; 168 M_ADD(res.D_s.hi, res.D_s.lo, rhs->D_s.hi, rhs->D_s.lo); 169 #endif 170 return res; 171 } 172 173 /* -------------------------------------------------------------------------*/ 174 175 vint64 176 subv64( 177 const vint64 *lhs, 178 const vint64 *rhs 179 ) 180 { 181 vint64 res; 182 183 #if defined(HAVE_INT64) 184 res.Q_s = lhs->Q_s - rhs->Q_s; 185 #else 186 res = *lhs; 187 M_SUB(res.D_s.hi, res.D_s.lo, rhs->D_s.hi, rhs->D_s.lo); 188 #endif 189 return res; 190 } 191 192 /* -------------------------------------------------------------------------*/ 193 194 vint64 195 addv64i32( 196 const vint64 * lhs, 197 int32_t rhs 198 ) 199 { 200 vint64 res; 201 202 res = *lhs; 203 #if defined(HAVE_INT64) 204 res.q_s += rhs; 205 #else 206 M_ADD(res.D_s.hi, res.D_s.lo, -(rhs < 0), rhs); 207 #endif 208 return res; 209 } 210 211 /* -------------------------------------------------------------------------*/ 212 213 vint64 214 subv64i32( 215 const vint64 * lhs, 216 int32_t rhs 217 ) 218 { 219 vint64 res; 220 221 res = *lhs; 222 #if defined(HAVE_INT64) 223 res.q_s -= rhs; 224 #else 225 M_SUB(res.D_s.hi, res.D_s.lo, -(rhs < 0), rhs); 226 #endif 227 return res; 228 } 229 230 /* -------------------------------------------------------------------------*/ 231 232 vint64 233 addv64u32( 234 const vint64 * lhs, 235 uint32_t rhs 236 ) 237 { 238 vint64 res; 239 240 res = *lhs; 241 #if defined(HAVE_INT64) 242 res.Q_s += rhs; 243 #else 244 M_ADD(res.D_s.hi, res.D_s.lo, 0, rhs); 245 #endif 246 return res; 247 } 248 249 /* -------------------------------------------------------------------------*/ 250 251 vint64 252 subv64u32( 253 const vint64 * lhs, 254 uint32_t rhs 255 ) 256 { 257 vint64 res; 258 259 res = *lhs; 260 #if defined(HAVE_INT64) 261 res.Q_s -= rhs; 262 #else 263 M_SUB(res.D_s.hi, res.D_s.lo, 0, rhs); 264 #endif 265 return res; 266 } 267