File Coverage

deps/libgit2/src/libgit2/patch.c
Criterion Covered Total %
statement 64 106 60.3
branch 44 106 41.5
condition n/a
subroutine n/a
pod n/a
total 108 212 50.9


line stmt bran cond sub pod time code
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 "patch.h"
9              
10             #include "git2/patch.h"
11             #include "diff.h"
12              
13 42           int git_patch__invoke_callbacks(
14             git_patch *patch,
15             git_diff_file_cb file_cb,
16             git_diff_binary_cb binary_cb,
17             git_diff_hunk_cb hunk_cb,
18             git_diff_line_cb line_cb,
19             void *payload)
20             {
21 42           int error = 0;
22             uint32_t i, j;
23              
24 42 50         if (file_cb)
25 42           error = file_cb(patch->delta, 0, payload);
26              
27 42 100         if (error)
28 1           return error;
29              
30 41 100         if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) != 0) {
31 1 50         if (binary_cb)
32 1           error = binary_cb(patch->delta, &patch->binary, payload);
33              
34 1           return error;
35             }
36              
37 40 100         if (!hunk_cb && !line_cb)
    100          
38 20           return error;
39              
40 39 50         for (i = 0; !error && i < git_array_size(patch->hunks); ++i) {
    100          
41 19 50         git_patch_hunk *h = git_array_get(patch->hunks, i);
42              
43 19 100         if (hunk_cb)
44 17           error = hunk_cb(patch->delta, &h->hunk, payload);
45              
46 19 50         if (!line_cb)
47 0           continue;
48              
49 57 50         for (j = 0; !error && j < h->line_count; ++j) {
    100          
50 38           git_diff_line *l =
51 38 50         git_array_get(patch->lines, h->line_start + j);
52              
53 38           error = line_cb(patch->delta, &h->hunk, l, payload);
54             }
55             }
56              
57 20           return error;
58             }
59              
60 0           size_t git_patch_size(
61             git_patch *patch,
62             int include_context,
63             int include_hunk_headers,
64             int include_file_headers)
65             {
66             size_t out;
67              
68 0 0         GIT_ASSERT_ARG(patch);
69              
70 0           out = patch->content_size;
71              
72 0 0         if (!include_context)
73 0           out -= patch->context_size;
74              
75 0 0         if (include_hunk_headers)
76 0           out += patch->header_size;
77              
78 0 0         if (include_file_headers) {
79 0           git_str file_header = GIT_STR_INIT;
80              
81 0 0         if (git_diff_delta__format_file_header(
82 0           &file_header, patch->delta, NULL, NULL, 0, true) < 0)
83 0           git_error_clear();
84             else
85 0           out += git_str_len(&file_header);
86              
87 0           git_str_dispose(&file_header);
88             }
89              
90 0           return out;
91             }
92              
93 8           int git_patch_line_stats(
94             size_t *total_ctxt,
95             size_t *total_adds,
96             size_t *total_dels,
97             const git_patch *patch)
98             {
99             size_t totals[3], idx;
100              
101 8           memset(totals, 0, sizeof(totals));
102              
103 18 100         for (idx = 0; idx < git_array_size(patch->lines); ++idx) {
104 10 50         git_diff_line *line = git_array_get(patch->lines, idx);
105 10 50         if (!line)
106 0           continue;
107              
108 10           switch (line->origin) {
109 0           case GIT_DIFF_LINE_CONTEXT: totals[0]++; break;
110 6           case GIT_DIFF_LINE_ADDITION: totals[1]++; break;
111 1           case GIT_DIFF_LINE_DELETION: totals[2]++; break;
112             default:
113             /* diff --stat and --numstat don't count EOFNL marks because
114             * they will always be paired with a ADDITION or DELETION line.
115             */
116 3           break;
117             }
118             }
119              
120 8 100         if (total_ctxt)
121 2           *total_ctxt = totals[0];
122 8 50         if (total_adds)
123 8           *total_adds = totals[1];
124 8 50         if (total_dels)
125 8           *total_dels = totals[2];
126              
127 8           return 0;
128             }
129              
130 3           const git_diff_delta *git_patch_get_delta(const git_patch *patch)
131             {
132 3 50         GIT_ASSERT_ARG_WITH_RETVAL(patch, NULL);
133 3           return patch->delta;
134             }
135              
136 10           size_t git_patch_num_hunks(const git_patch *patch)
137             {
138 10 50         GIT_ASSERT_ARG(patch);
139 10           return git_array_size(patch->hunks);
140             }
141              
142 0           static int patch_error_outofrange(const char *thing)
143             {
144 0           git_error_set(GIT_ERROR_INVALID, "patch %s index out of range", thing);
145 0           return GIT_ENOTFOUND;
146             }
147              
148 4           int git_patch_get_hunk(
149             const git_diff_hunk **out,
150             size_t *lines_in_hunk,
151             git_patch *patch,
152             size_t hunk_idx)
153             {
154             git_patch_hunk *hunk;
155 4 50         GIT_ASSERT_ARG(patch);
156              
157 4 50         hunk = git_array_get(patch->hunks, hunk_idx);
158              
159 4 50         if (!hunk) {
160 0 0         if (out) *out = NULL;
161 0 0         if (lines_in_hunk) *lines_in_hunk = 0;
162 0           return patch_error_outofrange("hunk");
163             }
164              
165 4 50         if (out) *out = &hunk->hunk;
166 4 50         if (lines_in_hunk) *lines_in_hunk = hunk->line_count;
167 4           return 0;
168             }
169              
170 0           int git_patch_num_lines_in_hunk(const git_patch *patch, size_t hunk_idx)
171             {
172             git_patch_hunk *hunk;
173 0 0         GIT_ASSERT_ARG(patch);
174              
175 0 0         if (!(hunk = git_array_get(patch->hunks, hunk_idx)))
    0          
176 0           return patch_error_outofrange("hunk");
177 0           return (int)hunk->line_count;
178             }
179              
180 0           int git_patch_get_line_in_hunk(
181             const git_diff_line **out,
182             git_patch *patch,
183             size_t hunk_idx,
184             size_t line_of_hunk)
185             {
186             git_patch_hunk *hunk;
187             git_diff_line *line;
188              
189 0 0         GIT_ASSERT_ARG(patch);
190              
191 0 0         if (!(hunk = git_array_get(patch->hunks, hunk_idx))) {
    0          
192 0 0         if (out) *out = NULL;
193 0           return patch_error_outofrange("hunk");
194             }
195              
196 0 0         if (line_of_hunk >= hunk->line_count ||
    0          
197 0 0         !(line = git_array_get(
198             patch->lines, hunk->line_start + line_of_hunk))) {
199 0 0         if (out) *out = NULL;
200 0           return patch_error_outofrange("line");
201             }
202              
203 0 0         if (out) *out = line;
204 0           return 0;
205             }
206              
207 0           git_repository *git_patch_owner(const git_patch *patch)
208             {
209 0           return patch->repo;
210             }
211              
212 51           int git_patch_from_diff(git_patch **out, git_diff *diff, size_t idx)
213             {
214 51 50         GIT_ASSERT_ARG(out);
215 51 50         GIT_ASSERT_ARG(diff);
216 51 50         GIT_ASSERT_ARG(diff->patch_fn);
217 51           return diff->patch_fn(out, diff, idx);
218             }
219              
220 52           static void git_patch__free(git_patch *patch)
221             {
222 52 50         if (patch->free_fn)
223 52           patch->free_fn(patch);
224 52           }
225              
226 54           void git_patch_free(git_patch *patch)
227             {
228 54 50         if (patch)
229 54 100         GIT_REFCOUNT_DEC(patch, git_patch__free);
    50          
230 54           }