From 9606eabd82e6523ffb8ab8b3eeb405f24e3e2346 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 2 Dec 2024 09:23:45 -0500 Subject: bfstd: Add more strto*() wrappers --- src/bfstd.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++----------- src/bfstd.h | 27 ++++++++++++++----------- 2 files changed, 69 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/bfstd.c b/src/bfstd.c index b58d69e..738c956 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -211,35 +211,77 @@ const char *xgetprogname(void) { return cmd; } -int xstrtoll(const char *str, char **end, int base, long long *value) { - // strtoll() skips leading spaces, but we want to reject them +/** Common prologue for xstrto*() wrappers. */ +static int xstrtox_prologue(const char *str) { + // strto*() skips leading spaces, but we want to reject them if (xisspace(str[0])) { errno = EINVAL; return -1; } - // If end is NULL, make sure the entire string is valid - bool entire = !end; - char *endp; - if (!end) { - end = &endp; - } - errno = 0; - long long result = strtoll(str, end, base); + return 0; +} + +/** Common epilogue for xstrto*() wrappers. */ +static int xstrtox_epilogue(const char *str, char **end, char *endp) { if (errno != 0) { return -1; } - if (*end == str || (entire && **end != '\0')) { + if (end) { + *end = endp; + } + + // If end is NULL, make sure the entire string is valid + if (endp == str || (!end && *endp != '\0')) { errno = EINVAL; return -1; } - *value = result; return 0; } +int xstrtol(const char *str, char **end, int base, long *value) { + if (xstrtox_prologue(str) != 0) { + return -1; + } + + char *endp; + *value = strtol(str, &endp, base); + return xstrtox_epilogue(str, end, endp); +} + +int xstrtoll(const char *str, char **end, int base, long long *value) { + if (xstrtox_prologue(str) != 0) { + return -1; + } + + char *endp; + *value = strtoll(str, &endp, base); + return xstrtox_epilogue(str, end, endp); +} + +int xstrtof(const char *str, char **end, float *value) { + if (xstrtox_prologue(str) != 0) { + return -1; + } + + char *endp; + *value = strtof(str, &endp); + return xstrtox_epilogue(str, end, endp); +} + +int xstrtod(const char *str, char **end, double *value) { + if (xstrtox_prologue(str) != 0) { + return -1; + } + + char *endp; + *value = strtod(str, &endp); + return xstrtox_epilogue(str, end, endp); +} + /** Compile and execute a regular expression for xrpmatch(). */ static int xrpregex(nl_item item, const char *response) { const char *pattern = nl_langinfo(item); diff --git a/src/bfstd.h b/src/bfstd.h index 97867fd..84f92ec 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -178,23 +178,26 @@ int open_cterm(int flags); */ const char *xgetprogname(void); +/** + * Wrapper for strtol() that forbids leading spaces. + */ +int xstrtol(const char *str, char **end, int base, long *value); + /** * Wrapper for strtoll() that forbids leading spaces. - * - * @str - * The string to parse. - * @end - * If non-NULL, will hold a pointer to the first invalid character. - * If NULL, the entire string must be valid. - * @base - * The base for the conversion, or 0 to auto-detect. - * @value - * Will hold the parsed integer value, on success. - * @return - * 0 on success, -1 on failure. */ int xstrtoll(const char *str, char **end, int base, long long *value); +/** + * Wrapper for strtof() that forbids leading spaces. + */ +int xstrtof(const char *str, char **end, float *value); + +/** + * Wrapper for strtod() that forbids leading spaces. + */ +int xstrtod(const char *str, char **end, double *value); + /** * Process a yes/no prompt. * -- cgit v1.2.3