// Copyright (c) 2012, 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. part of "dart:io"; class _Platform { external static int _numberOfProcessors(); external static String _pathSeparator(); external static String _operatingSystem(); external static _operatingSystemVersion(); external static _localHostname(); external static _executable(); external static _resolvedExecutable(); /// Retrieve the entries of the process environment. /// /// The result is an [Iterable] of strings, where each string represents /// an environment entry. /// /// Environment entries should be strings containing /// a non-empty name and a value separated by a '=' character. /// The name does not contain a '=' character, /// so the name is everything up to the first '=' character. /// Values are everything after the first '=' character. /// A value may contain further '=' characters, and it may be empty. /// /// Returns an [OSError] if retrieving the environment fails. external static _environment(); external static List _executableArguments(); external static String? _packageConfig(); external static String _version(); external static String _localeName(); external static Uri _script(); @pragma("vm:shared") static String executable = _executable(); @pragma("vm:shared") static String resolvedExecutable = _resolvedExecutable(); @pragma("vm:shared") static String? packageConfig = _packageConfig(); @pragma("vm:entry-point") static String Function()? _localeClosure; static String localeName() { final result = (_localeClosure == null) ? _localeName() : _localeClosure!(); if (result is OSError) { throw result; } return result; } // Cache the OS environment. This can be an OSError instance if // retrieving the environment failed. static var /*OSError?|Map?*/ _environmentCache; static int get numberOfProcessors => _numberOfProcessors(); static String get pathSeparator => _pathSeparator(); static String get operatingSystem => _operatingSystem(); static Uri get script => _script(); static String? _cachedOSVersion; static String get operatingSystemVersion { if (_cachedOSVersion == null) { var result = _operatingSystemVersion(); if (result is OSError) { throw result; } _cachedOSVersion = result; } return _cachedOSVersion!; } static String get localHostname { var result = _localHostname(); if (result is OSError) { throw result; } return result; } static List get executableArguments => _executableArguments(); static Map get environment { if (_environmentCache == null) { var env = _environment(); if (env is Iterable) { var result = Platform.isWindows ? _CaseInsensitiveStringMap() : Map(); for (var environmentEntry in env) { if (environmentEntry == null) { continue; } // TODO(kallentu): [_environment()] emits Iterable which is // why the cast and check is needed. Every element is a String, // however, so refactor [_environment()] at some point to emit // Iterables instead. var text = environmentEntry as String; // The Strings returned by [_environment()] are expected to be // valid environment entries, but exceptions have been seen // (e.g., an entry of just '=' has been seen on OS/X). // Invalid entries (lines without a '=' or with an empty name) // are discarded. var equalsIndex = text.indexOf('='); if (equalsIndex > 0) { result[text.substring(0, equalsIndex)] = text.substring( equalsIndex + 1, ); } } _environmentCache = UnmodifiableMapView(result); } else { _environmentCache = env; } } if (_environmentCache is OSError) { throw _environmentCache; } else { return _environmentCache!; } } static String get version => _version(); } // Environment variables are case-insensitive on Windows. In order // to reflect that we use a case-insensitive string map on Windows. class _CaseInsensitiveStringMap extends MapBase { final Map _map = Map(); bool containsKey(Object? key) => key is String && _map.containsKey(key.toUpperCase()); bool containsValue(Object? value) => _map.containsValue(value); V? operator [](Object? key) => key is String ? _map[key.toUpperCase()] : null; void operator []=(String key, V value) { _map[key.toUpperCase()] = value; } V putIfAbsent(String key, V ifAbsent()) { return _map.putIfAbsent(key.toUpperCase(), ifAbsent); } void addAll(Map other) { other.forEach((key, value) => this[key.toUpperCase()] = value); } V? remove(Object? key) => key is String ? _map.remove(key.toUpperCase()) : null; void clear() { _map.clear(); } void forEach(void f(String key, V value)) { _map.forEach(f); } Iterable get keys => _map.keys; Iterable get values => _map.values; int get length => _map.length; bool get isEmpty => _map.isEmpty; bool get isNotEmpty => _map.isNotEmpty; Iterable> get entries => _map.entries; Map map(MapEntry transform(String key, V value)) => _map.map(transform); V update(String key, V update(V value), {V ifAbsent()?}) => _map.update(key.toUpperCase(), update, ifAbsent: ifAbsent); void updateAll(V update(String key, V value)) { _map.updateAll(update); } void removeWhere(bool test(String key, V value)) { _map.removeWhere(test); } String toString() => _map.toString(); }