diff --git a/src/Expression.cpp b/src/Expression.cpp index 495f28143..eb03ab371 100644 --- a/src/Expression.cpp +++ b/src/Expression.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -199,39 +200,15 @@ bool Expression::eval (Task& task) else if (arg->first == "!~") { // std::cout << "# " << left.dump () << " !~ " << right.dump () << "\n"; - bool result = false; + bool case_sensitive = context.config.getBoolean ("search.case.sensitive"); + bool result = !eval_match (left, right, case_sensitive); // Matches against description are really against either description, // annotations or project. - if (left._raw == "description") + // Short-circuit if match already failed. + if (result && left._raw == "description") { - if (right._raw_type == "rx") - { - throw std::string ("rx not supported"); - } - else - { - left.cast (Variant::v_string); - right.cast (Variant::v_string); - if (left._string.find (right._string) == std::string::npos) - result = true; - } - } - - // Matches against non-description fields are treated as-is. - else - { - if (right._raw_type == "rx") - { - throw std::string ("rx not supported"); - } - else - { - left.cast (Variant::v_string); - right.cast (Variant::v_string); - if (left._string.find (right._string) == std::string::npos) - result = true; - } + // TODO check further. } left = Variant (result); @@ -277,39 +254,15 @@ bool Expression::eval (Task& task) else if (arg->first == "~") { // std::cout << "# " << left.dump () << " ~ " << right.dump () << "\n"; - bool result = false; + bool case_sensitive = context.config.getBoolean ("search.case.sensitive"); + bool result = eval_match (left, right, case_sensitive); // Matches against description are really against either description, // annotations or project. - if (left._raw == "description") + // Short-circuit if match is already found. + if (!result && left._raw == "description") { - if (right._raw_type == "rx") - { - throw std::string ("rx not supported"); - } - else - { - left.cast (Variant::v_string); - right.cast (Variant::v_string); - if (left._string.find (right._string) != std::string::npos) - result = true; - } - } - - // Matches against non-description fields are treated as-is. - else - { - if (right._raw_type == "rx") - { - throw std::string ("rx not supported"); - } - else - { - left.cast (Variant::v_string); - right.cast (Variant::v_string); - if (left._string.find (right._string) != std::string::npos) - result = true; - } + // TODO check further. } left = Variant (result); @@ -384,6 +337,32 @@ bool Expression::eval (Task& task) return pass_fail; } +//////////////////////////////////////////////////////////////////////////////// +bool Expression::eval_match (Variant& left, Variant& right, bool case_sensitive) +{ + if (right._raw_type == "rx") + { + left.cast (Variant::v_string); + right.cast (Variant::v_string); + + // Create a cached entry, if it does not already exist. + if (_regexes.find (right._string) == _regexes.end ()) + _regexes[right._string] = RegX (right._string, case_sensitive); + + if (_regexes[right._string].match (left._string)) + return true; + } + else + { + left.cast (Variant::v_string); + right.cast (Variant::v_string); + if (find (left._string, right._string, (bool) case_sensitive) != std::string::npos) + return true; + } + + return false; +} + //////////////////////////////////////////////////////////////////////////////// void Expression::create_variant ( Variant& variant, diff --git a/src/Expression.h b/src/Expression.h index 56767ad5a..b7d0a13f3 100644 --- a/src/Expression.h +++ b/src/Expression.h @@ -32,6 +32,7 @@ #include #include #include +#include #include class Expression @@ -56,10 +57,11 @@ private: bool is_new_style (); private: - + bool eval_match (Variant&, Variant&, bool); private: Arguments _args; + std::map _regexes; }; #endif diff --git a/src/RegX.cpp b/src/RegX.cpp index 151aa9064..0b2653cca 100644 --- a/src/RegX.cpp +++ b/src/RegX.cpp @@ -34,6 +34,14 @@ //#define _POSIX_C_SOURCE 1 #define MAX_MATCHES 64 +//////////////////////////////////////////////////////////////////////////////// +RegX::RegX () +: _compiled (false) +, _pattern ("") +, _case_sensitive (true) +{ +} + //////////////////////////////////////////////////////////////////////////////// RegX::RegX ( const std::string& pattern, diff --git a/src/RegX.h b/src/RegX.h index 067009d2d..d93a0883c 100644 --- a/src/RegX.h +++ b/src/RegX.h @@ -36,6 +36,7 @@ class RegX { public: + RegX (); RegX (const std::string&, bool caseSensitive = true); RegX (const RegX&); RegX& operator= (const RegX&);