5 static int matches_pathspec(const char *name, char **spec, int cnt)
8 int namelen = strlen(name);
9 for (i = 0; i < cnt; i++) {
10 int speclen = strlen(spec[i]);
11 if (! strncmp(spec[i], name, speclen) &&
13 (name[speclen] == 0 ||
14 name[speclen] == '/'))
20 static int parse_oneside_change(const char *cp, unsigned char *sha1,
23 while ((ch = *cp) && '0' <= ch && ch <= '7')
24 cp++; /* skip mode bits */
25 if (strncmp(cp, "\tblob\t", 6))
28 if (get_sha1_hex(cp, sha1))
37 #define STATUS_CACHED 0 /* cached and sha1 valid */
38 #define STATUS_ABSENT 1 /* diff-tree says old removed or new added */
39 #define STATUS_UNCACHED 2 /* diff-cache output: read from working tree */
41 static int parse_diff_tree_output(const char *buf,
42 unsigned char *old_sha1,
44 unsigned char *new_sha1,
49 static unsigned char null_sha[20] = { 0, };
53 *old_status = STATUS_ABSENT;
54 *new_status = (memcmp(new_sha1, null_sha, sizeof(null_sha)) ?
55 STATUS_CACHED : STATUS_UNCACHED);
56 return parse_oneside_change(cp, new_sha1, path);
58 *new_status = STATUS_ABSENT;
59 *old_status = (memcmp(old_sha1, null_sha, sizeof(null_sha)) ?
60 STATUS_CACHED : STATUS_UNCACHED);
61 return parse_oneside_change(cp, old_sha1, path);
68 /* This is for '*' entries */
69 while ((ch = *cp) && ('0' <= ch && ch <= '7'))
70 cp++; /* skip mode bits */
71 if (strncmp(cp, "->", 2))
74 while ((ch = *cp) && ('0' <= ch && ch <= '7'))
75 cp++; /* skip mode bits */
76 if (strncmp(cp, "\tblob\t", 6))
79 if (get_sha1_hex(cp, old_sha1))
82 if (strncmp(cp, "->", 2))
85 if (get_sha1_hex(cp, new_sha1))
91 *old_status = (memcmp(old_sha1, null_sha, sizeof(null_sha)) ?
92 STATUS_CACHED : STATUS_UNCACHED);
93 *new_status = (memcmp(new_sha1, null_sha, sizeof(null_sha)) ?
94 STATUS_CACHED : STATUS_UNCACHED);
98 static int sha1err(const char *path, const unsigned char *sha1)
100 return error("diff-tree-helper: unable to read sha1 file of %s (%s)",
101 path, sha1_to_hex(sha1));
104 static int fserr(const char *path)
106 return error("diff-tree-helper: unable to read file %s", path);
109 static char *map_whole_file(const char *path, unsigned long *size) {
114 if ((fd = open(path, O_RDONLY)) < 0) {
115 error("diff-tree-helper: unable to read file %s", path);
118 if (fstat(fd, &st) < 0) {
120 error("diff-tree-helper: unable to stat file %s", path);
124 buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
129 static int show_diff(const unsigned char *old_sha1, int old_status,
130 const unsigned char *new_sha1, int new_status,
131 const char *path, int reverse_diff)
133 char other[PATH_MAX];
144 switch (old_status) {
146 blob = read_sha1_file(old_sha1, type, &size);
148 return sha1err(path, old_sha1);
150 switch (new_status) {
152 strcpy(other, ".diff_tree_helper_XXXXXX");
155 die("unable to create temp-file");
156 if (write(fd, blob, size) != size)
157 die("unable to write temp-file");
161 blob = read_sha1_file(new_sha1, type, &size);
163 return sha1err(path, new_sha1);
166 /* new = blob, old = fs */
167 reverse = !reverse_diff;
172 case STATUS_UNCACHED:
173 fs = ((new_status == STATUS_ABSENT) ?
175 reverse = reverse_diff;
179 reverse = reverse_diff;
184 switch (new_status) {
186 blob = read_sha1_file(new_sha1, type, &size);
188 return sha1err(path, new_sha1);
189 /* old = fs, new = blob */
191 reverse = !reverse_diff;
195 return error("diff-tree-helper: absent from both old and new?");
196 case STATUS_UNCACHED:
200 /* old = blob, new = fs */
201 reverse = reverse_diff;
204 reverse = reverse_diff;
208 case STATUS_UNCACHED:
209 fs = path; /* old = fs, new = blob */
210 reverse = !reverse_diff;
212 switch (new_status) {
214 blob = read_sha1_file(new_sha1, type, &size);
216 return sha1err(path, new_sha1);
224 case STATUS_UNCACHED:
226 blob = map_whole_file(path, &size);
232 reverse = reverse_diff;
237 reverse = reverse_diff;
245 reverse /* 0: diff blob fs
250 if (need_unmap && blob)
257 static const char *diff_tree_helper_usage =
258 "diff-tree-helper [-R] [-z] paths...";
260 int main(int ac, char **av) {
262 int reverse_diff = 0;
263 int line_termination = '\n';
267 while (1 < ac && av[1][0] == '-') {
270 else if (av[1][1] == 'z')
271 line_termination = 0;
273 usage(diff_tree_helper_usage);
276 /* the remaining parameters are paths patterns */
281 int old_status, new_status;
282 unsigned char old_sha1[20], new_sha1[20];
284 read_line(&sb, stdin, line_termination);
287 if (parse_diff_tree_output(sb.buf,
288 old_sha1, &old_status,
289 new_sha1, &new_status,
291 fprintf(stderr, "cannot parse %s\n", sb.buf);
294 if (1 < ac && ! matches_pathspec(path, av+1, ac-1))
297 show_diff(old_sha1, old_status,
298 new_sha1, new_status,