Commit 27e54bcf82fe27bdfadbaa9c5383ee8a948ea33c

Russell Belfer 2014-02-07T14:17:19

Add public diff print helpers The usefulness of these helpers came up for me while debugging some of the iterator changes that I was making, so since they have also been requested (albeit indirectly) I thought I'd include them.

diff --git a/include/git2/sys/diff.h b/include/git2/sys/diff.h
new file mode 100644
index 0000000..bc6cdf3
--- /dev/null
+++ b/include/git2/sys/diff.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_sys_git_diff_h__
+#define INCLUDE_sys_git_diff_h__
+
+#include "git2/common.h"
+#include "git2/types.h"
+#include "git2/oid.h"
+
+/**
+ * @file git2/sys/diff.h
+ * @brief Low-level Git diff utilities
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * Diff print callback that writes to a git_buf.
+ *
+ * This function is provided not for you to call it directly, but instead
+ * so you can use it as a function pointer to the `git_diff_print` or
+ * `git_patch_print` APIs.  When using those APIs, you specify a callback
+ * to actually handle the diff and/or patch data.
+ *
+ * Use this callback to easily write that data to a `git_buf` buffer.  You
+ * must pass a `git_buf *` value as the payload to the `git_diff_print`
+ * and/or `git_patch_print` function.  The data will be appended to the
+ * buffer (after any existing content).
+ */
+GIT_EXTERN(int) git_diff_print_callback__to_buf(
+	const git_diff_delta *delta,
+	const git_diff_hunk *hunk,
+	const git_diff_line *line,
+	void *payload); /*< payload must be a `git_buf *` */
+
+/**
+ * Diff print callback that writes to stdio FILE handle.
+ *
+ * This function is provided not for you to call it directly, but instead
+ * so you can use it as a function pointer to the `git_diff_print` or
+ * `git_patch_print` APIs.  When using those APIs, you specify a callback
+ * to actually handle the diff and/or patch data.
+ *
+ * Use this callback to easily write that data to a stdio FILE handle.  You
+ * must pass a `FILE *` value (such as `stdout` or `stderr` or the return
+ * value from `fopen()`) as the payload to the `git_diff_print`
+ * and/or `git_patch_print` function.  If you pass NULL, this will write
+ * data to `stdout`.
+ */
+GIT_EXTERN(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); /*< payload must be a `FILE *` */
+
+/** @} */
+GIT_END_DECL
+#endif
diff --git a/src/diff_print.c b/src/diff_print.c
index 1a09bed..a7f7b6f 100644
--- a/src/diff_print.c
+++ b/src/diff_print.c
@@ -8,6 +8,7 @@
 #include "diff.h"
 #include "diff_patch.h"
 #include "fileops.h"
+#include "git2/sys/diff.h"
 
 typedef struct {
 	git_diff *diff;
@@ -435,7 +436,7 @@ int git_patch_print(
 	return error;
 }
 
-static int diff_print_to_buffer_cb(
+int git_diff_print_callback__to_buf(
 	const git_diff_delta *delta,
 	const git_diff_hunk *hunk,
 	const git_diff_line *line,
@@ -444,6 +445,11 @@ static int diff_print_to_buffer_cb(
 	git_buf *output = payload;
 	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)
@@ -452,10 +458,28 @@ static int diff_print_to_buffer_cb(
 	return git_buf_put(output, line->content, line->content_len);
 }
 
+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)
+{
+	FILE *fp = payload ? payload : stdout;
+
+	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);
+	return 0;
+}
+
 /* print a git_patch to a git_buf */
 int git_patch_to_buf(
 	git_buf *out,
 	git_patch *patch)
 {
-	return git_patch_print(patch, diff_print_to_buffer_cb, out);
+	return git_patch_print(patch, git_diff_print_callback__to_buf, out);
 }
diff --git a/tests/diff/diff_helpers.c b/tests/diff/diff_helpers.c
index 33bb561..279cb20 100644
--- a/tests/diff/diff_helpers.c
+++ b/tests/diff/diff_helpers.c
@@ -1,5 +1,6 @@
 #include "clar_libgit2.h"
 #include "diff_helpers.h"
+#include "git2/sys/diff.h"
 
 git_tree *resolve_commit_oid_to_tree(
 	git_repository *repo,
@@ -215,32 +216,16 @@ abort:
 	return GIT_EUSER;
 }
 
-static int diff_print_cb(
-	const git_diff_delta *delta,
-	const git_diff_hunk *hunk,
-	const git_diff_line *line,
-	void *payload)
-{
-	FILE *fp = payload;
-
-	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);
-	return 0;
-}
-
 void diff_print(FILE *fp, git_diff *diff)
 {
-	cl_git_pass(git_diff_print(
-		diff, GIT_DIFF_FORMAT_PATCH, diff_print_cb, fp ? fp : stderr));
+	cl_git_pass(
+		git_diff_print(diff, GIT_DIFF_FORMAT_PATCH,
+			git_diff_print_callback__to_file_handle, fp ? fp : stderr));
 }
 
 void diff_print_raw(FILE *fp, git_diff *diff)
 {
-	cl_git_pass(git_diff_print(
-		diff, GIT_DIFF_FORMAT_RAW, diff_print_cb, fp ? fp : stderr));
+	cl_git_pass(
+		git_diff_print(diff, GIT_DIFF_FORMAT_RAW,
+			git_diff_print_callback__to_file_handle, fp ? fp : stderr));
 }