{"thread":{"id":"56853","subject":"[PATCH 1/8] grep.h: remove unused \"regex_t regexp\" from grep_opt","startedAt":"2021-11-06T21:11:03Z","lastAt":"2022-03-04T10:05:12Z","messageCount":151,"participants":["Ævar Arnfjörð Bjarmason","Taylor Blau","Junio C Hamano","Fabian Stelzer"],"isPatch":true,"patchVersion":1,"patchTotal":8},"messages":[{"id":"440606","messageId":"patch-1.8-412b8b65266-20211106T210711Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-0.8-00000000000-20211106T210711Z-avarab@gmail.com","subject":"[PATCH 1/8] grep.h: remove unused \"regex_t regexp\" from grep_opt","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-06T21:10:47Z","receivedAt":"2021-11-06T21:11:03Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This \"regex_t\" in grep_opt has not been used since\nf9b9faf6f8a (builtin-grep: allow more than one patterns., 2006-05-02),\nwe still use a \"regex_t\" for compiling regexes, but that's in the\n\"grep_pat\" struct\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 3e8815c347b..95cccb670f9 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -136,7 +136,6 @@ struct grep_opt {\n \n \tconst char *prefix;\n \tint prefix_length;\n-\tregex_t regexp;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440607","messageId":"cover-0.8-00000000000-20211106T210711Z-avarab@gmail.com","threadId":"56853","inReplyTo":null,"subject":"[PATCH 0/8] grep: simplify & delete code by changing obscure cfg variable behavior","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-06T21:10:46Z","receivedAt":"2021-11-06T21:11:03Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"I'd like to use the grep API for more things in some upcoming\noptimization patches, and to do that I need to use grep_init(),\ngrep_config() etc.\n\nThese APIs have a very unusual API, and we've got quite a bit of code\nin grep.c to support an obscure edge case in how \"grep.extendedRegexp\"\nbehaves when clashing with a \"grep.patternType\" variable present in\nthe same config space.\n\nThis series is an opinionated change of that behavior, and resulting\nlarge deletion of code.\n\nThe series starts out by deleting some unused code in grep.c, and\nmoving a bit of related builtin/grep.c-specific code to that file, and\nout of grep.c.\n\nÆvar Arnfjörð Bjarmason (8):\n  grep.h: remove unused \"regex_t regexp\" from grep_opt\n  git.c & grep.c: assert that \"prefix\" is NULL or non-zero string\n  grep: remove unused \"prefix_length\" member\n  grep.c: move \"prefix\" out of \"struct grep_opt\"\n  log tests: check if grep_config() is called by \"log\"-like cmds\n  grep API: call grep_config() after grep_init()\n  grep: simplify config parsing, change grep.<rx config> interaction\n  grep: make \"extendedRegexp=true\" the same as \"patternType=extended\"\n\n Documentation/config/grep.txt |   4 +-\n Documentation/git-grep.txt    |   4 +-\n builtin/grep.c                |  31 +++++----\n builtin/log.c                 |  13 +++-\n git.c                         |   4 +-\n grep.c                        | 118 ++++------------------------------\n grep.h                        |  34 ++++++----\n revision.c                    |   4 +-\n t/t4202-log.sh                |  16 +++++\n t/t7810-grep.sh               |   4 +-\n 10 files changed, 89 insertions(+), 143 deletions(-)\n\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440608","messageId":"patch-2.8-244715e3497-20211106T210711Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-0.8-00000000000-20211106T210711Z-avarab@gmail.com","subject":"[PATCH 2/8] git.c & grep.c: assert that \"prefix\" is NULL or non-zero string","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-06T21:10:48Z","receivedAt":"2021-11-06T21:11:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"prefix\" we get from setup.c is either going to be NULL or a\nstring of length >0, never \"\". So let's drop the \"prefix && *prefix\"\ncheck in grep.c added in 0d042fecf2f (git-grep: show pathnames\nrelative to the current directory, 2006-08-11).\n\nAs seen in code in revision.c that was added in cd676a51367 (diff\n--relative: output paths as relative to the current subdirectory,\n2008-02-12) we have existing code that does away with this assertion.\n\nThis makes it easier to reason about a subsequent change to the\n\"prefix_length\" code in grep.c in a subsequent commit, and since we're\ngoing to the trouble of doing that let's leave behind an assert() to\npromise this to any future callers.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n git.c  | 4 ++--\n grep.c | 2 +-\n 2 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/git.c b/git.c\nindex 5ff21be21f3..aa4f0d77c4b 100644\n--- a/git.c\n+++ b/git.c\n@@ -420,9 +420,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n {\n \tint status, help;\n \tstruct stat st;\n-\tconst char *prefix;\n+\tconst char *prefix = NULL;\n \n-\tprefix = NULL;\n \thelp = argc == 2 && !strcmp(argv[1], \"-h\");\n \tif (!help) {\n \t\tif (p->option & RUN_SETUP)\n@@ -431,6 +430,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t\t\tint nongit_ok;\n \t\t\tprefix = setup_git_directory_gently(&nongit_ok);\n \t\t}\n+\t\tassert(!prefix || (prefix && *prefix));\n \t\tprecompose_argv_prefix(argc, argv, NULL);\n \t\tif (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY) &&\n \t\t    !(p->option & DELAY_PAGER_CONFIG))\ndiff --git a/grep.c b/grep.c\nindex f6e113e9f0f..88ebc504630 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -145,7 +145,7 @@ void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix\n \n \topt->repo = repo;\n \topt->prefix = prefix;\n-\topt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;\n+\topt->prefix_length = prefix ? strlen(prefix) : 0;\n \topt->pattern_tail = &opt->pattern_list;\n \topt->header_tail = &opt->header_list;\n }\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440609","messageId":"patch-3.8-3338cc95b81-20211106T210711Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-0.8-00000000000-20211106T210711Z-avarab@gmail.com","subject":"[PATCH 3/8] grep: remove unused \"prefix_length\" member","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-06T21:10:49Z","receivedAt":"2021-11-06T21:11:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Remove the \"prefix_length\" member, which we compute with a strlen() on\nthe \"prefix\" argument to grep_init(), but whose strlen() hasn't been\nused since 493b7a08d80 (grep: accept relative paths outside current\nworking directory, 2009-09-05).\n\nWhen this code was added in 0d042fecf2f (git-grep: show pathnames\nrelative to the current directory, 2006-08-11) we used the length, but\nsince 493b7a08d80 we haven't used it for anything except a boolean\ncheck that we could have done on the \"prefix\" member itself.\n\nBefore a preceding commit we also used to guard the strlen() with\n\"prefix && *prefix\", but as that commit notes the RHS of that && chain\nwas also redundant.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 4 ++--\n grep.c         | 1 -\n grep.h         | 1 -\n 3 files changed, 2 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 9e34a820ad4..bd4d2107351 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -315,7 +315,7 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \tstrbuf_reset(out);\n \n \tif (opt->null_following_name) {\n-\t\tif (opt->relative && opt->prefix_length) {\n+\t\tif (opt->relative && opt->prefix) {\n \t\t\tstruct strbuf rel_buf = STRBUF_INIT;\n \t\t\tconst char *rel_name =\n \t\t\t\trelative_path(filename + tree_name_len,\n@@ -332,7 +332,7 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \t\treturn;\n \t}\n \n-\tif (opt->relative && opt->prefix_length)\n+\tif (opt->relative && opt->prefix)\n \t\tquote_path(filename + tree_name_len, opt->prefix, out, 0);\n \telse\n \t\tquote_c_style(filename + tree_name_len, out, NULL, 0);\ndiff --git a/grep.c b/grep.c\nindex 88ebc504630..755afb5f96d 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -145,7 +145,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix\n \n \topt->repo = repo;\n \topt->prefix = prefix;\n-\topt->prefix_length = prefix ? strlen(prefix) : 0;\n \topt->pattern_tail = &opt->pattern_list;\n \topt->header_tail = &opt->header_list;\n }\ndiff --git a/grep.h b/grep.h\nindex 95cccb670f9..467d775b5a9 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -135,7 +135,6 @@ struct grep_opt {\n \tstruct repository *repo;\n \n \tconst char *prefix;\n-\tint prefix_length;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440610","messageId":"patch-4.8-78298657d69-20211106T210711Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-0.8-00000000000-20211106T210711Z-avarab@gmail.com","subject":"[PATCH 4/8] grep.c: move \"prefix\" out of \"struct grep_opt\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-06T21:10:50Z","receivedAt":"2021-11-06T21:11:08Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The \"struct grep_opt\" is a mixture of things that would be needed by\nall callers of the grep.c API, and quite a few things that only the\nbuiltin/grep.c needs.\n\nSince we got rid of \"prefix_length\" in the previous commit, let's move\nthe \"prefix\" variable over to \"builtin/grep.c\" where it's used. To do\nthis let's create a \"struct grep_cmd_opt\", which we'll have a pointer\nto in a new \"caller_priv\" member in \"struct grep_opt\" (the existing\n\"priv\" is used by the top-level \"grep.c\" itself).\n\nWe might eventually need to have grep_opt_dup() learn about this new\nmember, but since the prefix can be a \"const char *const\" (i.e. we\nnever change it in any way) let's leave that aside for now, in any\ncase \"builtin/grep.c\" is the only user of grep_opt_dup(), even though\nit lives in the top-level \"grep.c\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 17 ++++++++++++-----\n grep.c         |  3 +--\n grep.h         |  4 ++--\n revision.c     |  2 +-\n 4 files changed, 16 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex bd4d2107351..960c7aac123 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -37,6 +37,10 @@ static int num_threads;\n \n static pthread_t *threads;\n \n+struct grep_cmd_opt {\n+\tconst char *const prefix;\n+};\n+\n /* We use one producer thread and THREADS consumer\n  * threads. The producer adds struct work_items to 'todo' and the\n  * consumers pick work items from the same array.\n@@ -312,14 +316,15 @@ static int grep_cmd_config(const char *var, const char *value, void *cb)\n static void grep_source_name(struct grep_opt *opt, const char *filename,\n \t\t\t     int tree_name_len, struct strbuf *out)\n {\n+\tstruct grep_cmd_opt *opt_cmd = opt->caller_priv;\n \tstrbuf_reset(out);\n \n \tif (opt->null_following_name) {\n-\t\tif (opt->relative && opt->prefix) {\n+\t\tif (opt->relative && opt_cmd->prefix) {\n \t\t\tstruct strbuf rel_buf = STRBUF_INIT;\n \t\t\tconst char *rel_name =\n \t\t\t\trelative_path(filename + tree_name_len,\n-\t\t\t\t\t      opt->prefix, &rel_buf);\n+\t\t\t\t\t      opt_cmd->prefix, &rel_buf);\n \n \t\t\tif (tree_name_len)\n \t\t\t\tstrbuf_add(out, filename, tree_name_len);\n@@ -332,8 +337,8 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \t\treturn;\n \t}\n \n-\tif (opt->relative && opt->prefix)\n-\t\tquote_path(filename + tree_name_len, opt->prefix, out, 0);\n+\tif (opt->relative && opt_cmd->prefix)\n+\t\tquote_path(filename + tree_name_len, opt_cmd->prefix, out, 0);\n \telse\n \t\tquote_c_style(filename + tree_name_len, out, NULL, 0);\n \n@@ -837,6 +842,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tint external_grep_allowed__ignored;\n \tconst char *show_in_pager = NULL, *default_pager = \"dummy\";\n \tstruct grep_opt opt;\n+\tstruct grep_cmd_opt opt_cmd = { .prefix = prefix };\n \tstruct object_array list = OBJECT_ARRAY_INIT;\n \tstruct pathspec pathspec;\n \tstruct string_list path_list = STRING_LIST_INIT_DUP;\n@@ -964,7 +970,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t};\n \n \tgit_config(grep_cmd_config, NULL);\n-\tgrep_init(&opt, the_repository, prefix);\n+\tgrep_init(&opt, the_repository);\n+\topt.caller_priv = &opt_cmd;\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/grep.c b/grep.c\nindex 755afb5f96d..c9065254aeb 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -139,12 +139,11 @@ int grep_config(const char *var, const char *value, void *cb)\n  * default values from the template we read the configuration\n  * information in an earlier call to git_config(grep_config).\n  */\n-void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)\n+void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n \t*opt = grep_defaults;\n \n \topt->repo = repo;\n-\topt->prefix = prefix;\n \topt->pattern_tail = &opt->pattern_list;\n \topt->header_tail = &opt->header_list;\n }\ndiff --git a/grep.h b/grep.h\nindex 467d775b5a9..6b923d8599c 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -134,7 +134,6 @@ struct grep_opt {\n \t */\n \tstruct repository *repo;\n \n-\tconst char *prefix;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n@@ -172,6 +171,7 @@ struct grep_opt {\n \tint show_hunk_mark;\n \tint file_break;\n \tint heading;\n+\tvoid *caller_priv;\n \tvoid *priv;\n \n \tvoid (*output)(struct grep_opt *opt, const void *data, size_t size);\n@@ -179,7 +179,7 @@ struct grep_opt {\n };\n \n int grep_config(const char *var, const char *value, void *);\n-void grep_init(struct grep_opt *, struct repository *repo, const char *prefix);\n+void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex ab7c1358042..9f9b0d2429e 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1833,7 +1833,7 @@ void repo_init_revisions(struct repository *r,\n \trevs->commit_format = CMIT_FMT_DEFAULT;\n \trevs->expand_tabs_in_log_default = 8;\n \n-\tgrep_init(&revs->grep_filter, revs->repo, prefix);\n+\tgrep_init(&revs->grep_filter, revs->repo);\n \trevs->grep_filter.status_only = 1;\n \n \trepo_diff_setup(revs->repo, &revs->diffopt);\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440611","messageId":"patch-5.8-ba9be0b9283-20211106T210711Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-0.8-00000000000-20211106T210711Z-avarab@gmail.com","subject":"[PATCH 5/8] log tests: check if grep_config() is called by \"log\"-like cmds","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-06T21:10:51Z","receivedAt":"2021-11-06T21:11:08Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the tests added in my 9df46763ef1 (log: add exhaustive tests\nfor pattern style options & config, 2017-05-20) to check not only\nwhether \"git log\" handles \"grep.patternType\", but also \"git show\"\netc.\n\nIt's sufficient to check whether a PCRE regex matches for the purposes\nof this test, we otherwise assume that it's running the same code as\n\"git log\", whose behavior is tested more exhaustively by test added in\n9df46763ef1e.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4202-log.sh | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)\n\ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex 7884e3d46b3..a114c49ef27 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -449,6 +449,22 @@ test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurati\n \t)\n '\n \n+for cmd in show whatchanged reflog format-patch\n+do\n+\tmyarg=\n+\tif test \"$cmd\" = \"format-patch\"\n+\tthen\n+\t\tmyarg=\"HEAD~..\"\n+\tfi\n+\n+\ttest_expect_success PCRE \"$cmd: understands grep.patternType=perl, like 'log'\" '\n+\t\tgit -c grep.patternType=fixed -C pattern-type $cmd --grep=\"1(?=\\|2)\" $myarg >actual &&\n+\t\ttest_must_be_empty actual &&\n+\t\tgit -c grep.patternType=perl -C pattern-type $cmd --grep=\"1(?=\\|2)\" $myarg >actual &&\n+\t\ttest_file_not_empty actual\n+\t'\n+done\n+\n test_expect_success 'log --author' '\n \tcat >expect <<-\\EOF &&\n \tAuthor: <BOLD;RED>A U<RESET> Thor <author@example.com>\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440612","messageId":"patch-6.8-933ac853bca-20211106T210711Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-0.8-00000000000-20211106T210711Z-avarab@gmail.com","subject":"[PATCH 6/8] grep API: call grep_config() after grep_init()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-06T21:10:52Z","receivedAt":"2021-11-06T21:11:10Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The grep_init() function used the odd pattern of initializing the\npassed-in \"struct grep_opt\" with a statically defined \"grep_defaults\"\nstruct, which would be modified in-place when we invoked\ngrep_config().\n\nSo we effectively (b) initialized config, (a) then defaults, (c)\nfollowed by user options. Usually those are ordered as \"a\", \"b\" and\n\"c\" instead.\n\nAs the comments being removed here show the previous behavior needed\nto be carefully explained as we'd potentially share the populated\nconfiguration among different instances of grep_init(). In practice we\ndidn't do that, but now that it can't be a concern anymore let's\nremove those comments.\n\nSee 6ba9bb76e02 (grep: copy struct in one fell swoop, 2020-11-29) and\n7687a0541e0 (grep: move the configuration parsing logic to grep.[ch],\n2012-10-09) for the commits that added the comments.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c |  4 ++--\n builtin/log.c  | 13 +++++++++++--\n grep.c         | 39 +++------------------------------------\n grep.h         | 21 +++++++++++++++++++++\n 4 files changed, 37 insertions(+), 40 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 960c7aac123..7f95f44e948 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -288,7 +288,7 @@ static int wait_all(void)\n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n \tint st = grep_config(var, value, cb);\n-\tif (git_color_default_config(var, value, cb) < 0)\n+\tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n \tif (!strcmp(var, \"grep.threads\")) {\n@@ -969,8 +969,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\tOPT_END()\n \t};\n \n-\tgit_config(grep_cmd_config, NULL);\n \tgrep_init(&opt, the_repository);\n+\tgit_config(grep_cmd_config, &opt);\n \topt.caller_priv = &opt_cmd;\n \n \t/*\ndiff --git a/builtin/log.c b/builtin/log.c\nindex f75d87e8d7f..bfddacdfa6c 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -505,8 +505,6 @@ static int git_log_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n-\tif (grep_config(var, value, cb) < 0)\n-\t\treturn -1;\n \tif (git_gpg_config(var, value, cb) < 0)\n \t\treturn -1;\n \treturn git_diff_ui_config(var, value, cb);\n@@ -521,6 +519,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.simplify_history = 0;\n \tmemset(&opt, 0, sizeof(opt));\n@@ -635,6 +635,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \n \tmemset(&match_all, 0, sizeof(match_all));\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.always_show_header = 1;\n \trev.no_walk = 1;\n@@ -718,6 +720,8 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n \tinit_reflog_walk(&rev.reflog_info);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.verbose_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -751,6 +755,8 @@ int cmd_log(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.always_show_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -1833,10 +1839,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \textra_hdr.strdup_strings = 1;\n \textra_to.strdup_strings = 1;\n \textra_cc.strdup_strings = 1;\n+\n \tinit_log_defaults();\n \tinit_display_notes(&notes_opt);\n \tgit_config(git_format_config, NULL);\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.show_notes = show_notes;\n \tmemcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));\n \trev.commit_format = CMIT_FMT_EMAIL;\ndiff --git a/grep.c b/grep.c\nindex c9065254aeb..fb3f63c63ef 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -19,27 +19,6 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)\n \tfwrite(buf, size, 1, stdout);\n }\n \n-static struct grep_opt grep_defaults = {\n-\t.relative = 1,\n-\t.pathname = 1,\n-\t.max_depth = -1,\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t.colors = {\n-\t\t[GREP_COLOR_CONTEXT] = \"\",\n-\t\t[GREP_COLOR_FILENAME] = \"\",\n-\t\t[GREP_COLOR_FUNCTION] = \"\",\n-\t\t[GREP_COLOR_LINENO] = \"\",\n-\t\t[GREP_COLOR_COLUMNNO] = \"\",\n-\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_SELECTED] = \"\",\n-\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN,\n-\t},\n-\t.only_matching = 0,\n-\t.color = -1,\n-\t.output = std_output,\n-};\n-\n static const char *color_grep_slots[] = {\n \t[GREP_COLOR_CONTEXT]\t    = \"context\",\n \t[GREP_COLOR_FILENAME]\t    = \"filename\",\n@@ -75,20 +54,12 @@ define_list_config_array_extra(color_grep_slots, {\"match\"});\n  */\n int grep_config(const char *var, const char *value, void *cb)\n {\n-\tstruct grep_opt *opt = &grep_defaults;\n+\tstruct grep_opt *opt = cb;\n \tconst char *slot;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\t/*\n-\t * The instance of grep_opt that we set up here is copied by\n-\t * grep_init() to be used by each individual invocation.\n-\t * When populating a new field of this structure here, be\n-\t * sure to think about ownership -- e.g., you might need to\n-\t * override the shallow copy in grep_init() with a deep copy.\n-\t */\n-\n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n \t\treturn 0;\n@@ -134,14 +105,10 @@ int grep_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/*\n- * Initialize one instance of grep_opt and copy the\n- * default values from the template we read the configuration\n- * information in an earlier call to git_config(grep_config).\n- */\n void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n-\t*opt = grep_defaults;\n+\tstruct grep_opt blank = GREP_OPT_INIT;\n+\tmemcpy(opt, &blank, sizeof(*opt));\n \n \topt->repo = repo;\n \topt->pattern_tail = &opt->pattern_list;\ndiff --git a/grep.h b/grep.h\nindex 6b923d8599c..30a7dfd3294 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -178,6 +178,27 @@ struct grep_opt {\n \tvoid *output_priv;\n };\n \n+#define GREP_OPT_INIT { \\\n+\t.relative = 1, \\\n+\t.pathname = 1, \\\n+\t.max_depth = -1, \\\n+\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n+\t.colors = { \\\n+\t\t[GREP_COLOR_CONTEXT] = \"\", \\\n+\t\t[GREP_COLOR_FILENAME] = \"\", \\\n+\t\t[GREP_COLOR_FUNCTION] = \"\", \\\n+\t\t[GREP_COLOR_LINENO] = \"\", \\\n+\t\t[GREP_COLOR_COLUMNNO] = \"\", \\\n+\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_SELECTED] = \"\", \\\n+\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n+\t}, \\\n+\t.only_matching = 0, \\\n+\t.color = -1, \\\n+\t.output = std_output, \\\n+}\n+\n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440613","messageId":"patch-7.8-677a8f8520f-20211106T210711Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-0.8-00000000000-20211106T210711Z-avarab@gmail.com","subject":"[PATCH 7/8] grep: simplify config parsing, change grep.<rx config> interaction","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-06T21:10:53Z","receivedAt":"2021-11-06T21:11:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the interaction between \"grep.patternType=default\" and\n\"grep.extendedRegexp=true\" to make setting \"grep.extendedRegexp=true\"\nsynonymous with setting \"grep.patternType=extended\".\n\nThis changes our existing config parsing behavior as detailed below,\nbut in a way that's consistent with how we parse other\nconfiguration.\n\nPedantically speaking we're probably breaking past promises here, but\nI doubt that this will impact anyone in practice. The reduction in\ncomplexity and resulting consistency with other default config\nbehavior is worth it.\n\nWhen \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\ngrep.patternType configuration setting, 2012-08-03) we made two\nseemingly contradictory promises:\n\n 1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n    will return to the default matching behavior\".\n\n 2. Support the existing \"grep.extendedRegexp\" option, but ignore it\n    when the new \"grep.patternType\" is set, *except* \"when the\n    `grep.patternType` option is set. to a value other than 'default'\".\n\nI think that 84befcd0a4a probably didn't intend this behavior, but\ninstead ended up conflating our internal \"unspecified\" state with a\nuser's explicit desire to set the configuration back to the\ndefault.\n\nI.e. a user would correctly expect this to keep working:\n\n    # ERE grep\n    git -c grep.extendedRegexp=true grep <pattern>\n\nAnd likewise for \"grep.patternType=default\" to take precedence over\nthe disfavored \"grep.extendedRegexp\" option, i.e. the usual \"last set\nwins\" semantics.\n\n    # BRE grep\n    git -c grep.extendedRegexp=true -c grep.patternType=basic grep <pattern>\n\nBut probably not for this to ignore the new \"grep.patternType\" option\nentirely, say if /etc/gitconfig was still setting\n\"grep.extendedRegexp\", but \"~/.gitconfig\" used the new\n\"grep.patternType\" (and wanted to use the \"default\" value):\n\n    # Was ERE, now BRE\n    git -c grep.extendedRegexp=true grep.patternType=default grep <pattern>\n\nI think that in practice nobody or almost nobody is going to be\nrelying on this obscure interaction, and as shown here it makes the\nconfig parsing much simpler. We no longer have to carry a complex\nstate machine in \"grep_commit_pattern_type()\" and\n\"grep_set_pattern_type_option()\".\n\nWe can also do away with the \"int fixed\" and \"int pcre2\" members in\nfavor of using \"pattern_type_option\" directly in \"grep.c\", as well as\ndropping the \"pattern_type_arg\" variable in \"builtin/grep.c\" in favor\nof using the \"pattern_type_option\" member directly.\n\nSee my 07a3d411739 (grep: remove regflags from the public grep_opt\nAPI, 2017-06-29) for addition of the two comments being removed here,\ni.e. the complexity noted in that commit is now going away.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config/grep.txt |  3 +-\n Documentation/git-grep.txt    |  3 +-\n builtin/grep.c                | 10 ++---\n grep.c                        | 71 +++++------------------------------\n grep.h                        |  6 +--\n revision.c                    |  2 -\n t/t7810-grep.sh               |  2 +-\n 7 files changed, 17 insertions(+), 80 deletions(-)\n\ndiff --git a/Documentation/config/grep.txt b/Documentation/config/grep.txt\nindex 44abe45a7ca..2669b1757d3 100644\n--- a/Documentation/config/grep.txt\n+++ b/Documentation/config/grep.txt\n@@ -12,8 +12,7 @@ grep.patternType::\n \n grep.extendedRegexp::\n \tIf set to true, enable `--extended-regexp` option by default. This\n-\toption is ignored when the `grep.patternType` option is set to a value\n-\tother than 'default'.\n+\toption is ignored when the `grep.patternType` option is set.\n \n grep.threads::\n \tNumber of grep worker threads to use.\ndiff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt\nindex 3d393fbac1b..078dfeadf50 100644\n--- a/Documentation/git-grep.txt\n+++ b/Documentation/git-grep.txt\n@@ -348,8 +348,7 @@ grep.patternType::\n \n grep.extendedRegexp::\n \tIf set to true, enable `--extended-regexp` option by default. This\n-\toption is ignored when the `grep.patternType` option is set to a value\n-\tother than 'default'.\n+\toption is ignored when the `grep.patternType` option is set.\n \n grep.threads::\n \tNumber of grep worker threads to use. If unset (or set to 0), Git will\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 7f95f44e948..a4964baf9c0 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -849,7 +849,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tint i;\n \tint dummy;\n \tint use_index = 1;\n-\tint pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;\n \tint allow_revs;\n \n \tstruct option options[] = {\n@@ -883,16 +882,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"descend at most <depth> levels\"), PARSE_OPT_NONEG,\n \t\t\tNULL, 1 },\n \t\tOPT_GROUP(\"\"),\n-\t\tOPT_SET_INT('E', \"extended-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('E', \"extended-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use extended POSIX regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_ERE),\n-\t\tOPT_SET_INT('G', \"basic-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('G', \"basic-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use basic POSIX regular expressions (default)\"),\n \t\t\t    GREP_PATTERN_TYPE_BRE),\n-\t\tOPT_SET_INT('F', \"fixed-strings\", &pattern_type_arg,\n+\t\tOPT_SET_INT('F', \"fixed-strings\", &opt.pattern_type_option,\n \t\t\t    N_(\"interpret patterns as fixed strings\"),\n \t\t\t    GREP_PATTERN_TYPE_FIXED),\n-\t\tOPT_SET_INT('P', \"perl-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('P', \"perl-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use Perl-compatible regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_PCRE),\n \t\tOPT_GROUP(\"\"),\n@@ -986,7 +985,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, grep_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH |\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n-\tgrep_commit_pattern_type(pattern_type_arg, &opt);\n \n \tif (use_index && !startup_info->have_repository) {\n \t\tint fallback = 0;\ndiff --git a/grep.c b/grep.c\nindex fb3f63c63ef..dda8e536fe3 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -60,8 +60,10 @@ int grep_config(const char *var, const char *value, void *cb)\n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\tif (!strcmp(var, \"grep.extendedregexp\")) {\n-\t\topt->extended_regexp_option = git_config_bool(var, value);\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_UNSPECIFIED &&\n+\t    !strcmp(var, \"grep.extendedregexp\") &&\n+\t    git_config_bool(var, value)) {\n+\t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n \t\treturn 0;\n \t}\n \n@@ -115,62 +117,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo)\n \topt->header_tail = &opt->header_list;\n }\n \n-static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\t/*\n-\t * When committing to the pattern type by setting the relevant\n-\t * fields in grep_opt it's generally not necessary to zero out\n-\t * the fields we're not choosing, since they won't have been\n-\t * set by anything. The extended_regexp_option field is the\n-\t * only exception to this.\n-\t *\n-\t * This is because in the process of parsing grep.patternType\n-\t * & grep.extendedRegexp we set opt->pattern_type_option and\n-\t * opt->extended_regexp_option, respectively. We then\n-\t * internally use opt->extended_regexp_option to see if we're\n-\t * compiling an ERE. It must be unset if that's not actually\n-\t * the case.\n-\t */\n-\tif (pattern_type != GREP_PATTERN_TYPE_ERE &&\n-\t    opt->extended_regexp_option)\n-\t\topt->extended_regexp_option = 0;\n-\n-\tswitch (pattern_type) {\n-\tcase GREP_PATTERN_TYPE_UNSPECIFIED:\n-\t\t/* fall through */\n-\n-\tcase GREP_PATTERN_TYPE_BRE:\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_ERE:\n-\t\topt->extended_regexp_option = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_FIXED:\n-\t\topt->fixed = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_PCRE:\n-\t\topt->pcre2 = 1;\n-\t\tbreak;\n-\t}\n-}\n-\n-void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\tif (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(pattern_type, opt);\n-\telse if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(opt->pattern_type_option, opt);\n-\telse if (opt->extended_regexp_option)\n-\t\t/*\n-\t\t * This branch *must* happen after setting from the\n-\t\t * opt->pattern_type_option above, we don't want\n-\t\t * grep.extendedRegexp to override grep.patternType!\n-\t\t */\n-\t\tgrep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);\n-}\n-\n static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,\n \t\t\t\t\tconst char *origin, int no,\n \t\t\t\t\tenum grep_pat_token t,\n@@ -492,9 +438,10 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \n \tp->word_regexp = opt->word_regexp;\n \tp->ignore_case = opt->ignore_case;\n-\tp->fixed = opt->fixed;\n+\tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\n \n-\tif (memchr(p->pattern, 0, p->patternlen) && !opt->pcre2)\n+\tif (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE &&\n+\t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n \tp->is_fixed = is_fixed(p->pattern, p->patternlen);\n@@ -545,14 +492,14 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \t\treturn;\n \t}\n \n-\tif (opt->pcre2) {\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_PCRE) {\n \t\tcompile_pcre2_pattern(p, opt);\n \t\treturn;\n \t}\n \n \tif (p->ignore_case)\n \t\tregflags |= REG_ICASE;\n-\tif (opt->extended_regexp_option)\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_ERE)\n \t\tregflags |= REG_EXTENDED;\n \terr = regcomp(&p->regexp, p->pattern, regflags);\n \tif (err) {\ndiff --git a/grep.h b/grep.h\nindex 30a7dfd3294..e4e548aed90 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -143,7 +143,6 @@ struct grep_opt {\n \tint unmatch_name_only;\n \tint count;\n \tint word_regexp;\n-\tint fixed;\n \tint all_match;\n #define GREP_BINARY_DEFAULT\t0\n #define GREP_BINARY_NOMATCH\t1\n@@ -152,7 +151,6 @@ struct grep_opt {\n \tint allow_textconv;\n \tint extended;\n \tint use_reflog_filter;\n-\tint pcre2;\n \tint relative;\n \tint pathname;\n \tint null_following_name;\n@@ -161,8 +159,7 @@ struct grep_opt {\n \tint max_depth;\n \tint funcname;\n \tint funcbody;\n-\tint extended_regexp_option;\n-\tint pattern_type_option;\n+\tenum grep_pattern_type pattern_type_option;\n \tint ignore_locale;\n \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n \tunsigned pre_context;\n@@ -201,7 +198,6 @@ struct grep_opt {\n \n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n-void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\n void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex 9f9b0d2429e..ed29d245c89 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2864,8 +2864,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \n \tdiff_setup_done(&revs->diffopt);\n \n-\tgrep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t\t\t\t &revs->grep_filter);\n \tif (!is_encoding_utf8(get_log_output_encoding()))\n \t\trevs->grep_filter.ignore_locale = 1;\n \tcompile_grep_patterns(&revs->grep_filter);\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 6b6423a07c3..a59a9726357 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -443,7 +443,7 @@ do\n \t'\n \n \ttest_expect_success \"grep $L with grep.extendedRegexp=true and grep.patternType=default\" '\n-\t\techo \"${HC}ab:abc\" >expected &&\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n \t\tgit \\\n \t\t\t-c grep.extendedRegexp=true \\\n \t\t\t-c grep.patternType=default \\\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440614","messageId":"patch-8.8-dadd5dff77a-20211106T210711Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-0.8-00000000000-20211106T210711Z-avarab@gmail.com","subject":"[PATCH 8/8] grep: make \"extendedRegexp=true\" the same as \"patternType=extended\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-06T21:10:54Z","receivedAt":"2021-11-06T21:11:15Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"In the preceding commit we changed how a \"grep.patternType=default\"\nset after \"grep.extendedRegexp=true\" would be handled so that the last\nset would win, but a \"grep.extendedRegexp=true\" would only be used if\n\"grep.patternType\" was set to a value other than \"default\".\n\nThus a user who had old config and set \"grep.extendedRegexp=true\" in\ntheir ~/.gitconfig expecting ERE behavior would be opted-in to say\n\"perl\" regexes if a system \"/etc/gitconfig\" started setting\n\"grep.patternType=perl\".\n\nThese funny semantics of only paying attention to a set if another key\nis not set to a given value aren't how we treat other config keys, so\nlet's do away with this caveat for consistency.\n\nThe new semantics are simple, a \"grep.extendedRegexp=true\" is an exact\nsynonym for specifying \"grep.patternType=extended\" in the\nconfig. We'll keep ignoring \"\"grep.extendedRegexp=false\", although\narguably we could treat it as a \"grep.patternType=basic\".\n\nAs argued in the preceding commit I think this behavior came about\nbecause we were conflating the state of our code's own internal\n\"default\" value with what we found in explicit user config. See\n84befcd0a4a (grep: add a grep.patternType configuration setting,\n2012-08-03) for that past behavior.\n\nLet's further change the documentation to note that\n\"grep.extendedRegexp\" is a deprecated synonym, perhaps we'll be able\nto remove it at some point in the future and do away with this\nspecial-case entirely.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config/grep.txt | 3 +--\n Documentation/git-grep.txt    | 3 +--\n grep.c                        | 8 +++-----\n grep.h                        | 5 +----\n t/t7810-grep.sh               | 2 +-\n 5 files changed, 7 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/config/grep.txt b/Documentation/config/grep.txt\nindex 2669b1757d3..9868ea8a061 100644\n--- a/Documentation/config/grep.txt\n+++ b/Documentation/config/grep.txt\n@@ -11,8 +11,7 @@ grep.patternType::\n \tvalue 'default' will return to the default matching behavior.\n \n grep.extendedRegexp::\n-\tIf set to true, enable `--extended-regexp` option by default. This\n-\toption is ignored when the `grep.patternType` option is set.\n+\tDeprecated synonym for 'grep.patternType=extended`.\n \n grep.threads::\n \tNumber of grep worker threads to use.\ndiff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt\nindex 078dfeadf50..211ba6801b0 100644\n--- a/Documentation/git-grep.txt\n+++ b/Documentation/git-grep.txt\n@@ -347,8 +347,7 @@ grep.patternType::\n \tvalue 'default' will return to the default matching behavior.\n \n grep.extendedRegexp::\n-\tIf set to true, enable `--extended-regexp` option by default. This\n-\toption is ignored when the `grep.patternType` option is set.\n+\tDeprecated synonym for 'grep.patternType=extended`.\n \n grep.threads::\n \tNumber of grep worker threads to use. If unset (or set to 0), Git will\ndiff --git a/grep.c b/grep.c\nindex dda8e536fe3..ef8746d85f0 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -33,9 +33,8 @@ static const char *color_grep_slots[] = {\n \n static int parse_pattern_type_arg(const char *opt, const char *arg)\n {\n-\tif (!strcmp(arg, \"default\"))\n-\t\treturn GREP_PATTERN_TYPE_UNSPECIFIED;\n-\telse if (!strcmp(arg, \"basic\"))\n+\tif (!strcmp(arg, \"basic\") ||\n+\t    !strcmp(arg, \"default\"))\n \t\treturn GREP_PATTERN_TYPE_BRE;\n \telse if (!strcmp(arg, \"extended\"))\n \t\treturn GREP_PATTERN_TYPE_ERE;\n@@ -60,8 +59,7 @@ int grep_config(const char *var, const char *value, void *cb)\n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_UNSPECIFIED &&\n-\t    !strcmp(var, \"grep.extendedregexp\") &&\n+\tif (!strcmp(var, \"grep.extendedregexp\") &&\n \t    git_config_bool(var, value)) {\n \t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n \t\treturn 0;\ndiff --git a/grep.h b/grep.h\nindex e4e548aed90..55b23d045e0 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -94,8 +94,7 @@ enum grep_expr_node {\n };\n \n enum grep_pattern_type {\n-\tGREP_PATTERN_TYPE_UNSPECIFIED = 0,\n-\tGREP_PATTERN_TYPE_BRE,\n+\tGREP_PATTERN_TYPE_BRE = 0,\n \tGREP_PATTERN_TYPE_ERE,\n \tGREP_PATTERN_TYPE_FIXED,\n \tGREP_PATTERN_TYPE_PCRE\n@@ -179,7 +178,6 @@ struct grep_opt {\n \t.relative = 1, \\\n \t.pathname = 1, \\\n \t.max_depth = -1, \\\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n \t.colors = { \\\n \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n \t\t[GREP_COLOR_FILENAME] = \"\", \\\n@@ -191,7 +189,6 @@ struct grep_opt {\n \t\t[GREP_COLOR_SELECTED] = \"\", \\\n \t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n \t}, \\\n-\t.only_matching = 0, \\\n \t.color = -1, \\\n \t.output = std_output, \\\n }\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex a59a9726357..afca938a4d0 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -461,7 +461,7 @@ do\n \t'\n \n \ttest_expect_success \"grep $L with grep.patternType=basic and grep.extendedRegexp=true\" '\n-\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\techo \"${HC}ab:abc\" >expected &&\n \t\tgit \\\n \t\t\t-c grep.patternType=basic \\\n \t\t\t-c grep.extendedRegexp=true \\\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440687","messageId":"YYmKcOHInPWtKrWh@nand.local","threadId":"56853","inReplyTo":"patch-2.8-244715e3497-20211106T210711Z-avarab@gmail.com","subject":"Re: [PATCH 2/8] git.c & grep.c: assert that \"prefix\" is NULL or non-zero string","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-11-08T20:37:04Z","receivedAt":"2021-11-08T20:37:08Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Sat, Nov 06, 2021 at 10:10:48PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> @@ -431,6 +430,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n>  \t\t\tint nongit_ok;\n>  \t\t\tprefix = setup_git_directory_gently(&nongit_ok);\n>  \t\t}\n> +\t\tassert(!prefix || (prefix && *prefix));\n\nSmall nit, but the check to `prefix` (in `prefix && *prefix`) is\nredundant with the left-hand side of the or.\n\n>  \t\tprecompose_argv_prefix(argc, argv, NULL);\n>  \t\tif (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY) &&\n>  \t\t    !(p->option & DELAY_PAGER_CONFIG))\n> diff --git a/grep.c b/grep.c\n> index f6e113e9f0f..88ebc504630 100644\n> --- a/grep.c\n> +++ b/grep.c\n> @@ -145,7 +145,7 @@ void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix\n>\n>  \topt->repo = repo;\n>  \topt->prefix = prefix;\n> -\topt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;\n> +\topt->prefix_length = prefix ? strlen(prefix) : 0;\n\nLooking around, ls-tree's initialization includes a conditional of the\nform:\n\n    if (prefix && *prefix)\n      chomp_prefix = strlen(prefix);\n\nSo that could be cleaned up too. But honestly, the pre-image of this\npatch (and the spot in ls-tree) doesn't make a lot of sense to me to\nbegin with.\n\nEven if prefix were the empty string, calling strlen() on it will just\ngive us zero. So there is no difference between assigning `str && *str ?\nstrlen(str) : 0` and `str ? strlen(str) : 0`.\n\nSo I am confused why this needs hardening with an assertion when it\nseems like the checks before calling strlen() were overly restrictive to\nbegin with. In other words: why not only include this hunk (either in\nthis patch, or squashed into another patch later on)?\n\nThanks,\nTaylor\n"},{"id":"440688","messageId":"YYmLoTGTKO3VbSXu@nand.local","threadId":"56853","inReplyTo":"patch-3.8-3338cc95b81-20211106T210711Z-avarab@gmail.com","subject":"Re: [PATCH 3/8] grep: remove unused \"prefix_length\" member","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-11-08T20:42:09Z","receivedAt":"2021-11-08T20:42:13Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Sat, Nov 06, 2021 at 10:10:49PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> Remove the \"prefix_length\" member, which we compute with a strlen() on\n> the \"prefix\" argument to grep_init(), but whose strlen() hasn't been\n> used since 493b7a08d80 (grep: accept relative paths outside current\n> working directory, 2009-09-05).\n\nOK, so now we *are* relying on the assumption that prefix is either NULL\nor a non-empty string.\n\nI assume that the last patch was along the lines of \"let's clean up this\nredundant check before calling strlen()\" and \"prepare to not call\nstrlen() at all and just check the string itself for NULL\". To be\nhonest, I imagine that it would have been much easier to review if these\ntwo had been squashed into one, since I was a little surprised to see\nthe line I had just been commenting on in the previous patch removed.\n\nPerhaps I should have looked a little further in the series before\ncommenting there, but I think it would have been even easier for\nreviewers to see these two patches together.\n\n> When this code was added in 0d042fecf2f (git-grep: show pathnames\n> relative to the current directory, 2006-08-11) we used the length, but\n> since 493b7a08d80 we haven't used it for anything except a boolean\n> check that we could have done on the \"prefix\" member itself.\n>\n> Before a preceding commit we also used to guard the strlen() with\n> \"prefix && *prefix\", but as that commit notes the RHS of that && chain\n> was also redundant.\n\nEverything in this patch looks fine to me, assuming that prefix is\nindeed always NULL or non-empty (which I haven't verified myself).\n\nThanks,\nTaylor\n"},{"id":"440689","messageId":"YYmO9xlgFGhQlFZg@nand.local","threadId":"56853","inReplyTo":"patch-4.8-78298657d69-20211106T210711Z-avarab@gmail.com","subject":"Re: [PATCH 4/8] grep.c: move \"prefix\" out of \"struct grep_opt\"","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-11-08T20:56:23Z","receivedAt":"2021-11-08T20:56:29Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Sat, Nov 06, 2021 at 10:10:50PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> The \"struct grep_opt\" is a mixture of things that would be needed by\n> all callers of the grep.c API, and quite a few things that only the\n> builtin/grep.c needs.\n>\n> Since we got rid of \"prefix_length\" in the previous commit, let's move\n> the \"prefix\" variable over to \"builtin/grep.c\" where it's used. To do\n> this let's create a \"struct grep_cmd_opt\", which we'll have a pointer\n> to in a new \"caller_priv\" member in \"struct grep_opt\" (the existing\n> \"priv\" is used by the top-level \"grep.c\" itself).\n\nI'm definitely in favor of removing specialized, caller-specific bits\nfrom an internal API. But I'm not sure why grep.c needs to keep track o\nthis new \"caller_priv\" field at all.\n\nAmong the uses of `prefix` in builtin/grep.c, I see grep_source_name,\nand the call to run_pager(). Would it be more straightforward to pass\ndown prefix from cmd_grep down to its use in grep_source_name?\n\nThere are quite a few intermediary functions that we go through to get\nfrom cmd_grep() down to grep_source_name(). For instance, we could reach\nit through:\n\n    cmd_grep -> grep_tree -> grep_submodule -> grep_cache -> grep_oid ->\n    grep_source_name\n\nBut passing prefix from cmd_grep down to grep_source_name without\nrelying on the internals of grep.c seems like a good direction to me. I\ncould even buy that (ab)using a static variable in builtin/grep.c to\nkeep track of a constant prefix value would save you some plumbing\n(though I'd rather see the usage spelled out more explicitly).\n\nAll of that is to say that I share your motivation for this patch and\nthink that the direction is good, but I would have preferred to do it\nwithout the caller_priv variable (unless there is something that I am\nmissing here).\n\nThanks,\nTaylor\n"},{"id":"440691","messageId":"YYmbTOR+uk7prM8A@nand.local","threadId":"56853","inReplyTo":"patch-6.8-933ac853bca-20211106T210711Z-avarab@gmail.com","subject":"Re: [PATCH 6/8] grep API: call grep_config() after grep_init()","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-11-08T21:49:00Z","receivedAt":"2021-11-08T21:49:07Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Sat, Nov 06, 2021 at 10:10:52PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> The grep_init() function used the odd pattern of initializing the\n> passed-in \"struct grep_opt\" with a statically defined \"grep_defaults\"\n> struct, which would be modified in-place when we invoked\n> grep_config().\n>\n> So we effectively (b) initialized config, (a) then defaults, (c)\n> followed by user options. Usually those are ordered as \"a\", \"b\" and\n> \"c\" instead.\n\nDo we risk changing any user-visible behavior here? Based on my reading\nof grep.c before and after this patch, I think the answer is \"no\", but I\nwasn't sure if you had done a similar analysis.\n\nIn any case, I think the \"bring your own structure\" instead of getting\none copied around is much easier to reason about. Even if we weren't\naccidentally stomping on ownership of the struct before, not having to\nreason about it is a nice benefit.\n\n> As the comments being removed here show the previous behavior needed\n> to be carefully explained as we'd potentially share the populated\n> configuration among different instances of grep_init(). In practice we\n> didn't do that, but now that it can't be a concern anymore let's\n> remove those comments.\n\nMakes sense, I agree.\n\n> diff --git a/builtin/grep.c b/builtin/grep.c\n> index 960c7aac123..7f95f44e948 100644\n> --- a/builtin/grep.c\n> +++ b/builtin/grep.c\n> @@ -288,7 +288,7 @@ static int wait_all(void)\n>  static int grep_cmd_config(const char *var, const char *value, void *cb)\n>  {\n>  \tint st = grep_config(var, value, cb);\n> -\tif (git_color_default_config(var, value, cb) < 0)\n> +\tif (git_color_default_config(var, value, NULL) < 0)\n\nThis doesn't appear strictly related to the rest of your changes, but\nonly serves to prevent the caller-provided data from being sent down to\ngit_color_default_config().\n\nIt didn't matter before because (a) the caller doesn't specify any data\nto begin with, and git_color_default_config() (or the functions that it\ncalls) don't do anything with the extra pointer. Now cmd_grep() is going\nto start passing around a pointer to a struct grep_opt.\n\nBut git_color_default_config() still doesn't do anything with the\npointer it receives, and passing that pointer around is standard\npractice among config.c code. So I don't think that this hunk is\nstrictly necessary, and it's somewhat different than the pattern\nestablished within config.c.\n\nI wouldn't be sad to see this hunk dropped (and in fact have a slight\npreference leaning this way), but I don't mind keeping it around,\neither.\n\n>  \t\tst = -1;\n>\n>  \tif (!strcmp(var, \"grep.threads\")) {\n> @@ -969,8 +969,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n>  \t\tOPT_END()\n>  \t};\n>\n> -\tgit_config(grep_cmd_config, NULL);\n>  \tgrep_init(&opt, the_repository);\n> +\tgit_config(grep_cmd_config, &opt);\n>  \topt.caller_priv = &opt_cmd;\n>\n>  \t/*\n> diff --git a/builtin/log.c b/builtin/log.c\n> index f75d87e8d7f..bfddacdfa6c 100644\n> --- a/builtin/log.c\n> +++ b/builtin/log.c\n> @@ -505,8 +505,6 @@ static int git_log_config(const char *var, const char *value, void *cb)\n>  \t\treturn 0;\n>  \t}\n>\n> -\tif (grep_config(var, value, cb) < 0)\n> -\t\treturn -1;\n>  \tif (git_gpg_config(var, value, cb) < 0)\n>  \t\treturn -1;\n>  \treturn git_diff_ui_config(var, value, cb);\n> @@ -521,6 +519,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n>  \tgit_config(git_log_config, NULL);\n>\n>  \trepo_init_revisions(the_repository, &rev, prefix);\n> +\tgit_config(grep_config, &rev.grep_filter);\n> +\n>  \trev.diff = 1;\n>  \trev.simplify_history = 0;\n>  \tmemset(&opt, 0, sizeof(opt));\n> @@ -635,6 +635,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n>\n>  \tmemset(&match_all, 0, sizeof(match_all));\n>  \trepo_init_revisions(the_repository, &rev, prefix);\n> +\tgit_config(grep_config, &rev.grep_filter);\n> +\n>  \trev.diff = 1;\n>  \trev.always_show_header = 1;\n>  \trev.no_walk = 1;\n> @@ -718,6 +720,8 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)\n>\n>  \trepo_init_revisions(the_repository, &rev, prefix);\n>  \tinit_reflog_walk(&rev.reflog_info);\n> +\tgit_config(grep_config, &rev.grep_filter);\n> +\n>  \trev.verbose_header = 1;\n>  \tmemset(&opt, 0, sizeof(opt));\n>  \topt.def = \"HEAD\";\n> @@ -751,6 +755,8 @@ int cmd_log(int argc, const char **argv, const char *prefix)\n>  \tgit_config(git_log_config, NULL);\n>\n>  \trepo_init_revisions(the_repository, &rev, prefix);\n> +\tgit_config(grep_config, &rev.grep_filter);\n> +\n>  \trev.always_show_header = 1;\n>  \tmemset(&opt, 0, sizeof(opt));\n>  \topt.def = \"HEAD\";\n> @@ -1833,10 +1839,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n>  \textra_hdr.strdup_strings = 1;\n>  \textra_to.strdup_strings = 1;\n>  \textra_cc.strdup_strings = 1;\n> +\n>  \tinit_log_defaults();\n>  \tinit_display_notes(&notes_opt);\n>  \tgit_config(git_format_config, NULL);\n>  \trepo_init_revisions(the_repository, &rev, prefix);\n> +\tgit_config(grep_config, &rev.grep_filter);\n> +\n>  \trev.show_notes = show_notes;\n>  \tmemcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));\n>  \trev.commit_format = CMIT_FMT_EMAIL;\n> diff --git a/grep.c b/grep.c\n> index c9065254aeb..fb3f63c63ef 100644\n> --- a/grep.c\n> +++ b/grep.c\n> @@ -19,27 +19,6 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)\n>  \tfwrite(buf, size, 1, stdout);\n>  }\n>\n> -static struct grep_opt grep_defaults = {\n> -\t.relative = 1,\n> -\t.pathname = 1,\n> -\t.max_depth = -1,\n> -\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED,\n> -\t.colors = {\n> -\t\t[GREP_COLOR_CONTEXT] = \"\",\n> -\t\t[GREP_COLOR_FILENAME] = \"\",\n> -\t\t[GREP_COLOR_FUNCTION] = \"\",\n> -\t\t[GREP_COLOR_LINENO] = \"\",\n> -\t\t[GREP_COLOR_COLUMNNO] = \"\",\n> -\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED,\n> -\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED,\n> -\t\t[GREP_COLOR_SELECTED] = \"\",\n> -\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN,\n> -\t},\n> -\t.only_matching = 0,\n> -\t.color = -1,\n> -\t.output = std_output,\n> -};\n> -\n>  static const char *color_grep_slots[] = {\n>  \t[GREP_COLOR_CONTEXT]\t    = \"context\",\n>  \t[GREP_COLOR_FILENAME]\t    = \"filename\",\n> @@ -75,20 +54,12 @@ define_list_config_array_extra(color_grep_slots, {\"match\"});\n>   */\n>  int grep_config(const char *var, const char *value, void *cb)\n>  {\n> -\tstruct grep_opt *opt = &grep_defaults;\n> +\tstruct grep_opt *opt = cb;\n>  \tconst char *slot;\n>\n>  \tif (userdiff_config(var, value) < 0)\n>  \t\treturn -1;\n>\n> -\t/*\n> -\t * The instance of grep_opt that we set up here is copied by\n> -\t * grep_init() to be used by each individual invocation.\n> -\t * When populating a new field of this structure here, be\n> -\t * sure to think about ownership -- e.g., you might need to\n> -\t * override the shallow copy in grep_init() with a deep copy.\n> -\t */\n> -\n>  \tif (!strcmp(var, \"grep.extendedregexp\")) {\n>  \t\topt->extended_regexp_option = git_config_bool(var, value);\n>  \t\treturn 0;\n> @@ -134,14 +105,10 @@ int grep_config(const char *var, const char *value, void *cb)\n>  \treturn 0;\n>  }\n>\n> -/*\n> - * Initialize one instance of grep_opt and copy the\n> - * default values from the template we read the configuration\n> - * information in an earlier call to git_config(grep_config).\n> - */\n>  void grep_init(struct grep_opt *opt, struct repository *repo)\n>  {\n> -\t*opt = grep_defaults;\n> +\tstruct grep_opt blank = GREP_OPT_INIT;\n> +\tmemcpy(opt, &blank, sizeof(*opt));\n\nI'm nit-picking, but creating a throwaway struct for the convenience of\nusing designated initialization (at the cost of having to memcpy an\nentire struct around) seems like overkill.\n\nEspecially since we're just going to write into the other fields of the\nthe target struct anyway, I'd probably rather have seen everything\nwritten out explicitly without the throwaway or memcpy.\n\nThanks,\nTaylor\n"},{"id":"440698","messageId":"YYms4czKVnQFWYQ+@nand.local","threadId":"56853","inReplyTo":"patch-7.8-677a8f8520f-20211106T210711Z-avarab@gmail.com","subject":"Re: [PATCH 7/8] grep: simplify config parsing, change grep.<rx config> interaction","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-11-08T23:04:01Z","receivedAt":"2021-11-08T23:04:05Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Sat, Nov 06, 2021 at 10:10:53PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> I.e. a user would correctly expect this to keep working:\n>\n>     # ERE grep\n>     git -c grep.extendedRegexp=true grep <pattern>\n>\n> And likewise for \"grep.patternType=default\" to take precedence over\n> the disfavored \"grep.extendedRegexp\" option, i.e. the usual \"last set\n> wins\" semantics.\n>\n>     # BRE grep\n>     git -c grep.extendedRegexp=true -c grep.patternType=basic grep <pattern>\n>\n> But probably not for this to ignore the new \"grep.patternType\" option\n> entirely, say if /etc/gitconfig was still setting\n> \"grep.extendedRegexp\", but \"~/.gitconfig\" used the new\n> \"grep.patternType\" (and wanted to use the \"default\" value):\n>\n>     # Was ERE, now BRE\n>     git -c grep.extendedRegexp=true grep.patternType=default grep <pattern>\n\nOK, so this is the case that we'd be \"breaking\". And I think that the\nnew behavior you're outlining here (where a higher-precedence\ngrep.patternType=default overrides a lower-precedence\ngrep.extendedRegexp=true, resulting in using BRE over ERE) makes more\nsense.\n\nAt least, it makes more sense if your expectation of \"default\" is \"the\ndefault matching behavior\", not \"fallthrough to grep.extendedRegexp\".\n\nIn any case, I am sensitive to breaking existing user workflows, but\nthis seems so obscure to me that I have a hard time expecting that\nm(any?) users will even notice this at all.\n\nThe situation I'm most concerned about is having grep.extendedRegexp set\nin, say, /etc/gitconfig and grep.patternType=default set at a\nhigher-precedence level.\n\n> ---\n>  Documentation/config/grep.txt |  3 +-\n>  Documentation/git-grep.txt    |  3 +-\n\nNot the fault of your patch, but these two are annoyingly (and subtly)\ndifferent from one another. Could we clean this up and put everything in\nDocumentation/config/grep.txt (and then include that in the\nCONFIGURATION section of Documentation/git-grep.txt)?\n\n>  builtin/grep.c                | 10 ++---\n>  grep.c                        | 71 +++++------------------------------\n>  grep.h                        |  6 +--\n>  revision.c                    |  2 -\n>  t/t7810-grep.sh               |  2 +-\n>  7 files changed, 17 insertions(+), 80 deletions(-)\n>\n> diff --git a/Documentation/config/grep.txt b/Documentation/config/grep.txt\n> index 44abe45a7ca..2669b1757d3 100644\n> --- a/Documentation/config/grep.txt\n> +++ b/Documentation/config/grep.txt\n> @@ -12,8 +12,7 @@ grep.patternType::\n>\n>  grep.extendedRegexp::\n>  \tIf set to true, enable `--extended-regexp` option by default. This\n> -\toption is ignored when the `grep.patternType` option is set to a value\n> -\tother than 'default'.\n> +\toption is ignored when the `grep.patternType` option is set.\n>\n>  grep.threads::\n>  \tNumber of grep worker threads to use.\n> diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt\n> index 3d393fbac1b..078dfeadf50 100644\n> --- a/Documentation/git-grep.txt\n> +++ b/Documentation/git-grep.txt\n> @@ -348,8 +348,7 @@ grep.patternType::\n>\n>  grep.extendedRegexp::\n>  \tIf set to true, enable `--extended-regexp` option by default. This\n> -\toption is ignored when the `grep.patternType` option is set to a value\n> -\tother than 'default'.\n> +\toption is ignored when the `grep.patternType` option is set.\n\nMakes sense, and matches your description.\n\n> diff --git a/grep.c b/grep.c\n> index fb3f63c63ef..dda8e536fe3 100644\n> --- a/grep.c\n> +++ b/grep.c\n> @@ -60,8 +60,10 @@ int grep_config(const char *var, const char *value, void *cb)\n>  \tif (userdiff_config(var, value) < 0)\n>  \t\treturn -1;\n>\n> -\tif (!strcmp(var, \"grep.extendedregexp\")) {\n> -\t\topt->extended_regexp_option = git_config_bool(var, value);\n> +\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_UNSPECIFIED &&\n> +\t    !strcmp(var, \"grep.extendedregexp\") &&\n> +\t    git_config_bool(var, value)) {\n> +\t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n>  \t\treturn 0;\n>  \t}\n\nAnd here's our \"as long as we haven't set the pattern type already via\ngrep.patternType, allow grep.extendedRegexp to set it\". But the same\n\"only set when unspecified\" condition *isn't* in place for\ngrep.patternType, which is what makes us prefer values from that\nconfiguration over the other. Makes sense.\n\nEverything else looks good here, too.\n\nThanks,\nTaylor\n"},{"id":"440718","messageId":"211109.86ee7qdqz0.gmgdl@evledraar.gmail.com","threadId":"56853","inReplyTo":"YYms4czKVnQFWYQ+@nand.local","subject":"Re: [PATCH 7/8] grep: simplify config parsing, change grep.<rx config> interaction","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-09T02:01:12Z","receivedAt":"2021-11-09T02:04:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Nov 08 2021, Taylor Blau wrote:\n\n> On Sat, Nov 06, 2021 at 10:10:53PM +0100, Ævar Arnfjörð Bjarmason wrote:\n>> I.e. a user would correctly expect this to keep working:\n>>\n>>     # ERE grep\n>>     git -c grep.extendedRegexp=true grep <pattern>\n>>\n>> And likewise for \"grep.patternType=default\" to take precedence over\n>> the disfavored \"grep.extendedRegexp\" option, i.e. the usual \"last set\n>> wins\" semantics.\n>>\n>>     # BRE grep\n>>     git -c grep.extendedRegexp=true -c grep.patternType=basic grep <pattern>\n>>\n>> But probably not for this to ignore the new \"grep.patternType\" option\n>> entirely, say if /etc/gitconfig was still setting\n>> \"grep.extendedRegexp\", but \"~/.gitconfig\" used the new\n>> \"grep.patternType\" (and wanted to use the \"default\" value):\n>>\n>>     # Was ERE, now BRE\n>>     git -c grep.extendedRegexp=true grep.patternType=default grep <pattern>\n>\n> OK, so this is the case that we'd be \"breaking\". And I think that the\n> new behavior you're outlining here (where a higher-precedence\n> grep.patternType=default overrides a lower-precedence\n> grep.extendedRegexp=true, resulting in using BRE over ERE) makes more\n> sense.\n>\n> At least, it makes more sense if your expectation of \"default\" is \"the\n> default matching behavior\", not \"fallthrough to grep.extendedRegexp\".\n>\n> In any case, I am sensitive to breaking existing user workflows, but\n> this seems so obscure to me that I have a hard time expecting that\n> m(any?) users will even notice this at all.\n>\n> The situation I'm most concerned about is having grep.extendedRegexp set\n> in, say, /etc/gitconfig and grep.patternType=default set at a\n> higher-precedence level.\n\n*nod*, but the only user who'd end up with that is someone who's trying\nto override grep.extendedRegexp but failing to do it, so this would\nhelp.\n\nOr someone who'd read the docs, understood that we promised that would\ndo nothing, and inserted that just to test us, but that seems unlikely\n:)\n\nOr, I suppose someone who's entirely confused, and will continue being\neven more confused now that behavior changes on a git upgrade from ERE\nto BRE.\n\nI'm hoping the last two paragraphs describe no-one & that this is safe\nto do.\n\n>> ---\n>>  Documentation/config/grep.txt |  3 +-\n>>  Documentation/git-grep.txt    |  3 +-\n>\n> Not the fault of your patch, but these two are annoyingly (and subtly)\n> different from one another. Could we clean this up and put everything in\n> Documentation/config/grep.txt (and then include that in the\n> CONFIGURATION section of Documentation/git-grep.txt)?\n\nI've got a large series to do that for all of these, but opted to skip\nthat particular digression here (even for just grep.txt it's a bit\ndistracting).\n"},{"id":"440720","messageId":"211109.86a6iedqpf.gmgdl@evledraar.gmail.com","threadId":"56853","inReplyTo":"YYmbTOR+uk7prM8A@nand.local","subject":"Re: [PATCH 6/8] grep API: call grep_config() after grep_init()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-09T02:06:22Z","receivedAt":"2021-11-09T02:10:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Nov 08 2021, Taylor Blau wrote:\n\n> On Sat, Nov 06, 2021 at 10:10:52PM +0100, Ævar Arnfjörð Bjarmason wrote:\n>> The grep_init() function used the odd pattern of initializing the\n>> passed-in \"struct grep_opt\" with a statically defined \"grep_defaults\"\n>> struct, which would be modified in-place when we invoked\n>> grep_config().\n>>\n>> So we effectively (b) initialized config, (a) then defaults, (c)\n>> followed by user options. Usually those are ordered as \"a\", \"b\" and\n>> \"c\" instead.\n>\n> Do we risk changing any user-visible behavior here? Based on my reading\n> of grep.c before and after this patch, I think the answer is \"no\", but I\n> wasn't sure if you had done a similar analysis.\n>\n> In any case, I think the \"bring your own structure\" instead of getting\n> one copied around is much easier to reason about. Even if we weren't\n> accidentally stomping on ownership of the struct before, not having to\n> reason about it is a nice benefit.\n\nI don't think we're changing any behavior except the one noted in this\nseries.\n\nWe only set a few config variables, so I thought that was fairly easy to\ntrace...\n\n> [...]\n>> diff --git a/builtin/grep.c b/builtin/grep.c\n>> index 960c7aac123..7f95f44e948 100644\n>> --- a/builtin/grep.c\n>> +++ b/builtin/grep.c\n>> @@ -288,7 +288,7 @@ static int wait_all(void)\n>>  static int grep_cmd_config(const char *var, const char *value, void *cb)\n>>  {\n>>  \tint st = grep_config(var, value, cb);\n>> -\tif (git_color_default_config(var, value, cb) < 0)\n>> +\tif (git_color_default_config(var, value, NULL) < 0)\n>\n> This doesn't appear strictly related to the rest of your changes, but\n> only serves to prevent the caller-provided data from being sent down to\n> git_color_default_config().\n>\n> It didn't matter before because (a) the caller doesn't specify any data\n> to begin with, and git_color_default_config() (or the functions that it\n> calls) don't do anything with the extra pointer. Now cmd_grep() is going\n> to start passing around a pointer to a struct grep_opt.\n>\n> But git_color_default_config() still doesn't do anything with the\n> pointer it receives, and passing that pointer around is standard\n> practice among config.c code. So I don't think that this hunk is\n> strictly necessary, and it's somewhat different than the pattern\n> established within config.c.\n>\n> I wouldn't be sad to see this hunk dropped (and in fact have a slight\n> preference leaning this way), but I don't mind keeping it around,\n> either.\n\nWill either split it up or drop it.\n\n> [...]\n>> -/*\n>> - * Initialize one instance of grep_opt and copy the\n>> - * default values from the template we read the configuration\n>> - * information in an earlier call to git_config(grep_config).\n>> - */\n>>  void grep_init(struct grep_opt *opt, struct repository *repo)\n>>  {\n>> -\t*opt = grep_defaults;\n>> +\tstruct grep_opt blank = GREP_OPT_INIT;\n>> +\tmemcpy(opt, &blank, sizeof(*opt));\n>\n> I'm nit-picking, but creating a throwaway struct for the convenience of\n> using designated initialization (at the cost of having to memcpy an\n> entire struct around) seems like overkill.\n>\n> Especially since we're just going to write into the other fields of the\n> the target struct anyway, I'd probably rather have seen everything\n> written out explicitly without the throwaway or memcpy.\n\nIt's a widely used pattern in the codebase at this point, see\n5726a6b4012 (*.c *_init(): define in terms of corresponding *_INIT\nmacro, 2021-07-01) (mine, but I stole it from Jeff King).\n\nAs his linked-to compiler test shows the memcpy() is optimized away, so\nmodern compilers will treat these idioms the same way.\n\nThere was a suggestions somewhere that we should prorably move to that\n\"*<x> = <y>\" or whatever it was briefer C99 (I think) syntax across the\nboard, it would be less verbose. But I haven't tested if it's as widely\nsupported, so I've just been sticking with that blank/memcpy() pattern\nfor \"do init in terms of macro\".\n"},{"id":"440721","messageId":"211109.865yt2dqmf.gmgdl@evledraar.gmail.com","threadId":"56853","inReplyTo":"YYmO9xlgFGhQlFZg@nand.local","subject":"Re: [PATCH 4/8] grep.c: move \"prefix\" out of \"struct grep_opt\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-09T02:10:31Z","receivedAt":"2021-11-09T02:12:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Nov 08 2021, Taylor Blau wrote:\n\n> On Sat, Nov 06, 2021 at 10:10:50PM +0100, Ævar Arnfjörð Bjarmason wrote:\n>> The \"struct grep_opt\" is a mixture of things that would be needed by\n>> all callers of the grep.c API, and quite a few things that only the\n>> builtin/grep.c needs.\n>>\n>> Since we got rid of \"prefix_length\" in the previous commit, let's move\n>> the \"prefix\" variable over to \"builtin/grep.c\" where it's used. To do\n>> this let's create a \"struct grep_cmd_opt\", which we'll have a pointer\n>> to in a new \"caller_priv\" member in \"struct grep_opt\" (the existing\n>> \"priv\" is used by the top-level \"grep.c\" itself).\n>\n> I'm definitely in favor of removing specialized, caller-specific bits\n> from an internal API. But I'm not sure why grep.c needs to keep track o\n> this new \"caller_priv\" field at all.\n>\n> Among the uses of `prefix` in builtin/grep.c, I see grep_source_name,\n> and the call to run_pager(). Would it be more straightforward to pass\n> down prefix from cmd_grep down to its use in grep_source_name?\n>\n> There are quite a few intermediary functions that we go through to get\n> from cmd_grep() down to grep_source_name(). For instance, we could reach\n> it through:\n>\n>     cmd_grep -> grep_tree -> grep_submodule -> grep_cache -> grep_oid ->\n>     grep_source_name\n>\n> But passing prefix from cmd_grep down to grep_source_name without\n> relying on the internals of grep.c seems like a good direction to me. I\n> could even buy that (ab)using a static variable in builtin/grep.c to\n> keep track of a constant prefix value would save you some plumbing\n> (though I'd rather see the usage spelled out more explicitly).\n>\n> All of that is to say that I share your motivation for this patch and\n> think that the direction is good, but I would have preferred to do it\n> without the caller_priv variable (unless there is something that I am\n> missing here).\n\nYes, that would make much more sense. I just had tunnel vision while\nwriting this, evidently. Yeah, just either passing it or using a static\nvariable in grep.c would make more sense.\n\nArguably we could even have it be read only (const char *const) and have\na global \"the_prefix\" or something, but it's probably not widely used\nenough for that to make sense.\n\n\n\n\n"},{"id":"440788","messageId":"YYsPRxe0hgJYlisq@nand.local","threadId":"56853","inReplyTo":"211109.86ee7qdqz0.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 7/8] grep: simplify config parsing, change grep.<rx config> interaction","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-11-10T00:16:07Z","receivedAt":"2021-11-10T00:16:11Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Tue, Nov 09, 2021 at 03:01:12AM +0100, Ævar Arnfjörð Bjarmason wrote:\n> Or someone who'd read the docs, understood that we promised that would\n> do nothing, and inserted that just to test us, but that seems unlikely\n> :)\n>\n> Or, I suppose someone who's entirely confused, and will continue being\n> even more confused now that behavior changes on a git upgrade from ERE\n> to BRE.\n>\n> I'm hoping the last two paragraphs describe no-one & that this is safe\n> to do.\n\nYeah, I agree that it seems very unlikely that anybody would actually be\naffected here, so I'm comfortable with the change.\n\n> >> ---\n> >>  Documentation/config/grep.txt |  3 +-\n> >>  Documentation/git-grep.txt    |  3 +-\n> >\n> > Not the fault of your patch, but these two are annoyingly (and subtly)\n> > different from one another. Could we clean this up and put everything in\n> > Documentation/config/grep.txt (and then include that in the\n> > CONFIGURATION section of Documentation/git-grep.txt)?\n>\n> I've got a large series to do that for all of these, but opted to skip\n> that particular digression here (even for just grep.txt it's a bit\n> distracting).\n\nI think that you could include a preparatory clean-up in this series to\nmake the Documentation/config/grep.txt included by\nDocumentation/git-grep.txt without being too distracting. But if punting\non it now works better for you, I don't think either makes a reviewer's\njob substantially different.\n\nThanks,\nTaylor\n"},{"id":"440789","messageId":"YYsPySOHR8h+CYbl@nand.local","threadId":"56853","inReplyTo":"211109.86a6iedqpf.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 6/8] grep API: call grep_config() after grep_init()","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-11-10T00:18:17Z","receivedAt":"2021-11-10T00:18:21Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Tue, Nov 09, 2021 at 03:06:22AM +0100, Ævar Arnfjörð Bjarmason wrote:\n> >> -/*\n> >> - * Initialize one instance of grep_opt and copy the\n> >> - * default values from the template we read the configuration\n> >> - * information in an earlier call to git_config(grep_config).\n> >> - */\n> >>  void grep_init(struct grep_opt *opt, struct repository *repo)\n> >>  {\n> >> -\t*opt = grep_defaults;\n> >> +\tstruct grep_opt blank = GREP_OPT_INIT;\n> >> +\tmemcpy(opt, &blank, sizeof(*opt));\n> >\n> > I'm nit-picking, but creating a throwaway struct for the convenience of\n> > using designated initialization (at the cost of having to memcpy an\n> > entire struct around) seems like overkill.\n> >\n> > Especially since we're just going to write into the other fields of the\n> > the target struct anyway, I'd probably rather have seen everything\n> > written out explicitly without the throwaway or memcpy.\n>\n> It's a widely used pattern in the codebase at this point, see\n> 5726a6b4012 (*.c *_init(): define in terms of corresponding *_INIT\n> macro, 2021-07-01) (mine, but I stole it from Jeff King).\n>\n> As his linked-to compiler test shows the memcpy() is optimized away, so\n> modern compilers will treat these idioms the same way.\n>\n> There was a suggestions somewhere that we should prorably move to that\n> \"*<x> = <y>\" or whatever it was briefer C99 (I think) syntax across the\n> board, it would be less verbose. But I haven't tested if it's as widely\n> supported, so I've just been sticking with that blank/memcpy() pattern\n> for \"do init in terms of macro\".\n\nI do at least prefer memcpy() over *<x> = <y> when x and y are\nstructures. But I wasn't aware that this was common in our codebase.\nAnyway, my suggestion was only along the lines of \"you're already\nwriting individual fields below, so why not just do that throughout\ninstead of memcpy()-ing some of them via a macro which expands to a\ndesignated initializer?\"\n\nBut this is a cosmetic point, so whatever you feel fits in most with the\nsurrounding style (so long as the pattern we're propagating isn't\nterrible, which is the case here) then I'm OK with it.\n\nThanks,\nTaylor\n"},{"id":"440790","messageId":"YYsP8WM14RvgE7w9@nand.local","threadId":"56853","inReplyTo":"211109.865yt2dqmf.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 4/8] grep.c: move \"prefix\" out of \"struct grep_opt\"","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-11-10T00:18:57Z","receivedAt":"2021-11-10T00:19:02Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Tue, Nov 09, 2021 at 03:10:31AM +0100, Ævar Arnfjörð Bjarmason wrote:\n> > All of that is to say that I share your motivation for this patch and\n> > think that the direction is good, but I would have preferred to do it\n> > without the caller_priv variable (unless there is something that I am\n> > missing here).\n>\n> Yes, that would make much more sense. I just had tunnel vision while\n> writing this, evidently. Yeah, just either passing it or using a static\n> variable in grep.c would make more sense.\n>\n> Arguably we could even have it be read only (const char *const) and have\n> a global \"the_prefix\" or something, but it's probably not widely used\n> enough for that to make sense.\n\nEither of the first two seem fine to me, but introducing `the_prefix`\nseems both over-specified, and too big a step for this series alone.\n\nThanks,\nTaylor\n"},{"id":"440795","messageId":"cover-v2-0.8-00000000000-20211110T013632Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-0.8-00000000000-20211106T210711Z-avarab@gmail.com","subject":"[PATCH v2 0/8] grep: simplify & delete code by changing obscure cfg variable behavior","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-10T01:43:42Z","receivedAt":"2021-11-10T01:43:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This series changes the behavior of an obscure interaction between\n\"grep.extendedRegexp=true\" and \"grep.patternType=default\". See\n7-8/8. Along the way we can delete a lot of code that was needed to\nsupport the previous behavior.\n\nFor v1 and a more extensive summary see [1]. Thanks a lot Taylor for\nthe detailed review on v1!\n\nHopefully this v1 addresses all the feedback on one way or another,\nit's still 8 patches, but much of the early part of v1 is squashed\ntogether & re-done as suggested.\n\nThen there's a mid-series de-duplication of the grep config\ndocumentation. I ended up keeping the change to not needlessly pass\n\"cb\" around in grep_cmd_config(), but that's now also in its own\npatch.\n\n1. https://lore.kernel.org/git/cover-0.8-00000000000-20211106T210711Z-avarab@gmail.com/\n\nÆvar Arnfjörð Bjarmason (8):\n  grep.h: remove unused \"regex_t regexp\" from grep_opt\n  built-ins: trust the \"prefix\" from run_builtin()\n  log tests: check if grep_config() is called by \"log\"-like cmds\n  grep docs: de-duplicate configuration sections\n  grep.c: don't pass along NULL callback value\n  grep API: call grep_config() after grep_init()\n  grep: simplify config parsing, change grep.<rx config> interaction\n  grep: make \"extendedRegexp=true\" the same as \"patternType=extended\"\n\n Documentation/config/grep.txt |  11 ++--\n Documentation/git-grep.txt    |  30 +--------\n builtin/grep.c                |  27 ++++----\n builtin/log.c                 |  13 +++-\n builtin/ls-tree.c             |   9 ++-\n git.c                         |   4 +-\n grep.c                        | 118 ++++------------------------------\n grep.h                        |  35 ++++++----\n revision.c                    |   4 +-\n t/t4202-log.sh                |  16 +++++\n t/t7810-grep.sh               |   4 +-\n 11 files changed, 97 insertions(+), 174 deletions(-)\n\nRange-diff against v1:\n1:  412b8b65266 = 1:  1435db727ef grep.h: remove unused \"regex_t regexp\" from grep_opt\n2:  244715e3497 < -:  ----------- git.c & grep.c: assert that \"prefix\" is NULL or non-zero string\n3:  3338cc95b81 < -:  ----------- grep: remove unused \"prefix_length\" member\n4:  78298657d69 < -:  ----------- grep.c: move \"prefix\" out of \"struct grep_opt\"\n-:  ----------- > 2:  63cf2fe266d built-ins: trust the \"prefix\" from run_builtin()\n5:  ba9be0b9283 = 3:  41e38ebb32c log tests: check if grep_config() is called by \"log\"-like cmds\n-:  ----------- > 4:  efe95397d72 grep docs: de-duplicate configuration sections\n-:  ----------- > 5:  d0f0ac6c7ae grep.c: don't pass along NULL callback value\n6:  933ac853bca ! 6:  917944f79a5 grep API: call grep_config() after grep_init()\n    @@ Commit message\n         didn't do that, but now that it can't be a concern anymore let's\n         remove those comments.\n     \n    +    This does not change the behavior of any of the configuration\n    +    variables or options. That would have been the case if we didn't move\n    +    around the grep_config() call in \"builtin/log.c\". But now that we call\n    +    \"grep_config\" after \"git_log_config\" and \"git_format_config\" we'll\n    +    need to pass in the already initialized \"struct grep_opt *\".\n    +\n         See 6ba9bb76e02 (grep: copy struct in one fell swoop, 2020-11-29) and\n         7687a0541e0 (grep: move the configuration parsing logic to grep.[ch],\n         2012-10-09) for the commits that added the comments.\n     \n    +    The memcpy() pattern here will be optimized away and follows the\n    +    convention of other *_init() functions. See 5726a6b4012 (*.c *_init():\n    +    define in terms of corresponding *_INIT macro, 2021-07-01).\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/grep.c ##\n     @@ builtin/grep.c: static int wait_all(void)\n    + \n      static int grep_cmd_config(const char *var, const char *value, void *cb)\n      {\n    - \tint st = grep_config(var, value, cb);\n    --\tif (git_color_default_config(var, value, cb) < 0)\n    -+\tif (git_color_default_config(var, value, NULL) < 0)\n    +-\tint st = grep_config(var, value, NULL);\n    ++\tint st = grep_config(var, value, cb);\n    + \tif (git_color_default_config(var, value, NULL) < 0)\n      \t\tst = -1;\n      \n    - \tif (!strcmp(var, \"grep.threads\")) {\n     @@ builtin/grep.c: int cmd_grep(int argc, const char **argv, const char *prefix)\n    - \t\tOPT_END()\n      \t};\n    + \tgrep_prefix = prefix;\n      \n     -\tgit_config(grep_cmd_config, NULL);\n      \tgrep_init(&opt, the_repository);\n     +\tgit_config(grep_cmd_config, &opt);\n    - \topt.caller_priv = &opt_cmd;\n      \n      \t/*\n    + \t * If there is no -- then the paths must exist in the working\n     \n      ## builtin/log.c ##\n     @@ builtin/log.c: static int git_log_config(const char *var, const char *value, void *cb)\n    @@ grep.c: int grep_config(const char *var, const char *value, void *cb)\n     \n      ## grep.h ##\n     @@ grep.h: struct grep_opt {\n    + \tint show_hunk_mark;\n    + \tint file_break;\n    + \tint heading;\n    ++\tvoid *caller_priv;\n    + \tvoid *priv;\n    + \n    + \tvoid (*output)(struct grep_opt *opt, const void *data, size_t size);\n      \tvoid *output_priv;\n      };\n      \n7:  677a8f8520f ! 7:  140a7416223 grep: simplify config parsing, change grep.<rx config> interaction\n    @@ Commit message\n         but in a way that's consistent with how we parse other\n         configuration.\n     \n    -    Pedantically speaking we're probably breaking past promises here, but\n    -    I doubt that this will impact anyone in practice. The reduction in\n    -    complexity and resulting consistency with other default config\n    -    behavior is worth it.\n    +    We are breaking past promises here, but I doubt that this will impact\n    +    anyone in practice. The reduction in complexity and resulting\n    +    consistency with other default config behavior is worth it.\n     \n         When \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\n         grep.patternType configuration setting, 2012-08-03) we made two\n    @@ Commit message\n             # BRE grep\n             git -c grep.extendedRegexp=true -c grep.patternType=basic grep <pattern>\n     \n    -    But probably not for this to ignore the new \"grep.patternType\" option\n    -    entirely, say if /etc/gitconfig was still setting\n    +    But probably not for this to ignore the favored \"grep.patternType\"\n    +    option entirely, say if /etc/gitconfig was still setting\n         \"grep.extendedRegexp\", but \"~/.gitconfig\" used the new\n         \"grep.patternType\" (and wanted to use the \"default\" value):\n     \n    @@ Documentation/config/grep.txt: grep.patternType::\n      \tIf set to true, enable `--extended-regexp` option by default. This\n     -\toption is ignored when the `grep.patternType` option is set to a value\n     -\tother than 'default'.\n    -+\toption is ignored when the `grep.patternType` option is set.\n    - \n    - grep.threads::\n    - \tNumber of grep worker threads to use.\n    -\n    - ## Documentation/git-grep.txt ##\n    -@@ Documentation/git-grep.txt: grep.patternType::\n    - \n    - grep.extendedRegexp::\n    - \tIf set to true, enable `--extended-regexp` option by default. This\n    --\toption is ignored when the `grep.patternType` option is set to a value\n    --\tother than 'default'.\n     +\toption is ignored when the `grep.patternType` option is set.\n      \n      grep.threads::\n8:  dadd5dff77a ! 8:  cc904d93b26 grep: make \"extendedRegexp=true\" the same as \"patternType=extended\"\n    @@ Documentation/config/grep.txt: grep.patternType::\n      grep.extendedRegexp::\n     -\tIf set to true, enable `--extended-regexp` option by default. This\n     -\toption is ignored when the `grep.patternType` option is set.\n    -+\tDeprecated synonym for 'grep.patternType=extended`.\n    - \n    - grep.threads::\n    - \tNumber of grep worker threads to use.\n    -\n    - ## Documentation/git-grep.txt ##\n    -@@ Documentation/git-grep.txt: grep.patternType::\n    - \tvalue 'default' will return to the default matching behavior.\n    - \n    - grep.extendedRegexp::\n    --\tIf set to true, enable `--extended-regexp` option by default. This\n    --\toption is ignored when the `grep.patternType` option is set.\n     +\tDeprecated synonym for 'grep.patternType=extended`.\n      \n      grep.threads::\n    @@ grep.h: struct grep_opt {\n      \t.colors = { \\\n      \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n      \t\t[GREP_COLOR_FILENAME] = \"\", \\\n    -@@ grep.h: struct grep_opt {\n    - \t\t[GREP_COLOR_SELECTED] = \"\", \\\n    - \t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n    - \t}, \\\n    --\t.only_matching = 0, \\\n    - \t.color = -1, \\\n    - \t.output = std_output, \\\n    - }\n     \n      ## t/t7810-grep.sh ##\n     @@ t/t7810-grep.sh: do\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440796","messageId":"patch-v2-1.8-1435db727ef-20211110T013632Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v2-0.8-00000000000-20211110T013632Z-avarab@gmail.com","subject":"[PATCH v2 1/8] grep.h: remove unused \"regex_t regexp\" from grep_opt","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-10T01:43:43Z","receivedAt":"2021-11-10T01:44:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This \"regex_t\" in grep_opt has not been used since\nf9b9faf6f8a (builtin-grep: allow more than one patterns., 2006-05-02),\nwe still use a \"regex_t\" for compiling regexes, but that's in the\n\"grep_pat\" struct\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 3e8815c347b..95cccb670f9 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -136,7 +136,6 @@ struct grep_opt {\n \n \tconst char *prefix;\n \tint prefix_length;\n-\tregex_t regexp;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440798","messageId":"patch-v2-2.8-63cf2fe266d-20211110T013632Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v2-0.8-00000000000-20211110T013632Z-avarab@gmail.com","subject":"[PATCH v2 2/8] built-ins: trust the \"prefix\" from run_builtin()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-10T01:43:44Z","receivedAt":"2021-11-10T01:44:02Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in \"builtin/grep.c\" and \"builtin/ls-tree.c\" to trust the\n\"prefix\" passed from \"run_builtin()\". The \"prefix\" we get from setup.c\nis either going to be NULL or a string of length >0, never \"\".\n\nSo we can drop the \"prefix && *prefix\" checks added for\n\"builtin/grep.c\" in 0d042fecf2f (git-grep: show pathnames relative to\nthe current directory, 2006-08-11), and for \"builtin/ls-tree.c\" in\na69dd585fca (ls-tree: chomp leading directories when run from a\nsubdirectory, 2005-12-23).\n\nAs seen in code in revision.c that was added in cd676a51367 (diff\n--relative: output paths as relative to the current subdirectory,\n2008-02-12) we already have existing code that does away with this\nassertion.\n\nThis makes it easier to reason about a subsequent change to the\n\"prefix_length\" code in grep.c in a subsequent commit, and since we're\ngoing to the trouble of doing that let's leave behind an assert() to\npromise this to any future callers.\n\nFor \"builtin/grep.c\" it would be painful to pass the \"prefix\" down the\ncallchain of:\n\n    cmd_grep -> grep_tree -> grep_submodule -> grep_cache -> grep_oid ->\n    grep_source_name\n\nSo for the code that needs it in grep_source_name() let's add a\n\"grep_prefix\" variable similar to the existing \"ls_tree_prefix\".\n\nWhile at it let's move the code in cmd_ls_tree() around so that we\nassign to the \"ls_tree_prefix\" right after declaring the variables,\nand stop assigning to \"prefix\". We only subsequently used that\nvariable later in the function after clobbering it. Let's just use our\nown \"grep_prefix\" instead.\n\nLet's also add an assert() in git.c, so that we'll make this promise\nabout the \"prefix\" to any current and future callers, as well as to\nany readers of the code.\n\nCode history:\n\n * The strlen() in \"grep.c\" hasn't been used since 493b7a08d80 (grep:\n   accept relative paths outside current working directory, 2009-09-05).\n\n   When that code was added in 0d042fecf2f (git-grep: show pathnames\n   relative to the current directory, 2006-08-11) we used the length.\n\n   But since 493b7a08d80 we haven't used it for anything except a\n   boolean check that we could have done on the \"prefix\" member\n   itself.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c    | 13 ++++++++-----\n builtin/ls-tree.c |  9 ++++-----\n git.c             |  4 ++--\n grep.c            |  4 +---\n grep.h            |  4 +---\n revision.c        |  2 +-\n 6 files changed, 17 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 9e34a820ad4..d85cbabea67 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -26,6 +26,8 @@\n #include \"object-store.h\"\n #include \"packfile.h\"\n \n+static const char *grep_prefix;\n+\n static char const * const grep_usage[] = {\n \tN_(\"git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]\"),\n \tNULL\n@@ -315,11 +317,11 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \tstrbuf_reset(out);\n \n \tif (opt->null_following_name) {\n-\t\tif (opt->relative && opt->prefix_length) {\n+\t\tif (opt->relative && grep_prefix) {\n \t\t\tstruct strbuf rel_buf = STRBUF_INIT;\n \t\t\tconst char *rel_name =\n \t\t\t\trelative_path(filename + tree_name_len,\n-\t\t\t\t\t      opt->prefix, &rel_buf);\n+\t\t\t\t\t      grep_prefix, &rel_buf);\n \n \t\t\tif (tree_name_len)\n \t\t\t\tstrbuf_add(out, filename, tree_name_len);\n@@ -332,8 +334,8 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \t\treturn;\n \t}\n \n-\tif (opt->relative && opt->prefix_length)\n-\t\tquote_path(filename + tree_name_len, opt->prefix, out, 0);\n+\tif (opt->relative && grep_prefix)\n+\t\tquote_path(filename + tree_name_len, grep_prefix, out, 0);\n \telse\n \t\tquote_c_style(filename + tree_name_len, out, NULL, 0);\n \n@@ -962,9 +964,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\t   PARSE_OPT_NOCOMPLETE),\n \t\tOPT_END()\n \t};\n+\tgrep_prefix = prefix;\n \n \tgit_config(grep_cmd_config, NULL);\n-\tgrep_init(&opt, the_repository, prefix);\n+\tgrep_init(&opt, the_repository);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 3a442631c71..84bed6d5612 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -147,16 +147,15 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \t\tOPT__ABBREV(&abbrev),\n \t\tOPT_END()\n \t};\n-\n-\tgit_config(git_default_config, NULL);\n \tls_tree_prefix = prefix;\n-\tif (prefix && *prefix)\n+\tif (prefix)\n \t\tchomp_prefix = strlen(prefix);\n \n+\tgit_config(git_default_config, NULL);\n \targc = parse_options(argc, argv, prefix, ls_tree_options,\n \t\t\t     ls_tree_usage, 0);\n \tif (full_tree) {\n-\t\tls_tree_prefix = prefix = NULL;\n+\t\tls_tree_prefix = NULL;\n \t\tchomp_prefix = 0;\n \t}\n \t/* -d -r should imply -t, but -d by itself should not have to. */\n@@ -178,7 +177,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \tparse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &\n \t\t\t\t  ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n \t\t       PATHSPEC_PREFER_CWD,\n-\t\t       prefix, argv + 1);\n+\t\t       ls_tree_prefix, argv + 1);\n \tfor (i = 0; i < pathspec.nr; i++)\n \t\tpathspec.items[i].nowildcard_len = pathspec.items[i].len;\n \tpathspec.has_wildcard = 0;\ndiff --git a/git.c b/git.c\nindex 5ff21be21f3..611bf2f63eb 100644\n--- a/git.c\n+++ b/git.c\n@@ -420,9 +420,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n {\n \tint status, help;\n \tstruct stat st;\n-\tconst char *prefix;\n+\tconst char *prefix = NULL;\n \n-\tprefix = NULL;\n \thelp = argc == 2 && !strcmp(argv[1], \"-h\");\n \tif (!help) {\n \t\tif (p->option & RUN_SETUP)\n@@ -431,6 +430,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t\t\tint nongit_ok;\n \t\t\tprefix = setup_git_directory_gently(&nongit_ok);\n \t\t}\n+\t\tassert(!prefix || *prefix);\n \t\tprecompose_argv_prefix(argc, argv, NULL);\n \t\tif (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY) &&\n \t\t    !(p->option & DELAY_PAGER_CONFIG))\ndiff --git a/grep.c b/grep.c\nindex f6e113e9f0f..c9065254aeb 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -139,13 +139,11 @@ int grep_config(const char *var, const char *value, void *cb)\n  * default values from the template we read the configuration\n  * information in an earlier call to git_config(grep_config).\n  */\n-void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)\n+void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n \t*opt = grep_defaults;\n \n \topt->repo = repo;\n-\topt->prefix = prefix;\n-\topt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;\n \topt->pattern_tail = &opt->pattern_list;\n \topt->header_tail = &opt->header_list;\n }\ndiff --git a/grep.h b/grep.h\nindex 95cccb670f9..62deadb885f 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -134,8 +134,6 @@ struct grep_opt {\n \t */\n \tstruct repository *repo;\n \n-\tconst char *prefix;\n-\tint prefix_length;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n@@ -180,7 +178,7 @@ struct grep_opt {\n };\n \n int grep_config(const char *var, const char *value, void *);\n-void grep_init(struct grep_opt *, struct repository *repo, const char *prefix);\n+void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex ab7c1358042..9f9b0d2429e 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1833,7 +1833,7 @@ void repo_init_revisions(struct repository *r,\n \trevs->commit_format = CMIT_FMT_DEFAULT;\n \trevs->expand_tabs_in_log_default = 8;\n \n-\tgrep_init(&revs->grep_filter, revs->repo, prefix);\n+\tgrep_init(&revs->grep_filter, revs->repo);\n \trevs->grep_filter.status_only = 1;\n \n \trepo_diff_setup(revs->repo, &revs->diffopt);\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440797","messageId":"patch-v2-3.8-41e38ebb32c-20211110T013632Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v2-0.8-00000000000-20211110T013632Z-avarab@gmail.com","subject":"[PATCH v2 3/8] log tests: check if grep_config() is called by \"log\"-like cmds","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-10T01:43:45Z","receivedAt":"2021-11-10T01:44:03Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the tests added in my 9df46763ef1 (log: add exhaustive tests\nfor pattern style options & config, 2017-05-20) to check not only\nwhether \"git log\" handles \"grep.patternType\", but also \"git show\"\netc.\n\nIt's sufficient to check whether a PCRE regex matches for the purposes\nof this test, we otherwise assume that it's running the same code as\n\"git log\", whose behavior is tested more exhaustively by test added in\n9df46763ef1e.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4202-log.sh | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)\n\ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex 7884e3d46b3..a114c49ef27 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -449,6 +449,22 @@ test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurati\n \t)\n '\n \n+for cmd in show whatchanged reflog format-patch\n+do\n+\tmyarg=\n+\tif test \"$cmd\" = \"format-patch\"\n+\tthen\n+\t\tmyarg=\"HEAD~..\"\n+\tfi\n+\n+\ttest_expect_success PCRE \"$cmd: understands grep.patternType=perl, like 'log'\" '\n+\t\tgit -c grep.patternType=fixed -C pattern-type $cmd --grep=\"1(?=\\|2)\" $myarg >actual &&\n+\t\ttest_must_be_empty actual &&\n+\t\tgit -c grep.patternType=perl -C pattern-type $cmd --grep=\"1(?=\\|2)\" $myarg >actual &&\n+\t\ttest_file_not_empty actual\n+\t'\n+done\n+\n test_expect_success 'log --author' '\n \tcat >expect <<-\\EOF &&\n \tAuthor: <BOLD;RED>A U<RESET> Thor <author@example.com>\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440799","messageId":"patch-v2-4.8-efe95397d72-20211110T013632Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v2-0.8-00000000000-20211110T013632Z-avarab@gmail.com","subject":"[PATCH v2 4/8] grep docs: de-duplicate configuration sections","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-10T01:43:46Z","receivedAt":"2021-11-10T01:44:04Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Include the \"config/grep.txt\" file in \"git-grep.txt\", instead of\nrepeating an almost identical description of the \"grep\" configuration\nvariables in two places. In a subsequent commit we'll amend this\ndocumentation, and can now do so in one place instead of two.\n\nLet's also add a short blurb at the top indicating that this is\nincluded documentation, so users won't think that they need to read\nthe two versions and compare them.\n\nThat wording is copy/pasted from the change I made in b6a8d09f6d8 (gc\ndocs: include the \"gc.*\" section from \"config\" in \"gc\", 2019-04-07),\neventually we'll want to include this via template, and indeed this\nchange is extracted from a WIP series that fixes all these\n\"CONFIGURATION\" includes which does that. But doing that would require\nbuild system changes, so let's punt on it for now.\n\nThere is no loss of information here that isn't shown in the addition\nto \"grep.txt\". This change was made by copying the contents of\n\"git-grep.txt\"'s version over the \"grep.txt\" version. Aside from the\nchange \"grep.txt\" being made here the two were identical.\n\nThis documentation started being copy/pasted around in\nb22520a37c8 (grep: allow -E and -n to be turned on by default via\nconfiguration, 2011-03-30). After that in e.g. 6453f7b3486 (grep: add\ngrep.fullName config variable, 2014-03-17) they started drifting\napart, with only grep.fullName being described in the command\ndocumentation.\n\nIn 434e6e753fe (config.txt: move grep.* to a separate file,\n2018-10-27) we gained the include, but didn't do this next step, let's\ndo it now.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config/grep.txt |  7 +++++--\n Documentation/git-grep.txt    | 30 +++---------------------------\n 2 files changed, 8 insertions(+), 29 deletions(-)\n\ndiff --git a/Documentation/config/grep.txt b/Documentation/config/grep.txt\nindex 44abe45a7ca..ae51f2d91c8 100644\n--- a/Documentation/config/grep.txt\n+++ b/Documentation/config/grep.txt\n@@ -16,8 +16,11 @@ grep.extendedRegexp::\n \tother than 'default'.\n \n grep.threads::\n-\tNumber of grep worker threads to use.\n-\tSee `grep.threads` in linkgit:git-grep[1] for more information.\n+\tNumber of grep worker threads to use. If unset (or set to 0), Git will\n+\tuse as many threads as the number of logical cores available.\n+\n+grep.fullName::\n+\tIf set to true, enable `--full-name` option by default.\n \n grep.fallbackToNoIndex::\n \tIf set to true, fall back to git grep --no-index if git grep\ndiff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt\nindex 3d393fbac1b..29d5ce04f5a 100644\n--- a/Documentation/git-grep.txt\n+++ b/Documentation/git-grep.txt\n@@ -334,34 +334,10 @@ performance in this case, it might be desirable to use `--threads=1`.\n CONFIGURATION\n -------------\n \n-grep.lineNumber::\n-\tIf set to true, enable `-n` option by default.\n-\n-grep.column::\n-\tIf set to true, enable the `--column` option by default.\n-\n-grep.patternType::\n-\tSet the default matching behavior. Using a value of 'basic', 'extended',\n-\t'fixed', or 'perl' will enable the `--basic-regexp`, `--extended-regexp`,\n-\t`--fixed-strings`, or `--perl-regexp` option accordingly, while the\n-\tvalue 'default' will return to the default matching behavior.\n-\n-grep.extendedRegexp::\n-\tIf set to true, enable `--extended-regexp` option by default. This\n-\toption is ignored when the `grep.patternType` option is set to a value\n-\tother than 'default'.\n-\n-grep.threads::\n-\tNumber of grep worker threads to use. If unset (or set to 0), Git will\n-\tuse as many threads as the number of logical cores available.\n-\n-grep.fullName::\n-\tIf set to true, enable `--full-name` option by default.\n-\n-grep.fallbackToNoIndex::\n-\tIf set to true, fall back to git grep --no-index if git grep\n-\tis executed outside of a git repository.  Defaults to false.\n+The below documentation is the same as what's found in\n+linkgit:git-config[1]:\n \n+include::config/grep.txt[]\n \n GIT\n ---\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440800","messageId":"patch-v2-5.8-d0f0ac6c7ae-20211110T013632Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v2-0.8-00000000000-20211110T013632Z-avarab@gmail.com","subject":"[PATCH v2 5/8] grep.c: don't pass along NULL callback value","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-10T01:43:47Z","receivedAt":"2021-11-10T01:44:05Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change grep_cmd_config() top stop passing around the always-NULL \"cb\"\nvalue. When this code was added in 7e8f59d577e (grep: color patterns\nin output, 2009-03-07) it was non-NULL, but when that changed in\n15fabd1bbd4 (builtin/grep.c: make configuration callback more\nreusable, 2012-10-09) this code was left behind.\n\nIn a subsequent change I'll start using the \"cb\" value, this will make\nit clear which functions we call need it, and which don't.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex d85cbabea67..5ec4cecae45 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,8 +285,8 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, cb);\n-\tif (git_color_default_config(var, value, cb) < 0)\n+\tint st = grep_config(var, value, NULL);\n+\tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n \tif (!strcmp(var, \"grep.threads\")) {\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440801","messageId":"patch-v2-6.8-917944f79a5-20211110T013632Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v2-0.8-00000000000-20211110T013632Z-avarab@gmail.com","subject":"[PATCH v2 6/8] grep API: call grep_config() after grep_init()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-10T01:43:48Z","receivedAt":"2021-11-10T01:44:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The grep_init() function used the odd pattern of initializing the\npassed-in \"struct grep_opt\" with a statically defined \"grep_defaults\"\nstruct, which would be modified in-place when we invoked\ngrep_config().\n\nSo we effectively (b) initialized config, (a) then defaults, (c)\nfollowed by user options. Usually those are ordered as \"a\", \"b\" and\n\"c\" instead.\n\nAs the comments being removed here show the previous behavior needed\nto be carefully explained as we'd potentially share the populated\nconfiguration among different instances of grep_init(). In practice we\ndidn't do that, but now that it can't be a concern anymore let's\nremove those comments.\n\nThis does not change the behavior of any of the configuration\nvariables or options. That would have been the case if we didn't move\naround the grep_config() call in \"builtin/log.c\". But now that we call\n\"grep_config\" after \"git_log_config\" and \"git_format_config\" we'll\nneed to pass in the already initialized \"struct grep_opt *\".\n\nSee 6ba9bb76e02 (grep: copy struct in one fell swoop, 2020-11-29) and\n7687a0541e0 (grep: move the configuration parsing logic to grep.[ch],\n2012-10-09) for the commits that added the comments.\n\nThe memcpy() pattern here will be optimized away and follows the\nconvention of other *_init() functions. See 5726a6b4012 (*.c *_init():\ndefine in terms of corresponding *_INIT macro, 2021-07-01).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c |  4 ++--\n builtin/log.c  | 13 +++++++++++--\n grep.c         | 39 +++------------------------------------\n grep.h         | 22 ++++++++++++++++++++++\n 4 files changed, 38 insertions(+), 40 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5ec4cecae45..0ea124321b6 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,7 +285,7 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, NULL);\n+\tint st = grep_config(var, value, cb);\n \tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n@@ -966,8 +966,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t};\n \tgrep_prefix = prefix;\n \n-\tgit_config(grep_cmd_config, NULL);\n \tgrep_init(&opt, the_repository);\n+\tgit_config(grep_cmd_config, &opt);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/log.c b/builtin/log.c\nindex f75d87e8d7f..bfddacdfa6c 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -505,8 +505,6 @@ static int git_log_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n-\tif (grep_config(var, value, cb) < 0)\n-\t\treturn -1;\n \tif (git_gpg_config(var, value, cb) < 0)\n \t\treturn -1;\n \treturn git_diff_ui_config(var, value, cb);\n@@ -521,6 +519,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.simplify_history = 0;\n \tmemset(&opt, 0, sizeof(opt));\n@@ -635,6 +635,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \n \tmemset(&match_all, 0, sizeof(match_all));\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.always_show_header = 1;\n \trev.no_walk = 1;\n@@ -718,6 +720,8 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n \tinit_reflog_walk(&rev.reflog_info);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.verbose_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -751,6 +755,8 @@ int cmd_log(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.always_show_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -1833,10 +1839,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \textra_hdr.strdup_strings = 1;\n \textra_to.strdup_strings = 1;\n \textra_cc.strdup_strings = 1;\n+\n \tinit_log_defaults();\n \tinit_display_notes(&notes_opt);\n \tgit_config(git_format_config, NULL);\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.show_notes = show_notes;\n \tmemcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));\n \trev.commit_format = CMIT_FMT_EMAIL;\ndiff --git a/grep.c b/grep.c\nindex c9065254aeb..fb3f63c63ef 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -19,27 +19,6 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)\n \tfwrite(buf, size, 1, stdout);\n }\n \n-static struct grep_opt grep_defaults = {\n-\t.relative = 1,\n-\t.pathname = 1,\n-\t.max_depth = -1,\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t.colors = {\n-\t\t[GREP_COLOR_CONTEXT] = \"\",\n-\t\t[GREP_COLOR_FILENAME] = \"\",\n-\t\t[GREP_COLOR_FUNCTION] = \"\",\n-\t\t[GREP_COLOR_LINENO] = \"\",\n-\t\t[GREP_COLOR_COLUMNNO] = \"\",\n-\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_SELECTED] = \"\",\n-\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN,\n-\t},\n-\t.only_matching = 0,\n-\t.color = -1,\n-\t.output = std_output,\n-};\n-\n static const char *color_grep_slots[] = {\n \t[GREP_COLOR_CONTEXT]\t    = \"context\",\n \t[GREP_COLOR_FILENAME]\t    = \"filename\",\n@@ -75,20 +54,12 @@ define_list_config_array_extra(color_grep_slots, {\"match\"});\n  */\n int grep_config(const char *var, const char *value, void *cb)\n {\n-\tstruct grep_opt *opt = &grep_defaults;\n+\tstruct grep_opt *opt = cb;\n \tconst char *slot;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\t/*\n-\t * The instance of grep_opt that we set up here is copied by\n-\t * grep_init() to be used by each individual invocation.\n-\t * When populating a new field of this structure here, be\n-\t * sure to think about ownership -- e.g., you might need to\n-\t * override the shallow copy in grep_init() with a deep copy.\n-\t */\n-\n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n \t\treturn 0;\n@@ -134,14 +105,10 @@ int grep_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/*\n- * Initialize one instance of grep_opt and copy the\n- * default values from the template we read the configuration\n- * information in an earlier call to git_config(grep_config).\n- */\n void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n-\t*opt = grep_defaults;\n+\tstruct grep_opt blank = GREP_OPT_INIT;\n+\tmemcpy(opt, &blank, sizeof(*opt));\n \n \topt->repo = repo;\n \topt->pattern_tail = &opt->pattern_list;\ndiff --git a/grep.h b/grep.h\nindex 62deadb885f..30a7dfd3294 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -171,12 +171,34 @@ struct grep_opt {\n \tint show_hunk_mark;\n \tint file_break;\n \tint heading;\n+\tvoid *caller_priv;\n \tvoid *priv;\n \n \tvoid (*output)(struct grep_opt *opt, const void *data, size_t size);\n \tvoid *output_priv;\n };\n \n+#define GREP_OPT_INIT { \\\n+\t.relative = 1, \\\n+\t.pathname = 1, \\\n+\t.max_depth = -1, \\\n+\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n+\t.colors = { \\\n+\t\t[GREP_COLOR_CONTEXT] = \"\", \\\n+\t\t[GREP_COLOR_FILENAME] = \"\", \\\n+\t\t[GREP_COLOR_FUNCTION] = \"\", \\\n+\t\t[GREP_COLOR_LINENO] = \"\", \\\n+\t\t[GREP_COLOR_COLUMNNO] = \"\", \\\n+\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_SELECTED] = \"\", \\\n+\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n+\t}, \\\n+\t.only_matching = 0, \\\n+\t.color = -1, \\\n+\t.output = std_output, \\\n+}\n+\n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440802","messageId":"patch-v2-7.8-140a7416223-20211110T013632Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v2-0.8-00000000000-20211110T013632Z-avarab@gmail.com","subject":"[PATCH v2 7/8] grep: simplify config parsing, change grep.<rx config> interaction","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-10T01:43:49Z","receivedAt":"2021-11-10T01:44:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the interaction between \"grep.patternType=default\" and\n\"grep.extendedRegexp=true\" to make setting \"grep.extendedRegexp=true\"\nsynonymous with setting \"grep.patternType=extended\".\n\nThis changes our existing config parsing behavior as detailed below,\nbut in a way that's consistent with how we parse other\nconfiguration.\n\nWe are breaking past promises here, but I doubt that this will impact\nanyone in practice. The reduction in complexity and resulting\nconsistency with other default config behavior is worth it.\n\nWhen \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\ngrep.patternType configuration setting, 2012-08-03) we made two\nseemingly contradictory promises:\n\n 1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n    will return to the default matching behavior\".\n\n 2. Support the existing \"grep.extendedRegexp\" option, but ignore it\n    when the new \"grep.patternType\" is set, *except* \"when the\n    `grep.patternType` option is set. to a value other than 'default'\".\n\nI think that 84befcd0a4a probably didn't intend this behavior, but\ninstead ended up conflating our internal \"unspecified\" state with a\nuser's explicit desire to set the configuration back to the\ndefault.\n\nI.e. a user would correctly expect this to keep working:\n\n    # ERE grep\n    git -c grep.extendedRegexp=true grep <pattern>\n\nAnd likewise for \"grep.patternType=default\" to take precedence over\nthe disfavored \"grep.extendedRegexp\" option, i.e. the usual \"last set\nwins\" semantics.\n\n    # BRE grep\n    git -c grep.extendedRegexp=true -c grep.patternType=basic grep <pattern>\n\nBut probably not for this to ignore the favored \"grep.patternType\"\noption entirely, say if /etc/gitconfig was still setting\n\"grep.extendedRegexp\", but \"~/.gitconfig\" used the new\n\"grep.patternType\" (and wanted to use the \"default\" value):\n\n    # Was ERE, now BRE\n    git -c grep.extendedRegexp=true grep.patternType=default grep <pattern>\n\nI think that in practice nobody or almost nobody is going to be\nrelying on this obscure interaction, and as shown here it makes the\nconfig parsing much simpler. We no longer have to carry a complex\nstate machine in \"grep_commit_pattern_type()\" and\n\"grep_set_pattern_type_option()\".\n\nWe can also do away with the \"int fixed\" and \"int pcre2\" members in\nfavor of using \"pattern_type_option\" directly in \"grep.c\", as well as\ndropping the \"pattern_type_arg\" variable in \"builtin/grep.c\" in favor\nof using the \"pattern_type_option\" member directly.\n\nSee my 07a3d411739 (grep: remove regflags from the public grep_opt\nAPI, 2017-06-29) for addition of the two comments being removed here,\ni.e. the complexity noted in that commit is now going away.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config/grep.txt |  3 +-\n builtin/grep.c                | 10 ++---\n grep.c                        | 71 +++++------------------------------\n grep.h                        |  6 +--\n revision.c                    |  2 -\n t/t7810-grep.sh               |  2 +-\n 6 files changed, 16 insertions(+), 78 deletions(-)\n\ndiff --git a/Documentation/config/grep.txt b/Documentation/config/grep.txt\nindex ae51f2d91c8..f4b7d3041fb 100644\n--- a/Documentation/config/grep.txt\n+++ b/Documentation/config/grep.txt\n@@ -12,8 +12,7 @@ grep.patternType::\n \n grep.extendedRegexp::\n \tIf set to true, enable `--extended-regexp` option by default. This\n-\toption is ignored when the `grep.patternType` option is set to a value\n-\tother than 'default'.\n+\toption is ignored when the `grep.patternType` option is set.\n \n grep.threads::\n \tNumber of grep worker threads to use. If unset (or set to 0), Git will\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 0ea124321b6..942c4b25077 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -845,7 +845,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tint i;\n \tint dummy;\n \tint use_index = 1;\n-\tint pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;\n \tint allow_revs;\n \n \tstruct option options[] = {\n@@ -879,16 +878,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"descend at most <depth> levels\"), PARSE_OPT_NONEG,\n \t\t\tNULL, 1 },\n \t\tOPT_GROUP(\"\"),\n-\t\tOPT_SET_INT('E', \"extended-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('E', \"extended-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use extended POSIX regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_ERE),\n-\t\tOPT_SET_INT('G', \"basic-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('G', \"basic-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use basic POSIX regular expressions (default)\"),\n \t\t\t    GREP_PATTERN_TYPE_BRE),\n-\t\tOPT_SET_INT('F', \"fixed-strings\", &pattern_type_arg,\n+\t\tOPT_SET_INT('F', \"fixed-strings\", &opt.pattern_type_option,\n \t\t\t    N_(\"interpret patterns as fixed strings\"),\n \t\t\t    GREP_PATTERN_TYPE_FIXED),\n-\t\tOPT_SET_INT('P', \"perl-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('P', \"perl-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use Perl-compatible regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_PCRE),\n \t\tOPT_GROUP(\"\"),\n@@ -982,7 +981,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, grep_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH |\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n-\tgrep_commit_pattern_type(pattern_type_arg, &opt);\n \n \tif (use_index && !startup_info->have_repository) {\n \t\tint fallback = 0;\ndiff --git a/grep.c b/grep.c\nindex fb3f63c63ef..dda8e536fe3 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -60,8 +60,10 @@ int grep_config(const char *var, const char *value, void *cb)\n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\tif (!strcmp(var, \"grep.extendedregexp\")) {\n-\t\topt->extended_regexp_option = git_config_bool(var, value);\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_UNSPECIFIED &&\n+\t    !strcmp(var, \"grep.extendedregexp\") &&\n+\t    git_config_bool(var, value)) {\n+\t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n \t\treturn 0;\n \t}\n \n@@ -115,62 +117,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo)\n \topt->header_tail = &opt->header_list;\n }\n \n-static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\t/*\n-\t * When committing to the pattern type by setting the relevant\n-\t * fields in grep_opt it's generally not necessary to zero out\n-\t * the fields we're not choosing, since they won't have been\n-\t * set by anything. The extended_regexp_option field is the\n-\t * only exception to this.\n-\t *\n-\t * This is because in the process of parsing grep.patternType\n-\t * & grep.extendedRegexp we set opt->pattern_type_option and\n-\t * opt->extended_regexp_option, respectively. We then\n-\t * internally use opt->extended_regexp_option to see if we're\n-\t * compiling an ERE. It must be unset if that's not actually\n-\t * the case.\n-\t */\n-\tif (pattern_type != GREP_PATTERN_TYPE_ERE &&\n-\t    opt->extended_regexp_option)\n-\t\topt->extended_regexp_option = 0;\n-\n-\tswitch (pattern_type) {\n-\tcase GREP_PATTERN_TYPE_UNSPECIFIED:\n-\t\t/* fall through */\n-\n-\tcase GREP_PATTERN_TYPE_BRE:\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_ERE:\n-\t\topt->extended_regexp_option = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_FIXED:\n-\t\topt->fixed = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_PCRE:\n-\t\topt->pcre2 = 1;\n-\t\tbreak;\n-\t}\n-}\n-\n-void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\tif (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(pattern_type, opt);\n-\telse if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(opt->pattern_type_option, opt);\n-\telse if (opt->extended_regexp_option)\n-\t\t/*\n-\t\t * This branch *must* happen after setting from the\n-\t\t * opt->pattern_type_option above, we don't want\n-\t\t * grep.extendedRegexp to override grep.patternType!\n-\t\t */\n-\t\tgrep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);\n-}\n-\n static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,\n \t\t\t\t\tconst char *origin, int no,\n \t\t\t\t\tenum grep_pat_token t,\n@@ -492,9 +438,10 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \n \tp->word_regexp = opt->word_regexp;\n \tp->ignore_case = opt->ignore_case;\n-\tp->fixed = opt->fixed;\n+\tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\n \n-\tif (memchr(p->pattern, 0, p->patternlen) && !opt->pcre2)\n+\tif (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE &&\n+\t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n \tp->is_fixed = is_fixed(p->pattern, p->patternlen);\n@@ -545,14 +492,14 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \t\treturn;\n \t}\n \n-\tif (opt->pcre2) {\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_PCRE) {\n \t\tcompile_pcre2_pattern(p, opt);\n \t\treturn;\n \t}\n \n \tif (p->ignore_case)\n \t\tregflags |= REG_ICASE;\n-\tif (opt->extended_regexp_option)\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_ERE)\n \t\tregflags |= REG_EXTENDED;\n \terr = regcomp(&p->regexp, p->pattern, regflags);\n \tif (err) {\ndiff --git a/grep.h b/grep.h\nindex 30a7dfd3294..e4e548aed90 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -143,7 +143,6 @@ struct grep_opt {\n \tint unmatch_name_only;\n \tint count;\n \tint word_regexp;\n-\tint fixed;\n \tint all_match;\n #define GREP_BINARY_DEFAULT\t0\n #define GREP_BINARY_NOMATCH\t1\n@@ -152,7 +151,6 @@ struct grep_opt {\n \tint allow_textconv;\n \tint extended;\n \tint use_reflog_filter;\n-\tint pcre2;\n \tint relative;\n \tint pathname;\n \tint null_following_name;\n@@ -161,8 +159,7 @@ struct grep_opt {\n \tint max_depth;\n \tint funcname;\n \tint funcbody;\n-\tint extended_regexp_option;\n-\tint pattern_type_option;\n+\tenum grep_pattern_type pattern_type_option;\n \tint ignore_locale;\n \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n \tunsigned pre_context;\n@@ -201,7 +198,6 @@ struct grep_opt {\n \n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n-void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\n void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex 9f9b0d2429e..ed29d245c89 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2864,8 +2864,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \n \tdiff_setup_done(&revs->diffopt);\n \n-\tgrep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t\t\t\t &revs->grep_filter);\n \tif (!is_encoding_utf8(get_log_output_encoding()))\n \t\trevs->grep_filter.ignore_locale = 1;\n \tcompile_grep_patterns(&revs->grep_filter);\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 6b6423a07c3..a59a9726357 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -443,7 +443,7 @@ do\n \t'\n \n \ttest_expect_success \"grep $L with grep.extendedRegexp=true and grep.patternType=default\" '\n-\t\techo \"${HC}ab:abc\" >expected &&\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n \t\tgit \\\n \t\t\t-c grep.extendedRegexp=true \\\n \t\t\t-c grep.patternType=default \\\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440803","messageId":"patch-v2-8.8-cc904d93b26-20211110T013632Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v2-0.8-00000000000-20211110T013632Z-avarab@gmail.com","subject":"[PATCH v2 8/8] grep: make \"extendedRegexp=true\" the same as \"patternType=extended\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-10T01:43:50Z","receivedAt":"2021-11-10T01:44:09Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"In the preceding commit we changed how a \"grep.patternType=default\"\nset after \"grep.extendedRegexp=true\" would be handled so that the last\nset would win, but a \"grep.extendedRegexp=true\" would only be used if\n\"grep.patternType\" was set to a value other than \"default\".\n\nThus a user who had old config and set \"grep.extendedRegexp=true\" in\ntheir ~/.gitconfig expecting ERE behavior would be opted-in to say\n\"perl\" regexes if a system \"/etc/gitconfig\" started setting\n\"grep.patternType=perl\".\n\nThese funny semantics of only paying attention to a set if another key\nis not set to a given value aren't how we treat other config keys, so\nlet's do away with this caveat for consistency.\n\nThe new semantics are simple, a \"grep.extendedRegexp=true\" is an exact\nsynonym for specifying \"grep.patternType=extended\" in the\nconfig. We'll keep ignoring \"\"grep.extendedRegexp=false\", although\narguably we could treat it as a \"grep.patternType=basic\".\n\nAs argued in the preceding commit I think this behavior came about\nbecause we were conflating the state of our code's own internal\n\"default\" value with what we found in explicit user config. See\n84befcd0a4a (grep: add a grep.patternType configuration setting,\n2012-08-03) for that past behavior.\n\nLet's further change the documentation to note that\n\"grep.extendedRegexp\" is a deprecated synonym, perhaps we'll be able\nto remove it at some point in the future and do away with this\nspecial-case entirely.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config/grep.txt | 3 +--\n grep.c                        | 8 +++-----\n grep.h                        | 4 +---\n t/t7810-grep.sh               | 2 +-\n 4 files changed, 6 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/config/grep.txt b/Documentation/config/grep.txt\nindex f4b7d3041fb..33e5f3827bc 100644\n--- a/Documentation/config/grep.txt\n+++ b/Documentation/config/grep.txt\n@@ -11,8 +11,7 @@ grep.patternType::\n \tvalue 'default' will return to the default matching behavior.\n \n grep.extendedRegexp::\n-\tIf set to true, enable `--extended-regexp` option by default. This\n-\toption is ignored when the `grep.patternType` option is set.\n+\tDeprecated synonym for 'grep.patternType=extended`.\n \n grep.threads::\n \tNumber of grep worker threads to use. If unset (or set to 0), Git will\ndiff --git a/grep.c b/grep.c\nindex dda8e536fe3..ef8746d85f0 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -33,9 +33,8 @@ static const char *color_grep_slots[] = {\n \n static int parse_pattern_type_arg(const char *opt, const char *arg)\n {\n-\tif (!strcmp(arg, \"default\"))\n-\t\treturn GREP_PATTERN_TYPE_UNSPECIFIED;\n-\telse if (!strcmp(arg, \"basic\"))\n+\tif (!strcmp(arg, \"basic\") ||\n+\t    !strcmp(arg, \"default\"))\n \t\treturn GREP_PATTERN_TYPE_BRE;\n \telse if (!strcmp(arg, \"extended\"))\n \t\treturn GREP_PATTERN_TYPE_ERE;\n@@ -60,8 +59,7 @@ int grep_config(const char *var, const char *value, void *cb)\n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_UNSPECIFIED &&\n-\t    !strcmp(var, \"grep.extendedregexp\") &&\n+\tif (!strcmp(var, \"grep.extendedregexp\") &&\n \t    git_config_bool(var, value)) {\n \t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n \t\treturn 0;\ndiff --git a/grep.h b/grep.h\nindex e4e548aed90..8ef70d125ff 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -94,8 +94,7 @@ enum grep_expr_node {\n };\n \n enum grep_pattern_type {\n-\tGREP_PATTERN_TYPE_UNSPECIFIED = 0,\n-\tGREP_PATTERN_TYPE_BRE,\n+\tGREP_PATTERN_TYPE_BRE = 0,\n \tGREP_PATTERN_TYPE_ERE,\n \tGREP_PATTERN_TYPE_FIXED,\n \tGREP_PATTERN_TYPE_PCRE\n@@ -179,7 +178,6 @@ struct grep_opt {\n \t.relative = 1, \\\n \t.pathname = 1, \\\n \t.max_depth = -1, \\\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n \t.colors = { \\\n \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n \t\t[GREP_COLOR_FILENAME] = \"\", \\\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex a59a9726357..afca938a4d0 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -461,7 +461,7 @@ do\n \t'\n \n \ttest_expect_success \"grep $L with grep.patternType=basic and grep.extendedRegexp=true\" '\n-\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\techo \"${HC}ab:abc\" >expected &&\n \t\tgit \\\n \t\t\t-c grep.patternType=basic \\\n \t\t\t-c grep.extendedRegexp=true \\\n-- \n2.34.0.rc1.741.gab7bfd97031\n\n"},{"id":"440804","messageId":"YYstK7qP5c7U6rn0@nand.local","threadId":"56853","inReplyTo":"cover-v2-0.8-00000000000-20211110T013632Z-avarab@gmail.com","subject":"Re: [PATCH v2 0/8] grep: simplify & delete code by changing obscure cfg variable behavior","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-11-10T02:23:39Z","receivedAt":"2021-11-10T02:23:44Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Wed, Nov 10, 2021 at 02:43:42AM +0100, Ævar Arnfjörð Bjarmason wrote:\n> For v1 and a more extensive summary see [1]. Thanks a lot Taylor for\n> the detailed review on v1!\n\nThanks. I'm going to put this version on my review backlog for now if\nyou don't mind, since I think it's more pertinent for us to focus on the\nupcoming release.\n\nBut I look forward to getting back to this once the release has\nstabilized a little bit.\n\n\nThanks,\nTaylor\n"},{"id":"440988","messageId":"xmqqilwxtkuv.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v2-1.8-1435db727ef-20211110T013632Z-avarab@gmail.com","subject":"Re: [PATCH v2 1/8] grep.h: remove unused \"regex_t regexp\" from grep_opt","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-12T16:11:20Z","receivedAt":"2021-11-12T16:11:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> This \"regex_t\" in grep_opt has not been used since\n> f9b9faf6f8a (builtin-grep: allow more than one patterns., 2006-05-02),\n> we still use a \"regex_t\" for compiling regexes, but that's in the\n> \"grep_pat\" struct\".\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  grep.h | 1 -\n>  1 file changed, 1 deletion(-)\n>\n> diff --git a/grep.h b/grep.h\n> index 3e8815c347b..95cccb670f9 100644\n> --- a/grep.h\n> +++ b/grep.h\n> @@ -136,7 +136,6 @@ struct grep_opt {\n>  \n>  \tconst char *prefix;\n>  \tint prefix_length;\n> -\tregex_t regexp;\n>  \tint linenum;\n>  \tint columnnum;\n>  \tint invert;\n\nI would have expected \"this used to be used but no longer; only\ninitialization of and assignment to it remain\"; I am somewhat\nsurprised to see there is no mention to it anywhere in the code ;-)\n\nGood find.  \n"},{"id":"440991","messageId":"xmqq7dddtjmd.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v2-2.8-63cf2fe266d-20211110T013632Z-avarab@gmail.com","subject":"Re: [PATCH v2 2/8] built-ins: trust the \"prefix\" from run_builtin()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-12T16:38:02Z","receivedAt":"2021-11-12T16:38:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\n> index 3a442631c71..84bed6d5612 100644\n> --- a/builtin/ls-tree.c\n> +++ b/builtin/ls-tree.c\n> @@ -147,16 +147,15 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n>  \t\tOPT__ABBREV(&abbrev),\n>  \t\tOPT_END()\n>  \t};\n> -\n> -\tgit_config(git_default_config, NULL);\n>  \tls_tree_prefix = prefix;\n\nSee below.\n\n> -\tif (prefix && *prefix)\n> +\tif (prefix)\n>  \t\tchomp_prefix = strlen(prefix);\n\nWe now assume a non-NULL prefix means a non-NUL *prefix, so this\nchange is understandable.\n\n> +\tgit_config(git_default_config, NULL);\n\nThis moving down of git_config() call is not.  A necessary change,\nor an unrelated churn?  If necessary, why?  By not checking if prefix[0]\nis NUL, we now need to delay reading the configuration, because ...?\n\n>  \targc = parse_options(argc, argv, prefix, ls_tree_options,\n>  \t\t\t     ls_tree_usage, 0);\n>  \tif (full_tree) {\n> -\t\tls_tree_prefix = prefix = NULL;\n> +\t\tls_tree_prefix = NULL;\n>  \t\tchomp_prefix = 0;\n>  \t}\n>  \t/* -d -r should imply -t, but -d by itself should not have to. */\n> @@ -178,7 +177,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n>  \tparse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &\n>  \t\t\t\t  ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n>  \t\t       PATHSPEC_PREFER_CWD,\n> -\t\t       prefix, argv + 1);\n> +\t\t       ls_tree_prefix, argv + 1);\n\nThe above two are unnecessary changes.\n\nIt was not like the introduction of ls_tree_prefix was made in order\nto get rid of \"prefix\" altogether.  We still have and use prefix,\nbut we have ls_tree_prefix to expose the value of it to other\nfunctions as a way to \"cheat\", without having to pass it through as\na parameter (and cheating is OK as its scope is limited to the file).\n\nPerhaps make a conscious effort to refrain from making such\nunnecessary changes, especially when working on a multi-patch\nseries, which may avoid wearing down reviewers?\n\n> diff --git a/git.c b/git.c\n> index 5ff21be21f3..611bf2f63eb 100644\n> --- a/git.c\n> +++ b/git.c\n> @@ -420,9 +420,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n>  {\n>  \tint status, help;\n>  \tstruct stat st;\n> -\tconst char *prefix;\n> +\tconst char *prefix = NULL;\n>  \n> -\tprefix = NULL;\n>  \thelp = argc == 2 && !strcmp(argv[1], \"-h\");\n>  \tif (!help) {\n>  \t\tif (p->option & RUN_SETUP)\n\nLikewise.  Little cuts accumulate.\n\n> @@ -431,6 +430,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n>  \t\t\tint nongit_ok;\n>  \t\t\tprefix = setup_git_directory_gently(&nongit_ok);\n>  \t\t}\n> +\t\tassert(!prefix || *prefix);\n\nGood.\n\n> diff --git a/grep.h b/grep.h\n> index 95cccb670f9..62deadb885f 100644\n> --- a/grep.h\n> +++ b/grep.h\n> @@ -134,8 +134,6 @@ struct grep_opt {\n>  \t */\n>  \tstruct repository *repo;\n>  \n> -\tconst char *prefix;\n> -\tint prefix_length;\n\nSo, builtin/grep.c is the only user of the low-level grep machinery\nthat needs to touch these two, and we can lose these members now\nthat builtin/grep.c relies on the file-scope global instead.  OK.\n\n> diff --git a/revision.c b/revision.c\n> index ab7c1358042..9f9b0d2429e 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -1833,7 +1833,7 @@ void repo_init_revisions(struct repository *r,\n>  \trevs->commit_format = CMIT_FMT_DEFAULT;\n>  \trevs->expand_tabs_in_log_default = 8;\n>  \n> -\tgrep_init(&revs->grep_filter, revs->repo, prefix);\n> +\tgrep_init(&revs->grep_filter, revs->repo);\n>  \trevs->grep_filter.status_only = 1;\n>  \n>  \trepo_diff_setup(revs->repo, &revs->diffopt);\n"},{"id":"440993","messageId":"xmqqsfw1s3lt.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v2-3.8-41e38ebb32c-20211110T013632Z-avarab@gmail.com","subject":"Re: [PATCH v2 3/8] log tests: check if grep_config() is called by \"log\"-like cmds","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-12T17:09:18Z","receivedAt":"2021-11-12T17:09:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Extend the tests added in my 9df46763ef1 (log: add exhaustive tests\n> for pattern style options & config, 2017-05-20) to check not only\n> whether \"git log\" handles \"grep.patternType\", but also \"git show\"\n> etc.\n>\n> It's sufficient to check whether a PCRE regex matches for the purposes\n> of this test, we otherwise assume that it's running the same code as\n> \"git log\", whose behavior is tested more exhaustively by test added in\n> 9df46763ef1e.\n\nI do agree with the reasoning that it is sufficient to check with\nonly one kind, but it is unclear if PCRE is so special and if so\nwhy.  Wouldn't testing with, say grep.patternType=extended, alone\nalso be sufficient?  The reason I am asking it is mostly because the\nabove description is insufficient to answer these questions, but\nalso because we can lose the prerequisite and gain a bit wider test\ncoverage, if we use a pattern that is not PCRE.\n\nKnowing that \"show\", \"whatchanged\", \"reflog\", and \"format-patch\" all\nshare the same backend in builtin/log.c, I am not sure how much\nvalue the new tests add.  Testing the \"--grep-reflog\" option and the\n\"git rev-list\" command may exercise a bit different code path,\nthough.\n\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t4202-log.sh | 16 ++++++++++++++++\n>  1 file changed, 16 insertions(+)\n>\n> diff --git a/t/t4202-log.sh b/t/t4202-log.sh\n> index 7884e3d46b3..a114c49ef27 100755\n> --- a/t/t4202-log.sh\n> +++ b/t/t4202-log.sh\n> @@ -449,6 +449,22 @@ test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurati\n>  \t)\n>  '\n>  \n> +for cmd in show whatchanged reflog format-patch\n> +do\n> +\tmyarg=\n> +\tif test \"$cmd\" = \"format-patch\"\n> +\tthen\n> +\t\tmyarg=\"HEAD~..\"\n> +\tfi\n\nI prefer to send the output that ought to contain the grep hits\nconsistently to \"actual\", i.e.\n\n\tcase \"$cmd\" in\n\tformat-patch) myarg=\"--stdout -1\" ;;\n\t*) myarg= ;;\n\tesac\t\n\ninstead of sending only the filenames.\n\nI also prefer \"case/esac\" as it would be more concise when we need\nto tweak myarg per command later.\n\n> +\ttest_expect_success PCRE \"$cmd: understands grep.patternType=perl, like 'log'\" '\n> +\t\tgit -c grep.patternType=fixed -C pattern-type $cmd --grep=\"1(?=\\|2)\" $myarg >actual &&\n> +\t\ttest_must_be_empty actual &&\n> +\t\tgit -c grep.patternType=perl -C pattern-type $cmd --grep=\"1(?=\\|2)\" $myarg >actual &&\n> +\t\ttest_file_not_empty actual\n> +\t'\n> +done\n> +\n>  test_expect_success 'log --author' '\n>  \tcat >expect <<-\\EOF &&\n>  \tAuthor: <BOLD;RED>A U<RESET> Thor <author@example.com>\n\nThanks.\n"},{"id":"440994","messageId":"xmqqo86ps3ao.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v2-4.8-efe95397d72-20211110T013632Z-avarab@gmail.com","subject":"Re: [PATCH v2 4/8] grep docs: de-duplicate configuration sections","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-12T17:15:59Z","receivedAt":"2021-11-12T17:16:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Include the \"config/grep.txt\" file in \"git-grep.txt\", instead of\n> repeating an almost identical description of the \"grep\" configuration\n> variables in two places. In a subsequent commit we'll amend this\n> documentation, and can now do so in one place instead of two.\n\nGood find.  They are indeed almost identical.  I am not sure about\nthe value of ...\n\n> +The below documentation is the same as what's found in\n> +linkgit:git-config[1]:\n\n... when everybody becomes consistent, but in the meantime, while\nsome documentation pages are consistent while others are not, I can\nsee how it might help.\n\nThe patch looks good.\n\nThanks.\n"},{"id":"440995","messageId":"xmqqk0hds36f.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v2-5.8-d0f0ac6c7ae-20211110T013632Z-avarab@gmail.com","subject":"Re: [PATCH v2 5/8] grep.c: don't pass along NULL callback value","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-12T17:18:32Z","receivedAt":"2021-11-12T17:18:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change grep_cmd_config() top stop passing around the always-NULL \"cb\"\n\n\"Change X top stop passing\"?  I cannot guess so I will not say \"I'll\nfix it to X, no need to resend\".\n\nThe change itself does seem sensible.\n\nThanks.\n\n> value. When this code was added in 7e8f59d577e (grep: color patterns\n> in output, 2009-03-07) it was non-NULL, but when that changed in\n> 15fabd1bbd4 (builtin/grep.c: make configuration callback more\n> reusable, 2012-10-09) this code was left behind.\n>\n> In a subsequent change I'll start using the \"cb\" value, this will make\n> it clear which functions we call need it, and which don't.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/grep.c | 4 ++--\n>  1 file changed, 2 insertions(+), 2 deletions(-)\n>\n> diff --git a/builtin/grep.c b/builtin/grep.c\n> index d85cbabea67..5ec4cecae45 100644\n> --- a/builtin/grep.c\n> +++ b/builtin/grep.c\n> @@ -285,8 +285,8 @@ static int wait_all(void)\n>  \n>  static int grep_cmd_config(const char *var, const char *value, void *cb)\n>  {\n> -\tint st = grep_config(var, value, cb);\n> -\tif (git_color_default_config(var, value, cb) < 0)\n> +\tint st = grep_config(var, value, NULL);\n> +\tif (git_color_default_config(var, value, NULL) < 0)\n>  \t\tst = -1;\n>  \n>  \tif (!strcmp(var, \"grep.threads\")) {\n"},{"id":"440996","messageId":"xmqq7ddds2id.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v2-6.8-917944f79a5-20211110T013632Z-avarab@gmail.com","subject":"Re: [PATCH v2 6/8] grep API: call grep_config() after grep_init()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-12T17:32:58Z","receivedAt":"2021-11-12T17:33:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> The grep_init() function used the odd pattern of initializing the\n> passed-in \"struct grep_opt\" with a statically defined \"grep_defaults\"\n> struct, which would be modified in-place when we invoked\n> grep_config().\n>\n> So we effectively (b) initialized config, (a) then defaults, (c)\n> followed by user options. Usually those are ordered as \"a\", \"b\" and\n> \"c\" instead.\n>\n> As the comments being removed here show the previous behavior needed\n> to be carefully explained as we'd potentially share the populated\n> configuration among different instances of grep_init(). In practice we\n> didn't do that, but now that it can't be a concern anymore let's\n> remove those comments.\n\nOK, so we did this because we wanted to be able to\n\n   1. call grep_config() only once to populate the template;\n\n   2. call grep_init() more than once, and match the grep_opt to\n      what the config wanted, without having to call grep_config()\n      once per grep_init() invocation.\n\n   3. each invocation of grep_init() in 2. may be followed by\n      parse_options() to further tweak grep_opt.\n\nAnd now we instead have to do\n\n   1. call grep_init()\n   2. call grep_config()\n   3. parse_options() to tweak\n\nfor each instance of grep_opt, which is much more common.\n\nOK.\n\n> diff --git a/builtin/log.c b/builtin/log.c\n> index f75d87e8d7f..bfddacdfa6c 100644\n> --- a/builtin/log.c\n> +++ b/builtin/log.c\n> @@ -505,8 +505,6 @@ static int git_log_config(const char *var, const char *value, void *cb)\n>  \t\treturn 0;\n>  \t}\n>  \n> -\tif (grep_config(var, value, cb) < 0)\n> -\t\treturn -1;\n\nThis used to tweak the \"default template\", which we no longer use,\nso can go?  And in its place ...\n\n>  \tif (git_gpg_config(var, value, cb) < 0)\n>  \t\treturn -1;\n>  \treturn git_diff_ui_config(var, value, cb);\n> @@ -521,6 +519,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n>  \tgit_config(git_log_config, NULL);\n>  \n>  \trepo_init_revisions(the_repository, &rev, prefix);\n> +\tgit_config(grep_config, &rev.grep_filter);\n> +\n\n... each command in the \"log\" family tweaks the grep_opt used for\nreal from the configuration.\n\n>  \trev.diff = 1;\n>  \trev.simplify_history = 0;\n>  \tmemset(&opt, 0, sizeof(opt));\n> @@ -635,6 +635,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n>  \n>  \tmemset(&match_all, 0, sizeof(match_all));\n>  \trepo_init_revisions(the_repository, &rev, prefix);\n> +\tgit_config(grep_config, &rev.grep_filter);\n> +\n\nDitto.  OK, the new pattern makes sense.\n\n> diff --git a/grep.h b/grep.h\n> index 62deadb885f..30a7dfd3294 100644\n> --- a/grep.h\n> +++ b/grep.h\n> @@ -171,12 +171,34 @@ struct grep_opt {\n>  \tint show_hunk_mark;\n>  \tint file_break;\n>  \tint heading;\n> +\tvoid *caller_priv;\n\nThis is unrelated and unexplained change, isn't it?\n\n>  \tvoid *priv;\n>  \n>  \tvoid (*output)(struct grep_opt *opt, const void *data, size_t size);\n>  \tvoid *output_priv;\n>  };\n>  \n> +#define GREP_OPT_INIT { \\\n> +\t.relative = 1, \\\n> +\t.pathname = 1, \\\n> +\t.max_depth = -1, \\\n> +\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n> +\t.colors = { \\\n> +\t\t[GREP_COLOR_CONTEXT] = \"\", \\\n> +\t\t[GREP_COLOR_FILENAME] = \"\", \\\n> +\t\t[GREP_COLOR_FUNCTION] = \"\", \\\n> +\t\t[GREP_COLOR_LINENO] = \"\", \\\n> +\t\t[GREP_COLOR_COLUMNNO] = \"\", \\\n> +\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, \\\n> +\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, \\\n> +\t\t[GREP_COLOR_SELECTED] = \"\", \\\n> +\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n> +\t}, \\\n> +\t.only_matching = 0, \\\n> +\t.color = -1, \\\n> +\t.output = std_output, \\\n> +}\n\nOther than the mysterious caller_priv bit, the change makes sense to\nme.\n\nThanks.\n"},{"id":"440999","messageId":"xmqqpmr5qj0f.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v2-7.8-140a7416223-20211110T013632Z-avarab@gmail.com","subject":"Re: [PATCH v2 7/8] grep: simplify config parsing, change grep.<rx config> interaction","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-12T19:19:28Z","receivedAt":"2021-11-12T19:19:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change the interaction between \"grep.patternType=default\" and\n> \"grep.extendedRegexp=true\" to make setting \"grep.extendedRegexp=true\"\n> synonymous with setting \"grep.patternType=extended\".\n\nThis description alone is not quite understandable.  It is not\nsaying much more than the single line title, and presense of it does\nnot seem to improve the understanding by the readers.\n\n> When \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\n> grep.patternType configuration setting, 2012-08-03) we made two\n> seemingly contradictory promises:\n>\n>  1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n>     will return to the default matching behavior\".\n>\n>  2. Support the existing \"grep.extendedRegexp\" option, but ignore it\n>     when the new \"grep.patternType\" is set, *except* \"when the\n>     `grep.patternType` option is set. to a value other than 'default'\".\n\nOK, so setting grep.patternType=default makes grep.extendedRegexp to\nbe taken into account.  By grep.patternType to something else, the\nother one is ignored.  2. is a very explicit way to say so.  Where\ndid you get 1. from?  If you have this paragraph in the log message\nin mind, I agree that it is less than ideally phrased, but ...\n\n    Rather than adding an additional setting for grep.fooRegexp for\n    current and future pattern matching options, add a\n    grep.patternType setting that can accept appropriate values for\n    modifying the default grep pattern matching behavior. The\n    current values are \"basic\", \"extended\", \"fixed\", \"perl\" and\n    \"default\" for setting -G, -E, -F, -P and the default behavior\n    respectively.\n\n... with the understanding of 2. (which is in what the commit adds\nto Documentation/config.txt), it is reasonable to understand that\n\"the default behaviour\" is \"use BRE or ERE, depending on the setting\nof grep.extendedRegexp\".\n\nDoesn't the code behave that way?  I think the above is exactly how\nthe commit wanted to make the code behave.\n\n> I think that 84befcd0a4a probably didn't intend this behavior, but\n> instead ended up conflating our internal \"unspecified\" state with a\n> user's explicit desire to set the configuration back to the\n> default.\n\nI am not sure where that comes from, but if I imagine somebody\nconfuses between \"default\" and \"basic\" and considers \"default\" a\nsynonym for \"basic\", I can sort-of understand it.  Is it what is\nhappening here?\n\nBut it is not what the original .patternType patch wanted to do back\nthen, and it is not what we want to see now.\n\n> I.e. a user would correctly expect this to keep working:\n>\n>     # ERE grep\n>     git -c grep.extendedRegexp=true grep <pattern>\n\nThis makes sense.\n\n> And likewise for \"grep.patternType=default\" to take precedence over\n> the disfavored \"grep.extendedRegexp\" option, i.e. the usual \"last set\n> wins\" semantics.\n>\n>     # BRE grep\n>     git -c grep.extendedRegexp=true -c grep.patternType=basic grep <pattern>\n\nThis makes sense, too.\n\nDo either of the above two not work as you expect (i.e. the first\nuse ERE and the second use BRE)?\n\nWhat I have trouble with is that it is unclear if you are describing\nwhat should happen (in the above, I said \"makes sense\", to show my\nagreement, assuming that it is the case), or if you are describing\nwhat does happen that you disagree with. \n\nAnother thing I have trouble with is your mention of \"keep working\".\nAre you proposing to deliberately break what is working as users\ncorrectly expect?  Why?\n\n> But probably not for this to ignore the favored \"grep.patternType\"\n> option entirely, say if /etc/gitconfig was still setting\n> \"grep.extendedRegexp\", but \"~/.gitconfig\" used the new\n> \"grep.patternType\" (and wanted to use the \"default\" value):\n>\n>     # Was ERE, now BRE\n>     git -c grep.extendedRegexp=true grep.patternType=default grep <pattern>\n\nI do not quite get your \"Was X, now Y\" label.  What did you want to\nsay with that?\n\nAlso I am not sure what you exactly mean when you say \"and wanted to\nuse the 'default' value\".  There is no single \"THE\" default value.\nIf patternType=default is the last patterntype (it may be set in\nmany places, but the last one should win), the user is telling that\nthe last-one-wins setting of extendedRegexp is to be honored.  So,\nif grep.extendedRegexp in /etc/gitconfig is the last one defined, we\nwould choose between BRE and ERE depending on that setting.\n\nIsn't that what is happening in the current code?\n\nOr are all the above explanation result of simple misunderstanding\nthat setting to \"default\" means setting to \"basic\"?\n\n"},{"id":"441000","messageId":"xmqqk0hdqifg.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v2-8.8-cc904d93b26-20211110T013632Z-avarab@gmail.com","subject":"Re: [PATCH v2 8/8] grep: make \"extendedRegexp=true\" the same as \"patternType=extended\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-12T19:32:03Z","receivedAt":"2021-11-12T19:32:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> In the preceding commit we changed how a \"grep.patternType=default\"\n> set after \"grep.extendedRegexp=true\" would be handled so that the last\n> set would win, but a \"grep.extendedRegexp=true\" would only be used if\n> \"grep.patternType\" was set to a value other than \"default\".\n\nI am getting the feeling that my suspicion about your confusion in\n7/8 is right.\n\nThe grep.patternType=default was merely a backward compatibility\nmeasure for those who were used to grep.extendedRegexp=true/false\nway of doing things, and \"default\" never meant to mean \"basic\".  It\nmerely was an instruction to \"honor the old extendedRegexp variable\nfor this old timer\".  The intention all along was that patternType\nwas a more flexible single true way to set the type to supersede\nextendedRegexp but we couldn't discontinue the support for the\nlatter all of a sudden, and the \"default\" was invented as the\ntransition mechanism, but it ended up as the mechanism to choose\neither new (setting patternType to some other value) or old\n(patternType is set to default, making the value given to\nextendedRegexp is the only thing that matters) world to live in.\n\nIf you want to change anything in this area, the right thing to do\nis rather to _deprecate_ extendedRegexp and eventually remove\nextendedRegexp together with the \"default\" setting to patternType, I\nwould think, not to change the semantics of extendedRegexp in any\nway.\n\nThanks.\n"},{"id":"441063","messageId":"211113.86lf1stlw3.gmgdl@evledraar.gmail.com","threadId":"56853","inReplyTo":"xmqqpmr5qj0f.fsf@gitster.g","subject":"Re: [PATCH v2 7/8] grep: simplify config parsing, change grep.<rx config> interaction","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-13T09:55:04Z","receivedAt":"2021-11-13T10:01:21Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Nov 12 2021, Junio C Hamano wrote:\n\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n> [...]\n\nI'll try to reply to all the rest of the feedback, just really quick on\nthis, because I think it might represent a bit of a gordian knot.\n\n> Another thing I have trouble with is your mention of \"keep working\".\n> Are you proposing to deliberately break what is working as users\n> correctly expect?  Why?\n\nYes, I'd like to change the behavior, because it makes the grep API much\neasier to deal with, and beacuse I think it impacts nobody in practice.\n\nThe real goal for this series is that I've got pending patches to\nspeedup diffcore-pickaxe massively by moving it over to PCRE & drop the\nkwset.c code. An old perf test I dug up for that is in [1].\n\nTo do that I needed to re-use the bits of grep.c machinery that deal\nwith setting up patterns, dealing with BRE,ERE,PCRE etc. elsewhere.\n\nI *can* do that in a different way, but it's going to be much easier if\nwe can gradually evolve the already working grep API to become an\ninternal textual pattern matching API. Eventually I'd like to move all\nof regcomp()/regexec() over to such a thing, because we can for any\nother ranodm thing we use regexes for get speedups by using PCRE (and\noptionally use its interface to understand BRE/ERE syntax).\n\nThe alternative is to split that part off from grep.c, which is a bit\nmore painful, or to have the init bits etc. take some \"no config doesn't\ngo first\", \"no it goes first\" flags just to support this one API user.\n\nSo it would be generally useful to know if you're at all open to\nthat. Reading between the lines in some other comments I fear that it\nmay be a \"no\" except if we mark it as deprecated, wait some years, maybe\nremove/change it then etc.\n\n1.\n\n    GIT_TEST_LONG= GIT_PERF_REPEAT_COUNT=10 GIT_PERF_MAKE_OPTS='-j8 USE_LIBPCRE=1 CFLAGS=-O3 LIBPCREDIR=/home/avar/g/pcre2/inst' ./run origin/next HEAD -- p4209-pickaxe.sh\n    Test                                                                      origin/next       HEAD\n    ------------------------------------------------------------------------------------------------------------------\n    4209.1: git log -S'int main' <limit-rev>..                                0.38(0.36+0.01)   0.37(0.33+0.04) -2.6%\n    4209.2: git log -S'æ' <limit-rev>..                                       0.51(0.47+0.04)   0.32(0.27+0.05) -37.3%\n    4209.3: git log --pickaxe-regex -S'(int|void|null)' <limit-rev>..         0.72(0.68+0.03)   0.57(0.54+0.03) -20.8%\n    4209.4: git log --pickaxe-regex -S'if *\\([^ ]+ & ' <limit-rev>..          0.60(0.55+0.02)   0.39(0.34+0.05) -35.0%\n    4209.5: git log --pickaxe-regex -S'[àáâãäåæñøùúûüýþ]' <limit-rev>..       0.43(0.40+0.03)   0.50(0.44+0.06) +16.3%\n    4209.6: git log -G'(int|void|null)' <limit-rev>..                         0.64(0.55+0.09)   0.63(0.56+0.05) -1.6%\n    4209.7: git log -G'if *\\([^ ]+ & ' <limit-rev>..                          0.64(0.59+0.05)   0.63(0.56+0.06) -1.6%\n    4209.8: git log -G'[àáâãäåæñøùúûüýþ]' <limit-rev>..                       0.63(0.54+0.08)   0.62(0.55+0.06) -1.6%\n    4209.9: git log -i -S'int main' <limit-rev>..                             0.39(0.35+0.03)   0.38(0.35+0.02) -2.6%\n    4209.10: git log -i -S'æ' <limit-rev>..                                   0.39(0.33+0.06)   0.32(0.28+0.04) -17.9%\n    4209.11: git log -i --pickaxe-regex -S'(int|void|null)' <limit-rev>..     0.90(0.84+0.05)   0.58(0.53+0.04) -35.6%\n    4209.12: git log -i --pickaxe-regex -S'if *\\([^ ]+ & ' <limit-rev>..      0.71(0.64+0.06)   0.40(0.37+0.03) -43.7%\n    4209.13: git log -i --pickaxe-regex -S'[àáâãäåæñøùúûüýþ]' <limit-rev>..   0.43(0.40+0.03)   0.50(0.46+0.04) +16.3%\n    4209.14: git log -i -G'(int|void|null)' <limit-rev>..                     0.64(0.57+0.06)   0.62(0.56+0.05) -3.1%\n    4209.15: git log -i -G'if *\\([^ ]+ & ' <limit-rev>..                      0.65(0.59+0.06)   0.63(0.54+0.08) -3.1%\n    4209.16: git log -i -G'[àáâãäåæñøùúûüýþ]' <limit-rev>..                   0.63(0.55+0.08)   0.62(0.56+0.05) -1.6%\n"},{"id":"442457","messageId":"cover-v3-0.7-00000000000-20211129T143956Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v2-0.8-00000000000-20211110T013632Z-avarab@gmail.com","subject":"[PATCH v3 0/7] grep: simplify & delete \"init\" & \"config\" code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-29T14:50:46Z","receivedAt":"2021-11-29T18:27:32Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"In v1 and v2[1] of this series more code in grep.c was deleted by\nchanging what I think is a really obscure interaction between\n\"grep.extendedRegexp=true\" and \"grep.patternType\".\n\nJunio preferred having a deprecation period[2], so here's a re-roll\nthat preserves all existing behavior, at the cost of bit less code\ndeletion & simplification (from \"97 insertions(+), 174 deletions(-)\"\nto \"106 insertions(+), 131 deletions(-)\").\n\nNotes on individual patches below. This re-roll should address all\noutstanding feedback on v2.\n\n1. https://lore.kernel.org/git/cover-v2-0.8-00000000000-20211110T013632Z-avarab@gmail.com/\n2. https://lore.kernel.org/git/xmqqk0hdqifg.fsf@gitster.g/\n\nÆvar Arnfjörð Bjarmason (7):\n  grep.h: remove unused \"regex_t regexp\" from grep_opt\n\nNo change.\n\n  log tests: check if grep_config() is called by \"log\"-like cmds\n\nSimplified the test, and it no longer depends (optionally) PCRE. We\njust test BRE v.s. ERE instead.\n\n  grep tests: add missing \"grep.patternType\" config test\n\nA new test to assert existing behavior, we had a blindspot in this\narea (could have hidden a possible regression).\n\n  built-ins: trust the \"prefix\" from run_builtin()\n\nSubstantially the same, but I made some edits as requested to minimize\nthe diff size / skip any cleanups-while-at it.\n\n  grep.c: don't pass along NULL callback value\n\nTrivial commit message typo fix.\n\n  grep API: call grep_config() after grep_init()\n\nRemoved stray leftover WIP code (an unused \"caller_priv\" struct\nmember), oops.\n\n  grep: simplify config parsing and option parsing\n\nMostly new, replaces the now-ejected two last commits of v2 that\nchanged obscure behavior. We still delete most of the code involved in\nthis part of grep initialization and config handling, but now with no\nchanges in existing behavior.\n\nThis is now also ejected:\n\n  grep docs: de-duplicate configuration sections\n  (https://lore.kernel.org/git/patch-v2-4.8-efe95397d72-20211110T013632Z-avarab@gmail.com/)\n\nSince I don't need to change any documentation anymore, moving around\nthe grep docs to live in one place isn't within the scope of this\nseries.\n\n builtin/grep.c    |  27 +++++-----\n builtin/log.c     |  13 ++++-\n builtin/ls-tree.c |   2 +-\n git.c             |   1 +\n grep.c            | 124 ++++++++--------------------------------------\n grep.h            |  33 ++++++++----\n revision.c        |   4 +-\n t/t4202-log.sh    |  24 +++++++++\n t/t7810-grep.sh   |   9 ++++\n 9 files changed, 106 insertions(+), 131 deletions(-)\n\nRange-diff against v2:\n1:  1435db727ef = 1:  71ff51cb3c9 grep.h: remove unused \"regex_t regexp\" from grep_opt\n3:  41e38ebb32c ! 2:  ec8e42ced1a log tests: check if grep_config() is called by \"log\"-like cmds\n    @@ Commit message\n         whether \"git log\" handles \"grep.patternType\", but also \"git show\"\n         etc.\n     \n    -    It's sufficient to check whether a PCRE regex matches for the purposes\n    -    of this test, we otherwise assume that it's running the same code as\n    -    \"git log\", whose behavior is tested more exhaustively by test added in\n    -    9df46763ef1e.\n    +    It's sufficient to check whether we match a \"fixed\" or a \"basic\" regex\n    +    here to see if these codepaths correctly invoked grep_config(). We\n    +    don't need to check the details of their regular expression matching\n    +    as the \"log\" test does.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    @@ t/t4202-log.sh: test_expect_success !FAIL_PREREQS 'log with various grep.pattern\n      \n     +for cmd in show whatchanged reflog format-patch\n     +do\n    -+\tmyarg=\n    -+\tif test \"$cmd\" = \"format-patch\"\n    -+\tthen\n    -+\t\tmyarg=\"HEAD~..\"\n    -+\tfi\n    ++\tcase \"$cmd\" in\n    ++\tformat-patch) myarg=\"HEAD~..\" ;;\n    ++\t*) myarg= ;;\n    ++\tesac\n     +\n    -+\ttest_expect_success PCRE \"$cmd: understands grep.patternType=perl, like 'log'\" '\n    -+\t\tgit -c grep.patternType=fixed -C pattern-type $cmd --grep=\"1(?=\\|2)\" $myarg >actual &&\n    -+\t\ttest_must_be_empty actual &&\n    -+\t\tgit -c grep.patternType=perl -C pattern-type $cmd --grep=\"1(?=\\|2)\" $myarg >actual &&\n    -+\t\ttest_file_not_empty actual\n    ++\ttest_expect_success \"$cmd: understands grep.patternType, like 'log'\" '\n    ++\t\tgit init \"pattern-type-$cmd\" &&\n    ++\t\t(\n    ++\t\t\tcd \"pattern-type-$cmd\" &&\n    ++\t\t\ttest_commit 1 file A &&\n    ++\t\t\ttest_commit \"(1|2)\" file B 2 &&\n    ++\n    ++\t\t\tgit -c grep.patternType=fixed $cmd --grep=\"...\" $myarg >actual &&\n    ++\t\t\ttest_must_be_empty actual &&\n    ++\n    ++\t\t\tgit -c grep.patternType=basic $cmd --grep=\"...\" $myarg >actual &&\n    ++\t\t\ttest_file_not_empty actual\n    ++\t\t)\n     +\t'\n     +done\n    ++test_done\n     +\n      test_expect_success 'log --author' '\n      \tcat >expect <<-\\EOF &&\n8:  cc904d93b26 ! 3:  fcad1b1664b grep: make \"extendedRegexp=true\" the same as \"patternType=extended\"\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    grep: make \"extendedRegexp=true\" the same as \"patternType=extended\"\n    +    grep tests: add missing \"grep.patternType\" config test\n     \n    -    In the preceding commit we changed how a \"grep.patternType=default\"\n    -    set after \"grep.extendedRegexp=true\" would be handled so that the last\n    -    set would win, but a \"grep.extendedRegexp=true\" would only be used if\n    -    \"grep.patternType\" was set to a value other than \"default\".\n    -\n    -    Thus a user who had old config and set \"grep.extendedRegexp=true\" in\n    -    their ~/.gitconfig expecting ERE behavior would be opted-in to say\n    -    \"perl\" regexes if a system \"/etc/gitconfig\" started setting\n    -    \"grep.patternType=perl\".\n    -\n    -    These funny semantics of only paying attention to a set if another key\n    -    is not set to a given value aren't how we treat other config keys, so\n    -    let's do away with this caveat for consistency.\n    -\n    -    The new semantics are simple, a \"grep.extendedRegexp=true\" is an exact\n    -    synonym for specifying \"grep.patternType=extended\" in the\n    -    config. We'll keep ignoring \"\"grep.extendedRegexp=false\", although\n    -    arguably we could treat it as a \"grep.patternType=basic\".\n    -\n    -    As argued in the preceding commit I think this behavior came about\n    -    because we were conflating the state of our code's own internal\n    -    \"default\" value with what we found in explicit user config. See\n    -    84befcd0a4a (grep: add a grep.patternType configuration setting,\n    -    2012-08-03) for that past behavior.\n    -\n    -    Let's further change the documentation to note that\n    -    \"grep.extendedRegexp\" is a deprecated synonym, perhaps we'll be able\n    -    to remove it at some point in the future and do away with this\n    -    special-case entirely.\n    +    Extend the grep tests to assert that setting\n    +    \"grep.patternType=extended\" followed by \"grep.patternType=default\"\n    +    will behave as if \"--extended-regexp\" was provided, and not as\n    +    \"--basic-regexp\". In a subsequent commit we'll need to treat\n    +    \"grep.patternType=default\" as a special-case, but let's make sure we\n    +    don't ignore it if \"grep.patternType\" was set to a non-\"default\" value\n    +    before.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    - ## Documentation/config/grep.txt ##\n    -@@ Documentation/config/grep.txt: grep.patternType::\n    - \tvalue 'default' will return to the default matching behavior.\n    - \n    - grep.extendedRegexp::\n    --\tIf set to true, enable `--extended-regexp` option by default. This\n    --\toption is ignored when the `grep.patternType` option is set.\n    -+\tDeprecated synonym for 'grep.patternType=extended`.\n    - \n    - grep.threads::\n    - \tNumber of grep worker threads to use. If unset (or set to 0), Git will\n    -\n    - ## grep.c ##\n    -@@ grep.c: static const char *color_grep_slots[] = {\n    - \n    - static int parse_pattern_type_arg(const char *opt, const char *arg)\n    - {\n    --\tif (!strcmp(arg, \"default\"))\n    --\t\treturn GREP_PATTERN_TYPE_UNSPECIFIED;\n    --\telse if (!strcmp(arg, \"basic\"))\n    -+\tif (!strcmp(arg, \"basic\") ||\n    -+\t    !strcmp(arg, \"default\"))\n    - \t\treturn GREP_PATTERN_TYPE_BRE;\n    - \telse if (!strcmp(arg, \"extended\"))\n    - \t\treturn GREP_PATTERN_TYPE_ERE;\n    -@@ grep.c: int grep_config(const char *var, const char *value, void *cb)\n    - \tif (userdiff_config(var, value) < 0)\n    - \t\treturn -1;\n    - \n    --\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_UNSPECIFIED &&\n    --\t    !strcmp(var, \"grep.extendedregexp\") &&\n    -+\tif (!strcmp(var, \"grep.extendedregexp\") &&\n    - \t    git_config_bool(var, value)) {\n    - \t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n    - \t\treturn 0;\n    -\n    - ## grep.h ##\n    -@@ grep.h: enum grep_expr_node {\n    - };\n    - \n    - enum grep_pattern_type {\n    --\tGREP_PATTERN_TYPE_UNSPECIFIED = 0,\n    --\tGREP_PATTERN_TYPE_BRE,\n    -+\tGREP_PATTERN_TYPE_BRE = 0,\n    - \tGREP_PATTERN_TYPE_ERE,\n    - \tGREP_PATTERN_TYPE_FIXED,\n    - \tGREP_PATTERN_TYPE_PCRE\n    -@@ grep.h: struct grep_opt {\n    - \t.relative = 1, \\\n    - \t.pathname = 1, \\\n    - \t.max_depth = -1, \\\n    --\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n    - \t.colors = { \\\n    - \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n    - \t\t[GREP_COLOR_FILENAME] = \"\", \\\n    -\n      ## t/t7810-grep.sh ##\n     @@ t/t7810-grep.sh: do\n    + \t\ttest_cmp expected actual\n      \t'\n      \n    - \ttest_expect_success \"grep $L with grep.patternType=basic and grep.extendedRegexp=true\" '\n    --\t\techo \"${HC}ab:a+bc\" >expected &&\n    -+\t\techo \"${HC}ab:abc\" >expected &&\n    ++\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n    ++\t\techo \"${HC}ab:a+bc\" >expected &&\n    ++\t\tgit \\\n    ++\t\t\t-c grep.patternType=extended \\\n    ++\t\t\t-c grep.patternType=default \\\n    ++\t\t\tgrep \"a+b*c\" $H ab >actual &&\n    ++\t\ttest_cmp expected actual\n    ++\t'\n    ++\n    + \ttest_expect_success \"grep $L with grep.patternType=extended and grep.extendedRegexp=false\" '\n    + \t\techo \"${HC}ab:abc\" >expected &&\n      \t\tgit \\\n    - \t\t\t-c grep.patternType=basic \\\n    - \t\t\t-c grep.extendedRegexp=true \\\n2:  63cf2fe266d ! 4:  854ffe8d0b9 built-ins: trust the \"prefix\" from run_builtin()\n    @@ builtin/grep.c: int cmd_grep(int argc, const char **argv, const char *prefix)\n     \n      ## builtin/ls-tree.c ##\n     @@ builtin/ls-tree.c: int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n    - \t\tOPT__ABBREV(&abbrev),\n    - \t\tOPT_END()\n    - \t};\n    --\n    --\tgit_config(git_default_config, NULL);\n    + \n    + \tgit_config(git_default_config, NULL);\n      \tls_tree_prefix = prefix;\n     -\tif (prefix && *prefix)\n     +\tif (prefix)\n      \t\tchomp_prefix = strlen(prefix);\n      \n    -+\tgit_config(git_default_config, NULL);\n      \targc = parse_options(argc, argv, prefix, ls_tree_options,\n    - \t\t\t     ls_tree_usage, 0);\n    - \tif (full_tree) {\n    --\t\tls_tree_prefix = prefix = NULL;\n    -+\t\tls_tree_prefix = NULL;\n    - \t\tchomp_prefix = 0;\n    - \t}\n    - \t/* -d -r should imply -t, but -d by itself should not have to. */\n    -@@ builtin/ls-tree.c: int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n    - \tparse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &\n    - \t\t\t\t  ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),\n    - \t\t       PATHSPEC_PREFER_CWD,\n    --\t\t       prefix, argv + 1);\n    -+\t\t       ls_tree_prefix, argv + 1);\n    - \tfor (i = 0; i < pathspec.nr; i++)\n    - \t\tpathspec.items[i].nowildcard_len = pathspec.items[i].len;\n    - \tpathspec.has_wildcard = 0;\n     \n      ## git.c ##\n    -@@ git.c: static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n    - {\n    - \tint status, help;\n    - \tstruct stat st;\n    --\tconst char *prefix;\n    -+\tconst char *prefix = NULL;\n    - \n    --\tprefix = NULL;\n    - \thelp = argc == 2 && !strcmp(argv[1], \"-h\");\n    - \tif (!help) {\n    - \t\tif (p->option & RUN_SETUP)\n     @@ git.c: static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n      \t\t\tint nongit_ok;\n      \t\t\tprefix = setup_git_directory_gently(&nongit_ok);\n4:  efe95397d72 < -:  ----------- grep docs: de-duplicate configuration sections\n5:  d0f0ac6c7ae ! 5:  2536eae2c32 grep.c: don't pass along NULL callback value\n    @@ Metadata\n      ## Commit message ##\n         grep.c: don't pass along NULL callback value\n     \n    -    Change grep_cmd_config() top stop passing around the always-NULL \"cb\"\n    +    Change grep_cmd_config() to stop passing around the always-NULL \"cb\"\n         value. When this code was added in 7e8f59d577e (grep: color patterns\n         in output, 2009-03-07) it was non-NULL, but when that changed in\n         15fabd1bbd4 (builtin/grep.c: make configuration callback more\n6:  917944f79a5 ! 6:  4e1be7c165b grep API: call grep_config() after grep_init()\n    @@ grep.c: int grep_config(const char *var, const char *value, void *cb)\n     \n      ## grep.h ##\n     @@ grep.h: struct grep_opt {\n    - \tint show_hunk_mark;\n    - \tint file_break;\n    - \tint heading;\n    -+\tvoid *caller_priv;\n    - \tvoid *priv;\n    - \n    - \tvoid (*output)(struct grep_opt *opt, const void *data, size_t size);\n      \tvoid *output_priv;\n      };\n      \n7:  140a7416223 ! 7:  f40ab932cb1 grep: simplify config parsing, change grep.<rx config> interaction\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    grep: simplify config parsing, change grep.<rx config> interaction\n    +    grep: simplify config parsing and option parsing\n     \n    -    Change the interaction between \"grep.patternType=default\" and\n    -    \"grep.extendedRegexp=true\" to make setting \"grep.extendedRegexp=true\"\n    -    synonymous with setting \"grep.patternType=extended\".\n    -\n    -    This changes our existing config parsing behavior as detailed below,\n    -    but in a way that's consistent with how we parse other\n    -    configuration.\n    -\n    -    We are breaking past promises here, but I doubt that this will impact\n    -    anyone in practice. The reduction in complexity and resulting\n    -    consistency with other default config behavior is worth it.\n    +    Simplify the parsing of \"grep.patternType\" and\n    +    \"grep.extendedRegexp\". This changes no behavior, but gets rid of\n    +    complex parsing logic that isn't needed anymore.\n     \n         When \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\n    -    grep.patternType configuration setting, 2012-08-03) we made two\n    -    seemingly contradictory promises:\n    +    grep.patternType configuration setting, 2012-08-03) we promised that:\n     \n          1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n             will return to the default matching behavior\".\n     \n    -     2. Support the existing \"grep.extendedRegexp\" option, but ignore it\n    -        when the new \"grep.patternType\" is set, *except* \"when the\n    -        `grep.patternType` option is set. to a value other than 'default'\".\n    -\n    -    I think that 84befcd0a4a probably didn't intend this behavior, but\n    -    instead ended up conflating our internal \"unspecified\" state with a\n    -    user's explicit desire to set the configuration back to the\n    -    default.\n    -\n    -    I.e. a user would correctly expect this to keep working:\n    -\n    -        # ERE grep\n    -        git -c grep.extendedRegexp=true grep <pattern>\n    -\n    -    And likewise for \"grep.patternType=default\" to take precedence over\n    -    the disfavored \"grep.extendedRegexp\" option, i.e. the usual \"last set\n    -    wins\" semantics.\n    +     2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n    +        it when the new \"grep.patternType\" option is set. We said we'd\n    +        only ignore the older \"grep.extendedRegexp\" option \"when the\n    +        `grep.patternType` option is set. to a value other than\n    +        'default'\".\n     \n    -        # BRE grep\n    -        git -c grep.extendedRegexp=true -c grep.patternType=basic grep <pattern>\n    +    In a preceding commit we changed grep_config() to be called after\n    +    grep_init(), which means that much of the complexity here can go\n    +    away.\n     \n    -    But probably not for this to ignore the favored \"grep.patternType\"\n    -    option entirely, say if /etc/gitconfig was still setting\n    -    \"grep.extendedRegexp\", but \"~/.gitconfig\" used the new\n    -    \"grep.patternType\" (and wanted to use the \"default\" value):\n    -\n    -        # Was ERE, now BRE\n    -        git -c grep.extendedRegexp=true grep.patternType=default grep <pattern>\n    -\n    -    I think that in practice nobody or almost nobody is going to be\n    -    relying on this obscure interaction, and as shown here it makes the\n    -    config parsing much simpler. We no longer have to carry a complex\n    -    state machine in \"grep_commit_pattern_type()\" and\n    -    \"grep_set_pattern_type_option()\".\n    -\n    -    We can also do away with the \"int fixed\" and \"int pcre2\" members in\n    -    favor of using \"pattern_type_option\" directly in \"grep.c\", as well as\n    -    dropping the \"pattern_type_arg\" variable in \"builtin/grep.c\" in favor\n    -    of using the \"pattern_type_option\" member directly.\n    +    Now as before when we only understand a \"grep.extendedRegexp\" setting\n    +    of \"true\", and if \"grep.patterntype=default\" is set we'll interpret it\n    +    as \"grep.patterntype=basic\", except if we previously saw a\n    +    \"grep.extendedRegexp\", then it's interpreted as\n    +    \"grep.patterntype=extended\".\n     \n         See my 07a3d411739 (grep: remove regflags from the public grep_opt\n         API, 2017-06-29) for addition of the two comments being removed here,\n         i.e. the complexity noted in that commit is now going away.\n     \n    -    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n    +    We don't need grep_commit_pattern_type() anymore, we can instead have\n    +    OPT_SET_INT() in \"builtin/grep.c\" manipulate the \"pattern_type_option\"\n    +    member in \"struct grep_opt\" directly.\n     \n    - ## Documentation/config/grep.txt ##\n    -@@ Documentation/config/grep.txt: grep.patternType::\n    - \n    - grep.extendedRegexp::\n    - \tIf set to true, enable `--extended-regexp` option by default. This\n    --\toption is ignored when the `grep.patternType` option is set to a value\n    --\tother than 'default'.\n    -+\toption is ignored when the `grep.patternType` option is set.\n    - \n    - grep.threads::\n    - \tNumber of grep worker threads to use. If unset (or set to 0), Git will\n    +    We can also do away with the indirection of the \"int fixed\" and \"int\n    +    pcre2\" members in favor of using \"pattern_type_option\" directly in\n    +    \"grep.c\".\n    +\n    +    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/grep.c ##\n     @@ builtin/grep.c: int cmd_grep(int argc, const char **argv, const char *prefix)\n    @@ builtin/grep.c: int cmd_grep(int argc, const char **argv, const char *prefix)\n      \t\tint fallback = 0;\n     \n      ## grep.c ##\n    +@@ grep.c: static const char *color_grep_slots[] = {\n    + \n    + static int parse_pattern_type_arg(const char *opt, const char *arg)\n    + {\n    +-\tif (!strcmp(arg, \"default\"))\n    +-\t\treturn GREP_PATTERN_TYPE_UNSPECIFIED;\n    +-\telse if (!strcmp(arg, \"basic\"))\n    ++\tif (!strcmp(arg, \"basic\"))\n    + \t\treturn GREP_PATTERN_TYPE_BRE;\n    + \telse if (!strcmp(arg, \"extended\"))\n    + \t\treturn GREP_PATTERN_TYPE_ERE;\n     @@ grep.c: int grep_config(const char *var, const char *value, void *cb)\n    - \tif (userdiff_config(var, value) < 0)\n      \t\treturn -1;\n      \n    --\tif (!strcmp(var, \"grep.extendedregexp\")) {\n    --\t\topt->extended_regexp_option = git_config_bool(var, value);\n    -+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_UNSPECIFIED &&\n    -+\t    !strcmp(var, \"grep.extendedregexp\") &&\n    -+\t    git_config_bool(var, value)) {\n    -+\t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n    + \tif (!strcmp(var, \"grep.extendedregexp\")) {\n    ++\t\tif (opt->extended_regexp_option)\n    ++\t\t\treturn 0;\n    + \t\topt->extended_regexp_option = git_config_bool(var, value);\n    ++\t\tif (opt->extended_regexp_option)\n    ++\t\t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n    ++\t\treturn 0;\n    ++\t}\n    ++\n    ++\tif (!strcmp(var, \"grep.patterntype\") &&\n    ++\t    !strcmp(value, \"default\")) {\n    ++\t\topt->pattern_type_option = opt->extended_regexp_option == 1\n    ++\t\t\t? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n      \t\treturn 0;\n      \t}\n      \n    + \tif (!strcmp(var, \"grep.patterntype\")) {\n    ++\t\topt->extended_regexp_option = -1; /* ignore */\n    + \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n    + \t\treturn 0;\n    + \t}\n     @@ grep.c: void grep_init(struct grep_opt *opt, struct repository *repo)\n      \topt->header_tail = &opt->header_list;\n      }\n    @@ grep.c: static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n      \tif (err) {\n     \n      ## grep.h ##\n    +@@ grep.h: enum grep_expr_node {\n    + };\n    + \n    + enum grep_pattern_type {\n    +-\tGREP_PATTERN_TYPE_UNSPECIFIED = 0,\n    +-\tGREP_PATTERN_TYPE_BRE,\n    ++\tGREP_PATTERN_TYPE_BRE = 0,\n    + \tGREP_PATTERN_TYPE_ERE,\n    + \tGREP_PATTERN_TYPE_FIXED,\n    + \tGREP_PATTERN_TYPE_PCRE\n     @@ grep.h: struct grep_opt {\n      \tint unmatch_name_only;\n      \tint count;\n    @@ grep.h: struct grep_opt {\n      \tint pathname;\n      \tint null_following_name;\n     @@ grep.h: struct grep_opt {\n    - \tint max_depth;\n      \tint funcname;\n      \tint funcbody;\n    --\tint extended_regexp_option;\n    + \tint extended_regexp_option;\n     -\tint pattern_type_option;\n     +\tenum grep_pattern_type pattern_type_option;\n      \tint ignore_locale;\n      \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n      \tunsigned pre_context;\n     @@ grep.h: struct grep_opt {\n    + \t.relative = 1, \\\n    + \t.pathname = 1, \\\n    + \t.max_depth = -1, \\\n    +-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n    + \t.colors = { \\\n    + \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n    + \t\t[GREP_COLOR_FILENAME] = \"\", \\\n    +@@ grep.h: struct grep_opt {\n      \n      int grep_config(const char *var, const char *value, void *);\n      void grep_init(struct grep_opt *, struct repository *repo);\n    @@ revision.c: int setup_revisions(int argc, const char **argv, struct rev_info *re\n      \tif (!is_encoding_utf8(get_log_output_encoding()))\n      \t\trevs->grep_filter.ignore_locale = 1;\n      \tcompile_grep_patterns(&revs->grep_filter);\n    -\n    - ## t/t7810-grep.sh ##\n    -@@ t/t7810-grep.sh: do\n    - \t'\n    - \n    - \ttest_expect_success \"grep $L with grep.extendedRegexp=true and grep.patternType=default\" '\n    --\t\techo \"${HC}ab:abc\" >expected &&\n    -+\t\techo \"${HC}ab:a+bc\" >expected &&\n    - \t\tgit \\\n    - \t\t\t-c grep.extendedRegexp=true \\\n    - \t\t\t-c grep.patternType=default \\\n-- \n2.34.1.841.gf15fb7e6f34\n\n"},{"id":"442458","messageId":"patch-v3-1.7-71ff51cb3c9-20211129T143956Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v3-0.7-00000000000-20211129T143956Z-avarab@gmail.com","subject":"[PATCH v3 1/7] grep.h: remove unused \"regex_t regexp\" from grep_opt","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-29T14:50:47Z","receivedAt":"2021-11-29T18:27:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This \"regex_t\" in grep_opt has not been used since\nf9b9faf6f8a (builtin-grep: allow more than one patterns., 2006-05-02),\nwe still use a \"regex_t\" for compiling regexes, but that's in the\n\"grep_pat\" struct\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 3e8815c347b..95cccb670f9 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -136,7 +136,6 @@ struct grep_opt {\n \n \tconst char *prefix;\n \tint prefix_length;\n-\tregex_t regexp;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n-- \n2.34.1.841.gf15fb7e6f34\n\n"},{"id":"442459","messageId":"patch-v3-2.7-ec8e42ced1a-20211129T143956Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v3-0.7-00000000000-20211129T143956Z-avarab@gmail.com","subject":"[PATCH v3 2/7] log tests: check if grep_config() is called by \"log\"-like cmds","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-29T14:50:48Z","receivedAt":"2021-11-29T18:27:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the tests added in my 9df46763ef1 (log: add exhaustive tests\nfor pattern style options & config, 2017-05-20) to check not only\nwhether \"git log\" handles \"grep.patternType\", but also \"git show\"\netc.\n\nIt's sufficient to check whether we match a \"fixed\" or a \"basic\" regex\nhere to see if these codepaths correctly invoked grep_config(). We\ndon't need to check the details of their regular expression matching\nas the \"log\" test does.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4202-log.sh | 24 ++++++++++++++++++++++++\n 1 file changed, 24 insertions(+)\n\ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex 7884e3d46b3..11bb25440b0 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -449,6 +449,30 @@ test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurati\n \t)\n '\n \n+for cmd in show whatchanged reflog format-patch\n+do\n+\tcase \"$cmd\" in\n+\tformat-patch) myarg=\"HEAD~..\" ;;\n+\t*) myarg= ;;\n+\tesac\n+\n+\ttest_expect_success \"$cmd: understands grep.patternType, like 'log'\" '\n+\t\tgit init \"pattern-type-$cmd\" &&\n+\t\t(\n+\t\t\tcd \"pattern-type-$cmd\" &&\n+\t\t\ttest_commit 1 file A &&\n+\t\t\ttest_commit \"(1|2)\" file B 2 &&\n+\n+\t\t\tgit -c grep.patternType=fixed $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_must_be_empty actual &&\n+\n+\t\t\tgit -c grep.patternType=basic $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_file_not_empty actual\n+\t\t)\n+\t'\n+done\n+test_done\n+\n test_expect_success 'log --author' '\n \tcat >expect <<-\\EOF &&\n \tAuthor: <BOLD;RED>A U<RESET> Thor <author@example.com>\n-- \n2.34.1.841.gf15fb7e6f34\n\n"},{"id":"442460","messageId":"patch-v3-4.7-854ffe8d0b9-20211129T143956Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v3-0.7-00000000000-20211129T143956Z-avarab@gmail.com","subject":"[PATCH v3 4/7] built-ins: trust the \"prefix\" from run_builtin()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-29T14:50:50Z","receivedAt":"2021-11-29T18:27:56Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in \"builtin/grep.c\" and \"builtin/ls-tree.c\" to trust the\n\"prefix\" passed from \"run_builtin()\". The \"prefix\" we get from setup.c\nis either going to be NULL or a string of length >0, never \"\".\n\nSo we can drop the \"prefix && *prefix\" checks added for\n\"builtin/grep.c\" in 0d042fecf2f (git-grep: show pathnames relative to\nthe current directory, 2006-08-11), and for \"builtin/ls-tree.c\" in\na69dd585fca (ls-tree: chomp leading directories when run from a\nsubdirectory, 2005-12-23).\n\nAs seen in code in revision.c that was added in cd676a51367 (diff\n--relative: output paths as relative to the current subdirectory,\n2008-02-12) we already have existing code that does away with this\nassertion.\n\nThis makes it easier to reason about a subsequent change to the\n\"prefix_length\" code in grep.c in a subsequent commit, and since we're\ngoing to the trouble of doing that let's leave behind an assert() to\npromise this to any future callers.\n\nFor \"builtin/grep.c\" it would be painful to pass the \"prefix\" down the\ncallchain of:\n\n    cmd_grep -> grep_tree -> grep_submodule -> grep_cache -> grep_oid ->\n    grep_source_name\n\nSo for the code that needs it in grep_source_name() let's add a\n\"grep_prefix\" variable similar to the existing \"ls_tree_prefix\".\n\nWhile at it let's move the code in cmd_ls_tree() around so that we\nassign to the \"ls_tree_prefix\" right after declaring the variables,\nand stop assigning to \"prefix\". We only subsequently used that\nvariable later in the function after clobbering it. Let's just use our\nown \"grep_prefix\" instead.\n\nLet's also add an assert() in git.c, so that we'll make this promise\nabout the \"prefix\" to any current and future callers, as well as to\nany readers of the code.\n\nCode history:\n\n * The strlen() in \"grep.c\" hasn't been used since 493b7a08d80 (grep:\n   accept relative paths outside current working directory, 2009-09-05).\n\n   When that code was added in 0d042fecf2f (git-grep: show pathnames\n   relative to the current directory, 2006-08-11) we used the length.\n\n   But since 493b7a08d80 we haven't used it for anything except a\n   boolean check that we could have done on the \"prefix\" member\n   itself.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c    | 13 ++++++++-----\n builtin/ls-tree.c |  2 +-\n git.c             |  1 +\n grep.c            |  4 +---\n grep.h            |  4 +---\n revision.c        |  2 +-\n 6 files changed, 13 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 9e34a820ad4..d85cbabea67 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -26,6 +26,8 @@\n #include \"object-store.h\"\n #include \"packfile.h\"\n \n+static const char *grep_prefix;\n+\n static char const * const grep_usage[] = {\n \tN_(\"git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]\"),\n \tNULL\n@@ -315,11 +317,11 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \tstrbuf_reset(out);\n \n \tif (opt->null_following_name) {\n-\t\tif (opt->relative && opt->prefix_length) {\n+\t\tif (opt->relative && grep_prefix) {\n \t\t\tstruct strbuf rel_buf = STRBUF_INIT;\n \t\t\tconst char *rel_name =\n \t\t\t\trelative_path(filename + tree_name_len,\n-\t\t\t\t\t      opt->prefix, &rel_buf);\n+\t\t\t\t\t      grep_prefix, &rel_buf);\n \n \t\t\tif (tree_name_len)\n \t\t\t\tstrbuf_add(out, filename, tree_name_len);\n@@ -332,8 +334,8 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \t\treturn;\n \t}\n \n-\tif (opt->relative && opt->prefix_length)\n-\t\tquote_path(filename + tree_name_len, opt->prefix, out, 0);\n+\tif (opt->relative && grep_prefix)\n+\t\tquote_path(filename + tree_name_len, grep_prefix, out, 0);\n \telse\n \t\tquote_c_style(filename + tree_name_len, out, NULL, 0);\n \n@@ -962,9 +964,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\t   PARSE_OPT_NOCOMPLETE),\n \t\tOPT_END()\n \t};\n+\tgrep_prefix = prefix;\n \n \tgit_config(grep_cmd_config, NULL);\n-\tgrep_init(&opt, the_repository, prefix);\n+\tgrep_init(&opt, the_repository);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 3a442631c71..6cb554cbb0a 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -150,7 +150,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \n \tgit_config(git_default_config, NULL);\n \tls_tree_prefix = prefix;\n-\tif (prefix && *prefix)\n+\tif (prefix)\n \t\tchomp_prefix = strlen(prefix);\n \n \targc = parse_options(argc, argv, prefix, ls_tree_options,\ndiff --git a/git.c b/git.c\nindex 5ff21be21f3..6cf48adeb1f 100644\n--- a/git.c\n+++ b/git.c\n@@ -431,6 +431,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t\t\tint nongit_ok;\n \t\t\tprefix = setup_git_directory_gently(&nongit_ok);\n \t\t}\n+\t\tassert(!prefix || *prefix);\n \t\tprecompose_argv_prefix(argc, argv, NULL);\n \t\tif (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY) &&\n \t\t    !(p->option & DELAY_PAGER_CONFIG))\ndiff --git a/grep.c b/grep.c\nindex fe847a0111a..12b202598a9 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -139,13 +139,11 @@ int grep_config(const char *var, const char *value, void *cb)\n  * default values from the template we read the configuration\n  * information in an earlier call to git_config(grep_config).\n  */\n-void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)\n+void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n \t*opt = grep_defaults;\n \n \topt->repo = repo;\n-\topt->prefix = prefix;\n-\topt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;\n \topt->pattern_tail = &opt->pattern_list;\n \topt->header_tail = &opt->header_list;\n }\ndiff --git a/grep.h b/grep.h\nindex 95cccb670f9..62deadb885f 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -134,8 +134,6 @@ struct grep_opt {\n \t */\n \tstruct repository *repo;\n \n-\tconst char *prefix;\n-\tint prefix_length;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n@@ -180,7 +178,7 @@ struct grep_opt {\n };\n \n int grep_config(const char *var, const char *value, void *);\n-void grep_init(struct grep_opt *, struct repository *repo, const char *prefix);\n+void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex 1981a0859f0..a82e31df869 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1833,7 +1833,7 @@ void repo_init_revisions(struct repository *r,\n \trevs->commit_format = CMIT_FMT_DEFAULT;\n \trevs->expand_tabs_in_log_default = 8;\n \n-\tgrep_init(&revs->grep_filter, revs->repo, prefix);\n+\tgrep_init(&revs->grep_filter, revs->repo);\n \trevs->grep_filter.status_only = 1;\n \n \trepo_diff_setup(revs->repo, &revs->diffopt);\n-- \n2.34.1.841.gf15fb7e6f34\n\n"},{"id":"442461","messageId":"patch-v3-3.7-fcad1b1664b-20211129T143956Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v3-0.7-00000000000-20211129T143956Z-avarab@gmail.com","subject":"[PATCH v3 3/7] grep tests: add missing \"grep.patternType\" config test","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-29T14:50:49Z","receivedAt":"2021-11-29T18:28:15Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the grep tests to assert that setting\n\"grep.patternType=extended\" followed by \"grep.patternType=default\"\nwill behave as if \"--extended-regexp\" was provided, and not as\n\"--basic-regexp\". In a subsequent commit we'll need to treat\n\"grep.patternType=default\" as a special-case, but let's make sure we\ndon't ignore it if \"grep.patternType\" was set to a non-\"default\" value\nbefore.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7810-grep.sh | 9 +++++++++\n 1 file changed, 9 insertions(+)\n\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 6b6423a07c3..724b1bbbc1c 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -451,6 +451,15 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.patternType=extended and grep.extendedRegexp=false\" '\n \t\techo \"${HC}ab:abc\" >expected &&\n \t\tgit \\\n-- \n2.34.1.841.gf15fb7e6f34\n\n"},{"id":"442462","messageId":"patch-v3-6.7-4e1be7c165b-20211129T143956Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v3-0.7-00000000000-20211129T143956Z-avarab@gmail.com","subject":"[PATCH v3 6/7] grep API: call grep_config() after grep_init()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-29T14:50:52Z","receivedAt":"2021-11-29T18:28:20Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The grep_init() function used the odd pattern of initializing the\npassed-in \"struct grep_opt\" with a statically defined \"grep_defaults\"\nstruct, which would be modified in-place when we invoked\ngrep_config().\n\nSo we effectively (b) initialized config, (a) then defaults, (c)\nfollowed by user options. Usually those are ordered as \"a\", \"b\" and\n\"c\" instead.\n\nAs the comments being removed here show the previous behavior needed\nto be carefully explained as we'd potentially share the populated\nconfiguration among different instances of grep_init(). In practice we\ndidn't do that, but now that it can't be a concern anymore let's\nremove those comments.\n\nThis does not change the behavior of any of the configuration\nvariables or options. That would have been the case if we didn't move\naround the grep_config() call in \"builtin/log.c\". But now that we call\n\"grep_config\" after \"git_log_config\" and \"git_format_config\" we'll\nneed to pass in the already initialized \"struct grep_opt *\".\n\nSee 6ba9bb76e02 (grep: copy struct in one fell swoop, 2020-11-29) and\n7687a0541e0 (grep: move the configuration parsing logic to grep.[ch],\n2012-10-09) for the commits that added the comments.\n\nThe memcpy() pattern here will be optimized away and follows the\nconvention of other *_init() functions. See 5726a6b4012 (*.c *_init():\ndefine in terms of corresponding *_INIT macro, 2021-07-01).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c |  4 ++--\n builtin/log.c  | 13 +++++++++++--\n grep.c         | 39 +++------------------------------------\n grep.h         | 21 +++++++++++++++++++++\n 4 files changed, 37 insertions(+), 40 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5ec4cecae45..0ea124321b6 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,7 +285,7 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, NULL);\n+\tint st = grep_config(var, value, cb);\n \tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n@@ -966,8 +966,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t};\n \tgrep_prefix = prefix;\n \n-\tgit_config(grep_cmd_config, NULL);\n \tgrep_init(&opt, the_repository);\n+\tgit_config(grep_cmd_config, &opt);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/log.c b/builtin/log.c\nindex f75d87e8d7f..bfddacdfa6c 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -505,8 +505,6 @@ static int git_log_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n-\tif (grep_config(var, value, cb) < 0)\n-\t\treturn -1;\n \tif (git_gpg_config(var, value, cb) < 0)\n \t\treturn -1;\n \treturn git_diff_ui_config(var, value, cb);\n@@ -521,6 +519,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.simplify_history = 0;\n \tmemset(&opt, 0, sizeof(opt));\n@@ -635,6 +635,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \n \tmemset(&match_all, 0, sizeof(match_all));\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.always_show_header = 1;\n \trev.no_walk = 1;\n@@ -718,6 +720,8 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n \tinit_reflog_walk(&rev.reflog_info);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.verbose_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -751,6 +755,8 @@ int cmd_log(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.always_show_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -1833,10 +1839,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \textra_hdr.strdup_strings = 1;\n \textra_to.strdup_strings = 1;\n \textra_cc.strdup_strings = 1;\n+\n \tinit_log_defaults();\n \tinit_display_notes(&notes_opt);\n \tgit_config(git_format_config, NULL);\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.show_notes = show_notes;\n \tmemcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));\n \trev.commit_format = CMIT_FMT_EMAIL;\ndiff --git a/grep.c b/grep.c\nindex 12b202598a9..8dfa0300786 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -19,27 +19,6 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)\n \tfwrite(buf, size, 1, stdout);\n }\n \n-static struct grep_opt grep_defaults = {\n-\t.relative = 1,\n-\t.pathname = 1,\n-\t.max_depth = -1,\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t.colors = {\n-\t\t[GREP_COLOR_CONTEXT] = \"\",\n-\t\t[GREP_COLOR_FILENAME] = \"\",\n-\t\t[GREP_COLOR_FUNCTION] = \"\",\n-\t\t[GREP_COLOR_LINENO] = \"\",\n-\t\t[GREP_COLOR_COLUMNNO] = \"\",\n-\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_SELECTED] = \"\",\n-\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN,\n-\t},\n-\t.only_matching = 0,\n-\t.color = -1,\n-\t.output = std_output,\n-};\n-\n static const char *color_grep_slots[] = {\n \t[GREP_COLOR_CONTEXT]\t    = \"context\",\n \t[GREP_COLOR_FILENAME]\t    = \"filename\",\n@@ -75,20 +54,12 @@ define_list_config_array_extra(color_grep_slots, {\"match\"});\n  */\n int grep_config(const char *var, const char *value, void *cb)\n {\n-\tstruct grep_opt *opt = &grep_defaults;\n+\tstruct grep_opt *opt = cb;\n \tconst char *slot;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\t/*\n-\t * The instance of grep_opt that we set up here is copied by\n-\t * grep_init() to be used by each individual invocation.\n-\t * When populating a new field of this structure here, be\n-\t * sure to think about ownership -- e.g., you might need to\n-\t * override the shallow copy in grep_init() with a deep copy.\n-\t */\n-\n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n \t\treturn 0;\n@@ -134,14 +105,10 @@ int grep_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/*\n- * Initialize one instance of grep_opt and copy the\n- * default values from the template we read the configuration\n- * information in an earlier call to git_config(grep_config).\n- */\n void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n-\t*opt = grep_defaults;\n+\tstruct grep_opt blank = GREP_OPT_INIT;\n+\tmemcpy(opt, &blank, sizeof(*opt));\n \n \topt->repo = repo;\n \topt->pattern_tail = &opt->pattern_list;\ndiff --git a/grep.h b/grep.h\nindex 62deadb885f..b651eb291f7 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -177,6 +177,27 @@ struct grep_opt {\n \tvoid *output_priv;\n };\n \n+#define GREP_OPT_INIT { \\\n+\t.relative = 1, \\\n+\t.pathname = 1, \\\n+\t.max_depth = -1, \\\n+\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n+\t.colors = { \\\n+\t\t[GREP_COLOR_CONTEXT] = \"\", \\\n+\t\t[GREP_COLOR_FILENAME] = \"\", \\\n+\t\t[GREP_COLOR_FUNCTION] = \"\", \\\n+\t\t[GREP_COLOR_LINENO] = \"\", \\\n+\t\t[GREP_COLOR_COLUMNNO] = \"\", \\\n+\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_SELECTED] = \"\", \\\n+\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n+\t}, \\\n+\t.only_matching = 0, \\\n+\t.color = -1, \\\n+\t.output = std_output, \\\n+}\n+\n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n-- \n2.34.1.841.gf15fb7e6f34\n\n"},{"id":"442463","messageId":"patch-v3-5.7-2536eae2c32-20211129T143956Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v3-0.7-00000000000-20211129T143956Z-avarab@gmail.com","subject":"[PATCH v3 5/7] grep.c: don't pass along NULL callback value","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-29T14:50:51Z","receivedAt":"2021-11-29T18:28:22Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change grep_cmd_config() to stop passing around the always-NULL \"cb\"\nvalue. When this code was added in 7e8f59d577e (grep: color patterns\nin output, 2009-03-07) it was non-NULL, but when that changed in\n15fabd1bbd4 (builtin/grep.c: make configuration callback more\nreusable, 2012-10-09) this code was left behind.\n\nIn a subsequent change I'll start using the \"cb\" value, this will make\nit clear which functions we call need it, and which don't.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex d85cbabea67..5ec4cecae45 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,8 +285,8 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, cb);\n-\tif (git_color_default_config(var, value, cb) < 0)\n+\tint st = grep_config(var, value, NULL);\n+\tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n \tif (!strcmp(var, \"grep.threads\")) {\n-- \n2.34.1.841.gf15fb7e6f34\n\n"},{"id":"442464","messageId":"patch-v3-7.7-f40ab932cb1-20211129T143956Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v3-0.7-00000000000-20211129T143956Z-avarab@gmail.com","subject":"[PATCH v3 7/7] grep: simplify config parsing and option parsing","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-11-29T14:50:53Z","receivedAt":"2021-11-29T18:28:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Simplify the parsing of \"grep.patternType\" and\n\"grep.extendedRegexp\". This changes no behavior, but gets rid of\ncomplex parsing logic that isn't needed anymore.\n\nWhen \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\ngrep.patternType configuration setting, 2012-08-03) we promised that:\n\n 1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n    will return to the default matching behavior\".\n\n 2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n    it when the new \"grep.patternType\" option is set. We said we'd\n    only ignore the older \"grep.extendedRegexp\" option \"when the\n    `grep.patternType` option is set. to a value other than\n    'default'\".\n\nIn a preceding commit we changed grep_config() to be called after\ngrep_init(), which means that much of the complexity here can go\naway.\n\nNow as before when we only understand a \"grep.extendedRegexp\" setting\nof \"true\", and if \"grep.patterntype=default\" is set we'll interpret it\nas \"grep.patterntype=basic\", except if we previously saw a\n\"grep.extendedRegexp\", then it's interpreted as\n\"grep.patterntype=extended\".\n\nSee my 07a3d411739 (grep: remove regflags from the public grep_opt\nAPI, 2017-06-29) for addition of the two comments being removed here,\ni.e. the complexity noted in that commit is now going away.\n\nWe don't need grep_commit_pattern_type() anymore, we can instead have\nOPT_SET_INT() in \"builtin/grep.c\" manipulate the \"pattern_type_option\"\nmember in \"struct grep_opt\" directly.\n\nWe can also do away with the indirection of the \"int fixed\" and \"int\npcre2\" members in favor of using \"pattern_type_option\" directly in\n\"grep.c\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 10 +++----\n grep.c         | 81 +++++++++++---------------------------------------\n grep.h         |  9 ++----\n revision.c     |  2 --\n 4 files changed, 24 insertions(+), 78 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 0ea124321b6..942c4b25077 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -845,7 +845,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tint i;\n \tint dummy;\n \tint use_index = 1;\n-\tint pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;\n \tint allow_revs;\n \n \tstruct option options[] = {\n@@ -879,16 +878,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"descend at most <depth> levels\"), PARSE_OPT_NONEG,\n \t\t\tNULL, 1 },\n \t\tOPT_GROUP(\"\"),\n-\t\tOPT_SET_INT('E', \"extended-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('E', \"extended-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use extended POSIX regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_ERE),\n-\t\tOPT_SET_INT('G', \"basic-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('G', \"basic-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use basic POSIX regular expressions (default)\"),\n \t\t\t    GREP_PATTERN_TYPE_BRE),\n-\t\tOPT_SET_INT('F', \"fixed-strings\", &pattern_type_arg,\n+\t\tOPT_SET_INT('F', \"fixed-strings\", &opt.pattern_type_option,\n \t\t\t    N_(\"interpret patterns as fixed strings\"),\n \t\t\t    GREP_PATTERN_TYPE_FIXED),\n-\t\tOPT_SET_INT('P', \"perl-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('P', \"perl-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use Perl-compatible regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_PCRE),\n \t\tOPT_GROUP(\"\"),\n@@ -982,7 +981,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, grep_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH |\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n-\tgrep_commit_pattern_type(pattern_type_arg, &opt);\n \n \tif (use_index && !startup_info->have_repository) {\n \t\tint fallback = 0;\ndiff --git a/grep.c b/grep.c\nindex 8dfa0300786..b5342064066 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -33,9 +33,7 @@ static const char *color_grep_slots[] = {\n \n static int parse_pattern_type_arg(const char *opt, const char *arg)\n {\n-\tif (!strcmp(arg, \"default\"))\n-\t\treturn GREP_PATTERN_TYPE_UNSPECIFIED;\n-\telse if (!strcmp(arg, \"basic\"))\n+\tif (!strcmp(arg, \"basic\"))\n \t\treturn GREP_PATTERN_TYPE_BRE;\n \telse if (!strcmp(arg, \"extended\"))\n \t\treturn GREP_PATTERN_TYPE_ERE;\n@@ -61,11 +59,23 @@ int grep_config(const char *var, const char *value, void *cb)\n \t\treturn -1;\n \n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n+\t\tif (opt->extended_regexp_option)\n+\t\t\treturn 0;\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n+\t\tif (opt->extended_regexp_option)\n+\t\t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n+\t\treturn 0;\n+\t}\n+\n+\tif (!strcmp(var, \"grep.patterntype\") &&\n+\t    !strcmp(value, \"default\")) {\n+\t\topt->pattern_type_option = opt->extended_regexp_option == 1\n+\t\t\t? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(var, \"grep.patterntype\")) {\n+\t\topt->extended_regexp_option = -1; /* ignore */\n \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n \t\treturn 0;\n \t}\n@@ -115,62 +125,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo)\n \topt->header_tail = &opt->header_list;\n }\n \n-static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\t/*\n-\t * When committing to the pattern type by setting the relevant\n-\t * fields in grep_opt it's generally not necessary to zero out\n-\t * the fields we're not choosing, since they won't have been\n-\t * set by anything. The extended_regexp_option field is the\n-\t * only exception to this.\n-\t *\n-\t * This is because in the process of parsing grep.patternType\n-\t * & grep.extendedRegexp we set opt->pattern_type_option and\n-\t * opt->extended_regexp_option, respectively. We then\n-\t * internally use opt->extended_regexp_option to see if we're\n-\t * compiling an ERE. It must be unset if that's not actually\n-\t * the case.\n-\t */\n-\tif (pattern_type != GREP_PATTERN_TYPE_ERE &&\n-\t    opt->extended_regexp_option)\n-\t\topt->extended_regexp_option = 0;\n-\n-\tswitch (pattern_type) {\n-\tcase GREP_PATTERN_TYPE_UNSPECIFIED:\n-\t\t/* fall through */\n-\n-\tcase GREP_PATTERN_TYPE_BRE:\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_ERE:\n-\t\topt->extended_regexp_option = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_FIXED:\n-\t\topt->fixed = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_PCRE:\n-\t\topt->pcre2 = 1;\n-\t\tbreak;\n-\t}\n-}\n-\n-void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\tif (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(pattern_type, opt);\n-\telse if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(opt->pattern_type_option, opt);\n-\telse if (opt->extended_regexp_option)\n-\t\t/*\n-\t\t * This branch *must* happen after setting from the\n-\t\t * opt->pattern_type_option above, we don't want\n-\t\t * grep.extendedRegexp to override grep.patternType!\n-\t\t */\n-\t\tgrep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);\n-}\n-\n static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,\n \t\t\t\t\tconst char *origin, int no,\n \t\t\t\t\tenum grep_pat_token t,\n@@ -490,9 +444,10 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \n \tp->word_regexp = opt->word_regexp;\n \tp->ignore_case = opt->ignore_case;\n-\tp->fixed = opt->fixed;\n+\tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\n \n-\tif (memchr(p->pattern, 0, p->patternlen) && !opt->pcre2)\n+\tif (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE &&\n+\t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n \tp->is_fixed = is_fixed(p->pattern, p->patternlen);\n@@ -543,14 +498,14 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \t\treturn;\n \t}\n \n-\tif (opt->pcre2) {\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_PCRE) {\n \t\tcompile_pcre2_pattern(p, opt);\n \t\treturn;\n \t}\n \n \tif (p->ignore_case)\n \t\tregflags |= REG_ICASE;\n-\tif (opt->extended_regexp_option)\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_ERE)\n \t\tregflags |= REG_EXTENDED;\n \terr = regcomp(&p->regexp, p->pattern, regflags);\n \tif (err) {\ndiff --git a/grep.h b/grep.h\nindex b651eb291f7..ab2ce833b40 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -94,8 +94,7 @@ enum grep_expr_node {\n };\n \n enum grep_pattern_type {\n-\tGREP_PATTERN_TYPE_UNSPECIFIED = 0,\n-\tGREP_PATTERN_TYPE_BRE,\n+\tGREP_PATTERN_TYPE_BRE = 0,\n \tGREP_PATTERN_TYPE_ERE,\n \tGREP_PATTERN_TYPE_FIXED,\n \tGREP_PATTERN_TYPE_PCRE\n@@ -143,7 +142,6 @@ struct grep_opt {\n \tint unmatch_name_only;\n \tint count;\n \tint word_regexp;\n-\tint fixed;\n \tint all_match;\n #define GREP_BINARY_DEFAULT\t0\n #define GREP_BINARY_NOMATCH\t1\n@@ -152,7 +150,6 @@ struct grep_opt {\n \tint allow_textconv;\n \tint extended;\n \tint use_reflog_filter;\n-\tint pcre2;\n \tint relative;\n \tint pathname;\n \tint null_following_name;\n@@ -162,7 +159,7 @@ struct grep_opt {\n \tint funcname;\n \tint funcbody;\n \tint extended_regexp_option;\n-\tint pattern_type_option;\n+\tenum grep_pattern_type pattern_type_option;\n \tint ignore_locale;\n \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n \tunsigned pre_context;\n@@ -181,7 +178,6 @@ struct grep_opt {\n \t.relative = 1, \\\n \t.pathname = 1, \\\n \t.max_depth = -1, \\\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n \t.colors = { \\\n \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n \t\t[GREP_COLOR_FILENAME] = \"\", \\\n@@ -200,7 +196,6 @@ struct grep_opt {\n \n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n-void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\n void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex a82e31df869..d08c7ae6c35 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2855,8 +2855,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \n \tdiff_setup_done(&revs->diffopt);\n \n-\tgrep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t\t\t\t &revs->grep_filter);\n \tif (!is_encoding_utf8(get_log_output_encoding()))\n \t\trevs->grep_filter.ignore_locale = 1;\n \tcompile_grep_patterns(&revs->grep_filter);\n-- \n2.34.1.841.gf15fb7e6f34\n\n"},{"id":"442491","messageId":"xmqqk0gq6592.fsf@gitster.g","threadId":"56853","inReplyTo":"cover-v3-0.7-00000000000-20211129T143956Z-avarab@gmail.com","subject":"Re: [PATCH v3 0/7] grep: simplify & delete \"init\" & \"config\" code","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-29T21:06:49Z","receivedAt":"2021-11-29T21:08:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> In v1 and v2[1] of this series more code in grep.c was deleted by\n> changing what I think is a really obscure interaction between\n> \"grep.extendedRegexp=true\" and \"grep.patternType\".\n>\n> Junio preferred having a deprecation period[2], so here's a re-roll\n> that preserves all existing behavior, at the cost of bit less code\n> deletion & simplification (from \"97 insertions(+), 174 deletions(-)\"\n> to \"106 insertions(+), 131 deletions(-)\").\n\nDeprecating grep.extendedRegexp and forcing users to only use the\ngrep.patterntype would be a lot more sensible way forward than\ngiving it a new meaning and letting these two variables interact\nwith each other.\n\nDepending on how cleanly the internal code can become, with the\nformer variable still supported for backward compatibility, we might\nnot need to break working set-up existing end-users have, though.\n\nWe'll see.\n\nThanks.\n"},{"id":"442494","messageId":"xmqqfsre63w8.fsf@gitster.g","threadId":"56853","inReplyTo":"cover-v3-0.7-00000000000-20211129T143956Z-avarab@gmail.com","subject":"Re: [PATCH v3 0/7] grep: simplify & delete \"init\" & \"config\" code","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-29T21:36:07Z","receivedAt":"2021-11-29T21:38:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n>   log tests: check if grep_config() is called by \"log\"-like cmds\n>\n> Simplified the test, and it no longer depends (optionally) PCRE. We\n> just test BRE v.s. ERE instead.\n\nHmph.  I see tests between fixed vs basic, though.\n\n"},{"id":"442498","messageId":"xmqqbl22634q.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v3-3.7-fcad1b1664b-20211129T143956Z-avarab@gmail.com","subject":"Re: [PATCH v3 3/7] grep tests: add missing \"grep.patternType\" config test","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-11-29T21:52:37Z","receivedAt":"2021-11-29T21:54:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Extend the grep tests to assert that setting\n> \"grep.patternType=extended\" followed by \"grep.patternType=default\"\n> will behave as if \"--extended-regexp\" was provided, and not as\n> \"--basic-regexp\".\n\ngrep.patternType is the usual \"last-one wins\".  If the last value\nset to patternType is the default, the setting to grep.extendedRegexp\nshould take effect (so if it is set to true, we'd see ERE behavour).\n\nBack in the days when the \"return to the default matching behavior\"\npart was written in 84befcd0 (grep: add a grep.patternType\nconfiguration setting, 2012-08-03), grep.extendedRegexp was the only\nway to configure the behaviour since b22520a3 (grep: allow -E and -n\nto be turned on by default via configuration, 2011-03-30).  It was\nunderstandable that we referred to the behaviour that honors the\nolder configuration variable as \"the default matching\" behaviour.\nIt is fairly clear in its log message:\n\n    When grep.patternType is set to a value other than \"default\", the\n    grep.extendedRegexp setting is ignored. The value of \"default\" restores\n    the current default behavior, including the grep.extendedRegexp\n    behavior.\n\nSo, unless your description is a typo, I am somewhat surprised by\nyour findings that =default that comes later does not defeat an\nearlier =extended.\n\nIt should just clear that earlier extended set by grep.patternType\nand only pay attention to grep.extendedRegexp variable.  Doing\nanything else is a bug, I think.\n\nThanks.\n\ndiff --git i/Documentation/config/grep.txt w/Documentation/config/grep.txt\nindex 44abe45a7c..95fcb3ca29 100644\n--- i/Documentation/config/grep.txt\n+++ w/Documentation/config/grep.txt\n@@ -8,7 +8,8 @@ grep.patternType::\n \tSet the default matching behavior. Using a value of 'basic', 'extended',\n \t'fixed', or 'perl' will enable the `--basic-regexp`, `--extended-regexp`,\n \t`--fixed-strings`, or `--perl-regexp` option accordingly, while the\n-\tvalue 'default' will return to the default matching behavior.\n+\tvalue 'default' will return to the default matching behavior, which is,\n+\tto honor `grep.extendedRegexp` option and choose either basic or extended.\n \n grep.extendedRegexp::\n \tIf set to true, enable `--extended-regexp` option by default. This\n\n"},{"id":"442926","messageId":"xmqqk0gmtswe.fsf@gitster.g","threadId":"56853","inReplyTo":"xmqqbl22634q.fsf@gitster.g","subject":"Re: [PATCH v3 3/7] grep tests: add missing \"grep.patternType\" config test","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-12-03T00:48:49Z","receivedAt":"2021-12-03T00:49:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> Extend the grep tests to assert that setting\n>> \"grep.patternType=extended\" followed by \"grep.patternType=default\"\n>> will behave as if \"--extended-regexp\" was provided, and not as\n>> \"--basic-regexp\".\n>\n> grep.patternType is the usual \"last-one wins\".  If the last value\n> set to patternType is the default, the setting to grep.extendedRegexp\n> should take effect (so if it is set to true, we'd see ERE behavour).\n>\n> Back in the days when the \"return to the default matching behavior\"\n> part was written in 84befcd0 (grep: add a grep.patternType\n> configuration setting, 2012-08-03), grep.extendedRegexp was the only\n> way to configure the behaviour since b22520a3 (grep: allow -E and -n\n> to be turned on by default via configuration, 2011-03-30).  It was\n> understandable that we referred to the behaviour that honors the\n> older configuration variable as \"the default matching\" behaviour.\n> It is fairly clear in its log message:\n>\n>     When grep.patternType is set to a value other than \"default\", the\n>     grep.extendedRegexp setting is ignored. The value of \"default\" restores\n>     the current default behavior, including the grep.extendedRegexp\n>     behavior.\n>\n> So, unless your description is a typo, I am somewhat surprised by\n> your findings that =default that comes later does not defeat an\n> earlier =extended.\n>\n> It should just clear that earlier extended set by grep.patternType\n> and only pay attention to grep.extendedRegexp variable.  Doing\n> anything else is a bug, I think.\n\nSo, let's see how \n\n  $ git -c grep.patternType=extended \\\n\t-c grep.patternType=default \\\n\tgrep foo\n\nworks today.\n\nWe start from builtin/grep.c::cmd_grep(), which calls\ngit_config(grep_cmd_config).  grep_cmd_config() farms out most of\nthe work to grep.c::grep_config(), which populates the grep_defaults\nstructure. grep_defaults.pattern_type_option first becomes\nGREP_PATTERN_TYPE_ERE and then it gets overwritten to\nGREP_PATTERN_TYPE_UNSPECIFIED.\n\nThen grep.c::grep_init() copies that grep_defaults to the\nper-invocation \"struct grep_opt opt\" that is on-stack in\nbuiltin/grep.c::cmd_grep().  \n\nopt.patternType becomes GREP_PATTERN_TYPE_UNSPECIFIED;\nopt.extendedRegexp in the same structure is 0, because nobody has\ntouched the corresponding member in grep_defaults in\ngrep_cmd_config().\n\nThen parse_options() gets its turn to futz with members in \"opt\".\n-E/-G/-F/-P would be parsed into a separate variable \"pattern_type\";\nin this case, there is no command line option, so the pattern_type\nvariable has GREP_PATTERN_TYPE_UNSPECIFIED.\n\nAnd finally grep.c::grep_commit_pattern_type() is called to combine\nwhat is in \"pattern_type\" and \"opt\".\n\nIt calls grep_set_pattern_type_option() to futz with members in opt\nthat is what determines the final choice.\n\n - If pattern_type is not UNSPECIFIED, use that;\n\n - Otherwise, if opt->pattern_type_option is not UNSPECIFIED, use that;\n\n - Otherwise, i.e. if pattern_type from the command line and\n   opt->pattern_type_option from the configuration are both\n   UNSPECIFIED, then check if opt->extended_regexp_option (which is\n   set from the config via grep.extendedRegexp) is set.  If so, call\n   grep_set_pattern_type_option() to use ERE.\n\nNow, what does grep_set_pattern_type_option() do?\n\nThe first thing it does is when pattern_type given is not ERE, drop\nthe opt->extended_regexp_option bit (which may have been set by\nhaving grep.extendedRegexp configuration set to true).  This is\nbecause, just like 'fixed' and 'pcre2', the runtime after the opt\nstructure is set up, the code does not look at a single \"type\"\nmember that enumerates BRE, ERE, FIXED, PCRE to determine the type\nof the pattern, and the 'extended_regexp_option' member, after\ngrep_commit_pattern_type() finishes its processing, is used to\nsignal that ERE is in effect.  But as we've seen in the design goal\nof the earlier change 84befcd0 (grep: add a grep.patternType\nconfiguration setting, 2012-08-03), the bit obtained from the\ngrep.extendedRegexp configuration variable is only valid when\ngrep.patternType is set to UNSPECIFIED (aka default), so there needs\nsome dropping of this bit happen.\n\nBut with two grep.patternType configuration, I do not think the bug\nwill trigger.  As we traced above, we just get UNSPECIFIED in\ngrep_defaults.pattern_type_option, that is copied to cmd_grep()::opt,\nand it gets combined with UNSPECIFIED in cmd_grep()::pattern_type in\ngrep_commit_pattern_type().  But the three-step logic in the \"commit\"\nwill not do anything in this case.  So, I do not see any code that\nmakes this behave as if \"git grep -E foo\" was given.\n\nI suspect that if you do\n\n  $ git -c grep.extendedRegexp=true \\\n\t-c grep.patternType=default \\\n\tgrep foo\n\nit should set the .extended_regexp_option member to true and the\n.pattern_type_option member to UNSPECIFIED in grep_defaults, copy it\nto cmd_grep()::opt, and grep_commit_pattern_type() will try to\ncombine that \"opt\" with pattern_type==UNSPECIFIED.  The third \"both\npattern_type and opt.pattern_type_option are UNSPECIFIED\" case\ntriggers, and grep_set_pattern_type_option() would be called, with\nits pattern_type parameter explicitly set to ERE.\n\nThe logic to combine these two are convoluted and I sense that it\ncould be simplified without breaking the established semantics, but\nso far I am not seeing how the code can break in such a way that\n\n>> Extend the grep tests to assert that setting\n>> \"grep.patternType=extended\" followed by \"grep.patternType=default\"\n>> will behave as if \"--extended-regexp\" was provided, and not as\n>> \"--basic-regexp\".\n\nthis claim holds.\n\nSo,... after spending too much time following the code, I went back\nto the actual test added by the code and see this:\n\n+\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n\nHere, file \"ac\" has three lines\n\n        a+b*c\n        a+bc\n        abc\n\nand \"a+b*c\" pattern is designed to hit the first line with -F, the\nsecond one with -G (because + is literal in BRE so it must exist\nliterally in the haystack, b* matches single b but not literal b* in\nthe haystack), the last one with -E (because neither + or * is\nliteral, so the first two lines do not match, but the last one\nmatches).  The expectation in the code, unlike what is in the log\nmessage, is that this should match as if -G was given.\n\nSo, I guess there is no bug (other than the alarming false report in\nthe log message).\n\n\n\n"},{"id":"442959","messageId":"cover-v4-0.7-00000000000-20211203T101348Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v2-0.8-00000000000-20211110T013632Z-avarab@gmail.com","subject":"[PATCH v4 0/7] grep: simplify & delete \"init\" & \"config\" code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-03T10:19:47Z","receivedAt":"2021-12-03T10:20:10Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A simplification and code deletion of the overly complex setup for the\ngrep API, no behavior changes. For v3 see:\nhttps://lore.kernel.org/git/cover-v3-0.7-00000000000-20211129T143956Z-avarab@gmail.com/\n\nAs Junio notes in\nhttps://lore.kernel.org/git/xmqqbl22634q.fsf@gitster.g/ my previous\n3/7 had entirely the wrong commit message for the change it was\nmaking, i.e. the code itself was correct, but I somehow got things\nreversed in my head when writing the explanation.\n\nThat's fixed here, and for good measure I added another related test\nto the same commit for the same existing behavior.\n\nÆvar Arnfjörð Bjarmason (7):\n  grep.h: remove unused \"regex_t regexp\" from grep_opt\n  log tests: check if grep_config() is called by \"log\"-like cmds\n  grep tests: add missing \"grep.patternType\" config test\n  built-ins: trust the \"prefix\" from run_builtin()\n  grep.c: don't pass along NULL callback value\n  grep API: call grep_config() after grep_init()\n  grep: simplify config parsing and option parsing\n\n builtin/grep.c    |  27 +++++-----\n builtin/log.c     |  13 ++++-\n builtin/ls-tree.c |   2 +-\n git.c             |   1 +\n grep.c            | 124 ++++++++--------------------------------------\n grep.h            |  33 ++++++++----\n revision.c        |   4 +-\n t/t4202-log.sh    |  24 +++++++++\n t/t7810-grep.sh   |  19 +++++++\n 9 files changed, 116 insertions(+), 131 deletions(-)\n\nRange-diff against v3:\n1:  71ff51cb3c9 = 1:  d7d232b2b52 grep.h: remove unused \"regex_t regexp\" from grep_opt\n2:  ec8e42ced1a = 2:  f853d669682 log tests: check if grep_config() is called by \"log\"-like cmds\n3:  fcad1b1664b ! 3:  a97b7de3a3c grep tests: add missing \"grep.patternType\" config test\n    @@ Commit message\n     \n         Extend the grep tests to assert that setting\n         \"grep.patternType=extended\" followed by \"grep.patternType=default\"\n    -    will behave as if \"--extended-regexp\" was provided, and not as\n    -    \"--basic-regexp\". In a subsequent commit we'll need to treat\n    +    will behave as if \"--basic-regexp\" was provided, and not as\n    +    \"--extended-regexp\". In a subsequent commit we'll need to treat\n         \"grep.patternType=default\" as a special-case, but let's make sure we\n    -    don't ignore it if \"grep.patternType\" was set to a non-\"default\" value\n    -    before.\n    +    ignore it if it's being set to \"default\" following an earlier\n    +    non-\"default\" \"grep.patternType\" setting.\n    +\n    +    Let's also test what happens when we have a sequence of \"extended\"\n    +    followed by \"default\" and \"fixed\". In that case the \"fixed\" should\n    +    prevail.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    @@ t/t7810-grep.sh: do\n     +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n     +\t\ttest_cmp expected actual\n     +\t'\n    ++\n    ++\ttest_expect_success \"grep $L with grep.patternType=[extended -> default -> fixed]\" '\n    ++\t\techo \"${HC}ab:a+b*c\" >expected &&\n    ++\t\tgit \\\n    ++\t\t\t-c grep.patternType=extended \\\n    ++\t\t\t-c grep.patternType=default \\\n    ++\t\t\t-c grep.patternType=fixed \\\n    ++\t\t\tgrep \"a+b*c\" $H ab >actual &&\n    ++\t\ttest_cmp expected actual\n    ++\t'\n     +\n      \ttest_expect_success \"grep $L with grep.patternType=extended and grep.extendedRegexp=false\" '\n      \t\techo \"${HC}ab:abc\" >expected &&\n4:  854ffe8d0b9 = 4:  f7d995a5a80 built-ins: trust the \"prefix\" from run_builtin()\n5:  2536eae2c32 = 5:  ab1685f0dad grep.c: don't pass along NULL callback value\n6:  4e1be7c165b = 6:  8ffa22df8c7 grep API: call grep_config() after grep_init()\n7:  f40ab932cb1 = 7:  efbd1c50b43 grep: simplify config parsing and option parsing\n-- \n2.34.1.875.gb925cffed1e\n\n"},{"id":"442960","messageId":"patch-v4-1.7-d7d232b2b52-20211203T101348Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v4-0.7-00000000000-20211203T101348Z-avarab@gmail.com","subject":"[PATCH v4 1/7] grep.h: remove unused \"regex_t regexp\" from grep_opt","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-03T10:19:48Z","receivedAt":"2021-12-03T10:20:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This \"regex_t\" in grep_opt has not been used since\nf9b9faf6f8a (builtin-grep: allow more than one patterns., 2006-05-02),\nwe still use a \"regex_t\" for compiling regexes, but that's in the\n\"grep_pat\" struct\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 3e8815c347b..95cccb670f9 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -136,7 +136,6 @@ struct grep_opt {\n \n \tconst char *prefix;\n \tint prefix_length;\n-\tregex_t regexp;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n-- \n2.34.1.875.gb925cffed1e\n\n"},{"id":"442961","messageId":"patch-v4-2.7-f853d669682-20211203T101348Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v4-0.7-00000000000-20211203T101348Z-avarab@gmail.com","subject":"[PATCH v4 2/7] log tests: check if grep_config() is called by \"log\"-like cmds","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-03T10:19:49Z","receivedAt":"2021-12-03T10:20:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the tests added in my 9df46763ef1 (log: add exhaustive tests\nfor pattern style options & config, 2017-05-20) to check not only\nwhether \"git log\" handles \"grep.patternType\", but also \"git show\"\netc.\n\nIt's sufficient to check whether we match a \"fixed\" or a \"basic\" regex\nhere to see if these codepaths correctly invoked grep_config(). We\ndon't need to check the details of their regular expression matching\nas the \"log\" test does.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4202-log.sh | 24 ++++++++++++++++++++++++\n 1 file changed, 24 insertions(+)\n\ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex 7884e3d46b3..11bb25440b0 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -449,6 +449,30 @@ test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurati\n \t)\n '\n \n+for cmd in show whatchanged reflog format-patch\n+do\n+\tcase \"$cmd\" in\n+\tformat-patch) myarg=\"HEAD~..\" ;;\n+\t*) myarg= ;;\n+\tesac\n+\n+\ttest_expect_success \"$cmd: understands grep.patternType, like 'log'\" '\n+\t\tgit init \"pattern-type-$cmd\" &&\n+\t\t(\n+\t\t\tcd \"pattern-type-$cmd\" &&\n+\t\t\ttest_commit 1 file A &&\n+\t\t\ttest_commit \"(1|2)\" file B 2 &&\n+\n+\t\t\tgit -c grep.patternType=fixed $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_must_be_empty actual &&\n+\n+\t\t\tgit -c grep.patternType=basic $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_file_not_empty actual\n+\t\t)\n+\t'\n+done\n+test_done\n+\n test_expect_success 'log --author' '\n \tcat >expect <<-\\EOF &&\n \tAuthor: <BOLD;RED>A U<RESET> Thor <author@example.com>\n-- \n2.34.1.875.gb925cffed1e\n\n"},{"id":"442962","messageId":"patch-v4-3.7-a97b7de3a3c-20211203T101348Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v4-0.7-00000000000-20211203T101348Z-avarab@gmail.com","subject":"[PATCH v4 3/7] grep tests: add missing \"grep.patternType\" config test","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-03T10:19:50Z","receivedAt":"2021-12-03T10:20:20Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the grep tests to assert that setting\n\"grep.patternType=extended\" followed by \"grep.patternType=default\"\nwill behave as if \"--basic-regexp\" was provided, and not as\n\"--extended-regexp\". In a subsequent commit we'll need to treat\n\"grep.patternType=default\" as a special-case, but let's make sure we\nignore it if it's being set to \"default\" following an earlier\nnon-\"default\" \"grep.patternType\" setting.\n\nLet's also test what happens when we have a sequence of \"extended\"\nfollowed by \"default\" and \"fixed\". In that case the \"fixed\" should\nprevail.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7810-grep.sh | 19 +++++++++++++++++++\n 1 file changed, 19 insertions(+)\n\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 6b6423a07c3..113902c3bda 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -451,6 +451,25 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.patternType=[extended -> default -> fixed]\" '\n+\t\techo \"${HC}ab:a+b*c\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\t-c grep.patternType=fixed \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.patternType=extended and grep.extendedRegexp=false\" '\n \t\techo \"${HC}ab:abc\" >expected &&\n \t\tgit \\\n-- \n2.34.1.875.gb925cffed1e\n\n"},{"id":"442963","messageId":"patch-v4-4.7-f7d995a5a80-20211203T101348Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v4-0.7-00000000000-20211203T101348Z-avarab@gmail.com","subject":"[PATCH v4 4/7] built-ins: trust the \"prefix\" from run_builtin()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-03T10:19:51Z","receivedAt":"2021-12-03T10:20:23Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in \"builtin/grep.c\" and \"builtin/ls-tree.c\" to trust the\n\"prefix\" passed from \"run_builtin()\". The \"prefix\" we get from setup.c\nis either going to be NULL or a string of length >0, never \"\".\n\nSo we can drop the \"prefix && *prefix\" checks added for\n\"builtin/grep.c\" in 0d042fecf2f (git-grep: show pathnames relative to\nthe current directory, 2006-08-11), and for \"builtin/ls-tree.c\" in\na69dd585fca (ls-tree: chomp leading directories when run from a\nsubdirectory, 2005-12-23).\n\nAs seen in code in revision.c that was added in cd676a51367 (diff\n--relative: output paths as relative to the current subdirectory,\n2008-02-12) we already have existing code that does away with this\nassertion.\n\nThis makes it easier to reason about a subsequent change to the\n\"prefix_length\" code in grep.c in a subsequent commit, and since we're\ngoing to the trouble of doing that let's leave behind an assert() to\npromise this to any future callers.\n\nFor \"builtin/grep.c\" it would be painful to pass the \"prefix\" down the\ncallchain of:\n\n    cmd_grep -> grep_tree -> grep_submodule -> grep_cache -> grep_oid ->\n    grep_source_name\n\nSo for the code that needs it in grep_source_name() let's add a\n\"grep_prefix\" variable similar to the existing \"ls_tree_prefix\".\n\nWhile at it let's move the code in cmd_ls_tree() around so that we\nassign to the \"ls_tree_prefix\" right after declaring the variables,\nand stop assigning to \"prefix\". We only subsequently used that\nvariable later in the function after clobbering it. Let's just use our\nown \"grep_prefix\" instead.\n\nLet's also add an assert() in git.c, so that we'll make this promise\nabout the \"prefix\" to any current and future callers, as well as to\nany readers of the code.\n\nCode history:\n\n * The strlen() in \"grep.c\" hasn't been used since 493b7a08d80 (grep:\n   accept relative paths outside current working directory, 2009-09-05).\n\n   When that code was added in 0d042fecf2f (git-grep: show pathnames\n   relative to the current directory, 2006-08-11) we used the length.\n\n   But since 493b7a08d80 we haven't used it for anything except a\n   boolean check that we could have done on the \"prefix\" member\n   itself.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c    | 13 ++++++++-----\n builtin/ls-tree.c |  2 +-\n git.c             |  1 +\n grep.c            |  4 +---\n grep.h            |  4 +---\n revision.c        |  2 +-\n 6 files changed, 13 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 9e34a820ad4..d85cbabea67 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -26,6 +26,8 @@\n #include \"object-store.h\"\n #include \"packfile.h\"\n \n+static const char *grep_prefix;\n+\n static char const * const grep_usage[] = {\n \tN_(\"git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]\"),\n \tNULL\n@@ -315,11 +317,11 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \tstrbuf_reset(out);\n \n \tif (opt->null_following_name) {\n-\t\tif (opt->relative && opt->prefix_length) {\n+\t\tif (opt->relative && grep_prefix) {\n \t\t\tstruct strbuf rel_buf = STRBUF_INIT;\n \t\t\tconst char *rel_name =\n \t\t\t\trelative_path(filename + tree_name_len,\n-\t\t\t\t\t      opt->prefix, &rel_buf);\n+\t\t\t\t\t      grep_prefix, &rel_buf);\n \n \t\t\tif (tree_name_len)\n \t\t\t\tstrbuf_add(out, filename, tree_name_len);\n@@ -332,8 +334,8 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \t\treturn;\n \t}\n \n-\tif (opt->relative && opt->prefix_length)\n-\t\tquote_path(filename + tree_name_len, opt->prefix, out, 0);\n+\tif (opt->relative && grep_prefix)\n+\t\tquote_path(filename + tree_name_len, grep_prefix, out, 0);\n \telse\n \t\tquote_c_style(filename + tree_name_len, out, NULL, 0);\n \n@@ -962,9 +964,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\t   PARSE_OPT_NOCOMPLETE),\n \t\tOPT_END()\n \t};\n+\tgrep_prefix = prefix;\n \n \tgit_config(grep_cmd_config, NULL);\n-\tgrep_init(&opt, the_repository, prefix);\n+\tgrep_init(&opt, the_repository);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 3a442631c71..6cb554cbb0a 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -150,7 +150,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \n \tgit_config(git_default_config, NULL);\n \tls_tree_prefix = prefix;\n-\tif (prefix && *prefix)\n+\tif (prefix)\n \t\tchomp_prefix = strlen(prefix);\n \n \targc = parse_options(argc, argv, prefix, ls_tree_options,\ndiff --git a/git.c b/git.c\nindex 5ff21be21f3..6cf48adeb1f 100644\n--- a/git.c\n+++ b/git.c\n@@ -431,6 +431,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t\t\tint nongit_ok;\n \t\t\tprefix = setup_git_directory_gently(&nongit_ok);\n \t\t}\n+\t\tassert(!prefix || *prefix);\n \t\tprecompose_argv_prefix(argc, argv, NULL);\n \t\tif (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY) &&\n \t\t    !(p->option & DELAY_PAGER_CONFIG))\ndiff --git a/grep.c b/grep.c\nindex fe847a0111a..12b202598a9 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -139,13 +139,11 @@ int grep_config(const char *var, const char *value, void *cb)\n  * default values from the template we read the configuration\n  * information in an earlier call to git_config(grep_config).\n  */\n-void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)\n+void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n \t*opt = grep_defaults;\n \n \topt->repo = repo;\n-\topt->prefix = prefix;\n-\topt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;\n \topt->pattern_tail = &opt->pattern_list;\n \topt->header_tail = &opt->header_list;\n }\ndiff --git a/grep.h b/grep.h\nindex 95cccb670f9..62deadb885f 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -134,8 +134,6 @@ struct grep_opt {\n \t */\n \tstruct repository *repo;\n \n-\tconst char *prefix;\n-\tint prefix_length;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n@@ -180,7 +178,7 @@ struct grep_opt {\n };\n \n int grep_config(const char *var, const char *value, void *);\n-void grep_init(struct grep_opt *, struct repository *repo, const char *prefix);\n+void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex 1981a0859f0..a82e31df869 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1833,7 +1833,7 @@ void repo_init_revisions(struct repository *r,\n \trevs->commit_format = CMIT_FMT_DEFAULT;\n \trevs->expand_tabs_in_log_default = 8;\n \n-\tgrep_init(&revs->grep_filter, revs->repo, prefix);\n+\tgrep_init(&revs->grep_filter, revs->repo);\n \trevs->grep_filter.status_only = 1;\n \n \trepo_diff_setup(revs->repo, &revs->diffopt);\n-- \n2.34.1.875.gb925cffed1e\n\n"},{"id":"442964","messageId":"patch-v4-5.7-ab1685f0dad-20211203T101348Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v4-0.7-00000000000-20211203T101348Z-avarab@gmail.com","subject":"[PATCH v4 5/7] grep.c: don't pass along NULL callback value","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-03T10:19:52Z","receivedAt":"2021-12-03T10:20:25Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change grep_cmd_config() to stop passing around the always-NULL \"cb\"\nvalue. When this code was added in 7e8f59d577e (grep: color patterns\nin output, 2009-03-07) it was non-NULL, but when that changed in\n15fabd1bbd4 (builtin/grep.c: make configuration callback more\nreusable, 2012-10-09) this code was left behind.\n\nIn a subsequent change I'll start using the \"cb\" value, this will make\nit clear which functions we call need it, and which don't.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex d85cbabea67..5ec4cecae45 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,8 +285,8 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, cb);\n-\tif (git_color_default_config(var, value, cb) < 0)\n+\tint st = grep_config(var, value, NULL);\n+\tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n \tif (!strcmp(var, \"grep.threads\")) {\n-- \n2.34.1.875.gb925cffed1e\n\n"},{"id":"442965","messageId":"patch-v4-6.7-8ffa22df8c7-20211203T101348Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v4-0.7-00000000000-20211203T101348Z-avarab@gmail.com","subject":"[PATCH v4 6/7] grep API: call grep_config() after grep_init()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-03T10:19:53Z","receivedAt":"2021-12-03T10:20:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The grep_init() function used the odd pattern of initializing the\npassed-in \"struct grep_opt\" with a statically defined \"grep_defaults\"\nstruct, which would be modified in-place when we invoked\ngrep_config().\n\nSo we effectively (b) initialized config, (a) then defaults, (c)\nfollowed by user options. Usually those are ordered as \"a\", \"b\" and\n\"c\" instead.\n\nAs the comments being removed here show the previous behavior needed\nto be carefully explained as we'd potentially share the populated\nconfiguration among different instances of grep_init(). In practice we\ndidn't do that, but now that it can't be a concern anymore let's\nremove those comments.\n\nThis does not change the behavior of any of the configuration\nvariables or options. That would have been the case if we didn't move\naround the grep_config() call in \"builtin/log.c\". But now that we call\n\"grep_config\" after \"git_log_config\" and \"git_format_config\" we'll\nneed to pass in the already initialized \"struct grep_opt *\".\n\nSee 6ba9bb76e02 (grep: copy struct in one fell swoop, 2020-11-29) and\n7687a0541e0 (grep: move the configuration parsing logic to grep.[ch],\n2012-10-09) for the commits that added the comments.\n\nThe memcpy() pattern here will be optimized away and follows the\nconvention of other *_init() functions. See 5726a6b4012 (*.c *_init():\ndefine in terms of corresponding *_INIT macro, 2021-07-01).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c |  4 ++--\n builtin/log.c  | 13 +++++++++++--\n grep.c         | 39 +++------------------------------------\n grep.h         | 21 +++++++++++++++++++++\n 4 files changed, 37 insertions(+), 40 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5ec4cecae45..0ea124321b6 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,7 +285,7 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, NULL);\n+\tint st = grep_config(var, value, cb);\n \tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n@@ -966,8 +966,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t};\n \tgrep_prefix = prefix;\n \n-\tgit_config(grep_cmd_config, NULL);\n \tgrep_init(&opt, the_repository);\n+\tgit_config(grep_cmd_config, &opt);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/log.c b/builtin/log.c\nindex f75d87e8d7f..bfddacdfa6c 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -505,8 +505,6 @@ static int git_log_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n-\tif (grep_config(var, value, cb) < 0)\n-\t\treturn -1;\n \tif (git_gpg_config(var, value, cb) < 0)\n \t\treturn -1;\n \treturn git_diff_ui_config(var, value, cb);\n@@ -521,6 +519,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.simplify_history = 0;\n \tmemset(&opt, 0, sizeof(opt));\n@@ -635,6 +635,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \n \tmemset(&match_all, 0, sizeof(match_all));\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.always_show_header = 1;\n \trev.no_walk = 1;\n@@ -718,6 +720,8 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n \tinit_reflog_walk(&rev.reflog_info);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.verbose_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -751,6 +755,8 @@ int cmd_log(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.always_show_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -1833,10 +1839,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \textra_hdr.strdup_strings = 1;\n \textra_to.strdup_strings = 1;\n \textra_cc.strdup_strings = 1;\n+\n \tinit_log_defaults();\n \tinit_display_notes(&notes_opt);\n \tgit_config(git_format_config, NULL);\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.show_notes = show_notes;\n \tmemcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));\n \trev.commit_format = CMIT_FMT_EMAIL;\ndiff --git a/grep.c b/grep.c\nindex 12b202598a9..8dfa0300786 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -19,27 +19,6 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)\n \tfwrite(buf, size, 1, stdout);\n }\n \n-static struct grep_opt grep_defaults = {\n-\t.relative = 1,\n-\t.pathname = 1,\n-\t.max_depth = -1,\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t.colors = {\n-\t\t[GREP_COLOR_CONTEXT] = \"\",\n-\t\t[GREP_COLOR_FILENAME] = \"\",\n-\t\t[GREP_COLOR_FUNCTION] = \"\",\n-\t\t[GREP_COLOR_LINENO] = \"\",\n-\t\t[GREP_COLOR_COLUMNNO] = \"\",\n-\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_SELECTED] = \"\",\n-\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN,\n-\t},\n-\t.only_matching = 0,\n-\t.color = -1,\n-\t.output = std_output,\n-};\n-\n static const char *color_grep_slots[] = {\n \t[GREP_COLOR_CONTEXT]\t    = \"context\",\n \t[GREP_COLOR_FILENAME]\t    = \"filename\",\n@@ -75,20 +54,12 @@ define_list_config_array_extra(color_grep_slots, {\"match\"});\n  */\n int grep_config(const char *var, const char *value, void *cb)\n {\n-\tstruct grep_opt *opt = &grep_defaults;\n+\tstruct grep_opt *opt = cb;\n \tconst char *slot;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\t/*\n-\t * The instance of grep_opt that we set up here is copied by\n-\t * grep_init() to be used by each individual invocation.\n-\t * When populating a new field of this structure here, be\n-\t * sure to think about ownership -- e.g., you might need to\n-\t * override the shallow copy in grep_init() with a deep copy.\n-\t */\n-\n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n \t\treturn 0;\n@@ -134,14 +105,10 @@ int grep_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/*\n- * Initialize one instance of grep_opt and copy the\n- * default values from the template we read the configuration\n- * information in an earlier call to git_config(grep_config).\n- */\n void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n-\t*opt = grep_defaults;\n+\tstruct grep_opt blank = GREP_OPT_INIT;\n+\tmemcpy(opt, &blank, sizeof(*opt));\n \n \topt->repo = repo;\n \topt->pattern_tail = &opt->pattern_list;\ndiff --git a/grep.h b/grep.h\nindex 62deadb885f..b651eb291f7 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -177,6 +177,27 @@ struct grep_opt {\n \tvoid *output_priv;\n };\n \n+#define GREP_OPT_INIT { \\\n+\t.relative = 1, \\\n+\t.pathname = 1, \\\n+\t.max_depth = -1, \\\n+\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n+\t.colors = { \\\n+\t\t[GREP_COLOR_CONTEXT] = \"\", \\\n+\t\t[GREP_COLOR_FILENAME] = \"\", \\\n+\t\t[GREP_COLOR_FUNCTION] = \"\", \\\n+\t\t[GREP_COLOR_LINENO] = \"\", \\\n+\t\t[GREP_COLOR_COLUMNNO] = \"\", \\\n+\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_SELECTED] = \"\", \\\n+\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n+\t}, \\\n+\t.only_matching = 0, \\\n+\t.color = -1, \\\n+\t.output = std_output, \\\n+}\n+\n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n-- \n2.34.1.875.gb925cffed1e\n\n"},{"id":"442966","messageId":"patch-v4-7.7-efbd1c50b43-20211203T101348Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v4-0.7-00000000000-20211203T101348Z-avarab@gmail.com","subject":"[PATCH v4 7/7] grep: simplify config parsing and option parsing","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-03T10:19:54Z","receivedAt":"2021-12-03T10:20:34Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Simplify the parsing of \"grep.patternType\" and\n\"grep.extendedRegexp\". This changes no behavior, but gets rid of\ncomplex parsing logic that isn't needed anymore.\n\nWhen \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\ngrep.patternType configuration setting, 2012-08-03) we promised that:\n\n 1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n    will return to the default matching behavior\".\n\n 2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n    it when the new \"grep.patternType\" option is set. We said we'd\n    only ignore the older \"grep.extendedRegexp\" option \"when the\n    `grep.patternType` option is set. to a value other than\n    'default'\".\n\nIn a preceding commit we changed grep_config() to be called after\ngrep_init(), which means that much of the complexity here can go\naway.\n\nNow as before when we only understand a \"grep.extendedRegexp\" setting\nof \"true\", and if \"grep.patterntype=default\" is set we'll interpret it\nas \"grep.patterntype=basic\", except if we previously saw a\n\"grep.extendedRegexp\", then it's interpreted as\n\"grep.patterntype=extended\".\n\nSee my 07a3d411739 (grep: remove regflags from the public grep_opt\nAPI, 2017-06-29) for addition of the two comments being removed here,\ni.e. the complexity noted in that commit is now going away.\n\nWe don't need grep_commit_pattern_type() anymore, we can instead have\nOPT_SET_INT() in \"builtin/grep.c\" manipulate the \"pattern_type_option\"\nmember in \"struct grep_opt\" directly.\n\nWe can also do away with the indirection of the \"int fixed\" and \"int\npcre2\" members in favor of using \"pattern_type_option\" directly in\n\"grep.c\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 10 +++----\n grep.c         | 81 +++++++++++---------------------------------------\n grep.h         |  9 ++----\n revision.c     |  2 --\n 4 files changed, 24 insertions(+), 78 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 0ea124321b6..942c4b25077 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -845,7 +845,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tint i;\n \tint dummy;\n \tint use_index = 1;\n-\tint pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;\n \tint allow_revs;\n \n \tstruct option options[] = {\n@@ -879,16 +878,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"descend at most <depth> levels\"), PARSE_OPT_NONEG,\n \t\t\tNULL, 1 },\n \t\tOPT_GROUP(\"\"),\n-\t\tOPT_SET_INT('E', \"extended-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('E', \"extended-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use extended POSIX regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_ERE),\n-\t\tOPT_SET_INT('G', \"basic-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('G', \"basic-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use basic POSIX regular expressions (default)\"),\n \t\t\t    GREP_PATTERN_TYPE_BRE),\n-\t\tOPT_SET_INT('F', \"fixed-strings\", &pattern_type_arg,\n+\t\tOPT_SET_INT('F', \"fixed-strings\", &opt.pattern_type_option,\n \t\t\t    N_(\"interpret patterns as fixed strings\"),\n \t\t\t    GREP_PATTERN_TYPE_FIXED),\n-\t\tOPT_SET_INT('P', \"perl-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('P', \"perl-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use Perl-compatible regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_PCRE),\n \t\tOPT_GROUP(\"\"),\n@@ -982,7 +981,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, grep_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH |\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n-\tgrep_commit_pattern_type(pattern_type_arg, &opt);\n \n \tif (use_index && !startup_info->have_repository) {\n \t\tint fallback = 0;\ndiff --git a/grep.c b/grep.c\nindex 8dfa0300786..b5342064066 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -33,9 +33,7 @@ static const char *color_grep_slots[] = {\n \n static int parse_pattern_type_arg(const char *opt, const char *arg)\n {\n-\tif (!strcmp(arg, \"default\"))\n-\t\treturn GREP_PATTERN_TYPE_UNSPECIFIED;\n-\telse if (!strcmp(arg, \"basic\"))\n+\tif (!strcmp(arg, \"basic\"))\n \t\treturn GREP_PATTERN_TYPE_BRE;\n \telse if (!strcmp(arg, \"extended\"))\n \t\treturn GREP_PATTERN_TYPE_ERE;\n@@ -61,11 +59,23 @@ int grep_config(const char *var, const char *value, void *cb)\n \t\treturn -1;\n \n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n+\t\tif (opt->extended_regexp_option)\n+\t\t\treturn 0;\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n+\t\tif (opt->extended_regexp_option)\n+\t\t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n+\t\treturn 0;\n+\t}\n+\n+\tif (!strcmp(var, \"grep.patterntype\") &&\n+\t    !strcmp(value, \"default\")) {\n+\t\topt->pattern_type_option = opt->extended_regexp_option == 1\n+\t\t\t? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(var, \"grep.patterntype\")) {\n+\t\topt->extended_regexp_option = -1; /* ignore */\n \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n \t\treturn 0;\n \t}\n@@ -115,62 +125,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo)\n \topt->header_tail = &opt->header_list;\n }\n \n-static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\t/*\n-\t * When committing to the pattern type by setting the relevant\n-\t * fields in grep_opt it's generally not necessary to zero out\n-\t * the fields we're not choosing, since they won't have been\n-\t * set by anything. The extended_regexp_option field is the\n-\t * only exception to this.\n-\t *\n-\t * This is because in the process of parsing grep.patternType\n-\t * & grep.extendedRegexp we set opt->pattern_type_option and\n-\t * opt->extended_regexp_option, respectively. We then\n-\t * internally use opt->extended_regexp_option to see if we're\n-\t * compiling an ERE. It must be unset if that's not actually\n-\t * the case.\n-\t */\n-\tif (pattern_type != GREP_PATTERN_TYPE_ERE &&\n-\t    opt->extended_regexp_option)\n-\t\topt->extended_regexp_option = 0;\n-\n-\tswitch (pattern_type) {\n-\tcase GREP_PATTERN_TYPE_UNSPECIFIED:\n-\t\t/* fall through */\n-\n-\tcase GREP_PATTERN_TYPE_BRE:\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_ERE:\n-\t\topt->extended_regexp_option = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_FIXED:\n-\t\topt->fixed = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_PCRE:\n-\t\topt->pcre2 = 1;\n-\t\tbreak;\n-\t}\n-}\n-\n-void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\tif (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(pattern_type, opt);\n-\telse if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(opt->pattern_type_option, opt);\n-\telse if (opt->extended_regexp_option)\n-\t\t/*\n-\t\t * This branch *must* happen after setting from the\n-\t\t * opt->pattern_type_option above, we don't want\n-\t\t * grep.extendedRegexp to override grep.patternType!\n-\t\t */\n-\t\tgrep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);\n-}\n-\n static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,\n \t\t\t\t\tconst char *origin, int no,\n \t\t\t\t\tenum grep_pat_token t,\n@@ -490,9 +444,10 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \n \tp->word_regexp = opt->word_regexp;\n \tp->ignore_case = opt->ignore_case;\n-\tp->fixed = opt->fixed;\n+\tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\n \n-\tif (memchr(p->pattern, 0, p->patternlen) && !opt->pcre2)\n+\tif (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE &&\n+\t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n \tp->is_fixed = is_fixed(p->pattern, p->patternlen);\n@@ -543,14 +498,14 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \t\treturn;\n \t}\n \n-\tif (opt->pcre2) {\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_PCRE) {\n \t\tcompile_pcre2_pattern(p, opt);\n \t\treturn;\n \t}\n \n \tif (p->ignore_case)\n \t\tregflags |= REG_ICASE;\n-\tif (opt->extended_regexp_option)\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_ERE)\n \t\tregflags |= REG_EXTENDED;\n \terr = regcomp(&p->regexp, p->pattern, regflags);\n \tif (err) {\ndiff --git a/grep.h b/grep.h\nindex b651eb291f7..ab2ce833b40 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -94,8 +94,7 @@ enum grep_expr_node {\n };\n \n enum grep_pattern_type {\n-\tGREP_PATTERN_TYPE_UNSPECIFIED = 0,\n-\tGREP_PATTERN_TYPE_BRE,\n+\tGREP_PATTERN_TYPE_BRE = 0,\n \tGREP_PATTERN_TYPE_ERE,\n \tGREP_PATTERN_TYPE_FIXED,\n \tGREP_PATTERN_TYPE_PCRE\n@@ -143,7 +142,6 @@ struct grep_opt {\n \tint unmatch_name_only;\n \tint count;\n \tint word_regexp;\n-\tint fixed;\n \tint all_match;\n #define GREP_BINARY_DEFAULT\t0\n #define GREP_BINARY_NOMATCH\t1\n@@ -152,7 +150,6 @@ struct grep_opt {\n \tint allow_textconv;\n \tint extended;\n \tint use_reflog_filter;\n-\tint pcre2;\n \tint relative;\n \tint pathname;\n \tint null_following_name;\n@@ -162,7 +159,7 @@ struct grep_opt {\n \tint funcname;\n \tint funcbody;\n \tint extended_regexp_option;\n-\tint pattern_type_option;\n+\tenum grep_pattern_type pattern_type_option;\n \tint ignore_locale;\n \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n \tunsigned pre_context;\n@@ -181,7 +178,6 @@ struct grep_opt {\n \t.relative = 1, \\\n \t.pathname = 1, \\\n \t.max_depth = -1, \\\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n \t.colors = { \\\n \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n \t\t[GREP_COLOR_FILENAME] = \"\", \\\n@@ -200,7 +196,6 @@ struct grep_opt {\n \n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n-void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\n void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex a82e31df869..d08c7ae6c35 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2855,8 +2855,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \n \tdiff_setup_done(&revs->diffopt);\n \n-\tgrep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t\t\t\t &revs->grep_filter);\n \tif (!is_encoding_utf8(get_log_output_encoding()))\n \t\trevs->grep_filter.ignore_locale = 1;\n \tcompile_grep_patterns(&revs->grep_filter);\n-- \n2.34.1.875.gb925cffed1e\n\n"},{"id":"444694","messageId":"cover-v5-0.7-00000000000-20211222T025214Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v4-0.7-00000000000-20211203T101348Z-avarab@gmail.com","subject":"[PATCH v5 0/7] grep: simplify & delete \"init\" & \"config\" code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-22T02:58:50Z","receivedAt":"2021-12-22T02:59:04Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A simplification and code deletion of the overly complex setup for the\ngrep API, no behavior changes. For v4 see:\nhttps://lore.kernel.org/git/cover-v4-0.7-00000000000-20211203T101348Z-avarab@gmail.com/\n\nThis re-roll is rebased on the latest push-out to \"master\", now-landed\ntopic had a minor conflict with it in git.c.\n\nÆvar Arnfjörð Bjarmason (7):\n  grep.h: remove unused \"regex_t regexp\" from grep_opt\n  log tests: check if grep_config() is called by \"log\"-like cmds\n  grep tests: add missing \"grep.patternType\" config test\n  built-ins: trust the \"prefix\" from run_builtin()\n  grep.c: don't pass along NULL callback value\n  grep API: call grep_config() after grep_init()\n  grep: simplify config parsing and option parsing\n\n builtin/grep.c    |  27 +++++-----\n builtin/log.c     |  13 ++++-\n builtin/ls-tree.c |   2 +-\n git.c             |   1 +\n grep.c            | 124 ++++++++--------------------------------------\n grep.h            |  33 ++++++++----\n revision.c        |   4 +-\n t/t4202-log.sh    |  24 +++++++++\n t/t7810-grep.sh   |  19 +++++++\n 9 files changed, 116 insertions(+), 131 deletions(-)\n\nRange-diff against v4:\n1:  d7d232b2b52 = 1:  b6a3e0e2e08 grep.h: remove unused \"regex_t regexp\" from grep_opt\n2:  f853d669682 = 2:  c0d77b2683f log tests: check if grep_config() is called by \"log\"-like cmds\n3:  a97b7de3a3c = 3:  f02f246aa23 grep tests: add missing \"grep.patternType\" config test\n4:  f7d995a5a80 ! 4:  a542a352eab built-ins: trust the \"prefix\" from run_builtin()\n    @@ builtin/ls-tree.c: int cmd_ls_tree(int argc, const char **argv, const char *pref\n     \n      ## git.c ##\n     @@ git.c: static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n    - \t\t\tint nongit_ok;\n    - \t\t\tprefix = setup_git_directory_gently(&nongit_ok);\n    - \t\t}\n    -+\t\tassert(!prefix || *prefix);\n    - \t\tprecompose_argv_prefix(argc, argv, NULL);\n    - \t\tif (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY) &&\n    - \t\t    !(p->option & DELAY_PAGER_CONFIG))\n    + \t} else {\n    + \t\tprefix = NULL;\n    + \t}\n    ++\tassert(!prefix || *prefix);\n    + \tprecompose_argv_prefix(argc, argv, NULL);\n    + \tif (use_pager == -1 && run_setup &&\n    + \t\t!(p->option & DELAY_PAGER_CONFIG))\n     \n      ## grep.c ##\n     @@ grep.c: int grep_config(const char *var, const char *value, void *cb)\n5:  ab1685f0dad = 5:  a33b00a247e grep.c: don't pass along NULL callback value\n6:  8ffa22df8c7 = 6:  92b1c3958fa grep API: call grep_config() after grep_init()\n7:  efbd1c50b43 = 7:  63de643ebc2 grep: simplify config parsing and option parsing\n-- \n2.34.1.1146.gb52885e7c44\n\n"},{"id":"444695","messageId":"patch-v5-1.7-b6a3e0e2e08-20211222T025214Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v5-0.7-00000000000-20211222T025214Z-avarab@gmail.com","subject":"[PATCH v5 1/7] grep.h: remove unused \"regex_t regexp\" from grep_opt","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-22T02:58:51Z","receivedAt":"2021-12-22T02:59:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This \"regex_t\" in grep_opt has not been used since\nf9b9faf6f8a (builtin-grep: allow more than one patterns., 2006-05-02),\nwe still use a \"regex_t\" for compiling regexes, but that's in the\n\"grep_pat\" struct\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 3e8815c347b..95cccb670f9 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -136,7 +136,6 @@ struct grep_opt {\n \n \tconst char *prefix;\n \tint prefix_length;\n-\tregex_t regexp;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n-- \n2.34.1.1146.gb52885e7c44\n\n"},{"id":"444696","messageId":"patch-v5-2.7-c0d77b2683f-20211222T025214Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v5-0.7-00000000000-20211222T025214Z-avarab@gmail.com","subject":"[PATCH v5 2/7] log tests: check if grep_config() is called by \"log\"-like cmds","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-22T02:58:52Z","receivedAt":"2021-12-22T02:59:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the tests added in my 9df46763ef1 (log: add exhaustive tests\nfor pattern style options & config, 2017-05-20) to check not only\nwhether \"git log\" handles \"grep.patternType\", but also \"git show\"\netc.\n\nIt's sufficient to check whether we match a \"fixed\" or a \"basic\" regex\nhere to see if these codepaths correctly invoked grep_config(). We\ndon't need to check the details of their regular expression matching\nas the \"log\" test does.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4202-log.sh | 24 ++++++++++++++++++++++++\n 1 file changed, 24 insertions(+)\n\ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex 2ced7e9d817..2490f2cd5ed 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -449,6 +449,30 @@ test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurati\n \t)\n '\n \n+for cmd in show whatchanged reflog format-patch\n+do\n+\tcase \"$cmd\" in\n+\tformat-patch) myarg=\"HEAD~..\" ;;\n+\t*) myarg= ;;\n+\tesac\n+\n+\ttest_expect_success \"$cmd: understands grep.patternType, like 'log'\" '\n+\t\tgit init \"pattern-type-$cmd\" &&\n+\t\t(\n+\t\t\tcd \"pattern-type-$cmd\" &&\n+\t\t\ttest_commit 1 file A &&\n+\t\t\ttest_commit \"(1|2)\" file B 2 &&\n+\n+\t\t\tgit -c grep.patternType=fixed $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_must_be_empty actual &&\n+\n+\t\t\tgit -c grep.patternType=basic $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_file_not_empty actual\n+\t\t)\n+\t'\n+done\n+test_done\n+\n test_expect_success 'log --author' '\n \tcat >expect <<-\\EOF &&\n \tAuthor: <BOLD;RED>A U<RESET> Thor <author@example.com>\n-- \n2.34.1.1146.gb52885e7c44\n\n"},{"id":"444697","messageId":"patch-v5-3.7-f02f246aa23-20211222T025214Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v5-0.7-00000000000-20211222T025214Z-avarab@gmail.com","subject":"[PATCH v5 3/7] grep tests: add missing \"grep.patternType\" config test","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-22T02:58:53Z","receivedAt":"2021-12-22T02:59:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the grep tests to assert that setting\n\"grep.patternType=extended\" followed by \"grep.patternType=default\"\nwill behave as if \"--basic-regexp\" was provided, and not as\n\"--extended-regexp\". In a subsequent commit we'll need to treat\n\"grep.patternType=default\" as a special-case, but let's make sure we\nignore it if it's being set to \"default\" following an earlier\nnon-\"default\" \"grep.patternType\" setting.\n\nLet's also test what happens when we have a sequence of \"extended\"\nfollowed by \"default\" and \"fixed\". In that case the \"fixed\" should\nprevail.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7810-grep.sh | 19 +++++++++++++++++++\n 1 file changed, 19 insertions(+)\n\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 6b6423a07c3..113902c3bda 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -451,6 +451,25 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.patternType=[extended -> default -> fixed]\" '\n+\t\techo \"${HC}ab:a+b*c\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\t-c grep.patternType=fixed \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.patternType=extended and grep.extendedRegexp=false\" '\n \t\techo \"${HC}ab:abc\" >expected &&\n \t\tgit \\\n-- \n2.34.1.1146.gb52885e7c44\n\n"},{"id":"444698","messageId":"patch-v5-4.7-a542a352eab-20211222T025214Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v5-0.7-00000000000-20211222T025214Z-avarab@gmail.com","subject":"[PATCH v5 4/7] built-ins: trust the \"prefix\" from run_builtin()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-22T02:58:54Z","receivedAt":"2021-12-22T02:59:08Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in \"builtin/grep.c\" and \"builtin/ls-tree.c\" to trust the\n\"prefix\" passed from \"run_builtin()\". The \"prefix\" we get from setup.c\nis either going to be NULL or a string of length >0, never \"\".\n\nSo we can drop the \"prefix && *prefix\" checks added for\n\"builtin/grep.c\" in 0d042fecf2f (git-grep: show pathnames relative to\nthe current directory, 2006-08-11), and for \"builtin/ls-tree.c\" in\na69dd585fca (ls-tree: chomp leading directories when run from a\nsubdirectory, 2005-12-23).\n\nAs seen in code in revision.c that was added in cd676a51367 (diff\n--relative: output paths as relative to the current subdirectory,\n2008-02-12) we already have existing code that does away with this\nassertion.\n\nThis makes it easier to reason about a subsequent change to the\n\"prefix_length\" code in grep.c in a subsequent commit, and since we're\ngoing to the trouble of doing that let's leave behind an assert() to\npromise this to any future callers.\n\nFor \"builtin/grep.c\" it would be painful to pass the \"prefix\" down the\ncallchain of:\n\n    cmd_grep -> grep_tree -> grep_submodule -> grep_cache -> grep_oid ->\n    grep_source_name\n\nSo for the code that needs it in grep_source_name() let's add a\n\"grep_prefix\" variable similar to the existing \"ls_tree_prefix\".\n\nWhile at it let's move the code in cmd_ls_tree() around so that we\nassign to the \"ls_tree_prefix\" right after declaring the variables,\nand stop assigning to \"prefix\". We only subsequently used that\nvariable later in the function after clobbering it. Let's just use our\nown \"grep_prefix\" instead.\n\nLet's also add an assert() in git.c, so that we'll make this promise\nabout the \"prefix\" to any current and future callers, as well as to\nany readers of the code.\n\nCode history:\n\n * The strlen() in \"grep.c\" hasn't been used since 493b7a08d80 (grep:\n   accept relative paths outside current working directory, 2009-09-05).\n\n   When that code was added in 0d042fecf2f (git-grep: show pathnames\n   relative to the current directory, 2006-08-11) we used the length.\n\n   But since 493b7a08d80 we haven't used it for anything except a\n   boolean check that we could have done on the \"prefix\" member\n   itself.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c    | 13 ++++++++-----\n builtin/ls-tree.c |  2 +-\n git.c             |  1 +\n grep.c            |  4 +---\n grep.h            |  4 +---\n revision.c        |  2 +-\n 6 files changed, 13 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 9e34a820ad4..d85cbabea67 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -26,6 +26,8 @@\n #include \"object-store.h\"\n #include \"packfile.h\"\n \n+static const char *grep_prefix;\n+\n static char const * const grep_usage[] = {\n \tN_(\"git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]\"),\n \tNULL\n@@ -315,11 +317,11 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \tstrbuf_reset(out);\n \n \tif (opt->null_following_name) {\n-\t\tif (opt->relative && opt->prefix_length) {\n+\t\tif (opt->relative && grep_prefix) {\n \t\t\tstruct strbuf rel_buf = STRBUF_INIT;\n \t\t\tconst char *rel_name =\n \t\t\t\trelative_path(filename + tree_name_len,\n-\t\t\t\t\t      opt->prefix, &rel_buf);\n+\t\t\t\t\t      grep_prefix, &rel_buf);\n \n \t\t\tif (tree_name_len)\n \t\t\t\tstrbuf_add(out, filename, tree_name_len);\n@@ -332,8 +334,8 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \t\treturn;\n \t}\n \n-\tif (opt->relative && opt->prefix_length)\n-\t\tquote_path(filename + tree_name_len, opt->prefix, out, 0);\n+\tif (opt->relative && grep_prefix)\n+\t\tquote_path(filename + tree_name_len, grep_prefix, out, 0);\n \telse\n \t\tquote_c_style(filename + tree_name_len, out, NULL, 0);\n \n@@ -962,9 +964,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\t   PARSE_OPT_NOCOMPLETE),\n \t\tOPT_END()\n \t};\n+\tgrep_prefix = prefix;\n \n \tgit_config(grep_cmd_config, NULL);\n-\tgrep_init(&opt, the_repository, prefix);\n+\tgrep_init(&opt, the_repository);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 3a442631c71..6cb554cbb0a 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -150,7 +150,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \n \tgit_config(git_default_config, NULL);\n \tls_tree_prefix = prefix;\n-\tif (prefix && *prefix)\n+\tif (prefix)\n \t\tchomp_prefix = strlen(prefix);\n \n \targc = parse_options(argc, argv, prefix, ls_tree_options,\ndiff --git a/git.c b/git.c\nindex 7edafd8ecff..575d95046f2 100644\n--- a/git.c\n+++ b/git.c\n@@ -436,6 +436,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t} else {\n \t\tprefix = NULL;\n \t}\n+\tassert(!prefix || *prefix);\n \tprecompose_argv_prefix(argc, argv, NULL);\n \tif (use_pager == -1 && run_setup &&\n \t\t!(p->option & DELAY_PAGER_CONFIG))\ndiff --git a/grep.c b/grep.c\nindex fe847a0111a..12b202598a9 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -139,13 +139,11 @@ int grep_config(const char *var, const char *value, void *cb)\n  * default values from the template we read the configuration\n  * information in an earlier call to git_config(grep_config).\n  */\n-void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)\n+void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n \t*opt = grep_defaults;\n \n \topt->repo = repo;\n-\topt->prefix = prefix;\n-\topt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;\n \topt->pattern_tail = &opt->pattern_list;\n \topt->header_tail = &opt->header_list;\n }\ndiff --git a/grep.h b/grep.h\nindex 95cccb670f9..62deadb885f 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -134,8 +134,6 @@ struct grep_opt {\n \t */\n \tstruct repository *repo;\n \n-\tconst char *prefix;\n-\tint prefix_length;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n@@ -180,7 +178,7 @@ struct grep_opt {\n };\n \n int grep_config(const char *var, const char *value, void *);\n-void grep_init(struct grep_opt *, struct repository *repo, const char *prefix);\n+void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex 5390a479b30..495328e859c 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1838,7 +1838,7 @@ void repo_init_revisions(struct repository *r,\n \trevs->commit_format = CMIT_FMT_DEFAULT;\n \trevs->expand_tabs_in_log_default = 8;\n \n-\tgrep_init(&revs->grep_filter, revs->repo, prefix);\n+\tgrep_init(&revs->grep_filter, revs->repo);\n \trevs->grep_filter.status_only = 1;\n \n \trepo_diff_setup(revs->repo, &revs->diffopt);\n-- \n2.34.1.1146.gb52885e7c44\n\n"},{"id":"444699","messageId":"patch-v5-5.7-a33b00a247e-20211222T025214Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v5-0.7-00000000000-20211222T025214Z-avarab@gmail.com","subject":"[PATCH v5 5/7] grep.c: don't pass along NULL callback value","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-22T02:58:55Z","receivedAt":"2021-12-22T02:59:09Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change grep_cmd_config() to stop passing around the always-NULL \"cb\"\nvalue. When this code was added in 7e8f59d577e (grep: color patterns\nin output, 2009-03-07) it was non-NULL, but when that changed in\n15fabd1bbd4 (builtin/grep.c: make configuration callback more\nreusable, 2012-10-09) this code was left behind.\n\nIn a subsequent change I'll start using the \"cb\" value, this will make\nit clear which functions we call need it, and which don't.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex d85cbabea67..5ec4cecae45 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,8 +285,8 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, cb);\n-\tif (git_color_default_config(var, value, cb) < 0)\n+\tint st = grep_config(var, value, NULL);\n+\tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n \tif (!strcmp(var, \"grep.threads\")) {\n-- \n2.34.1.1146.gb52885e7c44\n\n"},{"id":"444700","messageId":"patch-v5-6.7-92b1c3958fa-20211222T025214Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v5-0.7-00000000000-20211222T025214Z-avarab@gmail.com","subject":"[PATCH v5 6/7] grep API: call grep_config() after grep_init()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-22T02:58:56Z","receivedAt":"2021-12-22T02:59:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The grep_init() function used the odd pattern of initializing the\npassed-in \"struct grep_opt\" with a statically defined \"grep_defaults\"\nstruct, which would be modified in-place when we invoked\ngrep_config().\n\nSo we effectively (b) initialized config, (a) then defaults, (c)\nfollowed by user options. Usually those are ordered as \"a\", \"b\" and\n\"c\" instead.\n\nAs the comments being removed here show the previous behavior needed\nto be carefully explained as we'd potentially share the populated\nconfiguration among different instances of grep_init(). In practice we\ndidn't do that, but now that it can't be a concern anymore let's\nremove those comments.\n\nThis does not change the behavior of any of the configuration\nvariables or options. That would have been the case if we didn't move\naround the grep_config() call in \"builtin/log.c\". But now that we call\n\"grep_config\" after \"git_log_config\" and \"git_format_config\" we'll\nneed to pass in the already initialized \"struct grep_opt *\".\n\nSee 6ba9bb76e02 (grep: copy struct in one fell swoop, 2020-11-29) and\n7687a0541e0 (grep: move the configuration parsing logic to grep.[ch],\n2012-10-09) for the commits that added the comments.\n\nThe memcpy() pattern here will be optimized away and follows the\nconvention of other *_init() functions. See 5726a6b4012 (*.c *_init():\ndefine in terms of corresponding *_INIT macro, 2021-07-01).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c |  4 ++--\n builtin/log.c  | 13 +++++++++++--\n grep.c         | 39 +++------------------------------------\n grep.h         | 21 +++++++++++++++++++++\n 4 files changed, 37 insertions(+), 40 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5ec4cecae45..0ea124321b6 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,7 +285,7 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, NULL);\n+\tint st = grep_config(var, value, cb);\n \tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n@@ -966,8 +966,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t};\n \tgrep_prefix = prefix;\n \n-\tgit_config(grep_cmd_config, NULL);\n \tgrep_init(&opt, the_repository);\n+\tgit_config(grep_cmd_config, &opt);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 93ace0dde7d..fdde77e4ebb 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -520,8 +520,6 @@ static int git_log_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n-\tif (grep_config(var, value, cb) < 0)\n-\t\treturn -1;\n \tif (git_gpg_config(var, value, cb) < 0)\n \t\treturn -1;\n \treturn git_diff_ui_config(var, value, cb);\n@@ -536,6 +534,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.simplify_history = 0;\n \tmemset(&opt, 0, sizeof(opt));\n@@ -650,6 +650,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \n \tmemset(&match_all, 0, sizeof(match_all));\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.always_show_header = 1;\n \trev.no_walk = 1;\n@@ -733,6 +735,8 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n \tinit_reflog_walk(&rev.reflog_info);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.verbose_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -766,6 +770,8 @@ int cmd_log(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.always_show_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -1848,10 +1854,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \textra_hdr.strdup_strings = 1;\n \textra_to.strdup_strings = 1;\n \textra_cc.strdup_strings = 1;\n+\n \tinit_log_defaults();\n \tinit_display_notes(&notes_opt);\n \tgit_config(git_format_config, NULL);\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.show_notes = show_notes;\n \tmemcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));\n \trev.commit_format = CMIT_FMT_EMAIL;\ndiff --git a/grep.c b/grep.c\nindex 12b202598a9..8dfa0300786 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -19,27 +19,6 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)\n \tfwrite(buf, size, 1, stdout);\n }\n \n-static struct grep_opt grep_defaults = {\n-\t.relative = 1,\n-\t.pathname = 1,\n-\t.max_depth = -1,\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t.colors = {\n-\t\t[GREP_COLOR_CONTEXT] = \"\",\n-\t\t[GREP_COLOR_FILENAME] = \"\",\n-\t\t[GREP_COLOR_FUNCTION] = \"\",\n-\t\t[GREP_COLOR_LINENO] = \"\",\n-\t\t[GREP_COLOR_COLUMNNO] = \"\",\n-\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_SELECTED] = \"\",\n-\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN,\n-\t},\n-\t.only_matching = 0,\n-\t.color = -1,\n-\t.output = std_output,\n-};\n-\n static const char *color_grep_slots[] = {\n \t[GREP_COLOR_CONTEXT]\t    = \"context\",\n \t[GREP_COLOR_FILENAME]\t    = \"filename\",\n@@ -75,20 +54,12 @@ define_list_config_array_extra(color_grep_slots, {\"match\"});\n  */\n int grep_config(const char *var, const char *value, void *cb)\n {\n-\tstruct grep_opt *opt = &grep_defaults;\n+\tstruct grep_opt *opt = cb;\n \tconst char *slot;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\t/*\n-\t * The instance of grep_opt that we set up here is copied by\n-\t * grep_init() to be used by each individual invocation.\n-\t * When populating a new field of this structure here, be\n-\t * sure to think about ownership -- e.g., you might need to\n-\t * override the shallow copy in grep_init() with a deep copy.\n-\t */\n-\n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n \t\treturn 0;\n@@ -134,14 +105,10 @@ int grep_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/*\n- * Initialize one instance of grep_opt and copy the\n- * default values from the template we read the configuration\n- * information in an earlier call to git_config(grep_config).\n- */\n void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n-\t*opt = grep_defaults;\n+\tstruct grep_opt blank = GREP_OPT_INIT;\n+\tmemcpy(opt, &blank, sizeof(*opt));\n \n \topt->repo = repo;\n \topt->pattern_tail = &opt->pattern_list;\ndiff --git a/grep.h b/grep.h\nindex 62deadb885f..b651eb291f7 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -177,6 +177,27 @@ struct grep_opt {\n \tvoid *output_priv;\n };\n \n+#define GREP_OPT_INIT { \\\n+\t.relative = 1, \\\n+\t.pathname = 1, \\\n+\t.max_depth = -1, \\\n+\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n+\t.colors = { \\\n+\t\t[GREP_COLOR_CONTEXT] = \"\", \\\n+\t\t[GREP_COLOR_FILENAME] = \"\", \\\n+\t\t[GREP_COLOR_FUNCTION] = \"\", \\\n+\t\t[GREP_COLOR_LINENO] = \"\", \\\n+\t\t[GREP_COLOR_COLUMNNO] = \"\", \\\n+\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_SELECTED] = \"\", \\\n+\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n+\t}, \\\n+\t.only_matching = 0, \\\n+\t.color = -1, \\\n+\t.output = std_output, \\\n+}\n+\n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n-- \n2.34.1.1146.gb52885e7c44\n\n"},{"id":"444701","messageId":"patch-v5-7.7-63de643ebc2-20211222T025214Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v5-0.7-00000000000-20211222T025214Z-avarab@gmail.com","subject":"[PATCH v5 7/7] grep: simplify config parsing and option parsing","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-22T02:58:57Z","receivedAt":"2021-12-22T02:59:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Simplify the parsing of \"grep.patternType\" and\n\"grep.extendedRegexp\". This changes no behavior, but gets rid of\ncomplex parsing logic that isn't needed anymore.\n\nWhen \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\ngrep.patternType configuration setting, 2012-08-03) we promised that:\n\n 1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n    will return to the default matching behavior\".\n\n 2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n    it when the new \"grep.patternType\" option is set. We said we'd\n    only ignore the older \"grep.extendedRegexp\" option \"when the\n    `grep.patternType` option is set. to a value other than\n    'default'\".\n\nIn a preceding commit we changed grep_config() to be called after\ngrep_init(), which means that much of the complexity here can go\naway.\n\nNow as before when we only understand a \"grep.extendedRegexp\" setting\nof \"true\", and if \"grep.patterntype=default\" is set we'll interpret it\nas \"grep.patterntype=basic\", except if we previously saw a\n\"grep.extendedRegexp\", then it's interpreted as\n\"grep.patterntype=extended\".\n\nSee my 07a3d411739 (grep: remove regflags from the public grep_opt\nAPI, 2017-06-29) for addition of the two comments being removed here,\ni.e. the complexity noted in that commit is now going away.\n\nWe don't need grep_commit_pattern_type() anymore, we can instead have\nOPT_SET_INT() in \"builtin/grep.c\" manipulate the \"pattern_type_option\"\nmember in \"struct grep_opt\" directly.\n\nWe can also do away with the indirection of the \"int fixed\" and \"int\npcre2\" members in favor of using \"pattern_type_option\" directly in\n\"grep.c\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 10 +++----\n grep.c         | 81 +++++++++++---------------------------------------\n grep.h         |  9 ++----\n revision.c     |  2 --\n 4 files changed, 24 insertions(+), 78 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 0ea124321b6..942c4b25077 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -845,7 +845,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tint i;\n \tint dummy;\n \tint use_index = 1;\n-\tint pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;\n \tint allow_revs;\n \n \tstruct option options[] = {\n@@ -879,16 +878,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"descend at most <depth> levels\"), PARSE_OPT_NONEG,\n \t\t\tNULL, 1 },\n \t\tOPT_GROUP(\"\"),\n-\t\tOPT_SET_INT('E', \"extended-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('E', \"extended-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use extended POSIX regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_ERE),\n-\t\tOPT_SET_INT('G', \"basic-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('G', \"basic-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use basic POSIX regular expressions (default)\"),\n \t\t\t    GREP_PATTERN_TYPE_BRE),\n-\t\tOPT_SET_INT('F', \"fixed-strings\", &pattern_type_arg,\n+\t\tOPT_SET_INT('F', \"fixed-strings\", &opt.pattern_type_option,\n \t\t\t    N_(\"interpret patterns as fixed strings\"),\n \t\t\t    GREP_PATTERN_TYPE_FIXED),\n-\t\tOPT_SET_INT('P', \"perl-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('P', \"perl-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use Perl-compatible regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_PCRE),\n \t\tOPT_GROUP(\"\"),\n@@ -982,7 +981,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, grep_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH |\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n-\tgrep_commit_pattern_type(pattern_type_arg, &opt);\n \n \tif (use_index && !startup_info->have_repository) {\n \t\tint fallback = 0;\ndiff --git a/grep.c b/grep.c\nindex 8dfa0300786..b5342064066 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -33,9 +33,7 @@ static const char *color_grep_slots[] = {\n \n static int parse_pattern_type_arg(const char *opt, const char *arg)\n {\n-\tif (!strcmp(arg, \"default\"))\n-\t\treturn GREP_PATTERN_TYPE_UNSPECIFIED;\n-\telse if (!strcmp(arg, \"basic\"))\n+\tif (!strcmp(arg, \"basic\"))\n \t\treturn GREP_PATTERN_TYPE_BRE;\n \telse if (!strcmp(arg, \"extended\"))\n \t\treturn GREP_PATTERN_TYPE_ERE;\n@@ -61,11 +59,23 @@ int grep_config(const char *var, const char *value, void *cb)\n \t\treturn -1;\n \n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n+\t\tif (opt->extended_regexp_option)\n+\t\t\treturn 0;\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n+\t\tif (opt->extended_regexp_option)\n+\t\t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n+\t\treturn 0;\n+\t}\n+\n+\tif (!strcmp(var, \"grep.patterntype\") &&\n+\t    !strcmp(value, \"default\")) {\n+\t\topt->pattern_type_option = opt->extended_regexp_option == 1\n+\t\t\t? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(var, \"grep.patterntype\")) {\n+\t\topt->extended_regexp_option = -1; /* ignore */\n \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n \t\treturn 0;\n \t}\n@@ -115,62 +125,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo)\n \topt->header_tail = &opt->header_list;\n }\n \n-static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\t/*\n-\t * When committing to the pattern type by setting the relevant\n-\t * fields in grep_opt it's generally not necessary to zero out\n-\t * the fields we're not choosing, since they won't have been\n-\t * set by anything. The extended_regexp_option field is the\n-\t * only exception to this.\n-\t *\n-\t * This is because in the process of parsing grep.patternType\n-\t * & grep.extendedRegexp we set opt->pattern_type_option and\n-\t * opt->extended_regexp_option, respectively. We then\n-\t * internally use opt->extended_regexp_option to see if we're\n-\t * compiling an ERE. It must be unset if that's not actually\n-\t * the case.\n-\t */\n-\tif (pattern_type != GREP_PATTERN_TYPE_ERE &&\n-\t    opt->extended_regexp_option)\n-\t\topt->extended_regexp_option = 0;\n-\n-\tswitch (pattern_type) {\n-\tcase GREP_PATTERN_TYPE_UNSPECIFIED:\n-\t\t/* fall through */\n-\n-\tcase GREP_PATTERN_TYPE_BRE:\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_ERE:\n-\t\topt->extended_regexp_option = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_FIXED:\n-\t\topt->fixed = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_PCRE:\n-\t\topt->pcre2 = 1;\n-\t\tbreak;\n-\t}\n-}\n-\n-void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\tif (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(pattern_type, opt);\n-\telse if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(opt->pattern_type_option, opt);\n-\telse if (opt->extended_regexp_option)\n-\t\t/*\n-\t\t * This branch *must* happen after setting from the\n-\t\t * opt->pattern_type_option above, we don't want\n-\t\t * grep.extendedRegexp to override grep.patternType!\n-\t\t */\n-\t\tgrep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);\n-}\n-\n static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,\n \t\t\t\t\tconst char *origin, int no,\n \t\t\t\t\tenum grep_pat_token t,\n@@ -490,9 +444,10 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \n \tp->word_regexp = opt->word_regexp;\n \tp->ignore_case = opt->ignore_case;\n-\tp->fixed = opt->fixed;\n+\tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\n \n-\tif (memchr(p->pattern, 0, p->patternlen) && !opt->pcre2)\n+\tif (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE &&\n+\t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n \tp->is_fixed = is_fixed(p->pattern, p->patternlen);\n@@ -543,14 +498,14 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \t\treturn;\n \t}\n \n-\tif (opt->pcre2) {\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_PCRE) {\n \t\tcompile_pcre2_pattern(p, opt);\n \t\treturn;\n \t}\n \n \tif (p->ignore_case)\n \t\tregflags |= REG_ICASE;\n-\tif (opt->extended_regexp_option)\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_ERE)\n \t\tregflags |= REG_EXTENDED;\n \terr = regcomp(&p->regexp, p->pattern, regflags);\n \tif (err) {\ndiff --git a/grep.h b/grep.h\nindex b651eb291f7..ab2ce833b40 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -94,8 +94,7 @@ enum grep_expr_node {\n };\n \n enum grep_pattern_type {\n-\tGREP_PATTERN_TYPE_UNSPECIFIED = 0,\n-\tGREP_PATTERN_TYPE_BRE,\n+\tGREP_PATTERN_TYPE_BRE = 0,\n \tGREP_PATTERN_TYPE_ERE,\n \tGREP_PATTERN_TYPE_FIXED,\n \tGREP_PATTERN_TYPE_PCRE\n@@ -143,7 +142,6 @@ struct grep_opt {\n \tint unmatch_name_only;\n \tint count;\n \tint word_regexp;\n-\tint fixed;\n \tint all_match;\n #define GREP_BINARY_DEFAULT\t0\n #define GREP_BINARY_NOMATCH\t1\n@@ -152,7 +150,6 @@ struct grep_opt {\n \tint allow_textconv;\n \tint extended;\n \tint use_reflog_filter;\n-\tint pcre2;\n \tint relative;\n \tint pathname;\n \tint null_following_name;\n@@ -162,7 +159,7 @@ struct grep_opt {\n \tint funcname;\n \tint funcbody;\n \tint extended_regexp_option;\n-\tint pattern_type_option;\n+\tenum grep_pattern_type pattern_type_option;\n \tint ignore_locale;\n \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n \tunsigned pre_context;\n@@ -181,7 +178,6 @@ struct grep_opt {\n \t.relative = 1, \\\n \t.pathname = 1, \\\n \t.max_depth = -1, \\\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n \t.colors = { \\\n \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n \t\t[GREP_COLOR_FILENAME] = \"\", \\\n@@ -200,7 +196,6 @@ struct grep_opt {\n \n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n-void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\n void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex 495328e859c..298d0ea7574 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2860,8 +2860,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \n \tdiff_setup_done(&revs->diffopt);\n \n-\tgrep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t\t\t\t &revs->grep_filter);\n \tif (!is_encoding_utf8(get_log_output_encoding()))\n \t\trevs->grep_filter.ignore_locale = 1;\n \tcompile_grep_patterns(&revs->grep_filter);\n-- \n2.34.1.1146.gb52885e7c44\n\n"},{"id":"444847","messageId":"xmqqy24ccgd3.fsf@gitster.g","threadId":"56853","inReplyTo":"cover-v5-0.7-00000000000-20211222T025214Z-avarab@gmail.com","subject":"Re: [PATCH v5 0/7] grep: simplify & delete \"init\" & \"config\" code","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-12-23T00:30:32Z","receivedAt":"2021-12-23T00:30:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> A simplification and code deletion of the overly complex setup for the\n> grep API, no behavior changes. For v4 see:\n> https://lore.kernel.org/git/cover-v4-0.7-00000000000-20211203T101348Z-avarab@gmail.com/\n>\n> This re-roll is rebased on the latest push-out to \"master\", now-landed\n> topic had a minor conflict with it in git.c.\n\nI understand that this has no changes other than the rebase to\nadjust for the \"even when we are running 'git cmd -h', make sure we\ntry to find where the git repository is (gently)\".  Am I correct?\n\nI am not complaining for lack of improvements or anything.  I am\nonly making sure that I am applying the right version to a right\nbase.\n\nTHanks.\n"},{"id":"444884","messageId":"xmqq35mj7yd4.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v5-3.7-f02f246aa23-20211222T025214Z-avarab@gmail.com","subject":"Re: [PATCH v5 3/7] grep tests: add missing \"grep.patternType\" config test","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-12-23T22:25:11Z","receivedAt":"2021-12-23T22:26:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Extend the grep tests to assert that setting\n> \"grep.patternType=extended\" followed by \"grep.patternType=default\"\n> will behave as if \"--basic-regexp\" was provided, and not as\n> \"--extended-regexp\". In a subsequent commit we'll need to treat\n> \"grep.patternType=default\" as a special-case, but let's make sure we\n> ignore it if it's being set to \"default\" following an earlier\n> non-\"default\" \"grep.patternType\" setting.\n>\n> Let's also test what happens when we have a sequence of \"extended\"\n> followed by \"default\" and \"fixed\". In that case the \"fixed\" should\n> prevail.\n\nThe grep.patternType configuration variable has the \"last one wins\"\nsemantics just all the usual configuration variable, but the meaning\nof the variable when it is set to \"default\" depends on the value set\nto grep.extendedRegexp variable.\n\nIf you rewrite with the above understanding, what you wrote will\nbecome a lot more concise.\n\n    Extend the grep tests to assert that grep.patternType is the\n    usual \"last one wins\" variable, and specifically, setting it to\n    \"default\" has the same meaning as setting it to \"basic\" when\n    grep.extendedRegexp is not set (or set to false).\n\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t7810-grep.sh | 19 +++++++++++++++++++\n>  1 file changed, 19 insertions(+)\n>\n> diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\n> index 6b6423a07c3..113902c3bda 100755\n> --- a/t/t7810-grep.sh\n> +++ b/t/t7810-grep.sh\n> @@ -451,6 +451,25 @@ do\n>  \t\ttest_cmp expected actual\n>  \t'\n>  \n> +\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n> +\t\techo \"${HC}ab:a+bc\" >expected &&\n> +\t\tgit \\\n> +\t\t\t-c grep.patternType=extended \\\n> +\t\t\t-c grep.patternType=default \\\n> +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n> +\t\ttest_cmp expected actual\n> +\t'\n> +\n> +\ttest_expect_success \"grep $L with grep.patternType=[extended -> default -> fixed]\" '\n> +\t\techo \"${HC}ab:a+b*c\" >expected &&\n> +\t\tgit \\\n> +\t\t\t-c grep.patternType=extended \\\n> +\t\t\t-c grep.patternType=default \\\n> +\t\t\t-c grep.patternType=fixed \\\n> +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n\nAnd from that point of view, I think the second new test has much\nless value than a possible alternative to ensure grep.patternType\nset to fixed and then default behaves like setting it to extended\nwhen grep.extendedRegexp is set to true.  As written, this is just\ntesting that the variable we designed and know to be \"last one wins\"\nbehaves as one once more.\n\n> +\t\ttest_cmp expected actual\n> +\t'\n> +\n>  \ttest_expect_success \"grep $L with grep.patternType=extended and grep.extendedRegexp=false\" '\n>  \t\techo \"${HC}ab:abc\" >expected &&\n>  \t\tgit \\\n"},{"id":"444885","messageId":"xmqqv8zf6j86.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v5-7.7-63de643ebc2-20211222T025214Z-avarab@gmail.com","subject":"Re: [PATCH v5 7/7] grep: simplify config parsing and option parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-12-23T22:37:29Z","receivedAt":"2021-12-23T22:37:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Simplify the parsing of \"grep.patternType\" and\n> \"grep.extendedRegexp\". This changes no behavior, but gets rid of\n> complex parsing logic that isn't needed anymore.\n>\n> When \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\n> grep.patternType configuration setting, 2012-08-03) we promised that:\n>\n>  1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n>     will return to the default matching behavior\".\n\nYou need to call it into readers' attention that back then the\nauthor of that commit meant by \"the default\" to mean \"whatever the\nconfiguration system specified before the patch applied, i.e. with\ngrep.extendedRegexp\".\n\n>  2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n>     it when the new \"grep.patternType\" option is set. We said we'd\n>     only ignore the older \"grep.extendedRegexp\" option \"when the\n>     `grep.patternType` option is set. to a value other than\n>     'default'\".\n\nYes, in short, you can think of it this way.\n\n - We use grep.patternType as the source of truth.  It is a usual\n   last-one-wins variable, with values like fixed, basic, pcre,\n   etc.\n\n - There however is a special value 'default', which may mean\n   'basic' or 'extended', depending on what grep.extendedRegexp is\n   set to.\n\n> In a preceding commit we changed grep_config() to be called after\n> grep_init(), which means that much of the complexity here can go\n> away.\n>\n> Now as before when we only understand a \"grep.extendedRegexp\" setting\n> of \"true\", and if \"grep.patterntype=default\" is set we'll interpret it\n> as \"grep.patterntype=basic\",\n\nIs that a typo?  If extendedRegexp is set to 'true', then the\n'default' would mean 'extended', so I would expect that we'd\nsee it as the same as setting it 'grep.patternType=extended'.\n\n> except if we previously saw a\n> \"grep.extendedRegexp\", then it's interpreted as\n> \"grep.patterntype=extended\".\n\nI am not sure what this means.  grep.extendedRegexp is also a usual\nlast-one-wins variable.  If you had this series:\n\n    git \\\n    -c grep.extendedRegexp = false \\\n    -c grep.extendedRegexp = true \\\n    -c grep.patternType = default \\\n    some-command-that-take-regexp\n\nthe last grep.extendedRegexp is true, and the last grep.patternType\nis default, so the command sould work on extended.  It is also true\nif you had\n\n    git \\\n    -c grep.extendedRegexp = false \\\n    -c grep.patternType = default \\\n    -c grep.extendedRegexp = true \\\n    some-command-that-take-regexp\n\nThat is why it is important to remember the fact that patternType\nwas give as \"default\" before you finish reading the configuration\nand you are sure you know the last value of grep.extendedRegexp.\nOnly after that, you can resolve what that \"default\" means between\n\"basic\" and \"extended\".  Trying to interpret \"default\" as soon as\nyou see it in grep.patternType and trying to make it into either\n\"basic\" or \"extended\" will not work unless you know you have the\nfinal value of grep.extendedRegexp.\n\n> We don't need grep_commit_pattern_type() anymore,...\n\nAnd I think that is what this function wanted to say: \"we now have\nseen all necessary, so we can commit what pattern type we are going\nto use; before this point, we couldn't tell what 'default' meant\".\n\nSo I am not sure how any change that says we do not need the\n\"commit\" phase can be correct.\n"},{"id":"444928","messageId":"xmqqfsqh35vu.fsf_-_@gitster.g","threadId":"56853","inReplyTo":"xmqq35mj7yd4.fsf@gitster.g","subject":"Re* [PATCH v5 3/7] grep tests: add missing \"grep.patternType\" config test","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-12-25T00:06:13Z","receivedAt":"2021-12-25T00:06:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> The grep.patternType configuration variable has the \"last one wins\"\n> semantics just all the usual configuration variable, but the meaning\n> of the variable when it is set to \"default\" depends on the value set\n> to grep.extendedRegexp variable.\n>\n> If you rewrite with the above understanding, what you wrote will\n> become a lot more concise.\n>\n>     Extend the grep tests to assert that grep.patternType is the\n>     usual \"last one wins\" variable, and specifically, setting it to\n>     \"default\" has the same meaning as setting it to \"basic\" when\n>     grep.extendedRegexp is not set (or set to false).\n\nAlso, it is probably a good idea to strees that grep.extendedRegexp\nis also \"last one wins\", so as I wrote in a separate message, Git\nfinds the last one for grep.extendedRegexp and grep.patternType\nindependently and combines these last values to come up with the\npattern type it uses.\n\nI'll tentatively queue the following patch between your 3/7 and 4/7,\nbut it probably is a good idea to squash it into 3/7, as it belongs\nto the same theme: clarify how these two variables are meant to\ninteract with each other.\n\n----- >8 --------- >8 --------- >8 --------- >8 --------- >8 --------- >8 ----\nSubject: [PATCH] t7810: make sure grep.extendedRegexp is also last-one-wins\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t7810-grep.sh | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 113902c3bd..2c17704e01 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -451,6 +451,16 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n \t\techo \"${HC}ab:a+bc\" >expected &&\n \t\tgit \\\n-- \n2.34.1-563-g3368a7891b\n\n"},{"id":"444929","messageId":"xmqqa6gp35a6.fsf_-_@gitster.g","threadId":"56853","inReplyTo":"xmqqfsqh35vu.fsf_-_@gitster.g","subject":"[RFC/PATCH] grep: allow scripts to ignore configured pattern type","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-12-25T00:19:13Z","receivedAt":"2021-12-25T00:19:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We made a mistake to add grep.extendedRegexp configuration variable\nlong time ago, and made things even worse by introducing an even\nmore generalized grep.patternType configuration variable.\n\nThis was mostly because interactive users were lazy and wanted a way\nto declare \"I do not live in the ancient age, and my regexps are\nalways extended\" and write \"git grep\" without having to type three\nmore letters \" -E\" on the command line.\n\nBut this in turn forces script writers to always specify what kind\nof patterns they are writing, because without such command line\noverride, the interpretation of the patterns they write in their\nscripts will be affected by the configuration variables of the user\nwho is running their script.\n\nIntroduce GIT_DISABLE_GREP_PATTERN_CONFIG environment variable that\nscript writers can set to \"true\" and export at the very beginning of\ntheir script to defeat grep.extendedRegexp and grep.patternType\nconfiguration variables.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n * This is merely a weather balloon without proper documentation and\n   test.  It might be even better idea to make such an environment\n   variable to _specify_ what kind of pattern the script uses,\n   instead of \"we defeat end-user configuration and now we are\n   forced to write in basic or have to write -E/-P etc.\", which is\n   what this patch does.\n\n grep.c | 11 +++++++++--\n 1 file changed, 9 insertions(+), 2 deletions(-)\n\ndiff --git a/grep.c b/grep.c\nindex fe847a0111..0cfb698b51 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -77,10 +77,15 @@ int grep_config(const char *var, const char *value, void *cb)\n {\n \tstruct grep_opt *opt = &grep_defaults;\n \tconst char *slot;\n+\tstatic int disable_pattern_type_config = -1;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n+\tif (disable_pattern_type_config < 0)\n+\t\tdisable_pattern_type_config =\n+\t\t\tgit_env_bool(\"GIT_DISABLE_GREP_PATTERN_CONFIG\", 0);\n+\n \t/*\n \t * The instance of grep_opt that we set up here is copied by\n \t * grep_init() to be used by each individual invocation.\n@@ -90,12 +95,14 @@ int grep_config(const char *var, const char *value, void *cb)\n \t */\n \n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n-\t\topt->extended_regexp_option = git_config_bool(var, value);\n+\t\tif (!disable_pattern_type_config)\n+\t\t\topt->extended_regexp_option = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(var, \"grep.patterntype\")) {\n-\t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n+\t\tif (!disable_pattern_type_config)\n+\t\t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n \t\treturn 0;\n \t}\n \n-- \n2.34.1-563-g3368a7891b\n\n"},{"id":"444932","messageId":"xmqqwnjt5wcd.fsf@gitster.g","threadId":"56853","inReplyTo":"xmqqfsqh35vu.fsf_-_@gitster.g","subject":"Re: Re* [PATCH v5 3/7] grep tests: add missing \"grep.patternType\" config test","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-12-25T01:04:02Z","receivedAt":"2021-12-25T01:04:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> I'll tentatively queue the following patch between your 3/7 and 4/7,\n> but it probably is a good idea to squash it into 3/7, as it belongs\n> to the same theme: clarify how these two variables are meant to\n> interact with each other.\n\nJust as I suspected earlier, up to the [PATCH 6/7] of the series\npasses this test and this test reveals the breakage in [PATCH 7/7].\n\nIn the review of that step, I said \"I am not sure how any change\nthat says we do not need the \"commit\" phase can be correct.\" but\ncome to think of it, it was a bit too strong.  It is possible to\nimplement correct semantics without the \"commit\" phase, as long as\nwe do not try to decide between basic and extended too hastily when\nwe see grep.patternType=default, before we are sure that we will not\nsee any new definition of grep.extendedRegexp [*].  In the extreme,\nwe could keep it as 'default' until the time just before we compile\nthe regexp and consult the final value of grep.extendedRegexp to\ndecide between the two, and such an implementation would still give\ncorrect results without having to have a \"commit\" phase.\n\n\n[Footnote]\n\n* The story is the same for the `--patternType=default` command line\n  option, but by the time we read the command line option, we should\n  be already done with the configuration, and there is no command\n  line option to override the grep.extendedRegexp configuration\n  variable, so we do not have to worry about that case.  When we\n  read --patternType=default from the command line, we can safely\n  use the value we know about grep.extendedRegexp and decide to use\n  either basic or extended.\n\n  But that is not true for grep.patternType configuration varialble,\n  as the additional test I am responding to shows.\n\n> ----- >8 --------- >8 --------- >8 --------- >8 --------- >8 --------- >8 ----\n> Subject: [PATCH] t7810: make sure grep.extendedRegexp is also last-one-wins\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  t/t7810-grep.sh | 10 ++++++++++\n>  1 file changed, 10 insertions(+)\n>\n> diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\n> index 113902c3bd..2c17704e01 100755\n> --- a/t/t7810-grep.sh\n> +++ b/t/t7810-grep.sh\n> @@ -451,6 +451,16 @@ do\n>  \t\ttest_cmp expected actual\n>  \t'\n>  \n> +\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins\" '\n> +\t\techo \"${HC}ab:a+bc\" >expected &&\n> +\t\tgit \\\n> +\t\t\t-c grep.extendedRegexp=true \\\n> +\t\t\t-c grep.patternType=default \\\n> +\t\t\t-c grep.extendedRegexp=false \\\n> +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n> +\t\ttest_cmp expected actual\n> +\t'\n> +\n>  \ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n>  \t\techo \"${HC}ab:a+bc\" >expected &&\n>  \t\tgit \\\n"},{"id":"444974","messageId":"cover-v6-0.7-00000000000-20211226T223035Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v5-0.7-00000000000-20211222T025214Z-avarab@gmail.com","subject":"[PATCH v6 0/7] grep: simplify & delete \"init\" & \"config\" code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-26T22:37:12Z","receivedAt":"2021-12-26T22:37:30Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A simplification and code deletion of the overly complex setup for the\ngrep API, no behavior changes. For v5 see:\nhttps://lore.kernel.org/git/cover-v5-0.7-00000000000-20211222T025214Z-avarab@gmail.com\n\nChanges since v4:\n\n * As Junio pointed out there were behavior changes in the v4. I\n   integrated/squashed the change he added to the\n   gitster/ab/grep-patterntype branch to add the tests, and a fixed\n   7/7 correctly handles the case of a flip-flopping\n   grep.extendedRegexp now.\n\n * Some commit message additions/rewording that I hope will address\n   relevant comments from Junio.\n\nÆvar Arnfjörð Bjarmason (7):\n  grep.h: remove unused \"regex_t regexp\" from grep_opt\n  log tests: check if grep_config() is called by \"log\"-like cmds\n  grep tests: add missing \"grep.patternType\" config tests\n  built-ins: trust the \"prefix\" from run_builtin()\n  grep.c: don't pass along NULL callback value\n  grep API: call grep_config() after grep_init()\n  grep: simplify config parsing and option parsing\n\n builtin/grep.c    |  27 +++++-----\n builtin/log.c     |  13 ++++-\n builtin/ls-tree.c |   2 +-\n git.c             |   1 +\n grep.c            | 126 +++++++++-------------------------------------\n grep.h            |  33 ++++++++----\n revision.c        |   4 +-\n t/t4202-log.sh    |  24 +++++++++\n t/t7810-grep.sh   |  39 ++++++++++++++\n 9 files changed, 138 insertions(+), 131 deletions(-)\n\nRange-diff against v5:\n1:  b6a3e0e2e08 = 1:  b62e6b6162a grep.h: remove unused \"regex_t regexp\" from grep_opt\n2:  c0d77b2683f = 2:  0edcdb50afd log tests: check if grep_config() is called by \"log\"-like cmds\n3:  f02f246aa23 ! 3:  1b724d5e2e9 grep tests: add missing \"grep.patternType\" config test\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    grep tests: add missing \"grep.patternType\" config test\n    +    grep tests: add missing \"grep.patternType\" config tests\n     \n         Extend the grep tests to assert that setting\n         \"grep.patternType=extended\" followed by \"grep.patternType=default\"\n    @@ Commit message\n     \n         Let's also test what happens when we have a sequence of \"extended\"\n         followed by \"default\" and \"fixed\". In that case the \"fixed\" should\n    -    prevail.\n    +    prevail, as well as tests to check that a \"grep.extendedRegexp=true\"\n    +    followed by a \"grep.extendedRegexp=false\" behaves as though\n    +    \"grep.extendedRegexp\" wasn't provided.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n    +    Signed-off-by: Junio C Hamano <gitster@pobox.com>\n     \n      ## t/t7810-grep.sh ##\n     @@ t/t7810-grep.sh: do\n      \t\ttest_cmp expected actual\n      \t'\n      \n    ++\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins\" '\n    ++\t\techo \"${HC}ab:a+bc\" >expected &&\n    ++\t\tgit \\\n    ++\t\t\t-c grep.extendedRegexp=true \\\n    ++\t\t\t-c grep.patternType=basic \\\n    ++\t\t\t-c grep.extendedRegexp=false \\\n    ++\t\t\tgrep \"a+b*c\" $H ab >actual &&\n    ++\t\ttest_cmp expected actual\n    ++\t'\n    ++\n    ++\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins & defers to grep.patternType\" '\n    ++\t\techo \"${HC}ab:abc\" >expected &&\n    ++\t\tgit \\\n    ++\t\t\t-c grep.extendedRegexp=true \\\n    ++\t\t\t-c grep.patternType=extended \\\n    ++\t\t\t-c grep.extendedRegexp=false \\\n    ++\t\t\tgrep \"a+b*c\" $H ab >actual &&\n    ++\t\ttest_cmp expected actual\n    ++\t'\n    ++\n     +\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n     +\t\techo \"${HC}ab:a+bc\" >expected &&\n     +\t\tgit \\\n4:  a542a352eab = 4:  f4876552771 built-ins: trust the \"prefix\" from run_builtin()\n5:  a33b00a247e = 5:  069b0339146 grep.c: don't pass along NULL callback value\n6:  92b1c3958fa = 6:  e38eca56959 grep API: call grep_config() after grep_init()\n7:  63de643ebc2 ! 7:  88dfd40bf9e grep: simplify config parsing and option parsing\n    @@ Commit message\n          1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n             will return to the default matching behavior\".\n     \n    +        In that context \"the default\" meant whatever the configuration\n    +        system specified before that change, i.e. via grep.extendedRegexp.\n    +\n          2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n             it when the new \"grep.patternType\" option is set. We said we'd\n             only ignore the older \"grep.extendedRegexp\" option \"when the\n    @@ Commit message\n         grep_init(), which means that much of the complexity here can go\n         away.\n     \n    -    Now as before when we only understand a \"grep.extendedRegexp\" setting\n    -    of \"true\", and if \"grep.patterntype=default\" is set we'll interpret it\n    -    as \"grep.patterntype=basic\", except if we previously saw a\n    -    \"grep.extendedRegexp\", then it's interpreted as\n    -    \"grep.patterntype=extended\".\n    +    As before \"grep.extendedRegexp\" is a last-one-wins variable. We need\n    +    to maintain state inside parse_pattern_type_arg() to ignore it if a\n    +    non-\"default\" grep.patternType was seen, but otherwise flip between\n    +    BRE and ERE for \"grep.extendedRegexp=[false|true]\".\n     \n         See my 07a3d411739 (grep: remove regflags from the public grep_opt\n         API, 2017-06-29) for addition of the two comments being removed here,\n    @@ grep.c: int grep_config(const char *var, const char *value, void *cb)\n      \t\treturn -1;\n      \n      \tif (!strcmp(var, \"grep.extendedregexp\")) {\n    -+\t\tif (opt->extended_regexp_option)\n    ++\t\tif (opt->extended_regexp_option == -1)\n     +\t\t\treturn 0;\n      \t\topt->extended_regexp_option = git_config_bool(var, value);\n     +\t\tif (opt->extended_regexp_option)\n     +\t\t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n    ++\t\telse\n    ++\t\t\topt->pattern_type_option = GREP_PATTERN_TYPE_BRE;\n     +\t\treturn 0;\n     +\t}\n     +\n-- \n2.34.1.1239.g84ae229c870\n\n"},{"id":"444975","messageId":"patch-v6-1.7-b62e6b6162a-20211226T223035Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v6-0.7-00000000000-20211226T223035Z-avarab@gmail.com","subject":"[PATCH v6 1/7] grep.h: remove unused \"regex_t regexp\" from grep_opt","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-26T22:37:13Z","receivedAt":"2021-12-26T22:37:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This \"regex_t\" in grep_opt has not been used since\nf9b9faf6f8a (builtin-grep: allow more than one patterns., 2006-05-02),\nwe still use a \"regex_t\" for compiling regexes, but that's in the\n\"grep_pat\" struct\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 3e8815c347b..95cccb670f9 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -136,7 +136,6 @@ struct grep_opt {\n \n \tconst char *prefix;\n \tint prefix_length;\n-\tregex_t regexp;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n-- \n2.34.1.1239.g84ae229c870\n\n"},{"id":"444976","messageId":"patch-v6-2.7-0edcdb50afd-20211226T223035Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v6-0.7-00000000000-20211226T223035Z-avarab@gmail.com","subject":"[PATCH v6 2/7] log tests: check if grep_config() is called by \"log\"-like cmds","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-26T22:37:14Z","receivedAt":"2021-12-26T22:37:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the tests added in my 9df46763ef1 (log: add exhaustive tests\nfor pattern style options & config, 2017-05-20) to check not only\nwhether \"git log\" handles \"grep.patternType\", but also \"git show\"\netc.\n\nIt's sufficient to check whether we match a \"fixed\" or a \"basic\" regex\nhere to see if these codepaths correctly invoked grep_config(). We\ndon't need to check the details of their regular expression matching\nas the \"log\" test does.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4202-log.sh | 24 ++++++++++++++++++++++++\n 1 file changed, 24 insertions(+)\n\ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex 2ced7e9d817..2490f2cd5ed 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -449,6 +449,30 @@ test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurati\n \t)\n '\n \n+for cmd in show whatchanged reflog format-patch\n+do\n+\tcase \"$cmd\" in\n+\tformat-patch) myarg=\"HEAD~..\" ;;\n+\t*) myarg= ;;\n+\tesac\n+\n+\ttest_expect_success \"$cmd: understands grep.patternType, like 'log'\" '\n+\t\tgit init \"pattern-type-$cmd\" &&\n+\t\t(\n+\t\t\tcd \"pattern-type-$cmd\" &&\n+\t\t\ttest_commit 1 file A &&\n+\t\t\ttest_commit \"(1|2)\" file B 2 &&\n+\n+\t\t\tgit -c grep.patternType=fixed $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_must_be_empty actual &&\n+\n+\t\t\tgit -c grep.patternType=basic $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_file_not_empty actual\n+\t\t)\n+\t'\n+done\n+test_done\n+\n test_expect_success 'log --author' '\n \tcat >expect <<-\\EOF &&\n \tAuthor: <BOLD;RED>A U<RESET> Thor <author@example.com>\n-- \n2.34.1.1239.g84ae229c870\n\n"},{"id":"444977","messageId":"patch-v6-3.7-1b724d5e2e9-20211226T223035Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v6-0.7-00000000000-20211226T223035Z-avarab@gmail.com","subject":"[PATCH v6 3/7] grep tests: add missing \"grep.patternType\" config tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-26T22:37:15Z","receivedAt":"2021-12-26T22:37:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the grep tests to assert that setting\n\"grep.patternType=extended\" followed by \"grep.patternType=default\"\nwill behave as if \"--basic-regexp\" was provided, and not as\n\"--extended-regexp\". In a subsequent commit we'll need to treat\n\"grep.patternType=default\" as a special-case, but let's make sure we\nignore it if it's being set to \"default\" following an earlier\nnon-\"default\" \"grep.patternType\" setting.\n\nLet's also test what happens when we have a sequence of \"extended\"\nfollowed by \"default\" and \"fixed\". In that case the \"fixed\" should\nprevail, as well as tests to check that a \"grep.extendedRegexp=true\"\nfollowed by a \"grep.extendedRegexp=false\" behaves as though\n\"grep.extendedRegexp\" wasn't provided.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t7810-grep.sh | 39 +++++++++++++++++++++++++++++++++++++++\n 1 file changed, 39 insertions(+)\n\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 6b6423a07c3..664f884e12a 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -451,6 +451,45 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=basic \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins & defers to grep.patternType\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.patternType=[extended -> default -> fixed]\" '\n+\t\techo \"${HC}ab:a+b*c\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\t-c grep.patternType=fixed \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.patternType=extended and grep.extendedRegexp=false\" '\n \t\techo \"${HC}ab:abc\" >expected &&\n \t\tgit \\\n-- \n2.34.1.1239.g84ae229c870\n\n"},{"id":"444978","messageId":"patch-v6-4.7-f4876552771-20211226T223035Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v6-0.7-00000000000-20211226T223035Z-avarab@gmail.com","subject":"[PATCH v6 4/7] built-ins: trust the \"prefix\" from run_builtin()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-26T22:37:16Z","receivedAt":"2021-12-26T22:37:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in \"builtin/grep.c\" and \"builtin/ls-tree.c\" to trust the\n\"prefix\" passed from \"run_builtin()\". The \"prefix\" we get from setup.c\nis either going to be NULL or a string of length >0, never \"\".\n\nSo we can drop the \"prefix && *prefix\" checks added for\n\"builtin/grep.c\" in 0d042fecf2f (git-grep: show pathnames relative to\nthe current directory, 2006-08-11), and for \"builtin/ls-tree.c\" in\na69dd585fca (ls-tree: chomp leading directories when run from a\nsubdirectory, 2005-12-23).\n\nAs seen in code in revision.c that was added in cd676a51367 (diff\n--relative: output paths as relative to the current subdirectory,\n2008-02-12) we already have existing code that does away with this\nassertion.\n\nThis makes it easier to reason about a subsequent change to the\n\"prefix_length\" code in grep.c in a subsequent commit, and since we're\ngoing to the trouble of doing that let's leave behind an assert() to\npromise this to any future callers.\n\nFor \"builtin/grep.c\" it would be painful to pass the \"prefix\" down the\ncallchain of:\n\n    cmd_grep -> grep_tree -> grep_submodule -> grep_cache -> grep_oid ->\n    grep_source_name\n\nSo for the code that needs it in grep_source_name() let's add a\n\"grep_prefix\" variable similar to the existing \"ls_tree_prefix\".\n\nWhile at it let's move the code in cmd_ls_tree() around so that we\nassign to the \"ls_tree_prefix\" right after declaring the variables,\nand stop assigning to \"prefix\". We only subsequently used that\nvariable later in the function after clobbering it. Let's just use our\nown \"grep_prefix\" instead.\n\nLet's also add an assert() in git.c, so that we'll make this promise\nabout the \"prefix\" to any current and future callers, as well as to\nany readers of the code.\n\nCode history:\n\n * The strlen() in \"grep.c\" hasn't been used since 493b7a08d80 (grep:\n   accept relative paths outside current working directory, 2009-09-05).\n\n   When that code was added in 0d042fecf2f (git-grep: show pathnames\n   relative to the current directory, 2006-08-11) we used the length.\n\n   But since 493b7a08d80 we haven't used it for anything except a\n   boolean check that we could have done on the \"prefix\" member\n   itself.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c    | 13 ++++++++-----\n builtin/ls-tree.c |  2 +-\n git.c             |  1 +\n grep.c            |  4 +---\n grep.h            |  4 +---\n revision.c        |  2 +-\n 6 files changed, 13 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 9e34a820ad4..d85cbabea67 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -26,6 +26,8 @@\n #include \"object-store.h\"\n #include \"packfile.h\"\n \n+static const char *grep_prefix;\n+\n static char const * const grep_usage[] = {\n \tN_(\"git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]\"),\n \tNULL\n@@ -315,11 +317,11 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \tstrbuf_reset(out);\n \n \tif (opt->null_following_name) {\n-\t\tif (opt->relative && opt->prefix_length) {\n+\t\tif (opt->relative && grep_prefix) {\n \t\t\tstruct strbuf rel_buf = STRBUF_INIT;\n \t\t\tconst char *rel_name =\n \t\t\t\trelative_path(filename + tree_name_len,\n-\t\t\t\t\t      opt->prefix, &rel_buf);\n+\t\t\t\t\t      grep_prefix, &rel_buf);\n \n \t\t\tif (tree_name_len)\n \t\t\t\tstrbuf_add(out, filename, tree_name_len);\n@@ -332,8 +334,8 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \t\treturn;\n \t}\n \n-\tif (opt->relative && opt->prefix_length)\n-\t\tquote_path(filename + tree_name_len, opt->prefix, out, 0);\n+\tif (opt->relative && grep_prefix)\n+\t\tquote_path(filename + tree_name_len, grep_prefix, out, 0);\n \telse\n \t\tquote_c_style(filename + tree_name_len, out, NULL, 0);\n \n@@ -962,9 +964,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\t   PARSE_OPT_NOCOMPLETE),\n \t\tOPT_END()\n \t};\n+\tgrep_prefix = prefix;\n \n \tgit_config(grep_cmd_config, NULL);\n-\tgrep_init(&opt, the_repository, prefix);\n+\tgrep_init(&opt, the_repository);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 3a442631c71..6cb554cbb0a 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -150,7 +150,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \n \tgit_config(git_default_config, NULL);\n \tls_tree_prefix = prefix;\n-\tif (prefix && *prefix)\n+\tif (prefix)\n \t\tchomp_prefix = strlen(prefix);\n \n \targc = parse_options(argc, argv, prefix, ls_tree_options,\ndiff --git a/git.c b/git.c\nindex 7edafd8ecff..575d95046f2 100644\n--- a/git.c\n+++ b/git.c\n@@ -436,6 +436,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t} else {\n \t\tprefix = NULL;\n \t}\n+\tassert(!prefix || *prefix);\n \tprecompose_argv_prefix(argc, argv, NULL);\n \tif (use_pager == -1 && run_setup &&\n \t\t!(p->option & DELAY_PAGER_CONFIG))\ndiff --git a/grep.c b/grep.c\nindex fe847a0111a..12b202598a9 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -139,13 +139,11 @@ int grep_config(const char *var, const char *value, void *cb)\n  * default values from the template we read the configuration\n  * information in an earlier call to git_config(grep_config).\n  */\n-void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)\n+void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n \t*opt = grep_defaults;\n \n \topt->repo = repo;\n-\topt->prefix = prefix;\n-\topt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;\n \topt->pattern_tail = &opt->pattern_list;\n \topt->header_tail = &opt->header_list;\n }\ndiff --git a/grep.h b/grep.h\nindex 95cccb670f9..62deadb885f 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -134,8 +134,6 @@ struct grep_opt {\n \t */\n \tstruct repository *repo;\n \n-\tconst char *prefix;\n-\tint prefix_length;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n@@ -180,7 +178,7 @@ struct grep_opt {\n };\n \n int grep_config(const char *var, const char *value, void *);\n-void grep_init(struct grep_opt *, struct repository *repo, const char *prefix);\n+void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex 5390a479b30..495328e859c 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1838,7 +1838,7 @@ void repo_init_revisions(struct repository *r,\n \trevs->commit_format = CMIT_FMT_DEFAULT;\n \trevs->expand_tabs_in_log_default = 8;\n \n-\tgrep_init(&revs->grep_filter, revs->repo, prefix);\n+\tgrep_init(&revs->grep_filter, revs->repo);\n \trevs->grep_filter.status_only = 1;\n \n \trepo_diff_setup(revs->repo, &revs->diffopt);\n-- \n2.34.1.1239.g84ae229c870\n\n"},{"id":"444979","messageId":"patch-v6-5.7-069b0339146-20211226T223035Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v6-0.7-00000000000-20211226T223035Z-avarab@gmail.com","subject":"[PATCH v6 5/7] grep.c: don't pass along NULL callback value","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-26T22:37:17Z","receivedAt":"2021-12-26T22:37:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change grep_cmd_config() to stop passing around the always-NULL \"cb\"\nvalue. When this code was added in 7e8f59d577e (grep: color patterns\nin output, 2009-03-07) it was non-NULL, but when that changed in\n15fabd1bbd4 (builtin/grep.c: make configuration callback more\nreusable, 2012-10-09) this code was left behind.\n\nIn a subsequent change I'll start using the \"cb\" value, this will make\nit clear which functions we call need it, and which don't.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex d85cbabea67..5ec4cecae45 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,8 +285,8 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, cb);\n-\tif (git_color_default_config(var, value, cb) < 0)\n+\tint st = grep_config(var, value, NULL);\n+\tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n \tif (!strcmp(var, \"grep.threads\")) {\n-- \n2.34.1.1239.g84ae229c870\n\n"},{"id":"444980","messageId":"patch-v6-6.7-e38eca56959-20211226T223035Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v6-0.7-00000000000-20211226T223035Z-avarab@gmail.com","subject":"[PATCH v6 6/7] grep API: call grep_config() after grep_init()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-26T22:37:18Z","receivedAt":"2021-12-26T22:37:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The grep_init() function used the odd pattern of initializing the\npassed-in \"struct grep_opt\" with a statically defined \"grep_defaults\"\nstruct, which would be modified in-place when we invoked\ngrep_config().\n\nSo we effectively (b) initialized config, (a) then defaults, (c)\nfollowed by user options. Usually those are ordered as \"a\", \"b\" and\n\"c\" instead.\n\nAs the comments being removed here show the previous behavior needed\nto be carefully explained as we'd potentially share the populated\nconfiguration among different instances of grep_init(). In practice we\ndidn't do that, but now that it can't be a concern anymore let's\nremove those comments.\n\nThis does not change the behavior of any of the configuration\nvariables or options. That would have been the case if we didn't move\naround the grep_config() call in \"builtin/log.c\". But now that we call\n\"grep_config\" after \"git_log_config\" and \"git_format_config\" we'll\nneed to pass in the already initialized \"struct grep_opt *\".\n\nSee 6ba9bb76e02 (grep: copy struct in one fell swoop, 2020-11-29) and\n7687a0541e0 (grep: move the configuration parsing logic to grep.[ch],\n2012-10-09) for the commits that added the comments.\n\nThe memcpy() pattern here will be optimized away and follows the\nconvention of other *_init() functions. See 5726a6b4012 (*.c *_init():\ndefine in terms of corresponding *_INIT macro, 2021-07-01).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c |  4 ++--\n builtin/log.c  | 13 +++++++++++--\n grep.c         | 39 +++------------------------------------\n grep.h         | 21 +++++++++++++++++++++\n 4 files changed, 37 insertions(+), 40 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5ec4cecae45..0ea124321b6 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,7 +285,7 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, NULL);\n+\tint st = grep_config(var, value, cb);\n \tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n@@ -966,8 +966,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t};\n \tgrep_prefix = prefix;\n \n-\tgit_config(grep_cmd_config, NULL);\n \tgrep_init(&opt, the_repository);\n+\tgit_config(grep_cmd_config, &opt);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 93ace0dde7d..fdde77e4ebb 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -520,8 +520,6 @@ static int git_log_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n-\tif (grep_config(var, value, cb) < 0)\n-\t\treturn -1;\n \tif (git_gpg_config(var, value, cb) < 0)\n \t\treturn -1;\n \treturn git_diff_ui_config(var, value, cb);\n@@ -536,6 +534,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.simplify_history = 0;\n \tmemset(&opt, 0, sizeof(opt));\n@@ -650,6 +650,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \n \tmemset(&match_all, 0, sizeof(match_all));\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.always_show_header = 1;\n \trev.no_walk = 1;\n@@ -733,6 +735,8 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n \tinit_reflog_walk(&rev.reflog_info);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.verbose_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -766,6 +770,8 @@ int cmd_log(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.always_show_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -1848,10 +1854,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \textra_hdr.strdup_strings = 1;\n \textra_to.strdup_strings = 1;\n \textra_cc.strdup_strings = 1;\n+\n \tinit_log_defaults();\n \tinit_display_notes(&notes_opt);\n \tgit_config(git_format_config, NULL);\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.show_notes = show_notes;\n \tmemcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));\n \trev.commit_format = CMIT_FMT_EMAIL;\ndiff --git a/grep.c b/grep.c\nindex 12b202598a9..8dfa0300786 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -19,27 +19,6 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)\n \tfwrite(buf, size, 1, stdout);\n }\n \n-static struct grep_opt grep_defaults = {\n-\t.relative = 1,\n-\t.pathname = 1,\n-\t.max_depth = -1,\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t.colors = {\n-\t\t[GREP_COLOR_CONTEXT] = \"\",\n-\t\t[GREP_COLOR_FILENAME] = \"\",\n-\t\t[GREP_COLOR_FUNCTION] = \"\",\n-\t\t[GREP_COLOR_LINENO] = \"\",\n-\t\t[GREP_COLOR_COLUMNNO] = \"\",\n-\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_SELECTED] = \"\",\n-\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN,\n-\t},\n-\t.only_matching = 0,\n-\t.color = -1,\n-\t.output = std_output,\n-};\n-\n static const char *color_grep_slots[] = {\n \t[GREP_COLOR_CONTEXT]\t    = \"context\",\n \t[GREP_COLOR_FILENAME]\t    = \"filename\",\n@@ -75,20 +54,12 @@ define_list_config_array_extra(color_grep_slots, {\"match\"});\n  */\n int grep_config(const char *var, const char *value, void *cb)\n {\n-\tstruct grep_opt *opt = &grep_defaults;\n+\tstruct grep_opt *opt = cb;\n \tconst char *slot;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\t/*\n-\t * The instance of grep_opt that we set up here is copied by\n-\t * grep_init() to be used by each individual invocation.\n-\t * When populating a new field of this structure here, be\n-\t * sure to think about ownership -- e.g., you might need to\n-\t * override the shallow copy in grep_init() with a deep copy.\n-\t */\n-\n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n \t\treturn 0;\n@@ -134,14 +105,10 @@ int grep_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/*\n- * Initialize one instance of grep_opt and copy the\n- * default values from the template we read the configuration\n- * information in an earlier call to git_config(grep_config).\n- */\n void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n-\t*opt = grep_defaults;\n+\tstruct grep_opt blank = GREP_OPT_INIT;\n+\tmemcpy(opt, &blank, sizeof(*opt));\n \n \topt->repo = repo;\n \topt->pattern_tail = &opt->pattern_list;\ndiff --git a/grep.h b/grep.h\nindex 62deadb885f..b651eb291f7 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -177,6 +177,27 @@ struct grep_opt {\n \tvoid *output_priv;\n };\n \n+#define GREP_OPT_INIT { \\\n+\t.relative = 1, \\\n+\t.pathname = 1, \\\n+\t.max_depth = -1, \\\n+\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n+\t.colors = { \\\n+\t\t[GREP_COLOR_CONTEXT] = \"\", \\\n+\t\t[GREP_COLOR_FILENAME] = \"\", \\\n+\t\t[GREP_COLOR_FUNCTION] = \"\", \\\n+\t\t[GREP_COLOR_LINENO] = \"\", \\\n+\t\t[GREP_COLOR_COLUMNNO] = \"\", \\\n+\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_SELECTED] = \"\", \\\n+\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n+\t}, \\\n+\t.only_matching = 0, \\\n+\t.color = -1, \\\n+\t.output = std_output, \\\n+}\n+\n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n-- \n2.34.1.1239.g84ae229c870\n\n"},{"id":"444981","messageId":"patch-v6-7.7-88dfd40bf9e-20211226T223035Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v6-0.7-00000000000-20211226T223035Z-avarab@gmail.com","subject":"[PATCH v6 7/7] grep: simplify config parsing and option parsing","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-26T22:37:19Z","receivedAt":"2021-12-26T22:37:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Simplify the parsing of \"grep.patternType\" and\n\"grep.extendedRegexp\". This changes no behavior, but gets rid of\ncomplex parsing logic that isn't needed anymore.\n\nWhen \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\ngrep.patternType configuration setting, 2012-08-03) we promised that:\n\n 1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n    will return to the default matching behavior\".\n\n    In that context \"the default\" meant whatever the configuration\n    system specified before that change, i.e. via grep.extendedRegexp.\n\n 2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n    it when the new \"grep.patternType\" option is set. We said we'd\n    only ignore the older \"grep.extendedRegexp\" option \"when the\n    `grep.patternType` option is set. to a value other than\n    'default'\".\n\nIn a preceding commit we changed grep_config() to be called after\ngrep_init(), which means that much of the complexity here can go\naway.\n\nAs before \"grep.extendedRegexp\" is a last-one-wins variable. We need\nto maintain state inside parse_pattern_type_arg() to ignore it if a\nnon-\"default\" grep.patternType was seen, but otherwise flip between\nBRE and ERE for \"grep.extendedRegexp=[false|true]\".\n\nSee my 07a3d411739 (grep: remove regflags from the public grep_opt\nAPI, 2017-06-29) for addition of the two comments being removed here,\ni.e. the complexity noted in that commit is now going away.\n\nWe don't need grep_commit_pattern_type() anymore, we can instead have\nOPT_SET_INT() in \"builtin/grep.c\" manipulate the \"pattern_type_option\"\nmember in \"struct grep_opt\" directly.\n\nWe can also do away with the indirection of the \"int fixed\" and \"int\npcre2\" members in favor of using \"pattern_type_option\" directly in\n\"grep.c\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 10 +++---\n grep.c         | 83 ++++++++++++--------------------------------------\n grep.h         |  9 ++----\n revision.c     |  2 --\n 4 files changed, 26 insertions(+), 78 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 0ea124321b6..942c4b25077 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -845,7 +845,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tint i;\n \tint dummy;\n \tint use_index = 1;\n-\tint pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;\n \tint allow_revs;\n \n \tstruct option options[] = {\n@@ -879,16 +878,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"descend at most <depth> levels\"), PARSE_OPT_NONEG,\n \t\t\tNULL, 1 },\n \t\tOPT_GROUP(\"\"),\n-\t\tOPT_SET_INT('E', \"extended-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('E', \"extended-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use extended POSIX regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_ERE),\n-\t\tOPT_SET_INT('G', \"basic-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('G', \"basic-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use basic POSIX regular expressions (default)\"),\n \t\t\t    GREP_PATTERN_TYPE_BRE),\n-\t\tOPT_SET_INT('F', \"fixed-strings\", &pattern_type_arg,\n+\t\tOPT_SET_INT('F', \"fixed-strings\", &opt.pattern_type_option,\n \t\t\t    N_(\"interpret patterns as fixed strings\"),\n \t\t\t    GREP_PATTERN_TYPE_FIXED),\n-\t\tOPT_SET_INT('P', \"perl-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('P', \"perl-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use Perl-compatible regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_PCRE),\n \t\tOPT_GROUP(\"\"),\n@@ -982,7 +981,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, grep_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH |\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n-\tgrep_commit_pattern_type(pattern_type_arg, &opt);\n \n \tif (use_index && !startup_info->have_repository) {\n \t\tint fallback = 0;\ndiff --git a/grep.c b/grep.c\nindex 8dfa0300786..e964f402472 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -33,9 +33,7 @@ static const char *color_grep_slots[] = {\n \n static int parse_pattern_type_arg(const char *opt, const char *arg)\n {\n-\tif (!strcmp(arg, \"default\"))\n-\t\treturn GREP_PATTERN_TYPE_UNSPECIFIED;\n-\telse if (!strcmp(arg, \"basic\"))\n+\tif (!strcmp(arg, \"basic\"))\n \t\treturn GREP_PATTERN_TYPE_BRE;\n \telse if (!strcmp(arg, \"extended\"))\n \t\treturn GREP_PATTERN_TYPE_ERE;\n@@ -61,11 +59,25 @@ int grep_config(const char *var, const char *value, void *cb)\n \t\treturn -1;\n \n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n+\t\tif (opt->extended_regexp_option == -1)\n+\t\t\treturn 0;\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n+\t\tif (opt->extended_regexp_option)\n+\t\t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n+\t\telse\n+\t\t\topt->pattern_type_option = GREP_PATTERN_TYPE_BRE;\n+\t\treturn 0;\n+\t}\n+\n+\tif (!strcmp(var, \"grep.patterntype\") &&\n+\t    !strcmp(value, \"default\")) {\n+\t\topt->pattern_type_option = opt->extended_regexp_option == 1\n+\t\t\t? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(var, \"grep.patterntype\")) {\n+\t\topt->extended_regexp_option = -1; /* ignore */\n \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n \t\treturn 0;\n \t}\n@@ -115,62 +127,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo)\n \topt->header_tail = &opt->header_list;\n }\n \n-static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\t/*\n-\t * When committing to the pattern type by setting the relevant\n-\t * fields in grep_opt it's generally not necessary to zero out\n-\t * the fields we're not choosing, since they won't have been\n-\t * set by anything. The extended_regexp_option field is the\n-\t * only exception to this.\n-\t *\n-\t * This is because in the process of parsing grep.patternType\n-\t * & grep.extendedRegexp we set opt->pattern_type_option and\n-\t * opt->extended_regexp_option, respectively. We then\n-\t * internally use opt->extended_regexp_option to see if we're\n-\t * compiling an ERE. It must be unset if that's not actually\n-\t * the case.\n-\t */\n-\tif (pattern_type != GREP_PATTERN_TYPE_ERE &&\n-\t    opt->extended_regexp_option)\n-\t\topt->extended_regexp_option = 0;\n-\n-\tswitch (pattern_type) {\n-\tcase GREP_PATTERN_TYPE_UNSPECIFIED:\n-\t\t/* fall through */\n-\n-\tcase GREP_PATTERN_TYPE_BRE:\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_ERE:\n-\t\topt->extended_regexp_option = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_FIXED:\n-\t\topt->fixed = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_PCRE:\n-\t\topt->pcre2 = 1;\n-\t\tbreak;\n-\t}\n-}\n-\n-void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\tif (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(pattern_type, opt);\n-\telse if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(opt->pattern_type_option, opt);\n-\telse if (opt->extended_regexp_option)\n-\t\t/*\n-\t\t * This branch *must* happen after setting from the\n-\t\t * opt->pattern_type_option above, we don't want\n-\t\t * grep.extendedRegexp to override grep.patternType!\n-\t\t */\n-\t\tgrep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);\n-}\n-\n static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,\n \t\t\t\t\tconst char *origin, int no,\n \t\t\t\t\tenum grep_pat_token t,\n@@ -490,9 +446,10 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \n \tp->word_regexp = opt->word_regexp;\n \tp->ignore_case = opt->ignore_case;\n-\tp->fixed = opt->fixed;\n+\tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\n \n-\tif (memchr(p->pattern, 0, p->patternlen) && !opt->pcre2)\n+\tif (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE &&\n+\t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n \tp->is_fixed = is_fixed(p->pattern, p->patternlen);\n@@ -543,14 +500,14 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \t\treturn;\n \t}\n \n-\tif (opt->pcre2) {\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_PCRE) {\n \t\tcompile_pcre2_pattern(p, opt);\n \t\treturn;\n \t}\n \n \tif (p->ignore_case)\n \t\tregflags |= REG_ICASE;\n-\tif (opt->extended_regexp_option)\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_ERE)\n \t\tregflags |= REG_EXTENDED;\n \terr = regcomp(&p->regexp, p->pattern, regflags);\n \tif (err) {\ndiff --git a/grep.h b/grep.h\nindex b651eb291f7..ab2ce833b40 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -94,8 +94,7 @@ enum grep_expr_node {\n };\n \n enum grep_pattern_type {\n-\tGREP_PATTERN_TYPE_UNSPECIFIED = 0,\n-\tGREP_PATTERN_TYPE_BRE,\n+\tGREP_PATTERN_TYPE_BRE = 0,\n \tGREP_PATTERN_TYPE_ERE,\n \tGREP_PATTERN_TYPE_FIXED,\n \tGREP_PATTERN_TYPE_PCRE\n@@ -143,7 +142,6 @@ struct grep_opt {\n \tint unmatch_name_only;\n \tint count;\n \tint word_regexp;\n-\tint fixed;\n \tint all_match;\n #define GREP_BINARY_DEFAULT\t0\n #define GREP_BINARY_NOMATCH\t1\n@@ -152,7 +150,6 @@ struct grep_opt {\n \tint allow_textconv;\n \tint extended;\n \tint use_reflog_filter;\n-\tint pcre2;\n \tint relative;\n \tint pathname;\n \tint null_following_name;\n@@ -162,7 +159,7 @@ struct grep_opt {\n \tint funcname;\n \tint funcbody;\n \tint extended_regexp_option;\n-\tint pattern_type_option;\n+\tenum grep_pattern_type pattern_type_option;\n \tint ignore_locale;\n \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n \tunsigned pre_context;\n@@ -181,7 +178,6 @@ struct grep_opt {\n \t.relative = 1, \\\n \t.pathname = 1, \\\n \t.max_depth = -1, \\\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n \t.colors = { \\\n \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n \t\t[GREP_COLOR_FILENAME] = \"\", \\\n@@ -200,7 +196,6 @@ struct grep_opt {\n \n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n-void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\n void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex 495328e859c..298d0ea7574 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2860,8 +2860,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \n \tdiff_setup_done(&revs->diffopt);\n \n-\tgrep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t\t\t\t &revs->grep_filter);\n \tif (!is_encoding_utf8(get_log_output_encoding()))\n \t\trevs->grep_filter.ignore_locale = 1;\n \tcompile_grep_patterns(&revs->grep_filter);\n-- \n2.34.1.1239.g84ae229c870\n\n"},{"id":"444983","messageId":"211227.86czljez86.gmgdl@evledraar.gmail.com","threadId":"56853","inReplyTo":"xmqqa6gp35a6.fsf_-_@gitster.g","subject":"Re: [RFC/PATCH] grep: allow scripts to ignore configured pattern type","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-26T23:09:05Z","receivedAt":"2021-12-26T23:13:50Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Dec 24 2021, Junio C Hamano wrote:\n\n> We made a mistake to add grep.extendedRegexp configuration variable\n> long time ago, and made things even worse by introducing an even\n> more generalized grep.patternType configuration variable.\n>\n> This was mostly because interactive users were lazy and wanted a way\n> to declare \"I do not live in the ancient age, and my regexps are\n> always extended\" and write \"git grep\" without having to type three\n> more letters \" -E\" on the command line.\n>\n> But this in turn forces script writers to always specify what kind\n> of patterns they are writing, because without such command line\n> override, the interpretation of the patterns they write in their\n> scripts will be affected by the configuration variables of the user\n> who is running their script.\n>\n> Introduce GIT_DISABLE_GREP_PATTERN_CONFIG environment variable that\n> script writers can set to \"true\" and export at the very beginning of\n> their script to defeat grep.extendedRegexp and grep.patternType\n> configuration variables.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>\n>  * This is merely a weather balloon without proper documentation and\n>    test.  It might be even better idea to make such an environment\n>    variable to _specify_ what kind of pattern the script uses,\n>    instead of \"we defeat end-user configuration and now we are\n>    forced to write in basic or have to write -E/-P etc.\", which is\n>    what this patch does.\n\nYou note the lack of documentation. I do think anything in this\ndirection would do well to:\n\n * Specify what it is we're promising now exactly. The git-grep\n   command is in \"main porcelain\" now, this change sounds like we're\n   promising to make its output more plumbing-like.\n\n * As an aside I think a good follow-up to my series would be to\n   just start warning() and eventually die()-ing on grep.extendedRegexp\n   which would make this a bit simpler.\n\n * A \"GIT_DISABLE_GREP_PATTERN_CONFIG\" seems overly narrow. Just a few lines\n   from the code being patched here we read the grep.lineNumber config, which is\n   similarly annoying if you're parsing the \"git grep\" output, so at least a\n   \"GIT_DISABLE_GREP_CONFIG\" would be handy.\n\n * But more generally we've had discussions on and off on-list about supporting\n   a generic way to disable reading the config. Supporting e.g. \"git --no-config\" or\n   a \"GIT_NO_CONFIG\" would be handy, even if all it did for now (and we could document\n   it as such) would be to change the behavior of grep.\n \n\n>  grep.c | 11 +++++++++--\n>  1 file changed, 9 insertions(+), 2 deletions(-)\n>\n> diff --git a/grep.c b/grep.c\n> index fe847a0111..0cfb698b51 100644\n> --- a/grep.c\n> +++ b/grep.c\n> @@ -77,10 +77,15 @@ int grep_config(const char *var, const char *value, void *cb)\n>  {\n>  \tstruct grep_opt *opt = &grep_defaults;\n>  \tconst char *slot;\n> +\tstatic int disable_pattern_type_config = -1;\n>  \n>  \tif (userdiff_config(var, value) < 0)\n>  \t\treturn -1;\n>  \n> +\tif (disable_pattern_type_config < 0)\n> +\t\tdisable_pattern_type_config =\n> +\t\t\tgit_env_bool(\"GIT_DISABLE_GREP_PATTERN_CONFIG\", 0);\n> +\n>  \t/*\n>  \t * The instance of grep_opt that we set up here is copied by\n>  \t * grep_init() to be used by each individual invocation.\n> @@ -90,12 +95,14 @@ int grep_config(const char *var, const char *value, void *cb)\n>  \t */\n>  \n>  \tif (!strcmp(var, \"grep.extendedregexp\")) {\n> -\t\topt->extended_regexp_option = git_config_bool(var, value);\n> +\t\tif (!disable_pattern_type_config)\n> +\t\t\topt->extended_regexp_option = git_config_bool(var, value);\n>  \t\treturn 0;\n>  \t}\n>  \n>  \tif (!strcmp(var, \"grep.patterntype\")) {\n> -\t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n> +\t\tif (!disable_pattern_type_config)\n> +\t\t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n>  \t\treturn 0;\n>  \t}\n\n"},{"id":"444993","messageId":"xmqqpmpid1jc.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v6-7.7-88dfd40bf9e-20211226T223035Z-avarab@gmail.com","subject":"Re: [PATCH v6 7/7] grep: simplify config parsing and option parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-12-27T06:06:47Z","receivedAt":"2021-12-27T06:06:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> @@ -143,7 +142,6 @@ struct grep_opt {\n>  \tint unmatch_name_only;\n>  \tint count;\n>  \tint word_regexp;\n> -\tint fixed;\n>  \tint all_match;\n>  #define GREP_BINARY_DEFAULT\t0\n>  #define GREP_BINARY_NOMATCH\t1\n> @@ -152,7 +150,6 @@ struct grep_opt {\n>  \tint allow_textconv;\n>  \tint extended;\n>  \tint use_reflog_filter;\n> -\tint pcre2;\n>  \tint relative;\n>  \tint pathname;\n>  \tint null_following_name;\n> @@ -162,7 +159,7 @@ struct grep_opt {\n>  \tint funcname;\n>  \tint funcbody;\n>  \tint extended_regexp_option;\n> -\tint pattern_type_option;\n> +\tenum grep_pattern_type pattern_type_option;\n>  \tint ignore_locale;\n>  \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n>  \tunsigned pre_context;\n> @@ -181,7 +178,6 @@ struct grep_opt {\n>  \t.relative = 1, \\\n>  \t.pathname = 1, \\\n>  \t.max_depth = -1, \\\n> -\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n>  \t.colors = { \\\n>  \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n>  \t\t[GREP_COLOR_FILENAME] = \"\", \\\n\nI very much like the lossage of redundant fixed and pcre2 members.\n\nAs I kept telling you, we still need a separate bit to keep track of\nthe last value of grep.extendedRegexp, but the primary mechanism to\ndetermine what pattern type to use should be a single enum that is\npattern_type.  When we see \"fixed\", \"pcre\", \"-G\", etc. from\ngrep.patternType config or from command line, we can stuff their\nenum values in pattern_type member of this struct, and when we see\n\"default\", we need to leave \"default\" in pattern_type member until\nwe see the last definition of grep.extendedRegexp, at which time\nwe can turn it into either \"basic\" or \"extended\".\n\nSo having only two members is absolutely the right thing to do.\n\nBut this part convinces me that whatever this patch does, it will\nnot possible be capable of doing the right thing.  You cannot\nimplement \"we have to remember that the last grep.patternType we saw\nwas DEFAULT and in that case we cannot decide the real pattern type\nuntil we see the last definition of grep.extendedRegexp, which may\nbe well after we saw the last grep.patternType definition\" without a\nvalue in this enum to express that the last value we saw was DEFAULT.\n\n>  enum grep_pattern_type {\n> -\tGREP_PATTERN_TYPE_UNSPECIFIED = 0,\n> -\tGREP_PATTERN_TYPE_BRE,\n> +\tGREP_PATTERN_TYPE_BRE = 0,\n>  \tGREP_PATTERN_TYPE_ERE,\n>  \tGREP_PATTERN_TYPE_FIXED,\n>  \tGREP_PATTERN_TYPE_PCRE\n\n> @@ -982,7 +981,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n>  \targc = parse_options(argc, argv, prefix, options, grep_usage,\n>  \t\t\t     PARSE_OPT_KEEP_DASHDASH |\n>  \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n> -\tgrep_commit_pattern_type(pattern_type_arg, &opt);\n\nIn other words, this lossage is likely wrong.  Let's keep reading\nand see how well the config reader in this patch does. \n\n> @@ -61,11 +59,25 @@ int grep_config(const char *var, const char *value, void *cb)\n>  \t\treturn -1;\n>  \n>  \tif (!strcmp(var, \"grep.extendedregexp\")) {\n> +\t\tif (opt->extended_regexp_option == -1)\n> +\t\t\treturn 0;\n>  \t\topt->extended_regexp_option = git_config_bool(var, value);\n> +\t\tif (opt->extended_regexp_option)\n> +\t\t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n> +\t\telse\n> +\t\t\topt->pattern_type_option = GREP_PATTERN_TYPE_BRE;\n> +\t\treturn 0;\n> +\t}\n> +\tif (!strcmp(var, \"grep.patterntype\") &&\n> +\t    !strcmp(value, \"default\")) {\n> +\t\topt->pattern_type_option = opt->extended_regexp_option == 1\n> +\t\t\t? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n>  \t\treturn 0;\n>  \t}\n>  \n>  \tif (!strcmp(var, \"grep.patterntype\")) {\n> +\t\topt->extended_regexp_option = -1; /* ignore */\n>  \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n>  \t\treturn 0;\n>  \t}\n\nThe above does not look correct at all.\n\nWhat happens when the configuration parser sees these configuration\nvariables in this sequence:\n\n - grep.patternType set to say \"pcre\" (or anything not \"default\").\n - grep.extendedRegexp set to \"true\".\n - grep.patternType set to \"default\".\n\nAfter these three variable definitions with the usual \"last one\nwins\" (for each variable independently), the last value for the\ngrep.patternType variable is \"default\", and the last value for\nthe grep.extendedRegexp variable is \"true\".  The user wants to use\nthe ERE patterns.\n\nThe way the above code would work on this three variable definition\nsequence, as far as I read it, would however not give us the desired\nbehaviour.  First we drop extended_regexp_option member to -1 while\nsetting PCRE to attern_type_option member, and then grep.extendedRegexp\nis totally ignored, and then we see patterntype set to default and\nnotice extended_regexp_option is *NOT* 1 (because you ignored it and\nleft it to -1), and end up using BRE, no?\n\nI agree 100% with the direction that .fixed and .pcre2 members that\nwere added over time to the struct are redundant and it is a very\ngood idea to get rid of them.  But we need to keep track of two\nconfiguration variables separately to allow them the \"last one wins\"\nsemantics independently, and for that, you cannot lose the \"default\"\nvalue from the enum.  It is impossible not to store the fact that\n\"default\" was the last value so far we saw for grep.patternType\nbecause you do not know, at the point of seeing \"default\", what the\nfinal value for grep.extendedRegexp will be.  If you want to correctly\nimplement the interaction between two variables without regression,\nthat is.\n"},{"id":"445007","messageId":"xmqq4k6tyj8r.fsf@gitster.g","threadId":"56853","inReplyTo":"xmqqpmpid1jc.fsf@gitster.g","subject":"Re: [PATCH v6 7/7] grep: simplify config parsing and option parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-12-27T18:51:00Z","receivedAt":"2021-12-27T18:51:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> The above does not look correct at all.\n>\n> What happens when the configuration parser sees these configuration\n> variables in this sequence:\n>\n>  - grep.patternType set to say \"pcre\" (or anything not \"default\").\n>  - grep.extendedRegexp set to \"true\".\n>  - grep.patternType set to \"default\".\n>\n> After these three variable definitions with the usual \"last one\n> wins\" (for each variable independently), the last value for the\n> grep.patternType variable is \"default\", and the last value for\n> the grep.extendedRegexp variable is \"true\".  The user wants to use\n> the ERE patterns.\n\nBy the way, the example I gave you for the previous round, and\nsimilarly the one in the message I am responding to were all written\nto help you realize that it is simply a broken approach if we do not\nkeep \"default\" as default and instead resolve it to either \"basic\"\nor \"extended\" too early.  The goal of these examples was *NOT* to\ntell you \"this single thing is broken with the code in this round so\nlet's fix it\".\n\nIt seems I am not succeeding in conveying that point, and specially\nI smell that in the change between v5 and v6.\n\nSo let me try to be a bit more explicit.  Let's not do another round\nof \"I think this is a moral equivalent of what you want, even though\nit is not done the way you suggested.\" I think we wasted a reroll or\nthree with that attitude in changes leading to v6 already, after I\ngave my review to v5, and I think the v5 review essentially was a\nrepeat of my review for v3's 3/7, so if I conveyed the point clearly\nenough back then, perhaps we didn't have to waste your time on v4\nand v5, either.  Sorry about that.\n\nSo, here is what this step of the series SHOULD do:\n\n * Use two members to keep track of the final configuration value we\n   saw for grep.patternTYpe and grep.extendedRegexp independently.\n   The existing .fixed and .pcre2 fields are superfluous.  But no\n   more \"ah, we see patternType so let's ignore extendedRegexp\"\n   games.\n\n * When parsing the command line options -G, -E, etc., update the\n   .patternType member with the value found.  We do not want to and\n   need to touch .extendedRegexp member, whose SOLE purpose should\n   be to keep track of \"what the last value we saw for\n   grep.extendedRegexp configuration variable\".\n\n * Do ALL THE ABOVE while keeping \"default\" in the .patternType\n   member as \"default\" as-is given by the user; do not turn it into\n   \"basic\" or \"extended\" in config callback at all.\n\n * At some point of your choice between the time we finished parsing\n   both configuration variables and command line options and the\n   time we compile the pattern string to regexp objects of various\n   types, look at the .patternType member and resolve it into\n   basic/extended IFF it is set to default, using .extendedRegexp\n   member (for this to work correctly, it is important not to let\n   -E/-G command like options to touch .extendedRegexp member---it\n   should be used ONLY to keep track of \"what the last value we saw\n   for grep.extendedRegexp configuration variable\").\n\n * After the above step is done, .extendedRegexp member is no longer\n   needed and we can compile the pattern using only the value in\n   .patternType member.\n\nThe penultimate bullet point gives us a wiggle room to lose the\n\"commit\" thing and delay it until the very last moment, the function\nthat decides to call which regexp engine's regcomp.  The important\nthing is that we cannot lose the value \"default\" from .patternType\nfield or lose the last value given to .extendedRegexp field too\nearly, namely, before we have read all the configurtion streams and\nknow the last value for these two variables.\n\nThanks.  Hopefully I was clear enough this time.\n\n----- >8 ---- ----- >8 ---- ----- >8 ---- ----- >8 ---- ----- >8 -----\nSubject: [PATCH] fixup! grep tests: add missing \"grep.patternType\" config tests\n\n---\n t/t7810-grep.sh | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 664f884e12..2e2829ee55 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -471,6 +471,16 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=fixed \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n \t\techo \"${HC}ab:a+bc\" >expected &&\n \t\tgit \\\n-- \n2.34.1-568-g69e9fd72b5\n\n"},{"id":"445039","messageId":"patch-v7-01.10-b62e6b6162a-20211228T004707Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v7-00.10-00000000000-20211228T004707Z-avarab@gmail.com","subject":"[PATCH v7 01/10] grep.h: remove unused \"regex_t regexp\" from grep_opt","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-28T01:07:36Z","receivedAt":"2021-12-28T01:07:52Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This \"regex_t\" in grep_opt has not been used since\nf9b9faf6f8a (builtin-grep: allow more than one patterns., 2006-05-02),\nwe still use a \"regex_t\" for compiling regexes, but that's in the\n\"grep_pat\" struct\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 3e8815c347b..95cccb670f9 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -136,7 +136,6 @@ struct grep_opt {\n \n \tconst char *prefix;\n \tint prefix_length;\n-\tregex_t regexp;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n-- \n2.34.1.1250.g6a242c1e9ad\n\n"},{"id":"445040","messageId":"cover-v7-00.10-00000000000-20211228T004707Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v6-0.7-00000000000-20211226T223035Z-avarab@gmail.com","subject":"[PATCH v7 00/10] grep: simplify & delete \"init\" & \"config\" code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-28T01:07:35Z","receivedAt":"2021-12-28T01:07:52Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A re-roll that should *hopefully* address the comments Junio had in\nhttps://lore.kernel.org/git/xmqq4k6tyj8r.fsf@gitster.g/; To quote\nthose:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n> [...]\n> By the way, the example I gave you for the previous round, and\n> similarly the one in the message I am responding to were all written\n> to help you realize that it is simply a broken approach if we do not\n> keep \"default\" as default and instead resolve it to either \"basic\"\n> or \"extended\" too early.  The goal of these examples was *NOT* to\n> tell you \"this single thing is broken with the code in this round so\n> let's fix it\".\n\nYes, the v6 was broken. Sorry about that. Between re-rolling some\nother things and coming back to this series I managed to miss some of\nthose subtleties.\n\n> So let me try to be a bit more explicit.  Let's not do another round\n> of \"I think this is a moral equivalent of what you want, even though\n> it is not done the way you suggested.\" I think we wasted a reroll or\n> three with that attitude in changes leading to v6 already, after I\n> gave my review to v5, and I think the v5 review essentially was a\n> repeat of my review for v3's 3/7, so if I conveyed the point clearly\n> enough back then, perhaps we didn't have to waste your time on v4\n> and v5, either.  Sorry about that.\n>\n> So, here is what this step of the series SHOULD do:\n\nSo, at the risk of another wasted re-roll this doesn't exactly\nimplement what you suggested, but I think it'll finally cover all the\nbasis of being bug-for-bug compatible with the old implementation now.\n\nI started this re-roll by implementing it exactly as you suggested,\nalong with new tests (both your fixup, and more), but as the updated\ncommit message in 09/10 details found that I could convert it back to\na state machine around a static variable in \"grep_config()\", which has\nthe advantage of getting rid of more \"struct grep_opt\" fields annd\nnarrowing the behavior to just that function.\n\nMore comments on the range-diff below:\n\nÆvar Arnfjörð Bjarmason (10):\n  grep.h: remove unused \"regex_t regexp\" from grep_opt\n  log tests: check if grep_config() is called by \"log\"-like cmds\n\nNo changes.\n\n  grep tests: add missing \"grep.patternType\" config tests\n\nA couple of new tests.\n\n  built-ins: trust the \"prefix\" from run_builtin()\n  grep.c: don't pass along NULL callback value\n  grep API: call grep_config() after grep_init()\n\nNo changes.\n\n  grep.h: make \"grep_opt.pattern_type_option\" use its enum\n  grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"\n\nI split these two off from the previous tip commit to make the diff\nfor the next one smaller.\n\n  grep: simplify config parsing and option parsing\n\nChanged, as noted above.\n\n  grep.[ch]: remove GREP_PATTERN_TYPE_UNSPECIFIED\n\nWith that new behavior we can also get rid of\nGREP_PATTERN_TYPE_UNSPECIFIED. It's still implicitly there as == 0,\nbut for a non-switch'd enum type treating these as \"flags\" makes more\nsense, and makes the code in grep_config() more straightforward &\nbrief.\n\n builtin/grep.c    |  27 +++++-----\n builtin/log.c     |  13 ++++-\n builtin/ls-tree.c |   2 +-\n git.c             |   1 +\n grep.c            | 126 +++++++++-------------------------------------\n grep.h            |  34 +++++++++----\n revision.c        |   4 +-\n t/t4202-log.sh    |  24 +++++++++\n t/t7810-grep.sh   |  68 +++++++++++++++++++++++++\n 9 files changed, 168 insertions(+), 131 deletions(-)\n\nRange-diff against v6:\n 1:  b62e6b6162a =  1:  b62e6b6162a grep.h: remove unused \"regex_t regexp\" from grep_opt\n 2:  0edcdb50afd =  2:  0edcdb50afd log tests: check if grep_config() is called by \"log\"-like cmds\n 3:  1b724d5e2e9 !  3:  e1b4b5b77e0 grep tests: add missing \"grep.patternType\" config tests\n    @@ t/t7810-grep.sh: do\n     +\t\ttest_cmp expected actual\n     +\t'\n     +\n    ++\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n    ++\t\techo \"${HC}ab:abc\" >expected &&\n    ++\t\tgit \\\n    ++\t\t\t-c grep.patternType=fixed \\\n    ++\t\t\t-c grep.extendedRegexp=true \\\n    ++\t\t\t-c grep.patternType=default \\\n    ++\t\t\tgrep \"a+b*c\" $H ab >actual &&\n    ++\t\ttest_cmp expected actual\n    ++\t'\n    ++\n    ++\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (ERE)\" '\n    ++\t\techo \"${HC}ab:a+bc\" >expected &&\n    ++\t\tgit \\\n    ++\t\t\t-c grep.patternType=default \\\n    ++\t\t\t-c grep.extendedRegexp=true \\\n    ++\t\t\t-c grep.patternType=basic \\\n    ++\t\t\tgrep \"a+b*c\" $H ab >actual &&\n    ++\t\ttest_cmp expected actual\n    ++\t'\n    ++\n     +\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n     +\t\techo \"${HC}ab:a+bc\" >expected &&\n     +\t\tgit \\\n    @@ t/t7810-grep.sh: do\n      \ttest_expect_success \"grep $L with grep.patternType=extended and grep.extendedRegexp=false\" '\n      \t\techo \"${HC}ab:abc\" >expected &&\n      \t\tgit \\\n    +@@ t/t7810-grep.sh: do\n    + \t\ttest_cmp expected actual\n    + \t'\n    + \n    ++\ttest_expect_success \"grep $L with grep.extendedRegexp=false and grep.patternType=default\" '\n    ++\t\techo \"${HC}ab:abc\" >expected &&\n    ++\t\tgit \\\n    ++\t\t\t-c grep.extendedRegexp=false \\\n    ++\t\t\t-c grep.patternType=extended \\\n    ++\t\t\tgrep \"a+b*c\" $H ab >actual &&\n    ++\t\ttest_cmp expected actual\n    ++\t'\n    ++\n    + \ttest_expect_success \"grep $L with grep.extendedRegexp=true and grep.patternType=basic\" '\n    + \t\techo \"${HC}ab:a+bc\" >expected &&\n    + \t\tgit \\\n 4:  f4876552771 =  4:  6d91a765fd7 built-ins: trust the \"prefix\" from run_builtin()\n 5:  069b0339146 =  5:  844b4727ca3 grep.c: don't pass along NULL callback value\n 6:  e38eca56959 =  6:  d9cf9bf5e37 grep API: call grep_config() after grep_init()\n -:  ----------- >  7:  57ecc5c0d65 grep.h: make \"grep_opt.pattern_type_option\" use its enum\n -:  ----------- >  8:  7dbeafde26b grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"\n 7:  88dfd40bf9e !  9:  c6ca39b4554 grep: simplify config parsing and option parsing\n    @@ Commit message\n         grep_init(), which means that much of the complexity here can go\n         away.\n     \n    -    As before \"grep.extendedRegexp\" is a last-one-wins variable. We need\n    -    to maintain state inside parse_pattern_type_arg() to ignore it if a\n    -    non-\"default\" grep.patternType was seen, but otherwise flip between\n    -    BRE and ERE for \"grep.extendedRegexp=[false|true]\".\n    +    As before both \"grep.patternType\" and \"grep.extendedRegexp\" are\n    +    last-one-wins variable, with \"grep.extendedRegexp\" yielding to\n    +    \"grep.patternType\", except when \"grep.patternType=default\".\n    +\n    +    Note that this applies as we parse the config, i.e. a sequence of:\n    +\n    +        -c grep.patternType=perl\n    +        -c grep.extendedRegexp=true \\\n    +        -c grep.patternType=default\n    +\n    +    Should select ERE due to \"grep.extendedRegexp=true and\n    +    grep.extendedRegexp=default\", not BRE, even though that's the\n    +    \"default\" patternType. We can determine this as we parse the config,\n    +    because:\n    +\n    +     * If we see \"grep.extendedRegexp\" we set the internal \"ero\" to its\n    +       boolean value.\n    +\n    +     * If we see \"grep.extendedRegexp\" but\n    +       \"grep.patternType=[default|<unset>]\" is in effect we *don't* set\n    +       the internal \"pattern_type_option\" to update the pattern type.\n    +\n    +     * If we see \"grep.patternType!=default\" we can set our internal\n    +       \"pattern_type_option\" directly, it doesn't matter what the state of\n    +       \"grep.extendedRegexp\" is, but we don't forget what it was, in case\n    +       we see a \"grep.patternType=default\" again.\n    +\n    +     * If we see a \"grep.patternType=default\" we can set the pattern to\n    +       ERE or BRE depending on whether we last saw a\n    +       \"grep.extendedRegexp=true\" or\n    +       \"grep.extendedRegexp=[false|<unset>]\".\n    +\n    +    We could equally call this new adjust_pattern_type() in\n    +    compile_regexp(), i.e. this fixup on top of this passes all our\n    +    tests (with -U0 for brevity):\n    +\n    +        @@ -60,0 +61 @@ static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n    +        +static int ero = -1;\n    +        @@ -65 +65,0 @@ int grep_config(const char *var, const char *value, void *cb)\n    +        -       static int ero = -1;\n    +        @@ -72 +71,0 @@ int grep_config(const char *var, const char *value, void *cb)\n    +        -               adjust_pattern_type(&opt->pattern_type_option, ero);\n    +        @@ -80 +78,0 @@ int grep_config(const char *var, const char *value, void *cb)\n    +        -               adjust_pattern_type(&opt->pattern_type_option, ero);\n    +        @@ -445,0 +444,2 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n    +        +       if (ero != -1)\n    +        +               adjust_pattern_type(&opt->pattern_type_option, ero);\n    +\n    +    But doing it as we stream the git_config() makes it\n    +    clear that we can determine the interplay between these two variables\n    +    as we go. We don't need to wait until we see the last value of the two\n    +    configuration variables.\n    +\n    +    This is true because of the rationale above, and because the\n    +    subsequent code in compile_regexp() treats\n    +    \"pattern_type_option=GREP_PATTERN_TYPE_{UNSPECIFIED,BRE}\"\n    +    equally. I.e. we'll end up with different internal\n    +    \"\"pattern_type_option\" values there for:\n    +\n    +        # UNSPECIFIED\n    +        -c grep.patternType=default\n    +        # BRE\n    +        -c grep.extendedRegexp=false -c grep.patternType=default\n    +\n    +    But the difference won't matter, which simplifies some of this logic,\n    +    we never need to adjust a \"grep.patternType\" if we didn't see a\n    +    \"grep.extendedRegexp\" before. We can also remove the\n    +    \"extended_regexp_option\" member from \"struct grep_opt\" in favor of a\n    +    static variable in grep_config().\n    +\n    +    The command-line parsing in cmd_grep() can then completely ignore\n    +    \"grep.extendedRegexp\". Whatever effect it had before that step won't\n    +    matter if we see -G, -E, -P etc.\n     \n         See my 07a3d411739 (grep: remove regflags from the public grep_opt\n         API, 2017-06-29) for addition of the two comments being removed here,\n         i.e. the complexity noted in that commit is now going away.\n     \n    -    We don't need grep_commit_pattern_type() anymore, we can instead have\n    -    OPT_SET_INT() in \"builtin/grep.c\" manipulate the \"pattern_type_option\"\n    -    member in \"struct grep_opt\" directly.\n    -\n    -    We can also do away with the indirection of the \"int fixed\" and \"int\n    -    pcre2\" members in favor of using \"pattern_type_option\" directly in\n    -    \"grep.c\".\n    -\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/grep.c ##\n    @@ builtin/grep.c: int cmd_grep(int argc, const char **argv, const char *prefix)\n      \t\tint fallback = 0;\n     \n      ## grep.c ##\n    -@@ grep.c: static const char *color_grep_slots[] = {\n    +@@ grep.c: static int parse_pattern_type_arg(const char *opt, const char *arg)\n      \n    - static int parse_pattern_type_arg(const char *opt, const char *arg)\n    - {\n    --\tif (!strcmp(arg, \"default\"))\n    --\t\treturn GREP_PATTERN_TYPE_UNSPECIFIED;\n    --\telse if (!strcmp(arg, \"basic\"))\n    -+\tif (!strcmp(arg, \"basic\"))\n    - \t\treturn GREP_PATTERN_TYPE_BRE;\n    - \telse if (!strcmp(arg, \"extended\"))\n    - \t\treturn GREP_PATTERN_TYPE_ERE;\n    + define_list_config_array_extra(color_grep_slots, {\"match\"});\n    + \n    ++static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n    ++{\n    ++\tif (*pto == GREP_PATTERN_TYPE_UNSPECIFIED)\n    ++\t\t*pto = ero ? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n    ++}\n    ++\n    + /*\n    +  * Read the configuration file once and store it in\n    +  * the grep_defaults template.\n     @@ grep.c: int grep_config(const char *var, const char *value, void *cb)\n    + {\n    + \tstruct grep_opt *opt = cb;\n    + \tconst char *slot;\n    ++\tstatic int ero = -1;\n    + \n    + \tif (userdiff_config(var, value) < 0)\n      \t\treturn -1;\n      \n      \tif (!strcmp(var, \"grep.extendedregexp\")) {\n    -+\t\tif (opt->extended_regexp_option == -1)\n    -+\t\t\treturn 0;\n    - \t\topt->extended_regexp_option = git_config_bool(var, value);\n    -+\t\tif (opt->extended_regexp_option)\n    -+\t\t\topt->pattern_type_option = GREP_PATTERN_TYPE_ERE;\n    -+\t\telse\n    -+\t\t\topt->pattern_type_option = GREP_PATTERN_TYPE_BRE;\n    -+\t\treturn 0;\n    -+\t}\n    -+\n    -+\tif (!strcmp(var, \"grep.patterntype\") &&\n    -+\t    !strcmp(value, \"default\")) {\n    -+\t\topt->pattern_type_option = opt->extended_regexp_option == 1\n    -+\t\t\t? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n    +-\t\topt->extended_regexp_option = git_config_bool(var, value);\n    ++\t\tero = git_config_bool(var, value);\n    ++\t\tadjust_pattern_type(&opt->pattern_type_option, ero);\n      \t\treturn 0;\n      \t}\n      \n      \tif (!strcmp(var, \"grep.patterntype\")) {\n    -+\t\topt->extended_regexp_option = -1; /* ignore */\n      \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n    ++\t\tif (ero == -1)\n    ++\t\t\treturn 0;\n    ++\t\tadjust_pattern_type(&opt->pattern_type_option, ero);\n      \t\treturn 0;\n      \t}\n    + \n     @@ grep.c: void grep_init(struct grep_opt *opt, struct repository *repo)\n      \topt->header_tail = &opt->header_list;\n      }\n    @@ grep.c: static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n     -\tp->fixed = opt->fixed;\n     +\tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\n      \n    --\tif (memchr(p->pattern, 0, p->patternlen) && !opt->pcre2)\n    +-\tif (!opt->pcre2 &&\n     +\tif (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE &&\n    -+\t    memchr(p->pattern, 0, p->patternlen))\n    + \t    memchr(p->pattern, 0, p->patternlen))\n      \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n      \n    - \tp->is_fixed = is_fixed(p->pattern, p->patternlen);\n     @@ grep.c: static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n      \t\treturn;\n      \t}\n    @@ grep.c: static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n      \tif (err) {\n     \n      ## grep.h ##\n    -@@ grep.h: enum grep_expr_node {\n    - };\n    - \n    - enum grep_pattern_type {\n    --\tGREP_PATTERN_TYPE_UNSPECIFIED = 0,\n    --\tGREP_PATTERN_TYPE_BRE,\n    -+\tGREP_PATTERN_TYPE_BRE = 0,\n    - \tGREP_PATTERN_TYPE_ERE,\n    - \tGREP_PATTERN_TYPE_FIXED,\n    - \tGREP_PATTERN_TYPE_PCRE\n     @@ grep.h: struct grep_opt {\n      \tint unmatch_name_only;\n      \tint count;\n    @@ grep.h: struct grep_opt {\n      \tint pathname;\n      \tint null_following_name;\n     @@ grep.h: struct grep_opt {\n    + \tint max_depth;\n      \tint funcname;\n      \tint funcbody;\n    - \tint extended_regexp_option;\n    --\tint pattern_type_option;\n    -+\tenum grep_pattern_type pattern_type_option;\n    +-\tint extended_regexp_option;\n    + \tenum grep_pattern_type pattern_type_option;\n      \tint ignore_locale;\n      \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n    - \tunsigned pre_context;\n    -@@ grep.h: struct grep_opt {\n    - \t.relative = 1, \\\n    - \t.pathname = 1, \\\n    - \t.max_depth = -1, \\\n    --\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n    - \t.colors = { \\\n    - \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n    - \t\t[GREP_COLOR_FILENAME] = \"\", \\\n     @@ grep.h: struct grep_opt {\n      \n      int grep_config(const char *var, const char *value, void *);\n -:  ----------- > 10:  b764c09d2b7 grep.[ch]: remove GREP_PATTERN_TYPE_UNSPECIFIED\n-- \n2.34.1.1250.g6a242c1e9ad\n\n"},{"id":"445041","messageId":"patch-v7-02.10-0edcdb50afd-20211228T004707Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v7-00.10-00000000000-20211228T004707Z-avarab@gmail.com","subject":"[PATCH v7 02/10] log tests: check if grep_config() is called by \"log\"-like cmds","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-28T01:07:37Z","receivedAt":"2021-12-28T01:07:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the tests added in my 9df46763ef1 (log: add exhaustive tests\nfor pattern style options & config, 2017-05-20) to check not only\nwhether \"git log\" handles \"grep.patternType\", but also \"git show\"\netc.\n\nIt's sufficient to check whether we match a \"fixed\" or a \"basic\" regex\nhere to see if these codepaths correctly invoked grep_config(). We\ndon't need to check the details of their regular expression matching\nas the \"log\" test does.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4202-log.sh | 24 ++++++++++++++++++++++++\n 1 file changed, 24 insertions(+)\n\ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex 2ced7e9d817..2490f2cd5ed 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -449,6 +449,30 @@ test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurati\n \t)\n '\n \n+for cmd in show whatchanged reflog format-patch\n+do\n+\tcase \"$cmd\" in\n+\tformat-patch) myarg=\"HEAD~..\" ;;\n+\t*) myarg= ;;\n+\tesac\n+\n+\ttest_expect_success \"$cmd: understands grep.patternType, like 'log'\" '\n+\t\tgit init \"pattern-type-$cmd\" &&\n+\t\t(\n+\t\t\tcd \"pattern-type-$cmd\" &&\n+\t\t\ttest_commit 1 file A &&\n+\t\t\ttest_commit \"(1|2)\" file B 2 &&\n+\n+\t\t\tgit -c grep.patternType=fixed $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_must_be_empty actual &&\n+\n+\t\t\tgit -c grep.patternType=basic $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_file_not_empty actual\n+\t\t)\n+\t'\n+done\n+test_done\n+\n test_expect_success 'log --author' '\n \tcat >expect <<-\\EOF &&\n \tAuthor: <BOLD;RED>A U<RESET> Thor <author@example.com>\n-- \n2.34.1.1250.g6a242c1e9ad\n\n"},{"id":"445042","messageId":"patch-v7-03.10-e1b4b5b77e0-20211228T004707Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v7-00.10-00000000000-20211228T004707Z-avarab@gmail.com","subject":"[PATCH v7 03/10] grep tests: add missing \"grep.patternType\" config tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-28T01:07:38Z","receivedAt":"2021-12-28T01:07:59Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the grep tests to assert that setting\n\"grep.patternType=extended\" followed by \"grep.patternType=default\"\nwill behave as if \"--basic-regexp\" was provided, and not as\n\"--extended-regexp\". In a subsequent commit we'll need to treat\n\"grep.patternType=default\" as a special-case, but let's make sure we\nignore it if it's being set to \"default\" following an earlier\nnon-\"default\" \"grep.patternType\" setting.\n\nLet's also test what happens when we have a sequence of \"extended\"\nfollowed by \"default\" and \"fixed\". In that case the \"fixed\" should\nprevail, as well as tests to check that a \"grep.extendedRegexp=true\"\nfollowed by a \"grep.extendedRegexp=false\" behaves as though\n\"grep.extendedRegexp\" wasn't provided.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t7810-grep.sh | 68 +++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 68 insertions(+)\n\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 6b6423a07c3..dce653d749d 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -451,6 +451,65 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=basic \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins & defers to grep.patternType\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=fixed \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (ERE)\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=basic \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.patternType=[extended -> default -> fixed]\" '\n+\t\techo \"${HC}ab:a+b*c\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\t-c grep.patternType=fixed \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.patternType=extended and grep.extendedRegexp=false\" '\n \t\techo \"${HC}ab:abc\" >expected &&\n \t\tgit \\\n@@ -478,6 +537,15 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.extendedRegexp=false and grep.patternType=default\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.extendedRegexp=true and grep.patternType=basic\" '\n \t\techo \"${HC}ab:a+bc\" >expected &&\n \t\tgit \\\n-- \n2.34.1.1250.g6a242c1e9ad\n\n"},{"id":"445043","messageId":"patch-v7-04.10-6d91a765fd7-20211228T004707Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v7-00.10-00000000000-20211228T004707Z-avarab@gmail.com","subject":"[PATCH v7 04/10] built-ins: trust the \"prefix\" from run_builtin()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-28T01:07:39Z","receivedAt":"2021-12-28T01:08:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in \"builtin/grep.c\" and \"builtin/ls-tree.c\" to trust the\n\"prefix\" passed from \"run_builtin()\". The \"prefix\" we get from setup.c\nis either going to be NULL or a string of length >0, never \"\".\n\nSo we can drop the \"prefix && *prefix\" checks added for\n\"builtin/grep.c\" in 0d042fecf2f (git-grep: show pathnames relative to\nthe current directory, 2006-08-11), and for \"builtin/ls-tree.c\" in\na69dd585fca (ls-tree: chomp leading directories when run from a\nsubdirectory, 2005-12-23).\n\nAs seen in code in revision.c that was added in cd676a51367 (diff\n--relative: output paths as relative to the current subdirectory,\n2008-02-12) we already have existing code that does away with this\nassertion.\n\nThis makes it easier to reason about a subsequent change to the\n\"prefix_length\" code in grep.c in a subsequent commit, and since we're\ngoing to the trouble of doing that let's leave behind an assert() to\npromise this to any future callers.\n\nFor \"builtin/grep.c\" it would be painful to pass the \"prefix\" down the\ncallchain of:\n\n    cmd_grep -> grep_tree -> grep_submodule -> grep_cache -> grep_oid ->\n    grep_source_name\n\nSo for the code that needs it in grep_source_name() let's add a\n\"grep_prefix\" variable similar to the existing \"ls_tree_prefix\".\n\nWhile at it let's move the code in cmd_ls_tree() around so that we\nassign to the \"ls_tree_prefix\" right after declaring the variables,\nand stop assigning to \"prefix\". We only subsequently used that\nvariable later in the function after clobbering it. Let's just use our\nown \"grep_prefix\" instead.\n\nLet's also add an assert() in git.c, so that we'll make this promise\nabout the \"prefix\" to any current and future callers, as well as to\nany readers of the code.\n\nCode history:\n\n * The strlen() in \"grep.c\" hasn't been used since 493b7a08d80 (grep:\n   accept relative paths outside current working directory, 2009-09-05).\n\n   When that code was added in 0d042fecf2f (git-grep: show pathnames\n   relative to the current directory, 2006-08-11) we used the length.\n\n   But since 493b7a08d80 we haven't used it for anything except a\n   boolean check that we could have done on the \"prefix\" member\n   itself.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c    | 13 ++++++++-----\n builtin/ls-tree.c |  2 +-\n git.c             |  1 +\n grep.c            |  4 +---\n grep.h            |  4 +---\n revision.c        |  2 +-\n 6 files changed, 13 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 9e34a820ad4..d85cbabea67 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -26,6 +26,8 @@\n #include \"object-store.h\"\n #include \"packfile.h\"\n \n+static const char *grep_prefix;\n+\n static char const * const grep_usage[] = {\n \tN_(\"git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]\"),\n \tNULL\n@@ -315,11 +317,11 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \tstrbuf_reset(out);\n \n \tif (opt->null_following_name) {\n-\t\tif (opt->relative && opt->prefix_length) {\n+\t\tif (opt->relative && grep_prefix) {\n \t\t\tstruct strbuf rel_buf = STRBUF_INIT;\n \t\t\tconst char *rel_name =\n \t\t\t\trelative_path(filename + tree_name_len,\n-\t\t\t\t\t      opt->prefix, &rel_buf);\n+\t\t\t\t\t      grep_prefix, &rel_buf);\n \n \t\t\tif (tree_name_len)\n \t\t\t\tstrbuf_add(out, filename, tree_name_len);\n@@ -332,8 +334,8 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \t\treturn;\n \t}\n \n-\tif (opt->relative && opt->prefix_length)\n-\t\tquote_path(filename + tree_name_len, opt->prefix, out, 0);\n+\tif (opt->relative && grep_prefix)\n+\t\tquote_path(filename + tree_name_len, grep_prefix, out, 0);\n \telse\n \t\tquote_c_style(filename + tree_name_len, out, NULL, 0);\n \n@@ -962,9 +964,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\t   PARSE_OPT_NOCOMPLETE),\n \t\tOPT_END()\n \t};\n+\tgrep_prefix = prefix;\n \n \tgit_config(grep_cmd_config, NULL);\n-\tgrep_init(&opt, the_repository, prefix);\n+\tgrep_init(&opt, the_repository);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 3a442631c71..6cb554cbb0a 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -150,7 +150,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \n \tgit_config(git_default_config, NULL);\n \tls_tree_prefix = prefix;\n-\tif (prefix && *prefix)\n+\tif (prefix)\n \t\tchomp_prefix = strlen(prefix);\n \n \targc = parse_options(argc, argv, prefix, ls_tree_options,\ndiff --git a/git.c b/git.c\nindex 7edafd8ecff..575d95046f2 100644\n--- a/git.c\n+++ b/git.c\n@@ -436,6 +436,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t} else {\n \t\tprefix = NULL;\n \t}\n+\tassert(!prefix || *prefix);\n \tprecompose_argv_prefix(argc, argv, NULL);\n \tif (use_pager == -1 && run_setup &&\n \t\t!(p->option & DELAY_PAGER_CONFIG))\ndiff --git a/grep.c b/grep.c\nindex fe847a0111a..12b202598a9 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -139,13 +139,11 @@ int grep_config(const char *var, const char *value, void *cb)\n  * default values from the template we read the configuration\n  * information in an earlier call to git_config(grep_config).\n  */\n-void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)\n+void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n \t*opt = grep_defaults;\n \n \topt->repo = repo;\n-\topt->prefix = prefix;\n-\topt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;\n \topt->pattern_tail = &opt->pattern_list;\n \topt->header_tail = &opt->header_list;\n }\ndiff --git a/grep.h b/grep.h\nindex 95cccb670f9..62deadb885f 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -134,8 +134,6 @@ struct grep_opt {\n \t */\n \tstruct repository *repo;\n \n-\tconst char *prefix;\n-\tint prefix_length;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n@@ -180,7 +178,7 @@ struct grep_opt {\n };\n \n int grep_config(const char *var, const char *value, void *);\n-void grep_init(struct grep_opt *, struct repository *repo, const char *prefix);\n+void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex 5390a479b30..495328e859c 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1838,7 +1838,7 @@ void repo_init_revisions(struct repository *r,\n \trevs->commit_format = CMIT_FMT_DEFAULT;\n \trevs->expand_tabs_in_log_default = 8;\n \n-\tgrep_init(&revs->grep_filter, revs->repo, prefix);\n+\tgrep_init(&revs->grep_filter, revs->repo);\n \trevs->grep_filter.status_only = 1;\n \n \trepo_diff_setup(revs->repo, &revs->diffopt);\n-- \n2.34.1.1250.g6a242c1e9ad\n\n"},{"id":"445044","messageId":"patch-v7-05.10-844b4727ca3-20211228T004707Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v7-00.10-00000000000-20211228T004707Z-avarab@gmail.com","subject":"[PATCH v7 05/10] grep.c: don't pass along NULL callback value","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-28T01:07:40Z","receivedAt":"2021-12-28T01:08:01Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change grep_cmd_config() to stop passing around the always-NULL \"cb\"\nvalue. When this code was added in 7e8f59d577e (grep: color patterns\nin output, 2009-03-07) it was non-NULL, but when that changed in\n15fabd1bbd4 (builtin/grep.c: make configuration callback more\nreusable, 2012-10-09) this code was left behind.\n\nIn a subsequent change I'll start using the \"cb\" value, this will make\nit clear which functions we call need it, and which don't.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex d85cbabea67..5ec4cecae45 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,8 +285,8 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, cb);\n-\tif (git_color_default_config(var, value, cb) < 0)\n+\tint st = grep_config(var, value, NULL);\n+\tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n \tif (!strcmp(var, \"grep.threads\")) {\n-- \n2.34.1.1250.g6a242c1e9ad\n\n"},{"id":"445045","messageId":"patch-v7-06.10-d9cf9bf5e37-20211228T004707Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v7-00.10-00000000000-20211228T004707Z-avarab@gmail.com","subject":"[PATCH v7 06/10] grep API: call grep_config() after grep_init()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-28T01:07:41Z","receivedAt":"2021-12-28T01:08:03Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The grep_init() function used the odd pattern of initializing the\npassed-in \"struct grep_opt\" with a statically defined \"grep_defaults\"\nstruct, which would be modified in-place when we invoked\ngrep_config().\n\nSo we effectively (b) initialized config, (a) then defaults, (c)\nfollowed by user options. Usually those are ordered as \"a\", \"b\" and\n\"c\" instead.\n\nAs the comments being removed here show the previous behavior needed\nto be carefully explained as we'd potentially share the populated\nconfiguration among different instances of grep_init(). In practice we\ndidn't do that, but now that it can't be a concern anymore let's\nremove those comments.\n\nThis does not change the behavior of any of the configuration\nvariables or options. That would have been the case if we didn't move\naround the grep_config() call in \"builtin/log.c\". But now that we call\n\"grep_config\" after \"git_log_config\" and \"git_format_config\" we'll\nneed to pass in the already initialized \"struct grep_opt *\".\n\nSee 6ba9bb76e02 (grep: copy struct in one fell swoop, 2020-11-29) and\n7687a0541e0 (grep: move the configuration parsing logic to grep.[ch],\n2012-10-09) for the commits that added the comments.\n\nThe memcpy() pattern here will be optimized away and follows the\nconvention of other *_init() functions. See 5726a6b4012 (*.c *_init():\ndefine in terms of corresponding *_INIT macro, 2021-07-01).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c |  4 ++--\n builtin/log.c  | 13 +++++++++++--\n grep.c         | 39 +++------------------------------------\n grep.h         | 21 +++++++++++++++++++++\n 4 files changed, 37 insertions(+), 40 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5ec4cecae45..0ea124321b6 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,7 +285,7 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, NULL);\n+\tint st = grep_config(var, value, cb);\n \tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n@@ -966,8 +966,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t};\n \tgrep_prefix = prefix;\n \n-\tgit_config(grep_cmd_config, NULL);\n \tgrep_init(&opt, the_repository);\n+\tgit_config(grep_cmd_config, &opt);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 93ace0dde7d..fdde77e4ebb 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -520,8 +520,6 @@ static int git_log_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n-\tif (grep_config(var, value, cb) < 0)\n-\t\treturn -1;\n \tif (git_gpg_config(var, value, cb) < 0)\n \t\treturn -1;\n \treturn git_diff_ui_config(var, value, cb);\n@@ -536,6 +534,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.simplify_history = 0;\n \tmemset(&opt, 0, sizeof(opt));\n@@ -650,6 +650,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \n \tmemset(&match_all, 0, sizeof(match_all));\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.always_show_header = 1;\n \trev.no_walk = 1;\n@@ -733,6 +735,8 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n \tinit_reflog_walk(&rev.reflog_info);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.verbose_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -766,6 +770,8 @@ int cmd_log(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.always_show_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -1848,10 +1854,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \textra_hdr.strdup_strings = 1;\n \textra_to.strdup_strings = 1;\n \textra_cc.strdup_strings = 1;\n+\n \tinit_log_defaults();\n \tinit_display_notes(&notes_opt);\n \tgit_config(git_format_config, NULL);\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.show_notes = show_notes;\n \tmemcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));\n \trev.commit_format = CMIT_FMT_EMAIL;\ndiff --git a/grep.c b/grep.c\nindex 12b202598a9..8dfa0300786 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -19,27 +19,6 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)\n \tfwrite(buf, size, 1, stdout);\n }\n \n-static struct grep_opt grep_defaults = {\n-\t.relative = 1,\n-\t.pathname = 1,\n-\t.max_depth = -1,\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t.colors = {\n-\t\t[GREP_COLOR_CONTEXT] = \"\",\n-\t\t[GREP_COLOR_FILENAME] = \"\",\n-\t\t[GREP_COLOR_FUNCTION] = \"\",\n-\t\t[GREP_COLOR_LINENO] = \"\",\n-\t\t[GREP_COLOR_COLUMNNO] = \"\",\n-\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_SELECTED] = \"\",\n-\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN,\n-\t},\n-\t.only_matching = 0,\n-\t.color = -1,\n-\t.output = std_output,\n-};\n-\n static const char *color_grep_slots[] = {\n \t[GREP_COLOR_CONTEXT]\t    = \"context\",\n \t[GREP_COLOR_FILENAME]\t    = \"filename\",\n@@ -75,20 +54,12 @@ define_list_config_array_extra(color_grep_slots, {\"match\"});\n  */\n int grep_config(const char *var, const char *value, void *cb)\n {\n-\tstruct grep_opt *opt = &grep_defaults;\n+\tstruct grep_opt *opt = cb;\n \tconst char *slot;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\t/*\n-\t * The instance of grep_opt that we set up here is copied by\n-\t * grep_init() to be used by each individual invocation.\n-\t * When populating a new field of this structure here, be\n-\t * sure to think about ownership -- e.g., you might need to\n-\t * override the shallow copy in grep_init() with a deep copy.\n-\t */\n-\n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n \t\treturn 0;\n@@ -134,14 +105,10 @@ int grep_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/*\n- * Initialize one instance of grep_opt and copy the\n- * default values from the template we read the configuration\n- * information in an earlier call to git_config(grep_config).\n- */\n void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n-\t*opt = grep_defaults;\n+\tstruct grep_opt blank = GREP_OPT_INIT;\n+\tmemcpy(opt, &blank, sizeof(*opt));\n \n \topt->repo = repo;\n \topt->pattern_tail = &opt->pattern_list;\ndiff --git a/grep.h b/grep.h\nindex 62deadb885f..b651eb291f7 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -177,6 +177,27 @@ struct grep_opt {\n \tvoid *output_priv;\n };\n \n+#define GREP_OPT_INIT { \\\n+\t.relative = 1, \\\n+\t.pathname = 1, \\\n+\t.max_depth = -1, \\\n+\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n+\t.colors = { \\\n+\t\t[GREP_COLOR_CONTEXT] = \"\", \\\n+\t\t[GREP_COLOR_FILENAME] = \"\", \\\n+\t\t[GREP_COLOR_FUNCTION] = \"\", \\\n+\t\t[GREP_COLOR_LINENO] = \"\", \\\n+\t\t[GREP_COLOR_COLUMNNO] = \"\", \\\n+\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_SELECTED] = \"\", \\\n+\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n+\t}, \\\n+\t.only_matching = 0, \\\n+\t.color = -1, \\\n+\t.output = std_output, \\\n+}\n+\n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n-- \n2.34.1.1250.g6a242c1e9ad\n\n"},{"id":"445046","messageId":"patch-v7-10.10-b764c09d2b7-20211228T004707Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v7-00.10-00000000000-20211228T004707Z-avarab@gmail.com","subject":"[PATCH v7 10/10] grep.[ch]: remove GREP_PATTERN_TYPE_UNSPECIFIED","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-28T01:07:45Z","receivedAt":"2021-12-28T01:08:04Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Remove the need for \"GREP_PATTERN_TYPE_UNSPECIFIED\" in favor of having\nthe users of the \"pattern_type_option\" member check whether that\nmember is set or not.\n\nThe \"UNSPECIFIED\" case was already handled implicitly in\ncompile_regexp(), and we don't use this \"enum\" in a \"switch\"\nstatement, so let's not explicitly name the\n\"GREP_PATTERN_TYPE_UNSPECIFIED = 0\" case. It is still important that\n\"GREP_PATTERN_TYPE_BRE != 0\", as can be seen in failing tests if the\nparsing for \"basic\" in parse_pattern_type_arg() is made to \"return 0\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.c | 9 ++++++---\n grep.h | 4 +---\n 2 files changed, 7 insertions(+), 6 deletions(-)\n\ndiff --git a/grep.c b/grep.c\nindex a6712adbce7..914eb5dee9b 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -34,7 +34,7 @@ static const char *color_grep_slots[] = {\n static int parse_pattern_type_arg(const char *opt, const char *arg)\n {\n \tif (!strcmp(arg, \"default\"))\n-\t\treturn GREP_PATTERN_TYPE_UNSPECIFIED;\n+\t\treturn 0;\n \telse if (!strcmp(arg, \"basic\"))\n \t\treturn GREP_PATTERN_TYPE_BRE;\n \telse if (!strcmp(arg, \"extended\"))\n@@ -50,8 +50,7 @@ define_list_config_array_extra(color_grep_slots, {\"match\"});\n \n static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n {\n-\tif (*pto == GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\t*pto = ero ? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n+\t*pto = ero ? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n }\n \n /*\n@@ -69,12 +68,16 @@ int grep_config(const char *var, const char *value, void *cb)\n \n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\tero = git_config_bool(var, value);\n+\t\tif (opt->pattern_type_option)\n+\t\t\treturn 0;\n \t\tadjust_pattern_type(&opt->pattern_type_option, ero);\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(var, \"grep.patterntype\")) {\n \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n+\t\tif (opt->pattern_type_option)\n+\t\t\treturn 0;\n \t\tif (ero == -1)\n \t\t\treturn 0;\n \t\tadjust_pattern_type(&opt->pattern_type_option, ero);\ndiff --git a/grep.h b/grep.h\nindex 32ff4dad3de..e365b689287 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -94,8 +94,7 @@ enum grep_expr_node {\n };\n \n enum grep_pattern_type {\n-\tGREP_PATTERN_TYPE_UNSPECIFIED = 0,\n-\tGREP_PATTERN_TYPE_BRE,\n+\tGREP_PATTERN_TYPE_BRE = 1,\n \tGREP_PATTERN_TYPE_ERE,\n \tGREP_PATTERN_TYPE_FIXED,\n \tGREP_PATTERN_TYPE_PCRE\n@@ -178,7 +177,6 @@ struct grep_opt {\n \t.relative = 1, \\\n \t.pathname = 1, \\\n \t.max_depth = -1, \\\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n \t.colors = { \\\n \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n \t\t[GREP_COLOR_FILENAME] = \"\", \\\n-- \n2.34.1.1250.g6a242c1e9ad\n\n"},{"id":"445048","messageId":"patch-v7-09.10-c6ca39b4554-20211228T004707Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v7-00.10-00000000000-20211228T004707Z-avarab@gmail.com","subject":"[PATCH v7 09/10] grep: simplify config parsing and option parsing","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-28T01:07:44Z","receivedAt":"2021-12-28T01:08:04Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Simplify the parsing of \"grep.patternType\" and\n\"grep.extendedRegexp\". This changes no behavior, but gets rid of\ncomplex parsing logic that isn't needed anymore.\n\nWhen \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\ngrep.patternType configuration setting, 2012-08-03) we promised that:\n\n 1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n    will return to the default matching behavior\".\n\n    In that context \"the default\" meant whatever the configuration\n    system specified before that change, i.e. via grep.extendedRegexp.\n\n 2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n    it when the new \"grep.patternType\" option is set. We said we'd\n    only ignore the older \"grep.extendedRegexp\" option \"when the\n    `grep.patternType` option is set. to a value other than\n    'default'\".\n\nIn a preceding commit we changed grep_config() to be called after\ngrep_init(), which means that much of the complexity here can go\naway.\n\nAs before both \"grep.patternType\" and \"grep.extendedRegexp\" are\nlast-one-wins variable, with \"grep.extendedRegexp\" yielding to\n\"grep.patternType\", except when \"grep.patternType=default\".\n\nNote that this applies as we parse the config, i.e. a sequence of:\n\n    -c grep.patternType=perl\n    -c grep.extendedRegexp=true \\\n    -c grep.patternType=default\n\nShould select ERE due to \"grep.extendedRegexp=true and\ngrep.extendedRegexp=default\", not BRE, even though that's the\n\"default\" patternType. We can determine this as we parse the config,\nbecause:\n\n * If we see \"grep.extendedRegexp\" we set the internal \"ero\" to its\n   boolean value.\n\n * If we see \"grep.extendedRegexp\" but\n   \"grep.patternType=[default|<unset>]\" is in effect we *don't* set\n   the internal \"pattern_type_option\" to update the pattern type.\n\n * If we see \"grep.patternType!=default\" we can set our internal\n   \"pattern_type_option\" directly, it doesn't matter what the state of\n   \"grep.extendedRegexp\" is, but we don't forget what it was, in case\n   we see a \"grep.patternType=default\" again.\n\n * If we see a \"grep.patternType=default\" we can set the pattern to\n   ERE or BRE depending on whether we last saw a\n   \"grep.extendedRegexp=true\" or\n   \"grep.extendedRegexp=[false|<unset>]\".\n\nWe could equally call this new adjust_pattern_type() in\ncompile_regexp(), i.e. this fixup on top of this passes all our\ntests (with -U0 for brevity):\n\n    @@ -60,0 +61 @@ static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n    +static int ero = -1;\n    @@ -65 +65,0 @@ int grep_config(const char *var, const char *value, void *cb)\n    -       static int ero = -1;\n    @@ -72 +71,0 @@ int grep_config(const char *var, const char *value, void *cb)\n    -               adjust_pattern_type(&opt->pattern_type_option, ero);\n    @@ -80 +78,0 @@ int grep_config(const char *var, const char *value, void *cb)\n    -               adjust_pattern_type(&opt->pattern_type_option, ero);\n    @@ -445,0 +444,2 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n    +       if (ero != -1)\n    +               adjust_pattern_type(&opt->pattern_type_option, ero);\n\nBut doing it as we stream the git_config() makes it\nclear that we can determine the interplay between these two variables\nas we go. We don't need to wait until we see the last value of the two\nconfiguration variables.\n\nThis is true because of the rationale above, and because the\nsubsequent code in compile_regexp() treats\n\"pattern_type_option=GREP_PATTERN_TYPE_{UNSPECIFIED,BRE}\"\nequally. I.e. we'll end up with different internal\n\"\"pattern_type_option\" values there for:\n\n    # UNSPECIFIED\n    -c grep.patternType=default\n    # BRE\n    -c grep.extendedRegexp=false -c grep.patternType=default\n\nBut the difference won't matter, which simplifies some of this logic,\nwe never need to adjust a \"grep.patternType\" if we didn't see a\n\"grep.extendedRegexp\" before. We can also remove the\n\"extended_regexp_option\" member from \"struct grep_opt\" in favor of a\nstatic variable in grep_config().\n\nThe command-line parsing in cmd_grep() can then completely ignore\n\"grep.extendedRegexp\". Whatever effect it had before that step won't\nmatter if we see -G, -E, -P etc.\n\nSee my 07a3d411739 (grep: remove regflags from the public grep_opt\nAPI, 2017-06-29) for addition of the two comments being removed here,\ni.e. the complexity noted in that commit is now going away.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 10 +++----\n grep.c         | 77 +++++++++++---------------------------------------\n grep.h         |  4 ---\n revision.c     |  2 --\n 4 files changed, 20 insertions(+), 73 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 0ea124321b6..942c4b25077 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -845,7 +845,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tint i;\n \tint dummy;\n \tint use_index = 1;\n-\tint pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;\n \tint allow_revs;\n \n \tstruct option options[] = {\n@@ -879,16 +878,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"descend at most <depth> levels\"), PARSE_OPT_NONEG,\n \t\t\tNULL, 1 },\n \t\tOPT_GROUP(\"\"),\n-\t\tOPT_SET_INT('E', \"extended-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('E', \"extended-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use extended POSIX regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_ERE),\n-\t\tOPT_SET_INT('G', \"basic-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('G', \"basic-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use basic POSIX regular expressions (default)\"),\n \t\t\t    GREP_PATTERN_TYPE_BRE),\n-\t\tOPT_SET_INT('F', \"fixed-strings\", &pattern_type_arg,\n+\t\tOPT_SET_INT('F', \"fixed-strings\", &opt.pattern_type_option,\n \t\t\t    N_(\"interpret patterns as fixed strings\"),\n \t\t\t    GREP_PATTERN_TYPE_FIXED),\n-\t\tOPT_SET_INT('P', \"perl-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('P', \"perl-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use Perl-compatible regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_PCRE),\n \t\tOPT_GROUP(\"\"),\n@@ -982,7 +981,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, grep_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH |\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n-\tgrep_commit_pattern_type(pattern_type_arg, &opt);\n \n \tif (use_index && !startup_info->have_repository) {\n \t\tint fallback = 0;\ndiff --git a/grep.c b/grep.c\nindex f85be8b6eac..a6712adbce7 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -48,6 +48,12 @@ static int parse_pattern_type_arg(const char *opt, const char *arg)\n \n define_list_config_array_extra(color_grep_slots, {\"match\"});\n \n+static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n+{\n+\tif (*pto == GREP_PATTERN_TYPE_UNSPECIFIED)\n+\t\t*pto = ero ? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n+}\n+\n /*\n  * Read the configuration file once and store it in\n  * the grep_defaults template.\n@@ -56,17 +62,22 @@ int grep_config(const char *var, const char *value, void *cb)\n {\n \tstruct grep_opt *opt = cb;\n \tconst char *slot;\n+\tstatic int ero = -1;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n-\t\topt->extended_regexp_option = git_config_bool(var, value);\n+\t\tero = git_config_bool(var, value);\n+\t\tadjust_pattern_type(&opt->pattern_type_option, ero);\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(var, \"grep.patterntype\")) {\n \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n+\t\tif (ero == -1)\n+\t\t\treturn 0;\n+\t\tadjust_pattern_type(&opt->pattern_type_option, ero);\n \t\treturn 0;\n \t}\n \n@@ -115,62 +126,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo)\n \topt->header_tail = &opt->header_list;\n }\n \n-static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\t/*\n-\t * When committing to the pattern type by setting the relevant\n-\t * fields in grep_opt it's generally not necessary to zero out\n-\t * the fields we're not choosing, since they won't have been\n-\t * set by anything. The extended_regexp_option field is the\n-\t * only exception to this.\n-\t *\n-\t * This is because in the process of parsing grep.patternType\n-\t * & grep.extendedRegexp we set opt->pattern_type_option and\n-\t * opt->extended_regexp_option, respectively. We then\n-\t * internally use opt->extended_regexp_option to see if we're\n-\t * compiling an ERE. It must be unset if that's not actually\n-\t * the case.\n-\t */\n-\tif (pattern_type != GREP_PATTERN_TYPE_ERE &&\n-\t    opt->extended_regexp_option)\n-\t\topt->extended_regexp_option = 0;\n-\n-\tswitch (pattern_type) {\n-\tcase GREP_PATTERN_TYPE_UNSPECIFIED:\n-\t\t/* fall through */\n-\n-\tcase GREP_PATTERN_TYPE_BRE:\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_ERE:\n-\t\topt->extended_regexp_option = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_FIXED:\n-\t\topt->fixed = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_PCRE:\n-\t\topt->pcre2 = 1;\n-\t\tbreak;\n-\t}\n-}\n-\n-void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\tif (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(pattern_type, opt);\n-\telse if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(opt->pattern_type_option, opt);\n-\telse if (opt->extended_regexp_option)\n-\t\t/*\n-\t\t * This branch *must* happen after setting from the\n-\t\t * opt->pattern_type_option above, we don't want\n-\t\t * grep.extendedRegexp to override grep.patternType!\n-\t\t */\n-\t\tgrep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);\n-}\n-\n static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,\n \t\t\t\t\tconst char *origin, int no,\n \t\t\t\t\tenum grep_pat_token t,\n@@ -490,9 +445,9 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \n \tp->word_regexp = opt->word_regexp;\n \tp->ignore_case = opt->ignore_case;\n-\tp->fixed = opt->fixed;\n+\tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\n \n-\tif (!opt->pcre2 &&\n+\tif (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE &&\n \t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n@@ -544,14 +499,14 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \t\treturn;\n \t}\n \n-\tif (opt->pcre2) {\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_PCRE) {\n \t\tcompile_pcre2_pattern(p, opt);\n \t\treturn;\n \t}\n \n \tif (p->ignore_case)\n \t\tregflags |= REG_ICASE;\n-\tif (opt->extended_regexp_option)\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_ERE)\n \t\tregflags |= REG_EXTENDED;\n \terr = regcomp(&p->regexp, p->pattern, regflags);\n \tif (err) {\ndiff --git a/grep.h b/grep.h\nindex bae2899e364..32ff4dad3de 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -143,7 +143,6 @@ struct grep_opt {\n \tint unmatch_name_only;\n \tint count;\n \tint word_regexp;\n-\tint fixed;\n \tint all_match;\n #define GREP_BINARY_DEFAULT\t0\n #define GREP_BINARY_NOMATCH\t1\n@@ -152,7 +151,6 @@ struct grep_opt {\n \tint allow_textconv;\n \tint extended;\n \tint use_reflog_filter;\n-\tint pcre2;\n \tint relative;\n \tint pathname;\n \tint null_following_name;\n@@ -161,7 +159,6 @@ struct grep_opt {\n \tint max_depth;\n \tint funcname;\n \tint funcbody;\n-\tint extended_regexp_option;\n \tenum grep_pattern_type pattern_type_option;\n \tint ignore_locale;\n \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n@@ -200,7 +197,6 @@ struct grep_opt {\n \n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n-void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\n void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex 495328e859c..298d0ea7574 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2860,8 +2860,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \n \tdiff_setup_done(&revs->diffopt);\n \n-\tgrep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t\t\t\t &revs->grep_filter);\n \tif (!is_encoding_utf8(get_log_output_encoding()))\n \t\trevs->grep_filter.ignore_locale = 1;\n \tcompile_grep_patterns(&revs->grep_filter);\n-- \n2.34.1.1250.g6a242c1e9ad\n\n"},{"id":"445047","messageId":"patch-v7-07.10-57ecc5c0d65-20211228T004707Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v7-00.10-00000000000-20211228T004707Z-avarab@gmail.com","subject":"[PATCH v7 07/10] grep.h: make \"grep_opt.pattern_type_option\" use its enum","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-28T01:07:42Z","receivedAt":"2021-12-28T01:08:05Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the \"pattern_type_option\" member of \"struct grep_opt\" to use\nthe enum type we use for it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex b651eb291f7..bae2899e364 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -162,7 +162,7 @@ struct grep_opt {\n \tint funcname;\n \tint funcbody;\n \tint extended_regexp_option;\n-\tint pattern_type_option;\n+\tenum grep_pattern_type pattern_type_option;\n \tint ignore_locale;\n \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n \tunsigned pre_context;\n-- \n2.34.1.1250.g6a242c1e9ad\n\n"},{"id":"445049","messageId":"patch-v7-08.10-7dbeafde26b-20211228T004707Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v7-00.10-00000000000-20211228T004707Z-avarab@gmail.com","subject":"[PATCH v7 08/10] grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-12-28T01:07:43Z","receivedAt":"2021-12-28T01:08:08Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in compile_regexp() to check the cheaper boolean\n\"!opt->pcre2\" condition before the \"memchr()\" search.\n\nThis doesn't noticeably optimize anything, but makes the code more\nobvious and conventional. The line wrapping being added here also\nmakes a subsequent commit smaller.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/grep.c b/grep.c\nindex 8dfa0300786..f85be8b6eac 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -492,7 +492,8 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \tp->ignore_case = opt->ignore_case;\n \tp->fixed = opt->fixed;\n \n-\tif (memchr(p->pattern, 0, p->patternlen) && !opt->pcre2)\n+\tif (!opt->pcre2 &&\n+\t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n \tp->is_fixed = is_fixed(p->pattern, p->patternlen);\n-- \n2.34.1.1250.g6a242c1e9ad\n\n"},{"id":"446412","messageId":"cover-v8-00.10-00000000000-20220118T155211Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v7-00.10-00000000000-20211228T004707Z-avarab@gmail.com","subject":"[PATCH v8 00/10] grep: simplify & delete \"init\" & \"config\" code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-18T15:55:12Z","receivedAt":"2022-01-18T15:55:32Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A v8 re-roll of this series. For context and v7 see:\nhttps://lore.kernel.org/git/cover-v7-00.10-00000000000-20211228T004707Z-avarab@gmail.com\n\nThe v7 has not been picked up yet. The ab/grep-patterntype in Junio's\ntree is the v6. This v8 is rebased on \"master\" for a merge conflict\nwith the now-merged lh/use-gnu-color-in-grep.\n\nÆvar Arnfjörð Bjarmason (10):\n  grep.h: remove unused \"regex_t regexp\" from grep_opt\n  log tests: check if grep_config() is called by \"log\"-like cmds\n  grep tests: add missing \"grep.patternType\" config tests\n  built-ins: trust the \"prefix\" from run_builtin()\n  grep.c: don't pass along NULL callback value\n  grep API: call grep_config() after grep_init()\n  grep.h: make \"grep_opt.pattern_type_option\" use its enum\n  grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"\n  grep: simplify config parsing and option parsing\n  grep.[ch]: remove GREP_PATTERN_TYPE_UNSPECIFIED\n\n builtin/grep.c    |  27 +++++-----\n builtin/log.c     |  13 ++++-\n builtin/ls-tree.c |   2 +-\n git.c             |   1 +\n grep.c            | 126 +++++++++-------------------------------------\n grep.h            |  34 +++++++++----\n revision.c        |   4 +-\n t/t4202-log.sh    |  24 +++++++++\n t/t7810-grep.sh   |  68 +++++++++++++++++++++++++\n 9 files changed, 168 insertions(+), 131 deletions(-)\n\nRange-diff against v7:\n 1:  b62e6b6162a =  1:  010a2066656 grep.h: remove unused \"regex_t regexp\" from grep_opt\n 2:  0edcdb50afd =  2:  e4981fa3417 log tests: check if grep_config() is called by \"log\"-like cmds\n 3:  e1b4b5b77e0 =  3:  59092169e55 grep tests: add missing \"grep.patternType\" config tests\n 4:  6d91a765fd7 =  4:  331c9019a0e built-ins: trust the \"prefix\" from run_builtin()\n 5:  844b4727ca3 =  5:  25dd327b653 grep.c: don't pass along NULL callback value\n 6:  d9cf9bf5e37 !  6:  3c559ad006a grep API: call grep_config() after grep_init()\n    @@ grep.c: static void std_output(struct grep_opt *opt, const void *buf, size_t siz\n     -\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED,\n     -\t.colors = {\n     -\t\t[GREP_COLOR_CONTEXT] = \"\",\n    --\t\t[GREP_COLOR_FILENAME] = \"\",\n    +-\t\t[GREP_COLOR_FILENAME] = GIT_COLOR_MAGENTA,\n     -\t\t[GREP_COLOR_FUNCTION] = \"\",\n    --\t\t[GREP_COLOR_LINENO] = \"\",\n    --\t\t[GREP_COLOR_COLUMNNO] = \"\",\n    +-\t\t[GREP_COLOR_LINENO] = GIT_COLOR_GREEN,\n    +-\t\t[GREP_COLOR_COLUMNNO] = GIT_COLOR_GREEN,\n     -\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED,\n     -\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED,\n     -\t\t[GREP_COLOR_SELECTED] = \"\",\n    @@ grep.h: struct grep_opt {\n     +\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n     +\t.colors = { \\\n     +\t\t[GREP_COLOR_CONTEXT] = \"\", \\\n    -+\t\t[GREP_COLOR_FILENAME] = \"\", \\\n    ++\t\t[GREP_COLOR_FILENAME] = GIT_COLOR_MAGENTA, \\\n     +\t\t[GREP_COLOR_FUNCTION] = \"\", \\\n    -+\t\t[GREP_COLOR_LINENO] = \"\", \\\n    -+\t\t[GREP_COLOR_COLUMNNO] = \"\", \\\n    ++\t\t[GREP_COLOR_LINENO] = GIT_COLOR_GREEN, \\\n    ++\t\t[GREP_COLOR_COLUMNNO] = GIT_COLOR_GREEN, \\\n     +\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, \\\n     +\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, \\\n     +\t\t[GREP_COLOR_SELECTED] = \"\", \\\n 7:  57ecc5c0d65 =  7:  daf873899c1 grep.h: make \"grep_opt.pattern_type_option\" use its enum\n 8:  7dbeafde26b =  8:  62650a78ea9 grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"\n 9:  c6ca39b4554 !  9:  c211bb0c69d grep: simplify config parsing and option parsing\n    @@ grep.h: struct grep_opt {\n      \tint word_regexp;\n     -\tint fixed;\n      \tint all_match;\n    - #define GREP_BINARY_DEFAULT\t0\n    - #define GREP_BINARY_NOMATCH\t1\n    + \tint no_body_match;\n    + \tint body_hit;\n     @@ grep.h: struct grep_opt {\n      \tint allow_textconv;\n      \tint extended;\n10:  b764c09d2b7 ! 10:  b52a0c11fa9 grep.[ch]: remove GREP_PATTERN_TYPE_UNSPECIFIED\n    @@ grep.h: struct grep_opt {\n     -\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n      \t.colors = { \\\n      \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n    - \t\t[GREP_COLOR_FILENAME] = \"\", \\\n    + \t\t[GREP_COLOR_FILENAME] = GIT_COLOR_MAGENTA, \\\n-- \n2.35.0.rc1.864.g57621b115b6\n\n"},{"id":"446413","messageId":"patch-v8-01.10-010a2066656-20220118T155211Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v8-00.10-00000000000-20220118T155211Z-avarab@gmail.com","subject":"[PATCH v8 01/10] grep.h: remove unused \"regex_t regexp\" from grep_opt","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-18T15:55:13Z","receivedAt":"2022-01-18T15:55:33Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This \"regex_t\" in grep_opt has not been used since\nf9b9faf6f8a (builtin-grep: allow more than one patterns., 2006-05-02),\nwe still use a \"regex_t\" for compiling regexes, but that's in the\n\"grep_pat\" struct\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 6a1f0ab0172..400172676a1 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -136,7 +136,6 @@ struct grep_opt {\n \n \tconst char *prefix;\n \tint prefix_length;\n-\tregex_t regexp;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n-- \n2.35.0.rc1.864.g57621b115b6\n\n"},{"id":"446414","messageId":"patch-v8-02.10-e4981fa3417-20220118T155211Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v8-00.10-00000000000-20220118T155211Z-avarab@gmail.com","subject":"[PATCH v8 02/10] log tests: check if grep_config() is called by \"log\"-like cmds","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-18T15:55:14Z","receivedAt":"2022-01-18T15:55:35Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the tests added in my 9df46763ef1 (log: add exhaustive tests\nfor pattern style options & config, 2017-05-20) to check not only\nwhether \"git log\" handles \"grep.patternType\", but also \"git show\"\netc.\n\nIt's sufficient to check whether we match a \"fixed\" or a \"basic\" regex\nhere to see if these codepaths correctly invoked grep_config(). We\ndon't need to check the details of their regular expression matching\nas the \"log\" test does.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4202-log.sh | 24 ++++++++++++++++++++++++\n 1 file changed, 24 insertions(+)\n\ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex 50495598619..e775b378e4b 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -449,6 +449,30 @@ test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurati\n \t)\n '\n \n+for cmd in show whatchanged reflog format-patch\n+do\n+\tcase \"$cmd\" in\n+\tformat-patch) myarg=\"HEAD~..\" ;;\n+\t*) myarg= ;;\n+\tesac\n+\n+\ttest_expect_success \"$cmd: understands grep.patternType, like 'log'\" '\n+\t\tgit init \"pattern-type-$cmd\" &&\n+\t\t(\n+\t\t\tcd \"pattern-type-$cmd\" &&\n+\t\t\ttest_commit 1 file A &&\n+\t\t\ttest_commit \"(1|2)\" file B 2 &&\n+\n+\t\t\tgit -c grep.patternType=fixed $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_must_be_empty actual &&\n+\n+\t\t\tgit -c grep.patternType=basic $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_file_not_empty actual\n+\t\t)\n+\t'\n+done\n+test_done\n+\n test_expect_success 'log --author' '\n \tcat >expect <<-\\EOF &&\n \tAuthor: <BOLD;RED>A U<RESET> Thor <author@example.com>\n-- \n2.35.0.rc1.864.g57621b115b6\n\n"},{"id":"446415","messageId":"patch-v8-03.10-59092169e55-20220118T155211Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v8-00.10-00000000000-20220118T155211Z-avarab@gmail.com","subject":"[PATCH v8 03/10] grep tests: add missing \"grep.patternType\" config tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-18T15:55:15Z","receivedAt":"2022-01-18T15:55:36Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the grep tests to assert that setting\n\"grep.patternType=extended\" followed by \"grep.patternType=default\"\nwill behave as if \"--basic-regexp\" was provided, and not as\n\"--extended-regexp\". In a subsequent commit we'll need to treat\n\"grep.patternType=default\" as a special-case, but let's make sure we\nignore it if it's being set to \"default\" following an earlier\nnon-\"default\" \"grep.patternType\" setting.\n\nLet's also test what happens when we have a sequence of \"extended\"\nfollowed by \"default\" and \"fixed\". In that case the \"fixed\" should\nprevail, as well as tests to check that a \"grep.extendedRegexp=true\"\nfollowed by a \"grep.extendedRegexp=false\" behaves as though\n\"grep.extendedRegexp\" wasn't provided.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t7810-grep.sh | 68 +++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 68 insertions(+)\n\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 424c31c3287..34d8f69c1de 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -451,6 +451,65 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=basic \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins & defers to grep.patternType\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=fixed \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (ERE)\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=basic \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.patternType=[extended -> default -> fixed]\" '\n+\t\techo \"${HC}ab:a+b*c\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\t-c grep.patternType=fixed \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.patternType=extended and grep.extendedRegexp=false\" '\n \t\techo \"${HC}ab:abc\" >expected &&\n \t\tgit \\\n@@ -478,6 +537,15 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.extendedRegexp=false and grep.patternType=default\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.extendedRegexp=true and grep.patternType=basic\" '\n \t\techo \"${HC}ab:a+bc\" >expected &&\n \t\tgit \\\n-- \n2.35.0.rc1.864.g57621b115b6\n\n"},{"id":"446416","messageId":"patch-v8-04.10-331c9019a0e-20220118T155211Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v8-00.10-00000000000-20220118T155211Z-avarab@gmail.com","subject":"[PATCH v8 04/10] built-ins: trust the \"prefix\" from run_builtin()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-18T15:55:16Z","receivedAt":"2022-01-18T15:55:38Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in \"builtin/grep.c\" and \"builtin/ls-tree.c\" to trust the\n\"prefix\" passed from \"run_builtin()\". The \"prefix\" we get from setup.c\nis either going to be NULL or a string of length >0, never \"\".\n\nSo we can drop the \"prefix && *prefix\" checks added for\n\"builtin/grep.c\" in 0d042fecf2f (git-grep: show pathnames relative to\nthe current directory, 2006-08-11), and for \"builtin/ls-tree.c\" in\na69dd585fca (ls-tree: chomp leading directories when run from a\nsubdirectory, 2005-12-23).\n\nAs seen in code in revision.c that was added in cd676a51367 (diff\n--relative: output paths as relative to the current subdirectory,\n2008-02-12) we already have existing code that does away with this\nassertion.\n\nThis makes it easier to reason about a subsequent change to the\n\"prefix_length\" code in grep.c in a subsequent commit, and since we're\ngoing to the trouble of doing that let's leave behind an assert() to\npromise this to any future callers.\n\nFor \"builtin/grep.c\" it would be painful to pass the \"prefix\" down the\ncallchain of:\n\n    cmd_grep -> grep_tree -> grep_submodule -> grep_cache -> grep_oid ->\n    grep_source_name\n\nSo for the code that needs it in grep_source_name() let's add a\n\"grep_prefix\" variable similar to the existing \"ls_tree_prefix\".\n\nWhile at it let's move the code in cmd_ls_tree() around so that we\nassign to the \"ls_tree_prefix\" right after declaring the variables,\nand stop assigning to \"prefix\". We only subsequently used that\nvariable later in the function after clobbering it. Let's just use our\nown \"grep_prefix\" instead.\n\nLet's also add an assert() in git.c, so that we'll make this promise\nabout the \"prefix\" to any current and future callers, as well as to\nany readers of the code.\n\nCode history:\n\n * The strlen() in \"grep.c\" hasn't been used since 493b7a08d80 (grep:\n   accept relative paths outside current working directory, 2009-09-05).\n\n   When that code was added in 0d042fecf2f (git-grep: show pathnames\n   relative to the current directory, 2006-08-11) we used the length.\n\n   But since 493b7a08d80 we haven't used it for anything except a\n   boolean check that we could have done on the \"prefix\" member\n   itself.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c    | 13 ++++++++-----\n builtin/ls-tree.c |  2 +-\n git.c             |  1 +\n grep.c            |  4 +---\n grep.h            |  4 +---\n revision.c        |  2 +-\n 6 files changed, 13 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 9e34a820ad4..d85cbabea67 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -26,6 +26,8 @@\n #include \"object-store.h\"\n #include \"packfile.h\"\n \n+static const char *grep_prefix;\n+\n static char const * const grep_usage[] = {\n \tN_(\"git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]\"),\n \tNULL\n@@ -315,11 +317,11 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \tstrbuf_reset(out);\n \n \tif (opt->null_following_name) {\n-\t\tif (opt->relative && opt->prefix_length) {\n+\t\tif (opt->relative && grep_prefix) {\n \t\t\tstruct strbuf rel_buf = STRBUF_INIT;\n \t\t\tconst char *rel_name =\n \t\t\t\trelative_path(filename + tree_name_len,\n-\t\t\t\t\t      opt->prefix, &rel_buf);\n+\t\t\t\t\t      grep_prefix, &rel_buf);\n \n \t\t\tif (tree_name_len)\n \t\t\t\tstrbuf_add(out, filename, tree_name_len);\n@@ -332,8 +334,8 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \t\treturn;\n \t}\n \n-\tif (opt->relative && opt->prefix_length)\n-\t\tquote_path(filename + tree_name_len, opt->prefix, out, 0);\n+\tif (opt->relative && grep_prefix)\n+\t\tquote_path(filename + tree_name_len, grep_prefix, out, 0);\n \telse\n \t\tquote_c_style(filename + tree_name_len, out, NULL, 0);\n \n@@ -962,9 +964,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\t   PARSE_OPT_NOCOMPLETE),\n \t\tOPT_END()\n \t};\n+\tgrep_prefix = prefix;\n \n \tgit_config(grep_cmd_config, NULL);\n-\tgrep_init(&opt, the_repository, prefix);\n+\tgrep_init(&opt, the_repository);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 3a442631c71..6cb554cbb0a 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -150,7 +150,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \n \tgit_config(git_default_config, NULL);\n \tls_tree_prefix = prefix;\n-\tif (prefix && *prefix)\n+\tif (prefix)\n \t\tchomp_prefix = strlen(prefix);\n \n \targc = parse_options(argc, argv, prefix, ls_tree_options,\ndiff --git a/git.c b/git.c\nindex edda922ce6d..9d257e092da 100644\n--- a/git.c\n+++ b/git.c\n@@ -436,6 +436,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t} else {\n \t\tprefix = NULL;\n \t}\n+\tassert(!prefix || *prefix);\n \tprecompose_argv_prefix(argc, argv, NULL);\n \tif (use_pager == -1 && run_setup &&\n \t\t!(p->option & DELAY_PAGER_CONFIG))\ndiff --git a/grep.c b/grep.c\nindex 7bb0360869a..8421dc55486 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -139,13 +139,11 @@ int grep_config(const char *var, const char *value, void *cb)\n  * default values from the template we read the configuration\n  * information in an earlier call to git_config(grep_config).\n  */\n-void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)\n+void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n \t*opt = grep_defaults;\n \n \topt->repo = repo;\n-\topt->prefix = prefix;\n-\topt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;\n \topt->pattern_tail = &opt->pattern_list;\n \topt->header_tail = &opt->header_list;\n }\ndiff --git a/grep.h b/grep.h\nindex 400172676a1..23a2a41d2c4 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -134,8 +134,6 @@ struct grep_opt {\n \t */\n \tstruct repository *repo;\n \n-\tconst char *prefix;\n-\tint prefix_length;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n@@ -182,7 +180,7 @@ struct grep_opt {\n };\n \n int grep_config(const char *var, const char *value, void *);\n-void grep_init(struct grep_opt *, struct repository *repo, const char *prefix);\n+void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex ad4286fbdde..d6e0e2b23b5 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1838,7 +1838,7 @@ void repo_init_revisions(struct repository *r,\n \trevs->commit_format = CMIT_FMT_DEFAULT;\n \trevs->expand_tabs_in_log_default = 8;\n \n-\tgrep_init(&revs->grep_filter, revs->repo, prefix);\n+\tgrep_init(&revs->grep_filter, revs->repo);\n \trevs->grep_filter.status_only = 1;\n \n \trepo_diff_setup(revs->repo, &revs->diffopt);\n-- \n2.35.0.rc1.864.g57621b115b6\n\n"},{"id":"446417","messageId":"patch-v8-05.10-25dd327b653-20220118T155211Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v8-00.10-00000000000-20220118T155211Z-avarab@gmail.com","subject":"[PATCH v8 05/10] grep.c: don't pass along NULL callback value","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-18T15:55:17Z","receivedAt":"2022-01-18T15:55:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change grep_cmd_config() to stop passing around the always-NULL \"cb\"\nvalue. When this code was added in 7e8f59d577e (grep: color patterns\nin output, 2009-03-07) it was non-NULL, but when that changed in\n15fabd1bbd4 (builtin/grep.c: make configuration callback more\nreusable, 2012-10-09) this code was left behind.\n\nIn a subsequent change I'll start using the \"cb\" value, this will make\nit clear which functions we call need it, and which don't.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex d85cbabea67..5ec4cecae45 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,8 +285,8 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, cb);\n-\tif (git_color_default_config(var, value, cb) < 0)\n+\tint st = grep_config(var, value, NULL);\n+\tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n \tif (!strcmp(var, \"grep.threads\")) {\n-- \n2.35.0.rc1.864.g57621b115b6\n\n"},{"id":"446418","messageId":"patch-v8-06.10-3c559ad006a-20220118T155211Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v8-00.10-00000000000-20220118T155211Z-avarab@gmail.com","subject":"[PATCH v8 06/10] grep API: call grep_config() after grep_init()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-18T15:55:18Z","receivedAt":"2022-01-18T15:55:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The grep_init() function used the odd pattern of initializing the\npassed-in \"struct grep_opt\" with a statically defined \"grep_defaults\"\nstruct, which would be modified in-place when we invoked\ngrep_config().\n\nSo we effectively (b) initialized config, (a) then defaults, (c)\nfollowed by user options. Usually those are ordered as \"a\", \"b\" and\n\"c\" instead.\n\nAs the comments being removed here show the previous behavior needed\nto be carefully explained as we'd potentially share the populated\nconfiguration among different instances of grep_init(). In practice we\ndidn't do that, but now that it can't be a concern anymore let's\nremove those comments.\n\nThis does not change the behavior of any of the configuration\nvariables or options. That would have been the case if we didn't move\naround the grep_config() call in \"builtin/log.c\". But now that we call\n\"grep_config\" after \"git_log_config\" and \"git_format_config\" we'll\nneed to pass in the already initialized \"struct grep_opt *\".\n\nSee 6ba9bb76e02 (grep: copy struct in one fell swoop, 2020-11-29) and\n7687a0541e0 (grep: move the configuration parsing logic to grep.[ch],\n2012-10-09) for the commits that added the comments.\n\nThe memcpy() pattern here will be optimized away and follows the\nconvention of other *_init() functions. See 5726a6b4012 (*.c *_init():\ndefine in terms of corresponding *_INIT macro, 2021-07-01).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c |  4 ++--\n builtin/log.c  | 13 +++++++++++--\n grep.c         | 39 +++------------------------------------\n grep.h         | 21 +++++++++++++++++++++\n 4 files changed, 37 insertions(+), 40 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5ec4cecae45..0ea124321b6 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,7 +285,7 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, NULL);\n+\tint st = grep_config(var, value, cb);\n \tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n@@ -966,8 +966,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t};\n \tgrep_prefix = prefix;\n \n-\tgit_config(grep_cmd_config, NULL);\n \tgrep_init(&opt, the_repository);\n+\tgit_config(grep_cmd_config, &opt);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 4b493408cc5..06283b37e7a 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -520,8 +520,6 @@ static int git_log_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n-\tif (grep_config(var, value, cb) < 0)\n-\t\treturn -1;\n \tif (git_gpg_config(var, value, cb) < 0)\n \t\treturn -1;\n \treturn git_diff_ui_config(var, value, cb);\n@@ -536,6 +534,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.simplify_history = 0;\n \tmemset(&opt, 0, sizeof(opt));\n@@ -650,6 +650,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \n \tmemset(&match_all, 0, sizeof(match_all));\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.always_show_header = 1;\n \trev.no_walk = 1;\n@@ -733,6 +735,8 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n \tinit_reflog_walk(&rev.reflog_info);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.verbose_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -766,6 +770,8 @@ int cmd_log(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.always_show_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -1848,10 +1854,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \textra_hdr.strdup_strings = 1;\n \textra_to.strdup_strings = 1;\n \textra_cc.strdup_strings = 1;\n+\n \tinit_log_defaults();\n \tinit_display_notes(&notes_opt);\n \tgit_config(git_format_config, NULL);\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.show_notes = show_notes;\n \tmemcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));\n \trev.commit_format = CMIT_FMT_EMAIL;\ndiff --git a/grep.c b/grep.c\nindex 8421dc55486..35e12e43c09 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -19,27 +19,6 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)\n \tfwrite(buf, size, 1, stdout);\n }\n \n-static struct grep_opt grep_defaults = {\n-\t.relative = 1,\n-\t.pathname = 1,\n-\t.max_depth = -1,\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t.colors = {\n-\t\t[GREP_COLOR_CONTEXT] = \"\",\n-\t\t[GREP_COLOR_FILENAME] = GIT_COLOR_MAGENTA,\n-\t\t[GREP_COLOR_FUNCTION] = \"\",\n-\t\t[GREP_COLOR_LINENO] = GIT_COLOR_GREEN,\n-\t\t[GREP_COLOR_COLUMNNO] = GIT_COLOR_GREEN,\n-\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_SELECTED] = \"\",\n-\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN,\n-\t},\n-\t.only_matching = 0,\n-\t.color = -1,\n-\t.output = std_output,\n-};\n-\n static const char *color_grep_slots[] = {\n \t[GREP_COLOR_CONTEXT]\t    = \"context\",\n \t[GREP_COLOR_FILENAME]\t    = \"filename\",\n@@ -75,20 +54,12 @@ define_list_config_array_extra(color_grep_slots, {\"match\"});\n  */\n int grep_config(const char *var, const char *value, void *cb)\n {\n-\tstruct grep_opt *opt = &grep_defaults;\n+\tstruct grep_opt *opt = cb;\n \tconst char *slot;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\t/*\n-\t * The instance of grep_opt that we set up here is copied by\n-\t * grep_init() to be used by each individual invocation.\n-\t * When populating a new field of this structure here, be\n-\t * sure to think about ownership -- e.g., you might need to\n-\t * override the shallow copy in grep_init() with a deep copy.\n-\t */\n-\n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n \t\treturn 0;\n@@ -134,14 +105,10 @@ int grep_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/*\n- * Initialize one instance of grep_opt and copy the\n- * default values from the template we read the configuration\n- * information in an earlier call to git_config(grep_config).\n- */\n void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n-\t*opt = grep_defaults;\n+\tstruct grep_opt blank = GREP_OPT_INIT;\n+\tmemcpy(opt, &blank, sizeof(*opt));\n \n \topt->repo = repo;\n \topt->pattern_tail = &opt->pattern_list;\ndiff --git a/grep.h b/grep.h\nindex 23a2a41d2c4..3112d1c2a38 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -179,6 +179,27 @@ struct grep_opt {\n \tvoid *output_priv;\n };\n \n+#define GREP_OPT_INIT { \\\n+\t.relative = 1, \\\n+\t.pathname = 1, \\\n+\t.max_depth = -1, \\\n+\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n+\t.colors = { \\\n+\t\t[GREP_COLOR_CONTEXT] = \"\", \\\n+\t\t[GREP_COLOR_FILENAME] = GIT_COLOR_MAGENTA, \\\n+\t\t[GREP_COLOR_FUNCTION] = \"\", \\\n+\t\t[GREP_COLOR_LINENO] = GIT_COLOR_GREEN, \\\n+\t\t[GREP_COLOR_COLUMNNO] = GIT_COLOR_GREEN, \\\n+\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_SELECTED] = \"\", \\\n+\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n+\t}, \\\n+\t.only_matching = 0, \\\n+\t.color = -1, \\\n+\t.output = std_output, \\\n+}\n+\n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n-- \n2.35.0.rc1.864.g57621b115b6\n\n"},{"id":"446419","messageId":"patch-v8-07.10-daf873899c1-20220118T155211Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v8-00.10-00000000000-20220118T155211Z-avarab@gmail.com","subject":"[PATCH v8 07/10] grep.h: make \"grep_opt.pattern_type_option\" use its enum","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-18T15:55:19Z","receivedAt":"2022-01-18T15:55:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the \"pattern_type_option\" member of \"struct grep_opt\" to use\nthe enum type we use for it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 3112d1c2a38..89a2ce51130 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -164,7 +164,7 @@ struct grep_opt {\n \tint funcname;\n \tint funcbody;\n \tint extended_regexp_option;\n-\tint pattern_type_option;\n+\tenum grep_pattern_type pattern_type_option;\n \tint ignore_locale;\n \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n \tunsigned pre_context;\n-- \n2.35.0.rc1.864.g57621b115b6\n\n"},{"id":"446420","messageId":"patch-v8-08.10-62650a78ea9-20220118T155211Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v8-00.10-00000000000-20220118T155211Z-avarab@gmail.com","subject":"[PATCH v8 08/10] grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-18T15:55:20Z","receivedAt":"2022-01-18T15:55:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in compile_regexp() to check the cheaper boolean\n\"!opt->pcre2\" condition before the \"memchr()\" search.\n\nThis doesn't noticeably optimize anything, but makes the code more\nobvious and conventional. The line wrapping being added here also\nmakes a subsequent commit smaller.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/grep.c b/grep.c\nindex 35e12e43c09..60228a95a4f 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -492,7 +492,8 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \tp->ignore_case = opt->ignore_case;\n \tp->fixed = opt->fixed;\n \n-\tif (memchr(p->pattern, 0, p->patternlen) && !opt->pcre2)\n+\tif (!opt->pcre2 &&\n+\t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n \tp->is_fixed = is_fixed(p->pattern, p->patternlen);\n-- \n2.35.0.rc1.864.g57621b115b6\n\n"},{"id":"446421","messageId":"patch-v8-10.10-b52a0c11fa9-20220118T155211Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v8-00.10-00000000000-20220118T155211Z-avarab@gmail.com","subject":"[PATCH v8 10/10] grep.[ch]: remove GREP_PATTERN_TYPE_UNSPECIFIED","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-18T15:55:22Z","receivedAt":"2022-01-18T15:55:47Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Remove the need for \"GREP_PATTERN_TYPE_UNSPECIFIED\" in favor of having\nthe users of the \"pattern_type_option\" member check whether that\nmember is set or not.\n\nThe \"UNSPECIFIED\" case was already handled implicitly in\ncompile_regexp(), and we don't use this \"enum\" in a \"switch\"\nstatement, so let's not explicitly name the\n\"GREP_PATTERN_TYPE_UNSPECIFIED = 0\" case. It is still important that\n\"GREP_PATTERN_TYPE_BRE != 0\", as can be seen in failing tests if the\nparsing for \"basic\" in parse_pattern_type_arg() is made to \"return 0\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.c | 9 ++++++---\n grep.h | 4 +---\n 2 files changed, 7 insertions(+), 6 deletions(-)\n\ndiff --git a/grep.c b/grep.c\nindex bb487e994d0..3497df48ca6 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -34,7 +34,7 @@ static const char *color_grep_slots[] = {\n static int parse_pattern_type_arg(const char *opt, const char *arg)\n {\n \tif (!strcmp(arg, \"default\"))\n-\t\treturn GREP_PATTERN_TYPE_UNSPECIFIED;\n+\t\treturn 0;\n \telse if (!strcmp(arg, \"basic\"))\n \t\treturn GREP_PATTERN_TYPE_BRE;\n \telse if (!strcmp(arg, \"extended\"))\n@@ -50,8 +50,7 @@ define_list_config_array_extra(color_grep_slots, {\"match\"});\n \n static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n {\n-\tif (*pto == GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\t*pto = ero ? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n+\t*pto = ero ? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n }\n \n /*\n@@ -69,12 +68,16 @@ int grep_config(const char *var, const char *value, void *cb)\n \n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\tero = git_config_bool(var, value);\n+\t\tif (opt->pattern_type_option)\n+\t\t\treturn 0;\n \t\tadjust_pattern_type(&opt->pattern_type_option, ero);\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(var, \"grep.patterntype\")) {\n \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n+\t\tif (opt->pattern_type_option)\n+\t\t\treturn 0;\n \t\tif (ero == -1)\n \t\t\treturn 0;\n \t\tadjust_pattern_type(&opt->pattern_type_option, ero);\ndiff --git a/grep.h b/grep.h\nindex ab0f8290784..460cb75a357 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -94,8 +94,7 @@ enum grep_expr_node {\n };\n \n enum grep_pattern_type {\n-\tGREP_PATTERN_TYPE_UNSPECIFIED = 0,\n-\tGREP_PATTERN_TYPE_BRE,\n+\tGREP_PATTERN_TYPE_BRE = 1,\n \tGREP_PATTERN_TYPE_ERE,\n \tGREP_PATTERN_TYPE_FIXED,\n \tGREP_PATTERN_TYPE_PCRE\n@@ -180,7 +179,6 @@ struct grep_opt {\n \t.relative = 1, \\\n \t.pathname = 1, \\\n \t.max_depth = -1, \\\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n \t.colors = { \\\n \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n \t\t[GREP_COLOR_FILENAME] = GIT_COLOR_MAGENTA, \\\n-- \n2.35.0.rc1.864.g57621b115b6\n\n"},{"id":"446422","messageId":"patch-v8-09.10-c211bb0c69d-20220118T155211Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v8-00.10-00000000000-20220118T155211Z-avarab@gmail.com","subject":"[PATCH v8 09/10] grep: simplify config parsing and option parsing","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-18T15:55:21Z","receivedAt":"2022-01-18T15:55:48Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Simplify the parsing of \"grep.patternType\" and\n\"grep.extendedRegexp\". This changes no behavior, but gets rid of\ncomplex parsing logic that isn't needed anymore.\n\nWhen \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\ngrep.patternType configuration setting, 2012-08-03) we promised that:\n\n 1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n    will return to the default matching behavior\".\n\n    In that context \"the default\" meant whatever the configuration\n    system specified before that change, i.e. via grep.extendedRegexp.\n\n 2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n    it when the new \"grep.patternType\" option is set. We said we'd\n    only ignore the older \"grep.extendedRegexp\" option \"when the\n    `grep.patternType` option is set. to a value other than\n    'default'\".\n\nIn a preceding commit we changed grep_config() to be called after\ngrep_init(), which means that much of the complexity here can go\naway.\n\nAs before both \"grep.patternType\" and \"grep.extendedRegexp\" are\nlast-one-wins variable, with \"grep.extendedRegexp\" yielding to\n\"grep.patternType\", except when \"grep.patternType=default\".\n\nNote that this applies as we parse the config, i.e. a sequence of:\n\n    -c grep.patternType=perl\n    -c grep.extendedRegexp=true \\\n    -c grep.patternType=default\n\nShould select ERE due to \"grep.extendedRegexp=true and\ngrep.extendedRegexp=default\", not BRE, even though that's the\n\"default\" patternType. We can determine this as we parse the config,\nbecause:\n\n * If we see \"grep.extendedRegexp\" we set the internal \"ero\" to its\n   boolean value.\n\n * If we see \"grep.extendedRegexp\" but\n   \"grep.patternType=[default|<unset>]\" is in effect we *don't* set\n   the internal \"pattern_type_option\" to update the pattern type.\n\n * If we see \"grep.patternType!=default\" we can set our internal\n   \"pattern_type_option\" directly, it doesn't matter what the state of\n   \"grep.extendedRegexp\" is, but we don't forget what it was, in case\n   we see a \"grep.patternType=default\" again.\n\n * If we see a \"grep.patternType=default\" we can set the pattern to\n   ERE or BRE depending on whether we last saw a\n   \"grep.extendedRegexp=true\" or\n   \"grep.extendedRegexp=[false|<unset>]\".\n\nWe could equally call this new adjust_pattern_type() in\ncompile_regexp(), i.e. this fixup on top of this passes all our\ntests (with -U0 for brevity):\n\n    @@ -60,0 +61 @@ static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n    +static int ero = -1;\n    @@ -65 +65,0 @@ int grep_config(const char *var, const char *value, void *cb)\n    -       static int ero = -1;\n    @@ -72 +71,0 @@ int grep_config(const char *var, const char *value, void *cb)\n    -               adjust_pattern_type(&opt->pattern_type_option, ero);\n    @@ -80 +78,0 @@ int grep_config(const char *var, const char *value, void *cb)\n    -               adjust_pattern_type(&opt->pattern_type_option, ero);\n    @@ -445,0 +444,2 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n    +       if (ero != -1)\n    +               adjust_pattern_type(&opt->pattern_type_option, ero);\n\nBut doing it as we stream the git_config() makes it\nclear that we can determine the interplay between these two variables\nas we go. We don't need to wait until we see the last value of the two\nconfiguration variables.\n\nThis is true because of the rationale above, and because the\nsubsequent code in compile_regexp() treats\n\"pattern_type_option=GREP_PATTERN_TYPE_{UNSPECIFIED,BRE}\"\nequally. I.e. we'll end up with different internal\n\"\"pattern_type_option\" values there for:\n\n    # UNSPECIFIED\n    -c grep.patternType=default\n    # BRE\n    -c grep.extendedRegexp=false -c grep.patternType=default\n\nBut the difference won't matter, which simplifies some of this logic,\nwe never need to adjust a \"grep.patternType\" if we didn't see a\n\"grep.extendedRegexp\" before. We can also remove the\n\"extended_regexp_option\" member from \"struct grep_opt\" in favor of a\nstatic variable in grep_config().\n\nThe command-line parsing in cmd_grep() can then completely ignore\n\"grep.extendedRegexp\". Whatever effect it had before that step won't\nmatter if we see -G, -E, -P etc.\n\nSee my 07a3d411739 (grep: remove regflags from the public grep_opt\nAPI, 2017-06-29) for addition of the two comments being removed here,\ni.e. the complexity noted in that commit is now going away.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 10 +++----\n grep.c         | 77 +++++++++++---------------------------------------\n grep.h         |  4 ---\n revision.c     |  2 --\n 4 files changed, 20 insertions(+), 73 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 0ea124321b6..942c4b25077 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -845,7 +845,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tint i;\n \tint dummy;\n \tint use_index = 1;\n-\tint pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;\n \tint allow_revs;\n \n \tstruct option options[] = {\n@@ -879,16 +878,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"descend at most <depth> levels\"), PARSE_OPT_NONEG,\n \t\t\tNULL, 1 },\n \t\tOPT_GROUP(\"\"),\n-\t\tOPT_SET_INT('E', \"extended-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('E', \"extended-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use extended POSIX regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_ERE),\n-\t\tOPT_SET_INT('G', \"basic-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('G', \"basic-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use basic POSIX regular expressions (default)\"),\n \t\t\t    GREP_PATTERN_TYPE_BRE),\n-\t\tOPT_SET_INT('F', \"fixed-strings\", &pattern_type_arg,\n+\t\tOPT_SET_INT('F', \"fixed-strings\", &opt.pattern_type_option,\n \t\t\t    N_(\"interpret patterns as fixed strings\"),\n \t\t\t    GREP_PATTERN_TYPE_FIXED),\n-\t\tOPT_SET_INT('P', \"perl-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('P', \"perl-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use Perl-compatible regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_PCRE),\n \t\tOPT_GROUP(\"\"),\n@@ -982,7 +981,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, grep_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH |\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n-\tgrep_commit_pattern_type(pattern_type_arg, &opt);\n \n \tif (use_index && !startup_info->have_repository) {\n \t\tint fallback = 0;\ndiff --git a/grep.c b/grep.c\nindex 60228a95a4f..bb487e994d0 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -48,6 +48,12 @@ static int parse_pattern_type_arg(const char *opt, const char *arg)\n \n define_list_config_array_extra(color_grep_slots, {\"match\"});\n \n+static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n+{\n+\tif (*pto == GREP_PATTERN_TYPE_UNSPECIFIED)\n+\t\t*pto = ero ? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n+}\n+\n /*\n  * Read the configuration file once and store it in\n  * the grep_defaults template.\n@@ -56,17 +62,22 @@ int grep_config(const char *var, const char *value, void *cb)\n {\n \tstruct grep_opt *opt = cb;\n \tconst char *slot;\n+\tstatic int ero = -1;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n-\t\topt->extended_regexp_option = git_config_bool(var, value);\n+\t\tero = git_config_bool(var, value);\n+\t\tadjust_pattern_type(&opt->pattern_type_option, ero);\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(var, \"grep.patterntype\")) {\n \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n+\t\tif (ero == -1)\n+\t\t\treturn 0;\n+\t\tadjust_pattern_type(&opt->pattern_type_option, ero);\n \t\treturn 0;\n \t}\n \n@@ -115,62 +126,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo)\n \topt->header_tail = &opt->header_list;\n }\n \n-static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\t/*\n-\t * When committing to the pattern type by setting the relevant\n-\t * fields in grep_opt it's generally not necessary to zero out\n-\t * the fields we're not choosing, since they won't have been\n-\t * set by anything. The extended_regexp_option field is the\n-\t * only exception to this.\n-\t *\n-\t * This is because in the process of parsing grep.patternType\n-\t * & grep.extendedRegexp we set opt->pattern_type_option and\n-\t * opt->extended_regexp_option, respectively. We then\n-\t * internally use opt->extended_regexp_option to see if we're\n-\t * compiling an ERE. It must be unset if that's not actually\n-\t * the case.\n-\t */\n-\tif (pattern_type != GREP_PATTERN_TYPE_ERE &&\n-\t    opt->extended_regexp_option)\n-\t\topt->extended_regexp_option = 0;\n-\n-\tswitch (pattern_type) {\n-\tcase GREP_PATTERN_TYPE_UNSPECIFIED:\n-\t\t/* fall through */\n-\n-\tcase GREP_PATTERN_TYPE_BRE:\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_ERE:\n-\t\topt->extended_regexp_option = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_FIXED:\n-\t\topt->fixed = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_PCRE:\n-\t\topt->pcre2 = 1;\n-\t\tbreak;\n-\t}\n-}\n-\n-void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\tif (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(pattern_type, opt);\n-\telse if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(opt->pattern_type_option, opt);\n-\telse if (opt->extended_regexp_option)\n-\t\t/*\n-\t\t * This branch *must* happen after setting from the\n-\t\t * opt->pattern_type_option above, we don't want\n-\t\t * grep.extendedRegexp to override grep.patternType!\n-\t\t */\n-\t\tgrep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);\n-}\n-\n static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,\n \t\t\t\t\tconst char *origin, int no,\n \t\t\t\t\tenum grep_pat_token t,\n@@ -490,9 +445,9 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \n \tp->word_regexp = opt->word_regexp;\n \tp->ignore_case = opt->ignore_case;\n-\tp->fixed = opt->fixed;\n+\tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\n \n-\tif (!opt->pcre2 &&\n+\tif (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE &&\n \t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n@@ -544,14 +499,14 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \t\treturn;\n \t}\n \n-\tif (opt->pcre2) {\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_PCRE) {\n \t\tcompile_pcre2_pattern(p, opt);\n \t\treturn;\n \t}\n \n \tif (p->ignore_case)\n \t\tregflags |= REG_ICASE;\n-\tif (opt->extended_regexp_option)\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_ERE)\n \t\tregflags |= REG_EXTENDED;\n \terr = regcomp(&p->regexp, p->pattern, regflags);\n \tif (err) {\ndiff --git a/grep.h b/grep.h\nindex 89a2ce51130..ab0f8290784 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -143,7 +143,6 @@ struct grep_opt {\n \tint unmatch_name_only;\n \tint count;\n \tint word_regexp;\n-\tint fixed;\n \tint all_match;\n \tint no_body_match;\n \tint body_hit;\n@@ -154,7 +153,6 @@ struct grep_opt {\n \tint allow_textconv;\n \tint extended;\n \tint use_reflog_filter;\n-\tint pcre2;\n \tint relative;\n \tint pathname;\n \tint null_following_name;\n@@ -163,7 +161,6 @@ struct grep_opt {\n \tint max_depth;\n \tint funcname;\n \tint funcbody;\n-\tint extended_regexp_option;\n \tenum grep_pattern_type pattern_type_option;\n \tint ignore_locale;\n \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n@@ -202,7 +199,6 @@ struct grep_opt {\n \n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n-void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\n void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex d6e0e2b23b5..dd301e30147 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2860,8 +2860,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \n \tdiff_setup_done(&revs->diffopt);\n \n-\tgrep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t\t\t\t &revs->grep_filter);\n \tif (!is_encoding_utf8(get_log_output_encoding()))\n \t\trevs->grep_filter.ignore_locale = 1;\n \tcompile_grep_patterns(&revs->grep_filter);\n-- \n2.35.0.rc1.864.g57621b115b6\n\n"},{"id":"446460","messageId":"xmqq8rvcr73v.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v8-09.10-c211bb0c69d-20220118T155211Z-avarab@gmail.com","subject":"Re: [PATCH v8 09/10] grep: simplify config parsing and option parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-01-18T22:50:44Z","receivedAt":"2022-01-18T22:50:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> When \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\n> grep.patternType configuration setting, 2012-08-03) we promised that:\n>\n>  1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n>     will return to the default matching behavior\".\n>\n>     In that context \"the default\" meant whatever the configuration\n>     system specified before that change, i.e. via grep.extendedRegexp.\n>\n>  2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n>     it when the new \"grep.patternType\" option is set. We said we'd\n>     only ignore the older \"grep.extendedRegexp\" option \"when the\n>     `grep.patternType` option is set. to a value other than\n>     'default'\".\n\nExtra period in the middle of a sentence after \"set\".\n\n> As before both \"grep.patternType\" and \"grep.extendedRegexp\" are\n> last-one-wins variable, with \"grep.extendedRegexp\" yielding to\n> \"grep.patternType\", except when \"grep.patternType=default\".\n>\n> Note that this applies as we parse the config, i.e. a sequence of:\n>\n>     -c grep.patternType=perl\n>     -c grep.extendedRegexp=true \\\n>     -c grep.patternType=default\n>\n> Should select ERE due to \"grep.extendedRegexp=true and\n\nDowncase \"S\" in \"should\", as this is still in the middle of the\nsentence that began with \"Note that\".\n\n> grep.extendedRegexp=default\", not BRE, even though that's the\n\nThe second one should be \"grep.patternType=default\".\n\n> \"default\" patternType. We can determine this as we parse the config,\n\nDrop \"even though that's the default patternType\".  You've already\nexplained that it is not what \"default\" for the \"patternType\" (which\nany reader who has been following so far would take as a reference\nto \"grep.patternType\") at all.  You can also drop \", not BRE,\" while\ndoing so.\n\n> because:\n>\n>  * If we see \"grep.extendedRegexp\" we set the internal \"ero\" to its\n>    boolean value.\n>\n>  * If we see \"grep.extendedRegexp\" but\n>    \"grep.patternType=[default|<unset>]\" is in effect we *don't* set\n>    the internal \"pattern_type_option\" to update the pattern type.\n>\n>  * If we see \"grep.patternType!=default\" we can set our internal\n>    \"pattern_type_option\" directly, it doesn't matter what the state of\n>    \"grep.extendedRegexp\" is, but we don't forget what it was, in case\n>    we see a \"grep.patternType=default\" again.\n>\n>  * If we see a \"grep.patternType=default\" we can set the pattern to\n>    ERE or BRE depending on whether we last saw a\n>    \"grep.extendedRegexp=true\" or\n>    \"grep.extendedRegexp=[false|<unset>]\".\n\nThat sounds complex enough, doesn't it?  The statement that opens\nthe proposed log mesage is \"gets rid of complex parsing logic that\nisn't needed\", but the above sounds more like a complex logic is\nbeing traded with another.\n\n> diff --git a/grep.c b/grep.c\n> index 60228a95a4f..bb487e994d0 100644\n> --- a/grep.c\n> +++ b/grep.c\n> @@ -48,6 +48,12 @@ static int parse_pattern_type_arg(const char *opt, const char *arg)\n>  \n>  define_list_config_array_extra(color_grep_slots, {\"match\"});\n>  \n> +static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n> +{\n> +\tif (*pto == GREP_PATTERN_TYPE_UNSPECIFIED)\n> +\t\t*pto = ero ? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n> +}\n> +\n>  /*\n>   * Read the configuration file once and store it in\n>   * the grep_defaults template.\n> @@ -56,17 +62,22 @@ int grep_config(const char *var, const char *value, void *cb)\n>  {\n>  \tstruct grep_opt *opt = cb;\n>  \tconst char *slot;\n> +\tstatic int ero = -1;\n\nIs this new reentrancy issue worth it?  I think it makes the whole\nthing unnecessarily complex, compared to a more naïve \"we keep track\nof the last-one-that-won for grep.extendedRegexp and\ngrep.patternType separately during option and config parsing inside\nthe grep_opt structure, and then combine the two when we compile the\npattern string into regexp or pcre object\" approach.\n\nLet's ask it in a different way.  What is this static, that is way\nseparated from all the members in the grep_opt structure, buying us?\nCertainly not the ease of understanding what the code is doing.  Not\nthe size of the overall grep_opt structure (which we do not allocate\ntons anyway).  Other than that fact that you can say \"I did it my\nown way, ignoring reviewer suggestions, I won!!!\", I do not see any\nupside with this code.\n\nPUzzled.\n"},{"id":"446461","messageId":"xmqq4k60r6wa.fsf@gitster.g","threadId":"56853","inReplyTo":"xmqq8rvcr73v.fsf@gitster.g","subject":"Re: [PATCH v8 09/10] grep: simplify config parsing and option parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-01-18T22:55:17Z","receivedAt":"2022-01-18T22:55:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>> @@ -56,17 +62,22 @@ int grep_config(const char *var, const char *value, void *cb)\n>>  {\n>>  \tstruct grep_opt *opt = cb;\n>>  \tconst char *slot;\n>> +\tstatic int ero = -1;\n>\n> Is this new reentrancy issue worth it?  I think it makes the whole\n> thing unnecessarily complex, compared to a more naïve \"we keep track\n> of the last-one-that-won for grep.extendedRegexp and\n> grep.patternType separately during option and config parsing inside\n> the grep_opt structure, and then combine the two when we compile the\n> pattern string into regexp or pcre object\" approach.\n\nAnother problem is that there are those corporate server-side folks\nwho are interested in giving an endpoint that lets clients to ask\nperforming Git operations (like grep and blame).  Adding more statics\ninstead of keeping track of dynamic runtime structure like grep_opt\nis deliberately making things more difficult for them, isn't it?\n\n\n"},{"id":"446471","messageId":"220119.86wniwo9mz.gmgdl@evledraar.gmail.com","threadId":"56853","inReplyTo":"xmqq8rvcr73v.fsf@gitster.g","subject":"Re: [PATCH v8 09/10] grep: simplify config parsing and option parsing","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-19T00:17:28Z","receivedAt":"2022-01-19T00:24:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Jan 18 2022, Junio C Hamano wrote:\n\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> When \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\n>> grep.patternType configuration setting, 2012-08-03) we promised that:\n>>\n>>  1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n>>     will return to the default matching behavior\".\n>>\n>>     In that context \"the default\" meant whatever the configuration\n>>     system specified before that change, i.e. via grep.extendedRegexp.\n>>\n>>  2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n>>     it when the new \"grep.patternType\" option is set. We said we'd\n>>     only ignore the older \"grep.extendedRegexp\" option \"when the\n>>     `grep.patternType` option is set. to a value other than\n>>     'default'\".\n>\n> Extra period in the middle of a sentence after \"set\".\n>\n>> As before both \"grep.patternType\" and \"grep.extendedRegexp\" are\n>> last-one-wins variable, with \"grep.extendedRegexp\" yielding to\n>> \"grep.patternType\", except when \"grep.patternType=default\".\n>>\n>> Note that this applies as we parse the config, i.e. a sequence of:\n>>\n>>     -c grep.patternType=perl\n>>     -c grep.extendedRegexp=true \\\n>>     -c grep.patternType=default\n>>\n>> Should select ERE due to \"grep.extendedRegexp=true and\n>\n> Downcase \"S\" in \"should\", as this is still in the middle of the\n> sentence that began with \"Note that\".\n>\n>> grep.extendedRegexp=default\", not BRE, even though that's the\n>\n> The second one should be \"grep.patternType=default\".\n\n*nod*\n\n>> \"default\" patternType. We can determine this as we parse the config,\n>\n> Drop \"even though that's the default patternType\".  You've already\n> explained that it is not what \"default\" for the \"patternType\" (which\n> any reader who has been following so far would take as a reference\n> to \"grep.patternType\") at all.  You can also drop \", not BRE,\" while\n> doing so.\n>\n>> because:\n>>\n>>  * If we see \"grep.extendedRegexp\" we set the internal \"ero\" to its\n>>    boolean value.\n>>\n>>  * If we see \"grep.extendedRegexp\" but\n>>    \"grep.patternType=[default|<unset>]\" is in effect we *don't* set\n>>    the internal \"pattern_type_option\" to update the pattern type.\n>>\n>>  * If we see \"grep.patternType!=default\" we can set our internal\n>>    \"pattern_type_option\" directly, it doesn't matter what the state of\n>>    \"grep.extendedRegexp\" is, but we don't forget what it was, in case\n>>    we see a \"grep.patternType=default\" again.\n>>\n>>  * If we see a \"grep.patternType=default\" we can set the pattern to\n>>    ERE or BRE depending on whether we last saw a\n>>    \"grep.extendedRegexp=true\" or\n>>    \"grep.extendedRegexp=[false|<unset>]\".\n>\n> That sounds complex enough, doesn't it?  The statement that opens\n> the proposed log mesage is \"gets rid of complex parsing logic that\n> isn't needed\", but the above sounds more like a complex logic is\n> being traded with another.\n\nThe complexity this series is addressing is that you couldn't treat this\nlike most other built-in / library APIs, where we instantiate defaults,\ndo config, then CLI parsing.\n\n>> diff --git a/grep.c b/grep.c\n>> index 60228a95a4f..bb487e994d0 100644\n>> --- a/grep.c\n>> +++ b/grep.c\n>> @@ -48,6 +48,12 @@ static int parse_pattern_type_arg(const char *opt, const char *arg)\n>>  \n>>  define_list_config_array_extra(color_grep_slots, {\"match\"});\n>>  \n>> +static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n>> +{\n>> +\tif (*pto == GREP_PATTERN_TYPE_UNSPECIFIED)\n>> +\t\t*pto = ero ? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n>> +}\n>> +\n>>  /*\n>>   * Read the configuration file once and store it in\n>>   * the grep_defaults template.\n>> @@ -56,17 +62,22 @@ int grep_config(const char *var, const char *value, void *cb)\n>>  {\n>>  \tstruct grep_opt *opt = cb;\n>>  \tconst char *slot;\n>> +\tstatic int ero = -1;\n>\n> Is this new reentrancy issue worth it?  I think it makes the whole\n> thing unnecessarily complex, compared to a more naïve \"we keep track\n> of the last-one-that-won for grep.extendedRegexp and\n> grep.patternType separately during option and config parsing inside\n> the grep_opt structure, and then combine the two when we compile the\n> pattern string into regexp or pcre object\" approach.\n\nI can move back to using the variable in the struct. The post-image here\nis from incrementally working on that, until I saw that it wasn't needed\noutside the config parsing step itself.\n\nIs a reentrancy issue a practical concern? This part of the grep API is\nexplicitly called by the whole init-once/config-once/getopt-once step in\nbuiltin/grep.c (and revision.c).\n\n> Let's ask it in a different way.  What is this static, that is way\n> separated from all the members in the grep_opt structure, buying us?\n> Certainly not the ease of understanding what the code is doing.  Not\n> the size of the overall grep_opt structure (which we do not allocate\n> tons anyway).  Other than that fact that you can say \"I did it my\n> own way, ignoring reviewer suggestions, I won!!!\", I do not see any\n> upside with this code.\n\nThe ease of understanding that the state isn't needed outside of the\nconfig callback, but that's in the eye of the beholder I suppose. That's\nnot true of the other remaining struct members.\n\nThen downthread you mention:\n\n> Another problem is that there are those corporate server-side folks\n> who are interested in giving an endpoint that lets clients to ask\n> performing Git operations (like grep and blame).  Adding more statics\n> instead of keeping track of dynamic runtime structure like grep_opt\n> is deliberately making things more difficult for them, isn't it?\n\nIIRC I'm the only person who's been advocating that as an eventual neat\nthing to do, and I don't see how this would make it harder.\n\nIf we had a grep IPC call of some sort we'd surely limit it to the\n\"modern\" config of grep.patternType, and take the opportunity to\ndeprecate grep.extendedRegexp from that interface.\n\nOr it would take explicit parameters, instead of allowing the passing of\nconfig from a remote process.\n\nIn either case the required surgery and scaffolding to make that work\nwill at most be trivially impacted by these changes, and likely not at\nall.\n"},{"id":"446479","messageId":"xmqq35lkpm4q.fsf@gitster.g","threadId":"56853","inReplyTo":"220119.86wniwo9mz.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v8 09/10] grep: simplify config parsing and option parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-01-19T01:09:09Z","receivedAt":"2022-01-19T01:09:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> If we had a grep IPC call of some sort we'd surely limit it to the\n> \"modern\" config of grep.patternType, and take the opportunity to\n> deprecate grep.extendedRegexp from that interface.\n\nA process that visits more than one repositories, with different\nconfiguration, does not have such a choice.  As far as I tell, there\nis not yet a way to undo the static in the code after these patches\nso that such a process can reset between repositories.\n\nA member that is necessary only during configuration parsing is not\na problem as long as the field is marked clearly as such (I wouldn't\neven call that \"not a NEW problem\", since it is not a problem to\nbegin with, and I am sure there are more examples in other\nsubsystems).  A static inside a helper function that has subtle\ninteractions with second and subsequent invocations makes the code\nmuch harder to follow, on the other hand.\n"},{"id":"446481","messageId":"220119.86bl08o76l.gmgdl@evledraar.gmail.com","threadId":"56853","inReplyTo":"xmqq35lkpm4q.fsf@gitster.g","subject":"Re: [PATCH v8 09/10] grep: simplify config parsing and option parsing","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-19T01:15:53Z","receivedAt":"2022-01-19T01:17:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Jan 18 2022, Junio C Hamano wrote:\n\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> If we had a grep IPC call of some sort we'd surely limit it to the\n>> \"modern\" config of grep.patternType, and take the opportunity to\n>> deprecate grep.extendedRegexp from that interface.\n>\n> A process that visits more than one repositories, with different\n> configuration, does not have such a choice.  As far as I tell, there\n> is not yet a way to undo the static in the code after these patches\n> so that such a process can reset between repositories.\n\nYes, it does assume the current one-shot API users, e.g. \"git grep\n--recurse-submodules\" only reads the config of the one parent repo.\n\n> A member that is necessary only during configuration parsing is not\n> a problem as long as the field is marked clearly as such (I wouldn't\n> even call that \"not a NEW problem\", since it is not a problem to\n> begin with, and I am sure there are more examples in other\n> subsystems).  A static inside a helper function that has subtle\n> interactions with second and subsequent invocations makes the code\n> much harder to follow, on the other hand.\n\n*nod*, will change it.\n"},{"id":"447064","messageId":"cover-v9-0.9-00000000000-20220127T115058Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v8-00.10-00000000000-20220118T155211Z-avarab@gmail.com","subject":"[PATCH v9 0/9] grep: simplify & delete \"init\" & \"config\" code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T11:56:22Z","receivedAt":"2022-01-27T11:56:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This series makes using the grep.[ch] API easier, by having it follow\nthe usual pattern of being initialized with:\n\n    defaults -> config -> command-line\n\nThis is to make some follow-up work easier, this is a net code\ndeletion if we exclude newly added tests.\n\nChanges since v8:\n\n * Addressed Junio's comments on the last two patches, the 9/9 is now\n   rewritten to use the \"struct grep_opts\" to track the\n   \"extended_regexp_option\" member, and the previous 10/10 has been\n   dropped.\n\nFor the v8 see\nhttps://lore.kernel.org/git/cover-v8-00.10-00000000000-20220118T155211Z-avarab@gmail.com/\n\nÆvar Arnfjörð Bjarmason (9):\n  grep.h: remove unused \"regex_t regexp\" from grep_opt\n  log tests: check if grep_config() is called by \"log\"-like cmds\n  grep tests: add missing \"grep.patternType\" config tests\n  built-ins: trust the \"prefix\" from run_builtin()\n  grep.c: don't pass along NULL callback value\n  grep API: call grep_config() after grep_init()\n  grep.h: make \"grep_opt.pattern_type_option\" use its enum\n  grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"\n  grep: simplify config parsing and option parsing\n\n builtin/grep.c    |  27 ++++++-----\n builtin/log.c     |  13 ++++-\n builtin/ls-tree.c |   2 +-\n git.c             |   1 +\n grep.c            | 120 ++++++++--------------------------------------\n grep.h            |  32 +++++++++----\n revision.c        |   4 +-\n t/t4202-log.sh    |  24 ++++++++++\n t/t7810-grep.sh   |  68 ++++++++++++++++++++++++++\n 9 files changed, 165 insertions(+), 126 deletions(-)\n\nRange-diff against v8:\n 1:  010a2066656 =  1:  b9372cde017 grep.h: remove unused \"regex_t regexp\" from grep_opt\n 2:  e4981fa3417 =  2:  30219a0ae9d log tests: check if grep_config() is called by \"log\"-like cmds\n 3:  59092169e55 =  3:  a75b288340b grep tests: add missing \"grep.patternType\" config tests\n 4:  331c9019a0e =  4:  6e7f9730a7d built-ins: trust the \"prefix\" from run_builtin()\n 5:  25dd327b653 =  5:  fbcfea84696 grep.c: don't pass along NULL callback value\n 6:  3c559ad006a =  6:  96c8cc7806e grep API: call grep_config() after grep_init()\n 7:  daf873899c1 =  7:  e09616056b4 grep.h: make \"grep_opt.pattern_type_option\" use its enum\n 8:  62650a78ea9 =  8:  61fc6a4dac8 grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"\n 9:  c211bb0c69d !  9:  445467e87f7 grep: simplify config parsing and option parsing\n    @@ Commit message\n          2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n             it when the new \"grep.patternType\" option is set. We said we'd\n             only ignore the older \"grep.extendedRegexp\" option \"when the\n    -        `grep.patternType` option is set. to a value other than\n    +        `grep.patternType` option is set to a value other than\n             'default'\".\n     \n         In a preceding commit we changed grep_config() to be called after\n    @@ Commit message\n             -c grep.extendedRegexp=true \\\n             -c grep.patternType=default\n     \n    -    Should select ERE due to \"grep.extendedRegexp=true and\n    -    grep.extendedRegexp=default\", not BRE, even though that's the\n    -    \"default\" patternType. We can determine this as we parse the config,\n    -    because:\n    +    should select ERE due to \"grep.extendedRegexp=true and\n    +    grep.patternType=default\". We can determine this as we parse the\n    +    config, because:\n     \n    -     * If we see \"grep.extendedRegexp\" we set the internal \"ero\" to its\n    -       boolean value.\n    +     * If we see \"grep.extendedRegexp\" we set \"extended_regexp_option\" to\n    +       its boolean value.\n     \n          * If we see \"grep.extendedRegexp\" but\n            \"grep.patternType=[default|<unset>]\" is in effect we *don't* set\n    @@ Commit message\n     \n          * If we see \"grep.patternType!=default\" we can set our internal\n            \"pattern_type_option\" directly, it doesn't matter what the state of\n    -       \"grep.extendedRegexp\" is, but we don't forget what it was, in case\n    -       we see a \"grep.patternType=default\" again.\n    +       \"extended_regexp_option\" is, but we don't forget what it was, in\n    +       case we see a \"grep.patternType=default\" again.\n     \n          * If we see a \"grep.patternType=default\" we can set the pattern to\n            ERE or BRE depending on whether we last saw a\n            \"grep.extendedRegexp=true\" or\n            \"grep.extendedRegexp=[false|<unset>]\".\n     \n    -    We could equally call this new adjust_pattern_type() in\n    -    compile_regexp(), i.e. this fixup on top of this passes all our\n    -    tests (with -U0 for brevity):\n    -\n    -        @@ -60,0 +61 @@ static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n    -        +static int ero = -1;\n    -        @@ -65 +65,0 @@ int grep_config(const char *var, const char *value, void *cb)\n    -        -       static int ero = -1;\n    -        @@ -72 +71,0 @@ int grep_config(const char *var, const char *value, void *cb)\n    -        -               adjust_pattern_type(&opt->pattern_type_option, ero);\n    -        @@ -80 +78,0 @@ int grep_config(const char *var, const char *value, void *cb)\n    -        -               adjust_pattern_type(&opt->pattern_type_option, ero);\n    -        @@ -445,0 +444,2 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n    -        +       if (ero != -1)\n    -        +               adjust_pattern_type(&opt->pattern_type_option, ero);\n    -\n    -    But doing it as we stream the git_config() makes it\n    -    clear that we can determine the interplay between these two variables\n    -    as we go. We don't need to wait until we see the last value of the two\n    -    configuration variables.\n    -\n    -    This is true because of the rationale above, and because the\n    -    subsequent code in compile_regexp() treats\n    -    \"pattern_type_option=GREP_PATTERN_TYPE_{UNSPECIFIED,BRE}\"\n    -    equally. I.e. we'll end up with different internal\n    -    \"\"pattern_type_option\" values there for:\n    -\n    -        # UNSPECIFIED\n    -        -c grep.patternType=default\n    -        # BRE\n    -        -c grep.extendedRegexp=false -c grep.patternType=default\n    -\n    -    But the difference won't matter, which simplifies some of this logic,\n    -    we never need to adjust a \"grep.patternType\" if we didn't see a\n    -    \"grep.extendedRegexp\" before. We can also remove the\n    -    \"extended_regexp_option\" member from \"struct grep_opt\" in favor of a\n    -    static variable in grep_config().\n    +    With this change the \"extended_regexp_option\" member is only used\n    +    within grep_config(), and in the current codebase we could equally\n    +    track it as a \"static\" variable within that function, see [1] for a\n    +    version for this patch that did that. We're keeping it a struct member\n    +    to make that function reentrant, in case it ends up mattering in the\n    +    future.\n     \n         The command-line parsing in cmd_grep() can then completely ignore\n         \"grep.extendedRegexp\". Whatever effect it had before that step won't\n    @@ Commit message\n         API, 2017-06-29) for addition of the two comments being removed here,\n         i.e. the complexity noted in that commit is now going away.\n     \n    +    1. https://lore.kernel.org/git/patch-v8-09.10-c211bb0c69d-20220118T155211Z-avarab@gmail.com/\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## builtin/grep.c ##\n    @@ grep.c: static int parse_pattern_type_arg(const char *opt, const char *arg)\n       * Read the configuration file once and store it in\n       * the grep_defaults template.\n     @@ grep.c: int grep_config(const char *var, const char *value, void *cb)\n    - {\n    - \tstruct grep_opt *opt = cb;\n    - \tconst char *slot;\n    -+\tstatic int ero = -1;\n    - \n    - \tif (userdiff_config(var, value) < 0)\n    - \t\treturn -1;\n      \n      \tif (!strcmp(var, \"grep.extendedregexp\")) {\n    --\t\topt->extended_regexp_option = git_config_bool(var, value);\n    -+\t\tero = git_config_bool(var, value);\n    -+\t\tadjust_pattern_type(&opt->pattern_type_option, ero);\n    + \t\topt->extended_regexp_option = git_config_bool(var, value);\n    ++\t\tadjust_pattern_type(&opt->pattern_type_option,\n    ++\t\t\t\t    opt->extended_regexp_option);\n      \t\treturn 0;\n      \t}\n      \n      \tif (!strcmp(var, \"grep.patterntype\")) {\n      \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n    -+\t\tif (ero == -1)\n    ++\t\tif (opt->extended_regexp_option == -1)\n     +\t\t\treturn 0;\n    -+\t\tadjust_pattern_type(&opt->pattern_type_option, ero);\n    ++\t\tadjust_pattern_type(&opt->pattern_type_option,\n    ++\t\t\t\t    opt->extended_regexp_option);\n      \t\treturn 0;\n      \t}\n      \n    @@ grep.h: struct grep_opt {\n      \tint pathname;\n      \tint null_following_name;\n     @@ grep.h: struct grep_opt {\n    - \tint max_depth;\n    - \tint funcname;\n    - \tint funcbody;\n    --\tint extended_regexp_option;\n    - \tenum grep_pattern_type pattern_type_option;\n    - \tint ignore_locale;\n    - \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n    + \t.relative = 1, \\\n    + \t.pathname = 1, \\\n    + \t.max_depth = -1, \\\n    ++\t.extended_regexp_option = -1, \\\n    + \t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n    + \t.colors = { \\\n    + \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n     @@ grep.h: struct grep_opt {\n      \n      int grep_config(const char *var, const char *value, void *);\n10:  b52a0c11fa9 <  -:  ----------- grep.[ch]: remove GREP_PATTERN_TYPE_UNSPECIFIED\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447065","messageId":"patch-v9-1.9-b9372cde017-20220127T115058Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v9-0.9-00000000000-20220127T115058Z-avarab@gmail.com","subject":"[PATCH v9 1/9] grep.h: remove unused \"regex_t regexp\" from grep_opt","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T11:56:23Z","receivedAt":"2022-01-27T11:56:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This \"regex_t\" in grep_opt has not been used since\nf9b9faf6f8a (builtin-grep: allow more than one patterns., 2006-05-02),\nwe still use a \"regex_t\" for compiling regexes, but that's in the\n\"grep_pat\" struct\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 6a1f0ab0172..400172676a1 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -136,7 +136,6 @@ struct grep_opt {\n \n \tconst char *prefix;\n \tint prefix_length;\n-\tregex_t regexp;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447066","messageId":"patch-v9-2.9-30219a0ae9d-20220127T115058Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v9-0.9-00000000000-20220127T115058Z-avarab@gmail.com","subject":"[PATCH v9 2/9] log tests: check if grep_config() is called by \"log\"-like cmds","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T11:56:24Z","receivedAt":"2022-01-27T11:56:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the tests added in my 9df46763ef1 (log: add exhaustive tests\nfor pattern style options & config, 2017-05-20) to check not only\nwhether \"git log\" handles \"grep.patternType\", but also \"git show\"\netc.\n\nIt's sufficient to check whether we match a \"fixed\" or a \"basic\" regex\nhere to see if these codepaths correctly invoked grep_config(). We\ndon't need to check the details of their regular expression matching\nas the \"log\" test does.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4202-log.sh | 24 ++++++++++++++++++++++++\n 1 file changed, 24 insertions(+)\n\ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex 50495598619..e775b378e4b 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -449,6 +449,30 @@ test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurati\n \t)\n '\n \n+for cmd in show whatchanged reflog format-patch\n+do\n+\tcase \"$cmd\" in\n+\tformat-patch) myarg=\"HEAD~..\" ;;\n+\t*) myarg= ;;\n+\tesac\n+\n+\ttest_expect_success \"$cmd: understands grep.patternType, like 'log'\" '\n+\t\tgit init \"pattern-type-$cmd\" &&\n+\t\t(\n+\t\t\tcd \"pattern-type-$cmd\" &&\n+\t\t\ttest_commit 1 file A &&\n+\t\t\ttest_commit \"(1|2)\" file B 2 &&\n+\n+\t\t\tgit -c grep.patternType=fixed $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_must_be_empty actual &&\n+\n+\t\t\tgit -c grep.patternType=basic $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_file_not_empty actual\n+\t\t)\n+\t'\n+done\n+test_done\n+\n test_expect_success 'log --author' '\n \tcat >expect <<-\\EOF &&\n \tAuthor: <BOLD;RED>A U<RESET> Thor <author@example.com>\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447067","messageId":"patch-v9-3.9-a75b288340b-20220127T115058Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v9-0.9-00000000000-20220127T115058Z-avarab@gmail.com","subject":"[PATCH v9 3/9] grep tests: add missing \"grep.patternType\" config tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T11:56:25Z","receivedAt":"2022-01-27T11:56:44Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the grep tests to assert that setting\n\"grep.patternType=extended\" followed by \"grep.patternType=default\"\nwill behave as if \"--basic-regexp\" was provided, and not as\n\"--extended-regexp\". In a subsequent commit we'll need to treat\n\"grep.patternType=default\" as a special-case, but let's make sure we\nignore it if it's being set to \"default\" following an earlier\nnon-\"default\" \"grep.patternType\" setting.\n\nLet's also test what happens when we have a sequence of \"extended\"\nfollowed by \"default\" and \"fixed\". In that case the \"fixed\" should\nprevail, as well as tests to check that a \"grep.extendedRegexp=true\"\nfollowed by a \"grep.extendedRegexp=false\" behaves as though\n\"grep.extendedRegexp\" wasn't provided.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t7810-grep.sh | 68 +++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 68 insertions(+)\n\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 424c31c3287..34d8f69c1de 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -451,6 +451,65 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=basic \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins & defers to grep.patternType\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=fixed \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (ERE)\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=basic \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.patternType=[extended -> default -> fixed]\" '\n+\t\techo \"${HC}ab:a+b*c\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\t-c grep.patternType=fixed \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.patternType=extended and grep.extendedRegexp=false\" '\n \t\techo \"${HC}ab:abc\" >expected &&\n \t\tgit \\\n@@ -478,6 +537,15 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.extendedRegexp=false and grep.patternType=default\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.extendedRegexp=true and grep.patternType=basic\" '\n \t\techo \"${HC}ab:a+bc\" >expected &&\n \t\tgit \\\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447068","messageId":"patch-v9-4.9-6e7f9730a7d-20220127T115058Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v9-0.9-00000000000-20220127T115058Z-avarab@gmail.com","subject":"[PATCH v9 4/9] built-ins: trust the \"prefix\" from run_builtin()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T11:56:26Z","receivedAt":"2022-01-27T11:56:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in \"builtin/grep.c\" and \"builtin/ls-tree.c\" to trust the\n\"prefix\" passed from \"run_builtin()\". The \"prefix\" we get from setup.c\nis either going to be NULL or a string of length >0, never \"\".\n\nSo we can drop the \"prefix && *prefix\" checks added for\n\"builtin/grep.c\" in 0d042fecf2f (git-grep: show pathnames relative to\nthe current directory, 2006-08-11), and for \"builtin/ls-tree.c\" in\na69dd585fca (ls-tree: chomp leading directories when run from a\nsubdirectory, 2005-12-23).\n\nAs seen in code in revision.c that was added in cd676a51367 (diff\n--relative: output paths as relative to the current subdirectory,\n2008-02-12) we already have existing code that does away with this\nassertion.\n\nThis makes it easier to reason about a subsequent change to the\n\"prefix_length\" code in grep.c in a subsequent commit, and since we're\ngoing to the trouble of doing that let's leave behind an assert() to\npromise this to any future callers.\n\nFor \"builtin/grep.c\" it would be painful to pass the \"prefix\" down the\ncallchain of:\n\n    cmd_grep -> grep_tree -> grep_submodule -> grep_cache -> grep_oid ->\n    grep_source_name\n\nSo for the code that needs it in grep_source_name() let's add a\n\"grep_prefix\" variable similar to the existing \"ls_tree_prefix\".\n\nWhile at it let's move the code in cmd_ls_tree() around so that we\nassign to the \"ls_tree_prefix\" right after declaring the variables,\nand stop assigning to \"prefix\". We only subsequently used that\nvariable later in the function after clobbering it. Let's just use our\nown \"grep_prefix\" instead.\n\nLet's also add an assert() in git.c, so that we'll make this promise\nabout the \"prefix\" to any current and future callers, as well as to\nany readers of the code.\n\nCode history:\n\n * The strlen() in \"grep.c\" hasn't been used since 493b7a08d80 (grep:\n   accept relative paths outside current working directory, 2009-09-05).\n\n   When that code was added in 0d042fecf2f (git-grep: show pathnames\n   relative to the current directory, 2006-08-11) we used the length.\n\n   But since 493b7a08d80 we haven't used it for anything except a\n   boolean check that we could have done on the \"prefix\" member\n   itself.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c    | 13 ++++++++-----\n builtin/ls-tree.c |  2 +-\n git.c             |  1 +\n grep.c            |  4 +---\n grep.h            |  4 +---\n revision.c        |  2 +-\n 6 files changed, 13 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 9e34a820ad4..d85cbabea67 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -26,6 +26,8 @@\n #include \"object-store.h\"\n #include \"packfile.h\"\n \n+static const char *grep_prefix;\n+\n static char const * const grep_usage[] = {\n \tN_(\"git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]\"),\n \tNULL\n@@ -315,11 +317,11 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \tstrbuf_reset(out);\n \n \tif (opt->null_following_name) {\n-\t\tif (opt->relative && opt->prefix_length) {\n+\t\tif (opt->relative && grep_prefix) {\n \t\t\tstruct strbuf rel_buf = STRBUF_INIT;\n \t\t\tconst char *rel_name =\n \t\t\t\trelative_path(filename + tree_name_len,\n-\t\t\t\t\t      opt->prefix, &rel_buf);\n+\t\t\t\t\t      grep_prefix, &rel_buf);\n \n \t\t\tif (tree_name_len)\n \t\t\t\tstrbuf_add(out, filename, tree_name_len);\n@@ -332,8 +334,8 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \t\treturn;\n \t}\n \n-\tif (opt->relative && opt->prefix_length)\n-\t\tquote_path(filename + tree_name_len, opt->prefix, out, 0);\n+\tif (opt->relative && grep_prefix)\n+\t\tquote_path(filename + tree_name_len, grep_prefix, out, 0);\n \telse\n \t\tquote_c_style(filename + tree_name_len, out, NULL, 0);\n \n@@ -962,9 +964,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\t   PARSE_OPT_NOCOMPLETE),\n \t\tOPT_END()\n \t};\n+\tgrep_prefix = prefix;\n \n \tgit_config(grep_cmd_config, NULL);\n-\tgrep_init(&opt, the_repository, prefix);\n+\tgrep_init(&opt, the_repository);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 3a442631c71..6cb554cbb0a 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -150,7 +150,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \n \tgit_config(git_default_config, NULL);\n \tls_tree_prefix = prefix;\n-\tif (prefix && *prefix)\n+\tif (prefix)\n \t\tchomp_prefix = strlen(prefix);\n \n \targc = parse_options(argc, argv, prefix, ls_tree_options,\ndiff --git a/git.c b/git.c\nindex edda922ce6d..9d257e092da 100644\n--- a/git.c\n+++ b/git.c\n@@ -436,6 +436,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t} else {\n \t\tprefix = NULL;\n \t}\n+\tassert(!prefix || *prefix);\n \tprecompose_argv_prefix(argc, argv, NULL);\n \tif (use_pager == -1 && run_setup &&\n \t\t!(p->option & DELAY_PAGER_CONFIG))\ndiff --git a/grep.c b/grep.c\nindex 7bb0360869a..8421dc55486 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -139,13 +139,11 @@ int grep_config(const char *var, const char *value, void *cb)\n  * default values from the template we read the configuration\n  * information in an earlier call to git_config(grep_config).\n  */\n-void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)\n+void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n \t*opt = grep_defaults;\n \n \topt->repo = repo;\n-\topt->prefix = prefix;\n-\topt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;\n \topt->pattern_tail = &opt->pattern_list;\n \topt->header_tail = &opt->header_list;\n }\ndiff --git a/grep.h b/grep.h\nindex 400172676a1..23a2a41d2c4 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -134,8 +134,6 @@ struct grep_opt {\n \t */\n \tstruct repository *repo;\n \n-\tconst char *prefix;\n-\tint prefix_length;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n@@ -182,7 +180,7 @@ struct grep_opt {\n };\n \n int grep_config(const char *var, const char *value, void *);\n-void grep_init(struct grep_opt *, struct repository *repo, const char *prefix);\n+void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex ad4286fbdde..d6e0e2b23b5 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1838,7 +1838,7 @@ void repo_init_revisions(struct repository *r,\n \trevs->commit_format = CMIT_FMT_DEFAULT;\n \trevs->expand_tabs_in_log_default = 8;\n \n-\tgrep_init(&revs->grep_filter, revs->repo, prefix);\n+\tgrep_init(&revs->grep_filter, revs->repo);\n \trevs->grep_filter.status_only = 1;\n \n \trepo_diff_setup(revs->repo, &revs->diffopt);\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447069","messageId":"patch-v9-5.9-fbcfea84696-20220127T115058Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v9-0.9-00000000000-20220127T115058Z-avarab@gmail.com","subject":"[PATCH v9 5/9] grep.c: don't pass along NULL callback value","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T11:56:27Z","receivedAt":"2022-01-27T11:56:47Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change grep_cmd_config() to stop passing around the always-NULL \"cb\"\nvalue. When this code was added in 7e8f59d577e (grep: color patterns\nin output, 2009-03-07) it was non-NULL, but when that changed in\n15fabd1bbd4 (builtin/grep.c: make configuration callback more\nreusable, 2012-10-09) this code was left behind.\n\nIn a subsequent change I'll start using the \"cb\" value, this will make\nit clear which functions we call need it, and which don't.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex d85cbabea67..5ec4cecae45 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,8 +285,8 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, cb);\n-\tif (git_color_default_config(var, value, cb) < 0)\n+\tint st = grep_config(var, value, NULL);\n+\tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n \tif (!strcmp(var, \"grep.threads\")) {\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447070","messageId":"patch-v9-6.9-96c8cc7806e-20220127T115058Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v9-0.9-00000000000-20220127T115058Z-avarab@gmail.com","subject":"[PATCH v9 6/9] grep API: call grep_config() after grep_init()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T11:56:28Z","receivedAt":"2022-01-27T11:56:48Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The grep_init() function used the odd pattern of initializing the\npassed-in \"struct grep_opt\" with a statically defined \"grep_defaults\"\nstruct, which would be modified in-place when we invoked\ngrep_config().\n\nSo we effectively (b) initialized config, (a) then defaults, (c)\nfollowed by user options. Usually those are ordered as \"a\", \"b\" and\n\"c\" instead.\n\nAs the comments being removed here show the previous behavior needed\nto be carefully explained as we'd potentially share the populated\nconfiguration among different instances of grep_init(). In practice we\ndidn't do that, but now that it can't be a concern anymore let's\nremove those comments.\n\nThis does not change the behavior of any of the configuration\nvariables or options. That would have been the case if we didn't move\naround the grep_config() call in \"builtin/log.c\". But now that we call\n\"grep_config\" after \"git_log_config\" and \"git_format_config\" we'll\nneed to pass in the already initialized \"struct grep_opt *\".\n\nSee 6ba9bb76e02 (grep: copy struct in one fell swoop, 2020-11-29) and\n7687a0541e0 (grep: move the configuration parsing logic to grep.[ch],\n2012-10-09) for the commits that added the comments.\n\nThe memcpy() pattern here will be optimized away and follows the\nconvention of other *_init() functions. See 5726a6b4012 (*.c *_init():\ndefine in terms of corresponding *_INIT macro, 2021-07-01).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c |  4 ++--\n builtin/log.c  | 13 +++++++++++--\n grep.c         | 39 +++------------------------------------\n grep.h         | 21 +++++++++++++++++++++\n 4 files changed, 37 insertions(+), 40 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5ec4cecae45..0ea124321b6 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,7 +285,7 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, NULL);\n+\tint st = grep_config(var, value, cb);\n \tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n@@ -966,8 +966,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t};\n \tgrep_prefix = prefix;\n \n-\tgit_config(grep_cmd_config, NULL);\n \tgrep_init(&opt, the_repository);\n+\tgit_config(grep_cmd_config, &opt);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 4b493408cc5..06283b37e7a 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -520,8 +520,6 @@ static int git_log_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n-\tif (grep_config(var, value, cb) < 0)\n-\t\treturn -1;\n \tif (git_gpg_config(var, value, cb) < 0)\n \t\treturn -1;\n \treturn git_diff_ui_config(var, value, cb);\n@@ -536,6 +534,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.simplify_history = 0;\n \tmemset(&opt, 0, sizeof(opt));\n@@ -650,6 +650,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \n \tmemset(&match_all, 0, sizeof(match_all));\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.always_show_header = 1;\n \trev.no_walk = 1;\n@@ -733,6 +735,8 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n \tinit_reflog_walk(&rev.reflog_info);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.verbose_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -766,6 +770,8 @@ int cmd_log(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.always_show_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -1848,10 +1854,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \textra_hdr.strdup_strings = 1;\n \textra_to.strdup_strings = 1;\n \textra_cc.strdup_strings = 1;\n+\n \tinit_log_defaults();\n \tinit_display_notes(&notes_opt);\n \tgit_config(git_format_config, NULL);\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.show_notes = show_notes;\n \tmemcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));\n \trev.commit_format = CMIT_FMT_EMAIL;\ndiff --git a/grep.c b/grep.c\nindex 8421dc55486..35e12e43c09 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -19,27 +19,6 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)\n \tfwrite(buf, size, 1, stdout);\n }\n \n-static struct grep_opt grep_defaults = {\n-\t.relative = 1,\n-\t.pathname = 1,\n-\t.max_depth = -1,\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t.colors = {\n-\t\t[GREP_COLOR_CONTEXT] = \"\",\n-\t\t[GREP_COLOR_FILENAME] = GIT_COLOR_MAGENTA,\n-\t\t[GREP_COLOR_FUNCTION] = \"\",\n-\t\t[GREP_COLOR_LINENO] = GIT_COLOR_GREEN,\n-\t\t[GREP_COLOR_COLUMNNO] = GIT_COLOR_GREEN,\n-\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_SELECTED] = \"\",\n-\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN,\n-\t},\n-\t.only_matching = 0,\n-\t.color = -1,\n-\t.output = std_output,\n-};\n-\n static const char *color_grep_slots[] = {\n \t[GREP_COLOR_CONTEXT]\t    = \"context\",\n \t[GREP_COLOR_FILENAME]\t    = \"filename\",\n@@ -75,20 +54,12 @@ define_list_config_array_extra(color_grep_slots, {\"match\"});\n  */\n int grep_config(const char *var, const char *value, void *cb)\n {\n-\tstruct grep_opt *opt = &grep_defaults;\n+\tstruct grep_opt *opt = cb;\n \tconst char *slot;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\t/*\n-\t * The instance of grep_opt that we set up here is copied by\n-\t * grep_init() to be used by each individual invocation.\n-\t * When populating a new field of this structure here, be\n-\t * sure to think about ownership -- e.g., you might need to\n-\t * override the shallow copy in grep_init() with a deep copy.\n-\t */\n-\n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n \t\treturn 0;\n@@ -134,14 +105,10 @@ int grep_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/*\n- * Initialize one instance of grep_opt and copy the\n- * default values from the template we read the configuration\n- * information in an earlier call to git_config(grep_config).\n- */\n void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n-\t*opt = grep_defaults;\n+\tstruct grep_opt blank = GREP_OPT_INIT;\n+\tmemcpy(opt, &blank, sizeof(*opt));\n \n \topt->repo = repo;\n \topt->pattern_tail = &opt->pattern_list;\ndiff --git a/grep.h b/grep.h\nindex 23a2a41d2c4..3112d1c2a38 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -179,6 +179,27 @@ struct grep_opt {\n \tvoid *output_priv;\n };\n \n+#define GREP_OPT_INIT { \\\n+\t.relative = 1, \\\n+\t.pathname = 1, \\\n+\t.max_depth = -1, \\\n+\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n+\t.colors = { \\\n+\t\t[GREP_COLOR_CONTEXT] = \"\", \\\n+\t\t[GREP_COLOR_FILENAME] = GIT_COLOR_MAGENTA, \\\n+\t\t[GREP_COLOR_FUNCTION] = \"\", \\\n+\t\t[GREP_COLOR_LINENO] = GIT_COLOR_GREEN, \\\n+\t\t[GREP_COLOR_COLUMNNO] = GIT_COLOR_GREEN, \\\n+\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_SELECTED] = \"\", \\\n+\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n+\t}, \\\n+\t.only_matching = 0, \\\n+\t.color = -1, \\\n+\t.output = std_output, \\\n+}\n+\n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447071","messageId":"patch-v9-7.9-e09616056b4-20220127T115058Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v9-0.9-00000000000-20220127T115058Z-avarab@gmail.com","subject":"[PATCH v9 7/9] grep.h: make \"grep_opt.pattern_type_option\" use its enum","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T11:56:29Z","receivedAt":"2022-01-27T11:56:51Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the \"pattern_type_option\" member of \"struct grep_opt\" to use\nthe enum type we use for it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 3112d1c2a38..89a2ce51130 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -164,7 +164,7 @@ struct grep_opt {\n \tint funcname;\n \tint funcbody;\n \tint extended_regexp_option;\n-\tint pattern_type_option;\n+\tenum grep_pattern_type pattern_type_option;\n \tint ignore_locale;\n \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n \tunsigned pre_context;\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447072","messageId":"patch-v9-9.9-445467e87f7-20220127T115058Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v9-0.9-00000000000-20220127T115058Z-avarab@gmail.com","subject":"[PATCH v9 9/9] grep: simplify config parsing and option parsing","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T11:56:31Z","receivedAt":"2022-01-27T11:56:56Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Simplify the parsing of \"grep.patternType\" and\n\"grep.extendedRegexp\". This changes no behavior, but gets rid of\ncomplex parsing logic that isn't needed anymore.\n\nWhen \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\ngrep.patternType configuration setting, 2012-08-03) we promised that:\n\n 1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n    will return to the default matching behavior\".\n\n    In that context \"the default\" meant whatever the configuration\n    system specified before that change, i.e. via grep.extendedRegexp.\n\n 2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n    it when the new \"grep.patternType\" option is set. We said we'd\n    only ignore the older \"grep.extendedRegexp\" option \"when the\n    `grep.patternType` option is set to a value other than\n    'default'\".\n\nIn a preceding commit we changed grep_config() to be called after\ngrep_init(), which means that much of the complexity here can go\naway.\n\nAs before both \"grep.patternType\" and \"grep.extendedRegexp\" are\nlast-one-wins variable, with \"grep.extendedRegexp\" yielding to\n\"grep.patternType\", except when \"grep.patternType=default\".\n\nNote that this applies as we parse the config, i.e. a sequence of:\n\n    -c grep.patternType=perl\n    -c grep.extendedRegexp=true \\\n    -c grep.patternType=default\n\nshould select ERE due to \"grep.extendedRegexp=true and\ngrep.patternType=default\". We can determine this as we parse the\nconfig, because:\n\n * If we see \"grep.extendedRegexp\" we set \"extended_regexp_option\" to\n   its boolean value.\n\n * If we see \"grep.extendedRegexp\" but\n   \"grep.patternType=[default|<unset>]\" is in effect we *don't* set\n   the internal \"pattern_type_option\" to update the pattern type.\n\n * If we see \"grep.patternType!=default\" we can set our internal\n   \"pattern_type_option\" directly, it doesn't matter what the state of\n   \"extended_regexp_option\" is, but we don't forget what it was, in\n   case we see a \"grep.patternType=default\" again.\n\n * If we see a \"grep.patternType=default\" we can set the pattern to\n   ERE or BRE depending on whether we last saw a\n   \"grep.extendedRegexp=true\" or\n   \"grep.extendedRegexp=[false|<unset>]\".\n\nWith this change the \"extended_regexp_option\" member is only used\nwithin grep_config(), and in the current codebase we could equally\ntrack it as a \"static\" variable within that function, see [1] for a\nversion for this patch that did that. We're keeping it a struct member\nto make that function reentrant, in case it ends up mattering in the\nfuture.\n\nThe command-line parsing in cmd_grep() can then completely ignore\n\"grep.extendedRegexp\". Whatever effect it had before that step won't\nmatter if we see -G, -E, -P etc.\n\nSee my 07a3d411739 (grep: remove regflags from the public grep_opt\nAPI, 2017-06-29) for addition of the two comments being removed here,\ni.e. the complexity noted in that commit is now going away.\n\n1. https://lore.kernel.org/git/patch-v8-09.10-c211bb0c69d-20220118T155211Z-avarab@gmail.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 10 +++----\n grep.c         | 76 +++++++++++---------------------------------------\n grep.h         |  4 +--\n revision.c     |  2 --\n 4 files changed, 21 insertions(+), 71 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 0ea124321b6..942c4b25077 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -845,7 +845,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tint i;\n \tint dummy;\n \tint use_index = 1;\n-\tint pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;\n \tint allow_revs;\n \n \tstruct option options[] = {\n@@ -879,16 +878,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"descend at most <depth> levels\"), PARSE_OPT_NONEG,\n \t\t\tNULL, 1 },\n \t\tOPT_GROUP(\"\"),\n-\t\tOPT_SET_INT('E', \"extended-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('E', \"extended-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use extended POSIX regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_ERE),\n-\t\tOPT_SET_INT('G', \"basic-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('G', \"basic-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use basic POSIX regular expressions (default)\"),\n \t\t\t    GREP_PATTERN_TYPE_BRE),\n-\t\tOPT_SET_INT('F', \"fixed-strings\", &pattern_type_arg,\n+\t\tOPT_SET_INT('F', \"fixed-strings\", &opt.pattern_type_option,\n \t\t\t    N_(\"interpret patterns as fixed strings\"),\n \t\t\t    GREP_PATTERN_TYPE_FIXED),\n-\t\tOPT_SET_INT('P', \"perl-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('P', \"perl-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use Perl-compatible regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_PCRE),\n \t\tOPT_GROUP(\"\"),\n@@ -982,7 +981,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, grep_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH |\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n-\tgrep_commit_pattern_type(pattern_type_arg, &opt);\n \n \tif (use_index && !startup_info->have_repository) {\n \t\tint fallback = 0;\ndiff --git a/grep.c b/grep.c\nindex 60228a95a4f..f07a21ff1aa 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -48,6 +48,12 @@ static int parse_pattern_type_arg(const char *opt, const char *arg)\n \n define_list_config_array_extra(color_grep_slots, {\"match\"});\n \n+static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n+{\n+\tif (*pto == GREP_PATTERN_TYPE_UNSPECIFIED)\n+\t\t*pto = ero ? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n+}\n+\n /*\n  * Read the configuration file once and store it in\n  * the grep_defaults template.\n@@ -62,11 +68,17 @@ int grep_config(const char *var, const char *value, void *cb)\n \n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n+\t\tadjust_pattern_type(&opt->pattern_type_option,\n+\t\t\t\t    opt->extended_regexp_option);\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(var, \"grep.patterntype\")) {\n \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n+\t\tif (opt->extended_regexp_option == -1)\n+\t\t\treturn 0;\n+\t\tadjust_pattern_type(&opt->pattern_type_option,\n+\t\t\t\t    opt->extended_regexp_option);\n \t\treturn 0;\n \t}\n \n@@ -115,62 +127,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo)\n \topt->header_tail = &opt->header_list;\n }\n \n-static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\t/*\n-\t * When committing to the pattern type by setting the relevant\n-\t * fields in grep_opt it's generally not necessary to zero out\n-\t * the fields we're not choosing, since they won't have been\n-\t * set by anything. The extended_regexp_option field is the\n-\t * only exception to this.\n-\t *\n-\t * This is because in the process of parsing grep.patternType\n-\t * & grep.extendedRegexp we set opt->pattern_type_option and\n-\t * opt->extended_regexp_option, respectively. We then\n-\t * internally use opt->extended_regexp_option to see if we're\n-\t * compiling an ERE. It must be unset if that's not actually\n-\t * the case.\n-\t */\n-\tif (pattern_type != GREP_PATTERN_TYPE_ERE &&\n-\t    opt->extended_regexp_option)\n-\t\topt->extended_regexp_option = 0;\n-\n-\tswitch (pattern_type) {\n-\tcase GREP_PATTERN_TYPE_UNSPECIFIED:\n-\t\t/* fall through */\n-\n-\tcase GREP_PATTERN_TYPE_BRE:\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_ERE:\n-\t\topt->extended_regexp_option = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_FIXED:\n-\t\topt->fixed = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_PCRE:\n-\t\topt->pcre2 = 1;\n-\t\tbreak;\n-\t}\n-}\n-\n-void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\tif (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(pattern_type, opt);\n-\telse if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(opt->pattern_type_option, opt);\n-\telse if (opt->extended_regexp_option)\n-\t\t/*\n-\t\t * This branch *must* happen after setting from the\n-\t\t * opt->pattern_type_option above, we don't want\n-\t\t * grep.extendedRegexp to override grep.patternType!\n-\t\t */\n-\t\tgrep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);\n-}\n-\n static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,\n \t\t\t\t\tconst char *origin, int no,\n \t\t\t\t\tenum grep_pat_token t,\n@@ -490,9 +446,9 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \n \tp->word_regexp = opt->word_regexp;\n \tp->ignore_case = opt->ignore_case;\n-\tp->fixed = opt->fixed;\n+\tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\n \n-\tif (!opt->pcre2 &&\n+\tif (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE &&\n \t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n@@ -544,14 +500,14 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \t\treturn;\n \t}\n \n-\tif (opt->pcre2) {\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_PCRE) {\n \t\tcompile_pcre2_pattern(p, opt);\n \t\treturn;\n \t}\n \n \tif (p->ignore_case)\n \t\tregflags |= REG_ICASE;\n-\tif (opt->extended_regexp_option)\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_ERE)\n \t\tregflags |= REG_EXTENDED;\n \terr = regcomp(&p->regexp, p->pattern, regflags);\n \tif (err) {\ndiff --git a/grep.h b/grep.h\nindex 89a2ce51130..f89324e9aa9 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -143,7 +143,6 @@ struct grep_opt {\n \tint unmatch_name_only;\n \tint count;\n \tint word_regexp;\n-\tint fixed;\n \tint all_match;\n \tint no_body_match;\n \tint body_hit;\n@@ -154,7 +153,6 @@ struct grep_opt {\n \tint allow_textconv;\n \tint extended;\n \tint use_reflog_filter;\n-\tint pcre2;\n \tint relative;\n \tint pathname;\n \tint null_following_name;\n@@ -183,6 +181,7 @@ struct grep_opt {\n \t.relative = 1, \\\n \t.pathname = 1, \\\n \t.max_depth = -1, \\\n+\t.extended_regexp_option = -1, \\\n \t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n \t.colors = { \\\n \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n@@ -202,7 +201,6 @@ struct grep_opt {\n \n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n-void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\n void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex d6e0e2b23b5..dd301e30147 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2860,8 +2860,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \n \tdiff_setup_done(&revs->diffopt);\n \n-\tgrep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t\t\t\t &revs->grep_filter);\n \tif (!is_encoding_utf8(get_log_output_encoding()))\n \t\trevs->grep_filter.ignore_locale = 1;\n \tcompile_grep_patterns(&revs->grep_filter);\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447073","messageId":"patch-v9-8.9-61fc6a4dac8-20220127T115058Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v9-0.9-00000000000-20220127T115058Z-avarab@gmail.com","subject":"[PATCH v9 8/9] grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-01-27T11:56:30Z","receivedAt":"2022-01-27T11:57:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in compile_regexp() to check the cheaper boolean\n\"!opt->pcre2\" condition before the \"memchr()\" search.\n\nThis doesn't noticeably optimize anything, but makes the code more\nobvious and conventional. The line wrapping being added here also\nmakes a subsequent commit smaller.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/grep.c b/grep.c\nindex 35e12e43c09..60228a95a4f 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -492,7 +492,8 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \tp->ignore_case = opt->ignore_case;\n \tp->fixed = opt->fixed;\n \n-\tif (memchr(p->pattern, 0, p->patternlen) && !opt->pcre2)\n+\tif (!opt->pcre2 &&\n+\t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n \tp->is_fixed = is_fixed(p->pattern, p->patternlen);\n-- \n2.35.0.894.g563b84683b9\n\n"},{"id":"447127","messageId":"xmqq35l82a7i.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v9-9.9-445467e87f7-20220127T115058Z-avarab@gmail.com","subject":"Re: [PATCH v9 9/9] grep: simplify config parsing and option parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-01-27T20:30:09Z","receivedAt":"2022-01-27T20:30:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> In a preceding commit we changed grep_config() to be called after\n> grep_init(), which means that much of the complexity here can go\n> away.\n>\n> As before both \"grep.patternType\" and \"grep.extendedRegexp\" are\n> last-one-wins variable, with \"grep.extendedRegexp\" yielding to\n> \"grep.patternType\", except when \"grep.patternType=default\".\n>\n> Note that this applies as we parse the config, i.e. a sequence of:\n>\n>     -c grep.patternType=perl\n>     -c grep.extendedRegexp=true \\\n>     -c grep.patternType=default\n>\n> should select ERE due to \"grep.extendedRegexp=true and\n> grep.patternType=default\".\n\nCorrect.  The same reasoning would apply to:\n\n\t-c grep.extendedRegexp=true \\ \n\t-c grep.patternType=perl \\\n\t-c grep.patternType=default\n\nwhich should also select ERE due to \"grep.extendedRegexp=true and\ngrep.patternType=default\".  As we re-check grep.extendedRegexp every\ntime grep.patternType changes, and we keep extendedRegexp as a\nseparate copy without getting lost like earlier rounds of this\nseries, this should work.\n\nWould this also work?\n\n\t-c grep.extendedRegexp=false \\\n\t-c grep.patternType=default \\\n\t-c grep.extendedRegexp=true\n\nWe do keep extendedRegexp, but as soon as we read .patternType that\nis default, adjust_pattern_type() overwrites the pattern_type_option\nmember with BRE, and the fact that .patternType was specified as \"do\nwhatever the .extendedRegexp says\" is lost when we read the third\none.\n\nSo, no, I am not sure this is correct.\n\n> diff --git a/grep.c b/grep.c\n> index 60228a95a4f..f07a21ff1aa 100644\n> --- a/grep.c\n> +++ b/grep.c\n> @@ -48,6 +48,12 @@ static int parse_pattern_type_arg(const char *opt, const char *arg)\n>  \n>  define_list_config_array_extra(color_grep_slots, {\"match\"});\n>  \n> +static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n> +{\n> +\tif (*pto == GREP_PATTERN_TYPE_UNSPECIFIED)\n> +\t\t*pto = ero ? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n> +}\n\nOK.  Earlier rounds just replaced the UNSPECIFIED with hardcoded value \"0\",\nwhich was more or less pointless.  I think this is easier to follow.\n\nBut as I said, \"committing\" ERE vs BRE in this manner is probably\nway too early and produce an incorrect result.  Instead ...\n\n> @@ -490,9 +446,9 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n\n... this is the right place to do the \"see if pattern_type_option is\n'default' and if so use 'extended_regexp_option' to commit to either\nBRE or ERE\".\n\nI guess that is what I have been repeating during the review of the\npast few rounds.  Am I overlooking some other cases where that\nsimpler-to-explain approach does not work?\n\n>  \tp->word_regexp = opt->word_regexp;\n>  \tp->ignore_case = opt->ignore_case;\n> -\tp->fixed = opt->fixed;\n> +\tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\n>  \n> -\tif (!opt->pcre2 &&\n> +\tif (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE &&\n>  \t    memchr(p->pattern, 0, p->patternlen))\n>  \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n>  \n> @@ -544,14 +500,14 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n>  \t\treturn;\n>  \t}\n>  \n> -\tif (opt->pcre2) {\n> +\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_PCRE) {\n>  \t\tcompile_pcre2_pattern(p, opt);\n>  \t\treturn;\n>  \t}\n>  \n>  \tif (p->ignore_case)\n>  \t\tregflags |= REG_ICASE;\n> -\tif (opt->extended_regexp_option)\n> +\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_ERE)\n>  \t\tregflags |= REG_EXTENDED;\n>  \terr = regcomp(&p->regexp, p->pattern, regflags);\n>  \tif (err) {\n> diff --git a/grep.h b/grep.h\n> index 89a2ce51130..f89324e9aa9 100644\n> --- a/grep.h\n> +++ b/grep.h\n> @@ -143,7 +143,6 @@ struct grep_opt {\n>  \tint unmatch_name_only;\n>  \tint count;\n>  \tint word_regexp;\n> -\tint fixed;\n>  \tint all_match;\n>  \tint no_body_match;\n>  \tint body_hit;\n> @@ -154,7 +153,6 @@ struct grep_opt {\n>  \tint allow_textconv;\n>  \tint extended;\n>  \tint use_reflog_filter;\n> -\tint pcre2;\n>  \tint relative;\n>  \tint pathname;\n>  \tint null_following_name;\n> @@ -183,6 +181,7 @@ struct grep_opt {\n>  \t.relative = 1, \\\n>  \t.pathname = 1, \\\n>  \t.max_depth = -1, \\\n> +\t.extended_regexp_option = -1, \\\n\nI do not think you meant this.  Uninitialized grep.extendedRegexp\ndefaults to 0 (BRE), I think.\n\n>  \t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n>  \t.colors = { \\\n>  \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n> @@ -202,7 +201,6 @@ struct grep_opt {\n>  \n>  int grep_config(const char *var, const char *value, void *);\n>  void grep_init(struct grep_opt *, struct repository *repo);\n> -void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n>  \n>  void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\n>  void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);\n> diff --git a/revision.c b/revision.c\n> index d6e0e2b23b5..dd301e30147 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -2860,8 +2860,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n>  \n>  \tdiff_setup_done(&revs->diffopt);\n>  \n> -\tgrep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,\n> -\t\t\t\t &revs->grep_filter);\n>  \tif (!is_encoding_utf8(get_log_output_encoding()))\n>  \t\trevs->grep_filter.ignore_locale = 1;\n>  \tcompile_grep_patterns(&revs->grep_filter);\n"},{"id":"447135","messageId":"xmqqpmoczwtu.fsf@gitster.g","threadId":"56853","inReplyTo":"xmqq35l82a7i.fsf@gitster.g","subject":"Re: [PATCH v9 9/9] grep: simplify config parsing and option parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-01-27T21:35:09Z","receivedAt":"2022-01-27T21:35:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Would this also work?\n>\n> \t-c grep.extendedRegexp=false \\\n> \t-c grep.patternType=default \\\n> \t-c grep.extendedRegexp=true\n>\n> We do keep extendedRegexp, but as soon as we read .patternType that\n> is default, adjust_pattern_type() overwrites the pattern_type_option\n> member with BRE, and the fact that .patternType was specified as \"do\n> whatever the .extendedRegexp says\" is lost when we read the third\n> one.\n>\n> So, no, I am not sure this is correct.\n> ...\n> But as I said, \"committing\" ERE vs BRE in this manner is probably\n> way too early and produce an incorrect result.  Instead ...\n>\n>> @@ -490,9 +446,9 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n>\n> ... this is the right place to do the \"see if pattern_type_option is\n> 'default' and if so use 'extended_regexp_option' to commit to either\n> BRE or ERE\".\n>\n> I guess that is what I have been repeating during the review of the\n> past few rounds.  Am I overlooking some other cases where that\n> simpler-to-explain approach does not work?\n> ...\n>>  \t.max_depth = -1, \\\n>> +\t.extended_regexp_option = -1, \\\n>\n> I do not think you meant this.  Uninitialized grep.extendedRegexp\n> defaults to 0 (BRE), I think.\n\nTaking all together, here is a squashable fix with an additional\ntest.\n\nIn addition to squashing the following in, we must update the\nproposed log message.  Given that, even after taking _this long_ (I\nthink I have been saying this since the review of v5 iteration),\nthis series is still making the same mistake again, the fact that\nthe code needs to read all the configuration variables before it can\ncorrectly decide what type the user really means deserves to be\nstressed in the log message.\n\nDespite what the proposed log message for this round (and many other\nprevious iterations) claimed, it fundamentally cannot be done inside\nthe callback, simply because the callback will not know how many\nmore times it will be called with what value for grep.patternType\nand grep.extendedRegexp.  It can be done anywhere after the option\nparser has finished reading all the options and knows there will not\nbe any more grep.patternType and grep.extendedRegexp that would\naffect the computation.  One of the most natural such place is at\nthe beginning of compile_regexp(), I would think.\n\nOther than that, all the previous steps looked good, so did the\nparts of this commit that the attached fix-up does not touch.  It is\ngreat that we do not have to carry \"fixed\", \"pcre\", etc. around as\nseparate members.\n\nThanks.\n\n grep.c          | 17 +++++------------\n grep.h          |  2 +-\n t/t7810-grep.sh | 10 ++++++++++\n 3 files changed, 16 insertions(+), 13 deletions(-)\n\ndiff --git c/grep.c w/grep.c\nindex f07a21ff1a..a8f503f55c 100644\n--- c/grep.c\n+++ w/grep.c\n@@ -48,12 +48,6 @@ static int parse_pattern_type_arg(const char *opt, const char *arg)\n \n define_list_config_array_extra(color_grep_slots, {\"match\"});\n \n-static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n-{\n-\tif (*pto == GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\t*pto = ero ? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n-}\n-\n /*\n  * Read the configuration file once and store it in\n  * the grep_defaults template.\n@@ -68,17 +62,11 @@ int grep_config(const char *var, const char *value, void *cb)\n \n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n-\t\tadjust_pattern_type(&opt->pattern_type_option,\n-\t\t\t\t    opt->extended_regexp_option);\n \t\treturn 0;\n \t}\n \n \tif (!strcmp(var, \"grep.patterntype\")) {\n \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n-\t\tif (opt->extended_regexp_option == -1)\n-\t\t\treturn 0;\n-\t\tadjust_pattern_type(&opt->pattern_type_option,\n-\t\t\t\t    opt->extended_regexp_option);\n \t\treturn 0;\n \t}\n \n@@ -444,6 +432,11 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \tint err;\n \tint regflags = REG_NEWLINE;\n \n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_UNSPECIFIED)\n+\t\topt->pattern_type_option = (opt->extended_regexp_option\n+\t\t\t\t\t    ? GREP_PATTERN_TYPE_ERE\n+\t\t\t\t\t    : GREP_PATTERN_TYPE_BRE);\n+\n \tp->word_regexp = opt->word_regexp;\n \tp->ignore_case = opt->ignore_case;\n \tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\ndiff --git c/grep.h w/grep.h\nindex f89324e9aa..bdc6765482 100644\n--- c/grep.h\n+++ w/grep.h\n@@ -181,7 +181,7 @@ struct grep_opt {\n \t.relative = 1, \\\n \t.pathname = 1, \\\n \t.max_depth = -1, \\\n-\t.extended_regexp_option = -1, \\\n+\t.extended_regexp_option = 0, \\\n \t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n \t.colors = { \\\n \t\t[GREP_COLOR_CONTEXT] = \"\", \\\ndiff --git c/t/t7810-grep.sh w/t/t7810-grep.sh\nindex 34d8f69c1d..b818e656ad 100755\n--- c/t/t7810-grep.sh\n+++ w/t/t7810-grep.sh\n@@ -491,6 +491,16 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (ERE)\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n \t\techo \"${HC}ab:a+bc\" >expected &&\n \t\tgit \\\n"},{"id":"447136","messageId":"xmqqk0ekzwn8.fsf@gitster.g","threadId":"56853","inReplyTo":"xmqqpmoczwtu.fsf@gitster.g","subject":"Re: [PATCH v9 9/9] grep: simplify config parsing and option parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-01-27T21:39:07Z","receivedAt":"2022-01-27T21:39:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> In addition to squashing the following in, we must update the\n> proposed log message.  Given that, even after taking _this long_ (I\n> think I have been saying this since the review of v5 iteration),\n\nI found a reference:\n\n    https://lore.kernel.org/git/xmqqv8zf6j86.fsf@gitster.g/\n\nit indeed was [v5 7/7].\n\nIt is interesting that the breaking example I gave in the message is\nexactly the one that I wrote (without going back to the archive) in\nthe \"squashable fix\" patch in the message I am responding to.\n"},{"id":"447769","messageId":"cover-v10-0.9-00000000000-20220204T211534Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v9-0.9-00000000000-20220127T115058Z-avarab@gmail.com","subject":"[PATCH v10 0/9] grep: simplify & delete \"init\" & \"config\" code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-04T21:20:42Z","receivedAt":"2022-02-04T21:21:02Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This series makes using the grep.[ch] API easier, by having it follow\nthe usual pattern of being initialized with:\n\n    defaults -> config -> command-line\n\nThis is to make some follow-up work easier, this is a net code\ndeletion if we exclude newly added tests.\n\nChanges since v9:\n\n * Integrated the proposed fixup from Junio's branch, and updated both\n   the tests and commit messages accordingly. I changed \"BRE\" and\n   \"ERE\" in the test descriptions to indicate what we're expecting to\n   match as, and added the relevant test's from Junio's comments on an\n   earlier round.\n\nJunio: Sorry about the back & forth on this series. Each time I came\nback to it it had been a while, and between a large mail queue and\nfixing some isolated issues manged to lose the larger problem you were\npointing out. Thanks again!\n\nÆvar Arnfjörð Bjarmason (9):\n  grep.h: remove unused \"regex_t regexp\" from grep_opt\n  log tests: check if grep_config() is called by \"log\"-like cmds\n  grep tests: add missing \"grep.patternType\" config tests\n  built-ins: trust the \"prefix\" from run_builtin()\n  grep.c: don't pass along NULL callback value\n  grep API: call grep_config() after grep_init()\n  grep.h: make \"grep_opt.pattern_type_option\" use its enum\n  grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"\n  grep: simplify config parsing and option parsing\n\n builtin/grep.c    |  27 +++++------\n builtin/log.c     |  13 +++++-\n builtin/ls-tree.c |   2 +-\n git.c             |   1 +\n grep.c            | 113 ++++++----------------------------------------\n grep.h            |  31 +++++++++----\n revision.c        |   4 +-\n t/t4202-log.sh    |  24 ++++++++++\n t/t7810-grep.sh   |  96 +++++++++++++++++++++++++++++++++++++++\n 9 files changed, 185 insertions(+), 126 deletions(-)\n\nRange-diff against v9:\n 1:  b9372cde017 =  1:  184f7e0c5bd grep.h: remove unused \"regex_t regexp\" from grep_opt\n 2:  30219a0ae9d =  2:  ac397cc6a18 log tests: check if grep_config() is called by \"log\"-like cmds\n 3:  a75b288340b !  3:  3464c76cfd7 grep tests: add missing \"grep.patternType\" config tests\n    @@ Commit message\n         followed by a \"grep.extendedRegexp=false\" behaves as though\n         \"grep.extendedRegexp\" wasn't provided.\n     \n    +    See [1] for the source of some of these tests, and their\n    +    initial (pseudocode) implementation, and [2] for a later discussion\n    +    about a breakage due to missing testing (which had been noted in [1]\n    +    all along).\n    +\n    +    1. https://lore.kernel.org/git/xmqqv8zf6j86.fsf@gitster.g/\n    +    2. https://lore.kernel.org/git/xmqqpmoczwtu.fsf@gitster.g/\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n         Signed-off-by: Junio C Hamano <gitster@pobox.com>\n     \n    @@ t/t7810-grep.sh: do\n     +\t\ttest_cmp expected actual\n     +\t'\n     +\n    -+\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n    ++\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (ERE)\" '\n     +\t\techo \"${HC}ab:abc\" >expected &&\n     +\t\tgit \\\n     +\t\t\t-c grep.patternType=fixed \\\n    @@ t/t7810-grep.sh: do\n     +\t'\n     +\n     +\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (ERE)\" '\n    ++\t\techo \"${HC}ab:abc\" >expected &&\n    ++\t\tgit \\\n    ++\t\t\t-c grep.extendedRegexp=false \\\n    ++\t\t\t-c grep.patternType=default \\\n    ++\t\t\t-c grep.extendedRegexp=true \\\n    ++\t\t\tgrep \"a+b*c\" $H ab >actual &&\n    ++\t\ttest_cmp expected actual\n    ++\t'\n    ++\n    ++\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n    ++\t\techo \"${HC}ab:a+bc\" >expected &&\n    ++\t\tgit \\\n    ++\t\t\t-c grep.extendedRegexp=true \\\n    ++\t\t\t-c grep.extendedRegexp=false \\\n    ++\t\t\tgrep \"a+b*c\" $H ab >actual &&\n    ++\t\ttest_cmp expected actual\n    ++\t'\n    ++\n    ++\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n    ++\t\techo \"${HC}ab:abc\" >expected &&\n    ++\t\tgit \\\n    ++\t\t\t-c grep.extendedRegexp=false \\\n    ++\t\t\t-c grep.extendedRegexp=true \\\n    ++\t\t\t-c grep.patternType=default \\\n    ++\t\t\tgrep \"a+b*c\" $H ab >actual &&\n    ++\t\ttest_cmp expected actual\n    ++\t'\n    ++\n    ++\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n     +\t\techo \"${HC}ab:a+bc\" >expected &&\n     +\t\tgit \\\n     +\t\t\t-c grep.patternType=default \\\n    @@ t/t7810-grep.sh: do\n     +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n     +\t\ttest_cmp expected actual\n     +\t'\n    -+\n     +\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n     +\t\techo \"${HC}ab:a+bc\" >expected &&\n     +\t\tgit \\\n 4:  6e7f9730a7d =  4:  c6ada96298a built-ins: trust the \"prefix\" from run_builtin()\n 5:  fbcfea84696 =  5:  1f09de53e07 grep.c: don't pass along NULL callback value\n 6:  96c8cc7806e =  6:  ce646154538 grep API: call grep_config() after grep_init()\n 7:  e09616056b4 =  7:  6446b4f0f33 grep.h: make \"grep_opt.pattern_type_option\" use its enum\n 8:  61fc6a4dac8 =  8:  df8ba5aba68 grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"\n 9:  445467e87f7 !  9:  ccbdfa48315 grep: simplify config parsing and option parsing\n    @@ Commit message\n         last-one-wins variable, with \"grep.extendedRegexp\" yielding to\n         \"grep.patternType\", except when \"grep.patternType=default\".\n     \n    -    Note that this applies as we parse the config, i.e. a sequence of:\n    +    Note that as the previously added tests indicate this cannot be done\n    +    on-the-fly as we see the config variables, without introducing more\n    +    state keeping. I.e. if we see:\n     \n    -        -c grep.patternType=perl\n    -        -c grep.extendedRegexp=true \\\n    +        -c grep.extendedRegexp=false\n             -c grep.patternType=default\n    +        -c extendedRegexp=true\n    +\n    +    We need to select ERE, since grep.patternType=default unselects that\n    +    variable, which normally has higher precedence, but we also need to\n    +    select BRE in cases of:\n     \n    -    should select ERE due to \"grep.extendedRegexp=true and\n    -    grep.patternType=default\". We can determine this as we parse the\n    -    config, because:\n    +        -c grep.extendedRegexp=true \\\n    +        -c grep.extendedRegexp=false\n     \n    -     * If we see \"grep.extendedRegexp\" we set \"extended_regexp_option\" to\n    -       its boolean value.\n    +    Which would not be the case for this, which select ERE:\n     \n    -     * If we see \"grep.extendedRegexp\" but\n    -       \"grep.patternType=[default|<unset>]\" is in effect we *don't* set\n    -       the internal \"pattern_type_option\" to update the pattern type.\n    +        -c grep.patternType=extended \\\n    +        -c grep.extendedRegexp=false\n     \n    -     * If we see \"grep.patternType!=default\" we can set our internal\n    -       \"pattern_type_option\" directly, it doesn't matter what the state of\n    -       \"extended_regexp_option\" is, but we don't forget what it was, in\n    -       case we see a \"grep.patternType=default\" again.\n    +    Therefore we cannot do this on-the-fly in grep_config without also\n    +    introducing tracking variables for not only the pattern type, but what\n    +    the source of that pattern type was.\n     \n    -     * If we see a \"grep.patternType=default\" we can set the pattern to\n    -       ERE or BRE depending on whether we last saw a\n    -       \"grep.extendedRegexp=true\" or\n    -       \"grep.extendedRegexp=[false|<unset>]\".\n    +    So we need to decide on the pattern after our config was fully\n    +    parsed. Let's do that by deferring the decision on the pattern type\n    +    until it's time to compile it in compile_regexp().\n     \n    -    With this change the \"extended_regexp_option\" member is only used\n    -    within grep_config(), and in the current codebase we could equally\n    -    track it as a \"static\" variable within that function, see [1] for a\n    -    version for this patch that did that. We're keeping it a struct member\n    -    to make that function reentrant, in case it ends up mattering in the\n    -    future.\n    +    By that time we've not only parsed the config, but also handled the\n    +    command-line options. Those will set \"opt.pattern_type_option\" (*not*\n    +    \"opt.extended_regexp_option\"!).\n     \n    -    The command-line parsing in cmd_grep() can then completely ignore\n    -    \"grep.extendedRegexp\". Whatever effect it had before that step won't\n    -    matter if we see -G, -E, -P etc.\n    +    At that point all we need to do is see if \"grep.patternType\" was\n    +    UNSPECIFIED in the end (including an explicit \"=default\"), if so we'll\n    +    use the \"grep.extendedRegexp\" configuration, if any.\n     \n         See my 07a3d411739 (grep: remove regflags from the public grep_opt\n         API, 2017-06-29) for addition of the two comments being removed here,\n    @@ builtin/grep.c: int cmd_grep(int argc, const char **argv, const char *prefix)\n      \t\tint fallback = 0;\n     \n      ## grep.c ##\n    -@@ grep.c: static int parse_pattern_type_arg(const char *opt, const char *arg)\n    - \n    - define_list_config_array_extra(color_grep_slots, {\"match\"});\n    - \n    -+static void adjust_pattern_type(enum grep_pattern_type *pto, const int ero)\n    -+{\n    -+\tif (*pto == GREP_PATTERN_TYPE_UNSPECIFIED)\n    -+\t\t*pto = ero ? GREP_PATTERN_TYPE_ERE : GREP_PATTERN_TYPE_BRE;\n    -+}\n    -+\n    - /*\n    -  * Read the configuration file once and store it in\n    -  * the grep_defaults template.\n    -@@ grep.c: int grep_config(const char *var, const char *value, void *cb)\n    - \n    - \tif (!strcmp(var, \"grep.extendedregexp\")) {\n    - \t\topt->extended_regexp_option = git_config_bool(var, value);\n    -+\t\tadjust_pattern_type(&opt->pattern_type_option,\n    -+\t\t\t\t    opt->extended_regexp_option);\n    - \t\treturn 0;\n    - \t}\n    - \n    - \tif (!strcmp(var, \"grep.patterntype\")) {\n    - \t\topt->pattern_type_option = parse_pattern_type_arg(var, value);\n    -+\t\tif (opt->extended_regexp_option == -1)\n    -+\t\t\treturn 0;\n    -+\t\tadjust_pattern_type(&opt->pattern_type_option,\n    -+\t\t\t\t    opt->extended_regexp_option);\n    - \t\treturn 0;\n    - \t}\n    - \n     @@ grep.c: void grep_init(struct grep_opt *opt, struct repository *repo)\n      \topt->header_tail = &opt->header_list;\n      }\n    @@ grep.c: void grep_init(struct grep_opt *opt, struct repository *repo)\n      \t\t\t\t\tconst char *origin, int no,\n      \t\t\t\t\tenum grep_pat_token t,\n     @@ grep.c: static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n    + \tint err;\n    + \tint regflags = REG_NEWLINE;\n      \n    ++\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_UNSPECIFIED)\n    ++\t\topt->pattern_type_option = (opt->extended_regexp_option\n    ++\t\t\t\t\t    ? GREP_PATTERN_TYPE_ERE\n    ++\t\t\t\t\t    : GREP_PATTERN_TYPE_BRE);\n    ++\n      \tp->word_regexp = opt->word_regexp;\n      \tp->ignore_case = opt->ignore_case;\n     -\tp->fixed = opt->fixed;\n    @@ grep.h: struct grep_opt {\n      \tint pathname;\n      \tint null_following_name;\n     @@ grep.h: struct grep_opt {\n    - \t.relative = 1, \\\n    - \t.pathname = 1, \\\n    - \t.max_depth = -1, \\\n    -+\t.extended_regexp_option = -1, \\\n    - \t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n    - \t.colors = { \\\n    - \t\t[GREP_COLOR_CONTEXT] = \"\", \\\n    -@@ grep.h: struct grep_opt {\n      \n      int grep_config(const char *var, const char *value, void *);\n      void grep_init(struct grep_opt *, struct repository *repo);\n-- \n2.35.1.940.ge7a5b4b05f2\n\n"},{"id":"447770","messageId":"patch-v10-1.9-184f7e0c5bd-20220204T211534Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v10-0.9-00000000000-20220204T211534Z-avarab@gmail.com","subject":"[PATCH v10 1/9] grep.h: remove unused \"regex_t regexp\" from grep_opt","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-04T21:20:43Z","receivedAt":"2022-02-04T21:21:02Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This \"regex_t\" in grep_opt has not been used since\nf9b9faf6f8a (builtin-grep: allow more than one patterns., 2006-05-02),\nwe still use a \"regex_t\" for compiling regexes, but that's in the\n\"grep_pat\" struct\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 6a1f0ab0172..400172676a1 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -136,7 +136,6 @@ struct grep_opt {\n \n \tconst char *prefix;\n \tint prefix_length;\n-\tregex_t regexp;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n-- \n2.35.1.940.ge7a5b4b05f2\n\n"},{"id":"447771","messageId":"patch-v10-3.9-3464c76cfd7-20220204T211534Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v10-0.9-00000000000-20220204T211534Z-avarab@gmail.com","subject":"[PATCH v10 3/9] grep tests: add missing \"grep.patternType\" config tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-04T21:20:45Z","receivedAt":"2022-02-04T21:21:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the grep tests to assert that setting\n\"grep.patternType=extended\" followed by \"grep.patternType=default\"\nwill behave as if \"--basic-regexp\" was provided, and not as\n\"--extended-regexp\". In a subsequent commit we'll need to treat\n\"grep.patternType=default\" as a special-case, but let's make sure we\nignore it if it's being set to \"default\" following an earlier\nnon-\"default\" \"grep.patternType\" setting.\n\nLet's also test what happens when we have a sequence of \"extended\"\nfollowed by \"default\" and \"fixed\". In that case the \"fixed\" should\nprevail, as well as tests to check that a \"grep.extendedRegexp=true\"\nfollowed by a \"grep.extendedRegexp=false\" behaves as though\n\"grep.extendedRegexp\" wasn't provided.\n\nSee [1] for the source of some of these tests, and their\ninitial (pseudocode) implementation, and [2] for a later discussion\nabout a breakage due to missing testing (which had been noted in [1]\nall along).\n\n1. https://lore.kernel.org/git/xmqqv8zf6j86.fsf@gitster.g/\n2. https://lore.kernel.org/git/xmqqpmoczwtu.fsf@gitster.g/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t7810-grep.sh | 96 +++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 96 insertions(+)\n\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 424c31c3287..79884787da2 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -451,6 +451,93 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=basic \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins & defers to grep.patternType\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (ERE)\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=fixed \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (ERE)\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\t-c grep.extendedRegexp=true \\\n+\t\t\t-c grep.patternType=basic \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n+\t\techo \"${HC}ab:a+bc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep $L with grep.patternType=[extended -> default -> fixed]\" '\n+\t\techo \"${HC}ab:a+b*c\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\t-c grep.patternType=default \\\n+\t\t\t-c grep.patternType=fixed \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.patternType=extended and grep.extendedRegexp=false\" '\n \t\techo \"${HC}ab:abc\" >expected &&\n \t\tgit \\\n@@ -478,6 +565,15 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep $L with grep.extendedRegexp=false and grep.patternType=default\" '\n+\t\techo \"${HC}ab:abc\" >expected &&\n+\t\tgit \\\n+\t\t\t-c grep.extendedRegexp=false \\\n+\t\t\t-c grep.patternType=extended \\\n+\t\t\tgrep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n \ttest_expect_success \"grep $L with grep.extendedRegexp=true and grep.patternType=basic\" '\n \t\techo \"${HC}ab:a+bc\" >expected &&\n \t\tgit \\\n-- \n2.35.1.940.ge7a5b4b05f2\n\n"},{"id":"447772","messageId":"patch-v10-2.9-ac397cc6a18-20220204T211534Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v10-0.9-00000000000-20220204T211534Z-avarab@gmail.com","subject":"[PATCH v10 2/9] log tests: check if grep_config() is called by \"log\"-like cmds","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-04T21:20:44Z","receivedAt":"2022-02-04T21:21:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the tests added in my 9df46763ef1 (log: add exhaustive tests\nfor pattern style options & config, 2017-05-20) to check not only\nwhether \"git log\" handles \"grep.patternType\", but also \"git show\"\netc.\n\nIt's sufficient to check whether we match a \"fixed\" or a \"basic\" regex\nhere to see if these codepaths correctly invoked grep_config(). We\ndon't need to check the details of their regular expression matching\nas the \"log\" test does.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4202-log.sh | 24 ++++++++++++++++++++++++\n 1 file changed, 24 insertions(+)\n\ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex 50495598619..e775b378e4b 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -449,6 +449,30 @@ test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurati\n \t)\n '\n \n+for cmd in show whatchanged reflog format-patch\n+do\n+\tcase \"$cmd\" in\n+\tformat-patch) myarg=\"HEAD~..\" ;;\n+\t*) myarg= ;;\n+\tesac\n+\n+\ttest_expect_success \"$cmd: understands grep.patternType, like 'log'\" '\n+\t\tgit init \"pattern-type-$cmd\" &&\n+\t\t(\n+\t\t\tcd \"pattern-type-$cmd\" &&\n+\t\t\ttest_commit 1 file A &&\n+\t\t\ttest_commit \"(1|2)\" file B 2 &&\n+\n+\t\t\tgit -c grep.patternType=fixed $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_must_be_empty actual &&\n+\n+\t\t\tgit -c grep.patternType=basic $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_file_not_empty actual\n+\t\t)\n+\t'\n+done\n+test_done\n+\n test_expect_success 'log --author' '\n \tcat >expect <<-\\EOF &&\n \tAuthor: <BOLD;RED>A U<RESET> Thor <author@example.com>\n-- \n2.35.1.940.ge7a5b4b05f2\n\n"},{"id":"447773","messageId":"patch-v10-5.9-1f09de53e07-20220204T211534Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v10-0.9-00000000000-20220204T211534Z-avarab@gmail.com","subject":"[PATCH v10 5/9] grep.c: don't pass along NULL callback value","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-04T21:20:47Z","receivedAt":"2022-02-04T21:21:09Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change grep_cmd_config() to stop passing around the always-NULL \"cb\"\nvalue. When this code was added in 7e8f59d577e (grep: color patterns\nin output, 2009-03-07) it was non-NULL, but when that changed in\n15fabd1bbd4 (builtin/grep.c: make configuration callback more\nreusable, 2012-10-09) this code was left behind.\n\nIn a subsequent change I'll start using the \"cb\" value, this will make\nit clear which functions we call need it, and which don't.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex d85cbabea67..5ec4cecae45 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,8 +285,8 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, cb);\n-\tif (git_color_default_config(var, value, cb) < 0)\n+\tint st = grep_config(var, value, NULL);\n+\tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n \tif (!strcmp(var, \"grep.threads\")) {\n-- \n2.35.1.940.ge7a5b4b05f2\n\n"},{"id":"447774","messageId":"patch-v10-4.9-c6ada96298a-20220204T211534Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v10-0.9-00000000000-20220204T211534Z-avarab@gmail.com","subject":"[PATCH v10 4/9] built-ins: trust the \"prefix\" from run_builtin()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-04T21:20:46Z","receivedAt":"2022-02-04T21:21:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in \"builtin/grep.c\" and \"builtin/ls-tree.c\" to trust the\n\"prefix\" passed from \"run_builtin()\". The \"prefix\" we get from setup.c\nis either going to be NULL or a string of length >0, never \"\".\n\nSo we can drop the \"prefix && *prefix\" checks added for\n\"builtin/grep.c\" in 0d042fecf2f (git-grep: show pathnames relative to\nthe current directory, 2006-08-11), and for \"builtin/ls-tree.c\" in\na69dd585fca (ls-tree: chomp leading directories when run from a\nsubdirectory, 2005-12-23).\n\nAs seen in code in revision.c that was added in cd676a51367 (diff\n--relative: output paths as relative to the current subdirectory,\n2008-02-12) we already have existing code that does away with this\nassertion.\n\nThis makes it easier to reason about a subsequent change to the\n\"prefix_length\" code in grep.c in a subsequent commit, and since we're\ngoing to the trouble of doing that let's leave behind an assert() to\npromise this to any future callers.\n\nFor \"builtin/grep.c\" it would be painful to pass the \"prefix\" down the\ncallchain of:\n\n    cmd_grep -> grep_tree -> grep_submodule -> grep_cache -> grep_oid ->\n    grep_source_name\n\nSo for the code that needs it in grep_source_name() let's add a\n\"grep_prefix\" variable similar to the existing \"ls_tree_prefix\".\n\nWhile at it let's move the code in cmd_ls_tree() around so that we\nassign to the \"ls_tree_prefix\" right after declaring the variables,\nand stop assigning to \"prefix\". We only subsequently used that\nvariable later in the function after clobbering it. Let's just use our\nown \"grep_prefix\" instead.\n\nLet's also add an assert() in git.c, so that we'll make this promise\nabout the \"prefix\" to any current and future callers, as well as to\nany readers of the code.\n\nCode history:\n\n * The strlen() in \"grep.c\" hasn't been used since 493b7a08d80 (grep:\n   accept relative paths outside current working directory, 2009-09-05).\n\n   When that code was added in 0d042fecf2f (git-grep: show pathnames\n   relative to the current directory, 2006-08-11) we used the length.\n\n   But since 493b7a08d80 we haven't used it for anything except a\n   boolean check that we could have done on the \"prefix\" member\n   itself.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c    | 13 ++++++++-----\n builtin/ls-tree.c |  2 +-\n git.c             |  1 +\n grep.c            |  4 +---\n grep.h            |  4 +---\n revision.c        |  2 +-\n 6 files changed, 13 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 9e34a820ad4..d85cbabea67 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -26,6 +26,8 @@\n #include \"object-store.h\"\n #include \"packfile.h\"\n \n+static const char *grep_prefix;\n+\n static char const * const grep_usage[] = {\n \tN_(\"git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]\"),\n \tNULL\n@@ -315,11 +317,11 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \tstrbuf_reset(out);\n \n \tif (opt->null_following_name) {\n-\t\tif (opt->relative && opt->prefix_length) {\n+\t\tif (opt->relative && grep_prefix) {\n \t\t\tstruct strbuf rel_buf = STRBUF_INIT;\n \t\t\tconst char *rel_name =\n \t\t\t\trelative_path(filename + tree_name_len,\n-\t\t\t\t\t      opt->prefix, &rel_buf);\n+\t\t\t\t\t      grep_prefix, &rel_buf);\n \n \t\t\tif (tree_name_len)\n \t\t\t\tstrbuf_add(out, filename, tree_name_len);\n@@ -332,8 +334,8 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \t\treturn;\n \t}\n \n-\tif (opt->relative && opt->prefix_length)\n-\t\tquote_path(filename + tree_name_len, opt->prefix, out, 0);\n+\tif (opt->relative && grep_prefix)\n+\t\tquote_path(filename + tree_name_len, grep_prefix, out, 0);\n \telse\n \t\tquote_c_style(filename + tree_name_len, out, NULL, 0);\n \n@@ -962,9 +964,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\t   PARSE_OPT_NOCOMPLETE),\n \t\tOPT_END()\n \t};\n+\tgrep_prefix = prefix;\n \n \tgit_config(grep_cmd_config, NULL);\n-\tgrep_init(&opt, the_repository, prefix);\n+\tgrep_init(&opt, the_repository);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 3a442631c71..6cb554cbb0a 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -150,7 +150,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \n \tgit_config(git_default_config, NULL);\n \tls_tree_prefix = prefix;\n-\tif (prefix && *prefix)\n+\tif (prefix)\n \t\tchomp_prefix = strlen(prefix);\n \n \targc = parse_options(argc, argv, prefix, ls_tree_options,\ndiff --git a/git.c b/git.c\nindex edda922ce6d..9d257e092da 100644\n--- a/git.c\n+++ b/git.c\n@@ -436,6 +436,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t} else {\n \t\tprefix = NULL;\n \t}\n+\tassert(!prefix || *prefix);\n \tprecompose_argv_prefix(argc, argv, NULL);\n \tif (use_pager == -1 && run_setup &&\n \t\t!(p->option & DELAY_PAGER_CONFIG))\ndiff --git a/grep.c b/grep.c\nindex 7bb0360869a..8421dc55486 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -139,13 +139,11 @@ int grep_config(const char *var, const char *value, void *cb)\n  * default values from the template we read the configuration\n  * information in an earlier call to git_config(grep_config).\n  */\n-void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)\n+void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n \t*opt = grep_defaults;\n \n \topt->repo = repo;\n-\topt->prefix = prefix;\n-\topt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;\n \topt->pattern_tail = &opt->pattern_list;\n \topt->header_tail = &opt->header_list;\n }\ndiff --git a/grep.h b/grep.h\nindex 400172676a1..23a2a41d2c4 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -134,8 +134,6 @@ struct grep_opt {\n \t */\n \tstruct repository *repo;\n \n-\tconst char *prefix;\n-\tint prefix_length;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n@@ -182,7 +180,7 @@ struct grep_opt {\n };\n \n int grep_config(const char *var, const char *value, void *);\n-void grep_init(struct grep_opt *, struct repository *repo, const char *prefix);\n+void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex ad4286fbdde..d6e0e2b23b5 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1838,7 +1838,7 @@ void repo_init_revisions(struct repository *r,\n \trevs->commit_format = CMIT_FMT_DEFAULT;\n \trevs->expand_tabs_in_log_default = 8;\n \n-\tgrep_init(&revs->grep_filter, revs->repo, prefix);\n+\tgrep_init(&revs->grep_filter, revs->repo);\n \trevs->grep_filter.status_only = 1;\n \n \trepo_diff_setup(revs->repo, &revs->diffopt);\n-- \n2.35.1.940.ge7a5b4b05f2\n\n"},{"id":"447775","messageId":"patch-v10-7.9-6446b4f0f33-20220204T211534Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v10-0.9-00000000000-20220204T211534Z-avarab@gmail.com","subject":"[PATCH v10 7/9] grep.h: make \"grep_opt.pattern_type_option\" use its enum","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-04T21:20:49Z","receivedAt":"2022-02-04T21:21:14Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the \"pattern_type_option\" member of \"struct grep_opt\" to use\nthe enum type we use for it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 3112d1c2a38..89a2ce51130 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -164,7 +164,7 @@ struct grep_opt {\n \tint funcname;\n \tint funcbody;\n \tint extended_regexp_option;\n-\tint pattern_type_option;\n+\tenum grep_pattern_type pattern_type_option;\n \tint ignore_locale;\n \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n \tunsigned pre_context;\n-- \n2.35.1.940.ge7a5b4b05f2\n\n"},{"id":"447776","messageId":"patch-v10-8.9-df8ba5aba68-20220204T211534Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v10-0.9-00000000000-20220204T211534Z-avarab@gmail.com","subject":"[PATCH v10 8/9] grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-04T21:20:50Z","receivedAt":"2022-02-04T21:21:15Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in compile_regexp() to check the cheaper boolean\n\"!opt->pcre2\" condition before the \"memchr()\" search.\n\nThis doesn't noticeably optimize anything, but makes the code more\nobvious and conventional. The line wrapping being added here also\nmakes a subsequent commit smaller.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/grep.c b/grep.c\nindex 35e12e43c09..60228a95a4f 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -492,7 +492,8 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \tp->ignore_case = opt->ignore_case;\n \tp->fixed = opt->fixed;\n \n-\tif (memchr(p->pattern, 0, p->patternlen) && !opt->pcre2)\n+\tif (!opt->pcre2 &&\n+\t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n \tp->is_fixed = is_fixed(p->pattern, p->patternlen);\n-- \n2.35.1.940.ge7a5b4b05f2\n\n"},{"id":"447777","messageId":"patch-v10-6.9-ce646154538-20220204T211534Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v10-0.9-00000000000-20220204T211534Z-avarab@gmail.com","subject":"[PATCH v10 6/9] grep API: call grep_config() after grep_init()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-04T21:20:48Z","receivedAt":"2022-02-04T21:21:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The grep_init() function used the odd pattern of initializing the\npassed-in \"struct grep_opt\" with a statically defined \"grep_defaults\"\nstruct, which would be modified in-place when we invoked\ngrep_config().\n\nSo we effectively (b) initialized config, (a) then defaults, (c)\nfollowed by user options. Usually those are ordered as \"a\", \"b\" and\n\"c\" instead.\n\nAs the comments being removed here show the previous behavior needed\nto be carefully explained as we'd potentially share the populated\nconfiguration among different instances of grep_init(). In practice we\ndidn't do that, but now that it can't be a concern anymore let's\nremove those comments.\n\nThis does not change the behavior of any of the configuration\nvariables or options. That would have been the case if we didn't move\naround the grep_config() call in \"builtin/log.c\". But now that we call\n\"grep_config\" after \"git_log_config\" and \"git_format_config\" we'll\nneed to pass in the already initialized \"struct grep_opt *\".\n\nSee 6ba9bb76e02 (grep: copy struct in one fell swoop, 2020-11-29) and\n7687a0541e0 (grep: move the configuration parsing logic to grep.[ch],\n2012-10-09) for the commits that added the comments.\n\nThe memcpy() pattern here will be optimized away and follows the\nconvention of other *_init() functions. See 5726a6b4012 (*.c *_init():\ndefine in terms of corresponding *_INIT macro, 2021-07-01).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c |  4 ++--\n builtin/log.c  | 13 +++++++++++--\n grep.c         | 39 +++------------------------------------\n grep.h         | 21 +++++++++++++++++++++\n 4 files changed, 37 insertions(+), 40 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5ec4cecae45..0ea124321b6 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,7 +285,7 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, NULL);\n+\tint st = grep_config(var, value, cb);\n \tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n@@ -966,8 +966,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t};\n \tgrep_prefix = prefix;\n \n-\tgit_config(grep_cmd_config, NULL);\n \tgrep_init(&opt, the_repository);\n+\tgit_config(grep_cmd_config, &opt);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 4b493408cc5..06283b37e7a 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -520,8 +520,6 @@ static int git_log_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n-\tif (grep_config(var, value, cb) < 0)\n-\t\treturn -1;\n \tif (git_gpg_config(var, value, cb) < 0)\n \t\treturn -1;\n \treturn git_diff_ui_config(var, value, cb);\n@@ -536,6 +534,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.simplify_history = 0;\n \tmemset(&opt, 0, sizeof(opt));\n@@ -650,6 +650,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \n \tmemset(&match_all, 0, sizeof(match_all));\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.always_show_header = 1;\n \trev.no_walk = 1;\n@@ -733,6 +735,8 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n \tinit_reflog_walk(&rev.reflog_info);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.verbose_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -766,6 +770,8 @@ int cmd_log(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.always_show_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -1848,10 +1854,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \textra_hdr.strdup_strings = 1;\n \textra_to.strdup_strings = 1;\n \textra_cc.strdup_strings = 1;\n+\n \tinit_log_defaults();\n \tinit_display_notes(&notes_opt);\n \tgit_config(git_format_config, NULL);\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.show_notes = show_notes;\n \tmemcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));\n \trev.commit_format = CMIT_FMT_EMAIL;\ndiff --git a/grep.c b/grep.c\nindex 8421dc55486..35e12e43c09 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -19,27 +19,6 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)\n \tfwrite(buf, size, 1, stdout);\n }\n \n-static struct grep_opt grep_defaults = {\n-\t.relative = 1,\n-\t.pathname = 1,\n-\t.max_depth = -1,\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t.colors = {\n-\t\t[GREP_COLOR_CONTEXT] = \"\",\n-\t\t[GREP_COLOR_FILENAME] = GIT_COLOR_MAGENTA,\n-\t\t[GREP_COLOR_FUNCTION] = \"\",\n-\t\t[GREP_COLOR_LINENO] = GIT_COLOR_GREEN,\n-\t\t[GREP_COLOR_COLUMNNO] = GIT_COLOR_GREEN,\n-\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_SELECTED] = \"\",\n-\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN,\n-\t},\n-\t.only_matching = 0,\n-\t.color = -1,\n-\t.output = std_output,\n-};\n-\n static const char *color_grep_slots[] = {\n \t[GREP_COLOR_CONTEXT]\t    = \"context\",\n \t[GREP_COLOR_FILENAME]\t    = \"filename\",\n@@ -75,20 +54,12 @@ define_list_config_array_extra(color_grep_slots, {\"match\"});\n  */\n int grep_config(const char *var, const char *value, void *cb)\n {\n-\tstruct grep_opt *opt = &grep_defaults;\n+\tstruct grep_opt *opt = cb;\n \tconst char *slot;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\t/*\n-\t * The instance of grep_opt that we set up here is copied by\n-\t * grep_init() to be used by each individual invocation.\n-\t * When populating a new field of this structure here, be\n-\t * sure to think about ownership -- e.g., you might need to\n-\t * override the shallow copy in grep_init() with a deep copy.\n-\t */\n-\n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n \t\treturn 0;\n@@ -134,14 +105,10 @@ int grep_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/*\n- * Initialize one instance of grep_opt and copy the\n- * default values from the template we read the configuration\n- * information in an earlier call to git_config(grep_config).\n- */\n void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n-\t*opt = grep_defaults;\n+\tstruct grep_opt blank = GREP_OPT_INIT;\n+\tmemcpy(opt, &blank, sizeof(*opt));\n \n \topt->repo = repo;\n \topt->pattern_tail = &opt->pattern_list;\ndiff --git a/grep.h b/grep.h\nindex 23a2a41d2c4..3112d1c2a38 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -179,6 +179,27 @@ struct grep_opt {\n \tvoid *output_priv;\n };\n \n+#define GREP_OPT_INIT { \\\n+\t.relative = 1, \\\n+\t.pathname = 1, \\\n+\t.max_depth = -1, \\\n+\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n+\t.colors = { \\\n+\t\t[GREP_COLOR_CONTEXT] = \"\", \\\n+\t\t[GREP_COLOR_FILENAME] = GIT_COLOR_MAGENTA, \\\n+\t\t[GREP_COLOR_FUNCTION] = \"\", \\\n+\t\t[GREP_COLOR_LINENO] = GIT_COLOR_GREEN, \\\n+\t\t[GREP_COLOR_COLUMNNO] = GIT_COLOR_GREEN, \\\n+\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_SELECTED] = \"\", \\\n+\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n+\t}, \\\n+\t.only_matching = 0, \\\n+\t.color = -1, \\\n+\t.output = std_output, \\\n+}\n+\n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n-- \n2.35.1.940.ge7a5b4b05f2\n\n"},{"id":"447778","messageId":"patch-v10-9.9-ccbdfa48315-20220204T211534Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v10-0.9-00000000000-20220204T211534Z-avarab@gmail.com","subject":"[PATCH v10 9/9] grep: simplify config parsing and option parsing","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-04T21:20:51Z","receivedAt":"2022-02-04T21:21:19Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Simplify the parsing of \"grep.patternType\" and\n\"grep.extendedRegexp\". This changes no behavior, but gets rid of\ncomplex parsing logic that isn't needed anymore.\n\nWhen \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\ngrep.patternType configuration setting, 2012-08-03) we promised that:\n\n 1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n    will return to the default matching behavior\".\n\n    In that context \"the default\" meant whatever the configuration\n    system specified before that change, i.e. via grep.extendedRegexp.\n\n 2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n    it when the new \"grep.patternType\" option is set. We said we'd\n    only ignore the older \"grep.extendedRegexp\" option \"when the\n    `grep.patternType` option is set to a value other than\n    'default'\".\n\nIn a preceding commit we changed grep_config() to be called after\ngrep_init(), which means that much of the complexity here can go\naway.\n\nAs before both \"grep.patternType\" and \"grep.extendedRegexp\" are\nlast-one-wins variable, with \"grep.extendedRegexp\" yielding to\n\"grep.patternType\", except when \"grep.patternType=default\".\n\nNote that as the previously added tests indicate this cannot be done\non-the-fly as we see the config variables, without introducing more\nstate keeping. I.e. if we see:\n\n    -c grep.extendedRegexp=false\n    -c grep.patternType=default\n    -c extendedRegexp=true\n\nWe need to select ERE, since grep.patternType=default unselects that\nvariable, which normally has higher precedence, but we also need to\nselect BRE in cases of:\n\n    -c grep.extendedRegexp=true \\\n    -c grep.extendedRegexp=false\n\nWhich would not be the case for this, which select ERE:\n\n    -c grep.patternType=extended \\\n    -c grep.extendedRegexp=false\n\nTherefore we cannot do this on-the-fly in grep_config without also\nintroducing tracking variables for not only the pattern type, but what\nthe source of that pattern type was.\n\nSo we need to decide on the pattern after our config was fully\nparsed. Let's do that by deferring the decision on the pattern type\nuntil it's time to compile it in compile_regexp().\n\nBy that time we've not only parsed the config, but also handled the\ncommand-line options. Those will set \"opt.pattern_type_option\" (*not*\n\"opt.extended_regexp_option\"!).\n\nAt that point all we need to do is see if \"grep.patternType\" was\nUNSPECIFIED in the end (including an explicit \"=default\"), if so we'll\nuse the \"grep.extendedRegexp\" configuration, if any.\n\nSee my 07a3d411739 (grep: remove regflags from the public grep_opt\nAPI, 2017-06-29) for addition of the two comments being removed here,\ni.e. the complexity noted in that commit is now going away.\n\n1. https://lore.kernel.org/git/patch-v8-09.10-c211bb0c69d-20220118T155211Z-avarab@gmail.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 10 +++-----\n grep.c         | 69 +++++++-------------------------------------------\n grep.h         |  3 ---\n revision.c     |  2 --\n 4 files changed, 13 insertions(+), 71 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 0ea124321b6..942c4b25077 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -845,7 +845,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tint i;\n \tint dummy;\n \tint use_index = 1;\n-\tint pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;\n \tint allow_revs;\n \n \tstruct option options[] = {\n@@ -879,16 +878,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"descend at most <depth> levels\"), PARSE_OPT_NONEG,\n \t\t\tNULL, 1 },\n \t\tOPT_GROUP(\"\"),\n-\t\tOPT_SET_INT('E', \"extended-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('E', \"extended-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use extended POSIX regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_ERE),\n-\t\tOPT_SET_INT('G', \"basic-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('G', \"basic-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use basic POSIX regular expressions (default)\"),\n \t\t\t    GREP_PATTERN_TYPE_BRE),\n-\t\tOPT_SET_INT('F', \"fixed-strings\", &pattern_type_arg,\n+\t\tOPT_SET_INT('F', \"fixed-strings\", &opt.pattern_type_option,\n \t\t\t    N_(\"interpret patterns as fixed strings\"),\n \t\t\t    GREP_PATTERN_TYPE_FIXED),\n-\t\tOPT_SET_INT('P', \"perl-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('P', \"perl-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use Perl-compatible regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_PCRE),\n \t\tOPT_GROUP(\"\"),\n@@ -982,7 +981,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, grep_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH |\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n-\tgrep_commit_pattern_type(pattern_type_arg, &opt);\n \n \tif (use_index && !startup_info->have_repository) {\n \t\tint fallback = 0;\ndiff --git a/grep.c b/grep.c\nindex 60228a95a4f..a8f503f55c7 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -115,62 +115,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo)\n \topt->header_tail = &opt->header_list;\n }\n \n-static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\t/*\n-\t * When committing to the pattern type by setting the relevant\n-\t * fields in grep_opt it's generally not necessary to zero out\n-\t * the fields we're not choosing, since they won't have been\n-\t * set by anything. The extended_regexp_option field is the\n-\t * only exception to this.\n-\t *\n-\t * This is because in the process of parsing grep.patternType\n-\t * & grep.extendedRegexp we set opt->pattern_type_option and\n-\t * opt->extended_regexp_option, respectively. We then\n-\t * internally use opt->extended_regexp_option to see if we're\n-\t * compiling an ERE. It must be unset if that's not actually\n-\t * the case.\n-\t */\n-\tif (pattern_type != GREP_PATTERN_TYPE_ERE &&\n-\t    opt->extended_regexp_option)\n-\t\topt->extended_regexp_option = 0;\n-\n-\tswitch (pattern_type) {\n-\tcase GREP_PATTERN_TYPE_UNSPECIFIED:\n-\t\t/* fall through */\n-\n-\tcase GREP_PATTERN_TYPE_BRE:\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_ERE:\n-\t\topt->extended_regexp_option = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_FIXED:\n-\t\topt->fixed = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_PCRE:\n-\t\topt->pcre2 = 1;\n-\t\tbreak;\n-\t}\n-}\n-\n-void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\tif (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(pattern_type, opt);\n-\telse if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(opt->pattern_type_option, opt);\n-\telse if (opt->extended_regexp_option)\n-\t\t/*\n-\t\t * This branch *must* happen after setting from the\n-\t\t * opt->pattern_type_option above, we don't want\n-\t\t * grep.extendedRegexp to override grep.patternType!\n-\t\t */\n-\t\tgrep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);\n-}\n-\n static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,\n \t\t\t\t\tconst char *origin, int no,\n \t\t\t\t\tenum grep_pat_token t,\n@@ -488,11 +432,16 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \tint err;\n \tint regflags = REG_NEWLINE;\n \n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_UNSPECIFIED)\n+\t\topt->pattern_type_option = (opt->extended_regexp_option\n+\t\t\t\t\t    ? GREP_PATTERN_TYPE_ERE\n+\t\t\t\t\t    : GREP_PATTERN_TYPE_BRE);\n+\n \tp->word_regexp = opt->word_regexp;\n \tp->ignore_case = opt->ignore_case;\n-\tp->fixed = opt->fixed;\n+\tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\n \n-\tif (!opt->pcre2 &&\n+\tif (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE &&\n \t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n@@ -544,14 +493,14 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \t\treturn;\n \t}\n \n-\tif (opt->pcre2) {\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_PCRE) {\n \t\tcompile_pcre2_pattern(p, opt);\n \t\treturn;\n \t}\n \n \tif (p->ignore_case)\n \t\tregflags |= REG_ICASE;\n-\tif (opt->extended_regexp_option)\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_ERE)\n \t\tregflags |= REG_EXTENDED;\n \terr = regcomp(&p->regexp, p->pattern, regflags);\n \tif (err) {\ndiff --git a/grep.h b/grep.h\nindex 89a2ce51130..c722d25ed9d 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -143,7 +143,6 @@ struct grep_opt {\n \tint unmatch_name_only;\n \tint count;\n \tint word_regexp;\n-\tint fixed;\n \tint all_match;\n \tint no_body_match;\n \tint body_hit;\n@@ -154,7 +153,6 @@ struct grep_opt {\n \tint allow_textconv;\n \tint extended;\n \tint use_reflog_filter;\n-\tint pcre2;\n \tint relative;\n \tint pathname;\n \tint null_following_name;\n@@ -202,7 +200,6 @@ struct grep_opt {\n \n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n-void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\n void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex d6e0e2b23b5..dd301e30147 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2860,8 +2860,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \n \tdiff_setup_done(&revs->diffopt);\n \n-\tgrep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t\t\t\t &revs->grep_filter);\n \tif (!is_encoding_utf8(get_log_output_encoding()))\n \t\trevs->grep_filter.ignore_locale = 1;\n \tcompile_grep_patterns(&revs->grep_filter);\n-- \n2.35.1.940.ge7a5b4b05f2\n\n"},{"id":"447782","messageId":"xmqqmtj6jkuk.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v10-3.9-3464c76cfd7-20220204T211534Z-avarab@gmail.com","subject":"Re: [PATCH v10 3/9] grep tests: add missing \"grep.patternType\" config tests","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-02-04T23:03:15Z","receivedAt":"2022-02-04T23:03:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> +\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n> +\t\techo \"${HC}ab:a+bc\" >expected &&\n> +\t\tgit \\\n> +\t\t\t-c grep.patternType=default \\\n> +\t\t\t-c grep.extendedRegexp=true \\\n> +\t\t\t-c grep.patternType=basic \\\n> +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n> +\t\ttest_cmp expected actual\n> +\t'\n> +\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n\nMising blank line between tests.\n\nOther than that, this step looks good.\n\nNo need to resend; I'll fix this part up locally again.\n\nThanks.\n"},{"id":"447785","messageId":"xmqqv8xui5ah.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v10-3.9-3464c76cfd7-20220204T211534Z-avarab@gmail.com","subject":"Re: [PATCH v10 3/9] grep tests: add missing \"grep.patternType\" config tests","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-02-04T23:24:38Z","receivedAt":"2022-02-04T23:24:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> +\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins\" '\n\nThe statement is true, but ...\n\n> +\t\techo \"${HC}ab:a+bc\" >expected &&\n> +\t\tgit \\\n> +\t\t\t-c grep.extendedRegexp=true \\\n> +\t\t\t-c grep.patternType=basic \\\n> +\t\t\t-c grep.extendedRegexp=false \\\n\n... I do not think that is what is tested here.  It checks that\nthe value of grep.extendedRegexp is irrelevant when grep.patternType\nis anything but default, no?  In other words, if you lose the last\none that overrides the earlier .extendedRegexp=true, this should\nstill pass, no?\n\n> +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n> +\t\ttest_cmp expected actual\n> +\t'\n> +\n> +\ttest_expect_success \"grep $L with grep.extendedRegexp is last-one-wins & defers to grep.patternType\" '\n> +\t\techo \"${HC}ab:abc\" >expected &&\n> +\t\tgit \\\n> +\t\t\t-c grep.extendedRegexp=true \\\n> +\t\t\t-c grep.patternType=extended \\\n> +\t\t\t-c grep.extendedRegexp=false \\\n\nLikewise.  grep.extendedRegexp being last-one-wins has no relevance\nto this result, just like the previous one.  I would understand:\n\n\tgrep $L with grep.patternType=extended pays no atention to grep.extendedRegexp\n\nthough.\n\n> +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n> +\t\ttest_cmp expected actual\n> +\t'\n> +\n> +\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (ERE)\" '\n> +\t\techo \"${HC}ab:abc\" >expected &&\n> +\t\tgit \\\n> +\t\t\t-c grep.patternType=fixed \\\n> +\t\t\t-c grep.extendedRegexp=true \\\n> +\t\t\t-c grep.patternType=default \\\n> +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n\n.patternType=default lets .extendedRegexp to decide, and we get ERE.\n\nThis does have a correct name and tests the right thing (but\ngrep.extendedRegexp is set only once in this, so \"last-one-wins\" is\ntechnically correct but may not be very useful thing to stress upon\n;-).\n\n> +\t\ttest_cmp expected actual\n> +\t'\n> +\n> +\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (ERE)\" '\n> +\t\techo \"${HC}ab:abc\" >expected &&\n> +\t\tgit \\\n> +\t\t\t-c grep.extendedRegexp=false \\\n> +\t\t\t-c grep.patternType=default \\\n> +\t\t\t-c grep.extendedRegexp=true \\\n\n.patternType=default lets .extendedRegexp to decide, and we get ERE.\n\nFuture readers might wonder why we are are testing the same thing\nagain, without enough imagination to guess what faulty implementation\nis possible to require this test ;-).\n\n> +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n> +\t\ttest_cmp expected actual\n> +\t'\n> +\n> +\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n> +\t\techo \"${HC}ab:a+bc\" >expected &&\n> +\t\tgit \\\n> +\t\t\t-c grep.extendedRegexp=true \\\n> +\t\t\t-c grep.extendedRegexp=false \\\n> +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n\n.patternType=default that is implicit is the \"last\" value and lets\n.extendedRegexp to decide, and we get BRE.\n\n> +\t\ttest_cmp expected actual\n> +\t'\n> +\n> +\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n> +\t\techo \"${HC}ab:abc\" >expected &&\n> +\t\tgit \\\n> +\t\t\t-c grep.extendedRegexp=false \\\n> +\t\t\t-c grep.extendedRegexp=true \\\n> +\t\t\t-c grep.patternType=default \\\n\nSimilar.  As the default for .patternType is the default anyway,\neven with an implementation that commits the choice too early would\nget this right, as it assumes that .patternType is the default when\nit sees true given to .extendedRegexp variable.\n\n> +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n> +\t\ttest_cmp expected actual\n> +\t'\n> +\n> +\ttest_expect_success \"grep $L with grep.extendedRegexp and grep.patternType are both last-one-wins independently (BRE)\" '\n> +\t\techo \"${HC}ab:a+bc\" >expected &&\n> +\t\tgit \\\n> +\t\t\t-c grep.patternType=default \\\n> +\t\t\t-c grep.extendedRegexp=true \\\n> +\t\t\t-c grep.patternType=basic \\\n\nThe last value for .patternType not being \"default\" makes it the\nonly thing that matters.  This one also tests the right thing.\n\n> +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n> +\t\ttest_cmp expected actual\n> +\t'\n> +\ttest_expect_success \"grep $L with grep.patternType=extended and grep.patternType=default\" '\n> +\t\techo \"${HC}ab:a+bc\" >expected &&\n> +\t\tgit \\\n> +\t\t\t-c grep.patternType=extended \\\n> +\t\t\t-c grep.patternType=default \\\n\nThe last value for .patternType being \"default\" lets .extendedRegexp\nto decide, but .extendedRegexp is left to its default, which is\nfalse, so we should get BRE.\n\n> +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n> +\t\ttest_cmp expected actual\n> +\t'\n> +\n> +\ttest_expect_success \"grep $L with grep.patternType=[extended -> default -> fixed]\" '\n> +\t\techo \"${HC}ab:a+b*c\" >expected &&\n> +\t\tgit \\\n> +\t\t\t-c grep.patternType=extended \\\n> +\t\t\t-c grep.patternType=default \\\n> +\t\t\t-c grep.patternType=fixed \\\n> +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n\nOK.\n\n> +\t\ttest_cmp expected actual\n> +\t'\n> +\n>  \ttest_expect_success \"grep $L with grep.patternType=extended and grep.extendedRegexp=false\" '\n>  \t\techo \"${HC}ab:abc\" >expected &&\n>  \t\tgit \\\n> @@ -478,6 +565,15 @@ do\n>  \t\ttest_cmp expected actual\n>  \t'\n>  \n> +\ttest_expect_success \"grep $L with grep.extendedRegexp=false and grep.patternType=default\" '\n> +\t\techo \"${HC}ab:abc\" >expected &&\n> +\t\tgit \\\n> +\t\t\t-c grep.extendedRegexp=false \\\n> +\t\t\t-c grep.patternType=extended \\\n\nAgain, .patternType not being \"default\" makes .extendedRegexp not to\nmatter at all, and we get ERE.\n\n> +\t\t\tgrep \"a+b*c\" $H ab >actual &&\n> +\t\ttest_cmp expected actual\n> +\t'\n> +\n>  \ttest_expect_success \"grep $L with grep.extendedRegexp=true and grep.patternType=basic\" '\n>  \t\techo \"${HC}ab:a+bc\" >expected &&\n>  \t\tgit \\\n\nAll tests look correct.  The first two had labels that missed the\npoint of what is being tested, which need fixing.  Other tests were\ncorrect, I know that all of them may have helped to catch mistakes\nmade in past iterations of this series, but without knowing the past\nmistakes, new readers may not get exactly the point of these tests.\n\nThanks.\n"},{"id":"447786","messageId":"xmqqk0eai4i8.fsf@gitster.g","threadId":"56853","inReplyTo":"patch-v10-9.9-ccbdfa48315-20220204T211534Z-avarab@gmail.com","subject":"Re: [PATCH v10 9/9] grep: simplify config parsing and option parsing","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-02-04T23:41:35Z","receivedAt":"2022-02-04T23:41:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Note that as the previously added tests indicate this cannot be done\n> on-the-fly as we see the config variables, without introducing more\n> state keeping. I.e. if we see:\n>\n>     -c grep.extendedRegexp=false\n>     -c grep.patternType=default\n>     -c extendedRegexp=true\n>\n> We need to select ERE, since grep.patternType=default unselects that\n> variable, which normally has higher precedence, but we also need to\n> select BRE in cases of:\n>\n>     -c grep.extendedRegexp=true \\\n>     -c grep.extendedRegexp=false\n>\n> Which would not be the case for this, which select ERE:\n>\n>     -c grep.patternType=extended \\\n>     -c grep.extendedRegexp=false\n\nI think the latter two examples can lose the backslash at the end\n(and all of them can lose \"-c\").  We can rewrite the preamble of the\nfirst one to clarify what we are trying to say with this notation,\nperhaps like\n\n\tI.e. if we see these configuration variable definitions in\n\tthis order:\n\n> -static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n> -{\n> -\t/*\n> -\t * When committing to the pattern type by setting the relevant\n> -\t * fields in grep_opt it's generally not necessary to zero out\n> -\t * the fields we're not choosing, since they won't have been\n> -\t * set by anything. The extended_regexp_option field is the\n> -\t * only exception to this.\n> -\t *\n> -\t * This is because in the process of parsing grep.patternType\n> -\t * & grep.extendedRegexp we set opt->pattern_type_option and\n> -\t * opt->extended_regexp_option, respectively. We then\n> -\t * internally use opt->extended_regexp_option to see if we're\n> -\t * compiling an ERE. It must be unset if that's not actually\n> -\t * the case.\n> -\t */\n> -\tif (pattern_type != GREP_PATTERN_TYPE_ERE &&\n> -\t    opt->extended_regexp_option)\n> -\t\topt->extended_regexp_option = 0;\n> -\n> -\tswitch (pattern_type) {\n> -\tcase GREP_PATTERN_TYPE_UNSPECIFIED:\n> -\t\t/* fall through */\n> -\n> -\tcase GREP_PATTERN_TYPE_BRE:\n> -\t\tbreak;\n> -\n> -\tcase GREP_PATTERN_TYPE_ERE:\n> -\t\topt->extended_regexp_option = 1;\n> -\t\tbreak;\n> -\n> -\tcase GREP_PATTERN_TYPE_FIXED:\n> -\t\topt->fixed = 1;\n> -\t\tbreak;\n> -\n> -\tcase GREP_PATTERN_TYPE_PCRE:\n> -\t\topt->pcre2 = 1;\n> -\t\tbreak;\n> -\t}\n> -}\n>\n> -void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n> -{\n> -\tif (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)\n> -\t\tgrep_set_pattern_type_option(pattern_type, opt);\n> -\telse if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)\n> -\t\tgrep_set_pattern_type_option(opt->pattern_type_option, opt);\n> -\telse if (opt->extended_regexp_option)\n> -\t\t/*\n> -\t\t * This branch *must* happen after setting from the\n> -\t\t * opt->pattern_type_option above, we don't want\n> -\t\t * grep.extendedRegexp to override grep.patternType!\n> -\t\t */\n> -\t\tgrep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);\n> -}\n\nIt is great that we can lose this, together with the associated\nfields like fixed and pcre2.\n\n> @@ -488,11 +432,16 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n>  \tint err;\n>  \tint regflags = REG_NEWLINE;\n>  \n> +\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_UNSPECIFIED)\n> +\t\topt->pattern_type_option = (opt->extended_regexp_option\n> +\t\t\t\t\t    ? GREP_PATTERN_TYPE_ERE\n> +\t\t\t\t\t    : GREP_PATTERN_TYPE_BRE);\n\nIt is nice that we can forget about .extended_regrexp_option member\nafter this point, and .pattern_type_option will be the only thing\nthat matters.\n\n>  \tp->word_regexp = opt->word_regexp;\n>  \tp->ignore_case = opt->ignore_case;\n> -\tp->fixed = opt->fixed;\n> +\tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\n\nThis makes readers wonder if we can further lose members in p\n(specifically .fixed), but cleaning up the grep_opt members is\nalready a great progress.\n\nLooking good.  Other than minor tweaks I mentioned on the proposed\nlog message, I didn't see anything wrong in this version.\n\nThanks.\n"},{"id":"448502","messageId":"cover-v11-00.10-00000000000-20220216T000006Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v10-0.9-00000000000-20220204T211534Z-avarab@gmail.com","subject":"[PATCH v11 00/10] grep: simplify & delete \"init\" & \"config\" code","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-16T00:00:29Z","receivedAt":"2022-02-16T00:01:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This series makes using the grep.[ch] API easier, by having it follow\nthe usual pattern of being initialized with:\n\n    defaults -> config -> command-line\n\nThis is to make some follow-up work easier, this is a net code\ndeletion if we exclude newly added tests.\n\nChanges since v9:\n\n  * A new 3/10 and 4/10 hopefully address the comments about the test\n    code. I ended up just adding a helper to reduce the existing and\n    new verbosity of the tests, which should make it easier to reason\n    about them.\n\nÆvar Arnfjörð Bjarmason (10):\n  grep.h: remove unused \"regex_t regexp\" from grep_opt\n  log tests: check if grep_config() is called by \"log\"-like cmds\n  grep tests: create a helper function for \"BRE\" or \"ERE\"\n  grep tests: add missing \"grep.patternType\" config tests\n  built-ins: trust the \"prefix\" from run_builtin()\n  grep.c: don't pass along NULL callback value\n  grep API: call grep_config() after grep_init()\n  grep.h: make \"grep_opt.pattern_type_option\" use its enum\n  grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"\n  grep: simplify config parsing and option parsing\n\n builtin/grep.c    |  27 +++----\n builtin/log.c     |  13 +++-\n builtin/ls-tree.c |   2 +-\n git.c             |   1 +\n grep.c            | 113 ++++------------------------\n grep.h            |  31 ++++++--\n revision.c        |   4 +-\n t/t4202-log.sh    |  24 ++++++\n t/t7810-grep.sh   | 186 ++++++++++++++++++++++++++--------------------\n 9 files changed, 195 insertions(+), 206 deletions(-)\n\nRange-diff against v10:\n 1:  184f7e0c5bd =  1:  67af9123727 grep.h: remove unused \"regex_t regexp\" from grep_opt\n 2:  ac397cc6a18 =  2:  b275d23f0a8 log tests: check if grep_config() is called by \"log\"-like cmds\n 3:  3464c76cfd7 <  -:  ----------- grep tests: add missing \"grep.patternType\" config tests\n -:  ----------- >  3:  b0f91bf7e4a grep tests: create a helper function for \"BRE\" or \"ERE\"\n -:  ----------- >  4:  9906edd4f58 grep tests: add missing \"grep.patternType\" config tests\n 4:  c6ada96298a =  5:  7389f767388 built-ins: trust the \"prefix\" from run_builtin()\n 5:  1f09de53e07 =  6:  38bfa0ed5f9 grep.c: don't pass along NULL callback value\n 6:  ce646154538 =  7:  a4c1ee91dc9 grep API: call grep_config() after grep_init()\n 7:  6446b4f0f33 =  8:  fa0da3a9fba grep.h: make \"grep_opt.pattern_type_option\" use its enum\n 8:  df8ba5aba68 =  9:  243ceccc1ad grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"\n 9:  ccbdfa48315 = 10:  38bc5dc9461 grep: simplify config parsing and option parsing\n-- \n2.35.1.1028.g9479bb34b83\n\n"},{"id":"448503","messageId":"patch-v11-01.10-67af9123727-20220216T000006Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v11-00.10-00000000000-20220216T000006Z-avarab@gmail.com","subject":"[PATCH v11 01/10] grep.h: remove unused \"regex_t regexp\" from grep_opt","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-16T00:00:30Z","receivedAt":"2022-02-16T00:01:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This \"regex_t\" in grep_opt has not been used since\nf9b9faf6f8a (builtin-grep: allow more than one patterns., 2006-05-02),\nwe still use a \"regex_t\" for compiling regexes, but that's in the\n\"grep_pat\" struct\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 6a1f0ab0172..400172676a1 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -136,7 +136,6 @@ struct grep_opt {\n \n \tconst char *prefix;\n \tint prefix_length;\n-\tregex_t regexp;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n-- \n2.35.1.1028.g9479bb34b83\n\n"},{"id":"448504","messageId":"patch-v11-02.10-b275d23f0a8-20220216T000006Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v11-00.10-00000000000-20220216T000006Z-avarab@gmail.com","subject":"[PATCH v11 02/10] log tests: check if grep_config() is called by \"log\"-like cmds","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-16T00:00:31Z","receivedAt":"2022-02-16T00:01:19Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the tests added in my 9df46763ef1 (log: add exhaustive tests\nfor pattern style options & config, 2017-05-20) to check not only\nwhether \"git log\" handles \"grep.patternType\", but also \"git show\"\netc.\n\nIt's sufficient to check whether we match a \"fixed\" or a \"basic\" regex\nhere to see if these codepaths correctly invoked grep_config(). We\ndon't need to check the details of their regular expression matching\nas the \"log\" test does.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t4202-log.sh | 24 ++++++++++++++++++++++++\n 1 file changed, 24 insertions(+)\n\ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex dc884107de4..5c4385c745b 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -449,6 +449,30 @@ test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurati\n \t)\n '\n \n+for cmd in show whatchanged reflog format-patch\n+do\n+\tcase \"$cmd\" in\n+\tformat-patch) myarg=\"HEAD~..\" ;;\n+\t*) myarg= ;;\n+\tesac\n+\n+\ttest_expect_success \"$cmd: understands grep.patternType, like 'log'\" '\n+\t\tgit init \"pattern-type-$cmd\" &&\n+\t\t(\n+\t\t\tcd \"pattern-type-$cmd\" &&\n+\t\t\ttest_commit 1 file A &&\n+\t\t\ttest_commit \"(1|2)\" file B 2 &&\n+\n+\t\t\tgit -c grep.patternType=fixed $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_must_be_empty actual &&\n+\n+\t\t\tgit -c grep.patternType=basic $cmd --grep=\"...\" $myarg >actual &&\n+\t\t\ttest_file_not_empty actual\n+\t\t)\n+\t'\n+done\n+test_done\n+\n test_expect_success 'log --author' '\n \tcat >expect <<-\\EOF &&\n \tAuthor: <BOLD;RED>A U<RESET> Thor <author@example.com>\n-- \n2.35.1.1028.g9479bb34b83\n\n"},{"id":"448505","messageId":"patch-v11-05.10-7389f767388-20220216T000006Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v11-00.10-00000000000-20220216T000006Z-avarab@gmail.com","subject":"[PATCH v11 05/10] built-ins: trust the \"prefix\" from run_builtin()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-16T00:00:34Z","receivedAt":"2022-02-16T00:01:19Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in \"builtin/grep.c\" and \"builtin/ls-tree.c\" to trust the\n\"prefix\" passed from \"run_builtin()\". The \"prefix\" we get from setup.c\nis either going to be NULL or a string of length >0, never \"\".\n\nSo we can drop the \"prefix && *prefix\" checks added for\n\"builtin/grep.c\" in 0d042fecf2f (git-grep: show pathnames relative to\nthe current directory, 2006-08-11), and for \"builtin/ls-tree.c\" in\na69dd585fca (ls-tree: chomp leading directories when run from a\nsubdirectory, 2005-12-23).\n\nAs seen in code in revision.c that was added in cd676a51367 (diff\n--relative: output paths as relative to the current subdirectory,\n2008-02-12) we already have existing code that does away with this\nassertion.\n\nThis makes it easier to reason about a subsequent change to the\n\"prefix_length\" code in grep.c in a subsequent commit, and since we're\ngoing to the trouble of doing that let's leave behind an assert() to\npromise this to any future callers.\n\nFor \"builtin/grep.c\" it would be painful to pass the \"prefix\" down the\ncallchain of:\n\n    cmd_grep -> grep_tree -> grep_submodule -> grep_cache -> grep_oid ->\n    grep_source_name\n\nSo for the code that needs it in grep_source_name() let's add a\n\"grep_prefix\" variable similar to the existing \"ls_tree_prefix\".\n\nWhile at it let's move the code in cmd_ls_tree() around so that we\nassign to the \"ls_tree_prefix\" right after declaring the variables,\nand stop assigning to \"prefix\". We only subsequently used that\nvariable later in the function after clobbering it. Let's just use our\nown \"grep_prefix\" instead.\n\nLet's also add an assert() in git.c, so that we'll make this promise\nabout the \"prefix\" to any current and future callers, as well as to\nany readers of the code.\n\nCode history:\n\n * The strlen() in \"grep.c\" hasn't been used since 493b7a08d80 (grep:\n   accept relative paths outside current working directory, 2009-09-05).\n\n   When that code was added in 0d042fecf2f (git-grep: show pathnames\n   relative to the current directory, 2006-08-11) we used the length.\n\n   But since 493b7a08d80 we haven't used it for anything except a\n   boolean check that we could have done on the \"prefix\" member\n   itself.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c    | 13 ++++++++-----\n builtin/ls-tree.c |  2 +-\n git.c             |  1 +\n grep.c            |  4 +---\n grep.h            |  4 +---\n revision.c        |  2 +-\n 6 files changed, 13 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 9e34a820ad4..d85cbabea67 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -26,6 +26,8 @@\n #include \"object-store.h\"\n #include \"packfile.h\"\n \n+static const char *grep_prefix;\n+\n static char const * const grep_usage[] = {\n \tN_(\"git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]\"),\n \tNULL\n@@ -315,11 +317,11 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \tstrbuf_reset(out);\n \n \tif (opt->null_following_name) {\n-\t\tif (opt->relative && opt->prefix_length) {\n+\t\tif (opt->relative && grep_prefix) {\n \t\t\tstruct strbuf rel_buf = STRBUF_INIT;\n \t\t\tconst char *rel_name =\n \t\t\t\trelative_path(filename + tree_name_len,\n-\t\t\t\t\t      opt->prefix, &rel_buf);\n+\t\t\t\t\t      grep_prefix, &rel_buf);\n \n \t\t\tif (tree_name_len)\n \t\t\t\tstrbuf_add(out, filename, tree_name_len);\n@@ -332,8 +334,8 @@ static void grep_source_name(struct grep_opt *opt, const char *filename,\n \t\treturn;\n \t}\n \n-\tif (opt->relative && opt->prefix_length)\n-\t\tquote_path(filename + tree_name_len, opt->prefix, out, 0);\n+\tif (opt->relative && grep_prefix)\n+\t\tquote_path(filename + tree_name_len, grep_prefix, out, 0);\n \telse\n \t\tquote_c_style(filename + tree_name_len, out, NULL, 0);\n \n@@ -962,9 +964,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\t   PARSE_OPT_NOCOMPLETE),\n \t\tOPT_END()\n \t};\n+\tgrep_prefix = prefix;\n \n \tgit_config(grep_cmd_config, NULL);\n-\tgrep_init(&opt, the_repository, prefix);\n+\tgrep_init(&opt, the_repository);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex 3a442631c71..6cb554cbb0a 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -150,7 +150,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)\n \n \tgit_config(git_default_config, NULL);\n \tls_tree_prefix = prefix;\n-\tif (prefix && *prefix)\n+\tif (prefix)\n \t\tchomp_prefix = strlen(prefix);\n \n \targc = parse_options(argc, argv, prefix, ls_tree_options,\ndiff --git a/git.c b/git.c\nindex 340665d4a04..a25940d72e8 100644\n--- a/git.c\n+++ b/git.c\n@@ -436,6 +436,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)\n \t} else {\n \t\tprefix = NULL;\n \t}\n+\tassert(!prefix || *prefix);\n \tprecompose_argv_prefix(argc, argv, NULL);\n \tif (use_pager == -1 && run_setup &&\n \t\t!(p->option & DELAY_PAGER_CONFIG))\ndiff --git a/grep.c b/grep.c\nindex 5bec7fd7935..8b61cbc3e09 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -139,13 +139,11 @@ int grep_config(const char *var, const char *value, void *cb)\n  * default values from the template we read the configuration\n  * information in an earlier call to git_config(grep_config).\n  */\n-void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix)\n+void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n \t*opt = grep_defaults;\n \n \topt->repo = repo;\n-\topt->prefix = prefix;\n-\topt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;\n \topt->pattern_tail = &opt->pattern_list;\n \topt->header_tail = &opt->header_list;\n }\ndiff --git a/grep.h b/grep.h\nindex 400172676a1..23a2a41d2c4 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -134,8 +134,6 @@ struct grep_opt {\n \t */\n \tstruct repository *repo;\n \n-\tconst char *prefix;\n-\tint prefix_length;\n \tint linenum;\n \tint columnnum;\n \tint invert;\n@@ -182,7 +180,7 @@ struct grep_opt {\n };\n \n int grep_config(const char *var, const char *value, void *);\n-void grep_init(struct grep_opt *, struct repository *repo, const char *prefix);\n+void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex ad4286fbdde..d6e0e2b23b5 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1838,7 +1838,7 @@ void repo_init_revisions(struct repository *r,\n \trevs->commit_format = CMIT_FMT_DEFAULT;\n \trevs->expand_tabs_in_log_default = 8;\n \n-\tgrep_init(&revs->grep_filter, revs->repo, prefix);\n+\tgrep_init(&revs->grep_filter, revs->repo);\n \trevs->grep_filter.status_only = 1;\n \n \trepo_diff_setup(revs->repo, &revs->diffopt);\n-- \n2.35.1.1028.g9479bb34b83\n\n"},{"id":"448506","messageId":"patch-v11-03.10-b0f91bf7e4a-20220216T000006Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v11-00.10-00000000000-20220216T000006Z-avarab@gmail.com","subject":"[PATCH v11 03/10] grep tests: create a helper function for \"BRE\" or \"ERE\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-16T00:00:32Z","receivedAt":"2022-02-16T00:01:21Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor the repeated test code for finding out whether a given set of\nconfiguration will pick basic, extended or fixed into a new\n\"test_pattern_type\" helper function.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7810-grep.sh | 134 +++++++++++++++++++-----------------------------\n 1 file changed, 54 insertions(+), 80 deletions(-)\n\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 424c31c3287..6f1103b54b9 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -98,6 +98,37 @@ test_expect_success 'grep should not segfault with a bad input' '\n \n test_invalid_grep_expression --and -e A\n \n+test_pattern_type () {\n+\tH=$1 &&\n+\tHC=$2 &&\n+\tL=$3 &&\n+\ttype=$4 &&\n+\tshift 4 &&\n+\n+\texpected_str= &&\n+\tcase \"$type\" in\n+\tBRE)\n+\t\texpected_str=\"${HC}ab:a+bc\"\n+\t\t;;\n+\tERE)\n+\t\texpected_str=\"${HC}ab:abc\"\n+\t\t;;\n+\tFIX)\n+\t\texpected_str=\"${HC}ab:a+b*c\"\n+\t\t;;\n+\t*)\n+\t\tBUG \"unknown pattern type '$type'\"\n+\t\t;;\n+\tesac &&\n+\tconfig_str=\"$@\" &&\n+\n+\ttest_expect_success \"grep $L with '$config_str' interpreted as $type\" '\n+\t\techo $expected_str >expected &&\n+\t\tgit $config_str grep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+}\n+\n for H in HEAD ''\n do\n \tcase \"$H\" in\n@@ -393,35 +424,13 @@ do\n \t\tgit grep --no-recursive -n -e vvv $H -- t . >actual &&\n \t\ttest_cmp expected actual\n \t'\n-\ttest_expect_success \"grep $L with grep.extendedRegexp=false\" '\n-\t\techo \"${HC}ab:a+bc\" >expected &&\n-\t\tgit -c grep.extendedRegexp=false grep \"a+b*c\" $H ab >actual &&\n-\t\ttest_cmp expected actual\n-\t'\n \n-\ttest_expect_success \"grep $L with grep.extendedRegexp=true\" '\n-\t\techo \"${HC}ab:abc\" >expected &&\n-\t\tgit -c grep.extendedRegexp=true grep \"a+b*c\" $H ab >actual &&\n-\t\ttest_cmp expected actual\n-\t'\n \n-\ttest_expect_success \"grep $L with grep.patterntype=basic\" '\n-\t\techo \"${HC}ab:a+bc\" >expected &&\n-\t\tgit -c grep.patterntype=basic grep \"a+b*c\" $H ab >actual &&\n-\t\ttest_cmp expected actual\n-\t'\n-\n-\ttest_expect_success \"grep $L with grep.patterntype=extended\" '\n-\t\techo \"${HC}ab:abc\" >expected &&\n-\t\tgit -c grep.patterntype=extended grep \"a+b*c\" $H ab >actual &&\n-\t\ttest_cmp expected actual\n-\t'\n-\n-\ttest_expect_success \"grep $L with grep.patterntype=fixed\" '\n-\t\techo \"${HC}ab:a+b*c\" >expected &&\n-\t\tgit -c grep.patterntype=fixed grep \"a+b*c\" $H ab >actual &&\n-\t\ttest_cmp expected actual\n-\t'\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE -c grep.extendedRegexp=false\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE -c grep.extendedRegexp=true\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE -c grep.patternType=basic\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE -c grep.patternType=extended\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" FIX -c grep.patternType=fixed\n \n \ttest_expect_success PCRE \"grep $L with grep.patterntype=perl\" '\n \t\techo \"${HC}ab:a+b*c\" >expected &&\n@@ -433,59 +442,24 @@ do\n \t\ttest_must_fail git -c grep.patterntype=perl grep \"foo.*bar\"\n \t'\n \n-\ttest_expect_success \"grep $L with grep.patternType=default and grep.extendedRegexp=true\" '\n-\t\techo \"${HC}ab:abc\" >expected &&\n-\t\tgit \\\n-\t\t\t-c grep.patternType=default \\\n-\t\t\t-c grep.extendedRegexp=true \\\n-\t\t\tgrep \"a+b*c\" $H ab >actual &&\n-\t\ttest_cmp expected actual\n-\t'\n-\n-\ttest_expect_success \"grep $L with grep.extendedRegexp=true and grep.patternType=default\" '\n-\t\techo \"${HC}ab:abc\" >expected &&\n-\t\tgit \\\n-\t\t\t-c grep.extendedRegexp=true \\\n-\t\t\t-c grep.patternType=default \\\n-\t\t\tgrep \"a+b*c\" $H ab >actual &&\n-\t\ttest_cmp expected actual\n-\t'\n-\n-\ttest_expect_success \"grep $L with grep.patternType=extended and grep.extendedRegexp=false\" '\n-\t\techo \"${HC}ab:abc\" >expected &&\n-\t\tgit \\\n-\t\t\t-c grep.patternType=extended \\\n-\t\t\t-c grep.extendedRegexp=false \\\n-\t\t\tgrep \"a+b*c\" $H ab >actual &&\n-\t\ttest_cmp expected actual\n-\t'\n-\n-\ttest_expect_success \"grep $L with grep.patternType=basic and grep.extendedRegexp=true\" '\n-\t\techo \"${HC}ab:a+bc\" >expected &&\n-\t\tgit \\\n-\t\t\t-c grep.patternType=basic \\\n-\t\t\t-c grep.extendedRegexp=true \\\n-\t\t\tgrep \"a+b*c\" $H ab >actual &&\n-\t\ttest_cmp expected actual\n-\t'\n-\n-\ttest_expect_success \"grep $L with grep.extendedRegexp=false and grep.patternType=extended\" '\n-\t\techo \"${HC}ab:abc\" >expected &&\n-\t\tgit \\\n-\t\t\t-c grep.extendedRegexp=false \\\n-\t\t\t-c grep.patternType=extended \\\n-\t\t\tgrep \"a+b*c\" $H ab >actual &&\n-\t\ttest_cmp expected actual\n-\t'\n-\n-\ttest_expect_success \"grep $L with grep.extendedRegexp=true and grep.patternType=basic\" '\n-\t\techo \"${HC}ab:a+bc\" >expected &&\n-\t\tgit \\\n-\t\t\t-c grep.extendedRegexp=true \\\n-\t\t\t-c grep.patternType=basic \\\n-\t\t\tgrep \"a+b*c\" $H ab >actual &&\n-\t\ttest_cmp expected actual\n-\t'\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.patternType=default \\\n+\t\t-c grep.extendedRegexp=true\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.patternType=default\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.patternType=extended \\\n+\t\t-c grep.extendedRegexp=false\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE \\\n+\t\t-c grep.patternType=basic \\\n+\t\t-c grep.extendedRegexp=true\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.extendedRegexp=false \\\n+\t\t-c grep.patternType=extended\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.patternType=basic\n \n \ttest_expect_success \"grep --count $L\" '\n \t\techo ${HC}ab:3 >expected &&\n-- \n2.35.1.1028.g9479bb34b83\n\n"},{"id":"448507","messageId":"patch-v11-04.10-9906edd4f58-20220216T000006Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v11-00.10-00000000000-20220216T000006Z-avarab@gmail.com","subject":"[PATCH v11 04/10] grep tests: add missing \"grep.patternType\" config tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-16T00:00:33Z","receivedAt":"2022-02-16T00:01:23Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the grep tests to assert that setting\n\"grep.patternType=extended\" followed by \"grep.patternType=default\"\nwill behave as if \"--basic-regexp\" was provided, and not as\n\"--extended-regexp\". In a subsequent commit we'll need to treat\n\"grep.patternType=default\" as a special-case, but let's make sure we\nignore it if it's being set to \"default\" following an earlier\nnon-\"default\" \"grep.patternType\" setting.\n\nLet's also test what happens when we have a sequence of \"extended\"\nfollowed by \"default\" and \"fixed\". In that case the \"fixed\" should\nprevail, as well as tests to check that a \"grep.extendedRegexp=true\"\nfollowed by a \"grep.extendedRegexp=false\" behaves as though\n\"grep.extendedRegexp\" wasn't provided.\n\nSee [1] for the source of some of these tests, and their\ninitial (pseudocode) implementation, and [2] for a later discussion\nabout a breakage due to missing testing (which had been noted in [1]\nall along).\n\n1. https://lore.kernel.org/git/xmqqv8zf6j86.fsf@gitster.g/\n2. https://lore.kernel.org/git/xmqqpmoczwtu.fsf@gitster.g/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t7810-grep.sh | 52 +++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 52 insertions(+)\n\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 6f1103b54b9..69356011713 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -461,6 +461,58 @@ do\n \t\t-c grep.extendedRegexp=true \\\n \t\t-c grep.patternType=basic\n \n+\t# grep.extendedRegexp is last-one-wins\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.extendedRegexp=false\n+\n+\t# grep.patternType=basic pays no attention to grep.extendedRegexp\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.patternType=basic \\\n+\t\t-c grep.extendedRegexp=false\n+\n+\t# grep.patternType=extended pays no attention to grep.extendedRegexp\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.patternType=extended \\\n+\t\t-c grep.extendedRegexp=false\n+\n+\t# grep.extendedRegexp is used with a last-one-wins grep.patternType=default\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.patternType=fixed \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.patternType=default\n+\n+\t# grep.extendedRegexp is used with earlier grep.patternType=default\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.extendedRegexp=false \\\n+\t\t-c grep.patternType=default \\\n+\t\t-c grep.extendedRegexp=true\n+\n+\t# grep.extendedRegexp is used with a last-one-loses grep.patternType=default\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.extendedRegexp=false \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.patternType=default\n+\n+\t# grep.extendedRegexp and grep.patternType are both last-one-wins independently\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE \\\n+\t\t-c grep.patternType=default \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.patternType=basic\n+\n+\t# grep.patternType=extended and grep.patternType=default\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE \\\n+\t\t-c grep.patternType=extended \\\n+\t\t-c grep.patternType=default\n+\n+\t# grep.patternType=[extended -> default -> fixed] (BRE)\" '\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" FIX \\\n+\t\t-c grep.patternType=extended \\\n+\t\t-c grep.patternType=default \\\n+\t\t-c grep.patternType=fixed\n+\n \ttest_expect_success \"grep --count $L\" '\n \t\techo ${HC}ab:3 >expected &&\n \t\tgit grep --count -e b $H -- ab >actual &&\n-- \n2.35.1.1028.g9479bb34b83\n\n"},{"id":"448508","messageId":"patch-v11-06.10-38bfa0ed5f9-20220216T000006Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v11-00.10-00000000000-20220216T000006Z-avarab@gmail.com","subject":"[PATCH v11 06/10] grep.c: don't pass along NULL callback value","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-16T00:00:35Z","receivedAt":"2022-02-16T00:01:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change grep_cmd_config() to stop passing around the always-NULL \"cb\"\nvalue. When this code was added in 7e8f59d577e (grep: color patterns\nin output, 2009-03-07) it was non-NULL, but when that changed in\n15fabd1bbd4 (builtin/grep.c: make configuration callback more\nreusable, 2012-10-09) this code was left behind.\n\nIn a subsequent change I'll start using the \"cb\" value, this will make\nit clear which functions we call need it, and which don't.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex d85cbabea67..5ec4cecae45 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,8 +285,8 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, cb);\n-\tif (git_color_default_config(var, value, cb) < 0)\n+\tint st = grep_config(var, value, NULL);\n+\tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n \tif (!strcmp(var, \"grep.threads\")) {\n-- \n2.35.1.1028.g9479bb34b83\n\n"},{"id":"448509","messageId":"patch-v11-08.10-fa0da3a9fba-20220216T000006Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v11-00.10-00000000000-20220216T000006Z-avarab@gmail.com","subject":"[PATCH v11 08/10] grep.h: make \"grep_opt.pattern_type_option\" use its enum","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-16T00:00:37Z","receivedAt":"2022-02-16T00:01:29Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the \"pattern_type_option\" member of \"struct grep_opt\" to use\nthe enum type we use for it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.h | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/grep.h b/grep.h\nindex 3112d1c2a38..89a2ce51130 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -164,7 +164,7 @@ struct grep_opt {\n \tint funcname;\n \tint funcbody;\n \tint extended_regexp_option;\n-\tint pattern_type_option;\n+\tenum grep_pattern_type pattern_type_option;\n \tint ignore_locale;\n \tchar colors[NR_GREP_COLORS][COLOR_MAXLEN];\n \tunsigned pre_context;\n-- \n2.35.1.1028.g9479bb34b83\n\n"},{"id":"448510","messageId":"patch-v11-07.10-a4c1ee91dc9-20220216T000006Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v11-00.10-00000000000-20220216T000006Z-avarab@gmail.com","subject":"[PATCH v11 07/10] grep API: call grep_config() after grep_init()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-16T00:00:36Z","receivedAt":"2022-02-16T00:01:30Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The grep_init() function used the odd pattern of initializing the\npassed-in \"struct grep_opt\" with a statically defined \"grep_defaults\"\nstruct, which would be modified in-place when we invoked\ngrep_config().\n\nSo we effectively (b) initialized config, (a) then defaults, (c)\nfollowed by user options. Usually those are ordered as \"a\", \"b\" and\n\"c\" instead.\n\nAs the comments being removed here show the previous behavior needed\nto be carefully explained as we'd potentially share the populated\nconfiguration among different instances of grep_init(). In practice we\ndidn't do that, but now that it can't be a concern anymore let's\nremove those comments.\n\nThis does not change the behavior of any of the configuration\nvariables or options. That would have been the case if we didn't move\naround the grep_config() call in \"builtin/log.c\". But now that we call\n\"grep_config\" after \"git_log_config\" and \"git_format_config\" we'll\nneed to pass in the already initialized \"struct grep_opt *\".\n\nSee 6ba9bb76e02 (grep: copy struct in one fell swoop, 2020-11-29) and\n7687a0541e0 (grep: move the configuration parsing logic to grep.[ch],\n2012-10-09) for the commits that added the comments.\n\nThe memcpy() pattern here will be optimized away and follows the\nconvention of other *_init() functions. See 5726a6b4012 (*.c *_init():\ndefine in terms of corresponding *_INIT macro, 2021-07-01).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c |  4 ++--\n builtin/log.c  | 13 +++++++++++--\n grep.c         | 39 +++------------------------------------\n grep.h         | 21 +++++++++++++++++++++\n 4 files changed, 37 insertions(+), 40 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5ec4cecae45..0ea124321b6 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -285,7 +285,7 @@ static int wait_all(void)\n \n static int grep_cmd_config(const char *var, const char *value, void *cb)\n {\n-\tint st = grep_config(var, value, NULL);\n+\tint st = grep_config(var, value, cb);\n \tif (git_color_default_config(var, value, NULL) < 0)\n \t\tst = -1;\n \n@@ -966,8 +966,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t};\n \tgrep_prefix = prefix;\n \n-\tgit_config(grep_cmd_config, NULL);\n \tgrep_init(&opt, the_repository);\n+\tgit_config(grep_cmd_config, &opt);\n \n \t/*\n \t * If there is no -- then the paths must exist in the working\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 4b493408cc5..06283b37e7a 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -520,8 +520,6 @@ static int git_log_config(const char *var, const char *value, void *cb)\n \t\treturn 0;\n \t}\n \n-\tif (grep_config(var, value, cb) < 0)\n-\t\treturn -1;\n \tif (git_gpg_config(var, value, cb) < 0)\n \t\treturn -1;\n \treturn git_diff_ui_config(var, value, cb);\n@@ -536,6 +534,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.simplify_history = 0;\n \tmemset(&opt, 0, sizeof(opt));\n@@ -650,6 +650,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \n \tmemset(&match_all, 0, sizeof(match_all));\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.diff = 1;\n \trev.always_show_header = 1;\n \trev.no_walk = 1;\n@@ -733,6 +735,8 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n \tinit_reflog_walk(&rev.reflog_info);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.verbose_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -766,6 +770,8 @@ int cmd_log(int argc, const char **argv, const char *prefix)\n \tgit_config(git_log_config, NULL);\n \n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.always_show_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n@@ -1848,10 +1854,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \textra_hdr.strdup_strings = 1;\n \textra_to.strdup_strings = 1;\n \textra_cc.strdup_strings = 1;\n+\n \tinit_log_defaults();\n \tinit_display_notes(&notes_opt);\n \tgit_config(git_format_config, NULL);\n \trepo_init_revisions(the_repository, &rev, prefix);\n+\tgit_config(grep_config, &rev.grep_filter);\n+\n \trev.show_notes = show_notes;\n \tmemcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));\n \trev.commit_format = CMIT_FMT_EMAIL;\ndiff --git a/grep.c b/grep.c\nindex 8b61cbc3e09..2f6a01c52a5 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -19,27 +19,6 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)\n \tfwrite(buf, size, 1, stdout);\n }\n \n-static struct grep_opt grep_defaults = {\n-\t.relative = 1,\n-\t.pathname = 1,\n-\t.max_depth = -1,\n-\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t.colors = {\n-\t\t[GREP_COLOR_CONTEXT] = \"\",\n-\t\t[GREP_COLOR_FILENAME] = GIT_COLOR_MAGENTA,\n-\t\t[GREP_COLOR_FUNCTION] = \"\",\n-\t\t[GREP_COLOR_LINENO] = GIT_COLOR_GREEN,\n-\t\t[GREP_COLOR_COLUMNNO] = GIT_COLOR_GREEN,\n-\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED,\n-\t\t[GREP_COLOR_SELECTED] = \"\",\n-\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN,\n-\t},\n-\t.only_matching = 0,\n-\t.color = -1,\n-\t.output = std_output,\n-};\n-\n static const char *color_grep_slots[] = {\n \t[GREP_COLOR_CONTEXT]\t    = \"context\",\n \t[GREP_COLOR_FILENAME]\t    = \"filename\",\n@@ -75,20 +54,12 @@ define_list_config_array_extra(color_grep_slots, {\"match\"});\n  */\n int grep_config(const char *var, const char *value, void *cb)\n {\n-\tstruct grep_opt *opt = &grep_defaults;\n+\tstruct grep_opt *opt = cb;\n \tconst char *slot;\n \n \tif (userdiff_config(var, value) < 0)\n \t\treturn -1;\n \n-\t/*\n-\t * The instance of grep_opt that we set up here is copied by\n-\t * grep_init() to be used by each individual invocation.\n-\t * When populating a new field of this structure here, be\n-\t * sure to think about ownership -- e.g., you might need to\n-\t * override the shallow copy in grep_init() with a deep copy.\n-\t */\n-\n \tif (!strcmp(var, \"grep.extendedregexp\")) {\n \t\topt->extended_regexp_option = git_config_bool(var, value);\n \t\treturn 0;\n@@ -134,14 +105,10 @@ int grep_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/*\n- * Initialize one instance of grep_opt and copy the\n- * default values from the template we read the configuration\n- * information in an earlier call to git_config(grep_config).\n- */\n void grep_init(struct grep_opt *opt, struct repository *repo)\n {\n-\t*opt = grep_defaults;\n+\tstruct grep_opt blank = GREP_OPT_INIT;\n+\tmemcpy(opt, &blank, sizeof(*opt));\n \n \topt->repo = repo;\n \topt->pattern_tail = &opt->pattern_list;\ndiff --git a/grep.h b/grep.h\nindex 23a2a41d2c4..3112d1c2a38 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -179,6 +179,27 @@ struct grep_opt {\n \tvoid *output_priv;\n };\n \n+#define GREP_OPT_INIT { \\\n+\t.relative = 1, \\\n+\t.pathname = 1, \\\n+\t.max_depth = -1, \\\n+\t.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, \\\n+\t.colors = { \\\n+\t\t[GREP_COLOR_CONTEXT] = \"\", \\\n+\t\t[GREP_COLOR_FILENAME] = GIT_COLOR_MAGENTA, \\\n+\t\t[GREP_COLOR_FUNCTION] = \"\", \\\n+\t\t[GREP_COLOR_LINENO] = GIT_COLOR_GREEN, \\\n+\t\t[GREP_COLOR_COLUMNNO] = GIT_COLOR_GREEN, \\\n+\t\t[GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, \\\n+\t\t[GREP_COLOR_SELECTED] = \"\", \\\n+\t\t[GREP_COLOR_SEP] = GIT_COLOR_CYAN, \\\n+\t}, \\\n+\t.only_matching = 0, \\\n+\t.color = -1, \\\n+\t.output = std_output, \\\n+}\n+\n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n-- \n2.35.1.1028.g9479bb34b83\n\n"},{"id":"448511","messageId":"patch-v11-09.10-243ceccc1ad-20220216T000006Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v11-00.10-00000000000-20220216T000006Z-avarab@gmail.com","subject":"[PATCH v11 09/10] grep.c: do \"if (bool && memchr())\" not \"if (memchr() && bool)\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-16T00:00:38Z","receivedAt":"2022-02-16T00:01:32Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code in compile_regexp() to check the cheaper boolean\n\"!opt->pcre2\" condition before the \"memchr()\" search.\n\nThis doesn't noticeably optimize anything, but makes the code more\nobvious and conventional. The line wrapping being added here also\nmakes a subsequent commit smaller.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n grep.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/grep.c b/grep.c\nindex 2f6a01c52a5..62f2595f68a 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -492,7 +492,8 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \tp->ignore_case = opt->ignore_case;\n \tp->fixed = opt->fixed;\n \n-\tif (memchr(p->pattern, 0, p->patternlen) && !opt->pcre2)\n+\tif (!opt->pcre2 &&\n+\t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n \tp->is_fixed = is_fixed(p->pattern, p->patternlen);\n-- \n2.35.1.1028.g9479bb34b83\n\n"},{"id":"448512","messageId":"patch-v11-10.10-38bc5dc9461-20220216T000006Z-avarab@gmail.com","threadId":"56853","inReplyTo":"cover-v11-00.10-00000000000-20220216T000006Z-avarab@gmail.com","subject":"[PATCH v11 10/10] grep: simplify config parsing and option parsing","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-02-16T00:00:39Z","receivedAt":"2022-02-16T00:01:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Simplify the parsing of \"grep.patternType\" and\n\"grep.extendedRegexp\". This changes no behavior, but gets rid of\ncomplex parsing logic that isn't needed anymore.\n\nWhen \"grep.patternType\" was introduced in 84befcd0a4a (grep: add a\ngrep.patternType configuration setting, 2012-08-03) we promised that:\n\n 1. You can set \"grep.patternType\", and \"[setting it to] 'default'\n    will return to the default matching behavior\".\n\n    In that context \"the default\" meant whatever the configuration\n    system specified before that change, i.e. via grep.extendedRegexp.\n\n 2. We'd support the existing \"grep.extendedRegexp\" option, but ignore\n    it when the new \"grep.patternType\" option is set. We said we'd\n    only ignore the older \"grep.extendedRegexp\" option \"when the\n    `grep.patternType` option is set to a value other than\n    'default'\".\n\nIn a preceding commit we changed grep_config() to be called after\ngrep_init(), which means that much of the complexity here can go\naway.\n\nAs before both \"grep.patternType\" and \"grep.extendedRegexp\" are\nlast-one-wins variable, with \"grep.extendedRegexp\" yielding to\n\"grep.patternType\", except when \"grep.patternType=default\".\n\nNote that as the previously added tests indicate this cannot be done\non-the-fly as we see the config variables, without introducing more\nstate keeping. I.e. if we see:\n\n    -c grep.extendedRegexp=false\n    -c grep.patternType=default\n    -c extendedRegexp=true\n\nWe need to select ERE, since grep.patternType=default unselects that\nvariable, which normally has higher precedence, but we also need to\nselect BRE in cases of:\n\n    -c grep.extendedRegexp=true \\\n    -c grep.extendedRegexp=false\n\nWhich would not be the case for this, which select ERE:\n\n    -c grep.patternType=extended \\\n    -c grep.extendedRegexp=false\n\nTherefore we cannot do this on-the-fly in grep_config without also\nintroducing tracking variables for not only the pattern type, but what\nthe source of that pattern type was.\n\nSo we need to decide on the pattern after our config was fully\nparsed. Let's do that by deferring the decision on the pattern type\nuntil it's time to compile it in compile_regexp().\n\nBy that time we've not only parsed the config, but also handled the\ncommand-line options. Those will set \"opt.pattern_type_option\" (*not*\n\"opt.extended_regexp_option\"!).\n\nAt that point all we need to do is see if \"grep.patternType\" was\nUNSPECIFIED in the end (including an explicit \"=default\"), if so we'll\nuse the \"grep.extendedRegexp\" configuration, if any.\n\nSee my 07a3d411739 (grep: remove regflags from the public grep_opt\nAPI, 2017-06-29) for addition of the two comments being removed here,\ni.e. the complexity noted in that commit is now going away.\n\n1. https://lore.kernel.org/git/patch-v8-09.10-c211bb0c69d-20220118T155211Z-avarab@gmail.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/grep.c | 10 +++-----\n grep.c         | 69 +++++++-------------------------------------------\n grep.h         |  3 ---\n revision.c     |  2 --\n 4 files changed, 13 insertions(+), 71 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 0ea124321b6..942c4b25077 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -845,7 +845,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tint i;\n \tint dummy;\n \tint use_index = 1;\n-\tint pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;\n \tint allow_revs;\n \n \tstruct option options[] = {\n@@ -879,16 +878,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"descend at most <depth> levels\"), PARSE_OPT_NONEG,\n \t\t\tNULL, 1 },\n \t\tOPT_GROUP(\"\"),\n-\t\tOPT_SET_INT('E', \"extended-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('E', \"extended-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use extended POSIX regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_ERE),\n-\t\tOPT_SET_INT('G', \"basic-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('G', \"basic-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use basic POSIX regular expressions (default)\"),\n \t\t\t    GREP_PATTERN_TYPE_BRE),\n-\t\tOPT_SET_INT('F', \"fixed-strings\", &pattern_type_arg,\n+\t\tOPT_SET_INT('F', \"fixed-strings\", &opt.pattern_type_option,\n \t\t\t    N_(\"interpret patterns as fixed strings\"),\n \t\t\t    GREP_PATTERN_TYPE_FIXED),\n-\t\tOPT_SET_INT('P', \"perl-regexp\", &pattern_type_arg,\n+\t\tOPT_SET_INT('P', \"perl-regexp\", &opt.pattern_type_option,\n \t\t\t    N_(\"use Perl-compatible regular expressions\"),\n \t\t\t    GREP_PATTERN_TYPE_PCRE),\n \t\tOPT_GROUP(\"\"),\n@@ -982,7 +981,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, grep_usage,\n \t\t\t     PARSE_OPT_KEEP_DASHDASH |\n \t\t\t     PARSE_OPT_STOP_AT_NON_OPTION);\n-\tgrep_commit_pattern_type(pattern_type_arg, &opt);\n \n \tif (use_index && !startup_info->have_repository) {\n \t\tint fallback = 0;\ndiff --git a/grep.c b/grep.c\nindex 62f2595f68a..d5ad9617d99 100644\n--- a/grep.c\n+++ b/grep.c\n@@ -115,62 +115,6 @@ void grep_init(struct grep_opt *opt, struct repository *repo)\n \topt->header_tail = &opt->header_list;\n }\n \n-static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\t/*\n-\t * When committing to the pattern type by setting the relevant\n-\t * fields in grep_opt it's generally not necessary to zero out\n-\t * the fields we're not choosing, since they won't have been\n-\t * set by anything. The extended_regexp_option field is the\n-\t * only exception to this.\n-\t *\n-\t * This is because in the process of parsing grep.patternType\n-\t * & grep.extendedRegexp we set opt->pattern_type_option and\n-\t * opt->extended_regexp_option, respectively. We then\n-\t * internally use opt->extended_regexp_option to see if we're\n-\t * compiling an ERE. It must be unset if that's not actually\n-\t * the case.\n-\t */\n-\tif (pattern_type != GREP_PATTERN_TYPE_ERE &&\n-\t    opt->extended_regexp_option)\n-\t\topt->extended_regexp_option = 0;\n-\n-\tswitch (pattern_type) {\n-\tcase GREP_PATTERN_TYPE_UNSPECIFIED:\n-\t\t/* fall through */\n-\n-\tcase GREP_PATTERN_TYPE_BRE:\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_ERE:\n-\t\topt->extended_regexp_option = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_FIXED:\n-\t\topt->fixed = 1;\n-\t\tbreak;\n-\n-\tcase GREP_PATTERN_TYPE_PCRE:\n-\t\topt->pcre2 = 1;\n-\t\tbreak;\n-\t}\n-}\n-\n-void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)\n-{\n-\tif (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(pattern_type, opt);\n-\telse if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)\n-\t\tgrep_set_pattern_type_option(opt->pattern_type_option, opt);\n-\telse if (opt->extended_regexp_option)\n-\t\t/*\n-\t\t * This branch *must* happen after setting from the\n-\t\t * opt->pattern_type_option above, we don't want\n-\t\t * grep.extendedRegexp to override grep.patternType!\n-\t\t */\n-\t\tgrep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);\n-}\n-\n static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,\n \t\t\t\t\tconst char *origin, int no,\n \t\t\t\t\tenum grep_pat_token t,\n@@ -488,11 +432,16 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \tint err;\n \tint regflags = REG_NEWLINE;\n \n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_UNSPECIFIED)\n+\t\topt->pattern_type_option = (opt->extended_regexp_option\n+\t\t\t\t\t    ? GREP_PATTERN_TYPE_ERE\n+\t\t\t\t\t    : GREP_PATTERN_TYPE_BRE);\n+\n \tp->word_regexp = opt->word_regexp;\n \tp->ignore_case = opt->ignore_case;\n-\tp->fixed = opt->fixed;\n+\tp->fixed = opt->pattern_type_option == GREP_PATTERN_TYPE_FIXED;\n \n-\tif (!opt->pcre2 &&\n+\tif (opt->pattern_type_option != GREP_PATTERN_TYPE_PCRE &&\n \t    memchr(p->pattern, 0, p->patternlen))\n \t\tdie(_(\"given pattern contains NULL byte (via -f <file>). This is only supported with -P under PCRE v2\"));\n \n@@ -544,14 +493,14 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)\n \t\treturn;\n \t}\n \n-\tif (opt->pcre2) {\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_PCRE) {\n \t\tcompile_pcre2_pattern(p, opt);\n \t\treturn;\n \t}\n \n \tif (p->ignore_case)\n \t\tregflags |= REG_ICASE;\n-\tif (opt->extended_regexp_option)\n+\tif (opt->pattern_type_option == GREP_PATTERN_TYPE_ERE)\n \t\tregflags |= REG_EXTENDED;\n \terr = regcomp(&p->regexp, p->pattern, regflags);\n \tif (err) {\ndiff --git a/grep.h b/grep.h\nindex 89a2ce51130..c722d25ed9d 100644\n--- a/grep.h\n+++ b/grep.h\n@@ -143,7 +143,6 @@ struct grep_opt {\n \tint unmatch_name_only;\n \tint count;\n \tint word_regexp;\n-\tint fixed;\n \tint all_match;\n \tint no_body_match;\n \tint body_hit;\n@@ -154,7 +153,6 @@ struct grep_opt {\n \tint allow_textconv;\n \tint extended;\n \tint use_reflog_filter;\n-\tint pcre2;\n \tint relative;\n \tint pathname;\n \tint null_following_name;\n@@ -202,7 +200,6 @@ struct grep_opt {\n \n int grep_config(const char *var, const char *value, void *);\n void grep_init(struct grep_opt *, struct repository *repo);\n-void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);\n \n void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);\n void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);\ndiff --git a/revision.c b/revision.c\nindex d6e0e2b23b5..dd301e30147 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2860,8 +2860,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \n \tdiff_setup_done(&revs->diffopt);\n \n-\tgrep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,\n-\t\t\t\t &revs->grep_filter);\n \tif (!is_encoding_utf8(get_log_output_encoding()))\n \t\trevs->grep_filter.ignore_locale = 1;\n \tcompile_grep_patterns(&revs->grep_filter);\n-- \n2.35.1.1028.g9479bb34b83\n\n"},{"id":"448527","messageId":"xmqqh78zwo0g.fsf@gitster.g","threadId":"56853","inReplyTo":"cover-v11-00.10-00000000000-20220216T000006Z-avarab@gmail.com","subject":"Re: [PATCH v11 00/10] grep: simplify & delete \"init\" & \"config\" code","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-02-16T02:20:31Z","receivedAt":"2022-02-16T02:20:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n>   * A new 3/10 and 4/10 hopefully address the comments about the test\n>     code. I ended up just adding a helper to reduce the existing and\n>     new verbosity of the tests, which should make it easier to reason\n>     about them.\n\nHere is an excerpt plus comments on \"git diff @{1}\" after queuing\nthe new series.  I found only a few minor \"Huh?\", none of them a\nhuge deal.\n\nWill queue; thanks.\n\n+test_pattern_type () {\n+\tH=$1 &&\n+\tHC=$2 &&\n+\tL=$3 &&\n+\ttype=$4 &&\n+\tshift 4 &&\n+\n+\texpected_str= &&\n+\tcase \"$type\" in\n+\tBRE)\n+\t\texpected_str=\"${HC}ab:a+bc\"\n+\t\t;;\n+\tERE)\n+\t\texpected_str=\"${HC}ab:abc\"\n+\t\t;;\n+\tFIX)\n+\t\texpected_str=\"${HC}ab:a+b*c\"\n+\t\t;;\n+\t*)\n+\t\tBUG \"unknown pattern type '$type'\"\n+\t\t;;\n+\tesac &&\n\nExcellent.  I always had to think twice when commenting on earlier\nrounds of the patches which expected strings corresponded to what\npattern type.  Now we have a clearly defined table.\n\n+\tconfig_str=\"$@\" &&\n\nThis forces each element of $@ to lose its identity, and makes it a\nsingle string separated by a whitespace, so it is less misleading to\nwrite\n\n\tconfig_str=\"$*\"\n\ninstead, but it is not a huge deal.\n\n+\ttest_expect_success \"grep $L with '$config_str' interpreted as $type\" '\n+\t\techo $expected_str >expected &&\n+\t\tgit $config_str grep \"a+b*c\" $H ab >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n\nWe must leave $config_str unquoted (because we do want the string\nsplit at $IFS), but not quoting \"$expected_str\" looks a bit yucky\n(because we have no intention to let $IFS to split it).\n\n+}\n+\n\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE -c grep.extendedRegexp=false\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE -c grep.extendedRegexp=true\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE -c grep.patternType=basic\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE -c grep.patternType=extended\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" FIX -c grep.patternType=fixed\n \nThis part demonstrates the beauty of the new helper very well ;-)\n\ns/FIX/FIXED/ would be more grammatically correct.  It would break\nalignment above and I suspect that was why the patch chose to say\n\"FIX\" instead, but I am not sure if the alignment here is so\nvaluable.\n\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.patternType=default \\\n+\t\t-c grep.extendedRegexp=true\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.patternType=default\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.patternType=extended \\\n+\t\t-c grep.extendedRegexp=false\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE \\\n+\t\t-c grep.patternType=basic \\\n+\t\t-c grep.extendedRegexp=true\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.extendedRegexp=false \\\n+\t\t-c grep.patternType=extended\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.patternType=basic\n\nOK.  A bit redundant, knowing the implementation that parses the two\nvariables independently just like any other two variables, but these\nare correct, which counts even more ;-).\n\n+\t# grep.extendedRegexp is last-one-wins\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.extendedRegexp=false\n+\n+\t# grep.patternType=basic pays no attention to grep.extendedRegexp\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.patternType=basic \\\n+\t\t-c grep.extendedRegexp=false\n+\n+\t# grep.patternType=extended pays no attention to grep.extendedRegexp\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.patternType=extended \\\n+\t\t-c grep.extendedRegexp=false\n\nAll correct.\n\n+\t# grep.extendedRegexp is used with a last-one-wins grep.patternType=default\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.patternType=fixed \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.patternType=default\n\nNice.\n\n+\t# grep.extendedRegexp is used with earlier grep.patternType=default\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.extendedRegexp=false \\\n+\t\t-c grep.patternType=default \\\n+\t\t-c grep.extendedRegexp=true\n\nOK.  I would have expected \"the last\" instead of \"earlier\".  Because\nthese two variables are independently \"the last one wins\", just like\nany two variables that are \"the last one wins\", the relative order\nof their appearance does not matter.\n\n+\t# grep.extendedRegexp is used with a last-one-loses grep.patternType=default\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" ERE \\\n+\t\t-c grep.extendedRegexp=false \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.patternType=default\n\nI am not sure what last-one-loses mean here.  Both variables are\nindependently last-one-wins, so at the end of the parsing,\ngrep.extendedRegexp has 'true' (because it is the last value seen\nfor the variable) while grep.patternType has 'default' (again, it is\nthe last value seen for the variable).\n\n+\t# grep.extendedRegexp and grep.patternType are both last-one-wins independently\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE \\\n+\t\t-c grep.patternType=default \\\n+\t\t-c grep.extendedRegexp=true \\\n+\t\t-c grep.patternType=basic\n\nThe title of this one gets the gist of the mistakes in the code in\nearlier rounds.\n\n+\t# grep.patternType=extended and grep.patternType=default\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" BRE \\\n+\t\t-c grep.patternType=extended \\\n+\t\t-c grep.patternType=default\n+\n+\t# grep.patternType=[extended -> default -> fixed] (BRE)\" '\n+\ttest_pattern_type \"$H\" \"$HC\" \"$L\" FIX \\\n+\t\t-c grep.patternType=extended \\\n+\t\t-c grep.patternType=default \\\n+\t\t-c grep.patternType=fixed\n \nOK.\n\n \ttest_expect_success \"grep --count $L\" '\n \t\techo ${HC}ab:3 >expected &&\n"},{"id":"450364","messageId":"20220304085719.yht6hiuybhgfd6vo@fs","threadId":"56853","inReplyTo":"patch-v3-2.7-ec8e42ced1a-20211129T143956Z-avarab@gmail.com","subject":"Tests in t4202 are aborted early, was: Re: [PATCH v3 2/7] log","fromName":"Fabian Stelzer","fromEmail":"fs@gigacodes.de","sentAt":"2022-03-04T08:57:19Z","receivedAt":"2022-03-04T08:57:28Z","isPatch":true,"sender":{"key":"fs@gigacodes.de","avatar":"https://avatars.githubusercontent.com/u/564858?v=4"},"body":"On 29.11.2021 15:50, Ævar Arnfjörð Bjarmason wrote:\n>Extend the tests added in my 9df46763ef1 (log: add exhaustive tests\n>for pattern style options & config, 2017-05-20) to check not only\n>whether \"git log\" handles \"grep.patternType\", but also \"git show\"\n>etc.\n>\n>It's sufficient to check whether we match a \"fixed\" or a \"basic\" regex\n>here to see if these codepaths correctly invoked grep_config(). We\n>don't need to check the details of their regular expression matching\n>as the \"log\" test does.\n>\n>Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>---\n> t/t4202-log.sh | 24 ++++++++++++++++++++++++\n> 1 file changed, 24 insertions(+)\n>\n>diff --git a/t/t4202-log.sh b/t/t4202-log.sh\n>index 7884e3d46b3..11bb25440b0 100755\n>--- a/t/t4202-log.sh\n>+++ b/t/t4202-log.sh\n>@@ -449,6 +449,30 @@ test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurati\n> \t)\n> '\n>\n>+for cmd in show whatchanged reflog format-patch\n>+do\n>+\tcase \"$cmd\" in\n>+\tformat-patch) myarg=\"HEAD~..\" ;;\n>+\t*) myarg= ;;\n>+\tesac\n>+\n>+\ttest_expect_success \"$cmd: understands grep.patternType, like 'log'\" '\n>+\t\tgit init \"pattern-type-$cmd\" &&\n>+\t\t(\n>+\t\t\tcd \"pattern-type-$cmd\" &&\n>+\t\t\ttest_commit 1 file A &&\n>+\t\t\ttest_commit \"(1|2)\" file B 2 &&\n>+\n>+\t\t\tgit -c grep.patternType=fixed $cmd --grep=\"...\" $myarg >actual &&\n>+\t\t\ttest_must_be_empty actual &&\n>+\n>+\t\t\tgit -c grep.patternType=basic $cmd --grep=\"...\" $myarg >actual &&\n>+\t\t\ttest_file_not_empty actual\n>+\t\t)\n>+\t'\n>+done\n>+test_done\n\nAfter rebasing my work from <20220302090250.590450-1-fs@gigacodes.de> on \nmaster I was a bit confused as to why my tests in t4202 were no longer \nexecuting and none of my changes did anything about it. I suppose this \n`test_done` is left over from testing and slipped into master?\n\n>+\n> test_expect_success 'log --author' '\n> \tcat >expect <<-\\EOF &&\n> \tAuthor: <BOLD;RED>A U<RESET> Thor <author@example.com>\n>-- \n>2.34.1.841.gf15fb7e6f34\n>\n"},{"id":"450367","messageId":"patch-1.1-3b41c1a26d4-20220304T093323Z-avarab@gmail.com","threadId":"56853","inReplyTo":"20220304085719.yht6hiuybhgfd6vo@fs","subject":"[PATCH] log tests: fix \"abort tests early\" regression in ff37a60c369","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-04T10:05:01Z","receivedAt":"2022-03-04T10:05:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix a regression in ff37a60c369 (log tests: check if grep_config() is\ncalled by \"log\"-like cmds, 2022-02-16), a \"test_done\" command used\nduring development made it into a submitted patch causing tests 41-136\nin t/t4202-log.sh to be skipped.\n\nReported-by: Fabian Stelzer <fs@gigacodes.de>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n\nOn Fri, Mar 04 2022, Fabian Stelzer wrote:\n\n> After rebasing my work from <20220302090250.590450-1-fs@gigacodes.de>\n> on master I was a bit confused as to why my tests in t4202 were no\n> longer executing and none of my changes did anything about it. I\n> suppose this `test_done` is left over from testing and slipped into\n> master?\n\nOuch! Yes, that's a rather obvious stupid mistake of mine that\nshouldn't have escaped the lab. Sorry!\n\nFWIW since we haven't run these tests in a while (not too long\nthough!) it's conceivable that CI would fail on them, but in addition\nto passing locally here's passing CI for this change:\nhttps://github.com/avar/git/runs/5420131756\n\nSo we should be OK with this change.\n\n t/t4202-log.sh | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex 55fac644464..46e413bcc93 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -484,7 +484,6 @@ do\n \t\t)\n \t'\n done\n-test_done\n \n test_expect_success 'log --author' '\n \tcat >expect <<-\\EOF &&\n-- \n2.35.1.1230.ga6e6579e98c\n\n"}]}