We have no floating point support in barebox and no strtod. Still some user interaction could benefit from being able to supply command arguments or device parameters in a format with decimal points. This new simple_strtofract() function parses a fixed point format consisting of a 32 bit integer and 32 bit fractional part and returns it multiplied by a division argument. e.g. simple_strtofract("1.02", NULL, 1000) == 1020 Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> --- v1 -> v2: - no change --- include/linux/kernel.h | 1 + lib/strtox.c | 57 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index cd7dac73f93a..dd108ba0abf7 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -92,6 +92,7 @@ extern unsigned long simple_strtoul(const char *,char **,unsigned int); extern long simple_strtol(const char *,char **,unsigned int); extern unsigned long long simple_strtoull(const char *,char **,unsigned int); extern long long simple_strtoll(const char *,char **,unsigned int); +extern s64 simple_strtofract(const char *cp, char **endp, u32 division); /* The `const' in roundup() prevents gcc-3.3 from calling __divdi3 */ #define roundup(x, y) ( \ diff --git a/lib/strtox.c b/lib/strtox.c index 76927743a72c..5ef0f0923a9e 100644 --- a/lib/strtox.c +++ b/lib/strtox.c @@ -78,3 +78,60 @@ long long simple_strtoll(const char *cp, char **endp, unsigned int base) return simple_strtoull(cp, endp, base); } EXPORT_SYMBOL(simple_strtoll); + +static unsigned int simple_strtouint(const char *cp, char **endp, unsigned int base) +{ + unsigned int ret; + + ret = simple_strtoull(cp, endp, base); + if (ret != (unsigned int)ret) { + if (endp) + *endp = (char *)cp; + return 0; + } + + return ret; +} + +s64 simple_strtofract(const char *cp, char **endp, u32 division) +{ + char *end = (char *)cp; + s64 integer, fract, scale, result = 0; + int fract_len = 0, sign = 1; + + switch (*cp) { + case '-': + sign = -1; + fallthrough; + case '+': + cp++; + } + + if (!isdigit(*cp)) + goto out; + + integer = simple_strtouint(cp, &end, 10); + if (end == cp) + goto out; + + if (*end == '.' || *end == ',') { + cp = end + 1; + fract = simple_strtouint(cp, &end, 10); + fract_len = end - cp; + } + + result = integer * division; + + scale = 1; + for (int i = 0; i < fract_len; i++) + scale *= 10; + if (fract_len > 0) + result += (fract * division) / scale; + +out: + if (endp) + *endp = end; + + return sign * result; +} +EXPORT_SYMBOL(simple_strtofract); -- 2.39.2