diff options
Diffstat (limited to 'grep-printer/src')
-rw-r--r-- | grep-printer/src/standard.rs | 59 | ||||
-rw-r--r-- | grep-printer/src/summary.rs | 28 |
2 files changed, 85 insertions, 2 deletions
diff --git a/grep-printer/src/standard.rs b/grep-printer/src/standard.rs index 6ead1db6..068f96a4 100644 --- a/grep-printer/src/standard.rs +++ b/grep-printer/src/standard.rs @@ -5,6 +5,7 @@ use std::path::Path; use std::sync::Arc; use std::time::Instant; +use bstr::BStr; use grep_matcher::{Match, Matcher}; use grep_searcher::{ LineStep, Searcher, @@ -743,6 +744,11 @@ impl<'p, 's, M: Matcher, W: WriteColor> Sink for StandardSink<'p, 's, M, W> { stats.add_matches(self.standard.matches.len() as u64); stats.add_matched_lines(mat.lines().count() as u64); } + if searcher.binary_detection().convert_byte().is_some() { + if self.binary_byte_offset.is_some() { + return Ok(false); + } + } StandardImpl::from_match(searcher, self, mat).sink()?; Ok(!self.should_quit()) @@ -764,6 +770,12 @@ impl<'p, 's, M: Matcher, W: WriteColor> Sink for StandardSink<'p, 's, M, W> { self.record_matches(ctx.bytes())?; self.replace(ctx.bytes())?; } + if searcher.binary_detection().convert_byte().is_some() { + if self.binary_byte_offset.is_some() { + return Ok(false); + } + } + StandardImpl::from_context(searcher, self, ctx).sink()?; Ok(!self.should_quit()) } @@ -776,6 +788,15 @@ impl<'p, 's, M: Matcher, W: WriteColor> Sink for StandardSink<'p, 's, M, W> { Ok(true) } + fn binary_data( + &mut self, + _searcher: &Searcher, + binary_byte_offset: u64, + ) -> Result<bool, io::Error> { + self.binary_byte_offset = Some(binary_byte_offset); + Ok(true) + } + fn begin( &mut self, _searcher: &Searcher, @@ -793,10 +814,12 @@ impl<'p, 's, M: Matcher, W: WriteColor> Sink for StandardSink<'p, 's, M, W> { fn finish( &mut self, - _searcher: &Searcher, + searcher: &Searcher, finish: &SinkFinish, ) -> Result<(), io::Error> { - self.binary_byte_offset = finish.binary_byte_offset(); + if let Some(offset) = self.binary_byte_offset { + StandardImpl::new(searcher, self).write_binary_message(offset)?; + } if let Some(stats) = self.stats.as_mut() { stats.add_elapsed(self.start_time.elapsed()); stats.add_searches(1); @@ -1314,6 +1337,38 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> { Ok(()) } + fn write_binary_message(&self, offset: u64) -> io::Result<()> { + if self.sink.match_count == 0 { + return Ok(()); + } + + let bin = self.searcher.binary_detection(); + if let Some(byte) = bin.quit_byte() { + self.write(b"WARNING: stopped searching binary file ")?; + if let Some(path) = self.path() { + self.write_spec(self.config().colors.path(), path.as_bytes())?; + self.write(b" ")?; + } + let remainder = format!( + "after match (found {:?} byte around offset {})\n", + BStr::new(&[byte]), offset, + ); + self.write(remainder.as_bytes())?; + } else if let Some(byte) = bin.convert_byte() { + self.write(b"Binary file ")?; + if let Some(path) = self.path() { + self.write_spec(self.config().colors.path(), path.as_bytes())?; + self.write(b" ")?; + } + let remainder = format!( + "matches (found {:?} byte around offset {})\n", + BStr::new(&[byte]), offset, + ); + self.write(remainder.as_bytes())?; + } + Ok(()) + } + fn write_context_separator(&self) -> io::Result<()> { if let Some(ref sep) = *self.config().separator_context { self.write(sep)?; diff --git a/grep-printer/src/summary.rs b/grep-printer/src/summary.rs index deb7e609..a1c7785e 100644 --- a/grep-printer/src/summary.rs +++ b/grep-printer/src/summary.rs @@ -636,6 +636,34 @@ impl<'p, 's, M: Matcher, W: WriteColor> Sink for SummarySink<'p, 's, M, W> { stats.add_bytes_searched(finish.byte_count()); stats.add_bytes_printed(self.summary.wtr.borrow().count()); } + // If our binary detection method says to quit after seeing binary + // data, then we shouldn't print any results at all, even if we've + // found a match before detecting binary data. The intent here is to + // keep BinaryDetection::quit as a form of filter. Otherwise, we can + // present a matching file with a smaller number of matches than + // there might be, which can be quite misleading. + // + // If our binary detection method is to convert binary data, then we + // don't quit and therefore search the entire contents of the file. + // + // There is an unfortunate inconsistency here. Namely, when using + // Quiet or PathWithMatch, then the printer can quit after the first + // match seen, which could be long before seeing binary data. This + // means that using PathWithMatch can print a path where as using + // Count might not print it at all because of binary data. + // + // It's not possible to fix this without also potentially significantly + // impacting the performance of Quiet or PathWithMatch, so we accept + // the bug. + if self.binary_byte_offset.is_some() + && searcher.binary_detection().quit_byte().is_some() + { + // Squash the match count. The statistics reported will still + // contain the match count, but the "official" match count should + // be zero. + self.match_count = 0; + return Ok(()); + } let show_count = !self.summary.config.exclude_zero |