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