vendor/libgit2/src/diff_print.c in rugged-0.19.0 vs vendor/libgit2/src/diff_print.c in rugged-0.21.0

- old
+ new

@@ -5,30 +5,49 @@ * a Linking Exception. For full terms see the included COPYING file. */ #include "common.h" #include "diff.h" #include "diff_patch.h" -#include "buffer.h" +#include "fileops.h" +#include "zstream.h" +#include "blob.h" +#include "delta.h" +#include "git2/sys/diff.h" typedef struct { - git_diff_list *diff; - git_diff_data_cb print_cb; + git_diff *diff; + git_diff_format_t format; + git_diff_line_cb print_cb; void *payload; git_buf *buf; + uint32_t flags; int oid_strlen; + git_diff_line line; } diff_print_info; static int diff_print_info_init( diff_print_info *pi, - git_buf *out, git_diff_list *diff, git_diff_data_cb cb, void *payload) + git_buf *out, + git_diff *diff, + git_diff_format_t format, + git_diff_line_cb cb, + void *payload) { pi->diff = diff; + pi->format = format; pi->print_cb = cb; pi->payload = payload; pi->buf = out; - if (!diff || !diff->repo) + 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; @@ -37,18 +56,23 @@ if (pi->oid_strlen < 2) pi->oid_strlen = 2; else 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 char diff_pick_suffix(int mode) { if (S_ISDIR(mode)) return '/'; - else if (mode & 0100) /* -V536 */ + else if (GIT_PERMS_IS_EXEC(mode)) /* -V536 */ /* in git, modes are very regular, so we must have 0100755 mode */ return '*'; else return ' '; } @@ -69,96 +93,97 @@ } return code; } -static int callback_error(void) +static int diff_print_one_name_only( + const git_diff_delta *delta, float progress, void *data) { - giterr_clear(); - return GIT_EUSER; + 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_compact( +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->diff ? pi->diff->strcomp : git__strcmp; GIT_UNUSED(progress); - if (code == ' ') + 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, + 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 (%o -> %o)\n", code, - delta->old_file.path, new_suffix, delta->old_file.mode, delta->new_file.mode); + 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; - if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR, - git_buf_cstr(out), git_buf_len(out), pi->payload)) - return callback_error(); + pi->line.origin = GIT_DIFF_LINE_FILE_HDR; + pi->line.content = git_buf_cstr(out); + pi->line.content_len = git_buf_len(out); - return 0; + return pi->print_cb(delta, NULL, &pi->line, pi->payload); } -/* print a git_diff_list to a print callback in compact format */ -int git_diff_print_compact( - git_diff_list *diff, - git_diff_data_cb print_cb, - void *payload) -{ - int error; - git_buf buf = GIT_BUF_INIT; - diff_print_info pi; - - if (!(error = diff_print_info_init(&pi, &buf, diff, print_cb, payload))) - error = git_diff_foreach(diff, diff_print_one_compact, NULL, NULL, &pi); - - git_buf_free(&buf); - - return error; -} - 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; 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 (code == ' ') + if ((pi->flags & GIT_DIFF_SHOW_UNMODIFIED) == 0 && code == ' ') return 0; git_buf_clear(out); - git_oid_tostr(start_oid, pi->oid_strlen, &delta->old_file.oid); - git_oid_tostr(end_oid, pi->oid_strlen, &delta->new_file.oid); + 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, ":%06o %06o %s... %s... %c", + 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); @@ -171,42 +196,24 @@ delta->old_file.path : delta->new_file.path); if (git_buf_oom(out)) return -1; - if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR, - git_buf_cstr(out), git_buf_len(out), pi->payload)) - return callback_error(); + pi->line.origin = GIT_DIFF_LINE_FILE_HDR; + pi->line.content = git_buf_cstr(out); + pi->line.content_len = git_buf_len(out); - return 0; + return pi->print_cb(delta, NULL, &pi->line, pi->payload); } -/* print a git_diff_list to a print callback in raw output format */ -int git_diff_print_raw( - git_diff_list *diff, - git_diff_data_cb print_cb, - void *payload) +static int diff_print_oid_range( + git_buf *out, const git_diff_delta *delta, int oid_strlen) { - int error; - git_buf buf = GIT_BUF_INIT; - diff_print_info pi; - - if (!(error = diff_print_info_init(&pi, &buf, diff, print_cb, payload))) - error = git_diff_foreach(diff, diff_print_one_raw, NULL, NULL, &pi); - - git_buf_free(&buf); - - return error; -} - -static int diff_print_oid_range(diff_print_info *pi, const git_diff_delta *delta) -{ - git_buf *out = pi->buf; char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1]; - git_oid_tostr(start_oid, pi->oid_strlen, &delta->old_file.oid); - git_oid_tostr(end_oid, pi->oid_strlen, &delta->new_file.oid); + 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); @@ -220,211 +227,406 @@ git_buf_printf(out, "new mode %o\n", delta->new_file.mode); } git_buf_printf(out, "index %s..%s\n", start_oid, end_oid); } - if (git_buf_oom(out)) - return -1; - - return 0; + return git_buf_oom(out) ? -1 : 0; } -static int diff_print_patch_file( - const git_diff_delta *delta, float progress, void *data) +static int diff_delta_format_with_paths( + git_buf *out, + const git_diff_delta *delta, + const char *oldpfx, + const char *newpfx, + const char *template) { - diff_print_info *pi = data; - const char *oldpfx = pi->diff ? pi->diff->opts.old_prefix : NULL; const char *oldpath = delta->old_file.path; - const char *newpfx = pi->diff ? pi->diff->opts.new_prefix : NULL; const char *newpath = delta->new_file.path; - uint32_t opts_flags = pi->diff ? pi->diff->opts.flags : GIT_DIFF_NORMAL; - GIT_UNUSED(progress); + if (git_oid_iszero(&delta->old_file.id)) { + oldpfx = ""; + oldpath = "/dev/null"; + } + if (git_oid_iszero(&delta->new_file.id)) { + newpfx = ""; + newpath = "/dev/null"; + } - if (S_ISDIR(delta->new_file.mode) || - delta->status == GIT_DELTA_UNMODIFIED || - delta->status == GIT_DELTA_IGNORED || - (delta->status == GIT_DELTA_UNTRACKED && - (opts_flags & GIT_DIFF_INCLUDE_UNTRACKED_CONTENT) == 0)) - return 0; + 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(pi->buf); - git_buf_printf(pi->buf, "diff --git %s%s %s%s\n", + 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); - if (diff_print_oid_range(pi, delta) < 0) - return -1; + GITERR_CHECK_ERROR(diff_print_oid_range(out, delta, oid_strlen)); - if (git_oid_iszero(&delta->old_file.oid)) { - oldpfx = ""; - oldpath = "/dev/null"; + 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 print_binary_hunk(diff_print_info *pi, git_blob *old, git_blob *new) +{ + 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; } - if (git_oid_iszero(&delta->new_file.oid)) { - newpfx = ""; - newpath = "/dev/null"; + + 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; + } + } } - if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0) { - git_buf_printf(pi->buf, "--- %s%s\n", oldpfx, oldpath); - git_buf_printf(pi->buf, "+++ %s%s\n", newpfx, newpath); + git_buf_printf(pi->buf, "%s %lu\n", out_type, inflated_len); + pi->line.num_lines++; + + for (scan = out->ptr, end = out->ptr + out->size; 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_put_base85(pi->buf, scan, chunk_len); + git_buf_putc(pi->buf, '\n'); + + if (git_buf_oom(pi->buf)) { + error = -1; + goto done; + } + + scan += chunk_len; + pi->line.num_lines++; } - if (git_buf_oom(pi->buf)) - return -1; +done: + git_buf_free(&deflate); + git_buf_free(&delta); - if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR, - git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) - return callback_error(); + return error; +} - if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 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) +{ + git_blob *old = NULL, *new = NULL; + const git_oid *old_id, *new_id; + int error; + size_t pre_binary_size; + + if ((pi->flags & GIT_DIFF_SHOW_BINARY) == 0) + goto noshow; + + 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 || + (error = git_buf_putc(pi->buf, '\n')) < 0 || + (error = print_binary_hunk(pi, new, old)) < 0) + { + if (error == GIT_EBUFS) { + giterr_clear(); + git_buf_truncate(pi->buf, pre_binary_size); + goto noshow; + } + } + + 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, + "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->diff ? pi->diff->opts.old_prefix : DIFF_OLD_PREFIX_DEFAULT; + const char *newpfx = + pi->diff ? pi->diff->opts.new_prefix : DIFF_NEW_PREFIX_DEFAULT; + + bool binary = !!(delta->flags & GIT_DIFF_FLAG_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_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); + + if ((error = pi->print_cb(delta, NULL, &pi->line, pi->payload)) != 0) + return error; + + if (!binary) + return 0; + git_buf_clear(pi->buf); - git_buf_printf( - pi->buf, "Binary files %s%s and %s%s differ\n", - oldpfx, oldpath, newpfx, newpath); - if (git_buf_oom(pi->buf)) - return -1; - if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_BINARY, - git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) - return callback_error(); + if ((error = diff_print_patch_file_binary(pi, delta, oldpfx, newpfx)) < 0) + return error; - return 0; + 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_range *r, - const char *header, - size_t header_len, + const git_diff_hunk *h, void *data) { diff_print_info *pi = data; if (S_ISDIR(d->new_file.mode)) return 0; - git_buf_clear(pi->buf); - if (git_buf_printf(pi->buf, "%.*s", (int)header_len, header) < 0) - return -1; + pi->line.origin = GIT_DIFF_LINE_HUNK_HDR; + pi->line.content = h->header; + pi->line.content_len = h->header_len; - if (pi->print_cb(d, r, GIT_DIFF_LINE_HUNK_HDR, - git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) - return callback_error(); - - return 0; + return pi->print_cb(d, h, &pi->line, pi->payload); } static int diff_print_patch_line( const git_diff_delta *delta, - const git_diff_range *range, - char line_origin, /* GIT_DIFF_LINE value from above */ - const char *content, - size_t content_len, + 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; - git_buf_clear(pi->buf); - - if (line_origin == GIT_DIFF_LINE_ADDITION || - line_origin == GIT_DIFF_LINE_DELETION || - line_origin == GIT_DIFF_LINE_CONTEXT) - git_buf_printf(pi->buf, "%c%.*s", line_origin, (int)content_len, content); - else if (content_len > 0) - git_buf_printf(pi->buf, "%.*s", (int)content_len, content); - - if (git_buf_oom(pi->buf)) - return -1; - - if (pi->print_cb(delta, range, line_origin, - git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) - return callback_error(); - - return 0; + return pi->print_cb(delta, hunk, line, pi->payload); } -/* print a git_diff_list to an output callback in patch format */ -int git_diff_print_patch( - git_diff_list *diff, - git_diff_data_cb print_cb, +/* 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_hunk_cb print_hunk = NULL; + git_diff_line_cb print_line = NULL; - if (!(error = diff_print_info_init(&pi, &buf, diff, print_cb, payload))) + switch (format) { + case GIT_DIFF_FORMAT_PATCH: + print_file = diff_print_patch_file; + 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( + &pi, &buf, diff, format, print_cb, payload))) + { error = git_diff_foreach( - diff, diff_print_patch_file, diff_print_patch_hunk, - diff_print_patch_line, &pi); + diff, print_file, 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; } -/* print a git_diff_patch to an output callback */ -int git_diff_patch_print( - git_diff_patch *patch, - git_diff_data_cb print_cb, +/* 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( - &pi, &temp, git_diff_patch__diff(patch), print_cb, payload))) - error = git_diff_patch__invoke_callbacks( + &pi, &temp, git_patch__diff(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); + if (error) /* make sure error message is set */ + giterr_set_after_callback_function(error, "git_patch_print"); + } + git_buf_free(&temp); return error; } -static int diff_print_to_buffer_cb( +int git_diff_print_callback__to_buf( const git_diff_delta *delta, - const git_diff_range *range, - char line_origin, - const char *content, - size_t content_len, + const git_diff_hunk *hunk, + const git_diff_line *line, void *payload) { git_buf *output = payload; - GIT_UNUSED(delta); GIT_UNUSED(range); GIT_UNUSED(line_origin); - return git_buf_put(output, content, content_len); + 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); } -/* print a git_diff_patch to a string buffer */ -int git_diff_patch_to_str( - char **string, - git_diff_patch *patch) +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) { - int error; - git_buf output = GIT_BUF_INIT; + FILE *fp = payload ? payload : stdout; - error = git_diff_patch_print(patch, diff_print_to_buffer_cb, &output); + GIT_UNUSED(delta); GIT_UNUSED(hunk); - /* GIT_EUSER means git_buf_put in print_to_buffer_cb returned -1, - * meaning a memory allocation failure, so just map to -1... - */ - if (error == GIT_EUSER) - error = -1; + 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; +} - *string = git_buf_detach(&output); - - 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); }