int options = PCRE2_MULTILINE;
const uint8_t *character_tables = NULL;
int jitret;
+ int patinforet;
+ size_t jitsizearg;
assert(opt->pcre2);
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);
+
+ /*
+ * The pcre2_config(PCRE2_CONFIG_JIT, ...) call just
+ * tells us whether the library itself supports JIT,
+ * but to see whether we're going to be actually using
+ * JIT we need to extract PCRE2_INFO_JITSIZE from the
+ * pattern *after* we do pcre2_jit_compile() above.
+ *
+ * This is because if the pattern contains the
+ * (*NO_JIT) verb (see pcre2syntax(3))
+ * pcre2_jit_compile() will exit early with 0. If we
+ * then proceed to call pcre2_jit_match() further down
+ * the line instead of pcre2_match() we'll either
+ * segfault (pre PCRE 10.31) or run into a fatal error
+ * (post PCRE2 10.31)
+ */
+ patinforet = pcre2_pattern_info(p->pcre2_pattern, PCRE2_INFO_JITSIZE, &jitsizearg);
+ if (patinforet)
+ BUG("pcre2_pattern_info() failed: %d", patinforet);
+ if (jitsizearg == 0) {
+ p->pcre2_jit_on = 0;
+ return;
+ }
+
p->pcre2_jit_stack = pcre2_jit_stack_create(1, 1024 * 1024, NULL);
if (!p->pcre2_jit_stack)
die("Couldn't allocate PCRE2 JIT stack");
}
}
+static int is_empty_line(const char *bol, const char *eol);
+
static void show_pre_context(struct grep_opt *opt, struct grep_source *gs,
char *bol, char *end, unsigned lno)
{
- unsigned cur = lno, from = 1, funcname_lno = 0;
- int funcname_needed = !!opt->funcname;
-
- if (opt->funcbody && !match_funcname(opt, gs, bol, end))
- funcname_needed = 2;
+ unsigned cur = lno, from = 1, funcname_lno = 0, orig_from;
+ int funcname_needed = !!opt->funcname, comment_needed = 0;
if (opt->pre_context < lno)
from = lno - opt->pre_context;
if (from <= opt->last_shown)
from = opt->last_shown + 1;
+ orig_from = from;
+ if (opt->funcbody) {
+ if (match_funcname(opt, gs, bol, end))
+ comment_needed = 1;
+ else
+ funcname_needed = 1;
+ from = opt->last_shown + 1;
+ }
/* Rewind. */
- while (bol > gs->buf &&
- cur > (funcname_needed == 2 ? opt->last_shown + 1 : from)) {
+ while (bol > gs->buf && cur > from) {
+ char *next_bol = bol;
char *eol = --bol;
while (bol > gs->buf && bol[-1] != '\n')
bol--;
cur--;
+ if (comment_needed && (is_empty_line(bol, eol) ||
+ match_funcname(opt, gs, bol, eol))) {
+ comment_needed = 0;
+ from = orig_from;
+ if (cur < from) {
+ cur++;
+ bol = next_bol;
+ break;
+ }
+ }
if (funcname_needed && match_funcname(opt, gs, bol, eol)) {
funcname_lno = cur;
funcname_needed = 0;
+ if (opt->funcbody)
+ comment_needed = 1;
+ else
+ from = orig_from;
}
}
echo " line with leading space3"
echo "line without leading space2"
} >space &&
+ cat >hello.ps1 <<-\EOF &&
+ # No-op.
+ function dummy() {}
+
+ # Say hello.
+ function hello() {
+ echo "Hello world."
+ } # hello
+
+ # Still a no-op.
+ function dummy() {}
+ EOF
git add . &&
test_tick &&
git commit -m initial
test_cmp expected actual
'
-cat >expected <<EOF
-hello.c= printf("Hello world.\n");
-hello.c: return 0;
-hello.c- /* char ?? */
-EOF
-
test_expect_success 'grep -W with userdiff' '
test_when_finished "rm -f .gitattributes" &&
- git config diff.custom.xfuncname "(printf.*|})$" &&
- echo "hello.c diff=custom" >.gitattributes &&
- git grep -W return >actual &&
- test_cmp expected actual
+ git config diff.custom.xfuncname "^function .*$" &&
+ echo "hello.ps1 diff=custom" >.gitattributes &&
+ git grep -W echo >function-context-userdiff-actual
+'
+
+test_expect_success ' includes preceding comment' '
+ grep "# Say hello" function-context-userdiff-actual
+'
+
+test_expect_success ' includes function line' '
+ grep "=function hello" function-context-userdiff-actual
+'
+
+test_expect_success ' includes matching line' '
+ grep ": echo" function-context-userdiff-actual
+'
+
+test_expect_success ' includes last line of the function' '
+ grep "} # hello" function-context-userdiff-actual
'
for threads in $(test_seq 0 10)
test_cmp expected actual
'
+ test_expect_success LIBPCRE2 "grep -P with (*NO_JIT) doesn't error out" '
+ git grep -P "(*NO_JIT)\p{Ps}.*?\p{Pe}" hello.c >actual &&
+ test_cmp expected actual
+
+ '
+
test_expect_success !PCRE 'grep -P pattern errors without PCRE' '
test_must_fail git grep -P "foo.*bar"
'