4da2614fc699ddb6d6a963c1181ac5b372272a1f
[git.git] / diff-helper.c
1 /*
2  * Copyright (C) 2005 Junio C Hamano
3  */
4 #include "cache.h"
5 #include "strbuf.h"
6 #include "diff.h"
7
8 static const char *pickaxe = NULL;
9 static int line_termination = '\n';
10 static int inter_name_termination = '\t';
11
12 static const char *diff_helper_usage =
13         "git-diff-helper [-z] [-S<string>] paths...";
14
15 int main(int ac, const char **av) {
16         struct strbuf sb;
17
18         strbuf_init(&sb);
19
20         while (1 < ac && av[1][0] == '-') {
21                 if (av[1][1] == 'z')
22                         line_termination = inter_name_termination = 0;
23                 else if (av[1][1] == 'S') {
24                         pickaxe = av[1] + 2;
25                 }
26                 else
27                         usage(diff_helper_usage);
28                 ac--; av++;
29         }
30         /* the remaining parameters are paths patterns */
31
32         diff_setup(0);
33         while (1) {
34                 unsigned old_mode, new_mode;
35                 unsigned char old_sha1[20], new_sha1[20];
36                 char old_path[PATH_MAX];
37                 int status, score, two_paths;
38                 char new_path[PATH_MAX];
39
40                 int ch;
41                 char *cp, *ep;
42
43                 read_line(&sb, stdin, line_termination);
44                 if (sb.eof)
45                         break;
46                 switch (sb.buf[0]) {
47                 case ':':
48                         /* parse the first part up to the status */
49                         cp = sb.buf + 1;
50                         old_mode = new_mode = 0;
51                         while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
52                                 old_mode = (old_mode << 3) | (ch - '0');
53                                 cp++;
54                         }
55                         if (*cp++ != ' ')
56                                 break;
57                         while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
58                                 new_mode = (new_mode << 3) | (ch - '0');
59                                 cp++;
60                         }
61                         if (*cp++ != ' ')
62                                 break;
63                         if (get_sha1_hex(cp, old_sha1))
64                                 break;
65                         cp += 40;
66                         if (*cp++ != ' ')
67                                 break;
68                         if (get_sha1_hex(cp, new_sha1))
69                                 break;
70                         cp += 40;
71                         if (*cp++ != ' ')
72                                 break;
73                         status = *cp++;
74                         if (!strchr("MCRNDU", status))
75                                 break;
76                         two_paths = score = 0;
77                         if (status == 'R' || status == 'C') {
78                                 two_paths = 1;
79                                 sscanf(cp, "%d", &score);
80                                 if (line_termination) {
81                                         cp = strchr(cp,
82                                                     inter_name_termination);
83                                         if (!cp)
84                                                 break;
85                                 }
86                         }
87
88                         if (*cp++ != inter_name_termination)
89                                 break;
90
91                         /* first pathname */
92                         if (!line_termination) {
93                                 read_line(&sb, stdin, line_termination);
94                                 if (sb.eof)
95                                         break;
96                                 strcpy(old_path, sb.buf);
97                         }
98                         else if (!two_paths)
99                                 strcpy(old_path, cp);
100                         else {
101                                 ep = strchr(cp, inter_name_termination);
102                                 if (!ep)
103                                         break;
104                                 strncpy(old_path, cp, ep-cp);
105                                 old_path[ep-cp] = 0;
106                                 cp = ep + 1;
107                         }
108
109                         /* second pathname */
110                         if (!two_paths)
111                                 strcpy(new_path, old_path);
112                         else {
113                                 if (!line_termination) {
114                                         read_line(&sb, stdin,
115                                                   line_termination);
116                                         if (sb.eof)
117                                                 break;
118                                         strcpy(new_path, sb.buf);
119                                 }
120                                 else
121                                         strcpy(new_path, cp);
122                         }
123                         diff_helper_input(old_mode, new_mode,
124                                           old_sha1, new_sha1,
125                                           old_path, status, score,
126                                           new_path);
127                         continue;
128                 }
129                 if (pickaxe)
130                         diffcore_pickaxe(pickaxe);
131                 if (1 < ac)
132                         diffcore_pathspec(av + 1);
133                 diff_flush(DIFF_FORMAT_PATCH, 0);
134                 printf("%s\n", sb.buf);
135         }
136         if (pickaxe)
137                 diffcore_pickaxe(pickaxe);
138         if (1 < ac)
139                 diffcore_pathspec(av + 1);
140         diff_flush(DIFF_FORMAT_PATCH, 0);
141         return 0;
142 }