]>
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; | |
100 | p = commit->parents; | |
101 | while (p) { | |
102 | if (!--idx) { | |
103 | memcpy(result, p->item->object.sha1, 20); | |
104 | return 0; | |
105 | } | |
106 | p = p->next; | |
107 | } | |
108 | return -1; | |
109 | } | |
110 | ||
5736bef1 LT |
111 | static int find_short_object_filename(int len, const char *name, unsigned char *sha1) |
112 | { | |
113 | static char dirname[PATH_MAX]; | |
114 | char hex[40]; | |
115 | DIR *dir; | |
116 | int found; | |
117 | ||
118 | snprintf(dirname, sizeof(dirname), "%s/%.2s", get_object_directory(), name); | |
119 | dir = opendir(dirname); | |
120 | sprintf(hex, "%.2s", name); | |
121 | found = 0; | |
122 | if (dir) { | |
123 | struct dirent *de; | |
124 | while ((de = readdir(dir)) != NULL) { | |
125 | if (strlen(de->d_name) != 38) | |
126 | continue; | |
127 | if (memcmp(de->d_name, name + 2, len-2)) | |
128 | continue; | |
129 | memcpy(hex + 2, de->d_name, 38); | |
130 | if (++found > 1) | |
131 | break; | |
132 | } | |
133 | closedir(dir); | |
134 | } | |
135 | if (found == 1) | |
136 | return get_sha1_hex(hex, sha1) == 0; | |
137 | return 0; | |
138 | } | |
139 | ||
671fe4bb LT |
140 | static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b) |
141 | { | |
142 | do { | |
143 | if (*a != *b) | |
144 | return 0; | |
145 | a++; | |
146 | b++; | |
147 | len -= 2; | |
148 | } while (len > 1); | |
149 | if (len) | |
150 | if ((*a ^ *b) & 0xf0) | |
151 | return 0; | |
152 | return 1; | |
153 | } | |
154 | ||
5736bef1 LT |
155 | static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1) |
156 | { | |
671fe4bb LT |
157 | struct packed_git *p; |
158 | ||
159 | prepare_packed_git(); | |
160 | for (p = packed_git; p; p = p->next) { | |
161 | unsigned num = num_packed_objects(p); | |
162 | unsigned first = 0, last = num; | |
163 | while (first < last) { | |
164 | unsigned mid = (first + last) / 2; | |
165 | unsigned char now[20]; | |
166 | int cmp; | |
167 | ||
168 | nth_packed_object_sha1(p, mid, now); | |
169 | cmp = memcmp(match, now, 20); | |
170 | if (!cmp) { | |
171 | first = mid; | |
172 | break; | |
173 | } | |
174 | if (cmp > 0) { | |
175 | first = mid+1; | |
176 | continue; | |
177 | } | |
178 | last = mid; | |
179 | } | |
180 | if (first < num) { | |
181 | unsigned char now[20], next[20]; | |
182 | nth_packed_object_sha1(p, first, now); | |
183 | if (match_sha(len, match, now)) { | |
184 | if (nth_packed_object_sha1(p, first+1, next) || !match_sha(len, match, next)) { | |
185 | memcpy(sha1, now, 20); | |
186 | return 1; | |
187 | } | |
188 | } | |
189 | } | |
190 | } | |
5736bef1 LT |
191 | return 0; |
192 | } | |
193 | ||
194 | static int get_short_sha1(char *name, unsigned char *sha1) | |
195 | { | |
196 | int i; | |
197 | char canonical[40]; | |
198 | unsigned char res[20]; | |
199 | ||
200 | memset(res, 0, 20); | |
201 | memset(canonical, 'x', 40); | |
202 | for (i = 0;;i++) { | |
203 | unsigned char c = name[i]; | |
204 | unsigned char val; | |
205 | if (!c || i > 40) | |
206 | break; | |
207 | if (c >= '0' && c <= '9') | |
208 | val = c - '0'; | |
209 | else if (c >= 'a' && c <= 'f') | |
210 | val = c - 'a' + 10; | |
211 | else if (c >= 'A' && c <='F') { | |
212 | val = c - 'A' + 10; | |
213 | c -= 'A' - 'a'; | |
214 | } | |
215 | else | |
216 | return -1; | |
217 | canonical[i] = c; | |
218 | if (!(i & 1)) | |
219 | val <<= 4; | |
220 | res[i >> 1] |= val; | |
221 | } | |
222 | if (i < 4) | |
223 | return -1; | |
224 | if (find_short_object_filename(i, canonical, sha1)) | |
225 | return 0; | |
226 | if (find_short_packed_object(i, res, sha1)) | |
227 | return 0; | |
228 | return -1; | |
229 | } | |
230 | ||
a8be83fe LT |
231 | /* |
232 | * This is like "get_sha1()", except it allows "sha1 expressions", | |
218e441d | 233 | * notably "xyz^" for "parent of xyz" |
a8be83fe LT |
234 | */ |
235 | static int get_extended_sha1(char *name, unsigned char *sha1) | |
236 | { | |
5736bef1 | 237 | int parent, ret; |
a8be83fe LT |
238 | int len = strlen(name); |
239 | ||
240 | parent = 1; | |
218e441d | 241 | if (len > 2 && name[len-1] >= '1' && name[len-1] <= '9') { |
a8be83fe LT |
242 | parent = name[len-1] - '0'; |
243 | len--; | |
244 | } | |
218e441d | 245 | if (len > 1 && name[len-1] == '^') { |
218e441d | 246 | name[len-1] = 0; |
a8be83fe | 247 | ret = get_parent(name, sha1, parent); |
218e441d | 248 | name[len-1] = '^'; |
a8be83fe LT |
249 | if (!ret) |
250 | return 0; | |
251 | } | |
5736bef1 LT |
252 | ret = get_sha1(name, sha1); |
253 | if (!ret) | |
254 | return 0; | |
255 | return get_short_sha1(name, sha1); | |
a8be83fe LT |
256 | } |
257 | ||
023d66ed LT |
258 | static void show_default(void) |
259 | { | |
260 | char *s = def; | |
261 | ||
262 | if (s) { | |
263 | unsigned char sha1[20]; | |
264 | ||
265 | def = NULL; | |
266 | if (!get_extended_sha1(s, sha1)) { | |
042a4ed7 | 267 | show_rev(NORMAL, sha1); |
023d66ed LT |
268 | return; |
269 | } | |
270 | show_arg(s); | |
271 | } | |
272 | } | |
273 | ||
960bba0d LT |
274 | static int show_reference(const char *refname, const unsigned char *sha1) |
275 | { | |
276 | show_rev(NORMAL, sha1); | |
277 | return 0; | |
278 | } | |
279 | ||
178cb243 LT |
280 | int main(int argc, char **argv) |
281 | { | |
023d66ed | 282 | int i, as_is = 0; |
178cb243 LT |
283 | unsigned char sha1[20]; |
284 | ||
285 | for (i = 1; i < argc; i++) { | |
286 | char *arg = argv[i]; | |
287 | char *dotdot; | |
288 | ||
289 | if (as_is) { | |
023d66ed | 290 | show_norev(arg); |
178cb243 LT |
291 | continue; |
292 | } | |
293 | if (*arg == '-') { | |
294 | if (!strcmp(arg, "--")) { | |
023d66ed | 295 | show_default(); |
8ebb0184 LT |
296 | if (revs_only) |
297 | break; | |
178cb243 LT |
298 | as_is = 1; |
299 | } | |
300 | if (!strcmp(arg, "--default")) { | |
178cb243 LT |
301 | def = argv[i+1]; |
302 | i++; | |
303 | continue; | |
304 | } | |
8ebb0184 LT |
305 | if (!strcmp(arg, "--revs-only")) { |
306 | revs_only = 1; | |
307 | continue; | |
308 | } | |
309 | if (!strcmp(arg, "--no-revs")) { | |
310 | no_revs = 1; | |
311 | continue; | |
312 | } | |
f79b65aa LT |
313 | if (!strcmp(arg, "--flags")) { |
314 | flags_only = 1; | |
315 | continue; | |
316 | } | |
317 | if (!strcmp(arg, "--no-flags")) { | |
318 | no_flags = 1; | |
319 | continue; | |
320 | } | |
023d66ed LT |
321 | if (!strcmp(arg, "--verify")) { |
322 | revs_only = 1; | |
323 | do_rev_argument = 0; | |
324 | single_rev = 1; | |
325 | continue; | |
921d865e | 326 | } |
042a4ed7 LT |
327 | if (!strcmp(arg, "--not")) { |
328 | show_type ^= REVERSED; | |
329 | continue; | |
330 | } | |
960bba0d LT |
331 | if (!strcmp(arg, "--all")) { |
332 | for_each_ref(show_reference); | |
333 | continue; | |
334 | } | |
023d66ed | 335 | show_arg(arg); |
178cb243 LT |
336 | continue; |
337 | } | |
178cb243 LT |
338 | dotdot = strstr(arg, ".."); |
339 | if (dotdot) { | |
340 | unsigned char end[20]; | |
341 | char *n = dotdot+2; | |
342 | *dotdot = 0; | |
a8be83fe | 343 | if (!get_extended_sha1(arg, sha1)) { |
178cb243 LT |
344 | if (!*n) |
345 | n = "HEAD"; | |
a8be83fe | 346 | if (!get_extended_sha1(n, end)) { |
8ebb0184 LT |
347 | if (no_revs) |
348 | continue; | |
349 | def = NULL; | |
042a4ed7 LT |
350 | show_rev(NORMAL, end); |
351 | show_rev(REVERSED, sha1); | |
178cb243 LT |
352 | continue; |
353 | } | |
354 | } | |
355 | *dotdot = '.'; | |
356 | } | |
a8be83fe | 357 | if (!get_extended_sha1(arg, sha1)) { |
800644c5 LT |
358 | if (no_revs) |
359 | continue; | |
360 | def = NULL; | |
042a4ed7 | 361 | show_rev(NORMAL, sha1); |
800644c5 LT |
362 | continue; |
363 | } | |
a8be83fe | 364 | if (*arg == '^' && !get_extended_sha1(arg+1, sha1)) { |
800644c5 LT |
365 | if (no_revs) |
366 | continue; | |
367 | def = NULL; | |
042a4ed7 | 368 | show_rev(REVERSED, sha1); |
800644c5 LT |
369 | continue; |
370 | } | |
023d66ed LT |
371 | show_default(); |
372 | show_norev(arg); | |
373 | } | |
374 | show_default(); | |
375 | if (single_rev && output_revs != 1) { | |
376 | fprintf(stderr, "Needed a single revision\n"); | |
377 | exit(1); | |
178cb243 | 378 | } |
178cb243 LT |
379 | return 0; |
380 | } |