* All affected files: Update postal address of FSF.
[s-roff.git] / contrib / groffer / groffer.sh
blob30d6c5bab837be5c954261e45f0ad53a93802de3
1 #! /bin/sh
3 # groffer - display groff files
5 # Source file position: <groff-source>/contrib/groffer/groffer.sh
7 # Copyright (C) 2001,2002,2003,2004,2005 Free Software Foundation, Inc.
8 # Written by Bernd Warken
10 # This file is part of groff version @VERSION@.
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)
15 # any later version.
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 files COPYING and LICENSE in the top
24 # directory of the groff source. If not, write to the Free Software
25 # Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
27 _PROGRAM_NAME='groffer';
28 _PROGRAM_VERSION='0.9.13';
29 _LAST_UPDATE='17 May 2005';
32 ########################################################################
33 # Determine the shell under which to run this script from the command
34 # line arguments or $GROFF_OPT; if none is specified, just go on with
35 # the starting shell.
37 if test _"${_groffer_run}"_ = __; then
38 # only reached during the first run of the script
40 export _groffer_run; # counter for the runs of groffer
41 _groffer_run='first';
43 export _PROGRAM_NAME;
44 export _PROGRAM_VERSION;
45 export _LAST_UPDATE;
47 export GROFFER_OPT; # option environment for groffer
48 export _GROFFER_SH; # file name of this shell script
49 export _OUTPUT_FILE_NAME; # output generated, see main_set_res..()
51 export _CONFFILES; # configuration files
52 _CONFFILES="/etc/groff/groffer.conf ${HOME}/.groff/groffer.conf";
54 case "$0" in
55 *${_PROGRAM_NAME}*)
56 _GROFFER_SH="$0";
57 # was: _GROFFER_SH="@BINDIR@/${_PROGRAM_NAME}";
60 echo "The ${_PROGRAM_NAME} script should be started directly." >&2
61 exit 1;
63 esac;
65 ###########################
66 # _get_opt_shell ("$@")
68 # Determine whether `--shell' was specified in $GROFF_OPT or in $*;
69 # if so echo its argument.
71 _get_opt_shell()
73 local i;
74 local _sh;
75 case " ${GROFFER_OPT} $*" in
76 *\ --shell\ *|*\ --shell=*)
78 eval set -- "${GROFFER_OPT}" '"$@"';
79 _sh='';
80 for i in "$@"; do
81 case "$1" in
82 --shell)
83 if test "$#" -ge 2; then
84 _sh="$2";
85 shift;
86 fi;
88 --shell=?*)
89 # delete up to first `=' character
90 _sh="$(echo -n "$1" | sed -e 's/^[^=]*=//')";
92 esac;
93 shift;
94 done;
95 echo -n "${_sh}";
98 esac;
102 ###########################
103 # _test_on_shell (<name>)
105 # Test whether <name> is a shell program of Bourne type (POSIX sh).
107 _test_on_shell()
109 if test "$#" -le 0 || test _"$1"_ = __; then
110 return 1;
112 # do not quote $1 to allow arguments
113 test _"$($1 -c 's=ok; echo -n "$s"' 2>/dev/null)"_ = _ok_;
116 # do the shell determination from command line and $GROFFER_OPT
117 _shell="$(_get_opt_shell "$@")";
119 if test _"${_shell}"_ = __; then
120 # none found, so look at the `--shell' lines in configuration files
121 export f;
122 for f in ${_CONFFILES}; do
123 if test -f $f; then
124 _all="$(cat $f | sed -n -e '/^--shell[= ] *\([^ ]*\)$/s//\1/p')"
125 for s in ${_all}; do
126 _shell=$s;
127 done;
129 done;
130 unset f;
131 unset s;
132 unset _all;
135 # restart the script with the last found $_shell, if it is a shell
136 if _test_on_shell "${_shell}"; then
137 _groffer_run='second';
138 # do not quote $_shell to allow arguments
139 exec ${_shell} "${_GROFFER_SH}" "$@";
140 exit;
143 _groffer_run='second';
144 unset _shell;
146 fi; # end of first run
148 if test _"${_groffer_run}"_ != _second_;
149 then
150 echo "$_groffer_run should be 'second' here." >&2
151 exit 1
154 unset _groffer_run
157 ########################################################################
158 # diagnostic messages
160 export _DEBUG;
161 _DEBUG='no'; # disable debugging information
162 #_DEBUG='yes'; # enable debugging information
164 export _DEBUG_LM;
165 _DEBUG_LM='no'; # disable landmark messages
166 #_DEBUG_LM='yes'; # enable landmark messages
169 ########################################################################
170 # Environment Variables
171 ########################################################################
173 # Environment variables that exist only for this file start with an
174 # underscore letter. Global variables to this file are written in
175 # upper case letters, e.g. $_GLOBAL_VARIABLE; temporary variables
176 # start with an underline and use only lower case letters and
177 # underlines, e.g. $_local_variable .
179 # [A-Z]* system variables, e.g. $MANPATH
180 # _[A-Z_]* global file variables, e.g. $_MAN_PATH
181 # _[a-z_]* temporary variables, e.g. $_manpath
183 # Due to incompatibilities of the `ash' shell, the name of loop
184 # variables in `for' must be single character
185 # [a-z] local loop variables, e.g. $i
188 ########################################################################
189 # read-only variables (global to this file)
190 ########################################################################
192 # characters
194 export _BQUOTE;
195 export _BSLASH;
196 export _DQUOTE;
197 export _NEWLINE;
198 export _LBRACK;
199 export _LPAR;
200 export _RBRACK;
201 export _RPAR;
202 export _SPACE;
203 export _SQUOTE;
204 export _TAB;
206 _BQUOTE='`';
207 _BSLASH='\';
208 _DQUOTE='"';
209 _NEWLINE='
211 _LBRACK='[';
212 _LPAR='(';
213 _RBRACK=']';
214 _RPAR=')';
215 _SPACE=' ';
216 _SQUOTE="'";
217 _TAB=' ';
219 # function return values; `0' means ok; other values are error codes
220 export _ALL_EXIT;
221 export _BAD;
222 export _ERROR;
223 export _GOOD;
224 export _NO;
225 export _OK;
226 export _YES;
228 _GOOD='0'; # return ok
229 _BAD='1'; # return negatively, error code `1'
230 _ERROR='7'; # for syntax errors; no `-1' in `ash'
232 _ALL_EXIT="${_GOOD} ${_BAD} ${_ERROR}"; # all exit codes (for `trap_set')
234 _NO="${_BAD}";
235 _YES="${_GOOD}";
236 _OK="${_GOOD}";
238 # quasi-functions, call with `eval'
239 export return_ok;
240 export return_good;
241 export return_bad;
242 export return_yes;
243 export return_no;
244 export return_error;
245 return_ok="func_pop; return ${_OK}";
246 return_good="func_pop; return ${_GOOD}";
247 return_bad="func_pop; return ${_BAD}";
248 return_yes="func_pop; return ${_YES}";
249 return_no="func_pop; return ${_NO}";
250 return_error="func_pop; return ${_ERROR}";
253 export _DEFAULT_MODES;
254 _DEFAULT_MODES='x,ps,tty';
255 export _DEFAULT_RESOLUTION;
256 _DEFAULT_RESOLUTION='75';
258 export _DEFAULT_TTY_DEVICE;
259 _DEFAULT_TTY_DEVICE='latin1';
261 # _VIEWER_* viewer programs for different modes (only X is necessary)
262 # _VIEWER_* a comma-separated list of viewer programs (with options)
263 export _VIEWER_DVI; # viewer program for dvi mode
264 export _VIEWER_PS; # viewer program for ps mode
265 export _VIEWER_HTML_X; # viewer program for html mode in X
266 export _VIEWER_HTML_TTY; # viewer program for html mode in tty
267 _VIEWER_DVI='kdvi,xdvi,dvilx';
268 _VIEWER_PDF='kghostview,ggv,xpdf,acroread,kpdf';
269 _VIEWER_PS='kghostview,ggv,gv,ghostview,gs_x11,gs';
270 _VIEWER_HTML='konqueror,mozilla,netscape,opera,amaya,arena,lynx';
271 _VIEWER_X='gxditview,xditview';
273 # Search automatically in standard sections `1' to `8', and in the
274 # traditional sections `9', `n', and `o'. On many systems, there
275 # exist even more sections, mostly containing a set of man pages
276 # special to a specific program package. These aren't searched for
277 # automatically, but must be specified on the command line.
278 export _MAN_AUTO_SEC;
279 _MAN_AUTO_SEC="'1' '2' '3' '4' '5' '6' '7' '8' '9' 'n' 'o'"
281 export _PROCESS_ID; # for shutting down the program
282 _PROCESS_ID="$$";
285 ############ the command line options of the involved programs
287 # The naming scheme for the options environment names is
288 # $_OPTS_<prog>_<length>[_<argspec>]
290 # <prog>: program name GROFFER, GROFF, or CMDLINE (for all
291 # command line options)
292 # <length>: LONG (long options) or SHORT (single character options)
293 # <argspec>: ARG for options with argument, NA for no argument;
294 # without _<argspec> both the ones with and without arg.
296 # Each option that takes an argument must be specified with a
297 # trailing : (colon).
299 # exports
300 export _OPTS_GROFFER_SHORT_NA;
301 export _OPTS_GROFFER_SHORT_ARG;
302 export _OPTS_GROFFER_LONG_NA;
303 export _OPTS_GROFFER_LONG_ARG;
304 export _OPTS_GROFF_SHORT_NA;
305 export _OPTS_GROFF_SHORT_ARG;
306 export _OPTS_GROFF_LONG_NA;
307 export _OPTS_GROFF_LONG_ARG;
308 export _OPTS_X_SHORT_ARG;
309 export _OPTS_X_SHORT_NA;
310 export _OPTS_X_LONG_ARG;
311 export _OPTS_X_LONG_NA;
312 export _OPTS_MAN_SHORT_ARG;
313 export _OPTS_MAN_SHORT_NA;
314 export _OPTS_MAN_LONG_ARG;
315 export _OPTS_MAN_LONG_NA;
316 export _OPTS_MANOPT_SHORT_ARG;
317 export _OPTS_MANOPT_SHORT_NA;
318 export _OPTS_MANOPT_LONG_ARG;
319 export _OPTS_MANOPT_LONG_NA;
320 export _OPTS_CMDLINE_SHORT_NA;
321 export _OPTS_CMDLINE_SHORT_ARG;
322 export _OPTS_CMDLINE_LONG_NA;
323 export _OPTS_CMDLINE_LONG_ARG;
325 ###### groffer native options
327 _OPTS_GROFFER_SHORT_NA="'h' 'Q' 'v' 'V' 'X' 'Z'";
328 _OPTS_GROFFER_SHORT_ARG="'T'";
330 _OPTS_GROFFER_LONG_NA="'auto' 'debug' 'default' 'dvi' \
331 'groff' 'help' 'intermediate-output' 'html' 'man' \
332 'no-location' 'no-man' 'pdf' 'ps' 'rv' 'source' 'text' 'text-device' \
333 'title' 'tty' 'tty-device' 'version' 'whatis' 'where' 'www' 'x' 'X'";
335 _OPTS_GROFFER_LONG_ARG="\
336 'apropos' 'apropos-data' 'apropos-devel' 'apropos-progs' \
337 'default-modes' 'device' 'dvi-viewer' 'extension' 'fg' 'fn' 'font' \
338 'foreground' 'html-viewer' 'mode' 'pdf-viewer' 'ps-viewer' 'shell' \
339 'tty-viewer' 'www-viewer' 'x-viewer' 'X-viewer'";
341 ##### groffer options inhereted from groff
343 _OPTS_GROFF_SHORT_NA="'a' 'b' 'c' 'C' 'e' 'E' 'g' 'G' 'i' 'l' 'N' 'p' \
344 'R' 's' 'S' 't' 'U' 'z'";
345 _OPTS_GROFF_SHORT_ARG="'d' 'f' 'F' 'I' 'L' 'm' 'M' 'n' 'o' 'P' 'r' \
346 'w' 'W'";
347 _OPTS_GROFF_LONG_NA="";
348 _OPTS_GROFF_LONG_ARG="";
350 ##### groffer options inhereted from the X Window toolkit
352 _OPTS_X_SHORT_NA="";
353 _OPTS_X_SHORT_ARG="";
355 _OPTS_X_LONG_NA="'iconic' 'rv'";
357 _OPTS_X_LONG_ARG="'background' 'bd' 'bg' 'bordercolor' 'borderwidth' \
358 'bw' 'display' 'fg' 'fn' 'font' 'foreground' 'ft', 'geometry'
359 'resolution' 'title' 'xrm'";
361 ###### groffer options inherited from man
363 _OPTS_MAN_SHORT_NA="";
364 _OPTS_MAN_SHORT_ARG="";
366 _OPTS_MAN_LONG_NA="'all' 'ascii' 'catman' 'debug' 'ditroff' 'help' \
367 'local-file' 'location' 'pager' 'troff' 'update' 'version' \
368 'whatis' 'where'";
370 _OPTS_MAN_LONG_ARG="'extension' 'locale' 'manpath' \
371 'pager' 'preprocessor' 'prompt' 'sections' 'systems' 'troff-device'";
373 ###### additional options for parsing $MANOPT only
375 _OPTS_MANOPT_SHORT_NA="'7' 'a' 'c' 'd' 'D' 'f' 'h' 'k' 'l' 't' 'u' \
376 'V' 'w' 'Z'";
377 _OPTS_MANOPT_SHORT_ARG="'e' 'L' 'm' 'M' 'p' 'P' 'r' 'S' 'T'";
379 _OPTS_MANOPT_LONG_NA="${_OPTS_MAN_LONG_NA} \
380 'apropos' 'debug' 'default' 'html' 'ignore-case' 'location-cat' \
381 'match-case' 'troff' 'update' 'version' 'where-cat'";
383 _OPTS_MANOPT_LONG_ARG="${_OPTS_MAN_LONG_NA} \
384 'config_file' 'encoding' 'locale'";
386 ###### collections of command line options
388 _OPTS_CMDLINE_SHORT_NA="${_OPTS_GROFFER_SHORT_NA}\
389 ${_OPTS_GROFF_SHORT_NA} ${_OPTS_X_SHORT_NA} ${_OPTS_MAN_SHORT_NA}";
390 _OPTS_CMDLINE_SHORT_ARG="${_OPTS_GROFFER_SHORT_ARG} \
391 ${_OPTS_GROFF_SHORT_ARG} ${_OPTS_X_SHORT_ARG} ${_OPTS_MAN_SHORT_ARG}";
393 _OPTS_CMDLINE_LONG_NA="${_OPTS_GROFFER_LONG_NA} \
394 ${_OPTS_GROFF_LONG_NA} ${_OPTS_X_LONG_NA} ${_OPTS_MAN_LONG_NA}";
395 _OPTS_CMDLINE_LONG_ARG="${_OPTS_GROFFER_LONG_ARG} \
396 ${_OPTS_GROFF_LONG_ARG} ${_OPTS_MAN_LONG_ARG} ${_OPTS_X_LONG_ARG}";
399 ########################################################################
400 # read-write variables (global to this file)
401 ########################################################################
403 export _ADDOPTS_GROFF; # Transp. options for groff (`eval').
404 export _ADDOPTS_POST; # Transp. options postproc (`eval').
405 export _ADDOPTS_X; # Transp. options X postproc (`eval').
406 export _DEFAULT_MODES; # Set default modes.
407 export _DISPLAY_MODE; # Display mode.
408 export _DISPLAY_PROG; # Viewer program to be used for display.
409 export _DISPLAY_ARGS; # X resources for the viewer program.
410 export _FILEARGS; # Stores filespec parameters.
411 export _FUNC_STACK; # Store debugging information.
412 export _REGISTERED_TITLE; # Processed file names.
413 # _HAS_* from availability tests
414 export _HAS_COMPRESSION; # `yes' if compression is available
415 export _HAS_OPTS_GNU; # `yes' if GNU `getopt' is available
416 export _HAS_OPTS_POSIX; # `yes' if POSIX `getopts' is available
417 # _MAN_* finally used configuration of man searching
418 export _MAN_ALL; # search all man pages per filespec
419 export _MAN_ENABLE; # enable search for man pages
420 export _MAN_EXT; # extension for man pages
421 export _MAN_FORCE; # force file parameter to be man pages
422 export _MAN_IS_SETUP; # setup man variables only once
423 export _MAN_LANG; # language for man pages
424 export _MAN_LANG_DONE; # language dirs added to man path
425 export _MAN_PATH; # search path for man pages
426 export _MAN_SEC; # sections for man pages; sep. `:'
427 export _MAN_SEC_DONE; # sections added to man path
428 export _MAN_SYS; # system names for man pages; sep. `,'
429 export _MAN_SYS; # system names added to man path
430 # _MANOPT_* as parsed from $MANOPT
431 export _MANOPT_ALL; # $MANOPT --all
432 export _MANOPT_EXTENSION; # $MANOPT --extension
433 export _MANOPT_LANG; # $MANOPT --locale
434 export _MANOPT_PATH; # $MANOPT --manpath
435 export _MANOPT_PAGER; # $MANOPT --pager
436 export _MANOPT_SEC; # $MANOPT --sections
437 export _MANOPT_SYS; # $MANOPT --systems
438 # _OPT_* as parsed from groffer command line
439 export _OPT_ALL; # display all suitable man pages.
440 export _OPT_APROPOS; # call `apropos' program.
441 export _OPT_APROPOS_DATA; # `apropos' for man sections 4, 5, 7
442 export _OPT_APROPOS_DEVEL; # `apropos' for man sections 2, 3, 9
443 export _OPT_APROPOS_PROGS; # `apropos' for man sections 1, 6, 8
444 export _OPT_BD; # set border color in some modes.
445 export _OPT_BG; # set background color in some modes.
446 export _OPT_BW; # set border width in some modes.
447 export _OPT_DEBUG; # print debugging information on stderr.
448 export _OPT_DEFAULT_MODES; # `,'-list of modes when no mode given.
449 export _OPT_DEVICE; # device option.
450 export _OPT_DISPLAY; # set X display.
451 export _OPT_FG; # set foreground color in some modes.
452 export _OPT_FN; # set font in some modes.
453 export _OPT_GEOMETRY; # set size and position of viewer in X.
454 export _OPT_ICONIC; # -iconic option for X viewers.
455 export _OPT_LANG; # set language for man pages
456 export _OPT_LOCATION; # print processed file names to stderr
457 export _OPT_MODE; # values: X, tty, Q, Z, ""
458 export _OPT_MANPATH; # manual setting of path for man-pages
459 export _OPT_PAGER; # specify paging program for tty mode
460 export _OPT_RESOLUTION; # set X resolution in dpi
461 export _OPT_RV; # reverse fore- and background colors.
462 export _OPT_SECTIONS; # sections for man page search
463 export _OPT_SYSTEMS; # man pages of different OS's
464 export _OPT_TITLE; # title for gxditview window
465 export _OPT_TEXT_DEVICE; # set device for tty mode.
466 export _OPT_V; # groff option -V.
467 export _OPT_VIEWER_DVI; # viewer program for dvi mode
468 export _OPT_VIEWER_PDF; # viewer program for pdf mode
469 export _OPT_VIEWER_PS; # viewer program for ps mode
470 export _OPT_VIEWER_HTML; # viewer program for html mode
471 export _OPT_VIEWER_X; # viewer program for x mode
472 export _OPT_WHATIS; # print the one-liner man info
473 export _OPT_XRM; # specify X resource.
474 export _OPT_Z; # groff option -Z.
475 # _TMP_* temporary files
476 export _TMP_DIR; # groffer directory for temporary files
477 export _TMP_CAT; # stores concatenation of everything
478 export _TMP_STDIN; # stores stdin, if any
480 # these variables are preset in section `Preset' after the rudim. test
483 ########################################################################
484 # Test of rudimentary shell functionality
485 ########################################################################
488 ########################################################################
489 # Test of `test'.
491 test "a" = "a" || exit 1;
494 ########################################################################
495 # Test of `echo' and the `$()' construct.
497 echo -n '' >/dev/null || exit "${_ERROR}";
498 if test _"$(echo -n 'te' && echo -n '' && echo -n 'st')"_ != _test_; then
499 exit "${_ERROR}";
503 ########################################################################
504 # Test of function definitions.
506 _t_e_s_t_f_u_n_c_()
508 return "${_OK}";
511 if _t_e_s_t_f_u_n_c_ 2>/dev/null; then
513 else
514 echo 'shell does not support function definitions.' >&2;
515 exit "${_ERROR}";
519 ########################################################################
520 # Preset and reset of read-write global variables
521 ########################################################################
524 # For variables that can be reset by option `--default', see reset().
526 _FILEARGS='';
528 # _HAS_* from availability tests
529 _HAS_COMPRESSION='';
530 _HAS_OPTS_GNU='';
531 _HAS_OPTS_POSIX='';
533 # _TMP_* temporary files
534 _TMP_DIR='';
535 _TMP_CAT='';
536 _TMP_STDIN='';
539 ########################################################################
540 # reset ()
542 # Reset the variables that can be affected by options to their default.
544 reset()
546 if test "$#" -ne 0; then
547 error "reset() does not have arguments.";
550 _ADDOPTS_GROFF='';
551 _ADDOPTS_POST='';
552 _ADDOPTS_X='';
553 _DISPLAY_ARGS='';
554 _DISPLAY_MODE='';
555 _DISPLAY_PROG='';
556 _REGISTERED_TITLE='';
558 # _MAN_* finally used configuration of man searching
559 _MAN_ALL='no';
560 _MAN_ENABLE='yes'; # do search for man-pages
561 _MAN_EXT='';
562 _MAN_FORCE='no'; # first local file, then search man page
563 _MAN_IS_SETUP='no';
564 _MAN_LANG='';
565 _MAN_LANG_DONE='no';
566 _MAN_PATH='';
567 _MAN_SEC='';
568 _MAN_SEC_DONE='no';
569 _MAN_SYS='';
570 _MAN_SYS_DONE='no';
572 # _MANOPT_* as parsed from $MANOPT
573 _MANOPT_ALL='no';
574 _MANOPT_EXTENSION='';
575 _MANOPT_LANG='';
576 _MANOPT_PATH='';
577 _MANOPT_PAGER='';
578 _MANOPT_SEC='';
579 _MANOPT_SYS='';
581 # _OPT_* as parsed from groffer command line
582 _OPT_ALL='no';
583 _OPT_APROPOS='';
584 _OPT_APROPOS_DATA='';
585 _OPT_APROPOS_DEVEL='';
586 _OPT_APROPOS_PROGS='';
587 _OPT_BD='';
588 _OPT_BG='';
589 _OPT_BW='';
590 _OPT_DEBUG='no';
591 _OPT_DEFAULT_MODES='';
592 _OPT_DEVICE='';
593 _OPT_DISPLAY='';
594 _OPT_FG='';
595 _OPT_FN='';
596 _OPT_GEOMETRY='';
597 _OPT_ICONIC='no';
598 _OPT_LANG='';
599 _OPT_LOCATION='no';
600 _OPT_MODE='';
601 _OPT_MANPATH='';
602 _OPT_PAGER='';
603 _OPT_RESOLUTION='';
604 _OPT_RV='no';
605 _OPT_SECTIONS='';
606 _OPT_SYSTEMS='';
607 _OPT_TITLE='';
608 _OPT_TEXT_DEVICE='';
609 _OPT_V='no';
610 _OPT_VIEWER_DVI='';
611 _OPT_VIEWER_PDF='';
612 _OPT_VIEWER_PS='';
613 _OPT_VIEWER_HTML='';
614 _OPT_VIEWER_X='';
615 _OPT_WHATIS='no';
616 _OPT_XRM='';
617 _OPT_Z='no';
621 reset;
624 ########################################################################
625 # Functions for error handling and debugging
626 ########################################################################
629 ##############
630 # landmark (<text>)
632 # Print <text> to standard error as a debugging aid.
634 # Globals: $_DEBUG_LM
636 landmark()
638 if test _"${_DEBUG_LM}"_ = _yes_; then
639 echo ">>> $*" >&2;
643 landmark "1: debugging functions";
646 ##############
647 # clean_up ()
649 # Clean up at exit.
651 clean_up()
653 if test -d "${_TMP_DIR}"; then
654 rm -f -r "${_TMP_DIR}";
659 ##############
660 # echo2 (<text>*)
662 # Output to stderr.
664 # Arguments : arbitrary text.
666 echo2()
668 echo "$*" >&2;
672 ##############
673 # echo2n (<text>*)
675 # Output to stderr.
677 # Arguments : arbitrary text.
679 echo2n()
681 echo -n "$*" >&2;
685 #############
686 # diag (text>*)
688 # Output a diagnostic message to stderr
690 diag()
692 echo2 '>>>>>'"$*";
696 #############
697 # error (<text>*)
699 # Print an error message to standard error; exit with an error condition
701 error()
703 local i;
704 local _code;
705 _code="${_ERROR}";
706 case "$#" in
707 0) true; ;;
708 1) echo2 'groffer error: '"$1"; ;;
710 echo2 'groffer error: '"$1";
711 _code="$2";
713 *) echo2 'groffer error: wrong number of arguments in error().'; ;;
714 esac;
715 if test _"${_DEBUG}"_ = _yes_; then
716 func_stack_dump;
718 clean_up;
719 kill "${_PROCESS_ID}" >/dev/null 2>&1;
720 kill -9 "${_PROCESS_ID}" >/dev/null 2>&1;
721 exit "${_code}";
725 #############
726 # abort (<text>*)
728 # Terminate program with error condition
730 abort()
732 error "Program aborted.";
733 exit 1;
737 #############
738 # func_check (<func_name> <rel_op> <nr_args> "$@")
740 # Check number of arguments and register to _FUNC_STACK.
742 # Arguments: >=3
743 # <func_name>: name of the calling function.
744 # <rel_op>: a relational operator: = != < > <= >=
745 # <nr_args>: number of arguments to be checked against <operator>
746 # "$@": the arguments of the calling function.
748 func_check()
750 local _comp;
751 local _fname;
752 local _nargs;
753 local _op;
754 local _s;
755 if test "$#" -lt 3; then
756 error 'func_check() needs at least 3 arguments.';
758 _fname="$1";
759 case "$3" in
761 _nargs="$3";
762 _s='';
764 0|[2-9])
765 _nargs="$3";
766 _s='s';
769 error "func_check(): third argument must be a digit.";
771 esac;
772 case "$2" in
773 '='|'-eq')
774 _op='-eq';
775 _comp='exactly';
777 '>='|'-ge')
778 _op='-ge';
779 _comp='at least';
781 '<='|'-le')
782 _op='-le';
783 _comp='at most';
785 '<'|'-lt')
786 _op='-lt';
787 _comp='less than';
789 '>'|'-gt')
790 _op='-gt';
791 _comp='more than';
793 '!='|'-ne')
794 _op='-ne';
795 _comp='not';
798 error \
799 'func_check(): second argument is not a relational operator.';
801 esac;
802 shift 3;
803 if test "$#" "${_op}" "${_nargs}"; then
804 do_nothing;
805 else
806 error \
807 "${_fname}"'() needs '"${_comp} ${_nargs}"' argument'"${_s}"'.';
809 if test _"${_DEBUG}"_ = _yes_; then
810 func_push "${_fname} $*";
815 #############
816 # func_pop ()
818 # Retrieve the top element from the stack.
820 # The stack elements are separated by `!'; the popped element is
821 # identical to the original element, except that all `!' characters
822 # were removed.
824 # Arguments: 1
826 func_pop()
828 if test _"${_DEBUG}"_ = _yes_; then
829 if test "$#" -ne 0; then
830 error 'func_pop() does not have arguments.';
832 case "${_FUNC_STACK}" in
834 error 'func_pop(): stack is empty.';
836 *!*)
837 # split at first bang `!'.
838 _FUNC_STACK="$(echo -n ${_FUNC_STACK} \
839 | sed -e 's/^[^!]*!//')";
842 _FUNC_STACK='';
844 esac;
849 #############
850 # func_push (<element>)
852 # Store another element to stack.
854 # The stack elements are separated by `!'; if <element> contains a `!'
855 # it is removed first.
857 # Arguments: 1
859 func_push()
861 local _element;
862 if test _"${_DEBUG}"_ = _yes_; then
863 if test "$#" -ne 1; then
864 error 'func_push() needs 1 argument.';
866 case "$1" in
867 *'!'*)
868 # remove all bangs `!'.
869 _element="$(echo -n "$1" | sed -e 's/!//g')";
872 _element="$1";
874 esac;
875 if test _"${_FUNC_STACK}"_ = __; then
876 _FUNC_STACK="${_element}";
877 else
878 _FUNC_STACK="${_element}!${_FUNC_STACK}";
884 #############
885 # func_stack_dump ()
887 # Print the content of the stack. Ignore the arguments.
889 func_stack_dump()
891 diag 'call stack:';
892 case "${_FUNC_STACK}" in
893 *!*)
894 _rest="${_FUNC_STACK}";
895 while test _"${_rest}"_ != __; do
896 # get part before the first bang `!'.
897 diag "$(echo -n "${_rest}" | sed -e 's/!.*$//')";
898 # delete part before and including the first bang `!'.
899 _rest="$(echo -n "${_rest}" | sed -e 's/^[^!]*!//')";
900 done;
903 diag "${_FUNC_STACK}";
905 esac;
909 ########################################################################
910 # System Test
911 ########################################################################
913 landmark "2: system test";
915 # Test the availability of the system utilities used in this script.
918 ########################################################################
919 # Test of `true'.
921 if true >/dev/null 2>&1; then
922 true;
923 else
924 true()
926 return "${_GOOD}";
929 false()
931 return "${_BAD}";
936 ########################################################################
937 # Test of `unset'.
939 _test='test';
940 if unset _test >/dev/null 2>&1 && test _"${_test}"_ = __; then
941 true;
942 else
943 unset()
945 for v in "$@"; do
946 eval "$v"='';
947 done;
950 unset _test;
952 ########################################################################
953 # Test of builtin `local'
956 _t_e_s_t_f_u_n_c_()
958 local _test >/dev/null 2>&1 || return "${_BAD}";
961 if _t_e_s_t_f_u_n_c_; then
963 else
964 local()
966 if test _"$1"_ != __; then
967 error "overriding global variable \`$1' with local value.";
973 ########################################################################
974 # Test of global setting in functions
976 _global='outside';
977 _clobber='outside';
979 _t_e_s_t_f_u_n_c_()
981 local _clobber;
982 _global='inside';
983 _clobber='inside';
986 _t_e_s_t_f_u_n_c_;
987 if test _"${_global}"_ != _inside_ || test _"${_clobber}"_ != _outside_;
988 then
989 error "Cannot assign to global variables from within functions.";
992 unset _global;
993 unset _clobber;
996 ########################################################################
997 # Test of function `sed'.
1000 if test _"$(echo xTesTx \
1001 | sed -e 's/^.\([Tt]e*x*sTT*\).*$/\1/' \
1002 | sed -e '\|T|s|T|t|g')"_ != _test_;
1003 then
1004 error 'Test of "sed" command failed.';
1008 ########################################################################
1009 # Test of function `cat'.
1011 if test _"$(echo test | cat)"_ != _test_; then
1012 error 'Test of "cat" command failed.';
1016 ########################################################################
1017 # Test for compression.
1019 if test _"$(echo 'test' | gzip -c -d -f - 2>/dev/null)"_ = _test_; then
1020 _HAS_COMPRESSION='yes';
1021 if echo 'test' | bzip2 -c 2>/dev/null | bzip2 -t 2>/dev/null \
1022 && test _"$(echo 'test' | bzip2 -c 2>/dev/null \
1023 | bzip2 -d -c 2>/dev/null)"_ \
1024 = _test_; then
1025 _HAS_BZIP='yes';
1026 else
1027 _HAS_BZIP='no';
1029 else
1030 _HAS_COMPRESSION='no';
1031 _HAS_BZIP='no';
1035 ########################################################################
1036 _t_e_s_t_f_u_n_c_()
1042 ########################################################################
1043 # Definition of normal Functions in alphabetical order
1044 ########################################################################
1045 landmark "3: functions";
1047 ########################################################################
1048 # abort (<text>*)
1050 # Unconditionally terminate the program with error code;
1051 # useful for debugging.
1053 # defined above
1056 ########################################################################
1057 # apropos_run (<name>)
1060 apropos_run() {
1061 func_check apropos_run = 1 "$@";
1062 if apropos apropos >/dev/null 2>/dev/null; then
1063 apropos "$1";
1064 elif man --apropos man >/dev/null 2>/dev/null; then
1065 man --apropos "$1";
1066 elif man -k man >/dev/null 2>/dev/null; then
1067 man -k "$1";
1072 ########################################################################
1073 # base_name (<path>)
1075 # Get the file name part of <path>, i.e. delete everything up to last
1076 # `/' from the beginning of <path>. Remove final slashes, too, to get a
1077 # non-empty output.
1079 # Arguments : 1
1080 # Output : the file name part (without slashes)
1082 base_name()
1084 func_check base_name = 1 "$@";
1085 local f;
1086 f="$1";
1087 case "$f" in
1089 # delete all final slashes
1090 f="$(echo -n "$f" | sed -e '\|.*|s|//*$||')";
1092 esac;
1093 case "$f" in
1094 /|'')
1095 eval "${return_bad}";
1097 */*)
1098 # delete everything before and including the last slash `/'.
1099 echo -n "$f" | sed -e '\|.*|s|^.*//*\([^/]*\)$|\1|';
1102 echo -n "$f";
1104 esac;
1105 eval "${return_ok}";
1109 ########################################################################
1110 # catz (<file>)
1112 # Decompress if possible or just print <file> to standard output.
1114 # gzip, bzip2, and .Z decompression is supported.
1116 # Arguments: 1, a file name.
1117 # Output: the content of <file>, possibly decompressed.
1119 if test _"${_HAS_COMPRESSION}"_ = _yes_; then
1120 catz()
1122 func_check catz = 1 "$@";
1123 case "$1" in
1125 error 'catz(): empty file name';
1127 '-')
1128 error 'catz(): for standard input use save_stdin()';
1130 esac;
1131 if obj _HAS_BZIP is_yes; then
1132 if bzip2 -t "$1" 2>/dev/null; then
1133 bzip2 -c -d "$1" 2>/dev/null;
1134 eval "${return_ok}";
1137 gzip -c -d -f "$1" 2>/dev/null;
1138 eval "${return_ok}";
1140 else
1141 catz()
1143 func_check catz = 1 "$@";
1144 cat "$1";
1145 eval "${return_ok}";
1150 ########################################################################
1151 # clean_up ()
1153 # Do the final cleaning up before exiting; used by the trap calls.
1155 # defined above
1158 ########################################################################
1159 # diag (<text>*)
1161 # Print marked message to standard error; useful for debugging.
1163 # defined above
1166 ########################################################################
1167 landmark '4: dirname()*';
1168 ########################################################################
1170 #######################################################################
1171 # dirname_append (<dir> <name>)
1173 # Append `name' to `dir' with clean handling of `/'.
1175 # Arguments : 2
1176 # Output : the generated new directory name <dir>/<name>
1178 dirname_append()
1180 func_check dirname_append = 2 "$@";
1181 local _res;
1182 if is_empty "$1"; then
1183 error "dir_append(): first argument is empty.";
1185 if is_empty "$2"; then
1186 echo -n "$1";
1187 else
1188 dirname_chop "$1"/"$2";
1190 eval "${return_ok}";
1194 ########################################################################
1195 # dirname_chop (<name>)
1197 # Remove unnecessary slashes from directory name.
1199 # Argument: 1, a directory name.
1200 # Output: path without double, or trailing slashes.
1202 dirname_chop()
1204 func_check dirname_chop = 1 "$@";
1205 local _arg;
1206 local _res;
1207 local _sep;
1208 # replace all multiple slashes by a single slash `/'.
1209 _res="$(echo -n "$1" | sed -e '\|.*|s|///*|/|g')";
1210 case "${_res}" in
1211 ?*/)
1212 # remove trailing slash '/';
1213 echo -n "${_res}" | sed -e '\|.*|s|/$||';
1215 *) echo -n "${_res}"; ;;
1216 esac;
1217 eval "${return_ok}";
1221 ########################################################################
1222 # do_filearg (<filearg>)
1224 # Append the file, man-page, or standard input corresponding to the
1225 # argument to the temporary file. If this is compressed in the gzip
1226 # or Z format it is decompressed. A title element is generated.
1228 # Argument either:
1229 # - name of an existing files.
1230 # - `-' to represent standard input (several times allowed).
1231 # - `man:name.(section)' the man-page for `name' in `section'.
1232 # - `man:name.section' the man-page for `name' in `section'.
1233 # - `man:name' the man-page for `name' in the lowest `section'.
1234 # - `name.section' the man-page for `name' in `section'.
1235 # - `name' the man-page for `name' in the lowest `section'.
1236 # Globals :
1237 # $_TMP_STDIN, $_MAN_ENABLE, $_MAN_IS_SETUP, $_OPT_MAN
1239 # Output : none
1240 # Return : $_GOOD if found, ${_BAD} otherwise.
1242 do_filearg()
1244 func_check do_filearg = 1 "$@";
1245 local _filespec;
1246 local i;
1247 _filespec="$1";
1248 # store sequence into positional parameters
1249 case "${_filespec}" in
1251 eval "${return_good}";
1253 '-')
1254 register_file '-';
1255 eval "${return_good}";
1257 */*) # with directory part; so no man search
1258 set -- 'File';
1261 if obj _MAN_ENABLE is_yes; then
1262 if obj _MAN_FORCE is_yes; then
1263 set -- 'Manpage' 'File';
1264 else
1265 set -- 'File' 'Manpage';
1267 else
1268 set -- 'File';
1271 esac;
1272 for i in "$@"; do
1273 case "$i" in
1274 File)
1275 if test -f "${_filespec}"; then
1276 if test -r "${_filespec}"; then
1277 register_file "${_filespec}";
1278 eval "${return_good}";
1279 else
1280 echo2 "could not read \`${_filespec}'";
1281 eval "${return_bad}";
1283 else
1284 continue;
1287 Manpage) # parse filespec as man page
1288 if obj _MAN_IS_SETUP is_not_yes; then
1289 man_setup;
1291 if man_do_filespec "${_filespec}"; then
1292 eval "${return_good}";
1293 else
1294 continue;
1297 esac;
1298 done;
1299 eval "${return_bad}";
1300 } # do_filearg()
1303 ########################################################################
1304 # do_nothing ()
1306 # Dummy function.
1308 do_nothing()
1310 return "${_OK}";
1314 ########################################################################
1315 # echo2 (<text>*)
1317 # Print to standard error with final line break.
1319 # defined above
1322 ########################################################################
1323 # echo2n (<text>*)
1325 # Print to standard error without final line break.
1327 # defined above
1330 ########################################################################
1331 # error (<text>*)
1333 # Print error message and exit with error code.
1335 # defined above
1338 ########################################################################
1339 # func_check (<func_name> <rel_op> <nr_args> "$@")
1341 # Check number of arguments and register to _FUNC_STACK.
1343 # Arguments: >=3
1344 # <func_name>: name of the calling function.
1345 # <rel_op>: a relational operator: = != < > <= >=
1346 # <nr_args>: number of arguments to be checked against <operator>
1347 # "$@": the arguments of the calling function.
1349 # defined above
1351 #########################################################################
1352 # func_pop ()
1354 # Delete the top element from the function call stack.
1356 # defined above
1359 ########################################################################
1360 # func_push (<element>)
1362 # Store another element to function call stack.
1364 # defined above
1367 ########################################################################
1368 # func_stack_dump ()
1370 # Print the content of the stack.
1372 # defined above
1375 ########################################################################
1376 # get_first_essential (<arg>*)
1378 # Retrieve first non-empty argument.
1380 # Return : `1' if all arguments are empty, `0' if found.
1381 # Output : the retrieved non-empty argument.
1383 get_first_essential()
1385 func_check get_first_essential '>=' 0 "$@";
1386 local i;
1387 if is_equal "$#" 0; then
1388 eval "${return_ok}";
1390 for i in "$@"; do
1391 if obj i is_not_empty; then
1392 echo -n "$i";
1393 eval "${return_ok}";
1395 done;
1396 eval "${return_bad}";
1400 ########################################################################
1401 landmark '5: is_*()';
1402 ########################################################################
1404 ########################################################################
1405 # is_dir (<name>)
1407 # Test whether `name' is a directory.
1409 # Arguments : 1
1410 # Return : `0' if arg1 is a directory, `1' otherwise.
1412 is_dir()
1414 func_check is_dir = 1 "$@";
1415 if test -d "$1" && test -r "$1"; then
1416 eval "${return_yes}";
1418 eval "${return_no}";
1422 ########################################################################
1423 # is_empty (<string>)
1425 # Test whether `string' is empty.
1427 # Arguments : <=1
1428 # Return : `0' if arg1 is empty or does not exist, `1' otherwise.
1430 is_empty()
1432 func_check is_empty = 1 "$@";
1433 if test _"$1"_ = __; then
1434 eval "${return_yes}";
1436 eval "${return_no}";
1440 ########################################################################
1441 # is_equal (<string1> <string2>)
1443 # Test whether `string1' is equal to <string2>.
1445 # Arguments : 2
1446 # Return : `0' both arguments are equal strings, `1' otherwise.
1448 is_equal()
1450 func_check is_equal = 2 "$@";
1451 if test _"$1"_ = _"$2"_; then
1452 eval "${return_yes}";
1454 eval "${return_no}";
1458 ########################################################################
1459 # is_existing (<name>)
1461 # Test whether `name' is an existing file or directory.
1463 # Arguments : 1
1464 # Return : `0' if arg1 exists, `1' otherwise.
1466 is_existing()
1468 func_check is_existing = 1 "$@";
1469 if test -e "$1"; then
1470 eval "${return_yes}";
1472 eval "${return_no}";
1476 ########################################################################
1477 # is_file (<name>)
1479 # Test whether `name' is a readable file.
1481 # Arguments : 1
1482 # Return : `0' if arg1 is a readable file, `1' otherwise.
1484 is_file()
1486 func_check is_file = 1 "$@";
1487 if test -f "$1" && test -r "$1"; then
1488 eval "${return_yes}";
1490 eval "${return_no}";
1494 ########################################################################
1495 # is_non_empty_file (<file_name>)
1497 # Test whether `file_name' is a non-empty existing file.
1499 # Arguments : <=1
1500 # Return :
1501 # `0' if arg1 is a non-empty existing file
1502 # `1' otherwise
1504 is_non_empty_file()
1506 func_check is_non_empty_file = 1 "$@";
1507 if is_file "$1" && test -s "$1"; then
1508 eval "${return_yes}";
1510 eval "${return_no}";
1514 ########################################################################
1515 # is_not_dir (<name>)
1517 # Test whether `name' is not a readable directory.
1519 # Arguments : 1
1520 # Return : `0' if arg1 is a directory, `1' otherwise.
1522 is_not_dir()
1524 func_check is_not_dir = 1 "$@";
1525 if is_dir "$1"; then
1526 eval "${return_no}";
1528 eval "${return_yes}";
1532 ########################################################################
1533 # is_not_empty (<string>)
1535 # Test whether `string' is not empty.
1537 # Arguments : <=1
1538 # Return : `0' if arg1 exists and is not empty, `1' otherwise.
1540 is_not_empty()
1542 func_check is_not_empty = 1 "$@";
1543 if is_empty "$1"; then
1544 eval "${return_no}";
1546 eval "${return_yes}";
1550 ########################################################################
1551 # is_not_equal (<string1> <string2>)
1553 # Test whether `string1' differs from `string2'.
1555 # Arguments : 2
1557 is_not_equal()
1559 func_check is_not_equal = 2 "$@";
1560 if is_equal "$1" "$2"; then
1561 eval "${return_no}";
1563 eval "${return_yes}";
1567 ########################################################################
1568 # is_not_file (<filename>)
1570 # Test whether `name' is a not readable file.
1572 # Arguments : >=1 (empty allowed), more args are ignored
1574 is_not_file()
1576 func_check is_not_file '>=' 1 "$@";
1577 if is_file "$1"; then
1578 eval "${return_no}";
1580 eval "${return_yes}";
1584 ########################################################################
1585 # is_not_prog (<name>)
1587 # Verify that arg is a not program in $PATH.
1589 # Arguments : >=1 (empty allowed)
1590 # more args are ignored, this allows to specify progs with arguments
1592 is_not_prog()
1594 func_check is_not_prog '>=' 1 "$@";
1595 if where "$1" >/dev/null; then
1596 eval "${return_no}";
1598 eval "${return_yes}";
1602 ########################################################################
1603 # is_not_writable (<name>)
1605 # Test whether `name' is a not a writable file or directory.
1607 # Arguments : >=1 (empty allowed), more args are ignored
1609 is_not_writable()
1611 func_check is_not_writable '>=' 1 "$@";
1612 if is_writable "$1"; then
1613 eval "${return_no}";
1615 eval "${return_yes}";
1619 ########################################################################
1620 # is_not_yes (<string>)
1622 # Test whether `string' is not "yes".
1624 # Arguments : 1
1626 is_not_yes()
1628 func_check is_not_yes = 1 "$@";
1629 if is_yes "$1"; then
1630 eval "${return_no}";
1632 eval "${return_yes}";
1636 ########################################################################
1637 # is_prog (<name>)
1639 # Determine whether arg is a program in $PATH
1641 # Arguments : >=0 (empty allowed)
1642 # more args are ignored, this allows to specify progs with arguments
1644 is_prog()
1646 func_check is_prog '>=' 0 "$@";
1647 case "$#" in
1649 eval "${return_no}";
1652 if where "$1" >/dev/null; then
1653 eval "${return_yes}";
1656 esac
1657 eval "${return_no}";
1661 ########################################################################
1662 # is_writable (<name>)
1664 # Test whether `name' is a writable file or directory.
1666 # Arguments : >=1 (empty allowed), more args are ignored
1668 is_writable()
1670 func_check is_writable '>=' 1 "$@";
1671 if test -r "$1"; then
1672 if test -w "$1"; then
1673 eval "${return_yes}";
1676 eval "${return_no}";
1680 ########################################################################
1681 # is_yes (<string>)
1683 # Test whether `string' has value "yes".
1685 # Arguments : <=1
1686 # Return : `0' if arg1 is `yes', `1' otherwise.
1688 is_yes()
1690 func_check is_yes = 1 "$@";
1691 if is_equal "$1" 'yes'; then
1692 eval "${return_yes}";
1694 eval "${return_no}";
1698 ########################################################################
1699 # landmark ()
1701 # Print debugging information on standard error if $_DEBUG_LM is `yes'.
1703 # Globals: $_DEBUG_LM
1705 # Defined in section `Debugging functions'.
1708 ########################################################################
1709 # leave ()
1711 # Clean exit without an error.
1713 leave()
1715 clean_up;
1716 exit "${_OK}";
1720 ########################################################################
1721 landmark '6: list_*()';
1722 ########################################################################
1724 # `list' is an object class that represents an array or list. Its
1725 # data consists of space-separated single-quoted elements. So a list
1726 # has the form "'first' 'second' '...' 'last'". See list_append() for
1727 # more details on the list structure. The array elements of `list'
1728 # can be get by `set -- $list`.
1731 ########################################################################
1732 # list_append (<list> <element>...)
1734 # Arguments: >=2
1735 # <list>: a variable name for a list of single-quoted elements
1736 # <element>: some sequence of characters.
1737 # Output: none, but $<list> is set to
1738 # if <list> is empty: "'<element>' '...'"
1739 # otherwise: "$list '<element>' ..."
1741 list_append()
1743 func_check list_append '>=' 2 "$@";
1744 local _element;
1745 local _list;
1746 local _name;
1747 _name="$1";
1748 eval _list='"${'$1'}"';
1749 shift;
1750 for s in "$@"; do
1751 case "$s" in
1752 *\'*)
1753 # escape each single quote by replacing each
1754 # "'" (squote) by "'\''" (squote bslash squote squote);
1755 # note that the backslash must be doubled in the following `sed'
1756 _element="$(echo -n "$s" | sed -e 's/'"${_SQUOTE}"'/&\\&&/g')";
1758 '')
1759 _element="";
1762 _element="$s";
1764 esac;
1765 if obj _list is_empty; then
1766 _list="'${_element}'";
1767 else
1768 _list="${_list} '${_element}'";
1770 done;
1771 eval "${_name}"='"${_list}"';
1772 eval "${return_ok}";
1776 ########################################################################
1777 # list_from_cmdline (<pre_name_of_opt_lists> [<cmdline_arg>...])
1779 # Transform command line arguments into a normalized form.
1781 # Options, option arguments, and file parameters are identified and
1782 # output each as a single-quoted argument of its own. Options and
1783 # file parameters are separated by a '--' argument.
1785 # Arguments: >=1
1786 # <pre_name>: common part of a set of 4 environment variable names:
1787 # $<pre_name>_SHORT_NA: list of short options without an arg.
1788 # $<pre_name>_SHORT_ARG: list of short options that have an arg.
1789 # $<pre_name>_LONG_NA: list of long options without an arg.
1790 # $<pre_name>_LONG_ARG: list of long options that have an arg.
1791 # <cmdline_arg>...: the arguments from a command line, such as "$@",
1792 # the content of a variable, or direct arguments.
1794 # Output: ['-[-]opt' ['optarg']]... '--' ['filename']...
1796 # Example:
1797 # list_from_cmdline PRE 'a b' 'c' '' 'long' -a f1 -bcarg --long=larg f2
1798 # If $PRE_SHORT_NA, $PRE_SHORT_ARG, $PRE_LONG_NA, and $PRE_LONG_ARG are
1799 # none-empty option lists, this will result in printing:
1800 # '-a' '-b' '-c' 'arg' '--long' 'larg' '--' 'f1' 'f2'
1802 # Use this function in the following way:
1803 # eval set -- "$(args_norm PRE_NAME "$@")";
1804 # while test "$1" != '--'; do
1805 # case "$1" in
1806 # ...
1807 # esac;
1808 # shift;
1809 # done;
1810 # shift; #skip '--'
1811 # # all positional parameters ("$@") left are file name parameters.
1813 list_from_cmdline()
1815 func_check list_from_cmdline '>=' 1 "$@";
1816 local _fparams;
1817 local _fn;
1818 local _short_a;
1819 local _short_n;
1820 local _long_a;
1821 local _long_n;
1822 local _result;
1823 _short_n="$(obj_data "$1"_SHORT_NA)"; # short options, no argument
1824 _short_a="$(obj_data "$1"_SHORT_ARG)"; # short options, with argument
1825 _long_n="$(obj_data "$1"_LONG_NA)"; # long options, no argument
1826 _long_a="$(obj_data "$1"_LONG_ARG)"; # long options, with argument
1827 if obj _short_n is_empty; then
1828 error 'list_from_cmdline(): no $'"$1"'_SHORT_NA options.';
1830 if obj _short_a is_empty; then
1831 error 'list_from_cmdline(): no $'"$1"'_SHORT_ARG options.';
1833 if obj _long_n is_empty; then
1834 error 'list_from_cmdline(): no $'"$1"'_LONG_NA options.';
1836 if obj _long_a is_empty; then
1837 error 'list_from_cmdline(): no $'"$1"'_LONG_ARG options.';
1839 shift;
1840 _fn='list_from_cmdline():'; # for error messages
1841 if is_equal "$#" 0; then
1842 echo -n "'--'";
1843 eval "${return_ok}";
1845 _fparams='';
1846 _result='';
1847 while test "$#" -ge 1; do
1848 _arg="$1";
1849 shift;
1850 case "$_arg" in
1851 --) break; ;;
1852 --?*)
1853 # delete leading '--';
1854 _opt="$(echo -n "${_arg}" | sed -e 's/^..//')";
1855 if list_has _long_n "${_opt}"; then
1856 # long option, no argument
1857 list_append _result "--${_opt}";
1858 continue;
1860 # test on `--opt=arg'
1861 if string_contains "${_opt}" '='; then
1862 # extract option by deleting from the first '=' to the end
1863 _lopt="$(echo -n "${_opt}" | sed -e 's/=.*$//')";
1864 if list_has _long_a "${_lopt}"; then
1865 # get the option argument by deleting up to first `='
1866 _optarg="$(echo -n "${_opt}" | sed -e 's/^[^=]*=//')";
1867 list_append _result "--${_lopt}" "${_optarg}";
1868 continue;
1871 if list_has _long_a "${_opt}"; then
1872 # long option with argument
1873 if test "$#" -le 0; then
1874 error "${_fn} no argument for option --${_opt}."
1876 list_append _result "--${_opt}" "$1";
1877 shift;
1878 continue;
1880 error "${_fn} --${_opt} is not an option."
1882 -?*) # short option (cluster)
1883 # delete leading `-';
1884 _rest="$(echo -n "${_arg}" | sed -e 's/^-//')";
1885 while obj _rest is_not_empty; do
1886 # get next short option from cluster (first char of $_rest)
1887 _optchar="$(echo -n "${_rest}" | sed -e 's/^\(.\).*$/\1/')";
1888 # remove first character from ${_rest};
1889 _rest="$(echo -n "${_rest}" | sed -e 's/^.//')";
1890 if list_has _short_n "${_optchar}"; then
1891 list_append _result "-${_optchar}";
1892 continue;
1893 elif list_has _short_a "${_optchar}"; then
1894 if obj _rest is_empty; then
1895 if test "$#" -ge 1; then
1896 list_append _result "-${_optchar}" "$1";
1897 shift;
1898 continue;
1899 else
1900 error \
1901 "${_fn}"' no argument for option -'"${_optchar}."
1903 else # rest is the argument
1904 list_append _result "-${_optchar}" "${_rest}";
1905 _rest='';
1906 continue;
1908 else
1909 error "${_fn} unknown option -${_optchar}."
1911 done;
1914 # Here, $_arg is not an option, so a file parameter.
1915 list_append _fparams "${_arg}";
1917 # Ignore the strange option handling of $POSIXLY_CORRECT to
1918 # end option parsing after the first file name argument. To
1919 # reuse it, do a `break' here if $POSIXLY_CORRECT is
1920 # non-empty.
1922 esac;
1923 done;
1924 list_append _result '--';
1925 if obj _fparams is_not_empty; then
1926 _result="${_result} ${_fparams}";
1928 if test "$#" -gt 0; then
1929 list_append _result "$@";
1931 echo -n "$_result";
1932 eval "${return_ok}";
1933 } # list_from_cmdline()
1936 ########################################################################
1937 # list_from_split (<string> <separator>)
1939 # In <string>, escape all white space characters and replace each
1940 # <separator> by space.
1942 # Arguments: 2: a <string> that is to be split into parts divided by
1943 # <separator>
1944 # Output: the resulting list string
1946 list_from_split()
1948 func_check list_from_split = 2 "$@";
1949 local _s;
1951 # precede each space or tab by a backslash `\' (doubled for `sed')
1952 _s="$(echo -n "$1" | sed -e 's/\(['"${_SPACE}${_TAB}"']\)/\\\1/g')";
1954 # replace split character of string by the list separator ` ' (space).
1955 case "$2" in
1956 /) # cannot use normal `sed' separator
1957 echo -n "${_s}" | sed -e '\|.*|s|'"$2"'| |g';
1959 ?) # use normal `sed' separator
1960 echo -n "${_s}" | sed -e 's/'"$2"'/ /g';
1962 ??*)
1963 error 'list_from_split(): separator must be a single character.';
1965 esac;
1966 eval "${return_ok}";
1970 ########################################################################
1971 # list_get (<list>)
1973 # Check whether <list> is a space-separated list of '-quoted elements.
1975 # If the test fails an error is raised.
1976 # If the test succeeds the argument is echoed.
1978 # Testing criteria:
1979 # A list has the form "'first' 'second' '...' 'last'". So it has a
1980 # leading and a final quote and the elements are separated by "' '"
1981 # constructs. If these are all removed there should not be any
1982 # unescaped single-quotes left. Watch out for escaped single
1983 # quotes; they have the form '\'' (sq bs sq sq).
1985 # Arguments: 1
1986 # Output: the argument <list> unchanged, if the check succeeded.
1988 list_get()
1990 func_check list_get = 1 "$@";
1991 local _list;
1992 eval _list='"${'$1'}"';
1993 # remove leading and final space characters
1994 _list="$(echo -n "${_list}" | \
1995 sed -e 's/^['"${_SPACE}${_TAB}"']*//' | \
1996 sed -e 's/['"${_SPACE}${_TAB}"']*$//')";
1997 case "${_list}" in
1999 eval "${return_ok}";
2001 \'*\')
2002 echo -n "${_list}";
2003 eval "${return_ok}";
2006 error "list_get(): bad list: $1"
2008 esac;
2009 eval "${return_ok}";
2013 ########################################################################
2014 # list_has (<var_name> <element>)
2016 # Arguments: 2
2017 # <var_name>: a variable name for a list of single-quoted elements
2018 # <element>: some sequence of characters.
2019 # Output:
2020 # if <list> is empty: "'<element>' '...'"
2021 # otherwise: "list '<element>' ..."
2023 list_has()
2025 func_check list_has = 2 "$@";
2026 eval _list='"${'$1'}"';
2027 if obj _list is_empty; then
2028 eval "${return_no}";
2030 _element="$2";
2031 case "$2" in
2032 \'*\') _element="$2"; ;;
2033 *) _element="'$2'"; ;;
2034 esac;
2035 if string_contains "${_list}" "${_element}"; then
2036 eval "${return_yes}";
2037 else
2038 eval "${return_no}";
2040 eval "${return_ok}";
2044 ########################################################################
2045 # list_has_not (<list> <element>)
2047 # Arguments: 2
2048 # <list>: a space-separated list of single-quoted elements.
2049 # <element>: some sequence of characters.
2050 # Output:
2051 # if <list> is empty: "'<element>' '...'"
2052 # otherwise: "<list> '<element>' ..."
2054 list_has_not()
2056 func_check list_has_not = 2 "$@";
2057 eval _list='"${'$1'}"';
2058 if obj _list is_empty; then
2059 eval "${return_yes}";
2061 _element="$2";
2062 case "$2" in
2063 \'*\') _element="$2"; ;;
2064 *) _element="'$2'"; ;;
2065 esac;
2066 if string_contains "${_list}" "${_element}"; then
2067 eval "${return_no}";
2068 else
2069 eval "${return_yes}";
2071 eval "${return_ok}";
2075 ########################################################################
2076 landmark '7: man_*()';
2077 ########################################################################
2079 ########################################################################
2080 # man_do_filespec (<filespec>)
2082 # Print suitable man page(s) for filespec to $_TMP_CAT.
2084 # Arguments : 2
2085 # <filespec>: argument of the form `man:name.section', `man:name',
2086 # `man:name(section)', `name.section', `name'.
2088 # Globals : $_OPT_ALL
2090 # Output : none.
2091 # Return : `0' if man page was found, `1' else.
2093 # Only called from do_fileargs(), checks on $MANPATH and
2094 # $_MAN_ENABLE are assumed.
2096 man_do_filespec()
2098 func_check man_do_filespec = 1 "$@";
2099 local _got_one;
2100 local _name;
2101 local _prevsec;
2102 local _res;
2103 local _section;
2104 local _spec;
2105 local _string;
2106 local s;
2107 if obj _MAN_PATH is_empty; then
2108 eval "${return_bad}";
2110 if is_empty "$1"; then
2111 eval "${return_bad}";
2113 _spec="$1";
2114 _name='';
2115 _section='';
2116 case "${_spec}" in
2117 */*) # not a man spec when it contains '/'
2118 eval "${return_bad}";
2120 man:?*\(?*\)) # man:name(section)
2121 _name="$(echo -n "${_spec}" \
2122 | sed -e 's/^man:\(..*\)(\(..*\))$/\1/')";
2123 _section="$(echo -n "${_spec}" \
2124 | sed -e 's/^man:\(..*\)(\(..*\))$/\2/')";
2126 man:?*.[0-9on]) # man:name.section
2127 _name="$(echo -n "${_spec}" \
2128 | sed -e 's/^man:\(..*\)\..$/\1/')";
2129 _section="$(echo -n "${_spec}" \
2130 | sed -e 's/^.*\(.\)$/\1/')";
2132 man:?*) # man:name
2133 _name="$(echo -n "${_spec}" | sed -e 's/^man://')";
2135 ?*\(?*\)) # name(section)
2136 _name="$(echo -n "${_spec}" \
2137 | sed -e 's/^\(..*\)(\(..*\))$/\1/')";
2138 _section="$(echo -n "${_spec}" \
2139 | sed -e 's/^\(..*\)(\(..*\))$/\2/')";
2141 ?*.[0-9on]) # name.section
2142 _name="$(echo -n "${_spec}" \
2143 | sed -e 's/^\(..*\)\..$/\1/')";
2144 _section="$(echo -n "${_spec}" \
2145 | sed -e 's/^.*\(.\)$/\1/')";
2148 _name="${_filespec}";
2150 esac;
2151 if obj _name is_empty; then
2152 eval "${return_bad}";
2154 _got_one='no';
2155 if obj _section is_empty; then
2156 eval set -- "${_MAN_AUTO_SEC}";
2157 for s in "$@"; do
2158 if man_search_section "${_name}" "$s"; then # found
2159 if obj _MAN_ALL is_yes; then
2160 _got_one='yes';
2161 else
2162 eval "${return_good}";
2165 done;
2166 else
2167 if man_search_section "${_name}" "${_section}"; then
2168 eval "${return_good}";
2169 else
2170 eval "${return_bad}";
2173 if obj _MAN_ALL is_yes && is_yes "${_got_one}"; then
2174 eval "${return_good}";
2176 eval "${return_bad}";
2177 } # man_do_filespec()
2180 ########################################################################
2181 # man_register_file (<file> <name> [<section>])
2183 # Write a found man page file and register the title element.
2185 # Arguments: 1, 2, or 3; maybe empty
2186 # Output: none
2188 man_register_file()
2190 func_check man_register_file '>=' 2 "$@";
2191 case "$#" in
2192 2|3) do_nothing; ;;
2194 error "man_register_file() expects 2 or 3 arguments.";
2196 esac;
2197 if is_empty "$1"; then
2198 error 'man_register_file(): file name is empty';
2200 to_tmp "$1";
2201 case "$#" in
2203 register_title "man:$2";
2204 eval "${return_ok}";
2207 register_title "$2.$3";
2208 eval "${return_ok}";
2210 esac;
2211 eval "${return_ok}";
2215 ########################################################################
2216 # man_search_section (<name> <section>)
2218 # Retrieve man pages.
2220 # Arguments : 2
2221 # Globals : $_MAN_PATH, $_MAN_EXT
2222 # Return : 0 if found, 1 otherwise
2224 man_search_section()
2226 func_check man_search_section = 2 "$@";
2227 local _dir;
2228 local _ext;
2229 local _got_one;
2230 local _name;
2231 local _prefix
2232 local _section;
2233 local d;
2234 local f;
2235 if obj _MAN_PATH is_empty; then
2236 eval "${return_bad}";
2238 if is_empty "$1"; then
2239 eval "${return_bad}";
2241 if is_empty "$2"; then
2242 eval "${return_bad}";
2244 _name="$1";
2245 _section="$2";
2246 eval set -- "$(path_split "${_MAN_PATH}")";
2247 _got_one='no';
2248 if obj _MAN_EXT is_empty; then
2249 for d in "$@"; do
2250 _dir="$(dirname_append "$d" "man${_section}")";
2251 if obj _dir is_dir; then
2252 _prefix="$(dirname_append "${_dir}" "${_name}.${_section}")";
2253 for f in $(echo -n ${_prefix}*); do
2254 if obj f is_file; then
2255 if is_yes "${_got_one}"; then
2256 register_file "$f";
2257 elif obj _MAN_ALL is_yes; then
2258 man_register_file "$f" "${_name}";
2259 else
2260 man_register_file "$f" "${_name}" "${_section}";
2261 eval "${return_good}";
2263 _got_one='yes';
2265 done;
2267 done;
2268 else
2269 _ext="${_MAN_EXT}";
2270 # check for directory name having trailing extension
2271 for d in "$@"; do
2272 _dir="$(dirname_append $d man${_section}${_ext})";
2273 if obj _dir is_dir; then
2274 _prefix="$(dirname_append "${_dir}" "${_name}.${_section}")";
2275 for f in ${_prefix}*; do
2276 if obj f is_file; then
2277 if is_yes "${_got_one}"; then
2278 register_file "$f";
2279 elif obj _MAN_ALL is_yes; then
2280 man_register_file "$f" "${_name}";
2281 else
2282 man_register_file "$f" "${_name}" "${_section}";
2283 eval "${return_good}";
2285 _got_one='yes';
2287 done;
2289 done;
2290 # check for files with extension in directories without extension
2291 for d in "$@"; do
2292 _dir="$(dirname_append "$d" "man${_section}")";
2293 if obj _dir is_dir; then
2294 _prefix="$(dirname_append "${_dir}" \
2295 "${_name}.${_section}${_ext}")";
2296 for f in ${_prefix}*; do
2297 if obj f is_file; then
2298 if is_yes "${_got_one}"; then
2299 register_file "$f";
2300 elif obj _MAN_ALL is_yes; then
2301 man_register_file "$f" "${_name}";
2302 else
2303 man_register_file "$f" "${_name}" "${_section}";
2304 eval "${return_good}";
2306 _got_one='yes';
2308 done;
2310 done;
2312 if obj _MAN_ALL is_yes && is_yes "${_got_one}"; then
2313 eval "${return_good}";
2315 eval "${return_bad}";
2316 } # man_search_section()
2319 ########################################################################
2320 # man_setup ()
2322 # Setup the variables $_MAN_* needed for man page searching.
2324 # Globals:
2325 # in: $_OPT_*, $_MANOPT_*, $LANG, $LC_MESSAGES, $LC_ALL,
2326 # $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM, $MANOPT.
2327 # out: $_MAN_PATH, $_MAN_LANG, $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2,
2328 # $_MAN_SEC, $_MAN_ALL
2329 # in/out: $_MAN_ENABLE
2331 # The precedence for the variables related to `man' is that of GNU
2332 # `man', i.e.
2334 # $LANG; overridden by
2335 # $LC_MESSAGES; overridden by
2336 # $LC_ALL; this has the same precedence as
2337 # $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM; overridden by
2338 # $MANOPT; overridden by
2339 # the groffer command line options.
2341 man_setup()
2343 func_check main_man_setup = 0 "$@";
2344 local _lang;
2346 if obj _MAN_IS_SETUP is_yes; then
2347 eval "${return_ok}";
2349 _MAN_IS_SETUP='yes';
2351 if obj _MAN_ENABLE is_not_yes; then
2352 eval "${return_ok}";
2355 # determine basic path for man pages
2356 _MAN_PATH="$(get_first_essential \
2357 "${_OPT_MANPATH}" "${_MANOPT_PATH}" "${MANPATH}")";
2358 if obj _MAN_PATH is_empty; then
2359 manpath_set_from_path;
2360 else
2361 _MAN_PATH="$(path_clean "${_MAN_PATH}")";
2363 if obj _MAN_PATH is_empty; then
2364 if is_prog 'manpath'; then
2365 _MAN_PATH="$(manpath 2>/dev/null)"; # not always available
2368 if obj _MAN_PATH is_empty; then
2369 _MAN_ENABLE="no";
2370 eval "${return_ok}";
2373 _MAN_ALL="$(get_first_essential "${_OPT_ALL}" "${_MANOPT_ALL}")";
2374 if obj _MAN_ALL is_empty; then
2375 _MAN_ALL='no';
2378 _MAN_SYS="$(get_first_essential \
2379 "${_OPT_SYSTEMS}" "${_MANOPT_SYS}" "${SYSTEM}")";
2380 _lang="$(get_first_essential \
2381 "${_OPT_LANG}" "${LC_ALL}" "${LC_MESSAGES}" "${LANG}")";
2382 case "${_lang}" in
2383 C|POSIX)
2384 _MAN_LANG="";
2385 _MAN_LANG2="";
2388 _MAN_LANG="${_lang}";
2389 _MAN_LANG2="";
2392 _MAN_LANG="${_lang}";
2393 # get first two characters of $_lang
2394 _MAN_LANG2="$(echo -n "${_lang}" | sed -e 's/^\(..\).*$/\1/')";
2396 esac;
2397 # from now on, use only $_LANG, forget about $_OPT_LANG, $LC_*.
2399 manpath_add_lang_sys; # this is very slow
2401 _MAN_SEC="$(get_first_essential \
2402 "${_OPT_SECT}" "${_MANOPT_SEC}" "${MANSEC}")";
2403 if obj _MAN_PATH is_empty; then
2404 _MAN_ENABLE="no";
2405 eval "${return_ok}";
2408 _MAN_EXT="$(get_first_essential \
2409 "${_OPT_EXTENSION}" "${_MANOPT_EXTENSION}")";
2410 eval "${return_ok}";
2411 } # man_setup()
2414 ########################################################################
2415 landmark '8: manpath_*()';
2416 ########################################################################
2418 ########################################################################
2419 # manpath_add_lang_sys ()
2421 # Add language and operating system specific directories to man path.
2423 # Arguments : 0
2424 # Output : none
2425 # Globals:
2426 # in: $_MAN_SYS: has the form `os1,os2,...', a comma separated
2427 # list of names of operating systems.
2428 # $_MAN_LANG and $_MAN_LANG2: each a single name
2429 # in/out: $_MAN_PATH: has the form `dir1:dir2:...', a colon
2430 # separated list of directories.
2432 manpath_add_lang_sys()
2434 func_check manpath_add_lang_sys = 0 "$@";
2435 local p;
2436 local _mp;
2437 if obj _MAN_PATH is_empty; then
2438 eval "${return_ok}";
2440 # twice test both sys and lang
2441 eval set -- "$(path_split "${_MAN_PATH}")";
2442 _mp='';
2443 for p in "$@"; do # loop on man path directories
2444 _mp="$(_manpath_add_lang_sys_single "${_mp}" "$p")";
2445 done;
2446 eval set -- "$(path_split "${_mp}")";
2447 for p in "$@"; do # loop on man path directories
2448 _mp="$(_manpath_add_lang_sys_single "${_mp}" "$p")";
2449 done;
2450 _MAN_PATH="$(path_chop "${_mp}")";
2451 eval "${return_ok}";
2455 _manpath_add_lang_sys_single()
2457 # To the directory in $1 append existing sys/lang subdirectories
2458 # Function is necessary to split the OS list.
2460 # globals: in: $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2
2461 # argument: 2: `man_path' and `dir'
2462 # output: colon-separated path of the retrieved subdirectories
2464 func_check _manpath_add_lang_sys_single = 2 "$@";
2465 local d;
2466 _res="$1";
2467 _parent="$2";
2468 eval set -- "$(list_from_split "${_MAN_SYS}" ',')";
2469 for d in "$@" "${_MAN_LANG}" "${_MAN_LANG2}"; do
2470 _dir="$(dirname_append "${_parent}" "$d")";
2471 if obj _res path_not_contains "${_dir}" && obj _dir is_dir; then
2472 _res="${_res}:${_dir}";
2474 done;
2475 if path_not_contains "${_res}" "${_parent}"; then
2476 _res="${_res}:${_parent}";
2478 path_chop "${_res}";
2481 # end manpath_add_lang_sys ()
2484 ########################################################################
2485 # manpath_set_from_path ()
2487 # Determine basic search path for man pages from $PATH.
2489 # Return: `0' if a valid man path was retrieved.
2490 # Output: none
2491 # Globals:
2492 # in: $PATH
2493 # out: $_MAN_PATH
2495 manpath_set_from_path()
2497 func_check manpath_set_from_path = 0 "$@";
2498 local _base;
2499 local _mandir;
2500 local _manpath;
2501 local d;
2502 local e;
2503 _manpath='';
2505 # get a basic man path from $PATH
2506 if obj PATH is_not_empty; then
2507 eval set -- "$(path_split "${PATH}")";
2508 for d in "$@"; do
2509 # delete the final `/bin' part
2510 _base="$(echo -n "$d" | sed -e '\|.*|s|//*bin/*$||')";
2511 for e in /share/man /man; do
2512 _mandir="${_base}$e";
2513 if test -d "${_mandir}" && test -r "${_mandir}"; then
2514 _manpath="${_manpath}:${_mandir}";
2516 done;
2517 done;
2520 # append some default directories
2521 for d in /usr/local/share/man /usr/local/man \
2522 /usr/share/man /usr/man \
2523 /usr/X11R6/man /usr/openwin/man \
2524 /opt/share/man /opt/man \
2525 /opt/gnome/man /opt/kde/man; do
2526 if obj _manpath path_not_contains "$d" && obj d is_dir; then
2527 _manpath="${_manpath}:$d";
2529 done;
2531 _MAN_PATH="${_manpath}";
2532 eval "${return_ok}";
2533 } # manpath_set_from_path()
2536 ########################################################################
2537 landmark '9: obj_*()';
2538 ########################################################################
2540 ########################################################################
2541 # obj (<object> <call_name> <arg>...)
2543 # This works like a method (object function) call for an object.
2544 # Run "<call_name> $<object> <arg> ...".
2546 # The first argument represents an object whose data is given as first
2547 # argument to <call_name>().
2549 # Argument: >=2
2550 # <object>: variable name
2551 # <call_name>: a program or function name
2553 obj()
2555 func_check obj '>=' 2 "$@";
2556 local func;
2557 local var;
2558 if is_empty "$2"; then
2559 error "obj(): function name is empty."
2560 else
2561 func="$2";
2563 eval arg1='"${'$1'}"';
2564 shift;
2565 shift;
2566 eval "${func}"' "${arg1}" "$@"';
2570 ########################################################################
2571 # obj_data (<object>)
2573 # Print the data of <object>, i.e. the content of $<object>.
2574 # For possible later extensions.
2576 # Arguments: 1
2577 # <object>: a variable name
2578 # Output: the data of <object>
2580 obj_data()
2582 func_check obj '=' 1 "$@";
2583 if is_empty "$1"; then
2584 error "obj_data(): object name is empty."
2586 eval echo -n '"${'$1'}"';
2590 ########################################################################
2591 # obj_from_output (<object> <call_name> <arg>...)
2593 # Run '$<object>="$(<call_name> <arg>...)"' to set the result of a
2594 # function call to a global variable.
2596 # Arguments: >=2
2597 # <object>: a variable name
2598 # <call_name>: the name of a function or program
2599 # <arg>: optional argument to <call_name>
2600 # Output: none
2602 obj_from_output()
2604 func_check obj_from_output '>=' 2 "$@";
2605 local result_name;
2606 if is_empty "$1"; then
2607 error "res(): variable name is empty.";
2608 elif is_empty "$2"; then
2609 error "res(): function name is empty."
2610 else
2611 result_name="$1";
2613 shift;
2614 eval "${result_name}"'="$('"$@"')"';
2618 ########################################################################
2619 # obj_set (<object> <data>)
2621 # Set the data of <object>, i.e. call "$<object>=<data>".
2623 # Arguments: 2
2624 # <object>: a variable name
2625 # <data>: a string
2626 # Output:: none
2628 obj_set()
2630 func_check obj_set '=' 2 "$@";
2631 if is_empty "$1"; then
2632 error "obj_set(): object name is empty."
2634 eval "$1"='"$2"';
2638 ########################################################################
2639 # path_chop (<path>)
2641 # Remove unnecessary colons from path.
2643 # Argument: 1, a colon separated path.
2644 # Output: path without leading, double, or trailing colons.
2646 path_chop()
2648 func_check path_chop = 1 "$@";
2649 local _res;
2651 # replace multiple colons by a single colon `:'
2652 # remove leading and trailing colons
2653 echo -n "$1" | sed -e 's/:::*/:/g' |
2654 sed -e 's/^:*//' |
2655 sed -e 's/:*$//';
2656 eval "${return_ok}";
2660 ########################################################################
2661 # path_clean (<path>)
2663 # Remove non-existing directories from a colon-separated list.
2665 # Argument: 1, a colon separated path.
2666 # Output: colon-separated list of existing directories.
2668 path_clean()
2670 func_check path_clean = 1 "$@";
2671 local _arg;
2672 local _dir;
2673 local _res;
2674 local i;
2675 if is_not_equal "$#" 1; then
2676 error 'path_clean() needs 1 argument.';
2678 _arg="$1";
2679 eval set -- "$(path_split "${_arg}")";
2680 _res="";
2681 for i in "$@"; do
2682 if obj i is_not_empty \
2683 && obj _res path_not_contains "$i" \
2684 && obj i is_dir;
2685 then
2686 case "$i" in
2687 ?*/) _res="${_res}$(dirname_chop "$i")"; ;;
2688 *) _res="${_res}:$i";
2689 esac;
2691 done;
2692 if path_chop "${_res}"; then
2693 eval "${return_ok}";
2694 else
2695 eval "${return_badk}";
2700 ########################################################################
2701 # path_contains (<path> <dir>)
2703 # Test whether `dir' is contained in `path', a list separated by `:'.
2705 # Arguments : 2 arguments.
2706 # Return : `0' if arg2 is substring of arg1, `1' otherwise.
2708 path_contains()
2710 func_check path_contains = 2 "$@";
2711 case ":$1:" in
2712 *":$2:"*)
2713 eval "${return_yes}";
2716 eval "${return_no}";
2718 esac;
2719 eval "${return_ok}";
2723 ########################################################################
2724 # path_not_contains (<path> <dir>)
2726 # Test whether `dir' is not contained in colon separated `path'.
2728 # Arguments : 2 arguments.
2730 path_not_contains()
2732 func_check path_not_contains = 2 "$@";
2733 if path_contains "$1" "$2"; then
2734 eval "${return_no}";
2735 else
2736 eval "${return_yes}";
2738 eval "${return_ok}";
2742 ########################################################################
2743 # path_split (<path>)
2745 # In `path' escape white space and replace each colon by a space.
2747 # Arguments: 1: a colon-separated path
2748 # Output: the resulting list, process with `eval set --'
2750 path_split()
2752 func_check path_split = 1 "$@";
2753 list_from_split "$1" ':';
2754 eval "${return_ok}";
2758 ########################################################################
2759 landmark '10: register_*()';
2760 ########################################################################
2762 ########################################################################
2763 # register_file (<filename>)
2765 # Write a found file and register the title element.
2767 # Arguments: 1: a file name
2768 # Output: none
2770 register_file()
2772 func_check register_file = 1 "$@";
2773 if is_empty "$1"; then
2774 error 'register_file(): file name is empty';
2776 if is_equal "$1" '-'; then
2777 to_tmp "${_TMP_STDIN}";
2778 register_title '-';
2779 else
2780 to_tmp "$1";
2781 register_title "$(base_name "$1")";
2783 eval "${return_ok}";
2787 ########################################################################
2788 # register_title (<filespec>)
2790 # Create title element from <filespec> and append to $_REGISTERED_TITLE
2792 # Globals: $_REGISTERED_TITLE (rw)
2794 register_title()
2796 func_check register_title = 1 "$@";
2797 local _title;
2798 if is_empty "$1"; then
2799 eval "${return_ok}";
2801 _title="$(base_name "$1")"; # remove directory part
2803 # remove extension `.gz'
2804 _title="$(echo -n "${_title}" | sed -e 's/\.gz$//')";
2805 # remove extension `.Z'
2806 _title="$(echo -n "${_title}" | sed -e 's/\.Z$//')";
2808 if obj _title is_empty; then
2809 eval "${return_ok}";
2811 _REGISTERED_TITLE="${_REGISTERED_TITLE} ${_title}";
2812 eval "${return_ok}";
2816 ########################################################################
2817 # reset ()
2819 # Reset the variables that can be affected by options to their default.
2822 # Defined in section `Preset' after the rudimentary shell tests.
2825 ########################################################################
2826 # save_stdin ()
2828 # Store standard input to temporary file (with decompression).
2830 if obj _HAS_COMPRESSION is_yes; then
2831 save_stdin()
2833 local _f;
2834 func_check save_stdin = 0 "$@";
2835 _f="${_TMP_DIR}"/INPUT;
2836 cat >"${_f}";
2837 catz "${_f}" >"${_TMP_STDIN}";
2838 rm -f "${_f}";
2839 eval "${return_ok}";
2841 else
2842 save_stdin()
2844 func_check save_stdin = 0 "$@";
2845 cat >"${_TMP_STDIN}";
2846 eval "${return_ok}";
2851 ########################################################################
2852 landmark '11: stack_*()';
2853 ########################################################################
2855 ########################################################################
2856 # string_contains (<string> <part>)
2858 # Test whether `part' is contained in `string'.
2860 # Arguments : 2 text arguments.
2861 # Return : `0' if arg2 is substring of arg1, `1' otherwise.
2863 string_contains()
2865 func_check string_contains = 2 "$@";
2866 case "$1" in
2867 *"$2"*)
2868 eval "${return_yes}";
2871 eval "${return_no}";
2873 esac;
2874 eval "${return_ok}";
2878 ########################################################################
2879 # string_not_contains (<string> <part>)
2881 # Test whether `part' is not substring of `string'.
2883 # Arguments : 2 text arguments.
2884 # Return : `0' if arg2 is substring of arg1, `1' otherwise.
2886 string_not_contains()
2888 func_check string_not_contains = 2 "$@";
2889 if string_contains "$1" "$2"; then
2890 eval "${return_no}";
2891 else
2892 eval "${return_yes}";
2894 eval "${return_ok}";
2898 ########################################################################
2899 landmark '12: tmp_*()';
2900 ########################################################################
2902 ########################################################################
2903 # tmp_cat ()
2905 # output the temporary cat file (the concatenation of all input)
2907 tmp_cat()
2909 cat "${_TMP_CAT}";
2913 ########################################################################
2914 # tmp_create (<suffix>?)
2916 # create temporary file
2918 # It's safe to use the shell process ID together with a suffix to
2919 # have multiple temporary files.
2921 # Output : name of created file
2923 tmp_create()
2925 func_check tmp_create '<=' 1 "$@";
2926 local _tmp;
2927 # the output file does not have `,' as first character
2928 _tmp="${_TMP_DIR}/,$1";
2929 echo -n >"${_tmp}";
2930 echo -n "${_tmp}"; # output file name
2931 eval "${return_ok}";
2935 ########################################################################
2936 # to_tmp (<filename>)
2938 # print file (decompressed) to the temporary cat file
2940 to_tmp()
2942 func_check to_tmp = 1 "$@";
2943 if is_file "$1"; then
2944 if obj _OPT_LOCATION is_yes; then
2945 echo2 "$1";
2947 if obj _OPT_WHATIS is_yes; then
2948 what_is "$1" >>"${_TMP_CAT}";
2949 else
2950 catz "$1" >>"${_TMP_CAT}";
2952 else
2953 error "to_tmp(): could not read file \`$1'.";
2955 eval "${return_ok}";
2959 ########################################################################
2960 # trap_clean ()
2962 # disable trap on all exit codes ($_ALL_EXIT)
2964 # Arguments: 0
2965 # Globals: $_ALL_EXIT
2967 trap_clean()
2969 func_check trap_clean = 0 "$@";
2970 local i;
2971 for i in ${_ALL_EXIT}; do
2972 trap "" "$i" 2>/dev/null || true;
2973 done;
2974 eval "${return_ok}";
2978 ########################################################################
2979 # trap_set (<functionname>)
2981 # call function on all exit codes ($_ALL_EXIT)
2983 # Arguments: 1 (name of a shell function)
2984 # Globals: $_ALL_EXIT
2986 trap_set()
2988 func_check trap_set = 1 "$@";
2989 local i;
2990 for i in ${_ALL_EXIT}; do
2991 trap "$1" "$i" 2>/dev/null || true;
2992 done;
2993 eval "${return_ok}";
2997 ########################################################################
2998 # usage ()
3000 # print usage information to stderr; for groffer option --help.
3002 usage()
3004 func_check usage = 0 "$@";
3005 echo;
3006 version;
3007 echo 'Usage: '"${_PROGRAM_NAME}"' [option]... [filespec]...';
3008 cat <<EOF
3010 Display roff files, standard input, and/or Unix manual pages with a X
3011 Window viewer or in several text modes. All input is decompressed
3012 on-the-fly with all formats that gzip can handle.
3014 "filespec" is one of
3015 "filename" name of a readable file
3016 "-" for standard input
3017 "man:name.n" man page "name" in section "n"
3018 "man:name" man page "name" in first section found
3019 "name.n" man page "name" in section "n"
3020 "name" man page "name" in first section found
3021 and some more (see groffer(1) for details).
3023 -h --help print this usage message.
3024 -Q --source output as roff source.
3025 -T --device=name pass to groff using output device "name".
3026 -v --version print version information.
3027 -V display the groff execution pipe instead of formatting.
3028 -X --X --x display with "gxditview" using groff -X.
3029 -Z --ditroff --intermediate-output
3030 generate groff intermediate output without
3031 post-processing and viewing, like groff -Z.
3032 All other short options are interpreted as "groff" formatting options.
3034 The most important groffer long options are
3036 --apropos=name start man's "apropos" program for "name".
3037 --apropos-data=name
3038 "apropos" for "name" in man's data sections 4, 5, 7.
3039 --apropos-devel=name
3040 "apropos" for "name" in development sections 2, 3, 9.
3041 --apropos-progs=name
3042 "apropos" for "name" in man's program sections 1, 6, 8.
3043 --auto choose mode automatically from the default mode list.
3044 --default reset all options to the default value.
3045 --default-modes=mode1,mode2,...
3046 set sequence of automatically tried modes.
3047 --dvi display in a viewer for TeX device independent format.
3048 --dvi-viewer choose the viewer program for dvi mode.
3049 --groff process like groff, disable viewing features.
3050 --help display this helping output.
3051 --html --www display in a web browser.
3052 --html-viewer choose the web browser for www mode.
3053 --man check file parameters first whether they are man pages.
3054 --mode=auto|dvi|groff|html|pdf|ps|source|text|tty|www|x|X
3055 choose display mode.
3056 --no-man disable man-page facility.
3057 --pager=program preset the paging program for tty mode.
3058 --pdf display in a PDF viewer.
3059 --pdf-viewer choose the viewer program for pdf mode.
3060 --ps display in a Postscript viewer.
3061 --ps-viewer choose the viewer program for ps mode.
3062 --shell specify shell under which to run this program.
3063 --text output in a text device without a pager.
3064 --tty display with a pager on text terminal even when in X.
3065 --www-viewer same as --html-viewer
3066 --x-viewer choose viewer program for x mode (X mode).
3067 --X-viewer same as "--xviewer".
3069 The usual X Windows toolkit options transformed into GNU long options
3070 --background=color, --bd=size, --bg=color, --bordercolor=color,
3071 --borderwidth=size, --bw=size, --display=Xdisplay, --fg=color,
3072 --fn=font, --font=font, --foreground=color, --geometry=geom, --iconic,
3073 --resolution=dpi, --rv, --title=text, --xrm=resource
3075 Long options of GNU "man"
3076 --all, --ascii, --ditroff, --extension=suffix, --locale=language,
3077 --local-file=name, --location, --manpath=dir1:dir2:...,
3078 --sections=s1:s2:..., --systems=s1,s2,..., --whatis, --where, ...
3081 eval "${return_ok}";
3085 ########################################################################
3086 # version ()
3088 # print version information to stderr
3090 version()
3092 func_check version = 0 "$@";
3093 echo2 "${_PROGRAM_NAME} ${_PROGRAM_VERSION} of ${_LAST_UPDATE}";
3094 # also display groff's version, but not the called subprograms
3095 groff -v 2>&1 | sed -e '/^ *$/q' | sed -e '1s/^/is part of /' >&2;
3099 ########################################################################
3100 # warning (<string>)
3102 # Print warning to stderr
3104 warning()
3106 echo2 "warning: $*";
3110 ########################################################################
3111 # what_is (<filename>)
3113 # Interpret <filename> as a man page and display its `whatis'
3114 # information as a fragment written in the groff language.
3116 what_is()
3118 func_check what_is = 1 "$@";
3119 local _res;
3120 local _dot;
3121 if is_not_file "$1"; then
3122 error "what_is(): argument is not a readable file."
3124 _dot='^\.['"${_SPACE}${_TAB}"']*';
3125 echo '.br';
3126 echo "$1: ";
3127 echo '.br';
3128 echo -n ' ';
3129 # grep the line containing `.TH' macro, if any
3130 _res="$(catz "$1" | sed -e '/'"${_dot}"'TH /p
3131 d')";
3132 if obj _res is_not_empty; then # traditional man style
3133 # get the text between the first and the second `.SH' macro, by
3134 # - delete up to first .SH;
3135 # - of this, print everything up to next .SH, and delete the rest;
3136 # - of this, delete the final .SH line;
3137 catz "$1" | sed -e '1,/'"${_dot}"'SH/d' \
3138 | sed -e '1,/'"${_dot}"'SH/p
3139 d' \
3140 | sed -e '/'"${_dot}"'SH/d';
3141 eval "${return_ok}";
3143 # grep the line containing `.Dd' macro, if any
3144 _res="$(catz "$1" | sed -e '/'"${_dot}"'Dd /p
3145 d')";
3146 if obj _res is_not_empty; then # BSD doc style
3147 # get the text between the first and the second `.Nd' macro, by
3148 # - delete up to first .Nd;
3149 # - of this, print everything up to next .Nd, and delete the rest;
3150 # - of this, delete the final .Nd line;
3151 catz "$1" | sed -e '1,/'"${_dot}"'Nd/d' \
3152 | sed -e '1,/'"${_dot}"'Nd/p
3153 d' \
3154 | sed -e '/'"${_dot}"'Nd/d';
3155 eval "${return_ok}";
3157 echo 'is not a man page.';
3158 eval "${return_bad}";
3162 ########################################################################
3163 # where (<program>)
3165 # Output path of a program if in $PATH.
3167 # Arguments : >=1 (empty allowed)
3168 # more args are ignored, this allows to specify progs with arguments
3169 # Return : `0' if arg1 is a program in $PATH, `1' otherwise.
3171 where()
3173 func_check where '>=' 1 "$@";
3174 local _file;
3175 local _arg;
3176 local p;
3177 _arg="$1";
3178 if obj _arg is_empty; then
3179 eval "${return_bad}";
3181 case "${_arg}" in
3183 if test -f "${_arg}" && test -x "${_arg}"; then
3184 eval "${return_ok}";
3185 else
3186 eval "${return_bad}";
3189 esac;
3190 eval set -- "$(path_split "${PATH}")";
3191 for p in "$@"; do
3192 case "$p" in
3193 */) _file=${p}${_arg}; ;;
3194 *) _file=${p}/${_arg}; ;;
3195 esac;
3196 if test -f "${_file}" && test -x "${_file}"; then
3197 echo -n "${_file}";
3198 eval "${return_ok}";
3200 done;
3201 eval "${return_bad}";
3205 ########################################################################
3206 # main* Functions
3207 ########################################################################
3209 # The main area contains the following parts:
3210 # - main_init(): initialize temporary files and set exit trap
3211 # - main_parse_MANOPT(): parse $MANOPT
3212 # - main_parse_args(): argument parsing
3213 # - main_set_mode (): determine the display mode
3214 # - main_do_fileargs(): process filespec arguments
3215 # - main_set_resources(): setup X resources
3216 # - main_display(): do the displaying
3217 # - main(): the main function that calls all main_*()
3219 # These parts are implemented as functions, being defined below in the
3220 # sequence they are called in the main() function.
3223 #######################################################################
3224 # main_init ()
3226 # set exit trap and create temporary files
3228 # Globals: $_TMP_DIR, $_TMP_CAT, $_TMP_STDIN
3230 landmark '13: main_init()';
3231 main_init()
3233 func_check main_init = 0 "$@";
3234 # call clean_up() on any signal
3235 trap_set clean_up;
3237 # create temporary directory
3238 umask 0022;
3239 _TMP_DIR='';
3240 for d in "${GROFF_TMPDIR}" "${TMPDIR}" "${TMP}" "${TEMP}" \
3241 "${TEMPDIR}" "${HOME}"'/tmp' '/tmp' "${HOME}" '.';
3243 if obj d is_empty || obj d is_not_dir || obj d is_not_writable; then
3244 continue;
3246 case "$d" in
3248 _TMP_DIR="${d}";
3251 _TMP_DIR="${d}"'/';
3253 esac;
3254 _TMP_DIR="${_TMP_DIR}${_PROGRAM_NAME}${_PROCESS_ID}";
3255 while obj _TMP_DIR is_existing; do
3256 rm -f -r "${_TMP_DIR}" 2>/dev/null;
3257 if obj _TMP_DIR is_existing; then
3258 # $_TMP_DIR could not be removed
3259 _TMP_DIR="${_TMP_DIR}"'X';
3260 continue;
3261 else
3262 # $_TMP_DIR was removed
3263 break;
3265 done;
3266 mkdir "${_TMP_DIR}";
3267 if is_not_equal "$?" 0; then
3268 if obj _TMP_DIR is_existing; then
3269 rm -f -r "${_TMP_DIR}" 2>/dev/null;
3271 _TMP_DIR='';
3272 continue;
3274 if obj _TMP_DIR is_dir && obj _TMP_DIR is_writable; then
3275 # $_TMP_DIR can now be used as temporary directory
3276 break;
3278 if obj _TMP_DIR is_existing; then
3279 rm -f -r "${_TMP_DIR}" 2>/dev/null;
3281 _TMP_DIR='';
3282 continue;
3283 done;
3284 unset d;
3285 if obj _TMP_DIR is_empty; then
3286 error "Couldn't create a directory for storing temporary files.";
3289 _TMP_CAT="$(tmp_create groffer_cat)";
3290 _TMP_STDIN="$(tmp_create groffer_input)";
3292 # groffer configuration files
3293 for f in ${_CONFFILES}; do
3294 if obj f is_file; then
3295 echo '_groffer_opt=""' >>${_TMP_CAT};
3296 # collect the lines starting with a minus
3297 cat "$f" | sed -e \
3298 's/^[ ]*\(-.*\)$/_groffer_opt="${_groffer_opt} \1"'/ \
3299 >>${_TMP_CAT};
3300 # prepend the collected information to $GROFFER_OPT
3301 echo 'GROFFER_OPT="${_groffer_opt} ${GROFFER_OPT}"' >>${_TMP_CAT};
3303 done;
3304 . "${_TMP_CAT}";
3305 _TMP_CAT="$(tmp_create groffer_cat)";
3307 eval "${return_ok}";
3308 } # main_init()
3311 ########################################################################
3312 # main_parse_MANOPT ()
3314 # Parse $MANOPT to retrieve man options, but only if it is a non-empty
3315 # string; found man arguments can be overwritten by the command line.
3317 # Globals:
3318 # in: $MANOPT, $_OPTS_MANOPT_*
3319 # out: $_MANOPT_*
3320 # in/out: $GROFFER_OPT
3322 landmark '14: main_parse_MANOPT()';
3323 main_parse_MANOPT()
3325 func_check main_parse_MANOPT = 0 "$@";
3326 local _opt;
3327 local _list;
3328 _list='';
3329 if obj MANOPT is_not_empty; then
3330 MANOPT="$(echo -n "${MANOPT}" | \
3331 sed -e 's/^'"${_SPACE}${_SPACE}"'*//')";
3333 if obj MANOPT is_empty; then
3334 eval "${return_ok}";
3336 # add arguments in $MANOPT by mapping them to groffer options
3337 eval set -- "$(list_from_cmdline _OPTS_MANOPT "${MANOPT}")";
3338 until test "$#" -le 0 || is_equal "$1" '--'; do
3339 _opt="$1";
3340 shift;
3341 case "${_opt}" in
3342 -7|--ascii)
3343 list_append _list '--ascii';
3345 -a|--all)
3346 list_append _list '--all';
3348 -c|--catman)
3349 do_nothing;
3350 shift;
3352 -d|--debug)
3353 list_append _list '--debug';
3355 -D|--default)
3356 # undo all man options so far
3357 _list='';
3359 -e|--extension)
3360 list_append _list '--extension';
3361 shift;
3363 -f|--whatis)
3364 list_append _list '--whatis';
3365 shift;
3367 -h|--help)
3368 do_nothing;
3369 shift;
3371 -k|--apropos)
3372 # groffer's --apropos takes an argument, but man's does not, so
3373 do_nothing;
3374 shift;
3376 -l|--local-file)
3377 list_append _list '--local-file';
3379 -L|--locale)
3380 list_append _list '--locale' "$1";
3381 shift;
3383 -m|--systems)
3384 list_append _list '--systems' "$1";
3385 shift;
3387 -M|--manpath)
3388 list_append _list '--manpath' "$1";
3389 shift;
3391 -p|--preprocessor)
3392 do_nothing;
3393 shift;
3395 -P|--pager|--tty-viewer)
3396 list_append _list '--pager' "$1";
3397 shift;
3399 -r|--prompt)
3400 do_nothing;
3401 shift;
3403 -S|--sections)
3404 list_append _list '--sections' "$1";
3405 shift;
3407 -t|--troff)
3408 do_nothing;
3409 shift;
3411 -T|--device)
3412 list_append _list '-T' "$1";
3413 shift;
3415 -u|--update)
3416 do_nothing;
3417 shift;
3419 -V|--version)
3420 do_nothing;
3422 -w|--where|--location)
3423 list_append _list '--location';
3425 -Z|--ditroff)
3426 list_append _list '-Z' "$1";
3427 shift;
3429 # ignore all other options
3430 esac;
3431 done;
3432 # append the 2 lists in $_list and $GROFFER_OPT to $GROFFER_OPT
3433 if obj GROFFER_OPT is_empty; then
3434 GROFFER_OPT="${_list}";
3435 elif obj _list is_not_empty; then
3436 GROFFER_OPT="${_list} ${GROFFER_OPT}";
3438 eval "${return_ok}";
3439 } # main_parse_MANOPT()
3442 ########################################################################
3443 # main_parse_args (<command_line_args>*)
3445 # Parse arguments; process options and filespec parameters
3447 # Arguments: pass the command line arguments unaltered.
3448 # Globals:
3449 # in: $_OPTS_*
3450 # out: $_OPT_*, $_ADDOPTS, $_FILEARGS
3452 landmark '15: main_parse_args()';
3453 main_parse_args()
3455 func_check main_parse_args '>=' 0 "$@";
3456 local _arg;
3457 local _code;
3458 local _dpi;
3459 local _longopt;
3460 local _mode;
3461 local _opt;
3462 local _optchar;
3463 local _optarg;
3464 local _opts;
3465 local _string;
3467 eval set -- "${GROFFER_OPT}" '"$@"';
3469 eval set -- "$(list_from_cmdline _OPTS_CMDLINE "$@")";
3471 # By the call of `eval', unnecessary quoting was removed. So the
3472 # positional shell parameters ($1, $2, ...) are now guaranteed to
3473 # represent an option or an argument to the previous option, if any;
3474 # then a `--' argument for separating options and
3475 # parameters; followed by the filespec parameters if any.
3477 # Note, the existence of arguments to options has already been checked.
3478 # So a check for `$#' or `--' should not be done for arguments.
3480 until test "$#" -le 0 || is_equal "$1" '--'; do
3481 _opt="$1"; # $_opt is fed into the option handler
3482 shift;
3483 case "${_opt}" in
3484 -h|--help)
3485 usage;
3486 leave;
3488 -Q|--source) # output source code (`Quellcode').
3489 _OPT_MODE='source';
3491 -T|--device|--troff-device) # device; arg
3492 _OPT_DEVICE="$1";
3493 _check_device_with_mode;
3494 shift;
3496 -v|--version)
3497 version;
3498 leave;
3501 _OPT_V='yes';
3503 -Z|--ditroff|--intermediate-output) # groff intermediate output
3504 _OPT_Z='yes';
3506 -X|--X|--x)
3507 _OPT_MODE=x;
3510 # delete leading `-'
3511 _optchar="$(echo -n "${_opt}" | sed -e 's/^.//')";
3512 if list_has _OPTS_GROFF_SHORT_NA "${_optchar}";
3513 then
3514 list_append _ADDOPTS_GROFF "${_opt}";
3515 elif list_has _OPTS_GROFF_SHORT_ARG "${_optchar}";
3516 then
3517 list_append _ADDOPTS_GROFF "${_opt}" "$1";
3518 shift;
3519 else
3520 error "Unknown option : \`$1'";
3523 --all)
3524 _OPT_ALL="yes";
3526 --apropos) # run `apropos'
3527 apropos_run "$1";
3528 _code="$?";
3529 clean_up;
3530 exit "${_code}";
3532 --apropos-data) # run `apropos' for data sections
3533 apropos_run "$1" | grep '^[^(]*([457][^)]*)';
3534 _code="$?";
3535 clean_up;
3536 exit "${_code}";
3538 --apropos-devel) # run `apropos' for development sections
3539 apropos_run "$1" | grep '^[^(]*([239][^)]*)';
3540 _code="$?";
3541 clean_up;
3542 exit "${_code}";
3544 --apropos-progs) # run `apropos' for program sections
3545 apropos_run "$1" | grep '^[^(]*([168][^)]*)';
3546 _code="$?";
3547 clean_up;
3548 exit "${_code}";
3550 --ascii)
3551 list_append _ADDOPTS_GROFF '-mtty-char';
3552 if obj _mode is_empty; then
3553 _mode='text';
3556 --auto) # the default automatic mode
3557 _mode='';
3559 --bd) # border color for viewers, arg;
3560 _OPT_BD="$1";
3561 shift;
3563 --bg|--backgroud) # background color for viewers, arg;
3564 _OPT_BG="$1";
3565 shift;
3567 --bw) # border width for viewers, arg;
3568 _OPT_BW="$1";
3569 shift;
3571 --default) # reset variables to default
3572 reset;
3574 --default-modes) # sequence of modes in auto mode; arg
3575 _OPT_DEFAULT_MODES="$1";
3576 shift;
3578 --debug) # buggy, only for development
3579 _OPT_DEBUG='yes';
3581 --display) # set X display, arg
3582 _OPT_DISPLAY="$1";
3583 shift;
3585 --dvi)
3586 _OPT_MODE='dvi';
3588 --dvi-viewer) # viewer program for dvi mode; arg
3589 _OPT_VIEWER_DVI="$1";
3590 shift;
3592 --extension) # the extension for man pages, arg
3593 _OPT_EXTENSION="$1";
3594 shift;
3596 --fg|--foreground) # foreground color for viewers, arg;
3597 _OPT_FG="$1";
3598 shift;
3600 --fn|--font) # set font for viewers, arg;
3601 _OPT_FN="$1";
3602 shift;
3604 --geometry) # window geometry for viewers, arg;
3605 _OPT_GEOMETRY="$1";
3606 shift;
3608 --groff)
3609 _OPT_MODE='groff';
3611 --html|--www) # display with web browser
3612 _OPT_MODE=html;
3614 --html-viewer|--www-viewer) # viewer program for html mode; arg
3615 _OPT_VIEWER_HTML="$1";
3616 shift;
3618 --iconic) # start viewers as icons
3619 _OPT_ICONIC='yes';
3621 --locale) # set language for man pages, arg
3622 # argument is xx[_territory[.codeset[@modifier]]] (ISO 639,...)
3623 _OPT_LANG="$1";
3624 shift;
3626 --local-file) # force local files; same as `--no-man'
3627 _MAN_FORCE='no';
3628 _MAN_ENABLE='no';
3630 --location|--where) # print file locations to stderr
3631 _OPT_LOCATION='yes';
3633 --man) # force all file params to be man pages
3634 _MAN_ENABLE='yes';
3635 _MAN_FORCE='yes';
3637 --manpath) # specify search path for man pages, arg
3638 # arg is colon-separated list of directories
3639 _OPT_MANPATH="$1";
3640 shift;
3642 --mode) # display mode
3643 _arg="$1";
3644 shift;
3645 case "${_arg}" in
3646 auto|'') # search mode automatically among default
3647 _mode='';
3649 groff) # pass input to plain groff
3650 _mode='groff';
3652 html|www) # display with a web browser
3653 _mode='html';
3655 dvi) # display with xdvi viewer
3656 _mode='dvi';
3658 pdf) # display with PDF viewer
3659 _mode='pdf';
3661 ps) # display with Postscript viewer
3662 _mode='ps';
3664 text) # output on terminal
3665 _mode='text';
3667 tty) # output on terminal
3668 _mode='tty';
3670 X|x) # output on X roff viewer
3671 _mode='x';
3673 Q|source) # display source code
3674 _mode="source";
3677 error "unknown mode ${_arg}";
3679 esac;
3680 _OPT_MODE="${_mode}";
3682 --no-location) # disable former call to `--location'
3683 _OPT_LOCATION='yes';
3685 --no-man) # disable search for man pages
3686 # the same as --local-file
3687 _MAN_FORCE="no";
3688 _MAN_ENABLE="no";
3690 --pager) # set paging program for tty mode, arg
3691 _OPT_PAGER="$1";
3692 shift;
3694 --pdf)
3695 _OPT_MODE='pdf';
3697 --pdf-viewer) # viewer program for ps mode; arg
3698 _OPT_VIEWER_PDF="$1";
3699 shift;
3701 --ps)
3702 _OPT_MODE='ps';
3704 --ps-viewer) # viewer program for ps mode; arg
3705 _OPT_VIEWER_PS="$1";
3706 shift;
3708 --resolution) # set resolution for X devices, arg
3709 _arg="$1";
3710 shift;
3711 case "${_arg}" in
3712 75|75dpi)
3713 _dpi=75;
3715 100|100dpi)
3716 _dpi=100;
3719 error "only resoutions of 75 or 100 dpi are supported";
3721 esac;
3722 _OPT_RESOLUTION="${_dpi}";
3724 --rv)
3725 _OPT_RV='yes';
3727 --sections) # specify sections for man pages, arg
3728 # arg is colon-separated list of section names
3729 _OPT_SECTIONS="$1";
3730 shift;
3732 --shell)
3733 # already done during the first run; so ignore the argument
3734 shift;
3736 --systems) # man pages for different OS's, arg
3737 # argument is a comma-separated list
3738 _OPT_SYSTEMS="$1";
3739 shift;
3741 --text) # text mode without pager
3742 _OPT_MODE=text;
3744 --title) # title for X viewers; arg
3745 _OPT_TITLE="$1";
3746 shift;
3748 --tty) # tty mode, text with pager
3749 _OPT_MODE=tty;
3751 --text-device|--tty-device) # device for tty mode; arg
3752 _OPT_TEXT_DEVICE="$1";
3753 shift;
3755 --whatis)
3756 _OPT_WHATIS='yes';
3758 --xrm) # pass X resource string, arg;
3759 list_append _OPT_XRM "$1";
3760 shift;
3762 --x-viewer|--X-viewer) # viewer program for x mode; arg
3763 _OPT_VIEWER_X="$1";
3764 shift;
3767 error 'error on argument parsing : '"\`$*'";
3769 esac;
3770 done;
3771 shift; # remove `--' argument
3773 if obj _DEBUG is_not_yes; then
3774 if obj _OPT_DEBUG is_yes; then
3775 _DEBUG='yes';
3779 # Remaining arguments are file names (filespecs).
3780 # Save them to list $_FILEARGS
3781 if is_equal "$#" 0; then # use "-" for standard input
3782 set -- '-';
3784 _FILEARGS='';
3785 list_append _FILEARGS "$@";
3786 if list_has _FILEARGS '-'; then
3787 save_stdin;
3789 # $_FILEARGS must be retrieved with `eval set -- "$_FILEARGS"'
3790 eval "${return_ok}";
3791 } # main_parse_args()
3793 # Called from main_parse_args() because double `case' is not possible.
3794 # Globals: $_OPT_DEVICE, $_OPT_MODE
3795 _check_device_with_mode()
3797 func_check _check_device_with_mode = 0 "$@";
3798 case "${_OPT_DEVICE}" in
3799 dvi)
3800 _OPT_MODE=dvi;
3801 eval "${return_ok}";
3803 html)
3804 _OPT_MODE=html;
3805 eval "${return_ok}";
3807 lbp|lj4)
3808 _OPT_MODE=groff;
3809 eval "${return_ok}";
3812 _OPT_MODE=ps;
3813 eval "${return_ok}";
3815 ascii|cp1047|latin1|utf8)
3816 if obj _OPT_MODE is_not_equal text; then
3817 _OPT_MODE=tty; # default text mode
3819 eval "${return_ok}";
3822 _OPT_MODE=x;
3823 eval "${return_ok}";
3825 *) # unknown device, go to groff mode
3826 _OPT_MODE=groff;
3827 eval "${return_ok}";
3829 esac;
3830 eval "${return_error}";
3834 ########################################################################
3835 # main_set_mode ()
3837 # Determine the display mode.
3839 # Globals:
3840 # in: $DISPLAY, $_OPT_MODE, $_OPT_DEVICE
3841 # out: $_DISPLAY_MODE
3844 # _get_first_prog (<proglist>)
3846 # Retrieve first argument that represents an existing program in $PATH.
3847 # Local function for main_set_mode().
3849 # Arguments: 1; a comma-separated list of commands (with options),
3850 # like $_VIEWER_*.
3852 # Return : `1' if none found, `0' if found.
3853 # Output : the argument that succeded.
3855 landmark '16: main_set_mode()';
3856 main_set_mode()
3858 func_check main_set_mode = 0 "$@";
3859 local m;
3860 local _modes;
3861 local _viewer;
3862 local _viewers;
3864 # handle apropos
3865 if obj _OPT_APROPOS is_not_empty; then
3866 apropos "${_OPT_APROPOS}";
3867 _code="$?";
3868 clean_up;
3869 exit "${_code}";
3871 if obj _OPT_APROPOS_DATA is_not_empty; then
3872 apropos "$@" | grep '^[^(]*([457])';
3873 _code="$?";
3874 clean_up;
3875 exit "${_code}";
3877 if obj _OPT_APROPOS_DEVEL is_not_empty; then
3878 apropos "$@" | grep '^[^(]*([239])';
3879 _code="$?";
3880 clean_up;
3881 exit "${_code}";
3883 if obj _OPT_APROPOS_PROGS is_not_empty; then
3884 apropos "$@" | grep '^[^(]*([168])';
3885 _code="$?";
3886 clean_up;
3887 exit "${_code}";
3890 # set display
3891 if obj _OPT_DISPLAY is_not_empty; then
3892 DISPLAY="${_OPT_DISPLAY}";
3895 if obj _OPT_V is_yes; then
3896 _DISPLAY_MODE='groff';
3897 list_append _ADDOPTS_GROFF '-V';
3899 if obj _OPT_Z is_yes; then
3900 _DISPLAY_MODE='groff';
3901 list_append _ADDOPTS_GROFF '-Z';
3903 if obj _OPT_MODE is_equal 'groff'; then
3904 _DISPLAY_MODE='groff';
3906 if obj _DISPLAY_MODE is_equal 'groff'; then
3907 eval "${return_ok}";
3910 if obj _OPT_MODE is_equal 'source'; then
3911 _DISPLAY_MODE='source';
3912 eval "${return_ok}";
3915 case "${_OPT_MODE}" in
3916 '') # automatic mode
3917 case "${_OPT_DEVICE}" in
3919 if obj DISPLAY is_empty; then
3920 error "no X display found for device ${_OPT_DEVICE}";
3922 _DISPLAY_MODE='x';
3923 eval "${return_ok}";
3925 ascii|cp1047|latin1|utf8)
3926 if obj _DISPLAY_MODE is_not_equal 'text'; then
3927 _DISPLAY_MODE='tty';
3929 eval "${return_ok}";
3931 esac;
3932 if obj DISPLAY is_empty; then
3933 _DISPLAY_MODE='tty';
3934 eval "${return_ok}";
3937 if obj _OPT_DEFAULT_MODES is_empty; then
3938 _modes="${_DEFAULT_MODES}";
3939 else
3940 _modes="${_OPT_DEFAULT_MODES}";
3943 text)
3944 _DISPLAY_MODE='text';
3945 eval "${return_ok}";
3947 tty)
3948 _DISPLAY_MODE='tty';
3949 eval "${return_ok}";
3951 *) # display mode was given
3952 if obj DISPLAY is_empty; then
3953 error "you must be in X Window for ${_OPT_MODE} mode.";
3955 _modes="${_OPT_MODE}";
3957 esac;
3959 # only viewer modes are left
3960 eval set -- "$(list_from_split "${_modes}" ',')";
3961 while test "$#" -gt 0; do
3962 m="$1";
3963 shift;
3964 case "$m" in
3965 text)
3966 _DISPLAY_MODE='text';
3967 eval "${return_ok}";
3969 tty)
3970 _DISPLAY_MODE='tty';
3971 eval "${return_ok}";
3974 if obj _OPT_VIEWER_X is_not_empty; then
3975 _viewers="${_OPT_VIEWER_X}";
3976 else
3977 _viewers="${_VIEWER_X}";
3979 _viewer="$(_get_first_prog "${_viewers}")";
3980 if is_not_equal "$?" 0; then
3981 continue;
3983 _DISPLAY_PROG="${_viewer}";
3984 _DISPLAY_MODE='x';
3985 eval "${return_ok}";
3987 dvi)
3988 if obj _OPT_VIEWER_DVI is_not_empty; then
3989 _viewers="${_OPT_VIEWER_DVI}";
3990 else
3991 _viewers="${_VIEWER_DVI}";
3993 _viewer="$(_get_first_prog "${_viewers}")";
3994 if is_not_equal "$?" 0; then
3995 continue;
3997 _DISPLAY_PROG="${_viewer}";
3998 _DISPLAY_MODE="dvi";
3999 eval "${return_ok}";
4001 pdf)
4002 if obj _OPT_VIEWER_PDF is_not_empty; then
4003 _viewers="${_OPT_VIEWER_PDF}";
4004 else
4005 _viewers="${_VIEWER_PDF}";
4007 _viewer="$(_get_first_prog "${_viewers}")";
4008 if is_not_equal "$?" 0; then
4009 continue;
4011 _DISPLAY_PROG="${_viewer}";
4012 _DISPLAY_MODE="pdf";
4013 eval "${return_ok}";
4016 if obj _OPT_VIEWER_PS is_not_empty; then
4017 _viewers="${_OPT_VIEWER_PS}";
4018 else
4019 _viewers="${_VIEWER_PS}";
4021 _viewer="$(_get_first_prog "${_viewers}")";
4022 if is_not_equal "$?" 0; then
4023 continue;
4025 _DISPLAY_PROG="${_viewer}";
4026 _DISPLAY_MODE="ps";
4027 eval "${return_ok}";
4029 html)
4030 if obj _OPT_VIEWER_HTML is_not_empty; then
4031 _viewers="${_OPT_VIEWER_HTML}";
4032 else
4033 _viewers="${_VIEWER_HTML}";
4035 _viewer="$(_get_first_prog "${_viewers}")";
4036 if is_not_equal "$?" 0; then
4037 continue;
4039 _DISPLAY_PROG="${_viewer}";
4040 _DISPLAY_MODE=html;
4041 eval "${return_ok}";
4043 esac;
4044 done;
4045 error "no suitable display mode found.";
4048 _get_first_prog()
4050 local i;
4051 if is_equal "$#" 0; then
4052 error "_get_first_prog() needs 1 argument.";
4054 if is_empty "$1"; then
4055 return "${_BAD}";
4057 eval set -- "$(list_from_split "$1" ',')";
4058 for i in "$@"; do
4059 if obj i is_empty; then
4060 continue;
4062 if is_prog "$(get_first_essential $i)"; then
4063 echo -n "$i";
4064 return "${_GOOD}";
4066 done;
4067 return "${_BAD}";
4068 } # main_set_mode()
4071 #######################################################################
4072 # main_do_fileargs ()
4074 # Process filespec arguments in $_FILEARGS.
4076 # Globals:
4077 # in: $_FILEARGS (process with `eval set -- "$_FILEARGS"')
4079 landmark '17: main_do_fileargs()';
4080 main_do_fileargs()
4082 func_check main_do_fileargs = 0 "$@";
4083 local _exitcode;
4084 local _filespec;
4085 local _name;
4086 _exitcode="${_BAD}";
4087 eval set -- "${_FILEARGS}";
4088 unset _FILEARGS;
4089 # temporary storage of all input to $_TMP_CAT
4090 while test "$#" -ge 2; do
4091 # test for `s name' arguments, with `s' a 1-char standard section
4092 _filespec="$1";
4093 shift;
4094 case "${_filespec}" in
4096 continue;
4098 '-')
4099 if register_file '-'; then
4100 _exitcode="${_GOOD}";
4102 continue;
4105 if list_has_not _MAN_AUTO_SEC "${_filespec}"; then
4106 if do_filearg "${_filespec}"; then
4107 _exitcode="${_GOOD}";
4109 continue;
4111 _name="$1";
4112 case "${_name}" in
4113 */*|man:*|*\(*\)|*."${_filespec}")
4114 if do_filearg "${_filespec}"; then
4115 _exitcode="${_GOOD}";
4117 continue;
4119 esac;
4120 if do_filearg "man:${_name}(${_filespec})"; then
4121 _exitcode="${_GOOD}";
4122 shift;
4123 continue;
4124 else
4125 if do_filearg "${_filespec}"; then
4126 _exitcode="${_GOOD}";
4128 continue;
4132 if do_filearg "${_filespec}"; then
4133 _exitcode="${_GOOD}";
4135 continue;
4137 esac;
4138 done; # end of `s name' test
4139 while test "$#" -gt 0; do
4140 _filespec="$1";
4141 shift;
4142 if do_filearg "${_filespec}"; then
4143 _exitcode="${_GOOD}";
4145 done;
4146 rm -f "${_TMP_STDIN}";
4147 if is_equal "${_exitcode}" "${_BAD}"; then
4148 eval "${return_bad}";
4150 eval "${return_ok}";
4151 } # main_do_fileargs()
4154 ########################################################################
4155 # main_set_resources ()
4157 # Determine options for setting X resources with $_DISPLAY_PROG.
4159 # Globals: $_DISPLAY_PROG, $_OUTPUT_FILE_NAME
4161 landmark '18: main_set_resources()';
4162 main_set_resources()
4164 func_check main_set_resources = 0 "$@";
4165 local _prog; # viewer program
4166 local _rl; # resource list
4167 local n;
4168 _title="$(get_first_essential \
4169 "${_OPT_TITLE}" "${_REGISTERED_TITLE}")";
4170 _OUTPUT_FILE_NAME='';
4171 set -- ${_title};
4172 until is_equal "$#" 0; do
4173 n="$1";
4174 case "$n" in
4176 continue;
4179 n="$(echo -n "$1" | sed -e 's/^,,*//')";
4181 esac
4182 if obj n is_empty; then
4183 continue;
4185 if obj _OUTPUT_FILE_NAME is_not_empty; then
4186 _OUTPUT_FILE_NAME="${_OUTPUT_FILE_NAME},";
4188 _OUTPUT_FILE_NAME="${_OUTPUT_FILE_NAME}$n";
4189 shift;
4190 done;
4191 case "${_OUTPUT_FILE_NAME}" in
4193 _OUTPUT_FILE_NAME='-';
4196 error "$_OUTPUT_FILE_NAME starts with a comma.";
4198 esac;
4199 _OUTPUT_FILE_NAME="${_TMP_DIR}/${_OUTPUT_FILE_NAME}";
4201 if obj _DISPLAY_PROG is_empty; then # for example, for groff mode
4202 _DISPLAY_ARGS='';
4203 eval "${return_ok}";
4206 set -- ${_DISPLAY_PROG};
4207 _prog="$(base_name "$1")";
4208 _rl='';
4209 if obj _OPT_BD is_not_empty; then
4210 case "${_prog}" in
4211 ghostview|gv|gxditview|xditview|xdvi)
4212 list_append _rl '-bd' "${_OPT_BD}";
4214 esac;
4216 if obj _OPT_BG is_not_empty; then
4217 case "${_prog}" in
4218 ghostview|gv|gxditview|xditview|xdvi)
4219 list_append _rl '-bg' "${_OPT_BG}";
4221 xpdf)
4222 list_append _rl '-papercolor' "${_OPT_BG}";
4224 esac;
4226 if obj _OPT_BW is_not_empty; then
4227 case "${_prog}" in
4228 ghostview|gv|gxditview|xditview|xdvi)
4229 _list_append _rl '-bw' "${_OPT_BW}";
4231 esac;
4233 if obj _OPT_FG is_not_empty; then
4234 case "${_prog}" in
4235 ghostview|gv|gxditview|xditview|xdvi)
4236 list_append _rl '-fg' "${_OPT_FG}";
4238 esac;
4240 if is_not_empty "${_OPT_FN}"; then
4241 case "${_prog}" in
4242 ghostview|gv|gxditview|xditview|xdvi)
4243 list_append _rl '-fn' "${_OPT_FN}";
4245 esac;
4247 if is_not_empty "${_OPT_GEOMETRY}"; then
4248 case "${_prog}" in
4249 ghostview|gv|gxditview|xditview|xdvi|xpdf)
4250 list_append _rl '-geometry' "${_OPT_GEOMETRY}";
4252 esac;
4254 if is_empty "${_OPT_RESOLUTION}"; then
4255 _OPT_RESOLUTION="${_DEFAULT_RESOLUTION}";
4256 case "${_prog}" in
4257 gxditview|xditview)
4258 list_append _rl '-resolution' "${_DEFAULT_RESOLUTION}";
4260 xpdf)
4261 case "${_DEFAULT_RESOLUTION}" in
4263 # 72dpi is '100'
4264 list_append _rl '-z' '104';
4266 100)
4267 list_append _rl '-z' '139';
4269 esac;
4271 esac;
4272 else
4273 case "${_prog}" in
4274 ghostview|gv|gxditview|xditview|xdvi)
4275 list_append _rl '-resolution' "${_OPT_RESOLUTION}";
4277 xpdf)
4278 case "${_OPT_RESOLUTION}" in
4280 list_append _rl '-z' '104';
4281 # '100' corresponds to 72dpi
4283 100)
4284 list_append _rl '-z' '139';
4286 esac;
4288 esac;
4290 if is_yes "${_OPT_ICONIC}"; then
4291 case "${_prog}" in
4292 ghostview|gv|gxditview|xditview|xdvi)
4293 list_append _rl '-iconic';
4295 esac;
4297 if is_yes "${_OPT_RV}"; then
4298 case "${_prog}" in
4299 ghostview|gv|gxditview|xditview|xdvi)
4300 list_append _rl '-rv';
4302 esac;
4304 if is_not_empty "${_OPT_XRM}"; then
4305 case "${_prog}" in
4306 ghostview|gv|gxditview|xditview|xdvi|xpdf)
4307 eval set -- "{$_OPT_XRM}";
4308 for i in "$@"; do
4309 list_append _rl '-xrm' "$i";
4310 done;
4312 esac;
4314 if is_not_empty "${_title}"; then
4315 case "${_prog}" in
4316 gxditview|xditview)
4317 list_append _rl '-title' "${_title}";
4319 esac;
4321 _DISPLAY_ARGS="${_rl}";
4323 eval "${return_ok}";
4324 } # main_set_resources
4327 ########################################################################
4328 # main_display ()
4330 # Do the actual display of the whole thing.
4332 # Globals:
4333 # in: $_DISPLAY_MODE, $_OPT_DEVICE,
4334 # $_ADDOPTS_GROFF, $_ADDOPTS_POST, $_ADDOPTS_X,
4335 # $_REGISTERED_TITLE, $_TMP_CAT,
4336 # $_OPT_PAGER $PAGER $_MANOPT_PAGER
4338 landmark '19: main_display()';
4339 main_display()
4341 func_check main_display = 0 "$@";
4342 local p;
4343 local _addopts;
4344 local _device;
4345 local _groggy;
4346 local _modefile;
4347 local _options;
4348 local _pager;
4349 local _title;
4350 export _addopts;
4351 export _groggy;
4352 export _modefile;
4354 if obj _TMP_CAT is_non_empty_file; then
4355 _modefile="${_OUTPUT_FILE_NAME}";
4356 else
4357 clean_up;
4358 eval "${return_ok}";
4360 case "${_DISPLAY_MODE}" in
4361 groff)
4362 _ADDOPTS_GROFF="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}";
4363 if obj _OPT_DEVICE is_not_empty; then
4364 _ADDOPTS_GROFF="${_ADDOPTS_GROFF} -T${_OPT_DEVICE}";
4366 _groggy="$(tmp_cat | eval grog "${_options}")";
4367 trap_clean;
4368 # start a new shell program to get another process ID.
4369 sh -c '
4370 set -e;
4371 test -f "${_modefile}" && rm -f "${_modefile}";
4372 mv "${_TMP_CAT}" "${_modefile}";
4373 cat "${_modefile}" | \
4375 clean_up()
4377 if test -d "${_TMP_DIR}"; then
4378 rm -f "${_TMP_DIR}"/* || true;
4379 rmdir "${_TMP_DIR}";
4382 trap clean_up 0 2>/dev/null || true;
4383 eval "${_groggy}" "${_ADDOPTS_GROFF}";
4384 ) &'
4386 text|tty)
4387 case "${_OPT_DEVICE}" in
4389 _device="$(get_first_essential \
4390 "${_OPT_TEXT_DEVICE}" "${_DEFAULT_TTY_DEVICE}")";
4392 ascii|cp1047|latin1|utf8)
4393 _device="${_OPT_DEVICE}";
4396 warning \
4397 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4399 esac;
4400 _addopts="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}";
4401 _groggy="$(tmp_cat | grog -T${_device})";
4402 if obj _DISPLAY_MODE is_equal 'text'; then
4403 tmp_cat | eval "${_groggy}" "${_addopts}";
4404 else
4405 _pager='';
4406 for p in "${_OPT_PAGER}" "${PAGER}" "${_MANOPT_PAGER}" \
4407 'less -r -R' 'more' 'pager' 'cat'; do
4408 if is_prog $p; then # no "" for is_prog() allows args for $p
4409 _pager="$p";
4410 break;
4412 done;
4413 if obj _pager is_empty; then
4414 error 'no pager program found for tty mode';
4416 tmp_cat | eval "${_groggy}" "${_addopts}" | \
4417 eval "${_pager}";
4419 clean_up;
4422 #### viewer modes
4424 dvi)
4425 case "${_OPT_DEVICE}" in
4426 ''|dvi) do_nothing; ;;
4428 warning \
4429 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4431 esac;
4432 _modefile="${_modefile}".dvi;
4433 _groggy="$(tmp_cat | grog -Tdvi)";
4434 _do_display;
4436 html)
4437 case "${_OPT_DEVICE}" in
4438 ''|html) do_nothing; ;;
4440 warning \
4441 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4443 esac;
4444 _modefile="${_modefile}".html;
4445 _groggy="$(tmp_cat | grog -Thtml)";
4446 _do_display;
4448 pdf)
4449 case "${_OPT_DEVICE}" in
4450 ''|ps)
4451 do_nothing;
4454 warning \
4455 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4457 esac;
4458 _groggy="$(tmp_cat | grog -Tps)";
4459 trap_clean;
4460 # start a new shell program to get another process ID.
4461 sh -c '
4462 set -e;
4463 _psfile="${_modefile}.ps";
4464 _modefile="${_modefile}.pdf";
4465 test -f "${_psfile}" && rm -f "${_psfile}";
4466 test -f "${_modefile}" && rm -f "${_modefile}";
4467 cat "${_TMP_CAT}" | \
4468 eval "${_groggy}" "${_ADDOPTS_GROFF}" > "${_psfile}";
4469 gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \
4470 -sOutputFile="${_modefile}" -c save pop -f "${_psfile}";
4471 test -f "${_psfile}" && rm -f "${_psfile}";
4472 test -f "${_TMP_CAT}" && rm -f "${_TMP_CAT}";
4474 clean_up() {
4475 rm -f "${_modefile}";
4476 if test -d "${_TMP_DIR}"; then
4477 rm -f "${_TMP_DIR}"/* || true;
4478 rmdir "${_TMP_DIR}";
4481 trap clean_up 0 2>/dev/null || true;
4482 eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "${_modefile}";
4483 ) &'
4486 case "${_OPT_DEVICE}" in
4487 ''|ps)
4488 do_nothing;
4491 warning \
4492 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4494 esac;
4495 _modefile="${_modefile}".ps;
4496 _groggy="$(tmp_cat | grog -Tps)";
4497 _do_display;
4499 source)
4500 tmp_cat;
4501 clean_up;
4504 case "${_OPT_DEVICE}" in
4506 _groggy="$(tmp_cat | grog -Z)";
4508 X*|ps)
4509 _groggy="$(tmp_cat | grog -T"${_OPT_DEVICE}" -Z)";
4512 warning \
4513 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4514 _groggy="$(tmp_cat | grog -Z)";
4516 esac;
4517 _do_display;
4520 error "unknown mode \`${_DISPLAY_MODE}'";
4522 esac;
4523 eval "${return_ok}";
4524 } # main_display()
4526 _do_display()
4528 func_check _do_display = 0 "$@";
4529 trap_clean;
4530 # start a new shell program for another process ID and better
4531 # cleaning-up of the temporary files.
4532 sh -c '
4533 set -e;
4534 test -f "${_modefile}" && rm -f "${_modefile}";
4535 cat "${_TMP_CAT}" | \
4536 eval "${_groggy}" "${_ADDOPTS_GROFF}" > "${_modefile}";
4537 rm -f "${_TMP_CAT}";
4539 clean_up() {
4540 if test -d "${_TMP_DIR}"; then
4541 rm -f "${_TMP_DIR}"/* || true;
4542 rmdir "${_TMP_DIR}";
4545 trap clean_up 0 2>/dev/null || true;
4546 eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "${_modefile}";
4547 ) &'
4551 ########################################################################
4552 # main (<command_line_args>*)
4554 # The main function for groffer.
4556 # Arguments:
4558 main()
4560 func_check main '>=' 0 "$@";
4561 # Do not change the sequence of the following functions!
4562 main_init;
4563 main_parse_MANOPT;
4564 main_parse_args "$@";
4565 main_set_mode;
4566 main_do_fileargs;
4567 main_set_resources;
4568 main_display;
4569 eval "${return_ok}";
4572 landmark '20: end of function definitions';
4574 ########################################################################
4576 main "$@";