From owner-dev-commits-src-all@freebsd.org Mon Feb 8 18:41:28 2021 Return-Path: Delivered-To: dev-commits-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 1ED5253CBE7; Mon, 8 Feb 2021 18:41:28 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4DZFGw0Qcdz4fN0; Mon, 8 Feb 2021 18:41:28 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 007DF1C369; Mon, 8 Feb 2021 18:41:28 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 118IfRXW024033; Mon, 8 Feb 2021 18:41:27 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 118IfRgO024032; Mon, 8 Feb 2021 18:41:27 GMT (envelope-from git) Date: Mon, 8 Feb 2021 18:41:27 GMT Message-Id: <202102081841.118IfRgO024032@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kyle Evans Subject: git: 3e2d96ac974d - main - grep: fix -A handling in conjunction with -m match limitation MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kevans X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 3e2d96ac974db823255a6f40b90eeffa6e38d022 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-all@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for all branches of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 08 Feb 2021 18:41:28 -0000 The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=3e2d96ac974db823255a6f40b90eeffa6e38d022 commit 3e2d96ac974db823255a6f40b90eeffa6e38d022 Author: Kyle Evans AuthorDate: 2021-02-08 18:31:17 +0000 Commit: Kyle Evans CommitDate: 2021-02-08 18:41:22 +0000 grep: fix -A handling in conjunction with -m match limitation The basic issue here is that grep, when given -m 1, would stop all line processing once it hit the match count and exit immediately. The problem with exiting immediately is that -A processing only happens when subsequent lines are processed and do not match. The fix here is relatively easy; when bsdgrep matches a line, it resets the 'tail' of the matching context to the value supplied to -A and dumps anything that's been queued up for -B. After the current line has been printed and tail is reset, we check our mcount and do what's needed. Therefore, at the time that we decide we're doing nothing, we know that 'tail' of the context is correct and we can simply continue on if there's still more to pick up. With this change, we still bail out immediately if there's been no -A flag. If -A was supplied, we signal that we should continue on. However, subsequent lines will not even bothere to try and process the line. We have reached the match count, so even if the next line would match then we must process it if it hadn't. Thus, the loop in procfile() can short-circuit and just process the line as a non-match until procmatches() indicates that it's safe to stop. A test has been added to reflect both that we should be picking up the next line and that the next line should be considered a non-match even if it should have been. PR: 253350 MFC-after: 3 days --- contrib/netbsd-tests/usr.bin/grep/t_grep.sh | 17 +++++++++++++++++ usr.bin/grep/util.c | 21 ++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/contrib/netbsd-tests/usr.bin/grep/t_grep.sh b/contrib/netbsd-tests/usr.bin/grep/t_grep.sh index ef3f0617465e..d2539a8250de 100755 --- a/contrib/netbsd-tests/usr.bin/grep/t_grep.sh +++ b/contrib/netbsd-tests/usr.bin/grep/t_grep.sh @@ -907,6 +907,22 @@ mflag_body() atf_check -o inline:"test1:2\n" grep -m 2 -EHc "a|b|e|f" test1 } +atf_test_case mflag_trail_ctx +mflag_trail_ctx_head() +{ + atf_set "descr" "Check proper handling of -m with trailing context (PR 253350)" +} +mflag_trail_ctx_body() +{ + printf "foo\nfoo\nbar\nfoo\nbar\nfoo\nbar\n" > test1 + + # Should pick up the next line after matching the first. + atf_check -o inline:"foo\nfoo\n" grep -A1 -m1 foo test1 + + # Make sure the trailer is picked up as a non-match! + atf_check -o inline:"1:foo\n2-foo\n" grep -A1 -nm1 foo test1 +} + atf_test_case zgrep_multiple_files zgrep_multiple_files_head() { @@ -978,6 +994,7 @@ atf_init_test_cases() atf_add_test_case fgrep_oflag atf_add_test_case cflag atf_add_test_case mflag + atf_add_test_case mflag_trail_ctx atf_add_test_case zgrep_multiple_files # End FreeBSD } diff --git a/usr.bin/grep/util.c b/usr.bin/grep/util.c index f22b7abd79ef..a2520e24de8e 100644 --- a/usr.bin/grep/util.c +++ b/usr.bin/grep/util.c @@ -252,6 +252,16 @@ static bool procmatches(struct mprintc *mc, struct parsec *pc, bool matched) { + if (mflag && mcount <= 0) { + /* + * We already hit our match count, but we need to keep dumping + * lines until we've lost our tail. + */ + grep_printline(&pc->ln, '-'); + mc->tail--; + return (mc->tail != 0); + } + /* * XXX TODO: This should loop over pc->matches and handle things on a * line-by-line basis, setting up a `struct str` as needed. @@ -265,7 +275,7 @@ procmatches(struct mprintc *mc, struct parsec *pc, bool matched) /* XXX TODO: Decrement by number of matched lines */ mcount -= 1; if (mcount <= 0) - return (false); + return (mc->tail != 0); } } else if (mc->doctx) procmatch_nomatch(mc, pc); @@ -357,6 +367,15 @@ procfile(const char *fn) return (0); } + if (mflag && mcount <= 0) { + /* + * Short-circuit, already hit match count and now we're + * just picking up any remaining pieces. + */ + if (!procmatches(&mc, &pc, false)) + break; + continue; + } line_matched = procline(&pc) == !vflag; if (line_matched) ++lines;