diff --git a/qdevices/test-utils.c b/qdevices/test-utils.c index dcdd9f5..d94a086 100644 --- a/qdevices/test-utils.c +++ b/qdevices/test-utils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 Red Hat, Inc. + * Copyright (c) 2015-2020 Red Hat, Inc. * * All rights reserved. * @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "utils.h" @@ -44,6 +45,8 @@ main(void) { long long int ll; long long int lli; + double dbl; + double dbli; char buf[32]; assert(utils_strtonum("0", 0, 100, &ll) == 0); @@ -92,5 +95,47 @@ main(void) assert(utils_parse_bool_str("noo") == -1); assert(utils_parse_bool_str("01") == -1); + assert(utils_strtod("0", 0, 100, &dbl) == 0); + assert(dbl == 0); + + assert(utils_strtod("0.0", 0, 100, &dbl) == 0); + assert(dbl == 0); + + assert(utils_strtod("100", 0, 100, &dbl) == 0); + assert(dbl == 100); + + assert(utils_strtod("100.0", 0, 100, &dbl) == 0); + assert(dbl == 100); + + assert(utils_strtod("99.9", 0, 100, &dbl) == 0); + assert(dbl == 99.9); + + assert(utils_strtod("101", 0, 100, &dbl) != 0); + assert(utils_strtod("0", 1, 100, &dbl) != 0); + + errno = ERANGE; + assert(utils_strtod("10", 0, 100, &dbl) == 0); + assert(dbl == 10); + + assert(utils_strtod("-1", -1, 0, &dbl) == 0); + assert(dbl == -1); + + assert(utils_strtod("-10", -20, -10, &dbl) == 0); + assert(dbl == -10); + + assert(utils_strtod("0", 1, 0, &dbl) == -1); + + for (dbli = -100; dbli <= 100; dbli += 0.01) { + assert(snprintf(buf, sizeof(buf), "%f", dbli) > 0); + + assert(utils_strtod(buf, -100, 101, &dbl) == 0); + assert(fabs(dbl - dbli) < 0.0001); + } + + assert(utils_strtod("test", -1000, 1000, &dbl) == -1); + assert(utils_strtod("12a", -1000, 1000, &dbl) == -1); + assert(utils_strtod("inf", -1000, 1000, &dbl) == -1); + assert(utils_strtod("nan", -1000, 1000, &dbl) == -1); + return (0); } diff --git a/qdevices/utils.c b/qdevices/utils.c index bda3b6a..d151934 100644 --- a/qdevices/utils.c +++ b/qdevices/utils.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -236,3 +237,33 @@ utils_strtonum(const char *str, long long int min_val, long long int max_val, return (0); } + +/* + * Safer wrapper of strtod. Return 0 on success, otherwise -1. + */ +int +utils_strtod(const char *str, double min_val, double max_val, + double *res) +{ + double tmp_d; + char *ep; + + if (min_val > max_val) { + return (-1); + } + + errno = 0; + + tmp_d = strtod(str, &ep); + if (ep == str || *ep != '\0' || errno != 0) { + return (-1); + } + + if (tmp_d < min_val || tmp_d > max_val || isnan(tmp_d)) { + return (-1); + } + + *res = tmp_d; + + return (0); +} diff --git a/qdevices/utils.h b/qdevices/utils.h index 0d96df4..cb7abc2 100644 --- a/qdevices/utils.h +++ b/qdevices/utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018 Red Hat, Inc. + * Copyright (c) 2015-2020 Red Hat, Inc. * * All rights reserved. * @@ -65,6 +65,9 @@ extern int utils_fd_set_non_blocking(int fd); extern int utils_strtonum(const char *str, long long int min_val, long long int max_val, long long int *res); +extern int utils_strtod(const char *str, double min_val, double max_val, + double *res); + #ifdef __cplusplus } #endif