xref: /dflybsd-src/usr.bin/man/man.sh (revision a3b5347fe41709204f58820e4956595225e546c6)
1cde00b53SSascha Wildner#! /bin/sh
2cde00b53SSascha Wildner#
3cde00b53SSascha Wildner# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4cde00b53SSascha Wildner#
5cde00b53SSascha Wildner#  Copyright (c) 2010 Gordon Tetlow
6cde00b53SSascha Wildner#  All rights reserved.
7cde00b53SSascha Wildner#
8cde00b53SSascha Wildner#  Redistribution and use in source and binary forms, with or without
9cde00b53SSascha Wildner#  modification, are permitted provided that the following conditions
10cde00b53SSascha Wildner#  are met:
11cde00b53SSascha Wildner#  1. Redistributions of source code must retain the above copyright
12cde00b53SSascha Wildner#     notice, this list of conditions and the following disclaimer.
13cde00b53SSascha Wildner#  2. Redistributions in binary form must reproduce the above copyright
14cde00b53SSascha Wildner#     notice, this list of conditions and the following disclaimer in the
15cde00b53SSascha Wildner#     documentation and/or other materials provided with the distribution.
16cde00b53SSascha Wildner#
17cde00b53SSascha Wildner#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18cde00b53SSascha Wildner#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19cde00b53SSascha Wildner#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20cde00b53SSascha Wildner#  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21cde00b53SSascha Wildner#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22cde00b53SSascha Wildner#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23cde00b53SSascha Wildner#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24cde00b53SSascha Wildner#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25cde00b53SSascha Wildner#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26cde00b53SSascha Wildner#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27cde00b53SSascha Wildner#  SUCH DAMAGE.
28cde00b53SSascha Wildner#
29cde00b53SSascha Wildner# $FreeBSD: head/usr.bin/man/man.sh 340128 2018-11-04 16:58:55Z yuripv $
30cde00b53SSascha Wildner
31cde00b53SSascha Wildner# Usage: add_to_manpath path
32cde00b53SSascha Wildner# Adds a variable to manpath while ensuring we don't have duplicates.
33cde00b53SSascha Wildner# Returns true if we were able to add something. False otherwise.
34cde00b53SSascha Wildneradd_to_manpath() {
35cde00b53SSascha Wildner	case "$manpath" in
36cde00b53SSascha Wildner	*:$1)	decho "  Skipping duplicate manpath entry $1" 2 ;;
37cde00b53SSascha Wildner	$1:*)	decho "  Skipping duplicate manpath entry $1" 2 ;;
38cde00b53SSascha Wildner	*:$1:*)	decho "  Skipping duplicate manpath entry $1" 2 ;;
39cde00b53SSascha Wildner	*)	if [ -d "$1" ]; then
40cde00b53SSascha Wildner			decho "  Adding $1 to manpath"
41cde00b53SSascha Wildner			manpath="$manpath:$1"
42cde00b53SSascha Wildner			return 0
43cde00b53SSascha Wildner		fi
44cde00b53SSascha Wildner		;;
45cde00b53SSascha Wildner	esac
46cde00b53SSascha Wildner
47cde00b53SSascha Wildner	return 1
48cde00b53SSascha Wildner}
49cde00b53SSascha Wildner
50cde00b53SSascha Wildner# Usage: build_manlocales
51cde00b53SSascha Wildner# Builds a correct MANLOCALES variable.
52cde00b53SSascha Wildnerbuild_manlocales() {
53cde00b53SSascha Wildner	# If the user has set manlocales, who are we to argue.
54cde00b53SSascha Wildner	if [ -n "$MANLOCALES" ]; then
55cde00b53SSascha Wildner		return
56cde00b53SSascha Wildner	fi
57cde00b53SSascha Wildner
58cde00b53SSascha Wildner	parse_configs
59cde00b53SSascha Wildner
60cde00b53SSascha Wildner	# Trim leading colon
61cde00b53SSascha Wildner	MANLOCALES=${manlocales#:}
62cde00b53SSascha Wildner
63cde00b53SSascha Wildner	decho "Available manual locales: $MANLOCALES"
64cde00b53SSascha Wildner}
65cde00b53SSascha Wildner
66cde00b53SSascha Wildner# Usage: build_manpath
67cde00b53SSascha Wildner# Builds a correct MANPATH variable.
68cde00b53SSascha Wildnerbuild_manpath() {
69cde00b53SSascha Wildner	local IFS
70cde00b53SSascha Wildner
71cde00b53SSascha Wildner	# If the user has set a manpath, who are we to argue.
72cde00b53SSascha Wildner	if [ -n "$MANPATH" ]; then
73cde00b53SSascha Wildner		case "$MANPATH" in
74cde00b53SSascha Wildner		*:) PREPEND_MANPATH=${MANPATH} ;;
75cde00b53SSascha Wildner		:*) APPEND_MANPATH=${MANPATH} ;;
76cde00b53SSascha Wildner		*::*)
77cde00b53SSascha Wildner			PREPEND_MANPATH=${MANPATH%%::*}
78cde00b53SSascha Wildner			APPEND_MANPATH=${MANPATH#*::}
79cde00b53SSascha Wildner			;;
80cde00b53SSascha Wildner		*) return ;;
81cde00b53SSascha Wildner		esac
82cde00b53SSascha Wildner	fi
83cde00b53SSascha Wildner
84cde00b53SSascha Wildner	if [ -n "$PREPEND_MANPATH" ]; then
85cde00b53SSascha Wildner		IFS=:
86cde00b53SSascha Wildner		for path in $PREPEND_MANPATH; do
87cde00b53SSascha Wildner			add_to_manpath "$path"
88cde00b53SSascha Wildner		done
89cde00b53SSascha Wildner		unset IFS
90cde00b53SSascha Wildner	fi
91cde00b53SSascha Wildner
92cde00b53SSascha Wildner	search_path
93cde00b53SSascha Wildner
94cde00b53SSascha Wildner	decho "Adding default manpath entries"
95cde00b53SSascha Wildner	IFS=:
96cde00b53SSascha Wildner	for path in $man_default_path; do
97cde00b53SSascha Wildner		add_to_manpath "$path"
98cde00b53SSascha Wildner	done
99cde00b53SSascha Wildner	unset IFS
100cde00b53SSascha Wildner
101cde00b53SSascha Wildner	parse_configs
102cde00b53SSascha Wildner
103cde00b53SSascha Wildner	if [ -n "$APPEND_MANPATH" ]; then
104cde00b53SSascha Wildner		IFS=:
105cde00b53SSascha Wildner		for path in $APPEND_MANPATH; do
106cde00b53SSascha Wildner			add_to_manpath "$path"
107cde00b53SSascha Wildner		done
108cde00b53SSascha Wildner		unset IFS
109cde00b53SSascha Wildner	fi
110cde00b53SSascha Wildner	# Trim leading colon
111cde00b53SSascha Wildner	MANPATH=${manpath#:}
112cde00b53SSascha Wildner
113cde00b53SSascha Wildner	decho "Using manual path: $MANPATH"
114cde00b53SSascha Wildner}
115cde00b53SSascha Wildner
116cde00b53SSascha Wildner# Usage: check_cat catglob
117cde00b53SSascha Wildner# Checks to see if a cat glob is available.
118cde00b53SSascha Wildnercheck_cat() {
119cde00b53SSascha Wildner	if exists "$1"; then
120cde00b53SSascha Wildner		use_cat=yes
121cde00b53SSascha Wildner		catpage=$found
122cde00b53SSascha Wildner		setup_cattool $catpage
123cde00b53SSascha Wildner		decho "    Found catpage $catpage"
124cde00b53SSascha Wildner		return 0
125cde00b53SSascha Wildner	else
126cde00b53SSascha Wildner		return 1
127cde00b53SSascha Wildner	fi
128cde00b53SSascha Wildner}
129cde00b53SSascha Wildner
130cde00b53SSascha Wildner# Usage: check_man manglob catglob
131cde00b53SSascha Wildner# Given 2 globs, figures out if the manglob is available, if so, check to
132cde00b53SSascha Wildner# see if the catglob is also available and up to date.
133cde00b53SSascha Wildnercheck_man() {
134cde00b53SSascha Wildner	if exists "$1"; then
135cde00b53SSascha Wildner		# We have a match, check for a cat page
136cde00b53SSascha Wildner		manpage=$found
137cde00b53SSascha Wildner		setup_cattool $manpage
138cde00b53SSascha Wildner		decho "    Found manpage $manpage"
139cde00b53SSascha Wildner
140cde00b53SSascha Wildner		if [ -n "${use_width}" ]; then
141cde00b53SSascha Wildner			# non-standard width
142cde00b53SSascha Wildner			unset use_cat
143cde00b53SSascha Wildner			decho "    Skipping catpage: non-standard page width"
144cde00b53SSascha Wildner		elif exists "$2" && is_newer $found $manpage; then
145cde00b53SSascha Wildner			# cat page found and is newer, use that
146cde00b53SSascha Wildner			use_cat=yes
147cde00b53SSascha Wildner			catpage=$found
148cde00b53SSascha Wildner			setup_cattool $catpage
149cde00b53SSascha Wildner			decho "    Using catpage $catpage"
150cde00b53SSascha Wildner		else
151cde00b53SSascha Wildner			# no cat page or is older
152cde00b53SSascha Wildner			unset use_cat
153cde00b53SSascha Wildner			decho "    Skipping catpage: not found or old"
154cde00b53SSascha Wildner		fi
155cde00b53SSascha Wildner		return 0
156cde00b53SSascha Wildner	fi
157cde00b53SSascha Wildner
158cde00b53SSascha Wildner	return 1
159cde00b53SSascha Wildner}
160cde00b53SSascha Wildner
161cde00b53SSascha Wildner# Usage: decho "string" [debuglevel]
162cde00b53SSascha Wildner# Echoes to stderr string prefaced with -- if high enough debuglevel.
163cde00b53SSascha Wildnerdecho() {
164cde00b53SSascha Wildner	if [ $debug -ge ${2:-1} ]; then
165cde00b53SSascha Wildner		echo "-- $1" >&2
166cde00b53SSascha Wildner	fi
167cde00b53SSascha Wildner}
168cde00b53SSascha Wildner
169cde00b53SSascha Wildner# Usage: exists glob
170cde00b53SSascha Wildner# Returns true if glob resolves to a real file.
171cde00b53SSascha Wildnerexists() {
172cde00b53SSascha Wildner	local IFS
173cde00b53SSascha Wildner
174cde00b53SSascha Wildner	# Don't accidentally inherit callers IFS (breaks perl manpages)
175cde00b53SSascha Wildner	unset IFS
176cde00b53SSascha Wildner
177cde00b53SSascha Wildner	# Use some globbing tricks in the shell to determine if a file
178cde00b53SSascha Wildner	# exists or not.
179cde00b53SSascha Wildner	set +f
180cde00b53SSascha Wildner	set -- "$1" $1
181cde00b53SSascha Wildner	set -f
182cde00b53SSascha Wildner
183cde00b53SSascha Wildner	if [ "$1" != "$2" -a -r "$2" ]; then
184cde00b53SSascha Wildner		found="$2"
185cde00b53SSascha Wildner		return 0
186cde00b53SSascha Wildner	fi
187cde00b53SSascha Wildner
188cde00b53SSascha Wildner	return 1
189cde00b53SSascha Wildner}
190cde00b53SSascha Wildner
191cde00b53SSascha Wildner# Usage: find_file path section subdir pagename
192cde00b53SSascha Wildner# Returns: true if something is matched and found.
193cde00b53SSascha Wildner# Search the given path/section combo for a given page.
194cde00b53SSascha Wildnerfind_file() {
195cde00b53SSascha Wildner	local manroot catroot mann man0 catn cat0
196cde00b53SSascha Wildner
197cde00b53SSascha Wildner	manroot="$1/man$2"
198cde00b53SSascha Wildner	catroot="$1/cat$2"
199cde00b53SSascha Wildner	if [ -n "$3" ]; then
200cde00b53SSascha Wildner		manroot="$manroot/$3"
201cde00b53SSascha Wildner		catroot="$catroot/$3"
202cde00b53SSascha Wildner	fi
203cde00b53SSascha Wildner
204cde00b53SSascha Wildner	if [ ! -d "$manroot" -a ! -d "$catroot" ]; then
205cde00b53SSascha Wildner		return 1
206cde00b53SSascha Wildner	fi
207cde00b53SSascha Wildner	decho "  Searching directory $manroot" 2
208cde00b53SSascha Wildner
209cde00b53SSascha Wildner	mann="$manroot/$4.$2*"
210cde00b53SSascha Wildner	man0="$manroot/$4.0*"
211cde00b53SSascha Wildner	catn="$catroot/$4.$2*"
212cde00b53SSascha Wildner	cat0="$catroot/$4.0*"
213cde00b53SSascha Wildner
214cde00b53SSascha Wildner	# This is the behavior as seen by the original man utility.
215cde00b53SSascha Wildner	# Let's not change that which doesn't seem broken.
216cde00b53SSascha Wildner	if check_man "$mann" "$catn"; then
217cde00b53SSascha Wildner		return 0
218cde00b53SSascha Wildner	elif check_man "$man0" "$cat0"; then
219cde00b53SSascha Wildner		return 0
220cde00b53SSascha Wildner	elif check_cat "$catn"; then
221cde00b53SSascha Wildner		return 0
222cde00b53SSascha Wildner	elif check_cat "$cat0"; then
223cde00b53SSascha Wildner		return 0
224cde00b53SSascha Wildner	fi
225cde00b53SSascha Wildner
226cde00b53SSascha Wildner	return 1
227cde00b53SSascha Wildner}
228cde00b53SSascha Wildner
229cde00b53SSascha Wildner# Usage: is_newer file1 file2
230cde00b53SSascha Wildner# Returns true if file1 is newer than file2 as calculated by mtime.
231cde00b53SSascha Wildneris_newer() {
232cde00b53SSascha Wildner	if ! [ "$1" -ot "$2" ]; then
233cde00b53SSascha Wildner		decho "    mtime: $1 not older than $2" 3
234cde00b53SSascha Wildner		return 0
235cde00b53SSascha Wildner	else
236cde00b53SSascha Wildner		decho "    mtime: $1 older than $2" 3
237cde00b53SSascha Wildner		return 1
238cde00b53SSascha Wildner	fi
239cde00b53SSascha Wildner}
240cde00b53SSascha Wildner
241cde00b53SSascha Wildner# Usage: manpath_parse_args "$@"
242cde00b53SSascha Wildner# Parses commandline options for manpath.
243cde00b53SSascha Wildnermanpath_parse_args() {
244cde00b53SSascha Wildner	local cmd_arg
245cde00b53SSascha Wildner
246cde00b53SSascha Wildner	while getopts 'Ldq' cmd_arg; do
247cde00b53SSascha Wildner		case "${cmd_arg}" in
248cde00b53SSascha Wildner		L)	Lflag=Lflag ;;
249cde00b53SSascha Wildner		d)	debug=$(( $debug + 1 )) ;;
250cde00b53SSascha Wildner		q)	qflag=qflag ;;
251cde00b53SSascha Wildner		*)	manpath_usage ;;
252cde00b53SSascha Wildner		esac
253cde00b53SSascha Wildner	done >&2
254cde00b53SSascha Wildner}
255cde00b53SSascha Wildner
256cde00b53SSascha Wildner# Usage: manpath_usage
257cde00b53SSascha Wildner# Display usage for the manpath(1) utility.
258cde00b53SSascha Wildnermanpath_usage() {
259cde00b53SSascha Wildner	echo 'usage: manpath [-Ldq]' >&2
260cde00b53SSascha Wildner	exit 1
261cde00b53SSascha Wildner}
262cde00b53SSascha Wildner
263cde00b53SSascha Wildner# Usage: manpath_warnings
264cde00b53SSascha Wildner# Display some warnings to stderr.
265cde00b53SSascha Wildnermanpath_warnings() {
266cde00b53SSascha Wildner	if [ -n "$Lflag" -a -n "$MANLOCALES" ]; then
267cde00b53SSascha Wildner		echo "(Warning: MANLOCALES environment variable set)" >&2
268cde00b53SSascha Wildner	fi
269cde00b53SSascha Wildner}
270cde00b53SSascha Wildner
271cde00b53SSascha Wildner# Usage: man_check_for_so page path
272cde00b53SSascha Wildner# Returns: True if able to resolve the file, false if it ended in tears.
273cde00b53SSascha Wildner# Detects the presence of the .so directive and causes the file to be
274cde00b53SSascha Wildner# redirected to another source file.
275cde00b53SSascha Wildnerman_check_for_so() {
276cde00b53SSascha Wildner	local IFS line tstr
277cde00b53SSascha Wildner
278cde00b53SSascha Wildner	unset IFS
279cde00b53SSascha Wildner	if [ -n "$catpage" ]; then
280cde00b53SSascha Wildner		return 0
281cde00b53SSascha Wildner	fi
282cde00b53SSascha Wildner
283cde00b53SSascha Wildner	# We need to loop to accommodate multiple .so directives.
284cde00b53SSascha Wildner	while true
285cde00b53SSascha Wildner	do
286cde00b53SSascha Wildner		line=$($cattool $manpage | head -1)
287cde00b53SSascha Wildner		case "$line" in
288cde00b53SSascha Wildner		.so*)	trim "${line#.so}"
289cde00b53SSascha Wildner			decho "$manpage includes $tstr"
290cde00b53SSascha Wildner			# Glob and check for the file.
291cde00b53SSascha Wildner			if ! check_man "$path/$tstr*" ""; then
292cde00b53SSascha Wildner				decho "  Unable to find $tstr"
293cde00b53SSascha Wildner				return 1
294cde00b53SSascha Wildner			fi
295cde00b53SSascha Wildner			;;
296cde00b53SSascha Wildner		*)	break ;;
297cde00b53SSascha Wildner		esac
298cde00b53SSascha Wildner	done
299cde00b53SSascha Wildner
300cde00b53SSascha Wildner	return 0
301cde00b53SSascha Wildner}
302cde00b53SSascha Wildner
303cde00b53SSascha Wildner# Usage: man_display_page
304cde00b53SSascha Wildner# Display either the manpage or catpage depending on the use_cat variable
305cde00b53SSascha Wildnerman_display_page() {
306cde00b53SSascha Wildner	local IFS pipeline testline
307cde00b53SSascha Wildner
308cde00b53SSascha Wildner	# We are called with IFS set to colon. This causes really weird
309cde00b53SSascha Wildner	# things to happen for the variables that have spaces in them.
310cde00b53SSascha Wildner	unset IFS
311cde00b53SSascha Wildner
312cde00b53SSascha Wildner	# If we are supposed to use a catpage and we aren't using troff(1)
313cde00b53SSascha Wildner	# just zcat the catpage and we are done.
314cde00b53SSascha Wildner	if [ -z "$tflag" -a -n "$use_cat" ]; then
315cde00b53SSascha Wildner		if [ -n "$wflag" ]; then
316cde00b53SSascha Wildner			echo "$catpage (source: $manpage)"
317cde00b53SSascha Wildner			ret=0
318cde00b53SSascha Wildner		else
319cde00b53SSascha Wildner			if [ $debug -gt 0 ]; then
320cde00b53SSascha Wildner				decho "Command: $cattool $catpage | $MANPAGER"
321cde00b53SSascha Wildner				ret=0
322cde00b53SSascha Wildner			else
323cde00b53SSascha Wildner				eval "$cattool $catpage | $MANPAGER"
324cde00b53SSascha Wildner				ret=$?
325cde00b53SSascha Wildner			fi
326cde00b53SSascha Wildner		fi
327cde00b53SSascha Wildner		return
328cde00b53SSascha Wildner	fi
329cde00b53SSascha Wildner
330cde00b53SSascha Wildner	# Okay, we are using the manpage, do we just need to output the
331cde00b53SSascha Wildner	# name of the manpage?
332cde00b53SSascha Wildner	if [ -n "$wflag" ]; then
333cde00b53SSascha Wildner		echo "$manpage"
334cde00b53SSascha Wildner		ret=0
335cde00b53SSascha Wildner		return
336cde00b53SSascha Wildner	fi
337cde00b53SSascha Wildner
338cde00b53SSascha Wildner	if [ -n "$use_width" ]; then
339cde00b53SSascha Wildner		mandoc_args="-O width=${use_width}"
340cde00b53SSascha Wildner	fi
341cde00b53SSascha Wildner	testline="mandoc -Tlint -Wunsupp >/dev/null 2>&1"
342cde00b53SSascha Wildner	if [ -n "$tflag" ]; then
343cde00b53SSascha Wildner		pipeline="mandoc -Tps $mandoc_args"
344cde00b53SSascha Wildner	else
345cde00b53SSascha Wildner		pipeline="mandoc $mandoc_args | $MANPAGER"
346cde00b53SSascha Wildner	fi
347cde00b53SSascha Wildner
348cde00b53SSascha Wildner	if ! eval "$cattool $manpage | $testline" ;then
349cde00b53SSascha Wildner		if which -s groff; then
350cde00b53SSascha Wildner			man_display_page_groff
351cde00b53SSascha Wildner		else
352cde00b53SSascha Wildner			echo "This manpage needs groff(1) to be rendered" >&2
353cde00b53SSascha Wildner			echo "First install groff(1): " >&2
354cde00b53SSascha Wildner			echo "pkg install groff " >&2
355cde00b53SSascha Wildner			ret=1
356cde00b53SSascha Wildner		fi
357cde00b53SSascha Wildner		return
358cde00b53SSascha Wildner	fi
359cde00b53SSascha Wildner
360cde00b53SSascha Wildner	if [ $debug -gt 0 ]; then
361cde00b53SSascha Wildner		decho "Command: $cattool $manpage | $pipeline"
362cde00b53SSascha Wildner		ret=0
363cde00b53SSascha Wildner	else
364cde00b53SSascha Wildner		eval "$cattool $manpage | $pipeline"
365cde00b53SSascha Wildner		ret=$?
366cde00b53SSascha Wildner	fi
367cde00b53SSascha Wildner}
368cde00b53SSascha Wildner
369cde00b53SSascha Wildner# Usage: man_display_page_groff
370cde00b53SSascha Wildner# Display the manpage using groff
371cde00b53SSascha Wildnerman_display_page_groff() {
372cde00b53SSascha Wildner	local EQN NROFF PIC TBL TROFF REFER VGRIND
373cde00b53SSascha Wildner	local IFS l nroff_dev pipeline preproc_arg tool
374cde00b53SSascha Wildner
375cde00b53SSascha Wildner	# So, we really do need to parse the manpage. First, figure out the
376cde00b53SSascha Wildner	# device flag (-T) we have to pass to eqn(1) and groff(1). Then,
377cde00b53SSascha Wildner	# setup the pipeline of commands based on the user's request.
378cde00b53SSascha Wildner
379cde00b53SSascha Wildner	# If the manpage is from a particular charset, we need to setup nroff
380cde00b53SSascha Wildner	# to properly output for the correct device.
381cde00b53SSascha Wildner	case "${manpage}" in
382cde00b53SSascha Wildner	*.${man_charset}/*)
383cde00b53SSascha Wildner		# I don't pretend to know this; I'm just copying from the
384cde00b53SSascha Wildner		# previous version of man(1).
385cde00b53SSascha Wildner		case "$man_charset" in
386cde00b53SSascha Wildner		KOI8-R)		nroff_dev="koi8-r" ;;
387cde00b53SSascha Wildner		ISO8859-1)	nroff_dev="latin1" ;;
388cde00b53SSascha Wildner		ISO8859-15)	nroff_dev="latin1" ;;
389cde00b53SSascha Wildner		UTF-8)		nroff_dev="utf8" ;;
390cde00b53SSascha Wildner		*)		nroff_dev="ascii" ;;
391cde00b53SSascha Wildner		esac
392cde00b53SSascha Wildner
393cde00b53SSascha Wildner		NROFF="$NROFF -T$nroff_dev"
394cde00b53SSascha Wildner		EQN="$EQN -T$nroff_dev"
395cde00b53SSascha Wildner
396cde00b53SSascha Wildner		# Iff the manpage is from the locale and not just the charset,
397cde00b53SSascha Wildner		# then we need to define the locale string.
398cde00b53SSascha Wildner		case "${manpage}" in
399cde00b53SSascha Wildner		*/${man_lang}_${man_country}.${man_charset}/*)
400cde00b53SSascha Wildner			NROFF="$NROFF -dlocale=$man_lang.$man_charset"
401cde00b53SSascha Wildner			;;
402cde00b53SSascha Wildner		*/${man_lang}.${man_charset}/*)
403cde00b53SSascha Wildner			NROFF="$NROFF -dlocale=$man_lang.$man_charset"
404cde00b53SSascha Wildner			;;
405cde00b53SSascha Wildner		esac
406cde00b53SSascha Wildner
407cde00b53SSascha Wildner		# Allow language specific calls to override the default
408cde00b53SSascha Wildner		# set of utilities.
409cde00b53SSascha Wildner		l=$(echo $man_lang | tr [:lower:] [:upper:])
410cde00b53SSascha Wildner		for tool in EQN NROFF PIC TBL TROFF REFER VGRIND; do
411cde00b53SSascha Wildner			eval "$tool=\${${tool}_$l:-\$$tool}"
412cde00b53SSascha Wildner		done
413cde00b53SSascha Wildner		;;
414cde00b53SSascha Wildner	*)	NROFF="$NROFF -Tascii"
415cde00b53SSascha Wildner		EQN="$EQN -Tascii"
416cde00b53SSascha Wildner		;;
417cde00b53SSascha Wildner	esac
418cde00b53SSascha Wildner
419cde00b53SSascha Wildner	if [ -z "$MANCOLOR" ]; then
420cde00b53SSascha Wildner		NROFF="$NROFF -P-c"
421cde00b53SSascha Wildner	fi
422cde00b53SSascha Wildner
423cde00b53SSascha Wildner	if [ -n "${use_width}" ]; then
424cde00b53SSascha Wildner		NROFF="$NROFF -rLL=${use_width}n -rLT=${use_width}n"
425cde00b53SSascha Wildner	fi
426cde00b53SSascha Wildner
427cde00b53SSascha Wildner	if [ -n "$MANROFFSEQ" ]; then
428cde00b53SSascha Wildner		set -- -$MANROFFSEQ
429cde00b53SSascha Wildner		while getopts 'egprtv' preproc_arg; do
430cde00b53SSascha Wildner			case "${preproc_arg}" in
431cde00b53SSascha Wildner			e)	pipeline="$pipeline | $EQN" ;;
432cde00b53SSascha Wildner			g)	;; # Ignore for compatibility.
433cde00b53SSascha Wildner			p)	pipeline="$pipeline | $PIC" ;;
434cde00b53SSascha Wildner			r)	pipeline="$pipeline | $REFER" ;;
435cde00b53SSascha Wildner			t)	pipeline="$pipeline | $TBL" ;;
436cde00b53SSascha Wildner			v)	pipeline="$pipeline | $VGRIND" ;;
437cde00b53SSascha Wildner			*)	usage ;;
438cde00b53SSascha Wildner			esac
439cde00b53SSascha Wildner		done
440cde00b53SSascha Wildner		# Strip the leading " | " from the resulting pipeline.
441cde00b53SSascha Wildner		pipeline="${pipeline#" | "}"
442cde00b53SSascha Wildner	else
443cde00b53SSascha Wildner		pipeline="$TBL"
444cde00b53SSascha Wildner	fi
445cde00b53SSascha Wildner
446cde00b53SSascha Wildner	if [ -n "$tflag" ]; then
447cde00b53SSascha Wildner		pipeline="$pipeline | $TROFF"
448cde00b53SSascha Wildner	else
449cde00b53SSascha Wildner		pipeline="$pipeline | $NROFF | $MANPAGER"
450cde00b53SSascha Wildner	fi
451cde00b53SSascha Wildner
452cde00b53SSascha Wildner	if [ $debug -gt 0 ]; then
453cde00b53SSascha Wildner		decho "Command: $cattool $manpage | $pipeline"
454cde00b53SSascha Wildner		ret=0
455cde00b53SSascha Wildner	else
456cde00b53SSascha Wildner		eval "$cattool $manpage | $pipeline"
457cde00b53SSascha Wildner		ret=$?
458cde00b53SSascha Wildner	fi
459cde00b53SSascha Wildner}
460cde00b53SSascha Wildner
461cde00b53SSascha Wildner# Usage: man_find_and_display page
462cde00b53SSascha Wildner# Search through the manpaths looking for the given page.
463cde00b53SSascha Wildnerman_find_and_display() {
464cde00b53SSascha Wildner	local found_page locpath p path sect
465cde00b53SSascha Wildner
466cde00b53SSascha Wildner	# Check to see if it's a file. But only if it has a '/' in
467cde00b53SSascha Wildner	# the filename.
468cde00b53SSascha Wildner	case "$1" in
469cde00b53SSascha Wildner	*/*)	if [ -f "$1" -a -r "$1" ]; then
470cde00b53SSascha Wildner			decho "Found a usable page, displaying that"
471cde00b53SSascha Wildner			unset use_cat
472cde00b53SSascha Wildner			manpage="$1"
473cde00b53SSascha Wildner			setup_cattool $manpage
474cde00b53SSascha Wildner			if man_check_for_so $manpage $(dirname $manpage); then
475cde00b53SSascha Wildner				found_page=yes
476cde00b53SSascha Wildner				man_display_page
477cde00b53SSascha Wildner			fi
478cde00b53SSascha Wildner			return
479cde00b53SSascha Wildner		fi
480cde00b53SSascha Wildner		;;
481cde00b53SSascha Wildner	esac
482cde00b53SSascha Wildner
483cde00b53SSascha Wildner	IFS=:
484cde00b53SSascha Wildner	for sect in $MANSECT; do
485cde00b53SSascha Wildner		decho "Searching section $sect" 2
486cde00b53SSascha Wildner		for path in $MANPATH; do
487cde00b53SSascha Wildner			for locpath in $locpaths; do
488cde00b53SSascha Wildner				p=$path/$locpath
489cde00b53SSascha Wildner				p=${p%/.} # Rid ourselves of the trailing /.
490cde00b53SSascha Wildner
491cde00b53SSascha Wildner				# Check if there is a MACHINE specific manpath.
492cde00b53SSascha Wildner				if find_file $p $sect $MACHINE "$1"; then
493cde00b53SSascha Wildner					if man_check_for_so $manpage $p; then
494cde00b53SSascha Wildner						found_page=yes
495cde00b53SSascha Wildner						man_display_page
496cde00b53SSascha Wildner						if [ -n "$aflag" ]; then
497cde00b53SSascha Wildner							continue 2
498cde00b53SSascha Wildner						else
499cde00b53SSascha Wildner							return
500cde00b53SSascha Wildner						fi
501cde00b53SSascha Wildner					fi
502cde00b53SSascha Wildner				fi
503cde00b53SSascha Wildner
504cde00b53SSascha Wildner				# Check if there is a MACHINE_ARCH
505cde00b53SSascha Wildner				# specific manpath.
506cde00b53SSascha Wildner				if find_file $p $sect $MACHINE_ARCH "$1"; then
507cde00b53SSascha Wildner					if man_check_for_so $manpage $p; then
508cde00b53SSascha Wildner						found_page=yes
509cde00b53SSascha Wildner						man_display_page
510cde00b53SSascha Wildner						if [ -n "$aflag" ]; then
511cde00b53SSascha Wildner							continue 2
512cde00b53SSascha Wildner						else
513cde00b53SSascha Wildner							return
514cde00b53SSascha Wildner						fi
515cde00b53SSascha Wildner					fi
516cde00b53SSascha Wildner				fi
517cde00b53SSascha Wildner
518cde00b53SSascha Wildner				# Check plain old manpath.
519cde00b53SSascha Wildner				if find_file $p $sect '' "$1"; then
520cde00b53SSascha Wildner					if man_check_for_so $manpage $p; then
521cde00b53SSascha Wildner						found_page=yes
522cde00b53SSascha Wildner						man_display_page
523cde00b53SSascha Wildner						if [ -n "$aflag" ]; then
524cde00b53SSascha Wildner							continue 2
525cde00b53SSascha Wildner						else
526cde00b53SSascha Wildner							return
527cde00b53SSascha Wildner						fi
528cde00b53SSascha Wildner					fi
529cde00b53SSascha Wildner				fi
530cde00b53SSascha Wildner			done
531cde00b53SSascha Wildner		done
532cde00b53SSascha Wildner	done
533cde00b53SSascha Wildner	unset IFS
534cde00b53SSascha Wildner
535cde00b53SSascha Wildner	# Nothing? Well, we are done then.
536cde00b53SSascha Wildner	if [ -z "$found_page" ]; then
537cde00b53SSascha Wildner		echo "No manual entry for $1" >&2
538cde00b53SSascha Wildner		ret=1
539cde00b53SSascha Wildner		return
540cde00b53SSascha Wildner	fi
541cde00b53SSascha Wildner}
542cde00b53SSascha Wildner
543cde00b53SSascha Wildner# Usage: man_parse_args "$@"
544cde00b53SSascha Wildner# Parses commandline options for man.
545cde00b53SSascha Wildnerman_parse_args() {
546cde00b53SSascha Wildner	local IFS cmd_arg
547cde00b53SSascha Wildner
548cde00b53SSascha Wildner	while getopts 'M:P:S:adfhkm:op:tw' cmd_arg; do
549cde00b53SSascha Wildner		case "${cmd_arg}" in
550cde00b53SSascha Wildner		M)	MANPATH=$OPTARG ;;
551cde00b53SSascha Wildner		P)	MANPAGER=$OPTARG ;;
552cde00b53SSascha Wildner		S)	MANSECT=$OPTARG ;;
553cde00b53SSascha Wildner		a)	aflag=aflag ;;
554cde00b53SSascha Wildner		d)	debug=$(( $debug + 1 )) ;;
555cde00b53SSascha Wildner		f)	fflag=fflag ;;
556cde00b53SSascha Wildner		h)	man_usage 0 ;;
557cde00b53SSascha Wildner		k)	kflag=kflag ;;
558cde00b53SSascha Wildner		m)	mflag=$OPTARG ;;
559cde00b53SSascha Wildner		o)	oflag=oflag ;;
560cde00b53SSascha Wildner		p)	MANROFFSEQ=$OPTARG ;;
561cde00b53SSascha Wildner		t)	tflag=tflag ;;
562cde00b53SSascha Wildner		w)	wflag=wflag ;;
563cde00b53SSascha Wildner		*)	man_usage ;;
564cde00b53SSascha Wildner		esac
565cde00b53SSascha Wildner	done >&2
566cde00b53SSascha Wildner
567cde00b53SSascha Wildner	shift $(( $OPTIND - 1 ))
568cde00b53SSascha Wildner
569cde00b53SSascha Wildner	# Check the args for incompatible options.
570cde00b53SSascha Wildner	case "${fflag}${kflag}${tflag}${wflag}" in
571cde00b53SSascha Wildner	fflagkflag*)	echo "Incompatible options: -f and -k"; man_usage ;;
572cde00b53SSascha Wildner	fflag*tflag*)	echo "Incompatible options: -f and -t"; man_usage ;;
573cde00b53SSascha Wildner	fflag*wflag)	echo "Incompatible options: -f and -w"; man_usage ;;
574cde00b53SSascha Wildner	*kflagtflag*)	echo "Incompatible options: -k and -t"; man_usage ;;
575cde00b53SSascha Wildner	*kflag*wflag)	echo "Incompatible options: -k and -w"; man_usage ;;
576cde00b53SSascha Wildner	*tflagwflag)	echo "Incompatible options: -t and -w"; man_usage ;;
577cde00b53SSascha Wildner	esac
578cde00b53SSascha Wildner
579cde00b53SSascha Wildner	# Short circuit for whatis(1) and apropos(1)
580cde00b53SSascha Wildner	if [ -n "$fflag" ]; then
581cde00b53SSascha Wildner		do_whatis "$@"
582cde00b53SSascha Wildner		exit
583cde00b53SSascha Wildner	fi
584cde00b53SSascha Wildner
585cde00b53SSascha Wildner	if [ -n "$kflag" ]; then
586cde00b53SSascha Wildner		do_apropos "$@"
587cde00b53SSascha Wildner		exit
588cde00b53SSascha Wildner	fi
589cde00b53SSascha Wildner
590cde00b53SSascha Wildner	IFS=:
591cde00b53SSascha Wildner	for sect in $man_default_sections; do
592cde00b53SSascha Wildner		if [ "$sect" = "$1" ]; then
593cde00b53SSascha Wildner			decho "Detected manual section as first arg: $1"
594cde00b53SSascha Wildner			MANSECT="$1"
595cde00b53SSascha Wildner			shift
596cde00b53SSascha Wildner			break
597cde00b53SSascha Wildner		fi
598cde00b53SSascha Wildner	done
599cde00b53SSascha Wildner	unset IFS
600cde00b53SSascha Wildner
601cde00b53SSascha Wildner	pages="$*"
602cde00b53SSascha Wildner}
603cde00b53SSascha Wildner
604cde00b53SSascha Wildner# Usage: man_setup
605cde00b53SSascha Wildner# Setup various trivial but essential variables.
606cde00b53SSascha Wildnerman_setup() {
607cde00b53SSascha Wildner	# Setup machine and architecture variables.
608cde00b53SSascha Wildner	if [ -n "$mflag" ]; then
609cde00b53SSascha Wildner		MACHINE_ARCH=${mflag%%:*}
610cde00b53SSascha Wildner		MACHINE=${mflag##*:}
611cde00b53SSascha Wildner	fi
612cde00b53SSascha Wildner	if [ -z "$MACHINE_ARCH" ]; then
613cde00b53SSascha Wildner		MACHINE_ARCH=$($SYSCTL -n hw.machine_arch)
614cde00b53SSascha Wildner	fi
615cde00b53SSascha Wildner	if [ -z "$MACHINE" ]; then
616cde00b53SSascha Wildner		MACHINE=$($SYSCTL -n hw.machine)
617cde00b53SSascha Wildner	fi
618cde00b53SSascha Wildner	decho "Using architecture: $MACHINE_ARCH:$MACHINE"
619cde00b53SSascha Wildner
620cde00b53SSascha Wildner	setup_pager
621cde00b53SSascha Wildner
622cde00b53SSascha Wildner	# Setup manual sections to search.
623cde00b53SSascha Wildner	if [ -z "$MANSECT" ]; then
624cde00b53SSascha Wildner		MANSECT=$man_default_sections
625cde00b53SSascha Wildner	fi
626cde00b53SSascha Wildner	decho "Using manual sections: $MANSECT"
627cde00b53SSascha Wildner
628cde00b53SSascha Wildner	build_manpath
629cde00b53SSascha Wildner	man_setup_locale
630cde00b53SSascha Wildner	man_setup_width
631cde00b53SSascha Wildner}
632cde00b53SSascha Wildner
633cde00b53SSascha Wildner# Usage: man_setup_width
634cde00b53SSascha Wildner# Set up page width.
635cde00b53SSascha Wildnerman_setup_width() {
636cde00b53SSascha Wildner	local sizes
637cde00b53SSascha Wildner
638cde00b53SSascha Wildner	unset use_width
639cde00b53SSascha Wildner	case "$MANWIDTH" in
640cde00b53SSascha Wildner	[0-9]*)
641cde00b53SSascha Wildner		if [ "$MANWIDTH" -gt 0 2>/dev/null ]; then
642cde00b53SSascha Wildner			use_width=$MANWIDTH
643cde00b53SSascha Wildner		fi
644cde00b53SSascha Wildner		;;
645cde00b53SSascha Wildner	[Tt][Tt][Yy])
646cde00b53SSascha Wildner		if { sizes=$($STTY size 0>&3 2>/dev/null); } 3>&1; then
647cde00b53SSascha Wildner			set -- $sizes
648cde00b53SSascha Wildner			if [ $2 -gt 80 ]; then
649cde00b53SSascha Wildner				use_width=$(($2-2))
650cde00b53SSascha Wildner			fi
651cde00b53SSascha Wildner		fi
652cde00b53SSascha Wildner		;;
653cde00b53SSascha Wildner	esac
654cde00b53SSascha Wildner	if [ -n "$use_width" ]; then
655cde00b53SSascha Wildner		decho "Using non-standard page width: ${use_width}"
656cde00b53SSascha Wildner	else
657cde00b53SSascha Wildner		decho 'Using standard page width'
658cde00b53SSascha Wildner	fi
659cde00b53SSascha Wildner}
660cde00b53SSascha Wildner
661cde00b53SSascha Wildner# Usage: man_setup_locale
662cde00b53SSascha Wildner# Setup necessary locale variables.
663cde00b53SSascha Wildnerman_setup_locale() {
664cde00b53SSascha Wildner	local lang_cc
665cde00b53SSascha Wildner	local locstr
666cde00b53SSascha Wildner
667cde00b53SSascha Wildner	locpaths='.'
668cde00b53SSascha Wildner	man_charset='US-ASCII'
669cde00b53SSascha Wildner
670cde00b53SSascha Wildner	# Setup locale information.
671cde00b53SSascha Wildner	if [ -n "$oflag" ]; then
672cde00b53SSascha Wildner		decho 'Using non-localized manpages'
673cde00b53SSascha Wildner	else
674cde00b53SSascha Wildner		# Use the locale tool to give us proper locale information
675cde00b53SSascha Wildner		eval $( $LOCALE )
676cde00b53SSascha Wildner
677cde00b53SSascha Wildner		if [ -n "$LANG" ]; then
678cde00b53SSascha Wildner			locstr=$LANG
679cde00b53SSascha Wildner		else
680cde00b53SSascha Wildner			locstr=$LC_CTYPE
681cde00b53SSascha Wildner		fi
682cde00b53SSascha Wildner
683cde00b53SSascha Wildner		case "$locstr" in
684cde00b53SSascha Wildner		C)		;;
685cde00b53SSascha Wildner		C.UTF-8)	;;
686cde00b53SSascha Wildner		POSIX)		;;
687cde00b53SSascha Wildner		[a-z][a-z]_[A-Z][A-Z]\.*)
688cde00b53SSascha Wildner				lang_cc="${locstr%.*}"
689cde00b53SSascha Wildner				man_lang="${locstr%_*}"
690cde00b53SSascha Wildner				man_country="${lang_cc#*_}"
691cde00b53SSascha Wildner				man_charset="${locstr#*.}"
692cde00b53SSascha Wildner				locpaths="$locstr"
693cde00b53SSascha Wildner				locpaths="$locpaths:$man_lang.$man_charset"
694cde00b53SSascha Wildner				if [ "$man_lang" != "en" ]; then
695cde00b53SSascha Wildner					locpaths="$locpaths:en.$man_charset"
696cde00b53SSascha Wildner				fi
697cde00b53SSascha Wildner				locpaths="$locpaths:."
698cde00b53SSascha Wildner				;;
699cde00b53SSascha Wildner		*)		echo 'Unknown locale, assuming C' >&2
700cde00b53SSascha Wildner				;;
701cde00b53SSascha Wildner		esac
702cde00b53SSascha Wildner	fi
703cde00b53SSascha Wildner
704cde00b53SSascha Wildner	decho "Using locale paths: $locpaths"
705cde00b53SSascha Wildner}
706cde00b53SSascha Wildner
707cde00b53SSascha Wildner# Usage: man_usage [exitcode]
708cde00b53SSascha Wildner# Display usage for the man utility.
709cde00b53SSascha Wildnerman_usage() {
710cde00b53SSascha Wildner	echo 'Usage:'
711cde00b53SSascha Wildner	echo ' man [-adho] [-t | -w] [-M manpath] [-P pager] [-S mansect]'
712cde00b53SSascha Wildner	echo '     [-m arch[:machine]] [-p [eprtv]] [mansect] page [...]'
713cde00b53SSascha Wildner	echo ' man -f page [...] -- Emulates whatis(1)'
714cde00b53SSascha Wildner	echo ' man -k page [...] -- Emulates apropos(1)'
715cde00b53SSascha Wildner
716cde00b53SSascha Wildner	# When exit'ing with -h, it's not an error.
717cde00b53SSascha Wildner	exit ${1:-1}
718cde00b53SSascha Wildner}
719cde00b53SSascha Wildner
720cde00b53SSascha Wildner# Usage: parse_configs
721cde00b53SSascha Wildner# Reads the end-user adjustable config files.
722cde00b53SSascha Wildnerparse_configs() {
723cde00b53SSascha Wildner	local IFS file files
724cde00b53SSascha Wildner
725cde00b53SSascha Wildner	if [ -n "$parsed_configs" ]; then
726cde00b53SSascha Wildner		return
727cde00b53SSascha Wildner	fi
728cde00b53SSascha Wildner
729cde00b53SSascha Wildner	unset IFS
730cde00b53SSascha Wildner
731cde00b53SSascha Wildner	# Read the global config first in case the user wants
732cde00b53SSascha Wildner	# to override config_local.
733cde00b53SSascha Wildner	if [ -r "$config_global" ]; then
734cde00b53SSascha Wildner		parse_file "$config_global"
735cde00b53SSascha Wildner	fi
736cde00b53SSascha Wildner
737cde00b53SSascha Wildner	# Glob the list of files to parse.
738cde00b53SSascha Wildner	set +f
739cde00b53SSascha Wildner	files=$(echo $config_local)
740cde00b53SSascha Wildner	set -f
741cde00b53SSascha Wildner
742cde00b53SSascha Wildner	for file in $files; do
743cde00b53SSascha Wildner		if [ -r "$file" ]; then
744cde00b53SSascha Wildner			parse_file "$file"
745cde00b53SSascha Wildner		fi
746cde00b53SSascha Wildner	done
747cde00b53SSascha Wildner
748cde00b53SSascha Wildner	parsed_configs='yes'
749cde00b53SSascha Wildner}
750cde00b53SSascha Wildner
751cde00b53SSascha Wildner# Usage: parse_file file
752cde00b53SSascha Wildner# Reads the specified config files.
753cde00b53SSascha Wildnerparse_file() {
754cde00b53SSascha Wildner	local file line tstr var
755cde00b53SSascha Wildner
756cde00b53SSascha Wildner	file="$1"
757cde00b53SSascha Wildner	decho "Parsing config file: $file"
758cde00b53SSascha Wildner	while read line; do
759cde00b53SSascha Wildner		decho "  $line" 2
760cde00b53SSascha Wildner		case "$line" in
761cde00b53SSascha Wildner		\#*)		decho "    Comment" 3
762cde00b53SSascha Wildner				;;
763cde00b53SSascha Wildner		MANPATH*)	decho "    MANPATH" 3
764cde00b53SSascha Wildner				trim "${line#MANPATH}"
765cde00b53SSascha Wildner				add_to_manpath "$tstr"
766cde00b53SSascha Wildner				;;
767cde00b53SSascha Wildner		MANLOCALE*)	decho "    MANLOCALE" 3
768cde00b53SSascha Wildner				trim "${line#MANLOCALE}"
769cde00b53SSascha Wildner				manlocales="$manlocales:$tstr"
770cde00b53SSascha Wildner				;;
771cde00b53SSascha Wildner		MANCONFIG*)	decho "    MANCONFIG" 3
772cde00b53SSascha Wildner				trim "${line#MANCONFIG}"
773cde00b53SSascha Wildner				config_local="$tstr"
774cde00b53SSascha Wildner				;;
775cde00b53SSascha Wildner		# Set variables in the form of FOO_BAR
776cde00b53SSascha Wildner		*_*[\ \	]*)	var="${line%%[\ \	]*}"
777cde00b53SSascha Wildner				trim "${line#$var}"
778cde00b53SSascha Wildner				eval "$var=\"$tstr\""
779cde00b53SSascha Wildner				decho "    Parsed $var" 3
780cde00b53SSascha Wildner				;;
781cde00b53SSascha Wildner		esac
782cde00b53SSascha Wildner	done < "$file"
783cde00b53SSascha Wildner}
784cde00b53SSascha Wildner
785cde00b53SSascha Wildner# Usage: search_path
786cde00b53SSascha Wildner# Traverse $PATH looking for manpaths.
787cde00b53SSascha Wildnersearch_path() {
788cde00b53SSascha Wildner	local IFS p path
789cde00b53SSascha Wildner
790cde00b53SSascha Wildner	decho "Searching PATH for man directories"
791cde00b53SSascha Wildner
792cde00b53SSascha Wildner	IFS=:
793cde00b53SSascha Wildner	for path in $PATH; do
794cde00b53SSascha Wildner		if add_to_manpath "$path/man"; then
795cde00b53SSascha Wildner			:
796cde00b53SSascha Wildner		elif add_to_manpath "$path/MAN"; then
797cde00b53SSascha Wildner			:
798cde00b53SSascha Wildner		else
799cde00b53SSascha Wildner			case "$path" in
800cde00b53SSascha Wildner			*/bin)	p="${path%/bin}/share/man"
801cde00b53SSascha Wildner				add_to_manpath "$p"
802cde00b53SSascha Wildner				p="${path%/bin}/man"
803cde00b53SSascha Wildner				add_to_manpath "$p"
804cde00b53SSascha Wildner				;;
805cde00b53SSascha Wildner			esac
806cde00b53SSascha Wildner		fi
807cde00b53SSascha Wildner	done
808cde00b53SSascha Wildner	unset IFS
809cde00b53SSascha Wildner
810cde00b53SSascha Wildner	if [ -z "$manpath" ]; then
811cde00b53SSascha Wildner		decho '  Unable to find any manpaths, using default'
812cde00b53SSascha Wildner		manpath=$man_default_path
813cde00b53SSascha Wildner	fi
814cde00b53SSascha Wildner}
815cde00b53SSascha Wildner
816cde00b53SSascha Wildner# Usage: search_whatis cmd [arglist]
817cde00b53SSascha Wildner# Do the heavy lifting for apropos/whatis
818cde00b53SSascha Wildnersearch_whatis() {
819cde00b53SSascha Wildner	local IFS bad cmd f good key keywords loc opt out path rval wlist
820cde00b53SSascha Wildner
821cde00b53SSascha Wildner	cmd="$1"
822cde00b53SSascha Wildner	shift
823cde00b53SSascha Wildner
824cde00b53SSascha Wildner	whatis_parse_args "$@"
825cde00b53SSascha Wildner
826cde00b53SSascha Wildner	build_manpath
827cde00b53SSascha Wildner	build_manlocales
828cde00b53SSascha Wildner	setup_pager
829cde00b53SSascha Wildner
830cde00b53SSascha Wildner	if [ "$cmd" = "whatis" ]; then
831cde00b53SSascha Wildner		opt="-w"
832cde00b53SSascha Wildner	fi
833cde00b53SSascha Wildner
834cde00b53SSascha Wildner	f='whatis'
835cde00b53SSascha Wildner
836cde00b53SSascha Wildner	IFS=:
837cde00b53SSascha Wildner	for path in $MANPATH; do
838cde00b53SSascha Wildner		if [ \! -d "$path" ]; then
839cde00b53SSascha Wildner			decho "Skipping non-existent path: $path" 2
840cde00b53SSascha Wildner			continue
841cde00b53SSascha Wildner		fi
842cde00b53SSascha Wildner
843cde00b53SSascha Wildner		if [ -f "$path/$f" -a -r "$path/$f" ]; then
844cde00b53SSascha Wildner			decho "Found whatis: $path/$f"
845cde00b53SSascha Wildner			wlist="$wlist $path/$f"
846cde00b53SSascha Wildner		fi
847cde00b53SSascha Wildner
848cde00b53SSascha Wildner		for loc in $MANLOCALES; do
849cde00b53SSascha Wildner			if [ -f "$path/$loc/$f" -a -r "$path/$loc/$f" ]; then
850cde00b53SSascha Wildner				decho "Found whatis: $path/$loc/$f"
851cde00b53SSascha Wildner				wlist="$wlist $path/$loc/$f"
852cde00b53SSascha Wildner			fi
853cde00b53SSascha Wildner		done
854cde00b53SSascha Wildner	done
855cde00b53SSascha Wildner	unset IFS
856cde00b53SSascha Wildner
857cde00b53SSascha Wildner	if [ -z "$wlist" ]; then
858cde00b53SSascha Wildner		echo "$cmd: no whatis databases in $MANPATH" >&2
859cde00b53SSascha Wildner		exit 1
860cde00b53SSascha Wildner	fi
861cde00b53SSascha Wildner
862cde00b53SSascha Wildner	rval=0
863cde00b53SSascha Wildner	for key in $keywords; do
864cde00b53SSascha Wildner		out=$(grep -Ehi $opt -- "$key" $wlist)
865cde00b53SSascha Wildner		if [ -n "$out" ]; then
866cde00b53SSascha Wildner			good="$good\\n$out"
867cde00b53SSascha Wildner		else
868cde00b53SSascha Wildner			bad="$bad\\n$key: nothing appropriate"
869cde00b53SSascha Wildner			rval=1
870cde00b53SSascha Wildner		fi
871cde00b53SSascha Wildner	done
872cde00b53SSascha Wildner
873cde00b53SSascha Wildner	# Strip leading carriage return.
874cde00b53SSascha Wildner	good=${good#\\n}
875cde00b53SSascha Wildner	bad=${bad#\\n}
876cde00b53SSascha Wildner
877cde00b53SSascha Wildner	if [ -n "$good" ]; then
878cde00b53SSascha Wildner		echo -e "$good" | $MANPAGER
879cde00b53SSascha Wildner	fi
880cde00b53SSascha Wildner
881cde00b53SSascha Wildner	if [ -n "$bad" ]; then
882cde00b53SSascha Wildner		echo -e "$bad" >&2
883cde00b53SSascha Wildner	fi
884cde00b53SSascha Wildner
885cde00b53SSascha Wildner	exit $rval
886cde00b53SSascha Wildner}
887cde00b53SSascha Wildner
888cde00b53SSascha Wildner# Usage: setup_cattool page
889cde00b53SSascha Wildner# Finds an appropriate decompressor based on extension
890cde00b53SSascha Wildnersetup_cattool() {
891cde00b53SSascha Wildner	case "$1" in
892cde00b53SSascha Wildner	*.bz)	cattool='/usr/bin/bzcat' ;;
893cde00b53SSascha Wildner	*.bz2)	cattool='/usr/bin/bzcat' ;;
894cde00b53SSascha Wildner	*.gz)	cattool='/usr/bin/zcat' ;;
895cde00b53SSascha Wildner	*.lzma)	cattool='/usr/bin/lzcat' ;;
896cde00b53SSascha Wildner	*.xz)	cattool='/usr/bin/xzcat' ;;
897cde00b53SSascha Wildner	*)	cattool='/usr/bin/zcat -f' ;;
898cde00b53SSascha Wildner	esac
899cde00b53SSascha Wildner}
900cde00b53SSascha Wildner
901cde00b53SSascha Wildner# Usage: setup_pager
902cde00b53SSascha Wildner# Correctly sets $MANPAGER
903cde00b53SSascha Wildnersetup_pager() {
904cde00b53SSascha Wildner	# Setup pager.
905cde00b53SSascha Wildner	if [ -z "$MANPAGER" ]; then
906cde00b53SSascha Wildner		if [ -n "$MANCOLOR" ]; then
907cde00b53SSascha Wildner			MANPAGER="less -sR"
908cde00b53SSascha Wildner		else
909cde00b53SSascha Wildner			if [ -n "$PAGER" ]; then
910cde00b53SSascha Wildner				MANPAGER="$PAGER"
911cde00b53SSascha Wildner			else
912cde00b53SSascha Wildner				MANPAGER="less -s"
913cde00b53SSascha Wildner			fi
914cde00b53SSascha Wildner		fi
915cde00b53SSascha Wildner	fi
916cde00b53SSascha Wildner	decho "Using pager: $MANPAGER"
917cde00b53SSascha Wildner}
918cde00b53SSascha Wildner
919cde00b53SSascha Wildner# Usage: trim string
920cde00b53SSascha Wildner# Trims whitespace from beginning and end of a variable
921cde00b53SSascha Wildnertrim() {
922cde00b53SSascha Wildner	tstr=$1
923cde00b53SSascha Wildner	while true; do
924cde00b53SSascha Wildner		case "$tstr" in
925cde00b53SSascha Wildner		[\ \	]*)	tstr="${tstr##[\ \	]}" ;;
926cde00b53SSascha Wildner		*[\ \	])	tstr="${tstr%%[\ \	]}" ;;
927cde00b53SSascha Wildner		*)		break ;;
928cde00b53SSascha Wildner		esac
929cde00b53SSascha Wildner	done
930cde00b53SSascha Wildner}
931cde00b53SSascha Wildner
932cde00b53SSascha Wildner# Usage: whatis_parse_args "$@"
933cde00b53SSascha Wildner# Parse commandline args for whatis and apropos.
934cde00b53SSascha Wildnerwhatis_parse_args() {
935cde00b53SSascha Wildner	local cmd_arg
936cde00b53SSascha Wildner	while getopts 'd' cmd_arg; do
937cde00b53SSascha Wildner		case "${cmd_arg}" in
938cde00b53SSascha Wildner		d)	debug=$(( $debug + 1 )) ;;
939cde00b53SSascha Wildner		*)	whatis_usage ;;
940cde00b53SSascha Wildner		esac
941cde00b53SSascha Wildner	done >&2
942cde00b53SSascha Wildner
943cde00b53SSascha Wildner	shift $(( $OPTIND - 1 ))
944cde00b53SSascha Wildner
945cde00b53SSascha Wildner	keywords="$*"
946cde00b53SSascha Wildner}
947cde00b53SSascha Wildner
948cde00b53SSascha Wildner# Usage: whatis_usage
949cde00b53SSascha Wildner# Display usage for the whatis/apropos utility.
950cde00b53SSascha Wildnerwhatis_usage() {
951cde00b53SSascha Wildner	echo "usage: $cmd [-d] keyword [...]"
952cde00b53SSascha Wildner	exit 1
953cde00b53SSascha Wildner}
954cde00b53SSascha Wildner
955cde00b53SSascha Wildner
956cde00b53SSascha Wildner
957cde00b53SSascha Wildner# Supported commands
958cde00b53SSascha Wildnerdo_apropos() {
959cde00b53SSascha Wildner	[ $(stat -f %i /usr/bin/man) -ne $(stat -f %i /usr/bin/apropos) ] && \
960cde00b53SSascha Wildner		exec apropos "$@"
961cde00b53SSascha Wildner	search_whatis apropos "$@"
962cde00b53SSascha Wildner}
963cde00b53SSascha Wildner
964cde00b53SSascha Wildnerdo_man() {
965cde00b53SSascha Wildner	man_parse_args "$@"
966cde00b53SSascha Wildner	if [ -z "$pages" ]; then
967cde00b53SSascha Wildner		echo 'What manual page do you want?' >&2
968cde00b53SSascha Wildner		exit 1
969cde00b53SSascha Wildner	fi
970cde00b53SSascha Wildner	man_setup
971cde00b53SSascha Wildner
972cde00b53SSascha Wildner	for page in $pages; do
973cde00b53SSascha Wildner		decho "Searching for $page"
974cde00b53SSascha Wildner		man_find_and_display "$page"
975cde00b53SSascha Wildner	done
976cde00b53SSascha Wildner
977cde00b53SSascha Wildner	exit ${ret:-0}
978cde00b53SSascha Wildner}
979cde00b53SSascha Wildner
980cde00b53SSascha Wildnerdo_manpath() {
981cde00b53SSascha Wildner	manpath_parse_args "$@"
982cde00b53SSascha Wildner	if [ -z "$qflag" ]; then
983cde00b53SSascha Wildner		manpath_warnings
984cde00b53SSascha Wildner	fi
985cde00b53SSascha Wildner	if [ -n "$Lflag" ]; then
986cde00b53SSascha Wildner		build_manlocales
987cde00b53SSascha Wildner		echo $MANLOCALES
988cde00b53SSascha Wildner	else
989cde00b53SSascha Wildner		build_manpath
990cde00b53SSascha Wildner		echo $MANPATH
991cde00b53SSascha Wildner	fi
992cde00b53SSascha Wildner	exit 0
993cde00b53SSascha Wildner}
994cde00b53SSascha Wildner
995cde00b53SSascha Wildnerdo_whatis() {
996cde00b53SSascha Wildner	[ $(stat -f %i /usr/bin/man) -ne $(stat -f %i /usr/bin/whatis) ] && \
997cde00b53SSascha Wildner		exec whatis "$@"
998cde00b53SSascha Wildner	search_whatis whatis "$@"
999cde00b53SSascha Wildner}
1000cde00b53SSascha Wildner
1001cde00b53SSascha Wildner# User's PATH setting decides on the groff-suite to pick up.
1002cde00b53SSascha WildnerEQN=eqn
1003cde00b53SSascha WildnerNROFF='groff -S -P-h -Wall -mtty-char -man'
1004cde00b53SSascha WildnerPIC=pic
1005cde00b53SSascha WildnerREFER=refer
1006cde00b53SSascha WildnerTBL=tbl
1007cde00b53SSascha WildnerTROFF='groff -S -man'
1008cde00b53SSascha WildnerVGRIND=vgrind
1009cde00b53SSascha Wildner
1010cde00b53SSascha WildnerLOCALE=/usr/bin/locale
1011cde00b53SSascha WildnerSTTY=/bin/stty
1012cde00b53SSascha WildnerSYSCTL=/sbin/sysctl
1013cde00b53SSascha Wildner
1014cde00b53SSascha Wildnerdebug=0
1015cde00b53SSascha Wildnerman_default_sections='1:8:2:3:n:4:5:6:7:9:l'
1016*a3b5347fSSascha Wildnerman_default_path='/usr/share/man:/usr/local/share/man:/usr/local/man:/raven/share/man:/usr/pkg/man'
1017cde00b53SSascha Wildnercattool='/usr/bin/zcat -f'
1018cde00b53SSascha Wildner
1019cde00b53SSascha Wildnerconfig_global='/etc/man.conf'
1020cde00b53SSascha Wildner
1021cde00b53SSascha Wildner# This can be overridden via a setting in /etc/man.conf.
1022cde00b53SSascha Wildnerconfig_local='/usr/local/etc/man.d/*.conf'
1023cde00b53SSascha Wildner
1024cde00b53SSascha Wildner# Set noglobbing for now. I don't want spurious globbing.
1025cde00b53SSascha Wildnerset -f
1026cde00b53SSascha Wildner
1027cde00b53SSascha Wildnercase "$0" in
1028cde00b53SSascha Wildner*apropos)	do_apropos "$@" ;;
1029cde00b53SSascha Wildner*manpath)	do_manpath "$@" ;;
1030cde00b53SSascha Wildner*whatis)	do_whatis "$@" ;;
1031cde00b53SSascha Wildner*)		do_man "$@" ;;
1032cde00b53SSascha Wildneresac
1033