Merge pull request #498 from Unroll-Me/master
[mono.git] / mcs / class / corlib / System / Environment.cs
index 5b9da1c614623c6669585250970928e4179dc1e9..3f8878b0439bb5d04ba580ba6551da9fe9371d71 100644 (file)
@@ -39,6 +39,7 @@ using System.Security;
 using System.Security.Permissions;
 using System.Text;
 using System.Runtime.InteropServices;
+using System.Threading;
 
 namespace System {
 
@@ -55,7 +56,7 @@ namespace System {
                 * of icalls, do not require an increment.
                 */
 #pragma warning disable 169
-               private const int mono_corlib_version = 91;
+               private const int mono_corlib_version = 108;
 #pragma warning restore 169
 
                [ComVisible (true)]
@@ -84,7 +85,7 @@ namespace System {
                        ProgramFiles = 0x26,
                        MyPictures = 0x27,
                        CommonProgramFiles = 0x2b,
-#if NET_4_0 || MOONLIGHT
+#if NET_4_0 || MOONLIGHT || MOBILE
                        MyVideos = 0x0e,
 #endif
 #if NET_4_0
@@ -116,6 +117,8 @@ namespace System {
 
 #if NET_4_0
                public
+#else
+               internal
 #endif
                enum SpecialFolderOption {
                        None = 0,
@@ -129,9 +132,26 @@ namespace System {
                public static string CommandLine {
                        // note: security demand inherited from calling GetCommandLineArgs
                        get {
-                               // FIXME: we may need to quote, but any sane person
-                               // should use GetCommandLineArgs () instead.
-                               return String.Join (" ", GetCommandLineArgs ());
+                               StringBuilder sb = new StringBuilder ();
+                               foreach (string str in GetCommandLineArgs ()) {
+                                       bool escape = false;
+                                       string quote = "";
+                                       string s = str;
+                                       for (int i = 0; i < s.Length; i++) {
+                                               if (quote.Length == 0 && Char.IsWhiteSpace (s [i])) {
+                                                       quote = "\"";
+                                               } else if (s [i] == '"') {
+                                                       escape = true;
+                                               }
+                                       }
+                                       if (escape && quote.Length != 0) {
+                                               s = s.Replace ("\"", "\\\"");
+                                       }
+                                       sb.AppendFormat ("{0}{1}{0} ", quote, s);
+                               }
+                               if (sb.Length > 0)
+                                       sb.Length--;
+                               return sb.ToString ();
                        }
                }
 
@@ -149,6 +169,14 @@ namespace System {
                                Directory.SetCurrentDirectory (value);
                        }
                }
+               
+#if NET_4_5
+               public static int CurrentManagedThreadId {
+                       get {
+                               return Thread.CurrentThread.ManagedThreadId;
+                       }
+               }
+#endif
 
                /// <summary>
                /// Gets or sets the exit code of this process
@@ -178,12 +206,21 @@ namespace System {
                        get;
                }
 
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               extern static string GetNewLine ();
+
+               static string nl;
                /// <summary>
                /// Gets the standard new line value
                /// </summary>
-               public extern static string NewLine {
-                       [MethodImplAttribute (MethodImplOptions.InternalCall)]
-                       get;
+               public static string NewLine {
+                       get {
+                               if (nl != null)
+                                       return nl;
+
+                               nl = GetNewLine ();
+                               return nl;
+                       }
                }
 
                //
@@ -191,7 +228,7 @@ namespace System {
                //
                static OperatingSystem os;
 
-               internal static extern PlatformID Platform {
+               static extern PlatformID Platform {
                        [MethodImplAttribute (MethodImplOptions.InternalCall)]
                        get;
                }
@@ -207,6 +244,8 @@ namespace System {
                                if (os == null) {
                                        Version v = Version.CreateFromString (GetOSVersionString ());
                                        PlatformID p = Platform;
+                                       if (p == PlatformID.MacOSX)
+                                               p = PlatformID.Unix;
                                        os = new OperatingSystem (p, v);
                                }
                                return os;
@@ -327,6 +366,7 @@ namespace System {
                                // If value not found, add %FOO to stream,
                                //  and use the closing % for the next iteration.
                                // If value found, expand it in place of %FOO%
+                               int realOldOff2 = off2;
                                if (value == null) {
                                        result.Append ('%');
                                        result.Append (var);
@@ -350,7 +390,7 @@ namespace System {
                                // If value not found in current iteration, but a % was found for next iteration,
                                //  use text from current closing % to the next %.
                                else
-                                       textLen = off1 - oldOff2;
+                                       textLen = off1 - realOldOff2;
                                if(off1 >= oldOff2 || off1 == -1)
                                        result.Append (name, oldOff2+1, textLen);
                        } while (off2 > -1 && off2 < len);
@@ -447,7 +487,6 @@ namespace System {
                        return GetFolderPath (folder, SpecialFolderOption.None);
                }
 #if NET_4_0
-               [MonoTODO ("Figure out the folder path for all the new values in SpecialFolder. Use the 'option' argument.")]
                public
 #endif
                static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)
@@ -456,11 +495,11 @@ namespace System {
 
                        string dir = null;
 
-                       if (Environment.IsRunningOnWindows) {
+                       if (Environment.IsRunningOnWindows)
                                dir = GetWindowsFolderPath ((int) folder);
-                       } else {
-                               dir = InternalGetFolderPath (folder);
-                       }
+                       else
+                               dir = UnixGetFolderPath (folder, option);
+
 #if !NET_2_1
                        if ((dir != null) && (dir.Length > 0) && SecurityManager.SecurityEnabled) {
                                new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dir).Demand ();
@@ -469,8 +508,7 @@ namespace System {
                        return dir;
                }
 
-               private static string ReadXdgUserDir (string config_dir, string home_dir, 
-                       string key, string fallback)
+               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) {
@@ -489,19 +527,19 @@ namespace System {
                                        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;
-                        }
+                                               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) {
@@ -513,7 +551,7 @@ namespace System {
 
                // 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)
+               internal static string UnixGetFolderPath (SpecialFolder folder, SpecialFolderOption option)
                {
                        string home = internalGetHome ();
 
@@ -549,9 +587,10 @@ namespace System {
 #if MONOTOUCH
                        {
                                string dir = Path.Combine (Path.Combine (home, "Documents"), ".config");
-                               if (!Directory.Exists (dir))
-                                       Directory.CreateDirectory (dir);
-
+                               if (option == SpecialFolderOption.Create){
+                                       if (!Directory.Exists (dir))
+                                               Directory.CreateDirectory (dir);
+                               }
                                return dir;
                        }
 #else
@@ -576,27 +615,90 @@ namespace System {
                                return ReadXdgUserDir (config, home, "XDG_DESKTOP_DIR", "Desktop");
 
                        case SpecialFolder.MyMusic:
-                               return ReadXdgUserDir (config, home, "XDG_MUSIC_DIR", "Music");
+                               if (Platform == PlatformID.MacOSX)
+                                       return Path.Combine (home, "Music");
+                               else
+                                       return ReadXdgUserDir (config, home, "XDG_MUSIC_DIR", "Music");
 
                        case SpecialFolder.MyPictures:
-                               return ReadXdgUserDir (config, home, "XDG_PICTURES_DIR", "Pictures");
+                               if (Platform == PlatformID.MacOSX)
+                                       return Path.Combine (home, "Pictures");
+                               else
+                                       return ReadXdgUserDir (config, home, "XDG_PICTURES_DIR", "Pictures");
+                       
+                       case SpecialFolder.Templates:
+                               return ReadXdgUserDir (config, home, "XDG_TEMPLATES_DIR", "Templates");
+#if NET_4_0 || MOONLIGHT || MOBILE
+                       case SpecialFolder.MyVideos:
+                               return ReadXdgUserDir (config, home, "XDG_VIDEOS_DIR", "Videos");
+#endif
+#if NET_4_0
+                       case SpecialFolder.CommonTemplates:
+                               return "/usr/share/templates";
+                       case SpecialFolder.Fonts:
+                               if (Platform == PlatformID.MacOSX)
+                                       return Path.Combine (home, "Library", "Fonts");
                                
+                               return Path.Combine (home, ".fonts");
+#endif
                        // these simply dont exist on Linux
                        // The spec says if a folder doesnt exist, we
                        // should return ""
                        case SpecialFolder.Favorites:
+                               if (Platform == PlatformID.MacOSX)
+                                       return Path.Combine (home, "Library", "Favorites");
+                               else
+                                       return String.Empty;
+                               
+                       case SpecialFolder.ProgramFiles:
+                               if (Platform == PlatformID.MacOSX)
+                                       return "/Applications";
+                               else
+                                       return String.Empty;
+
+                       case SpecialFolder.InternetCache:
+                               if (Platform == PlatformID.MacOSX)
+                                       return Path.Combine (home, "Library", "Caches");
+                               else
+                                       return String.Empty;
+
+#if NET_4_0
+                               // #2873
+                       case SpecialFolder.UserProfile:
+                               return home;
+#endif
+
                        case SpecialFolder.Programs:
                        case SpecialFolder.SendTo:
                        case SpecialFolder.StartMenu:
                        case SpecialFolder.Startup:
-                       case SpecialFolder.Templates:
                        case SpecialFolder.Cookies:
                        case SpecialFolder.History:
-                       case SpecialFolder.InternetCache:
                        case SpecialFolder.Recent:
                        case SpecialFolder.CommonProgramFiles:
-                       case SpecialFolder.ProgramFiles:
                        case SpecialFolder.System:
+#if NET_4_0
+                       case SpecialFolder.NetworkShortcuts:
+                       case SpecialFolder.CommonStartMenu:
+                       case SpecialFolder.CommonPrograms:
+                       case SpecialFolder.CommonStartup:
+                       case SpecialFolder.CommonDesktopDirectory:
+                       case SpecialFolder.PrinterShortcuts:
+                       case SpecialFolder.Windows:
+                       case SpecialFolder.SystemX86:
+                       case SpecialFolder.ProgramFilesX86:
+                       case SpecialFolder.CommonProgramFilesX86:
+                       case SpecialFolder.CommonDocuments:
+                       case SpecialFolder.CommonAdminTools:
+                       case SpecialFolder.AdminTools:
+                       case SpecialFolder.CommonMusic:
+                       case SpecialFolder.CommonPictures:
+                       case SpecialFolder.CommonVideos:
+                       case SpecialFolder.Resources:
+                       case SpecialFolder.LocalizedResources:
+                       case SpecialFolder.CommonOemLinks:
+                       case SpecialFolder.CDBurning:
+#endif
                                return String.Empty;
                        // This is where data common to all users goes
                        case SpecialFolder.CommonApplicationData:
@@ -606,6 +708,7 @@ namespace System {
                         }
                 }
 
+               
                [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
                public static string[] GetLogicalDrives ()
                {
@@ -733,7 +836,7 @@ namespace System {
                        throw new NotImplementedException ();
                }
 
-#if NET_4_0 || MOONLIGHT
+#if NET_4_0 || MOONLIGHT || MOBILE
                [SecurityCritical]
                public static void FailFast (string message, Exception exception)
                {
@@ -808,6 +911,11 @@ namespace System {
                                return (platform == 4 || platform == 128 || platform == 6);
                        }
                }
+               static internal bool IsMacOS {
+                       get {
+                               return Environment.Platform == PlatformID.MacOSX;
+                       }
+               }
        }
 }