Replace SIZEOF_REGISTER with sizeof(mgreg_t) for consistency with sizeof(gpointer)
[mono.git] / mcs / class / corlib / System / Environment.cs
1 //------------------------------------------------------------------------------
2 // 
3 // System.Environment.cs 
4 //
5 // Copyright (C) 2001 Moonlight Enterprises, All Rights Reserved
6 // 
7 // Author:         Jim Richardson, develop@wtfo-guru.com
8 //                 Dan Lewis (dihlewis@yahoo.co.uk)
9 // Created:        Saturday, August 11, 2001 
10 //
11 //------------------------------------------------------------------------------
12 //
13 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System.IO;
36 using System.Collections;
37 using System.Runtime.CompilerServices;
38 using System.Security;
39 using System.Security.Permissions;
40 using System.Text;
41 using System.Runtime.InteropServices;
42
43 namespace System {
44
45         [ComVisible (true)]
46         public static class Environment {
47
48                 /*
49                  * This is the version number of the corlib-runtime interface. When
50                  * making changes to this interface (by changing the layout
51                  * of classes the runtime knows about, changing icall signature or
52                  * semantics etc), increment this variable. Also increment the
53                  * pair of this variable in the runtime in metadata/appdomain.c.
54                  * Changes which are already detected at runtime, like the addition
55                  * of icalls, do not require an increment.
56                  */
57 #pragma warning disable 169
58                 private const int mono_corlib_version = 94;
59 #pragma warning restore 169
60
61                 [ComVisible (true)]
62                 public enum SpecialFolder
63                 {       
64                         MyDocuments = 0x05,
65                         Desktop = 0x00,
66                         MyComputer = 0x11,
67                         Programs = 0x02,
68                         Personal = 0x05,
69                         Favorites = 0x06,
70                         Startup = 0x07,
71                         Recent = 0x08,
72                         SendTo = 0x09,
73                         StartMenu = 0x0b,
74                         MyMusic = 0x0d,
75                         DesktopDirectory = 0x10,
76                         Templates = 0x15,
77                         ApplicationData = 0x1a,
78                         LocalApplicationData = 0x1c,
79                         InternetCache = 0x20,
80                         Cookies = 0x21,
81                         History = 0x22,
82                         CommonApplicationData   = 0x23,
83                         System = 0x25,
84                         ProgramFiles = 0x26,
85                         MyPictures = 0x27,
86                         CommonProgramFiles = 0x2b,
87 #if NET_4_0 || MOONLIGHT
88                         MyVideos = 0x0e,
89 #endif
90 #if NET_4_0
91                         NetworkShortcuts = 0x13,
92                         Fonts = 0x14,
93                         CommonStartMenu = 0x16,
94                         CommonPrograms = 0x17,
95                         CommonStartup = 0x18,
96                         CommonDesktopDirectory = 0x19,
97                         PrinterShortcuts = 0x1b,
98                         Windows = 0x24,
99                         UserProfile = 0x28,
100                         SystemX86 = 0x29,
101                         ProgramFilesX86 = 0x2a,
102                         CommonProgramFilesX86 = 0x2c,
103                         CommonTemplates = 0x2d,
104                         CommonDocuments = 0x2e,
105                         CommonAdminTools = 0x2f,
106                         AdminTools = 0x30,
107                         CommonMusic = 0x35,
108                         CommonPictures = 0x36,
109                         CommonVideos = 0x37,
110                         Resources = 0x38,
111                         LocalizedResources = 0x39,
112                         CommonOemLinks = 0x3a,
113                         CDBurning = 0x3b,
114 #endif
115                 }
116
117 #if NET_4_0
118                 public
119 #endif
120                 enum SpecialFolderOption {
121                         None = 0,
122                         DoNotVerify = 0x4000,
123                         Create = 0x8000
124                 }
125
126                 /// <summary>
127                 /// Gets the command line for this process
128                 /// </summary>
129                 public static string CommandLine {
130                         // note: security demand inherited from calling GetCommandLineArgs
131                         get {
132                                 StringBuilder sb = new StringBuilder ();
133                                 foreach (string str in GetCommandLineArgs ()) {
134                                         bool escape = false;
135                                         string quote = "";
136                                         string s = str;
137                                         for (int i = 0; i < s.Length; i++) {
138                                                 if (quote.Length == 0 && Char.IsWhiteSpace (s [i])) {
139                                                         quote = "\"";
140                                                 } else if (s [i] == '"') {
141                                                         escape = true;
142                                                 }
143                                         }
144                                         if (escape && quote.Length != 0) {
145                                                 s = s.Replace ("\"", "\\\"");
146                                         }
147                                         sb.AppendFormat ("{0}{1}{0} ", quote, s);
148                                 }
149                                 if (sb.Length > 0)
150                                         sb.Length--;
151                                 return sb.ToString ();
152                         }
153                 }
154
155                 /// <summary>
156                 /// Gets or sets the current directory. Actually this is supposed to get
157                 /// and/or set the process start directory acording to the documentation
158                 /// but actually test revealed at beta2 it is just Getting/Setting the CurrentDirectory
159                 /// </summary>
160                 public static string CurrentDirectory
161                 {
162                         get {
163                                 return Directory.GetCurrentDirectory ();
164                         }
165                         set {
166                                 Directory.SetCurrentDirectory (value);
167                         }
168                 }
169
170                 /// <summary>
171                 /// Gets or sets the exit code of this process
172                 /// </summary>
173                 public extern static int ExitCode
174                 {       
175                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
176                         get;
177                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
178                         set;
179                 }
180
181                 static public extern bool HasShutdownStarted
182                 {
183                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
184                         get;
185                 }
186                 
187
188                 /// <summary>
189                 /// Gets the name of the local computer
190                 /// </summary>
191                 public extern static string MachineName {
192                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
193                         [EnvironmentPermission (SecurityAction.Demand, Read="COMPUTERNAME")]
194                         [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
195                         get;
196                 }
197
198                 /// <summary>
199                 /// Gets the standard new line value
200                 /// </summary>
201                 public extern static string NewLine {
202                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
203                         get;
204                 }
205
206                 //
207                 // Support methods and fields for OSVersion property
208                 //
209                 static OperatingSystem os;
210
211                 internal static extern PlatformID Platform {
212                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
213                         get;
214                 }
215
216                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
217                 internal static extern string GetOSVersionString ();
218
219                 /// <summary>
220                 /// Gets the current OS version information
221                 /// </summary>
222                 public static OperatingSystem OSVersion {
223                         get {
224                                 if (os == null) {
225                                         Version v = Version.CreateFromString (GetOSVersionString ());
226                                         PlatformID p = Platform;
227                                         os = new OperatingSystem (p, v);
228                                 }
229                                 return os;
230                         }
231                 }
232
233                 /// <summary>
234                 /// Get StackTrace
235                 /// </summary>
236                 public static string StackTrace {
237                         [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
238                         get {
239                                 System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (0, true);
240                                 return trace.ToString ();
241                         }
242                 }
243 #if !NET_2_1
244                 /// <summary>
245                 /// Get a fully qualified path to the system directory
246                 /// </summary>
247                 public static string SystemDirectory {
248                         get {
249                                 return GetFolderPath (SpecialFolder.System);
250                         }
251                 }
252 #endif
253                 /// <summary>
254                 /// Get the number of milliseconds that have elapsed since the system was booted
255                 /// </summary>
256                 public extern static int TickCount {
257                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
258                         get;
259                 }
260
261                 /// <summary>
262                 /// Get UserDomainName
263                 /// </summary>
264                 public static string UserDomainName {
265                         // FIXME: this variable doesn't exist (at least not on WinXP) - reported to MS as FDBK20562
266                         [EnvironmentPermission (SecurityAction.Demand, Read="USERDOMAINNAME")]
267                         get {
268                                 return MachineName;
269                         }
270                 }
271
272                 /// <summary>
273                 /// Gets a flag indicating whether the process is in interactive mode
274                 /// </summary>
275                 [MonoTODO ("Currently always returns false, regardless of interactive state")]
276                 public static bool UserInteractive {
277                         get {
278                                 return false;
279                         }
280                 }
281
282                 /// <summary>
283                 /// Get the user name of current process is running under
284                 /// </summary>
285                 public extern static string UserName {
286                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
287                         [EnvironmentPermission (SecurityAction.Demand, Read="USERNAME;USER")]
288                         get;
289                 }
290
291                 /// <summary>
292                 /// Get the version of the common language runtime 
293                 /// </summary>
294                 public static Version Version {
295                         get {
296                                 return new Version (Consts.FxFileVersion);
297                         }
298                 }
299
300                 /// <summary>
301                 /// Get the amount of physical memory mapped to process
302                 /// </summary>
303                 [MonoTODO ("Currently always returns zero")]
304                 public static long WorkingSet {
305                         [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
306                         get { return 0; }
307                 }
308
309                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
310                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
311                 public extern static void Exit (int exitCode);
312
313                 /// <summary>
314                 /// Substitute environment variables in the argument "name"
315                 /// </summary>
316                 public static string ExpandEnvironmentVariables (string name)
317                 {
318                         if (name == null)
319                                 throw new ArgumentNullException ("name");
320
321                         int off1 = name.IndexOf ('%');
322                         if (off1 == -1)
323                                 return name;
324
325                         int len = name.Length;
326                         int off2 = 0;
327                         if (off1 == len - 1 || (off2 = name.IndexOf ('%', off1 + 1)) == -1)
328                                 return name;
329
330                         StringBuilder result = new StringBuilder ();
331                         result.Append (name, 0, off1);
332                         Hashtable tbl = null;
333                         do {
334                                 string var = name.Substring (off1 + 1, off2 - off1 - 1);
335                                 string value = GetEnvironmentVariable (var);
336                                 if (value == null && Environment.IsRunningOnWindows) {
337                                         // On windows, env. vars. are case insensitive
338                                         if (tbl == null)
339                                                 tbl = GetEnvironmentVariablesNoCase ();
340
341                                         value = tbl [var] as string;
342                                 }
343                                 
344                                 // If value not found, add %FOO to stream,
345                                 //  and use the closing % for the next iteration.
346                                 // If value found, expand it in place of %FOO%
347                                 if (value == null) {
348                                         result.Append ('%');
349                                         result.Append (var);
350                                         off2--;
351                                 } else {
352                                         result.Append (value);
353                                 }
354                                 int oldOff2 = off2;
355                                 off1 = name.IndexOf ('%', off2 + 1);
356                                 // If no % found for off1, don't look for one for off2
357                                 off2 = (off1 == -1 || off2 > len-1)? -1 :name.IndexOf ('%', off1 + 1);
358                                 // textLen is the length of text between the closing % of current iteration
359                                 //  and the starting % of the next iteration if any. This text is added to output
360                                 int textLen;
361                                 // If no new % found, use all the remaining text
362                                 if (off1 == -1 || off2 == -1)
363                                         textLen = len - oldOff2 - 1;
364                                 // If value found in current iteration, use text after current closing % and next %
365                                 else if(value != null)
366                                         textLen = off1 - oldOff2 - 1;
367                                 // If value not found in current iteration, but a % was found for next iteration,
368                                 //  use text from current closing % to the next %.
369                                 else
370                                         textLen = off1 - oldOff2;
371                                 if(off1 >= oldOff2 || off1 == -1)
372                                         result.Append (name, oldOff2+1, textLen);
373                         } while (off2 > -1 && off2 < len);
374                                 
375                         return result.ToString ();
376
377                 }
378
379                 /// <summary>
380                 /// Return an array of the command line arguments of the current process
381                 /// </summary>
382                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
383                 [EnvironmentPermissionAttribute (SecurityAction.Demand, Read = "PATH")]
384                 public extern static string[] GetCommandLineArgs ();
385
386                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
387                 internal extern static string internalGetEnvironmentVariable (string variable);
388
389                 /// <summary>
390                 /// Return a string containing the value of the environment
391                 /// variable identifed by parameter "variable"
392                 /// </summary>
393                 public static string GetEnvironmentVariable (string variable)
394                 {
395 #if !NET_2_1
396                         if (SecurityManager.SecurityEnabled) {
397                                 new EnvironmentPermission (EnvironmentPermissionAccess.Read, variable).Demand ();
398                         }
399 #endif
400                         return internalGetEnvironmentVariable (variable);
401                 }
402
403                 static Hashtable GetEnvironmentVariablesNoCase ()
404                 {
405                         Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default,
406                                                         CaseInsensitiveComparer.Default);
407
408                         foreach (string name in GetEnvironmentVariableNames ()) {
409                                 vars [name] = internalGetEnvironmentVariable (name);
410                         }
411
412                         return vars;
413                 }
414
415                 /// <summary>
416                 /// Return a set of all environment variables and their values
417                 /// </summary>
418 #if !NET_2_1
419                 public static IDictionary GetEnvironmentVariables ()
420                 {
421                         StringBuilder sb = null;
422                         if (SecurityManager.SecurityEnabled) {
423                                 // we must have access to each variable to get the lot
424                                 sb = new StringBuilder ();
425                                 // but (performance-wise) we do not want a stack-walk
426                                 // for each of them so we concatenate them
427                         }
428
429                         Hashtable vars = new Hashtable ();
430                         foreach (string name in GetEnvironmentVariableNames ()) {
431                                 vars [name] = internalGetEnvironmentVariable (name);
432                                 if (sb != null) {
433                                         sb.Append (name);
434                                         sb.Append (";");
435                                 }
436                         }
437
438                         if (sb != null) {
439                                 new EnvironmentPermission (EnvironmentPermissionAccess.Read, sb.ToString ()).Demand ();
440                         }
441                         return vars;
442                 }
443 #else
444                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
445                 public static IDictionary GetEnvironmentVariables ()
446                 {
447                         Hashtable vars = new Hashtable ();
448                         foreach (string name in GetEnvironmentVariableNames ()) {
449                                 vars [name] = internalGetEnvironmentVariable (name);
450                         }
451                         return vars;
452                 }
453 #endif
454
455                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
456                 private extern static string GetWindowsFolderPath (int folder);
457
458                 /// <summary>
459                 /// Returns the fully qualified path of the
460                 /// folder specified by the "folder" parameter
461                 /// </summary>
462                 public static string GetFolderPath (SpecialFolder folder)
463                 {
464                         return GetFolderPath (folder, SpecialFolderOption.None);
465                 }
466 #if NET_4_0
467                 [MonoTODO ("Figure out the folder path for all the new values in SpecialFolder. Use the 'option' argument.")]
468                 public
469 #endif
470                 static string GetFolderPath(SpecialFolder folder, SpecialFolderOption option)
471                 {
472                         SecurityManager.EnsureElevatedPermissions (); // this is a no-op outside moonlight
473
474                         string dir = null;
475
476                         if (Environment.IsRunningOnWindows) {
477                                 dir = GetWindowsFolderPath ((int) folder);
478                         } else {
479                                 dir = InternalGetFolderPath (folder);
480                         }
481 #if !NET_2_1
482                         if ((dir != null) && (dir.Length > 0) && SecurityManager.SecurityEnabled) {
483                                 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dir).Demand ();
484                         }
485 #endif
486                         return dir;
487                 }
488
489                 private static string ReadXdgUserDir (string config_dir, string home_dir, 
490                         string key, string fallback)
491                 {
492                         string env_path = internalGetEnvironmentVariable (key);
493                         if (env_path != null && env_path != String.Empty) {
494                                 return env_path;
495                         }
496
497                         string user_dirs_path = Path.Combine (config_dir, "user-dirs.dirs");
498
499                         if (!File.Exists (user_dirs_path)) {
500                                 return Path.Combine (home_dir, fallback);
501                         }
502
503                         try {
504                                 using(StreamReader reader = new StreamReader (user_dirs_path)) {
505                                         string line;
506                                         while ((line = reader.ReadLine ()) != null) {
507                                                 line = line.Trim ();
508                                                 int delim_index = line.IndexOf ('=');
509                         if(delim_index > 8 && line.Substring (0, delim_index) == key) {
510                             string path = line.Substring (delim_index + 1).Trim ('"');
511                             bool relative = false;
512
513                             if (path.StartsWith ("$HOME/")) {
514                                 relative = true;
515                                 path = path.Substring (6);
516                             } else if (!path.StartsWith ("/")) {
517                                 relative = true;
518                             }
519
520                             return relative ? Path.Combine (home_dir, path) : path;
521                         }
522                                         }
523                                 }
524                         } catch (FileNotFoundException) {
525                         }
526
527                         return Path.Combine (home_dir, fallback);
528                 }
529
530
531                 // the security runtime (and maybe other parts of corlib) needs the
532                 // information to initialize themselves before permissions can be checked
533                 internal static string InternalGetFolderPath (SpecialFolder folder)
534                 {
535                         string home = internalGetHome ();
536
537                         // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
538
539                         // note: skip security check for environment variables
540                         string data = internalGetEnvironmentVariable ("XDG_DATA_HOME");
541                         if ((data == null) || (data == String.Empty)) {
542                                 data = Path.Combine (home, ".local");
543                                 data = Path.Combine (data, "share");
544                         }
545
546                         // note: skip security check for environment variables
547                         string config = internalGetEnvironmentVariable ("XDG_CONFIG_HOME");
548                         if ((config == null) || (config == String.Empty)) {
549                                 config = Path.Combine (home, ".config");
550                         }
551
552                         switch (folder) {
553                         // MyComputer is a virtual directory
554                         case SpecialFolder.MyComputer:
555                                 return String.Empty;
556
557                         // personal == ~
558                         case SpecialFolder.Personal:
559 #if MONOTOUCH
560                                 return Path.Combine (home, "Documents");
561 #else
562                                 return home;
563 #endif
564                         // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart.
565                         case SpecialFolder.ApplicationData:
566 #if MONOTOUCH
567                         {
568                                 string dir = Path.Combine (Path.Combine (home, "Documents"), ".config");
569                                 if (!Directory.Exists (dir))
570                                         Directory.CreateDirectory (dir);
571
572                                 return dir;
573                         }
574 #else
575                                 return config;
576 #endif
577                         //use FDO's DATA_HOME. This is *NOT* synced
578                         case SpecialFolder.LocalApplicationData:
579 #if MONOTOUCH
580                         {
581                                 string dir = Path.Combine (home, "Documents");
582                                 if (!Directory.Exists (dir))
583                                         Directory.CreateDirectory (dir);
584
585                                 return dir;
586                         }
587 #else
588                                 return data;
589 #endif
590
591                         case SpecialFolder.Desktop:
592                         case SpecialFolder.DesktopDirectory:
593                                 return ReadXdgUserDir (config, home, "XDG_DESKTOP_DIR", "Desktop");
594
595                         case SpecialFolder.MyMusic:
596                                 return ReadXdgUserDir (config, home, "XDG_MUSIC_DIR", "Music");
597
598                         case SpecialFolder.MyPictures:
599                                 return ReadXdgUserDir (config, home, "XDG_PICTURES_DIR", "Pictures");
600                         
601                         case SpecialFolder.Templates:
602                                 return ReadXdgUserDir (config, home, "XDG_TEMPLATES_DIR", "Templates");
603 #if NET_4_0 || MOONLIGHT
604                         case SpecialFolder.MyVideos:
605                                 return ReadXdgUserDir (config, home, "XDG_VIDEOS_DIR", "Videos");
606 #endif
607 #if NET_4_0
608                         case SpecialFolder.CommonTemplates:
609                                 return "/usr/share/templates";
610                         case SpecialFolder.Fonts:
611                                 return Path.Combine (home, ".fonts");
612 #endif
613                         // these simply dont exist on Linux
614                         // The spec says if a folder doesnt exist, we
615                         // should return ""
616                         case SpecialFolder.Favorites:
617                         case SpecialFolder.Programs:
618                         case SpecialFolder.SendTo:
619                         case SpecialFolder.StartMenu:
620                         case SpecialFolder.Startup:
621                         case SpecialFolder.Cookies:
622                         case SpecialFolder.History:
623                         case SpecialFolder.InternetCache:
624                         case SpecialFolder.Recent:
625                         case SpecialFolder.CommonProgramFiles:
626                         case SpecialFolder.ProgramFiles:
627                         case SpecialFolder.System:
628 #if NET_4_0
629                         case SpecialFolder.NetworkShortcuts:
630                         case SpecialFolder.CommonStartMenu:
631                         case SpecialFolder.CommonPrograms:
632                         case SpecialFolder.CommonStartup:
633                         case SpecialFolder.CommonDesktopDirectory:
634                         case SpecialFolder.PrinterShortcuts:
635                         case SpecialFolder.Windows:
636                         case SpecialFolder.UserProfile:
637                         case SpecialFolder.SystemX86:
638                         case SpecialFolder.ProgramFilesX86:
639                         case SpecialFolder.CommonProgramFilesX86:
640                         case SpecialFolder.CommonDocuments:
641                         case SpecialFolder.CommonAdminTools:
642                         case SpecialFolder.AdminTools:
643                         case SpecialFolder.CommonMusic:
644                         case SpecialFolder.CommonPictures:
645                         case SpecialFolder.CommonVideos:
646                         case SpecialFolder.Resources:
647                         case SpecialFolder.LocalizedResources:
648                         case SpecialFolder.CommonOemLinks:
649                         case SpecialFolder.CDBurning:
650 #endif
651                                 return String.Empty;
652                         // This is where data common to all users goes
653                         case SpecialFolder.CommonApplicationData:
654                                 return "/usr/share";
655                         default:
656                                 throw new ArgumentException ("Invalid SpecialFolder");
657                         }
658                 }
659
660                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
661                 public static string[] GetLogicalDrives ()
662                 {
663                         return GetLogicalDrivesInternal ();
664                 }
665
666 #if !NET_2_1
667                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
668                 private static extern void internalBroadcastSettingChange ();
669
670                 public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
671                 {
672                         switch (target) {
673                         case EnvironmentVariableTarget.Process:
674                                 return GetEnvironmentVariable (variable);
675                         case EnvironmentVariableTarget.Machine:
676                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
677                                 if (!IsRunningOnWindows)
678                                         return null;
679                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
680                                         object regvalue = env.GetValue (variable);
681                                         return (regvalue == null) ? null : regvalue.ToString ();
682                                 }
683                         case EnvironmentVariableTarget.User:
684                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
685                                 if (!IsRunningOnWindows)
686                                         return null;
687                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", false)) {
688                                         object regvalue = env.GetValue (variable);
689                                         return (regvalue == null) ? null : regvalue.ToString ();
690                                 }
691                         default:
692                                 throw new ArgumentException ("target");
693                         }
694                 }
695
696                 public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
697                 {
698                         IDictionary variables = (IDictionary)new Hashtable ();
699                         switch (target) {
700                         case EnvironmentVariableTarget.Process:
701                                 variables = GetEnvironmentVariables ();
702                                 break;
703                         case EnvironmentVariableTarget.Machine:
704                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
705                                 if (IsRunningOnWindows) {
706                                         using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
707                                                 string[] value_names = env.GetValueNames ();
708                                                 foreach (string value_name in value_names)
709                                                         variables.Add (value_name, env.GetValue (value_name));
710                                         }
711                                 }
712                                 break;
713                         case EnvironmentVariableTarget.User:
714                                 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
715                                 if (IsRunningOnWindows) {
716                                         using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment")) {
717                                                 string[] value_names = env.GetValueNames ();
718                                                 foreach (string value_name in value_names)
719                                                         variables.Add (value_name, env.GetValue (value_name));
720                                         }
721                                 }
722                                 break;
723                         default:
724                                 throw new ArgumentException ("target");
725                         }
726                         return variables;
727                 }
728
729                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
730                 public static void SetEnvironmentVariable (string variable, string value)
731                 {
732                         SetEnvironmentVariable (variable, value, EnvironmentVariableTarget.Process);
733                 }
734
735                 [EnvironmentPermission (SecurityAction.Demand, Unrestricted = true)]
736                 public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
737                 {
738                         if (variable == null)
739                                 throw new ArgumentNullException ("variable");
740                         if (variable == String.Empty)
741                                 throw new ArgumentException ("String cannot be of zero length.", "variable");
742                         if (variable.IndexOf ('=') != -1)
743                                 throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
744                         if (variable[0] == '\0')
745                                 throw new ArgumentException ("The first char in the string is the null character.", "variable");
746
747                         switch (target) {
748                         case EnvironmentVariableTarget.Process:
749                                 InternalSetEnvironmentVariable (variable, value);
750                                 break;
751                         case EnvironmentVariableTarget.Machine:
752                                 if (!IsRunningOnWindows)
753                                         return;
754                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true)) {
755                                         if (String.IsNullOrEmpty (value))
756                                                 env.DeleteValue (variable, false);
757                                         else
758                                                 env.SetValue (variable, value);
759                                         internalBroadcastSettingChange ();
760                                 }
761                                 break;
762                         case EnvironmentVariableTarget.User:
763                                 if (!IsRunningOnWindows)
764                                         return;
765                                 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", true)) {
766                                         if (String.IsNullOrEmpty (value))
767                                                 env.DeleteValue (variable, false);
768                                         else
769                                                 env.SetValue (variable, value);
770                                         internalBroadcastSettingChange ();
771                                 }
772                                 break;
773                         default:
774                                 throw new ArgumentException ("target");
775                         }
776                 }
777
778                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
779                 internal static extern void InternalSetEnvironmentVariable (string variable, string value);
780 #endif
781                 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode=true)]
782                 public static void FailFast (string message)
783                 {
784                         throw new NotImplementedException ();
785                 }
786
787 #if NET_4_0 || MOONLIGHT
788                 [SecurityCritical]
789                 public static void FailFast (string message, Exception exception)
790                 {
791                         throw new NotImplementedException ();
792                 }
793 #endif
794
795 #if NET_4_0
796                 public static bool Is64BitOperatingSystem {
797                         get { return IntPtr.Size == 8; } // FIXME: is this good enough?
798                 }
799
800                 public static bool Is64BitProcess {
801                         get { return Is64BitOperatingSystem; }
802                 }
803
804                 public static int SystemPageSize {
805                         get { return GetPageSize (); }
806                 }
807 #endif
808
809                 public static extern int ProcessorCount {
810                         [EnvironmentPermission (SecurityAction.Demand, Read="NUMBER_OF_PROCESSORS")]
811                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
812                         get;                    
813                 }
814
815                 // private methods
816
817                 internal static bool IsRunningOnWindows {
818                         get { return ((int) Platform < 4); }
819                 }
820 #if !NET_2_1
821                 //
822                 // Used by gacutil.exe
823                 //
824 #pragma warning disable 169             
825                 private static string GacPath {
826                         get {
827                                 if (Environment.IsRunningOnWindows) {
828                                         /* On windows, we don't know the path where mscorlib.dll will be installed */
829                                         string corlibDir = new DirectoryInfo (Path.GetDirectoryName (typeof (int).Assembly.Location)).Parent.Parent.FullName;
830                                         return Path.Combine (Path.Combine (corlibDir, "mono"), "gac");
831                                 }
832
833                                 return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
834                         }
835                 }
836 #pragma warning restore 169
837                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
838                 internal extern static string internalGetGacPath ();
839 #endif
840                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
841                 private extern static string [] GetLogicalDrivesInternal ();
842
843                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
844                 private extern static string [] GetEnvironmentVariableNames ();
845
846                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
847                 internal extern static string GetMachineConfigPath ();
848
849                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
850                 internal extern static string internalGetHome ();
851
852                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
853                 internal extern static int GetPageSize ();
854
855                 static internal bool IsUnix {
856                         get {
857                                 int platform = (int) Environment.Platform;
858
859                                 return (platform == 4 || platform == 128 || platform == 6);
860                         }
861                 }
862         }
863 }
864