Implement LCMapString using unicode collation tables.
Move CompareString and LCMapString to dlls/kernel/locale.c.
This commit is contained in:
parent
4cb212063b
commit
85d4281616
|
@ -16344,8 +16344,6 @@ esac
|
||||||
|
|
||||||
ac_config_commands="$ac_config_commands objects"
|
ac_config_commands="$ac_config_commands objects"
|
||||||
|
|
||||||
ac_config_commands="$ac_config_commands ole"
|
|
||||||
|
|
||||||
ac_config_commands="$ac_config_commands programs/regapi/tests"
|
ac_config_commands="$ac_config_commands programs/regapi/tests"
|
||||||
|
|
||||||
ac_config_commands="$ac_config_commands programs/regedit/tests"
|
ac_config_commands="$ac_config_commands programs/regedit/tests"
|
||||||
|
@ -17118,7 +17116,6 @@ do
|
||||||
"misc" ) CONFIG_COMMANDS="$CONFIG_COMMANDS misc" ;;
|
"misc" ) CONFIG_COMMANDS="$CONFIG_COMMANDS misc" ;;
|
||||||
"msdos" ) CONFIG_COMMANDS="$CONFIG_COMMANDS msdos" ;;
|
"msdos" ) CONFIG_COMMANDS="$CONFIG_COMMANDS msdos" ;;
|
||||||
"objects" ) CONFIG_COMMANDS="$CONFIG_COMMANDS objects" ;;
|
"objects" ) CONFIG_COMMANDS="$CONFIG_COMMANDS objects" ;;
|
||||||
"ole" ) CONFIG_COMMANDS="$CONFIG_COMMANDS ole" ;;
|
|
||||||
"programs/regapi/tests" ) CONFIG_COMMANDS="$CONFIG_COMMANDS programs/regapi/tests" ;;
|
"programs/regapi/tests" ) CONFIG_COMMANDS="$CONFIG_COMMANDS programs/regapi/tests" ;;
|
||||||
"programs/regedit/tests" ) CONFIG_COMMANDS="$CONFIG_COMMANDS programs/regedit/tests" ;;
|
"programs/regedit/tests" ) CONFIG_COMMANDS="$CONFIG_COMMANDS programs/regedit/tests" ;;
|
||||||
"relay32" ) CONFIG_COMMANDS="$CONFIG_COMMANDS relay32" ;;
|
"relay32" ) CONFIG_COMMANDS="$CONFIG_COMMANDS relay32" ;;
|
||||||
|
@ -17857,8 +17854,6 @@ echo "$as_me: creating misc" >&6;} && mkdir "misc") ;;
|
||||||
echo "$as_me: creating msdos" >&6;} && mkdir "msdos") ;;
|
echo "$as_me: creating msdos" >&6;} && mkdir "msdos") ;;
|
||||||
objects ) test -d "objects" || ({ echo "$as_me:$LINENO: creating objects" >&5
|
objects ) test -d "objects" || ({ echo "$as_me:$LINENO: creating objects" >&5
|
||||||
echo "$as_me: creating objects" >&6;} && mkdir "objects") ;;
|
echo "$as_me: creating objects" >&6;} && mkdir "objects") ;;
|
||||||
ole ) test -d "ole" || ({ echo "$as_me:$LINENO: creating ole" >&5
|
|
||||||
echo "$as_me: creating ole" >&6;} && mkdir "ole") ;;
|
|
||||||
programs/regapi/tests ) test -d "programs/regapi/tests" || ({ echo "$as_me:$LINENO: creating programs/regapi/tests" >&5
|
programs/regapi/tests ) test -d "programs/regapi/tests" || ({ echo "$as_me:$LINENO: creating programs/regapi/tests" >&5
|
||||||
echo "$as_me: creating programs/regapi/tests" >&6;} && mkdir "programs/regapi/tests") ;;
|
echo "$as_me: creating programs/regapi/tests" >&6;} && mkdir "programs/regapi/tests") ;;
|
||||||
programs/regedit/tests ) test -d "programs/regedit/tests" || ({ echo "$as_me:$LINENO: creating programs/regedit/tests" >&5
|
programs/regedit/tests ) test -d "programs/regedit/tests" || ({ echo "$as_me:$LINENO: creating programs/regedit/tests" >&5
|
||||||
|
|
|
@ -1351,7 +1351,6 @@ WINE_CONFIG_EXTRA_DIR(memory)
|
||||||
WINE_CONFIG_EXTRA_DIR(misc)
|
WINE_CONFIG_EXTRA_DIR(misc)
|
||||||
WINE_CONFIG_EXTRA_DIR(msdos)
|
WINE_CONFIG_EXTRA_DIR(msdos)
|
||||||
WINE_CONFIG_EXTRA_DIR(objects)
|
WINE_CONFIG_EXTRA_DIR(objects)
|
||||||
WINE_CONFIG_EXTRA_DIR(ole)
|
|
||||||
WINE_CONFIG_EXTRA_DIR(programs/regapi/tests)
|
WINE_CONFIG_EXTRA_DIR(programs/regapi/tests)
|
||||||
WINE_CONFIG_EXTRA_DIR(programs/regedit/tests)
|
WINE_CONFIG_EXTRA_DIR(programs/regedit/tests)
|
||||||
WINE_CONFIG_EXTRA_DIR(relay32)
|
WINE_CONFIG_EXTRA_DIR(relay32)
|
||||||
|
|
|
@ -20,7 +20,6 @@ SPEC_SRCS16 = \
|
||||||
windebug.spec
|
windebug.spec
|
||||||
|
|
||||||
C_SRCS = \
|
C_SRCS = \
|
||||||
$(TOPOBJDIR)/ole/ole2nls.c \
|
|
||||||
atom.c \
|
atom.c \
|
||||||
change.c \
|
change.c \
|
||||||
comm.c \
|
comm.c \
|
||||||
|
@ -65,7 +64,7 @@ MC_SRCS = \
|
||||||
messages/winerr_enu.mc
|
messages/winerr_enu.mc
|
||||||
|
|
||||||
SUBDIRS = tests
|
SUBDIRS = tests
|
||||||
EXTRASUBDIRS = messages nls $(TOPOBJDIR)/ole
|
EXTRASUBDIRS = messages nls
|
||||||
|
|
||||||
@MAKE_DLL_RULES@
|
@MAKE_DLL_RULES@
|
||||||
|
|
||||||
|
|
|
@ -535,7 +535,7 @@ static INT get_registry_locale_info( LPCWSTR value, LPWSTR buffer, INT len )
|
||||||
* GetLocaleInfoA (KERNEL32.@)
|
* GetLocaleInfoA (KERNEL32.@)
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* LANG_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
|
* LOCALE_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
|
||||||
*
|
*
|
||||||
* MS online documentation states that the string returned is NULL terminated
|
* MS online documentation states that the string returned is NULL terminated
|
||||||
* except for LOCALE_FONTSIGNATURE which "will return a non-NULL
|
* except for LOCALE_FONTSIGNATURE which "will return a non-NULL
|
||||||
|
@ -593,7 +593,7 @@ INT WINAPI GetLocaleInfoA( LCID lcid, LCTYPE lctype, LPSTR buffer, INT len )
|
||||||
* GetLocaleInfoW (KERNEL32.@)
|
* GetLocaleInfoW (KERNEL32.@)
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* LANG_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
|
* LOCALE_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
|
||||||
*
|
*
|
||||||
* MS online documentation states that the string returned is NULL terminated
|
* MS online documentation states that the string returned is NULL terminated
|
||||||
* except for LOCALE_FONTSIGNATURE which "will return a non-NULL
|
* except for LOCALE_FONTSIGNATURE which "will return a non-NULL
|
||||||
|
@ -617,8 +617,8 @@ INT WINAPI GetLocaleInfoW( LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len )
|
||||||
}
|
}
|
||||||
if (!len) buffer = NULL;
|
if (!len) buffer = NULL;
|
||||||
|
|
||||||
if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID();
|
if (lcid == LOCALE_NEUTRAL || lcid == LOCALE_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID();
|
||||||
else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID();
|
else if (lcid == LOCALE_USER_DEFAULT) lcid = GetUserDefaultLCID();
|
||||||
|
|
||||||
lcflags = lctype & LOCALE_LOCALEINFOFLAGSMASK;
|
lcflags = lctype & LOCALE_LOCALEINFOFLAGSMASK;
|
||||||
lctype &= ~LOCALE_LOCALEINFOFLAGSMASK;
|
lctype &= ~LOCALE_LOCALEINFOFLAGSMASK;
|
||||||
|
@ -705,8 +705,8 @@ BOOL WINAPI SetLocaleInfoA(LCID lcid, LCTYPE lctype, LPCSTR data)
|
||||||
DWORD len;
|
DWORD len;
|
||||||
BOOL ret;
|
BOOL ret;
|
||||||
|
|
||||||
if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID();
|
if (lcid == LOCALE_NEUTRAL || lcid == LOCALE_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID();
|
||||||
else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID();
|
else if (lcid == LOCALE_USER_DEFAULT) lcid = GetUserDefaultLCID();
|
||||||
|
|
||||||
if (!(lctype & LOCALE_USE_CP_ACP)) codepage = get_lcid_codepage( lcid );
|
if (!(lctype & LOCALE_USE_CP_ACP)) codepage = get_lcid_codepage( lcid );
|
||||||
len = MultiByteToWideChar( codepage, 0, data, -1, NULL, 0 );
|
len = MultiByteToWideChar( codepage, 0, data, -1, NULL, 0 );
|
||||||
|
@ -733,8 +733,8 @@ BOOL WINAPI SetLocaleInfoW( LCID lcid, LCTYPE lctype, LPCWSTR data )
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
HKEY hkey;
|
HKEY hkey;
|
||||||
|
|
||||||
if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID();
|
if (lcid == LOCALE_NEUTRAL || lcid == LOCALE_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID();
|
||||||
else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID();
|
else if (lcid == LOCALE_USER_DEFAULT) lcid = GetUserDefaultLCID();
|
||||||
|
|
||||||
if (!(value = get_locale_value_name( lctype )))
|
if (!(value = get_locale_value_name( lctype )))
|
||||||
{
|
{
|
||||||
|
@ -780,8 +780,8 @@ LCID WINAPI GetThreadLocale(void)
|
||||||
*/
|
*/
|
||||||
BOOL WINAPI SetThreadLocale( LCID lcid ) /* [in] Locale identifier */
|
BOOL WINAPI SetThreadLocale( LCID lcid ) /* [in] Locale identifier */
|
||||||
{
|
{
|
||||||
if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID();
|
if (lcid == LOCALE_NEUTRAL || lcid == LOCALE_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID();
|
||||||
else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID();
|
else if (lcid == LOCALE_USER_DEFAULT) lcid = GetUserDefaultLCID();
|
||||||
|
|
||||||
NtCurrentTeb()->CurrentLocale = lcid;
|
NtCurrentTeb()->CurrentLocale = lcid;
|
||||||
NtCurrentTeb()->code_page = get_lcid_codepage( lcid );
|
NtCurrentTeb()->code_page = get_lcid_codepage( lcid );
|
||||||
|
@ -994,6 +994,319 @@ BOOL WINAPI GetStringTypeExA( LCID locale, DWORD type, LPCSTR src, INT count, LP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* LCMapStringW (KERNEL32.@)
|
||||||
|
*/
|
||||||
|
INT WINAPI LCMapStringW(LCID lcid, DWORD flags, LPCWSTR src, INT srclen,
|
||||||
|
LPWSTR dst, INT dstlen)
|
||||||
|
{
|
||||||
|
LPWSTR dst_ptr;
|
||||||
|
|
||||||
|
if (!src || !srclen || dstlen < 0)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mutually exclusive flags */
|
||||||
|
if ((flags & (LCMAP_LOWERCASE | LCMAP_UPPERCASE)) == (LCMAP_LOWERCASE | LCMAP_UPPERCASE) ||
|
||||||
|
(flags & (LCMAP_HIRAGANA | LCMAP_KATAKANA)) == (LCMAP_HIRAGANA | LCMAP_KATAKANA) ||
|
||||||
|
(flags & (LCMAP_HALFWIDTH | LCMAP_FULLWIDTH)) == (LCMAP_HALFWIDTH | LCMAP_FULLWIDTH) ||
|
||||||
|
(flags & (LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE)) == (LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE))
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_FLAGS);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dstlen) dst = NULL;
|
||||||
|
|
||||||
|
if (lcid == LOCALE_NEUTRAL || lcid == LOCALE_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID();
|
||||||
|
else if (lcid == LOCALE_USER_DEFAULT) lcid = GetUserDefaultLCID();
|
||||||
|
|
||||||
|
if (flags & LCMAP_SORTKEY)
|
||||||
|
{
|
||||||
|
if (src == dst)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_FLAGS);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srclen < 0) srclen = strlenW(src);
|
||||||
|
|
||||||
|
TRACE("(0x%04lx,0x%08lx,%s,%d,%p,%d)\n",
|
||||||
|
lcid, flags, debugstr_wn(src, srclen), srclen, dst, dstlen);
|
||||||
|
|
||||||
|
return wine_get_sortkey(flags, src, srclen, (char *)dst, dstlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
|
||||||
|
if (flags & SORT_STRINGSORT)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_FLAGS);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srclen < 0) srclen = strlenW(src) + 1;
|
||||||
|
|
||||||
|
TRACE("(0x%04lx,0x%08lx,%s,%d,%p,%d)\n",
|
||||||
|
lcid, flags, debugstr_wn(src, srclen), srclen, dst, dstlen);
|
||||||
|
|
||||||
|
if (!dst) /* return required string length */
|
||||||
|
{
|
||||||
|
INT len;
|
||||||
|
|
||||||
|
for (len = 0; srclen; src++, srclen--)
|
||||||
|
{
|
||||||
|
WCHAR wch = *src;
|
||||||
|
/* tests show that win2k just ignores NORM_IGNORENONSPACE,
|
||||||
|
* and skips white space and punctuation characters for
|
||||||
|
* NORM_IGNORESYMBOLS.
|
||||||
|
*/
|
||||||
|
if ((flags & NORM_IGNORESYMBOLS) && (get_char_typeW(wch) & (C1_PUNCT | C1_SPACE)))
|
||||||
|
continue;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & LCMAP_UPPERCASE)
|
||||||
|
{
|
||||||
|
for (dst_ptr = dst; srclen && dstlen; src++, srclen--)
|
||||||
|
{
|
||||||
|
WCHAR wch = *src;
|
||||||
|
if ((flags & NORM_IGNORESYMBOLS) && (get_char_typeW(wch) & (C1_PUNCT | C1_SPACE)))
|
||||||
|
continue;
|
||||||
|
*dst_ptr++ = toupperW(wch);
|
||||||
|
dstlen--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (flags & LCMAP_LOWERCASE)
|
||||||
|
{
|
||||||
|
for (dst_ptr = dst; srclen && dstlen; src++, srclen--)
|
||||||
|
{
|
||||||
|
WCHAR wch = *src;
|
||||||
|
if ((flags & NORM_IGNORESYMBOLS) && (get_char_typeW(wch) & (C1_PUNCT | C1_SPACE)))
|
||||||
|
continue;
|
||||||
|
*dst_ptr++ = tolowerW(wch);
|
||||||
|
dstlen--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (src == dst)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_FLAGS);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (dst_ptr = dst; srclen && dstlen; src++, srclen--)
|
||||||
|
{
|
||||||
|
WCHAR wch = *src;
|
||||||
|
if ((flags & NORM_IGNORESYMBOLS) && (get_char_typeW(wch) & (C1_PUNCT | C1_SPACE)))
|
||||||
|
continue;
|
||||||
|
*dst_ptr++ = wch;
|
||||||
|
dstlen--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst_ptr - dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* LCMapStringA (KERNEL32.@)
|
||||||
|
*/
|
||||||
|
INT WINAPI LCMapStringA(LCID lcid, DWORD flags, LPCSTR src, INT srclen,
|
||||||
|
LPSTR dst, INT dstlen)
|
||||||
|
{
|
||||||
|
WCHAR bufW[128];
|
||||||
|
LPWSTR srcW, dstW;
|
||||||
|
INT ret = 0, srclenW, dstlenW;
|
||||||
|
UINT locale_cp;
|
||||||
|
|
||||||
|
if (!src || !srclen || dstlen < 0)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
|
||||||
|
(WCHAR *)&locale_cp, (sizeof(locale_cp)/sizeof(WCHAR)));
|
||||||
|
|
||||||
|
srclenW = MultiByteToWideChar(locale_cp, 0, src, srclen, bufW, 128);
|
||||||
|
if (srclenW)
|
||||||
|
srcW = bufW;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
srclenW = MultiByteToWideChar(locale_cp, 0, src, srclen, NULL, 0);
|
||||||
|
srcW = HeapAlloc(GetProcessHeap(), 0, srclenW * sizeof(WCHAR));
|
||||||
|
if (!srcW)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
MultiByteToWideChar(locale_cp, 0, src, srclen, srcW, srclenW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & LCMAP_SORTKEY)
|
||||||
|
{
|
||||||
|
if (src == dst)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_FLAGS);
|
||||||
|
goto map_string_exit;
|
||||||
|
}
|
||||||
|
ret = wine_get_sortkey(flags, srcW, srclenW, dst, dstlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & SORT_STRINGSORT)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_FLAGS);
|
||||||
|
goto map_string_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
dstlenW = LCMapStringW(lcid, flags, srcW, srclenW, NULL, 0);
|
||||||
|
dstW = HeapAlloc(GetProcessHeap(), 0, dstlenW * sizeof(WCHAR));
|
||||||
|
if (!dstW)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
goto map_string_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
LCMapStringW(lcid, flags, srcW, srclenW, dstW, dstlenW);
|
||||||
|
ret = WideCharToMultiByte(locale_cp, 0, dstW, dstlenW, dst, dstlen, NULL, NULL);
|
||||||
|
HeapFree(GetProcessHeap(), 0, dstW);
|
||||||
|
|
||||||
|
map_string_exit:
|
||||||
|
if (srcW != bufW) HeapFree(GetProcessHeap(), 0, srcW);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* CompareStringW (KERNEL32.@)
|
||||||
|
*/
|
||||||
|
INT WINAPI CompareStringW(LCID lcid, DWORD style,
|
||||||
|
LPCWSTR str1, INT len1, LPCWSTR str2, INT len2)
|
||||||
|
{
|
||||||
|
INT ret, len;
|
||||||
|
|
||||||
|
if (!str1 || !str2)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len1 < 0) len1 = lstrlenW(str1);
|
||||||
|
if (len2 < 0) len2 = lstrlenW(str2);
|
||||||
|
|
||||||
|
len = (len1 < len2) ? len1 : len2;
|
||||||
|
ret = (style & NORM_IGNORECASE) ? strncmpiW(str1, str2, len) :
|
||||||
|
strncmpW(str1, str2, len);
|
||||||
|
|
||||||
|
if (ret) /* need to translate result */
|
||||||
|
return (ret < 0) ? CSTR_LESS_THAN : CSTR_GREATER_THAN;
|
||||||
|
|
||||||
|
if (len1 == len2) return CSTR_EQUAL;
|
||||||
|
/* the longer one is lexically greater */
|
||||||
|
return (len1 < len2) ? CSTR_LESS_THAN : CSTR_GREATER_THAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* CompareStringA (KERNEL32.@)
|
||||||
|
*/
|
||||||
|
INT WINAPI CompareStringA(LCID lcid, DWORD style,
|
||||||
|
LPCSTR str1, INT len1, LPCSTR str2, INT len2)
|
||||||
|
{
|
||||||
|
WCHAR buf1W[128], buf2W[128];
|
||||||
|
LPWSTR str1W, str2W;
|
||||||
|
INT len1W, len2W, ret;
|
||||||
|
UINT locale_cp;
|
||||||
|
|
||||||
|
if (!str1 || !str2)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
|
||||||
|
(WCHAR *)&locale_cp, (sizeof(locale_cp)/sizeof(WCHAR)));
|
||||||
|
|
||||||
|
len1W = MultiByteToWideChar(locale_cp, 0, str1, len1, buf1W, 128);
|
||||||
|
if (len1W)
|
||||||
|
str1W = buf1W;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
len1W = MultiByteToWideChar(locale_cp, 0, str1, len1, NULL, 0);
|
||||||
|
str1W = HeapAlloc(GetProcessHeap(), 0, len1W * sizeof(WCHAR));
|
||||||
|
if (!str1W)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
MultiByteToWideChar(locale_cp, 0, str1, len1, str1W, len1W);
|
||||||
|
}
|
||||||
|
len2W = MultiByteToWideChar(locale_cp, 0, str2, len2, buf2W, 128);
|
||||||
|
if (len2W)
|
||||||
|
str2W = buf2W;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
len2W = MultiByteToWideChar(locale_cp, 0, str2, len2, NULL, 0);
|
||||||
|
str2W = HeapAlloc(GetProcessHeap(), 0, len2W * sizeof(WCHAR));
|
||||||
|
if (!str2W)
|
||||||
|
{
|
||||||
|
if (str1W != buf1W) HeapFree(GetProcessHeap(), 0, str1W);
|
||||||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
MultiByteToWideChar(locale_cp, 0, str2, len2, str2W, len2W);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = CompareStringW(lcid, style, str1W, len1W, str2W, len2W);
|
||||||
|
|
||||||
|
if (str1W != buf1W) HeapFree(GetProcessHeap(), 0, str1W);
|
||||||
|
if (str2W != buf2W) HeapFree(GetProcessHeap(), 0, str2W);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* lstrcmp (KERNEL32.@)
|
||||||
|
* lstrcmpA (KERNEL32.@)
|
||||||
|
*/
|
||||||
|
int WINAPI lstrcmpA(LPCSTR str1, LPCSTR str2)
|
||||||
|
{
|
||||||
|
int ret = CompareStringA(GetThreadLocale(), 0, str1, -1, str2, -1);
|
||||||
|
if (ret) ret -= 2;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* lstrcmpi (KERNEL32.@)
|
||||||
|
* lstrcmpiA (KERNEL32.@)
|
||||||
|
*/
|
||||||
|
int WINAPI lstrcmpiA(LPCSTR str1, LPCSTR str2)
|
||||||
|
{
|
||||||
|
int ret = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, str1, -1, str2, -1);
|
||||||
|
if (ret) ret -= 2;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* lstrcmpW (KERNEL32.@)
|
||||||
|
*/
|
||||||
|
int WINAPI lstrcmpW(LPCWSTR str1, LPCWSTR str2)
|
||||||
|
{
|
||||||
|
int ret = CompareStringW(GetThreadLocale(), 0, str1, -1, str2, -1);
|
||||||
|
if (ret) ret -= 2;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* lstrcmpiW (KERNEL32.@)
|
||||||
|
*/
|
||||||
|
int WINAPI lstrcmpiW(LPCWSTR str1, LPCWSTR str2)
|
||||||
|
{
|
||||||
|
int ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str1, -1, str2, -1);
|
||||||
|
if (ret) ret -= 2;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* LOCALE_Init
|
* LOCALE_Init
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* Test run on win2K (French)
|
* Test run on win2K (French)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2002 YASAR Mehmet
|
* Copyright (c) 2002 YASAR Mehmet
|
||||||
|
* Copyright 2003 Dmitry Timoshkov
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -696,30 +697,282 @@ char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
|
||||||
|
|
||||||
strcpy(buffer1, "Salut"); strcpy(buffer2, "Salute");
|
strcpy(buffer1, "Salut"); strcpy(buffer2, "Salute");
|
||||||
ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1);
|
ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1);
|
||||||
ok (ret== 1, "CompareStringA (st1=%s str2=%s) expected result=1", buffer1, buffer2);
|
ok(ret == 1, "CompareStringA (st1=%s str2=%s) expected result=1, got %d", buffer1, buffer2, ret);
|
||||||
|
|
||||||
strcpy(buffer1, "Salut"); strcpy(buffer2, "saLuT");
|
strcpy(buffer1, "Salut"); strcpy(buffer2, "saLuT");
|
||||||
ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1);
|
ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1);
|
||||||
ok (ret== 2, "CompareStringA (st1=%s str2=%s) expected result=2", buffer1, buffer2);
|
ok(ret == 2, "CompareStringA (st1=%s str2=%s) expected result=2, got %d", buffer1, buffer2, ret);
|
||||||
|
|
||||||
strcpy(buffer1, "Salut"); strcpy(buffer2, "hola");
|
strcpy(buffer1, "Salut"); strcpy(buffer2, "hola");
|
||||||
ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1);
|
ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1);
|
||||||
ok (ret== 3, "CompareStringA (st1=%s str2=%s) expected result=3", buffer1, buffer2);
|
ok(ret == 3, "CompareStringA (st1=%s str2=%s) expected result=3, got %d", buffer1, buffer2, ret);
|
||||||
|
|
||||||
strcpy(buffer1, "héhé"); strcpy(buffer2, "hèhè");
|
strcpy(buffer1, "haha"); strcpy(buffer2, "hoho");
|
||||||
ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1);
|
ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1);
|
||||||
ok (ret== 1, "CompareStringA (st1=%s str2=%s) expected result=1", buffer1, buffer2);
|
ok (ret == 1, "CompareStringA (st1=%s str2=%s) expected result=1, got %d", buffer1, buffer2, ret);
|
||||||
|
|
||||||
lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT );
|
lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT );
|
||||||
|
|
||||||
strcpy(buffer1, "héhé"); strcpy(buffer2, "hèhè");
|
strcpy(buffer1, "haha"); strcpy(buffer2, "hoho");
|
||||||
ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1);
|
ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1);
|
||||||
ok (ret== 1, "CompareStringA (st1=%s str2=%s) expected result=1", buffer1, buffer2);
|
ok (ret == 1, "CompareStringA (st1=%s str2=%s) expected result=1, got %d", buffer1, buffer2, ret);
|
||||||
|
|
||||||
ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, 0);
|
ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, 0);
|
||||||
ok (ret== 3, "CompareStringA (st1=%s str2=%s) expected result=3", buffer1, buffer2);
|
ok (ret == 3, "CompareStringA (st1=%s str2=%s) expected result=3, got %d", buffer1, buffer2, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_LCMapStringA(void)
|
||||||
|
{
|
||||||
|
int ret, ret2;
|
||||||
|
char buf[256], buf2[256];
|
||||||
|
static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
|
||||||
|
static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
|
||||||
|
static const char symbols_stripped[] = "justateststring1";
|
||||||
|
|
||||||
|
ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
|
||||||
|
upper_case, -1, buf, sizeof(buf));
|
||||||
|
ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
|
||||||
|
ok(GetLastError() == ERROR_INVALID_FLAGS,
|
||||||
|
"unexpected error code %ld\n", GetLastError());
|
||||||
|
|
||||||
|
ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
|
||||||
|
upper_case, -1, buf, sizeof(buf));
|
||||||
|
ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
|
||||||
|
ok(GetLastError() == ERROR_INVALID_FLAGS,
|
||||||
|
"unexpected error code %ld\n", GetLastError());
|
||||||
|
|
||||||
|
ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
|
||||||
|
|
||||||
|
upper_case, -1, buf, sizeof(buf));
|
||||||
|
ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
|
||||||
|
ok(GetLastError() == ERROR_INVALID_FLAGS,
|
||||||
|
"unexpected error code %ld\n", GetLastError());
|
||||||
|
|
||||||
|
ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
|
||||||
|
upper_case, -1, buf, sizeof(buf));
|
||||||
|
ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
|
||||||
|
ok(GetLastError() == ERROR_INVALID_FLAGS,
|
||||||
|
"unexpected error code %ld\n", GetLastError());
|
||||||
|
|
||||||
|
/* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
|
||||||
|
SetLastError(0xdeadbeef);
|
||||||
|
ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
|
||||||
|
upper_case, -1, buf, sizeof(buf));
|
||||||
|
ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
|
||||||
|
ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
|
||||||
|
|
||||||
|
/* test LCMAP_LOWERCASE */
|
||||||
|
ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
|
||||||
|
upper_case, -1, buf, sizeof(buf));
|
||||||
|
ok(ret == lstrlenA(upper_case) + 1,
|
||||||
|
"ret %d, error %ld, expected value %d\n",
|
||||||
|
ret, GetLastError(), lstrlenA(upper_case) + 1);
|
||||||
|
ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
|
||||||
|
|
||||||
|
/* test LCMAP_UPPERCASE */
|
||||||
|
ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
|
||||||
|
lower_case, -1, buf, sizeof(buf));
|
||||||
|
ok(ret == lstrlenA(lower_case) + 1,
|
||||||
|
"ret %d, error %ld, expected value %d\n",
|
||||||
|
ret, GetLastError(), lstrlenA(lower_case) + 1);
|
||||||
|
ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
|
||||||
|
|
||||||
|
/* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
|
||||||
|
lstrcpyA(buf, lower_case);
|
||||||
|
ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
|
||||||
|
buf, -1, buf, sizeof(buf));
|
||||||
|
if (!ret) /* Win9x */
|
||||||
|
trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok(ret == lstrlenA(lower_case) + 1,
|
||||||
|
"ret %d, error %ld, expected value %d\n",
|
||||||
|
ret, GetLastError(), lstrlenA(lower_case) + 1);
|
||||||
|
ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
|
||||||
|
}
|
||||||
|
lstrcpyA(buf, upper_case);
|
||||||
|
ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
|
||||||
|
buf, -1, buf, sizeof(buf));
|
||||||
|
if (!ret) /* Win9x */
|
||||||
|
trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok(ret == lstrlenA(upper_case) + 1,
|
||||||
|
"ret %d, error %ld, expected value %d\n",
|
||||||
|
ret, GetLastError(), lstrlenA(lower_case) + 1);
|
||||||
|
ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* otherwise src == dst should fail */
|
||||||
|
SetLastError(0xdeadbeef);
|
||||||
|
ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
|
||||||
|
buf, 10, buf, sizeof(buf));
|
||||||
|
ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
|
||||||
|
GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
|
||||||
|
"unexpected error code %ld\n", GetLastError());
|
||||||
|
ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
|
||||||
|
|
||||||
|
/* test whether '\0' is always appended */
|
||||||
|
ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
|
||||||
|
upper_case, -1, buf, sizeof(buf));
|
||||||
|
ok(ret, "LCMapStringA must succeed\n");
|
||||||
|
ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
|
||||||
|
upper_case, lstrlenA(upper_case), buf2, sizeof(buf2));
|
||||||
|
ok(ret, "LCMapStringA must succeed\n");
|
||||||
|
ok(ret == ret2, "lengths of sort keys must be equal\n");
|
||||||
|
ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
|
||||||
|
|
||||||
|
/* test LCMAP_SORTKEY | NORM_IGNORECASE */
|
||||||
|
ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
|
||||||
|
upper_case, -1, buf, sizeof(buf));
|
||||||
|
ok(ret, "LCMapStringA must succeed\n");
|
||||||
|
ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
|
||||||
|
lower_case, -1, buf2, sizeof(buf2));
|
||||||
|
ok(ret2, "LCMapStringA must succeed\n");
|
||||||
|
ok(ret == ret2, "lengths of sort keys must be equal\n");
|
||||||
|
ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n");
|
||||||
|
|
||||||
|
/* test NORM_IGNORENONSPACE */
|
||||||
|
lstrcpyA(buf, "foo");
|
||||||
|
ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
|
||||||
|
lower_case, -1, buf, sizeof(buf));
|
||||||
|
ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n",
|
||||||
|
lstrlenA(lower_case) + 1, ret);
|
||||||
|
ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
|
||||||
|
|
||||||
|
/* test NORM_IGNORESYMBOLS */
|
||||||
|
lstrcpyA(buf, "foo");
|
||||||
|
ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
|
||||||
|
lower_case, -1, buf, sizeof(buf));
|
||||||
|
ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
|
||||||
|
lstrlenA(symbols_stripped) + 1, ret);
|
||||||
|
ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_LCMapStringW(void)
|
||||||
|
{
|
||||||
|
int ret, ret2;
|
||||||
|
WCHAR buf[256], buf2[256];
|
||||||
|
char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
|
||||||
|
static const WCHAR upper_case[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0};
|
||||||
|
static const WCHAR lower_case[] = {'\t','j','u','s','t','!',' ','a',',',' ','t','e','s','t',';',' ','s','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
|
||||||
|
static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
|
||||||
|
static const WCHAR fooW[] = {'f','o','o',0};
|
||||||
|
|
||||||
|
ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE,
|
||||||
|
upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
|
||||||
|
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
|
||||||
|
{
|
||||||
|
trace("Skipping LCMapStringW tests on Win9x\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n");
|
||||||
|
ok(GetLastError() == ERROR_INVALID_FLAGS,
|
||||||
|
"unexpected error code %ld\n", GetLastError());
|
||||||
|
|
||||||
|
ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
|
||||||
|
upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
|
||||||
|
ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
|
||||||
|
ok(GetLastError() == ERROR_INVALID_FLAGS,
|
||||||
|
"unexpected error code %ld\n", GetLastError());
|
||||||
|
|
||||||
|
ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
|
||||||
|
upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
|
||||||
|
ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
|
||||||
|
ok(GetLastError() == ERROR_INVALID_FLAGS,
|
||||||
|
"unexpected error code %ld\n", GetLastError());
|
||||||
|
|
||||||
|
ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
|
||||||
|
upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
|
||||||
|
ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
|
||||||
|
ok(GetLastError() == ERROR_INVALID_FLAGS,
|
||||||
|
"unexpected error code %ld\n", GetLastError());
|
||||||
|
|
||||||
|
/* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
|
||||||
|
SetLastError(0xdeadbeef);
|
||||||
|
ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
|
||||||
|
upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
|
||||||
|
ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError());
|
||||||
|
ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
|
||||||
|
|
||||||
|
/* test LCMAP_LOWERCASE */
|
||||||
|
ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
|
||||||
|
upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
|
||||||
|
ok(ret == lstrlenW(upper_case) + 1,
|
||||||
|
"ret %d, error %ld, expected value %d\n",
|
||||||
|
ret, GetLastError(), lstrlenW(upper_case) + 1);
|
||||||
|
ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
|
||||||
|
|
||||||
|
/* test LCMAP_UPPERCASE */
|
||||||
|
ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
|
||||||
|
lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
|
||||||
|
ok(ret == lstrlenW(lower_case) + 1,
|
||||||
|
"ret %d, error %ld, expected value %d\n",
|
||||||
|
ret, GetLastError(), lstrlenW(lower_case) + 1);
|
||||||
|
ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
|
||||||
|
|
||||||
|
/* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
|
||||||
|
lstrcpyW(buf, lower_case);
|
||||||
|
ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
|
||||||
|
buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
|
||||||
|
ok(ret == lstrlenW(lower_case) + 1,
|
||||||
|
"ret %d, error %ld, expected value %d\n",
|
||||||
|
ret, GetLastError(), lstrlenW(lower_case) + 1);
|
||||||
|
ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
|
||||||
|
|
||||||
|
lstrcpyW(buf, upper_case);
|
||||||
|
ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
|
||||||
|
buf, -1, buf, sizeof(buf)/sizeof(WCHAR));
|
||||||
|
ok(ret == lstrlenW(upper_case) + 1,
|
||||||
|
"ret %d, error %ld, expected value %d\n",
|
||||||
|
ret, GetLastError(), lstrlenW(lower_case) + 1);
|
||||||
|
ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n");
|
||||||
|
|
||||||
|
/* otherwise src == dst should fail */
|
||||||
|
SetLastError(0xdeadbeef);
|
||||||
|
ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE,
|
||||||
|
buf, 10, buf, sizeof(buf));
|
||||||
|
ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ ||
|
||||||
|
GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */,
|
||||||
|
"unexpected error code %ld\n", GetLastError());
|
||||||
|
ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n");
|
||||||
|
|
||||||
|
/* test whether '\0' is always appended */
|
||||||
|
ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
|
||||||
|
upper_case, -1, buf, sizeof(buf));
|
||||||
|
ok(ret, "LCMapStringW must succeed\n");
|
||||||
|
ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
|
||||||
|
upper_case, lstrlenW(upper_case), buf2, sizeof(buf2));
|
||||||
|
ok(ret, "LCMapStringW must succeed\n");
|
||||||
|
ok(ret == ret2, "lengths of sort keys must be equal\n");
|
||||||
|
ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
|
||||||
|
|
||||||
|
/* test LCMAP_SORTKEY | NORM_IGNORECASE */
|
||||||
|
ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE,
|
||||||
|
upper_case, -1, buf, sizeof(buf));
|
||||||
|
ok(ret, "LCMapStringW must succeed\n");
|
||||||
|
ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY,
|
||||||
|
lower_case, -1, buf2, sizeof(buf2));
|
||||||
|
ok(ret2, "LCMapStringW must succeed\n");
|
||||||
|
ok(ret == ret2, "lengths of sort keys must be equal\n");
|
||||||
|
ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n");
|
||||||
|
|
||||||
|
/* test NORM_IGNORENONSPACE */
|
||||||
|
lstrcpyW(buf, fooW);
|
||||||
|
ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE,
|
||||||
|
lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
|
||||||
|
ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n",
|
||||||
|
lstrlenW(lower_case) + 1, ret);
|
||||||
|
ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n");
|
||||||
|
|
||||||
|
/* test NORM_IGNORESYMBOLS */
|
||||||
|
lstrcpyW(buf, fooW);
|
||||||
|
ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS,
|
||||||
|
lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
|
||||||
|
ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
|
||||||
|
lstrlenW(symbols_stripped) + 1, ret);
|
||||||
|
ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(locale)
|
START_TEST(locale)
|
||||||
{
|
{
|
||||||
|
@ -733,4 +986,7 @@ START_TEST(locale)
|
||||||
TestGetNumberFormat();
|
TestGetNumberFormat();
|
||||||
TestGetCurrencyFormat();
|
TestGetCurrencyFormat();
|
||||||
TestCompareStringA();
|
TestCompareStringA();
|
||||||
|
|
||||||
|
test_LCMapStringW();
|
||||||
|
test_LCMapStringA();
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,7 @@ static inline void release( void *ptr )
|
||||||
/* put an ASCII string into the debug buffer */
|
/* put an ASCII string into the debug buffer */
|
||||||
inline static char *put_string_a( const char *src, int n )
|
inline static char *put_string_a( const char *src, int n )
|
||||||
{
|
{
|
||||||
|
static const char hex[16] = "0123456789abcdef";
|
||||||
char *dst, *res;
|
char *dst, *res;
|
||||||
|
|
||||||
if (n == -1) n = strlen(src);
|
if (n == -1) n = strlen(src);
|
||||||
|
@ -123,9 +124,9 @@ inline static char *put_string_a( const char *src, int n )
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*dst++ = '\\';
|
*dst++ = '\\';
|
||||||
*dst++ = '0' + ((c >> 6) & 7);
|
*dst++ = 'x';
|
||||||
*dst++ = '0' + ((c >> 3) & 7);
|
*dst++ = hex[(c >> 4) & 0x0f];
|
||||||
*dst++ = '0' + ((c >> 0) & 7);
|
*dst++ = hex[c & 0x0f];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#ifndef __WINE_UNICODE_H
|
#ifndef __WINE_UNICODE_H
|
||||||
#define __WINE_UNICODE_H
|
#define __WINE_UNICODE_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winnls.h"
|
#include "winnls.h"
|
||||||
|
|
||||||
|
@ -71,6 +73,8 @@ extern int wine_cp_wcstombs( const union cptable *table, int flags,
|
||||||
extern int wine_utf8_wcstombs( const WCHAR *src, int srclen, char *dst, int dstlen );
|
extern int wine_utf8_wcstombs( const WCHAR *src, int srclen, char *dst, int dstlen );
|
||||||
extern int wine_utf8_mbstowcs( int flags, const char *src, int srclen, WCHAR *dst, int dstlen );
|
extern int wine_utf8_mbstowcs( int flags, const char *src, int srclen, WCHAR *dst, int dstlen );
|
||||||
|
|
||||||
|
extern int wine_get_sortkey( int flags, const WCHAR *src, int srclen, char *dst, int dstlen );
|
||||||
|
|
||||||
extern int strcmpiW( const WCHAR *str1, const WCHAR *str2 );
|
extern int strcmpiW( const WCHAR *str1, const WCHAR *str2 );
|
||||||
extern int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n );
|
extern int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n );
|
||||||
extern WCHAR *strstrW( const WCHAR *str, const WCHAR *sub );
|
extern WCHAR *strstrW( const WCHAR *str, const WCHAR *sub );
|
||||||
|
|
|
@ -196,6 +196,10 @@ extern "C" {
|
||||||
#define LCMAP_HALFWIDTH 0x00400000 /* map double byte to single byte */
|
#define LCMAP_HALFWIDTH 0x00400000 /* map double byte to single byte */
|
||||||
#define LCMAP_FULLWIDTH 0x00800000 /* map single byte to double byte */
|
#define LCMAP_FULLWIDTH 0x00800000 /* map single byte to double byte */
|
||||||
|
|
||||||
|
#define LCMAP_LINGUISTIC_CASING 0x01000000 /* use linguistic rules for casing */
|
||||||
|
#define LCMAP_SIMPLIFIED_CHINESE 0x02000000 /* map traditional chinese to simplified chinese */
|
||||||
|
#define LCMAP_TRADITIONAL_CHINESE 0x04000000 /* map simplified chinese to traditional chinese */
|
||||||
|
|
||||||
/* Date Flags for GetDateFormat. */
|
/* Date Flags for GetDateFormat. */
|
||||||
|
|
||||||
#define DATE_SHORTDATE 0x00000001 /* use short date picture */
|
#define DATE_SHORTDATE 0x00000001 /* use short date picture */
|
||||||
|
|
|
@ -70,9 +70,11 @@ CODEPAGES = \
|
||||||
|
|
||||||
C_SRCS = \
|
C_SRCS = \
|
||||||
casemap.c \
|
casemap.c \
|
||||||
|
collation.c \
|
||||||
compose.c \
|
compose.c \
|
||||||
cptable.c \
|
cptable.c \
|
||||||
mbtowc.c \
|
mbtowc.c \
|
||||||
|
sortkey.c \
|
||||||
string.c \
|
string.c \
|
||||||
utf8.c \
|
utf8.c \
|
||||||
wctomb.c \
|
wctomb.c \
|
||||||
|
|
|
@ -20,11 +20,10 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "winnls.h"
|
|
||||||
#include "wine/unicode.h"
|
#include "wine/unicode.h"
|
||||||
|
|
||||||
/* get the decomposition of a Unicode char */
|
/* get the decomposition of a Unicode char */
|
||||||
static int get_decomposition( WCHAR src, WCHAR *dst, unsigned int dstlen )
|
int get_decomposition( WCHAR src, WCHAR *dst, unsigned int dstlen )
|
||||||
{
|
{
|
||||||
extern const WCHAR unicode_decompose_table[];
|
extern const WCHAR unicode_decompose_table[];
|
||||||
const WCHAR *ptr = unicode_decompose_table;
|
const WCHAR *ptr = unicode_decompose_table;
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
* Unicode sort key generation
|
||||||
|
*
|
||||||
|
* Copyright 2003 Dmitry Timoshkov
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#include "wine/unicode.h"
|
||||||
|
|
||||||
|
extern int get_decomposition(WCHAR src, WCHAR *dst, unsigned int dstlen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* flags - normalization NORM_* flags
|
||||||
|
*
|
||||||
|
* FIXME: 'variable' flag not handled
|
||||||
|
*/
|
||||||
|
int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dstlen)
|
||||||
|
{
|
||||||
|
extern const unsigned int collation_table[];
|
||||||
|
WCHAR dummy[4]; /* no decomposition is larger than 4 chars */
|
||||||
|
int key_len[4];
|
||||||
|
char *key_ptr[4];
|
||||||
|
const WCHAR *src_save = src;
|
||||||
|
int srclen_save = srclen;
|
||||||
|
|
||||||
|
key_len[0] = key_len[1] = key_len[2] = key_len[3] = 0;
|
||||||
|
for (; srclen; srclen--, src++)
|
||||||
|
{
|
||||||
|
int decomposed_len = get_decomposition(*src, dummy, 4);
|
||||||
|
if (decomposed_len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < decomposed_len; i++)
|
||||||
|
{
|
||||||
|
WCHAR wch = dummy[i];
|
||||||
|
unsigned int ce;
|
||||||
|
|
||||||
|
/* tests show that win2k just ignores NORM_IGNORENONSPACE,
|
||||||
|
* and skips white space and punctuation characters for
|
||||||
|
* NORM_IGNORESYMBOLS.
|
||||||
|
*/
|
||||||
|
if ((flags & NORM_IGNORESYMBOLS) && (get_char_typeW(wch) & (C1_PUNCT | C1_SPACE)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (flags & NORM_IGNORECASE) wch = tolowerW(wch);
|
||||||
|
|
||||||
|
ce = collation_table[collation_table[wch >> 8] + (wch & 0xff)];
|
||||||
|
if (ce != (unsigned int)-1)
|
||||||
|
{
|
||||||
|
if (ce >> 16) key_len[0] += 2;
|
||||||
|
if ((ce >> 8) & 0xff) key_len[1]++;
|
||||||
|
if ((ce >> 4) & 0x0f) key_len[2]++;
|
||||||
|
/*if (ce & 1)
|
||||||
|
{
|
||||||
|
if (wch >> 8) key_len[3]++;
|
||||||
|
key_len[3]++;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
/*else
|
||||||
|
{
|
||||||
|
key_len[0] += 2;
|
||||||
|
if (wch >> 8) key_len[0]++;
|
||||||
|
if (wch & 0xff) key_len[0]++;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dstlen) /* compute length */
|
||||||
|
/* 4 * '\1' + 1 * '\0' + key length */
|
||||||
|
return key_len[0] + key_len[1] + key_len[2] + key_len[3] + 4 + 1;
|
||||||
|
|
||||||
|
if (dstlen < key_len[0] + key_len[1] + key_len[2] + key_len[3] + 4 + 1)
|
||||||
|
return 0; /* overflow */
|
||||||
|
|
||||||
|
src = src_save;
|
||||||
|
srclen = srclen_save;
|
||||||
|
|
||||||
|
key_ptr[0] = dst;
|
||||||
|
key_ptr[1] = key_ptr[0] + key_len[0] + 1;
|
||||||
|
key_ptr[2] = key_ptr[1] + key_len[1] + 1;
|
||||||
|
key_ptr[3] = key_ptr[2] + key_len[2] + 1;
|
||||||
|
|
||||||
|
for (; srclen; srclen--, src++)
|
||||||
|
{
|
||||||
|
int decomposed_len = get_decomposition(*src, dummy, 4);
|
||||||
|
if (decomposed_len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < decomposed_len; i++)
|
||||||
|
{
|
||||||
|
WCHAR wch = dummy[i];
|
||||||
|
unsigned int ce;
|
||||||
|
|
||||||
|
/* tests show that win2k just ignores NORM_IGNORENONSPACE,
|
||||||
|
* and skips white space and punctuation characters for
|
||||||
|
* NORM_IGNORESYMBOLS.
|
||||||
|
*/
|
||||||
|
if ((flags & NORM_IGNORESYMBOLS) && (get_char_typeW(wch) & (C1_PUNCT | C1_SPACE)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (flags & NORM_IGNORECASE) wch = tolowerW(wch);
|
||||||
|
|
||||||
|
ce = collation_table[collation_table[wch >> 8] + (wch & 0xff)];
|
||||||
|
if (ce != (unsigned int)-1)
|
||||||
|
{
|
||||||
|
WCHAR key;
|
||||||
|
if ((key = ce >> 16))
|
||||||
|
{
|
||||||
|
*key_ptr[0]++ = key >> 8;
|
||||||
|
*key_ptr[0]++ = key & 0xff;
|
||||||
|
}
|
||||||
|
/* make key 1 start from 2 */
|
||||||
|
if ((key = (ce >> 8) & 0xff)) *key_ptr[1]++ = key + 1;
|
||||||
|
/* make key 2 start from 2 */
|
||||||
|
if ((key = (ce >> 4) & 0x0f)) *key_ptr[2]++ = key + 1;
|
||||||
|
/* key 3 is always a character code */
|
||||||
|
/*if (ce & 1)
|
||||||
|
{
|
||||||
|
if (wch >> 8) *key_ptr[3]++ = wch >> 8;
|
||||||
|
if (wch & 0xff) *key_ptr[3]++ = wch & 0xff;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
/*else
|
||||||
|
{
|
||||||
|
*key_ptr[0]++ = 0xff;
|
||||||
|
*key_ptr[0]++ = 0xfe;
|
||||||
|
if (wch >> 8) *key_ptr[0]++ = wch >> 8;
|
||||||
|
if (wch & 0xff) *key_ptr[0]++ = wch & 0xff;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*key_ptr[0] = '\1';
|
||||||
|
*key_ptr[1] = '\1';
|
||||||
|
*key_ptr[2] = '\1';
|
||||||
|
*key_ptr[3]++ = '\1';
|
||||||
|
*key_ptr[3] = 0;
|
||||||
|
|
||||||
|
return key_ptr[3] - dst;
|
||||||
|
}
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "winnls.h"
|
|
||||||
#include "wine/unicode.h"
|
#include "wine/unicode.h"
|
||||||
|
|
||||||
/* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */
|
/* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "winnls.h"
|
|
||||||
#include "wine/unicode.h"
|
#include "wine/unicode.h"
|
||||||
|
|
||||||
/* search for a character in the unicode_compose_table; helper for compose() */
|
/* search for a character in the unicode_compose_table; helper for compose() */
|
||||||
|
|
|
@ -16,6 +16,7 @@ EXPORTS
|
||||||
wine_cp_get_table
|
wine_cp_get_table
|
||||||
wine_cp_mbstowcs
|
wine_cp_mbstowcs
|
||||||
wine_cp_wcstombs
|
wine_cp_wcstombs
|
||||||
|
wine_get_sortkey
|
||||||
wine_utf8_mbstowcs
|
wine_utf8_mbstowcs
|
||||||
wine_utf8_wcstombs
|
wine_utf8_wcstombs
|
||||||
wine_wctype_table
|
wine_wctype_table
|
||||||
|
|
1218
ole/ole2nls.c
1218
ole/ole2nls.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue