builtin-apply.c: make it more line oriented
This changes the way git-apply internally works to be more line oriented. The logic to find where the patch applies with offset used to count line numbers by always counting LF from the beginning of the buffer, but it is simplified because we count the line length of the target file and the preimage snippet upfront now. The ultimate motivation is to allow applying patches whose preimage context has whitespace corruption that has already been corrected in the local copy. For that purpose, we introduce a table of line-hash that allows us to match lines that differ only in whitespaces. Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Jan 26, 2008 at 17:42 UTC
b94f2eda99646fea71f84ccd895d94b0001d0db6
1 file changed
+280
-123
builtin-apply.c
+280
-123
@@ -161,6 +161,92 @@ struct patch {
161
struct patch *next;
162
};
163
164
+/*
165
+ * A line in a file, len-bytes long (includes the terminating LF,
166
+ * except for an incomplete line at the end if the file ends with
167
+ * one), and its contents hashes to 'hash'.
168
+ */
169
+struct line {
170
+ size_t len;
171
+ unsigned hash : 24;
172
+ unsigned flag : 8;
173
+};
174
+
175
+/*
176
+ * This represents a "file", which is an array of "lines".
177
+ */
178
+struct image {
179
+ char *buf;
180
+ size_t len;
181
+ size_t nr;
182
+ struct line *line_allocated;
183
+ struct line *line;
184
+};
185
+
186
+static uint32_t hash_line(const char *cp, size_t len)
187
+{
188
+ size_t i;
189
+ uint32_t h;
190
+ for (i = 0, h = 0; i < len; i++) {
191
+ if (!isspace(cp[i])) {
192
+ h = h * 3 + (cp[i] & 0xff);
193
+ }
194
+ }
195
+ return h;
196
+}
197
+
198
+static void prepare_image(struct image *image, char *buf, size_t len,
199
+ int prepare_linetable)
200
+{
201
+ const char *cp, *ep;
202
+ int n;
203
+
204
+ image->buf = buf;
205
+ image->len = len;
206
+
207
+ if (!prepare_linetable) {
208
+ image->line = NULL;
209
+ image->line_allocated = NULL;
210
+ image->nr = 0;
211
+ return;
212
+ }
213
+
214
+ ep = image->buf + image->len;
215
+
216
+ /* First count lines */
217
+ cp = image->buf;
218
+ n = 0;
219
+ while (cp < ep) {
220
+ cp = strchrnul(cp, '\n');
221
+ n++;
222
+ cp++;
223
+ }
224
+
225
+ image->line_allocated = xcalloc(n, sizeof(struct line));
226
+ image->line = image->line_allocated;
227
+ image->nr = n;
228
+ cp = image->buf;
229
+ n = 0;
230
+ while (cp < ep) {
231
+ const char *next;
232
+ for (next = cp; next < ep && *next != '\n'; next++)
233
+ ;
234
+ if (next < ep)
235
+ next++;
236
+ image->line[n].len = next - cp;
237
+ image->line[n].hash = hash_line(cp, next - cp);
238
+ cp = next;
239
+ n++;
240
+ }
241
+}
242
+
243
+static void clear_image(struct image *image)
244
+{
245
+ free(image->buf);
246
+ image->buf = NULL;
247
+ image->len = 0;
248
+}
249
+
250
static void say_patch_name(FILE *output, const char *pre,
251
struct patch *patch, const char *post)
252
{
@@ -1437,14 +1523,29 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
1523
}
1524
}
1525
1440
-static int match_fragment(const char *buf, unsigned long size,
1526
+static int match_fragment(struct image *img,
1527
+ struct image *preimage,
1528
+ struct image *postimage,
1529
unsigned long try,
1442
- const char *fragment, unsigned long fragsize,
1530
+ int try_lno,
1531
int match_beginning, int match_end)
1532
{
1445
- if (match_beginning && try)
1533
+ int i;
1534
+
1535
+ if (preimage->nr + try_lno > img->nr)
1536
+ return 0;
1537
+
1538
+ if (match_beginning && try_lno)
1539
+ return 0;
1540
+
1541
+ if (match_end && preimage->nr + try_lno != img->nr)
1542
return 0;
1543
1544
+ /* Quick hash check */
1545
+ for (i = 0; i < preimage->nr; i++)
1546
+ if (preimage->line[i].hash != img->line[try_lno + i].hash)
1547
+ return 0;
1548
+
1549
/*
1550
* Do we have an exact match? If we were told to match
1551
* at the end, size must be exactly at try+fragsize,
@@ -1453,9 +1554,9 @@ static int match_fragment(const char *buf, unsigned long size,
1554
* exactly.
1555
*/
1556
if ((match_end
1456
- ? (try + fragsize == size)
1457
- : (try + fragsize <= size)) &&
1458
- !memcmp(buf + try, fragment, fragsize))
1557
+ ? (try + preimage->len == img->len)
1558
+ : (try + preimage->len <= img->len)) &&
1559
+ !memcmp(img->buf + try, preimage->buf, preimage->len))
1560
return 1;
1561
1562
/*
@@ -1465,105 +1566,78 @@ static int match_fragment(const char *buf, unsigned long size,
1566
return 0;
1567
}
1568
1468
-static int find_offset(const char *buf, unsigned long size,
1469
- const char *fragment, unsigned long fragsize,
1470
- int line, int *lines,
1471
- int match_beginning, int match_end)
1569
+static int find_pos(struct image *img,
1570
+ struct image *preimage,
1571
+ struct image *postimage,
1572
+ int line,
1573
+ int match_beginning, int match_end)
1574
{
1473
- int i, no_more_backwards, no_more_forwards;
1474
- unsigned long start, backwards, forwards, try;
1575
+ int i;
1576
+ unsigned long backwards, forwards, try;
1577
+ int backwards_lno, forwards_lno, try_lno;
1578
1476
- if (fragsize > size)
1579
+ if (preimage->nr > img->nr)
1580
return -1;
1581
1479
- start = 0;
1480
- if (line > 1) {
1481
- unsigned long offset = 0;
1482
- i = line-1;
1483
- while (offset + fragsize <= size) {
1484
- if (buf[offset++] == '\n') {
1485
- start = offset;
1486
- if (!--i)
1487
- break;
1488
- }
1489
- }
1490
- }
1582
+ try = 0;
1583
+ for (i = 0; i < line; i++)
1584
+ try += img->line[i].len;
1585
1586
/*
1587
* There's probably some smart way to do this, but I'll leave
1588
* that to the smart and beautiful people. I'm simple and stupid.
1589
*/
1496
- backwards = start;
1497
- forwards = start;
1498
- try = start;
1590
+ backwards = try;
1591
+ backwards_lno = line;
1592
+ forwards = try;
1593
+ forwards_lno = line;
1594
+ try_lno = line;
1595
1596
for (i = 0; ; i++) {
1501
- no_more_backwards = !backwards;
1502
- no_more_forwards = (forwards + fragsize > size);
1503
-
1504
- if (match_fragment(buf, size, try, fragment, fragsize,
1505
- match_beginning, match_end)) {
1506
- int shift = ((i+1) >> 1);
1507
- if (i & 1)
1508
- shift = -shift;
1509
- *lines = shift;
1510
- return try;
1511
- }
1597
+ if (match_fragment(img, preimage, postimage,
1598
+ try, try_lno,
1599
+ match_beginning, match_end))
1600
+ return try_lno;
1601
1602
again:
1514
- if (no_more_backwards && no_more_forwards)
1603
+ if (backwards_lno == 0 && forwards_lno == img->nr)
1604
break;
1605
1606
if (i & 1) {
1518
- if (no_more_backwards) {
1607
+ if (backwards_lno == 0) {
1608
i++;
1609
goto again;
1610
}
1522
- do {
1523
- --backwards;
1524
- } while (backwards && buf[backwards-1] != '\n');
1611
+ backwards_lno--;
1612
+ backwards -= img->line[backwards_lno].len;
1613
try = backwards;
1614
+ try_lno = backwards_lno;
1615
} else {
1527
- if (no_more_forwards) {
1616
+ if (forwards_lno == img->nr) {
1617
i++;
1618
goto again;
1619
}
1531
- while (forwards + fragsize <= size) {
1532
- if (buf[forwards++] == '\n')
1533
- break;
1534
- }
1620
+ forwards += img->line[forwards_lno].len;
1621
+ forwards_lno++;
1622
try = forwards;
1623
+ try_lno = forwards_lno;
1624
}
1625
1626
}
1627
return -1;
1628
}
1629
1542
-static void remove_first_line(const char **rbuf, int *rsize)
1630
+static void remove_first_line(struct image *img)
1631
{
1544
- const char *buf = *rbuf;
1545
- int size = *rsize;
1546
- unsigned long offset;
1547
- offset = 0;
1548
- while (offset <= size) {
1549
- if (buf[offset++] == '\n')
1550
- break;
1551
- }
1552
- *rsize = size - offset;
1553
- *rbuf = buf + offset;
1632
+ img->buf += img->line[0].len;
1633
+ img->len -= img->line[0].len;
1634
+ img->line++;
1635
+ img->nr--;
1636
}
1637
1556
-static void remove_last_line(const char **rbuf, int *rsize)
1638
+static void remove_last_line(struct image *img)
1639
{
1558
- const char *buf = *rbuf;
1559
- int size = *rsize;
1560
- unsigned long offset;
1561
- offset = size - 1;
1562
- while (offset > 0) {
1563
- if (buf[--offset] == '\n')
1564
- break;
1565
- }
1566
- *rsize = offset + 1;
1640
+ img->len -= img->line[--img->nr].len;
1641
}
1642
1643
static int apply_line(char *output, const char *patch, int plen,
@@ -1668,19 +1742,75 @@ static int apply_line(char *output, const char *patch, int plen,
1742
return output + plen - buf;
1743
}
1744
1671
-static int apply_one_fragment(struct strbuf *buf, struct fragment *frag,
1745
+static void update_image(struct image *img,
1746
+ int applied_pos,
1747
+ struct image *preimage,
1748
+ struct image *postimage)
1749
+{
1750
+ /*
1751
+ * remove the copy of preimage at offset in img
1752
+ * and replace it with postimage
1753
+ */
1754
+ int i, nr;
1755
+ size_t remove_count, insert_count, applied_at = 0;
1756
+ char *result;
1757
+
1758
+ for (i = 0; i < applied_pos; i++)
1759
+ applied_at += img->line[i].len;
1760
+
1761
+ remove_count = 0;
1762
+ for (i = 0; i < preimage->nr; i++)
1763
+ remove_count += img->line[applied_pos + i].len;
1764
+ insert_count = postimage->len;
1765
+
1766
+ /* Adjust the contents */
1767
+ result = xmalloc(img->len + insert_count - remove_count + 1);
1768
+ memcpy(result, img->buf, applied_at);
1769
+ memcpy(result + applied_at, postimage->buf, postimage->len);
1770
+ memcpy(result + applied_at + postimage->len,
1771
+ img->buf + (applied_at + remove_count),
1772
+ img->len - (applied_at + remove_count));
1773
+ free(img->buf);
1774
+ img->buf = result;
1775
+ img->len += insert_count - remove_count;
1776
+ result[img->len] = '\0';
1777
+
1778
+ /* Adjust the line table */
1779
+ nr = img->nr + postimage->nr - preimage->nr;
1780
+ if (preimage->nr < postimage->nr) {
1781
+ /*
1782
+ * NOTE: this knows that we never call remove_first_line()
1783
+ * on anything other than pre/post image.
1784
+ */
1785
+ img->line = xrealloc(img->line, nr * sizeof(*img->line));
1786
+ img->line_allocated = img->line;
1787
+ }
1788
+ if (preimage->nr != postimage->nr)
1789
+ memmove(img->line + applied_pos + postimage->nr,
1790
+ img->line + applied_pos + preimage->nr,
1791
+ (img->nr - (applied_pos + preimage->nr)) *
1792
+ sizeof(*img->line));
1793
+ memcpy(img->line + applied_pos,
1794
+ postimage->line,
1795
+ postimage->nr * sizeof(*img->line));
1796
+ img->nr = nr;
1797
+}
1798
+
1799
+static int apply_one_fragment(struct image *img, struct fragment *frag,
1800
int inaccurate_eof, unsigned ws_rule)
1801
{
1802
int match_beginning, match_end;
1803
const char *patch = frag->patch;
1676
- int offset, size = frag->size;
1804
+ int size = frag->size;
1805
char *old = xmalloc(size);
1806
char *new = xmalloc(size);
1679
- const char *oldlines, *newlines;
1807
+ char *oldlines, *newlines;
1808
int oldsize = 0, newsize = 0;
1809
int new_blank_lines_at_end = 0;
1810
unsigned long leading, trailing;
1683
- int pos, lines;
1811
+ int pos, applied_pos;
1812
+ struct image preimage;
1813
+ struct image postimage;
1814
1815
while (size > 0) {
1816
char first;
@@ -1780,32 +1910,16 @@ static int apply_one_fragment(struct strbuf *buf, struct fragment *frag,
1910
match_end = !trailing;
1911
}
1912
1783
- lines = 0;
1784
- pos = frag->newpos;
1913
+ pos = frag->newpos ? (frag->newpos - 1) : 0;
1914
+ prepare_image(&preimage, oldlines, oldsize, 1);
1915
+ prepare_image(&postimage, newlines, newsize, 1);
1916
for (;;) {
1786
- offset = find_offset(buf->buf, buf->len,
1787
- oldlines, oldsize, pos, &lines,
1788
- match_beginning, match_end);
1789
- if (offset >= 0) {
1790
- if (ws_error_action == correct_ws_error &&
1791
- (buf->len - oldsize - offset == 0))
1792
- /* end of file? */
1793
- newsize -= new_blank_lines_at_end;
1917
1795
- /*
1796
- * Warn if it was necessary to reduce the number
1797
- * of context lines.
1798
- */
1799
- if ((leading != frag->leading) ||
1800
- (trailing != frag->trailing))
1801
- fprintf(stderr, "Context reduced to (%ld/%ld)"
1802
- " to apply fragment at %d\n",
1803
- leading, trailing, pos + lines);
1804
-
1805
- strbuf_splice(buf, offset, oldsize, newlines, newsize);
1806
- offset = 0;
1918
+ applied_pos = find_pos(img, &preimage, &postimage,
1919
+ pos, match_beginning, match_end);
1920
+
1921
+ if (applied_pos >= 0)
1922
break;
1808
- }
1923
1924
/* Am I at my context limits? */
1925
if ((leading <= p_context) && (trailing <= p_context))
@@ -1814,33 +1928,63 @@ static int apply_one_fragment(struct strbuf *buf, struct fragment *frag,
1928
match_beginning = match_end = 0;
1929
continue;
1930
}
1931
+
1932
/*
1933
* Reduce the number of context lines; reduce both
1934
* leading and trailing if they are equal otherwise
1935
* just reduce the larger context.
1936
*/
1937
if (leading >= trailing) {
1823
- remove_first_line(&oldlines, &oldsize);
1824
- remove_first_line(&newlines, &newsize);
1938
+ remove_first_line(&preimage);
1939
+ remove_first_line(&postimage);
1940
pos--;
1941
leading--;
1942
}
1943
if (trailing > leading) {
1829
- remove_last_line(&oldlines, &oldsize);
1830
- remove_last_line(&newlines, &newsize);
1944
+ remove_last_line(&preimage);
1945
+ remove_last_line(&postimage);
1946
trailing--;
1947
}
1948
}
1949
1835
- if (offset && apply_verbosely)
1836
- error("while searching for:\n%.*s", oldsize, oldlines);
1950
+ if (applied_pos >= 0) {
1951
+ if (ws_error_action == correct_ws_error &&
1952
+ new_blank_lines_at_end &&
1953
+ postimage.nr + applied_pos == img->nr) {
1954
+ /*
1955
+ * If the patch application adds blank lines
1956
+ * at the end, and if the patch applies at the
1957
+ * end of the image, remove those added blank
1958
+ * lines.
1959
+ */
1960
+ while (new_blank_lines_at_end--)
1961
+ remove_last_line(&postimage);
1962
+ }
1963
+
1964
+ /*
1965
+ * Warn if it was necessary to reduce the number
1966
+ * of context lines.
1967
+ */
1968
+ if ((leading != frag->leading) ||
1969
+ (trailing != frag->trailing))
1970
+ fprintf(stderr, "Context reduced to (%ld/%ld)"
1971
+ " to apply fragment at %d\n",
1972
+ leading, trailing, applied_pos+1);
1973
+ update_image(img, applied_pos, &preimage, &postimage);
1974
+ } else {
1975
+ if (apply_verbosely)
1976
+ error("while searching for:\n%.*s", oldsize, oldlines);
1977
+ }
1978
1979
free(old);
1980
free(new);
1840
- return offset;
1981
+ free(preimage.line_allocated);
1982
+ free(postimage.line_allocated);
1983
+
1984
+ return (applied_pos < 0);
1985
}
1986
1843
-static int apply_binary_fragment(struct strbuf *buf, struct patch *patch)
1987
+static int apply_binary_fragment(struct image *img, struct patch *patch)
1988
{
1989
struct fragment *fragment = patch->fragments;
1990
unsigned long len;
@@ -1857,22 +2001,26 @@ static int apply_binary_fragment(struct strbuf *buf, struct patch *patch)
2001
}
2002
switch (fragment->binary_patch_method) {
2003
case BINARY_DELTA_DEFLATED:
1860
- dst = patch_delta(buf->buf, buf->len, fragment->patch,
2004
+ dst = patch_delta(img->buf, img->len, fragment->patch,
2005
fragment->size, &len);
2006
if (!dst)
2007
return -1;
1864
- /* XXX patch_delta NUL-terminates */
1865
- strbuf_attach(buf, dst, len, len + 1);
2008
+ clear_image(img);
2009
+ img->buf = dst;
2010
+ img->len = len;
2011
return 0;
2012
case BINARY_LITERAL_DEFLATED:
1868
- strbuf_reset(buf);
1869
- strbuf_add(buf, fragment->patch, fragment->size);
2013
+ clear_image(img);
2014
+ img->len = fragment->size;
2015
+ img->buf = xmalloc(img->len+1);
2016
+ memcpy(img->buf, fragment->patch, img->len);
2017
+ img->buf[img->len] = '\0';
2018
return 0;
2019
}
2020
return -1;
2021
}
2022
1875
-static int apply_binary(struct strbuf *buf, struct patch *patch)
2023
+static int apply_binary(struct image *img, struct patch *patch)
2024
{
2025
const char *name = patch->old_name ? patch->old_name : patch->new_name;
2026
unsigned char sha1[20];
@@ -1893,7 +2041,7 @@ static int apply_binary(struct strbuf *buf, struct patch *patch)
2041
* See if the old one matches what the patch
2042
* applies to.
2043
*/
1896
- hash_sha1_file(buf->buf, buf->len, blob_type, sha1);
2044
+ hash_sha1_file(img->buf, img->len, blob_type, sha1);
2045
if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
2046
return error("the patch applies to '%s' (%s), "
2047
"which does not match the "
@@ -1902,14 +2050,14 @@ static int apply_binary(struct strbuf *buf, struct patch *patch)
2050
}
2051
else {
2052
/* Otherwise, the old one must be empty. */
1905
- if (buf->len)
2053
+ if (img->len)
2054
return error("the patch applies to an empty "
2055
"'%s' but it is not empty", name);
2056
}
2057
2058
get_sha1_hex(patch->new_sha1_prefix, sha1);
2059
if (is_null_sha1(sha1)) {
1912
- strbuf_release(buf);
2060
+ clear_image(img);
2061
return 0; /* deletion patch */
2062
}
2063
@@ -1924,20 +2072,21 @@ static int apply_binary(struct strbuf *buf, struct patch *patch)
2072
return error("the necessary postimage %s for "
2073
"'%s' cannot be read",
2074
patch->new_sha1_prefix, name);
1927
- /* XXX read_sha1_file NUL-terminates */
1928
- strbuf_attach(buf, result, size, size + 1);
2075
+ clear_image(img);
2076
+ img->buf = result;
2077
+ img->len = size;
2078
} else {
2079
/*
2080
* We have verified buf matches the preimage;
2081
* apply the patch data to it, which is stored
2082
* in the patch->fragments->{patch,size}.
2083
*/
1935
- if (apply_binary_fragment(buf, patch))
2084
+ if (apply_binary_fragment(img, patch))
2085
return error("binary patch does not apply to '%s'",
2086
name);
2087
2088
/* verify that the result matches */
1940
- hash_sha1_file(buf->buf, buf->len, blob_type, sha1);
2089
+ hash_sha1_file(img->buf, img->len, blob_type, sha1);
2090
if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix))
2091
return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)",
2092
name, patch->new_sha1_prefix, sha1_to_hex(sha1));
@@ -1946,7 +2095,7 @@ static int apply_binary(struct strbuf *buf, struct patch *patch)
2095
return 0;
2096
}
2097
1949
-static int apply_fragments(struct strbuf *buf, struct patch *patch)
2098
+static int apply_fragments(struct image *img, struct patch *patch)
2099
{
2100
struct fragment *frag = patch->fragments;
2101
const char *name = patch->old_name ? patch->old_name : patch->new_name;
@@ -1954,10 +2103,10 @@ static int apply_fragments(struct strbuf *buf, struct patch *patch)
2103
unsigned inaccurate_eof = patch->inaccurate_eof;
2104
2105
if (patch->is_binary)
1957
- return apply_binary(buf, patch);
2106
+ return apply_binary(img, patch);
2107
2108
while (frag) {
1960
- if (apply_one_fragment(buf, frag, inaccurate_eof, ws_rule)) {
2109
+ if (apply_one_fragment(img, frag, inaccurate_eof, ws_rule)) {
2110
error("patch failed: %s:%ld", name, frag->oldpos);
2111
if (!apply_with_reject)
2112
return -1;
@@ -1993,6 +2142,9 @@ static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
2142
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
2143
{
2144
struct strbuf buf;
2145
+ struct image image;
2146
+ size_t len;
2147
+ char *img;
2148
2149
strbuf_init(&buf, 0);
2150
if (cached) {
@@ -2015,9 +2167,14 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
2167
}
2168
}
2169
2018
- if (apply_fragments(&buf, patch) < 0)
2170
+ img = strbuf_detach(&buf, &len);
2171
+ prepare_image(&image, img, len, !patch->is_binary);
2172
+
2173
+ if (apply_fragments(&image, patch) < 0)
2174
return -1; /* note with --reject this succeeds. */
2020
- patch->result = strbuf_detach(&buf, &patch->resultsize);
2175
+ patch->result = image.buf;
2176
+ patch->resultsize = image.len;
2177
+ free(image.line_allocated);
2178
2179
if (0 < patch->is_delete && patch->resultsize)
2180
return error("removal patch leaves file contents");