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