* release of groffer 0.9.16
[s-roff.git] / contrib / groffer / groffer.sh
blob210a7ea599f84a38cc09b3f62212845b83623fc1
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.16';
29 _LAST_UPDATE='19 Jun 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}"_ = __;
38 then
39 # only reached during the first run of the script
41 export _groffer_run; # counter for the runs of groffer
42 _groffer_run='first';
44 export _PROGRAM_NAME;
45 export _PROGRAM_VERSION;
46 export _LAST_UPDATE;
48 export GROFFER_OPT; # option environment for groffer
49 export _GROFFER_SH; # file name of this shell script
50 export _OUTPUT_FILE_NAME; # output generated, see main_set_res..()
52 export _CONFFILES; # configuration files
53 _CONFFILES="/etc/groff/groffer.conf ${HOME}/.groff/groffer.conf";
55 case "$0" in
56 *${_PROGRAM_NAME}*)
57 _GROFFER_SH="$0";
58 # was: _GROFFER_SH="@BINDIR@/${_PROGRAM_NAME}";
61 echo "The ${_PROGRAM_NAME} script should be started directly." >&2
62 exit 1;
64 esac;
66 export _NULL_DEV;
67 if test -c /dev/null;
68 then
69 _NULL_DEV="/dev/null";
70 else
71 _NULL_DEV="NUL";
72 fi;
75 ###########################
76 # _get_opt_shell ("$@")
78 # Determine whether `--shell' was specified in $GROFF_OPT or in $*;
79 # if so echo its argument.
81 _get_opt_shell()
83 local i;
84 local _sh;
85 case " ${GROFFER_OPT} $*" in
86 *\ --shell\ *|*\ --shell=*)
88 eval set -- "${GROFFER_OPT}" '"$@"';
89 _sh='';
90 for i in "$@";
92 case "$1" in
93 --shell)
94 if test "$#" -ge 2;
95 then
96 _sh="$2";
97 shift;
98 fi;
100 --shell=?*)
101 # delete up to first `=' character
102 _sh="$(echo -n "$1" | sed -e 's/^[^=]*=//')";
104 esac;
105 shift;
106 done;
107 echo -n "${_sh}";
110 esac;
114 ###########################
115 # _test_on_shell (<name>)
117 # Test whether <name> is a shell program of Bourne type (POSIX sh).
119 _test_on_shell()
121 if test "$#" -le 0 || test _"$1"_ = __;
122 then
123 return 1;
125 # do not quote $1 to allow arguments
126 test _"$($1 -c 's=ok; echo -n "$s"' 2>${_NULL_DEV})"_ = _ok_;
129 # do the shell determination from command line and $GROFFER_OPT
130 _shell="$(_get_opt_shell "$@")";
132 if test _"${_shell}"_ = __;
133 then
134 # none found, so look at the `--shell' lines in configuration files
135 export f;
136 for f in ${_CONFFILES};
138 if test -f $f;
139 then
140 _all="$(cat $f | sed -n -e '/^--shell[= ] *\([^ ]*\)$/s//\1/p')"
141 for s in ${_all};
143 _shell=$s;
144 done;
146 done;
147 unset f;
148 unset s;
149 unset _all;
152 # restart the script with the last found $_shell, if it is a shell
153 if _test_on_shell "${_shell}";
154 then
155 _groffer_run='second';
156 # do not quote $_shell to allow arguments
157 exec ${_shell} "${_GROFFER_SH}" "$@";
158 exit;
161 _groffer_run='second';
162 unset _shell;
164 fi; # end of first run
166 if test _"${_groffer_run}"_ != _second_;
167 then
168 echo "$_groffer_run should be 'second' here." >&2
169 exit 1
172 unset _groffer_run
175 ########################################################################
176 # diagnostic messages
178 export _DEBUG;
179 _DEBUG='no'; # disable debugging information
180 #_DEBUG='yes'; # enable debugging information
182 export _DEBUG_LM;
183 _DEBUG_LM='no'; # disable landmark messages
184 #_DEBUG_LM='yes'; # enable landmark messages
187 ########################################################################
188 # Environment Variables
189 ########################################################################
191 # Environment variables that exist only for this file start with an
192 # underscore letter. Global variables to this file are written in
193 # upper case letters, e.g. $_GLOBAL_VARIABLE; temporary variables
194 # start with an underline and use only lower case letters and
195 # underlines, e.g. $_local_variable .
197 # [A-Z]* system variables, e.g. $MANPATH
198 # _[A-Z_]* global file variables, e.g. $_MAN_PATH
199 # _[a-z_]* temporary variables, e.g. $_manpath
201 # Due to incompatibilities of the `ash' shell, the name of loop
202 # variables in `for' must be single character
203 # [a-z] local loop variables, e.g. $i
206 ########################################################################
207 # read-only variables (global to this file)
208 ########################################################################
210 # characters
212 export _BQUOTE;
213 export _BSLASH;
214 export _DQUOTE;
215 export _NEWLINE;
216 export _LBRACK;
217 export _LPAR;
218 export _RBRACK;
219 export _RPAR;
220 export _SPACE;
221 export _SQUOTE;
222 export _TAB;
224 _BQUOTE='`';
225 _BSLASH='\';
226 _DQUOTE='"';
227 _NEWLINE='
229 _LBRACK='[';
230 _LPAR='(';
231 _RBRACK=']';
232 _RPAR=')';
233 _SPACE=' ';
234 _SQUOTE="'";
235 _TAB=' ';
237 # function return values; `0' means ok; other values are error codes
238 export _ALL_EXIT;
239 export _BAD;
240 export _ERROR;
241 export _GOOD;
242 export _NO;
243 export _OK;
244 export _YES;
246 _GOOD='0'; # return ok
247 _BAD='1'; # return negatively, error code `1'
248 _ERROR='7'; # for syntax errors; no `-1' in `ash'
250 _ALL_EXIT="${_GOOD} ${_BAD} ${_ERROR}"; # all exit codes (for `trap_set')
252 _NO="${_BAD}";
253 _YES="${_GOOD}";
254 _OK="${_GOOD}";
256 # quasi-functions, call with `eval'
257 export return_ok;
258 export return_good;
259 export return_bad;
260 export return_yes;
261 export return_no;
262 export return_error;
263 return_ok="func_pop; return ${_OK}";
264 return_good="func_pop; return ${_GOOD}";
265 return_bad="func_pop; return ${_BAD}";
266 return_yes="func_pop; return ${_YES}";
267 return_no="func_pop; return ${_NO}";
268 return_error="func_pop; return ${_ERROR}";
271 export _DEFAULT_MODES;
272 _DEFAULT_MODES='x,ps,tty';
273 export _DEFAULT_RESOLUTION;
274 _DEFAULT_RESOLUTION='75';
276 export _DEFAULT_TTY_DEVICE;
277 _DEFAULT_TTY_DEVICE='latin1';
279 # _VIEWER_* viewer programs for different modes (only X is necessary)
280 # _VIEWER_* a comma-separated list of viewer programs (with options)
281 export _VIEWER_DVI; # viewer program for dvi mode
282 export _VIEWER_PS; # viewer program for ps mode
283 export _VIEWER_HTML_X; # viewer program for html mode in X
284 export _VIEWER_HTML_TTY; # viewer program for html mode in tty
285 _VIEWER_DVI='kdvi,xdvi,dvilx';
286 _VIEWER_PDF='kghostview,ggv,xpdf,acroread,kpdf';
287 _VIEWER_PS='kghostview,ggv,gv,ghostview,gs_x11,gs';
288 _VIEWER_HTML='konqueror,mozilla,netscape,opera,amaya,arena,lynx';
289 _VIEWER_X='gxditview,xditview';
291 # Search automatically in standard sections `1' to `8', and in the
292 # traditional sections `9', `n', and `o'. On many systems, there
293 # exist even more sections, mostly containing a set of man pages
294 # special to a specific program package. These aren't searched for
295 # automatically, but must be specified on the command line.
296 export _MAN_AUTO_SEC;
297 _MAN_AUTO_SEC="'1' '2' '3' '4' '5' '6' '7' '8' '9' 'n' 'o'"
299 export _PROCESS_ID; # for shutting down the program
300 _PROCESS_ID="$$";
303 ############ the command line options of the involved programs
305 # The naming scheme for the options environment names is
306 # $_OPTS_<prog>_<length>[_<argspec>]
308 # <prog>: program name GROFFER, GROFF, or CMDLINE (for all
309 # command line options)
310 # <length>: LONG (long options) or SHORT (single character options)
311 # <argspec>: ARG for options with argument, NA for no argument;
312 # without _<argspec> both the ones with and without arg.
314 # Each option that takes an argument must be specified with a
315 # trailing : (colon).
317 # exports
318 export _OPTS_GROFFER_SHORT_NA;
319 export _OPTS_GROFFER_SHORT_ARG;
320 export _OPTS_GROFFER_LONG_NA;
321 export _OPTS_GROFFER_LONG_ARG;
322 export _OPTS_GROFF_SHORT_NA;
323 export _OPTS_GROFF_SHORT_ARG;
324 export _OPTS_GROFF_LONG_NA;
325 export _OPTS_GROFF_LONG_ARG;
326 export _OPTS_X_SHORT_ARG;
327 export _OPTS_X_SHORT_NA;
328 export _OPTS_X_LONG_ARG;
329 export _OPTS_X_LONG_NA;
330 export _OPTS_MAN_SHORT_ARG;
331 export _OPTS_MAN_SHORT_NA;
332 export _OPTS_MAN_LONG_ARG;
333 export _OPTS_MAN_LONG_NA;
334 export _OPTS_MANOPT_SHORT_ARG;
335 export _OPTS_MANOPT_SHORT_NA;
336 export _OPTS_MANOPT_LONG_ARG;
337 export _OPTS_MANOPT_LONG_NA;
338 export _OPTS_CMDLINE_SHORT_NA;
339 export _OPTS_CMDLINE_SHORT_ARG;
340 export _OPTS_CMDLINE_LONG_NA;
341 export _OPTS_CMDLINE_LONG_ARG;
343 ###### groffer native options
345 _OPTS_GROFFER_SHORT_NA="'h' 'Q' 'v' 'V' 'X' 'Z'";
346 _OPTS_GROFFER_SHORT_ARG="'T'";
348 _OPTS_GROFFER_LONG_NA="'auto' 'debug' 'default' 'dvi' \
349 'groff' 'help' 'intermediate-output' 'html' 'man' \
350 'no-location' 'no-man' 'pdf' 'ps' 'rv' 'source' 'text' 'text-device' \
351 'title' 'tty' 'tty-device' 'version' 'whatis' 'where' 'www' 'x' 'X'";
353 _OPTS_GROFFER_LONG_ARG="\
354 'apropos' 'apropos-data' 'apropos-devel' 'apropos-progs' \
355 'default-modes' 'device' 'dvi-viewer' 'extension' 'fg' 'fn' 'font' \
356 'foreground' 'html-viewer' 'mode' 'pdf-viewer' 'ps-viewer' 'shell' \
357 'tty-viewer' 'www-viewer' 'x-viewer' 'X-viewer'";
359 ##### groffer options inhereted from groff
361 _OPTS_GROFF_SHORT_NA="'a' 'b' 'c' 'C' 'e' 'E' 'g' 'G' 'i' 'l' 'N' 'p' \
362 'R' 's' 'S' 't' 'U' 'z'";
363 _OPTS_GROFF_SHORT_ARG="'d' 'f' 'F' 'I' 'L' 'm' 'M' 'n' 'o' 'P' 'r' \
364 'w' 'W'";
365 _OPTS_GROFF_LONG_NA="";
366 _OPTS_GROFF_LONG_ARG="";
368 ##### groffer options inhereted from the X Window toolkit
370 _OPTS_X_SHORT_NA="";
371 _OPTS_X_SHORT_ARG="";
373 _OPTS_X_LONG_NA="'iconic' 'rv'";
375 _OPTS_X_LONG_ARG="'background' 'bd' 'bg' 'bordercolor' 'borderwidth' \
376 'bw' 'display' 'fg' 'fn' 'font' 'foreground' 'ft', 'geometry'
377 'resolution' 'title' 'xrm'";
379 ###### groffer options inherited from man
381 _OPTS_MAN_SHORT_NA="";
382 _OPTS_MAN_SHORT_ARG="";
384 _OPTS_MAN_LONG_NA="'all' 'ascii' 'catman' 'debug' 'ditroff' 'help' \
385 'local-file' 'location' 'pager' 'troff' 'update' 'version' \
386 'whatis' 'where'";
388 _OPTS_MAN_LONG_ARG="'extension' 'locale' 'manpath' \
389 'pager' 'preprocessor' 'prompt' 'sections' 'systems' 'troff-device'";
391 ###### additional options for parsing $MANOPT only
393 _OPTS_MANOPT_SHORT_NA="'7' 'a' 'c' 'd' 'D' 'f' 'h' 'k' 'l' 't' 'u' \
394 'V' 'w' 'Z'";
395 _OPTS_MANOPT_SHORT_ARG="'e' 'L' 'm' 'M' 'p' 'P' 'r' 'S' 'T'";
397 _OPTS_MANOPT_LONG_NA="${_OPTS_MAN_LONG_NA} \
398 'apropos' 'debug' 'default' 'html' 'ignore-case' 'location-cat' \
399 'match-case' 'troff' 'update' 'version' 'where-cat'";
401 _OPTS_MANOPT_LONG_ARG="${_OPTS_MAN_LONG_NA} \
402 'config_file' 'encoding' 'locale'";
404 ###### collections of command line options
406 _OPTS_CMDLINE_SHORT_NA="${_OPTS_GROFFER_SHORT_NA}\
407 ${_OPTS_GROFF_SHORT_NA} ${_OPTS_X_SHORT_NA} ${_OPTS_MAN_SHORT_NA}";
408 _OPTS_CMDLINE_SHORT_ARG="${_OPTS_GROFFER_SHORT_ARG} \
409 ${_OPTS_GROFF_SHORT_ARG} ${_OPTS_X_SHORT_ARG} ${_OPTS_MAN_SHORT_ARG}";
411 _OPTS_CMDLINE_LONG_NA="${_OPTS_GROFFER_LONG_NA} \
412 ${_OPTS_GROFF_LONG_NA} ${_OPTS_X_LONG_NA} ${_OPTS_MAN_LONG_NA}";
413 _OPTS_CMDLINE_LONG_ARG="${_OPTS_GROFFER_LONG_ARG} \
414 ${_OPTS_GROFF_LONG_ARG} ${_OPTS_MAN_LONG_ARG} ${_OPTS_X_LONG_ARG}";
417 ########################################################################
418 # read-write variables (global to this file)
419 ########################################################################
421 export _ADDOPTS_GROFF; # Transp. options for groff (`eval').
422 export _ADDOPTS_POST; # Transp. options postproc (`eval').
423 export _ADDOPTS_X; # Transp. options X postproc (`eval').
424 export _DEFAULT_MODES; # Set default modes.
425 export _DISPLAY_MODE; # Display mode.
426 export _DISPLAY_PROG; # Viewer program to be used for display.
427 export _DISPLAY_ARGS; # X resources for the viewer program.
428 export _FILEARGS; # Stores filespec parameters.
429 export _FUNC_STACK; # Store debugging information.
430 export _REGISTERED_TITLE; # Processed file names.
431 # _HAS_* from availability tests
432 export _HAS_COMPRESSION; # `yes' if compression is available
433 export _HAS_OPTS_GNU; # `yes' if GNU `getopt' is available
434 export _HAS_OPTS_POSIX; # `yes' if POSIX `getopts' is available
435 # _MAN_* finally used configuration of man searching
436 export _MAN_ALL; # search all man pages per filespec
437 export _MAN_ENABLE; # enable search for man pages
438 export _MAN_EXT; # extension for man pages
439 export _MAN_FORCE; # force file parameter to be man pages
440 export _MAN_IS_SETUP; # setup man variables only once
441 export _MAN_LANG; # language for man pages
442 export _MAN_LANG_DONE; # language dirs added to man path
443 export _MAN_PATH; # search path for man pages
444 export _MAN_SEC; # sections for man pages; sep. `:'
445 export _MAN_SEC_DONE; # sections added to man path
446 export _MAN_SYS; # system names for man pages; sep. `,'
447 export _MAN_SYS; # system names added to man path
448 # _MANOPT_* as parsed from $MANOPT
449 export _MANOPT_ALL; # $MANOPT --all
450 export _MANOPT_EXTENSION; # $MANOPT --extension
451 export _MANOPT_LANG; # $MANOPT --locale
452 export _MANOPT_PATH; # $MANOPT --manpath
453 export _MANOPT_PAGER; # $MANOPT --pager
454 export _MANOPT_SEC; # $MANOPT --sections
455 export _MANOPT_SYS; # $MANOPT --systems
456 # _OPT_* as parsed from groffer command line
457 export _OPT_ALL; # display all suitable man pages.
458 export _OPT_APROPOS; # call `apropos' program.
459 export _OPT_APROPOS_DATA; # `apropos' for man sections 4, 5, 7
460 export _OPT_APROPOS_DEVEL; # `apropos' for man sections 2, 3, 9
461 export _OPT_APROPOS_PROGS; # `apropos' for man sections 1, 6, 8
462 export _OPT_BD; # set border color in some modes.
463 export _OPT_BG; # set background color in some modes.
464 export _OPT_BW; # set border width in some modes.
465 export _OPT_DEBUG; # print debugging information on stderr.
466 export _OPT_DEFAULT_MODES; # `,'-list of modes when no mode given.
467 export _OPT_DEVICE; # device option.
468 export _OPT_DISPLAY; # set X display.
469 export _OPT_FG; # set foreground color in some modes.
470 export _OPT_FN; # set font in some modes.
471 export _OPT_GEOMETRY; # set size and position of viewer in X.
472 export _OPT_ICONIC; # -iconic option for X viewers.
473 export _OPT_LANG; # set language for man pages
474 export _OPT_LOCATION; # print processed file names to stderr
475 export _OPT_MODE; # values: X, tty, Q, Z, ""
476 export _OPT_MANPATH; # manual setting of path for man-pages
477 export _OPT_PAGER; # specify paging program for tty mode
478 export _OPT_RESOLUTION; # set X resolution in dpi
479 export _OPT_RV; # reverse fore- and background colors.
480 export _OPT_SECTIONS; # sections for man page search
481 export _OPT_SYSTEMS; # man pages of different OS's
482 export _OPT_TITLE; # title for gxditview window
483 export _OPT_TEXT_DEVICE; # set device for tty mode.
484 export _OPT_V; # groff option -V.
485 export _OPT_VIEWER_DVI; # viewer program for dvi mode
486 export _OPT_VIEWER_PDF; # viewer program for pdf mode
487 export _OPT_VIEWER_PS; # viewer program for ps mode
488 export _OPT_VIEWER_HTML; # viewer program for html mode
489 export _OPT_VIEWER_X; # viewer program for x mode
490 export _OPT_WHATIS; # print the one-liner man info
491 export _OPT_XRM; # specify X resource.
492 export _OPT_Z; # groff option -Z.
493 # _TMP_* temporary files
494 export _TMP_DIR; # groffer directory for temporary files
495 export _TMP_CAT; # stores concatenation of everything
496 export _TMP_STDIN; # stores stdin, if any
498 # these variables are preset in section `Preset' after the rudim. test
501 ########################################################################
502 # Test of rudimentary shell functionality
503 ########################################################################
506 ########################################################################
507 # Test of `test'.
509 test "a" = "a" || exit 1;
512 ########################################################################
513 # Test of `echo' and the `$()' construct.
515 echo -n '' >${_NULL_DEV} || exit "${_ERROR}";
516 if test _"$(echo -n 'te' && echo -n '' && echo -n 'st')"_ != _test_;
517 then
518 exit "${_ERROR}";
522 ########################################################################
523 # Test of function definitions.
525 _t_e_s_t_f_u_n_c_()
527 return "${_OK}";
530 if _t_e_s_t_f_u_n_c_ 2>${_NULL_DEV};
531 then
533 else
534 echo 'shell does not support function definitions.' >&2;
535 exit "${_ERROR}";
539 ########################################################################
540 # Preset and reset of read-write global variables
541 ########################################################################
544 # For variables that can be reset by option `--default', see reset().
546 _FILEARGS='';
548 # _HAS_* from availability tests
549 _HAS_COMPRESSION='';
550 _HAS_OPTS_GNU='';
551 _HAS_OPTS_POSIX='';
553 # _TMP_* temporary files
554 _TMP_DIR='';
555 _TMP_CAT='';
556 _TMP_STDIN='';
559 ########################################################################
560 # reset ()
562 # Reset the variables that can be affected by options to their default.
564 reset()
566 if test "$#" -ne 0;
567 then
568 error "reset() does not have arguments.";
571 _ADDOPTS_GROFF='';
572 _ADDOPTS_POST='';
573 _ADDOPTS_X='';
574 _DISPLAY_ARGS='';
575 _DISPLAY_MODE='';
576 _DISPLAY_PROG='';
577 _REGISTERED_TITLE='';
579 # _MAN_* finally used configuration of man searching
580 _MAN_ALL='no';
581 _MAN_ENABLE='yes'; # do search for man-pages
582 _MAN_EXT='';
583 _MAN_FORCE='no'; # first local file, then search man page
584 _MAN_IS_SETUP='no';
585 _MAN_LANG='';
586 _MAN_LANG_DONE='no';
587 _MAN_PATH='';
588 _MAN_SEC='';
589 _MAN_SEC_DONE='no';
590 _MAN_SYS='';
591 _MAN_SYS_DONE='no';
593 # _MANOPT_* as parsed from $MANOPT
594 _MANOPT_ALL='no';
595 _MANOPT_EXTENSION='';
596 _MANOPT_LANG='';
597 _MANOPT_PATH='';
598 _MANOPT_PAGER='';
599 _MANOPT_SEC='';
600 _MANOPT_SYS='';
602 # _OPT_* as parsed from groffer command line
603 _OPT_ALL='no';
604 _OPT_APROPOS='';
605 _OPT_APROPOS_DATA='';
606 _OPT_APROPOS_DEVEL='';
607 _OPT_APROPOS_PROGS='';
608 _OPT_BD='';
609 _OPT_BG='';
610 _OPT_BW='';
611 _OPT_DEBUG='no';
612 _OPT_DEFAULT_MODES='';
613 _OPT_DEVICE='';
614 _OPT_DISPLAY='';
615 _OPT_FG='';
616 _OPT_FN='';
617 _OPT_GEOMETRY='';
618 _OPT_ICONIC='no';
619 _OPT_LANG='';
620 _OPT_LOCATION='no';
621 _OPT_MODE='';
622 _OPT_MANPATH='';
623 _OPT_PAGER='';
624 _OPT_RESOLUTION='';
625 _OPT_RV='no';
626 _OPT_SECTIONS='';
627 _OPT_SYSTEMS='';
628 _OPT_TITLE='';
629 _OPT_TEXT_DEVICE='';
630 _OPT_V='no';
631 _OPT_VIEWER_DVI='';
632 _OPT_VIEWER_PDF='';
633 _OPT_VIEWER_PS='';
634 _OPT_VIEWER_HTML='';
635 _OPT_VIEWER_X='';
636 _OPT_WHATIS='no';
637 _OPT_XRM='';
638 _OPT_Z='no';
642 reset;
645 ########################################################################
646 # Functions for error handling and debugging
647 ########################################################################
650 ##############
651 # landmark (<text>)
653 # Print <text> to standard error as a debugging aid.
655 # Globals: $_DEBUG_LM
657 landmark()
659 if test _"${_DEBUG_LM}"_ = _yes_;
660 then
661 echo ">>> $*" >&2;
665 landmark "1: debugging functions";
668 ##############
669 # clean_up ()
671 # Clean up at exit.
673 clean_up()
675 if test -d "${_TMP_DIR}";
676 then
677 rm -f -r "${_TMP_DIR}";
682 ##############
683 # echo2 (<text>*)
685 # Output to stderr.
687 # Arguments : arbitrary text.
689 echo2()
691 echo "$*" >&2;
695 ##############
696 # echo2n (<text>*)
698 # Output to stderr.
700 # Arguments : arbitrary text.
702 echo2n()
704 echo -n "$*" >&2;
708 #############
709 # diag (text>*)
711 # Output a diagnostic message to stderr
713 diag()
715 echo2 '>>>>>'"$*";
719 #############
720 # error (<text>*)
722 # Print an error message to standard error; exit with an error condition
724 error()
726 local i;
727 local _code;
728 _code="${_ERROR}";
729 case "$#" in
730 0) true; ;;
731 1) echo2 'groffer error: '"$1"; ;;
733 echo2 'groffer error: '"$1";
734 _code="$2";
736 *) echo2 'groffer error: wrong number of arguments in error().'; ;;
737 esac;
738 if test _"${_DEBUG}"_ = _yes_;
739 then
740 func_stack_dump;
742 clean_up;
743 kill "${_PROCESS_ID}" >${_NULL_DEV} 2>&1;
744 kill -9 "${_PROCESS_ID}" >${_NULL_DEV} 2>&1;
745 exit "${_code}";
749 #############
750 # abort (<text>*)
752 # Terminate program with error condition
754 abort()
756 error "Program aborted.";
757 exit 1;
761 #############
762 # func_check (<func_name> <rel_op> <nr_args> "$@")
764 # Check number of arguments and register to _FUNC_STACK.
766 # Arguments: >=3
767 # <func_name>: name of the calling function.
768 # <rel_op>: a relational operator: = != < > <= >=
769 # <nr_args>: number of arguments to be checked against <operator>
770 # "$@": the arguments of the calling function.
772 func_check()
774 local _comp;
775 local _fname;
776 local _nargs;
777 local _op;
778 local _s;
779 if test "$#" -lt 3;
780 then
781 error 'func_check() needs at least 3 arguments.';
783 _fname="$1";
784 case "$3" in
786 _nargs="$3";
787 _s='';
789 0|[2-9])
790 _nargs="$3";
791 _s='s';
794 error "func_check(): third argument must be a digit.";
796 esac;
797 case "$2" in
798 '='|'-eq')
799 _op='-eq';
800 _comp='exactly';
802 '>='|'-ge')
803 _op='-ge';
804 _comp='at least';
806 '<='|'-le')
807 _op='-le';
808 _comp='at most';
810 '<'|'-lt')
811 _op='-lt';
812 _comp='less than';
814 '>'|'-gt')
815 _op='-gt';
816 _comp='more than';
818 '!='|'-ne')
819 _op='-ne';
820 _comp='not';
823 error \
824 'func_check(): second argument is not a relational operator.';
826 esac;
827 shift 3;
828 if test "$#" "${_op}" "${_nargs}";
829 then
830 do_nothing;
831 else
832 error \
833 "${_fname}"'() needs '"${_comp} ${_nargs}"' argument'"${_s}"'.';
835 if test _"${_DEBUG}"_ = _yes_;
836 then
837 func_push "${_fname} $*";
842 #############
843 # func_pop ()
845 # Retrieve the top element from the stack.
847 # The stack elements are separated by `!'; the popped element is
848 # identical to the original element, except that all `!' characters
849 # were removed.
851 # Arguments: 1
853 func_pop()
855 if test _"${_DEBUG}"_ = _yes_;
856 then
857 if test "$#" -ne 0;
858 then
859 error 'func_pop() does not have arguments.';
861 case "${_FUNC_STACK}" in
863 error 'func_pop(): stack is empty.';
865 *!*)
866 # split at first bang `!'.
867 _FUNC_STACK="$(echo -n ${_FUNC_STACK} \
868 | sed -e 's/^[^!]*!//')";
871 _FUNC_STACK='';
873 esac;
878 #############
879 # func_push (<element>)
881 # Store another element to stack.
883 # The stack elements are separated by `!'; if <element> contains a `!'
884 # it is removed first.
886 # Arguments: 1
888 func_push()
890 local _element;
891 if test _"${_DEBUG}"_ = _yes_;
892 then
893 if test "$#" -ne 1;
894 then
895 error 'func_push() needs 1 argument.';
897 case "$1" in
898 *'!'*)
899 # remove all bangs `!'.
900 _element="$(echo -n "$1" | sed -e 's/!//g')";
903 _element="$1";
905 esac;
906 if test _"${_FUNC_STACK}"_ = __;
907 then
908 _FUNC_STACK="${_element}";
909 else
910 _FUNC_STACK="${_element}!${_FUNC_STACK}";
916 #############
917 # func_stack_dump ()
919 # Print the content of the stack. Ignore the arguments.
921 func_stack_dump()
923 diag 'call stack:';
924 case "${_FUNC_STACK}" in
925 *!*)
926 _rest="${_FUNC_STACK}";
927 while test _"${_rest}"_ != __;
929 # get part before the first bang `!'.
930 diag "$(echo -n "${_rest}" | sed -e 's/!.*$//')";
931 # delete part before and including the first bang `!'.
932 _rest="$(echo -n "${_rest}" | sed -e 's/^[^!]*!//')";
933 done;
936 diag "${_FUNC_STACK}";
938 esac;
942 ########################################################################
943 # System Test
944 ########################################################################
946 landmark "2: system test";
948 # Test the availability of the system utilities used in this script.
951 ########################################################################
952 # Test of `true'.
954 if true >${_NULL_DEV} 2>&1;
955 then
956 true;
957 else
958 true()
960 return "${_GOOD}";
963 false()
965 return "${_BAD}";
970 ########################################################################
971 # Test of `unset'.
973 _test='test';
974 if unset _test >${_NULL_DEV} 2>&1 && test _"${_test}"_ = __;
975 then
976 true;
977 else
978 unset()
980 for v in "$@";
982 eval "$v"='';
983 done;
986 unset _test;
988 ########################################################################
989 # Test of builtin `local'
992 _t_e_s_t_f_u_n_c_()
994 local _test >${_NULL_DEV} 2>&1 || return "${_BAD}";
997 if _t_e_s_t_f_u_n_c_;
998 then
1000 else
1001 local()
1003 if test _"$1"_ != __;
1004 then
1005 error "overriding global variable \`$1' with local value.";
1011 ########################################################################
1012 # Test of global setting in functions
1014 _global='outside';
1015 _clobber='outside';
1017 _t_e_s_t_f_u_n_c_()
1019 local _clobber;
1020 _global='inside';
1021 _clobber='inside';
1024 _t_e_s_t_f_u_n_c_;
1025 if test _"${_global}"_ != _inside_ || test _"${_clobber}"_ != _outside_;
1026 then
1027 error "Cannot assign to global variables from within functions.";
1030 unset _global;
1031 unset _clobber;
1034 ########################################################################
1035 # Test of function `sed'.
1038 if test _"$(echo xTesTx \
1039 | sed -e 's/^.\([Tt]e*x*sTT*\).*$/\1/' \
1040 | sed -e '\|T|s|T|t|g')"_ != _test_;
1041 then
1042 error 'Test of "sed" command failed.';
1046 ########################################################################
1047 # Test of function `cat'.
1049 if test _"$(echo test | cat)"_ != _test_;
1050 then
1051 error 'Test of "cat" command failed.';
1055 ########################################################################
1056 # Test for compression.
1058 if test _"$(echo 'test' | gzip -c -d -f - 2>${_NULL_DEV})"_ = _test_;
1059 then
1060 _HAS_COMPRESSION='yes';
1061 if echo 'test' | bzip2 -c 2>${_NULL_DEV} | bzip2 -t 2>${_NULL_DEV} \
1062 && test _"$(echo 'test' | bzip2 -c 2>${_NULL_DEV} \
1063 | bzip2 -d -c 2>${_NULL_DEV})"_ \
1064 = _test_;
1065 then
1066 _HAS_BZIP='yes';
1067 else
1068 _HAS_BZIP='no';
1070 else
1071 _HAS_COMPRESSION='no';
1072 _HAS_BZIP='no';
1076 ########################################################################
1077 _t_e_s_t_f_u_n_c_()
1083 ########################################################################
1084 # Definition of normal Functions in alphabetical order
1085 ########################################################################
1086 landmark "3: functions";
1088 ########################################################################
1089 # abort (<text>*)
1091 # Unconditionally terminate the program with error code;
1092 # useful for debugging.
1094 # defined above
1097 ########################################################################
1098 # apropos_run (<name>)
1101 apropos_run() {
1102 func_check apropos_run = 1 "$@";
1103 if apropos apropos >${_NULL_DEV} 2>${_NULL_DEV};
1104 then
1105 apropos "$1";
1106 elif man --apropos man >${_NULL_DEV} 2>${_NULL_DEV};
1107 then
1108 man --apropos "$1";
1109 elif man -k man >${_NULL_DEV} 2>${_NULL_DEV};
1110 then
1111 man -k "$1";
1116 ########################################################################
1117 # base_name (<path>)
1119 # Get the file name part of <path>, i.e. delete everything up to last
1120 # `/' from the beginning of <path>. Remove final slashes, too, to get a
1121 # non-empty output.
1123 # Arguments : 1
1124 # Output : the file name part (without slashes)
1126 base_name()
1128 func_check base_name = 1 "$@";
1129 local f;
1130 f="$1";
1131 case "$f" in
1133 # delete all final slashes
1134 f="$(echo -n "$f" | sed -e '\|.*|s|//*$||')";
1136 esac;
1137 case "$f" in
1138 /|'')
1139 eval "${return_bad}";
1141 */*)
1142 # delete everything before and including the last slash `/'.
1143 echo -n "$f" | sed -e '\|.*|s|^.*//*\([^/]*\)$|\1|';
1146 echo -n "$f";
1148 esac;
1149 eval "${return_ok}";
1153 ########################################################################
1154 # catz (<file>)
1156 # Decompress if possible or just print <file> to standard output.
1158 # gzip, bzip2, and .Z decompression is supported.
1160 # Arguments: 1, a file name.
1161 # Output: the content of <file>, possibly decompressed.
1163 if test _"${_HAS_COMPRESSION}"_ = _yes_;
1164 then
1165 catz()
1167 func_check catz = 1 "$@";
1168 case "$1" in
1170 error 'catz(): empty file name';
1172 '-')
1173 error 'catz(): for standard input use save_stdin()';
1175 esac;
1176 if obj _HAS_BZIP is_yes;
1177 then
1178 if bzip2 -t "$1" 2>${_NULL_DEV};
1179 then
1180 bzip2 -c -d "$1" 2>${_NULL_DEV};
1181 eval "${return_ok}";
1184 gzip -c -d -f "$1" 2>${_NULL_DEV};
1185 eval "${return_ok}";
1187 else
1188 catz()
1190 func_check catz = 1 "$@";
1191 cat "$1";
1192 eval "${return_ok}";
1197 ########################################################################
1198 # clean_up ()
1200 # Do the final cleaning up before exiting; used by the trap calls.
1202 # defined above
1205 ########################################################################
1206 # diag (<text>*)
1208 # Print marked message to standard error; useful for debugging.
1210 # defined above
1213 ########################################################################
1214 landmark '4: dirname()*';
1215 ########################################################################
1217 #######################################################################
1218 # dirname_append (<dir> <name>)
1220 # Append `name' to `dir' with clean handling of `/'.
1222 # Arguments : 2
1223 # Output : the generated new directory name <dir>/<name>
1225 dirname_append()
1227 func_check dirname_append = 2 "$@";
1228 local _res;
1229 if is_empty "$1";
1230 then
1231 error "dir_append(): first argument is empty.";
1233 if is_empty "$2";
1234 then
1235 echo -n "$1";
1236 else
1237 dirname_chop "$1"/"$2";
1239 eval "${return_ok}";
1243 ########################################################################
1244 # dirname_chop (<name>)
1246 # Remove unnecessary slashes from directory name.
1248 # Argument: 1, a directory name.
1249 # Output: path without double, or trailing slashes.
1251 dirname_chop()
1253 func_check dirname_chop = 1 "$@";
1254 local _arg;
1255 local _res;
1256 local _sep;
1257 # replace all multiple slashes by a single slash `/'.
1258 _res="$(echo -n "$1" | sed -e '\|.*|s|///*|/|g')";
1259 case "${_res}" in
1260 ?*/)
1261 # remove trailing slash '/';
1262 echo -n "${_res}" | sed -e '\|.*|s|/$||';
1264 *) echo -n "${_res}"; ;;
1265 esac;
1266 eval "${return_ok}";
1270 ########################################################################
1271 # do_filearg (<filearg>)
1273 # Append the file, man-page, or standard input corresponding to the
1274 # argument to the temporary file. If this is compressed in the gzip
1275 # or Z format it is decompressed. A title element is generated.
1277 # Argument either:
1278 # - name of an existing files.
1279 # - `-' to represent standard input (several times allowed).
1280 # - `man:name.(section)' the man-page for `name' in `section'.
1281 # - `man:name.section' the man-page for `name' in `section'.
1282 # - `man:name' the man-page for `name' in the lowest `section'.
1283 # - `name.section' the man-page for `name' in `section'.
1284 # - `name' the man-page for `name' in the lowest `section'.
1285 # Globals :
1286 # $_TMP_STDIN, $_MAN_ENABLE, $_MAN_IS_SETUP, $_OPT_MAN
1288 # Output : none
1289 # Return : $_GOOD if found, ${_BAD} otherwise.
1291 do_filearg()
1293 func_check do_filearg = 1 "$@";
1294 local _filespec;
1295 local i;
1296 _filespec="$1";
1297 # store sequence into positional parameters
1298 case "${_filespec}" in
1300 eval "${return_good}";
1302 '-')
1303 register_file '-';
1304 eval "${return_good}";
1306 */*) # with directory part; so no man search
1307 set -- 'File';
1310 if obj _MAN_ENABLE is_yes;
1311 then
1312 if obj _MAN_FORCE is_yes;
1313 then
1314 set -- 'Manpage' 'File';
1315 else
1316 set -- 'File' 'Manpage';
1318 else
1319 set -- 'File';
1322 esac;
1323 for i in "$@";
1325 case "$i" in
1326 File)
1327 if test -f "${_filespec}";
1328 then
1329 if test -r "${_filespec}";
1330 then
1331 register_file "${_filespec}";
1332 eval "${return_good}";
1333 else
1334 echo2 "could not read \`${_filespec}'";
1335 eval "${return_bad}";
1337 else
1338 continue;
1341 Manpage) # parse filespec as man page
1342 if obj _MAN_IS_SETUP is_not_yes;
1343 then
1344 man_setup;
1346 if man_do_filespec "${_filespec}";
1347 then
1348 eval "${return_good}";
1349 else
1350 continue;
1353 esac;
1354 done;
1355 eval "${return_bad}";
1356 } # do_filearg()
1359 ########################################################################
1360 # do_nothing ()
1362 # Dummy function.
1364 do_nothing()
1366 return "${_OK}";
1370 ########################################################################
1371 # echo2 (<text>*)
1373 # Print to standard error with final line break.
1375 # defined above
1378 ########################################################################
1379 # echo2n (<text>*)
1381 # Print to standard error without final line break.
1383 # defined above
1386 ########################################################################
1387 # error (<text>*)
1389 # Print error message and exit with error code.
1391 # defined above
1394 ########################################################################
1395 # func_check (<func_name> <rel_op> <nr_args> "$@")
1397 # Check number of arguments and register to _FUNC_STACK.
1399 # Arguments: >=3
1400 # <func_name>: name of the calling function.
1401 # <rel_op>: a relational operator: = != < > <= >=
1402 # <nr_args>: number of arguments to be checked against <operator>
1403 # "$@": the arguments of the calling function.
1405 # defined above
1407 #########################################################################
1408 # func_pop ()
1410 # Delete the top element from the function call stack.
1412 # defined above
1415 ########################################################################
1416 # func_push (<element>)
1418 # Store another element to function call stack.
1420 # defined above
1423 ########################################################################
1424 # func_stack_dump ()
1426 # Print the content of the stack.
1428 # defined above
1431 ########################################################################
1432 # get_first_essential (<arg>*)
1434 # Retrieve first non-empty argument.
1436 # Return : `1' if all arguments are empty, `0' if found.
1437 # Output : the retrieved non-empty argument.
1439 get_first_essential()
1441 func_check get_first_essential '>=' 0 "$@";
1442 local i;
1443 if is_equal "$#" 0;
1444 then
1445 eval "${return_ok}";
1447 for i in "$@";
1449 if obj i is_not_empty;
1450 then
1451 echo -n "$i";
1452 eval "${return_ok}";
1454 done;
1455 eval "${return_bad}";
1459 ########################################################################
1460 landmark '5: is_*()';
1461 ########################################################################
1463 ########################################################################
1464 # is_dir (<name>)
1466 # Test whether `name' is a directory.
1468 # Arguments : 1
1469 # Return : `0' if arg1 is a directory, `1' otherwise.
1471 is_dir()
1473 func_check is_dir = 1 "$@";
1474 if test -d "$1" && test -r "$1";
1475 then
1476 eval "${return_yes}";
1478 eval "${return_no}";
1482 ########################################################################
1483 # is_empty (<string>)
1485 # Test whether `string' is empty.
1487 # Arguments : <=1
1488 # Return : `0' if arg1 is empty or does not exist, `1' otherwise.
1490 is_empty()
1492 func_check is_empty = 1 "$@";
1493 if test _"$1"_ = __;
1494 then
1495 eval "${return_yes}";
1497 eval "${return_no}";
1501 ########################################################################
1502 # is_equal (<string1> <string2>)
1504 # Test whether `string1' is equal to <string2>.
1506 # Arguments : 2
1507 # Return : `0' both arguments are equal strings, `1' otherwise.
1509 is_equal()
1511 func_check is_equal = 2 "$@";
1512 if test _"$1"_ = _"$2"_;
1513 then
1514 eval "${return_yes}";
1516 eval "${return_no}";
1520 ########################################################################
1521 # is_existing (<name>)
1523 # Test whether `name' is an existing file or directory.
1525 # Arguments : 1
1526 # Return : `0' if arg1 exists, `1' otherwise.
1528 is_existing()
1530 func_check is_existing = 1 "$@";
1531 if test -e "$1";
1532 then
1533 eval "${return_yes}";
1535 eval "${return_no}";
1539 ########################################################################
1540 # is_file (<name>)
1542 # Test whether `name' is a readable file.
1544 # Arguments : 1
1545 # Return : `0' if arg1 is a readable file, `1' otherwise.
1547 is_file()
1549 func_check is_file = 1 "$@";
1550 if test -f "$1" && test -r "$1";
1551 then
1552 eval "${return_yes}";
1554 eval "${return_no}";
1558 ########################################################################
1559 # is_non_empty_file (<file_name>)
1561 # Test whether `file_name' is a non-empty existing file.
1563 # Arguments : <=1
1564 # Return :
1565 # `0' if arg1 is a non-empty existing file
1566 # `1' otherwise
1568 is_non_empty_file()
1570 func_check is_non_empty_file = 1 "$@";
1571 if is_file "$1" && test -s "$1";
1572 then
1573 eval "${return_yes}";
1575 eval "${return_no}";
1579 ########################################################################
1580 # is_not_dir (<name>)
1582 # Test whether `name' is not a readable directory.
1584 # Arguments : 1
1585 # Return : `0' if arg1 is a directory, `1' otherwise.
1587 is_not_dir()
1589 func_check is_not_dir = 1 "$@";
1590 if is_dir "$1";
1591 then
1592 eval "${return_no}";
1594 eval "${return_yes}";
1598 ########################################################################
1599 # is_not_empty (<string>)
1601 # Test whether `string' is not empty.
1603 # Arguments : <=1
1604 # Return : `0' if arg1 exists and is not empty, `1' otherwise.
1606 is_not_empty()
1608 func_check is_not_empty = 1 "$@";
1609 if is_empty "$1";
1610 then
1611 eval "${return_no}";
1613 eval "${return_yes}";
1617 ########################################################################
1618 # is_not_equal (<string1> <string2>)
1620 # Test whether `string1' differs from `string2'.
1622 # Arguments : 2
1624 is_not_equal()
1626 func_check is_not_equal = 2 "$@";
1627 if is_equal "$1" "$2";
1628 then
1629 eval "${return_no}";
1631 eval "${return_yes}";
1635 ########################################################################
1636 # is_not_file (<filename>)
1638 # Test whether `name' is a not readable file.
1640 # Arguments : >=1 (empty allowed), more args are ignored
1642 is_not_file()
1644 func_check is_not_file '>=' 1 "$@";
1645 if is_file "$1";
1646 then
1647 eval "${return_no}";
1649 eval "${return_yes}";
1653 ########################################################################
1654 # is_not_prog (<name>)
1656 # Verify that arg is a not program in $PATH.
1658 # Arguments : >=1 (empty allowed)
1659 # more args are ignored, this allows to specify progs with arguments
1661 is_not_prog()
1663 func_check is_not_prog '>=' 1 "$@";
1664 if where "$1" >${_NULL_DEV};
1665 then
1666 eval "${return_no}";
1668 eval "${return_yes}";
1672 ########################################################################
1673 # is_not_writable (<name>)
1675 # Test whether `name' is a not a writable file or directory.
1677 # Arguments : >=1 (empty allowed), more args are ignored
1679 is_not_writable()
1681 func_check is_not_writable '>=' 1 "$@";
1682 if is_writable "$1";
1683 then
1684 eval "${return_no}";
1686 eval "${return_yes}";
1690 ########################################################################
1691 # is_not_yes (<string>)
1693 # Test whether `string' is not "yes".
1695 # Arguments : 1
1697 is_not_yes()
1699 func_check is_not_yes = 1 "$@";
1700 if is_yes "$1";
1701 then
1702 eval "${return_no}";
1704 eval "${return_yes}";
1708 ########################################################################
1709 # is_prog (<name>)
1711 # Determine whether arg is a program in $PATH
1713 # Arguments : >=0 (empty allowed)
1714 # more args are ignored, this allows to specify progs with arguments
1716 is_prog()
1718 func_check is_prog '>=' 0 "$@";
1719 case "$#" in
1721 eval "${return_no}";
1724 if where "$1" >${_NULL_DEV};
1725 then
1726 eval "${return_yes}";
1729 esac
1730 eval "${return_no}";
1734 ########################################################################
1735 # is_writable (<name>)
1737 # Test whether `name' is a writable file or directory.
1739 # Arguments : >=1 (empty allowed), more args are ignored
1741 is_writable()
1743 func_check is_writable '>=' 1 "$@";
1744 if test -r "$1";
1745 then
1746 if test -w "$1";
1747 then
1748 eval "${return_yes}";
1751 eval "${return_no}";
1755 ########################################################################
1756 # is_yes (<string>)
1758 # Test whether `string' has value "yes".
1760 # Arguments : <=1
1761 # Return : `0' if arg1 is `yes', `1' otherwise.
1763 is_yes()
1765 func_check is_yes = 1 "$@";
1766 if is_equal "$1" 'yes';
1767 then
1768 eval "${return_yes}";
1770 eval "${return_no}";
1774 ########################################################################
1775 # landmark ()
1777 # Print debugging information on standard error if $_DEBUG_LM is `yes'.
1779 # Globals: $_DEBUG_LM
1781 # Defined in section `Debugging functions'.
1784 ########################################################################
1785 # leave ()
1787 # Clean exit without an error.
1789 leave()
1791 clean_up;
1792 exit "${_OK}";
1796 ########################################################################
1797 landmark '6: list_*()';
1798 ########################################################################
1800 # `list' is an object class that represents an array or list. Its
1801 # data consists of space-separated single-quoted elements. So a list
1802 # has the form "'first' 'second' '...' 'last'". See list_append() for
1803 # more details on the list structure. The array elements of `list'
1804 # can be get by `set -- $list`.
1807 ########################################################################
1808 # list_append (<list> <element>...)
1810 # Arguments: >=2
1811 # <list>: a variable name for a list of single-quoted elements
1812 # <element>: some sequence of characters.
1813 # Output: none, but $<list> is set to
1814 # if <list> is empty: "'<element>' '...'"
1815 # otherwise: "$list '<element>' ..."
1817 list_append()
1819 func_check list_append '>=' 2 "$@";
1820 local _element;
1821 local _list;
1822 local _name;
1823 _name="$1";
1824 eval _list='"${'$1'}"';
1825 shift;
1826 for s in "$@";
1828 case "$s" in
1829 *\'*)
1830 # escape each single quote by replacing each
1831 # "'" (squote) by "'\''" (squote bslash squote squote);
1832 # note that the backslash must be doubled in the following `sed'
1833 _element="$(echo -n "$s" | sed -e 's/'"${_SQUOTE}"'/&\\&&/g')";
1835 '')
1836 _element="";
1839 _element="$s";
1841 esac;
1842 if obj _list is_empty;
1843 then
1844 _list="'${_element}'";
1845 else
1846 _list="${_list} '${_element}'";
1848 done;
1849 eval "${_name}"='"${_list}"';
1850 eval "${return_ok}";
1854 ########################################################################
1855 # list_from_cmdline (<pre_name_of_opt_lists> [<cmdline_arg>...])
1857 # Transform command line arguments into a normalized form.
1859 # Options, option arguments, and file parameters are identified and
1860 # output each as a single-quoted argument of its own. Options and
1861 # file parameters are separated by a '--' argument.
1863 # Arguments: >=1
1864 # <pre_name>: common part of a set of 4 environment variable names:
1865 # $<pre_name>_SHORT_NA: list of short options without an arg.
1866 # $<pre_name>_SHORT_ARG: list of short options that have an arg.
1867 # $<pre_name>_LONG_NA: list of long options without an arg.
1868 # $<pre_name>_LONG_ARG: list of long options that have an arg.
1869 # <cmdline_arg>...: the arguments from a command line, such as "$@",
1870 # the content of a variable, or direct arguments.
1872 # Output: ['-[-]opt' ['optarg']]... '--' ['filename']...
1874 # Example:
1875 # list_from_cmdline PRE 'a b' 'c' '' 'long' -a f1 -bcarg --long=larg f2
1876 # If $PRE_SHORT_NA, $PRE_SHORT_ARG, $PRE_LONG_NA, and $PRE_LONG_ARG are
1877 # none-empty option lists, this will result in printing:
1878 # '-a' '-b' '-c' 'arg' '--long' 'larg' '--' 'f1' 'f2'
1880 # Use this function in the following way:
1881 # eval set -- "$(args_norm PRE_NAME "$@")";
1882 # while test "$1" != '--'; do
1883 # case "$1" in
1884 # ...
1885 # esac;
1886 # shift;
1887 # done;
1888 # shift; #skip '--'
1889 # # all positional parameters ("$@") left are file name parameters.
1891 list_from_cmdline()
1893 func_check list_from_cmdline '>=' 1 "$@";
1894 local _fparams;
1895 local _fn;
1896 local _short_a;
1897 local _short_n;
1898 local _long_a;
1899 local _long_n;
1900 local _result;
1901 _short_n="$(obj_data "$1"_SHORT_NA)"; # short options, no argument
1902 _short_a="$(obj_data "$1"_SHORT_ARG)"; # short options, with argument
1903 _long_n="$(obj_data "$1"_LONG_NA)"; # long options, no argument
1904 _long_a="$(obj_data "$1"_LONG_ARG)"; # long options, with argument
1905 if obj _short_n is_empty;
1906 then
1907 error 'list_from_cmdline(): no $'"$1"'_SHORT_NA options.';
1909 if obj _short_a is_empty;
1910 then
1911 error 'list_from_cmdline(): no $'"$1"'_SHORT_ARG options.';
1913 if obj _long_n is_empty;
1914 then
1915 error 'list_from_cmdline(): no $'"$1"'_LONG_NA options.';
1917 if obj _long_a is_empty;
1918 then
1919 error 'list_from_cmdline(): no $'"$1"'_LONG_ARG options.';
1921 shift;
1922 _fn='list_from_cmdline():'; # for error messages
1923 if is_equal "$#" 0;
1924 then
1925 echo -n "'--'";
1926 eval "${return_ok}";
1928 _fparams='';
1929 _result='';
1930 while test "$#" -ge 1;
1932 _arg="$1";
1933 shift;
1934 case "$_arg" in
1935 --) break; ;;
1936 --?*)
1937 # delete leading '--';
1938 _opt="$(echo -n "${_arg}" | sed -e 's/^..//')";
1939 if list_has _long_n "${_opt}";
1940 then
1941 # long option, no argument
1942 list_append _result "--${_opt}";
1943 continue;
1945 # test on `--opt=arg'
1946 if string_contains "${_opt}" '=';
1947 then
1948 # extract option by deleting from the first '=' to the end
1949 _lopt="$(echo -n "${_opt}" | sed -e 's/=.*$//')";
1950 if list_has _long_a "${_lopt}";
1951 then
1952 # get the option argument by deleting up to first `='
1953 _optarg="$(echo -n "${_opt}" | sed -e 's/^[^=]*=//')";
1954 list_append _result "--${_lopt}" "${_optarg}";
1955 continue;
1958 if list_has _long_a "${_opt}";
1959 then
1960 # long option with argument
1961 if test "$#" -le 0;
1962 then
1963 error "${_fn} no argument for option --${_opt}."
1965 list_append _result "--${_opt}" "$1";
1966 shift;
1967 continue;
1969 error "${_fn} --${_opt} is not an option."
1971 -?*) # short option (cluster)
1972 # delete leading `-';
1973 _rest="$(echo -n "${_arg}" | sed -e 's/^-//')";
1974 while obj _rest is_not_empty;
1976 # get next short option from cluster (first char of $_rest)
1977 _optchar="$(echo -n "${_rest}" | sed -e 's/^\(.\).*$/\1/')";
1978 # remove first character from ${_rest};
1979 _rest="$(echo -n "${_rest}" | sed -e 's/^.//')";
1980 if list_has _short_n "${_optchar}";
1981 then
1982 list_append _result "-${_optchar}";
1983 continue;
1984 elif list_has _short_a "${_optchar}";
1985 then
1986 if obj _rest is_empty;
1987 then
1988 if test "$#" -ge 1;
1989 then
1990 list_append _result "-${_optchar}" "$1";
1991 shift;
1992 continue;
1993 else
1994 error \
1995 "${_fn}"' no argument for option -'"${_optchar}."
1997 else # rest is the argument
1998 list_append _result "-${_optchar}" "${_rest}";
1999 _rest='';
2000 continue;
2002 else
2003 error "${_fn} unknown option -${_optchar}."
2005 done;
2008 # Here, $_arg is not an option, so a file parameter.
2009 list_append _fparams "${_arg}";
2011 # Ignore the strange option handling of $POSIXLY_CORRECT to
2012 # end option parsing after the first file name argument. To
2013 # reuse it, do a `break' here if $POSIXLY_CORRECT is
2014 # non-empty.
2016 esac;
2017 done;
2018 list_append _result '--';
2019 if obj _fparams is_not_empty;
2020 then
2021 _result="${_result} ${_fparams}";
2023 if test "$#" -gt 0;
2024 then
2025 list_append _result "$@";
2027 echo -n "$_result";
2028 eval "${return_ok}";
2029 } # list_from_cmdline()
2032 ########################################################################
2033 # list_from_split (<string> <separator>)
2035 # In <string>, escape all white space characters and replace each
2036 # <separator> by space.
2038 # Arguments: 2: a <string> that is to be split into parts divided by
2039 # <separator>
2040 # Output: the resulting list string
2042 list_from_split()
2044 func_check list_from_split = 2 "$@";
2045 local _s;
2047 # precede each space or tab by a backslash `\' (doubled for `sed')
2048 _s="$(echo -n "$1" | sed -e 's/\(['"${_SPACE}${_TAB}"']\)/\\\1/g')";
2050 # replace split character of string by the list separator ` ' (space).
2051 case "$2" in
2052 /) # cannot use normal `sed' separator
2053 echo -n "${_s}" | sed -e '\|.*|s|'"$2"'| |g';
2055 ?) # use normal `sed' separator
2056 echo -n "${_s}" | sed -e 's/'"$2"'/ /g';
2058 ??*)
2059 error 'list_from_split(): separator must be a single character.';
2061 esac;
2062 eval "${return_ok}";
2066 ########################################################################
2067 # list_get (<list>)
2069 # Check whether <list> is a space-separated list of '-quoted elements.
2071 # If the test fails an error is raised.
2072 # If the test succeeds the argument is echoed.
2074 # Testing criteria:
2075 # A list has the form "'first' 'second' '...' 'last'". So it has a
2076 # leading and a final quote and the elements are separated by "' '"
2077 # constructs. If these are all removed there should not be any
2078 # unescaped single-quotes left. Watch out for escaped single
2079 # quotes; they have the form '\'' (sq bs sq sq).
2081 # Arguments: 1
2082 # Output: the argument <list> unchanged, if the check succeeded.
2084 list_get()
2086 func_check list_get = 1 "$@";
2087 local _list;
2088 eval _list='"${'$1'}"';
2089 # remove leading and final space characters
2090 _list="$(echo -n "${_list}" | \
2091 sed -e 's/^['"${_SPACE}${_TAB}"']*//' | \
2092 sed -e 's/['"${_SPACE}${_TAB}"']*$//')";
2093 case "${_list}" in
2095 eval "${return_ok}";
2097 \'*\')
2098 echo -n "${_list}";
2099 eval "${return_ok}";
2102 error "list_get(): bad list: $1"
2104 esac;
2105 eval "${return_ok}";
2109 ########################################################################
2110 # list_has (<var_name> <element>)
2112 # Arguments: 2
2113 # <var_name>: a variable name for a list of single-quoted elements
2114 # <element>: some sequence of characters.
2115 # Output:
2116 # if <list> is empty: "'<element>' '...'"
2117 # otherwise: "list '<element>' ..."
2119 list_has()
2121 func_check list_has = 2 "$@";
2122 eval _list='"${'$1'}"';
2123 if obj _list is_empty;
2124 then
2125 eval "${return_no}";
2127 _element="$2";
2128 case "$2" in
2129 \'*\') _element="$2"; ;;
2130 *) _element="'$2'"; ;;
2131 esac;
2132 if string_contains "${_list}" "${_element}";
2133 then
2134 eval "${return_yes}";
2135 else
2136 eval "${return_no}";
2138 eval "${return_ok}";
2142 ########################################################################
2143 # list_has_not (<list> <element>)
2145 # Arguments: 2
2146 # <list>: a space-separated list of single-quoted elements.
2147 # <element>: some sequence of characters.
2148 # Output:
2149 # if <list> is empty: "'<element>' '...'"
2150 # otherwise: "<list> '<element>' ..."
2152 list_has_not()
2154 func_check list_has_not = 2 "$@";
2155 eval _list='"${'$1'}"';
2156 if obj _list is_empty;
2157 then
2158 eval "${return_yes}";
2160 _element="$2";
2161 case "$2" in
2162 \'*\') _element="$2"; ;;
2163 *) _element="'$2'"; ;;
2164 esac;
2165 if string_contains "${_list}" "${_element}";
2166 then
2167 eval "${return_no}";
2168 else
2169 eval "${return_yes}";
2171 eval "${return_ok}";
2175 ########################################################################
2176 landmark '7: man_*()';
2177 ########################################################################
2179 ########################################################################
2180 # man_do_filespec (<filespec>)
2182 # Print suitable man page(s) for filespec to $_TMP_CAT.
2184 # Arguments : 2
2185 # <filespec>: argument of the form `man:name.section', `man:name',
2186 # `man:name(section)', `name.section', `name'.
2188 # Globals : $_OPT_ALL
2190 # Output : none.
2191 # Return : `0' if man page was found, `1' else.
2193 # Only called from do_fileargs(), checks on $MANPATH and
2194 # $_MAN_ENABLE are assumed.
2196 man_do_filespec()
2198 func_check man_do_filespec = 1 "$@";
2199 local _got_one;
2200 local _name;
2201 local _prevsec;
2202 local _res;
2203 local _section;
2204 local _spec;
2205 local _string;
2206 local s;
2207 if obj _MAN_PATH is_empty;
2208 then
2209 eval "${return_bad}";
2211 if is_empty "$1";
2212 then
2213 eval "${return_bad}";
2215 _spec="$1";
2216 _name='';
2217 _section='';
2218 case "${_spec}" in
2219 */*) # not a man spec when it contains '/'
2220 eval "${return_bad}";
2222 man:?*\(?*\)) # man:name(section)
2223 _name="$(echo -n "${_spec}" \
2224 | sed -e 's/^man:\(..*\)(\(..*\))$/\1/')";
2225 _section="$(echo -n "${_spec}" \
2226 | sed -e 's/^man:\(..*\)(\(..*\))$/\2/')";
2228 man:?*.[0-9on]) # man:name.section
2229 _name="$(echo -n "${_spec}" \
2230 | sed -e 's/^man:\(..*\)\..$/\1/')";
2231 _section="$(echo -n "${_spec}" \
2232 | sed -e 's/^.*\(.\)$/\1/')";
2234 man:?*) # man:name
2235 _name="$(echo -n "${_spec}" | sed -e 's/^man://')";
2237 ?*\(?*\)) # name(section)
2238 _name="$(echo -n "${_spec}" \
2239 | sed -e 's/^\(..*\)(\(..*\))$/\1/')";
2240 _section="$(echo -n "${_spec}" \
2241 | sed -e 's/^\(..*\)(\(..*\))$/\2/')";
2243 ?*.[0-9on]) # name.section
2244 _name="$(echo -n "${_spec}" \
2245 | sed -e 's/^\(..*\)\..$/\1/')";
2246 _section="$(echo -n "${_spec}" \
2247 | sed -e 's/^.*\(.\)$/\1/')";
2250 _name="${_filespec}";
2252 esac;
2253 if obj _name is_empty;
2254 then
2255 eval "${return_bad}";
2257 _got_one='no';
2258 if obj _section is_empty;
2259 then
2260 eval set -- "${_MAN_AUTO_SEC}";
2261 for s in "$@";
2263 if man_search_section "${_name}" "$s";
2264 then # found
2265 if obj _MAN_ALL is_yes;
2266 then
2267 _got_one='yes';
2268 else
2269 eval "${return_good}";
2272 done;
2273 else
2274 if man_search_section "${_name}" "${_section}";
2275 then
2276 eval "${return_good}";
2277 else
2278 eval "${return_bad}";
2281 if obj _MAN_ALL is_yes && is_yes "${_got_one}";
2282 then
2283 eval "${return_good}";
2285 eval "${return_bad}";
2286 } # man_do_filespec()
2289 ########################################################################
2290 # man_register_file (<file> <name> [<section>])
2292 # Write a found man page file and register the title element.
2294 # Arguments: 1, 2, or 3; maybe empty
2295 # Output: none
2297 man_register_file()
2299 func_check man_register_file '>=' 2 "$@";
2300 case "$#" in
2301 2|3) do_nothing; ;;
2303 error "man_register_file() expects 2 or 3 arguments.";
2305 esac;
2306 if is_empty "$1";
2307 then
2308 error 'man_register_file(): file name is empty';
2310 to_tmp "$1";
2311 case "$#" in
2313 register_title "man:$2";
2314 eval "${return_ok}";
2317 register_title "$2.$3";
2318 eval "${return_ok}";
2320 esac;
2321 eval "${return_ok}";
2325 ########################################################################
2326 # man_search_section (<name> <section>)
2328 # Retrieve man pages.
2330 # Arguments : 2
2331 # Globals : $_MAN_PATH, $_MAN_EXT
2332 # Return : 0 if found, 1 otherwise
2334 man_search_section()
2336 func_check man_search_section = 2 "$@";
2337 local _dir;
2338 local _ext;
2339 local _got_one;
2340 local _name;
2341 local _prefix
2342 local _section;
2343 local d;
2344 local f;
2345 if obj _MAN_PATH is_empty;
2346 then
2347 eval "${return_bad}";
2349 if is_empty "$1";
2350 then
2351 eval "${return_bad}";
2353 if is_empty "$2";
2354 then
2355 eval "${return_bad}";
2357 _name="$1";
2358 _section="$2";
2359 eval set -- "$(path_split "${_MAN_PATH}")";
2360 _got_one='no';
2361 if obj _MAN_EXT is_empty;
2362 then
2363 for d in "$@";
2365 _dir="$(dirname_append "$d" "man${_section}")";
2366 if obj _dir is_dir;
2367 then
2368 _prefix="$(dirname_append "${_dir}" "${_name}.${_section}")";
2369 for f in $(echo -n ${_prefix}*);
2371 if obj f is_file;
2372 then
2373 if is_yes "${_got_one}";
2374 then
2375 register_file "$f";
2376 elif obj _MAN_ALL is_yes;
2377 then
2378 man_register_file "$f" "${_name}";
2379 else
2380 man_register_file "$f" "${_name}" "${_section}";
2381 eval "${return_good}";
2383 _got_one='yes';
2385 done;
2387 done;
2388 else
2389 _ext="${_MAN_EXT}";
2390 # check for directory name having trailing extension
2391 for d in "$@";
2393 _dir="$(dirname_append $d man${_section}${_ext})";
2394 if obj _dir is_dir;
2395 then
2396 _prefix="$(dirname_append "${_dir}" "${_name}.${_section}")";
2397 for f in ${_prefix}*;
2399 if obj f is_file;
2400 then
2401 if is_yes "${_got_one}";
2402 then
2403 register_file "$f";
2404 elif obj _MAN_ALL is_yes;
2405 then
2406 man_register_file "$f" "${_name}";
2407 else
2408 man_register_file "$f" "${_name}" "${_section}";
2409 eval "${return_good}";
2411 _got_one='yes';
2413 done;
2415 done;
2416 # check for files with extension in directories without extension
2417 for d in "$@";
2419 _dir="$(dirname_append "$d" "man${_section}")";
2420 if obj _dir is_dir;
2421 then
2422 _prefix="$(dirname_append "${_dir}" \
2423 "${_name}.${_section}${_ext}")";
2424 for f in ${_prefix}*;
2426 if obj f is_file;
2427 then
2428 if is_yes "${_got_one}";
2429 then
2430 register_file "$f";
2431 elif obj _MAN_ALL is_yes;
2432 then
2433 man_register_file "$f" "${_name}";
2434 else
2435 man_register_file "$f" "${_name}" "${_section}";
2436 eval "${return_good}";
2438 _got_one='yes';
2440 done;
2442 done;
2444 if obj _MAN_ALL is_yes && is_yes "${_got_one}";
2445 then
2446 eval "${return_good}";
2448 eval "${return_bad}";
2449 } # man_search_section()
2452 ########################################################################
2453 # man_setup ()
2455 # Setup the variables $_MAN_* needed for man page searching.
2457 # Globals:
2458 # in: $_OPT_*, $_MANOPT_*, $LANG, $LC_MESSAGES, $LC_ALL,
2459 # $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM, $MANOPT.
2460 # out: $_MAN_PATH, $_MAN_LANG, $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2,
2461 # $_MAN_SEC, $_MAN_ALL
2462 # in/out: $_MAN_ENABLE
2464 # The precedence for the variables related to `man' is that of GNU
2465 # `man', i.e.
2467 # $LANG; overridden by
2468 # $LC_MESSAGES; overridden by
2469 # $LC_ALL; this has the same precedence as
2470 # $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM; overridden by
2471 # $MANOPT; overridden by
2472 # the groffer command line options.
2474 man_setup()
2476 func_check main_man_setup = 0 "$@";
2477 local _lang;
2479 if obj _MAN_IS_SETUP is_yes;
2480 then
2481 eval "${return_ok}";
2483 _MAN_IS_SETUP='yes';
2485 if obj _MAN_ENABLE is_not_yes;
2486 then
2487 eval "${return_ok}";
2490 # determine basic path for man pages
2491 _MAN_PATH="$(get_first_essential \
2492 "${_OPT_MANPATH}" "${_MANOPT_PATH}" "${MANPATH}")";
2493 if obj _MAN_PATH is_empty;
2494 then
2495 manpath_set_from_path;
2496 else
2497 _MAN_PATH="$(path_clean "${_MAN_PATH}")";
2499 if obj _MAN_PATH is_empty;
2500 then
2501 if is_prog 'manpath';
2502 then
2503 _MAN_PATH="$(manpath 2>${_NULL_DEV})"; # not always available
2506 if obj _MAN_PATH is_empty;
2507 then
2508 _MAN_ENABLE="no";
2509 eval "${return_ok}";
2512 _MAN_ALL="$(get_first_essential "${_OPT_ALL}" "${_MANOPT_ALL}")";
2513 if obj _MAN_ALL is_empty;
2514 then
2515 _MAN_ALL='no';
2518 _MAN_SYS="$(get_first_essential \
2519 "${_OPT_SYSTEMS}" "${_MANOPT_SYS}" "${SYSTEM}")";
2520 _lang="$(get_first_essential \
2521 "${_OPT_LANG}" "${LC_ALL}" "${LC_MESSAGES}" "${LANG}")";
2522 case "${_lang}" in
2523 C|POSIX)
2524 _MAN_LANG="";
2525 _MAN_LANG2="";
2528 _MAN_LANG="${_lang}";
2529 _MAN_LANG2="";
2532 _MAN_LANG="${_lang}";
2533 # get first two characters of $_lang
2534 _MAN_LANG2="$(echo -n "${_lang}" | sed -e 's/^\(..\).*$/\1/')";
2536 esac;
2537 # from now on, use only $_LANG, forget about $_OPT_LANG, $LC_*.
2539 manpath_add_lang_sys; # this is very slow
2541 _MAN_SEC="$(get_first_essential \
2542 "${_OPT_SECT}" "${_MANOPT_SEC}" "${MANSEC}")";
2543 if obj _MAN_PATH is_empty;
2544 then
2545 _MAN_ENABLE="no";
2546 eval "${return_ok}";
2549 _MAN_EXT="$(get_first_essential \
2550 "${_OPT_EXTENSION}" "${_MANOPT_EXTENSION}")";
2551 eval "${return_ok}";
2552 } # man_setup()
2555 ########################################################################
2556 landmark '8: manpath_*()';
2557 ########################################################################
2559 ########################################################################
2560 # manpath_add_lang_sys ()
2562 # Add language and operating system specific directories to man path.
2564 # Arguments : 0
2565 # Output : none
2566 # Globals:
2567 # in: $_MAN_SYS: has the form `os1,os2,...', a comma separated
2568 # list of names of operating systems.
2569 # $_MAN_LANG and $_MAN_LANG2: each a single name
2570 # in/out: $_MAN_PATH: has the form `dir1:dir2:...', a colon
2571 # separated list of directories.
2573 manpath_add_lang_sys()
2575 func_check manpath_add_lang_sys = 0 "$@";
2576 local p;
2577 local _mp;
2578 if obj _MAN_PATH is_empty;
2579 then
2580 eval "${return_ok}";
2582 # twice test both sys and lang
2583 eval set -- "$(path_split "${_MAN_PATH}")";
2584 _mp='';
2585 for p in "$@";
2586 do # loop on man path directories
2587 _mp="$(_manpath_add_lang_sys_single "${_mp}" "$p")";
2588 done;
2589 eval set -- "$(path_split "${_mp}")";
2590 for p in "$@";
2591 do # loop on man path directories
2592 _mp="$(_manpath_add_lang_sys_single "${_mp}" "$p")";
2593 done;
2594 _MAN_PATH="$(path_chop "${_mp}")";
2595 eval "${return_ok}";
2599 _manpath_add_lang_sys_single()
2601 # To the directory in $1 append existing sys/lang subdirectories
2602 # Function is necessary to split the OS list.
2604 # globals: in: $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2
2605 # argument: 2: `man_path' and `dir'
2606 # output: colon-separated path of the retrieved subdirectories
2608 func_check _manpath_add_lang_sys_single = 2 "$@";
2609 local d;
2610 _res="$1";
2611 _parent="$2";
2612 eval set -- "$(list_from_split "${_MAN_SYS}" ',')";
2613 for d in "$@" "${_MAN_LANG}" "${_MAN_LANG2}";
2615 _dir="$(dirname_append "${_parent}" "$d")";
2616 if obj _res path_not_contains "${_dir}" && obj _dir is_dir;
2617 then
2618 _res="${_res}:${_dir}";
2620 done;
2621 if path_not_contains "${_res}" "${_parent}";
2622 then
2623 _res="${_res}:${_parent}";
2625 path_chop "${_res}";
2628 # end manpath_add_lang_sys ()
2631 ########################################################################
2632 # manpath_set_from_path ()
2634 # Determine basic search path for man pages from $PATH.
2636 # Return: `0' if a valid man path was retrieved.
2637 # Output: none
2638 # Globals:
2639 # in: $PATH
2640 # out: $_MAN_PATH
2642 manpath_set_from_path()
2644 func_check manpath_set_from_path = 0 "$@";
2645 local _base;
2646 local _mandir;
2647 local _manpath;
2648 local d;
2649 local e;
2650 _manpath='';
2652 # get a basic man path from $PATH
2653 if obj PATH is_not_empty;
2654 then
2655 eval set -- "$(path_split "${PATH}")";
2656 for d in "$@";
2658 # delete the final `/bin' part
2659 _base="$(echo -n "$d" | sed -e '\|.*|s|//*bin/*$||')";
2660 for e in /share/man /man;
2662 _mandir="${_base}$e";
2663 if test -d "${_mandir}" && test -r "${_mandir}";
2664 then
2665 _manpath="${_manpath}:${_mandir}";
2667 done;
2668 done;
2671 # append some default directories
2672 for d in /usr/local/share/man /usr/local/man \
2673 /usr/share/man /usr/man \
2674 /usr/X11R6/man /usr/openwin/man \
2675 /opt/share/man /opt/man \
2676 /opt/gnome/man /opt/kde/man;
2678 if obj _manpath path_not_contains "$d" && obj d is_dir;
2679 then
2680 _manpath="${_manpath}:$d";
2682 done;
2684 _MAN_PATH="${_manpath}";
2685 eval "${return_ok}";
2686 } # manpath_set_from_path()
2689 ########################################################################
2690 landmark '9: obj_*()';
2691 ########################################################################
2693 ########################################################################
2694 # obj (<object> <call_name> <arg>...)
2696 # This works like a method (object function) call for an object.
2697 # Run "<call_name> $<object> <arg> ...".
2699 # The first argument represents an object whose data is given as first
2700 # argument to <call_name>().
2702 # Argument: >=2
2703 # <object>: variable name
2704 # <call_name>: a program or function name
2706 obj()
2708 func_check obj '>=' 2 "$@";
2709 local func;
2710 local var;
2711 if is_empty "$2";
2712 then
2713 error "obj(): function name is empty."
2714 else
2715 func="$2";
2717 eval arg1='"${'$1'}"';
2718 shift;
2719 shift;
2720 eval "${func}"' "${arg1}" "$@"';
2724 ########################################################################
2725 # obj_data (<object>)
2727 # Print the data of <object>, i.e. the content of $<object>.
2728 # For possible later extensions.
2730 # Arguments: 1
2731 # <object>: a variable name
2732 # Output: the data of <object>
2734 obj_data()
2736 func_check obj '=' 1 "$@";
2737 if is_empty "$1";
2738 then
2739 error "obj_data(): object name is empty."
2741 eval echo -n '"${'$1'}"';
2745 ########################################################################
2746 # obj_from_output (<object> <call_name> <arg>...)
2748 # Run '$<object>="$(<call_name> <arg>...)"' to set the result of a
2749 # function call to a global variable.
2751 # Arguments: >=2
2752 # <object>: a variable name
2753 # <call_name>: the name of a function or program
2754 # <arg>: optional argument to <call_name>
2755 # Output: none
2757 obj_from_output()
2759 func_check obj_from_output '>=' 2 "$@";
2760 local result_name;
2761 if is_empty "$1";
2762 then
2763 error "res(): variable name is empty.";
2764 elif is_empty "$2";
2765 then
2766 error "res(): function name is empty."
2767 else
2768 result_name="$1";
2770 shift;
2771 eval "${result_name}"'="$('"$@"')"';
2775 ########################################################################
2776 # obj_set (<object> <data>)
2778 # Set the data of <object>, i.e. call "$<object>=<data>".
2780 # Arguments: 2
2781 # <object>: a variable name
2782 # <data>: a string
2783 # Output:: none
2785 obj_set()
2787 func_check obj_set '=' 2 "$@";
2788 if is_empty "$1";
2789 then
2790 error "obj_set(): object name is empty."
2792 eval "$1"='"$2"';
2796 ########################################################################
2797 # path_chop (<path>)
2799 # Remove unnecessary colons from path.
2801 # Argument: 1, a colon separated path.
2802 # Output: path without leading, double, or trailing colons.
2804 path_chop()
2806 func_check path_chop = 1 "$@";
2807 local _res;
2809 # replace multiple colons by a single colon `:'
2810 # remove leading and trailing colons
2811 echo -n "$1" | sed -e 's/:::*/:/g' |
2812 sed -e 's/^:*//' |
2813 sed -e 's/:*$//';
2814 eval "${return_ok}";
2818 ########################################################################
2819 # path_clean (<path>)
2821 # Remove non-existing directories from a colon-separated list.
2823 # Argument: 1, a colon separated path.
2824 # Output: colon-separated list of existing directories.
2826 path_clean()
2828 func_check path_clean = 1 "$@";
2829 local _arg;
2830 local _dir;
2831 local _res;
2832 local i;
2833 if is_not_equal "$#" 1;
2834 then
2835 error 'path_clean() needs 1 argument.';
2837 _arg="$1";
2838 eval set -- "$(path_split "${_arg}")";
2839 _res="";
2840 for i in "$@";
2842 if obj i is_not_empty \
2843 && obj _res path_not_contains "$i" \
2844 && obj i is_dir;
2845 then
2846 case "$i" in
2847 ?*/) _res="${_res}$(dirname_chop "$i")"; ;;
2848 *) _res="${_res}:$i";
2849 esac;
2851 done;
2852 if path_chop "${_res}";
2853 then
2854 eval "${return_ok}";
2855 else
2856 eval "${return_badk}";
2861 ########################################################################
2862 # path_contains (<path> <dir>)
2864 # Test whether `dir' is contained in `path', a list separated by `:'.
2866 # Arguments : 2 arguments.
2867 # Return : `0' if arg2 is substring of arg1, `1' otherwise.
2869 path_contains()
2871 func_check path_contains = 2 "$@";
2872 case ":$1:" in
2873 *":$2:"*)
2874 eval "${return_yes}";
2877 eval "${return_no}";
2879 esac;
2880 eval "${return_ok}";
2884 ########################################################################
2885 # path_not_contains (<path> <dir>)
2887 # Test whether `dir' is not contained in colon separated `path'.
2889 # Arguments : 2 arguments.
2891 path_not_contains()
2893 func_check path_not_contains = 2 "$@";
2894 if path_contains "$1" "$2";
2895 then
2896 eval "${return_no}";
2897 else
2898 eval "${return_yes}";
2900 eval "${return_ok}";
2904 ########################################################################
2905 # path_split (<path>)
2907 # In `path' escape white space and replace each colon by a space.
2909 # Arguments: 1: a colon-separated path
2910 # Output: the resulting list, process with `eval set --'
2912 path_split()
2914 func_check path_split = 1 "$@";
2915 list_from_split "$1" ':';
2916 eval "${return_ok}";
2920 ########################################################################
2921 landmark '10: register_*()';
2922 ########################################################################
2924 ########################################################################
2925 # register_file (<filename>)
2927 # Write a found file and register the title element.
2929 # Arguments: 1: a file name
2930 # Output: none
2932 register_file()
2934 func_check register_file = 1 "$@";
2935 if is_empty "$1";
2936 then
2937 error 'register_file(): file name is empty';
2939 if is_equal "$1" '-';
2940 then
2941 to_tmp "${_TMP_STDIN}";
2942 register_title '-';
2943 else
2944 to_tmp "$1";
2945 register_title "$(base_name "$1")";
2947 eval "${return_ok}";
2951 ########################################################################
2952 # register_title (<filespec>)
2954 # Create title element from <filespec> and append to $_REGISTERED_TITLE
2956 # Globals: $_REGISTERED_TITLE (rw)
2958 register_title()
2960 func_check register_title = 1 "$@";
2961 local _title;
2962 if is_empty "$1";
2963 then
2964 eval "${return_ok}";
2966 _title="$(base_name "$1")"; # remove directory part
2968 # remove extension `.gz'
2969 _title="$(echo -n "${_title}" | sed -e 's/\.gz$//')";
2970 # remove extension `.Z'
2971 _title="$(echo -n "${_title}" | sed -e 's/\.Z$//')";
2973 if obj _title is_empty;
2974 then
2975 eval "${return_ok}";
2977 _REGISTERED_TITLE="${_REGISTERED_TITLE} ${_title}";
2978 eval "${return_ok}";
2982 ########################################################################
2983 # reset ()
2985 # Reset the variables that can be affected by options to their default.
2988 # Defined in section `Preset' after the rudimentary shell tests.
2991 ########################################################################
2992 # save_stdin ()
2994 # Store standard input to temporary file (with decompression).
2996 if obj _HAS_COMPRESSION is_yes;
2997 then
2998 save_stdin()
3000 local _f;
3001 func_check save_stdin = 0 "$@";
3002 _f="${_TMP_DIR}"/INPUT;
3003 cat >"${_f}";
3004 catz "${_f}" >"${_TMP_STDIN}";
3005 rm -f "${_f}";
3006 eval "${return_ok}";
3008 else
3009 save_stdin()
3011 func_check save_stdin = 0 "$@";
3012 cat >"${_TMP_STDIN}";
3013 eval "${return_ok}";
3018 ########################################################################
3019 landmark '11: stack_*()';
3020 ########################################################################
3022 ########################################################################
3023 # string_contains (<string> <part>)
3025 # Test whether `part' is contained in `string'.
3027 # Arguments : 2 text arguments.
3028 # Return : `0' if arg2 is substring of arg1, `1' otherwise.
3030 string_contains()
3032 func_check string_contains = 2 "$@";
3033 case "$1" in
3034 *"$2"*)
3035 eval "${return_yes}";
3038 eval "${return_no}";
3040 esac;
3041 eval "${return_ok}";
3045 ########################################################################
3046 # string_not_contains (<string> <part>)
3048 # Test whether `part' is not substring of `string'.
3050 # Arguments : 2 text arguments.
3051 # Return : `0' if arg2 is substring of arg1, `1' otherwise.
3053 string_not_contains()
3055 func_check string_not_contains = 2 "$@";
3056 if string_contains "$1" "$2";
3057 then
3058 eval "${return_no}";
3059 else
3060 eval "${return_yes}";
3062 eval "${return_ok}";
3066 ########################################################################
3067 landmark '12: tmp_*()';
3068 ########################################################################
3070 ########################################################################
3071 # tmp_cat ()
3073 # output the temporary cat file (the concatenation of all input)
3075 tmp_cat()
3077 cat "${_TMP_CAT}";
3081 ########################################################################
3082 # tmp_create (<suffix>?)
3084 # create temporary file
3086 # It's safe to use the shell process ID together with a suffix to
3087 # have multiple temporary files.
3089 # Output : name of created file
3091 tmp_create()
3093 func_check tmp_create '<=' 1 "$@";
3094 local _tmp;
3095 # the output file does not have `,' as first character
3096 _tmp="${_TMP_DIR}/,$1";
3097 echo -n >"${_tmp}";
3098 echo -n "${_tmp}"; # output file name
3099 eval "${return_ok}";
3103 ########################################################################
3104 # to_tmp (<filename>)
3106 # print file (decompressed) to the temporary cat file
3108 to_tmp()
3110 func_check to_tmp = 1 "$@";
3111 if is_file "$1";
3112 then
3113 if obj _OPT_LOCATION is_yes;
3114 then
3115 echo2 "$1";
3117 if obj _OPT_WHATIS is_yes;
3118 then
3119 what_is "$1" >>"${_TMP_CAT}";
3120 else
3121 catz "$1" >>"${_TMP_CAT}";
3123 else
3124 error "to_tmp(): could not read file \`$1'.";
3126 eval "${return_ok}";
3130 ########################################################################
3131 # trap_clean ()
3133 # disable trap on all exit codes ($_ALL_EXIT)
3135 # Arguments: 0
3136 # Globals: $_ALL_EXIT
3138 trap_clean()
3140 func_check trap_clean = 0 "$@";
3141 local i;
3142 for i in ${_ALL_EXIT};
3144 trap "" "$i" 2>${_NULL_DEV} || true;
3145 done;
3146 eval "${return_ok}";
3150 ########################################################################
3151 # trap_set (<functionname>)
3153 # call function on all exit codes ($_ALL_EXIT)
3155 # Arguments: 1 (name of a shell function)
3156 # Globals: $_ALL_EXIT
3158 trap_set()
3160 func_check trap_set = 1 "$@";
3161 local i;
3162 for i in ${_ALL_EXIT};
3164 trap "$1" "$i" 2>${_NULL_DEV} || true;
3165 done;
3166 eval "${return_ok}";
3170 ########################################################################
3171 # usage ()
3173 # print usage information to stderr; for groffer option --help.
3175 usage()
3177 func_check usage = 0 "$@";
3178 echo;
3179 version;
3180 echo 'Usage: '"${_PROGRAM_NAME}"' [option]... [filespec]...';
3181 cat <<EOF
3183 Display roff files, standard input, and/or Unix manual pages with a X
3184 Window viewer or in several text modes. All input is decompressed
3185 on-the-fly with all formats that gzip can handle.
3187 "filespec" is one of
3188 "filename" name of a readable file
3189 "-" for standard input
3190 "man:name.n" man page "name" in section "n"
3191 "man:name" man page "name" in first section found
3192 "name.n" man page "name" in section "n"
3193 "name" man page "name" in first section found
3194 and some more (see groffer(1) for details).
3196 -h --help print this usage message.
3197 -Q --source output as roff source.
3198 -T --device=name pass to groff using output device "name".
3199 -v --version print version information.
3200 -V display the groff execution pipe instead of formatting.
3201 -X --X --x display with "gxditview" using groff -X.
3202 -Z --ditroff --intermediate-output
3203 generate groff intermediate output without
3204 post-processing and viewing, like groff -Z.
3205 All other short options are interpreted as "groff" formatting options.
3207 The most important groffer long options are
3209 --apropos=name start man's "apropos" program for "name".
3210 --apropos-data=name
3211 "apropos" for "name" in man's data sections 4, 5, 7.
3212 --apropos-devel=name
3213 "apropos" for "name" in development sections 2, 3, 9.
3214 --apropos-progs=name
3215 "apropos" for "name" in man's program sections 1, 6, 8.
3216 --auto choose mode automatically from the default mode list.
3217 --default reset all options to the default value.
3218 --default-modes=mode1,mode2,...
3219 set sequence of automatically tried modes.
3220 --dvi display in a viewer for TeX device independent format.
3221 --dvi-viewer choose the viewer program for dvi mode.
3222 --groff process like groff, disable viewing features.
3223 --help display this helping output.
3224 --html --www display in a web browser.
3225 --html-viewer choose the web browser for www mode.
3226 --man check file parameters first whether they are man pages.
3227 --mode=auto|dvi|groff|html|pdf|ps|source|text|tty|www|x|X
3228 choose display mode.
3229 --no-man disable man-page facility.
3230 --pager=program preset the paging program for tty mode.
3231 --pdf display in a PDF viewer.
3232 --pdf-viewer choose the viewer program for pdf mode.
3233 --ps display in a Postscript viewer.
3234 --ps-viewer choose the viewer program for ps mode.
3235 --shell specify shell under which to run this program.
3236 --text output in a text device without a pager.
3237 --tty display with a pager on text terminal even when in X.
3238 --www-viewer same as --html-viewer
3239 --x-viewer choose viewer program for x mode (X mode).
3240 --X-viewer same as "--xviewer".
3242 The usual X Windows toolkit options transformed into GNU long options
3243 --background=color, --bd=size, --bg=color, --bordercolor=color,
3244 --borderwidth=size, --bw=size, --display=Xdisplay, --fg=color,
3245 --fn=font, --font=font, --foreground=color, --geometry=geom, --iconic,
3246 --resolution=dpi, --rv, --title=text, --xrm=resource
3248 Long options of GNU "man"
3249 --all, --ascii, --ditroff, --extension=suffix, --locale=language,
3250 --local-file=name, --location, --manpath=dir1:dir2:...,
3251 --sections=s1:s2:..., --systems=s1,s2,..., --whatis, --where, ...
3254 eval "${return_ok}";
3258 ########################################################################
3259 # version ()
3261 # print version information to stderr
3263 version()
3265 func_check version = 0 "$@";
3266 echo2 "${_PROGRAM_NAME} ${_PROGRAM_VERSION} of ${_LAST_UPDATE}";
3267 # also display groff's version, but not the called subprograms
3268 groff -v 2>&1 | sed -e '/^ *$/q' | sed -e '1s/^/is part of /' >&2;
3272 ########################################################################
3273 # warning (<string>)
3275 # Print warning to stderr
3277 warning()
3279 echo2 "warning: $*";
3283 ########################################################################
3284 # what_is (<filename>)
3286 # Interpret <filename> as a man page and display its `whatis'
3287 # information as a fragment written in the groff language.
3289 what_is()
3291 func_check what_is = 1 "$@";
3292 local _res;
3293 local _dot;
3294 if is_not_file "$1";
3295 then
3296 error "what_is(): argument is not a readable file."
3298 _dot='^\.['"${_SPACE}${_TAB}"']*';
3299 echo '.br';
3300 echo "$1: ";
3301 echo '.br';
3302 echo -n ' ';
3303 # grep the line containing `.TH' macro, if any
3304 _res="$(catz "$1" | sed -e '/'"${_dot}"'TH /p
3305 d')";
3306 if obj _res is_not_empty;
3307 then # traditional man style
3308 # get the text between the first and the second `.SH' macro, by
3309 # - delete up to first .SH;
3310 # - of this, print everything up to next .SH, and delete the rest;
3311 # - of this, delete the final .SH line;
3312 catz "$1" | sed -e '1,/'"${_dot}"'SH/d' \
3313 | sed -e '1,/'"${_dot}"'SH/p
3314 d' \
3315 | sed -e '/'"${_dot}"'SH/d';
3316 eval "${return_ok}";
3318 # grep the line containing `.Dd' macro, if any
3319 _res="$(catz "$1" | sed -e '/'"${_dot}"'Dd /p
3320 d')";
3321 if obj _res is_not_empty;
3322 then # BSD doc style
3323 # get the text between the first and the second `.Nd' macro, by
3324 # - delete up to first .Nd;
3325 # - of this, print everything up to next .Nd, and delete the rest;
3326 # - of this, delete the final .Nd line;
3327 catz "$1" | sed -e '1,/'"${_dot}"'Nd/d' \
3328 | sed -e '1,/'"${_dot}"'Nd/p
3329 d' \
3330 | sed -e '/'"${_dot}"'Nd/d';
3331 eval "${return_ok}";
3333 echo 'is not a man page.';
3334 eval "${return_bad}";
3338 ########################################################################
3339 # where (<program>)
3341 # Output path of a program if in $PATH.
3343 # Arguments : >=1 (empty allowed)
3344 # more args are ignored, this allows to specify progs with arguments
3345 # Return : `0' if arg1 is a program in $PATH, `1' otherwise.
3347 where()
3349 func_check where '>=' 1 "$@";
3350 local _file;
3351 local _arg;
3352 local p;
3353 _arg="$1";
3354 if obj _arg is_empty;
3355 then
3356 eval "${return_bad}";
3358 case "${_arg}" in
3360 if test -f "${_arg}" && test -x "${_arg}";
3361 then
3362 eval "${return_ok}";
3363 else
3364 eval "${return_bad}";
3367 esac;
3368 eval set -- "$(path_split "${PATH}")";
3369 for p in "$@";
3371 case "$p" in
3372 */) _file=${p}${_arg}; ;;
3373 *) _file=${p}/${_arg}; ;;
3374 esac;
3375 if test -f "${_file}" && test -x "${_file}";
3376 then
3377 echo -n "${_file}";
3378 eval "${return_ok}";
3380 done;
3381 eval "${return_bad}";
3385 ########################################################################
3386 # main* Functions
3387 ########################################################################
3389 # The main area contains the following parts:
3390 # - main_init(): initialize temporary files and set exit trap
3391 # - main_parse_MANOPT(): parse $MANOPT
3392 # - main_parse_args(): argument parsing
3393 # - main_set_mode (): determine the display mode
3394 # - main_do_fileargs(): process filespec arguments
3395 # - main_set_resources(): setup X resources
3396 # - main_display(): do the displaying
3397 # - main(): the main function that calls all main_*()
3399 # These parts are implemented as functions, being defined below in the
3400 # sequence they are called in the main() function.
3403 #######################################################################
3404 # main_init ()
3406 # set exit trap and create temporary files
3408 # Globals: $_TMP_DIR, $_TMP_CAT, $_TMP_STDIN
3410 landmark '13: main_init()';
3411 main_init()
3413 func_check main_init = 0 "$@";
3414 # call clean_up() on any signal
3415 trap_set clean_up;
3417 # create temporary directory
3418 umask 0022;
3419 _TMP_DIR='';
3420 for d in "${GROFF_TMPDIR}" "${TMPDIR}" "${TMP}" "${TEMP}" \
3421 "${TEMPDIR}" "${HOME}"'/tmp' '/tmp' "${HOME}" '.';
3423 if obj d is_empty || obj d is_not_dir || obj d is_not_writable;
3424 then
3425 continue;
3427 case "$d" in
3429 _TMP_DIR="${d}";
3432 _TMP_DIR="${d}"'/';
3434 esac;
3435 _TMP_DIR="${_TMP_DIR}${_PROGRAM_NAME}${_PROCESS_ID}";
3436 while obj _TMP_DIR is_existing;
3438 rm -f -r "${_TMP_DIR}" 2>${_NULL_DEV};
3439 if obj _TMP_DIR is_existing;
3440 then
3441 # $_TMP_DIR could not be removed
3442 _TMP_DIR="${_TMP_DIR}"'X';
3443 continue;
3444 else
3445 # $_TMP_DIR was removed
3446 break;
3448 done;
3449 mkdir "${_TMP_DIR}";
3450 if is_not_equal "$?" 0;
3451 then
3452 if obj _TMP_DIR is_existing;
3453 then
3454 rm -f -r "${_TMP_DIR}" 2>${_NULL_DEV};
3456 _TMP_DIR='';
3457 continue;
3459 if obj _TMP_DIR is_dir && obj _TMP_DIR is_writable;
3460 then
3461 # $_TMP_DIR can now be used as temporary directory
3462 break;
3464 if obj _TMP_DIR is_existing;
3465 then
3466 rm -f -r "${_TMP_DIR}" 2>${_NULL_DEV};
3468 _TMP_DIR='';
3469 continue;
3470 done;
3471 unset d;
3472 if obj _TMP_DIR is_empty;
3473 then
3474 error "Couldn't create a directory for storing temporary files.";
3477 _TMP_CAT="$(tmp_create groffer_cat)";
3478 _TMP_STDIN="$(tmp_create groffer_input)";
3480 # groffer configuration files
3481 for f in ${_CONFFILES};
3483 if obj f is_file;
3484 then
3485 echo '_groffer_opt=""' >>${_TMP_CAT};
3486 # collect the lines starting with a minus
3487 cat "$f" | sed -e \
3488 's/^[ ]*\(-.*\)$/_groffer_opt="${_groffer_opt} \1"'/ \
3489 >>${_TMP_CAT};
3490 # prepend the collected information to $GROFFER_OPT
3491 echo 'GROFFER_OPT="${_groffer_opt} ${GROFFER_OPT}"' >>${_TMP_CAT};
3493 done;
3494 . "${_TMP_CAT}";
3495 _TMP_CAT="$(tmp_create groffer_cat)";
3497 eval "${return_ok}";
3498 } # main_init()
3501 ########################################################################
3502 # main_parse_MANOPT ()
3504 # Parse $MANOPT to retrieve man options, but only if it is a non-empty
3505 # string; found man arguments can be overwritten by the command line.
3507 # Globals:
3508 # in: $MANOPT, $_OPTS_MANOPT_*
3509 # out: $_MANOPT_*
3510 # in/out: $GROFFER_OPT
3512 landmark '14: main_parse_MANOPT()';
3513 main_parse_MANOPT()
3515 func_check main_parse_MANOPT = 0 "$@";
3516 local _opt;
3517 local _list;
3518 _list='';
3519 if obj MANOPT is_not_empty;
3520 then
3521 MANOPT="$(echo -n "${MANOPT}" | \
3522 sed -e 's/^'"${_SPACE}${_SPACE}"'*//')";
3524 if obj MANOPT is_empty;
3525 then
3526 eval "${return_ok}";
3528 # add arguments in $MANOPT by mapping them to groffer options
3529 eval set -- "$(list_from_cmdline _OPTS_MANOPT "${MANOPT}")";
3530 until test "$#" -le 0 || is_equal "$1" '--';
3532 _opt="$1";
3533 shift;
3534 case "${_opt}" in
3535 -7|--ascii)
3536 list_append _list '--ascii';
3538 -a|--all)
3539 list_append _list '--all';
3541 -c|--catman)
3542 do_nothing;
3543 shift;
3545 -d|--debug)
3546 list_append _list '--debug';
3548 -D|--default)
3549 # undo all man options so far
3550 _list='';
3552 -e|--extension)
3553 list_append _list '--extension';
3554 shift;
3556 -f|--whatis)
3557 list_append _list '--whatis';
3558 shift;
3560 -h|--help)
3561 do_nothing;
3562 shift;
3564 -k|--apropos)
3565 # groffer's --apropos takes an argument, but man's does not, so
3566 do_nothing;
3567 shift;
3569 -l|--local-file)
3570 list_append _list '--local-file';
3572 -L|--locale)
3573 list_append _list '--locale' "$1";
3574 shift;
3576 -m|--systems)
3577 list_append _list '--systems' "$1";
3578 shift;
3580 -M|--manpath)
3581 list_append _list '--manpath' "$1";
3582 shift;
3584 -p|--preprocessor)
3585 do_nothing;
3586 shift;
3588 -P|--pager|--tty-viewer)
3589 list_append _list '--pager' "$1";
3590 shift;
3592 -r|--prompt)
3593 do_nothing;
3594 shift;
3596 -S|--sections)
3597 list_append _list '--sections' "$1";
3598 shift;
3600 -t|--troff)
3601 do_nothing;
3602 shift;
3604 -T|--device)
3605 list_append _list '-T' "$1";
3606 shift;
3608 -u|--update)
3609 do_nothing;
3610 shift;
3612 -V|--version)
3613 do_nothing;
3615 -w|--where|--location)
3616 list_append _list '--location';
3618 -Z|--ditroff)
3619 list_append _list '-Z' "$1";
3620 shift;
3622 # ignore all other options
3623 esac;
3624 done;
3625 # append the 2 lists in $_list and $GROFFER_OPT to $GROFFER_OPT
3626 if obj GROFFER_OPT is_empty;
3627 then
3628 GROFFER_OPT="${_list}";
3629 elif obj _list is_not_empty;
3630 then
3631 GROFFER_OPT="${_list} ${GROFFER_OPT}";
3633 eval "${return_ok}";
3634 } # main_parse_MANOPT()
3637 ########################################################################
3638 # main_parse_args (<command_line_args>*)
3640 # Parse arguments; process options and filespec parameters
3642 # Arguments: pass the command line arguments unaltered.
3643 # Globals:
3644 # in: $_OPTS_*
3645 # out: $_OPT_*, $_ADDOPTS, $_FILEARGS
3647 landmark '15: main_parse_args()';
3648 main_parse_args()
3650 func_check main_parse_args '>=' 0 "$@";
3651 local _arg;
3652 local _code;
3653 local _dpi;
3654 local _longopt;
3655 local _mode;
3656 local _opt;
3657 local _optchar;
3658 local _optarg;
3659 local _opts;
3660 local _string;
3662 eval set -- "${GROFFER_OPT}" '"$@"';
3664 eval set -- "$(list_from_cmdline _OPTS_CMDLINE "$@")";
3666 # By the call of `eval', unnecessary quoting was removed. So the
3667 # positional shell parameters ($1, $2, ...) are now guaranteed to
3668 # represent an option or an argument to the previous option, if any;
3669 # then a `--' argument for separating options and
3670 # parameters; followed by the filespec parameters if any.
3672 # Note, the existence of arguments to options has already been checked.
3673 # So a check for `$#' or `--' should not be done for arguments.
3675 until test "$#" -le 0 || is_equal "$1" '--';
3677 _opt="$1"; # $_opt is fed into the option handler
3678 shift;
3679 case "${_opt}" in
3680 -h|--help)
3681 usage;
3682 leave;
3684 -Q|--source) # output source code (`Quellcode').
3685 _OPT_MODE='source';
3687 -T|--device|--troff-device) # device; arg
3688 _OPT_DEVICE="$1";
3689 _check_device_with_mode;
3690 shift;
3692 -v|--version)
3693 version;
3694 leave;
3697 _OPT_V='yes';
3699 -Z|--ditroff|--intermediate-output) # groff intermediate output
3700 _OPT_Z='yes';
3702 -X|--X|--x)
3703 _OPT_MODE=x;
3706 # delete leading `-'
3707 _optchar="$(echo -n "${_opt}" | sed -e 's/^.//')";
3708 if list_has _OPTS_GROFF_SHORT_NA "${_optchar}";
3709 then
3710 list_append _ADDOPTS_GROFF "${_opt}";
3711 elif list_has _OPTS_GROFF_SHORT_ARG "${_optchar}";
3712 then
3713 list_append _ADDOPTS_GROFF "${_opt}" "$1";
3714 shift;
3715 else
3716 error "Unknown option : \`$1'";
3719 --all)
3720 _OPT_ALL="yes";
3722 --apropos) # run `apropos'
3723 apropos_run "$1";
3724 _code="$?";
3725 clean_up;
3726 exit "${_code}";
3728 --apropos-data) # run `apropos' for data sections
3729 apropos_run "$1" | grep '^[^(]*([457][^)]*)';
3730 _code="$?";
3731 clean_up;
3732 exit "${_code}";
3734 --apropos-devel) # run `apropos' for development sections
3735 apropos_run "$1" | grep '^[^(]*([239][^)]*)';
3736 _code="$?";
3737 clean_up;
3738 exit "${_code}";
3740 --apropos-progs) # run `apropos' for program sections
3741 apropos_run "$1" | grep '^[^(]*([168][^)]*)';
3742 _code="$?";
3743 clean_up;
3744 exit "${_code}";
3746 --ascii)
3747 list_append _ADDOPTS_GROFF '-mtty-char';
3748 if obj _mode is_empty;
3749 then
3750 _mode='text';
3753 --auto) # the default automatic mode
3754 _mode='';
3756 --bd) # border color for viewers, arg;
3757 _OPT_BD="$1";
3758 shift;
3760 --bg|--backgroud) # background color for viewers, arg;
3761 _OPT_BG="$1";
3762 shift;
3764 --bw) # border width for viewers, arg;
3765 _OPT_BW="$1";
3766 shift;
3768 --default) # reset variables to default
3769 reset;
3771 --default-modes) # sequence of modes in auto mode; arg
3772 _OPT_DEFAULT_MODES="$1";
3773 shift;
3775 --debug) # buggy, only for development
3776 _OPT_DEBUG='yes';
3778 --display) # set X display, arg
3779 _OPT_DISPLAY="$1";
3780 shift;
3782 --dvi)
3783 _OPT_MODE='dvi';
3785 --dvi-viewer) # viewer program for dvi mode; arg
3786 _OPT_VIEWER_DVI="$1";
3787 shift;
3789 --extension) # the extension for man pages, arg
3790 _OPT_EXTENSION="$1";
3791 shift;
3793 --fg|--foreground) # foreground color for viewers, arg;
3794 _OPT_FG="$1";
3795 shift;
3797 --fn|--font) # set font for viewers, arg;
3798 _OPT_FN="$1";
3799 shift;
3801 --geometry) # window geometry for viewers, arg;
3802 _OPT_GEOMETRY="$1";
3803 shift;
3805 --groff)
3806 _OPT_MODE='groff';
3808 --html|--www) # display with web browser
3809 _OPT_MODE=html;
3811 --html-viewer|--www-viewer) # viewer program for html mode; arg
3812 _OPT_VIEWER_HTML="$1";
3813 shift;
3815 --iconic) # start viewers as icons
3816 _OPT_ICONIC='yes';
3818 --locale) # set language for man pages, arg
3819 # argument is xx[_territory[.codeset[@modifier]]] (ISO 639,...)
3820 _OPT_LANG="$1";
3821 shift;
3823 --local-file) # force local files; same as `--no-man'
3824 _MAN_FORCE='no';
3825 _MAN_ENABLE='no';
3827 --location|--where) # print file locations to stderr
3828 _OPT_LOCATION='yes';
3830 --man) # force all file params to be man pages
3831 _MAN_ENABLE='yes';
3832 _MAN_FORCE='yes';
3834 --manpath) # specify search path for man pages, arg
3835 # arg is colon-separated list of directories
3836 _OPT_MANPATH="$1";
3837 shift;
3839 --mode) # display mode
3840 _arg="$1";
3841 shift;
3842 case "${_arg}" in
3843 auto|'') # search mode automatically among default
3844 _mode='';
3846 groff) # pass input to plain groff
3847 _mode='groff';
3849 html|www) # display with a web browser
3850 _mode='html';
3852 dvi) # display with xdvi viewer
3853 _mode='dvi';
3855 pdf) # display with PDF viewer
3856 _mode='pdf';
3858 ps) # display with Postscript viewer
3859 _mode='ps';
3861 text) # output on terminal
3862 _mode='text';
3864 tty) # output on terminal
3865 _mode='tty';
3867 X|x) # output on X roff viewer
3868 _mode='x';
3870 Q|source) # display source code
3871 _mode="source";
3874 error "unknown mode ${_arg}";
3876 esac;
3877 _OPT_MODE="${_mode}";
3879 --no-location) # disable former call to `--location'
3880 _OPT_LOCATION='yes';
3882 --no-man) # disable search for man pages
3883 # the same as --local-file
3884 _MAN_FORCE="no";
3885 _MAN_ENABLE="no";
3887 --pager) # set paging program for tty mode, arg
3888 _OPT_PAGER="$1";
3889 shift;
3891 --pdf)
3892 _OPT_MODE='pdf';
3894 --pdf-viewer) # viewer program for ps mode; arg
3895 _OPT_VIEWER_PDF="$1";
3896 shift;
3898 --ps)
3899 _OPT_MODE='ps';
3901 --ps-viewer) # viewer program for ps mode; arg
3902 _OPT_VIEWER_PS="$1";
3903 shift;
3905 --resolution) # set resolution for X devices, arg
3906 _arg="$1";
3907 shift;
3908 case "${_arg}" in
3909 75|75dpi)
3910 _dpi=75;
3912 100|100dpi)
3913 _dpi=100;
3916 error "only resoutions of 75 or 100 dpi are supported";
3918 esac;
3919 _OPT_RESOLUTION="${_dpi}";
3921 --rv)
3922 _OPT_RV='yes';
3924 --sections) # specify sections for man pages, arg
3925 # arg is colon-separated list of section names
3926 _OPT_SECTIONS="$1";
3927 shift;
3929 --shell)
3930 # already done during the first run; so ignore the argument
3931 shift;
3933 --systems) # man pages for different OS's, arg
3934 # argument is a comma-separated list
3935 _OPT_SYSTEMS="$1";
3936 shift;
3938 --text) # text mode without pager
3939 _OPT_MODE=text;
3941 --title) # title for X viewers; arg
3942 _OPT_TITLE="$1";
3943 shift;
3945 --tty) # tty mode, text with pager
3946 _OPT_MODE=tty;
3948 --text-device|--tty-device) # device for tty mode; arg
3949 _OPT_TEXT_DEVICE="$1";
3950 shift;
3952 --whatis)
3953 _OPT_WHATIS='yes';
3955 --xrm) # pass X resource string, arg;
3956 list_append _OPT_XRM "$1";
3957 shift;
3959 --x-viewer|--X-viewer) # viewer program for x mode; arg
3960 _OPT_VIEWER_X="$1";
3961 shift;
3964 error 'error on argument parsing : '"\`$*'";
3966 esac;
3967 done;
3968 shift; # remove `--' argument
3970 if obj _DEBUG is_not_yes;
3971 then
3972 if obj _OPT_DEBUG is_yes;
3973 then
3974 _DEBUG='yes';
3978 # Remaining arguments are file names (filespecs).
3979 # Save them to list $_FILEARGS
3980 if is_equal "$#" 0;
3981 then # use "-" for standard input
3982 set -- '-';
3984 _FILEARGS='';
3985 list_append _FILEARGS "$@";
3986 if list_has _FILEARGS '-';
3987 then
3988 save_stdin;
3990 # $_FILEARGS must be retrieved with `eval set -- "$_FILEARGS"'
3991 eval "${return_ok}";
3992 } # main_parse_args()
3994 # Called from main_parse_args() because double `case' is not possible.
3995 # Globals: $_OPT_DEVICE, $_OPT_MODE
3996 _check_device_with_mode()
3998 func_check _check_device_with_mode = 0 "$@";
3999 case "${_OPT_DEVICE}" in
4000 dvi)
4001 _OPT_MODE=dvi;
4002 eval "${return_ok}";
4004 html)
4005 _OPT_MODE=html;
4006 eval "${return_ok}";
4008 lbp|lj4)
4009 _OPT_MODE=groff;
4010 eval "${return_ok}";
4013 _OPT_MODE=ps;
4014 eval "${return_ok}";
4016 ascii|cp1047|latin1|utf8)
4017 if obj _OPT_MODE is_not_equal text;
4018 then
4019 _OPT_MODE=tty; # default text mode
4021 eval "${return_ok}";
4024 _OPT_MODE=x;
4025 eval "${return_ok}";
4027 *) # unknown device, go to groff mode
4028 _OPT_MODE=groff;
4029 eval "${return_ok}";
4031 esac;
4032 eval "${return_error}";
4036 ########################################################################
4037 # main_set_mode ()
4039 # Determine the display mode.
4041 # Globals:
4042 # in: $DISPLAY, $_OPT_MODE, $_OPT_DEVICE
4043 # out: $_DISPLAY_MODE
4046 # _get_first_prog (<proglist>)
4048 # Retrieve first argument that represents an existing program in $PATH.
4049 # Local function for main_set_mode().
4051 # Arguments: 1; a comma-separated list of commands (with options),
4052 # like $_VIEWER_*.
4054 # Return : `1' if none found, `0' if found.
4055 # Output : the argument that succeded.
4057 landmark '16: main_set_mode()';
4058 main_set_mode()
4060 func_check main_set_mode = 0 "$@";
4061 local m;
4062 local _modes;
4063 local _viewer;
4064 local _viewers;
4066 # handle apropos
4067 if obj _OPT_APROPOS is_not_empty;
4068 then
4069 apropos "${_OPT_APROPOS}";
4070 _code="$?";
4071 clean_up;
4072 exit "${_code}";
4074 if obj _OPT_APROPOS_DATA is_not_empty;
4075 then
4076 apropos "$@" | grep '^[^(]*([457])';
4077 _code="$?";
4078 clean_up;
4079 exit "${_code}";
4081 if obj _OPT_APROPOS_DEVEL is_not_empty;
4082 then
4083 apropos "$@" | grep '^[^(]*([239])';
4084 _code="$?";
4085 clean_up;
4086 exit "${_code}";
4088 if obj _OPT_APROPOS_PROGS is_not_empty;
4089 then
4090 apropos "$@" | grep '^[^(]*([168])';
4091 _code="$?";
4092 clean_up;
4093 exit "${_code}";
4096 # set display
4097 if obj _OPT_DISPLAY is_not_empty;
4098 then
4099 DISPLAY="${_OPT_DISPLAY}";
4102 if obj _OPT_V is_yes;
4103 then
4104 _DISPLAY_MODE='groff';
4105 list_append _ADDOPTS_GROFF '-V';
4107 if obj _OPT_Z is_yes;
4108 then
4109 _DISPLAY_MODE='groff';
4110 list_append _ADDOPTS_GROFF '-Z';
4112 if obj _OPT_MODE is_equal 'groff';
4113 then
4114 _DISPLAY_MODE='groff';
4116 if obj _DISPLAY_MODE is_equal 'groff';
4117 then
4118 eval "${return_ok}";
4121 if obj _OPT_MODE is_equal 'source';
4122 then
4123 _DISPLAY_MODE='source';
4124 eval "${return_ok}";
4127 case "${_OPT_MODE}" in
4128 '') # automatic mode
4129 case "${_OPT_DEVICE}" in
4131 if obj DISPLAY is_empty;
4132 then
4133 error "no X display found for device ${_OPT_DEVICE}";
4135 _DISPLAY_MODE='x';
4136 eval "${return_ok}";
4138 ascii|cp1047|latin1|utf8)
4139 if obj _DISPLAY_MODE is_not_equal 'text';
4140 then
4141 _DISPLAY_MODE='tty';
4143 eval "${return_ok}";
4145 esac;
4146 if obj DISPLAY is_empty;
4147 then
4148 _DISPLAY_MODE='tty';
4149 eval "${return_ok}";
4152 if obj _OPT_DEFAULT_MODES is_empty;
4153 then
4154 _modes="${_DEFAULT_MODES}";
4155 else
4156 _modes="${_OPT_DEFAULT_MODES}";
4159 text)
4160 _DISPLAY_MODE='text';
4161 eval "${return_ok}";
4163 tty)
4164 _DISPLAY_MODE='tty';
4165 eval "${return_ok}";
4167 *) # display mode was given
4168 if obj DISPLAY is_empty;
4169 then
4170 error "you must be in X Window for ${_OPT_MODE} mode.";
4172 _modes="${_OPT_MODE}";
4174 esac;
4176 # only viewer modes are left
4177 eval set -- "$(list_from_split "${_modes}" ',')";
4178 while test "$#" -gt 0;
4180 m="$1";
4181 shift;
4182 case "$m" in
4183 text)
4184 _DISPLAY_MODE='text';
4185 eval "${return_ok}";
4187 tty)
4188 _DISPLAY_MODE='tty';
4189 eval "${return_ok}";
4192 if obj _OPT_VIEWER_X is_not_empty;
4193 then
4194 _viewers="${_OPT_VIEWER_X}";
4195 else
4196 _viewers="${_VIEWER_X}";
4198 _viewer="$(_get_first_prog "${_viewers}")";
4199 if is_not_equal "$?" 0;
4200 then
4201 continue;
4203 _DISPLAY_PROG="${_viewer}";
4204 _DISPLAY_MODE='x';
4205 eval "${return_ok}";
4207 dvi)
4208 if obj _OPT_VIEWER_DVI is_not_empty;
4209 then
4210 _viewers="${_OPT_VIEWER_DVI}";
4211 else
4212 _viewers="${_VIEWER_DVI}";
4214 _viewer="$(_get_first_prog "${_viewers}")";
4215 if is_not_equal "$?" 0;
4216 then
4217 continue;
4219 _DISPLAY_PROG="${_viewer}";
4220 _DISPLAY_MODE="dvi";
4221 eval "${return_ok}";
4223 pdf)
4224 if obj _OPT_VIEWER_PDF is_not_empty;
4225 then
4226 _viewers="${_OPT_VIEWER_PDF}";
4227 else
4228 _viewers="${_VIEWER_PDF}";
4230 _viewer="$(_get_first_prog "${_viewers}")";
4231 if is_not_equal "$?" 0;
4232 then
4233 continue;
4235 _DISPLAY_PROG="${_viewer}";
4236 _DISPLAY_MODE="pdf";
4237 eval "${return_ok}";
4240 if obj _OPT_VIEWER_PS is_not_empty;
4241 then
4242 _viewers="${_OPT_VIEWER_PS}";
4243 else
4244 _viewers="${_VIEWER_PS}";
4246 _viewer="$(_get_first_prog "${_viewers}")";
4247 if is_not_equal "$?" 0;
4248 then
4249 continue;
4251 _DISPLAY_PROG="${_viewer}";
4252 _DISPLAY_MODE="ps";
4253 eval "${return_ok}";
4255 html)
4256 if obj _OPT_VIEWER_HTML is_not_empty;
4257 then
4258 _viewers="${_OPT_VIEWER_HTML}";
4259 else
4260 _viewers="${_VIEWER_HTML}";
4262 _viewer="$(_get_first_prog "${_viewers}")";
4263 if is_not_equal "$?" 0;
4264 then
4265 continue;
4267 _DISPLAY_PROG="${_viewer}";
4268 _DISPLAY_MODE=html;
4269 eval "${return_ok}";
4271 esac;
4272 done;
4273 error "no suitable display mode found.";
4276 _get_first_prog()
4278 local i;
4279 if is_equal "$#" 0;
4280 then
4281 error "_get_first_prog() needs 1 argument.";
4283 if is_empty "$1";
4284 then
4285 return "${_BAD}";
4287 eval set -- "$(list_from_split "$1" ',')";
4288 for i in "$@";
4290 if obj i is_empty;
4291 then
4292 continue;
4294 if is_prog "$(get_first_essential $i)";
4295 then
4296 echo -n "$i";
4297 return "${_GOOD}";
4299 done;
4300 return "${_BAD}";
4301 } # main_set_mode()
4304 #######################################################################
4305 # main_do_fileargs ()
4307 # Process filespec arguments in $_FILEARGS.
4309 # Globals:
4310 # in: $_FILEARGS (process with `eval set -- "$_FILEARGS"')
4312 landmark '17: main_do_fileargs()';
4313 main_do_fileargs()
4315 func_check main_do_fileargs = 0 "$@";
4316 local _exitcode;
4317 local _filespec;
4318 local _name;
4319 _exitcode="${_BAD}";
4320 eval set -- "${_FILEARGS}";
4321 unset _FILEARGS;
4322 # temporary storage of all input to $_TMP_CAT
4323 while test "$#" -ge 2;
4325 # test for `s name' arguments, with `s' a 1-char standard section
4326 _filespec="$1";
4327 shift;
4328 case "${_filespec}" in
4330 continue;
4332 '-')
4333 if register_file '-';
4334 then
4335 _exitcode="${_GOOD}";
4337 continue;
4340 if list_has_not _MAN_AUTO_SEC "${_filespec}";
4341 then
4342 if do_filearg "${_filespec}";
4343 then
4344 _exitcode="${_GOOD}";
4346 continue;
4348 _name="$1";
4349 case "${_name}" in
4350 */*|man:*|*\(*\)|*."${_filespec}")
4351 if do_filearg "${_filespec}";
4352 then
4353 _exitcode="${_GOOD}";
4355 continue;
4357 esac;
4358 if do_filearg "man:${_name}(${_filespec})";
4359 then
4360 _exitcode="${_GOOD}";
4361 shift;
4362 continue;
4363 else
4364 if do_filearg "${_filespec}";
4365 then
4366 _exitcode="${_GOOD}";
4368 continue;
4372 if do_filearg "${_filespec}";
4373 then
4374 _exitcode="${_GOOD}";
4376 continue;
4378 esac;
4379 done; # end of `s name' test
4380 while test "$#" -gt 0;
4382 _filespec="$1";
4383 shift;
4384 if do_filearg "${_filespec}";
4385 then
4386 _exitcode="${_GOOD}";
4388 done;
4389 rm -f "${_TMP_STDIN}";
4390 if is_equal "${_exitcode}" "${_BAD}";
4391 then
4392 eval "${return_bad}";
4394 eval "${return_ok}";
4395 } # main_do_fileargs()
4398 ########################################################################
4399 # main_set_resources ()
4401 # Determine options for setting X resources with $_DISPLAY_PROG.
4403 # Globals: $_DISPLAY_PROG, $_OUTPUT_FILE_NAME
4405 landmark '18: main_set_resources()';
4406 main_set_resources()
4408 func_check main_set_resources = 0 "$@";
4409 local _prog; # viewer program
4410 local _rl; # resource list
4411 local n;
4412 _title="$(get_first_essential \
4413 "${_OPT_TITLE}" "${_REGISTERED_TITLE}")";
4414 _OUTPUT_FILE_NAME='';
4415 set -- ${_title};
4416 until is_equal "$#" 0;
4418 n="$1";
4419 case "$n" in
4421 continue;
4424 n="$(echo -n "$1" | sed -e 's/^,,*//')";
4426 esac
4427 if obj n is_empty;
4428 then
4429 continue;
4431 if obj _OUTPUT_FILE_NAME is_not_empty;
4432 then
4433 _OUTPUT_FILE_NAME="${_OUTPUT_FILE_NAME},";
4435 _OUTPUT_FILE_NAME="${_OUTPUT_FILE_NAME}$n";
4436 shift;
4437 done;
4438 case "${_OUTPUT_FILE_NAME}" in
4440 _OUTPUT_FILE_NAME='-';
4443 error "$_OUTPUT_FILE_NAME starts with a comma.";
4445 esac;
4446 _OUTPUT_FILE_NAME="${_TMP_DIR}/${_OUTPUT_FILE_NAME}";
4448 if obj _DISPLAY_PROG is_empty;
4449 then # for example, for groff mode
4450 _DISPLAY_ARGS='';
4451 eval "${return_ok}";
4454 set -- ${_DISPLAY_PROG};
4455 _prog="$(base_name "$1")";
4456 _rl='';
4457 if obj _OPT_BD is_not_empty;
4458 then
4459 case "${_prog}" in
4460 ghostview|gv|gxditview|xditview|xdvi)
4461 list_append _rl '-bd' "${_OPT_BD}";
4463 esac;
4465 if obj _OPT_BG is_not_empty;
4466 then
4467 case "${_prog}" in
4468 ghostview|gv|gxditview|xditview|xdvi)
4469 list_append _rl '-bg' "${_OPT_BG}";
4471 xpdf)
4472 list_append _rl '-papercolor' "${_OPT_BG}";
4474 esac;
4476 if obj _OPT_BW is_not_empty;
4477 then
4478 case "${_prog}" in
4479 ghostview|gv|gxditview|xditview|xdvi)
4480 _list_append _rl '-bw' "${_OPT_BW}";
4482 esac;
4484 if obj _OPT_FG is_not_empty;
4485 then
4486 case "${_prog}" in
4487 ghostview|gv|gxditview|xditview|xdvi)
4488 list_append _rl '-fg' "${_OPT_FG}";
4490 esac;
4492 if is_not_empty "${_OPT_FN}";
4493 then
4494 case "${_prog}" in
4495 ghostview|gv|gxditview|xditview|xdvi)
4496 list_append _rl '-fn' "${_OPT_FN}";
4498 esac;
4500 if is_not_empty "${_OPT_GEOMETRY}";
4501 then
4502 case "${_prog}" in
4503 ghostview|gv|gxditview|xditview|xdvi|xpdf)
4504 list_append _rl '-geometry' "${_OPT_GEOMETRY}";
4506 esac;
4508 if is_empty "${_OPT_RESOLUTION}";
4509 then
4510 _OPT_RESOLUTION="${_DEFAULT_RESOLUTION}";
4511 case "${_prog}" in
4512 gxditview|xditview)
4513 list_append _rl '-resolution' "${_DEFAULT_RESOLUTION}";
4515 xpdf)
4516 case "${_DEFAULT_RESOLUTION}" in
4518 # 72dpi is '100'
4519 list_append _rl '-z' '104';
4521 100)
4522 list_append _rl '-z' '139';
4524 esac;
4526 esac;
4527 else
4528 case "${_prog}" in
4529 ghostview|gv|gxditview|xditview|xdvi)
4530 list_append _rl '-resolution' "${_OPT_RESOLUTION}";
4532 xpdf)
4533 case "${_OPT_RESOLUTION}" in
4535 list_append _rl '-z' '104';
4536 # '100' corresponds to 72dpi
4538 100)
4539 list_append _rl '-z' '139';
4541 esac;
4543 esac;
4545 if is_yes "${_OPT_ICONIC}";
4546 then
4547 case "${_prog}" in
4548 ghostview|gv|gxditview|xditview|xdvi)
4549 list_append _rl '-iconic';
4551 esac;
4553 if is_yes "${_OPT_RV}";
4554 then
4555 case "${_prog}" in
4556 ghostview|gv|gxditview|xditview|xdvi)
4557 list_append _rl '-rv';
4559 esac;
4561 if is_not_empty "${_OPT_XRM}";
4562 then
4563 case "${_prog}" in
4564 ghostview|gv|gxditview|xditview|xdvi|xpdf)
4565 eval set -- "{$_OPT_XRM}";
4566 for i in "$@";
4568 list_append _rl '-xrm' "$i";
4569 done;
4571 esac;
4573 if is_not_empty "${_title}";
4574 then
4575 case "${_prog}" in
4576 gxditview|xditview)
4577 list_append _rl '-title' "${_title}";
4579 esac;
4581 _DISPLAY_ARGS="${_rl}";
4583 eval "${return_ok}";
4584 } # main_set_resources
4587 ########################################################################
4588 # main_display ()
4590 # Do the actual display of the whole thing.
4592 # Globals:
4593 # in: $_DISPLAY_MODE, $_OPT_DEVICE,
4594 # $_ADDOPTS_GROFF, $_ADDOPTS_POST, $_ADDOPTS_X,
4595 # $_REGISTERED_TITLE, $_TMP_CAT,
4596 # $_OPT_PAGER $PAGER $_MANOPT_PAGER
4598 landmark '19: main_display()';
4599 main_display()
4601 func_check main_display = 0 "$@";
4602 local p;
4603 local _addopts;
4604 local _device;
4605 local _groggy;
4606 local _modefile;
4607 local _options;
4608 local _pager;
4609 local _title;
4610 export _addopts;
4611 export _groggy;
4612 export _modefile;
4614 if obj _TMP_CAT is_non_empty_file;
4615 then
4616 _modefile="${_OUTPUT_FILE_NAME}";
4617 else
4618 clean_up;
4619 eval "${return_ok}";
4621 case "${_DISPLAY_MODE}" in
4622 groff)
4623 _ADDOPTS_GROFF="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}";
4624 if obj _OPT_DEVICE is_not_empty;
4625 then
4626 _ADDOPTS_GROFF="${_ADDOPTS_GROFF} -T${_OPT_DEVICE}";
4628 _groggy="$(tmp_cat | eval grog "${_options}")";
4629 trap_clean;
4630 # start a new shell program to get another process ID.
4631 sh -c '
4632 set -e;
4633 test -f "${_modefile}" && rm -f "${_modefile}";
4634 mv "${_TMP_CAT}" "${_modefile}";
4635 cat "${_modefile}" | \
4637 clean_up()
4639 if test -d "${_TMP_DIR}";
4640 then
4641 rm -f "${_TMP_DIR}"/* || true;
4642 rmdir "${_TMP_DIR}";
4645 trap clean_up 0 2>${_NULL_DEV} || true;
4646 eval "${_groggy}" "${_ADDOPTS_GROFF}";
4647 ) &'
4649 text|tty)
4650 case "${_OPT_DEVICE}" in
4652 _device="$(get_first_essential \
4653 "${_OPT_TEXT_DEVICE}" "${_DEFAULT_TTY_DEVICE}")";
4655 ascii|cp1047|latin1|utf8)
4656 _device="${_OPT_DEVICE}";
4659 warning \
4660 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4662 esac;
4663 _addopts="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}";
4664 _groggy="$(tmp_cat | grog -T${_device})";
4665 if obj _DISPLAY_MODE is_equal 'text';
4666 then
4667 tmp_cat | eval "${_groggy}" "${_addopts}";
4668 else
4669 _pager='';
4670 for p in "${_OPT_PAGER}" "${PAGER}" "${_MANOPT_PAGER}" \
4671 'less -r -R' 'more' 'pager' 'cat';
4673 if is_prog $p;
4674 then # no "" for is_prog() allows args for $p
4675 _pager="$p";
4676 break;
4678 done;
4679 if obj _pager is_empty;
4680 then
4681 error 'no pager program found for tty mode';
4683 tmp_cat | eval "${_groggy}" "${_addopts}" | \
4684 eval "${_pager}";
4686 clean_up;
4689 #### viewer modes
4691 dvi)
4692 case "${_OPT_DEVICE}" in
4693 ''|dvi) do_nothing; ;;
4695 warning \
4696 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4698 esac;
4699 _modefile="${_modefile}".dvi;
4700 _groggy="$(tmp_cat | grog -Tdvi)";
4701 _do_display;
4703 html)
4704 case "${_OPT_DEVICE}" in
4705 ''|html) do_nothing; ;;
4707 warning \
4708 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4710 esac;
4711 _modefile="${_modefile}".html;
4712 _groggy="$(tmp_cat | grog -Thtml)";
4713 _do_display;
4715 pdf)
4716 case "${_OPT_DEVICE}" in
4717 ''|ps)
4718 do_nothing;
4721 warning \
4722 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4724 esac;
4725 _groggy="$(tmp_cat | grog -Tps)";
4726 trap_clean;
4727 # start a new shell program to get another process ID.
4728 sh -c '
4729 set -e;
4730 _psfile="${_modefile}.ps";
4731 _modefile="${_modefile}.pdf";
4732 test -f "${_psfile}" && rm -f "${_psfile}";
4733 test -f "${_modefile}" && rm -f "${_modefile}";
4734 cat "${_TMP_CAT}" | \
4735 eval "${_groggy}" "${_ADDOPTS_GROFF}" > "${_psfile}";
4736 gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \
4737 -sOutputFile="${_modefile}" -c save pop -f "${_psfile}";
4738 test -f "${_psfile}" && rm -f "${_psfile}";
4739 test -f "${_TMP_CAT}" && rm -f "${_TMP_CAT}";
4741 clean_up() {
4742 rm -f "${_modefile}";
4743 if test -d "${_TMP_DIR}";
4744 then
4745 rm -f "${_TMP_DIR}"/* || true;
4746 rmdir "${_TMP_DIR}";
4749 trap clean_up 0 2>${_NULL_DEV} || true;
4750 eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "${_modefile}";
4751 ) &'
4754 case "${_OPT_DEVICE}" in
4755 ''|ps)
4756 do_nothing;
4759 warning \
4760 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4762 esac;
4763 _modefile="${_modefile}".ps;
4764 _groggy="$(tmp_cat | grog -Tps)";
4765 _do_display;
4767 source)
4768 tmp_cat;
4769 clean_up;
4772 case "${_OPT_DEVICE}" in
4774 _groggy="$(tmp_cat | grog -Z)";
4776 X*|ps)
4777 _groggy="$(tmp_cat | grog -T"${_OPT_DEVICE}" -Z)";
4780 warning \
4781 "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
4782 _groggy="$(tmp_cat | grog -Z)";
4784 esac;
4785 _do_display;
4788 error "unknown mode \`${_DISPLAY_MODE}'";
4790 esac;
4791 eval "${return_ok}";
4792 } # main_display()
4794 _do_display()
4796 func_check _do_display = 0 "$@";
4797 trap_clean;
4798 # start a new shell program for another process ID and better
4799 # cleaning-up of the temporary files.
4800 sh -c '
4801 set -e;
4802 test -f "${_modefile}" && rm -f "${_modefile}";
4803 cat "${_TMP_CAT}" | \
4804 eval "${_groggy}" "${_ADDOPTS_GROFF}" > "${_modefile}";
4805 rm -f "${_TMP_CAT}";
4807 clean_up() {
4808 if test -d "${_TMP_DIR}";
4809 then
4810 rm -f "${_TMP_DIR}"/* || true;
4811 rmdir "${_TMP_DIR}";
4814 trap clean_up 0 2>${_NULL_DEV} || true;
4815 eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "${_modefile}";
4816 ) &'
4820 ########################################################################
4821 # main (<command_line_args>*)
4823 # The main function for groffer.
4825 # Arguments:
4827 main()
4829 func_check main '>=' 0 "$@";
4830 # Do not change the sequence of the following functions!
4831 main_init;
4832 main_parse_MANOPT;
4833 main_parse_args "$@";
4834 main_set_mode;
4835 main_do_fileargs;
4836 main_set_resources;
4837 main_display;
4838 eval "${return_ok}";
4841 landmark '20: end of function definitions';
4843 ########################################################################
4845 main "$@";