1 /* $NetBSD: vint64ops.c,v 1.5 2020/05/25 20:47:24 christos Exp $ */ 2 3 /* 4 * vint64ops.c - operations on 'vint64' values 5 * 6 * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project. 7 * The contents of 'html/copyright.html' apply. 8 * ---------------------------------------------------------------------- 9 * This is an attempt to get the vint64 calculations stuff centralised. 10 */ 11 12 #include <config.h> 13 #include <stdlib.h> 14 #include <ctype.h> 15 #include <string.h> 16 #include <errno.h> 17 18 #include "ntp_types.h" 19 #include "ntp_fp.h" 20 #include "vint64ops.h" 21 22 /* --------------------------------------------------------------------- 23 * GCC is rather sticky with its 'const' attribute. We have to do it more 24 * explicit than with a cast if we want to get rid of a CONST qualifier. 25 * Greetings from the PASCAL world, where casting was only possible via 26 * untagged unions... 27 */ 28 static inline void* 29 noconst( 30 const void* ptr 31 ) 32 { 33 union { 34 const void * cp; 35 void * vp; 36 } tmp; 37 tmp.cp = ptr; 38 return tmp.vp; 39 } 40 41 /* -------------------------------------------------------------------------*/ 42 43 vint64 44 strtouv64( 45 const char * begp, 46 char ** endp, 47 int base 48 ) 49 { 50 vint64 res; 51 u_char digit; 52 int sig, num; 53 const u_char *src; 54 55 num = sig = 0; 56 src = (const u_char*)begp; 57 while (isspace(*src)) 58 src++; 59 60 if (*src == '-') { 61 src++; 62 sig = 1; 63 } else if (*src == '+') { 64 src++; 65 } 66 67 if (base == 0) { 68 base = 10; 69 if (*src == '0') { 70 base = 8; 71 if (toupper(*++src) == 'X') { 72 src++; 73 base = 16; 74 } 75 } 76 } else if (base == 16) { /* remove optional leading '0x' or '0X' */ 77 if (src[0] == '0' && toupper(src[1]) == 'X') 78 src += 2; 79 } else if (base <= 2 || base > 36) { 80 memset(&res, 0xFF, sizeof(res)); 81 errno = ERANGE; 82 return res; 83 } 84 85 memset(&res, 0, sizeof(res)); 86 while (*src) { 87 if (isdigit(*src)) 88 digit = *src - '0'; 89 else if (isupper(*src)) 90 digit = *src - 'A' + 10; 91 else if (islower(*src)) 92 digit = *src - 'a' + 10; 93 else 94 break; 95 if (digit >= base) 96 break; 97 num = 1; 98 #if defined(HAVE_INT64) 99 res.Q_s = res.Q_s * base + digit; 100 #else 101 /* res *= base, using 16x16->32 bit 102 * multiplication. Slow but portable. 103 */ 104 { 105 uint32_t accu; 106 accu = (uint32_t)res.W_s.ll * base; 107 res.W_s.ll = (uint16_t)accu; 108 accu = (accu >> 16) 109 + (uint32_t)res.W_s.lh * base; 110 res.W_s.lh = (uint16_t)accu; 111 /* the upper bits can be done in one step: */ 112 res.D_s.hi = res.D_s.hi * base + (accu >> 16); 113 } 114 M_ADD(res.D_s.hi, res.D_s.lo, 0, digit); 115 #endif 116 src++; 117 } 118 if (!num) 119 errno = EINVAL; 120 if (endp) 121 *endp = (char*)noconst(src); 122 if (sig) 123 M_NEG(res.D_s.hi, res.D_s.lo); 124 return res; 125 } 126 127 /* -------------------------------------------------------------------------*/ 128 129 int 130 icmpv64( 131 const vint64 * lhs, 132 const vint64 * rhs 133 ) 134 { 135 int res; 136 137 #if defined(HAVE_INT64) 138 res = (lhs->q_s > rhs->q_s) 139 - (lhs->q_s < rhs->q_s); 140 #else 141 res = (lhs->d_s.hi > rhs->d_s.hi) 142 - (lhs->d_s.hi < rhs->d_s.hi); 143 if ( ! res ) 144 res = (lhs->D_s.lo > rhs->D_s.lo) 145 - (lhs->D_s.lo < rhs->D_s.lo); 146 #endif 147 148 return res; 149 } 150 151 /* -------------------------------------------------------------------------*/ 152 153 int 154 ucmpv64( 155 const vint64 * lhs, 156 const vint64 * rhs 157 ) 158 { 159 int res; 160 161 #if defined(HAVE_INT64) 162 res = (lhs->Q_s > rhs->Q_s) 163 - (lhs->Q_s < rhs->Q_s); 164 #else 165 res = (lhs->D_s.hi > rhs->D_s.hi) 166 - (lhs->D_s.hi < rhs->D_s.hi); 167 if ( ! res ) 168 res = (lhs->D_s.lo > rhs->D_s.lo) 169 - (lhs->D_s.lo < rhs->D_s.lo); 170 #endif 171 return res; 172 } 173 174 /* -------------------------------------------------------------------------*/ 175 176 vint64 177 addv64( 178 const vint64 *lhs, 179 const vint64 *rhs 180 ) 181 { 182 vint64 res; 183 184 #if defined(HAVE_INT64) 185 res.Q_s = lhs->Q_s + rhs->Q_s; 186 #else 187 res = *lhs; 188 M_ADD(res.D_s.hi, res.D_s.lo, rhs->D_s.hi, rhs->D_s.lo); 189 #endif 190 return res; 191 } 192 193 /* -------------------------------------------------------------------------*/ 194 195 vint64 196 subv64( 197 const vint64 *lhs, 198 const vint64 *rhs 199 ) 200 { 201 vint64 res; 202 203 #if defined(HAVE_INT64) 204 res.Q_s = lhs->Q_s - rhs->Q_s; 205 #else 206 res = *lhs; 207 M_SUB(res.D_s.hi, res.D_s.lo, rhs->D_s.hi, rhs->D_s.lo); 208 #endif 209 return res; 210 } 211 212 /* -------------------------------------------------------------------------*/ 213 214 vint64 215 addv64i32( 216 const vint64 * lhs, 217 int32_t rhs 218 ) 219 { 220 vint64 res; 221 222 res = *lhs; 223 #if defined(HAVE_INT64) 224 res.q_s += rhs; 225 #else 226 M_ADD(res.D_s.hi, res.D_s.lo, -(rhs < 0), rhs); 227 #endif 228 return res; 229 } 230 231 /* -------------------------------------------------------------------------*/ 232 233 vint64 234 subv64i32( 235 const vint64 * lhs, 236 int32_t rhs 237 ) 238 { 239 vint64 res; 240 241 res = *lhs; 242 #if defined(HAVE_INT64) 243 res.q_s -= rhs; 244 #else 245 M_SUB(res.D_s.hi, res.D_s.lo, -(rhs < 0), rhs); 246 #endif 247 return res; 248 } 249 250 /* -------------------------------------------------------------------------*/ 251 252 vint64 253 addv64u32( 254 const vint64 * lhs, 255 uint32_t rhs 256 ) 257 { 258 vint64 res; 259 260 res = *lhs; 261 #if defined(HAVE_INT64) 262 res.Q_s += rhs; 263 #else 264 M_ADD(res.D_s.hi, res.D_s.lo, 0, rhs); 265 #endif 266 return res; 267 } 268 269 /* -------------------------------------------------------------------------*/ 270 271 vint64 272 subv64u32( 273 const vint64 * lhs, 274 uint32_t rhs 275 ) 276 { 277 vint64 res; 278 279 res = *lhs; 280 #if defined(HAVE_INT64) 281 res.Q_s -= rhs; 282 #else 283 M_SUB(res.D_s.hi, res.D_s.lo, 0, rhs); 284 #endif 285 return res; 286 } 287