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