@@ -67,26 +67,68 @@ public enum ProcessEnv {
67
67
/// Returns a dictionary containing the current environment.
68
68
public static var block : ProcessEnvironmentBlock { _vars }
69
69
70
+ #if os(Windows)
71
+ private static var _vars : ProcessEnvironmentBlock = {
72
+ guard let lpwchEnvironment = GetEnvironmentStringsW ( ) else { return [ : ] }
73
+ defer { FreeEnvironmentStringsW ( lpwchEnvironment) }
74
+ var environment : ProcessEnvironmentBlock = [ : ]
75
+ var pVariable = UnsafePointer < WCHAR > ( lpwchEnvironment)
76
+ while let entry = String . decodeCString ( pVariable, as: UTF16 . self) {
77
+ if entry. result. isEmpty { break }
78
+ let parts = entry. result. split ( separator: " = " , maxSplits: 1 , omittingEmptySubsequences: false )
79
+ if parts. count == 2 {
80
+ environment [ CaseInsensitiveString ( String ( parts [ 0 ] ) ) ] = String ( parts [ 1 ] )
81
+ }
82
+ pVariable = pVariable. advanced ( by: entry. result. utf16. count + 1 )
83
+ }
84
+ return environment
85
+ } ( )
86
+ #else
70
87
private static var _vars = ProcessEnvironmentBlock (
71
88
uniqueKeysWithValues: ProcessInfo . processInfo. environment. map {
72
89
( ProcessEnvironmentBlock . Key ( $0. key) , $0. value)
73
90
}
74
91
)
92
+ #endif
75
93
76
94
/// Invalidate the cached env.
77
95
public static func invalidateEnv( ) {
96
+ #if os(Windows)
97
+ guard let lpwchEnvironment = GetEnvironmentStringsW ( ) else {
98
+ _vars = [ : ]
99
+ return
100
+ }
101
+ defer { FreeEnvironmentStringsW ( lpwchEnvironment) }
102
+
103
+ var environment : ProcessEnvironmentBlock = [ : ]
104
+ var pVariable = UnsafePointer < WCHAR > ( lpwchEnvironment)
105
+ while let entry = String . decodeCString ( pVariable, as: UTF16 . self) {
106
+ if entry. result. isEmpty { break }
107
+ let parts = entry. result. split ( separator: " = " , maxSplits: 1 , omittingEmptySubsequences: false )
108
+ if parts. count == 2 {
109
+ environment [ CaseInsensitiveString ( String ( parts [ 0 ] ) ) ] = String ( parts [ 1 ] )
110
+ }
111
+ pVariable = pVariable. advanced ( by: entry. result. utf16. count + 1 )
112
+ }
113
+ _vars = environment
114
+ #else
78
115
_vars = ProcessEnvironmentBlock (
79
116
uniqueKeysWithValues: ProcessInfo . processInfo. environment. map {
80
117
( CaseInsensitiveString ( $0. key) , $0. value)
81
118
}
82
119
)
120
+ #endif
83
121
}
84
122
85
123
/// Set the given key and value in the process's environment.
86
124
public static func setVar( _ key: String , value: String ) throws {
87
125
#if os(Windows)
88
- guard TSCLibc . _putenv ( " \( key) = \( value) " ) == 0 else {
89
- throw SystemError . setenv ( Int32 ( GetLastError ( ) ) , key)
126
+ try key. withCString ( encodedAs: UTF16 . self) { pwszKey in
127
+ try value. withCString ( encodedAs: UTF16 . self) { pwszValue in
128
+ guard SetEnvironmentVariableW ( pwszKey, pwszValue) else {
129
+ throw SystemError . setenv ( Int32 ( GetLastError ( ) ) , key)
130
+ }
131
+ }
90
132
}
91
133
#else
92
134
guard TSCLibc . setenv ( key, value, 1 ) == 0 else {
@@ -99,7 +141,9 @@ public enum ProcessEnv {
99
141
/// Unset the give key in the process's environment.
100
142
public static func unsetVar( _ key: String ) throws {
101
143
#if os(Windows)
102
- guard TSCLibc . _putenv ( " \( key) = " ) == 0 else {
144
+ guard key. withCString ( encodedAs: UTF16 . self, {
145
+ SetEnvironmentVariableW ( $0, nil )
146
+ } ) else {
103
147
throw SystemError . unsetenv ( Int32 ( GetLastError ( ) ) , key)
104
148
}
105
149
#else
@@ -124,9 +168,7 @@ public enum ProcessEnv {
124
168
public static func chdir( _ path: AbsolutePath ) throws {
125
169
let path = path. pathString
126
170
#if os(Windows)
127
- guard path. withCString ( encodedAs: UTF16 . self, {
128
- SetCurrentDirectoryW ( $0)
129
- } ) else {
171
+ guard path. withCString ( encodedAs: UTF16 . self, SetCurrentDirectoryW) else {
130
172
throw SystemError . chdir ( Int32 ( GetLastError ( ) ) , path)
131
173
}
132
174
#else
0 commit comments