Allow removal of "path" when "path/file" exists.
[alt-git.git] / diff-tree-helper.c
blob51bb658be4f73c00016b4ecb82f09d30941998a4
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"
9 static int matches_pathspec(const char *name, const char **spec, int cnt)
11 int i;
12 int namelen = strlen(name);
13 for (i = 0; i < cnt; i++) {
14 int speclen = strlen(spec[i]);
15 if (! strncmp(spec[i], name, speclen) &&
16 speclen <= namelen &&
17 (name[speclen] == 0 ||
18 name[speclen] == '/'))
19 return 1;
21 return 0;
24 static int parse_oneside_change(const char *cp, struct diff_spec *one,
25 char *path)
27 int ch;
29 one->file_valid = one->sha1_valid = 1;
30 one->mode = 0;
31 while ((ch = *cp) && '0' <= ch && ch <= '7') {
32 one->mode = (one->mode << 3) | (ch - '0');
33 cp++;
36 if (strncmp(cp, "\tblob\t", 6))
37 return -1;
38 cp += 6;
39 if (get_sha1_hex(cp, one->blob_sha1))
40 return -1;
41 cp += 40;
42 if (*cp++ != '\t')
43 return -1;
44 strcpy(path, cp);
45 return 0;
48 static int parse_diff_tree_output(const char *buf,
49 const char **spec, int cnt, int reverse)
51 struct diff_spec old, new;
52 char path[PATH_MAX];
53 const char *cp = buf;
54 int ch;
56 switch (*cp++) {
57 case 'U':
58 if (!cnt || matches_pathspec(cp + 1, spec, cnt))
59 diff_unmerge(cp + 1);
60 return 0;
61 case '+':
62 old.file_valid = 0;
63 parse_oneside_change(cp, &new, path);
64 break;
65 case '-':
66 new.file_valid = 0;
67 parse_oneside_change(cp, &old, path);
68 break;
69 case '*':
70 old.file_valid = old.sha1_valid =
71 new.file_valid = new.sha1_valid = 1;
72 old.mode = new.mode = 0;
73 while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
74 old.mode = (old.mode << 3) | (ch - '0');
75 cp++;
77 if (strncmp(cp, "->", 2))
78 return -1;
79 cp += 2;
80 while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
81 new.mode = (new.mode << 3) | (ch - '0');
82 cp++;
84 if (strncmp(cp, "\tblob\t", 6))
85 return -1;
86 cp += 6;
87 if (get_sha1_hex(cp, old.blob_sha1))
88 return -1;
89 cp += 40;
90 if (strncmp(cp, "->", 2))
91 return -1;
92 cp += 2;
93 if (get_sha1_hex(cp, new.blob_sha1))
94 return -1;
95 cp += 40;
96 if (*cp++ != '\t')
97 return -1;
98 strcpy(path, cp);
99 break;
100 default:
101 return -1;
103 if (!cnt || matches_pathspec(path, spec, cnt)) {
104 if (reverse)
105 run_external_diff(path, &new, &old);
106 else
107 run_external_diff(path, &old, &new);
109 return 0;
112 static const char *diff_tree_helper_usage =
113 "diff-tree-helper [-R] [-z] paths...";
115 int main(int ac, const char **av) {
116 struct strbuf sb;
117 int reverse = 0;
118 int line_termination = '\n';
120 strbuf_init(&sb);
122 while (1 < ac && av[1][0] == '-') {
123 if (av[1][1] == 'R')
124 reverse = 1;
125 else if (av[1][1] == 'z')
126 line_termination = 0;
127 else
128 usage(diff_tree_helper_usage);
129 ac--; av++;
131 /* the remaining parameters are paths patterns */
133 while (1) {
134 int status;
135 read_line(&sb, stdin, line_termination);
136 if (sb.eof)
137 break;
138 status = parse_diff_tree_output(sb.buf, av+1, ac-1, reverse);
139 if (status)
140 fprintf(stderr, "cannot parse %s\n", sb.buf);
142 return 0;