Merge branch 'tojunio' of http://locke.catalyst.net.nz/git/git-martinlanghoff
authorJunio C Hamano <junkio@cox.net>
Thu, 17 Nov 2005 10:00:25 +0000 (02:00 -0800)
committerJunio C Hamano <junkio@cox.net>
Thu, 17 Nov 2005 10:00:25 +0000 (02:00 -0800)
cache.h
date.c
rev-parse.c
test-date.c

diff --git a/cache.h b/cache.h
index 08461cf..99afa2c 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -259,6 +259,7 @@ extern void *read_object_with_reference(const unsigned char *sha1,
 const char *show_date(unsigned long time, int timezone);
 int parse_date(const char *date, char *buf, int bufsize);
 void datestamp(char *buf, int bufsize);
+unsigned long approxidate(const char *);
 
 extern int setup_ident(void);
 extern char *get_ident(const char *name, const char *email, const char *date_str);
diff --git a/date.c b/date.c
index 63f5a09..73c063b 100644 (file)
--- a/date.c
+++ b/date.c
@@ -5,6 +5,7 @@
  */
 
 #include <time.h>
+#include <sys/time.h>
 
 #include "cache.h"
 
@@ -460,3 +461,126 @@ void datestamp(char *buf, int bufsize)
 
        date_string(now, offset, buf, bufsize);
 }
+
+static void update_tm(struct tm *tm, unsigned long sec)
+{
+       time_t n = mktime(tm) - sec;
+       localtime_r(&n, tm);
+}
+
+static const char *number_name[] = {
+       "zero", "one", "two", "three", "four",
+       "five", "six", "seven", "eight", "nine", "ten",
+};
+
+static struct typelen {
+       const char *type;
+       int length;
+} typelen[] = {
+       { "seconds", 1 },
+       { "minutes", 60 },
+       { "hours", 60*60 },
+       { "days", 24*60*60 },
+       { "weeks", 7*24*60*60 },
+       { NULL }
+};     
+
+static const char *approxidate_alpha(const char *date, struct tm *tm, int *num)
+{
+       struct typelen *tl;
+       const char *end = date;
+       int n = 1, i;
+
+       while (isalpha(*++end))
+               n++;
+
+       for (i = 0; i < 12; i++) {
+               int match = match_string(date, month_names[i]);
+               if (match >= 3) {
+                       tm->tm_mon = i;
+                       return end;
+               }
+       }
+
+       if (match_string(date, "yesterday") > 8) {
+               update_tm(tm, 24*60*60);
+               return end;
+       }
+
+       if (!*num) {
+               for (i = 1; i < 11; i++) {
+                       int len = strlen(number_name[i]);
+                       if (match_string(date, number_name[i]) == len) {
+                               *num = i;
+                               return end;
+                       }
+               }
+               if (match_string(date, "last") == 4)
+                       *num = 1;
+               return end;
+       }
+
+       tl = typelen;
+       while (tl->type) {
+               int len = strlen(tl->type);
+               if (match_string(date, tl->type) >= len-1) {
+                       update_tm(tm, tl->length * *num);
+                       *num = 0;
+                       return end;
+               }
+               tl++;
+       }
+
+       if (match_string(date, "months") >= 5) {
+               int n = tm->tm_mon - *num;
+               *num = 0;
+               while (n < 0) {
+                       n += 12;
+                       tm->tm_year--;
+               }
+               tm->tm_mon = n;
+               return end;
+       }
+
+       if (match_string(date, "years") >= 4) {
+               tm->tm_year -= *num;
+               *num = 0;
+               return end;
+       }
+
+       return end;
+}
+
+unsigned long approxidate(const char *date)
+{
+       int number = 0;
+       struct tm tm, now;
+       struct timeval tv;
+       char buffer[50];
+
+       if (parse_date(date, buffer, sizeof(buffer)) > 0)
+               return strtoul(buffer, NULL, 10);
+
+       gettimeofday(&tv, NULL);
+       localtime_r(&tv.tv_sec, &tm);
+       now = tm;
+       for (;;) {
+               unsigned char c = *date;
+               if (!c)
+                       break;
+               date++;
+               if (isdigit(c)) {
+                       char *end;
+                       number = strtoul(date-1, &end, 10);
+                       date = end;
+                       continue;
+               }
+               if (isalpha(c))
+                       date = approxidate_alpha(date-1, &tm, &number);
+       }
+       if (number > 0 && number < 32)
+               tm.tm_mday = number;
+       if (tm.tm_mon > now.tm_mon)
+               tm.tm_year--;
+       return mktime(&tm);
+}
index 5a98982..bb4949a 100644 (file)
@@ -131,25 +131,12 @@ static int show_reference(const char *refname, const unsigned char *sha1)
 
 static void show_datestring(const char *flag, const char *datestr)
 {
-       FILE *date;
        static char buffer[100];
-       static char cmd[1000];
-       int len;
 
        /* date handling requires both flags and revs */
        if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))
                return;
-       len = strlen(flag);
-       memcpy(buffer, flag, len);
-
-       snprintf(cmd, sizeof(cmd), "date --date=%s +%%s", sq_quote(datestr));
-       date = popen(cmd, "r");
-       if (!date || !fgets(buffer + len, sizeof(buffer) - len, date))
-               die("git-rev-list: bad date string");
-       pclose(date);
-       len = strlen(buffer);
-       if (buffer[len-1] == '\n')
-               buffer[--len] = 0;
+       snprintf(buffer, sizeof(buffer), "%s%lu", flag, approxidate(datestr));
        show(buffer);
 }
 
index 6fe3e28..93e8027 100644 (file)
@@ -15,6 +15,9 @@ int main(int argc, char **argv)
                parse_date(argv[i], result, sizeof(result));
                t = strtoul(result, NULL, 0);
                printf("%s -> %s -> %s", argv[i], result, ctime(&t));
+
+               t = approxidate(argv[i]);
+               printf("%s -> %s\n", argv[i], ctime(&t));
        }
        return 0;
 }