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
//! You can open files as part of parsing process too, might not be the best idea though
//! because depending on a context `bpaf` might need to evaluate some parsers multiple times.
//!
//! Main motivation for this example is that you can open a file as part of the argument parsing
//! and give a reader directly to user. In practice to replicate `cat`'s behavior you'd accept
//! multiple files with `many` and open them one by one in your code.

use bpaf::*;
use std::{
    ffi::OsString,
    fs::File,
    io::{stdin, BufRead, BufReader, Read},
};

fn main() {
    let file = positional::<OsString>("FILE")
        .help("File name to concatenate, with no FILE or when FILE is -, read standard input")
        .optional()
        .parse::<_, Box<dyn Read>, std::io::Error>(|path| {
            Ok(if let Some(path) = path {
                if path == "-" {
                    Box::new(stdin())
                } else {
                    Box::new(File::open(path)?)
                }
            } else {
                Box::new(stdin())
            })
        })
        .to_options()
        .descr("Concatenate a file to standard output")
        .run();

    let reader = BufReader::new(file);

    for line in reader.lines() {
        println!("{}", line.unwrap());
    }
}