summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSteve Harter <steveharter@users.noreply.github.com>2015-10-09 16:11:25 -0500
committerSteve Harter <steveharter@users.noreply.github.com>2015-10-09 16:11:25 -0500
commit53dbf8f90879727308527f16bf1d4b5ef2931bb0 (patch)
tree46c76e79333dc501427462e7f55879aeb699d5bf /src
parent8d80e964182be49e67974c774090c3beac8ed1f5 (diff)
parente3562c04b5e8a28b7d852ccbca627947b72a947d (diff)
downloadcoreclr-53dbf8f90879727308527f16bf1d4b5ef2931bb0.tar.gz
coreclr-53dbf8f90879727308527f16bf1d4b5ef2931bb0.tar.bz2
coreclr-53dbf8f90879727308527f16bf1d4b5ef2931bb0.zip
Merge pull request #1723 from steveharter/FixDefaultLocale
Add support for obtaining default locale in Linux and fix issue with collation not being passed to ICU
Diffstat (limited to 'src')
-rw-r--r--src/corefx/System.Globalization.Native/locale.cpp44
-rw-r--r--src/corefx/System.Globalization.Native/locale.hpp5
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Locale.cs4
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs92
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureData.cs8
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureInfo.Unix.cs28
6 files changed, 116 insertions, 65 deletions
diff --git a/src/corefx/System.Globalization.Native/locale.cpp b/src/corefx/System.Globalization.Native/locale.cpp
index e02c32d680..ca4569f9c9 100644
--- a/src/corefx/System.Globalization.Native/locale.cpp
+++ b/src/corefx/System.Globalization.Native/locale.cpp
@@ -36,8 +36,9 @@ Locale GetLocale(const UChar* localeName, bool canonize)
if (localeName != NULL)
{
- int32_t len = u_strlen(localeName);
- u_UCharsToChars(localeName, localeNameTemp, len + 1);
+ // use UnicodeString.extract instead of u_UCharsToChars; u_UCharsToChars considers '@' a variant and stops
+ UnicodeString str(localeName, -1, ULOC_FULLNAME_CAPACITY);
+ str.extract(0, str.length(), localeNameTemp);
}
Locale loc;
@@ -64,9 +65,10 @@ UErrorCode u_charsToUChars_safe(const char *str, UChar* value, int32_t valueLeng
return U_ZERO_ERROR;
}
-void FixupLocaleName(UChar* value, int32_t valueLength)
+int FixupLocaleName(UChar* value, int32_t valueLength)
{
- for (int i = 0; i < valueLength; i++)
+ int i = 0;
+ for (; i < valueLength; i++)
{
if (value[i] == (UChar)'\0')
{
@@ -77,8 +79,9 @@ void FixupLocaleName(UChar* value, int32_t valueLength)
value[i] = (UChar)'-';
}
}
-}
+ return i;
+}
extern "C" int32_t GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength)
{
@@ -100,3 +103,34 @@ extern "C" int32_t GetLocaleName(const UChar* localeName, UChar* value, int32_t
return UErrorCodeToBool(status);
}
+
+extern "C" int32_t GetDefaultLocaleName(UChar* value, int32_t valueLength)
+{
+ Locale locale = GetLocale(NULL);
+ if (locale.isBogus())
+ {
+ // ICU should be able to get default locale
+ return UErrorCodeToBool(U_INTERNAL_PROGRAM_ERROR);
+ }
+
+ UErrorCode status = u_charsToUChars_safe(locale.getBaseName(), value, valueLength);
+ if (U_SUCCESS(status))
+ {
+ int localeNameLen = FixupLocaleName(value, valueLength);
+
+ // if collation is present, return that to managed side
+ char collationValueTemp[ULOC_KEYWORDS_CAPACITY];
+ if (locale.getKeywordValue("collation", collationValueTemp, ULOC_KEYWORDS_CAPACITY, status) > 0)
+ {
+ // copy the collation; managed uses a "_" to represent collation (not "@collation=")
+ status = u_charsToUChars_safe("_", &value[localeNameLen], valueLength - localeNameLen);
+ if (U_SUCCESS(status))
+ {
+ status = u_charsToUChars_safe(collationValueTemp, &value[localeNameLen + 1], valueLength - localeNameLen - 1);
+ }
+ }
+ }
+
+ return UErrorCodeToBool(status);
+}
+
diff --git a/src/corefx/System.Globalization.Native/locale.hpp b/src/corefx/System.Globalization.Native/locale.hpp
index 894ea90936..0c100dae3c 100644
--- a/src/corefx/System.Globalization.Native/locale.hpp
+++ b/src/corefx/System.Globalization.Native/locale.hpp
@@ -43,6 +43,7 @@ UErrorCode u_charsToUChars_safe(const char *str, UChar* value, int32_t valueLeng
Function:
FixupLocaleName
-Replace underscores with hyphens to interop with existing .NET code
+Replace underscores with hyphens to interop with existing .NET code.
+Returns the length of the string.
*/
-void FixupLocaleName(UChar* value, int32_t valueLength);
+int FixupLocaleName(UChar* value, int32_t valueLength);
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Locale.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Locale.cs
index e8dfe739a0..3c291e50ea 100644
--- a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Locale.cs
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Locale.cs
@@ -19,6 +19,10 @@ internal static partial class Interop
[DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool GetDefaultLocaleName([Out] StringBuilder value, int valueLength);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
internal unsafe static extern bool GetLocaleTimeFormat(string localeName, bool shortFormat, [Out] StringBuilder value, int valueLength);
[DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode)]
diff --git a/src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs b/src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs
index 336db749a0..f53d7ceb77 100644
--- a/src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs
+++ b/src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs
@@ -13,9 +13,6 @@ namespace System.Globalization
{
internal partial class CultureData
{
- // Win32 constants
- const string LOCALE_NAME_SYSTEM_DEFAULT = @"!x-sys-default-locale";
-
// ICU constants
const int ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY = 100; // max size of keyword or value
const int ICU_ULOC_FULLNAME_CAPACITY = 157; // max size of locale name
@@ -30,47 +27,35 @@ namespace System.Globalization
Contract.Assert(this.sRealName != null);
string alternateSortName = string.Empty;
- string realNameBuffer = null;
- int index;
+ string realNameBuffer = this.sRealName;
- bool useSystemDefault = (this.sRealName == LOCALE_NAME_SYSTEM_DEFAULT);
- if (!useSystemDefault) //ICU uses null to obtain the default (system) locale
+ // Basic validation
+ if (realNameBuffer.Contains("@"))
{
- realNameBuffer = this.sRealName;
-
- // Basic validation
- if (realNameBuffer.Contains("@"))
- {
- return false; // don't allow ICU variants to come in directly
- }
+ return false; // don't allow ICU variants to come in directly
+ }
- // Replace _ (alternate sort) with @collation= for ICU
- index = realNameBuffer.IndexOf('_');
- if (index > 0)
+ // Replace _ (alternate sort) with @collation= for ICU
+ int index = realNameBuffer.IndexOf('_');
+ if (index > 0)
+ {
+ if (index >= (realNameBuffer.Length - 1) // must have characters after _
+ || realNameBuffer.Substring(index + 1).Contains("_")) // only one _ allowed
{
- if (index >= (realNameBuffer.Length - 1) // must have characters after _
- || realNameBuffer.Substring(index + 1).Contains("_")) // only one _ allowed
- {
- return false; // fail
- }
- alternateSortName = realNameBuffer.Substring(index + 1);
- realNameBuffer = realNameBuffer.Substring(0, index) + ICU_COLLATION_KEYWORD + alternateSortName;
+ return false; // fail
}
+ alternateSortName = realNameBuffer.Substring(index + 1);
+ realNameBuffer = realNameBuffer.Substring(0, index) + ICU_COLLATION_KEYWORD + alternateSortName;
}
// Get the locale name from ICU
- StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY);
- if (!Interop.GlobalizationInterop.GetLocaleName(realNameBuffer, sb, sb.Capacity))
+ if (!GetLocaleName(realNameBuffer, out this.sWindowsName))
{
- StringBuilderCache.Release(sb);
return false; // fail
}
- // Success - use the locale name returned which may be different than realNameBuffer (casing)
- this.sWindowsName = StringBuilderCache.GetStringAndRelease(sb); // the name passed to subsequent ICU calls
-
// Replace the ICU collation keyword with an _
- index = realNameBuffer.IndexOf(ICU_COLLATION_KEYWORD, StringComparison.Ordinal);
+ index = this.sWindowsName.IndexOf(ICU_COLLATION_KEYWORD, StringComparison.Ordinal);
if (index >= 0)
{
this.sName = this.sWindowsName.Substring(0, index) + "_" + alternateSortName;
@@ -79,21 +64,13 @@ namespace System.Globalization
{
this.sName = this.sWindowsName;
}
-
this.sRealName = this.sName;
this.sSpecificCulture = this.sRealName; // we don't attempt to find a non-neutral locale if a neutral is passed in (unlike win32)
this.iLanguage = this.ILANGUAGE;
if (this.iLanguage == 0)
{
- if (useSystemDefault)
- {
- this.iLanguage = LOCALE_CUSTOM_DEFAULT;
- }
- else
- {
- this.iLanguage = LOCALE_CUSTOM_UNSPECIFIED;
- }
+ this.iLanguage = LOCALE_CUSTOM_UNSPECIFIED;
}
this.bNeutral = (this.SISO3166CTRYNAME.Length == 0);
@@ -106,10 +83,41 @@ namespace System.Globalization
this.sName = this.sWindowsName.Substring(0, index);
}
}
+ return true;
+ }
+ internal static bool GetLocaleName(string localeName, out string windowsName)
+ {
+ // Get the locale name from ICU
+ StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY);
+ if (!Interop.GlobalizationInterop.GetLocaleName(localeName, sb, sb.Capacity))
+ {
+ StringBuilderCache.Release(sb);
+ windowsName = null;
+ return false; // fail
+ }
+
+ // Success - use the locale name returned which may be different than realNameBuffer (casing)
+ windowsName = StringBuilderCache.GetStringAndRelease(sb); // the name passed to subsequent ICU calls
+ return true;
+ }
+
+ internal static bool GetDefaultLocaleName(out string windowsName)
+ {
+ // Get the default (system) locale name from ICU
+ StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY);
+ if (!Interop.GlobalizationInterop.GetDefaultLocaleName(sb, sb.Capacity))
+ {
+ StringBuilderCache.Release(sb);
+ windowsName = null;
+ return false; // fail
+ }
+
+ // Success - use the locale name returned which may be different than realNameBuffer (casing)
+ windowsName = StringBuilderCache.GetStringAndRelease(sb); // the name passed to subsequent ICU calls
return true;
}
-
+
private string GetLocaleInfo(LocaleStringData type)
{
Contract.Assert(this.sWindowsName != null, "[CultureData.GetLocaleInfo] Expected this.sWindowsName to be populated already");
@@ -244,7 +252,7 @@ namespace System.Globalization
private static CultureInfo GetUserDefaultCulture()
{
- return new CultureInfo(LOCALE_NAME_SYSTEM_DEFAULT);
+ return CultureInfo.GetUserDefaultCulture();
}
}
}
diff --git a/src/mscorlib/corefx/System/Globalization/CultureData.cs b/src/mscorlib/corefx/System/Globalization/CultureData.cs
index 217bda6445..aabe66e238 100644
--- a/src/mscorlib/corefx/System/Globalization/CultureData.cs
+++ b/src/mscorlib/corefx/System/Globalization/CultureData.cs
@@ -1679,8 +1679,8 @@ namespace System.Globalization
{
// Note: Custom cultures might point at another culture's textinfo, however windows knows how
// to redirect it to the desired textinfo culture, so this is OK.
- Contract.Assert(this.sWindowsName != null, "[CultureData.STEXTINFO] Expected this.sWindowsName to be populated by already");
- return (this.sWindowsName);
+ Contract.Assert(this.sRealName != null, "[CultureData.STEXTINFO] Expected this.sRealName to be populated by already");
+ return (this.sRealName);
}
}
@@ -1689,8 +1689,8 @@ namespace System.Globalization
{
get
{
- Contract.Assert(this.sWindowsName != null, "[CultureData.SCOMPAREINFO] Expected this.sWindowsName to be populated by already");
- return (this.sWindowsName);
+ Contract.Assert(this.sRealName != null, "[CultureData.SCOMPAREINFO] Expected this.sRealName to be populated by already");
+ return (this.sRealName);
}
}
diff --git a/src/mscorlib/corefx/System/Globalization/CultureInfo.Unix.cs b/src/mscorlib/corefx/System/Globalization/CultureInfo.Unix.cs
index a6f0b30091..a786d11f1a 100644
--- a/src/mscorlib/corefx/System/Globalization/CultureInfo.Unix.cs
+++ b/src/mscorlib/corefx/System/Globalization/CultureInfo.Unix.cs
@@ -5,22 +5,26 @@ namespace System.Globalization
{
public partial class CultureInfo : IFormatProvider
{
- /// <summary>
- /// Gets the default user culture from WinRT, if available.
- /// </summary>
- /// <remarks>
- /// This method may return null, if there is no default user culture or if WinRT isn't available.
- /// </remarks>
private static CultureInfo GetUserDefaultCultureCacheOverride()
{
- // TODO: Implement this fully.
- return null;
+ return null; // ICU doesn't provide a user override
}
- private static CultureInfo GetUserDefaultCulture()
+ internal static CultureInfo GetUserDefaultCulture()
{
- // TODO: Implement this fully.
- return CultureInfo.InvariantCulture;
+ CultureInfo cultureInfo = null;
+ string localeName;
+ if (CultureData.GetDefaultLocaleName(out localeName))
+ {
+ cultureInfo = GetCultureByName(localeName, true);
+ cultureInfo.m_isReadOnly = true;
+ }
+ else
+ {
+ cultureInfo = CultureInfo.InvariantCulture;
+ }
+
+ return cultureInfo;
}
}
-} \ No newline at end of file
+}