1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use clap::clap_app;
use std::io::{stdout, Read, Write};

fn main() -> anyhow::Result<()> {
    let matches = clap_app!(my_app =>
        (version: "1.0")
        (author: "Ardente")
        (about: "Concatenates files and prints on the standard output")
        (@arg SHOW_ALL: -a --show_all "equivalent to -vET")
        (@arg NUMBER: -n --number "number all output lines")
        (@arg SHOW_ENDS: -E --show_ends "display $ at the end of each line")
        (@arg SHOW_NOPRINTING: -v --show_noprinting "use ^ and M- notation, except for LFD and TAB")
        (@arg FILE: +takes_value +multiple "File(s) to be concatenated to standard output; with no file or file is -, read standard input")
    ).get_matches();

    if !matches.is_present("FILE") || matches.value_of("FILE") == Some("-") {
        loop {
            let mut line = String::new();
            std::io::stdin().read_line(&mut line)?;

            print!("{}", line);
            std::io::stdout().flush()?;
        }
    } else if let Some(file_names) = matches.values_of("FILE") {
        for file_name in file_names {
            let file = std::fs::File::open(file_name);

            match file {
                Ok(mut file) => {
                    let mut file_text = vec![];
                    file.read_to_end(&mut file_text)?;

                    if matches.is_present("NUMBER") {
                        let count = file_text.split(|byte| *byte == b'\n').count();

                        file_text = file_text
                            .split(|byte| *byte == b'\n')
                            .enumerate()
                            .filter_map(|(number, line)| {
                                if file_text.ends_with(&[b'\n']) {
                                    if number != count - 1 {
                                        Some([format!("{:6}  ", number + 1).as_bytes(), line].concat())
                                    } else {
                                        None
                                    }
                                } else {
                                    Some([format!("{:6}  ", number + 1).as_bytes(), line].concat())
                                }
                            })
                            .enumerate()
                            .flat_map(|(number, line)| {
                                if !(file_text.ends_with(&[b'\n']) && number == count - 1) {
                                    [line, vec![b'\n']].concat()
                                } else {
                                    line
                                }
                            })
                            .collect();
                    }

                    stdout().write_all(&file_text)?;
                    std::io::stdout().flush()?;
                }
                Err(err) => {
                    eprintln!("rat: {}: {}", file_name, err)
                }
            }
        }
    }

    Ok(())
}