]> git.proxmox.com Git - libgit2.git/blame - src/commit.c
Implement internal methods to write on sources
[libgit2.git] / src / commit.c
CommitLineData
06160502 1/*
50298f44
SP
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.
06160502 5 *
50298f44
SP
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.)
06160502 14 *
50298f44
SP
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.
06160502 19 *
50298f44
SP
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.
06160502
SP
24 */
25
64a47c01 26#include "common.h"
4f0adcd0 27#include "commit.h"
417f0abc
VM
28#include "revwalk.h"
29#include "git/odb.h"
3315782c 30#include "git/repository.h"
06160502 31
1f798df2 32#define COMMIT_PRINT(commit) {\
52f2390b
VM
33 char oid[41]; oid[40] = 0;\
34 git_oid_fmt(oid, &commit->object.id);\
35 printf("Oid: %s | In degree: %d | Time: %u\n", oid, commit->in_degree, commit->commit_time);\
1f798df2
VM
36}
37
3315782c
VM
38static void clear_parents(git_commit *commit)
39{
40 git_commit_parents *node, *next_node;
41
42 node = commit->parents;
43 while (node) {
44 next_node = node->next;
45 free(node);
46 node = next_node;
47 }
48
49 commit->parents = NULL;
50}
51
40721f6b
VM
52void git_commit__free(git_commit *commit)
53{
3315782c 54 clear_parents(commit);
52f2390b 55
52f2390b
VM
56 free(commit->author);
57 free(commit->committer);
58 free(commit->message);
59 free(commit->message_short);
40721f6b
VM
60 free(commit);
61}
62
6533aadc 63const git_oid *git_commit_id(git_commit *c)
06160502 64{
c5696427 65 return &c->object.id;
06160502 66}
417f0abc 67
52f2390b 68int git_commit__parse(git_commit *commit, unsigned int parse_flags, int close_db_object)
8add0153 69{
de141d4b 70 int error = 0;
8add0153 71
f49a2e49 72 if ((error = git_object__source_open((git_object *)commit)) < 0)
f2408cc2 73 return error;
8add0153 74
52f2390b 75 error = git_commit__parse_buffer(commit,
f49a2e49 76 commit->object.source.raw.data, commit->object.source.raw.len, parse_flags);
52f2390b 77
f2408cc2 78 if (close_db_object)
f49a2e49 79 git_object__source_close((git_object *)commit);
8add0153 80
de141d4b 81 return error;
8add0153
VM
82}
83
52f2390b
VM
84int git_commit__parse_basic(git_commit *commit)
85{
86 int error;
87
88 if (commit->basic_parse)
89 return 0;
90
91 error = git_commit__parse(commit,
92 (GIT_COMMIT_TREE | GIT_COMMIT_PARENTS | GIT_COMMIT_TIME), 1);
93
94 if (error < 0)
95 return error;
96
97 commit->basic_parse = 1;
98 return 0;
99}
100
3315782c 101git_commit *git_commit_lookup(git_repository *repo, const git_oid *id)
8add0153 102{
3315782c 103 return (git_commit *)git_repository_lookup(repo, id, GIT_OBJ_COMMIT);
417f0abc
VM
104}
105
364788e1 106int git__parse_person(git_person *person, char **buffer_out,
52f2390b 107 const char *buffer_end, const char *header)
417f0abc 108{
52f2390b
VM
109 const size_t header_len = strlen(header);
110
111 int i;
112 char *buffer = *buffer_out;
113 char *line_end, *name, *email;
114
115 line_end = memchr(buffer, '\n', buffer_end - buffer);
116 if (!line_end)
6bb7aa13 117 return GIT_EOBJCORRUPTED;
417f0abc 118
52f2390b 119 if (buffer + (header_len + 1) > line_end)
6bb7aa13 120 return GIT_EOBJCORRUPTED;
417f0abc 121
52f2390b 122 if (memcmp(buffer, header, header_len) != 0)
6bb7aa13 123 return GIT_EOBJCORRUPTED;
417f0abc 124
52f2390b
VM
125 buffer += header_len;
126
127
128 /* Parse name field */
129 for (i = 0, name = person->name;
130 i < 64 && buffer < line_end && *buffer != '<';
131 ++i)
132 *name++ = *buffer++;
133
134 *(name - 1) = 0;
135
136 while (buffer < line_end && *buffer != '<')
137 buffer++;
138
139 if (++buffer >= line_end)
6bb7aa13 140 return GIT_EOBJCORRUPTED;
417f0abc 141
52f2390b
VM
142 /* Parse email field */
143 for (i = 0, email = person->email;
144 i < 64 && buffer < line_end && *buffer != '>';
145 ++i)
146 *email++ = *buffer++;
147
148 *email = 0;
149
150 while (buffer < line_end && *buffer != '>')
151 buffer++;
417f0abc 152
52f2390b 153 if (++buffer >= line_end)
6bb7aa13 154 return GIT_EOBJCORRUPTED;
69dca959 155
52f2390b
VM
156 person->time = strtol(buffer, &buffer, 10);
157
158 if (person->time == 0)
6bb7aa13 159 return GIT_EOBJCORRUPTED;
69dca959 160
52f2390b
VM
161 *buffer_out = (line_end + 1);
162 return 0;
417f0abc
VM
163}
164
364788e1 165int git__parse_oid(git_oid *oid, char **buffer_out,
52f2390b 166 const char *buffer_end, const char *header)
417f0abc 167{
9b3577ed
VM
168 const size_t sha_len = GIT_OID_HEXSZ;
169 const size_t header_len = strlen(header);
417f0abc 170
9b3577ed 171 char *buffer = *buffer_out;
417f0abc 172
9b3577ed 173 if (buffer + (header_len + sha_len + 1) > buffer_end)
6bb7aa13 174 return GIT_EOBJCORRUPTED;
417f0abc 175
9b3577ed 176 if (memcmp(buffer, header, header_len) != 0)
6bb7aa13 177 return GIT_EOBJCORRUPTED;
417f0abc 178
9b3577ed 179 if (buffer[header_len + sha_len] != '\n')
6bb7aa13 180 return GIT_EOBJCORRUPTED;
417f0abc 181
9b3577ed 182 if (git_oid_mkstr(oid, buffer + header_len) < 0)
6bb7aa13 183 return GIT_EOBJCORRUPTED;
417f0abc 184
9b3577ed 185 *buffer_out = buffer + (header_len + sha_len + 1);
417f0abc 186
9b3577ed 187 return 0;
417f0abc
VM
188}
189
52f2390b 190int git_commit__parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags)
417f0abc 191{
9b3577ed
VM
192 char *buffer = (char *)data;
193 const char *buffer_end = (char *)data + len;
417f0abc 194
9b3577ed 195 git_oid oid;
364788e1 196 git_person person;
417f0abc 197
364788e1 198 if (git__parse_oid(&oid, &buffer, buffer_end, "tree ") < 0)
6bb7aa13 199 return GIT_EOBJCORRUPTED;
417f0abc 200
52f2390b 201 if (parse_flags & GIT_COMMIT_TREE)
3315782c 202 commit->tree = git_tree_lookup(commit->object.repo, &oid);
225fe215 203
9b3577ed 204 /*
9b3577ed
VM
205 * TODO: commit grafts!
206 */
417f0abc 207
52f2390b 208 if (parse_flags & GIT_COMMIT_PARENTS)
3315782c 209 clear_parents(commit);
52f2390b 210
364788e1 211 while (git__parse_oid(&oid, &buffer, buffer_end, "parent ") == 0) {
9b3577ed 212 git_commit *parent;
3315782c 213 git_commit_parents *node;
417f0abc 214
52f2390b
VM
215 if ((parse_flags & GIT_COMMIT_PARENTS) == 0)
216 continue;
217
3315782c 218 if ((parent = git_commit_lookup(commit->object.repo, &oid)) == NULL)
6bb7aa13 219 return GIT_ENOTFOUND;
417f0abc 220
3315782c 221 if ((node = git__malloc(sizeof(git_commit_parents))) == NULL)
de141d4b 222 return GIT_ENOMEM;
3315782c
VM
223
224 node->commit = parent;
225 node->next = commit->parents;
226 commit->parents = node;
9b3577ed 227 }
417f0abc 228
364788e1 229 if (git__parse_person(&person, &buffer, buffer_end, "author ") < 0)
6bb7aa13 230 return GIT_EOBJCORRUPTED;
417f0abc 231
52f2390b
VM
232 if (parse_flags & GIT_COMMIT_AUTHOR) {
233 if (commit->author)
234 free(commit->author);
235
364788e1
VM
236 commit->author = git__malloc(sizeof(git_person));
237 memcpy(commit->author, &person, sizeof(git_person));
52f2390b
VM
238 }
239
364788e1 240 if (git__parse_person(&person, &buffer, buffer_end, "committer ") < 0)
52f2390b
VM
241 return GIT_EOBJCORRUPTED;
242
243 if (parse_flags & GIT_COMMIT_TIME)
244 commit->commit_time = person.time;
245
246 if (parse_flags & GIT_COMMIT_COMMITTER) {
247 if (commit->committer)
248 free(commit->committer);
249
364788e1
VM
250 commit->committer = git__malloc(sizeof(git_person));
251 memcpy(commit->committer, &person, sizeof(git_person));
52f2390b
VM
252 }
253
254 /* parse commit message */
255 while (buffer <= buffer_end && *buffer == '\n')
256 buffer++;
257
258 if (buffer < buffer_end)
259 {
260 if (parse_flags & GIT_COMMIT_MESSAGE) {
261 size_t message_len = buffer_end - buffer;
262
263 commit->message = git__malloc(message_len + 1);
264 memcpy(commit->message, buffer, message_len);
265 commit->message[message_len] = 0;
266 }
267
268 if (parse_flags & GIT_COMMIT_MESSAGE_SHORT) {
269 char *line_end;
270 size_t message_len;
271
272 line_end = memchr(buffer, '\n', buffer_end - buffer);
273 message_len = line_end - buffer;
274
275 commit->message_short = git__malloc(message_len + 1);
276 memcpy(commit->message_short, buffer, message_len);
277 commit->message_short[message_len] = 0;
278 }
279 }
417f0abc 280
9b3577ed 281 return 0;
417f0abc 282}
4caa8962 283
52f2390b
VM
284const git_tree *git_commit_tree(git_commit *commit)
285{
286 if (commit->tree)
287 return commit->tree;
288
289 git_commit__parse(commit, GIT_COMMIT_TREE, 0);
290 return commit->tree;
291}
292
364788e1 293const git_person *git_commit_author(git_commit *commit)
52f2390b
VM
294{
295 if (commit->author)
296 return commit->author;
297
298 git_commit__parse(commit, GIT_COMMIT_AUTHOR, 0);
299 return commit->author;
300}
301
364788e1 302const git_person *git_commit_committer(git_commit *commit)
52f2390b
VM
303{
304 if (commit->committer)
305 return commit->committer;
306
307 git_commit__parse(commit, GIT_COMMIT_COMMITTER, 0);
308 return commit->committer;
309}
310
311time_t git_commit_time(git_commit *commit)
312{
313 if (commit->commit_time)
314 return commit->commit_time;
315
316 git_commit__parse(commit, GIT_COMMIT_TIME, 0);
317 return commit->commit_time;
318}
319
320const char *git_commit_message(git_commit *commit)
321{
322 if (commit->message)
323 return commit->message;
324
325 git_commit__parse(commit, GIT_COMMIT_MESSAGE, 0);
326 return commit->message;
327}
328
329const char *git_commit_message_short(git_commit *commit)
330{
331 if (commit->message_short)
332 return commit->message_short;
333
334 git_commit__parse(commit, GIT_COMMIT_MESSAGE_SHORT, 0);
335 return commit->message_short;
336}