Blame src/diff_print.c

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