Home | History | Annotate | Line # | Download | only in libntp
      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 (at) 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