@matheusbsbs / matheus-bagliano / commits / b94f2eda99
Fork 0

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");