seq: use stdout.write_all() instead of print!()

Change from using `print!()` to using `stdout.write_all()` in order to
allow the main function to handle broken pipe errors gracefully.
This commit is contained in:
Jeffrey Finkelstein 2021-09-09 22:02:31 -04:00
parent 92a1f1422e
commit 96b8616a1a
2 changed files with 49 additions and 15 deletions

View file

@ -12,7 +12,7 @@ use num_traits::One;
use num_traits::Zero;
use num_traits::{Num, ToPrimitive};
use std::cmp;
use std::io::{stdout, Write};
use std::io::{stdout, ErrorKind, Write};
use std::str::FromStr;
use uucore::display::Quotable;
@ -192,7 +192,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.num_digits()
.max(increment.num_digits())
.max(last.num_digits());
match (first, last, increment) {
let result = match (first, last, increment) {
(Number::MinusZero, Number::BigInt(last), Number::BigInt(increment)) => print_seq_integers(
(BigInt::zero(), increment, last),
options.separator,
@ -219,8 +219,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
options.widths,
padding,
),
};
match result {
Ok(_) => 0,
Err(err) if err.kind() == ErrorKind::BrokenPipe => 0,
Err(_) => 1,
}
0
}
pub fn uu_app() -> App<'static, 'static> {
@ -276,7 +280,9 @@ fn print_seq(
terminator: String,
pad: bool,
padding: usize,
) {
) -> std::io::Result<()> {
let stdout = stdout();
let mut stdout = stdout.lock();
let (first, increment, last) = range;
let mut i = 0isize;
let mut value = first + i as f64 * increment;
@ -286,20 +292,21 @@ fn print_seq(
let before_dec = istr.find('.').unwrap_or(ilen);
if pad && before_dec < padding {
for _ in 0..(padding - before_dec) {
print!("0");
write!(stdout, "0")?;
}
}
print!("{}", istr);
write!(stdout, "{}", istr)?;
i += 1;
value = first + i as f64 * increment;
if !done_printing(&value, &increment, &last) {
print!("{}", separator);
write!(stdout, "{}", separator)?;
}
}
if (first >= last && increment < 0f64) || (first <= last && increment > 0f64) {
print!("{}", terminator);
write!(stdout, "{}", terminator)?;
}
crash_if_err!(1, stdout().flush());
stdout.flush()?;
Ok(())
}
/// Print an integer sequence.
@ -323,31 +330,34 @@ fn print_seq_integers(
pad: bool,
padding: usize,
is_first_minus_zero: bool,
) {
) -> std::io::Result<()> {
let stdout = stdout();
let mut stdout = stdout.lock();
let (first, increment, last) = range;
let mut value = first;
let mut is_first_iteration = true;
while !done_printing(&value, &increment, &last) {
if !is_first_iteration {
print!("{}", separator);
write!(stdout, "{}", separator)?;
}
let mut width = padding;
if is_first_iteration && is_first_minus_zero {
print!("-");
write!(stdout, "-")?;
width -= 1;
}
is_first_iteration = false;
if pad {
print!("{number:>0width$}", number = value, width = width);
write!(stdout, "{number:>0width$}", number = value, width = width)?;
} else {
print!("{}", value);
write!(stdout, "{}", value)?;
}
value += &increment;
}
if !is_first_iteration {
print!("{}", terminator);
write!(stdout, "{}", terminator)?;
}
Ok(())
}
#[cfg(test)]

View file

@ -1,4 +1,5 @@
use crate::common::util::*;
use std::io::Read;
#[test]
fn test_rejects_nan() {
@ -176,3 +177,26 @@ fn test_width_negative_zero() {
.stdout_is("-0\n01\n")
.no_stderr();
}
// TODO This is duplicated from `test_yes.rs`; refactor them.
/// Run `seq`, capture some of the output, close the pipe, and verify it.
fn run(args: &[&str], expected: &[u8]) {
let mut cmd = new_ucmd!();
let mut child = cmd.args(args).run_no_wait();
let mut stdout = child.stdout.take().unwrap();
let mut buf = vec![0; expected.len()];
stdout.read_exact(&mut buf).unwrap();
drop(stdout);
assert!(child.wait().unwrap().success());
assert_eq!(buf.as_slice(), expected);
}
#[test]
fn test_neg_inf() {
run(&["--", "-inf", "0"], b"-inf\n-inf\n-inf\n");
}
#[test]
fn test_inf() {
run(&["inf"], b"1\n2\n3\n");
}