diff --git a/lib/Makefile.am b/lib/Makefile.am index 5b1121c4..baef9cd2 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -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 index 00000000..197707b1 --- /dev/null +++ b/lib/atoi/strtoi.c @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2023, Alejandro Colomar +// SPDX-License-Identifier: BSD-3-Clause + + +#include + +#include "atoi/strtoi.h" + +#include + + +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 index 00000000..1f061fc0 --- /dev/null +++ b/lib/atoi/strtoi.h @@ -0,0 +1,96 @@ +// SPDX-FileCopyrightText: 2023, Alejandro Colomar +// SPDX-License-Identifier: BSD-3-Clause + + +#ifndef SHADOW_INCLUDE_LIB_ATOI_STRTOI_H_ +#define SHADOW_INCLUDE_LIB_ATOI_STRTOI_H_ + + +#include + +#include +#include +#include +#include +#include +#include + +#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