1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

wc: implement --total

This commit is contained in:
Daniel Hofstetter 2023-03-31 08:16:46 +02:00
parent 5d0f0144c1
commit 0fa08757fa
2 changed files with 125 additions and 14 deletions

View file

@ -42,6 +42,7 @@ struct Settings {
show_max_line_length: bool, show_max_line_length: bool,
files0_from_stdin_mode: bool, files0_from_stdin_mode: bool,
title_quoting_style: QuotingStyle, title_quoting_style: QuotingStyle,
total_when: TotalWhen,
} }
impl Settings { impl Settings {
@ -65,6 +66,7 @@ impl Settings {
show_max_line_length: matches.get_flag(options::MAX_LINE_LENGTH), show_max_line_length: matches.get_flag(options::MAX_LINE_LENGTH),
files0_from_stdin_mode, files0_from_stdin_mode,
title_quoting_style, title_quoting_style,
total_when: matches.get_one::<String>(options::TOTAL).unwrap().into(),
}; };
if settings.show_bytes if settings.show_bytes
@ -84,6 +86,7 @@ impl Settings {
show_max_line_length: false, show_max_line_length: false,
files0_from_stdin_mode, files0_from_stdin_mode,
title_quoting_style: settings.title_quoting_style, title_quoting_style: settings.title_quoting_style,
total_when: settings.total_when,
} }
} }
@ -107,6 +110,7 @@ pub mod options {
pub static FILES0_FROM: &str = "files0-from"; pub static FILES0_FROM: &str = "files0-from";
pub static LINES: &str = "lines"; pub static LINES: &str = "lines";
pub static MAX_LINE_LENGTH: &str = "max-line-length"; pub static MAX_LINE_LENGTH: &str = "max-line-length";
pub static TOTAL: &str = "total";
pub static WORDS: &str = "words"; pub static WORDS: &str = "words";
} }
@ -160,6 +164,37 @@ impl Input {
} }
} }
/// When to show the "total" line
#[derive(PartialEq)]
enum TotalWhen {
Auto,
Always,
Only,
Never,
}
impl From<&String> for TotalWhen {
fn from(s: &String) -> Self {
match s.as_ref() {
"auto" => Self::Auto,
"always" => Self::Always,
"only" => Self::Only,
"never" => Self::Never,
_ => unreachable!("Should have been caught by clap"),
}
}
}
impl TotalWhen {
fn is_total_row_visible(&self, num_inputs: usize) -> bool {
match self {
Self::Auto => num_inputs > 1,
Self::Always | Self::Only => true,
Self::Never => false,
}
}
}
#[derive(Debug)] #[derive(Debug)]
enum WcError { enum WcError {
FilesDisabled(String), FilesDisabled(String),
@ -246,6 +281,15 @@ pub fn uu_app() -> Command {
.help("print the length of the longest line") .help("print the length of the longest line")
.action(ArgAction::SetTrue), .action(ArgAction::SetTrue),
) )
.arg(
Arg::new(options::TOTAL)
.long(options::TOTAL)
.value_parser(["auto", "always", "only", "never"])
.default_value("auto")
.hide_default_value(true)
.value_name("WHEN")
.help("when to print a line with total counts"),
)
.arg( .arg(
Arg::new(options::WORDS) Arg::new(options::WORDS)
.short('w') .short('w')
@ -561,11 +605,19 @@ fn compute_number_width(inputs: &[Input], settings: &Settings) -> usize {
} }
fn wc(inputs: &[Input], settings: &Settings) -> UResult<()> { fn wc(inputs: &[Input], settings: &Settings) -> UResult<()> {
let number_width = compute_number_width(inputs, settings);
let mut total_word_count = WordCount::default(); let mut total_word_count = WordCount::default();
let num_inputs = inputs.len(); let (number_width, are_stats_visible, total_row_title) =
if settings.total_when == TotalWhen::Only {
(1, false, None)
} else {
let number_width = compute_number_width(inputs, settings);
let title = Some(String::from("total"));
(number_width, true, title)
};
let is_total_row_visible = settings.total_when.is_total_row_visible(inputs.len());
for input in inputs { for input in inputs {
let word_count = match word_count_from_input(input, settings) { let word_count = match word_count_from_input(input, settings) {
@ -595,20 +647,23 @@ fn wc(inputs: &[Input], settings: &Settings) -> UResult<()> {
}; };
total_word_count += word_count; total_word_count += word_count;
let result = word_count.with_title(input.to_title(&settings.title_quoting_style)); let result = word_count.with_title(input.to_title(&settings.title_quoting_style));
if let Err(err) = print_stats(settings, &result, number_width) {
show!(USimpleError::new( if are_stats_visible {
1, if let Err(err) = print_stats(settings, &result, number_width) {
format!( show!(USimpleError::new(
"failed to print result for {}: {}", 1,
&result.title.unwrap_or_else(|| String::from("<stdin>")), format!(
err, "failed to print result for {}: {}",
), &result.title.unwrap_or_else(|| String::from("<stdin>")),
)); err,
),
));
}
} }
} }
if num_inputs > 1 { if is_total_row_visible {
let total_result = total_word_count.with_title(Some(String::from("total"))); let total_result = total_word_count.with_title(total_row_title);
if let Err(err) = print_stats(settings, &total_result, number_width) { if let Err(err) = print_stats(settings, &total_result, number_width) {
show!(USimpleError::new( show!(USimpleError::new(
1, 1,

View file

@ -464,3 +464,59 @@ fn test_files0_from_with_stdin_try_read_from_stdin() {
.stderr_contains(MSG) .stderr_contains(MSG)
.stdout_is(""); .stdout_is("");
} }
#[test]
fn test_total_auto() {
new_ucmd!()
.args(&["lorem_ipsum.txt", "--total=auto"])
.run()
.stdout_is(" 13 109 772 lorem_ipsum.txt\n");
new_ucmd!()
.args(&["lorem_ipsum.txt", "moby_dick.txt", "--total=auto"])
.run()
.stdout_is(
" 13 109 772 lorem_ipsum.txt\n 18 204 1115 moby_dick.txt\n 31 313 1887 total\n",
);
}
#[test]
fn test_total_always() {
new_ucmd!()
.args(&["lorem_ipsum.txt", "--total=always"])
.run()
.stdout_is(" 13 109 772 lorem_ipsum.txt\n 13 109 772 total\n");
new_ucmd!()
.args(&["lorem_ipsum.txt", "moby_dick.txt", "--total=always"])
.run()
.stdout_is(
" 13 109 772 lorem_ipsum.txt\n 18 204 1115 moby_dick.txt\n 31 313 1887 total\n",
);
}
#[test]
fn test_total_never() {
new_ucmd!()
.args(&["lorem_ipsum.txt", "--total=never"])
.run()
.stdout_is(" 13 109 772 lorem_ipsum.txt\n");
new_ucmd!()
.args(&["lorem_ipsum.txt", "moby_dick.txt", "--total=never"])
.run()
.stdout_is(" 13 109 772 lorem_ipsum.txt\n 18 204 1115 moby_dick.txt\n");
}
#[test]
fn test_total_only() {
new_ucmd!()
.args(&["lorem_ipsum.txt", "--total=only"])
.run()
.stdout_is("13 109 772\n");
new_ucmd!()
.args(&["lorem_ipsum.txt", "moby_dick.txt", "--total=only"])
.run()
.stdout_is("31 313 1887\n");
}