From 96f98cea12d6ae80ecb45dba2fb14555c74612fc Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 18 Apr 2025 14:09:35 -0400 Subject: bfstd: Add some more integer parsing functions --- bench/ioq.c | 16 +++++----- src/bfstd.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/bfstd.h | 30 +++++++++++++++++++ tests/bfstd.c | 84 ++++++++++++++++++++++++++++++++++++++------------- tests/main.c | 8 ++--- tests/ptyx.c | 36 ++++++++++------------ tests/xtouch.c | 4 +-- 7 files changed, 218 insertions(+), 54 deletions(-) diff --git a/bench/ioq.c b/bench/ioq.c index 5db585a..61c9714 100644 --- a/bench/ioq.c +++ b/bench/ioq.c @@ -177,9 +177,9 @@ int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); // -d: queue depth - long depth = 4096; + unsigned int depth = 4096; // -j: threads - long threads = 0; + unsigned int threads = 0; // -t: timeout double timeout = 5.0; // -L|-H: ioq_nop() type @@ -190,13 +190,13 @@ int main(int argc, char *argv[]) { while (c = getopt(argc, argv, ":d:j:t:LH"), c != -1) { switch (c) { case 'd': - if (xstrtol(optarg, NULL, 10, &depth) != 0) { + if (xstrtoui(optarg, NULL, 10, &depth) != 0) { fprintf(stderr, "%s: Bad depth '%s': %s\n", cmd, optarg, errstr()); return EXIT_FAILURE; } break; case 'j': - if (xstrtol(optarg, NULL, 10, &threads) != 0) { + if (xstrtoui(optarg, NULL, 10, &threads) != 0) { fprintf(stderr, "%s: Bad thread count '%s': %s\n", cmd, optarg, errstr()); return EXIT_FAILURE; } @@ -222,7 +222,7 @@ int main(int argc, char *argv[]) { } } - if (threads <= 0) { + if (!threads) { threads = nproc(); if (threads > 8) { threads = 8; @@ -238,8 +238,8 @@ int main(int argc, char *argv[]) { printf("I/O queue benchmark (%s)\n\n", bfs_version); - printf("[-d] depth: %ld\n", depth); - printf("[-j] threads: %ld (including main)\n", threads + 1); + printf("[-d] depth: %u\n", depth); + printf("[-j] threads: %u (including main)\n", threads + 1); if (type == IOQ_NOP_HEAVY) { printf("[-H] type: heavy (with syscalls)\n"); } else { @@ -252,7 +252,7 @@ int main(int argc, char *argv[]) { fflush(stdout); struct ioq *ioq = ioq_create(depth, threads); - bfs_everify(ioq, "ioq_create(%ld, %ld)", depth, threads); + bfs_everify(ioq, "ioq_create(%u, %u)", depth, threads); // Pre-allocate all the requests while (ioq_capacity(ioq) > 0) { diff --git a/src/bfstd.c b/src/bfstd.c index 4269d55..b78af7a 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -235,6 +235,36 @@ static int xstrtox_epilogue(const char *str, char **end, char *endp) { return 0; } +int xstrtos(const char *str, char **end, int base, short *value) { + long n; + if (xstrtol(str, end, base, &n) != 0) { + return -1; + } + + if (n < SHRT_MIN || n > SHRT_MAX) { + errno = ERANGE; + return -1; + } + + *value = n; + return 0; +} + +int xstrtoi(const char *str, char **end, int base, int *value) { + long n; + if (xstrtol(str, end, base, &n) != 0) { + return -1; + } + + if (n < INT_MIN || n > INT_MAX) { + errno = ERANGE; + return -1; + } + + *value = n; + return 0; +} + int xstrtol(const char *str, char **end, int base, long *value) { if (xstrtox_prologue(str) != 0) { return -1; @@ -275,6 +305,70 @@ int xstrtod(const char *str, char **end, double *value) { return xstrtox_epilogue(str, end, endp); } +int xstrtous(const char *str, char **end, int base, unsigned short *value) { + unsigned long n; + if (xstrtoul(str, end, base, &n) != 0) { + return -1; + } + + if (n > USHRT_MAX) { + errno = ERANGE; + return -1; + } + + *value = n; + return 0; +} + +int xstrtoui(const char *str, char **end, int base, unsigned int *value) { + unsigned long n; + if (xstrtoul(str, end, base, &n) != 0) { + return -1; + } + + if (n > UINT_MAX) { + errno = ERANGE; + return -1; + } + + *value = n; + return 0; +} + +/** Common epilogue for xstrtou*() wrappers. */ +static int xstrtoux_epilogue(const char *str, char **end, char *endp) { + if (xstrtox_epilogue(str, end, endp) != 0) { + return -1; + } + + if (str[0] == '-') { + errno = ERANGE; + return -1; + } + + return 0; +} + +int xstrtoul(const char *str, char **end, int base, unsigned long *value) { + if (xstrtox_prologue(str) != 0) { + return -1; + } + + char *endp; + *value = strtoul(str, &endp, base); + return xstrtoux_epilogue(str, end, endp); +} + +int xstrtoull(const char *str, char **end, int base, unsigned long long *value) { + if (xstrtox_prologue(str) != 0) { + return -1; + } + + char *endp; + *value = strtoull(str, &endp, base); + return xstrtoux_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 51920c9..15dd949 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -168,6 +168,16 @@ char *xgetdelim(FILE *file, char delim); */ const char *xgetprogname(void); +/** + * Like xstrtol(), but for short. + */ +int xstrtos(const char *str, char **end, int base, short *value); + +/** + * Like xstrtol(), but for int. + */ +int xstrtoi(const char *str, char **end, int base, int *value); + /** * Wrapper for strtol() that forbids leading spaces. */ @@ -178,6 +188,26 @@ int xstrtol(const char *str, char **end, int base, long *value); */ int xstrtoll(const char *str, char **end, int base, long long *value); +/** + * Like xstrtoul(), but for unsigned short. + */ +int xstrtous(const char *str, char **end, int base, unsigned short *value); + +/** + * Like xstrtoul(), but for unsigned int. + */ +int xstrtoui(const char *str, char **end, int base, unsigned int *value); + +/** + * Wrapper for strtoul() that forbids leading spaces, negatives. + */ +int xstrtoul(const char *str, char **end, int base, unsigned long *value); + +/** + * Wrapper for strtoull() that forbids leading spaces, negatives. + */ +int xstrtoull(const char *str, char **end, int base, unsigned long long *value); + /** * Wrapper for strtof() that forbids leading spaces. */ diff --git a/tests/bfstd.c b/tests/bfstd.c index 685aa6c..6e15e2b 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -4,7 +4,6 @@ #include "tests.h" #include "bfstd.h" -#include "bit.h" #include "diag.h" #include @@ -95,37 +94,74 @@ static void check_wordescs(void) { /** xstrto*() test cases. */ static void check_strtox(void) { + short s; + unsigned short us; + int i; + unsigned int ui; long l; + unsigned long ul; long long ll; + unsigned long long ull; char *end; +#define check_strtouerr(err, str, end, base) \ + do { \ + bfs_echeck(xstrtous(str, end, base, &us) != 0 && errno == err); \ + bfs_echeck(xstrtoui(str, end, base, &ui) != 0 && errno == err); \ + bfs_echeck(xstrtoul(str, end, base, &ul) != 0 && errno == err); \ + bfs_echeck(xstrtoull(str, end, base, &ull) != 0 && errno == err); \ + } while (0) + + check_strtouerr(ERANGE, "-1", NULL, 0); + check_strtouerr(ERANGE, "-0x1", NULL, 0); + + check_strtouerr(EINVAL, "-", NULL, 0); + check_strtouerr(EINVAL, "-q", NULL, 0); + check_strtouerr(EINVAL, "-1q", NULL, 0); + check_strtouerr(EINVAL, "-0x", NULL, 0); + #define check_strtoerr(err, str, end, base) \ - bfs_echeck(xstrtol(str, end, base, &l) != 0 && errno == err); \ - bfs_echeck(xstrtoll(str, end, base, &ll) != 0 && errno == err) + do { \ + bfs_echeck(xstrtos(str, end, base, &s) != 0 && errno == err); \ + bfs_echeck(xstrtoi(str, end, base, &i) != 0 && errno == err); \ + bfs_echeck(xstrtol(str, end, base, &l) != 0 && errno == err); \ + bfs_echeck(xstrtoll(str, end, base, &ll) != 0 && errno == err); \ + check_strtouerr(err, str, end, base); \ + } while (0) check_strtoerr(EINVAL, "", NULL, 0); check_strtoerr(EINVAL, "", &end, 0); check_strtoerr(EINVAL, " 1 ", &end, 0); + check_strtoerr(EINVAL, " -1", NULL, 0); check_strtoerr(EINVAL, " 123", NULL, 0); check_strtoerr(EINVAL, "123 ", NULL, 0); check_strtoerr(EINVAL, "0789", NULL, 0); check_strtoerr(EINVAL, "789A", NULL, 0); check_strtoerr(EINVAL, "0x", NULL, 0); check_strtoerr(EINVAL, "0x789A", NULL, 10); - - if (LLONG_WIDTH == 64) { - check_strtoerr(ERANGE, "9223372036854775808", NULL, 0); - } + check_strtoerr(EINVAL, "0x-1", NULL, 0); + +#define check_strtotype(type, min, max, fmt, fn, str, base, v, n) \ + do { \ + if ((n) >= min && (n) <= max) { \ + bfs_echeck(fn(str, NULL, base, &v) == 0); \ + bfs_check(v == (type)(n), "%s('%s') == " fmt " (!= " fmt ")", #fn, str, v, (type)(n)); \ + } else { \ + bfs_echeck(fn(str, NULL, base, &v) != 0 && errno == ERANGE); \ + } \ + } while (0) #define check_strtoint(str, base, n) \ - if ((n) >= LONG_MIN && (n) <= LONG_MAX) { \ - bfs_echeck(xstrtol(str, NULL, base, &l) == 0); \ - bfs_check(l == (n), "xstrtol('%s') == %ld (!= %ld)", str, l, (long)(n)); \ - } else { \ - bfs_echeck(xstrtol(str, NULL, base, &l) != 0 && errno == ERANGE); \ - } \ - bfs_echeck(xstrtoll(str, NULL, base, &ll) == 0); \ - bfs_check(ll == (n), "xstrtoll('%s') == %lld (!= %lld)", str, ll, (long long)(n)) \ + do { \ + check_strtotype( signed short, SHRT_MIN, SHRT_MAX, "%d", xstrtos, str, base, s, n); \ + check_strtotype( signed int, INT_MIN, INT_MAX, "%d", xstrtoi, str, base, i, n); \ + check_strtotype( signed long, LONG_MIN, LONG_MAX, "%ld", xstrtol, str, base, l, n); \ + check_strtotype( signed long long, LLONG_MIN, LLONG_MAX, "%lld", xstrtoll, str, base, ll, n); \ + check_strtotype(unsigned short, 0, USHRT_MAX, "%u", xstrtous, str, base, us, n); \ + check_strtotype(unsigned int, 0, UINT_MAX, "%u", xstrtoui, str, base, ui, n); \ + check_strtotype(unsigned long, 0, ULONG_MAX, "%lu", xstrtoul, str, base, ul, n); \ + check_strtotype(unsigned long long, 0, ULLONG_MAX, "%llu", xstrtoull, str, base, ull, n); \ + } while (0) check_strtoint("123", 0, 123); check_strtoint("+123", 0, 123); @@ -139,13 +175,21 @@ static void check_strtox(void) { check_strtoint("123", 16, 0x123); - check_strtoint("9223372036854775807", 0, 9223372036854775807LL); - check_strtoint("-9223372036854775808", 0, -9223372036854775807LL - 1); + check_strtoint("0x7FFF", 0, 0x7FFF); + check_strtoint("-0x8000", 0, -0x8000); + + check_strtoint("0x7FFFFFFF", 0, 0x7FFFFFFFL); + check_strtoint("-0x80000000", 0, -0x7FFFFFFFL - 1); + + check_strtoint("0x7FFFFFFFFFFFFFFF", 0, 0x7FFFFFFFFFFFFFFFLL); + check_strtoint("-0x8000000000000000", 0, -0x7FFFFFFFFFFFFFFFLL - 1); #define check_strtoend(str, estr, base, n) \ - bfs_echeck(xstrtoll(str, &end, base, &ll) == 0); \ - bfs_check(ll == (n), "xstrtoll('%s') == %lld (!= %lld)", str, ll, (long long)(n)); \ - bfs_check(strcmp(end, estr) == 0, "xstrtoll('%s'): end == '%s' (!= '%s')", str, end, estr) \ + do { \ + bfs_echeck(xstrtoll(str, &end, base, &ll) == 0); \ + bfs_check(ll == (n), "xstrtoll('%s') == %lld (!= %lld)", str, ll, (long long)(n)); \ + bfs_check(strcmp(end, estr) == 0, "xstrtoll('%s'): end == '%s' (!= '%s')", str, end, estr); \ + } while (0) check_strtoend("123 ", " ", 0, 123); check_strtoend("0789", "89", 0, 07); diff --git a/tests/main.c b/tests/main.c index 4c770bd..9240e1c 100644 --- a/tests/main.c +++ b/tests/main.c @@ -222,15 +222,15 @@ int main(int argc, char *argv[]) { } tzset(); - long jobs = 0; + unsigned int jobs = 0; const char *cmd = argc > 0 ? argv[0] : "units"; int c; while (c = getopt(argc, argv, ":j:"), c != -1) { switch (c) { case 'j': - if (xstrtol(optarg, NULL, 10, &jobs) != 0 || jobs <= 0) { - fprintf(stderr, "%s: Bad job count '%s'\n", cmd, optarg); + if (xstrtoui(optarg, NULL, 10, &jobs) != 0) { + fprintf(stderr, "%s: Bad job count '%s': %s\n", cmd, optarg, errstr()); return EXIT_FAILURE; } break; @@ -243,7 +243,7 @@ int main(int argc, char *argv[]) { } } - if (jobs == 0) { + if (!jobs) { jobs = nproc(); } diff --git a/tests/ptyx.c b/tests/ptyx.c index 4d89581..59292df 100644 --- a/tests/ptyx.c +++ b/tests/ptyx.c @@ -65,25 +65,21 @@ int main(int argc, char *argv[]) { exit(EXIT_FAILURE); \ } while (0) - long width = -1; - long height = -1; + unsigned short width = 0; + unsigned short height = 0; // Parse the command line int c; while (c = getopt(argc, argv, "+:w:h:"), c != -1) { switch (c) { case 'w': - if (xstrtol(optarg, NULL, 10, &width) != 0) { + if (xstrtous(optarg, NULL, 10, &width) != 0) { edie("Bad width '%s'", optarg); - } else if (width < 0 || width > (long)USHRT_MAX) { - die("Bad width '%s'", optarg); } break; case 'h': - if (xstrtol(optarg, NULL, 10, &height) != 0) { + if (xstrtous(optarg, NULL, 10, &height) != 0) { edie("Bad height '%s'", optarg); - } else if (height < 0 || height > (long)USHRT_MAX) { - die("Bad height '%s'", optarg); } break; case ':': @@ -135,36 +131,36 @@ int main(int argc, char *argv[]) { // A new pty starts at 0x0, which is not very useful. Instead, grab the // default size from the current controlling terminal, if possible. - if (width < 0 || height < 0) { + if (!width || !height) { int tty = open_cterm(O_RDONLY | O_CLOEXEC); if (tty >= 0) { struct winsize ws; if (xtcgetwinsize(tty, &ws) != 0) { edie("tcgetwinsize()"); } - if (width < 0) { + if (!width) { width = ws.ws_col; } - if (height < 0) { + if (!height) { height = ws.ws_row; } xclose(tty); } } + if (!width) { + width = 80; + } + if (!height) { + height = 24; + } - // Get the current pty size + // Update the pty size struct winsize ws; if (xtcgetwinsize(pts, &ws) != 0) { edie("tcgetwinsize()"); } - - // Apply our options - if (width >= 0) { - ws.ws_col = width; - } - if (height >= 0) { - ws.ws_row = height; - } + ws.ws_col = width; + ws.ws_row = height; if (xtcsetwinsize(pts, &ws) != 0) { edie("tcsetwinsize()"); } diff --git a/tests/xtouch.c b/tests/xtouch.c index 5d65a4c..f33c573 100644 --- a/tests/xtouch.c +++ b/tests/xtouch.c @@ -217,8 +217,8 @@ int main(int argc, char *argv[]) { } if (marg) { - long mode; - if (xstrtol(marg, NULL, 8, &mode) == 0 && mode >= 0 && mode < 01000) { + unsigned int mode; + if (xstrtoui(marg, NULL, 8, &mode) == 0 && mode < 01000) { args.fmode = args.dmode = mode; } else { fprintf(stderr, "%s: Invalid mode '%s'\n", cmd, marg); -- cgit v1.2.3