Libify diff-files.
[git.git] / diff-lib.c
1 /*
2  * Copyright (C) 2005 Junio C Hamano
3  */
4 #include "cache.h"
5 #include "quote.h"
6 #include "commit.h"
7 #include "diff.h"
8 #include "diffcore.h"
9 #include "revision.h"
10
11 /*
12  * diff-files
13  */
14
15 int run_diff_files(struct rev_info *revs, int silent_on_removed)
16 {
17         int entries, i;
18         int diff_unmerged_stage = revs->max_count;
19
20         if (diff_unmerged_stage < 0)
21                 diff_unmerged_stage = 2;
22         entries = read_cache();
23         if (entries < 0) {
24                 perror("read_cache");
25                 return -1;
26         }
27         for (i = 0; i < entries; i++) {
28                 struct stat st;
29                 unsigned int oldmode, newmode;
30                 struct cache_entry *ce = active_cache[i];
31                 int changed;
32
33                 if (!ce_path_match(ce, revs->prune_data))
34                         continue;
35
36                 if (ce_stage(ce)) {
37                         struct {
38                                 struct combine_diff_path p;
39                                 struct combine_diff_parent filler[5];
40                         } combine;
41                         int num_compare_stages = 0;
42
43                         combine.p.next = NULL;
44                         combine.p.len = ce_namelen(ce);
45                         combine.p.path = xmalloc(combine.p.len + 1);
46                         memcpy(combine.p.path, ce->name, combine.p.len);
47                         combine.p.path[combine.p.len] = 0;
48                         combine.p.mode = 0;
49                         memset(combine.p.sha1, 0, 20);
50                         memset(&combine.p.parent[0], 0,
51                                sizeof(combine.filler));
52
53                         while (i < entries) {
54                                 struct cache_entry *nce = active_cache[i];
55                                 int stage;
56
57                                 if (strcmp(ce->name, nce->name))
58                                         break;
59
60                                 /* Stage #2 (ours) is the first parent,
61                                  * stage #3 (theirs) is the second.
62                                  */
63                                 stage = ce_stage(nce);
64                                 if (2 <= stage) {
65                                         int mode = ntohl(nce->ce_mode);
66                                         num_compare_stages++;
67                                         memcpy(combine.p.parent[stage-2].sha1,
68                                                nce->sha1, 20);
69                                         combine.p.parent[stage-2].mode =
70                                                 canon_mode(mode);
71                                         combine.p.parent[stage-2].status =
72                                                 DIFF_STATUS_MODIFIED;
73                                 }
74
75                                 /* diff against the proper unmerged stage */
76                                 if (stage == diff_unmerged_stage)
77                                         ce = nce;
78                                 i++;
79                         }
80                         /*
81                          * Compensate for loop update
82                          */
83                         i--;
84
85                         if (revs->combine_merges && num_compare_stages == 2) {
86                                 show_combined_diff(&combine.p, 2,
87                                                    revs->dense_combined_merges,
88                                                    revs);
89                                 free(combine.p.path);
90                                 continue;
91                         }
92                         free(combine.p.path);
93
94                         /*
95                          * Show the diff for the 'ce' if we found the one
96                          * from the desired stage.
97                          */
98                         diff_unmerge(&revs->diffopt, ce->name);
99                         if (ce_stage(ce) != diff_unmerged_stage)
100                                 continue;
101                 }
102
103                 if (lstat(ce->name, &st) < 0) {
104                         if (errno != ENOENT && errno != ENOTDIR) {
105                                 perror(ce->name);
106                                 continue;
107                         }
108                         if (silent_on_removed)
109                                 continue;
110                         diff_addremove(&revs->diffopt, '-', ntohl(ce->ce_mode),
111                                        ce->sha1, ce->name, NULL);
112                         continue;
113                 }
114                 changed = ce_match_stat(ce, &st, 0);
115                 if (!changed && !revs->diffopt.find_copies_harder)
116                         continue;
117                 oldmode = ntohl(ce->ce_mode);
118
119                 newmode = canon_mode(st.st_mode);
120                 if (!trust_executable_bit &&
121                     S_ISREG(newmode) && S_ISREG(oldmode) &&
122                     ((newmode ^ oldmode) == 0111))
123                         newmode = oldmode;
124                 diff_change(&revs->diffopt, oldmode, newmode,
125                             ce->sha1, (changed ? null_sha1 : ce->sha1),
126                             ce->name, NULL);
127
128         }
129         diffcore_std(&revs->diffopt);
130         diff_flush(&revs->diffopt);
131         return 0;
132 }
133