summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2024-06-04 12:51:12 -0400
committerTavian Barnes <tavianator@tavianator.com>2024-06-04 12:51:12 -0400
commit3da7fe8b4f5d6a41152d81bbfbd30b0ab3a9da1c (patch)
treee675798b2918c477cbbf69707a1d2f32120cd3df
parent32d252598e855829ebdc657e635f93270600b5a2 (diff)
downloadbfs-3da7fe8b4f5d6a41152d81bbfbd30b0ab3a9da1c.tar.xz
bfstd: New xstrtoll() wrapper
-rw-r--r--src/bfstd.c29
-rw-r--r--src/bfstd.h17
-rw-r--r--src/parse.c17
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;
}