Merge branch 'ab/pickaxe-pcre2'
Rewrite the backend for "diff -G/-S" to use pcre2 engine when available. * ab/pickaxe-pcre2: (22 commits) xdiff-interface: replace discard_hunk_line() with a flag xdiff users: use designated initializers for out_line pickaxe -G: don't special-case create/delete pickaxe -G: terminate early on matching lines xdiff-interface: allow early return from xdiff_emit_line_fn xdiff-interface: prepare for allowing early return pickaxe -S: slightly optimize contains() pickaxe: rename variables in has_changes() for brevity pickaxe -S: support content with NULs under --pickaxe-regex pickaxe: assert that we must have a needle under -G or -S pickaxe: refactor function selection in diffcore-pickaxe() perf: add performance test for pickaxe pickaxe/style: consolidate declarations and assignments diff.h: move pickaxe fields together again pickaxe: die when --find-object and --pickaxe-all are combined pickaxe: die when -G and --pickaxe-regex are combined pickaxe tests: add missing test for --no-pickaxe-regex being an error pickaxe tests: test for -G, -S and --find-object incompatibility pickaxe tests: add test for "log -S" not being a regex pickaxe tests: add test for diffgrep_consume() internals ...
This commit is contained in:
commit
4da281e84d
@ -107,15 +107,12 @@ static void show_diff(struct merge_list *entry)
|
|||||||
mmfile_t src, dst;
|
mmfile_t src, dst;
|
||||||
xpparam_t xpp;
|
xpparam_t xpp;
|
||||||
xdemitconf_t xecfg;
|
xdemitconf_t xecfg;
|
||||||
xdemitcb_t ecb;
|
xdemitcb_t ecb = { .out_line = show_outf };
|
||||||
|
|
||||||
memset(&xpp, 0, sizeof(xpp));
|
memset(&xpp, 0, sizeof(xpp));
|
||||||
xpp.flags = 0;
|
xpp.flags = 0;
|
||||||
memset(&xecfg, 0, sizeof(xecfg));
|
memset(&xecfg, 0, sizeof(xecfg));
|
||||||
xecfg.ctxlen = 3;
|
xecfg.ctxlen = 3;
|
||||||
ecb.out_hunk = NULL;
|
|
||||||
ecb.out_line = show_outf;
|
|
||||||
ecb.priv = NULL;
|
|
||||||
|
|
||||||
src.ptr = origin(entry, &size);
|
src.ptr = origin(entry, &size);
|
||||||
if (!src.ptr)
|
if (!src.ptr)
|
||||||
|
@ -28,7 +28,7 @@ static int diff_two(const char *file1, const char *label1,
|
|||||||
{
|
{
|
||||||
xpparam_t xpp;
|
xpparam_t xpp;
|
||||||
xdemitconf_t xecfg;
|
xdemitconf_t xecfg;
|
||||||
xdemitcb_t ecb;
|
xdemitcb_t ecb = { .out_line = outf };
|
||||||
mmfile_t minus, plus;
|
mmfile_t minus, plus;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -41,8 +41,6 @@ static int diff_two(const char *file1, const char *label1,
|
|||||||
xpp.flags = 0;
|
xpp.flags = 0;
|
||||||
memset(&xecfg, 0, sizeof(xecfg));
|
memset(&xecfg, 0, sizeof(xecfg));
|
||||||
xecfg.ctxlen = 3;
|
xecfg.ctxlen = 3;
|
||||||
ecb.out_hunk = NULL;
|
|
||||||
ecb.out_line = outf;
|
|
||||||
ret = xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
|
ret = xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
|
||||||
|
|
||||||
free(minus.ptr);
|
free(minus.ptr);
|
||||||
|
@ -403,11 +403,11 @@ static void consume_hunk(void *state_,
|
|||||||
state->sline[state->nb-1].p_lno[state->n] = state->ob;
|
state->sline[state->nb-1].p_lno[state->n] = state->ob;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void consume_line(void *state_, char *line, unsigned long len)
|
static int consume_line(void *state_, char *line, unsigned long len)
|
||||||
{
|
{
|
||||||
struct combine_diff_state *state = state_;
|
struct combine_diff_state *state = state_;
|
||||||
if (!state->lost_bucket)
|
if (!state->lost_bucket)
|
||||||
return; /* not in any hunk yet */
|
return 0; /* not in any hunk yet */
|
||||||
switch (line[0]) {
|
switch (line[0]) {
|
||||||
case '-':
|
case '-':
|
||||||
append_lost(state->lost_bucket, state->n, line+1, len-1);
|
append_lost(state->lost_bucket, state->n, line+1, len-1);
|
||||||
@ -417,6 +417,7 @@ static void consume_line(void *state_, char *line, unsigned long len)
|
|||||||
state->lno++;
|
state->lno++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void combine_diff(struct repository *r,
|
static void combine_diff(struct repository *r,
|
||||||
|
39
diff.c
39
diff.c
@ -2340,7 +2340,7 @@ static void find_lno(const char *line, struct emit_callback *ecbdata)
|
|||||||
ecbdata->lno_in_postimage = strtol(p + 1, NULL, 10);
|
ecbdata->lno_in_postimage = strtol(p + 1, NULL, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fn_out_consume(void *priv, char *line, unsigned long len)
|
static int fn_out_consume(void *priv, char *line, unsigned long len)
|
||||||
{
|
{
|
||||||
struct emit_callback *ecbdata = priv;
|
struct emit_callback *ecbdata = priv;
|
||||||
struct diff_options *o = ecbdata->opt;
|
struct diff_options *o = ecbdata->opt;
|
||||||
@ -2376,7 +2376,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
|||||||
len = sane_truncate_line(line, len);
|
len = sane_truncate_line(line, len);
|
||||||
find_lno(line, ecbdata);
|
find_lno(line, ecbdata);
|
||||||
emit_hunk_header(ecbdata, line, len);
|
emit_hunk_header(ecbdata, line, len);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ecbdata->diff_words) {
|
if (ecbdata->diff_words) {
|
||||||
@ -2386,11 +2386,11 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
|||||||
if (line[0] == '-') {
|
if (line[0] == '-') {
|
||||||
diff_words_append(line, len,
|
diff_words_append(line, len,
|
||||||
&ecbdata->diff_words->minus);
|
&ecbdata->diff_words->minus);
|
||||||
return;
|
return 0;
|
||||||
} else if (line[0] == '+') {
|
} else if (line[0] == '+') {
|
||||||
diff_words_append(line, len,
|
diff_words_append(line, len,
|
||||||
&ecbdata->diff_words->plus);
|
&ecbdata->diff_words->plus);
|
||||||
return;
|
return 0;
|
||||||
} else if (starts_with(line, "\\ ")) {
|
} else if (starts_with(line, "\\ ")) {
|
||||||
/*
|
/*
|
||||||
* Eat the "no newline at eof" marker as if we
|
* Eat the "no newline at eof" marker as if we
|
||||||
@ -2399,11 +2399,11 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
|||||||
* defer processing. If this is the end of
|
* defer processing. If this is the end of
|
||||||
* preimage, more "+" lines may come after it.
|
* preimage, more "+" lines may come after it.
|
||||||
*/
|
*/
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
diff_words_flush(ecbdata);
|
diff_words_flush(ecbdata);
|
||||||
emit_diff_symbol(o, s, line, len, 0);
|
emit_diff_symbol(o, s, line, len, 0);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (line[0]) {
|
switch (line[0]) {
|
||||||
@ -2427,6 +2427,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
|
|||||||
line, len, 0);
|
line, len, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pprint_rename(struct strbuf *name, const char *a, const char *b)
|
static void pprint_rename(struct strbuf *name, const char *a, const char *b)
|
||||||
@ -2526,7 +2527,7 @@ static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat,
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void diffstat_consume(void *priv, char *line, unsigned long len)
|
static int diffstat_consume(void *priv, char *line, unsigned long len)
|
||||||
{
|
{
|
||||||
struct diffstat_t *diffstat = priv;
|
struct diffstat_t *diffstat = priv;
|
||||||
struct diffstat_file *x = diffstat->files[diffstat->nr - 1];
|
struct diffstat_file *x = diffstat->files[diffstat->nr - 1];
|
||||||
@ -2535,6 +2536,7 @@ static void diffstat_consume(void *priv, char *line, unsigned long len)
|
|||||||
x->added++;
|
x->added++;
|
||||||
else if (line[0] == '-')
|
else if (line[0] == '-')
|
||||||
x->deleted++;
|
x->deleted++;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char mime_boundary_leader[] = "------------";
|
const char mime_boundary_leader[] = "------------";
|
||||||
@ -3212,7 +3214,7 @@ static void checkdiff_consume_hunk(void *priv,
|
|||||||
data->lineno = nb - 1;
|
data->lineno = nb - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkdiff_consume(void *priv, char *line, unsigned long len)
|
static int checkdiff_consume(void *priv, char *line, unsigned long len)
|
||||||
{
|
{
|
||||||
struct checkdiff_t *data = priv;
|
struct checkdiff_t *data = priv;
|
||||||
int marker_size = data->conflict_marker_size;
|
int marker_size = data->conflict_marker_size;
|
||||||
@ -3236,7 +3238,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
|
|||||||
}
|
}
|
||||||
bad = ws_check(line + 1, len - 1, data->ws_rule);
|
bad = ws_check(line + 1, len - 1, data->ws_rule);
|
||||||
if (!bad)
|
if (!bad)
|
||||||
return;
|
return 0;
|
||||||
data->status |= bad;
|
data->status |= bad;
|
||||||
err = whitespace_error_string(bad);
|
err = whitespace_error_string(bad);
|
||||||
fprintf(data->o->file, "%s%s:%d: %s.\n",
|
fprintf(data->o->file, "%s%s:%d: %s.\n",
|
||||||
@ -3248,6 +3250,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
|
|||||||
} else if (line[0] == ' ') {
|
} else if (line[0] == ' ') {
|
||||||
data->lineno++;
|
data->lineno++;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char *deflate_it(char *data,
|
static unsigned char *deflate_it(char *data,
|
||||||
@ -3726,7 +3729,8 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
|
|||||||
xpp.anchors_nr = o->anchors_nr;
|
xpp.anchors_nr = o->anchors_nr;
|
||||||
xecfg.ctxlen = o->context;
|
xecfg.ctxlen = o->context;
|
||||||
xecfg.interhunkctxlen = o->interhunkcontext;
|
xecfg.interhunkctxlen = o->interhunkcontext;
|
||||||
if (xdi_diff_outf(&mf1, &mf2, discard_hunk_line,
|
xecfg.flags = XDL_EMIT_NO_HUNK_HDR;
|
||||||
|
if (xdi_diff_outf(&mf1, &mf2, NULL,
|
||||||
diffstat_consume, diffstat, &xpp, &xecfg))
|
diffstat_consume, diffstat, &xpp, &xecfg))
|
||||||
die("unable to generate diffstat for %s", one->path);
|
die("unable to generate diffstat for %s", one->path);
|
||||||
|
|
||||||
@ -4632,6 +4636,12 @@ void diff_setup_done(struct diff_options *options)
|
|||||||
if (HAS_MULTI_BITS(options->pickaxe_opts & DIFF_PICKAXE_KINDS_MASK))
|
if (HAS_MULTI_BITS(options->pickaxe_opts & DIFF_PICKAXE_KINDS_MASK))
|
||||||
die(_("-G, -S and --find-object are mutually exclusive"));
|
die(_("-G, -S and --find-object are mutually exclusive"));
|
||||||
|
|
||||||
|
if (HAS_MULTI_BITS(options->pickaxe_opts & DIFF_PICKAXE_KINDS_G_REGEX_MASK))
|
||||||
|
die(_("-G and --pickaxe-regex are mutually exclusive, use --pickaxe-regex with -S"));
|
||||||
|
|
||||||
|
if (HAS_MULTI_BITS(options->pickaxe_opts & DIFF_PICKAXE_KINDS_ALL_OBJFIND_MASK))
|
||||||
|
die(_("---pickaxe-all and --find-object are mutually exclusive, use --pickaxe-all with -G and -S"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Most of the time we can say "there are changes"
|
* Most of the time we can say "there are changes"
|
||||||
* only by checking if there are changed paths, but
|
* only by checking if there are changed paths, but
|
||||||
@ -6119,17 +6129,18 @@ void flush_one_hunk(struct object_id *result, git_hash_ctx *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void patch_id_consume(void *priv, char *line, unsigned long len)
|
static int patch_id_consume(void *priv, char *line, unsigned long len)
|
||||||
{
|
{
|
||||||
struct patch_id_t *data = priv;
|
struct patch_id_t *data = priv;
|
||||||
int new_len;
|
int new_len;
|
||||||
|
|
||||||
if (len > 12 && starts_with(line, "\\ "))
|
if (len > 12 && starts_with(line, "\\ "))
|
||||||
return;
|
return 0;
|
||||||
new_len = remove_space(line, len);
|
new_len = remove_space(line, len);
|
||||||
|
|
||||||
the_hash_algo->update_fn(data->ctx, line, new_len);
|
the_hash_algo->update_fn(data->ctx, line, new_len);
|
||||||
data->patchlen += new_len;
|
data->patchlen += new_len;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void patch_id_add_string(git_hash_ctx *ctx, const char *str)
|
static void patch_id_add_string(git_hash_ctx *ctx, const char *str)
|
||||||
@ -6227,8 +6238,8 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid
|
|||||||
|
|
||||||
xpp.flags = 0;
|
xpp.flags = 0;
|
||||||
xecfg.ctxlen = 3;
|
xecfg.ctxlen = 3;
|
||||||
xecfg.flags = 0;
|
xecfg.flags = XDL_EMIT_NO_HUNK_HDR;
|
||||||
if (xdi_diff_outf(&mf1, &mf2, discard_hunk_line,
|
if (xdi_diff_outf(&mf1, &mf2, NULL,
|
||||||
patch_id_consume, &data, &xpp, &xecfg))
|
patch_id_consume, &data, &xpp, &xecfg))
|
||||||
return error("unable to generate patch-id diff for %s",
|
return error("unable to generate patch-id diff for %s",
|
||||||
p->one->path);
|
p->one->path);
|
||||||
|
7
diff.h
7
diff.h
@ -265,6 +265,7 @@ struct diff_options {
|
|||||||
* postimage of the diff_queue.
|
* postimage of the diff_queue.
|
||||||
*/
|
*/
|
||||||
const char *pickaxe;
|
const char *pickaxe;
|
||||||
|
unsigned pickaxe_opts;
|
||||||
|
|
||||||
/* -I<regex> */
|
/* -I<regex> */
|
||||||
regex_t **ignore_regex;
|
regex_t **ignore_regex;
|
||||||
@ -304,8 +305,6 @@ struct diff_options {
|
|||||||
/* The output format used when `diff_flush()` is run. */
|
/* The output format used when `diff_flush()` is run. */
|
||||||
int output_format;
|
int output_format;
|
||||||
|
|
||||||
unsigned pickaxe_opts;
|
|
||||||
|
|
||||||
/* Affects the way detection logic for complete rewrites, renames and
|
/* Affects the way detection logic for complete rewrites, renames and
|
||||||
* copies.
|
* copies.
|
||||||
*/
|
*/
|
||||||
@ -556,6 +555,10 @@ int git_config_rename(const char *var, const char *value);
|
|||||||
#define DIFF_PICKAXE_KINDS_MASK (DIFF_PICKAXE_KIND_S | \
|
#define DIFF_PICKAXE_KINDS_MASK (DIFF_PICKAXE_KIND_S | \
|
||||||
DIFF_PICKAXE_KIND_G | \
|
DIFF_PICKAXE_KIND_G | \
|
||||||
DIFF_PICKAXE_KIND_OBJFIND)
|
DIFF_PICKAXE_KIND_OBJFIND)
|
||||||
|
#define DIFF_PICKAXE_KINDS_G_REGEX_MASK (DIFF_PICKAXE_KIND_G | \
|
||||||
|
DIFF_PICKAXE_REGEX)
|
||||||
|
#define DIFF_PICKAXE_KINDS_ALL_OBJFIND_MASK (DIFF_PICKAXE_ALL | \
|
||||||
|
DIFF_PICKAXE_KIND_OBJFIND)
|
||||||
|
|
||||||
#define DIFF_PICKAXE_IGNORE_CASE 32
|
#define DIFF_PICKAXE_IGNORE_CASE 32
|
||||||
|
|
||||||
|
@ -19,38 +19,31 @@ struct diffgrep_cb {
|
|||||||
int hit;
|
int hit;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void diffgrep_consume(void *priv, char *line, unsigned long len)
|
static int diffgrep_consume(void *priv, char *line, unsigned long len)
|
||||||
{
|
{
|
||||||
struct diffgrep_cb *data = priv;
|
struct diffgrep_cb *data = priv;
|
||||||
regmatch_t regmatch;
|
regmatch_t regmatch;
|
||||||
|
|
||||||
if (line[0] != '+' && line[0] != '-')
|
if (line[0] != '+' && line[0] != '-')
|
||||||
return;
|
return 0;
|
||||||
if (data->hit)
|
if (data->hit)
|
||||||
/*
|
BUG("Already matched in diffgrep_consume! Broken xdiff_emit_line_fn?");
|
||||||
* NEEDSWORK: we should have a way to terminate the
|
if (!regexec_buf(data->regexp, line + 1, len - 1, 1,
|
||||||
* caller early.
|
®match, 0)) {
|
||||||
*/
|
data->hit = 1;
|
||||||
return;
|
return 1;
|
||||||
data->hit = !regexec_buf(data->regexp, line + 1, len - 1, 1,
|
}
|
||||||
®match, 0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int diff_grep(mmfile_t *one, mmfile_t *two,
|
static int diff_grep(mmfile_t *one, mmfile_t *two,
|
||||||
struct diff_options *o,
|
struct diff_options *o,
|
||||||
regex_t *regexp, kwset_t kws)
|
regex_t *regexp, kwset_t kws)
|
||||||
{
|
{
|
||||||
regmatch_t regmatch;
|
|
||||||
struct diffgrep_cb ecbdata;
|
struct diffgrep_cb ecbdata;
|
||||||
xpparam_t xpp;
|
xpparam_t xpp;
|
||||||
xdemitconf_t xecfg;
|
xdemitconf_t xecfg;
|
||||||
|
int ret;
|
||||||
if (!one)
|
|
||||||
return !regexec_buf(regexp, two->ptr, two->size,
|
|
||||||
1, ®match, 0);
|
|
||||||
if (!two)
|
|
||||||
return !regexec_buf(regexp, one->ptr, one->size,
|
|
||||||
1, ®match, 0);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have both sides; need to run textual diff and see if
|
* We have both sides; need to run textual diff and see if
|
||||||
@ -60,38 +53,47 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,
|
|||||||
memset(&xecfg, 0, sizeof(xecfg));
|
memset(&xecfg, 0, sizeof(xecfg));
|
||||||
ecbdata.regexp = regexp;
|
ecbdata.regexp = regexp;
|
||||||
ecbdata.hit = 0;
|
ecbdata.hit = 0;
|
||||||
|
xecfg.flags = XDL_EMIT_NO_HUNK_HDR;
|
||||||
xecfg.ctxlen = o->context;
|
xecfg.ctxlen = o->context;
|
||||||
xecfg.interhunkctxlen = o->interhunkcontext;
|
xecfg.interhunkctxlen = o->interhunkcontext;
|
||||||
if (xdi_diff_outf(one, two, discard_hunk_line, diffgrep_consume,
|
|
||||||
&ecbdata, &xpp, &xecfg))
|
/*
|
||||||
|
* An xdiff error might be our "data->hit" from above. See the
|
||||||
|
* comment for xdiff_emit_line_fn in xdiff-interface.h
|
||||||
|
*/
|
||||||
|
ret = xdi_diff_outf(one, two, NULL, diffgrep_consume,
|
||||||
|
&ecbdata, &xpp, &xecfg);
|
||||||
|
if (ecbdata.hit)
|
||||||
|
return 1;
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
return 0;
|
return 0;
|
||||||
return ecbdata.hit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws)
|
static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws,
|
||||||
|
unsigned int limit)
|
||||||
{
|
{
|
||||||
unsigned int cnt;
|
unsigned int cnt = 0;
|
||||||
unsigned long sz;
|
unsigned long sz = mf->size;
|
||||||
const char *data;
|
const char *data = mf->ptr;
|
||||||
|
|
||||||
sz = mf->size;
|
|
||||||
data = mf->ptr;
|
|
||||||
cnt = 0;
|
|
||||||
|
|
||||||
if (regexp) {
|
if (regexp) {
|
||||||
regmatch_t regmatch;
|
regmatch_t regmatch;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|
||||||
while (sz && *data &&
|
while (sz &&
|
||||||
!regexec_buf(regexp, data, sz, 1, ®match, flags)) {
|
!regexec_buf(regexp, data, sz, 1, ®match, flags)) {
|
||||||
flags |= REG_NOTBOL;
|
flags |= REG_NOTBOL;
|
||||||
data += regmatch.rm_eo;
|
data += regmatch.rm_eo;
|
||||||
sz -= regmatch.rm_eo;
|
sz -= regmatch.rm_eo;
|
||||||
if (sz && *data && regmatch.rm_so == regmatch.rm_eo) {
|
if (sz && regmatch.rm_so == regmatch.rm_eo) {
|
||||||
data++;
|
data++;
|
||||||
sz--;
|
sz--;
|
||||||
}
|
}
|
||||||
cnt++;
|
cnt++;
|
||||||
|
|
||||||
|
if (limit && cnt == limit)
|
||||||
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else { /* Classic exact string match */
|
} else { /* Classic exact string match */
|
||||||
@ -103,6 +105,9 @@ static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws)
|
|||||||
sz -= offset + kwsm.size[0];
|
sz -= offset + kwsm.size[0];
|
||||||
data += offset + kwsm.size[0];
|
data += offset + kwsm.size[0];
|
||||||
cnt++;
|
cnt++;
|
||||||
|
|
||||||
|
if (limit && cnt == limit)
|
||||||
|
return cnt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cnt;
|
return cnt;
|
||||||
@ -112,9 +117,9 @@ static int has_changes(mmfile_t *one, mmfile_t *two,
|
|||||||
struct diff_options *o,
|
struct diff_options *o,
|
||||||
regex_t *regexp, kwset_t kws)
|
regex_t *regexp, kwset_t kws)
|
||||||
{
|
{
|
||||||
unsigned int one_contains = one ? contains(one, regexp, kws) : 0;
|
unsigned int c1 = one ? contains(one, regexp, kws, 0) : 0;
|
||||||
unsigned int two_contains = two ? contains(two, regexp, kws) : 0;
|
unsigned int c2 = two ? contains(two, regexp, kws, c1 + 1) : 0;
|
||||||
return one_contains != two_contains;
|
return c1 != c2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,
|
static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,
|
||||||
@ -136,9 +141,6 @@ static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,
|
|||||||
oidset_contains(o->objfind, &p->two->oid));
|
oidset_contains(o->objfind, &p->two->oid));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!o->pickaxe[0])
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (o->flags.allow_textconv) {
|
if (o->flags.allow_textconv) {
|
||||||
textconv_one = get_textconv(o->repo, p->one);
|
textconv_one = get_textconv(o->repo, p->one);
|
||||||
textconv_two = get_textconv(o->repo, p->two);
|
textconv_two = get_textconv(o->repo, p->two);
|
||||||
@ -163,9 +165,7 @@ static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,
|
|||||||
mf1.size = fill_textconv(o->repo, textconv_one, p->one, &mf1.ptr);
|
mf1.size = fill_textconv(o->repo, textconv_one, p->one, &mf1.ptr);
|
||||||
mf2.size = fill_textconv(o->repo, textconv_two, p->two, &mf2.ptr);
|
mf2.size = fill_textconv(o->repo, textconv_two, p->two, &mf2.ptr);
|
||||||
|
|
||||||
ret = fn(DIFF_FILE_VALID(p->one) ? &mf1 : NULL,
|
ret = fn(&mf1, &mf2, o, regexp, kws);
|
||||||
DIFF_FILE_VALID(p->two) ? &mf2 : NULL,
|
|
||||||
o, regexp, kws);
|
|
||||||
|
|
||||||
if (textconv_one)
|
if (textconv_one)
|
||||||
free(mf1.ptr);
|
free(mf1.ptr);
|
||||||
@ -232,13 +232,31 @@ void diffcore_pickaxe(struct diff_options *o)
|
|||||||
int opts = o->pickaxe_opts;
|
int opts = o->pickaxe_opts;
|
||||||
regex_t regex, *regexp = NULL;
|
regex_t regex, *regexp = NULL;
|
||||||
kwset_t kws = NULL;
|
kwset_t kws = NULL;
|
||||||
|
pickaxe_fn fn;
|
||||||
|
|
||||||
|
if (opts & ~DIFF_PICKAXE_KIND_OBJFIND &&
|
||||||
|
(!needle || !*needle))
|
||||||
|
BUG("should have needle under -G or -S");
|
||||||
if (opts & (DIFF_PICKAXE_REGEX | DIFF_PICKAXE_KIND_G)) {
|
if (opts & (DIFF_PICKAXE_REGEX | DIFF_PICKAXE_KIND_G)) {
|
||||||
int cflags = REG_EXTENDED | REG_NEWLINE;
|
int cflags = REG_EXTENDED | REG_NEWLINE;
|
||||||
if (o->pickaxe_opts & DIFF_PICKAXE_IGNORE_CASE)
|
if (o->pickaxe_opts & DIFF_PICKAXE_IGNORE_CASE)
|
||||||
cflags |= REG_ICASE;
|
cflags |= REG_ICASE;
|
||||||
regcomp_or_die(®ex, needle, cflags);
|
regcomp_or_die(®ex, needle, cflags);
|
||||||
regexp = ®ex;
|
regexp = ®ex;
|
||||||
|
|
||||||
|
if (opts & DIFF_PICKAXE_KIND_G)
|
||||||
|
fn = diff_grep;
|
||||||
|
else if (opts & DIFF_PICKAXE_REGEX)
|
||||||
|
fn = has_changes;
|
||||||
|
else
|
||||||
|
/*
|
||||||
|
* We don't need to check the combination of
|
||||||
|
* -G and --pickaxe-regex, by the time we get
|
||||||
|
* here diff.c has already died if they're
|
||||||
|
* combined. See the usage tests in
|
||||||
|
* t4209-log-pickaxe.sh.
|
||||||
|
*/
|
||||||
|
BUG("unreachable");
|
||||||
} else if (opts & DIFF_PICKAXE_KIND_S) {
|
} else if (opts & DIFF_PICKAXE_KIND_S) {
|
||||||
if (o->pickaxe_opts & DIFF_PICKAXE_IGNORE_CASE &&
|
if (o->pickaxe_opts & DIFF_PICKAXE_IGNORE_CASE &&
|
||||||
has_non_ascii(needle)) {
|
has_non_ascii(needle)) {
|
||||||
@ -255,10 +273,14 @@ void diffcore_pickaxe(struct diff_options *o)
|
|||||||
kwsincr(kws, needle, strlen(needle));
|
kwsincr(kws, needle, strlen(needle));
|
||||||
kwsprep(kws);
|
kwsprep(kws);
|
||||||
}
|
}
|
||||||
|
fn = has_changes;
|
||||||
|
} else if (opts & DIFF_PICKAXE_KIND_OBJFIND) {
|
||||||
|
fn = NULL;
|
||||||
|
} else {
|
||||||
|
BUG("unknown pickaxe_opts flag");
|
||||||
}
|
}
|
||||||
|
|
||||||
pickaxe(&diff_queued_diff, o, regexp, kws,
|
pickaxe(&diff_queued_diff, o, regexp, kws, fn);
|
||||||
(opts & DIFF_PICKAXE_KIND_G) ? diff_grep : has_changes);
|
|
||||||
|
|
||||||
if (regexp)
|
if (regexp)
|
||||||
regfree(regexp);
|
regfree(regexp);
|
||||||
|
@ -274,9 +274,10 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)
|
|||||||
hashmap_clear(&map);
|
hashmap_clear(&map);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void diffsize_consume(void *data, char *line, unsigned long len)
|
static int diffsize_consume(void *data, char *line, unsigned long len)
|
||||||
{
|
{
|
||||||
(*(int *)data)++;
|
(*(int *)data)++;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void diffsize_hunk(void *data, long ob, long on, long nb, long nn,
|
static void diffsize_hunk(void *data, long ob, long on, long nb, long nn,
|
||||||
|
70
t/perf/p4209-pickaxe.sh
Executable file
70
t/perf/p4209-pickaxe.sh
Executable file
@ -0,0 +1,70 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description="Test pickaxe performance"
|
||||||
|
|
||||||
|
. ./perf-lib.sh
|
||||||
|
|
||||||
|
test_perf_default_repo
|
||||||
|
|
||||||
|
# Not --max-count, as that's the number of matching commit, so it's
|
||||||
|
# unbounded. We want to limit our revision walk here.
|
||||||
|
from_rev_desc=
|
||||||
|
from_rev=
|
||||||
|
max_count=1000
|
||||||
|
if test_have_prereq EXPENSIVE
|
||||||
|
then
|
||||||
|
max_count=10000
|
||||||
|
fi
|
||||||
|
from_rev=" $(git rev-list HEAD | head -n $max_count | tail -n 1).."
|
||||||
|
from_rev_desc=" <limit-rev>.."
|
||||||
|
|
||||||
|
for icase in \
|
||||||
|
'' \
|
||||||
|
'-i '
|
||||||
|
do
|
||||||
|
# -S (no regex)
|
||||||
|
for pattern in \
|
||||||
|
'int main' \
|
||||||
|
'æ'
|
||||||
|
do
|
||||||
|
for opts in \
|
||||||
|
'-S'
|
||||||
|
do
|
||||||
|
test_perf "git log $icase$opts'$pattern'$from_rev_desc" "
|
||||||
|
git log --pretty=format:%H $icase$opts'$pattern'$from_rev
|
||||||
|
"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# -S (regex)
|
||||||
|
for pattern in \
|
||||||
|
'(int|void|null)' \
|
||||||
|
'if *\([^ ]+ & ' \
|
||||||
|
'[àáâãäåæñøùúûüýþ]'
|
||||||
|
do
|
||||||
|
for opts in \
|
||||||
|
'--pickaxe-regex -S'
|
||||||
|
do
|
||||||
|
test_perf "git log $icase$opts'$pattern'$from_rev_desc" "
|
||||||
|
git log --pretty=format:%H $icase$opts'$pattern'$from_rev
|
||||||
|
"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# -G
|
||||||
|
for pattern in \
|
||||||
|
'(int|void|null)' \
|
||||||
|
'if *\([^ ]+ & ' \
|
||||||
|
'[àáâãäåæñøùúûüýþ]'
|
||||||
|
do
|
||||||
|
for opts in \
|
||||||
|
'-G'
|
||||||
|
do
|
||||||
|
test_perf "git log $icase$opts'$pattern'$from_rev_desc" "
|
||||||
|
git log --pretty=format:%H $icase$opts'$pattern'$from_rev
|
||||||
|
"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
test_done
|
@ -55,6 +55,43 @@ test_expect_success setup '
|
|||||||
git rev-parse --verify HEAD >expect_second
|
git rev-parse --verify HEAD >expect_second
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'usage' '
|
||||||
|
test_expect_code 129 git log -S 2>err &&
|
||||||
|
test_i18ngrep "switch.*requires a value" err &&
|
||||||
|
|
||||||
|
test_expect_code 129 git log -G 2>err &&
|
||||||
|
test_i18ngrep "switch.*requires a value" err &&
|
||||||
|
|
||||||
|
test_expect_code 128 git log -Gregex -Sstring 2>err &&
|
||||||
|
grep "mutually exclusive" err &&
|
||||||
|
|
||||||
|
test_expect_code 128 git log -Gregex --find-object=HEAD 2>err &&
|
||||||
|
grep "mutually exclusive" err &&
|
||||||
|
|
||||||
|
test_expect_code 128 git log -Sstring --find-object=HEAD 2>err &&
|
||||||
|
grep "mutually exclusive" err &&
|
||||||
|
|
||||||
|
test_expect_code 128 git log --pickaxe-all --find-object=HEAD 2>err &&
|
||||||
|
grep "mutually exclusive" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'usage: --pickaxe-regex' '
|
||||||
|
test_expect_code 128 git log -Gregex --pickaxe-regex 2>err &&
|
||||||
|
grep "mutually exclusive" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'usage: --no-pickaxe-regex' '
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
fatal: unrecognized argument: --no-pickaxe-regex
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_code 128 git log -Sstring --no-pickaxe-regex 2>actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
test_expect_code 128 git log -Gstring --no-pickaxe-regex 2>err &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test_log expect_initial --grep initial
|
test_log expect_initial --grep initial
|
||||||
test_log expect_nomatch --grep InItial
|
test_log expect_nomatch --grep InItial
|
||||||
test_log_icase expect_initial --grep InItial
|
test_log_icase expect_initial --grep InItial
|
||||||
@ -106,38 +143,83 @@ test_expect_success 'log -S --no-textconv (missing textconv tool)' '
|
|||||||
rm .gitattributes
|
rm .gitattributes
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'setup log -[GS] plain & regex' '
|
||||||
|
test_create_repo GS-plain &&
|
||||||
|
test_commit -C GS-plain --append A data.txt "a" &&
|
||||||
|
test_commit -C GS-plain --append B data.txt "a a" &&
|
||||||
|
test_commit -C GS-plain --append C data.txt "b" &&
|
||||||
|
test_commit -C GS-plain --append D data.txt "[b]" &&
|
||||||
|
test_commit -C GS-plain E data.txt "" &&
|
||||||
|
|
||||||
|
# We also include E, the deletion commit
|
||||||
|
git -C GS-plain log --grep="[ABE]" >A-to-B-then-E-log &&
|
||||||
|
git -C GS-plain log --grep="[CDE]" >C-to-D-then-E-log &&
|
||||||
|
git -C GS-plain log --grep="[DE]" >D-then-E-log &&
|
||||||
|
git -C GS-plain log >full-log
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'log -G trims diff new/old [-+]' '
|
||||||
|
git -C GS-plain log -G"[+-]a" >log &&
|
||||||
|
test_must_be_empty log &&
|
||||||
|
git -C GS-plain log -G"^a" >log &&
|
||||||
|
test_cmp log A-to-B-then-E-log
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'log -S<pat> is not a regex, but -S<pat> --pickaxe-regex is' '
|
||||||
|
git -C GS-plain log -S"a" >log &&
|
||||||
|
test_cmp log A-to-B-then-E-log &&
|
||||||
|
|
||||||
|
git -C GS-plain log -S"[a]" >log &&
|
||||||
|
test_must_be_empty log &&
|
||||||
|
|
||||||
|
git -C GS-plain log -S"[a]" --pickaxe-regex >log &&
|
||||||
|
test_cmp log A-to-B-then-E-log &&
|
||||||
|
|
||||||
|
git -C GS-plain log -S"[b]" >log &&
|
||||||
|
test_cmp log D-then-E-log &&
|
||||||
|
|
||||||
|
git -C GS-plain log -S"[b]" --pickaxe-regex >log &&
|
||||||
|
test_cmp log C-to-D-then-E-log
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'setup log -[GS] binary & --text' '
|
test_expect_success 'setup log -[GS] binary & --text' '
|
||||||
git checkout --orphan GS-binary-and-text &&
|
test_create_repo GS-bin-txt &&
|
||||||
git read-tree --empty &&
|
test_commit -C GS-bin-txt --printf A data.bin "a\na\0a\n" &&
|
||||||
printf "a\na\0a\n" >data.bin &&
|
test_commit -C GS-bin-txt --append --printf B data.bin "a\na\0a\n" &&
|
||||||
git add data.bin &&
|
test_commit -C GS-bin-txt C data.bin "" &&
|
||||||
git commit -m "create binary file" data.bin &&
|
git -C GS-bin-txt log >full-log
|
||||||
printf "a\na\0a\n" >>data.bin &&
|
|
||||||
git commit -m "modify binary file" data.bin &&
|
|
||||||
git rm data.bin &&
|
|
||||||
git commit -m "delete binary file" data.bin &&
|
|
||||||
git log >full-log
|
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'log -G ignores binary files' '
|
test_expect_success 'log -G ignores binary files' '
|
||||||
git log -Ga >log &&
|
git -C GS-bin-txt log -Ga >log &&
|
||||||
test_must_be_empty log
|
test_must_be_empty log
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'log -G looks into binary files with -a' '
|
test_expect_success 'log -G looks into binary files with -a' '
|
||||||
git log -a -Ga >log &&
|
git -C GS-bin-txt log -a -Ga >log &&
|
||||||
test_cmp log full-log
|
test_cmp log full-log
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'log -G looks into binary files with textconv filter' '
|
test_expect_success 'log -G looks into binary files with textconv filter' '
|
||||||
test_when_finished "rm .gitattributes" &&
|
test_when_finished "rm GS-bin-txt/.gitattributes" &&
|
||||||
|
(
|
||||||
|
cd GS-bin-txt &&
|
||||||
echo "* diff=bin" >.gitattributes &&
|
echo "* diff=bin" >.gitattributes &&
|
||||||
git -c diff.bin.textconv=cat log -Ga >log &&
|
git -c diff.bin.textconv=cat log -Ga >../log
|
||||||
|
) &&
|
||||||
test_cmp log full-log
|
test_cmp log full-log
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'log -S looks into binary files' '
|
test_expect_success 'log -S looks into binary files' '
|
||||||
git log -Sa >log &&
|
git -C GS-bin-txt log -Sa >log &&
|
||||||
|
test_cmp log full-log
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'log -S --pickaxe-regex looks into binary files' '
|
||||||
|
git -C GS-bin-txt log --pickaxe-regex -Sa >log &&
|
||||||
|
test_cmp log full-log &&
|
||||||
|
|
||||||
|
git -C GS-bin-txt log --pickaxe-regex -S"[a]" >log &&
|
||||||
test_cmp log full-log
|
test_cmp log full-log
|
||||||
'
|
'
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ test_expect_success 'setup' "
|
|||||||
git commit -m.
|
git commit -m.
|
||||||
"
|
"
|
||||||
|
|
||||||
# Simple fixed-string matching that can use kwset (no -i && non-ASCII)
|
# Simple fixed-string matching
|
||||||
nul_match P P P '-F' 'yQf'
|
nul_match P P P '-F' 'yQf'
|
||||||
nul_match P P P '-F' 'yQx'
|
nul_match P P P '-F' 'yQx'
|
||||||
nul_match P P P '-Fi' 'YQf'
|
nul_match P P P '-Fi' 'YQf'
|
||||||
@ -78,7 +78,7 @@ nul_match P P P '-Fi' '[Y]QF'
|
|||||||
nul_match P P P '-F' 'æQ[ð]'
|
nul_match P P P '-F' 'æQ[ð]'
|
||||||
nul_match P P P '-F' '[æ]Qð'
|
nul_match P P P '-F' '[æ]Qð'
|
||||||
|
|
||||||
# The -F kwset codepath can't handle -i && non-ASCII...
|
# Matching pattern and subject case with -i
|
||||||
nul_match P 1 1 '-i' '[æ]Qð'
|
nul_match P 1 1 '-i' '[æ]Qð'
|
||||||
|
|
||||||
# ...PCRE v2 only matches non-ASCII with -i casefolding under UTF-8
|
# ...PCRE v2 only matches non-ASCII with -i casefolding under UTF-8
|
||||||
|
@ -31,29 +31,36 @@ static int xdiff_out_hunk(void *priv_,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void consume_one(void *priv_, char *s, unsigned long size)
|
static int consume_one(void *priv_, char *s, unsigned long size)
|
||||||
{
|
{
|
||||||
struct xdiff_emit_state *priv = priv_;
|
struct xdiff_emit_state *priv = priv_;
|
||||||
char *ep;
|
char *ep;
|
||||||
while (size) {
|
while (size) {
|
||||||
unsigned long this_size;
|
unsigned long this_size;
|
||||||
|
int ret;
|
||||||
ep = memchr(s, '\n', size);
|
ep = memchr(s, '\n', size);
|
||||||
this_size = (ep == NULL) ? size : (ep - s + 1);
|
this_size = (ep == NULL) ? size : (ep - s + 1);
|
||||||
priv->line_fn(priv->consume_callback_data, s, this_size);
|
ret = priv->line_fn(priv->consume_callback_data, s, this_size);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
size -= this_size;
|
size -= this_size;
|
||||||
s += this_size;
|
s += this_size;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
|
static int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
|
||||||
{
|
{
|
||||||
struct xdiff_emit_state *priv = priv_;
|
struct xdiff_emit_state *priv = priv_;
|
||||||
int i;
|
int i;
|
||||||
|
int stop = 0;
|
||||||
|
|
||||||
if (!priv->line_fn)
|
if (!priv->line_fn)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < nbuf; i++) {
|
for (i = 0; i < nbuf; i++) {
|
||||||
|
if (stop)
|
||||||
|
return 1;
|
||||||
if (mb[i].ptr[mb[i].size-1] != '\n') {
|
if (mb[i].ptr[mb[i].size-1] != '\n') {
|
||||||
/* Incomplete line */
|
/* Incomplete line */
|
||||||
strbuf_add(&priv->remainder, mb[i].ptr, mb[i].size);
|
strbuf_add(&priv->remainder, mb[i].ptr, mb[i].size);
|
||||||
@ -62,17 +69,21 @@ static int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf)
|
|||||||
|
|
||||||
/* we have a complete line */
|
/* we have a complete line */
|
||||||
if (!priv->remainder.len) {
|
if (!priv->remainder.len) {
|
||||||
consume_one(priv, mb[i].ptr, mb[i].size);
|
stop = consume_one(priv, mb[i].ptr, mb[i].size);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
strbuf_add(&priv->remainder, mb[i].ptr, mb[i].size);
|
strbuf_add(&priv->remainder, mb[i].ptr, mb[i].size);
|
||||||
consume_one(priv, priv->remainder.buf, priv->remainder.len);
|
stop = consume_one(priv, priv->remainder.buf, priv->remainder.len);
|
||||||
strbuf_reset(&priv->remainder);
|
strbuf_reset(&priv->remainder);
|
||||||
}
|
}
|
||||||
|
if (stop)
|
||||||
|
return -1;
|
||||||
if (priv->remainder.len) {
|
if (priv->remainder.len) {
|
||||||
consume_one(priv, priv->remainder.buf, priv->remainder.len);
|
stop = consume_one(priv, priv->remainder.buf, priv->remainder.len);
|
||||||
strbuf_reset(&priv->remainder);
|
strbuf_reset(&priv->remainder);
|
||||||
}
|
}
|
||||||
|
if (stop)
|
||||||
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,12 +126,6 @@ int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t co
|
|||||||
return xdl_diff(&a, &b, xpp, xecfg, xecb);
|
return xdl_diff(&a, &b, xpp, xecfg, xecb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void discard_hunk_line(void *priv,
|
|
||||||
long ob, long on, long nb, long nn,
|
|
||||||
const char *func, long funclen)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
|
int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
|
||||||
xdiff_emit_hunk_fn hunk_fn,
|
xdiff_emit_hunk_fn hunk_fn,
|
||||||
xdiff_emit_line_fn line_fn,
|
xdiff_emit_line_fn line_fn,
|
||||||
|
@ -11,7 +11,28 @@
|
|||||||
*/
|
*/
|
||||||
#define MAX_XDIFF_SIZE (1024UL * 1024 * 1023)
|
#define MAX_XDIFF_SIZE (1024UL * 1024 * 1023)
|
||||||
|
|
||||||
typedef void (*xdiff_emit_line_fn)(void *, char *, unsigned long);
|
/**
|
||||||
|
* The `xdiff_emit_line_fn` function can return 1 to abort early, or 0
|
||||||
|
* to continue processing. Note that doing so is an all-or-nothing
|
||||||
|
* affair, as returning 1 will return all the way to the top-level,
|
||||||
|
* e.g. the xdi_diff_outf() call to generate the diff.
|
||||||
|
*
|
||||||
|
* Thus returning 1 means you won't be getting any more diff lines. If
|
||||||
|
* you need something in-between those two options you'll to use
|
||||||
|
* `xdl_emit_hunk_consume_func_t` and implement your own version of
|
||||||
|
* xdl_emit_diff().
|
||||||
|
*
|
||||||
|
* We may extend the interface in the future to understand other more
|
||||||
|
* granular return values. While you should return 1 to exit early,
|
||||||
|
* doing so will currently make your early return indistinguishable
|
||||||
|
* from an error internal to xdiff, xdiff itself will see that
|
||||||
|
* non-zero return and translate it to -1.
|
||||||
|
*
|
||||||
|
* See "diff_grep" in diffcore-pickaxe.c for a trick to work around
|
||||||
|
* this, i.e. using the "consume_callback_data" to note the desired
|
||||||
|
* early return.
|
||||||
|
*/
|
||||||
|
typedef int (*xdiff_emit_line_fn)(void *, char *, unsigned long);
|
||||||
typedef void (*xdiff_emit_hunk_fn)(void *data,
|
typedef void (*xdiff_emit_hunk_fn)(void *data,
|
||||||
long old_begin, long old_nr,
|
long old_begin, long old_nr,
|
||||||
long new_begin, long new_nr,
|
long new_begin, long new_nr,
|
||||||
@ -32,14 +53,6 @@ void xdiff_clear_find_func(xdemitconf_t *xecfg);
|
|||||||
int git_xmerge_config(const char *var, const char *value, void *cb);
|
int git_xmerge_config(const char *var, const char *value, void *cb);
|
||||||
extern int git_xmerge_style;
|
extern int git_xmerge_style;
|
||||||
|
|
||||||
/*
|
|
||||||
* Can be used as a no-op hunk_fn for xdi_diff_outf(), since a NULL
|
|
||||||
* one just sends the hunk line to the line_fn callback).
|
|
||||||
*/
|
|
||||||
void discard_hunk_line(void *priv,
|
|
||||||
long ob, long on, long nb, long nn,
|
|
||||||
const char *func, long funclen);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compare the strings l1 with l2 which are of size s1 and s2 respectively.
|
* Compare the strings l1 with l2 which are of size s1 and s2 respectively.
|
||||||
* Returns 1 if the strings are deemed equal, 0 otherwise.
|
* Returns 1 if the strings are deemed equal, 0 otherwise.
|
||||||
|
@ -50,6 +50,7 @@ extern "C" {
|
|||||||
|
|
||||||
/* xdemitconf_t.flags */
|
/* xdemitconf_t.flags */
|
||||||
#define XDL_EMIT_FUNCNAMES (1 << 0)
|
#define XDL_EMIT_FUNCNAMES (1 << 0)
|
||||||
|
#define XDL_EMIT_NO_HUNK_HDR (1 << 1)
|
||||||
#define XDL_EMIT_FUNCCONTEXT (1 << 2)
|
#define XDL_EMIT_FUNCCONTEXT (1 << 2)
|
||||||
|
|
||||||
/* merge simplification levels */
|
/* merge simplification levels */
|
||||||
|
@ -278,7 +278,8 @@ pre_context_calculation:
|
|||||||
s1 - 1, funclineprev);
|
s1 - 1, funclineprev);
|
||||||
funclineprev = s1 - 1;
|
funclineprev = s1 - 1;
|
||||||
}
|
}
|
||||||
if (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2,
|
if (!(xecfg->flags & XDL_EMIT_NO_HUNK_HDR) &&
|
||||||
|
xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2,
|
||||||
func_line.buf, func_line.len, ecb) < 0)
|
func_line.buf, func_line.len, ecb) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user