pub fn glob_match(pat: &[u8], s: &[u8]) -> bool {
let (mut pi, mut si) = (0usize, 0usize);
let (mut star, mut match_si): (Option<usize>, usize) = (None, 0);
while si < s.len() {
if pi < pat.len() && (pat[pi] == b'?' || pat[pi] == s[si]) {
pi += 1;
si += 1;
} else if pi < pat.len() && pat[pi] == b'*' {
star = Some(pi);
match_si = si;
pi += 1;
} else if let Some(sp) = star {
pi = sp + 1;
match_si += 1;
si = match_si;
} else {
return false;
}
}
while pi < pat.len() && pat[pi] == b'*' {
pi += 1;
}
pi == pat.len()
}
#[inline]
pub fn name_matches_extension(name: &[u8], ext: &[u8]) -> bool {
if name.len() <= ext.len() {
return false;
}
let dot_idx = name.len() - ext.len() - 1;
if name[dot_idx] != b'.' {
return false;
}
let suffix = &name[dot_idx + 1..];
for (a, b) in suffix.iter().zip(ext.iter()) {
if a.to_ascii_lowercase() != *b {
return false;
}
}
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn glob_basic() {
assert!(glob_match(b"*.txt", b"foo.txt"));
assert!(glob_match(b"file_00*", b"file_001.dat"));
assert!(!glob_match(b"file_00*", b"file_010.dat"));
assert!(glob_match(b"*", b"anything"));
assert!(glob_match(b"foo?bar", b"foo_bar"));
assert!(!glob_match(b"foo?bar", b"foo__bar"));
assert!(glob_match(b"a*b*c", b"axxbyyc"));
assert!(!glob_match(b"abc", b"abcd"));
}
#[test]
fn ext_match() {
assert!(name_matches_extension(b"foo.jpg", b"jpg"));
assert!(name_matches_extension(b"foo.JPG", b"jpg"));
assert!(!name_matches_extension(b"foo.jpeg", b"jpg"));
assert!(!name_matches_extension(b"foojpg", b"jpg"));
assert!(!name_matches_extension(b"jpg", b"jpg"));
assert!(name_matches_extension(b"a.b.c", b"c"));
}
}