]>
Commit | Line | Data |
---|---|---|
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 |
38 | static 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 |
52 | void 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 | 63 | const git_oid *git_commit_id(git_commit *c) |
06160502 | 64 | { |
c5696427 | 65 | return &c->object.id; |
06160502 | 66 | } |
417f0abc | 67 | |
52f2390b | 68 | int 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 |
84 | int 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 | 101 | git_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 | 106 | int 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 | 165 | int 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 | 190 | int 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 |
284 | const 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 | 293 | const 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 | 302 | const 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 | ||
311 | time_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 | ||
320 | const 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 | ||
329 | const 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 | } |