[PATCH] diff-cache/tree compatible output for show-diff (take 2).
[git.git] / show-diff.c
1 /*
2  * GIT - The information manager from hell
3  *
4  * Copyright (C) Linus Torvalds, 2005
5  */
6 #include "cache.h"
7
8 static const char *show_diff_usage = "show-diff [-q] [-s] [-z] [paths...]";
9
10 static int recursive = 0;
11 static int line_termination = '\n';
12 static int silent = 0;
13 static int silent_on_nonexisting_files = 0;
14
15 static int matches_pathspec(struct cache_entry *ce, char **spec, int cnt)
16 {
17         int i;
18         int namelen = ce_namelen(ce);
19         for (i = 0; i < cnt; i++) {
20                 int speclen = strlen(spec[i]);
21                 if (! strncmp(spec[i], ce->name, speclen) &&
22                     speclen <= namelen &&
23                     (ce->name[speclen] == 0 ||
24                      ce->name[speclen] == '/'))
25                         return 1;
26         }
27         return 0;
28 }
29
30 static void show_file(const char *prefix, struct cache_entry *ce)
31 {
32         printf("%s%o\t%s\t%s\t%s%c", prefix, ntohl(ce->ce_mode), "blob",
33                 sha1_to_hex(ce->sha1), ce->name, line_termination);
34 }
35
36 int main(int argc, char **argv)
37 {
38         static const char null_sha1_hex[] = "0000000000000000000000000000000000000000";
39         int entries = read_cache();
40         int i;
41
42         while (1 < argc && argv[1][0] == '-') {
43                 if (!strcmp(argv[1], "-s"))
44                         silent_on_nonexisting_files = silent = 1;
45                 else if (!strcmp(argv[1], "-q"))
46                         silent_on_nonexisting_files = 1;
47                 else if (!strcmp(argv[1], "-z"))
48                         line_termination = 0;
49                 else if (!strcmp(argv[1], "-r"))
50                         recursive = 1;          /* No-op */
51                 else
52                         usage(show_diff_usage);
53                 argv++; argc--;
54         }
55
56         /* At this point, if argc == 1, then we are doing everything.
57          * Otherwise argv[1] .. argv[argc-1] have the explicit paths.
58          */
59         if (entries < 0) {
60                 perror("read_cache");
61                 exit(1);
62         }
63
64         for (i = 0; i < entries; i++) {
65                 struct stat st;
66                 unsigned int oldmode, mode;
67                 struct cache_entry *ce = active_cache[i];
68                 int changed;
69
70                 if (1 < argc &&
71                     ! matches_pathspec(ce, argv+1, argc-1))
72                         continue;
73
74                 if (ce_stage(ce)) {
75                         printf("U %s%c", ce->name, line_termination);
76
77                         while (i < entries &&
78                                !strcmp(ce->name, active_cache[i]->name))
79                                 i++;
80                         i--; /* compensate for loop control increments */
81                         continue;
82                 }
83  
84                 if (stat(ce->name, &st) < 0) {
85                         if (errno != ENOENT) {
86                                 perror(ce->name);
87                                 continue;
88                         }       
89                         if (silent_on_nonexisting_files)
90                                 continue;
91                         show_file("-", ce);
92                         continue;
93                 }
94                 changed = cache_match_stat(ce, &st);
95                 if (!changed)
96                         continue;
97
98                 oldmode = ntohl(ce->ce_mode);
99                 mode = S_IFREG | ce_permissions(st.st_mode);
100
101                 printf("*%o->%o\t%s\t%s->%s\t%s%c",
102                         oldmode, mode, "blob",
103                         sha1_to_hex(ce->sha1), null_sha1_hex,
104                         ce->name, line_termination);
105         }
106         return 0;
107 }