4 static int find_short_object_filename(int len
, const char *name
, unsigned char *sha1
)
6 static char dirname
[PATH_MAX
];
11 snprintf(dirname
, sizeof(dirname
), "%s/%.2s", get_object_directory(), name
);
12 dir
= opendir(dirname
);
13 sprintf(hex
, "%.2s", name
);
17 while ((de
= readdir(dir
)) != NULL
) {
18 if (strlen(de
->d_name
) != 38)
20 if (memcmp(de
->d_name
, name
+ 2, len
-2))
22 memcpy(hex
+ 2, de
->d_name
, 38);
29 return get_sha1_hex(hex
, sha1
) == 0;
33 static int match_sha(unsigned len
, const unsigned char *a
, const unsigned char *b
)
48 static int find_short_packed_object(int len
, const unsigned char *match
, unsigned char *sha1
)
53 for (p
= packed_git
; p
; p
= p
->next
) {
54 unsigned num
= num_packed_objects(p
);
55 unsigned first
= 0, last
= num
;
56 while (first
< last
) {
57 unsigned mid
= (first
+ last
) / 2;
58 unsigned char now
[20];
61 nth_packed_object_sha1(p
, mid
, now
);
62 cmp
= memcmp(match
, now
, 20);
74 unsigned char now
[20], next
[20];
75 nth_packed_object_sha1(p
, first
, now
);
76 if (match_sha(len
, match
, now
)) {
77 if (nth_packed_object_sha1(p
, first
+1, next
) || !match_sha(len
, match
, next
)) {
78 memcpy(sha1
, now
, 20);
87 static int get_short_sha1(const char *name
, int len
, unsigned char *sha1
)
91 unsigned char res
[20];
96 memset(canonical
, 'x', 40);
97 for (i
= 0; i
< len
;i
++) {
98 unsigned char c
= name
[i
];
100 if (c
>= '0' && c
<= '9')
102 else if (c
>= 'a' && c
<= 'f')
104 else if (c
>= 'A' && c
<='F') {
115 if (find_short_object_filename(i
, canonical
, sha1
))
117 if (find_short_packed_object(i
, res
, sha1
))
122 static int get_sha1_file(const char *path
, unsigned char *result
)
125 int fd
= open(path
, O_RDONLY
);
130 len
= read(fd
, buffer
, sizeof(buffer
));
134 return get_sha1_hex(buffer
, result
);
137 static int get_sha1_basic(const char *str
, int len
, unsigned char *sha1
)
139 static const char *prefix
[] = {
148 if (len
== 40 && !get_sha1_hex(str
, sha1
))
151 for (p
= prefix
; *p
; p
++) {
152 char *pathname
= git_path("%s/%.*s", *p
, len
, str
);
153 if (!get_sha1_file(pathname
, sha1
))
160 static int get_sha1_1(const char *name
, int len
, unsigned char *sha1
);
162 static int get_parent(const char *name
, int len
,
163 unsigned char *result
, int idx
)
165 unsigned char sha1
[20];
166 int ret
= get_sha1_1(name
, len
, sha1
);
167 struct commit
*commit
;
168 struct commit_list
*p
;
172 commit
= lookup_commit_reference(sha1
);
175 if (parse_commit(commit
))
178 memcpy(result
, commit
->object
.sha1
, 20);
184 memcpy(result
, p
->item
->object
.sha1
, 20);
192 static int get_nth_ancestor(const char *name
, int len
,
193 unsigned char *result
, int generation
)
195 unsigned char sha1
[20];
196 int ret
= get_sha1_1(name
, len
, sha1
);
200 while (generation
--) {
201 struct commit
*commit
= lookup_commit_reference(sha1
);
203 if (!commit
|| parse_commit(commit
) || !commit
->parents
)
205 memcpy(sha1
, commit
->parents
->item
->object
.sha1
, 20);
207 memcpy(result
, sha1
, 20);
211 static int get_sha1_1(const char *name
, int len
, unsigned char *sha1
)
216 /* foo^[0-9] or foo^ (== foo^1); we do not do more than 9 parents. */
217 if (len
> 2 && name
[len
-2] == '^' &&
218 name
[len
-1] >= '0' && name
[len
-1] <= '9') {
219 parent
= name
[len
-1] - '0';
222 else if (len
> 1 && name
[len
-1] == '^') {
229 return get_parent(name
, len
, sha1
, parent
);
231 /* "name~3" is "name^^^",
232 * "name~12" is "name^^^^^^^^^^^^", and
233 * "name~" and "name~0" are name -- not "name^0"!
236 for (cp
= name
+ len
- 1; name
<= cp
; cp
--) {
238 if ('0' <= ch
&& ch
<= '9')
244 if (!parent
&& *cp
== '~') {
245 int len1
= cp
- name
;
247 while (cp
< name
+ len
)
248 parent
= parent
* 10 + *cp
++ - '0';
249 return get_nth_ancestor(name
, len1
, sha1
, parent
);
252 ret
= get_sha1_basic(name
, len
, sha1
);
255 return get_short_sha1(name
, len
, sha1
);
259 * This is like "get_sha1_basic()", except it allows "sha1 expressions",
260 * notably "xyz^" for "parent of xyz"
262 int get_sha1(const char *name
, unsigned char *sha1
)
264 return get_sha1_1(name
, strlen(name
), sha1
);