diff --git a/src/uu/comm/src/comm.rs b/src/uu/comm/src/comm.rs index d6366e4e5..931d0a054 100644 --- a/src/uu/comm/src/comm.rs +++ b/src/uu/comm/src/comm.rs @@ -9,7 +9,7 @@ use std::cmp::Ordering; use std::fs::File; use std::io::{self, stdin, BufRead, BufReader, Stdin}; use std::path::Path; -use uucore::error::{FromIo, UResult}; +use uucore::error::{FromIo, UResult, USimpleError}; use uucore::line_ending::LineEnding; use uucore::{format_usage, help_about, help_usage}; @@ -61,12 +61,7 @@ impl LineReader { } } -fn comm(a: &mut LineReader, b: &mut LineReader, opts: &ArgMatches) { - let delim = match opts.get_one::(options::DELIMITER).unwrap().as_str() { - "" => "\0", - delim => delim, - }; - +fn comm(a: &mut LineReader, b: &mut LineReader, delim: &str, opts: &ArgMatches) { let width_col_1 = usize::from(!opts.get_flag(options::COLUMN_1)); let width_col_2 = usize::from(!opts.get_flag(options::COLUMN_2)); @@ -152,7 +147,28 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let mut f1 = open_file(filename1, line_ending).map_err_context(|| filename1.to_string())?; let mut f2 = open_file(filename2, line_ending).map_err_context(|| filename2.to_string())?; - comm(&mut f1, &mut f2, &matches); + // Due to default_value(), there must be at least one value here, thus unwrap() must not panic. + let all_delimiters = matches + .get_many::(options::DELIMITER) + .unwrap() + .map(String::from) + .collect::>(); + for delim in &all_delimiters[1..] { + // Note that this check is very different from ".conflicts_with_self(true).action(ArgAction::Set)", + // as this accepts duplicate *identical* arguments. + if delim != &all_delimiters[0] { + // Note: This intentionally deviate from the GNU error message by inserting the word "conflicting". + return Err(USimpleError::new( + 1, + "comm: multiple conflicting output delimiters specified", + )); + } + } + let delim = match &*all_delimiters[0] { + "" => "\0", + delim => delim, + }; + comm(&mut f1, &mut f2, delim, &matches); Ok(()) } @@ -187,6 +203,7 @@ pub fn uu_app() -> Command { .value_name("STR") .default_value(options::DELIMITER_DEFAULT) .allow_hyphen_values(true) + .action(ArgAction::Append) .hide_default_value(true), ) .arg( diff --git a/tests/by-util/test_comm.rs b/tests/by-util/test_comm.rs index f6608c7eb..ce3814eac 100644 --- a/tests/by-util/test_comm.rs +++ b/tests/by-util/test_comm.rs @@ -107,6 +107,53 @@ fn output_delimiter_hyphen_help() { .stdout_only_fixture("ab_delimiter_hyphen_help.expected"); } +#[test] +fn output_delimiter_multiple_identical() { + new_ucmd!() + .args(&[ + "--output-delimiter=word", + "--output-delimiter=word", + "a", + "b", + ]) + .succeeds() + .stdout_only_fixture("ab_delimiter_word.expected"); +} + +#[test] +fn output_delimiter_multiple_different() { + new_ucmd!() + .args(&[ + "--output-delimiter=word", + "--output-delimiter=other", + "a", + "b", + ]) + .fails() + .no_stdout() + .stderr_contains("multiple") + .stderr_contains("output") + .stderr_contains("delimiters"); +} + +#[test] +#[ignore = "This is too weird; deviate intentionally."] +fn output_delimiter_multiple_different_prevents_help() { + new_ucmd!() + .args(&[ + "--output-delimiter=word", + "--output-delimiter=other", + "--help", + "a", + "b", + ]) + .fails() + .no_stdout() + .stderr_contains("multiple") + .stderr_contains("output") + .stderr_contains("delimiters"); +} + #[test] fn output_delimiter_nul() { new_ucmd!()