]> git.ipfire.org Git - thirdparty/gnulib.git/commitdiff
strtoul: Work around a bug on native Windows and Minix.
authorBruno Haible <bruno@clisp.org>
Fri, 2 Apr 2021 17:56:28 +0000 (19:56 +0200)
committerBruno Haible <bruno@clisp.org>
Fri, 2 Apr 2021 18:03:36 +0000 (20:03 +0200)
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.

ChangeLog
doc/posix-functions/strtoul.texi
lib/stdlib.in.h
m4/stdlib_h.m4
m4/strtoul.m4
modules/stdlib
modules/strtoul
tests/test-strtoul.c

index d5b833ae3bd8852415a5399ce61db8cea3ff2113..9ce3baeb4f65836404111a7de162421b77113b17 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+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.
index b79b56bb689de46bc1d5ddf6eb63038d7732029b..3b1fa7fb5eab77b15d28917cdbac84a8f0985485 100644 (file)
@@ -10,6 +10,10 @@ Portability problems fixed by Gnulib:
 @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:
index 49fc44e14a1efbe79eed15a0eb0fadc7d51955e1..0a377c075550816e9bd74c83d810a3d153719ff6 100644 (file)
@@ -1229,6 +1229,46 @@ _GL_WARN_ON_USE (strtoll, "strtoll is unportable - "
 # 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,
index 5a02972e05dbea9cc2e655515b96a4fa2076d824..5895586a23fee64373ad6ed7a3249e4aa00eca22 100644 (file)
@@ -1,4 +1,4 @@
-# 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,
@@ -28,7 +28,7 @@ AC_DEFUN([gl_STDLIB_H],
     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])
 
@@ -90,6 +90,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
   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])
@@ -139,6 +140,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
   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])
@@ -165,6 +167,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
   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])
 ])
index 853c1a6deb75717419d25c17b2818afd28bdfb0d..b915679703ab72dad38c71dda3420c56e4567f85 100644 (file)
@@ -1,4 +1,4 @@
-# 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,
@@ -6,5 +6,41 @@ dnl with or without modifications, as long as this notice is preserved.
 
 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
 ])
index 9b65a0181cab9c8bd6a888018a41fd99e1e67ec4..998f44d2408f979b6516c28993fbcb82769720f5 100644 (file)
@@ -64,6 +64,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
              -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' \
@@ -111,6 +112,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
              -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' \
@@ -137,6 +139,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \
              -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)' \
index 7f3139ca484fcd876c206ffdc747442e878e3d6f..c790e41f78d7353584a7996311e9238912d99a65 100644 (file)
@@ -1,24 +1,20 @@
 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:
 
index 0e1917daea44df89b23f356c9d3d63fa9f811efa..d34272bccd6795cfcad986c64dfc046ef6028674 100644 (file)
@@ -176,5 +176,67 @@ main (void)
     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;
 }