summaryrefslogtreecommitdiff
path: root/src/diff_print.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/diff_print.c')
-rw-r--r--src/diff_print.c280
1 files changed, 154 insertions, 126 deletions
diff --git a/src/diff_print.c b/src/diff_print.c
index 43a90b3d8..ebae4ea75 100644
--- a/src/diff_print.c
+++ b/src/diff_print.c
@@ -22,50 +22,92 @@ typedef struct {
uint32_t flags;
int oid_strlen;
git_diff_line line;
+ unsigned int
+ content_loaded : 1,
+ content_allocated : 1;
+ git_diff_file_content *ofile;
+ git_diff_file_content *nfile;
} diff_print_info;
-static int diff_print_info_init(
+static int diff_print_info_init__common(
diff_print_info *pi,
git_buf *out,
- git_diff *diff,
+ git_repository *repo,
git_diff_format_t format,
git_diff_line_cb cb,
void *payload)
{
- pi->diff = diff;
- pi->format = format;
+ pi->format = format;
pi->print_cb = cb;
- pi->payload = payload;
- pi->buf = out;
-
- if (diff)
- pi->flags = diff->opts.flags;
- else
- pi->flags = 0;
-
- if (diff && diff->opts.id_abbrev != 0)
- pi->oid_strlen = diff->opts.id_abbrev;
- else if (!diff || !diff->repo)
- pi->oid_strlen = GIT_ABBREV_DEFAULT;
- else if (git_repository__cvar(
- &pi->oid_strlen, diff->repo, GIT_CVAR_ABBREV) < 0)
- return -1;
+ 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 < 2)
- pi->oid_strlen = 2;
- else if (pi->oid_strlen > GIT_OID_HEXSZ + 1)
+ 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;
+ 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));
+
+ pi->diff = diff;
+
+ if (diff) {
+ pi->flags = diff->opts.flags;
+ pi->oid_strlen = diff->opts.id_abbrev;
+ }
+
+ 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)
+{
+ git_repository *repo = patch && patch->diff ? patch->diff->repo : NULL;
+
+ memset(pi, 0, sizeof(diff_print_info));
+
+ pi->diff = patch->diff;
+
+ pi->flags = patch->diff_opts.flags;
+ pi->oid_strlen = patch->diff_opts.id_abbrev;
+
+ pi->content_loaded = 1;
+ pi->ofile = &patch->ofile;
+ pi->nfile = &patch->nfile;
+
+ return diff_print_info_init__common(pi, out, repo, format, cb, payload);
+}
+
static char diff_pick_suffix(int mode)
{
if (S_ISDIR(mode))
@@ -283,66 +325,22 @@ int git_diff_delta__format_file_header(
return git_buf_oom(out) ? -1 : 0;
}
-static int print_binary_hunk(diff_print_info *pi, git_blob *old, git_blob *new)
+static int format_binary(
+ diff_print_info *pi,
+ git_diff_binary_t type,
+ const char *data,
+ size_t datalen,
+ size_t inflatedlen)
{
- git_buf deflate = GIT_BUF_INIT, delta = GIT_BUF_INIT, *out = NULL;
- const void *old_data, *new_data;
- git_off_t old_data_len, new_data_len;
- unsigned long delta_data_len, inflated_len;
- const char *out_type = "literal";
- char *scan, *end;
- int error;
-
- old_data = old ? git_blob_rawcontent(old) : NULL;
- new_data = new ? git_blob_rawcontent(new) : NULL;
-
- old_data_len = old ? git_blob_rawsize(old) : 0;
- new_data_len = new ? git_blob_rawsize(new) : 0;
-
- /* The git_delta function accepts unsigned long only */
- if (!git__is_ulong(old_data_len) || !git__is_ulong(new_data_len))
- return GIT_EBUFS;
-
- out = &deflate;
- inflated_len = (unsigned long)new_data_len;
-
- if ((error = git_zstream_deflatebuf(
- out, new_data, (size_t)new_data_len)) < 0)
- goto done;
-
- /* The git_delta function accepts unsigned long only */
- if (!git__is_ulong((git_off_t)deflate.size)) {
- error = GIT_EBUFS;
- goto done;
- }
+ const char *typename = type == GIT_DIFF_BINARY_DELTA ?
+ "delta" : "literal";
+ const char *scan, *end;
+ int error = 0;
- if (old && new) {
- void *delta_data = git_delta(
- old_data, (unsigned long)old_data_len,
- new_data, (unsigned long)new_data_len,
- &delta_data_len, (unsigned long)deflate.size);
-
- if (delta_data) {
- error = git_zstream_deflatebuf(
- &delta, delta_data, (size_t)delta_data_len);
-
- git__free(delta_data);
-
- if (error < 0)
- goto done;
-
- if (delta.size < deflate.size) {
- out = &delta;
- out_type = "delta";
- inflated_len = delta_data_len;
- }
- }
- }
-
- git_buf_printf(pi->buf, "%s %lu\n", out_type, inflated_len);
+ git_buf_printf(pi->buf, "%s %lu\n", typename, inflatedlen);
pi->line.num_lines++;
- for (scan = out->ptr, end = out->ptr + out->size; scan < end; ) {
+ for (scan = data, end = data + datalen; scan < end; ) {
size_t chunk_len = end - scan;
if (chunk_len > 52)
chunk_len = 52;
@@ -355,51 +353,74 @@ static int print_binary_hunk(diff_print_info *pi, git_blob *old, git_blob *new)
git_buf_encode_base85(pi->buf, scan, chunk_len);
git_buf_putc(pi->buf, '\n');
- if (git_buf_oom(pi->buf)) {
- error = -1;
- goto done;
- }
+ if (git_buf_oom(pi->buf))
+ return -1;
scan += chunk_len;
pi->line.num_lines++;
}
-done:
- git_buf_free(&deflate);
- git_buf_free(&delta);
+ return 0;
+}
- return error;
+static int diff_print_load_content(
+ diff_print_info *pi,
+ git_diff_delta *delta)
+{
+ git_diff_file_content *ofile, *nfile;
+ int error;
+
+ assert(pi->diff);
+
+ ofile = git__calloc(1, sizeof(git_diff_file_content));
+ nfile = git__calloc(1, sizeof(git_diff_file_content));
+
+ GITERR_CHECK_ALLOC(ofile);
+ GITERR_CHECK_ALLOC(nfile);
+
+ if ((error = git_diff_file_content__init_from_diff(
+ ofile, pi->diff, delta, true)) < 0 ||
+ (error = git_diff_file_content__init_from_diff(
+ nfile, pi->diff, delta, true)) < 0) {
+
+ git__free(ofile);
+ git__free(nfile);
+ return error;
+ }
+
+ pi->content_loaded = 1;
+ pi->content_allocated = 1;
+ pi->ofile = ofile;
+ pi->nfile = nfile;
+
+ return 0;
}
-/* git diff --binary 8d7523f~2 8d7523f~1 */
static int diff_print_patch_file_binary(
- diff_print_info *pi, const git_diff_delta *delta,
- const char *oldpfx, const char *newpfx)
+ diff_print_info *pi, git_diff_delta *delta,
+ const char *old_pfx, const char *new_pfx,
+ const git_diff_binary *binary)
{
- git_blob *old = NULL, *new = NULL;
- const git_oid *old_id, *new_id;
- int error;
size_t pre_binary_size;
+ int error;
if ((pi->flags & GIT_DIFF_SHOW_BINARY) == 0)
goto noshow;
+ if (!pi->content_loaded &&
+ (error = diff_print_load_content(pi, delta)) < 0)
+ return error;
+
pre_binary_size = pi->buf->size;
git_buf_printf(pi->buf, "GIT binary patch\n");
pi->line.num_lines++;
- old_id = (delta->status != GIT_DELTA_ADDED) ? &delta->old_file.id : NULL;
- new_id = (delta->status != GIT_DELTA_DELETED) ? &delta->new_file.id : NULL;
-
- if (old_id && (error = git_blob_lookup(&old, pi->diff->repo, old_id)) < 0)
- goto done;
- if (new_id && (error = git_blob_lookup(&new, pi->diff->repo,new_id)) < 0)
- goto done;
-
- if ((error = print_binary_hunk(pi, old, new)) < 0 ||
+ if ((error = format_binary(pi, binary->new_file.type, binary->new_file.data,
+ binary->new_file.datalen, binary->new_file.inflatedlen)) < 0 ||
(error = git_buf_putc(pi->buf, '\n')) < 0 ||
- (error = print_binary_hunk(pi, new, old)) < 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);
@@ -408,17 +429,12 @@ static int diff_print_patch_file_binary(
}
pi->line.num_lines++;
-
-done:
- git_blob_free(old);
- git_blob_free(new);
-
return error;
noshow:
pi->line.num_lines = 1;
return diff_delta_format_with_paths(
- pi->buf, delta, oldpfx, newpfx,
+ pi->buf, delta, old_pfx, new_pfx,
"Binary files %s%s and %s%s differ\n");
}
@@ -432,7 +448,8 @@ static int diff_print_patch_file(
const char *newpfx =
pi->diff ? pi->diff->opts.new_prefix : DIFF_NEW_PREFIX_DEFAULT;
- bool binary = !!(delta->flags & GIT_DIFF_FLAG_BINARY);
+ 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;
@@ -455,19 +472,29 @@ static int diff_print_patch_file(
pi->line.content = git_buf_cstr(pi->buf);
pi->line.content_len = git_buf_len(pi->buf);
- if ((error = pi->print_cb(delta, NULL, &pi->line, pi->payload)) != 0)
- return error;
+ return pi->print_cb(delta, NULL, &pi->line, pi->payload);
+}
- if (!binary)
- return 0;
+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->diff ? pi->diff->opts.old_prefix : DIFF_OLD_PREFIX_DEFAULT;
+ const char *new_pfx =
+ pi->diff ? pi->diff->opts.new_prefix : DIFF_NEW_PREFIX_DEFAULT;
+ int error;
git_buf_clear(pi->buf);
- if ((error = diff_print_patch_file_binary(pi, delta, oldpfx, newpfx)) < 0)
+ 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.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);
@@ -515,12 +542,14 @@ int git_diff_print(
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;
@@ -541,11 +570,10 @@ int git_diff_print(
return -1;
}
- if (!(error = diff_print_info_init(
- &pi, &buf, diff, format, print_cb, payload)))
- {
+ if (!(error = diff_print_info_init_fromdiff(
+ &pi, &buf, diff, format, print_cb, payload))) {
error = git_diff_foreach(
- diff, print_file, print_hunk, print_line, &pi);
+ 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");
@@ -568,13 +596,13 @@ int git_patch_print(
assert(patch && print_cb);
- if (!(error = diff_print_info_init(
- &pi, &temp, git_patch__diff(patch),
+ 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_hunk,
- diff_print_patch_line, &pi);
+ 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");