1#include "blame.h"
2
3void blame_origin_decref(struct blame_origin *o)
4{
5 if (o && --o->refcnt <= 0) {
6 struct blame_origin *p, *l = NULL;
7 if (o->previous)
8 blame_origin_decref(o->previous);
9 free(o->file.ptr);
10 /* Should be present exactly once in commit chain */
11 for (p = o->commit->util; p; l = p, p = p->next) {
12 if (p == o) {
13 if (l)
14 l->next = p->next;
15 else
16 o->commit->util = p->next;
17 free(o);
18 return;
19 }
20 }
21 die("internal error in blame_origin_decref");
22 }
23}
24
25/*
26 * Given a commit and a path in it, create a new origin structure.
27 * The callers that add blame to the scoreboard should use
28 * get_origin() to obtain shared, refcounted copy instead of calling
29 * this function directly.
30 */
31struct blame_origin *make_origin(struct commit *commit, const char *path)
32{
33 struct blame_origin *o;
34 FLEX_ALLOC_STR(o, path, path);
35 o->commit = commit;
36 o->refcnt = 1;
37 o->next = commit->util;
38 commit->util = o;
39 return o;
40}
41
42/*
43 * Locate an existing origin or create a new one.
44 * This moves the origin to front position in the commit util list.
45 */
46struct blame_origin *get_origin(struct commit *commit, const char *path)
47{
48 struct blame_origin *o, *l;
49
50 for (o = commit->util, l = NULL; o; l = o, o = o->next) {
51 if (!strcmp(o->path, path)) {
52 /* bump to front */
53 if (l) {
54 l->next = o->next;
55 o->next = commit->util;
56 commit->util = o;
57 }
58 return blame_origin_incref(o);
59 }
60 }
61 return make_origin(commit, path);
62}