]> git.proxmox.com Git - libgit2.git/blobdiff - src/diff_print.c
New upstream version 1.1.0+dfsg.1
[libgit2.git] / src / diff_print.c
index fd1a186c12d51acd2d8c389e55a56bc3ac58719c..9ce04d70e357f1ea2ed71adc78c3acd64bef1440 100644 (file)
@@ -4,11 +4,13 @@
  * 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_generate.h"
-#include "fileops.h"
+#include "futils.h"
 #include "zstream.h"
 #include "blob.h"
 #include "delta.h"
@@ -46,7 +48,7 @@ static int diff_print_info_init__common(
        if (!pi->id_strlen) {
                if (!repo)
                        pi->id_strlen = GIT_ABBREV_DEFAULT;
-               else if (git_repository__cvar(&pi->id_strlen, repo, GIT_CVAR_ABBREV) < 0)
+               else if (git_repository__configmap_lookup(&pi->id_strlen, repo, GIT_CONFIGMAP_ABBREV) < 0)
                        return -1;
        }
 
@@ -128,6 +130,7 @@ char git_diff_status_char(git_delta_t status)
        case GIT_DELTA_COPIED:     code = 'C'; break;
        case GIT_DELTA_IGNORED:    code = 'I'; break;
        case GIT_DELTA_UNTRACKED:  code = '?'; break;
+       case GIT_DELTA_TYPECHANGE: code = 'T'; break;
        case GIT_DELTA_UNREADABLE: code = 'X'; break;
        default:                   code = ' '; break;
        }
@@ -221,8 +224,8 @@ static int diff_print_one_raw(
                delta->new_file.id_abbrev;
 
        if (pi->id_strlen > id_abbrev) {
-               giterr_set(GITERR_PATCH,
-                       "The patch input contains %d id characters (cannot print %d)",
+               git_error_set(GIT_ERROR_PATCH,
+                       "the patch input contains %d id characters (cannot print %d)",
                        id_abbrev, pi->id_strlen);
                return -1;
        }
@@ -266,22 +269,23 @@ static int diff_print_modes(
 }
 
 static int diff_print_oid_range(
-       git_buf *out, const git_diff_delta *delta, int id_strlen)
+       git_buf *out, const git_diff_delta *delta, int id_strlen,
+       bool print_index)
 {
        char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1];
 
        if (delta->old_file.mode &&
                        id_strlen > delta->old_file.id_abbrev) {
-               giterr_set(GITERR_PATCH,
-                       "The patch input contains %d id characters (cannot print %d)",
+               git_error_set(GIT_ERROR_PATCH,
+                       "the patch input contains %d id characters (cannot print %d)",
                        delta->old_file.id_abbrev, id_strlen);
                return -1;
        }
 
        if ((delta->new_file.mode &&
                        id_strlen > delta->new_file.id_abbrev)) {
-               giterr_set(GITERR_PATCH,
-                       "The patch input contains %d id characters (cannot print %d)",
+               git_error_set(GIT_ERROR_PATCH,
+                       "the patch input contains %d id characters (cannot print %d)",
                        delta->new_file.id_abbrev, id_strlen);
                return -1;
        }
@@ -290,8 +294,9 @@ static int diff_print_oid_range(
        git_oid_tostr(end_oid, id_strlen + 1, &delta->new_file.id);
 
        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);
+               if (print_index)
+                       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);
@@ -300,7 +305,8 @@ static int diff_print_oid_range(
                else
                        diff_print_modes(out, delta);
 
-               git_buf_printf(out, "index %s..%s\n", start_oid, end_oid);
+               if (print_index)
+                       git_buf_printf(out, "index %s..%s\n", start_oid, end_oid);
        }
 
        return git_buf_oom(out) ? -1 : 0;
@@ -322,16 +328,16 @@ static int diff_delta_format_with_paths(
        const char *oldpath,
        const char *newpath)
 {
-       if (git_oid_iszero(&delta->old_file.id))
+       if (git_oid_is_zero(&delta->old_file.id))
                oldpath = "/dev/null";
 
-       if (git_oid_iszero(&delta->new_file.id))
+       if (git_oid_is_zero(&delta->new_file.id))
                newpath = "/dev/null";
 
        return git_buf_printf(out, template, oldpath, newpath);
 }
 
-int diff_delta_format_similarity_header(
+static int diff_delta_format_similarity_header(
        git_buf *out,
        const git_diff_delta *delta)
 {
@@ -340,22 +346,21 @@ int diff_delta_format_similarity_header(
        int error = 0;
 
        if (delta->similarity > 100) {
-               giterr_set(GITERR_PATCH, "invalid similarity %d", delta->similarity);
+               git_error_set(GIT_ERROR_PATCH, "invalid similarity %d", delta->similarity);
                error = -1;
                goto done;
        }
 
+       GIT_ASSERT(delta->status == GIT_DELTA_RENAMED || delta->status == GIT_DELTA_COPIED);
        if (delta->status == GIT_DELTA_RENAMED)
                type = "rename";
-       else if (delta->status == GIT_DELTA_COPIED)
-               type = "copy";
        else
-               abort();
+               type = "copy";
 
        if ((error = git_buf_puts(&old_path, delta->old_file.path)) < 0 ||
-               (error = git_buf_puts(&new_path, delta->new_file.path)) < 0 ||
-               (error = git_buf_quote(&old_path)) < 0 ||
-               (error = git_buf_quote(&new_path)) < 0)
+           (error = git_buf_puts(&new_path, delta->new_file.path)) < 0 ||
+           (error = git_buf_quote(&old_path)) < 0 ||
+           (error = git_buf_quote(&new_path)) < 0)
                goto done;
 
        git_buf_printf(out,
@@ -370,16 +375,16 @@ int diff_delta_format_similarity_header(
                error = -1;
 
 done:
-       git_buf_free(&old_path);
-       git_buf_free(&new_path);
+       git_buf_dispose(&old_path);
+       git_buf_dispose(&new_path);
 
        return error;
 }
 
 static bool delta_is_unchanged(const git_diff_delta *delta)
 {
-       if (git_oid_iszero(&delta->old_file.id) &&
-               git_oid_iszero(&delta->new_file.id))
+       if (git_oid_is_zero(&delta->old_file.id) &&
+               git_oid_is_zero(&delta->new_file.id))
                return true;
 
        if (delta->old_file.mode == GIT_FILEMODE_COMMIT ||
@@ -397,7 +402,8 @@ int git_diff_delta__format_file_header(
        const git_diff_delta *delta,
        const char *oldpfx,
        const char *newpfx,
-       int id_strlen)
+       int id_strlen,
+       bool print_index)
 {
        git_buf old_path = GIT_BUF_INIT, new_path = GIT_BUF_INIT;
        bool unchanged = delta_is_unchanged(delta);
@@ -421,14 +427,18 @@ int git_diff_delta__format_file_header(
        git_buf_printf(out, "diff --git %s %s\n",
                old_path.ptr, new_path.ptr);
 
+       if (unchanged && delta->old_file.mode != delta->new_file.mode)
+               diff_print_modes(out, delta);
+
        if (delta->status == GIT_DELTA_RENAMED ||
-               (delta->status == GIT_DELTA_COPIED && unchanged)) {
+           (delta->status == GIT_DELTA_COPIED && unchanged)) {
                if ((error = diff_delta_format_similarity_header(out, delta)) < 0)
                        goto done;
        }
 
        if (!unchanged) {
-               if ((error = diff_print_oid_range(out, delta, id_strlen)) < 0)
+               if ((error = diff_print_oid_range(out, delta,
+                                                 id_strlen, print_index)) < 0)
                        goto done;
 
                if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0)
@@ -436,15 +446,12 @@ int git_diff_delta__format_file_header(
                                "--- %s\n+++ %s\n", old_path.ptr, new_path.ptr);
        }
 
-       if (unchanged && delta->old_file.mode != delta->new_file.mode)
-               diff_print_modes(out, delta);
-
        if (git_buf_oom(out))
                error = -1;
 
 done:
-       git_buf_free(&old_path);
-       git_buf_free(&new_path);
+       git_buf_dispose(&old_path);
+       git_buf_dispose(&new_path);
 
        return error;
 }
@@ -484,6 +491,9 @@ static int format_binary(
        }
        git_buf_putc(pi->buf, '\n');
 
+       if (git_buf_oom(pi->buf))
+               return -1;
+
        return 0;
 }
 
@@ -494,21 +504,17 @@ static int diff_print_patch_file_binary_noshow(
        git_buf old_path = GIT_BUF_INIT, new_path = GIT_BUF_INIT;
        int error;
 
-       if ((error = diff_delta_format_path(
-                       &old_path, old_pfx, delta->old_file.path)) < 0 ||
-               (error = diff_delta_format_path(
-                       &new_path, new_pfx, delta->new_file.path)) < 0)
+       if ((error = diff_delta_format_path(&old_path, old_pfx, delta->old_file.path)) < 0 ||
+           (error = diff_delta_format_path(&new_path, new_pfx, delta->new_file.path)) < 0 ||
+           (error = diff_delta_format_with_paths(pi->buf, delta, "Binary files %s and %s differ\n",
+                                                 old_path.ptr, new_path.ptr)) < 0)
                goto done;
 
        pi->line.num_lines = 1;
-       error = diff_delta_format_with_paths(
-               pi->buf, delta, "Binary files %s and %s differ\n",
-               old_path.ptr, new_path.ptr);
 
 done:
-       git_buf_free(&old_path);
-       git_buf_free(&new_path);
-
+       git_buf_dispose(&old_path);
+       git_buf_dispose(&new_path);
        return error;
 }
 
@@ -532,12 +538,11 @@ static int diff_print_patch_file_binary(
        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) {
-
+                                  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_error_clear();
                        git_buf_truncate(pi->buf, pre_binary_size);
 
                        return diff_print_patch_file_binary_noshow(
@@ -563,6 +568,7 @@ static int diff_print_patch_file(
                (pi->flags & GIT_DIFF_FORCE_BINARY);
        bool show_binary = !!(pi->flags & GIT_DIFF_SHOW_BINARY);
        int id_strlen = pi->id_strlen;
+       bool print_index = (pi->format != GIT_DIFF_FORMAT_PATCH_ID);
 
        if (binary && show_binary)
                id_strlen = delta->old_file.id_abbrev ? delta->old_file.id_abbrev :
@@ -571,15 +577,15 @@ static int diff_print_patch_file(
        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 &&
+           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, id_strlen)) < 0)
+       if ((error = git_diff_delta__format_file_header(pi->buf, delta, oldpfx, newpfx,
+                                                       id_strlen, print_index)) < 0)
                return error;
 
        pi->line.origin      = GIT_DIFF_LINE_FILE_HDR;
@@ -667,6 +673,11 @@ int git_diff_print(
                print_hunk = diff_print_patch_hunk;
                print_line = diff_print_patch_line;
                break;
+       case GIT_DIFF_FORMAT_PATCH_ID:
+               print_file = diff_print_patch_file;
+               print_binary = diff_print_patch_binary;
+               print_line = diff_print_patch_line;
+               break;
        case GIT_DIFF_FORMAT_PATCH_HEADER:
                print_file = diff_print_patch_file;
                break;
@@ -680,21 +691,20 @@ int git_diff_print(
                print_file = diff_print_one_name_status;
                break;
        default:
-               giterr_set(GITERR_INVALID, "Unknown diff output format (%d)", format);
+               git_error_set(GIT_ERROR_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 = diff_print_info_init_fromdiff(&pi, &buf, diff, format, print_cb, payload)) < 0)
+               goto out;
 
-               if (error) /* make sure error message is set */
-                       giterr_set_after_callback_function(error, "git_diff_print");
+       if ((error = git_diff_foreach(diff, print_file, print_binary, print_hunk, print_line, &pi)) != 0) {
+               git_error_set_after_callback_function(error, "git_diff_print");
+               goto out;
        }
 
-       git_buf_free(&buf);
-
+out:
+       git_buf_dispose(&buf);
        return error;
 }
 
@@ -708,13 +718,13 @@ int git_diff_print_callback__to_buf(
        GIT_UNUSED(delta); GIT_UNUSED(hunk);
 
        if (!output) {
-               giterr_set(GITERR_INVALID, "Buffer pointer must be provided");
+               git_error_set(GIT_ERROR_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)
+           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);
@@ -727,14 +737,27 @@ int git_diff_print_callback__to_file_handle(
        void *payload)
 {
        FILE *fp = payload ? payload : stdout;
+       int error;
 
-       GIT_UNUSED(delta); GIT_UNUSED(hunk);
+       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);
+           line->origin == GIT_DIFF_LINE_ADDITION ||
+           line->origin == GIT_DIFF_LINE_DELETION) {
+               while ((error = fputc(line->origin, fp)) == EINTR)
+                       continue;
+               if (error) {
+                       git_error_set(GIT_ERROR_OS, "could not write status");
+                       return -1;
+               }
+       }
+
+       if (fwrite(line->content, line->content_len, 1, fp) != 1) {
+               git_error_set(GIT_ERROR_OS, "could not write line");
+               return -1;
+       }
+
        return 0;
 }
 
@@ -743,8 +766,7 @@ int git_diff_to_buf(git_buf *out, git_diff *diff, git_diff_format_t format)
 {
        assert(out && diff);
        git_buf_sanitize(out);
-       return git_diff_print(
-               diff, format, git_diff_print_callback__to_buf, out);
+       return git_diff_print(diff, format, git_diff_print_callback__to_buf, out);
 }
 
 /* print a git_patch to an output callback */
@@ -753,28 +775,24 @@ int git_patch_print(
        git_diff_line_cb print_cb,
        void *payload)
 {
-       int error;
        git_buf temp = GIT_BUF_INIT;
        diff_print_info pi;
+       int error;
 
        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");
-       }
+       if ((error = diff_print_info_init_frompatch(&pi, &temp, patch,
+                                                   GIT_DIFF_FORMAT_PATCH, print_cb, payload)) < 0)
+               goto out;
 
-       git_buf_free(&temp);
+       if ((error = git_patch__invoke_callbacks(patch, diff_print_patch_file, diff_print_patch_binary,
+                                                diff_print_patch_hunk, diff_print_patch_line, &pi)) < 0) {
+               git_error_set_after_callback_function(error, "git_patch_print");
+               goto out;
+       }
 
+out:
+       git_buf_dispose(&temp);
        return error;
 }