// Copyright (c) 2017 fd developers // Licensed under the Apache License, Version 2.0 // // or the MIT license , // at your option. All files in the project carrying such // notice may not be copied, modified, or distributed except // according to those terms. use regex_syntax::hir::Hir; use regex_syntax::Parser; use std::ffi::OsString; pub use self::file_types::FileTypes; mod file_types; pub mod filter; pub mod opts; macro_rules! print_error { ($($arg:tt)*) => (eprintln!($($arg)*)) } macro_rules! print_error_and_exit { ($($arg:tt)*) => { print_error!($($arg)*); ::std::process::exit(1); }; } /// Determine if a regex pattern contains a literal uppercase character. pub fn pattern_has_uppercase_char(pattern: &str) -> bool { Parser::new() .parse(pattern) .map(|hir| hir_has_uppercase_char(&hir)) .unwrap_or(false) } /// Determine if a regex expression contains a literal uppercase character. fn hir_has_uppercase_char(hir: &Hir) -> bool { use regex_syntax::hir::*; match *hir.kind() { HirKind::Literal(Literal::Unicode(c)) => c.is_uppercase(), HirKind::Class(Class::Unicode(ref ranges)) => ranges .iter() .any(|r| r.start().is_uppercase() || r.end().is_uppercase()), HirKind::Group(Group { ref hir, .. }) | HirKind::Repetition(Repetition { ref hir, .. }) => { hir_has_uppercase_char(hir) } HirKind::Concat(ref hirs) | HirKind::Alternation(ref hirs) => { hirs.iter().any(hir_has_uppercase_char) } _ => false, } } /// Maximum size of the output buffer before flushing results to the console pub const MAX_BUFFER_LENGTH: usize = 1000; /// Traverse args_os, looking for -exec and replacing it with --exec. /// /// # Returns /// /// * The args, with substitution if required pub fn transform_args_with_exec(original: I) -> Vec where I: Iterator, { let mut in_exec_opt = false; let target = OsString::from("-exec"); let long_start = OsString::from("--exec"); let short_start = OsString::from("-x"); let exec_end = OsString::from(";"); original.fold(vec![], |mut args, curr| { if in_exec_opt { if curr == exec_end { in_exec_opt = false; } args.push(curr); return args; } if curr == target || curr == long_start || curr == short_start { args.push(if curr == target { OsString::from("--exec") } else { curr }); in_exec_opt = true; } else { args.push(curr); } args }) } #[cfg(test)] mod tests { use super::*; fn oss(v: &str) -> OsString { OsString::from(v) } /// Ensure that -exec gets transformed into --exec #[test] fn normal_exec_substitution() { let original = vec![oss("fd"), oss("foo"), oss("-exec"), oss("cmd")]; let expected = vec![oss("fd"), oss("foo"), oss("--exec"), oss("cmd")]; let actual = transform_args_with_exec(original.into_iter()); assert_eq!(expected, actual); } /// Ensure that --exec is not touched #[test] fn passthru_of_original_exec() { let original = vec![oss("fd"), oss("foo"), oss("--exec"), oss("cmd")]; let expected = vec![oss("fd"), oss("foo"), oss("--exec"), oss("cmd")]; let actual = transform_args_with_exec(original.into_iter()); assert_eq!(expected, actual); } #[test] fn temp_check_that_exec_context_observed() { let original = vec![ oss("fd"), oss("foo"), oss("-exec"), oss("cmd"), oss("-exec"), oss("ls"), oss(";"), oss("-exec"), oss("rm"), oss(";"), oss("--exec"), oss("find"), oss("-exec"), oss("rm"), oss(";"), oss("-x"), oss("foo"), oss("-exec"), oss("something"), oss(";"), oss("-exec"), ]; let expected = vec![ oss("fd"), oss("foo"), oss("--exec"), oss("cmd"), oss("-exec"), oss("ls"), oss(";"), oss("--exec"), oss("rm"), oss(";"), oss("--exec"), oss("find"), oss("-exec"), oss("rm"), oss(";"), oss("-x"), oss("foo"), oss("-exec"), oss("something"), oss(";"), oss("--exec"), ]; let actual = transform_args_with_exec(original.into_iter()); assert_eq!(expected, actual); } }