Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
373 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,370 @@ | |||
#!/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§ion=$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 |