@@ -6,7 +6,7 @@ use std::{
6
6
ffi:: { OsStr , OsString } ,
7
7
fs:: { File , OpenOptions } ,
8
8
io:: { self , Write } ,
9
- os:: unix:: prelude:: { FromRawFd , OsStrExt , ExitStatusExt , IntoRawFd } ,
9
+ os:: unix:: { prelude:: { FromRawFd , OsStrExt , ExitStatusExt , IntoRawFd } , process :: CommandExt } ,
10
10
process,
11
11
} ;
12
12
@@ -152,6 +152,9 @@ pub enum Redirection {
152
152
pub enum Builtin {
153
153
Alias ,
154
154
Cd ,
155
+ Exec ,
156
+ Exec0 ,
157
+ Spawn0 ,
155
158
}
156
159
157
160
@@ -161,36 +164,76 @@ impl Builtin {
161
164
arguments : Box < [ Argument ] > ,
162
165
pos : SourcePos ,
163
166
) -> Result < Option < ErrorStatus > , Error > {
164
- let mut arguments = arguments. into_vec ( ) ;
167
+ let io_error = |error| Error :: io ( error, pos. copy ( ) ) ;
168
+ let mut args = Self :: resolve_args ( arguments, pos. copy ( ) ) ?;
165
169
166
170
match self {
167
- Builtin :: Alias => todo ! ( ) ,
171
+ Self :: Alias => todo ! ( ) ,
168
172
169
- Builtin :: Cd => {
170
- let arg = arguments
171
- . pop ( )
173
+ Self :: Cd => {
174
+ let dir = args
175
+ . next ( )
172
176
. ok_or_else ( || Panic :: invalid_args ( "argument" , 0 , pos. copy ( ) ) ) ?;
173
177
174
- if !arguments. is_empty ( ) {
178
+ let remaining_args = args. count ( ) ;
179
+ if remaining_args > 0 {
175
180
return Err (
176
- Panic :: invalid_args ( "argument" , arguments . len ( ) as u32 + 1 , pos. copy ( ) ) . into ( )
181
+ Panic :: invalid_args ( "argument" , remaining_args as u32 + 1 , pos. copy ( ) ) . into ( )
177
182
) ;
178
183
}
179
184
180
- let args = arg. resolve ( pos. copy ( ) ) ?;
181
-
182
- match args. as_ref ( ) {
183
- [ dir ] => std:: env:: set_current_dir ( dir. as_ref ( ) )
184
- . map_err ( |error| Error :: io ( error, pos. copy ( ) ) ) ?,
185
- other => return Err (
186
- Panic :: invalid_args ( "argument" , other. len ( ) as u32 , pos) . into ( )
187
- ) ,
188
- } ;
185
+ std:: env:: set_current_dir ( dir. as_ref ( ) ) . map_err ( io_error) ?;
189
186
190
187
Ok ( None )
191
188
}
189
+
190
+ Self :: Exec | Self :: Exec0 | Self :: Spawn0 => {
191
+ let cmd = args
192
+ . next ( )
193
+ . ok_or_else ( || Panic :: invalid_args ( "argument" , 0 , pos. copy ( ) ) ) ?;
194
+
195
+ let mut command = process:: Command :: new ( cmd) ;
196
+
197
+ if matches ! ( self , Self :: Exec0 | Self :: Spawn0 ) {
198
+ let arg0 = args
199
+ . next ( )
200
+ . ok_or_else ( || Panic :: invalid_args ( "arg0" , 0 , pos. copy ( ) ) ) ?;
201
+
202
+ command. arg0 ( arg0) ;
203
+ }
204
+
205
+ for arg in args {
206
+ command. arg ( arg) ;
207
+ }
208
+
209
+ if matches ! ( self , Self :: Spawn0 ) {
210
+ let process = command. spawn ( )
211
+ . map_err ( io_error) ?;
212
+
213
+ Ok ( ErrorStatus :: wait_child ( Child { process, pos } ) )
214
+ } else {
215
+ let error = command. exec ( ) ;
216
+ Err ( io_error ( error) )
217
+ }
218
+ }
192
219
}
193
220
}
221
+
222
+ fn resolve_args (
223
+ arguments : Box < [ Argument ] > ,
224
+ pos : SourcePos ,
225
+ ) -> Result < impl Iterator < Item = Box < OsStr > > , Error > {
226
+ let args = arguments
227
+ . into_vec ( )
228
+ . into_iter ( )
229
+ . map ( |arg| arg. resolve ( pos. copy ( ) ) )
230
+ . collect :: < Result < Vec < _ > , _ > > ( ) ?
231
+ . into_iter ( )
232
+ . map ( <[ _ ] >:: into_vec)
233
+ . flatten ( ) ;
234
+
235
+ Ok ( args)
236
+ }
194
237
}
195
238
196
239
@@ -199,6 +242,9 @@ impl<'a> From<&'a program::command::Builtin> for Builtin {
199
242
match builtin {
200
243
program:: command:: Builtin :: Alias => Self :: Alias ,
201
244
program:: command:: Builtin :: Cd => Self :: Cd ,
245
+ program:: command:: Builtin :: Exec => Self :: Exec ,
246
+ program:: command:: Builtin :: Exec0 => Self :: Exec0 ,
247
+ program:: command:: Builtin :: Spawn0 => Self :: Spawn0 ,
202
248
}
203
249
}
204
250
}
0 commit comments