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
,