Tryag File Manager
Home
-
Turbo Force
Current Path :
/
proc
/
self
/
root
/
usr
/
bin
/
Upload File :
New :
File
Dir
//proc/self/root/usr/bin/groffer
#!/bin/sh # groffer - display groff files # Source file position: <groff-source>/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 (<name>) # # Test whether <name> 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_<prog>_<length>[_<argspec>] # # <prog>: program name GROFFER, GROFF, or CMDLINE (for all # command line options) # <length>: LONG (long options) or SHORT (single character options) # <argspec>: ARG for options with argument, NA for no argument; # without _<argspec> 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 (<text>) # # Print <text> 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 (<text>*) # # Output to stderr. # # Arguments : arbitrary text. # echo2() { echo "$*" >&2; } ############## # echo2n (<text>*) # # Output to stderr. # # Arguments : arbitrary text. # echo2n() { echo -n "$*" >&2; } ############# # diag (text>*) # # Output a diagnostic message to stderr # diag() { echo2 '>>>>>'"$*"; } ############# # error (<text>*) # # 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 (<text>*) # # Terminate program with error condition # abort() { error "Program aborted."; exit 1; } ############# # func_check (<func_name> <rel_op> <nr_args> "$@") # # Check number of arguments and register to _FUNC_STACK. # # Arguments: >=3 # <func_name>: name of the calling function. # <rel_op>: a relational operator: = != < > <= >= # <nr_args>: number of arguments to be checked against <operator> # "$@": 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 (<element>) # # Store another element to stack. # # The stack elements are separated by `!'; if <element> 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 (<text>*) # # Unconditionally terminate the program with error code; # useful for debugging. # # defined above ######################################################################## # apropos_run (<name>) # # 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 (<path>) # # Get the file name part of <path>, i.e. delete everything up to last # `/' from the beginning of <path>. 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 (<file>) # # Decompress if possible or just print <file> to standard output. # # gzip, bzip2, and .Z decompression is supported. # # Arguments: 1, a file name. # Output: the content of <file>, 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 (<text>*) # # Print marked message to standard error; useful for debugging. # # defined above ######################################################################## landmark '4: dirname()*'; ######################################################################## ####################################################################### # dirname_append (<dir> <name>) # # Append `name' to `dir' with clean handling of `/'. # # Arguments : 2 # Output : the generated new directory name <dir>/<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 (<name>) # # 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 (<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 (<text>*) # # Print to standard error with final line break. # # defined above ######################################################################## # echo2n (<text>*) # # Print to standard error without final line break. # # defined above ######################################################################## # error (<text>*) # # Print error message and exit with error code. # # defined above ######################################################################## # func_check (<func_name> <rel_op> <nr_args> "$@") # # Check number of arguments and register to _FUNC_STACK. # # Arguments: >=3 # <func_name>: name of the calling function. # <rel_op>: a relational operator: = != < > <= >= # <nr_args>: number of arguments to be checked against <operator> # "$@": the arguments of the calling function. # # defined above ######################################################################### # func_pop () # # Delete the top element from the function call stack. # # defined above ######################################################################## # func_push (<element>) # # Store another element to function call stack. # # defined above ######################################################################## # func_stack_dump () # # Print the content of the stack. # # defined above ######################################################################## # get_first_essential (<arg>*) # # 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 (<name>) # # 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 (<string>) # # 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 (<string1> <string2>) # # Test whether `string1' is equal to <string2>. # # 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 (<name>) # # 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 (<file_name>) # # 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 (<name>) # # 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 (<string>) # # 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 (<string1> <string2>) # # 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 (<filename>) # # 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 (<name>) # # 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 (<name>) # # 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 (<string>) # # 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 (<name>) # # 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 (<name>) # # 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 (<string>) # # 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 (<list> <element>...) # # Arguments: >=2 # <list>: a variable name for a list of single-quoted elements # <element>: some sequence of characters. # Output: none, but $<list> is set to # if <list> is empty: "'<element>' '...'" # otherwise: "$list '<element>' ..." # 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 (<pre_name_of_opt_lists> [<cmdline_arg>...]) # # 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 # <pre_name>: common part of a set of 4 environment variable names: # $<pre_name>_SHORT_NA: list of short options without an arg. # $<pre_name>_SHORT_ARG: list of short options that have an arg. # $<pre_name>_LONG_NA: list of long options without an arg. # $<pre_name>_LONG_ARG: list of long options that have an arg. # <cmdline_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 (<string> <separator>) # # In <string>, escape all white space characters and replace each # <separator> by space. # # Arguments: 2: a <string> that is to be split into parts divided by # <separator> # 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 (<list>) # # Check whether <list> 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 <list> 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 (<var_name> <element>) # # Arguments: 2 # <var_name>: a variable name for a list of single-quoted elements # <element>: some sequence of characters. # Output: # if <list> is empty: "'<element>' '...'" # otherwise: "list '<element>' ..." # 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 (<list> <element>) # # Arguments: 2 # <list>: a space-separated list of single-quoted elements. # <element>: some sequence of characters. # Output: # if <list> is empty: "'<element>' '...'" # otherwise: "<list> '<element>' ..." # 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 (<filespec>) # # Print suitable man page(s) for filespec to $_TMP_CAT. # # Arguments : 2 # <filespec>: 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 (<file> <name> [<section>]) # # 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 (<name> <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 (<object> <call_name> <arg>...) # # This works like a method (object function) call for an object. # Run "<call_name> $<object> <arg> ...". # # The first argument represents an object whose data is given as first # argument to <call_name>(). # # Argument: >=2 # <object>: variable name # <call_name>: a program or function name # obj() { func_check obj '>=' 2 "$@"; local func; local var; if is_empty "$2"; then error "obj(): function name is empty." else func="$2"; fi; eval arg1='"${'$1'}"'; shift; shift; eval "${func}"' "${arg1}" "$@"'; } ######################################################################## # obj_data (<object>) # # Print the data of <object>, i.e. the content of $<object>. # For possible later extensions. # # Arguments: 1 # <object>: a variable name # Output: the data of <object> # obj_data() { func_check obj '=' 1 "$@"; if is_empty "$1"; then error "obj_data(): object name is empty." fi; eval echo -n '"${'$1'}"'; } ######################################################################## # obj_from_output (<object> <call_name> <arg>...) # # Run '$<object>="$(<call_name> <arg>...)"' to set the result of a # function call to a global variable. # # Arguments: >=2 # <object>: a variable name # <call_name>: the name of a function or program # <arg>: optional argument to <call_name> # Output: none # obj_from_output() { func_check obj_from_output '>=' 2 "$@"; local result_name; if is_empty "$1"; then error "res(): variable name is empty."; elif is_empty "$2"; then error "res(): function name is empty." else result_name="$1"; fi; shift; eval "${result_name}"'="$('"$@"')"'; } ######################################################################## # obj_set (<object> <data>) # # Set the data of <object>, i.e. call "$<object>=<data>". # # Arguments: 2 # <object>: a variable name # <data>: a string # Output:: none # obj_set() { func_check obj_set '=' 2 "$@"; if is_empty "$1"; then error "obj_set(): object name is empty." fi; eval "$1"='"$2"'; } ######################################################################## # path_chop (<path>) # # Remove unnecessary colons from path. # # Argument: 1, a colon separated path. # Output: path without leading, double, or trailing colons. # path_chop() { func_check path_chop = 1 "$@"; local _res; # replace multiple colons by a single colon `:' # remove leading and trailing colons echo -n "$1" | sed -e 's/:::*/:/g' | sed -e 's/^:*//' | sed -e 's/:*$//'; eval "${return_ok}"; } ######################################################################## # path_clean (<path>) # # Remove non-existing directories from a colon-separated list. # # Argument: 1, a colon separated path. # Output: colon-separated list of existing directories. # path_clean() { func_check path_clean = 1 "$@"; local _arg; local _dir; local _res; local i; if is_not_equal "$#" 1; then error 'path_clean() needs 1 argument.'; fi; _arg="$1"; eval set -- "$(path_split "${_arg}")"; _res=""; for i in "$@"; do if obj i is_not_empty \ && obj _res path_not_contains "$i" \ && obj i is_dir; then case "$i" in ?*/) _res="${_res}$(dirname_chop "$i")"; ;; *) _res="${_res}:$i"; esac; fi; done; if path_chop "${_res}"; then eval "${return_ok}"; else eval "${return_badk}"; fi; } ######################################################################## # path_contains (<path> <dir>) #- # Test whether `dir' is contained in `path', a list separated by `:'. # # Arguments : 2 arguments. # Return : `0' if arg2 is substring of arg1, `1' otherwise. # path_contains() { func_check path_contains = 2 "$@"; case ":$1:" in *":$2:"*) eval "${return_yes}"; ;; *) eval "${return_no}"; ;; esac; eval "${return_ok}"; } ######################################################################## # path_not_contains (<path> <dir>) #- # Test whether `dir' is not contained in colon separated `path'. # # Arguments : 2 arguments. # path_not_contains() { func_check path_not_contains = 2 "$@"; if path_contains "$1" "$2"; then eval "${return_no}"; else eval "${return_yes}"; fi; eval "${return_ok}"; } ######################################################################## # path_split (<path>) # # In `path' escape white space and replace each colon by a space. # # Arguments: 1: a colon-separated path # Output: the resulting list, process with `eval set --' # path_split() { func_check path_split = 1 "$@"; list_from_split "$1" ':'; eval "${return_ok}"; } ######################################################################## landmark '10: register_*()'; ######################################################################## ######################################################################## # register_file (<filename>) # # Write a found file and register the title element. # # Arguments: 1: a file name # Output: none # register_file() { func_check register_file = 1 "$@"; if is_empty "$1"; then error 'register_file(): file name is empty'; fi; if is_equal "$1" '-'; then to_tmp "${_TMP_STDIN}"; register_title '-'; else to_tmp "$1"; register_title "$(base_name "$1")"; fi; eval "${return_ok}"; } ######################################################################## # register_title (<filespec>) # # Create title element from <filespec> and append to $_REGISTERED_TITLE # # Globals: $_REGISTERED_TITLE (rw) # register_title() { func_check register_title = 1 "$@"; local _title; if is_empty "$1"; then eval "${return_ok}"; fi; _title="$(base_name "$1")"; # remove directory part # remove extension `.gz' _title="$(echo -n "${_title}" | sed -e 's/\.gz$//')"; # remove extension `.Z' _title="$(echo -n "${_title}" | sed -e 's/\.Z$//')"; if obj _title is_empty; then eval "${return_ok}"; fi; _REGISTERED_TITLE="${_REGISTERED_TITLE} ${_title}"; eval "${return_ok}"; } ######################################################################## # reset () # # Reset the variables that can be affected by options to their default. # # # Defined in section `Preset' after the rudimentary shell tests. ######################################################################## # save_stdin () # # Store standard input to temporary file (with decompression). # if obj _HAS_COMPRESSION is_yes; then save_stdin() { local _f; func_check save_stdin = 0 "$@"; _f="${_TMP_DIR}"/INPUT; cat >"${_f}"; catz "${_f}" >"${_TMP_STDIN}"; rm -f "${_f}"; eval "${return_ok}"; } else save_stdin() { func_check save_stdin = 0 "$@"; cat >"${_TMP_STDIN}"; eval "${return_ok}"; } fi; ######################################################################## landmark '11: stack_*()'; ######################################################################## ######################################################################## # string_contains (<string> <part>) # # Test whether `part' is contained in `string'. # # Arguments : 2 text arguments. # Return : `0' if arg2 is substring of arg1, `1' otherwise. # string_contains() { func_check string_contains = 2 "$@"; case "$1" in *"$2"*) eval "${return_yes}"; ;; *) eval "${return_no}"; ;; esac; eval "${return_ok}"; } ######################################################################## # string_not_contains (<string> <part>) # # Test whether `part' is not substring of `string'. # # Arguments : 2 text arguments. # Return : `0' if arg2 is substring of arg1, `1' otherwise. # string_not_contains() { func_check string_not_contains = 2 "$@"; if string_contains "$1" "$2"; then eval "${return_no}"; else eval "${return_yes}"; fi; eval "${return_ok}"; } ######################################################################## landmark '12: tmp_*()'; ######################################################################## ######################################################################## # tmp_cat () # # output the temporary cat file (the concatenation of all input) # tmp_cat() { cat "${_TMP_CAT}"; } ######################################################################## # tmp_create (<suffix>?) # # create temporary file # # It's safe to use the shell process ID together with a suffix to # have multiple temporary files. # # Output : name of created file # tmp_create() { func_check tmp_create '<=' 1 "$@"; local _tmp; # the output file does not have `,' as first character _tmp="${_TMP_DIR}/,$1"; echo -n >"${_tmp}"; echo -n "${_tmp}"; # output file name eval "${return_ok}"; } ######################################################################## # to_tmp (<filename>) # # print file (decompressed) to the temporary cat file # to_tmp() { func_check to_tmp = 1 "$@"; if is_file "$1"; then if obj _OPT_LOCATION is_yes; then echo2 "$1"; fi; if obj _OPT_WHATIS is_yes; then what_is "$1" >>"${_TMP_CAT}"; else catz "$1" >>"${_TMP_CAT}"; fi; else error "to_tmp(): could not read file \`$1'."; fi; eval "${return_ok}"; } ######################################################################## # trap_clean () # # disable trap on all exit codes ($_ALL_EXIT) # # Arguments: 0 # Globals: $_ALL_EXIT # trap_clean() { func_check trap_clean = 0 "$@"; local i; for i in ${_ALL_EXIT}; do trap "" "$i" 2>/dev/null || true; done; eval "${return_ok}"; } ######################################################################## # trap_set (<functionname>) # # call function on all exit codes ($_ALL_EXIT) # # Arguments: 1 (name of a shell function) # Globals: $_ALL_EXIT # trap_set() { func_check trap_set = 1 "$@"; local i; for i in ${_ALL_EXIT}; do trap "$1" "$i" 2>/dev/null || true; done; eval "${return_ok}"; } ######################################################################## # usage () # # print usage information to stderr; for groffer option --help. # usage() { func_check usage = 0 "$@"; echo; version; echo 'Usage: '"${_PROGRAM_NAME}"' [option]... [filespec]...'; cat <<EOF Display roff files, standard input, and/or Unix manual pages with a X Window viewer or in several text modes. All input is decompressed on-the-fly with all formats that gzip can handle. "filespec" is one of "filename" name of a readable file "-" for standard input "man:name.n" man page "name" in section "n" "man:name" man page "name" in first section found "name.n" man page "name" in section "n" "name" man page "name" in first section found and some more (see groffer(1) for details). -h --help print this usage message. -Q --source output as roff source. -T --device=name pass to groff using output device "name". -v --version print version information. -V display the groff execution pipe instead of formatting. -X --X --x display with "gxditview" using groff -X. -Z --ditroff --intermediate-output generate groff intermediate output without post-processing and viewing, like groff -Z. All other short options are interpreted as "groff" formatting options. The most important groffer long options are --apropos=name start man's "apropos" program for "name". --apropos-data=name "apropos" for "name" in man's data sections 4, 5, 7. --apropos-devel=name "apropos" for "name" in development sections 2, 3, 9. --apropos-progs=name "apropos" for "name" in man's program sections 1, 6, 8. --auto choose mode automatically from the default mode list. --default reset all options to the default value. --default-modes=mode1,mode2,... set sequence of automatically tried modes. --dvi display in a viewer for TeX device independent format. --dvi-viewer choose the viewer program for dvi mode. --groff process like groff, disable viewing features. --help display this helping output. --html --www display in a web browser. --html-viewer choose the web browser for www mode. --man check file parameters first whether they are man pages. --mode=auto|dvi|groff|html|pdf|ps|source|text|tty|www|x|X choose display mode. --no-man disable man-page facility. --pager=program preset the paging program for tty mode. --pdf display in a PDF viewer. --pdf-viewer choose the viewer program for pdf mode. --ps display in a Postscript viewer. --ps-viewer choose the viewer program for ps mode. --shell specify shell under which to run this program. --text output in a text device without a pager. --tty display with a pager on text terminal even when in X. --www-viewer same as --html-viewer --x-viewer choose viewer program for x mode (X mode). --X-viewer same as "--xviewer". The usual X Windows toolkit options transformed into GNU long options --background=color, --bd=size, --bg=color, --bordercolor=color, --borderwidth=size, --bw=size, --display=Xdisplay, --fg=color, --fn=font, --font=font, --foreground=color, --geometry=geom, --iconic, --resolution=dpi, --rv, --title=text, --xrm=resource Long options of GNU "man" --all, --ascii, --ditroff, --extension=suffix, --locale=language, --local-file=name, --location, --manpath=dir1:dir2:..., --sections=s1:s2:..., --systems=s1,s2,..., --whatis, --where, ... EOF eval "${return_ok}"; } ######################################################################## # version () # # print version information to stderr # version() { func_check version = 0 "$@"; echo2 "${_PROGRAM_NAME} ${_PROGRAM_VERSION} of ${_LAST_UPDATE}"; # also display groff's version, but not the called subprograms groff -v 2>&1 | sed -e '/^ *$/q' | sed -e '1s/^/is part of /' >&2; } ######################################################################## # warning (<string>) # # Print warning to stderr # warning() { echo2 "warning: $*"; } ######################################################################## # what_is (<filename>) # # Interpret <filename> as a man page and display its `whatis' # information as a fragment written in the groff language. # what_is() { func_check what_is = 1 "$@"; local _res; local _dot; if is_not_file "$1"; then error "what_is(): argument is not a readable file." fi; _dot='^\.['"${_SPACE}${_TAB}"']*'; echo '.br'; echo "$1: "; echo '.br'; echo -n ' '; # grep the line containing `.TH' macro, if any _res="$(catz "$1" | sed -e '/'"${_dot}"'TH /p d')"; if obj _res is_not_empty; then # traditional man style # get the text between the first and the second `.SH' macro, by # - delete up to first .SH; # - of this, print everything up to next .SH, and delete the rest; # - of this, delete the final .SH line; catz "$1" | sed -e '1,/'"${_dot}"'SH/d' \ | sed -e '1,/'"${_dot}"'SH/p d' \ | sed -e '/'"${_dot}"'SH/d'; eval "${return_ok}"; fi; # grep the line containing `.Dd' macro, if any _res="$(catz "$1" | sed -e '/'"${_dot}"'Dd /p d')"; if obj _res is_not_empty; then # BSD doc style # get the text between the first and the second `.Nd' macro, by # - delete up to first .Nd; # - of this, print everything up to next .Nd, and delete the rest; # - of this, delete the final .Nd line; catz "$1" | sed -e '1,/'"${_dot}"'Nd/d' \ | sed -e '1,/'"${_dot}"'Nd/p d' \ | sed -e '/'"${_dot}"'Nd/d'; eval "${return_ok}"; fi; echo 'is not a man page.'; eval "${return_bad}"; } ######################################################################## # where (<program>) # # Output path of a program if in $PATH. # # Arguments : >=1 (empty allowed) # more args are ignored, this allows to specify progs with arguments # Return : `0' if arg1 is a program in $PATH, `1' otherwise. # where() { func_check where '>=' 1 "$@"; local _file; local _arg; local p; _arg="$1"; if obj _arg is_empty; then eval "${return_bad}"; fi; case "${_arg}" in /*) if test -f "${_arg}" && test -x "${_arg}"; then eval "${return_ok}"; else eval "${return_bad}"; fi; ;; esac; eval set -- "$(path_split "${PATH}")"; for p in "$@"; do case "$p" in */) _file=${p}${_arg}; ;; *) _file=${p}/${_arg}; ;; esac; if test -f "${_file}" && test -x "${_file}"; then echo -n "${_file}"; eval "${return_ok}"; fi; done; eval "${return_bad}"; } ######################################################################## # main ######################################################################## # The main area contains the following parts: # - main_init(): initialize temporary files and set exit trap # - parse $MANOPT # - main_parse_args(): argument parsing # - determine display mode # - process filespec arguments # - setup X resources # - do the displaying # These parts are implemented as functions, being defined below in the # sequence they are called in the main() function. ####################################################################### # main_init () # # set exit trap and create temporary files # # Globals: $_TMP_CAT, $_TMP_STDIN # landmark '13: main_init()'; main_init() { func_check main_init = 0 "$@"; # call clean_up() on any signal trap_set clean_up; # determine temporary directory umask 000; _TMP_DIR=''; for d in "${GROFF_TMPDIR}" "${TMPDIR}" "${TMP}" "${TEMP}" \ "${TEMPDIR}" "${HOME}"'/tmp' '/tmp' "${HOME}" '.'; do if is_not_empty "$d"; then if obj d is_dir && obj d is_writable; then _TMP_DIR="`mktemp -d ${d}/${_PROGRAM_NAME}.XXXXXX`"; if test $? = 0; then break; else _TMP_DIR=''; continue; fi fi; if obj _TMP_DIR is_not_writable; then _TMP_DIR=''; continue; fi; fi; done; unset d; if obj _TMP_DIR is_empty; then error "Couldn't create a directory for storing temporary files."; fi; _TMP_CAT="$(tmp_create groffer_cat)"; _TMP_STDIN="$(tmp_create groffer_input)"; # groffer configuration files for f in ${_CONFFILES}; do if obj f is_file; then echo '_groffer_opt=""' >>${_TMP_CAT}; # collect the lines starting with a minus cat "$f" | sed -e \ 's/^[ ]*\(-.*\)$/_groffer_opt="${_groffer_opt} \1"'/ \ >>${_TMP_CAT}; # prepend the collected information to $GROFFER_OPT echo 'GROFFER_OPT="${_groffer_opt} ${GROFFER_OPT}"' >>${_TMP_CAT}; fi; done; . "${_TMP_CAT}"; _TMP_CAT="$(tmp_create groffer_cat)"; eval "${return_ok}"; } # main_init() ######################################################################## # main_parse_MANOPT () # # Parse $MANOPT to retrieve man options, but only if it is a non-empty # string; found man arguments can be overwritten by the command line. # # Globals: # in: $MANOPT, $_OPTS_MANOPT_* # out: $_MANOPT_* # in/out: $GROFFER_OPT # landmark '14: main_parse_MANOPT()'; main_parse_MANOPT() { func_check main_parse_MANOPT = 0 "$@"; local _opt; local _list; _list=''; if obj MANOPT is_not_empty; then MANOPT="$(echo -n "${MANOPT}" | \ sed -e 's/^'"${_SPACE}${_SPACE}"'*//')"; fi; if obj MANOPT is_empty; then eval "${return_ok}"; fi; # add arguments in $MANOPT by mapping them to groffer options eval set -- "$(list_from_cmdline _OPTS_MANOPT "${MANOPT}")"; until test "$#" -le 0 || is_equal "$1" '--'; do _opt="$1"; shift; case "${_opt}" in -7|--ascii) list_append _list '--ascii'; ;; -a|--all) list_append _list '--all'; ;; -c|--catman) do_nothing; shift; ;; -d|--debug) list_append _list '--debug'; ;; -D|--default) # undo all man options so far _list=''; ;; -e|--extension) list_append _list '--extension'; shift; ;; -f|--whatis) list_append _list '--whatis'; shift; ;; -h|--help) do_nothing; shift; ;; -k|--apropos) # groffer's --apropos takes an argument, but man's does not, so do_nothing; shift; ;; -l|--local-file) list_append _list '--local-file'; ;; -L|--locale) list_append _list '--locale' "$1"; shift; ;; -m|--systems) list_append _list '--systems' "$1"; shift; ;; -M|--manpath) list_append _list '--manpath' "$1"; shift; ;; -p|--preprocessor) do_nothing; shift; ;; -P|--pager|--tty-viewer) list_append _list '--pager' "$1"; shift; ;; -r|--prompt) do_nothing; shift; ;; -S|--sections) list_append _list '--sections' "$1"; shift; ;; -t|--troff) do_nothing; shift; ;; -T|--device) list_append _list '-T' "$1"; shift; ;; -u|--update) do_nothing; shift; ;; -V|--version) do_nothing; ;; -w|--where|--location) list_append _list '--location'; ;; -Z|--ditroff) list_append _list '-Z' "$1"; shift; ;; # ignore all other options esac; done; # append the 2 lists in $_list and $GROFFER_OPT to $GROFFER_OPT if obj GROFFER_OPT is_empty; then GROFFER_OPT="${_list}"; elif obj _list is_not_empty; then GROFFER_OPT="${_list} ${GROFFER_OPT}"; fi; eval "${return_ok}"; } # main_parse_MANOPT() ######################################################################## # main_parse_args (<command_line_args>*) # # Parse arguments; process options and filespec parameters # # Arguments: pass the command line arguments unaltered. # Globals: # in: $_OPTS_* # out: $_OPT_*, $_ADDOPTS, $_FILEARGS # landmark '15: main_parse_args()'; main_parse_args() { func_check main_parse_args '>=' 0 "$@"; local _arg; local _code; local _dpi; local _longopt; local _mode; local _opt; local _optchar; local _optarg; local _opts; local _string; eval set -- "${GROFFER_OPT}" '"$@"'; eval set -- "$(list_from_cmdline _OPTS_CMDLINE "$@")"; # By the call of `eval', unnecessary quoting was removed. So the # positional shell parameters ($1, $2, ...) are now guaranteed to # represent an option or an argument to the previous option, if any; # then a `--' argument for separating options and # parameters; followed by the filespec parameters if any. # Note, the existence of arguments to options has already been checked. # So a check for `$#' or `--' should not be done for arguments. until test "$#" -le 0 || is_equal "$1" '--'; do _opt="$1"; # $_opt is fed into the option handler shift; case "${_opt}" in -h|--help) usage; leave; ;; -Q|--source) # output source code (`Quellcode'). _OPT_MODE='source'; ;; -T|--device|--troff-device) # device; arg _OPT_DEVICE="$1"; _check_device_with_mode; shift; ;; -v|--version) version; leave; ;; -V) _OPT_V='yes'; ;; -Z|--ditroff|--intermediate-output) # groff intermediate output _OPT_Z='yes'; ;; -X|--X|--x) _OPT_MODE=x; ;; -?) # delete leading `-' _optchar="$(echo -n "${_opt}" | sed -e 's/^.//')"; if list_has _OPTS_GROFF_SHORT_NA "${_optchar}"; then list_append _ADDOPTS_GROFF "${_opt}"; elif list_has _OPTS_GROFF_SHORT_ARG "${_optchar}"; then list_append _ADDOPTS_GROFF "${_opt}" "$1"; shift; else error "Unknown option : \`$1'"; fi; ;; --all) _OPT_ALL="yes"; ;; --apropos) # run `apropos' apropos_run "$1"; _code="$?"; clean_up; exit "${_code}"; ;; --apropos-data) # run `apropos' for data sections apropos_run "$1" | grep '^[^(]*([457][^)]*)'; _code="$?"; clean_up; exit "${_code}"; ;; --apropos-devel) # run `apropos' for development sections apropos_run "$1" | grep '^[^(]*([239][^)]*)'; _code="$?"; clean_up; exit "${_code}"; ;; --apropos-progs) # run `apropos' for program sections apropos_run "$1" | grep '^[^(]*([168][^)]*)'; _code="$?"; clean_up; exit "${_code}"; ;; --ascii) list_append _ADDOPTS_GROFF '-mtty-char'; if obj _mode is_empty; then _mode='text'; fi; ;; --auto) # the default automatic mode _mode=''; ;; --bd) # border color for viewers, arg; _OPT_BD="$1"; shift; ;; --bg|--backgroud) # background color for viewers, arg; _OPT_BG="$1"; shift; ;; --bw) # border width for viewers, arg; _OPT_BW="$1"; shift; ;; --default) # reset variables to default reset; ;; --default-modes) # sequence of modes in auto mode; arg _OPT_DEFAULT_MODES="$1"; shift; ;; --debug) # buggy, only for development _OPT_DEBUG='yes'; ;; --display) # set X display, arg _OPT_DISPLAY="$1"; shift; ;; --dvi) _OPT_MODE='dvi'; ;; --dvi-viewer) # viewer program for dvi mode; arg _OPT_VIEWER_DVI="$1"; shift; ;; --extension) # the extension for man pages, arg _OPT_EXTENSION="$1"; shift; ;; --fg|--foreground) # foreground color for viewers, arg; _OPT_FG="$1"; shift; ;; --fn|--font) # set font for viewers, arg; _OPT_FN="$1"; shift; ;; --geometry) # window geometry for viewers, arg; _OPT_GEOMETRY="$1"; shift; ;; --groff) _OPT_MODE='groff'; ;; --html|--www) # display with web browser _OPT_MODE=html; ;; --html-viewer|--www-viewer) # viewer program for html mode; arg _OPT_VIEWER_HTML="$1"; shift; ;; --iconic) # start viewers as icons _OPT_ICONIC='yes'; ;; --locale) # set language for man pages, arg # argument is xx[_territory[.codeset[@modifier]]] (ISO 639,...) _OPT_LANG="$1"; shift; ;; --local-file) # force local files; same as `--no-man' _MAN_FORCE='no'; _MAN_ENABLE='no'; ;; --location|--where) # print file locations to stderr _OPT_LOCATION='yes'; ;; --man) # force all file params to be man pages _MAN_ENABLE='yes'; _MAN_FORCE='yes'; ;; --manpath) # specify search path for man pages, arg # arg is colon-separated list of directories _OPT_MANPATH="$1"; shift; ;; --mode) # display mode _arg="$1"; shift; case "${_arg}" in auto|'') # search mode automatically among default _mode=''; ;; groff) # pass input to plain groff _mode='groff'; ;; html|www) # display with a web browser _mode='html'; ;; dvi) # display with xdvi viewer _mode='dvi'; ;; pdf) # display with PDF viewer _mode='pdf'; ;; ps) # display with Postscript viewer _mode='ps'; ;; text) # output on terminal _mode='text'; ;; tty) # output on terminal _mode='tty'; ;; X|x) # output on X roff viewer _mode='x'; ;; Q|source) # display source code _mode="source"; ;; *) error "unknown mode ${_arg}"; ;; esac; _OPT_MODE="${_mode}"; ;; --no-location) # disable former call to `--location' _OPT_LOCATION='yes'; ;; --no-man) # disable search for man pages # the same as --local-file _MAN_FORCE="no"; _MAN_ENABLE="no"; ;; --pager) # set paging program for tty mode, arg _OPT_PAGER="$1"; shift; ;; --pdf) _OPT_MODE='pdf'; ;; --pdf-viewer) # viewer program for ps mode; arg _OPT_VIEWER_PDF="$1"; shift; ;; --ps) _OPT_MODE='ps'; ;; --ps-viewer) # viewer program for ps mode; arg _OPT_VIEWER_PS="$1"; shift; ;; --resolution) # set resolution for X devices, arg _arg="$1"; shift; case "${_arg}" in 75|75dpi) _dpi=75; ;; 100|100dpi) _dpi=100; ;; *) error "only resoutions of 75 or 100 dpi are supported"; ;; esac; _OPT_RESOLUTION="${_dpi}"; ;; --rv) _OPT_RV='yes'; ;; --sections) # specify sections for man pages, arg # arg is colon-separated list of section names _OPT_SECTIONS="$1"; shift; ;; --shell) # already done during the first run; so ignore the argument shift; ;; --systems) # man pages for different OS's, arg # argument is a comma-separated list _OPT_SYSTEMS="$1"; shift; ;; --text) # text mode without pager _OPT_MODE=text; ;; --title) # title for X viewers; arg _OPT_TITLE="$1"; shift; ;; --tty) # tty mode, text with pager _OPT_MODE=tty; ;; --text-device|--tty-device) # device for tty mode; arg _OPT_TEXT_DEVICE="$1"; shift; ;; --whatis) _OPT_WHATIS='yes'; ;; --xrm) # pass X resource string, arg; list_append _OPT_XRM "$1"; shift; ;; --x-viewer|--X-viewer) # viewer program for x mode; arg _OPT_VIEWER_X="$1"; shift; ;; *) error 'error on argument parsing : '"\`$*'"; ;; esac; done; shift; # remove `--' argument if obj _DEBUG is_not_yes; then if obj _OPT_DEBUG is_yes; then _DEBUG='yes'; fi; fi; # Remaining arguments are file names (filespecs). # Save them to list $_FILEARGS if is_equal "$#" 0; then # use "-" for standard input set -- '-'; fi; _FILEARGS=''; list_append _FILEARGS "$@"; if list_has _FILEARGS '-'; then save_stdin; fi; # $_FILEARGS must be retrieved with `eval set -- "$_FILEARGS"' eval "${return_ok}"; } # main_parse_args() # Called from main_parse_args() because double `case' is not possible. # Globals: $_OPT_DEVICE, $_OPT_MODE _check_device_with_mode() { func_check _check_device_with_mode = 0 "$@"; case "${_OPT_DEVICE}" in dvi) _OPT_MODE=dvi; eval "${return_ok}"; ;; html) _OPT_MODE=html; eval "${return_ok}"; ;; lbp|lj4) _OPT_MODE=groff; eval "${return_ok}"; ;; ps) _OPT_MODE=ps; eval "${return_ok}"; ;; ascii|cp1047|latin1|utf8) if obj _OPT_MODE is_not_equal text; then _OPT_MODE=tty; # default text mode fi; eval "${return_ok}"; ;; X*) _OPT_MODE=x; eval "${return_ok}"; ;; *) # unknown device, go to groff mode _OPT_MODE=groff; eval "${return_ok}"; ;; esac; eval "${return_error}"; } ######################################################################## # main_set_mode () # # Determine the display mode. # # Globals: # in: $DISPLAY, $_OPT_MODE, $_OPT_DEVICE # out: $_DISPLAY_MODE # # _get_first_prog (<proglist>) # # Retrieve first argument that represents an existing program in $PATH. # Local function for main_set_mode(). # # Arguments: 1; a comma-separated list of commands (with options), # like $_VIEWER_*. # # Return : `1' if none found, `0' if found. # Output : the argument that succeded. # landmark '16: main_set_mode()'; main_set_mode() { func_check main_set_mode = 0 "$@"; local m; local _modes; local _viewer; local _viewers; # handle apropos if obj _OPT_APROPOS is_not_empty; then apropos "${_OPT_APROPOS}"; _code="$?"; clean_up; exit "${_code}"; fi; if obj _OPT_APROPOS_DATA is_not_empty; then apropos "$@" | grep '^[^(]*([457])'; _code="$?"; clean_up; exit "${_code}"; fi; if obj _OPT_APROPOS_DEVEL is_not_empty; then apropos "$@" | grep '^[^(]*([239])'; _code="$?"; clean_up; exit "${_code}"; fi; if obj _OPT_APROPOS_PROGS is_not_empty; then apropos "$@" | grep '^[^(]*([168])'; _code="$?"; clean_up; exit "${_code}"; fi; # set display if obj _OPT_DISPLAY is_not_empty; then DISPLAY="${_OPT_DISPLAY}"; fi; if obj _OPT_V is_yes; then _DISPLAY_MODE='groff'; list_append _ADDOPTS_GROFF '-V'; fi; if obj _OPT_Z is_yes; then _DISPLAY_MODE='groff'; list_append _ADDOPTS_GROFF '-Z'; fi; if obj _OPT_MODE is_equal 'groff'; then _DISPLAY_MODE='groff'; fi; if obj _DISPLAY_MODE is_equal 'groff'; then eval "${return_ok}"; fi; if obj _OPT_MODE is_equal 'source'; then _DISPLAY_MODE='source'; eval "${return_ok}"; fi; case "${_OPT_MODE}" in '') # automatic mode case "${_OPT_DEVICE}" in X*) if obj DISPLAY is_empty; then error "no X display found for device ${_OPT_DEVICE}"; fi; _DISPLAY_MODE='x'; eval "${return_ok}"; ;; ascii|cp1047|latin1|utf8) if obj _DISPLAY_MODE is_not_equal 'text'; then _DISPLAY_MODE='tty'; fi; eval "${return_ok}"; ;; esac; if obj DISPLAY is_empty; then _DISPLAY_MODE='tty'; eval "${return_ok}"; fi; if obj _OPT_DEFAULT_MODES is_empty; then _modes="${_DEFAULT_MODES}"; else _modes="${_OPT_DEFAULT_MODES}"; fi; ;; text) _DISPLAY_MODE='text'; eval "${return_ok}"; ;; tty) _DISPLAY_MODE='tty'; eval "${return_ok}"; ;; *) # display mode was given if obj DISPLAY is_empty; then error "you must be in X Window for ${_OPT_MODE} mode."; fi; _modes="${_OPT_MODE}"; ;; esac; # only viewer modes are left eval set -- "$(list_from_split "${_modes}" ',')"; while test "$#" -gt 0; do m="$1"; shift; case "$m" in text) _DISPLAY_MODE='text'; eval "${return_ok}"; ;; tty) _DISPLAY_MODE='tty'; eval "${return_ok}"; ;; x) if obj _OPT_VIEWER_X is_not_empty; then _viewers="${_OPT_VIEWER_X}"; else _viewers="${_VIEWER_X}"; fi; _viewer="$(_get_first_prog "${_viewers}")"; if is_not_equal "$?" 0; then continue; fi; _DISPLAY_PROG="${_viewer}"; _DISPLAY_MODE='x'; eval "${return_ok}"; ;; dvi) if obj _OPT_VIEWER_DVI is_not_empty; then _viewers="${_OPT_VIEWER_DVI}"; else _viewers="${_VIEWER_DVI}"; fi; _viewer="$(_get_first_prog "${_viewers}")"; if is_not_equal "$?" 0; then continue; fi; _DISPLAY_PROG="${_viewer}"; _DISPLAY_MODE="dvi"; eval "${return_ok}"; ;; pdf) if obj _OPT_VIEWER_PDF is_not_empty; then _viewers="${_OPT_VIEWER_PDF}"; else _viewers="${_VIEWER_PDF}"; fi; _viewer="$(_get_first_prog "${_viewers}")"; if is_not_equal "$?" 0; then continue; fi; _DISPLAY_PROG="${_viewer}"; _DISPLAY_MODE="pdf"; eval "${return_ok}"; ;; ps) if obj _OPT_VIEWER_PS is_not_empty; then _viewers="${_OPT_VIEWER_PS}"; else _viewers="${_VIEWER_PS}"; fi; _viewer="$(_get_first_prog "${_viewers}")"; if is_not_equal "$?" 0; then continue; fi; _DISPLAY_PROG="${_viewer}"; _DISPLAY_MODE="ps"; eval "${return_ok}"; ;; html) if obj _OPT_VIEWER_HTML is_not_empty; then _viewers="${_OPT_VIEWER_HTML}"; else _viewers="${_VIEWER_HTML}"; fi; _viewer="$(_get_first_prog "${_viewers}")"; if is_not_equal "$?" 0; then continue; fi; _DISPLAY_PROG="${_viewer}"; _DISPLAY_MODE=html; eval "${return_ok}"; ;; esac; done; error "no suitable display mode found."; } _get_first_prog() { local i; if is_equal "$#" 0; then error "_get_first_prog() needs 1 argument."; fi; if is_empty "$1"; then return "${_BAD}"; fi; eval set -- "$(list_from_split "$1" ',')"; for i in "$@"; do if obj i is_empty; then continue; fi; if is_prog "$(get_first_essential $i)"; then echo -n "$i"; return "${_GOOD}"; fi; done; return "${_BAD}"; } # main_set_mode() ####################################################################### # main_do_fileargs () # # Process filespec arguments in $_FILEARGS. # # Globals: # in: $_FILEARGS (process with `eval set -- "$_FILEARGS"') # landmark '17: main_do_fileargs()'; main_do_fileargs() { func_check main_do_fileargs = 0 "$@"; local _exitcode; local _filespec; local _name; _exitcode="${_BAD}"; eval set -- "${_FILEARGS}"; unset _FILEARGS; # temporary storage of all input to $_TMP_CAT while test "$#" -ge 2; do # test for `s name' arguments, with `s' a 1-char standard section _filespec="$1"; shift; case "${_filespec}" in '') continue; ;; '-') if register_file '-'; then _exitcode="${_GOOD}"; fi; continue; ;; ?) if list_has_not _MAN_AUTO_SEC "${_filespec}"; then if do_filearg "${_filespec}"; then _exitcode="${_GOOD}"; fi; continue; fi; _name="$1"; case "${_name}" in */*|man:*|*\(*\)|*."${_filespec}") if do_filearg "${_filespec}"; then _exitcode="${_GOOD}"; fi; continue; ;; esac; if do_filearg "man:${_name}(${_filespec})"; then _exitcode="${_GOOD}"; shift; continue; else if do_filearg "${_filespec}"; then _exitcode="${_GOOD}"; fi; continue; fi; ;; *) if do_filearg "${_filespec}"; then _exitcode="${_GOOD}"; fi; continue; ;; esac; done; # end of `s name' test while test "$#" -gt 0; do _filespec="$1"; shift; if do_filearg "${_filespec}"; then _exitcode="${_GOOD}"; fi; done; rm -f "${_TMP_STDIN}"; if is_equal "${_exitcode}" "${_BAD}"; then eval "${return_bad}"; fi; eval "${return_ok}"; } # main_do_fileargs() ######################################################################## # main_set_resources () # # Determine options for setting X resources with $_DISPLAY_PROG. # # Globals: $_DISPLAY_PROG, $_OUTPUT_FILE_NAME # landmark '18: main_set_resources()'; main_set_resources() { func_check main_set_resources = 0 "$@"; local _prog; # viewer program local _rl; # resource list local n; _title="$(get_first_essential \ "${_OPT_TITLE}" "${_REGISTERED_TITLE}")"; _OUTPUT_FILE_NAME=''; set -- ${_title}; until is_equal "$#" 0; do n="$1"; case "$n" in '') continue; ;; ,*) n="$(echo -n "$1" | sed -e 's/^,,*//')"; ;; esac if obj n is_empty; then continue; fi; if obj _OUTPUT_FILE_NAME is_not_empty; then _OUTPUT_FILE_NAME="${_OUTPUT_FILE_NAME},"; fi; _OUTPUT_FILE_NAME="${_OUTPUT_FILE_NAME}$n"; shift; done; case "${_OUTPUT_FILE_NAME}" in '') _OUTPUT_FILE_NAME='-'; ;; ,*) error "$_OUTPUT_FILE_NAME starts with a comma."; ;; esac; _OUTPUT_FILE_NAME="${_TMP_DIR}/${_OUTPUT_FILE_NAME}"; if obj _DISPLAY_PROG is_empty; then # for example, for groff mode _DISPLAY_ARGS=''; eval "${return_ok}"; fi; set -- ${_DISPLAY_PROG}; _prog="$(base_name "$1")"; _rl=''; if obj _OPT_BD is_not_empty; then case "${_prog}" in ghostview|gv|gxditview|xditview|xdvi) list_append _rl '-bd' "${_OPT_BD}"; ;; esac; fi; if obj _OPT_BG is_not_empty; then case "${_prog}" in ghostview|gv|gxditview|xditview|xdvi) list_append _rl '-bg' "${_OPT_BG}"; ;; xpdf) list_append _rl '-papercolor' "${_OPT_BG}"; ;; esac; fi; if obj _OPT_BW is_not_empty; then case "${_prog}" in ghostview|gv|gxditview|xditview|xdvi) _list_append _rl '-bw' "${_OPT_BW}"; ;; esac; fi; if obj _OPT_FG is_not_empty; then case "${_prog}" in ghostview|gv|gxditview|xditview|xdvi) list_append _rl '-fg' "${_OPT_FG}"; ;; esac; fi; if is_not_empty "${_OPT_FN}"; then case "${_prog}" in ghostview|gv|gxditview|xditview|xdvi) list_append _rl '-fn' "${_OPT_FN}"; ;; esac; fi; if is_not_empty "${_OPT_GEOMETRY}"; then case "${_prog}" in ghostview|gv|gxditview|xditview|xdvi|xpdf) list_append _rl '-geometry' "${_OPT_GEOMETRY}"; ;; esac; fi; if is_empty "${_OPT_RESOLUTION}"; then _OPT_RESOLUTION="${_DEFAULT_RESOLUTION}"; case "${_prog}" in gxditview|xditview) list_append _rl '-resolution' "${_DEFAULT_RESOLUTION}"; ;; xpdf) case "${_DEFAULT_RESOLUTION}" in 75) # 72dpi is '100' list_append _rl '-z' '104'; ;; 100) list_append _rl '-z' '139'; ;; esac; ;; esac; else case "${_prog}" in ghostview|gv|gxditview|xditview|xdvi) list_append _rl '-resolution' "${_OPT_RESOLUTION}"; ;; xpdf) case "${_OPT_RESOLUTION}" in 75) list_append _rl '-z' '104'; # '100' corresponds to 72dpi ;; 100) list_append _rl '-z' '139'; ;; esac; ;; esac; fi; if is_yes "${_OPT_ICONIC}"; then case "${_prog}" in ghostview|gv|gxditview|xditview|xdvi) list_append _rl '-iconic'; ;; esac; fi; if is_yes "${_OPT_RV}"; then case "${_prog}" in ghostview|gv|gxditview|xditview|xdvi) list_append _rl '-rv'; ;; esac; fi; if is_not_empty "${_OPT_XRM}"; then case "${_prog}" in ghostview|gv|gxditview|xditview|xdvi|xpdf) eval set -- "{$_OPT_XRM}"; for i in "$@"; do list_append _rl '-xrm' "$i"; done; ;; esac; fi; if is_not_empty "${_title}"; then case "${_prog}" in gxditview|xditview) list_append _rl '-title' "${_title}"; ;; esac; fi; _DISPLAY_ARGS="${_rl}"; eval "${return_ok}"; } # main_set_resources ######################################################################## # main_display () # # Do the actual display of the whole thing. # # Globals: # in: $_DISPLAY_MODE, $_OPT_DEVICE, # $_ADDOPTS_GROFF, $_ADDOPTS_POST, $_ADDOPTS_X, # $_REGISTERED_TITLE, $_TMP_CAT, # $_OPT_PAGER $PAGER $_MANOPT_PAGER # landmark '19: main_display()'; main_display() { func_check main_display = 0 "$@"; local p; local _addopts; local _device; local _groggy; local _modefile; local _options; local _pager; local _title; export _addopts; export _groggy; export _modefile; if obj _TMP_CAT is_non_empty_file; then _modefile="${_OUTPUT_FILE_NAME}"; else clean_up; eval "${return_ok}"; fi; case "${_DISPLAY_MODE}" in groff) _ADDOPTS_GROFF="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}"; if obj _OPT_DEVICE is_not_empty; then _ADDOPTS_GROFF="${_ADDOPTS_GROFF} -T${_OPT_DEVICE}"; fi; _groggy="$(tmp_cat | eval grog "${_options}")"; trap_clean; # start a new shell program to get another process ID. sh -c ' set -e; test -f "${_modefile}" && rm -f "${_modefile}"; mv "${_TMP_CAT}" "${_modefile}"; cat "${_modefile}" | \ ( clean_up() { if test -d "${_TMP_DIR}"; then rm -f "${_TMP_DIR}"/* || true; rmdir "${_TMP_DIR}"; fi; } trap clean_up 0 2>/dev/null || true; eval "${_groggy}" "${_ADDOPTS_GROFF}"; ) &' ;; text|tty) case "${_OPT_DEVICE}" in '') _device="$(get_first_essential \ "${_OPT_TEXT_DEVICE}" "${_DEFAULT_TTY_DEVICE}")"; ;; ascii|cp1047|latin1|utf8) _device="${_OPT_DEVICE}"; ;; *) warning \ "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; ;; esac; _addopts="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}"; _groggy="$(tmp_cat | grog -T${_device})"; if obj _DISPLAY_MODE is_equal 'text'; then tmp_cat | eval "${_groggy}" "${_addopts}"; else _pager=''; for p in "${_OPT_PAGER}" "${PAGER}" "${_MANOPT_PAGER}" \ 'less -r -R' 'more' 'pager' 'cat'; do if is_prog $p; then # no "" for is_prog() allows args for $p _pager="$p"; break; fi; done; if obj _pager is_empty; then error 'no pager program found for tty mode'; fi; tmp_cat | eval "${_groggy}" "${_addopts}" | \ eval "${_pager}"; fi; clean_up; ;; #### viewer modes dvi) case "${_OPT_DEVICE}" in ''|dvi) do_nothing; ;; *) warning \ "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; ;; esac; _groggy="$(tmp_cat | grog -Tdvi)"; _do_display; ;; html) case "${_OPT_DEVICE}" in ''|html) do_nothing; ;; *) warning \ "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; ;; esac; _modefile="${_modefile}".html _groggy="$(tmp_cat | grog -Thtml)"; _do_display; ;; pdf) case "${_OPT_DEVICE}" in ''|ps) do_nothing; ;; *) warning \ "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; ;; esac; _modefile="${_modefile}" _groggy="$(tmp_cat | grog -Tps)"; trap_clean; # start a new shell program to get another process ID. sh -c ' set -e; _psfile="${_modefile}.ps"; _modefile="${_modefile}.pdf"; test -f "${_psfile}" && rm -f "${_psfile}"; test -f "${_modefile}" && rm -f "${_modefile}"; cat "${_TMP_CAT}" | \ eval "${_groggy}" "${_ADDOPTS_GROFF}" > "${_psfile}"; gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \ -sOutputFile="${_modefile}" -c save pop -f "${_psfile}"; test -f "${_psfile}" && rm -f "${_psfile}"; test -f "${_TMP_CAT}" && rm -f "${_TMP_CAT}"; ( clean_up() { rm -f "${_modefile}"; if test -d "${_TMP_DIR}"; then rm -f "${_TMP_DIR}"/* || true; rmdir "${_TMP_DIR}"; fi; } trap clean_up 0 2>/dev/null || true; eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "${_modefile}"; ) &' ;; ps) case "${_OPT_DEVICE}" in ''|ps) do_nothing; ;; *) warning \ "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; ;; esac; _groggy="$(tmp_cat | grog -Tps)"; _do_display; ;; source) tmp_cat; clean_up; ;; x) case "${_OPT_DEVICE}" in '') _groggy="$(tmp_cat | grog -Z)"; ;; X*|ps) _groggy="$(tmp_cat | grog -T"${_OPT_DEVICE}" -Z)"; ;; *) warning \ "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; _groggy="$(tmp_cat | grog -Z)"; ;; esac; _do_display; ;; *) error "unknown mode \`${_DISPLAY_MODE}'"; ;; esac; eval "${return_ok}"; } # main_display() _do_display() { func_check _do_display = 0 "$@"; trap_clean; # start a new shell program for another process ID and better # cleaning-up of the temporary files. sh -c ' set -e; test -f "${_modefile}" && rm -f "${_modefile}"; cat "${_TMP_CAT}" | \ eval "${_groggy}" "${_ADDOPTS_GROFF}" > "${_modefile}"; rm -f "${_TMP_CAT}"; ( clean_up() { if test -d "${_TMP_DIR}"; then rm -f "${_TMP_DIR}"/* || true; rmdir "${_TMP_DIR}"; fi; } trap clean_up 0 2>/dev/null || true; eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "${_modefile}"; ) &' } ######################################################################## # main (<command_line_args>*) # # The main function for groffer. # # Arguments: # main() { func_check main '>=' 0 "$@"; # Do not change the sequence of the following functions! main_init; main_parse_MANOPT; main_parse_args "$@"; main_set_mode; main_do_fileargs; main_set_resources; main_display; eval "${return_ok}"; } landmark '20: end of function definitions'; ######################################################################## main "$@";