Implemented strtolW/strtoulW in libwine_unicode and used it to replace
wcstol and friends.
diff --git a/dlls/comctl32/comctl32undoc.c b/dlls/comctl32/comctl32undoc.c
index fedd06a..2d843c2 100644
--- a/dlls/comctl32/comctl32undoc.c
+++ b/dlls/comctl32/comctl32undoc.c
@@ -67,8 +67,6 @@
typedef HRESULT (CALLBACK *DPALOADPROC)(LPLOADDATA,IStream*,LPARAM);
-INT __cdecl _wtoi(LPWSTR string);
-
/**************************************************************************
* DPA_LoadStream [COMCTL32.9]
*
@@ -2483,7 +2481,7 @@
INT WINAPI
COMCTL32_StrToIntW (LPWSTR lpString)
{
- return _wtoi(lpString);
+ return atoiW(lpString);
}
diff --git a/dlls/comctl32/ipaddress.c b/dlls/comctl32/ipaddress.c
index 5b200dd..8490699 100644
--- a/dlls/comctl32/ipaddress.c
+++ b/dlls/comctl32/ipaddress.c
@@ -31,6 +31,7 @@
#include "ntddk.h"
#include "winbase.h"
#include "commctrl.h"
+#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(ipaddress);
@@ -237,7 +238,7 @@
for (i = 0; i < 4; i++) {
ip_addr *= 256;
if (GetWindowTextW (infoPtr->Part[i].EditHwnd, field, 4))
- ip_addr += wcstol(field, 0, 10);
+ ip_addr += atolW(field);
else
invalid++;
}
@@ -320,7 +321,7 @@
if (!GetWindowTextW (part->EditHwnd, field, 4)) return FALSE;
- curValue = wcstol(field, 0, 10);
+ curValue = atoiW(field);
TRACE(" curValue=%d\n", curValue);
newValue = IPADDRESS_IPNotify(infoPtr, currentfield, curValue);
diff --git a/dlls/comctl32/updown.c b/dlls/comctl32/updown.c
index 74cc337..1e734fa 100644
--- a/dlls/comctl32/updown.c
+++ b/dlls/comctl32/updown.c
@@ -30,6 +30,7 @@
#include "commctrl.h"
#include "winnls.h"
#include "ntddk.h"
+#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(updown);
@@ -275,7 +276,7 @@
*dst = 0;
/* try to convert the number and validate it */
- newVal = wcstol(txt, &src, infoPtr->Base);
+ newVal = strtolW(txt, &src, infoPtr->Base);
if(*src || !UPDOWN_InBounds (infoPtr, newVal)) return FALSE;
}
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 687d1ef..5e46d88 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -884,7 +884,7 @@
@ cdecl _itoa(long ptr long) _itoa
@ cdecl _ltoa(long ptr long) _ltoa
@ cdecl _memccpy(ptr ptr long long) memccpy
-@ cdecl _memicmp(str str long) _memicmp
+@ cdecl _memicmp(str str long) NTDLL__memicmp
@ varargs _snprintf(ptr long ptr) snprintf
@ varargs _snwprintf(wstr long wstr) _snwprintf
@ cdecl _splitpath(str ptr ptr ptr ptr) _splitpath
@@ -900,8 +900,8 @@
@ cdecl _wcslwr(wstr) NTDLL__wcslwr
@ cdecl _wcsnicmp(wstr wstr long) NTDLL__wcsnicmp
@ cdecl _wcsupr(wstr) NTDLL__wcsupr
-@ cdecl _wtoi(wstr) _wtoi
-@ cdecl _wtol(wstr) _wtol
+@ cdecl _wtoi(wstr) NTDLL__wtoi
+@ cdecl _wtol(wstr) NTDLL__wtol
@ cdecl -noimport abs(long) abs
@ cdecl -noimport atan(double) atan
@ cdecl -noimport atoi(str) atoi
diff --git a/dlls/ntdll/string.c b/dlls/ntdll/string.c
index c05aeae..3e041a0 100644
--- a/dlls/ntdll/string.c
+++ b/dlls/ntdll/string.c
@@ -29,7 +29,7 @@
/*********************************************************************
* _memicmp (NTDLL.@)
*/
-INT __cdecl _memicmp( LPCSTR s1, LPCSTR s2, DWORD len )
+INT __cdecl NTDLL__memicmp( LPCSTR s1, LPCSTR s2, DWORD len )
{
int ret = 0;
while (len--)
diff --git a/dlls/ntdll/wcstring.c b/dlls/ntdll/wcstring.c
index 13a7751..162bc4e 100644
--- a/dlls/ntdll/wcstring.c
+++ b/dlls/ntdll/wcstring.c
@@ -303,51 +303,19 @@
/*********************************************************************
* wcstol (NTDLL.@)
- * Like strtol, but for wide character strings.
*/
-INT __cdecl NTDLL_wcstol(LPCWSTR s,LPWSTR *end,INT base)
+long __cdecl NTDLL_wcstol(LPCWSTR s,LPWSTR *end,INT base)
{
- UNICODE_STRING uni;
- ANSI_STRING ansi;
- INT ret;
- LPSTR endA;
-
- RtlInitUnicodeString( &uni, s );
- RtlUnicodeStringToAnsiString( &ansi, &uni, TRUE );
- ret = strtol( ansi.Buffer, &endA, base );
- if (end)
- {
- DWORD len;
- RtlMultiByteToUnicodeSize( &len, ansi.Buffer, endA - ansi.Buffer );
- *end = (LPWSTR)s + len/sizeof(WCHAR);
- }
- RtlFreeAnsiString( &ansi );
- return ret;
+ return strtolW( s, end, base );
}
/*********************************************************************
* wcstoul (NTDLL.@)
- * Like strtoul, but for wide character strings.
*/
-INT __cdecl NTDLL_wcstoul(LPCWSTR s,LPWSTR *end,INT base)
+unsigned long __cdecl NTDLL_wcstoul(LPCWSTR s,LPWSTR *end,INT base)
{
- UNICODE_STRING uni;
- ANSI_STRING ansi;
- INT ret;
- LPSTR endA;
-
- RtlInitUnicodeString( &uni, s );
- RtlUnicodeStringToAnsiString( &ansi, &uni, TRUE );
- ret = strtoul( ansi.Buffer, &endA, base );
- if (end)
- {
- DWORD len;
- RtlMultiByteToUnicodeSize( &len, ansi.Buffer, endA - ansi.Buffer );
- *end = (LPWSTR)s + len/sizeof(WCHAR);
- }
- RtlFreeAnsiString( &ansi );
- return ret;
+ return strtoulW( s, end, base );
}
@@ -405,19 +373,17 @@
* _wtol (NTDLL.@)
* Like atol, but for wide character strings.
*/
-LONG __cdecl _wtol(LPWSTR string)
+LONG __cdecl NTDLL__wtol(LPWSTR string)
{
- char buffer[30];
- NTDLL_wcstombs( buffer, string, sizeof(buffer) );
- return atol( buffer );
+ return strtolW( string, NULL, 10 );
}
/*********************************************************************
* _wtoi (NTDLL.@)
*/
-INT __cdecl _wtoi(LPWSTR string)
+INT __cdecl NTDLL__wtoi(LPWSTR string)
{
- return _wtol(string);
+ return NTDLL__wtol(string);
}
/* INTERNAL: Wide char snprintf
diff --git a/dlls/oleaut32/Makefile.in b/dlls/oleaut32/Makefile.in
index 7e0b2b7..45f1dae 100644
--- a/dlls/oleaut32/Makefile.in
+++ b/dlls/oleaut32/Makefile.in
@@ -6,7 +6,7 @@
IMPORTS = ole32 user32 gdi32 advapi32 kernel32 ntdll
DELAYIMPORTS = comctl32
ALTNAMES = ole2disp.dll typelib.dll
-EXTRALIBS = $(LIBUUID) @JPEGLIB@
+EXTRALIBS = $(LIBUNICODE) $(LIBUUID) @JPEGLIB@
LDDLLFLAGS = @LDDLLFLAGS@
SYMBOLFILE = $(MODULE).tmp.o
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c
index 8afe1fa..b6d7894 100644
--- a/dlls/oleaut32/typelib.c
+++ b/dlls/oleaut32/typelib.c
@@ -70,7 +70,6 @@
#include "ole2disp.h"
#include "typelib.h"
#include "wine/debug.h"
-#include "ntddk.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
WINE_DECLARE_DEBUG_CHANNEL(typelib);
@@ -287,7 +286,7 @@
/* Look for a trailing '\\' followed by an index */
pIndexStr = strrchrW(szFile, '\\');
if(pIndexStr && pIndexStr != szFile && *++pIndexStr != '\0') {
- index = wcstol(pIndexStr, NULL, 10);
+ index = atoiW(pIndexStr);
memcpy(szFileCopy, szFile,
(pIndexStr - szFile - 1) * sizeof(WCHAR));
szFileCopy[pIndexStr - szFile - 1] = '\0';
diff --git a/dlls/setupapi/install.c b/dlls/setupapi/install.c
index 9390d04..e3f8adf 100644
--- a/dlls/setupapi/install.c
+++ b/dlls/setupapi/install.c
@@ -315,7 +315,7 @@
if (type == REG_DWORD)
{
- DWORD dw = str ? wcstol( str, NULL, 16 ) : 0;
+ DWORD dw = str ? strtolW( str, NULL, 16 ) : 0;
TRACE( "setting dword %s to %lx\n", debugstr_w(value), dw );
RegSetValueExW( hkey, value, 0, type, (BYTE *)&dw, sizeof(dw) );
}
diff --git a/dlls/setupapi/parser.c b/dlls/setupapi/parser.c
index e17be95..3fc74e6 100644
--- a/dlls/setupapi/parser.c
+++ b/dlls/setupapi/parser.c
@@ -327,7 +327,7 @@
{
memcpy( dirid_str, str, *len * sizeof(WCHAR) );
dirid_str[*len] = 0;
- dirid = wcstol( dirid_str, &end, 10 );
+ dirid = strtolW( dirid_str, &end, 10 );
if (!*end) ret = get_dirid_subst( dirid, len );
HeapFree( GetProcessHeap(), 0, dirid_str );
return ret;
diff --git a/include/ntddk.h b/include/ntddk.h
index a8256e7..54879b7 100644
--- a/include/ntddk.h
+++ b/include/ntddk.h
@@ -759,7 +759,6 @@
DWORD len,
DWORD *pf);
-INT __cdecl wcstol(LPCWSTR,LPWSTR*,INT);
int __cdecl swprintf(LPWSTR,LPCWSTR,...);
/* resource functions */
diff --git a/include/wine/unicode.h b/include/wine/unicode.h
index 7fa9afa..1d48a98 100644
--- a/include/wine/unicode.h
+++ b/include/wine/unicode.h
@@ -71,6 +71,12 @@
extern int utf8_wcstombs( const WCHAR *src, int srclen, char *dst, int dstlen );
extern int utf8_mbstowcs( int flags, const char *src, int srclen, WCHAR *dst, int dstlen );
+extern int strcmpiW( const WCHAR *str1, const WCHAR *str2 );
+extern int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n );
+extern WCHAR *strstrW( const WCHAR *str, const WCHAR *sub );
+extern long int strtolW( const WCHAR *nptr, WCHAR **endptr, int base );
+extern unsigned long int strtoulW( const WCHAR *nptr, WCHAR **endptr, int base );
+
static inline int is_dbcs_leadbyte( const union cptable *table, unsigned char ch )
{
return (table->info.char_size == 2) && (table->dbcs.cp2uni_leadbytes[ch]);
@@ -244,8 +250,14 @@
return ret;
}
-extern int strcmpiW( const WCHAR *str1, const WCHAR *str2 );
-extern int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n );
-extern WCHAR *strstrW( const WCHAR *str, const WCHAR *sub );
+static inline long int atolW( const WCHAR *str )
+{
+ return strtolW( str, (WCHAR **)0, 10 );
+}
+
+static inline int atoiW( const WCHAR *str )
+{
+ return (int)atolW( str );
+}
#endif /* __WINE_UNICODE_H */
diff --git a/unicode/string.c b/unicode/string.c
index 47bce77..7b69204 100644
--- a/unicode/string.c
+++ b/unicode/string.c
@@ -18,6 +18,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <limits.h>
+
#include "wine/unicode.h"
int strcmpiW( const WCHAR *str1, const WCHAR *str2 )
@@ -50,3 +52,237 @@
}
return NULL;
}
+
+/* strtolW and strtoulW implementation based on the GNU C library code */
+/* Copyright (C) 1991,92,94,95,96,97,98,99,2000,2001 Free Software Foundation, Inc. */
+
+long int strtolW( const WCHAR *nptr, WCHAR **endptr, int base )
+{
+ int negative;
+ register unsigned long int cutoff;
+ register unsigned int cutlim;
+ register unsigned long int i;
+ register const WCHAR *s;
+ register WCHAR c;
+ const WCHAR *save, *end;
+ int overflow;
+
+ if (base < 0 || base == 1 || base > 36) return 0;
+
+ save = s = nptr;
+
+ /* Skip white space. */
+ while (isspaceW (*s))
+ ++s;
+ if (!*s) goto noconv;
+
+ /* Check for a sign. */
+ negative = 0;
+ if (*s == '-')
+ {
+ negative = 1;
+ ++s;
+ }
+ else if (*s == '+')
+ ++s;
+
+ /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
+ if (*s == '0')
+ {
+ if ((base == 0 || base == 16) && toupperW(s[1]) == 'X')
+ {
+ s += 2;
+ base = 16;
+ }
+ else if (base == 0)
+ base = 8;
+ }
+ else if (base == 0)
+ base = 10;
+
+ /* Save the pointer so we can check later if anything happened. */
+ save = s;
+ end = NULL;
+
+ cutoff = ULONG_MAX / (unsigned long int) base;
+ cutlim = ULONG_MAX % (unsigned long int) base;
+
+ overflow = 0;
+ i = 0;
+ c = *s;
+ for (;c != '\0'; c = *++s)
+ {
+ if (s == end)
+ break;
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (isalphaW (c))
+ c = toupperW (c) - 'A' + 10;
+ else
+ break;
+ if ((int) c >= base)
+ break;
+ /* Check for overflow. */
+ if (i > cutoff || (i == cutoff && c > cutlim))
+ overflow = 1;
+ else
+ {
+ i *= (unsigned long int) base;
+ i += c;
+ }
+ }
+
+ /* Check if anything actually happened. */
+ if (s == save)
+ goto noconv;
+
+ /* Store in ENDPTR the address of one character
+ past the last character we converted. */
+ if (endptr != NULL)
+ *endptr = (WCHAR *)s;
+
+ /* Check for a value that is within the range of
+ `unsigned LONG int', but outside the range of `LONG int'. */
+ if (overflow == 0
+ && i > (negative
+ ? -((unsigned long int) (LONG_MIN + 1)) + 1
+ : (unsigned long int) LONG_MAX))
+ overflow = 1;
+
+ if (overflow)
+ {
+ return negative ? LONG_MIN : LONG_MAX;
+ }
+
+ /* Return the result of the appropriate sign. */
+ return negative ? -i : i;
+
+noconv:
+ /* We must handle a special case here: the base is 0 or 16 and the
+ first two characters are '0' and 'x', but the rest are no
+ hexadecimal digits. This is no error case. We return 0 and
+ ENDPTR points to the `x`. */
+ if (endptr != NULL)
+ {
+ if (save - nptr >= 2 && toupperW (save[-1]) == 'X'
+ && save[-2] == '0')
+ *endptr = (WCHAR *)&save[-1];
+ else
+ /* There was no number to convert. */
+ *endptr = (WCHAR *)nptr;
+ }
+
+ return 0L;
+}
+
+
+unsigned long int strtoulW( const WCHAR *nptr, WCHAR **endptr, int base )
+{
+ int negative;
+ register unsigned long int cutoff;
+ register unsigned int cutlim;
+ register unsigned long int i;
+ register const WCHAR *s;
+ register WCHAR c;
+ const WCHAR *save, *end;
+ int overflow;
+
+ if (base < 0 || base == 1 || base > 36) return 0;
+
+ save = s = nptr;
+
+ /* Skip white space. */
+ while (isspaceW (*s))
+ ++s;
+ if (!*s) goto noconv;
+
+ /* Check for a sign. */
+ negative = 0;
+ if (*s == '-')
+ {
+ negative = 1;
+ ++s;
+ }
+ else if (*s == '+')
+ ++s;
+
+ /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
+ if (*s == '0')
+ {
+ if ((base == 0 || base == 16) && toupperW(s[1]) == 'X')
+ {
+ s += 2;
+ base = 16;
+ }
+ else if (base == 0)
+ base = 8;
+ }
+ else if (base == 0)
+ base = 10;
+
+ /* Save the pointer so we can check later if anything happened. */
+ save = s;
+ end = NULL;
+
+ cutoff = ULONG_MAX / (unsigned long int) base;
+ cutlim = ULONG_MAX % (unsigned long int) base;
+
+ overflow = 0;
+ i = 0;
+ c = *s;
+ for (;c != '\0'; c = *++s)
+ {
+ if (s == end)
+ break;
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (isalphaW (c))
+ c = toupperW (c) - 'A' + 10;
+ else
+ break;
+ if ((int) c >= base)
+ break;
+ /* Check for overflow. */
+ if (i > cutoff || (i == cutoff && c > cutlim))
+ overflow = 1;
+ else
+ {
+ i *= (unsigned long int) base;
+ i += c;
+ }
+ }
+
+ /* Check if anything actually happened. */
+ if (s == save)
+ goto noconv;
+
+ /* Store in ENDPTR the address of one character
+ past the last character we converted. */
+ if (endptr != NULL)
+ *endptr = (WCHAR *)s;
+
+ if (overflow)
+ {
+ return ULONG_MAX;
+ }
+
+ /* Return the result of the appropriate sign. */
+ return negative ? -i : i;
+
+noconv:
+ /* We must handle a special case here: the base is 0 or 16 and the
+ first two characters are '0' and 'x', but the rest are no
+ hexadecimal digits. This is no error case. We return 0 and
+ ENDPTR points to the `x`. */
+ if (endptr != NULL)
+ {
+ if (save - nptr >= 2 && toupperW (save[-1]) == 'X'
+ && save[-2] == '0')
+ *endptr = (WCHAR *)&save[-1];
+ else
+ /* There was no number to convert. */
+ *endptr = (WCHAR *)nptr;
+ }
+
+ return 0L;
+}