Current Path : /usr/src/contrib/groff/contrib/groffer/ |
FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64 |
Current File : //usr/src/contrib/groff/contrib/groffer/groffer2.sh |
#! /bin/sh # groffer - display groff files # Source file position: <groff-source>/contrib/groffer/groffer2.sh # Installed position: <prefix>/lib/groff/groffer/groffer2.sh # This file should not be run independently. It is called by # `groffer.sh' in the source or by the installed `groffer' program. # Copyright (C) 2001,2002,2003,2004,2005 # Free Software Foundation, Inc. # Written by Bernd Warken # Last update: 22 August 2005 # This file is part of `groffer', which is part of `groff'. # `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, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, # USA. ######################################################################## # Test of rudimentary shell functionality ######################################################################## ######################################################################## # Test of `unset' # export _UNSET; export _foo; _foo=bar; _res="$(unset _foo 2>&1)"; if unset _foo >${_NULL_DEV} 2>&1 && \ test _"${_res}"_ = __ && test _"${_foo}"_ = __ then _UNSET='unset'; eval "${_UNSET}" _foo; eval "${_UNSET}" _res; else _UNSET=':'; fi; ######################################################################## # Test of `test'. # if test a = a && test a != b && test -f "${_GROFFER_SH}" then :; else echo '"test" did not work.' >&2; exit "${_ERROR}"; fi; ######################################################################## # Test of `echo' and the `$()' construct. # if echo '' >${_NULL_DEV} then :; else echo '"echo" did not work.' >&2; exit "${_ERROR}"; fi; if test _"$(t1="$(echo te)" && t2="$(echo '')" && t3="$(echo 'st')" && echo "${t1}${t2}${t3}")"_ \ != _test_ then echo 'The "$()" construct did not work' >&2; exit "${_ERROR}"; fi; ######################################################################## # Test of sed program; test in groffer.sh is not valid here. # if test _"$(echo red | sed -e 's/r/s/')"_ != _sed_ then echo 'The sed program did not work.' >&2; exit "${_ERROR}"; fi; ######################################################################## # Test of function definitions. # _t_e_s_t_f_u_n_c_() { return 0; } if _t_e_s_t_f_u_n_c_ 2>${_NULL_DEV} then :; else echo 'Shell '"${_SHELL}"' does not support function definitions.' >&2; exit "${_ERROR}"; fi; ######################################################################## # debug - diagnostic messages ######################################################################## export _DEBUG_STACKS; _DEBUG_STACKS='no'; # disable stack output in each function #_DEBUG_STACKS='yes'; # enable stack output in each function export _DEBUG_LM; _DEBUG_LM='no'; # disable landmark messages #_DEBUG_LM='yes'; # enable landmark messages export _DEBUG_KEEP_FILES; _DEBUG_KEEP_FILES='no' # disable file keeping in temporary dir #_DEBUG_KEEP_FILES='yes' # enable file keeping in temporary dir export _DEBUG_PRINT_PARAMS; _DEBUG_PRINT_PARAMS='no'; # disable printing of all parameters #_DEBUG_PRINT_PARAMS='yes'; # enable printing of all parameters export _DEBUG_PRINT_SHELL; _DEBUG_PRINT_SHELL='no'; # disable printing of the shell name #_DEBUG_PRINT_SHELL='yes'; # enable printing of the shell name export _DEBUG_PRINT_TMPDIR; _DEBUG_PRINT_TMPDIR='no'; # disable printing of the temporary dir #_DEBUG_PRINT_TMPDIR='yes'; # enable printing of the temporary dir export _DEBUG_USER_WITH_STACK; _DEBUG_USER_WITH_STACK='no'; # disable stack dump in error_user() #_DEBUG_USER_WITH_STACK='yes'; # enable stack dump in error_user() # determine all --debug* options case " $*" in *\ --debug*) case " $* " in *' --debug '*) # _DEBUG_STACKS='yes'; # _DEBUG_LM='yes'; _DEBUG_KEEP_FILES='yes'; _DEBUG_PRINT_PARAMS='yes'; _DEBUG_PRINT_SHELL='yes'; _DEBUG_PRINT_TMPDIR='yes'; _DEBUG_USER_WITH_STACK='yes'; ;; esac; d=' --debug-all --debug-keep --debug-lm --debug-params --debug-shell '\ '--debug-stacks --debug-tmpdir --debug-user '; for i do case "$i" in --debug-s) echo 'The abbreviation --debug-s has multiple options: '\ '--debug-shell and --debug-stacks.' >&2 exit "${_ERROR}"; ;; esac; case "$d" in *\ ${i}*) # extract whole word of abbreviation $i s="$(cat <<EOF | sed -n -e 's/^.* \('"$i"'[^ ]*\) .*/\1/p' $d EOF )" case "$s" in '') continue; ;; --debug-all) _DEBUG_STACKS='yes'; _DEBUG_LM='yes'; _DEBUG_KEEP_FILES='yes'; _DEBUG_PRINT_PARAMS='yes'; _DEBUG_PRINT_SHELL='yes'; _DEBUG_PRINT_TMPDIR='yes'; _DEBUG_USER_WITH_STACK='yes'; ;; --debug-keep) _DEBUG_PRINT_TMPDIR='yes'; _DEBUG_KEEP_FILES='yes'; ;; --debug-lm) _DEBUG_LM='yes'; ;; --debug-params) _DEBUG_PRINT_PARAMS='yes'; ;; --debug-shell) _DEBUG_PRINT_SHELL='yes'; ;; --debug-stacks) _DEBUG_STACKS='yes'; ;; --debug-tmpdir) _DEBUG_PRINT_TMPDIR='yes'; ;; --debug-user) _DEBUG_USER_WITH_STACK='yes'; ;; esac; ;; esac; done ;; esac; if test _"${_DEBUG_PRINT_PARAMS}"_ = _yes_ then echo "parameters: $@" >&2; fi; if test _"${_DEBUG_PRINT_SHELL}"_ = _yes_ then if test _"${_SHELL}"_ = __ then if test _"${POSIXLY_CORRECT}"_ = _y_ then echo 'shell: bash as /bin/sh (none specified)' >&2; else echo 'shell: /bin/sh (none specified)' >&2; fi; else echo "shell: ${_SHELL}" >&2; fi; fi; ######################################################################## # 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) ######################################################################## # function return values; `0' means ok; other values are error codes export _ALL_EXIT; export _BAD; export _GOOD; export _NO; export _OK; export _YES; _GOOD='0'; # return ok _BAD='1'; # return negatively, error code `1' # $_ERROR was already defined as `7' in groffer.sh. _NO="${_BAD}"; _YES="${_GOOD}"; _OK="${_GOOD}"; # quasi-functions, call with `eval', e.g `eval "${return_ok}"' export return_ok; export return_good; export return_bad; export return_yes; export return_no; export return_error; export return_var; 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}"; return_var="func_pop; return"; # add number, e.g. `eval "${return_var} $n' 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_HTML_TTY; # viewer program for html mode in tty export _VIEWER_HTML_X; # viewer program for html mode in X export _VIEWER_PDF; # viewer program for pdf mode export _VIEWER_PS; # viewer program for ps mode export _VIEWER_X; # viewer program for X mode _VIEWER_DVI='kdvi,xdvi,dvilx'; _VIEWER_HTML_TTY='lynx'; _VIEWER_HTML_X='konqueror,mozilla,netscape,galeon,opera,amaya,arena'; _VIEWER_PDF='kghostview --scale 1.45,ggv,xpdf,acroread,kpdf'; _VIEWER_PS='kghostview --scale 1.45,ggv,gv,ghostview,gs_x11,gs'; _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_LIST; _MAN_AUTO_SEC_LIST="'1' '2' '3' '4' '5' '6' '7' '8' '9' 'n' 'o'"; export _MAN_AUTO_SEC_CHARS; _MAN_AUTO_SEC_CHARS='[123456789no]'; export _SPACE_SED; _SPACE_SED='['"${_SP}${_TAB}"']'; export _SPACE_CASE; _SPACE_CASE='[\'"${_SP}"'\'"${_TAB}"']'; 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' \ 'apropos' 'apropos-data' 'apropos-devel' 'apropos-progs' \ 'debug' 'debug-all' 'debug-keep' 'debug-lm' 'debug-params' 'debug-shell' \ 'debug-stacks' 'debug-tmpdir' 'debug-user' 'default' 'do-nothing' 'dvi' \ 'groff' 'help' 'intermediate-output' 'html' 'man' \ 'no-location' 'no-man' 'no-special' 'pdf' 'ps' 'rv' 'source' \ 'text' 'text-device' \ 'tty' 'tty-device' 'version' 'whatis' 'where' 'www' 'x' 'X'"; _OPTS_GROFFER_LONG_ARG="\ 'default-modes' 'device' 'dvi-viewer' 'dvi-viewer-tty' 'extension' 'fg' \ 'fn' 'font' 'foreground' 'html-viewer' 'html-viewer-tty' 'mode' \ 'pdf-viewer' 'pdf-viewer-tty' 'print' 'ps-viewer' 'ps-viewer-tty' 'shell' \ 'title' 'tty-viewer' 'tty-viewer-tty' 'www-viewer' 'www-viewer-tty' \ 'x-viewer' 'x-viewer-tty' 'X-viewer' 'X-viewer-tty'"; ##### 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' 'z'"; _OPTS_GROFF_SHORT_ARG="'d' 'f' 'F' 'I' 'L' 'm' 'M' 'n' 'o' 'P' 'r' \ 'w' 'W'"; _OPTS_GROFF_LONG_NA=""; _OPTS_GROFF_LONG_ARG=""; ##### 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' 'ditroff' \ 'local-file' 'location' 'troff' 'update'"; _OPTS_MAN_LONG_ARG="'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' 'help' 'html' 'ignore-case' 'location-cat' \ 'match-case' 'troff' 'update' 'version' 'whatis' 'where' 'where-cat'"; _OPTS_MANOPT_LONG_ARG="${_OPTS_MAN_LONG_NA} \ 'config_file' 'encoding' 'extension' '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 _ALL_PARAMS; # All options and file name parameters export _ADDOPTS_GROFF; # Transp. options for groff (`eval'). export _ADDOPTS_POST; # Transp. options postproc (`eval'). export _ADDOPTS_X; # Transp. options X postproc (`eval'). export _APROPOS_PROG; # Program to run apropos. export _APROPOS_SECTIONS; # Sections for different --apropos-*. 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 _FILESPEC_ARG; # Stores the actual filespec parameter. export _FUNC_STACK; # Store debugging information. export _REGISTERED_TITLE; # Processed file names. # _HAS_* from availability tests export _HAS_COMPRESSION; # `yes' if gzip compression is available export _HAS_BZIP; # `yes' if bzip2 compression 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_LANG2; # 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_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_DEFAULT_MODES; # `,'-list of modes when no mode given. export _OPT_DEVICE; # device option. export _OPT_DO_NOTHING; # do nothing in main_display(). 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 man description export _OPT_XRM; # specify X resource. export _OPT_Z; # groff option -Z. export _OUTPUT_FILE_NAME; # output generated, see main_set_res..() export _VIEWER_TERMINAL; # viewer options for terminal (--*-viewer-tty) # _TMP_* temporary directory and files export _TMP_DIR; # 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 ######################################################################## # Preset and reset of read-write global variables ######################################################################## export _START_DIR; # directory at start time of the script _START_DIR="$(pwd)"; # For variables that can be reset by option `--default', see reset(). _FILEARGS=''; # _HAS_* from availability tests _HAS_COMPRESSION=''; _HAS_BZIP=''; # _TMP_* temporary files _TMP_DIR=''; _TMP_CAT=''; _TMP_CONF=''; _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=''; _APROPOS_PROG=''; _APROPOS_SECTIONS=''; _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_LANG2=''; _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='no'; _OPT_BD=''; _OPT_BG=''; _OPT_BW=''; _OPT_DEFAULT_MODES=''; _OPT_DEVICE=''; _OPT_DISPLAY=''; _OPT_DO_NOTHING='no'; _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'; _VIEWER_TERMINAL='no'; } reset; ######################################################################## # Functions for error handling and debugging ######################################################################## ############## # echo1 (<text>*) # # Output to stdout. # # Arguments : arbitrary text including `-'. # echo1() { cat <<EOF $@ EOF } ############## # echo2 (<text>*) # # Output to stderr. # # Arguments : arbitrary text. # echo2() { cat >&2 <<EOF $@ EOF } ############## # landmark (<text>) # # Print <text> to standard error as a debugging aid. # # Globals: $_DEBUG_LM # landmark() { if test _"${_DEBUG_LM}"_ = _yes_ then echo2 "LM: $*"; fi; } landmark "1: debugging functions"; ############## # clean_up () # # Clean up at exit. # clean_up() { cd "${_START_DIR}" >"${_NULL_DEV}" 2>&1; if test _${_DEBUG_KEEP_FILES}_ = _yes_ then echo2 "Kept temporary directory ${_TMP_DIR}." else if test _"${_TMP_DIR}"_ != __ then if test -d "${_TMP_DIR}" || test -f "${_TMP_DIR}" then rm -f -r "${_TMP_DIR}" >${_NULL_DEV} 2>&1; fi; fi; fi; } ############# # diag (text>*) # # Output a diagnostic message to stderr # diag() { echo2 '>>>>>'"$*"; } ############# # error (<text>*) # # Print an error message to standard error, print the function stack, # exit with an error condition. The argument should contain the name # of the function from which it was called. This is for system errors. # error() { case "$#" in 1) echo2 'groffer error: '"$1"; ;; *) echo2 'groffer error: wrong number of arguments in error().'; ;; esac; func_stack_dump; if test _"${_TMP_DIR}"_ != __ && test -d "${_TMP_DIR}" then : >"${_TMP_DIR}"/,error; fi; exit "${_ERROR}"; } ############# # error_user (<text>*) # # Print an error message to standard error; exit with an error condition. # The error is supposed to be produce by the user. So the funtion stack # is omitted. # error_user() { case "$#" in 1) echo2 'groffer error: '"$1"; ;; *) echo2 'groffer error: wrong number of arguments in error_user().'; ;; esac; if test _"${_DEBUG_USER_WITH_STACK}"_ = _yes_ then func_stack_dump; fi; if test _"${_TMP_DIR}"_ != __ && test -d "${_TMP_DIR}" then : >"${_TMP_DIR}"/,error; fi; exit "${_ERROR}"; } ############# # exit_test () # # Test whether the former command ended with error(). Exit again. # # Globals: $_ERROR # exit_test() { if test "$?" = "${_ERROR}" then exit ${_ERROR}; fi; if test _"${_TMP_DIR}"_ != __ && test -f "${_TMP_DIR}"/,error then exit ${_ERROR}; fi; } ############# # 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. # # Variable prefix: fc # func_check() { if test "$#" -lt 3 then error 'func_check() needs at least 3 arguments.'; fi; fc_fname="$1"; case "$3" in 1) fc_nargs="$3"; fc_s=''; ;; 0|[2-9]) fc_nargs="$3"; fc_s='s'; ;; *) error "func_check(): third argument must be a digit."; ;; esac; case "$2" in '='|'-eq') fc_op='-eq'; fc_comp='exactly'; ;; '>='|'-ge') fc_op='-ge'; fc_comp='at least'; ;; '<='|'-le') fc_op='-le'; fc_comp='at most'; ;; '<'|'-lt') fc_op='-lt'; fc_comp='less than'; ;; '>'|'-gt') fc_op='-gt'; fc_comp='more than'; ;; '!='|'-ne') fc_op='-ne'; fc_comp='not'; ;; *) error \ 'func_check(): second argument is not a relational operator.'; ;; esac; shift; shift; shift; if test "$#" "${fc_op}" "${fc_nargs}" then do_nothing; else error "func_check(): \ ${fc_fname}"'() needs '"${fc_comp} ${fc_nargs}"' argument'"${fc_s}"'.'; fi; func_push "${fc_fname}"; if test _"${_DEBUG_STACKS}"_ = _yes_ then echo2 '+++ '"${fc_fname} $@"; echo2 '>>> '"${_FUNC_STACK}"; fi; eval ${_UNSET} fc_comp; eval ${_UNSET} fc_fname; eval ${_UNSET} fc_nargs; eval ${_UNSET} fc_op; eval ${_UNSET} fc_s; } ############# # 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 "$#" -ne 0 then error 'func_pop() does not have arguments.'; fi; case "${_FUNC_STACK}" in '') if test _"${_DEBUG_STACKS}"_ = _yes_ then error 'func_pop(): stack is empty.'; fi; ;; *!*) # split at first bang `!'. _FUNC_STACK="$(echo1 "${_FUNC_STACK}" | sed -e 's/^[^!]*!//')"; exit_test; ;; *) _FUNC_STACK=''; ;; esac; if test _"${_DEBUG_STACKS}"_ = _yes_ then echo2 '<<< '"${_FUNC_STACK}"; 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 # # Variable prefix: fp # func_push() { if test "$#" -ne 1 then error 'func_push() needs 1 argument.'; fi; case "$1" in *'!'*) # remove all bangs `!'. fp_element="$(echo1 "$1" | sed -e 's/!//g')"; exit_test; ;; *) fp_element="$1"; ;; esac; if test _"${_FUNC_STACK}"_ = __ then _FUNC_STACK="${fp_element}"; else _FUNC_STACK="${fp_element}!${_FUNC_STACK}"; fi; eval ${_UNSET} fp_element; } ############# # func_stack_dump () # # Print the content of the stack. Ignore the arguments. # func_stack_dump() { diag 'call stack: '"${_FUNC_STACK}"; } ######################################################################## # System Test ######################################################################## landmark "2: system test"; # Test the availability of the system utilities used in this script. ######################################################################## # Test of function `sed'. # if test _"$(echo xTesTx \ | sed -e 's/^.\([Tt]e*x*sTT*\).*$/\1/' \ | sed -e '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>${_NULL_DEV})"_ = _test_ then _HAS_COMPRESSION='yes'; if echo1 'test' | bzip2 -c 2>${_NULL_DEV} | bzip2 -t 2>${_NULL_DEV} \ && test _"$(echo 'test' | bzip2 -c 2>${_NULL_DEV} \ | bzip2 -d -c 2>${_NULL_DEV})"_ \ = _test_ then _HAS_BZIP='yes'; else _HAS_BZIP='no'; fi; else _HAS_COMPRESSION='no'; _HAS_BZIP='no'; fi; ######################################################################## # Definition of normal Functions in alphabetical order ######################################################################## landmark "3: functions"; ######################################################################## # apropos_filespec () # # Setup for the --apropos* options # apropos_filespec() { func_check apropos_filespec '=' 0 "$@"; if obj _OPT_APROPOS is_yes then eval to_tmp_line \ "'.SH $(echo1 "${_FILESPEC_ARG}" | sed 's/[^\\]-/\\-/g')'"; exit_test; if obj _APROPOS_PROG is_empty then error 'apropos_filespec: apropos_setup() must be run first.'; fi; if obj _APROPOS_SECTIONS is_empty then if obj _OPT_SECTIONS is_empty then s='^.*(.*).*$'; else s='^.*(['"$(echo1 "${_OPT_SECTIONS}" | sed -e 's/://g')"']'; fi; else s='^.*(['"${_APROPOS_SECTIONS}"']'; fi; eval "${_APROPOS_PROG}" "'${_FILESPEC_ARG}'" | \ sed -n -e ' /^'"${_FILESPEC_ARG}"': /p /'"$s"'/p ' | \ sort |\ sed -e ' s/^\(.* (..*)\) *- *\(.*\)$/\.br\n\.TP 15\n\.BR \1\n\2/ ' >>"${_TMP_CAT}"; fi; eval "${return_ok}"; } ######################################################################## # apropos_setup () # # Setup for the --apropos* options # apropos_setup() { func_check apropos_setup '=' 0 "$@"; if obj _OPT_APROPOS is_yes then if is_prog apropos then _APROPOS_PROG='apropos'; elif is_prog man then if man --apropos man >${_NULL_DEV} 2>${_NULL_DEV} then _APROPOS_PROG='man --apropos'; elif man -k man >${_NULL_DEV} 2>${_NULL_DEV} then _APROPOS_PROG='man -k'; fi; fi; if obj _APROPOS_PROG is_empty then error 'apropos_setup: no apropos program available.'; fi; to_tmp_line '.TH GROFFER APROPOS'; fi; eval "${return_ok}"; } ######################################################################## # 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) # # Variable prefix: bn # base_name() { func_check base_name = 1 "$@"; bn_name="$1"; case "${bn_name}" in */) # delete all final slashes bn_name="$(echo1 "${bn_name}" | sed -e 's|//*$||')"; exit_test; ;; esac; case "${bn_name}" in /|'') eval ${_UNSET} bn_name; eval "${return_bad}"; ;; */*) # delete everything before and including the last slash `/'. echo1 "${bn_name}" | sed -e 's|^.*//*\([^/]*\)$|\1|'; ;; *) obj bn_name echo1; ;; esac; eval ${_UNSET} bn_name; eval "${return_ok}"; } ######################################################################## # cat_z (<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 cat_z() { func_check cat_z = 1 "$@"; case "$1" in '') error 'cat_z(): empty file name'; ;; '-') error 'cat_z(): for standard input use save_stdin()'; ;; esac; if obj _HAS_BZIP is_yes then if bzip2 -t "$1" 2>${_NULL_DEV} then bzip2 -c -d "$1" 2>${_NULL_DEV}; eval "${return_ok}"; fi; fi; gzip -c -d -f "$1" 2>${_NULL_DEV}; eval "${return_ok}"; } else cat_z() { func_check cat_z = 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 "$@"; if is_empty "$1" then error "dir_append(): first argument is empty."; fi; if is_empty "$2" then echo1 "$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. # # Variable prefix: dc # dirname_chop() { func_check dirname_chop = 1 "$@"; # replace all multiple slashes by a single slash `/'. dc_res="$(echo1 "$1" | sed -e 's|///*|/|g')"; exit_test; case "${dc_res}" in ?*/) # remove trailing slash '/'; echo1 "${dc_res}" | sed -e 's|/$||'; ;; *) obj dc_res echo1 ;; esac; eval ${_UNSET} dc_res; 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 file. # - `-' 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. # # Variable prefix: df # do_filearg() { func_check do_filearg = 1 "$@"; df_filespec="$1"; # store sequence into positional parameters case "${df_filespec}" in '') eval ${_UNSET} df_filespec; eval "${return_good}"; ;; '-') register_file '-'; eval ${_UNSET} df_filespec; 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 do case "$i" in File) if test -f "${df_filespec}" then if test -r "${df_filespec}" then register_file "${df_filespec}"; eval ${_UNSET} df_filespec; eval ${_UNSET} df_no_man; eval "${return_good}"; else echo2 "could not read \`${df_filespec}'"; eval ${_UNSET} df_filespec; eval ${_UNSET} df_no_man; eval "${return_bad}"; fi; else if obj df_no_man is_not_empty then if obj _OPT_WHATIS is_yes then to_tmp_line "This is neither a file nor a man page." else echo2 "\`${df_filespec}' is neither a file nor a man page." fi; fi; df_no_file=yes; continue; fi; ;; Manpage) # parse filespec as man page if obj _MAN_IS_SETUP is_not_yes then man_setup; fi; if man_do_filespec "${df_filespec}" then eval ${_UNSET} df_filespec; eval ${_UNSET} df_no_file; eval "${return_good}"; else if obj df_no_file is_not_empty then if obj _OPT_WHATIS is_yes then to_tmp_line "This is neither a file nor a man page." else echo2 "\`${df_filespec}' is neither a file nor a man page." fi; fi; df_no_man=yes; continue; fi; ;; esac; done; eval ${_UNSET} df_filespec; eval ${_UNSET} df_no_file; eval ${_UNSET} df_no_man; eval "${return_bad}"; } # do_filearg() ######################################################################## # do_nothing () # # Dummy function. # do_nothing() { eval return "${_OK}"; } ######################################################################## # echo2 (<text>*) # # Print to standard error with final line break. # # defined above ######################################################################## # error (<text>*) # # Print error message and exit with error code. # # defined above ######################################################################## # exit_test () # # Test whether the former command ended with error(). Exit again. # # 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. # # Variable prefix: gfe # get_first_essential() { func_check get_first_essential '>=' 0 "$@"; if is_equal "$#" 0 then eval "${return_ok}"; fi; for i do gfe_var="$i"; if obj gfe_var is_not_empty then obj gfe_var echo1; eval ${_UNSET} gfe_var; eval "${return_ok}"; fi; done; eval ${_UNSET} gfe_var; 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 _"$1"_ != __ && 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_existing (<name>) # # Test whether `name' is an existing file or directory. Solaris 2.5 does # not have `test -e'. # # Arguments : 1 # Return : `0' if arg1 exists, `1' otherwise. # is_existing() { func_check is_existing '=' 1 "$@"; if test _"$1"_ = __ then eval "${return_no}"; fi; if test -f "$1" || test -d "$1" || test -c "$1" 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 is_not_empty "$1" && 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_non_empty_file '=' 1 "$@"; if is_file "$1" && test -s "$1" then eval "${return_yes}"; 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) # 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> [<arg>*]]) # # Verify that arg is a not program in $PATH. # # Arguments : >=0 (empty allowed) # more args are ignored, this allows to specify progs with arguments # is_not_prog() { func_check is_not_prog '>=' 0 "$@"; case "$#" in 0) eval "${return_yes}"; ;; *) if where_is "$1" >${_NULL_DEV} then eval "${return_no}"; fi; ;; esac 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_X () # # Test whether not running in X Window by checking $DISPLAY # is_not_X() { func_check is_X '=' 0 "$@"; if obj DISPLAY is_empty then eval "${return_yes}"; fi; eval "${return_no}"; } ######################################################################## # 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> [<arg>*]]) # # Determine whether <name> is a program in $PATH # # Arguments : >=0 (empty allowed) # <arg>* are ignored, this allows to specify progs with arguments. # is_prog() { func_check is_prog '>=' 0 "$@"; case "$#" in 0) eval "${return_no}"; ;; *) if where_is "$1" >${_NULL_DEV} 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 _"$1"_ = __ then eval "${return_no}"; fi; if test -r "$1" then if test -w "$1" then eval "${return_yes}"; fi; fi; eval "${return_no}"; } ######################################################################## # is_X () # # Test whether running in X Window by checking $DISPLAY # is_X() { func_check is_X '=' 0 "$@"; if obj DISPLAY is_not_empty then eval "${return_yes}"; fi; eval "${return_no}"; } ######################################################################## # is_yes (<string>) # # Test whether `string' has value "yes". # # 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 ([<code>]) # # Clean exit without an error or with <code>. # leave() { clean_up; if test $# = 0 then exit "${_OK}"; else exit "$1"; fi; } ######################################################################## 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 `eval set x "$list"; shift`. ######################################################################## # 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>' ..." # # Variable prefix: la # list_append() { func_check list_append '>=' 2 "$@"; la_name="$1"; eval la_list='"${'$1'}"'; shift; for s do la_s="$s"; case "${la_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' la_element="$(echo1 "${la_s}" | sed -e 's/'"${_SQ}"'/&\\&&/g')"; exit_test; ;; '') la_element=""; ;; *) la_element="${la_s}"; ;; esac; if obj la_list is_empty then la_list="'${la_element}'"; else la_list="${la_list} '${la_element}'"; fi; done; eval "${la_name}"='"${la_list}"'; eval ${_UNSET} la_element; eval ${_UNSET} la_list; eval ${_UNSET} la_name; eval ${_UNSET} la_s; 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 x "$(args_norm PRE_NAME "$@")"; # shift; # while test "$1" != '--'; do # case "$1" in # ... # esac; # shift; # done; # shift; #skip '--' # # all positional parameters ("$@") left are file name parameters. # # Variable prefix: lfc # list_from_cmdline() { func_check list_from_cmdline '>=' 1 "$@"; lfc_short_n="$(obj_data "$1"_SHORT_NA)"; # short options, no argument lfc_short_a="$(obj_data "$1"_SHORT_ARG)"; # short options, with argument lfc_long_n="$(obj_data "$1"_LONG_NA)"; # long options, no argument lfc_long_a="$(obj_data "$1"_LONG_ARG)"; # long options, with argument exit_test; if obj lfc_short_n is_empty then error 'list_from_cmdline(): no $'"$1"'_SHORT_NA options.'; fi; if obj lfc_short_a is_empty then error 'list_from_cmdline(): no $'"$1"'_SHORT_ARG options.'; fi; if obj lfc_long_n is_empty then error 'list_from_cmdline(): no $'"$1"'_LONG_NA options.'; fi; if obj lfc_long_a is_empty then error 'list_from_cmdline(): no $'"$1"'_LONG_ARG options.'; fi; shift; if is_equal "$#" 0 then echo1 -- eval ${_UNSET} lfc_fparams; eval ${_UNSET} lfc_short_a; eval ${_UNSET} lfc_short_n; eval ${_UNSET} lfc_long_a; eval ${_UNSET} lfc_long_n; eval ${_UNSET} lfc_result; eval "${return_ok}"; fi; lfc_fparams=''; lfc_result=''; while test "$#" -ge 1 do lfc_arg="$1"; shift; case "${lfc_arg}" in --) break; ;; --*=*) # delete leading '--'; lfc_abbrev="$(echo1 "${lfc_arg}" | sed -e 's/^--//')"; lfc_with_equal="${lfc_abbrev}"; # extract option by deleting from the first '=' to the end lfc_abbrev="$(echo1 "${lfc_with_equal}" | \ sed -e 's/^\([^=]*\)=.*$/\1/')"; lfc_opt="$(list_single_from_abbrev lfc_long_a "${lfc_abbrev}")"; exit_test; if obj lfc_opt is_empty then error_user "--${lfc_abbrev} is not an option."; else # get the option argument by deleting up to first `=' lfc_optarg="$(echo1 "${lfc_with_equal}" | sed -e 's/^[^=]*=//')"; exit_test; list_append lfc_result "--${lfc_opt}" "${lfc_optarg}"; continue; fi; ;; --*) # delete leading '--'; lfc_abbrev="$(echo1 "${lfc_arg}" | sed -e 's/^--//')"; if list_has lfc_long_n "${lfc_abbrev}" then lfc_opt="${lfc_abbrev}"; else exit_test; lfc_opt="$(list_single_from_abbrev lfc_long_n "${lfc_abbrev}")"; exit_test; if obj lfc_opt is_not_empty && is_not_equal "$#" 0 then a="$(list_single_from_abbrev lfc_long_a "${lfc_abbrev}")"; exit_test; if obj a is_not_empty then error_user "The abbreviation ${lfc_arg} \ has multiple options: --${lfc_opt} and --${a}."; fi; fi; fi; if obj lfc_opt is_not_empty then # long option, no argument list_append lfc_result "--${lfc_opt}"; continue; fi; lfc_opt="$(list_single_from_abbrev lfc_long_a "${lfc_abbrev}")"; exit_test; if obj lfc_opt is_not_empty then # long option with argument if test "$#" -le 0 then error_user "no argument for option --${lfc_opt}." fi; list_append lfc_result "--${lfc_opt}" "$1"; shift; continue; fi; error_user "${lfc_arg} is not an option."; ;; -?*) # short option (cluster) # delete leading `-'; lfc_rest="$(echo1 "${lfc_arg}" | sed -e 's/^-//')"; exit_test; while obj lfc_rest is_not_empty do # get next short option from cluster (first char of $lfc_rest) lfc_optchar="$(echo1 "${lfc_rest}" | sed -e 's/^\(.\).*$/\1/')"; # remove first character from ${lfc_rest}; lfc_rest="$(echo1 "${lfc_rest}" | sed -e 's/^.//')"; exit_test; if list_has lfc_short_n "${lfc_optchar}" then list_append lfc_result "-${lfc_optchar}"; continue; elif list_has lfc_short_a "${lfc_optchar}" then if obj lfc_rest is_empty then if test "$#" -ge 1 then list_append lfc_result "-${lfc_optchar}" "$1"; shift; continue; else error_user "no argument for option -${lfc_optchar}."; fi; else # rest is the argument list_append lfc_result "-${lfc_optchar}" "${lfc_rest}"; lfc_rest=''; continue; fi; else error_user "unknown option -${lfc_optchar}."; fi; done; ;; *) # Here, $lfc_arg is not an option, so a file parameter. list_append lfc_fparams "${lfc_arg}"; # Ignore the strange POSIX option handling to end option # parsing after the first file name argument. To reuse it, do # a `break' here if $POSIXLY_CORRECT of `bash' is not empty. # When `bash' is called as `sh' $POSIXLY_CORRECT is set # automatically to `y'. ;; esac; done; list_append lfc_result '--'; if obj lfc_fparams is_not_empty then lfc_result="${lfc_result} ${lfc_fparams}"; fi; if test "$#" -gt 0 then list_append lfc_result "$@"; fi; obj lfc_result echo1; eval ${_UNSET} lfc_abbrev; eval ${_UNSET} lfc_fparams; eval ${_UNSET} lfc_short_a; eval ${_UNSET} lfc_short_n; eval ${_UNSET} lfc_long_a; eval ${_UNSET} lfc_long_n; eval ${_UNSET} lfc_result; eval ${_UNSET} lfc_arg; eval ${_UNSET} lfc_opt; eval ${_UNSET} lfc_opt_arg; eval ${_UNSET} lfc_opt_char; eval ${_UNSET} lfc_with_equal; eval ${_UNSET} lfc_rest; 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 # # Variable prefix: lfs # list_from_split() { func_check list_from_split = 2 "$@"; # precede each space or tab by a backslash `\' (doubled for `sed') lfs_s="$(echo1 "$1" | sed -e 's/\('"${_SPACE_SED}"'\)/\\\1/g')"; exit_test; # replace split character of string by the list separator ` ' (space). case "$2" in /) # cannot use normal `sed' separator echo1 "${lfs_s}" | sed -e 's|'"$2"'| |g'; ;; ?) # use normal `sed' separator echo1 "${lfs_s}" | sed -e 's/'"$2"'/ /g'; ;; ??*) error 'list_from_split(): separator must be a single character.'; ;; esac; eval ${_UNSET} lfs_s; 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. # # Variable prefix: lg # list_get() { func_check list_get = 1 "$@"; eval lg_list='"${'$1'}"'; # remove leading and final space characters lg_list="$(echo1 "${lg_list}" | sed -e ' s/^'"${_SPACE_SED}"'*// s/'"${_SPACE_SED}"'*$// ')"; exit_test; case "${lg_list}" in '') eval ${_UNSET} lg_list; eval "${return_ok}"; ;; \'*\') obj lg_list echo1; eval ${_UNSET} lg_list; eval "${return_ok}"; ;; *) error "list_get(): bad list: $1" ;; esac; eval ${_UNSET} lg_list; eval "${return_ok}"; } ######################################################################## # list_has (<var_name> <element>) # # Test whether the list <var_name> has the element <element>. # # Arguments: 2 # <var_name>: a variable name for a list of single-quoted elements # <element>: some sequence of characters. # # Variable prefix: lh # list_has() { func_check list_has = 2 "$@"; eval lh_list='"${'$1'}"'; if obj lh_list is_empty then eval "${_UNSET}" lh_list; eval "${return_no}"; fi; case "$2" in \'*\') lh_element=" $2 "; ;; *) lh_element=" '$2' "; ;; esac; if string_contains " ${lh_list} " "${lh_element}" then eval "${_UNSET}" lh_list; eval "${_UNSET}" lh_element; eval "${return_yes}"; else eval "${_UNSET}" lh_list; eval "${_UNSET}" lh_element; eval "${return_no}"; fi; } ######################################################################## # list_has_abbrev (<var_name> <abbrev>) # # Test whether the list <var_name> has an element starting with <abbrev>. # # Arguments: 2 # <var_name>: a variable name for a list of single-quoted elements # <abbrev>: some sequence of characters. # # Variable prefix: lha # list_has_abbrev() { func_check list_has_abbrev = 2 "$@"; eval lha_list='"${'$1'}"'; if obj lha_list is_empty then eval "${_UNSET}" lha_list; eval "${return_no}"; fi; case "$2" in \'*) lha_element="$(echo1 "$2" | sed -e 's/'"${_SQ}"'$//')"; exit_test; ;; *) lha_element="'$2"; ;; esac; if string_contains " ${lha_list}" " ${lha_element}" then eval "${_UNSET}" lha_list; eval "${_UNSET}" lha_element; eval "${return_yes}"; else eval "${_UNSET}" lha_list; eval "${_UNSET}" lha_element; eval "${return_no}"; fi; eval "${return_ok}"; } ######################################################################## # list_has_not (<list> <element>) # # Test whether <list> has no <element>. # # Arguments: 2 # <list>: a space-separated list of single-quoted elements. # <element>: some sequence of characters. # # Variable prefix: lhn # list_has_not() { func_check list_has_not = 2 "$@"; eval lhn_list='"${'$1'}"'; if obj lhn_list is_empty then eval "${_UNSET}" lhn_list; eval "${return_yes}"; fi; case "$2" in \'*\') lhn_element=" $2 "; ;; *) lhn_element=" '$2' "; ;; esac; if string_contains " ${lhn_list} " "${lhn_element}" then eval "${_UNSET}" lhn_list; eval "${_UNSET}" lhn_element; eval "${return_no}"; else eval "${_UNSET}" lhn_list; eval "${_UNSET}" lhn_element; eval "${return_yes}"; fi; } ######################################################################## # list_single_from_abbrev (<list> <abbrev>) # # Check whether the list has an element starting with <abbrev>. If # there are more than a single element an error is created. # # Arguments: 2 # <list>: a variable name for a list of single-quoted elements # <abbrev>: some sequence of characters. # # Output: the found element. # # Variable prefix: lsfa # list_single_from_abbrev() { func_check list_single_from_abbrev = 2 "$@"; eval lsfa_list='"${'$1'}"'; if obj lsfa_list is_empty then eval "${_UNSET}" lsfa_list; eval "${return_no}"; fi; lsfa_abbrev="$2"; if list_has lsfa_list "${lsfa_abbrev}" then obj lsfa_abbrev echo1; eval "${_UNSET}" lsfa_abbrev; eval "${_UNSET}" lsfa_list; eval "${return_yes}"; fi; if list_has_abbrev lsfa_list "${lsfa_abbrev}" then lsfa_element=''; eval set x "${lsfa_list}"; shift; for i do case "$i" in ${lsfa_abbrev}*) if obj lsfa_element is_not_empty then error_user "The abbreviation --${lsfa_abbrev} \ has multiple options: --${lsfa_element} and --${i}."; fi; lsfa_element="$i"; ;; esac; done; obj lsfa_element echo1; eval "${_UNSET}" lsfa_abbrev; eval "${_UNSET}" lsfa_element; eval "${_UNSET}" lsfa_list; eval "${return_yes}"; else eval "${_UNSET}" lsfa_abbrev; eval "${_UNSET}" lsfa_element; eval "${_UNSET}" lsfa_list; eval "${return_no}"; fi; } ######################################################################## 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 (see man_setup()). # # Variable prefix: mdf # man_do_filespec() { func_check man_do_filespec = 1 "$@"; if obj _MAN_PATH is_empty then eval "${return_bad}"; fi; if is_empty "$1" then eval "${return_bad}"; fi; mdf_spec="$1"; mdf_name=''; mdf_section=''; case "${mdf_spec}" in */*) # not a man spec with containing '/' eval ${_UNSET} mdf_got_one; eval ${_UNSET} mdf_name; eval ${_UNSET} mdf_section; eval ${_UNSET} mdf_spec; eval "${return_bad}"; ;; man:?*\(?*\)) # man:name(section) mdf_name="$(echo1 "${mdf_spec}" \ | sed -e 's/^man:\(..*\)(\(..*\))$/\1/')"; mdf_section="$(echo1 "${mdf_spec}" \ | sed -e 's/^man:\(..*\)(\(..*\))$/\2/')"; exit_test; ;; man:?*.${_MAN_AUTO_SEC_CHARS}) # man:name.section mdf_name="$(echo1 "${mdf_spec}" \ | sed -e 's/^man:\(..*\)\..$/\1/')"; mdf_section="$(echo1 "${mdf_spec}" \ | sed -e 's/^.*\(.\)$/\1/')"; exit_test; ;; man:?*) # man:name mdf_name="$(echo1 "${mdf_spec}" | sed -e 's/^man://')"; exit_test; ;; ?*\(?*\)) # name(section) mdf_name="$(echo1 "${mdf_spec}" \ | sed -e 's/^\(..*\)(\(..*\))$/\1/')"; mdf_section="$(echo1 "${mdf_spec}" \ | sed -e 's/^\(..*\)(\(..*\))$/\2/')"; exit_test; ;; ?*.${_MAN_AUTO_SEC_CHARS}) # name.section mdf_name="$(echo1 "${mdf_spec}" \ | sed -e 's/^\(..*\)\..$/\1/')"; mdf_section="$(echo1 "${mdf_spec}" \ | sed -e 's/^.*\(.\)$/\1/')"; exit_test; ;; ?*) mdf_name="${mdf_spec}"; ;; esac; if obj mdf_name is_empty then eval ${_UNSET} mdf_got_one; eval ${_UNSET} mdf_name; eval ${_UNSET} mdf_section; eval ${_UNSET} mdf_spec; eval "${return_bad}"; fi; mdf_got_one='no'; if obj mdf_section is_empty then if obj _OPT_SECTIONS is_empty then eval set x "${_MAN_AUTO_SEC_LIST}"; else # use --sections when no section is given to filespec eval set x "$(echo1 "${_OPT_SECTIONS}" | sed -e 's/:/ /g')"; fi; shift; for s do mdf_s="$s"; if man_search_section "${mdf_name}" "${mdf_s}" then # found if obj _MAN_ALL is_yes then mdf_got_one='yes'; else eval ${_UNSET} mdf_got_one; eval ${_UNSET} mdf_name; eval ${_UNSET} mdf_s; eval ${_UNSET} mdf_section; eval ${_UNSET} mdf_spec; eval "${return_good}"; fi; fi; done; else if man_search_section "${mdf_name}" "${mdf_section}" then eval ${_UNSET} mdf_got_one; eval ${_UNSET} mdf_name; eval ${_UNSET} mdf_s; eval ${_UNSET} mdf_section; eval ${_UNSET} mdf_spec; eval "${return_good}"; else eval ${_UNSET} mdf_got_one; eval ${_UNSET} mdf_name; eval ${_UNSET} mdf_section; eval ${_UNSET} mdf_spec; eval "${return_bad}"; fi; fi; if obj _MAN_ALL is_yes && obj mdf_got_one is_yes then eval ${_UNSET} mdf_got_one; eval ${_UNSET} mdf_name; eval ${_UNSET} mdf_s; eval ${_UNSET} mdf_section; eval ${_UNSET} mdf_spec; eval "${return_good}"; fi; eval ${_UNSET} mdf_got_one; eval ${_UNSET} mdf_name; eval ${_UNSET} mdf_s; eval ${_UNSET} mdf_section; eval ${_UNSET} mdf_spec; 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 # # Variable prefix: mss # man_search_section() { func_check man_search_section = 2 "$@"; 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; mss_name="$1"; mss_section="$2"; eval set x "$(path_split "${_MAN_PATH}")"; exit_test; shift; mss_got_one='no'; if obj _MAN_EXT is_empty then for d do mss_dir="$(dirname_append "$d" "man${mss_section}")"; exit_test; if obj mss_dir is_dir then mss_prefix="$(\ dirname_append "${mss_dir}" "${mss_name}.${mss_section}")"; if obj _OPT_WHATIS is_yes then mss_files="$(eval ls "${mss_prefix}"'*' 2>${_NULL_DEV} | sed -e '\| found|s|.*||' )"; else mss_files="$(eval ls "'${mss_prefix}'"'*' 2>${_NULL_DEV} | sed -e '\| found|s|.*||' )"; fi; exit_test; if obj mss_files is_not_empty then # for f in $mss_files for f in $(eval set x ${mss_files}; shift; echo1 "$@") do exit_test; mss_f="$f"; if obj mss_f is_file then if is_yes "${mss_got_one}" then register_file "${mss_f}"; elif obj _MAN_ALL is_yes then man_register_file "${mss_f}" "${mss_name}"; else man_register_file "${mss_f}" "${mss_name}" "${mss_section}"; eval ${_UNSET} mss_dir; eval ${_UNSET} mss_ext; eval ${_UNSET} mss_f; eval ${_UNSET} mss_files; eval ${_UNSET} mss_got_one; eval ${_UNSET} mss_name; eval ${_UNSET} mss_prefix; eval ${_UNSET} mss_section; eval "${return_good}"; fi; mss_got_one='yes'; fi; done; fi; fi; done; else mss_ext="${_MAN_EXT}"; # check for directory name having trailing extension for d do mss_dir="$(dirname_append $d man${mss_section}${mss_ext})"; exit_test; if obj mss_dir is_dir then mss_prefix=\ "$(dirname_append "${mss_dir}" "${mss_name}.${mss_section}")"; mss_files="$( eval ls "${mss_prefix}"'*' 2>${_NULL_DEV} | sed -e '\|not found|s|.*||' )"; exit_test; if obj mss_files is_not_empty then # for f in $mss_files for f in $(eval set x ${mss_files}; shift; echo1 "$@") do mss_f="$f"; if obj mss_f is_file then if is_yes "${mss_got_one}" then register_file "${mss_f}"; elif obj _MAN_ALL is_yes then man_register_file "${mss_f}" "${mss_name}"; else man_register_file "${mss_f}" "${mss_name}" "${mss_section}"; eval ${_UNSET} mss_dir; eval ${_UNSET} mss_ext; eval ${_UNSET} mss_f; eval ${_UNSET} mss_files; eval ${_UNSET} mss_got_one; eval ${_UNSET} mss_name; eval ${_UNSET} mss_prefix; eval ${_UNSET} mss_section; eval "${return_good}"; fi; mss_got_one='yes'; fi; done; fi; fi; done; # check for files with extension in directories without extension for d do mss_dir="$(dirname_append "$d" "man${mss_section}")"; exit_test; if obj mss_dir is_dir then mss_prefix="$(dirname_append "${mss_dir}" \ "${mss_name}.${mss_section}${mss_ext}")"; mss_files="$(eval ls "${mss_prefix}"'*' 2>${_NULL_DEV} | sed -e '\|not found|s|.*||' )"; exit_test; if obj mss_files is_not_empty then # for f in $mss_files for f in $(eval set x ${mss_files}; shift; echo1 "$@") do mss_f="$f"; if obj mss_f is_file then if is_yes "${mss_got_one}" then register_file "${mss_f}"; elif obj _MAN_ALL is_yes then man_register_file "${mss_f}" "${mss_name}"; else man_register_file "${mss_f}" "${mss_name}" "${mss_section}"; eval ${_UNSET} mss_dir; eval ${_UNSET} mss_ext; eval ${_UNSET} mss_f; eval ${_UNSET} mss_files; eval ${_UNSET} mss_got_one; eval ${_UNSET} mss_name; eval ${_UNSET} mss_prefix; eval ${_UNSET} mss_section; eval "${return_good}"; fi; mss_got_one='yes'; fi; done; fi; fi; done; fi; if obj _MAN_ALL is_yes && is_yes "${mss_got_one}" then eval ${_UNSET} mss_dir; eval ${_UNSET} mss_ext; eval ${_UNSET} mss_f; eval ${_UNSET} mss_files; eval ${_UNSET} mss_got_one; eval ${_UNSET} mss_name; eval ${_UNSET} mss_prefix; eval ${_UNSET} mss_section; eval "${return_good}"; fi; eval ${_UNSET} mss_dir; eval ${_UNSET} mss_ext; eval ${_UNSET} mss_f; eval ${_UNSET} mss_files; eval ${_UNSET} mss_got_one; eval ${_UNSET} mss_name; eval ${_UNSET} mss_prefix; eval ${_UNSET} mss_section; 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. # # Variable prefix: ms # man_setup() { func_check main_man_setup = 0 "$@"; 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}")"; exit_test; if obj _MAN_PATH is_empty then manpath_set_from_path; else _MAN_PATH="$(path_clean "${_MAN_PATH}")"; exit_test; fi; if obj _MAN_PATH is_empty then if is_prog 'manpath' then _MAN_PATH="$(manpath 2>${_NULL_DEV})"; # not always available exit_test; 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}")"; exit_test; if obj _MAN_ALL is_empty then _MAN_ALL='no'; fi; _MAN_SYS="$(get_first_essential \ "${_OPT_SYSTEMS}" "${_MANOPT_SYS}" "${SYSTEM}")"; ms_lang="$(get_first_essential \ "${_OPT_LANG}" "${LC_ALL}" "${LC_MESSAGES}" "${LANG}")"; exit_test; case "${ms_lang}" in C|POSIX) _MAN_LANG=""; _MAN_LANG2=""; ;; ?) _MAN_LANG="${ms_lang}"; _MAN_LANG2=""; ;; *) _MAN_LANG="${ms_lang}"; # get first two characters of $ms_lang _MAN_LANG2="$(echo1 "${ms_lang}" | sed -e 's/^\(..\).*$/\1/')"; exit_test; ;; 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}")"; exit_test; if obj _MAN_PATH is_empty then _MAN_ENABLE="no"; eval ${_UNSET} ms_lang; eval "${return_ok}"; fi; _MAN_EXT="$(get_first_essential \ "${_OPT_EXTENSION}" "${_MANOPT_EXTENSION}")"; exit_test; eval ${_UNSET} ms_lang; 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. # # Variable prefix: mals # manpath_add_lang_sys() { func_check manpath_add_lang_sys = 0 "$@"; if obj _MAN_PATH is_empty then eval "${return_ok}"; fi; # twice test both sys and lang eval set x "$(path_split "${_MAN_PATH}")"; shift; exit_test; mals_mp=''; for p do # loop on man path directories mals_mp="$(_manpath_add_lang_sys_single "${mals_mp}" "$p")"; exit_test; done; eval set x "$(path_split "${mals_mp}")"; shift; exit_test; for p do # loop on man path directories mals_mp="$(_manpath_add_lang_sys_single "${mals_mp}" "$p")"; exit_test; done; _MAN_PATH="$(path_chop "${mals_mp}")"; exit_test; eval ${_UNSET} mals_mp; eval "${return_ok}"; } # 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 # # Variable prefix: _mals # _manpath_add_lang_sys_single() { func_check _manpath_add_lang_sys_single = 2 "$@"; _mals_res="$1"; _mals_parent="$2"; eval set x "$(list_from_split "${_MAN_SYS}" ',')"; shift; exit_test; for d in "$@" "${_MAN_LANG}" "${_MAN_LANG2}" do _mals_dir="$(dirname_append "${_mals_parent}" "$d")"; exit_test; if obj _mals_res path_not_contains "${_mals_dir}" && \ obj _mals_dir is_dir then _mals_res="${_mals_res}:${_mals_dir}"; fi; done; if path_not_contains "${_mals_res}" "${_mals_parent}" then _mals_res="${_mals_res}:${_mals_parent}"; fi; path_chop "${_mals_res}"; eval ${_UNSET} _mals_dir; eval ${_UNSET} _mals_parent; eval ${_UNSET} _mals_res; eval "${return_ok}"; } # 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 # # Variable prefix: msfp # manpath_set_from_path() { func_check manpath_set_from_path = 0 "$@"; msfp_manpath=''; # get a basic man path from $PATH if obj PATH is_not_empty then eval set x "$(path_split "${PATH}")"; shift; exit_test; for d do # delete the final `/bin' part msfp_base="$(echo1 "$d" | sed -e 's|//*bin/*$||')"; exit_test; for e in /share/man /man do msfp_mandir="${msfp_base}$e"; if test -d "${msfp_mandir}" && test -r "${msfp_mandir}" then msfp_manpath="${msfp_manpath}:${msfp_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 msfp_d="$d"; if obj msfp_manpath path_not_contains "${msfp_d}" && obj mfsp_d is_dir then msfp_manpath="${msfp_manpath}:${mfsp_d}"; fi; done; _MAN_PATH="${msfp_manpath}"; eval ${_UNSET} msfp_base; eval ${_UNSET} msfp_d; eval ${_UNSET} msfp_mandir; eval ${_UNSET} msfp_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 # # Variable prefix: o # obj() { func_check obj '>=' 2 "$@"; eval o_arg1='"${'$1'}"'; if is_empty "$2" then error "obj(): function name is empty." else o_func="$2"; fi; shift; shift; eval "${o_func}"' "${o_arg1}" "$@"'; n="$?"; eval ${_UNSET} o_arg1; eval ${_UNSET} o_func; eval "${return_var} $n"; } # obj() ######################################################################## # 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> # # Variable prefix: od # obj_data() { func_check obj '=' 1 "$@"; if is_empty "$1" then error "obj_data(): object name is empty." fi; eval od_res='"${'$1'}"'; obj od_res echo1; eval ${_UNSET} od_res; eval "${return_ok}"; } ######################################################################## # 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 # # Variable prefix: ofo # obj_from_output() { func_check obj_from_output '>=' 2 "$@"; if is_empty "$1" then error "res(): variable name is empty."; elif is_empty "$2" then error "res(): function name is empty." else ofo_result_name="$1"; fi; shift; eval "${ofo_result_name}"'="$('"$@"')"'; exit_test; eval "${return_ok}"; } ######################################################################## # 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"'; eval "${return_ok}"; } ######################################################################## # 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 "$@"; # replace multiple colons by a single colon `:' # remove leading and trailing colons echo1 "$1" | sed -e ' s/^:*// s/:::*/:/g 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. # # Variable prefix: pc # path_clean() { func_check path_clean = 1 "$@"; if is_not_equal "$#" 1 then error 'path_clean() needs 1 argument.'; fi; pc_arg="$1"; eval set x "$(path_split "${pc_arg}")"; exit_test; shift; pc_res=""; for i do pc_i="$i"; if obj pc_i is_not_empty \ && obj pc_res path_not_contains "${pc_i}" \ && obj pc_i is_dir then case "${pc_i}" in ?*/) pc_res="${pc_res}$(dirname_chop "${pc_i}")"; exit_test; ;; *) pc_res="${pc_res}:${pc_i}"; exit_test; ;; esac; fi; done; eval ${_UNSET} pc_arg; eval ${_UNSET} pc_i; eval ${_UNSET} pc_res; if path_chop "${pc_res}" then eval "${return_ok}"; else eval "${return_bad}"; 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 'stdin'; else to_tmp "$1"; register_title "$(base_name "$1")"; exit_test; fi; eval "${return_ok}"; } # register_file() ######################################################################## # register_title (<filespec>) # # Create title element from <filespec> and append to $_REGISTERED_TITLE # # Globals: $_REGISTERED_TITLE (rw) # # Variable prefix: rt # register_title() { func_check register_title '=' 1 "$@"; if is_empty "$1" then eval "${return_ok}"; fi; case "${_REGISTERED_TITLE}" in *\ *\ *\ *) eval "${return_ok}"; ;; esac; # remove directory part rt_title="$(base_name "$1")"; # replace space characters by `_' rt_title="$(echo1 "${rt_title}" | sed -e 's/[ ]/_/g')"; # remove extension `.bz2' rt_title="$(echo1 "${rt_title}" | sed -e 's/\.bz2$//')"; # remove extension `.gz' rt_title="$(echo1 "${rt_title}" | sed -e 's/\.gz$//')"; # remove extension `.Z' rt_title="$(echo1 "${rt_title}" | sed -e 's/\.Z$//')"; exit_test; if obj rt_title is_empty then eval ${_UNSET} rt_title; eval "${return_ok}"; fi; if obj _REGISTERED_TITLE is_empty then _REGISTERED_TITLE="${rt_title}"; else _REGISTERED_TITLE="${_REGISTERED_TITLE} ${rt_title}"; fi; eval ${_UNSET} rt_title; eval "${return_ok}"; } # register_title() ######################################################################## # reset () # # Reset the variables that can be affected by options to their default. # # # Defined in section `Preset' after the rudimentary shell tests. ######################################################################## # rm_file (<file_name>) # # Remove file if $_DEBUG_KEEP_FILES allows it. # # Globals: $_DEBUG_KEEP_FILES # rm_file() { func_check rm_file '=' 1 "$@"; if is_file "$1" then rm -f "$1" >${_NULL_DEV} 2>&1; fi; if is_existing "$1" then eval "${return_bad}"; else eval "${return_good}"; fi; } ######################################################################## # rm_file_with_debug (<file_name>) # # Remove file if $_DEBUG_KEEP_FILES allows it. # # Globals: $_DEBUG_KEEP_FILES # rm_file_with_debug() { func_check rm_file_with_debug '=' 1 "$@"; if obj _DEBUG_KEEP_FILES is_not_yes then if is_file "$1" then rm -f "$1" >${_NULL_DEV} 2>&1; fi; fi; if is_existing "$1" then eval "${return_bad}"; else eval "${return_good}"; fi; } ######################################################################## # rm_tree (<dir_name>) # # Remove file if $_DEBUG_KEEP_FILES allows it. # # Globals: $_DEBUG_KEEP_FILES # rm_tree() { func_check rm_tree '=' 1 "$@"; if is_existing "$1" then rm -f -r "$1" >${_NULL_DEV} 2>&1; fi; if is_existing "$1" then eval "${return_bad}"; else eval "${return_good}"; fi; } ######################################################################## # save_stdin () # # Store standard input to temporary file (with decompression). # # Variable prefix: ss # if obj _HAS_COMPRESSION is_yes then save_stdin() { func_check save_stdin '=' 0 "$@"; ss_f="${_TMP_DIR}"/INPUT; cat >"${ss_f}"; cat_z "${ss_f}" >"${_TMP_STDIN}"; rm_file "${ss_f}"; eval ${_UNSET} ss_f; eval "${return_ok}"; } else save_stdin() { func_check save_stdin = 0 "$@"; cat >"${_TMP_STDIN}"; eval "${return_ok}"; } fi; ######################################################################## # special_filespec () # # Handle special modes like whatis and apropos. # special_filespec() { func_check special_setup '=' 0 "$@"; if obj _OPT_APROPOS is_yes then if obj _OPT_WHATIS is_yes then error \ 'special_setup: $_OPT_APROPOS and $_OPT_WHATIS are both "yes"'; fi; apropos_filespec; eval "${return_ok}"; fi; if obj _OPT_WHATIS is_yes then whatis_filespec; fi; eval "${return_ok}"; } ######################################################################## # special_setup () # # Handle special modes like whatis and apropos. # special_setup() { func_check special_setup '=' 0 "$@"; if obj _OPT_APROPOS is_yes then if obj _OPT_WHATIS is_yes then error \ 'special_setup: $_OPT_APROPOS and $_OPT_WHATIS are both "yes"'; fi; apropos_setup; eval "${return_ok}"; fi; if obj _OPT_WHATIS is_yes then whatis_header; fi; eval "${return_ok}"; } ######################################################################## 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() { func_check tmp_cat '=' 0 "$@"; cat "${_TMP_CAT}"; eval "${return_var}" "$?"; } ######################################################################## # tmp_create (<suffix>?) # # Create temporary file. # # It's safe to use the shell process ID together with a suffix to # have multiple temporary files. # # Globals: $_TMP_DIR # # Output : name of created file # # Variable prefix: tc # tmp_create() { func_check tmp_create '<=' 1 "$@"; # the output file does not have `,' as first character, so these are # different names from the output file. tc_tmp="${_TMP_DIR}/,$1"; : >"${tc_tmp}" obj tc_tmp echo1; eval ${_UNSET} tc_tmp; eval "${return_ok}"; } ######################################################################## # to_tmp (<filename>) # # print file (decompressed) to the temporary cat file # to_tmp() { func_check to_tmp '=' 1 "$@"; if obj _TMP_CAT is_empty then error 'to_tmp_line: $_TMP_CAT is not yet set'; fi; if is_file "$1" then if obj _OPT_LOCATION is_yes then echo2 "$1"; fi; if obj _OPT_WHATIS is_yes then whatis_filename "$1" >>"${_TMP_CAT}"; else cat_z "$1" >>"${_TMP_CAT}"; fi; else error "to_tmp(): could not read file \`$1'."; fi; eval "${return_ok}"; } ######################################################################## # to_tmp_line ([<text>]) # # print line to the temporary cat file # to_tmp_line() { func_check to_tmp '>=' 0 "$@"; if obj _TMP_CAT is_empty then error 'to_tmp_line: $_TMP_CAT is not yet set'; fi; echo1 "$*" >>"${_TMP_CAT}"; eval "${return_ok}"; } ######################################################################## # trap_set # # call function on signal 0 # trap_set() { func_check trap_set '=' 0 "$@"; trap 'clean_up' 0 2>${_NULL_DEV} || :; eval "${return_ok}"; } ######################################################################## # trap_unset () # # disable trap on signal 0. # trap_unset() { func_check trap_unset '=' 0 "$@"; trap '' 0 2>${_NULL_DEV} || :; eval "${return_ok}"; } ######################################################################## # usage () # # print usage information to stderr; for groffer option --help. # usage() { func_check usage = 0 "$@"; echo; version; echo1 'Usage: groffer [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 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=prog choose the viewer program for dvi mode. --groff process like groff, disable viewing features. --help display this helping output. --html display in a web browser. --html-viewer=program choose the web browser for html 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. --no-special disable --all, --apropos*, and --whatis --pager=program preset the paging program for tty mode. --pdf display in a PDF viewer. --pdf-viewer=prog choose the viewer program for pdf mode. --ps display in a Postscript viewer. --ps-viewer=prog choose the viewer program for ps mode. --shell=program specify a shell under which to run groffer2.sh. --text output in a text device without a pager. --tty display with a pager on text terminal even when in X. --tty-viewer=prog select a pager for tty mode; same as --pager. --whatis display the file name and description of man pages --www same as --html. --www-viewer=prog same as --html-viewer --x --X display with "gxditview" using an X* device. --x-viewer=prog choose viewer program for x mode (X mode). --X-viewer=prog same as "--xviewer". Development options that are not useful for normal usage: --debug, --debug-all, --debug-keep, --debug-lm, --debug-params, --debug-shell, --debug-stacks, --debug-tmpdir, --debug-user, --do-nothing, --print=text Viewer programs for the different modes that run on the terminal: --dvi-viewer-tty=prog, --html-viewer-tty=prog, --pdf-viewer-tty=prog, --ps-viewer-tty=prog, --tty-viewer-tty, --X-viewer-tty=prog, --x-viewer-tty=prog, --www-viewer-tty=prog 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,..., --where, ... EOF eval "${return_ok}"; } ######################################################################## # version () # # print version information to stderr # version() { func_check version = 0 "$@"; echo1 "groffer ${_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 /'; eval "${return_ok}"; } ######################################################################## # warning (<string>) # # Print warning to stderr # warning() { echo2 "warning: $*"; } ######################################################################## # whatis_filename (<filename>) # # Interpret <filename> as a man page and display its `whatis' # information as a fragment written in the groff language. # # Variable prefix: wf # whatis_filename() { func_check whatis_filename = 1 "$@"; wf_arg="$1"; if obj wf_arg is_not_file then error "whatis_filename(): argument is not a readable file." fi; wf_dot='^\.'"${_SPACE_SED}"'*'; if obj _FILESPEC_ARG is_equal '-' then wf_arg='stdin'; fi; cat <<EOF \f[CR]${wf_arg}\f[]: .br EOF # get the parts of the file name wf_name="$(base_name $1)"; wf_section="$(echo1 $1 | sed -n -e ' s|^.*/man\('"${_MAN_AUTO_SEC_CHARS}"'\).*$|\1|p ')"; if obj wf_section is_not_empty then case "${wf_name}" in *.${wf_section}*) s='yes'; ;; *) s=''; wf_section=''; ;; esac if obj s is_yes then wf_name="$(echo1 ${wf_name} | sed -e ' s/^\(.*\)\.'${wf_section}'.*$/\1/ ')"; fi; fi; # traditional man style; grep the line containing `.TH' macro, if any wf_res="$(cat_z "$1" | sed -e ' /'"${wf_dot}"'TH /p d ')"; exit_test; if obj wf_res is_not_empty then # traditional man style # get the first line after the first `.SH' macro, by # - delete up to first .SH; # - print all lines before the next .SH; # - quit. wf_res="$(cat_z "$1" | sed -n -e ' 1,/'"${wf_dot}"'SH/d /'"${wf_dot}"'SH/q p ')"; if obj wf_section is_not_empty then case "${wf_res}" in ${wf_name}${_SPACE_CASE}*-${_SPACE_CASE}*) s='yes'; ;; *) s=''; ;; esac; if obj s is_yes then wf_res="$(obj wf_res echo1 | sed -e ' s/^'"${wf_name}${_SPACE_SED}"'[^-]*-'"${_SPACE_SED}"'*\(.*\)$/'"${wf_name}"' ('"${wf_section}"') \\[em] \1/ ')"; fi; fi; obj wf_res echo1; echo; eval ${_UNSET} wf_arg; eval ${_UNSET} wf_dot; eval ${_UNSET} wf_name; eval ${_UNSET} wf_res; eval ${_UNSET} wf_section; eval "${return_ok}"; fi; # mdoc style (BSD doc); grep the line containing `.Nd' macro, if any wf_res="$(cat_z "$1" | sed -n -e '/'"${wf_dot}"'Nd /s///p')"; exit_test; if obj wf_res is_not_empty then # BSD doc style if obj wf_section is_not_empty then wf_res="$(obj wf_res echo1 | sed -n -e ' s/^\(.*\)$/'"${wf_name}"' ('"${wf_section}"') \\[em] \1/p ')"; fi; obj wf_res echo1; echo; eval ${_UNSET} wf_arg; eval ${_UNSET} wf_dot; eval ${_UNSET} wf_name; eval ${_UNSET} wf_res; eval ${_UNSET} wf_section; eval "${return_ok}"; fi; echo1 'is not a man page'; echo; eval ${_UNSET} wf_arg; eval ${_UNSET} wf_dot; eval ${_UNSET} wf_name; eval ${_UNSET} wf_res; eval ${_UNSET} wf_section; eval "${return_bad}"; } ######################################################################## # whatis_filespec () # # Print the filespec name as .SH to the temporary cat file. # whatis_filespec() { func_check whatis_filespec '=' 0 "$@"; if obj _OPT_WHATIS is_yes then eval to_tmp_line \ "'.SH $(echo1 "${_FILESPEC_ARG}" | sed 's/[^\\]-/\\-/g')'"; exit_test; fi; eval "${return_ok}"; } ######################################################################## # whatis_header () # # Print the whatis header to the temporary cat file. # whatis_header() { func_check whatis_header '=' 0 "$@"; if obj _OPT_WHATIS is_yes then to_tmp_line '.TH GROFFER WHATIS'; fi; eval "${return_ok}"; } ######################################################################## # where_is (<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. # # Variable prefix: w # where_is() { func_check where_is '>=' 1 "$@"; w_arg="$1"; if obj w_arg is_empty then eval ${_UNSET} w_arg; eval "${return_bad}"; fi; case "${w_arg}" in /*) eval ${_UNSET} w_arg; eval ${_UNSET} w_file; if test -f "${w_arg}" && test -x "${w_arg}" then eval "${return_ok}"; else eval "${return_bad}"; fi; ;; esac; eval set x "$(path_split "${PATH}")"; exit_test; shift; for p do case "$p" in */) w_file=${p}${w_arg}; ;; *) w_file=${p}/${w_arg}; ;; esac; if test -f "${w_file}" && test -x "${w_file}" then obj w_file echo1; eval ${_UNSET} w_arg; eval ${_UNSET} w_file; eval "${return_ok}"; fi; done; eval ${_UNSET} w_arg; eval ${_UNSET} w_file; eval "${return_bad}"; } ######################################################################## # main* Functions ######################################################################## # The main area contains the following parts: # - main_init(): initialize temporary files and set exit trap # - main_parse_MANOPT(): parse $MANOPT # - main_parse_args(): argument parsing # - main_set_mode (): determine the display mode # - main_do_fileargs(): process filespec arguments # - main_set_resources(): setup X resources # - main_display(): do the displaying # - main(): the main function that calls all main_*() ####################################################################### # main_init () # # set exit trap and create temporary files # # Globals: $_TMP_DIR, $_TMP_CAT, $_TMP_STDIN # # Variable prefix: mi # main_init() { func_check main_init = 0 "$@"; # call clean_up() on shell termination. trap_set; # create temporary directory umask 0022; _TMP_DIR=''; for d in "${GROFF_TMPDIR}" "${TMPDIR}" "${TMP}" "${TEMP}" \ "${TEMPDIR}" "${HOME}"'/tmp' '/tmp' "${HOME}" '.' do mi_dir="$d"; if obj mi_dir is_empty || obj mi_dir is_not_dir || \ obj mi_dir is_not_writable then continue; fi; case "${mi_dir}" in */) _TMP_DIR="${mi_dir}"; ;; *) _TMP_DIR="${mi_dir}"'/'; ;; esac; _TMP_DIR="${_TMP_DIR}groffer${_PROCESS_ID}"; if obj _TMP_DIR rm_tree then : else mi_tdir_="${_TMP_DIR}"_; mi_n=1; mi_tdir_n="${mi_tdir_}${mi_n}"; while obj mi_tdir_n is_existing do if obj mi_tdir_n rm_tree then # directory could not be removed mi_n="$(expr "${mi_n}" + 1)"; mi_tdir_n="${mi_tdir_}${mi_n}"; continue; fi; done; _TMP_DIR="${mi_tdir_n}"; fi; eval mkdir "${_TMP_DIR}"; if is_not_equal "$?" 0 then obj _TMP_DIR rm_tree; _TMP_DIR=''; continue; fi; if obj _TMP_DIR is_dir && obj _TMP_DIR is_writable then # $_TMP_DIR can now be used as temporary directory break; fi; obj _TMP_DIR rm_tree; _TMP_DIR=''; continue; done; if obj _TMP_DIR is_empty then error "main_init: \ Couldn't create a directory for storing temporary files."; fi; if obj _DEBUG_PRINT_TMPDIR is_yes then echo2 "temporary directory: ${_TMP_DIR}"; fi; _TMP_CAT="$(tmp_create groffer_cat)"; _TMP_STDIN="$(tmp_create groffer_input)"; exit_test; eval ${_UNSET} mi_dir; eval ${_UNSET} mi_n; eval ${_UNSET} mi_tdir_; eval ${_UNSET} mi_tdir_n; 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_* # # Variable prefix: mpm # main_parse_MANOPT() { func_check main_parse_MANOPT = 0 "$@"; if obj MANOPT is_not_empty then # Delete leading and final spaces MANOPT="$(echo1 "${MANOPT}" | sed -e ' s/^'"${_SPACE_SED}"'*// s/'"${_SPACE_SED}"'*$// ')"; exit_test; fi; if obj MANOPT is_empty then eval "${return_ok}"; fi; mpm_list=''; # add arguments in $MANOPT by mapping them to groffer options eval set x "$(list_from_cmdline _OPTS_MANOPT "${MANOPT}")"; exit_test; shift; until test "$#" -le 0 || is_equal "$1" '--' do mpm_opt="$1"; shift; case "${mpm_opt}" in -7|--ascii) list_append mpm_list '--ascii'; ;; -a|--all) list_append mpm_list '--all'; ;; -c|--catman) do_nothing; shift; ;; -d|--debug) do_nothing; ;; -D|--default) # undo all man options so far mpm_list=''; ;; -e|--extension) list_append mpm_list '--extension'; shift; ;; -f|--whatis) list_append mpm_list '--whatis'; shift; ;; -h|--help) do_nothing; shift; ;; -k|--apropos) # groffer's --apropos takes an argument, but man's does not, so do_nothing; ;; -l|--local-file) do_nothing; ;; -L|--locale) list_append mpm_list '--locale' "$1"; shift; ;; -m|--systems) list_append mpm_list '--systems' "$1"; shift; ;; -M|--manpath) list_append mpm_list '--manpath' "$1"; shift; ;; -p|--preprocessor) do_nothing; shift; ;; -P|--pager) list_append mpm_list '--pager' "$1"; shift; ;; -r|--prompt) do_nothing; shift; ;; -S|--sections) list_append mpm_list '--sections' "$1"; shift; ;; -t|--troff) do_nothing; shift; ;; -T|--device) list_append mpm_list '-T' "$1"; shift; ;; -u|--update) do_nothing; shift; ;; -V|--version) do_nothing; ;; -w|--where|--location) list_append mpm_list '--location'; ;; -Z|--ditroff) do_nothing; ;; # ignore all other options esac; done; # prepend $mpm_list to the command line if obj mpm_list is_not_empty then eval set x "${mpm_list}" '"$@"'; shift; fi; eval ${_UNSET} mpm_list; eval ${_UNSET} mpm_opt; 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 # # Variable prefix: mpa # main_parse_args() { func_check main_parse_args '>=' 0 "$@"; _ALL_PARAMS="$(list_from_cmdline _OPTS_CMDLINE "$@")"; exit_test; if obj _DEBUG_PRINT_PARAMS is_yes then echo2 "parameters: ${_ALL_PARAMS}"; fi; eval set x "${_ALL_PARAMS}"; shift; # 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 mpa_opt="$1"; # $mpa_opt is fed into the option handler shift; case "${mpa_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) if is_X then _OPT_MODE=X; fi; ;; -?) # delete leading `-' mpa_optchar="$(echo1 "${mpa_opt}" | sed -e 's/^-//')"; exit_test; if list_has _OPTS_GROFF_SHORT_NA "${mpa_optchar}" then list_append _ADDOPTS_GROFF "${mpa_opt}"; elif list_has _OPTS_GROFF_SHORT_ARG "${mpa_optchar}" then list_append _ADDOPTS_GROFF "${mpa_opt}" "$1"; shift; else error "main_parse_args(): Unknown option : \`$1'"; fi; ;; --all) _OPT_ALL='yes'; ;; --apropos) # run `apropos' _OPT_APROPOS='yes'; _APROPOS_SECTIONS=''; _OPT_WHATIS='no'; ;; --apropos-data) # run `apropos' for data sections _OPT_APROPOS='yes'; _APROPOS_SECTIONS='457'; _OPT_WHATIS='no'; ;; --apropos-devel) # run `apropos' for development sections _OPT_APROPOS='yes'; _APROPOS_SECTIONS='239'; _OPT_WHATIS='no'; ;; --apropos-progs) # run `apropos' for program sections _OPT_APROPOS='yes'; _APROPOS_SECTIONS='168'; _OPT_WHATIS='no'; ;; --ascii) list_append _ADDOPTS_GROFF '-mtty-char'; if obj _OPT_MODE is_empty then _OPT_MODE='text'; fi; ;; --auto) # the default automatic mode _OPT_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; ;; --debug|--debug-all|--debug-keep|--debug-lm|--debug-params|\ --debug-shell|--debug-stacks|--debug-tmpdir|--debug-user) # debug is handled at the beginning :; ;; --default) # reset variables to default reset; ;; --default-modes) # sequence of modes in auto mode; arg _OPT_DEFAULT_MODES="$1"; shift; ;; --display) # set X display, arg _OPT_DISPLAY="$1"; shift; ;; --do-nothing) _OPT_DO_NOTHING='yes'; ;; --dvi) if is_X then _OPT_MODE='dvi'; fi; ;; --dvi-viewer) # viewer program for dvi mode; arg _VIEWER_TERMINAL='no'; _OPT_VIEWER_DVI="$1"; shift; ;; --dvi-viewer-tty) # viewer program for dvi mode in tty; arg _VIEWER_TERMINAL='yes'; _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 _VIEWER_TERMINAL='no'; _OPT_VIEWER_HTML="$1"; shift; ;; --html-viewer-tty|--www-viewer-tty) # viewer for html mode in tty; arg _VIEWER_TERMINAL='yes'; _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 mpa_arg="$1"; shift; case "${mpa_arg}" in auto|'') # search mode automatically among default _OPT_MODE=''; ;; groff) # pass input to plain groff _OPT_MODE='groff'; ;; html|www) # display with a web browser _OPT_MODE='html'; ;; dvi) # display with xdvi viewer if is_X then _OPT_MODE='dvi'; fi; ;; pdf) # display with PDF viewer if is_X then _OPT_MODE='pdf'; fi; ;; ps) # display with Postscript viewer if is_X then _OPT_MODE='ps'; fi; ;; text) # output on terminal _OPT_MODE='text'; ;; tty) # output on terminal _OPT_MODE='tty'; ;; X|x) # output on X roff viewer if is_X then _OPT_MODE='x'; fi; ;; Q|source) # display source code _OPT_MODE="source"; ;; *) error "main_parse_args(): unknown mode ${mpa_arg}"; ;; esac; ;; --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'; ;; --no-special) # disable some special former calls _OPT_ALL='no' _OPT_APROPOS='no' _OPT_WHATIS='no' ;; --pager|--tty-viewer|--tty-viewer-tty) # set paging program for tty mode, arg _VIEWER_TERMINAL='yes'; _OPT_PAGER="$1"; shift; ;; --pdf) if is_X then _OPT_MODE='pdf'; fi; ;; --pdf-viewer) # viewer program for ps mode; arg _VIEWER_TERMINAL='no'; _OPT_VIEWER_PDF="$1"; shift; ;; --pdf-viewer-tty) # viewer program for ps mode in tty; arg _VIEWER_TERMINAL='yes'; _OPT_VIEWER_PDF="$1"; shift; ;; --print) # for argument test echo2 "$1"; shift; ;; --ps) if is_X then _OPT_MODE='ps'; fi; ;; --ps-viewer) # viewer program for ps mode; arg _VIEWER_TERMINAL='no'; _OPT_VIEWER_PS="$1"; shift; ;; --ps-viewer-tty) # viewer program for ps mode in tty; arg _VIEWER_TERMINAL='yes'; _OPT_VIEWER_PS="$1"; shift; ;; --resolution) # set resolution for X devices, arg mpa_arg="$1"; shift; case "${mpa_arg}" in 75|75dpi) mpa_dpi=75; ;; 100|100dpi) mpa_dpi=100; ;; *) error "main_parse_args(): \ only resoutions of 75 or 100 dpi are supported"; ;; esac; _OPT_RESOLUTION="${mpa_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'; _OPT_ALL='yes'; _OPT_APROPOS='no'; ;; --X|--x) if is_X then _OPT_MODE=x; fi; ;; --xrm) # pass X resource string, arg; list_append _OPT_XRM "$1"; shift; ;; --x-viewer|--X-viewer) # viewer program for x mode; arg _VIEWER_TERMINAL='no'; _OPT_VIEWER_X="$1"; shift; ;; --x-viewer-tty|--X-viewer-tty) # viewer program for x mode in tty; arg _VIEWER_TERMINAL='yes'; _OPT_VIEWER_X="$1"; shift; ;; *) error 'main_parse_args(): error on argument parsing : '"\`$*'"; ;; esac; done; shift; # remove `--' argument if obj _OPT_DO_NOTHING is_yes then leave; fi; # Remaining arguments are file names (filespecs). # Save them to list $_FILEARGS if is_equal "$#" 0 then # use "-" for standard input set x '-'; shift; fi; _FILEARGS=''; list_append _FILEARGS "$@"; if list_has _FILEARGS '-' then save_stdin; fi; # $_FILEARGS must be retrieved with `eval set x "$_FILEARGS"; shift;' eval ${_UNSET} mpa_arg; eval ${_UNSET} mpa_dpi; eval ${_UNSET} mpa_opt; eval ${_UNSET} mpa_optchar; 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}"; } # _check_device_with_mode() of main_parse_args() ######################################################################## # main_set_mode () # # Determine the display mode. # # Globals: # in: $DISPLAY, $_OPT_MODE, $_OPT_DEVICE # out: $_DISPLAY_MODE # # Variable prefix: msm # main_set_mode() { func_check main_set_mode = 0 "$@"; # set display if obj _OPT_DISPLAY is_not_empty then DISPLAY="${_OPT_DISPLAY}"; fi; if obj _OPT_V is_yes then 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 ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; fi; if obj _OPT_MODE is_equal 'source' then _DISPLAY_MODE='source'; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; fi; case "${_OPT_MODE}" in '') # automatic mode case "${_OPT_DEVICE}" in X*) if is_not_X then error_user "no X display found for device ${_OPT_DEVICE}"; fi; _DISPLAY_MODE='x'; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; ;; ascii|cp1047|latin1|utf8) if obj _DISPLAY_MODE is_not_equal 'text' then _DISPLAY_MODE='tty'; fi; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; ;; esac; if is_not_X then _DISPLAY_MODE='tty'; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; fi; if obj _OPT_DEFAULT_MODES is_empty then msm_modes="${_DEFAULT_MODES}"; else msm_modes="${_OPT_DEFAULT_MODES}"; fi; ;; text) _DISPLAY_MODE='text'; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; ;; tty) _DISPLAY_MODE='tty'; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; ;; html) _DISPLAY_MODE='html'; msm_modes="${_OPT_MODE}"; ;; *) # display mode was given if is_not_X then error_user "You must be in X Window for ${_OPT_MODE} mode."; fi; msm_modes="${_OPT_MODE}"; ;; esac; # only viewer modes are left eval set x "$(list_from_split "${msm_modes}" ',')"; exit_test; shift; while test "$#" -gt 0 do m="$1"; shift; case "$m" in dvi) if obj _OPT_VIEWER_DVI is_not_empty then msm_viewer="${_OPT_VIEWER_DVI}"; else msm_viewer="$(_get_first_prog "$_VIEWER_DVI}")"; exit_test; fi; if obj msm_viewer is_empty then error 'No viewer for dvi mode available.'; fi; if is_not_equal "$?" 0 then continue; fi; _DISPLAY_PROG="${msm_viewer}"; _DISPLAY_MODE="dvi"; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; ;; html) if obj _OPT_VIEWER_HTML is_not_empty then msm_viewer="${_OPT_VIEWER_HTML}"; else if is_X then msm_viewers="${_VIEWER_HTML_X}"; else msm_viewers="${_VIEWER_HTML_TTY}"; fi; msm_viewer="$(_get_first_prog "${msm_viewers}")"; exit_test; fi; if obj msm_viewer is_empty then error 'No viewer for html mode available.'; fi; if is_not_equal "$?" 0 then continue; fi; _DISPLAY_PROG="${msm_viewer}"; _DISPLAY_MODE=html; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; ;; pdf) if obj _OPT_VIEWER_PDF is_not_empty then msm_viewer="${_OPT_VIEWER_PDF}"; else msm_viewer="$(_get_first_prog "${_VIEWER_PDF}")"; exit_test; fi; if obj msm_viewer is_empty then error 'No viewer for pdf mode available.'; fi; if is_not_equal "$?" 0 then continue; fi; _DISPLAY_PROG="${msm_viewer}"; _DISPLAY_MODE="pdf"; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; ;; ps) if obj _OPT_VIEWER_PS is_not_empty then msm_viewer="${_OPT_VIEWER_PS}"; else msm_viewer="$(_get_first_prog "${_VIEWER_PS}")"; exit_test; fi; if obj msm_viewer is_empty then error 'No viewer for ps mode available.'; fi; if is_not_equal "$?" 0 then continue; fi; _DISPLAY_PROG="${msm_viewer}"; _DISPLAY_MODE="ps"; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; ;; text) _DISPLAY_MODE='text'; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; ;; tty) _DISPLAY_MODE='tty'; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; ;; x) if obj _OPT_VIEWER_X is_not_empty then msm_viewer="${_OPT_VIEWER_X}"; else msm_viewer="$(_get_first_prog "${_VIEWER_X}")"; exit_test; fi; if obj msm_viewer is_empty then error 'No viewer for x mode available.'; fi; if is_not_equal "$?" 0 then continue; fi; _DISPLAY_PROG="${msm_viewer}"; _DISPLAY_MODE='x'; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; ;; X) _DISPLAY_MODE='X'; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; eval "${return_ok}"; ;; esac; done; eval ${_UNSET} msm_modes; eval ${_UNSET} msm_viewer; eval ${_UNSET} msm_viewers; error_user "No suitable display mode found."; } # main_set_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. # # Variable prefix: _gfp # _get_first_prog() { if is_equal "$#" 0 then error "_get_first_prog() needs 1 argument."; fi; if is_empty "$1" then return "${_BAD}"; fi; eval set x "$(list_from_split "$1" ',')"; exit_test; shift; for i do _gfp_i="$i"; if obj _gfp_i is_empty then continue; fi; if eval is_prog "$(get_first_essential ${_gfp_i})" then exit_test; obj _gfp_i echo1; eval ${_UNSET} _gfp_i; return "${_GOOD}"; fi; done; eval ${_UNSET} _gfp_i; return "${_BAD}"; } # _get_first_prog() of main_set_mode() ####################################################################### # main_do_fileargs () # # Process filespec arguments in $_FILEARGS. # # Globals: # in: $_FILEARGS (process with `eval set x "$_FILEARGS"; shift;') # # Variable prefix: mdfa # main_do_fileargs() { func_check main_do_fileargs = 0 "$@"; special_setup; eval set x "${_FILEARGS}"; shift; eval ${_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 mdfa_filespec="$1"; _FILESPEC_ARG="$1"; shift; case "${mdfa_filespec}" in '') continue; ;; '-') special_filespec; if obj _OPT_APROPOS is_yes then continue; fi; register_file '-' continue; ;; ?) if obj _OPT_APROPOS is_yes then special_filespec; continue; fi; if list_has_not _MAN_AUTO_SEC_LIST "${mdfa_filespec}" then special_filespec; do_filearg "${mdfa_filespec}" continue; fi; mdfa_name="$1"; _FILESPEC_ARG="${_FILESPEC_ARG} $1"; special_filespec; case "${mdfa_name}" in */*|man:*|*\(*\)|*."${mdfa_filespec}") do_filearg "${mdfa_filespec}" continue; ;; esac; shift; if do_filearg "man:${mdfa_name}(${mdfa_filespec})" then continue; else do_filearg "${mdfa_filespec}" continue; fi; ;; *) special_filespec; if obj _OPT_APROPOS is_yes then continue; fi; do_filearg "${mdfa_filespec}" continue; ;; esac; done; # end of `s name' test while test "$#" -gt 0 do mdfa_filespec="$1"; _FILESPEC_ARG="$1"; shift; special_filespec; if obj _OPT_APROPOS is_yes then continue; fi; do_filearg "${mdfa_filespec}" done; obj _TMP_STDIN rm_file_with_debug; eval ${_UNSET} mdfa_filespec; eval ${_UNSET} mdfa_name; eval "${return_ok}"; } # main_do_fileargs() ######################################################################## # main_set_resources () # # Determine options for setting X resources with $_DISPLAY_PROG. # # Globals: $_DISPLAY_PROG, $_OUTPUT_FILE_NAME # # Variable prefix: msr # main_set_resources() { func_check main_set_resources = 0 "$@"; # $msr_prog viewer program # $msr_rl resource list msr_title="$(get_first_essential \ "${_OPT_TITLE}" "${_REGISTERED_TITLE}")"; exit_test; _OUTPUT_FILE_NAME=''; eval set x "${msr_title}"; shift; until is_equal "$#" 0 do msr_n="$1"; case "${msr_n}" in '') continue; ;; ,*) msr_n="$(echo1 "$1" | sed -e 's/^,,*//')"; exit_test; ;; esac if obj msr_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}${msr_n}"; shift; done; case "${_OUTPUT_FILE_NAME}" in '') _OUTPUT_FILE_NAME='-'; ;; ,*) error "main_set_resources(): ${_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 ${_UNSET} msr_n; eval ${_UNSET} msr_prog; eval ${_UNSET} msr_rl; eval ${_UNSET} msr_title; eval "${return_ok}"; fi; eval set x "${_DISPLAY_PROG}"; shift; msr_prog="$(base_name "$1")"; exit_test; shift; if test $# != 0 then if obj _DISPLAY_PROG is_empty then _DISPLAY_ARGS="$*"; else _DISPLAY_ARGS="$* ${_DISPLAY_ARGS}"; fi; fi; msr_rl=''; if obj _OPT_BD is_not_empty then case "${msr_prog}" in ghostview|gv|gxditview|xditview|xdvi) list_append msr_rl '-bd' "${_OPT_BD}"; ;; esac; fi; if obj _OPT_BG is_not_empty then case "${msr_prog}" in ghostview|gv|gxditview|xditview|xdvi) list_append msr_rl '-bg' "${_OPT_BG}"; ;; kghostview) list_append msr_rl '--bg' "${_OPT_BG}"; ;; xpdf) list_append msr_rl '-papercolor' "${_OPT_BG}"; ;; esac; fi; if obj _OPT_BW is_not_empty then case "${msr_prog}" in ghostview|gv|gxditview|xditview|xdvi) _list_append msr_rl '-bw' "${_OPT_BW}"; ;; esac; fi; if obj _OPT_FG is_not_empty then case "${msr_prog}" in ghostview|gv|gxditview|xditview|xdvi) list_append msr_rl '-fg' "${_OPT_FG}"; ;; kghostview) list_append msr_rl '--fg' "${_OPT_FG}"; ;; esac; fi; if is_not_empty "${_OPT_FN}" then case "${msr_prog}" in ghostview|gv|gxditview|xditview|xdvi) list_append msr_rl '-fn' "${_OPT_FN}"; ;; kghostview) list_append msr_rl '--fn' "${_OPT_FN}"; ;; esac; fi; if is_not_empty "${_OPT_GEOMETRY}" then case "${msr_prog}" in ghostview|gv|gxditview|xditview|xdvi|xpdf) list_append msr_rl '-geometry' "${_OPT_GEOMETRY}"; ;; kghostview) list_append msr_rl '--geometry' "${_OPT_GEOMETRY}"; ;; esac; fi; if is_empty "${_OPT_RESOLUTION}" then _OPT_RESOLUTION="${_DEFAULT_RESOLUTION}"; case "${msr_prog}" in gxditview|xditview) list_append msr_rl '-resolution' "${_DEFAULT_RESOLUTION}"; ;; xpdf) case "${_DEFAULT_RESOLUTION}" in 75) # 72dpi is '100' list_append msr_rl '-z' '104'; ;; 100) list_append msr_rl '-z' '139'; ;; esac; ;; esac; else case "${msr_prog}" in ghostview|gv|gxditview|xditview|xdvi) list_append msr_rl '-resolution' "${_OPT_RESOLUTION}"; ;; xpdf) case "${_OPT_RESOLUTION}" in 75) list_append msr_rl '-z' '104'; # '100' corresponds to 72dpi ;; 100) list_append msr_rl '-z' '139'; ;; esac; ;; esac; fi; if is_yes "${_OPT_ICONIC}" then case "${msr_prog}" in ghostview|gv|gxditview|xditview|xdvi) list_append msr_rl '-iconic'; ;; esac; fi; if is_yes "${_OPT_RV}" then case "${msr_prog}" in ghostview|gv|gxditview|xditview|xdvi) list_append msr_rl '-rv'; ;; esac; fi; if is_not_empty "${_OPT_XRM}" then case "${msr_prog}" in ghostview|gv|gxditview|xditview|xdvi|xpdf) eval set x "${_OPT_XRM}"; shift; for i do list_append msr_rl '-xrm' "$i"; done; ;; esac; fi; if is_not_empty "${msr_title}" then case "${msr_prog}" in gxditview|xditview) list_append msr_rl '-title' "${msr_title}"; ;; esac; fi; _DISPLAY_ARGS="${msr_rl}"; eval ${_UNSET} msr_n; eval ${_UNSET} msr_prog; eval ${_UNSET} msr_rl; eval ${_UNSET} msr_title; 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, # $_TMP_CAT, $_OPT_PAGER, $PAGER, $_MANOPT_PAGER, # $_OUTPUT_FILE_NAME # # Variable prefix: md # main_display() { func_check main_display = 0 "$@"; export md_addopts; export md_groggy; export md_modefile; if obj _TMP_CAT is_non_empty_file then md_modefile="${_OUTPUT_FILE_NAME}"; else echo2 'groffer: empty input.'; clean_up; eval ${_UNSET} md_modefile; eval "${return_ok}"; fi; # go to the temporary directory to be able to access internal data files cd "${_TMP_DIR}" >"${_NULL_DEV}" 2>&1; 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; md_groggy="$(tmp_cat | eval grog "${md_options}")"; exit_test; _do_opt_V; obj md_modefile rm_file; mv "${_TMP_CAT}" "${md_modefile}"; trap_unset; cat "${md_modefile}" | \ { trap_set; eval "${md_groggy}" "${_ADDOPTS_GROFF}"; } & ;; text|tty) case "${_OPT_DEVICE}" in '') md_device="$(get_first_essential \ "${_OPT_TEXT_DEVICE}" "${_DEFAULT_TTY_DEVICE}")"; exit_test; ;; ascii|cp1047|latin1|utf8) md_device="${_OPT_DEVICE}"; ;; *) warning "main_display(): \ wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; ;; esac; md_addopts="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}"; md_groggy="$(tmp_cat | grog -T${md_device})"; exit_test; if obj _DISPLAY_MODE is_equal 'text' then _do_opt_V; tmp_cat | eval "${md_groggy}" "${md_addopts}"; else md_pager=''; for p in "${_OPT_PAGER}" "${PAGER}" "${_MANOPT_PAGER}" \ 'less -r -R' 'more' 'pager' 'cat' do md_p="$p"; if eval is_prog ${md_p} then # no "" for is_prog() allows args for $p md_pager="${md_p}"; break; fi; done; if obj md_pager is_empty then error 'main_display(): no pager program found for tty mode'; fi; _do_opt_V; tmp_cat | eval "${md_groggy}" "${md_addopts}" | \ eval "${md_pager}"; fi; clean_up; ;; source) tmp_cat; clean_up; ;; #### viewer modes dvi) case "${_OPT_DEVICE}" in ''|dvi) do_nothing; ;; *) warning "main_display(): \ wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}" ;; esac; md_modefile="${md_modefile}".dvi; md_groggy="$(tmp_cat | grog -Tdvi)"; exit_test; _do_display; ;; html) case "${_OPT_DEVICE}" in ''|html) do_nothing; ;; *) warning "main_display(): \ wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; ;; esac; md_modefile="${md_modefile}".html; md_groggy="$(tmp_cat | grog -Thtml)"; exit_test; _do_display; ;; pdf) case "${_OPT_DEVICE}" in ''|ps) do_nothing; ;; *) warning "main_display(): \ wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; ;; esac; md_groggy="$(tmp_cat | grog -Tps)"; exit_test; _do_display _make_pdf; ;; ps) case "${_OPT_DEVICE}" in ''|ps) do_nothing; ;; *) warning "main_display(): \ wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; ;; esac; md_modefile="${md_modefile}".ps; md_groggy="$(tmp_cat | grog -Tps)"; exit_test; _do_display; ;; x) case "${_OPT_DEVICE}" in X*) md_device="${_OPT_DEVICE}" ;; *) case "${_OPT_RESOLUTION}" in 100) md_device='X100'; if obj _OPT_GEOMETRY is_empty then case "${_DISPLAY_PROG}" in gxditview|xditview) # add width of 800dpi for resolution of 100dpi to the args list_append _DISPLAY_ARGS '-geometry' '800'; ;; esac; fi; ;; *) md_device='X75-12'; ;; esac esac; md_groggy="$(tmp_cat | grog -T${md_device} -Z)"; exit_test; _do_display; ;; X) case "${_OPT_DEVICE}" in '') md_groggy="$(tmp_cat | grog -X)"; exit_test; ;; X*|dvi|html|lbp|lj4|ps) # these devices work with md_groggy="$(tmp_cat | grog -T"${_OPT_DEVICE}" -X)"; exit_test; ;; *) warning "main_display(): \ wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; md_groggy="$(tmp_cat | grog -Z)"; exit_test; ;; esac; _do_display; ;; *) error "main_display(): unknown mode \`${_DISPLAY_MODE}'"; ;; esac; eval ${_UNSET} md_addopts; eval ${_UNSET} md_device; eval ${_UNSET} md_groggy; eval ${_UNSET} md_modefile; eval ${_UNSET} md_options; eval ${_UNSET} md_p; eval ${_UNSET} md_pager; eval "${return_ok}"; } # main_display() ######################## # _do_display ([<prog>]) # # Perform the generation of the output and view the result. If an # argument is given interpret it as a function name that is called in # the midst (actually only for `pdf'). # # Globals: $md_modefile, $md_groggy (from main_display()) # _do_display() { func_check _do_display '>=' 0 "$@"; _do_opt_V; if obj _DISPLAY_PROG is_empty then trap_unset; { trap_set; eval "${md_groggy}" "${_ADDOPTS_GROFF}" "${_TMP_CAT}"; } & else obj md_modefile rm_file; cat "${_TMP_CAT}" | \ eval "${md_groggy}" "${_ADDOPTS_GROFF}" > "${md_modefile}"; if is_not_empty "$1" then eval "$1"; fi; obj _TMP_CAT rm_file_with_debug; if obj _VIEWER_TERMINAL is_yes # for programs that run on tty then eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "\"${md_modefile}\""; else case "${_DISPLAY_PROG}" in # lynx\ *|less\ *|more\ *) # programs known to run on the terminal # eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "\"${md_modefile}\""; # ;; *) trap_unset; { trap_set; eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "\"${md_modefile}\""; } & ;; esac; fi; fi; eval "${return_ok}"; } # _do_display() of main_display() ############# # _do_opt_V () # # Check on option `-V'; if set print the corresponding output and leave. # # Globals: $_ALL_PARAMS, $_ADDOPTS_GROFF, $_DISPLAY_MODE, $_DISPLAY_PROG, # $_DISPLAY_ARGS, $md_groggy, $md_modefile # # Variable prefix: _doV # _do_opt_V() { func_check _do_opt_V '=' 0 "$@"; if obj _OPT_V is_yes then _OPT_V='no'; echo1 "Parameters: ${_ALL_PARAMS}"; echo1 "Display mode: ${_DISPLAY_MODE}"; echo1 "Output file: ${md_modefile}"; echo1 "Display prog: ${_DISPLAY_PROG} ${_DISPLAY_ARGS}"; a="$(eval echo1 "'${_ADDOPTS_GROFF}'")"; exit_test; echo1 "Output of grog: ${md_groggy} $a"; _doV_res="$(eval "${md_groggy}" "${_ADDOPTS_GROFF}")"; exit_test; echo1 "groff -V: ${_doV_res}" leave; fi; eval "${return_ok}"; } # _do_opt_V() of main_display() ############## # _make_pdf () # # Transform to pdf format; for pdf mode in _do_display(). # # Globals: $md_modefile (from main_display()) # # Variable prefix: _mp # _make_pdf() { func_check _do_display '=' 0 "$@"; _mp_psfile="${md_modefile}"; md_modefile="${md_modefile}.pdf"; obj md_modefile rm_file; if gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \ -sOutputFile="${md_modefile}" -c save pop -f "${_mp_psfile}" then :; else error '_make_pdf: could not transform into pdf format.'; fi; obj _mp_psfile rm_file_with_debug; eval ${_UNSET} _mp_psfile; eval "${return_ok}"; } # _make_pdf() of main_display() ######################################################################## # main (<command_line_args>*) # # The main function for groffer. # # Arguments: # main() { func_check main '>=' 0 "$@"; # Do not change the sequence of the following functions! landmark '13: main_init()'; main_init; landmark '14: main_parse_MANOPT()'; main_parse_MANOPT; landmark '15: main_parse_args()'; main_parse_args "$@"; landmark '16: main_set_mode()'; main_set_mode; landmark '17: main_do_fileargs()'; main_do_fileargs; landmark '18: main_set_resources()'; main_set_resources; landmark '19: main_display()'; main_display; eval "${return_ok}"; } ######################################################################## main "$@";