[PATCH] msvcr120: Implement strtof and _strtof_l (try 3)

Bernhard Übelacker bernhardu at vr-web.de
Thu Aug 13 21:44:07 CDT 2015


SuperTux 0.3.5a needs msvcr120.strtof.
Found during research for bug #39034.

Changes try 3:
- Avoid almost_equal with float, instead use compare_float from ddraw7 tests
  (thanks Henri Verbeet)
- Used functions should be available in all versions of msvcr120;
  therefore avoid the win_skips. (thanks Piotr Caban)

Changes try 2:
- In the test replaced the bit pattern comparison to detect
  infinity by msvcr120._finite
  (thanks Piotr Caban; _finitef is just available at arm and x86_64)

A note to the tests:
It seems because the functions get dynamically loaded the functions
_errno() and p__errno() returning different variables.
Therefore using also the dynamically loaded p__errno() in tests.
The executable built via make crosstest is linked against msvcrt.dll.
---
 dlls/msvcr120/msvcr120.spec    |  4 +-
 dlls/msvcr120/tests/msvcr120.c | 98 ++++++++++++++++++++++++++++++++++++++++++
 dlls/msvcrt/string.c           | 16 +++++++
 3 files changed, 116 insertions(+), 2 deletions(-)

diff --git a/dlls/msvcr120/msvcr120.spec b/dlls/msvcr120/msvcr120.spec
index c2aacac..07504b7 100644
--- a/dlls/msvcr120/msvcr120.spec
+++ b/dlls/msvcr120/msvcr120.spec
@@ -1728,7 +1728,7 @@
 @ cdecl _strtime(ptr) MSVCRT__strtime
 @ cdecl _strtime_s(ptr long)
 @ cdecl _strtod_l(str ptr ptr) MSVCRT_strtod_l
-@ stub _strtof_l
+@ cdecl _strtof_l(str ptr ptr) MSVCRT_strtof_l
 @ cdecl -ret64 _strtoi64(str ptr long) MSVCRT_strtoi64
 @ cdecl -ret64 _strtoi64_l(str ptr long ptr) MSVCRT_strtoi64_l
 @ stub _strtoimax_l
@@ -2383,7 +2383,7 @@
 @ cdecl strspn(str str) ntdll.strspn
 @ cdecl strstr(str str) MSVCRT_strstr
 @ cdecl strtod(str ptr) MSVCRT_strtod
-@ stub strtof
+@ cdecl strtof(str ptr) MSVCRT_strtof
 @ stub strtoimax
 @ cdecl strtok(str str) MSVCRT_strtok
 @ cdecl strtok_s(ptr str ptr) MSVCRT_strtok_s
diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c
index 330c6b1..05d951d 100644
--- a/dlls/msvcr120/tests/msvcr120.c
+++ b/dlls/msvcr120/tests/msvcr120.c
@@ -21,6 +21,8 @@
 #include <stdlib.h>
 #include <wchar.h>
 #include <stdio.h>
+#include <float.h>
+#include <limits.h>
 
 #include <windef.h>
 #include <winbase.h>
@@ -58,6 +60,22 @@ struct MSVCRT_lconv
     wchar_t* _W_negative_sign;
 };
 
+static BOOL compare_float(float f, float g, unsigned int ulps)
+{
+    int x = *(int *)&f;
+    int y = *(int *)&g;
+
+    if (x < 0)
+        x = INT_MIN - x;
+    if (y < 0)
+        y = INT_MIN - y;
+
+    if (abs(x - y) > ulps)
+        return FALSE;
+
+    return TRUE;
+}
+
 static char* (CDECL *p_setlocale)(int category, const char* locale);
 static struct MSVCRT_lconv* (CDECL *p_localeconv)(void);
 static size_t (CDECL *p_wcstombs_s)(size_t *ret, char* dest, size_t sz, const wchar_t* src, size_t max);
@@ -65,6 +83,9 @@ static int (CDECL *p__dsign)(double);
 static int (CDECL *p__fdsign)(float);
 static wchar_t** (CDECL *p____lc_locale_name_func)(void);
 static unsigned int (CDECL *p__GetConcurrency)(void);
+static float (CDECL *p__strtof_l)(const char *,char**,_locale_t);
+static float (CDECL *p_strtof)(const char *,char**);
+static int* (CDECL *p__errno)(void);
 
 static BOOL init(void)
 {
@@ -84,6 +105,9 @@ static BOOL init(void)
     p__fdsign = (void*)GetProcAddress(module, "_fdsign");
     p____lc_locale_name_func = (void*)GetProcAddress(module, "___lc_locale_name_func");
     p__GetConcurrency = (void*)GetProcAddress(module,"?_GetConcurrency at details@Concurrency@@YAIXZ");
+    p__strtof_l = (void*)GetProcAddress(module, "_strtof_l");
+    p_strtof = (void*)GetProcAddress(module, "strtof");
+    p__errno = (void*)GetProcAddress(module, "_errno");
     return TRUE;
 }
 
@@ -233,6 +257,79 @@ static void test__GetConcurrency(void)
     ok(c == si.dwNumberOfProcessors, "expected %u, got %u\n", si.dwNumberOfProcessors, c);
 }
 
+static void test__strtof(void)
+{
+    const char float1[] = "12.1";
+    const char float2[] = "3.402823466e+38";          /*FLT_MAX*/
+    const char float3[] = "-3.402823466e+38";
+    const char float4[] = "1.7976931348623158e+308";  /*DBL_MAX*/
+    const char float5[] = "-1.7976931348623158e+308";
+
+    char *end;
+    float f;
+
+    f = FLT_MAX * FLT_MAX;
+    ok(_finite(f) == 0, "_finite failed\n");
+
+    /*strtof*/
+    f = p_strtof(float1, &end);
+    ok(compare_float(f, 12.1, 4096), "f = %lf\n", f);
+    ok(end == float1+4, "incorrect end (%d)\n", (int)(end-float1));
+
+    *p__errno() = 0xdeadbeef;
+    f = p_strtof(float2, &end);
+    ok(compare_float(f, FLT_MAX, 4096), "f = %lf\n", f);
+    ok(*p__errno() == 0xdeadbeef, "errno = %x\n", *p__errno());
+    ok(end == float2+15, "incorrect end (%d)\n", (int)(end-float2));
+
+    *p__errno() = 0xdeadbeef;
+    f = p_strtof(float3, &end);
+    ok(compare_float(f, -FLT_MAX, 4096), "f = %lf\n", f);
+    ok(*p__errno() == 0xdeadbeef, "errno = %x\n", *p__errno());
+    ok(end == float3+16, "incorrect end (%d)\n", (int)(end-float3));
+
+    *p__errno() = 0xdeadbeef;
+    f = p_strtof(float4, &end);
+    ok(_finite(f) == 0, "f = %lf\n", f);
+    ok(*p__errno() == 0xdeadbeef, "errno = %x\n", *p__errno());
+    ok(end == float4+23, "incorrect end (%d)\n", (int)(end-float4));
+
+    *p__errno() = 0xdeadbeef;
+    f = p_strtof(float5, &end);
+    ok(_finite(f) == 0, "f = %lf\n", f);
+    ok(*p__errno() == 0xdeadbeef, "errno = %x\n", *p__errno());
+    ok(end == float5+24, "incorrect end (%d)\n", (int)(end-float5));
+
+    /*_strtof_l*/
+    f = p__strtof_l(float1, &end, NULL);
+    ok(compare_float(f, 12.1, 4096), "f = %lf\n", f);
+    ok(end == float1+4, "incorrect end (%d)\n", (int)(end-float1));
+
+    *p__errno() = 0xdeadbeef;
+    f = p__strtof_l(float2, &end, NULL);
+    ok(compare_float(f, FLT_MAX, 4096), "f = %lf\n", f);
+    ok(*p__errno() == 0xdeadbeef, "errno = %x\n", *p__errno());
+    ok(end == float2+15, "incorrect end (%d)\n", (int)(end-float2));
+
+    *p__errno() = 0xdeadbeef;
+    f = p__strtof_l(float3, &end, NULL);
+    ok(compare_float(f, -FLT_MAX, 4096), "f = %lf\n", f);
+    ok(*p__errno() == 0xdeadbeef, "errno = %x\n", *p__errno());
+    ok(end == float3+16, "incorrect end (%d)\n", (int)(end-float3));
+
+    *p__errno() = 0xdeadbeef;
+    f = p__strtof_l(float4, &end, NULL);
+    ok(_finite(f) == 0, "f = %lf\n", f);
+    ok(*p__errno() == 0xdeadbeef, "errno = %x\n", *p__errno());
+    ok(end == float4+23, "incorrect end (%d)\n", (int)(end-float4));
+
+    *p__errno() = 0xdeadbeef;
+    f = p__strtof_l(float5, &end, NULL);
+    ok(_finite(f) == 0, "f = %lf\n", f);
+    ok(*p__errno() == 0xdeadbeef, "errno = %x\n", *p__errno());
+    ok(end == float5+24, "incorrect end (%d)\n", (int)(end-float5));
+}
+
 START_TEST(msvcr120)
 {
     if (!init()) return;
@@ -240,4 +337,5 @@ START_TEST(msvcr120)
     test__dsign();
     test____lc_locale_name_func();
     test__GetConcurrency();
+    test__strtof();
 }
diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c
index 980d492..7195804 100644
--- a/dlls/msvcrt/string.c
+++ b/dlls/msvcrt/string.c
@@ -449,6 +449,22 @@ double CDECL MSVCRT_strtod( const char *str, char **end )
 }
 
 /*********************************************************************
+ *		strtof_l  (MSVCRT.@)
+ */
+float CDECL MSVCRT_strtof_l( const char *str, char **end, MSVCRT__locale_t locale)
+{
+    return MSVCRT_strtod_l(str, end, locale);
+}
+
+/*********************************************************************
+ *		strtof  (MSVCRT.@)
+ */
+float CDECL MSVCRT_strtof( const char *str, char **end )
+{
+    return MSVCRT_strtof_l(str, end, NULL);
+}
+
+/*********************************************************************
  *		atof  (MSVCRT.@)
  */
 double CDECL MSVCRT_atof( const char *str )
-- 
2.1.4




More information about the wine-patches mailing list