]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/groff/contrib/groffer/groffer2.sh
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / groff / contrib / groffer / groffer2.sh
1 #! /bin/sh
2
3 # groffer - display groff files
4
5 # Source file position: <groff-source>/contrib/groffer/groffer2.sh
6 # Installed position: <prefix>/lib/groff/groffer/groffer2.sh
7
8 # This file should not be run independently.  It is called by
9 # `groffer.sh' in the source or by the installed `groffer' program.
10
11 # Copyright (C) 2001,2002,2003,2004,2005
12 # Free Software Foundation, Inc.
13 # Written by Bernd Warken
14
15 # Last update: 22 August 2005
16
17 # This file is part of `groffer', which is part of `groff'.
18
19 # `groff' is free software; you can redistribute it and/or modify it
20 # under the terms of the GNU General Public License as published by
21 # the Free Software Foundation; either version 2, or (at your option)
22 # any later version.
23
24 # `groff' is distributed in the hope that it will be useful, but
25 # WITHOUT ANY WARRANTY; without even the implied warranty of
26 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27 # General Public License for more details.
28
29 # You should have received a copy of the GNU General Public License
30 # along with `groff'; see the files COPYING and LICENSE in the top
31 # directory of the `groff' source.  If not, write to the Free Software
32 # Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301,
33 # USA.
34
35
36 ########################################################################
37 #             Test of rudimentary shell functionality
38 ########################################################################
39
40
41 ########################################################################
42 # Test of `unset'
43 #
44 export _UNSET;
45 export _foo;
46 _foo=bar;
47 _res="$(unset _foo 2>&1)";
48 if unset _foo >${_NULL_DEV} 2>&1 && \
49    test _"${_res}"_ = __ && test _"${_foo}"_ = __
50 then
51   _UNSET='unset';
52   eval "${_UNSET}" _foo;
53   eval "${_UNSET}" _res;
54 else
55   _UNSET=':';
56 fi;
57
58
59 ########################################################################
60 # Test of `test'.
61 #
62 if test a = a && test a != b && test -f "${_GROFFER_SH}"
63 then
64   :;
65 else
66   echo '"test" did not work.' >&2;
67   exit "${_ERROR}";
68 fi;
69
70
71 ########################################################################
72 # Test of `echo' and the `$()' construct.
73 #
74 if echo '' >${_NULL_DEV}
75 then
76   :;
77 else
78   echo '"echo" did not work.' >&2;
79   exit "${_ERROR}";
80 fi;
81 if test _"$(t1="$(echo te)" &&
82             t2="$(echo '')" &&
83             t3="$(echo 'st')" &&
84             echo "${t1}${t2}${t3}")"_ \
85      != _test_
86 then
87   echo 'The "$()" construct did not work' >&2;
88   exit "${_ERROR}";
89 fi;
90
91
92 ########################################################################
93 # Test of sed program; test in groffer.sh is not valid here.
94 #
95 if test _"$(echo red | sed -e 's/r/s/')"_ != _sed_
96 then
97   echo 'The sed program did not work.' >&2;
98   exit "${_ERROR}";
99 fi;
100
101
102 ########################################################################
103 # Test of function definitions.
104 #
105 _t_e_s_t_f_u_n_c_()
106 {
107   return 0;
108 }
109
110 if _t_e_s_t_f_u_n_c_ 2>${_NULL_DEV}
111 then
112   :;
113 else
114   echo 'Shell '"${_SHELL}"' does not support function definitions.' >&2;
115   exit "${_ERROR}";
116 fi;
117
118
119 ########################################################################
120 #                    debug - diagnostic messages
121 ########################################################################
122
123 export _DEBUG_STACKS;
124 _DEBUG_STACKS='no';             # disable stack output in each function
125 #_DEBUG_STACKS='yes';           # enable stack output in each function
126
127 export _DEBUG_LM;
128 _DEBUG_LM='no';                 # disable landmark messages
129 #_DEBUG_LM='yes';               # enable landmark messages
130
131 export _DEBUG_KEEP_FILES;
132 _DEBUG_KEEP_FILES='no'          # disable file keeping in temporary dir
133 #_DEBUG_KEEP_FILES='yes'        # enable file keeping in temporary dir
134
135 export _DEBUG_PRINT_PARAMS;
136 _DEBUG_PRINT_PARAMS='no';       # disable printing of all parameters
137 #_DEBUG_PRINT_PARAMS='yes';     # enable printing of all parameters
138
139 export _DEBUG_PRINT_SHELL;
140 _DEBUG_PRINT_SHELL='no';        # disable printing of the shell name
141 #_DEBUG_PRINT_SHELL='yes';      # enable printing of the shell name
142
143 export _DEBUG_PRINT_TMPDIR;
144 _DEBUG_PRINT_TMPDIR='no';       # disable printing of the temporary dir
145 #_DEBUG_PRINT_TMPDIR='yes';     # enable printing of the temporary dir
146
147 export _DEBUG_USER_WITH_STACK;
148 _DEBUG_USER_WITH_STACK='no';    # disable stack dump in error_user()
149 #_DEBUG_USER_WITH_STACK='yes';  # enable stack dump in error_user()
150
151 # determine all --debug* options
152 case " $*" in
153 *\ --debug*)
154   case " $* " in
155   *' --debug '*)
156     # _DEBUG_STACKS='yes';
157     # _DEBUG_LM='yes';
158     _DEBUG_KEEP_FILES='yes';
159     _DEBUG_PRINT_PARAMS='yes';
160     _DEBUG_PRINT_SHELL='yes';
161     _DEBUG_PRINT_TMPDIR='yes';
162     _DEBUG_USER_WITH_STACK='yes';
163     ;;
164   esac;
165   d=' --debug-all --debug-keep --debug-lm --debug-params --debug-shell '\
166 '--debug-stacks --debug-tmpdir --debug-user ';
167   for i
168   do
169     case "$i" in
170     --debug-s)
171       echo 'The abbreviation --debug-s has multiple options: '\
172 '--debug-shell and --debug-stacks.' >&2
173       exit "${_ERROR}";
174       ;;
175     esac;
176     case "$d" in
177     *\ ${i}*)
178       # extract whole word of abbreviation $i
179       s="$(cat <<EOF | sed -n -e 's/^.* \('"$i"'[^ ]*\) .*/\1/p'
180 $d
181 EOF
182 )"
183       case "$s" in
184       '') continue; ;;
185       --debug-all)
186         _DEBUG_STACKS='yes';
187         _DEBUG_LM='yes';
188         _DEBUG_KEEP_FILES='yes';
189         _DEBUG_PRINT_PARAMS='yes';
190         _DEBUG_PRINT_SHELL='yes';
191         _DEBUG_PRINT_TMPDIR='yes';
192         _DEBUG_USER_WITH_STACK='yes';
193         ;;
194       --debug-keep)
195         _DEBUG_PRINT_TMPDIR='yes';
196         _DEBUG_KEEP_FILES='yes';
197         ;;
198       --debug-lm)
199         _DEBUG_LM='yes';
200         ;;
201       --debug-params)
202         _DEBUG_PRINT_PARAMS='yes';
203         ;;
204       --debug-shell)
205         _DEBUG_PRINT_SHELL='yes';
206         ;;
207       --debug-stacks)
208         _DEBUG_STACKS='yes';
209         ;;
210       --debug-tmpdir)
211         _DEBUG_PRINT_TMPDIR='yes';
212         ;;
213       --debug-user)
214         _DEBUG_USER_WITH_STACK='yes';
215         ;;
216       esac;
217       ;;
218     esac;
219   done
220   ;;
221 esac;
222
223 if test _"${_DEBUG_PRINT_PARAMS}"_ = _yes_
224 then
225   echo "parameters: $@" >&2;
226 fi;
227
228 if test _"${_DEBUG_PRINT_SHELL}"_ = _yes_
229 then
230   if test _"${_SHELL}"_ = __
231   then
232     if test _"${POSIXLY_CORRECT}"_ = _y_
233     then
234       echo 'shell: bash as /bin/sh (none specified)' >&2;
235     else
236       echo 'shell: /bin/sh (none specified)' >&2;
237     fi;
238   else
239     echo "shell: ${_SHELL}" >&2;
240   fi;
241 fi;
242
243
244 ########################################################################
245 #                       Environment Variables
246 ########################################################################
247
248 # Environment variables that exist only for this file start with an
249 # underscore letter.  Global variables to this file are written in
250 # upper case letters, e.g. $_GLOBAL_VARIABLE; temporary variables
251 # start with an underline and use only lower case letters and
252 # underlines, e.g.  $_local_variable .
253
254 #   [A-Z]*     system variables,      e.g. $MANPATH
255 #   _[A-Z_]*   global file variables, e.g. $_MAN_PATH
256 #   _[a-z_]*   temporary variables,   e.g. $_manpath
257
258 # Due to incompatibilities of the `ash' shell, the name of loop
259 # variables in `for' must be single character
260 #   [a-z]      local loop variables,   e.g. $i
261
262
263 ########################################################################
264 # read-only variables (global to this file)
265 ########################################################################
266
267 # function return values; `0' means ok; other values are error codes
268 export _ALL_EXIT;
269 export _BAD;
270 export _GOOD;
271 export _NO;
272 export _OK;
273 export _YES;
274
275 _GOOD='0';                      # return ok
276 _BAD='1';                       # return negatively, error code `1'
277 # $_ERROR was already defined as `7' in groffer.sh.
278
279 _NO="${_BAD}";
280 _YES="${_GOOD}";
281 _OK="${_GOOD}";
282
283 # quasi-functions, call with `eval', e.g `eval "${return_ok}"'
284 export return_ok;
285 export return_good;
286 export return_bad;
287 export return_yes;
288 export return_no;
289 export return_error;
290 export return_var;
291 return_ok="func_pop; return ${_OK}";
292 return_good="func_pop; return ${_GOOD}";
293 return_bad="func_pop; return ${_BAD}";
294 return_yes="func_pop; return ${_YES}";
295 return_no="func_pop; return ${_NO}";
296 return_error="func_pop; return ${_ERROR}";
297 return_var="func_pop; return";  # add number, e.g. `eval "${return_var} $n'
298
299
300 export _DEFAULT_MODES;
301 _DEFAULT_MODES='x,ps,tty';
302 export _DEFAULT_RESOLUTION;
303 _DEFAULT_RESOLUTION='75';
304
305 export _DEFAULT_TTY_DEVICE;
306 _DEFAULT_TTY_DEVICE='latin1';
307
308 # _VIEWER_* viewer programs for different modes (only X is necessary)
309 # _VIEWER_* a comma-separated list of viewer programs (with options)
310 export _VIEWER_DVI;             # viewer program for dvi mode
311 export _VIEWER_HTML_TTY;        # viewer program for html mode in tty
312 export _VIEWER_HTML_X;          # viewer program for html mode in X
313 export _VIEWER_PDF;             # viewer program for pdf mode
314 export _VIEWER_PS;              # viewer program for ps mode
315 export _VIEWER_X;               # viewer program for X mode
316 _VIEWER_DVI='kdvi,xdvi,dvilx';
317 _VIEWER_HTML_TTY='lynx';
318 _VIEWER_HTML_X='konqueror,mozilla,netscape,galeon,opera,amaya,arena';
319 _VIEWER_PDF='kghostview --scale 1.45,ggv,xpdf,acroread,kpdf';
320 _VIEWER_PS='kghostview --scale 1.45,ggv,gv,ghostview,gs_x11,gs';
321 _VIEWER_X='gxditview,xditview';
322
323 # Search automatically in standard sections `1' to `8', and in the
324 # traditional sections `9', `n', and `o'.  On many systems, there
325 # exist even more sections, mostly containing a set of man pages
326 # special to a specific program package.  These aren't searched for
327 # automatically, but must be specified on the command line.
328 export _MAN_AUTO_SEC_LIST;
329 _MAN_AUTO_SEC_LIST="'1' '2' '3' '4' '5' '6' '7' '8' '9' 'n' 'o'";
330 export _MAN_AUTO_SEC_CHARS;
331 _MAN_AUTO_SEC_CHARS='[123456789no]';
332
333 export _SPACE_SED;
334 _SPACE_SED='['"${_SP}${_TAB}"']';
335
336 export _SPACE_CASE;
337 _SPACE_CASE='[\'"${_SP}"'\'"${_TAB}"']';
338
339 export _PROCESS_ID;             # for shutting down the program
340 _PROCESS_ID="$$";
341
342
343 ############ the command line options of the involved programs
344 #
345 # The naming scheme for the options environment names is
346 # $_OPTS_<prog>_<length>[_<argspec>]
347 #
348 # <prog>:    program name GROFFER, GROFF, or CMDLINE (for all
349 #            command line options)
350 # <length>:  LONG (long options) or SHORT (single character options)
351 # <argspec>: ARG for options with argument, NA for no argument;
352 #            without _<argspec> both the ones with and without arg.
353 #
354 # Each option that takes an argument must be specified with a
355 # trailing : (colon).
356
357 # exports
358 export _OPTS_GROFFER_SHORT_NA;
359 export _OPTS_GROFFER_SHORT_ARG;
360 export _OPTS_GROFFER_LONG_NA;
361 export _OPTS_GROFFER_LONG_ARG;
362 export _OPTS_GROFF_SHORT_NA;
363 export _OPTS_GROFF_SHORT_ARG;
364 export _OPTS_GROFF_LONG_NA;
365 export _OPTS_GROFF_LONG_ARG;
366 export _OPTS_X_SHORT_ARG;
367 export _OPTS_X_SHORT_NA;
368 export _OPTS_X_LONG_ARG;
369 export _OPTS_X_LONG_NA;
370 export _OPTS_MAN_SHORT_ARG;
371 export _OPTS_MAN_SHORT_NA;
372 export _OPTS_MAN_LONG_ARG;
373 export _OPTS_MAN_LONG_NA;
374 export _OPTS_MANOPT_SHORT_ARG;
375 export _OPTS_MANOPT_SHORT_NA;
376 export _OPTS_MANOPT_LONG_ARG;
377 export _OPTS_MANOPT_LONG_NA;
378 export _OPTS_CMDLINE_SHORT_NA;
379 export _OPTS_CMDLINE_SHORT_ARG;
380 export _OPTS_CMDLINE_LONG_NA;
381 export _OPTS_CMDLINE_LONG_ARG;
382
383 ###### groffer native options
384
385 _OPTS_GROFFER_SHORT_NA="'h' 'Q' 'v' 'V' 'X' 'Z'";
386 _OPTS_GROFFER_SHORT_ARG="'T'";
387
388 _OPTS_GROFFER_LONG_NA="'auto' \
389 'apropos' 'apropos-data' 'apropos-devel' 'apropos-progs' \
390 'debug' 'debug-all' 'debug-keep' 'debug-lm' 'debug-params' 'debug-shell' \
391 'debug-stacks' 'debug-tmpdir' 'debug-user' 'default' 'do-nothing' 'dvi' \
392 'groff' 'help' 'intermediate-output' 'html' 'man' \
393 'no-location' 'no-man' 'no-special' 'pdf' 'ps' 'rv' 'source' \
394 'text' 'text-device' \
395 'tty' 'tty-device' 'version' 'whatis' 'where' 'www' 'x' 'X'";
396
397 _OPTS_GROFFER_LONG_ARG="\
398 'default-modes' 'device' 'dvi-viewer' 'dvi-viewer-tty' 'extension' 'fg' \
399 'fn' 'font' 'foreground' 'html-viewer' 'html-viewer-tty' 'mode' \
400 'pdf-viewer' 'pdf-viewer-tty' 'print' 'ps-viewer' 'ps-viewer-tty' 'shell' \
401 'title' 'tty-viewer' 'tty-viewer-tty' 'www-viewer' 'www-viewer-tty' \
402 'x-viewer' 'x-viewer-tty' 'X-viewer' 'X-viewer-tty'";
403
404 ##### groffer options inhereted from groff
405
406 _OPTS_GROFF_SHORT_NA="'a' 'b' 'c' 'C' 'e' 'E' 'g' 'G' 'i' 'l' 'N' 'p' \
407 'R' 's' 'S' 't' 'U' 'z'";
408 _OPTS_GROFF_SHORT_ARG="'d' 'f' 'F' 'I' 'L' 'm' 'M' 'n' 'o' 'P' 'r' \
409 'w' 'W'";
410 _OPTS_GROFF_LONG_NA="";
411 _OPTS_GROFF_LONG_ARG="";
412
413 ##### groffer options inhereted from the X Window toolkit
414
415 _OPTS_X_SHORT_NA="";
416 _OPTS_X_SHORT_ARG="";
417
418 _OPTS_X_LONG_NA="'iconic' 'rv'";
419
420 _OPTS_X_LONG_ARG="'background' 'bd' 'bg' 'bordercolor' 'borderwidth' \
421 'bw' 'display' 'fg' 'fn' 'font' 'foreground' 'ft' 'geometry' \
422 'resolution' 'title' 'xrm'";
423
424 ###### groffer options inherited from man
425
426 _OPTS_MAN_SHORT_NA="";
427 _OPTS_MAN_SHORT_ARG="";
428
429 _OPTS_MAN_LONG_NA="'all' 'ascii' 'catman' 'ditroff' \
430 'local-file' 'location' 'troff' 'update'";
431
432 _OPTS_MAN_LONG_ARG="'locale' 'manpath' \
433 'pager' 'preprocessor' 'prompt' 'sections' 'systems' 'troff-device'";
434
435 ###### additional options for parsing $MANOPT only
436
437 _OPTS_MANOPT_SHORT_NA="'7' 'a' 'c' 'd' 'D' 'f' 'h' 'k' 'l' 't' 'u' \
438 'V' 'w' 'Z'";
439 _OPTS_MANOPT_SHORT_ARG="'e' 'L' 'm' 'M' 'p' 'P' 'r' 'S' 'T'";
440
441 _OPTS_MANOPT_LONG_NA="${_OPTS_MAN_LONG_NA} \
442 'apropos' 'debug' 'default' 'help' 'html' 'ignore-case' 'location-cat' \
443 'match-case' 'troff' 'update' 'version' 'whatis' 'where' 'where-cat'";
444
445 _OPTS_MANOPT_LONG_ARG="${_OPTS_MAN_LONG_NA} \
446 'config_file' 'encoding' 'extension' 'locale'";
447
448 ###### collections of command line options
449
450 _OPTS_CMDLINE_SHORT_NA="${_OPTS_GROFFER_SHORT_NA} \
451 ${_OPTS_GROFF_SHORT_NA} ${_OPTS_X_SHORT_NA} ${_OPTS_MAN_SHORT_NA}";
452 _OPTS_CMDLINE_SHORT_ARG="${_OPTS_GROFFER_SHORT_ARG} \
453 ${_OPTS_GROFF_SHORT_ARG} ${_OPTS_X_SHORT_ARG} ${_OPTS_MAN_SHORT_ARG}";
454
455 _OPTS_CMDLINE_LONG_NA="${_OPTS_GROFFER_LONG_NA} \
456 ${_OPTS_GROFF_LONG_NA} ${_OPTS_X_LONG_NA} ${_OPTS_MAN_LONG_NA}";
457 _OPTS_CMDLINE_LONG_ARG="${_OPTS_GROFFER_LONG_ARG} \
458 ${_OPTS_GROFF_LONG_ARG} ${_OPTS_MAN_LONG_ARG} ${_OPTS_X_LONG_ARG}";
459
460
461 ########################################################################
462 # read-write variables (global to this file)
463 ########################################################################
464
465 export _ALL_PARAMS;             # All options and file name parameters
466 export _ADDOPTS_GROFF;          # Transp. options for groff (`eval').
467 export _ADDOPTS_POST;           # Transp. options postproc (`eval').
468 export _ADDOPTS_X;              # Transp. options X postproc (`eval').
469 export _APROPOS_PROG;           # Program to run apropos.
470 export _APROPOS_SECTIONS;       # Sections for different --apropos-*.
471 export _DEFAULT_MODES;          # Set default modes.
472 export _DISPLAY_MODE;           # Display mode.
473 export _DISPLAY_PROG;           # Viewer program to be used for display.
474 export _DISPLAY_ARGS;           # X resources for the viewer program.
475 export _FILEARGS;               # Stores filespec parameters.
476 export _FILESPEC_ARG;           # Stores the actual filespec parameter.
477 export _FUNC_STACK;             # Store debugging information.
478 export _REGISTERED_TITLE;       # Processed file names.
479 # _HAS_* from availability tests
480 export _HAS_COMPRESSION;        # `yes' if gzip compression is available
481 export _HAS_BZIP;               # `yes' if bzip2 compression is available
482 # _MAN_* finally used configuration of man searching
483 export _MAN_ALL;                # search all man pages per filespec
484 export _MAN_ENABLE;             # enable search for man pages
485 export _MAN_EXT;                # extension for man pages
486 export _MAN_FORCE;              # force file parameter to be man pages
487 export _MAN_IS_SETUP;           # setup man variables only once
488 export _MAN_LANG;               # language for man pages
489 export _MAN_LANG2;              # language for man pages
490 export _MAN_LANG_DONE;          # language dirs added to man path
491 export _MAN_PATH;               # search path for man pages
492 export _MAN_SEC;                # sections for man pages; sep. `:'
493 export _MAN_SEC_DONE;           # sections added to man path
494 export _MAN_SYS;                # system names for man pages; sep. `,'
495 export _MAN_SYS;                # system names added to man path
496 # _MANOPT_* as parsed from $MANOPT
497 export _MANOPT_ALL;             # $MANOPT --all
498 export _MANOPT_EXTENSION;       # $MANOPT --extension
499 export _MANOPT_LANG;            # $MANOPT --locale
500 export _MANOPT_PATH;            # $MANOPT --manpath
501 export _MANOPT_PAGER;           # $MANOPT --pager
502 export _MANOPT_SEC;             # $MANOPT --sections
503 export _MANOPT_SYS;             # $MANOPT --systems
504 # _OPT_* as parsed from groffer command line
505 export _OPT_ALL;                # display all suitable man pages.
506 export _OPT_APROPOS;            # call `apropos' program.
507 export _OPT_BD;                 # set border color in some modes.
508 export _OPT_BG;                 # set background color in some modes.
509 export _OPT_BW;                 # set border width in some modes.
510 export _OPT_DEFAULT_MODES;      # `,'-list of modes when no mode given.
511 export _OPT_DEVICE;             # device option.
512 export _OPT_DO_NOTHING;         # do nothing in main_display().
513 export _OPT_DISPLAY;            # set X display.
514 export _OPT_FG;                 # set foreground color in some modes.
515 export _OPT_FN;                 # set font in some modes.
516 export _OPT_GEOMETRY;           # set size and position of viewer in X.
517 export _OPT_ICONIC;             # -iconic option for X viewers.
518 export _OPT_LANG;               # set language for man pages
519 export _OPT_LOCATION;           # print processed file names to stderr
520 export _OPT_MODE;               # values: X, tty, Q, Z, ""
521 export _OPT_MANPATH;            # manual setting of path for man-pages
522 export _OPT_PAGER;              # specify paging program for tty mode
523 export _OPT_RESOLUTION;         # set X resolution in dpi
524 export _OPT_RV;                 # reverse fore- and background colors.
525 export _OPT_SECTIONS;           # sections for man page search
526 export _OPT_SYSTEMS;            # man pages of different OS's
527 export _OPT_TITLE;              # title for gxditview window
528 export _OPT_TEXT_DEVICE;        # set device for tty mode.
529 export _OPT_V;                  # groff option -V.
530 export _OPT_VIEWER_DVI;         # viewer program for dvi mode
531 export _OPT_VIEWER_PDF;         # viewer program for pdf mode
532 export _OPT_VIEWER_PS;          # viewer program for ps mode
533 export _OPT_VIEWER_HTML;        # viewer program for html mode
534 export _OPT_VIEWER_X;           # viewer program for x mode
535 export _OPT_WHATIS;             # print the man description
536 export _OPT_XRM;                # specify X resource.
537 export _OPT_Z;                  # groff option -Z.
538 export _OUTPUT_FILE_NAME;       # output generated, see main_set_res..()
539 export _VIEWER_TERMINAL;        # viewer options for terminal (--*-viewer-tty)
540 # _TMP_* temporary directory and files
541 export _TMP_DIR;                # groffer directory for temporary files
542 export _TMP_CAT;                # stores concatenation of everything
543 export _TMP_STDIN;              # stores stdin, if any
544
545 # these variables are preset in section `Preset' after the rudim. test
546
547
548 ########################################################################
549 # Preset and reset of read-write global variables
550 ########################################################################
551
552
553 export _START_DIR;              # directory at start time of the script
554 _START_DIR="$(pwd)";
555
556 # For variables that can be reset by option `--default', see reset().
557
558 _FILEARGS='';
559
560 # _HAS_* from availability tests
561 _HAS_COMPRESSION='';
562 _HAS_BZIP='';
563
564 # _TMP_* temporary files
565 _TMP_DIR='';
566 _TMP_CAT='';
567 _TMP_CONF='';
568 _TMP_STDIN='';
569
570
571 ########################################################################
572 # reset ()
573 #
574 # Reset the variables that can be affected by options to their default.
575 #
576 reset()
577 {
578   if test "$#" -ne 0
579   then
580     error "reset() does not have arguments.";
581   fi;
582
583   _ADDOPTS_GROFF='';
584   _ADDOPTS_POST='';
585   _ADDOPTS_X='';
586   _APROPOS_PROG='';
587   _APROPOS_SECTIONS='';
588   _DISPLAY_ARGS='';
589   _DISPLAY_MODE='';
590   _DISPLAY_PROG='';
591   _REGISTERED_TITLE='';
592
593   # _MAN_* finally used configuration of man searching
594   _MAN_ALL='no';
595   _MAN_ENABLE='yes';            # do search for man-pages
596   _MAN_EXT='';
597   _MAN_FORCE='no';              # first local file, then search man page
598   _MAN_IS_SETUP='no';
599   _MAN_LANG='';
600   _MAN_LANG2='';
601   _MAN_PATH='';
602   _MAN_SEC='';
603   _MAN_SEC_DONE='no';
604   _MAN_SYS='';
605   _MAN_SYS_DONE='no';
606
607   # _MANOPT_* as parsed from $MANOPT
608   _MANOPT_ALL='no';
609   _MANOPT_EXTENSION='';
610   _MANOPT_LANG='';
611   _MANOPT_PATH='';
612   _MANOPT_PAGER='';
613   _MANOPT_SEC='';
614   _MANOPT_SYS='';
615
616   # _OPT_* as parsed from groffer command line
617   _OPT_ALL='no';
618   _OPT_APROPOS='no';
619   _OPT_BD='';
620   _OPT_BG='';
621   _OPT_BW='';
622   _OPT_DEFAULT_MODES='';
623   _OPT_DEVICE='';
624   _OPT_DISPLAY='';
625   _OPT_DO_NOTHING='no';
626   _OPT_FG='';
627   _OPT_FN='';
628   _OPT_GEOMETRY='';
629   _OPT_ICONIC='no';
630   _OPT_LANG='';
631   _OPT_LOCATION='no';
632   _OPT_MODE='';
633   _OPT_MANPATH='';
634   _OPT_PAGER='';
635   _OPT_RESOLUTION='';
636   _OPT_RV='no';
637   _OPT_SECTIONS='';
638   _OPT_SYSTEMS='';
639   _OPT_TITLE='';
640   _OPT_TEXT_DEVICE='';
641   _OPT_V='no';
642   _OPT_VIEWER_DVI='';
643   _OPT_VIEWER_PDF='';
644   _OPT_VIEWER_PS='';
645   _OPT_VIEWER_HTML='';
646   _OPT_VIEWER_X='';
647   _OPT_WHATIS='no';
648   _OPT_XRM='';
649   _OPT_Z='no';
650   _VIEWER_TERMINAL='no';
651 }
652
653 reset;
654
655
656 ########################################################################
657 #          Functions for error handling and debugging
658 ########################################################################
659
660
661 ##############
662 # echo1 (<text>*)
663 #
664 # Output to stdout.
665 #
666 # Arguments : arbitrary text including `-'.
667 #
668 echo1()
669 {
670   cat <<EOF
671 $@
672 EOF
673 }
674
675
676 ##############
677 # echo2 (<text>*)
678 #
679 # Output to stderr.
680 #
681 # Arguments : arbitrary text.
682 #
683 echo2()
684 {
685   cat >&2 <<EOF
686 $@
687 EOF
688 }
689
690
691 ##############
692 # landmark (<text>)
693 #
694 # Print <text> to standard error as a debugging aid.
695 #
696 # Globals: $_DEBUG_LM
697 #
698 landmark()
699 {
700   if test _"${_DEBUG_LM}"_ = _yes_
701   then
702     echo2 "LM: $*";
703   fi;
704 }
705
706 landmark "1: debugging functions";
707
708
709 ##############
710 # clean_up ()
711 #
712 # Clean up at exit.
713 #
714 clean_up()
715 {
716   cd "${_START_DIR}" >"${_NULL_DEV}" 2>&1;
717   if test _${_DEBUG_KEEP_FILES}_ = _yes_
718   then
719     echo2 "Kept temporary directory ${_TMP_DIR}."
720   else
721     if test _"${_TMP_DIR}"_ != __
722     then
723       if test -d "${_TMP_DIR}" || test -f "${_TMP_DIR}"
724       then
725         rm -f -r "${_TMP_DIR}" >${_NULL_DEV} 2>&1;
726       fi; 
727     fi;
728   fi;
729 }
730
731
732 #############
733 # diag (text>*)
734 #
735 # Output a diagnostic message to stderr
736 #
737 diag()
738 {
739   echo2 '>>>>>'"$*";
740 }
741
742
743 #############
744 # error (<text>*)
745 #
746 # Print an error message to standard error, print the function stack,
747 # exit with an error condition.  The argument should contain the name
748 # of the function from which it was called.  This is for system errors.
749 #
750 error()
751 {
752   case "$#" in
753     1) echo2 'groffer error: '"$1"; ;;
754     *) echo2 'groffer error: wrong number of arguments in error().'; ;;
755   esac;
756   func_stack_dump;
757   if test _"${_TMP_DIR}"_ != __ && test -d "${_TMP_DIR}"
758   then
759     : >"${_TMP_DIR}"/,error;
760   fi;
761   exit "${_ERROR}";
762 }
763
764
765 #############
766 # error_user (<text>*)
767 #
768 # Print an error message to standard error; exit with an error condition.
769 # The error is supposed to be produce by the user.  So the funtion stack
770 # is omitted.
771 #
772 error_user()
773 {
774   case "$#" in
775     1)
776       echo2 'groffer error: '"$1";
777        ;;
778     *)
779       echo2 'groffer error: wrong number of arguments in error_user().';
780       ;;
781   esac;
782   if test _"${_DEBUG_USER_WITH_STACK}"_ = _yes_
783   then
784     func_stack_dump;
785   fi;
786   if test _"${_TMP_DIR}"_ != __ && test -d "${_TMP_DIR}"
787   then
788     : >"${_TMP_DIR}"/,error;
789   fi;
790   exit "${_ERROR}";
791 }
792
793
794 #############
795 # exit_test ()
796 #
797 # Test whether the former command ended with error().  Exit again.
798 #
799 # Globals: $_ERROR
800 #
801 exit_test()
802 {
803   if test "$?" = "${_ERROR}"
804   then
805     exit ${_ERROR};
806   fi;
807   if test _"${_TMP_DIR}"_ != __ && test -f "${_TMP_DIR}"/,error
808   then
809     exit ${_ERROR};
810   fi;
811 }
812
813
814 #############
815 # func_check (<func_name> <rel_op> <nr_args> "$@")
816 #
817 # Check number of arguments and register to _FUNC_STACK.
818 #
819 # Arguments: >=3
820 #   <func_name>: name of the calling function.
821 #   <rel_op>:    a relational operator: = != < > <= >=
822 #   <nr_args>:   number of arguments to be checked against <operator>
823 #   "$@":        the arguments of the calling function.
824 #
825 # Variable prefix: fc
826 #
827 func_check()
828 {
829   if test "$#" -lt 3
830   then
831     error 'func_check() needs at least 3 arguments.';
832   fi;
833   fc_fname="$1";
834   case "$3" in
835     1)
836       fc_nargs="$3";
837       fc_s='';
838       ;;
839     0|[2-9])
840       fc_nargs="$3";
841       fc_s='s';
842       ;;
843     *)
844       error "func_check(): third argument must be a digit.";
845       ;;
846   esac;
847   case "$2" in
848     '='|'-eq')
849       fc_op='-eq';
850       fc_comp='exactly';
851       ;;
852     '>='|'-ge')
853       fc_op='-ge';
854       fc_comp='at least';
855       ;;
856     '<='|'-le')
857       fc_op='-le';
858       fc_comp='at most';
859       ;;
860     '<'|'-lt')
861       fc_op='-lt';
862       fc_comp='less than';
863       ;;
864     '>'|'-gt')
865       fc_op='-gt';
866       fc_comp='more than';
867       ;;
868     '!='|'-ne')
869       fc_op='-ne';
870       fc_comp='not';
871       ;;
872     *)
873       error \
874         'func_check(): second argument is not a relational operator.';
875       ;;
876   esac;
877   shift;
878   shift;
879   shift;
880   if test "$#" "${fc_op}" "${fc_nargs}"
881   then
882     do_nothing;
883   else
884     error "func_check(): \
885 ${fc_fname}"'() needs '"${fc_comp} ${fc_nargs}"' argument'"${fc_s}"'.';
886   fi;
887   func_push "${fc_fname}";
888   if test _"${_DEBUG_STACKS}"_ = _yes_
889   then
890     echo2 '+++ '"${fc_fname} $@";
891     echo2 '>>> '"${_FUNC_STACK}";
892   fi;
893   eval ${_UNSET} fc_comp;
894   eval ${_UNSET} fc_fname;
895   eval ${_UNSET} fc_nargs;
896   eval ${_UNSET} fc_op;
897   eval ${_UNSET} fc_s;
898 }
899
900
901 #############
902 # func_pop ()
903 #
904 # Retrieve the top element from the stack.
905 #
906 # The stack elements are separated by `!'; the popped element is
907 # identical to the original element, except that all `!' characters
908 # were removed.
909 #
910 # Arguments: 1
911 #
912 func_pop()
913 {
914   if test "$#" -ne 0
915   then
916     error 'func_pop() does not have arguments.';
917   fi;
918   case "${_FUNC_STACK}" in
919   '')
920     if test _"${_DEBUG_STACKS}"_ = _yes_
921     then
922       error 'func_pop(): stack is empty.';
923     fi;
924     ;;
925   *!*)
926     # split at first bang `!'.
927     _FUNC_STACK="$(echo1 "${_FUNC_STACK}" | sed -e 's/^[^!]*!//')";
928     exit_test;
929     ;;
930   *)
931     _FUNC_STACK='';
932     ;;
933   esac;
934   if test _"${_DEBUG_STACKS}"_ = _yes_
935   then
936     echo2 '<<< '"${_FUNC_STACK}";
937   fi;
938 }
939
940
941 #############
942 # func_push (<element>)
943 #
944 # Store another element to stack.
945 #
946 # The stack elements are separated by `!'; if <element> contains a `!'
947 # it is removed first.
948 #
949 # Arguments: 1
950 #
951 # Variable prefix: fp
952 #
953 func_push()
954 {
955   if test "$#" -ne 1
956   then
957     error 'func_push() needs 1 argument.';
958   fi;
959   case "$1" in
960   *'!'*)
961     # remove all bangs `!'.
962     fp_element="$(echo1 "$1" | sed -e 's/!//g')";
963     exit_test;
964     ;;
965   *)
966     fp_element="$1";
967     ;;
968   esac;
969   if test _"${_FUNC_STACK}"_ = __
970   then
971     _FUNC_STACK="${fp_element}";
972   else
973     _FUNC_STACK="${fp_element}!${_FUNC_STACK}";
974   fi;
975   eval ${_UNSET} fp_element;
976 }
977
978
979 #############
980 # func_stack_dump ()
981 #
982 # Print the content of the stack.  Ignore the arguments.
983 #
984 func_stack_dump()
985 {
986   diag 'call stack: '"${_FUNC_STACK}";
987 }
988
989
990 ########################################################################
991 #                        System Test
992 ########################################################################
993
994 landmark "2: system test";
995
996 # Test the availability of the system utilities used in this script.
997
998
999 ########################################################################
1000 # Test of function `sed'.
1001 #
1002
1003 if test _"$(echo xTesTx \
1004            | sed -e 's/^.\([Tt]e*x*sTT*\).*$/\1/' \
1005            | sed -e 's|T|t|g')"_ != _test_
1006 then
1007   error 'Test of "sed" command failed.';
1008 fi;
1009
1010
1011 ########################################################################
1012 # Test of function `cat'.
1013 #
1014 if test _"$(echo test | cat)"_ != _test_
1015 then
1016   error 'Test of "cat" command failed.';
1017 fi;
1018
1019
1020 ########################################################################
1021 # Test for compression.
1022 #
1023 if test _"$(echo 'test' | gzip -c -d -f - 2>${_NULL_DEV})"_ = _test_
1024 then
1025   _HAS_COMPRESSION='yes';
1026   if echo1 'test' | bzip2 -c 2>${_NULL_DEV} | bzip2 -t 2>${_NULL_DEV} \
1027      && test _"$(echo 'test' | bzip2 -c 2>${_NULL_DEV} \
1028                              | bzip2 -d -c 2>${_NULL_DEV})"_ \
1029              = _test_
1030   then
1031     _HAS_BZIP='yes';
1032   else
1033     _HAS_BZIP='no';
1034   fi;
1035 else
1036   _HAS_COMPRESSION='no';
1037   _HAS_BZIP='no';
1038 fi;
1039
1040
1041 ########################################################################
1042 #       Definition of normal Functions in alphabetical order
1043 ########################################################################
1044 landmark "3: functions";
1045
1046 ########################################################################
1047 # apropos_filespec ()
1048 #
1049 # Setup for the --apropos* options
1050 #
1051 apropos_filespec()
1052 {
1053
1054   func_check apropos_filespec '=' 0 "$@";
1055   if obj _OPT_APROPOS is_yes
1056   then
1057     eval to_tmp_line \
1058       "'.SH $(echo1 "${_FILESPEC_ARG}" | sed 's/[^\\]-/\\-/g')'";
1059     exit_test;
1060     if obj _APROPOS_PROG is_empty
1061     then
1062       error 'apropos_filespec: apropos_setup() must be run first.';
1063     fi;
1064     if obj _APROPOS_SECTIONS is_empty
1065     then
1066       if obj _OPT_SECTIONS is_empty
1067       then
1068         s='^.*(.*).*$';
1069       else
1070         s='^.*(['"$(echo1 "${_OPT_SECTIONS}" | sed -e 's/://g')"']';
1071       fi;
1072     else
1073       s='^.*(['"${_APROPOS_SECTIONS}"']';
1074     fi;
1075     eval "${_APROPOS_PROG}" "'${_FILESPEC_ARG}'" | \
1076       sed -n -e '
1077 /^'"${_FILESPEC_ARG}"': /p
1078 /'"$s"'/p
1079 ' | \
1080       sort |\
1081       sed -e '
1082 s/^\(.* (..*)\)  *-  *\(.*\)$/\.br\n\.TP 15\n\.BR \1\n\2/
1083 ' >>"${_TMP_CAT}";
1084   fi;
1085   eval "${return_ok}";
1086 }
1087
1088
1089 ########################################################################
1090 # apropos_setup ()
1091 #
1092 # Setup for the --apropos* options
1093 #
1094 apropos_setup()
1095 {
1096   func_check apropos_setup '=' 0 "$@";
1097   if obj _OPT_APROPOS is_yes
1098   then
1099     if is_prog apropos
1100     then
1101       _APROPOS_PROG='apropos';
1102     elif is_prog man
1103     then
1104       if man --apropos man >${_NULL_DEV} 2>${_NULL_DEV}
1105       then
1106         _APROPOS_PROG='man --apropos';
1107       elif man -k man >${_NULL_DEV} 2>${_NULL_DEV}
1108       then
1109         _APROPOS_PROG='man -k';
1110       fi;
1111     fi;
1112     if obj _APROPOS_PROG is_empty
1113     then
1114       error 'apropos_setup: no apropos program available.';
1115     fi;
1116     to_tmp_line '.TH GROFFER APROPOS';
1117   fi;
1118   eval "${return_ok}";
1119 }
1120
1121
1122 ########################################################################
1123 # base_name (<path>)
1124 #
1125 # Get the file name part of <path>, i.e. delete everything up to last
1126 # `/' from the beginning of <path>.  Remove final slashes, too, to get a
1127 # non-empty output.
1128 #
1129 # Arguments : 1
1130 # Output    : the file name part (without slashes)
1131 #
1132 # Variable prefix: bn
1133 #
1134 base_name()
1135 {
1136   func_check base_name = 1 "$@";
1137   bn_name="$1";
1138   case "${bn_name}" in
1139     */)
1140       # delete all final slashes
1141       bn_name="$(echo1 "${bn_name}" | sed -e 's|//*$||')";
1142       exit_test;
1143       ;;
1144   esac;
1145   case "${bn_name}" in
1146     /|'')
1147       eval ${_UNSET} bn_name;
1148       eval "${return_bad}";
1149       ;;
1150     */*)
1151       # delete everything before and including the last slash `/'.
1152       echo1 "${bn_name}" | sed -e 's|^.*//*\([^/]*\)$|\1|';
1153       ;;
1154     *)
1155       obj bn_name echo1;
1156       ;;
1157   esac;
1158   eval ${_UNSET} bn_name;
1159   eval "${return_ok}";
1160 }
1161
1162
1163 ########################################################################
1164 # cat_z (<file>)
1165 #
1166 # Decompress if possible or just print <file> to standard output.
1167 #
1168 # gzip, bzip2, and .Z decompression is supported.
1169 #
1170 # Arguments: 1, a file name.
1171 # Output: the content of <file>, possibly decompressed.
1172 #
1173 if test _"${_HAS_COMPRESSION}"_ = _yes_
1174 then
1175   cat_z()
1176   {
1177     func_check cat_z = 1 "$@";
1178     case "$1" in
1179       '')
1180         error 'cat_z(): empty file name';
1181         ;;
1182       '-')
1183         error 'cat_z(): for standard input use save_stdin()';
1184         ;;
1185     esac;
1186     if obj _HAS_BZIP is_yes
1187     then
1188       if bzip2 -t "$1" 2>${_NULL_DEV}
1189       then
1190         bzip2 -c -d "$1" 2>${_NULL_DEV};
1191         eval "${return_ok}";
1192       fi;
1193     fi;
1194     gzip -c -d -f "$1" 2>${_NULL_DEV};
1195     eval "${return_ok}";
1196   }
1197 else
1198   cat_z()
1199   {
1200     func_check cat_z = 1 "$@";
1201     cat "$1";
1202     eval "${return_ok}";
1203   }
1204 fi;
1205
1206
1207 ########################################################################
1208 # clean_up ()
1209 #
1210 # Do the final cleaning up before exiting; used by the trap calls.
1211 #
1212 # defined above
1213
1214
1215 ########################################################################
1216 # diag (<text>*)
1217 #
1218 # Print marked message to standard error; useful for debugging.
1219 #
1220 # defined above
1221
1222
1223 ########################################################################
1224 landmark '4: dirname()*';
1225 ########################################################################
1226
1227 #######################################################################
1228 # dirname_append (<dir> <name>)
1229 #
1230 # Append `name' to `dir' with clean handling of `/'.
1231 #
1232 # Arguments : 2
1233 # Output    : the generated new directory name <dir>/<name>
1234 #
1235 dirname_append()
1236 {
1237   func_check dirname_append = 2 "$@";
1238   if is_empty "$1"
1239   then
1240     error "dir_append(): first argument is empty.";
1241   fi;
1242   if is_empty "$2"
1243   then
1244     echo1 "$1";
1245   else
1246     dirname_chop "$1"/"$2";
1247   fi;
1248   eval "${return_ok}";
1249 }
1250
1251
1252 ########################################################################
1253 # dirname_chop (<name>)
1254 #
1255 # Remove unnecessary slashes from directory name.
1256 #
1257 # Argument: 1, a directory name.
1258 # Output:   path without double, or trailing slashes.
1259 #
1260 # Variable prefix: dc
1261 #
1262 dirname_chop()
1263 {
1264   func_check dirname_chop = 1 "$@";
1265   # replace all multiple slashes by a single slash `/'.
1266   dc_res="$(echo1 "$1" | sed -e 's|///*|/|g')";
1267   exit_test;
1268   case "${dc_res}" in
1269   ?*/)
1270     # remove trailing slash '/';
1271     echo1 "${dc_res}" | sed -e 's|/$||';
1272     ;;
1273   *)
1274     obj dc_res echo1
1275     ;;
1276   esac;
1277   eval ${_UNSET} dc_res;
1278   eval "${return_ok}";
1279 }
1280
1281
1282 ########################################################################
1283 # do_filearg (<filearg>)
1284 #
1285 # Append the file, man-page, or standard input corresponding to the
1286 # argument to the temporary file.  If this is compressed in the gzip
1287 # or Z format it is decompressed.  A title element is generated.
1288 #
1289 # Argument either:
1290 #   - name of an existing file.
1291 #   - `-' to represent standard input (several times allowed).
1292 #   - `man:name.(section)' the man-page for `name' in `section'.
1293 #   - `man:name.section' the man-page for `name' in `section'.
1294 #   - `man:name' the man-page for `name' in the lowest `section'.
1295 #   - `name.section' the man-page for `name' in `section'.
1296 #   - `name' the man-page for `name' in the lowest `section'.
1297 # Globals :
1298 #   $_TMP_STDIN, $_MAN_ENABLE, $_MAN_IS_SETUP, $_OPT_MAN
1299 #
1300 # Output  : none
1301 # Return  : $_GOOD if found, ${_BAD} otherwise.
1302 #
1303 # Variable prefix: df
1304 #
1305 do_filearg()
1306 {
1307   func_check do_filearg = 1 "$@";
1308   df_filespec="$1";
1309   # store sequence into positional parameters
1310   case "${df_filespec}" in
1311   '')
1312     eval ${_UNSET} df_filespec;
1313     eval "${return_good}";
1314     ;;
1315   '-')
1316     register_file '-';
1317     eval ${_UNSET} df_filespec;
1318     eval "${return_good}";
1319     ;;
1320   */*)                         # with directory part; so no man search
1321     set 'File';
1322     ;;
1323   *)
1324     if obj _MAN_ENABLE is_yes
1325     then
1326       if obj _MAN_FORCE is_yes
1327       then
1328         set 'Manpage' 'File';
1329       else
1330         set 'File' 'Manpage';
1331       fi;
1332       else
1333       set 'File';
1334     fi;
1335     ;;
1336   esac;
1337   for i
1338   do
1339     case "$i" in
1340     File)
1341       if test -f "${df_filespec}"
1342       then
1343         if test -r "${df_filespec}"
1344         then
1345           register_file "${df_filespec}";
1346           eval ${_UNSET} df_filespec;
1347           eval ${_UNSET} df_no_man;
1348           eval "${return_good}";
1349         else
1350           echo2 "could not read \`${df_filespec}'";
1351           eval ${_UNSET} df_filespec;
1352           eval ${_UNSET} df_no_man;
1353           eval "${return_bad}";
1354         fi;
1355       else
1356         if obj df_no_man is_not_empty
1357         then
1358           if obj _OPT_WHATIS is_yes
1359           then
1360             to_tmp_line "This is neither a file nor a man page."
1361           else
1362             echo2 "\`${df_filespec}' is neither a file nor a man page."
1363           fi;
1364         fi;
1365         df_no_file=yes;
1366         continue;
1367       fi;
1368       ;;
1369     Manpage)                    # parse filespec as man page
1370       if obj _MAN_IS_SETUP is_not_yes
1371       then
1372         man_setup;
1373       fi;
1374       if man_do_filespec "${df_filespec}"
1375       then
1376         eval ${_UNSET} df_filespec;
1377         eval ${_UNSET} df_no_file;
1378         eval "${return_good}";
1379       else
1380         if obj df_no_file is_not_empty
1381         then
1382           if obj _OPT_WHATIS is_yes
1383           then
1384             to_tmp_line "This is neither a file nor a man page."
1385           else
1386             echo2 "\`${df_filespec}' is neither a file nor a man page."
1387           fi;
1388         fi;
1389         df_no_man=yes;
1390         continue;
1391       fi;
1392       ;;
1393     esac;
1394   done;
1395   eval ${_UNSET} df_filespec;
1396   eval ${_UNSET} df_no_file;
1397   eval ${_UNSET} df_no_man;
1398   eval "${return_bad}";
1399 } # do_filearg()
1400
1401
1402 ########################################################################
1403 # do_nothing ()
1404 #
1405 # Dummy function.
1406 #
1407 do_nothing()
1408 {
1409   eval return "${_OK}";
1410 }
1411
1412
1413 ########################################################################
1414 # echo2 (<text>*)
1415 #
1416 # Print to standard error with final line break.
1417 #
1418 # defined above
1419
1420
1421 ########################################################################
1422 # error (<text>*)
1423 #
1424 # Print error message and exit with error code.
1425 #
1426 # defined above
1427
1428
1429 ########################################################################
1430 # exit_test ()
1431 #
1432 # Test whether the former command ended with error().  Exit again.
1433 #
1434 # defined above
1435
1436
1437 ########################################################################
1438 # func_check (<func_name> <rel_op> <nr_args> "$@")
1439 #
1440 # Check number of arguments and register to _FUNC_STACK.
1441 #
1442 # Arguments: >=3
1443 #   <func_name>: name of the calling function.
1444 #   <rel_op>:    a relational operator: = != < > <= >=
1445 #   <nr_args>:   number of arguments to be checked against <operator>
1446 #   "$@":        the arguments of the calling function.
1447 #
1448 # defined above
1449
1450 #########################################################################
1451 # func_pop ()
1452 #
1453 # Delete the top element from the function call stack.
1454 #
1455 # defined above
1456
1457
1458 ########################################################################
1459 # func_push (<element>)
1460 #
1461 # Store another element to function call stack.
1462 #
1463 # defined above
1464
1465
1466 ########################################################################
1467 # func_stack_dump ()
1468 #
1469 # Print the content of the stack.
1470 #
1471 # defined above
1472
1473
1474 ########################################################################
1475 # get_first_essential (<arg>*)
1476 #
1477 # Retrieve first non-empty argument.
1478 #
1479 # Return  : `1' if all arguments are empty, `0' if found.
1480 # Output  : the retrieved non-empty argument.
1481 #
1482 # Variable prefix: gfe
1483 #
1484 get_first_essential()
1485 {
1486   func_check get_first_essential '>=' 0 "$@";
1487   if is_equal "$#" 0
1488   then
1489     eval "${return_ok}";
1490   fi;
1491   for i
1492   do
1493     gfe_var="$i";
1494     if obj gfe_var is_not_empty
1495     then
1496       obj gfe_var echo1;
1497       eval ${_UNSET} gfe_var;
1498       eval "${return_ok}";
1499     fi;
1500   done;
1501   eval ${_UNSET} gfe_var;
1502   eval "${return_bad}";
1503 }
1504
1505
1506 ########################################################################
1507 landmark '5: is_*()';
1508 ########################################################################
1509
1510 ########################################################################
1511 # is_dir (<name>)
1512 #
1513 # Test whether `name' is a directory.
1514 #
1515 # Arguments : 1
1516 # Return    : `0' if arg1 is a directory, `1' otherwise.
1517 #
1518 is_dir()
1519 {
1520   func_check is_dir '=' 1 "$@";
1521   if test _"$1"_ != __ && test -d "$1" && test -r "$1"
1522   then
1523     eval "${return_yes}";
1524   fi;
1525   eval "${return_no}";
1526 }
1527
1528
1529 ########################################################################
1530 # is_empty (<string>)
1531 #
1532 # Test whether `string' is empty.
1533 #
1534 # Arguments : <=1
1535 # Return    : `0' if arg1 is empty or does not exist, `1' otherwise.
1536 #
1537 is_empty()
1538 {
1539   func_check is_empty '=' 1 "$@";
1540   if test _"$1"_ = __
1541   then
1542     eval "${return_yes}";
1543   fi;
1544   eval "${return_no}";
1545 }
1546
1547
1548 ########################################################################
1549 # is_equal (<string1> <string2>)
1550 #
1551 # Test whether `string1' is equal to <string2>.
1552 #
1553 # Arguments : 2
1554 # Return    : `0' both arguments are equal strings, `1' otherwise.
1555 #
1556 is_equal()
1557 {
1558   func_check is_equal '=' 2 "$@";
1559   if test _"$1"_ = _"$2"_
1560   then
1561     eval "${return_yes}";
1562   fi;
1563   eval "${return_no}";
1564 }
1565
1566
1567 ########################################################################
1568 # is_existing (<name>)
1569 #
1570 # Test whether `name' is an existing file or directory.  Solaris 2.5 does
1571 # not have `test -e'.
1572 #
1573 # Arguments : 1
1574 # Return    : `0' if arg1 exists, `1' otherwise.
1575 #
1576 is_existing()
1577 {
1578   func_check is_existing '=' 1 "$@";
1579   if test _"$1"_ = __
1580   then
1581     eval "${return_no}";
1582   fi;
1583   if test -f "$1" || test -d "$1" || test -c "$1"
1584   then
1585     eval "${return_yes}";
1586   fi;
1587   eval "${return_no}";
1588 }
1589
1590
1591 ########################################################################
1592 # is_file (<name>)
1593 #
1594 # Test whether `name' is a readable file.
1595 #
1596 # Arguments : 1
1597 # Return    : `0' if arg1 is a readable file, `1' otherwise.
1598 #
1599 is_file()
1600 {
1601   func_check is_file '=' 1 "$@";
1602   if is_not_empty "$1" && test -f "$1" && test -r "$1"
1603   then
1604     eval "${return_yes}";
1605   fi;
1606   eval "${return_no}";
1607 }
1608
1609
1610 ########################################################################
1611 # is_non_empty_file (<file_name>)
1612 #
1613 # Test whether `file_name' is a non-empty existing file.
1614 #
1615 # Arguments : <=1
1616 # Return    :
1617 #   `0' if arg1 is a non-empty existing file
1618 #   `1' otherwise
1619 #
1620 is_non_empty_file()
1621 {
1622   func_check is_non_empty_file '=' 1 "$@";
1623   if is_file "$1" && test -s "$1"
1624   then
1625     eval "${return_yes}";
1626   fi;
1627   eval "${return_no}";
1628 }
1629
1630
1631 ########################################################################
1632 # is_not_dir (<name>)
1633 #
1634 # Test whether `name' is not a readable directory.
1635 #
1636 # Arguments : 1
1637 # Return    : `0' if arg1 is a directory, `1' otherwise.
1638 #
1639 is_not_dir()
1640 {
1641   func_check is_not_dir '=' 1 "$@";
1642   if is_dir "$1"
1643   then
1644     eval "${return_no}";
1645   fi;
1646   eval "${return_yes}";
1647 }
1648
1649
1650 ########################################################################
1651 # is_not_empty (<string>)
1652 #
1653 # Test whether `string' is not empty.
1654 #
1655 # Arguments : <=1
1656 # Return    : `0' if arg1 exists and is not empty, `1' otherwise.
1657 #
1658 is_not_empty()
1659 {
1660   func_check is_not_empty '=' 1 "$@";
1661   if is_empty "$1"
1662   then
1663     eval "${return_no}";
1664   fi;
1665   eval "${return_yes}";
1666 }
1667
1668
1669 ########################################################################
1670 # is_not_equal (<string1> <string2>)
1671 #
1672 # Test whether `string1' differs from `string2'.
1673 #
1674 # Arguments : 2
1675 #
1676 is_not_equal()
1677 {
1678   func_check is_not_equal '=' 2 "$@";
1679   if is_equal "$1" "$2"
1680   then
1681     eval "${return_no}";
1682   fi
1683   eval "${return_yes}";
1684 }
1685
1686
1687 ########################################################################
1688 # is_not_file (<filename>)
1689 #
1690 # Test whether `name' is a not readable file.
1691 #
1692 # Arguments : 1 (empty allowed)
1693 #
1694 is_not_file()
1695 {
1696   func_check is_not_file '=' 1 "$@";
1697   if is_file "$1"
1698   then
1699     eval "${return_no}";
1700   fi;
1701   eval "${return_yes}";
1702 }
1703
1704
1705 ########################################################################
1706 # is_not_prog ([<name> [<arg>*]])
1707 #
1708 # Verify that arg is a not program in $PATH.
1709 #
1710 # Arguments : >=0 (empty allowed)
1711 #   more args are ignored, this allows to specify progs with arguments
1712 #
1713 is_not_prog()
1714 {
1715   func_check is_not_prog '>=' 0 "$@";
1716   case "$#" in
1717   0)
1718     eval "${return_yes}";
1719     ;;
1720   *)
1721     if where_is "$1" >${_NULL_DEV}
1722     then
1723       eval "${return_no}";
1724     fi;
1725     ;;
1726   esac
1727   eval "${return_yes}";
1728 }
1729
1730
1731 ########################################################################
1732 # is_not_writable (<name>)
1733 #
1734 # Test whether `name' is a not a writable file or directory.
1735 #
1736 # Arguments : >=1 (empty allowed), more args are ignored
1737 #
1738 is_not_writable()
1739 {
1740   func_check is_not_writable '>=' 1 "$@";
1741   if is_writable "$1"
1742   then
1743     eval "${return_no}";
1744   fi;
1745   eval "${return_yes}";
1746 }
1747
1748
1749 ########################################################################
1750 # is_not_X ()
1751 #
1752 # Test whether not running in X Window by checking $DISPLAY
1753 #
1754 is_not_X()
1755 {
1756   func_check is_X '=' 0 "$@";
1757   if obj DISPLAY is_empty
1758   then
1759     eval "${return_yes}";
1760   fi;
1761   eval "${return_no}";
1762 }
1763
1764
1765 ########################################################################
1766 # is_not_yes (<string>)
1767 #
1768 # Test whether `string' is not "yes".
1769 #
1770 # Arguments : 1
1771 #
1772 is_not_yes()
1773 {
1774   func_check is_not_yes = 1 "$@";
1775   if is_yes "$1"
1776   then
1777     eval "${return_no}";
1778   fi;
1779   eval "${return_yes}";
1780 }
1781
1782
1783 ########################################################################
1784 # is_prog ([<name> [<arg>*]])
1785 #
1786 # Determine whether <name> is a program in $PATH
1787 #
1788 # Arguments : >=0 (empty allowed)
1789 #   <arg>* are ignored, this allows to specify progs with arguments.
1790 #
1791 is_prog()
1792 {
1793   func_check is_prog '>=' 0 "$@";
1794   case "$#" in
1795   0)
1796     eval "${return_no}";
1797     ;;
1798   *)
1799     if where_is "$1" >${_NULL_DEV}
1800     then
1801       eval "${return_yes}";
1802     fi;
1803     ;;
1804   esac
1805   eval "${return_no}";
1806 }
1807
1808
1809 ########################################################################
1810 # is_writable (<name>)
1811 #
1812 # Test whether `name' is a writable file or directory.
1813 #
1814 # Arguments : >=1 (empty allowed), more args are ignored
1815 #
1816 is_writable()
1817 {
1818   func_check is_writable '>=' 1 "$@";
1819   if test _"$1"_ = __
1820   then
1821     eval "${return_no}";
1822   fi;
1823   if test -r "$1"
1824   then
1825     if test -w "$1"
1826     then
1827       eval "${return_yes}";
1828     fi;
1829   fi;
1830   eval "${return_no}";
1831 }
1832
1833
1834 ########################################################################
1835 # is_X ()
1836 #
1837 # Test whether running in X Window by checking $DISPLAY
1838 #
1839 is_X()
1840 {
1841   func_check is_X '=' 0 "$@";
1842   if obj DISPLAY is_not_empty
1843   then
1844     eval "${return_yes}";
1845   fi;
1846   eval "${return_no}";
1847 }
1848
1849
1850 ########################################################################
1851 # is_yes (<string>)
1852 #
1853 # Test whether `string' has value "yes".
1854 #
1855 # Return    : `0' if arg1 is `yes', `1' otherwise.
1856 #
1857 is_yes()
1858 {
1859   func_check is_yes '=' 1 "$@";
1860   if is_equal "$1" 'yes'
1861   then
1862     eval "${return_yes}";
1863   fi;
1864   eval "${return_no}";
1865 }
1866
1867
1868 ########################################################################
1869 # landmark ()
1870 #
1871 # Print debugging information on standard error if $_DEBUG_LM is `yes'.
1872 #
1873 # Globals: $_DEBUG_LM
1874 #
1875 # Defined in section `Debugging functions'.
1876
1877
1878 ########################################################################
1879 # leave ([<code>])
1880 #
1881 # Clean exit without an error or with <code>.
1882 #
1883 leave()
1884 {
1885   clean_up;
1886   if test $# = 0
1887   then
1888     exit "${_OK}";
1889   else
1890     exit "$1";
1891   fi;
1892 }
1893
1894
1895 ########################################################################
1896 landmark '6: list_*()';
1897 ########################################################################
1898 #
1899 # `list' is an object class that represents an array or list.  Its
1900 # data consists of space-separated single-quoted elements.  So a list
1901 # has the form "'first' 'second' '...' 'last'".  See list_append() for
1902 # more details on the list structure.  The array elements of `list'
1903 # can be get by `eval set x "$list"; shift`.
1904
1905
1906 ########################################################################
1907 # list_append (<list> <element>...)
1908 #
1909 # Arguments: >=2
1910 #   <list>: a variable name for a list of single-quoted elements
1911 #   <element>:  some sequence of characters.
1912 # Output: none, but $<list> is set to
1913 #   if <list> is empty:  "'<element>' '...'"
1914 #   otherwise:           "$list '<element>' ..."
1915 #
1916 # Variable prefix: la
1917 #
1918 list_append()
1919 {
1920   func_check list_append '>=' 2 "$@";
1921   la_name="$1";
1922   eval la_list='"${'$1'}"';
1923   shift;
1924   for s
1925   do
1926     la_s="$s";
1927     case "${la_s}" in
1928     *\'*)
1929       # escape each single quote by replacing each
1930       # "'" (squote) by "'\''" (squote bslash squote squote);
1931       # note that the backslash must be doubled in the following `sed'
1932       la_element="$(echo1 "${la_s}" | sed -e 's/'"${_SQ}"'/&\\&&/g')";
1933       exit_test;
1934       ;;
1935     '')
1936       la_element="";
1937       ;;
1938     *)
1939       la_element="${la_s}";
1940       ;;
1941     esac;
1942     if obj la_list is_empty
1943     then
1944       la_list="'${la_element}'";
1945     else
1946       la_list="${la_list} '${la_element}'";
1947     fi;
1948   done;
1949   eval "${la_name}"='"${la_list}"';
1950   eval ${_UNSET} la_element;
1951   eval ${_UNSET} la_list;
1952   eval ${_UNSET} la_name;
1953   eval ${_UNSET} la_s;
1954   eval "${return_ok}";
1955 }
1956
1957
1958 ########################################################################
1959 # list_from_cmdline (<pre_name_of_opt_lists> [<cmdline_arg>...])
1960 #
1961 # Transform command line arguments into a normalized form.
1962 #
1963 # Options, option arguments, and file parameters are identified and
1964 # output each as a single-quoted argument of its own.  Options and
1965 # file parameters are separated by a '--' argument.
1966 #
1967 # Arguments: >=1
1968 #   <pre_name>: common part of a set of 4 environment variable names:
1969 #     $<pre_name>_SHORT_NA:  list of short options without an arg.
1970 #     $<pre_name>_SHORT_ARG: list of short options that have an arg.
1971 #     $<pre_name>_LONG_NA:   list of long options without an arg.
1972 #     $<pre_name>_LONG_ARG:  list of long options that have an arg.
1973 #   <cmdline_arg>...: the arguments from a command line, such as "$@",
1974 #                     the content of a variable, or direct arguments.
1975 #
1976 # Output: ['-[-]opt' ['optarg']]... '--' ['filename']...
1977 #
1978 # Example:
1979 #   list_from_cmdline PRE 'a b' 'c' '' 'long' -a f1 -bcarg --long=larg f2
1980 # If $PRE_SHORT_NA, $PRE_SHORT_ARG, $PRE_LONG_NA, and $PRE_LONG_ARG are
1981 # none-empty option lists, this will result in printing:
1982 #     '-a' '-b' '-c' 'arg' '--long' 'larg' '--' 'f1' 'f2'
1983 #
1984 #   Use this function in the following way:
1985 #     eval set x "$(args_norm PRE_NAME "$@")";
1986 #     shift;
1987 #     while test "$1" != '--'; do
1988 #       case "$1" in
1989 #       ...
1990 #       esac;
1991 #       shift;
1992 #     done;
1993 #     shift;         #skip '--'
1994 #     # all positional parameters ("$@") left are file name parameters.
1995 #
1996 # Variable prefix: lfc
1997 #
1998 list_from_cmdline()
1999 {
2000   func_check list_from_cmdline '>=' 1 "$@";
2001   lfc_short_n="$(obj_data "$1"_SHORT_NA)";  # short options, no argument
2002   lfc_short_a="$(obj_data "$1"_SHORT_ARG)"; # short options, with argument
2003   lfc_long_n="$(obj_data "$1"_LONG_NA)";    # long options, no argument
2004   lfc_long_a="$(obj_data "$1"_LONG_ARG)";   # long options, with argument
2005   exit_test;
2006   if obj lfc_short_n is_empty
2007   then
2008     error 'list_from_cmdline(): no $'"$1"'_SHORT_NA options.';
2009   fi;
2010   if obj lfc_short_a is_empty
2011   then
2012     error 'list_from_cmdline(): no $'"$1"'_SHORT_ARG options.';
2013   fi;
2014   if obj lfc_long_n is_empty
2015   then
2016     error 'list_from_cmdline(): no $'"$1"'_LONG_NA options.';
2017   fi;
2018   if obj lfc_long_a is_empty
2019   then
2020     error 'list_from_cmdline(): no $'"$1"'_LONG_ARG options.';
2021   fi;
2022
2023   shift;
2024   if is_equal "$#" 0
2025   then
2026     echo1 --
2027     eval ${_UNSET} lfc_fparams;
2028     eval ${_UNSET} lfc_short_a;
2029     eval ${_UNSET} lfc_short_n;
2030     eval ${_UNSET} lfc_long_a;
2031     eval ${_UNSET} lfc_long_n;
2032     eval ${_UNSET} lfc_result;
2033     eval "${return_ok}";
2034   fi;
2035
2036   lfc_fparams='';
2037   lfc_result='';
2038   while test "$#" -ge 1
2039   do
2040     lfc_arg="$1";
2041     shift;
2042     case "${lfc_arg}" in
2043     --) break; ;;
2044     --*=*)
2045       # delete leading '--';
2046       lfc_abbrev="$(echo1 "${lfc_arg}" | sed -e 's/^--//')";
2047       lfc_with_equal="${lfc_abbrev}";
2048       # extract option by deleting from the first '=' to the end
2049       lfc_abbrev="$(echo1 "${lfc_with_equal}" | \
2050                     sed -e 's/^\([^=]*\)=.*$/\1/')";
2051       lfc_opt="$(list_single_from_abbrev lfc_long_a "${lfc_abbrev}")";
2052       exit_test;
2053       if obj lfc_opt is_empty
2054       then
2055         error_user "--${lfc_abbrev} is not an option.";
2056       else
2057         # get the option argument by deleting up to first `='
2058         lfc_optarg="$(echo1 "${lfc_with_equal}" | sed -e 's/^[^=]*=//')";
2059         exit_test;
2060         list_append lfc_result "--${lfc_opt}" "${lfc_optarg}";
2061         continue;
2062       fi;
2063       ;;
2064     --*)
2065       # delete leading '--';
2066       lfc_abbrev="$(echo1 "${lfc_arg}" | sed -e 's/^--//')";
2067       if list_has lfc_long_n "${lfc_abbrev}"
2068       then
2069         lfc_opt="${lfc_abbrev}";
2070       else
2071         exit_test;
2072         lfc_opt="$(list_single_from_abbrev lfc_long_n "${lfc_abbrev}")";
2073         exit_test;
2074         if obj lfc_opt is_not_empty && is_not_equal "$#" 0
2075         then
2076           a="$(list_single_from_abbrev lfc_long_a "${lfc_abbrev}")";
2077           exit_test;
2078           if obj a is_not_empty
2079           then
2080             error_user "The abbreviation ${lfc_arg} \
2081 has multiple options: --${lfc_opt} and --${a}.";
2082           fi;
2083         fi;
2084       fi;
2085       if obj lfc_opt is_not_empty
2086       then
2087         # long option, no argument
2088         list_append lfc_result "--${lfc_opt}";
2089         continue;
2090       fi;
2091       lfc_opt="$(list_single_from_abbrev lfc_long_a "${lfc_abbrev}")";
2092       exit_test;
2093       if obj lfc_opt is_not_empty
2094       then
2095         # long option with argument
2096         if test "$#" -le 0
2097         then
2098           error_user "no argument for option --${lfc_opt}."
2099         fi;
2100         list_append lfc_result "--${lfc_opt}" "$1";
2101         shift;
2102         continue;
2103       fi;
2104       error_user "${lfc_arg} is not an option.";
2105       ;;
2106     -?*)                        # short option (cluster)
2107       # delete leading `-';
2108       lfc_rest="$(echo1 "${lfc_arg}" | sed -e 's/^-//')";
2109       exit_test;
2110       while obj lfc_rest is_not_empty
2111       do
2112         # get next short option from cluster (first char of $lfc_rest)
2113         lfc_optchar="$(echo1 "${lfc_rest}" | sed -e 's/^\(.\).*$/\1/')";
2114         # remove first character from ${lfc_rest};
2115         lfc_rest="$(echo1 "${lfc_rest}" | sed -e 's/^.//')";
2116         exit_test;
2117         if list_has lfc_short_n "${lfc_optchar}"
2118         then
2119           list_append lfc_result "-${lfc_optchar}";
2120           continue;
2121         elif list_has lfc_short_a "${lfc_optchar}"
2122         then
2123           if obj lfc_rest is_empty
2124           then
2125             if test "$#" -ge 1
2126             then
2127               list_append lfc_result "-${lfc_optchar}" "$1";
2128               shift;
2129               continue;
2130             else
2131               error_user "no argument for option -${lfc_optchar}.";
2132             fi;
2133           else                  # rest is the argument
2134             list_append lfc_result "-${lfc_optchar}" "${lfc_rest}";
2135             lfc_rest='';
2136             continue;
2137           fi;
2138         else
2139           error_user "unknown option -${lfc_optchar}.";
2140         fi;
2141       done;
2142       ;;
2143     *)
2144       # Here, $lfc_arg is not an option, so a file parameter.
2145       list_append lfc_fparams "${lfc_arg}";
2146
2147       # Ignore the strange POSIX option handling to end option
2148       # parsing after the first file name argument.  To reuse it, do
2149       # a `break' here if $POSIXLY_CORRECT of `bash' is not empty.
2150       # When `bash' is called as `sh' $POSIXLY_CORRECT is set
2151       # automatically to `y'.
2152       ;;
2153     esac;
2154   done;
2155   list_append lfc_result '--';
2156   if obj lfc_fparams is_not_empty
2157   then
2158     lfc_result="${lfc_result} ${lfc_fparams}";
2159   fi;
2160   if test "$#" -gt 0
2161   then
2162     list_append lfc_result "$@";
2163   fi;
2164   obj lfc_result echo1;
2165   eval ${_UNSET} lfc_abbrev;
2166   eval ${_UNSET} lfc_fparams;
2167   eval ${_UNSET} lfc_short_a;
2168   eval ${_UNSET} lfc_short_n;
2169   eval ${_UNSET} lfc_long_a;
2170   eval ${_UNSET} lfc_long_n;
2171   eval ${_UNSET} lfc_result;
2172   eval ${_UNSET} lfc_arg;
2173   eval ${_UNSET} lfc_opt;
2174   eval ${_UNSET} lfc_opt_arg;
2175   eval ${_UNSET} lfc_opt_char;
2176   eval ${_UNSET} lfc_with_equal;
2177   eval ${_UNSET} lfc_rest;
2178   eval "${return_ok}";
2179 } # list_from_cmdline()
2180
2181
2182 ########################################################################
2183 # list_from_split (<string> <separator>)
2184 #
2185 # In <string>, escape all white space characters and replace each
2186 # <separator> by space.
2187 #
2188 # Arguments: 2: a <string> that is to be split into parts divided by
2189 #               <separator>
2190 # Output:    the resulting list string
2191 #
2192 # Variable prefix: lfs
2193 #
2194 list_from_split()
2195 {
2196   func_check list_from_split = 2 "$@";
2197
2198   # precede each space or tab by a backslash `\' (doubled for `sed')
2199   lfs_s="$(echo1 "$1" | sed -e 's/\('"${_SPACE_SED}"'\)/\\\1/g')";
2200   exit_test;
2201
2202   # replace split character of string by the list separator ` ' (space).
2203   case "$2" in
2204     /)                          # cannot use normal `sed' separator
2205       echo1 "${lfs_s}" | sed -e 's|'"$2"'| |g';
2206       ;;
2207     ?)                          # use normal `sed' separator
2208       echo1 "${lfs_s}" | sed -e 's/'"$2"'/ /g';
2209       ;;
2210     ??*)
2211       error 'list_from_split(): separator must be a single character.';
2212       ;;
2213   esac;
2214   eval ${_UNSET} lfs_s;
2215   eval "${return_ok}";
2216 }
2217
2218
2219 ########################################################################
2220 # list_get (<list>)
2221 #
2222 # Check whether <list> is a space-separated list of '-quoted elements.
2223 #
2224 # If the test fails an error is raised.
2225 # If the test succeeds the argument is echoed.
2226 #
2227 # Testing criteria:
2228 #   A list has the form "'first' 'second' '...' 'last'".  So it has a
2229 #   leading and a final quote and the elements are separated by "' '"
2230 #   constructs.  If these are all removed there should not be any
2231 #   unescaped single-quotes left.  Watch out for escaped single
2232 #   quotes; they have the form '\'' (sq bs sq sq).
2233
2234 # Arguments: 1
2235 # Output: the argument <list> unchanged, if the check succeeded.
2236 #
2237 # Variable prefix: lg
2238 #
2239 list_get()
2240 {
2241   func_check list_get = 1 "$@";
2242   eval lg_list='"${'$1'}"';
2243   # remove leading and final space characters
2244   lg_list="$(echo1 "${lg_list}" | sed -e '
2245 s/^'"${_SPACE_SED}"'*//
2246 s/'"${_SPACE_SED}"'*$//
2247 ')";
2248   exit_test;
2249   case "${lg_list}" in
2250   '')
2251     eval ${_UNSET} lg_list;
2252     eval "${return_ok}";
2253     ;;
2254   \'*\')
2255     obj lg_list echo1;
2256     eval ${_UNSET} lg_list;
2257     eval "${return_ok}";
2258     ;;
2259   *)
2260     error "list_get(): bad list: $1"
2261     ;;
2262   esac;
2263   eval ${_UNSET} lg_list;
2264   eval "${return_ok}";
2265 }
2266
2267
2268 ########################################################################
2269 # list_has (<var_name> <element>)
2270 #
2271 # Test whether the list <var_name> has the element <element>.
2272 #
2273 # Arguments: 2
2274 #   <var_name>: a variable name for a list of single-quoted elements
2275 #   <element>:  some sequence of characters.
2276 #
2277 # Variable prefix: lh
2278 #
2279 list_has()
2280 {
2281   func_check list_has = 2 "$@";
2282   eval lh_list='"${'$1'}"';
2283   if obj lh_list is_empty
2284   then
2285     eval "${_UNSET}" lh_list;
2286     eval "${return_no}";
2287   fi;
2288   case "$2" in
2289     \'*\')  lh_element=" $2 "; ;;
2290     *)      lh_element=" '$2' "; ;;
2291   esac;
2292   if string_contains " ${lh_list} " "${lh_element}"
2293   then
2294     eval "${_UNSET}" lh_list;
2295     eval "${_UNSET}" lh_element;
2296     eval "${return_yes}";
2297   else
2298     eval "${_UNSET}" lh_list;
2299     eval "${_UNSET}" lh_element;
2300     eval "${return_no}";
2301   fi;
2302 }
2303
2304
2305 ########################################################################
2306 # list_has_abbrev (<var_name> <abbrev>)
2307 #
2308 # Test whether the list <var_name> has an element starting with <abbrev>.
2309 #
2310 # Arguments: 2
2311 #   <var_name>: a variable name for a list of single-quoted elements
2312 #   <abbrev>:   some sequence of characters.
2313 #
2314 # Variable prefix: lha
2315 #
2316 list_has_abbrev()
2317 {
2318   func_check list_has_abbrev = 2 "$@";
2319   eval lha_list='"${'$1'}"';
2320   if obj lha_list is_empty
2321   then
2322     eval "${_UNSET}" lha_list;
2323     eval "${return_no}";
2324   fi;
2325   case "$2" in
2326     \'*)
2327       lha_element="$(echo1 "$2" | sed -e 's/'"${_SQ}"'$//')";
2328       exit_test;
2329       ;;
2330     *) lha_element="'$2"; ;;
2331   esac;
2332   if string_contains " ${lha_list}" " ${lha_element}"
2333   then
2334     eval "${_UNSET}" lha_list;
2335     eval "${_UNSET}" lha_element;
2336     eval "${return_yes}";
2337   else
2338     eval "${_UNSET}" lha_list;
2339     eval "${_UNSET}" lha_element;
2340     eval "${return_no}";
2341   fi;
2342   eval "${return_ok}";
2343 }
2344
2345
2346 ########################################################################
2347 # list_has_not (<list> <element>)
2348 #
2349 # Test whether <list> has no <element>.
2350 #
2351 # Arguments: 2
2352 #   <list>:    a space-separated list of single-quoted elements.
2353 #   <element>: some sequence of characters.
2354 #
2355 # Variable prefix: lhn
2356 #
2357 list_has_not()
2358 {
2359   func_check list_has_not = 2 "$@";
2360   eval lhn_list='"${'$1'}"';
2361   if obj lhn_list is_empty
2362   then
2363     eval "${_UNSET}" lhn_list;
2364     eval "${return_yes}";
2365   fi;
2366   case "$2" in
2367     \'*\') lhn_element=" $2 "; ;;
2368     *)     lhn_element=" '$2' "; ;;
2369   esac;
2370   if string_contains " ${lhn_list} " "${lhn_element}"
2371   then
2372     eval "${_UNSET}" lhn_list;
2373     eval "${_UNSET}" lhn_element;
2374     eval "${return_no}";
2375   else
2376     eval "${_UNSET}" lhn_list;
2377     eval "${_UNSET}" lhn_element;
2378     eval "${return_yes}";
2379   fi;
2380 }
2381
2382
2383 ########################################################################
2384 # list_single_from_abbrev (<list> <abbrev>)
2385 #
2386 # Check whether the list has an element starting with <abbrev>.  If
2387 # there are more than a single element an error is created.
2388 #
2389 # Arguments: 2
2390 #   <list>:   a variable name for a list of single-quoted elements
2391 #   <abbrev>: some sequence of characters.
2392 #
2393 # Output: the found element.
2394 #
2395 # Variable prefix: lsfa
2396 #
2397 list_single_from_abbrev()
2398 {
2399   func_check list_single_from_abbrev = 2 "$@";
2400   eval lsfa_list='"${'$1'}"';
2401   if obj lsfa_list is_empty
2402   then
2403     eval "${_UNSET}" lsfa_list;
2404     eval "${return_no}";
2405   fi;
2406   lsfa_abbrev="$2";
2407   if list_has lsfa_list "${lsfa_abbrev}"
2408   then
2409     obj lsfa_abbrev echo1;
2410     eval "${_UNSET}" lsfa_abbrev;
2411     eval "${_UNSET}" lsfa_list;
2412     eval "${return_yes}";
2413   fi;
2414   if list_has_abbrev lsfa_list "${lsfa_abbrev}"
2415   then
2416     lsfa_element='';
2417     eval set x "${lsfa_list}";
2418     shift;
2419     for i
2420     do
2421       case "$i" in
2422       ${lsfa_abbrev}*)
2423         if obj lsfa_element is_not_empty
2424         then
2425           error_user "The abbreviation --${lsfa_abbrev} \
2426 has multiple options: --${lsfa_element} and --${i}.";
2427         fi;
2428         lsfa_element="$i";
2429         ;;
2430       esac;
2431     done;
2432     obj lsfa_element echo1;
2433     eval "${_UNSET}" lsfa_abbrev;
2434     eval "${_UNSET}" lsfa_element;
2435     eval "${_UNSET}" lsfa_list;
2436     eval "${return_yes}";
2437   else
2438     eval "${_UNSET}" lsfa_abbrev;
2439     eval "${_UNSET}" lsfa_element;
2440     eval "${_UNSET}" lsfa_list;
2441     eval "${return_no}";
2442   fi;
2443 }
2444
2445
2446 ########################################################################
2447 landmark '7: man_*()';
2448 ########################################################################
2449
2450 ########################################################################
2451 # man_do_filespec (<filespec>)
2452 #
2453 # Print suitable man page(s) for filespec to $_TMP_CAT.
2454 #
2455 # Arguments : 2
2456 #   <filespec>: argument of the form `man:name.section', `man:name',
2457 #               `man:name(section)', `name.section', `name'.
2458 #
2459 # Globals   : $_OPT_ALL
2460 #
2461 # Output    : none.
2462 # Return    : `0' if man page was found, `1' else.
2463 #
2464 # Only called from do_fileargs(), checks on $MANPATH and $_MAN_ENABLE
2465 # are assumed (see man_setup()).
2466 #
2467 # Variable prefix: mdf
2468 #
2469 man_do_filespec()
2470 {
2471   func_check man_do_filespec = 1 "$@";
2472   if obj _MAN_PATH is_empty
2473   then
2474     eval "${return_bad}";
2475   fi;
2476   if is_empty "$1"
2477   then
2478     eval "${return_bad}";
2479   fi;
2480   mdf_spec="$1";
2481   mdf_name='';
2482   mdf_section='';
2483   case "${mdf_spec}" in
2484   */*)                          # not a man spec with containing '/'
2485     eval ${_UNSET} mdf_got_one;
2486     eval ${_UNSET} mdf_name;
2487     eval ${_UNSET} mdf_section;
2488     eval ${_UNSET} mdf_spec;
2489     eval "${return_bad}";
2490     ;;
2491   man:?*\(?*\))                 # man:name(section)
2492     mdf_name="$(echo1 "${mdf_spec}" \
2493                 | sed -e 's/^man:\(..*\)(\(..*\))$/\1/')";
2494     mdf_section="$(echo1 "${mdf_spec}" \
2495                    | sed -e 's/^man:\(..*\)(\(..*\))$/\2/')";
2496     exit_test;
2497     ;;
2498   man:?*.${_MAN_AUTO_SEC_CHARS}) # man:name.section
2499     mdf_name="$(echo1 "${mdf_spec}" \
2500                 | sed -e 's/^man:\(..*\)\..$/\1/')";
2501     mdf_section="$(echo1 "${mdf_spec}" \
2502                    | sed -e 's/^.*\(.\)$/\1/')";
2503     exit_test;
2504     ;;
2505   man:?*)                       # man:name
2506     mdf_name="$(echo1 "${mdf_spec}" | sed -e 's/^man://')";
2507     exit_test;
2508     ;;
2509   ?*\(?*\))                     # name(section)
2510     mdf_name="$(echo1 "${mdf_spec}" \
2511                 | sed -e 's/^\(..*\)(\(..*\))$/\1/')";
2512     mdf_section="$(echo1 "${mdf_spec}" \
2513                    | sed -e 's/^\(..*\)(\(..*\))$/\2/')";
2514     exit_test;
2515     ;;
2516   ?*.${_MAN_AUTO_SEC_CHARS})    # name.section
2517     mdf_name="$(echo1 "${mdf_spec}" \
2518                 | sed -e 's/^\(..*\)\..$/\1/')";
2519     mdf_section="$(echo1 "${mdf_spec}" \
2520                    | sed -e 's/^.*\(.\)$/\1/')";
2521     exit_test;
2522     ;;
2523   ?*)
2524     mdf_name="${mdf_spec}";
2525     ;;
2526   esac;
2527   if obj mdf_name is_empty
2528   then
2529     eval ${_UNSET} mdf_got_one;
2530     eval ${_UNSET} mdf_name;
2531     eval ${_UNSET} mdf_section;
2532     eval ${_UNSET} mdf_spec;
2533     eval "${return_bad}";
2534   fi;
2535   mdf_got_one='no';
2536   if obj mdf_section is_empty
2537   then
2538     if obj _OPT_SECTIONS is_empty
2539     then
2540       eval set x "${_MAN_AUTO_SEC_LIST}";
2541     else
2542       # use --sections when no section is given to filespec
2543       eval set x "$(echo1 "${_OPT_SECTIONS}" | sed -e 's/:/ /g')";
2544     fi;
2545     shift;
2546     for s
2547     do
2548       mdf_s="$s";
2549       if man_search_section "${mdf_name}" "${mdf_s}"
2550       then                      # found
2551         if obj _MAN_ALL is_yes
2552         then
2553           mdf_got_one='yes';
2554         else
2555           eval ${_UNSET} mdf_got_one;
2556           eval ${_UNSET} mdf_name;
2557           eval ${_UNSET} mdf_s;
2558           eval ${_UNSET} mdf_section;
2559           eval ${_UNSET} mdf_spec;
2560           eval "${return_good}";
2561         fi;
2562       fi;
2563     done;
2564   else
2565     if man_search_section "${mdf_name}" "${mdf_section}"
2566     then
2567       eval ${_UNSET} mdf_got_one;
2568       eval ${_UNSET} mdf_name;
2569       eval ${_UNSET} mdf_s;
2570       eval ${_UNSET} mdf_section;
2571       eval ${_UNSET} mdf_spec;
2572       eval "${return_good}";
2573     else
2574       eval ${_UNSET} mdf_got_one;
2575       eval ${_UNSET} mdf_name;
2576       eval ${_UNSET} mdf_section;
2577       eval ${_UNSET} mdf_spec;
2578       eval "${return_bad}";
2579     fi;
2580   fi;
2581   if obj _MAN_ALL is_yes && obj mdf_got_one is_yes
2582   then
2583     eval ${_UNSET} mdf_got_one;
2584     eval ${_UNSET} mdf_name;
2585     eval ${_UNSET} mdf_s;
2586     eval ${_UNSET} mdf_section;
2587     eval ${_UNSET} mdf_spec;
2588     eval "${return_good}";
2589   fi;
2590   eval ${_UNSET} mdf_got_one;
2591   eval ${_UNSET} mdf_name;
2592   eval ${_UNSET} mdf_s;
2593   eval ${_UNSET} mdf_section;
2594   eval ${_UNSET} mdf_spec;
2595   eval "${return_bad}";
2596 } # man_do_filespec()
2597
2598
2599 ########################################################################
2600 # man_register_file (<file> <name> [<section>])
2601 #
2602 # Write a found man page file and register the title element.
2603 #
2604 # Arguments: 1, 2, or 3; maybe empty
2605 # Output: none
2606 #
2607 man_register_file()
2608 {
2609   func_check man_register_file '>=' 2 "$@";
2610   case "$#" in
2611     2|3) do_nothing; ;;
2612     *)
2613       error "man_register_file() expects 2 or 3 arguments.";
2614       ;;
2615   esac;
2616   if is_empty "$1"
2617   then
2618     error 'man_register_file(): file name is empty';
2619   fi;
2620   to_tmp "$1";
2621   case "$#" in
2622     2)
2623        register_title "man:$2";
2624        eval "${return_ok}";
2625        ;;
2626     3)
2627        register_title "$2.$3";
2628        eval "${return_ok}";
2629        ;;
2630   esac;
2631   eval "${return_ok}";
2632 }
2633
2634
2635 ########################################################################
2636 # man_search_section (<name> <section>)
2637 #
2638 # Retrieve man pages.
2639 #
2640 # Arguments : 2
2641 # Globals   : $_MAN_PATH, $_MAN_EXT
2642 # Return    : 0 if found, 1 otherwise
2643 #
2644 # Variable prefix: mss
2645 #
2646 man_search_section()
2647 {
2648   func_check man_search_section = 2 "$@";
2649   if obj _MAN_PATH is_empty
2650   then
2651     eval "${return_bad}";
2652   fi;
2653   if is_empty "$1"
2654   then
2655     eval "${return_bad}";
2656   fi;
2657   if is_empty "$2"
2658   then
2659     eval "${return_bad}";
2660   fi;
2661   mss_name="$1";
2662   mss_section="$2";
2663   eval set x "$(path_split "${_MAN_PATH}")";
2664   exit_test;
2665   shift;
2666   mss_got_one='no';
2667   if obj _MAN_EXT is_empty
2668   then
2669     for d
2670     do
2671       mss_dir="$(dirname_append "$d" "man${mss_section}")";
2672       exit_test;
2673       if obj mss_dir is_dir
2674       then
2675         mss_prefix="$(\
2676           dirname_append "${mss_dir}" "${mss_name}.${mss_section}")";
2677         if obj _OPT_WHATIS is_yes
2678         then
2679           mss_files="$(eval ls "${mss_prefix}"'*' 2>${_NULL_DEV} |
2680                        sed -e '\| found|s|.*||'
2681                        )";
2682         else
2683           mss_files="$(eval ls "'${mss_prefix}'"'*' 2>${_NULL_DEV} |
2684                        sed -e '\| found|s|.*||'
2685                        )";
2686         fi;
2687         exit_test;
2688         if obj mss_files is_not_empty
2689         then
2690           # for f in $mss_files
2691           for f in $(eval set x ${mss_files}; shift; echo1 "$@")
2692           do
2693             exit_test;
2694             mss_f="$f";
2695             if obj mss_f is_file
2696             then
2697               if is_yes "${mss_got_one}"
2698               then
2699                 register_file "${mss_f}";
2700               elif obj _MAN_ALL is_yes
2701               then
2702                 man_register_file "${mss_f}" "${mss_name}";
2703               else
2704                 man_register_file "${mss_f}" "${mss_name}" "${mss_section}";
2705                 eval ${_UNSET} mss_dir;
2706                 eval ${_UNSET} mss_ext;
2707                 eval ${_UNSET} mss_f;
2708                 eval ${_UNSET} mss_files;
2709                 eval ${_UNSET} mss_got_one;
2710                 eval ${_UNSET} mss_name;
2711                 eval ${_UNSET} mss_prefix;
2712                 eval ${_UNSET} mss_section;
2713                 eval "${return_good}";
2714               fi;
2715               mss_got_one='yes';
2716             fi;
2717           done;
2718         fi;
2719       fi;
2720     done;
2721   else
2722     mss_ext="${_MAN_EXT}";
2723     # check for directory name having trailing extension
2724     for d
2725     do
2726       mss_dir="$(dirname_append $d man${mss_section}${mss_ext})";
2727       exit_test;
2728       if obj mss_dir is_dir
2729       then
2730         mss_prefix=\
2731           "$(dirname_append "${mss_dir}" "${mss_name}.${mss_section}")";
2732         mss_files="$( eval ls "${mss_prefix}"'*' 2>${_NULL_DEV} |
2733                      sed -e '\|not found|s|.*||'
2734                      )";
2735         exit_test;
2736         if obj mss_files is_not_empty
2737         then
2738           # for f in $mss_files
2739           for f in $(eval set x ${mss_files}; shift; echo1 "$@")
2740           do
2741             mss_f="$f";
2742             if obj mss_f is_file
2743             then
2744               if is_yes "${mss_got_one}"
2745               then
2746                 register_file "${mss_f}";
2747               elif obj _MAN_ALL is_yes
2748               then
2749                 man_register_file "${mss_f}" "${mss_name}";
2750               else
2751                 man_register_file "${mss_f}" "${mss_name}" "${mss_section}";
2752                 eval ${_UNSET} mss_dir;
2753                 eval ${_UNSET} mss_ext;
2754                 eval ${_UNSET} mss_f;
2755                 eval ${_UNSET} mss_files;
2756                 eval ${_UNSET} mss_got_one;
2757                 eval ${_UNSET} mss_name;
2758                 eval ${_UNSET} mss_prefix;
2759                 eval ${_UNSET} mss_section;
2760                 eval "${return_good}";
2761               fi;
2762               mss_got_one='yes';
2763             fi;
2764           done;
2765         fi;
2766       fi;
2767     done;
2768     # check for files with extension in directories without extension
2769     for d
2770     do
2771       mss_dir="$(dirname_append "$d" "man${mss_section}")";
2772       exit_test;
2773       if obj mss_dir is_dir
2774       then
2775         mss_prefix="$(dirname_append "${mss_dir}" \
2776                         "${mss_name}.${mss_section}${mss_ext}")";
2777         mss_files="$(eval ls "${mss_prefix}"'*' 2>${_NULL_DEV} |
2778                      sed -e '\|not found|s|.*||'
2779                      )";
2780         exit_test;
2781         if obj mss_files is_not_empty
2782         then
2783           # for f in $mss_files
2784           for f in $(eval set x ${mss_files}; shift; echo1 "$@")
2785           do
2786             mss_f="$f";
2787             if obj mss_f is_file
2788             then
2789               if is_yes "${mss_got_one}"
2790               then
2791                 register_file "${mss_f}";
2792               elif obj _MAN_ALL is_yes
2793               then
2794                 man_register_file "${mss_f}" "${mss_name}";
2795               else
2796                 man_register_file "${mss_f}" "${mss_name}" "${mss_section}";
2797                 eval ${_UNSET} mss_dir;
2798                 eval ${_UNSET} mss_ext;
2799                 eval ${_UNSET} mss_f;
2800                 eval ${_UNSET} mss_files;
2801                 eval ${_UNSET} mss_got_one;
2802                 eval ${_UNSET} mss_name;
2803                 eval ${_UNSET} mss_prefix;
2804                 eval ${_UNSET} mss_section;
2805                 eval "${return_good}";
2806               fi;
2807               mss_got_one='yes';
2808             fi;
2809           done;
2810         fi;
2811       fi;
2812     done;
2813   fi;
2814   if obj _MAN_ALL is_yes && is_yes "${mss_got_one}"
2815   then
2816     eval ${_UNSET} mss_dir;
2817     eval ${_UNSET} mss_ext;
2818     eval ${_UNSET} mss_f;
2819     eval ${_UNSET} mss_files;
2820     eval ${_UNSET} mss_got_one;
2821     eval ${_UNSET} mss_name;
2822     eval ${_UNSET} mss_prefix;
2823     eval ${_UNSET} mss_section;
2824     eval "${return_good}";
2825   fi;
2826   eval ${_UNSET} mss_dir;
2827   eval ${_UNSET} mss_ext;
2828   eval ${_UNSET} mss_f;
2829   eval ${_UNSET} mss_files;
2830   eval ${_UNSET} mss_got_one;
2831   eval ${_UNSET} mss_name;
2832   eval ${_UNSET} mss_prefix;
2833   eval ${_UNSET} mss_section;
2834   eval "${return_bad}";
2835 } # man_search_section()
2836
2837
2838 ########################################################################
2839 # man_setup ()
2840 #
2841 # Setup the variables $_MAN_* needed for man page searching.
2842 #
2843 # Globals:
2844 #   in:     $_OPT_*, $_MANOPT_*, $LANG, $LC_MESSAGES, $LC_ALL,
2845 #           $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM, $MANOPT.
2846 #   out:    $_MAN_PATH, $_MAN_LANG, $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2,
2847 #           $_MAN_SEC, $_MAN_ALL
2848 #   in/out: $_MAN_ENABLE
2849 #
2850 # The precedence for the variables related to `man' is that of GNU
2851 # `man', i.e.
2852 #
2853 # $LANG; overridden by
2854 # $LC_MESSAGES; overridden by
2855 # $LC_ALL; this has the same precedence as
2856 # $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM; overridden by
2857 # $MANOPT; overridden by
2858 # the groffer command line options.
2859 #
2860 # Variable prefix: ms
2861 #
2862 man_setup()
2863 {
2864   func_check main_man_setup = 0 "$@";
2865
2866   if obj _MAN_IS_SETUP is_yes
2867   then
2868     eval "${return_ok}";
2869   fi;
2870   _MAN_IS_SETUP='yes';
2871
2872   if obj _MAN_ENABLE is_not_yes
2873   then
2874     eval "${return_ok}";
2875   fi;
2876
2877   # determine basic path for man pages
2878   _MAN_PATH="$(get_first_essential \
2879                "${_OPT_MANPATH}" "${_MANOPT_PATH}" "${MANPATH}")";
2880   exit_test;
2881   if obj _MAN_PATH is_empty
2882   then
2883     manpath_set_from_path;
2884   else
2885     _MAN_PATH="$(path_clean "${_MAN_PATH}")";
2886     exit_test;
2887   fi;
2888   if obj _MAN_PATH is_empty
2889   then
2890     if is_prog 'manpath'
2891     then
2892       _MAN_PATH="$(manpath 2>${_NULL_DEV})"; # not always available
2893       exit_test;
2894     fi;
2895   fi;
2896   if obj _MAN_PATH is_empty
2897   then
2898     _MAN_ENABLE="no";
2899     eval "${return_ok}";
2900   fi;
2901
2902   _MAN_ALL="$(get_first_essential "${_OPT_ALL}" "${_MANOPT_ALL}")";
2903   exit_test;
2904   if obj _MAN_ALL is_empty
2905   then
2906     _MAN_ALL='no';
2907   fi;
2908
2909   _MAN_SYS="$(get_first_essential \
2910               "${_OPT_SYSTEMS}" "${_MANOPT_SYS}" "${SYSTEM}")";
2911   ms_lang="$(get_first_essential \
2912            "${_OPT_LANG}" "${LC_ALL}" "${LC_MESSAGES}" "${LANG}")";
2913   exit_test;
2914   case "${ms_lang}" in
2915     C|POSIX)
2916       _MAN_LANG="";
2917       _MAN_LANG2="";
2918       ;;
2919     ?)
2920       _MAN_LANG="${ms_lang}";
2921       _MAN_LANG2="";
2922       ;;
2923     *)
2924       _MAN_LANG="${ms_lang}";
2925       # get first two characters of $ms_lang
2926       _MAN_LANG2="$(echo1 "${ms_lang}" | sed -e 's/^\(..\).*$/\1/')";
2927       exit_test;
2928       ;;
2929   esac;
2930   # from now on, use only $_LANG, forget about $_OPT_LANG, $LC_*.
2931
2932   manpath_add_lang_sys;         # this is very slow
2933
2934   _MAN_SEC="$(get_first_essential \
2935               "${_OPT_SECT}" "${_MANOPT_SEC}" "${MANSEC}")";
2936   exit_test;
2937   if obj _MAN_PATH is_empty
2938   then
2939     _MAN_ENABLE="no";
2940     eval ${_UNSET} ms_lang;
2941     eval "${return_ok}";
2942   fi;
2943
2944   _MAN_EXT="$(get_first_essential \
2945               "${_OPT_EXTENSION}" "${_MANOPT_EXTENSION}")";
2946   exit_test;
2947   eval ${_UNSET} ms_lang;
2948   eval "${return_ok}";
2949 } # man_setup()
2950
2951
2952 ########################################################################
2953 landmark '8: manpath_*()';
2954 ########################################################################
2955
2956 ########################################################################
2957 # manpath_add_lang_sys ()
2958 #
2959 # Add language and operating system specific directories to man path.
2960 #
2961 # Arguments : 0
2962 # Output    : none
2963 # Globals:
2964 #   in:     $_MAN_SYS: has the form `os1,os2,...', a comma separated
2965 #             list of names of operating systems.
2966 #           $_MAN_LANG and $_MAN_LANG2: each a single name
2967 #   in/out: $_MAN_PATH: has the form `dir1:dir2:...', a colon
2968 #             separated list of directories.
2969 #
2970 # Variable prefix: mals
2971 #
2972 manpath_add_lang_sys()
2973 {
2974   func_check manpath_add_lang_sys = 0 "$@";
2975   if obj _MAN_PATH is_empty
2976   then
2977     eval "${return_ok}";
2978   fi;
2979   # twice test both sys and lang
2980   eval set x "$(path_split "${_MAN_PATH}")";
2981   shift;
2982   exit_test;
2983   mals_mp='';
2984   for p
2985   do                            # loop on man path directories
2986     mals_mp="$(_manpath_add_lang_sys_single "${mals_mp}" "$p")";
2987     exit_test;
2988   done;
2989   eval set x "$(path_split "${mals_mp}")";
2990   shift;
2991   exit_test;
2992   for p
2993   do                            # loop on man path directories
2994     mals_mp="$(_manpath_add_lang_sys_single "${mals_mp}" "$p")";
2995     exit_test;
2996   done;
2997   _MAN_PATH="$(path_chop "${mals_mp}")";
2998   exit_test;
2999   eval ${_UNSET} mals_mp;
3000   eval "${return_ok}";
3001 }
3002
3003
3004 # To the directory in $1 append existing sys/lang subdirectories
3005 # Function is necessary to split the OS list.
3006 #
3007 # globals: in: $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2
3008 # argument: 2: `man_path' and `dir'
3009 # output: colon-separated path of the retrieved subdirectories
3010 #
3011 # Variable prefix: _mals
3012 #
3013 _manpath_add_lang_sys_single()
3014 {
3015   func_check _manpath_add_lang_sys_single = 2 "$@";
3016   _mals_res="$1";
3017   _mals_parent="$2";
3018   eval set x "$(list_from_split "${_MAN_SYS}" ',')";
3019   shift;
3020   exit_test;
3021   for d in "$@" "${_MAN_LANG}" "${_MAN_LANG2}"
3022   do
3023     _mals_dir="$(dirname_append "${_mals_parent}" "$d")";
3024     exit_test;
3025     if obj _mals_res path_not_contains "${_mals_dir}" && \
3026        obj _mals_dir is_dir
3027     then
3028       _mals_res="${_mals_res}:${_mals_dir}";
3029     fi;
3030   done;
3031   if path_not_contains "${_mals_res}" "${_mals_parent}"
3032   then
3033     _mals_res="${_mals_res}:${_mals_parent}";
3034   fi;
3035   path_chop "${_mals_res}";
3036   eval ${_UNSET} _mals_dir;
3037   eval ${_UNSET} _mals_parent;
3038   eval ${_UNSET} _mals_res;
3039   eval "${return_ok}";
3040 }
3041
3042 # end manpath_add_lang_sys ()
3043
3044
3045 ########################################################################
3046 # manpath_set_from_path ()
3047 #
3048 # Determine basic search path for man pages from $PATH.
3049 #
3050 # Return:    `0' if a valid man path was retrieved.
3051 # Output:    none
3052 # Globals:
3053 #   in:  $PATH
3054 #   out: $_MAN_PATH
3055 #
3056 # Variable prefix: msfp
3057 #
3058 manpath_set_from_path()
3059 {
3060   func_check manpath_set_from_path = 0 "$@";
3061
3062   msfp_manpath='';
3063
3064   # get a basic man path from $PATH
3065   if obj PATH is_not_empty
3066   then
3067     eval set x "$(path_split "${PATH}")";
3068     shift;
3069     exit_test;
3070     for d
3071     do
3072       # delete the final `/bin' part
3073       msfp_base="$(echo1 "$d" | sed -e 's|//*bin/*$||')";
3074       exit_test;
3075       for e in /share/man /man
3076       do
3077         msfp_mandir="${msfp_base}$e";
3078         if test -d "${msfp_mandir}" && test -r "${msfp_mandir}"
3079         then
3080           msfp_manpath="${msfp_manpath}:${msfp_mandir}";
3081         fi;
3082       done;
3083     done;
3084   fi;
3085
3086   # append some default directories
3087   for d in /usr/local/share/man /usr/local/man \
3088            /usr/share/man /usr/man \
3089            /usr/X11R6/man /usr/openwin/man \
3090            /opt/share/man /opt/man \
3091            /opt/gnome/man /opt/kde/man
3092   do
3093     msfp_d="$d";
3094     if obj msfp_manpath path_not_contains "${msfp_d}" && obj mfsp_d is_dir
3095     then
3096       msfp_manpath="${msfp_manpath}:${mfsp_d}";
3097     fi;
3098   done;
3099
3100   _MAN_PATH="${msfp_manpath}";
3101   eval ${_UNSET} msfp_base;
3102   eval ${_UNSET} msfp_d;
3103   eval ${_UNSET} msfp_mandir;
3104   eval ${_UNSET} msfp_manpath;
3105   eval "${return_ok}";
3106 } # manpath_set_from_path()
3107
3108
3109 ########################################################################
3110 landmark '9: obj_*()';
3111 ########################################################################
3112
3113 ########################################################################
3114 # obj (<object> <call_name> <arg>...)
3115 #
3116 # This works like a method (object function) call for an object.
3117 # Run "<call_name> $<object> <arg> ...".
3118 #
3119 # The first argument represents an object whose data is given as first
3120 # argument to <call_name>().
3121 #
3122 # Argument: >=2
3123 #           <object>: variable name
3124 #           <call_name>: a program or function name
3125 #
3126 # Variable prefix: o
3127 #
3128 obj()
3129 {
3130   func_check obj '>=' 2 "$@";
3131   eval o_arg1='"${'$1'}"';
3132   if is_empty "$2"
3133   then
3134     error "obj(): function name is empty."
3135   else
3136     o_func="$2";
3137   fi;
3138   shift;
3139   shift;
3140   eval "${o_func}"' "${o_arg1}" "$@"';
3141   n="$?";
3142   eval ${_UNSET} o_arg1;
3143   eval ${_UNSET} o_func;
3144   eval "${return_var} $n";
3145 } # obj()
3146
3147
3148 ########################################################################
3149 # obj_data (<object>)
3150 #
3151 # Print the data of <object>, i.e. the content of $<object>.
3152 # For possible later extensions.
3153 #
3154 # Arguments: 1
3155 #            <object>: a variable name
3156 # Output:    the data of <object>
3157 #
3158 # Variable prefix: od
3159 #
3160 obj_data()
3161 {
3162   func_check obj '=' 1 "$@";
3163   if is_empty "$1"
3164   then
3165     error "obj_data(): object name is empty."
3166   fi;
3167   eval od_res='"${'$1'}"';
3168   obj od_res echo1;
3169   eval ${_UNSET} od_res;
3170   eval "${return_ok}";
3171 }
3172
3173
3174 ########################################################################
3175 # obj_from_output (<object> <call_name> <arg>...)
3176 #
3177 # Run '$<object>="$(<call_name> <arg>...)"' to set the result of a
3178 # function call to a global variable.
3179 #
3180 # Arguments: >=2
3181 #            <object>: a variable name
3182 #            <call_name>: the name of a function or program
3183 #            <arg>: optional argument to <call_name>
3184 # Output:    none
3185 #
3186 # Variable prefix: ofo
3187 #
3188 obj_from_output()
3189 {
3190   func_check obj_from_output '>=' 2 "$@";
3191   if is_empty "$1"
3192   then
3193     error "res(): variable name is empty.";
3194   elif is_empty "$2"
3195   then
3196     error "res(): function name is empty."
3197   else
3198     ofo_result_name="$1";
3199   fi;
3200   shift;
3201   eval "${ofo_result_name}"'="$('"$@"')"';
3202   exit_test;
3203   eval "${return_ok}";
3204 }
3205
3206
3207 ########################################################################
3208 # obj_set (<object> <data>)
3209 #
3210 # Set the data of <object>, i.e. call "$<object>=<data>".
3211 #
3212 # Arguments: 2
3213 #            <object>: a variable name
3214 #            <data>: a string
3215 # Output::   none
3216 #
3217 obj_set()
3218 {
3219   func_check obj_set '=' 2 "$@";
3220   if is_empty "$1"
3221   then
3222     error "obj_set(): object name is empty."
3223   fi;
3224   eval "$1"='"$2"';
3225   eval "${return_ok}";
3226 }
3227
3228
3229 ########################################################################
3230 # path_chop (<path>)
3231 #
3232 # Remove unnecessary colons from path.
3233 #
3234 # Argument: 1, a colon separated path.
3235 # Output:   path without leading, double, or trailing colons.
3236 #
3237 path_chop()
3238 {
3239   func_check path_chop = 1 "$@";
3240
3241   # replace multiple colons by a single colon `:'
3242   # remove leading and trailing colons
3243   echo1 "$1" | sed -e '
3244 s/^:*//
3245 s/:::*/:/g
3246 s/:*$//
3247 ';
3248   eval "${return_ok}";
3249 }
3250
3251
3252 ########################################################################
3253 # path_clean (<path>)
3254 #
3255 # Remove non-existing directories from a colon-separated list.
3256 #
3257 # Argument: 1, a colon separated path.
3258 # Output:   colon-separated list of existing directories.
3259 #
3260 # Variable prefix: pc
3261 #
3262 path_clean()
3263 {
3264   func_check path_clean = 1 "$@";
3265   if is_not_equal "$#" 1
3266   then
3267     error 'path_clean() needs 1 argument.';
3268   fi;
3269   pc_arg="$1";
3270   eval set x "$(path_split "${pc_arg}")";
3271   exit_test;
3272   shift;
3273   pc_res="";
3274   for i
3275   do
3276     pc_i="$i";
3277     if obj pc_i is_not_empty \
3278        && obj pc_res path_not_contains "${pc_i}" \
3279        && obj pc_i is_dir
3280     then
3281       case "${pc_i}" in
3282       ?*/)
3283         pc_res="${pc_res}$(dirname_chop "${pc_i}")";
3284         exit_test;
3285         ;;
3286       *)
3287         pc_res="${pc_res}:${pc_i}";
3288         exit_test;
3289         ;;
3290       esac;
3291     fi;
3292   done;
3293   eval ${_UNSET} pc_arg;
3294   eval ${_UNSET} pc_i;
3295   eval ${_UNSET} pc_res;
3296   if path_chop "${pc_res}"
3297   then
3298     eval "${return_ok}";
3299   else
3300     eval "${return_bad}";
3301   fi;
3302 }
3303
3304
3305 ########################################################################
3306 # path_contains (<path> <dir>)
3307 #-
3308 # Test whether `dir' is contained in `path', a list separated by `:'.
3309 #
3310 # Arguments : 2 arguments.
3311 # Return    : `0' if arg2 is substring of arg1, `1' otherwise.
3312 #
3313 path_contains()
3314 {
3315   func_check path_contains = 2 "$@";
3316   case ":$1:" in
3317     *":$2:"*)
3318       eval "${return_yes}";
3319       ;;
3320     *)
3321       eval "${return_no}";
3322       ;;
3323   esac;
3324   eval "${return_ok}";
3325 }
3326
3327
3328 ########################################################################
3329 # path_not_contains (<path> <dir>)
3330 #
3331 # Test whether `dir' is not contained in colon separated `path'.
3332 #
3333 # Arguments : 2 arguments.
3334 #
3335 path_not_contains()
3336 {
3337   func_check path_not_contains = 2 "$@";
3338   if path_contains "$1" "$2"
3339   then
3340     eval "${return_no}";
3341   else
3342     eval "${return_yes}";
3343   fi;
3344   eval "${return_ok}";
3345 }
3346
3347
3348 ########################################################################
3349 # path_split (<path>)
3350 #
3351 # In `path' escape white space and replace each colon by a space.
3352 #
3353 # Arguments: 1: a colon-separated path
3354 # Output:    the resulting list, process with `eval set'
3355 #
3356 path_split()
3357 {
3358   func_check path_split = 1 "$@";
3359   list_from_split "$1" ':';
3360   eval "${return_ok}";
3361 }
3362
3363
3364 ########################################################################
3365 landmark '10: register_*()';
3366 ########################################################################
3367
3368 ########################################################################
3369 # register_file (<filename>)
3370 #
3371 # Write a found file and register the title element.
3372 #
3373 # Arguments: 1: a file name
3374 # Output: none
3375 #
3376 register_file()
3377 {
3378   func_check register_file = 1 "$@";
3379   if is_empty "$1"
3380   then
3381     error 'register_file(): file name is empty';
3382   fi;
3383   if is_equal "$1" '-'
3384   then
3385     to_tmp "${_TMP_STDIN}";
3386     register_title 'stdin';
3387   else
3388     to_tmp "$1";
3389     register_title "$(base_name "$1")";
3390     exit_test;
3391   fi;
3392   eval "${return_ok}";
3393 } # register_file()
3394
3395
3396 ########################################################################
3397 # register_title (<filespec>)
3398 #
3399 # Create title element from <filespec> and append to $_REGISTERED_TITLE
3400 #
3401 # Globals: $_REGISTERED_TITLE (rw)
3402 #
3403 # Variable prefix: rt
3404 #
3405 register_title()
3406 {
3407   func_check register_title '=' 1 "$@";
3408   if is_empty "$1"
3409   then
3410     eval "${return_ok}";
3411   fi;
3412
3413   case "${_REGISTERED_TITLE}" in
3414   *\ *\ *\ *)
3415     eval "${return_ok}";
3416     ;;
3417   esac;
3418
3419   # remove directory part
3420   rt_title="$(base_name "$1")";
3421   # replace space characters by `_'
3422   rt_title="$(echo1 "${rt_title}" | sed -e 's/[         ]/_/g')";
3423   # remove extension `.bz2'
3424   rt_title="$(echo1 "${rt_title}" | sed -e 's/\.bz2$//')";
3425   # remove extension `.gz'
3426   rt_title="$(echo1 "${rt_title}" | sed -e 's/\.gz$//')";
3427   # remove extension `.Z'
3428   rt_title="$(echo1 "${rt_title}" | sed -e 's/\.Z$//')";
3429   exit_test;
3430
3431   if obj rt_title is_empty
3432   then
3433     eval ${_UNSET} rt_title;
3434     eval "${return_ok}";
3435   fi;
3436   if obj _REGISTERED_TITLE is_empty
3437   then
3438     _REGISTERED_TITLE="${rt_title}";
3439   else
3440     _REGISTERED_TITLE="${_REGISTERED_TITLE} ${rt_title}";
3441   fi;
3442   eval ${_UNSET} rt_title;
3443   eval "${return_ok}";
3444 } # register_title()
3445
3446
3447 ########################################################################
3448 # reset ()
3449 #
3450 # Reset the variables that can be affected by options to their default.
3451 #
3452 #
3453 # Defined in section `Preset' after the rudimentary shell tests.
3454
3455
3456 ########################################################################
3457 # rm_file (<file_name>)
3458 #
3459 # Remove file if $_DEBUG_KEEP_FILES allows it.
3460 #
3461 # Globals: $_DEBUG_KEEP_FILES
3462 #
3463 rm_file()
3464 {
3465   func_check rm_file '=' 1 "$@";
3466   if is_file "$1"
3467   then
3468     rm -f "$1" >${_NULL_DEV} 2>&1;
3469   fi;
3470   if is_existing "$1"
3471   then
3472     eval "${return_bad}";
3473   else
3474     eval "${return_good}";
3475   fi;
3476 }
3477
3478
3479 ########################################################################
3480 # rm_file_with_debug (<file_name>)
3481 #
3482 # Remove file if $_DEBUG_KEEP_FILES allows it.
3483 #
3484 # Globals: $_DEBUG_KEEP_FILES
3485 #
3486 rm_file_with_debug()
3487 {
3488   func_check rm_file_with_debug '=' 1 "$@";
3489   if obj _DEBUG_KEEP_FILES is_not_yes
3490   then
3491     if is_file "$1"
3492     then
3493       rm -f "$1" >${_NULL_DEV} 2>&1;
3494     fi;
3495   fi;
3496   if is_existing "$1"
3497   then
3498     eval "${return_bad}";
3499   else
3500     eval "${return_good}";
3501   fi;
3502 }
3503
3504
3505 ########################################################################
3506 # rm_tree (<dir_name>)
3507 #
3508 # Remove file if $_DEBUG_KEEP_FILES allows it.
3509 #
3510 # Globals: $_DEBUG_KEEP_FILES
3511 #
3512 rm_tree()
3513 {
3514   func_check rm_tree '=' 1 "$@";
3515   if is_existing "$1"
3516   then
3517     rm -f -r "$1" >${_NULL_DEV} 2>&1;
3518   fi; 
3519   if is_existing "$1"
3520   then
3521     eval "${return_bad}";
3522   else
3523     eval "${return_good}";
3524   fi;
3525 }
3526
3527
3528 ########################################################################
3529 # save_stdin ()
3530 #
3531 # Store standard input to temporary file (with decompression).
3532 #
3533 # Variable prefix: ss
3534 #
3535 if obj _HAS_COMPRESSION is_yes
3536 then
3537   save_stdin()
3538   {
3539     func_check save_stdin '=' 0 "$@";
3540     ss_f="${_TMP_DIR}"/INPUT;
3541     cat >"${ss_f}";
3542     cat_z "${ss_f}" >"${_TMP_STDIN}";
3543     rm_file "${ss_f}";
3544     eval ${_UNSET} ss_f;
3545     eval "${return_ok}";
3546   }
3547 else
3548   save_stdin()
3549   {
3550     func_check save_stdin = 0 "$@";
3551     cat >"${_TMP_STDIN}";
3552     eval "${return_ok}";
3553   }
3554 fi;
3555
3556
3557 ########################################################################
3558 # special_filespec ()
3559 #
3560 # Handle special modes like whatis and apropos.
3561 #
3562 special_filespec()
3563 {
3564   func_check special_setup '=' 0 "$@";
3565   if obj _OPT_APROPOS is_yes
3566   then
3567     if obj _OPT_WHATIS is_yes
3568     then
3569       error \
3570         'special_setup: $_OPT_APROPOS and $_OPT_WHATIS are both "yes"';
3571     fi;
3572     apropos_filespec;
3573     eval "${return_ok}";
3574   fi;
3575   if obj _OPT_WHATIS is_yes
3576   then
3577     whatis_filespec;
3578   fi;
3579   eval "${return_ok}";
3580 }
3581
3582
3583 ########################################################################
3584 # special_setup ()
3585 #
3586 # Handle special modes like whatis and apropos.
3587 #
3588 special_setup()
3589 {
3590   func_check special_setup '=' 0 "$@";
3591   if obj _OPT_APROPOS is_yes
3592   then
3593     if obj _OPT_WHATIS is_yes
3594     then
3595       error \
3596         'special_setup: $_OPT_APROPOS and $_OPT_WHATIS are both "yes"';
3597     fi;
3598     apropos_setup;
3599     eval "${return_ok}";
3600   fi;
3601   if obj _OPT_WHATIS is_yes
3602   then
3603     whatis_header;
3604   fi;  
3605   eval "${return_ok}";
3606 }
3607
3608
3609 ########################################################################
3610 landmark '11: stack_*()';
3611 ########################################################################
3612
3613 ########################################################################
3614 # string_contains (<string> <part>)
3615 #
3616 # Test whether `part' is contained in `string'.
3617 #
3618 # Arguments : 2 text arguments.
3619 # Return    : `0' if arg2 is substring of arg1, `1' otherwise.
3620 #
3621 string_contains()
3622 {
3623   func_check string_contains '=' 2 "$@";
3624   case "$1" in
3625     *"$2"*)
3626       eval "${return_yes}";
3627       ;;
3628     *)
3629       eval "${return_no}";
3630       ;;
3631   esac;
3632   eval "${return_ok}";
3633 }
3634
3635
3636 ########################################################################
3637 # string_not_contains (<string> <part>)
3638 #
3639 # Test whether `part' is not substring of `string'.
3640 #
3641 # Arguments : 2 text arguments.
3642 # Return    : `0' if arg2 is substring of arg1, `1' otherwise.
3643 #
3644 string_not_contains()
3645 {
3646   func_check string_not_contains '=' 2 "$@";
3647   if string_contains "$1" "$2"
3648   then
3649     eval "${return_no}";
3650   else
3651     eval "${return_yes}";
3652   fi;
3653   eval "${return_ok}";
3654 }
3655
3656
3657 ########################################################################
3658 landmark '12: tmp_*()';
3659 ########################################################################
3660
3661 ########################################################################
3662 # tmp_cat ()
3663 #
3664 # output the temporary cat file (the concatenation of all input)
3665 #
3666 tmp_cat()
3667 {
3668   func_check tmp_cat '=' 0 "$@";
3669   cat "${_TMP_CAT}";
3670   eval "${return_var}" "$?";
3671 }
3672
3673
3674 ########################################################################
3675 # tmp_create (<suffix>?)
3676 #
3677 # Create temporary file.
3678 #
3679 # It's safe to use the shell process ID together with a suffix to
3680 # have multiple temporary files.
3681 #
3682 # Globals: $_TMP_DIR
3683 #
3684 # Output : name of created file
3685 #
3686 # Variable prefix: tc
3687 #
3688 tmp_create()
3689 {
3690   func_check tmp_create '<=' 1 "$@";
3691   # the output file does not have `,' as first character, so these are
3692   # different names from the output file.
3693   tc_tmp="${_TMP_DIR}/,$1";
3694   : >"${tc_tmp}"
3695   obj tc_tmp echo1;
3696   eval ${_UNSET} tc_tmp;
3697   eval "${return_ok}";
3698 }
3699
3700
3701 ########################################################################
3702 # to_tmp (<filename>)
3703 #
3704 # print file (decompressed) to the temporary cat file
3705 #
3706 to_tmp()
3707 {
3708   func_check to_tmp '=' 1 "$@";
3709   if obj _TMP_CAT is_empty
3710   then
3711     error 'to_tmp_line: $_TMP_CAT is not yet set';
3712   fi;
3713   if is_file "$1"
3714   then
3715     if obj _OPT_LOCATION is_yes
3716     then
3717       echo2 "$1";
3718     fi;
3719     if obj _OPT_WHATIS is_yes
3720     then
3721       whatis_filename "$1" >>"${_TMP_CAT}";
3722     else
3723       cat_z "$1" >>"${_TMP_CAT}";
3724     fi;
3725   else
3726     error "to_tmp(): could not read file \`$1'.";
3727   fi;
3728   eval "${return_ok}";
3729 }
3730
3731
3732 ########################################################################
3733 # to_tmp_line ([<text>])
3734 #
3735 # print line to the temporary cat file
3736 #
3737 to_tmp_line()
3738 {
3739   func_check to_tmp '>=' 0 "$@";
3740   if obj _TMP_CAT is_empty
3741   then
3742     error 'to_tmp_line: $_TMP_CAT is not yet set';
3743   fi;
3744   echo1 "$*" >>"${_TMP_CAT}";
3745   eval "${return_ok}";
3746 }
3747
3748
3749 ########################################################################
3750 # trap_set
3751 #
3752 # call function on signal 0
3753 #
3754 trap_set()
3755 {
3756   func_check trap_set '=' 0 "$@";
3757   trap 'clean_up' 0 2>${_NULL_DEV} || :;
3758   eval "${return_ok}";
3759 }
3760
3761
3762 ########################################################################
3763 # trap_unset ()
3764 #
3765 # disable trap on signal 0.
3766 #
3767 trap_unset()
3768 {
3769   func_check trap_unset '=' 0 "$@";
3770   trap '' 0 2>${_NULL_DEV} || :;
3771   eval "${return_ok}";
3772 }
3773
3774
3775 ########################################################################
3776 # usage ()
3777 #
3778 # print usage information to stderr; for groffer option --help.
3779 #
3780 usage()
3781 {
3782   func_check usage = 0 "$@";
3783   echo;
3784   version;
3785   echo1 'Usage: groffer [option]... [filespec]...';
3786   cat <<EOF
3787
3788 Display roff files, standard input, and/or Unix manual pages with a X
3789 Window viewer or in several text modes.  All input is decompressed
3790 on-the-fly with all formats that gzip can handle.
3791
3792 "filespec" is one of
3793   "filename"       name of a readable file
3794   "-"              for standard input
3795   "man:name.n"     man page "name" in section "n"
3796   "man:name"       man page "name" in first section found
3797   "name.n"         man page "name" in section "n"
3798   "name"           man page "name" in first section found
3799 and some more (see groffer(1) for details).
3800
3801 -h --help         print this usage message.
3802 -Q --source       output as roff source.
3803 -T --device=name  pass to groff using output device "name".
3804 -v --version      print version information.
3805 -V                display the groff execution pipe instead of formatting.
3806 -X                display with "gxditview" using groff -X.
3807 -Z --ditroff --intermediate-output
3808                   generate groff intermediate output without
3809                   post-processing and viewing, like groff -Z.
3810 All other short options are interpreted as "groff" formatting options.
3811
3812 The most important groffer long options are
3813
3814 --apropos=name    start man's "apropos" program for "name".
3815 --apropos-data=name
3816                   "apropos" for "name" in man's data sections 4, 5, 7.
3817 --apropos-devel=name
3818                   "apropos" for "name" in development sections 2, 3, 9.
3819 --apropos-progs=name
3820                   "apropos" for "name" in man's program sections 1, 6, 8.
3821 --auto            choose mode automatically from the default mode list.
3822 --default         reset all options to the default value.
3823 --default-modes=mode1,mode2,...
3824                   set sequence of automatically tried modes.
3825 --dvi             display in a viewer for TeX device independent format.
3826 --dvi-viewer=prog choose the viewer program for dvi mode.
3827 --groff           process like groff, disable viewing features.
3828 --help            display this helping output.
3829 --html            display in a web browser.
3830 --html-viewer=program
3831                   choose the web browser for html mode.
3832 --man             check file parameters first whether they are man pages.
3833 --mode=auto|dvi|groff|html|pdf|ps|source|text|tty|www|x|X
3834                   choose display mode.
3835 --no-man          disable man-page facility.
3836 --no-special      disable --all, --apropos*, and --whatis
3837 --pager=program   preset the paging program for tty mode.
3838 --pdf             display in a PDF viewer.
3839 --pdf-viewer=prog choose the viewer program for pdf mode.
3840 --ps              display in a Postscript viewer.
3841 --ps-viewer=prog  choose the viewer program for ps mode.
3842 --shell=program   specify a shell under which to run groffer2.sh.
3843 --text            output in a text device without a pager.
3844 --tty             display with a pager on text terminal even when in X.
3845 --tty-viewer=prog select a pager for tty mode; same as --pager.
3846 --whatis          display the file name and description of man pages
3847 --www             same as --html.
3848 --www-viewer=prog same as --html-viewer
3849 --x --X           display with "gxditview" using an X* device.
3850 --x-viewer=prog   choose viewer program for x mode (X mode).
3851 --X-viewer=prog   same as "--xviewer".
3852
3853 Development options that are not useful for normal usage:
3854 --debug, --debug-all, --debug-keep, --debug-lm, --debug-params,
3855 --debug-shell, --debug-stacks, --debug-tmpdir, --debug-user,
3856 --do-nothing, --print=text
3857
3858 Viewer programs for the different modes that run on the terminal:
3859 --dvi-viewer-tty=prog, --html-viewer-tty=prog, --pdf-viewer-tty=prog,
3860 --ps-viewer-tty=prog, --tty-viewer-tty, --X-viewer-tty=prog,
3861 --x-viewer-tty=prog, --www-viewer-tty=prog
3862
3863 The usual X Windows toolkit options transformed into GNU long options:
3864 --background=color, --bd=size, --bg=color, --bordercolor=color,
3865 --borderwidth=size, --bw=size, --display=Xdisplay, --fg=color,
3866 --fn=font, --font=font, --foreground=color, --geometry=geom, --iconic,
3867 --resolution=dpi, --rv, --title=text, --xrm=resource
3868
3869 Long options of GNU "man":
3870 --all, --ascii, --ditroff, --extension=suffix, --locale=language,
3871 --local-file=name, --location, --manpath=dir1:dir2:...,
3872 --sections=s1:s2:..., --systems=s1,s2,..., --where, ...
3873
3874 EOF
3875   eval "${return_ok}";
3876 }
3877
3878
3879 ########################################################################
3880 # version ()
3881 #
3882 # print version information to stderr
3883 #
3884 version()
3885 {
3886   func_check version = 0 "$@";
3887   echo1 "groffer ${_PROGRAM_VERSION} of ${_LAST_UPDATE}";
3888   # also display groff's version, but not the called subprograms
3889   groff -v 2>&1 | sed -e '/^ *$/q' | sed -e '1s/^/is part of /';
3890   eval "${return_ok}";
3891 }
3892
3893
3894 ########################################################################
3895 # warning (<string>)
3896 #
3897 # Print warning to stderr
3898 #
3899 warning()
3900 {
3901   echo2 "warning: $*";
3902 }
3903
3904
3905 ########################################################################
3906 # whatis_filename (<filename>)
3907 #
3908 # Interpret <filename> as a man page and display its `whatis'
3909 # information as a fragment written in the groff language.
3910 #
3911 # Variable prefix: wf
3912 #
3913 whatis_filename()
3914 {
3915   func_check whatis_filename = 1 "$@";
3916   wf_arg="$1";
3917   if obj wf_arg is_not_file
3918   then
3919     error "whatis_filename(): argument is not a readable file."
3920   fi;
3921   wf_dot='^\.'"${_SPACE_SED}"'*';
3922   if obj _FILESPEC_ARG is_equal '-'
3923   then
3924     wf_arg='stdin';
3925   fi;
3926   cat <<EOF
3927 \f[CR]${wf_arg}\f[]:
3928 .br
3929 EOF
3930
3931   # get the parts of the file name
3932   wf_name="$(base_name $1)";
3933   wf_section="$(echo1 $1 | sed -n -e '
3934 s|^.*/man\('"${_MAN_AUTO_SEC_CHARS}"'\).*$|\1|p
3935 ')";
3936   if obj wf_section is_not_empty
3937   then
3938     case "${wf_name}" in
3939     *.${wf_section}*)
3940       s='yes';
3941       ;;
3942     *)
3943       s='';
3944       wf_section='';
3945       ;;
3946     esac
3947     if obj s is_yes
3948     then
3949       wf_name="$(echo1 ${wf_name} | sed -e '
3950 s/^\(.*\)\.'${wf_section}'.*$/\1/
3951 ')";
3952     fi;
3953   fi;
3954
3955   # traditional man style; grep the line containing `.TH' macro, if any
3956   wf_res="$(cat_z "$1" | sed -e '
3957 /'"${wf_dot}"'TH /p
3958 d
3959 ')";
3960   exit_test;
3961   if obj wf_res is_not_empty
3962   then                          # traditional man style
3963     # get the first line after the first `.SH' macro, by
3964     # - delete up to first .SH;
3965     # - print all lines before the next .SH;
3966     # - quit.
3967     wf_res="$(cat_z "$1" | sed -n -e '
3968 1,/'"${wf_dot}"'SH/d
3969 /'"${wf_dot}"'SH/q
3970 p
3971 ')";
3972
3973     if obj wf_section is_not_empty
3974     then
3975       case "${wf_res}" in
3976       ${wf_name}${_SPACE_CASE}*-${_SPACE_CASE}*)
3977         s='yes';
3978         ;;
3979       *)
3980         s='';
3981         ;;
3982       esac;
3983       if obj s is_yes
3984       then
3985         wf_res="$(obj wf_res echo1 | sed -e '
3986 s/^'"${wf_name}${_SPACE_SED}"'[^-]*-'"${_SPACE_SED}"'*\(.*\)$/'"${wf_name}"' ('"${wf_section}"') \\[em] \1/
3987 ')";
3988       fi;
3989     fi;
3990     obj wf_res echo1;
3991     echo;
3992     eval ${_UNSET} wf_arg;
3993     eval ${_UNSET} wf_dot;
3994     eval ${_UNSET} wf_name;
3995     eval ${_UNSET} wf_res;
3996     eval ${_UNSET} wf_section;
3997     eval "${return_ok}";
3998   fi;
3999
4000   # mdoc style (BSD doc); grep the line containing `.Nd' macro, if any
4001   wf_res="$(cat_z "$1" | sed -n -e '/'"${wf_dot}"'Nd /s///p')";
4002   exit_test;
4003   if obj wf_res is_not_empty
4004   then                          # BSD doc style
4005     if obj wf_section is_not_empty
4006     then
4007       wf_res="$(obj wf_res echo1 | sed -n -e '
4008 s/^\(.*\)$/'"${wf_name}"' ('"${wf_section}"') \\[em] \1/p
4009 ')";
4010     fi;
4011     obj wf_res echo1;
4012     echo;
4013     eval ${_UNSET} wf_arg;
4014     eval ${_UNSET} wf_dot;
4015     eval ${_UNSET} wf_name;
4016     eval ${_UNSET} wf_res;
4017     eval ${_UNSET} wf_section;
4018     eval "${return_ok}";
4019   fi;
4020   echo1 'is not a man page';
4021   echo;
4022   eval ${_UNSET} wf_arg;
4023   eval ${_UNSET} wf_dot;
4024   eval ${_UNSET} wf_name;
4025   eval ${_UNSET} wf_res;
4026   eval ${_UNSET} wf_section;
4027   eval "${return_bad}";
4028 }
4029
4030
4031 ########################################################################
4032 # whatis_filespec ()
4033 #
4034 # Print the filespec name as .SH to the temporary cat file.
4035 #
4036 whatis_filespec()
4037 {
4038   func_check whatis_filespec '=' 0 "$@";
4039   if obj _OPT_WHATIS is_yes
4040   then
4041     eval to_tmp_line \
4042       "'.SH $(echo1 "${_FILESPEC_ARG}" | sed 's/[^\\]-/\\-/g')'";
4043     exit_test;
4044   fi;
4045   eval "${return_ok}";
4046 }
4047
4048
4049 ########################################################################
4050 # whatis_header ()
4051 #
4052 # Print the whatis header to the temporary cat file.
4053 #
4054 whatis_header()
4055 {
4056   func_check whatis_header '=' 0 "$@";
4057   if obj _OPT_WHATIS is_yes
4058   then
4059      to_tmp_line '.TH GROFFER WHATIS';
4060   fi;
4061   eval "${return_ok}";
4062 }
4063
4064
4065 ########################################################################
4066 # where_is (<program>)
4067 #
4068 # Output path of a program if in $PATH.
4069 #
4070 # Arguments : >=1 (empty allowed)
4071 #   more args are ignored, this allows to specify progs with arguments
4072 # Return    : `0' if arg1 is a program in $PATH, `1' otherwise.
4073 #
4074 # Variable prefix: w
4075 #
4076 where_is()
4077 {
4078   func_check where_is '>=' 1 "$@";
4079   w_arg="$1";
4080   if obj w_arg is_empty
4081   then
4082     eval ${_UNSET} w_arg;
4083     eval "${return_bad}";
4084   fi;
4085   case "${w_arg}" in
4086     /*)
4087       eval ${_UNSET} w_arg;
4088       eval ${_UNSET} w_file;
4089       if test -f "${w_arg}" && test -x "${w_arg}"
4090       then
4091         eval "${return_ok}";
4092       else
4093         eval "${return_bad}";
4094       fi;
4095       ;;
4096   esac;
4097   eval set x "$(path_split "${PATH}")";
4098   exit_test;
4099   shift;
4100   for p
4101   do
4102     case "$p" in
4103       */) w_file=${p}${w_arg}; ;;
4104       *)  w_file=${p}/${w_arg}; ;;
4105     esac;
4106     if test -f "${w_file}" && test -x "${w_file}"
4107     then
4108       obj w_file echo1;
4109       eval ${_UNSET} w_arg;
4110       eval ${_UNSET} w_file;
4111       eval "${return_ok}";
4112     fi;
4113   done;
4114   eval ${_UNSET} w_arg;
4115   eval ${_UNSET} w_file;
4116   eval "${return_bad}";
4117 }
4118
4119
4120 ########################################################################
4121 #                        main* Functions
4122 ########################################################################
4123
4124 # The main area contains the following parts:
4125 # - main_init(): initialize temporary files and set exit trap
4126 # - main_parse_MANOPT(): parse $MANOPT
4127 # - main_parse_args(): argument parsing
4128 # - main_set_mode (): determine the display mode
4129 # - main_do_fileargs(): process filespec arguments
4130 # - main_set_resources(): setup X resources
4131 # - main_display(): do the displaying
4132 # - main(): the main function that calls all main_*()
4133
4134
4135 #######################################################################
4136 # main_init ()
4137 #
4138 # set exit trap and create temporary files
4139 #
4140 # Globals: $_TMP_DIR, $_TMP_CAT, $_TMP_STDIN
4141 #
4142 # Variable prefix: mi
4143 #
4144 main_init()
4145 {
4146   func_check main_init = 0 "$@";
4147   # call clean_up() on shell termination.
4148   trap_set;
4149
4150   # create temporary directory
4151   umask 0022;
4152   _TMP_DIR='';
4153   for d in "${GROFF_TMPDIR}" "${TMPDIR}" "${TMP}" "${TEMP}" \
4154            "${TEMPDIR}" "${HOME}"'/tmp' '/tmp' "${HOME}" '.'
4155   do
4156     mi_dir="$d";
4157     if obj mi_dir is_empty || obj mi_dir is_not_dir || \
4158        obj mi_dir is_not_writable
4159     then
4160       continue;
4161     fi;
4162
4163     case "${mi_dir}" in
4164     */)
4165       _TMP_DIR="${mi_dir}";
4166       ;;
4167     *)
4168       _TMP_DIR="${mi_dir}"'/';
4169       ;;
4170     esac;
4171     _TMP_DIR="${_TMP_DIR}groffer${_PROCESS_ID}";
4172     if obj _TMP_DIR rm_tree
4173     then
4174       :
4175     else
4176       mi_tdir_="${_TMP_DIR}"_;
4177       mi_n=1;
4178       mi_tdir_n="${mi_tdir_}${mi_n}";
4179       while obj mi_tdir_n is_existing
4180       do
4181         if obj mi_tdir_n rm_tree
4182         then
4183           # directory could not be removed
4184           mi_n="$(expr "${mi_n}" + 1)";
4185           mi_tdir_n="${mi_tdir_}${mi_n}";
4186           continue;
4187         fi;
4188       done;
4189       _TMP_DIR="${mi_tdir_n}";
4190     fi;
4191     eval mkdir "${_TMP_DIR}";
4192     if is_not_equal "$?" 0
4193     then
4194       obj _TMP_DIR rm_tree;
4195       _TMP_DIR='';
4196       continue;
4197     fi;
4198     if obj _TMP_DIR is_dir && obj _TMP_DIR is_writable
4199     then
4200       # $_TMP_DIR can now be used as temporary directory
4201       break;
4202     fi;
4203     obj _TMP_DIR rm_tree;
4204     _TMP_DIR='';
4205     continue;
4206   done;
4207   if obj _TMP_DIR is_empty
4208   then
4209     error "main_init: \
4210 Couldn't create a directory for storing temporary files.";
4211   fi;
4212   if obj _DEBUG_PRINT_TMPDIR is_yes
4213   then
4214     echo2 "temporary directory: ${_TMP_DIR}";
4215   fi;
4216
4217   _TMP_CAT="$(tmp_create groffer_cat)";
4218   _TMP_STDIN="$(tmp_create groffer_input)";
4219   exit_test;
4220
4221   eval ${_UNSET} mi_dir;
4222   eval ${_UNSET} mi_n;
4223   eval ${_UNSET} mi_tdir_;
4224   eval ${_UNSET} mi_tdir_n;
4225   eval "${return_ok}";
4226 } # main_init()
4227
4228
4229 ########################################################################
4230 # main_parse_MANOPT ()
4231 #
4232 # Parse $MANOPT to retrieve man options, but only if it is a non-empty
4233 # string; found man arguments can be overwritten by the command line.
4234 #
4235 # Globals:
4236 #   in: $MANOPT, $_OPTS_MANOPT_*
4237 #   out: $_MANOPT_*
4238 #
4239 # Variable prefix: mpm
4240 #
4241 main_parse_MANOPT()
4242 {
4243   func_check main_parse_MANOPT = 0 "$@";
4244
4245   if obj MANOPT is_not_empty
4246   then
4247     # Delete leading and final spaces
4248     MANOPT="$(echo1 "${MANOPT}" | sed -e '
4249 s/^'"${_SPACE_SED}"'*//
4250 s/'"${_SPACE_SED}"'*$//
4251 ')";
4252   exit_test;
4253   fi;
4254   if obj MANOPT is_empty
4255   then
4256     eval "${return_ok}";
4257   fi;
4258
4259   mpm_list='';
4260   # add arguments in $MANOPT by mapping them to groffer options
4261   eval set x "$(list_from_cmdline _OPTS_MANOPT "${MANOPT}")";
4262   exit_test;
4263   shift;
4264   until test "$#" -le 0 || is_equal "$1" '--'
4265   do
4266     mpm_opt="$1";
4267     shift;
4268     case "${mpm_opt}" in
4269     -7|--ascii)
4270       list_append mpm_list '--ascii';
4271       ;;
4272     -a|--all)
4273       list_append mpm_list '--all';
4274       ;;
4275     -c|--catman)
4276       do_nothing;
4277       shift;
4278       ;;
4279     -d|--debug)
4280       do_nothing;
4281       ;;
4282     -D|--default)
4283       # undo all man options so far
4284       mpm_list='';
4285       ;;
4286     -e|--extension)
4287       list_append mpm_list '--extension';
4288       shift;
4289       ;;
4290     -f|--whatis)
4291       list_append mpm_list '--whatis';
4292       shift;
4293       ;;
4294     -h|--help)
4295       do_nothing;
4296       shift;
4297       ;;
4298     -k|--apropos)
4299       # groffer's --apropos takes an argument, but man's does not, so
4300       do_nothing;
4301       ;;
4302     -l|--local-file)
4303       do_nothing;
4304       ;;
4305     -L|--locale)
4306       list_append mpm_list '--locale' "$1";
4307       shift;
4308       ;;
4309     -m|--systems)
4310       list_append mpm_list '--systems' "$1";
4311       shift;
4312       ;;
4313     -M|--manpath)
4314       list_append mpm_list '--manpath' "$1";
4315       shift;
4316       ;;
4317     -p|--preprocessor)
4318       do_nothing;
4319       shift;
4320       ;;
4321     -P|--pager)
4322       list_append mpm_list '--pager' "$1";
4323       shift;
4324       ;;
4325     -r|--prompt)
4326       do_nothing;
4327       shift;
4328       ;;
4329     -S|--sections)
4330       list_append mpm_list '--sections' "$1";
4331       shift;
4332       ;;
4333     -t|--troff)
4334       do_nothing;
4335       shift;
4336       ;;
4337     -T|--device)
4338       list_append mpm_list '-T' "$1";
4339       shift;
4340       ;;
4341     -u|--update)
4342       do_nothing;
4343       shift;
4344       ;;
4345     -V|--version)
4346       do_nothing;
4347       ;;
4348     -w|--where|--location)
4349       list_append mpm_list '--location';
4350       ;;
4351     -Z|--ditroff)
4352       do_nothing;
4353       ;;
4354     # ignore all other options
4355     esac;
4356   done;
4357
4358   # prepend $mpm_list to the command line
4359   if obj mpm_list is_not_empty
4360   then
4361     eval set x "${mpm_list}" '"$@"';
4362     shift;
4363   fi;
4364
4365   eval ${_UNSET} mpm_list;
4366   eval ${_UNSET} mpm_opt;
4367   eval "${return_ok}";
4368 } # main_parse_MANOPT()
4369
4370
4371 ########################################################################
4372 # main_parse_args (<command_line_args>*)
4373 #
4374 # Parse arguments; process options and filespec parameters
4375 #
4376 # Arguments: pass the command line arguments unaltered.
4377 # Globals:
4378 #   in:  $_OPTS_*
4379 #   out: $_OPT_*, $_ADDOPTS, $_FILEARGS
4380 #
4381 # Variable prefix: mpa
4382 #
4383 main_parse_args()
4384 {
4385   func_check main_parse_args '>=' 0 "$@";
4386   _ALL_PARAMS="$(list_from_cmdline _OPTS_CMDLINE "$@")";
4387   exit_test;
4388   if obj _DEBUG_PRINT_PARAMS is_yes
4389   then
4390     echo2 "parameters: ${_ALL_PARAMS}";
4391   fi;
4392   eval set x "${_ALL_PARAMS}";
4393   shift;
4394
4395   # By the call of `eval', unnecessary quoting was removed.  So the
4396   # positional shell parameters ($1, $2, ...) are now guaranteed to
4397   # represent an option or an argument to the previous option, if any;
4398   # then a `--' argument for separating options and
4399   # parameters; followed by the filespec parameters if any.
4400
4401   # Note, the existence of arguments to options has already been checked.
4402   # So a check for `$#' or `--' should not be done for arguments.
4403
4404   until test "$#" -le 0 || is_equal "$1" '--'
4405   do
4406     mpa_opt="$1";               # $mpa_opt is fed into the option handler
4407     shift;
4408     case "${mpa_opt}" in
4409     -h|--help)
4410       usage;
4411       leave;
4412       ;;
4413     -Q|--source)                # output source code (`Quellcode').
4414       _OPT_MODE='source';
4415       ;;
4416     -T|--device|--troff-device) # device; arg
4417       _OPT_DEVICE="$1";
4418       _check_device_with_mode;
4419       shift;
4420       ;;
4421     -v|--version)
4422       version;
4423       leave;
4424       ;;
4425     -V)
4426       _OPT_V='yes';
4427       ;;
4428     -Z|--ditroff|--intermediate-output) # groff intermediate output
4429       _OPT_Z='yes';
4430       ;;
4431     -X)
4432       if is_X
4433       then
4434         _OPT_MODE=X;
4435       fi;
4436       ;;
4437     -?)
4438       # delete leading `-'
4439       mpa_optchar="$(echo1 "${mpa_opt}" | sed -e 's/^-//')";
4440       exit_test;
4441       if list_has _OPTS_GROFF_SHORT_NA "${mpa_optchar}"
4442       then
4443         list_append _ADDOPTS_GROFF "${mpa_opt}";
4444       elif list_has _OPTS_GROFF_SHORT_ARG "${mpa_optchar}"
4445       then
4446         list_append _ADDOPTS_GROFF "${mpa_opt}" "$1";
4447         shift;
4448       else
4449         error "main_parse_args(): Unknown option : \`$1'";
4450       fi;
4451       ;;
4452     --all)
4453         _OPT_ALL='yes';
4454         ;;
4455     --apropos)                  # run `apropos'
4456       _OPT_APROPOS='yes';
4457       _APROPOS_SECTIONS='';
4458       _OPT_WHATIS='no';
4459       ;;
4460     --apropos-data)             # run `apropos' for data sections
4461       _OPT_APROPOS='yes';
4462       _APROPOS_SECTIONS='457';
4463       _OPT_WHATIS='no';
4464       ;;
4465     --apropos-devel)            # run `apropos' for development sections
4466       _OPT_APROPOS='yes';
4467       _APROPOS_SECTIONS='239';
4468       _OPT_WHATIS='no';
4469       ;;
4470     --apropos-progs)            # run `apropos' for program sections
4471       _OPT_APROPOS='yes';
4472       _APROPOS_SECTIONS='168';
4473       _OPT_WHATIS='no';
4474       ;;
4475     --ascii)
4476       list_append _ADDOPTS_GROFF '-mtty-char';
4477       if obj _OPT_MODE is_empty
4478       then
4479         _OPT_MODE='text';
4480       fi;
4481       ;;
4482     --auto)                     # the default automatic mode
4483       _OPT_MODE='';
4484       ;;
4485     --bd)                       # border color for viewers, arg;
4486       _OPT_BD="$1";
4487       shift;
4488       ;;
4489     --bg|--backgroud)           # background color for viewers, arg;
4490       _OPT_BG="$1";
4491       shift;
4492       ;;
4493     --bw)                       # border width for viewers, arg;
4494       _OPT_BW="$1";
4495       shift;
4496       ;;
4497     --debug|--debug-all|--debug-keep|--debug-lm|--debug-params|\
4498 --debug-shell|--debug-stacks|--debug-tmpdir|--debug-user)
4499       # debug is handled at the beginning
4500       :;
4501       ;;
4502     --default)                  # reset variables to default
4503       reset;
4504       ;;
4505     --default-modes)            # sequence of modes in auto mode; arg
4506       _OPT_DEFAULT_MODES="$1";
4507       shift;
4508       ;;
4509     --display)                  # set X display, arg
4510       _OPT_DISPLAY="$1";
4511       shift;
4512       ;;
4513     --do-nothing)
4514       _OPT_DO_NOTHING='yes';
4515       ;;
4516     --dvi)
4517       if is_X
4518       then
4519         _OPT_MODE='dvi';
4520       fi;
4521       ;;
4522     --dvi-viewer)               # viewer program for dvi mode; arg
4523       _VIEWER_TERMINAL='no';
4524       _OPT_VIEWER_DVI="$1";
4525       shift;
4526       ;;
4527     --dvi-viewer-tty)           # viewer program for dvi mode in tty; arg
4528       _VIEWER_TERMINAL='yes';
4529       _OPT_VIEWER_DVI="$1";
4530       shift;
4531       ;;
4532     --extension)                # the extension for man pages, arg
4533       _OPT_EXTENSION="$1";
4534       shift;
4535       ;;
4536     --fg|--foreground)          # foreground color for viewers, arg;
4537       _OPT_FG="$1";
4538       shift;
4539       ;;
4540     --fn|--font)                # set font for viewers, arg;
4541       _OPT_FN="$1";
4542       shift;
4543       ;;
4544     --geometry)                 # window geometry for viewers, arg;
4545       _OPT_GEOMETRY="$1";
4546       shift;
4547       ;;
4548     --groff)
4549       _OPT_MODE='groff';
4550       ;;
4551     --html|--www)               # display with web browser
4552       _OPT_MODE=html;
4553       ;;
4554     --html-viewer|--www-viewer) # viewer program for html mode; arg
4555       _VIEWER_TERMINAL='no';
4556       _OPT_VIEWER_HTML="$1";
4557       shift;
4558       ;;
4559     --html-viewer-tty|--www-viewer-tty) # viewer for html mode in tty; arg
4560       _VIEWER_TERMINAL='yes';
4561       _OPT_VIEWER_HTML="$1";
4562       shift;
4563       ;;
4564     --iconic)                   # start viewers as icons
4565       _OPT_ICONIC='yes';
4566       ;;
4567     --locale)                   # set language for man pages, arg
4568       # argument is xx[_territory[.codeset[@modifier]]] (ISO 639,...)
4569       _OPT_LANG="$1";
4570       shift;
4571       ;;
4572     --local-file)               # force local files; same as `--no-man'
4573       _MAN_FORCE='no';
4574       _MAN_ENABLE='no';
4575       ;;
4576     --location|--where)         # print file locations to stderr
4577       _OPT_LOCATION='yes';
4578       ;;
4579     --man)                     # force all file params to be man pages
4580       _MAN_ENABLE='yes';
4581       _MAN_FORCE='yes';
4582       ;;
4583     --manpath)                # specify search path for man pages, arg
4584       # arg is colon-separated list of directories
4585       _OPT_MANPATH="$1";
4586       shift;
4587       ;;
4588     --mode)                     # display mode
4589       mpa_arg="$1";
4590       shift;
4591       case "${mpa_arg}" in
4592       auto|'')               # search mode automatically among default
4593         _OPT_MODE='';
4594         ;;
4595       groff)                    # pass input to plain groff
4596         _OPT_MODE='groff';
4597         ;;
4598       html|www)                 # display with a web browser
4599         _OPT_MODE='html';
4600         ;;
4601       dvi)                      # display with xdvi viewer
4602         if is_X
4603         then
4604           _OPT_MODE='dvi';
4605         fi;
4606         ;;
4607       pdf)                      # display with PDF viewer
4608         if is_X
4609         then
4610           _OPT_MODE='pdf';
4611         fi;
4612         ;;
4613       ps)                       # display with Postscript viewer
4614         if is_X
4615         then
4616           _OPT_MODE='ps';
4617         fi;
4618         ;;
4619       text)                     # output on terminal
4620         _OPT_MODE='text';
4621         ;;
4622       tty)                      # output on terminal
4623         _OPT_MODE='tty';
4624         ;;
4625       X|x)                      # output on X roff viewer
4626         if is_X
4627         then
4628           _OPT_MODE='x';
4629         fi;
4630         ;;
4631       Q|source)                 # display source code
4632         _OPT_MODE="source";
4633         ;;
4634       *)
4635         error "main_parse_args(): unknown mode ${mpa_arg}";
4636         ;;
4637       esac;
4638       ;;
4639     --no-location)              # disable former call to `--location'
4640       _OPT_LOCATION='yes';
4641       ;;
4642     --no-man)                   # disable search for man pages
4643       # the same as --local-file
4644       _MAN_FORCE='no';
4645       _MAN_ENABLE='no';
4646       ;;
4647     --no-special)               # disable some special former calls
4648       _OPT_ALL='no'
4649       _OPT_APROPOS='no'
4650       _OPT_WHATIS='no'
4651       ;;
4652     --pager|--tty-viewer|--tty-viewer-tty)
4653       # set paging program for tty mode, arg
4654       _VIEWER_TERMINAL='yes';
4655       _OPT_PAGER="$1";
4656       shift;
4657       ;;
4658     --pdf)
4659       if is_X
4660       then
4661         _OPT_MODE='pdf';
4662       fi;
4663       ;;
4664     --pdf-viewer)               # viewer program for ps mode; arg
4665       _VIEWER_TERMINAL='no';
4666       _OPT_VIEWER_PDF="$1";
4667       shift;
4668       ;;
4669     --pdf-viewer-tty)           # viewer program for ps mode in tty; arg
4670       _VIEWER_TERMINAL='yes';
4671       _OPT_VIEWER_PDF="$1";
4672       shift;
4673       ;;
4674     --print)                    # for argument test
4675       echo2 "$1";
4676       shift;
4677       ;;
4678     --ps)
4679       if is_X
4680       then
4681         _OPT_MODE='ps';
4682       fi;
4683       ;;
4684     --ps-viewer)                # viewer program for ps mode; arg
4685       _VIEWER_TERMINAL='no';
4686       _OPT_VIEWER_PS="$1";
4687       shift;
4688       ;;
4689     --ps-viewer-tty)            # viewer program for ps mode in tty; arg
4690       _VIEWER_TERMINAL='yes';
4691       _OPT_VIEWER_PS="$1";
4692       shift;
4693       ;;
4694     --resolution)               # set resolution for X devices, arg
4695       mpa_arg="$1";
4696       shift;
4697       case "${mpa_arg}" in
4698       75|75dpi)
4699         mpa_dpi=75;
4700         ;;
4701       100|100dpi)
4702         mpa_dpi=100;
4703         ;;
4704       *)
4705         error "main_parse_args(): \
4706 only resoutions of 75 or 100 dpi are supported";
4707         ;;
4708       esac;
4709       _OPT_RESOLUTION="${mpa_dpi}";
4710       ;;
4711     --rv)
4712       _OPT_RV='yes';
4713       ;;
4714     --sections)                 # specify sections for man pages, arg
4715       # arg is colon-separated list of section names
4716       _OPT_SECTIONS="$1";
4717       shift;
4718       ;;
4719     --shell)
4720       # already done during the first run; so ignore the argument
4721       shift;
4722       ;;
4723     --systems)                  # man pages for different OS's, arg
4724       # argument is a comma-separated list
4725       _OPT_SYSTEMS="$1";
4726       shift;
4727       ;;
4728     --text)                     # text mode without pager
4729       _OPT_MODE=text;
4730       ;;
4731     --title)                    # title for X viewers; arg
4732       _OPT_TITLE="$1";
4733       shift;
4734       ;;
4735     --tty)                      # tty mode, text with pager
4736       _OPT_MODE=tty;
4737       ;;
4738     --text-device|--tty-device) # device for tty mode; arg
4739       _OPT_TEXT_DEVICE="$1";
4740       shift;
4741       ;;
4742     --whatis)
4743       _OPT_WHATIS='yes';
4744       _OPT_ALL='yes';
4745       _OPT_APROPOS='no';
4746       ;;
4747     --X|--x)
4748       if is_X
4749       then
4750         _OPT_MODE=x;
4751       fi;
4752       ;;
4753     --xrm)                      # pass X resource string, arg;
4754       list_append _OPT_XRM "$1";
4755       shift;
4756       ;;
4757     --x-viewer|--X-viewer)      # viewer program for x mode; arg
4758       _VIEWER_TERMINAL='no';
4759       _OPT_VIEWER_X="$1";
4760       shift;
4761       ;;
4762     --x-viewer-tty|--X-viewer-tty) # viewer program for x mode in tty; arg
4763       _VIEWER_TERMINAL='yes';
4764       _OPT_VIEWER_X="$1";
4765       shift;
4766       ;;
4767     *)
4768       error 'main_parse_args(): error on argument parsing : '"\`$*'";
4769       ;;
4770     esac;
4771   done;
4772   shift;                        # remove `--' argument
4773
4774   if obj _OPT_DO_NOTHING is_yes
4775   then
4776     leave;
4777   fi;
4778
4779   # Remaining arguments are file names (filespecs).
4780   # Save them to list $_FILEARGS
4781   if is_equal "$#" 0
4782   then                          # use "-" for standard input
4783     set x '-';
4784     shift;
4785   fi;
4786   _FILEARGS='';
4787   list_append _FILEARGS "$@";
4788   if list_has _FILEARGS '-'
4789   then
4790     save_stdin;
4791   fi;
4792   # $_FILEARGS must be retrieved with `eval set x "$_FILEARGS"; shift;'
4793   eval ${_UNSET} mpa_arg;
4794   eval ${_UNSET} mpa_dpi;
4795   eval ${_UNSET} mpa_opt;
4796   eval ${_UNSET} mpa_optchar;
4797   eval "${return_ok}";
4798 } # main_parse_args()
4799
4800
4801 # Called from main_parse_args() because double `case' is not possible.
4802 # Globals: $_OPT_DEVICE, $_OPT_MODE
4803 _check_device_with_mode()
4804 {
4805   func_check _check_device_with_mode = 0 "$@";
4806   case "${_OPT_DEVICE}" in
4807   dvi)
4808     _OPT_MODE=dvi;
4809     eval "${return_ok}";
4810     ;;
4811   html)
4812     _OPT_MODE=html;
4813     eval "${return_ok}";
4814     ;;
4815   lbp|lj4)
4816     _OPT_MODE=groff;
4817     eval "${return_ok}";
4818     ;;
4819   ps)
4820     _OPT_MODE=ps;
4821     eval "${return_ok}";
4822     ;;
4823   ascii|cp1047|latin1|utf8)
4824     if obj _OPT_MODE is_not_equal text
4825     then
4826       _OPT_MODE=tty;            # default text mode
4827     fi;
4828     eval "${return_ok}";
4829     ;;
4830   X*)
4831     _OPT_MODE=x;
4832     eval "${return_ok}";
4833     ;;
4834   *)                            # unknown device, go to groff mode
4835     _OPT_MODE=groff;
4836     eval "${return_ok}";
4837     ;;
4838   esac;
4839   eval "${return_error}";
4840 } # _check_device_with_mode() of main_parse_args()
4841
4842
4843 ########################################################################
4844 # main_set_mode ()
4845 #
4846 # Determine the display mode.
4847 #
4848 # Globals:
4849 #   in:  $DISPLAY, $_OPT_MODE, $_OPT_DEVICE
4850 #   out: $_DISPLAY_MODE
4851 #
4852 # Variable prefix: msm
4853 #
4854 main_set_mode()
4855 {
4856   func_check main_set_mode = 0 "$@";
4857
4858   # set display
4859   if obj _OPT_DISPLAY is_not_empty
4860   then
4861     DISPLAY="${_OPT_DISPLAY}";
4862   fi;
4863
4864   if obj _OPT_V is_yes
4865   then
4866     list_append _ADDOPTS_GROFF '-V';
4867   fi;
4868   if obj _OPT_Z is_yes
4869   then
4870     _DISPLAY_MODE='groff';
4871     list_append _ADDOPTS_GROFF '-Z';
4872   fi;
4873   if obj _OPT_MODE is_equal 'groff'
4874   then
4875     _DISPLAY_MODE='groff';
4876   fi;
4877   if obj _DISPLAY_MODE is_equal 'groff'
4878   then
4879     eval ${_UNSET} msm_modes;
4880     eval ${_UNSET} msm_viewer;
4881     eval ${_UNSET} msm_viewers;
4882     eval "${return_ok}";
4883   fi;
4884
4885   if obj _OPT_MODE is_equal 'source'
4886   then
4887     _DISPLAY_MODE='source';
4888     eval ${_UNSET} msm_modes;
4889     eval ${_UNSET} msm_viewer;
4890     eval ${_UNSET} msm_viewers;
4891     eval "${return_ok}";
4892   fi;
4893
4894   case "${_OPT_MODE}" in
4895   '')                           # automatic mode
4896     case "${_OPT_DEVICE}" in
4897     X*)
4898      if is_not_X
4899       then
4900         error_user "no X display found for device ${_OPT_DEVICE}";
4901       fi;
4902       _DISPLAY_MODE='x';
4903       eval ${_UNSET} msm_modes;
4904       eval ${_UNSET} msm_viewer;
4905       eval ${_UNSET} msm_viewers;
4906       eval "${return_ok}";
4907       ;;
4908     ascii|cp1047|latin1|utf8)
4909       if obj _DISPLAY_MODE is_not_equal 'text'
4910       then
4911         _DISPLAY_MODE='tty';
4912       fi;
4913       eval ${_UNSET} msm_modes;
4914       eval ${_UNSET} msm_viewer;
4915       eval ${_UNSET} msm_viewers;
4916       eval "${return_ok}";
4917       ;;
4918     esac;
4919     if is_not_X
4920     then
4921       _DISPLAY_MODE='tty';
4922       eval ${_UNSET} msm_modes;
4923       eval ${_UNSET} msm_viewer;
4924       eval ${_UNSET} msm_viewers;
4925       eval "${return_ok}";
4926     fi;
4927
4928     if obj _OPT_DEFAULT_MODES is_empty
4929     then
4930       msm_modes="${_DEFAULT_MODES}";
4931     else
4932       msm_modes="${_OPT_DEFAULT_MODES}";
4933     fi;
4934     ;;
4935   text)
4936     _DISPLAY_MODE='text';
4937     eval ${_UNSET} msm_modes;
4938     eval ${_UNSET} msm_viewer;
4939     eval ${_UNSET} msm_viewers;
4940     eval "${return_ok}";
4941     ;;
4942   tty)
4943     _DISPLAY_MODE='tty';
4944     eval ${_UNSET} msm_modes;
4945     eval ${_UNSET} msm_viewer;
4946     eval ${_UNSET} msm_viewers;
4947     eval "${return_ok}";
4948     ;;
4949   html)
4950     _DISPLAY_MODE='html';
4951     msm_modes="${_OPT_MODE}";
4952     ;;
4953   *)                            # display mode was given
4954     if is_not_X
4955     then
4956       error_user "You must be in X Window for ${_OPT_MODE} mode.";
4957     fi;
4958     msm_modes="${_OPT_MODE}";
4959     ;;
4960   esac;
4961
4962   # only viewer modes are left
4963   eval set x "$(list_from_split "${msm_modes}" ',')";
4964   exit_test;
4965   shift;
4966   while test "$#" -gt 0
4967   do
4968     m="$1";
4969     shift;
4970     case "$m" in
4971     dvi)
4972       if obj _OPT_VIEWER_DVI is_not_empty
4973       then
4974         msm_viewer="${_OPT_VIEWER_DVI}";
4975       else
4976         msm_viewer="$(_get_first_prog "$_VIEWER_DVI}")";
4977         exit_test;
4978       fi;
4979       if obj msm_viewer is_empty
4980       then
4981         error 'No viewer for dvi mode available.';
4982       fi;
4983       if is_not_equal "$?" 0
4984       then
4985         continue;
4986       fi;
4987       _DISPLAY_PROG="${msm_viewer}";
4988       _DISPLAY_MODE="dvi";
4989       eval ${_UNSET} msm_modes;
4990       eval ${_UNSET} msm_viewer;
4991       eval ${_UNSET} msm_viewers;
4992       eval "${return_ok}";
4993       ;;
4994     html)
4995       if obj _OPT_VIEWER_HTML is_not_empty
4996       then
4997         msm_viewer="${_OPT_VIEWER_HTML}";
4998       else
4999         if is_X
5000         then
5001           msm_viewers="${_VIEWER_HTML_X}";
5002         else
5003           msm_viewers="${_VIEWER_HTML_TTY}";
5004         fi;
5005         msm_viewer="$(_get_first_prog "${msm_viewers}")";
5006         exit_test;
5007       fi;
5008       if obj msm_viewer is_empty
5009       then
5010         error 'No viewer for html mode available.';
5011       fi;
5012       if is_not_equal "$?" 0
5013       then
5014         continue;
5015       fi;
5016       _DISPLAY_PROG="${msm_viewer}";
5017       _DISPLAY_MODE=html;
5018       eval ${_UNSET} msm_modes;
5019       eval ${_UNSET} msm_viewer;
5020       eval ${_UNSET} msm_viewers;
5021       eval "${return_ok}";
5022       ;;
5023     pdf)
5024       if obj _OPT_VIEWER_PDF is_not_empty
5025       then
5026         msm_viewer="${_OPT_VIEWER_PDF}";
5027       else
5028         msm_viewer="$(_get_first_prog "${_VIEWER_PDF}")";
5029         exit_test;
5030       fi;
5031       if obj msm_viewer is_empty
5032       then
5033         error 'No viewer for pdf mode available.';
5034       fi;
5035       if is_not_equal "$?" 0
5036       then
5037         continue;
5038       fi;
5039       _DISPLAY_PROG="${msm_viewer}";
5040       _DISPLAY_MODE="pdf";
5041       eval ${_UNSET} msm_modes;
5042       eval ${_UNSET} msm_viewer;
5043       eval ${_UNSET} msm_viewers;
5044       eval "${return_ok}";
5045       ;;
5046     ps)
5047       if obj _OPT_VIEWER_PS is_not_empty
5048       then
5049         msm_viewer="${_OPT_VIEWER_PS}";
5050       else
5051         msm_viewer="$(_get_first_prog "${_VIEWER_PS}")";
5052         exit_test;
5053       fi;
5054       if obj msm_viewer is_empty
5055       then
5056         error 'No viewer for ps mode available.';
5057       fi;
5058       if is_not_equal "$?" 0
5059       then
5060         continue;
5061       fi;
5062       _DISPLAY_PROG="${msm_viewer}";
5063       _DISPLAY_MODE="ps";
5064      eval ${_UNSET} msm_modes;
5065       eval ${_UNSET} msm_viewer;
5066       eval ${_UNSET} msm_viewers;
5067       eval "${return_ok}";
5068       ;;
5069     text)
5070       _DISPLAY_MODE='text';
5071       eval ${_UNSET} msm_modes;
5072       eval ${_UNSET} msm_viewer;
5073       eval ${_UNSET} msm_viewers;
5074       eval "${return_ok}";
5075       ;;
5076     tty)
5077       _DISPLAY_MODE='tty';
5078       eval ${_UNSET} msm_modes;
5079       eval ${_UNSET} msm_viewer;
5080       eval ${_UNSET} msm_viewers;
5081       eval "${return_ok}";
5082       ;;
5083     x)
5084       if obj _OPT_VIEWER_X is_not_empty
5085       then
5086         msm_viewer="${_OPT_VIEWER_X}";
5087       else
5088         msm_viewer="$(_get_first_prog "${_VIEWER_X}")";
5089         exit_test;
5090       fi;
5091       if obj msm_viewer is_empty
5092       then
5093         error 'No viewer for x mode available.';
5094       fi;
5095       if is_not_equal "$?" 0
5096       then
5097         continue;
5098       fi;
5099       _DISPLAY_PROG="${msm_viewer}";
5100       _DISPLAY_MODE='x';
5101       eval ${_UNSET} msm_modes;
5102       eval ${_UNSET} msm_viewer;
5103       eval ${_UNSET} msm_viewers;
5104       eval "${return_ok}";
5105       ;;
5106     X)
5107       _DISPLAY_MODE='X';
5108       eval ${_UNSET} msm_modes;
5109       eval ${_UNSET} msm_viewer;
5110       eval ${_UNSET} msm_viewers;
5111       eval "${return_ok}";
5112       ;;
5113     esac;
5114   done;
5115   eval ${_UNSET} msm_modes;
5116   eval ${_UNSET} msm_viewer;
5117   eval ${_UNSET} msm_viewers;
5118   error_user "No suitable display mode found.";
5119 } # main_set_mode()
5120
5121
5122 # _get_first_prog (<proglist>)
5123 #
5124 # Retrieve first argument that represents an existing program in $PATH.
5125 # Local function for main_set_mode().
5126 #
5127 # Arguments: 1; a comma-separated list of commands (with options),
5128 #               like $_VIEWER_*.
5129 #
5130 # Return  : `1' if none found, `0' if found.
5131 # Output  : the argument that succeded.
5132 #
5133 # Variable prefix: _gfp
5134 #
5135 _get_first_prog()
5136 {
5137   if is_equal "$#" 0
5138   then
5139     error "_get_first_prog() needs 1 argument.";
5140   fi;
5141   if is_empty "$1"
5142   then
5143     return "${_BAD}";
5144   fi;
5145   eval set x "$(list_from_split "$1" ',')";
5146   exit_test;
5147   shift;
5148   for i
5149   do
5150     _gfp_i="$i";
5151     if obj _gfp_i is_empty
5152     then
5153       continue;
5154     fi;
5155     if eval is_prog "$(get_first_essential ${_gfp_i})"
5156     then
5157       exit_test;
5158       obj _gfp_i echo1;
5159       eval ${_UNSET} _gfp_i;
5160       return "${_GOOD}";
5161     fi;
5162   done;
5163   eval ${_UNSET} _gfp_i;
5164   return "${_BAD}";
5165 } # _get_first_prog() of main_set_mode()
5166
5167
5168 #######################################################################
5169 # main_do_fileargs ()
5170 #
5171 # Process filespec arguments in $_FILEARGS.
5172 #
5173 # Globals:
5174 #   in: $_FILEARGS (process with `eval set x "$_FILEARGS"; shift;')
5175 #
5176 # Variable prefix: mdfa
5177 #
5178 main_do_fileargs()
5179 {
5180   func_check main_do_fileargs = 0 "$@";
5181   special_setup;
5182   eval set x "${_FILEARGS}";
5183   shift;
5184   eval ${_UNSET} _FILEARGS;
5185   # temporary storage of all input to $_TMP_CAT
5186   while test "$#" -ge 2
5187   do
5188     # test for `s name' arguments, with `s' a 1-char standard section
5189     mdfa_filespec="$1";
5190     _FILESPEC_ARG="$1";
5191     shift;
5192     case "${mdfa_filespec}" in
5193     '')
5194       continue;
5195       ;;
5196     '-')
5197       special_filespec;
5198       if obj _OPT_APROPOS is_yes
5199       then
5200         continue;
5201       fi;
5202       register_file '-'
5203       continue;
5204       ;;
5205     ?)
5206       if obj _OPT_APROPOS is_yes
5207       then
5208         special_filespec;
5209         continue;
5210       fi;
5211       if list_has_not _MAN_AUTO_SEC_LIST "${mdfa_filespec}"
5212       then
5213         special_filespec;
5214         do_filearg "${mdfa_filespec}"
5215         continue;
5216       fi;
5217       mdfa_name="$1";
5218       _FILESPEC_ARG="${_FILESPEC_ARG} $1";
5219       special_filespec;
5220       case "${mdfa_name}" in
5221       */*|man:*|*\(*\)|*."${mdfa_filespec}")
5222         do_filearg "${mdfa_filespec}"
5223         continue;
5224         ;;
5225       esac;
5226       shift;
5227       if do_filearg "man:${mdfa_name}(${mdfa_filespec})"
5228       then
5229         continue;
5230       else
5231         do_filearg "${mdfa_filespec}"
5232         continue;
5233       fi;
5234       ;;
5235     *)
5236       special_filespec;
5237       if obj _OPT_APROPOS is_yes
5238       then
5239         continue;
5240       fi;
5241       do_filearg "${mdfa_filespec}"
5242       continue;
5243       ;;
5244     esac;
5245   done;                         # end of `s name' test
5246   while test "$#" -gt 0
5247   do
5248     mdfa_filespec="$1";
5249     _FILESPEC_ARG="$1";
5250     shift;
5251     special_filespec;
5252     if obj _OPT_APROPOS is_yes
5253     then
5254       continue;
5255     fi;
5256     do_filearg "${mdfa_filespec}"
5257   done;
5258   obj _TMP_STDIN rm_file_with_debug;
5259   eval ${_UNSET} mdfa_filespec;
5260   eval ${_UNSET} mdfa_name;
5261   eval "${return_ok}";
5262 } # main_do_fileargs()
5263
5264
5265 ########################################################################
5266 # main_set_resources ()
5267 #
5268 # Determine options for setting X resources with $_DISPLAY_PROG.
5269 #
5270 # Globals: $_DISPLAY_PROG, $_OUTPUT_FILE_NAME
5271 #
5272 # Variable prefix: msr
5273 #
5274 main_set_resources()
5275 {
5276   func_check main_set_resources = 0 "$@";
5277   # $msr_prog   viewer program
5278   # $msr_rl     resource list
5279   msr_title="$(get_first_essential \
5280                  "${_OPT_TITLE}" "${_REGISTERED_TITLE}")";
5281   exit_test;
5282   _OUTPUT_FILE_NAME='';
5283   eval set x "${msr_title}";
5284   shift;
5285   until is_equal "$#" 0
5286   do
5287     msr_n="$1";
5288     case "${msr_n}" in
5289     '')
5290       continue;
5291       ;;
5292     ,*)
5293       msr_n="$(echo1 "$1" | sed -e 's/^,,*//')";
5294       exit_test;
5295       ;;
5296     esac
5297     if obj msr_n is_empty
5298     then
5299       continue;
5300     fi;
5301     if obj _OUTPUT_FILE_NAME is_not_empty
5302     then
5303       _OUTPUT_FILE_NAME="${_OUTPUT_FILE_NAME}"',';
5304     fi;
5305     _OUTPUT_FILE_NAME="${_OUTPUT_FILE_NAME}${msr_n}";
5306     shift;
5307   done;
5308   case "${_OUTPUT_FILE_NAME}" in
5309   '')
5310     _OUTPUT_FILE_NAME='-';
5311     ;;
5312   ,*)
5313     error "main_set_resources(): ${_OUTPUT_FILE_NAME} starts with a comma.";
5314     ;;
5315   esac;
5316   _OUTPUT_FILE_NAME="${_TMP_DIR}/${_OUTPUT_FILE_NAME}";
5317
5318   if obj _DISPLAY_PROG is_empty
5319   then                          # for example, for groff mode
5320     _DISPLAY_ARGS='';
5321     eval ${_UNSET} msr_n;
5322     eval ${_UNSET} msr_prog;
5323     eval ${_UNSET} msr_rl;
5324     eval ${_UNSET} msr_title;
5325     eval "${return_ok}";
5326   fi;
5327
5328   eval set x "${_DISPLAY_PROG}";
5329   shift;
5330   msr_prog="$(base_name "$1")";
5331   exit_test;
5332   shift;
5333   if test $# != 0
5334   then
5335     if obj _DISPLAY_PROG is_empty
5336     then
5337       _DISPLAY_ARGS="$*";
5338     else
5339       _DISPLAY_ARGS="$* ${_DISPLAY_ARGS}";
5340     fi;
5341   fi;
5342   msr_rl='';
5343   if obj _OPT_BD is_not_empty
5344   then
5345     case "${msr_prog}" in
5346     ghostview|gv|gxditview|xditview|xdvi)
5347       list_append msr_rl '-bd' "${_OPT_BD}";
5348       ;;
5349     esac;
5350   fi;
5351   if obj _OPT_BG is_not_empty
5352   then
5353     case "${msr_prog}" in
5354     ghostview|gv|gxditview|xditview|xdvi)
5355       list_append msr_rl '-bg' "${_OPT_BG}";
5356       ;;
5357     kghostview)
5358       list_append msr_rl '--bg' "${_OPT_BG}";
5359       ;;
5360     xpdf)
5361       list_append msr_rl '-papercolor' "${_OPT_BG}";
5362       ;;
5363     esac;
5364   fi;
5365   if obj _OPT_BW is_not_empty
5366   then
5367     case "${msr_prog}" in
5368     ghostview|gv|gxditview|xditview|xdvi)
5369       _list_append msr_rl '-bw' "${_OPT_BW}";
5370       ;;
5371     esac;
5372   fi;
5373   if obj _OPT_FG is_not_empty
5374   then
5375     case "${msr_prog}" in
5376     ghostview|gv|gxditview|xditview|xdvi)
5377       list_append msr_rl '-fg' "${_OPT_FG}";
5378       ;;
5379     kghostview)
5380       list_append msr_rl '--fg' "${_OPT_FG}";
5381       ;;
5382     esac;
5383   fi;
5384   if is_not_empty "${_OPT_FN}"
5385   then
5386     case "${msr_prog}" in
5387     ghostview|gv|gxditview|xditview|xdvi)
5388       list_append msr_rl '-fn' "${_OPT_FN}";
5389       ;;
5390     kghostview)
5391       list_append msr_rl '--fn' "${_OPT_FN}";
5392       ;;
5393     esac;
5394   fi;
5395   if is_not_empty "${_OPT_GEOMETRY}"
5396   then
5397     case "${msr_prog}" in
5398     ghostview|gv|gxditview|xditview|xdvi|xpdf)
5399       list_append msr_rl '-geometry' "${_OPT_GEOMETRY}";
5400       ;;
5401     kghostview)
5402       list_append msr_rl '--geometry' "${_OPT_GEOMETRY}";
5403       ;;
5404     esac;
5405   fi;
5406   if is_empty "${_OPT_RESOLUTION}"
5407   then
5408     _OPT_RESOLUTION="${_DEFAULT_RESOLUTION}";
5409     case "${msr_prog}" in
5410     gxditview|xditview)
5411       list_append msr_rl '-resolution' "${_DEFAULT_RESOLUTION}";
5412       ;;
5413     xpdf)
5414       case "${_DEFAULT_RESOLUTION}" in
5415       75)
5416         # 72dpi is '100'
5417         list_append msr_rl '-z' '104';
5418         ;;
5419       100)
5420         list_append msr_rl '-z' '139';
5421         ;;
5422       esac;
5423       ;;
5424     esac;
5425   else
5426     case "${msr_prog}" in
5427     ghostview|gv|gxditview|xditview|xdvi)
5428       list_append msr_rl '-resolution' "${_OPT_RESOLUTION}";
5429       ;;
5430     xpdf)
5431       case "${_OPT_RESOLUTION}" in
5432       75)
5433         list_append msr_rl '-z' '104';
5434         # '100' corresponds to 72dpi
5435         ;;
5436       100)
5437         list_append msr_rl '-z' '139';
5438         ;;
5439       esac;
5440       ;;
5441     esac;
5442   fi;
5443   if is_yes "${_OPT_ICONIC}"
5444   then
5445     case "${msr_prog}" in
5446     ghostview|gv|gxditview|xditview|xdvi)
5447       list_append msr_rl '-iconic';
5448       ;;
5449     esac;
5450   fi;
5451   if is_yes "${_OPT_RV}"
5452   then
5453     case "${msr_prog}" in
5454     ghostview|gv|gxditview|xditview|xdvi)
5455       list_append msr_rl '-rv';
5456       ;;
5457     esac;
5458   fi;
5459   if is_not_empty "${_OPT_XRM}"
5460   then
5461     case "${msr_prog}" in
5462     ghostview|gv|gxditview|xditview|xdvi|xpdf)
5463       eval set x "${_OPT_XRM}";
5464       shift;
5465       for i
5466       do
5467         list_append msr_rl '-xrm' "$i";
5468       done;
5469       ;;
5470     esac;
5471   fi;
5472   if is_not_empty "${msr_title}"
5473   then
5474     case "${msr_prog}" in
5475     gxditview|xditview)
5476       list_append msr_rl '-title' "${msr_title}";
5477       ;;
5478     esac;
5479   fi;
5480   _DISPLAY_ARGS="${msr_rl}";
5481   eval ${_UNSET} msr_n;
5482   eval ${_UNSET} msr_prog;
5483   eval ${_UNSET} msr_rl;
5484   eval ${_UNSET} msr_title;
5485   eval "${return_ok}";
5486 } # main_set_resources
5487
5488
5489 ########################################################################
5490 # main_display ()
5491 #
5492 # Do the actual display of the whole thing.
5493 #
5494 # Globals:
5495 #   in: $_DISPLAY_MODE, $_OPT_DEVICE,
5496 #       $_ADDOPTS_GROFF, $_ADDOPTS_POST, $_ADDOPTS_X,
5497 #       $_TMP_CAT, $_OPT_PAGER, $PAGER, $_MANOPT_PAGER,
5498 #       $_OUTPUT_FILE_NAME
5499 #
5500 # Variable prefix: md
5501 #
5502 main_display()
5503 {
5504   func_check main_display = 0 "$@";
5505
5506   export md_addopts;
5507   export md_groggy;
5508   export md_modefile;
5509
5510   if obj _TMP_CAT is_non_empty_file
5511   then
5512     md_modefile="${_OUTPUT_FILE_NAME}";
5513   else
5514     echo2 'groffer: empty input.';
5515     clean_up;
5516     eval ${_UNSET} md_modefile;
5517     eval "${return_ok}";
5518   fi;
5519
5520   # go to the temporary directory to be able to access internal data files
5521   cd "${_TMP_DIR}" >"${_NULL_DEV}" 2>&1;
5522
5523   case "${_DISPLAY_MODE}" in
5524   groff)
5525     _ADDOPTS_GROFF="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}";
5526     if obj _OPT_DEVICE is_not_empty
5527     then
5528       _ADDOPTS_GROFF="${_ADDOPTS_GROFF} -T${_OPT_DEVICE}";
5529     fi;
5530     md_groggy="$(tmp_cat | eval grog "${md_options}")";
5531     exit_test;
5532     _do_opt_V;
5533
5534     obj md_modefile rm_file;
5535     mv "${_TMP_CAT}" "${md_modefile}";
5536     trap_unset;
5537     cat "${md_modefile}" | \
5538     {
5539       trap_set;
5540       eval "${md_groggy}" "${_ADDOPTS_GROFF}";
5541     } &
5542     ;;
5543   text|tty)
5544     case "${_OPT_DEVICE}" in
5545     '')
5546       md_device="$(get_first_essential \
5547                      "${_OPT_TEXT_DEVICE}" "${_DEFAULT_TTY_DEVICE}")";
5548       exit_test;
5549       ;;
5550     ascii|cp1047|latin1|utf8)
5551       md_device="${_OPT_DEVICE}";
5552       ;;
5553     *)
5554       warning "main_display(): \
5555 wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
5556       ;;
5557     esac;
5558     md_addopts="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}";
5559     md_groggy="$(tmp_cat | grog -T${md_device})";
5560     exit_test;
5561     if obj _DISPLAY_MODE is_equal 'text'
5562     then
5563       _do_opt_V;
5564       tmp_cat | eval "${md_groggy}" "${md_addopts}";
5565     else
5566       md_pager='';
5567       for p in "${_OPT_PAGER}" "${PAGER}" "${_MANOPT_PAGER}" \
5568                'less -r -R' 'more' 'pager' 'cat'
5569       do
5570         md_p="$p";
5571         if eval is_prog ${md_p}
5572         then                  # no "" for is_prog() allows args for $p
5573           md_pager="${md_p}";
5574           break;
5575         fi;
5576       done;
5577       if obj md_pager is_empty
5578       then
5579         error 'main_display(): no pager program found for tty mode';
5580       fi;
5581       _do_opt_V;
5582       tmp_cat | eval "${md_groggy}" "${md_addopts}" | \
5583                 eval "${md_pager}";
5584     fi;
5585     clean_up;
5586     ;;
5587   source)
5588     tmp_cat;
5589     clean_up;
5590     ;;
5591
5592   #### viewer modes
5593
5594   dvi)
5595     case "${_OPT_DEVICE}" in
5596     ''|dvi) do_nothing; ;;
5597     *)
5598       warning "main_display(): \
5599 wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"
5600       ;;
5601     esac;
5602     md_modefile="${md_modefile}".dvi;
5603     md_groggy="$(tmp_cat | grog -Tdvi)";
5604     exit_test;
5605     _do_display;
5606     ;;
5607   html)
5608     case "${_OPT_DEVICE}" in
5609     ''|html) do_nothing; ;;
5610     *)
5611       warning "main_display(): \
5612 wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
5613       ;;
5614     esac;
5615     md_modefile="${md_modefile}".html;
5616     md_groggy="$(tmp_cat | grog -Thtml)";
5617     exit_test;
5618     _do_display;
5619     ;;
5620   pdf)
5621     case "${_OPT_DEVICE}" in
5622     ''|ps)
5623       do_nothing;
5624       ;;
5625     *)
5626       warning "main_display(): \
5627 wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
5628       ;;
5629     esac;
5630     md_groggy="$(tmp_cat | grog -Tps)";
5631     exit_test;
5632     _do_display _make_pdf;
5633     ;;
5634   ps)
5635     case "${_OPT_DEVICE}" in
5636     ''|ps)
5637       do_nothing;
5638       ;;
5639     *)
5640       warning "main_display(): \
5641 wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
5642       ;;
5643     esac;
5644     md_modefile="${md_modefile}".ps;
5645     md_groggy="$(tmp_cat | grog -Tps)";
5646     exit_test;
5647     _do_display;
5648     ;;
5649   x)
5650     case "${_OPT_DEVICE}" in
5651     X*)
5652       md_device="${_OPT_DEVICE}"
5653       ;;
5654     *)
5655       case "${_OPT_RESOLUTION}" in
5656       100)
5657         md_device='X100';
5658         if obj _OPT_GEOMETRY is_empty
5659         then
5660           case "${_DISPLAY_PROG}" in
5661           gxditview|xditview)
5662             # add width of 800dpi for resolution of 100dpi to the args
5663             list_append _DISPLAY_ARGS '-geometry' '800';
5664             ;;
5665           esac;
5666         fi;
5667         ;;
5668       *)
5669         md_device='X75-12';
5670         ;;
5671       esac
5672     esac;
5673     md_groggy="$(tmp_cat | grog -T${md_device} -Z)";
5674     exit_test;
5675     _do_display;
5676     ;;
5677   X)
5678     case "${_OPT_DEVICE}" in
5679     '')
5680       md_groggy="$(tmp_cat | grog -X)";
5681       exit_test;
5682       ;;
5683     X*|dvi|html|lbp|lj4|ps)
5684       # these devices work with 
5685       md_groggy="$(tmp_cat | grog -T"${_OPT_DEVICE}" -X)";
5686       exit_test;
5687       ;;
5688     *)
5689       warning "main_display(): \
5690 wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}";
5691       md_groggy="$(tmp_cat | grog -Z)";
5692       exit_test;
5693       ;;
5694     esac;
5695     _do_display;
5696     ;;
5697   *)
5698     error "main_display(): unknown mode \`${_DISPLAY_MODE}'";
5699     ;;
5700   esac;
5701   eval ${_UNSET} md_addopts;
5702   eval ${_UNSET} md_device;
5703   eval ${_UNSET} md_groggy;
5704   eval ${_UNSET} md_modefile;
5705   eval ${_UNSET} md_options;
5706   eval ${_UNSET} md_p;
5707   eval ${_UNSET} md_pager;
5708   eval "${return_ok}";
5709 } # main_display()
5710
5711
5712 ########################
5713 # _do_display ([<prog>])
5714 #
5715 # Perform the generation of the output and view the result.  If an
5716 # argument is given interpret it as a function name that is called in
5717 # the midst (actually only for `pdf').
5718 #
5719 # Globals: $md_modefile, $md_groggy (from main_display())
5720 #
5721 _do_display()
5722 {
5723   func_check _do_display '>=' 0 "$@";
5724   _do_opt_V;
5725   if obj _DISPLAY_PROG is_empty
5726   then
5727     trap_unset;
5728     {
5729       trap_set;
5730       eval "${md_groggy}" "${_ADDOPTS_GROFF}" "${_TMP_CAT}";
5731     } &
5732   else
5733     obj md_modefile rm_file;
5734     cat "${_TMP_CAT}" | \
5735       eval "${md_groggy}" "${_ADDOPTS_GROFF}" > "${md_modefile}";
5736     if is_not_empty "$1"
5737     then
5738       eval "$1";
5739     fi;
5740     obj _TMP_CAT rm_file_with_debug;
5741     if obj _VIEWER_TERMINAL is_yes # for programs that run on tty
5742     then
5743       eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "\"${md_modefile}\"";
5744     else
5745       case "${_DISPLAY_PROG}" in
5746 #      lynx\ *|less\ *|more\ *) # programs known to run on the terminal
5747 #        eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "\"${md_modefile}\"";
5748 #        ;;
5749       *)
5750         trap_unset;
5751         {
5752           trap_set;
5753           eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "\"${md_modefile}\"";
5754         } &
5755         ;;
5756       esac;
5757     fi;
5758   fi;
5759   eval "${return_ok}";
5760 } # _do_display() of main_display()
5761
5762
5763 #############
5764 # _do_opt_V ()
5765 #
5766 # Check on option `-V'; if set print the corresponding output and leave.
5767 #
5768 # Globals: $_ALL_PARAMS, $_ADDOPTS_GROFF, $_DISPLAY_MODE, $_DISPLAY_PROG,
5769 #          $_DISPLAY_ARGS, $md_groggy,  $md_modefile
5770 #
5771 # Variable prefix: _doV
5772 #
5773 _do_opt_V()
5774 {
5775   func_check _do_opt_V '=' 0 "$@";
5776   if obj _OPT_V is_yes
5777   then
5778     _OPT_V='no';
5779     echo1 "Parameters:     ${_ALL_PARAMS}";
5780     echo1 "Display mode:   ${_DISPLAY_MODE}";
5781     echo1 "Output file:    ${md_modefile}";
5782     echo1 "Display prog:   ${_DISPLAY_PROG} ${_DISPLAY_ARGS}";
5783     a="$(eval echo1 "'${_ADDOPTS_GROFF}'")";
5784     exit_test;
5785     echo1 "Output of grog: ${md_groggy} $a";
5786     _doV_res="$(eval "${md_groggy}" "${_ADDOPTS_GROFF}")";
5787     exit_test;
5788     echo1 "groff -V:       ${_doV_res}"
5789     leave;
5790   fi;
5791   eval "${return_ok}";
5792 } # _do_opt_V() of main_display()
5793
5794
5795 ##############
5796 # _make_pdf ()
5797 #
5798 # Transform to pdf format; for pdf mode in _do_display().
5799 #
5800 # Globals: $md_modefile (from main_display())
5801
5802 # Variable prefix: _mp
5803 #
5804 _make_pdf()
5805 {
5806   func_check _do_display '=' 0 "$@";
5807   _mp_psfile="${md_modefile}";
5808   md_modefile="${md_modefile}.pdf";
5809   obj md_modefile rm_file;
5810   if gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \
5811         -sOutputFile="${md_modefile}" -c save pop -f "${_mp_psfile}"
5812   then
5813     :;
5814   else
5815     error '_make_pdf: could not transform into pdf format.';
5816   fi;
5817   obj _mp_psfile rm_file_with_debug;
5818   eval ${_UNSET} _mp_psfile;
5819   eval "${return_ok}";
5820 } # _make_pdf() of main_display()
5821
5822
5823 ########################################################################
5824 # main (<command_line_args>*)
5825 #
5826 # The main function for groffer.
5827 #
5828 # Arguments:
5829 #
5830 main()
5831 {
5832   func_check main '>=' 0 "$@";
5833   # Do not change the sequence of the following functions!
5834   landmark '13: main_init()';
5835   main_init;
5836   landmark '14: main_parse_MANOPT()';
5837   main_parse_MANOPT;
5838   landmark '15: main_parse_args()';
5839   main_parse_args "$@";
5840   landmark '16: main_set_mode()';
5841   main_set_mode;
5842   landmark '17: main_do_fileargs()';
5843   main_do_fileargs;
5844   landmark '18: main_set_resources()';
5845   main_set_resources;
5846   landmark '19: main_display()';
5847   main_display;
5848   eval "${return_ok}";
5849 }
5850
5851
5852 ########################################################################
5853
5854 main "$@";