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