kernel32: Get the initial locales from ntdll.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
f1bfd2c0b1
commit
ed09f37cef
|
@ -32,11 +32,6 @@
|
|||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <CoreFoundation/CFLocale.h>
|
||||
# include <CoreFoundation/CFString.h>
|
||||
#endif
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
|
@ -80,28 +75,6 @@ static const union cptable *oem_cptable;
|
|||
static const union cptable *mac_cptable;
|
||||
static const union cptable *unix_cptable; /* NULL if UTF8 */
|
||||
|
||||
struct locale_name
|
||||
{
|
||||
WCHAR win_name[128]; /* Windows name ("en-US") */
|
||||
WCHAR lang[128]; /* language ("en") (note: buffer contains the other strings too) */
|
||||
WCHAR *country; /* country ("US") */
|
||||
WCHAR *script; /* script ("Latn") for Windows format only */
|
||||
WCHAR *modifier; /* modifier or sort order */
|
||||
LCID lcid; /* corresponding LCID */
|
||||
int matches; /* number of elements matching LCID (0..3) */
|
||||
};
|
||||
|
||||
/* locale ids corresponding to the various Unix locale parameters */
|
||||
static LCID lcid_LC_COLLATE;
|
||||
static LCID lcid_LC_CTYPE;
|
||||
static LCID lcid_LC_MESSAGES;
|
||||
static LCID lcid_LC_MONETARY;
|
||||
static LCID lcid_LC_NUMERIC;
|
||||
static LCID lcid_LC_TIME;
|
||||
static LCID lcid_LC_PAPER;
|
||||
static LCID lcid_LC_MEASUREMENT;
|
||||
static LCID lcid_LC_TELEPHONE;
|
||||
|
||||
static const WCHAR iCalendarTypeW[] = {'i','C','a','l','e','n','d','a','r','T','y','p','e',0};
|
||||
static const WCHAR iCountryW[] = {'i','C','o','u','n','t','r','y',0};
|
||||
static const WCHAR iCurrDigitsW[] = {'i','C','u','r','r','D','i','g','i','t','s',0};
|
||||
|
@ -275,353 +248,6 @@ static const union cptable *get_codepage_table( unsigned int codepage )
|
|||
}
|
||||
|
||||
|
||||
static LANGID get_default_sublang( LANGID lang )
|
||||
{
|
||||
switch (lang)
|
||||
{
|
||||
case MAKELANGID( LANG_SPANISH, SUBLANG_NEUTRAL ):
|
||||
return MAKELANGID( LANG_SPANISH, SUBLANG_SPANISH_MODERN );
|
||||
case MAKELANGID( LANG_CHINESE, SUBLANG_NEUTRAL ):
|
||||
return MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED );
|
||||
case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE ):
|
||||
return MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED );
|
||||
case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL ):
|
||||
case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_MACAU ):
|
||||
return MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_HONGKONG );
|
||||
}
|
||||
if (SUBLANGID( lang ) == SUBLANG_NEUTRAL) lang = MAKELANGID( PRIMARYLANGID(lang), SUBLANG_DEFAULT );
|
||||
return lang;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* find_locale_id_callback
|
||||
*/
|
||||
static BOOL CALLBACK find_locale_id_callback( HMODULE hModule, LPCWSTR type,
|
||||
LPCWSTR name, LANGID lang, LPARAM lParam )
|
||||
{
|
||||
struct locale_name *data = (struct locale_name *)lParam;
|
||||
WCHAR buffer[128];
|
||||
int matches = 0;
|
||||
LCID lcid = MAKELCID( lang, SORT_DEFAULT ); /* FIXME: handle sort order */
|
||||
|
||||
if (PRIMARYLANGID(lang) == LANG_NEUTRAL) return TRUE; /* continue search */
|
||||
|
||||
/* first check exact name */
|
||||
if (data->win_name[0] &&
|
||||
GetLocaleInfoW( lcid, LOCALE_SNAME | LOCALE_NOUSEROVERRIDE, buffer, ARRAY_SIZE( buffer )))
|
||||
{
|
||||
if (!strcmpiW( data->win_name, buffer ))
|
||||
{
|
||||
matches = 3; /* everything matches */
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (!GetLocaleInfoW( lcid, LOCALE_SISO639LANGNAME | LOCALE_NOUSEROVERRIDE,
|
||||
buffer, ARRAY_SIZE( buffer )))
|
||||
return TRUE;
|
||||
if (strcmpiW( buffer, data->lang )) return TRUE;
|
||||
matches++; /* language name matched */
|
||||
|
||||
if (data->script)
|
||||
{
|
||||
if (GetLocaleInfoW( lcid, LOCALE_SSCRIPTS | LOCALE_NOUSEROVERRIDE,
|
||||
buffer, ARRAY_SIZE( buffer )))
|
||||
{
|
||||
const WCHAR *p = buffer;
|
||||
unsigned int len = strlenW( data->script );
|
||||
while (*p)
|
||||
{
|
||||
if (!strncmpiW( p, data->script, len ) && (!p[len] || p[len] == ';')) break;
|
||||
if (!(p = strchrW( p, ';'))) goto done;
|
||||
p++;
|
||||
}
|
||||
if (!*p) goto done;
|
||||
matches++; /* script matched */
|
||||
}
|
||||
}
|
||||
|
||||
if (data->country)
|
||||
{
|
||||
if (GetLocaleInfoW( lcid, LOCALE_SISO3166CTRYNAME|LOCALE_NOUSEROVERRIDE,
|
||||
buffer, ARRAY_SIZE( buffer )))
|
||||
{
|
||||
if (strcmpiW( buffer, data->country )) goto done;
|
||||
matches++; /* country name matched */
|
||||
}
|
||||
}
|
||||
else /* match default language */
|
||||
{
|
||||
LANGID def_lang = data->script ? lang : MAKELANGID( PRIMARYLANGID(lang), LANG_NEUTRAL );
|
||||
if (lang == get_default_sublang( def_lang )) matches++;
|
||||
}
|
||||
|
||||
/* FIXME: check sort order */
|
||||
|
||||
done:
|
||||
if (matches > data->matches)
|
||||
{
|
||||
data->lcid = lcid;
|
||||
data->matches = matches;
|
||||
}
|
||||
return (data->matches < 3); /* 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->script = name->modifier = NULL;
|
||||
name->lcid = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT );
|
||||
name->matches = 0;
|
||||
name->win_name[0] = 0;
|
||||
lstrcpynW( name->lang, str, ARRAY_SIZE( name->lang ));
|
||||
|
||||
if (!*name->lang)
|
||||
{
|
||||
name->lcid = LOCALE_INVARIANT;
|
||||
name->matches = 3;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(p = strpbrkW( name->lang, sepW )))
|
||||
{
|
||||
if (!strcmpW( name->lang, posixW ) || !strcmpW( name->lang, cW ))
|
||||
{
|
||||
name->matches = 3; /* 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 )) && *p == '-')
|
||||
{
|
||||
*p++ = 0;
|
||||
name->script = name->country;
|
||||
name->country = p;
|
||||
p = strpbrkW( p, winsepW );
|
||||
}
|
||||
if (p)
|
||||
{
|
||||
*p++ = 0;
|
||||
name->modifier = p;
|
||||
}
|
||||
/* second value can be script or country, check length to resolve the ambiguity */
|
||||
if (!name->script && strlenW( name->country ) == 4)
|
||||
{
|
||||
name->script = name->country;
|
||||
name->country = NULL;
|
||||
}
|
||||
}
|
||||
else /* Unix format */
|
||||
{
|
||||
if (*p == '_')
|
||||
{
|
||||
*p++ = 0;
|
||||
name->country = p;
|
||||
p = strpbrkW( p, sepW + 2 );
|
||||
}
|
||||
if (p && *p == '.')
|
||||
{
|
||||
*p++ = 0;
|
||||
/* charset, ignore */
|
||||
p = strchrW( p, '@' );
|
||||
}
|
||||
if (p)
|
||||
{
|
||||
*p++ = 0;
|
||||
name->modifier = p;
|
||||
}
|
||||
|
||||
/* rebuild a Windows name if possible */
|
||||
|
||||
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.
|
||||
*/
|
||||
static LCID convert_default_lcid( LCID lcid, LCTYPE lctype )
|
||||
{
|
||||
if (lcid == LOCALE_SYSTEM_DEFAULT ||
|
||||
lcid == LOCALE_USER_DEFAULT ||
|
||||
lcid == LOCALE_NEUTRAL)
|
||||
{
|
||||
LCID default_id = 0;
|
||||
|
||||
switch(lctype & 0xffff)
|
||||
{
|
||||
case LOCALE_SSORTNAME:
|
||||
default_id = lcid_LC_COLLATE;
|
||||
break;
|
||||
|
||||
case LOCALE_FONTSIGNATURE:
|
||||
case LOCALE_IDEFAULTANSICODEPAGE:
|
||||
case LOCALE_IDEFAULTCODEPAGE:
|
||||
case LOCALE_IDEFAULTEBCDICCODEPAGE:
|
||||
case LOCALE_IDEFAULTMACCODEPAGE:
|
||||
default_id = lcid_LC_CTYPE;
|
||||
break;
|
||||
|
||||
case LOCALE_ICURRDIGITS:
|
||||
case LOCALE_ICURRENCY:
|
||||
case LOCALE_IINTLCURRDIGITS:
|
||||
case LOCALE_INEGCURR:
|
||||
case LOCALE_INEGSEPBYSPACE:
|
||||
case LOCALE_INEGSIGNPOSN:
|
||||
case LOCALE_INEGSYMPRECEDES:
|
||||
case LOCALE_IPOSSEPBYSPACE:
|
||||
case LOCALE_IPOSSIGNPOSN:
|
||||
case LOCALE_IPOSSYMPRECEDES:
|
||||
case LOCALE_SCURRENCY:
|
||||
case LOCALE_SINTLSYMBOL:
|
||||
case LOCALE_SMONDECIMALSEP:
|
||||
case LOCALE_SMONGROUPING:
|
||||
case LOCALE_SMONTHOUSANDSEP:
|
||||
case LOCALE_SNATIVECURRNAME:
|
||||
default_id = lcid_LC_MONETARY;
|
||||
break;
|
||||
|
||||
case LOCALE_IDIGITS:
|
||||
case LOCALE_IDIGITSUBSTITUTION:
|
||||
case LOCALE_ILZERO:
|
||||
case LOCALE_INEGNUMBER:
|
||||
case LOCALE_SDECIMAL:
|
||||
case LOCALE_SGROUPING:
|
||||
case LOCALE_SNAN:
|
||||
case LOCALE_SNATIVEDIGITS:
|
||||
case LOCALE_SNEGATIVESIGN:
|
||||
case LOCALE_SNEGINFINITY:
|
||||
case LOCALE_SPOSINFINITY:
|
||||
case LOCALE_SPOSITIVESIGN:
|
||||
case LOCALE_STHOUSAND:
|
||||
default_id = lcid_LC_NUMERIC;
|
||||
break;
|
||||
|
||||
case LOCALE_ICALENDARTYPE:
|
||||
case LOCALE_ICENTURY:
|
||||
case LOCALE_IDATE:
|
||||
case LOCALE_IDAYLZERO:
|
||||
case LOCALE_IFIRSTDAYOFWEEK:
|
||||
case LOCALE_IFIRSTWEEKOFYEAR:
|
||||
case LOCALE_ILDATE:
|
||||
case LOCALE_IMONLZERO:
|
||||
case LOCALE_IOPTIONALCALENDAR:
|
||||
case LOCALE_ITIME:
|
||||
case LOCALE_ITIMEMARKPOSN:
|
||||
case LOCALE_ITLZERO:
|
||||
case LOCALE_S1159:
|
||||
case LOCALE_S2359:
|
||||
case LOCALE_SABBREVDAYNAME1:
|
||||
case LOCALE_SABBREVDAYNAME2:
|
||||
case LOCALE_SABBREVDAYNAME3:
|
||||
case LOCALE_SABBREVDAYNAME4:
|
||||
case LOCALE_SABBREVDAYNAME5:
|
||||
case LOCALE_SABBREVDAYNAME6:
|
||||
case LOCALE_SABBREVDAYNAME7:
|
||||
case LOCALE_SABBREVMONTHNAME1:
|
||||
case LOCALE_SABBREVMONTHNAME2:
|
||||
case LOCALE_SABBREVMONTHNAME3:
|
||||
case LOCALE_SABBREVMONTHNAME4:
|
||||
case LOCALE_SABBREVMONTHNAME5:
|
||||
case LOCALE_SABBREVMONTHNAME6:
|
||||
case LOCALE_SABBREVMONTHNAME7:
|
||||
case LOCALE_SABBREVMONTHNAME8:
|
||||
case LOCALE_SABBREVMONTHNAME9:
|
||||
case LOCALE_SABBREVMONTHNAME10:
|
||||
case LOCALE_SABBREVMONTHNAME11:
|
||||
case LOCALE_SABBREVMONTHNAME12:
|
||||
case LOCALE_SABBREVMONTHNAME13:
|
||||
case LOCALE_SDATE:
|
||||
case LOCALE_SDAYNAME1:
|
||||
case LOCALE_SDAYNAME2:
|
||||
case LOCALE_SDAYNAME3:
|
||||
case LOCALE_SDAYNAME4:
|
||||
case LOCALE_SDAYNAME5:
|
||||
case LOCALE_SDAYNAME6:
|
||||
case LOCALE_SDAYNAME7:
|
||||
case LOCALE_SDURATION:
|
||||
case LOCALE_SLONGDATE:
|
||||
case LOCALE_SMONTHNAME1:
|
||||
case LOCALE_SMONTHNAME2:
|
||||
case LOCALE_SMONTHNAME3:
|
||||
case LOCALE_SMONTHNAME4:
|
||||
case LOCALE_SMONTHNAME5:
|
||||
case LOCALE_SMONTHNAME6:
|
||||
case LOCALE_SMONTHNAME7:
|
||||
case LOCALE_SMONTHNAME8:
|
||||
case LOCALE_SMONTHNAME9:
|
||||
case LOCALE_SMONTHNAME10:
|
||||
case LOCALE_SMONTHNAME11:
|
||||
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_STIME:
|
||||
case LOCALE_STIMEFORMAT:
|
||||
case LOCALE_SYEARMONTH:
|
||||
default_id = lcid_LC_TIME;
|
||||
break;
|
||||
|
||||
case LOCALE_IPAPERSIZE:
|
||||
default_id = lcid_LC_PAPER;
|
||||
break;
|
||||
|
||||
case LOCALE_IMEASURE:
|
||||
default_id = lcid_LC_MEASUREMENT;
|
||||
break;
|
||||
|
||||
case LOCALE_ICOUNTRY:
|
||||
default_id = lcid_LC_TELEPHONE;
|
||||
break;
|
||||
}
|
||||
if (default_id) lcid = default_id;
|
||||
}
|
||||
return ConvertDefaultLocale( lcid );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* is_genitive_name_supported
|
||||
*
|
||||
|
@ -732,12 +358,6 @@ void LOCALE_InitRegistry(void)
|
|||
static const WCHAR maccpW[] = {'M','A','C','C','P',0};
|
||||
static const WCHAR localeW[] = {'L','o','c','a','l','e',0};
|
||||
static const WCHAR lc_ctypeW[] = { 'L','C','_','C','T','Y','P','E',0 };
|
||||
static const WCHAR lc_monetaryW[] = { 'L','C','_','M','O','N','E','T','A','R','Y',0 };
|
||||
static const WCHAR lc_numericW[] = { 'L','C','_','N','U','M','E','R','I','C',0 };
|
||||
static const WCHAR lc_timeW[] = { 'L','C','_','T','I','M','E',0 };
|
||||
static const WCHAR lc_measurementW[] = { 'L','C','_','M','E','A','S','U','R','E','M','E','N','T',0 };
|
||||
static const WCHAR lc_telephoneW[] = { 'L','C','_','T','E','L','E','P','H','O','N','E',0 };
|
||||
static const WCHAR lc_paperW[] = { 'L','C','_','P','A','P','E','R',0};
|
||||
static const struct
|
||||
{
|
||||
LPCWSTR name;
|
||||
|
@ -750,8 +370,7 @@ void LOCALE_InitRegistry(void)
|
|||
static const LCTYPE lc_messages_values[] = {
|
||||
LOCALE_SABBREVLANGNAME,
|
||||
LOCALE_SCOUNTRY,
|
||||
LOCALE_SLIST };
|
||||
static const LCTYPE lc_monetary_values[] = {
|
||||
LOCALE_SLIST,
|
||||
LOCALE_SCURRENCY,
|
||||
LOCALE_ICURRENCY,
|
||||
LOCALE_INEGCURR,
|
||||
|
@ -759,8 +378,7 @@ void LOCALE_InitRegistry(void)
|
|||
LOCALE_ILZERO,
|
||||
LOCALE_SMONDECIMALSEP,
|
||||
LOCALE_SMONGROUPING,
|
||||
LOCALE_SMONTHOUSANDSEP };
|
||||
static const LCTYPE lc_numeric_values[] = {
|
||||
LOCALE_SMONTHOUSANDSEP,
|
||||
LOCALE_SDECIMAL,
|
||||
LOCALE_STHOUSAND,
|
||||
LOCALE_IDIGITS,
|
||||
|
@ -769,8 +387,7 @@ void LOCALE_InitRegistry(void)
|
|||
LOCALE_INEGNUMBER,
|
||||
LOCALE_SNEGATIVESIGN,
|
||||
LOCALE_SPOSITIVESIGN,
|
||||
LOCALE_SGROUPING };
|
||||
static const LCTYPE lc_time_values[] = {
|
||||
LOCALE_SGROUPING,
|
||||
LOCALE_S1159,
|
||||
LOCALE_S2359,
|
||||
LOCALE_STIME,
|
||||
|
@ -785,10 +402,10 @@ void LOCALE_InitRegistry(void)
|
|||
LOCALE_IFIRSTWEEKOFYEAR,
|
||||
LOCALE_STIMEFORMAT,
|
||||
LOCALE_SYEARMONTH,
|
||||
LOCALE_IDATE };
|
||||
static const LCTYPE lc_measurement_values[] = { LOCALE_IMEASURE };
|
||||
static const LCTYPE lc_telephone_values[] = { LOCALE_ICOUNTRY };
|
||||
static const LCTYPE lc_paper_values[] = { LOCALE_IPAPERSIZE };
|
||||
LOCALE_IDATE,
|
||||
LOCALE_IMEASURE,
|
||||
LOCALE_ICOUNTRY,
|
||||
LOCALE_IPAPERSIZE };
|
||||
|
||||
UNICODE_STRING nameW;
|
||||
WCHAR bufferW[80];
|
||||
|
@ -799,22 +416,10 @@ void LOCALE_InitRegistry(void)
|
|||
if (!(hkey = create_registry_key()))
|
||||
return; /* don't do anything if we can't create the registry key */
|
||||
|
||||
locale_update_registry( hkey, localeW, lcid_LC_MESSAGES, lc_messages_values,
|
||||
locale_update_registry( hkey, localeW, lcid, lc_messages_values,
|
||||
ARRAY_SIZE( lc_messages_values ));
|
||||
locale_update_registry( hkey, lc_monetaryW, lcid_LC_MONETARY, lc_monetary_values,
|
||||
ARRAY_SIZE( lc_monetary_values ));
|
||||
locale_update_registry( hkey, lc_numericW, lcid_LC_NUMERIC, lc_numeric_values,
|
||||
ARRAY_SIZE( lc_numeric_values ));
|
||||
locale_update_registry( hkey, lc_timeW, lcid_LC_TIME, lc_time_values,
|
||||
ARRAY_SIZE( lc_time_values ));
|
||||
locale_update_registry( hkey, lc_measurementW, lcid_LC_MEASUREMENT, lc_measurement_values,
|
||||
ARRAY_SIZE( lc_measurement_values ));
|
||||
locale_update_registry( hkey, lc_telephoneW, lcid_LC_TELEPHONE, lc_telephone_values,
|
||||
ARRAY_SIZE( lc_telephone_values ));
|
||||
locale_update_registry( hkey, lc_paperW, lcid_LC_PAPER, lc_paper_values,
|
||||
ARRAY_SIZE( lc_paper_values ));
|
||||
|
||||
if (locale_update_registry( hkey, lc_ctypeW, lcid_LC_CTYPE, NULL, 0 ))
|
||||
if (locale_update_registry( hkey, lc_ctypeW, GetSystemDefaultLCID(), NULL, 0 ))
|
||||
{
|
||||
static const WCHAR codepageW[] =
|
||||
{'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
|
||||
|
@ -853,198 +458,6 @@ void LOCALE_InitRegistry(void)
|
|||
}
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
/***********************************************************************
|
||||
* get_mac_locale
|
||||
*
|
||||
* Return a locale identifier string reflecting the Mac locale, in a form
|
||||
* that parse_locale_name() will understand. So, strip out unusual
|
||||
* things like script, variant, etc. Or, rather, just construct it as
|
||||
* <lang>[_<country>]
|
||||
*/
|
||||
static const char* get_mac_locale(void)
|
||||
{
|
||||
static char mac_locale[50];
|
||||
|
||||
if (!mac_locale[0])
|
||||
{
|
||||
CFLocaleRef locale = CFLocaleCopyCurrent();
|
||||
CFStringRef lang = CFLocaleGetValue( locale, kCFLocaleLanguageCode );
|
||||
CFStringRef country = CFLocaleGetValue( locale, kCFLocaleCountryCode );
|
||||
CFStringRef locale_string;
|
||||
|
||||
if (country)
|
||||
locale_string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@_%@"), lang, country);
|
||||
else
|
||||
locale_string = CFStringCreateCopy(NULL, lang);
|
||||
|
||||
CFStringGetCString(locale_string, mac_locale, sizeof(mac_locale), kCFStringEncodingUTF8);
|
||||
CFRelease(locale);
|
||||
CFRelease(locale_string);
|
||||
}
|
||||
|
||||
return mac_locale;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* has_env
|
||||
*/
|
||||
static BOOL has_env(const char* name)
|
||||
{
|
||||
const char* value = getenv( name );
|
||||
return value && value[0];
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_locale
|
||||
*
|
||||
* Get the locale identifier for a given category. On most platforms,
|
||||
* this is just a thin wrapper around setlocale(). On OS X, though, it
|
||||
* is common for the Mac locale settings to not be supported by the C
|
||||
* library. So, we sometimes override the result with the Mac locale.
|
||||
*/
|
||||
static const char* get_locale(int category, const char* category_name)
|
||||
{
|
||||
const char* ret = setlocale(category, NULL);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (!strcmp(ret, "C"))
|
||||
{
|
||||
ret = getenv( category_name );
|
||||
if (!ret || !ret[0]) ret = getenv( "LC_ALL" );
|
||||
if (!ret || !ret[0]) ret = "C";
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
/* If LC_ALL is set, respect it as a user override.
|
||||
If LC_* is set, respect it as a user override, except if it's LC_CTYPE
|
||||
and equal to UTF-8. That's because, when the Mac locale isn't supported
|
||||
by the C library, Terminal.app sets LC_CTYPE=UTF-8 and doesn't set LANG.
|
||||
parse_locale_name() doesn't handle that properly, so we override that
|
||||
with the Mac locale (which uses UTF-8 for the charset, anyway).
|
||||
Otherwise:
|
||||
For LC_MESSAGES, we override the C library because the user language
|
||||
setting is separate from the locale setting on which LANG was based.
|
||||
If the C library didn't get anything better from LANG than C or POSIX,
|
||||
override that. That probably means the Mac locale isn't supported by
|
||||
the C library. */
|
||||
if (!has_env( "LC_ALL" ) &&
|
||||
((category == LC_CTYPE && !strcmp( ret, "UTF-8" )) ||
|
||||
(!has_env( category_name ) &&
|
||||
(category == LC_MESSAGES || !strcmp( ret, "C" ) || !strcmp( ret, "POSIX" )))))
|
||||
{
|
||||
const char* override = get_mac_locale();
|
||||
|
||||
if (category == LC_MESSAGES)
|
||||
{
|
||||
/* Retrieve the preferred language as chosen in System Preferences. */
|
||||
static char messages_locale[50];
|
||||
|
||||
if (!messages_locale[0])
|
||||
{
|
||||
CFArrayRef preferred_langs = CFLocaleCopyPreferredLanguages();
|
||||
if (preferred_langs && CFArrayGetCount( preferred_langs ))
|
||||
{
|
||||
CFStringRef preferred_lang = CFArrayGetValueAtIndex( preferred_langs, 0 );
|
||||
CFDictionaryRef components = CFLocaleCreateComponentsFromLocaleIdentifier( NULL, preferred_lang );
|
||||
if (components)
|
||||
{
|
||||
CFStringRef lang = CFDictionaryGetValue( components, kCFLocaleLanguageCode );
|
||||
CFStringRef country = CFDictionaryGetValue( components, kCFLocaleCountryCode );
|
||||
CFLocaleRef locale = NULL;
|
||||
CFStringRef locale_string;
|
||||
|
||||
if (!country)
|
||||
{
|
||||
locale = CFLocaleCopyCurrent();
|
||||
country = CFLocaleGetValue( locale, kCFLocaleCountryCode );
|
||||
}
|
||||
|
||||
if (country)
|
||||
locale_string = CFStringCreateWithFormat( NULL, NULL, CFSTR("%@_%@"), lang, country );
|
||||
else
|
||||
locale_string = CFStringCreateCopy( NULL, lang );
|
||||
CFStringGetCString( locale_string, messages_locale, sizeof(messages_locale), kCFStringEncodingUTF8 );
|
||||
|
||||
CFRelease( locale_string );
|
||||
if (locale) CFRelease( locale );
|
||||
CFRelease( components );
|
||||
}
|
||||
}
|
||||
if (preferred_langs)
|
||||
CFRelease( preferred_langs );
|
||||
}
|
||||
|
||||
if (messages_locale[0])
|
||||
override = messages_locale;
|
||||
}
|
||||
|
||||
TRACE( "%s is %s; overriding with %s\n", category_name, debugstr_a(ret), debugstr_a(override) );
|
||||
ret = override;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* setup_unix_locales
|
||||
*/
|
||||
static void setup_unix_locales(void)
|
||||
{
|
||||
struct locale_name locale_name;
|
||||
WCHAR buffer[128], ctype_buff[128];
|
||||
const char *locale;
|
||||
|
||||
if ((locale = get_locale( LC_CTYPE, "LC_CTYPE" )))
|
||||
{
|
||||
strcpynAtoW( ctype_buff, locale, ARRAY_SIZE( ctype_buff ));
|
||||
parse_locale_name( ctype_buff, &locale_name );
|
||||
lcid_LC_CTYPE = locale_name.lcid;
|
||||
}
|
||||
if (!lcid_LC_CTYPE) /* this one needs a default value */
|
||||
lcid_LC_CTYPE = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT );
|
||||
|
||||
TRACE( "got lcid %04x (%d matches) for LC_CTYPE=%s\n",
|
||||
locale_name.lcid, locale_name.matches, debugstr_a(locale) );
|
||||
|
||||
#define GET_UNIX_LOCALE(cat) do \
|
||||
if ((locale = get_locale( cat, #cat ))) \
|
||||
{ \
|
||||
strcpynAtoW( buffer, locale, ARRAY_SIZE(buffer) ); \
|
||||
if (!strcmpW( buffer, ctype_buff )) lcid_##cat = lcid_LC_CTYPE; \
|
||||
else { \
|
||||
parse_locale_name( buffer, &locale_name ); \
|
||||
lcid_##cat = locale_name.lcid; \
|
||||
TRACE( "got lcid %04x (%d matches) for " #cat "=%s\n", \
|
||||
locale_name.lcid, locale_name.matches, debugstr_a(locale) ); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
GET_UNIX_LOCALE( LC_COLLATE );
|
||||
GET_UNIX_LOCALE( LC_MESSAGES );
|
||||
GET_UNIX_LOCALE( LC_MONETARY );
|
||||
GET_UNIX_LOCALE( LC_NUMERIC );
|
||||
GET_UNIX_LOCALE( LC_TIME );
|
||||
#ifdef LC_PAPER
|
||||
GET_UNIX_LOCALE( LC_PAPER );
|
||||
#endif
|
||||
#ifdef LC_MEASUREMENT
|
||||
GET_UNIX_LOCALE( LC_MEASUREMENT );
|
||||
#endif
|
||||
#ifdef LC_TELEPHONE
|
||||
GET_UNIX_LOCALE( LC_TELEPHONE );
|
||||
#endif
|
||||
|
||||
#undef GET_UNIX_LOCALE
|
||||
}
|
||||
|
||||
|
||||
static BOOL get_dummy_preferred_ui_language( DWORD flags, ULONG *count, WCHAR *buffer, ULONG *size )
|
||||
{
|
||||
LCTYPE type;
|
||||
|
@ -1412,7 +825,6 @@ static int get_value_base_by_lctype( LCTYPE lctype )
|
|||
*/
|
||||
INT WINAPI GetLocaleInfoW( LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len )
|
||||
{
|
||||
LANGID lang_id;
|
||||
HRSRC hrsrc;
|
||||
HGLOBAL hmem;
|
||||
INT ret;
|
||||
|
@ -1434,8 +846,7 @@ INT WINAPI GetLocaleInfoW( LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len )
|
|||
|
||||
if (!len) buffer = NULL;
|
||||
|
||||
lcid = convert_default_lcid( lcid, lctype );
|
||||
|
||||
lcid = ConvertDefaultLocale( lcid );
|
||||
lcflags = lctype & LOCALE_LOCALEINFOFLAGSMASK;
|
||||
lctype &= 0xffff;
|
||||
|
||||
|
@ -1443,8 +854,7 @@ INT WINAPI GetLocaleInfoW( LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len )
|
|||
|
||||
/* first check for overrides in the registry */
|
||||
|
||||
if (!(lcflags & LOCALE_NOUSEROVERRIDE) &&
|
||||
lcid == convert_default_lcid( LOCALE_USER_DEFAULT, lctype ))
|
||||
if (!(lcflags & LOCALE_NOUSEROVERRIDE) && lcid == ConvertDefaultLocale( LOCALE_USER_DEFAULT ))
|
||||
{
|
||||
struct registry_value *value = get_locale_registry_value(lctype);
|
||||
|
||||
|
@ -1481,13 +891,8 @@ INT WINAPI GetLocaleInfoW( LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len )
|
|||
|
||||
/* now load it from kernel resources */
|
||||
|
||||
lang_id = LANGIDFROMLCID( lcid );
|
||||
|
||||
/* replace SUBLANG_NEUTRAL by SUBLANG_DEFAULT */
|
||||
if (SUBLANGID(lang_id) == SUBLANG_NEUTRAL) lang_id = get_default_sublang( lang_id );
|
||||
|
||||
if (!(hrsrc = FindResourceExW( kernel32_handle, (LPWSTR)RT_STRING,
|
||||
ULongToPtr((lctype >> 4) + 1), lang_id )))
|
||||
ULongToPtr((lctype >> 4) + 1), lcid )))
|
||||
{
|
||||
SetLastError( ERROR_INVALID_FLAGS ); /* no such lctype */
|
||||
return 0;
|
||||
|
@ -3532,33 +2937,10 @@ void LOCALE_Init(void)
|
|||
|
||||
UINT ansi_cp = 1252, oem_cp = 437, mac_cp = 10000, unix_cp;
|
||||
|
||||
setlocale( LC_ALL, "" );
|
||||
|
||||
#ifdef __APPLE__
|
||||
/* MacOS doesn't set the locale environment variables so we have to do it ourselves */
|
||||
if (!has_env("LANG"))
|
||||
{
|
||||
const char* mac_locale = get_mac_locale();
|
||||
|
||||
setenv( "LANG", mac_locale, 1 );
|
||||
if (setlocale( LC_ALL, "" ))
|
||||
TRACE( "setting LANG to '%s'\n", mac_locale );
|
||||
else
|
||||
{
|
||||
/* no C library locale matching Mac locale; don't pass garbage to children */
|
||||
unsetenv("LANG");
|
||||
TRACE( "Mac locale %s is not supported by the C library\n", debugstr_a(mac_locale) );
|
||||
}
|
||||
}
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
setup_unix_locales();
|
||||
if (!lcid_LC_MESSAGES) lcid_LC_MESSAGES = lcid_LC_CTYPE;
|
||||
|
||||
ansi_cp = get_lcid_codepage( LOCALE_USER_DEFAULT );
|
||||
GetLocaleInfoW( LOCALE_USER_DEFAULT, LOCALE_IDEFAULTMACCODEPAGE | LOCALE_RETURN_NUMBER,
|
||||
ansi_cp = get_lcid_codepage( LOCALE_SYSTEM_DEFAULT );
|
||||
GetLocaleInfoW( LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTMACCODEPAGE | LOCALE_RETURN_NUMBER,
|
||||
(LPWSTR)&mac_cp, sizeof(mac_cp)/sizeof(WCHAR) );
|
||||
GetLocaleInfoW( LOCALE_USER_DEFAULT, LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
|
||||
GetLocaleInfoW( LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
|
||||
(LPWSTR)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR) );
|
||||
|
||||
if (!(ansi_cptable = wine_cp_get_table( ansi_cp )))
|
||||
|
@ -3575,8 +2957,6 @@ void LOCALE_Init(void)
|
|||
TRACE( "ansi=%03d oem=%03d mac=%03d unix=%03d\n",
|
||||
ansi_cptable->info.codepage, oem_cptable->info.codepage,
|
||||
mac_cptable->info.codepage, unix_cp );
|
||||
|
||||
setlocale(LC_NUMERIC, "C"); /* FIXME: oleaut32 depends on this */
|
||||
}
|
||||
|
||||
static HANDLE NLS_RegOpenKey(HANDLE hRootKey, LPCWSTR szKeyName)
|
||||
|
|
Loading…
Reference in New Issue