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(())
}