grep/icase: avoid kwsset on literal non-ascii strings
When we detect the pattern is just a literal string, we avoid heavy regex engine and use fast substring search implemented in kwsset.c. But kws uses git-ctype which is locale-independent so it does not know how to fold case properly outside ascii range. Let regcomp or pcre take care of this case instead. Slower, but accurate. Noticed-by: Plamen Totev <plamen.totev@abv.bg> Helped-by: René Scharfe <l.s.r@web.de> Helped-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
Jun 25, 2016 at 07:22 UTC
5c1ebcca4d1df3b2a84d01b3f32ec13bf8f760f8
2 files changed
+29
-1
grep.c
+6
-1
@@ -4,6 +4,7 @@
4
#include "xdiff-interface.h"
5
#include "diff.h"
6
#include "diffcore.h"
7
+#include "commit.h"
8
9
static int grep_source_load(struct grep_source *gs);
10
static int grep_source_is_binary(struct grep_source *gs);
@@ -398,14 +399,18 @@ static int is_fixed(const char *s, size_t len)
399
400
static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
401
{
402
+ int icase, ascii_only;
403
int err;
404
405
p->word_regexp = opt->word_regexp;
406
p->ignore_case = opt->ignore_case;
407
+ icase = opt->regflags & REG_ICASE || p->ignore_case;
408
+ ascii_only = !has_non_ascii(p->pattern);
409
410
if (opt->fixed)
411
p->fixed = 1;
408
- else if (is_fixed(p->pattern, p->patternlen))
412
+ else if ((!icase || ascii_only) &&
413
+ is_fixed(p->pattern, p->patternlen))
414
p->fixed = 1;
415
else
416
p->fixed = 0;
t/t7812-grep-icase-non-ascii.sh
new
+23
@@ -0,0 +1,23 @@
1
+#!/bin/sh
2
+
3
+test_description='grep icase on non-English locales'
4
+
5
+. ./lib-gettext.sh
6
+
7
+test_expect_success GETTEXT_LOCALE 'setup' '
8
+ test_write_lines "TILRAUN: Halló Heimur!" >file &&
9
+ git add file &&
10
+ LC_ALL="$is_IS_locale" &&
11
+ export LC_ALL
12
+'
13
+
14
+test_have_prereq GETTEXT_LOCALE &&
15
+test-regex "HALLÓ" "Halló" ICASE &&
16
+test_set_prereq REGEX_LOCALE
17
+
18
+test_expect_success REGEX_LOCALE 'grep literal string, no -F' '
19
+ git grep -i "TILRAUN: Halló Heimur!" &&
20
+ git grep -i "TILRAUN: HALLÓ HEIMUR!"
21
+'
22
+
23
+test_done