c21030f8b35b9faacf6bcd15c7e6e999b4914494
[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 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;
36 using System.IO;
37 //using System.Diagnostics;
38 using System.Collections;
39 using System.Security;
40 using System.Security.Permissions;
41 using System.Runtime.CompilerServices;
42 using System.Text;
43
44 namespace System
45 {
46         public sealed 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 semantics etc),
52                  * 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                 private const int mono_corlib_version = 22;
58
59                 private Environment ()
60                 {
61                 }
62
63                 [MonoTODO]
64                 public enum SpecialFolder
65                 {       // TODO: Determine if these windoze style folder identifiers 
66                         //       have unix/linux counterparts
67
68 #if NET_1_1
69                         Desktop = 0x00,
70                         MyComputer = 0x11,
71 #endif
72                         Programs = 0x02,
73                         Personal = 0x05,
74                         Favorites = 0x06,
75                         Startup = 0x07,
76                         Recent = 0x08,
77                         SendTo = 0x09,
78                         StartMenu = 0x0b,
79                         MyMusic = 0x0d,
80                         DesktopDirectory = 0x10,
81                         Templates = 0x15,
82                         ApplicationData = 0x1a,
83                         LocalApplicationData = 0x1c,
84                         InternetCache = 0x20,
85                         Cookies = 0x21,
86                         History = 0x22,
87                         CommonApplicationData   = 0x23,
88                         System = 0x25,
89                         ProgramFiles = 0x26,
90                         MyPictures = 0x27,
91                         CommonProgramFiles = 0x2b,
92                 }
93
94                 // TODO: Make sure the security attributes do what I expect
95                         
96                 /// <summary>
97                 /// Gets the command line for this process
98                 /// </summary>
99                 public static string CommandLine
100                 {       // TODO: Coordinate with implementor of EnvironmentPermissionAttribute
101                         // [EnvironmentPermissionAttribute(SecurityAction.Demand, Read = "COMMANDLINE")]
102                         get
103                         {
104                                 // FIXME: we may need to quote, but any sane person
105                                 // should use GetCommandLineArgs () instead.
106                                 return String.Join (" ", GetCommandLineArgs ());
107                         }
108                 }
109
110                 /// <summary>
111                 /// Gets or sets the current directory. Actually this is supposed to get
112                 /// and/or set the process start directory acording to the documentation
113                 /// but actually test revealed at beta2 it is just Getting/Setting the CurrentDirectory
114                 /// </summary>
115                 public static string CurrentDirectory
116                 {
117                         // originally it was my thought that the external call would be made in
118                         // the directory class however that class has additional security requirements
119                         // so the Directory class will call this class for its get/set current directory
120                         get {
121                                 return Directory.GetCurrentDirectory ();
122                         }
123                         set {
124                                 Directory.SetCurrentDirectory (value);
125                         }
126                 }
127
128                 /// <summary>
129                 /// Gets or sets the exit code of this process
130                 /// </summary>
131                 public extern static int ExitCode
132                 {       
133                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
134                         get;
135                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
136                         set;
137                 }
138
139 #if NET_1_1
140                 static
141 #endif
142                 public extern bool HasShutdownStarted
143                 {
144                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
145                         get;
146                 }
147                 
148
149                 /// <summary>
150                 /// Gets the name of the local computer
151                 /// </summary>
152                 public extern static string MachineName {
153                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
154                         get;
155                 }
156
157                 /// <summary>
158                 /// Gets the standard new line value
159                 /// </summary>
160                 public extern static string NewLine {
161                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
162                         get;
163                 }
164
165                 //
166                 // Support methods and fields for OSVersion property
167                 //
168                 static OperatingSystem os;
169
170                 internal static extern PlatformID Platform {
171                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
172                         get;
173                 }
174
175                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
176                 internal static extern string GetOSVersionString ();
177
178                 /// <summary>
179                 /// Gets the current OS version information
180                 /// </summary>
181                 public static OperatingSystem OSVersion {
182                         get {
183                                 if (os == null) {
184                                         Version v = Version.CreateFromString (GetOSVersionString ());
185                                         os = new OperatingSystem (Platform, v);
186                                 }
187                                 return os;
188                         }
189                 }
190
191                 /// <summary>
192                 /// Get StackTrace
193                 /// </summary>
194                 public static string StackTrace {
195                         get {
196                                 System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (1);
197                                 return trace.ToString ();
198                         }
199                 }
200
201                 /// <summary>
202                 /// Get a fully qualified path to the system directory
203                 /// </summary>
204                 public static string SystemDirectory {
205                         get {
206                                 return GetFolderPath (SpecialFolder.System);
207                         }
208                 }
209
210                 /// <summary>
211                 /// Get the number of milliseconds that have elapsed since the system was booted
212                 /// </summary>
213                 public extern static int TickCount {
214                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
215                         get;
216                 }
217
218                 /// <summary>
219                 /// Get UserDomainName
220                 /// </summary>
221                 public static string UserDomainName {
222                         get {
223                                 return MachineName;
224                         }
225                 }
226
227                 /// <summary>
228                 /// Gets a flag indicating whether the process is in interactive mode
229                 /// </summary>
230                 [MonoTODO]
231                 public static bool UserInteractive {
232                         get {
233                                 return false;
234                         }
235                 }
236
237                 /// <summary>
238                 /// Get the user name of current process is running under
239                 /// </summary>
240                 public extern static string UserName
241                 {
242                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
243                         get;
244                 }
245
246                 /// <summary>
247                 /// Get the version of the common language runtime 
248                 /// </summary>
249                 public static Version Version {
250                         get {
251 #if NET_1_1                                 
252                                 return new Version (1, 1, 4322, 573);
253 #else
254                                 return new Version (1, 0, 3705, 288);
255 #endif
256                         }
257                 }
258
259                 /// <summary>
260                 /// Get the amount of physical memory mapped to process
261                 /// </summary>
262                 [MonoTODO]
263                 public static long WorkingSet
264                 {
265                         get {
266                                 return 0;
267                         }
268                 }
269
270                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
271                 public extern static void Exit (int exitCode);
272
273                 /// <summary>
274                 /// Substitute environment variables in the argument "name"
275                 /// </summary>
276                 public static string ExpandEnvironmentVariables (string name)
277                 {
278                         if (name == null)
279                                 throw new ArgumentNullException ("name");
280
281                         int off1 = name.IndexOf ('%');
282                         if (off1 == -1)
283                                 return name;
284
285                         int len = name.Length;
286                         int off2 = 0;
287                         if (off1 == len - 1 || (off2 = name.IndexOf ('%', off1 + 1)) == -1)
288                                 return name;
289
290                         PlatformID platform = Platform;
291                         StringBuilder result = new StringBuilder ();
292                         result.Append (name, 0, off1);
293                         Hashtable tbl = null;
294                         do {
295                                 string var = name.Substring (off1 + 1, off2 - off1 - 1);
296                                 string value = GetEnvironmentVariable (var);
297                                 if (value == null && (int) platform != 128) {
298                                         // On windows, env. vars. are case insensitive
299                                         if (tbl == null)
300                                                 tbl = GetEnvironmentVariablesNoCase ();
301
302                                         value = tbl [var] as string;
303                                 }
304                                 
305                                 if (value == null) {
306                                         result.Append ('%');
307                                         result.Append (var);
308                                         result.Append ('%');
309                                 } else {
310                                         result.Append (value);
311                                 }
312
313                                 if (off2 + 1 == len) {
314                                         off1 = off2;
315                                         off2 = -1;
316                                 } else {
317                                         off1 = off2 + 1;
318                                         off2 = (off1 + 1 == len) ? -1 : name.IndexOf ('%', off1 + 1);
319                                 }
320
321                         } while (off2 != -1);
322
323                         if (off1 + 1 < len)
324                                 result.Append (name.Substring (off1));
325
326                         return result.ToString ();
327                 }
328
329                 /// <summary>
330                 /// Return an array of the command line arguments of the current process
331                 /// </summary>
332                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
333                 public extern static string[] GetCommandLineArgs();
334
335                 /// <summary>
336                 /// Return a string containing the value of the environment
337                 /// variable identifed by parameter "variable"
338                 /// </summary>
339                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
340                 public extern static string GetEnvironmentVariable (string name);
341
342                 static Hashtable GetEnvironmentVariablesNoCase ()
343                 {
344                         Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default,
345                                                         CaseInsensitiveComparer.Default);
346
347                         foreach (string name in GetEnvironmentVariableNames ()) {
348                                 vars [name] = GetEnvironmentVariable (name);
349                         }
350
351                         return vars;
352                 }
353
354                 /// <summary>
355                 /// Return a set of all environment variables and their values
356                 /// </summary>
357            
358                 public static IDictionary GetEnvironmentVariables()
359                 {
360                         Hashtable vars = new Hashtable ();
361                         foreach (string name in GetEnvironmentVariableNames ()) {
362                                 vars [name] = GetEnvironmentVariable (name);
363                         }
364
365                         return vars;
366                 }
367
368
369                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
370                 private extern static string GetWindowsFolderPath (int folder);
371
372                 /// <summary>
373                 /// Returns the fully qualified path of the
374                 /// folder specified by the "folder" parameter
375                 /// </summary>
376                 public static string GetFolderPath (SpecialFolder folder)
377                 {
378                         if ((int) Platform != 128)
379                                 return GetWindowsFolderPath ((int) folder);
380
381                         string home = internalGetHome ();
382
383                         // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
384                         string data = GetEnvironmentVariable ("XDG_DATA_HOME");
385                         if ((data == null) || (data == String.Empty)) {
386                                 data = Path.Combine (home, ".local");
387                                 data = Path.Combine (data, "share");
388                         }
389
390                         string config = GetEnvironmentVariable ("XDG_CONFIG_HOME");
391                         if ((config == null) || (config == String.Empty)) {
392                                 config = Path.Combine (home, ".config");
393                         }
394
395                         switch (folder) {
396 #if NET_1_1
397                         // MyComputer is a virtual directory
398                         case SpecialFolder.MyComputer:
399                                 return "";
400 #endif
401                         // personal == ~
402                         case SpecialFolder.Personal:
403                                 return home;
404                         // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart.
405                         case SpecialFolder.ApplicationData:
406                                 return config;
407                         //use FDO's DATA_HOME. This is *NOT* synced
408                         case SpecialFolder.LocalApplicationData:
409                                 return data;
410 #if NET_1_1
411                         case SpecialFolder.Desktop:
412 #endif
413                         case SpecialFolder.DesktopDirectory:
414                                 return Path.Combine (home, "Desktop");
415                         
416                         // these simply dont exist on Linux
417                         // The spec says if a folder doesnt exist, we
418                         // should return ""
419                         case SpecialFolder.Favorites:
420                         case SpecialFolder.Programs:
421                         case SpecialFolder.SendTo:
422                         case SpecialFolder.StartMenu:
423                         case SpecialFolder.Startup:
424                         case SpecialFolder.MyMusic:
425                         case SpecialFolder.MyPictures:
426                         case SpecialFolder.Templates:
427                         case SpecialFolder.Cookies:
428                         case SpecialFolder.History:
429                         case SpecialFolder.InternetCache:
430                         case SpecialFolder.Recent:
431                         case SpecialFolder.CommonProgramFiles:
432                         case SpecialFolder.ProgramFiles:
433                         case SpecialFolder.System:
434                                 return "";
435                         // This is where data common to all users goes
436                         case SpecialFolder.CommonApplicationData:
437                                 return "/usr/share";
438                         default:
439                                 throw new ArgumentException ("Invalid SpecialFolder");
440                         }
441                 }
442
443                 public static string[] GetLogicalDrives ()
444                 {
445                         return GetLogicalDrivesInternal ();
446                 }
447
448                 static internal string GetResourceString (string s) { return ""; }
449
450                 // private methods
451
452                 private static string GacPath {
453                         get {
454                                 if ((int) Platform != 128) {
455                                         /* On windows, we don't know the path where mscorlib.dll will be installed */
456                                         string corlibDir = Path.GetDirectoryName (typeof (int).Assembly.Location);
457                                         return Path.Combine (Path.Combine (corlibDir, "mono"), "gac");
458                                 }
459
460                                 return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
461                         }
462                 }
463
464                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
465                 private extern static string [] GetLogicalDrivesInternal ();
466
467                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
468                 private extern static string [] GetEnvironmentVariableNames ();
469
470                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
471                 internal extern static string GetMachineConfigPath ();
472
473                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
474                 internal extern static string internalGetGacPath ();
475
476                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
477                 internal extern static string internalGetHome ();
478         }
479 }
480