2 * This file is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2,
4 * as published by the Free Software Foundation.
6 * In addition to the permissions in the GNU General Public License,
7 * the authors give you unlimited permission to link the compiled
8 * version of this file into combinations with other programs,
9 * and to distribute those combinations without any restriction
10 * coming from the use of this file. (The General Public License
11 * restrictions do apply in other respects; for example, they cover
12 * modification of the file, and distribution when not linked into
13 * a combined executable.)
15 * This file is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; see the file COPYING. If not, write to
22 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
31 #define COMMIT_PRINT(commit) {\
32 char oid[41]; oid[40] = 0;\
33 git_oid_fmt(oid, &commit->object.id);\
34 printf("Oid: %s | In degree: %d | Time: %u\n", oid, commit->in_degree, commit->commit_time);\
37 const git_oid
*git_commit_id(git_commit
*c
)
42 void git_commit__mark_uninteresting(git_commit
*commit
)
44 git_commit_node
*parents
;
49 parents
= commit
->parents
.head
;
51 commit
->uninteresting
= 1;
54 parents
->commit
->uninteresting
= 1;
55 parents
= parents
->next
;
59 git_commit
*git_commit_parse(git_revpool
*pool
, const git_oid
*id
)
61 git_commit
*commit
= NULL
;
63 if ((commit
= git_commit_lookup(pool
, id
)) == NULL
)
66 if (git_commit_parse_existing(commit
) < 0)
76 int git_commit_parse_existing(git_commit
*commit
)
84 error
= git_odb_read(&commit_obj
, commit
->object
.pool
->db
, &commit
->object
.id
);
88 if (commit_obj
.type
!= GIT_OBJ_COMMIT
) {
93 error
= git_commit__parse_buffer(commit
, commit_obj
.data
, commit_obj
.len
);
96 git_obj_close(&commit_obj
);
100 git_commit
*git_commit_lookup(git_revpool
*pool
, const git_oid
*id
)
102 git_commit
*commit
= NULL
;
107 commit
= (git_commit
*)git_revpool_table_lookup(pool
->commits
, id
);
111 commit
= git__malloc(sizeof(git_commit
));
116 memset(commit
, 0x0, sizeof(git_commit
));
118 // Initialize parent object
119 git_oid_cpy(&commit
->object
.id
, id
);
120 commit
->object
.pool
= pool
;
122 git_revpool_table_insert(pool
->commits
, (git_revpool_object
*)commit
);
127 int git_commit__parse_time(time_t *commit_time
, char *buffer
, const char *buffer_end
)
129 if (memcmp(buffer
, "author ", 7) != 0)
130 return GIT_EOBJCORRUPTED
;
132 buffer
= memchr(buffer
, '\n', buffer_end
- buffer
);
133 if (!buffer
|| ++buffer
>= buffer_end
)
134 return GIT_EOBJCORRUPTED
;
136 if (memcmp(buffer
, "committer ", 10) != 0)
137 return GIT_EOBJCORRUPTED
;
139 buffer
= memchr(buffer
, '>', buffer_end
- buffer
);
140 if (!buffer
|| ++buffer
>= buffer_end
)
141 return GIT_EOBJCORRUPTED
;
143 *commit_time
= strtol(buffer
, &buffer
, 10);
145 if (*commit_time
== 0)
146 return GIT_EOBJCORRUPTED
;
148 buffer
= memchr(buffer
, '\n', buffer_end
- buffer
);
149 if (!buffer
|| ++buffer
>= buffer_end
)
150 return GIT_EOBJCORRUPTED
;
152 return (buffer
< buffer_end
) ? 0 : -1;
155 int git_commit__parse_oid(git_oid
*oid
, char **buffer_out
, const char *buffer_end
, const char *header
)
157 const size_t sha_len
= GIT_OID_HEXSZ
;
158 const size_t header_len
= strlen(header
);
160 char *buffer
= *buffer_out
;
162 if (buffer
+ (header_len
+ sha_len
+ 1) > buffer_end
)
163 return GIT_EOBJCORRUPTED
;
165 if (memcmp(buffer
, header
, header_len
) != 0)
166 return GIT_EOBJCORRUPTED
;
168 if (buffer
[header_len
+ sha_len
] != '\n')
169 return GIT_EOBJCORRUPTED
;
171 if (git_oid_mkstr(oid
, buffer
+ header_len
) < 0)
172 return GIT_EOBJCORRUPTED
;
174 *buffer_out
= buffer
+ (header_len
+ sha_len
+ 1);
179 int git_commit__parse_buffer(git_commit
*commit
, void *data
, size_t len
)
181 char *buffer
= (char *)data
;
182 const char *buffer_end
= (char *)data
+ len
;
189 if (git_commit__parse_oid(&oid
, &buffer
, buffer_end
, "tree ") < 0)
190 return GIT_EOBJCORRUPTED
;
193 * TODO: load tree into commit object
194 * TODO: commit grafts!
197 while (git_commit__parse_oid(&oid
, &buffer
, buffer_end
, "parent ") == 0) {
200 if ((parent
= git_commit_lookup(commit
->object
.pool
, &oid
)) == NULL
)
201 return GIT_ENOTFOUND
;
203 // Inherit uninteresting flag
204 if (commit
->uninteresting
)
205 parent
->uninteresting
= 1;
207 if (git_commit_list_push_back(&commit
->parents
, parent
))
211 if (git_commit__parse_time(&commit
->commit_time
, buffer
, buffer_end
) < 0)
212 return GIT_EOBJCORRUPTED
;
219 int git_commit_list_push_back(git_commit_list
*list
, git_commit
*commit
)
221 git_commit_node
*node
= NULL
;
223 node
= git__malloc(sizeof(git_commit_list
));
228 node
->commit
= commit
;
230 node
->prev
= list
->tail
;
232 if (list
->tail
== NULL
) {
233 list
->head
= list
->tail
= node
;
235 list
->tail
->next
= node
;
243 int git_commit_list_push_front(git_commit_list
*list
, git_commit
*commit
)
245 git_commit_node
*node
= NULL
;
247 node
= git__malloc(sizeof(git_commit_list
));
252 node
->commit
= commit
;
253 node
->next
= list
->head
;
256 if (list
->head
== NULL
) {
257 list
->head
= list
->tail
= node
;
259 list
->head
->prev
= node
;
268 git_commit
*git_commit_list_pop_back(git_commit_list
*list
)
270 git_commit_node
*node
;
273 if (list
->tail
== NULL
)
277 list
->tail
= list
->tail
->prev
;
278 if (list
->tail
== NULL
)
281 commit
= node
->commit
;
289 git_commit
*git_commit_list_pop_front(git_commit_list
*list
)
291 git_commit_node
*node
;
294 if (list
->head
== NULL
)
298 list
->head
= list
->head
->next
;
299 if (list
->head
== NULL
)
302 commit
= node
->commit
;
310 void git_commit_list_clear(git_commit_list
*list
, int free_commits
)
312 git_commit_node
*node
, *next_node
;
319 next_node
= node
->next
;
324 list
->head
= list
->tail
= NULL
;
328 void git_commit_list_timesort(git_commit_list
*list
)
330 git_commit_node
*p
, *q
, *e
;
331 int in_size
, p_size
, q_size
, merge_count
, i
;
333 if (list
->head
== NULL
)
349 for (i
= 0; i
< in_size
&& q
; ++i
, q
= q
->next
)
352 while (p_size
> 0 || (q_size
> 0 && q
)) {
355 e
= q
, q
= q
->next
, q_size
--;
357 else if (q_size
== 0 || q
== NULL
||
358 p
->commit
->commit_time
>= q
->commit
->commit_time
)
359 e
= p
, p
= p
->next
, p_size
--;
362 e
= q
, q
= q
->next
, q_size
--;
364 if (list
->tail
!= NULL
)
365 list
->tail
->next
= e
;
369 e
->prev
= list
->tail
;
376 list
->tail
->next
= NULL
;
379 } while (merge_count
> 1);
382 void git_commit_list_toposort(git_commit_list
*list
)
385 git_commit_list topo
;
386 memset(&topo
, 0x0, sizeof(git_commit_list
));
388 while ((commit
= git_commit_list_pop_back(list
)) != NULL
) {
391 if (commit
->in_degree
> 0) {
392 commit
->topo_delay
= 1;
396 for (p
= commit
->parents
.head
; p
!= NULL
; p
= p
->next
) {
397 p
->commit
->in_degree
--;
399 if (p
->commit
->in_degree
== 0 && p
->commit
->topo_delay
) {
400 p
->commit
->topo_delay
= 0;
401 git_commit_list_push_back(list
, p
->commit
);
405 git_commit_list_push_back(&topo
, commit
);
408 list
->head
= topo
.head
;
409 list
->tail
= topo
.tail
;
410 list
->size
= topo
.size
;