xref: /freebsd/usr.bin/man/man.sh (revision aa0a1e58)
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	# Apparently the locale flags are switched on where the manpage is
316	# found not just the locale env variables.
317	nroff_dev="ascii"
318	case "X${use_locale}X${manpage}" in
319	XyesX*/${man_lang}*${man_charset}/*)
320		# I don't pretend to know this; I'm just copying from the
321		# previous version of man(1).
322		case "$man_charset" in
323		KOI8-R)		nroff_dev="koi8-r" ;;
324		ISO8859-1)	nroff_dev="latin1" ;;
325		ISO8859-15)	nroff_dev="latin1" ;;
326		UTF-8)		nroff_dev="utf8" ;;
327		*)		nroff_dev="ascii" ;;
328		esac
329
330		NROFF="$NROFF -T$nroff_dev -dlocale=$man_lang.$man_charset"
331		EQN="$EQN -T$nroff_dev"
332
333		# Allow language specific calls to override the default
334		# set of utilities.
335		l=$(echo $man_lang | tr [:lower:] [:upper:])
336		for tool in EQN COL NROFF PIC TBL TROFF REFER VGRIND; do
337			eval "$tool=\${${tool}_$l:-\$$tool}"
338		done
339		;;
340	*)	NROFF="$NROFF -Tascii"
341		EQN="$EQN -Tascii"
342		;;
343	esac
344
345	if [ -n "$MANROFFSEQ" ]; then
346		set -- -$MANROFFSEQ
347		while getopts 'egprtv' preproc_arg; do
348			case "${preproc_arg}" in
349			e)	pipeline="$pipeline | $EQN" ;;
350			g)	;; # Ignore for compatability.
351			p)	pipeline="$pipeline | $PIC" ;;
352			r)	pipeline="$pipeline | $REFER" ;;
353			t)	pipeline="$pipeline | $TBL"; use_col=yes ;;
354			v)	pipeline="$pipeline | $VGRIND" ;;
355			*)	usage ;;
356			esac
357		done
358		# Strip the leading " | " from the resulting pipeline.
359		pipeline="${pipeline#" | "}"
360	else
361		pipeline="$TBL"
362		use_col=yes
363	fi
364
365	if [ -n "$tflag" ]; then
366		pipeline="$pipeline | $TROFF"
367	else
368		pipeline="$pipeline | $NROFF"
369
370		if [ -n "$use_col" ]; then
371			pipeline="$pipeline | $COL"
372		fi
373
374		pipeline="$pipeline | $PAGER"
375	fi
376
377	if [ $debug -gt 0 ]; then
378		decho "Command: $cattool $manpage | $pipeline"
379		ret=0
380	else
381		eval "$cattool $manpage | $pipeline"
382		ret=$?
383	fi
384}
385
386# Usage: man_find_and_display page
387# Search through the manpaths looking for the given page.
388man_find_and_display() {
389	local found_page locpath p path sect
390
391	# Check to see if it's a file. But only if it has a '/' in
392	# the filename.
393	case "$1" in
394	*/*)	if [ -f "$1" -a -r "$1" ]; then
395			decho "Found a usable page, displaying that"
396			unset use_cat
397			manpage="$1"
398			setup_cattool $manpage
399			if man_check_for_so $manpage $(dirname $manpage); then
400				found_page=yes
401				man_display_page
402			fi
403			return
404		fi
405		;;
406	esac
407
408	IFS=:
409	for sect in $MANSECT; do
410		decho "Searching section $sect" 2
411		for path in $MANPATH; do
412			for locpath in $locpaths; do
413				p=$path/$locpath
414				p=${p%/.} # Rid ourselves of the trailing /.
415
416				# Check if there is a MACHINE specific manpath.
417				if find_file $p $sect $MACHINE "$1"; then
418					if man_check_for_so $manpage $p; then
419						found_page=yes
420						man_display_page
421						if [ -n "$aflag" ]; then
422							continue 2
423						else
424							return
425						fi
426					fi
427				fi
428
429				# Check if there is a MACHINE_ARCH
430				# specific manpath.
431				if find_file $p $sect $MACHINE_ARCH "$1"; then
432					if man_check_for_so $manpage $p; then
433						found_page=yes
434						man_display_page
435						if [ -n "$aflag" ]; then
436							continue 2
437						else
438							return
439						fi
440					fi
441				fi
442
443				# Check plain old manpath.
444				if find_file $p $sect '' "$1"; then
445					if man_check_for_so $manpage $p; then
446						found_page=yes
447						man_display_page
448						if [ -n "$aflag" ]; then
449							continue 2
450						else
451							return
452						fi
453					fi
454				fi
455			done
456		done
457	done
458	unset IFS
459
460	# Nothing? Well, we are done then.
461	if [ -z "$found_page" ]; then
462		echo "No manual entry for $1" >&2
463		ret=1
464		return
465	fi
466}
467
468# Usage: man_parse_args "$@"
469# Parses commandline options for man.
470man_parse_args() {
471	local IFS cmd_arg
472
473	while getopts 'M:P:S:adfhkm:op:tw' cmd_arg; do
474		case "${cmd_arg}" in
475		M)	MANPATH=$OPTARG ;;
476		P)	PAGER=$OPTARG ;;
477		S)	MANSECT=$OPTARG ;;
478		a)	aflag=aflag ;;
479		d)	debug=$(( $debug + 1 )) ;;
480		f)	fflag=fflag ;;
481		h)	man_usage 0 ;;
482		k)	kflag=kflag ;;
483		m)	mflag=$OPTARG ;;
484		o)	oflag=oflag ;;
485		p)	MANROFFSEQ=$OPTARG ;;
486		t)	tflag=tflag ;;
487		w)	wflag=wflag ;;
488		*)	man_usage ;;
489		esac
490	done >&2
491
492	shift $(( $OPTIND - 1 ))
493
494	# Check the args for incompatible options.
495	case "${fflag}${kflag}${tflag}${wflag}" in
496	fflagkflag*)	echo "Incompatible options: -f and -k"; man_usage ;;
497	fflag*tflag*)	echo "Incompatible options: -f and -t"; man_usage ;;
498	fflag*wflag)	echo "Incompatible options: -f and -w"; man_usage ;;
499	*kflagtflag*)	echo "Incompatible options: -k and -t"; man_usage ;;
500	*kflag*wflag)	echo "Incompatible options: -k and -w"; man_usage ;;
501	*tflagwflag)	echo "Incompatible options: -t and -w"; man_usage ;;
502	esac
503
504	# Short circuit for whatis(1) and apropos(1)
505	if [ -n "$fflag" ]; then
506		do_whatis "$@"
507		exit
508	fi
509
510	if [ -n "$kflag" ]; then
511		do_apropos "$@"
512		exit
513	fi
514
515	IFS=:
516	for sect in $man_default_sections; do
517		if [ "$sect" = "$1" ]; then
518			decho "Detected manual section as first arg: $1"
519			MANSECT="$1"
520			shift
521			break
522		fi
523	done
524	unset IFS
525
526	pages="$*"
527}
528
529# Usage: man_setup
530# Setup various trivial but essential variables.
531man_setup() {
532	# Setup machine and architecture variables.
533	if [ -n "$mflag" ]; then
534		MACHINE_ARCH=${mflag%%:*}
535		MACHINE=${mflag##*:}
536	fi
537	if [ -z "$MACHINE_ARCH" ]; then
538		MACHINE_ARCH=$($SYSCTL -n hw.machine_arch)
539	fi
540	if [ -z "$MACHINE" ]; then
541		MACHINE=$($SYSCTL -n hw.machine)
542	fi
543	decho "Using architecture: $MACHINE_ARCH:$MACHINE"
544
545	setup_pager
546
547	# Setup manual sections to search.
548	if [ -z "$MANSECT" ]; then
549		MANSECT=$man_default_sections
550	fi
551	decho "Using manual sections: $MANSECT"
552
553	build_manpath
554	man_setup_locale
555}
556
557# Usage: man_setup_locale
558# Setup necessary locale variables.
559man_setup_locale() {
560	# Setup locale information.
561	if [ -n "$oflag" ]; then
562		decho "Using non-localized manpages"
563		unset use_locale
564	elif [ -n "$LC_ALL" ]; then
565		parse_locale "$LC_ALL"
566	elif [ -n "$LC_CTYPE" ]; then
567		parse_locale "$LC_CTYPE"
568	elif [ -n "$LANG" ]; then
569		parse_locale "$LANG"
570	fi
571
572	if [ -n "$use_locale" ]; then
573		locpaths="${man_lang}_${man_country}.${man_charset}"
574		locpaths="$locpaths:$man_lang.$man_charset"
575		if [ "$man_lang" != "en" ]; then
576			locpaths="$locpaths:en.$man_charset"
577		fi
578		locpaths="$locpaths:."
579	else
580		locpaths="."
581	fi
582	decho "Using locale paths: $locpaths"
583}
584
585# Usage: man_usage [exitcode]
586# Display usage for the man utility.
587man_usage() {
588	echo 'Usage:'
589	echo ' man [-adho] [-t | -w] [-M manpath] [-P pager] [-S mansect]'
590	echo '     [-m arch[:machine]] [-p [eprtv]] [mansect] page [...]'
591	echo ' man -f page [...] -- Emulates whatis(1)'
592	echo ' man -k page [...] -- Emulates apropos(1)'
593
594	# When exit'ing with -h, it's not an error.
595	exit ${1:-1}
596}
597
598# Usage: parse_configs
599# Reads the end-user adjustable config files.
600parse_configs() {
601	local IFS file files
602
603	if [ -n "$parsed_configs" ]; then
604		return
605	fi
606
607	unset IFS
608
609	# Read the global config first in case the user wants
610	# to override config_local.
611	if [ -r "$config_global" ]; then
612		parse_file "$config_global"
613	fi
614
615	# Glob the list of files to parse.
616	set +f
617	files=$(echo $config_local)
618	set -f
619
620	for file in $files; do
621		if [ -r "$file" ]; then
622			parse_file "$file"
623		fi
624	done
625
626	parsed_configs='yes'
627}
628
629# Usage: parse_file file
630# Reads the specified config files.
631parse_file() {
632	local file line tstr var
633
634	file="$1"
635	decho "Parsing config file: $file"
636	while read line; do
637		decho "  $line" 2
638		case "$line" in
639		\#*)		decho "    Comment" 3
640				;;
641		MANPATH*)	decho "    MANPATH" 3
642				trim "${line#MANPATH}"
643				add_to_manpath "$tstr"
644				;;
645		MANLOCALE*)	decho "    MANLOCALE" 3
646				trim "${line#MANLOCALE}"
647				manlocales="$manlocales:$tstr"
648				;;
649		MANCONFIG*)	decho "    MANCONFIG" 3
650				trim "${line#MANCONF}"
651				config_local="$tstr"
652				;;
653		# Set variables in the form of FOO_BAR
654		*_*[\ \	]*)	var="${line%%[\ \	]*}"
655				trim "${line#$var}"
656				eval "$var=\"$tstr\""
657				decho "    Parsed $var" 3
658				;;
659		esac
660	done < "$file"
661}
662
663# Usage: parse_locale localestring
664# Setup locale variables for proper parsing.
665parse_locale() {
666	local lang_cc
667
668	case "$1" in
669	C)				;;
670	POSIX)				;;
671	[a-z][a-z]_[A-Z][A-Z]\.*)	lang_cc="${1%.*}"
672					man_lang="${1%_*}"
673					man_country="${lang_cc#*_}"
674					man_charset="${1#*.}"
675					use_locale=yes
676					return 0
677					;;
678	*)				echo 'Unknown locale, assuming C' >&2
679					;;
680	esac
681
682	unset use_locale
683}
684
685# Usage: search_path
686# Traverse $PATH looking for manpaths.
687search_path() {
688	local IFS p path
689
690	decho "Searching PATH for man directories"
691
692	IFS=:
693	for path in $PATH; do
694		# Do a little special casing since the base manpages
695		# are in /usr/share/man instead of /usr/man or /man.
696		case "$path" in
697		/bin|/usr/bin)	add_to_manpath "/usr/share/man" ;;
698		*)	if add_to_manpath "$path/man"; then
699				:
700			elif add_to_manpath "$path/MAN"; then
701				:
702			else
703				case "$path" in
704				*/bin)	p="${path%/bin}/man"
705					add_to_manpath "$p"
706					;;
707				*)	;;
708				esac
709			fi
710			;;
711		esac
712	done
713	unset IFS
714
715	if [ -z "$manpath" ]; then
716		decho '  Unable to find any manpaths, using default'
717		manpath=$man_default_path
718	fi
719}
720
721# Usage: search_whatis cmd [arglist]
722# Do the heavy lifting for apropos/whatis
723search_whatis() {
724	local IFS bad cmd f good key keywords loc opt out path rval wlist
725
726	cmd="$1"
727	shift
728
729	whatis_parse_args "$@"
730
731	build_manpath
732	build_manlocales
733	setup_pager
734
735	if [ "$cmd" = "whatis" ]; then
736		opt="-w"
737	fi
738
739	f='whatis'
740
741	IFS=:
742	for path in $MANPATH; do
743		if [ \! -d "$path" ]; then
744			decho "Skipping non-existent path: $path" 2
745			continue
746		fi
747
748		if [ -f "$path/$f" -a -r "$path/$f" ]; then
749			decho "Found whatis: $path/$f"
750			wlist="$wlist $path/$f"
751		fi
752
753		for loc in $MANLOCALES; do
754			if [ -f "$path/$loc/$f" -a -r "$path/$loc/$f" ]; then
755				decho "Found whatis: $path/$loc/$f"
756				wlist="$wlist $path/$loc/$f"
757			fi
758		done
759	done
760	unset IFS
761
762	if [ -z "$wlist" ]; then
763		echo "$cmd: no whatis databases in $MANPATH" >&2
764		exit 1
765	fi
766
767	rval=0
768	for key in $keywords; do
769		out=$(grep -Ehi $opt -- "$key" $wlist)
770		if [ -n "$out" ]; then
771			good="$good\\n$out"
772		else
773			bad="$bad\\n$key: nothing appropriate"
774			rval=1
775		fi
776	done
777
778	# Strip leading carriage return.
779	good=${good#\\n}
780	bad=${bad#\\n}
781
782	if [ -n "$good" ]; then
783		echo -e "$good" | $PAGER
784	fi
785
786	if [ -n "$bad" ]; then
787		echo -e "$bad" >&2
788	fi
789
790	exit $rval
791}
792
793# Usage: setup_cattool page
794# Finds an appropriate decompressor based on extension
795setup_cattool() {
796	case "$1" in
797	*.bz)	cattool='/usr/bin/bzcat' ;;
798	*.bz2)	cattool='/usr/bin/bzcat' ;;
799	*.gz)	cattool='/usr/bin/zcat' ;;
800	*.lzma)	cattool='/usr/bin/lzcat' ;;
801	*.xz)	cattool='/usr/bin/xzcat' ;;
802	*)	cattool='/usr/bin/zcat -f' ;;
803	esac
804}
805
806# Usage: setup_pager
807# Correctly sets $PAGER
808setup_pager() {
809	# Setup pager.
810	if [ -z "$PAGER" ]; then
811		PAGER="more -s"
812	fi
813	decho "Using pager: $PAGER"
814}
815
816# Usage: trim string
817# Trims whitespace from beginning and end of a variable
818trim() {
819	tstr=$1
820	while true; do
821		case "$tstr" in
822		[\ \	]*)	tstr="${tstr##[\ \	]}" ;;
823		*[\ \	])	tstr="${tstr%%[\ \	]}" ;;
824		*)		break ;;
825		esac
826	done
827}
828
829# Usage: whatis_parse_args "$@"
830# Parse commandline args for whatis and apropos.
831whatis_parse_args() {
832	local cmd_arg
833	while getopts 'd' cmd_arg; do
834		case "${cmd_arg}" in
835		d)	debug=$(( $debug + 1 )) ;;
836		*)	whatis_usage ;;
837		esac
838	done >&2
839
840	shift $(( $OPTIND - 1 ))
841
842	keywords="$*"
843}
844
845# Usage: whatis_usage
846# Display usage for the whatis/apropos utility.
847whatis_usage() {
848	echo "usage: $cmd [-d] keyword [...]"
849	exit 1
850}
851
852
853
854# Supported commands
855do_apropos() {
856	search_whatis apropos "$@"
857}
858
859do_man() {
860	man_parse_args "$@"
861	if [ -z "$pages" ]; then
862		echo 'What manual page do you want?' >&2
863		exit 1
864	fi
865	man_setup
866
867	for page in $pages; do
868		decho "Searching for $page"
869		man_find_and_display "$page"
870	done
871
872	exit ${ret:-0}
873}
874
875do_manpath() {
876	manpath_parse_args "$@"
877	if [ -z "$qflag" ]; then
878		manpath_warnings
879	fi
880	if [ -n "$Lflag" ]; then
881		build_manlocales
882		echo $MANLOCALES
883	else
884		build_manpath
885		echo $MANPATH
886	fi
887	exit 0
888}
889
890do_whatis() {
891	search_whatis whatis "$@"
892}
893
894EQN=/usr/bin/eqn
895COL=/usr/bin/col
896NROFF='/usr/bin/groff -S -Wall -mtty-char -man'
897PIC=/usr/bin/pic
898SYSCTL=/sbin/sysctl
899TBL=/usr/bin/tbl
900TROFF='/usr/bin/groff -S -man'
901REFER=/usr/bin/refer
902VGRIND=/usr/bin/vgrind
903
904debug=0
905man_default_sections='1:1aout:8:2:3:n:4:5:6:7:9:l'
906man_default_path='/usr/share/man:/usr/share/openssl/man:/usr/local/man'
907cattool='/usr/bin/zcat -f'
908
909config_global='/etc/man.conf'
910
911# This can be overridden via a setting in /etc/man.conf.
912config_local='/usr/local/etc/man.d/*.conf'
913
914# Set noglobbing for now. I don't want spurious globbing.
915set -f
916
917case "$0" in
918*apropos)	do_apropos "$@" ;;
919*manpath)	do_manpath "$@" ;;
920*whatis)	do_whatis "$@" ;;
921*)		do_man "$@" ;;
922esac
923