grep: simplify config parsing and option parsing

Simplify the parsing of "grep.patternType" and "grep.extendedRegexp". This changes no behavior, but gets rid of complex parsing logic that isn't needed anymore. When "grep.patternType" was introduced in 84befcd0a4a (grep: add a grep.patternType configuration setting, 2012-08-03) we promised that: 1. You can set "grep.patternType", and "[setting it to] 'default' will return to the default matching behavior". In that context "the default" meant whatever the configuration system specified before that change, i.e. via grep.extendedRegexp. 2. We'd support the existing "grep.extendedRegexp" option, but ignore it when the new "grep.patternType" option is set. We said we'd only ignore the older "grep.extendedRegexp" option "when the `grep.patternType` option is set to a value other than 'default'". In a preceding commit we changed grep_config() to be called after grep_init(), which means that much of the complexity here can go away. As before both "grep.patternType" and "grep.extendedRegexp" are last-one-wins variable, with "grep.extendedRegexp" yielding to "grep.patternType", except when "grep.patternType=default". Note that as the previously added tests indicate this cannot be done on-the-fly as we see the config variables, without introducing more state keeping. I.e. if we see: -c grep.extendedRegexp=false -c grep.patternType=default -c extendedRegexp=true We need to select ERE, since grep.patternType=default unselects that variable, which normally has higher precedence, but we also need to select BRE in cases of: -c grep.extendedRegexp=true \ -c grep.extendedRegexp=false Which would not be the case for this, which select ERE: -c grep.patternType=extended \ -c grep.extendedRegexp=false Therefore we cannot do this on-the-fly in grep_config without also introducing tracking variables for not only the pattern type, but what the source of that pattern type was. So we need to decide on the pattern after our config was fully parsed. Let's do that by deferring the decision on the pattern type until it's time to compile it in compile_regexp(). By that time we've not only parsed the config, but also handled the command-line options. Those will set "opt.pattern_type_option" (*not* "opt.extended_regexp_option"!). At that point all we need to do is see if "grep.patternType" was UNSPECIFIED in the end (including an explicit "=default"), if so we'll use the "grep.extendedRegexp" configuration, if any. See my 07a3d411739 (grep: remove regflags from the public grep_opt API, 2017-06-29) for addition of the two comments being removed here, i.e. the complexity noted in that commit is now going away. 1. https://lore.kernel.org/git/patch-v8-09.10-c211bb0c69d-20220118T155211Z-avarab@gmail.com/ Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Ævar Arnfjörð Bjarmason committed Feb 16, 2022 at 01:00 UTC 04bf052eef53c6be04d313d8ce11690beaf890b6
4 files changed +13 -71
builtin/grep.c
+4 -6
@@ -845,7 +845,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
845 int i;
846 int dummy;
847 int use_index = 1;
848 - int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;
848 int allow_revs;
849
850 struct option options[] = {
@@ -879,16 +878,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
878 N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
879 NULL, 1 },
880 OPT_GROUP(""),
882 - OPT_SET_INT('E', "extended-regexp", &pattern_type_arg,
881 + OPT_SET_INT('E', "extended-regexp", &opt.pattern_type_option,
882 N_("use extended POSIX regular expressions"),
883 GREP_PATTERN_TYPE_ERE),
885 - OPT_SET_INT('G', "basic-regexp", &pattern_type_arg,
884 + OPT_SET_INT('G', "basic-regexp", &opt.pattern_type_option,
885 N_("use basic POSIX regular expressions (default)"),
886 GREP_PATTERN_TYPE_BRE),
888 - OPT_SET_INT('F', "fixed-strings", &pattern_type_arg,
887 + OPT_SET_INT('F', "fixed-strings", &opt.pattern_type_option,
888 N_("interpret patterns as fixed strings"),
889 GREP_PATTERN_TYPE_FIXED),
891 - OPT_SET_INT('P', "perl-regexp", &pattern_type_arg,
890 + OPT_SET_INT('P', "perl-regexp", &opt.pattern_type_option,
891 N_("use Perl-compatible regular expressions"),
892 GREP_PATTERN_TYPE_PCRE),
893 OPT_GROUP(""),
@@ -982,7 +981,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
981 argc = parse_options(argc, argv, prefix, options, grep_usage,
982 PARSE_OPT_KEEP_DASHDASH |
983 PARSE_OPT_STOP_AT_NON_OPTION);
985 - grep_commit_pattern_type(pattern_type_arg, &opt);
984
985 if (use_index && !startup_info->have_repository) {
986 int fallback = 0;
grep.c
+9 -60
@@ -115,62 +115,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo)
115 opt->header_tail = &opt->header_list;
116 }
117
118 -static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)
119 -{
120 - /*
121 - * When committing to the pattern type by setting the relevant
122 - * fields in grep_opt it's generally not necessary to zero out
123 - * the fields we're not choosing, since they won't have been
124 - * set by anything. The extended_regexp_option field is the
125 - * only exception to this.
126 - *
127 - * This is because in the process of parsing grep.patternType
128 - * & grep.extendedRegexp we set opt->pattern_type_option and
129 - * opt->extended_regexp_option, respectively. We then
130 - * internally use opt->extended_regexp_option to see if we're
131 - * compiling an ERE. It must be unset if that's not actually
132 - * the case.
133 - */
134 - if (pattern_type != GREP_PATTERN_TYPE_ERE &&
135 - opt->extended_regexp_option)
136 - opt->extended_regexp_option = 0;
137 -
138 - switch (pattern_type) {
139 - case GREP_PATTERN_TYPE_UNSPECIFIED:
140 - /* fall through */
141 -
142 - case GREP_PATTERN_TYPE_BRE:
143 - break;
144 -
145 - case GREP_PATTERN_TYPE_ERE:
146 - opt->extended_regexp_option = 1;
147 - break;
148 -
149 - case GREP_PATTERN_TYPE_FIXED:
150 - opt->fixed = 1;
151 - break;
152 -
153 - case GREP_PATTERN_TYPE_PCRE:
154 - opt->pcre2 = 1;
155 - break;
156 - }
157 -}
158 -
159 -void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)
160 -{
161 - if (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)
162 - grep_set_pattern_type_option(pattern_type, opt);
163 - else if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)
164 - grep_set_pattern_type_option(opt->pattern_type_option, opt);
165 - else if (opt->extended_regexp_option)
166 - /*
167 - * This branch *must* happen after setting from the
168 - * opt->pattern_type_option above, we don't want
169 - * grep.extendedRegexp to override grep.patternType!
170 - */
171 - grep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);
172 -}
173 -
118 static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,
119 const char *origin, int no,
120 enum grep_pat_token t,
@@ -488,11 +432,16 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
432 int err;
433 int regflags = REG_NEWLINE;
434
435 + if (opt->pattern_type_option == GREP_PATTERN_TYPE_UNSPECIFIED)
436 + opt->pattern_type_option = (opt->extended_regexp_option
437 + ? GREP_PATTERN_TYPE_ERE
438 + : GREP_PATTERN_TYPE_BRE);
439 +
440 p->word_regexp = opt->word_regexp;
441 p->ignore_case = opt->ignore_case;
493 - p->fixed = opt->fixed;
442 + p->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;
443
495 - if (!opt->pcre2 &&
444 + if (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE &&
445 memchr(p->pattern, 0, p->patternlen))
446 die(_("given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2"));
447
@@ -544,14 +493,14 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
493 return;
494 }
495
547 - if (opt->pcre2) {
496 + if (opt->pattern_type_option == GREP_PATTERN_TYPE_PCRE) {
497 compile_pcre2_pattern(p, opt);
498 return;
499 }
500
501 if (p->ignore_case)
502 regflags |= REG_ICASE;
554 - if (opt->extended_regexp_option)
503 + if (opt->pattern_type_option == GREP_PATTERN_TYPE_ERE)
504 regflags |= REG_EXTENDED;
505 err = regcomp(&p->regexp, p->pattern, regflags);
506 if (err) {
grep.h
-3
@@ -143,7 +143,6 @@ struct grep_opt {
143 int unmatch_name_only;
144 int count;
145 int word_regexp;
146 - int fixed;
146 int all_match;
147 int no_body_match;
148 int body_hit;
@@ -154,7 +153,6 @@ struct grep_opt {
153 int allow_textconv;
154 int extended;
155 int use_reflog_filter;
157 - int pcre2;
156 int relative;
157 int pathname;
158 int null_following_name;
@@ -202,7 +200,6 @@ struct grep_opt {
200
201 int grep_config(const char *var, const char *value, void *);
202 void grep_init(struct grep_opt *, struct repository *repo);
205 -void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);
203
204 void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);
205 void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);
revision.c
-2
@@ -2860,8 +2860,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
2860
2861 diff_setup_done(&revs->diffopt);
2862
2863 - grep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,
2864 - &revs->grep_filter);
2863 if (!is_encoding_utf8(get_log_output_encoding()))
2864 revs->grep_filter.ignore_locale = 1;
2865 compile_grep_patterns(&revs->grep_filter);