summaryrefslogtreecommitdiff
path: root/diffcore-pickaxe.c
diff options
context:
space:
mode:
Diffstat (limited to 'diffcore-pickaxe.c')
-rw-r--r--diffcore-pickaxe.c92
1 files changed, 58 insertions, 34 deletions
diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c
index 185f86b284..239ce5122b 100644
--- a/diffcore-pickaxe.c
+++ b/diffcore-pickaxe.c
@@ -7,6 +7,8 @@
#include "diffcore.h"
#include "xdiff-interface.h"
#include "kwset.h"
+#include "commit.h"
+#include "quote.h"
typedef int (*pickaxe_fn)(mmfile_t *one, mmfile_t *two,
struct diff_options *o,
@@ -21,7 +23,6 @@ static void diffgrep_consume(void *priv, char *line, unsigned long len)
{
struct diffgrep_cb *data = priv;
regmatch_t regmatch;
- int hold;
if (line[0] != '+' && line[0] != '-')
return;
@@ -31,11 +32,8 @@ static void diffgrep_consume(void *priv, char *line, unsigned long len)
* caller early.
*/
return;
- /* Yuck -- line ought to be "const char *"! */
- hold = line[len];
- line[len] = '\0';
- data->hit = !regexec(data->regexp, line + 1, 1, &regmatch, 0);
- line[len] = hold;
+ data->hit = !regexec_buf(data->regexp, line + 1, len - 1, 1,
+ &regmatch, 0);
}
static int diff_grep(mmfile_t *one, mmfile_t *two,
@@ -48,9 +46,11 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,
xdemitconf_t xecfg;
if (!one)
- return !regexec(regexp, two->ptr, 1, &regmatch, 0);
+ return !regexec_buf(regexp, two->ptr, two->size,
+ 1, &regmatch, 0);
if (!two)
- return !regexec(regexp, one->ptr, 1, &regmatch, 0);
+ return !regexec_buf(regexp, one->ptr, one->size,
+ 1, &regmatch, 0);
/*
* We have both sides; need to run textual diff and see if
@@ -62,8 +62,8 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,
ecbdata.hit = 0;
xecfg.ctxlen = o->context;
xecfg.interhunkctxlen = o->interhunkcontext;
- xdi_diff_outf(one, two, diffgrep_consume, &ecbdata,
- &xpp, &xecfg);
+ if (xdi_diff_outf(one, two, diffgrep_consume, &ecbdata, &xpp, &xecfg))
+ return 0;
return ecbdata.hit;
}
@@ -81,12 +81,15 @@ static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws)
regmatch_t regmatch;
int flags = 0;
- assert(data[sz] == '\0');
- while (*data && !regexec(regexp, data, 1, &regmatch, flags)) {
+ while (sz && *data &&
+ !regexec_buf(regexp, data, sz, 1, &regmatch, flags)) {
flags |= REG_NOTBOL;
data += regmatch.rm_eo;
- if (*data && regmatch.rm_so == regmatch.rm_eo)
+ sz -= regmatch.rm_eo;
+ if (sz && *data && regmatch.rm_so == regmatch.rm_eo) {
data++;
+ sz--;
+ }
cnt++;
}
@@ -121,14 +124,21 @@ static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,
mmfile_t mf1, mf2;
int ret;
- if (!o->pickaxe[0])
- return 0;
-
/* ignore unmerged */
if (!DIFF_FILE_VALID(p->one) && !DIFF_FILE_VALID(p->two))
return 0;
- if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) {
+ if (o->objfind) {
+ return (DIFF_FILE_VALID(p->one) &&
+ oidset_contains(o->objfind, &p->one->oid)) ||
+ (DIFF_FILE_VALID(p->two) &&
+ oidset_contains(o->objfind, &p->two->oid));
+ }
+
+ if (!o->pickaxe[0])
+ return 0;
+
+ if (o->flags.allow_textconv) {
textconv_one = get_textconv(p->one);
textconv_two = get_textconv(p->two);
}
@@ -198,6 +208,18 @@ static void pickaxe(struct diff_queue_struct *q, struct diff_options *o,
*q = outq;
}
+static void regcomp_or_die(regex_t *regex, const char *needle, int cflags)
+{
+ int err = regcomp(regex, needle, cflags);
+ if (err) {
+ /* The POSIX.2 people are surely sick */
+ char errbuf[1024];
+ regerror(err, regex, errbuf, 1024);
+ regfree(regex);
+ die("invalid regex: %s", errbuf);
+ }
+}
+
void diffcore_pickaxe(struct diff_options *o)
{
const char *needle = o->pickaxe;
@@ -206,33 +228,35 @@ void diffcore_pickaxe(struct diff_options *o)
kwset_t kws = NULL;
if (opts & (DIFF_PICKAXE_REGEX | DIFF_PICKAXE_KIND_G)) {
- int err;
int cflags = REG_EXTENDED | REG_NEWLINE;
- if (DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE))
+ if (o->pickaxe_opts & DIFF_PICKAXE_IGNORE_CASE)
cflags |= REG_ICASE;
- err = regcomp(&regex, needle, cflags);
- if (err) {
- /* The POSIX.2 people are surely sick */
- char errbuf[1024];
- regerror(err, &regex, errbuf, 1024);
- regfree(&regex);
- die("invalid regex: %s", errbuf);
- }
+ regcomp_or_die(&regex, needle, cflags);
regexp = &regex;
- } else {
- kws = kwsalloc(DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE)
- ? tolower_trans_tbl : NULL);
- kwsincr(kws, needle, strlen(needle));
- kwsprep(kws);
+ } else if (opts & DIFF_PICKAXE_KIND_S) {
+ if (o->pickaxe_opts & DIFF_PICKAXE_IGNORE_CASE &&
+ has_non_ascii(needle)) {
+ struct strbuf sb = STRBUF_INIT;
+ int cflags = REG_NEWLINE | REG_ICASE;
+
+ basic_regex_quote_buf(&sb, needle);
+ regcomp_or_die(&regex, sb.buf, cflags);
+ strbuf_release(&sb);
+ regexp = &regex;
+ } else {
+ kws = kwsalloc(o->pickaxe_opts & DIFF_PICKAXE_IGNORE_CASE
+ ? tolower_trans_tbl : NULL);
+ kwsincr(kws, needle, strlen(needle));
+ kwsprep(kws);
+ }
}
- /* Might want to warn when both S and G are on; I don't care... */
pickaxe(&diff_queued_diff, o, regexp, kws,
(opts & DIFF_PICKAXE_KIND_G) ? diff_grep : has_changes);
if (regexp)
regfree(regexp);
- else
+ if (kws)
kwsfree(kws);
return;
}