1010
1111use os:: unix:: prelude:: * ;
1212
13- use collections:: hash_map:: { HashMap , Entry } ;
14- use env;
1513use ffi:: { OsString , OsStr , CString , CStr } ;
1614use fmt;
1715use io;
@@ -20,6 +18,8 @@ use ptr;
2018use sys:: fd:: FileDesc ;
2119use sys:: fs:: { File , OpenOptions } ;
2220use sys:: pipe:: { self , AnonPipe } ;
21+ use sys_common:: process:: { CommandEnv , DefaultEnvKey } ;
22+ use collections:: BTreeMap ;
2323
2424////////////////////////////////////////////////////////////////////////////////
2525// Command
@@ -45,9 +45,8 @@ pub struct Command {
4545 // other keys.
4646 program : CString ,
4747 args : Vec < CString > ,
48- env : Option < HashMap < OsString , ( usize , CString ) > > ,
4948 argv : Vec < * const c_char > ,
50- envp : Option < Vec < * const c_char > > ,
49+ env : CommandEnv < DefaultEnvKey > ,
5150
5251 cwd : Option < CString > ,
5352 uid : Option < uid_t > ,
@@ -96,8 +95,7 @@ impl Command {
9695 argv : vec ! [ program. as_ptr( ) , ptr:: null( ) ] ,
9796 program,
9897 args : Vec :: new ( ) ,
99- env : None ,
100- envp : None ,
98+ env : Default :: default ( ) ,
10199 cwd : None ,
102100 uid : None ,
103101 gid : None ,
@@ -121,68 +119,6 @@ impl Command {
121119 self . args . push ( arg) ;
122120 }
123121
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-
186122 pub fn cwd ( & mut self , dir : & OsStr ) {
187123 self . cwd = Some ( os2c ( dir, & mut self . saw_nul ) ) ;
188124 }
@@ -196,9 +132,6 @@ impl Command {
196132 pub fn saw_nul ( & self ) -> bool {
197133 self . saw_nul
198134 }
199- pub fn get_envp ( & self ) -> & Option < Vec < * const c_char > > {
200- & self . envp
201- }
202135 pub fn get_argv ( & self ) -> & Vec < * const c_char > {
203136 & self . argv
204137 }
@@ -237,6 +170,15 @@ impl Command {
237170 self . stderr = Some ( stderr) ;
238171 }
239172
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+
240182 pub fn setup_io ( & self , default : Stdio , needs_stdin : bool )
241183 -> io:: Result < ( StdioPipes , ChildPipes ) > {
242184 let null = Stdio :: Null ;
@@ -268,6 +210,53 @@ fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
268210 } )
269211}
270212
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+
271260impl Stdio {
272261 pub fn to_child_stdio ( & self , readable : bool )
273262 -> io:: Result < ( ChildStdio , Option < AnonPipe > ) > {
@@ -337,18 +326,6 @@ impl ChildStdio {
337326 }
338327}
339328
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-
352329impl fmt:: Debug for Command {
353330 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
354331 write ! ( f, "{:?}" , self . program) ?;
0 commit comments