+notmuch_query_t *
+notmuch_query_create (notmuch_database_t *notmuch,
+ const char *query_string)
+{
+
+ notmuch_query_t *query;
+ notmuch_status_t status;
+
+ status = notmuch_query_create_with_syntax (notmuch, query_string,
+ NOTMUCH_QUERY_SYNTAX_XAPIAN,
+ &query);
+ if (status)
+ return NULL;
+
+ return query;
+}
+
+notmuch_status_t
+notmuch_query_create_with_syntax (notmuch_database_t *notmuch,
+ const char *query_string,
+ notmuch_query_syntax_t syntax,
+ notmuch_query_t **output)
+{
+
+ notmuch_query_t *query;
+
+ if (! output)
+ return NOTMUCH_STATUS_NULL_POINTER;
+
+ query = _notmuch_query_constructor (notmuch, query_string);
+ if (! query)
+ return NOTMUCH_STATUS_OUT_OF_MEMORY;
+
+ if (syntax == NOTMUCH_QUERY_SYNTAX_SEXP && ! HAVE_SFSEXP) {
+ _notmuch_database_log (notmuch, "sexp query parser not available");
+ return NOTMUCH_STATUS_ILLEGAL_ARGUMENT;
+ }
+
+ query->syntax = syntax;
+
+ *output = query;
+
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
+static notmuch_status_t
+_notmuch_query_ensure_parsed_xapian (notmuch_query_t *query)
+{
+ try {
+ query->xapian_query =
+ query->notmuch->query_parser->
+ parse_query (query->query_string, NOTMUCH_QUERY_PARSER_FLAGS);
+
+ /* Xapian doesn't support skip_to on terms from a query since
+ * they are unordered, so cache a copy of all terms in
+ * something searchable.
+ */
+
+ for (Xapian::TermIterator t = query->xapian_query.get_terms_begin ();
+ t != query->xapian_query.get_terms_end (); ++t)
+ query->terms.insert (*t);
+
+ query->parsed = true;
+
+ } catch (const Xapian::Error &error) {
+ if (! query->notmuch->exception_reported) {
+ _notmuch_database_log (query->notmuch,
+ "A Xapian exception occurred parsing query: %s\n",
+ error.get_msg ().c_str ());
+ _notmuch_database_log_append (query->notmuch,
+ "Query string was: %s\n",
+ query->query_string);
+ query->notmuch->exception_reported = true;
+ }
+
+ return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
+ }
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
+static notmuch_status_t
+_notmuch_query_ensure_parsed_sexpr (notmuch_query_t *query)
+{
+ if (query->parsed)
+ return NOTMUCH_STATUS_SUCCESS;
+
+ query->xapian_query = Xapian::Query::MatchAll;
+ return NOTMUCH_STATUS_SUCCESS;
+}
+
+static notmuch_status_t
+_notmuch_query_ensure_parsed (notmuch_query_t *query)
+{
+ if (query->parsed)
+ return NOTMUCH_STATUS_SUCCESS;
+
+#if HAVE_SFSEXP
+ if (query->syntax == NOTMUCH_QUERY_SYNTAX_SEXP)
+ return _notmuch_query_ensure_parsed_sexpr (query);
+#endif
+
+ return _notmuch_query_ensure_parsed_xapian (query);
+}
+
+const char *
+notmuch_query_get_query_string (const notmuch_query_t *query)
+{
+ return query->query_string;
+}
+
+void
+notmuch_query_set_omit_excluded (notmuch_query_t *query,
+ notmuch_exclude_t omit_excluded)
+{
+ query->omit_excluded = omit_excluded;
+}
+