diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index 9d9b426b7..c0269c705 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -989,6 +989,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::INFILE) .long(options::INFILE) + .overrides_with(options::INFILE) .takes_value(true) .require_equals(true) .value_name("FILE") @@ -997,6 +998,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::OUTFILE) .long(options::OUTFILE) + .overrides_with(options::OUTFILE) .takes_value(true) .require_equals(true) .value_name("FILE") @@ -1005,6 +1007,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::IBS) .long(options::IBS) + .overrides_with(options::IBS) .takes_value(true) .require_equals(true) .value_name("N") @@ -1013,6 +1016,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::OBS) .long(options::OBS) + .overrides_with(options::OBS) .takes_value(true) .require_equals(true) .value_name("N") @@ -1021,6 +1025,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::BS) .long(options::BS) + .overrides_with(options::BS) .takes_value(true) .require_equals(true) .value_name("N") @@ -1029,6 +1034,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::CBS) .long(options::CBS) + .overrides_with(options::CBS) .takes_value(true) .require_equals(true) .value_name("N") @@ -1037,6 +1043,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::SKIP) .long(options::SKIP) + .overrides_with(options::SKIP) .takes_value(true) .require_equals(true) .value_name("N") @@ -1045,6 +1052,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::SEEK) .long(options::SEEK) + .overrides_with(options::SEEK) .takes_value(true) .require_equals(true) .value_name("N") @@ -1053,6 +1061,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::COUNT) .long(options::COUNT) + .overrides_with(options::COUNT) .takes_value(true) .require_equals(true) .value_name("N") @@ -1061,6 +1070,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::STATUS) .long(options::STATUS) + .overrides_with(options::STATUS) .takes_value(true) .require_equals(true) .value_name("LEVEL") @@ -1086,6 +1096,10 @@ Printing performance stats is also triggered by the INFO signal (where supported Arg::new(options::CONV) .long(options::CONV) .takes_value(true) + .multiple_occurrences(true) + .use_delimiter(true) + .require_delimiter(true) + .multiple_values(true) .require_equals(true) .value_name("CONV") .help("(alternatively conv=CONV[,CONV]) specifies a comma-separated list of conversion options or (for legacy reasons) file flags. Conversion options and file flags may be intermixed. @@ -1123,6 +1137,10 @@ Conversion Flags: Arg::new(options::IFLAG) .long(options::IFLAG) .takes_value(true) + .multiple_occurrences(true) + .use_delimiter(true) + .require_delimiter(true) + .multiple_values(true) .require_equals(true) .value_name("FLAG") .help("(alternatively iflag=FLAG[,FLAG]) a comma separated list of input flags which specify how the input source is treated. FLAG may be any of the input-flags or general-flags specified below. @@ -1149,6 +1167,10 @@ General-Flags Arg::new(options::OFLAG) .long(options::OFLAG) .takes_value(true) + .multiple_occurrences(true) + .use_delimiter(true) + .require_delimiter(true) + .multiple_values(true) .require_equals(true) .value_name("FLAG") .help("(alternatively oflag=FLAG[,FLAG]) a comma separated list of output flags which specify how the output source is treated. FLAG may be any of the output-flags or general-flags specified below. diff --git a/src/uu/dd/src/parseargs.rs b/src/uu/dd/src/parseargs.rs index 6bc7bcfd9..1425cae01 100644 --- a/src/uu/dd/src/parseargs.rs +++ b/src/uu/dd/src/parseargs.rs @@ -490,16 +490,11 @@ fn parse_flag_list>( tag: &str, matches: &Matches, ) -> Result, ParseError> { - let mut flags = Vec::new(); - - if let Some(comma_str) = matches.value_of(tag) { - for s in comma_str.split(',') { - let flag = s.parse()?; - flags.push(flag); - } - } - - Ok(flags) + matches + .values_of(tag) + .unwrap_or_default() + .map(|f| f.parse()) + .collect() } /// Parse Conversion Options (Input Variety) diff --git a/src/uu/dd/src/parseargs/unit_tests.rs b/src/uu/dd/src/parseargs/unit_tests.rs index a72944309..1e5b4b930 100644 --- a/src/uu/dd/src/parseargs/unit_tests.rs +++ b/src/uu/dd/src/parseargs/unit_tests.rs @@ -299,6 +299,116 @@ fn test_status_level_noxfer() { assert_eq!(st, StatusLevel::Noxfer); } +#[test] +fn test_multiple_flags_options() { + let args = vec![ + String::from("dd"), + String::from("--iflag=fullblock,directory"), + String::from("--iflag=skip_bytes"), + String::from("--oflag=direct"), + String::from("--oflag=dsync"), + String::from("--conv=ascii,ucase"), + String::from("--conv=unblock"), + ]; + let matches = uu_app().try_get_matches_from(args).unwrap(); + + // iflag + let iflags = parse_flag_list::(options::IFLAG, &matches).unwrap(); + assert_eq!( + vec![Flag::FullBlock, Flag::Directory, Flag::SkipBytes], + iflags + ); + + // oflag + let oflags = parse_flag_list::(options::OFLAG, &matches).unwrap(); + assert_eq!(vec![Flag::Direct, Flag::Dsync], oflags); + + // conv + let conv = parse_flag_list::(options::CONV, &matches).unwrap(); + assert_eq!( + vec![ConvFlag::FmtEtoA, ConvFlag::UCase, ConvFlag::Unblock], + conv + ); +} + +#[test] +fn test_override_multiple_options() { + let args = vec![ + String::from("dd"), + String::from("--if=foo.file"), + String::from("--if=correct.file"), + String::from("--of=bar.file"), + String::from("--of=correct.file"), + String::from("--ibs=256"), + String::from("--ibs=1024"), + String::from("--obs=256"), + String::from("--obs=1024"), + String::from("--cbs=1"), + String::from("--cbs=2"), + String::from("--skip=0"), + String::from("--skip=2"), + String::from("--seek=0"), + String::from("--seek=2"), + String::from("--status=none"), + String::from("--status=noxfer"), + String::from("--count=512"), + String::from("--count=1024"), + ]; + + let matches = uu_app().try_get_matches_from(args).unwrap(); + + // if + assert_eq!("correct.file", matches.value_of(options::INFILE).unwrap()); + + // of + assert_eq!("correct.file", matches.value_of(options::OUTFILE).unwrap()); + + // ibs + assert_eq!(1024, parse_ibs(&matches).unwrap()); + + // obs + assert_eq!(1024, parse_obs(&matches).unwrap()); + + // cbs + assert_eq!(2, parse_cbs(&matches).unwrap().unwrap()); + + // status + assert_eq!( + StatusLevel::Noxfer, + parse_status_level(&matches).unwrap().unwrap() + ); + + // skip + assert_eq!( + 200, + parse_skip_amt(&100, &IFlags::default(), &matches) + .unwrap() + .unwrap() + ); + + // seek + assert_eq!( + 200, + parse_seek_amt(&100, &OFlags::default(), &matches) + .unwrap() + .unwrap() + ); + + // count + assert_eq!( + CountType::Bytes(1024), + parse_count( + &IFlags { + count_bytes: true, + ..IFlags::default() + }, + &matches + ) + .unwrap() + .unwrap() + ); +} + // ----- IConvFlags/Output ----- #[test]