3 # groffer - display groff files
5 # File position: <groff-source>/contrib/groffer/groffer
7 # Copyright (C) 2001,2002 Free Software Foundation, Inc.
8 # Written by Bernd Warken <bwarken@mayn.de>
10 # This file is part of groff.
12 # groff is free software; you can redistribute it and/or modify it
13 # under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2, or (at your option)
17 # groff is distributed in the hope that it will be useful, but WITHOUT
18 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
20 # License for more details.
22 # You should have received a copy of the GNU General Public License
23 # along with groff; see the file COPYING. If not, write to the
24 # Free Software Foundation, 59 Temple Place - Suite 330, Boston,
28 export _PROGRAM_VERSION;
31 _PROGRAM_NAME='groffer';
32 _PROGRAM_VERSION='0.9.1';
33 _LAST_UPDATE='30 Sep 2002';
35 ########################################################################
36 # Determine the shell under which to run this script;
37 # if `ash' is available restart the script using `ash';
38 # otherwise just go on.
40 if test "${_groffer_run}" != 'second'; then
41 # only reached during the first run of the script
48 #_this="@BINDIR@/${_PROGRAM_NAME}";
51 ###########################
52 # _get_opt_shell ("$@")
54 # Determine whether `--shell' was specified in $GROFF_OPT or in $*;
55 # if so echo its argument.
61 case " ${GROFFER_OPT} $*" in
62 *\ --shell\ *|*\ --shell=*)
64 eval set -- "${GROFFER_OPT}" '"$@"';
69 if test "$#" -ge 2; then
75 # delete up to first `=' character
76 _sh="$(echo -n "$1" | sed -e 's/^[^=]*=//')";
88 ###########################
89 # _test_on_shell (<name>)
91 # Test whether <name> is a shell program of Bourne type (POSIX sh).
95 if test "$#" -le 0 || test "$1" = ''; then
98 # do not quote $1 to allow arguments
99 test "$($1 -c 's=ok; echo -n "$s"' 2>/dev/null)" = 'ok';
102 # do the shell determination
103 _shell="$(_get_opt_shell "$@")";
104 if test "${_shell}" = ''; then
107 if _test_on_shell "${_shell}"; then
108 _groffer_run='second';
109 # do not quote $_shell to allow arguments
110 exec ${_shell} "${_this}" "$@";
114 # clean-up of shell determination
130 ########################################################################
131 # diagnostic messages
134 _DEBUG='no'; # disable debugging information
135 #_DEBUG='yes'; # enable debugging information
138 _DEBUG_LM='no'; # disable landmark messages
139 #_DEBUG_LM='yes'; # enable landmark messages
142 ########################################################################
144 ########################################################################
146 # Display groff files and man pages on X or tty, even when compressed.
151 # Input comes from either standard input or command line parameters
152 # that represent either names of exisiting roff files or standardized
153 # specifications for man pages. All of these can be compressed in a
154 # format that is decompressible by `gzip'.
156 # The following displaying modes are available:
157 # - Display formatted input with the X roff viewer `gxditview',
158 # - with a Prostcript viewer,
159 # - with a dvi viewer,
160 # - with a web browser.
161 # - Display formatted input in a text terminal using a text device.
162 # - Generate output for some groff device on stdout without a viewer.
163 # - Output only the source code without any groff processing.
164 # - Generate the troff intermediate output on standard output
165 # without groff postprocessing.
166 # By default, the program tries to display with `gxditview' (1); if
167 # this does not work, text display (2) is used.
172 # Error handling and exit behavior is complicated by the fact that
173 # `exit' can only escape from the current shell; trouble occurs in
174 # subshells. This was solved by sending kill signals, see
175 # $_PROCESS_ID and error().
180 # This shell script is compatible to the both the GNU and the POSIX
181 # shell and utilities. Care was taken to restrict the programming
182 # technics used here in order to achieve POSIX compatibility as far
183 # back as POSIX P1003.2 Draft 11.2 of September 1991.
185 # The only non-builtin used here is POSIX `sed'. This script was
186 # tested under `bash', `ash', and `ksh'. The speed under `ash' is
187 # more than double when compared to the larger shells.
189 # This script provides its own option parser. It is compatible to the
190 # usual GNU style command line (option clusters, long options, mixing
191 # of options and non-option file names), except that it is not
192 # possible to abbreviate long option names.
194 # The mixing of options and file names can be prohibited by setting
195 # the environment variable `$POSIXLY_CORRECT' to a non-empty value.
196 # This enables the rather wicked POSIX behavior to terminate option
197 # parsing when the first non-option command line argument is found.
200 ########################################################################
201 # Survey of functions defined in this document
202 ########################################################################
204 # The elements specified within paranthesis `(<>)' give hints to what
205 # the arguments are meant to be; the argument names are irrelevant.
207 # <>* arbitrarily many such arguments, incl. none
208 # <>+ one or more such arguments
211 # A function that starts with an underscore `_' is an internal
212 # function for some function. The internal functions are defined just
213 # after their corresponding function; they are not mentioned in the
220 # clean_up_secondary ()
222 # dirname_append (<path> [<dir...>])
223 # dirname_chop (<path>)
224 # do_filearg (<filearg>)
229 # get_first_essential (<arg>*)
231 # is_empty (<string>)
232 # is_equal (<string1> <string2>)
234 # is_not_empty (<string>)
235 # is_not_equal (<string1> <string2>)
236 # is_not_file (<name>)
237 # is_not_prog (<name>)
242 # list_append (<list> <element>...)
243 # list_check (<list>)
244 # list_from_args (<arg>...)
245 # list_from_cmdline (<s_n> <s_a> <l_n> <l_n> [<cmdline_arg>...])
246 # list_from_split (<string> <separator>)
247 # list_has (<list> <element>)
248 # list_has_not (<list> <element>)
249 # list_length (<list>)
250 # main_*(), see after the functions
251 # man_do_filespec (<filespec>)
253 # man_register_file (<file> [<name> [<section>]])
254 # man_search_section (<name> <section>)
256 # manpath_add_lang(<path> <language>)
257 # manpath_add_system()
258 # manpath_from_path ()
259 # normalize_args (<shortopts> <longopts> <arg>*)
261 # path_clean (<path>)
262 # path_contains (<path> <dir>)
263 # path_not_contains (<path> <dir>)
264 # path_split (<path>)
265 # register_file (<filename>)
266 # register_title (<filespec>)
269 # string_contains (<string> <part>)
270 # string_not_contains (<string> <part>)
272 # tmp_create (<suffix>?)
273 # to_tmp (<filename>)
277 # whatis (<filename>)
281 ########################################################################
282 # Environment Variables
283 ########################################################################
285 # Environment variables that exist only for this file start with an
286 # underscore letter. Global variables to this file are written in
287 # upper case letters, e.g. $_GLOBAL_VARIABLE; temporary variables
288 # start with an underline and use only lower case letters and
289 # underlines, e.g. $_local_variable .
291 # [A-Z]* system variables, e.g. $MANPATH
292 # _[A-Z_]* global file variables, e.g. $_MAN_PATH
293 # _[a-z_]* temporary variables, e.g. $_manpath
295 # Due to incompatibilities of the `ash' shell, the name of loop
296 # variables in `for' must be single character
297 # [a-z] local loop variables, e.g. $i
300 ########################################################################
301 # External environment variables
303 # If these variables are exported here then the `ash' shell coughs
304 # when calling `groff' in `main_display()'.
306 if test "${GROFFER_EXPORT_EXTERNALS}" = 'yes'; then
308 # external system environment variables that are explicitly used
309 export DISPLAY; # Presets the X display.
310 export LANG; # For language specific man pages.
311 export LC_ALL; # For language specific man pages.
312 export LC_MESSAGES; # For language specific man pages.
313 export PAGER; # Paging program for tty mode.
314 export PATH; # Path for the programs called (: list).
316 # groffer native environment variables
317 export GROFFER_OPT # preset options for groffer.
319 # all groff environment variables are used, see groff(1)
320 export GROFF_BIN_PATH; # Path for all groff programs.
321 export GROFF_COMMAND_PREFIX; # '' (normally) or 'g' (several troffs).
322 export GROFF_FONT_PATH; # Path to non-default groff fonts.
323 export GROFF_TMAC_PATH; # Path to non-default groff macro files.
324 export GROFF_TMPDIR; # Directory for groff temporary files.
325 export GROFF_TYPESETTER; # Preset default device.
327 # all GNU man environment variables are used, see man(1).
328 export MANOPT; # Preset options for man pages.
329 export MANPATH; # Search path for man pages (: list).
330 export MANROFFSEQ; # Ignored because of grog guessing.
331 export MANSECT; # Search man pages only in sections (:).
332 export SYSTEM; # Man pages for different OS's (, list).
337 ########################################################################
338 # read-only variables (global to this file)
339 ########################################################################
368 # function return values; `0' means ok; other values are error codes
378 _GOOD='0'; # return ok
379 _BAD='1'; # return negatively, error code `1'
380 _BAD2='2'; # return negatively, error code `2'
381 _BAD3='3'; # return negatively, error code `3'
382 _ERROR='255'; # for syntax errors; no `-1' in `ash'
388 # quasi-functions, call with `eval'
395 return_ok="func_pop; return ${_OK}";
396 return_good="func_pop; return ${_GOOD}";
397 return_bad="func_pop; return ${_BAD}";
398 return_yes="func_pop; return ${_YES}";
399 return_no="func_pop; return ${_NO}";
400 return_error="func_pop; return ${_ERROR}";
404 _CONFFILES="/etc/groff/groffer.conf ${HOME}/.groff/groffer.conf";
406 export _DEFAULT_MODES;
407 _DEFAULT_MODES='ps,x,tty';
408 export _DEFAULT_RESOLUTION;
409 _DEFAULT_RESOLUTION='100';
411 export _DEFAULT_TTY_DEVICE;
412 _DEFAULT_TTY_DEVICE='latin1';
414 # _VIEWER_* viewer programs for different modes (only X is necessary)
415 # _VIEWER_* a comma-separated list of viewer programs (with options)
416 export _VIEWER_DVI; # viewer program for dvi mode
417 export _VIEWER_PS; # viewer program for ps mode
418 export _VIEWER_WWW_X; # viewer program for www mode in X
419 export _VIEWER_WWW_TTY; # viewer program for www mode in tty
420 _VIEWER_DVI='xdvi,dvilx';
421 _VIEWER_PDF='xpdf,acroread';
422 _VIEWER_PS='gv,ghostview,gs_x11,gs';
423 _VIEWER_WWW='mozilla,netscape,opera,amaya,arena';
424 _VIEWER_X='gxditview,xditview';
426 # Search automatically in standard sections `1' to `8', and in the
427 # traditional sections `9', `n', and `o'. On many systems, there
428 # exist even more sections, mostly containing a set of man pages
429 # special to a specific program package. These aren't searched for
430 # automatically, but must be specified on the command line.
431 export _MAN_AUTO_SEC;
432 _MAN_AUTO_SEC="'1' '2' '3' '4' '5' '6' '7' '8' '9' 'n' 'o'"
434 export _PROCESS_ID; # for shutting down the program
438 ############ the command line options of the involved programs
440 # The naming scheme for the options environment names is
441 # $_OPTS_<prog>_<length>[_<argspec>]
443 # <prog>: program name GROFFER, GROFF, or CMDLINE (for all
444 # command line options)
445 # <length>: LONG (long options) or SHORT (single character options)
446 # <argspec>: ARG for options with argument, NA for no argument;
447 # without _<argspec> both the ones with and without arg.
449 # Each option that takes an argument must be specified with a
450 # trailing : (colon).
453 export _OPTS_GROFFER_SHORT_NA;
454 export _OPTS_GROFFER_SHORT_ARG;
455 export _OPTS_GROFFER_LONG_NA;
456 export _OPTS_GROFFER_LONG_ARG;
457 export _OPTS_GROFF_SHORT_NA;
458 export _OPTS_GROFF_SHORT_ARG;
459 export _OPTS_GROFF_LONG_NA;
460 export _OPTS_GROFF_LONG_ARG;
461 export _OPTS_MAN_SHORT_ARG;
462 export _OPTS_MAN_SHORT_NA;
463 export _OPTS_MAN_LONG_ARG;
464 export _OPTS_MAN_LONG_NA;
465 export _OPTS_GROFFER_LONG;
466 export _OPTS_GROFFER_SHORT;
467 export _OPTS_GROFF_LONG;
468 export _OPTS_GROFF_SHORT;
469 export _OPTS_CMDLINE_SHORT_NA;
470 export _OPTS_CMDLINE_SHORT_ARG;
471 export _OPTS_CMDLINE_SHORT;
472 export _OPTS_CMDLINE_LONG_NA;
473 export _OPTS_CMDLINE_LONG_ARG;
474 export _OPTS_CMDLINE_LONG;
477 ###### native groffer options
479 _OPTS_GROFFER_SHORT_NA="'h' 'Q' 'v' 'V' 'X' 'Z'";
480 _OPTS_GROFFER_SHORT_ARG="'T'";
482 _OPTS_GROFFER_LONG_NA="'all' 'apropos' 'ascii' 'auto' 'default' 'dvi' \
483 'groff' 'help' 'intermediate-output' 'local-file' 'location' 'man' \
484 'no-location' 'no-man' 'pdf' 'ps' 'rv' 'source' 'tty' 'tty-device' \
485 'version' 'whatis' 'where' 'www' 'x'";
487 _OPTS_GROFFER_LONG_ARG="'background' 'bd' 'bg' 'bw' 'default-modes' \
488 'device' 'display' 'dvi-viewer' 'extension' 'fg' 'fn' 'font' \
489 'foreground' 'geometry' 'locale' 'manpath' 'mode' 'pager' \
490 'pdf-viewer' 'ps-viewer' 'resolution' 'sections' 'shell' \
491 'systems' 'title' 'troff-device' 'www-viewer' 'xrm' 'x-viewer'";
493 ##### options inhereted from groff
495 _OPTS_GROFF_SHORT_NA="'a' 'b' 'c' 'e' 'g' 'i' 'l' 'p' 's' 't' 'z' \
496 'C' 'E' 'G' 'N' 'R' 'S' 'U' 'V'";
497 _OPTS_GROFF_SHORT_ARG="'d' 'f' 'F' 'I' 'L' 'm' 'M' 'n' 'o' 'P' 'r' \
499 _OPTS_GROFF_LONG_NA="";
500 _OPTS_GROFF_LONG_ARG="";
502 ###### man options (for parsing $MANOPT only)
504 _OPTS_MAN_SHORT_NA="'7' 'a' 'c' 'd' 'D' 'f' 'h' 'k' 'l' 't' 'u' \
506 _OPTS_MAN_SHORT_ARG="'e' 'L' 'm' 'M' 'p' 'P' 'r' 'S' 'T'";
508 _OPTS_MAN_LONG_NA="'all' 'ascii' 'apropos' 'catman' 'debug' 'default' \
509 'ditroff' 'help' 'local-file' 'location' 'troff' 'update' 'version' \
512 _OPTS_MAN_LONG_ARG="'extension' 'locale' 'manpath' \
513 'pager' 'preprocessor' 'prompt' 'sections' 'systems' 'troff-device'";
515 ###### collections of options
519 _OPTS_GROFFER_LONG="${_OPTS_GROFFER_LONG_ARG} ${_OPTS_GROFFER_LONG_NA}";
520 _OPTS_GROFFER_SHORT=\
521 "${_OPTS_GROFFER_SHORT_ARG} ${_OPTS_GROFFER_SHORT_NA}";
525 _OPTS_GROFF_LONG="${_OPTS_GROFF_LONG_ARG} ${_OPTS_GROFF_LONG_NA}";
526 _OPTS_GROFF_SHORT="${_OPTS_GROFF_SHORT_ARG} ${_OPTS_GROFF_SHORT_NA}";
528 # all command line options
530 _OPTS_CMDLINE_SHORT_NA="\
531 ${_OPTS_GROFFER_SHORT_NA} ${_OPTS_GROFF_SHORT_NA}";
532 _OPTS_CMDLINE_SHORT_ARG="\
533 ${_OPTS_GROFFER_SHORT_ARG} ${_OPTS_GROFF_SHORT_ARG}";
534 _OPTS_CMDLINE_SHORT="${_OPTS_GROFFER_SHORT} ${_OPTS_GROFF_SHORT}";
536 _OPTS_CMDLINE_LONG_NA="${_OPTS_GROFFER_LONG_NA} \
537 ${_OPTS_GROFF_LONG_NA} ${_OPTS_MAN_LONG_NA}";
538 _OPTS_CMDLINE_LONG_ARG="${_OPTS_GROFFER_LONG_ARG} \
539 ${_OPTS_GROFF_LONG_ARG} ${_OPTS_MAN_LONG_ARG}";
540 _OPTS_CMDLINE_LONG="${_OPTS_GROFFER_LONG} ${_OPTS_GROFF_LONG}";
543 ########################################################################
544 # read-write variables (global to this file)
545 ########################################################################
547 export _ADDOPTS_GROFF; # Transp. options for groff (`eval').
548 export _ADDOPTS_POST; # Transp. options postproc (`eval').
549 export _ADDOPTS_X; # Transp. options X postproc (`eval').
550 export _DEFAULT_MODES; # Set default modes.
551 export _DISPLAY_MODE; # Display mode.
552 export _DISPLAY_PROG; # Viewer program to be used for display.
553 export _DISPLAY_ARGS; # X resources for the viewer program.
554 export _FILEARGS; # Stores filespec parameters.
555 export _FUNC_STACK; # Store debugging information.
556 export _REGISTERED_TITLE; # Processed file names.
557 # _HAS_* from availability tests
558 export _HAS_COMPRESSION; # `yes' if compression is available
559 export _HAS_OPTS_GNU; # `yes' if GNU `getopt' is available
560 export _HAS_OPTS_POSIX; # `yes' if POSIX `getopts' is available
561 # _MAN_* finally used configuration of man searching
562 export _MAN_ALL; # search all man pages per filespec
563 export _MAN_ENABLE; # enable search for man pages
564 export _MAN_EXT; # extension for man pages
565 export _MAN_FORCE; # force file parameter to be man pages
566 export _MAN_IS_SETUP; # setup man variables only once
567 export _MAN_LANG; # language for man pages
568 export _MAN_LANG_DONE; # language dirs added to man path
569 export _MAN_PATH; # search path for man pages
570 export _MAN_SEC; # sections for man pages; sep. `:'
571 export _MAN_SEC_DONE; # sections added to man path
572 export _MAN_SYS; # system names for man pages; sep. `,'
573 export _MAN_SYS; # system names added to man path
574 # _MANOPT_* as parsed from $MANOPT
575 export _MANOPT_ALL; # $MANOPT --all
576 export _MANOPT_EXTENSION; # $MANOPT --extension
577 export _MANOPT_LANG; # $MANOPT --locale
578 export _MANOPT_PATH; # $MANOPT --manpath
579 export _MANOPT_PAGER; # $MANOPT --pager
580 export _MANOPT_SEC; # $MANOPT --sections
581 export _MANOPT_SYS; # $MANOPT --systems
582 # _OPT_* as parsed from groffer command line
583 export _OPT_ALL; # display all suitable man pages.
584 export _OPT_APROPOS; # branch to `apropos' program.
585 export _OPT_BD; # set border color in some modes.
586 export _OPT_BG; # set background color in some modes.
587 export _OPT_BW; # set border width in some modes.
588 export _OPT_DEBUG; # print debugging information on stderr.
589 export _OPT_DEFAULT_MODES; # `,'-list of modes when no mode given.
590 export _OPT_DEVICE; # device option.
591 export _OPT_DISPLAY; # set X display.
592 export _OPT_FG; # set foreground color in some modes.
593 export _OPT_FN; # set font in some modes.
594 export _OPT_GEOMETRY; # set size and position of viewer in X.
595 export _OPT_LANG; # set language for man pages
596 export _OPT_LOCATION; # print processed file names to stderr
597 export _OPT_MODE; # values: X, tty, Q, Z, ""
598 export _OPT_MANPATH; # manual setting of path for man-pages
599 export _OPT_PAGER; # specify paging program for tty mode
600 export _OPT_RESOLUTION; # set X resolution in dpi
601 export _OPT_RV; # reverse fore- and background colors.
602 export _OPT_SECTIONS; # sections for man page search
603 export _OPT_SYSTEMS; # man pages of different OS's
604 export _OPT_TITLE; # title for gxditview window
605 export _OPT_TTY_DEVICE; # set device for tty mode.
606 export _OPT_V; # groff option -V.
607 export _OPT_VIEWER_DVI; # viewer program for dvi mode
608 export _OPT_VIEWER_PDF; # viewer program for pdf mode
609 export _OPT_VIEWER_PS; # viewer program for ps mode
610 export _OPT_VIEWER_WWW; # viewer program for www mode
611 export _OPT_VIEWER_X; # viewer program for x mode
612 export _OPT_WHATIS; # print the one-liner man info
613 export _OPT_X; # groff option -X.
614 export _OPT_XRM; # specify X resource.
615 export _OPT_Z; # groff option -Z.
616 # _TMP_* temporary files
617 export _TMP_DIR; # directory for temporary files
618 export _TMP_CAT; # stores concatenation of everything
619 export _TMP_PREFIX; # dir and base name for temporary files
620 export _TMP_STDIN; # stores stdin, if any
622 # these variables are preset in section `Preset' after the rudim. test
625 ########################################################################
626 # Test of rudimentary shell functionality
627 ########################################################################
630 ########################################################################
633 test "a" = "a" || exit 1;
636 ########################################################################
637 # Test of `echo' and the `$()' construct.
639 echo -n '' >/dev/null || exit "${_ERROR}";
640 if test "$(echo -n 'te' && echo -n '' && echo -n 'st')" != "test"; then
645 ########################################################################
646 # Test of function definitions.
653 if _t_e_s_t_f_u_n_c_ 2>/dev/null; then
656 echo 'shell does not support function definitions.' >&2;
661 ########################################################################
662 # Preset and reset of read-write global variables
663 ########################################################################
666 # For variables that can be reset by option `--default', see reset().
670 # _HAS_* from availability tests
675 # _TMP_* temporary files
682 ########################################################################
685 # Reset the variables that can be affected by options to their default.
689 if test "$#" -ne 0; then
690 error "reset() does not have arguments.";
699 _REGISTERED_TITLE='';
701 # _MAN_* finally used configuration of man searching
703 _MAN_ENABLE='yes'; # do search for man-pages
705 _MAN_FORCE='no'; # first local file, then search man page
715 # _MANOPT_* as parsed from $MANOPT
717 _MANOPT_EXTENSION='';
724 # _OPT_* as parsed from groffer command line
731 _OPT_DEFAULT_MODES='';
764 ########################################################################
765 # Functions for error handling and debugging
766 ########################################################################
772 # Print <text> to standard error as a debugging aid.
774 # Globals: $_DEBUG_LM
778 if test "${_DEBUG_LM}" = 'yes'; then
783 landmark "1: debugging functions";
799 # clean_up_secondary ()
801 # Clean up temporary files without $_TMP_CAT.
805 rm -f "${_TMP_STDIN}";
814 # Arguments : arbitrary text.
827 # Arguments : arbitrary text.
838 # Output a diagnostic message to stderr
849 # Print an error message to standard error; exit with an error condition
858 1) echo2 'groffer error: '"$1"; ;;
860 echo2 'groffer error: '"$1";
863 *) echo2 'groffer error: wrong number of arguments in error().'; ;;
865 if test "${_DEBUG}" = 'yes'; then
869 kill "${_PROCESS_ID}" >/dev/null 2>&1;
870 kill -9 "${_PROCESS_ID}" >/dev/null 2>&1;
878 # Terminate program with error condition
882 error "Program aborted.";
888 # func_check (<func_name> <rel_op> <nr_args> "$@")
890 # Check number of arguments and register to _FUNC_STACK.
893 # <func_name>: name of the calling function.
894 # <rel_op>: a relational operator: = != < > <= >=
895 # <nr_args>: number of arguments to be checked against <operator>
896 # "$@": the arguments of the calling function.
905 if test "$#" -lt 3; then
906 error 'func_check() needs at least 3 arguments.';
919 error "func_check(): third argument must be a digit.";
949 'func_check(): second argument is not a relational operator.';
953 if test "$#" "${_op}" "${_nargs}"; then
957 "${_fname}"'() needs '"${_comp} ${_nargs}"' argument'"${_s}"'.';
959 if test "${_DEBUG}" = 'yes'; then
960 func_push "${_fname} $*";
968 # Retrieve the top element from the stack.
970 # The stack elements are separated by `!'; the popped element is
971 # identical to the original element, except that all `!' characters
978 if test "${_DEBUG}" = 'yes'; then
979 if test "$#" -ne 0; then
980 error 'func_pop() does not have arguments.';
982 case "${_FUNC_STACK}" in
984 error 'func_pop(): stack is empty.';
987 # split at first bang `!'.
988 _FUNC_STACK="$(echo -n ${_FUNC_STACK} \
989 | sed -e 's/^[^!]*!//')";
1000 # func_push (<element>)
1002 # Store another element to stack.
1004 # The stack elements are separated by `!'; if <element> contains a `!'
1005 # it is removed first.
1012 if test "${_DEBUG}" = 'yes'; then
1013 if test "$#" -ne 1; then
1014 error 'func_push() needs 1 argument.';
1018 # remove all bangs `!'.
1019 _element="$(echo -n "$1" | sed -e 's/!//g')";
1025 if test "${_FUNC_STACK}" = ''; then
1026 _FUNC_STACK="${_element}";
1028 _FUNC_STACK="${_element}!${_FUNC_STACK}";
1035 # func_stack_dump ()
1037 # Print the content of the stack. Ignore the arguments.
1042 case "${_FUNC_STACK}" in
1044 _rest="${_FUNC_STACK}";
1045 while test "${_rest}" != ''; do
1046 # get part before the first bang `!'.
1047 diag "$(echo -n "${_rest}" | sed -e 's/^\([^!]*\)!.*$/\1/')";
1048 # delete part up to the first bang `!'.
1049 _rest="$(echo -n "${_rest}" | sed -e 's/^!*[^!]*!*//')";
1053 diag "${_FUNC_STACK}";
1059 ########################################################################
1061 ########################################################################
1063 landmark "2: system test";
1065 # Test the availability of the system utilities used in this script.
1068 ########################################################################
1071 if true >/dev/null 2>&1; then
1086 ########################################################################
1090 if unset _test >/dev/null 2>&1 && test "${_test}" = ''; then
1102 ########################################################################
1103 # Test of builtin `local'
1108 local _test >/dev/null 2>&1 || return "${_BAD}";
1111 if _t_e_s_t_f_u_n_c_; then
1116 if test "$1" != ''; then
1117 error "overriding global variable \`$1' with local value.";
1123 ########################################################################
1124 # Test of global setting in functions
1137 if test "${_global}" != 'inside' || test "${_clobber}" != 'outside';
1139 error "Cannot assign to global variables from within functions.";
1146 ########################################################################
1147 # Test of function `sed'.
1149 if test "$(echo xTesTx \
1150 | sed -e 's/^.\([Tt]e*x*sTT*\).*$/\1/' \
1151 | sed -e '\|T|s||t|g')" != 'test';
1153 error 'Test of "sed" command failed.';
1157 ########################################################################
1158 # Test of function `cat'.
1160 if test "$(echo test | cat)" != "test"; then
1161 error 'Test of "cat" command failed.';
1165 ########################################################################
1166 # Test for compression.
1168 if test "$(echo 'test' | gzip -c -d -f - 2>/dev/null)" = 'test'; then
1169 _HAS_COMPRESSION='yes';
1170 if echo 'test' | bzip2 -c 2>/dev/null | bzip2 -t 2>/dev/null \
1171 && test "$(echo 'test' | bzip2 -c 2>/dev/null \
1172 | bzip2 -d -c 2>/dev/null)" \
1179 _HAS_COMPRESSION='no';
1184 ########################################################################
1191 ########################################################################
1192 # Definition of normal Functions
1193 ########################################################################
1194 landmark "3: functions";
1196 ########################################################################
1199 # Unconditionally terminate the program with error code;
1200 # useful for debugging.
1205 ########################################################################
1206 # base_name (<path>)
1208 # Get the file name part of <path>, i.e. delete everything up to last
1209 # `/' from the beginning of <path>.
1212 # Output : the file name part (without slashes)
1216 func_check base_name = 1 "$@";
1222 # delete everything up to last slash `/'.
1223 echo -n "$1" | sed -e '\|^.*/*\([^/]*\)$|s||\1|';
1229 eval "${return_ok}";
1233 ########################################################################
1236 # Decompress if possible or just print <file> to standard output.
1238 # gzip, bzip2, and .Z decompression is supported.
1240 # Arguments: 1, a file name.
1241 # Output: the content of <file>, possibly decompressed.
1243 if test "${_HAS_COMPRESSION}" = 'yes'; then
1246 func_check catz = 1 "$@";
1249 error 'catz(): empty file name';
1252 error 'catz(): for standard input use save_stdin()';
1255 if is_yes "${_HAS_BZIP}"; then
1256 if bzip2 -t "$1" 2>/dev/null; then
1257 bzip2 -c -d "$1" 2>/dev/null;
1258 eval "${return_ok}";
1261 gzip -c -d -f "$1" 2>/dev/null;
1262 eval "${return_ok}";
1267 func_check catz = 1 "$@";
1269 eval "${return_ok}";
1274 ########################################################################
1277 # Do the final cleaning up before exiting; used by the trap calls.
1282 ########################################################################
1283 # clean_up_secondary ()
1285 # Do the second but final cleaning up.
1290 ########################################################################
1293 # Print marked message to standard error; useful for debugging.
1298 ########################################################################
1299 landmark '4: dirname()*';
1300 ########################################################################
1302 #######################################################################
1303 # dirname_append (<dir> <name>)
1305 # Append `name' to `dir' with clean handling of `/'.
1308 # Output : the generated new directory name <dir>/<name>
1312 func_check dirname_append = 2 "$@";
1314 if is_empty "$1"; then
1315 error "dir_append(): first argument is empty.";
1317 if is_empty "$2"; then
1320 dirname_chop "$1"/"$2";
1322 eval "${return_ok}";
1326 ########################################################################
1327 # dirname_chop (<name>)
1329 # Remove unnecessary slashes from directory name.
1331 # Argument: 1, a directory name.
1332 # Output: path without double, or trailing slashes.
1336 func_check dirname_chop = 1 "$@";
1340 # replace all multiple slashes by a single slash `/'.
1341 _res="$(echo -n "$1" | sed -e '\|///*|s||/|g')";
1344 # remove trailing slash '/';
1345 echo -n "${_res}" | sed -e '\|/$|s|||';
1347 *) echo -n "${_res}"; ;;
1349 eval "${return_ok}";
1353 ########################################################################
1354 # do_filearg (<filearg>)
1356 # Append the file, man-page, or standard input corresponding to the
1357 # argument to the temporary file. If this is compressed in the gzip
1358 # or Z format it is decompressed. A title element is generated.
1361 # - name of an existing files.
1362 # - `-' to represent standard input (several times allowed).
1363 # - `man:name.(section)' the man-page for `name' in `section'.
1364 # - `man:name.section' the man-page for `name' in `section'.
1365 # - `man:name' the man-page for `name' in the lowest `section'.
1366 # - `name.section' the man-page for `name' in `section'.
1367 # - `name' the man-page for `name' in the lowest `section'.
1369 # $_TMP_STDIN, $_MAN_ENABLE, $_MAN_IS_SETUP, $_OPT_MAN
1372 # Return : $_GOOD if found, ${_BAD} otherwise.
1376 func_check do_filearg = 1 "$@";
1380 # store sequence into positional parameters
1381 case "${_filespec}" in
1383 eval "${return_good}";
1387 eval "${return_good}";
1389 */*) # with directory part; so no man search
1393 if is_yes "${_MAN_ENABLE}"; then
1394 if is_yes "${_MAN_FORCE}"; then
1395 set -- 'Manpage' 'File';
1397 set -- 'File' 'Manpage';
1407 if test -f "${_filespec}"; then
1408 if test -r "${_filespec}"; then
1409 register_file "${_filespec}";
1410 eval "${return_good}";
1412 echo2 "could not read \`${_filespec}'";
1413 eval "${return_bad}";
1419 Manpage) # parse filespec as man page
1420 if is_not_yes "${_MAN_IS_SETUP}"; then
1423 if man_do_filespec "${_filespec}"; then
1424 eval "${return_good}";
1431 eval "${return_bad}";
1435 ########################################################################
1446 ########################################################################
1449 # Print to standard error with final line break.
1454 ########################################################################
1457 # Print to standard error without final line break.
1462 ########################################################################
1465 # Print error message and exit with error code.
1470 ########################################################################
1471 # func_check (<func_name> <rel_op> <nr_args> "$@")
1473 # Check number of arguments and register to _FUNC_STACK.
1476 # <func_name>: name of the calling function.
1477 # <rel_op>: a relational operator: = != < > <= >=
1478 # <nr_args>: number of arguments to be checked against <operator>
1479 # "$@": the arguments of the calling function.
1483 #########################################################################
1486 # Delete the top element from the function call stack.
1491 ########################################################################
1492 # func_push (<element>)
1494 # Store another element to function call stack.
1499 ########################################################################
1500 # func_stack_dump ()
1502 # Print the content of the stack.
1507 ########################################################################
1508 # get_first_essential (<arg>*)
1510 # Retrieve first non-empty argument.
1512 # Return : `1' if all arguments are empty, `0' if found.
1513 # Output : the retrieved non-empty argument.
1515 get_first_essential()
1517 func_check get_first_essential '>=' 0 "$@";
1519 if test "$#" -eq 0; then
1520 eval "${return_ok}";
1523 if is_not_empty "$i"; then
1525 eval "${return_ok}";
1528 eval "${return_bad}";
1532 ########################################################################
1533 landmark '5: is_*()';
1534 ########################################################################
1536 ########################################################################
1539 # Test whether `name' is a directory.
1542 # Return : `0' if arg1 is a directory, `1' otherwise.
1546 func_check is_dir = 1 "$@";
1547 if is_not_empty "$1" && test -d "$1" && test -r "$1"; then
1548 eval "${return_yes}";
1550 eval "${return_no}";
1552 eval "${return_ok}";
1556 ########################################################################
1557 # is_empty (<string>)
1559 # Test whether `string' is empty.
1562 # Return : `0' if arg1 is empty or does not exist, `1' otherwise.
1566 func_check is_empty = 1 "$@";
1567 if test -z "$1"; then
1568 eval "${return_yes}";
1570 eval "${return_no}";
1572 eval "${return_ok}";
1576 ########################################################################
1577 # is_equal (<string1> <string2>)
1579 # Test whether `string1' is equal to <string2>.
1582 # Return : `0' both arguments are equal strings, `1' otherwise.
1586 func_check is_equal = 2 "$@";
1587 if test "$1" = "$2"; then
1588 eval "${return_yes}";
1590 eval "${return_no}";
1592 eval "${return_ok}";
1596 ########################################################################
1599 # Test whether `name' is a readable file.
1602 # Return : `0' if arg1 is a readable file, `1' otherwise.
1606 func_check is_file = 1 "$@";
1607 if is_not_empty "$1" && test -f "$1" && test -r "$1"; then
1608 eval "${return_yes}";
1610 eval "${return_no}";
1612 eval "${return_ok}";
1616 ########################################################################
1617 # is_not_dir (<name>)
1619 # Test whether `name' is not a readable directory.
1622 # Return : `0' if arg1 is a directory, `1' otherwise.
1626 func_check is_not_dir = 1 "$@";
1627 if is_dir "$1"; then
1628 eval "${return_no}";
1630 eval "${return_yes}";
1632 eval "${return_ok}";
1636 ########################################################################
1637 # is_not_empty (<string>)
1639 # Test whether `string' is not empty.
1642 # Return : `0' if arg1 exists and is not empty, `1' otherwise.
1646 func_check is_not_empty = 1 "$@";
1647 if is_empty "$1"; then
1648 eval "${return_no}";
1650 eval "${return_yes}";
1652 eval "${return_ok}";
1656 ########################################################################
1657 # is_not_equal (<string1> <string2>)
1659 # Test whether `string1' and <string2> differ.
1665 func_check is_not_equal = 2 "$@";
1666 if is_equal "$1" "$2"; then
1667 eval "${return_no}";
1669 eval "${return_yes}";
1671 eval "${return_ok}";
1675 ########################################################################
1676 # is_not_file (<filename>)
1678 # Test whether `name' is a not readable file.
1680 # Arguments : >=1 (empty allowed), more args are ignored
1684 func_check is_not_file '>=' 1 "$@";
1685 if is_file "$1"; then
1686 eval "${return_no}";
1688 eval "${return_yes}";
1690 eval "${return_ok}";
1694 ########################################################################
1695 # is_not_prog (<name>)
1697 # Verify that arg is a not program in $PATH.
1699 # Arguments : >=1 (empty allowed)
1700 # more args are ignored, this allows to specify progs with arguments
1704 func_check is_not_prog '>=' 1 "$@";
1705 if where "$1" >/dev/null; then
1706 eval "${return_no}";
1708 eval "${return_yes}";
1710 eval "${return_ok}";
1714 ########################################################################
1715 # is_not_yes (<string>)
1717 # Test whether `string' is not "yes".
1723 func_check is_not_yes = 1 "$@";
1724 if test "$1" = 'yes'; then
1725 eval "${return_no}";
1727 eval "${return_yes}";
1729 eval "${return_ok}";
1733 ########################################################################
1736 # Determine whether arg is a program in $PATH
1738 # Arguments : >=1 (empty allowed)
1739 # more args are ignored, this allows to specify progs with arguments
1743 func_check is_prog '>=' 1 "$@";
1744 if where "$1" >/dev/null; then
1745 eval "${return_yes}";
1747 eval "${return_no}";
1749 eval "${return_ok}";
1753 ########################################################################
1756 # Test whether `string' has value "yes".
1759 # Return : `0' if arg1 is `yes', `1' otherwise.
1763 func_check is_yes = 1 "$@";
1764 if test "$1" = 'yes'; then
1765 eval "${return_yes}";
1767 eval "${return_no}";
1769 eval "${return_ok}";
1773 ########################################################################
1776 # Print debugging information on standard error if $_DEBUG_LM is `yes'.
1778 # Globals: $_DEBUG_LM
1780 # Defined in section `Debugging functions'.
1783 ########################################################################
1786 # Clean exit without an error.
1795 ########################################################################
1796 landmark '6: list_*()';
1797 ########################################################################
1799 ########################################################################
1800 # list_append (<list> <element>...)
1803 # <list>: a space-separated list of single-quoted elements.
1804 # <element>: some sequence of characters.
1806 # if <list> is empty: "'<element>' '...'"
1807 # otherwise: "<list> '<element>' ..."
1811 func_check list_append '>=' 2 "$@";
1819 # escape each single quote by replacing each "'" (squote)
1820 # by "'\''" (squote bslash squote squote);
1821 # note that the backslash must be doubled for `sed'.
1822 _element="$(echo -n "$s" | sed -e 's/'"${_SQUOTE}"'/&\\&&/g')";
1828 _res="${_res} '${_element}'";
1831 eval "${return_ok}";
1835 ########################################################################
1836 # list_check (<list>)
1838 # Check whether <list> is a space-separated list of '-quoted elements.
1840 # If the test fails an error is raised.
1841 # If the test succeeds the argument is echoed.
1844 # A list has the form "'first' 'second' '...' 'last'".
1845 # So it has a leading and a final quote and the elements are separated
1846 # by "' '" constructs. If these are all removed there should not be
1847 # any single-quotes left. Watch out for escaped single quotes; they
1848 # have the form '\'' (sq bs sq sq).
1851 # Output: the argument <list> unchanged, it the check succeeded.
1855 func_check list_check = 1 "$@";
1857 if is_empty "$1"; then
1858 eval "${return_ok}";
1861 \'*\') _list="$1"; ;;
1863 error "list_check() bad list: $1"
1866 # Remove leading single quote,
1867 # remove final single quote,
1868 # remove escaped single quotes (squote bslash squote squote)
1869 # [note that `sed' doubles the backslash (bslash bslash)],
1870 # remove field separators (squote space squote).
1871 _list="$(echo -n "${_list}" \
1872 | sed -e 's/^'"${_SQUOTE}"'//' \
1873 | sed -e 's/'"${_SQUOTE}"'$//' \
1875 's/'"${_SQUOTE}${_BSLASH}${_BSLASH}${_SQUOTE}${_SQUOTE}"'//g' \
1876 | sed -e 's/'"${_SQUOTE}${_SPACE}${_SPACE}"'*'"${_SQUOTE}"'//g')";
1878 *\'*) # criterium fails if squote is left
1879 error 'list_check() bad list: '"${_list}";
1883 eval "${return_ok}";
1887 ########################################################################
1888 # list_element_from_arg (<arg>)
1891 # <arg>: some sequence of characters (also single quotes allowed).
1892 # Output: the list element generated from <arg>.
1894 list_element_from_arg()
1896 func_check list_element_from_arg = 1 "$@";
1899 # replace each single quote "'" by "'\''".
1900 echo -n "$1" | sed -e 's/'\''/&\\&&/g'; # ' for emacs
1902 eval "${return_ok}";
1906 ########################################################################
1907 # list_from_args (<arg>...)
1909 # Generate a space-separated list of single-quoted elements from args.
1912 # <arg>: some sequence of characters.
1913 # Output: "'<arg>' '...'"
1917 func_check list_from_args '>=' 1 "$@";
1921 _list="$(list_append "${_list}" "$s")";
1924 eval "${return_ok}";
1928 ########################################################################
1929 # list_from_cmdline (<s_n> <s_a> <l_n> <l_n> [<cmdline_arg>...])
1931 # Transform command line arguments into a normalized form.
1933 # Options, option arguments, and file parameters are identified and
1934 # output each as a single-quoted argument of its own. Options and
1935 # file parameters are separated by a '--' argument.
1938 # <s_n>: space-separated list of short options without an arg.
1939 # <s_a>: space-separated list of short options that have an arg.
1940 # <l_n>: space-separated list of long options without an arg.
1941 # <l_a>: space-separated list of long options that have an arg.
1942 # <cmdline_arg>...: the arguments from the command line (by "$@").
1944 # Globals: $POSIXLY_CORRECT (only kept for compatibility).
1946 # Output: ['-[-]opt' ['optarg']]... '--' ['filename']...
1949 # list_normalize 'a b' 'c' '' 'long' -a f1 -bcarg --long=larg f2
1950 # will result in printing:
1951 # '-a' '-b' '-c' 'arg' '--long' 'larg' '--' 'f1' 'f2'
1952 # If $POSIXLY_CORRECT is not empty, the result will be:
1953 # '-a' '--' 'f1' '-bcarg' '--long=larg' 'f2'
1956 # In POSIX, the first non-option ends the option processing.
1957 # In GNU mode (default), non-options are sorted behind the options.
1959 # Use this function only in the following way:
1960 # eval set -- "$(args_norm '...' '...' '...' '...' "$@")";
1961 # while test "$1" != '--'; do
1968 # # all positional parameters ("$@") left are file name parameters.
1972 func_check list_from_cmdline '>=' 4 "$@";
1980 _short_n="$(list_check "$1")"; # short options, no argument
1981 _short_a="$(list_check "$2")"; # short options with argument
1982 _long_n="$(list_check "$3")"; # long options, no argument
1983 _long_a="$(list_check "$4")"; # long options with argument
1985 _fn='list_from_cmdline():'; # for error messages
1986 if test "$#" -eq 0; then
1988 eval "${return_ok}";
1992 while test "$#" -ge 1; do
1998 # delete leading '--';
1999 _opt="$(echo -n "${_arg}" | sed -e 's/^..//')";
2000 if list_has "${_long_n}" "${_opt}"; then
2001 # long option, no argument
2002 _result="$(list_append "${_result}" "--${_opt}")";
2005 if list_has "${_long_a}" "${_opt}"; then
2006 # long option with argument
2007 _result="$(list_append "${_result}" "--${_opt}")";
2008 if test "$#" -le 0; then
2009 error "${_fn} no argument for option --${_opt}."
2011 _result="$(list_append "${_result}" "$1")";
2015 # test on `--opt=arg'
2016 if string_contains "${_opt}" '='; then
2017 # extract option by deleting from the first '=' to the end
2018 _lopt="$(echo -n "${_opt}" | sed -e 's/=.*$//')";
2019 if list_has "${_long_a}" "${_lopt}"; then
2020 # get the option argument by deleting up to first `='
2021 _optarg="$(echo -n "${_opt}" | sed -e 's/^[^=]*=//')";
2022 _result="$(list_append "${_result}" \
2023 "--${_lopt}" "${_optarg}")";
2027 error "${_fn} --${_opt} is not an option."
2029 -?*) # short option (cluster)
2030 # delete leading `-';
2031 _rest="$(echo -n "${_arg}" | sed -e 's/^.//')";
2032 while is_not_empty "${_rest}"; do
2033 # get next short option from cluster (first char of $_rest)
2034 _optchar="$(echo -n "${_rest}" | sed -e 's/^\(.\).*$/\1/')";
2035 # remove first character from ${_rest};
2036 _rest="$(echo -n "${_rest}" | 's/^.//')";
2037 if list_has "${_short_n}" "${_optchar}"; then
2038 _result="$(list_append "${_result}" "-${_optchar}")";
2040 elif list_has "${_short_a}" "${_optchar}"; then
2041 # remove leading character
2042 case "${_optchar}" in
2043 /) # cannot use normal `sed' separator
2044 _rest="$(echo -n "${_rest}" | sed -e '\|^.|s|||')";
2047 _rest="$(echo -n "${_rest}" | sed -e 's/^.//')";
2050 error "${_fn} several chars parsed for short option."
2053 if is_empty "${_rest}"; then
2054 if test "$#" -ge 1; then
2055 _result="$(list_append "${_result}" \
2056 "-${_optchar}" "$1")";
2061 "${_fn}"' no argument for option -'"${_optchar}."
2063 else # rest is the argument
2064 _result="$(list_append "${_result}" \
2065 "-${_optchar}" "${_rest}")";
2070 error "${_fn} unknown option -${_optchar}."
2075 # Here, $_arg is not an option, so a file parameter.
2076 # When $POSIXLY_CORRECT is set this ends option parsing;
2077 # otherwise, the argument is stored as a file parameter and
2078 # option processing is continued.
2079 _fparams="$(list_append "${_fparams}" "${_arg}")";
2080 if is_not_empty "$POSIXLY_CORRECT"; then
2086 _result="$(list_append "${_result}" '--')";
2087 if is_not_empty "${_fparams}"; then
2088 _result="${_result} ${_fparams}";
2090 if test "$#" -gt 0; then
2091 _result="$(list_append "${_result}" "$@")";
2094 eval "${return_ok}";
2095 } # list_from_cmdline()
2098 ########################################################################
2099 # list_from_lists (<list1> <list2>...)
2101 # Generate a list from the concatenation of the lists in the arguments.
2104 # <list*>: string of space-separated single-quoted elements.
2105 # Output: "'<element1_of_list1>' ..."
2109 func_check list_from_lists '>=' 2 "$@";
2112 eval "${return_ok}";
2115 ########################################################################
2116 # list_from_split (<string> <separator>)
2118 # In <string> escape white space and replace each <separator> by space.
2120 # Arguments: 2: a <string> that is to be split into parts divided by
2122 # Output: the resulting string
2126 func_check list_from_split = 2 "$@";
2129 # precede each space or tab by a backslash `\' (doubled for `sed')
2130 _s="$(echo -n "$1" | sed -e 's/\(['"${_SPACE}${_TAB}"']\)/\\\1/g')";
2132 # replace split character of string by the list separator ` ' (space).
2134 /) # cannot use normal `sed' separator
2135 echo -n "${_s}" | sed -e '\|'"$2"'|s|| |g';
2137 ?) # use normal `sed' separator
2138 echo -n "${_s}" | sed -e 's/'"$2"'/ /g';
2141 error 'list_from_split(): separator must be a single character.';
2144 eval "${return_ok}";
2148 ########################################################################
2149 # list_has (<list> <element>)
2152 # <list>: a space-separated list of single-quoted elements.
2153 # <element>: some sequence of characters.
2155 # if <list> is empty: "'<element>' '...'"
2156 # otherwise: "<list> '<element>' ..."
2160 func_check list_has = 2 "$@";
2161 if is_empty "$1"; then
2162 eval "${return_no}";
2167 \'*\') _element="$2"; ;;
2168 *) _element="'$2'"; ;;
2170 if string_contains "${_list}" "${_element}"; then
2171 eval "${return_yes}";
2173 eval "${return_no}";
2175 eval "${return_ok}";
2179 ########################################################################
2180 # list_has_not (<list> <element>)
2183 # <list>: a space-separated list of single-quoted elements.
2184 # <element>: some sequence of characters.
2186 # if <list> is empty: "'<element>' '...'"
2187 # otherwise: "<list> '<element>' ..."
2191 func_check list_has_not = 2 "$@";
2192 if is_empty "$1"; then
2193 eval "${return_yes}";
2198 \'*\') _element="$2"; ;;
2199 *) _element="'$2'"; ;;
2201 if string_contains "${_list}" "${_element}"; then
2202 eval "${return_no}";
2204 eval "${return_yes}";
2206 eval "${return_ok}";
2210 ########################################################################
2211 # list_length (<list>)
2214 # <list>: a space-separated list of single-quoted elements.
2215 # Output: the number of elements in <list>
2219 func_check list_length = 1 "$@";
2222 eval "${return_ok}";
2226 ########################################################################
2227 # list_prepend (<list> <element>...)
2229 # Insert new <element> at the beginning of <list>
2232 # <list>: a space-separated list of single-quoted elements.
2233 # <element>: some sequence of characters.
2235 # if <list> is empty: "'<element>' ..."
2236 # otherwise: "'<element>' ... <list>"
2240 func_check list_prepend '>=' 2 "$@";
2245 # escape single quotes in list style (squote bslash squote squote).
2246 _element="$(echo -n "$s" | sed -e 's/'\''/&\\&&/g')";
2247 _res="'${_element}' ${_res}";
2250 eval "${return_ok}";
2254 ########################################################################
2255 landmark '7: man_*()';
2256 ########################################################################
2258 ########################################################################
2259 # man_do_filespec (<filespec>)
2261 # Print suitable man page(s) for filespec to $_TMP_CAT.
2264 # <filespec>: argument of the form `man:name.section', `man:name',
2265 # `man:name(section)', `name.section', `name'.
2267 # Globals : $_OPT_ALL
2270 # Return : `0' if man page was found, `1' else.
2272 # Only called from do_fileargs(), checks on $MANPATH and
2273 # $_MAN_ENABLE are assumed.
2277 func_check man_do_filespec = 1 "$@";
2286 if is_empty "${MANPATH}"; then
2287 eval "${return_bad}";
2289 if is_empty "$1"; then
2290 eval "${return_bad}";
2296 */*) # not a man spec when it contains '/'
2297 eval "${return_bad}";
2299 man:?*\(?*\)) # man:name(section)
2300 _name="$(echo -n "${_spec}" \
2301 | sed -e 's/^man:\(..*\)(\(..*\))$/\1/')";
2302 _section="$(echo -n "${_spec}" \
2303 | sed -e 's/^man:\(..*\)(\(..*\))$/\2/')";
2305 man:?*.?*) # man:name.section
2306 _name="$(echo -n "${_spec}" \
2307 | sed -e 's/^man:\(..*\)\.\(..*\)$/\1/')";
2308 _section="$(echo -n "${_spec}" \
2309 | sed -e 's/^man:\(..*\)\.\(..*\)$/\2/')";
2312 _name="$(echo -n "${_spec}" | sed -e 's/^man://')";
2314 ?*\(?*\)) # name(section)
2315 _name="$(echo -n "${_spec}" \
2316 | sed -e 's/^\(..*\)(\(..*\))$/\1/')";
2317 _section="$(echo -n "${_spec}" \
2318 | sed -e 's/^\(..*\)(\(..*\))$/\2/')";
2320 ?*.?*) # name.section
2321 _name="$(echo -n "${_spec}" \
2322 | sed -e 's/^\(..*\)\.\(..*\)$/\1/')";
2323 _section="$(echo -n "${_spec}" \
2324 | sed -e 's/^\(..*\)\.\(..*\)$/\2/')";
2327 _name="${_filespec}";
2330 if is_empty "${_name}"; then
2331 eval "${return_bad}";
2334 if is_empty "${_section}"; then
2335 eval set -- "${_MAN_AUTO_SEC}";
2337 if man_search_section "${_name}" "$s"; then # found
2338 if is_yes "${_MAN_ALL}"; then
2341 eval "${return_good}";
2346 if man_search_section "${_name}" "${_section}"; then
2347 eval "${return_good}";
2349 eval "${return_bad}";
2352 if is_yes "${_MAN_ALL}" && is_yes "${_got_one}"; then
2353 eval "${return_good}";
2355 eval "${return_bad}";
2356 } # man_do_filespec()
2359 ########################################################################
2360 # man_register_file (<file> <name> [<section>])
2362 # Write a found man page file and register the title element.
2364 # Arguments: 1, 2, or 3; maybe empty
2369 func_check man_register_file '>=' 2 "$@";
2373 error "man_register_file() expects 2 or 3 arguments.";
2376 if is_empty "$1"; then
2377 error 'man_register_file(): file name is empty';
2382 register_title "man:$2";
2383 eval "${return_ok}";
2386 register_title "$2($3)";
2387 eval "${return_ok}";
2390 eval "${return_ok}";
2394 ########################################################################
2395 # man_search_section (<name> <section>)
2397 # Retrieve man pages.
2400 # Globals : $_MAN_PATH, $_MAN_EXT
2401 # Return : 0 if found, 1 otherwise
2403 man_search_section()
2405 func_check man_search_section = 2 "$@";
2414 if is_empty "${_MAN_PATH}"; then
2415 eval "${return_bad}";
2417 if is_empty "$1"; then
2418 eval "${return_bad}";
2420 if is_empty "$2"; then
2421 eval "${return_bad}";
2425 eval set -- "$(path_split "${_MAN_PATH}")";
2427 if is_empty "${_MAN_EXT}"; then
2429 _dir="$(dirname_append "$d" "man${_section}")";
2430 if is_dir "${_dir}"; then
2431 _prefix="$(dirname_append "${_dir}" "${_name}.${_section}")";
2432 for f in $(echo -n ${_prefix}*); do
2433 if is_file "$f"; then
2434 if is_yes "${_got_one}"; then
2436 elif is_yes "${_MAN_ALL}"; then
2437 man_register_file "$f" "${_name}";
2439 man_register_file "$f" "${_name}" "${_section}";
2440 eval "${return_good}";
2449 # check for directory name having trailing extension
2451 _dir="$(dirname_append $d man${_section}${_ext})";
2452 if is_dir "${_dir}"; then
2453 _prefix="$(dirname_append "${_dir}" "${_name}.${_section}")";
2454 for f in ${_prefix}*; do
2455 if is_file "$f"; then
2456 if is_yes "${_got_one}"; then
2458 elif is_yes "${_MAN_ALL}"; then
2459 man_register_file "$f" "${_name}";
2461 man_register_file "$f" "${_name}" "${_section}";
2462 eval "${return_good}";
2469 # check for files with extension in directories without extension
2471 _dir="$(dirname_append "$d" "man${_section}")";
2472 if is_dir "${_dir}"; then
2473 _prefix="$(dirname_append "${_dir}" \
2474 "${_name}.${_section}${_ext}")";
2475 for f in ${_prefix}*; do
2476 if is_file "$f"; then
2477 if is_yes "${_got_one}"; then
2479 elif is_yes "${_MAN_ALL}"; then
2480 man_register_file "$f" "${_name}";
2482 man_register_file "$f" "${_name}" "${_section}";
2483 eval "${return_good}";
2491 if is_yes "${_MAN_ALL}" && is_yes "${_got_one}"; then
2492 eval "${return_good}";
2494 eval "${return_bad}";
2495 } # man_search_section()
2498 ########################################################################
2501 # Setup the variables $_MAN_* needed for man page searching.
2504 # in: $_OPT_*, $_MANOPT_*, $LANG, $LC_MESSAGES, $LC_ALL,
2505 # $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM, $MANOPT.
2506 # out: $_MAN_PATH, $_MAN_LANG, $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2,
2507 # $_MAN_SEC, $_MAN_ALL
2508 # in/out: $_MAN_ENABLE
2510 # The precedence for the variables related to `man' is that of GNU
2513 # $LANG; overridden by
2514 # $LC_MESSAGES; overridden by
2515 # $LC_ALL; this has the same precedence as
2516 # $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM; overridden by
2517 # $MANOPT; overridden by
2518 # the groffer command line options.
2522 func_check main_man_setup = 0 "$@";
2525 if is_yes "${_MAN_IS_SETUP}"; then
2526 eval "${return_ok}";
2528 _MAN_IS_SETUP='yes';
2530 if is_not_yes "${_MAN_ENABLE}"; then
2531 eval "${return_ok}";
2534 # determine basic path for man pages
2535 _MAN_PATH="$(get_first_essential \
2536 "${_OPT_MANPATH}" "${_MANOPT_PATH}" "${MANPATH}")";
2537 if is_empty "${_MAN_PATH}"; then
2538 if is_prog 'manpath'; then
2539 _MAN_PATH="$(manpath 2>/dev/null)"; # not always available
2542 if is_empty "${_MAN_PATH}"; then
2543 manpath_set_from_path;
2545 _MAN_PATH="$(path_clean "${_MAN_PATH}")";
2547 if is_empty "${_MAN_PATH}"; then
2549 eval "${return_ok}";
2552 _MAN_ALL="$(get_first_essential "${_OPT_ALL}" "${_MANOPT_ALL}")";
2553 if is_empty "${_MAN_ALL}"; then
2557 _MAN_SYS="$(get_first_essential \
2558 "${_OPT_SYSTEMS}" "${_MANOPT_SYS}" "${SYSTEM}")";
2559 _lang="$(get_first_essential \
2560 "${_OPT_LANG}" "${LC_ALL}" "${LC_MESSAGES}" "${LANG}")";
2567 _MAN_LANG="${_lang}";
2571 _MAN_LANG="${_lang}";
2572 # get first two characters of $_lang
2573 _MAN_LANG2="$(echo -n "${_lang}" | sed -e 's/^\(..\).*$/\1/')";
2576 # from now on, use only $_LANG, forget about $_OPT_LANG, $LC_*.
2578 manpath_add_lang_sys; # this is very slow
2580 _MAN_SEC="$(get_first_essential \
2581 "${_OPT_SECT}" "${_MANOPT_SEC}" "${MANSEC}")";
2582 if is_empty "${_MAN_PATH}"; then
2584 eval "${return_ok}";
2587 _MAN_EXT="$(get_first_essential \
2588 "${_OPT_EXTENSION}" "${_MANOPT_EXTENSION}")";
2589 eval "${return_ok}";
2593 ########################################################################
2594 landmark '8: manpath_*()';
2595 ########################################################################
2597 ########################################################################
2598 # manpath_add_lang_sys ()
2600 # Add language and operating system specific directories to man path.
2605 # in: $_MAN_SYS: has the form `os1,os2,...', a comma separated
2606 # list of names of operating systems.
2607 # $_MAN_LANG and $_MAN_LANG2: each a single name
2608 # in/out: $_MAN_PATH: has the form `dir1:dir2:...', a colon
2609 # separated list of directories.
2611 manpath_add_lang_sys()
2613 func_check manpath_add_lang_sys = 0 "$@";
2616 if is_empty "${_MAN_PATH}"; then
2617 eval "${return_ok}";
2619 # twice test both sys and lang
2620 eval set -- "$(path_split "${_MAN_PATH}")";
2622 for p in "$@"; do # loop on man path directories
2623 _mp="$(_manpath_add_lang_sys_single "${_mp}" "$p")";
2625 eval set -- "$(path_split "${_mp}")";
2626 for p in "$@"; do # loop on man path directories
2627 _mp="$(_manpath_add_lang_sys_single "${_mp}" "$p")";
2629 _MAN_PATH="$(path_chop "${_mp}")";
2630 eval "${return_ok}";
2634 _manpath_add_lang_sys_single()
2636 # To the directory in $1 append existing sys/lang subdirectories
2637 # Function is necessary to split the OS list.
2639 # globals: in: $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2
2640 # argument: 2: `man_path' and `dir'
2641 # output: colon-separated path of the retrieved subdirectories
2644 # if test "$#" -ne 2; then
2645 # error "manpath_add_system_single() needs 2 arguments.";
2649 eval set -- "$(list_from_split "${_MAN_SYS}" ',')";
2650 for d in "$@" "${_MAN_LANG}" "${_MAN_LANG2}"; do
2651 _dir="$(dirname_append "${_parent}" "$d")";
2652 if path_not_contains "${_res}" "${_dir}" && is_dir "${_dir}"; then
2653 _res="${_res}:${_dir}";
2656 if path_not_contains "${_res}" "${_parent}"; then
2657 _res="${_res}:${_parent}";
2659 path_chop "${_res}";
2662 # end manpath_add_lang_sys ()
2665 ########################################################################
2666 # manpath_set_from_path ()
2668 # Determine basic search path for man pages from $PATH.
2670 # Return: `0' if a valid man path was retrieved.
2676 manpath_set_from_path()
2678 func_check manpath_set_from_path = 0 "$@";
2686 # get a basic man path from $PATH
2687 if is_not_empty "${PATH}"; then
2688 eval set -- "$(path_split "${PATH}")";
2690 # delete the final `/bin' part
2691 _base="$(echo -n "$d" | sed -e '\|//*bin/*$|s|||')";
2692 for e in /share/man /man; do
2693 _mandir="${_base}$e";
2694 if test -d "${_mandir}" && test -r "${_mandir}"; then
2695 _manpath="${_manpath}:${_mandir}";
2701 # append some default directories
2702 for d in /usr/local/share/man /usr/local/man \
2703 /usr/share/man /usr/man \
2704 /usr/X11R6/man /usr/openwin/man \
2705 /opt/share/man /opt/man \
2706 /opt/gnome/man /opt/kde/man; do
2707 if path_not_contains "${_manpath}" "$d" && is_dir "$d"; then
2708 _manpath="${_manpath}:$d";
2712 _MAN_PATH="${_manpath}";
2713 eval "${return_ok}";
2714 } # manpath_set_from_path()
2717 ########################################################################
2718 landmark '9: path_*()';
2719 ########################################################################
2721 ########################################################################
2722 # path_chop (<path>)
2724 # Remove unnecessary colons from path.
2726 # Argument: 1, a colon separated path.
2727 # Output: path without leading, double, or trailing colons.
2731 func_check path_chop = 1 "$@";
2734 # replace multiple colons by a single colon `:'
2735 # remove leading and trailing colons
2736 echo -n "$1" | sed -e 's/:::*/:/g' |
2739 eval "${return_ok}";
2743 ########################################################################
2744 # path_clean (<path>)
2746 # Remove non-existing directories from a colon-separated list.
2748 # Argument: 1, a colon separated path.
2749 # Output: colon-separated list of existing directories.
2753 func_check path_clean = 1 "$@";
2758 if test "$#" -ne 1; then
2759 error 'path_clean() needs 1 argument.';
2762 eval set -- "$(path_split "${_arg}")";
2765 if is_not_empty "$i" \
2766 && path_not_contains "${_res}" "$i" \
2770 ?*/) _res="${_res}$(dirname_chop "$i")"; ;;
2771 *) _res="${_res}:$i";
2775 if path_chop "${_res}"; then
2776 eval "${return_ok}";
2778 eval "${return_badk}";
2783 ########################################################################
2784 # path_contains (<path> <dir>)
2786 # Test whether `dir' is contained in `path', a list separated by `:'.
2788 # Arguments : 2 arguments.
2789 # Return : `0' if arg2 is substring of arg1, `1' otherwise.
2793 func_check path_contains = 2 "$@";
2796 eval "${return_yes}";
2799 eval "${return_no}";
2802 eval "${return_ok}";
2806 ########################################################################
2807 # path_not_contains (<path> <dir>)
2809 # Test whether `dir' is not contained in colon separated `path'.
2811 # Arguments : 2 arguments.
2815 func_check path_not_contains = 2 "$@";
2816 if path_contains "$1" "$2"; then
2817 eval "${return_no}";
2819 eval "${return_yes}";
2821 eval "${return_ok}";
2825 ########################################################################
2826 # path_split (<path>)
2828 # In `path' escape white space and replace each colon by a space.
2830 # Arguments: 1: a colon-separated path
2831 # Output: the resulting list, process with `eval set --'
2835 func_check path_split = 1 "$@";
2836 list_from_split "$1" ':';
2837 eval "${return_ok}";
2841 ########################################################################
2844 # Reset the variables that can be affected by options to their default.
2847 # Defined in section `Preset' after the rudimentary shell tests.
2850 ########################################################################
2851 landmark '10: register_*()';
2852 ########################################################################
2854 ########################################################################
2855 # register_file (<filename>)
2857 # Write a found file and register the title element.
2859 # Arguments: 1: a file name
2864 func_check register_file = 1 "$@";
2865 if is_empty "$1"; then
2866 error 'register_file(): file name is empty';
2868 if is_equal "$1" '-'; then
2869 to_tmp "${_TMP_STDIN}";
2873 register_title "$(base_name "$1")";
2875 eval "${return_ok}";
2879 ########################################################################
2880 # register_title (<filespec>)
2882 # Create title element from <filespec> and append to $_REGISTERED_TITLE
2884 # Globals: $_REGISTERED_TITLE (rw)
2888 func_check register_title = 1 "$@";
2890 if is_empty "$1"; then
2891 eval "${return_ok}";
2893 _title="$(base_name "$1")"; # remove directory part
2895 # remove extension `.gz'
2896 _title="$(echo -n "${_title}" | sed -e 's/\.gz$//')";
2897 # remove extension `.Z'
2898 _title="$(echo -n "${_title}" | sed -e 's/\.Z$//')";
2900 if is_empty "${_title}"; then
2901 eval "${return_ok}";
2903 _REGISTERED_TITLE="${_REGISTERED_TITLE} ${_title}";
2904 eval "${return_ok}";
2908 ########################################################################
2911 # Store standard input to temporary file (with decompression).
2913 if test "${_HAS_COMPRESSION}" = 'yes'; then
2917 func_check save_stdin = 0 "$@";
2920 catz "${_f}" >"${_TMP_STDIN}";
2922 eval "${return_ok}";
2927 func_check save_stdin = 0 "$@";
2928 cat >"${_TMP_STDIN}";
2929 eval "${return_ok}";
2934 ########################################################################
2935 landmark '11: stack_*()';
2936 ########################################################################
2938 ########################################################################
2939 # string_contains (<string> <part>)
2941 # Test whether `part' is contained in `string'.
2943 # Arguments : 2 text arguments.
2944 # Return : `0' if arg2 is substring of arg1, `1' otherwise.
2948 func_check string_contains = 2 "$@";
2951 eval "${return_yes}";
2954 eval "${return_no}";
2957 eval "${return_ok}";
2961 ########################################################################
2962 # string_not_contains (<string> <part>)
2964 # Test whether `part' is not substring of `string'.
2966 # Arguments : 2 text arguments.
2967 # Return : `0' if arg2 is substring of arg1, `1' otherwise.
2969 string_not_contains()
2971 func_check string_not_contains = 2 "$@";
2972 if string_contains "$1" "$2"; then
2973 eval "${return_no}";
2975 eval "${return_yes}";
2977 eval "${return_ok}";
2981 ########################################################################
2982 landmark '12: tmp_*()';
2983 ########################################################################
2985 ########################################################################
2988 # output the temporary cat file (the concatenation of all input)
2996 ########################################################################
2997 # tmp_create (<suffix>?)
2999 # create temporary file
3001 # It's safe to use the shell process ID together with a suffix to
3002 # have multiple temporary files.
3004 # Output : name of created file
3008 func_check tmp_create '<=' 1 "$@";
3010 _tmp="${_TMP_PREFIX}${_PROCESS_ID}$1";
3013 eval "${return_ok}";
3017 ########################################################################
3018 # to_tmp (<filename>)
3020 # print file (decompressed) to the temporary cat file
3024 func_check to_tmp = 1 "$@";
3025 if is_file "$1"; then
3026 if is_yes "${_OPT_LOCATION}"; then
3029 if is_yes "${_OPT_WHATIS}"; then
3030 what_is "$1" >>"${_TMP_CAT}";
3032 catz "$1" >>"${_TMP_CAT}";
3035 error "to_tmp(): could not read file \`$1'.";
3037 eval "${return_ok}";
3041 ########################################################################
3044 # print usage information to stderr
3048 func_check usage = 0 "$@";
3052 Copyright (C) 2001 Free Software Foundation, Inc.
3053 This is free software licensed under the GNU General Public License.
3057 echo2 "Usage: ${_PROGRAM_NAME} ${_header} [option]... [filespec]...";
3061 where "filespec" is one of
3062 "filename" name of a readablefile
3063 "-" for standard input
3064 "man:name.n" man page "name" in section "n"
3065 "man:name" man page "name" in first section found
3066 "name.n" man page "name" in section "n"
3067 "name" man page "name" in first section found
3068 and some more (see groff(1) for details).
3070 Display roff files, standard input, and/or Unix manual pages with
3071 in a X window viewer or in a text pager.
3072 "-" stands for including standard input.
3073 "manpage" is the name of a man page, "x" its section.
3074 All input is decompressed on-the-fly (by gzip).
3076 -h --help print this usage message.
3077 -Q --source output as roff source.
3078 -T --device=name pass to groff using output device "name".
3079 -v --version print version information.
3081 All other short options are interpreted as "groff" formatting
3082 parameters and are transferred unmodified. The following groff
3083 options imply groff mode (groffer viewing disabled):
3085 -X display with "gxditview" using groff -X.
3086 -V display the groff execution pipe instead of formatting.
3087 -Z --ditroff --intermediate-output
3088 generate groff intermediate output without
3089 post-processing and viewing like groff -Z.
3091 The most important long options are
3093 --auto-modes=mode1,mode2,...
3094 set sequence of automatically tried modes.
3095 --bg set background color (not for all modes).
3096 --default reset effects of option processing so far.
3097 --display set the X device when displaying in X.
3098 --dpi=res set resolution to "res" ("75" (default) or "100").
3099 --dvi display in a viewer for TeX device independent format.
3100 --dvi-viewer choose the viewer program for dvi mode.
3101 --extension=ext restrict man pages to section suffix.
3102 --fg set foreground color (not for all modes).
3103 --geometry=geom set the window size and position when displaying in X.
3104 --groff process like groff, disable viewing features.
3105 --local-file same as --no-man.
3106 --locale=lang preset the language for man pages.
3107 --location print file locations additionally to standard error.
3108 --man check file parameters first whether they are man pages.
3109 --mode=auto|dvi|groff|pdf|ps|source|tty|www|x
3110 choose display mode.
3111 --no-location disable former call to "--location".
3112 --no-man disable man-page facility.
3113 --pager=program preset the paging program for tty mode.
3114 --pdf display in a PDF viewer.
3115 --pdf-viewer choose the viewer program for pdf mode.
3116 --ps display in a Postscript viewer.
3117 --ps-viewer choose the viewer program for ps mode.
3118 --shell specify shell under which to run this program.
3119 --systems=os1,os2,...
3120 search man pages for different operating systems.
3121 --title='text' set the title of the viewer window (not in all modes.
3122 --tty force paging on text terminal even when in X.
3123 --www display in a web browser.
3124 --www-viewer choose the web browser for www mode.
3125 --x display in an X roff viewer.
3126 --x-viewer choose viewer program for x mode.
3127 --xrm='resource' set X resouce.
3130 eval "${return_ok}";
3134 ########################################################################
3137 # print version information to stderr
3141 echo2 "${_PROGRAM_NAME} ${_PROGRAM_VERSION} of ${_LAST_UPDATE}";
3142 # also display groff's version, but not the called subprograms
3143 groff -v 2>&1 | sed -e '/^ *$/q' | sed -e '1s/^/is part of /' >&2;
3147 ########################################################################
3148 # warning (<string>)
3150 # Print warning to stderr
3154 echo2 "warning: $*";
3158 ########################################################################
3159 # what_is (<filename>)
3161 # Interpret <filename> as a man page and display its `whatis'
3162 # information as a fragment written in the groff language.
3166 func_check what_is = 1 "$@";
3169 if is_not_file "$1"; then
3170 error "what_is(): argument is not a readable file."
3172 _dot='^\.['"${_SPACE}${_TAB}"']*';
3177 # grep the line containing `.TH' macro, if any
3178 _res="$(catz "$1" | sed -e '/'"${_dot}"'TH /p
3180 if is_not_empty "${_res}"; then # traditional man style
3181 # get the text between the first and the second `.SH' macro, by
3182 # - delete up to first .SH;
3183 # - of this, print everything up to next .SH, and delete the rest;
3184 # - of this, delete the final .SH line;
3185 catz "$1" | sed -e '1,/'"${_dot}"'SH/d' \
3186 | sed -e '1,/'"${_dot}"'SH/p
3188 | sed -e '/'"${_dot}"'SH/d';
3189 eval "${return_ok}";
3191 # grep the line containing `.Dd' macro, if any
3192 _res="$(catz "$1" | sed -e '/'"${_dot}"'Dd /p
3194 if is_not_empty "${_res}"; then # BSD doc style
3195 # get the text between the first and the second `.Nd' macro, by
3196 # - delete up to first .Nd;
3197 # - of this, print everything up to next .Nd, and delete the rest;
3198 # - of this, delete the final .Nd line;
3199 catz "$1" | sed -e '1,/'"${_dot}"'Nd/d' \
3200 | sed -e '1,/'"${_dot}"'Nd/p
3202 | sed -e '/'"${_dot}"'Nd/d';
3203 eval "${return_ok}";
3205 echo 'is not a man page.';
3206 eval "${return_bad}";
3210 ########################################################################
3213 # Output path of a program if in $PATH.
3215 # Arguments : >=1 (empty allowed)
3216 # more args are ignored, this allows to specify progs with arguments
3217 # Return : `0' if arg1 is a program in $PATH, `1' otherwise.
3221 func_check where '>=' 1 "$@";
3226 if is_empty "${_arg}"; then
3227 eval "${return_bad}";
3231 if test -f "${_arg}" && test -x "${_arg}"; then
3232 eval "${return_ok}";
3234 eval "${return_bad}";
3238 eval set -- "$(path_split "${PATH}")";
3241 */) _file=$p${_arg}; ;;
3242 *) _file=$p/${_arg}; ;;
3244 if test -f "${_file}" && test -x "${_file}"; then
3246 eval "${return_ok}";
3249 eval "${return_bad}";
3253 ########################################################################
3255 ########################################################################
3257 # The main area contains the following parts:
3258 # - main_init(): initialize temporary files and set exit trap
3260 # - main_parse_args(): argument parsing
3261 # - determine display mode
3262 # - process filespec arguments
3263 # - setup X resources
3264 # - do the displaying
3266 # These parts are implemented as functions, being defined below in the
3267 # sequence they are called in the main() function.
3270 #######################################################################
3273 # set exit trap and create temporary files
3275 # Globals: $_TMP_CAT, $_TMP_STDIN
3277 landmark '13: main_init()';
3280 func_check main_init = 0 "$@";
3281 # call clean_up() on any signal
3282 trap clean_up 2>/dev/null || true;
3284 for f in ${_CONFFILES}; do
3285 if is_file "$f"; then
3290 # determine temporary directory
3291 for d in "${GROFF_TMPDIR}" "${TMPDIR}" "${TMP}" "${TEMP}" \
3292 "${TEMPDIR}" "${HOME}"'/tmp' '/tmp' "${HOME}" '.';
3294 if test "$d" != ""; then
3295 if test -d "$d" && test -r "$d" && test -w "$d"; then
3302 if test "${_TMP_DIR}" = ""; then
3303 error "Couldn't find a directory for storing temorary files.";
3305 _TMP_PREFIX="${_TMP_DIR}/${_PROGRAM_NAME}";
3307 _TMP_CAT="$(tmp_create)";
3308 _TMP_STDIN="$(tmp_create i)";
3309 eval "${return_ok}";
3313 ########################################################################
3314 # main_parse_MANOPT ()
3316 # Parse $MANOPT; this clobbered by the command line.
3319 # in: $MANOPT, $_OPTS_MAN_*
3321 # in/out: $GROFFER_OPT
3323 landmark '14: main_parse_MANOPT()';
3326 func_check main_parse_MANOPT = 0 "$@";
3331 eval set -- "$(list_from_cmdline \
3332 "${_OPTS_MAN_SHORT_NA}" "${_OPTS_MAN_SHORT_ARG}" \
3333 "${_OPTS_MAN_LONG_NA}" "${_OPTS_MAN_LONG_ARG}" \
3335 until test "$#" -le 0 || is_equal "$1" '--'; do
3340 _list="$(list_append "${_list}" '--ascii')";
3343 _list="$(list_append "${_list}" '--all')";
3350 _list="$(list_append "${_list}" '--debug')";
3353 # undo all man options so far
3357 _list="$(list_append "${_list}" '--extension')";
3361 _list="$(list_append "${_list}" '--whatis')";
3369 _list="$(list_append "${_list}" '--apropos')";
3373 _list="$(list_append "${_list}" '--local-file')";
3376 _list="$(list_append "${_list}" '--locale' "$1")";
3380 _list="$(list_append "${_list}" '--systems' "$1")";
3384 _list="$(list_append "${_list}" '--manpath' "$1")";
3392 _list="$(list_append "${_list}" '--pager' "$1")";
3400 _list="$(list_append "${_list}" '--sections' "$1")";
3408 _list="$(list_append "${_list}" '-T' "$1")";
3418 -w|--where|--location)
3419 _list="$(list_append "${_list}" '--location')";
3422 _list="$(list_append "${_list}" '-Z' "$1")";
3425 # ignore all other options
3428 GROFFER_OPT="$(list_from_lists "${_list}" "${GROFFER_OPT}")";
3429 eval "${return_ok}";
3430 } # main_parse_MANOPT()
3433 ########################################################################
3434 # main_parse_args (<command_line_args>*)
3436 # Parse arguments; process options and filespec parameters
3438 # Arguments: pass the command line arguments unaltered.
3441 # out: $_OPT_*, $_ADDOPTS, $_FILEARGS
3443 landmark '15: main_parse_args()';
3446 func_check main_parse_args '>=' 0 "$@";
3458 eval set -- "${GROFFER_OPT}" '"$@"';
3460 eval set -- "$(list_from_cmdline \
3461 "$_OPTS_CMDLINE_SHORT_NA" "$_OPTS_CMDLINE_SHORT_ARG" \
3462 "$_OPTS_CMDLINE_LONG_NA" "$_OPTS_CMDLINE_LONG_ARG" \
3465 # By the call of `eval', unnecessary quoting was removed. So the
3466 # positional shell parameters ($1, $2, ...) are now guaranteed to
3467 # represent an option or an argument to the previous option, if any;
3468 # then a `--' argument for separating options and
3469 # parameters; followed by the filespec parameters if any.
3471 # Note, the existence of arguments to options has already been checked.
3472 # So a check for `$#' or `--' should not be done for arguments.
3474 until test "$#" -le 0 || is_equal "$1" '--'; do
3475 _opt="$1"; # $_opt is fed into the option handler
3482 -Q|--source) # output source code (`Quellcode').
3485 -T|--device|--troff-device)
3500 -Z|--ditroff|--intermediate-output)
3501 # groff intermediate output
3505 # delete leading `-'
3506 _optchar="$(echo -n "${_opt}" | sed -e 's/^.//')";
3507 if list_has "${_OPTS_GROFF_SHORT_NA}" "${_optchar}";
3509 _ADDOPTS_GROFF="$(list_append "${_ADDOPTS_GROFF}" \
3511 elif list_has "${_OPTS_GROFF_SHORT_ARG}" "${_optchar}";
3513 _ADDOPTS_GROFF="$(list_append "${_ADDOPTS_GROFF}" \
3517 error "Unknown option : \`$1'";
3524 _ADDOPTS_GROFF="$(list_append "${_ADDOPTS_GROFF}" \
3530 --auto) # the default automatic mode
3533 --bd) # border color for viewers, arg;
3537 --bg|--backgroud) # background color for viewers, arg;
3541 --bw) # border width for viewers, arg;
3545 --default) # reset variables to default
3548 --default-modes) # sequence of modes in auto mode; arg
3549 _OPT_DEFAULT_MODES="$1";
3552 --debug) # sequence of modes in auto mode; arg
3555 --display) # set X display, arg
3562 --dvi-viewer) # viewer program for dvi mode; arg
3563 _OPT_VIEWER_DVI="$1";
3566 --extension) # the extension for man pages, arg
3567 _OPT_EXTENSION="$1";
3570 --fg|--foreground) # foreground color for viewers, arg;
3574 --fn|--font) # set font for viewers, arg;
3578 --geometry) # window geometry for viewers, arg;
3585 --locale) # set language for man pages, arg
3586 # argument is xx[_territory[.codeset[@modifier]]] (ISO 639,...)
3590 --local-file) # force local files; same as `--no-man'
3594 --location|--where) # print file locations to stderr
3595 _OPT_LOCATION='yes';
3597 --man) # force all file params to be man pages
3601 --manpath) # specify search path for man pages, arg
3602 # arg is colon-separated list of directories
3606 --mode) # display mode
3610 auto|'') # the default automatic mode
3613 groff) # pass input to plain groff
3616 dvi) # display with xdvi viewer
3619 pdf) # display with PDF viewer
3622 ps) # display with Postscript viewer
3625 X|x) # output on X roff viewer
3628 tty) # output on terminal
3631 Q|source) # display source code
3635 error "unknown mode ${_arg}";
3638 _OPT_MODE="${_mode}";
3640 --no-location) # disable former call to `--location'
3641 _OPT_LOCATION='yes';
3643 --no-man) # disable search for man pages
3644 # the same as --local-file
3648 --pager) # set paging program for tty mode, arg
3655 --pdf-viewer) # viewer program for ps mode; arg
3656 _OPT_VIEWER_PDF="$1";
3662 --ps-viewer) # viewer program for ps mode; arg
3663 _OPT_VIEWER_PS="$1";
3666 --resolution) # set resolution for X devices, arg
3677 error "only resoutions of 75 or 100 dpi are supported";
3680 _OPT_RESOLUTION="${_dpi}";
3685 --sections) # specify sections for man pages, arg
3686 # arg is colon-separated list of section names
3693 --systems) # man pages for different OS's, arg
3694 # argument is a comma-separated list
3698 --title) # title for X viewers; arg
3705 --tty-device) # device for tty mode; arg
3706 _OPT_TTY_DEVICE="$1";
3712 --www) # display with web browser
3715 --www-viewer) # viewer program for www mode; arg
3716 _OPT_VIEWER_WWW="$1";
3722 --xrm) # pass X resource string, arg;
3723 _OPT_XRM="$(list_append "${_OPT_XRM}" "$1")";
3726 --x-viewer) # viewer program for x mode; arg
3731 error 'error on argument parsing : '"\`$*'";
3735 shift; # remove `--' argument
3737 if test "${_DEBUG}" != 'yes'; then
3738 if test "${_OPT_DEBUG}" = 'yes'; then
3743 # Remaining arguments are file names (filespecs).
3744 # Save them to list $_FILEARGS
3745 if test "$#" -eq 0; then # use "-" for standard input
3748 _FILEARGS="$(list_from_args "$@")";
3749 if list_has "$_FILEARGS" '-'; then
3752 # $_FILEARGS must be retrieved with `eval set -- "$_FILEARGS"'
3753 eval "${return_ok}";
3754 } # main_parse_args()
3757 ########################################################################
3760 # Determine the display mode.
3763 # in: $DISPLAY, $_OPT_MODE, $_OPT_DEVICE
3764 # out: $_DISPLAY_MODE
3767 # _get_first_prog (<proglist>)
3769 # Retrieve first argument that represents an existing program in $PATH.
3770 # Local function for main_set_mode().
3772 # Arguments: 1; a comma-separated list of commands (with options),
3775 # Return : `1' if none found, `0' if found.
3776 # Output : the argument that succeded.
3778 landmark '16: main_set_mode()';
3781 func_check main_set_mode = 0 "$@";
3788 if is_yes "${_OPT_APROPOS}"; then
3796 if is_not_empty "${_OPT_DISPLAY}"; then
3797 DISPLAY="${_OPT_DISPLAY}";
3800 if is_yes "${_OPT_V}"; then
3801 _DISPLAY_MODE='groff';
3802 _ADDOPTS_GROFF="$(list_append "${_ADDOPTS_GROFF}" '-V')";
3804 if is_yes "${_OPT_X}"; then
3805 _DISPLAY_MODE='groff';
3806 _ADDOPTS_GROFF="$(list_append "${_ADDOPTS_GROFF}" '-X')";
3808 if is_yes "${_OPT_Z}"; then
3809 _DISPLAY_MODE='groff';
3810 _ADDOPTS_GROFF="$(list_append "${_ADDOPTS_GROFF}" '-Z')";
3812 if is_equal "${_OPT_MODE}" 'groff'; then
3813 _DISPLAY_MODE='groff';
3815 if is_equal "${_DISPLAY_MODE}" 'groff'; then
3816 eval "${return_ok}";
3819 if is_equal "${_OPT_MODE}" 'source'; then
3820 _DISPLAY_MODE='source';
3821 eval "${return_ok}";
3824 case "${_OPT_MODE}" in
3825 '') # automatic mode
3826 case "${_OPT_DEVICE}" in
3828 if is_empty "${DISPLAY}"; then
3829 error "no X display found for device ${_OPT_DEVICE}";
3832 eval "${return_ok}";
3834 ascii|cp1047|latin1|utf8)
3835 _DISPLAY_MODE='tty';
3836 eval "${return_ok}";
3839 if is_empty "${DISPLAY}"; then
3840 _DISPLAY_MODE='tty';
3841 eval "${return_ok}";
3844 if is_empty "${_OPT_DEFAULT_MODES}"; then
3845 _modes="${_DEFAULT_MODES}";
3847 _modes="${_OPT_DEFAULT_MODES}";
3851 _DISPLAY_MODE='tty';
3852 eval "${return_ok}";
3854 *) # display mode was given
3855 if is_empty "${DISPLAY}"; then
3856 error "you must be in X Window for ${_OPT_MODE} mode.";
3858 _modes="${_OPT_MODE}";
3862 # only viewer modes are left
3863 eval set -- "$(list_from_split "${_modes}" ',')";
3864 while test "$#" -gt 0; do
3869 _DISPLAY_MODE='tty';
3870 eval "${return_ok}";
3873 if is_not_empty "${_OPT_VIEWER_X}"; then
3874 _viewers="${_OPT_VIEWER_X}";
3876 _viewers="${_VIEWER_X}";
3878 _viewer="$(_get_first_prog "${_viewers}")";
3879 if test "$?" -ne 0; then
3882 _DISPLAY_PROG="${_viewer}";
3884 eval "${return_ok}";
3887 if is_not_empty "${_OPT_VIEWER_DVI}"; then
3888 _viewers="${_OPT_VIEWER_DVI}";
3890 _viewers="${_VIEWER_DVI}";
3892 _viewer="$(_get_first_prog "${_viewers}")";
3893 if test "$?" -ne 0; then
3896 _DISPLAY_PROG="${_viewer}";
3897 _DISPLAY_MODE="dvi";
3898 eval "${return_ok}";
3901 if is_not_empty "${_OPT_VIEWER_PDF}"; then
3902 _viewers="${_OPT_VIEWER_PDF}";
3904 _viewers="${_VIEWER_PDF}";
3906 _viewer="$(_get_first_prog "${_viewers}")";
3907 if test "$?" -ne 0; then
3910 _DISPLAY_PROG="${_viewer}";
3911 _DISPLAY_MODE="pdf";
3912 eval "${return_ok}";
3915 if is_not_empty "${_OPT_VIEWER_PS}"; then
3916 _viewers="${_OPT_VIEWER_PS}";
3918 _viewers="${_VIEWER_PS}";
3920 _viewer="$(_get_first_prog "${_viewers}")";
3921 if test "$?" -ne 0; then
3924 _DISPLAY_PROG="${_viewer}";
3926 eval "${return_ok}";
3929 if is_not_empty "${_OPT_VIEWER_WWW}"; then
3930 _viewers="${_OPT_VIEWER_WWW}";
3932 _viewers="${_VIEWER_WWW}";
3934 _viewer="$(_get_first_prog "${_viewers}")";
3935 if test "$?" -ne 0; then
3938 _DISPLAY_PROG="${_viewer}";
3939 _DISPLAY_MODE="www";
3940 eval "${return_ok}";
3944 error "no suitable display mode found.";
3950 if test "$#" -eq 0; then
3951 error "_get_first_prog() needs 1 argument.";
3953 if is_empty "$1"; then
3956 eval set -- "$(list_from_split "$1" ',')";
3958 if is_empty "$i"; then
3961 if is_prog "$(get_first_essential $i)"; then
3970 #######################################################################
3971 # main_do_fileargs ()
3973 # Process filespec arguments in $_FILEARGS.
3976 # in: $_FILEARGS (process with `eval set -- "$_FILEARGS"')
3978 landmark '17: main_do_fileargs()';
3981 func_check main_do_fileargs = 0 "$@";
3985 _exitcode="${_BAD}";
3986 eval set -- "${_FILEARGS}";
3988 # temporary storage of all input to $_TMP_CAT
3989 while test "$#" -ge 2; do
3990 # test for `s name' arguments, with `s' a 1-char standard section
3993 case "${_filespec}" in
3998 if register_file '-'; then
3999 _exitcode="${_GOOD}";
4004 if list_has_not "${_MAN_AUTO_SEC}" "${_filespec}"; then
4005 if do_filearg "${_filespec}"; then
4006 _exitcode="${_GOOD}";
4012 */*|man:*|*\(*\)|*."${_filespec}")
4013 if do_filearg "${_filespec}"; then
4014 _exitcode="${_GOOD}";
4019 if do_filearg "man:${_name}(${_filespec})"; then
4020 _exitcode="${_GOOD}";
4024 if do_filearg "${_filespec}"; then
4025 _exitcode="${_GOOD}";
4031 if do_filearg "${_filespec}"; then
4032 _exitcode="${_GOOD}";
4037 done; # end of `s name' test
4038 while test "$#" -gt 0; do
4041 if do_filearg "${_filespec}"; then
4042 _exitcode="${_GOOD}";
4046 if is_equal "${_exitcode}" "${_BAD}"; then
4047 eval "${return_bad}";
4049 eval "${return_ok}";
4050 } # main_do_fileargs()
4053 ########################################################################
4054 # main_set_resources ()
4056 # Determine options for setting X resources with $_DISPLAY_PROG.
4058 landmark '18: main_set_resources()';
4059 main_set_resources()
4061 func_check main_set_resources = 0 "$@";
4062 local _prog; # viewer program
4063 local _rl; # resource list
4065 if is_empty "${_DISPLAY_PROG}"; then
4066 eval "${return_ok}";
4068 set -- ${_DISPLAY_PROG};
4069 _prog="$(base_name "$1")";
4070 if is_not_empty "${_OPT_BD}"; then
4072 ghostview|gv|gxditview|xditview|xdvi)
4073 _rl="$(list_append "$_rl" '-bd' "${_OPT_BD}")";
4077 if is_not_empty "${_OPT_BG}"; then
4079 ghostview|gv|gxditview|xditview|xdvi)
4080 _rl="$(list_append "$_rl" '-bg' "${_OPT_BG}")";
4083 _rl="$(list_append "$_rl" '-papercolor' "${_OPT_BG}")";
4087 if is_not_empty "${_OPT_BW}"; then
4089 ghostview|gv|gxditview|xditview|xdvi)
4090 _rl="$(list_append "$_rl" '-bw' "${_OPT_BW}")";
4094 if is_not_empty "${_OPT_FG}"; then
4096 ghostview|gv|gxditview|xditview|xdvi)
4097 _rl="$(list_append "$_rl" '-fg' "${_OPT_FG}")";
4101 if is_not_empty "${_OPT_FN}"; then
4103 ghostview|gv|gxditview|xditview|xdvi)
4104 _rl="$(list_append "$_rl" '-fn' "${_OPT_FN}")";
4108 if is_not_empty "${_OPT_GEOMETRY}"; then
4110 ghostview|gv|gxditview|xditview|xdvi|xpdf)
4111 _rl="$(list_append "$_rl" '-geometry' "${_OPT_GEOMETRY}")";
4115 if is_empty "${_OPT_RESOLUTION}"; then
4118 _rl="$(list_append "$_rl" \
4119 '-resolution' "${_DEFAULT_RESOLUTION}")";
4122 case "${_DEFAULT_RESOLUTION}" in
4124 _rl="$(list_append "$_rl" '-z' '2')";
4127 _rl="$(list_append "$_rl" '-z' '3')";
4134 ghostview|gv|gxditview|xditview|xdvi)
4135 _rl="$(list_append "$_rl" '-resolution' "${_OPT_RESOLUTION}")";
4138 case "${_OPT_RESOLUTION}" in
4140 _rl="$(list_append "$_rl" '-z' '2')";
4143 _rl="$(list_append "$_rl" '-z' '3')";
4149 if is_not_empty "${_OPT_RV}"; then
4151 ghostview|gv|gxditview|xditview|xdvi)
4152 _rl="$(list_append "$_rl" '-rv')";
4156 if is_not_empty "${_OPT_XRM}"; then
4158 ghostview|gv|gxditview|xditview|xdvi|xpdf)
4159 eval set -- "{$_OPT_XRM}";
4161 _rl="$(list_append "$_rl" '-xrm' "$i")";
4166 _title="$(get_first_essential \
4167 "${_OPT_TITLE}" "${_REGISTERED_TITLE}")";
4168 if is_not_empty "${_title}"; then
4171 _rl="$(list_append "$_rl" '-title' "${_title}")";
4175 _DISPLAY_ARGS="${_rl}";
4176 eval "${return_ok}";
4177 } # main_set_resources
4180 ########################################################################
4183 # Do the actual display of the whole thing.
4186 # in: $_DISPLAY_MODE, $_OPT_DEVICE,
4187 # $_ADDOPTS_GROFF, $_ADDOPTS_POST, $_ADDOPTS_X,
4188 # $_REGISTERED_TITLE, $_TMP_PREFIX, $_TMP_CAT,
4189 # $_OPT_PAGER $PAGER $_MANOPT_PAGER
4191 landmark '19: main_display()';
4194 func_check main_display = 0 "$@";
4207 # Some display programs have trouble with empty input.
4208 # This is avoided by feeding a space character in this case.
4209 # Test on non-empty file by tracking a line with at least 1 character.
4210 if is_empty "$(tmp_cat | sed -e '/./q')"; then
4211 echo ' ' > "${_TMP_CAT}";
4214 case "${_DISPLAY_MODE}" in
4216 _ADDOPTS_GROFF="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}";
4217 if is_not_empty "${_OPT_DEVICE}"; then
4218 _ADDOPTS_GROFF="${_ADDOPTS_GROFF} -T${_OPT_DEVICE}";
4220 _groggy="$(tmp_cat | eval grog "${_options}")";
4221 trap "" EXIT 2>/dev/null || true;
4222 # start a new shell program to get another process ID.
4226 _modefile="${_TMP_DIR}/${_PROGRAM_NAME}${_PROCESS_ID}";
4227 rm -f "${_modefile}";
4228 mv "${_TMP_CAT}" "${_modefile}";
4229 rm -f "${_TMP_CAT}";
4230 cat "${_modefile}" | \
4234 rm -f "${_modefile}";
4236 trap clean_up EXIT 2>/dev/null || true;
4237 eval "${_groggy}" "${_ADDOPTS_GROFF}";
4241 case "${_OPT_DEVICE}" in
4243 _device="$(get_first_essential \
4244 "${_OPT_TTY_DEVICE}" "${_DEFAULT_TTY_DEVICE}")";
4246 ascii|cp1047|latin1|utf8)
4247 _device="${_OPT_DEVICE}";
4251 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4254 _addopts="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}";
4255 _groggy="$(tmp_cat | grog -T${_device})";
4257 for p in "${_OPT_PAGER}" "${PAGER}" "${_MANOPT_PAGER}" \
4258 'less' 'more' 'cat'; do
4259 if is_prog "$p"; then
4264 if is_empty "${_pager}"; then
4265 error 'no pager program found for tty mode';
4267 tmp_cat | eval "${_groggy}" "${_addopts}" | \
4275 case "${_OPT_DEVICE}" in
4276 ''|dvi) do_nothing; ;;
4279 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4282 _groggy="$(tmp_cat | grog -Tdvi)";
4286 case "${_OPT_DEVICE}" in
4292 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4295 _groggy="$(tmp_cat | grog -Tps)";
4296 trap "" EXIT 2>/dev/null || true;
4297 # start a new shell program to get another process ID.
4301 _psfile="${_TMP_DIR}/${_PROGRAM_NAME}${_PROCESS_ID}";
4302 _modefile="${_TMP_DIR}/${_PROGRAM_NAME}${_PROCESS_ID}.pdf";
4304 rm -f "${_modefile}";
4305 cat "${_TMP_CAT}" | \
4306 eval "${_groggy}" "${_ADDOPTS_GROFF}" > "${_psfile}";
4307 gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \
4308 -sOutputFile="${_modefile}" -c save pop -f "${_psfile}";
4310 rm -f "${_TMP_CAT}";
4314 rm -f "${_modefile}";
4316 trap clean_up EXIT 2>/dev/null || true;
4317 eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "${_modefile}";
4321 case "${_OPT_DEVICE}" in
4327 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4330 _groggy="$(tmp_cat | grog -Tps)";
4338 case "${_OPT_DEVICE}" in
4339 ''|html) do_nothing; ;;
4342 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4345 _groggy="$(tmp_cat | grog -Thtml)";
4349 case "${_OPT_DEVICE}" in
4351 _groggy="$(tmp_cat | grog -Z)";
4354 _groggy="$(tmp_cat | grog -T"${_OPT_DEVICE}" -Z)";
4358 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4359 _groggy="$(tmp_cat | grog -Z)";
4365 error "unknown mode \`${_DISPLAY_MODE}'";
4368 eval "${return_ok}";
4373 trap "" EXIT 2>/dev/null || true;
4374 # start a new shell program to get another process ID.
4378 _modefile="${_TMP_DIR}/${_PROGRAM_NAME}${_PROCESS_ID}";
4379 rm -f "${_modefile}";
4380 cat "${_TMP_CAT}" | \
4381 eval "${_groggy}" "${_ADDOPTS_GROFF}" > "${_modefile}";
4382 rm -f "${_TMP_CAT}";
4386 rm -f "${_modefile}";
4388 trap clean_up EXIT 2>/dev/null || true;
4389 eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "${_modefile}";
4394 ########################################################################
4395 # main (<command_line_args>*)
4397 # The main function for groffer.
4403 func_check main '>=' 0 "$@";
4404 # Do not change the sequence of the following functions!
4407 main_parse_args "$@";
4412 eval "${return_ok}";
4415 landmark '20: end of function definitions';
4417 ########################################################################