summaryrefslogtreecommitdiff
path: root/src/diff_print.c
diff options
context:
space:
mode:
authorBen Straub <bs@github.com>2013-09-16 16:12:31 -0700
committerBen Straub <bs@github.com>2013-09-16 16:12:31 -0700
commit549931679a77b280eb1f36afeda8930eb31d70f7 (patch)
tree2744e3e198ad146bae72f35369bbeb4f8028c8c3 /src/diff_print.c
parent1a68c168a6cdbe0db6e44fb582a7026a7d536c9d (diff)
parent8821c9aa5baf31e21c21825e8c91c765e6631e7f (diff)
downloadlibgit2-549931679a77b280eb1f36afeda8930eb31d70f7.tar.gz
Merge branch 'development' into blame_rebased
Conflicts: include/git2.h
Diffstat (limited to 'src/diff_print.c')
-rw-r--r--src/diff_print.c221
1 files changed, 130 insertions, 91 deletions
diff --git a/src/diff_print.c b/src/diff_print.c
index 244aa6e1d..ee4b5fc17 100644
--- a/src/diff_print.c
+++ b/src/diff_print.c
@@ -7,7 +7,7 @@
#include "common.h"
#include "diff.h"
#include "diff_patch.h"
-#include "buffer.h"
+#include "fileops.h"
typedef struct {
git_diff_list *diff;
@@ -21,14 +21,15 @@ static int diff_print_info_init(
diff_print_info *pi,
git_buf *out, git_diff_list *diff, git_diff_data_cb cb, void *payload)
{
- assert(diff && diff->repo);
-
pi->diff = diff;
pi->print_cb = cb;
pi->payload = payload;
pi->buf = out;
- if (git_repository__cvar(&pi->oid_strlen, diff->repo, GIT_CVAR_ABBREV) < 0)
+ 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->oid_strlen += 1; /* for NUL byte */
@@ -41,11 +42,11 @@ static int diff_print_info_init(
return 0;
}
-static char pick_suffix(int mode)
+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
@@ -76,45 +77,49 @@ static int callback_error(void)
return GIT_EUSER;
}
-static int print_compact(
+static int diff_print_one_compact(
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 == ' ')
return 0;
- old_suffix = pick_suffix(delta->old_file.mode);
- new_suffix = pick_suffix(delta->new_file.mode);
+ old_suffix = diff_pick_suffix(delta->old_file.mode);
+ new_suffix = diff_pick_suffix(delta->new_file.mode);
- git_buf_clear(pi->buf);
+ git_buf_clear(out);
if (delta->old_file.path != delta->new_file.path &&
- pi->diff->strcomp(delta->old_file.path,delta->new_file.path) != 0)
- git_buf_printf(pi->buf, "%c\t%s%c -> %s%c\n", code,
+ 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(pi->buf, "%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(pi->buf, "%c\t%s%c\n", code, delta->old_file.path, old_suffix);
+ git_buf_printf(out, "%c\t%s%c\n", code, delta->old_file.path, old_suffix);
else
- git_buf_printf(pi->buf, "%c\t%s\n", code, delta->old_file.path);
+ git_buf_printf(out, "%c\t%s\n", code, delta->old_file.path);
- if (git_buf_oom(pi->buf))
+ if (git_buf_oom(out))
return -1;
if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR,
- git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload))
+ git_buf_cstr(out), git_buf_len(out), pi->payload))
return callback_error();
return 0;
}
+/* 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,
@@ -125,17 +130,18 @@ int git_diff_print_compact(
diff_print_info pi;
if (!(error = diff_print_info_init(&pi, &buf, diff, print_cb, payload)))
- error = git_diff_foreach(diff, print_compact, NULL, NULL, &pi);
+ error = git_diff_foreach(diff, diff_print_one_compact, NULL, NULL, &pi);
git_buf_free(&buf);
return error;
}
-static int print_raw(
+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];
@@ -144,36 +150,37 @@ static int print_raw(
if (code == ' ')
return 0;
- git_buf_clear(pi->buf);
+ 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_buf_printf(
- pi->buf, ":%06o %06o %s... %s... %c",
+ out, ":%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(pi->buf, "%03u", delta->similarity);
+ git_buf_printf(out, "%03u", delta->similarity);
- if (delta->status == GIT_DELTA_RENAMED || delta->status == GIT_DELTA_COPIED)
+ if (delta->old_file.path != delta->new_file.path)
git_buf_printf(
- pi->buf, "\t%s %s\n", delta->old_file.path, delta->new_file.path);
+ out, "\t%s %s\n", delta->old_file.path, delta->new_file.path);
else
git_buf_printf(
- pi->buf, "\t%s\n", delta->old_file.path ?
+ out, "\t%s\n", delta->old_file.path ?
delta->old_file.path : delta->new_file.path);
- if (git_buf_oom(pi->buf))
+ if (git_buf_oom(out))
return -1;
if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR,
- git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload))
+ git_buf_cstr(out), git_buf_len(out), pi->payload))
return callback_error();
return 0;
}
+/* 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,
@@ -184,87 +191,115 @@ int git_diff_print_raw(
diff_print_info pi;
if (!(error = diff_print_info_init(&pi, &buf, diff, print_cb, payload)))
- error = git_diff_foreach(diff, print_raw, NULL, NULL, &pi);
+ error = git_diff_foreach(diff, diff_print_one_raw, NULL, NULL, &pi);
git_buf_free(&buf);
return error;
}
-static int print_oid_range(diff_print_info *pi, const git_diff_delta *delta)
+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];
- 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.oid);
+ git_oid_tostr(end_oid, oid_strlen, &delta->new_file.oid);
/* TODO: Match git diff more closely */
if (delta->old_file.mode == delta->new_file.mode) {
- git_buf_printf(pi->buf, "index %s..%s %o\n",
+ 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(pi->buf, "new file mode %o\n", delta->new_file.mode);
+ git_buf_printf(out, "new file mode %o\n", delta->new_file.mode);
} else if (delta->new_file.mode == 0) {
- git_buf_printf(pi->buf, "deleted file mode %o\n", delta->old_file.mode);
+ git_buf_printf(out, "deleted file mode %o\n", delta->old_file.mode);
} else {
- git_buf_printf(pi->buf, "old mode %o\n", delta->old_file.mode);
- git_buf_printf(pi->buf, "new mode %o\n", delta->new_file.mode);
+ 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(pi->buf, "index %s..%s\n", start_oid, end_oid);
+ git_buf_printf(out, "index %s..%s\n", start_oid, end_oid);
}
- if (git_buf_oom(pi->buf))
+ if (git_buf_oom(out))
return -1;
return 0;
}
-static int 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->opts.old_prefix;
const char *oldpath = delta->old_file.path;
- const char *newpfx = pi->diff->opts.new_prefix;
const char *newpath = delta->new_file.path;
- GIT_UNUSED(progress);
+ if (git_oid_iszero(&delta->old_file.oid)) {
+ oldpfx = "";
+ oldpath = "/dev/null";
+ }
+ if (git_oid_iszero(&delta->new_file.oid)) {
+ 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 &&
- (pi->diff->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", oldpfx, delta->old_file.path, newpfx, delta->new_file.path);
+ git_buf_clear(out);
- if (print_oid_range(pi, delta) < 0)
+ 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(out, delta, oid_strlen) < 0)
return -1;
- if (git_oid_iszero(&delta->old_file.oid)) {
- oldpfx = "";
- oldpath = "/dev/null";
- }
- if (git_oid_iszero(&delta->new_file.oid)) {
- newpfx = "";
- newpath = "/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");
- 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);
- }
+ return git_buf_oom(out) ? -1 : 0;
+}
- if (git_buf_oom(pi->buf))
+static int diff_print_patch_file(
+ const git_diff_delta *delta, float progress, void *data)
+{
+ 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;
+ uint32_t opts_flags = pi->diff ? pi->diff->opts.flags : GIT_DIFF_NORMAL;
+
+ 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 &&
+ (opts_flags & GIT_DIFF_INCLUDE_UNTRACKED_CONTENT) == 0))
+ return 0;
+
+ if (git_diff_delta__format_file_header(
+ pi->buf, delta, oldpfx, newpfx, pi->oid_strlen) < 0)
return -1;
if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR,
@@ -275,10 +310,10 @@ static int print_patch_file(
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))
+
+ if (diff_delta_format_with_paths(
+ pi->buf, delta, oldpfx, newpfx,
+ "Binary files %s%s and %s%s differ\n") < 0)
return -1;
if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_BINARY,
@@ -288,7 +323,7 @@ static int print_patch_file(
return 0;
}
-static int print_patch_hunk(
+static int diff_print_patch_hunk(
const git_diff_delta *d,
const git_diff_range *r,
const char *header,
@@ -311,7 +346,7 @@ static int print_patch_hunk(
return 0;
}
-static int print_patch_line(
+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 */
@@ -343,6 +378,7 @@ static int print_patch_line(
return 0;
}
+/* 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,
@@ -354,27 +390,15 @@ int git_diff_print_patch(
if (!(error = diff_print_info_init(&pi, &buf, diff, print_cb, payload)))
error = git_diff_foreach(
- diff, print_patch_file, print_patch_hunk, print_patch_line, &pi);
+ diff, diff_print_patch_file, diff_print_patch_hunk,
+ diff_print_patch_line, &pi);
git_buf_free(&buf);
return error;
}
-
-static int print_to_buffer_cb(
- const git_diff_delta *delta,
- const git_diff_range *range,
- char line_origin,
- const char *content,
- size_t content_len,
- void *payload)
-{
- git_buf *output = payload;
- GIT_UNUSED(delta); GIT_UNUSED(range); GIT_UNUSED(line_origin);
- return git_buf_put(output, content, content_len);
-}
-
+/* print a git_diff_patch to an output callback */
int git_diff_patch_print(
git_diff_patch *patch,
git_diff_data_cb print_cb,
@@ -389,13 +413,28 @@ int git_diff_patch_print(
if (!(error = diff_print_info_init(
&pi, &temp, git_diff_patch__diff(patch), print_cb, payload)))
error = git_diff_patch__invoke_callbacks(
- patch, print_patch_file, print_patch_hunk, print_patch_line, &pi);
+ patch, diff_print_patch_file, diff_print_patch_hunk,
+ diff_print_patch_line, &pi);
git_buf_free(&temp);
return error;
}
+static int diff_print_to_buffer_cb(
+ const git_diff_delta *delta,
+ const git_diff_range *range,
+ char line_origin,
+ const char *content,
+ size_t content_len,
+ void *payload)
+{
+ git_buf *output = payload;
+ GIT_UNUSED(delta); GIT_UNUSED(range); GIT_UNUSED(line_origin);
+ return git_buf_put(output, content, content_len);
+}
+
+/* print a git_diff_patch to a string buffer */
int git_diff_patch_to_str(
char **string,
git_diff_patch *patch)
@@ -403,7 +442,7 @@ int git_diff_patch_to_str(
int error;
git_buf output = GIT_BUF_INIT;
- error = git_diff_patch_print(patch, print_to_buffer_cb, &output);
+ error = git_diff_patch_print(patch, diff_print_to_buffer_cb, &output);
/* GIT_EUSER means git_buf_put in print_to_buffer_cb returned -1,
* meaning a memory allocation failure, so just map to -1...