1
1
// Licensed to the .NET Foundation under one or more agreements.
2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
- using System . Collections ;
5
- using System . Collections . Generic ;
6
- using System . Diagnostics ;
7
4
using System . Diagnostics . CodeAnalysis ;
8
- using System . Runtime . InteropServices ;
9
5
using System . Runtime ;
10
- using System . Text ;
11
6
using System . Threading ;
12
7
13
8
namespace System
@@ -16,157 +11,9 @@ public static partial class Environment
16
11
{
17
12
internal static int CurrentNativeThreadId => ManagedThreadId . Current ;
18
13
19
- private static Dictionary < string , string > s_environment ;
20
-
21
- private static string ? GetEnvironmentVariableCore ( string variable )
22
- {
23
- Debug . Assert ( variable != null ) ;
24
-
25
- if ( s_environment == null )
26
- {
27
- return Marshal . PtrToStringUTF8 ( Interop . Sys . GetEnv ( variable ) ) ;
28
- }
29
-
30
- lock ( s_environment )
31
- {
32
- variable = TrimStringOnFirstZero ( variable ) ;
33
- s_environment . TryGetValue ( variable , out string ? value ) ;
34
- return value ;
35
- }
36
- }
37
-
38
- private static void SetEnvironmentVariableCore ( string variable , string ? value )
39
- {
40
- Debug . Assert ( variable != null ) ;
41
-
42
- EnsureEnvironmentCached ( ) ;
43
- lock ( s_environment )
44
- {
45
- variable = TrimStringOnFirstZero ( variable ) ;
46
- value = value == null ? null : TrimStringOnFirstZero ( value ) ;
47
- if ( string . IsNullOrEmpty ( value ) )
48
- {
49
- s_environment . Remove ( variable ) ;
50
- }
51
- else
52
- {
53
- s_environment [ variable ] = value ;
54
- }
55
- }
56
- }
57
-
58
- public static IDictionary GetEnvironmentVariables ( )
59
- {
60
- var results = new Hashtable ( ) ;
61
-
62
- EnsureEnvironmentCached ( ) ;
63
- lock ( s_environment )
64
- {
65
- foreach ( var keyValuePair in s_environment )
66
- {
67
- results . Add ( keyValuePair . Key , keyValuePair . Value ) ;
68
- }
69
- }
70
-
71
- return results ;
72
- }
73
-
74
- private static string TrimStringOnFirstZero ( string value )
75
- {
76
- int index = value . IndexOf ( '\0 ' ) ;
77
- if ( index >= 0 )
78
- {
79
- return value . Substring ( 0 , index ) ;
80
- }
81
- return value ;
82
- }
83
-
84
- private static void EnsureEnvironmentCached ( )
85
- {
86
- if ( s_environment == null )
87
- {
88
- Interlocked . CompareExchange ( ref s_environment , GetSystemEnvironmentVariables ( ) , null ) ;
89
- }
90
- }
91
-
92
- private static Dictionary < string , string > GetSystemEnvironmentVariables ( )
93
- {
94
- var results = new Dictionary < string , string > ( ) ;
95
-
96
- IntPtr block = Interop . Sys . GetEnviron ( ) ;
97
- if ( block != IntPtr . Zero )
98
- {
99
- try
100
- {
101
- IntPtr blockIterator = block ;
102
-
103
- // Per man page, environment variables come back as an array of pointers to strings
104
- // Parse each pointer of strings individually
105
- while ( ParseEntry ( blockIterator , out string ? key , out string ? value ) )
106
- {
107
- if ( key != null && value != null )
108
- {
109
- try
110
- {
111
- // Add may throw if the environment block was corrupted leading to duplicate entries.
112
- // We allow such throws and eat them (rather than proactively checking for duplication)
113
- // to provide a non-fatal notification about the corruption.
114
- results . Add ( key , value ) ;
115
- }
116
- catch ( ArgumentException ) { }
117
- }
118
-
119
- // Increment to next environment variable entry
120
- blockIterator += IntPtr . Size ;
121
- }
122
- }
123
- finally
124
- {
125
- Interop . Sys . FreeEnviron ( block ) ;
126
- }
127
- }
128
-
129
- return results ;
130
-
131
- // Use a local, unsafe function since we cannot use `yield return` inside of an `unsafe` block
132
- static unsafe bool ParseEntry ( IntPtr current , out string ? key , out string ? value )
133
- {
134
- // Setup
135
- key = null ;
136
- value = null ;
137
-
138
- // Point to current entry
139
- byte * entry = * ( byte * * ) current ;
140
-
141
- // Per man page, "The last pointer in this array has the value NULL"
142
- // Therefore, if entry is null then we're at the end and can bail
143
- if ( entry == null )
144
- return false ;
145
-
146
- // Parse each byte of the entry until we hit either the separator '=' or '\0'.
147
- // This finds the split point for creating key/value strings below.
148
- // On some old OS, the environment block can be corrupted.
149
- // Some will not have '=', so we need to check for '\0'.
150
- byte * splitpoint = entry ;
151
- while ( * splitpoint != '=' && * splitpoint != '\0 ' )
152
- splitpoint ++ ;
153
-
154
- // Skip over entries starting with '=' and entries with no value (just a null-terminating char '\0')
155
- if ( splitpoint == entry || * splitpoint == '\0 ' )
156
- return true ;
157
-
158
- // The key is the bytes from start (0) until our splitpoint
159
- key = new string ( ( sbyte * ) entry , 0 , checked ( ( int ) ( splitpoint - entry ) ) ) ;
160
- // The value is the rest of the bytes starting after the splitpoint
161
- value = new string ( ( sbyte * ) ( splitpoint + 1 ) ) ;
162
-
163
- return true ;
164
- }
165
- }
14
+ public static long TickCount64 => ( long ) RuntimeImports . RhpGetTickCount64 ( ) ;
166
15
167
16
[ DoesNotReturn ]
168
17
private static void ExitRaw ( ) => Interop . Sys . Exit ( s_latchedExitCode ) ;
169
-
170
- public static long TickCount64 => ( long ) RuntimeImports . RhpGetTickCount64 ( ) ;
171
18
}
172
19
}
0 commit comments