+2021-04-02 Bruno Haible <bruno@clisp.org>
+
+ strtoul: Work around a bug on native Windows and Minix.
+ Reported by Eric Blake <eblake@redhat.com> in
+ <https://lists.gnu.org/archive/html/bug-gnulib/2021-03/msg00082.html>.
+ * lib/stdlib.in.h (strtoul): New declaration.
+ * m4/stdlib_h.m4 (gl_STDLIB_H): Test whether strtoul is declared.
+ (gl_STDLIB_H_DEFAULTS): Initialize GNULIB_STRTOUL, HAVE_STRTOUL,
+ REPLACE_STRTOUL.
+ * m4/strtoul.m4 (gl_FUNC_STRTOUL): Require gl_STDLIB_H_DEFAULTS. Test
+ whether strtoul works. Set REPLACE_STRTOUL.
+ * modules/stdlib (Makefile.am): Substitute GNULIB_STRTOUL, HAVE_STRTOUL,
+ REPLACE_STRTOUL.
+ * modules/strtoul (Status, Notice): Remove.
+ (Depends-on): Add stdlib.
+ (configure.ac): Test HAVE_STRTOUL and REPLACE_STRTOUL. Invoke
+ gl_STDLIB_MODULE_INDICATOR.
+ * tests/test-strtoul.c (main): Add tests of hexadecimal integer syntax.
+ * doc/posix-functions/strtoul.texi: Mention the bug.
+
2021-04-02 Bruno Haible <bruno@clisp.org>
strtol, strtoul, strtoll, strtoull: Optimize.
@itemize
@item
This function is missing on some old platforms.
+@item
+This function does not parse the leading @samp{0} when the input string is
+@code{"0x"} and the base is 16 or 0 on some platforms:
+Minix 3.3, mingw, MSVC 14.
@end itemize
Portability problems not fixed by Gnulib:
# endif
#endif
+#if @GNULIB_STRTOUL@
+/* Parse an unsigned integer whose textual representation starts at STRING.
+ The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0,
+ it may be decimal or octal (with prefix "0") or hexadecimal (with prefix
+ "0x").
+ If ENDPTR is not NULL, the address of the first byte after the integer is
+ stored in *ENDPTR.
+ Upon overflow, the return value is ULONG_MAX, and errno is set to ERANGE. */
+# if @REPLACE_STRTOUL@
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# define strtoul rpl_strtoul
+# endif
+# define GNULIB_defined_strtoul_function 1
+_GL_FUNCDECL_RPL (strtoul, unsigned long,
+ (const char *restrict string, char **restrict endptr,
+ int base)
+ _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (strtoul, unsigned long,
+ (const char *restrict string, char **restrict endptr,
+ int base));
+# else
+# if !@HAVE_STRTOUL@
+_GL_FUNCDECL_SYS (strtoul, unsigned long,
+ (const char *restrict string, char **restrict endptr,
+ int base)
+ _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (strtoul, unsigned long,
+ (const char *restrict string, char **restrict endptr,
+ int base));
+# endif
+_GL_CXXALIASWARN (strtoul);
+#elif defined GNULIB_POSIXCHECK
+# undef strtoul
+# if HAVE_RAW_DECL_STRTOUL
+_GL_WARN_ON_USE (strtoul, "strtoul is unportable - "
+ "use gnulib module strtoul for portability");
+# endif
+#endif
+
#if @GNULIB_STRTOULL@
/* Parse an unsigned integer whose textual representation starts at STRING.
The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0,
-# stdlib_h.m4 serial 55
+# stdlib_h.m4 serial 56
dnl Copyright (C) 2007-2021 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
posix_memalign posix_openpt ptsname ptsname_r qsort_r
random random_r reallocarray realpath rpmatch secure_getenv setenv
setstate setstate_r srandom srandom_r
- strtod strtold strtoll strtoull unlockpt unsetenv])
+ strtod strtold strtoll strtoul strtoull unlockpt unsetenv])
AC_REQUIRE([AC_C_RESTRICT])
GNULIB_STRTOD=0; AC_SUBST([GNULIB_STRTOD])
GNULIB_STRTOLD=0; AC_SUBST([GNULIB_STRTOLD])
GNULIB_STRTOLL=0; AC_SUBST([GNULIB_STRTOLL])
+ GNULIB_STRTOUL=0; AC_SUBST([GNULIB_STRTOUL])
GNULIB_STRTOULL=0; AC_SUBST([GNULIB_STRTOULL])
GNULIB_SYSTEM_POSIX=0; AC_SUBST([GNULIB_SYSTEM_POSIX])
GNULIB_UNLOCKPT=0; AC_SUBST([GNULIB_UNLOCKPT])
HAVE_STRTOD=1; AC_SUBST([HAVE_STRTOD])
HAVE_STRTOLD=1; AC_SUBST([HAVE_STRTOLD])
HAVE_STRTOLL=1; AC_SUBST([HAVE_STRTOLL])
+ HAVE_STRTOUL=1; AC_SUBST([HAVE_STRTOUL])
HAVE_STRTOULL=1; AC_SUBST([HAVE_STRTOULL])
HAVE_STRUCT_RANDOM_DATA=1; AC_SUBST([HAVE_STRUCT_RANDOM_DATA])
HAVE_SYS_LOADAVG_H=0; AC_SUBST([HAVE_SYS_LOADAVG_H])
REPLACE_SETSTATE=0; AC_SUBST([REPLACE_SETSTATE])
REPLACE_STRTOD=0; AC_SUBST([REPLACE_STRTOD])
REPLACE_STRTOLD=0; AC_SUBST([REPLACE_STRTOLD])
+ REPLACE_STRTOUL=0; AC_SUBST([REPLACE_STRTOUL])
REPLACE_UNSETENV=0; AC_SUBST([REPLACE_UNSETENV])
REPLACE_WCTOMB=0; AC_SUBST([REPLACE_WCTOMB])
])
-# strtoul.m4 serial 5
+# strtoul.m4 serial 6
dnl Copyright (C) 2002, 2006, 2009-2021 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
AC_DEFUN([gl_FUNC_STRTOUL],
[
+ AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+ AC_REQUIRE([AC_CANONICAL_HOST])
AC_CHECK_FUNCS([strtoul])
+ if test $ac_cv_func_strtoul = yes; then
+ AC_CACHE_CHECK([whether strtoul works],
+ [gl_cv_func_strtoul_works],
+ [AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <stdlib.h>]],
+ [[int result = 0;
+ char *term;
+ /* This test fails on Minix and native Windows. */
+ {
+ const char input[] = "0x";
+ (void) strtoul (input, &term, 16);
+ if (term != input + 1)
+ result |= 1;
+ }
+ return result;
+ ]])
+ ],
+ [gl_cv_func_strtoul_works=yes],
+ [gl_cv_func_strtoul_works=no],
+ [case "$host_os" in
+ # Guess no on native Windows.
+ mingw*) gl_cv_func_strtoul_works="guessing no" ;;
+ *) gl_cv_func_strtoul_works="$gl_cross_guess_normal" ;;
+ esac
+ ])
+ ])
+ case "$gl_cv_func_strtoul_works" in
+ *yes) ;;
+ *) REPLACE_STRTOUL=1 ;;
+ esac
+ else
+ HAVE_STRTOUL=0
+ fi
])
-e 's/@''GNULIB_STRTOD''@/$(GNULIB_STRTOD)/g' \
-e 's/@''GNULIB_STRTOLD''@/$(GNULIB_STRTOLD)/g' \
-e 's/@''GNULIB_STRTOLL''@/$(GNULIB_STRTOLL)/g' \
+ -e 's/@''GNULIB_STRTOUL''@/$(GNULIB_STRTOUL)/g' \
-e 's/@''GNULIB_STRTOULL''@/$(GNULIB_STRTOULL)/g' \
-e 's/@''GNULIB_SYSTEM_POSIX''@/$(GNULIB_SYSTEM_POSIX)/g' \
-e 's/@''GNULIB_UNLOCKPT''@/$(GNULIB_UNLOCKPT)/g' \
-e 's|@''HAVE_STRTOD''@|$(HAVE_STRTOD)|g' \
-e 's|@''HAVE_STRTOLD''@|$(HAVE_STRTOLD)|g' \
-e 's|@''HAVE_STRTOLL''@|$(HAVE_STRTOLL)|g' \
+ -e 's|@''HAVE_STRTOUL''@|$(HAVE_STRTOUL)|g' \
-e 's|@''HAVE_STRTOULL''@|$(HAVE_STRTOULL)|g' \
-e 's|@''HAVE_STRUCT_RANDOM_DATA''@|$(HAVE_STRUCT_RANDOM_DATA)|g' \
-e 's|@''HAVE_SYS_LOADAVG_H''@|$(HAVE_SYS_LOADAVG_H)|g' \
-e 's|@''REPLACE_SETSTATE''@|$(REPLACE_SETSTATE)|g' \
-e 's|@''REPLACE_STRTOD''@|$(REPLACE_STRTOD)|g' \
-e 's|@''REPLACE_STRTOLD''@|$(REPLACE_STRTOLD)|g' \
+ -e 's|@''REPLACE_STRTOUL''@|$(REPLACE_STRTOUL)|g' \
-e 's|@''REPLACE_UNSETENV''@|$(REPLACE_UNSETENV)|g' \
-e 's|@''REPLACE_WCTOMB''@|$(REPLACE_WCTOMB)|g' \
-e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
Description:
strtoul() function: convert string to 'unsigned long'.
-Status:
-obsolete
-
-Notice:
-This module is obsolete.
-
Files:
lib/strtol.c
lib/strtoul.c
m4/strtoul.m4
Depends-on:
+stdlib
configure.ac:
gl_FUNC_STRTOUL
-if test $ac_cv_func_strtoul = no; then
+if test $HAVE_STRTOUL = 0 || test $REPLACE_STRTOUL = 1; then
AC_LIBOBJ([strtoul])
fi
+gl_STDLIB_MODULE_INDICATOR([strtoul])
Makefile.am:
ASSERT (errno == 0);
}
+ /* Hexadecimal integer syntax. */
+ {
+ const char input[] = "0x2A";
+ char *ptr;
+ unsigned long result;
+ errno = 0;
+ result = strtoul (input, &ptr, 10);
+ ASSERT (result == 0UL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0x2A";
+ char *ptr;
+ unsigned long result;
+ errno = 0;
+ result = strtoul (input, &ptr, 16);
+ ASSERT (result == 42UL);
+ ASSERT (ptr == input + 4);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0x2A";
+ char *ptr;
+ unsigned long result;
+ errno = 0;
+ result = strtoul (input, &ptr, 0);
+ ASSERT (result == 42UL);
+ ASSERT (ptr == input + 4);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0x";
+ char *ptr;
+ unsigned long result;
+ errno = 0;
+ result = strtoul (input, &ptr, 10);
+ ASSERT (result == 0UL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0x";
+ char *ptr;
+ unsigned long result;
+ errno = 0;
+ result = strtoul (input, &ptr, 16);
+ ASSERT (result == 0UL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+ {
+ const char input[] = "0x";
+ char *ptr;
+ unsigned long result;
+ errno = 0;
+ result = strtoul (input, &ptr, 0);
+ ASSERT (result == 0UL);
+ ASSERT (ptr == input + 1);
+ ASSERT (errno == 0);
+ }
+
return 0;
}