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