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#
44export _UNSET;
45export _foo;
46_foo=bar;
47_res="$(unset _foo 2>&1)";
48if unset _foo >${_NULL_DEV} 2>&1 && \
49   test _"${_res}"_ = __ && test _"${_foo}"_ = __
50then
51  _UNSET='unset';
52  eval "${_UNSET}" _foo;
53  eval "${_UNSET}" _res;
54else
55  _UNSET=':';
56fi;
57
58
59########################################################################
60# Test of `test'.
61#
62if test a = a && test a != b && test -f "${_GROFFER_SH}"
63then
64  :;
65else
66  echo '"test" did not work.' >&2;
67  exit "${_ERROR}";
68fi;
69
70
71########################################################################
72# Test of `echo' and the `$()' construct.
73#
74if echo '' >${_NULL_DEV}
75then
76  :;
77else
78  echo '"echo" did not work.' >&2;
79  exit "${_ERROR}";
80fi;
81if test _"$(t1="$(echo te)" &&
82            t2="$(echo '')" &&
83            t3="$(echo 'st')" &&
84            echo "${t1}${t2}${t3}")"_ \
85     != _test_
86then
87  echo 'The "$()" construct did not work' >&2;
88  exit "${_ERROR}";
89fi;
90
91
92########################################################################
93# Test of sed program; test in groffer.sh is not valid here.
94#
95if test _"$(echo red | sed -e 's/r/s/')"_ != _sed_
96then
97  echo 'The sed program did not work.' >&2;
98  exit "${_ERROR}";
99fi;
100
101
102########################################################################
103# Test of function definitions.
104#
105_t_e_s_t_f_u_n_c_()
106{
107  return 0;
108}
109
110if _t_e_s_t_f_u_n_c_ 2>${_NULL_DEV}
111then
112  :;
113else
114  echo 'Shell '"${_SHELL}"' does not support function definitions.' >&2;
115  exit "${_ERROR}";
116fi;
117
118
119########################################################################
120#                    debug - diagnostic messages
121########################################################################
122
123export _DEBUG_STACKS;
124_DEBUG_STACKS='no';		# disable stack output in each function
125#_DEBUG_STACKS='yes';		# enable stack output in each function
126
127export _DEBUG_LM;
128_DEBUG_LM='no';			# disable landmark messages
129#_DEBUG_LM='yes';		# enable landmark messages
130
131export _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
135export _DEBUG_PRINT_PARAMS;
136_DEBUG_PRINT_PARAMS='no';	# disable printing of all parameters
137#_DEBUG_PRINT_PARAMS='yes';	# enable printing of all parameters
138
139export _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
143export _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
147export _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
152case " $*" 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
181EOF
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  ;;
221esac;
222
223if test _"${_DEBUG_PRINT_PARAMS}"_ = _yes_
224then
225  echo "parameters: $@" >&2;
226fi;
227
228if test _"${_DEBUG_PRINT_SHELL}"_ = _yes_
229then
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;
241fi;
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
268export _ALL_EXIT;
269export _BAD;
270export _GOOD;
271export _NO;
272export _OK;
273export _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}"'
284export return_ok;
285export return_good;
286export return_bad;
287export return_yes;
288export return_no;
289export return_error;
290export return_var;
291return_ok="func_pop; return ${_OK}";
292return_good="func_pop; return ${_GOOD}";
293return_bad="func_pop; return ${_BAD}";
294return_yes="func_pop; return ${_YES}";
295return_no="func_pop; return ${_NO}";
296return_error="func_pop; return ${_ERROR}";
297return_var="func_pop; return";	# add number, e.g. `eval "${return_var} $n'
298
299
300export _DEFAULT_MODES;
301_DEFAULT_MODES='x,ps,tty';
302export _DEFAULT_RESOLUTION;
303_DEFAULT_RESOLUTION='75';
304
305export _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)
310export _VIEWER_DVI;		# viewer program for dvi mode
311export _VIEWER_HTML_TTY;	# viewer program for html mode in tty
312export _VIEWER_HTML_X;		# viewer program for html mode in X
313export _VIEWER_PDF;		# viewer program for pdf mode
314export _VIEWER_PS;		# viewer program for ps mode
315export _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.
328export _MAN_AUTO_SEC_LIST;
329_MAN_AUTO_SEC_LIST="'1' '2' '3' '4' '5' '6' '7' '8' '9' 'n' 'o'";
330export _MAN_AUTO_SEC_CHARS;
331_MAN_AUTO_SEC_CHARS='[123456789no]';
332
333export _SPACE_SED;
334_SPACE_SED='['"${_SP}${_TAB}"']';
335
336export _SPACE_CASE;
337_SPACE_CASE='[\'"${_SP}"'\'"${_TAB}"']';
338
339export _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
358export _OPTS_GROFFER_SHORT_NA;
359export _OPTS_GROFFER_SHORT_ARG;
360export _OPTS_GROFFER_LONG_NA;
361export _OPTS_GROFFER_LONG_ARG;
362export _OPTS_GROFF_SHORT_NA;
363export _OPTS_GROFF_SHORT_ARG;
364export _OPTS_GROFF_LONG_NA;
365export _OPTS_GROFF_LONG_ARG;
366export _OPTS_X_SHORT_ARG;
367export _OPTS_X_SHORT_NA;
368export _OPTS_X_LONG_ARG;
369export _OPTS_X_LONG_NA;
370export _OPTS_MAN_SHORT_ARG;
371export _OPTS_MAN_SHORT_NA;
372export _OPTS_MAN_LONG_ARG;
373export _OPTS_MAN_LONG_NA;
374export _OPTS_MANOPT_SHORT_ARG;
375export _OPTS_MANOPT_SHORT_NA;
376export _OPTS_MANOPT_LONG_ARG;
377export _OPTS_MANOPT_LONG_NA;
378export _OPTS_CMDLINE_SHORT_NA;
379export _OPTS_CMDLINE_SHORT_ARG;
380export _OPTS_CMDLINE_LONG_NA;
381export _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
465export _ALL_PARAMS;		# All options and file name parameters
466export _ADDOPTS_GROFF;		# Transp. options for groff (`eval').
467export _ADDOPTS_POST;		# Transp. options postproc (`eval').
468export _ADDOPTS_X;		# Transp. options X postproc (`eval').
469export _APROPOS_PROG;		# Program to run apropos.
470export _APROPOS_SECTIONS;	# Sections for different --apropos-*.
471export _DEFAULT_MODES;		# Set default modes.
472export _DISPLAY_MODE;		# Display mode.
473export _DISPLAY_PROG;		# Viewer program to be used for display.
474export _DISPLAY_ARGS;		# X resources for the viewer program.
475export _FILEARGS;		# Stores filespec parameters.
476export _FILESPEC_ARG;		# Stores the actual filespec parameter.
477export _FUNC_STACK;		# Store debugging information.
478export _REGISTERED_TITLE;	# Processed file names.
479# _HAS_* from availability tests
480export _HAS_COMPRESSION;	# `yes' if gzip compression is available
481export _HAS_BZIP;		# `yes' if bzip2 compression is available
482# _MAN_* finally used configuration of man searching
483export _MAN_ALL;		# search all man pages per filespec
484export _MAN_ENABLE;		# enable search for man pages
485export _MAN_EXT;		# extension for man pages
486export _MAN_FORCE;		# force file parameter to be man pages
487export _MAN_IS_SETUP;		# setup man variables only once
488export _MAN_LANG;		# language for man pages
489export _MAN_LANG2;		# language for man pages
490export _MAN_LANG_DONE;		# language dirs added to man path
491export _MAN_PATH;		# search path for man pages
492export _MAN_SEC;		# sections for man pages; sep. `:'
493export _MAN_SEC_DONE;		# sections added to man path
494export _MAN_SYS;		# system names for man pages; sep. `,'
495export _MAN_SYS;		# system names added to man path
496# _MANOPT_* as parsed from $MANOPT
497export _MANOPT_ALL;		# $MANOPT --all
498export _MANOPT_EXTENSION;	# $MANOPT --extension
499export _MANOPT_LANG;		# $MANOPT --locale
500export _MANOPT_PATH;		# $MANOPT --manpath
501export _MANOPT_PAGER;		# $MANOPT --pager
502export _MANOPT_SEC;		# $MANOPT --sections
503export _MANOPT_SYS;		# $MANOPT --systems
504# _OPT_* as parsed from groffer command line
505export _OPT_ALL;		# display all suitable man pages.
506export _OPT_APROPOS;		# call `apropos' program.
507export _OPT_BD;			# set border color in some modes.
508export _OPT_BG;			# set background color in some modes.
509export _OPT_BW;			# set border width in some modes.
510export _OPT_DEFAULT_MODES;	# `,'-list of modes when no mode given.
511export _OPT_DEVICE;		# device option.
512export _OPT_DO_NOTHING;		# do nothing in main_display().
513export _OPT_DISPLAY;		# set X display.
514export _OPT_FG;			# set foreground color in some modes.
515export _OPT_FN;			# set font in some modes.
516export _OPT_GEOMETRY;		# set size and position of viewer in X.
517export _OPT_ICONIC;		# -iconic option for X viewers.
518export _OPT_LANG;		# set language for man pages
519export _OPT_LOCATION;		# print processed file names to stderr
520export _OPT_MODE;		# values: X, tty, Q, Z, ""
521export _OPT_MANPATH;		# manual setting of path for man-pages
522export _OPT_PAGER;		# specify paging program for tty mode
523export _OPT_RESOLUTION;		# set X resolution in dpi
524export _OPT_RV;			# reverse fore- and background colors.
525export _OPT_SECTIONS;		# sections for man page search
526export _OPT_SYSTEMS;		# man pages of different OS's
527export _OPT_TITLE;		# title for gxditview window
528export _OPT_TEXT_DEVICE;	# set device for tty mode.
529export _OPT_V;			# groff option -V.
530export _OPT_VIEWER_DVI;		# viewer program for dvi mode
531export _OPT_VIEWER_PDF;		# viewer program for pdf mode
532export _OPT_VIEWER_PS;		# viewer program for ps mode
533export _OPT_VIEWER_HTML;	# viewer program for html mode
534export _OPT_VIEWER_X;		# viewer program for x mode
535export _OPT_WHATIS;		# print the man description
536export _OPT_XRM;		# specify X resource.
537export _OPT_Z;			# groff option -Z.
538export _OUTPUT_FILE_NAME;	# output generated, see main_set_res..()
539export _VIEWER_TERMINAL;	# viewer options for terminal (--*-viewer-tty)
540# _TMP_* temporary directory and files
541export _TMP_DIR;		# groffer directory for temporary files
542export _TMP_CAT;		# stores concatenation of everything
543export _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
553export _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#
576reset()
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
653reset;
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#
668echo1()
669{
670  cat <<EOF
671$@
672EOF
673}
674
675
676##############
677# echo2 (<text>*)
678#
679# Output to stderr.
680#
681# Arguments : arbitrary text.
682#
683echo2()
684{
685  cat >&2 <<EOF
686$@
687EOF
688}
689
690
691##############
692# landmark (<text>)
693#
694# Print <text> to standard error as a debugging aid.
695#
696# Globals: $_DEBUG_LM
697#
698landmark()
699{
700  if test _"${_DEBUG_LM}"_ = _yes_
701  then
702    echo2 "LM: $*";
703  fi;
704}
705
706landmark "1: debugging functions";
707
708
709##############
710# clean_up ()
711#
712# Clean up at exit.
713#
714clean_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#
737diag()
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#
750error()
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#
772error_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#
801exit_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#
827func_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#
912func_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#
953func_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#
984func_stack_dump()
985{
986  diag 'call stack: '"${_FUNC_STACK}";
987}
988
989
990########################################################################
991#                        System Test
992########################################################################
993
994landmark "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
1003if test _"$(echo xTesTx \
1004           | sed -e 's/^.\([Tt]e*x*sTT*\).*$/\1/' \
1005           | sed -e 's|T|t|g')"_ != _test_
1006then
1007  error 'Test of "sed" command failed.';
1008fi;
1009
1010
1011########################################################################
1012# Test of function `cat'.
1013#
1014if test _"$(echo test | cat)"_ != _test_
1015then
1016  error 'Test of "cat" command failed.';
1017fi;
1018
1019
1020########################################################################
1021# Test for compression.
1022#
1023if test _"$(echo 'test' | gzip -c -d -f - 2>${_NULL_DEV})"_ = _test_
1024then
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;
1035else
1036  _HAS_COMPRESSION='no';
1037  _HAS_BZIP='no';
1038fi;
1039
1040
1041########################################################################
1042#       Definition of normal Functions in alphabetical order
1043########################################################################
1044landmark "3: functions";
1045
1046########################################################################
1047# apropos_filespec ()
1048#
1049# Setup for the --apropos* options
1050#
1051apropos_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 '
1082s/^\(.* (..*)\)  *-  *\(.*\)$/\.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#
1094apropos_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#
1134base_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#
1173if test _"${_HAS_COMPRESSION}"_ = _yes_
1174then
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  }
1197else
1198  cat_z()
1199  {
1200    func_check cat_z = 1 "$@";
1201    cat "$1";
1202    eval "${return_ok}";
1203  }
1204fi;
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########################################################################
1224landmark '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#
1235dirname_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#
1262dirname_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#
1305do_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#
1407do_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#
1484get_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########################################################################
1507landmark '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#
1518is_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#
1537is_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#
1556is_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#
1576is_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#
1599is_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#
1620is_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#
1639is_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#
1658is_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#
1676is_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#
1694is_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#
1713is_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#
1738is_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#
1754is_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#
1772is_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#
1791is_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#
1816is_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#
1839is_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#
1857is_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#
1883leave()
1884{
1885  clean_up;
1886  if test $# = 0
1887  then
1888    exit "${_OK}";
1889  else
1890    exit "$1";
1891  fi;
1892}
1893
1894
1895########################################################################
1896landmark '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#
1918list_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#
1998list_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} \
2081has 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#
2194list_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#
2239list_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 '
2245s/^'"${_SPACE_SED}"'*//
2246s/'"${_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#
2279list_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#
2316list_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#
2357list_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#
2397list_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} \
2426has 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########################################################################
2447landmark '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#
2469man_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#
2607man_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#
2646man_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#
2862man_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########################################################################
2953landmark '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#
2972manpath_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#
3058manpath_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########################################################################
3110landmark '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#
3128obj()
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#
3160obj_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#
3188obj_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#
3217obj_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#
3237path_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 '
3244s/^:*//
3245s/:::*/:/g
3246s/:*$//
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#
3262path_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#
3313path_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#
3335path_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#
3356path_split()
3357{
3358  func_check path_split = 1 "$@";
3359  list_from_split "$1" ':';
3360  eval "${return_ok}";
3361}
3362
3363
3364########################################################################
3365landmark '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#
3376register_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#
3405register_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#
3463rm_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#
3486rm_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#
3512rm_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#
3535if obj _HAS_COMPRESSION is_yes
3536then
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  }
3547else
3548  save_stdin()
3549  {
3550    func_check save_stdin = 0 "$@";
3551    cat >"${_TMP_STDIN}";
3552    eval "${return_ok}";
3553  }
3554fi;
3555
3556
3557########################################################################
3558# special_filespec ()
3559#
3560# Handle special modes like whatis and apropos.
3561#
3562special_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#
3588special_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########################################################################
3610landmark '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#
3621string_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#
3644string_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########################################################################
3658landmark '12: tmp_*()';
3659########################################################################
3660
3661########################################################################
3662# tmp_cat ()
3663#
3664# output the temporary cat file (the concatenation of all input)
3665#
3666tmp_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#
3688tmp_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#
3706to_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#
3737to_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#
3754trap_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#
3767trap_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#
3780usage()
3781{
3782  func_check usage = 0 "$@";
3783  echo;
3784  version;
3785  echo1 'Usage: groffer [option]... [filespec]...';
3786  cat <<EOF
3787
3788Display roff files, standard input, and/or Unix manual pages with a X
3789Window viewer or in several text modes.  All input is decompressed
3790on-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
3799and 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.
3810All other short options are interpreted as "groff" formatting options.
3811
3812The 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
3853Development 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
3858Viewer 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
3863The 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
3869Long 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
3874EOF
3875  eval "${return_ok}";
3876}
3877
3878
3879########################################################################
3880# version ()
3881#
3882# print version information to stderr
3883#
3884version()
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#
3899warning()
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#
3913whatis_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
3929EOF
3930
3931  # get the parts of the file name
3932  wf_name="$(base_name $1)";
3933  wf_section="$(echo1 $1 | sed -n -e '
3934s|^.*/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 '
3950s/^\(.*\)\.'${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
3958d
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 '
39681,/'"${wf_dot}"'SH/d
3969/'"${wf_dot}"'SH/q
3970p
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 '
3986s/^'"${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 '
4008s/^\(.*\)$/'"${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#
4036whatis_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#
4054whatis_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#
4076where_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#
4144main_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: \
4210Couldn'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#
4241main_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 '
4249s/^'"${_SPACE_SED}"'*//
4250s/'"${_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#
4383main_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(): \
4706only 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#
4854main_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#
5178main_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#
5274main_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#
5502main_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(): \
5555wrong 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(): \
5599wrong 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(): \
5612wrong 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(): \
5627wrong 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(): \
5641wrong 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(): \
5690wrong 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#
5830main()
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
5854main "$@";
5855