ntdll: Move the locales initialization to the Unix library.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
feature/deterministic
Alexandre Julliard 2020-06-11 11:38:16 +02:00
parent ee5c842e53
commit b86dc3926b
5 changed files with 200 additions and 142 deletions

View File

@ -22,16 +22,10 @@
#include "config.h"
#include "wine/port.h"
#include <locale.h>
#include <stdarg.h>
#include <string.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"
@ -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 */
}

View File

@ -44,6 +44,10 @@
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef __APPLE__
# include <CoreFoundation/CFLocale.h>
# include <CoreFoundation/CFString.h>
#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 );
}

View File

@ -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,

View File

@ -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 */

View File

@ -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 );