2004-09-20 Zoltan Varga <vargaz@freemail.hu>
[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 = 26;
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_2_0
252                                 // FIXME: this is the version number for MS.NET 2.0 beta1. 
253                                 // It must be changed when the final version is released.
254                                 return new Version (2, 0, 40607, 16);
255 #elif NET_1_1                               
256                                 return new Version (1, 1, 4322, 573);
257 #else
258                                 return new Version (1, 0, 3705, 288);
259 #endif
260                         }
261                 }
262
263                 /// <summary>
264                 /// Get the amount of physical memory mapped to process
265                 /// </summary>
266                 [MonoTODO]
267                 public static long WorkingSet
268                 {
269                         get {
270                                 return 0;
271                         }
272                 }
273
274                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
275                 public extern static void Exit (int exitCode);
276
277                 /// <summary>
278                 /// Substitute environment variables in the argument "name"
279                 /// </summary>
280                 public static string ExpandEnvironmentVariables (string name)
281                 {
282                         if (name == null)
283                                 throw new ArgumentNullException ("name");
284
285                         int off1 = name.IndexOf ('%');
286                         if (off1 == -1)
287                                 return name;
288
289                         int len = name.Length;
290                         int off2 = 0;
291                         if (off1 == len - 1 || (off2 = name.IndexOf ('%', off1 + 1)) == -1)
292                                 return name;
293
294                         PlatformID platform = Platform;
295                         StringBuilder result = new StringBuilder ();
296                         result.Append (name, 0, off1);
297                         Hashtable tbl = null;
298                         do {
299                                 string var = name.Substring (off1 + 1, off2 - off1 - 1);
300                                 string value = GetEnvironmentVariable (var);
301                                 if (value == null && (int) platform != 128) {
302                                         // On windows, env. vars. are case insensitive
303                                         if (tbl == null)
304                                                 tbl = GetEnvironmentVariablesNoCase ();
305
306                                         value = tbl [var] as string;
307                                 }
308                                 
309                                 if (value == null) {
310                                         result.Append ('%');
311                                         result.Append (var);
312                                         result.Append ('%');
313                                 } else {
314                                         result.Append (value);
315                                 }
316
317                                 if (off2 + 1 == len) {
318                                         off1 = off2;
319                                         off2 = -1;
320                                 } else {
321                                         off1 = off2 + 1;
322                                         off2 = (off1 + 1 == len) ? -1 : name.IndexOf ('%', off1 + 1);
323                                 }
324
325                         } while (off2 != -1);
326
327                         if (off1 + 1 < len)
328                                 result.Append (name.Substring (off1));
329
330                         return result.ToString ();
331                 }
332
333                 /// <summary>
334                 /// Return an array of the command line arguments of the current process
335                 /// </summary>
336                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
337                 public extern static string[] GetCommandLineArgs();
338
339                 /// <summary>
340                 /// Return a string containing the value of the environment
341                 /// variable identifed by parameter "variable"
342                 /// </summary>
343                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
344                 public extern static string GetEnvironmentVariable (string name);
345
346                 static Hashtable GetEnvironmentVariablesNoCase ()
347                 {
348                         Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default,
349                                                         CaseInsensitiveComparer.Default);
350
351                         foreach (string name in GetEnvironmentVariableNames ()) {
352                                 vars [name] = GetEnvironmentVariable (name);
353                         }
354
355                         return vars;
356                 }
357
358                 /// <summary>
359                 /// Return a set of all environment variables and their values
360                 /// </summary>
361            
362                 public static IDictionary GetEnvironmentVariables()
363                 {
364                         Hashtable vars = new Hashtable ();
365                         foreach (string name in GetEnvironmentVariableNames ()) {
366                                 vars [name] = GetEnvironmentVariable (name);
367                         }
368
369                         return vars;
370                 }
371
372
373                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
374                 private extern static string GetWindowsFolderPath (int folder);
375
376                 /// <summary>
377                 /// Returns the fully qualified path of the
378                 /// folder specified by the "folder" parameter
379                 /// </summary>
380                 public static string GetFolderPath (SpecialFolder folder)
381                 {
382                         if ((int) Platform != 128)
383                                 return GetWindowsFolderPath ((int) folder);
384
385                         string home = internalGetHome ();
386
387                         // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
388                         string data = GetEnvironmentVariable ("XDG_DATA_HOME");
389                         if ((data == null) || (data == String.Empty)) {
390                                 data = Path.Combine (home, ".local");
391                                 data = Path.Combine (data, "share");
392                         }
393
394                         string config = GetEnvironmentVariable ("XDG_CONFIG_HOME");
395                         if ((config == null) || (config == String.Empty)) {
396                                 config = Path.Combine (home, ".config");
397                         }
398
399                         switch (folder) {
400 #if NET_1_1
401                         // MyComputer is a virtual directory
402                         case SpecialFolder.MyComputer:
403                                 return "";
404 #endif
405                         // personal == ~
406                         case SpecialFolder.Personal:
407                                 return home;
408                         // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart.
409                         case SpecialFolder.ApplicationData:
410                                 return config;
411                         //use FDO's DATA_HOME. This is *NOT* synced
412                         case SpecialFolder.LocalApplicationData:
413                                 return data;
414 #if NET_1_1
415                         case SpecialFolder.Desktop:
416 #endif
417                         case SpecialFolder.DesktopDirectory:
418                                 return Path.Combine (home, "Desktop");
419                         
420                         // these simply dont exist on Linux
421                         // The spec says if a folder doesnt exist, we
422                         // should return ""
423                         case SpecialFolder.Favorites:
424                         case SpecialFolder.Programs:
425                         case SpecialFolder.SendTo:
426                         case SpecialFolder.StartMenu:
427                         case SpecialFolder.Startup:
428                         case SpecialFolder.MyMusic:
429                         case SpecialFolder.MyPictures:
430                         case SpecialFolder.Templates:
431                         case SpecialFolder.Cookies:
432                         case SpecialFolder.History:
433                         case SpecialFolder.InternetCache:
434                         case SpecialFolder.Recent:
435                         case SpecialFolder.CommonProgramFiles:
436                         case SpecialFolder.ProgramFiles:
437                         case SpecialFolder.System:
438                                 return "";
439                         // This is where data common to all users goes
440                         case SpecialFolder.CommonApplicationData:
441                                 return "/usr/share";
442                         default:
443                                 throw new ArgumentException ("Invalid SpecialFolder");
444                         }
445                 }
446
447                 public static string[] GetLogicalDrives ()
448                 {
449                         return GetLogicalDrivesInternal ();
450                 }
451
452                 static internal string GetResourceString (string s) { return ""; }
453
454                 
455 #if NET_2_0
456                 public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
457                 {
458                         return (string)(GetEnvironmentVariables (target) [variable]);
459                 }
460
461                 [MonoTODO]
462                 public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
463                 {
464                         throw new NotImplementedException ();
465                 }
466
467                 public static void SetEnvironmentVariable (string variable, string value)
468                 {
469                         SetEnvironmentVariable (variable, value, EnvironmentVariableTarget.Process);
470                 }
471
472                 [MonoTODO]
473                 public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
474                 {
475                         throw new NotImplementedException ();
476                 }
477
478                 [MonoTODO]
479                 static bool IsServerGC {
480                         get {
481                                 throw new NotImplementedException ();
482                         }
483                 }
484
485                 [MonoTODO]
486                 static int ProcessorCount {
487                         get {
488                                 throw new NotImplementedException ();
489                         }
490                 }
491 #endif                
492                 
493                 // private methods
494
495                 private static string GacPath {
496                         get {
497                                 if ((int) Platform != 128) {
498                                         /* On windows, we don't know the path where mscorlib.dll will be installed */
499                                         string corlibDir = new DirectoryInfo (Path.GetDirectoryName (typeof (int).Assembly.Location)).Parent.Parent.FullName;
500                                         return Path.Combine (Path.Combine (corlibDir, "mono"), "gac");
501                                 }
502
503                                 return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
504                         }
505                 }
506
507                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
508                 private extern static string [] GetLogicalDrivesInternal ();
509
510                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
511                 private extern static string [] GetEnvironmentVariableNames ();
512
513                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
514                 internal extern static string GetMachineConfigPath ();
515
516                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
517                 internal extern static string internalGetGacPath ();
518
519                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
520                 internal extern static string internalGetHome ();
521         }
522 }
523