Line Flow Count Block(s) Source
1 - /*
2 - * Copyright (C) the libgit2 contributors. All rights reserved.
3 - *
4 - * This file is part of libgit2, distributed under the GNU GPL v2 with
5 - * a Linking Exception. For full terms see the included COPYING file.
6 - */
7 -
8 - #include "blame_git.h"
9 -
10 - #include "commit.h"
11 - #include "blob.h"
12 - #include "xdiff/xinclude.h"
13 - #include "diff_xdiff.h"
14 -
15 - /*
16 - * Origin is refcounted and usually we keep the blob contents to be
17 - * reused.
18 - */
19 33695 2 static git_blame__origin *origin_incref(git_blame__origin *o)
20 - {
21 33695 2 if (o)
22 33695 3 o->refcnt++;
23 33695 4 return o;
24 - }
25 -
26 38956 2 static void origin_decref(git_blame__origin *o)
27 - {
28 38956 2,3 if (o && --o->refcnt <= 0) {
29 3386 4 if (o->previous)
30 172 5 origin_decref(o->previous);
31 3386 6 git_blob_free(o->blob);
32 3386 7 git_commit_free(o->commit);
33 3386 8 git__free(o);
34 - }
35 38956 9 }
36 -
37 - /* Given a commit and a path in it, create a new origin structure. */
38 3393 2 static int make_origin(git_blame__origin **out, git_commit *commit, const char *path)
39 - {
40 - git_blame__origin *o;
41 - git_object *blob;
42 3393 2 size_t path_len = strlen(path), alloc_len;
43 3393 2 int error = 0;
44 -
45 3393 2,3 if ((error = git_object_lookup_bypath(&blob, (git_object*)commit,
46 - path, GIT_OBJECT_BLOB)) < 0)
47 7 4 return error;
48 -
49 3386 5-11 GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, sizeof(*o), path_len);
50 3386 12-18 GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1);
51 3386 19 o = git__calloc(1, alloc_len);
52 3386 20,21 GIT_ERROR_CHECK_ALLOC(o);
53 -
54 3386 22 o->commit = commit;
55 3386 22 o->blob = (git_blob *) blob;
56 3386 22 o->refcnt = 1;
57 3386 22 strcpy(o->path, path);
58 -
59 3386 22 *out = o;
60 -
61 3386 22 return 0;
62 - }
63 -
64 - /* Locate an existing origin or create a new one. */
65 3143 2 int git_blame__get_origin(
66 - git_blame__origin **out,
67 - git_blame *blame,
68 - git_commit *commit,
69 - const char *path)
70 - {
71 - git_blame__entry *e;
72 -
73 85947 2,7,8 for (e = blame->ent; e; e = e->next) {
74 82804 3,4 if (e->suspect->commit == commit && !strcmp(e->suspect->path, path)) {
75 ##### 5,6 *out = origin_incref(e->suspect);
76 - }
77 - }
78 3143 9 return make_origin(out, commit, path);
79 - }
80 -
81 - typedef struct blame_chunk_cb_data {
82 - git_blame *blame;
83 - git_blame__origin *target;
84 - git_blame__origin *parent;
85 - long tlno;
86 - long plno;
87 - }blame_chunk_cb_data;
88 -
89 175619 2 static bool same_suspect(git_blame__origin *a, git_blame__origin *b)
90 - {
91 175619 2 if (a == b)
92 31002 3 return true;
93 144617 4-7 if (git_oid_cmp(git_commit_id(a->commit), git_commit_id(b->commit)))
94 144617 8 return false;
95 ##### 9 return 0 == strcmp(a->path, b->path);
96 - }
97 -
98 - /* find the line number of the last line the target is suspected for */
99 199 2 static bool find_last_in_target(size_t *out, git_blame *blame, git_blame__origin *target)
100 - {
101 - git_blame__entry *e;
102 199 2 size_t last_in_target = 0;
103 199 2 bool found = false;
104 -
105 199 2 *out = 0;
106 -
107 4034 2,9,10 for (e=blame->ent; e; e=e->next) {
108 3835 3-5 if (e->guilty || !same_suspect(e->suspect, target))
109 2816 6 continue;
110 1019 7 if (last_in_target < e->s_lno + e->num_lines) {
111 1019 8 found = true;
112 1019 8 last_in_target = e->s_lno + e->num_lines;
113 - }
114 - }
115 -
116 199 11 *out = last_in_target;
117 199 11 return found;
118 - }
119 -
120 - /*
121 - * It is known that lines between tlno to same came from parent, and e
122 - * has an overlap with that range. it also is known that parent's
123 - * line plno corresponds to e's line tlno.
124 - *
125 - * <---- e ----->
126 - * <------> (entirely within)
127 - * <------------> (extends past)
128 - * <------------> (starts before)
129 - * <------------------> (entirely encloses)
130 - *
131 - * Split e into potentially three parts; before this chunk, the chunk
132 - * to be blamed for the parent, and after that portion.
133 - */
134 1013 2 static void split_overlap(git_blame__entry *split, git_blame__entry *e,
135 - size_t tlno, size_t plno, size_t same, git_blame__origin *parent)
136 - {
137 - size_t chunk_end_lno;
138 -
139 1013 2 if (e->s_lno < tlno) {
140 - /* there is a pre-chunk part not blamed on the parent */
141 47 3 split[0].suspect = origin_incref(e->suspect);
142 47 4 split[0].lno = e->lno;
143 47 4 split[0].s_lno = e->s_lno;
144 47 4 split[0].num_lines = tlno - e->s_lno;
145 47 4 split[1].lno = e->lno + tlno - e->s_lno;
146 47 4 split[1].s_lno = plno;
147 - } else {
148 966 5 split[1].lno = e->lno;
149 966 5 split[1].s_lno = plno + (e->s_lno - tlno);
150 - }
151 -
152 1013 6 if (same < e->s_lno + e->num_lines) {
153 - /* there is a post-chunk part not blamed on parent */
154 104 7 split[2].suspect = origin_incref(e->suspect);
155 104 8 split[2].lno = e->lno + (same - e->s_lno);
156 104 8 split[2].s_lno = e->s_lno + (same - e->s_lno);
157 104 8 split[2].num_lines = e->s_lno + e->num_lines - same;
158 104 8 chunk_end_lno = split[2].lno;
159 - } else {
160 909 9 chunk_end_lno = e->lno + e->num_lines;
161 - }
162 1013 10 split[1].num_lines = chunk_end_lno - split[1].lno;
163 -
164 - /*
165 - * if it turns out there is nothing to blame the parent for, forget about
166 - * the splitting. !split[1].suspect signals this.
167 - */
168 1013 10 if (split[1].num_lines < 1)
169 1013 11,14 return;
170 1013 12 split[1].suspect = origin_incref(parent);
171 - }
172 -
173 - /*
174 - * Link in a new blame entry to the scoreboard. Entries that cover the same
175 - * line range have been removed from the scoreboard previously.
176 - */
177 151 2 static void add_blame_entry(git_blame *blame, git_blame__entry *e)
178 - {
179 151 2 git_blame__entry *ent, *prev = NULL;
180 -
181 151 2 origin_incref(e->suspect);
182 -
183 1244 3-6 for (ent = blame->ent; ent && ent->lno < e->lno; ent = ent->next)
184 1093 4 prev = ent;
185 -
186 - /* prev, if not NULL, is the last one that is below e */
187 151 7 e->prev = prev;
188 151 7 if (prev) {
189 151 8 e->next = prev->next;
190 151 8 prev->next = e;
191 - } else {
192 ##### 9 e->next = blame->ent;
193 ##### 9 blame->ent = e;
194 - }
195 151 10 if (e->next)
196 116 11 e->next->prev = e;
197 151 12 }
198 -
199 - /*
200 - * src typically is on-stack; we want to copy the information in it to
201 - * a malloced blame_entry that is already on the linked list of the scoreboard.
202 - * The origin of dst loses a refcnt while the origin of src gains one.
203 - */
204 1013 2 static void dup_entry(git_blame__entry *dst, git_blame__entry *src)
205 - {
206 - git_blame__entry *p, *n;
207 -
208 1013 2 p = dst->prev;
209 1013 2 n = dst->next;
210 1013 2 origin_incref(src->suspect);
211 1013 3 origin_decref(dst->suspect);
212 1013 4 memcpy(dst, src, sizeof(*src));
213 1013 4 dst->prev = p;
214 1013 4 dst->next = n;
215 1013 4 dst->score = 0;
216 1013 4 }
217 -
218 - /*
219 - * split_overlap() divided an existing blame e into up to three parts in split.
220 - * Adjust the linked list of blames in the scoreboard to reflect the split.
221 - */
222 1013 2 static int split_blame(git_blame *blame, git_blame__entry *split, git_blame__entry *e)
223 - {
224 - git_blame__entry *new_entry;
225 -
226 1013 2,3 if (split[0].suspect && split[2].suspect) {
227 - /* The first part (reuse storage for the existing entry e */
228 4 4 dup_entry(e, &split[0]);
229 -
230 - /* The last part -- me */
231 4 5 new_entry = git__malloc(sizeof(*new_entry));
232 4 6,7 GIT_ERROR_CHECK_ALLOC(new_entry);
233 4 8 memcpy(new_entry, &(split[2]), sizeof(git_blame__entry));
234 4 8 add_blame_entry(blame, new_entry);
235 -
236 - /* ... and the middle part -- parent */
237 4 9 new_entry = git__malloc(sizeof(*new_entry));
238 4 10,11 GIT_ERROR_CHECK_ALLOC(new_entry);
239 4 12 memcpy(new_entry, &(split[1]), sizeof(git_blame__entry));
240 4 12 add_blame_entry(blame, new_entry);
241 1009 13,14 } else if (!split[0].suspect && !split[2].suspect) {
242 - /*
243 - * The parent covers the entire area; reuse storage for e and replace it
244 - * with the parent
245 - */
246 866 15 dup_entry(e, &split[1]);
247 143 16 } else if (split[0].suspect) {
248 - /* me and then parent */
249 43 17 dup_entry(e, &split[0]);
250 43 18 new_entry = git__malloc(sizeof(*new_entry));
251 43 19,20 GIT_ERROR_CHECK_ALLOC(new_entry);
252 43 21 memcpy(new_entry, &(split[1]), sizeof(git_blame__entry));
253 43 21 add_blame_entry(blame, new_entry);
254 - } else {
255 - /* parent and then me */
256 100 22 dup_entry(e, &split[1]);
257 100 23 new_entry = git__malloc(sizeof(*new_entry));
258 100 24,25 GIT_ERROR_CHECK_ALLOC(new_entry);
259 100 26 memcpy(new_entry, &(split[2]), sizeof(git_blame__entry));
260 100 26 add_blame_entry(blame, new_entry);
261 - }
262 -
263 1013 27 return 0;
264 - }
265 -
266 - /*
267 - * After splitting the blame, the origins used by the on-stack blame_entry
268 - * should lose one refcnt each.
269 - */
270 1013 2 static void decref_split(git_blame__entry *split)
271 - {
272 - int i;
273 4052 2,4,5 for (i=0; i<3; i++)
274 3039 3 origin_decref(split[i].suspect);
275 1013 6 }
276 -
277 - /*
278 - * Helper for blame_chunk(). blame_entry e is known to overlap with the patch
279 - * hunk; split it and pass blame to the parent.
280 - */
281 1013 2 static int blame_overlap(
282 - git_blame *blame,
283 - git_blame__entry *e,
284 - size_t tlno,
285 - size_t plno,
286 - size_t same,
287 - git_blame__origin *parent)
288 - {
289 1013 2 git_blame__entry split[3] = {{0}};
290 -
291 1013 2 split_overlap(split, e, tlno, plno, same, parent);
292 1013 3 if (split[1].suspect)
293 1013 4,5 if (split_blame(blame, split, e) < 0)
294 ##### 6 return -1;
295 1013 7 decref_split(split);
296 -
297 1013 8 return 0;
298 - }
299 -
300 - /*
301 - * Process one hunk from the patch between the current suspect for blame_entry
302 - * e and its parent. Find and split the overlap, and pass blame to the
303 - * overlapping part to the parent.
304 - */
305 407 2 static int blame_chunk(
306 - git_blame *blame,
307 - size_t tlno,
308 - size_t plno,
309 - size_t same,
310 - git_blame__origin *target,
311 - git_blame__origin *parent)
312 - {
313 - git_blame__entry *e;
314 -
315 9001 2,13,14 for (e = blame->ent; e; e = e->next) {
316 8594 3-5 if (e->guilty || !same_suspect(e->suspect, target))
317 6663 6 continue;
318 1931 7 if (same <= e->s_lno)
319 762 8 continue;
320 1169 9 if (tlno < e->s_lno + e->num_lines) {
321 1013 10,11 if (blame_overlap(blame, e, tlno, plno, same, parent) < 0)
322 ##### 12 return -1;
323 - }
324 - }
325 -
326 407 15 return 0;
327 - }
328 -
329 216 2 static int my_emit(
330 - long start_a, long count_a,
331 - long start_b, long count_b,
332 - void *cb_data)
333 - {
334 216 2 blame_chunk_cb_data *d = (blame_chunk_cb_data *)cb_data;
335 -
336 216 2,3 if (blame_chunk(d->blame, d->tlno, d->plno, start_b, d->target, d->parent) < 0)
337 ##### 4 return -1;
338 216 5 d->plno = start_a + count_a;
339 216 5 d->tlno = start_b + count_b;
340 -
341 216 5 return 0;
342 - }
343 -
344 191 2 static void trim_common_tail(mmfile_t *a, mmfile_t *b, long ctx)
345 - {
346 191 2 const int blk = 1024;
347 191 2 long trimmed = 0, recovered = 0;
348 191 2 char *ap = a->ptr + a->size;
349 191 2 char *bp = b->ptr + b->size;
350 191 2 long smaller = (long)((a->size < b->size) ? a->size : b->size);
351 -
352 191 2 if (ctx)
353 191 3,13 return;
354 -
355 193 4,6,7 while (blk + trimmed <= smaller && !memcmp(ap - blk, bp - blk, blk)) {
356 2 5 trimmed += blk;
357 2 5 ap -= blk;
358 2 5 bp -= blk;
359 - }
360 -
361 231 8,11 while (recovered < trimmed)
362 42 9 if (ap[recovered++] == '\n')
363 2 10 break;
364 191 12 a->size -= trimmed - recovered;
365 191 12 b->size -= trimmed - recovered;
366 - }
367 -
368 191 2 static int diff_hunks(mmfile_t file_a, mmfile_t file_b, void *cb_data, git_blame_options *options)
369 - {
370 191 2 xdemitconf_t xecfg = {0};
371 191 2 xdemitcb_t ecb = {0};
372 191 2 xpparam_t xpp = {0};
373 -
374 191 2 if (options->flags & GIT_BLAME_IGNORE_WHITESPACE)
375 3 3 xpp.flags |= XDF_IGNORE_WHITESPACE;
376 -
377 191 4 xecfg.hunk_func = my_emit;
378 191 4 ecb.priv = cb_data;
379 -
380 191 4 trim_common_tail(&file_a, &file_b, 0);
381 -
382 191 5,6 if (file_a.size > GIT_XDIFF_MAX_SIZE ||
383 191 6 file_b.size > GIT_XDIFF_MAX_SIZE) {
384 ##### 7 git_error_set(GIT_ERROR_INVALID, "file too large to blame");
385 ##### 8 return -1;
386 - }
387 -
388 191 9 return xdl_diff(&file_a, &file_b, &xpp, &xecfg, &ecb);
389 - }
390 -
391 382 2 static void fill_origin_blob(git_blame__origin *o, mmfile_t *file)
392 - {
393 382 2 memset(file, 0, sizeof(*file));
394 382 2 if (o->blob) {
395 382 3 file->ptr = (char*)git_blob_rawcontent(o->blob);
396 382 4 file->size = (size_t)git_blob_rawsize(o->blob);
397 - }
398 382 6 }
399 -
400 199 2 static int pass_blame_to_parent(
401 - git_blame *blame,
402 - git_blame__origin *target,
403 - git_blame__origin *parent)
404 - {
405 - size_t last_in_target;
406 - mmfile_t file_p, file_o;
407 199 2 blame_chunk_cb_data d = { blame, target, parent, 0, 0 };
408 -
409 199 2,3 if (!find_last_in_target(&last_in_target, blame, target))
410 8 4 return 1; /* nothing remains for this target */
411 -
412 191 5 fill_origin_blob(parent, &file_p);
413 191 6 fill_origin_blob(target, &file_o);
414 -
415 191 7,8 if (diff_hunks(file_p, file_o, &d, &blame->options) < 0)
416 ##### 9 return -1;
417 -
418 - /* The reset (i.e. anything after tlno) are the same as the parent */
419 191 10,11 if (blame_chunk(blame, d.tlno, d.plno, last_in_target, target, parent) < 0)
420 ##### 12 return -1;
421 -
422 191 13 return 0;
423 - }
424 -
425 246 2 static int paths_on_dup(void **old, void *new)
426 - {
427 - GIT_UNUSED(old);
428 246 2 git__free(new);
429 246 3 return -1;
430 - }
431 -
432 3371 2 static git_blame__origin* find_origin(
433 - git_blame *blame,
434 - git_commit *parent,
435 - git_blame__origin *origin)
436 - {
437 3371 2 git_blame__origin *porigin = NULL;
438 3371 2 git_diff *difflist = NULL;
439 3371 2 git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT;
440 3371 2 git_tree *otree=NULL, *ptree=NULL;
441 -
442 - /* Get the trees from this commit and its parent */
443 3371 2,3,5 if (0 != git_commit_tree(&otree, origin->commit) ||
444 3371 4 0 != git_commit_tree(&ptree, parent))
445 - goto cleanup;
446 -
447 - /* Configure the diff */
448 3371 6 diffopts.context_lines = 0;
449 3371 6 diffopts.flags = GIT_DIFF_SKIP_BINARY_CHECK;
450 -
451 - /* Check to see if files we're interested have changed */
452 3371 6 diffopts.pathspec.count = blame->paths.length;
453 3371 6 diffopts.pathspec.strings = (char**)blame->paths.contents;
454 3371 6,7 if (0 != git_diff_tree_to_tree(&difflist, blame->repository, ptree, otree, &diffopts))
455 ##### 8 goto cleanup;
456 -
457 3371 9,10 if (!git_diff_num_deltas(difflist)) {
458 - /* No changes; copy data */
459 3121 11 git_blame__get_origin(&porigin, blame, parent, origin->path);
460 - } else {
461 250 12 git_diff_find_options findopts = GIT_DIFF_FIND_OPTIONS_INIT;
462 - int i;
463 -
464 - /* Generate a full diff between the two trees */
465 250 12 git_diff_free(difflist);
466 250 13 diffopts.pathspec.count = 0;
467 250 13,14 if (0 != git_diff_tree_to_tree(&difflist, blame->repository, ptree, otree, &diffopts))
468 ##### 15,30 goto cleanup;
469 -
470 - /* Let diff find renames */
471 250 16 findopts.flags = GIT_DIFF_FIND_RENAMES;
472 250 16,17 if (0 != git_diff_find_similar(difflist, &findopts))
473 ##### 18 goto cleanup;
474 -
475 - /* Find one that matches */
476 6882 19,26-29 for (i=0; i<(int)git_diff_num_deltas(difflist); i++) {
477 6632 20 const git_diff_delta *delta = git_diff_get_delta(difflist, i);
478 -
479 6632 21,22 if (!git_vector_bsearch(NULL, &blame->paths, delta->new_file.path))
480 - {
481 250 23,24 git_vector_insert_sorted(&blame->paths, (void*)git__strdup(delta->old_file.path),
482 - paths_on_dup);
483 250 25 make_origin(&porigin, parent, delta->old_file.path);
484 - }
485 - }
486 - }
487 -
488 - cleanup:
489 3371 31 git_diff_free(difflist);
490 3371 32 git_tree_free(otree);
491 3371 33 git_tree_free(ptree);
492 3371 34 return porigin;
493 - }
494 -
495 - /*
496 - * The blobs of origin and porigin exactly match, so everything origin is
497 - * suspected for can be blamed on the parent.
498 - */
499 3123 2 static int pass_whole_blame(git_blame *blame,
500 - git_blame__origin *origin, git_blame__origin *porigin)
501 - {
502 - git_blame__entry *e;
503 -
504 3123 2,5 if (!porigin->blob &&
505 ##### 3,4 git_object_lookup((git_object**)&porigin->blob, blame->repository,
506 ##### 3 git_blob_id(origin->blob), GIT_OBJECT_BLOB) < 0)
507 ##### 6 return -1;
508 86007 7,14,15 for (e=blame->ent; e; e=e->next) {
509 82884 8,9 if (!same_suspect(e->suspect, origin))
510 55005 10 continue;
511 27879 11 origin_incref(porigin);
512 27879 12 origin_decref(e->suspect);
513 27879 13 e->suspect = porigin;
514 - }
515 -
516 3123 16 return 0;
517 - }
518 -
519 3316 2 static int pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt)
520 - {
521 3316 2 git_commit *commit = origin->commit;
522 - int i, num_parents;
523 - git_blame__origin *sg_buf[16];
524 3316 2 git_blame__origin *porigin, **sg_origin = sg_buf;
525 3316 2 int ret, error = 0;
526 -
527 3316 2 num_parents = git_commit_parentcount(commit);
528 3316 3-5 if (!git_oid_cmp(git_commit_id(commit), &blame->options.oldest_commit))
529 - /* Stop at oldest specified commit */
530 1 6 num_parents = 0;
531 3315 7,8 else if (opt & GIT_BLAME_FIRST_PARENT && num_parents > 1)
532 - /* Limit search to the first parent */
533 1 9 num_parents = 1;
534 -
535 3316 10 if (!num_parents) {
536 15 11,12 git_oid_cpy(&blame->options.oldest_commit, git_commit_id(commit));
537 15 13 goto finish;
538 3301 14 } else if (num_parents < (int)ARRAY_SIZE(sg_buf))
539 3301 15 memset(sg_buf, 0, sizeof(sg_buf));
540 - else {
541 ##### 16 sg_origin = git__calloc(num_parents, sizeof(*sg_origin));
542 ##### 17,18 GIT_ERROR_CHECK_ALLOC(sg_origin);
543 - }
544 -
545 3549 19,53,54 for (i=0; i<num_parents; i++) {
546 - git_commit *p;
547 - int j, same;
548 -
549 3371 20 if (sg_origin[i])
550 7 21,50 continue;
551 -
552 3371 22,23 if ((error = git_commit_parent(&p, origin->commit, i)) < 0)
553 3123 24,52 goto finish;
554 3371 25 porigin = find_origin(blame, p, origin);
555 -
556 3371 26 if (!porigin) {
557 - /*
558 - * We only have to decrement the parent's
559 - * reference count when no porigin has
560 - * been created, as otherwise the commit
561 - * is assigned to the created object.
562 - */
563 7 27 git_commit_free(p);
564 7 28 continue;
565 - }
566 3364 29,30,34 if (porigin->blob && origin->blob &&
567 3364 31-33 !git_oid_cmp(git_blob_id(porigin->blob), git_blob_id(origin->blob))) {
568 3123 35 error = pass_whole_blame(blame, origin, porigin);
569 3123 36 origin_decref(porigin);
570 3123 51 goto finish;
571 - }
572 268 37,44,45 for (j = same = 0; j<i; j++)
573 27 38,42 if (sg_origin[j] &&
574 27 39-41 !git_oid_cmp(git_blob_id(sg_origin[j]->blob), git_blob_id(porigin->blob))) {
575 ##### 43 same = 1;
576 ##### 43 break;
577 - }
578 241 46 if (!same)
579 241 47 sg_origin[i] = porigin;
580 - else
581 241 48,49 origin_decref(porigin);
582 - }
583 -
584 - /* Standard blame */
585 375 55,66,67 for (i=0; i<num_parents; i++) {
586 205 56 git_blame__origin *porigin = sg_origin[i];
587 205 56 if (!porigin)
588 6 57 continue;
589 199 58 if (!origin->previous) {
590 172 59 origin_incref(porigin);
591 172 60 origin->previous = porigin;
592 - }
593 -
594 199 61,62 if ((ret = pass_blame_to_parent(blame, origin, porigin)) != 0) {
595 8 63 if (ret < 0)
596 ##### 64 error = -1;
597 -
598 8 65 goto finish;
599 - }
600 - }
601 -
602 - /* TODO: optionally find moves in parents' files */
603 -
604 - /* TODO: optionally find copies in parents' files */
605 -
606 - finish:
607 7623 68,71,72 for (i=0; i<num_parents; i++)
608 4307 69 if (sg_origin[i])
609 241 70 origin_decref(sg_origin[i]);
610 3316 73 if (sg_origin != sg_buf)
611 ##### 74 git__free(sg_origin);
612 3316 75 return error;
613 - }
614 -
615 - /*
616 - * If two blame entries that are next to each other came from
617 - * contiguous lines in the same origin (i.e. <commit, path> pair),
618 - * merge them together.
619 - */
620 22 2 static void coalesce(git_blame *blame)
621 - {
622 - git_blame__entry *ent, *next;
623 -
624 173 2,12-14 for (ent=blame->ent; ent && (next = ent->next); ent = next) {
625 151 3-5 if (same_suspect(ent->suspect, next->suspect) &&
626 ##### 5,6 ent->guilty == next->guilty &&
627 ##### 6 ent->s_lno + ent->num_lines == next->s_lno)
628 - {
629 ##### 7 ent->num_lines += next->num_lines;
630 ##### 7 ent->next = next->next;
631 ##### 7 if (ent->next)
632 ##### 8 ent->next->prev = ent;
633 ##### 9 origin_decref(next->suspect);
634 ##### 10 git__free(next);
635 ##### 11 ent->score = 0;
636 ##### 11 next = ent; /* again */
637 - }
638 - }
639 22 15 }
640 -
641 22 2 int git_blame__like_git(git_blame *blame, uint32_t opt)
642 - {
643 22 2 int error = 0;
644 -
645 - while (true) {
646 - git_blame__entry *ent;
647 3338 3 git_blame__origin *suspect = NULL;
648 -
649 - /* Find a suspect to break down */
650 8789 3,6-8 for (ent = blame->ent; !suspect && ent; ent = ent->next)
651 5451 4 if (!ent->guilty)
652 3316 5 suspect = ent->suspect;
653 3338 9 if (!suspect)
654 22 10 break;
655 -
656 - /* We'll use this suspect later in the loop, so hold on to it for now. */
657 3316 11 origin_incref(suspect);
658 -
659 3316 12,13 if ((error = pass_blame(blame, suspect, opt)) < 0)
660 ##### 14 break;
661 -
662 - /* Take responsibility for the remaining entries */
663 89945 15,21,22 for (ent = blame->ent; ent; ent = ent->next) {
664 86629 16,17 if (same_suspect(ent->suspect, suspect)) {
665 173 18 ent->guilty = true;
666 173 18-20 ent->is_boundary = !git_oid_cmp(
667 173 18 git_commit_id(suspect->commit),
668 173 18 &blame->options.oldest_commit);
669 - }
670 - }
671 3316 23 origin_decref(suspect);
672 3316 24 }
673 -
674 22 25 if (!error)
675 22 26 coalesce(blame);
676 -
677 22 27 return error;
678 - }
679 -
680 173 2 void git_blame__free_entry(git_blame__entry *ent)
681 - {
682 173 2,3,6 if (!ent) return;
683 173 4 origin_decref(ent->suspect);
684 173 5 git__free(ent);
685 - }