Index: base/shell/cmd/config.h =================================================================== --- base/shell/cmd/config.h (revision 59145) +++ base/shell/cmd/config.h (working copy) @@ -39,13 +39,6 @@ #define FEATURE_REDIRECTION -/* Define one of these to select the used locale. */ -/* (date and time formats etc.) used in DATE, TIME, */ -/* DIR, PROMPT etc. */ -#define LOCALE_WINDOWS /* System locale */ -/* #define LOCALE_GERMAN */ /* German locale */ -/* #define LOCALE_DEFAULT */ /* United States locale */ - #ifdef NT4_INTERNAL_COMMANDS #define INCLUDE_CMD_ACTIVATE #endif Index: dll/win32/kernel32/winnls/string/lang.c =================================================================== --- dll/win32/kernel32/winnls/string/lang.c (revision 59145) +++ dll/win32/kernel32/winnls/string/lang.c (working copy) @@ -3,7 +3,7 @@ * * Copyright 1995 Martin von Loewis * Copyright 1998 David Lee Lambert - * Copyright 2000 Julio C√©sar G√°zquez + * Copyright 2000 Julio César Gázquez * Copyright 2002 Alexandre Julliard for CodeWeavers * * This library is free software; you can redistribute it and/or @@ -186,6 +186,198 @@ } /*********************************************************************** + * charset_cmp (internal) + */ +static int charset_cmp( const void *name, const void *entry ) +{ + const struct charset_entry *charset = entry; + return strcasecmp( name, charset->charset_name ); +} + +/*********************************************************************** + * find_charset + */ +static UINT find_charset( const WCHAR *name ) +{ + const struct charset_entry *entry; + char charset_name[16]; + size_t i, j; + + /* remove punctuation characters from charset name */ + for (i = j = 0; name[i] && j < sizeof(charset_name)-1; i++) + if (isalnum((unsigned char)name[i])) charset_name[j++] = name[i]; + charset_name[j] = 0; + + entry = bsearch( charset_name, charset_names, + sizeof(charset_names)/sizeof(charset_names[0]), + sizeof(charset_names[0]), charset_cmp ); + if (entry) return entry->codepage; + return 0; +} + + +/*********************************************************************** + * find_locale_id_callback + */ +static BOOL CALLBACK find_locale_id_callback( HMODULE hModule, LPCWSTR type, + LPCWSTR name, WORD LangID, LPARAM lParam ) +{ + struct locale_name *data = (struct locale_name *)lParam; + WCHAR buffer[128]; + int matches = 0; + LCID lcid = MAKELCID( LangID, SORT_DEFAULT ); /* FIXME: handle sort order */ + + if (PRIMARYLANGID(LangID) == LANG_NEUTRAL) return TRUE; /* continue search */ + + /* first check exact name */ + if (data->win_name[0] && + GetLocaleInfoW( lcid, LOCALE_SNAME | LOCALE_NOUSEROVERRIDE, + buffer, sizeof(buffer)/sizeof(WCHAR) )) + { + if (!strcmpW( data->win_name, buffer )) + { + matches = 4; /* everything matches */ + goto done; + } + } + + if (!GetLocaleInfoW( lcid, LOCALE_SISO639LANGNAME | LOCALE_NOUSEROVERRIDE, + buffer, sizeof(buffer)/sizeof(WCHAR) )) + return TRUE; + if (strcmpW( buffer, data->lang )) return TRUE; + matches++; /* language name matched */ + + if (data->country) + { + if (GetLocaleInfoW( lcid, LOCALE_SISO3166CTRYNAME|LOCALE_NOUSEROVERRIDE, + buffer, sizeof(buffer)/sizeof(WCHAR) )) + { + if (strcmpW( buffer, data->country )) goto done; + matches++; /* country name matched */ + } + } + else /* match default language */ + { + if (SUBLANGID(LangID) == SUBLANG_DEFAULT) matches++; + } + + if (data->codepage) + { + UINT unix_cp; + if (GetLocaleInfoW( lcid, LOCALE_IDEFAULTUNIXCODEPAGE | LOCALE_RETURN_NUMBER, + (LPWSTR)&unix_cp, sizeof(unix_cp)/sizeof(WCHAR) )) + { + if (unix_cp == data->codepage) matches++; + } + } + + /* FIXME: check sort order */ + +done: + if (matches > data->matches) + { + data->lcid = lcid; + data->matches = matches; + } + return (data->matches < 4); /* no need to continue for perfect match */ +} + + +/*********************************************************************** + * parse_locale_name + * + * Parse a locale name into a struct locale_name, handling both Windows and Unix formats. + * Unix format is: lang[_country][.charset][@modifier] + * Windows format is: lang[-script][-country][_modifier] + */ +static void parse_locale_name( const WCHAR *str, struct locale_name *name ) +{ + static const WCHAR sepW[] = {'-','_','.','@',0}; + static const WCHAR winsepW[] = {'-','_',0}; + static const WCHAR posixW[] = {'P','O','S','I','X',0}; + static const WCHAR cW[] = {'C',0}; + static const WCHAR latinW[] = {'l','a','t','i','n',0}; + static const WCHAR latnW[] = {'-','L','a','t','n',0}; + WCHAR *p; + + TRACE("%s\n", debugstr_w(str)); + + name->country = name->charset = name->script = name->modifier = NULL; + name->lcid = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT ); + name->matches = 0; + name->codepage = 0; + name->win_name[0] = 0; + lstrcpynW( name->lang, str, sizeof(name->lang)/sizeof(WCHAR) ); + + if (!(p = strpbrkW( name->lang, sepW ))) + { + if (!strcmpW( name->lang, posixW ) || !strcmpW( name->lang, cW )) + { + name->matches = 4; /* perfect match for default English lcid */ + return; + } + strcpyW( name->win_name, name->lang ); + } + else if (*p == '-') /* Windows format */ + { + strcpyW( name->win_name, name->lang ); + *p++ = 0; + name->country = p; + if (!(p = strpbrkW( p, winsepW ))) goto done; + if (*p == '-') + { + *p++ = 0; + name->script = name->country; + name->country = p; + if (!(p = strpbrkW( p, winsepW ))) goto done; + } + *p++ = 0; + name->modifier = p; + } + else /* Unix format */ + { + if (*p == '_') + { + *p++ = 0; + name->country = p; + p = strpbrkW( p, sepW + 2 ); + } + if (p && *p == '.') + { + *p++ = 0; + name->charset = p; + p = strchrW( p, '@' ); + } + if (p) + { + *p++ = 0; + name->modifier = p; + } + + if (name->charset) + name->codepage = find_charset( name->charset ); + + /* rebuild a Windows name if possible */ + + if (name->charset) goto done; /* can't specify charset in Windows format */ + if (name->modifier && strcmpW( name->modifier, latinW )) + goto done; /* only Latn script supported for now */ + strcpyW( name->win_name, name->lang ); + if (name->modifier) strcatW( name->win_name, latnW ); + if (name->country) + { + p = name->win_name + strlenW(name->win_name); + *p++ = '-'; + strcpyW( p, name->country ); + } + } +done: + EnumResourceLanguagesW( kernel32_handle, (LPCWSTR)RT_STRING, (LPCWSTR)LOCALE_ILANGUAGE, + find_locale_id_callback, (LPARAM)name ); +} + + +/*********************************************************************** * convert_default_lcid * * Get the default LCID to use for a given lctype in GetLocaleInfo. @@ -238,11 +430,11 @@ case LOCALE_INEGNUMBER: case LOCALE_SDECIMAL: case LOCALE_SGROUPING: - //case LOCALE_SNAN: + case LOCALE_SNAN: case LOCALE_SNATIVEDIGITS: case LOCALE_SNEGATIVESIGN: - //case LOCALE_SNEGINFINITY: - //case LOCALE_SPOSINFINITY: + case LOCALE_SNEGINFINITY: + case LOCALE_SPOSINFINITY: case LOCALE_SPOSITIVESIGN: case LOCALE_STHOUSAND: default_id = lcid_LC_NUMERIC; @@ -290,7 +482,7 @@ case LOCALE_SDAYNAME5: case LOCALE_SDAYNAME6: case LOCALE_SDAYNAME7: - //case LOCALE_SDURATION: + case LOCALE_SDURATION: case LOCALE_SLONGDATE: case LOCALE_SMONTHNAME1: case LOCALE_SMONTHNAME2: @@ -306,13 +498,13 @@ case LOCALE_SMONTHNAME12: case LOCALE_SMONTHNAME13: case LOCALE_SSHORTDATE: - //case LOCALE_SSHORTESTDAYNAME1: - //case LOCALE_SSHORTESTDAYNAME2: - //case LOCALE_SSHORTESTDAYNAME3: - //case LOCALE_SSHORTESTDAYNAME4: - //case LOCALE_SSHORTESTDAYNAME5: - //case LOCALE_SSHORTESTDAYNAME6: - //case LOCALE_SSHORTESTDAYNAME7: + case LOCALE_SSHORTESTDAYNAME1: + case LOCALE_SSHORTESTDAYNAME2: + case LOCALE_SSHORTESTDAYNAME3: + case LOCALE_SSHORTESTDAYNAME4: + case LOCALE_SSHORTESTDAYNAME5: + case LOCALE_SSHORTESTDAYNAME6: + case LOCALE_SSHORTESTDAYNAME7: case LOCALE_STIME: case LOCALE_STIMEFORMAT: case LOCALE_SYEARMONTH: @@ -399,6 +591,17 @@ } /*********************************************************************** + * LCIDToLocaleName (KERNEL32.@) + */ +INT WINAPI LCIDToLocaleName( LCID lcid, LPWSTR name, INT count, DWORD flags ) +{ + if (flags) FIXME( "unsupported flags %x\n", flags ); + + return GetLocaleInfoW( lcid, LOCALE_SNAME | LOCALE_NOUSEROVERRIDE, name, count ); +} + + +/*********************************************************************** * GetUserDefaultLangID (KERNEL32.@) * * Get the default language Id for the current user. @@ -469,6 +672,14 @@ return lcid; } +/*********************************************************************** + * GetSystemDefaultLocaleName (KERNEL32.@) + */ +INT WINAPI GetSystemDefaultLocaleName(LPWSTR localename, INT len) +{ + LCID lcid = GetSystemDefaultLCID(); + return LCIDToLocaleName(lcid, localename, len, 0); +} /*********************************************************************** * GetUserDefaultUILanguage (KERNEL32.@) @@ -508,6 +719,38 @@ return lang; } + +/*********************************************************************** + * LocaleNameToLCID (KERNEL32.@) + */ +LCID WINAPI LocaleNameToLCID( LPCWSTR name, DWORD flags ) +{ + struct locale_name locale_name; + + if (flags) FIXME( "unsupported flags %x\n", flags ); + + if (name == LOCALE_NAME_USER_DEFAULT) + return GetUserDefaultLCID(); + + /* string parsing */ + parse_locale_name( name, &locale_name ); + + TRACE( "found lcid %x for %s, matches %d\n", + locale_name.lcid, debugstr_w(name), locale_name.matches ); + + if (!locale_name.matches) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + if (locale_name.matches == 1) + WARN( "locale %s not recognized, defaulting to %s\n", + debugstr_w(name), debugstr_w(locale_name.lang) ); + + return locale_name.lcid; +} + /****************************************************************************** * get_locale_value_name * @@ -754,6 +997,10 @@ return ret; } +static int get_value_base_by_lctype( LCTYPE lctype ) +{ + return lctype == LOCALE_ILANGUAGE || lctype == LOCALE_IDEFAULTLANGUAGE ? 16 : 10; +} /****************************************************************************** * GetLocaleInfoW (KERNEL32.@) @@ -807,7 +1054,7 @@ if (ret > 0) { WCHAR *end; - UINT number = strtolW( tmp, &end, 10 ); + UINT number = strtolW( tmp, &end, get_value_base_by_lctype( lctype ) ); if (*end) /* invalid number */ { SetLastError( ERROR_INVALID_FLAGS ); @@ -880,7 +1127,7 @@ if (!tmp) return 0; memcpy( tmp, p + 1, *p * sizeof(WCHAR) ); tmp[*p] = 0; - number = strtolW( tmp, &end, 10 ); + number = strtolW( tmp, &end, get_value_base_by_lctype( lctype ) ); if (!*end) memcpy( buffer, &number, sizeof(number) ); else /* invalid number */ @@ -904,7 +1151,33 @@ return ret; } +/****************************************************************************** + * GetLocaleInfoEx (KERNEL32.@) + */ +INT WINAPI GetLocaleInfoEx(LPCWSTR locale, LCTYPE info, LPWSTR buffer, INT len) +{ + LCID lcid = LocaleNameToLCID(locale, 0); + TRACE("%s, lcid=0x%x, 0x%x\n", debugstr_w(locale), lcid, info); + + if (!lcid) return 0; + + /* special handling for neutral locale names */ + if (info == LOCALE_SNAME && strlenW(locale) == 2) + { + if (len && len < 3) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return 0; + } + + if (len) strcpyW(buffer, locale); + return 3; + } + + return GetLocaleInfoW(lcid, info, buffer, len); +} + /****************************************************************************** * SetLocaleInfoA [KERNEL32.@] * @@ -1152,7 +1425,22 @@ (LPCWSTR)LOCALE_ILANGUAGE, LANGIDFROMLCID(lcid)) != 0; } +/****************************************************************************** + * IsValidLocaleName (KERNEL32.@) + */ +BOOL WINAPI IsValidLocaleName( LPCWSTR locale ) +{ + struct locale_name locale_name; + /* string parsing */ + parse_locale_name( locale, &locale_name ); + + TRACE( "found lcid %x for %s, matches %d\n", + locale_name.lcid, debugstr_w(locale), locale_name.matches ); + + return locale_name.matches > 0; +} + static BOOL CALLBACK enum_lang_proc_a( HMODULE hModule, LPCSTR type, LPCSTR name, WORD LangID, LONG_PTR lParam ) { @@ -1210,6 +1498,56 @@ return TRUE; } + +struct enum_locale_ex_data +{ + LOCALE_ENUMPROCEX proc; + DWORD flags; + LPARAM lparam; +}; + +static BOOL CALLBACK enum_locale_ex_proc( HMODULE module, LPCWSTR type, + LPCWSTR name, WORD lang, LONG_PTR lparam ) +{ + struct enum_locale_ex_data *data = (struct enum_locale_ex_data *)lparam; + WCHAR buffer[256]; + DWORD neutral; + unsigned int flags; + + GetLocaleInfoW( MAKELCID( lang, SORT_DEFAULT ), LOCALE_SNAME | LOCALE_NOUSEROVERRIDE, + buffer, sizeof(buffer) / sizeof(WCHAR) ); + if (!GetLocaleInfoW( MAKELCID( lang, SORT_DEFAULT ), + LOCALE_INEUTRAL | LOCALE_NOUSEROVERRIDE | LOCALE_RETURN_NUMBER, + (LPWSTR)&neutral, sizeof(neutral) / sizeof(WCHAR) )) + neutral = 0; + flags = LOCALE_WINDOWS; + flags |= neutral ? LOCALE_NEUTRALDATA : LOCALE_SPECIFICDATA; + if (data->flags && ~(data->flags & flags)) return TRUE; + return data->proc( buffer, flags, data->lparam ); +} + +/****************************************************************************** + * EnumSystemLocalesEx (KERNEL32.@) + */ +BOOL WINAPI EnumSystemLocalesEx( LOCALE_ENUMPROCEX proc, DWORD flags, LPARAM lparam, LPVOID reserved ) +{ + struct enum_locale_ex_data data; + + if (reserved) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + data.proc = proc; + data.flags = flags; + data.lparam = lparam; + EnumResourceLanguagesW( kernel32_handle, (LPCWSTR)RT_STRING, + (LPCWSTR)MAKEINTRESOURCE((LOCALE_SNAME >> 4) + 1), + enum_locale_ex_proc, (LONG_PTR)&data ); + return TRUE; +} + + /*********************************************************************** * VerLanguageNameA (KERNEL32.@) * @@ -1405,15 +1743,34 @@ /************************************************************************* - * LCMapStringW (KERNEL32.@) + * LCMapStringEx (KERNEL32.@) * - * See LCMapStringA. + * Map characters in a locale sensitive string. + * + * PARAMS + * name [I] Locale name for the conversion. + * flags [I] Flags controlling the mapping (LCMAP_ constants from "winnls.h") + * src [I] String to map + * srclen [I] Length of src in chars, or -1 if src is NUL terminated + * dst [O] Destination for mapped string + * dstlen [I] Length of dst in characters + * version [I] reserved, must be NULL + * reserved [I] reserved, must be NULL + * lparam [I] reserved, must be 0 + * + * RETURNS + * Success: The length of the mapped string in dst, including the NUL terminator. + * Failure: 0. Use GetLastError() to determine the cause. */ -INT WINAPI LCMapStringW(LCID lcid, DWORD flags, LPCWSTR src, INT srclen, - LPWSTR dst, INT dstlen) +INT WINAPI LCMapStringEx(LPCWSTR name, DWORD flags, LPCWSTR src, INT srclen, LPWSTR dst, INT dstlen, + LPNLSVERSIONINFO version, LPVOID reserved, LPARAM lparam) { LPWSTR dst_ptr; + if (version) FIXME("unsupported version structure %p\n", version); + if (reserved) FIXME("unsupported reserved pointer %p\n", reserved); + if (lparam) FIXME("unsupported lparam %lx\n", lparam); + if (!src || !srclen || dstlen < 0) { SetLastError(ERROR_INVALID_PARAMETER); @@ -1432,8 +1789,6 @@ if (!dstlen) dst = NULL; - lcid = ConvertDefaultLocale(lcid); - if (flags & LCMAP_SORTKEY) { INT ret; @@ -1445,8 +1800,8 @@ if (srclen < 0) srclen = strlenW(src); - TRACE("(0x%04x,0x%08x,%s,%d,%p,%d)\n", - lcid, flags, debugstr_wn(src, srclen), srclen, dst, dstlen); + TRACE("(%s,0x%08x,%s,%d,%p,%d)\n", + debugstr_w(name), flags, debugstr_wn(src, srclen), srclen, dst, dstlen); ret = wine_get_sortkey(flags, src, srclen, (char *)dst, dstlen); if (ret == 0) @@ -1465,8 +1820,8 @@ if (srclen < 0) srclen = strlenW(src) + 1; - TRACE("(0x%04x,0x%08x,%s,%d,%p,%d)\n", - lcid, flags, debugstr_wn(src, srclen), srclen, dst, dstlen); + TRACE("(%s,0x%08x,%s,%d,%p,%d)\n", + debugstr_w(name), flags, debugstr_wn(src, srclen), srclen, dst, dstlen); if (!dst) /* return required string length */ { @@ -1535,6 +1890,20 @@ } /************************************************************************* + * LCMapStringW (KERNEL32.@) + * + * See LCMapStringA. + */ +INT WINAPI LCMapStringW(LCID lcid, DWORD flags, LPCWSTR src, INT srclen, + LPWSTR dst, INT dstlen) +{ + TRACE("(0x%04x,0x%08x,%s,%d,%p,%d)\n", + lcid, flags, debugstr_wn(src, srclen), srclen, dst, dstlen); + + return LCMapStringEx(NULL, flags, src, srclen, dst, dstlen, NULL, NULL, 0); +} + +/************************************************************************* * LCMapStringA (KERNEL32.@) * * Map characters in a locale sensitive string. @@ -1603,7 +1972,7 @@ goto map_string_exit; } - dstlenW = LCMapStringW(lcid, flags, srcW, srclenW, NULL, 0); + dstlenW = LCMapStringEx(NULL, flags, srcW, srclenW, NULL, 0, NULL, NULL, 0); if (!dstlenW) goto map_string_exit; @@ -1614,7 +1983,7 @@ goto map_string_exit; } - LCMapStringW(lcid, flags, srcW, srclenW, dstW, dstlenW); + LCMapStringEx(NULL, flags, srcW, srclenW, dstW, dstlenW, NULL, NULL, 0); ret = WideCharToMultiByte(locale_cp, 0, dstW, dstlenW, dst, dstlen, NULL, NULL); HeapFree(GetProcessHeap(), 0, dstW); @@ -1730,22 +2099,24 @@ } /****************************************************************************** - * CompareStringW (KERNEL32.@) - * - * See CompareStringA. + * CompareStringEx (KERNEL32.@) */ -INT WINAPI CompareStringW(LCID lcid, DWORD style, - LPCWSTR str1, INT len1, LPCWSTR str2, INT len2) +INT WINAPI CompareStringEx(LPCWSTR locale, DWORD flags, LPCWSTR str1, INT len1, + LPCWSTR str2, INT len2, LPNLSVERSIONINFO version, LPVOID reserved, LPARAM lParam) { INT ret; + if (version) FIXME("unexpected version parameter\n"); + if (reserved) FIXME("unexpected reserved value\n"); + if (lParam) FIXME("unexpected lParam\n"); + if (!str1 || !str2) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } - if( style & ~(NORM_IGNORECASE|NORM_IGNORENONSPACE|NORM_IGNORESYMBOLS| + if( flags & ~(NORM_IGNORECASE|NORM_IGNORENONSPACE|NORM_IGNORESYMBOLS| SORT_STRINGSORT|NORM_IGNOREKANATYPE|NORM_IGNOREWIDTH|LOCALE_USE_CP_ACP|0x10000000) ) { SetLastError(ERROR_INVALID_FLAGS); @@ -1753,13 +2124,13 @@ } /* this style is related to diacritics in Arabic, Japanese, and Hebrew */ - if (style & 0x10000000) - WARN("Ignoring unknown style 0x10000000\n"); + if (flags & 0x10000000) + WARN("Ignoring unknown flags 0x10000000\n"); if (len1 < 0) len1 = strlenW(str1); if (len2 < 0) len2 = strlenW(str2); - ret = wine_compare_string(style, str1, len1, str2, len2); + ret = wine_compare_string(flags, str1, len1, str2, len2); if (ret) /* need to translate result */ return (ret < 0) ? CSTR_LESS_THAN : CSTR_GREATER_THAN; @@ -1767,13 +2138,25 @@ } /****************************************************************************** + * CompareStringW (KERNEL32.@) + * + * See CompareStringA. + */ +INT WINAPI CompareStringW(LCID lcid, DWORD flags, + LPCWSTR str1, INT len1, LPCWSTR str2, INT len2) +{ + return CompareStringEx(NULL, flags, str1, len1, str2, len2, NULL, NULL, 0); +} + + +/****************************************************************************** * CompareStringA (KERNEL32.@) * * Compare two locale sensitive strings. * * PARAMS * lcid [I] LCID for the comparison - * style [I] Flags for the comparison (NORM_ constants from "winnls.h"). + * flags [I] Flags for the comparison (NORM_ constants from "winnls.h"). * str1 [I] First string to compare * len1 [I] Length of str1, or -1 if str1 is NUL terminated * str2 [I] Second string to compare @@ -1784,13 +2167,13 @@ * str1 is less than, equal to or greater than str2 respectively. * Failure: FALSE. Use GetLastError() to determine the cause. */ -INT WINAPI CompareStringA(LCID lcid, DWORD style, +INT WINAPI CompareStringA(LCID lcid, DWORD flags, LPCSTR str1, INT len1, LPCSTR str2, INT len2) { WCHAR *buf1W = NtCurrentTeb()->StaticUnicodeBuffer; WCHAR *buf2W = buf1W + 130; LPWSTR str1W, str2W; - INT len1W, len2W, ret; + INT len1W = 0, len2W = 0, ret; UINT locale_cp = CP_ACP; if (!str1 || !str2) @@ -1801,45 +2184,95 @@ if (len1 < 0) len1 = strlen(str1); if (len2 < 0) len2 = strlen(str2); - if (!(style & LOCALE_USE_CP_ACP)) locale_cp = get_lcid_codepage( lcid ); + if (!(flags & LOCALE_USE_CP_ACP)) locale_cp = get_lcid_codepage( lcid ); - len1W = MultiByteToWideChar(locale_cp, 0, str1, len1, buf1W, 130); - if (len1W) - str1W = buf1W; - else + if (len1) { - len1W = MultiByteToWideChar(locale_cp, 0, str1, len1, NULL, 0); - str1W = HeapAlloc(GetProcessHeap(), 0, len1W * sizeof(WCHAR)); - if (!str1W) + if (len1 <= 130) len1W = MultiByteToWideChar(locale_cp, 0, str1, len1, buf1W, 130); + if (len1W) + str1W = buf1W; + else { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; + 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); } - MultiByteToWideChar(locale_cp, 0, str1, len1, str1W, len1W); } - len2W = MultiByteToWideChar(locale_cp, 0, str2, len2, buf2W, 130); - if (len2W) - str2W = buf2W; else { - len2W = MultiByteToWideChar(locale_cp, 0, str2, len2, NULL, 0); - str2W = HeapAlloc(GetProcessHeap(), 0, len2W * sizeof(WCHAR)); - if (!str2W) + len1W = 0; + str1W = buf1W; + } + + if (len2) + { + if (len2 <= 130) len2W = MultiByteToWideChar(locale_cp, 0, str2, len2, buf2W, 130); + if (len2W) + str2W = buf2W; + else { - if (str1W != buf1W) HeapFree(GetProcessHeap(), 0, str1W); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; + 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); } - MultiByteToWideChar(locale_cp, 0, str2, len2, str2W, len2W); } + else + { + len2W = 0; + str2W = buf2W; + } - ret = CompareStringW(lcid, style, str1W, len1W, str2W, len2W); + ret = CompareStringEx(NULL, flags, str1W, len1W, str2W, len2W, NULL, NULL, 0); if (str1W != buf1W) HeapFree(GetProcessHeap(), 0, str1W); if (str2W != buf2W) HeapFree(GetProcessHeap(), 0, str2W); return ret; } +/****************************************************************************** + * CompareStringOrdinal (KERNEL32.@) + */ +INT WINAPI CompareStringOrdinal(const WCHAR *str1, INT len1, const WCHAR *str2, INT len2, BOOL ignore_case) +{ + int ret, len; + + if (!str1 || !str2) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + if (len1 < 0) len1 = strlenW(str1); + if (len2 < 0) len2 = strlenW(str2); + + len = min(len1, len2); + if (ignore_case) + { + ret = memicmpW(str1, str2, len); + } + else + { + ret = 0; + for (; len > 0; len--) + if ((ret = (*str1++ - *str2++))) break; + } + if (!ret) ret = len1 - len2; + + if (ret < 0) return CSTR_LESS_THAN; + if (ret > 0) return CSTR_GREATER_THAN; + return CSTR_EQUAL; +} + static HANDLE NLS_RegOpenKey(HANDLE hRootKey, LPCWSTR szKeyName) { UNICODE_STRING keyName; @@ -2832,3 +3265,14 @@ return 0; } + +INT WINAPI GetUserDefaultLocaleName(LPWSTR localename, int buffersize) +{ + LCID userlcid; + + TRACE("%p, %d\n", localename, buffersize); + + userlcid = GetUserDefaultLCID(); + return LCIDToLocaleName(userlcid, localename, buffersize, 0); +} + Index: include/psdk/winnls.h =================================================================== --- include/psdk/winnls.h (revision 59145) +++ include/psdk/winnls.h (working copy) @@ -14,130 +14,174 @@ #define MAX_LEADBYTES 12 #define MAX_DEFAULTCHAR 2 -#define LOCALE_ALL 0x00 +#define LOCALE_ALL 0x00 +#define LOCALE_WINDOWS 0x01 +#define LOCALE_SUPPLEMENTAL 0x02 +#define LOCALE_ALTERNATE_SORTS 0x04 +#define LOCALE_REPLACEMENT 0x08 +#define LOCALE_NEUTRALDATA 0x10 +#define LOCALE_SPECIFICDATA 0x20 -#define LOCALE_NOUSEROVERRIDE 0x80000000 -#define LOCALE_USE_CP_ACP 0x40000000 -#if (WINVER >= 0x0400) -#define LOCALE_RETURN_NUMBER 0x20000000 -#endif -#define LOCALE_RETURN_GENITIVE_NAMES 0x10000000 -#define LOCALE_ILANGUAGE 1 -#define LOCALE_SLANGUAGE 2 -#define LOCALE_SENGLANGUAGE 0x1001 -#define LOCALE_SABBREVLANGNAME 3 -#define LOCALE_SNATIVELANGNAME 4 -#define LOCALE_ICOUNTRY 5 -#define LOCALE_SCOUNTRY 6 -#define LOCALE_SENGCOUNTRY 0x1002 -#define LOCALE_SABBREVCTRYNAME 7 -#define LOCALE_SNATIVECTRYNAME 8 -#define LOCALE_IDEFAULTLANGUAGE 9 -#define LOCALE_IDEFAULTCOUNTRY 10 -#define LOCALE_IDEFAULTCODEPAGE 11 -#define LOCALE_IDEFAULTANSICODEPAGE 0x1004 -#define LOCALE_IDEFAULTMACCODEPAGE 0x1011 -#define LOCALE_SLIST 12 -#define LOCALE_IMEASURE 13 -#define LOCALE_SDECIMAL 14 -#define LOCALE_STHOUSAND 15 -#define LOCALE_SGROUPING 16 -#define LOCALE_IDIGITS 17 -#define LOCALE_ILZERO 18 -#define LOCALE_INEGNUMBER 0x1010 -#define LOCALE_SNATIVEDIGITS 19 -#define LOCALE_SCURRENCY 20 -#define LOCALE_SINTLSYMBOL 21 -#define LOCALE_SMONDECIMALSEP 22 -#define LOCALE_SMONTHOUSANDSEP 23 -#define LOCALE_SMONGROUPING 24 -#define LOCALE_ICURRDIGITS 25 -#define LOCALE_IINTLCURRDIGITS 26 -#define LOCALE_ICURRENCY 27 -#define LOCALE_INEGCURR 28 -#define LOCALE_SDATE 29 -#define LOCALE_STIME 30 -#define LOCALE_SSHORTDATE 31 -#define LOCALE_SLONGDATE 32 -#define LOCALE_STIMEFORMAT 0x1003 -#define LOCALE_IDATE 33 -#define LOCALE_ILDATE 34 -#define LOCALE_ITIME 35 -#define LOCALE_ITIMEMARKPOSN 0x1005 -#define LOCALE_ICENTURY 36 -#define LOCALE_ITLZERO 37 -#define LOCALE_IDAYLZERO 38 -#define LOCALE_IMONLZERO 39 -#define LOCALE_S1159 40 -#define LOCALE_S2359 41 -#define LOCALE_ICALENDARTYPE 0x1009 -#define LOCALE_IOPTIONALCALENDAR 0x100B -#define LOCALE_IFIRSTDAYOFWEEK 0x100C -#define LOCALE_IFIRSTWEEKOFYEAR 0x100D -#define LOCALE_SDAYNAME1 42 -#define LOCALE_SDAYNAME2 43 -#define LOCALE_SDAYNAME3 44 -#define LOCALE_SDAYNAME4 45 -#define LOCALE_SDAYNAME5 46 -#define LOCALE_SDAYNAME6 47 -#define LOCALE_SDAYNAME7 48 -#define LOCALE_SABBREVDAYNAME1 49 -#define LOCALE_SABBREVDAYNAME2 50 -#define LOCALE_SABBREVDAYNAME3 51 -#define LOCALE_SABBREVDAYNAME4 52 -#define LOCALE_SABBREVDAYNAME5 53 -#define LOCALE_SABBREVDAYNAME6 54 -#define LOCALE_SABBREVDAYNAME7 55 -#define LOCALE_SMONTHNAME1 56 -#define LOCALE_SMONTHNAME2 57 -#define LOCALE_SMONTHNAME3 58 -#define LOCALE_SMONTHNAME4 59 -#define LOCALE_SMONTHNAME5 60 -#define LOCALE_SMONTHNAME6 61 -#define LOCALE_SMONTHNAME7 62 -#define LOCALE_SMONTHNAME8 63 -#define LOCALE_SMONTHNAME9 64 -#define LOCALE_SMONTHNAME10 65 -#define LOCALE_SMONTHNAME11 66 -#define LOCALE_SMONTHNAME12 67 -#define LOCALE_SMONTHNAME13 0x100E -#define LOCALE_SABBREVMONTHNAME1 68 -#define LOCALE_SABBREVMONTHNAME2 69 -#define LOCALE_SABBREVMONTHNAME3 70 -#define LOCALE_SABBREVMONTHNAME4 71 -#define LOCALE_SABBREVMONTHNAME5 72 -#define LOCALE_SABBREVMONTHNAME6 73 -#define LOCALE_SABBREVMONTHNAME7 74 -#define LOCALE_SABBREVMONTHNAME8 75 -#define LOCALE_SABBREVMONTHNAME9 76 -#define LOCALE_SABBREVMONTHNAME10 77 -#define LOCALE_SABBREVMONTHNAME11 78 -#define LOCALE_SABBREVMONTHNAME12 79 -#define LOCALE_SABBREVMONTHNAME13 0x100F -#define LOCALE_SPOSITIVESIGN 80 -#define LOCALE_SNEGATIVESIGN 81 -#define LOCALE_SSCRIPTS 108 -#define LOCALE_IPOSSIGNPOSN 82 -#define LOCALE_INEGSIGNPOSN 83 -#define LOCALE_IPOSSYMPRECEDES 84 -#define LOCALE_IPOSSEPBYSPACE 85 -#define LOCALE_INEGSYMPRECEDES 86 -#define LOCALE_INEGSEPBYSPACE 87 -#if (WINVER >= 0x0400) -#define LOCALE_FONTSIGNATURE 88 -#define LOCALE_SISO639LANGNAME 89 -#define LOCALE_SISO3166CTRYNAME 90 -#define LOCALE_SNAME 92 -#endif -#if (WINVER >= 0x0600) -#define LOCALE_SSCRIPTS 108 -#endif #define LOCALE_SYSTEM_DEFAULT 0x800 #define LOCALE_USER_DEFAULT 0x400 + +/* Locale flags */ +#define LOCALE_NOUSEROVERRIDE 0x80000000 +#define LOCALE_USE_CP_ACP 0x40000000 +#define LOCALE_RETURN_NUMBER 0x20000000 +#define LOCALE_RETURN_GENITIVE_NAMES 0x10000000 + +#define LOCALE_ILANGUAGE 0x0001 +#define LOCALE_SLANGUAGE 0x0002 +#define LOCALE_SENGLANGUAGE 0x1001 +#define LOCALE_SENGLISHLANGUAGENAME 0x1001 +#define LOCALE_SABBREVLANGNAME 0x0003 +#define LOCALE_SNATIVELANGNAME 0x0004 +#define LOCALE_SNATIVELANGUAGENAME 0x0004 +#define LOCALE_ICOUNTRY 0x0005 +#define LOCALE_SCOUNTRY 0x0006 +#define LOCALE_SLOCALIZEDCOUNTRYNAME 0x0006 +#define LOCALE_SENGCOUNTRY 0x1002 +#define LOCALE_SENGLISHCOUNTRYNAME 0x1002 +#define LOCALE_SABBREVCTRYNAME 0x0007 +#define LOCALE_SNATIVECTRYNAME 0x0008 +#define LOCALE_SNATIVECOUNTRYNAME 0x0008 +#define LOCALE_IDEFAULTLANGUAGE 0x0009 +#define LOCALE_IDEFAULTCOUNTRY 0x000A +#define LOCALE_IDEFAULTCODEPAGE 0x000B +#define LOCALE_IDEFAULTANSICODEPAGE 0x1004 +#define LOCALE_IDEFAULTMACCODEPAGE 0x1011 +#define LOCALE_SLIST 0x000C +#define LOCALE_IMEASURE 0x000D +#define LOCALE_SDECIMAL 0x000E +#define LOCALE_STHOUSAND 0x000F +#define LOCALE_SGROUPING 0x0010 +#define LOCALE_IDIGITS 0x0011 +#define LOCALE_ILZERO 0x0012 +#define LOCALE_INEGNUMBER 0x1010 +#define LOCALE_SNATIVEDIGITS 0x0013 +#define LOCALE_SCURRENCY 0x0014 +#define LOCALE_SINTLSYMBOL 0x0015 +#define LOCALE_SMONDECIMALSEP 0x0016 +#define LOCALE_SMONTHOUSANDSEP 0x0017 +#define LOCALE_SMONGROUPING 0x0018 +#define LOCALE_ICURRDIGITS 0x0019 +#define LOCALE_IINTLCURRDIGITS 0x001A +#define LOCALE_ICURRENCY 0x001B +#define LOCALE_INEGCURR 0x001C +#define LOCALE_SDATE 0x001D +#define LOCALE_STIME 0x001E +#define LOCALE_SSHORTDATE 0x001F +#define LOCALE_SLONGDATE 0x0020 +#define LOCALE_STIMEFORMAT 0x1003 +#define LOCALE_IDATE 0x0021 +#define LOCALE_ILDATE 0x0022 +#define LOCALE_ITIME 0x0023 +#define LOCALE_ITIMEMARKPOSN 0x1005 +#define LOCALE_ICENTURY 0x0024 +#define LOCALE_ITLZERO 0x0025 +#define LOCALE_IDAYLZERO 0x0026 +#define LOCALE_IMONLZERO 0x0027 +#define LOCALE_S1159 0x0028 +#define LOCALE_S2359 0x0029 +#define LOCALE_ICALENDARTYPE 0x1009 +#define LOCALE_IOPTIONALCALENDAR 0x100B +#define LOCALE_IFIRSTDAYOFWEEK 0x100C +#define LOCALE_IFIRSTWEEKOFYEAR 0x100D +#define LOCALE_SDAYNAME1 0x002A +#define LOCALE_SDAYNAME2 0x002B +#define LOCALE_SDAYNAME3 0x002C +#define LOCALE_SDAYNAME4 0x002D +#define LOCALE_SDAYNAME5 0x002E +#define LOCALE_SDAYNAME6 0x002F +#define LOCALE_SDAYNAME7 0x0030 +#define LOCALE_SABBREVDAYNAME1 0x0031 +#define LOCALE_SABBREVDAYNAME2 0x0032 +#define LOCALE_SABBREVDAYNAME3 0x0033 +#define LOCALE_SABBREVDAYNAME4 0x0034 +#define LOCALE_SABBREVDAYNAME5 0x0035 +#define LOCALE_SABBREVDAYNAME6 0x0036 +#define LOCALE_SABBREVDAYNAME7 0x0037 +#define LOCALE_SMONTHNAME1 0x0038 +#define LOCALE_SMONTHNAME2 0x0039 +#define LOCALE_SMONTHNAME3 0x003A +#define LOCALE_SMONTHNAME4 0x003B +#define LOCALE_SMONTHNAME5 0x003C +#define LOCALE_SMONTHNAME6 0x003D +#define LOCALE_SMONTHNAME7 0x003E +#define LOCALE_SMONTHNAME8 0x003F +#define LOCALE_SMONTHNAME9 0x0040 +#define LOCALE_SMONTHNAME10 0x0041 +#define LOCALE_SMONTHNAME11 0x0042 +#define LOCALE_SMONTHNAME12 0x0043 +#define LOCALE_SMONTHNAME13 0x100E +#define LOCALE_SABBREVMONTHNAME1 0x0044 +#define LOCALE_SABBREVMONTHNAME2 0x0045 +#define LOCALE_SABBREVMONTHNAME3 0x0046 +#define LOCALE_SABBREVMONTHNAME4 0x0047 +#define LOCALE_SABBREVMONTHNAME5 0x0048 +#define LOCALE_SABBREVMONTHNAME6 0x0049 +#define LOCALE_SABBREVMONTHNAME7 0x004A +#define LOCALE_SABBREVMONTHNAME8 0x004B +#define LOCALE_SABBREVMONTHNAME9 0x004C +#define LOCALE_SABBREVMONTHNAME10 0x004D +#define LOCALE_SABBREVMONTHNAME11 0x004E +#define LOCALE_SABBREVMONTHNAME12 0x004F +#define LOCALE_SABBREVMONTHNAME13 0x100F +#define LOCALE_SPOSITIVESIGN 0x0050 +#define LOCALE_SNEGATIVESIGN 0x0051 +#define LOCALE_IPOSSIGNPOSN 0x0052 +#define LOCALE_INEGSIGNPOSN 0x0053 +#define LOCALE_IPOSSYMPRECEDES 0x0054 +#define LOCALE_IPOSSEPBYSPACE 0x0055 +#define LOCALE_INEGSYMPRECEDES 0x0056 +#define LOCALE_INEGSEPBYSPACE 0x0057 +#define LOCALE_FONTSIGNATURE 0x0058 +#define LOCALE_SISO639LANGNAME 0x0059 +#define LOCALE_SISO3166CTRYNAME 0x005A +#define LOCALE_IGEOID 0x005B +#define LOCALE_SNAME 0x005C +#define LOCALE_SDURATION 0x005D +#define LOCALE_SKEYBOARDSTOINSTALL 0x005E +#define LOCALE_SSHORTESTDAYNAME1 0x0060 +#define LOCALE_SSHORTESTDAYNAME2 0x0061 +#define LOCALE_SSHORTESTDAYNAME3 0x0062 +#define LOCALE_SSHORTESTDAYNAME4 0x0063 +#define LOCALE_SSHORTESTDAYNAME5 0x0064 +#define LOCALE_SSHORTESTDAYNAME6 0x0065 +#define LOCALE_SSHORTESTDAYNAME7 0x0066 +#define LOCALE_SISO639LANGNAME2 0x0067 +#define LOCALE_SISO3166CTRYNAME2 0x0068 +#define LOCALE_SNAN 0x0069 +#define LOCALE_SPOSINFINITY 0x006A +#define LOCALE_SNEGINFINITY 0x006B +#define LOCALE_SSCRIPTS 0x006C +#define LOCALE_SPARENT 0x006D +#define LOCALE_SCONSOLEFALLBACKNAME 0x006E +#define LOCALE_SLANGDISPLAYNAME 0x006F +#define LOCALE_SLOCALIZEDLANGUAGENAME 0x006F #define LOCALE_IREADINGLAYOUT 0x0070 #define LOCALE_INEUTRAL 0x0071 +#define LOCALE_SENGLISHDISPLAYNAME 0x0072 +#define LOCALE_SNATIVEDISPLAYNAME 0x0073 +#define LOCALE_INEGATIVEPERCENT 0x0074 +#define LOCALE_IPOSITIVEPERCENT 0x0075 +#define LOCALE_SPERCENT 0x0076 +#define LOCALE_SPERMILLE 0x0077 +#define LOCALE_SMONTHDAY 0x0078 +#define LOCALE_SSHORTTIME 0x0079 +#define LOCALE_SOPENTYPELANGUAGETAG 0X007A +#define LOCALE_SSORTLOCALE 0x007B +#define LOCALE_IDEFAULTEBCDICCODEPAGE 0x1012 +#define LOCALE_IPAPERSIZE 0x100A +#define LOCALE_SENGCURRNAME 0x1007 +#define LOCALE_SNATIVECURRNAME 0x1008 +#define LOCALE_SYEARMONTH 0x1006 +#define LOCALE_SSORTNAME 0x1013 +#define LOCALE_IDIGITSUBSTITUTION 0x1014 + #if defined(__GNUC__) # define LOCALE_NAME_INVARIANT (const WCHAR []){ 0 } #elif defined(_MSC_VER) @@ -890,6 +934,15 @@ #if (WINVER >= 0x0600) +int +WINAPI +LCIDToLocaleName( + _In_ LCID Locale, + _Out_opt_ LPWSTR lpName, + _In_ int cchName, + _In_ DWORD dwFlags +); + _Success_(return != FALSE) BOOL WINAPI