[notmuch] [PATCH 4/4] integrate keithp's date.c into the notmuch date parser and delete my previous own attempt

Sebastian Spaeth Sebastian at SSpaeth.de
Tue Jan 26 03:43:41 PST 2010


Signed-off-by: Sebastian Spaeth <Sebastian at SSpaeth.de>
---
 lib/database.cc |   84 ++++++++++--------------------------------------------
 lib/date.c      |   59 ++++++--------------------------------
 lib/notmuch.h   |   20 +++++++++++++
 notmuch-new.c   |    1 +
 notmuch.1       |   33 +++++++++++----------
 notmuch.c       |   20 +++++++------
 6 files changed, 74 insertions(+), 143 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index b386e1a..78cd898 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -219,6 +219,8 @@ notmuch_status_to_string (notmuch_status_t status)
 	return "Erroneous NULL pointer";
     case NOTMUCH_STATUS_TAG_TOO_LONG:
 	return "Tag value is too long (exceeds NOTMUCH_TAG_MAX)";
+    case NOTMUCH_STATUS_INVALID_DATE:
+	return "Date value did not parse to a valid date";
     case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW:
 	return "Unbalanced number of calls to notmuch_message_freeze/thaw";
     default:
@@ -497,83 +499,29 @@ _notmuch_database_ensure_writable (notmuch_database_t *notmuch)
 struct MaildateValueRangeProcessor : public Xapian::ValueRangeProcessor {
     MaildateValueRangeProcessor() {}
 
-  time_t
-  parsedate(std::string &str, bool early) {
-    /* Parse the date to a 'time_t', return NULL on error            */
-    /* possible time formats: YYYY-MM-DD, YYYY-MM, YYYY,             */
-    /* MM-DD (current month), DD (day in current month).             */
-    /* Uses start of time unit when 'early', end otherwise, e.g.     */
-    /* 2001:=2001-01-01:00:00:00 when 'early' or 2001-12-31:23:59:59 */
-    bool now = false;
-    struct tm *timeinfo;
-    time_t timet;
-    int year = 0, month = 0, day = 0;
-
-    now = (str == "now");
-
-    if (str.size() == 2) {
-      /* We got just current day in month, parse & remove it */
-      day = atoi(str.c_str());
-      str.erase(0,2);
-    }
-    
-    if (str.size() == 4 or str.size() > 5) {
-      /* expect a year, parse & remove it */
-      year = atoi(str.c_str());
-      str.erase(0,5);
-    }
-
-    /* parse & remove month if there is sth left in the string */
-    month = atoi(str.c_str());
-    str.erase(0,3);
-
-    /* Parse day if we have one left */
-    if (str.size())
-      day = atoi(str.c_str());	
-
-    if (!now && year == 0 && month == 0 && day == 0)
-      // no expected time format
-      return -1 ;
-
-    timet = time(NULL);                /* init timeinfo with current time */
-    timeinfo = gmtime(&timet);
-
-    if (!now) {
-      /* add timeunit if !early (1 second too much, which we deduct later   */
-      if (!early) {
-	if (year && !month)        ++year;  /* only year given              */
-	if (year && month && !day) ++month; /* year & month given           */
-      }
-      if (year)  timeinfo -> tm_year = year - 1900;
-      if (month) timeinfo -> tm_mon = month - 1;
-      if (day)   timeinfo -> tm_mday = (early ? day : ++day);
-      else       timeinfo -> tm_mday = 1;
-
-      timeinfo -> tm_hour = 0;
-      timeinfo -> tm_min  = 0;
-      timeinfo -> tm_sec  = (early ? 0 : -1); /* -1 sec if !early */
-    }
-    timet = mktime(timeinfo);
-
-    return timet;
-  }
-
     Xapian::valueno operator()(std::string &begin, std::string &end) {
-      time_t begintime, endtime;
+      time_t begin_first,begin_last, end_first, end_last;
+      int retval;
 
       if (begin.substr(0, 5) != "date:")
 	 return Xapian::BAD_VALUENO;
       begin.erase(0, 5);
 
-      begintime = parsedate(begin, true);
-      endtime   = parsedate(end, false);
+      retval = notmuch_parse_date(begin.c_str(), &begin_first, &begin_last, 0);
 
-      if ((begintime == -1) || (endtime == -1))
-	// parsedate failed, no valid time format
+      if (retval == NOTMUCH_STATUS_INVALID_DATE) {
+	fprintf(stderr,"Begin date failed to parse: %s",begin.c_str());
 	return Xapian::BAD_VALUENO;
+      }
+
+      retval = notmuch_parse_date(end.c_str(),&end_first,&end_last,begin_first);
+      if (retval == NOTMUCH_STATUS_INVALID_DATE) {
+	fprintf(stderr,"End date failed to parse: %s",end.c_str());
+	return Xapian::BAD_VALUENO;
+      }
 
-      begin.assign(Xapian::sortable_serialise(begintime));
-      end.assign(Xapian::sortable_serialise(endtime));
+      begin.assign(Xapian::sortable_serialise(begin_first));
+      end.assign(Xapian::sortable_serialise(end_last));
 
       return NOTMUCH_VALUE_TIMESTAMP;
     }
diff --git a/lib/date.c b/lib/date.c
index 09c5ef9..805a1d9 100644
--- a/lib/date.c
+++ b/lib/date.c
@@ -37,6 +37,7 @@ today(struct tm *result, time_t after) {
 }
 
 static int parse_today(const char *text, time_t *first, time_t *last, time_t after) {
+    (void)after; /*disable unused paramter warning*/
     if (strcasecmp(text, "today") == 0) {
 	struct tm n;
 	today(&n, 0);
@@ -56,6 +57,7 @@ static int parse_yesterday(const char *text, time_t *first, time_t *last, time_t
 	return 0;
     }
     return 1;
+    (void)after; /*disable unused paramter warning*/
 }
 
 static int parse_thisweek(const char *text, time_t *first, time_t *last, time_t after) {
@@ -67,6 +69,7 @@ static int parse_thisweek(const char *text, time_t *first, time_t *last, time_t
 	return 0;
     }
     return 1;
+    (void)after; /*disable unused paramter warning*/
 }
 
 static int parse_lastweek(const char *text, time_t *first, time_t *last, time_t after) {
@@ -78,6 +81,7 @@ static int parse_lastweek(const char *text, time_t *first, time_t *last, time_t
 	return 0;
     }
     return 1;
+    (void)after; /*disable unused paramter warning*/
 }
 
 static int parse_thismonth(const char *text, time_t *first, time_t *last, time_t after) {
@@ -94,6 +98,7 @@ static int parse_thismonth(const char *text, time_t *first, time_t *last, time_t
 	return 0;
     }
     return 1;
+    (void)after; /*disable unused paramter warning*/
 }
 
 static int parse_lastmonth(const char *text, time_t *first, time_t *last, time_t after) {
@@ -115,6 +120,7 @@ static int parse_lastmonth(const char *text, time_t *first, time_t *last, time_t
 	return 0;
     }
     return 1;
+    (void)after; /*disable unused paramter warning*/
 }
 
 static const char *months[12][2] = {
@@ -308,6 +314,7 @@ static int parse_iso(const char *text, time_t *first, time_t *last, time_t after
 	return 0;
     }
     return 1;
+    (void)after; /*disable unused paramter warning*/
 }
 
 /* month[/day[/year]] */
@@ -396,8 +403,8 @@ static int (*parsers[])(const char *text, time_t *first, time_t *last, time_t af
     0,
 };
 
-static notmuch_status_t
-notmuch_one_date(const char *text, time_t *first, time_t *last, time_t after)
+notmuch_status_t
+notmuch_parse_date(const char *text, time_t *first, time_t *last, time_t after)
 {
     int		i;
     for (i = 0; parsers[i]; i++)
@@ -405,51 +412,3 @@ notmuch_one_date(const char *text, time_t *first, time_t *last, time_t after)
 	    return NOTMUCH_STATUS_SUCCESS;
     return NOTMUCH_STATUS_INVALID_DATE;
 }
-
-notmuch_status_t
-notmuch_date(const char *text, time_t *first, time_t *last)
-{
-    char	*dots;
-    char	first_text[80], last_text[80];
-    notmuch_status_t	status;
-    time_t	first_first, first_last, last_first, last_last;
-
-    if (strlen(text) > sizeof (first_text))
-	return NOTMUCH_STATUS_INVALID_DATE;
-    dots = strstr(text, "..");
-    if (dots) {
-	strncpy(first_text, text, dots - text);
-	first_text[dots-text] = '\0';
-	status = notmuch_one_date(first_text, &first_first, &first_last, 0);
-	if (status)
-	    return status;
-	status = notmuch_one_date(dots + 2, &last_first, &last_last, first_first);
-	if (status)
-	    return status;
-	*first = first_first;
-	*last = last_last;
-	return 0;
-    }
-    return notmuch_one_date(text, first, last, 0);
-}
-
-#if 1
-int
-main (int argc, char **argv)
-{
-    int	i;
-    for (i = 1; i < argc; i++) {
-	time_t	first, last;
-
-	if (notmuch_date(argv[i], &first, &last) == 0) {
-	    char	first_string[80], last_string[80];
-
-	    ctime_r(&first, first_string);
-	    first_string[strlen(first_string)-1] = '\0';
-	    ctime_r(&last, last_string);
-	    last_string[strlen(last_string)-1] = '\0';
-	    printf ("%s: %s - %s\n", argv[i], first_string, last_string);
-	}
-    }
-}
-#endif
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 15c9db4..be474bf 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -78,6 +78,8 @@ typedef int notmuch_bool_t;
  * NOTMUCH_STATUS_TAG_TOO_LONG: A tag value is too long (exceeds
  *	NOTMUCH_TAG_MAX)
  *
+ * NOTMUCH_STATUS_INVALID_DATE: Date parsing failed
+ *
  * NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: The notmuch_message_thaw
  *	function has been called more times than notmuch_message_freeze.
  *
@@ -96,6 +98,7 @@ typedef enum _notmuch_status {
     NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID,
     NOTMUCH_STATUS_NULL_POINTER,
     NOTMUCH_STATUS_TAG_TOO_LONG,
+    NOTMUCH_STATUS_INVALID_DATE,
     NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW,
 
     NOTMUCH_STATUS_LAST_STATUS
@@ -1086,6 +1089,23 @@ notmuch_filenames_advance (notmuch_filenames_t *filenames);
 void
 notmuch_filenames_destroy (notmuch_filenames_t *filenames);
 
+notmuch_status_t
+notmuch_parse_date(const char *text, time_t *first, time_t *last, time_t after);
+/* Parse a string into the first and last possible timestamps.
+ * It parses the possible formats and stops if one pattern matches.
+ * Keywords: 'today','yesterday','thisweek','lastweek','thismonth',
+ *           'lastmonth'
+ * Month-day : month[-day]] (month: January, Jan, or 1)\n"
+ * ISO format: year[-month[-day]]
+ * US format : month[/day[/year]]
+ *
+ * 'after' is used to fill in bits from context if left out, e.g. a
+ * 'date:2004..01' will find from 2004-01-01 through 2004-01-31
+ *
+ * Return values:
+ * NOTMUCH_STATUS_SUCCESS
+ * NOTMUCH_STATUS_INVALID_DATE: Error parsing the date string
+ */
 NOTMUCH_END_DECLS
 
 #endif
diff --git a/notmuch-new.c b/notmuch-new.c
index f25c71f..5da31c1 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -431,6 +431,7 @@ add_files_recursive (notmuch_database_t *notmuch,
 	    ret = status;
 	    goto DONE;
 	default:
+	case NOTMUCH_STATUS_INVALID_DATE:
 	case NOTMUCH_STATUS_FILE_ERROR:
 	case NOTMUCH_STATUS_NULL_POINTER:
 	case NOTMUCH_STATUS_TAG_TOO_LONG:
diff --git a/notmuch.1 b/notmuch.1
index 38379b1..175fe86 100644
--- a/notmuch.1
+++ b/notmuch.1
@@ -417,22 +417,23 @@ particular time range, (based on the Date: header) with a syntax of:
 
 A 
 .B date 
-can be specified in the following formats:
-.BR 
-.B YYYY
-(e.g 2001 meaning since 2001, or through 2001, depending on whether it is the start or end). 2) 
-.B YYYY-MM
-meaning from/to month MM in year YYYY, 3) 
-.B YYYY-MM-DD
-(from/to that exact day) 4) 
-.B MM-DD 
-(from/to month/day in the current year) 5) 
-.B DD
-(from/to day DD in current month). 6) the keyword
-.B now
-can be used to denote NOW (so a "05-01..now" finds all mails from May until now).
-.BR
-Formats can be mixed, so "date:2001..22" means from 2001-01-01 until the 22nd this months.
+can be specified in various formats. It parses the formats in this order and stops if one pattern matches:
+
+	Keywords:
+.B today, 
+.B yesterday, 
+.B thisweek, 
+.B lastweek, 
+.B thismonth, 
+.B lastmonth.
+
+	Month-day: month[-day]] (month: "January", "Jan", 1)
+
+	ISO format: year[-month[-day]]
+
+	US format : month[/day[/year]]
+
+The date parser will try to fill in bits in the enddate from context if left out, e.g. a 'date:2004..01' will find from 2004-01-01 through 2004-01-31.
 
 .SH SEE ALSO
 The emacs-based interface to notmuch (available as
diff --git a/notmuch.c b/notmuch.c
index 808a370..b8fe01a 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -94,16 +94,18 @@ static const char search_terms_help[] =
     "\t\tFinally, results can be restricted to only messages within a\n"
     "\t\tparticular time range, (based on the Date: header) with a\n"
     "\t\tsyntax of: date:<startdate>..<enddate>\n"
-    "\t\tIt can be specified in the following formats:\n"
-    "\t\tYYYY (e.g 2001 meaning since 2001, or through 2001, depending\n"
-    "\t\ton whether it is the start or end). 2) YYYY-MM meaning from/to\n"
-    "\t\tmonth MM in year YYYY, 3) YYYY-MM-DD (that exact day) 4)\n"
-    "\t\tMM-DD (month/day in the current year) 5) DD (day DD in \n"
-    "\t\tcurrent month). 6) the keyword 'now' can be used to denote\n"
-    "\t\tNOW (so a 'date:05-01..now' finds all mails from May until now).\n"
     "\n"
-    "\t\tFormats can be mixed, so 'date:2001..22' means from 2001-01-01\n"
-    "\t\tuntil the 22nd this months.\n"
+    "\t\tIt can be specified in the following formats, parsing will \n"
+    "\t\tstop if the first pattern matches:\n"
+    "\t\tKeywords: 'today','yesterday','thisweek','lastweek',\n"
+    "\t\t'thismonth', 'lastmonth'. \n"
+    "\t\tmonth-day : month[-day]] (month: January, Jan, or 1)\n"
+    "\t\tISO format: year[-month[-day]] (month: January, Jan, or 1)\n"
+    "\t\tUS format : month[/day[/year]]\n"
+    "\n"
+    "\t\tThe parser will fill in bits in the enddate from context if\n"
+    "\t\tleft out, e.g. a 'date:2004..01' will find from 2004-01-01\n"
+    "\t\tthrough 2004-01-31\n"
     "\n\n";
 
 command_t commands[] = {
-- 
1.6.3.3



More information about the notmuch mailing list