From 9b6f433ebbf983c52da0b35b053bc00a4b57dbe5 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 16 May 2002 18:58:47 +0000 Subject: [PATCH] Implemented strtolW/strtoulW in libwine_unicode and used it to replace wcstol and friends. --- dlls/comctl32/comctl32undoc.c | 4 +- dlls/comctl32/ipaddress.c | 5 +- dlls/comctl32/updown.c | 3 +- dlls/ntdll/ntdll.spec | 6 +- dlls/ntdll/string.c | 2 +- dlls/ntdll/wcstring.c | 50 ++----- dlls/oleaut32/Makefile.in | 2 +- dlls/oleaut32/typelib.c | 3 +- dlls/setupapi/install.c | 2 +- dlls/setupapi/parser.c | 2 +- include/ntddk.h | 1 - include/wine/unicode.h | 18 ++- unicode/string.c | 236 ++++++++++++++++++++++++++++++++++ 13 files changed, 273 insertions(+), 61 deletions(-) diff --git a/dlls/comctl32/comctl32undoc.c b/dlls/comctl32/comctl32undoc.c index fedd06a3f75..2d843c2bd0b 100644 --- a/dlls/comctl32/comctl32undoc.c +++ b/dlls/comctl32/comctl32undoc.c @@ -67,8 +67,6 @@ typedef struct _LOADDATA typedef HRESULT (CALLBACK *DPALOADPROC)(LPLOADDATA,IStream*,LPARAM); -INT __cdecl _wtoi(LPWSTR string); - /************************************************************************** * DPA_LoadStream [COMCTL32.9] * @@ -2483,7 +2481,7 @@ COMCTL32_StrToIntA (LPSTR lpString) 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 5b200dd8e37..84906999df4 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 @@ static int IPADDRESS_GetAddress (IPADDRESS_INFO *infoPtr, LPDWORD ip_address) 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 @@ static BOOL IPADDRESS_ConstrainField (IPADDRESS_INFO *infoPtr, int currentfield) 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 74cc3370ae1..1e734faabd0 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 @@ static BOOL UPDOWN_GetBuddyInt (UPDOWN_INFO *infoPtr) *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 687d1ef083d..5e46d88bd9c 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -884,7 +884,7 @@ name ntdll @ 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 @@ name ntdll @ 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 c05aeaebd73..3e041a0dccc 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 13a7751f98b..162bc4e4dab 100644 --- a/dlls/ntdll/wcstring.c +++ b/dlls/ntdll/wcstring.c @@ -303,51 +303,19 @@ INT __cdecl NTDLL_mbstowcs( LPWSTR dst, LPCSTR src, INT n ) /********************************************************************* * 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 @@ LPWSTR __cdecl _ultow(ULONG value, LPWSTR string, INT radix) * _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 7e0b2b7d4ac..45f1dae9e74 100644 --- a/dlls/oleaut32/Makefile.in +++ b/dlls/oleaut32/Makefile.in @@ -6,7 +6,7 @@ MODULE = oleaut32.dll 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 8afe1faa1dc..b6d7894f536 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 @@ HRESULT WINAPI LoadTypeLibEx( /* 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 9390d04e867..e3f8adf4e0a 100644 --- a/dlls/setupapi/install.c +++ b/dlls/setupapi/install.c @@ -315,7 +315,7 @@ static BOOL do_reg_operation( HKEY hkey, const WCHAR *value, INFCONTEXT *context 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 e17be955273..3fc74e65ba6 100644 --- a/dlls/setupapi/parser.c +++ b/dlls/setupapi/parser.c @@ -327,7 +327,7 @@ static const WCHAR *get_string_subst( struct inf_file *file, const WCHAR *str, u { 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 a8256e7cc29..54879b76ec2 100644 --- a/include/ntddk.h +++ b/include/ntddk.h @@ -759,7 +759,6 @@ DWORD WINAPI RtlIsTextUnicode( 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 7fa9afa090f..1d48a982b95 100644 --- a/include/wine/unicode.h +++ b/include/wine/unicode.h @@ -71,6 +71,12 @@ extern int cp_wcstombs( const union cptable *table, int flags, 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 @@ static inline WCHAR *struprW( WCHAR *str ) 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 47bce77537a..7b69204c4c2 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 + #include "wine/unicode.h" int strcmpiW( const WCHAR *str1, const WCHAR *str2 ) @@ -50,3 +52,237 @@ WCHAR *strstrW( const WCHAR *str, const WCHAR *sub ) } 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; +}