summaryrefslogtreecommitdiff
path: root/src/corefx
diff options
context:
space:
mode:
authorMatt Ellis <matell@microsoft.com>2016-04-19 14:58:12 -0700
committerMatt Ellis <matell@microsoft.com>2016-04-25 15:26:55 -0700
commitdb3ad091c544ae67f8f32fe36245fcb1210f6111 (patch)
treee5d1f43ebab45aed453d7d8a98128886ff3ea7e7 /src/corefx
parentfa9d085cfffe748f0bb9c977d0ddf00b0d654168 (diff)
downloadcoreclr-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.cpp39
-rw-r--r--src/corefx/System.Globalization.Native/locale.hpp9
-rw-r--r--src/corefx/System.Globalization.Native/localeStringData.cpp4
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);