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