12b15cb3dSCy Schubert /* 22b15cb3dSCy Schubert * vint64ops.c - operations on 'vint64' values 32b15cb3dSCy Schubert * 42b15cb3dSCy Schubert * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project. 52b15cb3dSCy Schubert * The contents of 'html/copyright.html' apply. 62b15cb3dSCy Schubert * ---------------------------------------------------------------------- 72b15cb3dSCy Schubert * This is an attempt to get the vint64 calculations stuff centralised. 82b15cb3dSCy Schubert */ 92b15cb3dSCy Schubert 102b15cb3dSCy Schubert #include <config.h> 112b15cb3dSCy Schubert #include <stdlib.h> 122b15cb3dSCy Schubert #include <ctype.h> 132b15cb3dSCy Schubert #include <string.h> 142b15cb3dSCy Schubert #include <errno.h> 152b15cb3dSCy Schubert 162b15cb3dSCy Schubert #include "ntp_types.h" 172b15cb3dSCy Schubert #include "ntp_fp.h" 18*f5f40dd6SCy Schubert #include "ntp_malloc.h" 192b15cb3dSCy Schubert #include "vint64ops.h" 202b15cb3dSCy Schubert 212b15cb3dSCy Schubert /* -------------------------------------------------------------------------*/ 222b15cb3dSCy Schubert 232b15cb3dSCy Schubert vint64 242b15cb3dSCy Schubert strtouv64( 25*f5f40dd6SCy Schubert char * begp, 26*f5f40dd6SCy Schubert char ** endp, 272b15cb3dSCy Schubert int base 282b15cb3dSCy Schubert ) 292b15cb3dSCy Schubert { 302b15cb3dSCy Schubert vint64 res; 312b15cb3dSCy Schubert u_char digit; 322b15cb3dSCy Schubert int sig, num; 33*f5f40dd6SCy Schubert u_char *src; 342b15cb3dSCy Schubert 352b15cb3dSCy Schubert num = sig = 0; 36*f5f40dd6SCy Schubert src = (u_char *)begp; 372b15cb3dSCy Schubert while (isspace(*src)) 382b15cb3dSCy Schubert src++; 392b15cb3dSCy Schubert 402b15cb3dSCy Schubert if (*src == '-') { 412b15cb3dSCy Schubert src++; 422b15cb3dSCy Schubert sig = 1; 432b15cb3dSCy Schubert } else if (*src == '+') { 442b15cb3dSCy Schubert src++; 452b15cb3dSCy Schubert } 462b15cb3dSCy Schubert 472b15cb3dSCy Schubert if (base == 0) { 482b15cb3dSCy Schubert base = 10; 492b15cb3dSCy Schubert if (*src == '0') { 502b15cb3dSCy Schubert base = 8; 512b15cb3dSCy Schubert if (toupper(*++src) == 'X') { 522b15cb3dSCy Schubert src++; 532b15cb3dSCy Schubert base = 16; 542b15cb3dSCy Schubert } 552b15cb3dSCy Schubert } 562b15cb3dSCy Schubert } else if (base == 16) { /* remove optional leading '0x' or '0X' */ 572b15cb3dSCy Schubert if (src[0] == '0' && toupper(src[1]) == 'X') 582b15cb3dSCy Schubert src += 2; 592b15cb3dSCy Schubert } else if (base <= 2 || base > 36) { 602b15cb3dSCy Schubert memset(&res, 0xFF, sizeof(res)); 612b15cb3dSCy Schubert errno = ERANGE; 622b15cb3dSCy Schubert return res; 632b15cb3dSCy Schubert } 642b15cb3dSCy Schubert 65*f5f40dd6SCy Schubert ZERO(res); 662b15cb3dSCy Schubert while (*src) { 672b15cb3dSCy Schubert if (isdigit(*src)) 682b15cb3dSCy Schubert digit = *src - '0'; 692b15cb3dSCy Schubert else if (isupper(*src)) 702b15cb3dSCy Schubert digit = *src - 'A' + 10; 712b15cb3dSCy Schubert else if (islower(*src)) 722b15cb3dSCy Schubert digit = *src - 'a' + 10; 732b15cb3dSCy Schubert else 742b15cb3dSCy Schubert break; 752b15cb3dSCy Schubert if (digit >= base) 762b15cb3dSCy Schubert break; 772b15cb3dSCy Schubert num = 1; 782b15cb3dSCy Schubert #if defined(HAVE_INT64) 792b15cb3dSCy Schubert res.Q_s = res.Q_s * base + digit; 802b15cb3dSCy Schubert #else 812b15cb3dSCy Schubert /* res *= base, using 16x16->32 bit 822b15cb3dSCy Schubert * multiplication. Slow but portable. 832b15cb3dSCy Schubert */ 842b15cb3dSCy Schubert { 852b15cb3dSCy Schubert uint32_t accu; 862b15cb3dSCy Schubert accu = (uint32_t)res.W_s.ll * base; 872b15cb3dSCy Schubert res.W_s.ll = (uint16_t)accu; 882b15cb3dSCy Schubert accu = (accu >> 16) 892b15cb3dSCy Schubert + (uint32_t)res.W_s.lh * base; 902b15cb3dSCy Schubert res.W_s.lh = (uint16_t)accu; 912b15cb3dSCy Schubert /* the upper bits can be done in one step: */ 922b15cb3dSCy Schubert res.D_s.hi = res.D_s.hi * base + (accu >> 16); 932b15cb3dSCy Schubert } 942b15cb3dSCy Schubert M_ADD(res.D_s.hi, res.D_s.lo, 0, digit); 952b15cb3dSCy Schubert #endif 962b15cb3dSCy Schubert src++; 972b15cb3dSCy Schubert } 982b15cb3dSCy Schubert if (!num) 992b15cb3dSCy Schubert errno = EINVAL; 1002b15cb3dSCy Schubert if (endp) 101*f5f40dd6SCy Schubert *endp = (char *)src; 1022b15cb3dSCy Schubert if (sig) 1032b15cb3dSCy Schubert M_NEG(res.D_s.hi, res.D_s.lo); 1042b15cb3dSCy Schubert return res; 1052b15cb3dSCy Schubert } 1062b15cb3dSCy Schubert 1072b15cb3dSCy Schubert /* -------------------------------------------------------------------------*/ 1082b15cb3dSCy Schubert 1092b15cb3dSCy Schubert int 1102b15cb3dSCy Schubert icmpv64( 1112b15cb3dSCy Schubert const vint64 * lhs, 1122b15cb3dSCy Schubert const vint64 * rhs 1132b15cb3dSCy Schubert ) 1142b15cb3dSCy Schubert { 1152b15cb3dSCy Schubert int res; 1162b15cb3dSCy Schubert 1172b15cb3dSCy Schubert #if defined(HAVE_INT64) 1182b15cb3dSCy Schubert res = (lhs->q_s > rhs->q_s) 1192b15cb3dSCy Schubert - (lhs->q_s < rhs->q_s); 1202b15cb3dSCy Schubert #else 1212b15cb3dSCy Schubert res = (lhs->d_s.hi > rhs->d_s.hi) 1222b15cb3dSCy Schubert - (lhs->d_s.hi < rhs->d_s.hi); 1232b15cb3dSCy Schubert if ( ! res ) 1242b15cb3dSCy Schubert res = (lhs->D_s.lo > rhs->D_s.lo) 1252b15cb3dSCy Schubert - (lhs->D_s.lo < rhs->D_s.lo); 1262b15cb3dSCy Schubert #endif 1272b15cb3dSCy Schubert 1282b15cb3dSCy Schubert return res; 1292b15cb3dSCy Schubert } 1302b15cb3dSCy Schubert 1312b15cb3dSCy Schubert /* -------------------------------------------------------------------------*/ 1322b15cb3dSCy Schubert 1332b15cb3dSCy Schubert int 1342b15cb3dSCy Schubert ucmpv64( 1352b15cb3dSCy Schubert const vint64 * lhs, 1362b15cb3dSCy Schubert const vint64 * rhs 1372b15cb3dSCy Schubert ) 1382b15cb3dSCy Schubert { 1392b15cb3dSCy Schubert int res; 1402b15cb3dSCy Schubert 1412b15cb3dSCy Schubert #if defined(HAVE_INT64) 1422b15cb3dSCy Schubert res = (lhs->Q_s > rhs->Q_s) 1432b15cb3dSCy Schubert - (lhs->Q_s < rhs->Q_s); 1442b15cb3dSCy Schubert #else 1452b15cb3dSCy Schubert res = (lhs->D_s.hi > rhs->D_s.hi) 1462b15cb3dSCy Schubert - (lhs->D_s.hi < rhs->D_s.hi); 1472b15cb3dSCy Schubert if ( ! res ) 1482b15cb3dSCy Schubert res = (lhs->D_s.lo > rhs->D_s.lo) 1492b15cb3dSCy Schubert - (lhs->D_s.lo < rhs->D_s.lo); 1502b15cb3dSCy Schubert #endif 1512b15cb3dSCy Schubert return res; 1522b15cb3dSCy Schubert } 1532b15cb3dSCy Schubert 1542b15cb3dSCy Schubert /* -------------------------------------------------------------------------*/ 1552b15cb3dSCy Schubert 1562b15cb3dSCy Schubert vint64 1572b15cb3dSCy Schubert addv64( 1582b15cb3dSCy Schubert const vint64 *lhs, 1592b15cb3dSCy Schubert const vint64 *rhs 1602b15cb3dSCy Schubert ) 1612b15cb3dSCy Schubert { 1622b15cb3dSCy Schubert vint64 res; 1632b15cb3dSCy Schubert 1642b15cb3dSCy Schubert #if defined(HAVE_INT64) 1652b15cb3dSCy Schubert res.Q_s = lhs->Q_s + rhs->Q_s; 1662b15cb3dSCy Schubert #else 1672b15cb3dSCy Schubert res = *lhs; 1682b15cb3dSCy Schubert M_ADD(res.D_s.hi, res.D_s.lo, rhs->D_s.hi, rhs->D_s.lo); 1692b15cb3dSCy Schubert #endif 1702b15cb3dSCy Schubert return res; 1712b15cb3dSCy Schubert } 1722b15cb3dSCy Schubert 1732b15cb3dSCy Schubert /* -------------------------------------------------------------------------*/ 1742b15cb3dSCy Schubert 1752b15cb3dSCy Schubert vint64 1762b15cb3dSCy Schubert subv64( 1772b15cb3dSCy Schubert const vint64 *lhs, 1782b15cb3dSCy Schubert const vint64 *rhs 1792b15cb3dSCy Schubert ) 1802b15cb3dSCy Schubert { 1812b15cb3dSCy Schubert vint64 res; 1822b15cb3dSCy Schubert 1832b15cb3dSCy Schubert #if defined(HAVE_INT64) 1842b15cb3dSCy Schubert res.Q_s = lhs->Q_s - rhs->Q_s; 1852b15cb3dSCy Schubert #else 1862b15cb3dSCy Schubert res = *lhs; 1872b15cb3dSCy Schubert M_SUB(res.D_s.hi, res.D_s.lo, rhs->D_s.hi, rhs->D_s.lo); 1882b15cb3dSCy Schubert #endif 1892b15cb3dSCy Schubert return res; 1902b15cb3dSCy Schubert } 1912b15cb3dSCy Schubert 1922b15cb3dSCy Schubert /* -------------------------------------------------------------------------*/ 1932b15cb3dSCy Schubert 1942b15cb3dSCy Schubert vint64 1952b15cb3dSCy Schubert addv64i32( 1962b15cb3dSCy Schubert const vint64 * lhs, 1972b15cb3dSCy Schubert int32_t rhs 1982b15cb3dSCy Schubert ) 1992b15cb3dSCy Schubert { 2002b15cb3dSCy Schubert vint64 res; 2012b15cb3dSCy Schubert 2022b15cb3dSCy Schubert res = *lhs; 2032b15cb3dSCy Schubert #if defined(HAVE_INT64) 2042b15cb3dSCy Schubert res.q_s += rhs; 2052b15cb3dSCy Schubert #else 2062b15cb3dSCy Schubert M_ADD(res.D_s.hi, res.D_s.lo, -(rhs < 0), rhs); 2072b15cb3dSCy Schubert #endif 2082b15cb3dSCy Schubert return res; 2092b15cb3dSCy Schubert } 2102b15cb3dSCy Schubert 2112b15cb3dSCy Schubert /* -------------------------------------------------------------------------*/ 2122b15cb3dSCy Schubert 2132b15cb3dSCy Schubert vint64 2142b15cb3dSCy Schubert subv64i32( 2152b15cb3dSCy Schubert const vint64 * lhs, 2162b15cb3dSCy Schubert int32_t rhs 2172b15cb3dSCy Schubert ) 2182b15cb3dSCy Schubert { 2192b15cb3dSCy Schubert vint64 res; 2202b15cb3dSCy Schubert 2212b15cb3dSCy Schubert res = *lhs; 2222b15cb3dSCy Schubert #if defined(HAVE_INT64) 2232b15cb3dSCy Schubert res.q_s -= rhs; 2242b15cb3dSCy Schubert #else 2252b15cb3dSCy Schubert M_SUB(res.D_s.hi, res.D_s.lo, -(rhs < 0), rhs); 2262b15cb3dSCy Schubert #endif 2272b15cb3dSCy Schubert return res; 2282b15cb3dSCy Schubert } 2292b15cb3dSCy Schubert 2302b15cb3dSCy Schubert /* -------------------------------------------------------------------------*/ 2312b15cb3dSCy Schubert 2322b15cb3dSCy Schubert vint64 2332b15cb3dSCy Schubert addv64u32( 2342b15cb3dSCy Schubert const vint64 * lhs, 2352b15cb3dSCy Schubert uint32_t rhs 2362b15cb3dSCy Schubert ) 2372b15cb3dSCy Schubert { 2382b15cb3dSCy Schubert vint64 res; 2392b15cb3dSCy Schubert 2402b15cb3dSCy Schubert res = *lhs; 2412b15cb3dSCy Schubert #if defined(HAVE_INT64) 2422b15cb3dSCy Schubert res.Q_s += rhs; 2432b15cb3dSCy Schubert #else 2442b15cb3dSCy Schubert M_ADD(res.D_s.hi, res.D_s.lo, 0, rhs); 2452b15cb3dSCy Schubert #endif 2462b15cb3dSCy Schubert return res; 2472b15cb3dSCy Schubert } 2482b15cb3dSCy Schubert 2492b15cb3dSCy Schubert /* -------------------------------------------------------------------------*/ 2502b15cb3dSCy Schubert 2512b15cb3dSCy Schubert vint64 2522b15cb3dSCy Schubert subv64u32( 2532b15cb3dSCy Schubert const vint64 * lhs, 2542b15cb3dSCy Schubert uint32_t rhs 2552b15cb3dSCy Schubert ) 2562b15cb3dSCy Schubert { 2572b15cb3dSCy Schubert vint64 res; 2582b15cb3dSCy Schubert 2592b15cb3dSCy Schubert res = *lhs; 2602b15cb3dSCy Schubert #if defined(HAVE_INT64) 2612b15cb3dSCy Schubert res.Q_s -= rhs; 2622b15cb3dSCy Schubert #else 2632b15cb3dSCy Schubert M_SUB(res.D_s.hi, res.D_s.lo, 0, rhs); 2642b15cb3dSCy Schubert #endif 2652b15cb3dSCy Schubert return res; 2662b15cb3dSCy Schubert } 267