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;
16 static int flags_only
= 0;
17 static int no_flags
= 0;
18 static int output_sq
= 0;
22 static int show_type
= NORMAL
;
24 static int get_extended_sha1(char *name
, unsigned char *sha1
);
27 * Some arguments are relevant "revision" arguments,
28 * others are about output format or other details.
29 * This sorts it all out.
31 static int is_rev_argument(const char *arg
)
33 static const char *rev_args
[] = {
40 const char **p
= rev_args
;
43 const char *str
= *p
++;
48 if (!strncmp(arg
, str
, len
))
53 static void show(const char *arg
)
59 while ((ch
= *arg
++)) {
61 fputs("'\\'", stdout
);
71 static void show_rev(int type
, const unsigned char *sha1
)
77 /* Hexadecimal string plus possibly a carret;
78 * this does not have to be quoted even under output_sq.
80 printf("%s%s%c", type
== show_type
? "" : "^", sha1_to_hex(sha1
),
81 output_sq
? ' ' : '\n');
84 static void show_rev_arg(char *rev
)
91 static void show_norev(char *norev
)
100 static void show_arg(char *arg
)
104 if (do_rev_argument
&& is_rev_argument(arg
))
110 static int get_parent(char *name
, unsigned char *result
, int idx
)
112 unsigned char sha1
[20];
113 int ret
= get_extended_sha1(name
, sha1
);
114 struct commit
*commit
;
115 struct commit_list
*p
;
119 commit
= lookup_commit_reference(sha1
);
122 if (parse_commit(commit
))
125 memcpy(result
, commit
->object
.sha1
, 20);
131 memcpy(result
, p
->item
->object
.sha1
, 20);
139 static int find_short_object_filename(int len
, const char *name
, unsigned char *sha1
)
141 static char dirname
[PATH_MAX
];
146 snprintf(dirname
, sizeof(dirname
), "%s/%.2s", get_object_directory(), name
);
147 dir
= opendir(dirname
);
148 sprintf(hex
, "%.2s", name
);
152 while ((de
= readdir(dir
)) != NULL
) {
153 if (strlen(de
->d_name
) != 38)
155 if (memcmp(de
->d_name
, name
+ 2, len
-2))
157 memcpy(hex
+ 2, de
->d_name
, 38);
164 return get_sha1_hex(hex
, sha1
) == 0;
168 static int match_sha(unsigned len
, const unsigned char *a
, const unsigned char *b
)
178 if ((*a
^ *b
) & 0xf0)
183 static int find_short_packed_object(int len
, const unsigned char *match
, unsigned char *sha1
)
185 struct packed_git
*p
;
187 prepare_packed_git();
188 for (p
= packed_git
; p
; p
= p
->next
) {
189 unsigned num
= num_packed_objects(p
);
190 unsigned first
= 0, last
= num
;
191 while (first
< last
) {
192 unsigned mid
= (first
+ last
) / 2;
193 unsigned char now
[20];
196 nth_packed_object_sha1(p
, mid
, now
);
197 cmp
= memcmp(match
, now
, 20);
209 unsigned char now
[20], next
[20];
210 nth_packed_object_sha1(p
, first
, now
);
211 if (match_sha(len
, match
, now
)) {
212 if (nth_packed_object_sha1(p
, first
+1, next
) || !match_sha(len
, match
, next
)) {
213 memcpy(sha1
, now
, 20);
222 static int get_short_sha1(char *name
, unsigned char *sha1
)
226 unsigned char res
[20];
229 memset(canonical
, 'x', 40);
231 unsigned char c
= name
[i
];
235 if (c
>= '0' && c
<= '9')
237 else if (c
>= 'a' && c
<= 'f')
239 else if (c
>= 'A' && c
<='F') {
252 if (find_short_object_filename(i
, canonical
, sha1
))
254 if (find_short_packed_object(i
, res
, sha1
))
260 * This is like "get_sha1()", except it allows "sha1 expressions",
261 * notably "xyz^" for "parent of xyz"
263 static int get_extended_sha1(char *name
, unsigned char *sha1
)
266 int len
= strlen(name
);
269 if (len
> 2 && name
[len
-1] >= '0' && name
[len
-1] <= '9') {
270 parent
= name
[len
-1] - '0';
273 if (len
> 1 && name
[len
-1] == '^') {
275 ret
= get_parent(name
, sha1
, parent
);
280 ret
= get_sha1(name
, sha1
);
283 return get_short_sha1(name
, sha1
);
286 static void show_default(void)
291 unsigned char sha1
[20];
294 if (!get_extended_sha1(s
, sha1
)) {
295 show_rev(NORMAL
, sha1
);
302 static int show_reference(const char *refname
, const unsigned char *sha1
)
304 show_rev(NORMAL
, sha1
);
308 int main(int argc
, char **argv
)
311 unsigned char sha1
[20];
313 for (i
= 1; i
< argc
; i
++) {
322 if (!strcmp(arg
, "--")) {
328 if (!strcmp(arg
, "--default")) {
333 if (!strcmp(arg
, "--revs-only")) {
337 if (!strcmp(arg
, "--no-revs")) {
341 if (!strcmp(arg
, "--flags")) {
345 if (!strcmp(arg
, "--no-flags")) {
349 if (!strcmp(arg
, "--verify")) {
355 if (!strcmp(arg
, "--sq")) {
359 if (!strcmp(arg
, "--not")) {
360 show_type
^= REVERSED
;
363 if (!strcmp(arg
, "--all")) {
364 for_each_ref(show_reference
);
370 dotdot
= strstr(arg
, "..");
372 unsigned char end
[20];
375 if (!get_extended_sha1(arg
, sha1
)) {
378 if (!get_extended_sha1(n
, end
)) {
382 show_rev(NORMAL
, end
);
383 show_rev(REVERSED
, sha1
);
389 if (!get_extended_sha1(arg
, sha1
)) {
393 show_rev(NORMAL
, sha1
);
396 if (*arg
== '^' && !get_extended_sha1(arg
+1, sha1
)) {
400 show_rev(REVERSED
, sha1
);
407 if (single_rev
&& output_revs
!= 1) {
408 fprintf(stderr
, "Needed a single revision\n");