diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2024-06-04 12:51:12 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2024-06-04 12:51:12 -0400 |
commit | 3da7fe8b4f5d6a41152d81bbfbd30b0ab3a9da1c (patch) | |
tree | e675798b2918c477cbbf69707a1d2f32120cd3df | |
parent | 32d252598e855829ebdc657e635f93270600b5a2 (diff) | |
download | bfs-3da7fe8b4f5d6a41152d81bbfbd30b0ab3a9da1c.tar.xz |
bfstd: New xstrtoll() wrapper
-rw-r--r-- | src/bfstd.c | 29 | ||||
-rw-r--r-- | src/bfstd.h | 17 | ||||
-rw-r--r-- | src/parse.c | 17 |
3 files changed, 48 insertions, 15 deletions
diff --git a/src/bfstd.c b/src/bfstd.c index 44eda7c..6d244ca 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -209,6 +209,35 @@ 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 + 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); + if (errno != 0) { + return -1; + } + + if (*end == str || (entire && **end != '\0')) { + errno = EINVAL; + return -1; + } + + *value = result; + return 0; +} + /** 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 f5d8622..45db81a 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -179,6 +179,23 @@ int open_cterm(int flags); const char *xgetprogname(void); /** + * Wrapper for strtoll() that forbids leading spaces. + * + * @param str + * The string to parse. + * @param end + * If non-NULL, will hold a pointer to the first invalid character. + * If NULL, the entire string must be valid. + * @param base + * The base for the conversion, or 0 to auto-detect. + * @param 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); + +/** * Process a yes/no prompt. * * @return 1 for yes, 0 for no, and -1 for unknown. diff --git a/src/parse.c b/src/parse.c index 3c17bc6..e1a46db 100644 --- a/src/parse.c +++ b/src/parse.c @@ -526,20 +526,14 @@ enum int_flags { * Parse an integer. */ static const char *parse_int(const struct bfs_parser *parser, char **arg, const char *str, void *result, enum int_flags flags) { - // strtoll() skips leading spaces, but we want to reject them - if (xisspace(str[0])) { - goto bad; - } - int base = flags & IF_BASE_MASK; if (base == 0) { base = 10; } char *endptr; - errno = 0; - long long value = strtoll(str, &endptr, base); - if (errno != 0) { + long long value; + if (xstrtoll(str, &endptr, base, &value) != 0) { if (errno == ERANGE) { goto range; } else { @@ -547,13 +541,6 @@ static const char *parse_int(const struct bfs_parser *parser, char **arg, const } } - // https://github.com/llvm/llvm-project/issues/64946 - sanitize_init(&endptr); - - if (endptr == str) { - goto bad; - } - if (!(flags & IF_PARTIAL_OK) && *endptr != '\0') { goto bad; } |