1
0
mirror of https://https.git.savannah.gnu.org/git/gnulib.git synced 2026-09-01 02:34:55 +00:00

strtof: New module.

* lib/stdlib.in.h (strtof): New declaration.
* lib/strtod.c: Support USE_FLOAT.
* lib/strtof.c: New file.
* m4/strtof.m4: New file, based on m4/strtod.m4.
* m4/ldexpf.m4 (gl_CHECK_LDEXPF_NO_LIBM): New macro, based on
m4/ldexp.m4.
* m4/stdlib_h.m4 (gl_STDLIB_H_REQUIRE_DEFAULTS): Initialize
GNULIB_STRTOF.
* modules/stdlib (Makefile.am): Substitute GNULIB_STRTOF, HAVE_STRTOF,
REPLACE_STRTOF.
* modules/strtof: New file.
* tests/test-stdlib-c++.cc (strtof): Check signature.
* doc/posix-functions/strtof.texi: Mention the new module and the bugs
that it fixes.
(gl_STDLIB_H_DEFAULTS): Initialize HAVE_STRTOF, REPLACE_STRTOF.
This commit is contained in:
Bruno Haible
2024-02-21 22:45:47 +01:00
parent c78e0437cc
commit 01a485ed9b
11 changed files with 342 additions and 15 deletions
+19
View File
@@ -1,3 +1,22 @@
2024-02-21 Bruno Haible <bruno@clisp.org>
strtof: New module.
* lib/stdlib.in.h (strtof): New declaration.
* lib/strtod.c: Support USE_FLOAT.
* lib/strtof.c: New file.
* m4/strtof.m4: New file, based on m4/strtod.m4.
* m4/ldexpf.m4 (gl_CHECK_LDEXPF_NO_LIBM): New macro, based on
m4/ldexp.m4.
* m4/stdlib_h.m4 (gl_STDLIB_H_REQUIRE_DEFAULTS): Initialize
GNULIB_STRTOF.
* modules/stdlib (Makefile.am): Substitute GNULIB_STRTOF, HAVE_STRTOF,
REPLACE_STRTOF.
* modules/strtof: New file.
* tests/test-stdlib-c++.cc (strtof): Check signature.
* doc/posix-functions/strtof.texi: Mention the new module and the bugs
that it fixes.
(gl_STDLIB_H_DEFAULTS): Initialize HAVE_STRTOF, REPLACE_STRTOF.
2024-02-21 Bruno Haible <bruno@clisp.org>
strtod, strtold tests: Avoid a test failure on native Windows.
+29 -3
View File
@@ -4,15 +4,41 @@
POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/strtof.html}
Gnulib module: ---
Gnulib module: strtof
Portability problems fixed by Gnulib:
@itemize
@item
This function is missing on some platforms:
NetBSD 3.0, OpenBSD 3.8, Minix 3.1.8, HP-UX 11, IRIX 6.5, Solaris 9, MSVC 9, Android 4.4.
@item
This function returns the wrong end pointer for @samp{-0x} on some
platforms:
glibc 2.4, Mac OS X 10.5, FreeBSD 6.2.
@item
This function fails to parse @samp{NaN()} on some platforms:
glibc-2.5, FreeBSD 6.2.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
@item
This function is missing on some platforms:
NetBSD 3.0, OpenBSD 3.8, Minix 3.1.8, HP-UX 11, IRIX 6.5, Solaris 9, MSVC 9, Android 4.4.
This function returns +0.0 (not @minus{}0.0) for negative underflow on some
platforms:
glibc 2.7, mingw, MSVC 14.
@item
This function cannot distinguish between ``nan'' and ``-nan'' on some
platforms:
glibc 2.7, mingw, MSVC 14.
@item
This function fails to correctly parse very long strings on some
platforms:
Mac OS X 10.5, FreeBSD 6.2, NetBSD 5.0, Cygwin, mingw, MSVC 14.
@item
The replacement function does not always return correctly rounded results.
@end itemize
+32
View File
@@ -1591,6 +1591,38 @@ _GL_WARN_ON_USE (strtod, "strtod is unportable - "
# endif
#endif
#if @GNULIB_STRTOF@
/* Parse a float from STRING, updating ENDP if appropriate. */
# if @REPLACE_STRTOF@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
# define strtof rpl_strtof
# endif
# define GNULIB_defined_strtof_function 1
_GL_FUNCDECL_RPL (strtof, float,
(const char *restrict str, char **restrict endp)
_GL_ARG_NONNULL ((1)));
_GL_CXXALIAS_RPL (strtof, float,
(const char *restrict str, char **restrict endp));
# else
# if !@HAVE_STRTOF@
_GL_FUNCDECL_SYS (strtof, float,
(const char *restrict str, char **restrict endp)
_GL_ARG_NONNULL ((1)));
# endif
_GL_CXXALIAS_SYS (strtof, float,
(const char *restrict str, char **restrict endp));
# endif
# if __GLIBC__ >= 2
_GL_CXXALIASWARN (strtof);
# endif
#elif defined GNULIB_POSIXCHECK
# undef strtof
# if HAVE_RAW_DECL_STRTOF
_GL_WARN_ON_USE (strtof, "strtof is unportable - "
"use gnulib module strtof for portability");
# endif
#endif
#if @GNULIB_STRTOLD@
/* Parse a 'long double' from STRING, updating ENDP if appropriate. */
# if @REPLACE_STRTOLD@
+29 -10
View File
@@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#if ! defined USE_LONG_DOUBLE
#if ! (defined USE_FLOAT || defined USE_LONG_DOUBLE)
# include <config.h>
#endif
@@ -23,7 +23,7 @@
#include <ctype.h> /* isspace() */
#include <errno.h>
#include <float.h> /* {DBL,LDBL}_{MIN,MAX} */
#include <float.h> /* {FLT,DBL,LDBL}_{MIN,MAX} */
#include <limits.h> /* LONG_{MIN,MAX} */
#include <locale.h> /* localeconv() */
#include <math.h> /* NAN */
@@ -37,7 +37,20 @@
#undef MIN
#undef MAX
#ifdef USE_LONG_DOUBLE
#if defined USE_FLOAT
# define STRTOD strtof
# define LDEXP ldexpf
# define HAVE_UNDERLYING_STRTOD HAVE_STRTOF
# define DOUBLE float
# define MIN FLT_MIN
# define MAX FLT_MAX
# define L_(literal) literal##f
# if HAVE_LDEXPF_IN_LIBC
# define USE_LDEXP 1
# else
# define USE_LDEXP 0
# endif
#elif defined USE_LONG_DOUBLE
# define STRTOD strtold
# define LDEXP ldexpl
# if defined __hpux && defined __hppa
@@ -54,6 +67,11 @@
# define MIN LDBL_MIN
# define MAX LDBL_MAX
# define L_(literal) literal##L
# if HAVE_LDEXPL_IN_LIBC
# define USE_LDEXP 1
# else
# define USE_LDEXP 0
# endif
#else
# define STRTOD strtod
# define LDEXP ldexp
@@ -62,12 +80,11 @@
# define MIN DBL_MIN
# define MAX DBL_MAX
# define L_(literal) literal
#endif
#if (defined USE_LONG_DOUBLE ? HAVE_LDEXPM_IN_LIBC : HAVE_LDEXP_IN_LIBC)
# define USE_LDEXP 1
#else
# define USE_LDEXP 0
# if HAVE_LDEXP_IN_LIBC
# define USE_LDEXP 1
# else
# define USE_LDEXP 0
# endif
#endif
/* Return true if C is a space in the current locale, avoiding
@@ -311,7 +328,9 @@ minus_zero (void)
DOUBLE
STRTOD (const char *nptr, char **endptr)
#if HAVE_UNDERLYING_STRTOD
# ifdef USE_LONG_DOUBLE
# if defined USE_FLOAT
# undef strtof
# elif defined USE_LONG_DOUBLE
# undef strtold
# else
# undef strtod
+22
View File
@@ -0,0 +1,22 @@
/* Convert string to 'float'.
Copyright (C) 2024 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Bruno Haible <bruno@clisp.org>, 2024. */
#include <config.h>
#define USE_FLOAT
#include "strtod.c"
+21 -1
View File
@@ -1,4 +1,4 @@
# ldexpf.m4 serial 2
# ldexpf.m4 serial 3
dnl Copyright (C) 2011-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -23,3 +23,23 @@ AC_DEFUN([gl_FUNC_LDEXPF],
fi
AC_SUBST([LDEXPF_LIBM])
])
dnl Test whether ldexpf() can be used without linking with libm.
dnl Set gl_cv_func_ldexpf_no_libm to 'yes' or 'no' accordingly.
AC_DEFUN([gl_CHECK_LDEXPF_NO_LIBM],
[
AC_CACHE_CHECK([whether ldexpf() can be used without linking with libm],
[gl_cv_func_ldexpf_no_libm],
[
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#ifndef __NO_MATH_INLINES
# define __NO_MATH_INLINES 1 /* for glibc */
#endif
#include <math.h>
float (*funcptr) (float, int) = ldexpf;
float x;]],
[[return ldexpf (x, -1) > 0;]])],
[gl_cv_func_ldexpf_no_libm=yes],
[gl_cv_func_ldexpf_no_libm=no])
])
])
+4 -1
View File
@@ -1,4 +1,4 @@
# stdlib_h.m4 serial 76
# stdlib_h.m4 serial 77
dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -145,6 +145,7 @@ AC_DEFUN([gl_STDLIB_H_REQUIRE_DEFAULTS],
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SECURE_GETENV])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETENV])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOD])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOF])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOL])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOLD])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOLL])
@@ -205,6 +206,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_STRTOF=1; AC_SUBST([HAVE_STRTOF])
HAVE_STRTOL=1; AC_SUBST([HAVE_STRTOL])
HAVE_STRTOLD=1; AC_SUBST([HAVE_STRTOLD])
HAVE_STRTOLL=1; AC_SUBST([HAVE_STRTOLL])
@@ -248,6 +250,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_STRTOF=0; AC_SUBST([REPLACE_STRTOF])
REPLACE_STRTOL=0; AC_SUBST([REPLACE_STRTOL])
REPLACE_STRTOLD=0; AC_SUBST([REPLACE_STRTOLD])
REPLACE_STRTOLL=0; AC_SUBST([REPLACE_STRTOLL])
+142
View File
@@ -0,0 +1,142 @@
# strtof.m4 serial 1
dnl Copyright (C) 2002-2003, 2006-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
AC_DEFUN([gl_FUNC_STRTOF],
[
AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
dnl Test whether strtof is declared.
dnl Don't call AC_FUNC_STRTOF, because it does not have the right guess
dnl when cross-compiling.
dnl Don't call AC_CHECK_FUNCS([strtof]) because it would collide with the
dnl ac_cv_func_strtof variable set by the AC_FUNC_STRTOF macro.
AC_CHECK_DECLS_ONCE([strtof])
if test $ac_cv_have_decl_strtof != yes; then
HAVE_STRTOF=0
fi
if test $HAVE_STRTOF = 1; then
AC_CACHE_CHECK([whether strtof obeys C99], [gl_cv_func_strtof_works],
[AC_RUN_IFELSE([AC_LANG_PROGRAM([[
#include <stdlib.h>
#include <math.h>
#include <errno.h>
/* Compare two numbers with ==.
This is a separate function because IRIX 6.5 "cc -O" miscompiles an
'x == x' test. */
static int
numeric_equal (float x, float y)
{
return x == y;
}
]], [[
int result = 0;
{
/* In some old versions of Linux (2000 or before), strtof mis-parses
strings with leading '+'. */
const char *string = " +69";
char *term;
float value = strtof (string, &term);
if (value != 69 || term != (string + 4))
result |= 1;
}
{
/* Under Solaris 2.4, strtof returns the wrong value for the
terminating character under some conditions. */
const char *string = "NaN";
char *term;
strtof (string, &term);
if (term != string && *(term - 1) == 0)
result |= 2;
}
{
/* Older glibc and Cygwin mis-parse "-0x". */
const char *string = "-0x";
char *term;
float value = strtof (string, &term);
float zero = 0.0f;
if (1.0f / value != -1.0f / zero || term != (string + 2))
result |= 4;
}
{
/* Many platforms do not parse hex floats. */
const char *string = "0XaP+1";
char *term;
float value = strtof (string, &term);
if (value != 20.0f || term != (string + 6))
result |= 8;
}
{
/* Many platforms do not parse infinities. HP-UX 11.31 parses inf,
but mistakenly sets errno. */
const char *string = "inf";
char *term;
float value;
errno = 0;
value = strtof (string, &term);
if (value != HUGE_VAL || term != (string + 3) || errno)
result |= 16;
}
{
/* glibc 2.7 and cygwin 1.5.24 misparse "nan()". */
const char *string = "nan()";
char *term;
float value = strtof (string, &term);
if (numeric_equal (value, value) || term != (string + 5))
result |= 32;
}
{
/* darwin 10.6.1 misparses "nan(". */
const char *string = "nan(";
char *term;
float value = strtof (string, &term);
if (numeric_equal (value, value) || term != (string + 3))
result |= 64;
}
return result;
]])],
[gl_cv_func_strtof_works=yes],
[gl_cv_func_strtof_works=no],
[dnl The last known bugs in glibc strtof(), as of this writing,
dnl were fixed in version 2.8
AC_EGREP_CPP([Lucky user],
[
#include <features.h>
#ifdef __GNU_LIBRARY__
#if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) || (__GLIBC__ > 2)) \
&& !defined __UCLIBC__
Lucky user
#endif
#endif
],
[gl_cv_func_strtof_works="guessing yes"],
[case "$host_os" in
# Guess yes on musl systems.
*-musl* | midipix*) gl_cv_func_strtof_works="guessing yes" ;;
# Guess yes on native Windows.
mingw* | windows*) gl_cv_func_strtof_works="guessing yes" ;;
*) gl_cv_func_strtof_works="$gl_cross_guess_normal" ;;
esac
])
])
])
case "$gl_cv_func_strtof_works" in
*yes) ;;
*)
REPLACE_STRTOF=1
;;
esac
fi
])
# Prerequisites of lib/strtof.c.
AC_DEFUN([gl_PREREQ_STRTOF], [
AC_REQUIRE([gl_CHECK_LDEXPF_NO_LIBM])
if test $gl_cv_func_ldexpf_no_libm = yes; then
AC_DEFINE([HAVE_LDEXPF_IN_LIBC], [1],
[Define if the ldexpf function is available in libc.])
fi
gl_CHECK_FUNCS_ANDROID([nl_langinfo], [[#include <langinfo.h>]])
])
+3
View File
@@ -73,6 +73,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_STRTOF''@/$(GNULIB_STRTOF)/g' \
-e 's/@''GNULIB_STRTOL''@/$(GNULIB_STRTOL)/g' \
-e 's/@''GNULIB_STRTOLD''@/$(GNULIB_STRTOLD)/g' \
-e 's/@''GNULIB_STRTOLL''@/$(GNULIB_STRTOLL)/g' \
@@ -125,6 +126,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_STRTOF''@|$(HAVE_STRTOF)|g' \
-e 's|@''HAVE_STRTOL''@|$(HAVE_STRTOL)|g' \
-e 's|@''HAVE_STRTOLD''@|$(HAVE_STRTOLD)|g' \
-e 's|@''HAVE_STRTOLL''@|$(HAVE_STRTOLL)|g' \
@@ -170,6 +172,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_STRTOF''@|$(REPLACE_STRTOF)|g' \
-e 's|@''REPLACE_STRTOL''@|$(REPLACE_STRTOL)|g' \
-e 's|@''REPLACE_STRTOLD''@|$(REPLACE_STRTOLD)|g' \
-e 's|@''REPLACE_STRTOLL''@|$(REPLACE_STRTOLL)|g' \
+37
View File
@@ -0,0 +1,37 @@
Description:
strtof() function: convert string to 'float'.
Files:
lib/strtof.c
lib/strtod.c
m4/strtof.m4
m4/ldexpf.m4
Depends-on:
stdlib
c-ctype [test $HAVE_STRTOF = 0 || test $REPLACE_STRTOF = 1]
math [test $HAVE_STRTOF = 0 || test $REPLACE_STRTOF = 1]
stdbool [test $HAVE_STRTOF = 0 || test $REPLACE_STRTOF = 1]
configure.ac:
gl_FUNC_STRTOF
gl_CONDITIONAL([GL_COND_OBJ_STRTOF],
[test $HAVE_STRTOF = 0 || test $REPLACE_STRTOF = 1])
AM_COND_IF([GL_COND_OBJ_STRTOF], [
gl_PREREQ_STRTOF
])
gl_STDLIB_MODULE_INDICATOR([strtof])
Makefile.am:
if GL_COND_OBJ_STRTOF
lib_SOURCES += strtof.c
endif
Include:
<stdlib.h>
License:
LGPL
Maintainer:
all
+4
View File
@@ -187,6 +187,10 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::setenv, int,
SIGNATURE_CHECK (GNULIB_NAMESPACE::strtod, double, (const char *, char **));
#endif
#if GNULIB_TEST_STRTOF
SIGNATURE_CHECK (GNULIB_NAMESPACE::strtof, float, (const char *, char **));
#endif
#if GNULIB_TEST_STRTOLL
SIGNATURE_CHECK (GNULIB_NAMESPACE::strtoll, long long,
(const char *, char **, int));