Alexandre Julliard : ntdll: Reimplement wcstol/wcstoul using the msvcrt code.

Alexandre Julliard julliard at winehq.org
Wed Mar 11 17:38:30 CDT 2020


Module: wine
Branch: master
Commit: 295660b98595a4e8a54124a51ff95f058a115366
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=295660b98595a4e8a54124a51ff95f058a115366

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Wed Mar 11 09:29:24 2020 +0100

ntdll: Reimplement wcstol/wcstoul using the msvcrt code.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/tests/string.c |  72 +++++++++++++++++++++++++
 dlls/ntdll/wcstring.c     | 130 +++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 183 insertions(+), 19 deletions(-)

diff --git a/dlls/ntdll/tests/string.c b/dlls/ntdll/tests/string.c
index d6de1b2909..8280942db5 100644
--- a/dlls/ntdll/tests/string.c
+++ b/dlls/ntdll/tests/string.c
@@ -22,6 +22,7 @@
  */
 
 #include <stdlib.h>
+#include <limits.h>
 
 #include "ntdll_test.h"
 #include "winnls.h"
@@ -47,6 +48,8 @@ static LPSTR    (__cdecl *p_ui64toa)(ULONGLONG, LPSTR, INT);
 static int      (__cdecl *p_wtoi)(LPCWSTR);
 static LONG     (__cdecl *p_wtol)(LPCWSTR);
 static LONGLONG (__cdecl *p_wtoi64)(LPCWSTR);
+static LONG     (__cdecl *pwcstol)(LPCWSTR,LPWSTR*,INT);
+static ULONG    (__cdecl *pwcstoul)(LPCWSTR,LPWSTR*,INT);
 static LPWSTR   (__cdecl *p_itow)(int, LPWSTR, int);
 static LPWSTR   (__cdecl *p_ltow)(LONG, LPWSTR, INT);
 static LPWSTR   (__cdecl *p_ultow)(ULONG, LPWSTR, INT);
@@ -102,6 +105,8 @@ static void InitFunctionPtrs(void)
     X(_wtoi);
     X(_wtol);
     X(_wtoi64);
+    X(wcstol);
+    X(wcstoul);
     X(_itow);
     X(_ltow);
     X(_ultow);
@@ -1153,6 +1158,72 @@ static void test_wtoi64(void)
     ok( result == 0, "got %s\n", wine_dbgstr_longlong(result) );
 }
 
+static void test_wcstol(void)
+{
+    static const struct { WCHAR str[24]; LONG res; ULONG ures; int base; } tests[] =
+    {
+        { L"9", 9, 9, 10 },
+        { L" ", 0, 0 },
+        { L"-1234", -1234, -1234 },
+        { L"\x09\x0a\x0b\x0c\x0d -123", -123, -123 },
+        { L"\xa0 +44", 44, 44 },
+        { L"\x2002\x2003 +55", 0, 0 },
+        { L"\x3000 +66", 0, 0 },
+        { { 0x3231 }, 0, 0 }, /* PARENTHESIZED IDEOGRAPH STOCK */
+        { { 0x4e00 }, 0, 0 }, /* CJK Ideograph, First */
+        { { 0x0bef }, 0, 0 }, /* TAMIL DIGIT NINE */
+        { { 0x0e59 }, 9, 9 }, /* THAI DIGIT NINE */
+        { { 0xff19 }, 9, 9 }, /* FULLWIDTH DIGIT NINE */
+        { { 0x00b9 }, 0, 0 }, /* SUPERSCRIPT ONE */
+        { { '-',0x0e50,'x',0xff19,'1' }, -0x91, -0x91 },
+        { { '+',0x0e50,0xff17,'1' }, 071, 071 },
+        { { 0xff19,'f',0x0e59,0xff46 }, 0x9f9, 0x9f9, 16 },
+        { L"2147483647", 2147483647, 2147483647 },
+        { L"2147483648", LONG_MAX, 2147483648 },
+        { L"4294967295", LONG_MAX, 4294967295 },
+        { L"4294967296", LONG_MAX, ULONG_MAX },
+        { L"9223372036854775807", LONG_MAX, ULONG_MAX },
+        { L"-2147483647", -2147483647, -2147483647 },
+        { L"-2147483648", LONG_MIN, LONG_MIN },
+        { L"-4294967295", LONG_MIN, 1 },
+        { L"-4294967296", LONG_MIN, 1 },
+        { L"-9223372036854775807", LONG_MIN, 1 },
+    };
+    static const WCHAR zeros[] =
+    {
+        0x0660, 0x06f0, 0x0966, 0x09e6, 0x0a66, 0x0ae6, 0x0b66, 0x0c66, 0x0ce6,
+        0x0d66, 0x0e50, 0x0ed0, 0x0f20, 0x1040, 0x17e0, 0x1810, 0xff10
+    };
+    unsigned int i;
+    LONG res;
+    ULONG ures;
+    WCHAR *endpos;
+
+    for (i = 0; i < ARRAY_SIZE(tests); i++)
+    {
+        res = pwcstol( tests[i].str, &endpos, tests[i].base );
+        ok( res == tests[i].res, "%u: %s res %08x\n", i, wine_dbgstr_w(tests[i].str), res );
+        if (!res) ok( endpos == tests[i].str, "%u: wrong endpos %p/%p\n", i, endpos, tests[i].str );
+        ures = pwcstoul( tests[i].str, &endpos, tests[i].base );
+        ok( ures == tests[i].ures, "%u: %s res %08x\n", i, wine_dbgstr_w(tests[i].str), ures );
+    }
+
+    /* Test various unicode digits */
+    for (i = 0; i < ARRAY_SIZE(zeros); ++i)
+    {
+        WCHAR tmp[] = { zeros[i] + 4, zeros[i], zeros[i] + 5, 0 };
+        res = pwcstol(tmp, NULL, 0);
+        ok(res == 405, "with zero = U+%04X: got %d, expected 405\n", zeros[i], res);
+        ures = pwcstoul(tmp, NULL, 0);
+        ok(ures == 405, "with zero = U+%04X: got %u, expected 405\n", zeros[i], ures);
+        tmp[1] = zeros[i] + 10;
+        res = pwcstol(tmp, NULL, 16);
+        ok(res == 4, "with zero = U+%04X: got %d, expected 4\n", zeros[i], res);
+        ures = pwcstoul(tmp, NULL, 16);
+        ok(ures == 4, "with zero = U+%04X: got %u, expected 4\n", zeros[i], ures);
+    }
+}
+
 static void test_wcschr(void)
 {
     static const WCHAR teststringW[] = {'a','b','r','a','c','a','d','a','b','r','a',0};
@@ -1670,6 +1741,7 @@ START_TEST(string)
     test_wtoi();
     test_wtol();
     test_wtoi64();
+    test_wcstol();
     test_wcschr();
     test_wcsrchr();
     test_wcslwrupr();
diff --git a/dlls/ntdll/wcstring.c b/dlls/ntdll/wcstring.c
index 0acad184f9..01c4bd0296 100644
--- a/dlls/ntdll/wcstring.c
+++ b/dlls/ntdll/wcstring.c
@@ -23,7 +23,6 @@
 #include "config.h"
 
 #include <ctype.h>
-#include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
@@ -340,24 +339,6 @@ INT __cdecl NTDLL_mbstowcs( LPWSTR dst, LPCSTR src, INT n )
 }
 
 
-/*********************************************************************
- *                  wcstol  (NTDLL.@)
- */
-LONG __cdecl NTDLL_wcstol(LPCWSTR s, LPWSTR *end, INT base)
-{
-    return strtolW( s, end, base );
-}
-
-
-/*********************************************************************
- *                  wcstoul  (NTDLL.@)
- */
-ULONG __cdecl NTDLL_wcstoul(LPCWSTR s, LPWSTR *end, INT base)
-{
-    return strtoulW( s, end, base );
-}
-
-
 /*********************************************************************
  *           iswctype    (NTDLL.@)
  */
@@ -442,6 +423,117 @@ INT __cdecl NTDLL_iswxdigit( WCHAR wc )
 }
 
 
+static int wctoint( WCHAR c )
+{
+    /* NOTE: MAP_FOLDDIGITS supports too many things. */
+    /* Unicode points that contain digits 0-9; keep this sorted! */
+    static const WCHAR zeros[] =
+    {
+        0x0660, 0x06f0, 0x0966, 0x09e6, 0x0a66, 0x0ae6, 0x0b66, 0x0c66, 0x0ce6,
+        0x0d66, 0x0e50, 0x0ed0, 0x0f20, 0x1040, 0x17e0, 0x1810, 0xff10
+    };
+    int i;
+
+    if ('0' <= c && c <= '9') return c - '0';
+    if ('A' <= c && c <= 'Z') return c - 'A' + 10;
+    if ('a' <= c && c <= 'z') return c - 'a' + 10;
+    for (i = 0; i < ARRAY_SIZE(zeros) && c >= zeros[i]; i++)
+        if (zeros[i] <= c && c <= zeros[i] + 9) return c - zeros[i];
+
+    return -1;
+}
+
+/*********************************************************************
+ *                  wcstol  (NTDLL.@)
+ */
+LONG __cdecl NTDLL_wcstol(LPCWSTR s, LPWSTR *end, INT base)
+{
+    BOOL negative = FALSE, empty = TRUE;
+    LONG ret = 0;
+
+    if (base < 0 || base == 1 || base > 36) return 0;
+    if (end) *end = (WCHAR *)s;
+    while (NTDLL_iswspace(*s)) s++;
+
+    if (*s == '-')
+    {
+        negative = TRUE;
+        s++;
+    }
+    else if (*s == '+') s++;
+
+    if ((base == 0 || base == 16) && !wctoint( *s ) && (s[1] == 'x' || s[1] == 'X'))
+    {
+        base = 16;
+        s += 2;
+    }
+    if (base == 0) base = wctoint( *s ) ? 10 : 8;
+
+    while (*s)
+    {
+        int v = wctoint( *s );
+        if (v < 0 || v >= base) break;
+        if (negative) v = -v;
+        s++;
+        empty = FALSE;
+
+        if (!negative && (ret > MAXLONG / base || ret * base > MAXLONG - v))
+            ret = MAXLONG;
+        else if (negative && (ret < (LONG)MINLONG / base || ret * base < (LONG)(MINLONG - v)))
+            ret = MINLONG;
+        else
+            ret = ret * base + v;
+    }
+
+    if (end && !empty) *end = (WCHAR *)s;
+    return ret;
+}
+
+
+/*********************************************************************
+ *                  wcstoul  (NTDLL.@)
+ */
+ULONG __cdecl NTDLL_wcstoul(LPCWSTR s, LPWSTR *end, INT base)
+{
+    BOOL negative = FALSE, empty = TRUE;
+    ULONG ret = 0;
+
+    if (base < 0 || base == 1 || base > 36) return 0;
+    if (end) *end = (WCHAR *)s;
+    while (NTDLL_iswspace(*s)) s++;
+
+    if (*s == '-')
+    {
+        negative = TRUE;
+        s++;
+    }
+    else if (*s == '+') s++;
+
+    if ((base == 0 || base == 16) && !wctoint( *s ) && (s[1] == 'x' || s[1] == 'X'))
+    {
+        base = 16;
+        s += 2;
+    }
+    if (base == 0) base = wctoint( *s ) ? 10 : 8;
+
+    while (*s)
+    {
+        int v = wctoint( *s );
+        if (v < 0 || v >= base) break;
+        s++;
+        empty = FALSE;
+
+        if (ret > MAXDWORD / base || ret * base > MAXDWORD - v)
+            ret = MAXDWORD;
+        else
+            ret = ret * base + v;
+    }
+
+    if (end && !empty) *end = (WCHAR *)s;
+    return negative ? -ret : ret;
+}
+
+
 /*********************************************************************
  *      _ultow   (NTDLL.@)
  *




More information about the wine-cvs mailing list