]> git.proxmox.com Git - libgit2.git/blame - src/patch.c
Refresh patches
[libgit2.git] / src / patch.c
CommitLineData
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
13int 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
60size_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
93int 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 130const 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 136size_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 142static 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
148int 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 170int 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
180int 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
207git_repository *git_patch_owner(const git_patch *patch)
208{
209 return patch->repo;
210}
211
b859faa6
ET
212int 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 220static 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 226void git_patch_free(git_patch *patch)
d34f6826 227{
804d5fe9
ET
228 if (patch)
229 GIT_REFCOUNT_DEC(patch, git_patch__free);
d34f6826 230}