apply: split quoted filename handling into new function

The new find_name_gnu() function handles new-style '--- "a/foo"'
patch header lines, leaving find_name() itself a bit less
daunting.

Functional change: do not clobber the p-value when there are not
enough path components in a quoted file name to honor it.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jonathan Nieder 2010-08-18 20:46:46 -05:00 committed by Junio C Hamano
parent 64fdc08dac
commit bb7306b5a3
2 changed files with 70 additions and 33 deletions

View File

@ -416,31 +416,29 @@ static char *squash_slash(char *name)
return name; return name;
} }
static char *find_name(const char *line, char *def, int p_value, int terminate) static char *find_name_gnu(const char *line, char *def, int p_value)
{ {
int len;
const char *start = NULL;
if (p_value == 0)
start = line;
if (*line == '"') {
struct strbuf name = STRBUF_INIT; struct strbuf name = STRBUF_INIT;
char *cp;
/* /*
* Proposed "new-style" GNU patch/diff format; see * Proposed "new-style" GNU patch/diff format; see
* http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2 * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
*/ */
if (!unquote_c_style(&name, line, NULL)) { if (unquote_c_style(&name, line, NULL)) {
char *cp; strbuf_release(&name);
return NULL;
}
for (cp = name.buf; p_value; p_value--) { for (cp = name.buf; p_value; p_value--) {
cp = strchr(cp, '/'); cp = strchr(cp, '/');
if (!cp) if (!cp) {
break; strbuf_release(&name);
return NULL;
}
cp++; cp++;
} }
if (cp) {
/* name can later be freed, so we need /* name can later be freed, so we need
* to memmove, not just return cp * to memmove, not just return cp
*/ */
@ -449,11 +447,21 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
if (root) if (root)
strbuf_insert(&name, 0, root, root_len); strbuf_insert(&name, 0, root, root_len);
return squash_slash(strbuf_detach(&name, NULL)); return squash_slash(strbuf_detach(&name, NULL));
} }
}
strbuf_release(&name); static char *find_name(const char *line, char *def, int p_value, int terminate)
{
int len;
const char *start = NULL;
if (*line == '"') {
char *name = find_name_gnu(line, def, p_value);
if (name)
return name;
} }
if (p_value == 0)
start = line;
for (;;) { for (;;) {
char c = *line; char c = *line;

View File

@ -10,21 +10,50 @@ test_description='git apply -p handling.'
test_expect_success setup ' test_expect_success setup '
mkdir sub && mkdir sub &&
echo A >sub/file1 && echo A >sub/file1 &&
cp sub/file1 file1 && cp sub/file1 file1.saved &&
git add sub/file1 && git add sub/file1 &&
echo B >sub/file1 && echo B >sub/file1 &&
git diff >patch.file && git diff >patch.file &&
rm sub/file1 && git checkout -- sub/file1 &&
rmdir sub git mv sub süb &&
echo B >süb/file1 &&
git diff >patch.escaped &&
grep "[\]" patch.escaped &&
rm süb/file1 &&
rmdir süb
' '
test_expect_success 'apply git diff with -p2' ' test_expect_success 'apply git diff with -p2' '
cp file1.saved file1 &&
git apply -p2 patch.file git apply -p2 patch.file
' '
test_expect_success 'apply with too large -p' ' test_expect_success 'apply with too large -p' '
cp file1.saved file1 &&
test_must_fail git apply --stat -p3 patch.file 2>err && test_must_fail git apply --stat -p3 patch.file 2>err &&
grep "removing 3 leading" err grep "removing 3 leading" err
' '
test_expect_success 'apply (-p2) traditional diff with funny filenames' '
cat >patch.quotes <<-\EOF &&
diff -u "a/"sub/file1 "b/"sub/file1
--- "a/"sub/file1
+++ "b/"sub/file1
@@ -1 +1 @@
-A
+B
EOF
echo B >expected &&
cp file1.saved file1 &&
git apply -p2 patch.quotes &&
test_cmp expected file1
'
test_expect_success 'apply with too large -p and fancy filename' '
cp file1.saved file1 &&
test_must_fail git apply --stat -p3 patch.escaped 2>err &&
grep "removing 3 leading" err
'
test_done test_done