]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
lib/atoi/strtoi.[ch]: strtoi_(), strtou_(): Add functions
authorAlejandro Colomar <alx@kernel.org>
Fri, 1 Dec 2023 21:34:31 +0000 (22:34 +0100)
committerSerge Hallyn <serge@hallyn.com>
Thu, 1 Feb 2024 04:26:19 +0000 (22:26 -0600)
These functions are identical to strtoi(3bsd) and strtou(3bsd), except
for one important thing: if both ERANGE and ENOTSUP conditions happen,
the BSD functions report ENOTSUP, which is bogus; our strtoi_() and
strtou_() report ERANGE.

Link: <https://lists.sr.ht/~hallyn/shadow/%3CZZoQDms6Sv6e5SPE%40debian%3E>
Link: <https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=57828>
Cc: Thorsten Glaser <tg@mirbsd.de>
Cc: christos <christos@netbsd.org>
Cc: roy <roy@netbsd.org>
Cc: Guillem Jover <guillem@hadrons.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
lib/Makefile.am
lib/atoi/strtoi.c [new file with mode: 0644]
lib/atoi/strtoi.h [new file with mode: 0644]

index 5b1121c4c79b878330e703f9a4a228a6336ea904..baef9cd2f6bb2d83874f552d7aada6967cc3fbc6 100644 (file)
@@ -31,6 +31,8 @@ libshadow_la_SOURCES = \
        agetpass.h \
        alloc.c \
        alloc.h \
+       atoi/strtoi.c \
+       atoi/strtoi.h \
        atoi/strtou_noneg.c \
        atoi/strtou_noneg.h \
        attr.h \
diff --git a/lib/atoi/strtoi.c b/lib/atoi/strtoi.c
new file mode 100644 (file)
index 0000000..197707b
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: 2023, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: BSD-3-Clause
+
+
+#include <config.h>
+
+#include "atoi/strtoi.h"
+
+#include <stdint.h>
+
+
+extern inline intmax_t strtoi_(const char *s, char **restrict endp, int base,
+    intmax_t min, intmax_t max, int *restrict status);
+extern inline uintmax_t strtou_(const char *s, char **restrict endp, int base,
+    uintmax_t min, uintmax_t max, int *restrict status);
diff --git a/lib/atoi/strtoi.h b/lib/atoi/strtoi.h
new file mode 100644 (file)
index 0000000..1f061fc
--- /dev/null
@@ -0,0 +1,96 @@
+// SPDX-FileCopyrightText: 2023, Alejandro Colomar <alx@kernel.org>
+// SPDX-License-Identifier: BSD-3-Clause
+
+
+#ifndef SHADOW_INCLUDE_LIB_ATOI_STRTOI_H_
+#define SHADOW_INCLUDE_LIB_ATOI_STRTOI_H_
+
+
+#include <config.h>
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/param.h>
+
+#include "attr.h"
+
+
+#define strtoNmax(TYPE, ...)                                                  \
+(                                                                             \
+       _Generic((TYPE) 0,                                                    \
+               intmax_t:  strtoimax,                                         \
+               uintmax_t: strtoumax                                          \
+       )(__VA_ARGS__)                                                        \
+)
+
+
+#define strtoN(s, endp, base, min, max, status, TYPE)                         \
+({                                                                            \
+       const char  *s_ = s;                                                  \
+       char        **endp_ = endp;                                           \
+       int         base_ = base;                                             \
+       TYPE        min_ = min;                                               \
+       TYPE        max_ = max;                                               \
+       int         *status_ = status;                                        \
+                                                                              \
+       int         e_, st_;                                                  \
+       char        *end_;                                                    \
+       TYPE        n_;                                                       \
+                                                                              \
+       if (endp_ == NULL)                                                    \
+               endp_ = &end_;                                                \
+       if (status_ == NULL)                                                  \
+               status_ = &st_;                                               \
+                                                                              \
+       if (base_ != 0 && (base_ < 0 || base_ > 36)) {                        \
+               *status_ = EINVAL;                                            \
+               n_ = 0;                                                       \
+                                                                              \
+       } else {                                                              \
+               e_ = errno;                                                   \
+               errno = 0;                                                    \
+               n_ = strtoNmax(TYPE, s_, endp_, base_);                       \
+                                                                              \
+               if (*endp_ == s_)                                             \
+                       *status_ = ECANCELED;                                 \
+               else if (errno == ERANGE || n_ < min_ || n_ > max_)           \
+                       *status_ = ERANGE;                                    \
+               else if (**endp_ != '\0')                                     \
+                       *status_ = ENOTSUP;                                   \
+               else                                                          \
+                       *status_ = 0;                                         \
+                                                                              \
+               errno = e_;                                                   \
+       }                                                                     \
+       MAX(min_, MIN(max_, n_));                                             \
+})
+
+
+ATTR_STRING(1) ATTR_ACCESS(write_only, 2) ATTR_ACCESS(write_only, 6)
+inline intmax_t strtoi_(const char *s, char **restrict endp, int base,
+    intmax_t min, intmax_t max, int *restrict status);
+ATTR_STRING(1) ATTR_ACCESS(write_only, 2) ATTR_ACCESS(write_only, 6)
+inline uintmax_t strtou_(const char *s, char **restrict endp, int base,
+    uintmax_t min, uintmax_t max, int *restrict status);
+
+
+inline intmax_t
+strtoi_(const char *s, char **restrict endp, int base,
+    intmax_t min, intmax_t max, int *restrict status)
+{
+       return strtoN(s, endp, base, min, max, status, intmax_t);
+}
+
+
+inline uintmax_t
+strtou_(const char *s, char **restrict endp, int base,
+    uintmax_t min, uintmax_t max, int *restrict status)
+{
+       return strtoN(s, endp, base, min, max, status, uintmax_t);
+}
+
+
+#endif  // include guard