diff options
author | Yorhel <git@yorhel.nl> | 2015-04-23 10:53:27 +0200 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2015-04-23 10:53:27 +0200 |
commit | 3c66b5f385f49af91ea5467d5ce1b0c10dbf8cfb (patch) | |
tree | 3fd0658ef80d99aa650a4d357c7fc4a16c4b34ed | |
parent | cc54b6fbd2d2ac0877d6b33fe5a5280acb4766e4 (diff) |
Regex matching
This breaks the tests because Regex doesn't have Eq. Can try something
else maybe...
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/filter.rs | 71 | ||||
-rw-r--r-- | src/main.rs | 1 |
3 files changed, 70 insertions, 3 deletions
@@ -7,3 +7,4 @@ authors = ["Yorhel <git@yorhel.nl>"] time = "*" peg = "*" getopts = "*" +regex = "*" diff --git a/src/filter.rs b/src/filter.rs index f3d2ade..d4ce4bd 100644 --- a/src/filter.rs +++ b/src/filter.rs @@ -1,3 +1,6 @@ +use regex::Regex; +use super::Line; + #[derive(Clone,Copy,Debug,PartialEq,Eq)] pub enum FilterCmp { Ge, @@ -8,13 +11,26 @@ pub enum FilterCmp { Ne, } -#[derive(Debug,PartialEq,Eq)] +#[derive(Clone,Copy,Debug,PartialEq,Eq)] +pub enum FilterStrField { + Host, + Ident, + User, + Method, + Path, + Proto, + Referer, + Ua, +} + +#[derive(Debug)] pub enum Filter { And(Box<Filter>, Box<Filter>), Or(Box<Filter>, Box<Filter>), Not(Box<Filter>), SizeCmp(FilterCmp, u64), StatusCmp(FilterCmp, u16), + Match(FilterStrField, Regex), } @@ -34,10 +50,40 @@ cmp -> super::FilterCmp / "=" { super::FilterCmp::Eq } / "!=" { super::FilterCmp::Ne } +strfield -> super::FilterStrField + = "host" { super::FilterStrField::Host } + / "ident" { super::FilterStrField::Ident } + / "user" { super::FilterStrField::User } + / "method" { super::FilterStrField::Method } + / "path" { super::FilterStrField::Path } + / "proto" { super::FilterStrField::Proto } + / "referer" { super::FilterStrField::Referer } + / "ua" { super::FilterStrField::Ua } + unsigned -> u64 = [1-9][0-9]* { match_str.parse().unwrap() } / "0" { 0u64 } +unit_mult -> u64 + = "G" { 1u64<<30 } + / "M" { 1u64<<20 } + / "k" { 1u64<<10 } + / { 1u64 } + +size -> u64 + = u:unsigned m:unit_mult { u * m } + +string_part -> &'input str + = [^"\\]+ { match_str } + / "\\\"" { "\"" } + / "\\\\" { "\\" } + +string -> String + = "\"" s:string_part* "\"" { s.concat() } + +regex -> super::super::regex::Regex + = s:string {? match super::super::regex::Regex::new(&s) { Ok(x) => Ok(x), Err(_) => Err("Invalid regular expression") } } + ws = [ ]* @@ -48,8 +94,9 @@ filter -> super::Filter / "!" ws x:filter { super::Filter::Not(Box::new(x)) } / "(" ws a:filter "&" ws b:filter ")" ws { super::Filter::And(Box::new(a), Box::new(b)) } / "(" ws a:filter "|" ws b:filter ")" ws { super::Filter::Or(Box::new(a), Box::new(b)) } - / "size" ws c:cmp ws n:unsigned ws { super::Filter::SizeCmp(c, n) } + / "size" ws c:cmp ws n:size ws { super::Filter::SizeCmp(c, n) } / "status" ws c:cmp ws n:unsigned ws { super::Filter::StatusCmp(c, n as u16) } + / f:strfield ws "~" ws r:regex ws { super::Filter::Match(f, r) } "#); @@ -68,6 +115,22 @@ impl FilterCmp { } +impl FilterStrField { + fn getfield<'a>(self, l: &'a Line) -> &'a str { + match self { + FilterStrField::Host => l.host, + FilterStrField::Ident => l.ident, + FilterStrField::User => l.user, + FilterStrField::Method => l.method, + FilterStrField::Path => l.path, + FilterStrField::Proto => l.proto, + FilterStrField::Referer => l.referer.unwrap_or(""), + FilterStrField::Ua => l.ua.unwrap_or(""), + } + } +} + + impl Filter { pub fn new(filter: &str) -> Result<Filter, ()> { match filterparse::filter(filter) { @@ -76,13 +139,14 @@ impl Filter { } } - pub fn apply(&self, line: &super::Line) -> bool { + pub fn apply(&self, line: &Line) -> bool { match *self { Filter::And(ref a, ref b) => a.apply(line) && b.apply(line), Filter::Or(ref a, ref b) => a.apply(line) || b.apply(line), Filter::Not(ref a) => !a.apply(line), Filter::SizeCmp(c, x) => c.apply(x, line.size), Filter::StatusCmp(c, x) => c.apply(x, line.status), + Filter::Match(f, ref r) => r.is_match(f.getfield(&line)) } } } @@ -91,6 +155,7 @@ impl Filter { #[test] fn test_parse() { assert_eq!(Filter::new("size > 1"), Ok(Filter::SizeCmp(FilterCmp::Gt, 1))); + assert_eq!(Filter::new("size < 1G"), Ok(Filter::SizeCmp(FilterCmp::Lt, 1024*1024*1024))); assert_eq!(Filter::new(" ( status >= 1 & status<=10) "), Ok(Filter::And( Box::new(Filter::StatusCmp(FilterCmp::Ge, 1)), diff --git a/src/main.rs b/src/main.rs index e7b5475..f94107b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ extern crate test; extern crate time; extern crate getopts; +extern crate regex; mod line; mod filter; |