diff --git a/dlls/ntdll/locale.c b/dlls/ntdll/locale.c index 15ccdeb2e63..d6bde700e42 100644 --- a/dlls/ntdll/locale.c +++ b/dlls/ntdll/locale.c @@ -22,16 +22,10 @@ #include "config.h" #include "wine/port.h" -#include #include #include #include -#ifdef __APPLE__ -# include -# include -#endif - #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" @@ -697,80 +691,18 @@ void init_unix_codepage(void) unix_funcs->get_unix_codepage( &unix_table ); } -/* Unix format is: lang[_country][.charset][@modifier] - * Windows format is: lang[-script][-country][_modifier] */ -static LCID unix_locale_to_lcid( const char *unix_name ) + +static LCID locale_to_lcid( WCHAR *win_name ) { - static const WCHAR sepW[] = {'_','.','@',0}; - static const WCHAR posixW[] = {'P','O','S','I','X',0}; - static const WCHAR cW[] = {'C',0}; - static const WCHAR euroW[] = {'e','u','r','o',0}; - static const WCHAR latinW[] = {'l','a','t','i','n',0}; - static const WCHAR latnW[] = {'-','L','a','t','n',0}; - WCHAR buffer[LOCALE_NAME_MAX_LENGTH], win_name[LOCALE_NAME_MAX_LENGTH]; - WCHAR *p, *country = NULL, *modifier = NULL; - DWORD len; + WCHAR *p; LCID lcid; - if (!unix_name || !unix_name[0] || !strcmp( unix_name, "C" )) - { - unix_name = getenv( "LC_ALL" ); - if (!unix_name || !unix_name[0]) return 0; - } - - len = ntdll_umbstowcs( unix_name, strlen(unix_name), buffer, ARRAY_SIZE(buffer) ); - if (len == ARRAY_SIZE(buffer)) return 0; - buffer[len] = 0; - - if (!(p = wcspbrk( buffer, sepW ))) - { - if (!wcscmp( buffer, posixW ) || !wcscmp( buffer, cW )) - return MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT ); - wcscpy( win_name, buffer ); - } - else - { - if (*p == '_') - { - *p++ = 0; - country = p; - p = wcspbrk( p, sepW + 1 ); - } - if (p && *p == '.') - { - *p++ = 0; - /* charset, ignore */ - p = wcschr( p, '@' ); - } - if (p) - { - *p++ = 0; - modifier = p; - } - } - - /* rebuild a Windows name */ - - wcscpy( win_name, buffer ); - if (modifier) - { - if (!wcscmp( modifier, latinW )) wcscat( win_name, latnW ); - else if (!wcscmp( modifier, euroW )) {} /* ignore */ - else return 0; - } - if (country) - { - p = win_name + wcslen(win_name); - *p++ = '-'; - wcscpy( p, country ); - } - if (!RtlLocaleNameToLcid( win_name, &lcid, 0 )) return lcid; /* try neutral name */ - if (country) + if ((p = wcsrchr( win_name, '-' ))) { - p[-1] = 0; + *p = 0; if (!RtlLocaleNameToLcid( win_name, &lcid, 2 )) { if (SUBLANGID(lcid) == SUBLANG_NEUTRAL) @@ -787,75 +719,20 @@ static LCID unix_locale_to_lcid( const char *unix_name ) */ void init_locale( HMODULE module ) { + WCHAR system_locale[LOCALE_NAME_MAX_LENGTH]; + WCHAR user_locale[LOCALE_NAME_MAX_LENGTH]; LCID system_lcid, user_lcid; +#ifdef __APPLE__ + const struct norm_table *info; + load_norm_table( NormalizationC, &info ); +#endif + kernel32_handle = module; - setlocale( LC_ALL, "" ); - - system_lcid = unix_locale_to_lcid( setlocale( LC_CTYPE, NULL )); - user_lcid = unix_locale_to_lcid( setlocale( LC_MESSAGES, NULL )); - -#ifdef __APPLE__ - { - const struct norm_table *info; - load_norm_table( NormalizationC, &info ); - } - if (!system_lcid) - { - char buffer[LOCALE_NAME_MAX_LENGTH]; - - 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, buffer, sizeof(buffer), kCFStringEncodingUTF8); - system_lcid = unix_locale_to_lcid( buffer ); - CFRelease(locale); - CFRelease(locale_string); - } - if (!user_lcid) - { - /* Retrieve the preferred language as chosen in System Preferences. */ - char buffer[LOCALE_NAME_MAX_LENGTH]; - 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, buffer, sizeof(buffer), kCFStringEncodingUTF8 ); - CFRelease( locale_string ); - if (locale) CFRelease( locale ); - CFRelease( components ); - user_lcid = unix_locale_to_lcid( buffer ); - } - } - if (preferred_langs) CFRelease( preferred_langs ); - } -#endif - + unix_funcs->get_locales( system_locale, user_locale ); + system_lcid = locale_to_lcid( system_locale ); + user_lcid = locale_to_lcid( user_locale ); if (!system_lcid) system_lcid = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT ); if (!user_lcid) user_lcid = system_lcid; @@ -863,8 +740,6 @@ void init_locale( HMODULE module ) NtSetDefaultLocale( TRUE, user_lcid ); NtSetDefaultLocale( FALSE, system_lcid ); TRACE( "system=%04x user=%04x\n", system_lcid, user_lcid ); - - setlocale( LC_NUMERIC, "C" ); /* FIXME: oleaut32 depends on this */ } diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c index 95d3c7679cb..2d6fe6ec966 100644 --- a/dlls/ntdll/unix/env.c +++ b/dlls/ntdll/unix/env.c @@ -44,6 +44,10 @@ #ifdef HAVE_UNISTD_H # include #endif +#ifdef __APPLE__ +# include +# include +#endif #include "ntstatus.h" #define WIN32_NO_STATUS @@ -67,6 +71,8 @@ static char **main_envp; static WCHAR **main_wargv; static CPTABLEINFO unix_table; +static WCHAR system_locale[LOCALE_NAME_MAX_LENGTH]; +static WCHAR user_locale[LOCALE_NAME_MAX_LENGTH]; #ifdef __APPLE__ @@ -529,12 +535,146 @@ static WCHAR **build_wargv( char **argv ) } +/* Unix format is: lang[_country][.charset][@modifier] + * Windows format is: lang[-script][-country][_modifier] */ +static BOOL unix_to_win_locale( const char *unix_name, WCHAR *win_name ) +{ + static const WCHAR sepW[] = {'_','.','@',0}; + static const WCHAR posixW[] = {'P','O','S','I','X',0}; + static const WCHAR cW[] = {'C',0}; + static const WCHAR euroW[] = {'e','u','r','o',0}; + static const WCHAR latinW[] = {'l','a','t','i','n',0}; + static const WCHAR latnW[] = {'-','L','a','t','n',0}; + static const WCHAR enUSW[] = {'e','n','-','U','S',0}; + WCHAR buffer[LOCALE_NAME_MAX_LENGTH]; + WCHAR *p, *country = NULL, *modifier = NULL; + DWORD len; + + if (!unix_name || !unix_name[0] || !strcmp( unix_name, "C" )) + { + unix_name = getenv( "LC_ALL" ); + if (!unix_name || !unix_name[0]) return FALSE; + } + + len = ntdll_umbstowcs( unix_name, strlen(unix_name), buffer, ARRAY_SIZE(buffer) ); + if (len == ARRAY_SIZE(buffer)) return FALSE; + buffer[len] = 0; + + if (!(p = wcspbrk( buffer, sepW ))) + { + if (!wcscmp( buffer, posixW ) || !wcscmp( buffer, cW )) + wcscpy( win_name, enUSW ); + else + wcscpy( win_name, buffer ); + return TRUE; + } + + if (*p == '_') + { + *p++ = 0; + country = p; + p = wcspbrk( p, sepW + 1 ); + } + if (p && *p == '.') + { + *p++ = 0; + /* charset, ignore */ + p = wcschr( p, '@' ); + } + if (p) + { + *p++ = 0; + modifier = p; + } + + /* rebuild a Windows name */ + + wcscpy( win_name, buffer ); + if (modifier) + { + if (!wcscmp( modifier, latinW )) wcscat( win_name, latnW ); + else if (!wcscmp( modifier, euroW )) {} /* ignore */ + else return FALSE; + } + if (country) + { + p = win_name + wcslen(win_name); + *p++ = '-'; + wcscpy( p, country ); + } + return TRUE; +} + + +/****************************************************************** + * init_locale + */ +static void init_locale(void) +{ + setlocale( LC_ALL, "" ); + if (!unix_to_win_locale( setlocale( LC_CTYPE, NULL ), system_locale )) system_locale[0] = 0; + if (!unix_to_win_locale( setlocale( LC_MESSAGES, NULL ), user_locale )) user_locale[0] = 0; + +#ifdef __APPLE__ + if (!system_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, system_locale, sizeof(system_locale), kCFStringEncodingUTF8); + CFRelease(locale); + CFRelease(locale_string); + } + if (!user_locale[0]) + { + /* Retrieve the preferred language as chosen in System Preferences. */ + 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, user_locale, sizeof(user_locale), kCFStringEncodingUTF8 ); + CFRelease( locale_string ); + if (locale) CFRelease( locale ); + CFRelease( components ); + } + } + if (preferred_langs) CFRelease( preferred_langs ); + } +#endif +} + + /*********************************************************************** * init_environment */ void init_environment( int argc, char *argv[], char *envp[] ) { init_unix_codepage(); + init_locale(); set_process_name( argc, argv ); __wine_main_argc = main_argc = argc; __wine_main_argv = main_argv = argv; @@ -604,3 +744,15 @@ void CDECL get_unix_codepage( CPTABLEINFO *table ) { *table = unix_table; } + + +/************************************************************************* + * get_locales + * + * Return the system and user locales. Buffers must be at least LOCALE_NAME_MAX_LENGTH chars long. + */ +void CDECL get_locales( WCHAR *sys, WCHAR *user ) +{ + wcscpy( sys, system_locale ); + wcscpy( user, user_locale ); +} diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 50acd84139f..bb13144f9d5 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -902,6 +902,7 @@ static struct unix_funcs unix_funcs = get_paths, get_dll_path, get_unix_codepage, + get_locales, get_version, get_build_id, get_host_version, diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 6830ec2b63f..cc30761b1e2 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -81,6 +81,7 @@ int CDECL mmap_enum_reserved_areas( int (CDECL *enum_func)(void *base, SIZE_T s extern void CDECL get_main_args( int *argc, char **argv[], char **envp[] ) DECLSPEC_HIDDEN; extern NTSTATUS CDECL get_initial_environment( WCHAR **wargv[], WCHAR *env, SIZE_T *size ) DECLSPEC_HIDDEN; extern void CDECL get_unix_codepage( CPTABLEINFO *table ) DECLSPEC_HIDDEN; +extern void CDECL get_locales( WCHAR *sys, WCHAR *user ) DECLSPEC_HIDDEN; extern NTSTATUS CDECL virtual_map_section( HANDLE handle, PVOID *addr_ptr, unsigned short zero_bits_64, SIZE_T commit_size, const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, ULONG alloc_type, ULONG protect, pe_image_info_t *image_info ) DECLSPEC_HIDDEN; @@ -190,7 +191,35 @@ static inline WCHAR *ntdll_wcscpy( WCHAR *dst, const WCHAR *src ) return dst; } -#define wcslen(str) ntdll_wcslen(str) +static inline WCHAR *ntdll_wcscat( WCHAR *dst, const WCHAR *src ) +{ + ntdll_wcscpy( dst + ntdll_wcslen(dst), src ); + return dst; +} + +static inline int ntdll_wcscmp( const WCHAR *str1, const WCHAR *str2 ) +{ + while (*str1 && (*str1 == *str2)) { str1++; str2++; } + return *str1 - *str2; +} + +static inline WCHAR *ntdll_wcschr( const WCHAR *str, WCHAR ch ) +{ + do { if (*str == ch) return (WCHAR *)(ULONG_PTR)str; } while (*str++); + return NULL; +} + +static inline WCHAR *ntdll_wcspbrk( const WCHAR *str, const WCHAR *accept ) +{ + for ( ; *str; str++) if (ntdll_wcschr( accept, *str )) return (WCHAR *)(ULONG_PTR)str; + return NULL; +} + +#define wcslen(str) ntdll_wcslen(str) #define wcscpy(dst,src) ntdll_wcscpy(dst,src) +#define wcscat(dst,src) ntdll_wcscat(dst,src) +#define wcscmp(s1,s2) ntdll_wcscmp(s1,s2) +#define wcschr(str,ch) ntdll_wcschr(str,ch) +#define wcspbrk(str,ac) ntdll_wcspbrk(str,ac) #endif /* __NTDLL_UNIX_PRIVATE_H */ diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 938c4ec9c97..54705b7f6d2 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -28,7 +28,7 @@ struct ldt_copy; struct msghdr; /* increment this when you change the function table */ -#define NTDLL_UNIXLIB_VERSION 39 +#define NTDLL_UNIXLIB_VERSION 40 struct unix_funcs { @@ -175,6 +175,7 @@ struct unix_funcs void (CDECL *get_paths)( const char **builddir, const char **datadir, const char **configdir ); void (CDECL *get_dll_path)( const char ***paths, SIZE_T *maxlen ); void (CDECL *get_unix_codepage)( CPTABLEINFO *table ); + void (CDECL *get_locales)( WCHAR *sys, WCHAR *user ); const char * (CDECL *get_version)(void); const char * (CDECL *get_build_id)(void); void (CDECL *get_host_version)( const char **sysname, const char **release );