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