diff_parse.c 2.31 KB
Newer Older
1 2 3 4 5 6
/*
 * 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.
 */
7

8
#include "diff_parse.h"
9 10

#include "diff.h"
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
#include "patch.h"
#include "patch_parse.h"

static void diff_parsed_free(git_diff *d)
{
	git_diff_parsed *diff = (git_diff_parsed *)d;
	git_patch *patch;
	size_t i;

	git_vector_foreach(&diff->patches, i, patch)
		git_patch_free(patch);

	git_vector_free(&diff->patches);

	git_vector_free(&diff->base.deltas);
	git_pool_clear(&diff->base.pool);

	git__memzero(diff, sizeof(*diff));
	git__free(diff);
}

static git_diff_parsed *diff_parsed_alloc(void)
{
	git_diff_parsed *diff;

	if ((diff = git__calloc(1, sizeof(git_diff_parsed))) == NULL)
		return NULL;

	GIT_REFCOUNT_INC(diff);
	diff->base.type = GIT_DIFF_TYPE_PARSED;
	diff->base.strcomp = git__strcmp;
	diff->base.strncomp = git__strncmp;
	diff->base.pfxcomp = git__prefixcmp;
	diff->base.entrycomp = git_diff__entry_cmp;
45
	diff->base.patch_fn = git_patch_parsed_from_diff;
46 47
	diff->base.free_fn = diff_parsed_free;

48
	if (git_diff_init_options(&diff->base.opts, GIT_DIFF_OPTIONS_VERSION) < 0) {
49
		git__free(diff);
50 51 52
		return NULL;
	}

53 54
	diff->base.opts.flags &= ~GIT_DIFF_IGNORE_CASE;

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
	git_pool_init(&diff->base.pool, 1);

	if (git_vector_init(&diff->patches, 0, NULL) < 0 ||
		git_vector_init(&diff->base.deltas, 0, git_diff_delta__cmp) < 0) {
		git_diff_free(&diff->base);
		return NULL;
	}

	git_vector_set_cmp(&diff->base.deltas, git_diff_delta__cmp);

	return diff;
}

int git_diff_from_buffer(
	git_diff **out,
	const char *content,
	size_t content_len)
{
	git_diff_parsed *diff;
	git_patch *patch;
	git_patch_parse_ctx *ctx = NULL;
	int error = 0;

	*out = NULL;

	diff = diff_parsed_alloc();
	GITERR_CHECK_ALLOC(diff);

	ctx = git_patch_parse_ctx_init(content, content_len, NULL);
	GITERR_CHECK_ALLOC(ctx);

86
	while (ctx->parse_ctx.remain_len) {
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
		if ((error = git_patch_parse(&patch, ctx)) < 0)
			break;

		git_vector_insert(&diff->patches, patch);
		git_vector_insert(&diff->base.deltas, patch->delta);
	}

	if (error == GIT_ENOTFOUND && git_vector_length(&diff->patches) > 0) {
		giterr_clear();
		error = 0;
	}

	git_patch_parse_ctx_free(ctx);

	if (error < 0)
		git_diff_free(&diff->base);
	else
		*out = &diff->base;

	return error;
}