[notmuch] [PATCH] Make the date parser nicer

Sebastian Spaeth Sebastian at SSpaeth.de
Sun Jan 24 06:13:53 PST 2010


Currently we have to enter mail dates as timestamps. This approach does 2 things: 1) it requires the prefix 'date:'
2) it allows dates to be specified in some formats. So a notmuch show date:2005..2006-05-12 will find all mails from 2005-01-01 until 2006-05-12.
The code is probably not in a proper location yet and needs to be shoved around by someone more knowledgable than me.
My C++ skills are somewhat,... lacking...

Possible time formats: YYYY-MM-DD,YYYY-MM (in that month) , YYYY (in that year)
MM-DD (month-day in current year), DD (day in current month)

Signed-off-by: Sebastian Spaeth <Sebastian at SSpaeth.de>
---
 lib/database.cc |   90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 89 insertions(+), 1 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 5b12320..9c2842d 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -494,6 +494,94 @@ _notmuch_database_ensure_writable (notmuch_database_t *notmuch)
     return NOTMUCH_STATUS_SUCCESS;
 }
 
+struct MaildateValueRangeProcessor : public Xapian::ValueRangeProcessor {
+    MaildateValueRangeProcessor() {}
+
+  time_t
+  parsedate(std::string &str, bool early) {
+	// Parse the begin date to time_t
+	// possible time formats:
+	// YYYY-MM-DD (size 10)
+	// YYYY-MM    (size 7)
+	// YYYY       (size 4)
+	//      MM-DD (size 5)
+	//         DD (size 2)
+        // begin of time unit when 'early', end of when not
+	struct tm *timeinfo;
+	time_t timet;
+	//const char * startptr;
+	int year = 0, month = 0, day = 0;
+
+	if (str.size() == 2) {
+	  // parse day, then remove it from the string
+	  day = atoi(str.c_str());
+	  str.erase(0,2);
+	}
+
+	if (str.size() == 4 or str.size() == 7 or str.size() == 10) {
+	  // parse year, then remove it from the string
+	  year = atoi(str.c_str());
+	  str.erase(0,5);
+	}
+	
+	month = atoi(str.c_str());
+	str.erase(0,3);
+
+	// Do we have a day component left?
+	if (str.size())
+		   day = atoi(str.c_str());	
+
+	if (year == 0 && month == 0 && day == 0)
+	  // no expected time format
+	  return NULL ;
+
+	timet = time(NULL);
+	timeinfo = gmtime( &timet );
+	timeinfo -> tm_isdst = 0;
+	if (!early && !month) ++year; 
+	if (year)  timeinfo -> tm_year = year - 1900;
+
+	if (month) timeinfo -> tm_mon = month - 1;
+	//else if (year) timeinfo -> tm_mon = (early ? 0: 12);
+
+	if (day) timeinfo -> tm_mday = (early ? day : ++day);
+	else timeinfo -> tm_mday = 1;
+
+	timeinfo -> tm_hour = 0;
+	timeinfo -> tm_min  = 0;
+	timeinfo -> tm_sec  = 0;
+	timet = mktime ( timeinfo );
+
+        if (!early) --timet;
+	if (timet == -1)
+	  return NULL;
+	return timet;
+  }
+
+    Xapian::valueno operator()(std::string &begin, std::string &end) {
+      time_t begintime, endtime;
+
+      if (begin.substr(0, 5) != "date:")
+	 return Xapian::BAD_VALUENO;
+      begin.erase(0, 5);
+
+      begintime = parsedate ( begin, true);
+      if (begintime == -1)
+	// no valid time format
+	return Xapian::BAD_VALUENO;
+
+      endtime = parsedate ( end, false);
+      if (endtime == -1)
+	// no valid time format
+	return Xapian::BAD_VALUENO;
+
+      begin.assign(Xapian::sortable_serialise(begintime));
+      end.assign(Xapian::sortable_serialise(endtime));
+
+      return NOTMUCH_VALUE_TIMESTAMP;
+    }
+};
+
 notmuch_database_t *
 notmuch_database_open (const char *path,
 		       notmuch_database_mode_t mode)
@@ -570,7 +658,7 @@ notmuch_database_open (const char *path,
 	notmuch->query_parser = new Xapian::QueryParser;
 	notmuch->term_gen = new Xapian::TermGenerator;
 	notmuch->term_gen->set_stemmer (Xapian::Stem ("english"));
-	notmuch->value_range_processor = new Xapian::NumberValueRangeProcessor (NOTMUCH_VALUE_TIMESTAMP, "date:", true);
+	notmuch->value_range_processor = new MaildateValueRangeProcessor();
 
 	notmuch->query_parser->set_default_op (Xapian::Query::OP_AND);
 	notmuch->query_parser->set_database (*notmuch->xapian_db);
-- 
1.6.3.3



More information about the notmuch mailing list