diff --git a/src/main.rs b/src/main.rs index 7b8613f8..27c1d92f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -464,8 +464,28 @@ fn exit_if_nested_disabled(config: &config::Config) { } } +fn args_as_utf8(args: I) -> Result, String> +where + I: IntoIterator, +{ + args.into_iter() + .enumerate() + .map(|(index, arg)| { + arg.into_string() + .map_err(|_| format!("argument {index} is not valid UTF-8")) + }) + .collect() +} + fn main() -> io::Result<()> { - let raw_args: Vec = std::env::args().collect(); + let raw_args: Vec = match args_as_utf8(std::env::args_os()) { + Ok(args) => args, + Err(err) => { + eprintln!("error: {err}"); + eprintln!("run 'herdr --help' for usage"); + std::process::exit(2); + } + }; let args = match session::configure_from_args(&raw_args) { Ok(args) => args, Err(err) => { @@ -905,4 +925,38 @@ mod tests { .iter() .all(|message| !message.starts_with("herdr:"))); } + + #[cfg(unix)] + fn invalid_utf8_arg() -> std::ffi::OsString { + use std::os::unix::ffi::OsStringExt; + std::ffi::OsString::from_vec(vec![0xff]) + } + + #[cfg(windows)] + fn invalid_utf8_arg() -> std::ffi::OsString { + use std::os::windows::ffi::OsStringExt; + std::ffi::OsString::from_wide(&[0xd800]) + } + + #[test] + fn args_as_utf8_passes_through_valid_arguments() { + let args = ["herdr", "pane", "get", "pane-1"].map(std::ffi::OsString::from); + assert_eq!( + args_as_utf8(args).unwrap(), + ["herdr", "pane", "get", "pane-1"] + ); + } + + #[test] + fn args_as_utf8_reports_the_offending_argument_instead_of_panicking() { + let args = vec![ + std::ffi::OsString::from("herdr"), + std::ffi::OsString::from("pane"), + invalid_utf8_arg(), + ]; + assert_eq!( + args_as_utf8(args).unwrap_err(), + "argument 2 is not valid UTF-8" + ); + } }