|
| 1 | +use clap::Parser; |
| 2 | +use std::error::Error; |
| 3 | +use std::fs::File; |
| 4 | +use std::io::{self, BufRead, BufReader}; |
| 5 | + |
| 6 | +type MyResult<T> = Result<T, Box<dyn Error>>; |
| 7 | + |
| 8 | +#[derive(Debug, Parser)] |
| 9 | +#[command(author, version, about)] |
| 10 | +/// Rust version of `cat` |
| 11 | +pub struct Args { |
| 12 | + /// Input file(s) |
| 13 | + #[arg(value_name = "FILE", default_value = "-")] |
| 14 | + files: Vec<String>, |
| 15 | + |
| 16 | + /// Number lines |
| 17 | + #[arg( |
| 18 | + short('n'), |
| 19 | + long("number"), |
| 20 | + conflicts_with("number_nonblank_lines") |
| 21 | + )] |
| 22 | + number_lines: bool, |
| 23 | + |
| 24 | + /// Number non-blank lines |
| 25 | + #[arg(short('b'), long("number-nonblank"))] |
| 26 | + number_nonblank_lines: bool, |
| 27 | +} |
| 28 | + |
| 29 | +// -------------------------------------------------- |
1 | 30 | fn main() { |
2 | | - if let Err(e) = catr::get_args().and_then(catr::run) { |
| 31 | + if let Err(e) = run(Args::parse()) { |
3 | 32 | eprintln!("{}", e); |
4 | 33 | std::process::exit(1); |
5 | 34 | } |
6 | 35 | } |
| 36 | + |
| 37 | +// -------------------------------------------------- |
| 38 | +pub fn run(args: Args) -> MyResult<()> { |
| 39 | + for filename in args.files { |
| 40 | + match open(&filename) { |
| 41 | + Err(e) => eprintln!("{}: {}", filename, e), |
| 42 | + Ok(file) => { |
| 43 | + let mut last_num = 0; |
| 44 | + for (line_num, line_result) in file.lines().enumerate() { |
| 45 | + let line = line_result?; |
| 46 | + if args.number_lines { |
| 47 | + println!("{:6}\t{}", line_num + 1, line); |
| 48 | + } else if args.number_nonblank_lines { |
| 49 | + if !line.is_empty() { |
| 50 | + last_num += 1; |
| 51 | + println!("{:6}\t{}", last_num, line); |
| 52 | + } else { |
| 53 | + println!(); |
| 54 | + } |
| 55 | + } else { |
| 56 | + println!("{}", line); |
| 57 | + } |
| 58 | + } |
| 59 | + } |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + Ok(()) |
| 64 | +} |
| 65 | + |
| 66 | +// -------------------------------------------------- |
| 67 | +fn open(filename: &str) -> MyResult<Box<dyn BufRead>> { |
| 68 | + match filename { |
| 69 | + "-" => Ok(Box::new(BufReader::new(io::stdin()))), |
| 70 | + _ => Ok(Box::new(BufReader::new(File::open(filename)?))), |
| 71 | + } |
| 72 | +} |
0 commit comments