Merge branch 'maint-1.7.0' into maint-1.7.1
[gitweb.git] / date.c
diff --git a/date.c b/date.c
index 45f3684ceee465170a520ecf5f25dcaa0e5ed84e..6bae49ca330a69df5e2cf29e1e461f2490d99b2f 100644 (file)
--- a/date.c
+++ b/date.c
@@ -229,6 +229,7 @@ static const struct {
 
        { "GMT",    0, 0, },    /* Greenwich Mean */
        { "UTC",    0, 0, },    /* Universal (Coordinated) */
+       { "Z",      0, 0, },    /* Zulu, alias for UTC */
 
        { "WET",    0, 0, },    /* Western European */
        { "BST",    0, 1, },    /* British Summer */
@@ -305,7 +306,7 @@ static int match_alpha(const char *date, struct tm *tm, int *offset)
 
        for (i = 0; i < ARRAY_SIZE(timezone_names); i++) {
                int match = match_string(date, timezone_names[i].name);
-               if (match >= 3) {
+               if (match >= 3 || match == strlen(timezone_names[i].name)) {
                        int off = timezone_names[i].offset;
 
                        /* This is bogus, but we like summer */
@@ -696,6 +697,11 @@ static unsigned long update_tm(struct tm *tm, struct tm *now, unsigned long sec)
        return n;
 }
 
+static void date_now(struct tm *tm, struct tm *now, int *num)
+{
+       update_tm(tm, now, 0);
+}
+
 static void date_yesterday(struct tm *tm, struct tm *now, int *num)
 {
        update_tm(tm, now, 24*60*60);
@@ -770,6 +776,7 @@ static const struct special {
        { "PM", date_pm },
        { "AM", date_am },
        { "never", date_never },
+       { "now", date_now },
        { NULL }
 };
 
@@ -790,7 +797,7 @@ static const struct typelen {
        { NULL }
 };
 
-static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm *now, int *num)
+static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm *now, int *num, int *touched)
 {
        const struct typelen *tl;
        const struct special *s;
@@ -804,6 +811,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
                int match = match_string(date, month_names[i]);
                if (match >= 3) {
                        tm->tm_mon = i;
+                       *touched = 1;
                        return end;
                }
        }
@@ -812,6 +820,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
                int len = strlen(s->name);
                if (match_string(date, s->name) == len) {
                        s->fn(tm, now, num);
+                       *touched = 1;
                        return end;
                }
        }
@@ -821,11 +830,14 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
                        int len = strlen(number_name[i]);
                        if (match_string(date, number_name[i]) == len) {
                                *num = i;
+                               *touched = 1;
                                return end;
                        }
                }
-               if (match_string(date, "last") == 4)
+               if (match_string(date, "last") == 4) {
                        *num = 1;
+                       *touched = 1;
+               }
                return end;
        }
 
@@ -835,6 +847,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
                if (match_string(date, tl->type) >= len-1) {
                        update_tm(tm, now, tl->length * *num);
                        *num = 0;
+                       *touched = 1;
                        return end;
                }
                tl++;
@@ -852,6 +865,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
                        diff += 7*n;
 
                        update_tm(tm, now, diff * 24 * 60 * 60);
+                       *touched = 1;
                        return end;
                }
        }
@@ -866,6 +880,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
                        tm->tm_year--;
                }
                tm->tm_mon = n;
+               *touched = 1;
                return end;
        }
 
@@ -873,6 +888,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
                update_tm(tm, now, 0); /* fill in date fields if needed */
                tm->tm_year -= *num;
                *num = 0;
+               *touched = 1;
                return end;
        }
 
@@ -929,9 +945,12 @@ static void pending_number(struct tm *tm, int *num)
        }
 }
 
-static unsigned long approxidate_str(const char *date, const struct timeval *tv)
+static unsigned long approxidate_str(const char *date,
+                                    const struct timeval *tv,
+                                    int *error_ret)
 {
        int number = 0;
+       int touched = 0;
        struct tm tm, now;
        time_t time_sec;
 
@@ -951,33 +970,42 @@ static unsigned long approxidate_str(const char *date, const struct timeval *tv)
                if (isdigit(c)) {
                        pending_number(&tm, &number);
                        date = approxidate_digit(date-1, &tm, &number);
+                       touched = 1;
                        continue;
                }
                if (isalpha(c))
-                       date = approxidate_alpha(date-1, &tm, &now, &number);
+                       date = approxidate_alpha(date-1, &tm, &now, &number, &touched);
        }
        pending_number(&tm, &number);
+       if (!touched)
+               *error_ret = 1;
        return update_tm(&tm, &now, 0);
 }
 
 unsigned long approxidate_relative(const char *date, const struct timeval *tv)
 {
        char buffer[50];
+       int errors = 0;
 
        if (parse_date(date, buffer, sizeof(buffer)) > 0)
                return strtoul(buffer, NULL, 0);
 
-       return approxidate_str(date, tv);
+       return approxidate_str(date, tv, &errors);
 }
 
-unsigned long approxidate(const char *date)
+unsigned long approxidate_careful(const char *date, int *error_ret)
 {
        struct timeval tv;
        char buffer[50];
+       int dummy = 0;
+       if (!error_ret)
+               error_ret = &dummy;
 
-       if (parse_date(date, buffer, sizeof(buffer)) > 0)
+       if (parse_date(date, buffer, sizeof(buffer)) > 0) {
+               *error_ret = 0;
                return strtoul(buffer, NULL, 0);
+       }
 
        gettimeofday(&tv, NULL);
-       return approxidate_str(date, &tv);
+       return approxidate_str(date, &tv, error_ret);
 }