index 9deb206faa5259e4f4f0a458ddc14dd4762da10b..acecf8de54e0446c16da2291de6d90b4606f3287 100644 (file)
--- a/apply.c
+++ b/apply.c
*/
#include <fnmatch.h>
#include "cache.h"
*/
#include <fnmatch.h>
#include "cache.h"
+#include "cache-tree.h"
#include "quote.h"
#include "quote.h"
+#include "blob.h"
// --check turns on checking that the working tree matches the
// files that are being modified, but doesn't apply the patch
// --check turns on checking that the working tree matches the
// files that are being modified, but doesn't apply the patch
static int no_add = 0;
static int show_index_info = 0;
static int line_termination = '\n';
static int no_add = 0;
static int show_index_info = 0;
static int line_termination = '\n';
+static unsigned long p_context = -1;
static const char apply_usage[] =
static const char apply_usage[] =
-"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] <patch>...";
+"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
static enum whitespace_eol {
nowarn_whitespace,
static enum whitespace_eol {
nowarn_whitespace,
static int linenr = 1;
struct fragment {
static int linenr = 1;
struct fragment {
+ unsigned long leading, trailing;
unsigned long oldpos, oldlines;
unsigned long newpos, newlines;
const char *patch;
unsigned long oldpos, oldlines;
unsigned long newpos, newlines;
const char *patch;
@@ -651,7 +655,7 @@ static int parse_git_header(char *line, int len, unsigned int size, struct patch
len = linelen(line, size);
if (!len || line[len-1] != '\n')
break;
len = linelen(line, size);
if (!len || line[len-1] != '\n')
break;
- for (i = 0; i < sizeof(optable) / sizeof(optable[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(optable); i++) {
const struct opentry *p = optable + i;
int oplen = strlen(p->str);
if (len < oplen || memcmp(p->str, line, oplen))
const struct opentry *p = optable + i;
int oplen = strlen(p->str);
if (len < oplen || memcmp(p->str, line, oplen))
@@ -693,7 +697,7 @@ static int parse_range(const char *line, int len, int offset, const char *expect
line += digits;
len -= digits;
line += digits;
len -= digits;
- *p2 = *p1;
+ *p2 = 1;
if (*line == ',') {
digits = parse_num(line+1, p2);
if (!digits)
if (*line == ',') {
digits = parse_num(line+1, p2);
if (!digits)
@@ -816,12 +820,15 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
int added, deleted;
int len = linelen(line, size), offset;
unsigned long oldlines, newlines;
int added, deleted;
int len = linelen(line, size), offset;
unsigned long oldlines, newlines;
+ unsigned long leading, trailing;
offset = parse_fragment_header(line, len, fragment);
if (offset < 0)
return -1;
oldlines = fragment->oldlines;
newlines = fragment->newlines;
offset = parse_fragment_header(line, len, fragment);
if (offset < 0)
return -1;
oldlines = fragment->oldlines;
newlines = fragment->newlines;
+ leading = 0;
+ trailing = 0;
if (patch->is_new < 0) {
patch->is_new = !oldlines;
if (patch->is_new < 0) {
patch->is_new = !oldlines;
@@ -834,7 +841,7 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
patch->new_name = NULL;
}
patch->new_name = NULL;
}
- if (patch->is_new != !oldlines)
+ if (patch->is_new && oldlines)
return error("new file depends on old contents");
if (patch->is_delete != !newlines) {
if (newlines)
return error("new file depends on old contents");
if (patch->is_delete != !newlines) {
if (newlines)
@@ -859,10 +866,14 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
case ' ':
oldlines--;
newlines--;
case ' ':
oldlines--;
newlines--;
+ if (!deleted && !added)
+ leading++;
+ trailing++;
break;
case '-':
deleted++;
oldlines--;
break;
case '-':
deleted++;
oldlines--;
+ trailing = 0;
break;
case '+':
/*
break;
case '+':
/*
@@ -886,6 +897,7 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
}
added++;
newlines--;
}
added++;
newlines--;
+ trailing = 0;
break;
/* We allow "\ No newline at end of file". Depending
break;
/* We allow "\ No newline at end of file". Depending
@@ -901,6 +913,11 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
break;
}
}
break;
}
}
+ if (oldlines || newlines)
+ return -1;
+ fragment->leading = leading;
+ fragment->trailing = trailing;
+
/* If a fragment ends with an incomplete line, we failed to include
* it in the above loop because we hit oldlines == newlines == 0
* before seeing it.
/* If a fragment ends with an incomplete line, we failed to include
* it in the above loop because we hit oldlines == newlines == 0
* before seeing it.
@@ -922,8 +939,7 @@ static int parse_single_patch(char *line, unsigned long size, struct patch *patc
struct fragment *fragment;
int len;
struct fragment *fragment;
int len;
- fragment = xmalloc(sizeof(*fragment));
- memset(fragment, 0, sizeof(*fragment));
+ fragment = xcalloc(1, sizeof(*fragment));
len = parse_fragment(line, size, patch, fragment);
if (len <= 0)
die("corrupt patch at line %d", linenr);
len = parse_fragment(line, size, patch, fragment);
if (len <= 0)
die("corrupt patch at line %d", linenr);
@@ -1085,7 +1101,7 @@ static int read_old_data(struct stat *st, const char *path, void *buf, unsigned
}
}
}
}
-static int find_offset(const char *buf, unsigned long size, const char *fragment, unsigned long fragsize, int line)
+static int find_offset(const char *buf, unsigned long size, const char *fragment, unsigned long fragsize, int line, int *lines)
{
int i;
unsigned long start, backwards, forwards;
{
int i;
unsigned long start, backwards, forwards;
@@ -1146,6 +1162,7 @@ static int find_offset(const char *buf, unsigned long size, const char *fragment
n = (i >> 1)+1;
if (i & 1)
n = -n;
n = (i >> 1)+1;
if (i & 1)
n = -n;
+ *lines = n;
return try;
}
return try;
}
@@ -1155,6 +1172,33 @@ static int find_offset(const char *buf, unsigned long size, const char *fragment
return -1;
}
return -1;
}
+static void remove_first_line(const char **rbuf, int *rsize)
+{
+ const char *buf = *rbuf;
+ int size = *rsize;
+ unsigned long offset;
+ offset = 0;
+ while (offset <= size) {
+ if (buf[offset++] == '\n')
+ break;
+ }
+ *rsize = size - offset;
+ *rbuf = buf + offset;
+}
+
+static void remove_last_line(const char **rbuf, int *rsize)
+{
+ const char *buf = *rbuf;
+ int size = *rsize;
+ unsigned long offset;
+ offset = size - 1;
+ while (offset > 0) {
+ if (buf[--offset] == '\n')
+ break;
+ }
+ *rsize = offset + 1;
+}
+
struct buffer_desc {
char *buffer;
unsigned long size;
struct buffer_desc {
char *buffer;
unsigned long size;
@@ -1190,7 +1234,10 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag)
int offset, size = frag->size;
char *old = xmalloc(size);
char *new = xmalloc(size);
int offset, size = frag->size;
char *old = xmalloc(size);
char *new = xmalloc(size);
+ const char *oldlines, *newlines;
int oldsize = 0, newsize = 0;
int oldsize = 0, newsize = 0;
+ unsigned long leading, trailing;
+ int pos, lines;
while (size > 0) {
int len = linelen(patch, size);
while (size > 0) {
int len = linelen(patch, size);
@@ -1239,23 +1286,59 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag)
newsize--;
}
#endif
newsize--;
}
#endif
-
- offset = find_offset(buf, desc->size, old, oldsize, frag->newpos);
- if (offset >= 0) {
- int diff = newsize - oldsize;
- unsigned long size = desc->size + diff;
- unsigned long alloc = desc->alloc;
-
- if (size > alloc) {
- alloc = size + 8192;
- desc->alloc = alloc;
- buf = xrealloc(buf, alloc);
- desc->buffer = buf;
+
+ oldlines = old;
+ newlines = new;
+ leading = frag->leading;
+ trailing = frag->trailing;
+ lines = 0;
+ pos = frag->newpos;
+ for (;;) {
+ offset = find_offset(buf, desc->size, oldlines, oldsize, pos, &lines);
+ if (offset >= 0) {
+ int diff = newsize - oldsize;
+ unsigned long size = desc->size + diff;
+ unsigned long alloc = desc->alloc;
+
+ /* Warn if it was necessary to reduce the number
+ * of context lines.
+ */
+ if ((leading != frag->leading) || (trailing != frag->trailing))
+ fprintf(stderr, "Context reduced to (%ld/%ld) to apply fragment at %d\n",
+ leading, trailing, pos + lines);
+
+ if (size > alloc) {
+ alloc = size + 8192;
+ desc->alloc = alloc;
+ buf = xrealloc(buf, alloc);
+ desc->buffer = buf;
+ }
+ desc->size = size;
+ memmove(buf + offset + newsize, buf + offset + oldsize, size - offset - newsize);
+ memcpy(buf + offset, newlines, newsize);
+ offset = 0;
+
+ break;
+ }
+
+ /* Am I at my context limits? */
+ if ((leading <= p_context) && (trailing <= p_context))
+ break;
+ /* Reduce the number of context lines
+ * Reduce both leading and trailing if they are equal
+ * otherwise just reduce the larger context.
+ */
+ if (leading >= trailing) {
+ remove_first_line(&oldlines, &oldsize);
+ remove_first_line(&newlines, &newsize);
+ pos--;
+ leading--;
+ }
+ if (trailing > leading) {
+ remove_last_line(&oldlines, &oldsize);
+ remove_last_line(&newlines, &newsize);
+ trailing--;
}
}
- desc->size = size;
- memmove(buf + offset + newsize, buf + offset + oldsize, size - offset - newsize);
- memcpy(buf + offset, new, newsize);
- offset = 0;
}
free(old);
}
free(old);
* applies to.
*/
write_sha1_file_prepare(desc->buffer, desc->size,
* applies to.
*/
write_sha1_file_prepare(desc->buffer, desc->size,
- "blob", sha1, hdr, &hdrlen);
+ blob_type, sha1, hdr, &hdrlen);
if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
return error("the patch applies to '%s' (%s), "
"which does not match the "
if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
return error("the patch applies to '%s' (%s), "
"which does not match the "
costate.not_new = 0;
costate.refresh_cache = 1;
if (checkout_entry(active_cache[pos],
costate.not_new = 0;
costate.refresh_cache = 1;
if (checkout_entry(active_cache[pos],
- &costate) ||
+ &costate,
+ NULL) ||
lstat(old_name, &st))
return -1;
}
lstat(old_name, &st))
return -1;
}
if (write_index) {
if (remove_file_from_cache(patch->old_name) < 0)
die("unable to remove %s from index", patch->old_name);
if (write_index) {
if (remove_file_from_cache(patch->old_name) < 0)
die("unable to remove %s from index", patch->old_name);
+ cache_tree_invalidate_path(active_cache_tree, patch->old_name);
}
unlink(patch->old_name);
}
}
unlink(patch->old_name);
}
@@ -1648,15 +1733,14 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
if (!write_index)
return;
if (!write_index)
return;
- ce = xmalloc(ce_size);
- memset(ce, 0, ce_size);
+ ce = xcalloc(1, ce_size);
memcpy(ce->name, path, namelen);
ce->ce_mode = create_ce_mode(mode);
ce->ce_flags = htons(namelen);
if (lstat(path, &st) < 0)
die("unable to stat newly created file %s", path);
fill_stat_cache_info(ce, &st);
memcpy(ce->name, path, namelen);
ce->ce_mode = create_ce_mode(mode);
ce->ce_flags = htons(namelen);
if (lstat(path, &st) < 0)
die("unable to stat newly created file %s", path);
fill_stat_cache_info(ce, &st);
- if (write_sha1_file(buf, size, "blob", ce->sha1) < 0)
+ if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0)
die("unable to create backing store for newly created file %s", path);
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
die("unable to add cache entry for %s", path);
die("unable to create backing store for newly created file %s", path);
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
die("unable to add cache entry for %s", path);
if (!mode)
mode = S_IFREG | 0644;
if (!mode)
mode = S_IFREG | 0644;
- create_one_file(path, mode, buf, size);
+ create_one_file(path, mode, buf, size);
add_index_file(path, mode, buf, size);
add_index_file(path, mode, buf, size);
+ cache_tree_invalidate_path(active_cache_tree, path);
}
static void write_out_one_result(struct patch *patch)
}
static void write_out_one_result(struct patch *patch)
struct patch *patch;
int nr;
struct patch *patch;
int nr;
- patch = xmalloc(sizeof(*patch));
- memset(patch, 0, sizeof(*patch));
+ patch = xcalloc(1, sizeof(*patch));
nr = parse_chunk(buffer + offset, size, patch);
if (nr < 0)
break;
nr = parse_chunk(buffer + offset, size, patch);
if (nr < 0)
break;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
+ char *end;
int fd;
if (!strcmp(arg, "-")) {
int fd;
if (!strcmp(arg, "-")) {
line_termination = 0;
continue;
}
line_termination = 0;
continue;
}
+ if (!strncmp(arg, "-C", 2)) {
+ p_context = strtoul(arg + 2, &end, 0);
+ if (*end != '\0')
+ die("unrecognized context count '%s'", arg + 2);
+ continue;
+ }
if (!strncmp(arg, "--whitespace=", 13)) {
whitespace_option = arg + 13;
parse_whitespace_option(arg + 13);
if (!strncmp(arg, "--whitespace=", 13)) {
whitespace_option = arg + 13;
parse_whitespace_option(arg + 13);