Skip to content

Commit 93cfa7c

Browse files
committed
approxidate_careful() reports errorneous date string
For a long time, the time based reflog syntax (e.g. master@{yesterday}) didn't complain when the "human readable" timestamp was misspelled, as the underlying mechanism tried to be as lenient as possible. The funny thing was that parsing of "@{now}" even relied on the fact that anything not recognized by the machinery returned the current timestamp. Introduce approxidate_careful() that takes an optional pointer to an integer, that gets assigned 1 when the input does not make sense as a timestamp. As I am too lazy to fix all the callers that use approxidate(), most of the callers do not take advantage of the error checking, but convert the code to parse reflog to use it as a demonstration. Tests are mostly from Jeff King. Signed-off-by: Junio C Hamano <[email protected]>
1 parent 35eabd1 commit 93cfa7c

File tree

4 files changed

+86
-10
lines changed

4 files changed

+86
-10
lines changed

cache.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,8 @@ const char *show_date_relative(unsigned long time, int tz,
740740
size_t timebuf_size);
741741
int parse_date(const char *date, char *buf, int bufsize);
742742
void datestamp(char *buf, int bufsize);
743-
unsigned long approxidate(const char *);
743+
#define approxidate(s) approxidate_careful((s), NULL)
744+
unsigned long approxidate_careful(const char *, int *);
744745
unsigned long approxidate_relative(const char *date, const struct timeval *now);
745746
enum date_mode parse_date_format(const char *format);
746747

date.c

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,11 @@ static unsigned long update_tm(struct tm *tm, struct tm *now, unsigned long sec)
696696
return n;
697697
}
698698

699+
static void date_now(struct tm *tm, struct tm *now, int *num)
700+
{
701+
update_tm(tm, now, 0);
702+
}
703+
699704
static void date_yesterday(struct tm *tm, struct tm *now, int *num)
700705
{
701706
update_tm(tm, now, 24*60*60);
@@ -770,6 +775,7 @@ static const struct special {
770775
{ "PM", date_pm },
771776
{ "AM", date_am },
772777
{ "never", date_never },
778+
{ "now", date_now },
773779
{ NULL }
774780
};
775781

@@ -790,7 +796,7 @@ static const struct typelen {
790796
{ NULL }
791797
};
792798

793-
static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm *now, int *num)
799+
static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm *now, int *num, int *touched)
794800
{
795801
const struct typelen *tl;
796802
const struct special *s;
@@ -804,6 +810,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
804810
int match = match_string(date, month_names[i]);
805811
if (match >= 3) {
806812
tm->tm_mon = i;
813+
*touched = 1;
807814
return end;
808815
}
809816
}
@@ -812,6 +819,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
812819
int len = strlen(s->name);
813820
if (match_string(date, s->name) == len) {
814821
s->fn(tm, now, num);
822+
*touched = 1;
815823
return end;
816824
}
817825
}
@@ -821,11 +829,14 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
821829
int len = strlen(number_name[i]);
822830
if (match_string(date, number_name[i]) == len) {
823831
*num = i;
832+
*touched = 1;
824833
return end;
825834
}
826835
}
827-
if (match_string(date, "last") == 4)
836+
if (match_string(date, "last") == 4) {
828837
*num = 1;
838+
*touched = 1;
839+
}
829840
return end;
830841
}
831842

@@ -835,6 +846,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
835846
if (match_string(date, tl->type) >= len-1) {
836847
update_tm(tm, now, tl->length * *num);
837848
*num = 0;
849+
*touched = 1;
838850
return end;
839851
}
840852
tl++;
@@ -852,6 +864,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
852864
diff += 7*n;
853865

854866
update_tm(tm, now, diff * 24 * 60 * 60);
867+
*touched = 1;
855868
return end;
856869
}
857870
}
@@ -866,13 +879,15 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
866879
tm->tm_year--;
867880
}
868881
tm->tm_mon = n;
882+
*touched = 1;
869883
return end;
870884
}
871885

872886
if (match_string(date, "years") >= 4) {
873887
update_tm(tm, now, 0); /* fill in date fields if needed */
874888
tm->tm_year -= *num;
875889
*num = 0;
890+
*touched = 1;
876891
return end;
877892
}
878893

@@ -929,9 +944,12 @@ static void pending_number(struct tm *tm, int *num)
929944
}
930945
}
931946

932-
static unsigned long approxidate_str(const char *date, const struct timeval *tv)
947+
static unsigned long approxidate_str(const char *date,
948+
const struct timeval *tv,
949+
int *error_ret)
933950
{
934951
int number = 0;
952+
int touched = 0;
935953
struct tm tm, now;
936954
time_t time_sec;
937955

@@ -951,33 +969,42 @@ static unsigned long approxidate_str(const char *date, const struct timeval *tv)
951969
if (isdigit(c)) {
952970
pending_number(&tm, &number);
953971
date = approxidate_digit(date-1, &tm, &number);
972+
touched = 1;
954973
continue;
955974
}
956975
if (isalpha(c))
957-
date = approxidate_alpha(date-1, &tm, &now, &number);
976+
date = approxidate_alpha(date-1, &tm, &now, &number, &touched);
958977
}
959978
pending_number(&tm, &number);
979+
if (!touched)
980+
*error_ret = 1;
960981
return update_tm(&tm, &now, 0);
961982
}
962983

963984
unsigned long approxidate_relative(const char *date, const struct timeval *tv)
964985
{
965986
char buffer[50];
987+
int errors = 0;
966988

967989
if (parse_date(date, buffer, sizeof(buffer)) > 0)
968990
return strtoul(buffer, NULL, 0);
969991

970-
return approxidate_str(date, tv);
992+
return approxidate_str(date, tv, &errors);
971993
}
972994

973-
unsigned long approxidate(const char *date)
995+
unsigned long approxidate_careful(const char *date, int *error_ret)
974996
{
975997
struct timeval tv;
976998
char buffer[50];
999+
int dummy = 0;
1000+
if (!error_ret)
1001+
error_ret = &dummy;
9771002

978-
if (parse_date(date, buffer, sizeof(buffer)) > 0)
1003+
if (parse_date(date, buffer, sizeof(buffer)) > 0) {
1004+
*error_ret = 0;
9791005
return strtoul(buffer, NULL, 0);
1006+
}
9801007

9811008
gettimeofday(&tv, NULL);
982-
return approxidate_str(date, &tv);
1009+
return approxidate_str(date, &tv, error_ret);
9831010
}

sha1_name.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,11 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
395395
} else if (0 <= nth)
396396
at_time = 0;
397397
else {
398+
int errors = 0;
398399
char *tmp = xstrndup(str + at + 2, reflog_len);
399-
at_time = approxidate(tmp);
400+
at_time = approxidate_careful(tmp, &errors);
401+
if (errors)
402+
die("Bogus timestamp '%s'", tmp);
400403
free(tmp);
401404
}
402405
if (read_ref_at(real_ref, at_time, nth, sha1, NULL,

t/t0101-at-syntax.sh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/bin/sh
2+
3+
test_description='various @{whatever} syntax tests'
4+
. ./test-lib.sh
5+
6+
test_expect_success 'setup' '
7+
test_commit one &&
8+
test_commit two
9+
'
10+
11+
check_at() {
12+
echo "$2" >expect &&
13+
git log -1 --format=%s "$1" >actual &&
14+
test_cmp expect actual
15+
}
16+
17+
test_expect_success '@{0} shows current' '
18+
check_at @{0} two
19+
'
20+
21+
test_expect_success '@{1} shows old' '
22+
check_at @{1} one
23+
'
24+
25+
test_expect_success '@{now} shows current' '
26+
check_at @{now} two
27+
'
28+
29+
test_expect_success '@{30.years.ago} shows old' '
30+
check_at @{30.years.ago} one
31+
'
32+
33+
test_expect_success 'silly approxidates work' '
34+
check_at @{3.hot.dogs.and.30.years.ago} one
35+
'
36+
37+
test_expect_success 'notice misspelled upstream' '
38+
test_must_fail git log -1 --format=%s @{usptream}
39+
'
40+
41+
test_expect_success 'complain about total nonsense' '
42+
test_must_fail git log -1 --format=%s @{utter.bogosity}
43+
'
44+
45+
test_done

0 commit comments

Comments
 (0)