diff options
Diffstat (limited to 'src/diff_xdiff.c')
-rw-r--r-- | src/diff_xdiff.c | 135 |
1 files changed, 105 insertions, 30 deletions
diff --git a/src/diff_xdiff.c b/src/diff_xdiff.c index 7694fb996..e0bc11f7f 100644 --- a/src/diff_xdiff.c +++ b/src/diff_xdiff.c @@ -24,26 +24,26 @@ static int git_xdiff_scan_int(const char **str, int *value) return (digits > 0) ? 0 : -1; } -static int git_xdiff_parse_hunk(git_diff_range *range, const char *header) +static int git_xdiff_parse_hunk(git_diff_hunk *hunk, const char *header) { /* expect something of the form "@@ -%d[,%d] +%d[,%d] @@" */ if (*header != '@') return -1; - if (git_xdiff_scan_int(&header, &range->old_start) < 0) + if (git_xdiff_scan_int(&header, &hunk->old_start) < 0) return -1; if (*header == ',') { - if (git_xdiff_scan_int(&header, &range->old_lines) < 0) + if (git_xdiff_scan_int(&header, &hunk->old_lines) < 0) return -1; } else - range->old_lines = 1; - if (git_xdiff_scan_int(&header, &range->new_start) < 0) + hunk->old_lines = 1; + if (git_xdiff_scan_int(&header, &hunk->new_start) < 0) return -1; if (*header == ',') { - if (git_xdiff_scan_int(&header, &range->new_lines) < 0) + if (git_xdiff_scan_int(&header, &hunk->new_lines) < 0) return -1; } else - range->new_lines = 1; - if (range->old_start < 0 || range->new_start < 0) + hunk->new_lines = 1; + if (hunk->old_start < 0 || hunk->new_start < 0) return -1; return 0; @@ -51,38 +51,104 @@ static int git_xdiff_parse_hunk(git_diff_range *range, const char *header) typedef struct { git_xdiff_output *xo; - git_diff_patch *patch; - git_diff_range range; + git_patch *patch; + git_diff_hunk hunk; + int old_lineno, new_lineno; + mmfile_t xd_old_data, xd_new_data; } git_xdiff_info; +static int diff_update_lines( + git_xdiff_info *info, + git_diff_line *line, + const char *content, + size_t content_len) +{ + const char *scan = content, *scan_end = content + content_len; + + for (line->num_lines = 0; scan < scan_end; ++scan) + if (*scan == '\n') + ++line->num_lines; + + line->content = content; + line->content_len = content_len; + + /* expect " "/"-"/"+", then data */ + switch (line->origin) { + case GIT_DIFF_LINE_ADDITION: + case GIT_DIFF_LINE_DEL_EOFNL: + line->old_lineno = -1; + line->new_lineno = info->new_lineno; + info->new_lineno += (int)line->num_lines; + break; + case GIT_DIFF_LINE_DELETION: + case GIT_DIFF_LINE_ADD_EOFNL: + line->old_lineno = info->old_lineno; + line->new_lineno = -1; + info->old_lineno += (int)line->num_lines; + break; + case GIT_DIFF_LINE_CONTEXT: + case GIT_DIFF_LINE_CONTEXT_EOFNL: + line->old_lineno = info->old_lineno; + line->new_lineno = info->new_lineno; + info->old_lineno += (int)line->num_lines; + info->new_lineno += (int)line->num_lines; + break; + default: + giterr_set(GITERR_INVALID, "Unknown diff line origin %02x", + (unsigned int)line->origin); + return -1; + } + + return 0; +} + static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len) { git_xdiff_info *info = priv; - git_diff_patch *patch = info->patch; - const git_diff_delta *delta = git_diff_patch_delta(patch); + git_patch *patch = info->patch; + const git_diff_delta *delta = git_patch_get_delta(patch); git_diff_output *output = &info->xo->output; + git_diff_line line; if (len == 1) { - output->error = git_xdiff_parse_hunk(&info->range, bufs[0].ptr); + output->error = git_xdiff_parse_hunk(&info->hunk, bufs[0].ptr); if (output->error < 0) return output->error; + info->hunk.header_len = bufs[0].size; + if (info->hunk.header_len >= sizeof(info->hunk.header)) + info->hunk.header_len = sizeof(info->hunk.header) - 1; + memcpy(info->hunk.header, bufs[0].ptr, info->hunk.header_len); + info->hunk.header[info->hunk.header_len] = '\0'; + if (output->hunk_cb != NULL && - output->hunk_cb(delta, &info->range, - bufs[0].ptr, bufs[0].size, output->payload)) + output->hunk_cb(delta, &info->hunk, output->payload)) output->error = GIT_EUSER; + + info->old_lineno = info->hunk.old_start; + info->new_lineno = info->hunk.new_start; } if (len == 2 || len == 3) { /* expect " "/"-"/"+", then data */ - char origin = + line.origin = (*bufs[0].ptr == '+') ? GIT_DIFF_LINE_ADDITION : (*bufs[0].ptr == '-') ? GIT_DIFF_LINE_DELETION : GIT_DIFF_LINE_CONTEXT; - if (output->data_cb != NULL && - output->data_cb(delta, &info->range, - origin, bufs[1].ptr, bufs[1].size, output->payload)) + if (line.origin == GIT_DIFF_LINE_ADDITION) + line.content_offset = bufs[1].ptr - info->xd_new_data.ptr; + else if (line.origin == GIT_DIFF_LINE_DELETION) + line.content_offset = bufs[1].ptr - info->xd_old_data.ptr; + else + line.content_offset = -1; + + output->error = diff_update_lines( + info, &line, bufs[1].ptr, bufs[1].size); + + if (!output->error && + output->data_cb != NULL && + output->data_cb(delta, &info->hunk, &line, output->payload)) output->error = GIT_EUSER; } @@ -92,26 +158,30 @@ static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len) * If we have a '-' and a third buf, then we have removed a line * with out a newline but added a blank line, so ADD_EOFNL. */ - char origin = + line.origin = (*bufs[0].ptr == '+') ? GIT_DIFF_LINE_DEL_EOFNL : (*bufs[0].ptr == '-') ? GIT_DIFF_LINE_ADD_EOFNL : GIT_DIFF_LINE_CONTEXT_EOFNL; - if (output->data_cb != NULL && - output->data_cb(delta, &info->range, - origin, bufs[2].ptr, bufs[2].size, output->payload)) + line.content_offset = -1; + + output->error = diff_update_lines( + info, &line, bufs[2].ptr, bufs[2].size); + + if (!output->error && + output->data_cb != NULL && + output->data_cb(delta, &info->hunk, &line, output->payload)) output->error = GIT_EUSER; } return output->error; } -static int git_xdiff(git_diff_output *output, git_diff_patch *patch) +static int git_xdiff(git_diff_output *output, git_patch *patch) { git_xdiff_output *xo = (git_xdiff_output *)output; git_xdiff_info info; git_diff_find_context_payload findctxt; - mmfile_t xd_old_data, xd_new_data; memset(&info, 0, sizeof(info)); info.patch = patch; @@ -120,7 +190,7 @@ static int git_xdiff(git_diff_output *output, git_diff_patch *patch) xo->callback.priv = &info; git_diff_find_context_init( - &xo->config.find_func, &findctxt, git_diff_patch__driver(patch)); + &xo->config.find_func, &findctxt, git_patch__driver(patch)); xo->config.find_func_priv = &findctxt; if (xo->config.find_func != NULL) @@ -132,10 +202,10 @@ static int git_xdiff(git_diff_output *output, git_diff_patch *patch) * updates are needed to xo->params.flags */ - git_diff_patch__old_data(&xd_old_data.ptr, &xd_old_data.size, patch); - git_diff_patch__new_data(&xd_new_data.ptr, &xd_new_data.size, patch); + git_patch__old_data(&info.xd_old_data.ptr, &info.xd_old_data.size, patch); + git_patch__new_data(&info.xd_new_data.ptr, &info.xd_new_data.size, patch); - xdl_diff(&xd_old_data, &xd_new_data, + xdl_diff(&info.xd_old_data, &info.xd_new_data, &xo->params, &xo->config, &xo->callback); git_diff_find_context_clear(&findctxt); @@ -145,7 +215,7 @@ static int git_xdiff(git_diff_output *output, git_diff_patch *patch) void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts) { - uint32_t flags = opts ? opts->flags : GIT_DIFF_NORMAL; + uint32_t flags = opts ? opts->flags : 0; xo->output.diff_cb = git_xdiff; @@ -161,6 +231,11 @@ void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts) if (flags & GIT_DIFF_IGNORE_WHITESPACE_EOL) xo->params.flags |= XDF_IGNORE_WHITESPACE_AT_EOL; + if (flags & GIT_DIFF_PATIENCE) + xo->params.flags |= XDF_PATIENCE_DIFF; + if (flags & GIT_DIFF_MINIMAL) + xo->params.flags |= XDF_NEED_MINIMAL; + memset(&xo->callback, 0, sizeof(xo->callback)); xo->callback.outf = git_xdiff_cb; } |