mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-03 20:02:04 +00:00
217 lines
4.2 KiB
C
217 lines
4.2 KiB
C
#include "git2/patch.h"
|
|
#include "diff.h"
|
|
#include "patch.h"
|
|
|
|
|
|
int git_patch__invoke_callbacks(
|
|
git_patch *patch,
|
|
git_diff_file_cb file_cb,
|
|
git_diff_binary_cb binary_cb,
|
|
git_diff_hunk_cb hunk_cb,
|
|
git_diff_line_cb line_cb,
|
|
void *payload)
|
|
{
|
|
int error = 0;
|
|
uint32_t i, j;
|
|
|
|
if (file_cb)
|
|
error = file_cb(patch->delta, 0, payload);
|
|
|
|
if (error)
|
|
return error;
|
|
|
|
if ((patch->delta->flags & GIT_DIFF_FLAG_BINARY) != 0) {
|
|
if (binary_cb)
|
|
error = binary_cb(patch->delta, &patch->binary, payload);
|
|
|
|
return error;
|
|
}
|
|
|
|
if (!hunk_cb && !line_cb)
|
|
return error;
|
|
|
|
for (i = 0; !error && i < git_array_size(patch->hunks); ++i) {
|
|
git_patch_hunk *h = git_array_get(patch->hunks, i);
|
|
|
|
if (hunk_cb)
|
|
error = hunk_cb(patch->delta, &h->hunk, payload);
|
|
|
|
if (!line_cb)
|
|
continue;
|
|
|
|
for (j = 0; !error && j < h->line_count; ++j) {
|
|
git_diff_line *l =
|
|
git_array_get(patch->lines, h->line_start + j);
|
|
|
|
error = line_cb(patch->delta, &h->hunk, l, payload);
|
|
}
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
size_t git_patch_size(
|
|
git_patch *patch,
|
|
int include_context,
|
|
int include_hunk_headers,
|
|
int include_file_headers)
|
|
{
|
|
size_t out;
|
|
|
|
assert(patch);
|
|
|
|
out = patch->content_size;
|
|
|
|
if (!include_context)
|
|
out -= patch->context_size;
|
|
|
|
if (include_hunk_headers)
|
|
out += patch->header_size;
|
|
|
|
if (include_file_headers) {
|
|
git_buf file_header = GIT_BUF_INIT;
|
|
|
|
if (git_diff_delta__format_file_header(
|
|
&file_header, patch->delta, NULL, NULL, 0) < 0)
|
|
giterr_clear();
|
|
else
|
|
out += git_buf_len(&file_header);
|
|
|
|
git_buf_free(&file_header);
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
int git_patch_line_stats(
|
|
size_t *total_ctxt,
|
|
size_t *total_adds,
|
|
size_t *total_dels,
|
|
const git_patch *patch)
|
|
{
|
|
size_t totals[3], idx;
|
|
|
|
memset(totals, 0, sizeof(totals));
|
|
|
|
for (idx = 0; idx < git_array_size(patch->lines); ++idx) {
|
|
git_diff_line *line = git_array_get(patch->lines, idx);
|
|
if (!line)
|
|
continue;
|
|
|
|
switch (line->origin) {
|
|
case GIT_DIFF_LINE_CONTEXT: totals[0]++; break;
|
|
case GIT_DIFF_LINE_ADDITION: totals[1]++; break;
|
|
case GIT_DIFF_LINE_DELETION: totals[2]++; break;
|
|
default:
|
|
/* diff --stat and --numstat don't count EOFNL marks because
|
|
* they will always be paired with a ADDITION or DELETION line.
|
|
*/
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (total_ctxt)
|
|
*total_ctxt = totals[0];
|
|
if (total_adds)
|
|
*total_adds = totals[1];
|
|
if (total_dels)
|
|
*total_dels = totals[2];
|
|
|
|
return 0;
|
|
}
|
|
|
|
const git_diff_delta *git_patch_get_delta(const git_patch *patch)
|
|
{
|
|
assert(patch);
|
|
return patch->delta;
|
|
}
|
|
|
|
size_t git_patch_num_hunks(const git_patch *patch)
|
|
{
|
|
assert(patch);
|
|
return git_array_size(patch->hunks);
|
|
}
|
|
|
|
static int patch_error_outofrange(const char *thing)
|
|
{
|
|
giterr_set(GITERR_INVALID, "patch %s index out of range", thing);
|
|
return GIT_ENOTFOUND;
|
|
}
|
|
|
|
int git_patch_get_hunk(
|
|
const git_diff_hunk **out,
|
|
size_t *lines_in_hunk,
|
|
git_patch *patch,
|
|
size_t hunk_idx)
|
|
{
|
|
git_patch_hunk *hunk;
|
|
assert(patch);
|
|
|
|
hunk = git_array_get(patch->hunks, hunk_idx);
|
|
|
|
if (!hunk) {
|
|
if (out) *out = NULL;
|
|
if (lines_in_hunk) *lines_in_hunk = 0;
|
|
return patch_error_outofrange("hunk");
|
|
}
|
|
|
|
if (out) *out = &hunk->hunk;
|
|
if (lines_in_hunk) *lines_in_hunk = hunk->line_count;
|
|
return 0;
|
|
}
|
|
|
|
int git_patch_num_lines_in_hunk(const git_patch *patch, size_t hunk_idx)
|
|
{
|
|
git_patch_hunk *hunk;
|
|
assert(patch);
|
|
|
|
if (!(hunk = git_array_get(patch->hunks, hunk_idx)))
|
|
return patch_error_outofrange("hunk");
|
|
return (int)hunk->line_count;
|
|
}
|
|
|
|
int git_patch_get_line_in_hunk(
|
|
const git_diff_line **out,
|
|
git_patch *patch,
|
|
size_t hunk_idx,
|
|
size_t line_of_hunk)
|
|
{
|
|
git_patch_hunk *hunk;
|
|
git_diff_line *line;
|
|
|
|
assert(patch);
|
|
|
|
if (!(hunk = git_array_get(patch->hunks, hunk_idx))) {
|
|
if (out) *out = NULL;
|
|
return patch_error_outofrange("hunk");
|
|
}
|
|
|
|
if (line_of_hunk >= hunk->line_count ||
|
|
!(line = git_array_get(
|
|
patch->lines, hunk->line_start + line_of_hunk))) {
|
|
if (out) *out = NULL;
|
|
return patch_error_outofrange("line");
|
|
}
|
|
|
|
if (out) *out = line;
|
|
return 0;
|
|
}
|
|
|
|
int git_patch_from_diff(git_patch **out, git_diff *diff, size_t idx)
|
|
{
|
|
assert(out && diff && diff->patch_fn);
|
|
return diff->patch_fn(out, diff, idx);
|
|
}
|
|
|
|
static void git_patch__free(git_patch *patch)
|
|
{
|
|
if (patch->free_fn)
|
|
patch->free_fn(patch);
|
|
}
|
|
|
|
void git_patch_free(git_patch *patch)
|
|
{
|
|
if (patch)
|
|
GIT_REFCOUNT_DEC(patch, git_patch__free);
|
|
}
|