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
73
74
75
76
77
#![allow(dead_code)]
const HELP: &str = "\
USAGE: app [OPTIONS] --number NUMBER INPUT
OPTIONS:
--number NUMBER Set a number (required)
--opt-number NUMBER Set an optional number
--width WIDTH Set a width (non-zero, default 10)
ARGS:
<INPUT> Input file
";
#[derive(Debug)]
struct AppArgs {
number: u32,
opt_number: Option<u32>,
width: u32,
input: std::path::PathBuf,
}
fn parse_width(s: &str) -> Result<u32, String> {
let w = s.parse().map_err(|_| "not a number")?;
if w != 0 {
Ok(w)
} else {
Err("width must be positive".to_string())
}
}
fn main() {
let args = match parse_args() {
Ok(args) => args,
Err(err) => {
eprintln!("Error: {}.", err);
std::process::exit(1);
}
};
println!("{:#?}", args);
}
fn parse_args() -> Result<AppArgs, lexopt::Error> {
use lexopt::prelude::*;
let mut number = None;
let mut opt_number = None;
let mut width = 10;
let mut input = None;
let mut parser = lexopt::Parser::from_env();
while let Some(arg) = parser.next()? {
match arg {
Short('h') | Long("help") => {
print!("{}", HELP);
std::process::exit(0);
}
Long("number") => number = Some(parser.value()?.parse()?),
Long("opt-number") => opt_number = Some(parser.value()?.parse()?),
Long("width") => width = parser.value()?.parse_with(parse_width)?,
Value(path) if input.is_none() => input = Some(path.into()),
_ => return Err(arg.unexpected()),
}
}
Ok(AppArgs {
number: number.ok_or("missing required option --number")?,
opt_number,
width,
input: input.ok_or("missing required argument INPUT")?,
})
}