int save_commit_buffer = 1;
const char *commit_type = "commit";
-static int commit_count;
static struct commit *check_commit(struct object *obj,
const unsigned char *sha1,
struct object *obj = lookup_object(sha1);
if (!obj) {
struct commit *c = alloc_commit_node();
- c->index = commit_count++;
return create_object(sha1, OBJ_COMMIT, c);
}
if (!obj->type)
return 0;
}
+struct commit_buffer {
+ void *buffer;
+ unsigned long size;
+};
+define_commit_slab(buffer_slab, struct commit_buffer);
+static struct buffer_slab buffer_slab = COMMIT_SLAB_INIT(1, buffer_slab);
+
+void set_commit_buffer(struct commit *commit, void *buffer, unsigned long size)
+{
+ struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
+ v->buffer = buffer;
+ v->size = size;
+}
+
+const void *get_cached_commit_buffer(const struct commit *commit, unsigned long *sizep)
+{
+ struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
+ if (sizep)
+ *sizep = v->size;
+ return v->buffer;
+}
+
+const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep)
+{
+ const void *ret = get_cached_commit_buffer(commit, sizep);
+ if (!ret) {
+ enum object_type type;
+ unsigned long size;
+ ret = read_sha1_file(commit->object.sha1, &type, &size);
+ if (!ret)
+ die("cannot read commit object %s",
+ sha1_to_hex(commit->object.sha1));
+ if (type != OBJ_COMMIT)
+ die("expected commit for %s, got %s",
+ sha1_to_hex(commit->object.sha1), typename(type));
+ if (sizep)
+ *sizep = size;
+ }
+ return ret;
+}
+
+void unuse_commit_buffer(const struct commit *commit, const void *buffer)
+{
+ struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
+ if (v->buffer != buffer)
+ free((void *)buffer);
+}
+
+void free_commit_buffer(struct commit *commit)
+{
+ struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
+ free(v->buffer);
+ v->buffer = NULL;
+ v->size = 0;
+}
+
+const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
+{
+ struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
+ void *ret;
+
+ ret = v->buffer;
+ if (sizep)
+ *sizep = v->size;
+
+ v->buffer = NULL;
+ v->size = 0;
+ return ret;
+}
+
int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size)
{
const char *tail = buffer;
}
ret = parse_commit_buffer(item, buffer, size);
if (save_commit_buffer && !ret) {
- item->buffer = buffer;
+ set_commit_buffer(item, buffer, size);
return 0;
}
free(buffer);
struct commit *commit)
{
const char *buf, *line_end, *ident_line;
- char *buffer = NULL;
+ const char *buffer = get_commit_buffer(commit, NULL);
struct ident_split ident;
char *date_end;
unsigned long date;
- if (!commit->buffer) {
- unsigned long size;
- enum object_type type;
- buffer = read_sha1_file(commit->object.sha1, &type, &size);
- if (!buffer)
- return;
- }
-
- for (buf = commit->buffer ? commit->buffer : buffer;
- buf;
- buf = line_end + 1) {
+ for (buf = buffer; buf; buf = line_end + 1) {
line_end = strchrnul(buf, '\n');
- ident_line = skip_prefix(buf, "author ");
- if (!ident_line) {
+ if (!skip_prefix(buf, "author ", &ident_line)) {
if (!line_end[0] || line_end[1] == '\n')
return; /* end of header */
continue;
*(author_date_slab_at(author_date, commit)) = date;
fail_exit:
- free(buffer);
+ unuse_commit_buffer(commit, buffer);
}
static int compare_commits_by_author_date(const void *a_, const void *b_,
static const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT);
-static struct commit *interesting(struct commit_list *list)
+static int queue_has_nonstale(struct prio_queue *queue)
{
- while (list) {
- struct commit *commit = list->item;
- list = list->next;
- if (commit->object.flags & STALE)
- continue;
- return commit;
+ int i;
+ for (i = 0; i < queue->nr; i++) {
+ struct commit *commit = queue->array[i].data;
+ if (!(commit->object.flags & STALE))
+ return 1;
}
- return NULL;
+ return 0;
}
/* all input commits in one and twos[] must have been parsed! */
static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos)
{
- struct commit_list *list = NULL;
+ struct prio_queue queue = { compare_commits_by_commit_date };
struct commit_list *result = NULL;
int i;
one->object.flags |= PARENT1;
- commit_list_insert_by_date(one, &list);
- if (!n)
- return list;
+ if (!n) {
+ commit_list_append(one, &result);
+ return result;
+ }
+ prio_queue_put(&queue, one);
+
for (i = 0; i < n; i++) {
twos[i]->object.flags |= PARENT2;
- commit_list_insert_by_date(twos[i], &list);
+ prio_queue_put(&queue, twos[i]);
}
- while (interesting(list)) {
- struct commit *commit;
+ while (queue_has_nonstale(&queue)) {
+ struct commit *commit = prio_queue_get(&queue);
struct commit_list *parents;
- struct commit_list *next;
int flags;
- commit = list->item;
- next = list->next;
- free(list);
- list = next;
-
flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
if (flags == (PARENT1 | PARENT2)) {
if (!(commit->object.flags & RESULT)) {
if (parse_commit(p))
return NULL;
p->object.flags |= flags;
- commit_list_insert_by_date(p, &list);
+ prio_queue_put(&queue, p);
}
}
- free_commit_list(list);
+ clear_prio_queue(&queue);
return result;
}
return 0;
}
-int parse_signed_commit(const unsigned char *sha1,
+int parse_signed_commit(const struct commit *commit,
struct strbuf *payload, struct strbuf *signature)
{
+
unsigned long size;
- enum object_type type;
- char *buffer = read_sha1_file(sha1, &type, &size);
+ const char *buffer = get_commit_buffer(commit, &size);
int in_signature, saw_signature = -1;
- char *line, *tail;
-
- if (!buffer || type != OBJ_COMMIT)
- goto cleanup;
+ const char *line, *tail;
line = buffer;
tail = buffer + size;
saw_signature = 0;
while (line < tail) {
const char *sig = NULL;
- char *next = memchr(line, '\n', tail - line);
+ const char *next = memchr(line, '\n', tail - line);
next = next ? next + 1 : tail;
if (in_signature && line[0] == ' ')
}
line = next;
}
- cleanup:
- free(buffer);
+ unuse_commit_buffer(commit, buffer);
return saw_signature;
}
for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) {
const char *found, *next;
- found = skip_prefix(buf, sigcheck_gpg_status[i].check + 1);
- if (!found) {
+ if (!skip_prefix(buf, sigcheck_gpg_status[i].check + 1, &found)) {
found = strstr(buf, sigcheck_gpg_status[i].check);
if (!found)
continue;
sigc->result = 'N';
- if (parse_signed_commit(commit->object.sha1,
- &payload, &signature) <= 0)
+ if (parse_signed_commit(commit, &payload, &signature) <= 0)
goto out;
status = verify_signed_buffer(payload.buf, payload.len,
signature.buf, signature.len,
&gpg_output, &gpg_status);
if (status && !gpg_output.len)
goto out;
+ sigc->payload = strbuf_detach(&payload, NULL);
sigc->gpg_output = strbuf_detach(&gpg_output, NULL);
sigc->gpg_status = strbuf_detach(&gpg_status, NULL);
parse_gpg_output(sigc);
{
struct commit_extra_header *extra = NULL;
unsigned long size;
- enum object_type type;
- char *buffer = read_sha1_file(commit->object.sha1, &type, &size);
- if (buffer && type == OBJ_COMMIT)
- extra = read_commit_extra_header_lines(buffer, size, exclude);
- free(buffer);
+ const char *buffer = get_commit_buffer(commit, &size);
+ extra = read_commit_extra_header_lines(buffer, size, exclude);
+ unuse_commit_buffer(commit, buffer);
return extra;
}
}
}
-int commit_tree(const struct strbuf *msg, const unsigned char *tree,
+int commit_tree(const char *msg, size_t msg_len,
+ const unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author, const char *sign_commit)
{
int result;
append_merge_tag_headers(parents, &tail);
- result = commit_tree_extended(msg, tree, parents, ret,
+ result = commit_tree_extended(msg, msg_len, tree, parents, ret,
author, sign_commit, extra);
free_commit_extra_headers(extra);
return result;
"You may want to amend it after fixing the message, or set the config\n"
"variable i18n.commitencoding to the encoding your project uses.\n";
-int commit_tree_extended(const struct strbuf *msg, const unsigned char *tree,
+int commit_tree_extended(const char *msg, size_t msg_len,
+ const unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author, const char *sign_commit,
struct commit_extra_header *extra)
assert_sha1_type(tree, OBJ_TREE);
- if (memchr(msg->buf, '\0', msg->len))
+ if (memchr(msg, '\0', msg_len))
return error("a NUL byte in commit log message not allowed.");
/* Not having i18n.commitencoding is the same as having utf-8 */
strbuf_addch(&buffer, '\n');
/* And add the comment */
- strbuf_addbuf(&buffer, msg);
+ strbuf_add(&buffer, msg, msg_len);
/* And check the encoding */
if (encoding_is_utf8 && !verify_utf8(&buffer))