Skip to main content

linuxutils_text/
line.rs

1use linuxutils_common::man::ManContent;
2
3pub const MAN: ManContent = ManContent::empty();
4
5use clap::Parser;
6use std::{
7    io::{self, BufRead, Write},
8    process::ExitCode,
9};
10
11/// Read one line from standard input and write it to standard output.
12#[derive(Parser)]
13#[command(name = "line", version, about)]
14pub struct Args {}
15
16pub fn run(_args: Args) -> ExitCode {
17    let stdin = io::stdin();
18    let reader = stdin.lock();
19    let mut stdout = io::stdout().lock();
20
21    match line(reader, &mut stdout) {
22        Ok(true) => ExitCode::SUCCESS,
23        Ok(false) => ExitCode::from(1),
24        Err(e) => {
25            eprintln!("line: {e}");
26            ExitCode::FAILURE
27        }
28    }
29}
30
31/// Read one line from `reader` and write it to `writer`, followed by a newline.
32///
33/// Returns `true` if a line was read, `false` on EOF.
34pub fn line(
35    mut reader: impl BufRead,
36    writer: &mut impl Write,
37) -> io::Result<bool> {
38    let mut buf = String::new();
39    let bytes_read = reader.read_line(&mut buf)?;
40
41    // Strip the trailing newline if present — we always write our own.
42    let line = buf.trim_end_matches('\n').trim_end_matches('\r');
43    writeln!(writer, "{line}")?;
44
45    Ok(bytes_read > 0)
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn reads_first_line_only() {
54        let input = b"hello\nworld\n";
55        let mut output = Vec::new();
56        let ok = line(&input[..], &mut output).unwrap();
57        assert!(ok);
58        assert_eq!(output, b"hello\n");
59    }
60
61    #[test]
62    fn eof_returns_false() {
63        let input = b"";
64        let mut output = Vec::new();
65        let ok = line(&input[..], &mut output).unwrap();
66        assert!(!ok);
67        assert_eq!(output, b"\n");
68    }
69
70    #[test]
71    fn line_without_newline() {
72        let input = b"hello";
73        let mut output = Vec::new();
74        let ok = line(&input[..], &mut output).unwrap();
75        assert!(ok);
76        assert_eq!(output, b"hello\n");
77    }
78}