//------------------------------------------------------------------------------ // // System.Environment.cs // // Copyright (C) 2001 Moonlight Enterprises, All Rights Reserved // // Author: Jim Richardson, develop@wtfo-guru.com // Dan Lewis (dihlewis@yahoo.co.uk) // Created: Saturday, August 11, 2001 // //------------------------------------------------------------------------------ // // Copyright (C) 2004 Novell, Inc (http://www.novell.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.IO; //using System.Diagnostics; using System.Collections; using System.Security; using System.Security.Permissions; using System.Runtime.CompilerServices; using System.Text; namespace System { public sealed class Environment { /* * This is the version number of the corlib-runtime interface. When * making changes to this interface (by changing the layout * of classes the runtime knows about, changing icall semantics etc), * increment this variable. Also increment the * pair of this variable in the runtime in metadata/appdomain.c. * Changes which are already detected at runtime, like the addition * of icalls, do not require an increment. */ private const int mono_corlib_version = 22; private Environment () { } [MonoTODO] public enum SpecialFolder { // TODO: Determine if these windoze style folder identifiers // have unix/linux counterparts #if NET_1_1 Desktop = 0x00, MyComputer = 0x11, #endif Programs = 0x02, Personal = 0x05, Favorites = 0x06, Startup = 0x07, Recent = 0x08, SendTo = 0x09, StartMenu = 0x0b, MyMusic = 0x0d, DesktopDirectory = 0x10, Templates = 0x15, ApplicationData = 0x1a, LocalApplicationData = 0x1c, InternetCache = 0x20, Cookies = 0x21, History = 0x22, CommonApplicationData = 0x23, System = 0x25, ProgramFiles = 0x26, MyPictures = 0x27, CommonProgramFiles = 0x2b, } // TODO: Make sure the security attributes do what I expect /// /// Gets the command line for this process /// public static string CommandLine { // TODO: Coordinate with implementor of EnvironmentPermissionAttribute // [EnvironmentPermissionAttribute(SecurityAction.Demand, Read = "COMMANDLINE")] get { // FIXME: we may need to quote, but any sane person // should use GetCommandLineArgs () instead. return String.Join (" ", GetCommandLineArgs ()); } } /// /// Gets or sets the current directory. Actually this is supposed to get /// and/or set the process start directory acording to the documentation /// but actually test revealed at beta2 it is just Getting/Setting the CurrentDirectory /// public static string CurrentDirectory { // originally it was my thought that the external call would be made in // the directory class however that class has additional security requirements // so the Directory class will call this class for its get/set current directory get { return Directory.GetCurrentDirectory (); } set { Directory.SetCurrentDirectory (value); } } /// /// Gets or sets the exit code of this process /// public extern static int ExitCode { [MethodImplAttribute (MethodImplOptions.InternalCall)] get; [MethodImplAttribute (MethodImplOptions.InternalCall)] set; } #if NET_1_1 static #endif public extern bool HasShutdownStarted { [MethodImplAttribute (MethodImplOptions.InternalCall)] get; } /// /// Gets the name of the local computer /// public extern static string MachineName { [MethodImplAttribute (MethodImplOptions.InternalCall)] get; } /// /// Gets the standard new line value /// public extern static string NewLine { [MethodImplAttribute (MethodImplOptions.InternalCall)] get; } // // Support methods and fields for OSVersion property // static OperatingSystem os; internal static extern PlatformID Platform { [MethodImplAttribute (MethodImplOptions.InternalCall)] get; } [MethodImplAttribute (MethodImplOptions.InternalCall)] internal static extern string GetOSVersionString (); /// /// Gets the current OS version information /// public static OperatingSystem OSVersion { get { if (os == null) { Version v = Version.CreateFromString (GetOSVersionString ()); os = new OperatingSystem (Platform, v); } return os; } } /// /// Get StackTrace /// public static string StackTrace { get { System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (1); return trace.ToString (); } } /// /// Get a fully qualified path to the system directory /// public static string SystemDirectory { get { return GetFolderPath (SpecialFolder.System); } } /// /// Get the number of milliseconds that have elapsed since the system was booted /// public extern static int TickCount { [MethodImplAttribute (MethodImplOptions.InternalCall)] get; } /// /// Get UserDomainName /// public static string UserDomainName { get { return MachineName; } } /// /// Gets a flag indicating whether the process is in interactive mode /// [MonoTODO] public static bool UserInteractive { get { return false; } } /// /// Get the user name of current process is running under /// public extern static string UserName { [MethodImplAttribute (MethodImplOptions.InternalCall)] get; } /// /// Get the version of the common language runtime /// public static Version Version { get { #if NET_1_1 return new Version (1, 1, 4322, 573); #else return new Version (1, 0, 3705, 288); #endif } } /// /// Get the amount of physical memory mapped to process /// [MonoTODO] public static long WorkingSet { get { return 0; } } [MethodImplAttribute (MethodImplOptions.InternalCall)] public extern static void Exit (int exitCode); /// /// Substitute environment variables in the argument "name" /// public static string ExpandEnvironmentVariables (string name) { if (name == null) throw new ArgumentNullException ("name"); int off1 = name.IndexOf ('%'); if (off1 == -1) return name; int len = name.Length; int off2 = 0; if (off1 == len - 1 || (off2 = name.IndexOf ('%', off1 + 1)) == -1) return name; PlatformID platform = Platform; StringBuilder result = new StringBuilder (); result.Append (name, 0, off1); Hashtable tbl = null; do { string var = name.Substring (off1 + 1, off2 - off1 - 1); string value = GetEnvironmentVariable (var); if (value == null && (int) platform != 128) { // On windows, env. vars. are case insensitive if (tbl == null) tbl = GetEnvironmentVariablesNoCase (); value = tbl [var] as string; } if (value == null) { result.Append ('%'); result.Append (var); result.Append ('%'); } else { result.Append (value); } if (off2 + 1 == len) { off1 = off2; off2 = -1; } else { off1 = off2 + 1; off2 = (off1 + 1 == len) ? -1 : name.IndexOf ('%', off1 + 1); } } while (off2 != -1); if (off1 + 1 < len) result.Append (name.Substring (off1)); return result.ToString (); } /// /// Return an array of the command line arguments of the current process /// [MethodImplAttribute (MethodImplOptions.InternalCall)] public extern static string[] GetCommandLineArgs(); /// /// Return a string containing the value of the environment /// variable identifed by parameter "variable" /// [MethodImplAttribute (MethodImplOptions.InternalCall)] public extern static string GetEnvironmentVariable (string name); static Hashtable GetEnvironmentVariablesNoCase () { Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default); foreach (string name in GetEnvironmentVariableNames ()) { vars [name] = GetEnvironmentVariable (name); } return vars; } /// /// Return a set of all environment variables and their values /// public static IDictionary GetEnvironmentVariables() { Hashtable vars = new Hashtable (); foreach (string name in GetEnvironmentVariableNames ()) { vars [name] = GetEnvironmentVariable (name); } return vars; } [MethodImplAttribute (MethodImplOptions.InternalCall)] private extern static string GetWindowsFolderPath (int folder); /// /// Returns the fully qualified path of the /// folder specified by the "folder" parameter /// public static string GetFolderPath (SpecialFolder folder) { if ((int) Platform != 128) return GetWindowsFolderPath ((int) folder); string home = internalGetHome (); // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html string data = GetEnvironmentVariable ("XDG_DATA_HOME"); if ((data == null) || (data == String.Empty)) { data = Path.Combine (home, ".local"); data = Path.Combine (data, "share"); } string config = GetEnvironmentVariable ("XDG_CONFIG_HOME"); if ((config == null) || (config == String.Empty)) { config = Path.Combine (home, ".config"); } switch (folder) { #if NET_1_1 // MyComputer is a virtual directory case SpecialFolder.MyComputer: return ""; #endif // personal == ~ case SpecialFolder.Personal: return home; // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart. case SpecialFolder.ApplicationData: return config; //use FDO's DATA_HOME. This is *NOT* synced case SpecialFolder.LocalApplicationData: return data; #if NET_1_1 case SpecialFolder.Desktop: #endif case SpecialFolder.DesktopDirectory: return Path.Combine (home, "Desktop"); // these simply dont exist on Linux // The spec says if a folder doesnt exist, we // should return "" case SpecialFolder.Favorites: case SpecialFolder.Programs: case SpecialFolder.SendTo: case SpecialFolder.StartMenu: case SpecialFolder.Startup: case SpecialFolder.MyMusic: case SpecialFolder.MyPictures: case SpecialFolder.Templates: case SpecialFolder.Cookies: case SpecialFolder.History: case SpecialFolder.InternetCache: case SpecialFolder.Recent: case SpecialFolder.CommonProgramFiles: case SpecialFolder.ProgramFiles: case SpecialFolder.System: return ""; // This is where data common to all users goes case SpecialFolder.CommonApplicationData: return "/usr/share"; default: throw new ArgumentException ("Invalid SpecialFolder"); } } public static string[] GetLogicalDrives () { return GetLogicalDrivesInternal (); } static internal string GetResourceString (string s) { return ""; } // private methods private static string GacPath { get { if ((int) Platform != 128) { /* On windows, we don't know the path where mscorlib.dll will be installed */ string corlibDir = Path.GetDirectoryName (typeof (int).Assembly.Location); return Path.Combine (Path.Combine (corlibDir, "mono"), "gac"); } return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac"); } } [MethodImplAttribute (MethodImplOptions.InternalCall)] private extern static string [] GetLogicalDrivesInternal (); [MethodImplAttribute (MethodImplOptions.InternalCall)] private extern static string [] GetEnvironmentVariableNames (); [MethodImplAttribute (MethodImplOptions.InternalCall)] internal extern static string GetMachineConfigPath (); [MethodImplAttribute (MethodImplOptions.InternalCall)] internal extern static string internalGetGacPath (); [MethodImplAttribute (MethodImplOptions.InternalCall)] internal extern static string internalGetHome (); } }