Skip to content

Commit 665999d

Browse files
Clean up previous commit
1 parent 12d86e8 commit 665999d

File tree

1 file changed

+54
-41
lines changed

1 file changed

+54
-41
lines changed

text/tail.rs

Lines changed: 54 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ use std::collections::VecDeque;
88
use std::error::Error;
99
use std::fmt::Display;
1010
use std::fs::File;
11-
use std::io::{self, BufRead, BufReader, ErrorKind, Read, Seek, SeekFrom, StdoutLock, Write};
11+
use std::io::{
12+
self, BufRead, BufReader, ErrorKind, Read, Seek, SeekFrom, StdinLock, StdoutLock, Write,
13+
};
1214
use std::path::PathBuf;
1315
use std::str::FromStr;
1416
use std::sync::mpsc;
1517
use std::time::Duration;
1618

17-
#[derive(Clone)]
1819
enum RelativeFrom {
1920
StartOfFile(usize),
2021
EndOfFile(usize),
@@ -75,6 +76,7 @@ impl FromStr for RelativeFrom {
7576
}
7677

7778
/// tail - copy the last part of a file
79+
/// If neither -n nor -c are specified, copies the last 10 lines (-n 10).
7880
#[derive(Parser)]
7981
#[command(version, about)]
8082
struct Args {
@@ -120,6 +122,24 @@ impl Args {
120122
}
121123
}
122124

125+
enum FileOrStdin {
126+
File(PathBuf, BufReader<File>),
127+
Stdin(StdinLock<'static>),
128+
}
129+
130+
impl FileOrStdin {
131+
fn get_buf_read(&mut self) -> &mut dyn BufRead {
132+
match self {
133+
Self::File(_, ref mut bu) => bu,
134+
Self::Stdin(ref mut st) => st,
135+
}
136+
}
137+
}
138+
139+
fn print_bytes(stdout_lock: &mut StdoutLock, bytes: &[u8]) -> io::Result<()> {
140+
stdout_lock.write_all(bytes)
141+
}
142+
123143
fn print_n_lines<R: Read + BufRead>(
124144
stdout_lock: &mut StdoutLock,
125145
read: &mut R,
@@ -263,7 +283,7 @@ fn print_n_bytes<R: Read>(
263283
let mut buffer_1 = vec![0_u8; n];
264284

265285
// Buffer to store the last `n` bytes read.
266-
let mut buffer_2 = vec![];
286+
let mut buffer_2 = Vec::<u8>::new();
267287

268288
// Continuously read bytes into buffer_1.
269289
loop {
@@ -334,19 +354,12 @@ fn print_n_bytes<R: Read>(
334354
Ok(())
335355
}
336356

337-
fn print_bytes(stdout_lock: &mut StdoutLock, bytes: &[u8]) -> io::Result<()> {
338-
stdout_lock.write_all(bytes)
339-
}
340-
341357
/// The main logic for the `tail` command.
342358
///
343359
/// This function processes the command-line arguments to determine how many lines or bytes
344360
/// to print from the end of a specified file or standard input. It supports an option to
345361
/// follow the file, printing new data as it is appended to the file.
346362
///
347-
/// # Arguments
348-
/// * `args` - The command-line arguments parsed into an `Args` struct.
349-
///
350363
/// # Returns
351364
/// * `Ok(())` - If the operation completes successfully.
352365
/// * `Err(Box<dyn std::error::Error>)` - If an error occurs during the operation.
@@ -356,54 +369,54 @@ fn print_bytes(stdout_lock: &mut StdoutLock, bytes: &[u8]) -> io::Result<()> {
356369
/// - The specified file cannot be opened.
357370
/// - An error occurs while reading from the file or stdin.
358371
/// - An error occurs while watching the file for changes.
359-
///
360372
fn tail(
361373
file: Option<PathBuf>,
362374
follow: bool,
363375
bytes_or_lines: BytesOrLines,
364376
) -> Result<(), Box<dyn Error>> {
365-
fn get_stdin() -> (Box<dyn Read>, bool) {
366-
(Box::new(io::stdin().lock()), false)
377+
fn get_stdin() -> FileOrStdin {
378+
FileOrStdin::Stdin(io::stdin().lock())
367379
}
368380

369-
// open file, or stdin
370-
let (box_dyn_read, reading_from_file): (Box<dyn Read>, bool) = match &file {
381+
let mut file_or_stdin = match file {
371382
Some(pa) => {
372383
if pa.as_os_str() == "-" {
373384
get_stdin()
374385
} else {
375-
(Box::new(File::open(pa)?), true)
386+
let fi = File::open(pa.as_path())?;
387+
388+
FileOrStdin::File(pa, BufReader::new(fi))
376389
}
377390
}
378391
None => get_stdin(),
379392
};
380393

381-
let mut buf_reader = io::BufReader::new(box_dyn_read);
382-
383394
let mut stdout_lock = io::stdout().lock();
384395

385-
match bytes_or_lines {
386-
BytesOrLines::Bytes(re) => {
387-
print_n_bytes(&mut stdout_lock, &mut buf_reader, re)?;
388-
}
389-
BytesOrLines::Lines(re) => {
390-
print_n_lines(&mut stdout_lock, &mut buf_reader, re)?;
396+
{
397+
let mut buf_reader = file_or_stdin.get_buf_read();
398+
399+
match bytes_or_lines {
400+
BytesOrLines::Bytes(re) => {
401+
print_n_bytes(&mut stdout_lock, &mut buf_reader, re)?;
402+
}
403+
BytesOrLines::Lines(re) => {
404+
print_n_lines(&mut stdout_lock, &mut buf_reader, re)?;
405+
}
391406
}
392407
}
393408

394-
// If follow option is specified, continue monitoring the file
395-
if let Some(pa) = file {
396-
if follow && reading_from_file {
397-
// Opening a file and placing the cursor at the end of the file
398-
let mut file = File::open(pa.as_path())?;
399-
file.seek(SeekFrom::End(0))?;
400-
401-
let mut reader = BufReader::new(&file);
409+
if follow {
410+
// If follow option is specified, continue monitoring the file
411+
if let FileOrStdin::File(pa, mut bu) = file_or_stdin {
412+
// Move the the cursor to the end of the file
413+
// Is this still necessary now that the `BufReader` and underlying `File` are being reused?
414+
bu.seek(SeekFrom::End(0_i64))?;
402415

403416
let (tx, rx) = mpsc::channel();
404417

405418
// Automatically select the best implementation for your platform.
406-
let mut debouncer = new_debouncer(Duration::from_millis(1), None, tx).unwrap();
419+
let mut debouncer = new_debouncer(Duration::from_millis(1_u64), None, tx).unwrap();
407420

408421
// Add a path to be watched.
409422
// below will be monitored for changes.
@@ -420,19 +433,19 @@ fn tail(
420433
| EventKind::Modify(ModifyKind::Data(_))
421434
| EventKind::Modify(ModifyKind::Other) => {
422435
// If the file has been modified, check if the file was truncated
423-
let metadata = file.metadata()?;
436+
let metadata = bu.get_mut().metadata()?;
424437
let current_size = metadata.len();
425438

426-
if current_size < reader.stream_position()? {
439+
if current_size < bu.stream_position()? {
427440
eprintln!("\ntail: {}: file truncated", pa.display());
428441

429-
reader.seek(SeekFrom::Start(0_u64))?;
442+
bu.seek(SeekFrom::Start(0_u64))?;
430443
}
431444

432445
// Read the new lines and output them
433-
let mut new_data = vec![];
446+
let mut new_data = Vec::<u8>::new();
434447

435-
let bytes_read = reader.read_to_end(&mut new_data)?;
448+
let bytes_read = bu.read_to_end(&mut new_data)?;
436449

437450
if bytes_read > 0_usize {
438451
print_bytes(&mut stdout_lock, &new_data)?;
@@ -447,7 +460,7 @@ fn tail(
447460
}
448461
}
449462
Err(ve) => {
450-
eprintln!("watch error: {ve:?}");
463+
eprintln!("tail: watch error: {ve:?}");
451464
}
452465
}
453466
}
@@ -473,10 +486,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
473486
}
474487
};
475488

476-
let mut exit_code = 0;
489+
let mut exit_code = 0_i32;
477490

478491
if let Err(er) = tail(args.file, args.follow, bytes_or_lines) {
479-
exit_code = 1;
492+
exit_code = 1_i32;
480493

481494
eprintln!("tail: {}", er);
482495
}

0 commit comments

Comments
 (0)