2007-11-17 Miguel de Icaza <miguel@novell.com>
[mono.git] / mcs / class / corlib / System / Environment.cs
index 94e7c44d9f708e1687d7c4f892148facf7782fea..6cfa7341934ae203b8669629221e3c6ca43ba043 100644 (file)
@@ -38,9 +38,13 @@ using System.Runtime.CompilerServices;
 using System.Security;
 using System.Security.Permissions;
 using System.Text;
+using System.Runtime.InteropServices;
 
 namespace System {
 
+#if NET_2_0
+       [ComVisible (true)]
+#endif
 #if NET_2_0
        public static class Environment {
 #else
@@ -59,9 +63,8 @@ namespace System {
                 * Changes which are already detected at runtime, like the addition
                 * of icalls, do not require an increment.
                 */
-               private const int mono_corlib_version = 43;
-               
-               [MonoTODO]
+               private const int mono_corlib_version = 61;
+               
                public enum SpecialFolder
                {       // TODO: Determine if these windoze style folder identifiers 
                        //       have unix/linux counterparts
@@ -197,7 +200,7 @@ namespace System {
                public static string StackTrace {
                        [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
                        get {
-                               System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (1);
+                               System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (0, true);
                                return trace.ToString ();
                        }
                }
@@ -233,7 +236,7 @@ namespace System {
                /// <summary>
                /// Gets a flag indicating whether the process is in interactive mode
                /// </summary>
-               [MonoTODO]
+               [MonoTODO ("Currently always returns false, regardless of interactive state")]
                public static bool UserInteractive {
                        get {
                                return false;
@@ -254,14 +257,14 @@ namespace System {
                /// </summary>
                public static Version Version {
                        get {
-                               return new Version (Consts.RuntimeVersion);
+                               return new Version (Consts.FxFileVersion);
                        }
                }
 
                /// <summary>
                /// Get the amount of physical memory mapped to process
                /// </summary>
-               [MonoTODO]
+               [MonoTODO ("Currently always returns zero")]
                public static long WorkingSet {
                        [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
                        get { return 0; }
@@ -434,6 +437,48 @@ namespace System {
                        return dir;
                }
 
+               private static string ReadXdgUserDir (string config_dir, string home_dir, 
+                       string key, string fallback)
+               {
+                       string env_path = internalGetEnvironmentVariable (key);
+                       if (env_path != null && env_path != String.Empty) {
+                               return env_path;
+                       }
+
+                       string user_dirs_path = Path.Combine (config_dir, "user-dirs.dirs");
+
+                       if (!File.Exists (user_dirs_path)) {
+                               return Path.Combine (home_dir, fallback);
+                       }
+
+                       try {
+                               using(StreamReader reader = new StreamReader (user_dirs_path)) {
+                                       string line;
+                                       while ((line = reader.ReadLine ()) != null) {
+                                               line = line.Trim ();
+                                               int delim_index = line.IndexOf ('=');
+                        if(delim_index > 8 && line.Substring (0, delim_index) == key) {
+                            string path = line.Substring (delim_index + 1).Trim ('"');
+                            bool relative = false;
+
+                            if (path.StartsWith ("$HOME/")) {
+                                relative = true;
+                                path = path.Substring (6);
+                            } else if (!path.StartsWith ("/")) {
+                                relative = true;
+                            }
+
+                            return relative ? Path.Combine (home_dir, path) : path;
+                        }
+                                       }
+                               }
+                       } catch (FileNotFoundException) {
+                       }
+
+                       return Path.Combine (home_dir, fallback);
+               }
+
+
                // the security runtime (and maybe other parts of corlib) needs the
                // information to initialize themselves before permissions can be checked
                internal static string InternalGetFolderPath (SpecialFolder folder)
@@ -474,8 +519,14 @@ namespace System {
                        case SpecialFolder.Desktop:
 #endif
                        case SpecialFolder.DesktopDirectory:
-                               return Path.Combine (home, "Desktop");
-                       
+                               return ReadXdgUserDir (config, home, "XDG_DESKTOP_DIR", "Desktop");
+
+                       case SpecialFolder.MyMusic:
+                               return ReadXdgUserDir (config, home, "XDG_MUSIC_DIR", "Music");
+
+                       case SpecialFolder.MyPictures:
+                               return ReadXdgUserDir (config, home, "XDG_PICTURES_DIR", "Pictures");
+                               
                        // these simply dont exist on Linux
                        // The spec says if a folder doesnt exist, we
                        // should return ""
@@ -484,8 +535,6 @@ namespace System {
                        case SpecialFolder.SendTo:
                        case SpecialFolder.StartMenu:
                        case SpecialFolder.Startup:
-                       case SpecialFolder.MyMusic:
-                       case SpecialFolder.MyPictures:
                        case SpecialFolder.Templates:
                        case SpecialFolder.Cookies:
                        case SpecialFolder.History:
@@ -510,11 +559,10 @@ namespace System {
                }
 
                // FIXME: Anyone using this anywhere ?
-               static internal string GetResourceString (string s) { return ""; }
+               static internal string GetResourceString (string s) { return String.Empty; }
 
                 
 #if NET_2_0
-               [MonoTODO ("Machine and User targets aren't supported")]
                public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
                {
                        switch (target) {
@@ -522,86 +570,120 @@ namespace System {
                                return GetEnvironmentVariable (variable);
                        case EnvironmentVariableTarget.Machine:
                                new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
-                               // under Windows this reads the LOCAL_MACHINE registry key for env vars
-                               throw new NotImplementedException ();
+                               if (!IsRunningOnWindows)
+                                       return null;
+                               using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
+                                       return env.GetValue (variable).ToString ();
+                               }
                        case EnvironmentVariableTarget.User:
                                new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
-                               // under Windows this reads the CURRENT_USER registry key for env vars
-                               throw new NotImplementedException ();
+                               if (!IsRunningOnWindows)
+                                       return null;
+                               using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", false)) {
+                                       return env.GetValue (variable).ToString ();
+                               }
                        default:
                                throw new ArgumentException ("target");
                        }
                }
 
-               [MonoTODO ("Machine and User targets aren't supported")]
                public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
                {
+                       IDictionary variables = (IDictionary)new Hashtable ();
                        switch (target) {
                        case EnvironmentVariableTarget.Process:
-                               return GetEnvironmentVariables ();
+                               variables = GetEnvironmentVariables ();
+                               break;
                        case EnvironmentVariableTarget.Machine:
                                new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
-                               // under Windows this reads the LOCAL_MACHINE registry key for env vars
-                               throw new NotImplementedException ();
+                               if (IsRunningOnWindows) {
+                                       using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
+                                               string[] value_names = env.GetValueNames ();
+                                               foreach (string value_name in value_names)
+                                                       variables.Add (value_name, env.GetValue (value_name));
+                                       }
+                               }
+                               break;
                        case EnvironmentVariableTarget.User:
                                new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
-                               // under Windows this reads the CURRENT_USER registry key for env vars
-                               throw new NotImplementedException ();
+                               if (IsRunningOnWindows) {
+                                       using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment")) {
+                                               string[] value_names = env.GetValueNames ();
+                                               foreach (string value_name in value_names)
+                                                       variables.Add (value_name, env.GetValue (value_name));
+                                       }
+                               }
+                               break;
                        default:
                                throw new ArgumentException ("target");
                        }
+                       return variables;
                }
 
-               [MonoTODO]
                [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
                public static void SetEnvironmentVariable (string variable, string value)
                {
-                       InternalSetEnvironmentVariable (variable, value);
+                       SetEnvironmentVariable (variable, value, EnvironmentVariableTarget.Process);
                }
 
-               [MonoTODO]
-               [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
+               [EnvironmentPermission (SecurityAction.Demand, Unrestricted = true)]
                public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
                {
+                       if (variable == null)
+                               throw new ArgumentNullException ("variable");
+                       if (variable == String.Empty)
+                               throw new ArgumentException ("String cannot be of zero length.", "variable");
+                       if (variable.IndexOf ('=') != -1)
+                               throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
+                       if (variable[0] == '\0')
+                               throw new ArgumentException ("The first char in the string is the null character.", "variable");
+
                        switch (target) {
                        case EnvironmentVariableTarget.Process:
                                InternalSetEnvironmentVariable (variable, value);
                                break;
                        case EnvironmentVariableTarget.Machine:
-                               // under Windows this reads the LOCAL_MACHINE registry key for env vars
-                               throw new NotImplementedException ();
+                               if (!IsRunningOnWindows)
+                                       return;
+                               using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true)) {
+                                       if (value == null || value.Length == 0)
+                                               env.DeleteValue (variable, false);
+                                       else
+                                               env.SetValue (variable, value);
+                               }
+                               break;
                        case EnvironmentVariableTarget.User:
-                               // under Windows this reads the CURRENT_USER registry key for env vars
-                               throw new NotImplementedException ();
+                               if (!IsRunningOnWindows)
+                                       return;
+                               using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", true)) {
+                                       if (value == null || value.Length == 0)
+                                               env.DeleteValue (variable, false);
+                                       else
+                                               env.SetValue (variable, value);
+                               }
+                               break;
                        default:
                                throw new ArgumentException ("target");
                        }
                }
 
-               // FIXME: to be changed as an icall when implemented
-               internal static void InternalSetEnvironmentVariable (string variable, string value)
-               {
-                       throw new NotImplementedException ();
-               }
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               internal static extern void InternalSetEnvironmentVariable (string variable, string value);
 
-               [MonoTODO]
-               public static int ProcessorCount {
+               public static extern int ProcessorCount {
                        [EnvironmentPermission (SecurityAction.Demand, Read="NUMBER_OF_PROCESSORS")]
-                       get {
-                               // note: Changes to the NUMBER_OF_PROCESSORS environment variable
-                               // under Windows doesn't affect the (good) value returned.
-                               throw new NotImplementedException ();
-                       }
+                       [MethodImplAttribute (MethodImplOptions.InternalCall)]
+                       get;                    
                }
 
-               [MonoTODO ("not much documented")]
+               [MonoTODO ("Not implemented")]
                [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode=true)]
                public static void FailFast (string message)
                {
                        throw new NotImplementedException ();
                }
-#endif                
-                
+#endif
+
                // private methods
 
                internal static bool IsRunningOnWindows {