Re: priorities for 0.7
[notmuch-archives.git] / 35 / 37aa2d67fd539a45bc73ddd101955b16a00db2
1 Return-Path: <Sebastian@SSpaeth.de>\r
2 X-Original-To: notmuch@notmuchmail.org\r
3 Delivered-To: notmuch@notmuchmail.org\r
4 Received: from localhost (localhost [127.0.0.1])\r
5         by olra.theworths.org (Postfix) with ESMTP id C8E67431FD8\r
6         for <notmuch@notmuchmail.org>; Tue, 26 Jan 2010 03:44:23 -0800 (PST)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -1.837\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-1.837 tagged_above=-999 required=5 tests=[AWL=0.762,\r
12         BAYES_00=-2.599] autolearn=ham\r
13 Received: from olra.theworths.org ([127.0.0.1])\r
14         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
15         with ESMTP id x-rBuP++X4Cn for <notmuch@notmuchmail.org>;\r
16         Tue, 26 Jan 2010 03:44:21 -0800 (PST)\r
17 Received: from homiemail-a20.g.dreamhost.com (caiajhbdccah.dreamhost.com\r
18         [208.97.132.207])\r
19         by olra.theworths.org (Postfix) with ESMTP id D7F1F431FBD\r
20         for <notmuch@notmuchmail.org>; Tue, 26 Jan 2010 03:44:20 -0800 (PST)\r
21 Received: from localhost.localdomain (mtec-hg-docking-2-dhcp-062.ethz.ch\r
22         [82.130.121.62])\r
23         by homiemail-a20.g.dreamhost.com (Postfix) with ESMTPA id C68F97EC061; \r
24         Tue, 26 Jan 2010 03:44:19 -0800 (PST)\r
25 From: Sebastian Spaeth <Sebastian@SSpaeth.de>\r
26 To: notmuch@notmuchmail.org\r
27 Date: Tue, 26 Jan 2010 12:43:41 +0100\r
28 Message-Id: <1264506221-9636-4-git-send-email-Sebastian@SSpaeth.de>\r
29 X-Mailer: git-send-email 1.6.3.3\r
30 In-Reply-To: <1264506221-9636-3-git-send-email-Sebastian@SSpaeth.de>\r
31 References: <1264506221-9636-1-git-send-email-Sebastian@SSpaeth.de>\r
32         <1264506221-9636-2-git-send-email-Sebastian@SSpaeth.de>\r
33         <1264506221-9636-3-git-send-email-Sebastian@SSpaeth.de>\r
34 Subject: [notmuch] [PATCH 4/4] integrate keithp's date.c into the notmuch\r
35         date parser and delete my previous own attempt\r
36 X-BeenThere: notmuch@notmuchmail.org\r
37 X-Mailman-Version: 2.1.13\r
38 Precedence: list\r
39 List-Id: "Use and development of the notmuch mail system."\r
40         <notmuch.notmuchmail.org>\r
41 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
42         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
43 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
44 List-Post: <mailto:notmuch@notmuchmail.org>\r
45 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
46 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
47         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
48 X-List-Received-Date: Tue, 26 Jan 2010 11:44:24 -0000\r
49 \r
50 Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>\r
51 ---\r
52  lib/database.cc |   84 ++++++++++--------------------------------------------\r
53  lib/date.c      |   59 ++++++--------------------------------\r
54  lib/notmuch.h   |   20 +++++++++++++\r
55  notmuch-new.c   |    1 +\r
56  notmuch.1       |   33 +++++++++++----------\r
57  notmuch.c       |   20 +++++++------\r
58  6 files changed, 74 insertions(+), 143 deletions(-)\r
59 \r
60 diff --git a/lib/database.cc b/lib/database.cc\r
61 index b386e1a..78cd898 100644\r
62 --- a/lib/database.cc\r
63 +++ b/lib/database.cc\r
64 @@ -219,6 +219,8 @@ notmuch_status_to_string (notmuch_status_t status)\r
65         return "Erroneous NULL pointer";\r
66      case NOTMUCH_STATUS_TAG_TOO_LONG:\r
67         return "Tag value is too long (exceeds NOTMUCH_TAG_MAX)";\r
68 +    case NOTMUCH_STATUS_INVALID_DATE:\r
69 +       return "Date value did not parse to a valid date";\r
70      case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW:\r
71         return "Unbalanced number of calls to notmuch_message_freeze/thaw";\r
72      default:\r
73 @@ -497,83 +499,29 @@ _notmuch_database_ensure_writable (notmuch_database_t *notmuch)\r
74  struct MaildateValueRangeProcessor : public Xapian::ValueRangeProcessor {\r
75      MaildateValueRangeProcessor() {}\r
76  \r
77 -  time_t\r
78 -  parsedate(std::string &str, bool early) {\r
79 -    /* Parse the date to a 'time_t', return NULL on error            */\r
80 -    /* possible time formats: YYYY-MM-DD, YYYY-MM, YYYY,             */\r
81 -    /* MM-DD (current month), DD (day in current month).             */\r
82 -    /* Uses start of time unit when 'early', end otherwise, e.g.     */\r
83 -    /* 2001:=2001-01-01:00:00:00 when 'early' or 2001-12-31:23:59:59 */\r
84 -    bool now = false;\r
85 -    struct tm *timeinfo;\r
86 -    time_t timet;\r
87 -    int year = 0, month = 0, day = 0;\r
88 -\r
89 -    now = (str == "now");\r
90 -\r
91 -    if (str.size() == 2) {\r
92 -      /* We got just current day in month, parse & remove it */\r
93 -      day = atoi(str.c_str());\r
94 -      str.erase(0,2);\r
95 -    }\r
96 -    \r
97 -    if (str.size() == 4 or str.size() > 5) {\r
98 -      /* expect a year, parse & remove it */\r
99 -      year = atoi(str.c_str());\r
100 -      str.erase(0,5);\r
101 -    }\r
102 -\r
103 -    /* parse & remove month if there is sth left in the string */\r
104 -    month = atoi(str.c_str());\r
105 -    str.erase(0,3);\r
106 -\r
107 -    /* Parse day if we have one left */\r
108 -    if (str.size())\r
109 -      day = atoi(str.c_str()); \r
110 -\r
111 -    if (!now && year == 0 && month == 0 && day == 0)\r
112 -      // no expected time format\r
113 -      return -1 ;\r
114 -\r
115 -    timet = time(NULL);                /* init timeinfo with current time */\r
116 -    timeinfo = gmtime(&timet);\r
117 -\r
118 -    if (!now) {\r
119 -      /* add timeunit if !early (1 second too much, which we deduct later   */\r
120 -      if (!early) {\r
121 -       if (year && !month)        ++year;  /* only year given              */\r
122 -       if (year && month && !day) ++month; /* year & month given           */\r
123 -      }\r
124 -      if (year)  timeinfo -> tm_year = year - 1900;\r
125 -      if (month) timeinfo -> tm_mon = month - 1;\r
126 -      if (day)   timeinfo -> tm_mday = (early ? day : ++day);\r
127 -      else       timeinfo -> tm_mday = 1;\r
128 -\r
129 -      timeinfo -> tm_hour = 0;\r
130 -      timeinfo -> tm_min  = 0;\r
131 -      timeinfo -> tm_sec  = (early ? 0 : -1); /* -1 sec if !early */\r
132 -    }\r
133 -    timet = mktime(timeinfo);\r
134 -\r
135 -    return timet;\r
136 -  }\r
137 -\r
138      Xapian::valueno operator()(std::string &begin, std::string &end) {\r
139 -      time_t begintime, endtime;\r
140 +      time_t begin_first,begin_last, end_first, end_last;\r
141 +      int retval;\r
142  \r
143        if (begin.substr(0, 5) != "date:")\r
144          return Xapian::BAD_VALUENO;\r
145        begin.erase(0, 5);\r
146  \r
147 -      begintime = parsedate(begin, true);\r
148 -      endtime   = parsedate(end, false);\r
149 +      retval = notmuch_parse_date(begin.c_str(), &begin_first, &begin_last, 0);\r
150  \r
151 -      if ((begintime == -1) || (endtime == -1))\r
152 -       // parsedate failed, no valid time format\r
153 +      if (retval == NOTMUCH_STATUS_INVALID_DATE) {\r
154 +       fprintf(stderr,"Begin date failed to parse: %s",begin.c_str());\r
155         return Xapian::BAD_VALUENO;\r
156 +      }\r
157 +\r
158 +      retval = notmuch_parse_date(end.c_str(),&end_first,&end_last,begin_first);\r
159 +      if (retval == NOTMUCH_STATUS_INVALID_DATE) {\r
160 +       fprintf(stderr,"End date failed to parse: %s",end.c_str());\r
161 +       return Xapian::BAD_VALUENO;\r
162 +      }\r
163  \r
164 -      begin.assign(Xapian::sortable_serialise(begintime));\r
165 -      end.assign(Xapian::sortable_serialise(endtime));\r
166 +      begin.assign(Xapian::sortable_serialise(begin_first));\r
167 +      end.assign(Xapian::sortable_serialise(end_last));\r
168  \r
169        return NOTMUCH_VALUE_TIMESTAMP;\r
170      }\r
171 diff --git a/lib/date.c b/lib/date.c\r
172 index 09c5ef9..805a1d9 100644\r
173 --- a/lib/date.c\r
174 +++ b/lib/date.c\r
175 @@ -37,6 +37,7 @@ today(struct tm *result, time_t after) {\r
176  }\r
177  \r
178  static int parse_today(const char *text, time_t *first, time_t *last, time_t after) {\r
179 +    (void)after; /*disable unused paramter warning*/\r
180      if (strcasecmp(text, "today") == 0) {\r
181         struct tm n;\r
182         today(&n, 0);\r
183 @@ -56,6 +57,7 @@ static int parse_yesterday(const char *text, time_t *first, time_t *last, time_t\r
184         return 0;\r
185      }\r
186      return 1;\r
187 +    (void)after; /*disable unused paramter warning*/\r
188  }\r
189  \r
190  static int parse_thisweek(const char *text, time_t *first, time_t *last, time_t after) {\r
191 @@ -67,6 +69,7 @@ static int parse_thisweek(const char *text, time_t *first, time_t *last, time_t\r
192         return 0;\r
193      }\r
194      return 1;\r
195 +    (void)after; /*disable unused paramter warning*/\r
196  }\r
197  \r
198  static int parse_lastweek(const char *text, time_t *first, time_t *last, time_t after) {\r
199 @@ -78,6 +81,7 @@ static int parse_lastweek(const char *text, time_t *first, time_t *last, time_t\r
200         return 0;\r
201      }\r
202      return 1;\r
203 +    (void)after; /*disable unused paramter warning*/\r
204  }\r
205  \r
206  static int parse_thismonth(const char *text, time_t *first, time_t *last, time_t after) {\r
207 @@ -94,6 +98,7 @@ static int parse_thismonth(const char *text, time_t *first, time_t *last, time_t\r
208         return 0;\r
209      }\r
210      return 1;\r
211 +    (void)after; /*disable unused paramter warning*/\r
212  }\r
213  \r
214  static int parse_lastmonth(const char *text, time_t *first, time_t *last, time_t after) {\r
215 @@ -115,6 +120,7 @@ static int parse_lastmonth(const char *text, time_t *first, time_t *last, time_t\r
216         return 0;\r
217      }\r
218      return 1;\r
219 +    (void)after; /*disable unused paramter warning*/\r
220  }\r
221  \r
222  static const char *months[12][2] = {\r
223 @@ -308,6 +314,7 @@ static int parse_iso(const char *text, time_t *first, time_t *last, time_t after\r
224         return 0;\r
225      }\r
226      return 1;\r
227 +    (void)after; /*disable unused paramter warning*/\r
228  }\r
229  \r
230  /* month[/day[/year]] */\r
231 @@ -396,8 +403,8 @@ static int (*parsers[])(const char *text, time_t *first, time_t *last, time_t af\r
232      0,\r
233  };\r
234  \r
235 -static notmuch_status_t\r
236 -notmuch_one_date(const char *text, time_t *first, time_t *last, time_t after)\r
237 +notmuch_status_t\r
238 +notmuch_parse_date(const char *text, time_t *first, time_t *last, time_t after)\r
239  {\r
240      int                i;\r
241      for (i = 0; parsers[i]; i++)\r
242 @@ -405,51 +412,3 @@ notmuch_one_date(const char *text, time_t *first, time_t *last, time_t after)\r
243             return NOTMUCH_STATUS_SUCCESS;\r
244      return NOTMUCH_STATUS_INVALID_DATE;\r
245  }\r
246 -\r
247 -notmuch_status_t\r
248 -notmuch_date(const char *text, time_t *first, time_t *last)\r
249 -{\r
250 -    char       *dots;\r
251 -    char       first_text[80], last_text[80];\r
252 -    notmuch_status_t   status;\r
253 -    time_t     first_first, first_last, last_first, last_last;\r
254 -\r
255 -    if (strlen(text) > sizeof (first_text))\r
256 -       return NOTMUCH_STATUS_INVALID_DATE;\r
257 -    dots = strstr(text, "..");\r
258 -    if (dots) {\r
259 -       strncpy(first_text, text, dots - text);\r
260 -       first_text[dots-text] = '\0';\r
261 -       status = notmuch_one_date(first_text, &first_first, &first_last, 0);\r
262 -       if (status)\r
263 -           return status;\r
264 -       status = notmuch_one_date(dots + 2, &last_first, &last_last, first_first);\r
265 -       if (status)\r
266 -           return status;\r
267 -       *first = first_first;\r
268 -       *last = last_last;\r
269 -       return 0;\r
270 -    }\r
271 -    return notmuch_one_date(text, first, last, 0);\r
272 -}\r
273 -\r
274 -#if 1\r
275 -int\r
276 -main (int argc, char **argv)\r
277 -{\r
278 -    int        i;\r
279 -    for (i = 1; i < argc; i++) {\r
280 -       time_t  first, last;\r
281 -\r
282 -       if (notmuch_date(argv[i], &first, &last) == 0) {\r
283 -           char        first_string[80], last_string[80];\r
284 -\r
285 -           ctime_r(&first, first_string);\r
286 -           first_string[strlen(first_string)-1] = '\0';\r
287 -           ctime_r(&last, last_string);\r
288 -           last_string[strlen(last_string)-1] = '\0';\r
289 -           printf ("%s: %s - %s\n", argv[i], first_string, last_string);\r
290 -       }\r
291 -    }\r
292 -}\r
293 -#endif\r
294 diff --git a/lib/notmuch.h b/lib/notmuch.h\r
295 index 15c9db4..be474bf 100644\r
296 --- a/lib/notmuch.h\r
297 +++ b/lib/notmuch.h\r
298 @@ -78,6 +78,8 @@ typedef int notmuch_bool_t;\r
299   * NOTMUCH_STATUS_TAG_TOO_LONG: A tag value is too long (exceeds\r
300   *     NOTMUCH_TAG_MAX)\r
301   *\r
302 + * NOTMUCH_STATUS_INVALID_DATE: Date parsing failed\r
303 + *\r
304   * NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: The notmuch_message_thaw\r
305   *     function has been called more times than notmuch_message_freeze.\r
306   *\r
307 @@ -96,6 +98,7 @@ typedef enum _notmuch_status {\r
308      NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID,\r
309      NOTMUCH_STATUS_NULL_POINTER,\r
310      NOTMUCH_STATUS_TAG_TOO_LONG,\r
311 +    NOTMUCH_STATUS_INVALID_DATE,\r
312      NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW,\r
313  \r
314      NOTMUCH_STATUS_LAST_STATUS\r
315 @@ -1086,6 +1089,23 @@ notmuch_filenames_advance (notmuch_filenames_t *filenames);\r
316  void\r
317  notmuch_filenames_destroy (notmuch_filenames_t *filenames);\r
318  \r
319 +notmuch_status_t\r
320 +notmuch_parse_date(const char *text, time_t *first, time_t *last, time_t after);\r
321 +/* Parse a string into the first and last possible timestamps.\r
322 + * It parses the possible formats and stops if one pattern matches.\r
323 + * Keywords: 'today','yesterday','thisweek','lastweek','thismonth',\r
324 + *           'lastmonth'\r
325 + * Month-day : month[-day]] (month: January, Jan, or 1)\n"\r
326 + * ISO format: year[-month[-day]]\r
327 + * US format : month[/day[/year]]\r
328 + *\r
329 + * 'after' is used to fill in bits from context if left out, e.g. a\r
330 + * 'date:2004..01' will find from 2004-01-01 through 2004-01-31\r
331 + *\r
332 + * Return values:\r
333 + * NOTMUCH_STATUS_SUCCESS\r
334 + * NOTMUCH_STATUS_INVALID_DATE: Error parsing the date string\r
335 + */\r
336  NOTMUCH_END_DECLS\r
337  \r
338  #endif\r
339 diff --git a/notmuch-new.c b/notmuch-new.c\r
340 index f25c71f..5da31c1 100644\r
341 --- a/notmuch-new.c\r
342 +++ b/notmuch-new.c\r
343 @@ -431,6 +431,7 @@ add_files_recursive (notmuch_database_t *notmuch,\r
344             ret = status;\r
345             goto DONE;\r
346         default:\r
347 +       case NOTMUCH_STATUS_INVALID_DATE:\r
348         case NOTMUCH_STATUS_FILE_ERROR:\r
349         case NOTMUCH_STATUS_NULL_POINTER:\r
350         case NOTMUCH_STATUS_TAG_TOO_LONG:\r
351 diff --git a/notmuch.1 b/notmuch.1\r
352 index 38379b1..175fe86 100644\r
353 --- a/notmuch.1\r
354 +++ b/notmuch.1\r
355 @@ -417,22 +417,23 @@ particular time range, (based on the Date: header) with a syntax of:\r
356  \r
357  A \r
358  .B date \r
359 -can be specified in the following formats:\r
360 -.BR \r
361 -.B YYYY\r
362 -(e.g 2001 meaning since 2001, or through 2001, depending on whether it is the start or end). 2) \r
363 -.B YYYY-MM\r
364 -meaning from/to month MM in year YYYY, 3) \r
365 -.B YYYY-MM-DD\r
366 -(from/to that exact day) 4) \r
367 -.B MM-DD \r
368 -(from/to month/day in the current year) 5) \r
369 -.B DD\r
370 -(from/to day DD in current month). 6) the keyword\r
371 -.B now\r
372 -can be used to denote NOW (so a "05-01..now" finds all mails from May until now).\r
373 -.BR\r
374 -Formats can be mixed, so "date:2001..22" means from 2001-01-01 until the 22nd this months.\r
375 +can be specified in various formats. It parses the formats in this order and stops if one pattern matches:\r
376 +\r
377 +       Keywords:\r
378 +.B today, \r
379 +.B yesterday, \r
380 +.B thisweek, \r
381 +.B lastweek, \r
382 +.B thismonth, \r
383 +.B lastmonth.\r
384 +\r
385 +       Month-day: month[-day]] (month: "January", "Jan", 1)\r
386 +\r
387 +       ISO format: year[-month[-day]]\r
388 +\r
389 +       US format : month[/day[/year]]\r
390 +\r
391 +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.\r
392  \r
393  .SH SEE ALSO\r
394  The emacs-based interface to notmuch (available as\r
395 diff --git a/notmuch.c b/notmuch.c\r
396 index 808a370..b8fe01a 100644\r
397 --- a/notmuch.c\r
398 +++ b/notmuch.c\r
399 @@ -94,16 +94,18 @@ static const char search_terms_help[] =\r
400      "\t\tFinally, results can be restricted to only messages within a\n"\r
401      "\t\tparticular time range, (based on the Date: header) with a\n"\r
402      "\t\tsyntax of: date:<startdate>..<enddate>\n"\r
403 -    "\t\tIt can be specified in the following formats:\n"\r
404 -    "\t\tYYYY (e.g 2001 meaning since 2001, or through 2001, depending\n"\r
405 -    "\t\ton whether it is the start or end). 2) YYYY-MM meaning from/to\n"\r
406 -    "\t\tmonth MM in year YYYY, 3) YYYY-MM-DD (that exact day) 4)\n"\r
407 -    "\t\tMM-DD (month/day in the current year) 5) DD (day DD in \n"\r
408 -    "\t\tcurrent month). 6) the keyword 'now' can be used to denote\n"\r
409 -    "\t\tNOW (so a 'date:05-01..now' finds all mails from May until now).\n"\r
410      "\n"\r
411 -    "\t\tFormats can be mixed, so 'date:2001..22' means from 2001-01-01\n"\r
412 -    "\t\tuntil the 22nd this months.\n"\r
413 +    "\t\tIt can be specified in the following formats, parsing will \n"\r
414 +    "\t\tstop if the first pattern matches:\n"\r
415 +    "\t\tKeywords: 'today','yesterday','thisweek','lastweek',\n"\r
416 +    "\t\t'thismonth', 'lastmonth'. \n"\r
417 +    "\t\tmonth-day : month[-day]] (month: January, Jan, or 1)\n"\r
418 +    "\t\tISO format: year[-month[-day]] (month: January, Jan, or 1)\n"\r
419 +    "\t\tUS format : month[/day[/year]]\n"\r
420 +    "\n"\r
421 +    "\t\tThe parser will fill in bits in the enddate from context if\n"\r
422 +    "\t\tleft out, e.g. a 'date:2004..01' will find from 2004-01-01\n"\r
423 +    "\t\tthrough 2004-01-31\n"\r
424      "\n\n";\r
425  \r
426  command_t commands[] = {\r
427 -- \r
428 1.6.3.3\r
429 \r