/* $NetBSD: mstolfp.c,v 1.9 2024/08/18 20:47:13 christos Exp $ */ /* * mstolfp - convert an ascii string in milliseconds to an l_fp number */ #include #include #include #include "ntp_fp.h" #include "ntp_stdlib.h" int mstolfp( const char *str, l_fp *lfp ) { int ch, neg = 0; u_int32 q, r; /* * We understand numbers of the form: * * [spaces][-|+][digits][.][digits][spaces|\n|\0] * * This is kinda hack. We use 'atolfp' to do the basic parsing * (after some initial checks) and then divide the result by * 1000. The original implementation avoided that by * hacking up the input string to move the decimal point, but * that needed string manipulations prone to buffer overruns. * To avoid that trouble we do the conversion first and adjust * the result. */ while (isspace(ch = *(const unsigned char*)str)) ++str; switch (ch) { case '-': neg = TRUE; /* FALLTHROUGH */ case '+': ++str; default : break; } if (!isdigit(ch = *(const unsigned char*)str) && (ch != '.')) return 0; if (!atolfp(str, lfp)) return 0; /* now do a chained/overlapping division by 1000 to get from * seconds to msec. 1000 is small enough to go with temporary * 32bit accus for Q and R. */ q = lfp->l_ui / 1000u; r = lfp->l_ui - (q * 1000u); lfp->l_ui = q; r = (r << 16) | (lfp->l_uf >> 16); q = r / 1000u; r = ((r - q * 1000) << 16) | (lfp->l_uf & 0x0FFFFu); lfp->l_uf = q << 16; q = r / 1000; lfp->l_uf |= q; r -= q * 1000u; /* fix sign */ if (neg) L_NEG(lfp); /* round */ if (r >= 500) L_ADDF(lfp, (neg ? -1 : 1)); return 1; }