>From 705c23696fcaf5bd9d4f0aaecd106b4a2c1417b2 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Fri, 2 Apr 2021 20:42:13 +0200 Subject: [PATCH 5/7] strtol: Work around a bug on native Windows and Minix. * lib/stdlib.in.h (strtol): New declaration. * m4/stdlib_h.m4 (gl_STDLIB_H): Test whether strtol is declared. (gl_STDLIB_H_DEFAULTS): Initialize GNULIB_STRTOL, HAVE_STRTOL, REPLACE_STRTOL. * m4/strtol.m4 (gl_FUNC_STRTOL): Require gl_STDLIB_H_DEFAULTS. Test whether strtol works. Set REPLACE_STRTOL. * modules/stdlib (Makefile.am): Substitute GNULIB_STRTOL, HAVE_STRTOL, REPLACE_STRTOL. * modules/strtol (Status, Notice): Remove. (Depends-on): Add stdlib. (configure.ac): Test HAVE_STRTOL and REPLACE_STRTOL. Invoke gl_STDLIB_MODULE_INDICATOR. * tests/test-strtol.c (main): Add tests of hexadecimal integer syntax. * doc/posix-functions/strtol.texi: Mention the bug. --- ChangeLog | 18 ++++++++++++ doc/posix-functions/strtol.texi | 4 +++ lib/stdlib.in.h | 41 +++++++++++++++++++++++++++ m4/stdlib_h.m4 | 7 +++-- m4/strtol.m4 | 38 ++++++++++++++++++++++++- modules/stdlib | 3 ++ modules/strtol | 10 ++----- tests/test-strtol.c | 62 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 173 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5d752ab..9a84589 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,23 @@ 2021-04-02 Bruno Haible + strtol: Work around a bug on native Windows and Minix. + * lib/stdlib.in.h (strtol): New declaration. + * m4/stdlib_h.m4 (gl_STDLIB_H): Test whether strtol is declared. + (gl_STDLIB_H_DEFAULTS): Initialize GNULIB_STRTOL, HAVE_STRTOL, + REPLACE_STRTOL. + * m4/strtol.m4 (gl_FUNC_STRTOL): Require gl_STDLIB_H_DEFAULTS. Test + whether strtol works. Set REPLACE_STRTOL. + * modules/stdlib (Makefile.am): Substitute GNULIB_STRTOL, HAVE_STRTOL, + REPLACE_STRTOL. + * modules/strtol (Status, Notice): Remove. + (Depends-on): Add stdlib. + (configure.ac): Test HAVE_STRTOL and REPLACE_STRTOL. Invoke + gl_STDLIB_MODULE_INDICATOR. + * tests/test-strtol.c (main): Add tests of hexadecimal integer syntax. + * doc/posix-functions/strtol.texi: Mention the bug. + +2021-04-02 Bruno Haible + strtoull: Work around a bug on native Windows and Minix. * lib/stdlib.in.h (strtoull): Override if REPLACE_STRTOULL is 1. * m4/stdlib_h.m4 (gl_STDLIB_H_DEFAULTS): Initialize REPLACE_STRTOULL. diff --git a/doc/posix-functions/strtol.texi b/doc/posix-functions/strtol.texi index bf539c4..c9333ce 100644 --- a/doc/posix-functions/strtol.texi +++ b/doc/posix-functions/strtol.texi @@ -11,6 +11,10 @@ Portability problems fixed by Gnulib: @item This function is missing on some old platforms. @end itemize +@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. Portability problems not fixed by Gnulib: @itemize diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h index 0506362..e2c461b 100644 --- a/lib/stdlib.in.h +++ b/lib/stdlib.in.h @@ -1202,6 +1202,47 @@ _GL_WARN_ON_USE (strtold, "strtold is unportable - " # endif #endif +#if @GNULIB_STRTOL@ +/* Parse a signed 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 LONG_MAX or LONG_MIN, and errno is set + to ERANGE. */ +# if @REPLACE_STRTOL@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# define strtol rpl_strtol +# endif +# define GNULIB_defined_strtol_function 1 +_GL_FUNCDECL_RPL (strtol, long, + (const char *restrict string, char **restrict endptr, + int base) + _GL_ARG_NONNULL ((1))); +_GL_CXXALIAS_RPL (strtol, long, + (const char *restrict string, char **restrict endptr, + int base)); +# else +# if !@HAVE_STRTOL@ +_GL_FUNCDECL_SYS (strtol, long, + (const char *restrict string, char **restrict endptr, + int base) + _GL_ARG_NONNULL ((1))); +# endif +_GL_CXXALIAS_SYS (strtol, long, + (const char *restrict string, char **restrict endptr, + int base)); +# endif +_GL_CXXALIASWARN (strtol); +#elif defined GNULIB_POSIXCHECK +# undef strtol +# if HAVE_RAW_DECL_STRTOL +_GL_WARN_ON_USE (strtol, "strtol is unportable - " + "use gnulib module strtol for portability"); +# endif +#endif + #if @GNULIB_STRTOLL@ /* Parse a signed integer whose textual representation starts at STRING. The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0, diff --git a/m4/stdlib_h.m4 b/m4/stdlib_h.m4 index 652ba86..7f084f1 100644 --- a/m4/stdlib_h.m4 +++ b/m4/stdlib_h.m4 @@ -1,4 +1,4 @@ -# stdlib_h.m4 serial 57 +# stdlib_h.m4 serial 58 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 strtoul strtoull unlockpt unsetenv]) + strtod strtol strtold strtoll strtoul strtoull unlockpt unsetenv]) AC_REQUIRE([AC_C_RESTRICT]) @@ -88,6 +88,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS], GNULIB_SECURE_GETENV=0; AC_SUBST([GNULIB_SECURE_GETENV]) GNULIB_SETENV=0; AC_SUBST([GNULIB_SETENV]) GNULIB_STRTOD=0; AC_SUBST([GNULIB_STRTOD]) + GNULIB_STRTOL=0; AC_SUBST([GNULIB_STRTOL]) GNULIB_STRTOLD=0; AC_SUBST([GNULIB_STRTOLD]) GNULIB_STRTOLL=0; AC_SUBST([GNULIB_STRTOLL]) GNULIB_STRTOUL=0; AC_SUBST([GNULIB_STRTOUL]) @@ -138,6 +139,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS], HAVE_SETSTATE=1; AC_SUBST([HAVE_SETSTATE]) HAVE_DECL_SETSTATE=1; AC_SUBST([HAVE_DECL_SETSTATE]) HAVE_STRTOD=1; AC_SUBST([HAVE_STRTOD]) + HAVE_STRTOL=1; AC_SUBST([HAVE_STRTOL]) HAVE_STRTOLD=1; AC_SUBST([HAVE_STRTOLD]) HAVE_STRTOLL=1; AC_SUBST([HAVE_STRTOLL]) HAVE_STRTOUL=1; AC_SUBST([HAVE_STRTOUL]) @@ -166,6 +168,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS], REPLACE_SETENV=0; AC_SUBST([REPLACE_SETENV]) REPLACE_SETSTATE=0; AC_SUBST([REPLACE_SETSTATE]) REPLACE_STRTOD=0; AC_SUBST([REPLACE_STRTOD]) + REPLACE_STRTOL=0; AC_SUBST([REPLACE_STRTOL]) REPLACE_STRTOLD=0; AC_SUBST([REPLACE_STRTOLD]) REPLACE_STRTOUL=0; AC_SUBST([REPLACE_STRTOUL]) REPLACE_STRTOULL=0; AC_SUBST([REPLACE_STRTOULL]) diff --git a/m4/strtol.m4 b/m4/strtol.m4 index ec7b8d1..343507b 100644 --- a/m4/strtol.m4 +++ b/m4/strtol.m4 @@ -1,4 +1,4 @@ -# strtol.m4 serial 6 +# strtol.m4 serial 7 dnl Copyright (C) 2002-2003, 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_STRTOL], [ + AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) + AC_REQUIRE([AC_CANONICAL_HOST]) AC_CHECK_FUNCS([strtol]) + if test $ac_cv_func_strtol = yes; then + AC_CACHE_CHECK([whether strtol works], + [gl_cv_func_strtol_works], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[int result = 0; + char *term; + /* This test fails on Minix and native Windows. */ + { + const char input[] = "0x"; + (void) strtol (input, &term, 16); + if (term != input + 1) + result |= 1; + } + return result; + ]]) + ], + [gl_cv_func_strtol_works=yes], + [gl_cv_func_strtol_works=no], + [case "$host_os" in + # Guess no on native Windows. + mingw*) gl_cv_func_strtol_works="guessing no" ;; + *) gl_cv_func_strtol_works="$gl_cross_guess_normal" ;; + esac + ]) + ]) + case "$gl_cv_func_strtol_works" in + *yes) ;; + *) REPLACE_STRTOL=1 ;; + esac + else + HAVE_STRTOL=0 + fi ]) diff --git a/modules/stdlib b/modules/stdlib index 4bd7a5c..33b8d50 100644 --- a/modules/stdlib +++ b/modules/stdlib @@ -62,6 +62,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \ -e 's/@''GNULIB_SECURE_GETENV''@/$(GNULIB_SECURE_GETENV)/g' \ -e 's/@''GNULIB_SETENV''@/$(GNULIB_SETENV)/g' \ -e 's/@''GNULIB_STRTOD''@/$(GNULIB_STRTOD)/g' \ + -e 's/@''GNULIB_STRTOL''@/$(GNULIB_STRTOL)/g' \ -e 's/@''GNULIB_STRTOLD''@/$(GNULIB_STRTOLD)/g' \ -e 's/@''GNULIB_STRTOLL''@/$(GNULIB_STRTOLL)/g' \ -e 's/@''GNULIB_STRTOUL''@/$(GNULIB_STRTOUL)/g' \ @@ -110,6 +111,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \ -e 's|@''HAVE_SETSTATE''@|$(HAVE_SETSTATE)|g' \ -e 's|@''HAVE_DECL_SETSTATE''@|$(HAVE_DECL_SETSTATE)|g' \ -e 's|@''HAVE_STRTOD''@|$(HAVE_STRTOD)|g' \ + -e 's|@''HAVE_STRTOL''@|$(HAVE_STRTOL)|g' \ -e 's|@''HAVE_STRTOLD''@|$(HAVE_STRTOLD)|g' \ -e 's|@''HAVE_STRTOLL''@|$(HAVE_STRTOLL)|g' \ -e 's|@''HAVE_STRTOUL''@|$(HAVE_STRTOUL)|g' \ @@ -138,6 +140,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \ -e 's|@''REPLACE_SETENV''@|$(REPLACE_SETENV)|g' \ -e 's|@''REPLACE_SETSTATE''@|$(REPLACE_SETSTATE)|g' \ -e 's|@''REPLACE_STRTOD''@|$(REPLACE_STRTOD)|g' \ + -e 's|@''REPLACE_STRTOL''@|$(REPLACE_STRTOL)|g' \ -e 's|@''REPLACE_STRTOLD''@|$(REPLACE_STRTOLD)|g' \ -e 's|@''REPLACE_STRTOUL''@|$(REPLACE_STRTOUL)|g' \ -e 's|@''REPLACE_STRTOULL''@|$(REPLACE_STRTOULL)|g' \ diff --git a/modules/strtol b/modules/strtol index 65b6946..24d4c73 100644 --- a/modules/strtol +++ b/modules/strtol @@ -1,23 +1,19 @@ Description: strtol() function: convert string to 'long'. -Status: -obsolete - -Notice: -This module is obsolete. - Files: lib/strtol.c m4/strtol.m4 Depends-on: +stdlib configure.ac: gl_FUNC_STRTOL -if test $ac_cv_func_strtol = no; then +if test $HAVE_STRTOL = 0 || test $REPLACE_STRTOL = 1; then AC_LIBOBJ([strtol]) fi +gl_STDLIB_MODULE_INDICATOR([strtol]) Makefile.am: diff --git a/tests/test-strtol.c b/tests/test-strtol.c index 105bc58..467514c 100644 --- a/tests/test-strtol.c +++ b/tests/test-strtol.c @@ -177,5 +177,67 @@ main (void) ASSERT (errno == 0); } + /* Hexadecimal integer syntax. */ + { + const char input[] = "0x2A"; + char *ptr; + long result; + errno = 0; + result = strtol (input, &ptr, 10); + ASSERT (result == 0L); + ASSERT (ptr == input + 1); + ASSERT (errno == 0); + } + { + const char input[] = "0x2A"; + char *ptr; + long result; + errno = 0; + result = strtol (input, &ptr, 16); + ASSERT (result == 42L); + ASSERT (ptr == input + 4); + ASSERT (errno == 0); + } + { + const char input[] = "0x2A"; + char *ptr; + long result; + errno = 0; + result = strtol (input, &ptr, 0); + ASSERT (result == 42L); + ASSERT (ptr == input + 4); + ASSERT (errno == 0); + } + { + const char input[] = "0x"; + char *ptr; + long result; + errno = 0; + result = strtol (input, &ptr, 10); + ASSERT (result == 0L); + ASSERT (ptr == input + 1); + ASSERT (errno == 0); + } + { + const char input[] = "0x"; + char *ptr; + long result; + errno = 0; + result = strtol (input, &ptr, 16); + ASSERT (result == 0L); + ASSERT (ptr == input + 1); + ASSERT (errno == 0); + } + { + const char input[] = "0x"; + char *ptr; + long result; + errno = 0; + result = strtol (input, &ptr, 0); + ASSERT (result == 0L); + ASSERT (ptr == input + 1); + ASSERT (errno == 0); + } + return 0; } -- 2.7.4