xref: /netbsd-src/external/bsd/ntp/dist/libntp/mstolfp.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: mstolfp.c,v 1.9 2024/08/18 20:47:13 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  * mstolfp - convert an ascii string in milliseconds to an l_fp number
5abb0f93cSkardel  */
62950cc38Schristos #include <config.h>
7abb0f93cSkardel #include <stdio.h>
8abb0f93cSkardel #include <ctype.h>
9abb0f93cSkardel 
10abb0f93cSkardel #include "ntp_fp.h"
11abb0f93cSkardel #include "ntp_stdlib.h"
12abb0f93cSkardel 
13abb0f93cSkardel int
14abb0f93cSkardel mstolfp(
15abb0f93cSkardel 	const char *str,
16abb0f93cSkardel 	l_fp *lfp
17abb0f93cSkardel 	)
18abb0f93cSkardel {
19*eabc0478Schristos 	int        ch, neg = 0;
20*eabc0478Schristos 	u_int32    q, r;
21abb0f93cSkardel 
22abb0f93cSkardel 	/*
23abb0f93cSkardel 	 * We understand numbers of the form:
24abb0f93cSkardel 	 *
25cdfa2a7eSchristos 	 * [spaces][-|+][digits][.][digits][spaces|\n|\0]
26abb0f93cSkardel 	 *
27*eabc0478Schristos 	 * This is kinda hack.  We use 'atolfp' to do the basic parsing
28*eabc0478Schristos 	 * (after some initial checks) and then divide the result by
29*eabc0478Schristos 	 * 1000.  The original implementation avoided that by
30*eabc0478Schristos 	 * hacking up the input string to move the decimal point, but
31*eabc0478Schristos 	 * that needed string manipulations prone to buffer overruns.
32*eabc0478Schristos 	 * To avoid that trouble we do the conversion first and adjust
33*eabc0478Schristos 	 * the result.
34abb0f93cSkardel 	 */
35abb0f93cSkardel 
36*eabc0478Schristos 	while (isspace(ch = *(const unsigned char*)str))
37*eabc0478Schristos 		++str;
38*eabc0478Schristos 
39*eabc0478Schristos 	switch (ch) {
40*eabc0478Schristos 	    case '-': neg = TRUE;
41*eabc0478Schristos 		/* FALLTHROUGH */
42*eabc0478Schristos 	    case '+': ++str;
43*eabc0478Schristos 	    default : break;
44abb0f93cSkardel 	}
45abb0f93cSkardel 
46*eabc0478Schristos 	if (!isdigit(ch = *(const unsigned char*)str) && (ch != '.'))
47*eabc0478Schristos 		return 0;
48*eabc0478Schristos 	if (!atolfp(str, lfp))
49abb0f93cSkardel 		return 0;
50abb0f93cSkardel 
51*eabc0478Schristos 	/* now do a chained/overlapping division by 1000 to get from
52*eabc0478Schristos 	 * seconds to msec. 1000 is small enough to go with temporary
53*eabc0478Schristos 	 * 32bit accus for Q and R.
54abb0f93cSkardel 	 */
55*eabc0478Schristos 	q = lfp->l_ui / 1000u;
56*eabc0478Schristos 	r = lfp->l_ui - (q * 1000u);
57*eabc0478Schristos 	lfp->l_ui = q;
58abb0f93cSkardel 
59*eabc0478Schristos 	r = (r << 16) | (lfp->l_uf >> 16);
60*eabc0478Schristos 	q = r / 1000u;
61*eabc0478Schristos 	r = ((r - q * 1000) << 16) | (lfp->l_uf & 0x0FFFFu);
62*eabc0478Schristos 	lfp->l_uf = q << 16;
63*eabc0478Schristos 	q = r / 1000;
64*eabc0478Schristos 	lfp->l_uf |= q;
65*eabc0478Schristos 	r -= q * 1000u;
66abb0f93cSkardel 
67*eabc0478Schristos 	/* fix sign */
68*eabc0478Schristos 	if (neg)
69*eabc0478Schristos 		L_NEG(lfp);
70*eabc0478Schristos 	/* round */
71*eabc0478Schristos 	if (r >= 500)
72*eabc0478Schristos 		L_ADDF(lfp, (neg ? -1 : 1));
73*eabc0478Schristos 	return 1;
74abb0f93cSkardel }
75