xref: /freebsd/usr.bin/man/man.sh (revision f555b39e6bb7cbfbe1905e90f64c4dfc4456fabb)
1c535eb59SGordon Tetlow#! /bin/sh
2c535eb59SGordon Tetlow#
31de7b4b8SPedro F. Giffuni# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
41de7b4b8SPedro F. Giffuni#
5c535eb59SGordon Tetlow#  Copyright (c) 2010 Gordon Tetlow
6c535eb59SGordon Tetlow#  All rights reserved.
7c535eb59SGordon Tetlow#
8c535eb59SGordon Tetlow#  Redistribution and use in source and binary forms, with or without
9c535eb59SGordon Tetlow#  modification, are permitted provided that the following conditions
10c535eb59SGordon Tetlow#  are met:
11c535eb59SGordon Tetlow#  1. Redistributions of source code must retain the above copyright
12c535eb59SGordon Tetlow#     notice, this list of conditions and the following disclaimer.
13c535eb59SGordon Tetlow#  2. Redistributions in binary form must reproduce the above copyright
14c535eb59SGordon Tetlow#     notice, this list of conditions and the following disclaimer in the
15c535eb59SGordon Tetlow#     documentation and/or other materials provided with the distribution.
16c535eb59SGordon Tetlow#
17c535eb59SGordon Tetlow#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18c535eb59SGordon Tetlow#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19c535eb59SGordon Tetlow#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20c535eb59SGordon Tetlow#  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21c535eb59SGordon Tetlow#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22c535eb59SGordon Tetlow#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23c535eb59SGordon Tetlow#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24c535eb59SGordon Tetlow#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25c535eb59SGordon Tetlow#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26c535eb59SGordon Tetlow#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27c535eb59SGordon Tetlow#  SUCH DAMAGE.
28c535eb59SGordon Tetlow#
29c535eb59SGordon Tetlow# $FreeBSD$
30c535eb59SGordon Tetlow
31c535eb59SGordon Tetlow# Usage: add_to_manpath path
32c535eb59SGordon Tetlow# Adds a variable to manpath while ensuring we don't have duplicates.
33c535eb59SGordon Tetlow# Returns true if we were able to add something. False otherwise.
34c535eb59SGordon Tetlowadd_to_manpath() {
35c535eb59SGordon Tetlow	case "$manpath" in
36c535eb59SGordon Tetlow	*:$1)	decho "  Skipping duplicate manpath entry $1" 2 ;;
37c535eb59SGordon Tetlow	$1:*)	decho "  Skipping duplicate manpath entry $1" 2 ;;
38c535eb59SGordon Tetlow	*:$1:*)	decho "  Skipping duplicate manpath entry $1" 2 ;;
39c535eb59SGordon Tetlow	*)	if [ -d "$1" ]; then
40c535eb59SGordon Tetlow			decho "  Adding $1 to manpath"
41c535eb59SGordon Tetlow			manpath="$manpath:$1"
42c535eb59SGordon Tetlow			return 0
43c535eb59SGordon Tetlow		fi
44c535eb59SGordon Tetlow		;;
45c535eb59SGordon Tetlow	esac
46c535eb59SGordon Tetlow
47c535eb59SGordon Tetlow	return 1
48c535eb59SGordon Tetlow}
49c535eb59SGordon Tetlow
50c535eb59SGordon Tetlow# Usage: build_manlocales
51c535eb59SGordon Tetlow# Builds a correct MANLOCALES variable.
52c535eb59SGordon Tetlowbuild_manlocales() {
53c535eb59SGordon Tetlow	# If the user has set manlocales, who are we to argue.
54c535eb59SGordon Tetlow	if [ -n "$MANLOCALES" ]; then
55c535eb59SGordon Tetlow		return
56c535eb59SGordon Tetlow	fi
57c535eb59SGordon Tetlow
58c535eb59SGordon Tetlow	parse_configs
59c535eb59SGordon Tetlow
60c535eb59SGordon Tetlow	# Trim leading colon
61c535eb59SGordon Tetlow	MANLOCALES=${manlocales#:}
62c535eb59SGordon Tetlow
63c535eb59SGordon Tetlow	decho "Available manual locales: $MANLOCALES"
64c535eb59SGordon Tetlow}
65c535eb59SGordon Tetlow
66c535eb59SGordon Tetlow# Usage: build_manpath
67c535eb59SGordon Tetlow# Builds a correct MANPATH variable.
68c535eb59SGordon Tetlowbuild_manpath() {
69c535eb59SGordon Tetlow	local IFS
70c535eb59SGordon Tetlow
71c535eb59SGordon Tetlow	# If the user has set a manpath, who are we to argue.
72c535eb59SGordon Tetlow	if [ -n "$MANPATH" ]; then
73b2394e73SBaptiste Daroussin		case "$MANPATH" in
74b2394e73SBaptiste Daroussin		*:) PREPEND_MANPATH=${MANPATH} ;;
75b2394e73SBaptiste Daroussin		:*) APPEND_MANPATH=${MANPATH} ;;
76b2394e73SBaptiste Daroussin		*::*)
77b2394e73SBaptiste Daroussin			PREPEND_MANPATH=${MANPATH%%::*}
78b2394e73SBaptiste Daroussin			APPEND_MANPATH=${MANPATH#*::}
79b2394e73SBaptiste Daroussin			;;
80b2394e73SBaptiste Daroussin		*) return ;;
81b2394e73SBaptiste Daroussin		esac
82b2394e73SBaptiste Daroussin	fi
83b2394e73SBaptiste Daroussin
84b2394e73SBaptiste Daroussin	if [ -n "$PREPEND_MANPATH" ]; then
85b2394e73SBaptiste Daroussin		IFS=:
86b2394e73SBaptiste Daroussin		for path in $PREPEND_MANPATH; do
87b2394e73SBaptiste Daroussin			add_to_manpath "$path"
88b2394e73SBaptiste Daroussin		done
89b2394e73SBaptiste Daroussin		unset IFS
90c535eb59SGordon Tetlow	fi
91c535eb59SGordon Tetlow
92c535eb59SGordon Tetlow	search_path
93c535eb59SGordon Tetlow
94c535eb59SGordon Tetlow	decho "Adding default manpath entries"
95c535eb59SGordon Tetlow	IFS=:
96c535eb59SGordon Tetlow	for path in $man_default_path; do
97c535eb59SGordon Tetlow		add_to_manpath "$path"
98c535eb59SGordon Tetlow	done
99c535eb59SGordon Tetlow	unset IFS
100c535eb59SGordon Tetlow
101c535eb59SGordon Tetlow	parse_configs
102c535eb59SGordon Tetlow
103b2394e73SBaptiste Daroussin	if [ -n "$APPEND_MANPATH" ]; then
104b2394e73SBaptiste Daroussin		IFS=:
105b2394e73SBaptiste Daroussin		for path in $APPEND_MANPATH; do
106b2394e73SBaptiste Daroussin			add_to_manpath "$path"
107b2394e73SBaptiste Daroussin		done
108b2394e73SBaptiste Daroussin		unset IFS
109b2394e73SBaptiste Daroussin	fi
110c535eb59SGordon Tetlow	# Trim leading colon
111c535eb59SGordon Tetlow	MANPATH=${manpath#:}
112c535eb59SGordon Tetlow
113c535eb59SGordon Tetlow	decho "Using manual path: $MANPATH"
114c535eb59SGordon Tetlow}
115c535eb59SGordon Tetlow
116c535eb59SGordon Tetlow# Usage: check_cat catglob
117c535eb59SGordon Tetlow# Checks to see if a cat glob is available.
118c535eb59SGordon Tetlowcheck_cat() {
119c535eb59SGordon Tetlow	if exists "$1"; then
120c535eb59SGordon Tetlow		use_cat=yes
121c535eb59SGordon Tetlow		catpage=$found
12257cd9717SGordon Tetlow		setup_cattool $catpage
123c535eb59SGordon Tetlow		decho "    Found catpage $catpage"
124c535eb59SGordon Tetlow		return 0
125c535eb59SGordon Tetlow	else
126c535eb59SGordon Tetlow		return 1
127c535eb59SGordon Tetlow	fi
128c535eb59SGordon Tetlow}
129c535eb59SGordon Tetlow
130c535eb59SGordon Tetlow# Usage: check_man manglob catglob
131c535eb59SGordon Tetlow# Given 2 globs, figures out if the manglob is available, if so, check to
132c535eb59SGordon Tetlow# see if the catglob is also available and up to date.
133c535eb59SGordon Tetlowcheck_man() {
134c535eb59SGordon Tetlow	if exists "$1"; then
135c535eb59SGordon Tetlow		# We have a match, check for a cat page
136c535eb59SGordon Tetlow		manpage=$found
13757cd9717SGordon Tetlow		setup_cattool $manpage
138c535eb59SGordon Tetlow		decho "    Found manpage $manpage"
139c535eb59SGordon Tetlow
140a0094449SRuslan Ermilov		if [ -n "${use_width}" ]; then
141a0094449SRuslan Ermilov			# non-standard width
142a0094449SRuslan Ermilov			unset use_cat
143a0094449SRuslan Ermilov			decho "    Skipping catpage: non-standard page width"
144a0094449SRuslan Ermilov		elif exists "$2" && is_newer $found $manpage; then
145c535eb59SGordon Tetlow			# cat page found and is newer, use that
146c535eb59SGordon Tetlow			use_cat=yes
147c535eb59SGordon Tetlow			catpage=$found
14857cd9717SGordon Tetlow			setup_cattool $catpage
149c535eb59SGordon Tetlow			decho "    Using catpage $catpage"
150c535eb59SGordon Tetlow		else
151c535eb59SGordon Tetlow			# no cat page or is older
152c535eb59SGordon Tetlow			unset use_cat
153c535eb59SGordon Tetlow			decho "    Skipping catpage: not found or old"
154c535eb59SGordon Tetlow		fi
155c535eb59SGordon Tetlow		return 0
156c535eb59SGordon Tetlow	fi
157c535eb59SGordon Tetlow
158c535eb59SGordon Tetlow	return 1
159c535eb59SGordon Tetlow}
160c535eb59SGordon Tetlow
161c535eb59SGordon Tetlow# Usage: decho "string" [debuglevel]
162c535eb59SGordon Tetlow# Echoes to stderr string prefaced with -- if high enough debuglevel.
163c535eb59SGordon Tetlowdecho() {
164c535eb59SGordon Tetlow	if [ $debug -ge ${2:-1} ]; then
165c535eb59SGordon Tetlow		echo "-- $1" >&2
166c535eb59SGordon Tetlow	fi
167c535eb59SGordon Tetlow}
168c535eb59SGordon Tetlow
169c535eb59SGordon Tetlow# Usage: exists glob
170c535eb59SGordon Tetlow# Returns true if glob resolves to a real file.
171c535eb59SGordon Tetlowexists() {
172c535eb59SGordon Tetlow	local IFS
173c535eb59SGordon Tetlow
174c535eb59SGordon Tetlow	# Don't accidentally inherit callers IFS (breaks perl manpages)
175c535eb59SGordon Tetlow	unset IFS
176c535eb59SGordon Tetlow
177c535eb59SGordon Tetlow	# Use some globbing tricks in the shell to determine if a file
178c535eb59SGordon Tetlow	# exists or not.
179c535eb59SGordon Tetlow	set +f
180c535eb59SGordon Tetlow	set -- "$1" $1
181c535eb59SGordon Tetlow	set -f
182c535eb59SGordon Tetlow
183c535eb59SGordon Tetlow	if [ "$1" != "$2" -a -r "$2" ]; then
184c535eb59SGordon Tetlow		found="$2"
185c535eb59SGordon Tetlow		return 0
186c535eb59SGordon Tetlow	fi
187c535eb59SGordon Tetlow
188c535eb59SGordon Tetlow	return 1
189c535eb59SGordon Tetlow}
190c535eb59SGordon Tetlow
191c535eb59SGordon Tetlow# Usage: find_file path section subdir pagename
192c535eb59SGordon Tetlow# Returns: true if something is matched and found.
193c535eb59SGordon Tetlow# Search the given path/section combo for a given page.
194c535eb59SGordon Tetlowfind_file() {
195c535eb59SGordon Tetlow	local manroot catroot mann man0 catn cat0
196c535eb59SGordon Tetlow
197c535eb59SGordon Tetlow	manroot="$1/man$2"
198c535eb59SGordon Tetlow	catroot="$1/cat$2"
199c535eb59SGordon Tetlow	if [ -n "$3" ]; then
200c535eb59SGordon Tetlow		manroot="$manroot/$3"
201c535eb59SGordon Tetlow		catroot="$catroot/$3"
202c535eb59SGordon Tetlow	fi
203c535eb59SGordon Tetlow
204625490e8SBaptiste Daroussin	if [ ! -d "$manroot" -a ! -d "$catroot" ]; then
205c535eb59SGordon Tetlow		return 1
206c535eb59SGordon Tetlow	fi
207c535eb59SGordon Tetlow	decho "  Searching directory $manroot" 2
208c535eb59SGordon Tetlow
209c535eb59SGordon Tetlow	mann="$manroot/$4.$2*"
210c535eb59SGordon Tetlow	man0="$manroot/$4.0*"
211c535eb59SGordon Tetlow	catn="$catroot/$4.$2*"
212c535eb59SGordon Tetlow	cat0="$catroot/$4.0*"
213c535eb59SGordon Tetlow
214c535eb59SGordon Tetlow	# This is the behavior as seen by the original man utility.
215c535eb59SGordon Tetlow	# Let's not change that which doesn't seem broken.
216c535eb59SGordon Tetlow	if check_man "$mann" "$catn"; then
217c535eb59SGordon Tetlow		return 0
218c535eb59SGordon Tetlow	elif check_man "$man0" "$cat0"; then
219c535eb59SGordon Tetlow		return 0
220c535eb59SGordon Tetlow	elif check_cat "$catn"; then
221c535eb59SGordon Tetlow		return 0
222c535eb59SGordon Tetlow	elif check_cat "$cat0"; then
223c535eb59SGordon Tetlow		return 0
224c535eb59SGordon Tetlow	fi
225c535eb59SGordon Tetlow
226c535eb59SGordon Tetlow	return 1
227c535eb59SGordon Tetlow}
228c535eb59SGordon Tetlow
229c535eb59SGordon Tetlow# Usage: is_newer file1 file2
230c535eb59SGordon Tetlow# Returns true if file1 is newer than file2 as calculated by mtime.
231c535eb59SGordon Tetlowis_newer() {
2329b61837aSUlrich Spörlein	if ! [ "$1" -ot "$2" ]; then
2339b61837aSUlrich Spörlein		decho "    mtime: $1 not older than $2" 3
234c535eb59SGordon Tetlow		return 0
235c535eb59SGordon Tetlow	else
236c535eb59SGordon Tetlow		decho "    mtime: $1 older than $2" 3
237c535eb59SGordon Tetlow		return 1
238c535eb59SGordon Tetlow	fi
239c535eb59SGordon Tetlow}
240c535eb59SGordon Tetlow
241c535eb59SGordon Tetlow# Usage: manpath_parse_args "$@"
242c535eb59SGordon Tetlow# Parses commandline options for manpath.
243c535eb59SGordon Tetlowmanpath_parse_args() {
244c535eb59SGordon Tetlow	local cmd_arg
245c535eb59SGordon Tetlow
246*f555b39eSKyle Evans	OPTIND=1
247c535eb59SGordon Tetlow	while getopts 'Ldq' cmd_arg; do
248c535eb59SGordon Tetlow		case "${cmd_arg}" in
249c535eb59SGordon Tetlow		L)	Lflag=Lflag ;;
250c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
251c535eb59SGordon Tetlow		q)	qflag=qflag ;;
252c535eb59SGordon Tetlow		*)	manpath_usage ;;
253c535eb59SGordon Tetlow		esac
254c535eb59SGordon Tetlow	done >&2
255c535eb59SGordon Tetlow}
256c535eb59SGordon Tetlow
257c535eb59SGordon Tetlow# Usage: manpath_usage
258c535eb59SGordon Tetlow# Display usage for the manpath(1) utility.
259c535eb59SGordon Tetlowmanpath_usage() {
260c535eb59SGordon Tetlow	echo 'usage: manpath [-Ldq]' >&2
261c535eb59SGordon Tetlow	exit 1
262c535eb59SGordon Tetlow}
263c535eb59SGordon Tetlow
264c535eb59SGordon Tetlow# Usage: manpath_warnings
265c535eb59SGordon Tetlow# Display some warnings to stderr.
266c535eb59SGordon Tetlowmanpath_warnings() {
267c535eb59SGordon Tetlow	if [ -n "$Lflag" -a -n "$MANLOCALES" ]; then
268c535eb59SGordon Tetlow		echo "(Warning: MANLOCALES environment variable set)" >&2
269c535eb59SGordon Tetlow	fi
270c535eb59SGordon Tetlow}
271c535eb59SGordon Tetlow
27257cd9717SGordon Tetlow# Usage: man_check_for_so page path
27357cd9717SGordon Tetlow# Returns: True if able to resolve the file, false if it ended in tears.
27457cd9717SGordon Tetlow# Detects the presence of the .so directive and causes the file to be
27557cd9717SGordon Tetlow# redirected to another source file.
27657cd9717SGordon Tetlowman_check_for_so() {
27757cd9717SGordon Tetlow	local IFS line tstr
27857cd9717SGordon Tetlow
27957cd9717SGordon Tetlow	unset IFS
280d9405a92SBaptiste Daroussin	if [ -n "$catpage" ]; then
281d9405a92SBaptiste Daroussin		return 0
282d9405a92SBaptiste Daroussin	fi
28357cd9717SGordon Tetlow
28457cd9717SGordon Tetlow	# We need to loop to accommodate multiple .so directives.
28557cd9717SGordon Tetlow	while true
28657cd9717SGordon Tetlow	do
28757cd9717SGordon Tetlow		line=$($cattool $manpage | head -1)
28857cd9717SGordon Tetlow		case "$line" in
28957cd9717SGordon Tetlow		.so*)	trim "${line#.so}"
29057cd9717SGordon Tetlow			decho "$manpage includes $tstr"
29157cd9717SGordon Tetlow			# Glob and check for the file.
29257cd9717SGordon Tetlow			if ! check_man "$path/$tstr*" ""; then
29357cd9717SGordon Tetlow				decho "  Unable to find $tstr"
29457cd9717SGordon Tetlow				return 1
29557cd9717SGordon Tetlow			fi
29657cd9717SGordon Tetlow			;;
29757cd9717SGordon Tetlow		*)	break ;;
29857cd9717SGordon Tetlow		esac
29957cd9717SGordon Tetlow	done
30057cd9717SGordon Tetlow
30157cd9717SGordon Tetlow	return 0
30257cd9717SGordon Tetlow}
30357cd9717SGordon Tetlow
304b43edc06SBaptiste Daroussin# Usage: man_display_page
305b43edc06SBaptiste Daroussin# Display either the manpage or catpage depending on the use_cat variable
306c535eb59SGordon Tetlowman_display_page() {
3071fb816daSBaptiste Daroussin	local IFS pipeline testline
308c535eb59SGordon Tetlow
309c535eb59SGordon Tetlow	# We are called with IFS set to colon. This causes really weird
310c535eb59SGordon Tetlow	# things to happen for the variables that have spaces in them.
311c535eb59SGordon Tetlow	unset IFS
312c535eb59SGordon Tetlow
313c535eb59SGordon Tetlow	# If we are supposed to use a catpage and we aren't using troff(1)
314c535eb59SGordon Tetlow	# just zcat the catpage and we are done.
315c535eb59SGordon Tetlow	if [ -z "$tflag" -a -n "$use_cat" ]; then
316c535eb59SGordon Tetlow		if [ -n "$wflag" ]; then
317c535eb59SGordon Tetlow			echo "$catpage (source: $manpage)"
318c535eb59SGordon Tetlow			ret=0
319c535eb59SGordon Tetlow		else
320c535eb59SGordon Tetlow			if [ $debug -gt 0 ]; then
321a6a3e856SRuslan Ermilov				decho "Command: $cattool $catpage | $MANPAGER"
322c535eb59SGordon Tetlow				ret=0
323c535eb59SGordon Tetlow			else
324a6a3e856SRuslan Ermilov				eval "$cattool $catpage | $MANPAGER"
325c535eb59SGordon Tetlow				ret=$?
326c535eb59SGordon Tetlow			fi
327c535eb59SGordon Tetlow		fi
328c535eb59SGordon Tetlow		return
329c535eb59SGordon Tetlow	fi
330c535eb59SGordon Tetlow
331c535eb59SGordon Tetlow	# Okay, we are using the manpage, do we just need to output the
332c535eb59SGordon Tetlow	# name of the manpage?
333c535eb59SGordon Tetlow	if [ -n "$wflag" ]; then
334c535eb59SGordon Tetlow		echo "$manpage"
335c535eb59SGordon Tetlow		ret=0
336c535eb59SGordon Tetlow		return
337c535eb59SGordon Tetlow	fi
338c535eb59SGordon Tetlow
339d433cf9aSBaptiste Daroussin	if [ -n "$use_width" ]; then
340d433cf9aSBaptiste Daroussin		mandoc_args="-O width=${use_width}"
341d433cf9aSBaptiste Daroussin	fi
342451c2becSBaptiste Daroussin	testline="mandoc -Tlint -Wunsupp >/dev/null 2>&1"
343449a792dSBaptiste Daroussin	if [ -n "$tflag" ]; then
344449a792dSBaptiste Daroussin		pipeline="mandoc -Tps $mandoc_args"
345449a792dSBaptiste Daroussin	else
346d433cf9aSBaptiste Daroussin		pipeline="mandoc $mandoc_args | $MANPAGER"
347449a792dSBaptiste Daroussin	fi
348d6096801SBaptiste Daroussin
349d6096801SBaptiste Daroussin	if ! eval "$cattool $manpage | $testline" ;then
350f17575acSBaptiste Daroussin		if which -s groff; then
351d6096801SBaptiste Daroussin			man_display_page_groff
352d6096801SBaptiste Daroussin		else
353d6096801SBaptiste Daroussin			echo "This manpage needs groff(1) to be rendered" >&2
354d6096801SBaptiste Daroussin			echo "First install groff(1): " >&2
355d6096801SBaptiste Daroussin			echo "pkg install groff " >&2
356d6096801SBaptiste Daroussin			ret=1
357d6096801SBaptiste Daroussin		fi
358d6096801SBaptiste Daroussin		return
359d6096801SBaptiste Daroussin	fi
360d6096801SBaptiste Daroussin
361d6096801SBaptiste Daroussin	if [ $debug -gt 0 ]; then
362d6096801SBaptiste Daroussin		decho "Command: $cattool $manpage | $pipeline"
363d6096801SBaptiste Daroussin		ret=0
364d6096801SBaptiste Daroussin	else
365d6096801SBaptiste Daroussin		eval "$cattool $manpage | $pipeline"
366d6096801SBaptiste Daroussin		ret=$?
367d6096801SBaptiste Daroussin	fi
368d6096801SBaptiste Daroussin}
369d6096801SBaptiste Daroussin
370b43edc06SBaptiste Daroussin# Usage: man_display_page_groff
371b43edc06SBaptiste Daroussin# Display the manpage using groff
372d6096801SBaptiste Daroussinman_display_page_groff() {
373d6096801SBaptiste Daroussin	local EQN NROFF PIC TBL TROFF REFER VGRIND
374d6096801SBaptiste Daroussin	local IFS l nroff_dev pipeline preproc_arg tool
375d6096801SBaptiste Daroussin
376c535eb59SGordon Tetlow	# So, we really do need to parse the manpage. First, figure out the
377c535eb59SGordon Tetlow	# device flag (-T) we have to pass to eqn(1) and groff(1). Then,
378c535eb59SGordon Tetlow	# setup the pipeline of commands based on the user's request.
379c535eb59SGordon Tetlow
380deeff310SGordon Tetlow	# If the manpage is from a particular charset, we need to setup nroff
381deeff310SGordon Tetlow	# to properly output for the correct device.
382deeff310SGordon Tetlow	case "${manpage}" in
383deeff310SGordon Tetlow	*.${man_charset}/*)
384c535eb59SGordon Tetlow		# I don't pretend to know this; I'm just copying from the
385c535eb59SGordon Tetlow		# previous version of man(1).
386c535eb59SGordon Tetlow		case "$man_charset" in
387c535eb59SGordon Tetlow		KOI8-R)		nroff_dev="koi8-r" ;;
388c535eb59SGordon Tetlow		ISO8859-1)	nroff_dev="latin1" ;;
389c535eb59SGordon Tetlow		ISO8859-15)	nroff_dev="latin1" ;;
390c535eb59SGordon Tetlow		UTF-8)		nroff_dev="utf8" ;;
391c535eb59SGordon Tetlow		*)		nroff_dev="ascii" ;;
392c535eb59SGordon Tetlow		esac
393c535eb59SGordon Tetlow
394deeff310SGordon Tetlow		NROFF="$NROFF -T$nroff_dev"
395c535eb59SGordon Tetlow		EQN="$EQN -T$nroff_dev"
396c535eb59SGordon Tetlow
397deeff310SGordon Tetlow		# Iff the manpage is from the locale and not just the charset,
398deeff310SGordon Tetlow		# then we need to define the locale string.
399deeff310SGordon Tetlow		case "${manpage}" in
400deeff310SGordon Tetlow		*/${man_lang}_${man_country}.${man_charset}/*)
401deeff310SGordon Tetlow			NROFF="$NROFF -dlocale=$man_lang.$man_charset"
402deeff310SGordon Tetlow			;;
403deeff310SGordon Tetlow		*/${man_lang}.${man_charset}/*)
404deeff310SGordon Tetlow			NROFF="$NROFF -dlocale=$man_lang.$man_charset"
405deeff310SGordon Tetlow			;;
406deeff310SGordon Tetlow		esac
407deeff310SGordon Tetlow
408c535eb59SGordon Tetlow		# Allow language specific calls to override the default
409c535eb59SGordon Tetlow		# set of utilities.
410c535eb59SGordon Tetlow		l=$(echo $man_lang | tr [:lower:] [:upper:])
411b70e2025SRuslan Ermilov		for tool in EQN NROFF PIC TBL TROFF REFER VGRIND; do
412c535eb59SGordon Tetlow			eval "$tool=\${${tool}_$l:-\$$tool}"
413c535eb59SGordon Tetlow		done
414c535eb59SGordon Tetlow		;;
415c535eb59SGordon Tetlow	*)	NROFF="$NROFF -Tascii"
416c535eb59SGordon Tetlow		EQN="$EQN -Tascii"
417c535eb59SGordon Tetlow		;;
418c535eb59SGordon Tetlow	esac
419c535eb59SGordon Tetlow
420a6a3e856SRuslan Ermilov	if [ -z "$MANCOLOR" ]; then
421a6a3e856SRuslan Ermilov		NROFF="$NROFF -P-c"
422a6a3e856SRuslan Ermilov	fi
423a6a3e856SRuslan Ermilov
424a0094449SRuslan Ermilov	if [ -n "${use_width}" ]; then
425a0094449SRuslan Ermilov		NROFF="$NROFF -rLL=${use_width}n -rLT=${use_width}n"
426a0094449SRuslan Ermilov	fi
427a0094449SRuslan Ermilov
428c535eb59SGordon Tetlow	if [ -n "$MANROFFSEQ" ]; then
429c535eb59SGordon Tetlow		set -- -$MANROFFSEQ
430*f555b39eSKyle Evans		OPTIND=1
431c535eb59SGordon Tetlow		while getopts 'egprtv' preproc_arg; do
432c535eb59SGordon Tetlow			case "${preproc_arg}" in
433c535eb59SGordon Tetlow			e)	pipeline="$pipeline | $EQN" ;;
434487ac9acSUlrich Spörlein			g)	;; # Ignore for compatibility.
435c535eb59SGordon Tetlow			p)	pipeline="$pipeline | $PIC" ;;
436c535eb59SGordon Tetlow			r)	pipeline="$pipeline | $REFER" ;;
437b70e2025SRuslan Ermilov			t)	pipeline="$pipeline | $TBL" ;;
438c535eb59SGordon Tetlow			v)	pipeline="$pipeline | $VGRIND" ;;
439c535eb59SGordon Tetlow			*)	usage ;;
440c535eb59SGordon Tetlow			esac
441c535eb59SGordon Tetlow		done
442c535eb59SGordon Tetlow		# Strip the leading " | " from the resulting pipeline.
443c535eb59SGordon Tetlow		pipeline="${pipeline#" | "}"
444c535eb59SGordon Tetlow	else
445c535eb59SGordon Tetlow		pipeline="$TBL"
446c535eb59SGordon Tetlow	fi
447c535eb59SGordon Tetlow
448c535eb59SGordon Tetlow	if [ -n "$tflag" ]; then
449c535eb59SGordon Tetlow		pipeline="$pipeline | $TROFF"
450c535eb59SGordon Tetlow	else
451a6a3e856SRuslan Ermilov		pipeline="$pipeline | $NROFF | $MANPAGER"
452c535eb59SGordon Tetlow	fi
453c535eb59SGordon Tetlow
454c535eb59SGordon Tetlow	if [ $debug -gt 0 ]; then
45557cd9717SGordon Tetlow		decho "Command: $cattool $manpage | $pipeline"
456c535eb59SGordon Tetlow		ret=0
457c535eb59SGordon Tetlow	else
45857cd9717SGordon Tetlow		eval "$cattool $manpage | $pipeline"
459c535eb59SGordon Tetlow		ret=$?
460c535eb59SGordon Tetlow	fi
461c535eb59SGordon Tetlow}
462c535eb59SGordon Tetlow
463c535eb59SGordon Tetlow# Usage: man_find_and_display page
464c535eb59SGordon Tetlow# Search through the manpaths looking for the given page.
465c535eb59SGordon Tetlowman_find_and_display() {
466c535eb59SGordon Tetlow	local found_page locpath p path sect
467c535eb59SGordon Tetlow
4683d9127f1SGordon Tetlow	# Check to see if it's a file. But only if it has a '/' in
4693d9127f1SGordon Tetlow	# the filename.
4703d9127f1SGordon Tetlow	case "$1" in
4713d9127f1SGordon Tetlow	*/*)	if [ -f "$1" -a -r "$1" ]; then
4723d9127f1SGordon Tetlow			decho "Found a usable page, displaying that"
4733d9127f1SGordon Tetlow			unset use_cat
4743d9127f1SGordon Tetlow			manpage="$1"
47557cd9717SGordon Tetlow			setup_cattool $manpage
47657cd9717SGordon Tetlow			if man_check_for_so $manpage $(dirname $manpage); then
47757cd9717SGordon Tetlow				found_page=yes
4783d9127f1SGordon Tetlow				man_display_page
47957cd9717SGordon Tetlow			fi
4803d9127f1SGordon Tetlow			return
4813d9127f1SGordon Tetlow		fi
4823d9127f1SGordon Tetlow		;;
4833d9127f1SGordon Tetlow	esac
4843d9127f1SGordon Tetlow
485c535eb59SGordon Tetlow	IFS=:
486c535eb59SGordon Tetlow	for sect in $MANSECT; do
487c535eb59SGordon Tetlow		decho "Searching section $sect" 2
488c535eb59SGordon Tetlow		for path in $MANPATH; do
489c535eb59SGordon Tetlow			for locpath in $locpaths; do
490c535eb59SGordon Tetlow				p=$path/$locpath
491c535eb59SGordon Tetlow				p=${p%/.} # Rid ourselves of the trailing /.
492c535eb59SGordon Tetlow
493c535eb59SGordon Tetlow				# Check if there is a MACHINE specific manpath.
494c535eb59SGordon Tetlow				if find_file $p $sect $MACHINE "$1"; then
49557cd9717SGordon Tetlow					if man_check_for_so $manpage $p; then
496c535eb59SGordon Tetlow						found_page=yes
497c535eb59SGordon Tetlow						man_display_page
4981d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
4991d7c660aSGordon Tetlow							continue 2
5001d7c660aSGordon Tetlow						else
501c535eb59SGordon Tetlow							return
502c535eb59SGordon Tetlow						fi
503c535eb59SGordon Tetlow					fi
50457cd9717SGordon Tetlow				fi
505c535eb59SGordon Tetlow
506c535eb59SGordon Tetlow				# Check if there is a MACHINE_ARCH
507c535eb59SGordon Tetlow				# specific manpath.
508c535eb59SGordon Tetlow				if find_file $p $sect $MACHINE_ARCH "$1"; then
50957cd9717SGordon Tetlow					if man_check_for_so $manpage $p; then
510c535eb59SGordon Tetlow						found_page=yes
511c535eb59SGordon Tetlow						man_display_page
5121d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
5131d7c660aSGordon Tetlow							continue 2
5141d7c660aSGordon Tetlow						else
515c535eb59SGordon Tetlow							return
516c535eb59SGordon Tetlow						fi
517c535eb59SGordon Tetlow					fi
51857cd9717SGordon Tetlow				fi
519c535eb59SGordon Tetlow
520c535eb59SGordon Tetlow				# Check plain old manpath.
521c535eb59SGordon Tetlow				if find_file $p $sect '' "$1"; then
52257cd9717SGordon Tetlow					if man_check_for_so $manpage $p; then
523c535eb59SGordon Tetlow						found_page=yes
524c535eb59SGordon Tetlow						man_display_page
5251d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
5261d7c660aSGordon Tetlow							continue 2
5271d7c660aSGordon Tetlow						else
528c535eb59SGordon Tetlow							return
529c535eb59SGordon Tetlow						fi
530c535eb59SGordon Tetlow					fi
53157cd9717SGordon Tetlow				fi
532c535eb59SGordon Tetlow			done
533c535eb59SGordon Tetlow		done
534c535eb59SGordon Tetlow	done
535c535eb59SGordon Tetlow	unset IFS
536c535eb59SGordon Tetlow
537c535eb59SGordon Tetlow	# Nothing? Well, we are done then.
538c535eb59SGordon Tetlow	if [ -z "$found_page" ]; then
539c535eb59SGordon Tetlow		echo "No manual entry for $1" >&2
540c535eb59SGordon Tetlow		ret=1
541c535eb59SGordon Tetlow		return
542c535eb59SGordon Tetlow	fi
543c535eb59SGordon Tetlow}
544c535eb59SGordon Tetlow
545c535eb59SGordon Tetlow# Usage: man_parse_args "$@"
546c535eb59SGordon Tetlow# Parses commandline options for man.
547c535eb59SGordon Tetlowman_parse_args() {
548c535eb59SGordon Tetlow	local IFS cmd_arg
549c535eb59SGordon Tetlow
550*f555b39eSKyle Evans	OPTIND=1
551c535eb59SGordon Tetlow	while getopts 'M:P:S:adfhkm:op:tw' cmd_arg; do
552c535eb59SGordon Tetlow		case "${cmd_arg}" in
553c535eb59SGordon Tetlow		M)	MANPATH=$OPTARG ;;
554a6a3e856SRuslan Ermilov		P)	MANPAGER=$OPTARG ;;
555c535eb59SGordon Tetlow		S)	MANSECT=$OPTARG ;;
556c535eb59SGordon Tetlow		a)	aflag=aflag ;;
557c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
558c535eb59SGordon Tetlow		f)	fflag=fflag ;;
559c535eb59SGordon Tetlow		h)	man_usage 0 ;;
560c535eb59SGordon Tetlow		k)	kflag=kflag ;;
561c535eb59SGordon Tetlow		m)	mflag=$OPTARG ;;
562c535eb59SGordon Tetlow		o)	oflag=oflag ;;
563c535eb59SGordon Tetlow		p)	MANROFFSEQ=$OPTARG ;;
564c535eb59SGordon Tetlow		t)	tflag=tflag ;;
565c535eb59SGordon Tetlow		w)	wflag=wflag ;;
566c535eb59SGordon Tetlow		*)	man_usage ;;
567c535eb59SGordon Tetlow		esac
568c535eb59SGordon Tetlow	done >&2
569c535eb59SGordon Tetlow
570c535eb59SGordon Tetlow	shift $(( $OPTIND - 1 ))
571c535eb59SGordon Tetlow
572c535eb59SGordon Tetlow	# Check the args for incompatible options.
573c535eb59SGordon Tetlow	case "${fflag}${kflag}${tflag}${wflag}" in
574c535eb59SGordon Tetlow	fflagkflag*)	echo "Incompatible options: -f and -k"; man_usage ;;
575c535eb59SGordon Tetlow	fflag*tflag*)	echo "Incompatible options: -f and -t"; man_usage ;;
576c535eb59SGordon Tetlow	fflag*wflag)	echo "Incompatible options: -f and -w"; man_usage ;;
577c535eb59SGordon Tetlow	*kflagtflag*)	echo "Incompatible options: -k and -t"; man_usage ;;
578c535eb59SGordon Tetlow	*kflag*wflag)	echo "Incompatible options: -k and -w"; man_usage ;;
579c535eb59SGordon Tetlow	*tflagwflag)	echo "Incompatible options: -t and -w"; man_usage ;;
580c535eb59SGordon Tetlow	esac
581c535eb59SGordon Tetlow
582c535eb59SGordon Tetlow	# Short circuit for whatis(1) and apropos(1)
583c535eb59SGordon Tetlow	if [ -n "$fflag" ]; then
584c535eb59SGordon Tetlow		do_whatis "$@"
585c535eb59SGordon Tetlow		exit
586c535eb59SGordon Tetlow	fi
587c535eb59SGordon Tetlow
588c535eb59SGordon Tetlow	if [ -n "$kflag" ]; then
589c535eb59SGordon Tetlow		do_apropos "$@"
590c535eb59SGordon Tetlow		exit
591c535eb59SGordon Tetlow	fi
592c535eb59SGordon Tetlow
593c535eb59SGordon Tetlow	IFS=:
594c535eb59SGordon Tetlow	for sect in $man_default_sections; do
595c535eb59SGordon Tetlow		if [ "$sect" = "$1" ]; then
596c535eb59SGordon Tetlow			decho "Detected manual section as first arg: $1"
597c535eb59SGordon Tetlow			MANSECT="$1"
598c535eb59SGordon Tetlow			shift
599c535eb59SGordon Tetlow			break
600c535eb59SGordon Tetlow		fi
601c535eb59SGordon Tetlow	done
602c535eb59SGordon Tetlow	unset IFS
603c535eb59SGordon Tetlow
604c535eb59SGordon Tetlow	pages="$*"
605c535eb59SGordon Tetlow}
606c535eb59SGordon Tetlow
607c535eb59SGordon Tetlow# Usage: man_setup
608c535eb59SGordon Tetlow# Setup various trivial but essential variables.
609c535eb59SGordon Tetlowman_setup() {
610c535eb59SGordon Tetlow	# Setup machine and architecture variables.
611c535eb59SGordon Tetlow	if [ -n "$mflag" ]; then
612c535eb59SGordon Tetlow		MACHINE_ARCH=${mflag%%:*}
613c535eb59SGordon Tetlow		MACHINE=${mflag##*:}
614c535eb59SGordon Tetlow	fi
615c535eb59SGordon Tetlow	if [ -z "$MACHINE_ARCH" ]; then
61682db8a5eSGordon Tetlow		MACHINE_ARCH=$($SYSCTL -n hw.machine_arch)
617c535eb59SGordon Tetlow	fi
618c535eb59SGordon Tetlow	if [ -z "$MACHINE" ]; then
61982db8a5eSGordon Tetlow		MACHINE=$($SYSCTL -n hw.machine)
620c535eb59SGordon Tetlow	fi
621c535eb59SGordon Tetlow	decho "Using architecture: $MACHINE_ARCH:$MACHINE"
622c535eb59SGordon Tetlow
623c535eb59SGordon Tetlow	setup_pager
624c535eb59SGordon Tetlow
625c535eb59SGordon Tetlow	# Setup manual sections to search.
626c535eb59SGordon Tetlow	if [ -z "$MANSECT" ]; then
627c535eb59SGordon Tetlow		MANSECT=$man_default_sections
628c535eb59SGordon Tetlow	fi
629c535eb59SGordon Tetlow	decho "Using manual sections: $MANSECT"
630c535eb59SGordon Tetlow
631c535eb59SGordon Tetlow	build_manpath
632c535eb59SGordon Tetlow	man_setup_locale
633a0094449SRuslan Ermilov	man_setup_width
634a0094449SRuslan Ermilov}
635a0094449SRuslan Ermilov
636a0094449SRuslan Ermilov# Usage: man_setup_width
637a0094449SRuslan Ermilov# Set up page width.
638a0094449SRuslan Ermilovman_setup_width() {
639a0094449SRuslan Ermilov	local sizes
640a0094449SRuslan Ermilov
641a0094449SRuslan Ermilov	unset use_width
642a0094449SRuslan Ermilov	case "$MANWIDTH" in
643a0094449SRuslan Ermilov	[0-9]*)
644a0094449SRuslan Ermilov		if [ "$MANWIDTH" -gt 0 2>/dev/null ]; then
645a0094449SRuslan Ermilov			use_width=$MANWIDTH
646a0094449SRuslan Ermilov		fi
647a0094449SRuslan Ermilov		;;
648a0094449SRuslan Ermilov	[Tt][Tt][Yy])
649a0094449SRuslan Ermilov		if { sizes=$($STTY size 0>&3 2>/dev/null); } 3>&1; then
650a0094449SRuslan Ermilov			set -- $sizes
651a0094449SRuslan Ermilov			if [ $2 -gt 80 ]; then
652a0094449SRuslan Ermilov				use_width=$(($2-2))
653a0094449SRuslan Ermilov			fi
654a0094449SRuslan Ermilov		fi
655a0094449SRuslan Ermilov		;;
656a0094449SRuslan Ermilov	esac
657a0094449SRuslan Ermilov	if [ -n "$use_width" ]; then
658a0094449SRuslan Ermilov		decho "Using non-standard page width: ${use_width}"
659a0094449SRuslan Ermilov	else
660a0094449SRuslan Ermilov		decho 'Using standard page width'
661a0094449SRuslan Ermilov	fi
662c535eb59SGordon Tetlow}
663c535eb59SGordon Tetlow
664c535eb59SGordon Tetlow# Usage: man_setup_locale
665c535eb59SGordon Tetlow# Setup necessary locale variables.
666c535eb59SGordon Tetlowman_setup_locale() {
667deeff310SGordon Tetlow	local lang_cc
6689508f8c0SYuri Pankov	local locstr
669deeff310SGordon Tetlow
670deeff310SGordon Tetlow	locpaths='.'
671deeff310SGordon Tetlow	man_charset='US-ASCII'
672deeff310SGordon Tetlow
673c535eb59SGordon Tetlow	# Setup locale information.
674c535eb59SGordon Tetlow	if [ -n "$oflag" ]; then
675deeff310SGordon Tetlow		decho 'Using non-localized manpages'
676deeff310SGordon Tetlow	else
6779508f8c0SYuri Pankov		# Use the locale tool to give us proper locale information
678deeff310SGordon Tetlow		eval $( $LOCALE )
679c535eb59SGordon Tetlow
6809508f8c0SYuri Pankov		if [ -n "$LANG" ]; then
6819508f8c0SYuri Pankov			locstr=$LANG
6829508f8c0SYuri Pankov		else
6839508f8c0SYuri Pankov			locstr=$LC_CTYPE
6849508f8c0SYuri Pankov		fi
6859508f8c0SYuri Pankov
6869508f8c0SYuri Pankov		case "$locstr" in
687deeff310SGordon Tetlow		C)		;;
6889508f8c0SYuri Pankov		C.UTF-8)	;;
689deeff310SGordon Tetlow		POSIX)		;;
690deeff310SGordon Tetlow		[a-z][a-z]_[A-Z][A-Z]\.*)
6919508f8c0SYuri Pankov				lang_cc="${locstr%.*}"
6929508f8c0SYuri Pankov				man_lang="${locstr%_*}"
693deeff310SGordon Tetlow				man_country="${lang_cc#*_}"
6949508f8c0SYuri Pankov				man_charset="${locstr#*.}"
6959508f8c0SYuri Pankov				locpaths="$locstr"
696c535eb59SGordon Tetlow				locpaths="$locpaths:$man_lang.$man_charset"
697c535eb59SGordon Tetlow				if [ "$man_lang" != "en" ]; then
698c535eb59SGordon Tetlow					locpaths="$locpaths:en.$man_charset"
699c535eb59SGordon Tetlow				fi
700c535eb59SGordon Tetlow				locpaths="$locpaths:."
701deeff310SGordon Tetlow				;;
702deeff310SGordon Tetlow		*)		echo 'Unknown locale, assuming C' >&2
703deeff310SGordon Tetlow				;;
704deeff310SGordon Tetlow		esac
705c535eb59SGordon Tetlow	fi
706deeff310SGordon Tetlow
707c535eb59SGordon Tetlow	decho "Using locale paths: $locpaths"
708c535eb59SGordon Tetlow}
709c535eb59SGordon Tetlow
710c535eb59SGordon Tetlow# Usage: man_usage [exitcode]
711c535eb59SGordon Tetlow# Display usage for the man utility.
712c535eb59SGordon Tetlowman_usage() {
713c535eb59SGordon Tetlow	echo 'Usage:'
714c535eb59SGordon Tetlow	echo ' man [-adho] [-t | -w] [-M manpath] [-P pager] [-S mansect]'
715c535eb59SGordon Tetlow	echo '     [-m arch[:machine]] [-p [eprtv]] [mansect] page [...]'
716c535eb59SGordon Tetlow	echo ' man -f page [...] -- Emulates whatis(1)'
717c535eb59SGordon Tetlow	echo ' man -k page [...] -- Emulates apropos(1)'
718c535eb59SGordon Tetlow
719c535eb59SGordon Tetlow	# When exit'ing with -h, it's not an error.
720c535eb59SGordon Tetlow	exit ${1:-1}
721c535eb59SGordon Tetlow}
722c535eb59SGordon Tetlow
723c535eb59SGordon Tetlow# Usage: parse_configs
724c535eb59SGordon Tetlow# Reads the end-user adjustable config files.
725c535eb59SGordon Tetlowparse_configs() {
726c535eb59SGordon Tetlow	local IFS file files
727c535eb59SGordon Tetlow
728c535eb59SGordon Tetlow	if [ -n "$parsed_configs" ]; then
729c535eb59SGordon Tetlow		return
730c535eb59SGordon Tetlow	fi
731c535eb59SGordon Tetlow
732c535eb59SGordon Tetlow	unset IFS
733c535eb59SGordon Tetlow
734c535eb59SGordon Tetlow	# Read the global config first in case the user wants
735c535eb59SGordon Tetlow	# to override config_local.
736c535eb59SGordon Tetlow	if [ -r "$config_global" ]; then
737c535eb59SGordon Tetlow		parse_file "$config_global"
738c535eb59SGordon Tetlow	fi
739c535eb59SGordon Tetlow
740c535eb59SGordon Tetlow	# Glob the list of files to parse.
741c535eb59SGordon Tetlow	set +f
742c535eb59SGordon Tetlow	files=$(echo $config_local)
743c535eb59SGordon Tetlow	set -f
744c535eb59SGordon Tetlow
745c535eb59SGordon Tetlow	for file in $files; do
746c535eb59SGordon Tetlow		if [ -r "$file" ]; then
747c535eb59SGordon Tetlow			parse_file "$file"
748c535eb59SGordon Tetlow		fi
749c535eb59SGordon Tetlow	done
750c535eb59SGordon Tetlow
751c535eb59SGordon Tetlow	parsed_configs='yes'
752c535eb59SGordon Tetlow}
753c535eb59SGordon Tetlow
754c535eb59SGordon Tetlow# Usage: parse_file file
755c535eb59SGordon Tetlow# Reads the specified config files.
756c535eb59SGordon Tetlowparse_file() {
757c535eb59SGordon Tetlow	local file line tstr var
758c535eb59SGordon Tetlow
759c535eb59SGordon Tetlow	file="$1"
760c535eb59SGordon Tetlow	decho "Parsing config file: $file"
761c535eb59SGordon Tetlow	while read line; do
762c535eb59SGordon Tetlow		decho "  $line" 2
763c535eb59SGordon Tetlow		case "$line" in
764c535eb59SGordon Tetlow		\#*)		decho "    Comment" 3
765c535eb59SGordon Tetlow				;;
766c535eb59SGordon Tetlow		MANPATH*)	decho "    MANPATH" 3
767c535eb59SGordon Tetlow				trim "${line#MANPATH}"
768c535eb59SGordon Tetlow				add_to_manpath "$tstr"
769c535eb59SGordon Tetlow				;;
770c535eb59SGordon Tetlow		MANLOCALE*)	decho "    MANLOCALE" 3
771c535eb59SGordon Tetlow				trim "${line#MANLOCALE}"
772c535eb59SGordon Tetlow				manlocales="$manlocales:$tstr"
773c535eb59SGordon Tetlow				;;
774c535eb59SGordon Tetlow		MANCONFIG*)	decho "    MANCONFIG" 3
775a1528c80SRuslan Ermilov				trim "${line#MANCONFIG}"
776c535eb59SGordon Tetlow				config_local="$tstr"
777c535eb59SGordon Tetlow				;;
778c535eb59SGordon Tetlow		# Set variables in the form of FOO_BAR
779c535eb59SGordon Tetlow		*_*[\ \	]*)	var="${line%%[\ \	]*}"
780c535eb59SGordon Tetlow				trim "${line#$var}"
781c535eb59SGordon Tetlow				eval "$var=\"$tstr\""
782c535eb59SGordon Tetlow				decho "    Parsed $var" 3
783c535eb59SGordon Tetlow				;;
784c535eb59SGordon Tetlow		esac
785c535eb59SGordon Tetlow	done < "$file"
786c535eb59SGordon Tetlow}
787c535eb59SGordon Tetlow
788c535eb59SGordon Tetlow# Usage: search_path
789c535eb59SGordon Tetlow# Traverse $PATH looking for manpaths.
790c535eb59SGordon Tetlowsearch_path() {
791c535eb59SGordon Tetlow	local IFS p path
792c535eb59SGordon Tetlow
793c535eb59SGordon Tetlow	decho "Searching PATH for man directories"
794c535eb59SGordon Tetlow
795c535eb59SGordon Tetlow	IFS=:
796c535eb59SGordon Tetlow	for path in $PATH; do
797971c1c42STijl Coosemans		if add_to_manpath "$path/man"; then
798c535eb59SGordon Tetlow			:
799c535eb59SGordon Tetlow		elif add_to_manpath "$path/MAN"; then
800c535eb59SGordon Tetlow			:
801c535eb59SGordon Tetlow		else
802c535eb59SGordon Tetlow			case "$path" in
803971c1c42STijl Coosemans			*/bin)	p="${path%/bin}/share/man"
804c535eb59SGordon Tetlow				add_to_manpath "$p"
805971c1c42STijl Coosemans				p="${path%/bin}/man"
80661d5f2d1SBaptiste Daroussin				add_to_manpath "$p"
807c535eb59SGordon Tetlow				;;
808c535eb59SGordon Tetlow			esac
809c535eb59SGordon Tetlow		fi
810c535eb59SGordon Tetlow	done
811c535eb59SGordon Tetlow	unset IFS
812c535eb59SGordon Tetlow
813c535eb59SGordon Tetlow	if [ -z "$manpath" ]; then
814c535eb59SGordon Tetlow		decho '  Unable to find any manpaths, using default'
815c535eb59SGordon Tetlow		manpath=$man_default_path
816c535eb59SGordon Tetlow	fi
817c535eb59SGordon Tetlow}
818c535eb59SGordon Tetlow
819c535eb59SGordon Tetlow# Usage: search_whatis cmd [arglist]
820c535eb59SGordon Tetlow# Do the heavy lifting for apropos/whatis
821c535eb59SGordon Tetlowsearch_whatis() {
822c535eb59SGordon Tetlow	local IFS bad cmd f good key keywords loc opt out path rval wlist
823c535eb59SGordon Tetlow
824c535eb59SGordon Tetlow	cmd="$1"
825c535eb59SGordon Tetlow	shift
826c535eb59SGordon Tetlow
827c535eb59SGordon Tetlow	whatis_parse_args "$@"
828c535eb59SGordon Tetlow
829c535eb59SGordon Tetlow	build_manpath
830c535eb59SGordon Tetlow	build_manlocales
831c535eb59SGordon Tetlow	setup_pager
832c535eb59SGordon Tetlow
833c535eb59SGordon Tetlow	if [ "$cmd" = "whatis" ]; then
834c535eb59SGordon Tetlow		opt="-w"
835c535eb59SGordon Tetlow	fi
836c535eb59SGordon Tetlow
837c535eb59SGordon Tetlow	f='whatis'
838c535eb59SGordon Tetlow
839c535eb59SGordon Tetlow	IFS=:
840c535eb59SGordon Tetlow	for path in $MANPATH; do
841c535eb59SGordon Tetlow		if [ \! -d "$path" ]; then
842c535eb59SGordon Tetlow			decho "Skipping non-existent path: $path" 2
843c535eb59SGordon Tetlow			continue
844c535eb59SGordon Tetlow		fi
845c535eb59SGordon Tetlow
846c535eb59SGordon Tetlow		if [ -f "$path/$f" -a -r "$path/$f" ]; then
847c535eb59SGordon Tetlow			decho "Found whatis: $path/$f"
848c535eb59SGordon Tetlow			wlist="$wlist $path/$f"
849c535eb59SGordon Tetlow		fi
850c535eb59SGordon Tetlow
851c535eb59SGordon Tetlow		for loc in $MANLOCALES; do
852c535eb59SGordon Tetlow			if [ -f "$path/$loc/$f" -a -r "$path/$loc/$f" ]; then
853c535eb59SGordon Tetlow				decho "Found whatis: $path/$loc/$f"
854c535eb59SGordon Tetlow				wlist="$wlist $path/$loc/$f"
855c535eb59SGordon Tetlow			fi
856c535eb59SGordon Tetlow		done
857c535eb59SGordon Tetlow	done
858c535eb59SGordon Tetlow	unset IFS
859c535eb59SGordon Tetlow
860c535eb59SGordon Tetlow	if [ -z "$wlist" ]; then
861c535eb59SGordon Tetlow		echo "$cmd: no whatis databases in $MANPATH" >&2
862c535eb59SGordon Tetlow		exit 1
863c535eb59SGordon Tetlow	fi
864c535eb59SGordon Tetlow
865c535eb59SGordon Tetlow	rval=0
866c535eb59SGordon Tetlow	for key in $keywords; do
867c535eb59SGordon Tetlow		out=$(grep -Ehi $opt -- "$key" $wlist)
868c535eb59SGordon Tetlow		if [ -n "$out" ]; then
869c535eb59SGordon Tetlow			good="$good\\n$out"
870c535eb59SGordon Tetlow		else
871c535eb59SGordon Tetlow			bad="$bad\\n$key: nothing appropriate"
872c535eb59SGordon Tetlow			rval=1
873c535eb59SGordon Tetlow		fi
874c535eb59SGordon Tetlow	done
875c535eb59SGordon Tetlow
876c535eb59SGordon Tetlow	# Strip leading carriage return.
877c535eb59SGordon Tetlow	good=${good#\\n}
878c535eb59SGordon Tetlow	bad=${bad#\\n}
879c535eb59SGordon Tetlow
880c535eb59SGordon Tetlow	if [ -n "$good" ]; then
881a6a3e856SRuslan Ermilov		echo -e "$good" | $MANPAGER
882c535eb59SGordon Tetlow	fi
883c535eb59SGordon Tetlow
884c535eb59SGordon Tetlow	if [ -n "$bad" ]; then
88500e05e69SGordon Tetlow		echo -e "$bad" >&2
886c535eb59SGordon Tetlow	fi
887c535eb59SGordon Tetlow
888c535eb59SGordon Tetlow	exit $rval
889c535eb59SGordon Tetlow}
890c535eb59SGordon Tetlow
89157cd9717SGordon Tetlow# Usage: setup_cattool page
89257cd9717SGordon Tetlow# Finds an appropriate decompressor based on extension
89357cd9717SGordon Tetlowsetup_cattool() {
89457cd9717SGordon Tetlow	case "$1" in
89557cd9717SGordon Tetlow	*.bz)	cattool='/usr/bin/bzcat' ;;
89657cd9717SGordon Tetlow	*.bz2)	cattool='/usr/bin/bzcat' ;;
89757cd9717SGordon Tetlow	*.gz)	cattool='/usr/bin/zcat' ;;
89857cd9717SGordon Tetlow	*.lzma)	cattool='/usr/bin/lzcat' ;;
89957cd9717SGordon Tetlow	*.xz)	cattool='/usr/bin/xzcat' ;;
90057cd9717SGordon Tetlow	*)	cattool='/usr/bin/zcat -f' ;;
90157cd9717SGordon Tetlow	esac
90257cd9717SGordon Tetlow}
90357cd9717SGordon Tetlow
904c535eb59SGordon Tetlow# Usage: setup_pager
905a6a3e856SRuslan Ermilov# Correctly sets $MANPAGER
906c535eb59SGordon Tetlowsetup_pager() {
907c535eb59SGordon Tetlow	# Setup pager.
908a6a3e856SRuslan Ermilov	if [ -z "$MANPAGER" ]; then
909a6a3e856SRuslan Ermilov		if [ -n "$MANCOLOR" ]; then
910a6a3e856SRuslan Ermilov			MANPAGER="less -sR"
911a6a3e856SRuslan Ermilov		else
912a6a3e856SRuslan Ermilov			if [ -n "$PAGER" ]; then
913a6a3e856SRuslan Ermilov				MANPAGER="$PAGER"
914a6a3e856SRuslan Ermilov			else
91547cc9ee1SAlan Somers				MANPAGER="less -s"
916c535eb59SGordon Tetlow			fi
917a6a3e856SRuslan Ermilov		fi
918a6a3e856SRuslan Ermilov	fi
919a6a3e856SRuslan Ermilov	decho "Using pager: $MANPAGER"
920c535eb59SGordon Tetlow}
921c535eb59SGordon Tetlow
922c535eb59SGordon Tetlow# Usage: trim string
923c535eb59SGordon Tetlow# Trims whitespace from beginning and end of a variable
924c535eb59SGordon Tetlowtrim() {
925c535eb59SGordon Tetlow	tstr=$1
926c535eb59SGordon Tetlow	while true; do
927c535eb59SGordon Tetlow		case "$tstr" in
928c535eb59SGordon Tetlow		[\ \	]*)	tstr="${tstr##[\ \	]}" ;;
929c535eb59SGordon Tetlow		*[\ \	])	tstr="${tstr%%[\ \	]}" ;;
930c535eb59SGordon Tetlow		*)		break ;;
931c535eb59SGordon Tetlow		esac
932c535eb59SGordon Tetlow	done
933c535eb59SGordon Tetlow}
934c535eb59SGordon Tetlow
935c535eb59SGordon Tetlow# Usage: whatis_parse_args "$@"
936c535eb59SGordon Tetlow# Parse commandline args for whatis and apropos.
937c535eb59SGordon Tetlowwhatis_parse_args() {
938c535eb59SGordon Tetlow	local cmd_arg
939*f555b39eSKyle Evans	OPTIND=1
940c535eb59SGordon Tetlow	while getopts 'd' cmd_arg; do
941c535eb59SGordon Tetlow		case "${cmd_arg}" in
942c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
943c535eb59SGordon Tetlow		*)	whatis_usage ;;
944c535eb59SGordon Tetlow		esac
945c535eb59SGordon Tetlow	done >&2
946c535eb59SGordon Tetlow
947c535eb59SGordon Tetlow	shift $(( $OPTIND - 1 ))
948c535eb59SGordon Tetlow
949c535eb59SGordon Tetlow	keywords="$*"
950c535eb59SGordon Tetlow}
951c535eb59SGordon Tetlow
952c535eb59SGordon Tetlow# Usage: whatis_usage
953c535eb59SGordon Tetlow# Display usage for the whatis/apropos utility.
954c535eb59SGordon Tetlowwhatis_usage() {
955c535eb59SGordon Tetlow	echo "usage: $cmd [-d] keyword [...]"
956c535eb59SGordon Tetlow	exit 1
957c535eb59SGordon Tetlow}
958c535eb59SGordon Tetlow
959c535eb59SGordon Tetlow
960c535eb59SGordon Tetlow
961c535eb59SGordon Tetlow# Supported commands
962c535eb59SGordon Tetlowdo_apropos() {
96324ef7420SBaptiste Daroussin	[ $(stat -f %i /usr/bin/man) -ne $(stat -f %i /usr/bin/apropos) ] && \
964772246efSBaptiste Daroussin		exec apropos "$@"
965c535eb59SGordon Tetlow	search_whatis apropos "$@"
966c535eb59SGordon Tetlow}
967c535eb59SGordon Tetlow
968c535eb59SGordon Tetlowdo_man() {
969c535eb59SGordon Tetlow	man_parse_args "$@"
970c535eb59SGordon Tetlow	if [ -z "$pages" ]; then
971c535eb59SGordon Tetlow		echo 'What manual page do you want?' >&2
972c535eb59SGordon Tetlow		exit 1
973c535eb59SGordon Tetlow	fi
974c535eb59SGordon Tetlow	man_setup
975c535eb59SGordon Tetlow
976c535eb59SGordon Tetlow	for page in $pages; do
977c535eb59SGordon Tetlow		decho "Searching for $page"
978c535eb59SGordon Tetlow		man_find_and_display "$page"
979c535eb59SGordon Tetlow	done
980c535eb59SGordon Tetlow
981c535eb59SGordon Tetlow	exit ${ret:-0}
982c535eb59SGordon Tetlow}
983c535eb59SGordon Tetlow
984c535eb59SGordon Tetlowdo_manpath() {
985c535eb59SGordon Tetlow	manpath_parse_args "$@"
986c535eb59SGordon Tetlow	if [ -z "$qflag" ]; then
987c535eb59SGordon Tetlow		manpath_warnings
988c535eb59SGordon Tetlow	fi
989c535eb59SGordon Tetlow	if [ -n "$Lflag" ]; then
990c535eb59SGordon Tetlow		build_manlocales
991c535eb59SGordon Tetlow		echo $MANLOCALES
992c535eb59SGordon Tetlow	else
993c535eb59SGordon Tetlow		build_manpath
994c535eb59SGordon Tetlow		echo $MANPATH
995c535eb59SGordon Tetlow	fi
996c535eb59SGordon Tetlow	exit 0
997c535eb59SGordon Tetlow}
998c535eb59SGordon Tetlow
999c535eb59SGordon Tetlowdo_whatis() {
100024ef7420SBaptiste Daroussin	[ $(stat -f %i /usr/bin/man) -ne $(stat -f %i /usr/bin/whatis) ] && \
1001772246efSBaptiste Daroussin		exec whatis "$@"
1002c535eb59SGordon Tetlow	search_whatis whatis "$@"
1003c535eb59SGordon Tetlow}
1004c535eb59SGordon Tetlow
1005aeea395eSUlrich Spörlein# User's PATH setting decides on the groff-suite to pick up.
1006aeea395eSUlrich SpörleinEQN=eqn
1007a6a3e856SRuslan ErmilovNROFF='groff -S -P-h -Wall -mtty-char -man'
1008aeea395eSUlrich SpörleinPIC=pic
1009aeea395eSUlrich SpörleinREFER=refer
1010aeea395eSUlrich SpörleinTBL=tbl
10113d120968SUlrich SpörleinTROFF='groff -S -man'
1012aeea395eSUlrich SpörleinVGRIND=vgrind
1013aeea395eSUlrich Spörlein
1014deeff310SGordon TetlowLOCALE=/usr/bin/locale
1015a0094449SRuslan ErmilovSTTY=/bin/stty
101682db8a5eSGordon TetlowSYSCTL=/sbin/sysctl
1017c535eb59SGordon Tetlow
1018c535eb59SGordon Tetlowdebug=0
101973577bf0SRyan Moellerman_default_sections='1:8:2:3:3lua:n:4:5:6:7:9:l'
1020971c1c42STijl Coosemansman_default_path='/usr/share/man:/usr/share/openssl/man:/usr/local/share/man:/usr/local/man'
102157cd9717SGordon Tetlowcattool='/usr/bin/zcat -f'
1022c535eb59SGordon Tetlow
1023c535eb59SGordon Tetlowconfig_global='/etc/man.conf'
1024c535eb59SGordon Tetlow
1025c535eb59SGordon Tetlow# This can be overridden via a setting in /etc/man.conf.
1026c535eb59SGordon Tetlowconfig_local='/usr/local/etc/man.d/*.conf'
1027c535eb59SGordon Tetlow
1028c535eb59SGordon Tetlow# Set noglobbing for now. I don't want spurious globbing.
1029c535eb59SGordon Tetlowset -f
1030c535eb59SGordon Tetlow
1031c535eb59SGordon Tetlowcase "$0" in
1032c535eb59SGordon Tetlow*apropos)	do_apropos "$@" ;;
1033c535eb59SGordon Tetlow*manpath)	do_manpath "$@" ;;
1034c535eb59SGordon Tetlow*whatis)	do_whatis "$@" ;;
1035c535eb59SGordon Tetlow*)		do_man "$@" ;;
1036c535eb59SGordon Tetlowesac
1037