diff options
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/errors.rs | 5 | ||||
| -rw-r--r-- | src/filters.rs | 19 | ||||
| -rw-r--r-- | src/main.rs | 62 | 
4 files changed, 67 insertions, 20 deletions
| @@ -15,3 +15,4 @@ chrono = "0.4"  rayon = "1"  num-traits = "0.2"  humantime = "1.1" +zip = "0.5" diff --git a/src/errors.rs b/src/errors.rs index 7cb1886..286a92e 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -14,5 +14,10 @@ quick_error! {              cause(err)              display("I/O error: {}", err)          } +        Parsing(err: evtclib::raw::ParseError) { +            from() +            cause(err) +            display("Parsing error: {}", err) +        }      }  } diff --git a/src/filters.rs b/src/filters.rs index d8d43ea..8433690 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -1,16 +1,21 @@ -use evtclib::{AgentName, Log}; +use evtclib::{Agent, AgentName}; +use evtclib::raw::parser::PartialEvtc;  use super::{SearchField, LogResult, Opt};  use chrono::Datelike;  /// Do filtering based on the character or account name. -pub fn filter_name(log: &Log, opt: &Opt) -> bool { -    for player in log.players() { -        match player.name() { +pub fn filter_name(evtc: &PartialEvtc, opt: &Opt) -> bool { +    for player in &evtc.agents { +        let fancy = Agent::from_raw(player); +        if fancy.is_err() { +            continue; +        } +        match fancy.unwrap().name() {              AgentName::Player { -                account_name, -                character_name, +                ref account_name, +                ref character_name,                  ..              } => {                  if (opt.field.contains(&SearchField::Account) && opt.expression.is_match(account_name)) @@ -19,7 +24,7 @@ pub fn filter_name(log: &Log, opt: &Opt) -> bool {                      return true;                  }              } -            _ => unreachable!(), +            _ => (),          }      }      false diff --git a/src/main.rs b/src/main.rs index 099262c..87ebbb0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,9 +9,10 @@ extern crate num_traits;  extern crate rayon;  extern crate regex;  extern crate walkdir; +extern crate zip;  use std::fs::File; -use std::io::{self, BufReader}; +use std::io::{self, BufReader, Read, Seek};  use std::path::PathBuf;  use std::str::FromStr; @@ -220,6 +221,30 @@ fn try_from_str_simple_error<T: FromStr>(input: &str) -> Result<T, String>      T::from_str(input).map_err(|_| format!("'{}' is an invalid value", input))  } + +enum ZipWrapper<R: Read + Seek> { +    Raw(Option<R>), +    Zipped(zip::ZipArchive<R>), +} + +impl<R: Read + Seek> ZipWrapper<R> { +    pub fn raw(input: R) -> Self { +        ZipWrapper::Raw(Some(input)) +    } + +    pub fn zipped(input: R) -> Self { +        ZipWrapper::Zipped(zip::ZipArchive::new(input).unwrap()) +    } + +    pub fn get_stream<'a>(&'a mut self) -> Box<(dyn Read + 'a)> { +        match *self { +            ZipWrapper::Raw(ref mut o) => Box::new(o.take().unwrap()), +            ZipWrapper::Zipped(ref mut z) => Box::new(z.by_index(0).unwrap()), +        } +    } +} + +  fn main() {      let opt = Opt::from_args(); @@ -258,8 +283,13 @@ fn grep(opt: &Opt) -> Result<(), RuntimeError> {              let entry = entry?;              s.spawn(move |_| {                  if is_log_file(&entry) { -                    if let Some(result) = search_log(&entry, opt).unwrap() { -                        output::output(io::stdout(), opt, &result).unwrap(); +                    let search = search_log(&entry, opt); +                    match search { +                        Ok(None) => (), +                        Ok(Some(result)) => output::output(io::stdout(), opt, &result).unwrap(), +                        Err(err) => { +                            debug!("Runtime error while scanning {:?}: {}", entry.path(), err); +                        }                      }                  }              }); @@ -274,18 +304,25 @@ fn grep(opt: &Opt) -> Result<(), RuntimeError> {  /// If the log doesn't match, returns `Ok(None)`.  /// If there was a fatal error, returns `Err(..)`.  fn search_log(entry: &DirEntry, opt: &Opt) -> Result<Option<LogResult>, RuntimeError> { -    let mut input = BufReader::new(File::open(entry.path())?); -    let raw = if entry +    let file_stream = BufReader::new(File::open(entry.path())?); +    let is_zip = entry          .file_name()          .to_str()          .map(|n| n.ends_with(".zip") || n.ends_with(".zevtc")) -        .unwrap_or(false) -    { -        evtclib::raw::parse_zip(&mut input) -    } else { -        evtclib::raw::parse_file(&mut input) +        .unwrap_or(false); +    let mut wrapper = match is_zip { +        false => ZipWrapper::raw(file_stream), +        true => ZipWrapper::zipped(file_stream),      }; -    let parsed = raw.ok().and_then(|m| evtclib::process(&m).ok()); +    let mut stream = wrapper.get_stream(); +    let partial = evtclib::raw::parser::parse_partial_file(&mut stream)?; + +    if filters::filter_name(&partial, opt) == opt.invert { +        return Ok(None) +    } + +    let raw = evtclib::raw::parser::finish_parsing(partial, &mut stream)?; +    let parsed = evtclib::process(&raw).ok();      let log = if let Some(e) = parsed {          e      } else { @@ -295,8 +332,7 @@ fn search_log(entry: &DirEntry, opt: &Opt) -> Result<Option<LogResult>, RuntimeE      let info = extract_info(entry, &log); -    let take_log = filters::filter_name(&log, opt) == !opt.invert -        && filters::filter_outcome(&info, opt) +    let take_log = filters::filter_outcome(&info, opt)          && filters::filter_weekday(&info, opt)          && filters::filter_time(&info, opt); | 
