xref: /freebsd/usr.bin/man/man.sh (revision b2394e73fc1dc71c1fd3171d1c5d913b1e890f9e)
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
71*b2394e73SBaptiste Daroussin		case "$MANPATH" in
72*b2394e73SBaptiste Daroussin		*:) PREPEND_MANPATH=${MANPATH} ;;
73*b2394e73SBaptiste Daroussin		:*) APPEND_MANPATH=${MANPATH} ;;
74*b2394e73SBaptiste Daroussin		*::*)
75*b2394e73SBaptiste Daroussin			PREPEND_MANPATH=${MANPATH%%::*}
76*b2394e73SBaptiste Daroussin			APPEND_MANPATH=${MANPATH#*::}
77*b2394e73SBaptiste Daroussin			;;
78*b2394e73SBaptiste Daroussin		*) return ;;
79*b2394e73SBaptiste Daroussin		esac
80*b2394e73SBaptiste Daroussin	fi
81*b2394e73SBaptiste Daroussin
82*b2394e73SBaptiste Daroussin	if [ -n "$PREPEND_MANPATH" ]; then
83*b2394e73SBaptiste Daroussin		IFS=:
84*b2394e73SBaptiste Daroussin		for path in $PREPEND_MANPATH; do
85*b2394e73SBaptiste Daroussin			add_to_manpath "$path"
86*b2394e73SBaptiste Daroussin		done
87*b2394e73SBaptiste Daroussin		unset IFS
88c535eb59SGordon Tetlow	fi
89c535eb59SGordon Tetlow
90c535eb59SGordon Tetlow	search_path
91c535eb59SGordon Tetlow
92c535eb59SGordon Tetlow	decho "Adding default manpath entries"
93c535eb59SGordon Tetlow	IFS=:
94c535eb59SGordon Tetlow	for path in $man_default_path; do
95c535eb59SGordon Tetlow		add_to_manpath "$path"
96c535eb59SGordon Tetlow	done
97c535eb59SGordon Tetlow	unset IFS
98c535eb59SGordon Tetlow
99c535eb59SGordon Tetlow	parse_configs
100c535eb59SGordon Tetlow
101*b2394e73SBaptiste Daroussin	if [ -n "$APPEND_MANPATH" ]; then
102*b2394e73SBaptiste Daroussin		IFS=:
103*b2394e73SBaptiste Daroussin		for path in $APPEND_MANPATH; do
104*b2394e73SBaptiste Daroussin			add_to_manpath "$path"
105*b2394e73SBaptiste Daroussin		done
106*b2394e73SBaptiste Daroussin		unset IFS
107*b2394e73SBaptiste Daroussin	fi
108c535eb59SGordon Tetlow	# Trim leading colon
109c535eb59SGordon Tetlow	MANPATH=${manpath#:}
110c535eb59SGordon Tetlow
111c535eb59SGordon Tetlow	decho "Using manual path: $MANPATH"
112c535eb59SGordon Tetlow}
113c535eb59SGordon Tetlow
114c535eb59SGordon Tetlow# Usage: check_cat catglob
115c535eb59SGordon Tetlow# Checks to see if a cat glob is available.
116c535eb59SGordon Tetlowcheck_cat() {
117c535eb59SGordon Tetlow	if exists "$1"; then
118c535eb59SGordon Tetlow		use_cat=yes
119c535eb59SGordon Tetlow		catpage=$found
12057cd9717SGordon Tetlow		setup_cattool $catpage
121c535eb59SGordon Tetlow		decho "    Found catpage $catpage"
122c535eb59SGordon Tetlow		return 0
123c535eb59SGordon Tetlow	else
124c535eb59SGordon Tetlow		return 1
125c535eb59SGordon Tetlow	fi
126c535eb59SGordon Tetlow}
127c535eb59SGordon Tetlow
128c535eb59SGordon Tetlow# Usage: check_man manglob catglob
129c535eb59SGordon Tetlow# Given 2 globs, figures out if the manglob is available, if so, check to
130c535eb59SGordon Tetlow# see if the catglob is also available and up to date.
131c535eb59SGordon Tetlowcheck_man() {
132c535eb59SGordon Tetlow	if exists "$1"; then
133c535eb59SGordon Tetlow		# We have a match, check for a cat page
134c535eb59SGordon Tetlow		manpage=$found
13557cd9717SGordon Tetlow		setup_cattool $manpage
136c535eb59SGordon Tetlow		decho "    Found manpage $manpage"
137c535eb59SGordon Tetlow
138a0094449SRuslan Ermilov		if [ -n "${use_width}" ]; then
139a0094449SRuslan Ermilov			# non-standard width
140a0094449SRuslan Ermilov			unset use_cat
141a0094449SRuslan Ermilov			decho "    Skipping catpage: non-standard page width"
142a0094449SRuslan Ermilov		elif exists "$2" && is_newer $found $manpage; then
143c535eb59SGordon Tetlow			# cat page found and is newer, use that
144c535eb59SGordon Tetlow			use_cat=yes
145c535eb59SGordon Tetlow			catpage=$found
14657cd9717SGordon Tetlow			setup_cattool $catpage
147c535eb59SGordon Tetlow			decho "    Using catpage $catpage"
148c535eb59SGordon Tetlow		else
149c535eb59SGordon Tetlow			# no cat page or is older
150c535eb59SGordon Tetlow			unset use_cat
151c535eb59SGordon Tetlow			decho "    Skipping catpage: not found or old"
152c535eb59SGordon Tetlow		fi
153c535eb59SGordon Tetlow		return 0
154c535eb59SGordon Tetlow	fi
155c535eb59SGordon Tetlow
156c535eb59SGordon Tetlow	return 1
157c535eb59SGordon Tetlow}
158c535eb59SGordon Tetlow
159c535eb59SGordon Tetlow# Usage: decho "string" [debuglevel]
160c535eb59SGordon Tetlow# Echoes to stderr string prefaced with -- if high enough debuglevel.
161c535eb59SGordon Tetlowdecho() {
162c535eb59SGordon Tetlow	if [ $debug -ge ${2:-1} ]; then
163c535eb59SGordon Tetlow		echo "-- $1" >&2
164c535eb59SGordon Tetlow	fi
165c535eb59SGordon Tetlow}
166c535eb59SGordon Tetlow
167c535eb59SGordon Tetlow# Usage: exists glob
168c535eb59SGordon Tetlow# Returns true if glob resolves to a real file.
169c535eb59SGordon Tetlowexists() {
170c535eb59SGordon Tetlow	local IFS
171c535eb59SGordon Tetlow
172c535eb59SGordon Tetlow	# Don't accidentally inherit callers IFS (breaks perl manpages)
173c535eb59SGordon Tetlow	unset IFS
174c535eb59SGordon Tetlow
175c535eb59SGordon Tetlow	# Use some globbing tricks in the shell to determine if a file
176c535eb59SGordon Tetlow	# exists or not.
177c535eb59SGordon Tetlow	set +f
178c535eb59SGordon Tetlow	set -- "$1" $1
179c535eb59SGordon Tetlow	set -f
180c535eb59SGordon Tetlow
181c535eb59SGordon Tetlow	if [ "$1" != "$2" -a -r "$2" ]; then
182c535eb59SGordon Tetlow		found="$2"
183c535eb59SGordon Tetlow		return 0
184c535eb59SGordon Tetlow	fi
185c535eb59SGordon Tetlow
186c535eb59SGordon Tetlow	return 1
187c535eb59SGordon Tetlow}
188c535eb59SGordon Tetlow
189c535eb59SGordon Tetlow# Usage: find_file path section subdir pagename
190c535eb59SGordon Tetlow# Returns: true if something is matched and found.
191c535eb59SGordon Tetlow# Search the given path/section combo for a given page.
192c535eb59SGordon Tetlowfind_file() {
193c535eb59SGordon Tetlow	local manroot catroot mann man0 catn cat0
194c535eb59SGordon Tetlow
195c535eb59SGordon Tetlow	manroot="$1/man$2"
196c535eb59SGordon Tetlow	catroot="$1/cat$2"
197c535eb59SGordon Tetlow	if [ -n "$3" ]; then
198c535eb59SGordon Tetlow		manroot="$manroot/$3"
199c535eb59SGordon Tetlow		catroot="$catroot/$3"
200c535eb59SGordon Tetlow	fi
201c535eb59SGordon Tetlow
202c535eb59SGordon Tetlow	if [ ! -d "$manroot" ]; then
203c535eb59SGordon Tetlow		return 1
204c535eb59SGordon Tetlow	fi
205c535eb59SGordon Tetlow	decho "  Searching directory $manroot" 2
206c535eb59SGordon Tetlow
207c535eb59SGordon Tetlow	mann="$manroot/$4.$2*"
208c535eb59SGordon Tetlow	man0="$manroot/$4.0*"
209c535eb59SGordon Tetlow	catn="$catroot/$4.$2*"
210c535eb59SGordon Tetlow	cat0="$catroot/$4.0*"
211c535eb59SGordon Tetlow
212c535eb59SGordon Tetlow	# This is the behavior as seen by the original man utility.
213c535eb59SGordon Tetlow	# Let's not change that which doesn't seem broken.
214c535eb59SGordon Tetlow	if check_man "$mann" "$catn"; then
215c535eb59SGordon Tetlow		return 0
216c535eb59SGordon Tetlow	elif check_man "$man0" "$cat0"; then
217c535eb59SGordon Tetlow		return 0
218c535eb59SGordon Tetlow	elif check_cat "$catn"; then
219c535eb59SGordon Tetlow		return 0
220c535eb59SGordon Tetlow	elif check_cat "$cat0"; then
221c535eb59SGordon Tetlow		return 0
222c535eb59SGordon Tetlow	fi
223c535eb59SGordon Tetlow
224c535eb59SGordon Tetlow	return 1
225c535eb59SGordon Tetlow}
226c535eb59SGordon Tetlow
227c535eb59SGordon Tetlow# Usage: is_newer file1 file2
228c535eb59SGordon Tetlow# Returns true if file1 is newer than file2 as calculated by mtime.
229c535eb59SGordon Tetlowis_newer() {
2309b61837aSUlrich Spörlein	if ! [ "$1" -ot "$2" ]; then
2319b61837aSUlrich Spörlein		decho "    mtime: $1 not older than $2" 3
232c535eb59SGordon Tetlow		return 0
233c535eb59SGordon Tetlow	else
234c535eb59SGordon Tetlow		decho "    mtime: $1 older than $2" 3
235c535eb59SGordon Tetlow		return 1
236c535eb59SGordon Tetlow	fi
237c535eb59SGordon Tetlow}
238c535eb59SGordon Tetlow
239c535eb59SGordon Tetlow# Usage: manpath_parse_args "$@"
240c535eb59SGordon Tetlow# Parses commandline options for manpath.
241c535eb59SGordon Tetlowmanpath_parse_args() {
242c535eb59SGordon Tetlow	local cmd_arg
243c535eb59SGordon Tetlow
244c535eb59SGordon Tetlow	while getopts 'Ldq' cmd_arg; do
245c535eb59SGordon Tetlow		case "${cmd_arg}" in
246c535eb59SGordon Tetlow		L)	Lflag=Lflag ;;
247c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
248c535eb59SGordon Tetlow		q)	qflag=qflag ;;
249c535eb59SGordon Tetlow		*)	manpath_usage ;;
250c535eb59SGordon Tetlow		esac
251c535eb59SGordon Tetlow	done >&2
252c535eb59SGordon Tetlow}
253c535eb59SGordon Tetlow
254c535eb59SGordon Tetlow# Usage: manpath_usage
255c535eb59SGordon Tetlow# Display usage for the manpath(1) utility.
256c535eb59SGordon Tetlowmanpath_usage() {
257c535eb59SGordon Tetlow	echo 'usage: manpath [-Ldq]' >&2
258c535eb59SGordon Tetlow	exit 1
259c535eb59SGordon Tetlow}
260c535eb59SGordon Tetlow
261c535eb59SGordon Tetlow# Usage: manpath_warnings
262c535eb59SGordon Tetlow# Display some warnings to stderr.
263c535eb59SGordon Tetlowmanpath_warnings() {
264c535eb59SGordon Tetlow	if [ -z "$Lflag" -a -n "$MANPATH" ]; then
265c535eb59SGordon Tetlow		echo "(Warning: MANPATH environment variable set)" >&2
266c535eb59SGordon Tetlow	fi
267c535eb59SGordon Tetlow
268c535eb59SGordon Tetlow	if [ -n "$Lflag" -a -n "$MANLOCALES" ]; then
269c535eb59SGordon Tetlow		echo "(Warning: MANLOCALES environment variable set)" >&2
270c535eb59SGordon Tetlow	fi
271c535eb59SGordon Tetlow}
272c535eb59SGordon Tetlow
27357cd9717SGordon Tetlow# Usage: man_check_for_so page path
27457cd9717SGordon Tetlow# Returns: True if able to resolve the file, false if it ended in tears.
27557cd9717SGordon Tetlow# Detects the presence of the .so directive and causes the file to be
27657cd9717SGordon Tetlow# redirected to another source file.
27757cd9717SGordon Tetlowman_check_for_so() {
27857cd9717SGordon Tetlow	local IFS line tstr
27957cd9717SGordon Tetlow
28057cd9717SGordon Tetlow	unset IFS
28157cd9717SGordon Tetlow
28257cd9717SGordon Tetlow	# We need to loop to accommodate multiple .so directives.
28357cd9717SGordon Tetlow	while true
28457cd9717SGordon Tetlow	do
28557cd9717SGordon Tetlow		line=$($cattool $manpage | head -1)
28657cd9717SGordon Tetlow		case "$line" in
28757cd9717SGordon Tetlow		.so*)	trim "${line#.so}"
28857cd9717SGordon Tetlow			decho "$manpage includes $tstr"
28957cd9717SGordon Tetlow			# Glob and check for the file.
29057cd9717SGordon Tetlow			if ! check_man "$path/$tstr*" ""; then
29157cd9717SGordon Tetlow				decho "  Unable to find $tstr"
29257cd9717SGordon Tetlow				return 1
29357cd9717SGordon Tetlow			fi
29457cd9717SGordon Tetlow			;;
29557cd9717SGordon Tetlow		*)	break ;;
29657cd9717SGordon Tetlow		esac
29757cd9717SGordon Tetlow	done
29857cd9717SGordon Tetlow
29957cd9717SGordon Tetlow	return 0
30057cd9717SGordon Tetlow}
30157cd9717SGordon Tetlow
302b43edc06SBaptiste Daroussin# Usage: man_display_page
303b43edc06SBaptiste Daroussin# Display either the manpage or catpage depending on the use_cat variable
304c535eb59SGordon Tetlowman_display_page() {
3051fb816daSBaptiste Daroussin	local IFS pipeline testline
306c535eb59SGordon Tetlow
307c535eb59SGordon Tetlow	# We are called with IFS set to colon. This causes really weird
308c535eb59SGordon Tetlow	# things to happen for the variables that have spaces in them.
309c535eb59SGordon Tetlow	unset IFS
310c535eb59SGordon Tetlow
311c535eb59SGordon Tetlow	# If we are supposed to use a catpage and we aren't using troff(1)
312c535eb59SGordon Tetlow	# just zcat the catpage and we are done.
313c535eb59SGordon Tetlow	if [ -z "$tflag" -a -n "$use_cat" ]; then
314c535eb59SGordon Tetlow		if [ -n "$wflag" ]; then
315c535eb59SGordon Tetlow			echo "$catpage (source: $manpage)"
316c535eb59SGordon Tetlow			ret=0
317c535eb59SGordon Tetlow		else
318c535eb59SGordon Tetlow			if [ $debug -gt 0 ]; then
319a6a3e856SRuslan Ermilov				decho "Command: $cattool $catpage | $MANPAGER"
320c535eb59SGordon Tetlow				ret=0
321c535eb59SGordon Tetlow			else
322a6a3e856SRuslan Ermilov				eval "$cattool $catpage | $MANPAGER"
323c535eb59SGordon Tetlow				ret=$?
324c535eb59SGordon Tetlow			fi
325c535eb59SGordon Tetlow		fi
326c535eb59SGordon Tetlow		return
327c535eb59SGordon Tetlow	fi
328c535eb59SGordon Tetlow
329c535eb59SGordon Tetlow	# Okay, we are using the manpage, do we just need to output the
330c535eb59SGordon Tetlow	# name of the manpage?
331c535eb59SGordon Tetlow	if [ -n "$wflag" ]; then
332c535eb59SGordon Tetlow		echo "$manpage"
333c535eb59SGordon Tetlow		ret=0
334c535eb59SGordon Tetlow		return
335c535eb59SGordon Tetlow	fi
336c535eb59SGordon Tetlow
337d433cf9aSBaptiste Daroussin	if [ -n "$use_width" ]; then
338d433cf9aSBaptiste Daroussin		mandoc_args="-O width=${use_width}"
339d433cf9aSBaptiste Daroussin	fi
340849684b0SBaptiste Daroussin	testline="mandoc -Tlint -Wunsupp 2>/dev/null"
341449a792dSBaptiste Daroussin	if [ -n "$tflag" ]; then
342449a792dSBaptiste Daroussin		pipeline="mandoc -Tps $mandoc_args"
343449a792dSBaptiste Daroussin	else
344d433cf9aSBaptiste Daroussin		pipeline="mandoc $mandoc_args | $MANPAGER"
345449a792dSBaptiste Daroussin	fi
346d6096801SBaptiste Daroussin
347d6096801SBaptiste Daroussin	if ! eval "$cattool $manpage | $testline" ;then
348f17575acSBaptiste Daroussin		if which -s groff; then
349d6096801SBaptiste Daroussin			man_display_page_groff
350d6096801SBaptiste Daroussin		else
351d6096801SBaptiste Daroussin			echo "This manpage needs groff(1) to be rendered" >&2
352d6096801SBaptiste Daroussin			echo "First install groff(1): " >&2
353d6096801SBaptiste Daroussin			echo "pkg install groff " >&2
354d6096801SBaptiste Daroussin			ret=1
355d6096801SBaptiste Daroussin		fi
356d6096801SBaptiste Daroussin		return
357d6096801SBaptiste Daroussin	fi
358d6096801SBaptiste Daroussin
359d6096801SBaptiste Daroussin	if [ $debug -gt 0 ]; then
360d6096801SBaptiste Daroussin		decho "Command: $cattool $manpage | $pipeline"
361d6096801SBaptiste Daroussin		ret=0
362d6096801SBaptiste Daroussin	else
363d6096801SBaptiste Daroussin		eval "$cattool $manpage | $pipeline"
364d6096801SBaptiste Daroussin		ret=$?
365d6096801SBaptiste Daroussin	fi
366d6096801SBaptiste Daroussin}
367d6096801SBaptiste Daroussin
368b43edc06SBaptiste Daroussin# Usage: man_display_page_groff
369b43edc06SBaptiste Daroussin# Display the manpage using groff
370d6096801SBaptiste Daroussinman_display_page_groff() {
371d6096801SBaptiste Daroussin	local EQN NROFF PIC TBL TROFF REFER VGRIND
372d6096801SBaptiste Daroussin	local IFS l nroff_dev pipeline preproc_arg tool
373d6096801SBaptiste Daroussin
374c535eb59SGordon Tetlow	# So, we really do need to parse the manpage. First, figure out the
375c535eb59SGordon Tetlow	# device flag (-T) we have to pass to eqn(1) and groff(1). Then,
376c535eb59SGordon Tetlow	# setup the pipeline of commands based on the user's request.
377c535eb59SGordon Tetlow
378deeff310SGordon Tetlow	# If the manpage is from a particular charset, we need to setup nroff
379deeff310SGordon Tetlow	# to properly output for the correct device.
380deeff310SGordon Tetlow	case "${manpage}" in
381deeff310SGordon Tetlow	*.${man_charset}/*)
382c535eb59SGordon Tetlow		# I don't pretend to know this; I'm just copying from the
383c535eb59SGordon Tetlow		# previous version of man(1).
384c535eb59SGordon Tetlow		case "$man_charset" in
385c535eb59SGordon Tetlow		KOI8-R)		nroff_dev="koi8-r" ;;
386c535eb59SGordon Tetlow		ISO8859-1)	nroff_dev="latin1" ;;
387c535eb59SGordon Tetlow		ISO8859-15)	nroff_dev="latin1" ;;
388c535eb59SGordon Tetlow		UTF-8)		nroff_dev="utf8" ;;
389c535eb59SGordon Tetlow		*)		nroff_dev="ascii" ;;
390c535eb59SGordon Tetlow		esac
391c535eb59SGordon Tetlow
392deeff310SGordon Tetlow		NROFF="$NROFF -T$nroff_dev"
393c535eb59SGordon Tetlow		EQN="$EQN -T$nroff_dev"
394c535eb59SGordon Tetlow
395deeff310SGordon Tetlow		# Iff the manpage is from the locale and not just the charset,
396deeff310SGordon Tetlow		# then we need to define the locale string.
397deeff310SGordon Tetlow		case "${manpage}" in
398deeff310SGordon Tetlow		*/${man_lang}_${man_country}.${man_charset}/*)
399deeff310SGordon Tetlow			NROFF="$NROFF -dlocale=$man_lang.$man_charset"
400deeff310SGordon Tetlow			;;
401deeff310SGordon Tetlow		*/${man_lang}.${man_charset}/*)
402deeff310SGordon Tetlow			NROFF="$NROFF -dlocale=$man_lang.$man_charset"
403deeff310SGordon Tetlow			;;
404deeff310SGordon Tetlow		esac
405deeff310SGordon Tetlow
406c535eb59SGordon Tetlow		# Allow language specific calls to override the default
407c535eb59SGordon Tetlow		# set of utilities.
408c535eb59SGordon Tetlow		l=$(echo $man_lang | tr [:lower:] [:upper:])
409b70e2025SRuslan Ermilov		for tool in EQN NROFF PIC TBL TROFF REFER VGRIND; do
410c535eb59SGordon Tetlow			eval "$tool=\${${tool}_$l:-\$$tool}"
411c535eb59SGordon Tetlow		done
412c535eb59SGordon Tetlow		;;
413c535eb59SGordon Tetlow	*)	NROFF="$NROFF -Tascii"
414c535eb59SGordon Tetlow		EQN="$EQN -Tascii"
415c535eb59SGordon Tetlow		;;
416c535eb59SGordon Tetlow	esac
417c535eb59SGordon Tetlow
418a6a3e856SRuslan Ermilov	if [ -z "$MANCOLOR" ]; then
419a6a3e856SRuslan Ermilov		NROFF="$NROFF -P-c"
420a6a3e856SRuslan Ermilov	fi
421a6a3e856SRuslan Ermilov
422a0094449SRuslan Ermilov	if [ -n "${use_width}" ]; then
423a0094449SRuslan Ermilov		NROFF="$NROFF -rLL=${use_width}n -rLT=${use_width}n"
424a0094449SRuslan Ermilov	fi
425a0094449SRuslan Ermilov
426c535eb59SGordon Tetlow	if [ -n "$MANROFFSEQ" ]; then
427c535eb59SGordon Tetlow		set -- -$MANROFFSEQ
428c535eb59SGordon Tetlow		while getopts 'egprtv' preproc_arg; do
429c535eb59SGordon Tetlow			case "${preproc_arg}" in
430c535eb59SGordon Tetlow			e)	pipeline="$pipeline | $EQN" ;;
431487ac9acSUlrich Spörlein			g)	;; # Ignore for compatibility.
432c535eb59SGordon Tetlow			p)	pipeline="$pipeline | $PIC" ;;
433c535eb59SGordon Tetlow			r)	pipeline="$pipeline | $REFER" ;;
434b70e2025SRuslan Ermilov			t)	pipeline="$pipeline | $TBL" ;;
435c535eb59SGordon Tetlow			v)	pipeline="$pipeline | $VGRIND" ;;
436c535eb59SGordon Tetlow			*)	usage ;;
437c535eb59SGordon Tetlow			esac
438c535eb59SGordon Tetlow		done
439c535eb59SGordon Tetlow		# Strip the leading " | " from the resulting pipeline.
440c535eb59SGordon Tetlow		pipeline="${pipeline#" | "}"
441c535eb59SGordon Tetlow	else
442c535eb59SGordon Tetlow		pipeline="$TBL"
443c535eb59SGordon Tetlow	fi
444c535eb59SGordon Tetlow
445c535eb59SGordon Tetlow	if [ -n "$tflag" ]; then
446c535eb59SGordon Tetlow		pipeline="$pipeline | $TROFF"
447c535eb59SGordon Tetlow	else
448a6a3e856SRuslan Ermilov		pipeline="$pipeline | $NROFF | $MANPAGER"
449c535eb59SGordon Tetlow	fi
450c535eb59SGordon Tetlow
451c535eb59SGordon Tetlow	if [ $debug -gt 0 ]; then
45257cd9717SGordon Tetlow		decho "Command: $cattool $manpage | $pipeline"
453c535eb59SGordon Tetlow		ret=0
454c535eb59SGordon Tetlow	else
45557cd9717SGordon Tetlow		eval "$cattool $manpage | $pipeline"
456c535eb59SGordon Tetlow		ret=$?
457c535eb59SGordon Tetlow	fi
458c535eb59SGordon Tetlow}
459c535eb59SGordon Tetlow
460c535eb59SGordon Tetlow# Usage: man_find_and_display page
461c535eb59SGordon Tetlow# Search through the manpaths looking for the given page.
462c535eb59SGordon Tetlowman_find_and_display() {
463c535eb59SGordon Tetlow	local found_page locpath p path sect
464c535eb59SGordon Tetlow
4653d9127f1SGordon Tetlow	# Check to see if it's a file. But only if it has a '/' in
4663d9127f1SGordon Tetlow	# the filename.
4673d9127f1SGordon Tetlow	case "$1" in
4683d9127f1SGordon Tetlow	*/*)	if [ -f "$1" -a -r "$1" ]; then
4693d9127f1SGordon Tetlow			decho "Found a usable page, displaying that"
4703d9127f1SGordon Tetlow			unset use_cat
4713d9127f1SGordon Tetlow			manpage="$1"
47257cd9717SGordon Tetlow			setup_cattool $manpage
47357cd9717SGordon Tetlow			if man_check_for_so $manpage $(dirname $manpage); then
47457cd9717SGordon Tetlow				found_page=yes
4753d9127f1SGordon Tetlow				man_display_page
47657cd9717SGordon Tetlow			fi
4773d9127f1SGordon Tetlow			return
4783d9127f1SGordon Tetlow		fi
4793d9127f1SGordon Tetlow		;;
4803d9127f1SGordon Tetlow	esac
4813d9127f1SGordon Tetlow
482c535eb59SGordon Tetlow	IFS=:
483c535eb59SGordon Tetlow	for sect in $MANSECT; do
484c535eb59SGordon Tetlow		decho "Searching section $sect" 2
485c535eb59SGordon Tetlow		for path in $MANPATH; do
486c535eb59SGordon Tetlow			for locpath in $locpaths; do
487c535eb59SGordon Tetlow				p=$path/$locpath
488c535eb59SGordon Tetlow				p=${p%/.} # Rid ourselves of the trailing /.
489c535eb59SGordon Tetlow
490c535eb59SGordon Tetlow				# Check if there is a MACHINE specific manpath.
491c535eb59SGordon Tetlow				if find_file $p $sect $MACHINE "$1"; then
49257cd9717SGordon Tetlow					if man_check_for_so $manpage $p; then
493c535eb59SGordon Tetlow						found_page=yes
494c535eb59SGordon Tetlow						man_display_page
4951d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
4961d7c660aSGordon Tetlow							continue 2
4971d7c660aSGordon Tetlow						else
498c535eb59SGordon Tetlow							return
499c535eb59SGordon Tetlow						fi
500c535eb59SGordon Tetlow					fi
50157cd9717SGordon Tetlow				fi
502c535eb59SGordon Tetlow
503c535eb59SGordon Tetlow				# Check if there is a MACHINE_ARCH
504c535eb59SGordon Tetlow				# specific manpath.
505c535eb59SGordon Tetlow				if find_file $p $sect $MACHINE_ARCH "$1"; then
50657cd9717SGordon Tetlow					if man_check_for_so $manpage $p; then
507c535eb59SGordon Tetlow						found_page=yes
508c535eb59SGordon Tetlow						man_display_page
5091d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
5101d7c660aSGordon Tetlow							continue 2
5111d7c660aSGordon Tetlow						else
512c535eb59SGordon Tetlow							return
513c535eb59SGordon Tetlow						fi
514c535eb59SGordon Tetlow					fi
51557cd9717SGordon Tetlow				fi
516c535eb59SGordon Tetlow
517c535eb59SGordon Tetlow				# Check plain old manpath.
518c535eb59SGordon Tetlow				if find_file $p $sect '' "$1"; then
51957cd9717SGordon Tetlow					if man_check_for_so $manpage $p; then
520c535eb59SGordon Tetlow						found_page=yes
521c535eb59SGordon Tetlow						man_display_page
5221d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
5231d7c660aSGordon Tetlow							continue 2
5241d7c660aSGordon Tetlow						else
525c535eb59SGordon Tetlow							return
526c535eb59SGordon Tetlow						fi
527c535eb59SGordon Tetlow					fi
52857cd9717SGordon Tetlow				fi
529c535eb59SGordon Tetlow			done
530c535eb59SGordon Tetlow		done
531c535eb59SGordon Tetlow	done
532c535eb59SGordon Tetlow	unset IFS
533c535eb59SGordon Tetlow
534c535eb59SGordon Tetlow	# Nothing? Well, we are done then.
535c535eb59SGordon Tetlow	if [ -z "$found_page" ]; then
536c535eb59SGordon Tetlow		echo "No manual entry for $1" >&2
537c535eb59SGordon Tetlow		ret=1
538c535eb59SGordon Tetlow		return
539c535eb59SGordon Tetlow	fi
540c535eb59SGordon Tetlow}
541c535eb59SGordon Tetlow
542c535eb59SGordon Tetlow# Usage: man_parse_args "$@"
543c535eb59SGordon Tetlow# Parses commandline options for man.
544c535eb59SGordon Tetlowman_parse_args() {
545c535eb59SGordon Tetlow	local IFS cmd_arg
546c535eb59SGordon Tetlow
547c535eb59SGordon Tetlow	while getopts 'M:P:S:adfhkm:op:tw' cmd_arg; do
548c535eb59SGordon Tetlow		case "${cmd_arg}" in
549c535eb59SGordon Tetlow		M)	MANPATH=$OPTARG ;;
550a6a3e856SRuslan Ermilov		P)	MANPAGER=$OPTARG ;;
551c535eb59SGordon Tetlow		S)	MANSECT=$OPTARG ;;
552c535eb59SGordon Tetlow		a)	aflag=aflag ;;
553c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
554c535eb59SGordon Tetlow		f)	fflag=fflag ;;
555c535eb59SGordon Tetlow		h)	man_usage 0 ;;
556c535eb59SGordon Tetlow		k)	kflag=kflag ;;
557c535eb59SGordon Tetlow		m)	mflag=$OPTARG ;;
558c535eb59SGordon Tetlow		o)	oflag=oflag ;;
559c535eb59SGordon Tetlow		p)	MANROFFSEQ=$OPTARG ;;
560c535eb59SGordon Tetlow		t)	tflag=tflag ;;
561c535eb59SGordon Tetlow		w)	wflag=wflag ;;
562c535eb59SGordon Tetlow		*)	man_usage ;;
563c535eb59SGordon Tetlow		esac
564c535eb59SGordon Tetlow	done >&2
565c535eb59SGordon Tetlow
566c535eb59SGordon Tetlow	shift $(( $OPTIND - 1 ))
567c535eb59SGordon Tetlow
568c535eb59SGordon Tetlow	# Check the args for incompatible options.
569c535eb59SGordon Tetlow	case "${fflag}${kflag}${tflag}${wflag}" in
570c535eb59SGordon Tetlow	fflagkflag*)	echo "Incompatible options: -f and -k"; man_usage ;;
571c535eb59SGordon Tetlow	fflag*tflag*)	echo "Incompatible options: -f and -t"; man_usage ;;
572c535eb59SGordon Tetlow	fflag*wflag)	echo "Incompatible options: -f and -w"; man_usage ;;
573c535eb59SGordon Tetlow	*kflagtflag*)	echo "Incompatible options: -k and -t"; man_usage ;;
574c535eb59SGordon Tetlow	*kflag*wflag)	echo "Incompatible options: -k and -w"; man_usage ;;
575c535eb59SGordon Tetlow	*tflagwflag)	echo "Incompatible options: -t and -w"; man_usage ;;
576c535eb59SGordon Tetlow	esac
577c535eb59SGordon Tetlow
578c535eb59SGordon Tetlow	# Short circuit for whatis(1) and apropos(1)
579c535eb59SGordon Tetlow	if [ -n "$fflag" ]; then
580c535eb59SGordon Tetlow		do_whatis "$@"
581c535eb59SGordon Tetlow		exit
582c535eb59SGordon Tetlow	fi
583c535eb59SGordon Tetlow
584c535eb59SGordon Tetlow	if [ -n "$kflag" ]; then
585c535eb59SGordon Tetlow		do_apropos "$@"
586c535eb59SGordon Tetlow		exit
587c535eb59SGordon Tetlow	fi
588c535eb59SGordon Tetlow
589c535eb59SGordon Tetlow	IFS=:
590c535eb59SGordon Tetlow	for sect in $man_default_sections; do
591c535eb59SGordon Tetlow		if [ "$sect" = "$1" ]; then
592c535eb59SGordon Tetlow			decho "Detected manual section as first arg: $1"
593c535eb59SGordon Tetlow			MANSECT="$1"
594c535eb59SGordon Tetlow			shift
595c535eb59SGordon Tetlow			break
596c535eb59SGordon Tetlow		fi
597c535eb59SGordon Tetlow	done
598c535eb59SGordon Tetlow	unset IFS
599c535eb59SGordon Tetlow
600c535eb59SGordon Tetlow	pages="$*"
601c535eb59SGordon Tetlow}
602c535eb59SGordon Tetlow
603c535eb59SGordon Tetlow# Usage: man_setup
604c535eb59SGordon Tetlow# Setup various trivial but essential variables.
605c535eb59SGordon Tetlowman_setup() {
606c535eb59SGordon Tetlow	# Setup machine and architecture variables.
607c535eb59SGordon Tetlow	if [ -n "$mflag" ]; then
608c535eb59SGordon Tetlow		MACHINE_ARCH=${mflag%%:*}
609c535eb59SGordon Tetlow		MACHINE=${mflag##*:}
610c535eb59SGordon Tetlow	fi
611c535eb59SGordon Tetlow	if [ -z "$MACHINE_ARCH" ]; then
61282db8a5eSGordon Tetlow		MACHINE_ARCH=$($SYSCTL -n hw.machine_arch)
613c535eb59SGordon Tetlow	fi
614c535eb59SGordon Tetlow	if [ -z "$MACHINE" ]; then
61582db8a5eSGordon Tetlow		MACHINE=$($SYSCTL -n hw.machine)
616c535eb59SGordon Tetlow	fi
617c535eb59SGordon Tetlow	decho "Using architecture: $MACHINE_ARCH:$MACHINE"
618c535eb59SGordon Tetlow
619c535eb59SGordon Tetlow	setup_pager
620c535eb59SGordon Tetlow
621c535eb59SGordon Tetlow	# Setup manual sections to search.
622c535eb59SGordon Tetlow	if [ -z "$MANSECT" ]; then
623c535eb59SGordon Tetlow		MANSECT=$man_default_sections
624c535eb59SGordon Tetlow	fi
625c535eb59SGordon Tetlow	decho "Using manual sections: $MANSECT"
626c535eb59SGordon Tetlow
627c535eb59SGordon Tetlow	build_manpath
628c535eb59SGordon Tetlow	man_setup_locale
629a0094449SRuslan Ermilov	man_setup_width
630a0094449SRuslan Ermilov}
631a0094449SRuslan Ermilov
632a0094449SRuslan Ermilov# Usage: man_setup_width
633a0094449SRuslan Ermilov# Set up page width.
634a0094449SRuslan Ermilovman_setup_width() {
635a0094449SRuslan Ermilov	local sizes
636a0094449SRuslan Ermilov
637a0094449SRuslan Ermilov	unset use_width
638a0094449SRuslan Ermilov	case "$MANWIDTH" in
639a0094449SRuslan Ermilov	[0-9]*)
640a0094449SRuslan Ermilov		if [ "$MANWIDTH" -gt 0 2>/dev/null ]; then
641a0094449SRuslan Ermilov			use_width=$MANWIDTH
642a0094449SRuslan Ermilov		fi
643a0094449SRuslan Ermilov		;;
644a0094449SRuslan Ermilov	[Tt][Tt][Yy])
645a0094449SRuslan Ermilov		if { sizes=$($STTY size 0>&3 2>/dev/null); } 3>&1; then
646a0094449SRuslan Ermilov			set -- $sizes
647a0094449SRuslan Ermilov			if [ $2 -gt 80 ]; then
648a0094449SRuslan Ermilov				use_width=$(($2-2))
649a0094449SRuslan Ermilov			fi
650a0094449SRuslan Ermilov		fi
651a0094449SRuslan Ermilov		;;
652a0094449SRuslan Ermilov	esac
653a0094449SRuslan Ermilov	if [ -n "$use_width" ]; then
654a0094449SRuslan Ermilov		decho "Using non-standard page width: ${use_width}"
655a0094449SRuslan Ermilov	else
656a0094449SRuslan Ermilov		decho 'Using standard page width'
657a0094449SRuslan Ermilov	fi
658c535eb59SGordon Tetlow}
659c535eb59SGordon Tetlow
660c535eb59SGordon Tetlow# Usage: man_setup_locale
661c535eb59SGordon Tetlow# Setup necessary locale variables.
662c535eb59SGordon Tetlowman_setup_locale() {
663deeff310SGordon Tetlow	local lang_cc
664deeff310SGordon Tetlow
665deeff310SGordon Tetlow	locpaths='.'
666deeff310SGordon Tetlow	man_charset='US-ASCII'
667deeff310SGordon Tetlow
668c535eb59SGordon Tetlow	# Setup locale information.
669c535eb59SGordon Tetlow	if [ -n "$oflag" ]; then
670deeff310SGordon Tetlow		decho 'Using non-localized manpages'
671deeff310SGordon Tetlow	else
672deeff310SGordon Tetlow		# Use the locale tool to give us the proper LC_CTYPE
673deeff310SGordon Tetlow		eval $( $LOCALE )
674c535eb59SGordon Tetlow
675deeff310SGordon Tetlow		case "$LC_CTYPE" in
676deeff310SGordon Tetlow		C)		;;
677deeff310SGordon Tetlow		POSIX)		;;
678deeff310SGordon Tetlow		[a-z][a-z]_[A-Z][A-Z]\.*)
679deeff310SGordon Tetlow				lang_cc="${LC_CTYPE%.*}"
680deeff310SGordon Tetlow				man_lang="${LC_CTYPE%_*}"
681deeff310SGordon Tetlow				man_country="${lang_cc#*_}"
682deeff310SGordon Tetlow				man_charset="${LC_CTYPE#*.}"
683deeff310SGordon Tetlow				locpaths="$LC_CTYPE"
684c535eb59SGordon Tetlow				locpaths="$locpaths:$man_lang.$man_charset"
685c535eb59SGordon Tetlow				if [ "$man_lang" != "en" ]; then
686c535eb59SGordon Tetlow					locpaths="$locpaths:en.$man_charset"
687c535eb59SGordon Tetlow				fi
688c535eb59SGordon Tetlow				locpaths="$locpaths:."
689deeff310SGordon Tetlow				;;
690deeff310SGordon Tetlow		*)		echo 'Unknown locale, assuming C' >&2
691deeff310SGordon Tetlow				;;
692deeff310SGordon Tetlow		esac
693c535eb59SGordon Tetlow	fi
694deeff310SGordon Tetlow
695c535eb59SGordon Tetlow	decho "Using locale paths: $locpaths"
696c535eb59SGordon Tetlow}
697c535eb59SGordon Tetlow
698c535eb59SGordon Tetlow# Usage: man_usage [exitcode]
699c535eb59SGordon Tetlow# Display usage for the man utility.
700c535eb59SGordon Tetlowman_usage() {
701c535eb59SGordon Tetlow	echo 'Usage:'
702c535eb59SGordon Tetlow	echo ' man [-adho] [-t | -w] [-M manpath] [-P pager] [-S mansect]'
703c535eb59SGordon Tetlow	echo '     [-m arch[:machine]] [-p [eprtv]] [mansect] page [...]'
704c535eb59SGordon Tetlow	echo ' man -f page [...] -- Emulates whatis(1)'
705c535eb59SGordon Tetlow	echo ' man -k page [...] -- Emulates apropos(1)'
706c535eb59SGordon Tetlow
707c535eb59SGordon Tetlow	# When exit'ing with -h, it's not an error.
708c535eb59SGordon Tetlow	exit ${1:-1}
709c535eb59SGordon Tetlow}
710c535eb59SGordon Tetlow
711c535eb59SGordon Tetlow# Usage: parse_configs
712c535eb59SGordon Tetlow# Reads the end-user adjustable config files.
713c535eb59SGordon Tetlowparse_configs() {
714c535eb59SGordon Tetlow	local IFS file files
715c535eb59SGordon Tetlow
716c535eb59SGordon Tetlow	if [ -n "$parsed_configs" ]; then
717c535eb59SGordon Tetlow		return
718c535eb59SGordon Tetlow	fi
719c535eb59SGordon Tetlow
720c535eb59SGordon Tetlow	unset IFS
721c535eb59SGordon Tetlow
722c535eb59SGordon Tetlow	# Read the global config first in case the user wants
723c535eb59SGordon Tetlow	# to override config_local.
724c535eb59SGordon Tetlow	if [ -r "$config_global" ]; then
725c535eb59SGordon Tetlow		parse_file "$config_global"
726c535eb59SGordon Tetlow	fi
727c535eb59SGordon Tetlow
728c535eb59SGordon Tetlow	# Glob the list of files to parse.
729c535eb59SGordon Tetlow	set +f
730c535eb59SGordon Tetlow	files=$(echo $config_local)
731c535eb59SGordon Tetlow	set -f
732c535eb59SGordon Tetlow
733c535eb59SGordon Tetlow	for file in $files; do
734c535eb59SGordon Tetlow		if [ -r "$file" ]; then
735c535eb59SGordon Tetlow			parse_file "$file"
736c535eb59SGordon Tetlow		fi
737c535eb59SGordon Tetlow	done
738c535eb59SGordon Tetlow
739c535eb59SGordon Tetlow	parsed_configs='yes'
740c535eb59SGordon Tetlow}
741c535eb59SGordon Tetlow
742c535eb59SGordon Tetlow# Usage: parse_file file
743c535eb59SGordon Tetlow# Reads the specified config files.
744c535eb59SGordon Tetlowparse_file() {
745c535eb59SGordon Tetlow	local file line tstr var
746c535eb59SGordon Tetlow
747c535eb59SGordon Tetlow	file="$1"
748c535eb59SGordon Tetlow	decho "Parsing config file: $file"
749c535eb59SGordon Tetlow	while read line; do
750c535eb59SGordon Tetlow		decho "  $line" 2
751c535eb59SGordon Tetlow		case "$line" in
752c535eb59SGordon Tetlow		\#*)		decho "    Comment" 3
753c535eb59SGordon Tetlow				;;
754c535eb59SGordon Tetlow		MANPATH*)	decho "    MANPATH" 3
755c535eb59SGordon Tetlow				trim "${line#MANPATH}"
756c535eb59SGordon Tetlow				add_to_manpath "$tstr"
757c535eb59SGordon Tetlow				;;
758c535eb59SGordon Tetlow		MANLOCALE*)	decho "    MANLOCALE" 3
759c535eb59SGordon Tetlow				trim "${line#MANLOCALE}"
760c535eb59SGordon Tetlow				manlocales="$manlocales:$tstr"
761c535eb59SGordon Tetlow				;;
762c535eb59SGordon Tetlow		MANCONFIG*)	decho "    MANCONFIG" 3
763a1528c80SRuslan Ermilov				trim "${line#MANCONFIG}"
764c535eb59SGordon Tetlow				config_local="$tstr"
765c535eb59SGordon Tetlow				;;
766c535eb59SGordon Tetlow		# Set variables in the form of FOO_BAR
767c535eb59SGordon Tetlow		*_*[\ \	]*)	var="${line%%[\ \	]*}"
768c535eb59SGordon Tetlow				trim "${line#$var}"
769c535eb59SGordon Tetlow				eval "$var=\"$tstr\""
770c535eb59SGordon Tetlow				decho "    Parsed $var" 3
771c535eb59SGordon Tetlow				;;
772c535eb59SGordon Tetlow		esac
773c535eb59SGordon Tetlow	done < "$file"
774c535eb59SGordon Tetlow}
775c535eb59SGordon Tetlow
776c535eb59SGordon Tetlow# Usage: search_path
777c535eb59SGordon Tetlow# Traverse $PATH looking for manpaths.
778c535eb59SGordon Tetlowsearch_path() {
779c535eb59SGordon Tetlow	local IFS p path
780c535eb59SGordon Tetlow
781c535eb59SGordon Tetlow	decho "Searching PATH for man directories"
782c535eb59SGordon Tetlow
783c535eb59SGordon Tetlow	IFS=:
784c535eb59SGordon Tetlow	for path in $PATH; do
785c535eb59SGordon Tetlow		# Do a little special casing since the base manpages
786c535eb59SGordon Tetlow		# are in /usr/share/man instead of /usr/man or /man.
787c535eb59SGordon Tetlow		case "$path" in
788c535eb59SGordon Tetlow		/bin|/usr/bin)	add_to_manpath "/usr/share/man" ;;
789c535eb59SGordon Tetlow		*)	if add_to_manpath "$path/man"; then
790c535eb59SGordon Tetlow				:
791c535eb59SGordon Tetlow			elif add_to_manpath "$path/MAN"; then
792c535eb59SGordon Tetlow				:
793c535eb59SGordon Tetlow			else
794c535eb59SGordon Tetlow				case "$path" in
795c535eb59SGordon Tetlow				*/bin)	p="${path%/bin}/man"
796c535eb59SGordon Tetlow					add_to_manpath "$p"
79761d5f2d1SBaptiste Daroussin					p="${path%/bin}/share/man"
79861d5f2d1SBaptiste Daroussin					add_to_manpath "$p"
799c535eb59SGordon Tetlow					;;
800c535eb59SGordon Tetlow				*)	;;
801c535eb59SGordon Tetlow				esac
802c535eb59SGordon Tetlow			fi
803c535eb59SGordon Tetlow			;;
804c535eb59SGordon Tetlow		esac
805c535eb59SGordon Tetlow	done
806c535eb59SGordon Tetlow	unset IFS
807c535eb59SGordon Tetlow
808c535eb59SGordon Tetlow	if [ -z "$manpath" ]; then
809c535eb59SGordon Tetlow		decho '  Unable to find any manpaths, using default'
810c535eb59SGordon Tetlow		manpath=$man_default_path
811c535eb59SGordon Tetlow	fi
812c535eb59SGordon Tetlow}
813c535eb59SGordon Tetlow
814c535eb59SGordon Tetlow# Usage: search_whatis cmd [arglist]
815c535eb59SGordon Tetlow# Do the heavy lifting for apropos/whatis
816c535eb59SGordon Tetlowsearch_whatis() {
817c535eb59SGordon Tetlow	local IFS bad cmd f good key keywords loc opt out path rval wlist
818c535eb59SGordon Tetlow
819c535eb59SGordon Tetlow	cmd="$1"
820c535eb59SGordon Tetlow	shift
821c535eb59SGordon Tetlow
822c535eb59SGordon Tetlow	whatis_parse_args "$@"
823c535eb59SGordon Tetlow
824c535eb59SGordon Tetlow	build_manpath
825c535eb59SGordon Tetlow	build_manlocales
826c535eb59SGordon Tetlow	setup_pager
827c535eb59SGordon Tetlow
828c535eb59SGordon Tetlow	if [ "$cmd" = "whatis" ]; then
829c535eb59SGordon Tetlow		opt="-w"
830c535eb59SGordon Tetlow	fi
831c535eb59SGordon Tetlow
832c535eb59SGordon Tetlow	f='whatis'
833c535eb59SGordon Tetlow
834c535eb59SGordon Tetlow	IFS=:
835c535eb59SGordon Tetlow	for path in $MANPATH; do
836c535eb59SGordon Tetlow		if [ \! -d "$path" ]; then
837c535eb59SGordon Tetlow			decho "Skipping non-existent path: $path" 2
838c535eb59SGordon Tetlow			continue
839c535eb59SGordon Tetlow		fi
840c535eb59SGordon Tetlow
841c535eb59SGordon Tetlow		if [ -f "$path/$f" -a -r "$path/$f" ]; then
842c535eb59SGordon Tetlow			decho "Found whatis: $path/$f"
843c535eb59SGordon Tetlow			wlist="$wlist $path/$f"
844c535eb59SGordon Tetlow		fi
845c535eb59SGordon Tetlow
846c535eb59SGordon Tetlow		for loc in $MANLOCALES; do
847c535eb59SGordon Tetlow			if [ -f "$path/$loc/$f" -a -r "$path/$loc/$f" ]; then
848c535eb59SGordon Tetlow				decho "Found whatis: $path/$loc/$f"
849c535eb59SGordon Tetlow				wlist="$wlist $path/$loc/$f"
850c535eb59SGordon Tetlow			fi
851c535eb59SGordon Tetlow		done
852c535eb59SGordon Tetlow	done
853c535eb59SGordon Tetlow	unset IFS
854c535eb59SGordon Tetlow
855c535eb59SGordon Tetlow	if [ -z "$wlist" ]; then
856c535eb59SGordon Tetlow		echo "$cmd: no whatis databases in $MANPATH" >&2
857c535eb59SGordon Tetlow		exit 1
858c535eb59SGordon Tetlow	fi
859c535eb59SGordon Tetlow
860c535eb59SGordon Tetlow	rval=0
861c535eb59SGordon Tetlow	for key in $keywords; do
862c535eb59SGordon Tetlow		out=$(grep -Ehi $opt -- "$key" $wlist)
863c535eb59SGordon Tetlow		if [ -n "$out" ]; then
864c535eb59SGordon Tetlow			good="$good\\n$out"
865c535eb59SGordon Tetlow		else
866c535eb59SGordon Tetlow			bad="$bad\\n$key: nothing appropriate"
867c535eb59SGordon Tetlow			rval=1
868c535eb59SGordon Tetlow		fi
869c535eb59SGordon Tetlow	done
870c535eb59SGordon Tetlow
871c535eb59SGordon Tetlow	# Strip leading carriage return.
872c535eb59SGordon Tetlow	good=${good#\\n}
873c535eb59SGordon Tetlow	bad=${bad#\\n}
874c535eb59SGordon Tetlow
875c535eb59SGordon Tetlow	if [ -n "$good" ]; then
876a6a3e856SRuslan Ermilov		echo -e "$good" | $MANPAGER
877c535eb59SGordon Tetlow	fi
878c535eb59SGordon Tetlow
879c535eb59SGordon Tetlow	if [ -n "$bad" ]; then
88000e05e69SGordon Tetlow		echo -e "$bad" >&2
881c535eb59SGordon Tetlow	fi
882c535eb59SGordon Tetlow
883c535eb59SGordon Tetlow	exit $rval
884c535eb59SGordon Tetlow}
885c535eb59SGordon Tetlow
88657cd9717SGordon Tetlow# Usage: setup_cattool page
88757cd9717SGordon Tetlow# Finds an appropriate decompressor based on extension
88857cd9717SGordon Tetlowsetup_cattool() {
88957cd9717SGordon Tetlow	case "$1" in
89057cd9717SGordon Tetlow	*.bz)	cattool='/usr/bin/bzcat' ;;
89157cd9717SGordon Tetlow	*.bz2)	cattool='/usr/bin/bzcat' ;;
89257cd9717SGordon Tetlow	*.gz)	cattool='/usr/bin/zcat' ;;
89357cd9717SGordon Tetlow	*.lzma)	cattool='/usr/bin/lzcat' ;;
89457cd9717SGordon Tetlow	*.xz)	cattool='/usr/bin/xzcat' ;;
89557cd9717SGordon Tetlow	*)	cattool='/usr/bin/zcat -f' ;;
89657cd9717SGordon Tetlow	esac
89757cd9717SGordon Tetlow}
89857cd9717SGordon Tetlow
899c535eb59SGordon Tetlow# Usage: setup_pager
900a6a3e856SRuslan Ermilov# Correctly sets $MANPAGER
901c535eb59SGordon Tetlowsetup_pager() {
902c535eb59SGordon Tetlow	# Setup pager.
903a6a3e856SRuslan Ermilov	if [ -z "$MANPAGER" ]; then
904a6a3e856SRuslan Ermilov		if [ -n "$MANCOLOR" ]; then
905a6a3e856SRuslan Ermilov			MANPAGER="less -sR"
906a6a3e856SRuslan Ermilov		else
907a6a3e856SRuslan Ermilov			if [ -n "$PAGER" ]; then
908a6a3e856SRuslan Ermilov				MANPAGER="$PAGER"
909a6a3e856SRuslan Ermilov			else
910a6a3e856SRuslan Ermilov				MANPAGER="more -s"
911c535eb59SGordon Tetlow			fi
912a6a3e856SRuslan Ermilov		fi
913a6a3e856SRuslan Ermilov	fi
914a6a3e856SRuslan Ermilov	decho "Using pager: $MANPAGER"
915c535eb59SGordon Tetlow}
916c535eb59SGordon Tetlow
917c535eb59SGordon Tetlow# Usage: trim string
918c535eb59SGordon Tetlow# Trims whitespace from beginning and end of a variable
919c535eb59SGordon Tetlowtrim() {
920c535eb59SGordon Tetlow	tstr=$1
921c535eb59SGordon Tetlow	while true; do
922c535eb59SGordon Tetlow		case "$tstr" in
923c535eb59SGordon Tetlow		[\ \	]*)	tstr="${tstr##[\ \	]}" ;;
924c535eb59SGordon Tetlow		*[\ \	])	tstr="${tstr%%[\ \	]}" ;;
925c535eb59SGordon Tetlow		*)		break ;;
926c535eb59SGordon Tetlow		esac
927c535eb59SGordon Tetlow	done
928c535eb59SGordon Tetlow}
929c535eb59SGordon Tetlow
930c535eb59SGordon Tetlow# Usage: whatis_parse_args "$@"
931c535eb59SGordon Tetlow# Parse commandline args for whatis and apropos.
932c535eb59SGordon Tetlowwhatis_parse_args() {
933c535eb59SGordon Tetlow	local cmd_arg
934c535eb59SGordon Tetlow	while getopts 'd' cmd_arg; do
935c535eb59SGordon Tetlow		case "${cmd_arg}" in
936c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
937c535eb59SGordon Tetlow		*)	whatis_usage ;;
938c535eb59SGordon Tetlow		esac
939c535eb59SGordon Tetlow	done >&2
940c535eb59SGordon Tetlow
941c535eb59SGordon Tetlow	shift $(( $OPTIND - 1 ))
942c535eb59SGordon Tetlow
943c535eb59SGordon Tetlow	keywords="$*"
944c535eb59SGordon Tetlow}
945c535eb59SGordon Tetlow
946c535eb59SGordon Tetlow# Usage: whatis_usage
947c535eb59SGordon Tetlow# Display usage for the whatis/apropos utility.
948c535eb59SGordon Tetlowwhatis_usage() {
949c535eb59SGordon Tetlow	echo "usage: $cmd [-d] keyword [...]"
950c535eb59SGordon Tetlow	exit 1
951c535eb59SGordon Tetlow}
952c535eb59SGordon Tetlow
953c535eb59SGordon Tetlow
954c535eb59SGordon Tetlow
955c535eb59SGordon Tetlow# Supported commands
956c535eb59SGordon Tetlowdo_apropos() {
95724ef7420SBaptiste Daroussin	[ $(stat -f %i /usr/bin/man) -ne $(stat -f %i /usr/bin/apropos) ] && \
958772246efSBaptiste Daroussin		exec apropos "$@"
959c535eb59SGordon Tetlow	search_whatis apropos "$@"
960c535eb59SGordon Tetlow}
961c535eb59SGordon Tetlow
962c535eb59SGordon Tetlowdo_man() {
963c535eb59SGordon Tetlow	man_parse_args "$@"
964c535eb59SGordon Tetlow	if [ -z "$pages" ]; then
965c535eb59SGordon Tetlow		echo 'What manual page do you want?' >&2
966c535eb59SGordon Tetlow		exit 1
967c535eb59SGordon Tetlow	fi
968c535eb59SGordon Tetlow	man_setup
969c535eb59SGordon Tetlow
970c535eb59SGordon Tetlow	for page in $pages; do
971c535eb59SGordon Tetlow		decho "Searching for $page"
972c535eb59SGordon Tetlow		man_find_and_display "$page"
973c535eb59SGordon Tetlow	done
974c535eb59SGordon Tetlow
975c535eb59SGordon Tetlow	exit ${ret:-0}
976c535eb59SGordon Tetlow}
977c535eb59SGordon Tetlow
978c535eb59SGordon Tetlowdo_manpath() {
979c535eb59SGordon Tetlow	manpath_parse_args "$@"
980c535eb59SGordon Tetlow	if [ -z "$qflag" ]; then
981c535eb59SGordon Tetlow		manpath_warnings
982c535eb59SGordon Tetlow	fi
983c535eb59SGordon Tetlow	if [ -n "$Lflag" ]; then
984c535eb59SGordon Tetlow		build_manlocales
985c535eb59SGordon Tetlow		echo $MANLOCALES
986c535eb59SGordon Tetlow	else
987c535eb59SGordon Tetlow		build_manpath
988c535eb59SGordon Tetlow		echo $MANPATH
989c535eb59SGordon Tetlow	fi
990c535eb59SGordon Tetlow	exit 0
991c535eb59SGordon Tetlow}
992c535eb59SGordon Tetlow
993c535eb59SGordon Tetlowdo_whatis() {
99424ef7420SBaptiste Daroussin	[ $(stat -f %i /usr/bin/man) -ne $(stat -f %i /usr/bin/whatis) ] && \
995772246efSBaptiste Daroussin		exec whatis "$@"
996c535eb59SGordon Tetlow	search_whatis whatis "$@"
997c535eb59SGordon Tetlow}
998c535eb59SGordon Tetlow
999aeea395eSUlrich Spörlein# User's PATH setting decides on the groff-suite to pick up.
1000aeea395eSUlrich SpörleinEQN=eqn
1001a6a3e856SRuslan ErmilovNROFF='groff -S -P-h -Wall -mtty-char -man'
1002aeea395eSUlrich SpörleinPIC=pic
1003aeea395eSUlrich SpörleinREFER=refer
1004aeea395eSUlrich SpörleinTBL=tbl
10053d120968SUlrich SpörleinTROFF='groff -S -man'
1006aeea395eSUlrich SpörleinVGRIND=vgrind
1007aeea395eSUlrich Spörlein
1008deeff310SGordon TetlowLOCALE=/usr/bin/locale
1009a0094449SRuslan ErmilovSTTY=/bin/stty
101082db8a5eSGordon TetlowSYSCTL=/sbin/sysctl
1011c535eb59SGordon Tetlow
1012c535eb59SGordon Tetlowdebug=0
101340449c74SBrooks Davisman_default_sections='1:8:2:3:n:4:5:6:7:9:l'
1014c535eb59SGordon Tetlowman_default_path='/usr/share/man:/usr/share/openssl/man:/usr/local/man'
101557cd9717SGordon Tetlowcattool='/usr/bin/zcat -f'
1016c535eb59SGordon Tetlow
1017c535eb59SGordon Tetlowconfig_global='/etc/man.conf'
1018c535eb59SGordon Tetlow
1019c535eb59SGordon Tetlow# This can be overridden via a setting in /etc/man.conf.
1020c535eb59SGordon Tetlowconfig_local='/usr/local/etc/man.d/*.conf'
1021c535eb59SGordon Tetlow
1022c535eb59SGordon Tetlow# Set noglobbing for now. I don't want spurious globbing.
1023c535eb59SGordon Tetlowset -f
1024c535eb59SGordon Tetlow
1025c535eb59SGordon Tetlowcase "$0" in
1026c535eb59SGordon Tetlow*apropos)	do_apropos "$@" ;;
1027c535eb59SGordon Tetlow*manpath)	do_manpath "$@" ;;
1028c535eb59SGordon Tetlow*whatis)	do_whatis "$@" ;;
1029c535eb59SGordon Tetlow*)		do_man "$@" ;;
1030c535eb59SGordon Tetlowesac
1031