Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 371 lines (317 sloc) 7.92 KB
#!/bin/sh
#
# Fetch man pages for selected OS from a man page mirror.
# Copyright © 2004 Emre Sevinc <fz@ileriseviye.org>
# Tweaked by KIVILCIM "Sundance" Hindistan <sundance@fazlamesai.net>
# Lots of changes by Recai Oktaþ <roktas@debian.org>
#
# Licensed under the GNU General Public License, version 2.
# See the file `http://www.gnu.org/copyleft/gpl.txt'.
# ------------------------------------------------------------------------------
# Script constants
# ------------------------------------------------------------------------------
NAME=wman
THIS=${0##*/}
SYSTEM_CONF=/etc/${NAME}rc
USER_CONF=$HOME/.${NAME}rc
# ------------------------------------------------------------------------------
# Default setting for target OSes
# ------------------------------------------------------------------------------
DEFAULT_OPENBSD='
OSNAME=OpenBSD
HOST=http://www.openbsd.org
CGI=cgi-bin/man.cgi?query=$page&sektion=$sect&format=troff
FORMAT=raw
FAILURE=[Nn]o [Mm]anual [Ee]ntry
'
DEFAULT_FREEBSD='
OSNAME=FreeBSD
HOST=http://www.freebsd.org
CGI=cgi/man.cgi?query=$page&sektion=$sect&format=troff
FORMAT=html
FAILURE=^[Ss]orry
'
DEFAULT_NETBSD='
OSNAME=NetBSD
HOST=http://netbsd.gw.com
CGI=cgi-bin/man-cgi?$page+$sect
FORMAT=html
FILTER=DEFAULT_NETBSD_FILTER
FAILURE=[Mm]anual [Pp]age was not found
'
DEFAULT_NETBSD_FILTER () {
sed '/^-----/,$d'
}
DEFAULT_DRAGONFLY='
OSNAME=Dragonfly BSD
HOST=http://leaf.dragonflybsd.org
CGI=cgi/web-man?command=$page&section=$sect
FORMAT=html
FAILURE=[Mm]anual [Pp]age could not be found
'
DEFAULT_LINUX='
OSNAME=GNU/Linux
HOST=http://www.freebsd.org
CGI=cgi/man.cgi?query=$page&sektion=$sect&manpath=Red+Hat+Linux%2Fi386+9&format=troff
FORMAT=html
FAILURE=^[Ss]orry
'
# ------------------------------------------------------------------------------
# Helpers
# ------------------------------------------------------------------------------
# Portable which(1).
pathfind () {
ifs_save="$IFS"
IFS=:
for _p in $PATH; do
if [ -x "$_p/$*" ] && [ -f "$_p/$*" ]; then
IFS="$OLDIFS"
return 0
fi
done
IFS="$ifs_save"
return 1
}
dumper_raw () {
for p in wget lynx w3m curl links w3c; do
if pathfind $p; then
dumper=$p
break
fi
done
# Setup proper options.
case "$dumper" in
wget) opt="-O-" ;;
lynx) opt="-source" ;;
w3m) opt="-dump_source" ;;
curl) opt="" ;;
links) opt="-source" ;;
w3c) opt="-n -get" ;;
"") printf "Couldn't locate a program to fetch files from net " >&2
printf "(e.g. wget, w3m, lynx, w3c, or curl).\n" >&2
exit 1 ;;
esac
$dumper $opt "$@"
}
dumper_html () {
# TODO w3c
for p in w3m links elinks lynx; do
if pathfind $p; then
dumper=$p
break
fi
done
# Setup proper options.
case "$dumper" in
w3m) opt="-dump" ;;
links) opt="-dump" ;;
elinks) opt="-dump" ;;
lynx) opt="-dump" ;;
"") printf "Couldn't locate a program to fetch files from net " >&2
printf "(e.g. lynx, w3m, lynx or w3c).\n" >&2
exit 1 ;;
esac
$dumper $opt "$@"
}
is_cache_valid () {
cache="$1"
failstamp="$2"
if [ $(sed '/^[[:blank:]]*$/d' $cache | wc -l) -lt 20 ]; then
[ -z "$DEBUG" ] || echo >&2 "Fetched file is too small!"
return 1
fi
if sed '/^[[:blank:]]*$/d;{3q}' $cache | grep -q "$failstamp"; then
[ -z "$DEBUG" ] || echo >&2 "Failure stamp '$failstamp' seen!"
return 1
fi
return 0
}
# ------------------------------------------------------------------------------
# Init
# ------------------------------------------------------------------------------
LC_ALL=C
export LC_ALL
for conf in $SYSTEM_CONF $USER_CONF; do
# Read user conf file.
if [ -r $conf ]; then
case $- in
*e*) ;;
*) set -e; noexitonerr=yes ;;
esac
trap "Error in configuration file $conf; aborting." QUIT INT
. $conf
trap - QUIT INT
if [ -n "$noexitonerr" ]; then
set +e
fi
fi
done
OS=
DEBUG=${DEBUG-}
CACHE_RENEW=
while getopts o:dhn opt; do
case $opt in
o) OS="$OPTARG" ;;
d) DEBUG=yes ;;
r) CACHE_RENEW=yes ;;
h) cat >&2 <<- EOF
Usage: $THIS [options] [section] page
Options:
-o os_name operating system (e.g. openbsd, netbsd)
-d print debug info
-n renew cache
-h this screen
EOF
exit 2 ;;
esac
done
shift $(($OPTIND - 1))
if [ -z "$OS" ] && ! [ "$THIS" = "$NAME" ]; then
OS=$(echo "$THIS" | sed 's/^man[-_+]//')
else
DEFAULT_OS=${DEFAULT_OS:-$(uname)}
OS=${OS:-$DEFAULT_OS}
fi
if [ -z "$OS" ]; then
echo "Couldn't determine OS; aborting"
exit 1
fi
OS=$(echo $OS | tr 'a-z' 'A-Z')
# Defaults for some global settings.
PAGER=${PAGER-less}
DEBUG=${DEBUG:-}
CACHEROOT=${CACHEROOT-$HOME/.$THIS}
if [ $# -eq 0 ]; then
echo >&2 "What manual page do you want?"
exit 1
fi
sect=
case "$1" in
[1-9])
sect=$1
shift
if [ -z "$1" ]; then
echo >&2 "What manual page do you want from section ${sect}?"
exit 1
fi
;;
esac
page="$1"
NEWLINE='
'
OLDIFS="$IFS"
_expand_variable () {
condensed=${1:?'variable empty!'}
eval "this=\$$condensed"
# Expand page and sect.
eval "this=\"$this\""
IFS="$NEWLINE"
for line in $this; do
IFS="$OLDIFS"
var="${line%%=*}"
val="${line#[!=]*=}"
case "$var" in
'OSNAME'|'HOST'|'CGI'|'FORMAT'|'FILTER'|'FAILURE')
var="man_$(echo $var | tr 'A-Z' 'a-z')"
eval "$var=\${$var:-$val}" ;;
*)
continue ;;
esac
done
}
# User settings.
_expand_variable "$OS"
# Builtin default settings.
_expand_variable "DEFAULT_$OS"
man_url="$man_host/$man_cgi"
man_dumper="dumper_$man_format"
man_osname="${man_osname:-$(echo $OS | tr 'A-Z' 'a-z')}"
[ -z "$DEBUG" ] || cat >&2 <<- EOF
Fetch parameters:
OS: $man_osname
Page: $page
Section: $sect
Host: $man_host
CGI: $man_cgi
Format: $man_format
Dumper: $man_dumper
Filter: $man_filter
Failure: '$man_failure'
Resulting url: $man_url
EOF
( eval $man_dumper </dev/null >/dev/null 2>&1 )
if [ $? -eq 127 ]; then
echo >&2 "No such '$man_format' dumper for '$OS'; aborting"
exit 1
fi
if [ -n "$man_filter" ]; then
( eval $man_filter </dev/null >/dev/null 2>&1 )
if [ $? -eq 127 ]; then
echo >&2 "No such '$man_filter' for '$OS'; aborting"
exit 1
fi
else
man_filter=cat
fi
# ... now cache variables
cachedir=$CACHEROOT/$(echo $OS | tr 'A-Z' 'a-z')
man_cache=$cachedir/$page.${sect:-0} # use 0 to catch the default man page
# ------------------------------------------------------------------------------
# Main
# ------------------------------------------------------------------------------
if [ -n "$CACHE_RENEW" ] || {
[ -f $man_cache ] && ! is_cache_valid $man_cache "$man_failure"
}; then
rm -f $man_cache
fi
what="$man_osname manual entry for $page"
if [ -n "$sect" ]; then
what="$what in section $sect"
fi
if ! [ -f $man_cache ]; then
# Initiate cache if it doesn't exist.
(umask 0077 && mkdir -p $cachedir)
tmpfile="$(mktemp $cachedir/$THIS.XXXXXXXX)" || exit 1
# Remove partial files.
trap 'exitcode=$?
[ -z "$tmpfile" ] || rm -rf "$tmpfile"
exit $exitcode' 0 1 2 3 13 15
printf "Querying $what... " >&2
if $man_dumper "$man_url" 2>/dev/null | sed '/./,$!d' >$tmpfile; then
if is_cache_valid $tmpfile "$man_failure"; then
echo "success."
mv -f $tmpfile $man_cache && tmpfile=
else
echo "failed."
fi >&2
else
echo >&2 "fetch failed."
fi
fi
if ! [ -f $man_cache ]; then
echo >&2 "No $what."
exit 1
fi
# Attempt to reduce cache space whenever a section is explicitly given.
# Note that we avoid to extract the section info from cache file, since
# this might be unreliable for some formats and also it would increase
# the code complexity.
if [ "$sect" != "0" ]; then
man_fallback=$cachedir/$page.0
if [ -f $man_fallback ] && ! [ -L $man_fallback ]; then
(
cd $cachedir
# Search for an idantic file.
found=
for f in $page.[1-9]; do
if cmp -s $f $man_fallback; then
found=$f
break
fi
done
# If found, symlink it to sectioned file to reduce space.
[ -z "$found" ] || ln -sf $found $man_fallback
)
fi
fi
$man_filter <$man_cache | $PAGER