10
10
11
11
use os:: unix:: prelude:: * ;
12
12
13
- use collections:: hash_map:: { HashMap , Entry } ;
14
- use env;
15
13
use ffi:: { OsString , OsStr , CString , CStr } ;
16
14
use fmt;
17
15
use io;
@@ -20,6 +18,8 @@ use ptr;
20
18
use sys:: fd:: FileDesc ;
21
19
use sys:: fs:: { File , OpenOptions } ;
22
20
use sys:: pipe:: { self , AnonPipe } ;
21
+ use sys_common:: process:: { CommandEnv , DefaultEnvKey } ;
22
+ use collections:: BTreeMap ;
23
23
24
24
////////////////////////////////////////////////////////////////////////////////
25
25
// Command
@@ -45,9 +45,8 @@ pub struct Command {
45
45
// other keys.
46
46
program : CString ,
47
47
args : Vec < CString > ,
48
- env : Option < HashMap < OsString , ( usize , CString ) > > ,
49
48
argv : Vec < * const c_char > ,
50
- envp : Option < Vec < * const c_char > > ,
49
+ env : CommandEnv < DefaultEnvKey > ,
51
50
52
51
cwd : Option < CString > ,
53
52
uid : Option < uid_t > ,
@@ -96,8 +95,7 @@ impl Command {
96
95
argv : vec ! [ program. as_ptr( ) , ptr:: null( ) ] ,
97
96
program,
98
97
args : Vec :: new ( ) ,
99
- env : None ,
100
- envp : None ,
98
+ env : Default :: default ( ) ,
101
99
cwd : None ,
102
100
uid : None ,
103
101
gid : None ,
@@ -121,68 +119,6 @@ impl Command {
121
119
self . args . push ( arg) ;
122
120
}
123
121
124
- fn init_env_map ( & mut self ) -> ( & mut HashMap < OsString , ( usize , CString ) > ,
125
- & mut Vec < * const c_char > ) {
126
- if self . env . is_none ( ) {
127
- let mut map = HashMap :: new ( ) ;
128
- let mut envp = Vec :: new ( ) ;
129
- for ( k, v) in env:: vars_os ( ) {
130
- let s = pair_to_key ( & k, & v, & mut self . saw_nul ) ;
131
- envp. push ( s. as_ptr ( ) ) ;
132
- map. insert ( k, ( envp. len ( ) - 1 , s) ) ;
133
- }
134
- envp. push ( ptr:: null ( ) ) ;
135
- self . env = Some ( map) ;
136
- self . envp = Some ( envp) ;
137
- }
138
- ( self . env . as_mut ( ) . unwrap ( ) , self . envp . as_mut ( ) . unwrap ( ) )
139
- }
140
-
141
- pub fn env ( & mut self , key : & OsStr , val : & OsStr ) {
142
- let new_key = pair_to_key ( key, val, & mut self . saw_nul ) ;
143
- let ( map, envp) = self . init_env_map ( ) ;
144
-
145
- // If `key` is already present then we just update `envp` in place
146
- // (and store the owned value), but if it's not there we override the
147
- // trailing NULL pointer, add a new NULL pointer, and store where we
148
- // were located.
149
- match map. entry ( key. to_owned ( ) ) {
150
- Entry :: Occupied ( mut e) => {
151
- let ( i, ref mut s) = * e. get_mut ( ) ;
152
- envp[ i] = new_key. as_ptr ( ) ;
153
- * s = new_key;
154
- }
155
- Entry :: Vacant ( e) => {
156
- let len = envp. len ( ) ;
157
- envp[ len - 1 ] = new_key. as_ptr ( ) ;
158
- envp. push ( ptr:: null ( ) ) ;
159
- e. insert ( ( len - 1 , new_key) ) ;
160
- }
161
- }
162
- }
163
-
164
- pub fn env_remove ( & mut self , key : & OsStr ) {
165
- let ( map, envp) = self . init_env_map ( ) ;
166
-
167
- // If we actually ended up removing a key, then we need to update the
168
- // position of all keys that come after us in `envp` because they're all
169
- // one element sooner now.
170
- if let Some ( ( i, _) ) = map. remove ( key) {
171
- envp. remove ( i) ;
172
-
173
- for ( _, & mut ( ref mut j, _) ) in map. iter_mut ( ) {
174
- if * j >= i {
175
- * j -= 1 ;
176
- }
177
- }
178
- }
179
- }
180
-
181
- pub fn env_clear ( & mut self ) {
182
- self . env = Some ( HashMap :: new ( ) ) ;
183
- self . envp = Some ( vec ! [ ptr:: null( ) ] ) ;
184
- }
185
-
186
122
pub fn cwd ( & mut self , dir : & OsStr ) {
187
123
self . cwd = Some ( os2c ( dir, & mut self . saw_nul ) ) ;
188
124
}
@@ -196,9 +132,6 @@ impl Command {
196
132
pub fn saw_nul ( & self ) -> bool {
197
133
self . saw_nul
198
134
}
199
- pub fn get_envp ( & self ) -> & Option < Vec < * const c_char > > {
200
- & self . envp
201
- }
202
135
pub fn get_argv ( & self ) -> & Vec < * const c_char > {
203
136
& self . argv
204
137
}
@@ -237,6 +170,15 @@ impl Command {
237
170
self . stderr = Some ( stderr) ;
238
171
}
239
172
173
+ pub fn env_mut ( & mut self ) -> & mut CommandEnv < DefaultEnvKey > {
174
+ & mut self . env
175
+ }
176
+
177
+ pub fn capture_env ( & mut self ) -> Option < CStringArray > {
178
+ let maybe_env = self . env . capture_if_changed ( ) ;
179
+ maybe_env. map ( |env| construct_envp ( env, & mut self . saw_nul ) )
180
+ }
181
+
240
182
pub fn setup_io ( & self , default : Stdio , needs_stdin : bool )
241
183
-> io:: Result < ( StdioPipes , ChildPipes ) > {
242
184
let null = Stdio :: Null ;
@@ -268,6 +210,53 @@ fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
268
210
} )
269
211
}
270
212
213
+ // Helper type to manage ownership of the strings within a C-style array.
214
+ pub struct CStringArray {
215
+ items : Vec < CString > ,
216
+ ptrs : Vec < * const c_char >
217
+ }
218
+
219
+ impl CStringArray {
220
+ pub fn with_capacity ( capacity : usize ) -> Self {
221
+ let mut result = CStringArray {
222
+ items : Vec :: with_capacity ( capacity) ,
223
+ ptrs : Vec :: with_capacity ( capacity+1 )
224
+ } ;
225
+ result. ptrs . push ( ptr:: null ( ) ) ;
226
+ result
227
+ }
228
+ pub fn push ( & mut self , item : CString ) {
229
+ let l = self . ptrs . len ( ) ;
230
+ self . ptrs [ l-1 ] = item. as_ptr ( ) ;
231
+ self . ptrs . push ( ptr:: null ( ) ) ;
232
+ self . items . push ( item) ;
233
+ }
234
+ pub fn as_ptr ( & self ) -> * const * const c_char {
235
+ self . ptrs . as_ptr ( )
236
+ }
237
+ }
238
+
239
+ fn construct_envp ( env : BTreeMap < DefaultEnvKey , OsString > , saw_nul : & mut bool ) -> CStringArray {
240
+ let mut result = CStringArray :: with_capacity ( env. len ( ) ) ;
241
+ for ( k, v) in env {
242
+ let mut k: OsString = k. into ( ) ;
243
+
244
+ // Reserve additional space for '=' and null terminator
245
+ k. reserve_exact ( v. len ( ) + 2 ) ;
246
+ k. push ( "=" ) ;
247
+ k. push ( & v) ;
248
+
249
+ // Add the new entry into the array
250
+ if let Ok ( item) = CString :: new ( k. into_vec ( ) ) {
251
+ result. push ( item) ;
252
+ } else {
253
+ * saw_nul = true ;
254
+ }
255
+ }
256
+
257
+ result
258
+ }
259
+
271
260
impl Stdio {
272
261
pub fn to_child_stdio ( & self , readable : bool )
273
262
-> io:: Result < ( ChildStdio , Option < AnonPipe > ) > {
@@ -337,18 +326,6 @@ impl ChildStdio {
337
326
}
338
327
}
339
328
340
- fn pair_to_key ( key : & OsStr , value : & OsStr , saw_nul : & mut bool ) -> CString {
341
- let ( key, value) = ( key. as_bytes ( ) , value. as_bytes ( ) ) ;
342
- let mut v = Vec :: with_capacity ( key. len ( ) + value. len ( ) + 1 ) ;
343
- v. extend ( key) ;
344
- v. push ( b'=' ) ;
345
- v. extend ( value) ;
346
- CString :: new ( v) . unwrap_or_else ( |_e| {
347
- * saw_nul = true ;
348
- CString :: new ( "foo=bar" ) . unwrap ( )
349
- } )
350
- }
351
-
352
329
impl fmt:: Debug for Command {
353
330
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
354
331
write ! ( f, "{:?}" , self . program) ?;
0 commit comments