]> git.notmuchmail.org Git - notmuch/blobdiff - lib/regexp-fields.cc
Merge branch 'release'
[notmuch] / lib / regexp-fields.cc
index 9873af8039919e07fd7e8c8fbdc3e36dd05b98f5..0feb50e586ba84f1c4ef84cb62e78ea679b472c3 100644 (file)
@@ -26,7 +26,6 @@
 #include "notmuch-private.h"
 #include "database-private.h"
 
-#if HAVE_XAPIAN_FIELD_PROCESSOR
 static void
 compile_regex (regex_t &regexp, const char *str)
 {
@@ -35,10 +34,10 @@ compile_regex (regex_t &regexp, const char *str)
     if (err != 0) {
        size_t len = regerror (err, &regexp, NULL, 0);
        char *buffer = new char[len];
-       std::string msg;
+       std::string msg = "Regexp error: ";
        (void) regerror (err, &regexp, buffer, len);
-       msg.assign (buffer, len);
-       delete buffer;
+       msg.append (buffer, len);
+       delete[] buffer;
 
        throw Xapian::QueryParserError (msg);
     }
@@ -62,11 +61,6 @@ RegexpPostingSource::init (const Xapian::Database &db)
     it_ = db_.valuestream_begin (slot_);
     end_ = db.valuestream_end (slot_);
     started_ = false;
-
-    /* make sure we start on a matching value */
-    while (!at_end() && regexec (&regexp_, (*it_).c_str (), 0, NULL, 0) != 0) {
-       ++it_;
-    }
 }
 
 Xapian::doccount
@@ -113,37 +107,103 @@ RegexpPostingSource::next (unused (double min_wt))
     }
 }
 
-static inline Xapian::valueno _find_slot (std::string prefix)
+void
+RegexpPostingSource::skip_to (Xapian::docid did, unused (double min_wt))
+{
+    started_ = true;
+    it_.skip_to (did);
+    for (; ! at_end (); ++it_) {
+       std::string value = *it_;
+       if (regexec (&regexp_, value.c_str (), 0, NULL, 0) == 0)
+           break;
+    }
+}
+
+bool
+RegexpPostingSource::check (Xapian::docid did, unused (double min_wt))
+{
+    started_ = true;
+    if (! it_.check (did) || at_end ())
+       return false;
+    return (regexec (&regexp_, (*it_).c_str (), 0, NULL, 0) == 0);
+}
+
+static inline Xapian::valueno
+_find_slot (std::string prefix)
 {
     if (prefix == "from")
        return NOTMUCH_VALUE_FROM;
     else if (prefix == "subject")
        return NOTMUCH_VALUE_SUBJECT;
+    else if (prefix == "mid")
+       return NOTMUCH_VALUE_MESSAGE_ID;
     else
-       throw Xapian::QueryParserError ("unsupported regexp field '" + prefix + "'");
+       return Xapian::BAD_VALUENO;
 }
 
-RegexpFieldProcessor::RegexpFieldProcessor (std::string prefix, Xapian::QueryParser &parser_, notmuch_database_t *notmuch_)
-       : slot (_find_slot (prefix)), term_prefix (_find_prefix (prefix.c_str ())),
-         parser (parser_), notmuch (notmuch_)
+RegexpFieldProcessor::RegexpFieldProcessor (std::string prefix,
+                                           notmuch_field_flag_t options_,
+                                           Xapian::QueryParser &parser_,
+                                           notmuch_database_t *notmuch_)
+    : slot (_find_slot (prefix)),
+    term_prefix (_find_prefix (prefix.c_str ())),
+    options (options_),
+    parser (parser_),
+    notmuch (notmuch_)
 {
 };
 
 Xapian::Query
 RegexpFieldProcessor::operator() (const std::string & str)
 {
+    if (str.empty ()) {
+       if (options & NOTMUCH_FIELD_PROBABILISTIC) {
+           return Xapian::Query (Xapian::Query::OP_AND_NOT,
+                                 Xapian::Query::MatchAll,
+                                 Xapian::Query (Xapian::Query::OP_WILDCARD, term_prefix));
+       } else {
+           return Xapian::Query (term_prefix);
+       }
+    }
+
     if (str.at (0) == '/') {
-       if (str.at (str.size () - 1) == '/'){
-           RegexpPostingSource *postings = new RegexpPostingSource (slot, str.substr(1,str.size () - 2));
-           return Xapian::Query (postings->release ());
+       if (str.length () > 1 && str.at (str.size () - 1) == '/') {
+           std::string regexp_str = str.substr (1, str.size () - 2);
+           if (slot != Xapian::BAD_VALUENO) {
+               RegexpPostingSource *postings = new RegexpPostingSource (slot, regexp_str);
+               return Xapian::Query (postings->release ());
+           } else {
+               std::vector<std::string> terms;
+               regex_t regexp;
+
+               compile_regex (regexp, regexp_str.c_str ());
+               for (Xapian::TermIterator it = notmuch->xapian_db->allterms_begin (term_prefix);
+                    it != notmuch->xapian_db->allterms_end (); ++it) {
+                   if (regexec (&regexp, (*it).c_str () + term_prefix.size (),
+                                0, NULL, 0) == 0)
+                       terms.push_back (*it);
+               }
+               return Xapian::Query (Xapian::Query::OP_OR, terms.begin (), terms.end ());
+           }
        } else {
            throw Xapian::QueryParserError ("unmatched regex delimiter in '" + str + "'");
        }
     } else {
-       /* TODO replace this with a nicer API level triggering of
-        * phrase parsing, when possible */
-       std::string quoted='"' + str + '"';
-       return parser.parse_query (quoted, NOTMUCH_QUERY_PARSER_FLAGS, term_prefix);
+       if (options & NOTMUCH_FIELD_PROBABILISTIC) {
+           /* TODO replace this with a nicer API level triggering of
+            * phrase parsing, when possible */
+           std::string query_str;
+
+           if (*str.rbegin () != '*' || str.find (' ') != std::string::npos)
+               query_str = '"' + str + '"';
+           else
+               query_str = str;
+
+           return parser.parse_query (query_str, NOTMUCH_QUERY_PARSER_FLAGS, term_prefix);
+       } else {
+           /* Boolean prefix */
+           std::string term = term_prefix + str;
+           return Xapian::Query (term);
+       }
     }
 }
-#endif