diff options
Diffstat (limited to 'contrib/ntp/libntp/mstolfp.c')
-rw-r--r-- | contrib/ntp/libntp/mstolfp.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/contrib/ntp/libntp/mstolfp.c b/contrib/ntp/libntp/mstolfp.c new file mode 100644 index 000000000000..428f71bdbae9 --- /dev/null +++ b/contrib/ntp/libntp/mstolfp.c @@ -0,0 +1,71 @@ +/* + * mstolfp - convert an ascii string in milliseconds to an l_fp number + */ +#include <config.h> +#include <stdio.h> +#include <ctype.h> + +#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; + 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; +} |