xref: /freebsd/contrib/ntp/libntp/mstolfp.c (revision f39bffc62c1395bde25d152c7f68fdf7cbaab414)
1 /*
2  * mstolfp - convert an ascii string in milliseconds to an l_fp number
3  */
4 #include <config.h>
5 #include <stdio.h>
6 #include <ctype.h>
7 
8 #include "ntp_fp.h"
9 #include "ntp_stdlib.h"
10 
11 int
12 mstolfp(
13 	const char *str,
14 	l_fp *lfp
15 	)
16 {
17 	register const char *cp;
18 	register char *bp;
19 	register const char *cpdec;
20 	char buf[100];
21 
22 	/*
23 	 * We understand numbers of the form:
24 	 *
25 	 * [spaces][-][digits][.][digits][spaces|\n|\0]
26 	 *
27 	 * This is one enormous hack.  Since I didn't feel like
28 	 * rewriting the decoding routine for milliseconds, what
29 	 * is essentially done here is to make a copy of the string
30 	 * with the decimal moved over three places so the seconds
31 	 * decoding routine can be used.
32 	 */
33 	bp = buf;
34 	cp = str;
35 	while (isspace((unsigned char)*cp))
36 	    cp++;
37 
38 	if (*cp == '-') {
39 		*bp++ = '-';
40 		cp++;
41 	}
42 
43 	if (*cp != '.' && !isdigit((unsigned char)*cp))
44 	    return 0;
45 
46 
47 	/*
48 	 * Search forward for the decimal point or the end of the string.
49 	 */
50 	cpdec = cp;
51 	while (isdigit((unsigned char)*cpdec))
52 	    cpdec++;
53 
54 	/*
55 	 * Found something.  If we have more than three digits copy the
56 	 * excess over, else insert a leading 0.
57 	 */
58 	if ((cpdec - cp) > 3) {
59 		do {
60 			*bp++ = (char)*cp++;
61 		} while ((cpdec - cp) > 3);
62 	} else {
63 		*bp++ = '0';
64 	}
65 
66 	/*
67 	 * Stick the decimal in.  If we've got less than three digits in
68 	 * front of the millisecond decimal we insert the appropriate number
69 	 * of zeros.
70 	 */
71 	*bp++ = '.';
72 	if ((cpdec - cp) < 3) {
73 		size_t i = 3 - (cpdec - cp);
74 		do {
75 			*bp++ = '0';
76 		} while (--i > 0);
77 	}
78 
79 	/*
80 	 * Copy the remainder up to the millisecond decimal.  If cpdec
81 	 * is pointing at a decimal point, copy in the trailing number too.
82 	 */
83 	while (cp < cpdec)
84 	    *bp++ = (char)*cp++;
85 
86 	if (*cp == '.') {
87 		cp++;
88 		while (isdigit((unsigned char)*cp))
89 		    *bp++ = (char)*cp++;
90 	}
91 	*bp = '\0';
92 
93 	/*
94 	 * Check to make sure the string is properly terminated.  If
95 	 * so, give the buffer to the decoding routine.
96 	 */
97 	if (*cp != '\0' && !isspace((unsigned char)*cp))
98 	    return 0;
99 	return atolfp(buf, lfp);
100 }
101