diff options
author | gordon <gordon@FreeBSD.org> | 2010-10-01 03:59:18 +0000 |
---|---|---|
committer | gordon <gordon@FreeBSD.org> | 2010-10-01 03:59:18 +0000 |
commit | bca578aa589a604cbcbbcd06f44a9ad7ee03b217 (patch) | |
tree | 708bd168c141804478d45bfa4d42255e64db3b50 /usr.bin/man | |
parent | 170a247ca87cf9b0fa48d0e07f9d51fa2c404900 (diff) | |
download | FreeBSD-src-bca578aa589a604cbcbbcd06f44a9ad7ee03b217.zip FreeBSD-src-bca578aa589a604cbcbbcd06f44a9ad7ee03b217.tar.gz |
Implementaiton of man, manpath, whatis, and apropos written entirely in sh.
Features of this new version in favor of the old one:
BSD licensed -- old one is GPL.
Imports configuration from /etc/man.conf and LOCALBASE/etc/man.d/*.conf
allowing ports to extend the base functionality. The pluggable
configuration can supplement the manual search path (retiring use.perl),
add locales, and override language specific toolsets (attempt to merge
the japanese/man port into the base system as much as possible).
Much effort has been made to make this version mirror the functionality
of the existing implementation. For 99% of users, it should be a drop in
replacement.
PR: gnu/143271, gnu/4419
Reviewed by: dougb (previous versions)
Approved by: wes (mentor)
Diffstat (limited to 'usr.bin/man')
-rw-r--r-- | usr.bin/man/Makefile | 11 | ||||
-rw-r--r-- | usr.bin/man/apropos.1 | 88 | ||||
-rw-r--r-- | usr.bin/man/man.1 | 299 | ||||
-rw-r--r-- | usr.bin/man/man.conf.5 | 142 | ||||
-rwxr-xr-x | usr.bin/man/man.sh | 847 | ||||
-rw-r--r-- | usr.bin/man/manpath.1 | 123 |
6 files changed, 1510 insertions, 0 deletions
diff --git a/usr.bin/man/Makefile b/usr.bin/man/Makefile new file mode 100644 index 0000000..3e37b59 --- /dev/null +++ b/usr.bin/man/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +SCRIPTS= man.sh +LINKS= ${BINDIR}/man ${BINDIR}/apropos \ + ${BINDIR}/man ${BINDIR}/manpath \ + ${BINDIR}/man ${BINDIR}/whatis + +MAN= man.1 manpath.1 apropos.1 man.conf.5 +MLINKS= apropos.1 whatis.1 + +.include <bsd.prog.mk> diff --git a/usr.bin/man/apropos.1 b/usr.bin/man/apropos.1 new file mode 100644 index 0000000..4b79ada --- /dev/null +++ b/usr.bin/man/apropos.1 @@ -0,0 +1,88 @@ +.\"- +.\" Copyright (c) 2010 Gordon Tetlow +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd September 1, 2010 +.Dt APROPOS 1 +.Os +.Sh NAME +.Nm apropos , +.Nm whatis +.Nd keyword search whatis documentation databases +.Sh SYNOPSIS +.Nm +.Op Fl d +.Ar keyword ... +.Nm whatis +.Op Fl d +.Ar keyword ... +.Sh DESCRIPTION +The +.Nm +utility searches a set of databases looking for documentation matching each +.Ar keyword +and displays the results. +The +.Nm whatis +utility does the same search but only on complete words. +.Bl -tag -width ".Fl d" +.It Fl d +Print extra debugging information. +.El +.Pp +The +.Ar keyword +is simply passed to +.Xr grep 1 +allowing for extended regular expression matches. +.Sh ENVIRONMENT +The following environment variables affect the execution of +.Nm : +.Bl -tag -width ".Ev PAGER" +.It Ev MANLOCALES , MANPATH , PATH +Used to find the location of the +.Nm whatis +database files. See +.Xr manpath 1 +for additional information. +.It Ev PAGER +Program used to display files. +If unset, +.Ic "more -s" +is used. +.El +.Sh DIAGNOSTICS +The +.Nm +utility exits 0 if a keyword matched and 1 if no keywords are matched or no +.Nm whatis +databases are found. +.Sh SEE ALSO +.Xr grep 1 , +.Xr makewhatis 1 , +.Xr man 1 , +.Xr manpath 1 , +.Xr man.conf 5 diff --git a/usr.bin/man/man.1 b/usr.bin/man/man.1 new file mode 100644 index 0000000..751ea46 --- /dev/null +++ b/usr.bin/man/man.1 @@ -0,0 +1,299 @@ +.\"- +.\" Copyright (c) 2010 Gordon Tetlow +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd September 1, 2010 +.Dt MAN 1 +.Os +.Sh NAME +.Nm man +.Nd display online manual documentation pages +.Sh SYNOPSIS +.Nm +.Op Fl adho +.Op Fl t | Fl w +.Op Fl M Ar manpath +.Op Fl P Ar pager +.Op Fl S Ar mansect +.Op Fl m Ar arch Ns Op : Ns Ar machine +.Op Fl p Op Ar eprtv +.Op Ar mansect +.Ar page ... +.Nm +.Fl f +.Ar keyword ... +.Nm +.Fl k +.Ar keyword ... +.Sh DESCRIPTION +The +.Nm +utility finds and displays online manual documentation pages. +If +.Ar mansect +is provided, +.Nm +restricts the search to the specific section of the manual. +.Pp +Options that +.Nm +understands: +.Bl -tag -width indent +.It Fl M Ar manpath +Forces a specific colon separated manual path instead of the default +search path. +See +.Xr manpath 1 . +Overrides the +.Ev MANPATH +environment variable. +.It Fl P Ar pager +Use specified pager. +Defaults to +.Ic "more -s" . +Overrides the +.Ev PAGER +environment variable. +.It Fl S Ar mansect +Restricts manual sections searched to the specified colon delimited list. +Defaults to +.Va 1:1aout:8:2:3:n:4:5:6:7:9:l . +Overrides the +.Ev MANSECT +environment variable. +.It Fl a +Display all manual pages instead of just the first found for each +.Ar page +argument. +.It Fl d +Print extra debugging information. +Repeat for increased verbosity. +Does not display the manual page. +.It Fl f +Emulate +.Xr whatis 1 . +.It Fl h +Display short help message and exit. +.It Fl k +Emulate +.Xr apropos 1 . +.It Fl m Ar arch Ns Op : Ns Ar machine +Override the default architecture and machine settings allowing lookup of +other platform specific manual pages. +See +.Sx IMPLEMENTATION NOTES +for how this option changes the default behavior. +Overrides the +.Ev MACHINE_ARCH +and +.Ev MACHINE +environment variables. +.It Fl o +Force use of non-localized manual pages. +See +.Sx IMPLEMENTATION NOTES +for how locale specific searches work. +Overrides the +.Ev LC_ALL , LC_CTYPE , +and +.Ev LANG +environment variables. +.It Fl p Op Ar eprtv +Use the list of given preprocessors before running +.Xr nroff 1 +or +.Xr troff 1 . +Valid preprocessors arguments: +.Bl -tag -width indent -compact +.It Cm e +.Xr eqn 1 +.It Cm p +.Xr pic 1 +.It Cm r +.Xr refer 1 +.It Cm t +.Xr tbl 1 +.It Cm v +.Xr vgrind 1 +.El +Overrides the +.Ev MANROFFSEQ +environment variable. +.It Fl t +Send manual page source through +.Xr troff 1 +allowing transformation of the manual pages to other formats. +.It Fl w +Display the location of the manual page instead of the contents of +the manual page. +.El +.Sh IMPLEMENTATION NOTES +.Ss Locale Specific Searches +The +.Nm +utility supports manual pages in different locales. +The search behavior is dictated by the first of three +environment variables with a nonempty string: +.Ev LC_ALL , +.Ev LC_CTYPE , +or +.Ev LANG . +If set, +.Nm +will search for locale specific manual pages using the following logic: +.Bl -item -compact -offset indent +.Sm off +.It +.Va lang _ +.Va country . +.Va charset +.It +.Va lang . +.Va charset +.It +.Li en . +.Va charset +.Sm on +.El +For example, if +.Ev LC_ALL +is set to +.Va ja_JP.eucJP , +.Nm +will search the following paths when considering section 1 manual pages in +.Pa /usr/share/man : +.Bl -item -compact -offset indent +.It +.Pa /usr/share/man/ja_JP.eucJP/man1 +.It +.Pa /usr/share/man/ja.eucJP/man1 +.It +.Pa /usr/share/man/en.eucJP/man1 +.It +.Pa /usr/share/man/man1 +.El +.Ss Platform Specific Searches +The +.Nm +utility supports platform specific manual pages. +The search behavior is dictated by the +.Fl m +option or the +.Ev MACHINE_ARCH +and +.Ev MACHINE +environment variables. +For example, if +.Ev MACHINE_ARCH +is set to +.Va i386 +and +.Ev MACHINE +is set to +.Va pc98 , +.Nm +will search the following paths when considering section 4 manual pages in +.Pa /usr/share/man : +.Bl -item -compact -offset indent +.It +.Pa /usr/share/man/man4/pc98 +.It +.Pa /usr/share/man/man4/i386 +.It +.Pa /usr/share/man/man4 +.El +.Sh ENVIRONMENT +The following environment variables affect the execution of +.Nm : +.Bl -tag -width ".Ev MANPATH" +.It Ev LC_ALL , LC_CTYPE , LANG +Used to find locale specific manual pages. +Valid values can be found by running the +.Xr locale 1 +command. +See +.Sx IMPLEMENTATION NOTES +for details. +Influenced by the +.Fl o +option. +.It Ev MACHINE_ARCH , MACHINE +Used to find platform specific manual pages. +If unset, the output of +.Ic "sysctl hw.machine_arch" +and +.Ic "sysctl hw.machine" +is used respectively. +See +.Sx IMPLEMENTATION NOTES +for details. +Corresponds to the +.Fl m +option. +.It Ev MANPATH +Used to find the location of the manual files. +See +.Xr manpath 1 +for additional information. +Corresponds to the +.Fl M +option. +.It Ev MANROFFSEQ +Used to determine the preprocessors for the manual source before running +.Xr nroff 1 +or +.Xr troff 1 . +If unset, defaults to +.Xr tbl 1 . +Corresponds to the +.Fl p +option. +.It Ev MANSECT +Restricts manual sections searched to the specified colon delimited list. +Corresponds to the +.Fl S +option. +.It Ev PAGER +Program used to display files. +If unset, +.Ic "more -s" +is used. +.El +.Sh FILES +.Bl -tag -width indent -compact +.It Pa /etc/man.conf +System configuration file. +.It Pa /usr/local/etc/man.d/*.conf +Local configuration files. +.El +.Sh SEE ALSO +.Xr apropos 1 , +.Xr locale 1 , +.Xr manpath 1 , +.Xr man.conf 5 , +.Xr nroff 1 , +.Xr troff 1 , +.Xr whatis 1 diff --git a/usr.bin/man/man.conf.5 b/usr.bin/man/man.conf.5 new file mode 100644 index 0000000..6326bc1 --- /dev/null +++ b/usr.bin/man/man.conf.5 @@ -0,0 +1,142 @@ +.\"- +.\" Copyright (c) 2010 Gordon Tetlow +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd September 1, 2010 +.Os +.Dt MAN.CONF 5 +.Sh NAME +.Nm man.conf +.Nd +.Xr man 1 +and +.Xr manpath 1 +configuration files +.Sh DESCRIPTION +The +.Nm +file is used to configure the manual search path, locales, and utility set for +.Xr man 1 +and its related utilities. +During initialization, +.Xr man 1 +reads the configuration files located at +.Pa /usr/local/etc/man.d/*.conf +and +.Pa /etc/man.conf . +.Pp +The files contained in +.Pa /usr/local/etc/man.d/*.conf +are intended to be used by the +.Xr ports 7 +system for extending the manual set to support additional paths and locales. +.Pa /etc/man.conf +is intended to be used by the local administrator to set additional policy. +.Pp +Currently supported configuration variables include: +.Bl -tag -offset indent +.It MANCONFIG +Overrides the default location to import additional manual configuration files. +Defaults to +.Pa /usr/local/etc/man.d/*.conf . +.It MANPATH +Adds the specified directory to the manual search path. +.It MANLOCALE +Indicates support is available for the given locale. +.El +.Pp +For pages in a given language, overriding the default toolset for +display is supported via the following definitions: +.Bl -tag -offset indent -compact +.It EQN Ns _ Ns Va LANG +.It COL Ns _ Ns Va LANG +.It NROFF Ns _ Ns Va LANG +.It PIC Ns _ Ns Va LANG +.It TBL Ns _ Ns Va LANG +.It TROFF Ns _ Ns Va LANG +.It REFER Ns _ Ns Va LANG +.It VGRIND Ns _ Ns Va LANG +.El +.Pp +See the +.Sx EXAMPLES +section for how to use these variables. +.Sh IMPLEMENTATION NOTES +The parser used for this utility is very basic and only supports comment +characters (#) at the beginning of a line. +.Sh FILES +.Bl -tag -compact +.It Pa /etc/man.conf +System configuration file. +.It Pa /usr/local/etc/man.d/*.conf +Local configuration files. +.El +.Sh EXAMPLES +A perl port that needs to install additional manual pages outside of the +default location could install a file in +.Pa /usr/local/etc/man.d/perl.conf +with the following contents: +.Bd -literal -offset indent +# Add perl man pages to search path +MANPATH /usr/local/lib/perl5/5.8.9/man +MANPATH /usr/local/lib/perl5/5.8.9/perl/man +.Ed +.Pp +A Japanese localization port could install a custom toolset and include a +file in +.Pa /usr/local/etc/man.d/ja-man-doc.conf +with the following contents: +.Bd -literal -offset indent +# Setup Japanese toolset +MANLOCALE ja_JP.eucJP +EQN_JA /usr/local/bin/gepn +PIC_JA /usr/local/bin/gpic +TBL_JA /usr/local/bin/gtbl +NROFF_JA /usr/local/bin/groff -man -dlang=ja_JP.eucJP +TROFF_JA /usr/local/bin/groff -man -dlang=ja_JP.euc.jp +.Ed +.Pp +If the system administrator decides to override the +.Va LOCALBASE +.Xr make 1 +variable causing all +.Xr ports 7 +to be installed into +.Pa /opt +instead of +.Pa /usr/local , +specifying the following in +.Pa /etc/man.conf +will accommodate this change: +.Bd -literal -offset indent +# Look for additional configuration files +MANCONFIG /opt/etc/man.d/*.conf +.Ed +.Sh SEE ALSO +.Xr apropos 1 , +.Xr man 1 , +.Xr manpath 1 , +.Xr whatis 1 diff --git a/usr.bin/man/man.sh b/usr.bin/man/man.sh new file mode 100755 index 0000000..f8da4da --- /dev/null +++ b/usr.bin/man/man.sh @@ -0,0 +1,847 @@ +#! /bin/sh +# +# Copyright (c) 2010 Gordon Tetlow +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ + +# Usage: add_to_manpath path +# Adds a variable to manpath while ensuring we don't have duplicates. +# Returns true if we were able to add something. False otherwise. +add_to_manpath() { + case "$manpath" in + *:$1) decho " Skipping duplicate manpath entry $1" 2 ;; + $1:*) decho " Skipping duplicate manpath entry $1" 2 ;; + *:$1:*) decho " Skipping duplicate manpath entry $1" 2 ;; + *) if [ -d "$1" ]; then + decho " Adding $1 to manpath" + manpath="$manpath:$1" + return 0 + fi + ;; + esac + + return 1 +} + +# Usage: build_manlocales +# Builds a correct MANLOCALES variable. +build_manlocales() { + # If the user has set manlocales, who are we to argue. + if [ -n "$MANLOCALES" ]; then + return + fi + + parse_configs + + # Trim leading colon + MANLOCALES=${manlocales#:} + + decho "Available manual locales: $MANLOCALES" +} + +# Usage: build_manpath +# Builds a correct MANPATH variable. +build_manpath() { + local IFS + + # If the user has set a manpath, who are we to argue. + if [ -n "$MANPATH" ]; then + return + fi + + search_path + + decho "Adding default manpath entries" + IFS=: + for path in $man_default_path; do + add_to_manpath "$path" + done + unset IFS + + parse_configs + + # Trim leading colon + MANPATH=${manpath#:} + + decho "Using manual path: $MANPATH" +} + +# Usage: check_cat catglob +# Checks to see if a cat glob is available. +check_cat() { + if exists "$1"; then + use_cat=yes + catpage=$found + decho " Found catpage $catpage" + return 0 + else + return 1 + fi +} + +# Usage: check_man manglob catglob +# Given 2 globs, figures out if the manglob is available, if so, check to +# see if the catglob is also available and up to date. +check_man() { + if exists "$1"; then + # We have a match, check for a cat page + manpage=$found + decho " Found manpage $manpage" + + if exists "$2" && is_newer $found $manpage; then + # cat page found and is newer, use that + use_cat=yes + catpage=$found + decho " Using catpage $catpage" + else + # no cat page or is older + unset use_cat + decho " Skipping catpage: not found or old" + fi + return 0 + fi + + return 1 +} + +# Usage: decho "string" [debuglevel] +# Echoes to stderr string prefaced with -- if high enough debuglevel. +decho() { + if [ $debug -ge ${2:-1} ]; then + echo "-- $1" >&2 + fi +} + +# Usage: exists glob +# Returns true if glob resolves to a real file. +exists() { + local IFS + + # Don't accidentally inherit callers IFS (breaks perl manpages) + unset IFS + + # Use some globbing tricks in the shell to determine if a file + # exists or not. + set +f + set -- "$1" $1 + set -f + + if [ "$1" != "$2" -a -r "$2" ]; then + found="$2" + return 0 + fi + + return 1 +} + +# Usage: find_file path section subdir pagename +# Returns: true if something is matched and found. +# Search the given path/section combo for a given page. +find_file() { + local manroot catroot mann man0 catn cat0 + + manroot="$1/man$2" + catroot="$1/cat$2" + if [ -n "$3" ]; then + manroot="$manroot/$3" + catroot="$catroot/$3" + fi + + if [ ! -d "$manroot" ]; then + return 1 + fi + decho " Searching directory $manroot" 2 + + mann="$manroot/$4.$2*" + man0="$manroot/$4.0*" + catn="$catroot/$4.$2*" + cat0="$catroot/$4.0*" + + # This is the behavior as seen by the original man utility. + # Let's not change that which doesn't seem broken. + if check_man "$mann" "$catn"; then + return 0 + elif check_man "$man0" "$cat0"; then + return 0 + elif check_cat "$catn"; then + return 0 + elif check_cat "$cat0"; then + return 0 + fi + + return 1 +} + +# Usage: is_newer file1 file2 +# Returns true if file1 is newer than file2 as calculated by mtime. +is_newer() { + if [ $(stat -f %m $1) -gt $(stat -f %m $2) ]; then + decho " mtime: $1 newer than $2" 3 + return 0 + else + decho " mtime: $1 older than $2" 3 + return 1 + fi +} + +# Usage: manpath_parse_args "$@" +# Parses commandline options for manpath. +manpath_parse_args() { + local cmd_arg + + while getopts 'Ldq' cmd_arg; do + case "${cmd_arg}" in + L) Lflag=Lflag ;; + d) debug=$(( $debug + 1 )) ;; + q) qflag=qflag ;; + *) manpath_usage ;; + esac + done >&2 +} + +# Usage: manpath_usage +# Display usage for the manpath(1) utility. +manpath_usage() { + echo 'usage: manpath [-Ldq]' >&2 + exit 1 +} + +# Usage: manpath_warnings +# Display some warnings to stderr. +manpath_warnings() { + if [ -z "$Lflag" -a -n "$MANPATH" ]; then + echo "(Warning: MANPATH environment variable set)" >&2 + fi + + if [ -n "$Lflag" -a -n "$MANLOCALES" ]; then + echo "(Warning: MANLOCALES environment variable set)" >&2 + fi +} + +# Usage: man_display_page +# Display either the manpage or catpage depending on the use_cat variable +man_display_page() { + local EQN COL NROFF PIC TBL TROFF REFER VGRIND + local IFS l nroff_dev pipeline preproc_arg tool + + # We are called with IFS set to colon. This causes really weird + # things to happen for the variables that have spaces in them. + unset IFS + + # If we are supposed to use a catpage and we aren't using troff(1) + # just zcat the catpage and we are done. + if [ -z "$tflag" -a -n "$use_cat" ]; then + if [ -n "$wflag" ]; then + echo "$catpage (source: $manpage)" + ret=0 + else + if [ $debug -gt 0 ]; then + decho "Command: $ZCAT $catpage | $PAGER" + ret=0 + else + eval "$ZCAT $catpage | $PAGER" + ret=$? + fi + fi + return + fi + + # Okay, we are using the manpage, do we just need to output the + # name of the manpage? + if [ -n "$wflag" ]; then + echo "$manpage" + ret=0 + return + fi + + # So, we really do need to parse the manpage. First, figure out the + # device flag (-T) we have to pass to eqn(1) and groff(1). Then, + # setup the pipeline of commands based on the user's request. + + # Apparently the locale flags are switched on where the manpage is + # found not just the locale env variables. + nroff_dev="ascii" + case "X${use_locale}X${manpage}" in + XyesX*/${man_lang}*${man_charset}/*) + # I don't pretend to know this; I'm just copying from the + # previous version of man(1). + case "$man_charset" in + KOI8-R) nroff_dev="koi8-r" ;; + ISO8859-1) nroff_dev="latin1" ;; + ISO8859-15) nroff_dev="latin1" ;; + UTF-8) nroff_dev="utf8" ;; + *) nroff_dev="ascii" ;; + esac + + NROFF="$NROFF -T$nroff_dev -dlocale=$man_lang.$man_charset" + EQN="$EQN -T$nroff_dev" + + # Allow language specific calls to override the default + # set of utilities. + l=$(echo $man_lang | tr [:lower:] [:upper:]) + for tool in EQN COL NROFF PIC TBL TROFF REFER VGRIND; do + eval "$tool=\${${tool}_$l:-\$$tool}" + done + ;; + *) NROFF="$NROFF -Tascii" + EQN="$EQN -Tascii" + ;; + esac + + if [ -n "$MANROFFSEQ" ]; then + set -- -$MANROFFSEQ + while getopts 'egprtv' preproc_arg; do + case "${preproc_arg}" in + e) pipeline="$pipeline | $EQN" ;; + g) ;; # Ignore for compatability. + p) pipeline="$pipeline | $PIC" ;; + r) pipeline="$pipeline | $REFER" ;; + t) pipeline="$pipeline | $TBL"; use_col=yes ;; + v) pipeline="$pipeline | $VGRIND" ;; + *) usage ;; + esac + done + # Strip the leading " | " from the resulting pipeline. + pipeline="${pipeline#" | "}" + else + pipeline="$TBL" + use_col=yes + fi + + if [ -n "$tflag" ]; then + pipeline="$pipeline | $TROFF" + else + pipeline="$pipeline | $NROFF" + + if [ -n "$use_col" ]; then + pipeline="$pipeline | $COL" + fi + + pipeline="$pipeline | $PAGER" + fi + + if [ $debug -gt 0 ]; then + decho "Command: $ZCAT $manpage | $pipeline" + ret=0 + else + eval "$ZCAT $manpage | $pipeline" + ret=$? + fi +} + +# Usage: man_find_and_display page +# Search through the manpaths looking for the given page. +man_find_and_display() { + local found_page locpath p path sect + + IFS=: + for sect in $MANSECT; do + decho "Searching section $sect" 2 + for path in $MANPATH; do + for locpath in $locpaths; do + p=$path/$locpath + p=${p%/.} # Rid ourselves of the trailing /. + + # Check if there is a MACHINE specific manpath. + if find_file $p $sect $MACHINE "$1"; then + found_page=yes + man_display_page + if [ -z "$aflag" ]; then + return + fi + fi + + # Check if there is a MACHINE_ARCH + # specific manpath. + if find_file $p $sect $MACHINE_ARCH "$1"; then + found_page=yes + man_display_page + if [ -z "$aflag" ]; then + return + fi + fi + + # Check plain old manpath. + if find_file $p $sect '' "$1"; then + found_page=yes + man_display_page + if [ -z "$aflag" ]; then + return + fi + fi + done + done + done + unset IFS + + # Nothing? Well, we are done then. + if [ -z "$found_page" ]; then + echo "No manual entry for $1" >&2 + ret=1 + return + fi +} + +# Usage: man_parse_args "$@" +# Parses commandline options for man. +man_parse_args() { + local IFS cmd_arg + + while getopts 'M:P:S:adfhkm:op:tw' cmd_arg; do + case "${cmd_arg}" in + M) MANPATH=$OPTARG ;; + P) PAGER=$OPTARG ;; + S) MANSECT=$OPTARG ;; + a) aflag=aflag ;; + d) debug=$(( $debug + 1 )) ;; + f) fflag=fflag ;; + h) man_usage 0 ;; + k) kflag=kflag ;; + m) mflag=$OPTARG ;; + o) oflag=oflag ;; + p) MANROFFSEQ=$OPTARG ;; + t) tflag=tflag ;; + w) wflag=wflag ;; + *) man_usage ;; + esac + done >&2 + + shift $(( $OPTIND - 1 )) + + # Check the args for incompatible options. + case "${fflag}${kflag}${tflag}${wflag}" in + fflagkflag*) echo "Incompatible options: -f and -k"; man_usage ;; + fflag*tflag*) echo "Incompatible options: -f and -t"; man_usage ;; + fflag*wflag) echo "Incompatible options: -f and -w"; man_usage ;; + *kflagtflag*) echo "Incompatible options: -k and -t"; man_usage ;; + *kflag*wflag) echo "Incompatible options: -k and -w"; man_usage ;; + *tflagwflag) echo "Incompatible options: -t and -w"; man_usage ;; + esac + + # Short circuit for whatis(1) and apropos(1) + if [ -n "$fflag" ]; then + do_whatis "$@" + exit + fi + + if [ -n "$kflag" ]; then + do_apropos "$@" + exit + fi + + IFS=: + for sect in $man_default_sections; do + if [ "$sect" = "$1" ]; then + decho "Detected manual section as first arg: $1" + MANSECT="$1" + shift + break + fi + done + unset IFS + + pages="$*" +} + +# Usage: man_setup +# Setup various trivial but essential variables. +man_setup() { + # Setup machine and architecture variables. + if [ -n "$mflag" ]; then + MACHINE_ARCH=${mflag%%:*} + MACHINE=${mflag##*:} + fi + if [ -z "$MACHINE_ARCH" ]; then + MACHINE_ARCH=$(sysctl -n hw.machine_arch) + fi + if [ -z "$MACHINE" ]; then + MACHINE=$(sysctl -n hw.machine) + fi + decho "Using architecture: $MACHINE_ARCH:$MACHINE" + + setup_pager + + # Setup manual sections to search. + if [ -z "$MANSECT" ]; then + MANSECT=$man_default_sections + fi + decho "Using manual sections: $MANSECT" + + build_manpath + man_setup_locale +} + +# Usage: man_setup_locale +# Setup necessary locale variables. +man_setup_locale() { + # Setup locale information. + if [ -n "$oflag" ]; then + decho "Using non-localized manpages" + unset use_locale + elif [ -n "$LC_ALL" ]; then + parse_locale "$LC_ALL" + elif [ -n "$LC_CTYPE" ]; then + parse_locale "$LC_CTYPE" + elif [ -n "$LANG" ]; then + parse_locale "$LANG" + fi + + if [ -n "$use_locale" ]; then + locpaths="${man_lang}_${man_country}.${man_charset}" + locpaths="$locpaths:$man_lang.$man_charset" + if [ "$man_lang" != "en" ]; then + locpaths="$locpaths:en.$man_charset" + fi + locpaths="$locpaths:." + else + locpaths="." + fi + decho "Using locale paths: $locpaths" +} + +# Usage: man_usage [exitcode] +# Display usage for the man utility. +man_usage() { + echo 'Usage:' + echo ' man [-adho] [-t | -w] [-M manpath] [-P pager] [-S mansect]' + echo ' [-m arch[:machine]] [-p [eprtv]] [mansect] page [...]' + echo ' man -f page [...] -- Emulates whatis(1)' + echo ' man -k page [...] -- Emulates apropos(1)' + + # When exit'ing with -h, it's not an error. + exit ${1:-1} +} + +# Usage: parse_configs +# Reads the end-user adjustable config files. +parse_configs() { + local IFS file files + + if [ -n "$parsed_configs" ]; then + return + fi + + unset IFS + + # Read the global config first in case the user wants + # to override config_local. + if [ -r "$config_global" ]; then + parse_file "$config_global" + fi + + # Glob the list of files to parse. + set +f + files=$(echo $config_local) + set -f + + for file in $files; do + if [ -r "$file" ]; then + parse_file "$file" + fi + done + + parsed_configs='yes' +} + +# Usage: parse_file file +# Reads the specified config files. +parse_file() { + local file line tstr var + + file="$1" + decho "Parsing config file: $file" + while read line; do + decho " $line" 2 + case "$line" in + \#*) decho " Comment" 3 + ;; + MANPATH*) decho " MANPATH" 3 + trim "${line#MANPATH}" + add_to_manpath "$tstr" + ;; + MANLOCALE*) decho " MANLOCALE" 3 + trim "${line#MANLOCALE}" + manlocales="$manlocales:$tstr" + ;; + MANCONFIG*) decho " MANCONFIG" 3 + trim "${line#MANCONF}" + config_local="$tstr" + ;; + # Set variables in the form of FOO_BAR + *_*[\ \ ]*) var="${line%%[\ \ ]*}" + trim "${line#$var}" + eval "$var=\"$tstr\"" + decho " Parsed $var" 3 + ;; + esac + done < "$file" +} + +# Usage: parse_locale localestring +# Setup locale variables for proper parsing. +parse_locale() { + local lang_cc + + case "$1" in + C) ;; + POSIX) ;; + [a-z][a-z]_[A-Z][A-Z]\.*) lang_cc="${1%.*}" + man_lang="${1%_*}" + man_country="${lang_cc#*_}" + man_charset="${1#*.}" + use_locale=yes + return 0 + ;; + *) echo 'Unknown locale, assuming C' >&2 + ;; + esac + + unset use_locale +} + +# Usage: search_path +# Traverse $PATH looking for manpaths. +search_path() { + local IFS p path + + decho "Searching PATH for man directories" + + IFS=: + for path in $PATH; do + # Do a little special casing since the base manpages + # are in /usr/share/man instead of /usr/man or /man. + case "$path" in + /bin|/usr/bin) add_to_manpath "/usr/share/man" ;; + *) if add_to_manpath "$path/man"; then + : + elif add_to_manpath "$path/MAN"; then + : + else + case "$path" in + */bin) p="${path%/bin}/man" + add_to_manpath "$p" + ;; + *) ;; + esac + fi + ;; + esac + done + unset IFS + + if [ -z "$manpath" ]; then + decho ' Unable to find any manpaths, using default' + manpath=$man_default_path + fi +} + +# Usage: search_whatis cmd [arglist] +# Do the heavy lifting for apropos/whatis +search_whatis() { + local IFS bad cmd f good key keywords loc opt out path rval wlist + + cmd="$1" + shift + + whatis_parse_args "$@" + + build_manpath + build_manlocales + setup_pager + + if [ "$cmd" = "whatis" ]; then + opt="-w" + fi + + f='whatis' + + IFS=: + for path in $MANPATH; do + if [ \! -d "$path" ]; then + decho "Skipping non-existent path: $path" 2 + continue + fi + + if [ -f "$path/$f" -a -r "$path/$f" ]; then + decho "Found whatis: $path/$f" + wlist="$wlist $path/$f" + fi + + for loc in $MANLOCALES; do + if [ -f "$path/$loc/$f" -a -r "$path/$loc/$f" ]; then + decho "Found whatis: $path/$loc/$f" + wlist="$wlist $path/$loc/$f" + fi + done + done + unset IFS + + if [ -z "$wlist" ]; then + echo "$cmd: no whatis databases in $MANPATH" >&2 + exit 1 + fi + + rval=0 + for key in $keywords; do + out=$(grep -Ehi $opt -- "$key" $wlist) + if [ -n "$out" ]; then + good="$good\\n$out" + else + bad="$bad\\n$key: nothing appropriate" + rval=1 + fi + done + + # Strip leading carriage return. + good=${good#\\n} + bad=${bad#\\n} + + if [ -n "$good" ]; then + echo -e $good | $PAGER + fi + + if [ -n "$bad" ]; then + echo -e $bad >&2 + fi + + exit $rval +} + +# Usage: setup_pager +# Correctly sets $PAGER +setup_pager() { + # Setup pager. + if [ -z "$PAGER" ]; then + PAGER="more -s" + fi + decho "Using pager: $PAGER" +} + +# Usage: trim string +# Trims whitespace from beginning and end of a variable +trim() { + tstr=$1 + while true; do + case "$tstr" in + [\ \ ]*) tstr="${tstr##[\ \ ]}" ;; + *[\ \ ]) tstr="${tstr%%[\ \ ]}" ;; + *) break ;; + esac + done +} + +# Usage: whatis_parse_args "$@" +# Parse commandline args for whatis and apropos. +whatis_parse_args() { + local cmd_arg + while getopts 'd' cmd_arg; do + case "${cmd_arg}" in + d) debug=$(( $debug + 1 )) ;; + *) whatis_usage ;; + esac + done >&2 + + shift $(( $OPTIND - 1 )) + + keywords="$*" +} + +# Usage: whatis_usage +# Display usage for the whatis/apropos utility. +whatis_usage() { + echo "usage: $cmd [-d] keyword [...]" + exit 1 +} + + + +# Supported commands +do_apropos() { + search_whatis apropos "$@" +} + +do_man() { + man_parse_args "$@" + if [ -z "$pages" ]; then + echo 'What manual page do you want?' >&2 + exit 1 + fi + man_setup + + for page in $pages; do + decho "Searching for $page" + man_find_and_display "$page" + done + + exit ${ret:-0} +} + +do_manpath() { + manpath_parse_args "$@" + if [ -z "$qflag" ]; then + manpath_warnings + fi + if [ -n "$Lflag" ]; then + build_manlocales + echo $MANLOCALES + else + build_manpath + echo $MANPATH + fi + exit 0 +} + +do_whatis() { + search_whatis whatis "$@" +} + +EQN=/usr/bin/eqn +COL=/usr/bin/col +NROFF='/usr/bin/groff -S -Wall -mtty-char -man' +PIC=/usr/bin/pic +TBL=/usr/bin/tbl +TROFF='/usr/bin/groff -S -man' +REFER=/usr/bin/refer +VGRIND=/usr/bin/vgrind +ZCAT='/usr/bin/zcat -f' + +debug=0 +man_default_sections='1:1aout:8:2:3:n:4:5:6:7:9:l' +man_default_path='/usr/share/man:/usr/share/openssl/man:/usr/local/man' + +config_global='/etc/man.conf' + +# This can be overridden via a setting in /etc/man.conf. +config_local='/usr/local/etc/man.d/*.conf' + +# Set noglobbing for now. I don't want spurious globbing. +set -f + +case "$0" in +*apropos) do_apropos "$@" ;; +*manpath) do_manpath "$@" ;; +*whatis) do_whatis "$@" ;; +*) do_man "$@" ;; +esac diff --git a/usr.bin/man/manpath.1 b/usr.bin/man/manpath.1 new file mode 100644 index 0000000..2cf39ab --- /dev/null +++ b/usr.bin/man/manpath.1 @@ -0,0 +1,123 @@ +.\"- +.\" Copyright (c) 2010 Gordon Tetlow +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd September 1, 2010 +.Dt MANPATH 1 +.Os +.Sh NAME +.Nm manpath +.Nd display search path for manual pages +.Sh SYNOPSIS +.Nm +.Op Fl Ldq +.Sh DESCRIPTION +The +.Nm +utility determines the user's manual search path from +the user's +.Ev PATH , +and local configuration files. +This result is echoed to the standard output. +.Bl -tag -width ".Fl d" +.It Fl L +Output manual locales list instead of the manual path. +.It Fl d +Print extra debugging information. +.It Fl q +Suppresses warning messages. +.El +.Sh IMPLEMENTATION NOTES +The +.Nm +utility constructs the manual path from two sources: +.Bl -enum -compact +.It +From each component of the user's +.Ev PATH +for the first of: +.Bl -dash -compact +.It +.Pa pathname/man +.It +.Pa pathname/MAN +.It +If pathname ends with /bin: +.Pa pathname/../man +.El +Note: Special logic exists to make +.Pa /bin +and +.Pa /usr/bin +look in +.Pa /usr/share/man +for manual files. +.It +The configuration files listed in the +.Sx FILES +section for +.Va MANPATH +entries. +.El +The information from these locations is then concatenated together. +.Pp +If the +.Fl L +flag is set, the +.Nm +utility will search the configuration files listed in the +.Sx FILES +section for +.Va MANLOCALE +entries. +.Sh ENVIRONMENT +The following environment variables affect the execution of +.Nm : +.Bl -tag -width ".Ev MANLOCALES" +.It Ev MANLOCALES +If set with the +.Fl L +flag, causes the utility to display a warning and the value, overriding any +other configuration found on the system. +.It Ev MANPATH +If set, causes the utility to display a warning and the value, overriding +any other configuration found on the system. +.It Ev PATH +Influences the manual path as described in the +.Sx IMPLEMENTATION NOTES . +.El +.Sh FILES +.Bl -tag -width indent -compact +.It Pa /etc/man.conf +System configuration file. +.It Pa /usr/local/etc/man.d/*.conf +Local configuration files. +.El +.Sh SEE ALSO +.Xr apropos 1 , +.Xr man 1 , +.Xr man.conf 5 , +.Xr whatis 1 |