]>
git.proxmox.com Git - libgit2.git/blob - src/commit_list.c
2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
8 #include "commit_list.h"
14 int git_commit_list_time_cmp(const void *a
, const void *b
)
16 int64_t time_a
= ((git_commit_list_node
*) a
)->time
;
17 int64_t time_b
= ((git_commit_list_node
*) b
)->time
;
27 git_commit_list
*git_commit_list_insert(git_commit_list_node
*item
, git_commit_list
**list_p
)
29 git_commit_list
*new_list
= git__malloc(sizeof(git_commit_list
));
30 if (new_list
!= NULL
) {
31 new_list
->item
= item
;
32 new_list
->next
= *list_p
;
38 git_commit_list
*git_commit_list_insert_by_date(git_commit_list_node
*item
, git_commit_list
**list_p
)
40 git_commit_list
**pp
= list_p
;
43 while ((p
= *pp
) != NULL
) {
44 if (git_commit_list_time_cmp(p
->item
, item
) > 0)
50 return git_commit_list_insert(item
, pp
);
53 git_commit_list_node
*git_commit_list_alloc_node(git_revwalk
*walk
)
55 return (git_commit_list_node
*)git_pool_mallocz(&walk
->commit_pool
, 1);
58 static int commit_error(git_commit_list_node
*commit
, const char *msg
)
60 char commit_oid
[GIT_OID_HEXSZ
+ 1];
61 git_oid_fmt(commit_oid
, &commit
->oid
);
62 commit_oid
[GIT_OID_HEXSZ
] = '\0';
64 giterr_set(GITERR_ODB
, "failed to parse commit %s - %s", commit_oid
, msg
);
69 static git_commit_list_node
**alloc_parents(
70 git_revwalk
*walk
, git_commit_list_node
*commit
, size_t n_parents
)
72 if (n_parents
<= PARENTS_PER_COMMIT
)
73 return (git_commit_list_node
**)((char *)commit
+ sizeof(git_commit_list_node
));
75 return (git_commit_list_node
**)git_pool_malloc(
76 &walk
->commit_pool
, (uint32_t)(n_parents
* sizeof(git_commit_list_node
*)));
80 void git_commit_list_free(git_commit_list
**list_p
)
82 git_commit_list
*list
= *list_p
;
88 git_commit_list
*temp
= list
;
96 git_commit_list_node
*git_commit_list_pop(git_commit_list
**stack
)
98 git_commit_list
*top
= *stack
;
99 git_commit_list_node
*item
= top
? top
->item
: NULL
;
108 static int commit_quick_parse(
110 git_commit_list_node
*commit
,
111 const uint8_t *buffer
,
114 const size_t parent_len
= strlen("parent ") + GIT_OID_HEXSZ
+ 1;
115 const uint8_t *buffer_end
= buffer
+ buffer_len
;
116 const uint8_t *parents_start
, *committer_start
;
120 buffer
+= strlen("tree ") + GIT_OID_HEXSZ
+ 1;
122 parents_start
= buffer
;
123 while (buffer
+ parent_len
< buffer_end
&& memcmp(buffer
, "parent ", strlen("parent ")) == 0) {
125 buffer
+= parent_len
;
128 commit
->parents
= alloc_parents(walk
, commit
, parents
);
129 GITERR_CHECK_ALLOC(commit
->parents
);
131 buffer
= parents_start
;
132 for (i
= 0; i
< parents
; ++i
) {
135 if (git_oid_fromstr(&oid
, (const char *)buffer
+ strlen("parent ")) < 0)
138 commit
->parents
[i
] = git_revwalk__commit_lookup(walk
, &oid
);
139 if (commit
->parents
[i
] == NULL
)
142 buffer
+= parent_len
;
145 commit
->out_degree
= (unsigned short)parents
;
147 if ((committer_start
= buffer
= memchr(buffer
, '\n', buffer_end
- buffer
)) == NULL
)
148 return commit_error(commit
, "object is corrupted");
152 if ((buffer
= memchr(buffer
, '\n', buffer_end
- buffer
)) == NULL
)
153 return commit_error(commit
, "object is corrupted");
155 /* Skip trailing spaces */
156 while (buffer
> committer_start
&& git__isspace(*buffer
))
159 /* Seek for the beginning of the pack of digits */
160 while (buffer
> committer_start
&& git__isdigit(*buffer
))
163 /* Skip potential timezone offset */
164 if ((buffer
> committer_start
) && (*buffer
== '+' || *buffer
== '-')) {
167 while (buffer
> committer_start
&& git__isspace(*buffer
))
170 while (buffer
> committer_start
&& git__isdigit(*buffer
))
174 if ((buffer
== committer_start
) || (git__strtol64(&commit_time
, (char *)(buffer
+ 1), NULL
, 10) < 0))
175 return commit_error(commit
, "cannot parse commit time");
177 commit
->time
= commit_time
;
182 int git_commit_list_parse(git_revwalk
*walk
, git_commit_list_node
*commit
)
190 if ((error
= git_odb_read(&obj
, walk
->odb
, &commit
->oid
)) < 0)
193 if (obj
->cached
.type
!= GIT_OBJ_COMMIT
) {
194 giterr_set(GITERR_INVALID
, "object is no commit object");
197 error
= commit_quick_parse(
199 (const uint8_t *)git_odb_object_data(obj
),
200 git_odb_object_size(obj
));
202 git_odb_object_free(obj
);