source src/patch.c
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 "patch.h" | ||
9 | - | |||
10 | - | #include "git2/patch.h" | ||
11 | - | #include "diff.h" | ||
12 | - | |||
13 | 912 | 2 | 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 | 912 | 2 | int error = 0; | |
22 | - | uint32_t i, j; | ||
23 | - | |||
24 | 912 | 2 | if (file_cb) | |
25 | 912 | 3 | error = file_cb(patch->delta, 0, payload); | |
26 | - | |||
27 | 912 | 4 | if (error) | |
28 | 5 | 5 | return error; | |
29 | - | |||
30 | 907 | 6 | if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) != 0) { | |
31 | 40 | 7 | if (binary_cb) | |
32 | 40 | 8 | error = binary_cb(patch->delta, &patch->binary, payload); | |
33 | - | |||
34 | 40 | 9 | return error; | |
35 | - | } | ||
36 | - | |||
37 | 867 | 10,11 | if (!hunk_cb && !line_cb) | |
38 | 181 | 12 | return error; | |
39 | - | |||
40 | 1269 | 13,29-31 | for (i = 0; !error && i < git_array_size(patch->hunks); ++i) { | |
41 | 583 | 14-16 | git_patch_hunk *h = git_array_get(patch->hunks, i); | |
42 | - | |||
43 | 583 | 17 | if (hunk_cb) | |
44 | 567 | 18 | error = hunk_cb(patch->delta, &h->hunk, payload); | |
45 | - | |||
46 | 583 | 19 | if (!line_cb) | |
47 | ##### | 20 | continue; | |
48 | - | |||
49 | 7363 | 21,26-28 | for (j = 0; !error && j < h->line_count; ++j) { | |
50 | 6780 | 25 | git_diff_line *l = | |
51 | 6780 | 22-24 | git_array_get(patch->lines, h->line_start + j); | |
52 | - | |||
53 | 6780 | 25 | error = line_cb(patch->delta, &h->hunk, l, payload); | |
54 | - | } | ||
55 | - | } | ||
56 | - | |||
57 | 686 | 32 | return error; | |
58 | - | } | ||
59 | - | |||
60 | 8 | 2 | 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 | 8 | 2,3 | assert(patch); | |
69 | - | |||
70 | 8 | 4 | out = patch->content_size; | |
71 | - | |||
72 | 8 | 4 | if (!include_context) | |
73 | 2 | 5 | out -= patch->context_size; | |
74 | - | |||
75 | 8 | 6 | if (include_hunk_headers) | |
76 | 4 | 7 | out += patch->header_size; | |
77 | - | |||
78 | 8 | 8 | if (include_file_headers) { | |
79 | 2 | 9 | git_buf file_header = GIT_BUF_INIT; | |
80 | - | |||
81 | 2 | 9,10 | if (git_diff_delta__format_file_header( | |
82 | 2 | 9 | &file_header, patch->delta, NULL, NULL, 0, true) < 0) | |
83 | ##### | 11 | git_error_clear(); | |
84 | - | else | ||
85 | 2 | 12,13 | out += git_buf_len(&file_header); | |
86 | - | |||
87 | 2 | 14,15 | git_buf_dispose(&file_header); | |
88 | - | } | ||
89 | - | |||
90 | 8 | 16 | return out; | |
91 | - | } | ||
92 | - | |||
93 | 58 | 2 | 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 | 58 | 2 | memset(totals, 0, sizeof(totals)); | |
102 | - | |||
103 | 553 | 2,13,14 | for (idx = 0; idx < git_array_size(patch->lines); ++idx) { | |
104 | 495 | 3-5 | git_diff_line *line = git_array_get(patch->lines, idx); | |
105 | 495 | 6 | if (!line) | |
106 | ##### | 7 | continue; | |
107 | - | |||
108 | 495 | 8 | switch (line->origin) { | |
109 | 192 | 9 | case GIT_DIFF_LINE_CONTEXT: totals[0]++; break; | |
110 | 184 | 10 | case GIT_DIFF_LINE_ADDITION: totals[1]++; break; | |
111 | 116 | 11 | 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 | 12 | break; | |
117 | - | } | ||
118 | - | } | ||
119 | - | |||
120 | 58 | 15 | if (total_ctxt) | |
121 | 9 | 16 | *total_ctxt = totals[0]; | |
122 | 58 | 17 | if (total_adds) | |
123 | 58 | 18 | *total_adds = totals[1]; | |
124 | 58 | 19 | if (total_dels) | |
125 | 58 | 20 | *total_dels = totals[2]; | |
126 | - | |||
127 | 58 | 21 | return 0; | |
128 | - | } | ||
129 | - | |||
130 | 373 | 2 | const git_diff_delta *git_patch_get_delta(const git_patch *patch) | |
131 | - | { | ||
132 | 373 | 2,3 | assert(patch); | |
133 | 373 | 4 | return patch->delta; | |
134 | - | } | ||
135 | - | |||
136 | 170 | 2 | size_t git_patch_num_hunks(const git_patch *patch) | |
137 | - | { | ||
138 | 170 | 2,3 | assert(patch); | |
139 | 170 | 4 | return git_array_size(patch->hunks); | |
140 | - | } | ||
141 | - | |||
142 | 34 | 2 | static int patch_error_outofrange(const char *thing) | |
143 | - | { | ||
144 | 34 | 2 | git_error_set(GIT_ERROR_INVALID, "patch %s index out of range", thing); | |
145 | 34 | 3 | return GIT_ENOTFOUND; | |
146 | - | } | ||
147 | - | |||
148 | 106 | 2 | 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 | 106 | 2,3 | assert(patch); | |
156 | - | |||
157 | 106 | 4-6 | hunk = git_array_get(patch->hunks, hunk_idx); | |
158 | - | |||
159 | 106 | 7 | if (!hunk) { | |
160 | 8 | 8,9 | if (out) *out = NULL; | |
161 | 8 | 10,11 | if (lines_in_hunk) *lines_in_hunk = 0; | |
162 | 8 | 12 | return patch_error_outofrange("hunk"); | |
163 | - | } | ||
164 | - | |||
165 | 98 | 13,14 | if (out) *out = &hunk->hunk; | |
166 | 98 | 15,16 | if (lines_in_hunk) *lines_in_hunk = hunk->line_count; | |
167 | 98 | 17 | return 0; | |
168 | - | } | ||
169 | - | |||
170 | 29 | 2 | int git_patch_num_lines_in_hunk(const git_patch *patch, size_t hunk_idx) | |
171 | - | { | ||
172 | - | git_patch_hunk *hunk; | ||
173 | 29 | 2,3 | assert(patch); | |
174 | - | |||
175 | 29 | 4-7 | if (!(hunk = git_array_get(patch->hunks, hunk_idx))) | |
176 | ##### | 8 | return patch_error_outofrange("hunk"); | |
177 | 29 | 9 | return (int)hunk->line_count; | |
178 | - | } | ||
179 | - | |||
180 | 380 | 2 | 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 | 380 | 2,3 | assert(patch); | |
190 | - | |||
191 | 380 | 4-7 | if (!(hunk = git_array_get(patch->hunks, hunk_idx))) { | |
192 | ##### | 8,9 | if (out) *out = NULL; | |
193 | ##### | 10 | return patch_error_outofrange("hunk"); | |
194 | - | } | ||
195 | - | |||
196 | 380 | 11,15 | if (line_of_hunk >= hunk->line_count || | |
197 | 354 | 12-14 | !(line = git_array_get( | |
198 | - | patch->lines, hunk->line_start + line_of_hunk))) { | ||
199 | 26 | 16,17 | if (out) *out = NULL; | |
200 | 26 | 18 | return patch_error_outofrange("line"); | |
201 | - | } | ||
202 | - | |||
203 | 354 | 19,20 | if (out) *out = line; | |
204 | 354 | 21 | return 0; | |
205 | - | } | ||
206 | - | |||
207 | 1243 | 2 | int git_patch_from_diff(git_patch **out, git_diff *diff, size_t idx) | |
208 | - | { | ||
209 | 1243 | 2-5 | assert(out && diff && diff->patch_fn); | |
210 | 1243 | 6 | return diff->patch_fn(out, diff, idx); | |
211 | - | } | ||
212 | - | |||
213 | 1486 | 2 | static void git_patch__free(git_patch *patch) | |
214 | - | { | ||
215 | 1486 | 2 | if (patch->free_fn) | |
216 | 1484 | 3 | patch->free_fn(patch); | |
217 | 1486 | 4 | } | |
218 | - | |||
219 | 1597 | 2 | void git_patch_free(git_patch *patch) | |
220 | - | { | ||
221 | 1597 | 2 | if (patch) | |
222 | 1596 | 3-6 | GIT_REFCOUNT_DEC(patch, git_patch__free); | |
223 | 1597 | 7 | } |