* 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 "git2/version.h"
-#include "common.h"
+
#include "diff.h"
+
+#include "git2/version.h"
#include "diff_generate.h"
#include "patch.h"
#include "commit.h"
#include "index.h"
-#define DIFF_FLAG_IS_SET(DIFF,FLAG) \
- (((DIFF)->opts.flags & (FLAG)) != 0)
-#define DIFF_FLAG_ISNT_SET(DIFF,FLAG) \
- (((DIFF)->opts.flags & (FLAG)) == 0)
-#define DIFF_FLAG_SET(DIFF,FLAG,VAL) (DIFF)->opts.flags = \
- (VAL) ? ((DIFF)->opts.flags | (FLAG)) : ((DIFF)->opts.flags & ~(VAL))
+struct patch_id_args {
+ git_hash_ctx ctx;
+ git_oid result;
+ int first_file;
+};
GIT_INLINE(const char *) diff_delta__path(const git_diff_delta *delta)
{
return str;
}
-const char *git_diff_delta__path(const git_diff_delta *delta)
-{
- return diff_delta__path(delta);
-}
-
int git_diff_delta__cmp(const void *a, const void *b)
{
const git_diff_delta *da = a, *db = b;
int git_diff_get_perfdata(git_diff_perfdata *out, const git_diff *diff)
{
assert(out);
- GITERR_CHECK_VERSION(out, GIT_DIFF_PERFDATA_VERSION, "git_diff_perfdata");
+ GIT_ERROR_CHECK_VERSION(out, GIT_DIFF_PERFDATA_VERSION, "git_diff_perfdata");
out->stat_calls = diff->perf.stat_calls;
out->oid_calculations = diff->perf.oid_calculations;
return 0;
}
-int git_diff_format_email__append_header_tobuf(
+int git_diff_foreach(
+ git_diff *diff,
+ git_diff_file_cb file_cb,
+ git_diff_binary_cb binary_cb,
+ git_diff_hunk_cb hunk_cb,
+ git_diff_line_cb data_cb,
+ void *payload)
+{
+ int error = 0;
+ git_diff_delta *delta;
+ size_t idx;
+
+ assert(diff);
+
+ git_vector_foreach(&diff->deltas, idx, delta) {
+ git_patch *patch;
+
+ /* check flags against patch status */
+ if (git_diff_delta__should_skip(&diff->opts, delta))
+ continue;
+
+ if ((error = git_patch_from_diff(&patch, diff, idx)) != 0)
+ break;
+
+ error = git_patch__invoke_callbacks(patch, file_cb, binary_cb,
+ hunk_cb, data_cb, payload);
+ git_patch_free(patch);
+
+ if (error)
+ break;
+ }
+
+ return error;
+}
+
+static int diff_format_email_append_header_tobuf(
git_buf *out,
const git_oid *id,
const git_signature *author,
return error;
}
-int git_diff_format_email__append_patches_tobuf(
+static int diff_format_email_append_patches_tobuf(
git_buf *out,
git_diff *diff)
{
assert(out && diff && opts);
assert(opts->summary && opts->id && opts->author);
- GITERR_CHECK_VERSION(opts,
+ GIT_ERROR_CHECK_VERSION(opts,
GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION,
"git_format_email_options");
if (!ignore_marker) {
if (opts->patch_no > opts->total_patches) {
- giterr_set(GITERR_INVALID,
+ git_error_set(GIT_ERROR_INVALID,
"patch %"PRIuZ" out of range. max %"PRIuZ,
opts->patch_no, opts->total_patches);
return -1;
}
if (opts->patch_no == 0) {
- giterr_set(GITERR_INVALID,
+ git_error_set(GIT_ERROR_INVALID,
"invalid patch no %"PRIuZ". should be >0", opts->patch_no);
return -1;
}
size_t offset = 0;
if ((offset = (loc - opts->summary)) == 0) {
- giterr_set(GITERR_INVALID, "summary is empty");
+ git_error_set(GIT_ERROR_INVALID, "summary is empty");
error = -1;
goto on_error;
}
- GITERR_CHECK_ALLOC_ADD(&allocsize, offset, 1);
+ GIT_ERROR_CHECK_ALLOC_ADD(&allocsize, offset, 1);
summary = git__calloc(allocsize, sizeof(char));
- GITERR_CHECK_ALLOC(summary);
+ GIT_ERROR_CHECK_ALLOC(summary);
strncpy(summary, opts->summary, offset);
}
- error = git_diff_format_email__append_header_tobuf(out,
+ error = diff_format_email_append_header_tobuf(out,
opts->id, opts->author, summary == NULL ? opts->summary : summary,
opts->body, opts->patch_no, opts->total_patches, ignore_marker);
(error = git_diff_get_stats(&stats, diff)) < 0 ||
(error = git_diff_stats_to_buf(out, stats, format_flags, 0)) < 0 ||
(error = git_buf_putc(out, '\n')) < 0 ||
- (error = git_diff_format_email__append_patches_tobuf(out, diff)) < 0)
+ (error = diff_format_email_append_patches_tobuf(out, diff)) < 0)
goto on_error;
error = git_buf_puts(out, "--\nlibgit2 " LIBGIT2_VERSION "\n\n");
git_commit *commit,
size_t patch_no,
size_t total_patches,
- git_diff_format_email_flags_t flags,
+ uint32_t flags,
const git_diff_options *diff_opts)
{
git_diff *diff = NULL;
return error;
}
-int git_diff_init_options(git_diff_options *opts, unsigned int version)
+int git_diff_options_init(git_diff_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_diff_options, GIT_DIFF_OPTIONS_INIT);
return 0;
}
-int git_diff_find_init_options(
+#ifndef GIT_DEPRECATE_HARD
+int git_diff_init_options(git_diff_options *opts, unsigned int version)
+{
+ return git_diff_options_init(opts, version);
+}
+#endif
+
+int git_diff_find_options_init(
git_diff_find_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
return 0;
}
-int git_diff_format_email_init_options(
+#ifndef GIT_DEPRECATE_HARD
+int git_diff_find_init_options(
+ git_diff_find_options *opts, unsigned int version)
+{
+ return git_diff_find_options_init(opts, version);
+}
+#endif
+
+int git_diff_format_email_options_init(
git_diff_format_email_options *opts, unsigned int version)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
return 0;
}
+#ifndef GIT_DEPRECATE_HARD
+int git_diff_format_email_init_options(
+ git_diff_format_email_options *opts, unsigned int version)
+{
+ return git_diff_format_email_options_init(opts, version);
+}
+#endif
+
+static int flush_hunk(git_oid *result, git_hash_ctx *ctx)
+{
+ git_oid hash;
+ unsigned short carry = 0;
+ int error, i;
+
+ if ((error = git_hash_final(&hash, ctx)) < 0 ||
+ (error = git_hash_init(ctx)) < 0)
+ return error;
+
+ for (i = 0; i < GIT_OID_RAWSZ; i++) {
+ carry += result->id[i] + hash.id[i];
+ result->id[i] = (unsigned char)carry;
+ carry >>= 8;
+ }
+
+ return 0;
+}
+
+static void strip_spaces(git_buf *buf)
+{
+ char *src = buf->ptr, *dst = buf->ptr;
+ char c;
+ size_t len = 0;
+
+ while ((c = *src++) != '\0') {
+ if (!git__isspace(c)) {
+ *dst++ = c;
+ len++;
+ }
+ }
+
+ git_buf_truncate(buf, len);
+}
+
+static int diff_patchid_print_callback_to_buf(
+ const git_diff_delta *delta,
+ const git_diff_hunk *hunk,
+ const git_diff_line *line,
+ void *payload)
+{
+ struct patch_id_args *args = (struct patch_id_args *) payload;
+ git_buf buf = GIT_BUF_INIT;
+ int error = 0;
+
+ if (line->origin == GIT_DIFF_LINE_CONTEXT_EOFNL ||
+ line->origin == GIT_DIFF_LINE_ADD_EOFNL ||
+ line->origin == GIT_DIFF_LINE_DEL_EOFNL)
+ goto out;
+
+ if ((error = git_diff_print_callback__to_buf(delta, hunk,
+ line, &buf)) < 0)
+ goto out;
+
+ strip_spaces(&buf);
+
+ if (line->origin == GIT_DIFF_LINE_FILE_HDR &&
+ !args->first_file &&
+ (error = flush_hunk(&args->result, &args->ctx) < 0))
+ goto out;
+
+ if ((error = git_hash_update(&args->ctx, buf.ptr, buf.size)) < 0)
+ goto out;
+
+ if (line->origin == GIT_DIFF_LINE_FILE_HDR && args->first_file)
+ args->first_file = 0;
+
+out:
+ git_buf_dispose(&buf);
+ return error;
+}
+
+int git_diff_patchid_options_init(git_diff_patchid_options *opts, unsigned int version)
+{
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(
+ opts, version, git_diff_patchid_options, GIT_DIFF_PATCHID_OPTIONS_INIT);
+ return 0;
+}
+
+int git_diff_patchid(git_oid *out, git_diff *diff, git_diff_patchid_options *opts)
+{
+ struct patch_id_args args;
+ int error;
+
+ GIT_ERROR_CHECK_VERSION(
+ opts, GIT_DIFF_PATCHID_OPTIONS_VERSION, "git_diff_patchid_options");
+
+ memset(&args, 0, sizeof(args));
+ args.first_file = 1;
+ if ((error = git_hash_ctx_init(&args.ctx)) < 0)
+ goto out;
+
+ if ((error = git_diff_print(diff,
+ GIT_DIFF_FORMAT_PATCH_ID,
+ diff_patchid_print_callback_to_buf,
+ &args)) < 0)
+ goto out;
+
+ if ((error = (flush_hunk(&args.result, &args.ctx))) < 0)
+ goto out;
+
+ git_oid_cpy(out, &args.result);
+
+out:
+ git_hash_ctx_cleanup(&args.ctx);
+ return error;
+}