[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: [PATCH] -r { DATE } with words

From: Stefan Sperling <stsp_at_elego.de>
Date: Tue, 17 May 2011 11:36:55 +0200

On Tue, May 17, 2011 at 12:45:50AM +0200, Stefan Sperling wrote:
> Any comments or objections?

Neels didn't like the arbitrary "round to 00:00 of next day" rules
and everyone in the hackathon room seems to agree. So "one day ago"
is now the same as "24 hours ago".

I also dropped the "yesterday" keyword because it overlaps with "one day ago".

[[[
Add support for the following revision { DATE } specifications:

  "now" resolves to the most recent revision as of the current time.

  "N years|months|weeks|days|hours|minutes ago" resolve to the most recent
  revision prior to the specified time. A year always has 365 days.
  A month always has 30 days. N may be a word from "zero" up to "twelve",
  or a non-negative digit. To help scripts, N=0 is allowed and produces
  the same result as "now", and if N=1 the final 's' of the unit name
  is allowed, but not required.

* subversion/libsvn_subr/date.c
  (unit_words_table, number_words_table, words_match): New.
  (svn_parse_date): Parse new date specifications.
]]]

Index: subversion/libsvn_subr/date.c
===================================================================
--- subversion/libsvn_subr/date.c (revision 1104073)
+++ subversion/libsvn_subr/date.c (working copy)
@@ -22,6 +22,7 @@
 
 #include "svn_time.h"
 #include "svn_error.h"
+#include "svn_string.h"
 
 #include "svn_private_config.h"
 
@@ -187,6 +188,126 @@ template_match(apr_time_exp_t *expt, svn_boolean_t
   return TRUE;
 }
 
+static struct unit_words_table {
+ const char *word;
+ apr_time_t value;
+} unit_words_table[] = {
+ /* Word matching does not concern itself with exact days of the month
+ * or leap years so these amounts are always fixed. */
+ { "years", apr_time_from_sec(60 * 60 * 24 * 365) },
+ { "months", apr_time_from_sec(60 * 60 * 24 * 30) },
+ { "weeks", apr_time_from_sec(60 * 60 * 24 * 7) },
+ { "days", apr_time_from_sec(60 * 60 * 24) },
+ { "hours", apr_time_from_sec(60 * 60) },
+ { "minutes", apr_time_from_sec(60) },
+ { "mins", apr_time_from_sec(60) },
+ { NULL , 0 }
+};
+
+static struct number_words_table {
+ const char *word;
+ int number;
+} number_words_table[] = {
+ { "zero", 0 }, { "one", 1 }, { "two", 2 }, { "three", 3 }, { "four", 4 },
+ { "five", 5 }, { "six", 6 }, { "seven", 7 }, { "eight", 8 }, { "nine", 9 },
+ { "ten", 10 }, { "eleven", 11 }, { "twelve", 12 }, { NULL, 0 }
+};
+
+/* Attempt to match the date-string in TEXT according to the following rules:
+ *
+ * "now" resolves to the most recent revision as of the current time NOW.
+ * "N years|months|weeks|days|hours|minutes ago" resolve to the most recent
+ * revision prior to the specified time. N may either be a word from
+ * NUMBER_WORDS_TABLE defined above, or a non-negative digit.
+ *
+ * Return TRUE on successful match, FALSE otherwise. On successful match,
+ * fill in *EXP with the matched value and set *LOCALTZ to TRUE (this
+ * function always uses local time). Use POOL for temporary allocations. */
+static svn_boolean_t
+words_match(apr_time_exp_t *expt, svn_boolean_t *localtz,
+ apr_time_t now, const char *text, apr_pool_t *pool)
+{
+ apr_time_t t = -1;
+ const char *word;
+ apr_array_header_t *words;
+
+ words = svn_cstring_split(text, " ", TRUE /* chop_whitespace */, pool);
+
+ if (words->nelts == 0)
+ return FALSE;
+
+ word = APR_ARRAY_IDX(words, 0, const char *);
+
+ if ((words->nelts == 1) && (!strcmp(word, "now")))
+ t = now;
+ else if (words->nelts == 3)
+ {
+ int i;
+ int n = -1;
+ const char *number_str;
+ const char *unit_str;
+
+ /* Try to parse a number word. */
+ for (i = 0, number_str = number_words_table[i].word;
+ number_str = number_words_table[i].word, number_str != NULL; i++)
+ {
+ if (!strcmp(word, number_str))
+ {
+ n = number_words_table[i].number;
+ break;
+ }
+ }
+
+ if (n < 0)
+ {
+ svn_error_t *err;
+
+ /* Try to parse a digit. */
+ err = svn_cstring_atoi(&n, word);
+ if (err)
+ {
+ svn_error_clear(err);
+ return FALSE;
+ }
+ if (n < 0)
+ return FALSE;
+ }
+
+ /* Try to parse a unit. */
+ word = APR_ARRAY_IDX(words, 1, const char *);
+ for (i = 0, unit_str = unit_words_table[i].word;
+ unit_str = unit_words_table[i].word, unit_str != NULL; i++)
+ {
+ /* Tolerate missing trailing 's' from unit for n=1. */
+ if (!strcmp(word, unit_str) ||
+ (n == 1 && !strncmp(word, unit_str, strlen(unit_str) - 1)))
+ {
+ t = now - (n * unit_words_table[i].value);
+ break;
+ }
+ }
+ if (t < 0)
+ return FALSE;
+
+ /* Require trailing "ago". */
+ word = APR_ARRAY_IDX(words, 2, const char *);
+ if (strcmp(word, "ago"))
+ return FALSE;
+ }
+ else
+ return FALSE;
+
+ if (t >= 0)
+ {
+ if (apr_time_exp_lt(expt, t) != APR_SUCCESS)
+ return FALSE;
+ *localtz = TRUE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
 static int
 valid_days_by_month[] = {
   31, 29, 31, 30,
@@ -244,7 +365,7 @@ svn_parse_date(svn_boolean_t *matched, apr_time_t
       expt.tm_mon = expnow.tm_mon;
       expt.tm_mday = expnow.tm_mday;
     }
- else
+ else if (!words_match(&expt, &localtz, now, text, pool))
     return SVN_NO_ERROR;
 
   /* Range validation, allowing for leap seconds */
Received on 2011-05-17 11:37:36 CEST

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.