diff --git a/Makefile.am b/Makefile.am index 4f4c3c17..9e397206 100644 --- a/Makefile.am +++ b/Makefile.am @@ -233,13 +233,16 @@ ps_pscommand_SOURCES = \ lib/fileutils.c \ lib/signals.c +TESTS = lib/test_strtod_nol + # lib/test_* binaries noinst_PROGRAMS = \ lib/test_strutils \ lib/test_fileutils \ lib/test_process \ proc/test_sysinfo \ - proc/test_namespace + proc/test_namespace \ + $(TESTS) lib_test_strutils_SOURCES = lib/test_strutils.c lib/strutils.c lib_test_strutils_LDADD = @@ -252,6 +255,9 @@ proc_test_sysinfo_SOURCES = proc/test_sysinfo.c proc_test_sysinfo_LDADD = proc/libprocps.la proc_test_namespace_SOURCES = proc/test_namespace.c proc_test_namespace_LDADD = proc/libprocps.la +lib_test_strtod_nol_SOURCES = lib/test_strtod_nol.c lib/strutils.c +lib_test_strtod_nol_LDADD = + if EXAMPLE_FILES sysconf_DATA = sysctl.conf endif diff --git a/include/strutils.h b/include/strutils.h index 9df33c21..85a61920 100644 --- a/include/strutils.h +++ b/include/strutils.h @@ -7,5 +7,6 @@ extern long strtol_or_err(const char *str, const char *errmesg); extern double strtod_or_err(const char *str, const char *errmesg); +double strtod_nol_or_err(char *str, const char *errmesg); #endif diff --git a/lib/.gitignore b/lib/.gitignore index 7043aff7..e54c8ee2 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -1,5 +1,7 @@ .dirstamp +*.trs test_fileutils test_process test_strutils test_nsutils +test_strtod_nol diff --git a/lib/strutils.c b/lib/strutils.c index 0fd3cf71..e5245db0 100644 --- a/lib/strutils.c +++ b/lib/strutils.c @@ -21,6 +21,7 @@ */ #include +#include #include "c.h" #include "strutils.h" @@ -60,3 +61,63 @@ double strtod_or_err(const char *str, const char *errmesg) error(EXIT_FAILURE, errno, "%s: '%s'", errmesg, str); return 0; } + +/* + * Covert a string into a double in a non-locale aware way. + * This means the decimal point can be either . or , + * Also means you cannot use the other for thousands separator + * + * Exits on failure like its other _or_err cousins + */ +double strtod_nol_or_err(char *str, const char *errmesg) +{ + double num; + const char *cp, *radix; + double mult; + int negative = 0; + + if (str != NULL && *str != '\0') { + num = 0.0; + cp = str; + /* strip leading spaces */ + while (isspace(*cp)) + cp++; + + /* get sign */ + if (*cp == '-') { + negative = 1; + cp++; + } else if (*cp == '+') + cp++; + + /* find radix */ + radix = cp; + mult=0.1; + while(isdigit(*radix)) { + radix++; + mult *= 10; + } + while(isdigit(*cp)) { + num += (*cp - '0') * mult; + mult /= 10; + cp++; + } + /* got the integers */ + if (*cp == '\0') + return (negative?-num:num); + if (*cp != '.' && *cp != ',') + error(EXIT_FAILURE, EINVAL, "%s: '%s'", errmesg, str); + + cp++; + mult = 0.1; + while(isdigit(*cp)) { + num += (*cp - '0') * mult; + mult /= 10; + cp++; + } + if (*cp == '\0') + return (negative?-num:num); + } + error(EXIT_FAILURE, errno, "%s: '%s'", errmesg, str); + return 0; +} diff --git a/lib/test_strtod_nol.c b/lib/test_strtod_nol.c new file mode 100644 index 00000000..0be798c2 --- /dev/null +++ b/lib/test_strtod_nol.c @@ -0,0 +1,45 @@ + +#include +#include +#include "strutils.h" + +struct strtod_tests { + char *string; + double result; +}; + +struct strtod_tests tests[] = { + {"123", 123.0}, + {"-123", -123.0}, + {"12.34", 12.34}, + {"-12.34", -12.34}, + {".34", 0.34}, + {"-.34", -0.34}, + {"12,34", 12.34}, + {"-12,34", -12.34}, + {",34", 0.34}, + {"-,34", -0.34}, + {"0", 0.0}, + {".0", 0.0}, + {"0.0", 0.0}, + {NULL, 0.0} +}; + + + +int main(int argc, char *argv[]) +{ + int i; + double val; + + for(i=0; tests[i].string != NULL; i++) { + if(strtod_nol_or_err(tests[i].string, "Cannot parse number") != + tests[i].result) { + fprintf(stderr, "FAIL: strtod_nol_or_err(\"%s\") != %f\n", + tests[i].string, tests[i].result); + return EXIT_FAILURE; + } + //fprintf(stderr, "PASS: strtod_nol for %s\n", tests[i].string); + } + return EXIT_SUCCESS; +}