@ -234,6 +234,7 @@ pg_perm_setlocale(int category, const char *locale)
result = IsoLocaleName ( locale ) ;
result = IsoLocaleName ( locale ) ;
if ( result = = NULL )
if ( result = = NULL )
result = ( char * ) locale ;
result = ( char * ) locale ;
elog ( DEBUG3 , " IsoLocaleName() executed; locale: \" %s \" " , result ) ;
# endif /* WIN32 */
# endif /* WIN32 */
break ;
break ;
# endif /* LC_MESSAGES */
# endif /* LC_MESSAGES */
@ -971,25 +972,185 @@ cache_locale_time(void)
* string . Furthermore , msvcr110 . dll changed the undocumented _locale_t
* string . Furthermore , msvcr110 . dll changed the undocumented _locale_t
* content to carry locale names instead of locale identifiers .
* content to carry locale names instead of locale identifiers .
*
*
* MinGW headers declare _create_locale ( ) , but msvcrt . dll lacks that symbol .
* Visual Studio 2015 should still be able to do the same as Visual Studio
* IsoLocaleName ( ) always fails in a MinGW - built postgres . exe , so only
* 2012 , but the declaration of locale_name is missing in _locale_t , causing
* Unix - style values of the lc_messages GUC can elicit localized messages . In
* this code compilation to fail , hence this falls back instead on to
* particular , every lc_messages setting that initdb can select automatically
* enumerating all system locales by using EnumSystemLocalesEx to find the
* will yield only C - locale messages . XXX This could be fixed by running the
* required locale name . If the input argument is in Unix - style then we can
* fully - qualified locale name through a lookup table .
* get ISO Locale name directly by using GetLocaleInfoEx ( ) with LCType as
* LOCALE_SNAME .
*
* MinGW headers declare _create_locale ( ) , but msvcrt . dll lacks that symbol in
* releases before Windows 8. IsoLocaleName ( ) always fails in a MinGW - built
* postgres . exe , so only Unix - style values of the lc_messages GUC can elicit
* localized messages . In particular , every lc_messages setting that initdb
* can select automatically will yield only C - locale messages . XXX This could
* be fixed by running the fully - qualified locale name through a lookup table .
*
*
* This function returns a pointer to a static buffer bearing the converted
* This function returns a pointer to a static buffer bearing the converted
* name or NULL if conversion fails .
* name or NULL if conversion fails .
*
*
* [ 1 ] http : //msdn.microsoft.com/en-us/library/windows/desktop/dd373763.aspx
* [ 1 ] https : //docs.microsoft.com/en-us/windows/win32/intl/locale-identifiers
* [ 2 ] http : //msdn.microsoft.com/en-us/library/windows/desktop/dd373814.aspx
* [ 2 ] https : //docs.microsoft.com/en-us/windows/win32/intl/locale-names
*/
# if _MSC_VER >= 1900
/*
* Callback function for EnumSystemLocalesEx ( ) in get_iso_localename ( ) .
*
* This function enumerates all system locales , searching for one that matches
* an input with the format : < Language > [ _ < Country > ] , e . g .
* English [ _United States ]
*
* The input is a three wchar_t array as an LPARAM . The first element is the
* locale_name we want to match , the second element is an allocated buffer
* where the Unix - style locale is copied if a match is found , and the third
* element is the search status , 1 if a match was found , 0 otherwise .
*/
static BOOL CALLBACK
search_locale_enum ( LPWSTR pStr , DWORD dwFlags , LPARAM lparam )
{
wchar_t test_locale [ LOCALE_NAME_MAX_LENGTH ] ;
wchar_t * * argv ;
( void ) ( dwFlags ) ;
argv = ( wchar_t * * ) lparam ;
* argv [ 2 ] = ( wchar_t ) 0 ;
memset ( test_locale , 0 , sizeof ( test_locale ) ) ;
/* Get the name of the <Language> in English */
if ( GetLocaleInfoEx ( pStr , LOCALE_SENGLISHLANGUAGENAME ,
test_locale , LOCALE_NAME_MAX_LENGTH ) )
{
/*
* If the enumerated locale does not have a hyphen ( " en " ) OR the
* lc_message input does not have an underscore ( " English " ) , we only
* need to compare the < Language > tags .
*/
if ( wcsrchr ( pStr , ' - ' ) = = NULL | | wcsrchr ( argv [ 0 ] , ' _ ' ) = = NULL )
{
if ( _wcsicmp ( argv [ 0 ] , test_locale ) = = 0 )
{
wcscpy ( argv [ 1 ] , pStr ) ;
* argv [ 2 ] = ( wchar_t ) 1 ;
return FALSE ;
}
}
/*
* We have to compare a full < Language > _ < Country > tag , so we append
* the underscore and name of the country / region in English , e . g .
* " English_United States " .
*/
else
{
size_t len ;
wcscat ( test_locale , L " _ " ) ;
len = wcslen ( test_locale ) ;
if ( GetLocaleInfoEx ( pStr , LOCALE_SENGLISHCOUNTRYNAME ,
test_locale + len ,
LOCALE_NAME_MAX_LENGTH - len ) )
{
if ( _wcsicmp ( argv [ 0 ] , test_locale ) = = 0 )
{
wcscpy ( argv [ 1 ] , pStr ) ;
* argv [ 2 ] = ( wchar_t ) 1 ;
return FALSE ;
}
}
}
}
return TRUE ;
}
/*
* This function converts a Windows locale name to an ISO formatted version
* for Visual Studio 2015 or greater .
*
* Returns NULL , if no valid conversion was found .
*/
static char *
get_iso_localename ( const char * winlocname )
{
wchar_t wc_locale_name [ LOCALE_NAME_MAX_LENGTH ] ;
wchar_t buffer [ LOCALE_NAME_MAX_LENGTH ] ;
static char iso_lc_messages [ LOCALE_NAME_MAX_LENGTH ] ;
char * period ;
int len ;
int ret_val ;
/*
* Valid locales have the following syntax :
* < Language > [ _ < Country > [ . < CodePage > ] ]
*
* GetLocaleInfoEx can only take locale name without code - page and for the
* purpose of this API the code - page doesn ' t matter .
*/
period = strchr ( winlocname , ' . ' ) ;
if ( period ! = NULL )
len = period - winlocname ;
else
len = pg_mbstrlen ( winlocname ) ;
memset ( wc_locale_name , 0 , sizeof ( wc_locale_name ) ) ;
memset ( buffer , 0 , sizeof ( buffer ) ) ;
MultiByteToWideChar ( CP_ACP , 0 , winlocname , len , wc_locale_name ,
LOCALE_NAME_MAX_LENGTH ) ;
/*
* If the lc_messages is already an Unix - style string , we have a direct
* match with LOCALE_SNAME , e . g . en - US , en_US .
*/
ret_val = GetLocaleInfoEx ( wc_locale_name , LOCALE_SNAME , ( LPWSTR ) & buffer ,
LOCALE_NAME_MAX_LENGTH ) ;
if ( ! ret_val )
{
/*
* Search for a locale in the system that matches language and country
* name .
*/
wchar_t * argv [ 3 ] ;
argv [ 0 ] = wc_locale_name ;
argv [ 1 ] = buffer ;
argv [ 2 ] = ( wchar_t * ) & ret_val ;
EnumSystemLocalesEx ( search_locale_enum , LOCALE_WINDOWS , ( LPARAM ) argv ,
NULL ) ;
}
if ( ret_val )
{
size_t rc ;
char * hyphen ;
/* Locale names use only ASCII, any conversion locale suffices. */
rc = wchar2char ( iso_lc_messages , buffer , sizeof ( iso_lc_messages ) , NULL ) ;
if ( rc = = - 1 | | rc = = sizeof ( iso_lc_messages ) )
return NULL ;
/*
* Simply replace the hyphen with an underscore . See comments in
* IsoLocaleName .
*/
*/
hyphen = strchr ( iso_lc_messages , ' - ' ) ;
if ( hyphen )
* hyphen = ' _ ' ;
return iso_lc_messages ;
}
return NULL ;
}
# endif /* _MSC_VER >= 1900 */
static char *
static char *
IsoLocaleName ( const char * winlocname )
IsoLocaleName ( const char * winlocname )
{
{
# ifdef _MSC_VER
# if defined(_MSC_VER)
static char iso_lc_messages [ 32 ] ;
static char iso_lc_messages [ LOCALE_NAME_MAX_LENGTH ] ;
_locale_t loct = NULL ;
if ( pg_strcasecmp ( " c " , winlocname ) = = 0 | |
if ( pg_strcasecmp ( " c " , winlocname ) = = 0 | |
pg_strcasecmp ( " posix " , winlocname ) = = 0 )
pg_strcasecmp ( " posix " , winlocname ) = = 0 )
@ -997,6 +1158,12 @@ IsoLocaleName(const char *winlocname)
strcpy ( iso_lc_messages , " C " ) ;
strcpy ( iso_lc_messages , " C " ) ;
return iso_lc_messages ;
return iso_lc_messages ;
}
}
else
{
# if (_MSC_VER >= 1900) /* Visual Studio 2015 or later */
return get_iso_localename ( winlocname ) ;
# else
_locale_t loct ;
loct = _create_locale ( LC_CTYPE , winlocname ) ;
loct = _create_locale ( LC_CTYPE , winlocname ) ;
if ( loct ! = NULL )
if ( loct ! = NULL )
@ -1012,24 +1179,27 @@ IsoLocaleName(const char *winlocname)
return NULL ;
return NULL ;
/*
/*
* Since the message catalogs sit on a case - insensitive filesystem , we
* Since the message catalogs sit on a case - insensitive
* need not standardize letter case here . So long as we do not ship
* filesystem , we need not standardize letter case here . So long
* message catalogs for which it would matter , we also need not
* as we do not ship message catalogs for which it would matter ,
* translate the script / variant portion , e . g . uz - Cyrl - UZ to
* we also need not translate the script / variant portion , e . g .
* uz_UZ @ cyrillic . Simply replace the hyphen with an underscore .
* uz - Cyrl - UZ to uz_UZ @ cyrillic . Simply replace the hyphen with
* an underscore .
*
*
* Note that the locale name can be less - specific than the value w e
* Note that the locale name can be less - specific than the value
* would derive under earlier Visual Studio releases . For example ,
* we would derive under earlier Visual Studio releases . For
* French_France .1252 yields just " fr " . This does not affect any of
* example , French_France .1252 yields just " fr " . This does not
* the country - specific message catalogs available as of this writing
* affect any of the country - specific message catalogs available
* ( pt_BR , zh_CN , zh_TW ) .
* as of this writing ( pt_BR , zh_CN , zh_TW ) .
*/
*/
hyphen = strchr ( iso_lc_messages , ' - ' ) ;
hyphen = strchr ( iso_lc_messages , ' - ' ) ;
if ( hyphen )
if ( hyphen )
* hyphen = ' _ ' ;
* hyphen = ' _ ' ;
return iso_lc_messages ;
return iso_lc_messages ;
}
}
# endif /* _MSC_VER */
# endif /* Visual Studio 2015 or later */
}
# endif /* defined(_MSC_VER) */
return NULL ; /* Not supported on this version of msvc/mingw */
return NULL ; /* Not supported on this version of msvc/mingw */
}
}
# endif /* WIN32 && LC_MESSAGES */
# endif /* WIN32 && LC_MESSAGES */