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