|
1 | | -use std::error; |
2 | | -use std::fmt; |
3 | | -use std::fs; |
4 | | -use std::io; |
| 1 | +use std::{env, error, fmt, fs, io}; |
5 | 2 |
|
6 | 3 | use rustc_session::EarlyDiagCtxt; |
| 4 | +use rustc_span::ErrorGuaranteed; |
7 | 5 |
|
8 | 6 | /// Expands argfiles in command line arguments. |
9 | 7 | #[derive(Default)] |
@@ -86,41 +84,70 @@ impl Expander { |
86 | 84 | fn read_file(path: &str) -> Result<String, Error> { |
87 | 85 | fs::read_to_string(path).map_err(|e| { |
88 | 86 | if e.kind() == io::ErrorKind::InvalidData { |
89 | | - Error::Utf8Error(Some(path.to_string())) |
| 87 | + Error::Utf8Error(path.to_string()) |
90 | 88 | } else { |
91 | 89 | Error::IOError(path.to_string(), e) |
92 | 90 | } |
93 | 91 | }) |
94 | 92 | } |
95 | 93 | } |
96 | 94 |
|
| 95 | +/// Replaces any `@file` arguments with the contents of `file`, with each line of `file` as a |
| 96 | +/// separate argument. |
| 97 | +/// |
97 | 98 | /// **Note:** This function doesn't interpret argument 0 in any special way. |
98 | 99 | /// If this function is intended to be used with command line arguments, |
99 | 100 | /// `argv[0]` must be removed prior to calling it manually. |
100 | | -pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec<String> { |
| 101 | +pub fn arg_expand_all( |
| 102 | + early_dcx: &EarlyDiagCtxt, |
| 103 | + at_args: &[String], |
| 104 | +) -> Result<Vec<String>, ErrorGuaranteed> { |
101 | 105 | let mut expander = Expander::default(); |
| 106 | + let mut result = Ok(()); |
102 | 107 | for arg in at_args { |
103 | 108 | if let Err(err) = expander.arg(arg) { |
104 | | - early_dcx.early_fatal(format!("Failed to load argument file: {err}")); |
| 109 | + result = Err(early_dcx.early_err(format!("failed to load argument file: {err}"))); |
105 | 110 | } |
106 | 111 | } |
107 | | - expander.finish() |
| 112 | + result.map(|()| expander.finish()) |
| 113 | +} |
| 114 | + |
| 115 | +/// Gets the raw unprocessed command-line arguments as Unicode strings, without doing any further |
| 116 | +/// processing (e.g., without `@file` expansion). |
| 117 | +/// |
| 118 | +/// This function is identical to [`env::args()`] except that it emits an error when it encounters |
| 119 | +/// non-Unicode arguments instead of panicking. |
| 120 | +pub fn raw_args(early_dcx: &EarlyDiagCtxt) -> Result<Vec<String>, ErrorGuaranteed> { |
| 121 | + let mut res = Ok(Vec::new()); |
| 122 | + for (i, arg) in env::args_os().enumerate() { |
| 123 | + match arg.into_string() { |
| 124 | + Ok(arg) => { |
| 125 | + if let Ok(args) = &mut res { |
| 126 | + args.push(arg); |
| 127 | + } |
| 128 | + } |
| 129 | + Err(arg) => { |
| 130 | + res = |
| 131 | + Err(early_dcx.early_err(format!("argument {i} is not valid Unicode: {arg:?}"))) |
| 132 | + } |
| 133 | + } |
| 134 | + } |
| 135 | + res |
108 | 136 | } |
109 | 137 |
|
110 | 138 | #[derive(Debug)] |
111 | | -pub enum Error { |
112 | | - Utf8Error(Option<String>), |
| 139 | +enum Error { |
| 140 | + Utf8Error(String), |
113 | 141 | IOError(String, io::Error), |
114 | 142 | ShellParseError(String), |
115 | 143 | } |
116 | 144 |
|
117 | 145 | impl fmt::Display for Error { |
118 | 146 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
119 | 147 | match self { |
120 | | - Error::Utf8Error(None) => write!(fmt, "Utf8 error"), |
121 | | - Error::Utf8Error(Some(path)) => write!(fmt, "Utf8 error in {path}"), |
122 | | - Error::IOError(path, err) => write!(fmt, "IO Error: {path}: {err}"), |
123 | | - Error::ShellParseError(path) => write!(fmt, "Invalid shell-style arguments in {path}"), |
| 148 | + Error::Utf8Error(path) => write!(fmt, "UTF-8 error in {path}"), |
| 149 | + Error::IOError(path, err) => write!(fmt, "IO error: {path}: {err}"), |
| 150 | + Error::ShellParseError(path) => write!(fmt, "invalid shell-style arguments in {path}"), |
124 | 151 | } |
125 | 152 | } |
126 | 153 | } |
|
0 commit comments