diff options
Diffstat (limited to 'contrib/groffer/shell/groffer2.sh')
-rw-r--r-- | contrib/groffer/shell/groffer2.sh | 7312 |
1 files changed, 7312 insertions, 0 deletions
diff --git a/contrib/groffer/shell/groffer2.sh b/contrib/groffer/shell/groffer2.sh new file mode 100644 index 00000000..d76c6bd5 --- /dev/null +++ b/contrib/groffer/shell/groffer2.sh @@ -0,0 +1,7312 @@ +#! /bin/sh + +# groffer - display groff files + +# Source file position: <groff-source>/contrib/groffer/shell/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, 2006, 2009 +# Free Software Foundation, Inc. +# Written by Bernd Warken <groff-bernd.warken-72@web.de>. + +# Last update: 5 Jan 2009 + +# 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>. + + +######################################################################## +# Test of rudimentary shell functionality +######################################################################## + +# Zsh is not Bourne compatible without the following: +if test -n "$ZSH_VERSION"; then + emulate sh + NULLCMD=: +fi + + +######################################################################## +# 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 xTesTx \ + | sed -n 's/^.\([Tt]e*x*sTT*\).*$/\1/p' \ + | sed 's|T|t|g')"_ != _test_ +then + echo 'The sed program did not work.' >&2; + exit "${_ERROR}"; +fi; + + +######################################################################## +# Test of `cat'. +# +if test _"$(echo test | cat)"_ != _test_ +then + error 'Test of "cat" command failed.'; +fi; + + +######################################################################## +# Test of function definitions. +# +_t_e_s_t_f_u_n_c_() +{ + return 0; +} + +_test_func() +{ + echo test; +} + +if _t_e_s_t_f_u_n_c_ 2>${_NULL_DEV} && \ + test _"$(_test_func 2>${_NULL_DEV})"_ = _test_ +then + :; +else + echo 'Shell '"${_SHELL}"' does not support function definitions.' >&2; + exit "${_ERROR}"; +fi; + + +######################################################################## +# landmark (<text>) +# +# Print <text> to standard error as a debugging aid. +# +# Globals: $_DEBUG_LM +# +landmark() +{ + if test _"${_DEBUG_LM}"_ = _yes_ + then + echo "LM: $*" >&2; + fi; +} # landmark() + + +######################################################################## +# test for compression. +# +export _HAS_COMPRESSION; +export _HAS_BZIP; +if test _"$(echo 'test' | gzip -c -d -f - 2>${_NULL_DEV})"_ = _test_ +then + _HAS_COMPRESSION='yes'; + if echo '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; + + +######################################################################## +# debug - diagnostic messages +######################################################################## + +export _DEBUG_FUNC_CHECK; +if test _"${_BEFORE_MAKE}"_ = _yes_ +then + _DEBUG_FUNC_CHECK='yes'; +else + _DEBUG_FUNC_CHECK='no'; +fi; +_DEBUG_FUNC_CHECK='no'; # disable function checking +#_DEBUG_FUNC_CHECK='yes'; # enable function checking + +export _DEBUG_STACKS; +_DEBUG_STACKS='no'; # disable stack output in each function +#_DEBUG_STACKS='yes'; # enable stack output in each function + +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() + +export _DEBUG_LM; +_DEBUG_LM='no'; # disable landmark messages +#_DEBUG_LM='yes'; # enable landmark messages + +export _DEBUG_GROG; +_DEBUG_GROG='no'; # disable grog output +#_DEBUG_GROG='yes'; # enable grog output + +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_PRINT_FILENAMES; +_DEBUG_PRINT_FILENAMES='no'; # disable printing of the found file names +#_DEBUG_PRINT_FILENAMES='yes'; # enable printing of the found file names + +# determine all --debug* options +case " $*" in +*\ --deb*|*\ --d*-*) + # --debug-* options + d=' --debug-all --debug-filenames --debug-func --debug-grog '\ +'--debug-not-func --debug-keep --debug-lm --debug-params '\ +'--debug-shell --debug-stacks --debug-tmpdir --debug-user '; + # non-debug options with scheme --d*-* + n=' --do-nothing --default-modes --dvi-viewer --dvi-viewer-tty '; + for i + do + case "$i" in + --deb|--debu|--debug) + _DEBUG_FUNC_CHECK='yes'; + # _DEBUG_STACKS='yes'; + _DEBUG_USER_WITH_STACK='yes'; + # _DEBUG_LM='yes'; + _DEBUG_GROG='yes'; + _DEBUG_KEEP_FILES='yes'; + _DEBUG_PRINT_PARAMS='yes'; + _DEBUG_PRINT_SHELL='yes'; + _DEBUG_PRINT_TMPDIR='yes'; + _DEBUG_PRINT_FILENAMES='yes'; + continue; + ;; + --d*-*) + # before `-' + b="$(echo x"$i" | sed 's/^x--\([^-]*\)-.*$/\1/')"; + # after `-' + a="$(echo x"$i" | sed 's/^x--[^-]*-\(.*\)$/\1/')"; + ;; + *) + continue; + ;; + esac; + case "$n" in + *\ --$b*-$a*) + continue; + ;; + esac; + case "$d" in + *\ --$b*-$a*) + case "$a" in + f|s) # double --debug-* options + continue; + ;; + esac; + # extract whole word of double abbreviation + s="$(cat <<EOF | sed -n 's/^.* \(--'"$b"'[^ -]*-'"$a"'[^ ]*\) .*/\1/p' +$d +EOF +)" + case "$s" in + '') continue; ;; + --debug-all) + _DEBUG_FUNC_CHECK='yes'; + _DEBUG_STACKS='yes'; + _DEBUG_USER_WITH_STACK='yes'; + _DEBUG_GROG='yes'; + _DEBUG_LM='yes'; + _DEBUG_KEEP_FILES='yes'; + _DEBUG_PRINT_PARAMS='yes'; + _DEBUG_PRINT_SHELL='yes'; + _DEBUG_PRINT_TMPDIR='yes'; + _DEBUG_PRINT_FILENAMES='yes'; + _DEBUG_PRINT_FILENAMES='yes'; + ;; + --debug-filenames) + _DEBUG_PRINT_FILENAMES='yes'; + ;; + --debug-func) + _DEBUG_FUNC_CHECK='yes'; + ;; + --debug-not-func) + _DEBUG_FUNC_CHECK='no'; + _DEBUG_STACKS='no'; + _DEBUG_USER_WITH_STACK='no'; + ;; + --debug-grog) + _DEBUG_GROG='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_STACKS}"_ = _yes_ || \ + test _"${_DEBUG_USER_WITH_STACK}"_ = _yes_ +then + _DEBUG_FUNC_CHECK='yes'; +fi + +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 +######################################################################## + +landmark "1: 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 a single character. +# [a-z] local loop variables, e.g. $i + +# In functions, other writings are used for variables. As some shells +# do not support the `local' command a unique prefix in lower case is +# constructed for each function, most are the abbreviation of the +# function name. All variable names start with this prefix. +# ${prefix}_[a-z_]* variable name in a function, e.g. $msm_modes + + +######################################################################## +# read-only variables (global to this file) +######################################################################## + +# function return values; `0' means ok; other values are error codes +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="'pdf' 'html' 'ps' 'x' 'dvi' 'tty'"; +export _DEFAULT_RESOLUTION; +_DEFAULT_RESOLUTION='75'; + +export _DEFAULT_TTY_DEVICE; +_DEFAULT_TTY_DEVICE='latin1'; + +# _VIEWER_* viewer programs for different modes constructed as lists +export _VIEWER_DVI_TTY; # viewer program for dvi mode in tty +export _VIEWER_DVI_X; # viewer program for dvi mode in X +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_TTY; # viewer program for pdf mode in tty +export _VIEWER_PDF_X; # viewer program for pdf mode in X +export _VIEWER_PS_TTY; # viewer program for ps mode in tty +export _VIEWER_PS_X; # viewer program for ps mode in X +export _VIEWER_TTY_TTY; # viewer program for X/x mode in tty +export _VIEWER_TTY_X; # viewer program for X/x mode in X +export _VIEWER_X_TTY; # viewer program for X/x mode in tty +export _VIEWER_X_X; # viewer program for X/x mode in X +_VIEWER_DVI_TTY=""; +_VIEWER_DVI_X="'kdvi' 'xdvi' 'dvilx'"; +_VIEWER_HTML_TTY="'lynx' 'w3m'"; +_VIEWER_HTML_X="'konqueror' 'epiphany' 'mozilla-firefox' 'firefox' 'mozilla' \ +'netscape' 'galeon' 'opera' 'amaya' 'arena' 'mosaic'"; +_VIEWER_PDF_TTY=""; +_VIEWER_PDF_X="'kpdf' 'acroread' 'evince' 'xpdf -z 150' 'gpdf' \ +'kghostview --scale 1.45' 'ggv'"; +_VIEWER_PS_TTY=""; +_VIEWER_PS_X="'kpdf' 'kghostview --scale 1.45' 'evince' 'ggv' 'gv' \ +'ghostview' 'gs_x11,gs'"; +_VIEWER_TTY_TTY="'less -r -R' 'more' 'pager'"; +_VIEWER_TTY_X="'xless'"; +_VIEWER_X_TTY=""; +_VIEWER_X_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="$$"; + +export _START_DIR; # directory at start time of the script +_START_DIR="$(pwd)"; + + +############ 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-filenames' \ +'debug-func' 'debug-not-func' 'debug-grog' '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' 'to-stdout' 'text-device' 'tty' 'tty-device' \ +'version' 'whatis' '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' 'k' 'l' 'N' 'p' \ +'R' 's' 'S' 't' 'U' 'z'"; +_OPTS_GROFF_SHORT_ARG="'d' 'f' 'F' 'I' 'K' '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' 'where'"; + +_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 _APROPOS_PROG; # Program to run apropos. +export _APROPOS_SECTIONS; # Sections for different --apropos-*. +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 _FILE_NR; # number for temporary `,file,*' +export _FILEARGS; # Stores filespec parameters. +export _FILESPEC_ARG; # Stores the actual filespec parameter. +export _FILESPEC_IS_MAN; # filespec is for searching a man page +export _FUNC_STACK; # Store debugging information. +export _MACRO_PACKAGES; # groff's macro packages. +export _MACRO_PKG; # Macro package for each found file. +export _NO_FILESPECS; # Yes, if there are no filespec arguments. +export _OUTPUT_FILE_NAME; # output generated, see main_set_res..() +export _REG_TITLE_LIST; # Processed file names. +export _SOELIM_R; # option -r for soelim +export _SPECIAL_FILESPEC; # Filespec ran for apropos or whatis. +export _SPECIAL_SETUP; # Test on setup for apropos or whatis. +export _VIEWER_BACKGROUND; # viewer shall be run in the background or not +# _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_PATH; # search path for man pages as a list +export _MAN_SEC; # sections for man pages; sep. `:' +export _MAN_SEC_CHARS; # sections for man pages as [] construct +export _MAN_SEC_LIST; # sections for man pages as a list +export _MAN_SYS; # system names for man pages as a list +# _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 +# variables for mode pdf +export _PDF_DID_NOT_WORK; +export _PDF_HAS_GS; +export _PDF_HAS_PS2PDF; +# _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_EXTENSION; # set extension for man page search +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_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_STDOUT; # print mode file to standard output +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_HTML; # viewer program for html mode +export _OPT_VIEWER_PDF; # viewer program for pdf mode +export _OPT_VIEWER_PS; # viewer program for ps 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 +# _TMP_* temporary directory and files +export _TMP_DIR; # groffer directory for temporary files +export _TMP_CAT; # stores concatenation of everything +export _TMP_MAN; # stores find of man path +export _TMP_MANSPEC; # filters man pages with filespec +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 +######################################################################## + +# For variables that can be reset by option `--default', see reset(). + +_FILE_NR=0; +_FILEARGS=''; +_MACRO_PACKAGES="'-man' '-mdoc' '-me' '-mm' '-mom' '-ms'"; +_SPECIAL_FILESPEC='no'; +_SPECIAL_SETUP='no'; + +# _TMP_* temporary files +_TMP_DIR=''; +_TMP_CAT=''; +_TMP_MAN=''; +_TMP_CONF=''; +_TMP_STDIN=''; + +# variables for mode pdf +_PDF_DID_NOT_WORK='no'; +_PDF_HAS_GS='no'; +_PDF_HAS_PS2PDF='no'; + +# option -r for soelim +if : | soelim -r 2>${_NULL_DEV} >${_NULL_DEV} +then + _SOELIM_R='-r'; +else + _SOELIM_R=''; +fi; + +######################################################################## +# 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=''; + _APROPOS_PROG=''; + _APROPOS_SECTIONS=''; + _DISPLAY_ARGS=''; + _DISPLAY_MODE=''; + _DISPLAY_PROG=''; + _MACRO_PKG=''; + _NO_FILESPECS=''; + _REG_TITLE_LIST=''; + + # _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_CHARS=''; + _MAN_SEC_LIST=''; + _MAN_SYS=''; + + # _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_EXTENSION=''; + _OPT_FG=''; + _OPT_FN=''; + _OPT_GEOMETRY=''; + _OPT_ICONIC='no'; + _OPT_LANG=''; + _OPT_MODE=''; + _OPT_MANPATH=''; + _OPT_PAGER=''; + _OPT_RESOLUTION=''; + _OPT_RV='no'; + _OPT_SECTIONS=''; + _OPT_SYSTEMS=''; + _OPT_STDOUT='no'; + _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_BACKGROUND='no'; +} + +reset; + + +######################################################################## +# Preliminary functions for error handling +######################################################################## + +landmark "2: preliminary functions"; + +# These functions do not have a func-check frame. Basically they could be +# moved to the functions in alphabetical order. + +############## +# echo1 (<text>*) +# +# Output to stdout with final line break. +# +# Arguments : arbitrary text including `-'. +# +echo1() +{ + cat <<EOF +$@ +EOF +} # echo1() + + +############## +# echo2 (<text>*) +# +# Output to stderr with final line break. +# +# Arguments : arbitrary text including `-'. +# +echo2() +{ + cat >&2 <<EOF +$@ +EOF +} # echo2() + + + + +############## +# clean_up () +# +# Clean up at exit. +# +cu_already='no'; +clean_up() +{ + cd "${_START_DIR}" >"${_NULL_DEV}" 2>&1; + if test _${_DEBUG_KEEP_FILES}_ = _yes_ + then + if test _"$cu_already"_ = _yes_ + then + eval "${return_ok}"; + fi; + cu_already=yes; + echo2 "Kept temporary directory ${_TMP_DIR}." + else + if test _"${_TMP_DIR}"_ != __ + then + if test -e "${_TMP_DIR}" + then + rm -f -r "${_TMP_DIR}" >${_NULL_DEV} 2>&1; + fi; + fi; + fi; + eval "${return_ok}"; +} # clean_up() + + +############# +# diag (text>*) +# +# Output a diagnostic message to stderr. +# +diag() +{ + echo2 '>>>>>'"$*"; +} # diag() + + +############# +# 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() + + +############# +# error_user (<text>*) +# +# Print an error message to standard error; exit with an error condition. +# The error is supposed to be produced 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}"; +} # error_user() + + + +############# +# 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; +} # exit_test() + + +######################################################################## +# Definition of normal Functions in alphabetical order +######################################################################## + +landmark "3: functions"; + +######################################################################## +# apropos_filespec () +# +# Compose temporary file for filspec. +# +# Globals: in: $_OPT_APROPOS, $_SPECIAL_SETUP, $_FILESPEC_ARG, +# $_APROPOS_PROG, $_APROPOS_SECTIONS, $_OPT_SECTIONS +# out: $_SPECIAL_FILESPEC +# +# Variable prefix: af +# +apropos_filespec() +{ + + func_check apropos_filespec '=' 0 "$@"; + if obj _OPT_APROPOS is_yes + then + if obj _SPECIAL_SETUP is_not_yes + then + error 'apropos_filespec(): apropos_setup() must be run first.'; + fi; + _SPECIAL_FILESPEC='yes'; + if obj _NO_FILESPECS is_yes + then + to_tmp_line '.SH no filespec'; + eval "${_APROPOS_PROG}" | sed 's/^/\\\&/' >>"${_TMP_CAT}"; + eval "${return_ok}"; + fi; + eval to_tmp_line \ + "'.SH $(echo1 "${_FILESPEC_ARG}" | sed 's/[^\\]-/\\-/g')'"; + exit_test; + if obj _APROPOS_SECTIONS is_empty + then + if obj _OPT_SECTIONS is_empty + then + s='^.*(..*).*$'; + else + s='^.*(['"$(echo1 "${_OPT_SECTIONS}" | sed 's/://g')"']'; + fi; + else + s='^.*(['"${_APROPOS_SECTIONS}"']'; + fi; +### apropos_filespec() + af_filespec="$(echo1 "${_FILESPEC_ARG}" | sed ' +s,/,\\/,g +s/\./\\./g +')"; + eval "${_APROPOS_PROG}" "'${_FILESPEC_ARG}'" | \ + sed -n ' +/^'"${af_filespec}"': /s/^\(.*\)$/\\\&\1/p +/'"$s"'/p +' | \ + sort |\ + sed ' +s/^\(.*(..*).*\) *- *\(.*\)$/\.br\n\.TP 15\n\.BR \"\1\"\n\\\&\2/ +' >>"${_TMP_CAT}"; + eval ${_UNSET} af_filespec; + eval "${return_ok}"; + else + eval "${return_bad}"; + fi; +} # apropos_filespec() + + +######################################################################## +# apropos_setup () +# +# Setup for the --apropos* options, just 2 global variables are set. +# +# Globals: in: $_OPT_APROPOS +# out: $_SPECIAL_SETUP, $_APROPOS_PROG +# +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'; + _SPECIAL_SETUP='yes'; + if obj _OPT_TITLE is_empty + then + _OPT_TITLE='apropos'; + fi; + eval "${return_ok}"; + else + eval "${return_bad}"; + fi; +} # apropos_setup() + + +######################################################################## +# 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. The output is constructed according the shell +# program `basename'. +# +# 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 's|//*$||')"; + exit_test; + ;; + esac; + case "${bn_name}" in + '') + eval ${_UNSET} bn_name; + eval "${return_bad}"; + ;; + /) + # this is like `basename' does + echo1 '/'; + ;; + */*) + # delete everything before and including the last slash `/'. + echo1 "${bn_name}" | sed 's|^.*//*\([^/]*\)$|\1|'; + ;; + *) + obj bn_name echo1; + ;; + esac; + eval ${_UNSET} bn_name; + eval "${return_ok}"; +} # base_name() + + +######################################################################## +# 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. +# +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 is_file "$1" + then + :; + else + error 'cat_z(): argument $1 is not a file.'; + fi; + if test -s "$1" + then + :; + else + eval "${return_ok}"; + fi; + if obj _HAS_COMPRESSION is_yes + then + if obj _HAS_BZIP is_yes + then + # test whether being compressed with bz2 + if bzip2 -t "$1" 2>${_NULL_DEV} + then + bzip2 -c -d "$1" 2>${_NULL_DEV}; + eval "${return_ok}"; + fi; + fi; + # if not compressed gzip acts like `cat' + gzip -c -d -f "$1" 2>${_NULL_DEV}; + else + cat "$1"; + fi; + eval "${return_ok}"; +} # cat_z() + + +######################################################################## +# 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: dir_name()*'; +######################################################################## + +####################################################################### +# dir_name (<name>) +# +# Get the directory name of <name>. The output is constructed +# according to the shell program `dirname'. +# +# Arguments : 1 +# Output : the directory part of <name> +# +# Variable prefix: dn +# +dir_name() +{ + func_check dir_name = 1 "$@"; + obj_from_output dn_name dir_name_chop "$1"; + case "${dn_name}" in + ''|.) + echo1 '.'; + ;; + /) + echo1 '/'; + ;; + */*) + echo1 "$(echo1 "${dn_name}" | sed 's#/*[^/][^/]*$##')"; + ;; + *) + echo1 "${dn_name}"; + ;; + esac; + eval "${return_ok}"; +} # dir_name() + + +####################################################################### +# dir_name_append (<dir> <name>) +# +# Append `name' to `dir' with clean handling of `/'. +# +# Arguments : 2 +# Output : the generated new directory name <dir>/<name> +# +dir_name_append() +{ + func_check dir_name_append = 2 "$@"; + if is_empty "$1" + then + echo1 "$2"; + elif is_empty "$2" + then + echo1 "$1"; + else + dir_name_chop "$1"/"$2"; + fi; + eval "${return_ok}"; +} # dir_name_append() + + +######################################################################## +# dir_name_chop (<name>) +# +# Remove unnecessary slashes from directory name. +# +# Argument: 1, a directory name. +# Output: path without double, or trailing slashes. +# +# Variable prefix: dc +# +dir_name_chop() +{ + func_check dir_name_chop = 1 "$@"; + # replace all multiple slashes by a single slash `/'. + dc_res="$(echo1 "$1" | sed 's|///*|/|g')"; + exit_test; + case "${dc_res}" in + ?*/) + # remove trailing slash '/'; + echo1 "${dc_res}" | sed 's|/$||'; + ;; + *) + obj dc_res echo1 + ;; + esac; + eval ${_UNSET} dc_res; + eval "${return_ok}"; +} # dir_name_chop() + + +######################################################################## +# do_nothing () +# +# Dummy function that does nothing. +# +do_nothing() +{ + eval return "${_OK}"; +} # do_nothing() + + +######################################################################## +# echo1 (<text>*) +# +# Print to standard output with final line break. +# +# defined above + + +######################################################################## +# 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 + + +if test _"${_DEBUG_FUNC_CHECK}"_ = _yes_ +then + + ############# + # func_check (<func_name> <rel_op> <nr_args> "$@") + # + # This is called at the first line of each function. It checks the + # number of arguments of function <func_name> and registers the + # function call 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; +### func_check() + 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'; + ;; +### func_check() + *) + 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_check() + + + ############# + # func_pop () + # + # Retrieve the top element from the function stack. This is called + # by every return variable in each function. + # + # 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 's/^[^!]*!//')"; + exit_test; + ;; + *) + _FUNC_STACK=''; + ;; + esac; + if test _"${_DEBUG_STACKS}"_ = _yes_ + then + echo2 '<<< '"${_FUNC_STACK}"; + fi; + } # func_pop() + + + ############# + # func_push (<element>) + # + # Store another element to the function stack. This is called by + # func_check() at the beginning of each function. + # + # 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 '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_push() + + + ############# + # func_stack_dump () + # + # Print the content of the function stack. Ignore the arguments. + # + func_stack_dump() + { + diag 'call stack(): '"${_FUNC_STACK}"; + } # func_stack_dump() + +else # $_DEBUG_FUNC_CHECK is not `yes' + + func_check() { return; } + func_pop() { return; } + func_push() { return; } + func_stack_dump() { return; } + +fi; # test of $_DEBUG_FUNC_CHECK + + +######################################################################## +# 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}"; +} # get_first_essential() + + +######################################################################## +landmark '5: is_*()'; +######################################################################## + +######################################################################## +# is_dir (<name>) +# +# Test whether `name' is a readable directory. +# +# Arguments : 1 +# Return : `0' if arg1 is a directory, `1' otherwise. +# +is_dir() +{ + func_check is_dir '=' 1 "$@"; + if is_not_empty "$1" && test -d "$1" && test -r "$1" + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_dir() + + +######################################################################## +# 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_empty() + + +######################################################################## +# is_empty_file (<file_name>) +# +# Test whether <file_name> is an empty existing file. +# +# Arguments : <=1 +# Return : +# `0' if arg1 is an empty existing file +# `1' otherwise +# +is_empty_file() +{ + func_check is_empty_file '=' 1 "$@"; + if is_file "$1" + then + if test -s "$1" + then + eval "${return_no}"; + else + eval "${return_yes}"; + fi; + fi; + eval "${return_no}"; +} # is_empty_file() + + +######################################################################## +# 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_equal() + + +######################################################################## +# 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 is_empty "$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_existing() + + +######################################################################## +# 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_file() + + +######################################################################## +# is_greater_than (<integer1> <integer2>) +# +# Test whether <integer1> is greater than <integer2>. +# +# Arguments : 2 +# Return : `0' if <integer1> is a greater integer than <integer2>, +# `1' otherwise. +# +is_greater_than() +{ + func_check is_greater_than '=' 2 "$@"; + if is_integer "$1" && is_integer "$2" && test "$1" -gt "$2" + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_greater_than() + + +######################################################################## +# is_integer (<string>) +# +# Test whether `string' is an integer. +# +# Arguments : 1 +# Return : `0' if argument is an integer, `1' otherwise. +# +is_integer() +{ + func_check is_integer '=' 1 "$@"; + if is_equal "$(echo1 "$1" | sed -n ' +s/^[0-9][0-9]*$/ok/p +s/^[-+][0-9][0-9]*$/ok/p +')" 'ok' + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_integer() + + +######################################################################## +# is_not_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_not_empty_file() +{ + func_check is_not_empty_file '=' 1 "$@"; + if is_file "$1" && test -s "$1" + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_not_empty_file() + + +######################################################################## +# 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_dir() + + +######################################################################## +# 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_empty() + + +######################################################################## +# 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_equal() + + +######################################################################## +# is_not_file (<filename>) +# +# Test whether <filename> 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_file() + + +######################################################################## +# is_not_prog (<program>) +# +# Verify that <program> is not a command in $PATH. +# +# Arguments : 1, <program> can have spaces and arguments. +# +is_not_prog() +{ + func_check is_not_prog '=' 1 "$@"; + if where_is_prog "$1" >${_NULL_DEV} + then + eval "${return_no}"; + fi; + eval "${return_yes}"; +} # is_not_prog() + + +######################################################################## +# is_not_writable (<name>) +# +# Test whether <name> is 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_writable() + + +######################################################################## +# is_not_X () +# +# Test whether the script is not running in X Window by checking $DISPLAY. +# +is_not_X() +{ + func_check is_not_X '=' 0 "$@"; + if obj DISPLAY is_empty + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_not_X() + + +######################################################################## +# 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_not_yes() + + +######################################################################## +# is_prog (<name>) +# +# Determine whether <name> is a program in $PATH. +# +# Arguments : 1, <program> can have spaces and arguments. +# +is_prog() +{ + func_check is_prog '=' 1 "$@"; + if where_is_prog "$1" >${_NULL_DEV} + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_prog() + + +######################################################################## +# 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 is_empty "$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_writable() + + +######################################################################## +# is_X () +# +# Test whether the script is 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_X() + + +######################################################################## +# 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}"; +} # is_yes() + + +######################################################################## +# 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 error <code>. +# +leave() +{ + clean_up; + if test $# = 0 + then + exit "${_OK}"; + else + exit "$1"; + fi; +} # leave() + + +######################################################################## +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>...) +# +# Add one or more elements to an existing list. <list> may also be +# empty. +# +# 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 's/'"${_SQ}"'/&\\&&/g')"; + exit_test; + ;; + '') + la_element=""; + ;; + *) + la_element="${la_s}"; + ;; + esac; +### list_append() + 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_append() + + +######################################################################## +# 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 f1 -bcarg --lon=larg f2 low larg2 +# PRE_SHORT_NA="'a' 'b'" +# PRE_SHORT_ARG="'c' 'd'" +# PRE_LONG_NA="'help' 'version'" +# PRE_LONG_ARG="'longer' 'lower'" +# This will result in printing: +# '-a' '-b' '-c' 'arg' '--longer' 'larg' '--lower' 'larg2' '--' 'f1' 'f2' +# +# Use this function in the following way: +# eval set x "$(list_from_cmdline 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 "$@"; + # short options, no argument + obj_from_output lfc_short_n obj_data "$1"_SHORT_NA; + # short options, with argument + obj_from_output lfc_short_a obj_data "$1"_SHORT_ARG; + # long options, no argument + obj_from_output lfc_long_n obj_data "$1"_LONG_NA; + # long options, with argument + obj_from_output lfc_long_a obj_data "$1"_LONG_ARG; + 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; +### list_from_cmdline() + eval ${_UNSET} lfc_long_a; + eval ${_UNSET} lfc_long_n; + eval ${_UNSET} lfc_result; + eval "${return_ok}"; + fi; + + lfc_fparams=''; + lfc_result=''; + while is_greater_than "$#" 0 + do + lfc_arg="$1"; + shift; + case "${lfc_arg}" in + --) break; ;; + --*=*) + # delete leading '--'; + lfc_with_equal="$(echo1 "${lfc_arg}" | sed 's/^--//')"; + # extract option by deleting from the first '=' to the end + lfc_abbrev="$(echo1 "${lfc_with_equal}" | \ + sed 's/^\([^=]*\)=.*$/\1/')"; + obj_from_output lfc_opt \ + list_single_from_abbrev lfc_long_a "${lfc_abbrev}"; + 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 's/^[^=]*=//')"; + exit_test; + list_append lfc_result "--${lfc_opt}" "${lfc_optarg}"; + continue; + fi; +### list_from_cmdline() + ;; + --*) + # delete leading '--'; + lfc_abbrev="$(echo1 "${lfc_arg}" | sed 's/^--//')"; + if list_has lfc_long_n "${lfc_abbrev}" + then + lfc_opt="${lfc_abbrev}"; + else + obj_from_output lfc_opt \ + list_single_from_abbrev lfc_long_n "${lfc_abbrev}"; + if obj lfc_opt is_not_empty && is_not_equal "$#" 0 + then + obj_from_output a \ + list_single_from_abbrev lfc_long_a "${lfc_abbrev}"; + if obj a is_not_empty + then + error_user "The abbreviation ${lfc_arg} \ +has multiple options: --${lfc_opt} and --${a}."; + fi; + fi; + fi; # if list_has lfc_long_n "${lfc_abbrev}" + if obj lfc_opt is_not_empty + then + # long option, no argument + list_append lfc_result "--${lfc_opt}"; + continue; + fi; + obj_from_output lfc_opt \ + list_single_from_abbrev lfc_long_a "${lfc_abbrev}"; + if obj lfc_opt is_not_empty + then +### list_from_cmdline() + # long option with argument + if is_equal "$#" 0 + then + error_user "no argument for option --${lfc_opt}." + fi; + list_append lfc_result "--${lfc_opt}" "$1"; + shift; + continue; + fi; # if obj lfc_opt is_not_empty + error_user "${lfc_arg} is not an option."; + ;; + -?*) # short option (cluster) + # delete leading `-'; + lfc_rest="$(echo1 "${lfc_arg}" | sed '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 's/^\(.\).*$/\1/')"; + # remove first character from ${lfc_rest}; + lfc_rest="$(echo1 "${lfc_rest}" | sed '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 is_greater_than "$#" 0 + then +### list_from_cmdline() + 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; # if obj lfc_rest is_empty + else + error_user "unknown option -${lfc_optchar}."; + fi; # if list_has lfc_short_n "${lfc_optchar}" + done; # while obj lfc_rest is_not_empty + ;; + *) + # 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; # case "${lfc_arg}" in + done; # while is_greater_than "$#" 0 + list_append lfc_result '--'; + if obj lfc_fparams is_not_empty + then + lfc_result="${lfc_result} ${lfc_fparams}"; + fi; +### list_from_cmdline() + if is_greater_than "$#" 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_cmdline_with_minus (<pre_name_of_opt_lists> [<cmdline_arg>...]) +# +# Transform command line arguments into a normalized form with a double +# abbreviation before and after an internal `-' sign. +# +# 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 f1 -bcarg --lon=larg --h-n f2 low larg2 +# PRE_SHORT_NA="'a' 'b'" +# PRE_SHORT_ARG="'c' 'd'" +# PRE_LONG_NA="'help' 'version' 'hi-non-arg'" +# PRE_LONG_ARG="'long-arg' 'low-arg'" +# This will result in printing: +# '-a' '-b' '-c' 'arg' '--long-arg' 'larg' '--hi-non-arg' \ +# '--low-arg' 'larg2' '--' 'f1' 'f2' +# +# Use this function in the following way: +# eval set x "$(list_from_cmdline_with_minus 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: lfcwm +# +list_from_cmdline_with_minus() +{ + func_check list_from_cmdline_with_minus '>=' 1 "$@"; + # short options, no argument + obj_from_output lfcwm_short_n obj_data "$1"_SHORT_NA; + # short options, with argument + obj_from_output lfcwm_short_a obj_data "$1"_SHORT_ARG; + # long options, no argument + obj_from_output lfcwm_long_n obj_data "$1"_LONG_NA; + # long options, with argument + obj_from_output lfcwm_long_a obj_data "$1"_LONG_ARG; + if obj lfcwm_short_n is_empty + then + error 'list_from_cmdline(): no $'"$1"'_SHORT_NA options.'; + fi; + if obj lfcwm_short_a is_empty + then + error 'list_from_cmdline(): no $'"$1"'_SHORT_ARG options.'; + fi; + if obj lfcwm_long_n is_empty + then + error 'list_from_cmdline(): no $'"$1"'_LONG_NA options.'; + fi; + if obj lfcwm_long_a is_empty + then + error 'list_from_cmdline(): no $'"$1"'_LONG_ARG options.'; + fi; + shift; + + if is_equal "$#" 0 + then + echo1 "'--'"; + eval ${_UNSET} lfcwm_short_a; + eval ${_UNSET} lfcwm_short_n; +### list_from_cmdline_with_minus() + eval ${_UNSET} lfcwm_long_a; + eval ${_UNSET} lfcwm_long_n; + eval "${return_ok}"; + fi; + obj_from_output lfcwm_long_both lists_combine lfcwm_long_a lfcwm_long_n; + lfcwm_fparams=''; + lfcwm_result=''; + while is_greater_than "$#" 0 # command line arguments + do + lfcwm_arg="$1"; + shift; + lfcwm_optarg=''; + case "${lfcwm_arg}" in + --) + break; + ;; + --*=*) + # delete leading '--'; + lfcwm_with_equal="$(echo1 "${lfcwm_arg}" | sed 's/^--//')"; + # extract option by deleting from the first '=' to the end + lfcwm_abbrev="$(echo1 "${lfcwm_with_equal}" | \ + sed 's/^\([^=]*\)=.*$/\1/')"; + # extract option argument by deleting up to the first '=' + lfcwm_optarg="$(echo1 "${lfcwm_with_equal}" | \ + sed 's/^[^=]*=\(.*\)$/\1/')"; +### list_from_cmdline_with_minus() + if list_has lfcwm_long_a "${lfcwm_abbrev}" + then + lfcwm_opt="${lfcwm_abbrev}"; + else + obj_from_output lfcwm_opt \ + _search_abbrev lfcwm_long_a "${lfcwm_abbrev}"; + fi; + list_append lfcwm_result "--${lfcwm_opt}" "${lfcwm_optarg}"; + continue; + ;; + --*) + # delete leading '--'; + lfcwm_abbrev="$(echo1 "${lfcwm_arg}" | sed 's/^--//')"; + if list_has lfcwm_long_both "${lfcwm_abbrev}" + then + lfcwm_opt="${lfcwm_abbrev}"; + else + obj_from_output lfcwm_opt \ + _search_abbrev lfcwm_long_both "${lfcwm_abbrev}"; + fi; +### list_from_cmdline_with_minus() + if list_has lfcwm_long_a "${lfcwm_opt}" + then + if is_equal "$#" 0 + then + error_user "Option ${lfcwm_opt} needs an argument."; + fi; + lfcwm_optarg="$1"; + shift; + list_append lfcwm_result "--${lfcwm_opt}" "${lfcwm_optarg}"; + else + list_append lfcwm_result "--${lfcwm_opt}"; + fi; + continue; + ;; + -?*) # short option (cluster) + # delete leading '-'; + lfcwm_rest="$(echo1 "${lfcwm_arg}" | sed 's/^-//')"; + while obj lfcwm_rest is_not_empty + do + # get next short option from cluster (first char of $lfcwm_rest) + lfcwm_optchar="$(echo1 "${lfcwm_rest}" | sed 's/^\(.\).*$/\1/')"; + # remove first character from ${lfcwm_rest}; + lfcwm_rest="$(echo1 "${lfcwm_rest}" | sed 's/^.//')"; + if list_has lfcwm_short_n "${lfcwm_optchar}" + then + list_append lfcwm_result "-${lfcwm_optchar}"; + continue; + elif list_has lfcwm_short_a "${lfcwm_optchar}" + then + if obj lfcwm_rest is_empty + then + if is_greater_than "$#" 0 + then +### list_from_cmdline_with_minus() + list_append lfcwm_result "-${lfcwm_optchar}" "$1"; + shift; + continue; + else + error_user "no argument for option -${lfcwm_optchar}."; + fi; + else # rest is the argument + list_append lfcwm_result "-${lfcwm_optchar}" "${lfcwm_rest}"; + lfcwm_rest=''; + continue; + fi; # if obj lfcwm_rest is_empty + else + error_user "unknown option -${lfcwm_optchar}."; + fi; # if list_has lfcwm_short_n "${lfcwm_optchar}" + done; # while obj lfcwm_rest is_not_empty + ;; + *) + # Here, $lfcwm_arg is not an option, so a file parameter. + list_append lfcwm_fparams "${lfcwm_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 lfcwm_result '--'; + if obj lfcwm_fparams is_not_empty + then + lfcwm_result="${lfcwm_result} ${lfcwm_fparams}"; + fi; +### list_from_cmdline_with_minus() + if is_greater_than "$#" 0 + then + list_append lfcwm_result "$@"; + fi; + obj lfcwm_result echo1; + eval ${_UNSET} lfcwm_abbrev; + eval ${_UNSET} lfcwm_fparams; + eval ${_UNSET} lfcwm_short_a; + eval ${_UNSET} lfcwm_short_n; + eval ${_UNSET} lfcwm_long_a; + eval ${_UNSET} lfcwm_long_both; + eval ${_UNSET} lfcwm_long_n; + eval ${_UNSET} lfcwm_result; + eval ${_UNSET} lfcwm_arg; + eval ${_UNSET} lfcwm_opt; + eval ${_UNSET} lfcwm_optarg; + eval ${_UNSET} lfcwm_optchar; + eval ${_UNSET} lfcwm_with_equal; + eval ${_UNSET} lfcwm_rest; + eval "${return_ok}"; +} # list_from_cmdline_with_minus() + + +# _search_abbrev (<list> <abbrev>) +# +# Check whether <list> has an element constructed from the abbreviation +# <abbrev>. All `-' in <abbrev> are replaced by `-*'. This construction +# is searched first with `<construction>[^-]*'. If there is more than a +# single element an error is created. If none is found `<construction>*' +# is searched. Again an error is created for several results. +# This function was constructed from the former function +# list_single_from_abbrev(). +# +# This is a local function of list_from_cmdline_with_minus(). +# +# Arguments: 2 +# <list>: a variable name for a list of single-quoted elements +# <abbrev>: some sequence of characters. +# +# Output: the found element (always not empty), error when none found. +# +# Variable prefix: _sa +# +_search_abbrev() +{ + func_check _search_abbrev '=' 2 "$@"; + eval _sa_list='"${'$1'}"'; + if obj _sa_list is_empty + then + error "_search_abbrev(): list is empty."; + fi; + + _sa_abbrev="$2"; + if obj _sa_abbrev is_empty + then + error "_search_abbrev(): abbreviation argument is empty."; + fi; + + _sa_case="$(echo1 "${_sa_abbrev}" | sed 's/-/\*-/g')"; + _sa_opt=''; + case " ${_sa_list}" in + *\ \'${_sa_case}*) # list has the abbreviation + _sa_m1=''; + _sa_m2=''; + _sa_nm=''; + eval set x "${_sa_list}"; + shift; + for i # over the option list + do + _sa_i="$i"; +### _search_abbrev() of list_from_cmdline_with_minus() + case "${_sa_i}" in + ${_sa_case}*-*) + if obj _sa_m1 is_empty + then + _sa_m1="${_sa_i}"; + continue; + fi; + _sa_m2="${_sa_i}"; + continue; + ;; + ${_sa_case}*) + if obj _sa_nm is_empty + then + _sa_nm="${_sa_i}"; + continue; + fi; + error_user "The abbreviation --${_sa_abbrev} has multiple options "\ +"--${_sa_nm} and --${_sa_i}."; + ;; + esac; + done; + if obj _sa_nm is_empty + then + if obj _sa_m2 is_not_empty + then + error_user "The abbreviation --${_sa_abbrev} has multiple options "\ +"--${_sa_m1} and --${_sa_m2}."; + fi; +### _search_abbrev() of list_from_cmdline_with_minus() + if obj _sa_m1 is_not_empty + then + _sa_opt="${_sa_m1}"; + fi; + else + _sa_opt="${_sa_nm}"; + fi; + ;; + esac; + if obj _sa_opt is_empty + then + error_user "--${_sa_abbrev} is not an option."; + fi; + obj _sa_opt echo1; + eval "${_UNSET}" _sa_abbrev; + eval "${_UNSET}" _sa_case; + eval "${_UNSET}" _sa_i; + eval "${_UNSET}" _sa_list; + eval "${_UNSET}" _sa_m1; + eval "${_UNSET}" _sa_m2; + eval "${_UNSET}" _sa_nm; + eval "${_UNSET}" _sa_opt; + eval "${return_ok}"; +} # _search_abbrev() of list_from_cmdline_with_minus() + + +######################################################################## +# list_from_file (<list_name> <file_name>) +# +# Extrect the lines from <file_name> and store them as elements to list +# <list_name>. +# +# Arguments: 2 +# <list_name>: a variable name for output, a list of single-quoted elts +# <file_name>: the name of an existing file +# +# Variable prefix: lff +# +list_from_file() +{ + func_check list_from_file '=' 2 "$@"; + if is_not_file "$2" + then + eval "${return_bad}"; + fi; + lff_n="$(wc -l "$2" | eval sed "'s/^[ ${_TAB}]*\([0-9]\+\).*$/\1/'")"; + eval "$1"="''"; + if obj lff_n is_equal 0 + then + eval "${return_good}"; + fi; + lff_i=0; + while obj lff_i is_not_equal "${lff_n}" + do + lff_i="$(expr "${lff_i}" + 1)"; + list_append "$1" "$(eval sed -n "'${lff_i}p +${lff_i}q'" "'$2'")"; + done; + eval "${_UNSET}" lff_i; + eval "${_UNSET}" lff_n; + eval "${return_good}"; +} # list_from_file() + + +######################################################################## +# list_from_split (<string> <separator_char>) +# +# Split <string> by <separator_char> into a list, omitting the separator. +# +# Arguments: 2: a <string> that is to be split into parts divided by +# character <separator_char> +# Output: the resulting list string +# +# Variable prefix: lfs +# +list_from_split() +{ + func_check list_from_split = 2 "$@"; + if is_empty "$1" + then + eval "${return_ok}"; + fi; + case "$2" in + ?) + lfs_splitter="$2"; + ;; + '\:') + lfs_splitter=':'; + ;; + *) + error "list_from_split(): split argument $2 must be a single character."; + ;; + esac; + lfs_list=''; + lfs_rest="$1"; + while : + do + case "${lfs_rest}" in + *${lfs_splitter}*) + case "${lfs_splitter}" in + /) + lfs_elt="$(echo1 ${lfs_rest} | sed \ + 's|^\([^'"${lfs_splitter}"']*\)'"${lfs_splitter}"'.*|\1|')"; + lfs_rest="$(echo1 ${lfs_rest} | sed \ + 's|^[^'"${lfs_splitter}"']*'"${lfs_splitter}"'\(.*\)$|\1|')"; + ;; + *) +### list_from_split() + lfs_elt="$(echo1 ${lfs_rest} | sed \ + 's/^\([^'"${lfs_splitter}"']*\)'"${lfs_splitter}"'.*/\1/')"; + lfs_rest="$(echo1 ${lfs_rest} | sed \ + 's/^[^'"${lfs_splitter}"']*'"${lfs_splitter}"'\(.*\)$/\1/')"; + ;; + esac; + list_append lfs_list "${lfs_elt}" + continue; + ;; + *) + list_append lfs_list "${lfs_rest}" + break + ;; + esac; + done + echo1 "${lfs_list}"; + + eval ${_UNSET} lfs_elt; + eval ${_UNSET} lfs_list; + eval ${_UNSET} lfs_rest; + eval ${_UNSET} lfs_splitter; + eval "${return_ok}"; +} # list_from_split() + + +######################################################################## +# list_has (<list-name> <element>) +# +# Test whether the list <list-name> has the element <element>. +# +# Arguments: 2 +# <list_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() + + +######################################################################## +# list_has_abbrev (<list_var> <abbrev>) +# +# Test whether the list of <list_var> has an element starting with +# <abbrev>. +# +# Arguments: 2 +# <list_var>: 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 's/'"${_SQ}"'$//')"; + ;; + *) + 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_abbrev() + + +######################################################################## +# 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_has_not() + + +######################################################################## +# list_single_from_abbrev (<list-var> <abbrev>) +# +# Check whether the list has an element starting with <abbrev>. If +# there are more than a single element an error is raised. +# +# Arguments: 2 +# <list-var>: 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; +### list_single_from_abbrev() + 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; +} # list_single_from_abbrev() + + +######################################################################## +# list_uniq (<list>) +# +# Generate a list with only unique elements. +# +# Output: the corrected list +# +# Variable prefix: lu +# +list_uniq() +{ + func_check list_uniq '=' 1 "$@"; + if is_empty "$1" + then + eval "${return_ok}"; + fi; + eval a='"${'"$1"'}"'; + if obj a is_empty + then + eval "${return_ok}"; + fi; + eval set x "$a"; + shift; + lu_list=''; + for i + do + lu_i="$i"; + if list_has lu_list "${lu_i}" + then + continue; + else + list_append lu_list ${lu_i}; + fi; + done; + obj lu_list echo1; + eval "${_UNSET}" lu_i; + eval "${_UNSET}" lu_list; + eval "${return_ok}"; +} # list_uniq() + + +######################################################################## +# lists_combine (<list1> <list2> ...) +# +# Combine several lists to a single list. All arguments are list names. +# +# Output: the combined list +# +# Variable prefix: lc +# +lists_combine() +{ + func_check lists_combine '>=' 2 "$@"; + lc_list=''; + for i + do + eval lc_arg='"${'"$i"'}"'; + case "${lc_arg}" in + '') :; ;; + "'"*"'") + if obj lc_list is_empty + then + lc_list="${lc_arg}"; + else + lc_list="${lc_list} ${lc_arg}"; + fi; + ;; + *) + error 'lists_combine(): $'"$i"' is not a list.'; + ;; + esac; + done; + obj lc_list echo1; + eval "${_UNSET}" lc_arg; + eval "${_UNSET}" lc_list; + eval "${return_ok}"; +} # lists_combine() + + +######################################################################## +landmark '7: man_*()'; +######################################################################## + +######################################################################## +# Information on the search of man pages in groffer + +# The search of man pages is based on a set of directories. That +# starts with the so-called man path. This is determined in function +# man_setup() either by the command-line option --manpath, by $MANOPT, +# or by $MANPATH. There is also a program `manpath'. If all of this +# does not work a man path is created from $PATH with function +# manpath_set_from_path(). We now have a set of existing directories +# for the search of man pages; usually they end with `/man'. + +# The directory set of the man path can be changed in 2 ways. If +# operating system names are given in $SYSTEM or by --systems on the +# command-line all man path directory will be appended by these names. +# The appended system names replace the original man path; but if no +# system name is set, the original man path is kept. In `groffer', +# this is done by the function manpath_add_lang_sys() in man_setup(). + +# The next addition for directories is the language. It is specified +# by --locale or by one of the environment variables $LC_ALL, +# $LC_MESSAGES, and $LANG. The language name of `C' or `POSIX' means +# the return to the default language (usually English); this deletes +# former language specifications. The language name and its +# abbreviation with 2 characters is appended to the man page +# directories. But these new arising directories are added to the man +# page, they do not replace it such as the system names did. This is +# done by function manpath_add_lang_sys() in man_setup() as well. + +# Now we have the basic set of directories for the search of man pages +# for given filespec arguments. The real directories with the man +# page source files are gotten by appending `man<section>' to each +# directory, where section is a single character of the form +# `[1-9on]'. + +# There you find files named according to the form +# <name>.<section>[<extension>][<compression>], where `[]' means +# optional this time. <name> is the name of the man page; <section> +# is the single character from the last paragraphe; the optional +# <extension> consists of some letters denoting special aspects for +# the section; and the optional <compression> is something like `.gz', +# `.Z', or `.bz2', meaning that the file is compressed. + +# If name, section. and extension are specified on the command-line +# the file of the form <name>.<section><extension> with or without +# <compression> are handled. The first one found according to the +# directory set for the section is shown. + +# If just name and section are specified on the command-line then +# first <name>.<section> with or without <compression> are searched. +# If no matching file was found, <name>.<section><extension> with or +# without <compression> are searched for all possible extensions. + +# If only name is specified on the command-line then the section +# directories are searched by and by, starting with section `1', until +# a file is matched. + +# The function man_is_man() determines all suitable man files for a +# command-line argument, while man_get() searches the single matching +# file for display. + + +######################################################################## +# man_get (<man-name> [<section> [<extension>]]) +# +# Write a man page to the temporary file. +# +# Globals in: $_TMP_MANSPEC, $_MAN_SEC_CHARS, $_MAN_EXT, $_MAN_ALL +# +# Arguments: 1, 2, or 3 +# +# Variable prefix: mg +# +man_get() +{ + func_check man_get '>=' 1 "$@"; + if obj _TMP_MANSPEC is_empty + then + error 'man_get(): man_is_man() must be run first on '"$*".; + fi; + mg_name="$1"; + mg_sec="$2"; + if is_empty "$2" + then + mg_sec="${_MAN_SEC_CHARS}"; # take care it is not a single section + fi; + mg_ext="$3"; + if is_empty "$3" + then + mg_ext="${_MAN_EXT}"; + fi; + if obj _TMP_MANSPEC is_not_equal "${_TMP_DIR}/,man:$1:${mg_sec}${mg_ext}" + then + error 'man_get(): $_TMP_MANSPEC does not suit to the arguments '"$*".; + fi; +### man_get() + + if obj _MAN_ALL is_yes + then + list_from_file mg_list "${_TMP_MANSPEC}"; + eval set x ${mg_list}; + shift; + mg_ok='no'; + mg_list=''; + for f + do + mg_f="$f"; + if list_has mg_list "${mg_f}" + then + continue; + else + list_append mg_list "${mg_f}"; + fi; +### man_get() + if obj mg_f is_file + then + to_tmp "${mg_f}" && mg_ok='yes'; + fi; + done; + if obj mg_ok is_yes + then + register_title man:"${mg_name}"; + fi; + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_sec; + eval "${return_ok}"; + else # $_MAN_ALL is not 'yes' + if is_empty "$2" + then # no section from command line + if obj _MAN_SEC_LIST is_empty + then + m="${_MAN_AUTO_SEC_LIST}"; # list of all sections + else + m="${_MAN_SEC_LIST}"; # from --sections + fi; +### man_get() + for s in $(eval set x $m; shift; echo1 "$@") + do + mg_s="$s"; + list_from_file mg_list "${_TMP_MANSPEC}"; + eval set x ${mg_list}; + shift; + if obj mg_ext is_empty + then + for f + do + mg_f="$f"; + case "${mg_f}" in +*/man"${mg_s}"/"${mg_name}"."${mg_s}"|*/man"${mg_s}"/"${mg_name}"."${mg_s}".*) + if obj mg_f is_file + then + to_tmp "${mg_f}" && register_title "${mg_name}(${mg_s})"; + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_s; + eval ${_UNSET} mg_sec; + eval "${return_ok}"; + fi; + ;; + esac; # "$mg_f" + done; # for f + fi; # mg_ext is_empty +### man_get() + for f + do + mg_f="$f"; + case "${mg_f}" in + */man"${mg_s}"/"${mg_name}"."${mg_s}""${mg_ext}"*) + if obj mg_f is_file + then + to_tmp "${mg_f}" && register_title "${mg_name}(${mg_s})"; + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_s; + eval ${_UNSET} mg_sec; + eval "${return_ok}"; + fi; + ;; + esac; # "$mg_f" + done; # for f + done; # for s + else # $mg_sec is not empty, do with section + list_from_file mg_list "${_TMP_MANSPEC}"; + eval set x ${mg_list}; + shift; + if obj mg_ext is_empty + then + for f + do + mg_f="$f"; +### man_get() + case "${mg_f}" in +*/man"${mg_sec}"/"${mg_name}"."${mg_sec}"|\ +*/man"${mg_sec}"/"${mg_name}"."${mg_sec}".*) + if obj mg_f is_file + then + obj mg_f to_tmp && \ + register_title "${mg_name}(${mg_sec})"; + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_s; + eval ${_UNSET} mg_sec; + eval "${return_ok}"; + fi; + ;; + esac; + done; # for f + for f + do + mg_f="$f"; +### man_get() + case "${mg_f}" in +*/man"${mg_sec}"/"${mg_name}"."${mg_sec}"*) + if obj mg_f is_file + then + obj mg_f to_tmp && \ + register_title "${mg_name}(${mg_sec})"; + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_s; + eval ${_UNSET} mg_sec; + eval "${return_ok}"; + fi; + ;; + esac; + done; # for f + else # mg_ext is not empty + for f + do + mg_f="$f"; +### man_get() + case "${mg_f}" in +*/man"${mg_sec}"/"${mg_name}"."${mg_sec}""${mg_ext}"|\ +*/man"${mg_sec}"/"${mg_name}"."${mg_sec}""${mg_ext}".*) + if obj mg_f is_file + then + obj mg_f to_tmp && \ + register_title "${mg_name}(${mg_sec}${mg_ext})"; + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_s; + eval ${_UNSET} mg_sec; + eval "${return_ok}"; + fi; + ;; + esac; + done; # for f + for f + do + mg_f="$f"; +### man_get() + case "${mg_f}" in + */man"${mg_sec}"/"${mg_name}"."${mg_sec}""${mg_ext}"*) + if obj mg_f is_file + then + obj mg_f to_tmp && \ + register_title "${mg_name}(${mg_sec}${mg_ext})"; + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_s; + eval ${_UNSET} mg_sec; + eval "${return_ok}"; + fi; + ;; + esac; + done; # for f + fi; + fi; # $mg_sec + fi; # $_MAN_ALL + + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_sec; + eval ${_UNSET} mg_s; + eval "${return_ok}"; +} # man_get() + + +######################################################################## +# man_is_man (<man-name> [<section> [<extension>]]) +# +# Test whether <man-name> exists as man page. +# +# Globals: in: $_TMP_MAN, $_MAN_SEC_CHARS, $_TMP_DIR, $_MAN_EXT, +# $_MAN_AUTO_SEC_CHARS +# out: $_TMP_MANSPEC +# +# Arguments: 1, 2, or 3 +# +# Variable prefix: mim +# +man_is_man() +{ + func_check man_is_man '>=' 1 "$@"; + if is_empty "$1" + then + _TMP_MANSPEC=''; + eval "${return_no}"; + fi; + if obj _TMP_DIR is_empty + then + error 'man_is_man(): main_init() must be run first.'; + fi; + if obj _MAN_IS_SETUP is_not_yes + then + error 'man_is_man(): man_setup() must be run first.'; + fi; + mim_sec="$2"; + if is_empty "$2" + then + mim_sec="${_MAN_SEC_CHARS}"; + fi; + if is_empty "$3" + then + mim_ext="${_MAN_EXT}"; + else + mim_ext="$3"; + fi; + _TMP_MANSPEC="${_TMP_DIR}/,man:$1:${mim_sec}${mim_ext}"; +### man_is_man() + if obj _TMP_MANSPEC is_not_file + then + if obj mim_sec is_empty + then + m="${_MAN_AUTO_SEC_CHARS}"; + eval grep "'/man$m/$1\.$m${mim_ext}'" \ + "${_TMP_MAN}" > "${_TMP_MANSPEC}"; + else + eval grep "'/man${mim_sec}/$1\.${mim_sec}${mim_ext}'" \ + "${_TMP_MAN}" > "${_TMP_MANSPEC}"; + fi; + fi; + eval ${_UNSET} mim_ext; + eval ${_UNSET} mim_sec; + if obj _TMP_MANSPEC is_empty_file + then + rm_file_with_debug "${_TMP_MANSPEC}"; + eval "${return_no}"; + else + eval "${return_yes}"; + fi; +} # man_is_man() + + +######################################################################## +# man_setup () +# +# Setup the variables $_MAN_* needed for man page searching. +# +# Globals: +# in: $_OPT_*, $_MANOPT_*, $LANG, $LC_MESSAGES, $LC_ALL, +# $MANPATH, $MANSEC, $PAGER, $SYSTEM, $MANOPT. +# out: $_MAN_PATH, $_MAN_LANG, $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2, +# $_MAN_SEC, $_MAN_ALL, $_TMP_MAN +# 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, $MANSEC, $PAGER, $SYSTEM; overridden by +# $MANOPT; overridden by +# the groffer command line options. +# +# $MANROFFSEQ is ignored because grog determines the preprocessors. +# +# Variable prefix: ms +# +man_setup() +{ + func_check 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 + obj_from_output ms_path \ + get_first_essential "${_OPT_MANPATH}" "${_MANOPT_PATH}" "${MANPATH}"; + if obj ms_path is_empty && is_prog 'manpath' + then + obj_from_output ms_path manpath 2>${_NULL_DEV}; # not always available + fi; + if obj ms_path is_empty + then + manpath_set_from_path; + else + obj_from_output _MAN_PATH path_list "${ms_path}"; + fi; + if obj _MAN_PATH is_empty + then + _MAN_ENABLE="no"; + echo2 "man_setup(): man path is empty"; + eval ${_UNSET} ms_path; + eval "${return_ok}"; + fi; + obj_from_output _MAN_PATH list_uniq _MAN_PATH; +### man_setup() + + if obj _MAN_ALL is_not_yes + then + if obj _OPT_ALL is_yes || obj _MANOPT_ALL is_yes + then + _MAN_ALL='yes'; + else + _MAN_ALL='no'; + fi; + fi; + + ms_sys="$(get_first_essential \ + "${_OPT_SYSTEMS}" "${_MANOPT_SYS}" "${SYSTEM}")"; + if obj ms_sys is_not_empty + then + obj_from_output _MAN_SYS list_from_split "${ms_sys}" ','; + fi; + + obj_from_output ms_lang get_first_essential \ + "${_OPT_LANG}" "${LC_ALL}" "${LC_MESSAGES}" "${LANG}"; + case "${ms_lang}" in + C|POSIX) + _MAN_LANG=""; + _MAN_LANG2=""; + ;; + ?) + _MAN_LANG="${ms_lang}"; + _MAN_LANG2=""; + ;; + ??) + _MAN_LANG="${ms_lang}"; + _MAN_LANG2="${ms_lang}"; + ;; +### man_setup() + *) + _MAN_LANG="${ms_lang}"; + # get first two characters of $ms_lang + _MAN_LANG2="$(echo1 "${ms_lang}" | sed 's/^\(..\).*$/\1/')"; + exit_test; + ;; + esac; + # from now on, use only $_MAN_LANG*, forget about $_OPT_LANG, $LC_*. + + manpath_add_lang_sys; + obj_from_output _MAN_PATH list_uniq _MAN_PATH; + + obj_from_output _MAN_SEC get_first_essential \ + "${_OPT_SECTIONS}" "${_MANOPT_SEC}" "${MANSEC}"; + _MAN_SEC_LIST=""; + _MAN_SEC_CHARS=""; + case "${_MAN_SEC}" in + *:*) + eval set x "$(list_from_split "${_MAN_SEC}" :)"; + shift; + for s + do + if list_has _MAN_AUTO_SEC_LIST "$s" + then + list_append _MAN_SEC_LIST "$s"; + _MAN_SEC_CHARS="${_MAN_SEC_CHARS}$s"; + fi; + done + if obj _MAN_SEC_CHARS is_not_empty + then + _MAN_SEC_CHARS="[${_MAN_SEC_CHARS}]"; + fi; + ;; + *) + if list_has _MAN_AUTO_SEC_LIST "${_MAN_SEC}" + then + list_append _MAN_SEC_LIST "${_MAN_SEC}"; + _MAN_SEC_CHARS="[${_MAN_SEC}]"; + fi; + ;; + esac; + +### man_setup() + obj_from_output _MAN_EXT get_first_essential \ + "${_OPT_EXTENSION}" "${_MANOPT_EXTENSION}" "${EXTENSION}"; + + _TMP_MAN="$(tmp_create man)"; + + eval set x "${_MAN_PATH}"; + shift; + if is_not_equal "$#" 0 + then + for i + do + for j in "$i"/man* + do + if obj j is_dir + then + find "$j" >>"${_TMP_MAN}"; + fi; + done + done; + fi; + + eval ${_UNSET} ms_lang; + eval ${_UNSET} ms_list; + eval ${_UNSET} ms_path; + eval ${_UNSET} ms_sys; + 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: a list of names of operating systems. +# $_MAN_LANG and $_MAN_LANG2: each a single name +# in/out: $_MAN_PATH: list of directories which shall have the `man?' +# subdirectories. +# +# 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; + if obj _MAN_SYS is_empty + then + mals_mp="${_MAN_PATH}"; + else + mals_mp=''; + eval set x "${_MAN_SYS}"; + shift; + for s + do + _manpath_add_sys "$s"; + done; + fi; + + if obj mals_mp is_not_empty + then + mals_lang_path=''; + if is_equal "$_MAN_LANG" "$_MAN_LANG2" + then + mals_man_lang2=''; + else + mals_man_lang2="${_MAN_LANG2}"; + fi; + for i in "${_MAN_LANG}" "${mals_man_lang2}" + do + if obj i is_empty + then + continue; + fi; +### manpath_add_lang_sys() + mals_lang="$i"; + eval set x "${mals_mp}"; + shift; + for p + do + obj_from_output mals_dir dir_name_append "${p}" "${mals_lang}"; + if obj mals_dir is_dir + then + list_append mals_lang_path "${mals_dir}"; + fi; + done; + done; + obj_from_output mals_mp lists_combine mals_lang_path mals_mp; + fi; + + _MAN_PATH="${mals_mp}"; + eval ${_UNSET} mals_dir; + eval ${_UNSET} mals_lang; + eval ${_UNSET} mals_lang_path; + eval ${_UNSET} mals_man_lang2; + eval ${_UNSET} mals_mp; + eval "${return_ok}"; +} # manpath_add_lang_sys() + + +# _manpath_add_sys (<system>) +# +# Append the existing subdirectories <system> of man path directories to +# the list $mals_mp. +# +# Local function to manpath_add_lang_sys(). +# +# Argument: 1, a operating system name (for appending to a man path +# directory) +# +# Globals in: $_MAN_PATH +# Globals in/out: $mals_mp +# +# Variable prefix: _mas +# +_manpath_add_sys() +{ + func_check _manpath_add_sys '=' 1 "$@"; + case "$1" in + '') + :; + ;; + man) + obj_from_output mals_mp lists_combine mals_mp _MAN_PATH; + ;; + *) + _mas_sys="$1"; + eval set x "${_MAN_PATH}"; + shift; + for p + do + obj_from_output _mas_dir dir_name_append "${p}" "${_mas_sys}"; + if obj _mas_dir is_dir + then + list_append mals_mp "${_mas_dir}"; + fi; + done; + ;; + esac; + eval ${_UNSET} _mas_dir; + eval ${_UNSET} _mas_sys; + eval "${return_ok}"; +} # _manpath_add_sys() of 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 + # delete the final `/bin' part + p="$(echo1 "${PATH}" | sed 's|//*bin/*:|:|g')"; + obj_from_output msfp_list path_list "$p"; + # append some default directories + for b in /usr/local /usr/local /usr /usr \ + /usr/X11R6 /usr/openwin \ + /opt /opt/gnome /opt/kde + do + msfp_base="$b"; + if list_has_not msfp_list "${msfp_base}" && obj msfp_base is_dir + then + list_append msfp_list "${msfp_base}"; + fi; + done; + eval set x "${msfp_list}"; + shift; + for d + do + # including empty for former `/bin'. + msfp_base="$d"; + for e in /share/man /share/MAN /man /MAN + do + msfp_mandir="${msfp_base}$e"; + if obj msfp_mandir is_dir + then + list_append msfp_manpath "${msfp_mandir}"; + fi; + done; + done; + fi; + + _MAN_PATH="${msfp_manpath}"; + eval ${_UNSET} msfp_base; + eval ${_UNSET} msfp_list; + 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 name 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_data '=' 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_data() + + +######################################################################## +# obj_from_output (<object> <call_name> <arg>...) +# +# Run '$<object>="$(<call_name> <arg>...)"' to set the result of a +# function call to a global variable. Variables are not stored. +# +# 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 "obj_from_output(): variable name is empty."; + fi; + if is_empty "$2" + then + error "obj_from_output(): function name is empty." + fi; + ofo_result_name="$1"; + shift; + ofo_return=0; + if is_equal "$#" 0 + then + eval "${ofo_result_name}"'=""'; + else + ofo_list=''; + for i + do + list_append ofo_list "$i"; + done; + eval "${ofo_result_name}"'="$('"${ofo_list}"')"'; + ofo_return="$?"; + exit_test; + fi; + r="${ofo_return}"; + eval ${_UNSET} ofo_list; + eval ${_UNSET} ofo_return; + eval ${_UNSET} ofo_result_name; + eval "${return_var} $r"; +} # obj_from_output() + + +######################################################################## +# 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}"; +} # obj_set() + + +######################################################################## +# 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 ' +s/^:*// +s/:::*/:/g +s/:*$// +'; + eval "${return_ok}"; +} # path_chop() + + +######################################################################## +# 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_list "${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}:$(dir_name_chop "${pc_i}")"; + exit_test; + ;; + *) + pc_res="${pc_res}:${pc_i}"; + ;; + esac; + fi; + done; + path_chop "${pc_res}"; + eval ${_UNSET} pc_arg; + eval ${_UNSET} pc_i; + eval ${_UNSET} pc_res; + eval "${return_ok}"; +} # path_clean() + + +######################################################################## +# path_contains (<path> <dir>) +# +# Test whether <dir> is contained in <path>, a list separated by `:'. +# +# Arguments : 2 +# 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_contains() + + +######################################################################## +# path_not_contains (<path> <dir>) +# +# Test whether <dir> is not contained in colon separated <path>. +# +# Arguments : 2 +# +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_not_contains() + + +######################################################################## +# path_list (<path>) +# +# From a `:' separated path generate a list with unique elements. +# +# Arguments: 1: a colon-separated path +# Output: the resulting list, process it with `eval set' +# +# Variable prefix: pl +# +path_list() +{ + func_check path_list = 1 "$@"; + eval set x "$(list_from_split "$1" '\:')"; + shift; + pl_list=''; + for e + do + pl_elt="$e"; + if list_has pl_list "${pl_elt}" + then + continue; + else + list_append pl_list "${pl_elt}"; + fi; + done; + obj pl_list echo1; + eval ${_UNSET} pl_elt; + eval ${_UNSET} pl_list; + eval "${return_ok}"; +} # path_list() + + +######################################################################## +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 "$1"; + exit_test; + fi; + eval "${return_ok}"; +} # register_file() + + +######################################################################## +# register_title (<filespec>) +# +# Create title element from <filespec> and append to $_REG_TITLE_LIST. +# Basename is created. +# +# Globals: $_REG_TITLE_LIST (rw) +# +# Variable prefix: rt +# +register_title() +{ + func_check register_title '=' 1 "$@"; + if is_empty "$1" + then + eval "${return_ok}"; + fi; + + if obj _DEBUG_PRINT_FILENAMES is_yes + then + if is_equal "$1" 'stdin' + then + echo2 "file: standard input"; + else + if obj _FILESPEC_IS_MAN is_yes + then + echo2 "file title: $1"; + else + echo2 "file: $1"; + fi; + fi; + fi; + + case "${_REG_TITLE_LIST}" in + *\ *\ *\ *) + eval "${return_ok}"; + ;; + esac; + + # remove directory part + obj_from_output rt_title base_name "$1"; + # replace space characters by `_' + rt_title="$(echo1 "${rt_title}" | sed 's/[ ]/_/g')"; + # remove extension `.bz2' + rt_title="$(echo1 "${rt_title}" | sed 's/\.bz2$//')"; + # remove extension `.gz' + rt_title="$(echo1 "${rt_title}" | sed 's/\.gz$//')"; + # remove extension `.Z' + rt_title="$(echo1 "${rt_title}" | sed 's/\.Z$//')"; + + if obj rt_title is_empty + then + eval ${_UNSET} rt_title; + eval "${return_ok}"; + fi; + list_append _REG_TITLE_LIST "${rt_title}"; + 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. +# +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() + + +######################################################################## +# 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_file_with_debug() + + +######################################################################## +# rm_tree (<dir_name>) +# +# Remove a file or a complete directory tree. +# +# 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; +} # rm_tree() + + +######################################################################## +# 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}"; + } # save_stdin() +else # no compression + save_stdin() + { + func_check save_stdin '=' 0 "$@"; + cat >"${_TMP_STDIN}"; + eval "${return_ok}"; + } # save_stdin() +fi; + + +######################################################################## +# special_filespec () +# +# Handle special modes like whatis and apropos. Run their filespec +# functions if suitable. +# +# Globals: in: $_OPT_APROPOS, $_OPT_WHATIS, $_SPECIAL_SETUP +# out: $_SPECIAL_FILESPEC (internal) +# +special_filespec() +{ + func_check special_filespec '=' 0 "$@"; + if obj _OPT_APROPOS is_not_yes && obj _OPT_WHATIS is_not_yes + then + eval "${return_bad}"; + fi; + if obj _OPT_APROPOS is_yes && obj _OPT_WHATIS is_yes + then + error \ + 'special_filespec(): $_OPT_APROPOS and $_OPT_WHATIS are both "yes"'; + fi; + if obj _SPECIAL_SETUP is_not_yes + then + error 'special_filespec(): setup for apropos or whatis must be run first.'; + fi; + if apropos_filespec || whatis_filespec; + then + eval "${return_ok}"; + else + eval "${return_bad}"; + fi; +} # special_filespec() + + +######################################################################## +# special_setup () +# +# Handle special modes like whatis and apropos. Run their setup +# functions if suitable. +# +special_setup() +{ + func_check special_setup '=' 0 "$@"; + if obj _OPT_APROPOS is_yes && obj _OPT_WHATIS is_yes + then + error \ + 'special_setup(): $_OPT_APROPOS and $_OPT_WHATIS are both "yes"'; + fi; + if apropos_setup || whatis_setup + then + eval "${return_ok}"; + else + eval "${return_bad}"; + fi; +} # special_setup() + + +######################################################################## +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_contains() + + +######################################################################## +# 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}"; +} # string_not_contains() + + +######################################################################## +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_cat() + + +######################################################################## +# tmp_create (<suffix>?) +# +# Create temporary file. The generated name is `,' followed by +# <suffix>. +# +# Argument: 0 or 1 +# +# Globals: $_TMP_DIR +# +# Output : name of created file +# +# Variable prefix: tc +# +tmp_create() +{ + func_check tmp_create '<=' 1 "$@"; + if obj _TMP_DIR is_empty || obj _TMP_DIR is_not_dir + then + error 'tmp_create(): there is no temporary directory.'; + else + # the output file does not have `,' as first character, so these are + # different names from the output file. + tc_tmp="${_TMP_DIR}/,$1"; + obj tc_tmp rm_file; + : >"${tc_tmp}" + obj tc_tmp echo1; + fi; + eval ${_UNSET} tc_tmp; + eval "${return_ok}"; +} # tmp_create() + + +######################################################################## +# to_tmp (<filename>) +# +# Print file (decompressed) to the temporary cat file. +# +# Variable prefix: tt +# +to_tmp() +{ + func_check to_tmp '=' 1 "$@"; + if obj _TMP_CAT is_empty + then + error 'to_tmp(): $_TMP_CAT is not yet set'; + fi; + tt_1="$1"; + tt_so_nr=0; # number for temporary `,so,*,*' + if is_file "${tt_1}" + then + tt_dir="$(dir_name "${tt_1}")"; + if obj _OPT_WHATIS is_yes + then + whatis_filename "${tt_1}" >>"${_TMP_CAT}"; + else + _FILE_NR="$(expr ${_FILE_NR} + 1)"; + tt_file="${_TMP_DIR}/,file${_FILE_NR}"; + if obj _FILESPEC_IS_MAN is_yes + then + if obj _DEBUG_PRINT_FILENAMES is_yes + then + echo2 "file: ${tt_1}"; + fi; + tt_tmp="${_TMP_DIR}/,tmp"; + cat_z "${tt_1}" >"${tt_file}"; + grep '^\.[ ]*so[ ]' "${tt_file}" | + sed 's/^\.[ ]*so[ ]*//' >"${tt_tmp}"; + list_from_file tt_list "${tt_tmp}"; + eval set x ${tt_list}; + shift; + for i + do + tt_i="$i"; + tt_so_nr="$(expr ${tt_so_nr} + 1)"; + tt_sofile="${_TMP_DIR}/,so${_FILE_NR}_${tt_so_nr}"; + tt_sofiles="${tt_sofiles} ${tt_sofile}"; + _do_man_so "${tt_i}"; + done; + rm_file "${tt_tmp}"; + mv "${tt_file}" "${tt_tmp}"; + cat "${tt_tmp}" | soelim -I "${tt_dir}" ${_SOELIM_R} >"${tt_file}"; + for f in ${tt_sofiles} + do + rm_file_with_debug $f; + done; + rm_file "${tt_tmp}"; + else # $_FILESPEC_IS_MAN ist not yes + cat_z "${tt_1}" | soelim -I "${tt_dir}" ${_SOELIM_R} >"${tt_file}"; + fi; +### to_tmp() + obj_from_output tt_grog grog "${tt_file}"; + if is_not_equal "$?" 0 + then + exit "${_ERROR}"; + fi; + echo2 "grog output: ${tt_grog}"; + case " ${tt_grog} " in + *\ -m*) + eval set x "$(echo1 " ${tt_grog} " | sed ' +s/'"${_TAB}"'/ /g +s/ */ /g +s/ -m / -m/g +s/ -mm\([^ ]\)/ -m\1/g +')"; + shift; + for i + do + tt_i="$i"; + case "${tt_i}" in + -m*) + if list_has _MACRO_PACKAGES "${tt_i}" + then + case "${_MACRO_PKG}" in + '') + _MACRO_PKG="${tt_i}"; + ;; + ${tt_i}) + :; + ;; + -m*) + echo2 "Ignore ${tt_1} because it needs ${tt_i} instead "\ +"of ${_MACRO_PKG}." + rm_file_with_debug "${tt_file}"; + eval ${_UNSET} tt_1; + eval ${_UNSET} tt_dir; + eval ${_UNSET} tt_file; + eval ${_UNSET} tt_grog; + eval ${_UNSET} tt_i; + eval ${_UNSET} tt_so_nr; + eval ${_UNSET} tt_sofile; + eval ${_UNSET} tt_sofiles; + eval ${_UNSET} tt_sofound; + eval ${_UNSET} tt_list; + eval ${_UNSET} tt_tmp; + eval "${return_bad}"; + ;; +### to_tmp() + *) + error \ +'to_tmp(): $_MACRO_PKG does not start with -m: '"${_MACRO_PKG}"; + ;; + esac; + fi; + ;; + esac; + done; + ;; + esac; + cat "${tt_file}" >>"${_TMP_CAT}"; + rm_file_with_debug "${tt_file}"; + fi; + else + error "to_tmp(): could not read file \`${tt_1}'."; + fi; + eval ${_UNSET} tt_1; + eval ${_UNSET} tt_dir; + eval ${_UNSET} tt_file; + eval ${_UNSET} tt_grog; + eval ${_UNSET} tt_i; + eval ${_UNSET} tt_so_nr; + eval ${_UNSET} tt_sofile; + eval ${_UNSET} tt_sofiles; + eval ${_UNSET} tt_sofound; + eval ${_UNSET} tt_list; + eval ${_UNSET} tt_tmp; + eval "${return_ok}"; +} # to_tmp() + + +############# +# _do_man_so (<so_arg>) +# +# Handle single .so file name for man pages. +# +# Local function to to_tmp(). +# +# Globals from to_tmp(): $tt_tmp, $tt_sofile, $tt_file +# Globals: $_TMP_MAN +# +# Variable prefix: dms +# +_do_man_so() { + func_check _do_man_so '=' 1 "$@"; + _dms_so="$1"; # evt. with `\ ' + _dms_soname="$(echo $1 | sed 's/\\[ ]/ /g')"; # without `\ ' + case "${_dms_soname}" in + /*) # absolute path + if test -f "${_dms_soname}" + then + eval "${return_ok}"; + fi; + if test -f "${_dms_soname}"'.gz' + then + _dms_sofound="${_dms_soname}"'.gz'; + elif test -f "${_dms_soname}"'.Z' + then + _dms_sofound="${_dms_soname}"'.Z'; + elif test -f "${_dms_soname}"'.bz2' + then + _dms_sofound="${_dms_soname}"'.bz2'; + else + eval ${_UNSET} _dms_so; + eval ${_UNSET} _dms_soname; + eval "${return_ok}"; + fi; + ;; +### _do_man_so() of to_tmp() + *) # relative to man path + eval grep "'/${_dms_soname}\$'" "${_TMP_MAN}" >"${tt_tmp}"; + if is_empty_file "${tt_tmp}" + then + eval grep "'/${_dms_soname}.gz\$'" "${_TMP_MAN}" >"${tt_tmp}"; + if is_empty_file "${tt_tmp}" + then + eval grep "'/${_dms_soname}.Z\$'" "${_TMP_MAN}" >"${tt_tmp}"; + if is_empty_file "${tt_tmp}" + then + eval grep "'/${_dms_soname}.bz2\$'" "${_TMP_MAN}" >"${tt_tmp}"; + fi; + fi; + fi; + if is_empty_file "${tt_tmp}" + then + eval "${return_ok}"; + fi; + _dms_done='no'; + list_from_file _dms_list "${tt_tmp}"; + eval set x ${_dms_list}; + shift; + for i + do + _dms_sofound="$i"; + if obj _dms_sofound is_empty + then + continue; + fi; + _dms_done='yes'; + break; + done; +### _do_man_so() of to_tmp() + if obj _dms_done is_not_yes + then + eval ${_UNSET} _dms_done; + eval ${_UNSET} _dms_sofound; + eval "${return_ok}"; + fi; + ;; + esac; + if obj _DEBUG_PRINT_FILENAMES is_yes + then + echo2 "file from .so: ${_dms_so}"; + fi; + cat_z "${_dms_sofound}" >"${tt_sofile}"; + _dms_esc="$(echo ${_dms_so} | sed 's/\\/\\\\/g')"; + cat "${tt_file}" | eval sed \ +"'s#^\\.[ ]*so[ ]*\(${_dms_so}\|${_dms_esc}\|${_dms_soname}\)[ ]*\$'"\ +"'#.so ${tt_sofile}#'" \ + >"${tt_tmp}"; + rm_file "${tt_file}"; + mv "${tt_tmp}" "${tt_file}"; + eval ${_UNSET} _dms_done; + eval ${_UNSET} _dms_esc; + eval ${_UNSET} _dms_so; + eval ${_UNSET} _dms_sofound; + eval ${_UNSET} _dms_soname; + eval "${return_ok}"; +} # _do_man_so() of to_tmp() + + +######################################################################## +# to_tmp_line (<text>...) +# +# Print single line with <text> to the temporary cat file. +# +to_tmp_line() +{ + func_check to_tmp_line '>=' 1 "$@"; + if obj _TMP_CAT is_empty + then + error 'to_tmp_line(): $_TMP_CAT is not yet set'; + fi; + echo1 "$*" >>"${_TMP_CAT}"; + eval "${return_ok}"; +} # to_tmp_line() + + +######################################################################## +# 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_set() + + +######################################################################## +# trap_unset () +# +# Disable trap on signal 0. +# +trap_unset() +{ + func_check trap_unset '=' 0 "$@"; + trap '' 0 2>${_NULL_DEV} || :; + eval "${return_ok}"; +} # trap_unset() + + +######################################################################## +# usage () +# +# Print usage information to standard output; for groffer option --help. +# +usage() +{ + func_check usage = 0 "$@"; + echo; + version; + cat <<EOF + +Usage: groffer [option]... [filespec]... + +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.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.n" man page "name" in section "n" + "n name" man page "name" in section "n" + "name" man page "name" in first section found +where `section' is a single character out of [1-9on], optionally followed +by some more letters that are called the `extension'. + +-h --help print this usage message. +-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 a 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. +--source output as roff source. +--text output in a text device without a pager. +--to-stdout output the content of the mode file without display. +--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". + +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, ... + +Development options that are not useful for normal usage: +--debug, --debug-all, --debug-filenames, --debug-func, +--debug-not-func, --debug-grog, --debug-keep, --debug-lm, +--debug-params, --debug-shell, --debug-stacks, --debug-tmpdir, +--debug-user, --do-nothing, --print=text, --shell=prog + +EOF + + eval "${return_ok}"; +} # usage() + + +######################################################################## +# version () +# +# Print version information to standard output. +# For groffer option --version. +# +version() +{ + func_check version = 0 "$@"; + y="$(echo "${_LAST_UPDATE}" | sed 's/^.* //')"; + cat <<EOF +groffer ${_PROGRAM_VERSION} of ${_LAST_UPDATE} (shell version) +is part of groff version ${_GROFF_VERSION}. +Copyright (C) $y Free Software Foundation, Inc. +GNU groff and groffer come with ABSOLUTELY NO WARRANTY. +You may redistribute copies of groff and its subprograms +under the terms of the GNU General Public License. +EOF + eval "${return_ok}"; +} # version() + + +######################################################################## +# warning (<string>) +# +# Print warning to stderr. +# +warning() +{ + echo2 "warning: $*"; +} # warning() + + +######################################################################## +# whatis_filename (<filename>) +# +# Interpret <filename> as a man page and display its `whatis' +# information as a fragment written in the groff language. +# +# Globals: in: $_OPT_WHATIS, $_SPECIAL_SETUP, $_SPECIAL_FILESPEC, +# $_FILESPEC_ARG +# +# Variable prefix: wf +# +whatis_filename() +{ + func_check whatis_filename = 1 "$@"; + if obj _OPT_WHATIS is_not_yes + then + error 'whatis_filename(): $_OPT_WHATIS is not yes.'; + fi; + if obj _SPECIAL_SETUP is_not_yes + then + error \ + 'whatis_filename(): setup for whatis whatis_setup() must be run first.'; + fi; + if obj _SPECIAL_FILESPEC is_not_yes + then + error 'whatis_filename(): whatis_filespec() must be run first.'; + fi; + 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}"'*'; +### whatis_filename() + 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 ' +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=''; + ;; +### whatis_filename() + esac + if obj s is_yes + then + wf_name="$(echo1 ${wf_name} | sed ' +s/^\(.*\)\.'${wf_section}'.*$/\1/ +')"; + fi; + fi; + + # traditional man style; grep the line containing `.TH' macro, if any + wf_res="$(cat_z "$1" | sed ' +/'"${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 ' +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'; + ;; +### whatis_filename() + *) + s=''; + ;; + esac; + if obj s is_yes + then + wf_res="$(obj wf_res echo1 | sed ' +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 '/'"${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 ' +s/^\(.*\)$/'"${wf_name}"' ('"${wf_section}"') \\[em] \1/p +')"; + fi; +### whatis_filename() + 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_filename() + + + +######################################################################## +# whatis_filespec () +# +# Print the filespec name as .SH to the temporary cat file. +# +# Globals: in: $_OPT_WHATIS, $_SPECIAL_SETUP +# out: $_SPECIAL_FILESPEC +# +whatis_filespec() +{ + func_check whatis_filespec '=' 0 "$@"; + if obj _OPT_WHATIS is_yes + then + if obj _SPECIAL_SETUP is_not_yes + then + error 'whatis_filespec(): whatis_setup() must be run first.'; + fi; + _SPECIAL_FILESPEC='yes'; + eval to_tmp_line \ + "'.SH $(echo1 "${_FILESPEC_ARG}" | sed 's/[^\\]-/\\-/g')'"; + exit_test; + eval "${return_ok}"; + else + eval "${return_bad}"; + fi; +} # whatis_filespec() + + +######################################################################## +# whatis_setup () +# +# Print the whatis header to the temporary cat file; this is the setup +# for whatis. +# +# Globals: in: $_OPT_WHATIS +# out: $_SPECIAL_SETUP +# +whatis_setup() +{ + func_check whatis_setup '=' 0 "$@"; + if obj _OPT_WHATIS is_yes + then + to_tmp_line '.TH GROFFER WHATIS'; + _SPECIAL_SETUP='yes'; + if obj _OPT_TITLE is_empty + then + _OPT_TITLE='whatis'; + fi; + eval "${return_ok}"; + else + eval "${return_bad}"; + fi; +} # whatis_setup() + + +######################################################################## +# where_is_prog (<program>) +# +# Output path of a program and the given arguments if in $PATH. +# +# Arguments : 1, <program> can have spaces and arguments. +# Output : list of 2 elements: prog name (with directory) and arguments +# Return : `0' if arg1 is a program in $PATH, `1' otherwise. +# +# Variable prefix: wip +# +where_is_prog() +{ + func_check where_is_prog '=' 1 "$@"; + if is_empty "$1" + then + eval "${return_bad}"; + fi; + + # Remove disturbing multiple spaces and tabs + wip_1="$(echo1 "$1" | sed 's/[ ][ ]*/ /g' | \ + sed 's/\(\\\)* / /g' | sed 's/^ //' | sed 's/ $//')"; + wip_noarg="$(echo1 "${wip_1}" | sed 's/ -.*$//')"; + exit_test; + + if obj wip_noarg is_empty + then + eval ${_UNSET} wip_1; + eval ${_UNSET} wip_noarg; + eval "${return_bad}"; + fi; + + case "${wip_1}" in + *\ -*) + wip_args="$(echo1 "${wip_1}" | + eval sed "'s#^${wip_noarg} ##'")"; + exit_test; + ;; + *) + wip_args=''; + ;; + esac; + + wip_result=''; +### where_is_prog() + + if test -f "${wip_noarg}" && test -x "${wip_noarg}" + then + list_append wip_result "${wip_noarg}" "${wip_args}"; + exit_test; + obj wip_result echo1; + exit_test; + eval ${_UNSET} wip_1; + eval ${_UNSET} wip_args; + eval ${_UNSET} wip_noarg; + eval ${_UNSET} wip_result; + eval "${return_ok}"; + fi; + + # test whether $wip_noarg has directory, so it is not tested with $PATH + case "${wip_noarg}" in + */*) + # now $wip_noarg (with /) is not an executable file + + # test name with space + obj_from_output wip_name base_name "${wip_noarg}"; + obj_from_output wip_dir dir_name "${wip_noarg}"; + case "${wip_name}" in + *\ *) + wip_base="$(echo1 "${wip_name}" | sed 's/ .*$//')"; + exit_test; + obj_from_output wip_file dir_name_append "${wip_dir}" "${wip_base}"; + exit_test; +### where_is_prog() + if test -f "${wip_file}" && test -x "${wip_file}" + then + wip_baseargs="$(echo1 "${wip_name}" | + eval sed "'s#^${wip_base} ##'")"; + exit_test; + if obj wip_args is_empty + then + wip_args="${wip_baseargs}"; + else + wip_args="${wip_baseargs} ${wip_args}"; + fi; + + list_append wip_result "${wip_file}" "${wip_args}"; + exit_test; + obj wip_result echo1; + exit_test; + eval ${_UNSET} wip_1; + eval ${_UNSET} wip_args; + eval ${_UNSET} wip_base; + eval ${_UNSET} wip_baseargs; + eval ${_UNSET} wip_dir; + eval ${_UNSET} wip_file; + eval ${_UNSET} wip_name; + eval ${_UNSET} wip_noarg; + eval ${_UNSET} wip_result; + eval "${return_ok}"; + fi; # test ${wip_file} + ;; + esac; # end of test name with space + +### where_is_prog() + eval ${_UNSET} wip_1; + eval ${_UNSET} wip_args; + eval ${_UNSET} wip_base; + eval ${_UNSET} wip_dir; + eval ${_UNSET} wip_name; + eval ${_UNSET} wip_noarg; + eval ${_UNSET} wip_result; + eval "${return_bad}"; + ;; + esac; # test of $wip_noarg on path with directory + + + # now $wip_noarg does not have a /, so it is checked with $PATH. + + eval set x "$(path_list "${PATH}")"; + exit_test; + shift; + + # test path with $win_noarg, evt. with spaces + for d + do + wip_dir="$d"; + obj_from_output wip_file dir_name_append "${wip_dir}" "${wip_noarg}"; +### where_is_prog() + + # test $win_file on executable file + if test -f "${wip_file}" && test -x "${wip_file}" + then + list_append wip_result "${wip_file}" "${wip_args}"; + exit_test; + obj wip_result echo1; + exit_test; + eval ${_UNSET} wip_1; + eval ${_UNSET} wip_dir; + eval ${_UNSET} wip_file; + eval ${_UNSET} wip_noarg; + eval ${_UNSET} wip_result; + eval "${return_ok}"; + fi; # test $win_file on executable file + done; # test path with $win_prog with spaces + + case "${wip_noarg}" in + *\ *) + # test on path with base name without space + wip_base="$(echo1 "${wip_noarg}" | sed 's/^\([^ ]*\) .*$/\1/')"; + exit_test; + for d + do + wip_dir="$d"; + obj_from_output wip_file dir_name_append "${wip_dir}" "${wip_base}"; + exit_test; +### where_is_prog() + + # test $win_file on executable file + if test -f "${wip_file}" && test -x "${wip_file}" + then + wip_baseargs="$(echo1 "${wip_noarg}" | + sed 's/[^ ]* \(.*\)$/\1/')"; + exit_test; + if obj wip_args is_empty + then + wip_args="${wip_baseargs}"; + else + wip_args="${wip_args} ${wip_baseargs}"; + fi; + list_append wip_result "${wip_file}" "${wip_args}"; + exit_test; + obj wip_result echo1; + exit_test; + eval ${_UNSET} wip_1; + eval ${_UNSET} wip_args; + eval ${_UNSET} wip_base; + eval ${_UNSET} wip_baseargs; + eval ${_UNSET} wip_dir; + eval ${_UNSET} wip_file; + eval ${_UNSET} wip_name; + eval ${_UNSET} wip_noarg; + eval ${_UNSET} wip_result; + eval "${return_ok}"; + fi; # test of $wip_file on executable file + done; # test path with base name without space +### where_is_prog() + ;; + esac; # test of $wip_noarg on space + + eval ${_UNSET} wip_1; + eval ${_UNSET} wip_args; + eval ${_UNSET} wip_base; + eval ${_UNSET} wip_baseargs; + eval ${_UNSET} wip_dir; + eval ${_UNSET} wip_file; + eval ${_UNSET} wip_name; + eval ${_UNSET} wip_noarg; + eval ${_UNSET} wip_result; + eval "${return_bad}"; +} # where_is_prog() + + +######################################################################## +# 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 directory and some 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 0077; + _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}"; +### main_init() + 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; +### main_init() + if obj _DEBUG_PRINT_TMPDIR is_yes + then + echo2 "temporary directory: ${_TMP_DIR}"; + fi; + + obj_from_output _TMP_CAT tmp_create groffer_cat; + obj_from_output _TMP_STDIN tmp_create groffer_input; + + 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 ' +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'; + ;; +### main_parse_MANOPT() + -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; + ;; + -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; + ;; +### main_parse_MANOPT() + -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; + ;; + -T|--device) + list_append mpm_list '-T' "$1"; + shift; + ;; +### main_parse_MANOPT() + -u|--update) + do_nothing; + ;; + -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 "$@"; + obj_from_output _ALL_PARAMS list_from_cmdline_with_minus _OPTS_CMDLINE "$@"; + 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'; + ;; +### main_parse_args() + -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) + _OPT_MODE=X; + ;; + -?) + # delete leading `-' + mpa_optchar="$(echo1 "${mpa_opt}" | sed '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; +### main_parse_args() + 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'; + ;; +### main_parse_args() + --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|--bordercolor) # border color for viewers, arg; + _OPT_BD="$1"; + shift; + ;; + --bg|--backgroud) # background color for viewers, arg; + _OPT_BG="$1"; + shift; + ;; + --bw|--borderwidth) # border width for viewers, arg; + _OPT_BW="$1"; + shift; + ;; + --debug|--debug-all|--debug-filenames|--debug-func|--debug-not-func|\ +--debug-grog|--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; + ;; +### main_parse_args() + --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) + _OPT_MODE='dvi'; + ;; + --dvi-viewer|--dvi-viewer-tty) # viewer program for dvi mode; arg + _OPT_VIEWER_DVI="$1"; + shift; + ;; + --extension) # the extension for man pages, arg + _OPT_EXTENSION="$1"; + shift; + ;; +### main_parse_args() + --fg|--foreground) # foreground color for viewers, arg; + _OPT_FG="$1"; + shift; + ;; + --fn|--ft|--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|--html-viewer-tty|--www-viewer-tty) + # viewer program for html mode; arg + _OPT_VIEWER_HTML="$1"; + shift; + ;; + --iconic) # start viewers as icons + _OPT_ICONIC='yes'; + ;; +### main_parse_args() + --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 + _DEBUG_PRINT_FILENAMES='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'; + ;; +### main_parse_args() + html|www) # display with a web browser + _OPT_MODE='html'; + ;; + dvi) # display with xdvi viewer + _OPT_MODE='dvi'; + ;; + pdf) # display with PDF viewer + _OPT_MODE='pdf'; + ;; + ps) # display with Postscript viewer + _OPT_MODE='ps'; + ;; + text) # output on terminal + _OPT_MODE='text'; + ;; + tty) # output on terminal + _OPT_MODE='tty'; + ;; + X|x) # output on X roff viewer + _OPT_MODE='x'; + ;; +### main_parse_args() + Q|source) # display source code + _OPT_MODE="source"; + ;; + *) + error "main_parse_args(): unknown mode ${mpa_arg}"; + ;; + esac; + ;; + --no-location) # disable former call to `--location' + _DEBUG_PRINT_FILENAMES='no'; + ;; + --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 + _OPT_PAGER="$1"; + shift; + ;; + --pdf) + _OPT_MODE='pdf'; + ;; +### main_parse_args() + --pdf-viewer|--pdf-viewer-tty) # viewer program for pdf mode; arg + _OPT_VIEWER_PDF="$1"; + shift; + ;; + --print) # for argument test + echo2 "$1"; + shift; + ;; + --ps) + _OPT_MODE='ps'; + ;; + --ps-viewer|--ps-viewer-tty) # viewer program for ps mode; arg + _OPT_VIEWER_PS="$1"; + shift; + ;; +### main_parse_args() + --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; + ;; +### main_parse_args() + --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 + if is_not_empty "$1" + then + list_append _OPT_TITLE "$1"; + fi; + shift; + ;; + --to-stdout) # print mode file without display + _OPT_STDOUT='yes'; + ;; + --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_APROPOS='no'; + ;; + --X|--x) + _OPT_MODE=x; + ;; +### main_parse_args() + --xrm) # pass X resource string, arg; + list_append _OPT_XRM "$1"; + shift; + ;; + --x-viewer|--X-viewer|--x-viewer-tty|--X-viewer-tty) + # viewer program for x mode; arg + _OPT_VIEWER_X="$1"; + shift; + ;; + *) + error 'main_parse_args(): unknown option '"\`${mpa_opt}'."; + ;; + esac; + done; + shift; # remove `--' argument + + if obj _OPT_WHATIS is_yes + then + _MAN_ALL='yes'; + _APROPOS_SECTIONS=''; + fi; + + if obj _OPT_DO_NOTHING is_yes + then + leave; + fi; + +### main_parse_args() + case "$_OPT_DEFAULT_MODES" in + '') :; ;; + *,*) + obj_from_output _OPT_DEFAULT_MODES \ + obj _OPT_DEFAULT_MODES list_from_split ','; + ;; + *) :; ;; + esac; + + # Remaining arguments are file names (filespecs). + # Save them to list $_FILEARGS + if is_equal "$#" 0 + then # use "-" for standard input + _NO_FILESPECS='yes'; + set x '-'; + shift; + fi; + _FILEARGS=''; + list_append _FILEARGS "$@"; + # $_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 and the corresponding viewer program. +# +# 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_viewers; + eval "${return_ok}"; + fi; + +### main_set_mode() + + 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_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_viewers; + eval "${return_ok}"; + ;; +### main_set_mode() + esac; + if is_not_X + then + _DISPLAY_MODE='tty'; + eval ${_UNSET} msm_modes; + 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; + ;; + source) + _DISPLAY_MODE='source'; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + text) + _DISPLAY_MODE='text'; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + tty) + _DISPLAY_MODE='tty'; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; +### main_set_mode() + html) + _DISPLAY_MODE='html'; + msm_modes="${_OPT_MODE}"; + ;; + *) # display mode was given + msm_modes="${_OPT_MODE}"; + ;; + esac; + + eval set x "${msm_modes}"; + shift; + while is_greater_than "$#" 0 + do + msm_1="$1"; + shift; + + _VIEWER_BACKGROUND='no'; + + case "${msm_1}" in + dvi) + _get_prog_args DVI; + if is_not_equal "$?" 0 + then + continue; + fi; + if obj _DISPLAY_PROG is_empty + then + if is_equal "$#" 0 + then + error 'main_set_mode(): No viewer for dvi mode available.'; + else + continue; + fi; + fi; +### main_set_mode() + _DISPLAY_MODE="dvi"; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + html) + _get_prog_args HTML; + if is_not_equal "$?" 0 + then + continue; + fi; + if obj _DISPLAY_PROG is_empty + then + if is_equal "$#" 0 + then + error 'main_set_mode(): No viewer for html mode available.'; + else + continue; + fi; + fi; +### main_set_mode() + _DISPLAY_MODE=html; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + pdf) + if obj _PDF_DID_NOT_WORK is_yes + then + if is_equal "$#" 0 + then + error 'main_set_mode(): pdf mode did not work.'; + else + continue; + fi; + fi; + if obj _PDF_HAS_PS2PDF is_not_yes + then + if is_prog ps2pdf + then + _PDF_HAS_PS2PDF='yes'; + fi; + fi; + if obj _PDF_HAS_GS is_not_yes + then + if is_prog gs + then + _PDF_HAS_GS='yes'; + fi; + fi; + _get_prog_args PDF; + if is_not_equal "$?" 0 + then + _PDF_DID_NOT_WORK='yes'; + continue; + fi; + if obj _DISPLAY_PROG is_empty + then + _PDF_DID_NOT_WORK='yes'; + if is_equal "$#" 0 + then + error 'main_set_mode(): No viewer for pdf mode available.'; + else + continue; + fi; + fi; + _DISPLAY_MODE="pdf"; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; +### main_set_mode() + ps) + _get_prog_args PS; + if is_not_equal "$?" 0 + then + continue; + fi; + if obj _DISPLAY_PROG is_empty + then + if is_equal "$#" 0 + then + error 'main_set_mode(): No viewer for ps mode available.'; + else + continue; + fi; + fi; + _DISPLAY_MODE="ps"; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + text) + _DISPLAY_MODE='text'; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; +### main_set_mode() + tty) + _DISPLAY_MODE='tty'; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + x) + _get_prog_args x; + if is_not_equal "$?" 0 + then + continue; + fi; + if obj _DISPLAY_PROG is_empty + then + if is_equal "$#" 0 + then + error 'main_set_mode(): No viewer for x mode available.'; + else + continue; + fi; + fi; + _DISPLAY_MODE='x'; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; +### main_set_mode() + X) + _DISPLAY_MODE='X'; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + esac; + done; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + error_user "No suitable display mode found."; +} # main_set_mode() + + +# _get_prog_args (<MODE>) +# +# Simplification for loop in main_set_mode(). +# +# Globals in/out: $_VIEWER_BACKGROUND +# Globals in : $_OPT_VIEWER_<MODE>, $_VIEWER_<MODE>_X, $_VIEWER_<MODE>_TTY +# +# Variable prefix: _gpa +# +_get_prog_args() +{ + func_check _get_prog_args '=' 1 "$@"; + + x="$(echo1 $1 | tr [a-z] [A-Z])"; + eval _gpa_opt='"${_OPT_VIEWER_'"$x"'}"'; + _gpa_xlist=_VIEWER_"$x"_X; + _gpa_ttylist=_VIEWER_"$x"_TTY; + + if obj _gpa_opt is_empty + then + _VIEWER_BACKGROUND='no'; + if is_X + then + _get_first_prog "${_gpa_xlist}"; + x="$?"; + if is_equal "$x" 0 + then + _VIEWER_BACKGROUND='yes'; + fi; + else + _get_first_prog "${_gpa_ttylist}"; + x="$?"; + fi; + exit_test; + eval ${_UNSET} _gpa_opt; + eval ${_UNSET} _gpa_prog; + eval ${_UNSET} _gpa_ttylist; + eval ${_UNSET} _gpa_xlist; + eval "${return_var} $x"; +### _get_prog_args() of main_set_mode() + else # $_gpa_opt is not empty + obj_from_output _gpa_prog where_is_prog "${_gpa_opt}"; + if is_not_equal "$?" 0 || obj _gpa_prog is_empty + then + exit_test; + echo2 "_get_prog_args(): '${_gpa_opt}' is not an existing program."; + eval ${_UNSET} _gpa_opt; + eval ${_UNSET} _gpa_prog; + eval ${_UNSET} _gpa_ttylist; + eval ${_UNSET} _gpa_xlist; + eval "${return_bad}"; + fi; + exit_test; + + # $_gpa_prog from opt is an existing program + +### _get_prog_args() of main_set_mode() + if is_X + then + eval _check_prog_on_list ${_gpa_prog} ${_gpa_xlist}; + if is_equal "$?" 0 + then + _VIEWER_BACKGROUND='yes'; + else + _VIEWER_BACKGROUND='no'; + eval _check_prog_on_list ${_gpa_prog} ${_gpa_ttylist}; + fi; + else # is not X + _VIEWER_BACKGROUND='no'; + eval _check_prog_on_list ${_gpa_prog} ${_gpa_ttylist}; + fi; # is_X + fi; # test of $_gpa_opt + eval ${_UNSET} _gpa_opt; + eval ${_UNSET} _gpa_prog; + eval ${_UNSET} _gpa_ttylist; + eval ${_UNSET} _gpa_xlist; + eval "${return_good}"; +} # _get_prog_args() of main_set_mode() + + +# _get_first_prog (<prog_list_name>) +# +# Retrieve from the elements of the list in the argument the first +# existing program in $PATH. +# +# Local function for main_set_mode(). +# +# Return : `1' if none found, `0' if found. +# Output : none +# +# Variable prefix: _gfp +# +_get_first_prog() +{ + func_check _get_first_prog '=' 1 "$@"; + eval x='"${'"$1"'}"'; + eval set x "$x"; + shift; + for i + do + _gfp_i="$i"; + if obj _gfp_i is_empty + then + continue; + fi; + obj_from_output _gfp_result where_is_prog "${_gfp_i}"; + if is_equal "$?" 0 && obj _gfp_result is_not_empty + then + exit_test; + eval set x ${_gfp_result}; + shift; + _DISPLAY_PROG="$1"; + _DISPLAY_ARGS="$2"; + eval ${_UNSET} _gfp_i; + eval ${_UNSET} _gfp_result; + eval "${return_good}"; + fi; + exit_test; + done; + eval ${_UNSET} _gfp_i; + eval ${_UNSET} _gfp_result; + eval "${return_bad}"; +} # _get_first_prog() of main_set_mode() + + +# _check_prog_on_list (<prog> <args> <prog_list_name>) +# +# Check whether the content of <prog> is in the list <prog_list_name>. +# The globals are set correspondingly. +# +# Local function for main_set_mode(). +# +# Arguments: 3 +# +# Return : `1' if not a part of the list, `0' if found in the list. +# Output : none +# +# Globals in : $_VIEWER_<MODE>_X, $_VIEWER_<MODE>_TTY +# Globals in/out: $_DISPLAY_PROG, $_DISPLAY_ARGS +# +# Variable prefix: _cpol +# +_check_prog_on_list() +{ + func_check _check_prog_on_list '=' 3 "$@"; + _DISPLAY_PROG="$1"; + _DISPLAY_ARGS="$2"; + + eval _cpol_3='"${'"$3"'}"'; + eval set x "${_cpol_3}"; + shift; + eval ${_UNSET} _cpol_3; + + for i + do + _cpol_i="$i"; + obj_from_output _cpol_list where_is_prog "${_cpol_i}"; + if is_not_equal "$?" 0 || obj _cpol_list is_empty + then + exit_test; + continue; + fi; + exit_test; + _cpol_prog="$(eval set x ${_cpol_list}; shift; echo1 "$1")"; + + if is_not_equal "${_DISPLAY_PROG}" "${_cpol_prog}" + then + exit_test; + continue; + fi; + exit_test; +### _check_prog_on_list() of main_set_mode() + + # equal, prog found + + _cpol_args="$(eval set x ${_cpol_list}; shift; echo1 "$2")"; + eval ${_UNSET} _cpol_list; + if obj _cpol_args is_not_empty + then + if obj _DISPLAY_ARGS is_empty + then + _DISPLAY_ARGS="${_cpol_args}"; + else + _DISPLAY_ARGS="${_cpol_args} ${_DISPLAY_ARGS}"; + fi; + fi; + + eval ${_UNSET} _cpol_i; + eval ${_UNSET} _cpol_args; + eval ${_UNSET} _cpol_prog; + eval "${return_good}"; + done; # for vars in list + + # prog was not in the list + eval ${_UNSET} _cpol_i; + eval ${_UNSET} _cpol_args; + eval ${_UNSET} _cpol_list; + eval ${_UNSET} _cpol_prog; + eval "${return_bad}"; +} # _check_prog_on_list() of main_set_mode() + + +####################################################################### +# main_do_fileargs () +# +# Process filespec arguments. +# +# Globals: +# in: $_FILEARGS (process with `eval set x "$_FILEARGS"; shift;') +# +# Variable prefix: mdfa +# +main_do_fileargs() +{ + func_check main_do_fileargs = 0 "$@"; + special_setup; + if obj _OPT_APROPOS is_yes + then + if obj _NO_FILESPECS is_yes + then + apropos_filespec; + eval "${return_ok}"; + fi; + else + if list_has _FILEARGS '-' + then + save_stdin; + fi; + fi; + eval set x "${_FILEARGS}"; + shift; + eval ${_UNSET} _FILEARGS; +### main_do_fileargs() + while is_greater_than "$#" 0 + do + mdfa_filespec="$1"; + _FILESPEC_ARG="$1"; + shift; + _FILESPEC_IS_MAN='no'; + _TMP_MANSPEC=''; + _SPECIAL_FILESPEC='no'; + + case "${mdfa_filespec}" in + '') + continue; + ;; + esac; + + # check for file + case "${mdfa_filespec}" in + '-') + special_filespec; + if obj _OPT_APROPOS is_yes + then + continue; + fi; + register_file '-'; + continue; + ;; +### main_do_fileargs() + */*) + special_filespec; + if obj _OPT_APROPOS is_yes + then + continue; + fi; + if obj mdfa_filespec is_file + then + obj mdfa_filespec register_file; + else + echo2 "The argument ${mdfa_filespec} is not a file."; + fi; + continue; + ;; + *) + if obj _OPT_APROPOS is_yes + then + special_filespec; + continue; + fi; + # check whether filespec is an existing file + if obj _MAN_FORCE is_not_yes + then + if obj mdfa_filespec is_file + then + special_filespec; + obj mdfa_filespec register_file; + continue; + fi; + fi; + ;; + esac; +### main_do_fileargs() + + # now it must be a man page pattern + + if obj _MACRO_PKG is_not_empty && obj _MACRO_PKG is_not_equal '-man' + then + echo2 "${mdfa_filespec} is not a file, man pages are ignored "\ +"due to ${_MACRO_PKG}."; + continue; + fi; + + # check for man page + if obj _MAN_ENABLE is_not_yes + then + echo2 "The argument ${mdfa_filespec} is not a file."; + continue; + fi; + if obj _MAN_FORCE is_yes + then + mdfa_errmsg='is not a man page.'; + else + mdfa_errmsg='is neither a file nor a man page.'; + fi; +### main_do_fileargs() + man_setup; + _FILESPEC_IS_MAN='yes'; + + # test filespec with `man:...' or `...(...)' on man page + mdfa_name=''; + mdfa_section=''; + mdfa_ext=''; + + mdfa_names="${mdfa_filespec}"; + case "${mdfa_filespec}" in + man:*) + mdfa_names="${mdfa_names} "\ +"$(obj mdfa_filespec echo1 | sed 's/^man://')"; + ;; + esac; + + mdfa_continue='no'; + for i in ${mdfa_names} + do + mdfa_i=$i; + if obj mdfa_i man_is_man + then + special_filespec; + obj mdfa_i man_get; + mdfa_continue='yes'; + break; + fi; + case "${mdfa_i}" in + *\(${_MAN_AUTO_SEC_CHARS}*\)) + mdfa_section="$(obj mdfa_i echo1 | sed 's/^[^(]*(\(.\).*)$/\1/')"; + mdfa_name="$(obj mdfa_i echo1 | sed 's/^\([^(]*\)(.*)$/\1/')"; + mdfa_ext="$(obj mdfa_i echo1 | sed 's/^[^(]*(.\(.*\))$/\1/')"; + if man_is_man "${mdfa_name}" "${mdfa_section}" "${mdfa_ext}" + then + special_filespec; + man_get "${mdfa_name}" "${mdfa_section}" "${mdfa_ext}"; + mdfa_continue='yes'; + break; + fi; + ;; + *.${_MAN_AUTO_SEC_CHARS}*) + mdfa_name="$(obj mdfa_i echo1 | \ + sed 's/^\(.*\)\.'"${_MAN_AUTO_SEC_CHARS}"'.*$/\1/')"; + mdfa_section="$(obj mdfa_i echo1 | \ + sed 's/^.*\.\('"${_MAN_AUTO_SEC_CHARS}"'\).*$/\1/')"; + mdfa_ext="$(obj mdfa_i echo1 | \ + sed 's/^.*\.'"${_MAN_AUTO_SEC_CHARS}"'\(.*\)$/\1/')"; + if man_is_man "${mdfa_name}" "${mdfa_section}" "${mdfa_ext}" + then + special_filespec; + man_get "${mdfa_name}" "${mdfa_section}" "${mdfa_ext}"; + mdfa_continue='yes'; + break; + fi; + ;; + esac; + done; + + if obj mdfa_continue is_yes + then + continue; + fi; + +### main_do_fileargs() + # check on "s name", where "s" is a section with or without an extension + if is_not_empty "$1" + then + mdfa_name="$1"; + case "${mdfa_filespec}" in + ${_MAN_AUTO_SEC_CHARS}) + mdfa_section="${mdfa_filespec}"; + mdfa_ext=''; + ;; + ${_MAN_AUTO_SEC_CHARS}*) + mdfa_section="$(echo1 "${mdfa_filespec}" | \ + sed 's/^\(.\).*$/\1/')"; + mdfa_ext="$(echo1 "${mdfa_filespec}" | \ + sed 's/^.\(.*\)$/\1/')"; + ;; + *) + echo2 "${mdfa_filespec} ${mdfa_errmsg}"; + continue; + ;; + esac; + shift; + if man_is_man "${mdfa_name}" "${mdfa_section}" "${mdfa_ext}" + then + _FILESPEC_ARG="${mdfa_filespec} ${mdfa_name}"; + special_filespec; + man_get "${mdfa_name}" "${mdfa_section}" "${mdfa_ext}"; + continue; + else + echo2 "No man page for ${mdfa_name} with section ${mdfa_filespec}."; + continue; + fi; + fi; + +### main_do_fileargs() + echo2 "${mdfa_filespec} ${mdfa_errmsg}"; + continue; + done; + + obj _TMP_STDIN rm_file_with_debug; + eval ${_UNSET} mdfa_filespec; + eval ${_UNSET} mdfa_i; + eval ${_UNSET} mdfa_name; + eval ${_UNSET} mdfa_names; + 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 + for f in ${_TMP_DIR}/,man* + do + rm_file_with_debug $f; + done; + obj_from_output msr_title \ + get_first_essential "${_OPT_TITLE}" "${_REG_TITLE_LIST}"; + _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 '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; # until $# is 0 +### main_set_resources() + + 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; + obj_from_output msr_prog base_name "$1"; + shift; + if is_greater_than $# 0 + then + if obj _DISPLAY_ARGS is_empty + then + _DISPLAY_ARGS="$*"; + else + _DISPLAY_ARGS="$* ${_DISPLAY_ARGS}"; + fi; + fi; +### main_set_resources() + 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; +### main_set_resources() + 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; +### main_set_resources() + 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 "${_DISPLAY_PROG}" in + *-z*) + :; + ;; + *) # if xpdf does not have option -z + case "${_DEFAULT_RESOLUTION}" in + 75) + # 72dpi is '100' + list_append msr_rl '-z' '104'; + ;; + 100) + list_append msr_rl '-z' '139'; + ;; + esac; + ;; + esac; + ;; + esac; + else + case "${msr_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + list_append msr_rl '-resolution' "${_OPT_RESOLUTION}"; + ;; + xpdf) + case "${_DISPLAY_PROG}" in + *-z*) + :; + ;; + *) # if xpdf does not have option -z + case "${_OPT_RESOLUTION}" in + 75) + list_append msr_rl '-z' '104'; + # '100' corresponds to 72dpi + ;; +### main_set_resources() + 100) + list_append msr_rl '-z' '139'; + ;; + esac; + ;; + 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; +### main_set_resources() + ;; + esac; + fi; + if is_not_empty "${msr_title}" + then + case "${msr_prog}" in + gxditview|xditview) + list_append msr_rl '-title' "${msr_title}"; + ;; + esac; + fi; + if obj _DISPLAY_ARGS is_empty + then + _DISPLAY_ARGS="${msr_rl}"; + else + _DISPLAY_ARGS="${msr_l} ${_DISPLAY_ARGS}"; + fi; + 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, +# $_TMP_CAT, $_OPT_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_empty_file + then + echo2 'groffer: empty input.'; + clean_up; + eval "${return_ok}"; + fi; + + md_modefile="${_OUTPUT_FILE_NAME}"; + + # 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) + if obj _OPT_DEVICE is_not_empty + then + _ADDOPTS_GROFF="${_ADDOPTS_GROFF} -T${_OPT_DEVICE}"; + fi; + md_groggy="$(tmp_cat | eval grog)"; + if is_not_equal "$?" 0 + then + exit "${_ERROR}"; + fi; + echo2 "grog output: ${md_groggy}"; + exit_test; + _do_opt_V; + +### main_display() + 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 + '') + obj_from_output md_device \ + get_first_essential "${_OPT_TEXT_DEVICE}" "${_DEFAULT_TTY_DEVICE}"; + ;; + ascii|cp1047|latin1|utf8) + md_device="${_OPT_DEVICE}"; + ;; + *) + warning "main_display(): \ +wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; + ;; + esac; + md_addopts="${_ADDOPTS_GROFF}"; + md_groggy="$(tmp_cat | grog -T${md_device})"; + if is_not_equal "$?" 0 + then + exit "${_ERROR}"; + fi; + echo2 "grog output: ${md_groggy}"; + exit_test; + if obj _DISPLAY_MODE is_equal 'text' + then + _do_opt_V; + tmp_cat | eval "${md_groggy}" "${md_addopts}"; + else # $_DISPLAY_MODE is 'tty' +### main_display() + md_pager=''; + for p in "${_OPT_PAGER}" "${_MANOPT_PAGER}" "${PAGER}" + do + if obj p is_empty + then + continue; + fi; + obj_from_output md_pager where_is_prog "$p"; + if is_not_equal "$?" 0 || obj md_pager is_empty + then + md_pager=''; + continue; + fi; + eval set x $md_pager; + shift; + case "$1" in + */less) + if is_empty "$2" + then + md_pager="$1"' -r -R'; + else + md_pager="$1"' -r -R '"$2"; + fi; + ;; +### main_display() + *) + if is_empty "$2" + then + md_pager="$1"; + else + md_pager="$1 $2"; + fi; + ;; + esac; + break; + done; + if obj md_pager is_empty + then + eval set x ${_VIEWER_TTY_TTY} ${_VIEWER_TTY_X} 'cat'; + shift; + # that is: 'less -r -R' 'more' 'pager' 'xless' 'cat' + for p + do + if obj p is_empty + then + continue; + fi; + md_p="$p"; + if is_prog "${md_p}" + then + md_pager="${md_p}"; + break; + fi; + done; + fi; +### main_display() + 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; # $_DISPLAY_MODE + clean_up; + ;; # text|tty) + source) + tmp_cat; + clean_up; + ;; + + #### viewer modes + +### main_display() + 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)"; + if is_not_equal "$?" 0 + then + exit "${_ERROR}"; + fi; + echo2 "grog output: ${md_groggy}"; + 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)"; + if is_not_equal "$?" 0 + then + exit "${_ERROR}"; + fi; + echo2 "grog output: ${md_groggy}"; + exit_test; + _do_display; + ;; +### main_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)"; + if is_not_equal "$?" 0 + then + exit "${_ERROR}"; + fi; + echo2 "grog output: ${md_groggy}"; + 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)"; + if is_not_equal "$?" 0 + then + exit "${_ERROR}"; + fi; + echo2 "grog output: ${md_groggy}"; + exit_test; + _do_display; + ;; +### main_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)"; + if is_not_equal "$?" 0 + then + exit "${_ERROR}"; + fi; + echo2 "grog output: ${md_groggy}"; + exit_test; + _do_display; + ;; +### main_display() + X) + case "${_OPT_DEVICE}" in + '') + md_groggy="$(tmp_cat | grog -X)"; + if is_not_equal "$?" 0 + then + exit "${_ERROR}"; + fi; + echo2 "grog output: ${md_groggy}"; + exit_test; + ;; + X*|dvi|html|lbp|lj4|ps) + # these devices work with + md_groggy="$(tmp_cat | grog -T"${_OPT_DEVICE}" -X)"; + if is_not_equal "$?" 0 + then + exit "${_ERROR}"; + fi; + echo2 "grog output: ${md_groggy}"; + exit_test; + ;; + *) + warning "main_display(): \ +wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; + md_groggy="$(tmp_cat | grog -Z)"; + if is_not_equal "$?" 0 + then + exit "${_ERROR}"; + fi; + echo2 "grog output: ${md_groggy}"; + 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_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 obj md_modefile is_empty_file + then + echo2 '_do_display(): empty output.'; + clean_up; + exit; + fi; + if is_not_empty "$1" + then + eval "$1"; + fi; +### _do_display() of main_display() + obj _TMP_CAT rm_file_with_debug; + if obj _OPT_STDOUT is_yes + then + cat "${md_modefile}"; + clean_up; + exit; + fi; + if obj _VIEWER_BACKGROUND is_not_yes # for programs that run on tty + then + eval "'${_DISPLAY_PROG}'" ${_DISPLAY_ARGS} "\"${md_modefile}\""; + else + trap_unset; + { + trap_set; + eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "\"${md_modefile}\""; + } & + 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 _make_pdf '=' 0 "$@"; + _mp_psfile="${md_modefile}"; + md_modefile="${md_modefile}.pdf"; + obj md_modefile rm_file; + if obj _PDF_HAS_PS2PDF is_yes && ps2pdf "${_mp_psfile}" "${md_modefile}"; + then + :; + elif obj _PDF_HAS_GS is_yes && gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \ + -sOutputFile="${md_modefile}" -c save pop -f "${_mp_psfile}"; + then + :; + else + _PDF_DID_NOT_WORK='yes'; + echo2 '_make_pdf(): Could not transform into pdf format. '\ +'The Postscript mode (ps) is used instead.'; + _OPT_MODE='ps'; + main_set_mode; + main_set_resources; + main_display; + exit; + 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 "$@"; |