xref: /freebsd/usr.bin/man/man.sh (revision 8edb6fb572f29578877fdac3c30f718e589a0360)
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# $FreeBSD$
30c535eb59SGordon Tetlow
31433c5a8aSWolfram Schneider# Rendering a manual page is fast. Even a manual page several 100k in size
32433c5a8aSWolfram Schneider# takes less than a CPU second. If it takes much longer, it is very likely
33433c5a8aSWolfram Schneider# that a tool like mandoc(1) is running in an infinite loop. In this case
34433c5a8aSWolfram Schneider# it is better to terminate it.
35433c5a8aSWolfram Schneiderulimit -t 20
36433c5a8aSWolfram Schneider
37c535eb59SGordon Tetlow# Usage: add_to_manpath path
38c535eb59SGordon Tetlow# Adds a variable to manpath while ensuring we don't have duplicates.
39c535eb59SGordon Tetlow# Returns true if we were able to add something. False otherwise.
40c535eb59SGordon Tetlowadd_to_manpath() {
41c535eb59SGordon Tetlow	case "$manpath" in
42c535eb59SGordon Tetlow	*:$1)	decho "  Skipping duplicate manpath entry $1" 2 ;;
43c535eb59SGordon Tetlow	$1:*)	decho "  Skipping duplicate manpath entry $1" 2 ;;
44c535eb59SGordon Tetlow	*:$1:*)	decho "  Skipping duplicate manpath entry $1" 2 ;;
45c535eb59SGordon Tetlow	*)	if [ -d "$1" ]; then
46c535eb59SGordon Tetlow			decho "  Adding $1 to manpath"
47c535eb59SGordon Tetlow			manpath="$manpath:$1"
48c535eb59SGordon Tetlow			return 0
49c535eb59SGordon Tetlow		fi
50c535eb59SGordon Tetlow		;;
51c535eb59SGordon Tetlow	esac
52c535eb59SGordon Tetlow
53c535eb59SGordon Tetlow	return 1
54c535eb59SGordon Tetlow}
55c535eb59SGordon Tetlow
56c535eb59SGordon Tetlow# Usage: build_manlocales
57c535eb59SGordon Tetlow# Builds a correct MANLOCALES variable.
58c535eb59SGordon Tetlowbuild_manlocales() {
59c535eb59SGordon Tetlow	# If the user has set manlocales, who are we to argue.
60c535eb59SGordon Tetlow	if [ -n "$MANLOCALES" ]; then
61c535eb59SGordon Tetlow		return
62c535eb59SGordon Tetlow	fi
63c535eb59SGordon Tetlow
64c535eb59SGordon Tetlow	parse_configs
65c535eb59SGordon Tetlow
66c535eb59SGordon Tetlow	# Trim leading colon
67c535eb59SGordon Tetlow	MANLOCALES=${manlocales#:}
68c535eb59SGordon Tetlow
69c535eb59SGordon Tetlow	decho "Available manual locales: $MANLOCALES"
70c535eb59SGordon Tetlow}
71c535eb59SGordon Tetlow
72*8edb6fb5SMohamed Akram# Usage: build_mansect
73*8edb6fb5SMohamed Akram# Builds a correct MANSECT variable.
74*8edb6fb5SMohamed Akrambuild_mansect() {
75*8edb6fb5SMohamed Akram	# If the user has set mansect, who are we to argue.
76*8edb6fb5SMohamed Akram	if [ -n "$MANSECT" ]; then
77*8edb6fb5SMohamed Akram		return
78*8edb6fb5SMohamed Akram	fi
79*8edb6fb5SMohamed Akram
80*8edb6fb5SMohamed Akram	parse_configs
81*8edb6fb5SMohamed Akram
82*8edb6fb5SMohamed Akram	# Trim leading colon
83*8edb6fb5SMohamed Akram	MANSECT=${mansect#:}
84*8edb6fb5SMohamed Akram
85*8edb6fb5SMohamed Akram	if [ -z "$MANSECT" ]; then
86*8edb6fb5SMohamed Akram		MANSECT=$man_default_sections
87*8edb6fb5SMohamed Akram	fi
88*8edb6fb5SMohamed Akram	decho "Using manual sections: $MANSECT"
89*8edb6fb5SMohamed Akram}
90*8edb6fb5SMohamed Akram
91c535eb59SGordon Tetlow# Usage: build_manpath
92c535eb59SGordon Tetlow# Builds a correct MANPATH variable.
93c535eb59SGordon Tetlowbuild_manpath() {
94c535eb59SGordon Tetlow	local IFS
95c535eb59SGordon Tetlow
96c535eb59SGordon Tetlow	# If the user has set a manpath, who are we to argue.
97c535eb59SGordon Tetlow	if [ -n "$MANPATH" ]; then
98b2394e73SBaptiste Daroussin		case "$MANPATH" in
99b2394e73SBaptiste Daroussin		*:) PREPEND_MANPATH=${MANPATH} ;;
100b2394e73SBaptiste Daroussin		:*) APPEND_MANPATH=${MANPATH} ;;
101b2394e73SBaptiste Daroussin		*::*)
102b2394e73SBaptiste Daroussin			PREPEND_MANPATH=${MANPATH%%::*}
103b2394e73SBaptiste Daroussin			APPEND_MANPATH=${MANPATH#*::}
104b2394e73SBaptiste Daroussin			;;
105b2394e73SBaptiste Daroussin		*) return ;;
106b2394e73SBaptiste Daroussin		esac
107b2394e73SBaptiste Daroussin	fi
108b2394e73SBaptiste Daroussin
109b2394e73SBaptiste Daroussin	if [ -n "$PREPEND_MANPATH" ]; then
110b2394e73SBaptiste Daroussin		IFS=:
111b2394e73SBaptiste Daroussin		for path in $PREPEND_MANPATH; do
112b2394e73SBaptiste Daroussin			add_to_manpath "$path"
113b2394e73SBaptiste Daroussin		done
114b2394e73SBaptiste Daroussin		unset IFS
115c535eb59SGordon Tetlow	fi
116c535eb59SGordon Tetlow
117c535eb59SGordon Tetlow	search_path
118c535eb59SGordon Tetlow
119c535eb59SGordon Tetlow	decho "Adding default manpath entries"
120c535eb59SGordon Tetlow	IFS=:
121c535eb59SGordon Tetlow	for path in $man_default_path; do
122c535eb59SGordon Tetlow		add_to_manpath "$path"
123c535eb59SGordon Tetlow	done
124c535eb59SGordon Tetlow	unset IFS
125c535eb59SGordon Tetlow
126c535eb59SGordon Tetlow	parse_configs
127c535eb59SGordon Tetlow
128b2394e73SBaptiste Daroussin	if [ -n "$APPEND_MANPATH" ]; then
129b2394e73SBaptiste Daroussin		IFS=:
130b2394e73SBaptiste Daroussin		for path in $APPEND_MANPATH; do
131b2394e73SBaptiste Daroussin			add_to_manpath "$path"
132b2394e73SBaptiste Daroussin		done
133b2394e73SBaptiste Daroussin		unset IFS
134b2394e73SBaptiste Daroussin	fi
135c535eb59SGordon Tetlow	# Trim leading colon
136c535eb59SGordon Tetlow	MANPATH=${manpath#:}
137c535eb59SGordon Tetlow
138c535eb59SGordon Tetlow	decho "Using manual path: $MANPATH"
139c535eb59SGordon Tetlow}
140c535eb59SGordon Tetlow
141c535eb59SGordon Tetlow# Usage: check_cat catglob
142c535eb59SGordon Tetlow# Checks to see if a cat glob is available.
143c535eb59SGordon Tetlowcheck_cat() {
144c535eb59SGordon Tetlow	if exists "$1"; then
145c535eb59SGordon Tetlow		use_cat=yes
146c535eb59SGordon Tetlow		catpage=$found
14757cd9717SGordon Tetlow		setup_cattool $catpage
148c535eb59SGordon Tetlow		decho "    Found catpage $catpage"
149c535eb59SGordon Tetlow		return 0
150c535eb59SGordon Tetlow	else
151c535eb59SGordon Tetlow		return 1
152c535eb59SGordon Tetlow	fi
153c535eb59SGordon Tetlow}
154c535eb59SGordon Tetlow
155c535eb59SGordon Tetlow# Usage: check_man manglob catglob
156c535eb59SGordon Tetlow# Given 2 globs, figures out if the manglob is available, if so, check to
157c535eb59SGordon Tetlow# see if the catglob is also available and up to date.
158c535eb59SGordon Tetlowcheck_man() {
159c535eb59SGordon Tetlow	if exists "$1"; then
160c535eb59SGordon Tetlow		# We have a match, check for a cat page
161c535eb59SGordon Tetlow		manpage=$found
16257cd9717SGordon Tetlow		setup_cattool $manpage
163c535eb59SGordon Tetlow		decho "    Found manpage $manpage"
164c535eb59SGordon Tetlow
165a0094449SRuslan Ermilov		if [ -n "${use_width}" ]; then
166a0094449SRuslan Ermilov			# non-standard width
167a0094449SRuslan Ermilov			unset use_cat
168a0094449SRuslan Ermilov			decho "    Skipping catpage: non-standard page width"
169a0094449SRuslan Ermilov		elif exists "$2" && is_newer $found $manpage; then
170c535eb59SGordon Tetlow			# cat page found and is newer, use that
171c535eb59SGordon Tetlow			use_cat=yes
172c535eb59SGordon Tetlow			catpage=$found
17357cd9717SGordon Tetlow			setup_cattool $catpage
174c535eb59SGordon Tetlow			decho "    Using catpage $catpage"
175c535eb59SGordon Tetlow		else
176c535eb59SGordon Tetlow			# no cat page or is older
177c535eb59SGordon Tetlow			unset use_cat
178c535eb59SGordon Tetlow			decho "    Skipping catpage: not found or old"
179c535eb59SGordon Tetlow		fi
180c535eb59SGordon Tetlow		return 0
181c535eb59SGordon Tetlow	fi
182c535eb59SGordon Tetlow
183c535eb59SGordon Tetlow	return 1
184c535eb59SGordon Tetlow}
185c535eb59SGordon Tetlow
186c535eb59SGordon Tetlow# Usage: decho "string" [debuglevel]
187c535eb59SGordon Tetlow# Echoes to stderr string prefaced with -- if high enough debuglevel.
188c535eb59SGordon Tetlowdecho() {
189c535eb59SGordon Tetlow	if [ $debug -ge ${2:-1} ]; then
190c535eb59SGordon Tetlow		echo "-- $1" >&2
191c535eb59SGordon Tetlow	fi
192c535eb59SGordon Tetlow}
193c535eb59SGordon Tetlow
194c535eb59SGordon Tetlow# Usage: exists glob
195c535eb59SGordon Tetlow# Returns true if glob resolves to a real file.
196c535eb59SGordon Tetlowexists() {
197c535eb59SGordon Tetlow	local IFS
198c535eb59SGordon Tetlow
199c535eb59SGordon Tetlow	# Don't accidentally inherit callers IFS (breaks perl manpages)
200c535eb59SGordon Tetlow	unset IFS
201c535eb59SGordon Tetlow
202c535eb59SGordon Tetlow	# Use some globbing tricks in the shell to determine if a file
203c535eb59SGordon Tetlow	# exists or not.
204c535eb59SGordon Tetlow	set +f
205c535eb59SGordon Tetlow	set -- "$1" $1
206c535eb59SGordon Tetlow	set -f
207c535eb59SGordon Tetlow
208c535eb59SGordon Tetlow	if [ "$1" != "$2" -a -r "$2" ]; then
209c535eb59SGordon Tetlow		found="$2"
210c535eb59SGordon Tetlow		return 0
211c535eb59SGordon Tetlow	fi
212c535eb59SGordon Tetlow
213c535eb59SGordon Tetlow	return 1
214c535eb59SGordon Tetlow}
215c535eb59SGordon Tetlow
216c535eb59SGordon Tetlow# Usage: find_file path section subdir pagename
217c535eb59SGordon Tetlow# Returns: true if something is matched and found.
218c535eb59SGordon Tetlow# Search the given path/section combo for a given page.
219c535eb59SGordon Tetlowfind_file() {
220c535eb59SGordon Tetlow	local manroot catroot mann man0 catn cat0
221c535eb59SGordon Tetlow
222c535eb59SGordon Tetlow	manroot="$1/man$2"
223c535eb59SGordon Tetlow	catroot="$1/cat$2"
224c535eb59SGordon Tetlow	if [ -n "$3" ]; then
225c535eb59SGordon Tetlow		manroot="$manroot/$3"
226c535eb59SGordon Tetlow		catroot="$catroot/$3"
227c535eb59SGordon Tetlow	fi
228c535eb59SGordon Tetlow
229625490e8SBaptiste Daroussin	if [ ! -d "$manroot" -a ! -d "$catroot" ]; then
230c535eb59SGordon Tetlow		return 1
231c535eb59SGordon Tetlow	fi
232c535eb59SGordon Tetlow	decho "  Searching directory $manroot" 2
233c535eb59SGordon Tetlow
234c535eb59SGordon Tetlow	mann="$manroot/$4.$2*"
235c535eb59SGordon Tetlow	man0="$manroot/$4.0*"
236c535eb59SGordon Tetlow	catn="$catroot/$4.$2*"
237c535eb59SGordon Tetlow	cat0="$catroot/$4.0*"
238c535eb59SGordon Tetlow
239c535eb59SGordon Tetlow	# This is the behavior as seen by the original man utility.
240c535eb59SGordon Tetlow	# Let's not change that which doesn't seem broken.
241c535eb59SGordon Tetlow	if check_man "$mann" "$catn"; then
242c535eb59SGordon Tetlow		return 0
243c535eb59SGordon Tetlow	elif check_man "$man0" "$cat0"; then
244c535eb59SGordon Tetlow		return 0
245c535eb59SGordon Tetlow	elif check_cat "$catn"; then
246c535eb59SGordon Tetlow		return 0
247c535eb59SGordon Tetlow	elif check_cat "$cat0"; then
248c535eb59SGordon Tetlow		return 0
249c535eb59SGordon Tetlow	fi
250c535eb59SGordon Tetlow
251c535eb59SGordon Tetlow	return 1
252c535eb59SGordon Tetlow}
253c535eb59SGordon Tetlow
254c535eb59SGordon Tetlow# Usage: is_newer file1 file2
255c535eb59SGordon Tetlow# Returns true if file1 is newer than file2 as calculated by mtime.
256c535eb59SGordon Tetlowis_newer() {
2579b61837aSUlrich Spörlein	if ! [ "$1" -ot "$2" ]; then
2589b61837aSUlrich Spörlein		decho "    mtime: $1 not older than $2" 3
259c535eb59SGordon Tetlow		return 0
260c535eb59SGordon Tetlow	else
261c535eb59SGordon Tetlow		decho "    mtime: $1 older than $2" 3
262c535eb59SGordon Tetlow		return 1
263c535eb59SGordon Tetlow	fi
264c535eb59SGordon Tetlow}
265c535eb59SGordon Tetlow
266c535eb59SGordon Tetlow# Usage: manpath_parse_args "$@"
267c535eb59SGordon Tetlow# Parses commandline options for manpath.
268c535eb59SGordon Tetlowmanpath_parse_args() {
269c535eb59SGordon Tetlow	local cmd_arg
270c535eb59SGordon Tetlow
271f555b39eSKyle Evans	OPTIND=1
272c535eb59SGordon Tetlow	while getopts 'Ldq' cmd_arg; do
273c535eb59SGordon Tetlow		case "${cmd_arg}" in
274c535eb59SGordon Tetlow		L)	Lflag=Lflag ;;
275c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
276c535eb59SGordon Tetlow		q)	qflag=qflag ;;
277c535eb59SGordon Tetlow		*)	manpath_usage ;;
278c535eb59SGordon Tetlow		esac
279c535eb59SGordon Tetlow	done >&2
280c535eb59SGordon Tetlow}
281c535eb59SGordon Tetlow
282c535eb59SGordon Tetlow# Usage: manpath_usage
283c535eb59SGordon Tetlow# Display usage for the manpath(1) utility.
284c535eb59SGordon Tetlowmanpath_usage() {
285c535eb59SGordon Tetlow	echo 'usage: manpath [-Ldq]' >&2
286c535eb59SGordon Tetlow	exit 1
287c535eb59SGordon Tetlow}
288c535eb59SGordon Tetlow
289c535eb59SGordon Tetlow# Usage: manpath_warnings
290c535eb59SGordon Tetlow# Display some warnings to stderr.
291c535eb59SGordon Tetlowmanpath_warnings() {
292c535eb59SGordon Tetlow	if [ -n "$Lflag" -a -n "$MANLOCALES" ]; then
293c535eb59SGordon Tetlow		echo "(Warning: MANLOCALES environment variable set)" >&2
294c535eb59SGordon Tetlow	fi
295c535eb59SGordon Tetlow}
296c535eb59SGordon Tetlow
29757cd9717SGordon Tetlow# Usage: man_check_for_so page path
29857cd9717SGordon Tetlow# Returns: True if able to resolve the file, false if it ended in tears.
29957cd9717SGordon Tetlow# Detects the presence of the .so directive and causes the file to be
30057cd9717SGordon Tetlow# redirected to another source file.
30157cd9717SGordon Tetlowman_check_for_so() {
30257cd9717SGordon Tetlow	local IFS line tstr
30357cd9717SGordon Tetlow
30457cd9717SGordon Tetlow	unset IFS
305d9405a92SBaptiste Daroussin	if [ -n "$catpage" ]; then
306d9405a92SBaptiste Daroussin		return 0
307d9405a92SBaptiste Daroussin	fi
30857cd9717SGordon Tetlow
30957cd9717SGordon Tetlow	# We need to loop to accommodate multiple .so directives.
31057cd9717SGordon Tetlow	while true
31157cd9717SGordon Tetlow	do
31257cd9717SGordon Tetlow		line=$($cattool $manpage | head -1)
31357cd9717SGordon Tetlow		case "$line" in
31457cd9717SGordon Tetlow		.so*)	trim "${line#.so}"
31557cd9717SGordon Tetlow			decho "$manpage includes $tstr"
31657cd9717SGordon Tetlow			# Glob and check for the file.
31757cd9717SGordon Tetlow			if ! check_man "$path/$tstr*" ""; then
31857cd9717SGordon Tetlow				decho "  Unable to find $tstr"
31957cd9717SGordon Tetlow				return 1
32057cd9717SGordon Tetlow			fi
32157cd9717SGordon Tetlow			;;
32257cd9717SGordon Tetlow		*)	break ;;
32357cd9717SGordon Tetlow		esac
32457cd9717SGordon Tetlow	done
32557cd9717SGordon Tetlow
32657cd9717SGordon Tetlow	return 0
32757cd9717SGordon Tetlow}
32857cd9717SGordon Tetlow
329b43edc06SBaptiste Daroussin# Usage: man_display_page
330b43edc06SBaptiste Daroussin# Display either the manpage or catpage depending on the use_cat variable
331c535eb59SGordon Tetlowman_display_page() {
3321fb816daSBaptiste Daroussin	local IFS pipeline testline
333c535eb59SGordon Tetlow
334c535eb59SGordon Tetlow	# We are called with IFS set to colon. This causes really weird
335c535eb59SGordon Tetlow	# things to happen for the variables that have spaces in them.
336c535eb59SGordon Tetlow	unset IFS
337c535eb59SGordon Tetlow
338c535eb59SGordon Tetlow	# If we are supposed to use a catpage and we aren't using troff(1)
339c535eb59SGordon Tetlow	# just zcat the catpage and we are done.
340c535eb59SGordon Tetlow	if [ -z "$tflag" -a -n "$use_cat" ]; then
341c535eb59SGordon Tetlow		if [ -n "$wflag" ]; then
342c535eb59SGordon Tetlow			echo "$catpage (source: $manpage)"
343c535eb59SGordon Tetlow			ret=0
344c535eb59SGordon Tetlow		else
345c535eb59SGordon Tetlow			if [ $debug -gt 0 ]; then
346a6a3e856SRuslan Ermilov				decho "Command: $cattool $catpage | $MANPAGER"
347c535eb59SGordon Tetlow				ret=0
348c535eb59SGordon Tetlow			else
349a6a3e856SRuslan Ermilov				eval "$cattool $catpage | $MANPAGER"
350c535eb59SGordon Tetlow				ret=$?
351c535eb59SGordon Tetlow			fi
352c535eb59SGordon Tetlow		fi
353c535eb59SGordon Tetlow		return
354c535eb59SGordon Tetlow	fi
355c535eb59SGordon Tetlow
356c535eb59SGordon Tetlow	# Okay, we are using the manpage, do we just need to output the
357c535eb59SGordon Tetlow	# name of the manpage?
358c535eb59SGordon Tetlow	if [ -n "$wflag" ]; then
359c535eb59SGordon Tetlow		echo "$manpage"
360c535eb59SGordon Tetlow		ret=0
361c535eb59SGordon Tetlow		return
362c535eb59SGordon Tetlow	fi
363c535eb59SGordon Tetlow
364d433cf9aSBaptiste Daroussin	if [ -n "$use_width" ]; then
365d433cf9aSBaptiste Daroussin		mandoc_args="-O width=${use_width}"
366d433cf9aSBaptiste Daroussin	fi
367451c2becSBaptiste Daroussin	testline="mandoc -Tlint -Wunsupp >/dev/null 2>&1"
368449a792dSBaptiste Daroussin	if [ -n "$tflag" ]; then
369449a792dSBaptiste Daroussin		pipeline="mandoc -Tps $mandoc_args"
370449a792dSBaptiste Daroussin	else
371d433cf9aSBaptiste Daroussin		pipeline="mandoc $mandoc_args | $MANPAGER"
372449a792dSBaptiste Daroussin	fi
373d6096801SBaptiste Daroussin
374d6096801SBaptiste Daroussin	if ! eval "$cattool $manpage | $testline" ;then
375f17575acSBaptiste Daroussin		if which -s groff; then
376d6096801SBaptiste Daroussin			man_display_page_groff
377d6096801SBaptiste Daroussin		else
378d6096801SBaptiste Daroussin			echo "This manpage needs groff(1) to be rendered" >&2
379d6096801SBaptiste Daroussin			echo "First install groff(1): " >&2
380d6096801SBaptiste Daroussin			echo "pkg install groff " >&2
381d6096801SBaptiste Daroussin			ret=1
382d6096801SBaptiste Daroussin		fi
383d6096801SBaptiste Daroussin		return
384d6096801SBaptiste Daroussin	fi
385d6096801SBaptiste Daroussin
386d6096801SBaptiste Daroussin	if [ $debug -gt 0 ]; then
387d6096801SBaptiste Daroussin		decho "Command: $cattool $manpage | $pipeline"
388d6096801SBaptiste Daroussin		ret=0
389d6096801SBaptiste Daroussin	else
390d6096801SBaptiste Daroussin		eval "$cattool $manpage | $pipeline"
391d6096801SBaptiste Daroussin		ret=$?
392d6096801SBaptiste Daroussin	fi
393d6096801SBaptiste Daroussin}
394d6096801SBaptiste Daroussin
395b43edc06SBaptiste Daroussin# Usage: man_display_page_groff
396b43edc06SBaptiste Daroussin# Display the manpage using groff
397d6096801SBaptiste Daroussinman_display_page_groff() {
398d6096801SBaptiste Daroussin	local EQN NROFF PIC TBL TROFF REFER VGRIND
399d6096801SBaptiste Daroussin	local IFS l nroff_dev pipeline preproc_arg tool
400d6096801SBaptiste Daroussin
401c535eb59SGordon Tetlow	# So, we really do need to parse the manpage. First, figure out the
402c535eb59SGordon Tetlow	# device flag (-T) we have to pass to eqn(1) and groff(1). Then,
403c535eb59SGordon Tetlow	# setup the pipeline of commands based on the user's request.
404c535eb59SGordon Tetlow
405deeff310SGordon Tetlow	# If the manpage is from a particular charset, we need to setup nroff
406deeff310SGordon Tetlow	# to properly output for the correct device.
407deeff310SGordon Tetlow	case "${manpage}" in
408deeff310SGordon Tetlow	*.${man_charset}/*)
409c535eb59SGordon Tetlow		# I don't pretend to know this; I'm just copying from the
410c535eb59SGordon Tetlow		# previous version of man(1).
411c535eb59SGordon Tetlow		case "$man_charset" in
412c535eb59SGordon Tetlow		KOI8-R)		nroff_dev="koi8-r" ;;
413c535eb59SGordon Tetlow		ISO8859-1)	nroff_dev="latin1" ;;
414c535eb59SGordon Tetlow		ISO8859-15)	nroff_dev="latin1" ;;
415c535eb59SGordon Tetlow		UTF-8)		nroff_dev="utf8" ;;
416c535eb59SGordon Tetlow		*)		nroff_dev="ascii" ;;
417c535eb59SGordon Tetlow		esac
418c535eb59SGordon Tetlow
419deeff310SGordon Tetlow		NROFF="$NROFF -T$nroff_dev"
420c535eb59SGordon Tetlow		EQN="$EQN -T$nroff_dev"
421c535eb59SGordon Tetlow
422deeff310SGordon Tetlow		# Iff the manpage is from the locale and not just the charset,
423deeff310SGordon Tetlow		# then we need to define the locale string.
424deeff310SGordon Tetlow		case "${manpage}" in
425deeff310SGordon Tetlow		*/${man_lang}_${man_country}.${man_charset}/*)
426deeff310SGordon Tetlow			NROFF="$NROFF -dlocale=$man_lang.$man_charset"
427deeff310SGordon Tetlow			;;
428deeff310SGordon Tetlow		*/${man_lang}.${man_charset}/*)
429deeff310SGordon Tetlow			NROFF="$NROFF -dlocale=$man_lang.$man_charset"
430deeff310SGordon Tetlow			;;
431deeff310SGordon Tetlow		esac
432deeff310SGordon Tetlow
433c535eb59SGordon Tetlow		# Allow language specific calls to override the default
434c535eb59SGordon Tetlow		# set of utilities.
435c535eb59SGordon Tetlow		l=$(echo $man_lang | tr [:lower:] [:upper:])
436b70e2025SRuslan Ermilov		for tool in EQN NROFF PIC TBL TROFF REFER VGRIND; do
437c535eb59SGordon Tetlow			eval "$tool=\${${tool}_$l:-\$$tool}"
438c535eb59SGordon Tetlow		done
439c535eb59SGordon Tetlow		;;
440c535eb59SGordon Tetlow	*)	NROFF="$NROFF -Tascii"
441c535eb59SGordon Tetlow		EQN="$EQN -Tascii"
442c535eb59SGordon Tetlow		;;
443c535eb59SGordon Tetlow	esac
444c535eb59SGordon Tetlow
445a6a3e856SRuslan Ermilov	if [ -z "$MANCOLOR" ]; then
446a6a3e856SRuslan Ermilov		NROFF="$NROFF -P-c"
447a6a3e856SRuslan Ermilov	fi
448a6a3e856SRuslan Ermilov
449a0094449SRuslan Ermilov	if [ -n "${use_width}" ]; then
450a0094449SRuslan Ermilov		NROFF="$NROFF -rLL=${use_width}n -rLT=${use_width}n"
451a0094449SRuslan Ermilov	fi
452a0094449SRuslan Ermilov
453c535eb59SGordon Tetlow	if [ -n "$MANROFFSEQ" ]; then
454c535eb59SGordon Tetlow		set -- -$MANROFFSEQ
455f555b39eSKyle Evans		OPTIND=1
456c535eb59SGordon Tetlow		while getopts 'egprtv' preproc_arg; do
457c535eb59SGordon Tetlow			case "${preproc_arg}" in
458c535eb59SGordon Tetlow			e)	pipeline="$pipeline | $EQN" ;;
459487ac9acSUlrich Spörlein			g)	;; # Ignore for compatibility.
460c535eb59SGordon Tetlow			p)	pipeline="$pipeline | $PIC" ;;
461c535eb59SGordon Tetlow			r)	pipeline="$pipeline | $REFER" ;;
462b70e2025SRuslan Ermilov			t)	pipeline="$pipeline | $TBL" ;;
463c535eb59SGordon Tetlow			v)	pipeline="$pipeline | $VGRIND" ;;
464c535eb59SGordon Tetlow			*)	usage ;;
465c535eb59SGordon Tetlow			esac
466c535eb59SGordon Tetlow		done
467c535eb59SGordon Tetlow		# Strip the leading " | " from the resulting pipeline.
468c535eb59SGordon Tetlow		pipeline="${pipeline#" | "}"
469c535eb59SGordon Tetlow	else
470c535eb59SGordon Tetlow		pipeline="$TBL"
471c535eb59SGordon Tetlow	fi
472c535eb59SGordon Tetlow
473c535eb59SGordon Tetlow	if [ -n "$tflag" ]; then
474c535eb59SGordon Tetlow		pipeline="$pipeline | $TROFF"
475c535eb59SGordon Tetlow	else
476a6a3e856SRuslan Ermilov		pipeline="$pipeline | $NROFF | $MANPAGER"
477c535eb59SGordon Tetlow	fi
478c535eb59SGordon Tetlow
479c535eb59SGordon Tetlow	if [ $debug -gt 0 ]; then
48057cd9717SGordon Tetlow		decho "Command: $cattool $manpage | $pipeline"
481c535eb59SGordon Tetlow		ret=0
482c535eb59SGordon Tetlow	else
48357cd9717SGordon Tetlow		eval "$cattool $manpage | $pipeline"
484c535eb59SGordon Tetlow		ret=$?
485c535eb59SGordon Tetlow	fi
486c535eb59SGordon Tetlow}
487c535eb59SGordon Tetlow
488c535eb59SGordon Tetlow# Usage: man_find_and_display page
489c535eb59SGordon Tetlow# Search through the manpaths looking for the given page.
490c535eb59SGordon Tetlowman_find_and_display() {
491c535eb59SGordon Tetlow	local found_page locpath p path sect
492c535eb59SGordon Tetlow
4933d9127f1SGordon Tetlow	# Check to see if it's a file. But only if it has a '/' in
4943d9127f1SGordon Tetlow	# the filename.
4953d9127f1SGordon Tetlow	case "$1" in
4963d9127f1SGordon Tetlow	*/*)	if [ -f "$1" -a -r "$1" ]; then
4973d9127f1SGordon Tetlow			decho "Found a usable page, displaying that"
4983d9127f1SGordon Tetlow			unset use_cat
4993d9127f1SGordon Tetlow			manpage="$1"
50057cd9717SGordon Tetlow			setup_cattool $manpage
50157cd9717SGordon Tetlow			if man_check_for_so $manpage $(dirname $manpage); then
50257cd9717SGordon Tetlow				found_page=yes
5033d9127f1SGordon Tetlow				man_display_page
50457cd9717SGordon Tetlow			fi
5053d9127f1SGordon Tetlow			return
5063d9127f1SGordon Tetlow		fi
5073d9127f1SGordon Tetlow		;;
5083d9127f1SGordon Tetlow	esac
5093d9127f1SGordon Tetlow
510c535eb59SGordon Tetlow	IFS=:
511c535eb59SGordon Tetlow	for sect in $MANSECT; do
512c535eb59SGordon Tetlow		decho "Searching section $sect" 2
513c535eb59SGordon Tetlow		for path in $MANPATH; do
514c535eb59SGordon Tetlow			for locpath in $locpaths; do
515c535eb59SGordon Tetlow				p=$path/$locpath
516c535eb59SGordon Tetlow				p=${p%/.} # Rid ourselves of the trailing /.
517c535eb59SGordon Tetlow
518c535eb59SGordon Tetlow				# Check if there is a MACHINE specific manpath.
519c535eb59SGordon Tetlow				if find_file $p $sect $MACHINE "$1"; then
52057cd9717SGordon Tetlow					if man_check_for_so $manpage $p; then
521c535eb59SGordon Tetlow						found_page=yes
522c535eb59SGordon Tetlow						man_display_page
5231d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
5241d7c660aSGordon Tetlow							continue 2
5251d7c660aSGordon Tetlow						else
526c535eb59SGordon Tetlow							return
527c535eb59SGordon Tetlow						fi
528c535eb59SGordon Tetlow					fi
52957cd9717SGordon Tetlow				fi
530c535eb59SGordon Tetlow
531c535eb59SGordon Tetlow				# Check if there is a MACHINE_ARCH
532c535eb59SGordon Tetlow				# specific manpath.
533c535eb59SGordon Tetlow				if find_file $p $sect $MACHINE_ARCH "$1"; then
53457cd9717SGordon Tetlow					if man_check_for_so $manpage $p; then
535c535eb59SGordon Tetlow						found_page=yes
536c535eb59SGordon Tetlow						man_display_page
5371d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
5381d7c660aSGordon Tetlow							continue 2
5391d7c660aSGordon Tetlow						else
540c535eb59SGordon Tetlow							return
541c535eb59SGordon Tetlow						fi
542c535eb59SGordon Tetlow					fi
54357cd9717SGordon Tetlow				fi
544c535eb59SGordon Tetlow
545c535eb59SGordon Tetlow				# Check plain old manpath.
546c535eb59SGordon Tetlow				if find_file $p $sect '' "$1"; then
54757cd9717SGordon Tetlow					if man_check_for_so $manpage $p; then
548c535eb59SGordon Tetlow						found_page=yes
549c535eb59SGordon Tetlow						man_display_page
5501d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
5511d7c660aSGordon Tetlow							continue 2
5521d7c660aSGordon Tetlow						else
553c535eb59SGordon Tetlow							return
554c535eb59SGordon Tetlow						fi
555c535eb59SGordon Tetlow					fi
55657cd9717SGordon Tetlow				fi
557c535eb59SGordon Tetlow			done
558c535eb59SGordon Tetlow		done
559c535eb59SGordon Tetlow	done
560c535eb59SGordon Tetlow	unset IFS
561c535eb59SGordon Tetlow
562c535eb59SGordon Tetlow	# Nothing? Well, we are done then.
563c535eb59SGordon Tetlow	if [ -z "$found_page" ]; then
564c535eb59SGordon Tetlow		echo "No manual entry for $1" >&2
565c535eb59SGordon Tetlow		ret=1
566c535eb59SGordon Tetlow		return
567c535eb59SGordon Tetlow	fi
568c535eb59SGordon Tetlow}
569c535eb59SGordon Tetlow
570*8edb6fb5SMohamed Akram# Usage: man_parse_opts "$@"
571c535eb59SGordon Tetlow# Parses commandline options for man.
572*8edb6fb5SMohamed Akramman_parse_opts() {
573*8edb6fb5SMohamed Akram	local cmd_arg
574c535eb59SGordon Tetlow
575f555b39eSKyle Evans	OPTIND=1
5761594084fSFernando Apesteguía	while getopts 'K:M:P:S:adfhkm:op:tw' cmd_arg; do
577c535eb59SGordon Tetlow		case "${cmd_arg}" in
5781594084fSFernando Apesteguía		K)	Kflag=Kflag
5791594084fSFernando Apesteguía			REGEXP=$OPTARG ;;
580c535eb59SGordon Tetlow		M)	MANPATH=$OPTARG ;;
581a6a3e856SRuslan Ermilov		P)	MANPAGER=$OPTARG ;;
582c535eb59SGordon Tetlow		S)	MANSECT=$OPTARG ;;
583c535eb59SGordon Tetlow		a)	aflag=aflag ;;
584c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
585c535eb59SGordon Tetlow		f)	fflag=fflag ;;
586c535eb59SGordon Tetlow		h)	man_usage 0 ;;
587c535eb59SGordon Tetlow		k)	kflag=kflag ;;
588c535eb59SGordon Tetlow		m)	mflag=$OPTARG ;;
589c535eb59SGordon Tetlow		o)	oflag=oflag ;;
590c535eb59SGordon Tetlow		p)	MANROFFSEQ=$OPTARG ;;
591c535eb59SGordon Tetlow		t)	tflag=tflag ;;
592c535eb59SGordon Tetlow		w)	wflag=wflag ;;
593c535eb59SGordon Tetlow		*)	man_usage ;;
594c535eb59SGordon Tetlow		esac
595c535eb59SGordon Tetlow	done >&2
596c535eb59SGordon Tetlow
597c535eb59SGordon Tetlow	shift $(( $OPTIND - 1 ))
598c535eb59SGordon Tetlow
599c535eb59SGordon Tetlow	# Check the args for incompatible options.
6001594084fSFernando Apesteguía
6011594084fSFernando Apesteguía	case "${Kflag}${fflag}${kflag}${tflag}${wflag}" in
6021594084fSFernando Apesteguía	Kflagfflag*)	echo "Incompatible options: -K and -f"; man_usage ;;
6031594084fSFernando Apesteguía	Kflag*kflag*)	echo "Incompatible options: -K and -k"; man_usage ;;
6041594084fSFernando Apesteguía	Kflag*tflag)	echo "Incompatible options: -K and -t"; man_usage ;;
605c535eb59SGordon Tetlow	fflagkflag*)	echo "Incompatible options: -f and -k"; man_usage ;;
606c535eb59SGordon Tetlow	fflag*tflag*)	echo "Incompatible options: -f and -t"; man_usage ;;
607c535eb59SGordon Tetlow	fflag*wflag)	echo "Incompatible options: -f and -w"; man_usage ;;
608c535eb59SGordon Tetlow	*kflagtflag*)	echo "Incompatible options: -k and -t"; man_usage ;;
609c535eb59SGordon Tetlow	*kflag*wflag)	echo "Incompatible options: -k and -w"; man_usage ;;
610c535eb59SGordon Tetlow	*tflagwflag)	echo "Incompatible options: -t and -w"; man_usage ;;
611c535eb59SGordon Tetlow	esac
612c535eb59SGordon Tetlow
613c535eb59SGordon Tetlow	# Short circuit for whatis(1) and apropos(1)
614c535eb59SGordon Tetlow	if [ -n "$fflag" ]; then
615c535eb59SGordon Tetlow		do_whatis "$@"
616c535eb59SGordon Tetlow		exit
617c535eb59SGordon Tetlow	fi
618c535eb59SGordon Tetlow
619c535eb59SGordon Tetlow	if [ -n "$kflag" ]; then
620c535eb59SGordon Tetlow		do_apropos "$@"
621c535eb59SGordon Tetlow		exit
622c535eb59SGordon Tetlow	fi
623c535eb59SGordon Tetlow}
624c535eb59SGordon Tetlow
625c535eb59SGordon Tetlow# Usage: man_setup
626c535eb59SGordon Tetlow# Setup various trivial but essential variables.
627c535eb59SGordon Tetlowman_setup() {
628c535eb59SGordon Tetlow	# Setup machine and architecture variables.
629c535eb59SGordon Tetlow	if [ -n "$mflag" ]; then
630c535eb59SGordon Tetlow		MACHINE_ARCH=${mflag%%:*}
631c535eb59SGordon Tetlow		MACHINE=${mflag##*:}
632c535eb59SGordon Tetlow	fi
633c535eb59SGordon Tetlow	if [ -z "$MACHINE_ARCH" ]; then
63482db8a5eSGordon Tetlow		MACHINE_ARCH=$($SYSCTL -n hw.machine_arch)
635c535eb59SGordon Tetlow	fi
636c535eb59SGordon Tetlow	if [ -z "$MACHINE" ]; then
63782db8a5eSGordon Tetlow		MACHINE=$($SYSCTL -n hw.machine)
638c535eb59SGordon Tetlow	fi
639c535eb59SGordon Tetlow	decho "Using architecture: $MACHINE_ARCH:$MACHINE"
640c535eb59SGordon Tetlow
641c535eb59SGordon Tetlow	setup_pager
642c535eb59SGordon Tetlow	build_manpath
643*8edb6fb5SMohamed Akram	build_mansect
644c535eb59SGordon Tetlow	man_setup_locale
645a0094449SRuslan Ermilov	man_setup_width
646a0094449SRuslan Ermilov}
647a0094449SRuslan Ermilov
648a0094449SRuslan Ermilov# Usage: man_setup_width
649a0094449SRuslan Ermilov# Set up page width.
650a0094449SRuslan Ermilovman_setup_width() {
651a0094449SRuslan Ermilov	local sizes
652a0094449SRuslan Ermilov
653a0094449SRuslan Ermilov	unset use_width
654a0094449SRuslan Ermilov	case "$MANWIDTH" in
655a0094449SRuslan Ermilov	[0-9]*)
656a0094449SRuslan Ermilov		if [ "$MANWIDTH" -gt 0 2>/dev/null ]; then
657a0094449SRuslan Ermilov			use_width=$MANWIDTH
658a0094449SRuslan Ermilov		fi
659a0094449SRuslan Ermilov		;;
660a0094449SRuslan Ermilov	[Tt][Tt][Yy])
661a0094449SRuslan Ermilov		if { sizes=$($STTY size 0>&3 2>/dev/null); } 3>&1; then
662a0094449SRuslan Ermilov			set -- $sizes
663a0094449SRuslan Ermilov			if [ $2 -gt 80 ]; then
664a0094449SRuslan Ermilov				use_width=$(($2-2))
665a0094449SRuslan Ermilov			fi
666a0094449SRuslan Ermilov		fi
667a0094449SRuslan Ermilov		;;
668a0094449SRuslan Ermilov	esac
669a0094449SRuslan Ermilov	if [ -n "$use_width" ]; then
670a0094449SRuslan Ermilov		decho "Using non-standard page width: ${use_width}"
671a0094449SRuslan Ermilov	else
672a0094449SRuslan Ermilov		decho 'Using standard page width'
673a0094449SRuslan Ermilov	fi
674c535eb59SGordon Tetlow}
675c535eb59SGordon Tetlow
676c535eb59SGordon Tetlow# Usage: man_setup_locale
677c535eb59SGordon Tetlow# Setup necessary locale variables.
678c535eb59SGordon Tetlowman_setup_locale() {
679deeff310SGordon Tetlow	local lang_cc
6809508f8c0SYuri Pankov	local locstr
681deeff310SGordon Tetlow
682deeff310SGordon Tetlow	locpaths='.'
683deeff310SGordon Tetlow	man_charset='US-ASCII'
684deeff310SGordon Tetlow
685c535eb59SGordon Tetlow	# Setup locale information.
686c535eb59SGordon Tetlow	if [ -n "$oflag" ]; then
687deeff310SGordon Tetlow		decho 'Using non-localized manpages'
688deeff310SGordon Tetlow	else
6899508f8c0SYuri Pankov		# Use the locale tool to give us proper locale information
690deeff310SGordon Tetlow		eval $( $LOCALE )
691c535eb59SGordon Tetlow
6929508f8c0SYuri Pankov		if [ -n "$LANG" ]; then
6939508f8c0SYuri Pankov			locstr=$LANG
6949508f8c0SYuri Pankov		else
6959508f8c0SYuri Pankov			locstr=$LC_CTYPE
6969508f8c0SYuri Pankov		fi
6979508f8c0SYuri Pankov
6989508f8c0SYuri Pankov		case "$locstr" in
699deeff310SGordon Tetlow		C)		;;
7009508f8c0SYuri Pankov		C.UTF-8)	;;
701deeff310SGordon Tetlow		POSIX)		;;
702deeff310SGordon Tetlow		[a-z][a-z]_[A-Z][A-Z]\.*)
7039508f8c0SYuri Pankov				lang_cc="${locstr%.*}"
7049508f8c0SYuri Pankov				man_lang="${locstr%_*}"
705deeff310SGordon Tetlow				man_country="${lang_cc#*_}"
7069508f8c0SYuri Pankov				man_charset="${locstr#*.}"
7079508f8c0SYuri Pankov				locpaths="$locstr"
708c535eb59SGordon Tetlow				locpaths="$locpaths:$man_lang.$man_charset"
709c535eb59SGordon Tetlow				if [ "$man_lang" != "en" ]; then
710c535eb59SGordon Tetlow					locpaths="$locpaths:en.$man_charset"
711c535eb59SGordon Tetlow				fi
712c535eb59SGordon Tetlow				locpaths="$locpaths:."
713deeff310SGordon Tetlow				;;
714deeff310SGordon Tetlow		*)		echo 'Unknown locale, assuming C' >&2
715deeff310SGordon Tetlow				;;
716deeff310SGordon Tetlow		esac
717c535eb59SGordon Tetlow	fi
718deeff310SGordon Tetlow
719c535eb59SGordon Tetlow	decho "Using locale paths: $locpaths"
720c535eb59SGordon Tetlow}
721c535eb59SGordon Tetlow
722c535eb59SGordon Tetlow# Usage: man_usage [exitcode]
723c535eb59SGordon Tetlow# Display usage for the man utility.
724c535eb59SGordon Tetlowman_usage() {
725c535eb59SGordon Tetlow	echo 'Usage:'
7261594084fSFernando Apesteguía	echo ' man [-adho] [-t | -w] [-K regexp] [-M manpath] [-P pager] [-S mansect]'
727c535eb59SGordon Tetlow	echo '     [-m arch[:machine]] [-p [eprtv]] [mansect] page [...]'
728c535eb59SGordon Tetlow	echo ' man -f page [...] -- Emulates whatis(1)'
729c535eb59SGordon Tetlow	echo ' man -k page [...] -- Emulates apropos(1)'
730c535eb59SGordon Tetlow
731c535eb59SGordon Tetlow	# When exit'ing with -h, it's not an error.
732c535eb59SGordon Tetlow	exit ${1:-1}
733c535eb59SGordon Tetlow}
734c535eb59SGordon Tetlow
735c535eb59SGordon Tetlow# Usage: parse_configs
736c535eb59SGordon Tetlow# Reads the end-user adjustable config files.
737c535eb59SGordon Tetlowparse_configs() {
738c535eb59SGordon Tetlow	local IFS file files
739c535eb59SGordon Tetlow
740c535eb59SGordon Tetlow	if [ -n "$parsed_configs" ]; then
741c535eb59SGordon Tetlow		return
742c535eb59SGordon Tetlow	fi
743c535eb59SGordon Tetlow
744c535eb59SGordon Tetlow	unset IFS
745c535eb59SGordon Tetlow
746c535eb59SGordon Tetlow	# Read the global config first in case the user wants
747c535eb59SGordon Tetlow	# to override config_local.
748c535eb59SGordon Tetlow	if [ -r "$config_global" ]; then
749c535eb59SGordon Tetlow		parse_file "$config_global"
750c535eb59SGordon Tetlow	fi
751c535eb59SGordon Tetlow
752c535eb59SGordon Tetlow	# Glob the list of files to parse.
753c535eb59SGordon Tetlow	set +f
754c535eb59SGordon Tetlow	files=$(echo $config_local)
755c535eb59SGordon Tetlow	set -f
756c535eb59SGordon Tetlow
757c535eb59SGordon Tetlow	for file in $files; do
758c535eb59SGordon Tetlow		if [ -r "$file" ]; then
759c535eb59SGordon Tetlow			parse_file "$file"
760c535eb59SGordon Tetlow		fi
761c535eb59SGordon Tetlow	done
762c535eb59SGordon Tetlow
763c535eb59SGordon Tetlow	parsed_configs='yes'
764c535eb59SGordon Tetlow}
765c535eb59SGordon Tetlow
766c535eb59SGordon Tetlow# Usage: parse_file file
767c535eb59SGordon Tetlow# Reads the specified config files.
768c535eb59SGordon Tetlowparse_file() {
769c535eb59SGordon Tetlow	local file line tstr var
770c535eb59SGordon Tetlow
771c535eb59SGordon Tetlow	file="$1"
772c535eb59SGordon Tetlow	decho "Parsing config file: $file"
773c535eb59SGordon Tetlow	while read line; do
774c535eb59SGordon Tetlow		decho "  $line" 2
775c535eb59SGordon Tetlow		case "$line" in
776c535eb59SGordon Tetlow		\#*)		decho "    Comment" 3
777c535eb59SGordon Tetlow				;;
778c535eb59SGordon Tetlow		MANPATH*)	decho "    MANPATH" 3
779c535eb59SGordon Tetlow				trim "${line#MANPATH}"
780c535eb59SGordon Tetlow				add_to_manpath "$tstr"
781c535eb59SGordon Tetlow				;;
782c535eb59SGordon Tetlow		MANLOCALE*)	decho "    MANLOCALE" 3
783c535eb59SGordon Tetlow				trim "${line#MANLOCALE}"
784c535eb59SGordon Tetlow				manlocales="$manlocales:$tstr"
785c535eb59SGordon Tetlow				;;
786c535eb59SGordon Tetlow		MANCONFIG*)	decho "    MANCONFIG" 3
787a1528c80SRuslan Ermilov				trim "${line#MANCONFIG}"
788c535eb59SGordon Tetlow				config_local="$tstr"
789c535eb59SGordon Tetlow				;;
790*8edb6fb5SMohamed Akram		MANSECT*)	decho "    MANSECT" 3
791*8edb6fb5SMohamed Akram				trim "${line#MANSECT}"
792*8edb6fb5SMohamed Akram				mansect="$mansect:$tstr"
793*8edb6fb5SMohamed Akram				;;
794c535eb59SGordon Tetlow		# Set variables in the form of FOO_BAR
795c535eb59SGordon Tetlow		*_*[\ \	]*)	var="${line%%[\ \	]*}"
796c535eb59SGordon Tetlow				trim "${line#$var}"
797c535eb59SGordon Tetlow				eval "$var=\"$tstr\""
798c535eb59SGordon Tetlow				decho "    Parsed $var" 3
799c535eb59SGordon Tetlow				;;
800c535eb59SGordon Tetlow		esac
801c535eb59SGordon Tetlow	done < "$file"
802c535eb59SGordon Tetlow}
803c535eb59SGordon Tetlow
804c535eb59SGordon Tetlow# Usage: search_path
805c535eb59SGordon Tetlow# Traverse $PATH looking for manpaths.
806c535eb59SGordon Tetlowsearch_path() {
807c535eb59SGordon Tetlow	local IFS p path
808c535eb59SGordon Tetlow
809c535eb59SGordon Tetlow	decho "Searching PATH for man directories"
810c535eb59SGordon Tetlow
811c535eb59SGordon Tetlow	IFS=:
812c535eb59SGordon Tetlow	for path in $PATH; do
813971c1c42STijl Coosemans		if add_to_manpath "$path/man"; then
814c535eb59SGordon Tetlow			:
815c535eb59SGordon Tetlow		elif add_to_manpath "$path/MAN"; then
816c535eb59SGordon Tetlow			:
817c535eb59SGordon Tetlow		else
818c535eb59SGordon Tetlow			case "$path" in
819971c1c42STijl Coosemans			*/bin)	p="${path%/bin}/share/man"
820c535eb59SGordon Tetlow				add_to_manpath "$p"
821971c1c42STijl Coosemans				p="${path%/bin}/man"
82261d5f2d1SBaptiste Daroussin				add_to_manpath "$p"
823c535eb59SGordon Tetlow				;;
824c535eb59SGordon Tetlow			esac
825c535eb59SGordon Tetlow		fi
826c535eb59SGordon Tetlow	done
827c535eb59SGordon Tetlow	unset IFS
828c535eb59SGordon Tetlow
829c535eb59SGordon Tetlow	if [ -z "$manpath" ]; then
830c535eb59SGordon Tetlow		decho '  Unable to find any manpaths, using default'
831c535eb59SGordon Tetlow		manpath=$man_default_path
832c535eb59SGordon Tetlow	fi
833c535eb59SGordon Tetlow}
834c535eb59SGordon Tetlow
835c535eb59SGordon Tetlow# Usage: search_whatis cmd [arglist]
836c535eb59SGordon Tetlow# Do the heavy lifting for apropos/whatis
837c535eb59SGordon Tetlowsearch_whatis() {
838c535eb59SGordon Tetlow	local IFS bad cmd f good key keywords loc opt out path rval wlist
839c535eb59SGordon Tetlow
840c535eb59SGordon Tetlow	cmd="$1"
841c535eb59SGordon Tetlow	shift
842c535eb59SGordon Tetlow
843c535eb59SGordon Tetlow	whatis_parse_args "$@"
844c535eb59SGordon Tetlow
845c535eb59SGordon Tetlow	build_manpath
846c535eb59SGordon Tetlow	build_manlocales
847c535eb59SGordon Tetlow	setup_pager
848c535eb59SGordon Tetlow
849c535eb59SGordon Tetlow	if [ "$cmd" = "whatis" ]; then
850c535eb59SGordon Tetlow		opt="-w"
851c535eb59SGordon Tetlow	fi
852c535eb59SGordon Tetlow
853c535eb59SGordon Tetlow	f='whatis'
854c535eb59SGordon Tetlow
855c535eb59SGordon Tetlow	IFS=:
856c535eb59SGordon Tetlow	for path in $MANPATH; do
857c535eb59SGordon Tetlow		if [ \! -d "$path" ]; then
858c535eb59SGordon Tetlow			decho "Skipping non-existent path: $path" 2
859c535eb59SGordon Tetlow			continue
860c535eb59SGordon Tetlow		fi
861c535eb59SGordon Tetlow
862c535eb59SGordon Tetlow		if [ -f "$path/$f" -a -r "$path/$f" ]; then
863c535eb59SGordon Tetlow			decho "Found whatis: $path/$f"
864c535eb59SGordon Tetlow			wlist="$wlist $path/$f"
865c535eb59SGordon Tetlow		fi
866c535eb59SGordon Tetlow
867c535eb59SGordon Tetlow		for loc in $MANLOCALES; do
868c535eb59SGordon Tetlow			if [ -f "$path/$loc/$f" -a -r "$path/$loc/$f" ]; then
869c535eb59SGordon Tetlow				decho "Found whatis: $path/$loc/$f"
870c535eb59SGordon Tetlow				wlist="$wlist $path/$loc/$f"
871c535eb59SGordon Tetlow			fi
872c535eb59SGordon Tetlow		done
873c535eb59SGordon Tetlow	done
874c535eb59SGordon Tetlow	unset IFS
875c535eb59SGordon Tetlow
876c535eb59SGordon Tetlow	if [ -z "$wlist" ]; then
877c535eb59SGordon Tetlow		echo "$cmd: no whatis databases in $MANPATH" >&2
878c535eb59SGordon Tetlow		exit 1
879c535eb59SGordon Tetlow	fi
880c535eb59SGordon Tetlow
881c535eb59SGordon Tetlow	rval=0
882c535eb59SGordon Tetlow	for key in $keywords; do
883c535eb59SGordon Tetlow		out=$(grep -Ehi $opt -- "$key" $wlist)
884c535eb59SGordon Tetlow		if [ -n "$out" ]; then
885c535eb59SGordon Tetlow			good="$good\\n$out"
886c535eb59SGordon Tetlow		else
887c535eb59SGordon Tetlow			bad="$bad\\n$key: nothing appropriate"
888c535eb59SGordon Tetlow			rval=1
889c535eb59SGordon Tetlow		fi
890c535eb59SGordon Tetlow	done
891c535eb59SGordon Tetlow
892c535eb59SGordon Tetlow	# Strip leading carriage return.
893c535eb59SGordon Tetlow	good=${good#\\n}
894c535eb59SGordon Tetlow	bad=${bad#\\n}
895c535eb59SGordon Tetlow
896c535eb59SGordon Tetlow	if [ -n "$good" ]; then
897a6a3e856SRuslan Ermilov		echo -e "$good" | $MANPAGER
898c535eb59SGordon Tetlow	fi
899c535eb59SGordon Tetlow
900c535eb59SGordon Tetlow	if [ -n "$bad" ]; then
90100e05e69SGordon Tetlow		echo -e "$bad" >&2
902c535eb59SGordon Tetlow	fi
903c535eb59SGordon Tetlow
904c535eb59SGordon Tetlow	exit $rval
905c535eb59SGordon Tetlow}
906c535eb59SGordon Tetlow
90757cd9717SGordon Tetlow# Usage: setup_cattool page
90857cd9717SGordon Tetlow# Finds an appropriate decompressor based on extension
90957cd9717SGordon Tetlowsetup_cattool() {
91057cd9717SGordon Tetlow	case "$1" in
91157cd9717SGordon Tetlow	*.bz)	cattool='/usr/bin/bzcat' ;;
91257cd9717SGordon Tetlow	*.bz2)	cattool='/usr/bin/bzcat' ;;
91357cd9717SGordon Tetlow	*.gz)	cattool='/usr/bin/zcat' ;;
91457cd9717SGordon Tetlow	*.lzma)	cattool='/usr/bin/lzcat' ;;
91557cd9717SGordon Tetlow	*.xz)	cattool='/usr/bin/xzcat' ;;
916c8abb673SCameron Katri	*.zst)	cattool='/usr/bin/zstdcat' ;;
91757cd9717SGordon Tetlow	*)	cattool='/usr/bin/zcat -f' ;;
91857cd9717SGordon Tetlow	esac
91957cd9717SGordon Tetlow}
92057cd9717SGordon Tetlow
921c535eb59SGordon Tetlow# Usage: setup_pager
922a6a3e856SRuslan Ermilov# Correctly sets $MANPAGER
923c535eb59SGordon Tetlowsetup_pager() {
924c535eb59SGordon Tetlow	# Setup pager.
925a6a3e856SRuslan Ermilov	if [ -z "$MANPAGER" ]; then
926a6a3e856SRuslan Ermilov		if [ -n "$MANCOLOR" ]; then
927a6a3e856SRuslan Ermilov			MANPAGER="less -sR"
928a6a3e856SRuslan Ermilov		else
929a6a3e856SRuslan Ermilov			if [ -n "$PAGER" ]; then
930a6a3e856SRuslan Ermilov				MANPAGER="$PAGER"
931a6a3e856SRuslan Ermilov			else
93247cc9ee1SAlan Somers				MANPAGER="less -s"
933c535eb59SGordon Tetlow			fi
934a6a3e856SRuslan Ermilov		fi
935a6a3e856SRuslan Ermilov	fi
936a6a3e856SRuslan Ermilov	decho "Using pager: $MANPAGER"
937c535eb59SGordon Tetlow}
938c535eb59SGordon Tetlow
939c535eb59SGordon Tetlow# Usage: trim string
940c535eb59SGordon Tetlow# Trims whitespace from beginning and end of a variable
941c535eb59SGordon Tetlowtrim() {
942c535eb59SGordon Tetlow	tstr=$1
943c535eb59SGordon Tetlow	while true; do
944c535eb59SGordon Tetlow		case "$tstr" in
945c535eb59SGordon Tetlow		[\ \	]*)	tstr="${tstr##[\ \	]}" ;;
946c535eb59SGordon Tetlow		*[\ \	])	tstr="${tstr%%[\ \	]}" ;;
947c535eb59SGordon Tetlow		*)		break ;;
948c535eb59SGordon Tetlow		esac
949c535eb59SGordon Tetlow	done
950c535eb59SGordon Tetlow}
951c535eb59SGordon Tetlow
952c535eb59SGordon Tetlow# Usage: whatis_parse_args "$@"
953c535eb59SGordon Tetlow# Parse commandline args for whatis and apropos.
954c535eb59SGordon Tetlowwhatis_parse_args() {
955c535eb59SGordon Tetlow	local cmd_arg
956f555b39eSKyle Evans	OPTIND=1
957c535eb59SGordon Tetlow	while getopts 'd' cmd_arg; do
958c535eb59SGordon Tetlow		case "${cmd_arg}" in
959c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
960c535eb59SGordon Tetlow		*)	whatis_usage ;;
961c535eb59SGordon Tetlow		esac
962c535eb59SGordon Tetlow	done >&2
963c535eb59SGordon Tetlow
964c535eb59SGordon Tetlow	shift $(( $OPTIND - 1 ))
965c535eb59SGordon Tetlow
966c535eb59SGordon Tetlow	keywords="$*"
967c535eb59SGordon Tetlow}
968c535eb59SGordon Tetlow
969c535eb59SGordon Tetlow# Usage: whatis_usage
970c535eb59SGordon Tetlow# Display usage for the whatis/apropos utility.
971c535eb59SGordon Tetlowwhatis_usage() {
972c535eb59SGordon Tetlow	echo "usage: $cmd [-d] keyword [...]"
973c535eb59SGordon Tetlow	exit 1
974c535eb59SGordon Tetlow}
975c535eb59SGordon Tetlow
976c535eb59SGordon Tetlow
977c535eb59SGordon Tetlow
978c535eb59SGordon Tetlow# Supported commands
979c535eb59SGordon Tetlowdo_apropos() {
98024ef7420SBaptiste Daroussin	[ $(stat -f %i /usr/bin/man) -ne $(stat -f %i /usr/bin/apropos) ] && \
981772246efSBaptiste Daroussin		exec apropos "$@"
982c535eb59SGordon Tetlow	search_whatis apropos "$@"
983c535eb59SGordon Tetlow}
984c535eb59SGordon Tetlow
9851594084fSFernando Apesteguía# Usage: do_full_search reg_exp
9861594084fSFernando Apesteguía# Do a full search of the regular expression passed
9871594084fSFernando Apesteguía# as parameter in all man pages
9881594084fSFernando Apesteguíado_full_search() {
9891594084fSFernando Apesteguía	local gflags re
9901594084fSFernando Apesteguía	re=${1}
9911594084fSFernando Apesteguía
9921594084fSFernando Apesteguía	# Build grep(1) flags
9931594084fSFernando Apesteguía	gflags="-H"
9941594084fSFernando Apesteguía
9951594084fSFernando Apesteguía	# wflag implies -l for grep(1)
9961594084fSFernando Apesteguía	if [ -n "$wflag" ]; then
9971594084fSFernando Apesteguía		gflags="${gflags} -l"
9981594084fSFernando Apesteguía	fi
9991594084fSFernando Apesteguía
10001594084fSFernando Apesteguía	gflags="${gflags} --label"
10011594084fSFernando Apesteguía
10021594084fSFernando Apesteguía	set +f
10031594084fSFernando Apesteguía	for mpath in $(echo "${MANPATH}" | tr : [:blank:]); do
10041594084fSFernando Apesteguía		for section in $(echo "${MANSECT}" | tr : [:blank:]); do
10051594084fSFernando Apesteguía			for manfile in ${mpath}/man${section}/*.${section}*; do
10061594084fSFernando Apesteguía				mandoc "${manfile}" 2>/dev/null |
10071594084fSFernando Apesteguía					grep -E ${gflags} "${manfile}" -e ${re}
10081594084fSFernando Apesteguía			done
10091594084fSFernando Apesteguía		done
10101594084fSFernando Apesteguía	done
10111594084fSFernando Apesteguía	set -f
10121594084fSFernando Apesteguía}
10131594084fSFernando Apesteguía
1014c535eb59SGordon Tetlowdo_man() {
1015*8edb6fb5SMohamed Akram	local IFS
1016*8edb6fb5SMohamed Akram
1017*8edb6fb5SMohamed Akram	man_parse_opts "$@"
1018*8edb6fb5SMohamed Akram	man_setup
1019*8edb6fb5SMohamed Akram
1020*8edb6fb5SMohamed Akram	shift $(( $OPTIND - 1 ))
1021*8edb6fb5SMohamed Akram	IFS=:
1022*8edb6fb5SMohamed Akram	for sect in $MANSECT; do
1023*8edb6fb5SMohamed Akram		if [ "$sect" = "$1" ]; then
1024*8edb6fb5SMohamed Akram			decho "Detected manual section as first arg: $1"
1025*8edb6fb5SMohamed Akram			MANSECT="$1"
1026*8edb6fb5SMohamed Akram			shift
1027*8edb6fb5SMohamed Akram			break
1028*8edb6fb5SMohamed Akram		fi
1029*8edb6fb5SMohamed Akram	done
1030*8edb6fb5SMohamed Akram	unset IFS
1031*8edb6fb5SMohamed Akram	pages="$*"
1032*8edb6fb5SMohamed Akram
10331594084fSFernando Apesteguía	if [ -z "$pages" -a -z "${Kflag}" ]; then
1034c535eb59SGordon Tetlow		echo 'What manual page do you want?' >&2
1035c535eb59SGordon Tetlow		exit 1
1036c535eb59SGordon Tetlow	fi
1037c535eb59SGordon Tetlow
10381594084fSFernando Apesteguía	if [ ! -z "${Kflag}" ]; then
10391594084fSFernando Apesteguía		# Short circuit because -K flag does a sufficiently
10401594084fSFernando Apesteguía		# different thing like not showing the man page at all
10411594084fSFernando Apesteguía		do_full_search "${REGEXP}"
10421594084fSFernando Apesteguía	fi
10431594084fSFernando Apesteguía
1044c535eb59SGordon Tetlow	for page in $pages; do
1045c535eb59SGordon Tetlow		decho "Searching for $page"
1046c535eb59SGordon Tetlow		man_find_and_display "$page"
1047c535eb59SGordon Tetlow	done
1048c535eb59SGordon Tetlow
1049c535eb59SGordon Tetlow	exit ${ret:-0}
1050c535eb59SGordon Tetlow}
1051c535eb59SGordon Tetlow
1052c535eb59SGordon Tetlowdo_manpath() {
1053c535eb59SGordon Tetlow	manpath_parse_args "$@"
1054c535eb59SGordon Tetlow	if [ -z "$qflag" ]; then
1055c535eb59SGordon Tetlow		manpath_warnings
1056c535eb59SGordon Tetlow	fi
1057c535eb59SGordon Tetlow	if [ -n "$Lflag" ]; then
1058c535eb59SGordon Tetlow		build_manlocales
1059c535eb59SGordon Tetlow		echo $MANLOCALES
1060c535eb59SGordon Tetlow	else
1061c535eb59SGordon Tetlow		build_manpath
1062c535eb59SGordon Tetlow		echo $MANPATH
1063c535eb59SGordon Tetlow	fi
1064c535eb59SGordon Tetlow	exit 0
1065c535eb59SGordon Tetlow}
1066c535eb59SGordon Tetlow
1067c535eb59SGordon Tetlowdo_whatis() {
106824ef7420SBaptiste Daroussin	[ $(stat -f %i /usr/bin/man) -ne $(stat -f %i /usr/bin/whatis) ] && \
1069772246efSBaptiste Daroussin		exec whatis "$@"
1070c535eb59SGordon Tetlow	search_whatis whatis "$@"
1071c535eb59SGordon Tetlow}
1072c535eb59SGordon Tetlow
1073aeea395eSUlrich Spörlein# User's PATH setting decides on the groff-suite to pick up.
1074aeea395eSUlrich SpörleinEQN=eqn
1075a6a3e856SRuslan ErmilovNROFF='groff -S -P-h -Wall -mtty-char -man'
1076aeea395eSUlrich SpörleinPIC=pic
1077aeea395eSUlrich SpörleinREFER=refer
1078aeea395eSUlrich SpörleinTBL=tbl
10793d120968SUlrich SpörleinTROFF='groff -S -man'
1080aeea395eSUlrich SpörleinVGRIND=vgrind
1081aeea395eSUlrich Spörlein
1082deeff310SGordon TetlowLOCALE=/usr/bin/locale
1083a0094449SRuslan ErmilovSTTY=/bin/stty
108482db8a5eSGordon TetlowSYSCTL=/sbin/sysctl
1085c535eb59SGordon Tetlow
1086c535eb59SGordon Tetlowdebug=0
108773577bf0SRyan Moellerman_default_sections='1:8:2:3:3lua:n:4:5:6:7:9:l'
1088971c1c42STijl Coosemansman_default_path='/usr/share/man:/usr/share/openssl/man:/usr/local/share/man:/usr/local/man'
108957cd9717SGordon Tetlowcattool='/usr/bin/zcat -f'
1090c535eb59SGordon Tetlow
1091c535eb59SGordon Tetlowconfig_global='/etc/man.conf'
1092c535eb59SGordon Tetlow
1093c535eb59SGordon Tetlow# This can be overridden via a setting in /etc/man.conf.
1094c535eb59SGordon Tetlowconfig_local='/usr/local/etc/man.d/*.conf'
1095c535eb59SGordon Tetlow
1096c535eb59SGordon Tetlow# Set noglobbing for now. I don't want spurious globbing.
1097c535eb59SGordon Tetlowset -f
1098c535eb59SGordon Tetlow
1099c535eb59SGordon Tetlowcase "$0" in
1100c535eb59SGordon Tetlow*apropos)	do_apropos "$@" ;;
1101c535eb59SGordon Tetlow*manpath)	do_manpath "$@" ;;
1102c535eb59SGordon Tetlow*whatis)	do_whatis "$@" ;;
1103c535eb59SGordon Tetlow*)		do_man "$@" ;;
1104c535eb59SGordon Tetlowesac
1105