1use std::ffi::OsString;
2
3pub fn os_arg<'a>(args: &'a [OsString], index: usize, command: &str) -> Result<&'a str, String> {
4 args.get(index)
5 .and_then(|arg| arg.to_str())
6 .ok_or_else(|| format!("{command} arguments must be UTF-8"))
7}
8
9pub fn split_flag(token: &str) -> (&str, Option<&str>) {
10 token
11 .split_once('=')
12 .map_or((token, None), |(flag, value)| (flag, Some(value)))
13}
14
15pub fn flag_value(
16 args: &[OsString],
17 index: usize,
18 flag: &str,
19 inline_value: Option<&str>,
20 command: &str,
21) -> Result<(String, usize), String> {
22 if let Some(value) = inline_value {
23 return Ok((value.to_owned(), index + 1));
24 }
25 let value = os_arg(args, index + 1, command).map_err(|_| format!("{flag} requires a value"))?;
26 if value.starts_with("--") {
27 return Err(format!("{flag} requires a value"));
28 }
29 Ok((value.to_owned(), index + 2))
30}
31
32pub fn optional_flag_value(
33 args: &[OsString],
34 index: usize,
35 inline_value: Option<&str>,
36 command: &str,
37) -> Result<(Option<String>, usize), String> {
38 if let Some(value) = inline_value {
39 return Ok((Some(value.to_owned()), index + 1));
40 }
41 let Some(value) = args.get(index + 1).and_then(|arg| arg.to_str()) else {
42 return Ok((None, index + 1));
43 };
44 if value.starts_with('-') {
45 return Ok((None, index + 1));
46 }
47 os_arg(args, index + 1, command)?;
48 Ok((Some(value.to_owned()), index + 2))
49}
50
51pub fn optional_flag_value_or(
52 args: &[OsString],
53 index: usize,
54 inline_value: Option<&str>,
55 default_value: &str,
56 command: &str,
57) -> Result<(String, usize), String> {
58 if let Some(value) = inline_value {
59 if value.is_empty() {
60 return Ok((default_value.to_owned(), index + 1));
61 }
62 return Ok((value.to_owned(), index + 1));
63 }
64 match args.get(index + 1).and_then(|arg| arg.to_str()) {
65 Some(value) if !value.starts_with("--") => {
66 os_arg(args, index + 1, command)?;
67 Ok((value.to_owned(), index + 2))
68 }
69 _ => Ok((default_value.to_owned(), index + 1)),
70 }
71}