Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 35 additions & 23 deletions src/uu/cut/src/cut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,6 @@ impl<'a> From<&'a OsString> for Delimiter<'a> {
}
}

fn stdout_writer() -> Box<dyn Write> {
if std::io::stdout().is_terminal() {
Box::new(stdout())
} else {
Box::new(BufWriter::new(stdout())) as Box<dyn Write>
}
}

fn list_to_ranges(list: &str, complement: bool) -> Result<Vec<Range>, String> {
if complement {
Range::from_list(list).map(|r| uucore::ranges::complement(&r))
Expand All @@ -78,10 +70,14 @@ fn list_to_ranges(list: &str, complement: bool) -> Result<Vec<Range>, String> {
}
}

fn cut_bytes<R: Read>(reader: R, ranges: &[Range], opts: &Options) -> UResult<()> {
fn cut_bytes<R: Read, W: Write>(
reader: R,
out: &mut W,
ranges: &[Range],
opts: &Options,
) -> UResult<()> {
let newline_char = opts.line_ending.into();
let mut buf_in = BufReader::new(reader);
let mut out = stdout_writer();
let out_delim = opts.out_delimiter.unwrap_or(b"\t");

let result = buf_in.for_byte_record(newline_char, |line| {
Expand Down Expand Up @@ -112,16 +108,16 @@ fn cut_bytes<R: Read>(reader: R, ranges: &[Range], opts: &Options) -> UResult<()
}

// Output delimiter is explicitly specified
fn cut_fields_explicit_out_delim<R: Read, M: Matcher>(
fn cut_fields_explicit_out_delim<R: Read, W: Write, M: Matcher>(
reader: R,
out: &mut W,
matcher: &M,
ranges: &[Range],
only_delimited: bool,
newline_char: u8,
out_delim: &[u8],
) -> UResult<()> {
let mut buf_in = BufReader::new(reader);
let mut out = stdout_writer();

let result = buf_in.for_byte_record_with_terminator(newline_char, |line| {
let mut fields_pos = 1;
Expand Down Expand Up @@ -197,15 +193,15 @@ fn cut_fields_explicit_out_delim<R: Read, M: Matcher>(
}

// Output delimiter is the same as input delimiter
fn cut_fields_implicit_out_delim<R: Read, M: Matcher>(
fn cut_fields_implicit_out_delim<R: Read, W: Write, M: Matcher>(
reader: R,
out: &mut W,
matcher: &M,
ranges: &[Range],
only_delimited: bool,
newline_char: u8,
) -> UResult<()> {
let mut buf_in = BufReader::new(reader);
let mut out = stdout_writer();

let result = buf_in.for_byte_record_with_terminator(newline_char, |line| {
let mut fields_pos = 1;
Expand Down Expand Up @@ -268,14 +264,14 @@ fn cut_fields_implicit_out_delim<R: Read, M: Matcher>(
}

// The input delimiter is identical to `newline_char`
fn cut_fields_newline_char_delim<R: Read>(
fn cut_fields_newline_char_delim<R: Read, W: Write>(
reader: R,
out: &mut W,
ranges: &[Range],
newline_char: u8,
out_delim: &[u8],
) -> UResult<()> {
let buf_in = BufReader::new(reader);
let mut out = stdout_writer();

let segments: Vec<_> = buf_in.split(newline_char).filter_map(|x| x.ok()).collect();
let mut print_delim = false;
Expand All @@ -299,19 +295,25 @@ fn cut_fields_newline_char_delim<R: Read>(
Ok(())
}

fn cut_fields<R: Read>(reader: R, ranges: &[Range], opts: &Options) -> UResult<()> {
fn cut_fields<R: Read, W: Write>(
reader: R,
out: &mut W,
ranges: &[Range],
opts: &Options,
) -> UResult<()> {
let newline_char = opts.line_ending.into();
let field_opts = opts.field_opts.as_ref().unwrap(); // it is safe to unwrap() here - field_opts will always be Some() for cut_fields() call
match field_opts.delimiter {
Delimiter::Slice(delim) if delim == [newline_char] => {
let out_delim = opts.out_delimiter.unwrap_or(delim);
cut_fields_newline_char_delim(reader, ranges, newline_char, out_delim)
cut_fields_newline_char_delim(reader, out, ranges, newline_char, out_delim)
}
Delimiter::Slice(delim) => {
let matcher = ExactMatcher::new(delim);
match opts.out_delimiter {
Some(out_delim) => cut_fields_explicit_out_delim(
reader,
out,
&matcher,
ranges,
field_opts.only_delimited,
Expand All @@ -320,6 +322,7 @@ fn cut_fields<R: Read>(reader: R, ranges: &[Range], opts: &Options) -> UResult<(
),
None => cut_fields_implicit_out_delim(
reader,
out,
&matcher,
ranges,
field_opts.only_delimited,
Expand All @@ -331,6 +334,7 @@ fn cut_fields<R: Read>(reader: R, ranges: &[Range], opts: &Options) -> UResult<(
let matcher = WhitespaceMatcher {};
cut_fields_explicit_out_delim(
reader,
out,
&matcher,
ranges,
field_opts.only_delimited,
Expand All @@ -348,16 +352,22 @@ fn cut_files(mut filenames: Vec<String>, mode: &Mode) {
filenames.push("-".to_owned());
}

let mut out: Box<dyn Write> = if std::io::stdout().is_terminal() {
Box::new(stdout())
} else {
Box::new(BufWriter::new(stdout())) as Box<dyn Write>
};

for filename in &filenames {
if filename == "-" {
if stdin_read {
continue;
}

show_if_err!(match mode {
Mode::Bytes(ranges, opts) => cut_bytes(stdin(), ranges, opts),
Mode::Characters(ranges, opts) => cut_bytes(stdin(), ranges, opts),
Mode::Fields(ranges, opts) => cut_fields(stdin(), ranges, opts),
Mode::Bytes(ranges, opts) => cut_bytes(stdin(), &mut out, ranges, opts),
Mode::Characters(ranges, opts) => cut_bytes(stdin(), &mut out, ranges, opts),
Mode::Fields(ranges, opts) => cut_fields(stdin(), &mut out, ranges, opts),
});

stdin_read = true;
Expand All @@ -376,14 +386,16 @@ fn cut_files(mut filenames: Vec<String>, mode: &Mode) {
.and_then(|file| {
match &mode {
Mode::Bytes(ranges, opts) | Mode::Characters(ranges, opts) => {
cut_bytes(file, ranges, opts)
cut_bytes(file, &mut out, ranges, opts)
}
Mode::Fields(ranges, opts) => cut_fields(file, ranges, opts),
Mode::Fields(ranges, opts) => cut_fields(file, &mut out, ranges, opts),
}
})
);
}
}

show_if_err!(out.flush().map_err_context(|| "write error".into()));
}

// Get delimiter and output delimiter from `-d`/`--delimiter` and `--output-delimiter` options respectively
Expand Down
8 changes: 6 additions & 2 deletions src/uu/ptx/src/ptx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,8 @@ fn write_traditional_output(
let mut writer: BufWriter<Box<dyn Write>> = BufWriter::new(if output_filename == "-" {
Box::new(stdout())
} else {
let file = File::create(output_filename).map_err_context(String::new)?;
let file = File::create(output_filename)
.map_err_context(|| output_filename.maybe_quote().to_string())?;
Box::new(file)
});

Expand Down Expand Up @@ -673,8 +674,11 @@ fn write_traditional_output(
return Err(PtxError::DumbFormat.into());
}
};
writeln!(writer, "{output_line}").map_err_context(String::new)?;
writeln!(writer, "{output_line}").map_err_context(|| "write failed".into())?;
}

writer.flush().map_err_context(|| "write failed".into())?;

Ok(())
}

Expand Down
8 changes: 4 additions & 4 deletions src/uu/sort/src/ext_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ fn reader_writer<
}),
settings,
output,
);
)?;
} else {
print_sorted(chunk.lines().iter(), settings, output);
print_sorted(chunk.lines().iter(), settings, output)?;
}
}
ReadResult::SortedTwoChunks([a, b]) => {
Expand All @@ -138,9 +138,9 @@ fn reader_writer<
.map(|(line, _)| line),
settings,
output,
);
)?;
} else {
print_sorted(merged_iter.map(|(line, _)| line), settings, output);
print_sorted(merged_iter.map(|(line, _)| line), settings, output)?;
}
}
ReadResult::EmptyInput => {
Expand Down
21 changes: 14 additions & 7 deletions src/uu/sort/src/merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use std::{
};

use compare::Compare;
use uucore::error::UResult;
use uucore::error::{FromIo, UResult};

use crate::{
GlobalSettings, Output, SortError,
Expand Down Expand Up @@ -278,12 +278,19 @@ impl FileMerger<'_> {
}

fn write_all_to(mut self, settings: &GlobalSettings, out: &mut impl Write) -> UResult<()> {
while self.write_next(settings, out) {}
while self
.write_next(settings, out)
.map_err_context(|| "write failed".into())?
{}
drop(self.request_sender);
self.reader_join_handle.join().unwrap()
}

fn write_next(&mut self, settings: &GlobalSettings, out: &mut impl Write) -> bool {
fn write_next(
&mut self,
settings: &GlobalSettings,
out: &mut impl Write,
) -> std::io::Result<bool> {
if let Some(file) = self.heap.peek() {
let prev = self.prev.replace(PreviousLine {
chunk: file.current_chunk.clone(),
Expand All @@ -303,12 +310,12 @@ impl FileMerger<'_> {
file.current_chunk.line_data(),
);
if cmp == Ordering::Equal {
return;
return Ok(());
}
}
}
current_line.print(out, settings);
});
current_line.print(out, settings)
})?;

let was_last_line_for_file = file.current_chunk.lines().len() == file.line_idx + 1;

Expand All @@ -335,7 +342,7 @@ impl FileMerger<'_> {
}
}
}
!self.heap.is_empty()
Ok(!self.heap.is_empty())
}
}

Expand Down
23 changes: 16 additions & 7 deletions src/uu/sort/src/sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use std::str::Utf8Error;
use thiserror::Error;
use unicode_width::UnicodeWidthStr;
use uucore::display::Quotable;
use uucore::error::strip_errno;
use uucore::error::{FromIo, strip_errno};
use uucore::error::{UError, UResult, USimpleError, UUsageError, set_exit_code};
use uucore::line_ending::LineEnding;
use uucore::parse_size::{ParseSizeError, Parser};
Expand Down Expand Up @@ -481,13 +481,14 @@ impl<'a> Line<'a> {
Self { line, index }
}

fn print(&self, writer: &mut impl Write, settings: &GlobalSettings) {
fn print(&self, writer: &mut impl Write, settings: &GlobalSettings) -> std::io::Result<()> {
if settings.debug {
self.print_debug(settings, writer).unwrap();
self.print_debug(settings, writer)?;
} else {
writer.write_all(self.line.as_bytes()).unwrap();
writer.write_all(&[settings.line_ending.into()]).unwrap();
writer.write_all(self.line.as_bytes())?;
writer.write_all(&[settings.line_ending.into()])?;
}
Ok(())
}

/// Writes indicators for the selections this line matched. The original line content is NOT expected
Expand Down Expand Up @@ -1827,11 +1828,19 @@ fn print_sorted<'a, T: Iterator<Item = &'a Line<'a>>>(
iter: T,
settings: &GlobalSettings,
output: Output,
) {
) -> UResult<()> {
let output_name = output
.as_output_name()
.unwrap_or("standard output")
.to_owned();
let ctx = || format!("write failed: {}", output_name.maybe_quote());

let mut writer = output.into_write();
for line in iter {
line.print(&mut writer, settings);
line.print(&mut writer, settings).map_err_context(ctx)?;
}
writer.flush().map_err_context(ctx)?;
Ok(())
}

fn open(path: impl AsRef<OsStr>) -> UResult<Box<dyn Read + Send>> {
Expand Down
2 changes: 2 additions & 0 deletions src/uu/tac/src/tac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ fn buffer_tac_regex(
// After the loop terminates, write whatever bytes are remaining at
// the beginning of the buffer.
out.write_all(&data[0..following_line_start])?;
out.flush()?;
Ok(())
}

Expand Down Expand Up @@ -215,6 +216,7 @@ fn buffer_tac(data: &[u8], before: bool, separator: &str) -> std::io::Result<()>
// After the loop terminates, write whatever bytes are remaining at
// the beginning of the buffer.
out.write_all(&data[0..following_line_start])?;
out.flush()?;
Ok(())
}

Expand Down
2 changes: 1 addition & 1 deletion src/uu/tail/src/chunks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ impl BytesChunkBuffer {
Ok(())
}

pub fn print(&self, mut writer: impl Write) -> UResult<()> {
pub fn print(&self, writer: &mut impl Write) -> UResult<()> {
for chunk in &self.chunks {
writer.write_all(chunk.get_buffer())?;
}
Expand Down
8 changes: 4 additions & 4 deletions src/uu/tail/src/follow/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::text;
use std::collections::HashMap;
use std::collections::hash_map::Keys;
use std::fs::{File, Metadata};
use std::io::{BufRead, BufReader, BufWriter, stdout};
use std::io::{BufRead, BufReader, BufWriter, Write, stdout};
use std::path::{Path, PathBuf};
use uucore::error::UResult;

Expand Down Expand Up @@ -146,9 +146,9 @@ impl FileHandling {
self.header_printer.print(display_name.as_str());
}

let stdout = stdout();
let writer = BufWriter::new(stdout.lock());
chunks.print(writer)?;
let mut writer = BufWriter::new(stdout().lock());
chunks.print(&mut writer)?;
writer.flush()?;

self.last.replace(path.to_owned());
self.update_metadata(path, None);
Expand Down
4 changes: 2 additions & 2 deletions src/uu/tail/src/tail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,8 +399,7 @@ fn bounded_tail(file: &mut File, settings: &Settings) {
}

fn unbounded_tail<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> UResult<()> {
let stdout = stdout();
let mut writer = BufWriter::new(stdout.lock());
let mut writer = BufWriter::new(stdout().lock());
match &settings.mode {
FilterMode::Lines(Signum::Negative(count), sep) => {
let mut chunks = chunks::LinesChunkBuffer::new(*sep, *count);
Expand Down Expand Up @@ -459,6 +458,7 @@ fn unbounded_tail<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> UR
}
_ => {}
}
writer.flush()?;
Ok(())
}

Expand Down
Loading
Loading