1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-27 19:17:43 +00:00

Merge pull request #7704 from nyurik/optimize-dd

feat: optimize `dd` parsing, bugfix
This commit is contained in:
Yuri Astrakhan 2025-04-14 15:58:11 -04:00 committed by GitHub
parent d37f500bd3
commit c1d2a07c62
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 42 additions and 54 deletions

2
Cargo.lock generated
View file

@ -1333,7 +1333,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"windows-targets 0.48.5", "windows-targets 0.52.6",
] ]
[[package]] [[package]]

View file

@ -1397,11 +1397,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uu_app().try_get_matches_from(args)?; let matches = uu_app().try_get_matches_from(args)?;
let settings: Settings = Parser::new().parse( let settings: Settings = Parser::new().parse(
&matches matches
.get_many::<String>(options::OPERANDS) .get_many::<String>(options::OPERANDS)
.unwrap_or_default() .unwrap_or_default(),
.map(|s| s.as_ref())
.collect::<Vec<_>>()[..],
)?; )?;
let i = match settings.infile { let i = match settings.infile {

View file

@ -126,13 +126,19 @@ impl Parser {
Self::default() Self::default()
} }
pub(crate) fn parse(self, operands: &[&str]) -> Result<Settings, ParseError> { pub(crate) fn parse(
self,
operands: impl IntoIterator<Item: AsRef<str>>,
) -> Result<Settings, ParseError> {
self.read(operands)?.validate() self.read(operands)?.validate()
} }
pub(crate) fn read(mut self, operands: &[&str]) -> Result<Self, ParseError> { pub(crate) fn read(
mut self,
operands: impl IntoIterator<Item: AsRef<str>>,
) -> Result<Self, ParseError> {
for operand in operands { for operand in operands {
self.parse_operand(operand)?; self.parse_operand(operand.as_ref())?;
} }
Ok(self) Ok(self)

View file

@ -29,22 +29,14 @@ fn unimplemented_flags_should_error_non_linux() {
"noctty", "noctty",
"nofollow", "nofollow",
] { ] {
let args = vec![format!("iflag={flag}")]; let arg = format!("iflag={flag}");
if Parser::new().parse([&arg]).is_ok() {
if Parser::new() succeeded.push(arg);
.parse(&args.iter().map(AsRef::as_ref).collect::<Vec<_>>()[..])
.is_ok()
{
succeeded.push(format!("iflag={flag}"));
} }
let args = vec![format!("oflag={flag}")]; let arg = format!("oflag={flag}");
if Parser::new().parse([&arg]).is_ok() {
if Parser::new() succeeded.push(arg);
.parse(&args.iter().map(AsRef::as_ref).collect::<Vec<_>>()[..])
.is_ok()
{
succeeded.push(format!("iflag={flag}"));
} }
} }
@ -61,22 +53,14 @@ fn unimplemented_flags_should_error() {
// The following flags are not implemented // The following flags are not implemented
for flag in ["cio", "nolinks", "text", "binary"] { for flag in ["cio", "nolinks", "text", "binary"] {
let args = vec![format!("iflag={flag}")]; let arg = format!("iflag={flag}");
if Parser::new().parse([&arg]).is_ok() {
if Parser::new() succeeded.push(arg);
.parse(&args.iter().map(AsRef::as_ref).collect::<Vec<_>>()[..])
.is_ok()
{
succeeded.push(format!("iflag={flag}"));
} }
let args = vec![format!("oflag={flag}")]; let arg = format!("oflag={flag}");
if Parser::new().parse([&arg]).is_ok() {
if Parser::new() succeeded.push(arg);
.parse(&args.iter().map(AsRef::as_ref).collect::<Vec<_>>()[..])
.is_ok()
{
succeeded.push(format!("iflag={flag}"));
} }
} }
@ -88,14 +72,14 @@ fn unimplemented_flags_should_error() {
#[test] #[test]
fn test_status_level_absent() { fn test_status_level_absent() {
let args = &["if=foo.file", "of=bar.file"]; let args = ["if=foo.file", "of=bar.file"];
assert_eq!(Parser::new().parse(args).unwrap().status, None); assert_eq!(Parser::new().parse(args).unwrap().status, None);
} }
#[test] #[test]
fn test_status_level_none() { fn test_status_level_none() {
let args = &["status=none", "if=foo.file", "of=bar.file"]; let args = ["status=none", "if=foo.file", "of=bar.file"];
assert_eq!( assert_eq!(
Parser::new().parse(args).unwrap().status, Parser::new().parse(args).unwrap().status,
@ -106,7 +90,7 @@ fn test_status_level_none() {
#[test] #[test]
#[allow(clippy::cognitive_complexity)] #[allow(clippy::cognitive_complexity)]
fn test_all_top_level_args_no_leading_dashes() { fn test_all_top_level_args_no_leading_dashes() {
let args = &[ let args = [
"if=foo.file", "if=foo.file",
"of=bar.file", "of=bar.file",
"ibs=10", "ibs=10",
@ -181,7 +165,7 @@ fn test_all_top_level_args_no_leading_dashes() {
#[test] #[test]
fn test_status_level_progress() { fn test_status_level_progress() {
let args = &["if=foo.file", "of=bar.file", "status=progress"]; let args = ["if=foo.file", "of=bar.file", "status=progress"];
let settings = Parser::new().parse(args).unwrap(); let settings = Parser::new().parse(args).unwrap();
@ -190,7 +174,7 @@ fn test_status_level_progress() {
#[test] #[test]
fn test_status_level_noxfer() { fn test_status_level_noxfer() {
let args = &["if=foo.file", "status=noxfer", "of=bar.file"]; let args = ["if=foo.file", "status=noxfer", "of=bar.file"];
let settings = Parser::new().parse(args).unwrap(); let settings = Parser::new().parse(args).unwrap();
@ -199,7 +183,7 @@ fn test_status_level_noxfer() {
#[test] #[test]
fn test_multiple_flags_options() { fn test_multiple_flags_options() {
let args = &[ let args = [
"iflag=fullblock,count_bytes", "iflag=fullblock,count_bytes",
"iflag=skip_bytes", "iflag=skip_bytes",
"oflag=append", "oflag=append",
@ -246,7 +230,7 @@ fn test_multiple_flags_options() {
#[test] #[test]
fn test_override_multiple_options() { fn test_override_multiple_options() {
let args = &[ let args = [
"if=foo.file", "if=foo.file",
"if=correct.file", "if=correct.file",
"of=bar.file", "of=bar.file",
@ -288,31 +272,31 @@ fn test_override_multiple_options() {
#[test] #[test]
fn icf_ctable_error() { fn icf_ctable_error() {
let args = &["conv=ascii,ebcdic,ibm"]; let args = ["conv=ascii,ebcdic,ibm"];
assert!(Parser::new().parse(args).is_err()); assert!(Parser::new().parse(args).is_err());
} }
#[test] #[test]
fn icf_case_error() { fn icf_case_error() {
let args = &["conv=ucase,lcase"]; let args = ["conv=ucase,lcase"];
assert!(Parser::new().parse(args).is_err()); assert!(Parser::new().parse(args).is_err());
} }
#[test] #[test]
fn icf_block_error() { fn icf_block_error() {
let args = &["conv=block,unblock"]; let args = ["conv=block,unblock"];
assert!(Parser::new().parse(args).is_err()); assert!(Parser::new().parse(args).is_err());
} }
#[test] #[test]
fn icf_creat_error() { fn icf_creat_error() {
let args = &["conv=excl,nocreat"]; let args = ["conv=excl,nocreat"];
assert!(Parser::new().parse(args).is_err()); assert!(Parser::new().parse(args).is_err());
} }
#[test] #[test]
fn parse_icf_token_ibm() { fn parse_icf_token_ibm() {
let args = &["conv=ibm"]; let args = ["conv=ibm"];
let settings = Parser::new().parse(args).unwrap(); let settings = Parser::new().parse(args).unwrap();
assert_eq!( assert_eq!(
@ -326,7 +310,7 @@ fn parse_icf_token_ibm() {
#[test] #[test]
fn parse_icf_tokens_elu() { fn parse_icf_tokens_elu() {
let args = &["conv=ebcdic,lcase"]; let args = ["conv=ebcdic,lcase"];
let settings = Parser::new().parse(args).unwrap(); let settings = Parser::new().parse(args).unwrap();
assert_eq!( assert_eq!(
@ -340,7 +324,7 @@ fn parse_icf_tokens_elu() {
#[test] #[test]
fn parse_icf_tokens_remaining() { fn parse_icf_tokens_remaining() {
let args = &[ let args = [
"conv=ascii,ucase,block,sparse,swab,sync,noerror,excl,nocreat,notrunc,noerror,fdatasync,fsync", "conv=ascii,ucase,block,sparse,swab,sync,noerror,excl,nocreat,notrunc,noerror,fdatasync,fsync",
]; ];
assert_eq!( assert_eq!(
@ -369,7 +353,7 @@ fn parse_icf_tokens_remaining() {
#[test] #[test]
fn parse_iflag_tokens() { fn parse_iflag_tokens() {
let args = &["iflag=fullblock,count_bytes,skip_bytes"]; let args = ["iflag=fullblock,count_bytes,skip_bytes"];
assert_eq!( assert_eq!(
Parser::new().read(args), Parser::new().read(args),
Ok(Parser { Ok(Parser {
@ -386,7 +370,7 @@ fn parse_iflag_tokens() {
#[test] #[test]
fn parse_oflag_tokens() { fn parse_oflag_tokens() {
let args = &["oflag=append,seek_bytes"]; let args = ["oflag=append,seek_bytes"];
assert_eq!( assert_eq!(
Parser::new().read(args), Parser::new().read(args),
Ok(Parser { Ok(Parser {
@ -403,7 +387,7 @@ fn parse_oflag_tokens() {
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
#[test] #[test]
fn parse_iflag_tokens_linux() { fn parse_iflag_tokens_linux() {
let args = &["iflag=direct,directory,dsync,sync,nonblock,noatime,noctty,nofollow"]; let args = ["iflag=direct,directory,dsync,sync,nonblock,noatime,noctty,nofollow"];
assert_eq!( assert_eq!(
Parser::new().read(args), Parser::new().read(args),
Ok(Parser { Ok(Parser {
@ -426,7 +410,7 @@ fn parse_iflag_tokens_linux() {
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
#[test] #[test]
fn parse_oflag_tokens_linux() { fn parse_oflag_tokens_linux() {
let args = &["oflag=direct,directory,dsync,sync,nonblock,noatime,noctty,nofollow"]; let args = ["oflag=direct,directory,dsync,sync,nonblock,noatime,noctty,nofollow"];
assert_eq!( assert_eq!(
Parser::new().read(args), Parser::new().read(args),
Ok(Parser { Ok(Parser {