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