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 threadingmaint
commit
ae7e4d4fed
|
|
@ -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.
|
||||||
|
|
|
||||||
49
Makefile
49
Makefile
|
|
@ -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)
|
||||||
BASIC_CFLAGS += -DUSE_LIBPCRE1
|
|
||||||
ifdef LIBPCREDIR
|
ifneq (,$(USE_LIBPCRE1))
|
||||||
BASIC_CFLAGS += -I$(LIBPCREDIR)/include
|
ifdef USE_LIBPCRE2
|
||||||
EXTLIBS += -L$(LIBPCREDIR)/$(lib) $(CC_LD_DYNPATH)$(LIBPCREDIR)/$(lib)
|
$(error Only set USE_LIBPCRE1 (or its alias USE_LIBPCRE) or USE_LIBPCRE2, not both!)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
BASIC_CFLAGS += -DUSE_LIBPCRE1
|
||||||
EXTLIBS += -lpcre
|
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
|
||||||
|
EXTLIBS += -L$(LIBPCREDIR)/$(lib) $(CC_LD_DYNPATH)$(LIBPCREDIR)/$(lib)
|
||||||
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)))'\' >>$@+
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,8 @@ 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;
|
||||||
o->debug = 0;
|
if (i)
|
||||||
|
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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
79
configure.ac
79
configure.ac
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
185
grep.c
185
grep.c
|
|
@ -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);
|
||||||
pcre_free(p->pcre1_extra_info);
|
#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((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
33
grep.h
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 &&
|
||||||
|
|
|
||||||
|
|
@ -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?
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue