93 lines
2.7 KiB
Rust
93 lines
2.7 KiB
Rust
const GLOBCHARS: &[u8] = &[b'?', b'*', b'[', b']'];
|
|
const GLOBSTARTS: &[u8] = &[b'?', b'*', b']'];
|
|
|
|
// prepare_pattern
|
|
//
|
|
// This functions finds the first substring of characters, starting from the end
|
|
// of the search string, that does not contain glob-special characters. It
|
|
// returns a vector of those characters for comparison. The test cases have all
|
|
// been derived from tests performed on the original 1983 `patprep` function
|
|
// found in locate.c.
|
|
|
|
// Unlike the original database, we're going to assume that this slice contains
|
|
// only the content of the pattern, and no nulls at either end, relying instead
|
|
// on Rust's tracking the size of slices internally.
|
|
|
|
fn hunt<F>(name: &[u8], end: usize, alt: usize, comp: F) -> usize
|
|
where
|
|
F: Fn(&u8) -> bool,
|
|
{
|
|
let mut p = end;
|
|
while p > 0 {
|
|
if comp(&name[p]) {
|
|
return p;
|
|
}
|
|
p -= 1;
|
|
}
|
|
return alt;
|
|
}
|
|
|
|
pub fn prepare_pattern(name: &[u8]) -> Vec<u8> {
|
|
let mut eol = name.len();
|
|
if eol == 0 {
|
|
panic!("Library error - This function should never be called with an empty string.")
|
|
}
|
|
|
|
// After this point, eol always points to the index from where we want to
|
|
// stop, not to the character beyond that.
|
|
|
|
eol = hunt(name, eol - 1, 0, |&c| c != b'*' && c != b'?');
|
|
if name[eol] == b']' {
|
|
eol = hunt(&name, eol - 1, 0, |&c| c == b'[');
|
|
eol = if eol > 0 { eol - 1 } else { 0 }
|
|
}
|
|
|
|
if eol == 0 {
|
|
return if GLOBCHARS.contains(&name[0]) {
|
|
vec![b'/']
|
|
} else {
|
|
vec![name[0]]
|
|
};
|
|
}
|
|
|
|
let start = hunt(&name, eol, 0, |&c| GLOBSTARTS.contains(&c));
|
|
let start = if GLOBSTARTS.contains(&name[start]) {
|
|
start + 1
|
|
} else {
|
|
start
|
|
};
|
|
if start > eol {
|
|
vec![b'/']
|
|
} else {
|
|
name[start..eol + 1].to_vec()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_patterns() {
|
|
assert_eq!(prepare_pattern(b"testing"), b"testing");
|
|
assert_eq!(prepare_pattern(b"t"), b"t");
|
|
assert_eq!(prepare_pattern(b"test*"), b"test");
|
|
assert_eq!(prepare_pattern(b"test*"), b"test");
|
|
assert_eq!(
|
|
prepare_pattern(b"/foo/bar/whatever[0-9]"),
|
|
b"/foo/bar/whatever"
|
|
);
|
|
assert_eq!(prepare_pattern(b"/foo/bar/whatever*[0-9]"), b"/");
|
|
assert_eq!(
|
|
prepare_pattern(b"/foo/bar/whatever[0-9]"),
|
|
b"/foo/bar/whatever"
|
|
);
|
|
assert_eq!(
|
|
prepare_pattern(b"/foo/bar/whatever[0-9]*"),
|
|
b"/foo/bar/whatever"
|
|
);
|
|
assert_eq!(prepare_pattern(b"/foo/bar/*whatever[0-9]"), b"whatever");
|
|
assert_eq!(prepare_pattern(b"fooz]"), b"f");
|
|
}
|
|
}
|