Merge branch 'ab/pcre-v2'

Update "perl-compatible regular expression" support to enable JIT
and also allow linking with the newer PCRE v2 library.

* ab/pcre-v2:
  grep: add support for PCRE v2
  grep: un-break building with PCRE >= 8.32 without --enable-jit
  grep: un-break building with PCRE < 8.20
  grep: un-break building with PCRE < 8.32
  grep: add support for the PCRE v1 JIT API
  log: add -P as a synonym for --perl-regexp
  grep: skip pthreads overhead when using one thread
  grep: don't redundantly compile throwaway patterns under threading
maint
Junio C Hamano 2017-06-19 12:38:43 -07:00
commit ae7e4d4fed
10 changed files with 350 additions and 30 deletions

View File

@ -91,6 +91,7 @@ endif::git-rev-list[]
Consider the limiting patterns to be fixed strings (don't interpret Consider the limiting patterns to be fixed strings (don't interpret
pattern as a regular expression). pattern as a regular expression).


-P::
--perl-regexp:: --perl-regexp::
Consider the limiting patterns to be Perl-compatible regular Consider the limiting patterns to be Perl-compatible regular
expressions. expressions.

View File

@ -29,8 +29,23 @@ all::
# Perl-compatible regular expressions instead of standard or extended # Perl-compatible regular expressions instead of standard or extended
# POSIX regular expressions. # POSIX regular expressions.
# #
# Define LIBPCREDIR=/foo/bar if your libpcre header and library files are in # Currently USE_LIBPCRE is a synonym for USE_LIBPCRE1, define
# /foo/bar/include and /foo/bar/lib directories. # USE_LIBPCRE2 instead if you'd like to use version 2 of the PCRE
# library. The USE_LIBPCRE flag will likely be changed to mean v2 by
# default in future releases.
#
# When using USE_LIBPCRE1, define NO_LIBPCRE1_JIT if the PCRE v1
# library is compiled without --enable-jit. We will auto-detect
# whether the version of the PCRE v1 library in use has JIT support at
# all, but we unfortunately can't auto-detect whether JIT support
# hasn't been compiled in in an otherwise JIT-supporting version. If
# you have link-time errors about a missing `pcre_jit_exec` define
# this, or recompile PCRE v1 with --enable-jit.
#
# Define LIBPCREDIR=/foo/bar if your PCRE header and library files are
# in /foo/bar/include and /foo/bar/lib directories. Which version of
# PCRE this points to determined by the USE_LIBPCRE1 and USE_LIBPCRE2
# variables.
# #
# Define HAVE_ALLOCA_H if you have working alloca(3) defined in that header. # Define HAVE_ALLOCA_H if you have working alloca(3) defined in that header.
# #
@ -1089,13 +1104,29 @@ ifdef NO_LIBGEN_H
COMPAT_OBJS += compat/basename.o COMPAT_OBJS += compat/basename.o
endif endif


ifdef USE_LIBPCRE USE_LIBPCRE1 ?= $(USE_LIBPCRE)

ifneq (,$(USE_LIBPCRE1))
ifdef USE_LIBPCRE2
$(error Only set USE_LIBPCRE1 (or its alias USE_LIBPCRE) or USE_LIBPCRE2, not both!)
endif

BASIC_CFLAGS += -DUSE_LIBPCRE1 BASIC_CFLAGS += -DUSE_LIBPCRE1
ifdef LIBPCREDIR EXTLIBS += -lpcre

ifdef NO_LIBPCRE1_JIT
BASIC_CFLAGS += -DNO_LIBPCRE1_JIT
endif
endif

ifdef USE_LIBPCRE2
BASIC_CFLAGS += -DUSE_LIBPCRE2
EXTLIBS += -lpcre2-8
endif

ifdef LIBPCREDIR
BASIC_CFLAGS += -I$(LIBPCREDIR)/include BASIC_CFLAGS += -I$(LIBPCREDIR)/include
EXTLIBS += -L$(LIBPCREDIR)/$(lib) $(CC_LD_DYNPATH)$(LIBPCREDIR)/$(lib) EXTLIBS += -L$(LIBPCREDIR)/$(lib) $(CC_LD_DYNPATH)$(LIBPCREDIR)/$(lib)
endif
EXTLIBS += -lpcre
endif endif


ifdef HAVE_ALLOCA_H ifdef HAVE_ALLOCA_H
@ -2249,7 +2280,9 @@ GIT-BUILD-OPTIONS: FORCE
@echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@+ @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@+
@echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@+ @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@+
@echo NO_EXPAT=\''$(subst ','\'',$(subst ','\'',$(NO_EXPAT)))'\' >>$@+ @echo NO_EXPAT=\''$(subst ','\'',$(subst ','\'',$(NO_EXPAT)))'\' >>$@+
@echo USE_LIBPCRE1=\''$(subst ','\'',$(subst ','\'',$(USE_LIBPCRE)))'\' >>$@+ @echo USE_LIBPCRE1=\''$(subst ','\'',$(subst ','\'',$(USE_LIBPCRE1)))'\' >>$@+
@echo USE_LIBPCRE2=\''$(subst ','\'',$(subst ','\'',$(USE_LIBPCRE2)))'\' >>$@+
@echo NO_LIBPCRE1_JIT=\''$(subst ','\'',$(subst ','\'',$(NO_LIBPCRE1_JIT)))'\' >>$@+
@echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@+ @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@+
@echo NO_PTHREADS=\''$(subst ','\'',$(subst ','\'',$(NO_PTHREADS)))'\' >>$@+ @echo NO_PTHREADS=\''$(subst ','\'',$(subst ','\'',$(NO_PTHREADS)))'\' >>$@+
@echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@+ @echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@+

View File

@ -224,6 +224,7 @@ static void start_threads(struct grep_opt *opt)
int err; int err;
struct grep_opt *o = grep_opt_dup(opt); struct grep_opt *o = grep_opt_dup(opt);
o->output = strbuf_out; o->output = strbuf_out;
if (i)
o->debug = 0; o->debug = 0;
compile_grep_patterns(o); compile_grep_patterns(o);
err = pthread_create(&threads[i], NULL, run, o); err = pthread_create(&threads[i], NULL, run, o);
@ -1170,8 +1171,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (!opt.fixed && opt.ignore_case) if (!opt.fixed && opt.ignore_case)
opt.regflags |= REG_ICASE; opt.regflags |= REG_ICASE;


compile_grep_patterns(&opt);

/* /*
* We have to find "--" in a separate pass, because its presence * We have to find "--" in a separate pass, because its presence
* influences how we will parse arguments that come before it. * influences how we will parse arguments that come before it.
@ -1244,12 +1243,23 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
num_threads = GREP_NUM_THREADS_DEFAULT; num_threads = GREP_NUM_THREADS_DEFAULT;
else if (num_threads < 0) else if (num_threads < 0)
die(_("invalid number of threads specified (%d)"), num_threads); die(_("invalid number of threads specified (%d)"), num_threads);
if (num_threads == 1)
num_threads = 0;
#else #else
if (num_threads) if (num_threads)
warning(_("no threads support, ignoring --threads")); warning(_("no threads support, ignoring --threads"));
num_threads = 0; num_threads = 0;
#endif #endif


if (!num_threads)
/*
* The compiled patterns on the main path are only
* used when not using threading. Otherwise
* start_threads() below calls compile_grep_patterns()
* for each thread.
*/
compile_grep_patterns(&opt);

#ifndef NO_PTHREADS #ifndef NO_PTHREADS
if (num_threads) { if (num_threads) {
if (!(opt.name_only || opt.unmatch_name_only || opt.count) if (!(opt.name_only || opt.unmatch_name_only || opt.count)

View File

@ -555,6 +555,7 @@ else
NO_GETTEXT = NO_GETTEXT =
USE_GETTEXT_SCHEME = fallthrough USE_GETTEXT_SCHEME = fallthrough
USE_LIBPCRE= YesPlease USE_LIBPCRE= YesPlease
NO_LIBPCRE1_JIT = UnfortunatelyYes
NO_CURL = NO_CURL =
USE_NED_ALLOCATOR = YesPlease USE_NED_ALLOCATOR = YesPlease
else else

View File

@ -255,21 +255,61 @@ GIT_PARSE_WITH([openssl]))
# Perl-compatible regular expressions instead of standard or extended # Perl-compatible regular expressions instead of standard or extended
# POSIX regular expressions. # POSIX regular expressions.
# #
# Define LIBPCREDIR=/foo/bar if your libpcre header and library files are in # Currently USE_LIBPCRE is a synonym for USE_LIBPCRE1, define
# USE_LIBPCRE2 instead if you'd like to use version 2 of the PCRE
# library. The USE_LIBPCRE flag will likely be changed to mean v2 by
# default in future releases.
#
# Define LIBPCREDIR=/foo/bar if your PCRE header and library files are in
# /foo/bar/include and /foo/bar/lib directories. # /foo/bar/include and /foo/bar/lib directories.
# #
AC_ARG_WITH(libpcre, AC_ARG_WITH(libpcre,
AS_HELP_STRING([--with-libpcre],[support Perl-compatible regexes (default is NO)]) AS_HELP_STRING([--with-libpcre],[synonym for --with-libpcre1]),
AS_HELP_STRING([], [ARG can be also prefix for libpcre library and headers]),
if test "$withval" = "no"; then if test "$withval" = "no"; then
USE_LIBPCRE= USE_LIBPCRE1=
elif test "$withval" = "yes"; then elif test "$withval" = "yes"; then
USE_LIBPCRE=YesPlease USE_LIBPCRE1=YesPlease
else else
USE_LIBPCRE=YesPlease USE_LIBPCRE1=YesPlease
LIBPCREDIR=$withval LIBPCREDIR=$withval
AC_MSG_NOTICE([Setting LIBPCREDIR to $LIBPCREDIR]) AC_MSG_NOTICE([Setting LIBPCREDIR to $LIBPCREDIR])
dnl USE_LIBPCRE can still be modified below, so don't substitute dnl USE_LIBPCRE1 can still be modified below, so don't substitute
dnl it yet.
GIT_CONF_SUBST([LIBPCREDIR])
fi)

AC_ARG_WITH(libpcre1,
AS_HELP_STRING([--with-libpcre1],[support Perl-compatible regexes via libpcre1 (default is NO)])
AS_HELP_STRING([], [ARG can be also prefix for libpcre library and headers]),
if test "$withval" = "no"; then
USE_LIBPCRE1=
elif test "$withval" = "yes"; then
USE_LIBPCRE1=YesPlease
else
USE_LIBPCRE1=YesPlease
LIBPCREDIR=$withval
AC_MSG_NOTICE([Setting LIBPCREDIR to $LIBPCREDIR])
dnl USE_LIBPCRE1 can still be modified below, so don't substitute
dnl it yet.
GIT_CONF_SUBST([LIBPCREDIR])
fi)

AC_ARG_WITH(libpcre2,
AS_HELP_STRING([--with-libpcre2],[support Perl-compatible regexes via libpcre2 (default is NO)])
AS_HELP_STRING([], [ARG can be also prefix for libpcre library and headers]),
if test -n "$USE_LIBPCRE1"; then
AC_MSG_ERROR([Only supply one of --with-libpcre1 or --with-libpcre2!])
fi

if test "$withval" = "no"; then
USE_LIBPCRE2=
elif test "$withval" = "yes"; then
USE_LIBPCRE2=YesPlease
else
USE_LIBPCRE2=YesPlease
LIBPCREDIR=$withval
AC_MSG_NOTICE([Setting LIBPCREDIR to $LIBPCREDIR])
dnl USE_LIBPCRE2 can still be modified below, so don't substitute
dnl it yet. dnl it yet.
GIT_CONF_SUBST([LIBPCREDIR]) GIT_CONF_SUBST([LIBPCREDIR])
fi) fi)
@ -501,13 +541,11 @@ GIT_CONF_SUBST([NEEDS_SSL_WITH_CRYPTO])
GIT_CONF_SUBST([NO_OPENSSL]) GIT_CONF_SUBST([NO_OPENSSL])


# #
# Define USE_LIBPCRE if you have and want to use libpcre. Various # Handle the USE_LIBPCRE1 and USE_LIBPCRE2 options potentially set
# commands such as log and grep offer runtime options to use # above.
# Perl-compatible regular expressions instead of standard or extended
# POSIX regular expressions.
# #


if test -n "$USE_LIBPCRE"; then if test -n "$USE_LIBPCRE1"; then


GIT_STASH_FLAGS($LIBPCREDIR) GIT_STASH_FLAGS($LIBPCREDIR)


@ -517,7 +555,22 @@ AC_CHECK_LIB([pcre], [pcre_version],


GIT_UNSTASH_FLAGS($LIBPCREDIR) GIT_UNSTASH_FLAGS($LIBPCREDIR)


GIT_CONF_SUBST([USE_LIBPCRE]) GIT_CONF_SUBST([USE_LIBPCRE1])

fi


if test -n "$USE_LIBPCRE2"; then

GIT_STASH_FLAGS($LIBPCREDIR)

AC_CHECK_LIB([pcre2-8], [pcre2_config_8],
[USE_LIBPCRE2=YesPlease],
[USE_LIBPCRE2=])

GIT_UNSTASH_FLAGS($LIBPCREDIR)

GIT_CONF_SUBST([USE_LIBPCRE2])


fi fi



183
grep.c
View File

@ -179,22 +179,37 @@ static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, st
case GREP_PATTERN_TYPE_BRE: case GREP_PATTERN_TYPE_BRE:
opt->fixed = 0; opt->fixed = 0;
opt->pcre1 = 0; opt->pcre1 = 0;
opt->pcre2 = 0;
break; break;


case GREP_PATTERN_TYPE_ERE: case GREP_PATTERN_TYPE_ERE:
opt->fixed = 0; opt->fixed = 0;
opt->pcre1 = 0; opt->pcre1 = 0;
opt->pcre2 = 0;
opt->regflags |= REG_EXTENDED; opt->regflags |= REG_EXTENDED;
break; break;


case GREP_PATTERN_TYPE_FIXED: case GREP_PATTERN_TYPE_FIXED:
opt->fixed = 1; opt->fixed = 1;
opt->pcre1 = 0; opt->pcre1 = 0;
opt->pcre2 = 0;
break; break;


case GREP_PATTERN_TYPE_PCRE: case GREP_PATTERN_TYPE_PCRE:
opt->fixed = 0; opt->fixed = 0;
#ifdef USE_LIBPCRE2
opt->pcre1 = 0;
opt->pcre2 = 1;
#else
/*
* It's important that pcre1 always be assigned to
* even when there's no USE_LIBPCRE* defined. We still
* call the PCRE stub function, it just dies with
* "cannot use Perl-compatible regexes[...]".
*/
opt->pcre1 = 1; opt->pcre1 = 1;
opt->pcre2 = 0;
#endif
break; break;
} }
} }
@ -365,9 +380,22 @@ static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt)
if (!p->pcre1_regexp) if (!p->pcre1_regexp)
compile_regexp_failed(p, error); compile_regexp_failed(p, error);


p->pcre1_extra_info = pcre_study(p->pcre1_regexp, 0, &error); p->pcre1_extra_info = pcre_study(p->pcre1_regexp, PCRE_STUDY_JIT_COMPILE, &error);
if (!p->pcre1_extra_info && error) if (!p->pcre1_extra_info && error)
die("%s", error); die("%s", error);

#ifdef GIT_PCRE1_USE_JIT
pcre_config(PCRE_CONFIG_JIT, &p->pcre1_jit_on);
if (p->pcre1_jit_on == 1) {
p->pcre1_jit_stack = pcre_jit_stack_alloc(1, 1024 * 1024);
if (!p->pcre1_jit_stack)
die("Couldn't allocate PCRE JIT stack");
pcre_assign_jit_stack(p->pcre1_extra_info, NULL, p->pcre1_jit_stack);
} else if (p->pcre1_jit_on != 0) {
die("BUG: The pcre1_jit_on variable should be 0 or 1, not %d",
p->pcre1_jit_on);
}
#endif
} }


static int pcre1match(struct grep_pat *p, const char *line, const char *eol, static int pcre1match(struct grep_pat *p, const char *line, const char *eol,
@ -378,8 +406,19 @@ static int pcre1match(struct grep_pat *p, const char *line, const char *eol,
if (eflags & REG_NOTBOL) if (eflags & REG_NOTBOL)
flags |= PCRE_NOTBOL; flags |= PCRE_NOTBOL;


ret = pcre_exec(p->pcre1_regexp, p->pcre1_extra_info, line, eol - line, #ifdef GIT_PCRE1_USE_JIT
0, flags, ovector, ARRAY_SIZE(ovector)); if (p->pcre1_jit_on) {
ret = pcre_jit_exec(p->pcre1_regexp, p->pcre1_extra_info, line,
eol - line, 0, flags, ovector,
ARRAY_SIZE(ovector), p->pcre1_jit_stack);
} else
#endif
{
ret = pcre_exec(p->pcre1_regexp, p->pcre1_extra_info, line,
eol - line, 0, flags, ovector,
ARRAY_SIZE(ovector));
}

if (ret < 0 && ret != PCRE_ERROR_NOMATCH) if (ret < 0 && ret != PCRE_ERROR_NOMATCH)
die("pcre_exec failed with error code %d", ret); die("pcre_exec failed with error code %d", ret);
if (ret > 0) { if (ret > 0) {
@ -394,7 +433,15 @@ static int pcre1match(struct grep_pat *p, const char *line, const char *eol,
static void free_pcre1_regexp(struct grep_pat *p) static void free_pcre1_regexp(struct grep_pat *p)
{ {
pcre_free(p->pcre1_regexp); pcre_free(p->pcre1_regexp);
#ifdef GIT_PCRE1_USE_JIT
if (p->pcre1_jit_on) {
pcre_free_study(p->pcre1_extra_info);
pcre_jit_stack_free(p->pcre1_jit_stack);
} else
#endif
{
pcre_free(p->pcre1_extra_info); pcre_free(p->pcre1_extra_info);
}
pcre_free((void *)p->pcre1_tables); pcre_free((void *)p->pcre1_tables);
} }
#else /* !USE_LIBPCRE1 */ #else /* !USE_LIBPCRE1 */
@ -414,6 +461,127 @@ static void free_pcre1_regexp(struct grep_pat *p)
} }
#endif /* !USE_LIBPCRE1 */ #endif /* !USE_LIBPCRE1 */


#ifdef USE_LIBPCRE2
static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
{
int error;
PCRE2_UCHAR errbuf[256];
PCRE2_SIZE erroffset;
int options = PCRE2_MULTILINE;
const uint8_t *character_tables = NULL;
int jitret;

assert(opt->pcre2);

p->pcre2_compile_context = NULL;

if (opt->ignore_case) {
if (has_non_ascii(p->pattern)) {
character_tables = pcre2_maketables(NULL);
p->pcre2_compile_context = pcre2_compile_context_create(NULL);
pcre2_set_character_tables(p->pcre2_compile_context, character_tables);
}
options |= PCRE2_CASELESS;
}
if (is_utf8_locale() && has_non_ascii(p->pattern))
options |= PCRE2_UTF;

p->pcre2_pattern = pcre2_compile((PCRE2_SPTR)p->pattern,
p->patternlen, options, &error, &erroffset,
p->pcre2_compile_context);

if (p->pcre2_pattern) {
p->pcre2_match_data = pcre2_match_data_create_from_pattern(p->pcre2_pattern, NULL);
if (!p->pcre2_match_data)
die("Couldn't allocate PCRE2 match data");
} else {
pcre2_get_error_message(error, errbuf, sizeof(errbuf));
compile_regexp_failed(p, (const char *)&errbuf);
}

pcre2_config(PCRE2_CONFIG_JIT, &p->pcre2_jit_on);
if (p->pcre2_jit_on == 1) {
jitret = pcre2_jit_compile(p->pcre2_pattern, PCRE2_JIT_COMPLETE);
if (jitret)
die("Couldn't JIT the PCRE2 pattern '%s', got '%d'\n", p->pattern, jitret);
p->pcre2_jit_stack = pcre2_jit_stack_create(1, 1024 * 1024, NULL);
if (!p->pcre2_jit_stack)
die("Couldn't allocate PCRE2 JIT stack");
p->pcre2_match_context = pcre2_match_context_create(NULL);
if (!p->pcre2_jit_stack)
die("Couldn't allocate PCRE2 match context");
pcre2_jit_stack_assign(p->pcre2_match_context, NULL, p->pcre2_jit_stack);
} else if (p->pcre2_jit_on != 0) {
die("BUG: The pcre2_jit_on variable should be 0 or 1, not %d",
p->pcre1_jit_on);
}
}

static int pcre2match(struct grep_pat *p, const char *line, const char *eol,
regmatch_t *match, int eflags)
{
int ret, flags = 0;
PCRE2_SIZE *ovector;
PCRE2_UCHAR errbuf[256];

if (eflags & REG_NOTBOL)
flags |= PCRE2_NOTBOL;

if (p->pcre2_jit_on)
ret = pcre2_jit_match(p->pcre2_pattern, (unsigned char *)line,
eol - line, 0, flags, p->pcre2_match_data,
NULL);
else
ret = pcre2_match(p->pcre2_pattern, (unsigned char *)line,
eol - line, 0, flags, p->pcre2_match_data,
NULL);

if (ret < 0 && ret != PCRE2_ERROR_NOMATCH) {
pcre2_get_error_message(ret, errbuf, sizeof(errbuf));
die("%s failed with error code %d: %s",
(p->pcre2_jit_on ? "pcre2_jit_match" : "pcre2_match"), ret,
errbuf);
}
if (ret > 0) {
ovector = pcre2_get_ovector_pointer(p->pcre2_match_data);
ret = 0;
match->rm_so = (int)ovector[0];
match->rm_eo = (int)ovector[1];
}

return ret;
}

static void free_pcre2_pattern(struct grep_pat *p)
{
pcre2_compile_context_free(p->pcre2_compile_context);
pcre2_code_free(p->pcre2_pattern);
pcre2_match_data_free(p->pcre2_match_data);
pcre2_jit_stack_free(p->pcre2_jit_stack);
pcre2_match_context_free(p->pcre2_match_context);
}
#else /* !USE_LIBPCRE2 */
static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
{
/*
* Unreachable until USE_LIBPCRE2 becomes synonymous with
* USE_LIBPCRE. See the sibling comment in
* grep_set_pattern_type_option().
*/
die("cannot use Perl-compatible regexes when not compiled with USE_LIBPCRE");
}

static int pcre2match(struct grep_pat *p, const char *line, const char *eol,
regmatch_t *match, int eflags)
{
return 1;
}

static void free_pcre2_pattern(struct grep_pat *p)
{
}
#endif /* !USE_LIBPCRE2 */

static void compile_fixed_regexp(struct grep_pat *p, struct grep_opt *opt) static void compile_fixed_regexp(struct grep_pat *p, struct grep_opt *opt)
{ {
struct strbuf sb = STRBUF_INIT; struct strbuf sb = STRBUF_INIT;
@ -479,6 +647,11 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
return; return;
} }


if (opt->pcre2) {
compile_pcre2_pattern(p, opt);
return;
}

if (opt->pcre1) { if (opt->pcre1) {
compile_pcre1_regexp(p, opt); compile_pcre1_regexp(p, opt);
return; return;
@ -838,6 +1011,8 @@ void free_grep_patterns(struct grep_opt *opt)
kwsfree(p->kws); kwsfree(p->kws);
else if (p->pcre1_regexp) else if (p->pcre1_regexp)
free_pcre1_regexp(p); free_pcre1_regexp(p);
else if (p->pcre2_pattern)
free_pcre2_pattern(p);
else else
regfree(&p->regexp); regfree(&p->regexp);
free(p->pattern); free(p->pattern);
@ -918,6 +1093,8 @@ static int patmatch(struct grep_pat *p, char *line, char *eol,
hit = !fixmatch(p, line, eol, match); hit = !fixmatch(p, line, eol, match);
else if (p->pcre1_regexp) else if (p->pcre1_regexp)
hit = !pcre1match(p, line, eol, match, eflags); hit = !pcre1match(p, line, eol, match, eflags);
else if (p->pcre2_pattern)
hit = !pcre2match(p, line, eol, match, eflags);
else else
hit = !regexec_buf(&p->regexp, line, eol - line, 1, match, hit = !regexec_buf(&p->regexp, line, eol - line, 1, match,
eflags); eflags);

33
grep.h
View File

@ -3,9 +3,33 @@
#include "color.h" #include "color.h"
#ifdef USE_LIBPCRE1 #ifdef USE_LIBPCRE1
#include <pcre.h> #include <pcre.h>
#ifdef PCRE_CONFIG_JIT
#if PCRE_MAJOR >= 8 && PCRE_MINOR >= 32
#ifndef NO_LIBPCRE1_JIT
#define GIT_PCRE1_USE_JIT
#endif
#endif
#endif
#ifndef PCRE_STUDY_JIT_COMPILE
#define PCRE_STUDY_JIT_COMPILE 0
#endif
#if PCRE_MAJOR <= 8 && PCRE_MINOR < 20
typedef int pcre_jit_stack;
#endif
#else #else
typedef int pcre; typedef int pcre;
typedef int pcre_extra; typedef int pcre_extra;
typedef int pcre_jit_stack;
#endif
#ifdef USE_LIBPCRE2
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
#else
typedef int pcre2_code;
typedef int pcre2_match_data;
typedef int pcre2_compile_context;
typedef int pcre2_match_context;
typedef int pcre2_jit_stack;
#endif #endif
#include "kwset.h" #include "kwset.h"
#include "thread-utils.h" #include "thread-utils.h"
@ -48,7 +72,15 @@ struct grep_pat {
regex_t regexp; regex_t regexp;
pcre *pcre1_regexp; pcre *pcre1_regexp;
pcre_extra *pcre1_extra_info; pcre_extra *pcre1_extra_info;
pcre_jit_stack *pcre1_jit_stack;
const unsigned char *pcre1_tables; const unsigned char *pcre1_tables;
int pcre1_jit_on;
pcre2_code *pcre2_pattern;
pcre2_match_data *pcre2_match_data;
pcre2_compile_context *pcre2_compile_context;
pcre2_match_context *pcre2_match_context;
pcre2_jit_stack *pcre2_jit_stack;
uint32_t pcre2_jit_on;
kwset_t kws; kwset_t kws;
unsigned fixed:1; unsigned fixed:1;
unsigned ignore_case:1; unsigned ignore_case:1;
@ -112,6 +144,7 @@ struct grep_opt {
int extended; int extended;
int use_reflog_filter; int use_reflog_filter;
int pcre1; int pcre1;
int pcre2;
int relative; int relative;
int pathname; int pathname;
int null_following_name; int null_following_name;

View File

@ -2031,7 +2031,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
DIFF_OPT_SET(&revs->diffopt, PICKAXE_IGNORE_CASE); DIFF_OPT_SET(&revs->diffopt, PICKAXE_IGNORE_CASE);
} else if (!strcmp(arg, "--fixed-strings") || !strcmp(arg, "-F")) { } else if (!strcmp(arg, "--fixed-strings") || !strcmp(arg, "-F")) {
revs->grep_filter.pattern_type_option = GREP_PATTERN_TYPE_FIXED; revs->grep_filter.pattern_type_option = GREP_PATTERN_TYPE_FIXED;
} else if (!strcmp(arg, "--perl-regexp")) { } else if (!strcmp(arg, "--perl-regexp") || !strcmp(arg, "-P")) {
revs->grep_filter.pattern_type_option = GREP_PATTERN_TYPE_PCRE; revs->grep_filter.pattern_type_option = GREP_PATTERN_TYPE_PCRE;
} else if (!strcmp(arg, "--all-match")) { } else if (!strcmp(arg, "--all-match")) {
revs->grep_filter.all_match = 1; revs->grep_filter.all_match = 1;

View File

@ -404,8 +404,20 @@ test_expect_success 'log with various grep.patternType configurations & command-
--grep="(1|2)" >actual.fixed.short-arg && --grep="(1|2)" >actual.fixed.short-arg &&
git log --pretty=tformat:%s -E \ git log --pretty=tformat:%s -E \
--grep="\|2" >actual.extended.short-arg && --grep="\|2" >actual.extended.short-arg &&
if test_have_prereq PCRE
then
git log --pretty=tformat:%s -P \
--grep="[\d]\|" >actual.perl.short-arg
else
test_must_fail git log -P \
--grep="[\d]\|"
fi &&
test_cmp expect.fixed actual.fixed.short-arg && test_cmp expect.fixed actual.fixed.short-arg &&
test_cmp expect.extended actual.extended.short-arg && test_cmp expect.extended actual.extended.short-arg &&
if test_have_prereq PCRE
then
test_cmp expect.perl actual.perl.short-arg
fi &&


git log --pretty=tformat:%s --fixed-strings \ git log --pretty=tformat:%s --fixed-strings \
--grep="(1|2)" >actual.fixed.long-arg && --grep="(1|2)" >actual.fixed.long-arg &&

View File

@ -1020,7 +1020,7 @@ esac
test -z "$NO_PERL" && test_set_prereq PERL test -z "$NO_PERL" && test_set_prereq PERL
test -z "$NO_PTHREADS" && test_set_prereq PTHREADS test -z "$NO_PTHREADS" && test_set_prereq PTHREADS
test -z "$NO_PYTHON" && test_set_prereq PYTHON test -z "$NO_PYTHON" && test_set_prereq PYTHON
test -n "$USE_LIBPCRE1" && test_set_prereq PCRE test -n "$USE_LIBPCRE1$USE_LIBPCRE2" && test_set_prereq PCRE
test -z "$NO_GETTEXT" && test_set_prereq GETTEXT test -z "$NO_GETTEXT" && test_set_prereq GETTEXT


# Can we rely on git's output in the C locale? # Can we rely on git's output in the C locale?