summaryrefslogtreecommitdiff
path: root/commit.c
blob: 9f0668eb68cec56a738a58fe930ae0ae2960e2b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include "commit.h"
#include "cache.h"
#include <string.h>
#include <limits.h>

const char *commit_type = "commit";

struct commit *lookup_commit(unsigned char *sha1)
{
	struct object *obj = lookup_object(sha1);
	if (!obj) {
		struct commit *ret = malloc(sizeof(struct commit));
		memset(ret, 0, sizeof(struct commit));
		created_object(sha1, &ret->object);
		return ret;
	}
	if (obj->parsed && obj->type != commit_type) {
		error("Object %s is a %s, not a commit", 
		      sha1_to_hex(sha1), obj->type);
		return NULL;
	}
	return (struct commit *) obj;
}

static unsigned long parse_commit_date(const char *buf)
{
	unsigned long date;

	if (memcmp(buf, "author", 6))
		return 0;
	while (*buf++ != '\n')
		/* nada */;
	if (memcmp(buf, "committer", 9))
		return 0;
	while (*buf++ != '>')
		/* nada */;
	date = strtoul(buf, NULL, 10);
	if (date == ULONG_MAX)
		date = 0;
	return date;
}

int parse_commit(struct commit *item)
{
	char type[20];
	void * buffer, *bufptr;
	unsigned long size;
	unsigned char parent[20];
	if (item->object.parsed)
		return 0;
	item->object.parsed = 1;
	buffer = bufptr = read_sha1_file(item->object.sha1, type, &size);
	if (!buffer)
		return error("Could not read %s",
			     sha1_to_hex(item->object.sha1));
	if (strcmp(type, commit_type))
		return error("Object %s not a commit",
			     sha1_to_hex(item->object.sha1));
	item->object.type = commit_type;
	get_sha1_hex(bufptr + 5, parent);
	item->tree = lookup_tree(parent);
	add_ref(&item->object, &item->tree->object);
	bufptr += 46; /* "tree " + "hex sha1" + "\n" */
	while (!memcmp(bufptr, "parent ", 7) &&
	       !get_sha1_hex(bufptr + 7, parent)) {
		struct commit_list *new_parent = 
			malloc(sizeof(struct commit_list));
		new_parent->next = item->parents;
		new_parent->item = lookup_commit(parent);
		add_ref(&item->object, &new_parent->item->object);
		item->parents = new_parent;
		bufptr += 48;
	}
	item->date = parse_commit_date(bufptr);
	free(buffer);
	return 0;
}

void free_commit_list(struct commit_list *list)
{
	while (list) {
		struct commit_list *temp = list;
		list = temp->next;
		free(temp);
	}
}