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.
33 #define COMMIT_PRINT(commit) {\
34 char oid[41]; oid[40] = 0;\
35 git_oid_fmt(oid, &commit->object.id);\
36 printf("Oid: %s | In degree: %d | Time: %u\n", oid, commit->in_degree, commit->commit_time);\
39 const git_oid
*git_commit_id(git_commit
*c
)
44 void git_commit__mark_uninteresting(git_commit
*commit
)
49 git_commit_node
*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
)
83 if (git_odb_read(&commit_obj
, commit
->object
.pool
->db
, &commit
->object
.id
) < 0)
86 if (commit_obj
.type
!= GIT_OBJ_COMMIT
)
89 if (git_commit__parse_buffer(commit
, commit_obj
.data
, commit_obj
.len
) < 0)
92 git_obj_close(&commit_obj
);
97 git_obj_close(&commit_obj
);
101 git_commit
*git_commit_lookup(git_revpool
*pool
, const git_oid
*id
)
103 git_commit
*commit
= NULL
;
108 commit
= (git_commit
*)git_revpool_table_lookup(pool
->commits
, id
);
112 commit
= git__malloc(sizeof(git_commit
));
117 memset(commit
, 0x0, sizeof(git_commit
));
119 // Initialize parent object
120 git_oid_cpy(&commit
->object
.id
, id
);
121 commit
->object
.pool
= pool
;
123 git_revpool_table_insert(pool
->commits
, (git_revpool_object
*)commit
);
128 int git_commit__parse_time(time_t *commit_time
, char *buffer
, const char *buffer_end
)
130 if (memcmp(buffer
, "author ", 7) != 0)
131 return GIT_EOBJCORRUPTED
;
133 buffer
= memchr(buffer
, '\n', buffer_end
- buffer
);
134 if (buffer
== 0 || ++buffer
>= buffer_end
)
135 return GIT_EOBJCORRUPTED
;
137 if (memcmp(buffer
, "committer ", 10) != 0)
138 return GIT_EOBJCORRUPTED
;
140 buffer
= memchr(buffer
, '>', buffer_end
- buffer
);
141 if (buffer
== 0 || ++buffer
>= buffer_end
)
142 return GIT_EOBJCORRUPTED
;
144 *commit_time
= strtol(buffer
, &buffer
, 10);
146 if (*commit_time
== 0)
147 return GIT_EOBJCORRUPTED
;
149 buffer
= memchr(buffer
, '\n', buffer_end
- buffer
);
150 if (buffer
== 0 || ++buffer
>= buffer_end
)
151 return GIT_EOBJCORRUPTED
;
153 return (buffer
< buffer_end
) ? 0 : -1;
156 int git_commit__parse_oid(git_oid
*oid
, char **buffer_out
, const char *buffer_end
, const char *header
)
158 const size_t sha_len
= GIT_OID_HEXSZ
;
159 const size_t header_len
= strlen(header
);
161 char *buffer
= *buffer_out
;
163 if (buffer
+ (header_len
+ sha_len
+ 1) > buffer_end
)
164 return GIT_EOBJCORRUPTED
;
166 if (memcmp(buffer
, header
, header_len
) != 0)
167 return GIT_EOBJCORRUPTED
;
169 if (buffer
[header_len
+ sha_len
] != '\n')
170 return GIT_EOBJCORRUPTED
;
172 if (git_oid_mkstr(oid
, buffer
+ header_len
) < 0)
173 return GIT_EOBJCORRUPTED
;
175 *buffer_out
= buffer
+ (header_len
+ sha_len
+ 1);
180 int git_commit__parse_buffer(git_commit
*commit
, void *data
, size_t len
)
182 char *buffer
= (char *)data
;
183 const char *buffer_end
= (char *)data
+ len
;
190 if (git_commit__parse_oid(&oid
, &buffer
, buffer_end
, "tree ") < 0)
191 return GIT_EOBJCORRUPTED
;
194 * TODO: load tree into commit object
195 * TODO: commit grafts!
198 while (git_commit__parse_oid(&oid
, &buffer
, buffer_end
, "parent ") == 0) {
201 if ((parent
= git_commit_lookup(commit
->object
.pool
, &oid
)) == NULL
)
202 return GIT_ENOTFOUND
;
204 // Inherit uninteresting flag
205 if (commit
->uninteresting
)
206 parent
->uninteresting
= 1;
208 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
;