rlocate/crates/squozen/src/prepare_pattern.rs

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");
}
}