xref: /freebsd/usr.bin/man/man.sh (revision b8a484ec343d163a40f7cf4a6026e880f992c738)
1c535eb59SGordon Tetlow#! /bin/sh
2c535eb59SGordon Tetlow#
34d846d26SWarner Losh# SPDX-License-Identifier: BSD-2-Clause
41de7b4b8SPedro F. Giffuni#
5c535eb59SGordon Tetlow#  Copyright (c) 2010 Gordon Tetlow
6c535eb59SGordon Tetlow#  All rights reserved.
7c535eb59SGordon Tetlow#
8c535eb59SGordon Tetlow#  Redistribution and use in source and binary forms, with or without
9c535eb59SGordon Tetlow#  modification, are permitted provided that the following conditions
10c535eb59SGordon Tetlow#  are met:
11c535eb59SGordon Tetlow#  1. Redistributions of source code must retain the above copyright
12c535eb59SGordon Tetlow#     notice, this list of conditions and the following disclaimer.
13c535eb59SGordon Tetlow#  2. Redistributions in binary form must reproduce the above copyright
14c535eb59SGordon Tetlow#     notice, this list of conditions and the following disclaimer in the
15c535eb59SGordon Tetlow#     documentation and/or other materials provided with the distribution.
16c535eb59SGordon Tetlow#
17c535eb59SGordon Tetlow#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18c535eb59SGordon Tetlow#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19c535eb59SGordon Tetlow#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20c535eb59SGordon Tetlow#  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21c535eb59SGordon Tetlow#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22c535eb59SGordon Tetlow#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23c535eb59SGordon Tetlow#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24c535eb59SGordon Tetlow#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25c535eb59SGordon Tetlow#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26c535eb59SGordon Tetlow#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27c535eb59SGordon Tetlow#  SUCH DAMAGE.
28c535eb59SGordon Tetlow#
29c535eb59SGordon Tetlow
30433c5a8aSWolfram Schneider# Rendering a manual page is fast. Even a manual page several 100k in size
31433c5a8aSWolfram Schneider# takes less than a CPU second. If it takes much longer, it is very likely
32433c5a8aSWolfram Schneider# that a tool like mandoc(1) is running in an infinite loop. In this case
33433c5a8aSWolfram Schneider# it is better to terminate it.
34433c5a8aSWolfram Schneiderulimit -t 20
35433c5a8aSWolfram Schneider
36c535eb59SGordon Tetlow# Usage: add_to_manpath path
37c535eb59SGordon Tetlow# Adds a variable to manpath while ensuring we don't have duplicates.
38c535eb59SGordon Tetlow# Returns true if we were able to add something. False otherwise.
39c535eb59SGordon Tetlowadd_to_manpath() {
40c535eb59SGordon Tetlow	case "$manpath" in
41c535eb59SGordon Tetlow	*:$1)	decho "  Skipping duplicate manpath entry $1" 2 ;;
42c535eb59SGordon Tetlow	$1:*)	decho "  Skipping duplicate manpath entry $1" 2 ;;
43c535eb59SGordon Tetlow	*:$1:*)	decho "  Skipping duplicate manpath entry $1" 2 ;;
44c535eb59SGordon Tetlow	*)	if [ -d "$1" ]; then
45c535eb59SGordon Tetlow			decho "  Adding $1 to manpath"
46c535eb59SGordon Tetlow			manpath="$manpath:$1"
47c535eb59SGordon Tetlow			return 0
48c535eb59SGordon Tetlow		fi
49c535eb59SGordon Tetlow		;;
50c535eb59SGordon Tetlow	esac
51c535eb59SGordon Tetlow
52c535eb59SGordon Tetlow	return 1
53c535eb59SGordon Tetlow}
54c535eb59SGordon Tetlow
55c535eb59SGordon Tetlow# Usage: build_manlocales
56c535eb59SGordon Tetlow# Builds a correct MANLOCALES variable.
57c535eb59SGordon Tetlowbuild_manlocales() {
58c535eb59SGordon Tetlow	# If the user has set manlocales, who are we to argue.
59c535eb59SGordon Tetlow	if [ -n "$MANLOCALES" ]; then
60c535eb59SGordon Tetlow		return
61c535eb59SGordon Tetlow	fi
62c535eb59SGordon Tetlow
63c535eb59SGordon Tetlow	parse_configs
64c535eb59SGordon Tetlow
65c535eb59SGordon Tetlow	# Trim leading colon
66c535eb59SGordon Tetlow	MANLOCALES=${manlocales#:}
67c535eb59SGordon Tetlow
68c535eb59SGordon Tetlow	decho "Available manual locales: $MANLOCALES"
69c535eb59SGordon Tetlow}
70c535eb59SGordon Tetlow
718edb6fb5SMohamed Akram# Usage: build_mansect
728edb6fb5SMohamed Akram# Builds a correct MANSECT variable.
738edb6fb5SMohamed Akrambuild_mansect() {
748edb6fb5SMohamed Akram	# If the user has set mansect, who are we to argue.
758edb6fb5SMohamed Akram	if [ -n "$MANSECT" ]; then
768edb6fb5SMohamed Akram		return
778edb6fb5SMohamed Akram	fi
788edb6fb5SMohamed Akram
798edb6fb5SMohamed Akram	parse_configs
808edb6fb5SMohamed Akram
818edb6fb5SMohamed Akram	# Trim leading colon
828edb6fb5SMohamed Akram	MANSECT=${mansect#:}
838edb6fb5SMohamed Akram
848edb6fb5SMohamed Akram	if [ -z "$MANSECT" ]; then
858edb6fb5SMohamed Akram		MANSECT=$man_default_sections
868edb6fb5SMohamed Akram	fi
878edb6fb5SMohamed Akram	decho "Using manual sections: $MANSECT"
888edb6fb5SMohamed Akram}
898edb6fb5SMohamed Akram
90c535eb59SGordon Tetlow# Usage: build_manpath
91c535eb59SGordon Tetlow# Builds a correct MANPATH variable.
92c535eb59SGordon Tetlowbuild_manpath() {
93c535eb59SGordon Tetlow	local IFS
94c535eb59SGordon Tetlow
95c535eb59SGordon Tetlow	# If the user has set a manpath, who are we to argue.
96c535eb59SGordon Tetlow	if [ -n "$MANPATH" ]; then
97b2394e73SBaptiste Daroussin		case "$MANPATH" in
98b2394e73SBaptiste Daroussin		*:) PREPEND_MANPATH=${MANPATH} ;;
99b2394e73SBaptiste Daroussin		:*) APPEND_MANPATH=${MANPATH} ;;
100b2394e73SBaptiste Daroussin		*::*)
101b2394e73SBaptiste Daroussin			PREPEND_MANPATH=${MANPATH%%::*}
102b2394e73SBaptiste Daroussin			APPEND_MANPATH=${MANPATH#*::}
103b2394e73SBaptiste Daroussin			;;
104b2394e73SBaptiste Daroussin		*) return ;;
105b2394e73SBaptiste Daroussin		esac
106b2394e73SBaptiste Daroussin	fi
107b2394e73SBaptiste Daroussin
108b2394e73SBaptiste Daroussin	if [ -n "$PREPEND_MANPATH" ]; then
109b2394e73SBaptiste Daroussin		IFS=:
110b2394e73SBaptiste Daroussin		for path in $PREPEND_MANPATH; do
111b2394e73SBaptiste Daroussin			add_to_manpath "$path"
112b2394e73SBaptiste Daroussin		done
113b2394e73SBaptiste Daroussin		unset IFS
114c535eb59SGordon Tetlow	fi
115c535eb59SGordon Tetlow
116c535eb59SGordon Tetlow	search_path
117c535eb59SGordon Tetlow
118c535eb59SGordon Tetlow	decho "Adding default manpath entries"
119c535eb59SGordon Tetlow	IFS=:
120c535eb59SGordon Tetlow	for path in $man_default_path; do
121c535eb59SGordon Tetlow		add_to_manpath "$path"
122c535eb59SGordon Tetlow	done
123c535eb59SGordon Tetlow	unset IFS
124c535eb59SGordon Tetlow
125c535eb59SGordon Tetlow	parse_configs
126c535eb59SGordon Tetlow
127b2394e73SBaptiste Daroussin	if [ -n "$APPEND_MANPATH" ]; then
128b2394e73SBaptiste Daroussin		IFS=:
129b2394e73SBaptiste Daroussin		for path in $APPEND_MANPATH; do
130b2394e73SBaptiste Daroussin			add_to_manpath "$path"
131b2394e73SBaptiste Daroussin		done
132b2394e73SBaptiste Daroussin		unset IFS
133b2394e73SBaptiste Daroussin	fi
134c535eb59SGordon Tetlow	# Trim leading colon
135c535eb59SGordon Tetlow	MANPATH=${manpath#:}
136c535eb59SGordon Tetlow
137c535eb59SGordon Tetlow	decho "Using manual path: $MANPATH"
138c535eb59SGordon Tetlow}
139c535eb59SGordon Tetlow
140c535eb59SGordon Tetlow# Usage: check_cat catglob
141c535eb59SGordon Tetlow# Checks to see if a cat glob is available.
142c535eb59SGordon Tetlowcheck_cat() {
143c535eb59SGordon Tetlow	if exists "$1"; then
144c535eb59SGordon Tetlow		use_cat=yes
145c535eb59SGordon Tetlow		catpage=$found
146c4368d03SWolfram Schneider		setup_cattool "$catpage"
147c4368d03SWolfram Schneider		decho "    Found catpage \"$catpage\""
148c535eb59SGordon Tetlow		return 0
149c535eb59SGordon Tetlow	else
150c535eb59SGordon Tetlow		return 1
151c535eb59SGordon Tetlow	fi
152c535eb59SGordon Tetlow}
153c535eb59SGordon Tetlow
154c535eb59SGordon Tetlow# Usage: check_man manglob catglob
155c535eb59SGordon Tetlow# Given 2 globs, figures out if the manglob is available, if so, check to
156c535eb59SGordon Tetlow# see if the catglob is also available and up to date.
157c535eb59SGordon Tetlowcheck_man() {
158c535eb59SGordon Tetlow	if exists "$1"; then
159c535eb59SGordon Tetlow		# We have a match, check for a cat page
160c535eb59SGordon Tetlow		manpage=$found
16178948070SWolfram Schneider		setup_cattool "$manpage"
16278948070SWolfram Schneider		decho "    Found manpage \"$manpage\""
163c535eb59SGordon Tetlow
164a0094449SRuslan Ermilov		if [ -n "${use_width}" ]; then
165a0094449SRuslan Ermilov			# non-standard width
166a0094449SRuslan Ermilov			unset use_cat
167a0094449SRuslan Ermilov			decho "    Skipping catpage: non-standard page width"
16878948070SWolfram Schneider		elif exists "$2" && is_newer $found "$manpage"; then
169c535eb59SGordon Tetlow			# cat page found and is newer, use that
170c535eb59SGordon Tetlow			use_cat=yes
171c535eb59SGordon Tetlow			catpage=$found
172c4368d03SWolfram Schneider			setup_cattool "$catpage"
173c4368d03SWolfram Schneider			decho "    Using catpage \"$catpage\""
174c535eb59SGordon Tetlow		else
175c535eb59SGordon Tetlow			# no cat page or is older
176c535eb59SGordon Tetlow			unset use_cat
177c535eb59SGordon Tetlow			decho "    Skipping catpage: not found or old"
178c535eb59SGordon Tetlow		fi
179c535eb59SGordon Tetlow		return 0
180c535eb59SGordon Tetlow	fi
181c535eb59SGordon Tetlow
182c535eb59SGordon Tetlow	return 1
183c535eb59SGordon Tetlow}
184c535eb59SGordon Tetlow
185c535eb59SGordon Tetlow# Usage: decho "string" [debuglevel]
186c535eb59SGordon Tetlow# Echoes to stderr string prefaced with -- if high enough debuglevel.
187c535eb59SGordon Tetlowdecho() {
188c535eb59SGordon Tetlow	if [ $debug -ge ${2:-1} ]; then
189c535eb59SGordon Tetlow		echo "-- $1" >&2
190c535eb59SGordon Tetlow	fi
191c535eb59SGordon Tetlow}
192c535eb59SGordon Tetlow
193c535eb59SGordon Tetlow# Usage: exists glob
194e3c7b76fSWolfram Schneider#
195e3c7b76fSWolfram Schneider# Returns true if glob resolves to a real file and store the first
196e3c7b76fSWolfram Schneider# found filename in the variable $found
197c535eb59SGordon Tetlowexists() {
198c535eb59SGordon Tetlow	local IFS
199c535eb59SGordon Tetlow
200c535eb59SGordon Tetlow	# Don't accidentally inherit callers IFS (breaks perl manpages)
201c535eb59SGordon Tetlow	unset IFS
202c535eb59SGordon Tetlow
203c535eb59SGordon Tetlow	# Use some globbing tricks in the shell to determine if a file
204c535eb59SGordon Tetlow	# exists or not.
205c535eb59SGordon Tetlow	set +f
206e3c7b76fSWolfram Schneider	for file in "$1"*
207e3c7b76fSWolfram Schneider	do
208e3c7b76fSWolfram Schneider		if [ -r "$file" ]; then
209e3c7b76fSWolfram Schneider			found="$file"
210c535eb59SGordon Tetlow			set -f
211c535eb59SGordon Tetlow			return 0
212c535eb59SGordon Tetlow		fi
213e3c7b76fSWolfram Schneider	done
214e3c7b76fSWolfram Schneider	set -f
215c535eb59SGordon Tetlow
216c535eb59SGordon Tetlow	return 1
217c535eb59SGordon Tetlow}
218c535eb59SGordon Tetlow
219c535eb59SGordon Tetlow# Usage: find_file path section subdir pagename
220c535eb59SGordon Tetlow# Returns: true if something is matched and found.
221c535eb59SGordon Tetlow# Search the given path/section combo for a given page.
222c535eb59SGordon Tetlowfind_file() {
223c535eb59SGordon Tetlow	local manroot catroot mann man0 catn cat0
224c535eb59SGordon Tetlow
225c535eb59SGordon Tetlow	manroot="$1/man$2"
226c535eb59SGordon Tetlow	catroot="$1/cat$2"
227c535eb59SGordon Tetlow	if [ -n "$3" ]; then
228c535eb59SGordon Tetlow		manroot="$manroot/$3"
229c535eb59SGordon Tetlow		catroot="$catroot/$3"
230c535eb59SGordon Tetlow	fi
231c535eb59SGordon Tetlow
232625490e8SBaptiste Daroussin	if [ ! -d "$manroot" -a ! -d "$catroot" ]; then
233c535eb59SGordon Tetlow		return 1
234c535eb59SGordon Tetlow	fi
235c535eb59SGordon Tetlow	decho "  Searching directory $manroot" 2
236c535eb59SGordon Tetlow
237e3c7b76fSWolfram Schneider	mann="$manroot/$4.$2"
238e3c7b76fSWolfram Schneider	man0="$manroot/$4.0"
239e3c7b76fSWolfram Schneider	catn="$catroot/$4.$2"
240e3c7b76fSWolfram Schneider	cat0="$catroot/$4.0"
241c535eb59SGordon Tetlow
242c535eb59SGordon Tetlow	# This is the behavior as seen by the original man utility.
243c535eb59SGordon Tetlow	# Let's not change that which doesn't seem broken.
244c535eb59SGordon Tetlow	if check_man "$mann" "$catn"; then
245c535eb59SGordon Tetlow		return 0
246c535eb59SGordon Tetlow	elif check_man "$man0" "$cat0"; then
247c535eb59SGordon Tetlow		return 0
248c535eb59SGordon Tetlow	elif check_cat "$catn"; then
249c535eb59SGordon Tetlow		return 0
250c535eb59SGordon Tetlow	elif check_cat "$cat0"; then
251c535eb59SGordon Tetlow		return 0
252c535eb59SGordon Tetlow	fi
253c535eb59SGordon Tetlow
254c535eb59SGordon Tetlow	return 1
255c535eb59SGordon Tetlow}
256c535eb59SGordon Tetlow
257c535eb59SGordon Tetlow# Usage: is_newer file1 file2
258c535eb59SGordon Tetlow# Returns true if file1 is newer than file2 as calculated by mtime.
259c535eb59SGordon Tetlowis_newer() {
2609b61837aSUlrich Spörlein	if ! [ "$1" -ot "$2" ]; then
2619b61837aSUlrich Spörlein		decho "    mtime: $1 not older than $2" 3
262c535eb59SGordon Tetlow		return 0
263c535eb59SGordon Tetlow	else
264c535eb59SGordon Tetlow		decho "    mtime: $1 older than $2" 3
265c535eb59SGordon Tetlow		return 1
266c535eb59SGordon Tetlow	fi
267c535eb59SGordon Tetlow}
268c535eb59SGordon Tetlow
269c535eb59SGordon Tetlow# Usage: manpath_parse_args "$@"
270c535eb59SGordon Tetlow# Parses commandline options for manpath.
271c535eb59SGordon Tetlowmanpath_parse_args() {
272c535eb59SGordon Tetlow	local cmd_arg
273c535eb59SGordon Tetlow
274f555b39eSKyle Evans	OPTIND=1
275c535eb59SGordon Tetlow	while getopts 'Ldq' cmd_arg; do
276c535eb59SGordon Tetlow		case "${cmd_arg}" in
277c535eb59SGordon Tetlow		L)	Lflag=Lflag ;;
278c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
279c535eb59SGordon Tetlow		q)	qflag=qflag ;;
280c535eb59SGordon Tetlow		*)	manpath_usage ;;
281c535eb59SGordon Tetlow		esac
282c535eb59SGordon Tetlow	done >&2
283c535eb59SGordon Tetlow}
284c535eb59SGordon Tetlow
285c535eb59SGordon Tetlow# Usage: manpath_usage
286c535eb59SGordon Tetlow# Display usage for the manpath(1) utility.
287c535eb59SGordon Tetlowmanpath_usage() {
288c535eb59SGordon Tetlow	echo 'usage: manpath [-Ldq]' >&2
289c535eb59SGordon Tetlow	exit 1
290c535eb59SGordon Tetlow}
291c535eb59SGordon Tetlow
292c535eb59SGordon Tetlow# Usage: manpath_warnings
293c535eb59SGordon Tetlow# Display some warnings to stderr.
294c535eb59SGordon Tetlowmanpath_warnings() {
295c535eb59SGordon Tetlow	if [ -n "$Lflag" -a -n "$MANLOCALES" ]; then
296c535eb59SGordon Tetlow		echo "(Warning: MANLOCALES environment variable set)" >&2
297c535eb59SGordon Tetlow	fi
298c535eb59SGordon Tetlow}
299c535eb59SGordon Tetlow
30057cd9717SGordon Tetlow# Usage: man_check_for_so page path
30157cd9717SGordon Tetlow# Returns: True if able to resolve the file, false if it ended in tears.
30257cd9717SGordon Tetlow# Detects the presence of the .so directive and causes the file to be
30357cd9717SGordon Tetlow# redirected to another source file.
30457cd9717SGordon Tetlowman_check_for_so() {
30557cd9717SGordon Tetlow	local IFS line tstr
30657cd9717SGordon Tetlow
30757cd9717SGordon Tetlow	unset IFS
308d9405a92SBaptiste Daroussin	if [ -n "$catpage" ]; then
309d9405a92SBaptiste Daroussin		return 0
310d9405a92SBaptiste Daroussin	fi
31157cd9717SGordon Tetlow
31257cd9717SGordon Tetlow	# We need to loop to accommodate multiple .so directives.
31357cd9717SGordon Tetlow	while true
31457cd9717SGordon Tetlow	do
315ec13a838SMohamed Akram		line=$($cattool "$manpage" | head -n1)
31657cd9717SGordon Tetlow		case "$line" in
31757cd9717SGordon Tetlow		.so*)	trim "${line#.so}"
31857cd9717SGordon Tetlow			decho "$manpage includes $tstr"
31957cd9717SGordon Tetlow			# Glob and check for the file.
320e3c7b76fSWolfram Schneider			if ! check_man "$path/$tstr" ""; then
32157cd9717SGordon Tetlow				decho "  Unable to find $tstr"
32257cd9717SGordon Tetlow				return 1
32357cd9717SGordon Tetlow			fi
32457cd9717SGordon Tetlow			;;
32557cd9717SGordon Tetlow		*)	break ;;
32657cd9717SGordon Tetlow		esac
32757cd9717SGordon Tetlow	done
32857cd9717SGordon Tetlow
32957cd9717SGordon Tetlow	return 0
33057cd9717SGordon Tetlow}
33157cd9717SGordon Tetlow
332b43edc06SBaptiste Daroussin# Usage: man_display_page
333b43edc06SBaptiste Daroussin# Display either the manpage or catpage depending on the use_cat variable
334c535eb59SGordon Tetlowman_display_page() {
3351fb816daSBaptiste Daroussin	local IFS pipeline testline
336c535eb59SGordon Tetlow
337c535eb59SGordon Tetlow	# We are called with IFS set to colon. This causes really weird
338c535eb59SGordon Tetlow	# things to happen for the variables that have spaces in them.
339c535eb59SGordon Tetlow	unset IFS
340c535eb59SGordon Tetlow
341c535eb59SGordon Tetlow	# If we are supposed to use a catpage and we aren't using troff(1)
342c535eb59SGordon Tetlow	# just zcat the catpage and we are done.
343c535eb59SGordon Tetlow	if [ -z "$tflag" -a -n "$use_cat" ]; then
344c535eb59SGordon Tetlow		if [ -n "$wflag" ]; then
34578948070SWolfram Schneider			echo "$catpage (source: \"$manpage\")"
346c535eb59SGordon Tetlow			ret=0
347c535eb59SGordon Tetlow		else
348c535eb59SGordon Tetlow			if [ $debug -gt 0 ]; then
349c4368d03SWolfram Schneider				decho "Command: $cattool \"$catpage\" | $MANPAGER"
350c535eb59SGordon Tetlow				ret=0
351c535eb59SGordon Tetlow			else
352*b8a484ecSWolfram Schneider				$cattool "$catpage" | $MANPAGER
353c535eb59SGordon Tetlow				ret=$?
354c535eb59SGordon Tetlow			fi
355c535eb59SGordon Tetlow		fi
356c535eb59SGordon Tetlow		return
357c535eb59SGordon Tetlow	fi
358c535eb59SGordon Tetlow
359c535eb59SGordon Tetlow	# Okay, we are using the manpage, do we just need to output the
360c535eb59SGordon Tetlow	# name of the manpage?
361c535eb59SGordon Tetlow	if [ -n "$wflag" ]; then
362c535eb59SGordon Tetlow		echo "$manpage"
363c535eb59SGordon Tetlow		ret=0
364c535eb59SGordon Tetlow		return
365c535eb59SGordon Tetlow	fi
366c535eb59SGordon Tetlow
367d433cf9aSBaptiste Daroussin	if [ -n "$use_width" ]; then
368d433cf9aSBaptiste Daroussin		mandoc_args="-O width=${use_width}"
369d433cf9aSBaptiste Daroussin	fi
370451c2becSBaptiste Daroussin	testline="mandoc -Tlint -Wunsupp >/dev/null 2>&1"
371449a792dSBaptiste Daroussin	if [ -n "$tflag" ]; then
372449a792dSBaptiste Daroussin		pipeline="mandoc -Tps $mandoc_args"
373449a792dSBaptiste Daroussin	else
374d433cf9aSBaptiste Daroussin		pipeline="mandoc $mandoc_args | $MANPAGER"
375449a792dSBaptiste Daroussin	fi
376d6096801SBaptiste Daroussin
377*b8a484ecSWolfram Schneider	if ! $cattool "$manpage" | eval "$testline"; then
378f17575acSBaptiste Daroussin		if which -s groff; then
379d6096801SBaptiste Daroussin			man_display_page_groff
380d6096801SBaptiste Daroussin		else
381d6096801SBaptiste Daroussin			echo "This manpage needs groff(1) to be rendered" >&2
382d6096801SBaptiste Daroussin			echo "First install groff(1): " >&2
383d6096801SBaptiste Daroussin			echo "pkg install groff " >&2
384d6096801SBaptiste Daroussin			ret=1
385d6096801SBaptiste Daroussin		fi
386d6096801SBaptiste Daroussin		return
387d6096801SBaptiste Daroussin	fi
388d6096801SBaptiste Daroussin
389d6096801SBaptiste Daroussin	if [ $debug -gt 0 ]; then
390*b8a484ecSWolfram Schneider		decho "Command: $cattool \"$manpage\" | eval \"$pipeline\""
391d6096801SBaptiste Daroussin		ret=0
392d6096801SBaptiste Daroussin	else
393*b8a484ecSWolfram Schneider		$cattool "$manpage" | eval "$pipeline"
394d6096801SBaptiste Daroussin		ret=$?
395d6096801SBaptiste Daroussin	fi
396d6096801SBaptiste Daroussin}
397d6096801SBaptiste Daroussin
398b43edc06SBaptiste Daroussin# Usage: man_display_page_groff
399b43edc06SBaptiste Daroussin# Display the manpage using groff
400d6096801SBaptiste Daroussinman_display_page_groff() {
401d6096801SBaptiste Daroussin	local EQN NROFF PIC TBL TROFF REFER VGRIND
402d6096801SBaptiste Daroussin	local IFS l nroff_dev pipeline preproc_arg tool
403d6096801SBaptiste Daroussin
404c535eb59SGordon Tetlow	# So, we really do need to parse the manpage. First, figure out the
405c535eb59SGordon Tetlow	# device flag (-T) we have to pass to eqn(1) and groff(1). Then,
406c535eb59SGordon Tetlow	# setup the pipeline of commands based on the user's request.
407c535eb59SGordon Tetlow
408deeff310SGordon Tetlow	# If the manpage is from a particular charset, we need to setup nroff
409deeff310SGordon Tetlow	# to properly output for the correct device.
410deeff310SGordon Tetlow	case "${manpage}" in
411deeff310SGordon Tetlow	*.${man_charset}/*)
412c535eb59SGordon Tetlow		# I don't pretend to know this; I'm just copying from the
413c535eb59SGordon Tetlow		# previous version of man(1).
414c535eb59SGordon Tetlow		case "$man_charset" in
415c535eb59SGordon Tetlow		KOI8-R)		nroff_dev="koi8-r" ;;
416c535eb59SGordon Tetlow		ISO8859-1)	nroff_dev="latin1" ;;
417c535eb59SGordon Tetlow		ISO8859-15)	nroff_dev="latin1" ;;
418c535eb59SGordon Tetlow		UTF-8)		nroff_dev="utf8" ;;
419c535eb59SGordon Tetlow		*)		nroff_dev="ascii" ;;
420c535eb59SGordon Tetlow		esac
421c535eb59SGordon Tetlow
422deeff310SGordon Tetlow		NROFF="$NROFF -T$nroff_dev"
423c535eb59SGordon Tetlow		EQN="$EQN -T$nroff_dev"
424c535eb59SGordon Tetlow
425deeff310SGordon Tetlow		# Iff the manpage is from the locale and not just the charset,
426deeff310SGordon Tetlow		# then we need to define the locale string.
427deeff310SGordon Tetlow		case "${manpage}" in
428deeff310SGordon Tetlow		*/${man_lang}_${man_country}.${man_charset}/*)
429deeff310SGordon Tetlow			NROFF="$NROFF -dlocale=$man_lang.$man_charset"
430deeff310SGordon Tetlow			;;
431deeff310SGordon Tetlow		*/${man_lang}.${man_charset}/*)
432deeff310SGordon Tetlow			NROFF="$NROFF -dlocale=$man_lang.$man_charset"
433deeff310SGordon Tetlow			;;
434deeff310SGordon Tetlow		esac
435deeff310SGordon Tetlow
436c535eb59SGordon Tetlow		# Allow language specific calls to override the default
437c535eb59SGordon Tetlow		# set of utilities.
438c535eb59SGordon Tetlow		l=$(echo $man_lang | tr [:lower:] [:upper:])
439b70e2025SRuslan Ermilov		for tool in EQN NROFF PIC TBL TROFF REFER VGRIND; do
440c535eb59SGordon Tetlow			eval "$tool=\${${tool}_$l:-\$$tool}"
441c535eb59SGordon Tetlow		done
442c535eb59SGordon Tetlow		;;
443c535eb59SGordon Tetlow	*)	NROFF="$NROFF -Tascii"
444c535eb59SGordon Tetlow		EQN="$EQN -Tascii"
445c535eb59SGordon Tetlow		;;
446c535eb59SGordon Tetlow	esac
447c535eb59SGordon Tetlow
448a6a3e856SRuslan Ermilov	if [ -z "$MANCOLOR" ]; then
449a6a3e856SRuslan Ermilov		NROFF="$NROFF -P-c"
450a6a3e856SRuslan Ermilov	fi
451a6a3e856SRuslan Ermilov
452a0094449SRuslan Ermilov	if [ -n "${use_width}" ]; then
453a0094449SRuslan Ermilov		NROFF="$NROFF -rLL=${use_width}n -rLT=${use_width}n"
454a0094449SRuslan Ermilov	fi
455a0094449SRuslan Ermilov
456c535eb59SGordon Tetlow	if [ -n "$MANROFFSEQ" ]; then
457c535eb59SGordon Tetlow		set -- -$MANROFFSEQ
458f555b39eSKyle Evans		OPTIND=1
459c535eb59SGordon Tetlow		while getopts 'egprtv' preproc_arg; do
460c535eb59SGordon Tetlow			case "${preproc_arg}" in
461c535eb59SGordon Tetlow			e)	pipeline="$pipeline | $EQN" ;;
462487ac9acSUlrich Spörlein			g)	;; # Ignore for compatibility.
463c535eb59SGordon Tetlow			p)	pipeline="$pipeline | $PIC" ;;
464c535eb59SGordon Tetlow			r)	pipeline="$pipeline | $REFER" ;;
465b70e2025SRuslan Ermilov			t)	pipeline="$pipeline | $TBL" ;;
466c535eb59SGordon Tetlow			v)	pipeline="$pipeline | $VGRIND" ;;
467c535eb59SGordon Tetlow			*)	usage ;;
468c535eb59SGordon Tetlow			esac
469c535eb59SGordon Tetlow		done
470c535eb59SGordon Tetlow		# Strip the leading " | " from the resulting pipeline.
471c535eb59SGordon Tetlow		pipeline="${pipeline#" | "}"
472c535eb59SGordon Tetlow	else
473c535eb59SGordon Tetlow		pipeline="$TBL"
474c535eb59SGordon Tetlow	fi
475c535eb59SGordon Tetlow
476c535eb59SGordon Tetlow	if [ -n "$tflag" ]; then
477c535eb59SGordon Tetlow		pipeline="$pipeline | $TROFF"
478c535eb59SGordon Tetlow	else
479a6a3e856SRuslan Ermilov		pipeline="$pipeline | $NROFF | $MANPAGER"
480c535eb59SGordon Tetlow	fi
481c535eb59SGordon Tetlow
482c535eb59SGordon Tetlow	if [ $debug -gt 0 ]; then
483*b8a484ecSWolfram Schneider		decho "Command: $cattool \"$manpage\" | eval \"$pipeline\""
484c535eb59SGordon Tetlow		ret=0
485c535eb59SGordon Tetlow	else
486*b8a484ecSWolfram Schneider		$cattool "$manpage" | eval "$pipeline"
487c535eb59SGordon Tetlow		ret=$?
488c535eb59SGordon Tetlow	fi
489c535eb59SGordon Tetlow}
490c535eb59SGordon Tetlow
491c535eb59SGordon Tetlow# Usage: man_find_and_display page
492c535eb59SGordon Tetlow# Search through the manpaths looking for the given page.
493c535eb59SGordon Tetlowman_find_and_display() {
494c535eb59SGordon Tetlow	local found_page locpath p path sect
495c535eb59SGordon Tetlow
4963d9127f1SGordon Tetlow	# Check to see if it's a file. But only if it has a '/' in
4973d9127f1SGordon Tetlow	# the filename.
4983d9127f1SGordon Tetlow	case "$1" in
4993d9127f1SGordon Tetlow	*/*)	if [ -f "$1" -a -r "$1" ]; then
5003d9127f1SGordon Tetlow			decho "Found a usable page, displaying that"
5013d9127f1SGordon Tetlow			unset use_cat
5023d9127f1SGordon Tetlow			manpage="$1"
50378948070SWolfram Schneider			setup_cattool "$manpage"
50478948070SWolfram Schneider			if man_check_for_so "$manpage" "$(dirname \"$manpage"")"; then
50557cd9717SGordon Tetlow				found_page=yes
5063d9127f1SGordon Tetlow				man_display_page
50757cd9717SGordon Tetlow			fi
5083d9127f1SGordon Tetlow			return
5093d9127f1SGordon Tetlow		fi
5103d9127f1SGordon Tetlow		;;
5113d9127f1SGordon Tetlow	esac
5123d9127f1SGordon Tetlow
513c535eb59SGordon Tetlow	IFS=:
514c535eb59SGordon Tetlow	for sect in $MANSECT; do
515c535eb59SGordon Tetlow		decho "Searching section $sect" 2
516c535eb59SGordon Tetlow		for path in $MANPATH; do
517c535eb59SGordon Tetlow			for locpath in $locpaths; do
518c535eb59SGordon Tetlow				p=$path/$locpath
519c535eb59SGordon Tetlow				p=${p%/.} # Rid ourselves of the trailing /.
520c535eb59SGordon Tetlow
521c535eb59SGordon Tetlow				# Check if there is a MACHINE specific manpath.
522c535eb59SGordon Tetlow				if find_file $p $sect $MACHINE "$1"; then
52378948070SWolfram Schneider					if man_check_for_so "$manpage" $p; then
524c535eb59SGordon Tetlow						found_page=yes
525c535eb59SGordon Tetlow						man_display_page
5261d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
5271d7c660aSGordon Tetlow							continue 2
5281d7c660aSGordon Tetlow						else
529c535eb59SGordon Tetlow							return
530c535eb59SGordon Tetlow						fi
531c535eb59SGordon Tetlow					fi
53257cd9717SGordon Tetlow				fi
533c535eb59SGordon Tetlow
534c535eb59SGordon Tetlow				# Check if there is a MACHINE_ARCH
535c535eb59SGordon Tetlow				# specific manpath.
536c535eb59SGordon Tetlow				if find_file $p $sect $MACHINE_ARCH "$1"; then
53778948070SWolfram Schneider					if man_check_for_so "$manpage" $p; then
538c535eb59SGordon Tetlow						found_page=yes
539c535eb59SGordon Tetlow						man_display_page
5401d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
5411d7c660aSGordon Tetlow							continue 2
5421d7c660aSGordon Tetlow						else
543c535eb59SGordon Tetlow							return
544c535eb59SGordon Tetlow						fi
545c535eb59SGordon Tetlow					fi
54657cd9717SGordon Tetlow				fi
547c535eb59SGordon Tetlow
548c535eb59SGordon Tetlow				# Check plain old manpath.
549c535eb59SGordon Tetlow				if find_file $p $sect '' "$1"; then
55078948070SWolfram Schneider					if man_check_for_so "$manpage" $p; then
551c535eb59SGordon Tetlow						found_page=yes
552c535eb59SGordon Tetlow						man_display_page
5531d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
5541d7c660aSGordon Tetlow							continue 2
5551d7c660aSGordon Tetlow						else
556c535eb59SGordon Tetlow							return
557c535eb59SGordon Tetlow						fi
558c535eb59SGordon Tetlow					fi
55957cd9717SGordon Tetlow				fi
560c535eb59SGordon Tetlow			done
561c535eb59SGordon Tetlow		done
562c535eb59SGordon Tetlow	done
563c535eb59SGordon Tetlow	unset IFS
564c535eb59SGordon Tetlow
565c535eb59SGordon Tetlow	# Nothing? Well, we are done then.
566c535eb59SGordon Tetlow	if [ -z "$found_page" ]; then
56778948070SWolfram Schneider		echo "No manual entry for \"$1\"" >&2
568c535eb59SGordon Tetlow		ret=1
569c535eb59SGordon Tetlow		return
570c535eb59SGordon Tetlow	fi
571c535eb59SGordon Tetlow}
572c535eb59SGordon Tetlow
5738edb6fb5SMohamed Akram# Usage: man_parse_opts "$@"
574c535eb59SGordon Tetlow# Parses commandline options for man.
5758edb6fb5SMohamed Akramman_parse_opts() {
5768edb6fb5SMohamed Akram	local cmd_arg
577c535eb59SGordon Tetlow
578f555b39eSKyle Evans	OPTIND=1
5791594084fSFernando Apesteguía	while getopts 'K:M:P:S:adfhkm:op:tw' cmd_arg; do
580c535eb59SGordon Tetlow		case "${cmd_arg}" in
5811594084fSFernando Apesteguía		K)	Kflag=Kflag
5821594084fSFernando Apesteguía			REGEXP=$OPTARG ;;
583c535eb59SGordon Tetlow		M)	MANPATH=$OPTARG ;;
584a6a3e856SRuslan Ermilov		P)	MANPAGER=$OPTARG ;;
585c535eb59SGordon Tetlow		S)	MANSECT=$OPTARG ;;
586c535eb59SGordon Tetlow		a)	aflag=aflag ;;
587c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
588c535eb59SGordon Tetlow		f)	fflag=fflag ;;
589c535eb59SGordon Tetlow		h)	man_usage 0 ;;
590c535eb59SGordon Tetlow		k)	kflag=kflag ;;
591c535eb59SGordon Tetlow		m)	mflag=$OPTARG ;;
592c535eb59SGordon Tetlow		o)	oflag=oflag ;;
593c535eb59SGordon Tetlow		p)	MANROFFSEQ=$OPTARG ;;
594c535eb59SGordon Tetlow		t)	tflag=tflag ;;
595c535eb59SGordon Tetlow		w)	wflag=wflag ;;
596c535eb59SGordon Tetlow		*)	man_usage ;;
597c535eb59SGordon Tetlow		esac
598c535eb59SGordon Tetlow	done >&2
599c535eb59SGordon Tetlow
600c535eb59SGordon Tetlow	shift $(( $OPTIND - 1 ))
601c535eb59SGordon Tetlow
602c535eb59SGordon Tetlow	# Check the args for incompatible options.
6031594084fSFernando Apesteguía
6041594084fSFernando Apesteguía	case "${Kflag}${fflag}${kflag}${tflag}${wflag}" in
6051594084fSFernando Apesteguía	Kflagfflag*)	echo "Incompatible options: -K and -f"; man_usage ;;
6061594084fSFernando Apesteguía	Kflag*kflag*)	echo "Incompatible options: -K and -k"; man_usage ;;
6071594084fSFernando Apesteguía	Kflag*tflag)	echo "Incompatible options: -K and -t"; man_usage ;;
608c535eb59SGordon Tetlow	fflagkflag*)	echo "Incompatible options: -f and -k"; man_usage ;;
609c535eb59SGordon Tetlow	fflag*tflag*)	echo "Incompatible options: -f and -t"; man_usage ;;
610c535eb59SGordon Tetlow	fflag*wflag)	echo "Incompatible options: -f and -w"; man_usage ;;
611c535eb59SGordon Tetlow	*kflagtflag*)	echo "Incompatible options: -k and -t"; man_usage ;;
612c535eb59SGordon Tetlow	*kflag*wflag)	echo "Incompatible options: -k and -w"; man_usage ;;
613c535eb59SGordon Tetlow	*tflagwflag)	echo "Incompatible options: -t and -w"; man_usage ;;
614c535eb59SGordon Tetlow	esac
615c535eb59SGordon Tetlow
616c535eb59SGordon Tetlow	# Short circuit for whatis(1) and apropos(1)
617c535eb59SGordon Tetlow	if [ -n "$fflag" ]; then
618c535eb59SGordon Tetlow		do_whatis "$@"
619c535eb59SGordon Tetlow		exit
620c535eb59SGordon Tetlow	fi
621c535eb59SGordon Tetlow
622c535eb59SGordon Tetlow	if [ -n "$kflag" ]; then
623c535eb59SGordon Tetlow		do_apropos "$@"
624c535eb59SGordon Tetlow		exit
625c535eb59SGordon Tetlow	fi
626c535eb59SGordon Tetlow}
627c535eb59SGordon Tetlow
628c535eb59SGordon Tetlow# Usage: man_setup
629c535eb59SGordon Tetlow# Setup various trivial but essential variables.
630c535eb59SGordon Tetlowman_setup() {
631c535eb59SGordon Tetlow	# Setup machine and architecture variables.
632c535eb59SGordon Tetlow	if [ -n "$mflag" ]; then
633c535eb59SGordon Tetlow		MACHINE_ARCH=${mflag%%:*}
634c535eb59SGordon Tetlow		MACHINE=${mflag##*:}
635c535eb59SGordon Tetlow	fi
636c535eb59SGordon Tetlow	if [ -z "$MACHINE_ARCH" ]; then
63782db8a5eSGordon Tetlow		MACHINE_ARCH=$($SYSCTL -n hw.machine_arch)
638c535eb59SGordon Tetlow	fi
639c535eb59SGordon Tetlow	if [ -z "$MACHINE" ]; then
64082db8a5eSGordon Tetlow		MACHINE=$($SYSCTL -n hw.machine)
641c535eb59SGordon Tetlow	fi
642c535eb59SGordon Tetlow	decho "Using architecture: $MACHINE_ARCH:$MACHINE"
643c535eb59SGordon Tetlow
644c535eb59SGordon Tetlow	setup_pager
645c535eb59SGordon Tetlow	build_manpath
6468edb6fb5SMohamed Akram	build_mansect
647c535eb59SGordon Tetlow	man_setup_locale
648a0094449SRuslan Ermilov	man_setup_width
649a0094449SRuslan Ermilov}
650a0094449SRuslan Ermilov
651a0094449SRuslan Ermilov# Usage: man_setup_width
652a0094449SRuslan Ermilov# Set up page width.
653a0094449SRuslan Ermilovman_setup_width() {
654a0094449SRuslan Ermilov	local sizes
655a0094449SRuslan Ermilov
656a0094449SRuslan Ermilov	unset use_width
657a0094449SRuslan Ermilov	case "$MANWIDTH" in
658a0094449SRuslan Ermilov	[0-9]*)
659a0094449SRuslan Ermilov		if [ "$MANWIDTH" -gt 0 2>/dev/null ]; then
660a0094449SRuslan Ermilov			use_width=$MANWIDTH
661a0094449SRuslan Ermilov		fi
662a0094449SRuslan Ermilov		;;
663a0094449SRuslan Ermilov	[Tt][Tt][Yy])
664a0094449SRuslan Ermilov		if { sizes=$($STTY size 0>&3 2>/dev/null); } 3>&1; then
665a0094449SRuslan Ermilov			set -- $sizes
666a0094449SRuslan Ermilov			if [ $2 -gt 80 ]; then
667a0094449SRuslan Ermilov				use_width=$(($2-2))
668a0094449SRuslan Ermilov			fi
669a0094449SRuslan Ermilov		fi
670a0094449SRuslan Ermilov		;;
671a0094449SRuslan Ermilov	esac
672a0094449SRuslan Ermilov	if [ -n "$use_width" ]; then
673a0094449SRuslan Ermilov		decho "Using non-standard page width: ${use_width}"
674a0094449SRuslan Ermilov	else
675a0094449SRuslan Ermilov		decho 'Using standard page width'
676a0094449SRuslan Ermilov	fi
677c535eb59SGordon Tetlow}
678c535eb59SGordon Tetlow
679c535eb59SGordon Tetlow# Usage: man_setup_locale
680c535eb59SGordon Tetlow# Setup necessary locale variables.
681c535eb59SGordon Tetlowman_setup_locale() {
682deeff310SGordon Tetlow	local lang_cc
6839508f8c0SYuri Pankov	local locstr
684deeff310SGordon Tetlow
685deeff310SGordon Tetlow	locpaths='.'
686deeff310SGordon Tetlow	man_charset='US-ASCII'
687deeff310SGordon Tetlow
688c535eb59SGordon Tetlow	# Setup locale information.
689c535eb59SGordon Tetlow	if [ -n "$oflag" ]; then
690deeff310SGordon Tetlow		decho 'Using non-localized manpages'
691deeff310SGordon Tetlow	else
6929508f8c0SYuri Pankov		# Use the locale tool to give us proper locale information
693deeff310SGordon Tetlow		eval $( $LOCALE )
694c535eb59SGordon Tetlow
6959508f8c0SYuri Pankov		if [ -n "$LANG" ]; then
6969508f8c0SYuri Pankov			locstr=$LANG
6979508f8c0SYuri Pankov		else
6989508f8c0SYuri Pankov			locstr=$LC_CTYPE
6999508f8c0SYuri Pankov		fi
7009508f8c0SYuri Pankov
7019508f8c0SYuri Pankov		case "$locstr" in
702deeff310SGordon Tetlow		C)		;;
7039508f8c0SYuri Pankov		C.UTF-8)	;;
704deeff310SGordon Tetlow		POSIX)		;;
705deeff310SGordon Tetlow		[a-z][a-z]_[A-Z][A-Z]\.*)
7069508f8c0SYuri Pankov				lang_cc="${locstr%.*}"
7079508f8c0SYuri Pankov				man_lang="${locstr%_*}"
708deeff310SGordon Tetlow				man_country="${lang_cc#*_}"
7099508f8c0SYuri Pankov				man_charset="${locstr#*.}"
7109508f8c0SYuri Pankov				locpaths="$locstr"
711c535eb59SGordon Tetlow				locpaths="$locpaths:$man_lang.$man_charset"
712c535eb59SGordon Tetlow				if [ "$man_lang" != "en" ]; then
713c535eb59SGordon Tetlow					locpaths="$locpaths:en.$man_charset"
714c535eb59SGordon Tetlow				fi
715c535eb59SGordon Tetlow				locpaths="$locpaths:."
716deeff310SGordon Tetlow				;;
717deeff310SGordon Tetlow		*)		echo 'Unknown locale, assuming C' >&2
718deeff310SGordon Tetlow				;;
719deeff310SGordon Tetlow		esac
720c535eb59SGordon Tetlow	fi
721deeff310SGordon Tetlow
722c535eb59SGordon Tetlow	decho "Using locale paths: $locpaths"
723c535eb59SGordon Tetlow}
724c535eb59SGordon Tetlow
725c535eb59SGordon Tetlow# Usage: man_usage [exitcode]
726c535eb59SGordon Tetlow# Display usage for the man utility.
727c535eb59SGordon Tetlowman_usage() {
728c535eb59SGordon Tetlow	echo 'Usage:'
7291594084fSFernando Apesteguía	echo ' man [-adho] [-t | -w] [-K regexp] [-M manpath] [-P pager] [-S mansect]'
730c535eb59SGordon Tetlow	echo '     [-m arch[:machine]] [-p [eprtv]] [mansect] page [...]'
731c535eb59SGordon Tetlow	echo ' man -f page [...] -- Emulates whatis(1)'
732c535eb59SGordon Tetlow	echo ' man -k page [...] -- Emulates apropos(1)'
733c535eb59SGordon Tetlow
734c535eb59SGordon Tetlow	# When exit'ing with -h, it's not an error.
735c535eb59SGordon Tetlow	exit ${1:-1}
736c535eb59SGordon Tetlow}
737c535eb59SGordon Tetlow
738c535eb59SGordon Tetlow# Usage: parse_configs
739c535eb59SGordon Tetlow# Reads the end-user adjustable config files.
740c535eb59SGordon Tetlowparse_configs() {
741c535eb59SGordon Tetlow	local IFS file files
742c535eb59SGordon Tetlow
743c535eb59SGordon Tetlow	if [ -n "$parsed_configs" ]; then
744c535eb59SGordon Tetlow		return
745c535eb59SGordon Tetlow	fi
746c535eb59SGordon Tetlow
747c535eb59SGordon Tetlow	unset IFS
748c535eb59SGordon Tetlow
749c535eb59SGordon Tetlow	# Read the global config first in case the user wants
750c535eb59SGordon Tetlow	# to override config_local.
751c535eb59SGordon Tetlow	if [ -r "$config_global" ]; then
752c535eb59SGordon Tetlow		parse_file "$config_global"
753c535eb59SGordon Tetlow	fi
754c535eb59SGordon Tetlow
755c535eb59SGordon Tetlow	# Glob the list of files to parse.
756c535eb59SGordon Tetlow	set +f
757c535eb59SGordon Tetlow	files=$(echo $config_local)
758c535eb59SGordon Tetlow	set -f
759c535eb59SGordon Tetlow
760c535eb59SGordon Tetlow	for file in $files; do
761c535eb59SGordon Tetlow		if [ -r "$file" ]; then
762c535eb59SGordon Tetlow			parse_file "$file"
763c535eb59SGordon Tetlow		fi
764c535eb59SGordon Tetlow	done
765c535eb59SGordon Tetlow
766c535eb59SGordon Tetlow	parsed_configs='yes'
767c535eb59SGordon Tetlow}
768c535eb59SGordon Tetlow
769c535eb59SGordon Tetlow# Usage: parse_file file
770c535eb59SGordon Tetlow# Reads the specified config files.
771c535eb59SGordon Tetlowparse_file() {
772c535eb59SGordon Tetlow	local file line tstr var
773c535eb59SGordon Tetlow
774c535eb59SGordon Tetlow	file="$1"
775c535eb59SGordon Tetlow	decho "Parsing config file: $file"
776c535eb59SGordon Tetlow	while read line; do
777c535eb59SGordon Tetlow		decho "  $line" 2
778c535eb59SGordon Tetlow		case "$line" in
779c535eb59SGordon Tetlow		\#*)		decho "    Comment" 3
780c535eb59SGordon Tetlow				;;
781c535eb59SGordon Tetlow		MANPATH*)	decho "    MANPATH" 3
782c535eb59SGordon Tetlow				trim "${line#MANPATH}"
783c535eb59SGordon Tetlow				add_to_manpath "$tstr"
784c535eb59SGordon Tetlow				;;
785c535eb59SGordon Tetlow		MANLOCALE*)	decho "    MANLOCALE" 3
786c535eb59SGordon Tetlow				trim "${line#MANLOCALE}"
787c535eb59SGordon Tetlow				manlocales="$manlocales:$tstr"
788c535eb59SGordon Tetlow				;;
789c535eb59SGordon Tetlow		MANCONFIG*)	decho "    MANCONFIG" 3
790a1528c80SRuslan Ermilov				trim "${line#MANCONFIG}"
791c535eb59SGordon Tetlow				config_local="$tstr"
792c535eb59SGordon Tetlow				;;
7938edb6fb5SMohamed Akram		MANSECT*)	decho "    MANSECT" 3
7948edb6fb5SMohamed Akram				trim "${line#MANSECT}"
7958edb6fb5SMohamed Akram				mansect="$mansect:$tstr"
7968edb6fb5SMohamed Akram				;;
797c535eb59SGordon Tetlow		# Set variables in the form of FOO_BAR
798c535eb59SGordon Tetlow		*_*[\ \	]*)	var="${line%%[\ \	]*}"
799c535eb59SGordon Tetlow				trim "${line#$var}"
800c535eb59SGordon Tetlow				eval "$var=\"$tstr\""
801c535eb59SGordon Tetlow				decho "    Parsed $var" 3
802c535eb59SGordon Tetlow				;;
803c535eb59SGordon Tetlow		esac
804c535eb59SGordon Tetlow	done < "$file"
805c535eb59SGordon Tetlow}
806c535eb59SGordon Tetlow
807c535eb59SGordon Tetlow# Usage: search_path
808c535eb59SGordon Tetlow# Traverse $PATH looking for manpaths.
809c535eb59SGordon Tetlowsearch_path() {
810c535eb59SGordon Tetlow	local IFS p path
811c535eb59SGordon Tetlow
812c535eb59SGordon Tetlow	decho "Searching PATH for man directories"
813c535eb59SGordon Tetlow
814c535eb59SGordon Tetlow	IFS=:
815c535eb59SGordon Tetlow	for path in $PATH; do
816971c1c42STijl Coosemans		if add_to_manpath "$path/man"; then
817c535eb59SGordon Tetlow			:
818c535eb59SGordon Tetlow		elif add_to_manpath "$path/MAN"; then
819c535eb59SGordon Tetlow			:
820c535eb59SGordon Tetlow		else
821c535eb59SGordon Tetlow			case "$path" in
822971c1c42STijl Coosemans			*/bin)	p="${path%/bin}/share/man"
823c535eb59SGordon Tetlow				add_to_manpath "$p"
824971c1c42STijl Coosemans				p="${path%/bin}/man"
82561d5f2d1SBaptiste Daroussin				add_to_manpath "$p"
826c535eb59SGordon Tetlow				;;
827c535eb59SGordon Tetlow			esac
828c535eb59SGordon Tetlow		fi
829c535eb59SGordon Tetlow	done
830c535eb59SGordon Tetlow	unset IFS
831c535eb59SGordon Tetlow
832c535eb59SGordon Tetlow	if [ -z "$manpath" ]; then
833c535eb59SGordon Tetlow		decho '  Unable to find any manpaths, using default'
834c535eb59SGordon Tetlow		manpath=$man_default_path
835c535eb59SGordon Tetlow	fi
836c535eb59SGordon Tetlow}
837c535eb59SGordon Tetlow
838c535eb59SGordon Tetlow# Usage: search_whatis cmd [arglist]
839c535eb59SGordon Tetlow# Do the heavy lifting for apropos/whatis
840c535eb59SGordon Tetlowsearch_whatis() {
841c535eb59SGordon Tetlow	local IFS bad cmd f good key keywords loc opt out path rval wlist
842c535eb59SGordon Tetlow
843c535eb59SGordon Tetlow	cmd="$1"
844c535eb59SGordon Tetlow	shift
845c535eb59SGordon Tetlow
846c535eb59SGordon Tetlow	whatis_parse_args "$@"
847c535eb59SGordon Tetlow
848c535eb59SGordon Tetlow	build_manpath
849c535eb59SGordon Tetlow	build_manlocales
850c535eb59SGordon Tetlow	setup_pager
851c535eb59SGordon Tetlow
852c535eb59SGordon Tetlow	if [ "$cmd" = "whatis" ]; then
853c535eb59SGordon Tetlow		opt="-w"
854c535eb59SGordon Tetlow	fi
855c535eb59SGordon Tetlow
856c535eb59SGordon Tetlow	f='whatis'
857c535eb59SGordon Tetlow
858c535eb59SGordon Tetlow	IFS=:
859c535eb59SGordon Tetlow	for path in $MANPATH; do
860c535eb59SGordon Tetlow		if [ \! -d "$path" ]; then
861c535eb59SGordon Tetlow			decho "Skipping non-existent path: $path" 2
862c535eb59SGordon Tetlow			continue
863c535eb59SGordon Tetlow		fi
864c535eb59SGordon Tetlow
865c535eb59SGordon Tetlow		if [ -f "$path/$f" -a -r "$path/$f" ]; then
866c535eb59SGordon Tetlow			decho "Found whatis: $path/$f"
867c535eb59SGordon Tetlow			wlist="$wlist $path/$f"
868c535eb59SGordon Tetlow		fi
869c535eb59SGordon Tetlow
870c535eb59SGordon Tetlow		for loc in $MANLOCALES; do
871c535eb59SGordon Tetlow			if [ -f "$path/$loc/$f" -a -r "$path/$loc/$f" ]; then
872c535eb59SGordon Tetlow				decho "Found whatis: $path/$loc/$f"
873c535eb59SGordon Tetlow				wlist="$wlist $path/$loc/$f"
874c535eb59SGordon Tetlow			fi
875c535eb59SGordon Tetlow		done
876c535eb59SGordon Tetlow	done
877c535eb59SGordon Tetlow	unset IFS
878c535eb59SGordon Tetlow
879c535eb59SGordon Tetlow	if [ -z "$wlist" ]; then
880c535eb59SGordon Tetlow		echo "$cmd: no whatis databases in $MANPATH" >&2
881c535eb59SGordon Tetlow		exit 1
882c535eb59SGordon Tetlow	fi
883c535eb59SGordon Tetlow
884c535eb59SGordon Tetlow	rval=0
885c535eb59SGordon Tetlow	for key in $keywords; do
886c535eb59SGordon Tetlow		out=$(grep -Ehi $opt -- "$key" $wlist)
887c535eb59SGordon Tetlow		if [ -n "$out" ]; then
888c535eb59SGordon Tetlow			good="$good\\n$out"
889c535eb59SGordon Tetlow		else
890c535eb59SGordon Tetlow			bad="$bad\\n$key: nothing appropriate"
891c535eb59SGordon Tetlow			rval=1
892c535eb59SGordon Tetlow		fi
893c535eb59SGordon Tetlow	done
894c535eb59SGordon Tetlow
895c535eb59SGordon Tetlow	# Strip leading carriage return.
896c535eb59SGordon Tetlow	good=${good#\\n}
897c535eb59SGordon Tetlow	bad=${bad#\\n}
898c535eb59SGordon Tetlow
899c535eb59SGordon Tetlow	if [ -n "$good" ]; then
900ec13a838SMohamed Akram		printf '%b\n' "$good" | $MANPAGER
901c535eb59SGordon Tetlow	fi
902c535eb59SGordon Tetlow
903c535eb59SGordon Tetlow	if [ -n "$bad" ]; then
904ec13a838SMohamed Akram		printf '%b\n' "$bad" >&2
905c535eb59SGordon Tetlow	fi
906c535eb59SGordon Tetlow
907c535eb59SGordon Tetlow	exit $rval
908c535eb59SGordon Tetlow}
909c535eb59SGordon Tetlow
91057cd9717SGordon Tetlow# Usage: setup_cattool page
91157cd9717SGordon Tetlow# Finds an appropriate decompressor based on extension
91257cd9717SGordon Tetlowsetup_cattool() {
91357cd9717SGordon Tetlow	case "$1" in
91457cd9717SGordon Tetlow	*.bz)	cattool='/usr/bin/bzcat' ;;
91557cd9717SGordon Tetlow	*.bz2)	cattool='/usr/bin/bzcat' ;;
916b35ea9baSMohamed Akram	*.gz)	cattool='/usr/bin/gzcat' ;;
91757cd9717SGordon Tetlow	*.lzma)	cattool='/usr/bin/lzcat' ;;
91857cd9717SGordon Tetlow	*.xz)	cattool='/usr/bin/xzcat' ;;
919c8abb673SCameron Katri	*.zst)	cattool='/usr/bin/zstdcat' ;;
92057cd9717SGordon Tetlow	*)	cattool='/usr/bin/zcat -f' ;;
92157cd9717SGordon Tetlow	esac
92257cd9717SGordon Tetlow}
92357cd9717SGordon Tetlow
924c535eb59SGordon Tetlow# Usage: setup_pager
925a6a3e856SRuslan Ermilov# Correctly sets $MANPAGER
926c535eb59SGordon Tetlowsetup_pager() {
927c535eb59SGordon Tetlow	# Setup pager.
928a6a3e856SRuslan Ermilov	if [ -z "$MANPAGER" ]; then
929a6a3e856SRuslan Ermilov		if [ -n "$MANCOLOR" ]; then
930a6a3e856SRuslan Ermilov			MANPAGER="less -sR"
931a6a3e856SRuslan Ermilov		else
932a6a3e856SRuslan Ermilov			if [ -n "$PAGER" ]; then
933a6a3e856SRuslan Ermilov				MANPAGER="$PAGER"
934a6a3e856SRuslan Ermilov			else
93547cc9ee1SAlan Somers				MANPAGER="less -s"
936c535eb59SGordon Tetlow			fi
937a6a3e856SRuslan Ermilov		fi
938a6a3e856SRuslan Ermilov	fi
939a6a3e856SRuslan Ermilov	decho "Using pager: $MANPAGER"
940c535eb59SGordon Tetlow}
941c535eb59SGordon Tetlow
942c535eb59SGordon Tetlow# Usage: trim string
943c535eb59SGordon Tetlow# Trims whitespace from beginning and end of a variable
944c535eb59SGordon Tetlowtrim() {
945c535eb59SGordon Tetlow	tstr=$1
946c535eb59SGordon Tetlow	while true; do
947c535eb59SGordon Tetlow		case "$tstr" in
948c535eb59SGordon Tetlow		[\ \	]*)	tstr="${tstr##[\ \	]}" ;;
949c535eb59SGordon Tetlow		*[\ \	])	tstr="${tstr%%[\ \	]}" ;;
950c535eb59SGordon Tetlow		*)		break ;;
951c535eb59SGordon Tetlow		esac
952c535eb59SGordon Tetlow	done
953c535eb59SGordon Tetlow}
954c535eb59SGordon Tetlow
955c535eb59SGordon Tetlow# Usage: whatis_parse_args "$@"
956c535eb59SGordon Tetlow# Parse commandline args for whatis and apropos.
957c535eb59SGordon Tetlowwhatis_parse_args() {
958c535eb59SGordon Tetlow	local cmd_arg
959f555b39eSKyle Evans	OPTIND=1
960c535eb59SGordon Tetlow	while getopts 'd' cmd_arg; do
961c535eb59SGordon Tetlow		case "${cmd_arg}" in
962c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
963c535eb59SGordon Tetlow		*)	whatis_usage ;;
964c535eb59SGordon Tetlow		esac
965c535eb59SGordon Tetlow	done >&2
966c535eb59SGordon Tetlow
967c535eb59SGordon Tetlow	shift $(( $OPTIND - 1 ))
968c535eb59SGordon Tetlow
969c535eb59SGordon Tetlow	keywords="$*"
970c535eb59SGordon Tetlow}
971c535eb59SGordon Tetlow
972c535eb59SGordon Tetlow# Usage: whatis_usage
973c535eb59SGordon Tetlow# Display usage for the whatis/apropos utility.
974c535eb59SGordon Tetlowwhatis_usage() {
975c535eb59SGordon Tetlow	echo "usage: $cmd [-d] keyword [...]"
976c535eb59SGordon Tetlow	exit 1
977c535eb59SGordon Tetlow}
978c535eb59SGordon Tetlow
979c535eb59SGordon Tetlow
980c535eb59SGordon Tetlow
981c535eb59SGordon Tetlow# Supported commands
982c535eb59SGordon Tetlowdo_apropos() {
98324ef7420SBaptiste Daroussin	[ $(stat -f %i /usr/bin/man) -ne $(stat -f %i /usr/bin/apropos) ] && \
984772246efSBaptiste Daroussin		exec apropos "$@"
985c535eb59SGordon Tetlow	search_whatis apropos "$@"
986c535eb59SGordon Tetlow}
987c535eb59SGordon Tetlow
9881594084fSFernando Apesteguía# Usage: do_full_search reg_exp
9891594084fSFernando Apesteguía# Do a full search of the regular expression passed
9901594084fSFernando Apesteguía# as parameter in all man pages
9911594084fSFernando Apesteguíado_full_search() {
9921594084fSFernando Apesteguía	local gflags re
9931594084fSFernando Apesteguía	re=${1}
9941594084fSFernando Apesteguía
9951594084fSFernando Apesteguía	# Build grep(1) flags
9961594084fSFernando Apesteguía	gflags="-H"
9971594084fSFernando Apesteguía
9981594084fSFernando Apesteguía	# wflag implies -l for grep(1)
9991594084fSFernando Apesteguía	if [ -n "$wflag" ]; then
10001594084fSFernando Apesteguía		gflags="${gflags} -l"
10011594084fSFernando Apesteguía	fi
10021594084fSFernando Apesteguía
10031594084fSFernando Apesteguía	gflags="${gflags} --label"
10041594084fSFernando Apesteguía
10051594084fSFernando Apesteguía	set +f
10068a5c836bSEd Maste	for mpath in $(echo "${MANPATH}" | tr : '[:blank:]'); do
10078a5c836bSEd Maste		for section in $(echo "${MANSECT}" | tr : '[:blank:]'); do
10081594084fSFernando Apesteguía			for manfile in ${mpath}/man${section}/*.${section}*; do
10091594084fSFernando Apesteguía				mandoc "${manfile}" 2>/dev/null |
10108a5c836bSEd Maste					grep -E ${gflags} "${manfile}" -e "${re}"
10111594084fSFernando Apesteguía			done
10121594084fSFernando Apesteguía		done
10131594084fSFernando Apesteguía	done
10141594084fSFernando Apesteguía	set -f
10151594084fSFernando Apesteguía}
10161594084fSFernando Apesteguía
1017c535eb59SGordon Tetlowdo_man() {
10188edb6fb5SMohamed Akram	local IFS
10198edb6fb5SMohamed Akram
10208edb6fb5SMohamed Akram	man_parse_opts "$@"
10218edb6fb5SMohamed Akram	man_setup
10228edb6fb5SMohamed Akram
10238edb6fb5SMohamed Akram	shift $(( $OPTIND - 1 ))
10248edb6fb5SMohamed Akram	IFS=:
10258edb6fb5SMohamed Akram	for sect in $MANSECT; do
10268edb6fb5SMohamed Akram		if [ "$sect" = "$1" ]; then
10278edb6fb5SMohamed Akram			decho "Detected manual section as first arg: $1"
10288edb6fb5SMohamed Akram			MANSECT="$1"
10298edb6fb5SMohamed Akram			shift
10308edb6fb5SMohamed Akram			break
10318edb6fb5SMohamed Akram		fi
10328edb6fb5SMohamed Akram	done
10338edb6fb5SMohamed Akram	unset IFS
10348edb6fb5SMohamed Akram	pages="$*"
10358edb6fb5SMohamed Akram
10361594084fSFernando Apesteguía	if [ -z "$pages" -a -z "${Kflag}" ]; then
1037c535eb59SGordon Tetlow		echo 'What manual page do you want?' >&2
1038c535eb59SGordon Tetlow		exit 1
1039c535eb59SGordon Tetlow	fi
1040c535eb59SGordon Tetlow
10411594084fSFernando Apesteguía	if [ ! -z "${Kflag}" ]; then
10421594084fSFernando Apesteguía		# Short circuit because -K flag does a sufficiently
10431594084fSFernando Apesteguía		# different thing like not showing the man page at all
10441594084fSFernando Apesteguía		do_full_search "${REGEXP}"
10451594084fSFernando Apesteguía	fi
10461594084fSFernando Apesteguía
10471e82d882SWolfram Schneider	for page in "$@"; do
104878948070SWolfram Schneider		decho "Searching for \"$page\""
1049c535eb59SGordon Tetlow		man_find_and_display "$page"
1050c535eb59SGordon Tetlow	done
1051c535eb59SGordon Tetlow
1052c535eb59SGordon Tetlow	exit ${ret:-0}
1053c535eb59SGordon Tetlow}
1054c535eb59SGordon Tetlow
1055c535eb59SGordon Tetlowdo_manpath() {
1056c535eb59SGordon Tetlow	manpath_parse_args "$@"
1057c535eb59SGordon Tetlow	if [ -z "$qflag" ]; then
1058c535eb59SGordon Tetlow		manpath_warnings
1059c535eb59SGordon Tetlow	fi
1060c535eb59SGordon Tetlow	if [ -n "$Lflag" ]; then
1061c535eb59SGordon Tetlow		build_manlocales
1062c535eb59SGordon Tetlow		echo $MANLOCALES
1063c535eb59SGordon Tetlow	else
1064c535eb59SGordon Tetlow		build_manpath
1065c535eb59SGordon Tetlow		echo $MANPATH
1066c535eb59SGordon Tetlow	fi
1067c535eb59SGordon Tetlow	exit 0
1068c535eb59SGordon Tetlow}
1069c535eb59SGordon Tetlow
1070c535eb59SGordon Tetlowdo_whatis() {
107124ef7420SBaptiste Daroussin	[ $(stat -f %i /usr/bin/man) -ne $(stat -f %i /usr/bin/whatis) ] && \
1072772246efSBaptiste Daroussin		exec whatis "$@"
1073c535eb59SGordon Tetlow	search_whatis whatis "$@"
1074c535eb59SGordon Tetlow}
1075c535eb59SGordon Tetlow
1076aeea395eSUlrich Spörlein# User's PATH setting decides on the groff-suite to pick up.
1077aeea395eSUlrich SpörleinEQN=eqn
1078035f7c9aSWolfram SchneiderNROFF='groff -S -P-h -Wall -mtty-char -mandoc'
1079aeea395eSUlrich SpörleinPIC=pic
1080aeea395eSUlrich SpörleinREFER=refer
1081aeea395eSUlrich SpörleinTBL=tbl
1082035f7c9aSWolfram SchneiderTROFF='groff -S -mandoc'
1083aeea395eSUlrich SpörleinVGRIND=vgrind
1084aeea395eSUlrich Spörlein
1085deeff310SGordon TetlowLOCALE=/usr/bin/locale
1086a0094449SRuslan ErmilovSTTY=/bin/stty
108782db8a5eSGordon TetlowSYSCTL=/sbin/sysctl
1088c535eb59SGordon Tetlow
1089c535eb59SGordon Tetlowdebug=0
109073577bf0SRyan Moellerman_default_sections='1:8:2:3:3lua:n:4:5:6:7:9:l'
1091971c1c42STijl Coosemansman_default_path='/usr/share/man:/usr/share/openssl/man:/usr/local/share/man:/usr/local/man'
109257cd9717SGordon Tetlowcattool='/usr/bin/zcat -f'
1093c535eb59SGordon Tetlow
1094c535eb59SGordon Tetlowconfig_global='/etc/man.conf'
1095c535eb59SGordon Tetlow
1096c535eb59SGordon Tetlow# This can be overridden via a setting in /etc/man.conf.
1097c535eb59SGordon Tetlowconfig_local='/usr/local/etc/man.d/*.conf'
1098c535eb59SGordon Tetlow
1099c535eb59SGordon Tetlow# Set noglobbing for now. I don't want spurious globbing.
1100c535eb59SGordon Tetlowset -f
1101c535eb59SGordon Tetlow
1102c535eb59SGordon Tetlowcase "$0" in
1103c535eb59SGordon Tetlow*apropos)	do_apropos "$@" ;;
1104c535eb59SGordon Tetlow*manpath)	do_manpath "$@" ;;
1105c535eb59SGordon Tetlow*whatis)	do_whatis "$@" ;;
1106c535eb59SGordon Tetlow*)		do_man "$@" ;;
1107c535eb59SGordon Tetlowesac
1108