]>
Commit | Line | Data |
---|---|---|
c2e86add | 1 | #include "builtin.h" |
f9767222 | 2 | |
30e12b92 | 3 | static void flush_current_id(int patchlen, unsigned char *id, unsigned char *result) |
f9767222 | 4 | { |
f9767222 LT |
5 | char name[50]; |
6 | ||
7 | if (!patchlen) | |
8 | return; | |
9 | ||
f9767222 LT |
10 | memcpy(name, sha1_to_hex(id), 41); |
11 | printf("%s %s\n", sha1_to_hex(result), name); | |
f9767222 LT |
12 | } |
13 | ||
14 | static int remove_space(char *line) | |
15 | { | |
16 | char *src = line; | |
17 | char *dst = line; | |
18 | unsigned char c; | |
19 | ||
20 | while ((c = *src++) != '\0') { | |
21 | if (!isspace(c)) | |
22 | *dst++ = c; | |
23 | } | |
24 | return dst - line; | |
25 | } | |
26 | ||
580fb25b PB |
27 | static int scan_hunk_header(const char *p, int *p_before, int *p_after) |
28 | { | |
29 | static const char digits[] = "0123456789"; | |
30 | const char *q, *r; | |
31 | int n; | |
32 | ||
33 | q = p + 4; | |
34 | n = strspn(q, digits); | |
35 | if (q[n] == ',') { | |
36 | q += n + 1; | |
37 | n = strspn(q, digits); | |
38 | } | |
39 | if (n == 0 || q[n] != ' ' || q[n+1] != '+') | |
40 | return 0; | |
41 | ||
42 | r = q + n + 2; | |
43 | n = strspn(r, digits); | |
44 | if (r[n] == ',') { | |
45 | r += n + 1; | |
46 | n = strspn(r, digits); | |
47 | } | |
48 | if (n == 0) | |
49 | return 0; | |
50 | ||
51 | *p_before = atoi(q); | |
52 | *p_after = atoi(r); | |
53 | return 1; | |
54 | } | |
55 | ||
30e12b92 MT |
56 | static void flush_one_hunk(unsigned char *result, git_SHA_CTX *ctx) |
57 | { | |
58 | unsigned char hash[20]; | |
59 | unsigned short carry = 0; | |
60 | int i; | |
61 | ||
62 | git_SHA1_Final(hash, ctx); | |
63 | git_SHA1_Init(ctx); | |
64 | /* 20-byte sum, with carry */ | |
65 | for (i = 0; i < 20; ++i) { | |
66 | carry += result[i] + hash[i]; | |
67 | result[i] = carry; | |
68 | carry >>= 8; | |
69 | } | |
70 | } | |
71 | ||
72 | static int get_one_patchid(unsigned char *next_sha1, unsigned char *result, | |
73 | struct strbuf *line_buf, int stable) | |
f9767222 | 74 | { |
9ae144fb | 75 | int patchlen = 0, found_next = 0; |
580fb25b | 76 | int before = -1, after = -1; |
30e12b92 MT |
77 | git_SHA_CTX ctx; |
78 | ||
79 | git_SHA1_Init(&ctx); | |
80 | hashclr(result); | |
f9767222 | 81 | |
b9ab810b MS |
82 | while (strbuf_getwholeline(line_buf, stdin, '\n') != EOF) { |
83 | char *line = line_buf->buf; | |
f9767222 LT |
84 | char *p = line; |
85 | int len; | |
86 | ||
87 | if (!memcmp(line, "diff-tree ", 10)) | |
88 | p += 10; | |
8d3cbd27 JS |
89 | else if (!memcmp(line, "commit ", 7)) |
90 | p += 7; | |
580fb25b PB |
91 | else if (!memcmp(line, "From ", 5)) |
92 | p += 5; | |
2485eab5 MG |
93 | else if (!memcmp(line, "\\ ", 2) && 12 < strlen(line)) |
94 | continue; | |
f9767222 | 95 | |
9ae144fb PB |
96 | if (!get_sha1_hex(p, next_sha1)) { |
97 | found_next = 1; | |
98 | break; | |
f9767222 LT |
99 | } |
100 | ||
101 | /* Ignore commit comments */ | |
102 | if (!patchlen && memcmp(line, "diff ", 5)) | |
103 | continue; | |
104 | ||
580fb25b PB |
105 | /* Parsing diff header? */ |
106 | if (before == -1) { | |
107 | if (!memcmp(line, "index ", 6)) | |
108 | continue; | |
109 | else if (!memcmp(line, "--- ", 4)) | |
110 | before = after = 1; | |
111 | else if (!isalpha(line[0])) | |
112 | break; | |
113 | } | |
9fabdedc | 114 | |
580fb25b PB |
115 | /* Looking for a valid hunk header? */ |
116 | if (before == 0 && after == 0) { | |
117 | if (!memcmp(line, "@@ -", 4)) { | |
118 | /* Parse next hunk, but ignore line numbers. */ | |
119 | scan_hunk_header(line, &before, &after); | |
120 | continue; | |
121 | } | |
122 | ||
123 | /* Split at the end of the patch. */ | |
124 | if (memcmp(line, "diff ", 5)) | |
125 | break; | |
126 | ||
127 | /* Else we're parsing another header. */ | |
30e12b92 MT |
128 | if (stable) |
129 | flush_one_hunk(result, &ctx); | |
580fb25b PB |
130 | before = after = -1; |
131 | } | |
132 | ||
133 | /* If we get here, we're inside a hunk. */ | |
134 | if (line[0] == '-' || line[0] == ' ') | |
135 | before--; | |
136 | if (line[0] == '+' || line[0] == ' ') | |
137 | after--; | |
f9767222 LT |
138 | |
139 | /* Compute the sha without whitespace */ | |
140 | len = remove_space(line); | |
141 | patchlen += len; | |
30e12b92 | 142 | git_SHA1_Update(&ctx, line, len); |
9ae144fb PB |
143 | } |
144 | ||
145 | if (!found_next) | |
146 | hashclr(next_sha1); | |
147 | ||
30e12b92 MT |
148 | flush_one_hunk(result, &ctx); |
149 | ||
9ae144fb PB |
150 | return patchlen; |
151 | } | |
152 | ||
30e12b92 | 153 | static void generate_id_list(int stable) |
9ae144fb | 154 | { |
30e12b92 | 155 | unsigned char sha1[20], n[20], result[20]; |
9ae144fb | 156 | int patchlen; |
b9ab810b | 157 | struct strbuf line_buf = STRBUF_INIT; |
9ae144fb | 158 | |
9ae144fb PB |
159 | hashclr(sha1); |
160 | while (!feof(stdin)) { | |
30e12b92 MT |
161 | patchlen = get_one_patchid(n, result, &line_buf, stable); |
162 | flush_current_id(patchlen, sha1, result); | |
9ae144fb | 163 | hashcpy(sha1, n); |
f9767222 | 164 | } |
b9ab810b | 165 | strbuf_release(&line_buf); |
f9767222 LT |
166 | } |
167 | ||
30e12b92 MT |
168 | static const char patch_id_usage[] = "git patch-id [--stable | --unstable] < patch"; |
169 | ||
170 | static int git_patch_id_config(const char *var, const char *value, void *cb) | |
171 | { | |
172 | int *stable = cb; | |
173 | ||
174 | if (!strcmp(var, "patchid.stable")) { | |
175 | *stable = git_config_bool(var, value); | |
176 | return 0; | |
177 | } | |
178 | ||
179 | return git_default_config(var, value, cb); | |
180 | } | |
f9767222 | 181 | |
dedc0ec5 | 182 | int cmd_patch_id(int argc, const char **argv, const char *prefix) |
f9767222 | 183 | { |
30e12b92 MT |
184 | int stable = -1; |
185 | ||
186 | git_config(git_patch_id_config, &stable); | |
187 | ||
188 | /* If nothing is set, default to unstable. */ | |
189 | if (stable < 0) | |
190 | stable = 0; | |
191 | ||
192 | if (argc == 2 && !strcmp(argv[1], "--stable")) | |
193 | stable = 1; | |
194 | else if (argc == 2 && !strcmp(argv[1], "--unstable")) | |
195 | stable = 0; | |
196 | else if (argc != 1) | |
f9767222 LT |
197 | usage(patch_id_usage); |
198 | ||
30e12b92 | 199 | generate_id_list(stable); |
f9767222 | 200 | return 0; |
a6080a0a | 201 | } |