From ae6d854ec6134bda2f64d2747b5cd9b534c5bb04 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Thu, 30 Mar 2017 13:31:09 -0700 Subject: [PATCH] [dart:io] Adds Platform.localeName related #29126 R=fschneider@google.com Review-Url: https://codereview.chromium.org/2785073002 . --- CHANGELOG.md | 3 + .../tool/input_sdk/patch/io_patch.dart | 4 +- runtime/bin/io_natives.cc | 1 + runtime/bin/platform.cc | 10 ++++ runtime/bin/platform.h | 2 + runtime/bin/platform_android.cc | 5 ++ runtime/bin/platform_fuchsia.cc | 5 ++ runtime/bin/platform_linux.cc | 5 ++ runtime/bin/platform_macos.cc | 56 +++++++++++++++++++ runtime/bin/platform_patch.dart | 3 + runtime/bin/platform_unsupported.cc | 6 ++ runtime/bin/platform_win.cc | 10 ++++ .../_internal/js_runtime/lib/io_patch.dart | 5 ++ sdk/lib/io/platform.dart | 6 ++ sdk/lib/io/platform_impl.dart | 13 +++++ tests/standalone/io/locale_name_test.dart | 18 ++++++ 16 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 tests/standalone/io/locale_name_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d5f01332e9..b9fbe82d9e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ ### Core library changes +* `dart:io` + * Added `Platform.localeName`. + ### Dart VM ### Strong Mode diff --git a/pkg/dev_compiler/tool/input_sdk/patch/io_patch.dart b/pkg/dev_compiler/tool/input_sdk/patch/io_patch.dart index 8e72f3231b3..e7ed5bef5c6 100644 --- a/pkg/dev_compiler/tool/input_sdk/patch/io_patch.dart +++ b/pkg/dev_compiler/tool/input_sdk/patch/io_patch.dart @@ -252,8 +252,8 @@ class _Platform { } @patch - static _ansiSupported() { - throw new UnsupportedError("Platform._ansiSupported"); + static String _localeName() { + throw new UnsupportedError("Platform._localeName"); } } diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc index 035f84e3488..7542320fd1d 100644 --- a/runtime/bin/io_natives.cc +++ b/runtime/bin/io_natives.cc @@ -91,6 +91,7 @@ namespace bin { V(Platform_Environment, 0) \ V(Platform_ExecutableArguments, 0) \ V(Platform_GetVersion, 0) \ + V(Platform_LocaleName, 0) \ V(Process_Start, 11) \ V(Process_Wait, 5) \ V(Process_KillPid, 2) \ diff --git a/runtime/bin/platform.cc b/runtime/bin/platform.cc index e8b7849147f..bfe107fc1a6 100644 --- a/runtime/bin/platform.cc +++ b/runtime/bin/platform.cc @@ -109,6 +109,16 @@ void FUNCTION_NAME(Platform_GetVersion)(Dart_NativeArguments args) { Dart_SetReturnValue(args, Dart_NewStringFromCString(Dart_VersionString())); } + +void FUNCTION_NAME(Platform_LocaleName)(Dart_NativeArguments args) { + const char* locale = Platform::LocaleName(); + if (locale == NULL) { + Dart_SetReturnValue(args, DartUtils::NewDartOSError()); + } else { + Dart_SetReturnValue(args, Dart_NewStringFromCString(locale)); + } +} + } // namespace bin } // namespace dart diff --git a/runtime/bin/platform.h b/runtime/bin/platform.h index 9dc7e7a21a6..8fd4ef706a6 100644 --- a/runtime/bin/platform.h +++ b/runtime/bin/platform.h @@ -52,6 +52,8 @@ class Platform { // Extracts the local hostname. static bool LocalHostname(char* buffer, intptr_t buffer_length); + static const char* LocaleName(); + // Extracts the environment variables for the current process. The array of // strings is Dart_ScopeAllocated. The number of elements in the array is // returned in the count argument. diff --git a/runtime/bin/platform_android.cc b/runtime/bin/platform_android.cc index b81ce71e195..cba7fa497e2 100644 --- a/runtime/bin/platform_android.cc +++ b/runtime/bin/platform_android.cc @@ -57,6 +57,11 @@ const char* Platform::LibraryExtension() { } +const char* Platform::LocaleName() { + return getenv("LANG"); +} + + bool Platform::LocalHostname(char* buffer, intptr_t buffer_length) { return gethostname(buffer, buffer_length) == 0; } diff --git a/runtime/bin/platform_fuchsia.cc b/runtime/bin/platform_fuchsia.cc index 3b1a1c190ce..69c75ce5d40 100644 --- a/runtime/bin/platform_fuchsia.cc +++ b/runtime/bin/platform_fuchsia.cc @@ -47,6 +47,11 @@ const char* Platform::LibraryExtension() { } +const char* Platform::LocaleName() { + return getenv("LANG"); +} + + bool Platform::LocalHostname(char* buffer, intptr_t buffer_length) { return gethostname(buffer, buffer_length) == 0; } diff --git a/runtime/bin/platform_linux.cc b/runtime/bin/platform_linux.cc index b68f4921c7e..cd3497899c5 100644 --- a/runtime/bin/platform_linux.cc +++ b/runtime/bin/platform_linux.cc @@ -82,6 +82,11 @@ const char* Platform::LibraryExtension() { } +const char* Platform::LocaleName() { + return getenv("LANG"); +} + + bool Platform::LocalHostname(char* buffer, intptr_t buffer_length) { return gethostname(buffer, buffer_length) == 0; } diff --git a/runtime/bin/platform_macos.cc b/runtime/bin/platform_macos.cc index 0088956c210..f15ec3cc148 100644 --- a/runtime/bin/platform_macos.cc +++ b/runtime/bin/platform_macos.cc @@ -7,6 +7,8 @@ #include "bin/platform.h" +#include + #if !HOST_OS_IOS #include // NOLINT #endif // !HOST_OS_IOS @@ -98,6 +100,60 @@ const char* Platform::LibraryExtension() { } +static const char* GetLocaleName() { + CFLocaleRef locale = CFLocaleCopyCurrent(); + CFLocaleIdentifier locale_id = CFLocaleGetIdentifier(locale); + CFStringRef locale_string = reinterpret_cast(locale_id); + CFIndex len = CFStringGetLength(locale_string); + CFIndex max_len = + CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1; + char* result = reinterpret_cast(Dart_ScopeAllocate(max_len)); + ASSERT(result != NULL); + bool success = + CFStringGetCString(locale_string, result, max_len, kCFStringEncodingUTF8); + CFRelease(locale); + if (!success) { + return NULL; + } + return result; +} + + +static const char* GetPreferredLanguageName() { + CFArrayRef languages = CFLocaleCopyPreferredLanguages(); + CFIndex languages_length = CFArrayGetCount(languages); + if (languages_length < 1) { + CFRelease(languages); + return NULL; + } + CFTypeRef item = + reinterpret_cast(CFArrayGetValueAtIndex(languages, 0)); + CFTypeID item_type = CFGetTypeID(item); + ASSERT(item_type == CFStringGetTypeID()); + CFStringRef language = reinterpret_cast(item); + CFIndex len = CFStringGetLength(language); + CFIndex max_len = + CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1; + char* result = reinterpret_cast(Dart_ScopeAllocate(max_len)); + ASSERT(result != NULL); + bool success = + CFStringGetCString(language, result, max_len, kCFStringEncodingUTF8); + CFRelease(languages); + if (!success) { + return NULL; + } + return result; +} + + +const char* Platform::LocaleName() { + // First see if there is a preferred language. If not, return the + // current locale name. + const char* preferred_langauge = GetPreferredLanguageName(); + return (preferred_langauge != NULL) ? preferred_langauge : GetLocaleName(); +} + + bool Platform::LocalHostname(char* buffer, intptr_t buffer_length) { return gethostname(buffer, buffer_length) == 0; } diff --git a/runtime/bin/platform_patch.dart b/runtime/bin/platform_patch.dart index 70b68feabbf..f8d117e74e2 100644 --- a/runtime/bin/platform_patch.dart +++ b/runtime/bin/platform_patch.dart @@ -24,6 +24,9 @@ class _Platform { @patch static String _version() native "Platform_GetVersion"; + @patch + static String _localeName() native "Platform_LocaleName"; + @patch static String _packageRoot() => VMLibraryHooks.packageRootString; @patch diff --git a/runtime/bin/platform_unsupported.cc b/runtime/bin/platform_unsupported.cc index 64f62ef7e9b..51d4fa9cd62 100644 --- a/runtime/bin/platform_unsupported.cc +++ b/runtime/bin/platform_unsupported.cc @@ -64,6 +64,12 @@ void FUNCTION_NAME(Platform_GetVersion)(Dart_NativeArguments args) { "Platform is not supported on this platform")); } + +void FUNCTION_NAME(Platform_LocaleName)(Dart_NativeArguments args) { + Dart_ThrowException(DartUtils::NewInternalError( + "Platform is not supported on this platform")); +} + } // namespace bin } // namespace dart diff --git a/runtime/bin/platform_win.cc b/runtime/bin/platform_win.cc index 18526517e9f..8ec32d24e1d 100644 --- a/runtime/bin/platform_win.cc +++ b/runtime/bin/platform_win.cc @@ -198,6 +198,16 @@ const char* Platform::LibraryExtension() { } +const char* Platform::LocaleName() { + wchar_t locale_name[LOCALE_NAME_MAX_LENGTH]; + int result = GetUserDefaultLocaleName(locale_name, LOCALE_NAME_MAX_LENGTH); + if (result == 0) { + return NULL; + } + return StringUtilsWin::WideToUtf8(locale_name); +} + + bool Platform::LocalHostname(char* buffer, intptr_t buffer_length) { #if defined(DART_IO_DISABLED) || defined(PLATFORM_DISABLE_SOCKET) return false; diff --git a/sdk/lib/_internal/js_runtime/lib/io_patch.dart b/sdk/lib/_internal/js_runtime/lib/io_patch.dart index 46f8404ab2d..e7ed5bef5c6 100644 --- a/sdk/lib/_internal/js_runtime/lib/io_patch.dart +++ b/sdk/lib/_internal/js_runtime/lib/io_patch.dart @@ -250,6 +250,11 @@ class _Platform { static String _version() { throw new UnsupportedError("Platform._version"); } + + @patch + static String _localeName() { + throw new UnsupportedError("Platform._localeName"); + } } @patch diff --git a/sdk/lib/io/platform.dart b/sdk/lib/io/platform.dart index b087b053c32..580ad97db16 100644 --- a/sdk/lib/io/platform.dart +++ b/sdk/lib/io/platform.dart @@ -71,6 +71,7 @@ class Platform { static final _operatingSystem = _Platform.operatingSystem; static final _localHostname = _Platform.localHostname; static final _version = _Platform.version; + static final _localeName = _Platform.localeName; /** * Get the number of processors of the machine. @@ -83,6 +84,11 @@ class Platform { */ static String get pathSeparator => _pathSeparator; + /** + * Get the name of the current locale. + */ + static String get localeName => _localeName; + /** * Get a string (`linux`, `macos`, `windows`, `android`, or `ios`) * representing the operating system. diff --git a/sdk/lib/io/platform_impl.dart b/sdk/lib/io/platform_impl.dart index 5f68b7dbdef..e5de17d02e5 100644 --- a/sdk/lib/io/platform_impl.dart +++ b/sdk/lib/io/platform_impl.dart @@ -32,12 +32,25 @@ class _Platform { external static String _packageRoot(); external static String _packageConfig(); external static String _version(); + external static String _localeName(); static String executable = _executable(); static String resolvedExecutable = _resolvedExecutable(); static String packageRoot = _packageRoot(); static String packageConfig = _packageConfig(); + static String _cachedLocaleName; + static String get localeName { + if (_cachedLocaleName == null) { + var result = _localeName(); + if (result is OSError) { + throw result; + } + _cachedLocaleName = result; + } + return _cachedLocaleName; + } + // Cache the OS environment. This can be an OSError instance if // retrieving the environment failed. static var /*OSError|Map*/ _environmentCache; diff --git a/tests/standalone/io/locale_name_test.dart b/tests/standalone/io/locale_name_test.dart new file mode 100644 index 00000000000..6beffabb00a --- /dev/null +++ b/tests/standalone/io/locale_name_test.dart @@ -0,0 +1,18 @@ +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import "package:expect/expect.dart"; + +main() { + try { + Platform.localeName; + } catch (e, s) { + Expect.fail("Platform.localeName threw: $e\n$s\n"); + } + Expect.isNotNull(Platform.localeName); + Expect.isTrue(Platform.localeName is String); + print(Platform.localeName); +}