summaryrefslogtreecommitdiffstats
path: root/src/worker.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/worker.rs')
-rw-r--r--src/worker.rs397
1 files changed, 0 insertions, 397 deletions
diff --git a/src/worker.rs b/src/worker.rs
deleted file mode 100644
index cd8b81d2..00000000
--- a/src/worker.rs
+++ /dev/null
@@ -1,397 +0,0 @@
-use std::fs::File;
-use std::io;
-use std::path::{Path, PathBuf};
-
-use encoding_rs::Encoding;
-use grep::Grep;
-use ignore::DirEntry;
-use memmap::Mmap;
-use termcolor::WriteColor;
-
-// use decoder::DecodeReader;
-use encoding_rs_io::DecodeReaderBytesBuilder;
-use decompressor::{self, DecompressionReader};
-use preprocessor::PreprocessorReader;
-use pathutil::strip_prefix;
-use printer::Printer;
-use search_buffer::BufferSearcher;
-use search_stream::{InputBuffer, Searcher};
-
-use Result;
-
-pub enum Work {
- Stdin,
- DirEntry(DirEntry),
-}
-
-pub struct WorkerBuilder {
- grep: Grep,
- opts: Options,
-}
-
-#[derive(Clone, Debug)]
-struct Options {
- mmap: bool,
- encoding: Option<&'static Encoding>,
- after_context: usize,
- before_context: usize,
- byte_offset: bool,
- count: bool,
- count_matches: bool,
- files_with_matches: bool,
- files_without_matches: bool,
- eol: u8,
- invert_match: bool,
- line_number: bool,
- max_count: Option<u64>,
- quiet: bool,
- text: bool,
- preprocessor: Option<PathBuf>,
- search_zip_files: bool
-}
-
-impl Default for Options {
- fn default() -> Options {
- Options {
- mmap: false,
- encoding: None,
- after_context: 0,
- before_context: 0,
- byte_offset: false,
- count: false,
- count_matches: false,
- files_with_matches: false,
- files_without_matches: false,
- eol: b'\n',
- invert_match: false,
- line_number: false,
- max_count: None,
- quiet: false,
- text: false,
- search_zip_files: false,
- preprocessor: None,
- }
- }
-}
-
-impl WorkerBuilder {
- /// Create a new builder for a worker.
- ///
- /// A reusable input buffer and a grep matcher are required, but there
- /// are numerous additional options that can be configured on this builder.
- pub fn new(grep: Grep) -> WorkerBuilder {
- WorkerBuilder {
- grep: grep,
- opts: Options::default(),
- }
- }
-
- /// Create the worker from this builder.
- pub fn build(self) -> Worker {
- let mut inpbuf = InputBuffer::new();
- inpbuf.eol(self.opts.eol);
- Worker {
- grep: self.grep,
- inpbuf: inpbuf,
- decodebuf: vec![0; 8 * (1<<10)],
- opts: self.opts,
- }
- }
-
- /// The number of contextual lines to show after each match. The default
- /// is zero.
- pub fn after_context(mut self, count: usize) -> Self {
- self.opts.after_context = count;
- self
- }
-
- /// The number of contextual lines to show before each match. The default
- /// is zero.
- pub fn before_context(mut self, count: usize) -> Self {
- self.opts.before_context = count;
- self
- }
-
- /// If enabled, searching will print a 0-based offset of the
- /// matching line (or the actual match if -o is specified) before
- /// printing the line itself.
- ///
- /// Disabled by default.
- pub fn byte_offset(mut self, yes: bool) -> Self {
- self.opts.byte_offset = yes;
- self
- }
-
- /// If enabled, searching will print a count instead of each match.
- ///
- /// Disabled by default.
- pub fn count(mut self, yes: bool) -> Self {
- self.opts.count = yes;
- self
- }
-
- /// If enabled, searching will print the count of individual matches
- /// instead of each match.
- ///
- /// Disabled by default.
- pub fn count_matches(mut self, yes: bool) -> Self {
- self.opts.count_matches = yes;
- self
- }
-
- /// Set the encoding to use to read each file.
- ///
- /// If the encoding is `None` (the default), then the encoding is
- /// automatically detected on a best-effort per-file basis.
- pub fn encoding(mut self, enc: Option<&'static Encoding>) -> Self {
- self.opts.encoding = enc;
- self
- }
-
- /// If enabled, searching will print the path instead of each match.
- ///
- /// Disabled by default.
- pub fn files_with_matches(mut self, yes: bool) -> Self {
- self.opts.files_with_matches = yes;
- self
- }
-
- /// If enabled, searching will print the path of files without any matches.
- ///
- /// Disabled by default.
- pub fn files_without_matches(mut self, yes: bool) -> Self {
- self.opts.files_without_matches = yes;
- self
- }
-
- /// Set the end-of-line byte used by this searcher.
- pub fn eol(mut self, eol: u8) -> Self {
- self.opts.eol = eol;
- self
- }
-
- /// If enabled, matching is inverted so that lines that *don't* match the
- /// given pattern are treated as matches.
- pub fn invert_match(mut self, yes: bool) -> Self {
- self.opts.invert_match = yes;
- self
- }
-
- /// If enabled, compute line numbers and prefix each line of output with
- /// them.
- pub fn line_number(mut self, yes: bool) -> Self {
- self.opts.line_number = yes;
- self
- }
-
- /// Limit the number of matches to the given count.
- ///
- /// The default is None, which corresponds to no limit.
- pub fn max_count(mut self, count: Option<u64>) -> Self {
- self.opts.max_count = count;
- self
- }
-
- /// If enabled, try to use memory maps for searching if possible.
- pub fn mmap(mut self, yes: bool) -> Self {
- self.opts.mmap = yes;
- self
- }
-
- /// If enabled, don't show any output and quit searching after the first
- /// match is found.
- pub fn quiet(mut self, yes: bool) -> Self {
- self.opts.quiet = yes;
- self
- }
-
- /// If enabled, search binary files as if they were text.
- pub fn text(mut self, yes: bool) -> Self {
- self.opts.text = yes;
- self
- }
-
- /// If enabled, search through compressed files as well
- pub fn search_zip_files(mut self, yes: bool) -> Self {
- self.opts.search_zip_files = yes;
- self
- }
-
- /// If non-empty, search output of preprocessor run on each file
- pub fn preprocessor(mut self, command: Option<PathBuf>) -> Self {
- self.opts.preprocessor = command;
- self
- }
-}
-
-/// Worker is responsible for executing searches on file paths, while choosing
-/// streaming search or memory map search as appropriate.
-pub struct Worker {
- grep: Grep,
- inpbuf: InputBuffer,
- decodebuf: Vec<u8>,
- opts: Options,
-}
-
-impl Worker {
- /// Execute the worker with the given printer and work item.
- ///
- /// A work item can either be stdin or a file path.
- pub fn run<W: WriteColor>(
- &mut self,
- printer: &mut Printer<W>,
- work: Work,
- ) -> u64 {
- let result = match work {
- Work::Stdin => {
- let stdin = io::stdin();
- let stdin = stdin.lock();
- self.search(printer, Path::new("<stdin>"), stdin)
- }
- Work::DirEntry(dent) => {
- let mut path = dent.path();
- if self.opts.preprocessor.is_some() {
- let cmd = self.opts.preprocessor.clone().unwrap();
- match PreprocessorReader::from_cmd_path(cmd, path) {
- Ok(reader) => self.search(printer, path, reader),
- Err(err) => {
- message!("{}", err);
- return 0;
- }
- }
- } else if self.opts.search_zip_files
- && decompressor::is_compressed(path)
- {
- match DecompressionReader::from_path(path) {
- Some(reader) => self.search(printer, path, reader),
- None => {
- return 0;
- }
- }
- } else {
- let file = match File::open(path) {
- Ok(file) => file,
- Err(err) => {
- message!("{}: {}", path.display(), err);
- return 0;
- }
- };
- if let Some(p) = strip_prefix("./", path) {
- path = p;
- }
- if self.opts.mmap {
- self.search_mmap(printer, path, &file)
- } else {
- self.search(printer, path, file)
- }
- }
- }
- };
- match result {
- Ok(count) => {
- count
- }
- Err(err) => {
- message!("{}", err);
- 0
- }
- }
- }
-
- fn search<R: io::Read, W: WriteColor>(
- &mut self,
- printer: &mut Printer<W>,
- path: &Path,
- rdr: R,
- ) -> Result<u64> {
- let rdr = DecodeReaderBytesBuilder::new()
- .encoding(self.opts.encoding)
- .utf8_passthru(true)
- .build_with_buffer(rdr, &mut self.decodebuf)?;
- let searcher = Searcher::new(
- &mut self.inpbuf, printer, &self.grep, path, rdr);
- searcher
- .after_context(self.opts.after_context)
- .before_context(self.opts.before_context)
- .byte_offset(self.opts.byte_offset)
- .count(self.opts.count)
- .count_matches(self.opts.count_matches)
- .files_with_matches(self.opts.files_with_matches)
- .files_without_matches(self.opts.files_without_matches)
- .eol(self.opts.eol)
- .line_number(self.opts.line_number)
- .invert_match(self.opts.invert_match)
- .max_count(self.opts.max_count)
- .quiet(self.opts.quiet)
- .text(self.opts.text)
- .run()
- .map_err(From::from)
- }
-
- fn search_mmap<W: WriteColor>(
- &mut self,
- printer: &mut Printer<W>,
- path: &Path,
- file: &File,
- ) -> Result<u64> {
- if file.metadata()?.len() == 0 {
- // Opening a memory map with an empty file results in an error.
- // However, this may not actually be an empty file! For example,
- // /proc/cpuinfo reports itself as an empty file, but it can
- // produce data when it's read from. Therefore, we fall back to
- // regular read calls.
- return self.search(printer, path, file);
- }
- let mmap = match self.mmap(file)? {
- None => return self.search(printer, path, file),
- Some(mmap) => mmap,
- };
- let buf = &*mmap;
- if buf.len() >= 3 && Encoding::for_bom(buf).is_some() {
- // If we have a UTF-16 bom in our memory map, then we need to fall
- // back to the stream reader, which will do transcoding.
- return self.search(printer, path, file);
- }
- let searcher = BufferSearcher::new(printer, &self.grep, path, buf);
- Ok(searcher
- .byte_offset(self.opts.byte_offset)
- .count(self.opts.count)
- .count_matches(self.opts.count_matches)
- .files_with_matches(self.opts.files_with_matches)
- .files_without_matches(self.opts.files_without_matches)
- .eol(self.opts.eol)
- .line_number(self.opts.line_number)
- .invert_match(self.opts.invert_match)
- .max_count(self.opts.max_count)
- .quiet(self.opts.quiet)
- .text(self.opts.text)
- .run())
- }
-
- #[cfg(not(unix))]
- fn mmap(&self, file: &File) -> Result<Option<Mmap>> {
- Ok(Some(mmap_readonly(file)?))
- }
-
- #[cfg(unix)]
- fn mmap(&self, file: &File) -> Result<Option<Mmap>> {
- use libc::{EOVERFLOW, ENODEV, ENOMEM};
-
- let err = match mmap_readonly(file) {
- Ok(mmap) => return Ok(Some(mmap)),
- Err(err) => err,
- };
- let code = err.raw_os_error();
- if code == Some(EOVERFLOW)
- || code == Some(ENODEV)
- || code == Some(ENOMEM)
- {
- return Ok(None);
- }
- Err(From::from(err))
- }
-}
-
-fn mmap_readonly(file: &File) -> io::Result<Mmap> {
- unsafe { Mmap::map(file) }
-}