man.sh revision 278650
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: stable/10/usr.bin/man/man.sh 278650 2015-02-13 00:29:57Z sbruno $ 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 [ -n "${use_width}" ]; then 116 # non-standard width 117 unset use_cat 118 decho " Skipping catpage: non-standard page width" 119 elif exists "$2" && is_newer $found $manpage; then 120 # cat page found and is newer, use that 121 use_cat=yes 122 catpage=$found 123 setup_cattool $catpage 124 decho " Using catpage $catpage" 125 else 126 # no cat page or is older 127 unset use_cat 128 decho " Skipping catpage: not found or old" 129 fi 130 return 0 131 fi 132 133 return 1 134} 135 136# Usage: decho "string" [debuglevel] 137# Echoes to stderr string prefaced with -- if high enough debuglevel. 138decho() { 139 if [ $debug -ge ${2:-1} ]; then 140 echo "-- $1" >&2 141 fi 142} 143 144# Usage: exists glob 145# Returns true if glob resolves to a real file. 146exists() { 147 local IFS 148 149 # Don't accidentally inherit callers IFS (breaks perl manpages) 150 unset IFS 151 152 # Use some globbing tricks in the shell to determine if a file 153 # exists or not. 154 set +f 155 set -- "$1" $1 156 set -f 157 158 if [ "$1" != "$2" -a -r "$2" ]; then 159 found="$2" 160 return 0 161 fi 162 163 return 1 164} 165 166# Usage: find_file path section subdir pagename 167# Returns: true if something is matched and found. 168# Search the given path/section combo for a given page. 169find_file() { 170 local manroot catroot mann man0 catn cat0 171 172 manroot="$1/man$2" 173 catroot="$1/cat$2" 174 if [ -n "$3" ]; then 175 manroot="$manroot/$3" 176 catroot="$catroot/$3" 177 fi 178 179 if [ ! -d "$manroot" ]; then 180 return 1 181 fi 182 decho " Searching directory $manroot" 2 183 184 mann="$manroot/$4.$2*" 185 man0="$manroot/$4.0*" 186 catn="$catroot/$4.$2*" 187 cat0="$catroot/$4.0*" 188 189 # This is the behavior as seen by the original man utility. 190 # Let's not change that which doesn't seem broken. 191 if check_man "$mann" "$catn"; then 192 return 0 193 elif check_man "$man0" "$cat0"; then 194 return 0 195 elif check_cat "$catn"; then 196 return 0 197 elif check_cat "$cat0"; then 198 return 0 199 fi 200 201 return 1 202} 203 204# Usage: is_newer file1 file2 205# Returns true if file1 is newer than file2 as calculated by mtime. 206is_newer() { 207 if ! [ "$1" -ot "$2" ]; then 208 decho " mtime: $1 not older than $2" 3 209 return 0 210 else 211 decho " mtime: $1 older than $2" 3 212 return 1 213 fi 214} 215 216# Usage: manpath_parse_args "$@" 217# Parses commandline options for manpath. 218manpath_parse_args() { 219 local cmd_arg 220 221 while getopts 'Ldq' cmd_arg; do 222 case "${cmd_arg}" in 223 L) Lflag=Lflag ;; 224 d) debug=$(( $debug + 1 )) ;; 225 q) qflag=qflag ;; 226 *) manpath_usage ;; 227 esac 228 done >&2 229} 230 231# Usage: manpath_usage 232# Display usage for the manpath(1) utility. 233manpath_usage() { 234 echo 'usage: manpath [-Ldq]' >&2 235 exit 1 236} 237 238# Usage: manpath_warnings 239# Display some warnings to stderr. 240manpath_warnings() { 241 if [ -z "$Lflag" -a -n "$MANPATH" ]; then 242 echo "(Warning: MANPATH environment variable set)" >&2 243 fi 244 245 if [ -n "$Lflag" -a -n "$MANLOCALES" ]; then 246 echo "(Warning: MANLOCALES environment variable set)" >&2 247 fi 248} 249 250# Usage: man_check_for_so page path 251# Returns: True if able to resolve the file, false if it ended in tears. 252# Detects the presence of the .so directive and causes the file to be 253# redirected to another source file. 254man_check_for_so() { 255 local IFS line tstr 256 257 unset IFS 258 259 # We need to loop to accommodate multiple .so directives. 260 while true 261 do 262 line=$($cattool $manpage | head -1) 263 case "$line" in 264 .so*) trim "${line#.so}" 265 decho "$manpage includes $tstr" 266 # Glob and check for the file. 267 if ! check_man "$path/$tstr*" ""; then 268 decho " Unable to find $tstr" 269 return 1 270 fi 271 ;; 272 *) break ;; 273 esac 274 done 275 276 return 0 277} 278 279man_display_page() { 280 local IFS pipeline preconv_enc testline 281 282 # We are called with IFS set to colon. This causes really weird 283 # things to happen for the variables that have spaces in them. 284 unset IFS 285 286 # If we are supposed to use a catpage and we aren't using troff(1) 287 # just zcat the catpage and we are done. 288 if [ -z "$tflag" -a -n "$use_cat" ]; then 289 if [ -n "$wflag" ]; then 290 echo "$catpage (source: $manpage)" 291 ret=0 292 else 293 if [ $debug -gt 0 ]; then 294 decho "Command: $cattool $catpage | $MANPAGER" 295 ret=0 296 else 297 eval "$cattool $catpage | $MANPAGER" 298 ret=$? 299 fi 300 fi 301 return 302 fi 303 304 # Okay, we are using the manpage, do we just need to output the 305 # name of the manpage? 306 if [ -n "$wflag" ]; then 307 echo "$manpage" 308 ret=0 309 return 310 fi 311 312 case "${manpage}" in 313 *.${man_charset}/*) 314 case "$man_charset" in 315 ISO8859-1) preconv_enc="latin-1" ;; 316 ISO8859-15) preconv_enc="latin-1" ;; 317 UTF-8) preconv_enc="utf-8" ;; 318 esac 319 ;; 320 esac 321 322 if [ -n "$preconv_enc" ]; then 323 pipeline="preconv -e $preconv_enc |" 324 fi 325 testline="$pipeline mandoc -Tlint -Werror 2>/dev/null" 326 pipeline="$pipeline mandoc -Tlocale | $MANPAGER" 327 328 if ! eval "$cattool $manpage | $testline" ;then 329 if which -s groff2; then 330 man_display_page_groff 331 else 332 echo "This manpage needs groff(1) to be rendered" >&2 333 echo "First install groff(1): " >&2 334 echo "pkg install groff " >&2 335 ret=1 336 fi 337 return 338 fi 339 340 if [ $debug -gt 0 ]; then 341 decho "Command: $cattool $manpage | $pipeline" 342 ret=0 343 else 344 eval "$cattool $manpage | $pipeline" 345 ret=$? 346 fi 347} 348 349# Usage: man_display_page 350# Display either the manpage or catpage depending on the use_cat variable 351man_display_page_groff() { 352 local EQN NROFF PIC TBL TROFF REFER VGRIND 353 local IFS l nroff_dev pipeline preproc_arg tool 354 355 # So, we really do need to parse the manpage. First, figure out the 356 # device flag (-T) we have to pass to eqn(1) and groff(1). Then, 357 # setup the pipeline of commands based on the user's request. 358 359 # If the manpage is from a particular charset, we need to setup nroff 360 # to properly output for the correct device. 361 case "${manpage}" in 362 *.${man_charset}/*) 363 # I don't pretend to know this; I'm just copying from the 364 # previous version of man(1). 365 case "$man_charset" in 366 KOI8-R) nroff_dev="koi8-r" ;; 367 ISO8859-1) nroff_dev="latin1" ;; 368 ISO8859-15) nroff_dev="latin1" ;; 369 UTF-8) nroff_dev="utf8" ;; 370 *) nroff_dev="ascii" ;; 371 esac 372 373 NROFF="$NROFF -T$nroff_dev" 374 EQN="$EQN -T$nroff_dev" 375 376 # Iff the manpage is from the locale and not just the charset, 377 # then we need to define the locale string. 378 case "${manpage}" in 379 */${man_lang}_${man_country}.${man_charset}/*) 380 NROFF="$NROFF -dlocale=$man_lang.$man_charset" 381 ;; 382 */${man_lang}.${man_charset}/*) 383 NROFF="$NROFF -dlocale=$man_lang.$man_charset" 384 ;; 385 esac 386 387 # Allow language specific calls to override the default 388 # set of utilities. 389 l=$(echo $man_lang | tr [:lower:] [:upper:]) 390 for tool in EQN NROFF PIC TBL TROFF REFER VGRIND; do 391 eval "$tool=\${${tool}_$l:-\$$tool}" 392 done 393 ;; 394 *) NROFF="$NROFF -Tascii" 395 EQN="$EQN -Tascii" 396 ;; 397 esac 398 399 if [ -z "$MANCOLOR" ]; then 400 NROFF="$NROFF -P-c" 401 fi 402 403 if [ -n "${use_width}" ]; then 404 NROFF="$NROFF -rLL=${use_width}n -rLT=${use_width}n" 405 fi 406 407 if [ -n "$MANROFFSEQ" ]; then 408 set -- -$MANROFFSEQ 409 while getopts 'egprtv' preproc_arg; do 410 case "${preproc_arg}" in 411 e) pipeline="$pipeline | $EQN" ;; 412 g) ;; # Ignore for compatibility. 413 p) pipeline="$pipeline | $PIC" ;; 414 r) pipeline="$pipeline | $REFER" ;; 415 t) pipeline="$pipeline | $TBL" ;; 416 v) pipeline="$pipeline | $VGRIND" ;; 417 *) usage ;; 418 esac 419 done 420 # Strip the leading " | " from the resulting pipeline. 421 pipeline="${pipeline#" | "}" 422 else 423 pipeline="$TBL" 424 fi 425 426 if [ -n "$tflag" ]; then 427 pipeline="$pipeline | $TROFF" 428 else 429 pipeline="$pipeline | $NROFF | $MANPAGER" 430 fi 431 432 if [ $debug -gt 0 ]; then 433 decho "Command: $cattool $manpage | $pipeline" 434 ret=0 435 else 436 eval "$cattool $manpage | $pipeline" 437 ret=$? 438 fi 439} 440 441# Usage: man_find_and_display page 442# Search through the manpaths looking for the given page. 443man_find_and_display() { 444 local found_page locpath p path sect 445 446 # Check to see if it's a file. But only if it has a '/' in 447 # the filename. 448 case "$1" in 449 */*) if [ -f "$1" -a -r "$1" ]; then 450 decho "Found a usable page, displaying that" 451 unset use_cat 452 manpage="$1" 453 setup_cattool $manpage 454 if man_check_for_so $manpage $(dirname $manpage); then 455 found_page=yes 456 man_display_page 457 fi 458 return 459 fi 460 ;; 461 esac 462 463 IFS=: 464 for sect in $MANSECT; do 465 decho "Searching section $sect" 2 466 for path in $MANPATH; do 467 for locpath in $locpaths; do 468 p=$path/$locpath 469 p=${p%/.} # Rid ourselves of the trailing /. 470 471 # Check if there is a MACHINE specific manpath. 472 if find_file $p $sect $MACHINE "$1"; then 473 if man_check_for_so $manpage $p; then 474 found_page=yes 475 man_display_page 476 if [ -n "$aflag" ]; then 477 continue 2 478 else 479 return 480 fi 481 fi 482 fi 483 484 # Check if there is a MACHINE_ARCH 485 # specific manpath. 486 if find_file $p $sect $MACHINE_ARCH "$1"; then 487 if man_check_for_so $manpage $p; then 488 found_page=yes 489 man_display_page 490 if [ -n "$aflag" ]; then 491 continue 2 492 else 493 return 494 fi 495 fi 496 fi 497 498 # Check plain old manpath. 499 if find_file $p $sect '' "$1"; then 500 if man_check_for_so $manpage $p; then 501 found_page=yes 502 man_display_page 503 if [ -n "$aflag" ]; then 504 continue 2 505 else 506 return 507 fi 508 fi 509 fi 510 done 511 done 512 done 513 unset IFS 514 515 # Nothing? Well, we are done then. 516 if [ -z "$found_page" ]; then 517 echo "No manual entry for $1" >&2 518 ret=1 519 return 520 fi 521} 522 523# Usage: man_parse_args "$@" 524# Parses commandline options for man. 525man_parse_args() { 526 local IFS cmd_arg 527 528 while getopts 'M:P:S:adfhkm:op:tw' cmd_arg; do 529 case "${cmd_arg}" in 530 M) MANPATH=$OPTARG ;; 531 P) MANPAGER=$OPTARG ;; 532 S) MANSECT=$OPTARG ;; 533 a) aflag=aflag ;; 534 d) debug=$(( $debug + 1 )) ;; 535 f) fflag=fflag ;; 536 h) man_usage 0 ;; 537 k) kflag=kflag ;; 538 m) mflag=$OPTARG ;; 539 o) oflag=oflag ;; 540 p) MANROFFSEQ=$OPTARG ;; 541 t) tflag=tflag ;; 542 w) wflag=wflag ;; 543 *) man_usage ;; 544 esac 545 done >&2 546 547 shift $(( $OPTIND - 1 )) 548 549 # Check the args for incompatible options. 550 case "${fflag}${kflag}${tflag}${wflag}" in 551 fflagkflag*) echo "Incompatible options: -f and -k"; man_usage ;; 552 fflag*tflag*) echo "Incompatible options: -f and -t"; man_usage ;; 553 fflag*wflag) echo "Incompatible options: -f and -w"; man_usage ;; 554 *kflagtflag*) echo "Incompatible options: -k and -t"; man_usage ;; 555 *kflag*wflag) echo "Incompatible options: -k and -w"; man_usage ;; 556 *tflagwflag) echo "Incompatible options: -t and -w"; man_usage ;; 557 esac 558 559 # Short circuit for whatis(1) and apropos(1) 560 if [ -n "$fflag" ]; then 561 do_whatis "$@" 562 exit 563 fi 564 565 if [ -n "$kflag" ]; then 566 do_apropos "$@" 567 exit 568 fi 569 570 IFS=: 571 for sect in $man_default_sections; do 572 if [ "$sect" = "$1" ]; then 573 decho "Detected manual section as first arg: $1" 574 MANSECT="$1" 575 shift 576 break 577 fi 578 done 579 unset IFS 580 581 pages="$*" 582} 583 584# Usage: man_setup 585# Setup various trivial but essential variables. 586man_setup() { 587 # Setup machine and architecture variables. 588 if [ -n "$mflag" ]; then 589 MACHINE_ARCH=${mflag%%:*} 590 MACHINE=${mflag##*:} 591 fi 592 if [ -z "$MACHINE_ARCH" ]; then 593 MACHINE_ARCH=$($SYSCTL -n hw.machine_arch) 594 fi 595 if [ -z "$MACHINE" ]; then 596 MACHINE=$($SYSCTL -n hw.machine) 597 fi 598 decho "Using architecture: $MACHINE_ARCH:$MACHINE" 599 600 setup_pager 601 602 # Setup manual sections to search. 603 if [ -z "$MANSECT" ]; then 604 MANSECT=$man_default_sections 605 fi 606 decho "Using manual sections: $MANSECT" 607 608 build_manpath 609 man_setup_locale 610 man_setup_width 611} 612 613# Usage: man_setup_width 614# Set up page width. 615man_setup_width() { 616 local sizes 617 618 unset use_width 619 case "$MANWIDTH" in 620 [0-9]*) 621 if [ "$MANWIDTH" -gt 0 2>/dev/null ]; then 622 use_width=$MANWIDTH 623 fi 624 ;; 625 [Tt][Tt][Yy]) 626 if { sizes=$($STTY size 0>&3 2>/dev/null); } 3>&1; then 627 set -- $sizes 628 if [ $2 -gt 80 ]; then 629 use_width=$(($2-2)) 630 fi 631 fi 632 ;; 633 esac 634 if [ -n "$use_width" ]; then 635 decho "Using non-standard page width: ${use_width}" 636 else 637 decho 'Using standard page width' 638 fi 639} 640 641# Usage: man_setup_locale 642# Setup necessary locale variables. 643man_setup_locale() { 644 local lang_cc 645 646 locpaths='.' 647 man_charset='US-ASCII' 648 649 # Setup locale information. 650 if [ -n "$oflag" ]; then 651 decho 'Using non-localized manpages' 652 else 653 # Use the locale tool to give us the proper LC_CTYPE 654 eval $( $LOCALE ) 655 656 case "$LC_CTYPE" in 657 C) ;; 658 POSIX) ;; 659 [a-z][a-z]_[A-Z][A-Z]\.*) 660 lang_cc="${LC_CTYPE%.*}" 661 man_lang="${LC_CTYPE%_*}" 662 man_country="${lang_cc#*_}" 663 man_charset="${LC_CTYPE#*.}" 664 locpaths="$LC_CTYPE" 665 locpaths="$locpaths:$man_lang.$man_charset" 666 if [ "$man_lang" != "en" ]; then 667 locpaths="$locpaths:en.$man_charset" 668 fi 669 locpaths="$locpaths:." 670 ;; 671 *) echo 'Unknown locale, assuming C' >&2 672 ;; 673 esac 674 fi 675 676 decho "Using locale paths: $locpaths" 677} 678 679# Usage: man_usage [exitcode] 680# Display usage for the man utility. 681man_usage() { 682 echo 'Usage:' 683 echo ' man [-adho] [-t | -w] [-M manpath] [-P pager] [-S mansect]' 684 echo ' [-m arch[:machine]] [-p [eprtv]] [mansect] page [...]' 685 echo ' man -f page [...] -- Emulates whatis(1)' 686 echo ' man -k page [...] -- Emulates apropos(1)' 687 688 # When exit'ing with -h, it's not an error. 689 exit ${1:-1} 690} 691 692# Usage: parse_configs 693# Reads the end-user adjustable config files. 694parse_configs() { 695 local IFS file files 696 697 if [ -n "$parsed_configs" ]; then 698 return 699 fi 700 701 unset IFS 702 703 # Read the global config first in case the user wants 704 # to override config_local. 705 if [ -r "$config_global" ]; then 706 parse_file "$config_global" 707 fi 708 709 # Glob the list of files to parse. 710 set +f 711 files=$(echo $config_local) 712 set -f 713 714 for file in $files; do 715 if [ -r "$file" ]; then 716 parse_file "$file" 717 fi 718 done 719 720 parsed_configs='yes' 721} 722 723# Usage: parse_file file 724# Reads the specified config files. 725parse_file() { 726 local file line tstr var 727 728 file="$1" 729 decho "Parsing config file: $file" 730 while read line; do 731 decho " $line" 2 732 case "$line" in 733 \#*) decho " Comment" 3 734 ;; 735 MANPATH*) decho " MANPATH" 3 736 trim "${line#MANPATH}" 737 add_to_manpath "$tstr" 738 ;; 739 MANLOCALE*) decho " MANLOCALE" 3 740 trim "${line#MANLOCALE}" 741 manlocales="$manlocales:$tstr" 742 ;; 743 MANCONFIG*) decho " MANCONFIG" 3 744 trim "${line#MANCONFIG}" 745 config_local="$tstr" 746 ;; 747 # Set variables in the form of FOO_BAR 748 *_*[\ \ ]*) var="${line%%[\ \ ]*}" 749 trim "${line#$var}" 750 eval "$var=\"$tstr\"" 751 decho " Parsed $var" 3 752 ;; 753 esac 754 done < "$file" 755} 756 757# Usage: search_path 758# Traverse $PATH looking for manpaths. 759search_path() { 760 local IFS p path 761 762 decho "Searching PATH for man directories" 763 764 IFS=: 765 for path in $PATH; do 766 # Do a little special casing since the base manpages 767 # are in /usr/share/man instead of /usr/man or /man. 768 case "$path" in 769 /bin|/usr/bin) add_to_manpath "/usr/share/man" ;; 770 *) if add_to_manpath "$path/man"; then 771 : 772 elif add_to_manpath "$path/MAN"; then 773 : 774 else 775 case "$path" in 776 */bin) p="${path%/bin}/man" 777 add_to_manpath "$p" 778 ;; 779 *) ;; 780 esac 781 fi 782 ;; 783 esac 784 done 785 unset IFS 786 787 if [ -z "$manpath" ]; then 788 decho ' Unable to find any manpaths, using default' 789 manpath=$man_default_path 790 fi 791} 792 793# Usage: search_whatis cmd [arglist] 794# Do the heavy lifting for apropos/whatis 795search_whatis() { 796 local IFS bad cmd f good key keywords loc opt out path rval wlist 797 798 cmd="$1" 799 shift 800 801 whatis_parse_args "$@" 802 803 build_manpath 804 build_manlocales 805 setup_pager 806 807 if [ "$cmd" = "whatis" ]; then 808 opt="-w" 809 fi 810 811 f='whatis' 812 813 IFS=: 814 for path in $MANPATH; do 815 if [ \! -d "$path" ]; then 816 decho "Skipping non-existent path: $path" 2 817 continue 818 fi 819 820 if [ -f "$path/$f" -a -r "$path/$f" ]; then 821 decho "Found whatis: $path/$f" 822 wlist="$wlist $path/$f" 823 fi 824 825 for loc in $MANLOCALES; do 826 if [ -f "$path/$loc/$f" -a -r "$path/$loc/$f" ]; then 827 decho "Found whatis: $path/$loc/$f" 828 wlist="$wlist $path/$loc/$f" 829 fi 830 done 831 done 832 unset IFS 833 834 if [ -z "$wlist" ]; then 835 echo "$cmd: no whatis databases in $MANPATH" >&2 836 exit 1 837 fi 838 839 rval=0 840 for key in $keywords; do 841 out=$(grep -Ehi $opt -- "$key" $wlist) 842 if [ -n "$out" ]; then 843 good="$good\\n$out" 844 else 845 bad="$bad\\n$key: nothing appropriate" 846 rval=1 847 fi 848 done 849 850 # Strip leading carriage return. 851 good=${good#\\n} 852 bad=${bad#\\n} 853 854 if [ -n "$good" ]; then 855 echo -e "$good" | $MANPAGER 856 fi 857 858 if [ -n "$bad" ]; then 859 echo -e "$bad" >&2 860 fi 861 862 exit $rval 863} 864 865# Usage: setup_cattool page 866# Finds an appropriate decompressor based on extension 867setup_cattool() { 868 case "$1" in 869 *.bz) cattool='/usr/bin/bzcat' ;; 870 *.bz2) cattool='/usr/bin/bzcat' ;; 871 *.gz) cattool='/usr/bin/zcat' ;; 872 *.lzma) cattool='/usr/bin/lzcat' ;; 873 *.xz) cattool='/usr/bin/xzcat' ;; 874 *) cattool='/usr/bin/zcat -f' ;; 875 esac 876} 877 878# Usage: setup_pager 879# Correctly sets $MANPAGER 880setup_pager() { 881 # Setup pager. 882 if [ -z "$MANPAGER" ]; then 883 if [ -n "$MANCOLOR" ]; then 884 MANPAGER="less -sR" 885 else 886 if [ -n "$PAGER" ]; then 887 MANPAGER="$PAGER" 888 else 889 MANPAGER="more -s" 890 fi 891 fi 892 fi 893 decho "Using pager: $MANPAGER" 894} 895 896# Usage: trim string 897# Trims whitespace from beginning and end of a variable 898trim() { 899 tstr=$1 900 while true; do 901 case "$tstr" in 902 [\ \ ]*) tstr="${tstr##[\ \ ]}" ;; 903 *[\ \ ]) tstr="${tstr%%[\ \ ]}" ;; 904 *) break ;; 905 esac 906 done 907} 908 909# Usage: whatis_parse_args "$@" 910# Parse commandline args for whatis and apropos. 911whatis_parse_args() { 912 local cmd_arg 913 while getopts 'd' cmd_arg; do 914 case "${cmd_arg}" in 915 d) debug=$(( $debug + 1 )) ;; 916 *) whatis_usage ;; 917 esac 918 done >&2 919 920 shift $(( $OPTIND - 1 )) 921 922 keywords="$*" 923} 924 925# Usage: whatis_usage 926# Display usage for the whatis/apropos utility. 927whatis_usage() { 928 echo "usage: $cmd [-d] keyword [...]" 929 exit 1 930} 931 932 933 934# Supported commands 935do_apropos() { 936 search_whatis apropos "$@" 937} 938 939do_man() { 940 man_parse_args "$@" 941 if [ -z "$pages" ]; then 942 echo 'What manual page do you want?' >&2 943 exit 1 944 fi 945 man_setup 946 947 for page in $pages; do 948 decho "Searching for $page" 949 man_find_and_display "$page" 950 done 951 952 exit ${ret:-0} 953} 954 955do_manpath() { 956 manpath_parse_args "$@" 957 if [ -z "$qflag" ]; then 958 manpath_warnings 959 fi 960 if [ -n "$Lflag" ]; then 961 build_manlocales 962 echo $MANLOCALES 963 else 964 build_manpath 965 echo $MANPATH 966 fi 967 exit 0 968} 969 970do_whatis() { 971 search_whatis whatis "$@" 972} 973 974# User's PATH setting decides on the groff-suite to pick up. 975EQN=eqn 976NROFF='groff -S -P-h -Wall -mtty-char -man' 977PIC=pic 978REFER=refer 979TBL=tbl 980TROFF='groff -S -man' 981VGRIND=vgrind 982 983LOCALE=/usr/bin/locale 984STTY=/bin/stty 985SYSCTL=/sbin/sysctl 986 987debug=0 988man_default_sections='1:8:2:3:n:4:5:6:7:9:l' 989man_default_path='/usr/share/man:/usr/share/openssl/man:/usr/local/man' 990cattool='/usr/bin/zcat -f' 991 992config_global='/etc/man.conf' 993 994# This can be overridden via a setting in /etc/man.conf. 995config_local='/usr/local/etc/man.d/*.conf' 996 997# Set noglobbing for now. I don't want spurious globbing. 998set -f 999 1000case "$0" in 1001*apropos) do_apropos "$@" ;; 1002*manpath) do_manpath "$@" ;; 1003*whatis) do_whatis "$@" ;; 1004*) do_man "$@" ;; 1005esac 1006