mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-03 17:57:25 +00:00

Now that `git_diff_delta` data can be produced by reading patch file data, which may have an abbreviated oid, allow consumers to know that the id is abbreviated.
656 lines
16 KiB
C
656 lines
16 KiB
C
/*
|
|
* Copyright (C) the libgit2 contributors. All rights reserved.
|
|
*
|
|
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
|
* a Linking Exception. For full terms see the included COPYING file.
|
|
*/
|
|
#include "common.h"
|
|
#include "diff.h"
|
|
#include "diff_file.h"
|
|
#include "patch_diff.h"
|
|
#include "fileops.h"
|
|
#include "zstream.h"
|
|
#include "blob.h"
|
|
#include "delta.h"
|
|
#include "git2/sys/diff.h"
|
|
|
|
typedef struct {
|
|
git_diff_format_t format;
|
|
git_diff_line_cb print_cb;
|
|
void *payload;
|
|
|
|
git_buf *buf;
|
|
git_diff_line line;
|
|
|
|
const char *old_prefix;
|
|
const char *new_prefix;
|
|
uint32_t flags;
|
|
int oid_strlen;
|
|
|
|
int (*strcomp)(const char *, const char *);
|
|
} diff_print_info;
|
|
|
|
static int diff_print_info_init__common(
|
|
diff_print_info *pi,
|
|
git_buf *out,
|
|
git_repository *repo,
|
|
git_diff_format_t format,
|
|
git_diff_line_cb cb,
|
|
void *payload)
|
|
{
|
|
pi->format = format;
|
|
pi->print_cb = cb;
|
|
pi->payload = payload;
|
|
pi->buf = out;
|
|
|
|
if (!pi->oid_strlen) {
|
|
if (!repo)
|
|
pi->oid_strlen = GIT_ABBREV_DEFAULT;
|
|
else if (git_repository__cvar(&pi->oid_strlen, repo, GIT_CVAR_ABBREV) < 0)
|
|
return -1;
|
|
}
|
|
|
|
pi->oid_strlen += 1; /* for NUL byte */
|
|
|
|
if (pi->oid_strlen > GIT_OID_HEXSZ + 1)
|
|
pi->oid_strlen = GIT_OID_HEXSZ + 1;
|
|
|
|
memset(&pi->line, 0, sizeof(pi->line));
|
|
pi->line.old_lineno = -1;
|
|
pi->line.new_lineno = -1;
|
|
pi->line.num_lines = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int diff_print_info_init_fromdiff(
|
|
diff_print_info *pi,
|
|
git_buf *out,
|
|
git_diff *diff,
|
|
git_diff_format_t format,
|
|
git_diff_line_cb cb,
|
|
void *payload)
|
|
{
|
|
git_repository *repo = diff ? diff->repo : NULL;
|
|
|
|
memset(pi, 0, sizeof(diff_print_info));
|
|
|
|
if (diff) {
|
|
pi->flags = diff->opts.flags;
|
|
pi->oid_strlen = diff->opts.id_abbrev;
|
|
pi->old_prefix = diff->opts.old_prefix;
|
|
pi->new_prefix = diff->opts.new_prefix;
|
|
|
|
pi->strcomp = diff->strcomp;
|
|
}
|
|
|
|
return diff_print_info_init__common(pi, out, repo, format, cb, payload);
|
|
}
|
|
|
|
static int diff_print_info_init_frompatch(
|
|
diff_print_info *pi,
|
|
git_buf *out,
|
|
git_patch *patch,
|
|
git_diff_format_t format,
|
|
git_diff_line_cb cb,
|
|
void *payload)
|
|
{
|
|
assert(patch);
|
|
|
|
memset(pi, 0, sizeof(diff_print_info));
|
|
|
|
pi->flags = patch->diff_opts.flags;
|
|
pi->oid_strlen = patch->diff_opts.id_abbrev;
|
|
pi->old_prefix = patch->diff_opts.old_prefix;
|
|
pi->new_prefix = patch->diff_opts.new_prefix;
|
|
|
|
return diff_print_info_init__common(pi, out, patch->repo, format, cb, payload);
|
|
}
|
|
|
|
static char diff_pick_suffix(int mode)
|
|
{
|
|
if (S_ISDIR(mode))
|
|
return '/';
|
|
else if (GIT_PERMS_IS_EXEC(mode)) /* -V536 */
|
|
/* in git, modes are very regular, so we must have 0100755 mode */
|
|
return '*';
|
|
else
|
|
return ' ';
|
|
}
|
|
|
|
char git_diff_status_char(git_delta_t status)
|
|
{
|
|
char code;
|
|
|
|
switch (status) {
|
|
case GIT_DELTA_ADDED: code = 'A'; break;
|
|
case GIT_DELTA_DELETED: code = 'D'; break;
|
|
case GIT_DELTA_MODIFIED: code = 'M'; break;
|
|
case GIT_DELTA_RENAMED: code = 'R'; break;
|
|
case GIT_DELTA_COPIED: code = 'C'; break;
|
|
case GIT_DELTA_IGNORED: code = 'I'; break;
|
|
case GIT_DELTA_UNTRACKED: code = '?'; break;
|
|
case GIT_DELTA_UNREADABLE: code = 'X'; break;
|
|
default: code = ' '; break;
|
|
}
|
|
|
|
return code;
|
|
}
|
|
|
|
static int diff_print_one_name_only(
|
|
const git_diff_delta *delta, float progress, void *data)
|
|
{
|
|
diff_print_info *pi = data;
|
|
git_buf *out = pi->buf;
|
|
|
|
GIT_UNUSED(progress);
|
|
|
|
if ((pi->flags & GIT_DIFF_SHOW_UNMODIFIED) == 0 &&
|
|
delta->status == GIT_DELTA_UNMODIFIED)
|
|
return 0;
|
|
|
|
git_buf_clear(out);
|
|
git_buf_puts(out, delta->new_file.path);
|
|
git_buf_putc(out, '\n');
|
|
if (git_buf_oom(out))
|
|
return -1;
|
|
|
|
pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
|
|
pi->line.content = git_buf_cstr(out);
|
|
pi->line.content_len = git_buf_len(out);
|
|
|
|
return pi->print_cb(delta, NULL, &pi->line, pi->payload);
|
|
}
|
|
|
|
static int diff_print_one_name_status(
|
|
const git_diff_delta *delta, float progress, void *data)
|
|
{
|
|
diff_print_info *pi = data;
|
|
git_buf *out = pi->buf;
|
|
char old_suffix, new_suffix, code = git_diff_status_char(delta->status);
|
|
int(*strcomp)(const char *, const char *) = pi->strcomp ?
|
|
pi->strcomp : git__strcmp;
|
|
|
|
GIT_UNUSED(progress);
|
|
|
|
if ((pi->flags & GIT_DIFF_SHOW_UNMODIFIED) == 0 && code == ' ')
|
|
return 0;
|
|
|
|
old_suffix = diff_pick_suffix(delta->old_file.mode);
|
|
new_suffix = diff_pick_suffix(delta->new_file.mode);
|
|
|
|
git_buf_clear(out);
|
|
|
|
if (delta->old_file.path != delta->new_file.path &&
|
|
strcomp(delta->old_file.path,delta->new_file.path) != 0)
|
|
git_buf_printf(out, "%c\t%s%c %s%c\n", code,
|
|
delta->old_file.path, old_suffix, delta->new_file.path, new_suffix);
|
|
else if (delta->old_file.mode != delta->new_file.mode &&
|
|
delta->old_file.mode != 0 && delta->new_file.mode != 0)
|
|
git_buf_printf(out, "%c\t%s%c %s%c\n", code,
|
|
delta->old_file.path, old_suffix, delta->new_file.path, new_suffix);
|
|
else if (old_suffix != ' ')
|
|
git_buf_printf(out, "%c\t%s%c\n", code, delta->old_file.path, old_suffix);
|
|
else
|
|
git_buf_printf(out, "%c\t%s\n", code, delta->old_file.path);
|
|
if (git_buf_oom(out))
|
|
return -1;
|
|
|
|
pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
|
|
pi->line.content = git_buf_cstr(out);
|
|
pi->line.content_len = git_buf_len(out);
|
|
|
|
return pi->print_cb(delta, NULL, &pi->line, pi->payload);
|
|
}
|
|
|
|
static int diff_print_one_raw(
|
|
const git_diff_delta *delta, float progress, void *data)
|
|
{
|
|
diff_print_info *pi = data;
|
|
git_buf *out = pi->buf;
|
|
int id_abbrev;
|
|
char code = git_diff_status_char(delta->status);
|
|
char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1];
|
|
|
|
GIT_UNUSED(progress);
|
|
|
|
if ((pi->flags & GIT_DIFF_SHOW_UNMODIFIED) == 0 && code == ' ')
|
|
return 0;
|
|
|
|
git_buf_clear(out);
|
|
|
|
id_abbrev = delta->old_file.mode ? delta->old_file.id_abbrev :
|
|
delta->new_file.id_abbrev;
|
|
|
|
if (pi->oid_strlen - 1 > id_abbrev) {
|
|
giterr_set(GITERR_PATCH,
|
|
"The patch input contains %d id characters (cannot print %d)",
|
|
id_abbrev, pi->oid_strlen);
|
|
return -1;
|
|
}
|
|
|
|
git_oid_tostr(start_oid, pi->oid_strlen, &delta->old_file.id);
|
|
git_oid_tostr(end_oid, pi->oid_strlen, &delta->new_file.id);
|
|
|
|
git_buf_printf(
|
|
out, (pi->oid_strlen <= GIT_OID_HEXSZ) ?
|
|
":%06o %06o %s... %s... %c" : ":%06o %06o %s %s %c",
|
|
delta->old_file.mode, delta->new_file.mode, start_oid, end_oid, code);
|
|
|
|
if (delta->similarity > 0)
|
|
git_buf_printf(out, "%03u", delta->similarity);
|
|
|
|
if (delta->old_file.path != delta->new_file.path)
|
|
git_buf_printf(
|
|
out, "\t%s %s\n", delta->old_file.path, delta->new_file.path);
|
|
else
|
|
git_buf_printf(
|
|
out, "\t%s\n", delta->old_file.path ?
|
|
delta->old_file.path : delta->new_file.path);
|
|
|
|
if (git_buf_oom(out))
|
|
return -1;
|
|
|
|
pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
|
|
pi->line.content = git_buf_cstr(out);
|
|
pi->line.content_len = git_buf_len(out);
|
|
|
|
return pi->print_cb(delta, NULL, &pi->line, pi->payload);
|
|
}
|
|
|
|
static int diff_print_oid_range(
|
|
git_buf *out, const git_diff_delta *delta, int oid_strlen)
|
|
{
|
|
char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1];
|
|
|
|
if (delta->old_file.mode &&
|
|
oid_strlen - 1 > delta->old_file.id_abbrev) {
|
|
giterr_set(GITERR_PATCH,
|
|
"The patch input contains %d id characters (cannot print %d)",
|
|
delta->old_file.id_abbrev, oid_strlen);
|
|
return -1;
|
|
}
|
|
|
|
if ((delta->new_file.mode &&
|
|
oid_strlen - 1 > delta->new_file.id_abbrev)) {
|
|
giterr_set(GITERR_PATCH,
|
|
"The patch input contains %d id characters (cannot print %d)",
|
|
delta->new_file.id_abbrev, oid_strlen);
|
|
return -1;
|
|
}
|
|
|
|
git_oid_tostr(start_oid, oid_strlen, &delta->old_file.id);
|
|
git_oid_tostr(end_oid, oid_strlen, &delta->new_file.id);
|
|
|
|
/* TODO: Match git diff more closely */
|
|
if (delta->old_file.mode == delta->new_file.mode) {
|
|
git_buf_printf(out, "index %s..%s %o\n",
|
|
start_oid, end_oid, delta->old_file.mode);
|
|
} else {
|
|
if (delta->old_file.mode == 0) {
|
|
git_buf_printf(out, "new file mode %o\n", delta->new_file.mode);
|
|
} else if (delta->new_file.mode == 0) {
|
|
git_buf_printf(out, "deleted file mode %o\n", delta->old_file.mode);
|
|
} else {
|
|
git_buf_printf(out, "old mode %o\n", delta->old_file.mode);
|
|
git_buf_printf(out, "new mode %o\n", delta->new_file.mode);
|
|
}
|
|
git_buf_printf(out, "index %s..%s\n", start_oid, end_oid);
|
|
}
|
|
|
|
return git_buf_oom(out) ? -1 : 0;
|
|
}
|
|
|
|
static int diff_delta_format_with_paths(
|
|
git_buf *out,
|
|
const git_diff_delta *delta,
|
|
const char *oldpfx,
|
|
const char *newpfx,
|
|
const char *template)
|
|
{
|
|
const char *oldpath = delta->old_file.path;
|
|
const char *newpath = delta->new_file.path;
|
|
|
|
if (git_oid_iszero(&delta->old_file.id)) {
|
|
oldpfx = "";
|
|
oldpath = "/dev/null";
|
|
}
|
|
if (git_oid_iszero(&delta->new_file.id)) {
|
|
newpfx = "";
|
|
newpath = "/dev/null";
|
|
}
|
|
|
|
return git_buf_printf(out, template, oldpfx, oldpath, newpfx, newpath);
|
|
}
|
|
|
|
int git_diff_delta__format_file_header(
|
|
git_buf *out,
|
|
const git_diff_delta *delta,
|
|
const char *oldpfx,
|
|
const char *newpfx,
|
|
int oid_strlen)
|
|
{
|
|
if (!oldpfx)
|
|
oldpfx = DIFF_OLD_PREFIX_DEFAULT;
|
|
if (!newpfx)
|
|
newpfx = DIFF_NEW_PREFIX_DEFAULT;
|
|
if (!oid_strlen)
|
|
oid_strlen = GIT_ABBREV_DEFAULT + 1;
|
|
|
|
git_buf_clear(out);
|
|
|
|
git_buf_printf(out, "diff --git %s%s %s%s\n",
|
|
oldpfx, delta->old_file.path, newpfx, delta->new_file.path);
|
|
|
|
GITERR_CHECK_ERROR(diff_print_oid_range(out, delta, oid_strlen));
|
|
|
|
if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0)
|
|
diff_delta_format_with_paths(
|
|
out, delta, oldpfx, newpfx, "--- %s%s\n+++ %s%s\n");
|
|
|
|
return git_buf_oom(out) ? -1 : 0;
|
|
}
|
|
|
|
static int format_binary(
|
|
diff_print_info *pi,
|
|
git_diff_binary_t type,
|
|
const char *data,
|
|
size_t datalen,
|
|
size_t inflatedlen)
|
|
{
|
|
const char *typename = type == GIT_DIFF_BINARY_DELTA ?
|
|
"delta" : "literal";
|
|
const char *scan, *end;
|
|
|
|
git_buf_printf(pi->buf, "%s %" PRIuZ "\n", typename, inflatedlen);
|
|
pi->line.num_lines++;
|
|
|
|
for (scan = data, end = data + datalen; scan < end; ) {
|
|
size_t chunk_len = end - scan;
|
|
if (chunk_len > 52)
|
|
chunk_len = 52;
|
|
|
|
if (chunk_len <= 26)
|
|
git_buf_putc(pi->buf, (char)chunk_len + 'A' - 1);
|
|
else
|
|
git_buf_putc(pi->buf, (char)chunk_len - 26 + 'a' - 1);
|
|
|
|
git_buf_encode_base85(pi->buf, scan, chunk_len);
|
|
git_buf_putc(pi->buf, '\n');
|
|
|
|
if (git_buf_oom(pi->buf))
|
|
return -1;
|
|
|
|
scan += chunk_len;
|
|
pi->line.num_lines++;
|
|
}
|
|
git_buf_putc(pi->buf, '\n');
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int diff_print_patch_file_binary(
|
|
diff_print_info *pi, git_diff_delta *delta,
|
|
const char *old_pfx, const char *new_pfx,
|
|
const git_diff_binary *binary)
|
|
{
|
|
size_t pre_binary_size;
|
|
int error;
|
|
|
|
if ((pi->flags & GIT_DIFF_SHOW_BINARY) == 0)
|
|
goto noshow;
|
|
|
|
if (binary->new_file.datalen == 0 && binary->old_file.datalen == 0)
|
|
return 0;
|
|
|
|
pre_binary_size = pi->buf->size;
|
|
git_buf_printf(pi->buf, "GIT binary patch\n");
|
|
pi->line.num_lines++;
|
|
|
|
if ((error = format_binary(pi, binary->new_file.type, binary->new_file.data,
|
|
binary->new_file.datalen, binary->new_file.inflatedlen)) < 0 ||
|
|
(error = format_binary(pi, binary->old_file.type, binary->old_file.data,
|
|
binary->old_file.datalen, binary->old_file.inflatedlen)) < 0) {
|
|
|
|
if (error == GIT_EBUFS) {
|
|
giterr_clear();
|
|
git_buf_truncate(pi->buf, pre_binary_size);
|
|
goto noshow;
|
|
}
|
|
}
|
|
|
|
pi->line.num_lines++;
|
|
return error;
|
|
|
|
noshow:
|
|
pi->line.num_lines = 1;
|
|
return diff_delta_format_with_paths(
|
|
pi->buf, delta, old_pfx, new_pfx,
|
|
"Binary files %s%s and %s%s differ\n");
|
|
}
|
|
|
|
static int diff_print_patch_file(
|
|
const git_diff_delta *delta, float progress, void *data)
|
|
{
|
|
int error;
|
|
diff_print_info *pi = data;
|
|
const char *oldpfx =
|
|
pi->old_prefix ? pi->old_prefix : DIFF_OLD_PREFIX_DEFAULT;
|
|
const char *newpfx =
|
|
pi->new_prefix ? pi->new_prefix : DIFF_NEW_PREFIX_DEFAULT;
|
|
|
|
bool binary = (delta->flags & GIT_DIFF_FLAG_BINARY) ||
|
|
(pi->flags & GIT_DIFF_FORCE_BINARY);
|
|
bool show_binary = !!(pi->flags & GIT_DIFF_SHOW_BINARY);
|
|
int oid_strlen = binary && show_binary ?
|
|
GIT_OID_HEXSZ + 1 : pi->oid_strlen;
|
|
|
|
GIT_UNUSED(progress);
|
|
|
|
if (S_ISDIR(delta->new_file.mode) ||
|
|
delta->status == GIT_DELTA_UNMODIFIED ||
|
|
delta->status == GIT_DELTA_IGNORED ||
|
|
delta->status == GIT_DELTA_UNREADABLE ||
|
|
(delta->status == GIT_DELTA_UNTRACKED &&
|
|
(pi->flags & GIT_DIFF_SHOW_UNTRACKED_CONTENT) == 0))
|
|
return 0;
|
|
|
|
if ((error = git_diff_delta__format_file_header(
|
|
pi->buf, delta, oldpfx, newpfx, oid_strlen)) < 0)
|
|
return error;
|
|
|
|
pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
|
|
pi->line.content = git_buf_cstr(pi->buf);
|
|
pi->line.content_len = git_buf_len(pi->buf);
|
|
|
|
return pi->print_cb(delta, NULL, &pi->line, pi->payload);
|
|
}
|
|
|
|
static int diff_print_patch_binary(
|
|
const git_diff_delta *delta,
|
|
const git_diff_binary *binary,
|
|
void *data)
|
|
{
|
|
diff_print_info *pi = data;
|
|
const char *old_pfx =
|
|
pi->old_prefix ? pi->old_prefix : DIFF_OLD_PREFIX_DEFAULT;
|
|
const char *new_pfx =
|
|
pi->new_prefix ? pi->new_prefix : DIFF_NEW_PREFIX_DEFAULT;
|
|
int error;
|
|
|
|
git_buf_clear(pi->buf);
|
|
|
|
if ((error = diff_print_patch_file_binary(
|
|
pi, (git_diff_delta *)delta, old_pfx, new_pfx, binary)) < 0)
|
|
return error;
|
|
|
|
pi->line.origin = GIT_DIFF_LINE_BINARY;
|
|
pi->line.content = git_buf_cstr(pi->buf);
|
|
pi->line.content_len = git_buf_len(pi->buf);
|
|
|
|
return pi->print_cb(delta, NULL, &pi->line, pi->payload);
|
|
}
|
|
|
|
static int diff_print_patch_hunk(
|
|
const git_diff_delta *d,
|
|
const git_diff_hunk *h,
|
|
void *data)
|
|
{
|
|
diff_print_info *pi = data;
|
|
|
|
if (S_ISDIR(d->new_file.mode))
|
|
return 0;
|
|
|
|
pi->line.origin = GIT_DIFF_LINE_HUNK_HDR;
|
|
pi->line.content = h->header;
|
|
pi->line.content_len = h->header_len;
|
|
|
|
return pi->print_cb(d, h, &pi->line, pi->payload);
|
|
}
|
|
|
|
static int diff_print_patch_line(
|
|
const git_diff_delta *delta,
|
|
const git_diff_hunk *hunk,
|
|
const git_diff_line *line,
|
|
void *data)
|
|
{
|
|
diff_print_info *pi = data;
|
|
|
|
if (S_ISDIR(delta->new_file.mode))
|
|
return 0;
|
|
|
|
return pi->print_cb(delta, hunk, line, pi->payload);
|
|
}
|
|
|
|
/* print a git_diff to an output callback */
|
|
int git_diff_print(
|
|
git_diff *diff,
|
|
git_diff_format_t format,
|
|
git_diff_line_cb print_cb,
|
|
void *payload)
|
|
{
|
|
int error;
|
|
git_buf buf = GIT_BUF_INIT;
|
|
diff_print_info pi;
|
|
git_diff_file_cb print_file = NULL;
|
|
git_diff_binary_cb print_binary = NULL;
|
|
git_diff_hunk_cb print_hunk = NULL;
|
|
git_diff_line_cb print_line = NULL;
|
|
|
|
switch (format) {
|
|
case GIT_DIFF_FORMAT_PATCH:
|
|
print_file = diff_print_patch_file;
|
|
print_binary = diff_print_patch_binary;
|
|
print_hunk = diff_print_patch_hunk;
|
|
print_line = diff_print_patch_line;
|
|
break;
|
|
case GIT_DIFF_FORMAT_PATCH_HEADER:
|
|
print_file = diff_print_patch_file;
|
|
break;
|
|
case GIT_DIFF_FORMAT_RAW:
|
|
print_file = diff_print_one_raw;
|
|
break;
|
|
case GIT_DIFF_FORMAT_NAME_ONLY:
|
|
print_file = diff_print_one_name_only;
|
|
break;
|
|
case GIT_DIFF_FORMAT_NAME_STATUS:
|
|
print_file = diff_print_one_name_status;
|
|
break;
|
|
default:
|
|
giterr_set(GITERR_INVALID, "Unknown diff output format (%d)", format);
|
|
return -1;
|
|
}
|
|
|
|
if (!(error = diff_print_info_init_fromdiff(
|
|
&pi, &buf, diff, format, print_cb, payload))) {
|
|
error = git_diff_foreach(
|
|
diff, print_file, print_binary, print_hunk, print_line, &pi);
|
|
|
|
if (error) /* make sure error message is set */
|
|
giterr_set_after_callback_function(error, "git_diff_print");
|
|
}
|
|
|
|
git_buf_free(&buf);
|
|
|
|
return error;
|
|
}
|
|
|
|
int git_diff_print_callback__to_buf(
|
|
const git_diff_delta *delta,
|
|
const git_diff_hunk *hunk,
|
|
const git_diff_line *line,
|
|
void *payload)
|
|
{
|
|
git_buf *output = payload;
|
|
GIT_UNUSED(delta); GIT_UNUSED(hunk);
|
|
|
|
if (!output) {
|
|
giterr_set(GITERR_INVALID, "Buffer pointer must be provided");
|
|
return -1;
|
|
}
|
|
|
|
if (line->origin == GIT_DIFF_LINE_ADDITION ||
|
|
line->origin == GIT_DIFF_LINE_DELETION ||
|
|
line->origin == GIT_DIFF_LINE_CONTEXT)
|
|
git_buf_putc(output, line->origin);
|
|
|
|
return git_buf_put(output, line->content, line->content_len);
|
|
}
|
|
|
|
int git_diff_print_callback__to_file_handle(
|
|
const git_diff_delta *delta,
|
|
const git_diff_hunk *hunk,
|
|
const git_diff_line *line,
|
|
void *payload)
|
|
{
|
|
FILE *fp = payload ? payload : stdout;
|
|
|
|
GIT_UNUSED(delta); GIT_UNUSED(hunk);
|
|
|
|
if (line->origin == GIT_DIFF_LINE_CONTEXT ||
|
|
line->origin == GIT_DIFF_LINE_ADDITION ||
|
|
line->origin == GIT_DIFF_LINE_DELETION)
|
|
fputc(line->origin, fp);
|
|
fwrite(line->content, 1, line->content_len, fp);
|
|
return 0;
|
|
}
|
|
|
|
/* print a git_patch to an output callback */
|
|
int git_patch_print(
|
|
git_patch *patch,
|
|
git_diff_line_cb print_cb,
|
|
void *payload)
|
|
{
|
|
int error;
|
|
git_buf temp = GIT_BUF_INIT;
|
|
diff_print_info pi;
|
|
|
|
assert(patch && print_cb);
|
|
|
|
if (!(error = diff_print_info_init_frompatch(
|
|
&pi, &temp, patch,
|
|
GIT_DIFF_FORMAT_PATCH, print_cb, payload)))
|
|
{
|
|
error = git_patch__invoke_callbacks(
|
|
patch,
|
|
diff_print_patch_file, diff_print_patch_binary,
|
|
diff_print_patch_hunk, diff_print_patch_line,
|
|
&pi);
|
|
|
|
if (error) /* make sure error message is set */
|
|
giterr_set_after_callback_function(error, "git_patch_print");
|
|
}
|
|
|
|
git_buf_free(&temp);
|
|
|
|
return error;
|
|
}
|
|
|
|
/* print a git_patch to a git_buf */
|
|
int git_patch_to_buf(git_buf *out, git_patch *patch)
|
|
{
|
|
assert(out && patch);
|
|
git_buf_sanitize(out);
|
|
return git_patch_print(patch, git_diff_print_callback__to_buf, out);
|
|
}
|