xref: /freebsd/contrib/ntp/libntp/mstolfp.c (revision e7437ae907c89bf85a99c5cbb7ddd194a1ff1354)
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 == '-' || *cp == '+') {
39 		*bp++ = *cp++;
40 	}
41 
42 	if (*cp != '.' && !isdigit((unsigned char)*cp))
43 	    return 0;
44 
45 
46 	/*
47 	 * Search forward for the decimal point or the end of the string.
48 	 */
49 	cpdec = cp;
50 	while (isdigit((unsigned char)*cpdec))
51 	    cpdec++;
52 
53 	/*
54 	 * Found something.  If we have more than three digits copy the
55 	 * excess over, else insert a leading 0.
56 	 */
57 	if ((cpdec - cp) > 3) {
58 		do {
59 			*bp++ = (char)*cp++;
60 		} while ((cpdec - cp) > 3);
61 	} else {
62 		*bp++ = '0';
63 	}
64 
65 	/*
66 	 * Stick the decimal in.  If we've got less than three digits in
67 	 * front of the millisecond decimal we insert the appropriate number
68 	 * of zeros.
69 	 */
70 	*bp++ = '.';
71 	if ((cpdec - cp) < 3) {
72 		size_t i = 3 - (cpdec - cp);
73 		do {
74 			*bp++ = '0';
75 		} while (--i > 0);
76 	}
77 
78 	/*
79 	 * Copy the remainder up to the millisecond decimal.  If cpdec
80 	 * is pointing at a decimal point, copy in the trailing number too.
81 	 */
82 	while (cp < cpdec)
83 	    *bp++ = (char)*cp++;
84 
85 	if (*cp == '.') {
86 		cp++;
87 		while (isdigit((unsigned char)*cp))
88 		    *bp++ = (char)*cp++;
89 	}
90 	*bp = '\0';
91 
92 	/*
93 	 * Check to make sure the string is properly terminated.  If
94 	 * so, give the buffer to the decoding routine.
95 	 */
96 	if (*cp != '\0' && !isspace((unsigned char)*cp))
97 	    return 0;
98 	return atolfp(buf, lfp);
99 }
100