1213317Sgordon#! /bin/sh 2213317Sgordon# 3213317Sgordon# Copyright (c) 2010 Gordon Tetlow 4213317Sgordon# All rights reserved. 5213317Sgordon# 6213317Sgordon# Redistribution and use in source and binary forms, with or without 7213317Sgordon# modification, are permitted provided that the following conditions 8213317Sgordon# are met: 9213317Sgordon# 1. Redistributions of source code must retain the above copyright 10213317Sgordon# notice, this list of conditions and the following disclaimer. 11213317Sgordon# 2. Redistributions in binary form must reproduce the above copyright 12213317Sgordon# notice, this list of conditions and the following disclaimer in the 13213317Sgordon# documentation and/or other materials provided with the distribution. 14213317Sgordon# 15213317Sgordon# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16213317Sgordon# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17213317Sgordon# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18213317Sgordon# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19213317Sgordon# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20213317Sgordon# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21213317Sgordon# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22213317Sgordon# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23213317Sgordon# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24213317Sgordon# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25213317Sgordon# SUCH DAMAGE. 26213317Sgordon# 27213317Sgordon# $FreeBSD: stable/10/usr.bin/man/man.sh 326688 2017-12-08 10:47:29Z bapt $ 28213317Sgordon 29213317Sgordon# Usage: add_to_manpath path 30213317Sgordon# Adds a variable to manpath while ensuring we don't have duplicates. 31213317Sgordon# Returns true if we were able to add something. False otherwise. 32213317Sgordonadd_to_manpath() { 33213317Sgordon case "$manpath" in 34213317Sgordon *:$1) decho " Skipping duplicate manpath entry $1" 2 ;; 35213317Sgordon $1:*) decho " Skipping duplicate manpath entry $1" 2 ;; 36213317Sgordon *:$1:*) decho " Skipping duplicate manpath entry $1" 2 ;; 37213317Sgordon *) if [ -d "$1" ]; then 38213317Sgordon decho " Adding $1 to manpath" 39213317Sgordon manpath="$manpath:$1" 40213317Sgordon return 0 41213317Sgordon fi 42213317Sgordon ;; 43213317Sgordon esac 44213317Sgordon 45213317Sgordon return 1 46213317Sgordon} 47213317Sgordon 48213317Sgordon# Usage: build_manlocales 49213317Sgordon# Builds a correct MANLOCALES variable. 50213317Sgordonbuild_manlocales() { 51213317Sgordon # If the user has set manlocales, who are we to argue. 52213317Sgordon if [ -n "$MANLOCALES" ]; then 53213317Sgordon return 54213317Sgordon fi 55213317Sgordon 56213317Sgordon parse_configs 57213317Sgordon 58213317Sgordon # Trim leading colon 59213317Sgordon MANLOCALES=${manlocales#:} 60213317Sgordon 61213317Sgordon decho "Available manual locales: $MANLOCALES" 62213317Sgordon} 63213317Sgordon 64213317Sgordon# Usage: build_manpath 65213317Sgordon# Builds a correct MANPATH variable. 66213317Sgordonbuild_manpath() { 67213317Sgordon local IFS 68213317Sgordon 69213317Sgordon # If the user has set a manpath, who are we to argue. 70213317Sgordon if [ -n "$MANPATH" ]; then 71213317Sgordon return 72213317Sgordon fi 73213317Sgordon 74213317Sgordon search_path 75213317Sgordon 76213317Sgordon decho "Adding default manpath entries" 77213317Sgordon IFS=: 78213317Sgordon for path in $man_default_path; do 79213317Sgordon add_to_manpath "$path" 80213317Sgordon done 81213317Sgordon unset IFS 82213317Sgordon 83213317Sgordon parse_configs 84213317Sgordon 85213317Sgordon # Trim leading colon 86213317Sgordon MANPATH=${manpath#:} 87213317Sgordon 88213317Sgordon decho "Using manual path: $MANPATH" 89213317Sgordon} 90213317Sgordon 91213317Sgordon# Usage: check_cat catglob 92213317Sgordon# Checks to see if a cat glob is available. 93213317Sgordoncheck_cat() { 94213317Sgordon if exists "$1"; then 95213317Sgordon use_cat=yes 96213317Sgordon catpage=$found 97216140Sgordon setup_cattool $catpage 98213317Sgordon decho " Found catpage $catpage" 99213317Sgordon return 0 100213317Sgordon else 101213317Sgordon return 1 102213317Sgordon fi 103213317Sgordon} 104213317Sgordon 105213317Sgordon# Usage: check_man manglob catglob 106213317Sgordon# Given 2 globs, figures out if the manglob is available, if so, check to 107213317Sgordon# see if the catglob is also available and up to date. 108213317Sgordoncheck_man() { 109213317Sgordon if exists "$1"; then 110213317Sgordon # We have a match, check for a cat page 111213317Sgordon manpage=$found 112216140Sgordon setup_cattool $manpage 113213317Sgordon decho " Found manpage $manpage" 114213317Sgordon 115222635Sru if [ -n "${use_width}" ]; then 116222635Sru # non-standard width 117222635Sru unset use_cat 118222635Sru decho " Skipping catpage: non-standard page width" 119222635Sru elif exists "$2" && is_newer $found $manpage; then 120213317Sgordon # cat page found and is newer, use that 121213317Sgordon use_cat=yes 122213317Sgordon catpage=$found 123216140Sgordon setup_cattool $catpage 124213317Sgordon decho " Using catpage $catpage" 125213317Sgordon else 126213317Sgordon # no cat page or is older 127213317Sgordon unset use_cat 128213317Sgordon decho " Skipping catpage: not found or old" 129213317Sgordon fi 130213317Sgordon return 0 131213317Sgordon fi 132213317Sgordon 133213317Sgordon return 1 134213317Sgordon} 135213317Sgordon 136213317Sgordon# Usage: decho "string" [debuglevel] 137213317Sgordon# Echoes to stderr string prefaced with -- if high enough debuglevel. 138213317Sgordondecho() { 139213317Sgordon if [ $debug -ge ${2:-1} ]; then 140213317Sgordon echo "-- $1" >&2 141213317Sgordon fi 142213317Sgordon} 143213317Sgordon 144213317Sgordon# Usage: exists glob 145213317Sgordon# Returns true if glob resolves to a real file. 146213317Sgordonexists() { 147213317Sgordon local IFS 148213317Sgordon 149213317Sgordon # Don't accidentally inherit callers IFS (breaks perl manpages) 150213317Sgordon unset IFS 151213317Sgordon 152213317Sgordon # Use some globbing tricks in the shell to determine if a file 153213317Sgordon # exists or not. 154213317Sgordon set +f 155213317Sgordon set -- "$1" $1 156213317Sgordon set -f 157213317Sgordon 158213317Sgordon if [ "$1" != "$2" -a -r "$2" ]; then 159213317Sgordon found="$2" 160213317Sgordon return 0 161213317Sgordon fi 162213317Sgordon 163213317Sgordon return 1 164213317Sgordon} 165213317Sgordon 166213317Sgordon# Usage: find_file path section subdir pagename 167213317Sgordon# Returns: true if something is matched and found. 168213317Sgordon# Search the given path/section combo for a given page. 169213317Sgordonfind_file() { 170213317Sgordon local manroot catroot mann man0 catn cat0 171213317Sgordon 172213317Sgordon manroot="$1/man$2" 173213317Sgordon catroot="$1/cat$2" 174213317Sgordon if [ -n "$3" ]; then 175213317Sgordon manroot="$manroot/$3" 176213317Sgordon catroot="$catroot/$3" 177213317Sgordon fi 178213317Sgordon 179326688Sbapt if [ ! -d "$manroot" -a ! -d "$catroot" ]; then 180213317Sgordon return 1 181213317Sgordon fi 182213317Sgordon decho " Searching directory $manroot" 2 183213317Sgordon 184213317Sgordon mann="$manroot/$4.$2*" 185213317Sgordon man0="$manroot/$4.0*" 186213317Sgordon catn="$catroot/$4.$2*" 187213317Sgordon cat0="$catroot/$4.0*" 188213317Sgordon 189213317Sgordon # This is the behavior as seen by the original man utility. 190213317Sgordon # Let's not change that which doesn't seem broken. 191213317Sgordon if check_man "$mann" "$catn"; then 192213317Sgordon return 0 193213317Sgordon elif check_man "$man0" "$cat0"; then 194213317Sgordon return 0 195213317Sgordon elif check_cat "$catn"; then 196213317Sgordon return 0 197213317Sgordon elif check_cat "$cat0"; then 198213317Sgordon return 0 199213317Sgordon fi 200213317Sgordon 201213317Sgordon return 1 202213317Sgordon} 203213317Sgordon 204213317Sgordon# Usage: is_newer file1 file2 205213317Sgordon# Returns true if file1 is newer than file2 as calculated by mtime. 206213317Sgordonis_newer() { 207217831Suqs if ! [ "$1" -ot "$2" ]; then 208217831Suqs decho " mtime: $1 not older than $2" 3 209213317Sgordon return 0 210213317Sgordon else 211213317Sgordon decho " mtime: $1 older than $2" 3 212213317Sgordon return 1 213213317Sgordon fi 214213317Sgordon} 215213317Sgordon 216213317Sgordon# Usage: manpath_parse_args "$@" 217213317Sgordon# Parses commandline options for manpath. 218213317Sgordonmanpath_parse_args() { 219213317Sgordon local cmd_arg 220213317Sgordon 221213317Sgordon while getopts 'Ldq' cmd_arg; do 222213317Sgordon case "${cmd_arg}" in 223213317Sgordon L) Lflag=Lflag ;; 224213317Sgordon d) debug=$(( $debug + 1 )) ;; 225213317Sgordon q) qflag=qflag ;; 226213317Sgordon *) manpath_usage ;; 227213317Sgordon esac 228213317Sgordon done >&2 229213317Sgordon} 230213317Sgordon 231213317Sgordon# Usage: manpath_usage 232213317Sgordon# Display usage for the manpath(1) utility. 233213317Sgordonmanpath_usage() { 234213317Sgordon echo 'usage: manpath [-Ldq]' >&2 235213317Sgordon exit 1 236213317Sgordon} 237213317Sgordon 238213317Sgordon# Usage: manpath_warnings 239213317Sgordon# Display some warnings to stderr. 240213317Sgordonmanpath_warnings() { 241213317Sgordon if [ -z "$Lflag" -a -n "$MANPATH" ]; then 242213317Sgordon echo "(Warning: MANPATH environment variable set)" >&2 243213317Sgordon fi 244213317Sgordon 245213317Sgordon if [ -n "$Lflag" -a -n "$MANLOCALES" ]; then 246213317Sgordon echo "(Warning: MANLOCALES environment variable set)" >&2 247213317Sgordon fi 248213317Sgordon} 249213317Sgordon 250216140Sgordon# Usage: man_check_for_so page path 251216140Sgordon# Returns: True if able to resolve the file, false if it ended in tears. 252216140Sgordon# Detects the presence of the .so directive and causes the file to be 253216140Sgordon# redirected to another source file. 254216140Sgordonman_check_for_so() { 255216140Sgordon local IFS line tstr 256216140Sgordon 257216140Sgordon unset IFS 258326686Sbapt if [ -n "$catpage" ]; then 259326686Sbapt return 0 260326686Sbapt fi 261216140Sgordon 262216140Sgordon # We need to loop to accommodate multiple .so directives. 263216140Sgordon while true 264216140Sgordon do 265216140Sgordon line=$($cattool $manpage | head -1) 266216140Sgordon case "$line" in 267216140Sgordon .so*) trim "${line#.so}" 268216140Sgordon decho "$manpage includes $tstr" 269216140Sgordon # Glob and check for the file. 270216140Sgordon if ! check_man "$path/$tstr*" ""; then 271216140Sgordon decho " Unable to find $tstr" 272216140Sgordon return 1 273216140Sgordon fi 274216140Sgordon ;; 275216140Sgordon *) break ;; 276216140Sgordon esac 277216140Sgordon done 278216140Sgordon 279216140Sgordon return 0 280216140Sgordon} 281216140Sgordon 282278693Ssbruno# Usage: man_display_page 283278693Ssbruno# Display either the manpage or catpage depending on the use_cat variable 284213317Sgordonman_display_page() { 285278693Ssbruno local EQN NROFF PIC TBL TROFF REFER VGRIND 286278693Ssbruno local IFS l nroff_dev pipeline preproc_arg tool 287213317Sgordon 288213317Sgordon # We are called with IFS set to colon. This causes really weird 289213317Sgordon # things to happen for the variables that have spaces in them. 290213317Sgordon unset IFS 291213317Sgordon 292213317Sgordon # If we are supposed to use a catpage and we aren't using troff(1) 293213317Sgordon # just zcat the catpage and we are done. 294213317Sgordon if [ -z "$tflag" -a -n "$use_cat" ]; then 295213317Sgordon if [ -n "$wflag" ]; then 296213317Sgordon echo "$catpage (source: $manpage)" 297213317Sgordon ret=0 298213317Sgordon else 299213317Sgordon if [ $debug -gt 0 ]; then 300222653Sru decho "Command: $cattool $catpage | $MANPAGER" 301213317Sgordon ret=0 302213317Sgordon else 303222653Sru eval "$cattool $catpage | $MANPAGER" 304213317Sgordon ret=$? 305213317Sgordon fi 306213317Sgordon fi 307213317Sgordon return 308213317Sgordon fi 309213317Sgordon 310213317Sgordon # Okay, we are using the manpage, do we just need to output the 311213317Sgordon # name of the manpage? 312213317Sgordon if [ -n "$wflag" ]; then 313213317Sgordon echo "$manpage" 314213317Sgordon ret=0 315213317Sgordon return 316213317Sgordon fi 317213317Sgordon 318213317Sgordon # So, we really do need to parse the manpage. First, figure out the 319213317Sgordon # device flag (-T) we have to pass to eqn(1) and groff(1). Then, 320213317Sgordon # setup the pipeline of commands based on the user's request. 321213317Sgordon 322220261Sgordon # If the manpage is from a particular charset, we need to setup nroff 323220261Sgordon # to properly output for the correct device. 324220261Sgordon case "${manpage}" in 325220261Sgordon *.${man_charset}/*) 326213317Sgordon # I don't pretend to know this; I'm just copying from the 327213317Sgordon # previous version of man(1). 328213317Sgordon case "$man_charset" in 329213317Sgordon KOI8-R) nroff_dev="koi8-r" ;; 330213317Sgordon ISO8859-1) nroff_dev="latin1" ;; 331213317Sgordon ISO8859-15) nroff_dev="latin1" ;; 332213317Sgordon UTF-8) nroff_dev="utf8" ;; 333213317Sgordon *) nroff_dev="ascii" ;; 334213317Sgordon esac 335213317Sgordon 336220261Sgordon NROFF="$NROFF -T$nroff_dev" 337213317Sgordon EQN="$EQN -T$nroff_dev" 338213317Sgordon 339220261Sgordon # Iff the manpage is from the locale and not just the charset, 340220261Sgordon # then we need to define the locale string. 341220261Sgordon case "${manpage}" in 342220261Sgordon */${man_lang}_${man_country}.${man_charset}/*) 343220261Sgordon NROFF="$NROFF -dlocale=$man_lang.$man_charset" 344220261Sgordon ;; 345220261Sgordon */${man_lang}.${man_charset}/*) 346220261Sgordon NROFF="$NROFF -dlocale=$man_lang.$man_charset" 347220261Sgordon ;; 348220261Sgordon esac 349220261Sgordon 350213317Sgordon # Allow language specific calls to override the default 351213317Sgordon # set of utilities. 352213317Sgordon l=$(echo $man_lang | tr [:lower:] [:upper:]) 353222650Sru for tool in EQN NROFF PIC TBL TROFF REFER VGRIND; do 354213317Sgordon eval "$tool=\${${tool}_$l:-\$$tool}" 355213317Sgordon done 356213317Sgordon ;; 357213317Sgordon *) NROFF="$NROFF -Tascii" 358213317Sgordon EQN="$EQN -Tascii" 359213317Sgordon ;; 360213317Sgordon esac 361213317Sgordon 362222653Sru if [ -z "$MANCOLOR" ]; then 363222653Sru NROFF="$NROFF -P-c" 364222653Sru fi 365222653Sru 366222635Sru if [ -n "${use_width}" ]; then 367222635Sru NROFF="$NROFF -rLL=${use_width}n -rLT=${use_width}n" 368222635Sru fi 369222635Sru 370213317Sgordon if [ -n "$MANROFFSEQ" ]; then 371213317Sgordon set -- -$MANROFFSEQ 372213317Sgordon while getopts 'egprtv' preproc_arg; do 373213317Sgordon case "${preproc_arg}" in 374213317Sgordon e) pipeline="$pipeline | $EQN" ;; 375228992Suqs g) ;; # Ignore for compatibility. 376213317Sgordon p) pipeline="$pipeline | $PIC" ;; 377213317Sgordon r) pipeline="$pipeline | $REFER" ;; 378222650Sru t) pipeline="$pipeline | $TBL" ;; 379213317Sgordon v) pipeline="$pipeline | $VGRIND" ;; 380213317Sgordon *) usage ;; 381213317Sgordon esac 382213317Sgordon done 383213317Sgordon # Strip the leading " | " from the resulting pipeline. 384213317Sgordon pipeline="${pipeline#" | "}" 385213317Sgordon else 386213317Sgordon pipeline="$TBL" 387213317Sgordon fi 388213317Sgordon 389213317Sgordon if [ -n "$tflag" ]; then 390213317Sgordon pipeline="$pipeline | $TROFF" 391213317Sgordon else 392222653Sru pipeline="$pipeline | $NROFF | $MANPAGER" 393213317Sgordon fi 394213317Sgordon 395213317Sgordon if [ $debug -gt 0 ]; then 396216140Sgordon decho "Command: $cattool $manpage | $pipeline" 397213317Sgordon ret=0 398213317Sgordon else 399216140Sgordon eval "$cattool $manpage | $pipeline" 400213317Sgordon ret=$? 401213317Sgordon fi 402213317Sgordon} 403213317Sgordon 404213317Sgordon# Usage: man_find_and_display page 405213317Sgordon# Search through the manpaths looking for the given page. 406213317Sgordonman_find_and_display() { 407213317Sgordon local found_page locpath p path sect 408213317Sgordon 409213507Sgordon # Check to see if it's a file. But only if it has a '/' in 410213507Sgordon # the filename. 411213507Sgordon case "$1" in 412213507Sgordon */*) if [ -f "$1" -a -r "$1" ]; then 413213507Sgordon decho "Found a usable page, displaying that" 414213507Sgordon unset use_cat 415213507Sgordon manpage="$1" 416216140Sgordon setup_cattool $manpage 417216140Sgordon if man_check_for_so $manpage $(dirname $manpage); then 418216140Sgordon found_page=yes 419216140Sgordon man_display_page 420216140Sgordon fi 421213507Sgordon return 422213507Sgordon fi 423213507Sgordon ;; 424213507Sgordon esac 425213507Sgordon 426213317Sgordon IFS=: 427213317Sgordon for sect in $MANSECT; do 428213317Sgordon decho "Searching section $sect" 2 429213317Sgordon for path in $MANPATH; do 430213317Sgordon for locpath in $locpaths; do 431213317Sgordon p=$path/$locpath 432213317Sgordon p=${p%/.} # Rid ourselves of the trailing /. 433213317Sgordon 434213317Sgordon # Check if there is a MACHINE specific manpath. 435213317Sgordon if find_file $p $sect $MACHINE "$1"; then 436216140Sgordon if man_check_for_so $manpage $p; then 437216140Sgordon found_page=yes 438216140Sgordon man_display_page 439216140Sgordon if [ -n "$aflag" ]; then 440216140Sgordon continue 2 441216140Sgordon else 442216140Sgordon return 443216140Sgordon fi 444213317Sgordon fi 445213317Sgordon fi 446213317Sgordon 447213317Sgordon # Check if there is a MACHINE_ARCH 448213317Sgordon # specific manpath. 449213317Sgordon if find_file $p $sect $MACHINE_ARCH "$1"; then 450216140Sgordon if man_check_for_so $manpage $p; then 451216140Sgordon found_page=yes 452216140Sgordon man_display_page 453216140Sgordon if [ -n "$aflag" ]; then 454216140Sgordon continue 2 455216140Sgordon else 456216140Sgordon return 457216140Sgordon fi 458213317Sgordon fi 459213317Sgordon fi 460213317Sgordon 461213317Sgordon # Check plain old manpath. 462213317Sgordon if find_file $p $sect '' "$1"; then 463216140Sgordon if man_check_for_so $manpage $p; then 464216140Sgordon found_page=yes 465216140Sgordon man_display_page 466216140Sgordon if [ -n "$aflag" ]; then 467216140Sgordon continue 2 468216140Sgordon else 469216140Sgordon return 470216140Sgordon fi 471213317Sgordon fi 472213317Sgordon fi 473213317Sgordon done 474213317Sgordon done 475213317Sgordon done 476213317Sgordon unset IFS 477213317Sgordon 478213317Sgordon # Nothing? Well, we are done then. 479213317Sgordon if [ -z "$found_page" ]; then 480213317Sgordon echo "No manual entry for $1" >&2 481213317Sgordon ret=1 482213317Sgordon return 483213317Sgordon fi 484213317Sgordon} 485213317Sgordon 486213317Sgordon# Usage: man_parse_args "$@" 487213317Sgordon# Parses commandline options for man. 488213317Sgordonman_parse_args() { 489213317Sgordon local IFS cmd_arg 490213317Sgordon 491213317Sgordon while getopts 'M:P:S:adfhkm:op:tw' cmd_arg; do 492213317Sgordon case "${cmd_arg}" in 493213317Sgordon M) MANPATH=$OPTARG ;; 494222653Sru P) MANPAGER=$OPTARG ;; 495213317Sgordon S) MANSECT=$OPTARG ;; 496213317Sgordon a) aflag=aflag ;; 497213317Sgordon d) debug=$(( $debug + 1 )) ;; 498213317Sgordon f) fflag=fflag ;; 499213317Sgordon h) man_usage 0 ;; 500213317Sgordon k) kflag=kflag ;; 501213317Sgordon m) mflag=$OPTARG ;; 502213317Sgordon o) oflag=oflag ;; 503213317Sgordon p) MANROFFSEQ=$OPTARG ;; 504213317Sgordon t) tflag=tflag ;; 505213317Sgordon w) wflag=wflag ;; 506213317Sgordon *) man_usage ;; 507213317Sgordon esac 508213317Sgordon done >&2 509213317Sgordon 510213317Sgordon shift $(( $OPTIND - 1 )) 511213317Sgordon 512213317Sgordon # Check the args for incompatible options. 513213317Sgordon case "${fflag}${kflag}${tflag}${wflag}" in 514213317Sgordon fflagkflag*) echo "Incompatible options: -f and -k"; man_usage ;; 515213317Sgordon fflag*tflag*) echo "Incompatible options: -f and -t"; man_usage ;; 516213317Sgordon fflag*wflag) echo "Incompatible options: -f and -w"; man_usage ;; 517213317Sgordon *kflagtflag*) echo "Incompatible options: -k and -t"; man_usage ;; 518213317Sgordon *kflag*wflag) echo "Incompatible options: -k and -w"; man_usage ;; 519213317Sgordon *tflagwflag) echo "Incompatible options: -t and -w"; man_usage ;; 520213317Sgordon esac 521213317Sgordon 522213317Sgordon # Short circuit for whatis(1) and apropos(1) 523213317Sgordon if [ -n "$fflag" ]; then 524213317Sgordon do_whatis "$@" 525213317Sgordon exit 526213317Sgordon fi 527213317Sgordon 528213317Sgordon if [ -n "$kflag" ]; then 529213317Sgordon do_apropos "$@" 530213317Sgordon exit 531213317Sgordon fi 532213317Sgordon 533213317Sgordon IFS=: 534213317Sgordon for sect in $man_default_sections; do 535213317Sgordon if [ "$sect" = "$1" ]; then 536213317Sgordon decho "Detected manual section as first arg: $1" 537213317Sgordon MANSECT="$1" 538213317Sgordon shift 539213317Sgordon break 540213317Sgordon fi 541213317Sgordon done 542213317Sgordon unset IFS 543213317Sgordon 544213317Sgordon pages="$*" 545213317Sgordon} 546213317Sgordon 547213317Sgordon# Usage: man_setup 548213317Sgordon# Setup various trivial but essential variables. 549213317Sgordonman_setup() { 550213317Sgordon # Setup machine and architecture variables. 551213317Sgordon if [ -n "$mflag" ]; then 552213317Sgordon MACHINE_ARCH=${mflag%%:*} 553213317Sgordon MACHINE=${mflag##*:} 554213317Sgordon fi 555213317Sgordon if [ -z "$MACHINE_ARCH" ]; then 556216426Sgordon MACHINE_ARCH=$($SYSCTL -n hw.machine_arch) 557213317Sgordon fi 558213317Sgordon if [ -z "$MACHINE" ]; then 559216426Sgordon MACHINE=$($SYSCTL -n hw.machine) 560213317Sgordon fi 561213317Sgordon decho "Using architecture: $MACHINE_ARCH:$MACHINE" 562213317Sgordon 563213317Sgordon setup_pager 564213317Sgordon 565213317Sgordon # Setup manual sections to search. 566213317Sgordon if [ -z "$MANSECT" ]; then 567213317Sgordon MANSECT=$man_default_sections 568213317Sgordon fi 569213317Sgordon decho "Using manual sections: $MANSECT" 570213317Sgordon 571213317Sgordon build_manpath 572213317Sgordon man_setup_locale 573222635Sru man_setup_width 574213317Sgordon} 575213317Sgordon 576222635Sru# Usage: man_setup_width 577222635Sru# Set up page width. 578222635Sruman_setup_width() { 579222635Sru local sizes 580222635Sru 581222635Sru unset use_width 582222635Sru case "$MANWIDTH" in 583222635Sru [0-9]*) 584222635Sru if [ "$MANWIDTH" -gt 0 2>/dev/null ]; then 585222635Sru use_width=$MANWIDTH 586222635Sru fi 587222635Sru ;; 588222635Sru [Tt][Tt][Yy]) 589222635Sru if { sizes=$($STTY size 0>&3 2>/dev/null); } 3>&1; then 590222635Sru set -- $sizes 591222635Sru if [ $2 -gt 80 ]; then 592222635Sru use_width=$(($2-2)) 593222635Sru fi 594222635Sru fi 595222635Sru ;; 596222635Sru esac 597222635Sru if [ -n "$use_width" ]; then 598222635Sru decho "Using non-standard page width: ${use_width}" 599222635Sru else 600222635Sru decho 'Using standard page width' 601222635Sru fi 602222635Sru} 603222635Sru 604213317Sgordon# Usage: man_setup_locale 605213317Sgordon# Setup necessary locale variables. 606213317Sgordonman_setup_locale() { 607220261Sgordon local lang_cc 608220261Sgordon 609220261Sgordon locpaths='.' 610220261Sgordon man_charset='US-ASCII' 611220261Sgordon 612213317Sgordon # Setup locale information. 613213317Sgordon if [ -n "$oflag" ]; then 614220261Sgordon decho 'Using non-localized manpages' 615220261Sgordon else 616220261Sgordon # Use the locale tool to give us the proper LC_CTYPE 617220261Sgordon eval $( $LOCALE ) 618220261Sgordon 619220261Sgordon case "$LC_CTYPE" in 620220261Sgordon C) ;; 621220261Sgordon POSIX) ;; 622220261Sgordon [a-z][a-z]_[A-Z][A-Z]\.*) 623220261Sgordon lang_cc="${LC_CTYPE%.*}" 624220261Sgordon man_lang="${LC_CTYPE%_*}" 625220261Sgordon man_country="${lang_cc#*_}" 626220261Sgordon man_charset="${LC_CTYPE#*.}" 627220261Sgordon locpaths="$LC_CTYPE" 628220261Sgordon locpaths="$locpaths:$man_lang.$man_charset" 629220261Sgordon if [ "$man_lang" != "en" ]; then 630220261Sgordon locpaths="$locpaths:en.$man_charset" 631220261Sgordon fi 632220261Sgordon locpaths="$locpaths:." 633220261Sgordon ;; 634220261Sgordon *) echo 'Unknown locale, assuming C' >&2 635220261Sgordon ;; 636220261Sgordon esac 637213317Sgordon fi 638213317Sgordon 639213317Sgordon decho "Using locale paths: $locpaths" 640213317Sgordon} 641213317Sgordon 642213317Sgordon# Usage: man_usage [exitcode] 643213317Sgordon# Display usage for the man utility. 644213317Sgordonman_usage() { 645213317Sgordon echo 'Usage:' 646213317Sgordon echo ' man [-adho] [-t | -w] [-M manpath] [-P pager] [-S mansect]' 647213317Sgordon echo ' [-m arch[:machine]] [-p [eprtv]] [mansect] page [...]' 648213317Sgordon echo ' man -f page [...] -- Emulates whatis(1)' 649213317Sgordon echo ' man -k page [...] -- Emulates apropos(1)' 650213317Sgordon 651213317Sgordon # When exit'ing with -h, it's not an error. 652213317Sgordon exit ${1:-1} 653213317Sgordon} 654213317Sgordon 655213317Sgordon# Usage: parse_configs 656213317Sgordon# Reads the end-user adjustable config files. 657213317Sgordonparse_configs() { 658213317Sgordon local IFS file files 659213317Sgordon 660213317Sgordon if [ -n "$parsed_configs" ]; then 661213317Sgordon return 662213317Sgordon fi 663213317Sgordon 664213317Sgordon unset IFS 665213317Sgordon 666213317Sgordon # Read the global config first in case the user wants 667213317Sgordon # to override config_local. 668213317Sgordon if [ -r "$config_global" ]; then 669213317Sgordon parse_file "$config_global" 670213317Sgordon fi 671213317Sgordon 672213317Sgordon # Glob the list of files to parse. 673213317Sgordon set +f 674213317Sgordon files=$(echo $config_local) 675213317Sgordon set -f 676213317Sgordon 677213317Sgordon for file in $files; do 678213317Sgordon if [ -r "$file" ]; then 679213317Sgordon parse_file "$file" 680213317Sgordon fi 681213317Sgordon done 682213317Sgordon 683213317Sgordon parsed_configs='yes' 684213317Sgordon} 685213317Sgordon 686213317Sgordon# Usage: parse_file file 687213317Sgordon# Reads the specified config files. 688213317Sgordonparse_file() { 689213317Sgordon local file line tstr var 690213317Sgordon 691213317Sgordon file="$1" 692213317Sgordon decho "Parsing config file: $file" 693213317Sgordon while read line; do 694213317Sgordon decho " $line" 2 695213317Sgordon case "$line" in 696213317Sgordon \#*) decho " Comment" 3 697213317Sgordon ;; 698213317Sgordon MANPATH*) decho " MANPATH" 3 699213317Sgordon trim "${line#MANPATH}" 700213317Sgordon add_to_manpath "$tstr" 701213317Sgordon ;; 702213317Sgordon MANLOCALE*) decho " MANLOCALE" 3 703213317Sgordon trim "${line#MANLOCALE}" 704213317Sgordon manlocales="$manlocales:$tstr" 705213317Sgordon ;; 706213317Sgordon MANCONFIG*) decho " MANCONFIG" 3 707222638Sru trim "${line#MANCONFIG}" 708213317Sgordon config_local="$tstr" 709213317Sgordon ;; 710213317Sgordon # Set variables in the form of FOO_BAR 711213317Sgordon *_*[\ \ ]*) var="${line%%[\ \ ]*}" 712213317Sgordon trim "${line#$var}" 713213317Sgordon eval "$var=\"$tstr\"" 714213317Sgordon decho " Parsed $var" 3 715213317Sgordon ;; 716213317Sgordon esac 717213317Sgordon done < "$file" 718213317Sgordon} 719213317Sgordon 720213317Sgordon# Usage: search_path 721213317Sgordon# Traverse $PATH looking for manpaths. 722213317Sgordonsearch_path() { 723213317Sgordon local IFS p path 724213317Sgordon 725213317Sgordon decho "Searching PATH for man directories" 726213317Sgordon 727213317Sgordon IFS=: 728213317Sgordon for path in $PATH; do 729213317Sgordon # Do a little special casing since the base manpages 730213317Sgordon # are in /usr/share/man instead of /usr/man or /man. 731213317Sgordon case "$path" in 732213317Sgordon /bin|/usr/bin) add_to_manpath "/usr/share/man" ;; 733213317Sgordon *) if add_to_manpath "$path/man"; then 734213317Sgordon : 735213317Sgordon elif add_to_manpath "$path/MAN"; then 736213317Sgordon : 737213317Sgordon else 738213317Sgordon case "$path" in 739213317Sgordon */bin) p="${path%/bin}/man" 740213317Sgordon add_to_manpath "$p" 741213317Sgordon ;; 742213317Sgordon *) ;; 743213317Sgordon esac 744213317Sgordon fi 745213317Sgordon ;; 746213317Sgordon esac 747213317Sgordon done 748213317Sgordon unset IFS 749213317Sgordon 750213317Sgordon if [ -z "$manpath" ]; then 751213317Sgordon decho ' Unable to find any manpaths, using default' 752213317Sgordon manpath=$man_default_path 753213317Sgordon fi 754213317Sgordon} 755213317Sgordon 756213317Sgordon# Usage: search_whatis cmd [arglist] 757213317Sgordon# Do the heavy lifting for apropos/whatis 758213317Sgordonsearch_whatis() { 759213317Sgordon local IFS bad cmd f good key keywords loc opt out path rval wlist 760213317Sgordon 761213317Sgordon cmd="$1" 762213317Sgordon shift 763213317Sgordon 764213317Sgordon whatis_parse_args "$@" 765213317Sgordon 766213317Sgordon build_manpath 767213317Sgordon build_manlocales 768213317Sgordon setup_pager 769213317Sgordon 770213317Sgordon if [ "$cmd" = "whatis" ]; then 771213317Sgordon opt="-w" 772213317Sgordon fi 773213317Sgordon 774213317Sgordon f='whatis' 775213317Sgordon 776213317Sgordon IFS=: 777213317Sgordon for path in $MANPATH; do 778213317Sgordon if [ \! -d "$path" ]; then 779213317Sgordon decho "Skipping non-existent path: $path" 2 780213317Sgordon continue 781213317Sgordon fi 782213317Sgordon 783213317Sgordon if [ -f "$path/$f" -a -r "$path/$f" ]; then 784213317Sgordon decho "Found whatis: $path/$f" 785213317Sgordon wlist="$wlist $path/$f" 786213317Sgordon fi 787213317Sgordon 788213317Sgordon for loc in $MANLOCALES; do 789213317Sgordon if [ -f "$path/$loc/$f" -a -r "$path/$loc/$f" ]; then 790213317Sgordon decho "Found whatis: $path/$loc/$f" 791213317Sgordon wlist="$wlist $path/$loc/$f" 792213317Sgordon fi 793213317Sgordon done 794213317Sgordon done 795213317Sgordon unset IFS 796213317Sgordon 797213317Sgordon if [ -z "$wlist" ]; then 798213317Sgordon echo "$cmd: no whatis databases in $MANPATH" >&2 799213317Sgordon exit 1 800213317Sgordon fi 801213317Sgordon 802213317Sgordon rval=0 803213317Sgordon for key in $keywords; do 804213317Sgordon out=$(grep -Ehi $opt -- "$key" $wlist) 805213317Sgordon if [ -n "$out" ]; then 806213317Sgordon good="$good\\n$out" 807213317Sgordon else 808213317Sgordon bad="$bad\\n$key: nothing appropriate" 809213317Sgordon rval=1 810213317Sgordon fi 811213317Sgordon done 812213317Sgordon 813213317Sgordon # Strip leading carriage return. 814213317Sgordon good=${good#\\n} 815213317Sgordon bad=${bad#\\n} 816213317Sgordon 817213317Sgordon if [ -n "$good" ]; then 818222653Sru echo -e "$good" | $MANPAGER 819213317Sgordon fi 820213317Sgordon 821213317Sgordon if [ -n "$bad" ]; then 822213349Sgordon echo -e "$bad" >&2 823213317Sgordon fi 824213317Sgordon 825213317Sgordon exit $rval 826213317Sgordon} 827213317Sgordon 828216140Sgordon# Usage: setup_cattool page 829216140Sgordon# Finds an appropriate decompressor based on extension 830216140Sgordonsetup_cattool() { 831216140Sgordon case "$1" in 832216140Sgordon *.bz) cattool='/usr/bin/bzcat' ;; 833216140Sgordon *.bz2) cattool='/usr/bin/bzcat' ;; 834216140Sgordon *.gz) cattool='/usr/bin/zcat' ;; 835216140Sgordon *.lzma) cattool='/usr/bin/lzcat' ;; 836216140Sgordon *.xz) cattool='/usr/bin/xzcat' ;; 837216140Sgordon *) cattool='/usr/bin/zcat -f' ;; 838216140Sgordon esac 839216140Sgordon} 840216140Sgordon 841213317Sgordon# Usage: setup_pager 842222653Sru# Correctly sets $MANPAGER 843213317Sgordonsetup_pager() { 844213317Sgordon # Setup pager. 845222653Sru if [ -z "$MANPAGER" ]; then 846222653Sru if [ -n "$MANCOLOR" ]; then 847222653Sru MANPAGER="less -sR" 848222653Sru else 849222653Sru if [ -n "$PAGER" ]; then 850222653Sru MANPAGER="$PAGER" 851222653Sru else 852222653Sru MANPAGER="more -s" 853222653Sru fi 854222653Sru fi 855213317Sgordon fi 856222653Sru decho "Using pager: $MANPAGER" 857213317Sgordon} 858213317Sgordon 859213317Sgordon# Usage: trim string 860213317Sgordon# Trims whitespace from beginning and end of a variable 861213317Sgordontrim() { 862213317Sgordon tstr=$1 863213317Sgordon while true; do 864213317Sgordon case "$tstr" in 865213317Sgordon [\ \ ]*) tstr="${tstr##[\ \ ]}" ;; 866213317Sgordon *[\ \ ]) tstr="${tstr%%[\ \ ]}" ;; 867213317Sgordon *) break ;; 868213317Sgordon esac 869213317Sgordon done 870213317Sgordon} 871213317Sgordon 872213317Sgordon# Usage: whatis_parse_args "$@" 873213317Sgordon# Parse commandline args for whatis and apropos. 874213317Sgordonwhatis_parse_args() { 875213317Sgordon local cmd_arg 876213317Sgordon while getopts 'd' cmd_arg; do 877213317Sgordon case "${cmd_arg}" in 878213317Sgordon d) debug=$(( $debug + 1 )) ;; 879213317Sgordon *) whatis_usage ;; 880213317Sgordon esac 881213317Sgordon done >&2 882213317Sgordon 883213317Sgordon shift $(( $OPTIND - 1 )) 884213317Sgordon 885213317Sgordon keywords="$*" 886213317Sgordon} 887213317Sgordon 888213317Sgordon# Usage: whatis_usage 889213317Sgordon# Display usage for the whatis/apropos utility. 890213317Sgordonwhatis_usage() { 891213317Sgordon echo "usage: $cmd [-d] keyword [...]" 892213317Sgordon exit 1 893213317Sgordon} 894213317Sgordon 895213317Sgordon 896213317Sgordon 897213317Sgordon# Supported commands 898213317Sgordondo_apropos() { 899213317Sgordon search_whatis apropos "$@" 900213317Sgordon} 901213317Sgordon 902213317Sgordondo_man() { 903213317Sgordon man_parse_args "$@" 904213317Sgordon if [ -z "$pages" ]; then 905213317Sgordon echo 'What manual page do you want?' >&2 906213317Sgordon exit 1 907213317Sgordon fi 908213317Sgordon man_setup 909213317Sgordon 910213317Sgordon for page in $pages; do 911213317Sgordon decho "Searching for $page" 912213317Sgordon man_find_and_display "$page" 913213317Sgordon done 914213317Sgordon 915213317Sgordon exit ${ret:-0} 916213317Sgordon} 917213317Sgordon 918213317Sgordondo_manpath() { 919213317Sgordon manpath_parse_args "$@" 920213317Sgordon if [ -z "$qflag" ]; then 921213317Sgordon manpath_warnings 922213317Sgordon fi 923213317Sgordon if [ -n "$Lflag" ]; then 924213317Sgordon build_manlocales 925213317Sgordon echo $MANLOCALES 926213317Sgordon else 927213317Sgordon build_manpath 928213317Sgordon echo $MANPATH 929213317Sgordon fi 930213317Sgordon exit 0 931213317Sgordon} 932213317Sgordon 933213317Sgordondo_whatis() { 934213317Sgordon search_whatis whatis "$@" 935213317Sgordon} 936213317Sgordon 937221303Suqs# User's PATH setting decides on the groff-suite to pick up. 938221303SuqsEQN=eqn 939222653SruNROFF='groff -S -P-h -Wall -mtty-char -man' 940221303SuqsPIC=pic 941221303SuqsREFER=refer 942221303SuqsTBL=tbl 943222601SuqsTROFF='groff -S -man' 944221303SuqsVGRIND=vgrind 945221303Suqs 946220261SgordonLOCALE=/usr/bin/locale 947222635SruSTTY=/bin/stty 948216426SgordonSYSCTL=/sbin/sysctl 949213317Sgordon 950213317Sgordondebug=0 951245514Sbrooksman_default_sections='1:8:2:3:n:4:5:6:7:9:l' 952213317Sgordonman_default_path='/usr/share/man:/usr/share/openssl/man:/usr/local/man' 953216140Sgordoncattool='/usr/bin/zcat -f' 954213317Sgordon 955213317Sgordonconfig_global='/etc/man.conf' 956213317Sgordon 957213317Sgordon# This can be overridden via a setting in /etc/man.conf. 958213317Sgordonconfig_local='/usr/local/etc/man.d/*.conf' 959213317Sgordon 960213317Sgordon# Set noglobbing for now. I don't want spurious globbing. 961213317Sgordonset -f 962213317Sgordon 963213317Sgordoncase "$0" in 964213317Sgordon*apropos) do_apropos "$@" ;; 965213317Sgordon*manpath) do_manpath "$@" ;; 966213317Sgordon*whatis) do_whatis "$@" ;; 967213317Sgordon*) do_man "$@" ;; 968213317Sgordonesac 969