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