Viewing file: groffer (112.28 KB) -rwxr-xr-x Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |#!/bin/sh
# groffer - display groff files
# Source file position: /contrib/groffer/groffer.sh
# Copyright (C) 2001,2002,2003,2004 Free Software Foundation, Inc.
# Written by Bernd Warken
# This file is part of groff version 1.18.1.1.
# groff is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# groff is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
# You should have received a copy of the GNU General Public License
# along with groff; see the files COPYING and LICENSE in the top
# directory of the groff source. If not, write to the Free Software
# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
_PROGRAM_NAME='groffer';
_PROGRAM_VERSION='0.9.11';
_LAST_UPDATE='15 June 2004';
########################################################################
# Determine the shell under which to run this script from the command
# line arguments or $GROFF_OPT; if none is specified, just go on with
# the starting shell.
if test _"${_groffer_run}"_ = __; then
# only reached during the first run of the script
export _groffer_run; # counter for the runs of groffer
_groffer_run='first';
export _PROGRAM_NAME;
export _PROGRAM_VERSION;
export _LAST_UPDATE;
export GROFFER_OPT; # option environment for groffer
export _GROFFER_SH; # file name of this shell script
export _OUTPUT_FILE_NAME; # output generated, see main_set_res..()
export _CONFFILES; # configuration files
_CONFFILES="/etc/groff/groffer.conf ${HOME}/.groff/groffer.conf";
case "$0" in
*${_PROGRAM_NAME}*)
_GROFFER_SH="$0";
# was: _GROFFER_SH="/usr/bin/${_PROGRAM_NAME}";
;;
*)
echo "The ${_PROGRAM_NAME} script should be started directly." >&2
exit 1;
;;
esac;
###########################
# _get_opt_shell ("$@")
#
# Determine whether `--shell' was specified in $GROFF_OPT or in $*;
# if so echo its argument.
#
_get_opt_shell()
{
local i;
local _sh;
case " ${GROFFER_OPT} $*" in
*\ --shell\ *|*\ --shell=*)
(
eval set -- "${GROFFER_OPT}" '"$@"';
_sh='';
for i in "$@"; do
case "$1" in
--shell)
if test "$#" -ge 2; then
_sh="$2";
shift;
fi;
;;
--shell=?*)
# delete up to first `=' character
_sh="$(echo -n "$1" | sed -e 's/^[^=]*=//')";
;;
esac;
shift;
done;
echo -n "${_sh}";
)
;;
esac;
}
###########################
# _test_on_shell ()
#
# Test whether is a shell program of Bourne type (POSIX sh).
#
_test_on_shell()
{
if test "$#" -le 0 || test _"$1"_ = __; then
return 1;
fi;
# do not quote $1 to allow arguments
test _"$($1 -c 's=ok; echo -n "$s"' 2>/dev/null)"_ = _ok_;
}
# do the shell determination from command line and $GROFFER_OPT
_shell="$(_get_opt_shell "$@")";
if test _"${_shell}"_ = __; then
# none found, so look at the `--shell' lines in configuration files
export f;
for f in ${_CONFFILES}; do
if test -f $f; then
_all="$(cat $f | sed -n -e '/^--shell[= ] *\([^ ]*\)$/s//\1/p')"
for s in ${_all}; do
_shell=$s;
done;
fi;
done;
unset f;
unset s;
unset _all;
fi;
# restart the script with the last found $_shell, if it is a shell
if _test_on_shell "${_shell}"; then
_groffer_run='second';
# do not quote $_shell to allow arguments
exec ${_shell} "${_GROFFER_SH}" "$@";
exit;
fi;
_groffer_run='second';
unset _shell;
fi; # end of first run
if test _"${_groffer_run}"_ != _second_;
then
echo "$_groffer_run should be 'second' here." >&2
exit 1
fi;
unset _groffer_run
########################################################################
# diagnostic messages
#
export _DEBUG;
_DEBUG='no'; # disable debugging information
#_DEBUG='yes'; # enable debugging information
export _DEBUG_LM;
_DEBUG_LM='no'; # disable landmark messages
#_DEBUG_LM='yes'; # enable landmark messages
########################################################################
# Environment Variables
########################################################################
# Environment variables that exist only for this file start with an
# underscore letter. Global variables to this file are written in
# upper case letters, e.g. $_GLOBAL_VARIABLE; temporary variables
# start with an underline and use only lower case letters and
# underlines, e.g. $_local_variable .
# [A-Z]* system variables, e.g. $MANPATH
# _[A-Z_]* global file variables, e.g. $_MAN_PATH
# _[a-z_]* temporary variables, e.g. $_manpath
# Due to incompatibilities of the `ash' shell, the name of loop
# variables in `for' must be single character
# [a-z] local loop variables, e.g. $i
########################################################################
# read-only variables (global to this file)
########################################################################
# characters
export _BQUOTE;
export _BSLASH;
export _DQUOTE;
export _NEWLINE;
export _LBRACK;
export _LPAR;
export _RBRACK;
export _RPAR;
export _SPACE;
export _SQUOTE;
export _TAB;
_BQUOTE='`';
_BSLASH='\';
_DQUOTE='"';
_NEWLINE='
';
_LBRACK='[';
_LPAR='(';
_RBRACK=']';
_RPAR=')';
_SPACE=' ';
_SQUOTE="'";
_TAB=' ';
# function return values; `0' means ok; other values are error codes
export _ALL_EXIT;
export _BAD;
export _ERROR;
export _GOOD;
export _NO;
export _OK;
export _YES;
_GOOD='0'; # return ok
_BAD='1'; # return negatively, error code `1'
_ERROR='7'; # for syntax errors; no `-1' in `ash'
_ALL_EXIT="${_GOOD} ${_BAD} ${_ERROR}"; # all exit codes (for `trap_set')
_NO="${_BAD}";
_YES="${_GOOD}";
_OK="${_GOOD}";
# quasi-functions, call with `eval'
export return_ok;
export return_good;
export return_bad;
export return_yes;
export return_no;
export return_error;
return_ok="func_pop; return ${_OK}";
return_good="func_pop; return ${_GOOD}";
return_bad="func_pop; return ${_BAD}";
return_yes="func_pop; return ${_YES}";
return_no="func_pop; return ${_NO}";
return_error="func_pop; return ${_ERROR}";
export _DEFAULT_MODES;
_DEFAULT_MODES='x,ps,tty';
export _DEFAULT_RESOLUTION;
_DEFAULT_RESOLUTION='75';
export _DEFAULT_TTY_DEVICE;
_DEFAULT_TTY_DEVICE='latin1';
# _VIEWER_* viewer programs for different modes (only X is necessary)
# _VIEWER_* a comma-separated list of viewer programs (with options)
export _VIEWER_DVI; # viewer program for dvi mode
export _VIEWER_PS; # viewer program for ps mode
export _VIEWER_HTML_X; # viewer program for html mode in X
export _VIEWER_HTML_TTY; # viewer program for html mode in tty
_VIEWER_DVI='xdvi,dvilx';
_VIEWER_PDF='xpdf,acroread';
_VIEWER_PS='gv,ghostview,gs_x11,gs';
_VIEWER_HTML='konqueror,mozilla,netscape,opera,amaya,arena,lynx';
_VIEWER_X='gxditview,xditview';
# Search automatically in standard sections `1' to `8', and in the
# traditional sections `9', `n', and `o'. On many systems, there
# exist even more sections, mostly containing a set of man pages
# special to a specific program package. These aren't searched for
# automatically, but must be specified on the command line.
export _MAN_AUTO_SEC;
_MAN_AUTO_SEC="'1' '2' '3' '4' '5' '6' '7' '8' '9' 'n' 'o'"
export _PROCESS_ID; # for shutting down the program
_PROCESS_ID="$$";
############ the command line options of the involved programs
#
# The naming scheme for the options environment names is
# $_OPTS__[_]
#
# : program name GROFFER, GROFF, or CMDLINE (for all
# command line options)
# : LONG (long options) or SHORT (single character options)
# : ARG for options with argument, NA for no argument;
# without _ both the ones with and without arg.
#
# Each option that takes an argument must be specified with a
# trailing : (colon).
# exports
export _OPTS_GROFFER_SHORT_NA;
export _OPTS_GROFFER_SHORT_ARG;
export _OPTS_GROFFER_LONG_NA;
export _OPTS_GROFFER_LONG_ARG;
export _OPTS_GROFF_SHORT_NA;
export _OPTS_GROFF_SHORT_ARG;
export _OPTS_GROFF_LONG_NA;
export _OPTS_GROFF_LONG_ARG;
export _OPTS_X_SHORT_ARG;
export _OPTS_X_SHORT_NA;
export _OPTS_X_LONG_ARG;
export _OPTS_X_LONG_NA;
export _OPTS_MAN_SHORT_ARG;
export _OPTS_MAN_SHORT_NA;
export _OPTS_MAN_LONG_ARG;
export _OPTS_MAN_LONG_NA;
export _OPTS_MANOPT_SHORT_ARG;
export _OPTS_MANOPT_SHORT_NA;
export _OPTS_MANOPT_LONG_ARG;
export _OPTS_MANOPT_LONG_NA;
export _OPTS_CMDLINE_SHORT_NA;
export _OPTS_CMDLINE_SHORT_ARG;
export _OPTS_CMDLINE_LONG_NA;
export _OPTS_CMDLINE_LONG_ARG;
###### groffer native options
_OPTS_GROFFER_SHORT_NA="'h' 'Q' 'v' 'V' 'X' 'Z'";
_OPTS_GROFFER_SHORT_ARG="'T'";
_OPTS_GROFFER_LONG_NA="'auto' 'debug' 'default' 'dvi' \
'groff' 'help' 'intermediate-output' 'html' 'man' \
'no-location' 'no-man' 'pdf' 'ps' 'rv' 'source' 'text' 'text-device' \
'title' 'tty' 'tty-device' 'version' 'whatis' 'where' 'www' 'x' 'X'";
_OPTS_GROFFER_LONG_ARG="\
'apropos' 'apropos-data' 'apropos-devel' 'apropos-progs' \
'default-modes' 'dvi-viewer' 'extension' 'fg' 'fn' 'font' \
'foreground' 'html-viewer' 'mode' 'pdf-viewer' 'ps-viewer' 'shell' \
'tty-viewer' 'www-viewer' 'x-viewer' 'X-viewer'";
##### groffer options inhereted from groff
_OPTS_GROFF_SHORT_NA="'a' 'b' 'c' 'C' 'e' 'E' 'g' 'G' 'i' 'l' 'N' 'p' \
'R' 's' 'S' 't' 'U' 'V' 'z'";
_OPTS_GROFF_SHORT_ARG="'d' 'f' 'F' 'I' 'L' 'm' 'M' 'n' 'o' 'P' 'r' \
'w' 'W'";
_OPTS_GROFF_LONG_NA="'source'";
_OPTS_GROFF_LONG_ARG="'device' 'macro-file'";
##### groffer options inhereted from the X Window toolkit
_OPTS_X_SHORT_NA="";
_OPTS_X_SHORT_ARG="";
_OPTS_X_LONG_NA="'iconic' 'rv'";
_OPTS_X_LONG_ARG="'background' 'bd' 'bg' 'bordercolor' 'borderwidth' \
'bw' 'display' 'fg' 'fn' 'font' 'foreground' 'ft', 'geometry'
'resolution' 'title' 'xrm'";
###### groffer options inherited from man
_OPTS_MAN_SHORT_NA="";
_OPTS_MAN_SHORT_ARG="";
_OPTS_MAN_LONG_NA="'all' 'ascii' 'catman' 'debug' 'ditroff' 'help' \
'local-file' 'location' 'pager' 'troff' 'update' 'version' \
'whatis' 'where'";
_OPTS_MAN_LONG_ARG="'extension' 'locale' 'manpath' \
'pager' 'preprocessor' 'prompt' 'sections' 'systems' 'troff-device'";
###### additional options for parsing $MANOPT only
_OPTS_MANOPT_SHORT_NA="'7' 'a' 'c' 'd' 'D' 'f' 'h' 'k' 'l' 't' 'u' \
'V' 'w' 'Z'";
_OPTS_MANOPT_SHORT_ARG="'e' 'L' 'm' 'M' 'p' 'P' 'r' 'S' 'T'";
_OPTS_MANOPT_LONG_NA="${_OPTS_MAN_LONG_NA} \
'apropos' 'debug' 'default' 'html' 'ignore-case' 'location-cat' \
'match-case' 'troff' 'update' 'version' 'where-cat'";
_OPTS_MANOPT_LONG_ARG="${_OPTS_MAN_LONG_NA} \
'config_file' 'encoding' 'locale'";
###### collections of command line options
_OPTS_CMDLINE_SHORT_NA="${_OPTS_GROFFER_SHORT_NA}\
${_OPTS_GROFF_SHORT_NA} ${_OPTS_X_SHORT_NA} ${_OPTS_MAN_SHORT_NA}";
_OPTS_CMDLINE_SHORT_ARG="${_OPTS_GROFFER_SHORT_ARG} \
${_OPTS_GROFF_SHORT_ARG} ${_OPTS_X_SHORT_ARG} ${_OPTS_MAN_SHORT_ARG}";
_OPTS_CMDLINE_LONG_NA="${_OPTS_GROFFER_LONG_NA} \
${_OPTS_GROFF_LONG_NA} ${_OPTS_X_LONG_NA} ${_OPTS_MAN_LONG_NA}";
_OPTS_CMDLINE_LONG_ARG="${_OPTS_GROFFER_LONG_ARG} \
${_OPTS_GROFF_LONG_ARG} ${_OPTS_MAN_LONG_ARG} ${_OPTS_X_LONG_ARG}";
########################################################################
# read-write variables (global to this file)
########################################################################
export _ADDOPTS_GROFF; # Transp. options for groff (`eval').
export _ADDOPTS_POST; # Transp. options postproc (`eval').
export _ADDOPTS_X; # Transp. options X postproc (`eval').
export _DEFAULT_MODES; # Set default modes.
export _DISPLAY_MODE; # Display mode.
export _DISPLAY_PROG; # Viewer program to be used for display.
export _DISPLAY_ARGS; # X resources for the viewer program.
export _FILEARGS; # Stores filespec parameters.
export _FUNC_STACK; # Store debugging information.
export _REGISTERED_TITLE; # Processed file names.
# _HAS_* from availability tests
export _HAS_COMPRESSION; # `yes' if compression is available
export _HAS_OPTS_GNU; # `yes' if GNU `getopt' is available
export _HAS_OPTS_POSIX; # `yes' if POSIX `getopts' is available
# _MAN_* finally used configuration of man searching
export _MAN_ALL; # search all man pages per filespec
export _MAN_ENABLE; # enable search for man pages
export _MAN_EXT; # extension for man pages
export _MAN_FORCE; # force file parameter to be man pages
export _MAN_IS_SETUP; # setup man variables only once
export _MAN_LANG; # language for man pages
export _MAN_LANG_DONE; # language dirs added to man path
export _MAN_PATH; # search path for man pages
export _MAN_SEC; # sections for man pages; sep. `:'
export _MAN_SEC_DONE; # sections added to man path
export _MAN_SYS; # system names for man pages; sep. `,'
export _MAN_SYS; # system names added to man path
# _MANOPT_* as parsed from $MANOPT
export _MANOPT_ALL; # $MANOPT --all
export _MANOPT_EXTENSION; # $MANOPT --extension
export _MANOPT_LANG; # $MANOPT --locale
export _MANOPT_PATH; # $MANOPT --manpath
export _MANOPT_PAGER; # $MANOPT --pager
export _MANOPT_SEC; # $MANOPT --sections
export _MANOPT_SYS; # $MANOPT --systems
# _OPT_* as parsed from groffer command line
export _OPT_ALL; # display all suitable man pages.
export _OPT_APROPOS; # call `apropos' program.
export _OPT_APROPOS_DATA; # `apropos' for man sections 4, 5, 7
export _OPT_APROPOS_DEVEL; # `apropos' for man sections 2, 3, 9
export _OPT_APROPOS_PROGS; # `apropos' for man sections 1, 6, 8
export _OPT_BD; # set border color in some modes.
export _OPT_BG; # set background color in some modes.
export _OPT_BW; # set border width in some modes.
export _OPT_DEBUG; # print debugging information on stderr.
export _OPT_DEFAULT_MODES; # `,'-list of modes when no mode given.
export _OPT_DEVICE; # device option.
export _OPT_DISPLAY; # set X display.
export _OPT_FG; # set foreground color in some modes.
export _OPT_FN; # set font in some modes.
export _OPT_GEOMETRY; # set size and position of viewer in X.
export _OPT_ICONIC; # -iconic option for X viewers.
export _OPT_LANG; # set language for man pages
export _OPT_LOCATION; # print processed file names to stderr
export _OPT_MODE; # values: X, tty, Q, Z, ""
export _OPT_MANPATH; # manual setting of path for man-pages
export _OPT_PAGER; # specify paging program for tty mode
export _OPT_RESOLUTION; # set X resolution in dpi
export _OPT_RV; # reverse fore- and background colors.
export _OPT_SECTIONS; # sections for man page search
export _OPT_SYSTEMS; # man pages of different OS's
export _OPT_TITLE; # title for gxditview window
export _OPT_TEXT_DEVICE; # set device for tty mode.
export _OPT_V; # groff option -V.
export _OPT_VIEWER_DVI; # viewer program for dvi mode
export _OPT_VIEWER_PDF; # viewer program for pdf mode
export _OPT_VIEWER_PS; # viewer program for ps mode
export _OPT_VIEWER_HTML; # viewer program for html mode
export _OPT_VIEWER_X; # viewer program for x mode
export _OPT_WHATIS; # print the one-liner man info
export _OPT_XRM; # specify X resource.
export _OPT_Z; # groff option -Z.
# _TMP_* temporary files
export _TMP_DIR; # groff directory for temporary files
export _TMP_DIR_SUB; # groffer directory for temporary files
export _TMP_CAT; # stores concatenation of everything
export _TMP_STDIN; # stores stdin, if any
# these variables are preset in section `Preset' after the rudim. test
########################################################################
# Test of rudimentary shell functionality
########################################################################
########################################################################
# Test of `test'.
#
test "a" = "a" || exit 1;
########################################################################
# Test of `echo' and the `$()' construct.
#
echo -n '' >/dev/null || exit "${_ERROR}";
if test _"$(echo -n 'te' && echo -n '' && echo -n 'st')"_ != _test_; then
exit "${_ERROR}";
fi;
########################################################################
# Test of function definitions.
#
_t_e_s_t_f_u_n_c_()
{
return "${_OK}";
}
if _t_e_s_t_f_u_n_c_ 2>/dev/null; then
:
else
echo 'shell does not support function definitions.' >&2;
exit "${_ERROR}";
fi;
########################################################################
# Preset and reset of read-write global variables
########################################################################
# For variables that can be reset by option `--default', see reset().
_FILEARGS='';
# _HAS_* from availability tests
_HAS_COMPRESSION='';
_HAS_OPTS_GNU='';
_HAS_OPTS_POSIX='';
# _TMP_* temporary files
_TMP_DIR='';
_TMP_DIR_SUB='';
_TMP_CAT='';
_TMP_STDIN='';
########################################################################
# reset ()
#
# Reset the variables that can be affected by options to their default.
#
reset()
{
if test "$#" -ne 0; then
error "reset() does not have arguments.";
fi;
_ADDOPTS_GROFF='';
_ADDOPTS_POST='';
_ADDOPTS_X='';
_DISPLAY_ARGS='';
_DISPLAY_MODE='';
_DISPLAY_PROG='';
_REGISTERED_TITLE='';
# _MAN_* finally used configuration of man searching
_MAN_ALL='no';
_MAN_ENABLE='yes'; # do search for man-pages
_MAN_EXT='';
_MAN_FORCE='no'; # first local file, then search man page
_MAN_IS_SETUP='no';
_MAN_LANG='';
_MAN_LANG_DONE='no';
_MAN_PATH='';
_MAN_SEC='';
_MAN_SEC_DONE='no';
_MAN_SYS='';
_MAN_SYS_DONE='no';
# _MANOPT_* as parsed from $MANOPT
_MANOPT_ALL='no';
_MANOPT_EXTENSION='';
_MANOPT_LANG='';
_MANOPT_PATH='';
_MANOPT_PAGER='';
_MANOPT_SEC='';
_MANOPT_SYS='';
# _OPT_* as parsed from groffer command line
_OPT_ALL='no';
_OPT_APROPOS='';
_OPT_APROPOS_DATA='';
_OPT_APROPOS_DEVEL='';
_OPT_APROPOS_PROGS='';
_OPT_BD='';
_OPT_BG='';
_OPT_BW='';
_OPT_DEBUG='no';
_OPT_DEFAULT_MODES='';
_OPT_DEVICE='';
_OPT_DISPLAY='';
_OPT_FG='';
_OPT_FN='';
_OPT_GEOMETRY='';
_OPT_ICONIC='no';
_OPT_LANG='';
_OPT_LOCATION='no';
_OPT_MODE='';
_OPT_MANPATH='';
_OPT_PAGER='';
_OPT_RESOLUTION='';
_OPT_RV='no';
_OPT_SECTIONS='';
_OPT_SYSTEMS='';
_OPT_TITLE='';
_OPT_TEXT_DEVICE='';
_OPT_V='no';
_OPT_VIEWER_DVI='';
_OPT_VIEWER_PDF='';
_OPT_VIEWER_PS='';
_OPT_VIEWER_HTML='';
_OPT_VIEWER_X='';
_OPT_WHATIS='no';
_OPT_XRM='';
_OPT_Z='no';
}
reset;
########################################################################
# Functions for error handling and debugging
########################################################################
##############
# landmark ()
#
# Print to standard error as a debugging aid.
#
# Globals: $_DEBUG_LM
#
landmark()
{
if test _"${_DEBUG_LM}"_ = _yes_; then
echo ">>> $*" >&2;
fi;
}
landmark "1: debugging functions";
##############
# clean_up ()
#
# Clean up at exit.
#
clean_up()
{
if test -d "${_TMP_DIR}"; then
rm -f "${_TMP_DIR}"/*;
rmdir "${_TMP_DIR}";
fi;
}
##############
# echo2 (*)
#
# Output to stderr.
#
# Arguments : arbitrary text.
#
echo2()
{
echo "$*" >&2;
}
##############
# echo2n (*)
#
# Output to stderr.
#
# Arguments : arbitrary text.
#
echo2n()
{
echo -n "$*" >&2;
}
#############
# diag (text>*)
#
# Output a diagnostic message to stderr
#
diag()
{
echo2 '>>>>>'"$*";
}
#############
# error (*)
#
# Print an error message to standard error; exit with an error condition
#
error()
{
local i;
local _code;
_code="${_ERROR}";
case "$#" in
0) true; ;;
1) echo2 'groffer error: '"$1"; ;;
2)
echo2 'groffer error: '"$1";
_code="$2";
;;
*) echo2 'groffer error: wrong number of arguments in error().'; ;;
esac;
if test _"${_DEBUG}"_ = _yes_; then
func_stack_dump;
fi;
clean_up;
kill "${_PROCESS_ID}" >/dev/null 2>&1;
kill -9 "${_PROCESS_ID}" >/dev/null 2>&1;
exit "${_code}";
}
#############
# abort (*)
#
# Terminate program with error condition
#
abort()
{
error "Program aborted.";
exit 1;
}
#############
# func_check ( "$@")
#
# Check number of arguments and register to _FUNC_STACK.
#
# Arguments: >=3
# : name of the calling function.
# : a relational operator: = != < > <= >=
# : number of arguments to be checked against
# "$@": the arguments of the calling function.
#
func_check()
{
local _comp;
local _fname;
local _nargs;
local _op;
local _s;
if test "$#" -lt 3; then
error 'func_check() needs at least 3 arguments.';
fi;
_fname="$1";
case "$3" in
1)
_nargs="$3";
_s='';
;;
0|[2-9])
_nargs="$3";
_s='s';
;;
*)
error "func_check(): third argument must be a digit.";
;;
esac;
case "$2" in
'='|'-eq')
_op='-eq';
_comp='exactly';
;;
'>='|'-ge')
_op='-ge';
_comp='at least';
;;
'<='|'-le')
_op='-le';
_comp='at most';
;;
'<'|'-lt')
_op='-lt';
_comp='less than';
;;
'>'|'-gt')
_op='-gt';
_comp='more than';
;;
'!='|'-ne')
_op='-ne';
_comp='not';
;;
*)
error \
'func_check(): second argument is not a relational operator.';
;;
esac;
shift 3;
if test "$#" "${_op}" "${_nargs}"; then
do_nothing;
else
error \
"${_fname}"'() needs '"${_comp} ${_nargs}"' argument'"${_s}"'.';
fi;
if test _"${_DEBUG}"_ = _yes_; then
func_push "${_fname} $*";
fi;
}
#############
# func_pop ()
#
# Retrieve the top element from the stack.
#
# The stack elements are separated by `!'; the popped element is
# identical to the original element, except that all `!' characters
# were removed.
#
# Arguments: 1
#
func_pop()
{
if test _"${_DEBUG}"_ = _yes_; then
if test "$#" -ne 0; then
error 'func_pop() does not have arguments.';
fi;
case "${_FUNC_STACK}" in
'')
error 'func_pop(): stack is empty.';
;;
*!*)
# split at first bang `!'.
_FUNC_STACK="$(echo -n ${_FUNC_STACK} \
| sed -e 's/^[^!]*!//')";
;;
*)
_FUNC_STACK='';
;;
esac;
fi;
}
#############
# func_push ()
#
# Store another element to stack.
#
# The stack elements are separated by `!'; if contains a `!'
# it is removed first.
#
# Arguments: 1
#
func_push()
{
local _element;
if test _"${_DEBUG}"_ = _yes_; then
if test "$#" -ne 1; then
error 'func_push() needs 1 argument.';
fi;
case "$1" in
*'!'*)
# remove all bangs `!'.
_element="$(echo -n "$1" | sed -e 's/!//g')";
;;
*)
_element="$1";
;;
esac;
if test _"${_FUNC_STACK}"_ = __; then
_FUNC_STACK="${_element}";
else
_FUNC_STACK="${_element}!${_FUNC_STACK}";
fi;
fi;
}
#############
# func_stack_dump ()
#
# Print the content of the stack. Ignore the arguments.
#
func_stack_dump()
{
diag 'call stack:';
case "${_FUNC_STACK}" in
*!*)
_rest="${_FUNC_STACK}";
while test _"${_rest}"_ != __; do
# get part before the first bang `!'.
diag "$(echo -n "${_rest}" | sed -e 's/!.*$//')";
# delete part before and including the first bang `!'.
_rest="$(echo -n "${_rest}" | sed -e 's/^[^!]*!//')";
done;
;;
*)
diag "${_FUNC_STACK}";
;;
esac;
}
########################################################################
# System Test
########################################################################
landmark "2: system test";
# Test the availability of the system utilities used in this script.
########################################################################
# Test of `true'.
#
if true >/dev/null 2>&1; then
true;
else
true()
{
return "${_GOOD}";
}
false()
{
return "${_BAD}";
}
fi;
########################################################################
# Test of `unset'.
#
_test='test';
if unset _test >/dev/null 2>&1 && test _"${_test}"_ = __; then
true;
else
unset()
{
for v in "$@"; do
eval "$v"='';
done;
}
fi;
unset _test;
########################################################################
# Test of builtin `local'
#
_t_e_s_t_f_u_n_c_()
{
local _test >/dev/null 2>&1 || return "${_BAD}";
}
if _t_e_s_t_f_u_n_c_; then
:
else
local()
{
if test _"$1"_ != __; then
error "overriding global variable \`$1' with local value.";
fi;
}
fi;
########################################################################
# Test of global setting in functions
#
_global='outside';
_clobber='outside';
_t_e_s_t_f_u_n_c_()
{
local _clobber;
_global='inside';
_clobber='inside';
}
_t_e_s_t_f_u_n_c_;
if test _"${_global}"_ != _inside_ || test _"${_clobber}"_ != _outside_;
then
error "Cannot assign to global variables from within functions.";
fi;
unset _global;
unset _clobber;
########################################################################
# Test of function `sed'.
#
if test _"$(echo xTesTx \
| sed -e 's/^.\([Tt]e*x*sTT*\).*$/\1/' \
| sed -e '\|T|s|T|t|g')"_ != _test_;
then
error 'Test of "sed" command failed.';
fi;
########################################################################
# Test of function `cat'.
#
if test _"$(echo test | cat)"_ != _test_; then
error 'Test of "cat" command failed.';
fi;
########################################################################
# Test for compression.
#
if test _"$(echo 'test' | gzip -c -d -f - 2>/dev/null)"_ = _test_; then
_HAS_COMPRESSION='yes';
if echo 'test' | bzip2 -c 2>/dev/null | bzip2 -t 2>/dev/null \
&& test _"$(echo 'test' | bzip2 -c 2>/dev/null \
| bzip2 -d -c 2>/dev/null)"_ \
= _test_; then
_HAS_BZIP='yes';
else
_HAS_BZIP='no';
fi;
else
_HAS_COMPRESSION='no';
_HAS_BZIP='no';
fi;
########################################################################
_t_e_s_t_f_u_n_c_()
{
:
}
########################################################################
# Definition of normal Functions
########################################################################
landmark "3: functions";
########################################################################
# abort (*)
#
# Unconditionally terminate the program with error code;
# useful for debugging.
#
# defined above
########################################################################
# apropos_run ()
#
#
apropos_run() {
func_check apropos_run = 1 "$@";
if apropos apropos >/dev/null 2>/dev/null; then
apropos "$1";
elif man --apropos man >/dev/null 2>/dev/null; then
man --apropos "$1";
elif man -k man >/dev/null 2>/dev/null; then
man -k "$1";
fi;
}
########################################################################
# base_name ()
#
# Get the file name part of , i.e. delete everything up to last
# `/' from the beginning of . Remove final slashes, too, to get a
# non-empty output.
#
# Arguments : 1
# Output : the file name part (without slashes)
#
base_name()
{
func_check base_name = 1 "$@";
local f;
f="$1";
case "$f" in
*/)
# delete all final slashes
f="$(echo -n "$f" | sed -e '\|.*|s|//*$||')";
;;
esac;
case "$f" in
/|'')
eval "${return_bad}";
;;
*/*)
# delete everything before and including the last slash `/'.
echo -n "$f" | sed -e '\|.*|s|^.*//*\([^/]*\)$|\1|';
;;
*)
echo -n "$f";
;;
esac;
eval "${return_ok}";
}
########################################################################
# catz ()
#
# Decompress if possible or just print to standard output.
#
# gzip, bzip2, and .Z decompression is supported.
#
# Arguments: 1, a file name.
# Output: the content of , possibly decompressed.
#
if test _"${_HAS_COMPRESSION}"_ = _yes_; then
catz()
{
func_check catz = 1 "$@";
case "$1" in
'')
error 'catz(): empty file name';
;;
'-')
error 'catz(): for standard input use save_stdin()';
;;
esac;
if obj _HAS_BZIP is_yes; then
if bzip2 -t "$1" 2>/dev/null; then
bzip2 -c -d "$1" 2>/dev/null;
eval "${return_ok}";
fi;
fi;
gzip -c -d -f "$1" 2>/dev/null;
eval "${return_ok}";
}
else
catz()
{
func_check catz = 1 "$@";
cat "$1";
eval "${return_ok}";
}
fi;
########################################################################
# clean_up ()
#
# Do the final cleaning up before exiting; used by the trap calls.
#
# defined above
########################################################################
# diag (*)
#
# Print marked message to standard error; useful for debugging.
#
# defined above
########################################################################
landmark '4: dirname()*';
########################################################################
#######################################################################
# dirname_append ()
#
# Append `name' to `dir' with clean handling of `/'.
#
# Arguments : 2
# Output : the generated new directory name /
#
dirname_append()
{
func_check dirname_append = 2 "$@";
local _res;
if is_empty "$1"; then
error "dir_append(): first argument is empty.";
fi;
if is_empty "$2"; then
echo -n "$1";
else
dirname_chop "$1"/"$2";
fi;
eval "${return_ok}";
}
########################################################################
# dirname_chop ()
#
# Remove unnecessary slashes from directory name.
#
# Argument: 1, a directory name.
# Output: path without double, or trailing slashes.
#
dirname_chop()
{
func_check dirname_chop = 1 "$@";
local _arg;
local _res;
local _sep;
# replace all multiple slashes by a single slash `/'.
_res="$(echo -n "$1" | sed -e '\|.*|s|///*|/|g')";
case "${_res}" in
?*/)
# remove trailing slash '/';
echo -n "${_res}" | sed -e '\|.*|s|/$||';
;;
*) echo -n "${_res}"; ;;
esac;
eval "${return_ok}";
}
########################################################################
# do_filearg ()
#
# Append the file, man-page, or standard input corresponding to the
# argument to the temporary file. If this is compressed in the gzip
# or Z format it is decompressed. A title element is generated.
#
# Argument either:
# - name of an existing files.
# - `-' to represent standard input (several times allowed).
# - `man:name.(section)' the man-page for `name' in `section'.
# - `man:name.section' the man-page for `name' in `section'.
# - `man:name' the man-page for `name' in the lowest `section'.
# - `name.section' the man-page for `name' in `section'.
# - `name' the man-page for `name' in the lowest `section'.
# Globals :
# $_TMP_STDIN, $_MAN_ENABLE, $_MAN_IS_SETUP, $_OPT_MAN
#
# Output : none
# Return : $_GOOD if found, ${_BAD} otherwise.
#
do_filearg()
{
func_check do_filearg = 1 "$@";
local _filespec;
local i;
_filespec="$1";
# store sequence into positional parameters
case "${_filespec}" in
'')
eval "${return_good}";
;;
'-')
register_file '-';
eval "${return_good}";
;;
*/*) # with directory part; so no man search
set -- 'File';
;;
*)
if obj _MAN_ENABLE is_yes; then
if obj _MAN_FORCE is_yes; then
set -- 'Manpage' 'File';
else
set -- 'File' 'Manpage';
fi;
else
set -- 'File';
fi;
;;
esac;
for i in "$@"; do
case "$i" in
File)
if test -f "${_filespec}"; then
if test -r "${_filespec}"; then
register_file "${_filespec}";
eval "${return_good}";
else
echo2 "could not read \`${_filespec}'";
eval "${return_bad}";
fi;
else
continue;
fi;
;;
Manpage) # parse filespec as man page
if obj _MAN_IS_SETUP is_not_yes; then
man_setup;
fi;
if man_do_filespec "${_filespec}"; then
eval "${return_good}";
else
continue;
fi;
;;
esac;
done;
eval "${return_bad}";
} # do_filearg()
########################################################################
# do_nothing ()
#
# Dummy function.
#
do_nothing()
{
return "${_OK}";
}
########################################################################
# echo2 (*)
#
# Print to standard error with final line break.
#
# defined above
########################################################################
# echo2n (*)
#
# Print to standard error without final line break.
#
# defined above
########################################################################
# error (*)
#
# Print error message and exit with error code.
#
# defined above
########################################################################
# func_check ( "$@")
#
# Check number of arguments and register to _FUNC_STACK.
#
# Arguments: >=3
# : name of the calling function.
# : a relational operator: = != < > <= >=
# : number of arguments to be checked against
# "$@": the arguments of the calling function.
#
# defined above
#########################################################################
# func_pop ()
#
# Delete the top element from the function call stack.
#
# defined above
########################################################################
# func_push ()
#
# Store another element to function call stack.
#
# defined above
########################################################################
# func_stack_dump ()
#
# Print the content of the stack.
#
# defined above
########################################################################
# get_first_essential (*)
#
# Retrieve first non-empty argument.
#
# Return : `1' if all arguments are empty, `0' if found.
# Output : the retrieved non-empty argument.
#
get_first_essential()
{
func_check get_first_essential '>=' 0 "$@";
local i;
if is_equal "$#" 0; then
eval "${return_ok}";
fi;
for i in "$@"; do
if obj i is_not_empty; then
echo -n "$i";
eval "${return_ok}";
fi;
done;
eval "${return_bad}";
}
########################################################################
landmark '5: is_*()';
########################################################################
########################################################################
# is_dir ()
#
# Test whether `name' is a directory.
#
# Arguments : 1
# Return : `0' if arg1 is a directory, `1' otherwise.
#
is_dir()
{
func_check is_dir = 1 "$@";
if test -d "$1" && test -r "$1"; then
eval "${return_yes}";
fi;
eval "${return_no}";
}
########################################################################
# is_empty ()
#
# Test whether `string' is empty.
#
# Arguments : <=1
# Return : `0' if arg1 is empty or does not exist, `1' otherwise.
#
is_empty()
{
func_check is_empty = 1 "$@";
if test _"$1"_ = __; then
eval "${return_yes}";
fi;
eval "${return_no}";
}
########################################################################
# is_equal ()
#
# Test whether `string1' is equal to .
#
# Arguments : 2
# Return : `0' both arguments are equal strings, `1' otherwise.
#
is_equal()
{
func_check is_equal = 2 "$@";
if test _"$1"_ = _"$2"_; then
eval "${return_yes}";
fi;
eval "${return_no}";
}
########################################################################
# is_file ()
#
# Test whether `name' is a readable file.
#
# Arguments : 1
# Return : `0' if arg1 is a readable file, `1' otherwise.
#
is_file()
{
func_check is_file = 1 "$@";
if test -f "$1" && test -r "$1"; then
eval "${return_yes}";
fi;
eval "${return_no}";
}
########################################################################
# is_non_empty_file ()
#
# Test whether `file_name' is a non-empty existing file.
#
# Arguments : <=1
# Return :
# `0' if arg1 is a non-empty existing file
# `1' otherwise
#
is_non_empty_file()
{
func_check is_empty = 1 "$@";
if is_file "$1"; then
if is_not_empty "$(cat "$1" | sed -e '/./q')"; then
eval "${return_yes}";
fi;
fi;
eval "${return_no}";
}
########################################################################
# is_not_dir ()
#
# Test whether `name' is not a readable directory.
#
# Arguments : 1
# Return : `0' if arg1 is a directory, `1' otherwise.
#
is_not_dir()
{
func_check is_not_dir = 1 "$@";
if is_dir "$1"; then
eval "${return_no}";
fi;
eval "${return_yes}";
}
########################################################################
# is_not_empty ()
#
# Test whether `string' is not empty.
#
# Arguments : <=1
# Return : `0' if arg1 exists and is not empty, `1' otherwise.
#
is_not_empty()
{
func_check is_not_empty = 1 "$@";
if is_empty "$1"; then
eval "${return_no}";
fi;
eval "${return_yes}";
}
########################################################################
# is_not_equal ()
#
# Test whether `string1' differs from `string2'.
#
# Arguments : 2
#
is_not_equal()
{
func_check is_not_equal = 2 "$@";
if is_equal "$1" "$2"; then
eval "${return_no}";
fi
eval "${return_yes}";
}
########################################################################
# is_not_file ()
#
# Test whether `name' is a not readable file.
#
# Arguments : >=1 (empty allowed), more args are ignored
#
is_not_file()
{
func_check is_not_file '>=' 1 "$@";
if is_file "$1"; then
eval "${return_no}";
fi;
eval "${return_yes}";
}
########################################################################
# is_not_prog ()
#
# Verify that arg is a not program in $PATH.
#
# Arguments : >=1 (empty allowed)
# more args are ignored, this allows to specify progs with arguments
#
is_not_prog()
{
func_check is_not_prog '>=' 1 "$@";
if where "$1" >/dev/null; then
eval "${return_no}";
fi;
eval "${return_yes}";
}
########################################################################
# is_not_writable ()
#
# Test whether `name' is a not a writable file or directory.
#
# Arguments : >=1 (empty allowed), more args are ignored
#
is_not_writable()
{
func_check is_not_writable '>=' 1 "$@";
if is_writable "$1"; then
eval "${return_no}";
fi;
eval "${return_yes}";
}
########################################################################
# is_not_yes ()
#
# Test whether `string' is not "yes".
#
# Arguments : 1
#
is_not_yes()
{
func_check is_not_yes = 1 "$@";
if is_yes "$1"; then
eval "${return_no}";
fi;
eval "${return_yes}";
}
########################################################################
# is_prog ()
#
# Determine whether arg is a program in $PATH
#
# Arguments : >=0 (empty allowed)
# more args are ignored, this allows to specify progs with arguments
#
is_prog()
{
func_check is_prog '>=' 0 "$@";
case "$#" in
0)
eval "${return_no}";
;;
*)
if where "$1" >/dev/null; then
eval "${return_yes}";
fi;
;;
esac
eval "${return_no}";
}
########################################################################
# is_writable ()
#
# Test whether `name' is a writable file or directory.
#
# Arguments : >=1 (empty allowed), more args are ignored
#
is_writable()
{
func_check is_writable '>=' 1 "$@";
if test -r "$1"; then
if test -w "$1"; then
eval "${return_yes}";
fi;
fi;
eval "${return_no}";
}
########################################################################
# is_yes ()
#
# Test whether `string' has value "yes".
#
# Arguments : <=1
# Return : `0' if arg1 is `yes', `1' otherwise.
#
is_yes()
{
func_check is_yes = 1 "$@";
if is_equal "$1" 'yes'; then
eval "${return_yes}";
fi;
eval "${return_no}";
}
########################################################################
# landmark ()
#
# Print debugging information on standard error if $_DEBUG_LM is `yes'.
#
# Globals: $_DEBUG_LM
#
# Defined in section `Debugging functions'.
########################################################################
# leave ()
#
# Clean exit without an error.
#
leave()
{
clean_up;
exit "${_OK}";
}
########################################################################
landmark '6: list_*()';
########################################################################
#
# `list' is an object class that represents an array or list. Its
# data consists of space-separated single-quoted elements. So a list
# has the form "'first' 'second' '...' 'last'". See list_append() for
# more details on the list structure. The array elements of `list'
# can be get by `set -- $list`.
########################################################################
# list_append (...)
#
# Arguments: >=2
# : a variable name for a list of single-quoted elements
# : some sequence of characters.
# Output: none, but $ is set to
# if is empty: "'' '...'"
# otherwise: "$list '' ..."
#
list_append()
{
func_check list_append '>=' 2 "$@";
local _element;
local _list;
local _name;
_name="$1";
eval _list='"${'$1'}"';
shift;
for s in "$@"; do
case "$s" in
*\'*)
# escape each single quote by replacing each
# "'" (squote) by "'\''" (squote bslash squote squote);
# note that the backslash must be doubled in the following `sed'
_element="$(echo -n "$s" | sed -e 's/'"${_SQUOTE}"'/&\\&&/g')";
;;
'')
_element="";
;;
*)
_element="$s";
;;
esac;
if obj _list is_empty; then
_list="'${_element}'";
else
_list="${_list} '${_element}'";
fi;
done;
eval "${_name}"='"${_list}"';
eval "${return_ok}";
}
########################################################################
# list_from_cmdline ( [...])
#
# Transform command line arguments into a normalized form.
#
# Options, option arguments, and file parameters are identified and
# output each as a single-quoted argument of its own. Options and
# file parameters are separated by a '--' argument.
#
# Arguments: >=1
# : common part of a set of 4 environment variable names:
# $_SHORT_NA: list of short options without an arg.
# $_SHORT_ARG: list of short options that have an arg.
# $_LONG_NA: list of long options without an arg.
# $_LONG_ARG: list of long options that have an arg.
# ...: the arguments from a command line, such as "$@",
# the content of a variable, or direct arguments.
#
# Output: ['-[-]opt' ['optarg']]... '--' ['filename']...
#
# Example:
# list_from_cmdline PRE 'a b' 'c' '' 'long' -a f1 -bcarg --long=larg f2
# If $PRE_SHORT_NA, $PRE_SHORT_ARG, $PRE_LONG_NA, and $PRE_LONG_ARG are
# none-empty option lists, this will result in printing:
# '-a' '-b' '-c' 'arg' '--long' 'larg' '--' 'f1' 'f2'
#
# Use this function in the following way:
# eval set -- "$(args_norm PRE_NAME "$@")";
# while test "$1" != '--'; do
# case "$1" in
# ...
# esac;
# shift;
# done;
# shift; #skip '--'
# # all positional parameters ("$@") left are file name parameters.
#
list_from_cmdline()
{
func_check list_from_cmdline '>=' 1 "$@";
local _fparams;
local _fn;
local _short_a;
local _short_n;
local _long_a;
local _long_n;
local _result;
_short_n="$(obj_data "$1"_SHORT_NA)"; # short options, no argument
_short_a="$(obj_data "$1"_SHORT_ARG)"; # short options, with argument
_long_n="$(obj_data "$1"_LONG_NA)"; # long options, no argument
_long_a="$(obj_data "$1"_LONG_ARG)"; # long options, with argument
if obj _short_n is_empty; then
error 'list_from_cmdline(): no $'"$1"'_SHORT_NA options.';
fi;
if obj _short_a is_empty; then
error 'list_from_cmdline(): no $'"$1"'_SHORT_ARG options.';
fi;
if obj _long_n is_empty; then
error 'list_from_cmdline(): no $'"$1"'_LONG_NA options.';
fi;
if obj _long_a is_empty; then
error 'list_from_cmdline(): no $'"$1"'_LONG_ARG options.';
fi;
shift;
_fn='list_from_cmdline():'; # for error messages
if is_equal "$#" 0; then
echo -n "'--'";
eval "${return_ok}";
fi;
_fparams='';
_result='';
while test "$#" -ge 1; do
_arg="$1";
shift;
case "$_arg" in
--) break; ;;
--?*)
# delete leading '--';
_opt="$(echo -n "${_arg}" | sed -e 's/^..//')";
if list_has _long_n "${_opt}"; then
# long option, no argument
list_append _result "--${_opt}";
continue;
fi;
# test on `--opt=arg'
if string_contains "${_opt}" '='; then
# extract option by deleting from the first '=' to the end
_lopt="$(echo -n "${_opt}" | sed -e 's/=.*$//')";
if list_has _long_a "${_lopt}"; then
# get the option argument by deleting up to first `='
_optarg="$(echo -n "${_opt}" | sed -e 's/^[^=]*=//')";
list_append _result "--${_lopt}" "${_optarg}";
continue;
fi;
fi;
if list_has _long_a "${_opt}"; then
# long option with argument
if test "$#" -le 0; then
error "${_fn} no argument for option --${_opt}."
fi;
list_append _result "--${_opt}" "$1";
shift;
continue;
fi;
error "${_fn} --${_opt} is not an option."
;;
-?*) # short option (cluster)
# delete leading `-';
_rest="$(echo -n "${_arg}" | sed -e 's/^-//')";
while obj _rest is_not_empty; do
# get next short option from cluster (first char of $_rest)
_optchar="$(echo -n "${_rest}" | sed -e 's/^\(.\).*$/\1/')";
# remove first character from ${_rest};
_rest="$(echo -n "${_rest}" | sed -e 's/^.//')";
if list_has _short_n "${_optchar}"; then
list_append _result "-${_optchar}";
continue;
elif list_has _short_a "${_optchar}"; then
if obj _rest is_empty; then
if test "$#" -ge 1; then
list_append _result "-${_optchar}" "$1";
shift;
continue;
else
error \
"${_fn}"' no argument for option -'"${_optchar}."
fi;
else # rest is the argument
list_append _result "-${_optchar}" "${_rest}";
_rest='';
continue;
fi;
else
error "${_fn} unknown option -${_optchar}."
fi;
done;
;;
*)
# Here, $_arg is not an option, so a file parameter.
list_append _fparams "${_arg}";
# Ignore the strange option handling of $POSIXLY_CORRECT to
# end option parsing after the first file name argument. To
# reuse it, do a `break' here if $POSIXLY_CORRECT is
# non-empty.
;;
esac;
done;
list_append _result '--';
if obj _fparams is_not_empty; then
_result="${_result} ${_fparams}";
fi;
if test "$#" -gt 0; then
list_append _result "$@";
fi;
echo -n "$_result";
eval "${return_ok}";
} # list_from_cmdline()
########################################################################
# list_from_split ()
#
# In , escape all white space characters and replace each
# by space.
#
# Arguments: 2: a that is to be split into parts divided by
#
# Output: the resulting list string
#
list_from_split()
{
func_check list_from_split = 2 "$@";
local _s;
# precede each space or tab by a backslash `\' (doubled for `sed')
_s="$(echo -n "$1" | sed -e 's/\(['"${_SPACE}${_TAB}"']\)/\\\1/g')";
# replace split character of string by the list separator ` ' (space).
case "$2" in
/) # cannot use normal `sed' separator
echo -n "${_s}" | sed -e '\|.*|s|'"$2"'| |g';
;;
?) # use normal `sed' separator
echo -n "${_s}" | sed -e 's/'"$2"'/ /g';
;;
??*)
error 'list_from_split(): separator must be a single character.';
;;
esac;
eval "${return_ok}";
}
########################################################################
# list_get ()
#
# Check whether is a space-separated list of '-quoted elements.
#
# If the test fails an error is raised.
# If the test succeeds the argument is echoed.
#
# Testing criteria:
# A list has the form "'first' 'second' '...' 'last'". So it has a
# leading and a final quote and the elements are separated by "' '"
# constructs. If these are all removed there should not be any
# unescaped single-quotes left. Watch out for escaped single
# quotes; they have the form '\'' (sq bs sq sq).
# Arguments: 1
# Output: the argument unchanged, if the check succeeded.
#
list_get()
{
func_check list_get = 1 "$@";
local _list;
eval _list='"${'$1'}"';
# remove leading and final space characters
_list="$(echo -n "${_list}" | \
sed -e 's/^['"${_SPACE}${_TAB}"']*//' | \
sed -e 's/['"${_SPACE}${_TAB}"']*$//')";
case "${_list}" in
'')
eval "${return_ok}";
;;
\'*\')
echo -n "${_list}";
eval "${return_ok}";
;;
*)
error "list_get(): bad list: $1"
;;
esac;
eval "${return_ok}";
}
########################################################################
# list_has ()
#
# Arguments: 2
# : a variable name for a list of single-quoted elements
# : some sequence of characters.
# Output:
# if is empty: "'' '...'"
# otherwise: "list '' ..."
#
list_has()
{
func_check list_has = 2 "$@";
eval _list='"${'$1'}"';
if obj _list is_empty; then
eval "${return_no}";
fi;
_element="$2";
case "$2" in
\'*\') _element="$2"; ;;
*) _element="'$2'"; ;;
esac;
if string_contains "${_list}" "${_element}"; then
eval "${return_yes}";
else
eval "${return_no}";
fi;
eval "${return_ok}";
}
########################################################################
# list_has_not ()
#
# Arguments: 2
# : a space-separated list of single-quoted elements.
# : some sequence of characters.
# Output:
# if is empty: "'' '...'"
# otherwise: " '' ..."
#
list_has_not()
{
func_check list_has_not = 2 "$@";
eval _list='"${'$1'}"';
if obj _list is_empty; then
eval "${return_yes}";
fi;
_element="$2";
case "$2" in
\'*\') _element="$2"; ;;
*) _element="'$2'"; ;;
esac;
if string_contains "${_list}" "${_element}"; then
eval "${return_no}";
else
eval "${return_yes}";
fi;
eval "${return_ok}";
}
########################################################################
landmark '7: man_*()';
########################################################################
########################################################################
# man_do_filespec ()
#
# Print suitable man page(s) for filespec to $_TMP_CAT.
#
# Arguments : 2
# : argument of the form `man:name.section', `man:name',
# `man:name(section)', `name.section', `name'.
#
# Globals : $_OPT_ALL
#
# Output : none.
# Return : `0' if man page was found, `1' else.
#
# Only called from do_fileargs(), checks on $MANPATH and
# $_MAN_ENABLE are assumed.
#
man_do_filespec()
{
func_check man_do_filespec = 1 "$@";
local _got_one;
local _name;
local _prevsec;
local _res;
local _section;
local _spec;
local _string;
local s;
if obj _MAN_PATH is_empty; then
eval "${return_bad}";
fi;
if is_empty "$1"; then
eval "${return_bad}";
fi;
_spec="$1";
_name='';
_section='';
case "${_spec}" in
*/*) # not a man spec when it contains '/'
eval "${return_bad}";
;;
man:?*\(?*\)) # man:name(section)
_name="$(echo -n "${_spec}" \
| sed -e 's/^man:\(..*\)(\(..*\))$/\1/')";
_section="$(echo -n "${_spec}" \
| sed -e 's/^man:\(..*\)(\(..*\))$/\2/')";
;;
man:?*.[0-9on]) # man:name.section
_name="$(echo -n "${_spec}" \
| sed -e 's/^man:\(..*\)\..$/\1/')";
_section="$(echo -n "${_spec}" \
| sed -e 's/^.*\(.\)$/\1/')";
;;
man:?*) # man:name
_name="$(echo -n "${_spec}" | sed -e 's/^man://')";
;;
?*\(?*\)) # name(section)
_name="$(echo -n "${_spec}" \
| sed -e 's/^\(..*\)(\(..*\))$/\1/')";
_section="$(echo -n "${_spec}" \
| sed -e 's/^\(..*\)(\(..*\))$/\2/')";
;;
?*.[0-9on]) # name.section
_name="$(echo -n "${_spec}" \
| sed -e 's/^\(..*\)\..$/\1/')";
_section="$(echo -n "${_spec}" \
| sed -e 's/^.*\(.\)$/\1/')";
;;
?*)
_name="${_filespec}";
;;
esac;
if obj _name is_empty; then
eval "${return_bad}";
fi;
_got_one='no';
if obj _section is_empty; then
eval set -- "${_MAN_AUTO_SEC}";
for s in "$@"; do
if man_search_section "${_name}" "$s"; then # found
if obj _MAN_ALL is_yes; then
_got_one='yes';
else
eval "${return_good}";
fi;
fi;
done;
else
if man_search_section "${_name}" "${_section}"; then
eval "${return_good}";
else
eval "${return_bad}";
fi;
fi;
if obj _MAN_ALL is_yes && is_yes "${_got_one}"; then
eval "${return_good}";
fi;
eval "${return_bad}";
} # man_do_filespec()
########################################################################
# man_register_file ( [])
#
# Write a found man page file and register the title element.
#
# Arguments: 1, 2, or 3; maybe empty
# Output: none
#
man_register_file()
{
func_check man_register_file '>=' 2 "$@";
case "$#" in
2|3) do_nothing; ;;
*)
error "man_register_file() expects 2 or 3 arguments.";
;;
esac;
if is_empty "$1"; then
error 'man_register_file(): file name is empty';
fi;
to_tmp "$1";
case "$#" in
2)
register_title "man:$2";
eval "${return_ok}";
;;
3)
register_title "$2.$3";
eval "${return_ok}";
;;
esac;
eval "${return_ok}";
}
########################################################################
# man_search_section ()
#
# Retrieve man pages.
#
# Arguments : 2
# Globals : $_MAN_PATH, $_MAN_EXT
# Return : 0 if found, 1 otherwise
#
man_search_section()
{
func_check man_search_section = 2 "$@";
local _dir;
local _ext;
local _got_one;
local _name;
local _prefix
local _section;
local d;
local f;
if obj _MAN_PATH is_empty; then
eval "${return_bad}";
fi;
if is_empty "$1"; then
eval "${return_bad}";
fi;
if is_empty "$2"; then
eval "${return_bad}";
fi;
_name="$1";
_section="$2";
eval set -- "$(path_split "${_MAN_PATH}")";
_got_one='no';
if obj _MAN_EXT is_empty; then
for d in "$@"; do
_dir="$(dirname_append "$d" "man${_section}")";
if obj _dir is_dir; then
_prefix="$(dirname_append "${_dir}" "${_name}.${_section}")";
for f in $(echo -n ${_prefix}*); do
if obj f is_file; then
if is_yes "${_got_one}"; then
register_file "$f";
elif obj _MAN_ALL is_yes; then
man_register_file "$f" "${_name}";
else
man_register_file "$f" "${_name}" "${_section}";
eval "${return_good}";
fi;
_got_one='yes';
fi;
done;
fi;
done;
else
_ext="${_MAN_EXT}";
# check for directory name having trailing extension
for d in "$@"; do
_dir="$(dirname_append $d man${_section}${_ext})";
if obj _dir is_dir; then
_prefix="$(dirname_append "${_dir}" "${_name}.${_section}")";
for f in ${_prefix}*; do
if obj f is_file; then
if is_yes "${_got_one}"; then
register_file "$f";
elif obj _MAN_ALL is_yes; then
man_register_file "$f" "${_name}";
else
man_register_file "$f" "${_name}" "${_section}";
eval "${return_good}";
fi;
_got_one='yes';
fi;
done;
fi;
done;
# check for files with extension in directories without extension
for d in "$@"; do
_dir="$(dirname_append "$d" "man${_section}")";
if obj _dir is_dir; then
_prefix="$(dirname_append "${_dir}" \
"${_name}.${_section}${_ext}")";
for f in ${_prefix}*; do
if obj f is_file; then
if is_yes "${_got_one}"; then
register_file "$f";
elif obj _MAN_ALL is_yes; then
man_register_file "$f" "${_name}";
else
man_register_file "$f" "${_name}" "${_section}";
eval "${return_good}";
fi;
_got_one='yes';
fi;
done;
fi;
done;
fi;
if obj _MAN_ALL is_yes && is_yes "${_got_one}"; then
eval "${return_good}";
fi;
eval "${return_bad}";
} # man_search_section()
########################################################################
# man_setup ()
#
# Setup the variables $_MAN_* needed for man page searching.
#
# Globals:
# in: $_OPT_*, $_MANOPT_*, $LANG, $LC_MESSAGES, $LC_ALL,
# $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM, $MANOPT.
# out: $_MAN_PATH, $_MAN_LANG, $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2,
# $_MAN_SEC, $_MAN_ALL
# in/out: $_MAN_ENABLE
#
# The precedence for the variables related to `man' is that of GNU
# `man', i.e.
#
# $LANG; overridden by
# $LC_MESSAGES; overridden by
# $LC_ALL; this has the same precedence as
# $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM; overridden by
# $MANOPT; overridden by
# the groffer command line options.
#
man_setup()
{
func_check main_man_setup = 0 "$@";
local _lang;
if obj _MAN_IS_SETUP is_yes; then
eval "${return_ok}";
fi;
_MAN_IS_SETUP='yes';
if obj _MAN_ENABLE is_not_yes; then
eval "${return_ok}";
fi;
# determine basic path for man pages
_MAN_PATH="$(get_first_essential \
"${_OPT_MANPATH}" "${_MANOPT_PATH}" "${MANPATH}")";
if obj _MAN_PATH is_empty; then
manpath_set_from_path;
else
_MAN_PATH="$(path_clean "${_MAN_PATH}")";
fi;
if obj _MAN_PATH is_empty; then
if is_prog 'manpath'; then
_MAN_PATH="$(manpath 2>/dev/null)"; # not always available
fi;
fi;
if obj _MAN_PATH is_empty; then
_MAN_ENABLE="no";
eval "${return_ok}";
fi;
_MAN_ALL="$(get_first_essential "${_OPT_ALL}" "${_MANOPT_ALL}")";
if obj _MAN_ALL is_empty; then
_MAN_ALL='no';
fi;
_MAN_SYS="$(get_first_essential \
"${_OPT_SYSTEMS}" "${_MANOPT_SYS}" "${SYSTEM}")";
_lang="$(get_first_essential \
"${_OPT_LANG}" "${LC_ALL}" "${LC_MESSAGES}" "${LANG}")";
case "${_lang}" in
C|POSIX)
_MAN_LANG="";
_MAN_LANG2="";
;;
?)
_MAN_LANG="${_lang}";
_MAN_LANG2="";
;;
*)
_MAN_LANG="${_lang}";
# get first two characters of $_lang
_MAN_LANG2="$(echo -n "${_lang}" | sed -e 's/^\(..\).*$/\1/')";
;;
esac;
# from now on, use only $_LANG, forget about $_OPT_LANG, $LC_*.
manpath_add_lang_sys; # this is very slow
_MAN_SEC="$(get_first_essential \
"${_OPT_SECT}" "${_MANOPT_SEC}" "${MANSEC}")";
if obj _MAN_PATH is_empty; then
_MAN_ENABLE="no";
eval "${return_ok}";
fi;
_MAN_EXT="$(get_first_essential \
"${_OPT_EXTENSION}" "${_MANOPT_EXTENSION}")";
eval "${return_ok}";
} # man_setup()
########################################################################
landmark '8: manpath_*()';
########################################################################
########################################################################
# manpath_add_lang_sys ()
#
# Add language and operating system specific directories to man path.
#
# Arguments : 0
# Output : none
# Globals:
# in: $_MAN_SYS: has the form `os1,os2,...', a comma separated
# list of names of operating systems.
# $_MAN_LANG and $_MAN_LANG2: each a single name
# in/out: $_MAN_PATH: has the form `dir1:dir2:...', a colon
# separated list of directories.
#
manpath_add_lang_sys()
{
func_check manpath_add_lang_sys = 0 "$@";
local p;
local _mp;
if obj _MAN_PATH is_empty; then
eval "${return_ok}";
fi;
# twice test both sys and lang
eval set -- "$(path_split "${_MAN_PATH}")";
_mp='';
for p in "$@"; do # loop on man path directories
_mp="$(_manpath_add_lang_sys_single "${_mp}" "$p")";
done;
eval set -- "$(path_split "${_mp}")";
for p in "$@"; do # loop on man path directories
_mp="$(_manpath_add_lang_sys_single "${_mp}" "$p")";
done;
_MAN_PATH="$(path_chop "${_mp}")";
eval "${return_ok}";
}
_manpath_add_lang_sys_single()
{
# To the directory in $1 append existing sys/lang subdirectories
# Function is necessary to split the OS list.
#
# globals: in: $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2
# argument: 2: `man_path' and `dir'
# output: colon-separated path of the retrieved subdirectories
#
func_check _manpath_add_lang_sys_single = 2 "$@";
local d;
_res="$1";
_parent="$2";
eval set -- "$(list_from_split "${_MAN_SYS}" ',')";
for d in "$@" "${_MAN_LANG}" "${_MAN_LANG2}"; do
_dir="$(dirname_append "${_parent}" "$d")";
if obj _res path_not_contains "${_dir}" && obj _dir is_dir; then
_res="${_res}:${_dir}";
fi;
done;
if path_not_contains "${_res}" "${_parent}"; then
_res="${_res}:${_parent}";
fi;
path_chop "${_res}";
}
# end manpath_add_lang_sys ()
########################################################################
# manpath_set_from_path ()
#
# Determine basic search path for man pages from $PATH.
#
# Return: `0' if a valid man path was retrieved.
# Output: none
# Globals:
# in: $PATH
# out: $_MAN_PATH
#
manpath_set_from_path()
{
func_check manpath_set_from_path = 0 "$@";
local _base;
local _mandir;
local _manpath;
local d;
local e;
_manpath='';
# get a basic man path from $PATH
if obj PATH is_not_empty; then
eval set -- "$(path_split "${PATH}")";
for d in "$@"; do
# delete the final `/bin' part
_base="$(echo -n "$d" | sed -e '\|.*|s|//*bin/*$||')";
for e in /share/man /man; do
_mandir="${_base}$e";
if test -d "${_mandir}" && test -r "${_mandir}"; then
_manpath="${_manpath}:${_mandir}";
fi;
done;
done;
fi;
# append some default directories
for d in /usr/local/share/man /usr/local/man \
/usr/share/man /usr/man \
/usr/X11R6/man /usr/openwin/man \
/opt/share/man /opt/man \
/opt/gnome/man /opt/kde/man; do
if obj _manpath path_not_contains "$d" && obj d is_dir; then
_manpath="${_manpath}:$d";
fi;
done;
_MAN_PATH="${_manpath}";
eval "${return_ok}";
} # manpath_set_from_path()
########################################################################
landmark '9: obj_*()';
########################################################################
########################################################################
# obj (