]>
Commit | Line | Data |
---|---|---|
178cb243 LT |
1 | /* |
2 | * rev-parse.c | |
3 | * | |
4 | * Copyright (C) Linus Torvalds, 2005 | |
5 | */ | |
6 | #include "cache.h" | |
a8be83fe | 7 | #include "commit.h" |
960bba0d | 8 | #include "refs.h" |
a8be83fe | 9 | |
023d66ed LT |
10 | static char *def = NULL; |
11 | static int no_revs = 0; | |
12 | static int single_rev = 0; | |
13 | static int revs_only = 0; | |
14 | static int do_rev_argument = 1; | |
15 | static int output_revs = 0; | |
f79b65aa LT |
16 | static int flags_only = 0; |
17 | static int no_flags = 0; | |
023d66ed | 18 | |
042a4ed7 LT |
19 | #define NORMAL 0 |
20 | #define REVERSED 1 | |
21 | static int show_type = NORMAL; | |
22 | ||
a8be83fe | 23 | static int get_extended_sha1(char *name, unsigned char *sha1); |
178cb243 | 24 | |
921d865e LT |
25 | /* |
26 | * Some arguments are relevant "revision" arguments, | |
27 | * others are about output format or other details. | |
28 | * This sorts it all out. | |
29 | */ | |
30 | static int is_rev_argument(const char *arg) | |
31 | { | |
32 | static const char *rev_args[] = { | |
33 | "--max-count=", | |
34 | "--max-age=", | |
35 | "--min-age=", | |
36 | "--merge-order", | |
37 | NULL | |
38 | }; | |
39 | const char **p = rev_args; | |
40 | ||
41 | for (;;) { | |
42 | const char *str = *p++; | |
43 | int len; | |
44 | if (!str) | |
45 | return 0; | |
46 | len = strlen(str); | |
47 | if (!strncmp(arg, str, len)) | |
48 | return 1; | |
49 | } | |
50 | } | |
51 | ||
960bba0d | 52 | static void show_rev(int type, const unsigned char *sha1) |
023d66ed LT |
53 | { |
54 | if (no_revs) | |
55 | return; | |
56 | output_revs++; | |
042a4ed7 | 57 | printf("%s%s\n", type == show_type ? "" : "^", sha1_to_hex(sha1)); |
023d66ed LT |
58 | } |
59 | ||
60 | static void show_rev_arg(char *rev) | |
61 | { | |
62 | if (no_revs) | |
63 | return; | |
64 | puts(rev); | |
65 | } | |
66 | ||
67 | static void show_norev(char *norev) | |
68 | { | |
f79b65aa LT |
69 | if (flags_only) |
70 | return; | |
023d66ed LT |
71 | if (revs_only) |
72 | return; | |
73 | puts(norev); | |
74 | } | |
75 | ||
76 | static void show_arg(char *arg) | |
77 | { | |
f79b65aa LT |
78 | if (no_flags) |
79 | return; | |
023d66ed LT |
80 | if (do_rev_argument && is_rev_argument(arg)) |
81 | show_rev_arg(arg); | |
82 | else | |
83 | show_norev(arg); | |
84 | } | |
85 | ||
a8be83fe LT |
86 | static int get_parent(char *name, unsigned char *result, int idx) |
87 | { | |
88 | unsigned char sha1[20]; | |
89 | int ret = get_extended_sha1(name, sha1); | |
90 | struct commit *commit; | |
91 | struct commit_list *p; | |
92 | ||
93 | if (ret) | |
94 | return ret; | |
95 | commit = lookup_commit_reference(sha1); | |
96 | if (!commit) | |
97 | return -1; | |
98 | if (parse_commit(commit)) | |
99 | return -1; | |
79162bb8 LT |
100 | if (!idx) { |
101 | memcpy(result, commit->object.sha1, 20); | |
102 | return 0; | |
103 | } | |
a8be83fe LT |
104 | p = commit->parents; |
105 | while (p) { | |
106 | if (!--idx) { | |
107 | memcpy(result, p->item->object.sha1, 20); | |
108 | return 0; | |
109 | } | |
110 | p = p->next; | |
111 | } | |
112 | return -1; | |
113 | } | |
114 | ||
5736bef1 LT |
115 | static int find_short_object_filename(int len, const char *name, unsigned char *sha1) |
116 | { | |
117 | static char dirname[PATH_MAX]; | |
118 | char hex[40]; | |
119 | DIR *dir; | |
120 | int found; | |
121 | ||
122 | snprintf(dirname, sizeof(dirname), "%s/%.2s", get_object_directory(), name); | |
123 | dir = opendir(dirname); | |
124 | sprintf(hex, "%.2s", name); | |
125 | found = 0; | |
126 | if (dir) { | |
127 | struct dirent *de; | |
128 | while ((de = readdir(dir)) != NULL) { | |
129 | if (strlen(de->d_name) != 38) | |
130 | continue; | |
131 | if (memcmp(de->d_name, name + 2, len-2)) | |
132 | continue; | |
133 | memcpy(hex + 2, de->d_name, 38); | |
134 | if (++found > 1) | |
135 | break; | |
136 | } | |
137 | closedir(dir); | |
138 | } | |
139 | if (found == 1) | |
140 | return get_sha1_hex(hex, sha1) == 0; | |
141 | return 0; | |
142 | } | |
143 | ||
671fe4bb LT |
144 | static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b) |
145 | { | |
146 | do { | |
147 | if (*a != *b) | |
148 | return 0; | |
149 | a++; | |
150 | b++; | |
151 | len -= 2; | |
152 | } while (len > 1); | |
153 | if (len) | |
154 | if ((*a ^ *b) & 0xf0) | |
155 | return 0; | |
156 | return 1; | |
157 | } | |
158 | ||
5736bef1 LT |
159 | static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1) |
160 | { | |
671fe4bb LT |
161 | struct packed_git *p; |
162 | ||
163 | prepare_packed_git(); | |
164 | for (p = packed_git; p; p = p->next) { | |
165 | unsigned num = num_packed_objects(p); | |
166 | unsigned first = 0, last = num; | |
167 | while (first < last) { | |
168 | unsigned mid = (first + last) / 2; | |
169 | unsigned char now[20]; | |
170 | int cmp; | |
171 | ||
172 | nth_packed_object_sha1(p, mid, now); | |
173 | cmp = memcmp(match, now, 20); | |
174 | if (!cmp) { | |
175 | first = mid; | |
176 | break; | |
177 | } | |
178 | if (cmp > 0) { | |
179 | first = mid+1; | |
180 | continue; | |
181 | } | |
182 | last = mid; | |
183 | } | |
184 | if (first < num) { | |
185 | unsigned char now[20], next[20]; | |
186 | nth_packed_object_sha1(p, first, now); | |
187 | if (match_sha(len, match, now)) { | |
188 | if (nth_packed_object_sha1(p, first+1, next) || !match_sha(len, match, next)) { | |
189 | memcpy(sha1, now, 20); | |
190 | return 1; | |
191 | } | |
192 | } | |
193 | } | |
194 | } | |
5736bef1 LT |
195 | return 0; |
196 | } | |
197 | ||
198 | static int get_short_sha1(char *name, unsigned char *sha1) | |
199 | { | |
200 | int i; | |
201 | char canonical[40]; | |
202 | unsigned char res[20]; | |
203 | ||
204 | memset(res, 0, 20); | |
205 | memset(canonical, 'x', 40); | |
206 | for (i = 0;;i++) { | |
207 | unsigned char c = name[i]; | |
208 | unsigned char val; | |
209 | if (!c || i > 40) | |
210 | break; | |
211 | if (c >= '0' && c <= '9') | |
212 | val = c - '0'; | |
213 | else if (c >= 'a' && c <= 'f') | |
214 | val = c - 'a' + 10; | |
215 | else if (c >= 'A' && c <='F') { | |
216 | val = c - 'A' + 10; | |
217 | c -= 'A' - 'a'; | |
218 | } | |
219 | else | |
220 | return -1; | |
221 | canonical[i] = c; | |
222 | if (!(i & 1)) | |
223 | val <<= 4; | |
224 | res[i >> 1] |= val; | |
225 | } | |
226 | if (i < 4) | |
227 | return -1; | |
228 | if (find_short_object_filename(i, canonical, sha1)) | |
229 | return 0; | |
230 | if (find_short_packed_object(i, res, sha1)) | |
231 | return 0; | |
232 | return -1; | |
233 | } | |
234 | ||
a8be83fe LT |
235 | /* |
236 | * This is like "get_sha1()", except it allows "sha1 expressions", | |
218e441d | 237 | * notably "xyz^" for "parent of xyz" |
a8be83fe LT |
238 | */ |
239 | static int get_extended_sha1(char *name, unsigned char *sha1) | |
240 | { | |
5736bef1 | 241 | int parent, ret; |
a8be83fe LT |
242 | int len = strlen(name); |
243 | ||
244 | parent = 1; | |
79162bb8 | 245 | if (len > 2 && name[len-1] >= '0' && name[len-1] <= '9') { |
a8be83fe LT |
246 | parent = name[len-1] - '0'; |
247 | len--; | |
248 | } | |
218e441d | 249 | if (len > 1 && name[len-1] == '^') { |
218e441d | 250 | name[len-1] = 0; |
a8be83fe | 251 | ret = get_parent(name, sha1, parent); |
218e441d | 252 | name[len-1] = '^'; |
a8be83fe LT |
253 | if (!ret) |
254 | return 0; | |
255 | } | |
5736bef1 LT |
256 | ret = get_sha1(name, sha1); |
257 | if (!ret) | |
258 | return 0; | |
259 | return get_short_sha1(name, sha1); | |
a8be83fe LT |
260 | } |
261 | ||
023d66ed LT |
262 | static void show_default(void) |
263 | { | |
264 | char *s = def; | |
265 | ||
266 | if (s) { | |
267 | unsigned char sha1[20]; | |
268 | ||
269 | def = NULL; | |
270 | if (!get_extended_sha1(s, sha1)) { | |
042a4ed7 | 271 | show_rev(NORMAL, sha1); |
023d66ed LT |
272 | return; |
273 | } | |
274 | show_arg(s); | |
275 | } | |
276 | } | |
277 | ||
960bba0d LT |
278 | static int show_reference(const char *refname, const unsigned char *sha1) |
279 | { | |
280 | show_rev(NORMAL, sha1); | |
281 | return 0; | |
282 | } | |
283 | ||
178cb243 LT |
284 | int main(int argc, char **argv) |
285 | { | |
023d66ed | 286 | int i, as_is = 0; |
178cb243 LT |
287 | unsigned char sha1[20]; |
288 | ||
289 | for (i = 1; i < argc; i++) { | |
290 | char *arg = argv[i]; | |
291 | char *dotdot; | |
292 | ||
293 | if (as_is) { | |
023d66ed | 294 | show_norev(arg); |
178cb243 LT |
295 | continue; |
296 | } | |
297 | if (*arg == '-') { | |
298 | if (!strcmp(arg, "--")) { | |
023d66ed | 299 | show_default(); |
8ebb0184 LT |
300 | if (revs_only) |
301 | break; | |
178cb243 LT |
302 | as_is = 1; |
303 | } | |
304 | if (!strcmp(arg, "--default")) { | |
178cb243 LT |
305 | def = argv[i+1]; |
306 | i++; | |
307 | continue; | |
308 | } | |
8ebb0184 LT |
309 | if (!strcmp(arg, "--revs-only")) { |
310 | revs_only = 1; | |
311 | continue; | |
312 | } | |
313 | if (!strcmp(arg, "--no-revs")) { | |
314 | no_revs = 1; | |
315 | continue; | |
316 | } | |
f79b65aa LT |
317 | if (!strcmp(arg, "--flags")) { |
318 | flags_only = 1; | |
319 | continue; | |
320 | } | |
321 | if (!strcmp(arg, "--no-flags")) { | |
322 | no_flags = 1; | |
323 | continue; | |
324 | } | |
023d66ed LT |
325 | if (!strcmp(arg, "--verify")) { |
326 | revs_only = 1; | |
327 | do_rev_argument = 0; | |
328 | single_rev = 1; | |
329 | continue; | |
921d865e | 330 | } |
042a4ed7 LT |
331 | if (!strcmp(arg, "--not")) { |
332 | show_type ^= REVERSED; | |
333 | continue; | |
334 | } | |
960bba0d LT |
335 | if (!strcmp(arg, "--all")) { |
336 | for_each_ref(show_reference); | |
337 | continue; | |
338 | } | |
023d66ed | 339 | show_arg(arg); |
178cb243 LT |
340 | continue; |
341 | } | |
178cb243 LT |
342 | dotdot = strstr(arg, ".."); |
343 | if (dotdot) { | |
344 | unsigned char end[20]; | |
345 | char *n = dotdot+2; | |
346 | *dotdot = 0; | |
a8be83fe | 347 | if (!get_extended_sha1(arg, sha1)) { |
178cb243 LT |
348 | if (!*n) |
349 | n = "HEAD"; | |
a8be83fe | 350 | if (!get_extended_sha1(n, end)) { |
8ebb0184 LT |
351 | if (no_revs) |
352 | continue; | |
353 | def = NULL; | |
042a4ed7 LT |
354 | show_rev(NORMAL, end); |
355 | show_rev(REVERSED, sha1); | |
178cb243 LT |
356 | continue; |
357 | } | |
358 | } | |
359 | *dotdot = '.'; | |
360 | } | |
a8be83fe | 361 | if (!get_extended_sha1(arg, sha1)) { |
800644c5 LT |
362 | if (no_revs) |
363 | continue; | |
364 | def = NULL; | |
042a4ed7 | 365 | show_rev(NORMAL, sha1); |
800644c5 LT |
366 | continue; |
367 | } | |
a8be83fe | 368 | if (*arg == '^' && !get_extended_sha1(arg+1, sha1)) { |
800644c5 LT |
369 | if (no_revs) |
370 | continue; | |
371 | def = NULL; | |
042a4ed7 | 372 | show_rev(REVERSED, sha1); |
800644c5 LT |
373 | continue; |
374 | } | |
023d66ed LT |
375 | show_default(); |
376 | show_norev(arg); | |
377 | } | |
378 | show_default(); | |
379 | if (single_rev && output_revs != 1) { | |
380 | fprintf(stderr, "Needed a single revision\n"); | |
381 | exit(1); | |
178cb243 | 382 | } |
178cb243 LT |
383 | return 0; |
384 | } |