groff-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Groff-commit] groff/contrib/groffer/shell ChangeLog.0 README_...


From: Werner LEMBERG
Subject: [Groff-commit] groff/contrib/groffer/shell ChangeLog.0 README_...
Date: Sun, 11 Aug 2013 08:28:24 +0000

CVSROOT:        /sources/groff
Module name:    groff
Changes by:     Werner LEMBERG <wl>     13/08/11 08:28:24

Added files:
        contrib/groffer/shell: ChangeLog.0 README_SH groffer.man 
                               groffer.sh groffer2.sh roff2.sh 

Log message:
        Revert accidental removal in previous commit.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/groff/contrib/groffer/shell/ChangeLog.0?cvsroot=groff&rev=1.5
http://cvs.savannah.gnu.org/viewcvs/groff/contrib/groffer/shell/README_SH?cvsroot=groff&rev=1.9
http://cvs.savannah.gnu.org/viewcvs/groff/contrib/groffer/shell/groffer.man?cvsroot=groff&rev=1.20
http://cvs.savannah.gnu.org/viewcvs/groff/contrib/groffer/shell/groffer.sh?cvsroot=groff&rev=1.7
http://cvs.savannah.gnu.org/viewcvs/groff/contrib/groffer/shell/groffer2.sh?cvsroot=groff&rev=1.9
http://cvs.savannah.gnu.org/viewcvs/groff/contrib/groffer/shell/roff2.sh?cvsroot=groff&rev=1.7

Patches:
Index: ChangeLog.0
===================================================================
RCS file: ChangeLog.0
diff -N ChangeLog.0
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ ChangeLog.0 11 Aug 2013 08:28:23 -0000      1.5
@@ -0,0 +1,2122 @@
+2006-10-10  Bernd Warken <address@hidden>
+
+       * ChangeLog.0: This file is the former ChangeLog file of the
+       `groffer' versions 0.* consisting of a shell version only.  Since
+       then the files have been moved to the subdirectory `shell' of the
+       `groffer' main directory.
+
+2006-10-05  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.31
+
+       * groffer2.sh:
+       - _make_pdf(): Fix argument of `obj'.
+       - to_tmp(): Add option -r to soelim to omit the .lf request.  The
+       new global variable $_SOELIM_R stores the option if it is
+       available.  Use numbers for the names of the `file' and `so'
+       temporary files, such that the information for each filespec
+       argument is kept for debug.  New global variable $_FILE_NR.
+       - main_set_resources(): Remove `man' temporary files except for
+       debug
+       - man_get(): Change name in $_TMP_MANSPEC.
+       - man_is_man(): Change name in $_TMP_MANSPEC.  Remove file in
+       $_TMP_MANPEC if empty.
+       - _do_display() of main_display(): Add check on empty mode file.
+
+       * groffer.man: Filespec: Add information on the argument
+       handling of apropos.
+
+       Remove the space characters at the end of line in all files.
+
+2006-10-03  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.30
+
+       * groffer2.sh:
+       - Correct spacing.
+        - main_do_fileargs(): Distribute special_filespec() in order to
+        get a better heading for `whatis'.
+
+2006-10-03  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.29
+
+       * groffer2.sh:
+       - --to-stdtout: New option to display the generated mode file
+       without graphical display.
+       - _get_prog_args() of main_set_mode(): Make argument upper case.
+       - usage(): Add --to-stdout, remove -Q, reorder --source.
+
+       * groffer.man:
+       - Reorder the default viewers.
+       - Move `--source' to `groffer' options.
+       - Remove `-Q'.
+       - Add `--to-stdout'.
+       - Reconfigure the sections on filespec arguments.
+       - Remove information on wildcards.
+
+2006-10-01  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.28
+
+       * groffer.sh:
+       - Change all directories to end with `/'.
+       - In the state before the run of `make', make the script runnable
+       from each directory using $0 and `pwd'.
+
+       * groffer2.sh:
+       - main_init(): Change the umask to 0077 to allow only access for
+       the file owner for the temporary files.  This is done for security
+       reasons.
+       - version(): Put the whole output under `<<EOF'.
+       - usage(): Add information on filespec arguments.
+       - main_do_fileargs(): Rewrite the handling of filespec
+       parameters.  Fix filespec man:name.section.
+
+2006-09-26  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.27
+
+       * Makefile.sub: Add Emacs setting at the end of the file.
+
+       * TODO: Remove this file because it does not contain any actual
+       entries.
+
+       * groffer2.sh:
+       - main_set_mode(): Remove too early test of modes on X.  Fix pdf
+       mode.
+       - where_is_prog(): Fix this function to detect files in the
+       current directory.
+       - _get_prog_args() of main_set_mode(): Fix return;
+       - _get_first_prog() of main_set_mode(): Fix call of exit_test().
+       - cat_z(): Make it a single function and add file test.
+       - whatis_setup(): Rename whatis_header().  Fix display title to
+       `whatis'.
+       - apropos_setup(): Fix display title to `apropos'.
+       - Globals: Fix this section in the description of several
+       functions.
+       - apropos_filespec(): Fix variable $s and the corresponding sed
+       call.
+       - man_setup(): Add $EXTENSION.
+       - _do_man_so() of to_tmp(): Fix variables.
+       - $_ALL_EXIT: Remove unused variable.
+       - $_TITLE_ELT: Remove unused variable.
+       - man_set_resources(): Fix setting of $_DISPLAY_ARGS.
+       - main_display(): Fix description.  Remove $md_options.  Let
+       $MANOPT override system variables.
+
+2006-09-16  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.26
+
+       ### Simplification of main_set_mode()
+
+       * groffer2.sh:
+       - _get_first_prog() of main_set_mode(): Rewrite this function
+       such that it does not have an output, but set the variables
+       $_DISPLAY_PROG and $_DISPLAY_ARGS.
+       - _check_prog_on_list() of main_set_mode(): Rename and rewrite
+       _check_X_prog().  Suitable for being called for $_VIEWER_<mode>_X
+       and $_VIEWER_<mode>_TTY.  No output, but set the variables
+       $_DISPLAY_PROG and $_DISPLAY_ARGS.
+       - _obj_set_vars() of main_set_mode(): Remove this function.  It is
+       no longer necessary because its variables are set by the other
+       functions.
+       - _get_prog_args() of main_set_mode(): New function that
+       simplifies the loop in main_set_mode() and handles both
+       $_VIEWER_<mode>_X and $_VIEWER_<mode>_TTY.
+       - _process_mode() of main_set_mode(): Remove this function.
+       - main_set_mode(): Remove case for calling _process_mode().  In
+       the loop, use _get_prog_args() for simplification.
+       - main_parse_args(): Make --<mode>-viewer equivalent to
+       --<mode>-viewer-tty to make _process_mode() unnecessary.
+       - $_VIEWER_BACKGROUND: Start with `no'.
+
+       ### Extend the documentation
+
+       * groffer2.sh:
+       - Environment Variables: Add information on the naming of
+       variables in functions.
+       - $_ADDOPTS_POST, $_ADDOPTS_X: Remove these unused variables.
+       - apropos_setup(), apropos_setup (), base_name(), dir_name(),
+       echo1(), echo2(), func_check(), func_pop(), func_push(),
+       is_greater_than(), list_append(), list_from_split(),
+       _manpath_add_sys() of manpath_add_lang_sys(), rm_tree(),
+       special_filespec(), special_setup(), tmp_create(), to_tmp_line(),
+       usage(), version(), where_is_prog(), main_set_mode():
+       Fix and extend the description.  Many other function descriptions
+       were just fixed without being mentioned.
+       - landmark 7: man_*(): Add information on the search of `man'
+       pages.
+
+       * groffer.man:
+       - GNU `man' option overview: Add --location, --no-location, and
+       --where.
+       - GNU `man' options: Add the GNU `man' long options that are
+       accepted by `groffer', but just ignored.
+       - MAN PAGE SEARCHING: Correct and extend this section.
+
+       * TODO:
+       - Remove entry on function headers.
+       - Remove entry on GNU `man' options.
+       - Remove entry on search algorithm for `man' pages.
+
+       ### Other fixes
+
+       * groffer2.sh:
+       - man_get(): On `man' page search with given name and section
+       handle also files with extension when no files without extension
+       are found.
+
+2006-09-11  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.25
+
+       ### Version information
+
+       * groffer2.sh:
+       - version(): Add groffer to the version information; replace the
+       call of `groff --version'.
+
+       ### Configuration Files
+
+       * groffer.sh: Fix the configuration handling by removing all
+       quotes.  Arguments are ended by the end of the line.
+
+       * groffer.man: Fix the section on the configuration files.
+
+       ### Options
+
+       * groffer2.sh:
+       - $_OPTS_GROFF_SHORT_NA: Add `-k' as new groff option.
+       - main_pars_args(): Add X options `--ft', `--bordercolor',
+       `--borderwidth'.
+       - usage(): Add `--debug-filenames'.  Remove `*-viewer-tty'.
+       Correct first line after call of version().
+       - main_parse_MANOPT(): Fix `-h', `-t', and `-u' as options without
+       argument.
+
+       * groffer.man:
+       - Add documentation to `--fn', `--ft', `--bordercolor',
+       `--borderwidth'.
+       - Remove the `--*-viewer-tty' options.  These options are still
+       supported by the groffer program, but they aren't needed any
+       more.
+
+       ### soelim: Allow manpath and compressed files in .so requests, as
+       ### man does.
+
+       * groffer2.sh:
+       - $_FILESPEC_IS_MAN: New variable for storing if a filespec is for
+       searching a man page.
+       - to_tmp(): Rewrite. For existing file as filespec argument, add
+       call of `soelim' with the corresponding `-I dir' before the call
+       of `grog'.  For man paged, uncompress and store the files from .so
+       requests; replace the requests with the stored file names.
+       - _do_man_so() of to_tmp(): New function to handle the file of a
+       .so request.
+       - man_get(): For man pages without extension, add special search
+       strategy.
+
+       * README: Add the .so handling to the Compatiblity section.
+
+       ### Print file names debug
+
+       * groffer2.sh:
+       - $_OPT_LOCATION: Replace this variable by
+       $_DEBUG_PRINT_FILENAMES.
+       - register_file(): Move file name printing and call to basename to
+       register_title().
+       - _do_man_so() of to_tmp(): Add file name printing for man pages.
+
+       ### modes
+
+       * groffer2.sh:
+       - $_DEFAULT_MODES: New set of default modes in the sequence 'pdf',
+       'html', 'ps', 'x', 'dvi', and 'tty'.  That is done because the `x'
+       mode viewers `gxditview' and `xditview' are very bad programs.
+       - _make_pdf() of main_display(): If pdf format can not be
+       generated use Postscript mode (ps) instead for display.
+       - $_PDF_DID_NOT_WORK, $_PDF_HAS_PS2PDF, $_PDF_HAS_GS: New
+       variables for pdf mode to avoid several runs.
+       - $_VIEWER_TTY_TTY, $_VIEWER_TTY_X: Add these variables for the
+       viewers in tty mode.
+       - main_display(): Rewrite tty mode by using where_is_prog() to add
+       options to `less' from the command line.
+
+       * groffer.man:
+       - Add this information.
+       - Adjust the viewers in `SEE ALSO'.
+
+       ### Check viewer option for programs running in X Window
+
+       * groffer2.sh:
+       - _check_X_prog() of main_set_mode(): New function for checking if
+       a program of a command line argument is in the list for X for this
+       mode.
+       - _get_first_prog() of main_set_mode(): Use where_is_prog();
+       change the output to the same 3-element list as _check_X_prog().
+       - _obj_set_vars() of main_set_mode(): New function for setting
+       some variables in several modes.  Argument is the 3-element list
+       from _check_X_prog() or _get_first_prog().
+       - _process_mode() of main_set_mode(): Remove part with
+       list_has_not_prog().  This is better done by _check_X_prog().
+       - main_set_mode(): Use _check_X_prog() in different modes.
+       Correct several modes.  Add reset of $_VIEWER_BACKGROUND at the
+       beginning of the loop of default modes.
+
+       ### Allow man pages with space characters
+
+       * groffer2.sh:
+       - man_is_man(): Fix grep calls.
+       - list_from_file(): New function that reads the lines of a file as
+       list elements.
+       - man_get(): Fix `case' applications by double-quoting all
+       variables.  Use list_from_file() instead of setting with `cat'.
+       Add further tests.
+       - _do_man_so() of to_tmp(): Use list_from_file() instead of
+       setting with `cat'.
+
+       ### Allow program names with space
+
+       * groffer2.sh:
+       - is_prog(), is_not_program(): Change to exactly one argument with
+       possible spaces and arguments.  Fix all calls.
+       - where_is_prog(): Change to exactly one argument.  Change
+       variable prefix to `wip'.  Rewrite it to support programs with
+       spaces and arguments.  Return a list with 3 elements: the
+       program's directory, the program name, and the given arguments.
+       - main_display(): Correct tty mode.
+
+       ### Further fixes
+
+       * groffer2.sh:
+       - main_setup(): Fix func_check.
+       - clean_up(): Add variable to avoid several prints.
+       - where_is_prog(): Remove possible arguments from program
+       argument.
+       - obj_from_output(): As return value take the return value of the
+       called function.
+       - is_not_empty(): Rename of is_non_emtpy().
+       - $_VIEWER_BACKGROUND: Rename $_VIEWER_TERMINAL and reverse its
+       values.
+       - list_has_prog(), list_has_not_prog(): Remove these functions,
+       they are no longer needed.
+
+       * groffer.man:
+       - Add `--print' in OPTION OVERVIEW.
+       - Correct many entries with the non-breaking `\%' construct.
+
+2006-07-28  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.24
+
+       ### Extent long option abbreviation to abbreviations before each `-'.
+
+       * groffer2.sh:
+       - list_from_cmdline_with_minus(): New function, the same as
+       list_from_cmdline() with multiple abbreviations around `-'.
+       - _search_abbrev(): Subfunction of list_from_cmdline_with_minus().
+       - main_parse_args(): Use list_from_cmdline_with_minus() for
+       getting the double abbreviation, but keep main_parse_MANOPT()
+       to list_from_cmdline() for simple abbreviation of long options.
+       - For the debug test at the beginning, add the double abbreviation
+       functionality.
+
+       * README_SH, groffer.man: Document the multiple set of
+       abbreviations by `-'.
+
+       ### Fix handling of `--apropos*' and `--whatis'
+
+       * groffer2.sh:
+       - apropos_filespec(): Fix handling of `/' and `.' in sed; add `\&'
+       at the beginning of each non-macro groff line in sed.
+       - main_parse_args(): Set $_MAN_OPT to `yes' if --whatis is called.
+       - main_do_fileargs(): Fix dealing with `apropos' for several
+       cases.
+       - apropos_*(), special_*(), whatis_*(): Add two different return
+       values.
+       - $_SPECIAL_SETUP: New variable to test whether apropos_setup() or
+       whatis_header() had been run.
+       - Add language locale to --whatis, the `whatis' program does not
+       support this.
+
+       ### Handle several macro packages
+
+       * groffer2.sh:
+       - $_MACROS: New variable to store the actual macro package.
+       - $_MACRO_PACKAGES: New variable for the full macro packages of
+       groff (man, mdoc, me, mm, mom, ms).
+       - to_tmp(): Add test for different macro packages.  Ignore files
+       with a different one.
+       - main_do_fileargs(): Add different macro check before doing man
+       pages.
+
+       ### Rewrite the man page search
+
+       * groffer2.sh:
+       - $_MAN_SEC_CHARS, $_MAN_SEC_LIST: New variables from $_MAN_SEC.
+       Add these to man_setup().
+       - man_get(): New function that finally gets the man page or man
+       pages for a filespec.  Avoid double files.
+       - man_is_man(): New function that checks whether a name goes as
+       man page.
+       - manpath_add_lang_sys(): Fix handling of language addition for
+       short language names.
+       - main_parse_args(): Move handling of `-' to main_do_fileargs().
+       - do_filearg(), man_do_filespec(), man_register_file(),
+       man_search_section(): Remove these functions.
+       - main_do_fileargs(): Rewrite this function together with
+       the removed functions.
+       - list_uniq(): New function to remove the multiple elements from a
+       list.
+
+       ### Version handling.
+
+       * version.sh: New file for $_PROGRAM_VERSION, $_LAST_UPDATE, and
+       $_GROFF_VERSION_PRESET.
+
+       * groffer.sh:
+       - Add running of version.sh with `.'.
+       - Remove $_PROGRAM_VERSION and $_LAST_UPDATE.
+       - Run groffer2.sh with `.' instead of `exec'.  This allows to have
+       groffer2.sh without executive access permission.
+       - Determine $_BEFORE_MAKE by @VERSION@, use this variable on more
+       places.
+
+       * groffer2.sh:
+       - Remove executive access permission.
+       - version(): Write a version information without calling groff.
+
+       * Makefile.sub:
+       - Add version.sh.  Use $(INSTALL_DATA) instead of
+       $(INSTALL_SCRIPT) for version.sh and groffer2.sh.
+       - Add $(DESTDIR) to some elements of `sed' call in `groffer:'.
+
+       ### viewers for different modes
+
+       * groffer2.sh:
+       - $_VIEWER_HTML_X: Add `epiphany' as browser.
+       - $_VIEWER_PDF_X: Add `kpdf' and `evince' as pdf viewer for X.
+       Make `kpdf', `acroread', `evince', and `xpdf' the first automatic
+       pdf viewers for X because they support searching.  Add `gpdf'.
+       - $_VIEWER_PS_X: Add `kpdf' and `evince' as ps viewer for X; make
+       `kpdf' the first automatic ps viewer for X because it supports
+       searching even for Postscript.
+
+       ### pdf mode
+
+       * groffer2.sh:
+       - _make_pdf() of main_display(): add `ps2pdf' as secondary
+       transformer.
+       - main_set_resources(): Allow setting of resolution for `xpdf'
+       only if option -z is not set for `xpdf'.
+
+       ### Revise $_VIEWER_*
+
+       * groffer2.sh:
+       - $_VIEWER_<mode>_TTY: Add this variable to each mode even if it
+       is only empty.
+       - $_VIEWER_<mode>_X: Rename $_VIEWER_<mode> to this for each
+       mode.
+
+       ### Other fixes
+
+       * groffer2.sh:
+       - is_empty_file(): New function.
+       - obj_from_output(): Quote arguments by building a list.
+       - path_list(): Output path list with unique elements.
+       - where_is_prog(): Rename where_is().  Handle all file names
+       having a slash somewhere instead of only those that start with a
+       slash.
+       - $_REG_TITLE_LIST: Replace $_REGISTERED_TITLE and make it a
+       list.
+       - $_OPT_TITLE: Make it a list with at most 1 element.
+       - Remove double quotes in case patterns.
+       - _func_test(): For the function test at the beginning, add this
+       function for output check with $() construct.
+       - usage(): Add --shell.
+       - $_VIEWER_HTML_X: Add `firefox' and `mosaic'.
+       - list_get(): Remove this unused function.
+       - Fix func_check() calls in all functions.
+
+       * groffer.sh: Adjust groff version to 19.3.
+
+       * README: Add information list of the source files.
+
+2006-02-26  Claudio Fontana  <address@hidden>
+
+        * Makefile.sub: Add DESTDIR to install and uninstall targets
+        to support staged installations.
+
+2005-09-14  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.23
+
+       ### Increase the speed for the search of man pages
+
+       Run `find' on all man directories and ask this with `grep' instead
+       of scanning through many `ls'.
+
+       * groffer2.sh:
+       - $_TMP_MAN: New variable with the name of the file that stores
+       the `find' of the man path.
+       - $_TMP_MANSPEC: New variable with the name of the file that
+       stores the man page file names for each filespec.
+       - man_setup(): Do the `find' of the man path with $_TMP_MAN.
+       - man_do_filespec(): Add creation of $_TMP_MANSPEC.
+       - man_search_section(): Rewrite it to use $_TMP_MANSPEC.
+
+       * TODO: The demand on the increase of speed for man pages is now
+       removed.
+
+       ### Increase speed by enhancement of debug
+
+       * groffer.sh: $_BEFORE_MAKE: New variable that stores whether the
+       @...@ constructs are still available or already transformed by
+       `make'.
+
+       * groffer2.sh:
+       - $_DEBUG_FUNC_CHECK: New debug variable that regulates the check
+       calls at the beginning and end of most functions done by the
+       functions func_<name>().  By default, this is enabled before the
+       run of `make', and disabled after.  $_DEBUG_STACKS and
+       $_DEBUG_USER_WITH_STACK enable this variable automatically.
+       - --debug-func: New option for setting $_DEBUG_FUNC_CHECK.
+       - usage(), main_parse_args(): Add information for --debug-func.
+       - func_<name>(): Disable these functions if $_DEBUG_FUNC_CHECK is
+       not `yes'.
+
+       * groffer.man:
+       - Add information on --debug-func.
+       - Move the sections on options for development to the end of
+       option processing.
+
+       ### Fixes of man page search
+
+       - man_search_section(): Repair it such that extensions do not
+       occur in the directory name.
+       - manpath_set_from_path(): Rewrite it.  Add `.../MAN/...'
+       subdirectories additionally to `.../man/...'.
+       - manpath_add_lang_sys(): Rewrite it to overwrite _MAN_PATH by
+       systems parameter if any.  Then _MAN_PATH is prepended by the
+       language part.
+       - _manpath_add_sys(): New subfunction of manpath_add_lang_sys() to
+       handle the systems part.
+       - man_search_section: Fix it to handle section names that have
+       more than one character (an extension).
+       - $_MAN_PATH: Now stores man path as a list.  This is done in
+       man_setup() and manpath_set_from_path(), and used in
+       manpath_add_lang_sys().
+       - $_MAN_SYS: Now stores man systems parameter as a list.  This is
+       done in man_setup() and used in manpath_add_lang_sys().
+       - $_MAN_SEC_DONE, $_MAN_SYS_DONE, $_MAN_LANG_DONE: Remove these
+       variables.
+
+       ### Reorder the beginning of groffer2.sh
+
+       * groffer2.sh:
+       - func_<name>(): Move these functions to the functions in
+       alphabetical order.
+       - main_init(): Move "Test for compression" to this function.
+       - Move the "System Test" and function landmark() to the beginning
+       "Test of rudimentary shell functionality".  Change landmarks 1 and
+       2 to new positions.
+
+       ### Fix the mode when not in X
+
+       * groffer2.sh:
+       - main_parse_args(): Accept modes even when not in X, hoping for a
+       program given by option.  Add $_OPT_VIEWER_<MODE>_TTY.  Remove
+       $_VIEWER_TERMINAL.
+       - main_set_mode(): Add a section to set $_VIEWER_TERMINAL and move
+       the value of $_OPT_VIEWER_<MODE>_TTY to $_OPT_VIEWER_<MODE>.  When
+       not in X and no terminal programs are set remove $_OPT_MODE.  All
+       unknown programs are treated as terminal programs.
+       - usage(): Comment out options --<mode>-viewer-tty.  They exist
+       and are handled by `groffer', but they are no longer documented.
+       - $_OPT_VIEWER_<MODE>_TTY: New variables for option
+       --<mode>-viewer-tty.
+       - $_DEFAULT_MODE, $_VIEWER_<MODE>: Change it from , separation to
+       a list.  Rewrite _get_first_prog() of main_set_mode() to get
+       around with this.
+
+       * groffer.man: Remove information on --<mode>-viewer-tty.
+
+       ### Debug
+
+       * groffer2.sh:
+       - $_DEBUG_PRINT_FILENAMES: New variable for printing the file
+       names that are displayed by `groffer'.
+       - --debug-filenames: The corresponding option.  It is used in
+       man_register_file(), register_file(), and main_parse_args().
+
+       * groffer.man: Add information on --debug-filenames.
+
+       ### Other changements
+
+       * groffer2.sh:
+       - is_greater_than(): New function.  Use it where suitable.
+       - lists_combine(): New function to combine several lists to a
+       single list.
+       - list_from_split(): Rewrite it to output a list with quoted
+       elements.
+       - list_has_prog(), list_has_not_prog(): New functions to check the
+       list on an element that starts with a given word.
+       - obj_from_output(): Use this function at many places instead of
+       `var="$(...)"'; this makes the usage of exit_test() unnecessary.
+       - path_clean(): Fix assignment.
+       - path_list(): Rename path_split().
+       - tmp_create(): Add check of temporary file.
+       - usage(): Fix.
+
+       * README_SH:
+       - Fix section `Error handling'.
+       - Add section `Speed'.
+
+2005-08-22  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.22
+
+       ### `--whatis'
+
+       Produce a `groff' output and allow wild cards on filespec
+       parameters for `--whatis'.
+
+       * groffer2.sh:
+       - $_FILESPEC_ARG: New variable for storing the actual filespec
+       parameter.
+       - main_do_fileargs(): Set $_FILESPEC_ARG and add
+       what_is_filespec().
+        - main_parse_args(): Add --all to --whatis.
+       - to_tmp_line(): New function to write the arguments to the
+       temorary cat file.
+       - whatis_filename(): Rename of what_is().  Construct a better
+       printout using $_FILESPEC_ARG.  Repair the sed sequneces.
+       - whatis_filespec(): New function to print the filespec once
+       during the `whatis' process.
+       - whatis_header(): New funtion for printing the header of the
+       `whatis' output.
+
+       * groffer.man: Revise the documentation of --whatis.
+
+       ### `--apropos*'
+
+       Produce `groff' for `--apropos*'.  Allow `--sections' for
+       `--apropos', ignore it  with `--apropos-*'.
+
+       * groffer2.sh:
+       - --apropos*: Make these options without argument.
+       - $_APROPOS_PROG: New variable for the program that is is used for
+       `apropos'.
+       - $_APROPOS_SECTIONS: New variable to determine the sections that
+       are filtered out of `apropos' output depending on `--apropos-*'.
+       - apropos_filespec(): Handling of apropos at the filespec level.
+       - apropos_run(): Remove it.
+       - apropos_setup(): New function.
+       - main_set_mode(): Remove handling of $_OPT_APROPOS*.
+
+       * groffer.man:
+       - Revise the documentation of `--apropos*'.
+       - Split section 'options for GNU man' into two sections `options
+       for man pages' and `long options taken over from GNU man'.
+       - Move `--apropos*', `--whatis', `--man', and `--no-man' to
+       section `options for man pages'.
+
+       ### special display (apropos and whatis)
+
+       * groffer2.sh:
+       - special_setup(): New function that chooses the setup between
+       apropos and whatis.
+       - special_filespec(): New function that does the output at the
+       filespec level for apropos or whatis.
+
+       ### handle `--sections' for man page searching
+
+       * groffer2.sh:
+       - man_do_filespec(): Use $_OPT_SECTIONS of --sections instead of
+       $_MAN_AUTO_SEC if non-empty.  If a section was given on the
+       filespec parameter $_OPT_SECTIONS is ignored.  This differs from
+       `man' which always uses the restricted sections of --sections.
+       This function works for both normal man page search and whatis.
+       - apropos_filespec(): Use --sections for --apropos, but not for
+       --apropos-* because these provide already their own sections.
+
+       ### wildcards in filespec arguments
+
+       * groffer2.sh: Wildcards are now accepted.  In `--apropos*' and
+       `--whatis' they are interpreted as wildcard search elements; but
+       in normal display they are only handled as their own character.
+
+       ### development; new option
+
+       * groffer2.sh:
+       - --print: New option that prints just its argument for parameter
+       check.
+       - usage(): Add new option.
+       - $_OPT_DO_NOTHING: New variable for do_nothing().  Handle it at
+       the end of main_parse_Args().
+
+       * groffer.man: Add information on --print.
+
+       ### safe exit
+
+       * groffer2.sh:
+       - error(): Always exit with $_ERROR.
+       - exit_test(): New function to exit when first exit was hidden by
+       ().  Call it after each $().
+
+       ### automatic shell determination
+
+       * groffer.sh:
+       - If no option --shell is given perform a test of several shells
+       to automatically start some shell for groffer2.sh.  `ksh' is used
+       first because it can be safely terminated by Ctrl-C.
+       - This can be cancelled by providing --shell=''.
+       - Add test on `sed' program.
+
+       * groffer.man: Revise information on --shell.
+
+       ### trap
+
+       * groffer2.sh:
+       - trap_set(): Remove argument.  Instead of $_ALL_EXIT use only
+       signal 0.
+       - trap_unset(): Rename trap_clean().  Instead of $_ALL_EXIT use
+       only signal 0.
+       - $_ALL_EXIT: Remove this variable.
+       - Replace all direct `trap' calls by trap_set().
+
+       * README_SH: New section `Bugs' on `trap'..
+
+       ### user errors, error output without function stack
+
+       * groffer2.sh:
+       - error_user(): New function for user errors.
+       - error(): Remove call of clean_up() because the trap will do it
+       with the exit.  Remove the `kill' commands.  Create a temporary
+       file `.error' that can be tested by exit_test() for a better exit
+       test (especially for shell `ksh').
+       - $_DEBUG_USER_WITH_STACK: New variable to enable function stack
+       output in error_user().
+       - list_from_cmdline(), list_single_from_abbrev(), main_set_mode():
+       Use error_user().
+
+       ### test modes on X and tty
+
+       * groffer2,sh:
+       - is_X(), is_not_X(): New functions for checking on X Window.
+       - $_VIEWER_HTML_TTY, $_VIEWER_HTML_X: New variables that split
+       $_VIEWER_HTML.  Add `galeon'.
+       - main_parse_args(): Allow mode change for graphical modes only
+       when in X Window.
+       - _do_display() of main_display(): Create a special run for
+       viewers that run on the terminal; `lynx' is the only one so far.
+
+       ### add $GROFFER_MODE to command line
+
+       * groffer.sh:
+       - After the handling of the configuration files integrate
+       $GROFFER_OPT to the command line.
+       - This makes a `set' in the shell determination unnecessary.
+
+       * groffer2.sh:
+       - The debug test gets simpler because quotes are vanished without
+       $GROFFER_OPT.
+       - main_parse_MANOPT(): Prepend $mpm_list to the command line.
+       - main_parse_args(): `set' is unnecessary.
+
+       ### debug; new options
+
+       * groffer2.sh:
+       - --debug-all, --debug-lm, --debug-params, --debug-shell,
+       --debug-stacks, --debug-tmpdir, --debug-user: New options.
+       - --debug: Enable all debug variables except $_DEBUG_STACKS and
+       $_DEBUG_LM.  By the new options the smallest abbreviation is now
+       `--debug'.
+       - $_DEBUG_STACKS: Rename $_DEBUG.
+       - $_DEBUG_PRINT_TMPDIR: New debug variable for printing the name
+       of the temporary directory in main_init().
+       - $_OPT_DEBUG: Remove this variable because debug is handled at
+       the early part of the script.
+       - clean_up(): Enlarge $_DEBUG_KEEP_FILES to not deleting the
+       temporary directory.
+       - usage(): Move all development options on a section of its own.
+       - Move the test of rudimentary shell functionality at the
+       beginning of the script.  Add test on `sed'.
+       - Follow this by the debug section.  The determination of all
+       --debug* options can be done without a function.
+
+       * groffer.man: Revise information on --debug and add new options.
+
+       ### variables
+
+       * groffer.sh:
+       - $_ERROR: Move the definition of this variable here.
+       - $_GROFF_VERSION: New variable, is set over @...@ construct.
+       - $_OUTPUT_FILE_NAME: Move this variable to groffer2.sh.
+
+       * groffer2.sh:
+       - $_MAN_AUTO_SEC_LIST: Rename $_MAN_AUTO_SEC because it represents
+       a list.
+       - $_MAN_AUTO_SEC_CHARS: New read-only variable for storing
+       $_MAN_AUTO_SEC_LIST in [] construct.  Use it in man_do_filespec()
+       and whatis_filename().
+       - $_SPACE_CASE: New read-only variable with [] on space characters
+       with \ for `case' patterns.  Use it in several functions.
+       - $_SPACE_SED: New read-only variable with [] on space characters
+       for `sed'.  Use it in several functions.
+
+       ### options and display
+
+       * groffer2.sh:
+       - list_from_cmdline(): Add test whether the same abbreviation is
+       part of long options with and without arguments.  Give handling of
+       `=' a `case' pattern of its own.
+       - main_display(): Remove unnecessary calls of `clean_up' in order
+       to use `mozilla' without problems.  In _do_display(): Fix -X by
+       providing a different process when $_DISPLAY_PROG is empty.
+       - main_set_mode(): Accept options for viewers as is, without check
+       for program.  Add test whether no program is given for a mode.
+       This avoids unnecessary empty $_DISPLAY_PROG in main_display().
+
+       ### viewer programs that run on the terminal (tty); new options
+
+       * groffer2.sh:
+       - $_VIEWER_TERMINAL: New variable that stores whether a viewer was
+       supposed to run on tty.
+       - --dvi-viewer-tty, --html-viewer-tty, --pdf-viewer-tty,
+       --ps-viewer-tty, --tty-viewer-tty, --X-viewer-tty, --x-viewer-tty,
+       --www-viewer-tty: New options for viewers that run on a terminal.
+       - main_parse_args(), _do_display() of main_display(): Use the new
+       options and the new variable.
+       - usage(): Add the new options.
+
+       * groffer.man: Add information on options --*-viewer-tty.
+
+       ### other fixes
+
+       * groffer2.sh:
+       - _do_display() of main_display(): Bear errors of `groff' run.
+       - is_not_file: Fix to have exactly one argument.
+       - is_not_prog(): Handle no arguments.
+       - list_has_not(): Fix.
+       - main_do_fileargs(): Remove $mdfa_exitcode.
+       - register_title(): Limit title to 4 elements.
+       - version(): Print the version information to standard output just
+       like `groff' does.
+       - --no-special: New option to disable former calls of `--all',
+       `--apropos*', and `whatis.
+       - --title: Make it an option with argument.
+
+2005-08-07  Keith Marshall  <address@hidden>
+
+       * contrib/groffer/Makefile.sub (install): Reference groffer2.sh
+       as $(srcdir)/groffer2.sh, so it will install when building in a
+       different directory from the source.
+
+2005-08-02  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.21
+
+       ### @...@ constructs
+
+       * groffer.sh:
+       - $_AT: New variable for `@'.
+       - @...@: Replace the @...@ constructs by variables _AT_..._AT.
+       These constructs are transformed by `make' to useful information.
+       Keep all of these constructs in the first part of groffer.sh.  For
+       a run before a `make' call, the script sets these variables to
+       special values for testing purpose.
+       - $_GROFFER_LIBDIR: Variable pointing to the groffer library
+       directory @libdir@/groff/groffer.
+
+       ### Configuration files
+
+       * groffer.sh:
+       - Add test for `$()' construct.
+       - Read and transform the configuration files and execute the
+       emerging commands.  The `sed' script was heavily enlarged to
+       handle line with spaces and quotes.  The emerging script is now
+       called by `eval', so no temporary file is needed.
+       - $_CONF_FILE_ETC, $_CONF_FILE_HOME: New variables for the config
+       files.
+       - $_SQ, $_SP: Move variables for characters before the handling of
+       the configuration files.  Rename $_SQUOTE to $_SQ and $_SPACE to
+       $_SP.
+       - $GROFFER_OPT: Remove cleaning of this variable before the
+       reading of the configuration files.
+
+       * groffer2.sh:
+       - main_init(): Remove the getting of the configuration files.
+
+       ### Rewrite the shell determination
+
+       * groffer.sh:
+       - Get rid of all functions in `groffer.sh'.  Rewrite the shell
+       determination with `` and $().
+       - --shell: Shortest abbreviation is `--sh'.  Allow arguments for
+       the shell name.
+       - Allow an empty argument for --shell as shell name to overwrite a
+       specified shell; an empty shell name gets back to the default
+       shell.
+       - The shell determination now inludes the full handling of the
+       config files.  The `--shell' option needs no longer a line
+       starting with `-'.
+
+       ### Test of unset
+
+       * groffer.sh:
+       - Remove test of `unset'.
+       - Remove all calls of `unset'.
+       - Use one character names for all variables that are meant to be
+       local in this script.
+
+       * groffer2.sh:
+       - Move the test of `unset' to the testing of rudimentary shell
+       functionality without change.
+
+        ### Allow abbreviations for long options
+
+       * groffer2.sh:
+       - list_has_abbrev(): New function for checking a list having an
+       element with a given abbreviation.
+       - list_get_single_from_abbrev(): New function to retrieve the
+       element having a given abbreviation.
+       - list_from_cmd_line(): For an option abbreviation determine the
+       corresponding long option.
+       - From the man option lists remove the elements that are also in
+       a groffer list.
+       - Allow abbreviation for the early test of --debug.
+
+       * groffer.sh: Allow abbreviation for the early test on --shell.
+       - get_opt_shell(): Rewrite _get_opt_shell() and the shell test
+       around it.
+       - test_on_shell(): Rename function _test_on_shell().
+       - $_SHELL: global variable for the shell to run groffer2.sh.
+
+       ### Get rid of `sh -c'
+
+       * groffer2.sh:
+       - main_display(), _do_display(): Remove the `sh -c' calls.  Make
+       the cleanup working without it.
+       - _do_display(): Extend _do_display() such that it can be used for
+       the pdf mode as well.
+       - _make_pdf(): New subfunction of main_display() for running the
+       additional parts of pdf mode in _do_display().
+       - rm_file(), rm_file_with_debug(), rm_tree(): New functions for
+       removing files and directories.
+
+       ### Change directory
+
+       * groffer2.sh:
+       - $_START_DIR: New variable to store the directory at the starting
+       time of the script.
+       - main_display(): Go to the groffer temporary directory to be able
+       to process internal `groff' data like pictures.
+       - clean_up(): Get back to the starting directory.
+
+       ### Compatibility with strange shells
+
+       * groffer2.sh:
+       - clean_up(): `zsh' and `posh' had difficulties with `eval'.
+       - is_*(): Add test on empty argument.  Some shells return true on
+       `test -d' etc. with empty argument, while most shells return
+       false.
+       - echo1(); New function to print single line `cat <<EOF'.  Replace
+       all `echo x' by `echo1'.
+       - list_has_abbrev(), list_from_cmdline(): Correction.
+       - main_parse_MANOPT(): Repair and revise.
+       - --do-nothing: New option without output (for development).
+       - Rewrite rudimentary shell functionality near the beginning of
+       the script.
+
+       * groffer.sh, groffer2.sh:
+       - Remove `;' after the commands `if', `while', and `until'.
+
+       ### Debugging information
+
+       * groffer2.sh:
+       - $_DEBUG_PRINT_PARAMS: New variable for printing all parameters
+       from the config files, $GROFFER_OPT, and command line after they
+       have been transformed.
+       - $_DEBUG_PRINT_SHELL: New variable for printing the name of the
+       shell found in groff.sh.
+       - main(): Move the landmarks of main-*() into main().
+
+       ### Further checks and additions
+
+       * groffer.sh, groffer2.sh:
+       - $_PROGRAM_NAME: Replace this variable by `groffer'.  The program
+       name is now stable.
+       - $_GROFFER_RUN: Remove this variable.  As `groffer.sh' or
+       `groffer' is no longer rerun, this variable is not necessary any
+       more.
+
+       * groffer2.sh:
+       - main_set_resources(): Make the default viewers capable to use
+       arguments in the list.
+       - leave(): Add an argument for given exit code.  Use it where
+       suitable in main_*().
+       - do_filearg(): Add error messages for non-existing files and man
+       pages.
+       - _do_opt_V(): New subfunction of main_display() to handle the
+       output for option `-V'.  `groff -V' is greatly enlarged by
+       `groffer' specific information.
+       - register_title(): Handle file names with spaces.  Replace spaces
+       by `_'.
+       - is_existing(): Add `test -c' for special files.
+       - usage(): Add `=arg' to the options with an argument.  Add option
+       `--tty-viewer'.
+       - kghostview: In the default viewer list, add option
+       `--scale=1.45'.
+       - $_OPTS_CMDLINE_SHORT_NA: Correct a lacking space.
+
+       * Makefile.sub: Repair the installation instructions for
+       groffer2.sh.
+
+       * groffer.man:
+       - Add paragraph on option handling.
+       - Add option `--do-nothing'.
+       - Reorder option for development and `groff'.
+       - Rewrite documentation for option `-V'.
+       - Expand `--shell'.
+       - Reformulate sections CONFIGURATION FILES, COMPATIBILITY and SEE
+       ALSO.
+       - Make `man' italic where possible.
+       - .copyleft: Adjust the fonts.
+
+       * README: Update sections `Output' and `Compatibility'.
+
+       * README_SH:
+       - Add `mksh' as compatible shell.
+       - Add information on the scripts after the split.
+
+       * TODO: Remove some fulfilled parts.
+
+       * ChangeLog: Remove final spaces.
+
+2005-07-30  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.20
+
+       ### Split groffer.sh into two files groffer.sh and groffer2.sh.
+
+       * groffer.sh:
+       - Remove the second part of this script.  It is now in
+       groffer2.sh.
+       - $_GROFFER2_SH: New variable to point to the installed position
+       of `groffer2.sh'.  This position is presented using @address@hidden
+
+       * groffer2.sh: New script containing the second part of
+       groffer.sh. This script will be installed in the groffer library
+       directory @libdir@/groff/groffer, this might be
+       /usr/local/lib/groff/groffer/groffer2.sh for example.
+
+       * Makefile.sub:
+       - `groffer': Add replacement of @address@hidden
+       - `install_data': Add the installation of the groffer library
+       directory and groffer2.sh.
+       - `uninstall_sub': Delete the installed `groffer2.sh' and the
+       groffer library directory.
+
+       * README_SH:
+       - Remove the function list.
+       - Add argument options to the list of used commands.
+       - Documentation of the splitting of the script.
+       - Document the possible abbreviation of options.
+
+2005-07-07  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.19
+
+       * groffer.sh: extensions
+       - `mode x': Mode for the equivalent options `--x', `--mode x',
+       `--X' `--mode X', and the default mode.  The default assumes a
+       resolution of 75 dpi.  The default device for a resolution of 75
+       dpi is `X75-12', the default device for a resolution of 100 dpi is
+       `X100'.  The default geometry for the resolution of 100 dpi is set
+       to the width 800 dpi.
+       - `mode X': New mode for option -X only.
+       - `-V': Extent the `groff' output of -V by `groffer' specific
+       information (in main_display()).
+       - register_file(): Replace title `-' by `stdin'.
+       - $_DEBUG_KEEP_FILES: If set to `yes' the files in the temporary
+       directory are not deleted before the end trap.
+
+       * groffer.sh: get `zsh' to work as well
+       - tmp_create(): Use `: >file' for generating an empty file.
+       - rmdir: Replace `rmdir' by `rm -f -r'.
+       - eval: Add `eval' to many commands with variable arguments.
+
+       * groffer.sh: repair `debug'
+       - Print all debug output to stderr.
+       - $_FUNC_STACK: Built function call stack even when $_DEBUG is not
+       set.  Now the arguments are not added.
+       - $_DEBUG: If set to `yes' print 3 call stack events: the function
+       that is added with its arguments is printed with `+++ '
+       (func_push()); the call stack after the addition is printed with
+       `>>> ' (func_push()); the call stack after the removing is printed
+       with `<<< ' (func_pop()).
+       - error(): Always print the function call stack on errors.
+
+       * groffer.sh: Corrections
+       - $_groffer_run: Rename to $_GROFFER_RUN.
+       - $unset: Rename to $_UNSET.
+       - Repair test of `unset'.
+       - Repair test for `--shell'.  The script is now rerun under the
+       shell specified in the option argument.  This can increase the
+       speed.
+
+       * README_SH: `zsh' now works.
+
+       * groffer.man:
+       - Reformulate the information for the `groffer' specific details
+       of option `-V'.
+       - Add information on the debug process.
+       - Add information on the default devices in `x mode'.
+       - Minor corrections.
+
+2005-07-01  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.18
+
+       * groffer.sh: further shell compatibility
+       - `echo': Remove options and possible options of `echo' by
+       preceding the argument with a character `x' that is removed by
+       `sed' or replace `echo' by `cat <<EOF'.  `echo -n' seems to be not
+       portable, so it is omitted.
+       - `for': Remove `;' from within `for' (because of ksh).
+       - `ls': Old UNIX systems echoed the error message to standard
+       output.  So handle the output with `sed'.  If the output contains
+       `not found' map it to an empty string.
+       - `true': Replace `true' by command `:'.  Remove test of `true'
+       (because `ash' refuses the redefinition of builtins even in an
+       unreachable `if' branch).
+       - `false': Remove test of `false'; it isn't used any more.
+       - `test': As `test -e' does not exist in Solaris 2.5 replace it by
+       `test -f || test -d'.
+       - `unset': `unset' is said to be not portable.  As `ash' protests
+       against the definition of the function `unset()' in the test of
+       `unset' replace the test by defining `$unset' to `unset' if it
+       exists and to `:' otherwise.  Use `eval $unset' instead of the
+       direct command `unset'.
+       - _get_opt_shell(): Replace `for' loop with `shift' by `while'.
+       - man_search_section(): Replace `for f in filename*' by a test on
+       the existence of `filename*'.
+       - `zsh' interprets `$...'  as `"$..."'.  So `eval' must be called;
+       This cannot be used in `for i in $f', so it must be rewritten as
+       `for i in $(eval set x $f; shift; echo "$@")'
+
+       * groffer.sh:
+       - `--X', `--x', `--mode=X', `--mode=x': Make these options
+       equivalent to choosing an X device by setting `-TX75-12'.  `-X' is
+       still equivalent to `groff -X'.
+       - main_init(): Choose the name of the temporary file by adding a
+       number using `expr' if it exists and cannot be removed.
+       - main_parse_args():Repair some options by replacing `$mpa_mode'
+       by `$_OPT_MODE'.
+       - catz(): Rename it to cat_z() to avoid problem with existing
+       programs.
+       - where(): Rename to where_is().
+       - $_CONFFILES: Rename to $_CONF_FILES.
+       - $_HAS_BZIP: export and preset it.
+
+       * groffer.man:
+       - Document the `X mode' changes.
+       - Add address@hidden@' to `troff'.
+
+       * README, README_SH, TODO:
+       - Add date line `Latest update:'.
+       - Add `...' quoting to essential terms.
+       - Add Emacs mode at the end.
+
+       * README_SH:
+       - Add documentation on the above compatibility changes.
+       - Add documentation on used commands.
+       - Mention the tested shells.
+
+       * Makefile.sub:
+       Readd address@hidden@'.
+
+2005-06-23  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.17
+
+       * groffer.sh: get rid of `local' in functions (it is not POSIX)
+       - Replace local variables by variable names with a special prefix
+       that is an abbreviation of the corresponding function name (quasi-
+       local variables).
+       - Unset the quasi-local function variables before returning.
+       - _t_e_s_t_f_u_n_c_(): Remove tests for local and global
+       variables.
+       - Add quasi-local variables for saving the content of
+       single-character variables.
+       - Remove some unused local and global variables.
+       - Several variables were forgotten to make local.  They are now
+       made quasi-local.
+
+       * groffer.sh: other corrections
+       - $return_var: New function (after `eval') for an arbitrary
+       return value.
+       - obj*(): Add return modes.
+       - Rewrite tests for `true' and `false'.
+       - Add function names to error calls where it was forgotten.
+       - `for': Replace `for x in "$@"' by `for x'.
+       - `set': Replace `set -- ...' by `set x ...; shift'.
+       - `sed': Replace `\|.*|s|...|...|' by `s|...|...|'.
+
+       * README_SH:
+       - Add information on the removing of `local'.
+       - New section for non-POSIX shell restrictions.
+
+2005-06-20 Keith Marshall
+
+       * README-SH: Information of `Portable shells' in info autoconf.
+
+2005-06-19  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.16
+
+       * groffer.sh: Place each `then', `else', and `do' on a line of its
+       own because some shells do not support the mixture mode.
+
+       * groffer.man: Add section `BUGS'.
+
+       * README_SH:
+       - Add compatibility information.
+       - Correct documentation for function arguments.
+
+2005-06-18  Keith Marshall
+
+       * groffer.sh: $_NULL_DEV: Replace /dev/null by $_NULL_DEV which is
+       either /dev/null or NUL if /dev/null does not exist.
+
+2005-06-17  Zvezdan Petkovic
+
+       * Makefile.sub: $(RM): Define it to `rm -f' because not all `make'
+       programs have it predefined.
+
+2005-06-16  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.15
+
+       * Makefile.sub:
+       - Use `$(RM)'.
+       - Use `sed -f $(SH_DEPS_SED_SCRIPT)'.
+
+2005-05-20  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.14
+
+       * groffer.man: correction of non-hyphenation
+
+2005-05-17  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.13
+
+       * groffer.sh:
+       - $_VIEWER_DVI: Add `kdvi'.
+       - $_VIEWER_PDF: Add `kghostview', `ggv', and `kpdf'.
+       - $_VIEWER_PS: Add `kghostview' and `ggv'.
+       - $_modefile: For the output file name, add extension .ps for ps
+       mode and .dvi for dvi mode.  This exists already for the html and
+       pdf modes.
+       - Update some parts of the documentation.
+
+       * README, README_SH:
+       - Move some parts on usage from README_SH to README.
+       - Reformulate several parts of both files.
+
+       * groffer.man: update
+
+2005-05-14  Keith Marshall
+
+       * groffer.sh:
+       - first line: Add space to `#! /bin/sh'.
+
+2004-11-15  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.12
+
+       * groffer.sh:
+       - main_init(): Rewriting of the creation of the temporary
+       directory to ensure that it cannot be made writable apart from the
+       user.  If the directory already exists and cannot be removed then
+       append `X' to the directory name.
+       - is_non_empty_file(): fix it to use POSIX `test -s'.
+       - is_existing(): new function.
+       - POSIX `rm -f -r': use this in `clean_up()' and `main_init()'.
+       - `--macro-file': remove this unused long option.
+       - `-V', `--source', `--device': move these from groff options
+       to groffer options.
+       - `$_TMP_DIR_SUB': remove this unused variable.
+
+2004-06-15  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.11
+
+       * groffer.sh:
+       - To the search of the `--apropos-*' options, add man pages with a
+       subsection in their apropos output.
+
+2004-06-02  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.10
+
+       * groffer.sh:
+       - Remove automatic call of `ash' due to inconsistencies of
+       different ash versions.
+       - In the first run, add recognition of `--shell' lines in the
+       groffer configuration files.  To configure an external shell in
+       a configuration file, a line starting with `--shell' is
+       necessary.
+       - list_from_cmdline(): Simplify the arguments.
+       - As $POSIXLY_CORRECT is internally set to `y' by some GNU
+       `/bin/sh' shells the following 2 fixes are necessary:
+       -- `sed': Empty patterns are not allowed with $POSIXLY_CORRECT
+       set; so move the address information before the `s' command to the
+       pattern after the command, and write `.*' to the address field.
+       -- list_from_cmdline(): Remove the strange $POSIXLY_CORRECT style
+       to finish the option processing after the first non-option
+       argument; use the flexible GNU mixing of options and file names
+       instead.
+
+       * groffer.man:
+       - Remove any hints on `ash'.
+       - Add minus line behavior of `--shell' for configuration and add a
+       corresponding example.
+       - Update the information on $POSIXLY_CORRECT.
+
+2004-05-29  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.9
+
+       * groffer.sh:
+       Fix first run section to allow the starting shell to go on if
+       `ash' is not available.
+
+       * groffer.man:
+       Remove unnecessary information on groffer version.
+
+2004-05-12  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.8
+
+       * groffer.sh:
+       Fix problems of `test' by adding subs to arguments.
+
+       * groffer.man:
+       Write the file license as macros that are called in sections
+       AUTHOR and COPYING.
+
+       * .cvsignore:
+       Restore this file.
+
+2004-04-30  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.7
+
+       * groffer.sh:
+       - obj(), obj_data(), obj_from_output(), obj_set(): New object
+       oriented functions to minimize complicated `eval' commands.
+       - list_*(): Corrections.
+       - usage(): Streamlining.
+
+       * groffer.man, README_SH:
+       Corrections.
+
+2004-04-27  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.6
+
+       This version replaces the license of all files except ChangeLog of
+       the groffer source to the GNU General Public License (GPL) of the
+       version described in files COPYING and LICENSE in the groff top
+       source directory.
+
+       * groffer.man:
+       Changement from the GNU Free Documentation License (FDL) to
+       the GNU General Public License (GPL).
+
+       * README, README_SH, TODO:
+       Add license GNU General Public License (GPL).
+
+       * Makefile.sub, groffer.sh:
+       Keep the GNU General Public License (GPL), but refer to the
+       COPYING and LICENSE files.
+
+       * ChangeLog: Add a license in the style of Emacs ChangeLog file,
+       which is weaker than the GPL, but has its flavor.
+
+2004-04-24  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.5
+
+       This version is a rewrite of groffer in many parts, but it is kept
+       in the old single script style.
+
+       Overview of new options:
+       --text, --mode text, --tty-viewer,
+       --X, --mode X, --X-viewer, --html, --mode html, --html-view,
+       --apropos-data, --apropos-devel, --apropos-progs
+
+       New file:
+       <groffer-source>/README_SH
+
+
+       ******* Extension of the `apropos' handling
+
+        The output of man's `apropos' has grown immensely meanwhile, so it
+       has become inefficient.  Now `groffer' provides new options to get
+       the a selected information from this output.
+
+       * groffer.sh:
+        `--apropos-progs': new option for displaying only information
+        on programs (man page sections 1, 6, and 8)
+        `--apropos-data': new option for displaying only information
+        on documented data (man page sections 4, 5 and 7)
+        `--apropos-devel': new option for displaying only information
+        on development documentation (man page sections 2, 3 and 9)
+        `--apropos': still displays just the output of man's `apropos'
+       program.
+       - Specify all of these options as a single argument option; that
+       makes groffer's `--apropos' option slightly different because
+       the corresponding `man' option does not have arguments, but takes
+       all file arguments as apropos targets.  So just ignore the `man'
+       options `-k' and `--apropos' in the parsing of $MANOPT.
+       - Exit after processing one `apropos' call.
+
+
+       ******* Quasi object oriented function arguments
+
+       An object is the name of an environment variable.  The value of
+       this variable contains the object's content.  This allows to
+       specify function arguments and the calling syntax in a simpler way
+       by letting the first argument be a variable name, usable for input
+       or output.
+
+       Such an object type is `list', the string value of a shell
+       variable arranged in space-separated single-quoted elements, such
+       as $GROFFER_OPT internally.
+
+       * groffer.sh:
+       - Remove list_from_args(), list_element_from_arg()
+       list_from_lists(), list_length(), and list_prepend().
+       They can be replaced by list_append().
+       - All list*() functions are rearranged such that the first
+       argument is a list object, the name of a variable.
+
+
+       ******* Simplification of configuration files
+
+       The new syntax of the groffer configuration files is
+       - all lines starting with a `-' character are interpreted as
+       command line options for all calls of groffer; they are collected
+       and prepended to the actual value of $GROFFER_OPT; optional
+       spaces at the beginning.of the line are omitted.
+       - all other lines are interpreted as a shell command and executed
+       in the current shell of the groffer call.
+
+       Precedence:
+       - The command line and the external environment variables such as
+       $GROFFER_OPT of the groffer call have the highest precedence.
+       - This is overwritten by the configuration file in the user's home
+       directory.
+       - The system configuration file in /etc has the lowest
+       precedence.
+
+       * groffer.sh:
+       The configuration files are now called after the determination of
+       the temporary files in main_init().
+
+
+       ******* Script file name
+
+       The file name of the script is needed for the several calls during
+       the search for the optimal shell.
+
+       * groffer.sh:
+       - $_GROFFER_SH: replace $_this by $_GROFFER_SH and use $0 for
+       determining the file name of the script for the following calls,
+       instead of the cumbersome @BINDIR@ construction.
+       - Force the script to be called as an executable file, so $0 must
+       contain the program name.
+
+
+       ******* Improved temporary file names
+
+       Just like groff, groffer mixes all file parameters into a single
+       output file.  Its name is now constructed as a comma-separated
+       list built from the file name arguments without a leading comma.
+       So a leading comma can be used for the internal temporary file
+       names.
+
+       * groffer.sh:
+       - $_OUTPUT_FILE_NAME: new global variable as basis for the output
+       file name; it is set in main_set_resources().
+        - tmp_create(): use `,name' for temporary files different from
+       output file because the output file name does not start with a
+       comma.  `$$' is not needed anymore.
+       - main_display(): simplification of $_modefile in _do_display()
+       and single display modes.
+       - Add extension `.html' to output file name in html mode.
+       - base_name(): correction for strange positions of `/'.
+
+
+       ******* Mode fixes
+
+       * groffer.sh:
+       - Set the main default mode to `x' with groff's X Window viewer
+       `gxditview'.
+       - Allow 'x' and 'X' in `--mode' for the X Window mode; the same
+       for `--x' and `X', `--x-viewer' and `--X-viewer'.
+       - Make groff's `-X' equivalent to `mode X'.
+       - Fix `--auto', `--mode auto',  and `--default-modes'.
+       - `html' mode: new mode equivalent to `www', add `konqueror' and
+       `lynx' as viewers.
+       - `pdf' mode: fix zoom options for pdf-viewer `xpdf' in
+       main_set_resources(); in main_display() fix the display structure.
+       - Set default X Window resolution to 75dpi.  This is not optimal,
+       but with a higher value the options and resources for some viewers
+       must be optimized.
+       `--text' and `--mode text': new option for text output without a
+       pager.
+       - `--tty-viewer': new option equivalent to `--pager'.
+       - Correct the pagers for `tty' mode.
+       - Fix `groff' mode in main_set_resources() and main_display().
+       - Harmonize `--mode arg' with the equivalent options `--arg'.
+
+
+       ******* Fixes for command line options
+
+       * groffer.sh:
+       - list_from_cmdline(): fix the parsing of options with arguments.
+       - Rename $_OPT_TTY_DEVICE to $_OPT_TEXT_DEVICE.
+       - $_OPTS_X_*: new variables for the inhereted X Window variables.
+       - Improve the distribution of the command line options into
+       $_OPTS_GROFFER_*, $_OPTS_GROFF_*, $_OPTS_X_*, and $_OPTS_MAN_*.
+       - $_OPTS_MANOPT_*: new variables for the parsing of $MANOPT.
+       - Correct $_OPTS_CMDLINE_*.
+       - Remove some unused $_OPTS_*.
+       - `--iconic': new option from `-iconic' of the X Window toolkit.
+       - Correct `--rv' to an option without argument.
+       - Minor fixes of other  X Window toolkit options.
+
+
+       ******* Other fixes
+
+       * groffer.sh:
+       - is_prog(): allow 0 arguments.
+       - is_not_writable(): new function.
+       - is_*(): fix trailing return codes.
+        - Replace most `test' calls by is_*() functions.
+       - man_setup(): due to bugs in `manpath', prefer
+       manpath_set_from_path() for the determination of the man page path.
+       - man_search_section(): correction of some `for' loops.
+       - Remove export of external non-groffer variables.
+
+
+       ******* Documentation
+
+       * groffer.man:
+       - Reorder the option details according to the option origin as
+       groffer, groff, X, and man options.
+       - Add the programming changes information mentioned above.
+       - Support man pages with a dot in their name
+
+       * README_SH: new file
+       Move large parts of the documentation in `groffer.sh' into this
+       file.
+
+       * groffer.sh: usage():
+       - Change the output for `--help' to standard output.
+       - Restructure the information for this help output.
+
+
+       ******* Removement of the author's email address
+
+       Because of the extreme spam attacks, the author removed all
+       occurencies of his email address in every file of the groffer
+       source.
+
+2003-01-22  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.4
+
+       * groffer.sh: corrections for some restrictive shells
+       - Possible exit codes in actual `ash' are between 0 and 63.  To
+       handle even deeper restrictions, use 7 as maximal code instead
+       of 255 as replacement for error -1.
+       - Remove variables $_BAD2 and $_BAD3.
+       - Replace `trap' argument `EXIT' by 0 and write new fuctions
+       `trap_clean' and `trap_set' to handle the restrictions of `trap'
+       for some shells.
+       - Correct wrong $MANPATH to $_MAN_PATH in function
+       `man_do_filespec'.
+       - Test existence of directory before deleting it in the
+       `clean_up' definitions.
+       - Correct help output in `usage' (called by `--help').
+
+       * TODO:
+       Remove mention of `shoop' and `apropos'.
+
+2002-10-21  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.3
+
+       * groffer.sh: new temporary subdirectory
+       - Generate temporary subdirectory for storing temporary files
+       with better names in future groffer versions (name:
+       "groffer$$" in usual temporary directory).
+       - Use `umask 000' for temporary files to allow cleaning up
+       for everyone after a system break.
+       - Change both clean_up() functions (for normal shell and
+       for main_display() subshell) to handle the new subdirectory.
+       - clean_up_secondary() and $_TMP_PREFIX are unnecessary now, so
+       they were removed.
+
+       * Makefile.sub: `sed' commands for "groffer:"
+       - Remove "@g@" entry (not used in "groffer.sh").
+       - Add global replace for "@BINDIR@" and "@VERSION@" for future
+       usage.
+
+       * TODO: think about...
+       - writing part of groffer in C/C++.
+       - handling several files with different macro packages.
+
+2002-10-17  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * fixes of groffer 0.9.2
+
+       * groffer.sh:
+       Terminate main_parse_MANOPT() if $MANOPT is empty or consists
+       of space characters only.
+
+       * groffer.man: some fixes in "GROFFER OPTIONS"
+       - New macro ".Header_CB" for CB font in .TP headers; used for
+       definition of variables in option --mode.
+       - Fix some option references to refer to long options.
+
+       * README:
+       New file for general information on the groffer source; it is
+       not installed.
+
+2002-10-14  Bernd Warken <address@hidden>
+
+       * Makefile.sub:
+       add replacement "@BINDIR@" to "$(bindir)" for "groffer:"
+
+       * groffer.sh:
+       Define $_this as "@BINDIR@/${_PROGRAM_NAME}" to save the right
+       installation position of groffer for the special shell calling.
+
+       * groffer.man:
+       Remove double definition of filespec parameters.
+
+2002-10-13  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.2
+
+       * groffer.sh: fixes
+       - Fix some 'sed' functions: two in func_stack_dump(), one in
+         base_name(), add 'sed' command in list_from_cmdline().
+       - Finish main_parse_MANOPT() if $MANOPT is empty.
+       - Sort $_OPTS_GROFF_SHORT_NA like groff short options (but
+         unchanged).
+       - Fix some comments.
+
+       * groffer.man: make it more readable (but no additions)
+       - A shortened section "SYNOPSIS" is followed by a simplified
+         section "DESCRIPTION".
+       - The options from "SYNOPSIS" go to new section "OPTION
+         OVERVIEW" with all groffer options in a single subsection.
+       - The details of all groffer options are described in section
+         "GROFFER OPTIONS".
+       - New macro for file names ".File_name".
+       - "Option Parsing" is moved to section "COMPATIBILITY".
+       - Fix some "EXAMPLES".
+
+2002-09-30  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.1
+
+       * TODO: remove done entries
+       - Remove request for different shells.
+       - Remove the 'sed' complaints.
+
+2002-07-15  Bernd Warken <address@hidden>
+
+       * groffer.sh: replace `sed' interface by direct `sed'
+       - This improves the performance of the shell programming parts
+         and shortens the groffer script by about 5%.
+       - Remove functions: string_del_append(), string_del_leading(),
+         string_del_trailing(), string_flatten(), string_get_before(),
+         string_get_leading(), string_replace_all(), string_sed_s(),
+         and their auxiliary functions.
+       - Replace all calls of these functions by direct `sed' commands.
+       - Define variables for special characters to ease `sed' calls.
+       - Remove `$APPEND'.
+       - Restrict list_from_string() to single character separators.
+       - Correct list_check() and base_name().
+       - Add comments to all calls of `sed'.
+
+       * groffer.sh: add run-time support for several shells
+       - New option `--shell': stop execution and rerun groffer under
+         the shell specified in the argument of `--shell'.
+       - If no shell was specified at run-time, `ash' is tried first;
+         if `ash' is not available continue with the shell with which
+         groffer was called from the command line, or with the shell
+         name in the first line of the script, actually `/bin/sh'.
+
+2002-07-12  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * fixes for groffer 0.9.0
+
+       * groffer.sh: enhance version information
+       `groffer -v|--version' now print:
+       - groffer's version number and date
+       - the string `is part of '
+       - groff's version information (version number and copyright),
+         but not groff's `called subprograms' information.
+
+       * groffer.sh: minor fixes
+       - Fix the argument parser to process argument `-' correctly.
+       - Some display programs have trouble with empty input; feed a
+         line consisting of a single space character in this case for
+         all display modes (not for source or groff modes).
+
+       * TODO:
+       fix entry `shoop' (not 'shopt').
+
+2002-06-28  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.9.0
+
+       * groffer.sh: new mode `pdf'
+       - PDF (Portable Document Format):
+         -> Transform groff `ps' output into pdf using `gs'.
+         -> Pro: PDF viewers provide text searching (!).
+         -> Con: the transformation is quite slow.
+         -> Not suitable as an auto mode.
+       - New options `--pdf', `--pdf-viewer', `--mode pdf'.
+       - Standard pdf viewers `xpdf' and `acroread'.
+       - For `xpdf', choose zoom `z 3' for 100 dpi, `z 2' for 75 dpi.
+
+       * groffer.sh: support bzip2 decompression
+       - add test for `bzip2' with necessary options
+       - extend functions `catz()' and `save_stdin()'.
+
+       * TODO
+       remove entry on `bzip' decompression (done).
+
+       * groffer.man:
+       - Document new `pdf' features.
+       - Document new `bzip2' decompression.
+       - Fix documentation for `--auto-modes'.
+
+       * groffer.sh: minor fixes
+       - Improve device tests in `tty' and `dvi' modes.
+       - Internally, map mode `auto' to '' to facilitate tests.
+       - Fix auto mode sequence to: `ps,x,tty' as was intended.
+
+2002-06-25  Bernd Warken <address@hidden>
+
+       * groffer.sh:
+       Fix `source' mode.
+
+       * groffer.man:
+       Fix some indentations.
+
+2002-06-23  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.8
+
+       * Makefile.sub: add copyright section
+
+       * groffer.man:
+       - Document the new options.
+       - Revise the documentation of the modes.
+       - Document the configuration files in new section `FILES'.
+       - Redesign section `EXAMPLES'.
+       - Remove documentation for `-W'.
+
+       * groffer.sh: new debugging features
+       - Disabled by default; enabled by environment variables.
+       - Add landmark() to catch typos with quotes.
+       - Add a function call stack for suitable functions; implemented
+         as within the argument checker func_check().
+       - This implies the need to provide `return' with some clean-up
+         facility; implemented as `eval "$_return_..."'.
+       - Add option `--debug' to enable debugging at run-time.
+       - Actually, the groffer script uses only shell builtins found
+         in `ash' (a subset of POSIX) and POSIX `sed' as the only
+         external shell utility.
+
+       * groffer.sh: customization of viewers
+       - In `groff' mode, the groffer viewing facilities are disabled.
+       - The postprocessor option `-P' costumizes the viewer only in
+         some situations in the `groff' mode, so a new infrastructure
+         for viewer customization is necessary.
+       - Allow to specify arguments to the viewer programs specified
+         in `--*-viewer()'.
+       - Implement some of the essential X Toolkit resource options in
+         groffer, but with use a leading double minus.
+         -> `--bd': set border color.
+         -> `--bg', `--background': set background color.
+         -> `--bw': set border width.
+         -> `--display': set X display.
+         -> `--geometry': set size and position of viewer window.
+         -> `--fg', `--foreground': set foreground color.
+         -> `--ft', `--font': set font.
+         -> `--resolution': set X resolution in dpi.
+         -> `--title': set viewer window title.
+         -> `--xrm': set X resource.
+       - Remove misnamed option `--xrdb'.
+
+       * groffer.sh: new mode structure
+       - New Postcript mode `ps' (`--ps'):
+         -> default viewers: gv,ghostview,gs_x11,gs;
+         -> `--ps-viewer' sets the Postscript viewer.
+       - New mode `www' (`--www') for displaying in a web browser:
+         -> default browsers: mozilla,netscape,opera,amaya,arena;
+         -> `--www-viewer' sets the web browser.
+       - New dvi mode (`--dvi'); default viewer `xdvi':
+         -> default viewers: xdvi,dvilx;
+         -> `--dvi-viewer' sets the dvi viewer.
+       - New mode `auto':
+         -> active if no other mode is given or by new option `--auto';
+         -> selects from a sequence of modes that are tested until one
+           of them succeeds.
+         -> the default mode sequence is actually `ps', `x', `tty'.
+         -> `--default-modes' sets this mode sequence as a comma
+            separated string of program names, optionally each one
+            with arguments).
+       - New mode `groff':
+         -> process input like groff, ignore viewing options.
+         -> activated by new option `--groff'.
+         -> automatically active with one of `-V', `-X', `-Z'.
+       - Revise `tty' mode:
+         -> allow several text devices.
+         ->
+       - Reorganize the mode management:
+         -> new mode setting option `--mode'.
+         -> logically separate source, groff, and display modes.
+         -> intermediate output mode is now part of mode groff; remove
+            any special features around `-Z'.
+       - Update usage() to reflect the new option structure.
+
+       * groffer.sh: add configuration files
+       - `/etc/groff/groffer.conf' system-wide configuration.
+       - `${HOME}/.groff/groffer.conf' user configuration.
+       - The configuration file are shell scripts for now; later
+         implementations can identify this from the `#! /bin/sh' line.
+
+       * groffer.sh: new data structure `list':
+       - Implement a `list' data structure as a string consisting of
+         single-quoted elements, separated by a space character;
+         embedded single-quotes are escaped.
+
+       * groffer.sh: new option parser based on `list':
+       - Write new option parser based on `list', compatible to both
+         POSIX getopts() and GNU getopt().
+       - Long options are now available on GNU and non-GNU systems.
+       - Get rid of POSIX getopts() and GNU getopt().
+       - the `-W--longopt' construct is now obsolete; remove it.
+       - add test/function for `unset'.
+       - Option strings are now implemented as `list's in order to
+         allow unusual characters in options.
+       - Parse $MANOPT first; translate essential arguments into
+         groffer options.
+
+       * groffer.man:
+       - determine prompt length for `.Shell_cmd'* dynamically.
+       - naming scheme for static strings and registers changed to
+         `namespace:macro.variable'.
+
+
+2002-06-16  Werner Lemberg  <address@hidden>
+
+       * groffer.sh:
+       Implement man option `--ascii' by `-mtty-char'.
+
+
+2002-05-31  Werner LEMBERG  <address@hidden>
+
+        * groffer.man (@.Shell_cmd_width):
+       Increase to 4m (we use `sh#' as the prompt).
+
+
+2002-05-31  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.7
+
+       * groffer.sh: remove incompatibilities with the `ash' shell:
+       - do not use `!command':
+          -> use `else'
+         -> write `_not_' equivalents for some functions
+       - do not use `[^]' in `case':
+         ->  restructure some functions.
+       - only single-character names for loop variables:
+         -> spoils the paradigm of leading `_' for local variables.
+       - spurious trouble with `for i in ${var}':
+         -> use `eval set -- ${var}' and `for i in "$@"'
+       - do not change or use $IFS:
+         -> define new functions string_split() and `path_split()'.
+         -> result must be processed by `eval set --'.
+         -> solve conflicts with existing positional parameters.
+       - trouble with exporting external `$GROFF_*' variables:
+         -> hope that they were exported in the calling shell.
+       - not smart about additional blanks:
+         -> remove unnecessary white space.
+
+       * groffer.sh: improve run-time speed:
+       - `ash' more than doubles the speed of `bash'.
+       - speed-up `man_setup()'.
+
+
+2002-05-30  Werner Lemberg  <address@hidden>
+
+       * groffer.man:
+       - remove some wrong `\:'.
+       - rename macro names that start with a `[' (clashes with refer).
+       - fix TP_header.
+
+
+2002-05-28  Bernd Warken <address@hidden>
+       ________________________________________________________________
+       * release of groffer 0.6
+
+       This is almost a complete rewrite since groffer 0.5 .
+       ________________________________________________________________
+       * Documentation
+
+       * groffer.man:
+       - Apply the changes done in www.tmac (.URL and .MTO)
+       - Replace \fP by \f[].
+       - Redesign and rewrite most macros.
+       - Include the documentation for the new features.
+       - Greatly enlarge section ENVIRONMENT
+       - Add examples.
+
+       * TODO:
+       - Start a TODO file with several sections.
+
+       * ChangeLog:
+       Due to the many changes, shorten and rearrange the entries
+       since groffer 0.5 .
+       ________________________________________________________________
+       * Shell compatibility
+
+       * groffer.sh:
+       - Due to possible conflicts in old BSD versions, `[]' was
+         replaced by `test'; the `test' options `-a' and `-o' were
+         replaced by multiple calls of `test'.
+       - Write interface to the `sed' command `s' to become
+         independent of the delimiter character.  Rewrite all text
+         manipulating function to use this new scheme.  The new
+         functions are named `string_*'.
+       - `tr' is not needed any longer, replaced by `sed'.
+       - `grep' is not needed any longer, mostly replaced by `case'.
+       - Revision of test for `getopt'.
+       - Remove `set -a'; explicitly export variables.
+       - The only external programs used are POSIX `sed' and the
+         fallback to `apropos'.  All other program calls were
+         replaced by shell builtins and functions.
+
+       ________________________________________________________________
+       * Cosmetics
+
+       * groffer.sh:
+       - Implement a prefix based naming scheme for local variables
+         and functions (OOP-like).
+       - Introduce variables for white space (better readability with
+         $IFS).
+       - Store the names of the processed filespecs into a variable
+         instead of a temporary file.
+       - Error-prone shell constructions were replaced by functions
+         with a simple interface.
+       - To avoid too long pipes, replace supercat() by do_fileargs();
+         every input file is handled independently.
+
+       ________________________________________________________________
+       * New features:
+       - Add support for more X devices (e.g. X75-12 and X100-12).
+       - Add long option `--intermediate_output' to `-Z'.
+       - Make the options for mode selection clobber each other.
+       - Add option `--mode' with an argument having the following
+         values:
+         `X': force displaying in X, same as options `-X';
+         `tty': display with a pager on text terminal; same as `--tty';
+         `source', `default', `auto', etc.
+       - Make the handling of the X mode like in groff (e.g. -X -Tps).
+       - Make resolution for gxditview behave like groff (default
+         75 dpi).
+       - Add environment variable $GROFFER_OPT to preset groffer
+         options.
+
+       ________________________________________________________________
+       * implement most of the functionality of GNU `man'.
+
+       - Add all `man' long options to groffer.
+       - Add all `man' environment variables.
+       - Parse and use content of `$MANOPT'.
+       - The precedence of the options and environment variables
+         is regulated like in GNU `man'.
+       - Force the option `--manpath' to have a colon-separated
+         argument like GNU `man'.
+       - Support `man section name' calling convention.
+       - Remove all dependencies on `man -w'.
+
+       * groffer.sh:
+       - Add the new features above.
+       - Rewrite the search algorithm for man pages.
+       - Remove searching with `man -w' (problems with space
+         characters in file names).
+       - Fix and complement usage().
+       - The filespec parsers gets a function of its own do_manpage().
+
+
+2002-01-08  Bernd Warken <address@hidden>
+
+       * groffer 0.5 (beta) released
+
+       * groffer.man:
+       - Fix hyphenation problems with macros describing options.
+       - Fix the handling of some `-' characters.
+       - Examples of shell commands now print in font CR instead of CB.
+       - Remove documentation for option `-X'.
+       - Add documentation for option `--dpi'.
+
+       * groffer.sh:
+       - New method for creating temporary files, based on process
+         IDs.  This is reliable enough and suitable for GNU and POSIX.
+       - Run gxditview in a new shell instantiation for having a clean
+         handling of the temporary files when running in the
+         background.
+       - Revision of the retrieving method for the window title.
+       - Empty input is now tolerated.
+       - Export the variables that are set before the call of `set -a'.
+       - Function usage() corrected and updated.
+       - Unnecessary stuff removed.
+       - Comments adjusted.
+       - Pass option `-X' to groff, i.e. force X output with 75 dpi.
+       - Implement option `--dpi' for setting the resolution for the X
+         viewer, which had already been documented in earlier versions.
+
+2002-01-07  Bernd Warken <address@hidden> 
+
+       * groffer 0.4 (beta) released (as groff `contrib')
+
+       * groffer.man:
+       - New features documented.
+       - Macros stream-lined.
+       - Section EXAMPLES added.
+
+       * groffer.sh:
+       - System tests added/optimized.
+       - Speed/memory optimizations by defining some shell functions
+         alternatively depending on the text results.
+       - Use `gzip' for decompression instead of `zcat'.
+       - Signal handling added for clean exiting by `trap'.
+       - Temporary files exist only as long as necessary.
+       - Setup of path for man-pages moved after the option parsing.
+       - Fixed a bug in determining the path for man-pages.
+       - Fixed a bug in the handling of non-groffer options.
+
+       * New features:
+       - New option --tty for forcing paging on text terminal.
+       - New option --no-man for disabling the man-page feature.
+       - Implement reserved POSIX -W feature to simulate long options.
+       - gxditview is now run as a background process.
+
+2002-01-05  Werner LEMBERG  <address@hidden>
+
+        * Integrate groffer into groff's `contrib' tree.
+
+        * Makefile: Replaced by...
+        Makefile.sub: New file.
+
+        * groffer: Replaced by...
+        groffer.sh: New file.
+
+        * groffer.man (OptDef): Add missing backslashes.
+        Update copyright.
+
+2001-12-15  Bernd Warken <address@hidden>
+
+       * groffer 0.3 (alpha) released (still stand-alone package).
+
+       * GNU and POSIX are supported (POSIX without long options).
+
+       * New options : --man, --mandb, --title, --xrdb
+
+       * Support for command line arguments with embedded single space
+       characters (GNU only) .
+
+       * Several search methods for man-pages when no `man -w' is
+       available ($MANPATH, mandb, a default path).
+
+       * Language support for man-pages.
+
+       * Recognize the following filespecs as man-page parameters:
+         man:name(section), man:name, name.section, name.
+
+2001-12-03  Bernd Warken <address@hidden>
+
+       * Stand-alone package for groffer 0.2 (alpha) created
+       Files: groffer, groffer.man, Makefile, TODO, ChangeLog
+
+2001-12-02  Bernd Warken <address@hidden>
+
+       * groffer 0.2 (alpha) program released.
+
+       * Name changed from `groffview' to `groffer'.
+
+       * Comments added.
+
+       * Name changed from `groffview' to `groffer'.
+
+       * Options harmonized with groff.
+       New options : -Q --source, -T --device, -X .
+       Other options known from groff are passed unchanged.
+
+       * 100 dpi as default, 75 dpi only in emergency situations.
+
+       * Bugs with temporary files fixed.
+
+       * Code restructured and comments added.
+
+2001-11-28  Bernd Warken <address@hidden>
+
+       ***** groffview 0.1 (experimental) and groffview.man released
+       (predecessor of groffer, shell script)
+
+       * Options : -h --help, -v --version
+
+       * Search for man-pages based on $MANPATH
+
+       * development of `groffview' shell script started
+
+2001-11-28  Bernd Warken <address@hidden>
+
+       ________________________________________________________________
+       License
+
+       Copyright (C) 2001,2002,2003,2004,2005,2006
+       Free Software Foundation, Inc.
+       Written by Bernd Warken <address@hidden>.
+
+       Copying and distribution of this file, with or without
+       modification, are permitted provided the copyright notice and this
+       notice are preserved.
+
+       This file is part of `groffer', which is part of the `groff'
+       project.
+
+
+       Emacs settings
+
+       Local Variables:
+       mode: change-log
+       End:

Index: README_SH
===================================================================
RCS file: README_SH
diff -N README_SH
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ README_SH   11 Aug 2013 08:28:23 -0000      1.9
@@ -0,0 +1,297 @@
+README_SH
+
+Special description for the shell version of `groffer'
+
+
+The files related to the shell version are
+
+shell/groffer.sh       starting script of groffer
+shell/groffer2.sh      main script of groffer
+shell/groffer.man      manual page of groffer
+shell/README_SH                description of the shell version of the program
+shell/ChangeLog.0      information on all changements of groffer versions 0.*
+version.sh             script that handles the version information
+
+
+Scripts
+
+The shell version of `groffer' contains two files, `groffer.sh' and
+`groffer2.sh'.
+
+`groffer.sh' is a short introductory script without any functions.  I
+can be run with a very poor Bourne shell.  It just contains some basic
+variables, the reading of the configuration files, and the
+determination of the shell for `groffer2.sh'.  This script is
+transformed by `make' into `groffer' which will be installed into
address@hidden@, which is usually /usr/local/bin.
+
+`groffer2.sh' is a long main script with all functions; it is called
+by `groffer.sh' (`groffer' after installation).  It is installed
+unchanged into @libdir@/groff/groffer, which is usually
+/usr/local/lib/groff/groffer.  This script can be called with a
+different shell, using the `groffer' option `--shell'.
+
+
+Options
+
+The `groffer' script provides its own option parser.  It is compatible
+to the usual GNU style command line This includes long option names
+with two signs such as `--option', clusters of short options, the
+mixing of options and non-option file names, the option `--' to close
+the option handling, and it is possible to abbreviate the long option
+names.  The abbreviation of long options is enhanced by letting each
+internal `-' sign generate a new center of abbreviation.  So each
+command line argument starting with `--' can represent a multiple set
+of abbreviations.
+
+The flexible mixing of options and file names in GNU style is always
+possible, even if the environment variable `$POSIXLY_CORRECT' is set
+to a non-empty value.  This disables the rather wicked POSIX behavior
+to terminate option parsing when the first non-option command line
+argument is found.
+
+
+Error Handling
+
+Error handling and exit behavior is complicated by the fact that
+`exit' can only escape from the current shell; trouble occurs in
+subshells.  This was solved by adding a temporary error file that is
+tested by function exit_test() and by replacing `var=$(...)' by
+function obj_from_output().
+
+
+Function Definitions in `groffer2.sh'
+
+Each function in groffer2.sh has a description that starts with the
+function name and symbols for its arguments in parentheses `()'.  Each
+`<>' construction gives an argument name that just gives a hint on
+what the argument is meant to be; these argument names are otherwise
+irrelevant.  The `>' sign can be followed by another character that
+shows how many of these arguments are possible.
+
+<arg>      exactly 1 of this argument
+<arg>?     0 or 1 of these arguments
+<arg>*     arbitrarily many such arguments, incl. none
+<arg>+     one or more such arguments
+<arg>...   one or more such arguments
+[...]      optional arguments
+
+A function that starts with an underscore `_' is an internal function
+for some other function.  The internal functions are defined just
+after their corresponding function.
+
+
+External Environment Variables
+
+The groffer.sh script uses the following external system variables.
+It is supposed that these variables are already exported outside of
+groffer.sh; otherwise they do not have a value within the script.
+
+external system environment variables that are explicitly used
+$DISPLAY:              Presets the X display.
+$LANG:                 For language specific man pages.
+$LC_ALL:               For language specific man pages.
+$LC_MESSAGES:          For language specific man pages.
+$PAGER:                        Paging program for tty mode.
+$PATH:                 Path for the programs called (`:' separated list).
+
+groffer native environment variables
+$GROFFER_OPT           preset options for groffer.
+
+all groff environment variables are used, see groff(1)
+$GROFF_BIN_PATH:       Path for all groff programs.
+$GROFF_COMMAND_PREFIX: '' (normally) or 'g' (several troffs).
+$GROFF_FONT_PATH:      Path to non-default groff fonts.
+$GROFF_TMAC_PATH:      Path to non-default groff macro files.
+$GROFF_TMPDIR:         Directory for groff temporary files.
+$GROFF_TYPESETTER:     Preset default device.
+
+all GNU man environment variables are used, see man(1).
+$MANOPT:               Preset options for man pages.
+$MANPATH:              Search path for man pages (: list).
+$MANROFFSEQ:           Ignored because of grog guessing.
+$MANSECT:              Search man pages only in sections (:).
+$SYSTEM:               Man pages for different OS's (, list).
+
+
+Object-oriented Functions
+
+The groffer script provides an object-oriented construction (OOP).  In
+object-oriented terminology, a type of object is called a `class'; a
+function that handles objects from a class is named `method'.
+
+In the groffer script, the object is a variable name whose content is
+the object's data.  Methods are functions that have an object as first
+argument.
+
+The basic functions for object handling are obj_*().
+
+The class `list' represents an array structure, see list_*().
+
+
+Speed
+
+The major speed gain is the disabling of all debug features.  This is
+the default for the installed version of `groffer'.  Before the run of
+`make', the debug feature of $_DEBUG_FUNC_CHECK, corresponding to
+option --debug-func, is enabled by default.  The resulting heavy
+slowing down should be regarded as a temporary feature.
+
+Another increase of speed was the replacement of the many `ls' calls
+by analysing a `find' of manpath with `grep'.
+
+
+Shell Compatibility
+
+The `groffer' shell scripts are compatible to both the GNU and the
+POSIX shell and utilities.  Care was taken to restrict the programming
+technics used here in order to achieve POSIX compatibility as far back
+as POSIX P1003.2 Draft 11.2 of September 1991.  This draft is
+available at http://www.funet.fi/pub/doc/posix/p1003.2/d11.2 on the
+Internet.
+
+The POSIX draft does not include `local' variables for functions.  So
+this concept was replaced by global variables with a prefix that
+differs for each function.  The prefix is chosen from the function
+name.  These quasi-local variables are unset before each return of the
+function.
+
+For shell compatibility, see also Autobook, chapter 22.
+
+The `groffer' scripts were tested under the shells `ash', `bash',
+`bash-minimal', `dash', 'ksh', `mksh', `pdksh', 'posh', and `zsh'
+without problems in Linux Debian.  A shell can be tested by the
+`groffer' option `--shell', but that will run only with groffer2.sh.
+To start it directly from the beginning under this shell the following
+command can be used.
+
+  <shell-name> groffer.sh --shell=<shell-name> <argument>...
+
+
+Some shells are not fully POSIX compatible.  For them the following
+restrictions were done.  For more information look at the
+documentation `Portable shells' in the `info' page of `autoconf'
+(look-up in Emacs-Help-Manuals_Info).
+
+- The command parts `then', `else', and `do' must be written each on a
+  line of their own.
+
+- Replace `for i in "$@"' by `for i' and remove internal `;' (kah).
+
+- Replace `set -- ...' by `set x ...; shift'.  After the first
+  non-option argument, all arguments including those starting with `-'
+  are accepted as non-option.  For variables or `$()' constructs with
+  line-breaks, use `eval set' without quotes.  That transforms a
+  line-break within a variable to a space.
+
+- The name of the variable in `for' is chosen as a single character
+  (old ash).  The content of such variables is not safe because it can
+  also occur in other functions.  So it is often stored in an
+  additional quasi-local variable.
+
+- `echo' is not portable on options; some `echo' commands have many
+  options, others have none.  So `echo -n' cannot be used, such that
+  the output of each function has complete lines.  There are two
+  methods to avoid having `-' as the first character of any argument.
+  Either a character such as `x' can be prepended to the argument;
+  this must later on be removed by `sed'.  Otherwise, `echo' can be
+  replaced by `cat <<EOF'.
+
+- `ls' has problems.  Old UNIX systems echoed the error message to
+  standard output.  So handle the output with `sed'.  If the output
+  contains `not found' map it to an empty string.
+
+- As `test -e' is not available in Solaris 2.5 replace it by
+  `test -f || test -d'.
+
+- As `unset' is not supported by all shells replace it by `eval
+  ${_UNSET}' where this variable is `unset' if it exists and `:'
+  otherwise.
+
+- Some shells have problems with options in `eval'.  So quoting must
+  be done right to hide the options from `eval'.
+
+- In backquote calls `` avoid the backquote ` in comments.
+
+- Replace `true' by `:', `false' isn't used.
+
+- Do not redefine builtins as functions (ash).
+
+- Avoid `[^...]' in `case' patterns (ash).
+
+- `trap' does not allow error code 127.
+
+The scripts call the following commands with all options used:
+.
+:
+apropos
+break
+bzip2 -c -d -t
+cat
+catz
+cd
+continue
+echo
+eval
+expr
+grep
+groff -v
+grog -T -X -Z
+gs -c -d -f -q -s
+gzip -c -d -f
+less -r -R
+ls
+man -k --apropos
+mkdir
+mv
+pwd
+return
+rm -f -r
+rmdir
+sed -e -n
+set -e
+sh -c
+shift
+test -c -d -f -r -s -w -x
+trap
+umask
+unset
+
+
+Bugs
+
+If the `groffer' run is interrupted by Crtl-C the clean up is not done
+by all shells.  The `trap' commands work for the shells `bash',
+`bash-minimal', and 'ksh'; they do not work for `ash', `dash',
+`pdksh', `posh', and `zsh'.
+
+
+####### License
+
+Last update: 7 Feb 2011
+
+Copyright (C) 2003-2006, 2009, 2011
+  Free Software Foundation, Inc.
+Written by Bernd Warken <address@hidden>
+
+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/>.
+
+
+####### Emacs settings
+
+Local Variables:
+mode: text
+End:

Index: groffer.man
===================================================================
RCS file: groffer.man
diff -N groffer.man
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ groffer.man 11 Aug 2013 08:28:23 -0000      1.20
@@ -0,0 +1,4124 @@
+.TH GROFFER @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+groffer \- display groff files and man\~pages on X and tty
+.
+.SH "SYNOPSIS"
+.\" The .SH was moved to this place in order to appease `apropos'.
+.
+.\" --------------------------------------------------------------------
+.\" Legalese
+.\" --------------------------------------------------------------------
+.
+.de author
+This file was written by Bernd Warken <address@hidden>.
+..
+.de copyleft
+Copyright (C) 2001, 2002, 2004-2012
+ Free Software Foundation, Inc.
+.
+.P
+This file is part of
+.IR \%groffer ,
+which is part of
+.IR \%groff ,
+a free software project.
+.
+You can redistribute it and/or modify it under the terms of the
+.nh
+.B GNU General Public License
+.hy
+as published by the
+.nh
+.BR "Free Software Foundation" ,
+.hy
+either version 3 of the License, or (at your option) any later version.
+.
+.P
+You should have received a copy of the \f[CR]GNU General Public
+License\f[] along with
+.IR groff ,
+see the files \%\f[CB]COPYING\f[] and \%\f[CB]LICENSE\f[] in the top
+directory of the
+.I groff
+source package.
+.
+Or read the
+.I man\~page
+.BR gpl (1).
+You can also visit
+.nh
+.B <http://www.gnu.org/licenses/>.
+.hy
+..
+.
+.\" --------------------------------------------------------------------
+.\" Setup
+.\" --------------------------------------------------------------------
+.
+.ds Ellipsis "\&.\|.\|.\&\"
+.
+.\" --------------------------------------------------------------------
+.\" Macro definitions
+.
+.\" --------------------------------------------------------------------
+.\" .CB  (<text>...)
+.\"
+.\" Print in constant-width bold font.
+.\"
+.de CB
+.  ft CB
+.  Text \\$*
+.  ft
+..
+.\" --------------------------------------------------------------------
+.\" .CI  (<text>...)
+.\"
+.\" Print in constant-width italic font.
+.\"
+.de CI
+.  ft CI
+.  Text \\$*
+.  ft
+..
+.\" --------------------------------------------------------------------
+.\" .CR  (<text>...)
+.\"
+.\" Print in constant-width roman font.
+.\"
+.de CR
+.  ft CR
+.  Text \\$*
+.  ft
+..
+.\" --------------------------------------------------------------------
+.\" .Error  (<text>...)
+.\"
+.\" Print error message to terminal and abort.
+.\"
+.de Error
+.  tm \\$*
+.  ab
+..
+.\" --------------------------------------------------------------------
+.\" .Env_var  (<env_var_name> [<punct>])
+.\"
+.\" Display an environment variable, with optional punctuation.
+.\"
+.de Env_var
+.  nh
+.  SM
+.  Text \f[CB]\\$1\f[]\\$2
+.  hy
+..
+.\" --------------------------------------------------------------------
+.\" .File_name  (<path_name>)
+.\"
+.\" Display a file or directory name in CB font.
+.\"
+.de File_name
+.  Header_CB \\$@
+..
+.\" --------------------------------------------------------------------
+.\" .Header_CB  (<path_name>)
+.\"
+.\" Display a line in CB font, for example after .TP
+.\"
+.de Header_CB
+.  nh
+.  Text \f[CB]\\$1\f[]\\$2
+.  hy
+..
+.\"  --------------------------------------------------------------------
+.\" .Text  (<text>...)
+.\"
+.\" Treat the arguments as text, no matter how they look.
+.\"
+.de Text
+.  if \\n[.$]=0 \
+.    return
+.  nh
+.  nop \)\\$*\)
+.  hy
+..
+.\" --------------------------------------------------------------------
+.\" .Topic  ([<indent>])
+.\"
+.\" A bulleted paragraph
+.\"
+.de Topic
+.  ie \\n[.$]=0 \
+.    ds @indent 2m\"
+.  el \
+.    ds @indent \\$1\"
+.  IP \[bu] address@hidden
+.  rm @indent
+..
+
+.\" End of macro definitions
+.
+.
+.\" --------------------------------------------------------------------
+.\" SH "SYNOPSIS"
+.\" --------------------------------------------------------------------
+.
+.SY groffer
+.OP option \*[Ellipsis]
+.OP --
+.OP \%filespec \*[Ellipsis]
+.YS
+.
+.SY groffer
+.BR -h | --help
+.YS
+.
+.SY groffer
+.BR -v | --version
+.YS
+.
+.
+.\" --------------------------------------------------------------------
+.SH DESCRIPTION
+.\" --------------------------------------------------------------------
+.
+The
+.B \%groffer
+program is the easiest way to use
+.BR \%groff (@MAN1EXT@).
+It can display arbitrary documents written in the
+.I \%groff
+language, see
+.BR \%groff (@MAN7EXT@),
+or other
+.I \%roff
+languages, see
+.BR \%roff (@MAN7EXT@),
+that are compatible to the original
+.I \%troff
+language.
+.
+It finds and runs all necessary
+.I groff
+preprocessors, such as
+.BR @address@hidden .
+.
+.
+.P
+The
+.B \%groffer
+program also includes many of the features for finding and displaying
+the \%\f[CR]Unix\f[] manual pages
+.nh
+.RI ( man\~pages ),
+.hy
+such that it can be used as a replacement for a
+.BR \%man (1)
+program.
+.
+Moreover, compressed files that can be handled by
+.BR \%gzip (1)
+or
+.BR \%bzip2 (1)
+are decompressed on-the-fly.
+.
+.
+.P
+The normal usage is quite simple by supplying a file name or name of a
+.I \%man\~page
+without further options.
+.
+But the option handling has many possibilities for creating special
+behaviors.
+.
+This can be done either in configuration files, with the shell
+environment variable
+.Env_var \%$GROFFER_OPT ,
+or on the command line.
+.
+.
+.P
+The output can be generated and viewed in several different ways
+available for
+.IR \%groff .
+.
+This includes the
+.I \%groff
+native \%\f[CR]X\~Window\f[] viewer
+.BR \%gxditview (@MAN1EXT@),
+each
+.IR \%Postcript ,
+.IR \%pdf ,
+or
+.I \%dvi
+display program, a web browser by generating
+.I \%html
+in
+.IR \%www\~mode ,
+or several
+.I \%text\~modes
+in text terminals.
+.
+.
+.P
+Most of the options that must be named when running
+.B \%groff
+directly are determined automatically for
+.BR \%groffer ,
+due to the internal usage of the
+.BR \%grog (@MAN1EXT@)
+program.
+.
+But all parts can also be controlled manually by arguments.
+.
+.
+.P
+Several file names can be specified on the command line arguments.
+.
+They are transformed into a single document in the normal way of
+.BR \%groff .
+.
+.
+.P
+Option handling is done in \f[CR]GNU\f[] style.
+.
+Options and file names can be mixed freely.
+.
+The option
+.RB ` \-\- '
+closes the option handling, all following arguments are treated as
+file names.
+.
+Long options can be abbreviated in several ways.
+.
+.
+.\" --------------------------------------------------------------------
+.SH "OPTION OVERVIEW"
+.\" --------------------------------------------------------------------
+.
+.TP
+.I breaking options
+.RS
+.P
+.SY
+.OP -h\~\fR|\fB\~--help
+.OP -v\~\fR|\fB\~--version
+.YS
+.RE
+.
+.
+.TP
+.I \%groffer mode options
+.RS
+.P
+.SY
+.OP --auto
+.OP --default
+.OP --default\-modes mode1,mode2,\*[Ellipsis]
+.OP --dvi
+.OP --dvi\-viewer prog
+.OP --groff
+.OP --html
+.OP --html\-viewer prog
+.OP --mode display_mode
+.OP --pdf
+.OP --pdf\-viewer prog
+.OP --ps
+.OP --ps\-viewer prog
+.OP --source
+.OP --text
+.OP --to\-stdout
+.OP --tty
+.OP --tty\-viewer prog
+.OP --www
+.OP --www\-viewer prog
+.OP --x\~\fR|\fB\~--X
+.OP --x\-viewer\~\fR|\fB\~--X\-viewer prog
+.YS
+.RE
+.
+.
+.TP
+.I options related to \%groff
+.RS
+.P
+.SY
+.OP -T\~\fR|\fB\~--device device
+.OP -Z\~\fR|\fB\~--intermediate\-output\~\fR|\fB\~--ditroff
+.YS
+.P
+All further
+.B \%groff
+short options are accepted.
+.RE
+.
+.
+.TP
+.I options for man\~pages
+.RS
+.P
+.SY
+.OP --apropos
+.OP --apropos\-data
+.OP --apropos\-devel
+.OP --apropos\-progs
+.OP --man
+.OP --no\-man
+.OP --no\-special
+.OP --whatis
+.YS
+.RE
+.
+.
+.TP
+.I long options taken over from GNU man
+.RS
+.P
+.SY
+.OP --all
+.OP --ascii
+.OP --ditroff
+.OP --extension suffix
+.OP --locale language
+.OP --local\-file
+.OP --location\~\fR|\fB\~--where
+.OP --manpath dir1:dir2:\*[Ellipsis]
+.OP --no\-location
+.OP --pager program
+.OP --sections sec1:sec2:\*[Ellipsis]
+.OP --systems sys1,sys2,\*[Ellipsis]
+.OP --troff\-device device
+.YS
+.P
+Further long options of \f[CR]GNU\f[]
+.B man
+are accepted as well.
+.RE
+.
+.
+.TP
+.I X Window Toolkit options
+.RS
+.P
+.SY
+.OP --bd\~\fR|\fB\~--bordercolor pixels
+.OP --bg\~\fR|\fB\~--background color
+.OP --bw\~\fR|\fB\~--borderwidth pixels
+.OP --display X-display
+.OP --fg\~\fR|\fB\~--foreground color
+.OP --fn\~\fR|\fB\~--ft\~\fR|\fB\~--font font_name
+.OP --geometry size_pos
+.OP --resolution value
+.OP --rv
+.OP --title string
+.OP --xrm X\-resource
+.YS
+.RE
+.
+.
+.TP
+.I options for development
+.RS
+.P
+.SY
+.OP --debug
+.OP --debug\-all
+.OP --debug\-filenames
+.OP --debug\-func
+.OP --debug\-grog
+.OP --debug\-keep
+.OP --debug\-lm
+.OP --debug\-params
+.OP --debug\-shell
+.OP --debug\-stacks
+.OP --debug\-tmpdir
+.OP --debug\-user
+.OP --do\-nothing
+.OP --print text
+.OP --shell prog
+.OP -V
+.YS
+.RE
+.
+.
+.TP
+.I \%filespec arguments
+.RS
+.P
+The
+.I \%filespec
+parameters are all arguments that are neither an option nor an option
+argument.
+.
+They usually mean a file name or a
+.I man page
+searching scheme.
+.
+.
+.P
+In the following, the term
+.I section_extension
+is used.
+.
+It means a word that consists of a
+.I man section
+that is optionally followed by an
+.IR extension .
+.
+The name of a
+.I man section
+is a single character from
+.BR \%[1-9on] ,
+the
+.I extension
+is some word.
+.
+The
+.I extension
+is mostly lacking.
+.
+.
+.P
+No
+.I \%filespec
+parameters means standard input.
+.
+.
+.TP 10m
+.B -
+stands for standard input (can occur several times).
+.
+.
+.TP
+.I filename
+the path name of an existing file.
+.
+.
+.TP
+.BI man: name ( section_extension )
+.TQ
+.BI man: name . section_extension
+.TQ
+.IB name ( section_extension )
+.TQ
+.IB name . section_extension
+.TQ
+.I "section_extension name"
+search the \%man\~page
+.I \%name
+in the section with optional extension
+.IR section_extension .
+.
+.
+.TP
+.BI man: name
+\%man\~page in the lowest
+.I \%man\~section
+that has
+.IR \%name .
+.
+.
+.TP
+.I name
+if
+.I \%name
+is not an existing file search for the man\~page
+.I \%name
+in the lowest man\~section.
+.
+.RE
+.
+.
+.\" --------------------------------------------------------------------
+.SH "OPTION DETAILS"
+.\" --------------------------------------------------------------------
+.
+The
+.B \%groffer
+program can usually be run with very few options.
+.
+But for special purposes, it supports many options.
+.
+These can be classified in 5 option classes.
+.
+.
+.P
+All short options of
+.B \%groffer
+are compatible with the short options of
+.BR \%groff (@MAN1EXT@).
+.
+All long options of
+.B \%groffer
+are compatible with the long options of
+.BR \%man (1).
+.
+.
+.P
+Arguments for long option names can be abbreviated in several ways.
+.
+First, the argument is checked whether it can be prolonged as is.
+.
+Furthermore, each minus sign
+.B -
+is considered as a starting point for a new abbreviation.
+.
+This leads to a set of multiple abbreviations for a single argument.
+.
+For example,
+.B --de\-n\-f
+can be used as an abbreviation for
+.BR --debug\-not\-func ,
+but
+.B --de\-n
+works as well.
+.
+If the abbreviation of the argument leads to several resulting options
+an error is raised.
+.
+.
+.P
+These abbreviations are only allowed in the environment variable
+.Env_var \%$GROFFER_OPT ,
+but not in the configuration files.
+.
+In configuration, all long options must be exact.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "groffer breaking Options"
+.\" --------------------------------------------------------------------
+.
+As soon as one of these options is found on the command line it is
+executed, printed to standard output, and the running
+.B \%groffer
+is terminated thereafter.
+.
+All other arguments are ignored.
+.
+.
+.TP
+.B -h\~\fR|\fB\~--help
+Print help information with a short explanation of options to
+standard output.
+.
+.
+.TP
+.B -v\~\fR|\fB\~--version
+Print version information to standard output.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "groffer Mode Options"
+.\" --------------------------------------------------------------------
+.
+The display mode and the viewer programs are determined by these
+options.
+.
+If none of these mode and viewer options is specified
+.B \%groffer
+tries to find a suitable display mode automatically.
+.
+The default modes are
+.IR "mode pdf" ,
+.IR "mode ps" ,
+.IR "mode html" ,
+.IR "mode x" ,
+and
+.I "mode dvi"
+in \%\f[CR]X\~Window\f[] with different viewers and
+.I mode tty
+with device
+.I latin1
+under
+.B less
+on a terminal; other modes are tested if the programs for the main
+default mode do not exist.
+.
+.
+.P
+In \%\f[CR]X\~Window\f[],
+many programs create their own window when called.
+.B \%groffer
+can run these viewers as an independent program in the background.
+.
+As this does not work in text mode on a terminal (tty) there must be a
+way to know which viewers are \%\f[CR]X\~Window\f[] graphical
+programs.
+.
+The
+.B \%groffer
+script has a small set of information on some viewer names.
+.
+If a viewer argument of the command\-line chooses an element that is
+kept as \%\f[CR]X\~Window\f[] program in this list it is treated as a
+viewer that can run in the background.
+.
+All other, unknown viewer calls are not run in the background.
+.
+.
+.P
+For each mode, you are free to choose whatever viewer you want.
+.
+That need not be some graphical viewer suitable for this mode.
+.
+There is a chance to view the output source; for example, the
+combination of the options
+.B --mode=ps
+and
+.B --ps\-viewer=less
+shows the content of the
+.I Postscript
+output, the source code, with the pager
+.BR less .
+.
+.
+.TP
+.B --auto
+Equivalent to
+.BR --mode=auto .
+.
+.
+.TP
+.B --default
+Reset all configuration from previously processed command line options
+to the default values.
+.
+This is useful to wipe out all former options of the configuration, in
+.Env_var \%$GROFFER_OPT ,
+and restart option processing using only the rest of the command line.
+.
+.
+.TP
+.BI --default\-modes \ mode1,mode2,\*[Ellipsis]
+Set the sequence of modes for
+.I \%auto\~mode
+to the comma separated list given in the argument.
+.
+See
+.B --mode
+for details on modes.  Display in the default manner; actually, this
+means to try the modes
+.IR x ,
+.IR ps ,
+and
+.I \%tty
+in this sequence.
+.
+.
+.
+.TP
+.B --dvi
+Equivalent to
+.BR --mode=\%dvi .
+.
+.
+.TP
+.BI --dvi\-viewer \ prog
+Choose a viewer program for
+.IR \%dvi\~mode .
+.
+This can be a file name or a program to be searched in
+.Env_var $PATH .
+.
+Known \%\f[CR]X\~Window\f[]
+.I \%dvi
+viewers include
+.BR \%xdvi (1)
+and
+.BR \%dvilx (1).
+.
+In each case, arguments can be provided additionally.
+.
+.
+.TP
+.B --groff
+Equivalent to
+.BR --mode=groff .
+.
+.
+.TP
+.B --html
+Equivalent to
+.BR --mode=html .
+.
+.
+.TP
+.B --html\-viewer
+Choose a web browser program for viewing in
+.IR \%html\~mode .
+.
+It can be the path name of an executable file or a program in
+.Env_var $PATH .
+.
+In each case, arguments can be provided additionally.
+.
+.
+.TP
+.BI --mode \ value
+.
+Set the display mode.
+.
+The following mode values are recognized:
+.
+.RS
+.
+.TP
+.Header_CB auto
+Select the automatic determination of the display mode.
+.
+The sequence of modes that are tried can be set with the
+.B --default\-modes
+option.
+.
+Useful for restoring the
+.I \%default\~mode
+when a different mode was specified before.
+.
+.
+.TP
+.Header_CB dvi
+Display formatted input in a
+.I \%dvi
+viewer program.
+.
+By default, the formatted input is displayed with the
+.BR \%xdvi (1)
+program.
+.
+.
+.TP
+.Header_CB groff
+After the file determination, switch
+.B \%groffer
+to process the input like
+.BR \%groff (@MAN1EXT@)
+would do.
+.
+This disables the
+.I \%groffer
+viewing features.
+.
+.
+.TP
+.Header_CB html
+Translate the input into html format and display the result in a web
+browser program.
+.
+By default, the existence of a sequence of standard web browsers is
+tested, starting with
+.BR \%konqueror (1)
+and
+.BR \%mozilla (1).
+The text html viewer is
+.BR \%lynx (1).
+.
+.
+.TP
+.Header_CB pdf
+Display formatted input in a
+.I \%PDF
+(Portable Document Format) viewer
+program.
+.
+By default, the input is formatted by
+.B \%groff
+using the Postscript device, then it is transformed into the PDF file
+format using
+.BR \%gs (1),
+or
+.BR ps2pdf (1).
+If that's not possible, the
+.I Postscript mode (ps)
+is used instead.
+.
+Finally it is displayed using different viewer programs.
+.
+.I \%pdf
+has a big advantage because the text is displayed graphically and
+is searchable as well.
+.
+.
+.TP
+.Header_CB ps
+Display formatted input in a Postscript viewer program.
+.
+By default, the formatted input is displayed in one of many viewer
+programs.
+.
+.
+.TP
+.Header_CB text
+Format in a
+.I \%groff\~text\~mode
+and write the result to standard output without a pager or viewer
+program.
+.
+The text device,
+.I \%latin1
+by default, can be chosen with option
+.BR -T .
+.
+.
+.TP
+.Header_CB tty
+Format in a
+.I \%groff\~text\~mode
+and write the result to standard output using a text pager program,
+even when in \%\f[CR]X\~Window\f[].
+.
+.
+.TP
+.Header_CB www
+Equivalent to
+.BR --mode=html .
+.
+.
+.TP
+.Header_CB x
+Display the formatted input in a native
+.I roff
+viewer.
+.
+By default, the formatted input is displayed with the
+.BR \%gxditview (@MAN1EXT@)
+program being distributed together with
+.BR \%groff .
+But the standard \%\f[CR]X\~Window\f[] tool
+.BR \%xditview (1)
+can also be chosen with the option
+.BR --x\-viewer .
+The default resolution is
+.BR 75dpi ,
+but
+.B 100dpi
+are also possible.
+.
+The default
+.I groff
+device
+for the resolution of
+.B 75dpi
+is
+.BR X75\-12 ,
+for
+.B 100dpi
+it is
+.BR X100 .
+.
+The corresponding
+.I "groff intermediate output"
+for the actual device is generated and the result is displayed.
+.
+For a resolution of
+.BR 100dpi ,
+the default width of the geometry of the display program is chosen to
+.BR 850dpi .
+.
+.
+.TP
+.Header_CB X
+Equivalent to
+.BR --mode=x .
+.
+.
+.P
+The following modes do not use the
+.I \%groffer
+viewing features.
+.
+They are only interesting for advanced applications.
+.
+.
+.TP
+.Header_CB groff
+Generate device output with plain
+.I \%groff
+without using the special viewing features of
+.IR \%groffer .
+If no device was specified by option
+.B -T
+the
+.I \%groff
+default
+.B \%ps
+is assumed.
+.
+.
+.TP
+.Header_CB source
+Output the roff source code of the input files without further
+processing.
+.
+.
+.RE
+.
+.
+.TP
+.B --pdf
+Equivalent to
+.BR --mode=pdf .
+.
+.
+.TP
+.BI --pdf\-viewer \ prog
+Choose a viewer program for
+.IR \%pdf\~mode .
+.
+This can be a file name or a program to be searched in
+.Env_var $PATH ;
+arguments can be provided additionally.
+.
+.
+.TP
+.B --ps
+Equivalent to
+.BR --mode=ps .
+.
+.
+.TP
+.BI --ps\-viewer \ prog
+Choose a viewer program for
+.IR \%ps\~mode .
+.
+This can be a file name or a program to be searched in
+.Env_var $PATH .
+.
+Common Postscript viewers include
+.BR \%gv (1),
+.BR \%ghostview (1),
+and
+.BR \%gs (1),
+.
+In each case, arguments can be provided additionally.
+.
+.
+.TP
+.B --source
+Equivalent to
+.BR --mode=source .
+.
+.
+.TP
+.B --text
+Equivalent to
+.BR --mode=text .
+.
+.
+.TP
+.B --to\-stdout
+The file for the chosen mode is generated and its content is printed
+to standard output.
+.
+It will not be displayed in graphical mode.
+.
+.
+.TP
+.B --tty
+Equivalent to
+.BR --mode=tty .
+.
+.
+.TP
+.BI --tty\-viewer \ prog
+Choose a text pager for mode
+.IR tty .
+The standard pager is
+.BR less (1).
+This option is equivalent to
+.I man
+option
+.BR --pager=\fIprog\fP .
+The option argument can be a file name or a program to be searched in
+.Env_var $PATH ;
+arguments can be provided additionally.
+.
+.
+.TP
+.B --www
+Equivalent to
+.BR --mode=html .
+.
+.
+.TP
+.BI --www\-viewer \ prog
+Equivalent to
+.BR --html\-viewer .
+.
+.
+.TP
+.B --X\~\fR|\fB\~--x
+Equivalent to
+.BR --mode=x .
+.
+.
+.TP
+.BI --X\-viewer\~\fR|\fB\~--x\-viewer \ prog
+Choose a viewer program for
+.IR \%x\~mode .
+Suitable viewer programs are
+.BR \%gxditview (@MAN1EXT@)
+which is the default and
+.BR \%xditview (1).
+The argument can be any executable file or a program in
+.Env_var $PATH ;
+arguments can be provided additionally.
+.
+.
+.TP
+.B --
+Signals the end of option processing; all remaining arguments are
+interpreted as
+.I \%filespec
+parameters.
+.
+.
+.P
+Besides these,
+.B \%groffer
+accepts all short options that are valid for the
+.BR \%groff (@MAN1EXT@)
+program.
+.
+All
+.RB \%non- groffer
+options are sent unmodified via
+.B \%grog
+to
+.BR \%groff .
+.
+So postprocessors, macro packages, compatibility with
+.I classical
+.IR \%troff ,
+and much more can be manually specified.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Options related to groff"
+.\" --------------------------------------------------------------------
+.
+All short options of
+.B \%groffer
+are compatible with the short options of
+.BR \%groff (@MAN1EXT@).
+.
+The following of
+.B \%groff
+options have either an additional special meaning within
+.B \%groffer
+or make sense for normal usage.
+.
+.
+.P
+Because of the special outputting behavior of the
+.B \%groff
+option
+.B -Z
+.B \%groffer
+was designed to be switched into
+.IR \%groff\~mode ;
+the
+.I \%groffer
+viewing features are disabled there.
+.
+The other
+.B \%groff
+options do not switch the mode, but allow to customize the formatting
+process.
+.
+.
+.TP
+.B --a
+This generates an ascii approximation of output in the
+.IR \%text\~modes .
+.
+That could be important when the text pager has problems with control
+sequences in
+.IR "tty mode" .
+.
+.
+.TP
+.BI --m \ file
+Add
+.I \%file
+as a
+.I \%groff
+macro file.
+.
+This is useful in case it cannot be recognized automatically.
+.
+.
+.TP
+.BI --P \ opt_or_arg
+Send the argument
+.I \%opt_or_arg
+as an option or option argument to the actual
+.B \%groff
+postprocessor.
+.
+.
+.TP
+.B --T \fIdevname\fR\~\fR|\fB\~--device \fIdevname\fR
+.
+This option determines
+.BR \%groff 's
+output device.
+.
+The most important devices are the text output devices for referring
+to the different character sets, such as
+.BR \%ascii ,
+.BR \%utf8 ,
+.BR \%latin1 ,
+and others.
+.
+Each of these arguments switches
+.B \%groffer
+into a
+.I \%text\~mode
+using this device, to
+.I \%mode\~tty
+if the actual mode is not a
+.IR \%text\~mode .
+.
+The following
+.I \%devname
+arguments are mapped to the corresponding
+.B \%groffer
+.B --mode=\fIdevname\fR
+option:
+.BR \%dvi ,
+.BR \%html ,
+and
+.BR \%ps .
+All
+.B \%X*
+arguments are mapped to
+.IR \%mode\~x .
+Each other
+.I \%devname
+argument switches to
+.I \%mode\~groff
+using this device.
+.
+.
+.TP
+.B --X
+is equivalent to
+.BR "groff \-X" .
+It displays the
+.I groff intermediate output
+with
+.BR gxditview .
+As the quality is relatively bad this option is deprecated; use
+.B --X
+instead because the
+.I \%x\~mode
+uses an
+.IR X *
+device for a better display.
+.
+.
+.TP
+.B -Z\~\fR|\fB\~--intermediate-output\~\fR|\fB\~--ditroff
+Switch into
+.I \%groff\~mode
+and format the input with the
+.I \%groff intermediate output
+without postprocessing; see
+.BR \%groff_out (@MAN5EXT@).
+This is equivalent to option
+.B --ditroff
+of
+.IR \%man ,
+which can be used as well.
+.
+.
+.P
+All other
+.B \%groff
+options are supported by
+.BR \%groffer ,
+but they are just transparently transferred to
+.B \%groff
+without any intervention.
+.
+The options that are not explicitly handled by
+.B \%groffer
+are transparently passed to
+.BR \%groff .
+.
+Therefore these transparent options are not documented here, but in
+.BR \%groff (@MAN1EXT@).
+Due to the automatism in
+.BR \%groffer ,
+none of these
+.B \%groff
+options should be needed, except for advanced usage.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Options for man\~pages"
+.\" --------------------------------------------------------------------
+.
+.TP
+.B --apropos
+Start the
+.BR \%apropos (1)
+command or facility of
+.BR \%man (1)
+for searching the
+.I \%filespec
+arguments within all
+.I \%man\~page
+descriptions.
+.
+Each
+.I \%filespec
+argument is taken for search as it is;
+.I section
+specific parts are not handled, such that
+.B 7 groff
+searches for the two arguments
+.B 7
+and
+.BR groff ,
+with a large result; for the
+.I \%filespec
+.B groff.7
+nothing will be found.
+.
+The
+.I language
+locale is handled only when the called programs do support this; the
+GNU
+.B apropos
+and
+.B man \-k
+do not.
+.
+The display differs from the
+.B \%apropos
+program by the following concepts:
+.RS
+.Topic
+Construct a
+.I \%groff
+frame similar to a
+.I \%man\~page
+to the output of
+.BR \%apropos ,
+.Topic
+each
+.I \%filespec
+argument is searched on its own.
+.Topic
+The restriction by
+.B --sections
+is handled as well,
+.Topic
+wildcard characters are allowed and handled without a further option.
+.RE
+.
+.
+.TP
+.B --apropos\-data
+Show only the
+.B \%apropos
+descriptions for data documents, these are the
+.BR \%man (7)
+.IR sections\~4 ", " 5 ", and " 7 .
+.
+Direct
+.I section
+declarations are ignored, wildcards are accepted.
+.
+.
+.TP
+.B --apropos\-devel
+Show only the
+.B \%apropos
+descriptions for development documents, these are the
+.BR man (7)
+.IR sections\~2 ", " 3 ", and " 9 .
+.
+Direct
+.I section
+declarations are ignored, wildcards are accepted.
+.
+.
+.TP
+.B --apropos\-progs
+Show only the
+.B \%apropos
+descriptions for documents on programs, these are the
+.BR \%man (7)
+.IR sections\~1 ", " 6 ", and " 8 .
+.
+Direct
+.I section
+declarations are ignored, wildcards are accepted.
+.
+.
+.TP
+.B --whatis
+For each
+.I \%filespec
+argument search all
+.I \%man\~pages
+and display their description \[em] or say that it is not a
+.IR \%man\~page .
+This is written from anew, so it differs from
+.IR man 's
+.B whatis
+output by the following concepts
+.RS
+.Topic
+each retrieved file name is added,
+.Topic
+local files are handled as well,
+.Topic
+the \fIlanguage\fP and \fIsystem\fP locale is supported,
+.Topic
+the display is framed by a
+.I groff
+output format similar to a
+.IR \%man\~page ,
+.Topic
+wildcard characters are allowed without a further option.
+.RE
+.
+.
+.P
+The following options were added to
+.B \%groffer
+for choosing whether the file name arguments are interpreted as names
+for local files or as a search pattern for
+.IR \%man\~pages .
+.
+The default is looking up for local files.
+.
+.
+.TP
+.B --man
+Check the non-option command line arguments
+.nh
+.RI ( filespecs )
+.hy
+first on being
+.IR \%man\~pages ,
+then whether they represent an existing file.
+.
+By default, a
+.I \%filespec
+is first tested whether it is an existing file.
+.
+.
+.TP
+.B --no-man\~\fR|\fB\~--local-file
+Do not check for
+.IR \%man\~pages .
+.
+.B --local-file
+is the corresponding
+.B man
+option.
+.
+.
+.TP
+.B --no-special
+Disable former calls of
+.BR --all ,
+.BR --apropos* ,
+and
+.BR --whatis .
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Long options taken over from GNU man"
+.\" --------------------------------------------------------------------
+.
+The long options of
+.B \%groffer
+were synchronized with the long options of \f[CR]GNU\f[]
+.BR man .
+.
+All long options of \f[CR]GNU\f[]
+.B man
+are recognized, but not all of these options are important to
+.BR \%groffer ,
+so most of them are just ignored.
+.
+These ignored
+.B man
+options are
+.BR --catman ,
+.BR --troff ,
+and
+.BR --update .
+.
+.
+.P
+In the following, the
+.B man
+options that have a special meaning for
+.B \%groffer
+are documented.
+.
+.
+.P
+If your system has \f[CR]GNU\f[]
+.B man
+installed the full set of long and short options of the \f[CR]GNU\f[]
+.B man
+program can be passed via the environment variable
+.Env_var \%$MANOPT ;
+see
+.BR \%man (1).
+.
+.
+.TP
+.B --all
+In searching
+.IR \%man\~pages ,
+retrieve all suitable documents instead of only one.
+.
+.
+.TP
+.B -7\~\fR|\fB\~--ascii
+In
+.IR \%text\~modes ,
+display ASCII translation of special characters for critical environment.
+.
+This is equivalent to
+.BR "groff \%-mtty_char" ;
+see
+.BR groff_tmac (@MAN5EXT@).
+.
+.
+.TP
+.B --ditroff
+Produce
+.IR "groff intermediate output" .
+This is equivalent to
+.B \%groffer
+.BR -Z .
+.
+.
+.TP
+.BI --extension \ suffix
+Restrict
+.I \%man\~page
+search to file names that have
+.I \%suffix
+appended to their section element.
+.
+For example, in the file name
+.I \%/usr/share/man/man3/terminfo.3ncurses.gz
+the
+.I \%man\~page
+extension is
+.IR \%ncurses .
+.
+.
+.TP
+.BI --locale \ language
+.
+Set the language for
+.IR \%man\~pages .
+.
+This has the same effect, but overwrites
+.Env_var $LANG .
+.
+.
+.TP
+.B --location
+Print the location of the retrieved files to standard error.
+.
+.
+.TP
+.B --no-location
+Do not display the location of retrieved files; this resets a former
+call to
+.BR --location .
+.
+This was added by
+.BR \%groffer .
+.
+.
+.TP
+.BI --manpath \ 'dir1:dir2:\*[Ellipsis]'
+Use the specified search path for retrieving
+.I \%man\~pages
+instead of the program defaults.
+.
+If the argument is set to the empty string "" the search for
+.I \%man\~page
+is disabled.
+.
+.
+.TP
+.B --pager
+Set the pager program in
+.IR \%tty\~mode ;
+default is
+.BR \%less .
+This is equivalent to
+.BR --tty\-viewer .
+.
+.
+.TP
+.BI --sections \ sec1:sec2:\*[Ellipsis]
+Restrict searching for
+.I \%man\~pages
+to the given
+.IR sections ,
+a colon-separated list.
+.
+.
+.TP
+.BI --systems \ sys1,sys2,\*[Ellipsis]
+Search for
+.I \%man\~pages
+for the given operating systems; the argument
+.I \%systems
+is a comma-separated list.
+.
+.
+.TP
+.B --where
+Equivalent to
+.BR --location .
+.
+.
+.\" --------------------------------------------------------------------
+.SS "X\~\%Window\~\%Toolkit Options"
+.\" --------------------------------------------------------------------
+.
+The following long options were adapted from the corresponding
+\%\f[CR]X\~Window\~Toolkit\f[] options.
+.
+.B \%groffer
+will pass them to the actual viewer program if it is an
+\%\f[CR]X\~Window\f[] program.
+.
+Otherwise these options are ignored.
+.
+.
+.P
+Unfortunately these options use the old style of a single minus for
+long options.
+.
+For
+.B \%groffer
+that was changed to the standard with using a double minus for long
+options, for example,
+.B \%groffer
+uses the option
+.B --font
+for the \%\f[CR]X\~Window\f[] option
+.BR -font .
+.
+.
+.P
+See
+.BR X (7)
+and the documentation on the \%\f[CR]X\~Window\~Toolkit\f[] options
+for more details on these options and their arguments.
+.
+.
+.TP
+.BI --background \ color
+Set the background color of the viewer window.
+.
+.
+.TP
+.BI --bd \ pixels
+This is equivalent to
+.BR --bordercolor .
+.
+.
+.TP
+.BI --bg \ color
+This is equivalent to
+.BR --background .
+.
+.
+.TP
+.BI --bw \ pixels
+This is equivalent to
+.BR --borderwidth .
+.
+.
+.TP
+.BI --bordercolor \ pixels
+Specifies the color of the border surrounding the viewer window.
+.
+.
+.TP
+.BI --borderwidth \ pixels
+Specifies the width in pixels of the border surrounding the viewer
+window.
+.
+.
+.TP
+.BI --display \ X-display
+Set the \%\f[CR]X\~Window\f[] display on which the viewer program
+shall be started, see the \%\f[CR]X\~Window\f[] documentation for the
+syntax of the argument.
+.
+.
+.TP
+.BI --foreground \ color
+Set the foreground color of the viewer window.
+.
+.
+.TP
+.BI --fg \ color
+This is equivalent to
+.BR -foreground .
+.
+.
+.TP
+.BI --fn \ font_name
+This is equivalent to
+.BR --font .
+.
+.
+.TP
+.BI --font \ font_name
+Set the font used by the viewer window.
+.
+The argument is an \%\f[CR]X\~Window\f[] font name.
+.
+.
+.TP
+.BI --ft \ font_name
+This is equivalent to
+.BR --font .
+.
+.
+.TP
+.BI --geometry \ size_pos
+Set the geometry of the display window, that means its size and its
+starting position.
+.
+See
+.BR \%X (7)
+for the syntax of the argument.
+.
+.
+.TP
+.BI --resolution \ value
+Set \%\f[CR]X\~Window\f[] resolution in dpi (dots per inch) in some
+viewer programs.
+.
+The only supported dpi values are
+.B 75
+and
+.BR 100 .
+.
+Actually, the default resolution for
+.B \%groffer
+is set to
+.BR 75dpi .
+The resolution also sets the default device in
+.IR "mode x" .
+.
+.
+.TP
+.B --rv
+Reverse foreground and background color of the viewer window.
+.
+.
+.TP
+.BI --title "\ 'some text'"
+Set the title for the viewer window.
+.
+.
+.TP
+.BI --xrm \ 'resource'
+Set \f[CR]\%X\~Window\f[] resource.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Options for Development"
+.\" --------------------------------------------------------------------
+.
+.TP
+.B --debug
+Enable eight debugging informations.
+.
+The temporary files are kept and not deleted, the name of the
+temporary directory and the shell name for
+.File_name groffer2.sh
+are printed, the displayed file names are printed, the
+.B grog
+output is printed, the parameters are printed at several steps of
+development, and a function stack is output with function
+\f[CR]error_user()\f[] as well.
+.
+Neither the function call stack at the opening and closing of each
+function call nor the landmark information to determine how far the
+program is running are printed.
+.
+These seem to be the most useful parts among all debugging options.
+.
+.
+.TP
+.B --debug\-all
+Enable all ten debugging informations including the function call
+stack and the landmark information.
+.
+.
+.TP
+.B --debug\-filenames
+Print the names of the files and
+.I \%man\~pages
+that are displayed by
+.BR \&groffer .
+.
+.
+.TP
+.B --debug\-func
+Enable the basic debugging information for checking the functions on
+the beginning and end of each call.
+.
+The options
+.B --debug\-stacks
+and
+.B --debug\-user
+enable this option automatically.
+.
+This option is important for the development, but it decreases the
+speed of
+.B groffer
+by large amounts.
+.
+.
+.TP
+.B --debug\-grog
+Print the output of all
+.B grog
+commands.
+.
+.
+.TP
+.B --debug\-keep
+Enable two debugging informations, the printing of the name of the
+temporary directory and the keeping of the temporary files.
+.
+.
+.TP
+.B --debug\-lm
+Enable one debugging information, the landmark information.
+.
+.
+.TP
+.B --debug\-params
+Enable one debugging information, the parameters at several steps.
+.
+.
+.TP
+.B --debug\-shell
+Enable one debugging information, the shell name for
+.File_name groffer2.sh .
+.
+.
+.TP
+.B --debug\-stacks
+Enable one debugging information, the function call stack.
+.
+.
+.TP
+.B --debug\-tmpdir
+Enable one debugging information, the name of the temporary directory.
+.
+.
+.TP
+.B --debug\-user
+Enable one debugging information, the function stack with
+\f[CR]error_user()\f[].
+.
+.
+.TP
+.B --do-nothing
+This is like
+.BR --version ,
+but without the output; no viewer is started.
+.
+This makes only sense in development.
+.
+.
+.TP
+.B --print=\fItext\fR
+Just print the argument to standard error.
+.
+This is good for parameter check.
+.
+.
+.TP
+.B --shell \fIshell_program\fR
+Specify the shell under which the
+.File_name \%groffer2.sh
+script should be run.
+.
+This option overwrites the automatic shell determination of the
+program.
+.
+If the argument
+.I shell_program
+is empty a former shell option and the automatic shell determination
+is cancelled and the default shell is restored.
+.
+Some shells run considerably faster than the standard shell.
+.
+.
+.TP
+.B -V
+This is an advanced option for debugging only.
+.
+Instead of displaying the formatted input, a lot of
+.I \%groffer
+specific information is printed to standard output:
+.
+.RS
+.Topic
+the output file name in the temporary directory,
+.
+.Topic
+the display mode of the actual
+.B \%groffer
+run,
+.
+.Topic
+the display program for viewing the output with its arguments,
+.
+.Topic
+the active parameters from the config files, the arguments in
+.Env_var \%$GROFFER_OPT ,
+and the arguments of the command line,
+.
+.Topic
+the pipeline that would be run by the
+.B \%groff
+program, but without executing it.
+.RE
+.
+.
+.P
+Other useful debugging options are the
+.B \%groff
+option
+.B -Z
+and
+.BR --mode=groff .
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Filespec Arguments"
+.\" --------------------------------------------------------------------
+.
+A
+.I \%filespec
+parameter is an argument that is not an option or option argument.
+.
+In
+.BR \%groffer ,
+.I \%filespec
+parameters are a file name or a template for searching
+.IR \%man\~pages .
+.
+These input sources are collected and composed into a single output
+file such as
+.B \%groff
+does.
+.
+.
+.P
+The strange \%\f[CR]POSIX\f[] behavior to regard all arguments behind
+the first non-option argument as
+.I \%filespec
+arguments is ignored.
+.
+The \f[CR]GNU\f[] behavior to recognize options even when mixed with
+.I \%filespec
+arguments is used throughout.
+.
+But, as usual, the double minus argument
+.B --
+ends the option handling and interprets all following arguments as
+.I \%filespec
+arguments; so the \%\f[CR]POSIX\f[] behavior can be easily adopted.
+.
+.
+.P
+The options
+.B --apropos*
+have a special handling of
+.I filespec
+arguments.
+.
+Each argument is taken as a search scheme of its own.
+.
+Also a regexp (regular expression) can be used in the filespec.
+.
+For example,
+.B groffer --apropos '^gro.f$'
+searches
+.B groff
+in the
+.I man\~page
+name, while
+.B groffer --apropos groff
+searches
+.B groff
+somewhere in the name or description of the
+.IR man\~pages .
+.
+.
+.P
+All other parts of
+.IR groffer ,
+such as the normal display or the output with
+.B --whatis
+have a different scheme for
+.IR filespecs .
+No regular expressions are used for the arguments.
+.
+The
+.I filespec
+arguments are handled by the following scheme.
+.
+.
+.P
+It is necessary to know that on each system the
+.I \%man\~pages
+are sorted according to their content into several sections.
+.
+The
+.I classical man sections
+have a single-character name, either a digit from
+.B 1
+to
+.B 9
+or one of the characters
+.B n
+or
+.BR o .
+.
+.
+.P
+This can optionally be followed by a string, the so-called
+.IR extension .
+The
+.I extension
+allows to store several
+.I man\~pages
+with the same name in the same
+.IR section .
+But the
+.I extension
+is only rarely used, usually it is omitted.
+.
+Then the
+.I extensions
+are searched automatically by alphabet.
+.
+.
+.P
+In the following, we use the name
+.I section_extension
+for a word that consists of a single character
+.I section
+name or a
+.I section
+character that is followed by an
+.IR extension .
+.
+Each
+.I \%filespec
+parameter can have one of the following forms in decreasing sequence.
+.
+.
+.Topic
+No
+.I \%filespec
+parameters means that
+.B \%groffer
+waits for standard input.
+.
+The minus option
+.B -
+always stands for standard input; it can occur several times.
+.
+If you want to look up a
+.I \%man\~page
+called
+.B -
+use the argument
+.BR man:\- .
+.
+.
+.Topic
+Next a
+.I \%filespec
+is tested whether it is the path name of an existing file.
+.
+Otherwise it is assumed to be a searching pattern for a
+.IR \%man\~page .
+.
+.
+.Topic
+.BI \%man: name ( section_extension ) ,
+.BI \%man: name . section_extension,
+.IB \%name ( section_extension ) ,
+or
+.IB \%name . section_extension
+search the \%man\~page
+.I \%name
+in \%man\~section and possibly extension of
+.IR \%section_extension .
+.
+.
+.Topic
+Now
+.BI \%man: name
+searches for a
+.I \%man\~page
+in the lowest
+.I \%man\~section
+that has a document called
+.IR \%name .
+.
+.
+.Topic
+.I \%section_extension\~name
+is a pattern of 2 arguments that originates from a strange argument
+parsing of the
+.B man
+program.
+.
+Again, this searches the man page
+.I name
+with
+.IR \%section_extension ,
+a combination of a
+.I section
+character optionally followed by an
+.IR extension .
+.
+.
+.Topic
+We are left with the argument
+.I \%name
+which is not an existing file.
+.
+So this searches for the
+.I \%man\~page
+called
+.I \%name
+in the lowest
+.I \%man\~section
+that has a document for this name.
+.
+.
+.P
+Several file name arguments can be supplied.
+.
+They are mixed by
+.B \%groff
+into a single document.
+.
+Note that the set of option arguments must fit to all of these file
+arguments.
+.
+So they should have at least the same style of the
+.I \%groff
+language.
+.
+.
+.\" --------------------------------------------------------------------
+.SH "OUTPUT MODES"
+.\" --------------------------------------------------------------------
+.
+By default, the
+.B \%groffer
+program collects all input into a single file, formats it with the
+.B \%groff
+program for a certain device, and then chooses a suitable viewer
+program.
+.
+The device and viewer process in
+.B \%groffer
+is called a
+.IR \%mode .
+.
+The mode and viewer of a running
+.B \%groffer
+program is selected automatically, but the user can also choose it
+with options.
+.
+.
+The modes are selected by option the arguments of
+.BR --mode=\fIanymode .
+Additionally, each of this argument can be specified as an option of
+its own, such as
+.BR anymode .
+Most of these modes have a viewer program, which can be chosen by an
+option that is constructed like
+.BR --\fIanymode\fR\-viewer .
+.
+.
+.P
+Several different modes are offered, graphical modes for
+\f[CR]\%X\~Window\f[],
+.IR \%text\~modes ,
+and some direct
+.I \%groff\~modes
+for debugging and development.
+.
+.
+.P
+By default,
+.B \%groffer
+first tries whether
+.I \%x\~mode
+is possible, then
+.IR \%ps\~mode ,
+and finally
+.IR \%tty\~mode .
+.
+This mode testing sequence for
+.I \%auto\~mode
+can be changed by specifying a comma separated list of modes with the
+option
+.B --default\-modes.
+.
+.
+.P
+The searching for
+.I \%man\~pages
+and the decompression of the input are active in every mode.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Graphical Display Modes"
+.\" --------------------------------------------------------------------
+.
+The graphical display modes work mostly in the \%\f[CR]X\~Window\f[]
+environment (or similar implementations within other windowing
+environments).
+.
+The environment variable
+.Env_var \%$DISPLAY
+and the option
+.B --display
+are used for specifying the \%\f[CR]X\~Window\f[] display to be used.
+.
+If this environment variable is empty
+.B \%groffer
+assumes that no \%\f[CR]X\~Window\f[] is running and changes to a
+.IR \%text\~mode .
+.
+You can change this automatic behavior by the option
+.BR --default\-modes .
+.
+.
+.P
+Known viewers for the graphical display modes and their standard
+\%\f[CR]X\~Window\f[] viewer programs are
+.
+.Topic
+in a PDF viewer
+.nh
+.RI ( \%pdf\~mode )
+.hy
+.
+.Topic
+in a web browser
+.nh
+.RI ( html
+or
+.IR \%www\~mode )
+.hy
+.RE
+.
+.Topic
+in a Postscript viewer
+.nh
+.RI ( \%ps\~mode )
+.hy
+.
+.Topic
+\%\f[CR]X\~Window\f[]
+.I roff
+viewers such as
+.BR \%gxditview (@MAN1EXT@)
+or
+.BR \%xditview (1)
+(in
+.IR \%x\~mode )
+.
+.Topic
+in a dvi viewer program
+.nh
+.RI ( \%dvi\~mode )
+.hy
+.
+.
+.P
+The
+.I \%pdf\~mode
+has a major advantage \[em] it is the only graphical display mode that
+allows to search for text within the viewer; this can be a really
+important feature.
+.
+Unfortunately, it takes some time to transform the input into the PDF
+format, so it was not chosen as the major mode.
+.
+.
+.P
+These graphical viewers can be customized by options of the
+\%\f[CR]X\~Window\~Toolkit\f[].
+.
+But the
+.B \%groffer
+options use a leading double minus instead of the single minus used by
+the \%\f[CR]X\~Window\~Toolkit\f[].
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Text modes"
+.\" --------------------------------------------------------------------
+.
+There are two modes for text output,
+.I \%mode\~text
+for plain output without a pager and
+.I \%mode\~tty
+for a text output on a text terminal using some pager program.
+.
+.
+.P
+If the variable
+.Env_var \%$DISPLAY
+is not set or empty,
+.B \%groffer
+assumes that it should use
+.IR \%tty\~\%mode .
+.
+.
+.P
+In the actual implementation, the
+.I groff
+output device
+.I \%latin1
+is chosen for
+.IR \%text\~modes .
+.
+This can be changed by specifying option
+.B -T
+or
+.BR \%--device .
+.
+.
+.P
+The pager to be used can be specified by one of the options
+.B --pager
+and
+.BR --tty\-viewer ,
+or by the environment variable
+.Env_var \%$PAGER .
+If all of this is not used the
+.BR \%less (1)
+program with the option
+.B -r
+for correctly displaying control sequences is used as the default
+pager.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Special Modes for Debugging and Development"
+.\" --------------------------------------------------------------------
+.
+These modes use the
+.I \%groffer
+file determination and decompression.
+.
+This is combined into a single input file that is fed directly into
+.B \%groff
+with different strategy without the
+.I \%groffer
+viewing facilities.
+.
+These modes are regarded as advanced, they are useful for debugging
+and development purposes.
+.
+.
+.P
+The
+.I \%source\~mode
+with option
+.B --source
+just displays the decompressed input.
+.
+.
+.P
+Otion
+.B --to\-stdout
+does not display in a graphical mode.
+.
+It just generates the file for the chosen mode and then prints its
+content to standard output.
+.
+.
+.P
+The
+.I \%groff\~mode
+passes the input to
+.B \%groff
+using only some suitable options provided to
+.BR \%groffer .
+.
+This enables the user to save the generated output into a file or pipe
+it into another program.
+.
+.
+.P
+In
+.IR \%groff\~\%mode ,
+the option
+.B -Z
+disables post-processing, thus producing the
+.nh
+.I groff intermediate
+.IR output .
+.hy
+.
+In this mode, the input is formatted, but not postprocessed; see
+.BR \%groff_out (@MAN5EXT@)
+for details.
+.
+.
+.P
+All
+.B \%groff
+short options are supported by
+.BR \%groffer .
+.
+.
+.\" --------------------------------------------------------------------
+.SH "MAN PAGE SEARCHING"
+.\" --------------------------------------------------------------------
+.
+The default behavior of
+.B \%groffer
+is to first test whether a file parameter represents a local file; if
+it is not an existing file name, it is assumed to represent the name
+of a
+.IR \%man\~page .
+The following options can be used to determine whether the arguments
+should be handled as file name or
+.I \%man\~page
+arguments.
+.
+.TP
+.B --man
+forces to interpret all file parameters as
+.I \%filespecs
+for searching
+.IR \%man\~pages .
+.
+.TP
+.B --no\-man
+.TQ
+.B --local\-file
+disable the
+.I man
+searching; so only local files are displayed.
+.
+.
+.P
+If neither a local file nor a
+.I \%man\~page
+was retrieved for some file parameter a warning is issued on standard
+error, but processing is continued.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Search Algorithm"
+.\" --------------------------------------------------------------------
+.
+Let us now assume that a
+.I \%man\~page
+should be searched.
+.
+The
+.B \%groffer
+program provides a search facility for
+.IR \%man\~pages .
+.
+All long options, all environment variables, and most of the
+functionality of the \f[CR]GNU\fP
+.BR \%man (1)
+program were implemented.
+.
+The search algorithm shall determine which file is displayed for a given
+.IR \%man\~page .
+The process can be modified by options and environment variables.
+.
+.
+.P
+The only
+.I man
+action that is omitted in
+.B \%groffer
+are the preformatted
+.IR \%man\~pages ,
+also called
+.IR cat\~pages .
+.
+With the excellent performance of the actual computers, the
+preformatted
+.I \%man\~pages
+aren't necessary any longer.
+.
+Additionally,
+.B \%groffer
+is a
+.I roff
+program; it wants to read
+.I roff
+source files and format them itself.
+.
+.
+.P
+The algorithm for retrieving the file for a
+.I \%man\~page
+needs first a set of directories.
+.
+This set starts with the so-called
+.I man\~path
+that is modified later on by adding names of
+.I operating system
+and
+.IR language .
+.
+This arising set is used for adding the section directories which
+contain the
+.I \%man\~page
+files.
+.
+.
+.P
+The
+.I man\~path
+is a list of directories that are separated by colon.
+.
+It is generated by the following methods.
+.
+.Topic
+The environment variable
+.Env_var \%$MANPATH
+can be set.
+.
+.Topic
+It can be read from the arguments of the environment variable
+.Env_var \%$MANOPT .
+.
+.Topic
+The
+.I man\~path
+can be manually specified by using the option
+.BR --manpath .
+An empty argument disables the
+.I \%man\~page
+searching.
+.
+.Topic
+When no
+.I man\~path
+was set the
+.BR \%manpath (1)
+program is tried to determine one.
+.
+.Topic
+If this does not work a reasonable default path from
+.Env_var $PATH
+is determined.
+.
+.
+.P
+We now have a starting set of directories.
+.
+The first way to change this set is by adding names of
+.I operating
+.IR systems .
+.
+This assumes that
+.I \%man\~pages
+for several
+.I operating systems
+are installed.
+.
+This is not always true.
+.
+The names of such
+.I operating systems
+can be provided by 3 methods.
+.
+.Topic
+The environment variable
+.Env_var \%$SYSTEM
+has the lowest precedence.
+.
+.Topic
+This can be overridden by an option in
+.Env_var \%$MANOPT .
+.
+.Topic
+This again is overridden by the command line option
+.BR --systems .
+.
+.
+.P
+Several names of
+.I operating systems
+can be given by appending their names, separated by a comma.
+.
+.
+.P
+The
+.I man\~path
+is changed by appending each
+.I system
+name as subdirectory at the end of each directory of the set.
+.
+No directory of the
+.I man\~path
+set is kept.
+.
+But if no
+.I system
+name is specified the
+.I man\~path
+is left unchanged.
+.
+.
+.P
+After this, the actual set of directories can be changed by
+.I language
+information.
+.
+This assumes that there exist
+.I man\~pages
+in different languages.
+.
+The wanted
+.I language
+can be chosen by several methods.
+.
+.Topic
+Environment variable
+.Env_var $LANG .
+.
+.Topic
+This is overridden by
+.Env_var \%$LC_MESSAGES .
+.
+.Topic
+This is overridden by
+.Env_var $LC_ALL .
+.
+.Topic
+This can be overridden by providing an option in
+.Env_var \%$MANOPT .
+.
+.Topic
+All these environment variables are overridden by the command line
+option
+.BR --locale .
+.
+.
+.P
+The
+.I default language
+can be specified by specifying one of the pseudo-language parameters
+\f[CR]C\fP or \f[CR]\%POSIX\fP.
+.
+This is like deleting a formerly given
+.I language
+information.
+.
+The
+.I \%man\~pages
+in the
+.I default language
+are usually in English.
+.
+.
+.P
+Of course, the
+.I language
+name is determined by
+.BR man .
+In \f[CR]GNU\fP
+.BR man ,
+it is specified in the \%\f[CR]POSIX\~1003.1\fP based format:
+.P
+.nh
+\f[I]<language>\f[][\f[CB]_\f[]\f[I]<territory>\f[][\f[CB].\fP\
+\f[I]<character-set>\f[][\f[CB],\fP\f[I]<version>\fP]]],
+.hy
+.P
+but the two-letter code in
+.nh
+.I <language>
+.hy
+is sufficient for most purposes.
+.
+If for a complicated
+.I language
+formulation no
+.I \%man\~pages
+are found
+.B \%groffer
+searches the country part consisting of these first two characters as
+well.
+.
+.
+.P
+The actual directory set is copied thrice.
+.
+The
+.I language
+name is appended as subdirectory to each directory in the first copy
+of the actual directory set (this is only done when a language
+information is given).
+.
+Then the 2-letter abbreviation of the
+.I language
+name is appended as subdirectories to the second copy of the directory
+set (this is only done when the given language name has more than 2
+letters).
+.
+The third copy of the directory set is kept unchanged (if no
+.I language
+information is given this is the kept directory set).
+.
+These maximally 3 copies are appended to get the new directory set.
+.
+.
+.P
+We now have a complete set of directories to work with.
+.
+In each of these directories, the
+.I man
+files are separated in
+.IR sections .
+.
+The name of a
+.I section
+is represented by a single character, a digit between
+.I 1
+and
+.IR 9 ,
+or the character
+.I o
+or
+.IR n ,
+in this order.
+.
+.
+.P
+For each available
+.IR section ,
+a subdirectory
+.File_name man \fI<section>\fP
+exists containing all
+.I man
+files for this
+.IR section ,
+where
+.I <section>
+is a single character as described before.
+.
+Each
+.I man
+file in a
+.I section
+directory has the form
+.IR \%\f[CB]man\fP<section>\f[CB]/\fP<name>\f[CB].\fP<section>\
+[<extension>][\f[CB].\fP<compression>] ,
+where
+.I \%<extension>
+and
+.I \%<compression>
+are optional.
+.
+.I \%<name>
+is the name of the
+.I \%man\~page
+that is also specified as filespec argument on the command line.
+.
+.
+.P
+The
+.I extension
+is an addition to the section.
+.
+This postfix acts like a subsection.
+.
+An
+.I extension
+occurs only in the file name, not in name of the
+.I section
+subdirectory.
+.
+It can be specified on the command line.
+.
+.
+.P
+On the other hand, the
+.I compression
+is just an information on how the file is compressed.
+.
+This is not important for the user, such that it cannot be specified
+on the command line.
+.
+.
+.P
+There are 4 methods to specify a
+.I section
+on the command line:
+.
+.Topic
+Environment variable
+.Env_var \%$MANSECT
+.
+.Topic
+Command line option
+.B --sections
+.
+.Topic
+Appendix to the
+.I name
+argument in the form
+.I <name>.<section>
+.
+.Topic
+Preargument before the
+.I name
+argument in the form
+.I <section> <name>
+.
+.
+.P
+It is also possible to specify several
+.I sections
+by appending the single characters separated by colons.
+.
+One can imagine that this means to restrict the
+.I \%man\~page
+search to only some
+.IR sections .
+.
+The multiple
+.I sections
+are only possible for
+.Env_var \%$MANSECT
+and
+.BR --sections .
+.
+.
+.P
+If no
+.I section
+is specified all
+.I sections
+are searched one after the other in the given order, starting with
+.IR section\~1 ,
+until a suitable file is found.
+.
+.
+.P
+There are 4 methods to specify an
+.I extension
+on the command line.
+.
+But it is not necessary to provide the whole extension name, some
+abbreviation is good enough in most cases.
+.
+.Topic
+Environment variable
+.Env_var \%$EXTENSION
+.
+.Topic
+Command line option
+.B --extension
+.
+.Topic
+Appendix to the
+.I <name>.<section>
+argument in the form
+.I <name>.<section><extension>
+.
+.Topic
+Preargument before the
+.I name
+argument in the form
+.I <section><extension> <name>
+.
+.
+.P
+For further details on
+.I \%man\~page
+searching, see
+.BR \%man (1).
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Examples of man files"
+.\" --------------------------------------------------------------------
+.
+.TP
+.File_name /usr/share/man/man1/groff.1
+This is an uncompressed file for the
+.I \%man\~page
+\f[CR]groff\fP in
+.IR section\~1 .
+.
+It can be called by
+.EX
+\fIsh#\fR groffer\~groff
+.EE
+No
+.I section
+is specified here, so all
+.I sections
+should be searched, but as
+.I section\~1
+is searched first this file will be found first.
+.
+The file name is composed of the following components.
+.File_name /usr/share/man
+must be part of the
+.IR \%man\~path ;
+the subdirectory
+.File_name man1/
+and the part
+.File_name .1
+stand for the
+.IR section ;
+.File_name groff
+is the name of the
+.IR \%man\~page .
+.
+.
+.TP
+.File_name /usr/local/share/man/man7/groff.7.gz
+The file name is composed of the following components.
+.File_name /usr/local/share/man
+must be part of the
+.IR \%man\~path ;
+the subdirectory
+.File_name man7/
+and the part
+.File_name .7
+stand for the
+.IR section ;
+.File_name groff
+is the name of the
+.IR \%man\~page ;
+the final part
+.File_name .gz
+stands for a compression with
+.BR gzip (1).
+As the
+.I section
+is not the first one it must be specified as well.
+.
+This can be done by one of the following commands.
+.EX
+\fIsh#\fR\~groffer\~groff.7
+\fIsh#\fR\~groffer\~7\~groff
+\fIsh#\fR\~groffer\~\-\-sections=7\~groff
+.EE
+.
+.TP
+.File_name /usr/local/man/man1/ctags.1emacs21.bz2
+Here
+.File_name /usr/local/man
+must be in
+.IR \%man\~path ;
+the subdirectory
+.File_name man1/
+and the file name part
+.File_name .1
+stand for
+.IR section\~1 ;
+the name of the
+.I \%man\~page
+is
+.File_name ctags ;
+the section has an extension
+.File_name emacs21 ;
+and the file is compressed as
+.File_name .bz2
+with
+.BR bzip2 (1).
+The file can be viewed with one of the following commands
+.EX
+\fIsh#\fR\~groffer\~ctags.1e
+\fIsh#\fR\~groffer\~1e\~ctags
+\fIsh#\fR\~groffer\~\-\-extension=e\~\-\-sections=1\~ctags
+.EE
+where \f[CR]e\fP works as an abbreviation for the extension
+\f[CR]emacs21\fP.
+.
+.
+.TP
+.File_name /usr/man/linux/de/man7/man.7.Z
+The directory
+.File_name /usr/man
+is now part of the
+.IR \%man\~path ;
+then there is a subdirectory for an
+.I operating system
+name
+.File_name linux/ ;
+next comes  a subdirectory
+.File_name de/
+for the German
+.IR language ;
+the
+.I section
+names
+.File_name man7
+and
+.File_name .7
+are known so far;
+.File_name man
+is the name of the
+.IR \%man\~page ;
+and
+.File_name .Z
+signifies the compression that can be handled by
+.BR gzip (1).
+We want now show how to provide several values for some options.
+.
+That is possible for
+.I sections
+and
+.I operating system
+names.
+.
+So we use as
+.I sections\~5
+and
+.I 7
+and as
+.I system
+names
+.I linux
+and
+.IR aix .
+The command is then
+.sp
+.EX
+\fIsh#\fR groffer\~\-\-locale=de\~\-\-sections=5:7\~\-\-systems=linux,aix\~man
+\fIsh#\fR LANG=de\~MANSECT=5:7\~SYSTEM=linux,aix\~groffer\~man
+.EE
+.
+.
+.\" --------------------------------------------------------------------
+.SH DECOMPRESSION
+.\" --------------------------------------------------------------------
+.
+The program has a decompression facility.
+.
+If standard input or a file that was retrieved from the command line
+parameters is compressed with a format that is supported by either
+.BR \%gzip (1)
+or
+.BR \%bzip2 (1)
+it is decompressed on-the-fly.
+.
+This includes the \f[CR]GNU\fP
+.BR \%.gz ,
+.BR \%.bz2 ,
+and the traditional
+.B \%.Z
+compression.
+.
+The program displays the concatenation of all decompressed input in
+the sequence that was specified on the command line.
+.
+.
+.\" --------------------------------------------------------------------
+.SH "ENVIRONMENT"
+.\" --------------------------------------------------------------------
+.
+The
+.B \%groffer
+program supports many system variables, most of them by courtesy of
+other programs.
+.
+All environment variables of
+.BR \%groff (@MAN1EXT@)
+and \f[CR]GNU\fP
+.BR \%man (1)
+and some standard system variables are honored.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Native groffer Variables"
+.\" --------------------------------------------------------------------
+.
+.TP
+.Env_var \%$GROFFER_OPT
+Store options for a run of
+.BR \%groffer .
+.
+The options specified in this variable are overridden by the options
+given on the command line.
+.
+The content of this variable is run through the shell builtin `eval';
+so arguments containing white-space or special shell characters should
+be quoted.
+.
+Do not forget to export this variable, otherwise it does not exist
+during the run of
+.BR groffer .
+.
+.
+.\" --------------------------------------------------------------------
+.SS "System Variables"
+.\" --------------------------------------------------------------------
+.
+The
+.B \%groffer
+program is a shell script that is run through
+.File_name /bin/sh ,
+which can be internally linked to programs like
+.BR \%bash (1).
+The corresponding system environment is automatically effective.
+.
+The following variables have a special meaning for
+.BR \%groffer .
+.
+.
+.TP
+.Env_var \%$DISPLAY
+If this variable is set this indicates that the \%\f[CR]X\~Window\fP
+system is running.
+.
+Testing this variable decides on whether graphical or text output is
+generated.
+.
+This variable should not be changed by the user carelessly, but it can
+be used to start the graphical
+.B \%groffer
+on a remote \%\f[CR]X\~Window\fP terminal.
+.
+For example, depending on your system,
+.B \%groffer
+can be started on the second monitor by the command
+.sp
+.EX
+\fIsh#\fR DISPLAY=:0.1\~groffer\~what.ever &
+.EE
+.
+.
+.TP
+.Env_var \%$LC_ALL
+.TQ
+.Env_var \%$LC_MESSAGES
+.TQ
+.Env_var $LANG
+If one of these variables is set (in the above sequence), its content
+is interpreted as the locale, the language to be used, especially when
+retrieving
+.IR \%man\~pages .
+.
+A locale name is typically of the form
+.nh
+.IR language [\c
+.B _\c
+.IR territory [\c
+.B .\c
+.IR codeset [\c
+.B @\c
+.IR modifier ]]],
+.hy
+where
+.I \%language
+is an ISO 639 language code,
+.I \%territory
+is an ISO 3166 country code, and
+.I \%codeset
+is a character set or encoding identifier like ISO-8859-1 or UTF-8;
+see
+.BR \%setlocale (3).
+.
+The locale values \f[CR]C\fP and \%\f[CR]POSIX\fP
+stand for the default, i.e. the
+.I \%man\~page
+directories without a language prefix.
+.
+This is the same behavior as when all 3\~variables are unset.
+.
+.
+.TP
+.Env_var \%$PAGER
+This variable can be used to set the pager for the tty output.
+.
+For example, to disable the use of a pager completely set this
+variable to the
+.BR \%cat (1)
+program
+.sp
+.EX
+\fIsh#\fR PAGER=cat\~groffer\~anything
+.EE
+.sp
+.
+.TP
+.Env_var $PATH
+All programs within the
+.B \%groffer
+shell script are called without a fixed path.
+.
+Thus this environment variable determines the set of programs used
+within the run of
+.BR \%groffer .
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Groff Variables"
+.\" --------------------------------------------------------------------
+.
+The
+.B \%groffer
+program internally calls
+.BR \%groff ,
+so all environment variables documented in
+.BR \%groff (@MAN1EXT@)
+are internally used within
+.B \%groffer
+as well.
+.
+The following variable has a direct meaning for the
+.B \%groffer
+program.
+.
+.TP
+.Env_var \%$GROFF_TMPDIR
+If the value of this variable is an existing, writable directory,
+.B \%groffer
+uses it for storing its temporary files, just as
+.B groff
+does.
+.
+See the
+.BR \%groff (@MAN1EXT@)
+man page for more details on the location of temporary files.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Man Variables"
+.\" --------------------------------------------------------------------
+.
+Parts of the functionality of the
+.B man
+program were implemented in
+.BR \%groffer ;
+support for all environment variables documented in
+.BR \%man (1)
+was added to
+.BR \%groffer ,
+but the meaning was slightly modified due to the different approach in
+.BR \%groffer ;
+but the user interface is the same.
+.
+The
+.B man
+environment variables can be overwritten by options provided with
+.Env_var \%$MANOPT ,
+which in turn is overwritten by the command line.
+.
+.
+.TP
+.Env_var \%$EXTENSION
+Restrict the search for
+.I \%man\~pages
+to files having this extension.
+.
+This is overridden by option
+.BR --extension ;
+see there for details.
+.
+.
+.TP
+.Env_var \%$MANOPT
+This variable contains options as a preset for
+.BR \%man (1).
+As not all of these are relevant for
+.B \%groffer
+only the essential parts of its value are extracted.
+.
+The options specified in this variable overwrite the values of the
+other environment variables that are specific to
+.IR man .
+.
+All options specified in this variable are overridden by the options
+given on the command line.
+.
+.
+.TP
+.Env_var \%$MANPATH
+If set, this variable contains the directories in which the
+.I \%man\~page
+trees are stored.
+.
+This is overridden by option
+.BR \%--manpath .
+.
+.
+.TP
+.Env_var \%$MANSECT
+If this is a colon separated list of section names, the search for
+.I \%man\~pages
+is restricted to those manual sections in that order.
+.
+This is overridden by option
+.BR --sections .
+.
+.
+.TP
+.Env_var \%$SYSTEM
+If this is set to a comma separated list of names these are interpreted
+as
+.I \%man\~page
+trees for different operating systems.
+.
+This variable can be overwritten by option
+.BR --systems ;
+see there for details.
+.
+.
+.P
+The environment variable
+.Env_var \%$MANROFFSEQ
+is ignored by
+.B \%groffer
+because the necessary preprocessors are determined automatically.
+.
+.
+.\" --------------------------------------------------------------------
+.SH "CONFIGURATION FILES"
+.\" --------------------------------------------------------------------
+.
+The
+.B \%groffer
+program can be preconfigured by two configuration files.
+.
+.
+.TP
+.File_name \%/etc/groff/groffer.conf
+System-wide configuration file for
+.BR \%groffer .
+.
+.
+.TP
+.File_name \%$HOME/.groff/groffer.conf
+User-specific configuration file for
+.BR \%groffer ,
+where
+.Env_var \%$HOME
+denotes the user's home directory.
+.
+This file is called after the system-wide configuration file to enable
+overriding by the user.
+.
+.
+.P
+Both files are handled for the configuration, but the configuration
+file in
+.File_name /etc
+comes first; it is overwritten by the configuration file in the home
+directory; both configuration files are overwritten by the environment
+variable
+.Env_var \%$GROFFER_OPT ;
+everything is overwritten by the command line arguments.
+.
+.
+.P
+In the configuration files, arbitrary spaces are allowed at the
+beginning of each line, they are just ignored.
+.
+Apart from that, the lines of the configuration lines either start
+with a minus character, all other lines are interpreted as shell
+commands.
+.
+.
+.P
+The lines with the beginning minus are interpreted as
+.B groffer
+options.
+.
+This easily allows to set general
+.B \%groffer
+options that should be used with any call of
+.BR \%groffer .
+.
+.
+.P
+If a lines starts with a double minus it represents a
+.B \%groffer
+long option; everything behind the first equal sign
+.RB ` = '
+or space character up to the end of the line is interpreted as its
+argument.
+.
+A line starting with a single minus represents a short options cluster
+with or without a final argument.
+.
+It is not necessary to use quotes in these lines; quotes are just
+ignored.
+.
+.
+.P
+The lines starting with a minus are changed into a prepend to the
+existing value of
+.Env_var \%$GROFFER_OPT .
+.
+So the configuration files will be transferred into a shell script
+that is called within
+.BR \%groffer .
+.
+.
+.P
+It makes sense to use these configuration files for the following
+tasks:
+.
+.Topic
+Preset command line options, such as choosing a
+.I \%mode
+or a viewer.
+.
+These are written into lines starting with a single or double minus
+sign, followed by the option name.
+.
+.Topic
+Preset environment variables recognized by
+.BR \%groffer ;
+but do not forget to export them.
+.
+.Topic
+You can also write a shell function for calling, for example a viewer
+program for some
+.IR \%mode .
+Such a function can be fed into a corresponding
+.B --\f[I]mode\fP\-viewer
+option.
+.
+.Topic
+Enter
+.B --shell
+to specify a shell for the run of
+.File_name groffer2.sh .
+Some shells run much faster than the standard shell.
+.
+.
+.P
+As an example, consider the following configuration file that can be
+used either in
+.File_name \%/etc/groff/groffer.conf
+or
+.File_name \%~/.groff/groffer.conf .
+.
+.
+.P
+.ft CR
+.nh
+.nf
+# groffer configuration file
+#
+# groffer options that are used in each call of groffer
+\-\-shell=ksh
+\-\-foreground=DarkBlue
+\-\-resolution=100
+\-\-x\-viewer=gxditview \-geometry 900x1200
+#
+# some shell commands
+if test "$DISPLAY" = ""; then
+  export DISPLAY='localhost:0.0'
+fi
+date >>~/mygroffer.log
+.fi
+.hy
+.ft
+.
+.
+.P
+The lines starting with
+.B #
+are just ignored, so they act as command lines.
+.
+This configuration sets four
+.B \%groffer
+options (the lines starting with `\-') and runs two shell commands (the
+rest of the script).
+.
+This has the following effects:
+.
+.
+.Topic
+Use
+.B ksh
+as the shell to run the
+.B \%groffer
+script; if it works it should be faster than the usual
+.BR sh .
+.
+.
+.Topic
+Use a text color of
+.B \%DarkBlue
+in all viewers that support this, such as
+.BR \%gxditview .
+.
+.
+.Topic
+Use a resolution of
+.B 100dpi
+in all viewers that support this, such as
+.BR \%gxditview .
+.
+By this, the default device in
+.I x mode
+is set to
+.BR X100 .
+.
+.
+.Topic
+Force
+.BR \%gxditview (@MAN1EXT@)
+as the
+.I \%x-mode
+viewer using the geometry option for setting the width to
+.B 900px
+and the height to
+.BR 1200px .
+This geometry is suitable for a resolution of
+.BR 100dpi .
+.
+.
+.Topic
+If the environment variable
+.Env_var \%$DISPLAY
+is empty set it to
+.IR localhost:0.0 .
+.
+That allows to start
+.B \%groffer
+in the standard \%\f[CR]X\~Window\fP display, even when the program
+is called from a text console.
+.
+.
+.Topic
+Just for fun, the date of each
+.B \%groffer
+start is written to the file
+.File_name mygroffer.log
+in the home directory.
+.
+.
+.\" --------------------------------------------------------------------
+.SH "EXAMPLES"
+.\" --------------------------------------------------------------------
+.
+The usage of
+.B \%groffer
+is very easy.
+.
+Usually, it is just called with a file name or
+.IR \%man\~page .
+.
+The following examples, however, show that
+.B \%groffer
+has much more fancy capabilities.
+.
+.sp
+.EX
+\fIsh#\fR\~groffer\~/usr/local/share/doc/groff/meintro.ms.gz
+.EE
+.sp
+Decompress, format and display the compressed file
+.File_name meintro.ms.gz
+in the directory
+.File_name /usr/local/share/doc/groff ,
+using the standard viewer
+.B \%gxditview
+as graphical viewer when in \%\f[CR]X\~Window\fP, or the
+.BR \%less (1)
+pager program when not in \%\f[CR]X\~Window\fP.
+.
+.sp
+.EX
+\fIsh#\fR\~groffer\~groff
+.EE
+.sp
+If the file
+.File_name \%./groff
+exists use it as input.
+.
+Otherwise interpret the argument as a search for the
+.I \%man\~page
+named
+.B \%groff
+in the smallest possible
+.IR \%man\~section ,
+being section 1 in this case.
+.
+.sp
+.EX
+\fIsh#\fR\~groffer\~man:groff
+.EE
+.sp
+search for the
+.I \%man\~page
+of
+.B \%groff
+even when the file
+.File_name ./groff
+exists.
+.
+.sp
+.EX
+\fIsh#\fR\~groffer\~groff.7
+\fIsh#\fR\~groffer\~7\~groff
+.EE
+.sp
+search the
+.I \%man\~page
+of
+.B \%groff
+in
+.I \%man\~section
+.BR 7 .
+This section search works only for a digit or a single character from
+a small set.
+.
+.sp
+.EX
+\fIsh#\fR\~groffer\~fb.modes
+.EE
+.sp
+If the file
+.File_name ./fb.modes
+does not exist interpret this as a search for the
+.I \%man\~page
+of
+.BR fb.modes .
+As the extension
+.I \%modes
+is not a single character in classical section style the argument is
+not split to a search for
+.BR fb .
+.
+.sp
+.EX
+\fIsh#\fR\~groffer\~groff\~\[cq]troff(1)\[cq]\~man:roff
+.EE
+.sp
+The arguments that are not existing files are looked-up as the
+following
+.IR \%man\~pages :
+.B \%groff
+(automatic search, should be found in \fIman\fP\~section\~1),
+.B \%troff
+(in section\~1),
+and
+.B \%roff
+(in the section with the lowest number, being\~7 in this case).
+.
+The quotes around
+.nh
+.I \[cq]troff(1)\[cq]
+.hy
+are necessary because the parentheses are special shell characters;
+escaping them with a backslash character
+.I \[rs](
+and
+.I \[rs])
+would be possible, too.
+.
+The formatted files are concatenated and displayed in one piece.
+.
+.sp
+.EX
+\fIsh#\fR\~LANG=de\~groffer\~--man\~--www\~--www-viewer=galeon\~ls
+.EE
+.sp
+Retrieve the German
+.I \%man\~page
+(language
+.IR de )
+for the
+.B ls
+program, decompress it, format it to
+.I \%html
+format
+.nh
+.RI ( \%www\~mode )
+.hy
+and view the result in the web browser
+.BR \%galeon .
+The option
+.B --man
+guarantees that the
+.I \%man\~page
+is retrieved, even when a local file
+.File_name \%ls
+exists in the actual directory.
+.
+.
+.sp
+.EX
+\fIsh#\fR\~groffer\~--source\~'man:roff(7)'
+.EE
+.sp
+Get the
+.I \%man\~page
+called
+.I \%roff
+in \fIman\fP\~section 7, decompress it, and print its unformatted
+content, its source code.
+.
+.
+.sp
+.EX
+\fIsh#\fR\~groffer\~--de-p\~--in\~--ap
+.EE
+.sp
+This is a set of abbreviated arguments, it is determined as
+.br
+.sp
+.EX
+\fIsh#\fR\~groffer\~--debug-params\~--intermediate-output\~--apropos
+.EE
+.sp
+.
+.sp
+.EX
+\fIsh#\fR\~cat\~file.gz\~|\~groffer\~-Z\~-mfoo
+.EE
+.sp
+.
+The file
+.File_name file.gz
+is sent to standard input, this is decompressed, and then this is
+transported to the
+.I \%groff intermediate output mode
+without post-processing
+.RB ( groff
+option
+.BR -Z ),
+using macro package
+.I \%foo
+.RB ( groff
+option
+.BR -m ).
+.
+.
+.sp
+.EX
+\fIsh#\fR\~echo\~'\[rs]f[CB]WOW!'\~|
+> groffer --x --bg red --fg yellow --geometry 200x100 -
+.EX
+.sp
+.
+Display the word \f[CB]WOW!\fP in a small window in constant-width
+bold font, using color yellow on red background.
+.
+.
+.\" --------------------------------------------------------------------
+.SH "COMPATIBILITY"
+.\" --------------------------------------------------------------------
+.
+The
+.B \%groffer
+program consists of two shell scripts.
+.
+.
+.P
+The starting script is the file
+.File_name \%groffer
+that is installed in a
+.File_name bin
+directory.
+.
+It is generated from the source file
+.File_name \%groffer.sh .
+.
+It is just a short starting script without any functions such that it
+can run on very poor shells.
+.
+.
+.P
+The main part of the
+.B \%groffer
+program is the file
+.File_name groffer2.sh
+that is installed in the
+.I groff
+library directory.
+.
+This script can be run under a different shell by using the
+.B \%groffer
+option
+.BR --shell .
+.
+.
+.P
+Both scripts are compatible with both
+\f[CR]GNU\fP and \%\f[CR]POSIX\fP.
+.
+\%\f[CR]POSIX\fP compatibility refers to
+\%\f[CR]IEEE\~P1003.2/D11.2\fP of September 1991, a very early
+version of the \%\f[CR]POSIX\fP standard that is still freely
+available on the Internet at
+.UR http://\:www.funet.fi/\:pub/\:doc/\:posix/\:p1003.2/\:d11.2/\:all
+\%POSIX\~P1003.2\~draft\~11.2
+.UE .
+.
+.
+.P
+Only a restricted set of shell language elements and shell builtins is
+used to achieve even compatibility with some Bourne shells that are
+not fully \%\f[CR]POSIX\fP compatible.
+.
+The
+.B \%groffer
+shell scripts were tested on many shells, including the following
+Bourne shells:
+.BR \%ash (1),
+.BR \%bash (1),
+.BR \%dash (1),
+.BR \%ksh (1),
+.BR \%pdksh (1),
+.BR \%posh (1),
+and
+.BR \%zsh (1).
+So it should work on most actual free and commercial operating
+systems.
+.
+.
+.P
+The shell for the run of
+.File_name groffer2.sh
+can be chosen by the option
+.BR --shell
+on the command line or the environment variable
+.Env_var $GROFF_OPT .
+If you want to add it to one of the
+.B \%groffer
+configuration files you must write a line starting with
+.BR --shell .
+.
+.
+.P
+The
+.B \%groffer
+program provides its own parser for command line arguments that is
+compatible to both \%\f[CR]POSIX\fP
+.BR \%getopts (1)
+and \%\f[CR]GNU\fP
+.BR \%getopt (1).
+It can handle option arguments and file names containing white space
+and a large set of special characters.
+.
+The following standard types of options are supported.
+.
+.
+.Topic
+The option consisting of a single minus
+.B -
+refers to standard input.
+.
+.
+.Topic
+A single minus followed by characters refers to a single character
+option or a combination thereof; for example, the
+.B \%groffer
+short option combination
+.B -Qmfoo
+is equivalent to
+.BR -Q\~\-m\~foo .
+.
+.
+.Topic
+Long options are options with names longer than one character; they
+are always preceded by a double minus.
+.
+An option argument can either go to the next command line argument or
+be appended with an equal sign to the argument; for example,
+.B --long=arg
+is equivalent to
+.BR --long\~arg .
+.
+.
+.Topic
+An argument of
+.B --
+ends option parsing; all further command line arguments are
+interpreted as
+.I \%filespec
+parameters, i.e. file names or constructs for searching
+.IR \%man\~pages ).
+.
+.
+.Topic
+All command line arguments that are neither options nor option
+arguments are interpreted as
+.I \%filespec
+parameters and stored until option parsing has finished.
+.
+For example, the command line
+.sp
+.EX
+\fIsh#\fR\~groffer file1 -a -o arg file2
+.EE
+.sp
+is equivalent to
+.sp
+.EX
+\fIsh#\fR\~groffer -a -o arg -- file1 file2
+.EE
+.sp
+.
+.P
+The free mixing of options and
+.I \%filespec
+parameters follows the GNU principle.
+.
+That does not fulfill the strange option behavior of \%\f[CR]POSIX\fP
+that ends option processing as soon as the first non-option argument
+has been reached.
+.
+The end of option processing can be forced by the option
+.RB ` \-\- '
+anyway.
+.
+.
+.\" --------------------------------------------------------------------
+.SH "BUGS"
+.\" --------------------------------------------------------------------
+.
+Report bugs to the
+.MT address@hidden
+bug-groff mailing list 
+.ME .
+.
+Include a complete, self-contained example that will allow the bug to
+be reproduced, and say which version of
+.B \%groffer
+you are using.
+.
+.
+.P
+You can also use the
+.MT address@hidden
+groff mailing list
+.ME ,
+but you must first subscribe to this list.
+.
+You can do that by visiting the
+.UR http://\:lists.gnu.org/\:mailman/\:listinfo/\:groff
+groff mailing list web page
+.UE .
+.
+.
+.P
+See
+.BR \%groff (@MAN1EXT@)
+for information on availability.
+.
+.
+.\" --------------------------------------------------------------------
+.SH "SEE ALSO"
+.\" --------------------------------------------------------------------
+.
+.P
+.BR \%groff (@MAN1EXT@),
+.BR address@hidden@troff (@MAN1EXT@)
+.RS
+Details on the options and environment variables available in
+.BR \%groff ;
+all of them can be used with
+.BR \%groffer .
+.RE
+.
+.
+.TP
+.BR \%groff (@MAN7EXT@)
+Documentation of the
+.I \%groff
+language.
+.
+.
+.TP
+.BR \%grog (@MAN1EXT@)
+Internally,
+.B \%groffer
+tries to guess the
+.B \%groff
+command line options from the input using this program.
+.
+.
+.TP
+.BR groff_out (@MAN5EXT@)
+Documentation on the
+.I \%groff intermediate output
+.nh
+.RI ( ditroff
+output).
+.hy
+.
+.
+.TP
+.BR groff_tmac (@MAN5EXT@)
+Documentation on the
+.I \%groff
+macro files.
+.
+.
+.TP
+.BR \%man (1)
+The standard program to display
+.IR \%man\~pages .
+.
+The information there is only useful if it is the
+.I \%man\~page
+for GNU
+.BR man .
+Then it documents the options and environment variables that are
+supported by
+.BR \%groffer .
+.
+.
+.P
+.BR \%ash (1),
+.BR \%bash (1),
+.BR \%dash (1),
+.BR \%ksh (1),
+.BR \%pdksh (1),
+.BR \%posh (1),
+.BR \%sh (1),
+.BR \%zsh (1)
+.RS
+Bourne shells that were tested with
+.BR \%groffer .
+.RE
+.
+.
+.P
+.BR \%gxditview (@MAN1EXT@),
+.BR \%xditview (1x)
+.RS
+Viewers for
+.BR \%groffer 's
+.IR \%x\~mode .
+.RE
+.
+.
+.P
+.BR \%kpdf (1),
+.BR \%kghostview (1),
+.BR \%evince (1),
+.BR \%ggv (1),
+.BR \%gv (1),
+.BR \%ghostview (1),
+.BR \%gs (1)
+.RS
+Viewers for
+.BR \%groffer 's
+.IR \%ps\~mode .
+.RE
+.
+.
+.P
+.BR \%kpdf (1),
+.BR \%acroread (1),
+.BR \%evince (1),
+.BR \%xpdf (1),
+.BR \%gpdf (1),
+.BR \%kghostview (1),
+.BR \%ggv (1)
+.RS
+Viewers for
+.BR \%groffer 's
+.IR \%pdf\~mode .
+.RE
+.
+.
+.P
+.BR \%kdvi (1),
+.BR \%xdvi (1),
+.BR \%dvilx (1)
+.RS
+Viewers for
+.BR \%groffer 's
+.IR \%dvi\~mode .
+.RE
+.
+.
+.P
+.BR \%konqueror (1),
+.BR \%epiphany (1),
+.BR \%firefox (1),
+.BR \%mozilla (1),
+.BR \%netscape (1),
+.BR \%lynx (1)
+.RS
+Web-browsers for
+.BR \%groffer 's
+.I \%html
+or
+.IR \%www\~mode .
+.RE
+.
+.
+.TP
+.BR \%less (1)
+Standard pager program for the
+.IR \%tty\~mode .
+.
+.
+.P
+.BR \%gzip (1),
+.BR \%bzip2 (1)
+.RS
+The decompression programs supported by
+.BR \%groffer .
+.RE
+.
+.
+.\" --------------------------------------------------------------------
+.SH "AUTHOR"
+.\" --------------------------------------------------------------------
+.author
+.
+.
+.\" --------------------------------------------------------------------
+.SH "COPYING"
+.\" --------------------------------------------------------------------
+.copyleft
+.
+.
+.\" --------------------------------------------------------------------
+.\" Emacs settings
+.\" --------------------------------------------------------------------
+.
+.\" Local Variables:
+.\" mode: nroff
+.\" End:

Index: groffer.sh
===================================================================
RCS file: groffer.sh
diff -N groffer.sh
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ groffer.sh  11 Aug 2013 08:28:24 -0000      1.7
@@ -0,0 +1,384 @@
+#! /bin/sh
+
+# groffer - display groff files
+
+# Source file position: <groff-source>/contrib/groffer/groffer.sh
+# Installed position: <prefix>/bin/groffer
+
+# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009
+# Free Software Foundation, Inc.
+# Written by Bernd Warken <address@hidden>.
+
+# 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/>.
+
+########################################################################
+
+export GROFFER_OPT;            # option environment for groffer
+
+export _CONF_FILE_ETC;         # configuration file in /etc
+export _CONF_FILE_HOME;                # configuration file in $HOME
+export _CONF_FILES;            # configuration files
+_CONF_FILE_ETC='/etc/groff/groffer.conf';
+_CONF_FILE_HOME="${HOME}/.groff/groffer.conf";
+_CONF_FILES="${_CONF_FILE_ETC} ${_CONF_FILE_HOME}";
+
+# characters
+
+export _AT;
+export _SP;
+export _SQ;
+export _TAB;
+
+_AT='@';
+_SP=' ';
+_SQ="'";
+_TAB=' ';
+
+export _ERROR;
+_ERROR='7';                    # for syntax errors; no `-1' in `ash'
+
+# @...@ constructs
+
+export _BEFORE_MAKE;
+if test address@hidden@_ = _${_AT}VERSION${_AT}_
+then
+  # script before `make'
+  _BEFORE_MAKE='yes';
+else
+  _BEFORE_MAKE='no';
+fi;
+
+export _AT_BINDIR_AT;
+export _AT_G_AT;
+export _AT_LIBDIR_AT;
+export _GROFFER_LIBDIR;
+case "${_BEFORE_MAKE}" in
+yes)
+  self="$0";
+  case "${self}" in
+  /*) :; ;;
+  *)
+    curdir="$(pwd)";
+    case "${curdir}" in
+    */)
+      self="${curdir}${self}";
+      ;;
+    *)
+      self="${curdir}/${self}";
+      ;;
+    esac;
+    ;;
+  esac;
+  groffer_shell_dir="$(dirname ${self})";
+  case "${groffer_shell_dir}" in
+  */) :; ;;
+  *) groffer_shell_dir="${groffer_shell_dir}/";
+  esac;
+  groffer_top_dir="${groffer_shell_dir}../";
+  _AT_G_AT='';
+  _AT_BINDIR_AT="${groffer_shell_dir}";
+  _AT_LIBDIR_AT="${groffer_shell_dir}";
+  _GROFFER_LIBDIR="${_AT_LIBDIR_AT}";
+  _VERSION_SH="${groffer_top_dir}version.sh";
+  ;;
+no)
+  _AT_G_AT='@g@';
+  _AT_BINDIR_AT='@BINDIR@';
+  case "${_AT_BINDIR_AT}" in
+  */) :; ;;
+  *) _AT_BINDIR_AT="${_AT_BINDIR_AT}/";
+  esac;
+  _AT_LIBDIR_AT='@libdir@';
+  case "${_AT_LIBDIR_AT}" in
+  */) :; ;;
+  *) _AT_LIBDIR_AT="${_AT_LIBDIR_AT}/";
+  esac;
+  _GROFFER_LIBDIR="${_AT_LIBDIR_AT}"'groff/groffer/';
+  _VERSION_SH="${_GROFFER_LIBDIR}"'version.sh';
+  ;;
+esac;
+
+if test -f "${_VERSION_SH}"
+then
+  . "${_VERSION_SH}";
+fi;
+
+export _GROFF_VERSION;
+case "${_BEFORE_MAKE}" in
+yes)
+  _GROFF_VERSION="${_GROFF_VERSION_PRESET}";
+  ;;
+no)
+  _GROFF_VERSION='@VERSION@';
+  ;;
+esac;
+
+export _GROFFER2_SH;           # file name of the script that follows up
+_GROFFER2_SH="${_GROFFER_LIBDIR}"'groffer2.sh';
+
+export _GROFFER_SH;            # file name of this shell script
+case "$0" in
+*groffer*)
+  _GROFFER_SH="$0";
+  ;;
+*)
+  echo 'The groffer script should be started directly.' >&2
+  exit 1;
+  ;;
+esac;
+
+export _NULL_DEV;
+if test -c /dev/null
+then
+  _NULL_DEV="/dev/null";
+else
+  _NULL_DEV="NUL";
+fi;
+
+
+# Test of the `$()' construct.
+if test _"$(echo "$(echo 'test')")"_ \
+     != _test_
+then
+  echo 'The "$()" construct did not work.' >&2;
+  exit "${_ERROR}";
+fi;
+
+# Test of sed program
+if test _"$(echo red | sed 's/r/s/')"_ != _sed_
+then
+  echo 'The sed program did not work.' >&2;
+  exit "${_ERROR}";
+fi;
+
+# for some systems it is necessary to set some unset variables to `C'
+# according to Autobook, ch. 22
+for var in LANG LC_ALL LC_MESSAGES LC_CTYPES LANGUAGES
+do
+  if eval test _"\${$var+set}"_ = _set_
+  then
+    eval ${var}='C';
+    eval export ${var};
+  fi;
+done;
+
+
+########################### configuration
+
+# read and transform the configuration files, execute the arising commands
+for f in "${_CONF_FILE_HOME}" "${_CONF_FILE_ETC}"
+do
+  if test -f "$f"
+  then
+    o="";                      # $o means groffer option
+    # use "" quotes because of ksh and posh
+    eval "$(cat "$f" | sed -n '
+# Ignore comments
+/^['"${_SP}${_TAB}"']*#/d
+# Delete leading and final space
+s/^['"${_SP}${_TAB}"']*//
+s/['"${_SP}${_TAB}"']*$//
+# Print all lines with shell commands, those not starting with -
+/^[^-]/p
+# Remove all single and double quotes
+s/['"${_SQ}"'"]//g
+# Replace empty arguments
+s/^\(-[^ ]*\)=$/o="${o} \1 '"${_SQ}${_SQ}"'"/p
+# Replace division between option and argument by single space
+s/[='"${_SP}${_TAB}"']['"${_SP}${_TAB}"']*/'"${_SP}"'/
+# Handle lines without spaces
+s/^\(-[^'"${_SP}"']*\)$/o="${o} \1"/p
+# Encircle the remaining arguments with single quotes
+s/^\(-[^ ]*\) \(.*\)$/o="${o} \1 '"${_SQ}"'\2'"${_SQ}"'"/p
+')"
+
+    # Remove leading space
+    o="$(echo "$o" | sed 's/^ *//')";
+    if test _"${o}"_ != __
+    then
+      if test _"{GROFFER_OPT}"_ = __
+      then
+        GROFFER_OPT="${o}";
+      else
+        GROFFER_OPT="${o} ${GROFFER_OPT}";
+      fi;
+    fi;
+  fi;
+done;
+
+# integrate $GROFFER_OPT into the command line; it isn't needed any more
+if test _"${GROFFER_OPT}"_ != __
+then
+  eval set x "${GROFFER_OPT}" '"$@"';
+  shift;
+  GROFFER_OPT='';
+fi;
+
+
+########################### Determine the shell
+
+export _SHELL;
+
+supports_func=no;
+foo() { echo bar; } 2>${_NULL_DEV};
+if test _"$(foo)"_ = _bar_
+then
+  supports_func=yes;
+fi;
+
+# use "``" instead of "$()" for using the case ")" construct
+# do not use "" quotes because of ksh
+_SHELL=`
+  # $x means list.
+  # $s means shell.
+  # The command line arguments are taken over.
+  # Shifting herein does not have an effect outside.
+  export x;
+  case " $*" in
+  *\ --sh*)                    # abbreviation for --shell
+    x='';
+    s='';
+    # determine all --shell arguments, store them in $x in reverse order
+    while test $# != 0
+    do
+      case "$1" in
+      --shell|--sh|--she|--shel)
+        if test "$#" -ge 2
+        then
+          s="$2";
+          shift;
+        fi;
+        ;;
+      --shell=*|--sh=*|--she=*|--shel=*)
+        # delete up to first "=" character
+        s="$(echo x"$1" | sed 's/^x[^=]*=//')";
+        ;;
+      *)
+        shift;
+        continue;
+      esac;
+      if test _"${x}"_ = __
+      then
+        x="'${s}'";
+      else
+        x="'${s}' ${x}";
+      fi;
+      shift;
+    done;
+
+    # from all possible shells in $x determine the first being a shell
+    # or being empty
+    s="$(
+      # "" quotes because of posh
+      eval set x "${x}";
+      shift;
+      if test $# != 0
+      then
+        for i
+        do
+          if test _"$i"_ = __
+          then
+            if test _"${supports_func}"_ = _yes_
+            then
+              # use the empty argument as the default shell
+              echo 'standard shell';
+              break;
+            else
+              echo groffer: standard shell does not support functions. >&2;
+              continue;
+            fi;
+          else
+            # test $i on being a shell program;
+            # use this kind of quoting for posh
+            if test _"$(eval "$i -c 'echo ok'" 2>${_NULL_DEV})"_ = _ok_ >&2
+            then
+              # test whether shell supports functions
+              if eval "$i -c 'foo () { exit 0; }; foo'" 2>${_NULL_DEV}
+              then
+                # shell with function support found
+                cat <<EOF
+${i}
+EOF
+                break;
+              else
+                # if not being a shell with function support go on searching
+                echo groffer: argument $i is not a shell \
+with function support. >&2
+                continue;
+              fi;
+            else
+              # if not being a shell go on searching
+              echo groffer: argument $i is not a shell. >&2
+              continue;
+            fi;
+          fi;
+        done;
+      fi;
+    )";
+    if test _"${s}"_ != __
+    then
+      cat <<EOF
+${s}
+EOF
+    fi;
+    ;;
+  esac;
+`
+
+########################### test fast shells for automatic run
+
+if test _"${_SHELL}"_ = __
+then
+  # shell sorted by speed, bash is very slow
+  for s in ksh ash dash pdksh zsh posh sh bash
+  do
+    # test on shell with function support
+    if eval "$s -c 'foo () { exit 0; }; foo'" 2>${_NULL_DEV}
+    then
+      _SHELL="$s";
+      break;
+    fi;
+  done;
+fi;
+
+
+########################### start groffer2.sh
+
+if test _"${_SHELL}"_ = _'standard shell'_
+then
+  _SHELL='';
+fi;
+
+if test _"${_SHELL}"_ = __
+then
+  # no shell found, so start groffer2.sh normally
+  if test _${supports_func}_ = _yes_
+  then
+    eval . "'${_GROFFER2_SH}'" '"$@"';
+    exit;
+  else
+    echo groffer: standard shell does not support functions; no shell works.\
+Get some free working shell such as bash. >&2
+    exit "${_ERROR}";
+  fi;
+else
+  # start groffer2.sh with the found $_SHELL
+  # do not quote $_SHELL to allow arguments
+  eval exec "${_SHELL} '${_GROFFER2_SH}'" '"$@"';
+  exit;
+fi;

Index: groffer2.sh
===================================================================
RCS file: groffer2.sh
diff -N groffer2.sh
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ groffer2.sh 11 Aug 2013 08:28:24 -0000      1.9
@@ -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 <address@hidden>.
+
+# 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 address@hidden (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 "$@";

Index: roff2.sh
===================================================================
RCS file: roff2.sh
diff -N roff2.sh
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ roff2.sh    11 Aug 2013 08:28:24 -0000      1.7
@@ -0,0 +1,339 @@
+#! /bin/sh
+
+# roff2* - transform roff files into other formats
+
+# Source file position: <groff-source>/contrib/groffer/shell/roff2.sh
+# Installed position: <prefix>/bin/roff2*
+
+# Copyright (C) 2006, 2009 Free Software Foundation, Inc.
+# Written by Bernd Warken <address@hidden>.
+
+# 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/>.
+
+########################################################################
+
+
+##############
+# 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()
+
+
+error_no_groffer='no';
+error_no_groffer() {
+  if test _"$error_no_groffer" = _yes
+  then
+    return;
+  fi;
+  error_no_groffer='yes';
+  echo2 "$name: groffer is not available.";
+}
+
+
+error_no_options='no';
+error_no_options() {
+  if test _"$error_no_options" = _yes
+  then
+    return;
+  fi;
+  error_no_groffer='yes';
+  echo2 "$name: groffer options are not allowed.";
+}
+
+
+usage_with_groffer() {
+  cat <<EOF
+usage: $Name [option]... [--] [filespec]...
+
+-h | --help     print usage information
+-v | --version  print version information
+
+All other options are arbitrary options of "groffer"; the options
+override the behavior of this program.
+
+"filespec"s are the same as in "groffer": either the names of
+existing, readable files or "-" for standard input or a search pattern
+for man pages.  No "filespec" assumes standard input automatically.
+EOF
+}
+
+usage_without_groffer() {
+  cat <<EOF
+usage: $Name [option]... [--] [filespec]...
+
+-h | --help     print usage information
+-v | --version  print version information
+
+No other options are allowed because "groffer" is not available.
+
+The only "filespec"s allowed are the names of existing, readable files
+or "-" for standard input.  No "filespec" assumes standard input
+automatically.
+EOF
+}
+
+
+where_is_prog() {
+  for p in `echo $PATH|sed "s/:/ /g"`
+  do
+    f="${p}/$1";
+    if test -f "$f" && test -x "$f"
+    then
+      echo1 "$f";
+      return;
+    fi;
+  done;
+}
+
+
+########################################################################
+
+export NULL_DEV;
+if test -c /dev/null
+then
+  NULL_DEV='/dev/null';
+else
+  NULL_DEV='NUL';
+fi;
+
+name="$(echo1 "$0" | sed 's|^.*//*\([^/]*\)$|\1|')";
+
+case "$name" in
+roff2[a-z]*)
+  mode="$(echo1 "$name" | sed 's/^roff2//')";
+  ;;
+*)
+  echo2 "wrong program name: $name";
+  exit 1;
+  ;;
+esac;
+
+groff_version="$(groff --version 2>$NULL_DEV)";
+if test $? -gt 0
+then
+  echo2 "$name error: groff does not work.";
+  exit 1;
+fi;
+groffer_version="$(groffer --version 2>$NULL_DEV)";
+if test $? -gt 0
+then
+  has_groffer='no';
+else
+  has_groffer='yes';
+fi;
+
+if test _"${has_groffer}" = _yes
+then
+  for i
+  do
+    case $i in
+    -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+      echo1 "$name in $groffer_version";
+      exit 0;
+      ;;
+    -h|--h|--he|--hel|--help)
+      usage_with_groffer;
+      exit 0;
+      ;;
+    esac;
+  done;
+  groffer --to-stdout --$mode "$@";
+else                           # not has_groffer
+  reset=no;
+  double_minus=no;
+  for i
+  do
+    if test _"${reset}" = _no
+    then
+      set --;
+      reset=yes;
+    fi;
+    if test _"${double_minus}" = _yes
+    then
+      set -- "$@" "$i";
+      continue;
+    fi;
+    case "$i" in
+    --)
+      double_minus=yes;
+      continue;
+      ;;
+    -)
+      set -- "$@" '-';
+      continue;
+      ;;
+    -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+      echo1 "$name in $groff_version";
+      exit 0;
+      ;;
+    -h|--h|--he|--hel|--help)
+      usage_without_groffer;
+      exit 0;
+      ;;
+    -*)
+      error_no_groffer;
+      error_no_options;
+      ;;
+    *)
+      if test -f "$i" && test -r "$i"
+      then
+        set -- "$@" "$i";
+      else
+        error_no_groffer;
+        echo2 "$i is not an existing, readable file.";
+      fi;
+      continue;
+      ;;
+    esac;
+  done;                                # for i
+
+  if test $# -eq 0
+  then
+    set -- '-';
+  fi;
+  has_stdin=no;
+  for i
+  do
+    case "$i" in
+    -)
+      has_stdin=yes;
+      break;
+      ;;
+    esac;
+  done;
+
+  if test _$has_stdin = _yes
+  then
+    umask 0077;
+    tempdir='';
+    for d in "${GROFF_TMPDIR}" "${TMPDIR}" "${TMP}" "${TEMP}" \
+           "${TEMPDIR}" "${HOME}"'/tmp' '/tmp' "${HOME}" '.'
+    do
+      if test _"$d" = _ || ! test -d "$d" || ! test -w "$d"
+      then
+        continue;
+      fi;
+      case "$d" in
+      */)
+        tempdir="$d";
+        ;;
+      *)
+        tempdir="$d"'/';
+        ;;
+      esac;
+    done;
+    if test _$tempdir = _
+    then
+      echo2 "${name}: could not find a temporary directory."
+      exit 1;
+    fi;
+    stdin=${tempdir}${name}_$$;
+    if test -e "$stdin"
+    then
+      rm -f "$stdin";
+      n=0;
+      f="${stdin}_$n";
+      while test -e "$f"
+      do
+       rm -f "$f";
+        if ! test -e "$f"
+        then
+          break;
+        fi;
+        n="$(expr $n + 1)";
+        f="${stdin}_$n";
+      done;
+      stdin="$f";
+    fi;
+    reset=no;
+    for i
+    do
+      if test _"${reset}" = _no
+      then
+        set --;
+        reset=yes;
+      fi;
+      case "$i" in
+      -)
+        set -- "$@" "$stdin";
+        ;;
+      *)
+        set -- "$@" "$i";
+        ;;
+      esac;
+    done;
+    cat>"$stdin";
+  fi;                          # if has_stdin
+
+  case "$mode" in
+  x)
+    groff_options='-TX75-12 -Z';
+    ;;
+  text)
+    groff_options='-Tlatin1';
+    ;;
+  pdf)
+    ps2pdf="$(where_is_prog ps2pdf)";
+    if test _"$ps2pdf" = _
+    then
+      ps2pdf="$(where_is_prog gs)";
+      if test _"$ps2pdf" = _
+      then
+        echo2 "$name: cannot transform to pdf format.";
+        exit 1;
+      fi;
+      ps2pdf="$ps2pdf -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite '-sOutputFile=- 
-c save pop -f -";
+    else
+      ps2pdf="$ps2pdf -";
+    fi;
+    grog="$(grog -Tps "$@")";
+    eval $grog | ${ps2pdf};
+    exit $?;
+    ;;
+  *)
+    groff_options="-T$mode";
+    ;;
+  esac;
+  grog="$(grog $groff_options "$@")";
+  eval $grog;
+  exit $?;
+fi;                            # not has_groffer



reply via email to

[Prev in Thread] Current Thread [Next in Thread]