4 * Copyright (C) Linus Torvalds, 2005
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;
19 static int show_type = NORMAL;
21 static int get_extended_sha1(char *name, unsigned char *sha1);
24 * Some arguments are relevant "revision" arguments,
25 * others are about output format or other details.
26 * This sorts it all out.
28 static int is_rev_argument(const char *arg)
30 static const char *rev_args[] = {
37 const char **p = rev_args;
40 const char *str = *p++;
45 if (!strncmp(arg, str, len))
50 static void show_rev(int type, const unsigned char *sha1)
55 printf("%s%s\n", type == show_type ? "" : "^", sha1_to_hex(sha1));
58 static void show_rev_arg(char *rev)
65 static void show_norev(char *norev)
72 static void show_arg(char *arg)
74 if (do_rev_argument && is_rev_argument(arg))
80 static int get_parent(char *name, unsigned char *result, int idx)
82 unsigned char sha1[20];
83 int ret = get_extended_sha1(name, sha1);
84 struct commit *commit;
85 struct commit_list *p;
89 commit = lookup_commit_reference(sha1);
92 if (parse_commit(commit))
97 memcpy(result, p->item->object.sha1, 20);
105 static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
107 static char dirname[PATH_MAX];
112 snprintf(dirname, sizeof(dirname), "%s/%.2s", get_object_directory(), name);
113 dir = opendir(dirname);
114 sprintf(hex, "%.2s", name);
118 while ((de = readdir(dir)) != NULL) {
119 if (strlen(de->d_name) != 38)
121 if (memcmp(de->d_name, name + 2, len-2))
123 memcpy(hex + 2, de->d_name, 38);
130 return get_sha1_hex(hex, sha1) == 0;
134 static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b)
144 if ((*a ^ *b) & 0xf0)
149 static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1)
151 struct packed_git *p;
153 prepare_packed_git();
154 for (p = packed_git; p; p = p->next) {
155 unsigned num = num_packed_objects(p);
156 unsigned first = 0, last = num;
157 while (first < last) {
158 unsigned mid = (first + last) / 2;
159 unsigned char now[20];
162 nth_packed_object_sha1(p, mid, now);
163 cmp = memcmp(match, now, 20);
175 unsigned char now[20], next[20];
176 nth_packed_object_sha1(p, first, now);
177 if (match_sha(len, match, now)) {
178 if (nth_packed_object_sha1(p, first+1, next) || !match_sha(len, match, next)) {
179 memcpy(sha1, now, 20);
188 static int get_short_sha1(char *name, unsigned char *sha1)
192 unsigned char res[20];
195 memset(canonical, 'x', 40);
197 unsigned char c = name[i];
201 if (c >= '0' && c <= '9')
203 else if (c >= 'a' && c <= 'f')
205 else if (c >= 'A' && c <='F') {
218 if (find_short_object_filename(i, canonical, sha1))
220 if (find_short_packed_object(i, res, sha1))
226 * This is like "get_sha1()", except it allows "sha1 expressions",
227 * notably "xyz^" for "parent of xyz"
229 static int get_extended_sha1(char *name, unsigned char *sha1)
232 int len = strlen(name);
235 if (len > 2 && name[len-1] >= '1' && name[len-1] <= '9') {
236 parent = name[len-1] - '0';
239 if (len > 1 && name[len-1] == '^') {
241 ret = get_parent(name, sha1, parent);
246 ret = get_sha1(name, sha1);
249 return get_short_sha1(name, sha1);
252 static void show_default(void)
257 unsigned char sha1[20];
260 if (!get_extended_sha1(s, sha1)) {
261 show_rev(NORMAL, sha1);
268 static int show_reference(const char *refname, const unsigned char *sha1)
270 show_rev(NORMAL, sha1);
274 int main(int argc, char **argv)
277 unsigned char sha1[20];
279 for (i = 1; i < argc; i++) {
288 if (!strcmp(arg, "--")) {
294 if (!strcmp(arg, "--default")) {
299 if (!strcmp(arg, "--revs-only")) {
303 if (!strcmp(arg, "--no-revs")) {
307 if (!strcmp(arg, "--verify")) {
313 if (!strcmp(arg, "--not")) {
314 show_type ^= REVERSED;
317 if (!strcmp(arg, "--all")) {
318 for_each_ref(show_reference);
324 dotdot = strstr(arg, "..");
326 unsigned char end[20];
329 if (!get_extended_sha1(arg, sha1)) {
332 if (!get_extended_sha1(n, end)) {
336 show_rev(NORMAL, end);
337 show_rev(REVERSED, sha1);
343 if (!get_extended_sha1(arg, sha1)) {
347 show_rev(NORMAL, sha1);
350 if (*arg == '^' && !get_extended_sha1(arg+1, sha1)) {
354 show_rev(REVERSED, sha1);
361 if (single_rev && output_revs != 1) {
362 fprintf(stderr, "Needed a single revision\n");