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