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