xref: /freebsd/usr.bin/man/man.sh (revision 433c5a8ae42f0487cfe860af1d291ec3c7d009f7)
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
31*433c5a8aSWolfram Schneider# Rendering a manual page is fast. Even a manual page several 100k in size
32*433c5a8aSWolfram Schneider# takes less than a CPU second. If it takes much longer, it is very likely
33*433c5a8aSWolfram Schneider# that a tool like mandoc(1) is running in an infinite loop. In this case
34*433c5a8aSWolfram Schneider# it is better to terminate it.
35*433c5a8aSWolfram Schneiderulimit -t 20
36*433c5a8aSWolfram Schneider
37c535eb59SGordon Tetlow# Usage: add_to_manpath path
38c535eb59SGordon Tetlow# Adds a variable to manpath while ensuring we don't have duplicates.
39c535eb59SGordon Tetlow# Returns true if we were able to add something. False otherwise.
40c535eb59SGordon Tetlowadd_to_manpath() {
41c535eb59SGordon Tetlow	case "$manpath" in
42c535eb59SGordon Tetlow	*:$1)	decho "  Skipping duplicate manpath entry $1" 2 ;;
43c535eb59SGordon Tetlow	$1:*)	decho "  Skipping duplicate manpath entry $1" 2 ;;
44c535eb59SGordon Tetlow	*:$1:*)	decho "  Skipping duplicate manpath entry $1" 2 ;;
45c535eb59SGordon Tetlow	*)	if [ -d "$1" ]; then
46c535eb59SGordon Tetlow			decho "  Adding $1 to manpath"
47c535eb59SGordon Tetlow			manpath="$manpath:$1"
48c535eb59SGordon Tetlow			return 0
49c535eb59SGordon Tetlow		fi
50c535eb59SGordon Tetlow		;;
51c535eb59SGordon Tetlow	esac
52c535eb59SGordon Tetlow
53c535eb59SGordon Tetlow	return 1
54c535eb59SGordon Tetlow}
55c535eb59SGordon Tetlow
56c535eb59SGordon Tetlow# Usage: build_manlocales
57c535eb59SGordon Tetlow# Builds a correct MANLOCALES variable.
58c535eb59SGordon Tetlowbuild_manlocales() {
59c535eb59SGordon Tetlow	# If the user has set manlocales, who are we to argue.
60c535eb59SGordon Tetlow	if [ -n "$MANLOCALES" ]; then
61c535eb59SGordon Tetlow		return
62c535eb59SGordon Tetlow	fi
63c535eb59SGordon Tetlow
64c535eb59SGordon Tetlow	parse_configs
65c535eb59SGordon Tetlow
66c535eb59SGordon Tetlow	# Trim leading colon
67c535eb59SGordon Tetlow	MANLOCALES=${manlocales#:}
68c535eb59SGordon Tetlow
69c535eb59SGordon Tetlow	decho "Available manual locales: $MANLOCALES"
70c535eb59SGordon Tetlow}
71c535eb59SGordon Tetlow
72c535eb59SGordon Tetlow# Usage: build_manpath
73c535eb59SGordon Tetlow# Builds a correct MANPATH variable.
74c535eb59SGordon Tetlowbuild_manpath() {
75c535eb59SGordon Tetlow	local IFS
76c535eb59SGordon Tetlow
77c535eb59SGordon Tetlow	# If the user has set a manpath, who are we to argue.
78c535eb59SGordon Tetlow	if [ -n "$MANPATH" ]; then
79b2394e73SBaptiste Daroussin		case "$MANPATH" in
80b2394e73SBaptiste Daroussin		*:) PREPEND_MANPATH=${MANPATH} ;;
81b2394e73SBaptiste Daroussin		:*) APPEND_MANPATH=${MANPATH} ;;
82b2394e73SBaptiste Daroussin		*::*)
83b2394e73SBaptiste Daroussin			PREPEND_MANPATH=${MANPATH%%::*}
84b2394e73SBaptiste Daroussin			APPEND_MANPATH=${MANPATH#*::}
85b2394e73SBaptiste Daroussin			;;
86b2394e73SBaptiste Daroussin		*) return ;;
87b2394e73SBaptiste Daroussin		esac
88b2394e73SBaptiste Daroussin	fi
89b2394e73SBaptiste Daroussin
90b2394e73SBaptiste Daroussin	if [ -n "$PREPEND_MANPATH" ]; then
91b2394e73SBaptiste Daroussin		IFS=:
92b2394e73SBaptiste Daroussin		for path in $PREPEND_MANPATH; do
93b2394e73SBaptiste Daroussin			add_to_manpath "$path"
94b2394e73SBaptiste Daroussin		done
95b2394e73SBaptiste Daroussin		unset IFS
96c535eb59SGordon Tetlow	fi
97c535eb59SGordon Tetlow
98c535eb59SGordon Tetlow	search_path
99c535eb59SGordon Tetlow
100c535eb59SGordon Tetlow	decho "Adding default manpath entries"
101c535eb59SGordon Tetlow	IFS=:
102c535eb59SGordon Tetlow	for path in $man_default_path; do
103c535eb59SGordon Tetlow		add_to_manpath "$path"
104c535eb59SGordon Tetlow	done
105c535eb59SGordon Tetlow	unset IFS
106c535eb59SGordon Tetlow
107c535eb59SGordon Tetlow	parse_configs
108c535eb59SGordon Tetlow
109b2394e73SBaptiste Daroussin	if [ -n "$APPEND_MANPATH" ]; then
110b2394e73SBaptiste Daroussin		IFS=:
111b2394e73SBaptiste Daroussin		for path in $APPEND_MANPATH; do
112b2394e73SBaptiste Daroussin			add_to_manpath "$path"
113b2394e73SBaptiste Daroussin		done
114b2394e73SBaptiste Daroussin		unset IFS
115b2394e73SBaptiste Daroussin	fi
116c535eb59SGordon Tetlow	# Trim leading colon
117c535eb59SGordon Tetlow	MANPATH=${manpath#:}
118c535eb59SGordon Tetlow
119c535eb59SGordon Tetlow	decho "Using manual path: $MANPATH"
120c535eb59SGordon Tetlow}
121c535eb59SGordon Tetlow
122c535eb59SGordon Tetlow# Usage: check_cat catglob
123c535eb59SGordon Tetlow# Checks to see if a cat glob is available.
124c535eb59SGordon Tetlowcheck_cat() {
125c535eb59SGordon Tetlow	if exists "$1"; then
126c535eb59SGordon Tetlow		use_cat=yes
127c535eb59SGordon Tetlow		catpage=$found
12857cd9717SGordon Tetlow		setup_cattool $catpage
129c535eb59SGordon Tetlow		decho "    Found catpage $catpage"
130c535eb59SGordon Tetlow		return 0
131c535eb59SGordon Tetlow	else
132c535eb59SGordon Tetlow		return 1
133c535eb59SGordon Tetlow	fi
134c535eb59SGordon Tetlow}
135c535eb59SGordon Tetlow
136c535eb59SGordon Tetlow# Usage: check_man manglob catglob
137c535eb59SGordon Tetlow# Given 2 globs, figures out if the manglob is available, if so, check to
138c535eb59SGordon Tetlow# see if the catglob is also available and up to date.
139c535eb59SGordon Tetlowcheck_man() {
140c535eb59SGordon Tetlow	if exists "$1"; then
141c535eb59SGordon Tetlow		# We have a match, check for a cat page
142c535eb59SGordon Tetlow		manpage=$found
14357cd9717SGordon Tetlow		setup_cattool $manpage
144c535eb59SGordon Tetlow		decho "    Found manpage $manpage"
145c535eb59SGordon Tetlow
146a0094449SRuslan Ermilov		if [ -n "${use_width}" ]; then
147a0094449SRuslan Ermilov			# non-standard width
148a0094449SRuslan Ermilov			unset use_cat
149a0094449SRuslan Ermilov			decho "    Skipping catpage: non-standard page width"
150a0094449SRuslan Ermilov		elif exists "$2" && is_newer $found $manpage; then
151c535eb59SGordon Tetlow			# cat page found and is newer, use that
152c535eb59SGordon Tetlow			use_cat=yes
153c535eb59SGordon Tetlow			catpage=$found
15457cd9717SGordon Tetlow			setup_cattool $catpage
155c535eb59SGordon Tetlow			decho "    Using catpage $catpage"
156c535eb59SGordon Tetlow		else
157c535eb59SGordon Tetlow			# no cat page or is older
158c535eb59SGordon Tetlow			unset use_cat
159c535eb59SGordon Tetlow			decho "    Skipping catpage: not found or old"
160c535eb59SGordon Tetlow		fi
161c535eb59SGordon Tetlow		return 0
162c535eb59SGordon Tetlow	fi
163c535eb59SGordon Tetlow
164c535eb59SGordon Tetlow	return 1
165c535eb59SGordon Tetlow}
166c535eb59SGordon Tetlow
167c535eb59SGordon Tetlow# Usage: decho "string" [debuglevel]
168c535eb59SGordon Tetlow# Echoes to stderr string prefaced with -- if high enough debuglevel.
169c535eb59SGordon Tetlowdecho() {
170c535eb59SGordon Tetlow	if [ $debug -ge ${2:-1} ]; then
171c535eb59SGordon Tetlow		echo "-- $1" >&2
172c535eb59SGordon Tetlow	fi
173c535eb59SGordon Tetlow}
174c535eb59SGordon Tetlow
175c535eb59SGordon Tetlow# Usage: exists glob
176c535eb59SGordon Tetlow# Returns true if glob resolves to a real file.
177c535eb59SGordon Tetlowexists() {
178c535eb59SGordon Tetlow	local IFS
179c535eb59SGordon Tetlow
180c535eb59SGordon Tetlow	# Don't accidentally inherit callers IFS (breaks perl manpages)
181c535eb59SGordon Tetlow	unset IFS
182c535eb59SGordon Tetlow
183c535eb59SGordon Tetlow	# Use some globbing tricks in the shell to determine if a file
184c535eb59SGordon Tetlow	# exists or not.
185c535eb59SGordon Tetlow	set +f
186c535eb59SGordon Tetlow	set -- "$1" $1
187c535eb59SGordon Tetlow	set -f
188c535eb59SGordon Tetlow
189c535eb59SGordon Tetlow	if [ "$1" != "$2" -a -r "$2" ]; then
190c535eb59SGordon Tetlow		found="$2"
191c535eb59SGordon Tetlow		return 0
192c535eb59SGordon Tetlow	fi
193c535eb59SGordon Tetlow
194c535eb59SGordon Tetlow	return 1
195c535eb59SGordon Tetlow}
196c535eb59SGordon Tetlow
197c535eb59SGordon Tetlow# Usage: find_file path section subdir pagename
198c535eb59SGordon Tetlow# Returns: true if something is matched and found.
199c535eb59SGordon Tetlow# Search the given path/section combo for a given page.
200c535eb59SGordon Tetlowfind_file() {
201c535eb59SGordon Tetlow	local manroot catroot mann man0 catn cat0
202c535eb59SGordon Tetlow
203c535eb59SGordon Tetlow	manroot="$1/man$2"
204c535eb59SGordon Tetlow	catroot="$1/cat$2"
205c535eb59SGordon Tetlow	if [ -n "$3" ]; then
206c535eb59SGordon Tetlow		manroot="$manroot/$3"
207c535eb59SGordon Tetlow		catroot="$catroot/$3"
208c535eb59SGordon Tetlow	fi
209c535eb59SGordon Tetlow
210625490e8SBaptiste Daroussin	if [ ! -d "$manroot" -a ! -d "$catroot" ]; then
211c535eb59SGordon Tetlow		return 1
212c535eb59SGordon Tetlow	fi
213c535eb59SGordon Tetlow	decho "  Searching directory $manroot" 2
214c535eb59SGordon Tetlow
215c535eb59SGordon Tetlow	mann="$manroot/$4.$2*"
216c535eb59SGordon Tetlow	man0="$manroot/$4.0*"
217c535eb59SGordon Tetlow	catn="$catroot/$4.$2*"
218c535eb59SGordon Tetlow	cat0="$catroot/$4.0*"
219c535eb59SGordon Tetlow
220c535eb59SGordon Tetlow	# This is the behavior as seen by the original man utility.
221c535eb59SGordon Tetlow	# Let's not change that which doesn't seem broken.
222c535eb59SGordon Tetlow	if check_man "$mann" "$catn"; then
223c535eb59SGordon Tetlow		return 0
224c535eb59SGordon Tetlow	elif check_man "$man0" "$cat0"; then
225c535eb59SGordon Tetlow		return 0
226c535eb59SGordon Tetlow	elif check_cat "$catn"; then
227c535eb59SGordon Tetlow		return 0
228c535eb59SGordon Tetlow	elif check_cat "$cat0"; then
229c535eb59SGordon Tetlow		return 0
230c535eb59SGordon Tetlow	fi
231c535eb59SGordon Tetlow
232c535eb59SGordon Tetlow	return 1
233c535eb59SGordon Tetlow}
234c535eb59SGordon Tetlow
235c535eb59SGordon Tetlow# Usage: is_newer file1 file2
236c535eb59SGordon Tetlow# Returns true if file1 is newer than file2 as calculated by mtime.
237c535eb59SGordon Tetlowis_newer() {
2389b61837aSUlrich Spörlein	if ! [ "$1" -ot "$2" ]; then
2399b61837aSUlrich Spörlein		decho "    mtime: $1 not older than $2" 3
240c535eb59SGordon Tetlow		return 0
241c535eb59SGordon Tetlow	else
242c535eb59SGordon Tetlow		decho "    mtime: $1 older than $2" 3
243c535eb59SGordon Tetlow		return 1
244c535eb59SGordon Tetlow	fi
245c535eb59SGordon Tetlow}
246c535eb59SGordon Tetlow
247c535eb59SGordon Tetlow# Usage: manpath_parse_args "$@"
248c535eb59SGordon Tetlow# Parses commandline options for manpath.
249c535eb59SGordon Tetlowmanpath_parse_args() {
250c535eb59SGordon Tetlow	local cmd_arg
251c535eb59SGordon Tetlow
252f555b39eSKyle Evans	OPTIND=1
253c535eb59SGordon Tetlow	while getopts 'Ldq' cmd_arg; do
254c535eb59SGordon Tetlow		case "${cmd_arg}" in
255c535eb59SGordon Tetlow		L)	Lflag=Lflag ;;
256c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
257c535eb59SGordon Tetlow		q)	qflag=qflag ;;
258c535eb59SGordon Tetlow		*)	manpath_usage ;;
259c535eb59SGordon Tetlow		esac
260c535eb59SGordon Tetlow	done >&2
261c535eb59SGordon Tetlow}
262c535eb59SGordon Tetlow
263c535eb59SGordon Tetlow# Usage: manpath_usage
264c535eb59SGordon Tetlow# Display usage for the manpath(1) utility.
265c535eb59SGordon Tetlowmanpath_usage() {
266c535eb59SGordon Tetlow	echo 'usage: manpath [-Ldq]' >&2
267c535eb59SGordon Tetlow	exit 1
268c535eb59SGordon Tetlow}
269c535eb59SGordon Tetlow
270c535eb59SGordon Tetlow# Usage: manpath_warnings
271c535eb59SGordon Tetlow# Display some warnings to stderr.
272c535eb59SGordon Tetlowmanpath_warnings() {
273c535eb59SGordon Tetlow	if [ -n "$Lflag" -a -n "$MANLOCALES" ]; then
274c535eb59SGordon Tetlow		echo "(Warning: MANLOCALES environment variable set)" >&2
275c535eb59SGordon Tetlow	fi
276c535eb59SGordon Tetlow}
277c535eb59SGordon Tetlow
27857cd9717SGordon Tetlow# Usage: man_check_for_so page path
27957cd9717SGordon Tetlow# Returns: True if able to resolve the file, false if it ended in tears.
28057cd9717SGordon Tetlow# Detects the presence of the .so directive and causes the file to be
28157cd9717SGordon Tetlow# redirected to another source file.
28257cd9717SGordon Tetlowman_check_for_so() {
28357cd9717SGordon Tetlow	local IFS line tstr
28457cd9717SGordon Tetlow
28557cd9717SGordon Tetlow	unset IFS
286d9405a92SBaptiste Daroussin	if [ -n "$catpage" ]; then
287d9405a92SBaptiste Daroussin		return 0
288d9405a92SBaptiste Daroussin	fi
28957cd9717SGordon Tetlow
29057cd9717SGordon Tetlow	# We need to loop to accommodate multiple .so directives.
29157cd9717SGordon Tetlow	while true
29257cd9717SGordon Tetlow	do
29357cd9717SGordon Tetlow		line=$($cattool $manpage | head -1)
29457cd9717SGordon Tetlow		case "$line" in
29557cd9717SGordon Tetlow		.so*)	trim "${line#.so}"
29657cd9717SGordon Tetlow			decho "$manpage includes $tstr"
29757cd9717SGordon Tetlow			# Glob and check for the file.
29857cd9717SGordon Tetlow			if ! check_man "$path/$tstr*" ""; then
29957cd9717SGordon Tetlow				decho "  Unable to find $tstr"
30057cd9717SGordon Tetlow				return 1
30157cd9717SGordon Tetlow			fi
30257cd9717SGordon Tetlow			;;
30357cd9717SGordon Tetlow		*)	break ;;
30457cd9717SGordon Tetlow		esac
30557cd9717SGordon Tetlow	done
30657cd9717SGordon Tetlow
30757cd9717SGordon Tetlow	return 0
30857cd9717SGordon Tetlow}
30957cd9717SGordon Tetlow
310b43edc06SBaptiste Daroussin# Usage: man_display_page
311b43edc06SBaptiste Daroussin# Display either the manpage or catpage depending on the use_cat variable
312c535eb59SGordon Tetlowman_display_page() {
3131fb816daSBaptiste Daroussin	local IFS pipeline testline
314c535eb59SGordon Tetlow
315c535eb59SGordon Tetlow	# We are called with IFS set to colon. This causes really weird
316c535eb59SGordon Tetlow	# things to happen for the variables that have spaces in them.
317c535eb59SGordon Tetlow	unset IFS
318c535eb59SGordon Tetlow
319c535eb59SGordon Tetlow	# If we are supposed to use a catpage and we aren't using troff(1)
320c535eb59SGordon Tetlow	# just zcat the catpage and we are done.
321c535eb59SGordon Tetlow	if [ -z "$tflag" -a -n "$use_cat" ]; then
322c535eb59SGordon Tetlow		if [ -n "$wflag" ]; then
323c535eb59SGordon Tetlow			echo "$catpage (source: $manpage)"
324c535eb59SGordon Tetlow			ret=0
325c535eb59SGordon Tetlow		else
326c535eb59SGordon Tetlow			if [ $debug -gt 0 ]; then
327a6a3e856SRuslan Ermilov				decho "Command: $cattool $catpage | $MANPAGER"
328c535eb59SGordon Tetlow				ret=0
329c535eb59SGordon Tetlow			else
330a6a3e856SRuslan Ermilov				eval "$cattool $catpage | $MANPAGER"
331c535eb59SGordon Tetlow				ret=$?
332c535eb59SGordon Tetlow			fi
333c535eb59SGordon Tetlow		fi
334c535eb59SGordon Tetlow		return
335c535eb59SGordon Tetlow	fi
336c535eb59SGordon Tetlow
337c535eb59SGordon Tetlow	# Okay, we are using the manpage, do we just need to output the
338c535eb59SGordon Tetlow	# name of the manpage?
339c535eb59SGordon Tetlow	if [ -n "$wflag" ]; then
340c535eb59SGordon Tetlow		echo "$manpage"
341c535eb59SGordon Tetlow		ret=0
342c535eb59SGordon Tetlow		return
343c535eb59SGordon Tetlow	fi
344c535eb59SGordon Tetlow
345d433cf9aSBaptiste Daroussin	if [ -n "$use_width" ]; then
346d433cf9aSBaptiste Daroussin		mandoc_args="-O width=${use_width}"
347d433cf9aSBaptiste Daroussin	fi
348451c2becSBaptiste Daroussin	testline="mandoc -Tlint -Wunsupp >/dev/null 2>&1"
349449a792dSBaptiste Daroussin	if [ -n "$tflag" ]; then
350449a792dSBaptiste Daroussin		pipeline="mandoc -Tps $mandoc_args"
351449a792dSBaptiste Daroussin	else
352d433cf9aSBaptiste Daroussin		pipeline="mandoc $mandoc_args | $MANPAGER"
353449a792dSBaptiste Daroussin	fi
354d6096801SBaptiste Daroussin
355d6096801SBaptiste Daroussin	if ! eval "$cattool $manpage | $testline" ;then
356f17575acSBaptiste Daroussin		if which -s groff; then
357d6096801SBaptiste Daroussin			man_display_page_groff
358d6096801SBaptiste Daroussin		else
359d6096801SBaptiste Daroussin			echo "This manpage needs groff(1) to be rendered" >&2
360d6096801SBaptiste Daroussin			echo "First install groff(1): " >&2
361d6096801SBaptiste Daroussin			echo "pkg install groff " >&2
362d6096801SBaptiste Daroussin			ret=1
363d6096801SBaptiste Daroussin		fi
364d6096801SBaptiste Daroussin		return
365d6096801SBaptiste Daroussin	fi
366d6096801SBaptiste Daroussin
367d6096801SBaptiste Daroussin	if [ $debug -gt 0 ]; then
368d6096801SBaptiste Daroussin		decho "Command: $cattool $manpage | $pipeline"
369d6096801SBaptiste Daroussin		ret=0
370d6096801SBaptiste Daroussin	else
371d6096801SBaptiste Daroussin		eval "$cattool $manpage | $pipeline"
372d6096801SBaptiste Daroussin		ret=$?
373d6096801SBaptiste Daroussin	fi
374d6096801SBaptiste Daroussin}
375d6096801SBaptiste Daroussin
376b43edc06SBaptiste Daroussin# Usage: man_display_page_groff
377b43edc06SBaptiste Daroussin# Display the manpage using groff
378d6096801SBaptiste Daroussinman_display_page_groff() {
379d6096801SBaptiste Daroussin	local EQN NROFF PIC TBL TROFF REFER VGRIND
380d6096801SBaptiste Daroussin	local IFS l nroff_dev pipeline preproc_arg tool
381d6096801SBaptiste Daroussin
382c535eb59SGordon Tetlow	# So, we really do need to parse the manpage. First, figure out the
383c535eb59SGordon Tetlow	# device flag (-T) we have to pass to eqn(1) and groff(1). Then,
384c535eb59SGordon Tetlow	# setup the pipeline of commands based on the user's request.
385c535eb59SGordon Tetlow
386deeff310SGordon Tetlow	# If the manpage is from a particular charset, we need to setup nroff
387deeff310SGordon Tetlow	# to properly output for the correct device.
388deeff310SGordon Tetlow	case "${manpage}" in
389deeff310SGordon Tetlow	*.${man_charset}/*)
390c535eb59SGordon Tetlow		# I don't pretend to know this; I'm just copying from the
391c535eb59SGordon Tetlow		# previous version of man(1).
392c535eb59SGordon Tetlow		case "$man_charset" in
393c535eb59SGordon Tetlow		KOI8-R)		nroff_dev="koi8-r" ;;
394c535eb59SGordon Tetlow		ISO8859-1)	nroff_dev="latin1" ;;
395c535eb59SGordon Tetlow		ISO8859-15)	nroff_dev="latin1" ;;
396c535eb59SGordon Tetlow		UTF-8)		nroff_dev="utf8" ;;
397c535eb59SGordon Tetlow		*)		nroff_dev="ascii" ;;
398c535eb59SGordon Tetlow		esac
399c535eb59SGordon Tetlow
400deeff310SGordon Tetlow		NROFF="$NROFF -T$nroff_dev"
401c535eb59SGordon Tetlow		EQN="$EQN -T$nroff_dev"
402c535eb59SGordon Tetlow
403deeff310SGordon Tetlow		# Iff the manpage is from the locale and not just the charset,
404deeff310SGordon Tetlow		# then we need to define the locale string.
405deeff310SGordon Tetlow		case "${manpage}" in
406deeff310SGordon Tetlow		*/${man_lang}_${man_country}.${man_charset}/*)
407deeff310SGordon Tetlow			NROFF="$NROFF -dlocale=$man_lang.$man_charset"
408deeff310SGordon Tetlow			;;
409deeff310SGordon Tetlow		*/${man_lang}.${man_charset}/*)
410deeff310SGordon Tetlow			NROFF="$NROFF -dlocale=$man_lang.$man_charset"
411deeff310SGordon Tetlow			;;
412deeff310SGordon Tetlow		esac
413deeff310SGordon Tetlow
414c535eb59SGordon Tetlow		# Allow language specific calls to override the default
415c535eb59SGordon Tetlow		# set of utilities.
416c535eb59SGordon Tetlow		l=$(echo $man_lang | tr [:lower:] [:upper:])
417b70e2025SRuslan Ermilov		for tool in EQN NROFF PIC TBL TROFF REFER VGRIND; do
418c535eb59SGordon Tetlow			eval "$tool=\${${tool}_$l:-\$$tool}"
419c535eb59SGordon Tetlow		done
420c535eb59SGordon Tetlow		;;
421c535eb59SGordon Tetlow	*)	NROFF="$NROFF -Tascii"
422c535eb59SGordon Tetlow		EQN="$EQN -Tascii"
423c535eb59SGordon Tetlow		;;
424c535eb59SGordon Tetlow	esac
425c535eb59SGordon Tetlow
426a6a3e856SRuslan Ermilov	if [ -z "$MANCOLOR" ]; then
427a6a3e856SRuslan Ermilov		NROFF="$NROFF -P-c"
428a6a3e856SRuslan Ermilov	fi
429a6a3e856SRuslan Ermilov
430a0094449SRuslan Ermilov	if [ -n "${use_width}" ]; then
431a0094449SRuslan Ermilov		NROFF="$NROFF -rLL=${use_width}n -rLT=${use_width}n"
432a0094449SRuslan Ermilov	fi
433a0094449SRuslan Ermilov
434c535eb59SGordon Tetlow	if [ -n "$MANROFFSEQ" ]; then
435c535eb59SGordon Tetlow		set -- -$MANROFFSEQ
436f555b39eSKyle Evans		OPTIND=1
437c535eb59SGordon Tetlow		while getopts 'egprtv' preproc_arg; do
438c535eb59SGordon Tetlow			case "${preproc_arg}" in
439c535eb59SGordon Tetlow			e)	pipeline="$pipeline | $EQN" ;;
440487ac9acSUlrich Spörlein			g)	;; # Ignore for compatibility.
441c535eb59SGordon Tetlow			p)	pipeline="$pipeline | $PIC" ;;
442c535eb59SGordon Tetlow			r)	pipeline="$pipeline | $REFER" ;;
443b70e2025SRuslan Ermilov			t)	pipeline="$pipeline | $TBL" ;;
444c535eb59SGordon Tetlow			v)	pipeline="$pipeline | $VGRIND" ;;
445c535eb59SGordon Tetlow			*)	usage ;;
446c535eb59SGordon Tetlow			esac
447c535eb59SGordon Tetlow		done
448c535eb59SGordon Tetlow		# Strip the leading " | " from the resulting pipeline.
449c535eb59SGordon Tetlow		pipeline="${pipeline#" | "}"
450c535eb59SGordon Tetlow	else
451c535eb59SGordon Tetlow		pipeline="$TBL"
452c535eb59SGordon Tetlow	fi
453c535eb59SGordon Tetlow
454c535eb59SGordon Tetlow	if [ -n "$tflag" ]; then
455c535eb59SGordon Tetlow		pipeline="$pipeline | $TROFF"
456c535eb59SGordon Tetlow	else
457a6a3e856SRuslan Ermilov		pipeline="$pipeline | $NROFF | $MANPAGER"
458c535eb59SGordon Tetlow	fi
459c535eb59SGordon Tetlow
460c535eb59SGordon Tetlow	if [ $debug -gt 0 ]; then
46157cd9717SGordon Tetlow		decho "Command: $cattool $manpage | $pipeline"
462c535eb59SGordon Tetlow		ret=0
463c535eb59SGordon Tetlow	else
46457cd9717SGordon Tetlow		eval "$cattool $manpage | $pipeline"
465c535eb59SGordon Tetlow		ret=$?
466c535eb59SGordon Tetlow	fi
467c535eb59SGordon Tetlow}
468c535eb59SGordon Tetlow
469c535eb59SGordon Tetlow# Usage: man_find_and_display page
470c535eb59SGordon Tetlow# Search through the manpaths looking for the given page.
471c535eb59SGordon Tetlowman_find_and_display() {
472c535eb59SGordon Tetlow	local found_page locpath p path sect
473c535eb59SGordon Tetlow
4743d9127f1SGordon Tetlow	# Check to see if it's a file. But only if it has a '/' in
4753d9127f1SGordon Tetlow	# the filename.
4763d9127f1SGordon Tetlow	case "$1" in
4773d9127f1SGordon Tetlow	*/*)	if [ -f "$1" -a -r "$1" ]; then
4783d9127f1SGordon Tetlow			decho "Found a usable page, displaying that"
4793d9127f1SGordon Tetlow			unset use_cat
4803d9127f1SGordon Tetlow			manpage="$1"
48157cd9717SGordon Tetlow			setup_cattool $manpage
48257cd9717SGordon Tetlow			if man_check_for_so $manpage $(dirname $manpage); then
48357cd9717SGordon Tetlow				found_page=yes
4843d9127f1SGordon Tetlow				man_display_page
48557cd9717SGordon Tetlow			fi
4863d9127f1SGordon Tetlow			return
4873d9127f1SGordon Tetlow		fi
4883d9127f1SGordon Tetlow		;;
4893d9127f1SGordon Tetlow	esac
4903d9127f1SGordon Tetlow
491c535eb59SGordon Tetlow	IFS=:
492c535eb59SGordon Tetlow	for sect in $MANSECT; do
493c535eb59SGordon Tetlow		decho "Searching section $sect" 2
494c535eb59SGordon Tetlow		for path in $MANPATH; do
495c535eb59SGordon Tetlow			for locpath in $locpaths; do
496c535eb59SGordon Tetlow				p=$path/$locpath
497c535eb59SGordon Tetlow				p=${p%/.} # Rid ourselves of the trailing /.
498c535eb59SGordon Tetlow
499c535eb59SGordon Tetlow				# Check if there is a MACHINE specific manpath.
500c535eb59SGordon Tetlow				if find_file $p $sect $MACHINE "$1"; then
50157cd9717SGordon Tetlow					if man_check_for_so $manpage $p; then
502c535eb59SGordon Tetlow						found_page=yes
503c535eb59SGordon Tetlow						man_display_page
5041d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
5051d7c660aSGordon Tetlow							continue 2
5061d7c660aSGordon Tetlow						else
507c535eb59SGordon Tetlow							return
508c535eb59SGordon Tetlow						fi
509c535eb59SGordon Tetlow					fi
51057cd9717SGordon Tetlow				fi
511c535eb59SGordon Tetlow
512c535eb59SGordon Tetlow				# Check if there is a MACHINE_ARCH
513c535eb59SGordon Tetlow				# specific manpath.
514c535eb59SGordon Tetlow				if find_file $p $sect $MACHINE_ARCH "$1"; then
51557cd9717SGordon Tetlow					if man_check_for_so $manpage $p; then
516c535eb59SGordon Tetlow						found_page=yes
517c535eb59SGordon Tetlow						man_display_page
5181d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
5191d7c660aSGordon Tetlow							continue 2
5201d7c660aSGordon Tetlow						else
521c535eb59SGordon Tetlow							return
522c535eb59SGordon Tetlow						fi
523c535eb59SGordon Tetlow					fi
52457cd9717SGordon Tetlow				fi
525c535eb59SGordon Tetlow
526c535eb59SGordon Tetlow				# Check plain old manpath.
527c535eb59SGordon Tetlow				if find_file $p $sect '' "$1"; then
52857cd9717SGordon Tetlow					if man_check_for_so $manpage $p; then
529c535eb59SGordon Tetlow						found_page=yes
530c535eb59SGordon Tetlow						man_display_page
5311d7c660aSGordon Tetlow						if [ -n "$aflag" ]; then
5321d7c660aSGordon Tetlow							continue 2
5331d7c660aSGordon Tetlow						else
534c535eb59SGordon Tetlow							return
535c535eb59SGordon Tetlow						fi
536c535eb59SGordon Tetlow					fi
53757cd9717SGordon Tetlow				fi
538c535eb59SGordon Tetlow			done
539c535eb59SGordon Tetlow		done
540c535eb59SGordon Tetlow	done
541c535eb59SGordon Tetlow	unset IFS
542c535eb59SGordon Tetlow
543c535eb59SGordon Tetlow	# Nothing? Well, we are done then.
544c535eb59SGordon Tetlow	if [ -z "$found_page" ]; then
545c535eb59SGordon Tetlow		echo "No manual entry for $1" >&2
546c535eb59SGordon Tetlow		ret=1
547c535eb59SGordon Tetlow		return
548c535eb59SGordon Tetlow	fi
549c535eb59SGordon Tetlow}
550c535eb59SGordon Tetlow
551c535eb59SGordon Tetlow# Usage: man_parse_args "$@"
552c535eb59SGordon Tetlow# Parses commandline options for man.
553c535eb59SGordon Tetlowman_parse_args() {
554c535eb59SGordon Tetlow	local IFS cmd_arg
555c535eb59SGordon Tetlow
556f555b39eSKyle Evans	OPTIND=1
5571594084fSFernando Apesteguía	while getopts 'K:M:P:S:adfhkm:op:tw' cmd_arg; do
558c535eb59SGordon Tetlow		case "${cmd_arg}" in
5591594084fSFernando Apesteguía		K)	Kflag=Kflag
5601594084fSFernando Apesteguía			REGEXP=$OPTARG ;;
561c535eb59SGordon Tetlow		M)	MANPATH=$OPTARG ;;
562a6a3e856SRuslan Ermilov		P)	MANPAGER=$OPTARG ;;
563c535eb59SGordon Tetlow		S)	MANSECT=$OPTARG ;;
564c535eb59SGordon Tetlow		a)	aflag=aflag ;;
565c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
566c535eb59SGordon Tetlow		f)	fflag=fflag ;;
567c535eb59SGordon Tetlow		h)	man_usage 0 ;;
568c535eb59SGordon Tetlow		k)	kflag=kflag ;;
569c535eb59SGordon Tetlow		m)	mflag=$OPTARG ;;
570c535eb59SGordon Tetlow		o)	oflag=oflag ;;
571c535eb59SGordon Tetlow		p)	MANROFFSEQ=$OPTARG ;;
572c535eb59SGordon Tetlow		t)	tflag=tflag ;;
573c535eb59SGordon Tetlow		w)	wflag=wflag ;;
574c535eb59SGordon Tetlow		*)	man_usage ;;
575c535eb59SGordon Tetlow		esac
576c535eb59SGordon Tetlow	done >&2
577c535eb59SGordon Tetlow
578c535eb59SGordon Tetlow	shift $(( $OPTIND - 1 ))
579c535eb59SGordon Tetlow
580c535eb59SGordon Tetlow	# Check the args for incompatible options.
5811594084fSFernando Apesteguía
5821594084fSFernando Apesteguía	case "${Kflag}${fflag}${kflag}${tflag}${wflag}" in
5831594084fSFernando Apesteguía	Kflagfflag*)	echo "Incompatible options: -K and -f"; man_usage ;;
5841594084fSFernando Apesteguía	Kflag*kflag*)	echo "Incompatible options: -K and -k"; man_usage ;;
5851594084fSFernando Apesteguía	Kflag*tflag)	echo "Incompatible options: -K and -t"; man_usage ;;
586c535eb59SGordon Tetlow	fflagkflag*)	echo "Incompatible options: -f and -k"; man_usage ;;
587c535eb59SGordon Tetlow	fflag*tflag*)	echo "Incompatible options: -f and -t"; man_usage ;;
588c535eb59SGordon Tetlow	fflag*wflag)	echo "Incompatible options: -f and -w"; man_usage ;;
589c535eb59SGordon Tetlow	*kflagtflag*)	echo "Incompatible options: -k and -t"; man_usage ;;
590c535eb59SGordon Tetlow	*kflag*wflag)	echo "Incompatible options: -k and -w"; man_usage ;;
591c535eb59SGordon Tetlow	*tflagwflag)	echo "Incompatible options: -t and -w"; man_usage ;;
592c535eb59SGordon Tetlow	esac
593c535eb59SGordon Tetlow
594c535eb59SGordon Tetlow	# Short circuit for whatis(1) and apropos(1)
595c535eb59SGordon Tetlow	if [ -n "$fflag" ]; then
596c535eb59SGordon Tetlow		do_whatis "$@"
597c535eb59SGordon Tetlow		exit
598c535eb59SGordon Tetlow	fi
599c535eb59SGordon Tetlow
600c535eb59SGordon Tetlow	if [ -n "$kflag" ]; then
601c535eb59SGordon Tetlow		do_apropos "$@"
602c535eb59SGordon Tetlow		exit
603c535eb59SGordon Tetlow	fi
604c535eb59SGordon Tetlow
605c535eb59SGordon Tetlow	IFS=:
606c535eb59SGordon Tetlow	for sect in $man_default_sections; do
607c535eb59SGordon Tetlow		if [ "$sect" = "$1" ]; then
608c535eb59SGordon Tetlow			decho "Detected manual section as first arg: $1"
609c535eb59SGordon Tetlow			MANSECT="$1"
610c535eb59SGordon Tetlow			shift
611c535eb59SGordon Tetlow			break
612c535eb59SGordon Tetlow		fi
613c535eb59SGordon Tetlow	done
614c535eb59SGordon Tetlow	unset IFS
615c535eb59SGordon Tetlow
616c535eb59SGordon Tetlow	pages="$*"
617c535eb59SGordon Tetlow}
618c535eb59SGordon Tetlow
619c535eb59SGordon Tetlow# Usage: man_setup
620c535eb59SGordon Tetlow# Setup various trivial but essential variables.
621c535eb59SGordon Tetlowman_setup() {
622c535eb59SGordon Tetlow	# Setup machine and architecture variables.
623c535eb59SGordon Tetlow	if [ -n "$mflag" ]; then
624c535eb59SGordon Tetlow		MACHINE_ARCH=${mflag%%:*}
625c535eb59SGordon Tetlow		MACHINE=${mflag##*:}
626c535eb59SGordon Tetlow	fi
627c535eb59SGordon Tetlow	if [ -z "$MACHINE_ARCH" ]; then
62882db8a5eSGordon Tetlow		MACHINE_ARCH=$($SYSCTL -n hw.machine_arch)
629c535eb59SGordon Tetlow	fi
630c535eb59SGordon Tetlow	if [ -z "$MACHINE" ]; then
63182db8a5eSGordon Tetlow		MACHINE=$($SYSCTL -n hw.machine)
632c535eb59SGordon Tetlow	fi
633c535eb59SGordon Tetlow	decho "Using architecture: $MACHINE_ARCH:$MACHINE"
634c535eb59SGordon Tetlow
635c535eb59SGordon Tetlow	setup_pager
636c535eb59SGordon Tetlow
637c535eb59SGordon Tetlow	# Setup manual sections to search.
638c535eb59SGordon Tetlow	if [ -z "$MANSECT" ]; then
639c535eb59SGordon Tetlow		MANSECT=$man_default_sections
640c535eb59SGordon Tetlow	fi
641c535eb59SGordon Tetlow	decho "Using manual sections: $MANSECT"
642c535eb59SGordon Tetlow
643c535eb59SGordon Tetlow	build_manpath
644c535eb59SGordon Tetlow	man_setup_locale
645a0094449SRuslan Ermilov	man_setup_width
646a0094449SRuslan Ermilov}
647a0094449SRuslan Ermilov
648a0094449SRuslan Ermilov# Usage: man_setup_width
649a0094449SRuslan Ermilov# Set up page width.
650a0094449SRuslan Ermilovman_setup_width() {
651a0094449SRuslan Ermilov	local sizes
652a0094449SRuslan Ermilov
653a0094449SRuslan Ermilov	unset use_width
654a0094449SRuslan Ermilov	case "$MANWIDTH" in
655a0094449SRuslan Ermilov	[0-9]*)
656a0094449SRuslan Ermilov		if [ "$MANWIDTH" -gt 0 2>/dev/null ]; then
657a0094449SRuslan Ermilov			use_width=$MANWIDTH
658a0094449SRuslan Ermilov		fi
659a0094449SRuslan Ermilov		;;
660a0094449SRuslan Ermilov	[Tt][Tt][Yy])
661a0094449SRuslan Ermilov		if { sizes=$($STTY size 0>&3 2>/dev/null); } 3>&1; then
662a0094449SRuslan Ermilov			set -- $sizes
663a0094449SRuslan Ermilov			if [ $2 -gt 80 ]; then
664a0094449SRuslan Ermilov				use_width=$(($2-2))
665a0094449SRuslan Ermilov			fi
666a0094449SRuslan Ermilov		fi
667a0094449SRuslan Ermilov		;;
668a0094449SRuslan Ermilov	esac
669a0094449SRuslan Ermilov	if [ -n "$use_width" ]; then
670a0094449SRuslan Ermilov		decho "Using non-standard page width: ${use_width}"
671a0094449SRuslan Ermilov	else
672a0094449SRuslan Ermilov		decho 'Using standard page width'
673a0094449SRuslan Ermilov	fi
674c535eb59SGordon Tetlow}
675c535eb59SGordon Tetlow
676c535eb59SGordon Tetlow# Usage: man_setup_locale
677c535eb59SGordon Tetlow# Setup necessary locale variables.
678c535eb59SGordon Tetlowman_setup_locale() {
679deeff310SGordon Tetlow	local lang_cc
6809508f8c0SYuri Pankov	local locstr
681deeff310SGordon Tetlow
682deeff310SGordon Tetlow	locpaths='.'
683deeff310SGordon Tetlow	man_charset='US-ASCII'
684deeff310SGordon Tetlow
685c535eb59SGordon Tetlow	# Setup locale information.
686c535eb59SGordon Tetlow	if [ -n "$oflag" ]; then
687deeff310SGordon Tetlow		decho 'Using non-localized manpages'
688deeff310SGordon Tetlow	else
6899508f8c0SYuri Pankov		# Use the locale tool to give us proper locale information
690deeff310SGordon Tetlow		eval $( $LOCALE )
691c535eb59SGordon Tetlow
6929508f8c0SYuri Pankov		if [ -n "$LANG" ]; then
6939508f8c0SYuri Pankov			locstr=$LANG
6949508f8c0SYuri Pankov		else
6959508f8c0SYuri Pankov			locstr=$LC_CTYPE
6969508f8c0SYuri Pankov		fi
6979508f8c0SYuri Pankov
6989508f8c0SYuri Pankov		case "$locstr" in
699deeff310SGordon Tetlow		C)		;;
7009508f8c0SYuri Pankov		C.UTF-8)	;;
701deeff310SGordon Tetlow		POSIX)		;;
702deeff310SGordon Tetlow		[a-z][a-z]_[A-Z][A-Z]\.*)
7039508f8c0SYuri Pankov				lang_cc="${locstr%.*}"
7049508f8c0SYuri Pankov				man_lang="${locstr%_*}"
705deeff310SGordon Tetlow				man_country="${lang_cc#*_}"
7069508f8c0SYuri Pankov				man_charset="${locstr#*.}"
7079508f8c0SYuri Pankov				locpaths="$locstr"
708c535eb59SGordon Tetlow				locpaths="$locpaths:$man_lang.$man_charset"
709c535eb59SGordon Tetlow				if [ "$man_lang" != "en" ]; then
710c535eb59SGordon Tetlow					locpaths="$locpaths:en.$man_charset"
711c535eb59SGordon Tetlow				fi
712c535eb59SGordon Tetlow				locpaths="$locpaths:."
713deeff310SGordon Tetlow				;;
714deeff310SGordon Tetlow		*)		echo 'Unknown locale, assuming C' >&2
715deeff310SGordon Tetlow				;;
716deeff310SGordon Tetlow		esac
717c535eb59SGordon Tetlow	fi
718deeff310SGordon Tetlow
719c535eb59SGordon Tetlow	decho "Using locale paths: $locpaths"
720c535eb59SGordon Tetlow}
721c535eb59SGordon Tetlow
722c535eb59SGordon Tetlow# Usage: man_usage [exitcode]
723c535eb59SGordon Tetlow# Display usage for the man utility.
724c535eb59SGordon Tetlowman_usage() {
725c535eb59SGordon Tetlow	echo 'Usage:'
7261594084fSFernando Apesteguía	echo ' man [-adho] [-t | -w] [-K regexp] [-M manpath] [-P pager] [-S mansect]'
727c535eb59SGordon Tetlow	echo '     [-m arch[:machine]] [-p [eprtv]] [mansect] page [...]'
728c535eb59SGordon Tetlow	echo ' man -f page [...] -- Emulates whatis(1)'
729c535eb59SGordon Tetlow	echo ' man -k page [...] -- Emulates apropos(1)'
730c535eb59SGordon Tetlow
731c535eb59SGordon Tetlow	# When exit'ing with -h, it's not an error.
732c535eb59SGordon Tetlow	exit ${1:-1}
733c535eb59SGordon Tetlow}
734c535eb59SGordon Tetlow
735c535eb59SGordon Tetlow# Usage: parse_configs
736c535eb59SGordon Tetlow# Reads the end-user adjustable config files.
737c535eb59SGordon Tetlowparse_configs() {
738c535eb59SGordon Tetlow	local IFS file files
739c535eb59SGordon Tetlow
740c535eb59SGordon Tetlow	if [ -n "$parsed_configs" ]; then
741c535eb59SGordon Tetlow		return
742c535eb59SGordon Tetlow	fi
743c535eb59SGordon Tetlow
744c535eb59SGordon Tetlow	unset IFS
745c535eb59SGordon Tetlow
746c535eb59SGordon Tetlow	# Read the global config first in case the user wants
747c535eb59SGordon Tetlow	# to override config_local.
748c535eb59SGordon Tetlow	if [ -r "$config_global" ]; then
749c535eb59SGordon Tetlow		parse_file "$config_global"
750c535eb59SGordon Tetlow	fi
751c535eb59SGordon Tetlow
752c535eb59SGordon Tetlow	# Glob the list of files to parse.
753c535eb59SGordon Tetlow	set +f
754c535eb59SGordon Tetlow	files=$(echo $config_local)
755c535eb59SGordon Tetlow	set -f
756c535eb59SGordon Tetlow
757c535eb59SGordon Tetlow	for file in $files; do
758c535eb59SGordon Tetlow		if [ -r "$file" ]; then
759c535eb59SGordon Tetlow			parse_file "$file"
760c535eb59SGordon Tetlow		fi
761c535eb59SGordon Tetlow	done
762c535eb59SGordon Tetlow
763c535eb59SGordon Tetlow	parsed_configs='yes'
764c535eb59SGordon Tetlow}
765c535eb59SGordon Tetlow
766c535eb59SGordon Tetlow# Usage: parse_file file
767c535eb59SGordon Tetlow# Reads the specified config files.
768c535eb59SGordon Tetlowparse_file() {
769c535eb59SGordon Tetlow	local file line tstr var
770c535eb59SGordon Tetlow
771c535eb59SGordon Tetlow	file="$1"
772c535eb59SGordon Tetlow	decho "Parsing config file: $file"
773c535eb59SGordon Tetlow	while read line; do
774c535eb59SGordon Tetlow		decho "  $line" 2
775c535eb59SGordon Tetlow		case "$line" in
776c535eb59SGordon Tetlow		\#*)		decho "    Comment" 3
777c535eb59SGordon Tetlow				;;
778c535eb59SGordon Tetlow		MANPATH*)	decho "    MANPATH" 3
779c535eb59SGordon Tetlow				trim "${line#MANPATH}"
780c535eb59SGordon Tetlow				add_to_manpath "$tstr"
781c535eb59SGordon Tetlow				;;
782c535eb59SGordon Tetlow		MANLOCALE*)	decho "    MANLOCALE" 3
783c535eb59SGordon Tetlow				trim "${line#MANLOCALE}"
784c535eb59SGordon Tetlow				manlocales="$manlocales:$tstr"
785c535eb59SGordon Tetlow				;;
786c535eb59SGordon Tetlow		MANCONFIG*)	decho "    MANCONFIG" 3
787a1528c80SRuslan Ermilov				trim "${line#MANCONFIG}"
788c535eb59SGordon Tetlow				config_local="$tstr"
789c535eb59SGordon Tetlow				;;
790c535eb59SGordon Tetlow		# Set variables in the form of FOO_BAR
791c535eb59SGordon Tetlow		*_*[\ \	]*)	var="${line%%[\ \	]*}"
792c535eb59SGordon Tetlow				trim "${line#$var}"
793c535eb59SGordon Tetlow				eval "$var=\"$tstr\""
794c535eb59SGordon Tetlow				decho "    Parsed $var" 3
795c535eb59SGordon Tetlow				;;
796c535eb59SGordon Tetlow		esac
797c535eb59SGordon Tetlow	done < "$file"
798c535eb59SGordon Tetlow}
799c535eb59SGordon Tetlow
800c535eb59SGordon Tetlow# Usage: search_path
801c535eb59SGordon Tetlow# Traverse $PATH looking for manpaths.
802c535eb59SGordon Tetlowsearch_path() {
803c535eb59SGordon Tetlow	local IFS p path
804c535eb59SGordon Tetlow
805c535eb59SGordon Tetlow	decho "Searching PATH for man directories"
806c535eb59SGordon Tetlow
807c535eb59SGordon Tetlow	IFS=:
808c535eb59SGordon Tetlow	for path in $PATH; do
809971c1c42STijl Coosemans		if add_to_manpath "$path/man"; then
810c535eb59SGordon Tetlow			:
811c535eb59SGordon Tetlow		elif add_to_manpath "$path/MAN"; then
812c535eb59SGordon Tetlow			:
813c535eb59SGordon Tetlow		else
814c535eb59SGordon Tetlow			case "$path" in
815971c1c42STijl Coosemans			*/bin)	p="${path%/bin}/share/man"
816c535eb59SGordon Tetlow				add_to_manpath "$p"
817971c1c42STijl Coosemans				p="${path%/bin}/man"
81861d5f2d1SBaptiste Daroussin				add_to_manpath "$p"
819c535eb59SGordon Tetlow				;;
820c535eb59SGordon Tetlow			esac
821c535eb59SGordon Tetlow		fi
822c535eb59SGordon Tetlow	done
823c535eb59SGordon Tetlow	unset IFS
824c535eb59SGordon Tetlow
825c535eb59SGordon Tetlow	if [ -z "$manpath" ]; then
826c535eb59SGordon Tetlow		decho '  Unable to find any manpaths, using default'
827c535eb59SGordon Tetlow		manpath=$man_default_path
828c535eb59SGordon Tetlow	fi
829c535eb59SGordon Tetlow}
830c535eb59SGordon Tetlow
831c535eb59SGordon Tetlow# Usage: search_whatis cmd [arglist]
832c535eb59SGordon Tetlow# Do the heavy lifting for apropos/whatis
833c535eb59SGordon Tetlowsearch_whatis() {
834c535eb59SGordon Tetlow	local IFS bad cmd f good key keywords loc opt out path rval wlist
835c535eb59SGordon Tetlow
836c535eb59SGordon Tetlow	cmd="$1"
837c535eb59SGordon Tetlow	shift
838c535eb59SGordon Tetlow
839c535eb59SGordon Tetlow	whatis_parse_args "$@"
840c535eb59SGordon Tetlow
841c535eb59SGordon Tetlow	build_manpath
842c535eb59SGordon Tetlow	build_manlocales
843c535eb59SGordon Tetlow	setup_pager
844c535eb59SGordon Tetlow
845c535eb59SGordon Tetlow	if [ "$cmd" = "whatis" ]; then
846c535eb59SGordon Tetlow		opt="-w"
847c535eb59SGordon Tetlow	fi
848c535eb59SGordon Tetlow
849c535eb59SGordon Tetlow	f='whatis'
850c535eb59SGordon Tetlow
851c535eb59SGordon Tetlow	IFS=:
852c535eb59SGordon Tetlow	for path in $MANPATH; do
853c535eb59SGordon Tetlow		if [ \! -d "$path" ]; then
854c535eb59SGordon Tetlow			decho "Skipping non-existent path: $path" 2
855c535eb59SGordon Tetlow			continue
856c535eb59SGordon Tetlow		fi
857c535eb59SGordon Tetlow
858c535eb59SGordon Tetlow		if [ -f "$path/$f" -a -r "$path/$f" ]; then
859c535eb59SGordon Tetlow			decho "Found whatis: $path/$f"
860c535eb59SGordon Tetlow			wlist="$wlist $path/$f"
861c535eb59SGordon Tetlow		fi
862c535eb59SGordon Tetlow
863c535eb59SGordon Tetlow		for loc in $MANLOCALES; do
864c535eb59SGordon Tetlow			if [ -f "$path/$loc/$f" -a -r "$path/$loc/$f" ]; then
865c535eb59SGordon Tetlow				decho "Found whatis: $path/$loc/$f"
866c535eb59SGordon Tetlow				wlist="$wlist $path/$loc/$f"
867c535eb59SGordon Tetlow			fi
868c535eb59SGordon Tetlow		done
869c535eb59SGordon Tetlow	done
870c535eb59SGordon Tetlow	unset IFS
871c535eb59SGordon Tetlow
872c535eb59SGordon Tetlow	if [ -z "$wlist" ]; then
873c535eb59SGordon Tetlow		echo "$cmd: no whatis databases in $MANPATH" >&2
874c535eb59SGordon Tetlow		exit 1
875c535eb59SGordon Tetlow	fi
876c535eb59SGordon Tetlow
877c535eb59SGordon Tetlow	rval=0
878c535eb59SGordon Tetlow	for key in $keywords; do
879c535eb59SGordon Tetlow		out=$(grep -Ehi $opt -- "$key" $wlist)
880c535eb59SGordon Tetlow		if [ -n "$out" ]; then
881c535eb59SGordon Tetlow			good="$good\\n$out"
882c535eb59SGordon Tetlow		else
883c535eb59SGordon Tetlow			bad="$bad\\n$key: nothing appropriate"
884c535eb59SGordon Tetlow			rval=1
885c535eb59SGordon Tetlow		fi
886c535eb59SGordon Tetlow	done
887c535eb59SGordon Tetlow
888c535eb59SGordon Tetlow	# Strip leading carriage return.
889c535eb59SGordon Tetlow	good=${good#\\n}
890c535eb59SGordon Tetlow	bad=${bad#\\n}
891c535eb59SGordon Tetlow
892c535eb59SGordon Tetlow	if [ -n "$good" ]; then
893a6a3e856SRuslan Ermilov		echo -e "$good" | $MANPAGER
894c535eb59SGordon Tetlow	fi
895c535eb59SGordon Tetlow
896c535eb59SGordon Tetlow	if [ -n "$bad" ]; then
89700e05e69SGordon Tetlow		echo -e "$bad" >&2
898c535eb59SGordon Tetlow	fi
899c535eb59SGordon Tetlow
900c535eb59SGordon Tetlow	exit $rval
901c535eb59SGordon Tetlow}
902c535eb59SGordon Tetlow
90357cd9717SGordon Tetlow# Usage: setup_cattool page
90457cd9717SGordon Tetlow# Finds an appropriate decompressor based on extension
90557cd9717SGordon Tetlowsetup_cattool() {
90657cd9717SGordon Tetlow	case "$1" in
90757cd9717SGordon Tetlow	*.bz)	cattool='/usr/bin/bzcat' ;;
90857cd9717SGordon Tetlow	*.bz2)	cattool='/usr/bin/bzcat' ;;
90957cd9717SGordon Tetlow	*.gz)	cattool='/usr/bin/zcat' ;;
91057cd9717SGordon Tetlow	*.lzma)	cattool='/usr/bin/lzcat' ;;
91157cd9717SGordon Tetlow	*.xz)	cattool='/usr/bin/xzcat' ;;
91257cd9717SGordon Tetlow	*)	cattool='/usr/bin/zcat -f' ;;
91357cd9717SGordon Tetlow	esac
91457cd9717SGordon Tetlow}
91557cd9717SGordon Tetlow
916c535eb59SGordon Tetlow# Usage: setup_pager
917a6a3e856SRuslan Ermilov# Correctly sets $MANPAGER
918c535eb59SGordon Tetlowsetup_pager() {
919c535eb59SGordon Tetlow	# Setup pager.
920a6a3e856SRuslan Ermilov	if [ -z "$MANPAGER" ]; then
921a6a3e856SRuslan Ermilov		if [ -n "$MANCOLOR" ]; then
922a6a3e856SRuslan Ermilov			MANPAGER="less -sR"
923a6a3e856SRuslan Ermilov		else
924a6a3e856SRuslan Ermilov			if [ -n "$PAGER" ]; then
925a6a3e856SRuslan Ermilov				MANPAGER="$PAGER"
926a6a3e856SRuslan Ermilov			else
92747cc9ee1SAlan Somers				MANPAGER="less -s"
928c535eb59SGordon Tetlow			fi
929a6a3e856SRuslan Ermilov		fi
930a6a3e856SRuslan Ermilov	fi
931a6a3e856SRuslan Ermilov	decho "Using pager: $MANPAGER"
932c535eb59SGordon Tetlow}
933c535eb59SGordon Tetlow
934c535eb59SGordon Tetlow# Usage: trim string
935c535eb59SGordon Tetlow# Trims whitespace from beginning and end of a variable
936c535eb59SGordon Tetlowtrim() {
937c535eb59SGordon Tetlow	tstr=$1
938c535eb59SGordon Tetlow	while true; do
939c535eb59SGordon Tetlow		case "$tstr" in
940c535eb59SGordon Tetlow		[\ \	]*)	tstr="${tstr##[\ \	]}" ;;
941c535eb59SGordon Tetlow		*[\ \	])	tstr="${tstr%%[\ \	]}" ;;
942c535eb59SGordon Tetlow		*)		break ;;
943c535eb59SGordon Tetlow		esac
944c535eb59SGordon Tetlow	done
945c535eb59SGordon Tetlow}
946c535eb59SGordon Tetlow
947c535eb59SGordon Tetlow# Usage: whatis_parse_args "$@"
948c535eb59SGordon Tetlow# Parse commandline args for whatis and apropos.
949c535eb59SGordon Tetlowwhatis_parse_args() {
950c535eb59SGordon Tetlow	local cmd_arg
951f555b39eSKyle Evans	OPTIND=1
952c535eb59SGordon Tetlow	while getopts 'd' cmd_arg; do
953c535eb59SGordon Tetlow		case "${cmd_arg}" in
954c535eb59SGordon Tetlow		d)	debug=$(( $debug + 1 )) ;;
955c535eb59SGordon Tetlow		*)	whatis_usage ;;
956c535eb59SGordon Tetlow		esac
957c535eb59SGordon Tetlow	done >&2
958c535eb59SGordon Tetlow
959c535eb59SGordon Tetlow	shift $(( $OPTIND - 1 ))
960c535eb59SGordon Tetlow
961c535eb59SGordon Tetlow	keywords="$*"
962c535eb59SGordon Tetlow}
963c535eb59SGordon Tetlow
964c535eb59SGordon Tetlow# Usage: whatis_usage
965c535eb59SGordon Tetlow# Display usage for the whatis/apropos utility.
966c535eb59SGordon Tetlowwhatis_usage() {
967c535eb59SGordon Tetlow	echo "usage: $cmd [-d] keyword [...]"
968c535eb59SGordon Tetlow	exit 1
969c535eb59SGordon Tetlow}
970c535eb59SGordon Tetlow
971c535eb59SGordon Tetlow
972c535eb59SGordon Tetlow
973c535eb59SGordon Tetlow# Supported commands
974c535eb59SGordon Tetlowdo_apropos() {
97524ef7420SBaptiste Daroussin	[ $(stat -f %i /usr/bin/man) -ne $(stat -f %i /usr/bin/apropos) ] && \
976772246efSBaptiste Daroussin		exec apropos "$@"
977c535eb59SGordon Tetlow	search_whatis apropos "$@"
978c535eb59SGordon Tetlow}
979c535eb59SGordon Tetlow
9801594084fSFernando Apesteguía# Usage: do_full_search reg_exp
9811594084fSFernando Apesteguía# Do a full search of the regular expression passed
9821594084fSFernando Apesteguía# as parameter in all man pages
9831594084fSFernando Apesteguíado_full_search() {
9841594084fSFernando Apesteguía	local gflags re
9851594084fSFernando Apesteguía	re=${1}
9861594084fSFernando Apesteguía
9871594084fSFernando Apesteguía	# Build grep(1) flags
9881594084fSFernando Apesteguía	gflags="-H"
9891594084fSFernando Apesteguía
9901594084fSFernando Apesteguía	# wflag implies -l for grep(1)
9911594084fSFernando Apesteguía	if [ -n "$wflag" ]; then
9921594084fSFernando Apesteguía		gflags="${gflags} -l"
9931594084fSFernando Apesteguía	fi
9941594084fSFernando Apesteguía
9951594084fSFernando Apesteguía	gflags="${gflags} --label"
9961594084fSFernando Apesteguía
9971594084fSFernando Apesteguía	set +f
9981594084fSFernando Apesteguía	for mpath in $(echo "${MANPATH}" | tr : [:blank:]); do
9991594084fSFernando Apesteguía		for section in $(echo "${MANSECT}" | tr : [:blank:]); do
10001594084fSFernando Apesteguía			for manfile in ${mpath}/man${section}/*.${section}*; do
10011594084fSFernando Apesteguía				mandoc "${manfile}" 2>/dev/null |
10021594084fSFernando Apesteguía					grep -E ${gflags} "${manfile}" -e ${re}
10031594084fSFernando Apesteguía			done
10041594084fSFernando Apesteguía		done
10051594084fSFernando Apesteguía	done
10061594084fSFernando Apesteguía	set -f
10071594084fSFernando Apesteguía}
10081594084fSFernando Apesteguía
1009c535eb59SGordon Tetlowdo_man() {
1010c535eb59SGordon Tetlow	man_parse_args "$@"
10111594084fSFernando Apesteguía	if [ -z "$pages" -a -z "${Kflag}" ]; then
1012c535eb59SGordon Tetlow		echo 'What manual page do you want?' >&2
1013c535eb59SGordon Tetlow		exit 1
1014c535eb59SGordon Tetlow	fi
1015c535eb59SGordon Tetlow	man_setup
1016c535eb59SGordon Tetlow
10171594084fSFernando Apesteguía	if [ ! -z "${Kflag}" ]; then
10181594084fSFernando Apesteguía		# Short circuit because -K flag does a sufficiently
10191594084fSFernando Apesteguía		# different thing like not showing the man page at all
10201594084fSFernando Apesteguía		do_full_search "${REGEXP}"
10211594084fSFernando Apesteguía	fi
10221594084fSFernando Apesteguía
1023c535eb59SGordon Tetlow	for page in $pages; do
1024c535eb59SGordon Tetlow		decho "Searching for $page"
1025c535eb59SGordon Tetlow		man_find_and_display "$page"
1026c535eb59SGordon Tetlow	done
1027c535eb59SGordon Tetlow
1028c535eb59SGordon Tetlow	exit ${ret:-0}
1029c535eb59SGordon Tetlow}
1030c535eb59SGordon Tetlow
1031c535eb59SGordon Tetlowdo_manpath() {
1032c535eb59SGordon Tetlow	manpath_parse_args "$@"
1033c535eb59SGordon Tetlow	if [ -z "$qflag" ]; then
1034c535eb59SGordon Tetlow		manpath_warnings
1035c535eb59SGordon Tetlow	fi
1036c535eb59SGordon Tetlow	if [ -n "$Lflag" ]; then
1037c535eb59SGordon Tetlow		build_manlocales
1038c535eb59SGordon Tetlow		echo $MANLOCALES
1039c535eb59SGordon Tetlow	else
1040c535eb59SGordon Tetlow		build_manpath
1041c535eb59SGordon Tetlow		echo $MANPATH
1042c535eb59SGordon Tetlow	fi
1043c535eb59SGordon Tetlow	exit 0
1044c535eb59SGordon Tetlow}
1045c535eb59SGordon Tetlow
1046c535eb59SGordon Tetlowdo_whatis() {
104724ef7420SBaptiste Daroussin	[ $(stat -f %i /usr/bin/man) -ne $(stat -f %i /usr/bin/whatis) ] && \
1048772246efSBaptiste Daroussin		exec whatis "$@"
1049c535eb59SGordon Tetlow	search_whatis whatis "$@"
1050c535eb59SGordon Tetlow}
1051c535eb59SGordon Tetlow
1052aeea395eSUlrich Spörlein# User's PATH setting decides on the groff-suite to pick up.
1053aeea395eSUlrich SpörleinEQN=eqn
1054a6a3e856SRuslan ErmilovNROFF='groff -S -P-h -Wall -mtty-char -man'
1055aeea395eSUlrich SpörleinPIC=pic
1056aeea395eSUlrich SpörleinREFER=refer
1057aeea395eSUlrich SpörleinTBL=tbl
10583d120968SUlrich SpörleinTROFF='groff -S -man'
1059aeea395eSUlrich SpörleinVGRIND=vgrind
1060aeea395eSUlrich Spörlein
1061deeff310SGordon TetlowLOCALE=/usr/bin/locale
1062a0094449SRuslan ErmilovSTTY=/bin/stty
106382db8a5eSGordon TetlowSYSCTL=/sbin/sysctl
1064c535eb59SGordon Tetlow
1065c535eb59SGordon Tetlowdebug=0
106673577bf0SRyan Moellerman_default_sections='1:8:2:3:3lua:n:4:5:6:7:9:l'
1067971c1c42STijl Coosemansman_default_path='/usr/share/man:/usr/share/openssl/man:/usr/local/share/man:/usr/local/man'
106857cd9717SGordon Tetlowcattool='/usr/bin/zcat -f'
1069c535eb59SGordon Tetlow
1070c535eb59SGordon Tetlowconfig_global='/etc/man.conf'
1071c535eb59SGordon Tetlow
1072c535eb59SGordon Tetlow# This can be overridden via a setting in /etc/man.conf.
1073c535eb59SGordon Tetlowconfig_local='/usr/local/etc/man.d/*.conf'
1074c535eb59SGordon Tetlow
1075c535eb59SGordon Tetlow# Set noglobbing for now. I don't want spurious globbing.
1076c535eb59SGordon Tetlowset -f
1077c535eb59SGordon Tetlow
1078c535eb59SGordon Tetlowcase "$0" in
1079c535eb59SGordon Tetlow*apropos)	do_apropos "$@" ;;
1080c535eb59SGordon Tetlow*manpath)	do_manpath "$@" ;;
1081c535eb59SGordon Tetlow*whatis)	do_whatis "$@" ;;
1082c535eb59SGordon Tetlow*)		do_man "$@" ;;
1083c535eb59SGordon Tetlowesac
1084