From 9725c8dda20dc9bc02b552a2333963c8cb834d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Wed, 16 Feb 2022 01:00:34 +0100 Subject: built-ins: trust the "prefix" from run_builtin() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change code in "builtin/grep.c" and "builtin/ls-tree.c" to trust the "prefix" passed from "run_builtin()". The "prefix" we get from setup.c is either going to be NULL or a string of length >0, never "". So we can drop the "prefix && *prefix" checks added for "builtin/grep.c" in 0d042fecf2f (git-grep: show pathnames relative to the current directory, 2006-08-11), and for "builtin/ls-tree.c" in a69dd585fca (ls-tree: chomp leading directories when run from a subdirectory, 2005-12-23). As seen in code in revision.c that was added in cd676a51367 (diff --relative: output paths as relative to the current subdirectory, 2008-02-12) we already have existing code that does away with this assertion. This makes it easier to reason about a subsequent change to the "prefix_length" code in grep.c in a subsequent commit, and since we're going to the trouble of doing that let's leave behind an assert() to promise this to any future callers. For "builtin/grep.c" it would be painful to pass the "prefix" down the callchain of: cmd_grep -> grep_tree -> grep_submodule -> grep_cache -> grep_oid -> grep_source_name So for the code that needs it in grep_source_name() let's add a "grep_prefix" variable similar to the existing "ls_tree_prefix". While at it let's move the code in cmd_ls_tree() around so that we assign to the "ls_tree_prefix" right after declaring the variables, and stop assigning to "prefix". We only subsequently used that variable later in the function after clobbering it. Let's just use our own "grep_prefix" instead. Let's also add an assert() in git.c, so that we'll make this promise about the "prefix" to any current and future callers, as well as to any readers of the code. Code history: * The strlen() in "grep.c" hasn't been used since 493b7a08d80 (grep: accept relative paths outside current working directory, 2009-09-05). When that code was added in 0d042fecf2f (git-grep: show pathnames relative to the current directory, 2006-08-11) we used the length. But since 493b7a08d80 we haven't used it for anything except a boolean check that we could have done on the "prefix" member itself. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- grep.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'grep.c') diff --git a/grep.c b/grep.c index 7bb0360869..8421dc5548 100644 --- a/grep.c +++ b/grep.c @@ -139,13 +139,11 @@ int grep_config(const char *var, const char *value, void *cb) * default values from the template we read the configuration * information in an earlier call to git_config(grep_config). */ -void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix) +void grep_init(struct grep_opt *opt, struct repository *repo) { *opt = grep_defaults; opt->repo = repo; - opt->prefix = prefix; - opt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0; opt->pattern_tail = &opt->pattern_list; opt->header_tail = &opt->header_list; } -- cgit v1.2.3 From 72365bb49923da065e7a43e61a912ef17f143c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Wed, 16 Feb 2022 01:00:36 +0100 Subject: grep API: call grep_config() after grep_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The grep_init() function used the odd pattern of initializing the passed-in "struct grep_opt" with a statically defined "grep_defaults" struct, which would be modified in-place when we invoked grep_config(). So we effectively (b) initialized config, (a) then defaults, (c) followed by user options. Usually those are ordered as "a", "b" and "c" instead. As the comments being removed here show the previous behavior needed to be carefully explained as we'd potentially share the populated configuration among different instances of grep_init(). In practice we didn't do that, but now that it can't be a concern anymore let's remove those comments. This does not change the behavior of any of the configuration variables or options. That would have been the case if we didn't move around the grep_config() call in "builtin/log.c". But now that we call "grep_config" after "git_log_config" and "git_format_config" we'll need to pass in the already initialized "struct grep_opt *". See 6ba9bb76e02 (grep: copy struct in one fell swoop, 2020-11-29) and 7687a0541e0 (grep: move the configuration parsing logic to grep.[ch], 2012-10-09) for the commits that added the comments. The memcpy() pattern here will be optimized away and follows the convention of other *_init() functions. See 5726a6b4012 (*.c *_init(): define in terms of corresponding *_INIT macro, 2021-07-01). Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- grep.c | 39 +++------------------------------------ 1 file changed, 3 insertions(+), 36 deletions(-) (limited to 'grep.c') diff --git a/grep.c b/grep.c index 8421dc5548..35e12e43c0 100644 --- a/grep.c +++ b/grep.c @@ -19,27 +19,6 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size) fwrite(buf, size, 1, stdout); } -static struct grep_opt grep_defaults = { - .relative = 1, - .pathname = 1, - .max_depth = -1, - .pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, - .colors = { - [GREP_COLOR_CONTEXT] = "", - [GREP_COLOR_FILENAME] = GIT_COLOR_MAGENTA, - [GREP_COLOR_FUNCTION] = "", - [GREP_COLOR_LINENO] = GIT_COLOR_GREEN, - [GREP_COLOR_COLUMNNO] = GIT_COLOR_GREEN, - [GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, - [GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, - [GREP_COLOR_SELECTED] = "", - [GREP_COLOR_SEP] = GIT_COLOR_CYAN, - }, - .only_matching = 0, - .color = -1, - .output = std_output, -}; - static const char *color_grep_slots[] = { [GREP_COLOR_CONTEXT] = "context", [GREP_COLOR_FILENAME] = "filename", @@ -75,20 +54,12 @@ define_list_config_array_extra(color_grep_slots, {"match"}); */ int grep_config(const char *var, const char *value, void *cb) { - struct grep_opt *opt = &grep_defaults; + struct grep_opt *opt = cb; const char *slot; if (userdiff_config(var, value) < 0) return -1; - /* - * The instance of grep_opt that we set up here is copied by - * grep_init() to be used by each individual invocation. - * When populating a new field of this structure here, be - * sure to think about ownership -- e.g., you might need to - * override the shallow copy in grep_init() with a deep copy. - */ - if (!strcmp(var, "grep.extendedregexp")) { opt->extended_regexp_option = git_config_bool(var, value); return 0; @@ -134,14 +105,10 @@ int grep_config(const char *var, const char *value, void *cb) return 0; } -/* - * Initialize one instance of grep_opt and copy the - * default values from the template we read the configuration - * information in an earlier call to git_config(grep_config). - */ void grep_init(struct grep_opt *opt, struct repository *repo) { - *opt = grep_defaults; + struct grep_opt blank = GREP_OPT_INIT; + memcpy(opt, &blank, sizeof(*opt)); opt->repo = repo; opt->pattern_tail = &opt->pattern_list; -- cgit v1.2.3 From ae807d778f502c81ec55897ac6d1f42ef3a4e23b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Wed, 16 Feb 2022 01:00:38 +0100 Subject: grep.c: do "if (bool && memchr())" not "if (memchr() && bool)" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change code in compile_regexp() to check the cheaper boolean "!opt->pcre2" condition before the "memchr()" search. This doesn't noticeably optimize anything, but makes the code more obvious and conventional. The line wrapping being added here also makes a subsequent commit smaller. Signed-off-by: Ævar Arnfjörð Bjarmason Signed-off-by: Junio C Hamano --- grep.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'grep.c') diff --git a/grep.c b/grep.c index 35e12e43c0..60228a95a4 100644 --- a/grep.c +++ b/grep.c @@ -492,7 +492,8 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt) p->ignore_case = opt->ignore_case; p->fixed = opt->fixed; - if (memchr(p->pattern, 0, p->patternlen) && !opt->pcre2) + if (!opt->pcre2 && + memchr(p->pattern, 0, p->patternlen)) die(_("given pattern contains NULL byte (via -f ). This is only supported with -P under PCRE v2")); p->is_fixed = is_fixed(p->pattern, p->patternlen); -- cgit v1.2.3 From 04bf052eef53c6be04d313d8ce11690beaf890b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86var=20Arnfj=C3=B6r=C3=B0=20Bjarmason?= Date: Wed, 16 Feb 2022 01:00:39 +0100 Subject: grep: simplify config parsing and option parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Junio C Hamano --- grep.c | 69 +++++++++--------------------------------------------------------- 1 file changed, 9 insertions(+), 60 deletions(-) (limited to 'grep.c') diff --git a/grep.c b/grep.c index 60228a95a4..a8f503f55c 100644 --- a/grep.c +++ b/grep.c @@ -115,62 +115,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo) opt->header_tail = &opt->header_list; } -static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt) -{ - /* - * When committing to the pattern type by setting the relevant - * fields in grep_opt it's generally not necessary to zero out - * the fields we're not choosing, since they won't have been - * set by anything. The extended_regexp_option field is the - * only exception to this. - * - * This is because in the process of parsing grep.patternType - * & grep.extendedRegexp we set opt->pattern_type_option and - * opt->extended_regexp_option, respectively. We then - * internally use opt->extended_regexp_option to see if we're - * compiling an ERE. It must be unset if that's not actually - * the case. - */ - if (pattern_type != GREP_PATTERN_TYPE_ERE && - opt->extended_regexp_option) - opt->extended_regexp_option = 0; - - switch (pattern_type) { - case GREP_PATTERN_TYPE_UNSPECIFIED: - /* fall through */ - - case GREP_PATTERN_TYPE_BRE: - break; - - case GREP_PATTERN_TYPE_ERE: - opt->extended_regexp_option = 1; - break; - - case GREP_PATTERN_TYPE_FIXED: - opt->fixed = 1; - break; - - case GREP_PATTERN_TYPE_PCRE: - opt->pcre2 = 1; - break; - } -} - -void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt) -{ - if (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED) - grep_set_pattern_type_option(pattern_type, opt); - else if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED) - grep_set_pattern_type_option(opt->pattern_type_option, opt); - else if (opt->extended_regexp_option) - /* - * This branch *must* happen after setting from the - * opt->pattern_type_option above, we don't want - * grep.extendedRegexp to override grep.patternType! - */ - grep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt); -} - static struct grep_pat *create_grep_pat(const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t, @@ -488,11 +432,16 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt) int err; int regflags = REG_NEWLINE; + if (opt->pattern_type_option == GREP_PATTERN_TYPE_UNSPECIFIED) + opt->pattern_type_option = (opt->extended_regexp_option + ? GREP_PATTERN_TYPE_ERE + : GREP_PATTERN_TYPE_BRE); + p->word_regexp = opt->word_regexp; p->ignore_case = opt->ignore_case; - p->fixed = opt->fixed; + p->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED; - if (!opt->pcre2 && + if (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE && memchr(p->pattern, 0, p->patternlen)) die(_("given pattern contains NULL byte (via -f ). This is only supported with -P under PCRE v2")); @@ -544,14 +493,14 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt) return; } - if (opt->pcre2) { + if (opt->pattern_type_option == GREP_PATTERN_TYPE_PCRE) { compile_pcre2_pattern(p, opt); return; } if (p->ignore_case) regflags |= REG_ICASE; - if (opt->extended_regexp_option) + if (opt->pattern_type_option == GREP_PATTERN_TYPE_ERE) regflags |= REG_EXTENDED; err = regcomp(&p->regexp, p->pattern, regflags); if (err) { -- cgit v1.2.3