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 const git_oid
*git_commit_id(git_commit
*c
)
38 void git_commit__mark_uninteresting(git_commit
*commit
)
43 git_commit_node
*parents
= commit
->parents
.head
;
45 commit
->uninteresting
= 1;
49 parents
->commit
->uninteresting
= 1;
50 parents
= parents
->next
;
54 git_commit
*git_commit_parse(git_revpool
*pool
, const git_oid
*id
)
56 git_commit
*commit
= NULL
;
58 if ((commit
= git_commit_lookup(pool
, id
)) == NULL
)
61 if (git_commit_parse_existing(commit
) < 0)
71 int git_commit_parse_existing(git_commit
*commit
)
78 if (git_odb_read(&commit_obj
, commit
->object
.pool
->db
, &commit
->object
.id
) < 0)
81 if (commit_obj
.type
!= GIT_OBJ_COMMIT
)
84 if (git_commit__parse_buffer(commit
, commit_obj
.data
, commit_obj
.len
) < 0)
87 git_obj_close(&commit_obj
);
92 git_obj_close(&commit_obj
);
96 git_commit
*git_commit_lookup(git_revpool
*pool
, const git_oid
*id
)
98 git_commit
*commit
= NULL
;
103 commit
= (git_commit
*)git_revpool_table_lookup(pool
->commits
, id
);
107 commit
= git__malloc(sizeof(git_commit
));
112 memset(commit
, 0x0, sizeof(git_commit
));
114 // Initialize parent object
115 git_oid_cpy(&commit
->object
.id
, id
);
116 commit
->object
.pool
= pool
;
118 git_revpool_table_insert(pool
->commits
, (git_revpool_object
*)commit
);
123 int git_commit__parse_time(time_t *commit_time
, char *buffer
, const char *buffer_end
)
125 if (memcmp(buffer
, "author ", 7) != 0)
128 buffer
= memchr(buffer
, '\n', buffer_end
- buffer
);
129 if (buffer
== 0 || ++buffer
>= buffer_end
)
132 if (memcmp(buffer
, "committer ", 10) != 0)
135 buffer
= memchr(buffer
, '\n', buffer_end
- buffer
);
136 if (buffer
== 0 || ++buffer
>= buffer_end
)
139 *commit_time
= strtol(buffer
, &buffer
, 10);
141 return (buffer
< buffer_end
) ? 0 : -1;
144 int git_commit__parse_oid(git_oid
*oid
, char **buffer_out
, const char *buffer_end
, const char *header
)
146 const size_t sha_len
= GIT_OID_HEXSZ
;
147 const size_t header_len
= strlen(header
);
149 char *buffer
= *buffer_out
;
151 if (buffer
+ (header_len
+ sha_len
+ 1) > buffer_end
)
154 if (memcmp(buffer
, header
, header_len
) != 0)
157 if (buffer
[header_len
+ sha_len
] != '\n')
160 if (git_oid_mkstr(oid
, buffer
+ header_len
) < 0)
163 *buffer_out
= buffer
+ (header_len
+ sha_len
+ 1);
168 int git_commit__parse_buffer(git_commit
*commit
, void *data
, size_t len
)
170 char *buffer
= (char *)data
;
171 const char *buffer_end
= (char *)data
+ len
;
178 if (git_commit__parse_oid(&oid
, &buffer
, buffer_end
, "tree ") < 0)
182 * TODO: load tree into commit object
183 * TODO: commit grafts!
186 while (git_commit__parse_oid(&oid
, &buffer
, buffer_end
, "parent ") == 0) {
189 if ((parent
= git_commit_lookup(commit
->object
.pool
, &oid
)) == NULL
)
192 // Inherit uninteresting flag
193 if (commit
->uninteresting
)
194 parent
->uninteresting
= 1;
196 git_commit_list_push_back(&commit
->parents
, parent
);
199 if (git_commit__parse_time(&commit
->commit_time
, buffer
, buffer_end
) < 0)
207 void git_commit_list_push_back(git_commit_list
*list
, git_commit
*commit
)
209 git_commit_node
*node
= NULL
;
211 node
= git__malloc(sizeof(git_commit_list
));
216 node
->commit
= commit
;
218 node
->prev
= list
->tail
;
220 if (list
->tail
== NULL
)
222 list
->head
= list
->tail
= node
;
226 list
->tail
->next
= node
;
233 void git_commit_list_push_front(git_commit_list
*list
, git_commit
*commit
)
235 git_commit_node
*node
= NULL
;
237 node
= git__malloc(sizeof(git_commit_list
));
242 node
->commit
= commit
;
243 node
->next
= list
->head
;
246 if (list
->head
== NULL
)
248 list
->head
= list
->tail
= node
;
252 list
->head
->next
= node
;
260 git_commit
*git_commit_list_pop_back(git_commit_list
*list
)
262 git_commit_node
*node
;
265 if (list
->tail
== NULL
)
269 list
->tail
= list
->tail
->prev
;
270 if (list
->tail
== NULL
)
273 commit
= node
->commit
;
281 git_commit
*git_commit_list_pop_front(git_commit_list
*list
)
283 git_commit_node
*node
;
286 if (list
->head
== NULL
)
290 list
->head
= list
->head
->next
;
291 if (list
->head
== NULL
)
294 commit
= node
->commit
;
302 void git_commit_list_clear(git_commit_list
*list
, int free_commits
)
304 git_commit_node
*node
, *next_node
;
312 next_node
= node
->next
;
317 list
->head
= list
->tail
= NULL
;
321 void git_commit_list_timesort(git_commit_list
*list
)
323 git_commit_node
*p
, *q
, *e
;
324 int in_size
, p_size
, q_size
, merge_count
, i
;
326 if (list
->head
== NULL
)
344 for (i
= 0; i
< in_size
&& q
; ++i
, q
= q
->next
)
347 while (p_size
> 0 || (q_size
> 0 && q
))
350 e
= q
, q
= q
->next
, q_size
--;
352 else if (q_size
== 0 || q
== NULL
||
353 p
->commit
->commit_time
>= q
->commit
->commit_time
)
354 e
= p
, p
= p
->next
, p_size
--;
357 e
= q
, q
= q
->next
, q_size
--;
359 if (list
->tail
!= NULL
)
360 list
->tail
->next
= e
;
370 list
->tail
->next
= NULL
;
373 } while (merge_count
> 1);
376 void git_commit_list_toposort(git_commit_list
*list
)
379 git_commit_list topo
;
380 memset(&topo
, 0x0, sizeof(git_commit_list
));
382 while ((commit
= git_commit_list_pop_front(list
)) != NULL
)
386 if (commit
->in_degree
> 0)
388 commit
->topo_delay
= 1;
392 for (p
= commit
->parents
.head
; p
!= NULL
; p
= p
->next
)
394 p
->commit
->in_degree
--;
396 if (p
->commit
->in_degree
== 0 && p
->commit
->topo_delay
)
398 p
->commit
->topo_delay
= 0;
399 git_commit_list_push_front(list
, p
->commit
);
403 git_commit_list_push_back(&topo
, commit
);
406 list
->head
= topo
.head
;
407 list
->tail
= topo
.tail
;
408 list
->size
= topo
.size
;