Commit 17572f67 by Edward Thomson

git_patch_parse_ctx: refcount the context

parent 9be638ec
...@@ -61,21 +61,6 @@ typedef struct { ...@@ -61,21 +61,6 @@ typedef struct {
#define GIT_PATCH_OPTIONS_INIT { 1 } #define GIT_PATCH_OPTIONS_INIT { 1 }
/**
* Create a patch for a single file from the contents of a patch buffer.
*
* @param out The patch to be created
* @param contents The contents of a patch file
* @param contents_len The length of the patch file
* @param opts The git_patch_options
* @return 0 on success, <0 on failure.
*/
extern int git_patch_from_buffer(
git_patch **out,
const char *contents,
size_t contents_len,
git_patch_options *opts);
extern void git_patch_free(git_patch *patch); extern void git_patch_free(git_patch *patch);
#endif #endif
/*
* 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.
*/
#include "git2/patch.h" #include "git2/patch.h"
#include "patch.h" #include "patch.h"
#include "path.h" #include "path.h"
...@@ -6,13 +12,24 @@ ...@@ -6,13 +12,24 @@
( giterr_set(GITERR_PATCH, __VA_ARGS__), -1 ) ( giterr_set(GITERR_PATCH, __VA_ARGS__), -1 )
typedef struct { typedef struct {
git_patch base; git_refcount rc;
const char *content;
size_t content_len;
git_patch_options opts; git_patch_options opts;
/* the patch contents, which lines will point into. */ const char *line;
/* TODO: allow us to point somewhere refcounted. */ size_t line_len;
char *content; size_t line_num;
size_t remain;
} git_patch_parse_ctx;
typedef struct {
git_patch base;
git_patch_parse_ctx *ctx;
/* the paths from the `diff --git` header, these will be used if this is not /* the paths from the `diff --git` header, these will be used if this is not
* a rename (and rename paths are specified) or if no `+++`/`---` line specify * a rename (and rename paths are specified) or if no `+++`/`---` line specify
...@@ -30,20 +47,9 @@ typedef struct { ...@@ -30,20 +47,9 @@ typedef struct {
char *old_prefix, *new_prefix; char *old_prefix, *new_prefix;
} git_patch_parsed; } git_patch_parsed;
typedef struct {
const char *content;
size_t content_len;
const char *line;
size_t line_len;
size_t line_num;
size_t remain;
} patch_parse_ctx;
GIT_INLINE(bool) parse_ctx_contains( GIT_INLINE(bool) parse_ctx_contains(
patch_parse_ctx *ctx, const char *str, size_t len) git_patch_parse_ctx *ctx, const char *str, size_t len)
{ {
return (ctx->line_len >= len && memcmp(ctx->line, str, len) == 0); return (ctx->line_len >= len && memcmp(ctx->line, str, len) == 0);
} }
...@@ -51,7 +57,7 @@ GIT_INLINE(bool) parse_ctx_contains( ...@@ -51,7 +57,7 @@ GIT_INLINE(bool) parse_ctx_contains(
#define parse_ctx_contains_s(ctx, str) \ #define parse_ctx_contains_s(ctx, str) \
parse_ctx_contains(ctx, str, sizeof(str) - 1) parse_ctx_contains(ctx, str, sizeof(str) - 1)
static void parse_advance_line(patch_parse_ctx *ctx) static void parse_advance_line(git_patch_parse_ctx *ctx)
{ {
ctx->line += ctx->line_len; ctx->line += ctx->line_len;
ctx->remain -= ctx->line_len; ctx->remain -= ctx->line_len;
...@@ -59,7 +65,7 @@ static void parse_advance_line(patch_parse_ctx *ctx) ...@@ -59,7 +65,7 @@ static void parse_advance_line(patch_parse_ctx *ctx)
ctx->line_num++; ctx->line_num++;
} }
static void parse_advance_chars(patch_parse_ctx *ctx, size_t char_cnt) static void parse_advance_chars(git_patch_parse_ctx *ctx, size_t char_cnt)
{ {
ctx->line += char_cnt; ctx->line += char_cnt;
ctx->remain -= char_cnt; ctx->remain -= char_cnt;
...@@ -67,7 +73,7 @@ static void parse_advance_chars(patch_parse_ctx *ctx, size_t char_cnt) ...@@ -67,7 +73,7 @@ static void parse_advance_chars(patch_parse_ctx *ctx, size_t char_cnt)
} }
static int parse_advance_expected( static int parse_advance_expected(
patch_parse_ctx *ctx, git_patch_parse_ctx *ctx,
const char *expected, const char *expected,
size_t expected_len) size_t expected_len)
{ {
...@@ -84,7 +90,7 @@ static int parse_advance_expected( ...@@ -84,7 +90,7 @@ static int parse_advance_expected(
#define parse_advance_expected_s(ctx, str) \ #define parse_advance_expected_s(ctx, str) \
parse_advance_expected(ctx, str, sizeof(str) - 1) parse_advance_expected(ctx, str, sizeof(str) - 1)
static int parse_advance_ws(patch_parse_ctx *ctx) static int parse_advance_ws(git_patch_parse_ctx *ctx)
{ {
int ret = -1; int ret = -1;
...@@ -100,7 +106,7 @@ static int parse_advance_ws(patch_parse_ctx *ctx) ...@@ -100,7 +106,7 @@ static int parse_advance_ws(patch_parse_ctx *ctx)
return ret; return ret;
} }
static int parse_advance_nl(patch_parse_ctx *ctx) static int parse_advance_nl(git_patch_parse_ctx *ctx)
{ {
if (ctx->line_len != 1 || ctx->line[0] != '\n') if (ctx->line_len != 1 || ctx->line[0] != '\n')
return -1; return -1;
...@@ -109,7 +115,7 @@ static int parse_advance_nl(patch_parse_ctx *ctx) ...@@ -109,7 +115,7 @@ static int parse_advance_nl(patch_parse_ctx *ctx)
return 0; return 0;
} }
static int header_path_len(patch_parse_ctx *ctx) static int header_path_len(git_patch_parse_ctx *ctx)
{ {
bool inquote = 0; bool inquote = 0;
bool quoted = (ctx->line_len > 0 && ctx->line[0] == '"'); bool quoted = (ctx->line_len > 0 && ctx->line[0] == '"');
...@@ -129,7 +135,7 @@ static int header_path_len(patch_parse_ctx *ctx) ...@@ -129,7 +135,7 @@ static int header_path_len(patch_parse_ctx *ctx)
return len; return len;
} }
static int parse_header_path_buf(git_buf *path, patch_parse_ctx *ctx) static int parse_header_path_buf(git_buf *path, git_patch_parse_ctx *ctx)
{ {
int path_len, error = 0; int path_len, error = 0;
...@@ -154,7 +160,7 @@ done: ...@@ -154,7 +160,7 @@ done:
return error; return error;
} }
static int parse_header_path(char **out, patch_parse_ctx *ctx) static int parse_header_path(char **out, git_patch_parse_ctx *ctx)
{ {
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
int error = parse_header_path_buf(&path, ctx); int error = parse_header_path_buf(&path, ctx);
...@@ -165,18 +171,18 @@ static int parse_header_path(char **out, patch_parse_ctx *ctx) ...@@ -165,18 +171,18 @@ static int parse_header_path(char **out, patch_parse_ctx *ctx)
} }
static int parse_header_git_oldpath( static int parse_header_git_oldpath(
git_patch_parsed *patch, patch_parse_ctx *ctx) git_patch_parsed *patch, git_patch_parse_ctx *ctx)
{ {
return parse_header_path(&patch->old_path, ctx); return parse_header_path(&patch->old_path, ctx);
} }
static int parse_header_git_newpath( static int parse_header_git_newpath(
git_patch_parsed *patch, patch_parse_ctx *ctx) git_patch_parsed *patch, git_patch_parse_ctx *ctx)
{ {
return parse_header_path(&patch->new_path, ctx); return parse_header_path(&patch->new_path, ctx);
} }
static int parse_header_mode(uint16_t *mode, patch_parse_ctx *ctx) static int parse_header_mode(uint16_t *mode, git_patch_parse_ctx *ctx)
{ {
const char *end; const char *end;
int32_t m; int32_t m;
...@@ -201,7 +207,7 @@ static int parse_header_mode(uint16_t *mode, patch_parse_ctx *ctx) ...@@ -201,7 +207,7 @@ static int parse_header_mode(uint16_t *mode, patch_parse_ctx *ctx)
static int parse_header_oid( static int parse_header_oid(
git_oid *oid, git_oid *oid,
int *oid_len, int *oid_len,
patch_parse_ctx *ctx) git_patch_parse_ctx *ctx)
{ {
size_t len; size_t len;
...@@ -223,7 +229,7 @@ static int parse_header_oid( ...@@ -223,7 +229,7 @@ static int parse_header_oid(
} }
static int parse_header_git_index( static int parse_header_git_index(
git_patch_parsed *patch, patch_parse_ctx *ctx) git_patch_parsed *patch, git_patch_parse_ctx *ctx)
{ {
if (parse_header_oid(&patch->base.delta->old_file.id, if (parse_header_oid(&patch->base.delta->old_file.id,
&patch->base.delta->old_file.id_abbrev, ctx) < 0 || &patch->base.delta->old_file.id_abbrev, ctx) < 0 ||
...@@ -251,20 +257,20 @@ static int parse_header_git_index( ...@@ -251,20 +257,20 @@ static int parse_header_git_index(
} }
static int parse_header_git_oldmode( static int parse_header_git_oldmode(
git_patch_parsed *patch, patch_parse_ctx *ctx) git_patch_parsed *patch, git_patch_parse_ctx *ctx)
{ {
return parse_header_mode(&patch->base.delta->old_file.mode, ctx); return parse_header_mode(&patch->base.delta->old_file.mode, ctx);
} }
static int parse_header_git_newmode( static int parse_header_git_newmode(
git_patch_parsed *patch, patch_parse_ctx *ctx) git_patch_parsed *patch, git_patch_parse_ctx *ctx)
{ {
return parse_header_mode(&patch->base.delta->new_file.mode, ctx); return parse_header_mode(&patch->base.delta->new_file.mode, ctx);
} }
static int parse_header_git_deletedfilemode( static int parse_header_git_deletedfilemode(
git_patch_parsed *patch, git_patch_parsed *patch,
patch_parse_ctx *ctx) git_patch_parse_ctx *ctx)
{ {
git__free((char *)patch->base.delta->old_file.path); git__free((char *)patch->base.delta->old_file.path);
...@@ -277,7 +283,7 @@ static int parse_header_git_deletedfilemode( ...@@ -277,7 +283,7 @@ static int parse_header_git_deletedfilemode(
static int parse_header_git_newfilemode( static int parse_header_git_newfilemode(
git_patch_parsed *patch, git_patch_parsed *patch,
patch_parse_ctx *ctx) git_patch_parse_ctx *ctx)
{ {
git__free((char *)patch->base.delta->new_file.path); git__free((char *)patch->base.delta->new_file.path);
...@@ -290,7 +296,7 @@ static int parse_header_git_newfilemode( ...@@ -290,7 +296,7 @@ static int parse_header_git_newfilemode(
static int parse_header_rename( static int parse_header_rename(
char **out, char **out,
patch_parse_ctx *ctx) git_patch_parse_ctx *ctx)
{ {
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
...@@ -305,20 +311,20 @@ static int parse_header_rename( ...@@ -305,20 +311,20 @@ static int parse_header_rename(
} }
static int parse_header_renamefrom( static int parse_header_renamefrom(
git_patch_parsed *patch, patch_parse_ctx *ctx) git_patch_parsed *patch, git_patch_parse_ctx *ctx)
{ {
patch->base.delta->status = GIT_DELTA_RENAMED; patch->base.delta->status = GIT_DELTA_RENAMED;
return parse_header_rename(&patch->rename_old_path, ctx); return parse_header_rename(&patch->rename_old_path, ctx);
} }
static int parse_header_renameto( static int parse_header_renameto(
git_patch_parsed *patch, patch_parse_ctx *ctx) git_patch_parsed *patch, git_patch_parse_ctx *ctx)
{ {
patch->base.delta->status = GIT_DELTA_RENAMED; patch->base.delta->status = GIT_DELTA_RENAMED;
return parse_header_rename(&patch->rename_new_path, ctx); return parse_header_rename(&patch->rename_new_path, ctx);
} }
static int parse_header_percent(uint16_t *out, patch_parse_ctx *ctx) static int parse_header_percent(uint16_t *out, git_patch_parse_ctx *ctx)
{ {
int32_t val; int32_t val;
const char *end; const char *end;
...@@ -340,7 +346,7 @@ static int parse_header_percent(uint16_t *out, patch_parse_ctx *ctx) ...@@ -340,7 +346,7 @@ static int parse_header_percent(uint16_t *out, patch_parse_ctx *ctx)
} }
static int parse_header_similarity( static int parse_header_similarity(
git_patch_parsed *patch, patch_parse_ctx *ctx) git_patch_parsed *patch, git_patch_parse_ctx *ctx)
{ {
if (parse_header_percent(&patch->base.delta->similarity, ctx) < 0) if (parse_header_percent(&patch->base.delta->similarity, ctx) < 0)
return parse_err("invalid similarity percentage at line %d", return parse_err("invalid similarity percentage at line %d",
...@@ -350,7 +356,7 @@ static int parse_header_similarity( ...@@ -350,7 +356,7 @@ static int parse_header_similarity(
} }
static int parse_header_dissimilarity( static int parse_header_dissimilarity(
git_patch_parsed *patch, patch_parse_ctx *ctx) git_patch_parsed *patch, git_patch_parse_ctx *ctx)
{ {
uint16_t dissimilarity; uint16_t dissimilarity;
...@@ -365,7 +371,7 @@ static int parse_header_dissimilarity( ...@@ -365,7 +371,7 @@ static int parse_header_dissimilarity(
typedef struct { typedef struct {
const char *str; const char *str;
int(*fn)(git_patch_parsed *, patch_parse_ctx *); int(*fn)(git_patch_parsed *, git_patch_parse_ctx *);
} header_git_op; } header_git_op;
static const header_git_op header_git_ops[] = { static const header_git_op header_git_ops[] = {
...@@ -388,7 +394,7 @@ static const header_git_op header_git_ops[] = { ...@@ -388,7 +394,7 @@ static const header_git_op header_git_ops[] = {
static int parse_header_git( static int parse_header_git(
git_patch_parsed *patch, git_patch_parsed *patch,
patch_parse_ctx *ctx) git_patch_parse_ctx *ctx)
{ {
size_t i; size_t i;
int error = 0; int error = 0;
...@@ -443,7 +449,7 @@ done: ...@@ -443,7 +449,7 @@ done:
return error; return error;
} }
static int parse_number(git_off_t *out, patch_parse_ctx *ctx) static int parse_number(git_off_t *out, git_patch_parse_ctx *ctx)
{ {
const char *end; const char *end;
int64_t num; int64_t num;
...@@ -463,7 +469,7 @@ static int parse_number(git_off_t *out, patch_parse_ctx *ctx) ...@@ -463,7 +469,7 @@ static int parse_number(git_off_t *out, patch_parse_ctx *ctx)
return 0; return 0;
} }
static int parse_int(int *out, patch_parse_ctx *ctx) static int parse_int(int *out, git_patch_parse_ctx *ctx)
{ {
git_off_t num; git_off_t num;
...@@ -476,7 +482,7 @@ static int parse_int(int *out, patch_parse_ctx *ctx) ...@@ -476,7 +482,7 @@ static int parse_int(int *out, patch_parse_ctx *ctx)
static int parse_hunk_header( static int parse_hunk_header(
git_patch_hunk *hunk, git_patch_hunk *hunk,
patch_parse_ctx *ctx) git_patch_parse_ctx *ctx)
{ {
const char *header_start = ctx->line; const char *header_start = ctx->line;
...@@ -530,7 +536,7 @@ fail: ...@@ -530,7 +536,7 @@ fail:
static int parse_hunk_body( static int parse_hunk_body(
git_patch_parsed *patch, git_patch_parsed *patch,
git_patch_hunk *hunk, git_patch_hunk *hunk,
patch_parse_ctx *ctx) git_patch_parse_ctx *ctx)
{ {
git_diff_line *line; git_diff_line *line;
int error = 0; int error = 0;
...@@ -621,9 +627,9 @@ done: ...@@ -621,9 +627,9 @@ done:
return error; return error;
} }
static int parsed_patch_header( static int parse_patch_header(
git_patch_parsed *patch, git_patch_parsed *patch,
patch_parse_ctx *ctx) git_patch_parse_ctx *ctx)
{ {
int error = 0; int error = 0;
...@@ -671,9 +677,9 @@ done: ...@@ -671,9 +677,9 @@ done:
return error; return error;
} }
static int parsed_patch_binary_side( static int parse_patch_binary_side(
git_diff_binary_file *binary, git_diff_binary_file *binary,
patch_parse_ctx *ctx) git_patch_parse_ctx *ctx)
{ {
git_diff_binary_t type = GIT_DIFF_BINARY_NONE; git_diff_binary_t type = GIT_DIFF_BINARY_NONE;
git_buf base85 = GIT_BUF_INIT, decoded = GIT_BUF_INIT; git_buf base85 = GIT_BUF_INIT, decoded = GIT_BUF_INIT;
...@@ -750,9 +756,9 @@ done: ...@@ -750,9 +756,9 @@ done:
return error; return error;
} }
static int parsed_patch_binary( static int parse_patch_binary(
git_patch_parsed *patch, git_patch_parsed *patch,
patch_parse_ctx *ctx) git_patch_parse_ctx *ctx)
{ {
int error; int error;
...@@ -761,7 +767,7 @@ static int parsed_patch_binary( ...@@ -761,7 +767,7 @@ static int parsed_patch_binary(
return parse_err("corrupt git binary header at line %d", ctx->line_num); return parse_err("corrupt git binary header at line %d", ctx->line_num);
/* parse old->new binary diff */ /* parse old->new binary diff */
if ((error = parsed_patch_binary_side( if ((error = parse_patch_binary_side(
&patch->base.binary.new_file, ctx)) < 0) &patch->base.binary.new_file, ctx)) < 0)
return error; return error;
...@@ -770,7 +776,7 @@ static int parsed_patch_binary( ...@@ -770,7 +776,7 @@ static int parsed_patch_binary(
ctx->line_num); ctx->line_num);
/* parse new->old binary diff */ /* parse new->old binary diff */
if ((error = parsed_patch_binary_side( if ((error = parse_patch_binary_side(
&patch->base.binary.old_file, ctx)) < 0) &patch->base.binary.old_file, ctx)) < 0)
return error; return error;
...@@ -778,9 +784,9 @@ static int parsed_patch_binary( ...@@ -778,9 +784,9 @@ static int parsed_patch_binary(
return 0; return 0;
} }
static int parsed_patch_hunks( static int parse_patch_hunks(
git_patch_parsed *patch, git_patch_parsed *patch,
patch_parse_ctx *ctx) git_patch_parse_ctx *ctx)
{ {
git_patch_hunk *hunk; git_patch_hunk *hunk;
int error = 0; int error = 0;
...@@ -803,14 +809,14 @@ done: ...@@ -803,14 +809,14 @@ done:
return error; return error;
} }
static int parsed_patch_body( static int parse_patch_body(
git_patch_parsed *patch, patch_parse_ctx *ctx) git_patch_parsed *patch, git_patch_parse_ctx *ctx)
{ {
if (parse_ctx_contains_s(ctx, "GIT binary patch")) if (parse_ctx_contains_s(ctx, "GIT binary patch"))
return parsed_patch_binary(patch, ctx); return parse_patch_binary(patch, ctx);
else if (parse_ctx_contains_s(ctx, "@@ -")) else if (parse_ctx_contains_s(ctx, "@@ -"))
return parsed_patch_hunks(patch, ctx); return parse_patch_hunks(patch, ctx);
return 0; return 0;
} }
...@@ -840,12 +846,13 @@ static int check_prefix( ...@@ -840,12 +846,13 @@ static int check_prefix(
const char *path_start) const char *path_start)
{ {
const char *path = path_start; const char *path = path_start;
uint32_t remain = patch->opts.prefix_len; size_t prefix_len = patch->ctx->opts.prefix_len;
size_t remain = prefix_len;
*out = NULL; *out = NULL;
*out_len = 0; *out_len = 0;
if (patch->opts.prefix_len == 0) if (prefix_len == 0)
goto done; goto done;
/* leading slashes do not count as part of the prefix in git apply */ /* leading slashes do not count as part of the prefix in git apply */
...@@ -860,8 +867,9 @@ static int check_prefix( ...@@ -860,8 +867,9 @@ static int check_prefix(
} }
if (remain || !*path) if (remain || !*path)
return parse_err("header filename does not contain %d path components", return parse_err(
patch->opts.prefix_len); "header filename does not contain %d path components",
prefix_len);
done: done:
*out_len = (path - path_start); *out_len = (path - path_start);
...@@ -938,6 +946,50 @@ static int check_patch(git_patch_parsed *patch) ...@@ -938,6 +946,50 @@ static int check_patch(git_patch_parsed *patch)
return 0; return 0;
} }
static git_patch_parse_ctx *git_patch_parse_ctx_init(
const char *content,
size_t content_len,
const git_patch_options *opts)
{
git_patch_parse_ctx *ctx;
git_patch_options default_opts = GIT_PATCH_OPTIONS_INIT;
if ((ctx = git__calloc(1, sizeof(git_patch_parse_ctx))) == NULL)
return NULL;
if (content_len) {
if ((ctx->content = git__malloc(content_len)) == NULL)
return NULL;
memcpy((char *)ctx->content, content, content_len);
}
ctx->content_len = content_len;
ctx->remain = content_len;
if (opts)
memcpy(&ctx->opts, opts, sizeof(git_patch_options));
else
memcpy(&ctx->opts, &default_opts, sizeof(git_patch_options));
GIT_REFCOUNT_INC(ctx);
return ctx;
}
static void patch_parse_ctx_free(git_patch_parse_ctx *ctx)
{
if (!ctx)
return;
git__free((char *)ctx->content);
git__free(ctx);
}
static void git_patch_parse_ctx_free(git_patch_parse_ctx *ctx)
{
GIT_REFCOUNT_DEC(ctx, patch_parse_ctx_free);
}
static void patch_parsed__free(git_patch *p) static void patch_parsed__free(git_patch *p)
{ {
git_patch_parsed *patch = (git_patch_parsed *)p; git_patch_parsed *patch = (git_patch_parsed *)p;
...@@ -945,6 +997,8 @@ static void patch_parsed__free(git_patch *p) ...@@ -945,6 +997,8 @@ static void patch_parsed__free(git_patch *p)
if (!patch) if (!patch)
return; return;
git_patch_parse_ctx_free(patch->ctx);
git__free((char *)patch->base.binary.old_file.data); git__free((char *)patch->base.binary.old_file.data);
git__free((char *)patch->base.binary.new_file.data); git__free((char *)patch->base.binary.new_file.data);
git_array_clear(patch->base.hunks); git_array_clear(patch->base.hunks);
...@@ -959,30 +1013,25 @@ static void patch_parsed__free(git_patch *p) ...@@ -959,30 +1013,25 @@ static void patch_parsed__free(git_patch *p)
git__free(patch->rename_new_path); git__free(patch->rename_new_path);
git__free(patch->old_path); git__free(patch->old_path);
git__free(patch->new_path); git__free(patch->new_path);
git__free(patch->content);
git__free(patch); git__free(patch);
} }
int git_patch_from_buffer( static int git_patch_parse(
git_patch **out, git_patch **out,
const char *content, git_patch_parse_ctx *ctx)
size_t content_len,
git_patch_options *opts)
{ {
patch_parse_ctx ctx = { 0 };
git_patch_parsed *patch; git_patch_parsed *patch;
git_patch_options default_opts = GIT_PATCH_OPTIONS_INIT;
int error = 0; int error = 0;
assert(out && ctx);
*out = NULL; *out = NULL;
patch = git__calloc(1, sizeof(git_patch_parsed)); patch = git__calloc(1, sizeof(git_patch_parsed));
GITERR_CHECK_ALLOC(patch); GITERR_CHECK_ALLOC(patch);
if (opts) patch->ctx = ctx;
memcpy(&patch->opts, opts, sizeof(git_patch_options)); GIT_REFCOUNT_INC(patch->ctx);
else
memcpy(&patch->opts, &default_opts, sizeof(git_patch_options));
patch->base.free_fn = patch_parsed__free; patch->base.free_fn = patch_parsed__free;
...@@ -992,19 +1041,8 @@ int git_patch_from_buffer( ...@@ -992,19 +1041,8 @@ int git_patch_from_buffer(
patch->base.delta->status = GIT_DELTA_MODIFIED; patch->base.delta->status = GIT_DELTA_MODIFIED;
patch->base.delta->nfiles = 2; patch->base.delta->nfiles = 2;
if (content_len) { if ((error = parse_patch_header(patch, ctx)) < 0 ||
patch->content = git__malloc(content_len); (error = parse_patch_body(patch, ctx)) < 0 ||
GITERR_CHECK_ALLOC(patch->content);
memcpy(patch->content, content, content_len);
}
ctx.content = patch->content;
ctx.content_len = content_len;
ctx.remain = content_len;
if ((error = parsed_patch_header(patch, &ctx)) < 0 ||
(error = parsed_patch_body(patch, &ctx)) < 0 ||
(error = check_patch(patch)) < 0) (error = check_patch(patch)) < 0)
goto done; goto done;
...@@ -1021,3 +1059,22 @@ done: ...@@ -1021,3 +1059,22 @@ done:
return error; return error;
} }
int git_patch_from_buffer(
git_patch **out,
const char *content,
size_t content_len,
const git_patch_options *opts)
{
git_patch_parse_ctx *ctx;
int error;
ctx = git_patch_parse_ctx_init(content, content_len, opts);
GITERR_CHECK_ALLOC(ctx);
error = git_patch_parse(out, ctx);
git_patch_parse_ctx_free(ctx);
return error;
}
/*
* 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_patch_parse_h__
#define INCLUDE_patch_parse_h__
/**
* Create a patch for a single file from the contents of a patch buffer.
*
* @param out The patch to be created
* @param contents The contents of a patch file
* @param contents_len The length of the patch file
* @param opts The git_patch_options
* @return 0 on success, <0 on failure.
*/
extern int git_patch_from_buffer(
git_patch **out,
const char *contents,
size_t contents_len,
const git_patch_options *opts);
#endif
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "apply.h" #include "apply.h"
#include "patch.h" #include "patch.h"
#include "patch_parse.h"
#include "repository.h" #include "repository.h"
#include "buf_text.h" #include "buf_text.h"
......
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "patch.h" #include "patch.h"
#include "patch_parse.h"
#include "patch_common.h" #include "patch_common.h"
......
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "patch.h" #include "patch.h"
#include "patch_parse.h"
#include "patch_common.h" #include "patch_common.h"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment