1use std::path::PathBuf;
2
3pub enum GlobOutput {
4 Arg(PathBuf),
5 Args(Vec<PathBuf>),
6}
7
8pub fn expand_glob(pat: impl Into<PathBuf>) -> GlobOutput {
9 let pat: PathBuf = pat.into();
10 let mut files = Vec::new();
11 if let Ok(paths) = glob::glob(&pat.to_string_lossy()) {
12 for p in paths {
13 match p {
14 Ok(p) => {
15 files.push(p);
16 }
17 Err(err) => {
18 eprintln!("glob error while iterating {}, {}", pat.display(), err);
19 }
20 }
21 }
22 if files.is_empty() {
23 if pat.to_str().unwrap_or("").contains('\\') {
25 GlobOutput::Arg(remove_escapes(pat.to_str().unwrap_or("")).into())
26 } else {
27 GlobOutput::Arg(pat)
28 }
29 } else if pat.starts_with("./") {
30 GlobOutput::Args(
31 files
32 .iter()
33 .cloned()
34 .map(|f| {
35 let mut nf = PathBuf::new();
36 nf.push("./");
37 nf.push(f);
38 nf
39 })
40 .collect(),
41 )
42 } else {
43 GlobOutput::Args(files)
44 }
45 } else if pat.to_str().unwrap_or("").contains('\\') {
46 GlobOutput::Arg(remove_escapes(pat.to_str().unwrap_or("")).into())
47 } else {
48 GlobOutput::Arg(pat)
49 }
50}
51
52fn remove_escapes(pat: &str) -> String {
53 let mut ret = String::new();
54 let mut last_esc = false;
55 for ch in pat.chars() {
56 match ch {
57 '\\' if last_esc => {
58 ret.push('\\');
59 last_esc = false;
60 }
61 '\\' => last_esc = true,
62 '*' if last_esc => {
63 ret.push('*');
64 last_esc = false;
65 }
66 '?' if last_esc => {
67 ret.push('?');
68 last_esc = false;
69 }
70 '[' if last_esc => {
71 ret.push('[');
72 last_esc = false;
73 }
74 ']' if last_esc => {
75 ret.push(']');
76 last_esc = false;
77 }
78 _ => {
79 if last_esc {
80 ret.push('\\');
81 }
82 ret.push(ch);
83 last_esc = false;
84 }
85 }
86 }
87 ret
88}