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>
Jonathan Nieder committed
Aug 18, 2010 at 20:46 UTC
bb7306b5a350fd2143347be3d9b7d8588567d715
2 files changed
+70
-33
builtin/apply.c
+38
-30
@@ -416,44 +416,52 @@ static char *squash_slash(char *name)
416
return name;
417
}
418
419
+static char *find_name_gnu(const char *line, char *def, int p_value)
420
+{
421
+ struct strbuf name = STRBUF_INIT;
422
+ char *cp;
423
+
424
+ /*
425
+ * Proposed "new-style" GNU patch/diff format; see
426
+ * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
427
+ */
428
+ if (unquote_c_style(&name, line, NULL)) {
429
+ strbuf_release(&name);
430
+ return NULL;
431
+ }
432
+
433
+ for (cp = name.buf; p_value; p_value--) {
434
+ cp = strchr(cp, '/');
435
+ if (!cp) {
436
+ strbuf_release(&name);
437
+ return NULL;
438
+ }
439
+ cp++;
440
+ }
441
+
442
+ /* name can later be freed, so we need
443
+ * to memmove, not just return cp
444
+ */
445
+ strbuf_remove(&name, 0, cp - name.buf);
446
+ free(def);
447
+ if (root)
448
+ strbuf_insert(&name, 0, root, root_len);
449
+ return squash_slash(strbuf_detach(&name, NULL));
450
+}
451
+
452
static char *find_name(const char *line, char *def, int p_value, int terminate)
453
{
454
int len;
455
const char *start = NULL;
456
424
- if (p_value == 0)
425
- start = line;
426
-
457
if (*line == '"') {
428
- struct strbuf name = STRBUF_INIT;
429
-
430
- /*
431
- * Proposed "new-style" GNU patch/diff format; see
432
- * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
433
- */
434
- if (!unquote_c_style(&name, line, NULL)) {
435
- char *cp;
436
-
437
- for (cp = name.buf; p_value; p_value--) {
438
- cp = strchr(cp, '/');
439
- if (!cp)
440
- break;
441
- cp++;
442
- }
443
- if (cp) {
444
- /* name can later be freed, so we need
445
- * to memmove, not just return cp
446
- */
447
- strbuf_remove(&name, 0, cp - name.buf);
448
- free(def);
449
- if (root)
450
- strbuf_insert(&name, 0, root, root_len);
451
- return squash_slash(strbuf_detach(&name, NULL));
452
- }
453
- }
454
- strbuf_release(&name);
458
+ char *name = find_name_gnu(line, def, p_value);
459
+ if (name)
460
+ return name;
461
}
462
463
+ if (p_value == 0)
464
+ start = line;
465
for (;;) {
466
char c = *line;
467
t/t4120-apply-popt.sh
+32
-3
@@ -10,21 +10,50 @@ test_description='git apply -p handling.'
10
test_expect_success setup '
11
mkdir sub &&
12
echo A >sub/file1 &&
13
- cp sub/file1 file1 &&
13
+ cp sub/file1 file1.saved &&
14
git add sub/file1 &&
15
echo B >sub/file1 &&
16
git diff >patch.file &&
17
- rm sub/file1 &&
18
- rmdir sub
17
+ git checkout -- sub/file1 &&
18
+ git mv sub süb &&
19
+ echo B >süb/file1 &&
20
+ git diff >patch.escaped &&
21
+ grep "[\]" patch.escaped &&
22
+ rm süb/file1 &&
23
+ rmdir süb
24
'
25
26
test_expect_success 'apply git diff with -p2' '
27
+ cp file1.saved file1 &&
28
git apply -p2 patch.file
29
'
30
31
test_expect_success 'apply with too large -p' '
32
+ cp file1.saved file1 &&
33
test_must_fail git apply --stat -p3 patch.file 2>err &&
34
grep "removing 3 leading" err
35
'
36
37
+test_expect_success 'apply (-p2) traditional diff with funny filenames' '
38
+ cat >patch.quotes <<-\EOF &&
39
+ diff -u "a/"sub/file1 "b/"sub/file1
40
+ --- "a/"sub/file1
41
+ +++ "b/"sub/file1
42
+ @@ -1 +1 @@
43
+ -A
44
+ +B
45
+ EOF
46
+ echo B >expected &&
47
+
48
+ cp file1.saved file1 &&
49
+ git apply -p2 patch.quotes &&
50
+ test_cmp expected file1
51
+'
52
+
53
+test_expect_success 'apply with too large -p and fancy filename' '
54
+ cp file1.saved file1 &&
55
+ test_must_fail git apply --stat -p3 patch.escaped 2>err &&
56
+ grep "removing 3 leading" err
57
+'
58
+
59
test_done