From cb0ce0e1cbb248399c967c71d8859f29d94c6c13 Mon Sep 17 00:00:00 2001 From: wolimst <64784258+wolimst@users.noreply.github.com> Date: Fri, 9 Feb 2024 15:56:15 +0900 Subject: [PATCH 1/3] cut: show error for multiple mode args (-b, -c, -f) --- src/uu/cut/src/cut.rs | 27 ++++++++++++++++++++------- tests/by-util/test_cut.rs | 18 ++++++++++++++++++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/uu/cut/src/cut.rs b/src/uu/cut/src/cut.rs index f3f87beef..f37716258 100644 --- a/src/uu/cut/src/cut.rs +++ b/src/uu/cut/src/cut.rs @@ -359,12 +359,22 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let complement = matches.get_flag(options::COMPLEMENT); + let mode_args_count = [ + matches.indices_of(options::BYTES), + matches.indices_of(options::CHARACTERS), + matches.indices_of(options::FIELDS), + ] + .into_iter() + .filter_map(|mode| mode.map(|indices| indices.len())) + .sum(); + let mode_parse = match ( + mode_args_count, matches.get_one::(options::BYTES), matches.get_one::(options::CHARACTERS), matches.get_one::(options::FIELDS), ) { - (Some(byte_ranges), None, None) => list_to_ranges(byte_ranges, complement).map(|ranges| { + (1, Some(byte_ranges), None, None) => list_to_ranges(byte_ranges, complement).map(|ranges| { Mode::Bytes( ranges, Options { @@ -379,7 +389,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }, ) }), - (None, Some(char_ranges), None) => list_to_ranges(char_ranges, complement).map(|ranges| { + (1, None, Some(char_ranges), None) => list_to_ranges(char_ranges, complement).map(|ranges| { Mode::Characters( ranges, Options { @@ -394,7 +404,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }, ) }), - (None, None, Some(field_ranges)) => { + (1, None, None, Some(field_ranges)) => { list_to_ranges(field_ranges, complement).and_then(|ranges| { let out_delim = match matches.get_one::(options::OUTPUT_DELIMITER) { Some(s) => { @@ -461,7 +471,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } }) } - (ref b, ref c, ref f) if b.is_some() || c.is_some() || f.is_some() => Err( + (2.., _, _, _) => Err( "invalid usage: expects no more than one of --fields (-f), --chars (-c) or --bytes (-b)".into() ), _ => Err("invalid usage: expects one of --fields (-f), --chars (-c) or --bytes (-b)".into()), @@ -518,7 +528,8 @@ pub fn uu_app() -> Command { .long(options::BYTES) .help("filter byte columns from the input source") .allow_hyphen_values(true) - .value_name("LIST"), + .value_name("LIST") + .action(ArgAction::Append), ) .arg( Arg::new(options::CHARACTERS) @@ -526,7 +537,8 @@ pub fn uu_app() -> Command { .long(options::CHARACTERS) .help("alias for character mode") .allow_hyphen_values(true) - .value_name("LIST"), + .value_name("LIST") + .action(ArgAction::Append), ) .arg( Arg::new(options::DELIMITER) @@ -548,7 +560,8 @@ pub fn uu_app() -> Command { .long(options::FIELDS) .help("filter field columns from the input source") .allow_hyphen_values(true) - .value_name("LIST"), + .value_name("LIST") + .action(ArgAction::Append), ) .arg( Arg::new(options::COMPLEMENT) diff --git a/tests/by-util/test_cut.rs b/tests/by-util/test_cut.rs index bfa0885ce..2473ead19 100644 --- a/tests/by-util/test_cut.rs +++ b/tests/by-util/test_cut.rs @@ -270,3 +270,21 @@ fn test_multiple() { assert_eq!(result.stdout_str(), "b\n"); assert_eq!(result.stderr_str(), ""); } + +#[test] +fn test_multiple_mode_args() { + for args in [ + vec!["-b1", "-b2"], + vec!["-c1", "-c2"], + vec!["-f1", "-f2"], + vec!["-b1", "-c2"], + vec!["-b1", "-f2"], + vec!["-c1", "-f2"], + vec!["-b1", "-c2", "-f3"], + ] { + new_ucmd!() + .args(&args) + .fails() + .stderr_is("cut: invalid usage: expects no more than one of --fields (-f), --chars (-c) or --bytes (-b)\n"); + } +} From 0ac860657707a42b30450ce499e562209710a833 Mon Sep 17 00:00:00 2001 From: wolimst <64784258+wolimst@users.noreply.github.com> Date: Fri, 9 Feb 2024 22:15:18 +0900 Subject: [PATCH 2/3] cut: add comments about handling multiple cutting mode args --- src/uu/cut/src/cut.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/uu/cut/src/cut.rs b/src/uu/cut/src/cut.rs index f37716258..cf94a1bd0 100644 --- a/src/uu/cut/src/cut.rs +++ b/src/uu/cut/src/cut.rs @@ -359,6 +359,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let complement = matches.get_flag(options::COMPLEMENT); + // Only one, and only one of cutting mode arguments, i.e. `-b`, `-c`, `-f`, + // is expected. The number of those arguments is used for parsing a cutting + // mode and handling the error cases. let mode_args_count = [ matches.indices_of(options::BYTES), matches.indices_of(options::CHARACTERS), @@ -521,6 +524,13 @@ pub fn uu_app() -> Command { .about(ABOUT) .after_help(AFTER_HELP) .infer_long_args(true) + // While `args_override_self(true)` for some arguments, such as `-d` + // and `--output-delimiter`, is consistent to the behavior of GNU cut, + // arguments related to cutting mode, i.e. `-b`, `-c`, `-f`, should + // cause an error when there is more than one of them, as described in + // the manual of GNU cut: "Use one, and only one of -b, -c or -f". + // `ArgAction::Append` is used on `-b`, `-c`, `-f` arguments, so that + // the occurrences of those could be counted and be handled accordingly. .args_override_self(true) .arg( Arg::new(options::BYTES) From 6bec96aad1c6ae606f2c1c05bda51904cd88f5eb Mon Sep 17 00:00:00 2001 From: wolimst <64784258+wolimst@users.noreply.github.com> Date: Wed, 14 Feb 2024 20:02:42 +0900 Subject: [PATCH 3/3] cut: refactor mode args counting by removing nested map --- src/uu/cut/src/cut.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/cut/src/cut.rs b/src/uu/cut/src/cut.rs index cf94a1bd0..e89568716 100644 --- a/src/uu/cut/src/cut.rs +++ b/src/uu/cut/src/cut.rs @@ -368,7 +368,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { matches.indices_of(options::FIELDS), ] .into_iter() - .filter_map(|mode| mode.map(|indices| indices.len())) + .map(|indices| indices.unwrap_or_default().count()) .sum(); let mode_parse = match (