]> git.ipfire.org Git - thirdparty/git.git/blob - diff-helper.c
[PATCH] Diff overhaul, adding half of copy detection.
[thirdparty/git.git] / diff-helper.c
1 /*
2 * Copyright (C) 2005 Junio C Hamano
3 */
4 #include <limits.h>
5 #include "cache.h"
6 #include "strbuf.h"
7 #include "diff.h"
8
9 static int detect_rename = 0;
10 static int diff_score_opt = 0;
11 static int generate_patch = 1;
12
13 static int parse_oneside_change(const char *cp, int *mode,
14 unsigned char *sha1, char *path)
15 {
16 int ch, m;
17
18 m = 0;
19 while ((ch = *cp) && '0' <= ch && ch <= '7') {
20 m = (m << 3) | (ch - '0');
21 cp++;
22 }
23 *mode = m;
24 if (strncmp(cp, "\tblob\t", 6) && strncmp(cp, " blob ", 6) &&
25 strncmp(cp, "\ttree\t", 6) && strncmp(cp, " tree ", 6))
26 return -1;
27 cp += 6;
28 if (get_sha1_hex(cp, sha1))
29 return -1;
30 cp += 40;
31 if ((*cp != '\t') && *cp != ' ')
32 return -1;
33 strcpy(path, ++cp);
34 return 0;
35 }
36
37 static int parse_diff_raw_output(const char *buf)
38 {
39 char path[PATH_MAX];
40 unsigned char old_sha1[20], new_sha1[20];
41 const char *cp = buf;
42 int ch, old_mode, new_mode;
43
44 switch (*cp++) {
45 case 'U':
46 diff_unmerge(cp + 1);
47 break;
48 case '+':
49 if (parse_oneside_change(cp, &new_mode, new_sha1, path))
50 return -1;
51 diff_addremove('+', new_mode, new_sha1, path, NULL);
52 break;
53 case '-':
54 if (parse_oneside_change(cp, &old_mode, old_sha1, path))
55 return -1;
56 diff_addremove('-', old_mode, old_sha1, path, NULL);
57 break;
58 case '*':
59 old_mode = new_mode = 0;
60 while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
61 old_mode = (old_mode << 3) | (ch - '0');
62 cp++;
63 }
64 if (strncmp(cp, "->", 2))
65 return -1;
66 cp += 2;
67 while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
68 new_mode = (new_mode << 3) | (ch - '0');
69 cp++;
70 }
71 if (strncmp(cp, "\tblob\t", 6) && strncmp(cp, " blob ", 6) &&
72 strncmp(cp, "\ttree\t", 6) && strncmp(cp, " tree ", 6))
73 return -1;
74 cp += 6;
75 if (get_sha1_hex(cp, old_sha1))
76 return -1;
77 cp += 40;
78 if (strncmp(cp, "->", 2))
79 return -1;
80 cp += 2;
81 if (get_sha1_hex(cp, new_sha1))
82 return -1;
83 cp += 40;
84 if ((*cp != '\t') && *cp != ' ')
85 return -1;
86 strcpy(path, ++cp);
87 diff_change(old_mode, new_mode, old_sha1, new_sha1, path, NULL);
88 break;
89 default:
90 return -1;
91 }
92 return 0;
93 }
94
95 static const char *diff_helper_usage =
96 "git-diff-helper [-z] [-R] [-M] [-C] paths...";
97
98 int main(int ac, const char **av) {
99 struct strbuf sb;
100 int reverse = 0;
101 int line_termination = '\n';
102
103 strbuf_init(&sb);
104
105 while (1 < ac && av[1][0] == '-') {
106 if (av[1][1] == 'R')
107 reverse = 1;
108 else if (av[1][1] == 'z')
109 line_termination = 0;
110 else if (av[1][1] == 'p') /* hidden from the help */
111 generate_patch = 0;
112 else if (av[1][1] == 'M') {
113 detect_rename = 1;
114 diff_score_opt = diff_scoreopt_parse(av[1]);
115 }
116 else if (av[1][1] == 'C') {
117 detect_rename = 2;
118 diff_score_opt = diff_scoreopt_parse(av[1]);
119 }
120 else
121 usage(diff_helper_usage);
122 ac--; av++;
123 }
124 /* the remaining parameters are paths patterns */
125
126 diff_setup(detect_rename, diff_score_opt, reverse,
127 (generate_patch ? -1 : line_termination),
128 av+1, ac-1);
129
130 while (1) {
131 int status;
132 read_line(&sb, stdin, line_termination);
133 if (sb.eof)
134 break;
135 status = parse_diff_raw_output(sb.buf);
136 if (status) {
137 diff_flush();
138 printf("%s%c", sb.buf, line_termination);
139 }
140 }
141
142 diff_flush();
143 return 0;
144 }