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

View file

@ -10,21 +10,50 @@ test_description='git apply -p handling.'
test_expect_success setup '
mkdir sub &&
echo A >sub/file1 &&
cp sub/file1 file1 &&
cp sub/file1 file1.saved &&
git add sub/file1 &&
echo B >sub/file1 &&
git diff >patch.file &&
rm sub/file1 &&
rmdir sub
git checkout -- sub/file1 &&
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' '
cp file1.saved file1 &&
git apply -p2 patch.file
'
test_expect_success 'apply with too large -p' '
cp file1.saved file1 &&
test_must_fail git apply --stat -p3 patch.file 2>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