1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

cat: Collect output state into a struct

This commit is contained in:
Erik Vesteraas 2017-01-23 11:07:47 +01:00
parent 81996915df
commit 21d9152cfe

View file

@ -292,6 +292,14 @@ fn write_fast(files: Vec<String>) -> CatResult<()> {
} }
} }
/// State that persists between output of each file
struct OutputState {
/// The current line number
line_number: usize,
/// Whether the output cursor is at the beginning of a new line
at_line_start: bool,
}
/// Writes files to stdout with `options` as configuration. Returns /// Writes files to stdout with `options` as configuration. Returns
/// `Ok(())` if no errors were encountered, or an error with the /// `Ok(())` if no errors were encountered, or an error with the
@ -302,19 +310,16 @@ fn write_fast(files: Vec<String>) -> CatResult<()> {
/// * `files` - There is no short circuit when encountiner an error /// * `files` - There is no short circuit when encountiner an error
/// reading a file in this vector /// reading a file in this vector
fn write_lines(files: Vec<String>, options: &OutputOptions) -> CatResult<()> { fn write_lines(files: Vec<String>, options: &OutputOptions) -> CatResult<()> {
let mut line_counter: usize = 1;
let mut error_count = 0; let mut error_count = 0;
let mut at_line_start = true; let mut state = OutputState {
line_number: 1,
at_line_start: true,
};
for file in files { for file in files {
let written = write_file_lines(&file[..], options, line_counter, &mut at_line_start); if let Err(error) = write_file_lines(&file, options, &mut state) {
line_counter += match written {
Ok(lines) => lines,
Err(error) => {
writeln!(&mut stderr(), "{}", error).context(&file[..])?; writeln!(&mut stderr(), "{}", error).context(&file[..])?;
error_count += 1; error_count += 1;
0
}
} }
} }
@ -324,20 +329,16 @@ fn write_lines(files: Vec<String>, options: &OutputOptions) -> CatResult<()> {
} }
} }
/// Outputs file and returns result with the number of lines to stdout /// Outputs file contents to stdout in a linewise fashion,
/// from `file`. If line numbering is enabled, then start output /// propagating any errors that might occur.
/// numbering at `line_number`.
fn write_file_lines(file: &str, fn write_file_lines(file: &str,
options: &OutputOptions, options: &OutputOptions,
line_number: usize, state: &mut OutputState) -> CatResult<()> {
at_line_start: &mut bool) -> CatResult<usize> { let mut handle = open(file)?;
let mut handle = open(&file[..])?;
let mut in_buf = [0; 1024 * 31]; let mut in_buf = [0; 1024 * 31];
let mut writer = BufWriter::with_capacity(1024 * 64, stdout()); let mut writer = BufWriter::with_capacity(1024 * 64, stdout());
let mut one_blank_kept = false; let mut one_blank_kept = false;
let mut lines = 0;
while let Ok(n) = handle.reader.read(&mut in_buf) { while let Ok(n) = handle.reader.read(&mut in_buf) {
if n == 0 { if n == 0 {
break; break;
@ -347,25 +348,25 @@ fn write_file_lines(file: &str,
while pos < n { while pos < n {
// skip empty line_number enumerating them if needed // skip empty line_number enumerating them if needed
if in_buf[pos] == '\n' as u8 { if in_buf[pos] == '\n' as u8 {
if !*at_line_start || ! options.squeeze_blank || !one_blank_kept { if !state.at_line_start || !options.squeeze_blank || !one_blank_kept {
one_blank_kept = true; one_blank_kept = true;
if *at_line_start && options.number == NumberingMode::NumberAll { if state.at_line_start && options.number == NumberingMode::NumberAll {
write!(&mut writer, "{0:6}\t", line_number + lines)?; write!(&mut writer, "{0:6}\t", state.line_number)?;
lines += 1; state.line_number += 1;
} }
writer.write_all(options.end_of_line.as_bytes())?; writer.write_all(options.end_of_line.as_bytes())?;
if handle.is_interactive { if handle.is_interactive {
writer.flush().context(&file[..])?; writer.flush().context(&file[..])?;
} }
} }
*at_line_start = true; state.at_line_start = true;
pos += 1; pos += 1;
continue; continue;
} }
one_blank_kept = false; one_blank_kept = false;
if *at_line_start && options.number != NumberingMode::NumberNone { if state.at_line_start && options.number != NumberingMode::NumberNone {
write!(&mut writer, "{0:6}\t", line_number + lines)?; write!(&mut writer, "{0:6}\t", state.line_number)?;
lines += 1; state.line_number += 1;
} }
// print to end of line or end of buffer // print to end of line or end of buffer
@ -378,7 +379,7 @@ fn write_file_lines(file: &str,
}; };
// end of buffer? // end of buffer?
if offset == 0 { if offset == 0 {
*at_line_start = false; state.at_line_start = false;
break; break;
} }
// print suitable end of line // print suitable end of line
@ -386,12 +387,12 @@ fn write_file_lines(file: &str,
if handle.is_interactive { if handle.is_interactive {
writer.flush()?; writer.flush()?;
} }
*at_line_start = true; state.at_line_start = true;
pos += offset; pos += offset;
} }
} }
Ok(lines) Ok(())
} }
// write***_to_end methods // write***_to_end methods