From: Martin Storsjo Subject: [PATCH 2/2] ucrtbase: Make the strtod implementation C99 compatible Message-Id: <1440967636-19247-2-git-send-email-martin@martin.st> Date: Sun, 30 Aug 2015 23:47:16 +0300 Add a test for ucrtbase that verifies these aspects of the C99 behaviour of strtod. --- configure.ac | 1 + dlls/msvcrt/string.c | 34 ++++++++++++ dlls/ucrtbase/tests/Makefile.in | 5 ++ dlls/ucrtbase/tests/string.c | 112 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 dlls/ucrtbase/tests/Makefile.in create mode 100644 dlls/ucrtbase/tests/string.c diff --git a/configure.ac b/configure.ac index 9d93098..ba45f11 100644 --- a/configure.ac +++ b/configure.ac @@ -3321,6 +3321,7 @@ WINE_CONFIG_DLL(twain_32) WINE_CONFIG_TEST(dlls/twain_32/tests) WINE_CONFIG_DLL(typelib.dll16,enable_win16) WINE_CONFIG_DLL(ucrtbase) +WINE_CONFIG_TEST(dlls/ucrtbase/tests) WINE_CONFIG_DLL(unicows,,[implib]) WINE_CONFIG_DLL(updspapi) WINE_CONFIG_DLL(url,,[implib]) diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c index 980d492..2c427e8 100644 --- a/dlls/msvcrt/string.c +++ b/dlls/msvcrt/string.c @@ -36,6 +36,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); +MSVCRT_long CDECL MSVCRT_strtol(const char* nptr, char** end, int base); + /********************************************************************* * _mbsdup (MSVCRT.@) * _strdup (MSVCRT.@) @@ -339,6 +341,38 @@ static double strtod_helper(const char *str, char **end, MSVCRT__locale_t locale } else if(*p == '+') p++; +#if _MSVCR_VER >= 140 + if(p[0] == '0' && tolower(p[1]) == 'x') { + char *e; + MSVCRT_long val = sign*MSVCRT_strtol(p, &e, 16); + if(tolower(e[0]) == 'p') { + int exp = MSVCRT_strtol(&e[1], &e, 10); + if (exp > 0) + val <<= exp; + else + val >>= -exp; + } + if (end) + *end = e; + return val; + } + if(tolower(p[0]) == 'i' && tolower(p[1]) == 'n' && tolower(p[2]) == 'f') { + if (end) + *end = (char*) &p[3]; + if(tolower(p[3]) == 'i' && tolower(p[4]) == 'n' && tolower(p[5]) == 'i' && + tolower(p[6]) == 't' && tolower(p[7]) == 'y' && end) + *end = (char*) &p[8]; + return sign*INFINITY; + } + if(tolower(p[0]) == 'n' && + tolower(p[1]) == 'a' && + tolower(p[2]) == 'n') { + if (end) + *end = (char*) &p[3]; + return NAN; + } +#endif + while(isdigit(*p)) { found_digit = TRUE; hlp = d*10+*(p++)-'0'; diff --git a/dlls/ucrtbase/tests/Makefile.in b/dlls/ucrtbase/tests/Makefile.in new file mode 100644 index 0000000..2a57e5e --- /dev/null +++ b/dlls/ucrtbase/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = ucrtbase.dll +APPMODE = -mno-cygwin + +C_SRCS = \ + string.c diff --git a/dlls/ucrtbase/tests/string.c b/dlls/ucrtbase/tests/string.c new file mode 100644 index 0000000..1ff5efb --- /dev/null +++ b/dlls/ucrtbase/tests/string.c @@ -0,0 +1,112 @@ +/* + * Copyright 2015 Martin Storsjo + * + * This library 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 2.1 of the License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include "wine/test.h" + +#include + +#ifndef INFINITY +static inline float __port_infinity(void) +{ + static const unsigned __inf_bytes = 0x7f800000; + return *(const float *)&__inf_bytes; +} +#define INFINITY __port_infinity() +#endif + +#ifndef NAN +static inline float __port_nan(void) +{ + static const unsigned __nan_bytes = 0x7fc00000; + return *(const float *)&__nan_bytes; +} +#define NAN __port_nan() +#endif + +static double (CDECL *p_strtod)(const char*, char** end); + +static BOOL init(void) +{ + HMODULE module; + + module = LoadLibraryA("ucrtbase.dll"); + if (!module) + { + win_skip("ucrtbase.dll not installed\n"); + return FALSE; + } + + p_strtod = (void*)GetProcAddress(module, "strtod"); + return TRUE; +} + +static BOOL local_isnan(double d) +{ + return d != d; +} + +#define test_strtod_str(string, value, length) _test_strtod_str(__LINE__, string, value, length) +static void _test_strtod_str(int line, const char* string, double value, int length) +{ + char *end; + double d; + d = p_strtod(string, &end); + if (local_isnan(value)) + ok_(__FILE__, line)(local_isnan(d), "d = %lf (\"%s\")\n", d, string); + else + ok_(__FILE__, line)(d == value, "d = %lf (\"%s\")\n", d, string); + ok_(__FILE__, line)(end == string + length, "incorrect end (%d, \"%s\")\n", (int)(end - string), string); +} + +static void test_strtod(void) +{ + test_strtod_str("infinity", INFINITY, 8); + test_strtod_str("INFINITY", INFINITY, 8); + test_strtod_str("InFiNiTy", INFINITY, 8); + test_strtod_str("INF", INFINITY, 3); + test_strtod_str("-inf", -INFINITY, 4); + test_strtod_str("inf42", INFINITY, 3); + test_strtod_str("inffoo", INFINITY, 3); + test_strtod_str("infini", INFINITY, 3); + + test_strtod_str("NAN", NAN, 3); + test_strtod_str("nan", NAN, 3); + test_strtod_str("NaN", NAN, 3); + + test_strtod_str("0x42", 66, 4); + test_strtod_str("0X42", 66, 4); + test_strtod_str("-0x42", -66, 5); + test_strtod_str("0x1p1", 2, 5); + test_strtod_str("0x1P1", 2, 5); + test_strtod_str("0x1p+1", 2, 6); + test_strtod_str("0x2p-1", 1, 6); +} + +START_TEST(string) +{ + if (!init()) return; + test_strtod(); +} -- 1.8.1.2