@@ -5,39 +5,91 @@ use std::io;
5
5
6
6
use rustc_session:: EarlyErrorHandler ;
7
7
8
- fn arg_expand ( arg : String ) -> Result < Vec < String > , Error > {
9
- if let Some ( path) = arg. strip_prefix ( '@' ) {
10
- let file = match fs:: read_to_string ( path) {
11
- Ok ( file) => file,
12
- Err ( ref err) if err. kind ( ) == io:: ErrorKind :: InvalidData => {
13
- return Err ( Error :: Utf8Error ( Some ( path. to_string ( ) ) ) ) ;
8
+ #[ derive( Default ) ]
9
+ struct Expander {
10
+ shell_argfiles : bool ,
11
+ next_is_unstable_option : bool ,
12
+ expanded : Vec < String > ,
13
+ }
14
+
15
+ impl Expander {
16
+ fn arg ( & mut self , arg : & str ) -> Result < ( ) , Error > {
17
+ if let Some ( argfile) = arg. strip_prefix ( '@' ) {
18
+ match argfile. split_once ( ':' ) {
19
+ Some ( ( "shell" , path) ) if self . shell_argfiles => {
20
+ shlex:: split ( & Self :: read_file ( path) ?)
21
+ . ok_or_else ( || Error :: ShellParseError ( path. to_string ( ) ) ) ?
22
+ . into_iter ( )
23
+ . for_each ( |arg| self . push ( arg) ) ;
24
+ }
25
+ _ => {
26
+ let contents = Self :: read_file ( argfile) ?;
27
+ contents. lines ( ) . for_each ( |arg| self . push ( arg. to_string ( ) ) ) ;
28
+ }
29
+ }
30
+ } else {
31
+ self . push ( arg. to_string ( ) ) ;
32
+ }
33
+
34
+ Ok ( ( ) )
35
+ }
36
+
37
+ fn push ( & mut self , arg : String ) {
38
+ if self . next_is_unstable_option {
39
+ self . inspect_unstable_option ( & arg) ;
40
+ self . next_is_unstable_option = false ;
41
+ } else if let Some ( unstable_option) = arg. strip_prefix ( "-Z" ) {
42
+ if unstable_option. is_empty ( ) {
43
+ self . next_is_unstable_option = true ;
44
+ } else {
45
+ self . inspect_unstable_option ( unstable_option) ;
46
+ }
47
+ }
48
+
49
+ self . expanded . push ( arg) ;
50
+ }
51
+
52
+ fn finish ( self ) -> Vec < String > {
53
+ self . expanded
54
+ }
55
+
56
+ /// Parses any unstable flags specified on the command line.
57
+ fn inspect_unstable_option ( & mut self , option : & str ) {
58
+ match option {
59
+ "shell-argfiles" => self . shell_argfiles = true ,
60
+ _ => ( ) ,
61
+ }
62
+ }
63
+
64
+ fn read_file ( path : & str ) -> Result < String , Error > {
65
+ fs:: read_to_string ( path) . map_err ( |e| {
66
+ if e. kind ( ) == io:: ErrorKind :: InvalidData {
67
+ Error :: Utf8Error ( Some ( path. to_string ( ) ) )
68
+ } else {
69
+ Error :: IOError ( path. to_string ( ) , e)
14
70
}
15
- Err ( err) => return Err ( Error :: IOError ( path. to_string ( ) , err) ) ,
16
- } ;
17
- Ok ( file. lines ( ) . map ( ToString :: to_string) . collect ( ) )
18
- } else {
19
- Ok ( vec ! [ arg] )
71
+ } )
20
72
}
21
73
}
22
74
23
75
/// **Note:** This function doesn't interpret argument 0 in any special way.
24
76
/// If this function is intended to be used with command line arguments,
25
77
/// `argv[0]` must be removed prior to calling it manually.
26
78
pub fn arg_expand_all ( handler : & EarlyErrorHandler , at_args : & [ String ] ) -> Vec < String > {
27
- let mut args = Vec :: new ( ) ;
79
+ let mut expander = Expander :: default ( ) ;
28
80
for arg in at_args {
29
- match arg_expand ( arg. clone ( ) ) {
30
- Ok ( arg) => args. extend ( arg) ,
31
- Err ( err) => handler. early_error ( format ! ( "Failed to load argument file: {err}" ) ) ,
81
+ if let Err ( err) = expander. arg ( arg) {
82
+ handler. early_error ( format ! ( "Failed to load argument file: {err}" ) ) ;
32
83
}
33
84
}
34
- args
85
+ expander . finish ( )
35
86
}
36
87
37
88
#[ derive( Debug ) ]
38
89
pub enum Error {
39
90
Utf8Error ( Option < String > ) ,
40
91
IOError ( String , io:: Error ) ,
92
+ ShellParseError ( String ) ,
41
93
}
42
94
43
95
impl fmt:: Display for Error {
@@ -46,6 +98,7 @@ impl fmt::Display for Error {
46
98
Error :: Utf8Error ( None ) => write ! ( fmt, "Utf8 error" ) ,
47
99
Error :: Utf8Error ( Some ( path) ) => write ! ( fmt, "Utf8 error in {path}" ) ,
48
100
Error :: IOError ( path, err) => write ! ( fmt, "IO Error: {path}: {err}" ) ,
101
+ Error :: ShellParseError ( path) => write ! ( fmt, "Invalid shell-style arguments in {path}" ) ,
49
102
}
50
103
}
51
104
}
0 commit comments