Skip to content

Commit 7b676b1

Browse files
committed
Merge branch 'bg/apply-fix-blank-at-eof' into maint
* bg/apply-fix-blank-at-eof: t3417: Add test cases for "rebase --whitespace=fix" t4124: Add additional tests of --whitespace=fix apply: Allow blank context lines to match beyond EOF apply: Remove the quick rejection test apply: Don't unnecessarily update line lengths in the preimage
2 parents 846b8f6 + 59f5ced commit 7b676b1

File tree

4 files changed

+450
-40
lines changed

4 files changed

+450
-40
lines changed

builtin-apply.c

Lines changed: 145 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,33 +1854,76 @@ static int match_fragment(struct image *img,
18541854
{
18551855
int i;
18561856
char *fixed_buf, *buf, *orig, *target;
1857+
int preimage_limit;
18571858

1858-
if (preimage->nr + try_lno > img->nr)
1859+
if (preimage->nr + try_lno <= img->nr) {
1860+
/*
1861+
* The hunk falls within the boundaries of img.
1862+
*/
1863+
preimage_limit = preimage->nr;
1864+
if (match_end && (preimage->nr + try_lno != img->nr))
1865+
return 0;
1866+
} else if (ws_error_action == correct_ws_error &&
1867+
(ws_rule & WS_BLANK_AT_EOF) && match_end) {
1868+
/*
1869+
* This hunk that matches at the end extends beyond
1870+
* the end of img, and we are removing blank lines
1871+
* at the end of the file. This many lines from the
1872+
* beginning of the preimage must match with img, and
1873+
* the remainder of the preimage must be blank.
1874+
*/
1875+
preimage_limit = img->nr - try_lno;
1876+
} else {
1877+
/*
1878+
* The hunk extends beyond the end of the img and
1879+
* we are not removing blanks at the end, so we
1880+
* should reject the hunk at this position.
1881+
*/
18591882
return 0;
1883+
}
18601884

18611885
if (match_beginning && try_lno)
18621886
return 0;
18631887

1864-
if (match_end && preimage->nr + try_lno != img->nr)
1865-
return 0;
1866-
18671888
/* Quick hash check */
1868-
for (i = 0; i < preimage->nr; i++)
1889+
for (i = 0; i < preimage_limit; i++)
18691890
if (preimage->line[i].hash != img->line[try_lno + i].hash)
18701891
return 0;
18711892

1872-
/*
1873-
* Do we have an exact match? If we were told to match
1874-
* at the end, size must be exactly at try+fragsize,
1875-
* otherwise try+fragsize must be still within the preimage,
1876-
* and either case, the old piece should match the preimage
1877-
* exactly.
1878-
*/
1879-
if ((match_end
1880-
? (try + preimage->len == img->len)
1881-
: (try + preimage->len <= img->len)) &&
1882-
!memcmp(img->buf + try, preimage->buf, preimage->len))
1883-
return 1;
1893+
if (preimage_limit == preimage->nr) {
1894+
/*
1895+
* Do we have an exact match? If we were told to match
1896+
* at the end, size must be exactly at try+fragsize,
1897+
* otherwise try+fragsize must be still within the preimage,
1898+
* and either case, the old piece should match the preimage
1899+
* exactly.
1900+
*/
1901+
if ((match_end
1902+
? (try + preimage->len == img->len)
1903+
: (try + preimage->len <= img->len)) &&
1904+
!memcmp(img->buf + try, preimage->buf, preimage->len))
1905+
return 1;
1906+
} else {
1907+
/*
1908+
* The preimage extends beyond the end of img, so
1909+
* there cannot be an exact match.
1910+
*
1911+
* There must be one non-blank context line that match
1912+
* a line before the end of img.
1913+
*/
1914+
char *buf_end;
1915+
1916+
buf = preimage->buf;
1917+
buf_end = buf;
1918+
for (i = 0; i < preimage_limit; i++)
1919+
buf_end += preimage->line[i].len;
1920+
1921+
for ( ; buf < buf_end; buf++)
1922+
if (!isspace(*buf))
1923+
break;
1924+
if (buf == buf_end)
1925+
return 0;
1926+
}
18841927

18851928
/*
18861929
* No exact match. If we are ignoring whitespace, run a line-by-line
@@ -1891,7 +1934,10 @@ static int match_fragment(struct image *img,
18911934
size_t imgoff = 0;
18921935
size_t preoff = 0;
18931936
size_t postlen = postimage->len;
1894-
for (i = 0; i < preimage->nr; i++) {
1937+
size_t extra_chars;
1938+
char *preimage_eof;
1939+
char *preimage_end;
1940+
for (i = 0; i < preimage_limit; i++) {
18951941
size_t prelen = preimage->line[i].len;
18961942
size_t imglen = img->line[try_lno+i].len;
18971943

@@ -1905,20 +1951,36 @@ static int match_fragment(struct image *img,
19051951
}
19061952

19071953
/*
1908-
* Ok, the preimage matches with whitespace fuzz. Update it and
1909-
* the common postimage lines to use the same whitespace as the
1910-
* target. imgoff now holds the true length of the target that
1911-
* matches the preimage, and we need to update the line lengths
1912-
* of the preimage to match the target ones.
1954+
* Ok, the preimage matches with whitespace fuzz.
1955+
*
1956+
* imgoff now holds the true length of the target that
1957+
* matches the preimage before the end of the file.
1958+
*
1959+
* Count the number of characters in the preimage that fall
1960+
* beyond the end of the file and make sure that all of them
1961+
* are whitespace characters. (This can only happen if
1962+
* we are removing blank lines at the end of the file.)
19131963
*/
1914-
fixed_buf = xmalloc(imgoff);
1915-
memcpy(fixed_buf, img->buf + try, imgoff);
1916-
for (i = 0; i < preimage->nr; i++)
1917-
preimage->line[i].len = img->line[try_lno+i].len;
1964+
buf = preimage_eof = preimage->buf + preoff;
1965+
for ( ; i < preimage->nr; i++)
1966+
preoff += preimage->line[i].len;
1967+
preimage_end = preimage->buf + preoff;
1968+
for ( ; buf < preimage_end; buf++)
1969+
if (!isspace(*buf))
1970+
return 0;
19181971

19191972
/*
1920-
* Update the preimage buffer and the postimage context lines.
1973+
* Update the preimage and the common postimage context
1974+
* lines to use the same whitespace as the target.
1975+
* If whitespace is missing in the target (i.e.
1976+
* if the preimage extends beyond the end of the file),
1977+
* use the whitespace from the preimage.
19211978
*/
1979+
extra_chars = preimage_end - preimage_eof;
1980+
fixed_buf = xmalloc(imgoff + extra_chars);
1981+
memcpy(fixed_buf, img->buf + try, imgoff);
1982+
memcpy(fixed_buf + imgoff, preimage_eof, extra_chars);
1983+
imgoff += extra_chars;
19221984
update_pre_post_images(preimage, postimage,
19231985
fixed_buf, imgoff, postlen);
19241986
return 1;
@@ -1932,12 +1994,16 @@ static int match_fragment(struct image *img,
19321994
* it might with whitespace fuzz. We haven't been asked to
19331995
* ignore whitespace, we were asked to correct whitespace
19341996
* errors, so let's try matching after whitespace correction.
1997+
*
1998+
* The preimage may extend beyond the end of the file,
1999+
* but in this loop we will only handle the part of the
2000+
* preimage that falls within the file.
19352001
*/
19362002
fixed_buf = xmalloc(preimage->len + 1);
19372003
buf = fixed_buf;
19382004
orig = preimage->buf;
19392005
target = img->buf + try;
1940-
for (i = 0; i < preimage->nr; i++) {
2006+
for (i = 0; i < preimage_limit; i++) {
19412007
size_t fixlen; /* length after fixing the preimage */
19422008
size_t oldlen = preimage->line[i].len;
19432009
size_t tgtlen = img->line[try_lno + i].len;
@@ -1977,6 +2043,29 @@ static int match_fragment(struct image *img,
19772043
target += tgtlen;
19782044
}
19792045

2046+
2047+
/*
2048+
* Now handle the lines in the preimage that falls beyond the
2049+
* end of the file (if any). They will only match if they are
2050+
* empty or only contain whitespace (if WS_BLANK_AT_EOL is
2051+
* false).
2052+
*/
2053+
for ( ; i < preimage->nr; i++) {
2054+
size_t fixlen; /* length after fixing the preimage */
2055+
size_t oldlen = preimage->line[i].len;
2056+
int j;
2057+
2058+
/* Try fixing the line in the preimage */
2059+
fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL);
2060+
2061+
for (j = 0; j < fixlen; j++)
2062+
if (!isspace(buf[j]))
2063+
goto unmatch_exit;
2064+
2065+
orig += oldlen;
2066+
buf += fixlen;
2067+
}
2068+
19802069
/*
19812070
* Yes, the preimage is based on an older version that still
19822071
* has whitespace breakages unfixed, and fixing them makes the
@@ -2002,9 +2091,6 @@ static int find_pos(struct image *img,
20022091
unsigned long backwards, forwards, try;
20032092
int backwards_lno, forwards_lno, try_lno;
20042093

2005-
if (preimage->nr > img->nr)
2006-
return -1;
2007-
20082094
/*
20092095
* If match_beginning or match_end is specified, there is no
20102096
* point starting from a wrong line that will never match and
@@ -2015,7 +2101,12 @@ static int find_pos(struct image *img,
20152101
else if (match_end)
20162102
line = img->nr - preimage->nr;
20172103

2018-
if (line > img->nr)
2104+
/*
2105+
* Because the comparison is unsigned, the following test
2106+
* will also take care of a negative line number that can
2107+
* result when match_end and preimage is larger than the target.
2108+
*/
2109+
if ((size_t) line > img->nr)
20192110
line = img->nr;
20202111

20212112
try = 0;
@@ -2091,12 +2182,26 @@ static void update_image(struct image *img,
20912182
int i, nr;
20922183
size_t remove_count, insert_count, applied_at = 0;
20932184
char *result;
2185+
int preimage_limit;
2186+
2187+
/*
2188+
* If we are removing blank lines at the end of img,
2189+
* the preimage may extend beyond the end.
2190+
* If that is the case, we must be careful only to
2191+
* remove the part of the preimage that falls within
2192+
* the boundaries of img. Initialize preimage_limit
2193+
* to the number of lines in the preimage that falls
2194+
* within the boundaries.
2195+
*/
2196+
preimage_limit = preimage->nr;
2197+
if (preimage_limit > img->nr - applied_pos)
2198+
preimage_limit = img->nr - applied_pos;
20942199

20952200
for (i = 0; i < applied_pos; i++)
20962201
applied_at += img->line[i].len;
20972202

20982203
remove_count = 0;
2099-
for (i = 0; i < preimage->nr; i++)
2204+
for (i = 0; i < preimage_limit; i++)
21002205
remove_count += img->line[applied_pos + i].len;
21012206
insert_count = postimage->len;
21022207

@@ -2113,19 +2218,19 @@ static void update_image(struct image *img,
21132218
result[img->len] = '\0';
21142219

21152220
/* Adjust the line table */
2116-
nr = img->nr + postimage->nr - preimage->nr;
2117-
if (preimage->nr < postimage->nr) {
2221+
nr = img->nr + postimage->nr - preimage_limit;
2222+
if (preimage_limit < postimage->nr) {
21182223
/*
21192224
* NOTE: this knows that we never call remove_first_line()
21202225
* on anything other than pre/post image.
21212226
*/
21222227
img->line = xrealloc(img->line, nr * sizeof(*img->line));
21232228
img->line_allocated = img->line;
21242229
}
2125-
if (preimage->nr != postimage->nr)
2230+
if (preimage_limit != postimage->nr)
21262231
memmove(img->line + applied_pos + postimage->nr,
2127-
img->line + applied_pos + preimage->nr,
2128-
(img->nr - (applied_pos + preimage->nr)) *
2232+
img->line + applied_pos + preimage_limit,
2233+
(img->nr - (applied_pos + preimage_limit)) *
21292234
sizeof(*img->line));
21302235
memcpy(img->line + applied_pos,
21312236
postimage->line,
@@ -2321,7 +2426,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
23212426

23222427
if (applied_pos >= 0) {
23232428
if (new_blank_lines_at_end &&
2324-
preimage.nr + applied_pos == img->nr &&
2429+
preimage.nr + applied_pos >= img->nr &&
23252430
(ws_rule & WS_BLANK_AT_EOF) &&
23262431
ws_error_action != nowarn_ws_error) {
23272432
record_ws_error(WS_BLANK_AT_EOF, "+", 1, frag->linenr);

0 commit comments

Comments
 (0)