xref: /freebsd/contrib/ntp/libntp/vint64ops.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
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