Skip to content

Commit c5c5a16

Browse files
authored
Merge pull request #603 from brian-pane/eof
Ignore -E/-e flag when a delimiter is specified
1 parent 1a65b76 commit c5c5a16

File tree

2 files changed

+47
-21
lines changed

2 files changed

+47
-21
lines changed

src/xargs/mod.rs

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -812,10 +812,7 @@ fn validate_positive_usize(s: &str) -> Result<usize, String> {
812812
}
813813
}
814814

815-
fn normalize_options<'a>(
816-
options: &'a Options,
817-
matches: &'a clap::ArgMatches,
818-
) -> (Option<usize>, Option<usize>, &'a Option<String>, Option<u8>) {
815+
fn normalize_options(options: Options, matches: &clap::ArgMatches) -> Options {
819816
let (max_args, max_lines, replace) =
820817
match (options.max_args, options.max_lines, &options.replace) {
821818
// These 3 options are mutually exclusive.
@@ -824,10 +821,10 @@ fn normalize_options<'a>(
824821
// If `replace`, all matches in initial args should be replaced with extra args read from stdin.
825822
// It is possible to have multiple matches and multiple extra args, and the Cartesian product is desired.
826823
// To be specific, we process extra args one by one, and replace all matches with the same extra arg in each time.
827-
(Some(1), None, &options.replace)
824+
(Some(1), None, options.replace)
828825
}
829826
(Some(_), None, None) | (None, Some(_), None) | (None, None, None) => {
830-
(options.max_args, options.max_lines, &None)
827+
(options.max_args, options.max_lines, None)
831828
}
832829
_ => {
833830
eprintln!(
@@ -845,11 +842,11 @@ fn normalize_options<'a>(
845842
.flat_map(|o| matches.indices_of(o).and_then(|mut v| v.next_back()))
846843
.max();
847844
if lines_index > args_index && lines_index > replace_index {
848-
(None, options.max_lines, &None)
845+
(None, options.max_lines, None)
849846
} else if args_index > lines_index && args_index > replace_index {
850-
(options.max_args, None, &None)
847+
(options.max_args, None, None)
851848
} else {
852-
(Some(1), None, &options.replace)
849+
(Some(1), None, options.replace)
853850
}
854851
}
855852
};
@@ -871,7 +868,25 @@ fn normalize_options<'a>(
871868
(None, false) => replace.as_ref().map(|_| b'\n'),
872869
};
873870

874-
(max_args, max_lines, replace, delimiter)
871+
let eof_delimiter = if delimiter.is_some() {
872+
None
873+
} else {
874+
options.eof_delimiter
875+
};
876+
877+
Options {
878+
arg_file: options.arg_file,
879+
delimiter,
880+
exit_if_pass_char_limit: options.exit_if_pass_char_limit,
881+
max_args,
882+
max_chars: options.max_chars,
883+
max_lines,
884+
no_run_if_empty: options.no_run_if_empty,
885+
null: options.null,
886+
replace,
887+
verbose: options.verbose,
888+
eof_delimiter,
889+
}
875890
}
876891

877892
fn do_xargs(args: &[&str]) -> Result<CommandResult, XargsError> {
@@ -1007,7 +1022,7 @@ fn do_xargs(args: &[&str]) -> Result<CommandResult, XargsError> {
10071022
.value_name("eof-string")
10081023
.help(
10091024
"If specified, stop processing the input upon reaching an input \
1010-
item that matches eof-string",
1025+
item that matches eof-string (ignored if -d or -0 is used)",
10111026
)
10121027
.value_parser(clap::value_parser!(String)),
10131028
)
@@ -1074,7 +1089,7 @@ fn do_xargs(args: &[&str]) -> Result<CommandResult, XargsError> {
10741089
}),
10751090
};
10761091

1077-
let (max_args, max_lines, replace, delimiter) = normalize_options(&options, &matches);
1092+
let options = normalize_options(options, &matches);
10781093

10791094
let action = match matches.get_many::<OsString>(options::COMMAND) {
10801095
Some(args) if args.len() > 0 => {
@@ -1085,21 +1100,21 @@ fn do_xargs(args: &[&str]) -> Result<CommandResult, XargsError> {
10851100
let env = std::env::vars_os().collect();
10861101

10871102
let mut limiters = LimiterCollection::new();
1088-
if let Some(max_args) = max_args {
1103+
if let Some(max_args) = options.max_args {
10891104
limiters.add(MaxArgsCommandSizeLimiter::new(max_args));
10901105
}
1091-
if let Some(max_lines) = max_lines {
1106+
if let Some(max_lines) = options.max_lines {
10921107
limiters.add(MaxLinesCommandSizeLimiter::new(max_lines));
10931108
}
10941109
if let Some(max_chars) = options.max_chars {
10951110
limiters.add(MaxCharsCommandSizeLimiter::new(max_chars));
10961111
}
10971112
limiters.add(MaxCharsCommandSizeLimiter::new_system(&env));
10981113

1099-
let mut builder_options = CommandBuilderOptions::new(action, env, limiters, replace.clone())
1100-
.map_err(|_| {
1101-
"Base command and environment are too large to fit into one command execution"
1102-
})?;
1114+
let mut builder_options =
1115+
CommandBuilderOptions::new(action, env, limiters, options.replace.clone()).map_err(
1116+
|_| "Base command and environment are too large to fit into one command execution",
1117+
)?;
11031118

11041119
builder_options.verbose = options.verbose;
11051120
builder_options.close_stdin = options.arg_file.is_none();
@@ -1110,7 +1125,7 @@ fn do_xargs(args: &[&str]) -> Result<CommandResult, XargsError> {
11101125
Box::new(io::stdin())
11111126
};
11121127

1113-
let mut args: Box<dyn ArgumentReader> = if let Some(delimiter) = delimiter {
1128+
let mut args: Box<dyn ArgumentReader> = if let Some(delimiter) = options.delimiter {
11141129
Box::new(ByteDelimitedArgumentReader::new(args_file, delimiter))
11151130
} else {
11161131
Box::new(WhitespaceDelimitedArgumentReader::new(args_file))
@@ -1125,8 +1140,8 @@ fn do_xargs(args: &[&str]) -> Result<CommandResult, XargsError> {
11251140
args,
11261141
&InputProcessOptions::new(
11271142
options.exit_if_pass_char_limit,
1128-
max_args,
1129-
max_lines,
1143+
options.max_args,
1144+
options.max_lines,
11301145
options.no_run_if_empty,
11311146
),
11321147
)?;

tests/xargs_tests.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,3 +572,14 @@ fn xargs_eof() {
572572
.stdout(predicate::str::diff("ab\n"));
573573
}
574574
}
575+
576+
#[test]
577+
fn xargs_eof_with_delimiter() {
578+
cargo_bin_cmd!("xargs")
579+
.args(["-0", "-Ecd"])
580+
.write_stdin("ab\0cd\0ef")
581+
.assert()
582+
.success()
583+
.stderr(predicate::str::is_empty())
584+
.stdout(predicate::str::diff("ab cd ef\n"));
585+
}

0 commit comments

Comments
 (0)