diff options
author | Matt Ellis <matell@microsoft.com> | 2016-04-19 14:58:12 -0700 |
---|---|---|
committer | Matt Ellis <matell@microsoft.com> | 2016-04-25 15:26:55 -0700 |
commit | db3ad091c544ae67f8f32fe36245fcb1210f6111 (patch) | |
tree | e5d1f43ebab45aed453d7d8a98128886ff3ea7e7 /src/corefx | |
parent | fa9d085cfffe748f0bb9c977d0ddf00b0d654168 (diff) | |
download | coreclr-db3ad091c544ae67f8f32fe36245fcb1210f6111.tar.gz coreclr-db3ad091c544ae67f8f32fe36245fcb1210f6111.tar.bz2 coreclr-db3ad091c544ae67f8f32fe36245fcb1210f6111.zip |
Change how we detect the default locale
Previously, we would just ask ICU what it thought the default locale
was, since that seemed like a reasonable thing to do. However, in cases
where LANG, LC_MESSAGES and LC_ALL where unset and setlocale(3) returned
"C", ICU would use "en-US-POSIX" as a default locale.
The above case is actually what happens by default when you are running
in docker and en-US-POSIX has very odd collation rules (ASCII characters
which differ only by case are still treated as seperate letters) which
trip folks up.
So in this case, we'll use Invariant. If setlocale(3) returns a non
C/POSIX locale or any of LANG, LC_MESSAGES, or LC_ALL are set to non
empty values, we'll continue to let ICU figure out what to do.
Diffstat (limited to 'src/corefx')
-rw-r--r-- | src/corefx/System.Globalization.Native/locale.cpp | 39 | ||||
-rw-r--r-- | src/corefx/System.Globalization.Native/locale.hpp | 9 | ||||
-rw-r--r-- | src/corefx/System.Globalization.Native/localeStringData.cpp | 4 |
3 files changed, 49 insertions, 3 deletions
diff --git a/src/corefx/System.Globalization.Native/locale.cpp b/src/corefx/System.Globalization.Native/locale.cpp index 3b5c860270..1cb564a45a 100644 --- a/src/corefx/System.Globalization.Native/locale.cpp +++ b/src/corefx/System.Globalization.Native/locale.cpp @@ -6,6 +6,8 @@ #include <assert.h> #include <stdint.h> #include <string.h> +#include <stdlib.h> +#include <locale.h> #include "locale.hpp" @@ -110,6 +112,41 @@ int32_t FixupLocaleName(UChar* value, int32_t valueLength) return i; } +bool IsEnvVarSet(const char* name) +{ + const char* value = getenv(name); + + return (value != nullptr) && (strcmp("", value) != 0); +} + +// The behavior of uloc_getDefault() on POSIX systems is to query +// setlocale(LC_MESSAGES) and use that value, unless it is C or +// POSIX. In that case it tries to read LC_ALL, LC_MESSAGES and LANG +// and then falls back to en_US_POSIX if none of them are set. +// +// en_US_POSIX is a weird locale since the collation rules treat 'a' +// and 'A' as different letters even when ignoring case. Furthermore +// it's common for LC_ALL, LC_MESSAGES and LANG to be unset when +// running under Docker. +// +// We'd rather default to invariant in this case. If any of these +// are set, we'll just call into ICU and let it do whatever +// normalization it would do. +const char* DetectDefaultLocaleName() +{ + char* loc = setlocale(LC_MESSAGES, nullptr); + + if (loc != nullptr && (strcmp("C", loc) == 0 || strcmp("POSIX", loc) == 0)) + { + if (!IsEnvVarSet("LC_ALL") && !IsEnvVarSet("LC_MESSAGES") && !IsEnvVarSet("LANG")) + { + return ""; + } + } + + return uloc_getDefault(); +} + extern "C" int32_t GlobalizationNative_GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; @@ -135,7 +172,7 @@ extern "C" int32_t GlobalizationNative_GetDefaultLocaleName(UChar* value, int32_ char localeNameBuffer[ULOC_FULLNAME_CAPACITY]; UErrorCode status = U_ZERO_ERROR; - const char* defaultLocale = uloc_getDefault(); + const char* defaultLocale = DetectDefaultLocaleName(); uloc_getBaseName(defaultLocale, localeNameBuffer, ULOC_FULLNAME_CAPACITY, &status); diff --git a/src/corefx/System.Globalization.Native/locale.hpp b/src/corefx/System.Globalization.Native/locale.hpp index ed87d86af0..4845859960 100644 --- a/src/corefx/System.Globalization.Native/locale.hpp +++ b/src/corefx/System.Globalization.Native/locale.hpp @@ -41,3 +41,12 @@ Replace underscores with hyphens to interop with existing .NET code. Returns the length of the string. */ int FixupLocaleName(UChar* value, int32_t valueLength); + +/* +Function: +DetectDefaultLocaleName + +Detect the default locale for the machine, defaulting to Invaraint if +we can't compute one (different from uloc_getDefault()) would do. +*/ +const char* DetectDefaultLocaleName(); diff --git a/src/corefx/System.Globalization.Native/localeStringData.cpp b/src/corefx/System.Globalization.Native/localeStringData.cpp index 6adb38f9ac..927da67095 100644 --- a/src/corefx/System.Globalization.Native/localeStringData.cpp +++ b/src/corefx/System.Globalization.Native/localeStringData.cpp @@ -179,7 +179,7 @@ extern "C" int32_t GlobalizationNative_GetLocaleInfoString( switch (localeStringData) { case LocalizedDisplayName: - uloc_getDisplayName(locale, uloc_getDefault(), value, valueLength, &status); + uloc_getDisplayName(locale, DetectDefaultLocaleName(), value, valueLength, &status); break; case EnglishDisplayName: uloc_getDisplayName(locale, ULOC_ENGLISH, value, valueLength, &status); @@ -188,7 +188,7 @@ extern "C" int32_t GlobalizationNative_GetLocaleInfoString( uloc_getDisplayName(locale, locale, value, valueLength, &status); break; case LocalizedLanguageName: - uloc_getDisplayLanguage(locale, uloc_getDefault(), value, valueLength, &status); + uloc_getDisplayLanguage(locale, DetectDefaultLocaleName(), value, valueLength, &status); break; case EnglishLanguageName: uloc_getDisplayLanguage(locale, ULOC_ENGLISH, value, valueLength, &status); |