summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlejandro Colomar <alx@kernel.org>2024-01-12 17:28:44 +0100
committerAlejandro Colomar <alx@kernel.org>2024-01-13 19:42:36 +0100
commitf055932d64fa3bfa97a9fa5e53d2eafe906ced4e (patch)
tree1b0dceb3b8306aa04f4175a70c969dda151fce4c
parentee23a0d38b650977b72095502ea8d1346841f30b (diff)
downloadliba2i-f055932d64fa3bfa97a9fa5e53d2eafe906ced4e.tar.gz
share/tests/: Add tests
Signed-off-by: Alejandro Colomar <alx@kernel.org>
-rw-r--r--share/tests/a2i.h/a2i/a2i.c457
-rwxr-xr-xshare/tests/a2i.h/a2i/a2i.sh14
-rwxr-xr-xshare/tests/a2i.h/a2i/a2i_nobuild.sh72
-rw-r--r--share/tests/a2i.h/a2s/a2s.c457
-rwxr-xr-xshare/tests/a2i.h/a2s/a2s.sh14
-rwxr-xr-xshare/tests/a2i.h/a2s/a2s_nobuild.sh72
-rw-r--r--share/tests/a2i.h/a2sh/a2sh.c457
-rwxr-xr-xshare/tests/a2i.h/a2sh/a2sh.sh14
-rwxr-xr-xshare/tests/a2i.h/a2sh/a2sh_nobuild.sh53
-rw-r--r--share/tests/a2i.h/a2shh/a2shh.c457
-rwxr-xr-xshare/tests/a2i.h/a2shh/a2shh.sh14
-rwxr-xr-xshare/tests/a2i.h/a2shh/a2shh_nobuild.sh72
-rw-r--r--share/tests/a2i.h/a2si/a2si.c457
-rwxr-xr-xshare/tests/a2i.h/a2si/a2si.sh14
-rwxr-xr-xshare/tests/a2i.h/a2si/a2si_nobuild.sh53
-rw-r--r--share/tests/a2i.h/a2sl/a2sl.c457
-rwxr-xr-xshare/tests/a2i.h/a2sl/a2sl.sh14
-rwxr-xr-xshare/tests/a2i.h/a2sl/a2sl_nobuild.sh53
-rw-r--r--share/tests/a2i.h/a2sll/a2sll.c457
-rwxr-xr-xshare/tests/a2i.h/a2sll/a2sll.sh14
-rwxr-xr-xshare/tests/a2i.h/a2sll/a2sll_nobuild.sh53
-rw-r--r--share/tests/a2i.h/a2u/a2u.c468
-rwxr-xr-xshare/tests/a2i.h/a2u/a2u.sh14
-rwxr-xr-xshare/tests/a2i.h/a2u/a2u_nobuild.sh72
-rw-r--r--share/tests/a2i.h/a2uh/a2uh.c468
-rwxr-xr-xshare/tests/a2i.h/a2uh/a2uh.sh14
-rwxr-xr-xshare/tests/a2i.h/a2uh/a2uh_nobuild.sh53
-rw-r--r--share/tests/a2i.h/a2uhh/a2uhh.c468
-rwxr-xr-xshare/tests/a2i.h/a2uhh/a2uhh.sh14
-rwxr-xr-xshare/tests/a2i.h/a2uhh/a2uhh_nobuild.sh72
-rw-r--r--share/tests/a2i.h/a2ui/a2ui.c468
-rwxr-xr-xshare/tests/a2i.h/a2ui/a2ui.sh14
-rwxr-xr-xshare/tests/a2i.h/a2ui/a2ui_nobuild.sh53
-rw-r--r--share/tests/a2i.h/a2ul/a2ul.c468
-rwxr-xr-xshare/tests/a2i.h/a2ul/a2ul.sh14
-rwxr-xr-xshare/tests/a2i.h/a2ul/a2ul_nobuild.sh53
-rw-r--r--share/tests/a2i.h/a2ull/a2ull.c468
-rwxr-xr-xshare/tests/a2i.h/a2ull/a2ull.sh14
-rwxr-xr-xshare/tests/a2i.h/a2ull/a2ull_nobuild.sh53
-rw-r--r--share/tests/str2i.h/str2i/str2i.c152
-rwxr-xr-xshare/tests/str2i.h/str2i/str2i.sh14
-rwxr-xr-xshare/tests/str2i.h/str2i/str2i_nobuild.sh72
-rw-r--r--share/tests/str2i.h/str2s/str2s.c146
-rwxr-xr-xshare/tests/str2i.h/str2s/str2s.sh14
-rwxr-xr-xshare/tests/str2i.h/str2s/str2s_nobuild.sh72
-rw-r--r--share/tests/str2i.h/str2sh/str2sh.c146
-rwxr-xr-xshare/tests/str2i.h/str2sh/str2sh.sh14
-rwxr-xr-xshare/tests/str2i.h/str2sh/str2sh_nobuild.sh53
-rw-r--r--share/tests/str2i.h/str2shh/str2shh.c146
-rwxr-xr-xshare/tests/str2i.h/str2shh/str2shh.sh14
-rwxr-xr-xshare/tests/str2i.h/str2shh/str2shh_nobuild.sh72
-rw-r--r--share/tests/str2i.h/str2si/str2si.c146
-rwxr-xr-xshare/tests/str2i.h/str2si/str2si.sh14
-rwxr-xr-xshare/tests/str2i.h/str2si/str2si_nobuild.sh53
-rw-r--r--share/tests/str2i.h/str2sl/str2sl.c146
-rwxr-xr-xshare/tests/str2i.h/str2sl/str2sl.sh14
-rwxr-xr-xshare/tests/str2i.h/str2sl/str2sl_nobuild.sh53
-rw-r--r--share/tests/str2i.h/str2sll/str2sll.c146
-rwxr-xr-xshare/tests/str2i.h/str2sll/str2sll.sh14
-rwxr-xr-xshare/tests/str2i.h/str2sll/str2sll_nobuild.sh53
-rw-r--r--share/tests/str2i.h/str2u/str2u.c152
-rwxr-xr-xshare/tests/str2i.h/str2u/str2u.sh14
-rwxr-xr-xshare/tests/str2i.h/str2u/str2u_nobuild.sh72
-rw-r--r--share/tests/str2i.h/str2uh/str2uh.c152
-rwxr-xr-xshare/tests/str2i.h/str2uh/str2uh.sh14
-rwxr-xr-xshare/tests/str2i.h/str2uh/str2uh_nobuild.sh53
-rw-r--r--share/tests/str2i.h/str2uhh/str2uhh.c152
-rwxr-xr-xshare/tests/str2i.h/str2uhh/str2uhh.sh14
-rwxr-xr-xshare/tests/str2i.h/str2uhh/str2uhh_nobuild.sh72
-rw-r--r--share/tests/str2i.h/str2ui/str2ui.c152
-rwxr-xr-xshare/tests/str2i.h/str2ui/str2ui.sh14
-rwxr-xr-xshare/tests/str2i.h/str2ui/str2ui_nobuild.sh53
-rw-r--r--share/tests/str2i.h/str2ul/str2ul.c152
-rwxr-xr-xshare/tests/str2i.h/str2ul/str2ul.sh14
-rwxr-xr-xshare/tests/str2i.h/str2ul/str2ul_nobuild.sh53
-rw-r--r--share/tests/str2i.h/str2ull/str2ull.c152
-rwxr-xr-xshare/tests/str2i.h/str2ull/str2ull.sh14
-rwxr-xr-xshare/tests/str2i.h/str2ull/str2ull_nobuild.sh53
-rw-r--r--share/tests/strtoi.h/strtoi/strtoi.c387
-rwxr-xr-xshare/tests/strtoi.h/strtoi/strtoi.sh14
-rw-r--r--share/tests/strtoi.h/strtou/strtou.c393
-rwxr-xr-xshare/tests/strtoi.h/strtou/strtou.sh14
-rw-r--r--share/tests/strtoi.h/strtou_noneg/strtou_noneg.c393
-rwxr-xr-xshare/tests/strtoi.h/strtou_noneg/strtou_noneg.sh14
84 files changed, 11094 insertions, 0 deletions
diff --git a/share/tests/a2i.h/a2i/a2i.c b/share/tests/a2i.h/a2i/a2i.c
new file mode 100644
index 0000000..c65c081
--- /dev/null
+++ b/share/tests/a2i.h/a2i/a2i.c
@@ -0,0 +1,457 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/a2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ char *e = "unmodified";
+ unsigned int n;
+
+ assert(a2i(unsigned int, &n, "x99z", NULL, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2i(unsigned int, &n, "x99z", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2i(unsigned int, &n, "x99z", NULL, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(a2i(unsigned int, &n, "x99z", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2i(unsigned int, &n, "99z", NULL, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(a2i(unsigned int, &n, "99z", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2i(unsigned int, &n, "9z", NULL, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(a2i(unsigned int, &n, "9z", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ errno = 0;
+
+ assert(a2i(unsigned int, &n, "9", NULL, 0, 7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(a2i(unsigned int, &n, "9", &e, 0, 7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_base(void)
+{
+ char *e = "unmodified";
+ long n;
+
+ assert(a2i(long, &n, "1", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2i(long, &n, "1", &e, -1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2i(long, &n, "1", &e, -2, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2i(long, &n, "1", &e, 37, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2i(long, &n, "1", &e, 38, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2i(long, &n, "1", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(a2i(long, &n, "", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2i(long, &n, "foo", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2i(long, &n, "43", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2i(long, &n, "1", &e, 1, -42, -7) == -1);
+ assert(n == -7);
+ assert(errno == EINVAL);
+ assert(a2i(long, &n, "1", &e, 1, 42, -42) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2i(long, &n, "4foo", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ errno = 0;
+
+ assert(a2i(long, &n, "1", &e, 0, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "1", &e, 2, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "1", &e, 3, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "1", &e, 35, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "1", &e, 36, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2i(long, &n, "0b11", &e, 0, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i(long, &n, "0B11", &e, 0, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i(long, &n, "-0b11", &e, 0, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i(long, &n, "-0B11", &e, 0, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "011", &e, 0, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-011", &e, 0, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "11", &e, 0, -42, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-11", &e, 0, -42, 42) == 0);
+ assert(n == -11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "0x11", &e, 0, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "0X11", &e, 0, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-0x11", &e, 0, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-0X11", &e, 0, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i(long, &n, "011", &e, 2, -42, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "11", &e, 2, -42, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2i(long, &n, "0b11", NULL, 2, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i(long, &n, "0B11", NULL, 2, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-011", &e, 2, -42, 42) == 0);
+ assert(n == -3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-11", &e, 2, -42, 42) == 0);
+ assert(n == -3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2i(long, &n, "-0b11", NULL, 2, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i(long, &n, "-0B11", NULL, 2, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "011", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "0x11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "0X11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-011", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-0x11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-0X11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i(long, &n, "011", &e, 7, -42, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "11", &e, 7, -42, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-011", &e, 7, -42, 42) == 0);
+ assert(n == -8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-11", &e, 7, -42, 42) == 0);
+ assert(n == -8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "011", &e, 8, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "11", &e, 8, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-011", &e, 8, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-11", &e, 8, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "z", &e, 36, -42, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "Z", &e, 36, -42, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-z", &e, 36, -42, 42) == 0);
+ assert(n == -35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(long, &n, "-Z", &e, 36, -42, 42) == 0);
+ assert(n == -35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ char *e;
+ unsigned long long n;
+
+ assert(a2i(unsigned long long, &n, "", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(unsigned long long, &n, "foo", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2i(unsigned long long, &n, "foo 7", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2i(unsigned long long, &n, "", &e, 0, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+
+ assert(a2i(unsigned long long, &n, " 9", &e, 0, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(unsigned long long, &n, " \t\na", &e, 16, 2, 42) == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(unsigned long long, &n, " \t\n-a", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_range(void)
+{
+ char *e;
+ signed char n;
+
+ assert(a2i(signed char, &n, "-9", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(signed char, &n, "-8", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(signed char, &n, "43", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(signed char, &n, "44", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i(signed char, &n, "7", &e, 0, 7, -42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(signed char, &n, "42", &e, 0, 7, -42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i(signed char, &n, "-9z", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2i(signed char, &n, "-9 ", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ errno = 0;
+
+ assert(a2i(signed char, &n, "-7", &e, 0, -7, 42) == 0);
+ assert(n == -7);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(signed char, &n, "-6", &e, 0, -7, 42) == 0);
+ assert(n == -6);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(signed char, &n, "41", &e, 0, -7, 42) == 0);
+ assert(n == 41);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(signed char, &n, "42", &e, 0, -7, 42) == 0);
+ assert(n == 42);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i(signed char, &n, "-1", &e, 0, SCHAR_MIN, SCHAR_MAX) == 0);
+ assert(n == -1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(signed char, &n, "0x7F", &e, 0, SCHAR_MIN, SCHAR_MAX) == 0);
+ assert(n == 0x7F);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(signed char, &n, "0xFF", &e, 0, SCHAR_MIN, SCHAR_MAX) == -1);
+ assert(n == SCHAR_MAX);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i(signed char, &n, "-0xFF", &e, 0, SCHAR_MIN, SCHAR_MAX) == -1);
+ assert(n == SCHAR_MIN);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ char *e;
+ unsigned short n;
+
+ assert(a2i(unsigned short, &n, "\n9 fff 7", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2i(unsigned short, &n, "\n9\t", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2i(unsigned short, &n, "9 ", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+}
diff --git a/share/tests/a2i.h/a2i/a2i.sh b/share/tests/a2i.h/a2i/a2i.sh
new file mode 100755
index 0000000..5d15c49
--- /dev/null
+++ b/share/tests/a2i.h/a2i/a2i.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/a2i.c $LIBS;
+"$out";
diff --git a/share/tests/a2i.h/a2i/a2i_nobuild.sh b/share/tests/a2i.h/a2i/a2i_nobuild.sh
new file mode 100755
index 0000000..a91c0fa
--- /dev/null
+++ b/share/tests/a2i.h/a2i/a2i_nobuild.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected error: [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned char n;
+
+ a2i(signed char, &n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected error: [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ a2i(unsigned int, &n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- 'error: ._Generic. selector' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected error: '_Generic' selector"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ float n;
+
+ a2i(float, &n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
diff --git a/share/tests/a2i.h/a2s/a2s.c b/share/tests/a2i.h/a2s/a2s.c
new file mode 100644
index 0000000..c07b01e
--- /dev/null
+++ b/share/tests/a2i.h/a2s/a2s.c
@@ -0,0 +1,457 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/a2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ char *e = "unmodified";
+ int n;
+
+ assert(a2s(int, &n, "x99z", NULL, 1, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2s(int, &n, "x99z", &e, 1, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2s(int, &n, "x99z", NULL, 0, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(a2s(int, &n, "x99z", &e, 0, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2s(int, &n, "99z", NULL, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(a2s(int, &n, "99z", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2s(int, &n, "9z", NULL, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(a2s(int, &n, "9z", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ errno = 0;
+
+ assert(a2s(int, &n, "9", NULL, 0, -7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(a2s(int, &n, "9", &e, 0, -7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_base(void)
+{
+ char *e = "unmodified";
+ long n;
+
+ assert(a2s(long, &n, "1", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2s(long, &n, "1", &e, -1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2s(long, &n, "1", &e, -2, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2s(long, &n, "1", &e, 37, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2s(long, &n, "1", &e, 38, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2s(long, &n, "1", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(a2s(long, &n, "", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2s(long, &n, "foo", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2s(long, &n, "43", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2s(long, &n, "1", &e, 1, -42, -7) == -1);
+ assert(n == -7);
+ assert(errno == EINVAL);
+ assert(a2s(long, &n, "1", &e, 1, 42, -42) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2s(long, &n, "4foo", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ errno = 0;
+
+ assert(a2s(long, &n, "1", &e, 0, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "1", &e, 2, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "1", &e, 3, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "1", &e, 35, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "1", &e, 36, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2s(long, &n, "0b11", &e, 0, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2s(long, &n, "0B11", &e, 0, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2s(long, &n, "-0b11", &e, 0, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2s(long, &n, "-0B11", &e, 0, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "011", &e, 0, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-011", &e, 0, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "11", &e, 0, -42, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-11", &e, 0, -42, 42) == 0);
+ assert(n == -11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "0x11", &e, 0, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "0X11", &e, 0, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-0x11", &e, 0, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-0X11", &e, 0, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2s(long, &n, "011", &e, 2, -42, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "11", &e, 2, -42, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2s(long, &n, "0b11", NULL, 2, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2s(long, &n, "0B11", NULL, 2, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-011", &e, 2, -42, 42) == 0);
+ assert(n == -3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-11", &e, 2, -42, 42) == 0);
+ assert(n == -3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2s(long, &n, "-0b11", NULL, 2, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2s(long, &n, "-0B11", NULL, 2, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "011", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "0x11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "0X11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-011", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-0x11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-0X11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2s(long, &n, "011", &e, 7, -42, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "11", &e, 7, -42, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-011", &e, 7, -42, 42) == 0);
+ assert(n == -8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-11", &e, 7, -42, 42) == 0);
+ assert(n == -8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "011", &e, 8, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "11", &e, 8, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-011", &e, 8, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-11", &e, 8, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "z", &e, 36, -42, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "Z", &e, 36, -42, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-z", &e, 36, -42, 42) == 0);
+ assert(n == -35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long, &n, "-Z", &e, 36, -42, 42) == 0);
+ assert(n == -35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ char *e;
+ long long n;
+
+ assert(a2s(long long, &n, "", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long long, &n, "foo", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2s(long long, &n, "foo 7", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2s(long long, &n, "", &e, 0, 42, -42) == -1);
+ assert(n == 42);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+
+ assert(a2s(long long, &n, " 1", &e, 0, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long long, &n, " \t\na", &e, 16, -42, 42) == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(long long, &n, " \t\n-a", &e, 16, -42, 42) == 0);
+ assert(n == -10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_range(void)
+{
+ char *e;
+ signed char n;
+
+ assert(a2s(signed char, &n, "-9", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(signed char, &n, "-8", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(signed char, &n, "43", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(signed char, &n, "44", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2s(signed char, &n, "7", &e, 0, 7, -42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(signed char, &n, "42", &e, 0, 7, -42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2s(signed char, &n, "-9z", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2s(signed char, &n, "-9 ", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ errno = 0;
+
+ assert(a2s(signed char, &n, "-7", &e, 0, -7, 42) == 0);
+ assert(n == -7);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(signed char, &n, "-6", &e, 0, -7, 42) == 0);
+ assert(n == -6);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(signed char, &n, "41", &e, 0, -7, 42) == 0);
+ assert(n == 41);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(signed char, &n, "42", &e, 0, -7, 42) == 0);
+ assert(n == 42);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2s(signed char, &n, "-1", &e, 0, SCHAR_MIN, SCHAR_MAX) == 0);
+ assert(n == -1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(signed char, &n, "0x7F", &e, 0, SCHAR_MIN, SCHAR_MAX) == 0);
+ assert(n == 0x7F);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(signed char, &n, "0xFF", &e, 0, SCHAR_MIN, SCHAR_MAX) == -1);
+ assert(n == SCHAR_MAX);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2s(signed char, &n, "-0xFF", &e, 0, SCHAR_MIN, SCHAR_MAX) == -1);
+ assert(n == SCHAR_MIN);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ char *e;
+ short n;
+
+ assert(a2s(short, &n, "\n9 fff 7", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2s(short, &n, "\n9\t", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2s(short, &n, "9 ", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+}
diff --git a/share/tests/a2i.h/a2s/a2s.sh b/share/tests/a2i.h/a2s/a2s.sh
new file mode 100755
index 0000000..33a5e2b
--- /dev/null
+++ b/share/tests/a2i.h/a2s/a2s.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/a2s.c $LIBS;
+"$out";
diff --git a/share/tests/a2i.h/a2s/a2s_nobuild.sh b/share/tests/a2i.h/a2s/a2s_nobuild.sh
new file mode 100755
index 0000000..addcf7f
--- /dev/null
+++ b/share/tests/a2i.h/a2s/a2s_nobuild.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned char n;
+
+ a2s(signed char, &n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ long n;
+
+ a2s(int, &n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- 'static assertion failed' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected static assertion failed"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ a2s(unsigned long, &n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
diff --git a/share/tests/a2i.h/a2sh/a2sh.c b/share/tests/a2i.h/a2sh/a2sh.c
new file mode 100644
index 0000000..d12fab5
--- /dev/null
+++ b/share/tests/a2i.h/a2sh/a2sh.c
@@ -0,0 +1,457 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/a2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ char *e = "unmodified";
+ short n;
+
+ assert(a2sh(&n, "x99z", NULL, 1, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sh(&n, "x99z", &e, 1, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2sh(&n, "x99z", NULL, 0, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(a2sh(&n, "x99z", &e, 0, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2sh(&n, "99z", NULL, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(a2sh(&n, "99z", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2sh(&n, "9z", NULL, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(a2sh(&n, "9z", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ errno = 0;
+
+ assert(a2sh(&n, "9", NULL, 0, -7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(a2sh(&n, "9", &e, 0, -7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_base(void)
+{
+ char *e = "unmodified";
+ short n;
+
+ assert(a2sh(&n, "1", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sh(&n, "1", &e, -1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sh(&n, "1", &e, -2, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sh(&n, "1", &e, 37, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sh(&n, "1", &e, 38, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sh(&n, "1", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(a2sh(&n, "", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sh(&n, "foo", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sh(&n, "43", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sh(&n, "1", &e, 1, -42, -7) == -1);
+ assert(n == -7);
+ assert(errno == EINVAL);
+ assert(a2sh(&n, "1", &e, 1, 42, -42) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2sh(&n, "4foo", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ errno = 0;
+
+ assert(a2sh(&n, "1", &e, 0, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "1", &e, 2, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "1", &e, 3, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "1", &e, 35, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "1", &e, 36, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2sh(&n, "0b11", &e, 0, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sh(&n, "0B11", &e, 0, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sh(&n, "-0b11", &e, 0, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sh(&n, "-0B11", &e, 0, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "011", &e, 0, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-011", &e, 0, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "11", &e, 0, -42, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-11", &e, 0, -42, 42) == 0);
+ assert(n == -11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "0x11", &e, 0, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "0X11", &e, 0, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-0x11", &e, 0, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-0X11", &e, 0, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sh(&n, "011", &e, 2, -42, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "11", &e, 2, -42, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2sh(&n, "0b11", NULL, 2, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sh(&n, "0B11", NULL, 2, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-011", &e, 2, -42, 42) == 0);
+ assert(n == -3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-11", &e, 2, -42, 42) == 0);
+ assert(n == -3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2sh(&n, "-0b11", NULL, 2, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sh(&n, "-0B11", NULL, 2, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "011", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "0x11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "0X11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-011", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-0x11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-0X11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sh(&n, "011", &e, 7, -42, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "11", &e, 7, -42, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-011", &e, 7, -42, 42) == 0);
+ assert(n == -8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-11", &e, 7, -42, 42) == 0);
+ assert(n == -8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "011", &e, 8, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "11", &e, 8, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-011", &e, 8, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-11", &e, 8, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "z", &e, 36, -42, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "Z", &e, 36, -42, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-z", &e, 36, -42, 42) == 0);
+ assert(n == -35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-Z", &e, 36, -42, 42) == 0);
+ assert(n == -35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ char *e;
+ short n;
+
+ assert(a2sh(&n, "", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "foo", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2sh(&n, "foo 7", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2sh(&n, "", &e, 0, 42, -42) == -1);
+ assert(n == 42);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+
+ assert(a2sh(&n, " 1", &e, 0, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, " \t\na", &e, 16, -42, 42) == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, " \t\n-a", &e, 16, -42, 42) == 0);
+ assert(n == -10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_range(void)
+{
+ char *e;
+ short n;
+
+ assert(a2sh(&n, "-9", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-8", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "43", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "44", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sh(&n, "7", &e, 0, 7, -42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "42", &e, 0, 7, -42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sh(&n, "-9z", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2sh(&n, "-9 ", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ errno = 0;
+
+ assert(a2sh(&n, "-7", &e, 0, -7, 42) == 0);
+ assert(n == -7);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-6", &e, 0, -7, 42) == 0);
+ assert(n == -6);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "41", &e, 0, -7, 42) == 0);
+ assert(n == 41);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "42", &e, 0, -7, 42) == 0);
+ assert(n == 42);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sh(&n, "-1", &e, 0, SHRT_MIN, SHRT_MAX) == 0);
+ assert(n == -1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "0xFFF", &e, 0, SHRT_MIN, SHRT_MAX) == 0);
+ assert(n == 0xFFF);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "0xFFFF", &e, 0, SHRT_MIN, SHRT_MAX) == -1);
+ assert(n == SHRT_MAX);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sh(&n, "-0xFFFF", &e, 0, SHRT_MIN, SHRT_MAX) == -1);
+ assert(n == SHRT_MIN);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ char *e;
+ short n;
+
+ assert(a2sh(&n, "\n9 fff 7", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2sh(&n, "\n9\t", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2sh(&n, "9 ", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+}
diff --git a/share/tests/a2i.h/a2sh/a2sh.sh b/share/tests/a2i.h/a2sh/a2sh.sh
new file mode 100755
index 0000000..b49a23d
--- /dev/null
+++ b/share/tests/a2i.h/a2sh/a2sh.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/a2sh.c $LIBS;
+"$out";
diff --git a/share/tests/a2i.h/a2sh/a2sh_nobuild.sh b/share/tests/a2i.h/a2sh/a2sh_nobuild.sh
new file mode 100755
index 0000000..09a7b1c
--- /dev/null
+++ b/share/tests/a2i.h/a2sh/a2sh_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned short n;
+
+ a2sh(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ long n;
+
+ a2sh(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
diff --git a/share/tests/a2i.h/a2shh/a2shh.c b/share/tests/a2i.h/a2shh/a2shh.c
new file mode 100644
index 0000000..3f4b9b7
--- /dev/null
+++ b/share/tests/a2i.h/a2shh/a2shh.c
@@ -0,0 +1,457 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/a2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ char *e = "unmodified";
+ signed char n;
+
+ assert(a2shh(&n, "x99z", NULL, 1, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2shh(&n, "x99z", &e, 1, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2shh(&n, "x99z", NULL, 0, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(a2shh(&n, "x99z", &e, 0, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2shh(&n, "99z", NULL, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(a2shh(&n, "99z", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2shh(&n, "9z", NULL, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(a2shh(&n, "9z", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ errno = 0;
+
+ assert(a2shh(&n, "9", NULL, 0, -7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(a2shh(&n, "9", &e, 0, -7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_base(void)
+{
+ char *e = "unmodified";
+ signed char n;
+
+ assert(a2shh(&n, "1", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2shh(&n, "1", &e, -1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2shh(&n, "1", &e, -2, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2shh(&n, "1", &e, 37, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2shh(&n, "1", &e, 38, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2shh(&n, "1", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(a2shh(&n, "", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2shh(&n, "foo", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2shh(&n, "43", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2shh(&n, "1", &e, 1, -42, -7) == -1);
+ assert(n == -7);
+ assert(errno == EINVAL);
+ assert(a2shh(&n, "1", &e, 1, 42, -42) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2shh(&n, "4foo", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ errno = 0;
+
+ assert(a2shh(&n, "1", &e, 0, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "1", &e, 2, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "1", &e, 3, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "1", &e, 35, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "1", &e, 36, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2shh(&n, "0b11", &e, 0, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2shh(&n, "0B11", &e, 0, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2shh(&n, "-0b11", &e, 0, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2shh(&n, "-0B11", &e, 0, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "011", &e, 0, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-011", &e, 0, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "11", &e, 0, -42, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-11", &e, 0, -42, 42) == 0);
+ assert(n == -11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "0x11", &e, 0, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "0X11", &e, 0, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-0x11", &e, 0, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-0X11", &e, 0, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2shh(&n, "011", &e, 2, -42, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "11", &e, 2, -42, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2shh(&n, "0b11", NULL, 2, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2shh(&n, "0B11", NULL, 2, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-011", &e, 2, -42, 42) == 0);
+ assert(n == -3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-11", &e, 2, -42, 42) == 0);
+ assert(n == -3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2shh(&n, "-0b11", NULL, 2, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2shh(&n, "-0B11", NULL, 2, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "011", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "0x11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "0X11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-011", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-0x11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-0X11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2shh(&n, "011", &e, 7, -42, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "11", &e, 7, -42, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-011", &e, 7, -42, 42) == 0);
+ assert(n == -8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-11", &e, 7, -42, 42) == 0);
+ assert(n == -8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "011", &e, 8, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "11", &e, 8, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-011", &e, 8, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-11", &e, 8, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "z", &e, 36, -42, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "Z", &e, 36, -42, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-z", &e, 36, -42, 42) == 0);
+ assert(n == -35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-Z", &e, 36, -42, 42) == 0);
+ assert(n == -35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ char *e;
+ signed char n;
+
+ assert(a2shh(&n, "", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "foo", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2shh(&n, "foo 7", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2shh(&n, "", &e, 0, 42, -42) == -1);
+ assert(n == 42);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+
+ assert(a2shh(&n, " 1", &e, 0, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, " \t\na", &e, 16, -42, 42) == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, " \t\n-a", &e, 16, -42, 42) == 0);
+ assert(n == -10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_range(void)
+{
+ char *e;
+ signed char n;
+
+ assert(a2shh(&n, "-9", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-8", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "43", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "44", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2shh(&n, "7", &e, 0, 7, -42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "42", &e, 0, 7, -42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2shh(&n, "-9z", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2shh(&n, "-9 ", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ errno = 0;
+
+ assert(a2shh(&n, "-7", &e, 0, -7, 42) == 0);
+ assert(n == -7);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-6", &e, 0, -7, 42) == 0);
+ assert(n == -6);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "41", &e, 0, -7, 42) == 0);
+ assert(n == 41);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "42", &e, 0, -7, 42) == 0);
+ assert(n == 42);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2shh(&n, "-1", &e, 0, SCHAR_MIN, SCHAR_MAX) == 0);
+ assert(n == -1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "0x7F", &e, 0, SCHAR_MIN, SCHAR_MAX) == 0);
+ assert(n == 0x7F);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "0xFF", &e, 0, SCHAR_MIN, SCHAR_MAX) == -1);
+ assert(n == SCHAR_MAX);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2shh(&n, "-0xFF", &e, 0, SCHAR_MIN, SCHAR_MAX) == -1);
+ assert(n == SCHAR_MIN);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ char *e;
+ signed char n;
+
+ assert(a2shh(&n, "\n9 fff 7", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2shh(&n, "\n9\t", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2shh(&n, "9 ", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+}
diff --git a/share/tests/a2i.h/a2shh/a2shh.sh b/share/tests/a2i.h/a2shh/a2shh.sh
new file mode 100755
index 0000000..0b0a9d5
--- /dev/null
+++ b/share/tests/a2i.h/a2shh/a2shh.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/a2shh.c $LIBS;
+"$out";
diff --git a/share/tests/a2i.h/a2shh/a2shh_nobuild.sh b/share/tests/a2i.h/a2shh/a2shh_nobuild.sh
new file mode 100755
index 0000000..e01d682
--- /dev/null
+++ b/share/tests/a2i.h/a2shh/a2shh_nobuild.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned char n;
+
+ a2shh(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ char n;
+
+ a2shh(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ long n;
+
+ a2shh(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
diff --git a/share/tests/a2i.h/a2si/a2si.c b/share/tests/a2i.h/a2si/a2si.c
new file mode 100644
index 0000000..3ee3295
--- /dev/null
+++ b/share/tests/a2i.h/a2si/a2si.c
@@ -0,0 +1,457 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/a2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ char *e = "unmodified";
+ int n;
+
+ assert(a2si(&n, "x99z", NULL, 1, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2si(&n, "x99z", &e, 1, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2si(&n, "x99z", NULL, 0, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(a2si(&n, "x99z", &e, 0, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2si(&n, "99z", NULL, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(a2si(&n, "99z", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2si(&n, "9z", NULL, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(a2si(&n, "9z", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ errno = 0;
+
+ assert(a2si(&n, "9", NULL, 0, -7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(a2si(&n, "9", &e, 0, -7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_base(void)
+{
+ char *e = "unmodified";
+ int n;
+
+ assert(a2si(&n, "1", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2si(&n, "1", &e, -1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2si(&n, "1", &e, -2, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2si(&n, "1", &e, 37, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2si(&n, "1", &e, 38, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2si(&n, "1", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(a2si(&n, "", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2si(&n, "foo", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2si(&n, "43", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2si(&n, "1", &e, 1, -42, -7) == -1);
+ assert(n == -7);
+ assert(errno == EINVAL);
+ assert(a2si(&n, "1", &e, 1, 42, -42) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2si(&n, "4foo", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ errno = 0;
+
+ assert(a2si(&n, "1", &e, 0, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "1", &e, 2, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "1", &e, 3, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "1", &e, 35, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "1", &e, 36, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2si(&n, "0b11", &e, 0, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2si(&n, "0B11", &e, 0, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2si(&n, "-0b11", &e, 0, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2si(&n, "-0B11", &e, 0, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "011", &e, 0, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-011", &e, 0, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "11", &e, 0, -42, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-11", &e, 0, -42, 42) == 0);
+ assert(n == -11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "0x11", &e, 0, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "0X11", &e, 0, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-0x11", &e, 0, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-0X11", &e, 0, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2si(&n, "011", &e, 2, -42, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "11", &e, 2, -42, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2si(&n, "0b11", NULL, 2, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2si(&n, "0B11", NULL, 2, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-011", &e, 2, -42, 42) == 0);
+ assert(n == -3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-11", &e, 2, -42, 42) == 0);
+ assert(n == -3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2si(&n, "-0b11", NULL, 2, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2si(&n, "-0B11", NULL, 2, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "011", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "0x11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "0X11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-011", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-0x11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-0X11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2si(&n, "011", &e, 7, -42, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "11", &e, 7, -42, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-011", &e, 7, -42, 42) == 0);
+ assert(n == -8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-11", &e, 7, -42, 42) == 0);
+ assert(n == -8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "011", &e, 8, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "11", &e, 8, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-011", &e, 8, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-11", &e, 8, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "z", &e, 36, -42, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "Z", &e, 36, -42, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-z", &e, 36, -42, 42) == 0);
+ assert(n == -35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-Z", &e, 36, -42, 42) == 0);
+ assert(n == -35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ char *e;
+ int n;
+
+ assert(a2si(&n, "", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "foo", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2si(&n, "foo 7", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2si(&n, "", &e, 0, 42, -42) == -1);
+ assert(n == 42);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+
+ assert(a2si(&n, " 1", &e, 0, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, " \t\na", &e, 16, -42, 42) == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, " \t\n-a", &e, 16, -42, 42) == 0);
+ assert(n == -10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_range(void)
+{
+ char *e;
+ int n;
+
+ assert(a2si(&n, "-9", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-8", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "43", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "44", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2si(&n, "7", &e, 0, 7, -42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "42", &e, 0, 7, -42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2si(&n, "-9z", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2si(&n, "-9 ", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ errno = 0;
+
+ assert(a2si(&n, "-7", &e, 0, -7, 42) == 0);
+ assert(n == -7);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-6", &e, 0, -7, 42) == 0);
+ assert(n == -6);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "41", &e, 0, -7, 42) == 0);
+ assert(n == 41);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "42", &e, 0, -7, 42) == 0);
+ assert(n == 42);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2si(&n, "-1", &e, 0, INT_MIN, INT_MAX) == 0);
+ assert(n == -1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "0xFFF", &e, 0, INT_MIN, INT_MAX) == 0);
+ assert(n == 0xFFF);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "0xFFFFffffFFFFffff", &e, 0, INT_MIN, INT_MAX) == -1);
+ assert(n == INT_MAX);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2si(&n, "-0xFFFFffffFFFFffff", &e, 0, INT_MIN, INT_MAX) == -1);
+ assert(n == INT_MIN);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ char *e;
+ int n;
+
+ assert(a2si(&n, "\n9 fff 7", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2si(&n, "\n9\t", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2si(&n, "9 ", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+}
diff --git a/share/tests/a2i.h/a2si/a2si.sh b/share/tests/a2i.h/a2si/a2si.sh
new file mode 100755
index 0000000..109338c
--- /dev/null
+++ b/share/tests/a2i.h/a2si/a2si.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/a2si.c $LIBS;
+"$out";
diff --git a/share/tests/a2i.h/a2si/a2si_nobuild.sh b/share/tests/a2i.h/a2si/a2si_nobuild.sh
new file mode 100755
index 0000000..ecb2db6
--- /dev/null
+++ b/share/tests/a2i.h/a2si/a2si_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned int n;
+
+ a2si(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ long n;
+
+ a2si(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
diff --git a/share/tests/a2i.h/a2sl/a2sl.c b/share/tests/a2i.h/a2sl/a2sl.c
new file mode 100644
index 0000000..a91fb37
--- /dev/null
+++ b/share/tests/a2i.h/a2sl/a2sl.c
@@ -0,0 +1,457 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/a2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ char *e = "unmodified";
+ long n;
+
+ assert(a2sl(&n, "x99z", NULL, 1, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sl(&n, "x99z", &e, 1, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2sl(&n, "x99z", NULL, 0, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(a2sl(&n, "x99z", &e, 0, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2sl(&n, "99z", NULL, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(a2sl(&n, "99z", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2sl(&n, "9z", NULL, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(a2sl(&n, "9z", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ errno = 0;
+
+ assert(a2sl(&n, "9", NULL, 0, -7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(a2sl(&n, "9", &e, 0, -7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_base(void)
+{
+ char *e = "unmodified";
+ long n;
+
+ assert(a2sl(&n, "1", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sl(&n, "1", &e, -1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sl(&n, "1", &e, -2, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sl(&n, "1", &e, 37, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sl(&n, "1", &e, 38, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sl(&n, "1", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(a2sl(&n, "", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sl(&n, "foo", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sl(&n, "43", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sl(&n, "1", &e, 1, -42, -7) == -1);
+ assert(n == -7);
+ assert(errno == EINVAL);
+ assert(a2sl(&n, "1", &e, 1, 42, -42) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2sl(&n, "4foo", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ errno = 0;
+
+ assert(a2sl(&n, "1", &e, 0, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "1", &e, 2, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "1", &e, 3, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "1", &e, 35, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "1", &e, 36, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2sl(&n, "0b11", &e, 0, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sl(&n, "0B11", &e, 0, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sl(&n, "-0b11", &e, 0, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sl(&n, "-0B11", &e, 0, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "011", &e, 0, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-011", &e, 0, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "11", &e, 0, -42, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-11", &e, 0, -42, 42) == 0);
+ assert(n == -11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "0x11", &e, 0, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "0X11", &e, 0, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-0x11", &e, 0, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-0X11", &e, 0, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sl(&n, "011", &e, 2, -42, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "11", &e, 2, -42, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2sl(&n, "0b11", NULL, 2, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sl(&n, "0B11", NULL, 2, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-011", &e, 2, -42, 42) == 0);
+ assert(n == -3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-11", &e, 2, -42, 42) == 0);
+ assert(n == -3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2sl(&n, "-0b11", NULL, 2, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sl(&n, "-0B11", NULL, 2, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "011", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "0x11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "0X11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-011", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-0x11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-0X11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sl(&n, "011", &e, 7, -42, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "11", &e, 7, -42, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-011", &e, 7, -42, 42) == 0);
+ assert(n == -8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-11", &e, 7, -42, 42) == 0);
+ assert(n == -8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "011", &e, 8, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "11", &e, 8, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-011", &e, 8, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-11", &e, 8, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "z", &e, 36, -42, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "Z", &e, 36, -42, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-z", &e, 36, -42, 42) == 0);
+ assert(n == -35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-Z", &e, 36, -42, 42) == 0);
+ assert(n == -35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ char *e;
+ long n;
+
+ assert(a2sl(&n, "", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "foo", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2sl(&n, "foo 7", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2sl(&n, "", &e, 0, 42, -42) == -1);
+ assert(n == 42);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+
+ assert(a2sl(&n, " 1", &e, 0, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, " \t\na", &e, 16, -42, 42) == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, " \t\n-a", &e, 16, -42, 42) == 0);
+ assert(n == -10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_range(void)
+{
+ char *e;
+ long n;
+
+ assert(a2sl(&n, "-9", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-8", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "43", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "44", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sl(&n, "7", &e, 0, 7, -42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "42", &e, 0, 7, -42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sl(&n, "-9z", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2sl(&n, "-9 ", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ errno = 0;
+
+ assert(a2sl(&n, "-7", &e, 0, -7, 42) == 0);
+ assert(n == -7);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-6", &e, 0, -7, 42) == 0);
+ assert(n == -6);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "41", &e, 0, -7, 42) == 0);
+ assert(n == 41);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "42", &e, 0, -7, 42) == 0);
+ assert(n == 42);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sl(&n, "-1", &e, 0, LONG_MIN, LONG_MAX) == 0);
+ assert(n == -1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "0xFFFffff", &e, 0, LONG_MIN, LONG_MAX) == 0);
+ assert(n == 0xFFFffff);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "0xFFFFffffFFFFffff", &e, 0, LONG_MIN, LONG_MAX) == -1);
+ assert(n == LONG_MAX);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sl(&n, "-0xFFFFffffFFFFffff", &e, 0, LONG_MIN, LONG_MAX) == -1);
+ assert(n == LONG_MIN);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ char *e;
+ long n;
+
+ assert(a2sl(&n, "\n9 fff 7", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2sl(&n, "\n9\t", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2sl(&n, "9 ", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+}
diff --git a/share/tests/a2i.h/a2sl/a2sl.sh b/share/tests/a2i.h/a2sl/a2sl.sh
new file mode 100755
index 0000000..edec276
--- /dev/null
+++ b/share/tests/a2i.h/a2sl/a2sl.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/a2sl.c $LIBS;
+"$out";
diff --git a/share/tests/a2i.h/a2sl/a2sl_nobuild.sh b/share/tests/a2i.h/a2sl/a2sl_nobuild.sh
new file mode 100755
index 0000000..fd2b483
--- /dev/null
+++ b/share/tests/a2i.h/a2sl/a2sl_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ a2sl(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ int n;
+
+ a2sl(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
diff --git a/share/tests/a2i.h/a2sll/a2sll.c b/share/tests/a2i.h/a2sll/a2sll.c
new file mode 100644
index 0000000..ffce91f
--- /dev/null
+++ b/share/tests/a2i.h/a2sll/a2sll.c
@@ -0,0 +1,457 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/a2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ char *e = "unmodified";
+ long long n;
+
+ assert(a2sll(&n, "x99z", NULL, 1, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sll(&n, "x99z", &e, 1, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2sll(&n, "x99z", NULL, 0, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(a2sll(&n, "x99z", &e, 0, -7, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2sll(&n, "99z", NULL, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(a2sll(&n, "99z", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2sll(&n, "9z", NULL, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(a2sll(&n, "9z", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ errno = 0;
+
+ assert(a2sll(&n, "9", NULL, 0, -7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(a2sll(&n, "9", &e, 0, -7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_base(void)
+{
+ char *e = "unmodified";
+ long long n;
+
+ assert(a2sll(&n, "1", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sll(&n, "1", &e, -1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sll(&n, "1", &e, -2, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sll(&n, "1", &e, 37, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sll(&n, "1", &e, 38, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sll(&n, "1", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(a2sll(&n, "", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sll(&n, "foo", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sll(&n, "43", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2sll(&n, "1", &e, 1, -42, -7) == -1);
+ assert(n == -7);
+ assert(errno == EINVAL);
+ assert(a2sll(&n, "1", &e, 1, 42, -42) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2sll(&n, "4foo", &e, 1, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ errno = 0;
+
+ assert(a2sll(&n, "1", &e, 0, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "1", &e, 2, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "1", &e, 3, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "1", &e, 35, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "1", &e, 36, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2sll(&n, "0b11", &e, 0, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sll(&n, "0B11", &e, 0, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sll(&n, "-0b11", &e, 0, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sll(&n, "-0B11", &e, 0, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "011", &e, 0, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-011", &e, 0, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "11", &e, 0, -42, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-11", &e, 0, -42, 42) == 0);
+ assert(n == -11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "0x11", &e, 0, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "0X11", &e, 0, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-0x11", &e, 0, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-0X11", &e, 0, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sll(&n, "011", &e, 2, -42, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "11", &e, 2, -42, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2sll(&n, "0b11", NULL, 2, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sll(&n, "0B11", NULL, 2, -42, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-011", &e, 2, -42, 42) == 0);
+ assert(n == -3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-11", &e, 2, -42, 42) == 0);
+ assert(n == -3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2sll(&n, "-0b11", NULL, 2, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2sll(&n, "-0B11", NULL, 2, -42, 42) == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "011", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "0x11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "0X11", &e, 16, -42, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-011", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-0x11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-0X11", &e, 16, -42, 42) == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sll(&n, "011", &e, 7, -42, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "11", &e, 7, -42, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-011", &e, 7, -42, 42) == 0);
+ assert(n == -8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-11", &e, 7, -42, 42) == 0);
+ assert(n == -8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "011", &e, 8, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "11", &e, 8, -42, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-011", &e, 8, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-11", &e, 8, -42, 42) == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "z", &e, 36, -42, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "Z", &e, 36, -42, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-z", &e, 36, -42, 42) == 0);
+ assert(n == -35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-Z", &e, 36, -42, 42) == 0);
+ assert(n == -35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ char *e;
+ long long n;
+
+ assert(a2sll(&n, "", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "foo", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2sll(&n, "foo 7", &e, 0, -42, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2sll(&n, "", &e, 0, 42, -42) == -1);
+ assert(n == 42);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+
+ assert(a2sll(&n, " 1", &e, 0, -42, 42) == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, " \t\na", &e, 16, -42, 42) == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, " \t\n-a", &e, 16, -42, 42) == 0);
+ assert(n == -10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_range(void)
+{
+ char *e;
+ long long n;
+
+ assert(a2sll(&n, "-9", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-8", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "43", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "44", &e, 0, -7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sll(&n, "7", &e, 0, 7, -42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "42", &e, 0, 7, -42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sll(&n, "-9z", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2sll(&n, "-9 ", &e, 0, -7, 42) == -1);
+ assert(n == -7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ errno = 0;
+
+ assert(a2sll(&n, "-7", &e, 0, -7, 42) == 0);
+ assert(n == -7);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-6", &e, 0, -7, 42) == 0);
+ assert(n == -6);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "41", &e, 0, -7, 42) == 0);
+ assert(n == 41);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "42", &e, 0, -7, 42) == 0);
+ assert(n == 42);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2sll(&n, "-1", &e, 0, LLONG_MIN, LLONG_MAX) == 0);
+ assert(n == -1);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "0xFFFffffFFFFffff", &e, 0, LLONG_MIN, LLONG_MAX) == 0);
+ assert(n == 0xFFFffffFFFFffff);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "0xFFFFffffFFFFffff", &e, 0, LLONG_MIN, LLONG_MAX) == -1);
+ assert(n == LLONG_MAX);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2sll(&n, "-0xFFFFffffFFFFffff", &e, 0, LLONG_MIN, LLONG_MAX) == -1);
+ assert(n == LLONG_MIN);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ char *e;
+ long long n;
+
+ assert(a2sll(&n, "\n9 fff 7", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2sll(&n, "\n9\t", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2sll(&n, "9 ", &e, 0, -7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+}
diff --git a/share/tests/a2i.h/a2sll/a2sll.sh b/share/tests/a2i.h/a2sll/a2sll.sh
new file mode 100755
index 0000000..ed2aaaf
--- /dev/null
+++ b/share/tests/a2i.h/a2sll/a2sll.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/a2sll.c $LIBS;
+"$out";
diff --git a/share/tests/a2i.h/a2sll/a2sll_nobuild.sh b/share/tests/a2i.h/a2sll/a2sll_nobuild.sh
new file mode 100755
index 0000000..863714a
--- /dev/null
+++ b/share/tests/a2i.h/a2sll/a2sll_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long long n;
+
+ a2sll(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ long n;
+
+ a2sll(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
diff --git a/share/tests/a2i.h/a2u/a2u.c b/share/tests/a2i.h/a2u/a2u.c
new file mode 100644
index 0000000..28d1701
--- /dev/null
+++ b/share/tests/a2i.h/a2u/a2u.c
@@ -0,0 +1,468 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/a2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ char *e = "unmodified";
+ unsigned int n;
+
+ assert(a2u(unsigned int, &n, "x99z", NULL, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2u(unsigned int, &n, "x99z", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2u(unsigned int, &n, "x99z", NULL, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(a2u(unsigned int, &n, "x99z", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2u(unsigned int, &n, "99z", NULL, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(a2u(unsigned int, &n, "99z", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2u(unsigned int, &n, "9z", NULL, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(a2u(unsigned int, &n, "9z", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ errno = 0;
+
+ assert(a2u(unsigned int, &n, "9", NULL, 0, 7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(a2u(unsigned int, &n, "9", &e, 0, 7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_base(void)
+{
+ char *e = "unmodified";
+ unsigned long n;
+
+ assert(a2u(unsigned long, &n, "9", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2u(unsigned long, &n, "9", &e, -1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2u(unsigned long, &n, "9", &e, -2, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2u(unsigned long, &n, "9", &e, 37, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2u(unsigned long, &n, "9", &e, 38, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2u(unsigned long, &n, "9", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(a2u(unsigned long, &n, "", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2u(unsigned long, &n, "foo", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2u(unsigned long, &n, "43", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2u(unsigned long, &n, "9", &e, 1, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2u(unsigned long, &n, "9", &e, 1, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2u(unsigned long, &n, "9foo", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ errno = 0;
+
+ assert(a2u(unsigned long, &n, "11", &e, 0, 2, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "11", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "11", &e, 3, 2, 42) == 0);
+ assert(n == 4);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "11", &e, 35, 2, 42) == 0);
+ assert(n == 36);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "11", &e, 36, 2, 42) == 0);
+ assert(n == 37);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2u(unsigned long, &n, "0b11", &e, 0, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2u(unsigned long, &n, "0B11", &e, 0, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2u(unsigned long, &n, "-0b11", &e, 0, 2, 42) == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2u(unsigned long, &n, "-0B11", &e, 0, 2, 42) == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "011", &e, 0, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-011", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2u(unsigned long, &n, "11", &e, 0, 2, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2u(unsigned long, &n, "0x11", &e, 0, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "0X11", &e, 0, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-0x11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-0X11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+ assert(a2u(unsigned long, &n, "011", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "11", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2u(unsigned long, &n, "0b11", NULL, 2, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2u(unsigned long, &n, "0B11", NULL, 2, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-011", &e, 2, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-11", &e, 2, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ //assert(a2u(unsigned long, &n, "-0b11", NULL, 2, 2, 42) == -1);
+ //assertn == 2);
+ //assert(errno == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2u(unsigned long, &n, "-0B11", NULL, 2, 2, 42) == -1);
+ //assertn == 2);
+ //assert(errno == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2u(unsigned long, &n, "011", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "0x11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "0X11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-011", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-0x11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-0X11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+ assert(a2u(unsigned long, &n, "011", &e, 7, 2, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "11", &e, 7, 2, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-011", &e, 7, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-11", &e, 7, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2u(unsigned long, &n, "011", &e, 8, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "11", &e, 8, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-011", &e, 8, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-11", &e, 8, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2u(unsigned long, &n, "z", &e, 36, 2, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "Z", &e, 36, 2, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-z", &e, 36, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long, &n, "-Z", &e, 36, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ char *e;
+ unsigned long long n;
+
+ assert(a2u(unsigned long long, &n, "", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long long, &n, "foo", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2u(unsigned long long, &n, "foo 7", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2u(unsigned long long, &n, "", &e, 0, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+
+ assert(a2u(unsigned long long, &n, " 9", &e, 0, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long long, &n, " \t\na", &e, 16, 2, 42) == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned long long, &n, " \t\n-a", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_range(void)
+{
+ char *e;
+ unsigned char n;
+
+ assert(a2u(unsigned char, &n, "5", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned char, &n, "6", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned char, &n, "43", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned char, &n, "44", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2u(unsigned char, &n, "7", &e, 0, 7, 4) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned char, &n, "42", &e, 0, 7, 4) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2u(unsigned char, &n, "6z", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2u(unsigned char, &n, "6 ", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ errno = 0;
+ assert(a2u(unsigned char, &n, "7", &e, 0, 7, 42) == 0);
+ assert(n == 7);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned char, &n, "8", &e, 0, 7, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned char, &n, "41", &e, 0, 7, 42) == 0);
+ assert(n == 41);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned char, &n, "42", &e, 0, 7, 42) == 0);
+ assert(n == 42);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2u(unsigned char, &n, "-1", &e, 0, 0, UCHAR_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2u(unsigned char, &n, "0xFF", &e, 0, 0, UCHAR_MAX) == 0);
+ assert(n == 0xFF);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned char, &n, "-0xFF", &e, 0, 0, UCHAR_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned char, &n, "0xFF9", &e, 0, 0, UCHAR_MAX) == -1);
+ assert(n == UCHAR_MAX);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2u(unsigned char, &n, "-0xFF9", &e, 0, 0, UCHAR_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ char *e;
+ unsigned short n;
+
+ assert(a2u(unsigned short, &n, "\n9 fff 7", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2u(unsigned short, &n, "\n9\t", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2u(unsigned short, &n, "9 ", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+}
diff --git a/share/tests/a2i.h/a2u/a2u.sh b/share/tests/a2i.h/a2u/a2u.sh
new file mode 100755
index 0000000..c873f1d
--- /dev/null
+++ b/share/tests/a2i.h/a2u/a2u.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/a2u.c $LIBS;
+"$out";
diff --git a/share/tests/a2i.h/a2u/a2u_nobuild.sh b/share/tests/a2i.h/a2u/a2u_nobuild.sh
new file mode 100755
index 0000000..15b83c9
--- /dev/null
+++ b/share/tests/a2i.h/a2u/a2u_nobuild.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ signed char n;
+
+ a2u(unsigned char, &n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ a2u(unsigned int, &n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- 'static assertion failed' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected static assertion failed"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ long n;
+
+ a2u(long, &n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
diff --git a/share/tests/a2i.h/a2uh/a2uh.c b/share/tests/a2i.h/a2uh/a2uh.c
new file mode 100644
index 0000000..a5c88bf
--- /dev/null
+++ b/share/tests/a2i.h/a2uh/a2uh.c
@@ -0,0 +1,468 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/a2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ char *e = "unmodified";
+ unsigned short n;
+
+ assert(a2uh(&n, "x99z", NULL, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uh(&n, "x99z", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2uh(&n, "x99z", NULL, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(a2uh(&n, "x99z", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2uh(&n, "99z", NULL, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(a2uh(&n, "99z", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2uh(&n, "9z", NULL, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(a2uh(&n, "9z", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ errno = 0;
+
+ assert(a2uh(&n, "9", NULL, 0, 7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(a2uh(&n, "9", &e, 0, 7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_base(void)
+{
+ char *e = "unmodified";
+ unsigned short n;
+
+ assert(a2uh(&n, "9", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uh(&n, "9", &e, -1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uh(&n, "9", &e, -2, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uh(&n, "9", &e, 37, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uh(&n, "9", &e, 38, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uh(&n, "9", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(a2uh(&n, "", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uh(&n, "foo", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uh(&n, "43", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uh(&n, "9", &e, 1, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2uh(&n, "9", &e, 1, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2uh(&n, "9foo", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ errno = 0;
+
+ assert(a2uh(&n, "11", &e, 0, 2, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "11", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "11", &e, 3, 2, 42) == 0);
+ assert(n == 4);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "11", &e, 35, 2, 42) == 0);
+ assert(n == 36);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "11", &e, 36, 2, 42) == 0);
+ assert(n == 37);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2uh(&n, "0b11", &e, 0, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2uh(&n, "0B11", &e, 0, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2uh(&n, "-0b11", &e, 0, 2, 42) == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2uh(&n, "-0B11", &e, 0, 2, 42) == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "011", &e, 0, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-011", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2uh(&n, "11", &e, 0, 2, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2uh(&n, "0x11", &e, 0, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "0X11", &e, 0, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-0x11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-0X11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+ assert(a2uh(&n, "011", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "11", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2uh(&n, "0b11", NULL, 2, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2uh(&n, "0B11", NULL, 2, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-011", &e, 2, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-11", &e, 2, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ //assert(a2uh(&n, "-0b11", NULL, 2, 2, 42) == -1);
+ //assertn == 2);
+ //assert(errno == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2uh(&n, "-0B11", NULL, 2, 2, 42) == -1);
+ //assertn == 2);
+ //assert(errno == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2uh(&n, "011", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "0x11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "0X11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-011", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-0x11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-0X11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+ assert(a2uh(&n, "011", &e, 7, 2, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "11", &e, 7, 2, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-011", &e, 7, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-11", &e, 7, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2uh(&n, "011", &e, 8, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "11", &e, 8, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-011", &e, 8, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-11", &e, 8, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2uh(&n, "z", &e, 36, 2, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "Z", &e, 36, 2, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-z", &e, 36, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-Z", &e, 36, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ char *e;
+ unsigned short n;
+
+ assert(a2uh(&n, "", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "foo", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2uh(&n, "foo 7", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2uh(&n, "", &e, 0, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+
+ assert(a2uh(&n, " 9", &e, 0, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, " \t\na", &e, 16, 2, 42) == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, " \t\n-a", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_range(void)
+{
+ char *e;
+ unsigned short n;
+
+ assert(a2uh(&n, "5", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "6", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "43", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "44", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2uh(&n, "7", &e, 0, 7, 4) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "42", &e, 0, 7, 4) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2uh(&n, "6z", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2uh(&n, "6 ", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ errno = 0;
+ assert(a2uh(&n, "7", &e, 0, 7, 42) == 0);
+ assert(n == 7);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "8", &e, 0, 7, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "41", &e, 0, 7, 42) == 0);
+ assert(n == 41);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "42", &e, 0, 7, 42) == 0);
+ assert(n == 42);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2uh(&n, "-1", &e, 0, 0, USHRT_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2uh(&n, "0xFFFF", &e, 0, 0, USHRT_MAX) == 0);
+ assert(n == 0xFFFF);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-0xFFFF", &e, 0, 0, USHRT_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "0xFFFF9", &e, 0, 0, USHRT_MAX) == -1);
+ assert(n == USHRT_MAX);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uh(&n, "-0xFFFF9", &e, 0, 0, USHRT_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ char *e;
+ unsigned short n;
+
+ assert(a2uh(&n, "\n9 fff 7", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2uh(&n, "\n9\t", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2uh(&n, "9 ", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+}
diff --git a/share/tests/a2i.h/a2uh/a2uh.sh b/share/tests/a2i.h/a2uh/a2uh.sh
new file mode 100755
index 0000000..77586a2
--- /dev/null
+++ b/share/tests/a2i.h/a2uh/a2uh.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/a2uh.c $LIBS;
+"$out";
diff --git a/share/tests/a2i.h/a2uh/a2uh_nobuild.sh b/share/tests/a2i.h/a2uh/a2uh_nobuild.sh
new file mode 100755
index 0000000..923da5a
--- /dev/null
+++ b/share/tests/a2i.h/a2uh/a2uh_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ short n;
+
+ a2uh(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ a2uh(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
diff --git a/share/tests/a2i.h/a2uhh/a2uhh.c b/share/tests/a2i.h/a2uhh/a2uhh.c
new file mode 100644
index 0000000..ef0f2a8
--- /dev/null
+++ b/share/tests/a2i.h/a2uhh/a2uhh.c
@@ -0,0 +1,468 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/a2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ char *e = "unmodified";
+ unsigned char n;
+
+ assert(a2uhh(&n, "x99z", NULL, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uhh(&n, "x99z", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2uhh(&n, "x99z", NULL, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(a2uhh(&n, "x99z", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2uhh(&n, "99z", NULL, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(a2uhh(&n, "99z", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2uhh(&n, "9z", NULL, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(a2uhh(&n, "9z", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ errno = 0;
+
+ assert(a2uhh(&n, "9", NULL, 0, 7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(a2uhh(&n, "9", &e, 0, 7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_base(void)
+{
+ char *e = "unmodified";
+ unsigned char n;
+
+ assert(a2uhh(&n, "9", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uhh(&n, "9", &e, -1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uhh(&n, "9", &e, -2, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uhh(&n, "9", &e, 37, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uhh(&n, "9", &e, 38, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uhh(&n, "9", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(a2uhh(&n, "", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uhh(&n, "foo", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uhh(&n, "43", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2uhh(&n, "9", &e, 1, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2uhh(&n, "9", &e, 1, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2uhh(&n, "9foo", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ errno = 0;
+
+ assert(a2uhh(&n, "11", &e, 0, 2, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "11", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "11", &e, 3, 2, 42) == 0);
+ assert(n == 4);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "11", &e, 35, 2, 42) == 0);
+ assert(n == 36);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "11", &e, 36, 2, 42) == 0);
+ assert(n == 37);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2uhh(&n, "0b11", &e, 0, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2uhh(&n, "0B11", &e, 0, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2uhh(&n, "-0b11", &e, 0, 2, 42) == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2uhh(&n, "-0B11", &e, 0, 2, 42) == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "011", &e, 0, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-011", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2uhh(&n, "11", &e, 0, 2, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2uhh(&n, "0x11", &e, 0, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "0X11", &e, 0, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-0x11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-0X11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+ assert(a2uhh(&n, "011", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "11", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2uhh(&n, "0b11", NULL, 2, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2uhh(&n, "0B11", NULL, 2, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-011", &e, 2, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-11", &e, 2, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ //assert(a2uhh(&n, "-0b11", NULL, 2, 2, 42) == -1);
+ //assertn == 2);
+ //assert(errno == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2uhh(&n, "-0B11", NULL, 2, 2, 42) == -1);
+ //assertn == 2);
+ //assert(errno == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2uhh(&n, "011", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "0x11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "0X11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-011", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-0x11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-0X11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+ assert(a2uhh(&n, "011", &e, 7, 2, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "11", &e, 7, 2, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-011", &e, 7, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-11", &e, 7, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2uhh(&n, "011", &e, 8, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "11", &e, 8, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-011", &e, 8, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-11", &e, 8, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2uhh(&n, "z", &e, 36, 2, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "Z", &e, 36, 2, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-z", &e, 36, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-Z", &e, 36, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ char *e;
+ unsigned char n;
+
+ assert(a2uhh(&n, "", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "foo", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2uhh(&n, "foo 7", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2uhh(&n, "", &e, 0, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+
+ assert(a2uhh(&n, " 9", &e, 0, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, " \t\na", &e, 16, 2, 42) == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, " \t\n-a", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_range(void)
+{
+ char *e;
+ unsigned char n;
+
+ assert(a2uhh(&n, "5", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "6", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "43", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "44", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2uhh(&n, "7", &e, 0, 7, 4) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "42", &e, 0, 7, 4) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2uhh(&n, "6z", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2uhh(&n, "6 ", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ errno = 0;
+ assert(a2uhh(&n, "7", &e, 0, 7, 42) == 0);
+ assert(n == 7);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "8", &e, 0, 7, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "41", &e, 0, 7, 42) == 0);
+ assert(n == 41);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "42", &e, 0, 7, 42) == 0);
+ assert(n == 42);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2uhh(&n, "-1", &e, 0, 0, UCHAR_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2uhh(&n, "0xFF", &e, 0, 0, UCHAR_MAX) == 0);
+ assert(n == 0xFF);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-0xFF", &e, 0, 0, UCHAR_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "0xFF9", &e, 0, 0, UCHAR_MAX) == -1);
+ assert(n == UCHAR_MAX);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2uhh(&n, "-0xFF9", &e, 0, 0, UCHAR_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ char *e;
+ unsigned char n;
+
+ assert(a2uhh(&n, "\n9 fff 7", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2uhh(&n, "\n9\t", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2uhh(&n, "9 ", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+}
diff --git a/share/tests/a2i.h/a2uhh/a2uhh.sh b/share/tests/a2i.h/a2uhh/a2uhh.sh
new file mode 100755
index 0000000..3576757
--- /dev/null
+++ b/share/tests/a2i.h/a2uhh/a2uhh.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/a2uhh.c $LIBS;
+"$out";
diff --git a/share/tests/a2i.h/a2uhh/a2uhh_nobuild.sh b/share/tests/a2i.h/a2uhh/a2uhh_nobuild.sh
new file mode 100755
index 0000000..7a85a33
--- /dev/null
+++ b/share/tests/a2i.h/a2uhh/a2uhh_nobuild.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ signed char n;
+
+ a2uhh(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ char n;
+
+ a2uhh(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ a2uhh(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
diff --git a/share/tests/a2i.h/a2ui/a2ui.c b/share/tests/a2i.h/a2ui/a2ui.c
new file mode 100644
index 0000000..d94afbb
--- /dev/null
+++ b/share/tests/a2i.h/a2ui/a2ui.c
@@ -0,0 +1,468 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/a2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ char *e = "unmodified";
+ unsigned int n;
+
+ assert(a2ui(&n, "x99z", NULL, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ui(&n, "x99z", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2ui(&n, "x99z", NULL, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(a2ui(&n, "x99z", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2ui(&n, "99z", NULL, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(a2ui(&n, "99z", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2ui(&n, "9z", NULL, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(a2ui(&n, "9z", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ errno = 0;
+
+ assert(a2ui(&n, "9", NULL, 0, 7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(a2ui(&n, "9", &e, 0, 7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_base(void)
+{
+ char *e = "unmodified";
+ unsigned int n;
+
+ assert(a2ui(&n, "9", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ui(&n, "9", &e, -1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ui(&n, "9", &e, -2, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ui(&n, "9", &e, 37, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ui(&n, "9", &e, 38, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ui(&n, "9", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(a2ui(&n, "", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ui(&n, "foo", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ui(&n, "43", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ui(&n, "9", &e, 1, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2ui(&n, "9", &e, 1, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2ui(&n, "9foo", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ errno = 0;
+
+ assert(a2ui(&n, "11", &e, 0, 2, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "11", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "11", &e, 3, 2, 42) == 0);
+ assert(n == 4);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "11", &e, 35, 2, 42) == 0);
+ assert(n == 36);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "11", &e, 36, 2, 42) == 0);
+ assert(n == 37);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2ui(&n, "0b11", &e, 0, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ui(&n, "0B11", &e, 0, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ui(&n, "-0b11", &e, 0, 2, 42) == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ui(&n, "-0B11", &e, 0, 2, 42) == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "011", &e, 0, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-011", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ui(&n, "11", &e, 0, 2, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ui(&n, "0x11", &e, 0, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "0X11", &e, 0, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-0x11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-0X11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+ assert(a2ui(&n, "011", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "11", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2ui(&n, "0b11", NULL, 2, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ui(&n, "0B11", NULL, 2, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-011", &e, 2, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-11", &e, 2, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ //assert(a2ui(&n, "-0b11", NULL, 2, 2, 42) == -1);
+ //assertn == 2);
+ //assert(errno == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ui(&n, "-0B11", NULL, 2, 2, 42) == -1);
+ //assertn == 2);
+ //assert(errno == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ui(&n, "011", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "0x11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "0X11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-011", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-0x11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-0X11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+ assert(a2ui(&n, "011", &e, 7, 2, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "11", &e, 7, 2, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-011", &e, 7, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-11", &e, 7, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ui(&n, "011", &e, 8, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "11", &e, 8, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-011", &e, 8, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-11", &e, 8, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ui(&n, "z", &e, 36, 2, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "Z", &e, 36, 2, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-z", &e, 36, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-Z", &e, 36, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ char *e;
+ unsigned int n;
+
+ assert(a2ui(&n, "", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "foo", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2ui(&n, "foo 7", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2ui(&n, "", &e, 0, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+
+ assert(a2ui(&n, " 9", &e, 0, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, " \t\na", &e, 16, 2, 42) == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, " \t\n-a", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_range(void)
+{
+ char *e;
+ unsigned int n;
+
+ assert(a2ui(&n, "5", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "6", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "43", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "44", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2ui(&n, "7", &e, 0, 7, 4) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "42", &e, 0, 7, 4) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2ui(&n, "6z", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2ui(&n, "6 ", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ errno = 0;
+ assert(a2ui(&n, "7", &e, 0, 7, 42) == 0);
+ assert(n == 7);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "8", &e, 0, 7, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "41", &e, 0, 7, 42) == 0);
+ assert(n == 41);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "42", &e, 0, 7, 42) == 0);
+ assert(n == 42);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2ui(&n, "-1", &e, 0, 0, UINT_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ui(&n, "0xFFFF", &e, 0, 0, UINT_MAX) == 0);
+ assert(n == 0xFFFF);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-0xFFFFffffFFFFffff", &e, 0, 0, UINT_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "0xFFFFffffFFFFffff9", &e, 0, 0, UINT_MAX) == -1);
+ assert(n == UINT_MAX);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ui(&n, "-0xFFFFffffFFFFffff9", &e, 0, 0, UINT_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ char *e;
+ unsigned int n;
+
+ assert(a2ui(&n, "\n9 fff 7", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2ui(&n, "\n9\t", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2ui(&n, "9 ", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+}
diff --git a/share/tests/a2i.h/a2ui/a2ui.sh b/share/tests/a2i.h/a2ui/a2ui.sh
new file mode 100755
index 0000000..d58eba8
--- /dev/null
+++ b/share/tests/a2i.h/a2ui/a2ui.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/a2ui.c $LIBS;
+"$out";
diff --git a/share/tests/a2i.h/a2ui/a2ui_nobuild.sh b/share/tests/a2i.h/a2ui/a2ui_nobuild.sh
new file mode 100755
index 0000000..dfe578c
--- /dev/null
+++ b/share/tests/a2i.h/a2ui/a2ui_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ int n;
+
+ a2ui(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ a2ui(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
diff --git a/share/tests/a2i.h/a2ul/a2ul.c b/share/tests/a2i.h/a2ul/a2ul.c
new file mode 100644
index 0000000..fce7089
--- /dev/null
+++ b/share/tests/a2i.h/a2ul/a2ul.c
@@ -0,0 +1,468 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/a2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ char *e = "unmodified";
+ unsigned long n;
+
+ assert(a2ul(&n, "x99z", NULL, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ul(&n, "x99z", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2ul(&n, "x99z", NULL, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(a2ul(&n, "x99z", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2ul(&n, "99z", NULL, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(a2ul(&n, "99z", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2ul(&n, "9z", NULL, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(a2ul(&n, "9z", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ errno = 0;
+
+ assert(a2ul(&n, "9", NULL, 0, 7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(a2ul(&n, "9", &e, 0, 7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_base(void)
+{
+ char *e = "unmodified";
+ unsigned long n;
+
+ assert(a2ul(&n, "9", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ul(&n, "9", &e, -1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ul(&n, "9", &e, -2, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ul(&n, "9", &e, 37, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ul(&n, "9", &e, 38, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ul(&n, "9", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(a2ul(&n, "", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ul(&n, "foo", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ul(&n, "43", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ul(&n, "9", &e, 1, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2ul(&n, "9", &e, 1, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2ul(&n, "9foo", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ errno = 0;
+
+ assert(a2ul(&n, "11", &e, 0, 2, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "11", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "11", &e, 3, 2, 42) == 0);
+ assert(n == 4);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "11", &e, 35, 2, 42) == 0);
+ assert(n == 36);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "11", &e, 36, 2, 42) == 0);
+ assert(n == 37);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2ul(&n, "0b11", &e, 0, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ul(&n, "0B11", &e, 0, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ul(&n, "-0b11", &e, 0, 2, 42) == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ul(&n, "-0B11", &e, 0, 2, 42) == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "011", &e, 0, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-011", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ul(&n, "11", &e, 0, 2, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ul(&n, "0x11", &e, 0, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "0X11", &e, 0, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-0x11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-0X11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+ assert(a2ul(&n, "011", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "11", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2ul(&n, "0b11", NULL, 2, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ul(&n, "0B11", NULL, 2, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-011", &e, 2, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-11", &e, 2, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ //assert(a2ul(&n, "-0b11", NULL, 2, 2, 42) == -1);
+ //assertn == 2);
+ //assert(errno == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ul(&n, "-0B11", NULL, 2, 2, 42) == -1);
+ //assertn == 2);
+ //assert(errno == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ul(&n, "011", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "0x11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "0X11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-011", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-0x11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-0X11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+ assert(a2ul(&n, "011", &e, 7, 2, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "11", &e, 7, 2, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-011", &e, 7, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-11", &e, 7, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ul(&n, "011", &e, 8, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "11", &e, 8, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-011", &e, 8, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-11", &e, 8, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ul(&n, "z", &e, 36, 2, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "Z", &e, 36, 2, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-z", &e, 36, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-Z", &e, 36, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ char *e;
+ unsigned long n;
+
+ assert(a2ul(&n, "", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "foo", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2ul(&n, "foo 7", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2ul(&n, "", &e, 0, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+
+ assert(a2ul(&n, " 9", &e, 0, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, " \t\na", &e, 16, 2, 42) == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, " \t\n-a", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_range(void)
+{
+ char *e;
+ unsigned long n;
+
+ assert(a2ul(&n, "5", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "6", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "43", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "44", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2ul(&n, "7", &e, 0, 7, 4) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "42", &e, 0, 7, 4) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2ul(&n, "6z", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2ul(&n, "6 ", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ errno = 0;
+ assert(a2ul(&n, "7", &e, 0, 7, 42) == 0);
+ assert(n == 7);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "8", &e, 0, 7, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "41", &e, 0, 7, 42) == 0);
+ assert(n == 41);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "42", &e, 0, 7, 42) == 0);
+ assert(n == 42);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2ul(&n, "-1", &e, 0, 0, ULONG_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ul(&n, "0xFFFFffff", &e, 0, 0, ULONG_MAX) == 0);
+ assert(n == 0xFFFFffff);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-0xFFFFffffFFFFffff", &e, 0, 0, ULONG_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "0xFFFFffffFFFFffff9", &e, 0, 0, ULONG_MAX) == -1);
+ assert(n == ULONG_MAX);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ul(&n, "-0xFFFFffffFFFFffff9", &e, 0, 0, ULONG_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ char *e;
+ unsigned long n;
+
+ assert(a2ul(&n, "\n9 fff 7", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2ul(&n, "\n9\t", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2ul(&n, "9 ", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+}
diff --git a/share/tests/a2i.h/a2ul/a2ul.sh b/share/tests/a2i.h/a2ul/a2ul.sh
new file mode 100755
index 0000000..d0806e3
--- /dev/null
+++ b/share/tests/a2i.h/a2ul/a2ul.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/a2ul.c $LIBS;
+"$out";
diff --git a/share/tests/a2i.h/a2ul/a2ul_nobuild.sh b/share/tests/a2i.h/a2ul/a2ul_nobuild.sh
new file mode 100755
index 0000000..3b544dd
--- /dev/null
+++ b/share/tests/a2i.h/a2ul/a2ul_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ long n;
+
+ a2ul(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned int n;
+
+ a2ul(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
diff --git a/share/tests/a2i.h/a2ull/a2ull.c b/share/tests/a2i.h/a2ull/a2ull.c
new file mode 100644
index 0000000..9c9b8b7
--- /dev/null
+++ b/share/tests/a2i.h/a2ull/a2ull.c
@@ -0,0 +1,468 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/a2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ char *e = "unmodified";
+ unsigned long long n;
+
+ assert(a2ull(&n, "x99z", NULL, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ull(&n, "x99z", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2ull(&n, "x99z", NULL, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(a2ull(&n, "x99z", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2ull(&n, "99z", NULL, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(a2ull(&n, "99z", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2ull(&n, "9z", NULL, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(a2ull(&n, "9z", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ errno = 0;
+
+ assert(a2ull(&n, "9", NULL, 0, 7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(a2ull(&n, "9", &e, 0, 7, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_base(void)
+{
+ char *e = "unmodified";
+ unsigned long long n;
+
+ assert(a2ull(&n, "9", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ull(&n, "9", &e, -1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ull(&n, "9", &e, -2, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ull(&n, "9", &e, 37, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ull(&n, "9", &e, 38, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ull(&n, "9", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(a2ull(&n, "", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ull(&n, "foo", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ull(&n, "43", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+ assert(a2ull(&n, "9", &e, 1, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2ull(&n, "9", &e, 1, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == EINVAL);
+ assert(a2ull(&n, "9foo", &e, 1, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ errno = 0;
+
+ assert(a2ull(&n, "11", &e, 0, 2, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "11", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "11", &e, 3, 2, 42) == 0);
+ assert(n == 4);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "11", &e, 35, 2, 42) == 0);
+ assert(n == 36);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "11", &e, 36, 2, 42) == 0);
+ assert(n == 37);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2ull(&n, "0b11", &e, 0, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ull(&n, "0B11", &e, 0, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ull(&n, "-0b11", &e, 0, 2, 42) == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ull(&n, "-0B11", &e, 0, 2, 42) == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "011", &e, 0, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-011", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ull(&n, "11", &e, 0, 2, 42) == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ull(&n, "0x11", &e, 0, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "0X11", &e, 0, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-0x11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-0X11", &e, 0, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+ assert(a2ull(&n, "011", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "11", &e, 2, 2, 42) == 0);
+ assert(n == 3);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2ull(&n, "0b11", NULL, 2, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ull(&n, "0B11", NULL, 2, 2, 42) == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-011", &e, 2, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-11", &e, 2, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ //assert(a2ull(&n, "-0b11", NULL, 2, 2, 42) == -1);
+ //assertn == 2);
+ //assert(errno == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2ull(&n, "-0B11", NULL, 2, 2, 42) == -1);
+ //assertn == 2);
+ //assert(errno == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ull(&n, "011", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "0x11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "0X11", &e, 16, 2, 42) == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-011", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-0x11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-0X11", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+ assert(a2ull(&n, "011", &e, 7, 2, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "11", &e, 7, 2, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-011", &e, 7, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-11", &e, 7, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ull(&n, "011", &e, 8, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "11", &e, 8, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-011", &e, 8, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-11", &e, 8, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ull(&n, "z", &e, 36, 2, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "Z", &e, 36, 2, 42) == 0);
+ assert(n == 35);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-z", &e, 36, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-Z", &e, 36, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ char *e;
+ unsigned long long n;
+
+ assert(a2ull(&n, "", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "foo", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2ull(&n, "foo 7", &e, 0, 0, 42) == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2ull(&n, "", &e, 0, 42, 0) == -1);
+ assert(n == 42);
+ assert(errno == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ errno = 0;
+
+ assert(a2ull(&n, " 9", &e, 0, 2, 42) == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, " \t\na", &e, 16, 2, 42) == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, " \t\n-a", &e, 16, 2, 42) == -1);
+ assert(n == 2);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_range(void)
+{
+ char *e;
+ unsigned long long n;
+
+ assert(a2ull(&n, "5", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "6", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "43", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "44", &e, 0, 7, 42) == -1);
+ assert(n == 42);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2ull(&n, "7", &e, 0, 7, 4) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "42", &e, 0, 7, 4) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2ull(&n, "6z", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2ull(&n, "6 ", &e, 0, 7, 42) == -1);
+ assert(n == 7);
+ assert(errno == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ errno = 0;
+ assert(a2ull(&n, "7", &e, 0, 7, 42) == 0);
+ assert(n == 7);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "8", &e, 0, 7, 42) == 0);
+ assert(n == 8);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "41", &e, 0, 7, 42) == 0);
+ assert(n == 41);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "42", &e, 0, 7, 42) == 0);
+ assert(n == 42);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2ull(&n, "-1", &e, 0, 0, ULLONG_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ errno = 0;
+ assert(a2ull(&n, "0xFFFFffffFFFFffff", &e, 0, 0, ULLONG_MAX) == 0);
+ assert(n == ULLONG_MAX);
+ assert(errno == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-0xFFFFffffFFFFffff", &e, 0, 0, ULLONG_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "0xFFFFffffFFFFffff9", &e, 0, 0, ULLONG_MAX) == -1);
+ assert(n == ULLONG_MAX);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2ull(&n, "-0xFFFFffffFFFFffff9", &e, 0, 0, ULLONG_MAX) == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(strcmp(e, "") == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ char *e;
+ unsigned long long n;
+
+ assert(a2ull(&n, "\n9 fff 7", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2ull(&n, "\n9\t", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2ull(&n, "9 ", &e, 0, 7, 42) == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+}
diff --git a/share/tests/a2i.h/a2ull/a2ull.sh b/share/tests/a2i.h/a2ull/a2ull.sh
new file mode 100755
index 0000000..70c92db
--- /dev/null
+++ b/share/tests/a2i.h/a2ull/a2ull.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/a2ull.c $LIBS;
+"$out";
diff --git a/share/tests/a2i.h/a2ull/a2ull_nobuild.sh b/share/tests/a2i.h/a2ull/a2ull_nobuild.sh
new file mode 100755
index 0000000..5f1c6a8
--- /dev/null
+++ b/share/tests/a2i.h/a2ull/a2ull_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ long long n;
+
+ a2ull(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/a2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ a2ull(&n, "0", NULL, 0, 0, 0);
+ }
+__EOF__
diff --git a/share/tests/str2i.h/str2i/str2i.c b/share/tests/str2i.h/str2i/str2i.c
new file mode 100644
index 0000000..db2d70a
--- /dev/null
+++ b/share/tests/str2i.h/str2i/str2i.c
@@ -0,0 +1,152 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/str2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_base(void)
+{
+ unsigned int n;
+
+ errno = 0;
+
+ assert(str2i(unsigned int, &n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(str2i(unsigned int, &n, "0b11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2i(unsigned int, &n, "0B11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2i(unsigned int, &n, "-0b11") == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(str2i(unsigned int, &n, "-0B11") == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ assert(str2i(unsigned int, &n, "011") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2i(unsigned int, &n, "-011") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2i(unsigned int, &n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(str2i(unsigned int, &n, "-11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2i(unsigned int, &n, "0x11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2i(unsigned int, &n, "0X11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2i(unsigned int, &n, "-0x11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(str2i(unsigned int, &n, "-0X11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_leading_text(void)
+{
+ long long n;
+
+ assert(str2i(long long, &n, "") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2i(long long, &n, "foo") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2i(long long, &n, "foo 7") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+
+ errno = 0;
+
+ assert(str2i(long long, &n, " 1") == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(str2i(long long, &n, " \t\n0xa") == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(str2i(long long, &n, " \t\n-0xa") == 0);
+ assert(n == -10);
+ assert(errno == 0);
+}
+
+
+static void
+test_range(void)
+{
+ unsigned char n;
+
+ assert(str2i(unsigned char, &n, "-1") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2i(unsigned char, &n, "0xFF") == 0);
+ assert(n == 0xFF);
+ assert(errno == 0);
+ assert(str2i(unsigned char, &n, "-0xFF") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(str2i(unsigned char, &n, "0xFF9") == -1);
+ assert(n == UCHAR_MAX);
+ assert(errno == ERANGE);
+ assert(str2i(unsigned char, &n, "-0xFF9") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ short n;
+
+ assert(str2i(short, &n, "\n9 fff 7") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2i(short, &n, "\n9\t") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2i(short, &n, "9 ") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+}
diff --git a/share/tests/str2i.h/str2i/str2i.sh b/share/tests/str2i.h/str2i/str2i.sh
new file mode 100755
index 0000000..e22ff0c
--- /dev/null
+++ b/share/tests/str2i.h/str2i/str2i.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/str2i.c $LIBS;
+"$out";
diff --git a/share/tests/str2i.h/str2i/str2i_nobuild.sh b/share/tests/str2i.h/str2i/str2i_nobuild.sh
new file mode 100755
index 0000000..3645b84
--- /dev/null
+++ b/share/tests/str2i.h/str2i/str2i_nobuild.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected error: [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned char n;
+
+ str2i(signed char, &n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ str2s(unsigned int, &n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- 'error: ._Generic. selector' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected error: '_Generic' selector"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ float n;
+
+ str2i(float, &n, "0");
+ }
+__EOF__
diff --git a/share/tests/str2i.h/str2s/str2s.c b/share/tests/str2i.h/str2s/str2s.c
new file mode 100644
index 0000000..9c302f2
--- /dev/null
+++ b/share/tests/str2i.h/str2s/str2s.c
@@ -0,0 +1,146 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/str2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_base(void)
+{
+ int n;
+
+ errno = 0;
+
+ assert(str2s(int, &n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(str2s(int, &n, "0b11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2s(int, &n, "0B11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2s(int, &n, "-0b11") == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(str2s(int, &n, "-0B11") == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ assert(str2s(int, &n, "011") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2s(int, &n, "-011") == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(str2s(int, &n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(str2s(int, &n, "-11") == 0);
+ assert(n == -11);
+ assert(errno == 0);
+ assert(str2s(int, &n, "0x11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2s(int, &n, "0X11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2s(int, &n, "-0x11") == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(str2s(int, &n, "-0X11") == 0);
+ assert(n == -17);
+ assert(errno == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ long long n;
+
+ assert(str2s(long long, &n, "") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2s(long long, &n, "foo") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2s(long long, &n, "foo 7") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+
+ errno = 0;
+
+ assert(str2s(long long, &n, " 1") == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(str2s(long long, &n, " \t\n0xa") == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(str2s(long long, &n, " \t\n-0xa") == 0);
+ assert(n == -10);
+ assert(errno == 0);
+}
+
+
+static void
+test_range(void)
+{
+ signed char n;
+
+ assert(str2s(signed char, &n, "-1") == 0);
+ assert(n == -1);
+ assert(errno == 0);
+ assert(str2s(signed char, &n, "0x7F") == 0);
+ assert(n == 0x7F);
+ assert(errno == 0);
+ assert(str2s(signed char, &n, "0xFF") == -1);
+ assert(n == SCHAR_MAX);
+ assert(errno == ERANGE);
+ assert(str2s(signed char, &n, "-0xFF") == -1);
+ assert(n == SCHAR_MIN);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ short n;
+
+ assert(str2s(short, &n, "\n9 fff 7") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2s(short, &n, "\n9\t") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2s(short, &n, "9 ") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+}
diff --git a/share/tests/str2i.h/str2s/str2s.sh b/share/tests/str2i.h/str2s/str2s.sh
new file mode 100755
index 0000000..0849100
--- /dev/null
+++ b/share/tests/str2i.h/str2s/str2s.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/str2s.c $LIBS;
+"$out";
diff --git a/share/tests/str2i.h/str2s/str2s_nobuild.sh b/share/tests/str2i.h/str2s/str2s_nobuild.sh
new file mode 100755
index 0000000..c026b34
--- /dev/null
+++ b/share/tests/str2i.h/str2s/str2s_nobuild.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned char n;
+
+ str2s(signed char, &n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ long n;
+
+ str2s(int, &n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- 'static assertion failed' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected static assertion failed"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ str2s(unsigned long, &n, "0");
+ }
+__EOF__
diff --git a/share/tests/str2i.h/str2sh/str2sh.c b/share/tests/str2i.h/str2sh/str2sh.c
new file mode 100644
index 0000000..84b0b88
--- /dev/null
+++ b/share/tests/str2i.h/str2sh/str2sh.c
@@ -0,0 +1,146 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/str2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_base(void)
+{
+ short n;
+
+ errno = 0;
+
+ assert(str2sh(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(str2sh(&n, "0b11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2sh(&n, "0B11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2sh(&n, "-0b11") == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(str2sh(&n, "-0B11") == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ assert(str2sh(&n, "011") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2sh(&n, "-011") == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(str2sh(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(str2sh(&n, "-11") == 0);
+ assert(n == -11);
+ assert(errno == 0);
+ assert(str2sh(&n, "0x11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2sh(&n, "0X11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2sh(&n, "-0x11") == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(str2sh(&n, "-0X11") == 0);
+ assert(n == -17);
+ assert(errno == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ short n;
+
+ assert(str2sh(&n, "") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2sh(&n, "foo") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2sh(&n, "foo 7") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+
+ errno = 0;
+
+ assert(str2sh(&n, " 1") == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(str2sh(&n, " \t\n0xa") == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(str2sh(&n, " \t\n-0xa") == 0);
+ assert(n == -10);
+ assert(errno == 0);
+}
+
+
+static void
+test_range(void)
+{
+ short n;
+
+ assert(str2sh(&n, "-1") == 0);
+ assert(n == -1);
+ assert(errno == 0);
+ assert(str2sh(&n, "0xFFF") == 0);
+ assert(n == 0xFFF);
+ assert(errno == 0);
+ assert(str2sh(&n, "0xFFFF") == -1);
+ assert(n == SHRT_MAX);
+ assert(errno == ERANGE);
+ assert(str2sh(&n, "-0xFFFF") == -1);
+ assert(n == SHRT_MIN);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ short n;
+
+ assert(str2sh(&n, "\n9 fff 7") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2sh(&n, "\n9\t") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2sh(&n, "9 ") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+}
diff --git a/share/tests/str2i.h/str2sh/str2sh.sh b/share/tests/str2i.h/str2sh/str2sh.sh
new file mode 100755
index 0000000..57da282
--- /dev/null
+++ b/share/tests/str2i.h/str2sh/str2sh.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/str2sh.c $LIBS;
+"$out";
diff --git a/share/tests/str2i.h/str2sh/str2sh_nobuild.sh b/share/tests/str2i.h/str2sh/str2sh_nobuild.sh
new file mode 100755
index 0000000..5577bb7
--- /dev/null
+++ b/share/tests/str2i.h/str2sh/str2sh_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned short n;
+
+ str2sh(&n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ long n;
+
+ str2sh(&n, "0");
+ }
+__EOF__
diff --git a/share/tests/str2i.h/str2shh/str2shh.c b/share/tests/str2i.h/str2shh/str2shh.c
new file mode 100644
index 0000000..95b0540
--- /dev/null
+++ b/share/tests/str2i.h/str2shh/str2shh.c
@@ -0,0 +1,146 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/str2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_base(void)
+{
+ signed char n;
+
+ errno = 0;
+
+ assert(str2shh(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(str2shh(&n, "0b11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2shh(&n, "0B11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2shh(&n, "-0b11") == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(str2shh(&n, "-0B11") == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ assert(str2shh(&n, "011") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2shh(&n, "-011") == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(str2shh(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(str2shh(&n, "-11") == 0);
+ assert(n == -11);
+ assert(errno == 0);
+ assert(str2shh(&n, "0x11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2shh(&n, "0X11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2shh(&n, "-0x11") == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(str2shh(&n, "-0X11") == 0);
+ assert(n == -17);
+ assert(errno == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ signed char n;
+
+ assert(str2shh(&n, "") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2shh(&n, "foo") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2shh(&n, "foo 7") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+
+ errno = 0;
+
+ assert(str2shh(&n, " 1") == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(str2shh(&n, " \t\n0xa") == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(str2shh(&n, " \t\n-0xa") == 0);
+ assert(n == -10);
+ assert(errno == 0);
+}
+
+
+static void
+test_range(void)
+{
+ signed char n;
+
+ assert(str2shh(&n, "-1") == 0);
+ assert(n == -1);
+ assert(errno == 0);
+ assert(str2shh(&n, "0x7F") == 0);
+ assert(n == 0x7F);
+ assert(errno == 0);
+ assert(str2shh(&n, "0xFF") == -1);
+ assert(n == SCHAR_MAX);
+ assert(errno == ERANGE);
+ assert(str2shh(&n, "-0xFF") == -1);
+ assert(n == SCHAR_MIN);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ signed char n;
+
+ assert(str2shh(&n, "\n9 fff 7") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2shh(&n, "\n9\t") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2shh(&n, "9 ") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+}
diff --git a/share/tests/str2i.h/str2shh/str2shh.sh b/share/tests/str2i.h/str2shh/str2shh.sh
new file mode 100755
index 0000000..4fc8719
--- /dev/null
+++ b/share/tests/str2i.h/str2shh/str2shh.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/str2shh.c $LIBS;
+"$out";
diff --git a/share/tests/str2i.h/str2shh/str2shh_nobuild.sh b/share/tests/str2i.h/str2shh/str2shh_nobuild.sh
new file mode 100755
index 0000000..ea29e27
--- /dev/null
+++ b/share/tests/str2i.h/str2shh/str2shh_nobuild.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned char n;
+
+ str2shh(&n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ char n;
+
+ str2shh(&n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ long n;
+
+ str2shh(&n, "0");
+ }
+__EOF__
diff --git a/share/tests/str2i.h/str2si/str2si.c b/share/tests/str2i.h/str2si/str2si.c
new file mode 100644
index 0000000..279bd84
--- /dev/null
+++ b/share/tests/str2i.h/str2si/str2si.c
@@ -0,0 +1,146 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/str2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_base(void)
+{
+ int n;
+
+ errno = 0;
+
+ assert(str2si(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(str2si(&n, "0b11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2si(&n, "0B11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2si(&n, "-0b11") == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(str2si(&n, "-0B11") == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ assert(str2si(&n, "011") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2si(&n, "-011") == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(str2si(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(str2si(&n, "-11") == 0);
+ assert(n == -11);
+ assert(errno == 0);
+ assert(str2si(&n, "0x11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2si(&n, "0X11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2si(&n, "-0x11") == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(str2si(&n, "-0X11") == 0);
+ assert(n == -17);
+ assert(errno == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ int n;
+
+ assert(str2si(&n, "") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2si(&n, "foo") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2si(&n, "foo 7") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+
+ errno = 0;
+
+ assert(str2si(&n, " 1") == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(str2si(&n, " \t\n0xa") == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(str2si(&n, " \t\n-0xa") == 0);
+ assert(n == -10);
+ assert(errno == 0);
+}
+
+
+static void
+test_range(void)
+{
+ int n;
+
+ assert(str2si(&n, "-1") == 0);
+ assert(n == -1);
+ assert(errno == 0);
+ assert(str2si(&n, "0xFFF") == 0);
+ assert(n == 0xFFF);
+ assert(errno == 0);
+ assert(str2si(&n, "0xFFFFffffFFFFffff") == -1);
+ assert(n == INT_MAX);
+ assert(errno == ERANGE);
+ assert(str2si(&n, "-0xFFFFffffFFFFffff") == -1);
+ assert(n == INT_MIN);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ int n;
+
+ assert(str2si(&n, "\n9 fff 7") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2si(&n, "\n9\t") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2si(&n, "9 ") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+}
diff --git a/share/tests/str2i.h/str2si/str2si.sh b/share/tests/str2i.h/str2si/str2si.sh
new file mode 100755
index 0000000..582379f
--- /dev/null
+++ b/share/tests/str2i.h/str2si/str2si.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/str2si.c $LIBS;
+"$out";
diff --git a/share/tests/str2i.h/str2si/str2si_nobuild.sh b/share/tests/str2i.h/str2si/str2si_nobuild.sh
new file mode 100755
index 0000000..e25cb44
--- /dev/null
+++ b/share/tests/str2i.h/str2si/str2si_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned int n;
+
+ str2si(&n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ long n;
+
+ str2si(&n, "0");
+ }
+__EOF__
diff --git a/share/tests/str2i.h/str2sl/str2sl.c b/share/tests/str2i.h/str2sl/str2sl.c
new file mode 100644
index 0000000..62f7697
--- /dev/null
+++ b/share/tests/str2i.h/str2sl/str2sl.c
@@ -0,0 +1,146 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/str2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_base(void)
+{
+ long n;
+
+ errno = 0;
+
+ assert(str2sl(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(str2sl(&n, "0b11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2sl(&n, "0B11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2sl(&n, "-0b11") == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(str2sl(&n, "-0B11") == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ assert(str2sl(&n, "011") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2sl(&n, "-011") == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(str2sl(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(str2sl(&n, "-11") == 0);
+ assert(n == -11);
+ assert(errno == 0);
+ assert(str2sl(&n, "0x11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2sl(&n, "0X11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2sl(&n, "-0x11") == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(str2sl(&n, "-0X11") == 0);
+ assert(n == -17);
+ assert(errno == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ long n;
+
+ assert(str2sl(&n, "") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2sl(&n, "foo") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2sl(&n, "foo 7") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+
+ errno = 0;
+
+ assert(str2sl(&n, " 1") == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(str2sl(&n, " \t\n0xa") == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(str2sl(&n, " \t\n-0xa") == 0);
+ assert(n == -10);
+ assert(errno == 0);
+}
+
+
+static void
+test_range(void)
+{
+ long n;
+
+ assert(str2sl(&n, "-1") == 0);
+ assert(n == -1);
+ assert(errno == 0);
+ assert(str2sl(&n, "0xFFFffff") == 0);
+ assert(n == 0xFFFffff);
+ assert(errno == 0);
+ assert(str2sl(&n, "0xFFFFffffFFFFffff") == -1);
+ assert(n == LONG_MAX);
+ assert(errno == ERANGE);
+ assert(str2sl(&n, "-0xFFFFffffFFFFffff") == -1);
+ assert(n == LONG_MIN);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ long n;
+
+ assert(str2sl(&n, "\n9 fff 7") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2sl(&n, "\n9\t") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2sl(&n, "9 ") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+}
diff --git a/share/tests/str2i.h/str2sl/str2sl.sh b/share/tests/str2i.h/str2sl/str2sl.sh
new file mode 100755
index 0000000..a1d12b5
--- /dev/null
+++ b/share/tests/str2i.h/str2sl/str2sl.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/str2sl.c $LIBS;
+"$out";
diff --git a/share/tests/str2i.h/str2sl/str2sl_nobuild.sh b/share/tests/str2i.h/str2sl/str2sl_nobuild.sh
new file mode 100755
index 0000000..8bda94e
--- /dev/null
+++ b/share/tests/str2i.h/str2sl/str2sl_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ str2sl(&n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ int n;
+
+ str2sl(&n, "0");
+ }
+__EOF__
diff --git a/share/tests/str2i.h/str2sll/str2sll.c b/share/tests/str2i.h/str2sll/str2sll.c
new file mode 100644
index 0000000..3cb1d04
--- /dev/null
+++ b/share/tests/str2i.h/str2sll/str2sll.c
@@ -0,0 +1,146 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/str2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_base(void)
+{
+ long long n;
+
+ errno = 0;
+
+ assert(str2sll(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(str2sll(&n, "0b11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2sll(&n, "0B11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2sll(&n, "-0b11") == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ //assert(str2sll(&n, "-0B11") == 0);
+ //assertn == -3);
+ //assert(errno == 0);
+ assert(str2sll(&n, "011") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2sll(&n, "-011") == 0);
+ assert(n == -9);
+ assert(errno == 0);
+ assert(str2sll(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(str2sll(&n, "-11") == 0);
+ assert(n == -11);
+ assert(errno == 0);
+ assert(str2sll(&n, "0x11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2sll(&n, "0X11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2sll(&n, "-0x11") == 0);
+ assert(n == -17);
+ assert(errno == 0);
+ assert(str2sll(&n, "-0X11") == 0);
+ assert(n == -17);
+ assert(errno == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ long long n;
+
+ assert(str2sll(&n, "") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2sll(&n, "foo") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2sll(&n, "foo 7") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+
+ errno = 0;
+
+ assert(str2sll(&n, " 1") == 0);
+ assert(n == 1);
+ assert(errno == 0);
+ assert(str2sll(&n, " \t\n0xa") == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(str2sll(&n, " \t\n-0xa") == 0);
+ assert(n == -10);
+ assert(errno == 0);
+}
+
+
+static void
+test_range(void)
+{
+ long long n;
+
+ assert(str2sll(&n, "-1") == 0);
+ assert(n == -1);
+ assert(errno == 0);
+ assert(str2sll(&n, "0xFFFffffFFFFffff") == 0);
+ assert(n == 0xFFFffffFFFFffff);
+ assert(errno == 0);
+ assert(str2sll(&n, "0xFFFFffffFFFFffff") == -1);
+ assert(n == LLONG_MAX);
+ assert(errno == ERANGE);
+ assert(str2sll(&n, "-0xFFFFffffFFFFffff") == -1);
+ assert(n == LLONG_MIN);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ long long n;
+
+ assert(str2sll(&n, "\n9 fff 7") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2sll(&n, "\n9\t") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2sll(&n, "9 ") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+}
diff --git a/share/tests/str2i.h/str2sll/str2sll.sh b/share/tests/str2i.h/str2sll/str2sll.sh
new file mode 100755
index 0000000..13b6fc5
--- /dev/null
+++ b/share/tests/str2i.h/str2sll/str2sll.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/str2sll.c $LIBS;
+"$out";
diff --git a/share/tests/str2i.h/str2sll/str2sll_nobuild.sh b/share/tests/str2i.h/str2sll/str2sll_nobuild.sh
new file mode 100755
index 0000000..a354c2d
--- /dev/null
+++ b/share/tests/str2i.h/str2sll/str2sll_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long long n;
+
+ str2sll(&n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ long n;
+
+ str2sll(&n, "0");
+ }
+__EOF__
diff --git a/share/tests/str2i.h/str2u/str2u.c b/share/tests/str2i.h/str2u/str2u.c
new file mode 100644
index 0000000..9a227fe
--- /dev/null
+++ b/share/tests/str2i.h/str2u/str2u.c
@@ -0,0 +1,152 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/str2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_base(void)
+{
+ unsigned int n;
+
+ errno = 0;
+
+ assert(str2u(unsigned int, &n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(str2u(unsigned int, &n, "0b11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2u(unsigned int, &n, "0B11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2u(unsigned int, &n, "-0b11") == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(str2u(unsigned int, &n, "-0B11") == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ assert(str2u(unsigned int, &n, "011") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2u(unsigned int, &n, "-011") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2u(unsigned int, &n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(str2u(unsigned int, &n, "-11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2u(unsigned int, &n, "0x11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2u(unsigned int, &n, "0X11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2u(unsigned int, &n, "-0x11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(str2u(unsigned int, &n, "-0X11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_leading_text(void)
+{
+ unsigned long long n;
+
+ assert(str2u(unsigned long long, &n, "") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2u(unsigned long long, &n, "foo") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2u(unsigned long long, &n, "foo 7") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+
+ errno = 0;
+
+ assert(str2u(unsigned long long, &n, " 9") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2u(unsigned long long, &n, " \t\n0xa") == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(str2u(unsigned long long, &n, " \t\n-0xa") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_range(void)
+{
+ unsigned char n;
+
+ assert(str2u(unsigned char, &n, "-1") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2u(unsigned char, &n, "0xFF") == 0);
+ assert(n == 0xFF);
+ assert(errno == 0);
+ assert(str2u(unsigned char, &n, "-0xFF") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(str2u(unsigned char, &n, "0xFF9") == -1);
+ assert(n == UCHAR_MAX);
+ assert(errno == ERANGE);
+ assert(str2u(unsigned char, &n, "-0xFF9") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ unsigned short n;
+
+ assert(str2u(unsigned short, &n, "\n9 fff 7") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2u(unsigned short, &n, "\n9\t") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2u(unsigned short, &n, "9 ") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+}
diff --git a/share/tests/str2i.h/str2u/str2u.sh b/share/tests/str2i.h/str2u/str2u.sh
new file mode 100755
index 0000000..8c60d8e
--- /dev/null
+++ b/share/tests/str2i.h/str2u/str2u.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/str2u.c $LIBS;
+"$out";
diff --git a/share/tests/str2i.h/str2u/str2u_nobuild.sh b/share/tests/str2i.h/str2u/str2u_nobuild.sh
new file mode 100755
index 0000000..0e7a15a
--- /dev/null
+++ b/share/tests/str2i.h/str2u/str2u_nobuild.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ signed char n;
+
+ str2u(unsigned char, &n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ str2u(unsigned int, &n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- 'static assertion failed' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected static assertion failed"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ long n;
+
+ str2u(long, &n, "0");
+ }
+__EOF__
diff --git a/share/tests/str2i.h/str2uh/str2uh.c b/share/tests/str2i.h/str2uh/str2uh.c
new file mode 100644
index 0000000..998a88f
--- /dev/null
+++ b/share/tests/str2i.h/str2uh/str2uh.c
@@ -0,0 +1,152 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/str2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_base(void)
+{
+ unsigned short n;
+
+ errno = 0;
+
+ assert(str2uh(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(str2uh(&n, "0b11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2uh(&n, "0B11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2uh(&n, "-0b11") == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(str2uh(&n, "-0B11") == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ assert(str2uh(&n, "011") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2uh(&n, "-011") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2uh(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(str2uh(&n, "-11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2uh(&n, "0x11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2uh(&n, "0X11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2uh(&n, "-0x11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(str2uh(&n, "-0X11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_leading_text(void)
+{
+ unsigned short n;
+
+ assert(str2uh(&n, "") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2uh(&n, "foo") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2uh(&n, "foo 7") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+
+ errno = 0;
+
+ assert(str2uh(&n, " 9") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2uh(&n, " \t\n0xa") == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(str2uh(&n, " \t\n-0xa") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_range(void)
+{
+ unsigned short n;
+
+ assert(str2uh(&n, "-1") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2uh(&n, "0xFFFF") == 0);
+ assert(n == 0xFFFF);
+ assert(errno == 0);
+ assert(str2uh(&n, "-0xFFFF") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(str2uh(&n, "0xFFFF9") == -1);
+ assert(n == USHRT_MAX);
+ assert(errno == ERANGE);
+ assert(str2uh(&n, "-0xFFFF9") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ unsigned short n;
+
+ assert(str2uh(&n, "\n9 fff 7") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2uh(&n, "\n9\t") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2uh(&n, "9 ") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+}
diff --git a/share/tests/str2i.h/str2uh/str2uh.sh b/share/tests/str2i.h/str2uh/str2uh.sh
new file mode 100755
index 0000000..66bb5ad
--- /dev/null
+++ b/share/tests/str2i.h/str2uh/str2uh.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/str2uh.c $LIBS;
+"$out";
diff --git a/share/tests/str2i.h/str2uh/str2uh_nobuild.sh b/share/tests/str2i.h/str2uh/str2uh_nobuild.sh
new file mode 100755
index 0000000..60ca5a2
--- /dev/null
+++ b/share/tests/str2i.h/str2uh/str2uh_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ short n;
+
+ str2uh(&n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ str2uh(&n, "0");
+ }
+__EOF__
diff --git a/share/tests/str2i.h/str2uhh/str2uhh.c b/share/tests/str2i.h/str2uhh/str2uhh.c
new file mode 100644
index 0000000..f25f99e
--- /dev/null
+++ b/share/tests/str2i.h/str2uhh/str2uhh.c
@@ -0,0 +1,152 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/str2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_base(void)
+{
+ unsigned char n;
+
+ errno = 0;
+
+ assert(str2uhh(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(str2uhh(&n, "0b11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2uhh(&n, "0B11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2uhh(&n, "-0b11") == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(str2uhh(&n, "-0B11") == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ assert(str2uhh(&n, "011") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2uhh(&n, "-011") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2uhh(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(str2uhh(&n, "-11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2uhh(&n, "0x11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2uhh(&n, "0X11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2uhh(&n, "-0x11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(str2uhh(&n, "-0X11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_leading_text(void)
+{
+ unsigned char n;
+
+ assert(str2uhh(&n, "") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2uhh(&n, "foo") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2uhh(&n, "foo 7") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+
+ errno = 0;
+
+ assert(str2uhh(&n, " 9") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2uhh(&n, " \t\n0xa") == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(str2uhh(&n, " \t\n-0xa") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_range(void)
+{
+ unsigned char n;
+
+ assert(str2uhh(&n, "-1") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2uhh(&n, "0xFF") == 0);
+ assert(n == 0xFF);
+ assert(errno == 0);
+ assert(str2uhh(&n, "-0xFF") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(str2uhh(&n, "0xFF9") == -1);
+ assert(n == UCHAR_MAX);
+ assert(errno == ERANGE);
+ assert(str2uhh(&n, "-0xFF9") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ unsigned char n;
+
+ assert(str2uhh(&n, "\n9 fff 7") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2uhh(&n, "\n9\t") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2uhh(&n, "9 ") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+}
diff --git a/share/tests/str2i.h/str2uhh/str2uhh.sh b/share/tests/str2i.h/str2uhh/str2uhh.sh
new file mode 100755
index 0000000..7454d65
--- /dev/null
+++ b/share/tests/str2i.h/str2uhh/str2uhh.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/str2uhh.c $LIBS;
+"$out";
diff --git a/share/tests/str2i.h/str2uhh/str2uhh_nobuild.sh b/share/tests/str2i.h/str2uhh/str2uhh_nobuild.sh
new file mode 100755
index 0000000..d4fd98d
--- /dev/null
+++ b/share/tests/str2i.h/str2uhh/str2uhh_nobuild.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ signed char n;
+
+ str2uhh(&n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ char n;
+
+ str2uhh(&n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ str2uhh(&n, "0");
+ }
+__EOF__
diff --git a/share/tests/str2i.h/str2ui/str2ui.c b/share/tests/str2i.h/str2ui/str2ui.c
new file mode 100644
index 0000000..ca2c740
--- /dev/null
+++ b/share/tests/str2i.h/str2ui/str2ui.c
@@ -0,0 +1,152 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/str2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_base(void)
+{
+ unsigned int n;
+
+ errno = 0;
+
+ assert(str2ui(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(str2ui(&n, "0b11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2ui(&n, "0B11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2ui(&n, "-0b11") == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(str2ui(&n, "-0B11") == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ assert(str2ui(&n, "011") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2ui(&n, "-011") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2ui(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(str2ui(&n, "-11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2ui(&n, "0x11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2ui(&n, "0X11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2ui(&n, "-0x11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(str2ui(&n, "-0X11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_leading_text(void)
+{
+ unsigned int n;
+
+ assert(str2ui(&n, "") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2ui(&n, "foo") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2ui(&n, "foo 7") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+
+ errno = 0;
+
+ assert(str2ui(&n, " 9") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2ui(&n, " \t\n0xa") == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(str2ui(&n, " \t\n-0xa") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_range(void)
+{
+ unsigned int n;
+
+ assert(str2ui(&n, "-1") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2ui(&n, "0xFFFF") == 0);
+ assert(n == 0xFFFF);
+ assert(errno == 0);
+ assert(str2ui(&n, "-0xFFFFffffFFFFffff") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(str2ui(&n, "0xFFFFffffFFFFffff9") == -1);
+ assert(n == UINT_MAX);
+ assert(errno == ERANGE);
+ assert(str2ui(&n, "-0xFFFFffffFFFFffff9") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ unsigned int n;
+
+ assert(str2ui(&n, "\n9 fff 7") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2ui(&n, "\n9\t") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2ui(&n, "9 ") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+}
diff --git a/share/tests/str2i.h/str2ui/str2ui.sh b/share/tests/str2i.h/str2ui/str2ui.sh
new file mode 100755
index 0000000..3bc1669
--- /dev/null
+++ b/share/tests/str2i.h/str2ui/str2ui.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/str2ui.c $LIBS;
+"$out";
diff --git a/share/tests/str2i.h/str2ui/str2ui_nobuild.sh b/share/tests/str2i.h/str2ui/str2ui_nobuild.sh
new file mode 100755
index 0000000..60add18
--- /dev/null
+++ b/share/tests/str2i.h/str2ui/str2ui_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ int n;
+
+ str2ui(&n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ str2ui(&n, "0");
+ }
+__EOF__
diff --git a/share/tests/str2i.h/str2ul/str2ul.c b/share/tests/str2i.h/str2ul/str2ul.c
new file mode 100644
index 0000000..5b8f1c3
--- /dev/null
+++ b/share/tests/str2i.h/str2ul/str2ul.c
@@ -0,0 +1,152 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/str2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_base(void)
+{
+ unsigned long n;
+
+ errno = 0;
+
+ assert(str2ul(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(str2ul(&n, "0b11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2ul(&n, "0B11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2ul(&n, "-0b11") == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(str2ul(&n, "-0B11") == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ assert(str2ul(&n, "011") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2ul(&n, "-011") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2ul(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(str2ul(&n, "-11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2ul(&n, "0x11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2ul(&n, "0X11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2ul(&n, "-0x11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(str2ul(&n, "-0X11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_leading_text(void)
+{
+ unsigned long n;
+
+ assert(str2ul(&n, "") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2ul(&n, "foo") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2ul(&n, "foo 7") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+
+ errno = 0;
+
+ assert(str2ul(&n, " 9") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2ul(&n, " \t\n0xa") == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(str2ul(&n, " \t\n-0xa") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_range(void)
+{
+ unsigned long n;
+
+ assert(str2ul(&n, "-1") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2ul(&n, "0xFFFFffff") == 0);
+ assert(n == 0xFFFFffff);
+ assert(errno == 0);
+ assert(str2ul(&n, "-0xFFFFffffFFFFffff") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(str2ul(&n, "0xFFFFffffFFFFffff9") == -1);
+ assert(n == ULONG_MAX);
+ assert(errno == ERANGE);
+ assert(str2ul(&n, "-0xFFFFffffFFFFffff9") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ unsigned long n;
+
+ assert(str2ul(&n, "\n9 fff 7") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2ul(&n, "\n9\t") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2ul(&n, "9 ") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+}
diff --git a/share/tests/str2i.h/str2ul/str2ul.sh b/share/tests/str2i.h/str2ul/str2ul.sh
new file mode 100755
index 0000000..8ca5b06
--- /dev/null
+++ b/share/tests/str2i.h/str2ul/str2ul.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/str2ul.c $LIBS;
+"$out";
diff --git a/share/tests/str2i.h/str2ul/str2ul_nobuild.sh b/share/tests/str2i.h/str2ul/str2ul_nobuild.sh
new file mode 100755
index 0000000..ce29ec0
--- /dev/null
+++ b/share/tests/str2i.h/str2ul/str2ul_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ long n;
+
+ str2ul(&n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned int n;
+
+ str2ul(&n, "0");
+ }
+__EOF__
diff --git a/share/tests/str2i.h/str2ull/str2ull.c b/share/tests/str2i.h/str2ull/str2ull.c
new file mode 100644
index 0000000..9c6d7cf
--- /dev/null
+++ b/share/tests/str2i.h/str2ull/str2ull.c
@@ -0,0 +1,152 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/str2i.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_base(void)
+{
+ unsigned long long n;
+
+ errno = 0;
+
+ assert(str2ull(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(str2ull(&n, "0b11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2ull(&n, "0B11") == 0);
+ //assertn == 3);
+ //assert(errno == 0);
+ //assert(str2ull(&n, "-0b11") == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ //assert(str2ull(&n, "-0B11") == 0);
+ //assertn == 2);
+ //assert(errno == 0);
+ assert(str2ull(&n, "011") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2ull(&n, "-011") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2ull(&n, "11") == 0);
+ assert(n == 11);
+ assert(errno == 0);
+ assert(str2ull(&n, "-11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2ull(&n, "0x11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2ull(&n, "0X11") == 0);
+ assert(n == 17);
+ assert(errno == 0);
+ assert(str2ull(&n, "-0x11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(str2ull(&n, "-0X11") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_leading_text(void)
+{
+ unsigned long long n;
+
+ assert(str2ull(&n, "") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2ull(&n, "foo") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+ assert(str2ull(&n, "foo 7") == -1);
+ assert(n == 0);
+ assert(errno == ECANCELED);
+
+ errno = 0;
+
+ assert(str2ull(&n, " 9") == 0);
+ assert(n == 9);
+ assert(errno == 0);
+ assert(str2ull(&n, " \t\n0xa") == 0);
+ assert(n == 10);
+ assert(errno == 0);
+ assert(str2ull(&n, " \t\n-0xa") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_range(void)
+{
+ unsigned long long n;
+
+ assert(str2ull(&n, "-1") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ errno = 0;
+ assert(str2ull(&n, "0xFFFFffffFFFFffff") == 0);
+ assert(n == ULLONG_MAX);
+ assert(errno == 0);
+ assert(str2ull(&n, "-0xFFFFffffFFFFffff") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+ assert(str2ull(&n, "0xFFFFffffFFFFffff9") == -1);
+ assert(n == ULLONG_MAX);
+ assert(errno == ERANGE);
+ assert(str2ull(&n, "-0xFFFFffffFFFFffff9") == -1);
+ assert(n == 0);
+ assert(errno == ERANGE);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ unsigned long long n;
+
+ assert(str2ull(&n, "\n9 fff 7") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2ull(&n, "\n9\t") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+ assert(str2ull(&n, "9 ") == -1);
+ assert(n == 9);
+ assert(errno == ENOTSUP);
+}
diff --git a/share/tests/str2i.h/str2ull/str2ull.sh b/share/tests/str2i.h/str2ull/str2ull.sh
new file mode 100755
index 0000000..bcc4a98
--- /dev/null
+++ b/share/tests/str2i.h/str2ull/str2ull.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/str2ull.c $LIBS;
+"$out";
diff --git a/share/tests/str2i.h/str2ull/str2ull_nobuild.sh b/share/tests/str2i.h/str2ull/str2ull_nobuild.sh
new file mode 100755
index 0000000..9bb0eb2
--- /dev/null
+++ b/share/tests/str2i.h/str2ull/str2ull_nobuild.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/bash
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+
+set -Eeuf;
+
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=pointer-sign' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=pointer-sign]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ long long n;
+
+ str2ull(&n, "0");
+ }
+__EOF__
+
+
+cc $CFLAGS -o "$out" -x c - $LIBS 2>&1 <<__EOF__ \
+| if ! grep -- '-Werror=incompatible-pointer-types' >/dev/null; then \
+ >&2 printf '%s\n' "$0:$LINENO: Expected [-Werror=incompatible-pointer-types]"; \
+ exit 1; \
+else \
+ true; \
+fi;
+ #include <a2i/str2i.h>
+
+ int
+ main(void)
+ {
+ unsigned long n;
+
+ str2ull(&n, "0");
+ }
+__EOF__
diff --git a/share/tests/strtoi.h/strtoi/strtoi.c b/share/tests/strtoi.h/strtoi/strtoi.c
new file mode 100644
index 0000000..fd40689
--- /dev/null
+++ b/share/tests/strtoi.h/strtoi/strtoi.c
@@ -0,0 +1,387 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/strtoi.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ int s;
+ char *e = "unmodified";
+
+ errno = 0;
+
+ assert(a2i_strtoi("x99z", NULL, 1, -7, 42, NULL) == 0);
+ assert(a2i_strtoi("x99z", &e, 1, -7, 42, NULL) == 0);
+ assert(a2i_strtoi("x99z", NULL, 1, -7, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtoi("x99z", &e, 1, -7, 42, &s) == 0);
+ assert(s == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2i_strtoi("x99z", NULL, 0, -7, 42, NULL) == 0);
+ assert(a2i_strtoi("x99z", &e, 0, -7, 42, NULL) == 0);
+ assert(strcmp(e, "x99z") == 0);
+ assert(a2i_strtoi("x99z", NULL, 0, -7, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(a2i_strtoi("x99z", &e, 0, -7, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2i_strtoi("99z", NULL, 0, -7, 42, NULL) == 42);
+ assert(a2i_strtoi("99z", &e, 0, -7, 42, NULL) == 42);
+ assert(strcmp(e, "z") == 0);
+ assert(a2i_strtoi("99z", NULL, 0, -7, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(a2i_strtoi("99z", &e, 0, -7, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2i_strtoi("9z", NULL, 0, -7, 42, NULL) == 9);
+ assert(a2i_strtoi("9z", &e, 0, -7, 42, NULL) == 9);
+ assert(strcmp(e, "z") == 0);
+ assert(a2i_strtoi("9z", NULL, 0, -7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(a2i_strtoi("9z", &e, 0, -7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2i_strtoi("9", NULL, 0, -7, 42, NULL) == 9);
+ assert(a2i_strtoi("9", &e, 0, -7, 42, NULL) == 9);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("9", NULL, 0, -7, 42, &s) == 9);
+ assert(s == 0);
+ assert(a2i_strtoi("9", &e, 0, -7, 42, &s) == 9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(errno == 0);
+}
+
+
+static void
+test_base(void)
+{
+ int s;
+ char *e = "unmodified";
+
+ errno = 0;
+
+ assert(a2i_strtoi("1", &e, 1, -42, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtoi("1", &e, -1, -42, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtoi("1", &e, -2, -42, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtoi("1", &e, 37, -42, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtoi("1", &e, 38, -42, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtoi("1", &e, 1, -42, 42, &s) == 0);
+ assert(s == EINVAL);
+
+ assert(a2i_strtoi("", &e, 1, -42, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtoi("foo", &e, 1, -42, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtoi("43", &e, 1, -42, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtoi("1", &e, 1, -42, -7, &s) == -7);
+ assert(s == EINVAL);
+ assert(a2i_strtoi("1", &e, 1, 42, -42, &s) == 42);
+ assert(s == EINVAL);
+ assert(a2i_strtoi("4foo", &e, 1, -42, 42, &s) == 0);
+ assert(s == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2i_strtoi("1", &e, 0, -42, 42, &s) == 1);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("1", &e, 2, -42, 42, &s) == 1);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("1", &e, 3, -42, 42, &s) == 1);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("1", &e, 35, -42, 42, &s) == 1);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("1", &e, 36, -42, 42, &s) == 1);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2i_strtoi("0b11", &e, 0, -42, 42, &s) == 3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtoi("0B11", &e, 0, -42, 42, &s) == 3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtoi("-0b11", &e, 0, -42, 42, &s) == -3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtoi("-0B11", &e, 0, -42, 42, &s) == -3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("011", &e, 0, -42, 42, &s) == 9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-011", &e, 0, -42, 42, &s) == -9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("11", &e, 0, -42, 42, &s) == 11);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-11", &e, 0, -42, 42, &s) == -11);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("0x11", &e, 0, -42, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("0X11", &e, 0, -42, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-0x11", &e, 0, -42, 42, &s) == -17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-0X11", &e, 0, -42, 42, &s) == -17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtoi("011", &e, 2, -42, 42, &s) == 3);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("11", &e, 2, -42, 42, &s) == 3);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2i_strtoi("0b11", NULL, 2, -42, 42, &s) == 3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtoi("0B11", NULL, 2, -42, 42, &s) == 3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-011", &e, 2, -42, 42, &s) == -3);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-11", &e, 2, -42, 42, &s) == -3);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2i_strtoi("-0b11", NULL, 2, -42, 42, &s) == -3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtoi("-0B11", NULL, 2, -42, 42, &s) == -3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("011", &e, 16, -42, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("11", &e, 16, -42, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("0x11", &e, 16, -42, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("0X11", &e, 16, -42, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-011", &e, 16, -42, 42, &s) == -17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-11", &e, 16, -42, 42, &s) == -17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-0x11", &e, 16, -42, 42, &s) == -17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-0X11", &e, 16, -42, 42, &s) == -17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtoi("011", &e, 7, -42, 42, &s) == 8);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("11", &e, 7, -42, 42, &s) == 8);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-011", &e, 7, -42, 42, &s) == -8);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-11", &e, 7, -42, 42, &s) == -8);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("011", &e, 8, -42, 42, &s) == 9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("11", &e, 8, -42, 42, &s) == 9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-011", &e, 8, -42, 42, &s) == -9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-11", &e, 8, -42, 42, &s) == -9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("z", &e, 36, -42, 42, &s) == 35);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("Z", &e, 36, -42, 42, &s) == 35);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-z", &e, 36, -42, 42, &s) == -35);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-Z", &e, 36, -42, 42, &s) == -35);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(errno == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ int s;
+ char *e;
+
+ errno = 0;
+
+ assert(a2i_strtoi("", &e, 0, -42, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("foo", &e, 0, -42, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2i_strtoi("foo 7", &e, 0, -42, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2i_strtoi("", &e, 0, 42, -42, &s) == 42);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtoi(" 1", &e, 0, -42, 42, &s) == 1);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi(" \t\na", &e, 16, -42, 42, &s) == 10);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi(" \t\n-a", &e, 16, -42, 42, &s) == -10);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(errno == 0);
+}
+
+
+static void
+test_range(void)
+{
+ int s;
+ char *e;
+
+ errno = 0;
+
+ assert(a2i_strtoi("-9", &e, 0, -7, 42, &s) == -7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-8", &e, 0, -7, 42, &s) == -7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("43", &e, 0, -7, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("44", &e, 0, -7, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtoi("7", &e, 0, 7, -42, &s) == 7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("42", &e, 0, 7, -42, &s) == 7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtoi("-9z", &e, 0, -7, 42, &s) == -7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2i_strtoi("-9 ", &e, 0, -7, 42, &s) == -7);
+ assert(s == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ assert(a2i_strtoi("-7", &e, 0, -7, 42, &s) == -7);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-6", &e, 0, -7, 42, &s) == -6);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("41", &e, 0, -7, 42, &s) == 41);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("42", &e, 0, -7, 42, &s) == 42);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtoi("-1", &e, 0, INTMAX_MIN, INTMAX_MAX, &s) == -1);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("0xFFFFffffFFFFffff", &e, 0, INTMAX_MIN, INTMAX_MAX, &s) == INTMAX_MAX);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtoi("-0xFFFFffffFFFFffff", &e, 0, INTMAX_MIN, INTMAX_MAX, &s) == INTMAX_MIN);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(errno == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ int s;
+ char *e;
+
+ errno = 0;
+
+ assert(a2i_strtoi("\n9 fff 7", &e, 0, -7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2i_strtoi("\n9\t", &e, 0, -7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2i_strtoi("9 ", &e, 0, -7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+
+ assert(errno == 0);
+}
diff --git a/share/tests/strtoi.h/strtoi/strtoi.sh b/share/tests/strtoi.h/strtoi/strtoi.sh
new file mode 100755
index 0000000..b2199bd
--- /dev/null
+++ b/share/tests/strtoi.h/strtoi/strtoi.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/strtoi.c $LIBS;
+"$out";
diff --git a/share/tests/strtoi.h/strtou/strtou.c b/share/tests/strtoi.h/strtou/strtou.c
new file mode 100644
index 0000000..7d5cd51
--- /dev/null
+++ b/share/tests/strtoi.h/strtou/strtou.c
@@ -0,0 +1,393 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/strtoi.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ int s;
+ char *e = "unmodified";
+
+ errno = 0;
+
+ assert(a2i_strtou("x99z", NULL, 1, 0, 42, NULL) == 0);
+ assert(a2i_strtou("x99z", &e, 1, 0, 42, NULL) == 0);
+ assert(a2i_strtou("x99z", NULL, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou("x99z", &e, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2i_strtou("x99z", NULL, 0, 0, 42, NULL) == 0);
+ assert(a2i_strtou("x99z", &e, 0, 0, 42, NULL) == 0);
+ assert(strcmp(e, "x99z") == 0);
+ assert(a2i_strtou("x99z", NULL, 0, 0, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(a2i_strtou("x99z", &e, 0, 0, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2i_strtou("99z", NULL, 0, 7, 42, NULL) == 42);
+ assert(a2i_strtou("99z", &e, 0, 7, 42, NULL) == 42);
+ assert(strcmp(e, "z") == 0);
+ assert(a2i_strtou("99z", NULL, 0, 7, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(a2i_strtou("99z", &e, 0, 7, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2i_strtou("9z", NULL, 0, 7, 42, NULL) == 9);
+ assert(a2i_strtou("9z", &e, 0, 7, 42, NULL) == 9);
+ assert(strcmp(e, "z") == 0);
+ assert(a2i_strtou("9z", NULL, 0, 7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(a2i_strtou("9z", &e, 0, 7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2i_strtou("9", NULL, 0, 7, 42, NULL) == 9);
+ assert(a2i_strtou("9", &e, 0, 7, 42, NULL) == 9);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("9", NULL, 0, 7, 42, &s) == 9);
+ assert(s == 0);
+ assert(a2i_strtou("9", &e, 0, 7, 42, &s) == 9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(errno == 0);
+}
+
+
+static void
+test_base(void)
+{
+ int s;
+ char *e = "unmodified";
+
+ errno = 0;
+
+ assert(a2i_strtou("9", &e, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou("9", &e, -1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou("9", &e, -2, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou("9", &e, 37, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou("9", &e, 38, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou("9", &e, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+
+ assert(a2i_strtou("", &e, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou("foo", &e, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou("43", &e, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou("9", &e, 1, 42, 0, &s) == 42);
+ assert(s == EINVAL);
+ assert(a2i_strtou("9", &e, 1, 42, 0, &s) == 42);
+ assert(s == EINVAL);
+ assert(a2i_strtou("9foo", &e, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2i_strtou("11", &e, 0, 2, 42, &s) == 11);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("11", &e, 2, 2, 42, &s) == 3);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("11", &e, 3, 2, 42, &s) == 4);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("11", &e, 35, 2, 42, &s) == 36);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("11", &e, 36, 2, 42, &s) == 37);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2i_strtou("0b11", &e, 0, 2, 42, &s) == 3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtou("0B11", &e, 0, 2, 42, &s) == 3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtou("-0b11", &e, 0, 2, 42, &s) == 42);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtou("-0B11", &e, 0, 2, 42, &s) == 42);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("011", &e, 0, 2, 42, &s) == 9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-011", &e, 0, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("11", &e, 0, 2, 42, &s) == 11);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-11", &e, 0, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("0x11", &e, 0, 2, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("0X11", &e, 0, 2, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-0x11", &e, 0, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-0X11", &e, 0, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtou("011", &e, 2, 2, 42, &s) == 3);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("11", &e, 2, 2, 42, &s) == 3);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2i_strtou("0b11", NULL, 2, 2, 42, &s) == 3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtou("0B11", NULL, 2, 2, 42, &s) == 3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-011", &e, 2, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-11", &e, 2, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ //assert(a2i_strtou("-0b11", NULL, 2, 2, 42, &s) == 42);
+ //assert(s == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtou("-0B11", NULL, 2, 2, 42, &s) == 42);
+ //assert(s == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("011", &e, 16, 2, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("11", &e, 16, 2, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("0x11", &e, 16, 2, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("0X11", &e, 16, 2, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-011", &e, 16, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-11", &e, 16, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-0x11", &e, 16, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-0X11", &e, 16, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtou("011", &e, 7, 2, 42, &s) == 8);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("11", &e, 7, 2, 42, &s) == 8);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-011", &e, 7, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-11", &e, 7, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("011", &e, 8, 2, 42, &s) == 9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("11", &e, 8, 2, 42, &s) == 9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-011", &e, 8, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-11", &e, 8, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("z", &e, 36, 2, 42, &s) == 35);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("Z", &e, 36, 2, 42, &s) == 35);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-z", &e, 36, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-Z", &e, 36, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(errno == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ int s;
+ char *e;
+
+ errno = 0;
+
+ assert(a2i_strtou("", &e, 0, 0, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("foo", &e, 0, 0, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2i_strtou("foo 7", &e, 0, 0, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2i_strtou("", &e, 0, 42, 0, &s) == 42);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtou(" 9", &e, 0, 2, 42, &s) == 9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou(" \t\na", &e, 16, 2, 42, &s) == 10);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou(" \t\n-a", &e, 16, 2, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(errno == 0);
+}
+
+
+static void
+test_range(void)
+{
+ int s;
+ char *e;
+
+ errno = 0;
+
+ assert(a2i_strtou("5", &e, 0, 7, 42, &s) == 7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("6", &e, 0, 7, 42, &s) == 7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("43", &e, 0, 7, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("44", &e, 0, 7, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtou("7", &e, 0, 7, 4, &s) == 7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("42", &e, 0, 7, 4, &s) == 7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtou("6z", &e, 0, 7, 42, &s) == 7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2i_strtou("6 ", &e, 0, 7, 42, &s) == 7);
+ assert(s == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ assert(a2i_strtou("7", &e, 0, 7, 42, &s) == 7);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("8", &e, 0, 7, 42, &s) == 8);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("41", &e, 0, 7, 42, &s) == 41);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("42", &e, 0, 7, 42, &s) == 42);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtou("-1", &e, 0, 0, UINTMAX_MAX, &s) == UINTMAX_MAX);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("0xFFFFffffFFFFffff", &e, 0, 0, UINTMAX_MAX, &s) == UINTMAX_MAX);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-0xFFFFffffFFFFffff", &e, 0, 0, UINTMAX_MAX, &s) == 1);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("0xFFFFffffFFFFffff9", &e, 0, 0, UINTMAX_MAX, &s) == UINTMAX_MAX);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou("-0xFFFFffffFFFFffff9", &e, 0, 0, UINTMAX_MAX, &s) == UINTMAX_MAX);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(errno == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ int s;
+ char *e;
+
+ errno = 0;
+
+ assert(a2i_strtou("\n9 fff 7", &e, 0, 7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2i_strtou("\n9\t", &e, 0, 7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2i_strtou("9 ", &e, 0, 7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+
+ assert(errno == 0);
+}
diff --git a/share/tests/strtoi.h/strtou/strtou.sh b/share/tests/strtoi.h/strtou/strtou.sh
new file mode 100755
index 0000000..7ddab58
--- /dev/null
+++ b/share/tests/strtoi.h/strtou/strtou.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/strtou.c $LIBS;
+"$out";
diff --git a/share/tests/strtoi.h/strtou_noneg/strtou_noneg.c b/share/tests/strtoi.h/strtou_noneg/strtou_noneg.c
new file mode 100644
index 0000000..17cbfea
--- /dev/null
+++ b/share/tests/strtoi.h/strtou_noneg/strtou_noneg.c
@@ -0,0 +1,393 @@
+// SPDX-FileCopyrightText: 2024, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+
+
+#include <a2i/strtoi.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+
+static void test_null(void);
+static void test_base(void);
+static void test_leading_text(void);
+static void test_range(void);
+static void test_trailing_text(void);
+
+
+int
+main(void)
+{
+ test_null();
+ test_base();
+ test_leading_text();
+ test_range();
+ test_trailing_text();
+}
+
+
+static void
+test_null(void)
+{
+ int s;
+ char *e = "unmodified";
+
+ errno = 0;
+
+ assert(a2i_strtou_noneg("x99z", NULL, 1, 0, 42, NULL) == 0);
+ assert(a2i_strtou_noneg("x99z", &e, 1, 0, 42, NULL) == 0);
+ assert(a2i_strtou_noneg("x99z", NULL, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou_noneg("x99z", &e, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2i_strtou_noneg("x99z", NULL, 0, 0, 42, NULL) == 0);
+ assert(a2i_strtou_noneg("x99z", &e, 0, 0, 42, NULL) == 0);
+ assert(strcmp(e, "x99z") == 0);
+ assert(a2i_strtou_noneg("x99z", NULL, 0, 0, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(a2i_strtou_noneg("x99z", &e, 0, 0, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "x99z") == 0);
+
+ assert(a2i_strtou_noneg("99z", NULL, 0, 7, 42, NULL) == 42);
+ assert(a2i_strtou_noneg("99z", &e, 0, 7, 42, NULL) == 42);
+ assert(strcmp(e, "z") == 0);
+ assert(a2i_strtou_noneg("99z", NULL, 0, 7, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(a2i_strtou_noneg("99z", &e, 0, 7, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2i_strtou_noneg("9z", NULL, 0, 7, 42, NULL) == 9);
+ assert(a2i_strtou_noneg("9z", &e, 0, 7, 42, NULL) == 9);
+ assert(strcmp(e, "z") == 0);
+ assert(a2i_strtou_noneg("9z", NULL, 0, 7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(a2i_strtou_noneg("9z", &e, 0, 7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(strcmp(e, "z") == 0);
+
+ assert(a2i_strtou_noneg("9", NULL, 0, 7, 42, NULL) == 9);
+ assert(a2i_strtou_noneg("9", &e, 0, 7, 42, NULL) == 9);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("9", NULL, 0, 7, 42, &s) == 9);
+ assert(s == 0);
+ assert(a2i_strtou_noneg("9", &e, 0, 7, 42, &s) == 9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(errno == 0);
+}
+
+
+static void
+test_base(void)
+{
+ int s;
+ char *e = "unmodified";
+
+ errno = 0;
+
+ assert(a2i_strtou_noneg("9", &e, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou_noneg("9", &e, -1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou_noneg("9", &e, -2, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou_noneg("9", &e, 37, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou_noneg("9", &e, 38, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou_noneg("9", &e, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+
+ assert(a2i_strtou_noneg("", &e, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou_noneg("foo", &e, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou_noneg("43", &e, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+ assert(a2i_strtou_noneg("9", &e, 1, 42, 0, &s) == 42);
+ assert(s == EINVAL);
+ assert(a2i_strtou_noneg("9", &e, 1, 42, 0, &s) == 42);
+ assert(s == EINVAL);
+ assert(a2i_strtou_noneg("9foo", &e, 1, 0, 42, &s) == 0);
+ assert(s == EINVAL);
+
+ assert(strcmp(e, "unmodified") == 0);
+
+ assert(a2i_strtou_noneg("11", &e, 0, 2, 42, &s) == 11);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("11", &e, 2, 2, 42, &s) == 3);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("11", &e, 3, 2, 42, &s) == 4);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("11", &e, 35, 2, 42, &s) == 36);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("11", &e, 36, 2, 42, &s) == 37);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+
+ // Binary with "0b" depends on libc support.
+ //assert(a2i_strtou_noneg("0b11", &e, 0, 2, 42, &s) == 3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtou_noneg("0B11", &e, 0, 2, 42, &s) == 3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtou_noneg("-0b11", &e, 0, 2, 42, &s) == 2);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtou_noneg("-0B11", &e, 0, 2, 42, &s) == 2);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("011", &e, 0, 2, 42, &s) == 9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-011", &e, 0, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("11", &e, 0, 2, 42, &s) == 11);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-11", &e, 0, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("0x11", &e, 0, 2, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("0X11", &e, 0, 2, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-0x11", &e, 0, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-0X11", &e, 0, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtou_noneg("011", &e, 2, 2, 42, &s) == 3);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("11", &e, 2, 2, 42, &s) == 3);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ //assert(a2i_strtou_noneg("0b11", NULL, 2, 2, 42, &s) == 3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtou_noneg("0B11", NULL, 2, 2, 42, &s) == 3);
+ //assert(s == 0);
+ //assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-011", &e, 2, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-11", &e, 2, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ //assert(a2i_strtou_noneg("-0b11", NULL, 2, 2, 42, &s) == 2);
+ //assert(s == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ //assert(a2i_strtou_noneg("-0B11", NULL, 2, 2, 42, &s) == 2);
+ //assert(s == ERANGE);
+ //assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("011", &e, 16, 2, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("11", &e, 16, 2, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("0x11", &e, 16, 2, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("0X11", &e, 16, 2, 42, &s) == 17);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-011", &e, 16, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-11", &e, 16, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-0x11", &e, 16, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-0X11", &e, 16, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtou_noneg("011", &e, 7, 2, 42, &s) == 8);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("11", &e, 7, 2, 42, &s) == 8);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-011", &e, 7, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-11", &e, 7, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("011", &e, 8, 2, 42, &s) == 9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("11", &e, 8, 2, 42, &s) == 9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-011", &e, 8, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-11", &e, 8, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("z", &e, 36, 2, 42, &s) == 35);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("Z", &e, 36, 2, 42, &s) == 35);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-z", &e, 36, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-Z", &e, 36, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(errno == 0);
+}
+
+
+static void
+test_leading_text(void)
+{
+ int s;
+ char *e;
+
+ errno = 0;
+
+ assert(a2i_strtou_noneg("", &e, 0, 0, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("foo", &e, 0, 0, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "foo") == 0);
+ assert(a2i_strtou_noneg("foo 7", &e, 0, 0, 42, &s) == 0);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "foo 7") == 0);
+ assert(a2i_strtou_noneg("", &e, 0, 42, 0, &s) == 42);
+ assert(s == ECANCELED);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtou_noneg(" 9", &e, 0, 2, 42, &s) == 9);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg(" \t\na", &e, 16, 2, 42, &s) == 10);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg(" \t\n-a", &e, 16, 2, 42, &s) == 2);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(errno == 0);
+}
+
+
+static void
+test_range(void)
+{
+ int s;
+ char *e;
+
+ errno = 0;
+
+ assert(a2i_strtou_noneg("5", &e, 0, 7, 42, &s) == 7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("6", &e, 0, 7, 42, &s) == 7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("43", &e, 0, 7, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("44", &e, 0, 7, 42, &s) == 42);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtou_noneg("7", &e, 0, 7, 4, &s) == 7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("42", &e, 0, 7, 4, &s) == 7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtou_noneg("6z", &e, 0, 7, 42, &s) == 7);
+ assert(s == ERANGE);
+ assert(strcmp(e, "z") == 0);
+ assert(a2i_strtou_noneg("6 ", &e, 0, 7, 42, &s) == 7);
+ assert(s == ERANGE);
+ assert(strcmp(e, " ") == 0);
+
+ assert(a2i_strtou_noneg("7", &e, 0, 7, 42, &s) == 7);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("8", &e, 0, 7, 42, &s) == 8);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("41", &e, 0, 7, 42, &s) == 41);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("42", &e, 0, 7, 42, &s) == 42);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+
+ assert(a2i_strtou_noneg("-1", &e, 0, 0, UINTMAX_MAX, &s) == 0);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("0xFFFFffffFFFFffff", &e, 0, 0, UINTMAX_MAX, &s) == UINTMAX_MAX);
+ assert(s == 0);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-0xFFFFffffFFFFffff", &e, 0, 0, UINTMAX_MAX, &s) == 0);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("0xFFFFffffFFFFffff9", &e, 0, 0, UINTMAX_MAX, &s) == UINTMAX_MAX);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+ assert(a2i_strtou_noneg("-0xFFFFffffFFFFffff9", &e, 0, 0, UINTMAX_MAX, &s) == 0);
+ assert(s == ERANGE);
+ assert(strcmp(e, "") == 0);
+
+ assert(errno == 0);
+}
+
+
+static void
+test_trailing_text(void)
+{
+ int s;
+ char *e;
+
+ errno = 0;
+
+ assert(a2i_strtou_noneg("\n9 fff 7", &e, 0, 7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(strcmp(e, " fff 7") == 0);
+ assert(a2i_strtou_noneg("\n9\t", &e, 0, 7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(strcmp(e, "\t") == 0);
+ assert(a2i_strtou_noneg("9 ", &e, 0, 7, 42, &s) == 9);
+ assert(s == ENOTSUP);
+ assert(strcmp(e, " ") == 0);
+
+ assert(errno == 0);
+}
diff --git a/share/tests/strtoi.h/strtou_noneg/strtou_noneg.sh b/share/tests/strtoi.h/strtou_noneg/strtou_noneg.sh
new file mode 100755
index 0000000..989a492
--- /dev/null
+++ b/share/tests/strtoi.h/strtou_noneg/strtou_noneg.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2024 Alejandro Colomar <alx@kernel.org>
+# SPDX-License-Identifier: LGPL-3.0-or-later WITH LGPL-3.0-linking-exception
+
+out="$(mktemp)";
+CFLAGS="-std=gnu2x";
+CFLAGS="$CFLAGS -Wall";
+CFLAGS="$CFLAGS -Wextra";
+CFLAGS="$CFLAGS -Werror";
+CFLAGS="$CFLAGS $(pkgconf --cflags liba2i)";
+LIBS="$(pkgconf --libs liba2i)";
+
+cc $CFLAGS -o "$out" "$(dirname "$0")"/strtou_noneg.c $LIBS;
+"$out";