From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS22989 209.51.188.0/24 X-Spam-Status: No, score=-3.8 required=3.0 tests=AWL,BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,SPF_PASS shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by dcvr.yhbt.net (Postfix) with ESMTPS id 9AB701F453 for ; Wed, 30 Jan 2019 03:06:15 +0000 (UTC) Received: from localhost ([127.0.0.1]:59546 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gogCc-0001XT-0p for normalperson@yhbt.net; Tue, 29 Jan 2019 22:06:14 -0500 Received: from eggs.gnu.org ([209.51.188.92]:33373) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gogCT-0001XG-Aj for bug-gnulib@gnu.org; Tue, 29 Jan 2019 22:06:10 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gogCO-0000nY-DV for bug-gnulib@gnu.org; Tue, 29 Jan 2019 22:06:05 -0500 Received: from mo6-p00-ob.smtp.rzone.de ([2a01:238:20a:202:5300::8]:15292) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gogCJ-0000dW-GE for bug-gnulib@gnu.org; Tue, 29 Jan 2019 22:05:57 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1548817550; s=strato-dkim-0002; d=clisp.org; h=Message-ID:Date:Subject:To:From:X-RZG-CLASS-ID:X-RZG-AUTH:From: Subject:Sender; bh=WuVdXl5aik8BG18uOJwL1VQTjqV+BJSnTkubzF8Vy3w=; b=qlQd4HrRXgcGbPwKUtdLQLLa6/YO4/e+hdjgYtWQAWs3rOO5GAXNFDe9IbbF4rvq8a SsZVbZsUr+VBagIPpES6d3Pwu4toysbwaR1zMf4+QZXvLVsd+08PzPeVvprhaAWvRbuu t61bqt+o3U4EuXpQDFIOF6qXaGmz60Zg09rerhdISf0cV7tOwImON69S2HDJUdnhoSI0 Lql9mmm8LeRc025QQfyOwBUbfVvns8ezSgR1fj0aqkDekq1lrI7ob9tv4u903xtv5vEr 8Yv5wuQCEaKu/2quJMHP3Ja5WOQ498P2f7H0kyvQi6uNSdlxnpPFTe7xVdJRiSOsHNpg ZxPg== X-RZG-AUTH: ":Ln4Re0+Ic/6oZXR1YgKryK8brlshOcZlIWs+iCP5vnk6shH+AHjwLuWOGKf2y/s=" X-RZG-CLASS-ID: mo00 Received: from bruno.haible.de by smtp.strato.de (RZmta 44.9 DYNA|AUTH) with ESMTPSA id v0a34ev0U35n5Au (using TLSv1 with cipher ECDHE-RSA-AES256-SHA (curve secp521r1 with 521 ECDH bits, eq. 15360 bits RSA)) (Client did not present a certificate); Wed, 30 Jan 2019 04:05:49 +0100 (CET) From: Bruno Haible To: bug-gnulib@gnu.org Subject: new module 'strtold' Date: Wed, 30 Jan 2019 04:05:49 +0100 Message-ID: <15810183.GCsTEvYtY3@omega> User-Agent: KMail/5.1.3 (Linux/4.4.0-141-generic; KDE/5.18.0; x86_64; ; ) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="nextPart6055991.vFM6qUVRua" Content-Transfer-Encoding: 7Bit X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a01:238:20a:202:5300::8 X-BeenThere: bug-gnulib@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Gnulib discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnulib-bounces+normalperson=yhbt.net@gnu.org Sender: "bug-gnulib" This is a multi-part message in MIME format. --nextPart6055991.vFM6qUVRua Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="us-ascii" Hi, coreutils has recently started to use strtold() [1]. This causes compilation errors on Android 4.3: CC lib/cl-strtod.o CC lib/cl-strtold.o In file included from ../lib/cl-strtold.c:2: ../lib/cl-strtod.c: In function 'cl_strtold': ../lib/cl-strtod.c:62: warning: implicit declaration of function 'strtold' CCLD src/printf lib/libcoreutils.a(cl-strtold.o): In function `cl_strtold': cl-strtold.c:(.text+0x14): undefined reference to `strtold' collect2: ld returned 1 exit status make[2]: *** [src/printf] Error 1 CCLD src/seq lib/libcoreutils.a(cl-strtold.o): In function `cl_strtold': cl-strtold.c:(.text+0x14): undefined reference to `strtold' collect2: ld returned 1 exit status make[2]: *** [src/seq] Error 1 and similarly on Solaris 9 (both lack the strtold() function) and on HP-UX 11/hppa (where the function is declared to return a struct, not a 'long double'). And of course the function is not POSIX compliant on some platforms. Here comes a new gnulib module 'strtold'. Tested on - a glibc 2.3.2 system (Fedora 1) - Mac OS X 10.5, Mac OS X 10.4/PowerPC - FreeBSD 11.0 - NetBSD 7.1 - OpenBSD 6.0 - Minix 3.3 - AIX 7.1 - HP-UX 11.31/hppa - HP-UX 11.31/ia64 (test failure in line 574, also in test-strtod.c:574) - IRIX 6.5 - Solaris 9/SPARC, Solaris 10/SPARC, Solaris 10/x86 - Cygwin - mingw - Haiku - Android 4.3 Bruno [1] https://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=commitdiff;h=eb73e23f31f4ce363b1505cc77424832d5c39063 2019-01-29 Bruno Haible strtold: New module. * lib/stdlib.in.h (strtold): New declaration. * lib/strtold.c: New file. * lib/strtod.c: Consider USE_LONG_DOUBLE. (STRTOD, LDEXP, HAVE_UNDERLYING_STRTOD, DOUBLE, MIN, MAX, L_, USE_LDEXP): New macros. (LDEXP, scale_radix_exp, parse_number, STRTOD): Adapt for USE_LONG_DOUBLE. (underlying_strtod): Remove function. Replace with some macros. Re-add the code for a missing underlying function that was removed on 2013-02-19. * m4/strtold.m4: New file. * m4/stdlib_h.m4 (gl_STDLIB_H): Test whether strtold is declared. (gl_STDLIB_H_DEFAULTS): Initialize GNULIB_STRTOLD, HAVE_STRTOLD, REPLACE_STRTOLD. * modules/stdlib (Makefile.am): Substitute GNULIB_STRTOLD, HAVE_STRTOLD, REPLACE_STRTOLD. * modules/strtold: New file. * doc/posix-functions/strtold.texi: Document the new module. 2019-01-29 Bruno Haible strtold: Add tests. * tests/test-strtold.c: New file, based on tests/test-strtod.c. * modules/strtold-tests: New file. --nextPart6055991.vFM6qUVRua Content-Disposition: attachment; filename="0001-strtold-New-module.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="UTF-8"; name="0001-strtold-New-module.patch" >From ebad0cfebbb201a4e645495d244f899a39a305e3 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 30 Jan 2019 03:52:31 +0100 Subject: [PATCH 1/2] strtold: New module. * lib/stdlib.in.h (strtold): New declaration. * lib/strtold.c: New file. * lib/strtod.c: Consider USE_LONG_DOUBLE. (STRTOD, LDEXP, HAVE_UNDERLYING_STRTOD, DOUBLE, MIN, MAX, L_, USE_LDEXP): New macros. (LDEXP, scale_radix_exp, parse_number, STRTOD): Adapt for USE_LONG_DOUBLE. (underlying_strtod): Remove function. Replace with some macros. Re-add the code for a missing underlying function that was removed on 2013-02-19. * m4/strtold.m4: New file. * m4/stdlib_h.m4 (gl_STDLIB_H): Test whether strtold is declared. (gl_STDLIB_H_DEFAULTS): Initialize GNULIB_STRTOLD, HAVE_STRTOLD, REPLACE_STRTOLD. * modules/stdlib (Makefile.am): Substitute GNULIB_STRTOLD, HAVE_STRTOLD, REPLACE_STRTOLD. * modules/strtold: New file. * doc/posix-functions/strtold.texi: Document the new module. --- ChangeLog | 22 +++++++ doc/posix-functions/strtold.texi | 54 +++++++++++++++++- lib/stdlib.in.h | 25 ++++++++ lib/strtod.c | 113 +++++++++++++++++++++++------------- lib/strtold.c | 37 ++++++++++++ m4/stdlib_h.m4 | 7 ++- m4/strtold.m4 | 120 +++++++++++++++++++++++++++++++++++++++ modules/stdlib | 3 + modules/strtold | 35 ++++++++++++ 9 files changed, 371 insertions(+), 45 deletions(-) create mode 100644 lib/strtold.c create mode 100644 m4/strtold.m4 create mode 100644 modules/strtold diff --git a/ChangeLog b/ChangeLog index 51daf91..ef10452 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,27 @@ 2019-01-29 Bruno Haible + strtold: New module. + * lib/stdlib.in.h (strtold): New declaration. + * lib/strtold.c: New file. + * lib/strtod.c: Consider USE_LONG_DOUBLE. + (STRTOD, LDEXP, HAVE_UNDERLYING_STRTOD, DOUBLE, MIN, MAX, L_, + USE_LDEXP): New macros. + (LDEXP, scale_radix_exp, parse_number, STRTOD): Adapt for + USE_LONG_DOUBLE. + (underlying_strtod): Remove function. Replace with some macros. + Re-add the code for a missing underlying function that was removed on + 2013-02-19. + * m4/strtold.m4: New file. + * m4/stdlib_h.m4 (gl_STDLIB_H): Test whether strtold is declared. + (gl_STDLIB_H_DEFAULTS): Initialize GNULIB_STRTOLD, HAVE_STRTOLD, + REPLACE_STRTOLD. + * modules/stdlib (Makefile.am): Substitute GNULIB_STRTOLD, HAVE_STRTOLD, + REPLACE_STRTOLD. + * modules/strtold: New file. + * doc/posix-functions/strtold.texi: Document the new module. + +2019-01-29 Bruno Haible + strtod: Fix compilation error on IRIX 6.5. * modules/strtod (Depends-on): Add 'math'. diff --git a/doc/posix-functions/strtold.texi b/doc/posix-functions/strtold.texi index ff6f195..f136c54 100644 --- a/doc/posix-functions/strtold.texi +++ b/doc/posix-functions/strtold.texi @@ -4,15 +4,63 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/strtold.html} -Gnulib module: --- +Gnulib module: strtold Portability problems fixed by Gnulib: @itemize +@item +This function is missing on some platforms: +NetBSD 3.0, OpenBSD 3.8, Minix 3.1.8, older IRIX 6.5, OSF/1 4.0, Solaris 9, older Cygwin, MSVC 9, Interix 3.5, BeOS, Android 4.4. + +@item +This function returns a struct, not a @code{long double}, on some platforms: +HP-UX 11.31/hppa. + +@item +This function consumes whitespace even when there is nothing that should +be parsed on some platforms: +IRIX 6.5. + +@item +This function allows whitespace between @samp{e} and the exponent on +some platforms: +HP-UX 11.31/ia64, IRIX 6.5. + +@item +This function returns the wrong end pointer for @samp{-0x} on some +platforms: +glibc-2.3.2, Mac OS X 10.5, Haiku. + +@item +This function returns +0.0 (not @minus{}0.0) for @samp{-0} on some platforms: +IRIX 6.5. + +@item +This function fails to parse Infinities and plain NaNs on some platforms: +HP-UX 11.31/ia64, IRIX 6.5. + +@item +This function fails to parse @samp{NaN()} on some platforms: +glibc-2.3.2, IRIX 6.5, mingw, Haiku. + +@item +This function fails to parse @samp{NaN(@var{n-char-sequence})} on some +platforms: +IRIX 6.5. + +@item +This function parses @samp{NaN(@var{n-char-sequence})}, but returns +the wrong end pointer on some platforms: +glibc-2.3.2, mingw, Haiku. + +@item +This function fails to parse C99 hexadecimal floating point on some +platforms: +IRIX 6.5, mingw. @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, IRIX 6.5, OSF/1 4.0, Solaris 9, Cygwin, MSVC 9, Interix 3.5, BeOS, Android 4.4. +The replacement function does not always return correctly rounded results. @end itemize diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h index be8ab3b..b70444d 100644 --- a/lib/stdlib.in.h +++ b/lib/stdlib.in.h @@ -948,6 +948,31 @@ _GL_WARN_ON_USE (strtod, "strtod is unportable - " # endif #endif +#if @GNULIB_STRTOLD@ + /* Parse a 'long double' from STRING, updating ENDP if appropriate. */ +# if @REPLACE_STRTOLD@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# define strtold rpl_strtold +# endif +_GL_FUNCDECL_RPL (strtold, long double, (const char *str, char **endp) + _GL_ARG_NONNULL ((1))); +_GL_CXXALIAS_RPL (strtold, long double, (const char *str, char **endp)); +# else +# if !@HAVE_STRTOLD@ +_GL_FUNCDECL_SYS (strtold, long double, (const char *str, char **endp) + _GL_ARG_NONNULL ((1))); +# endif +_GL_CXXALIAS_SYS (strtold, long double, (const char *str, char **endp)); +# endif +_GL_CXXALIASWARN (strtold); +#elif defined GNULIB_POSIXCHECK +# undef strtold +# if HAVE_RAW_DECL_STRTOLD +_GL_WARN_ON_USE (strtold, "strtold is unportable - " + "use gnulib module strtold 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/lib/strtod.c b/lib/strtod.c index 9a28f4b..1d1ba27 100644 --- a/lib/strtod.c +++ b/lib/strtod.c @@ -14,8 +14,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include +#if ! defined USE_LONG_DOUBLE +# include +#endif +/* Specification. */ #include #include @@ -28,8 +31,36 @@ #include "c-ctype.h" -#ifndef HAVE_LDEXP_IN_LIBC -#define HAVE_LDEXP_IN_LIBC 0 +#undef MIN +#undef MAX +#ifdef USE_LONG_DOUBLE +# define STRTOD strtold +# define LDEXP ldexpl +# if defined __hpux && defined __hppa + /* We cannot call strtold on HP-UX/hppa, because its return type is a struct, + not a 'long double'. */ +# define HAVE_UNDERLYING_STRTOD 0 +# else +# define HAVE_UNDERLYING_STRTOD HAVE_STRTOLD +# endif +# define DOUBLE long double +# define MIN LDBL_MIN +# define MAX LDBL_MAX +# define L_(literal) literal##L +#else +# define STRTOD strtod +# define LDEXP ldexp +# define HAVE_UNDERLYING_STRTOD 1 +# define DOUBLE double +# 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 #endif /* Return true if C is a space in the current locale, avoiding @@ -41,20 +72,21 @@ locale_isspace (char c) return isspace (uc) != 0; } -#if !HAVE_LDEXP_IN_LIBC - #define ldexp dummy_ldexp +#if !USE_LDEXP + #undef LDEXP + #define LDEXP dummy_ldexp /* A dummy definition that will never be invoked. */ - static double ldexp (double x _GL_UNUSED, int exponent _GL_UNUSED) + static DOUBLE LDEXP (DOUBLE x _GL_UNUSED, int exponent _GL_UNUSED) { abort (); - return 0.0; + return L_(0.0); } #endif /* Return X * BASE**EXPONENT. Return an extreme value and set errno to ERANGE if underflow or overflow occurs. */ -static double -scale_radix_exp (double x, int radix, long int exponent) +static DOUBLE +scale_radix_exp (DOUBLE x, int radix, long int exponent) { /* If RADIX == 10, this code is neither precise nor fast; it is merely a straightforward and relatively portable approximation. @@ -63,11 +95,11 @@ scale_radix_exp (double x, int radix, long int exponent) long int e = exponent; - if (HAVE_LDEXP_IN_LIBC && radix == 2) - return ldexp (x, e < INT_MIN ? INT_MIN : INT_MAX < e ? INT_MAX : e); + if (USE_LDEXP && radix == 2) + return LDEXP (x, e < INT_MIN ? INT_MIN : INT_MAX < e ? INT_MAX : e); else { - double r = x; + DOUBLE r = x; if (r != 0) { @@ -87,12 +119,12 @@ scale_radix_exp (double x, int radix, long int exponent) { while (e-- != 0) { - if (r < -DBL_MAX / radix) + if (r < -MAX / radix) { errno = ERANGE; return -HUGE_VAL; } - else if (DBL_MAX / radix < r) + else if (MAX / radix < r) { errno = ERANGE; return HUGE_VAL; @@ -113,7 +145,7 @@ scale_radix_exp (double x, int radix, long int exponent) radix RADIX (either 10 or 2) exponent, and exponent character EXPCHAR. To convert from a number of digits to a radix exponent, multiply by RADIX_MULTIPLIER (either 1 or 4). */ -static double +static DOUBLE parse_number (const char *nptr, int base, int radix, int radix_multiplier, char expchar, char **endptr) @@ -121,7 +153,7 @@ parse_number (const char *nptr, const char *s = nptr; bool got_dot = false; long int exponent = 0; - double num = 0; + DOUBLE num = 0; for (;; ++s) { @@ -141,12 +173,12 @@ parse_number (const char *nptr, break; /* Make sure that multiplication by base will not overflow. */ - if (num <= DBL_MAX / base) + if (num <= MAX / base) num = num * base + digit; else { /* The value of the digit doesn't matter, since we have already - gotten as many digits as can be represented in a 'double'. + gotten as many digits as can be represented in a 'DOUBLE'. This doesn't necessarily mean the result will overflow. The exponent may reduce it to within range. @@ -185,32 +217,42 @@ parse_number (const char *nptr, return scale_radix_exp (num, radix, exponent); } -static double underlying_strtod (const char *, char **); - /* HP cc on HP-UX 10.20 has a bug with the constant expression -0.0. ICC 10.0 has a bug when optimizing the expression -zero. - The expression -DBL_MIN * DBL_MIN does not work when cross-compiling + The expression -MIN * MIN does not work when cross-compiling to PowerPC on Mac OS X 10.5. */ #if defined __hpux || defined __sgi || defined __ICC -static double +static DOUBLE compute_minus_zero (void) { - return -DBL_MIN * DBL_MIN; + return -MIN * MIN; } # define minus_zero compute_minus_zero () #else -double minus_zero = -0.0; +DOUBLE minus_zero = -0.0; #endif -/* Convert NPTR to a double. If ENDPTR is not NULL, a pointer to the +/* Convert NPTR to a DOUBLE. If ENDPTR is not NULL, a pointer to the character after the last one used in the number is put in *ENDPTR. */ -double -strtod (const char *nptr, char **endptr) +DOUBLE +STRTOD (const char *nptr, char **endptr) +#if HAVE_UNDERLYING_STRTOD +# ifdef USE_LONG_DOUBLE +# undef strtold +# else +# undef strtod +# endif +#else +# undef STRTOD +# define STRTOD(NPTR,ENDPTR) parse_number (NPTR, 10, 10, 1, 'e', ENDPTR) +#endif +/* From here on, STRTOD refers to the underlying implementation. It needs + to handle only finite unsigned decimal numbers with non-null ENDPTR. */ { bool negative = false; /* The number so far. */ - double num; + DOUBLE num; const char *s = nptr; const char *end; @@ -226,7 +268,7 @@ strtod (const char *nptr, char **endptr) if (*s == '-' || *s == '+') ++s; - num = underlying_strtod (s, &endbuf); + num = STRTOD (s, &endbuf); end = endbuf; if (c_isdigit (s[*s == '.'])) @@ -261,7 +303,7 @@ strtod (const char *nptr, char **endptr) else { /* If "1e 1" was misparsed as 10.0 instead of 1.0, re-do the - underlying strtod on a copy of the original string + underlying STRTOD on a copy of the original string truncated to avoid the bug. */ const char *e = s + 1; while (e < end && c_tolower (*e) != 'e') @@ -279,7 +321,7 @@ strtod (const char *nptr, char **endptr) else { dup[e - s] = '\0'; - num = underlying_strtod (dup, &endbuf); + num = STRTOD (dup, &endbuf); saved_errno = errno; free (dup); errno = saved_errno; @@ -344,12 +386,3 @@ strtod (const char *nptr, char **endptr) return minus_zero; return negative ? -num : num; } - -/* The underlying strtod implementation. This must be defined - after strtod because it #undefs strtod. */ -static double -underlying_strtod (const char *nptr, char **endptr) -{ -#undef strtod - return strtod (nptr, endptr); -} diff --git a/lib/strtold.c b/lib/strtold.c new file mode 100644 index 0000000..3791303 --- /dev/null +++ b/lib/strtold.c @@ -0,0 +1,37 @@ +/* Convert string to 'long double'. + Copyright (C) 2019 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Bruno Haible , 2019. */ + +#include + +#if HAVE_SAME_LONG_DOUBLE_AS_DOUBLE + +/* Specification. */ +# include + +long double +strtold (const char *str, char **endp) +{ + return strtod (str, endp); +} + +#else + +# define USE_LONG_DOUBLE +# include "strtod.c" + +#endif diff --git a/m4/stdlib_h.m4 b/m4/stdlib_h.m4 index c5db804..6121602 100644 --- a/m4/stdlib_h.m4 +++ b/m4/stdlib_h.m4 @@ -1,4 +1,4 @@ -# stdlib_h.m4 serial 47 +# stdlib_h.m4 serial 48 dnl Copyright (C) 2007-2019 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -26,7 +26,7 @@ AC_DEFUN([gl_STDLIB_H], initstate initstate_r mbtowc mkdtemp mkostemp mkostemps mkstemp mkstemps posix_openpt ptsname ptsname_r qsort_r random random_r reallocarray realpath rpmatch secure_getenv setenv setstate setstate_r srandom - srandom_r strtod strtoll strtoull unlockpt unsetenv]) + srandom_r strtod strtold strtoll strtoull unlockpt unsetenv]) ]) AC_DEFUN([gl_STDLIB_MODULE_INDICATOR], @@ -68,6 +68,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_STRTOLD=0; AC_SUBST([GNULIB_STRTOLD]) GNULIB_STRTOLL=0; AC_SUBST([GNULIB_STRTOLL]) GNULIB_STRTOULL=0; AC_SUBST([GNULIB_STRTOULL]) GNULIB_SYSTEM_POSIX=0; AC_SUBST([GNULIB_SYSTEM_POSIX]) @@ -105,6 +106,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_STRTOLD=1; AC_SUBST([HAVE_STRTOLD]) HAVE_STRTOLL=1; AC_SUBST([HAVE_STRTOLL]) HAVE_STRTOULL=1; AC_SUBST([HAVE_STRTOULL]) HAVE_STRUCT_RANDOM_DATA=1; AC_SUBST([HAVE_STRUCT_RANDOM_DATA]) @@ -128,6 +130,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_STRTOLD=0; AC_SUBST([REPLACE_STRTOLD]) REPLACE_UNSETENV=0; AC_SUBST([REPLACE_UNSETENV]) REPLACE_WCTOMB=0; AC_SUBST([REPLACE_WCTOMB]) ]) diff --git a/m4/strtold.m4 b/m4/strtold.m4 new file mode 100644 index 0000000..117b7f1 --- /dev/null +++ b/m4/strtold.m4 @@ -0,0 +1,120 @@ +# strtold.m4 serial 1 +dnl Copyright (C) 2002-2003, 2006-2019 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_STRTOLD], +[ + AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) + AC_REQUIRE([gl_LONG_DOUBLE_VS_DOUBLE]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CHECK_FUNCS_ONCE([strtold]) + if test $ac_cv_func_strtold != yes; then + HAVE_STRTOLD=0 + else + AC_CACHE_CHECK([whether strtold obeys C99], [gl_cv_func_strtold_works], + [AC_RUN_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include +/* Compare two numbers with ==. + This is a separate function because IRIX 6.5 "cc -O" miscompiles an + 'x == x' test. */ +static int +numeric_equal (long double x, long double y) +{ + return x == y; +} +]], [[ + int result = 0; + { + /* Under Solaris 2.4, strtod returns the wrong value for the + terminating character under some conditions. */ + const char *string = "NaN"; + char *term; + strtod (string, &term); + if (term != string && *(term - 1) == 0) + result |= 2; + } + { + /* Older glibc and Cygwin mis-parse "-0x". */ + const char *string = "-0x"; + char *term; + long double value = strtold (string, &term); + long double zero = 0.0L; + if (1.0L / value != -1.0L / zero || term != (string + 2)) + result |= 4; + } + { + /* IRIX 6.5, mingw do not parse hex floats. */ + const char *string = "0XaP+1"; + char *term; + long double value = strtold (string, &term); + if (value != 20.0L || term != (string + 6)) + result |= 8; + } + { + /* IRIX 6.5 does not parse infinities. HP-UX 11.31/ia64 parses inf, + but mistakenly sets errno. */ + const char *string = "inf"; + char *term; + long double value; + errno = 0; + value = strtod (string, &term); + if (value != HUGE_VAL || term != (string + 3) || errno) + result |= 16; + } + { + /* glibc-2.3.2, IRIX 6.5, mingw, Haiku misparse "nan()". */ + const char *string = "nan()"; + char *term; + long double value = strtold (string, &term); + if (numeric_equal (value, value) || term != (string + 5)) + result |= 32; + } + { + /* Mac OS X 10.5, IRIX 6.5 misparse "nan(". */ + const char *string = "nan("; + char *term; + long double value = strtold (string, &term); + if (numeric_equal (value, value) || term != (string + 3)) + result |= 64; + } + return result; +]])], + [gl_cv_func_strtold_works=yes], + [gl_cv_func_strtold_works=no], + [dnl The last known bugs in glibc strtold(), as of this writing, + dnl were fixed in version 2.8 + AC_EGREP_CPP([Lucky user], + [ +#include +#ifdef __GNU_LIBRARY__ + #if ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) || (__GLIBC__ > 2)) \ + && !defined __UCLIBC__ + Lucky user + #endif +#endif + ], + [gl_cv_func_strtold_works="guessing yes"], + [gl_cv_func_strtod_works="guessing no"]) + ]) + ]) + case "$gl_cv_func_strtold_works" in + *yes) ;; + *) + REPLACE_STRTOLD=1 + ;; + esac + fi +]) + +# Prerequisites of lib/strtold.c. +AC_DEFUN([gl_PREREQ_STRTOLD], [ + AC_REQUIRE([gl_CHECK_LDEXPL_NO_LIBM]) + if test $gl_cv_func_ldexpl_no_libm = yes; then + AC_DEFINE([HAVE_LDEXPL_IN_LIBC], [1], + [Define if the ldexpl function is available in libc.]) + fi +]) diff --git a/modules/stdlib b/modules/stdlib index a43f79c..ea838c9 100644 --- a/modules/stdlib +++ b/modules/stdlib @@ -59,6 +59,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_STRTOLD''@/$(GNULIB_STRTOLD)/g' \ -e 's/@''GNULIB_STRTOLL''@/$(GNULIB_STRTOLL)/g' \ -e 's/@''GNULIB_STRTOULL''@/$(GNULIB_STRTOULL)/g' \ -e 's/@''GNULIB_SYSTEM_POSIX''@/$(GNULIB_SYSTEM_POSIX)/g' \ @@ -95,6 +96,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_STRTOLD''@|$(HAVE_STRTOLD)|g' \ -e 's|@''HAVE_STRTOLL''@|$(HAVE_STRTOLL)|g' \ -e 's|@''HAVE_STRTOULL''@|$(HAVE_STRTOULL)|g' \ -e 's|@''HAVE_STRUCT_RANDOM_DATA''@|$(HAVE_STRUCT_RANDOM_DATA)|g' \ @@ -118,6 +120,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_STRTOLD''@|$(REPLACE_STRTOLD)|g' \ -e 's|@''REPLACE_UNSETENV''@|$(REPLACE_UNSETENV)|g' \ -e 's|@''REPLACE_WCTOMB''@|$(REPLACE_WCTOMB)|g' \ -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ diff --git a/modules/strtold b/modules/strtold new file mode 100644 index 0000000..f99b9e6 --- /dev/null +++ b/modules/strtold @@ -0,0 +1,35 @@ +Description: +strtold() function: convert string to 'long double'. + +Files: +lib/strtold.c +lib/strtod.c +m4/strtold.m4 +m4/math_h.m4 +m4/ldexpl.m4 + +Depends-on: +stdlib +c-ctype [test $HAVE_STRTOLD = 0 || test $REPLACE_STRTOLD = 1] +math [test $HAVE_STRTOLD = 0 || test $REPLACE_STRTOLD = 1] +stdbool [test $HAVE_STRTOLD = 0 || test $REPLACE_STRTOLD = 1] +strtod [{ test $HAVE_STRTOLD = 0 || test $REPLACE_STRTOLD = 1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1] + +configure.ac: +gl_FUNC_STRTOLD +if test $HAVE_STRTOLD = 0 || test $REPLACE_STRTOLD = 1; then + AC_LIBOBJ([strtold]) + gl_PREREQ_STRTOLD +fi +gl_STDLIB_MODULE_INDICATOR([strtold]) + +Makefile.am: + +Include: + + +License: +LGPL + +Maintainer: +all -- 2.7.4 --nextPart6055991.vFM6qUVRua Content-Disposition: attachment; filename="0002-strtold-Add-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="UTF-8"; name="0002-strtold-Add-tests.patch" >From c39d926ef784d4c9de90e48a5aca16d0acd57512 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 30 Jan 2019 03:53:43 +0100 Subject: [PATCH 2/2] strtold: Add tests. * tests/test-strtold.c: New file, based on tests/test-strtod.c. * modules/strtold-tests: New file. --- ChangeLog | 6 + modules/strtold-tests | 16 + tests/test-strtold.c | 986 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1008 insertions(+) create mode 100644 modules/strtold-tests create mode 100644 tests/test-strtold.c diff --git a/ChangeLog b/ChangeLog index ef10452..5ab5d83 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2019-01-29 Bruno Haible + strtold: Add tests. + * tests/test-strtold.c: New file, based on tests/test-strtod.c. + * modules/strtold-tests: New file. + +2019-01-29 Bruno Haible + strtold: New module. * lib/stdlib.in.h (strtold): New declaration. * lib/strtold.c: New file. diff --git a/modules/strtold-tests b/modules/strtold-tests new file mode 100644 index 0000000..8a812d2 --- /dev/null +++ b/modules/strtold-tests @@ -0,0 +1,16 @@ +Files: +tests/test-strtold.c +tests/signature.h +tests/minus-zero.h +tests/macros.h + +Depends-on: +float +isnanl-nolibm +signbit + +configure.ac: + +Makefile.am: +TESTS += test-strtold +check_PROGRAMS += test-strtold diff --git a/tests/test-strtold.c b/tests/test-strtold.c new file mode 100644 index 0000000..cd31787 --- /dev/null +++ b/tests/test-strtold.c @@ -0,0 +1,986 @@ +/* + * Copyright (C) 2008-2019 Free Software Foundation, Inc. + * Written by Eric Blake + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + +#include + +#include + +#include "signature.h" +SIGNATURE_CHECK (strtold, long double, (char const *, char **)); + +#include +#include +#include +#include + +#include "isnanl-nolibm.h" +#include "minus-zero.h" +#include "macros.h" + +/* Avoid requiring -lm just for fabsl. */ +#define FABSL(d) ((d) < 0.0L ? -(d) : (d)) + +int +main (void) +{ + int status = 0; + /* Subject sequence empty or invalid. */ + { + const char input[] = ""; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input); + ASSERT (errno == 0 || errno == EINVAL); + } + { + const char input[] = " "; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input); + ASSERT (errno == 0 || errno == EINVAL); + } + { + const char input[] = " +"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input); + ASSERT (errno == 0 || errno == EINVAL); + } + { + const char input[] = " ."; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input); + ASSERT (errno == 0 || errno == EINVAL); + } + { + const char input[] = " .e0"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input); /* IRIX 6.5 */ + ASSERT (errno == 0 || errno == EINVAL); + } + { + const char input[] = " +.e-0"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input); /* IRIX 6.5 */ + ASSERT (errno == 0 || errno == EINVAL); + } + { + const char input[] = " in"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input); + ASSERT (errno == 0 || errno == EINVAL); + } + { + const char input[] = " na"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input); + ASSERT (errno == 0 || errno == EINVAL); + } + + /* Simple floating point values. */ + { + const char input[] = "1"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + 1); + ASSERT (errno == 0); + } + { + const char input[] = "1."; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + 2); + ASSERT (errno == 0); + } + { + const char input[] = ".5"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + /* FIXME - gnulib's version is rather inaccurate. It would be + nice to guarantee an exact result, but for now, we settle for a + 1-ulp error. */ + ASSERT (FABSL (result - 0.5L) < LDBL_EPSILON); + ASSERT (ptr == input + 2); + ASSERT (errno == 0); + } + { + const char input[] = " 1"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + 2); + ASSERT (errno == 0); + } + { + const char input[] = "+1"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + 2); + ASSERT (errno == 0); + } + { + const char input[] = "-1"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == -1.0L); + ASSERT (ptr == input + 2); + ASSERT (errno == 0); + } + { + const char input[] = "1e0"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + 3); + ASSERT (errno == 0); + } + { + const char input[] = "1e+0"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + 4); + ASSERT (errno == 0); + } + { + const char input[] = "1e-0"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + 4); + ASSERT (errno == 0); + } + { + const char input[] = "1e1"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 10.0L); + ASSERT (ptr == input + 3); + ASSERT (errno == 0); + } + { + const char input[] = "5e-1"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + /* FIXME - gnulib's version is rather inaccurate. It would be + nice to guarantee an exact result, but for now, we settle for a + 1-ulp error. */ + ASSERT (FABSL (result - 0.5L) < LDBL_EPSILON); + ASSERT (ptr == input + 4); + ASSERT (errno == 0); + } + + /* Zero. */ + { + const char input[] = "0"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 1); + ASSERT (errno == 0); + } + { + const char input[] = ".0"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 2); + ASSERT (errno == 0); + } + { + const char input[] = "0e0"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 3); + ASSERT (errno == 0); + } + { + const char input[] = "0e+9999999"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 10); + ASSERT (errno == 0); + } + { + const char input[] = "0e-9999999"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 10); + ASSERT (errno == 0); + } + { + const char input[] = "-0"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!!signbit (result) == !!signbit (minus_zerol)); /* IRIX 6.5 */ + ASSERT (ptr == input + 2); + ASSERT (errno == 0); + } + + /* Suffixes. */ + { + const char input[] = "1f"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + 1); + ASSERT (errno == 0); + } + { + const char input[] = "1.f"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + 2); + ASSERT (errno == 0); + } + { + const char input[] = "1e"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + 1); + ASSERT (errno == 0); + } + { + const char input[] = "1e+"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + 1); + ASSERT (errno == 0); + } + { + const char input[] = "1e-"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + 1); + ASSERT (errno == 0); + } + { + const char input[] = "1E 2"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); /* HP-UX 11.31/ia64, IRIX 6.5 */ + ASSERT (ptr == input + 1); /* HP-UX 11.31/ia64, IRIX 6.5 */ + ASSERT (errno == 0); + } + { + const char input[] = "0x"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 1); /* glibc-2.3.2, Mac OS X 10.5, Haiku */ + ASSERT (errno == 0); + } + { + const char input[] = "00x1"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 2); + ASSERT (errno == 0); + } + { + const char input[] = "-0x"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!!signbit (result) == !!signbit (minus_zerol)); /* Mac OS X 10.5, IRIX 6.5 */ + ASSERT (ptr == input + 2); /* glibc-2.3.2, Mac OS X 10.5, Haiku */ + ASSERT (errno == 0); + } + { + const char input[] = "0xg"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 1); /* glibc-2.3.2, Mac OS X 10.5, Haiku */ + ASSERT (errno == 0); + } + { + const char input[] = "0xp"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 1); /* glibc-2.3.2, Mac OS X 10.5, Haiku */ + ASSERT (errno == 0); + } + { + const char input[] = "0XP"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 1); /* glibc-2.3.2, Mac OS X 10.5, Haiku */ + ASSERT (errno == 0); + } + { + const char input[] = "0x."; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 1); /* glibc-2.3.2, Mac OS X 10.5, Haiku */ + ASSERT (errno == 0); + } + { + const char input[] = "0xp+"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 1); /* glibc-2.3.2, Mac OS X 10.5, Haiku */ + ASSERT (errno == 0); + } + { + const char input[] = "0xp+1"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 1); /* glibc-2.3.2, Mac OS X 10.5, Haiku */ + ASSERT (errno == 0); + } + { + const char input[] = "0x.p+1"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 1); /* glibc-2.3.2, Mac OS X 10.5, Haiku */ + ASSERT (errno == 0); + } + { + const char input[] = "1p+1"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + 1); + ASSERT (errno == 0); + } + { + const char input[] = "1P+1"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + 1); + ASSERT (errno == 0); + } + + /* Overflow/underflow. */ + { + const char input[] = "1E1000000"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == HUGE_VALL); + ASSERT (ptr == input + 9); + ASSERT (errno == ERANGE); + } + { + const char input[] = "-1E1000000"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == -HUGE_VALL); + ASSERT (ptr == input + 10); + ASSERT (errno == ERANGE); + } + { + const char input[] = "1E-100000"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (0.0L <= result && result <= LDBL_MIN); + ASSERT (!signbit (result)); + ASSERT (ptr == input + 9); + ASSERT (errno == ERANGE); + } + { + const char input[] = "-1E-100000"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (-LDBL_MIN <= result && result <= 0.0L); +#if 0 + /* FIXME - this is glibc bug 5995; POSIX allows returning positive + 0 on negative underflow, even though quality of implementation + demands preserving the sign. Disable this test until fixed + glibc is more prevalent. */ + ASSERT (!!signbit (result) == !!signbit (minus_zerol)); /* glibc-2.3.2, Haiku */ +#endif + ASSERT (ptr == input + 10); + ASSERT (errno == ERANGE); + } + { + const char input[] = "1E 1000000"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); /* HP-UX 11.31/ia64, IRIX 6.5 */ + ASSERT (ptr == input + 1); /* HP-UX 11.31/ia64, IRIX 6.5 */ + ASSERT (errno == 0); /* HP-UX 11.31/ia64, IRIX 6.5 */ + } + { + const char input[] = "0x1P 1000000"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); /* HP-UX 11.31/ia64, IRIX 6.5, mingw */ + ASSERT (ptr == input + 3); /* HP-UX 11.31/ia64, IRIX 6.5, mingw */ + ASSERT (errno == 0); + } + + /* Infinity. */ + { + const char input[] = "iNf"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == HUGE_VALL); /* IRIX 6.5 */ + ASSERT (ptr == input + 3); /* IRIX 6.5 */ + ASSERT (errno == 0); /* HP-UX 11.31/ia64 */ + } + { + const char input[] = "-InF"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == -HUGE_VALL); /* IRIX 6.5 */ + ASSERT (ptr == input + 4); /* IRIX 6.5 */ + ASSERT (errno == 0); /* HP-UX 11.31/ia64 */ + } + { + const char input[] = "infinite"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == HUGE_VALL); /* IRIX 6.5 */ + ASSERT (ptr == input + 3); /* IRIX 6.5 */ + ASSERT (errno == 0); /* HP-UX 11.31/ia64 */ + } + { + const char input[] = "infinitY"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == HUGE_VALL); /* IRIX 6.5 */ + ASSERT (ptr == input + 8); /* IRIX 6.5 */ + ASSERT (errno == 0); /* HP-UX 11.31/ia64 */ + } + { + const char input[] = "infinitY."; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == HUGE_VALL); /* IRIX 6.5 */ + ASSERT (ptr == input + 8); /* IRIX 6.5 */ + ASSERT (errno == 0); /* HP-UX 11.31/ia64 */ + } + + /* NaN. Some processors set the sign bit of the default NaN, so all + we check is that using a sign changes the result. */ + { + const char input[] = "-nan"; + char *ptr1; + char *ptr2; + long double result1; + long double result2; + errno = 0; + result1 = strtold (input, &ptr1); + result2 = strtold (input + 1, &ptr2); +#if 1 /* All known CPUs support NaNs. */ + ASSERT (isnanl (result1)); /* IRIX 6.5 */ + ASSERT (isnanl (result2)); /* IRIX 6.5 */ +# if 0 + /* Sign bits of NaN is a portability sticking point, not worth + worrying about. */ + ASSERT (!!signbit (result1) != !!signbit (result2)); +# endif + ASSERT (ptr1 == input + 4); /* IRIX 6.5 */ + ASSERT (ptr2 == input + 4); /* IRIX 6.5 */ + ASSERT (errno == 0); /* HP-UX 11.31/ia64 */ +#else + ASSERT (result1 == 0.0L); + ASSERT (result2 == 0.0L); + ASSERT (!signbit (result1)); + ASSERT (!signbit (result2)); + ASSERT (ptr1 == input); + ASSERT (ptr2 == input + 1); + ASSERT (errno == 0 || errno == EINVAL); +#endif + } + { + const char input[] = "+nan("; + char *ptr1; + char *ptr2; + long double result1; + long double result2; + errno = 0; + result1 = strtold (input, &ptr1); + result2 = strtold (input + 1, &ptr2); +#if 1 /* All known CPUs support NaNs. */ + ASSERT (isnanl (result1)); /* IRIX 6.5 */ + ASSERT (isnanl (result2)); /* IRIX 6.5 */ + ASSERT (!!signbit (result1) == !!signbit (result2)); + ASSERT (ptr1 == input + 4); /* Mac OS X 10.5, IRIX 6.5 */ + ASSERT (ptr2 == input + 4); /* Mac OS X 10.5, IRIX 6.5 */ + ASSERT (errno == 0); /* HP-UX 11.31/ia64 */ +#else + ASSERT (result1 == 0.0L); + ASSERT (result2 == 0.0L); + ASSERT (!signbit (result1)); + ASSERT (!signbit (result2)); + ASSERT (ptr1 == input); + ASSERT (ptr2 == input + 1); + ASSERT (errno == 0 || errno == EINVAL); +#endif + } + { + const char input[] = "-nan()"; + char *ptr1; + char *ptr2; + long double result1; + long double result2; + errno = 0; + result1 = strtold (input, &ptr1); + result2 = strtold (input + 1, &ptr2); +#if 1 /* All known CPUs support NaNs. */ + ASSERT (isnanl (result1)); /* IRIX 6.5 */ + ASSERT (isnanl (result2)); /* IRIX 6.5 */ +# if 0 + /* Sign bits of NaN is a portability sticking point, not worth + worrying about. */ + ASSERT (!!signbit (result1) != !!signbit (result2)); /* glibc-2.3.2, musl libc, OpenBSD 6.0, IRIX 6.5, mingw, Haiku */ +# endif + ASSERT (ptr1 == input + 6); /* glibc-2.3.2, IRIX 6.5, mingw, Haiku */ + ASSERT (ptr2 == input + 6); /* glibc-2.3.2, IRIX 6.5, mingw, Haiku */ + ASSERT (errno == 0); /* HP-UX 11.31/ia64, Haiku */ +#else + ASSERT (result1 == 0.0L); + ASSERT (result2 == 0.0L); + ASSERT (!signbit (result1)); + ASSERT (!signbit (result2)); + ASSERT (ptr1 == input); + ASSERT (ptr2 == input + 1); + ASSERT (errno == 0 || errno == EINVAL); +#endif + } + { + const char input[] = " nan()."; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); +#if 1 /* All known CPUs support NaNs. */ + ASSERT (isnanl (result)); /* IRIX 6.5 */ + ASSERT (ptr == input + 6); /* glibc-2.3.2, IRIX 6.5, mingw, Haiku */ + ASSERT (errno == 0); /* HP-UX 11.31/ia64, Haiku */ +#else + ASSERT (result == 0.0L); + ASSERT (!signbit (result)); + ASSERT (ptr == input); + ASSERT (errno == 0 || errno == EINVAL); +#endif + } + { + /* The behavior of nan(0) is implementation-defined, but all + implementations we know of which handle optional + n-char-sequences handle nan(0) the same as nan(). */ + const char input[] = "-nan(0)."; + char *ptr1; + char *ptr2; + long double result1; + long double result2; + errno = 0; + result1 = strtold (input, &ptr1); + result2 = strtold (input + 1, &ptr2); +#if 1 /* All known CPUs support NaNs. */ + ASSERT (isnanl (result1)); /* IRIX 6.5 */ + ASSERT (isnanl (result2)); /* IRIX 6.5 */ +# if 0 + /* Sign bits of NaN is a portability sticking point, not worth + worrying about. */ + ASSERT (!!signbit (result1) != !!signbit (result2)); +# endif + ASSERT (ptr1 == input + 7); /* glibc-2.3.2, IRIX 6.5, mingw, Haiku */ + ASSERT (ptr2 == input + 7); /* glibc-2.3.2, IRIX 6.5, mingw, Haiku */ + ASSERT (errno == 0); /* HP-UX 11.31/ia64 */ +#else + ASSERT (result1 == 0.0L); + ASSERT (result2 == 0.0L); + ASSERT (!signbit (result1)); + ASSERT (!signbit (result2)); + ASSERT (ptr1 == input); + ASSERT (ptr2 == input + 1); + ASSERT (errno == 0 || errno == EINVAL); +#endif + } + + /* Hex. */ + { + const char input[] = "0xa"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 10.0L); /* IRIX 6.5, mingw */ + ASSERT (ptr == input + 3); /* IRIX 6.5, mingw */ + ASSERT (errno == 0); + } + { + const char input[] = "0XA"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 10.0L); /* IRIX 6.5, mingw */ + ASSERT (ptr == input + 3); /* IRIX 6.5, mingw */ + ASSERT (errno == 0); + } + { + const char input[] = "0x1p"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); /* IRIX 6.5, mingw */ + ASSERT (ptr == input + 3); /* IRIX 6.5, mingw */ + ASSERT (errno == 0); + } + { + const char input[] = "0x1p+"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); /* IRIX 6.5, mingw */ + ASSERT (ptr == input + 3); /* IRIX 6.5, mingw */ + ASSERT (errno == 0); + } + { + const char input[] = "0x1P+"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); /* IRIX 6.5, mingw */ + ASSERT (ptr == input + 3); /* IRIX 6.5, mingw */ + ASSERT (errno == 0); + } + { + const char input[] = "0x1p+1"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 2.0L); /* IRIX 6.5, mingw */ + ASSERT (ptr == input + 6); /* IRIX 6.5, mingw */ + ASSERT (errno == 0); + } + { + const char input[] = "0X1P+1"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 2.0L); /* IRIX 6.5, mingw */ + ASSERT (ptr == input + 6); /* IRIX 6.5, mingw */ + ASSERT (errno == 0); + } + { + const char input[] = "0x1p+1a"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 2.0L); /* IRIX 6.5, mingw */ + ASSERT (ptr == input + 6); /* IRIX 6.5, mingw */ + ASSERT (errno == 0); + } + { + const char input[] = "0x1p 2"; + char *ptr; + long double result; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); /* HP-UX 11.31/ia64, IRIX 6.5, mingw */ + ASSERT (ptr == input + 3); /* HP-UX 11.31/ia64, IRIX 6.5, mingw */ + ASSERT (errno == 0); + } + + /* Large buffers. */ + { + size_t m = 1000000; + char *input = malloc (m + 1); + if (input) + { + char *ptr; + long double result; + memset (input, '\t', m - 1); + input[m - 1] = '1'; + input[m] = '\0'; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + m); + ASSERT (errno == 0); + } + free (input); + } + { + size_t m = 1000000; + char *input = malloc (m + 1); + if (input) + { + char *ptr; + long double result; + memset (input, '0', m - 1); + input[m - 1] = '1'; + input[m] = '\0'; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); + ASSERT (ptr == input + m); + ASSERT (errno == 0); + } + free (input); + } +#if 0 + /* Newlib has an artificial limit of 20000 for the exponent. TODO - + gnulib should fix this. */ + { + size_t m = 1000000; + char *input = malloc (m + 1); + if (input) + { + char *ptr; + long double result; + input[0] = '.'; + memset (input + 1, '0', m - 10); + input[m - 9] = '1'; + input[m - 8] = 'e'; + input[m - 7] = '+'; + input[m - 6] = '9'; + input[m - 5] = '9'; + input[m - 4] = '9'; + input[m - 3] = '9'; + input[m - 2] = '9'; + input[m - 1] = '1'; + input[m] = '\0'; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); /* Mac OS X 10.5, FreeBSD 11.0, NetBSD 7.1, OpenBSD 6.0, Minix 3.3, IRIX 6.5, mingw */ + ASSERT (ptr == input + m); + ASSERT (errno == 0); /* Mac OS X 10.5, FreeBSD 11.0, NetBSD 7.1, OpenBSD 6.0, Minix 3.3, IRIX 6.5, mingw */ + } + free (input); + } + { + size_t m = 1000000; + char *input = malloc (m + 1); + if (input) + { + char *ptr; + long double result; + input[0] = '1'; + memset (input + 1, '0', m - 9); + input[m - 8] = 'e'; + input[m - 7] = '-'; + input[m - 6] = '9'; + input[m - 5] = '9'; + input[m - 4] = '9'; + input[m - 3] = '9'; + input[m - 2] = '9'; + input[m - 1] = '1'; + input[m] = '\0'; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 1.0L); /* Mac OS X 10.5, FreeBSD 11.0, NetBSD 7.1, OpenBSD 6.0, Minix 3.3, IRIX 6.5, mingw */ + ASSERT (ptr == input + m); + ASSERT (errno == 0); /* Mac OS X 10.5, FreeBSD 11.0, NetBSD 7.1, OpenBSD 6.0, Minix 3.3, IRIX 6.5, mingw */ + } + free (input); + } +#endif + { + size_t m = 1000000; + char *input = malloc (m + 1); + if (input) + { + char *ptr; + long double result; + input[0] = '-'; + input[1] = '0'; + input[2] = 'e'; + input[3] = '1'; + memset (input + 4, '0', m - 3); + input[m] = '\0'; + errno = 0; + result = strtold (input, &ptr); + ASSERT (result == 0.0L); + ASSERT (!!signbit (result) == !!signbit (minus_zerol)); /* IRIX 6.5 */ + ASSERT (ptr == input + m); + ASSERT (errno == 0); + } + free (input); + } + + /* Rounding. */ + /* TODO - is it worth some tests of rounding for typical IEEE corner + cases, such as .5 ULP rounding up to the smallest denormal and + not causing underflow, or LDBL_MIN - .5 ULP not causing an + infinite loop? */ + + return status; +} -- 2.7.4 --nextPart6055991.vFM6qUVRua--