git: 1594084f3fa8 - main - man(1): Add full search (-K) flag

From: Fernando Apesteguía <fernape_at_FreeBSD.org>
Date: Wed, 26 Jan 2022 11:28:02 UTC
The branch main has been updated by fernape (doc, ports committer):

URL: https://cgit.FreeBSD.org/src/commit/?id=1594084f3fa8daf95c0d8cdbd6487939506e268a

commit 1594084f3fa8daf95c0d8cdbd6487939506e268a
Author:     Fernando Apesteguía <fernape@FreeBSD.org>
AuthorDate: 2022-01-25 12:12:27 +0000
Commit:     Fernando Apesteguía <fernape@FreeBSD.org>
CommitDate: 2022-01-26 11:24:20 +0000

    man(1): Add full search (-K) flag
    
    This flag allows a full text search on man pages. Although this is a last resort
    option, it can be useful to pin point a certain man page.
    
    It can be used with -S to narrow the search.
    
    Unlike the Linux version, the search takes place in the rendered text so it
    avoids false-positives when the text is found in comments in the source files.
    
    It relies on `grep(1)` and `mandoc(1)` to do its job.
    
    Add flag documentation and EXAMPLES to the manual page (bump .Dd).
    
    Usage example:
    
    man -w -K '\<arm\>' -S 1:8
    
    Reviewed By: ceri, emaste, pauamma_gundo.com
    Approved by: manpages (bcr@), debdrup@
    Differential Revision: https://reviews.freebsd.org/D30984
---
 usr.bin/man/man.1  | 19 ++++++++++++++++++-
 usr.bin/man/man.sh | 49 +++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 63 insertions(+), 5 deletions(-)

diff --git a/usr.bin/man/man.1 b/usr.bin/man/man.1
index 42fd60a86164..9a611eff3005 100644
--- a/usr.bin/man/man.1
+++ b/usr.bin/man/man.1
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 9, 2021
+.Dd January 26, 2022
 .Dt MAN 1
 .Os
 .Sh NAME
@@ -43,6 +43,9 @@
 .Op Ar mansect
 .Ar page ...
 .Nm
+.Fl K
+.Ar regexp ...
+.Nm
 .Fl f
 .Ar keyword ...
 .Nm
@@ -93,6 +96,14 @@ Options that
 .Nm
 understands:
 .Bl -tag -width indent
+.It Fl K Ar regexp
+Does a full text search in all manual pages.
+.Ar regexp
+is a regular expression as understood by
+.Dq Li "grep -E" .
+This option requires
+.Xr mandoc 1 .
+This is a slow operation.
 .It Fl M Ar manpath
 Forces a specific colon separated manual path instead of the default
 search path.
@@ -392,8 +403,14 @@ manual page:
 $ man -w ls
 .Ed
 .Pp
+Show the location of manual pages in sections 1 and 8 which contain the word
+.Ql arm :
+.Bd -literal -offset indent
+$ ./man -w -K '\e<arm\e>' -S 1:8
+.Ed
 .Sh SEE ALSO
 .Xr apropos 1 ,
+.Xr egrep 1 ,
 .Xr intro 1 ,
 .Xr mandoc 1 ,
 .Xr manpath 1 ,
diff --git a/usr.bin/man/man.sh b/usr.bin/man/man.sh
index 084f4a06829b..2c2f1bf648de 100755
--- a/usr.bin/man/man.sh
+++ b/usr.bin/man/man.sh
@@ -548,8 +548,10 @@ man_parse_args() {
 	local IFS cmd_arg
 
 	OPTIND=1
-	while getopts 'M:P:S:adfhkm:op:tw' cmd_arg; do
+	while getopts 'K:M:P:S:adfhkm:op:tw' cmd_arg; do
 		case "${cmd_arg}" in
+		K)	Kflag=Kflag
+			REGEXP=$OPTARG ;;
 		M)	MANPATH=$OPTARG ;;
 		P)	MANPAGER=$OPTARG ;;
 		S)	MANSECT=$OPTARG ;;
@@ -570,7 +572,11 @@ man_parse_args() {
 	shift $(( $OPTIND - 1 ))
 
 	# Check the args for incompatible options.
-	case "${fflag}${kflag}${tflag}${wflag}" in
+
+	case "${Kflag}${fflag}${kflag}${tflag}${wflag}" in
+	Kflagfflag*)	echo "Incompatible options: -K and -f"; man_usage ;;
+	Kflag*kflag*)	echo "Incompatible options: -K and -k"; man_usage ;;
+	Kflag*tflag)	echo "Incompatible options: -K and -t"; man_usage ;;
 	fflagkflag*)	echo "Incompatible options: -f and -k"; man_usage ;;
 	fflag*tflag*)	echo "Incompatible options: -f and -t"; man_usage ;;
 	fflag*wflag)	echo "Incompatible options: -f and -w"; man_usage ;;
@@ -711,7 +717,7 @@ man_setup_locale() {
 # Display usage for the man utility.
 man_usage() {
 	echo 'Usage:'
-	echo ' man [-adho] [-t | -w] [-M manpath] [-P pager] [-S mansect]'
+	echo ' man [-adho] [-t | -w] [-K regexp] [-M manpath] [-P pager] [-S mansect]'
 	echo '     [-m arch[:machine]] [-p [eprtv]] [mansect] page [...]'
 	echo ' man -f page [...] -- Emulates whatis(1)'
 	echo ' man -k page [...] -- Emulates apropos(1)'
@@ -965,14 +971,49 @@ do_apropos() {
 	search_whatis apropos "$@"
 }
 
+# Usage: do_full_search reg_exp
+# Do a full search of the regular expression passed
+# as parameter in all man pages
+do_full_search() {
+	local gflags re
+	re=${1}
+
+	# Build grep(1) flags
+	gflags="-H"
+
+	# wflag implies -l for grep(1)
+	if [ -n "$wflag" ]; then
+		gflags="${gflags} -l"
+	fi
+
+	gflags="${gflags} --label"
+
+	set +f
+	for mpath in $(echo "${MANPATH}" | tr : [:blank:]); do
+		for section in $(echo "${MANSECT}" | tr : [:blank:]); do
+			for manfile in ${mpath}/man${section}/*.${section}*; do
+				mandoc "${manfile}" 2>/dev/null |
+					grep -E ${gflags} "${manfile}" -e ${re}
+			done
+		done
+	done
+	set -f
+}
+
 do_man() {
 	man_parse_args "$@"
-	if [ -z "$pages" ]; then
+	if [ -z "$pages" -a -z "${Kflag}" ]; then
 		echo 'What manual page do you want?' >&2
 		exit 1
 	fi
 	man_setup
 
+	if [ ! -z "${Kflag}" ]; then
+		# Short circuit because -K flag does a sufficiently
+		# different thing like not showing the man page at all
+		do_full_search "${REGEXP}"
+	fi
+
 	for page in $pages; do
 		decho "Searching for $page"
 		man_find_and_display "$page"