2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
10 #include "git2/patch.h"
13 int git_patch__invoke_callbacks(
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
,
25 error
= file_cb(patch
->delta
, 0, payload
);
30 if ((patch
->delta
->flags
& GIT_DIFF_FLAG_BINARY
) != 0) {
32 error
= binary_cb(patch
->delta
, &patch
->binary
, payload
);
37 if (!hunk_cb
&& !line_cb
)
40 for (i
= 0; !error
&& i
< git_array_size(patch
->hunks
); ++i
) {
41 git_patch_hunk
*h
= git_array_get(patch
->hunks
, i
);
44 error
= hunk_cb(patch
->delta
, &h
->hunk
, payload
);
49 for (j
= 0; !error
&& j
< h
->line_count
; ++j
) {
51 git_array_get(patch
->lines
, h
->line_start
+ j
);
53 error
= line_cb(patch
->delta
, &h
->hunk
, l
, payload
);
60 size_t git_patch_size(
63 int include_hunk_headers
,
64 int include_file_headers
)
68 GIT_ASSERT_ARG(patch
);
70 out
= patch
->content_size
;
73 out
-= patch
->context_size
;
75 if (include_hunk_headers
)
76 out
+= patch
->header_size
;
78 if (include_file_headers
) {
79 git_str file_header
= GIT_STR_INIT
;
81 if (git_diff_delta__format_file_header(
82 &file_header
, patch
->delta
, NULL
, NULL
, 0, true) < 0)
85 out
+= git_str_len(&file_header
);
87 git_str_dispose(&file_header
);
93 int git_patch_line_stats(
97 const git_patch
*patch
)
99 size_t totals
[3], idx
;
101 memset(totals
, 0, sizeof(totals
));
103 for (idx
= 0; idx
< git_array_size(patch
->lines
); ++idx
) {
104 git_diff_line
*line
= git_array_get(patch
->lines
, idx
);
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;
113 /* diff --stat and --numstat don't count EOFNL marks because
114 * they will always be paired with a ADDITION or DELETION line.
121 *total_ctxt
= totals
[0];
123 *total_adds
= totals
[1];
125 *total_dels
= totals
[2];
130 const git_diff_delta
*git_patch_get_delta(const git_patch
*patch
)
132 GIT_ASSERT_ARG_WITH_RETVAL(patch
, NULL
);
136 size_t git_patch_num_hunks(const git_patch
*patch
)
138 GIT_ASSERT_ARG(patch
);
139 return git_array_size(patch
->hunks
);
142 static int patch_error_outofrange(const char *thing
)
144 git_error_set(GIT_ERROR_INVALID
, "patch %s index out of range", thing
);
145 return GIT_ENOTFOUND
;
148 int git_patch_get_hunk(
149 const git_diff_hunk
**out
,
150 size_t *lines_in_hunk
,
154 git_patch_hunk
*hunk
;
155 GIT_ASSERT_ARG(patch
);
157 hunk
= git_array_get(patch
->hunks
, hunk_idx
);
160 if (out
) *out
= NULL
;
161 if (lines_in_hunk
) *lines_in_hunk
= 0;
162 return patch_error_outofrange("hunk");
165 if (out
) *out
= &hunk
->hunk
;
166 if (lines_in_hunk
) *lines_in_hunk
= hunk
->line_count
;
170 int git_patch_num_lines_in_hunk(const git_patch
*patch
, size_t hunk_idx
)
172 git_patch_hunk
*hunk
;
173 GIT_ASSERT_ARG(patch
);
175 if (!(hunk
= git_array_get(patch
->hunks
, hunk_idx
)))
176 return patch_error_outofrange("hunk");
177 return (int)hunk
->line_count
;
180 int git_patch_get_line_in_hunk(
181 const git_diff_line
**out
,
186 git_patch_hunk
*hunk
;
189 GIT_ASSERT_ARG(patch
);
191 if (!(hunk
= git_array_get(patch
->hunks
, hunk_idx
))) {
192 if (out
) *out
= NULL
;
193 return patch_error_outofrange("hunk");
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");
203 if (out
) *out
= line
;
207 git_repository
*git_patch_owner(const git_patch
*patch
)
212 int git_patch_from_diff(git_patch
**out
, git_diff
*diff
, size_t idx
)
215 GIT_ASSERT_ARG(diff
);
216 GIT_ASSERT_ARG(diff
->patch_fn
);
217 return diff
->patch_fn(out
, diff
, idx
);
220 static void git_patch__free(git_patch
*patch
)
223 patch
->free_fn(patch
);
226 void git_patch_free(git_patch
*patch
)
229 GIT_REFCOUNT_DEC(patch
, git_patch__free
);