summaryrefslogtreecommitdiff
path: root/contrib/groffer
diff options
context:
space:
mode:
authorwlemb <wlemb>2002-05-30 13:56:51 +0000
committerwlemb <wlemb>2002-05-30 13:56:51 +0000
commita20afffba417c6928d83a1472a1ab430c3c77a00 (patch)
tree678872ee6fd56b681fbcbf5d007fbf645cded073 /contrib/groffer
parent401849317227f20d5d78f9c1cfb194ebf2642c87 (diff)
downloadgroff-a20afffba417c6928d83a1472a1ab430c3c77a00.tar.gz
* doc/Makefile.sub (CLEANADD): Add grnexmpl.g, groff, and groff-*
to list only if srcdir != currdir. (distfiles): New target. * Makefile.in (EXTRADIRS): Add font/devlj4/generate. (NOMAKEDIRS): New variable. (DISTDIRS): Use it. ________________________________________________________________ * release of groffer 0.6 This is almost a complete rewrite since groffer 0.5 . ________________________________________________________________ * Documentation * groffer.man: - Apply the changes done in www.tmac (.URL and .MTO) - Replace \fP by \f[]. - Redesign and rewrite most macros. - Include the documentation for the new features. - Greatly enlarge section ENVIRONMENT - Add examples. * TODO: - Start a TODO file with several sections. * ChangeLog: Due to the many changes, shorten and rearrange the entries since groffer 0.5 . ________________________________________________________________ * Shell compatibility * groffer.sh: - Due to possible conflicts in old BSD versions, `[]' was replaced by `test'; the `test' options `-a' and `-o' were replaced by multiple calls of `test'. - Write interface to the `sed' command `s' to become independent of the delimiter character. Rewrite all text manipulating function to use this new scheme. The new functions are named `string_*'. - `tr' is not needed any longer, replaced by `sed'. - `grep' is not needed any longer, mostly replaced by `case'. - Revision of test for `getopt'. - Remove `set -a'; explicitly export variables. - The only external programs used are POSIX `sed' and the fallback to `apropos'. All other program calls were replaced by shell builtins and functions. ________________________________________________________________ * Cosmetics * groffer.sh: - Implement a prefix based naming scheme for local variables and functions (OOP-like). - Introduce variables for white space (better readability with $IFS). - Store the names of the processed filespecs into a variable instead of a temporary file. - Error-prone shell constructions were replaced by functions with a simple interface. - To avoid too long pipes, replace supercat() by do_fileargs(); every input file is handled independently. ________________________________________________________________ * New features: - Add support for more X devices (e.g. X75-12 and X100-12). - Add long option `--intermediate_output' to `-Z'. - Make the options for mode selection clobber each other. - Add option `--mode' with an argument having the following values: `X': force displaying in X, same as options `-X'; `tty': display with a pager on text terminal; same as `--tty'; `source', `default', `auto', etc. - Make the handling of the X mode like in groff (e.g. -X -Tps). - Make resolution for gxditview behave like groff (default 75 dpi). - Add environment variable $GROFFER_OPT to preset groffer options. ________________________________________________________________ * implement most of the functionality of GNU `man'. - Add all `man' long options to groffer. - Add all `man' environment variables. - Parse and use content of `$MANOPT'. - The precedence of the options and environment variables is regulated like in GNU `man'. - Force the option `--manpath' to have a colon-separated argument like GNU `man'. - Support `man section name' calling convention. - Remove all dependencies on `man -w'. * groffer.sh: - Add the new features above. - Rewrite the search algorithm for man pages. - Remove searching with `man -w' (problems with space characters in file names). - Fix and complement usage(). - The filespec parsers gets a function of its own do_manpage().
Diffstat (limited to 'contrib/groffer')
-rw-r--r--contrib/groffer/ChangeLog109
-rw-r--r--contrib/groffer/groffer.man2168
-rw-r--r--contrib/groffer/groffer.sh3733
3 files changed, 4499 insertions, 1511 deletions
diff --git a/contrib/groffer/ChangeLog b/contrib/groffer/ChangeLog
index 07403444..f0b0ed14 100644
--- a/contrib/groffer/ChangeLog
+++ b/contrib/groffer/ChangeLog
@@ -1,17 +1,108 @@
-2002-02-17 Werner LEMBERG <wl@gnu.org>
+2002-05-28 Bernd Warken <bwarken@mayn.de>
- * groffer.man: Updated to latest changes in www.tmac.
+ ________________________________________________________________
+ * release of groffer 0.6
-2002-01-08 Bernd Warken <bwarken@mayn.de>
+ This is almost a complete rewrite since groffer 0.5 .
+ ________________________________________________________________
+ * Documentation
+
+ * groffer.man:
+ - Apply the changes done in www.tmac (.URL and .MTO)
+ - Replace \fP by \f[].
+ - Redesign and rewrite most macros.
+ - Include the documentation for the new features.
+ - Greatly enlarge section ENVIRONMENT
+ - Add examples.
+
+ * TODO:
+ - Start a TODO file with several sections.
+
+ * ChangeLog:
+ Due to the many changes, shorten and rearrange the entries
+ since groffer 0.5 .
+ ________________________________________________________________
+ * Shell compatibility
+
+ * groffer.sh:
+ - Due to possible conflicts in old BSD versions, `[]' was
+ replaced by `test'; the `test' options `-a' and `-o' were
+ replaced by multiple calls of `test'.
+ - Write interface to the `sed' command `s' to become
+ independent of the delimiter character. Rewrite all text
+ manipulating function to use this new scheme. The new
+ functions are named `string_*'.
+ - `tr' is not needed any longer, replaced by `sed'.
+ - `grep' is not needed any longer, mostly replaced by `case'.
+ - Revision of test for `getopt'.
+ - Remove `set -a'; explicitly export variables.
+ - The only external programs used are POSIX `sed' and the
+ fallback to `apropos'. All other program calls were
+ replaced by shell builtins and functions.
+
+ ________________________________________________________________
+ * Cosmetics
+
+ * groffer.sh:
+ - Implement a prefix based naming scheme for local variables
+ and functions (OOP-like).
+ - Introduce variables for white space (better readability with
+ $IFS).
+ - Store the names of the processed filespecs into a variable
+ instead of a temporary file.
+ - Error-prone shell constructions were replaced by functions
+ with a simple interface.
+ - To avoid too long pipes, replace supercat() by do_fileargs();
+ every input file is handled independently.
+
+ ________________________________________________________________
+ * New features:
+ - Add support for more X devices (e.g. X75-12 and X100-12).
+ - Add long option `--intermediate_output' to `-Z'.
+ - Make the options for mode selection clobber each other.
+ - Add option `--mode' with an argument having the following
+ values:
+ `X': force displaying in X, same as options `-X';
+ `tty': display with a pager on text terminal; same as `--tty';
+ `source', `default', `auto', etc.
+ - Make the handling of the X mode like in groff (e.g. -X -Tps).
+ - Make resolution for gxditview behave like groff (default
+ 75 dpi).
+ - Add environment variable $GROFFER_OPT to preset groffer
+ options.
+
+ ________________________________________________________________
+ * implement most of the functionality of GNU `man'.
+
+ - Add all `man' long options to groffer.
+ - Add all `man' environment variables.
+ - Parse and use content of `$MANOPT'.
+ - The precedence of the options and environment variables
+ is regulated like in GNU `man'.
+ - Force the option `--manpath' to have a colon-separated
+ argument like GNU `man'.
+ - Support `man section name' calling convention.
+ - Remove all dependencies on `man -w'.
+ * groffer.sh:
+ - Add the new features above.
+ - Rewrite the search algorithm for man pages.
+ - Remove searching with `man -w' (problems with space
+ characters in file names).
+ - Fix and complement usage().
+ - The filespec parsers gets a function of its own do_manpage().
+
+
+2002-01-08 Bernd Warken <bwarken@mayn.de>
+
* groffer 0.5 (beta) released
* groffer.man:
- Fix hyphenation problems with macros describing options.
- Fix the handling of some `-' characters.
- Examples of shell commands now print in font CR instead of CB.
- - Remove documentation for option -X.
- - Add documentation for option --dpi.
+ - Remove documentation for option `-X'.
+ - Add documentation for option `--dpi'.
* groffer.sh:
- New method for creating temporary files, based on process
@@ -25,13 +116,13 @@
- Function usage() corrected and updated.
- Unnecessary stuff removed.
- Comments adjusted.
- - Pass option -X to groff, i.e. force X output with 75 dpi.
- - Implement option --dpi for setting the resolution for the X
+ - Pass option `-X' to groff, i.e. force X output with 75 dpi.
+ - Implement option `--dpi' for setting the resolution for the X
viewer, which had already been documented in earlier versions.
2002-01-07 Bernd Warken <bwarken@mayn.de>
- * groffer 0.4 (beta) released (integrated into groff `contrib')
+ * groffer 0.4 (beta) released (as groff `contrib')
* groffer.man:
- New features documented.
@@ -114,7 +205,7 @@
2001-11-28 Bernd Warken <bwarken@mayn.de>
- * groffview 0.1 (experimental) and groffview.man released
+ ***** groffview 0.1 (experimental) and groffview.man released
(predecessor of groffer, shell script)
* Options : -h --help, -v --version
diff --git a/contrib/groffer/groffer.man b/contrib/groffer/groffer.man
index 41278240..c81b1252 100644
--- a/contrib/groffer/groffer.man
+++ b/contrib/groffer/groffer.man
@@ -1,8 +1,17 @@
+.TH GROFFER @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.SH NAME
+groffer \- display groff files and man\~pages on X and tty
+.
+.
+.\" --------------------------------------------------------------------
+.\" Legalize
+.\" --------------------------------------------------------------------
+.
.ig
-groffer.man
+groffer.man - man page for groffer (section 1).
-Version : groffer 0.5 (beta)
-Last update : 08 Jan 2002
+Version : groffer 0.6
+Last update : 28 May 2002
This file is part of groff, the GNU roff type-setting system.
@@ -36,221 +45,500 @@ FDL in the main directory of the groff source package.
. ftr CB CW
.\}
.
-.ie t \{\
-. ds @- "\-\"
-. ds @-- "\-\-\"
-.\}
-.el \{\
-. ds @- "-\"
-. ds @-- "--\"
-.\}
+.ds @- "\-\""
+.ds @-- "\-\^\-\""
+.
+.ds @b- "\f[CB]-\f[]\""
+.ds @b-- "\f[CB]--\f[]\""
+.
+.ds @i- "\f[CI]-\f[]\""
+.ds @i-- "\f[CI]--\f[]\""
+.
+.ds Ellpisis .\|.\|.\"
+.
+./" static registers (@+...) used for inter-macro communication"
+.nr @.Shell_cmd_width 2m\" total width of prompt
+.
+.nr @+Synopsis_level 0
+.
+.nr @+TP_level 0
+.rr @+TP_header
+.rr @+TP_body
+.rr @+TP_indent
.
-.ds Ellipsis .\|.\|.\"
.
.\" --------------------------------------------------------------------
.\" Start macro definitions
-.eo
.
+.c --------------------------------------------------------------------
+.c .- ([<punct>])
+.c
+.c Print `-' (minus sign); optional punctuation.
+.c
+.de -
+. ie (\\n[.$] == 0) \
+. Opt_alt - ""
+. el \
+. Opt_alt - "" "\\$1"
+..
+.c --------------------------------------------------------------------
+.c .[-] ([<punct>])
+.c
+.c Print `[-]' (minus sign in brackets); optional punctuation.
+.c
+.de [-]
+. ie (\\n[.$] == 0) \
+. [Opt_alt] - ""
+. el \
+. [Opt_alt] - "" "\\$1"
+..
+.c --------------------------------------------------------------------
+.c .-- ([<punct>])
+.c
+.c Print `--' (double minus); optional punctuation.
+.c
+.de --
+. ie (\\n[.$] == 0) \
+. Opt_alt -- ""
+. el \
+. Opt_alt -- "" "\\$1"
+..
+.c --------------------------------------------------------------------
+.c .[--] ([<punct>])
+.c
+.c Print `[--]' (double minus in brackets); optional punctuation.
+.c
+.de [--]
+. ie (\\n[.$] == 0) \
+. [Opt_alt] -- ""
+. el \
+. [Opt_alt] -- "" "\\$1"
+..
+.c --------------------------------------------------------------------
+.c .c ([<ignored>...])
+.c
+.c Ignore all arguments like a comment, even after a .eo call.
+.c
.de c
-.\" this is like a comment request when escape mechanism is off
..
-.c --------------------------------------------------------------------
-.de Text
-. nop \)\$*
+.c --------------------------------------------------------------------
+.c .Error (<text>...)
+.c
+.c Print error message to terminal and abort.
+.c
+.de Error
+. tm \\$*
+. ab
..
.c --------------------------------------------------------------------
-.c environment variable
-.de EnvVar
+.c .Env_var (<env_var_name> [<punct>])
+.c
+.c Display an environment variable, with optional punctuation.
+.c
+.de Env_var
. nh
-. BR \$1 \$2
+. SM
+. Text \f[CB]\\$1\f[]\\$2
. hy
..
.c --------------------------------------------------------------------
-.c LongOpt ([name [punct]])
+.c .Long_opt ([<name> [<punct>]])
.c
-.c `--name' somwhere in the text
-.c second arg is punctuation
+.c Print `--name' somewhere in the text; optional punctuation.
.c
-.de LongOpt
-. ds @opt \$1\"
-. shift
-. nh
-. Text \f[CB]\*[@--]\f[]\f[B]\*[@opt]\f[]\/\$*
-. hy
-. rm @opt
+.de Long_opt
+. Opt_alt -- "\\$1" "" "\\$2"
..
.c --------------------------------------------------------------------
-.c [LongOpt] (name [arg])
+.c .[Long_opt] ([<name> [<punct>]])
.c
-.c long option in synopsis
+.c Print `--name' somewhere in the text; optional punctuation.
.c
-.de [LongOpt]
-. if (\n[.$] == 0) \
-. return
-. ds @opt \$1\"
-. shift
-. nh
-. ie (\n[.$] == 0) \
-. Text \f[R][\f[]\f[CB]\*[@--]\f[]\f[B]\*[@opt]\f[]\f[R]]\f[]
-. el \{\
-. Text \f[R][\f[]\f[CB]\*[@--]\f[]\f[B]\*[@opt]
-. Text \f[]\f[I]\/\$*\f[]\f[R]]\f[]
-. \}
-. hy
-. rm @opt
+.de [Long_opt]
+. [Opt_alt] -- "\\$1" "" "\\$2"
..
.c --------------------------------------------------------------------
-.c OptDef (shortopt [longopt [argument]])
+.c .Opt_alt ([<minus> <opt>]... [<arg> [<punct>]])
.c
-.c option documentation
-.c args : `shortopt', `longopt' can be ""
+.c Alternate options separated by a vertical bar.
.c
-.de OptDef
-. rm @short
-. rm @long
-. rm @arg
-. nh
-. if (\n[.$] >= 1) \{\
-. ds @1 \$1\"
-. if !'\*[@1]'' \
-. ds @short \f[CB]\*[@-]\*[@1]\f[]\"
-. if (\n[.$] >= 2) \{\
-. if !'\*[@short]'' \
-. as @short \f[CW]\0\f[]\"
-. ds @2 \$2\"
-. if !'\*[@2]'' \
-. ds @long \f[CB]\*[@--]\f[]\f[B]\*[@2]\f[]\"
-. if (\n[.$] >= 3) \{\
-. if !'\*[@long]'' \
-. as @long \|=\|\"
-. shift 2
-. ds @arg \fI\$*\"
-. \}
+.c Arguments:
+.c minus: either `-' or `--' (font CB).
+.c opt: a name for an option, empty allowed (font CB).
+.c arg: optionally, the argument to the option (font I).
+.c punct: optional punctuation (in the starting font).
+.c Result:
+.c The minus/opt argument pairs, each
+.c separated by a vertical bar `|', optionally add 'arg', separated
+.c a space character ` '.
+.c
+.c Example:
+.c .Opt_alt - T -- device -- device-troff device .
+.c results in
+.c -T|--device|--device-troff device.
+.c
+.de Opt_alt
+. Opt_alt_base "" | "" \\$@
+..
+.c --------------------------------------------------------------------
+.c .[Opt_alt] ([<minus> <opt>]... [<arg> [<punct>]])
+.c
+.c Alternate options in brackets for section SYNOPSIS.
+.c
+.c Arguments:
+.c minus: either `-' or `--' (font CB).
+.c opt: a name for an option, empty allowed (font CB).
+.c arg: optionally, the argument to the option (font I).
+.c punct: optional punctuation (in the starting font).
+.c Global strings written to:
+.c `@oa_prefix': left enclosing character (`[')
+.c `@oa_sep': separator (`|')
+.c `@oa_postfix': right enclosing character (`]')
+.c Result:
+.c The minus/opt argument pairs, each separated by a vertical
+.c bar `|', optionally add 'arg', separated by a space character ` '.
+.c
+.c Example:
+.c .[Opt_alt] - T -- device -- device-troff device .
+.c results in
+.c [-T|--device|--device-troff device].
+.c
+.de [Opt_alt]
+. Opt_alt_base [ | ] \\$@
+..
+.c --------------------------------------------------------------------
+.c .Opt_alt_base (<pre> <sep> <post> [<minus> <opt>]... [arg [punct]])
+.c
+.c Alternating options; base macro for many others; do not use directly.
+.c
+.c Arguments:
+.c <pre>: prefix, resulted is preceded by this.
+.c <sep>: separator between minux/opt pairs.
+.c <post>: postfix, is appended to the result.
+.c <minus>: either `-' or `--' (font CB).
+.c <opt>: a name for an option, empty allowed (font CB).
+.c <arg>: optionally, the argument to the option (font I).
+.c <punct>: optional punctuation (in the starting font).
+.c Result:
+.c String `<pre>' followed by the <minus>/<opt> argument pairs, each
+.c separated by string `<sep>', optionally add '<arg>', separated by
+.c a single space ` ', followed by the string `<post>'.
+.c
+.de Opt_alt_base
+. nr @font \\n[.f]\"
+. if (\\n[.$] < 3) \
+. Error .\\0: not enough arguments.
+. ds @pre \)\\$1\)\" prefix
+. ds @sep \)\\$2\)\" separator
+. ds @post \)\\$3\)\" postfix
+. shift 3
+. nr @count 0
+. ds @res \f[CW]\\*[@pre]\"
+. while (\\n[.$] >= 2) \{\
+. c do the pairs, break on no `-'
+. if !'\\$1'-' \{\
+. if !'\\$1'--' \
+. break
+. \}
+. c separator
+. if (\\n[@count] > 0) \
+. as @res \f[CW]\\*[@sep]\"
+. nr @count +1
+. as @res \f[CB]\\$1\\$2\:\" combine minus with option name
+. shift 2
+. \}
+. if (\\n[.$] >= 3) \
+. Error .\\0: wrong arguments: \\$@
+. c all pairs are done
+. ie (\\n[.$] == 0) \
+. as @res \f[CW]\\*[@post]\"
+. el \{\
+. c optional option argument
+. if !'\\$1'' \
+. as @res \f[CW] \:\,\f[I]\\$1\"
+. shift
+. as @res \\f[CW]\\*[@post]\" postfix
+. if (\\n[.$] >= 1) \{\
+. c add punctuation
+. as @res \f[\\n[@font]]\\$1\"
. \}
. \}
-. IP "\f[R]\*[@short]\*[@long]\*[@arg]\f[]"
+. nh
+. Text \\*[@res]
. hy
-. rm @1
-. rm @2
-. rm @arg
-. rm @short
-. rm @long
+. ft \\n[@font]
+. rr @count
+. rr @font
+. rm @pre
+. rm @post
+. rm @sep
+. rm @res
..
.c --------------------------------------------------------------------
-.c a shell command line
-.de ShellCommand
-. br
-. ad l
-. nh
-. Text \f[I]shell#\h'1m'\f[]\f[CR]\$*\f[]\&\"
-. ft R
-. ft P
-. hy
-. ad
+.c .Opt_def ([<minus> <opt>]... [<arg> [<punct>]])
+.c
+.c Definitions of options in section OPTIONS.
+.c
+.c Arguments:
+.c minus: either `-' or `--' (font CB).
+.c opt: a name for an option, empty allowed (font CB).
+.c arg: optionally, the argument to the option (font I).
+.c punct: optional punctuation (in the starting font).
+.c Result:
+.c The header for an indented paragraph, consisting of
+.c minus/opt argument pairs, each, separated by a space
+.c character ` ', optionally add 'arg', separated a space
+.c character ` '.
+.c
+.c Example:
+.c .Opt_def - T -- device -- device-troff device .
+.c results in
+.c -T --device --device-troff device.
+.c as the header of for indented paragraph.
+.c
+.de Opt_def
+. TP
+. Opt_alt_base "" "\~|\~" "" \\$@
..
.c --------------------------------------------------------------------
-.c ShellLongOpt ([name])
+.c .Opt_element ([<minus> <opt>]... [<arg> [<punct>]])
.c
-.c `--name' in a shell command
-.c second arg is punctuation
+.c Definitions of options in section OPTIONS.
.c
-.de ShellLongOpt
-. ds @1 \$1\"
-. shift
-. Text \*[@--]\*[@1]
-. rm @1
+.c Arguments:
+.c minus: either `-' or `--' (font CB).
+.c opt: a name for an option, empty allowed (font CB).
+.c arg: optionally, the argument to the option (font I).
+.c punct: optional punctuation (in the starting font).
+.c Result:
+.c The minus/opt argument pairs, each, separated by a space
+.c character ` ', optionally add 'arg', separated a space
+.c character ` '.
+.c
+.c Example:
+.c .Opt_element - T -- device -- device-troff device .
+.c results in
+.c -T --device --device-troff device.
+.c
+.de Opt_element
+. Opt_alt_base "" "\~" "" \\$@
..
.c --------------------------------------------------------------------
-.c ShellShortOpt ([char])
+.als Opt_list Opt_element
+.
+.c --------------------------------------------------------------------
+.c .Shell_cmd (<CR> [<CI>] ...)
.c
-.c `-c' somwhere in the text
-.c second arg is punctuation
+.c A shell command line; display args alternating in fonts CR and CI.
.c
-.de ShellShortOpt
-. ds @1 \$1\"
-. shift
-. Text \*[@-]\*[@1]
-. rm @1
+.c Examples:
+.c .Shell_cmd "groffer --dpi 100 file"
+.c result: `sh# groffer --dpi 100 file'
+.c with 'sh#' in font I, the rest in CR
+.c
+.c .Shell_cmd groffer\~--dpi\~100\~file
+.c result: the same as above
+.c
+.c .Shell_cmd "groffer --dpi=" value " file"
+.c result: sh# groffer --dpi=value file
+.c with `groffer --dpi=' and `file' in CR; `value' in CI
+.c
+.c .Shell_cmd groffer\~--dpi= value \~file
+.c result: the same as the previous example
+.c
+.de Shell_cmd
+. Shell_cmd_base "sh#" \\$@
..
.c --------------------------------------------------------------------
-.c ShortOpt ([char [punct]])
+.c .Shell_cmd+ (<CR> [<CI>] ...)
.c
-.c `-c' somwhere in the text
-.c second arg is punctuation
+.c A continuation line for .Shell_cmd.
.c
-.de ShortOpt
-. ds @opt \$1\"
-. shift
-. nh
-. Text \f[CB]\*[@-]\f[]\f[B]\*[@opt]\fP\/\$*
-. hy
-. rm @opt
+.de Shell_cmd+
+. Shell_cmd_base ">" \\$@
..
.c --------------------------------------------------------------------
-.c [ShortOpt] (name [arg])
+.c .Shell_cmd_base (<prompt> [<CR> [<CI>] ...])
.c
-.c short option in synopsis
+.c A shell command line; display args alternating in fonts CR and CI.
.c
-.de [ShortOpt]
-. if (\n[.$] == 0] \
+.c Globals: read-only register @.Shell_cmd_width
+.c
+.de Shell_cmd_base
+. if (\\n[.$] <= 0) \
. return
-. ds @opt \$1\"
+. nr @+font \\n[.f]\"
+. ds @prompt \f[I]\\$1\"
+. ft CR
+. nr @+gap \\n[@.Shell_cmd_width]\"
+. nr @+gap -\\w'\\*[@prompt]'\" gap between prompt and command
+. ds @res \\*[@prompt]\h'\\n[@+gap]u'\"
. shift
-. nh
-. ie (\n[.$] == 0) \
-. Text \f[R][\f[]\f[CB]\*[@-]\*[@opt]\f[]\f[R]]\f[]
-. el \{\
-. Text \f[R][\f[]\f[CB]\*[@-]\*[@opt]
-. Text \f[]\f[I]\/\$*\f[]\f[R]]\f[]
+. ds @cf CR\"
+. while (\\n[.$] > 0) \{\
+. as @res \\f[\\*[@cf]]\\$1\"
+. shift
+. ie '\\*[@cf]'CR' \
+. ds @cf I\"
+. el \
+. ds @cf CR\"
. \}
+. br
+. ad l
+. nh
+. nf
+. Text \\*[@res]\"
+. fi
. hy
-. rm @opt
+. ad
+. br
+. ft \\n[@+font]
+. rr @+font
+. rr @+gap
+. rm @cf
+. rm @res
+..
+.c --------------------------------------------------------------------
+.c .Short_opt ([<name> [<punct>]])
+.c
+.c Print `-name' somewhere in the Text; optional punctuation.
+.c
+.de Short_opt
+. Opt_alt - "\\$1" "" "\\$2"
+..
+.c --------------------------------------------------------------------
+.c .[Short_opt] ([name [punct]])
+.c
+.c Print `[-name]' somewhere in the Text; optional punctuation.
+.c
+.de [Short_opt]
+. [Opt_alt] - "\\$1" "" "\\$2"
..
.c --------------------------------------------------------------------
+.c .Synopsis ()
+.c
+.c Begin a synopsis section, to be ended by a ./Synopsis macro.
+.c
.de Synopsis
+. if (\\n[@+Synopsis_level] > 0) \
+. Error .\\$0: previous .Synopsis was not closed by ./Synopsis.
. nh
-. ds @1 \$1\"
-. nr @old_indent \n(.i
+. ds @1 \\$1\"
+. nr @old_indent \\n(.i
. ad l
-. in +\w'\fB\*[@1]\0'u
-. ti \n[@old_indent]u
-. B \*[@1]\0\c
+. in +\w'\fB\\*[@1]\0'u
+. ti \\n[@old_indent]u
+. B \\*[@1]\0\c
. rr @old_indent
. rm @1
+. nr @+Synopsis_level +1\" marker for ./Synopsis
..
-.de EndSynopsis
+.c --------------------------------------------------------------------
+.c ./Synopsis ()
+.c
+.c Close a synopsis section opened by the previous .Synopsis macro.
+.c
+.de /Synopsis
+. if (\\n[@+Synopsis_level] <= 0) \
+. Error .\\$0: no previous call of .Synopsis
. br
. ad
. in
. hy
+. nr @+Synopsis_level -1
+..
+.c --------------------------------------------------------------------
+.c .Text (<text>...)
+.c
+.c Treat the arguments as text, no matter how they look.
+.c
+.de Text
+. if (\\n[.$] == 0) \
+. return
+. nop \)\\$*\)
..
.c --------------------------------------------------------------------
-.c Topic
+.c .Topic ([<indent>])
.c
-.c a bulleted paragraph
+.c A bulleted paragraph
.c
.de Topic
-. TP 2m
+. ie (\\n[.$] = 0) \
+. .ds @indent 2m\"
+. el \
+. .ds @indent \\$1\"
+. TP \\*[@indent]
. Text \[bu]
+. rm @indent
..
.c --------------------------------------------------------------------
-.c Extends .TP header
+.c .TP+ ()
+.c
+.c Continuation line for .TP header.
+.c
.de TP+
. br
. ns
-. TP \$1
+. TP \\$1
+..
+.c --------------------------------------------------------------------
+.c .TP_header ([<indent>])
+.c
+.c Start a multi-line header for a .TP-like paragraph
+.c
+.de TP_header
+. if (\\n[@+TP_level] < 0) \
+. Error .\\$0: wrong level.
+. nr @+TP_level +1
+. ie (\\n[.$] == 0) \
+. rr @+TP_indent
+. el \
+. nr @+TP_indent \\$1
+. nr @+TP_header 1
+..
+.c --------------------------------------------------------------------
+.c .TP_body ([<indent>])
+.c
+.c End a previous .TP-header and beging the body of the paragraph.
+.c
+.de TP_body
+. if !r@+TP_header \
+. Error .\\$0: no previous call of .TP_header
+. if (\\n[@+TP_level] <= 0) \
+. Error .\\$0: wrong level.
+. br
+. ie (\\n[.$] == 0) \{\
+. ie r@+TP_indent \{\
+. RS \\n[@+TP_indent]u
+. \}
+. el \
+. RS
+. \}
+. el \
+. RS \\$1u
+. rr @+TP_indent
+. rr @+TP_header
+. nr @+TP_body 1
+..
+.c --------------------------------------------------------------------
+.c TP_end ()
+.c
+.c End of former .TP_body paragraph.
+.c
+.de TP_end
+. if !r@+TP_body \
+. Error .\\$0: no previous .TP_body.
+. if (\\n[@+TP_level] <= 0) \
+. Error TP_end: wrong level.
+. nr @+TP_level -1
+. rr @+TP_indent
+. rr @+TP_header
+. rr @+TP_body
+. br
+. RE
..
-.ec
-.\" End of macro definitions
-.
-.
-.\" --------------------------------------------------------------------
-.\" Title
-.\" --------------------------------------------------------------------
.
-.TH GROFFER @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
-.SH NAME
-groffer \- display groff files and man\~pages on X and tty
+.\" End of macro definitions
.
.
.\" --------------------------------------------------------------------
@@ -259,92 +547,177 @@ groffer \- display groff files and man\~pages on X and tty
.
.ad l
.Synopsis groffer
-.[ShortOpt] Q
-.[ShortOpt] T device
-.[ShortOpt] W arg
-.[LongOpt] dpi resolution
-.[LongOpt] man
-.[LongOpt] manpath man_page_dirs
-.[LongOpt] no\*[@-]man
-.[LongOpt] title "'title in X mode'"
-.[LongOpt] tty
-.[LongOpt] xrdb X_resouce_options
+.RI [ mode_options ]
+.RI [ man_options ]
.RI [ groff_options ]
-.RI [ filespec
-.Text \*[Ellipsis]]
-.EndSynopsis
+.[--]
+.RI [ "filespec" "\*[Ellipsis]]"
+./Synopsis
.
.Synopsis groffer
-.ShortOpt h
-|
-.LongOpt help
-.EndSynopsis
+.Opt_alt - h -- help
+./Synopsis
.
.Synopsis groffer
-.ShortOpt v
-|
-.LongOpt version
-.EndSynopsis
+.Opt_alt - v -- version
+./Synopsis
+.
+.
+.TP
+.I mode_options
+These options determine and configure the display mode.
+.
+They are all compatible with the options in both
+.BR groff (@MAN1EXT@)
+and GNU
+.BR man (1).
.
.P
-where each element of the
+.RS
+.[Opt_alt] - P to_postprocessor
+.[Opt_alt] - Q -- source
+.[Opt_alt] - T -- device -- troff-device device
+.[Opt_alt] - W arg
+.[Opt_alt] - X
+.[Opt_alt] - Z -- ditroff -- intermediate-output
+.[Opt_alt] -- dpi value
+.[Opt_alt] -- mode display_mode
+.[Opt_alt] -- pager program
+.[Opt_alt] -- title string
+.[Opt_alt] -- tty
+.RE
+.
+.
+.TP
+.I man_options
+These options regulate whether and how man pages are searched.
+.
+They are compatible with the long options of the
+.I GNU man
+program.
+.
+.
+.P
+.RS
+.[Opt_alt] -- all
+.[Opt_alt] -- apropos
+.[Opt_alt] -- extension suffix
+.[Opt_alt] -- lang -- locale language
+.[Opt_alt] -- local-file
+.[Opt_alt] -- location -- where
+.[Opt_alt] -- man
+.[Opt_alt] -- manpath man_page_dirs
+.[Opt_alt] -- no-location
+.[Opt_alt] -- no-man
+.[Opt_alt] -- sections colon_list
+.[Opt_alt] -- systems comma_list
+.[Opt_alt] -- whatis
+.RE
+.
+The full set of long and short options of the GNU man program can be
+passed via the environment variable
+.Env_var $MANOPT ,
+see
+.BR man (1)
+if your system has GNU man installed.
+.
+.
+.TP
+.I groff_options
+can be any combination of short options from the
+.I groff
+program; the options that are not explicitly handled by groffer are
+transparently passed to groff.
+.
+Almost any letter in both lower and upper case represents some groff
+option, see
+.BR groff (@MAN1EXT@).
+.
+.
+.TP
.I filespec
-sequence has one of the following forms, where testing is done in the
-specified sequence.
+is a sequence of file names or template parameters for searching
+man\~pages, see
+.BR man (1),
+having one of the following forms.
+.
+.
+.RS
.
.TP 10m
.I filename
the path name of an existing file.
.
+.
.TP
-.ShortOpt
+.Short_opt
stands for standard input (can occur several times).
.
+.
.TP
.BI man: name ( section )
search the man\~page
.I name
-in
-.IR section ,
-the same as
-.IB name . section
-above
+in section\~\c
+.IR section .
+.
.
.TP
.BI man: name . section
-the manual page (man\~page)
+search the man\~page
.I name
-in
-.IR section ,
-see
-.BR man (1).
+in section\~\c
+.IR section .
+.
.
.TP
.BI man: name
search the man\~page
.I name
-in the lowest section.
+in the lowest available section.
+.
+.
+.TP
+.IB name ( section )
+search the man\~page
+.I name
+in section\~\c
+.IR section .
+.
.
.TP
.IB name . section
-the manual page (man\~page)
+search the man\~page
.I name
-in
-.IR section ,
-see
-.BR man (1).
+in section\~\c
+.IR section .
+.
.
.TP
-.BI other_name
-if not an existing file search the man\~page
-.I other_name
-in the lowest section.
+.I standard_section
+if this is `1', \*[Ellipsis], `9', `o', or `n' try to retrieve the
+next argument as a man\~page in this section.
+.
+.
+.TP
+.I name
+search for the man\~page
+.I name
+in the lowest available section.
+.
.
.P
No
.I filespec
parameters means standard input.
.
+.RE
+.
+.
+.P
+For details on the options, see section
+.BR OPTIONS .
+.
.
.\" --------------------------------------------------------------------
.SH DESCRIPTION
@@ -363,6 +736,18 @@ using the graphical viewer program
.BR gxditview (@MAN1EXT@),
otherwise text output is displayed in a pager on the terminal.
.
+.
+.P
+A search facility for manual pages (man\~pages) is provided.
+.
+Almost the whole functionality of the
+.I GNU man
+program was provided or suitably adapted.
+.
+This makes the groffer program a valuable tool on systems with a bad
+man program.
+.
+.
.P
The program always concatenates all input specified by the non-option
parameters of the calling command line, or standard input if none are
@@ -370,13 +755,6 @@ given.
.
Compressed standard input or files are decompressed on-the-fly.
.
-.P
-Moreover, groffer provides a search facility for manual pages
-(man\~pages).
-.
-This makes the groffer program a graphical extension of the
-.BR man (1)
-program.
.
.P
Normally, the input is run through the
@@ -384,12 +762,13 @@ Normally, the input is run through the
text processor before being displayed.
.
By using the option
-.ShortOpt Q ,
-the roff source code is displayed without being processed.
+.Short_opt Q ,
+the roff source code is displayed without formatting.
+.
.
.P
The
-.ShortOpt T
+.Short_opt T
option allows to produce output for any output devices provided by
groff.
.
@@ -412,135 +791,467 @@ program.
.\" --------------------------------------------------------------------
.
If your system does not support GNU long options you can use the
-.ShortOpt W
+.Short_opt W
to simulate long options.
.
POSIX has reserved this option for such uses.
.
+.
.P
-The following options are caught be groffer and have a special
+All
+.B groff
+options are valid for groffer.
+.
+The groff options that are transparently transferred to groff are not
+documented here.
+.
+The following options are caught by groffer and have a special
meaning.
.
-.OptDef h help
+.
+.Opt_def - h
Print usage message to standard error and exit.
.
-.OptDef Q source
+.
+.Opt_def - Q
Output the roff source code of the input files unprocessed.
.
-.OptDef T device devname
+.
+.Opt_def - P opt_or_arg
+Pass the argument as an option to the actual postprocessor, for
+example to
+.I gxditview
+when displaying in X.
+.
+If the postprocessor option needs to be preceded by a single or double
+minus sign then this prefix must also be specified in the argument to
+option
+.Short_opt P .
+.
+If the postprocessor option needs an argument this must be specified
+as the argument of another, directly following
+.Short_opt P
+option.
+.
+.
+.RS
+.
+.Opt_def - P \*[@i-]opt
+Pass
+.I \*[@i-]opt
+unchanged to the actual postprocessor.
+.
+.
+.Opt_def - P \*[@i--]opt
+Pass
+.I \*[@i--]opt
+unchanged to the actual postprocessor.
+.
+.
+.TP_header
+.Opt_element - P \*[@i-]opt\~\c
+.Opt_element - P arg
+.TP_body
+Pass
+.I \*[@i-]opt arg
+unchanged to the actual postprocessor.
+.TP_end
+.
+.
+.TP_header
+.Opt_element - P \*[@i--]opt\~\c
+.Opt_element - P arg
+.TP_body
+Pass
+.I \*[@i--]opt arg
+unchanged to the actual postprocessor.
+.TP_end
+.
+.RE
+.
+.
+See also section
+.BR EXAMPLES .
+.
+.
+.Opt_def - T devname
Use
.I devname
-as the output device, just like in plain groff;
-if this is
-.B X75
-the X output with 75 dpi is selected, with
-.B X100
-X output will have 100 dpi, which is the default anyway; all other
-devices generate output that was processed for the specified device;
-this is printed onto standard output without a pager.
-.
-.OptDef v version
+as the output device, just like in plain groff.
+.
+The allowed device names are listed in
+.BR groff (@MAN1EXT@).
+.
+All device names that do begin with the letter
+.I X
+force displaying in an X window using gxditview.
+.
+All other device names generate output for the specified device; this
+is printed onto standard output without a pager.
+.
+.
+.Opt_def - v
Print version information onto standard error.
.
-.OptDef W "" arg
-There are 3 applications for the
-.ShortOpt W
-option:
-.br
-.ShortOpt W
-.I longopt
-is equivalent to
-.LongOpt longopt
-.br
-.ShortOpt W
-.I 'longopt=arg'
-is equivalent to
-.LongOpt longopt
-.I 'arg'
+.
+.Opt_def - W arg
+There are two applications for this option.
+.
+If the argument
+.I arg
+starts with a
+.--
+(double minus sign), it represents a long option, which is useful on
+systems that do not support the GNU long options; otherwise it is
+passed as option
+.Short_opt W
+to groff (disable a warning), see
+.BR troff (@MAN1EXT@).
+.
+.
+.RS
+.
+.TP
+.Opt_alt - W "\*[@i--]longopt"
+is equivalent to the groffer long option
+.Long_opt longopt
+without an argument.
+.
+.
+.TP_header
+.Opt_alt - W "\*[@i--]longopt\f[CW]=\f[]optarg"
.br
-.ShortOpt W
-.I warning
-is equivalent to the groff option
-.ShortOpt W
+.Opt_alt - W "\*[@i--]longopt"
+.Opt_alt - W optarg
+.TP_body
+are both equivalent to the groffer long option
+.Long_opt longopt
+with the argument
+.IR optarg .
+.TP_end
+.
+.
+.TP
+.Opt_alt - W warning
+is equivalent to the groff/troff option
+.Short_opt W
.I warning
-and is internally sent to groff.
+(disable the warning named
+.IR warning );
+internally, this is sent transparently to groff.
+.
+More exactly, an argument to
+.Short_opt W
+that is supposed to represent long options must always be specified
+together with a leading
+.--
+(double minus); an argument to the option must either be appended to
+the long option with a separating \f[CB]=\f[] (equals sign) or goes as
+argument to another
+.Short_opt W
+option.
+.
+.
+.P
+An argument to
+.Short_opt W
+that does not start with a leading
+.--
+(double minus) is interpreted as a groff warning option.
+.
+.RE
+.
+.
+.Opt_def - X
+Force displaying in an X window using gxditview.
+.
+This option was adapted from groff.
+.
+.
+.Opt_def - Z
+Display the groff intermediate output instead of the formatted input;
+equivalent to
+.Opt_alt -- mode Z .
+.
+The short option
+.Short_opt Z
+is inhereted from
+.BR groff (@MAN1EXT@) ,
+while the name of the long option
+.Long_opt ditroff
+originates from
+.BR man (1)
+and was only implemented for compatibility.
+.
+.
+.Opt_def -- all
+In searching man pages, retrieve all suitable ones.
+.
+.
+.Opt_def -- apropos
+Instead of displaying, start the `apropos' command for searching
+within man page descriptions; only kept for compatibility with `man'.
+.
+.
+.Opt_def -- bg color
+Set background color of display window.
+.
+The argument is an X color name, see
+.BR (1)
+for details.
+.
+If the actual display mode is not X then this option is ignored.
+.
.
-.OptDef "" dpi "resolution"
-Set resolution of the X viewer.
+.Opt_def -- display X-diplay
+Set the X display on which gxditview should be started, see
+.BR (1)
+for details.
+.
+If the actual display mode is not X then this option is ignored.
+.
+.
+.Opt_def -- ditroff
+Eqivalent to
+.Short_opt Z .
+This is kept for compatibiliy with GNU
+.BR man (1).
+.
+.
+.Opt_def -- dpi value
+Set resolution of the X viewer
+.BR gxditview (@MAN_EXT1@).
.
The only supported dpi values are
.B 75
and
.BR 100 .
-The writings
-.B 75dpi
-and
-.B 100dpi
-are also recognized as a valid argument.
+The resolution can also be forced by specifying option
+.Opt_alt - TX value .
+.
+If the actual display mode is not X then this option is ignored.
+.
+.
+.Opt_def -- extension suffix
+Restrict man\~page search to file names that have
+.I suffix
+appended to their section element.
+.
+For example, in the file name
+.I /usr/share/man/man3/terminfo.3ncurses.gz
+the man\~page extension is
+.IR ncurses .
+.
+Originates from GNU
+.IR man .
+.
+.
+.Opt_def -- fg color
+Set foreground color of display window.
+.
+The argument is an X color name, see
+.BR (1)
+for details.
+.
+If the actual display mode is not X then this option is ignored.
+.
+.
+.Opt_def -- device
+Eqivalent to
+.Short_opt T .
+.
+.
+.Opt_def -- geometry size_pos
+Set the geometry of the display window, that means its size and its
+starting position.
+.
+See
+.BR (1)
+for details on the syntax of the argument.
.
-.OptDef "" man
+If the actual display mode is not X then this option is ignored.
+.
+.
+.Opt_def -- help
+Eqivalent to
+.Short_opt h .
+.
+.
+.Opt_def -- intermediate-output
+Equivalent to
+.Short_opt Z .
+.
+.
+.Opt_def -- lang language
+.
+Set the language for man pages.
+.
+.
+.Opt_def -- location
+Print the location of the retrieved files to standard error.
+.
+.
+.Opt_def -- locale language
+.
+Equivalent to
+.Long_opt lang .
+.
+This option originates from GNU
+.BR man (1).
+.
+.
+.Opt_def -- man
Check the non-option command line arguments (filespecs) first on being
man\~pages, then whether they represent an existing file.
.
By default, a filespec is first tested if it is an existing file.
.
-.OptDef "" manpath "'dir1 dir2 \*[Ellipsis]'"
-.br
-.ns
-.OptDef "" manpath "'dir1:dir2:\*[Ellipsis]'"
+.
+.Opt_def -- manpath "'dir1:dir2:\*[Ellipsis]'"
Use the specified search path for retrieving man\~pages instead of the
program defaults.
.
If the argument is set to the empty string "" the search for man\~page
is disabled.
.
-.OptDef "" no\*[@-]man
+.
+.Opt_def -- mode value
+.
+Set the display mode.
+.
+The following mode values are recognized:
+.
+.
+.RS
+.
+.TP
+.B auto
+Let groffer choose where to display; this is the default.
+.
+.
+.TP
+.B tty
+Display in a text terminal; same as
+.Long_opt tty .
+.
+.
+.TP
+.B X
+Display in a X window; same as
+.Short_opt X .
+.
+.
+.TP
+.BR Q
+Display source code; same as
+.Short_opt Q .
+.
+.
+.TP
+.B source
+Display source code; same as
+.Short_opt Q .
+.
+.
+.TP
+.B Z
+Display groff intermediate output; same as
+.Short_opt Z .
+.
+.
+.TP
+.B intermediate-output
+Display groff intermediate output; same as
+.Short_opt Z .
+.
+.
+.TP
+.B default
+Display in the default manner, being actually
+.IR auto .
+Useful for restoring default behavior when other options are active.
+.
+.RE
+.
+.
+.Opt_def -- no-location
+Do not display the location of retireved files; this resets a former
+call to
+.Long_opt location .
+.
+.
+.Opt_def -- no-man
Do not check for man\~pages.
.
-.OptDef "" title "'some title of your own'"
+.
+.Opt_def -- pager
+Set the pager program in tty mode; default is
+.IR less .
+.
+.
+.Opt_def -- sections
+Restrict searching for man pages to the given
+.IR sections ,
+a colon-separated list.
+.
+.
+.Opt_def -- source
+Equivalent to
+.Short_opt Q .
+.
+.
+.Opt_def -- systems
+Search for man pages for the given operating systems; the argument
+.I systems
+is a comma-separated list.
+.
+.
+.Opt_def -- title "'this is my title'"
Set the title for the diplay window.
.
This effects only the X mode.
.
-.OptDef "" tty
-Use output on a text pager even when in X.
.
-.OptDef "" xrdb "'\*[@-]\fIopt1 arg1\fP \*[@-]\fIopt2 arg2 ...\fP'"
-Pass the argument unchanged to the X display program gxditview of
-groffer.
+.Opt_def -- to-postproc opt_or_arg
+Eqivalent to
+.Short_opt P .
.
-All options of
-.BR gxditview (@MAN1EXT@)
-are allowed; this inludes
-.ShortOpt bg
-(background color),
-.ShortOpt display
-(the X display to be used),
-.ShortOpt geometry
-(size and position of the window),
-.ShortOpt fg
-(foreground color),
-.ShortOpt fn
-(font),
-.ShortOpt xrm
-(set general X resource),
-and many more, see
-.BR X (1).
-Several
-.LongOpt xrdb
-options can be specified or several resource options can be stuffed
-into a single
-.LongOpt xrdb
-option.
.
-But note that this is not correctly parsed when the argument for a
-resource option contains a space or an embedded single quote character,
-even when they are escaped.
+.Opt_def -- troff-device
+Eqivalent to
+.Short_opt T .
+This option is only kept for compatibility with GNU
+.BR man (1).
+.
+.
+.Opt_def -- tty
+Choose tty display mode, that means use output on a text pager even
+when in X; eqivalent to
+.Long_opt mode\~tty .
+.
+.
+.Opt_def -- version
+Eqivalent to
+.Short_opt v .
+.
+.
+.Opt_def -- whatis
+Instead of displaying the content, get the one-liner description from
+the retrieved man page files \[em] or say that it is not a man page.
+.
+.
+.Opt_def -- where
+Eqivalent to
+.Long_opt location .
+.
.
.TP
-.LongOpt \" just `--'
+.--
Signals the end of option processing; all remaining arguments are
-interpreted as filespec parameters.
+interpreted as
+.I filespec
+parameters.
+.
.
.P
Besides these, groffer accepts all arguments that are valid for the
@@ -554,174 +1265,229 @@ and much more can be manually specified.
.
.
.\" --------------------------------------------------------------------
-.SH FEATURES
+.SH "OUTPUT MODES"
.\" --------------------------------------------------------------------
.
-This chapter describes the details of the features of the groffer
-program in detail.
+By default, the groffer program formats the input and then
+automatically chooses a suitable display mode, but the user can also
+choose between the following modes:
+.
+.Topic
+graphical display in X window with gxditview,
+.
+.Topic
+text display in a pager on the text terminal (tty),
+.
+.Topic
+generate output for a given device,
+.
+.Topic
+source code streamed onto standard output,
+.
+.Topic
+the groff intermediate output streamed onto standard output (for
+debugging).
+.
+.
+.P
+If no mode selecting option was provided, the input is formatted and
+diplayed; displaying on X is tried first, then the paging on the text
+terminal.
+.
+The other modes cannot be reached automatically, they must be
+specified by the user.
.
.
.\" --------------------------------------------------------------------
-.SS "Output modes"
+.SS "Displaying in X window"
.\" --------------------------------------------------------------------
.
-The groffer program provides 4 different operation modes,
-.Topic
-graphical display in X,
+The X mode can be chosen by the following methods:
+.
+.
.Topic
-text display in a pager,
+Automatically, if the environment variable
+.Env_var $DISPLAY
+is set and no other mode was forced;
+.
+.
.Topic
-output for a given device streamed onto standard output.
+by the options
+.Short_opt X ,
+.Long_opt X ,
+or
+.Opt_alt -- mode X ;
+.
+.
.Topic
-source code streamed onto standard output.
+by specifying one of the groff X* devices with option
+.Short_opt T .
+.
.
.P
-Normally, the input is processed by groff and then displayed in a
-viewer, either in X or on a text terminal.
-.
-If the environment variable
-.EnvVar $DISPLAY
-is set or one of the options
-.ShortOpt X ,
-.ShortOpt TX100 ,
+In X mode, the formatted input is displayed with the
+.BR gxditview (@MAN1EXT@)
+program, which can use two resolutions,
+.I 75 dpi
or
-.ShortOpt TX75
-is set the
-.B gxditview
-program will be started on the X terminal that is specified by the
-.EnvVar $DISPLAY
-variable.
+.IR "100 dpi" ,
+where
+.I dpi
+means
+.IR "dots per inch" .
+By default, groffer follows groff, which actually chooses 75 dpi.
+.
+.
+.P
+This resolution can be changed to 100 dpi by one of the following
+options:
+.
+.Topic
+.Opt_alt -- dpi\~100
+.
+.Topic
+.Opt_alt - T\~X100
+.
+.Topic
+.Opt_alt - T\~X100-12
+.
+.Topic
+.Opt_alt - P\~resolution - P\~100
+.
.
.P
-X provides two resolutions, the old value
-.B 75 dpi
-and the more modern value of
-.BR "100 dpi" ,
-which should be available on almost all modern computers.
+By replacing
+.I 100
+by
+.I 75
+in these options, the corresponding 75 dpi mode is activated.
.
-By default, the X resolution of 100 dpi is used if there are
-corresponding fonts available; this is checked by questioning the X
-font path using the shell command
-.ShellCommand xset q
.
.P
-The lower resolution can be explicitly specified by the option
-.ShortOpt TX75 ;
-the option
-.ShortOpt X
-is inherited from groff, actually it chooses 75 dpi as well.
+The resolution can be preset to a fixed value for all calls to groffer
+by including the option
+.Long_opt dpi
+into the environment variable
+.Env_var GROFFER_OPT .
+For example,
+.Shell_cmd "GROFFER_OPT='--dpi 100'"
+.Shell_cmd "export GROFFER_OPT"
+sets 100 dpi as default resolution for all groffer runs in this shell
+and its subshells.
+.
.
.P
+Note that the
+.Opt_alt - TX ...
+options force displaying in X, while the
+.Long_opt dpi
+is ignored when not displaying in X.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Displaying on a tty"
+.\" --------------------------------------------------------------------
+.
If the variable
-.EnvVar $DISPLAY
+.Env_var $DISPLAY
is not set or empty groffer assumes that it should produce output on a
text terminal.
.
+This mode can be enforced by the options
+.Long_opt tty
+or
+.Opt_alt -- mode tty .
+.
+.
+.P
In the actual implementation, the groff output device
.I latin1
is chosen and the processed output is piped into a pager program.
.
-The pager (together with options) can be specified by the environment
-variable
-.EnvVar $PAGER .
+The pager can be specified by the environment variable
+.Env_var $PAGER .
If this is not set or empty the
.BR less (1)
program is used as the default pager.
.
-.P
-Besides the two display modes above, for X and text pager, there are
-two more operating modes.
.
-These are streaming modes, that means both of them print to standard
-output without using a pager.
+.\" --------------------------------------------------------------------
+.SS "Displaying roff Source Files"
+.\" --------------------------------------------------------------------
+.
+Instead of the formatted output, it is also possible to have the
+source code displayed.
+.
+This mode must deliberately be requested by one of the options
+.Short_opt Q ,
+.Long_opt source ,
+.Long_opt "mode Q" ,
+.Long_opt "mode source" .
+.
.
.P
+The retrieved source files are decompressed and streamed to standard
+output without any pager or further processing.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Output for a specific Device"
+.\" --------------------------------------------------------------------
+.
If a device other than the
.B X
devices is specified with the
-.ShortOpt T
-option groffer assumes that the user wants to pipe the output into
-some kind of postprocessor.
+.Short_opt T
+then the input is formatted for this device and then send to standard
+output without further actions.
+.
+This enables the user save the generated output into a file of pipe it
+into some kind of postprocessing.
.
-The reason for this is that the output of many devices, such as
+.
+.P
+Output for some devices, such as
.BR ps ,
or
.B dvi
-is not directly displayable.
-.
-.P
-The user may also choose to read the source code of the input by
-specifying the
-.ShortOpt Q
-option.
-.
-Again, no output pager is used to allow piping.
+is not directly displayable without a special viewer.
.
.
.\" --------------------------------------------------------------------
-.SS Decompression
+.SH "FILE PARAMETERS"
.\" --------------------------------------------------------------------
.
-The program has a decompression facility.
-.
-If standard input or a file that is specified as a command line
-parameter was compressed by a format that is understood by
-.BR gzip (1)
-it is decompressed on-the-fly.
-.
-This includes the GNU
-.B .gz
-and the traditional
-.B .Z
-compression.
-.
-The program displays the concatenation of all decompressed input in
-the sequence that was specified on the command line.
+The non-option command line parameters determine which files should be
+displayed.
.
.
.\" --------------------------------------------------------------------
-.SS "Man\~Pages"
+.SS "Filespecs"
.\" --------------------------------------------------------------------
.
-The groffer program provides a search facility for system manual pages
-(man\~pages).
+The default behavior of groffer is to first test whether the file
+parameter is represents a local file; if not, it is assumed to
+represent a filespec for searching one or more man\~page.
.
-So it can be used as a replacement or a grapical extension for the
-.BR man (1)
-program.
+This behavior can be modified by options.
.
-.P
-Preformatted man\~pages (cat\~pages) are intentionally not supported,
-because groffer is a roff program, not a text pager.
.
-With the excellent performance of the actual computers, the
-preformatted man\~pages aren't necessary any longer.
+.TP
+.Long_opt man
+forces to interpret all file parameters as filespecs for searching
+man\~pages.
.
-Due to their inflexible nature, they provoke some trouble with
-changing line lengths.
+.TP
+.Long_opt no-man
+.TP+
+.Long_opt local_file
+disable the man searching; so only local files are displayed.
.
-These cat\~pages should be disabled with the man\~program, or be
-circumvented by using groffer instead.
.
.P
-The groffer program determines if the user wanted to diplay a man\~page
-by the following methods.
-.
-If a non-option command line parameter does not represent a valid file
-name groffer suspects whether this could be a system manual page
-(man\~page).
-.
The following parameter formats are recognized to represent a wanted
man\~page.
.
-.TP
-.IB name . section
-the man\~page
-.I name
-in
-.IR section .
-The corresponding command with the man program would be
-.ShellCommand man \f(CIsection name\fP
.
.TP
.BI man: name ( section )
@@ -731,13 +1497,25 @@ represent the man\~page
in
.IR section .
.
+.
.TP
.BI man: name
search the man\~page
.I name
in the lowest section.
The corresponding command with the man program would be
-.ShellCommand man \f(CIname\fP
+.Shell_cmd man\~ name
+.
+.
+.TP
+.IB name . section
+the man\~page
+.I name
+in
+.IR section .
+The corresponding command with the man program would be
+.Shell_cmd man\~ section\~name
+.
.
.TP
.I name
@@ -746,78 +1524,291 @@ if
is not an existing file search for the man\~page
.I name
in the lowest section just like
-.ShellCommand man \f(CIname\fP
+.Shell_cmd man\~ name
+.
+.
+.TP
+.I section name
+Even this curious construct known from the various
+.I man
+programs is handled.
+.
+For example,
+.Shell_cmd "groffer 7 groff"
+was modelled according to
+.Shell_cmd "man 7 groff"
+retrieves the man\~page named
+.I groff
+in section 7.
+.
+Only a few standard section names are accepted, being actually the
+number sections
+.I 1, 2, 3, 4, 5, 6, 7, 8,
+and
+.IR 9,
+and the lower case letters
+.I `o'
+and
+.IR `n' .
+.
+.
+.P
+If neither a local file nor a man\~page was retrieved for some file
+parameter a warning is issued on standard error, but processing is
+continued.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Man\~Page Searching"
+.\" --------------------------------------------------------------------
+.
+The groffer program provides a search facility for system manual pages
+(man\~pages).
+.
+All long options, all environment variables, and most of the
+functionality of the GNU
+.BR man (1)
+program were implemented.
+.
+.
+.P
+Preformatted man\~pages (cat\~pages) are intentionally excluded from
+the search because groffer is a roff program that wants to format by
+its own, not spit out stuff that was digested previously by someone
+else.
+.
+With the excellent performance of the actual computers, the
+preformatted man\~pages aren't necessary any longer.
+.
+Due to their inflexible nature, they tend to provoke some trouble with
+changing line lengths and different environments in networks.
+.
.
.P
The algorithm for retrieving man\~pages uses five search methods.
.
They are successively tried until a method works.
.
+.
.Topic
The search path can be manually specified by using the option
-.LongOpt manpath .
+.Long_opt manpath .
An empty argument disables the man\~page searching.
.
This overwrites the other methods.
.
+.
.Topic
-The best results are obtained when the
-.BR man (1)
-program has the command line option
-.ShortOpt w
-to determine the path of a man\~page.
+If this is not available the environment variable
+.Env_var $MANPATH
+is searched.
.
-This is available in the GNU version of
-.IR man .
.
.Topic
-If this isn't available the environment variable
-.EnvVar $MANPATH
-is searched.
+If this is empty, the program tries to read it from the environment
+variable
+.Env_var $MANOPT .
.
.Topic
-If this is empty the
+If this does not work, the
.BR manpath (1)
program for determining a path of man directories is tried.
.
+.
.Topic
If this does not work a reasonable default path is searched for
man\~pages.
.
+.
+.P
+After this, the path elements for the language (locale) and operating
+system specific man\~pages are added to the man\~path; their sequence
+is determined automatically.
+.
+For example, both
+.I /usr/share/man/linux/fr
+and
+.I /usr/share/man/fr/linux
+for french linux man\~pages are found.
+.
+The language and operating system names are determined from both
+environment variables and command line options.
+.
+.
+.P
+The locale is determined like in GNU man, that is from highest to
+lowest precedence:
+.Topic
+.Long_opt lang
+and
+.Long_opt locale
+.
+.Topic
+.Env_var $GROFFER_OPT
+.
+.Topic
+.Env_var $MANOPT
+.
+.Topic
+.Env_var $LCALL
+.
+.Topic
+.Env_var $LC_MESSAGES
+.
+.Topic
+.Env_var $LANG .
+.
+.
+.P
+The language locale is usually specified in the POSIX 1003.1 based
+format:
+.P
+\f[I]<language>\f[][\f[CB]_\f[]\f[I]<territory>\f[][\f[CB].\f[]\
+\f[I]<character-set>\f[][\f[CB],\f[]\f[I]<version>\f[]]]].
+.
+.
+.P
+If no man\~pages for a complicated locale are found the country part
+consisting of the first two characters (without the `\f[CB]_\f[]',
+`\f[CB].\f[]', and `\f[CB],\f[]', parts) of the locale is searched as
+well.
+.
+.
+.P
+If still not found the corresponding man\~page in the default language
+is used instead.
+.
+As usual, this default can be specified by one of \f[CW]C\f[] or
+\f[CW]POSIX\f[].
+.
+The man\~pages in the default language are usually in English.
+.
+.
+.P
+Several operating systems can be given by appending their names,
+separated by a comma.
+.
+This is then specified by the environment variable
+.Env_var $SYSTEM
+or by the command line option
+.Long_opt systems .
+The precedence is similar to the locale case above from highest to
+lowest precedence:
+.
+Topic
+.Long_opt systems
+.
+.Topic
+.Env_var $GROFFER_OPT
+.
+.Topic
+.Env_var $MANOPT
+.
+.Topic
+.Env_var $SYSTEM .
+.
+.
+.P
+When searching for man\~pages this man\~path with the additional
+language and system specific directories is used.
+.
+.
+.P
+The search can further be restricted by limiting it to certain
+sections.
+.
+A single section can be specified within a filespec, several sections
+as a colon-separated list in command line option
+.Long_opt sections
+or environment variable
+.Env_var $MANSECT .
+.
+When no section was specified a set of standard sections is searched
+until a suitable man\~page was found.
+.
+.
+.P
+Finally, the search can be restricted to a so-called
+.IR extension .
+This is a postfix that acts like a subsection.
+.
+It can be specified by
+.Long_opt extension
+or environment variable
+.Env_var $EXTENSION .
+.
+.
.P
-In all cases, language-specific man\~pages are searched first if the
-environment variable
-.EnvVar $LANG
-is set.
+For further details on man\~page searching, see
+.BR man (1).
.
.
.\" --------------------------------------------------------------------
-.SS "Source Code"
+.SS Decompression
.\" --------------------------------------------------------------------
.
-Usually, groffer displays the input in formatted form.
+The program has a decompression facility.
.
-When, however, the option
-.ShortOpt Q
-is specified on the command line the source code of the input is
-displayed instead; more exactly, it is printed onto standard output
-as is, without any pager or other formatter.
+If standard input or a file that was retrieved from the command line
+parameters is compressed with a format that is supported by
+.BR gzip (1)
+it is decompressed on-the-fly.
.
-.P
-In this source code displaying mode, the decompression and man\~page
-search features are still active.
+This includes the GNU
+.B .gz
+and the traditional
+.B .Z
+compression.
+.
+The program displays the concatenation of all decompressed input in
+the sequence that was specified on the command line.
.
-As no formatter or X window program is run in this mode all opotions
-different from
-.ShortOpt Q
-are silently ignored.
.
.\" --------------------------------------------------------------------
.SH "ENVIRONMENT"
.\" --------------------------------------------------------------------
.
+The groffer programs supports many system variables, most of them by
+courtesy of other programs.
+.
+All environment variables of
+.BR groff (@MAN1EXT@)
+and GNU
+.BR man (1)
+and some standard system variables are honored.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Native groffer Variables"
+.\" --------------------------------------------------------------------
+.
.TP
-.EnvVar $DISPLAY
+.Env_var GROFFER_OPT
+Store options for a run of groffer.
+.
+The options specified in this variable are overridden by the options
+given on the command line.
+.
+The content of this variable is run through the shell builitin `eval';
+so arguments containing white-space or special shell characters should
+be quoted.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "System Variables"
+.\" --------------------------------------------------------------------
+.
+The groffer program is a shell script that is run through
+.BR /bin/sh ,
+which can be internally linked to programs like
+.BR bash (1).
+The corresponding system environment is automatically effective.
+.
+The following variables have a special meaning for groffer.
+.
+.
+.TP
+.Env_var DISPLAY
If this variable is set this indicates that the X window system is
running.
.
@@ -829,29 +1820,157 @@ be used to start the graphical groffer on a remote X terminal.
.
For example, depending on your system, groffer can be started on the
second monitor by the command
-.ShellCommand DISPLAY=:0.1 groffer what.ever &
+.Shell_cmd DISPLAY=:0.1\~groffer\~ what.ever &
+.
+.
+.TP
+.Env_var LC_ALL
+.TP+
+.Env_var LC_MESSAGES
+.TP+
+.Env_var LANG
+If one of these variables is set (in the above sequence), its content
+is interpreted as the locale, the language to be used, especially when
+retrieving man\~pages.
+.
+A locale name is typically of the form
+.IR language [\c
+.B _\c
+.IR territory [\c
+.B .\c
+.IR codeset [\c
+.B @\c
+.IR modifier ]]],
+where
+.I language
+is an ISO 639 language code,
+.I territory
+is an ISO 3166 country code, and
+.I codeset
+is a character set or encoding identifier like ISO-8859-1 or UTF-8;
+see
+.BR setlocale (3).
+.
+The locale values\~\c
+.B C
+and
+.B POSIX
+stand for the default, i.e. the man\~page directories without a
+language prefix.
+.
+This is the same behavior as when all 3\~variables are unset.
+.
.
.TP
-.EnvVar $PAGER
+.Env_var PAGER
This variable can be used to set the pager for the tty output.
.
For example, to disable the use of a pager completely set this
variable to the
.BR cat (1)
program
-.ShellCommand PAGER=cat groffer anything
+.Shell_cmd PAGER=cat\~groffer\~ anything
+.
.
.TP
-.EnvVar $MANPATH
-if set, this variable contains the directories in which the man\~page
-trees are stored.
+.Env_var PATH
+All programs within the groffer shell script are called without a
+fixed path.
+.
+Thus this environment variable determines the set of programs used
+within the run of groffer.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Groff Variables"
+.\" --------------------------------------------------------------------
+.
+The groffer program internally calls groff, so all environment
+variables documented in
+.BR groff (@MAN1EXT@)
+are internally used within groffer as well; see there for details.
+.
+The following variables have a direct meaning for the groffer program.
.
.TP
-.EnvVar $LANG
-
-if set, this variable contains the directories in which the man\~page
+.Env_var GROFF_TMPDIR
+If the value of this variable is an existing, writable directory,
+groffer uses it for storing its temporary files, just as groff does.
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Man Variables"
+.\" --------------------------------------------------------------------
+.
+Parts of the functionality of the man program were implemented in
+groffer; support for all environment variables documented in
+.BR man (1)
+was added to groffer, but the meaning was slightly modified due to the
+different approach in groffer; but the user interface is the same.
+.
+The man environment variables can be overwritten by options provided
+with
+.Env_var MANOPT ,
+which in turn is overwritten by the command line.
+.
+.
+.TP
+.Env_var EXTENSION
+Restrict the search for man\~pages to files having this extension.
+.
+This is overridden by option
+.Long_opt extension ;
+see there for details.
+.
+.
+.TP
+.Env_var MANOPT
+This variable contains options as a preset for
+.BR man (1).
+As not all of these are relevant for groffer only the essential parts
+of its value are extracted.
+.
+The options specified in this variable overwrite the values of the
+other environment variables taht are specific to man.
+.
+All options specified in this variable are overridden by the options
+given on the command line.
+.
+.
+.TP
+.Env_var MANPATH
+If set, this variable contains the directories in which the man\~page
trees are stored.
.
+This is overridden by option
+.Long_opt manpath .
+.
+.
+.TP
+.Env_var MANSECT
+If this is a colon separated list of section names, the search for
+man\~pages is restricted to those manual sections in that order.
+.
+This is overridden by option
+.Long_opt sections .
+.
+.
+.TP
+.Env_var SYSTEM
+If this is set to a comma separated list of names these are interpreted
+as man\~page trees for different operating systems.
+.
+This variable can be overwritten by option
+.Long_opt systems ;
+see there for details.
+.
+.
+.P
+The environment variable
+.Env_var MANROFFSEQ
+is ignored by groffer because the necessary preprocessors are
+determined automatically.
+.
.
.\" --------------------------------------------------------------------
.SH "EXAMPLES"
@@ -859,63 +1978,75 @@ trees are stored.
.
The usage of groffer is very easy.
.
-Usually, it is just called with a filename or man\~page.
+Usually, it is just called with a file name or man\~page.
.
The following examples, however, show that groffer has much more fancy
capabilities.
.
+.
.TP
-.ShellCommand groffer docs/meintro.ms
+.Shell_cmd "groffer\~/usr/local/share/doc/groff/meintro.ms"
Format and display the file
.I meintro.ms
-in directory
-.I ./docs
+in the directory
+.IR /usr/local/share/doc/groff ,
using a graphical viewer when in X window, or the
-.B less
+.BR less (1)
pager program when not in X.
.
-The file must exist in this case because the slash character
-.RB ` / '
-suggests that this cannot be a man\~page.
.
.TP
-.ShellCommand groffer groffer.1 \[cq]less(1)\[cq] man:roff
+.Shell_cmd "groffer\~groff.7\~groff\~\[cq]troff(1)\[cq]\~man:gxditview"
.
-If none of the arguments is an existing file then lookup the three
+If none of the arguments is an existing file then lookup the four
man\~pages named
-.I groffer
-(in section\~1),
-.I less
+.I groff
+(in section\~7),
+.I groff
+(automatic search, should be found in section\~1),
+.I troff
(in section\~1),
+.I gxditview
+(automatic search, should be found in section\~1),
and
.I roff
(in the section with the lowest number, being\~7 in this case).
.
+The quotes around
+.I \[cq]troff(1)\[cq]
+are necessary because the paranthesis are special shell characters;
+escaping them with a backslash character
+.I \[rs](
+and
+.I \[rs])
+would be possible, too.
+.
The formatted files are concatenated and displayed in one piece.
.
+.
.TP
-.ShellCommand LANG=de groffer\~\c
-.ShellLongOpt man\~\c
-.ShellLongOpt source\~\c
-.ShellShortOpt T\~\c
-.Text html\~ls\~>ls.html
+.Shell_cmd "LANG=de\~groffer\~--man\~-Thtml\~ls\~>ls.html"
.
-Lookup the source file of the German manual page for the
+Lookup the German manual page for the
.B ls
-program, decompress it, convert it into htlm format and write the
+program, decompress it, convert it into html format and write the
result into the file
-.IR ls.html
+.IR ls.html .
+The option
+.Long_opt man
+guarantees that the man\~page is retrieved, even when a local file
+.I ls
+exists in the actual directory.
+.
.
.TP
-.ShellCommand cat stdin.1.gz | PAGER=more groffer\~\c
-.ShellLongOpt tty\~\c
-.Text a.ms\~\c
-.ShellShortOpt \~\c
-.Text b.ms.Z
+.Shell_cmd "cat\~stdin.1.gz\~|"
+.TP+
+.Shell_cmd+ "PAGER=more\~groffer\~--tty\~a.ms\~-\~b.ms.Z"
.
Display existing files
.IR a.ms ,
-.IR stdin.1.gz (decompress),
+.IR the standard input (being here the file stdin.1.gz) (decompress),
and
.IR b.ms.Z (decompress)
in this sequence on the text terminal, using
@@ -923,50 +2054,56 @@ in this sequence on the text terminal, using
as pager program instead of the default pager
.BR less .
.
+.
.TP
-.ShellCommand groffer\~\c
-.ShellShortOpt Wno\c
-.ShellShortOpt man\~\c
-.ShellShortOpt Wtitle=hello\~\c
-.ShellShortOpt Wmac\~\c
-.Text groff.1
-.
-Assume that
-.I groff.1
-is not meant to denote a man\~page, but an existing file
-in the current directory.
-.
-Process this file with the
-.RI ` mac '
-warnings disabled and display the result using
-.RI ` hello '
-as the viewer window's title.
+.Shell_cmd "groffer\~-X\~-W--title\~-W\~hello\~-W\~mac\~file"
.
The first two
-.option W
-options simulate long options; but as
+.Short_opt W
+options simulate groffer's long option
+.Long_opt title
+with its argument
+.IR hello .
+.
+But as
.I mac
-is not a long option for groffer it is passed unchanged to groff,
-where it disables the specified warnings.
+does not start with a minus sign, the third
+.Short_opt W
+option is passed unchanged to
+.BR groff (@MAN1EXT@),
+where it disables the warning named
+.IR mac .
+.
+The retrieved file is processed with the
+.RI ` mac '
+warnings disabled and the result is displayed in X window with the
+default resolution, using
+.RI ` hello '
+as the viewer window's title.
.
This command is equivalent to
-.ShellCommand groffer\~\c
-.ShellLongOpt title=hello\~\c
-.ShellLongOpt man\~\c
-.ShellShortOpt W\~\c
-.Text mac groff.7
+.Shell_cmd "groffer\~-X\~--title=hello\~-Wmac\~file"
+.
.
.TP
-.ShellCommand echo\~\[rs]fIgroffer\[rs]fP\~is\~\[rs]fBfat\[rs]fP |\&
+.Shell_cmd "echo\~'\[rs]f[CB]WOW!'\~|"
.TP+
-.ShellCommand groffer\~\c
-.ShellLongOpt xrdb=\[cq]\c
-.ShellShortOpt bg\~\c
-.Text red\~\c
-.ShellShortOpt fg\~\c
-.Text yellow\[cq]
+.Shell_cmd+ "groffer TX100 --bg red --fg yellow --geometry 200x100"
+.
+Display \f[CB]WOW!\f[] in a small window in constant-width bold font,
+using color yellow on red background.
.
-This looks a bit strange, try it :\-)
+If your shell does not have long options the options must be written as
+.br
+\f[CW]-TX100\~\:-W--bg\~\:-Wred\~\:-W--fg\~\:-Wyellow\~\:-W\c
+--geometry\\~\:200x100\f[].
+.br
+The equivalent options when using
+.Short_opt P
+are
+.br
+\f[CW]-TX100\~\:-P-bg\~\:-Pred\~\:-P-fg\~\:-Pyellow\~\:-P\c
+-geometry 200x100\f[].
.
.
.\" --------------------------------------------------------------------
@@ -975,25 +2112,45 @@ This looks a bit strange, try it :\-)
.
The
.B groffer
-shell script should be compatible to both POSIX and GNU.
+shell script is compatible to both POSIX and GNU.
.
POSIX compatibility refers to
.B P1003.2/D11.2
of September 1991.
.
+The script uses only a quite restricted set of shell language elements
+and shell utilities that is common to all POSIX versions; it should
+work on most actual commercial and free operating systems.
+.
+.
+.P
+Common implementations of the POSIX shell
+.BR sh (1)
+include
+.BR bash (1),
+.BR ksh (1),
+and others.
+.
+Free POSIX compatible shells and shell utilities for most operating
+systems are available at the
+.URL http://\:www.gnu.org/software/ "GNU software archive" .
+.
+.
.P
-This document describes the behavior on GNU systems.
+On systems without GNU
+.BR getopt (1),
+long options might not be available.
.
-Due to the limitations of POSIX as compared to GNU, not all features
-of groffer are available on non-GNU systems.
+In these cases, the groffer option
+.Short_opt W
+can be used to specify long options nevertheless; the option character
+.B W
+was reserved by the POSIX standard for applications like this.
.
-This includes arguments with embedded space characters, and the search
-capabilities of man\~pages.
.
.P
The groffer program can handle option arguments and file names that
-contain space characters, but mutliple space characters are flattened
-to a single space character.
+contain any white space characters.
.
.
.\" --------------------------------------------------------------------
@@ -1005,6 +2162,11 @@ to a single space character.
the GNU roff program.
.
.TP
+.BR troff (@MAN1EXT@)
+details on some options, environment variables and the warnings used
+in groff.
+.
+.TP
.BR grog (@MAN1EXT@)
tries to guess the groff command line options for given input files.
.
@@ -1022,9 +2184,15 @@ decompression of .gz or .Z files.
.BR man (1)
the standard way to diplay man\~pages.
.
+The
+.I man
+options and environment variables that are supported by groffer refer
+to
+.IR "GNU man" .
+.
.
.\" --------------------------------------------------------------------
-.SH "AUTHORS"
+.SH "AUTHOR"
.\" --------------------------------------------------------------------
.
Copyright (C) 2001, 2002 Free Software Foundation, Inc.
diff --git a/contrib/groffer/groffer.sh b/contrib/groffer/groffer.sh
index 683bc00d..f758ea6d 100644
--- a/contrib/groffer/groffer.sh
+++ b/contrib/groffer/groffer.sh
@@ -1,12 +1,10 @@
#!/bin/sh
-# groffer.sh
+# groffer - display groff files
-PROGRAM_NAME=groffer
-PROGRAM_VERSION="0.5 (beta)"
-LAST_UPDATE="08 Jan 2002"
+# File position: <groff-source>/contrib/groffer/groffer
-# Copyright (C) 2001 Free Software Foundation, Inc.
+# Copyright (C) 2001,2002 Free Software Foundation, Inc.
# Written by Bernd Warken <bwarken@mayn.de>
# This file is part of groff.
@@ -22,242 +20,688 @@ LAST_UPDATE="08 Jan 2002"
# License for more details.
# You should have received a copy of the GNU General Public License
-# along with groff; see the file COPYING. If not, write to the Free
-# Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
+# along with groff; see the file COPYING. If not, write to the
+# Free Software Foundation, 59 Temple Place - Suite 330, Boston,
+# MA 02111-1307, USA.
+
+export _PROGRAM_NAME;
+export _PROGRAM_VERSION;
+export _LAST_UPDATE;
+
+_PROGRAM_NAME=groffer
+_PROGRAM_VERSION="0.6"
+_LAST_UPDATE="27 May 2002"
########################################################################
-# Description
+# Description
########################################################################
-# Display groff files on X or tty, even when zipped.
+# Display groff files and man pages on X or tty, even when compressed.
-# This script tries to avoid features of special shells, so some
-# elements are programmed in a more complicated way than necessary.
+### Usage
+# Input comes from either standard input or command line parameters
+# that represent either names of exisiting roff files or standardized
+# specifications for man pages. All of these can be compressed in a
+# format that is decompressible by `gzip'.
+
+# Five displaying modes are available:
+# 1) Display processed input with the X roff viewer `gxditview'.
+# 2) Display processed input in a text terminal using a text device.
+# 3) Generate output for some groff device on stdout without a viewer.
+# 4) Output only the source code without any groff processing.
+# 5) Generate the troff intermediate output on standard output
+# without groff postprocessing.
+# By default, the program tries to display with `gxditview' (1); if
+# this does not work, text display (2) is used.
+
+
+### Error handling
-########################################################################
-# Debugging
-########################################################################
# Error handling and exit behavior is complicated by the fact that
-# `exit' can only escape from the current shell. This leads to trouble
-# in `$()' subshells.
+# `exit' can only escape from the current shell; trouble occurs in
+# subshells. This was solved by sending kill signals, see
+# $_PROCESS_ID and error().
#
-# for debugging only
-#set -x
-#set -v
-function diag ()
-{
- echo '>>>>>' "$@" >&2;
-}
-function abort ()
-{
- [ $# -gt 0 ] && diag "$@";
- error 2>/dev/null || exit 1;
-}
+### TODO
+
+# Add to existing man path the wanted system, language,
+# section/extension directories. Do not assume a fixed sequence of
+# the 3 additions above. So run all additions 3 times.
########################################################################
-# Setup
+# Compatibility
########################################################################
-export PROGRAM_NAME;
-export PROGRAM_VERSION;
-export LAST_UPDATE;
+# This script is compatible to POSIX and GNU. It works best in a GNU
+# system. Care was taken to restrict the programming technics used
+# here in order to achieve POSIX compatibility as far back as POSIX
+# P1003.2 Draft 11.2 of September 1991.
-set -a
+# In GNU, long options and the mixing of options and file name
+# parameters are available. In non-GNU environments, long options can
+# be simulated by preceding the long option and its argument by the
+# option `-W', which was reserved by POSIX for such usage. All
+# groffer features are accessible, but the usage is not as comfortable
+# as in GNU systems.
-# Survey of functions defined in this document
+
+########################################################################
+# General Setup
+########################################################################
+
+# set -a
+# set -x
+# set -v
+
+########################################################################
+# Survey of functions defined in this document
+########################################################################
# The elements specified within paranthesis `(<>)' give hints to what
# the arguments are meant to be; the argument names are irrelevant.
# <>? 0 or 1
-# <>* arbitrarily many incl. none
+# <>* arbitrarily many such arguments, incl. none
+# <>+ one or more such arguments
# <> exactly 1
-# append_args (<arg>*)
+# A function that starts with an underscore `_' is an internal
+# function for some function. The internal functions are defined just
+# after their corresponding function; they are not mentioned in the
+# following.
+
+# abort (text>*)
# base_name (path)
-# catz (<file>*)
-# check_dpi ()
+# catz (<file>)
# clean_up ()
-# count_next_quoted (<arg>*)
-# del_all_leading_from (<regexp> <string>)
-# del_ext_from (<extension> <filename>)
+# clean_up_secondary ()
+# diag (text>*)
+# dirname_append (<path> [<dir...>])
+# dirname_chop (<path>)
+# do_filearg (<filearg>)
+# do_nothing ()
# echo2 (<text>*)
-# error (<err_no> <text>*)
-# get_manpath ()
-# get_next_quoted (<arg>*)
-# is_substring_of (<part> <string>)
+# echo2n (<text>*)
+# error (<text>*)
+# get_first_essential (<arg>*)
+# is_dir (<name>)
+# is_empty (<string>)
+# is_equal (<string1> <string2>)
+# is_file (<name>)
+# is_not_empty (<string>)
+# is_not_equal (<string1> <string2>)
+# is_prog (<name>)
+# is_yes (<string>)
# leave ()
-# make_title ()
-# manpage_search_filespec (<filespec>)
-# manpage_search_name (<name> <section>?)
-# normalize_args (<arg>*)
-# output (<text>*)
+# main_*(), see after the functions
+# man_do_filespec (<filespec>)
+# man_is_setup ()
+# man_register_file (<file> [<name> [<section>]])
+# man_search_section (<name> <section>)
+# manpath_add_lang(<path> <language>)
+# manpath_add_system()
+# manpath_from_path ()
+# normalize_args (<shortopts> <longopts> <arg>*)
+# path_chop (<path>)
+# path_clean (<path>)
+# path_contains (<path> <dir>)
+# path_not_contains (<path> <dir>)
# register_title (<filespec>*)
-# save_stdin_if_any ()
-# shift_quoted (<arg>*)
-# supercat (<filearg>*)
+# save_stdin ()
+# string_contains (<string> <part>)
+# string_del_leading (<string> <regex>)
+# string_del_trailing (<string> <regex>)
+# string_flatten()
+# string_replace_all (<string> <regex> <replace>)
+# string_sed_s (<string> <regex> [<replace> [<flag>]])
# tmp_cat ()
# tmp_create (<suffix>?)
-# unquote (<arg>*)
+# to_tmp (<filename>)
# usage ()
# version ()
+# warning (<string>)
+# whatis (<filename>)
+# where (<program>)
########################################################################
# Environment Variables
########################################################################
-# Environment variables that are regarded as global to this file are
-# written in upper case letters and can use the underline character
-# inside, e.g. $GLOBAL_VARIABLE; local variables start with an
-# underline and use only lower case letters and underlines, e.g.
-# $_local_variable .
-
-# [A-Z]* system variables, e.g. $MANPATH
-# [A-Z][A_Z_]* global file variables, e.g. $MAN_PATH
-# _[a-z_]* local variables, e.g. $_manpath
-# _[a-z_] local loop variables, e.g. $_i
-
-# global variables
-DISPLAY_MODE="" # determined from command line arguments
-FILE_ARGS="" # the non-option command line parameters
-HAS_COMPRESSION="" # `yes' if compression is available
-HAS_MANW="" # `yes' if `man -w' is available
-HAS_OPTS_GNU="" # `yes' if GNU `getopt' is available
-HAS_OPTS_POSIX="" # `yes' if POSIX `getopts' is available
-MAN_PATH="" # search path for man-pages
-OTHER_OPTIONS="" # given non-native command line options
-OPT_SOURCE="" # source code option (`Quellcode')
-OPT_DEVICE="" # device option
-OPT_DPI="" # groff -X option
-OPT_MAN="" # interpret file params as man-pages
-OPT_MANPATH="" # manual setting of path for man-pages
-OPT_TITLE="" # title for gxditview window
-OPT_TTY="" # use text display instead of X
-OPT_XRDB="" # X resource arguments to gxditview
-TEMP_DIR="" # directory for temporary files
-TEMP_PREFIX="" # directory for temporary files
-TMP_CAT="" # stores concatenation of everything
-TMP_INPUT="" # stores stdin, if any
-TMP_TITLE="" # stores the names of processed args
-
-# command line arguments
-GROFFER_LONGOPTS="help man no-man source tty version";
-GROFFER_ARG_LONGS="device: dpi: manpath: title: xrdb:";
-GROFFER_SHORTOPTS="hQT:v";
-GROFF_ARG_SHORTS="d:f:F:I:L:m:M:n:o:P:r:w:W:"; # inhereted from groff
-GROFF_SHORTOPTS="abcegilpstzCEGNRSUVXZ"; # inhereted from groff
-ALL_SHORTOPTS=\
-"${GROFFER_SHORTOPTS}${GROFF_SHORTOPTS}${GROFF_ARG_SHORTS}";
-ALL_LONGOPTS="${GROFFER_LONGOPTS} $GROFFER_ARG_LONGS";
-
-PROCESS_ID="$$" # for shutting down the program
-
-ENABLE_MANPAGES=yes # enable search for man-pages
+# Environment variables that exist only for this file start with an
+# underscore letter. Global variables to this file are written in
+# upper case letters, e.g. $_GLOBAL_VARIABLE; temporary variables
+# start with an underline and use only lower case letters and
+# underlines, e.g. $_local_variable .
+
+# [A-Z]* system variables, e.g. $MANPATH
+# _[A-Z_]* global file variables, e.g. $_MAN_PATH
+# _[a-z_]* temporary variables, e.g. $_manpath
+# _[a-z] local loop variables, e.g. $_i
########################################################################
-# System Test
+# external system environment variables that are explicitly used
+
+export DISPLAY; # Presets the X display.
+export LANG; # For language specific man pages.
+export LC_ALL; # For language specific man pages.
+export LC_MESSAGES; # For language specific man pages.
+export OPTARG; # For option processing with getopts().
+export OPTIND; # For option processing with getopts().
+export PAGER; # Paging program for tty mode.
+export PATH; # Path for the programs called (: list).
+
+# groffer native environment variables
+export GROFFER_OPT # preset options for groffer.
+
+# all groff environment variables are used, see groff(1)
+export GROFF_BIN_PATH; # Path for all groff programs.
+export GROFF_COMMAND_PREFIX; # '' (normally) or 'g' (several troffs).
+export GROFF_FONT_PATH; # Path to non-default groff fonts.
+export GROFF_TMAC_PATH; # Path to non-default groff macro files.
+export GROFF_TYPESETTER; # Preset default device.
+export GROFF_TMPDIR; # Directory for groff temporary files.
+
+# variables from `man'
+export EXTENSION; # Restrict to man pages with extension.
+export MANOPT; # Preset options for man pages.
+export MANPATH; # Search path for man pages (: list).
+export MANSECT; # Search man pages only in sections (:).
+export SYSTEM; # Man pages for different OS's (, list).
+export MANROFFSEQ; # Ignored because of grog guessing.
+
+# do not export IFS.
+unset IFS;
+
+
########################################################################
+# read-only variables (global to this file)
-# Test the availability of the system utilities used in this script.
+export _SPACE;
+export _TAB;
+export _NEWLINE;
+
+_SPACE=' ';
+_TAB=' ';
+_NEWLINE='
+';
+
+# function return values; `0' means ok; other values are error codes
+export _BAD;
+export _BAD2;
+export _BAD3;
+export _ERROR;
+export _GOOD;
+export _NO;
+export _OK;
+export _YES;
+
+_GOOD='0'; # return ok
+_BAD='1'; # return negatively, error code `1'
+_BAD2='2'; # return negatively, error code `2'
+_BAD3='3'; # return negatively, error code `3'
+_ERROR='-1'; # syntax errors, etc.
+
+_NO="$_BAD";
+_YES="$_GOOD";
+_OK="$_GOOD";
+
+export _PROCESS_ID; # for shutting down the program
+_PROCESS_ID="$$";
+
+# Search automatically in standard sections `1' to `8', and in the
+# traditional sections `9', `n', and `o'. On many systems, there
+# exist even more sections, mostly containing a set of man pages
+# special to a specific program package. These aren't searched for
+# automatically, but must be specified on the command line.
+export _MAN_AUTO_SEC;
+_MAN_AUTO_SEC="1 2 3 4 5 6 7 8 9 n o"
+
+
+############ the command line options of several programs
+#
+# The naming scheme for the options environment names is
+# $_OPTS_<prog>_<length>[_<argspec>]
+#
+# <prog>: program name GROFFER, GROFF, or CMDLINE (for all
+# command line options)
+# <length>: LONG (long options) or SHORT (single character options)
+# <argspec>: ARG for options with argument, NA for no argument;
+# without _<argspec> both the ones with and without arg.
+#
+# Each option that takes an argument must be specified with a
+# trailing : (colon).
+
+
+###### native groffer options
+
+export _OPTS_GROFFER_SHORT_NA;
+export _OPTS_GROFFER_SHORT_ARG;
+export _OPTS_GROFFER_LONG_NA;
+export _OPTS_GROFFER_LONG_ARG;
+
+_OPTS_GROFFER_SHORT_NA="hQvXZ";
+_OPTS_GROFFER_SHORT_ARG="P:T:W:";
+
+_OPTS_GROFFER_LONG_NA="all apropos help intermediate-output \
+local-file location \
+man no-location no-man source title tty version whatis where";
+
+_OPTS_GROFFER_LONG_ARG="bg: device: display: dpi: extension: fg: \
+geometry: lang: locale: manpath: mode: pager: resolution: sections: \
+systems: title: to-postproc: troff-device: xrm:";
+
+##### options inhereted from groff
+
+export _OPTS_GROFF_SHORT_NA;
+export _OPTS_GROFF_SHORT_ARG;
+export _OPTS_GROFF_LONG_NA;
+export _OPTS_GROFF_LONG_ARG;
+
+_OPTS_GROFF_SHORT_NA="abcegilpstzCEGNRSUV";
+_OPTS_GROFF_SHORT_ARG="d:f:F:I:L:m:M:n:o:r:w:";
+_OPTS_GROFF_LONG_NA="";
+_OPTS_GROFF_LONG_ARG="";
+
+###### man options (for parsing $MANOPT only)
+
+export _OPTS_MAN_SHORT_ARG;
+export _OPTS_MAN_SHORT_NA;
+export _OPTS_MAN_LONG_ARG;
+export _OPTS_MAN_LONG_NA;
+
+_OPTS_MAN_SHORT_ARG="e:L:m:M:p:P:r:S:T:";
+_OPTS_MAN_SHORT_NA="acdDfhkltuVwZ";
+
+_OPTS_MAN_LONG_ARG="extension: lang: locale: manpath: pager: \
+preprocessor: prompt: sections: systems: troff-device:";
+
+_OPTS_MAN_LONG_NA="all apropos catman debug default ditroff help \
+local-file location troff update version whatis where";
+
+###### collections of options
+
+# groffer
+
+export _OPTS_GROFFER_LONG;
+export _OPTS_GROFFER_SHORT;
+_OPTS_GROFFER_LONG="${_OPTS_GROFFER_LONG_ARG} ${_OPTS_GROFFER_LONG_NA}";
+_OPTS_GROFFER_SHORT=\
+"${_OPTS_GROFFER_SHORT_ARG}${_OPTS_GROFFER_SHORT_NA}";
+
+# groff
+
+export _OPTS_GROFF_LONG;
+export _OPTS_GROFF_SHORT;
+_OPTS_GROFF_LONG="${_OPTS_GROFF_LONG_ARG} ${_OPTS_GROFF_LONG_NA}";
+_OPTS_GROFF_SHORT="${_OPTS_GROFF_SHORT_ARG}${_OPTS_GROFF_SHORT_NA}";
+
+# all command line options
+
+export _OPTS_CMDLINE_SHORT_NA;
+export _OPTS_CMDLINE_SHORT_ARG;
+export _OPTS_CMDLINE_SHORT;
+export _OPTS_CMDLINE_LONG_NA;
+export _OPTS_CMDLINE_LONG_ARG;
+export _OPTS_CMDLINE_LONG;
+
+_OPTS_CMDLINE_SHORT_NA="\
+${_OPTS_GROFFER_SHORT_NA}${_OPTS_GROFF_SHORT_NA}";
+_OPTS_CMDLINE_SHORT_ARG="\
+${_OPTS_GROFFER_SHORT_ARG}${_OPTS_GROFF_SHORT_ARG}";
+_OPTS_CMDLINE_SHORT="${_OPTS_GROFFER_SHORT}${_OPTS_GROFF_SHORT}";
+
+_OPTS_CMDLINE_LONG_NA="${_OPTS_GROFFER_LONG_NA} \
+${_OPTS_GROFF_LONG_NA} ${_OPTS_MAN_LONG_NA}";
+_OPTS_CMDLINE_LONG_ARG="${_OPTS_GROFFER_LONG_ARG} \
+${_OPTS_GROFF_LONG_ARG} ${_OPTS_MAN_LONG_ARG}";
+_OPTS_CMDLINE_LONG="${_OPTS_GROFFER_LONG} ${_OPTS_GROFF_LONG}";
+
+
+########################################################################
+# read-write variables (global to this file)
+
+export _DISPLAY_MODE; # From command line arguments.
+export _DISPLAY_PAGER; # Pager to be used on tty.
+export _FILEARGS; # Stores filespec parameters.
+export _ADDOPTS_GROFF; # Transp. options for groff (`eval').
+export _ADDOPTS_POST; # Transp. options postproc (`eval').
+export _ADDOPTS_X; # Transp. options X postproc (`eval').
+export _REGISTERED_TITLE; # Processed file names.
+_ADDOPTS_GROFF='';
+_ADDOPTS_POST='';
+_ADDOPTS_X='';
+_DISPLAY_MODE='';
+_DISPLAY_PAGER='';
+_FILEARGS='';
+_REGISTERED_TITLE='';
+
+# _HAS_* from availability tests
+export _HAS_COMPRESSION; # `yes' if compression is available
+export _HAS_OPTS_GNU; # `yes' if GNU `getopt' is available
+export _HAS_OPTS_POSIX; # `yes' if POSIX `getopts' is available
+_HAS_COMPRESSION='';
+_HAS_OPTS_GNU='';
+_HAS_OPTS_POSIX='';
+
+# _MAN_* finally used configuration of man searching
+export _MAN_ALL; # search all man pages per filespec
+export _MAN_ENABLE; # enable search for man pages
+export _MAN_EXT; # extension for man pages
+export _MAN_FORCE; # force file parameter to be man pages
+export _MAN_IS_SETUP; # setup man variables only once
+export _MAN_LANG; # language for man pages
+export _MAN_LANG_DONE; # language dirs added to man path
+export _MAN_PATH; # search path for man pages
+export _MAN_SEC; # sections for man pages; sep. `:'
+export _MAN_SEC_DONE; # sections added to man path
+export _MAN_SYS; # system names for man pages; sep. `,'
+export _MAN_SYS; # system names added to man path
+_MAN_ALL='no';
+_MAN_ENABLE='yes'; # do search for man-pages
+_MAN_EXT='';
+_MAN_FORCE='no'; # first local file, then search man page
+_MAN_IS_SETUP='no';
+_MAN_LANG='';
+_MAN_LANG_DONE='no';
+_MAN_PATH='';
+_MAN_SEC='';
+_MAN_SEC_DONE='no';
+_MAN_SYS='';
+_MAN_SYS_DONE='no';
+
+# _MANOPT_* as parsed from $MANOPT
+export _MANOPT_ALL; # $MANOPT --all
+export _MANOPT_EXTENSION; # $MANOPT --extension
+export _MANOPT_LANG; # $MANOPT --locale
+export _MANOPT_PATH; # $MANOPT --manpath
+export _MANOPT_PAGER; # $MANOPT --pager
+export _MANOPT_SEC; # $MANOPT --sections
+export _MANOPT_SYS; # $MANOPT --systems
+_MANOPT_ALL='no';
+_MANOPT_EXTENSION='';
+_MANOPT_LANG='';
+_MANOPT_PATH='';
+_MANOPT_PAGER='';
+_MANOPT_SEC='';
+_MANOPT_SYS='';
+
+# _OPT_* as parsed from groffer command line
+export _OPT_ALL; # display all suitable man pages
+export _OPT_APROPOS; # branch to `apropos' program
+export _OPT_DEVICE; # device option
+export _OPT_LANG; # set language for man pages
+export _OPT_LOCATION; # print processed file names to stderr
+export _OPT_MODE; # values: X, tty, Q, Z, ""
+export _OPT_MANPATH; # manual setting of path for man-pages
+export _OPT_PAGER; # specify paging program for tty mode
+export _OPT_SECTIONS; # sections for man page search
+export _OPT_SYSTEMS; # man pages of different OS's
+export _OPT_TITLE; # title for gxditview window
+export _OPT_WHATIS; # print the one-liner man info
+export _OPT_XRDB; # X resource arguments to gxditview
+_OPT_ALL='no';
+_OPT_APROPOS='no';
+_OPT_DEVICE='';
+_OPT_LANG='';
+_OPT_LOCATION='no';
+_OPT_MODE='';
+_OPT_MANPATH='';
+_OPT_PAGER='';
+_OPT_SECTIONS='';
+_OPT_SYSTEMS='';
+_OPT_TITLE='';
+_MANOPT_WHATIS='no';
+_OPT_XRDB='';
+
+# _TMP_* temporary files
+export _TMP_DIR; # directory for temporary files
+export _TMP_PREFIX; # dir and base name for temporary files
+export _TMP_CAT; # stores concatenation of everything
+export _TMP_STDIN; # stores stdin, if any
+_TMP_DIR='';
+_TMP_PREFIX='';
+_TMP_CAT='';
+_TMP_STDIN='';
########################################################################
-# Test of function "test".
+# Test of rudimentary shell functionality
+########################################################################
+
+########################################################################
+# Test of `test'.
#
-[ "a" = "a" ] || exit 1;
+test "a" = "a" || exit 1;
########################################################################
-# Test of function "echo".
+# Test of `echo' and the `$()' construct.
#
-if [ "$(echo -n 'te' && echo -n && echo 'st')" != "test" ]; then
- echo 'Test of "echo" command failed.' >&2;
- exit 1;
+echo -n '' >/dev/null || exit -1;
+if test "$(echo -n 'te' && echo -n '' && echo -n 'st')" != "test"; then
+ exit -1;
fi;
########################################################################
-# Test of function "true".
+# Test of function definitions.
#
-if ! true >/dev/null 2>&1; then
- true ()
- {
- : ;
- }
+_test_func()
+{
+ return 0;
+}
- false ()
+if ! _test_func; then
+ echo 'shell does not support function definitions.' >&2;
+ exit -1;
+fi;
+
+
+########################################################################
+# Test of builtin `local'
+#
+_global='outside';
+test_local()
+{
+ _global='inside';
+ local _local >/dev/null 2>&1 || return 1;
+}
+if ! test_local; then
+ local()
{
- ! : ;
+ for _i in "$@"; do
+ unset "${_i}";
+ done;
}
+ unset _i;
+fi;
+if test "${_global}" != 'inside'; then
+ error "Cannot assign to global variables from within functions.";
fi;
+unset _global;
+
+########################################################################
+# Functions for error handling and debugging
########################################################################
-# Test of function "sed".
+
+##############
+# clean_up ()
#
-if [ "$(echo teeest | sed -e '\|^teeest$|s|\(e\)\+|\1|')" != "test" ];
-then
- echo 'Test of "sed" command failed.' >&2;
+# Clean up at exit.
+#
+clean_up()
+{
+ clean_up_secondary;
+ rm -f "${_TMP_CAT}";
+}
+
+
+##############
+# clean_up_secondary ()
+#
+# Clean up temporary files without $_TMP_CAT.
+#
+clean_up_secondary()
+{
+ local _i;
+ for _i in "${_TMP_STDIN}"; do
+ rm -f "${_i}";
+ done;
+}
+
+
+##############
+# echo2 (<text>*)
+#
+# Output to stderr.
+#
+# Arguments : arbitrary text.
+#
+echo2()
+{
+ echo "$*" >&2;
+}
+
+
+##############
+# echo2n (<text>*)
+#
+# Output to stderr.
+#
+# Arguments : arbitrary text.
+#
+echo2n()
+{
+ echo -n "$*" >&2;
+}
+
+
+#############
+# error (<text>*)
+#
+# Print an error message to standard error; exit with an error condition
+#
+error()
+{
+ local _code;
+ _code=-1;
+ case "$#" in
+ 0) true; ;;
+ 1) echo2 'groffer error: '"$1"; ;;
+ 2)
+ echo2 'groffer error: '"$1";
+ _code="$2";
+ ;;
+ *) echo2 'groffer error: wrong number of arguments in error().'; ;;
+ esac;
+ clean_up;
+ kill "${_PROCESS_ID}" >/dev/null 2>&1;
+ kill -9 "${_PROCESS_ID}" >/dev/null 2>&1;
+ exit "${_code}";
+}
+
+
+#############
+# diag (text>*)
+#
+# Output a diagnostic message to stderr
+#
+function diag ()
+{
+ echo2 '>>>>>'"$*";
+}
+
+
+#############
+# abort (<text>*)
+#
+# Terminate program with error condition
+#
+function abort ()
+{
+ error "Program aborted.";
exit 1;
+}
+
+
+########################################################################
+# System Test
+########################################################################
+
+# Test the availability of the system utilities used in this script.
+
+
+########################################################################
+# Test of function `true'.
+#
+if ! true >/dev/null 2>&1; then
+ true ()
+ {
+ return 0;
+ }
+
+ false ()
+ {
+ return 1;
+ }
fi;
########################################################################
-# Test of function "grep".
+# Test of function `sed'.
#
-if [ "$( (echo no; echo test) | grep -e '^.e..$')" != "test" ]; then
- echo 'Test of "grep" command failed.' >&2;
- exit 1;
+if test "$(echo teeest | sed -e '\|^teeest$|s|\(e\)\+|\1|')" != "test";
+then
+ error 'Test of "sed" command failed.';
fi;
########################################################################
-# Test of function "cat".
+# Test of function `cat'.
#
-if [ "$(echo test | cat)" != "test" ]; then
- echo 'Test of "cat" command failed.' >&2;
- exit 1;
+if test "$(echo test | cat)" != "test"; then
+ error 'Test of "cat" command failed.';
fi;
########################################################################
# Test for compression.
#
-if [ "$(echo test | gzip -c -d -f -)" = "test" ]; then
- HAS_COMPRESSION="yes";
+if test "$(echo test | gzip -c -d -f -)" = "test"; then
+ _HAS_COMPRESSION="yes";
else
- HAS_COMPRESSION="no";
+ _HAS_COMPRESSION="no";
fi;
########################################################################
-# Test for temporary directory and file generating utility
+# Test for temporary directory and file generating utility.
#
-# determine temporary directory into `$TEMP_DIR'
-for _i in "$GROFF_TMPDIR $TMPDIR" "$TMP" "$TEMP" "$TEMPDIR" \
- "$HOME"/tmp /tmp "$HOME" .;
+# determine temporary directory into `$_TMP_DIR'
+for _i in "${GROFF_TMPDIR}" "${TMPDIR}" "${TMP}" "${TEMP}" \
+ "${TEMPDIR}" "${HOME}"/tmp /tmp "${HOME}" .;
do
- if [ "$_i" != "" ]; then
- if [ -d "$_i" -a -r "$_i" -a -w "$_i" ]; then
- TEMP_DIR="$_i";
+ if test "${_i}" != ""; then
+ if test -d "${_i}" && test -r "${_i}" && test -w "${_i}"; then
+ _TMP_DIR="${_i}";
break;
fi;
fi;
-done
-unset _i
-if [ "$TEMP_DIR" = "" ]; then
- echo "Couldn't find a directory for storing temorary files." >&2;
- exit 1;
+done;
+unset _i;
+if test "${_TMP_DIR}" = ""; then
+ error "Couldn't find a directory for storing temorary files.";
fi;
-TEMP_PREFIX="${TEMP_DIR}/${PROGRAM_NAME}";
+_TMP_PREFIX="${_TMP_DIR}/${_PROGRAM_NAME}";
########################################################################
@@ -265,858 +709,1634 @@ TEMP_PREFIX="${TEMP_DIR}/${PROGRAM_NAME}";
#
# GNU getopt
-if _res="$(getopt -l GNU: ab: --GNU getopt test 2>/dev/null |
- sed -e '\|^ *\(.*\) *$|s||\1|')"; then
- if [ "$_res" = "--GNU 'getopt' -- 'test'" ]; then
- HAS_OPTS_GNU="yes";
+unset GETOPT_COMPATIBLE;
+getopt -T >/dev/null 2>&1;
+if test "$?" -eq 4; then # special test for GNU enhanced version
+ _HAS_OPTS_GNU="yes";
+else
+ # POSIX getopts
+ OPTIND=1;
+ OPTARG="";
+ if getopts "t:" _opt -test 2>/dev/null && \
+ test "${_opt}" = "t" && \
+ test "${OPTARG}" = "est" && \
+ test "${OPTIND}" -eq 2; then
+ _HAS_OPTS_POSIX="yes";
+ else
+ error "No argument parser available (`getopt' or `getopts').";
fi;
+ unset _opt;
fi;
-# POSIX getopts
-OPTIND=1;
-OPTARG="";
-getopts "t:" _opt -test 2>/dev/null;
-if [ "$?" -eq 0 -a "$_opt" = "t" -a \
- "$OPTARG" = "est" -a "$OPTIND" -eq 2 ]; then
- HAS_OPTS_POSIX="yes";
-fi;
-
-if [ "$HAS_OPTS_GNU" = "" -a "$HAS_OPTS_POSIX" = "" ]; then
- error "No argument parser program available (`getopt' or `getopts').";
-fi;
-
-unset _opt;
-unset _res;
OPTIND=1;
OPTARG="";
########################################################################
-# Determine search method for man-pages
-#
-unset HAS_MANW # `yes' if `man -w' is available
-if _files="$(man -w man 2>/dev/null)"; then
- if [ "$_files" = "" ]; then
- HAS_MANW="no";
- else
- for _i in $_files; do
- if [ -f "$_i" ]; then
- HAS_MANW="yes";
- break;
- fi;
- done;
- fi;
- if [ "$HAS_MANW" != "yes" ]; then
- HAS_MANW="no";
- fi;
-fi;
-unset _files;
-unset _i;
-
-########################################################################
-# Shell Funtions
+# Definition of Functions
########################################################################
########################################################################
-# append_args (<arg>*)
-#
-# Append args to `string' separated by a space, omitting empty args.
+# abort (<text>*)
#
-# Arguments : >=2
-# Output : the generated string
+# Unconditionally terminate the program with error code;
+# useful for debugging.
#
-append_args()
-{
- local _res;
- while [ "$1" = "" ]; do
- if [ "$#" -eq 0 ]; then
- return;
- fi;
- shift;
- done;
- _res="$1";
- shift;
- while [ "$#" -ge 1 ]; do
- if [ "$1" != "" ]; then
- _res="$_res $1";
- fi;
- shift;
- done;
- output "$_res";
-}
+# defined above
########################################################################
-# base_name (path)
+# base_name (<path>)
#
-# Delete the directory part of `path', i.e. everything up to last `/'
-# at the beginning of `path'.
+# Get the file name part of <path>, i.e. delete everything up to last
+# `/' from the beginning of <path>.
#
# Arguments : 1
-# Output : the corrected string
+# Output : the file name part (without slashes)
#
base_name()
{
- if [ "$#" != 1 ]; then
- error 1 "Function base_name needs 1 argument.";
- fi
- output "$1" | sed -e '\|^\(.*/\)\+|s|||';
+ if test "$#" != 1; then
+ error "base_name() needs 1 argument.";
+ return "$_ERROR";
+ fi;
+ string_sed_s "$1" '^.*/\([^/]*\)$' '\1';
}
########################################################################
-# catz (<file>*)
+# catz (<file>)
#
# If compression is available decompress standard input and write it to
# standard output; otherwise copy standard input to standard output.
#
-if [ "$HAS_COMPRESSION" = "yes" ]; then
+if test "${_HAS_COMPRESSION}" = 'yes'; then
catz()
{
- cat "$@" | gzip -c -d -f;
+ if test "$#" -ne 1; then
+ error "catz() needs exactly 1 argument.";
+ return "$_ERROR";
+ fi;
+ cat "$1" | gzip -c -d -f 2>/dev/null;
}
else
catz()
{
- cat "$@";
+ if test "$#" -ne 1; then
+ error "catz() needs exactly 1 argument.";
+ return "$_ERROR";
+ fi;
+ cat "$1";
}
fi;
########################################################################
-# check_dpi ()
+# clean_up ()
+#
+# Do the final cleaning up before exiting; used by the trap calls.
+#
+# defined above
+
+
+########################################################################
+# clean_up_secondary ()
+#
+# Do the second but final cleaning up.
+#
+# defined above
+
+
+########################################################################
+# diag (<text>*)
+#
+# Print marked message to standard error; useful for debugging.
+#
+# defined above
+
+
+########################################################################
+# dirname_append (<dir> <name>)
#
-# Sanity check for having default X resolution 100 dpi (very defensive)
+# Append `name' to `dir' with clean handling of `/'.
#
-# Output : generated title
+# Arguments : >=1
+# Output : the generated new directory name
#
-check_dpi()
+dirname_append()
{
- local _res=100;
- local _fp;
- if _fp="$(xset q | grep '/font' 2>/dev/null)"; then
- case "$_fp" in
- *100*) : ; ;;
- *75*) _res=75; ;; # no 100 found in X font path, but 75
- esac;
+ local _res;
+ if test "$#" -ne 2; then
+ error "dir_append() needs 2 arguments.";
+ return "$_ERROR";
fi;
- output "$_res";
+ if is_empty "$1"; then
+ echo -n "$2";
+ return "$_OK";
+ fi;
+ dirname_chop "$1"/"$2";
}
########################################################################
-# clean_up () :
+# dirname_chop (<name>)
#
-# Clean exit without an error.
+# Remove unnecessary slashes from directory name.
#
-clean_up()
+# Argument: 1, a directory name.
+# Output: path without double, or trailing slashes.
+#
+dirname_chop()
{
- local _i;
- for _i in "$TMP_CAT" "$TMP_INPUT" "$TMP_TITLE"; do
- if [ -f "$_i" ]; then
- rm -r "$_i";
- fi;
- done;
+ local _arg;
+ local _res;
+ local _sep;
+ if test "$#" -ne 1; then
+ error 'dirname_chop() needs 1 argument.';
+ return "$_ERROR";
+ fi;
+ _res="$(string_replace_all "$1" '//\+' '/')";
+ case "$_res" in
+ ?*/) string_del_trailing "$_res" '/'; ;;
+ *) echo -n "$_res"; ;;
+ esac;
}
########################################################################
-# count_next_quoted (<arg>*)
-#
-# Expects single-quoted arguments, returns the first quoted argument.
+# do_filearg (<filearg>)
+#
+# Append the file, man-page, or standard input corresponding to the
+# argument to the temporary file. If this is compressed in the gzip
+# or Z format it is decompressed. A title element is generated.
+#
+# Argument either:
+# - name of an existing files.
+# - `-' to represent standard input (several times allowed).
+# - `man:name.(section)' the man-page for `name' in `section'.
+# - `man:name.section' the man-page for `name' in `section'.
+# - `man:name' the man-page for `name' in the lowest `section'.
+# - `name.section' the man-page for `name' in `section'.
+# - `name' the man-page for `name' in the lowest `section'.
+# Globals :
+# $_TMP_STDIN, $_MAN_ENABLE, $_MAN_IS_SETUP, $_OPT_MAN
#
-# Arguments : single-quoted, evt. with included spaces.
-# Output : number of arguments within the single-quote.
-# Return : `1' if arguments are not single-quoted, `0' otherwise.
+# Output : none
+# Return : $_GOOD if found, $_BAD otherwise.
#
-count_next_quoted()
+do_filearg()
{
- local _args;
- local _number;
- local _quoted_block="";
- if [ "$#" -eq 0 ]; then
- return 1;
+ local _filespec;
+ local _mode;
+ local _sequence;
+ if test "$#" -ne 1; then
+ error "do_filearg() expects 1 argument.";
+ return "$_ERROR";
fi;
- if output $1 | grep -e "^'" >/dev/null 2>&1; then
- # starts with a single quote
- while ! (output $1 | grep -e \'\$ >/dev/null 2>&1); do
- # doesn't end with a single quote
- _quoted_block="$(append_args $_quoted_block $1)";
- shift;
- if [ "$#" = 0 ]; then
- error "count_next_quoted : no closing quote found"
- return 1;
+ _filespec="$1";
+ case "$_filespec" in
+ '')
+ return "$_GOOD";
+ ;;
+ '-')
+ to_tmp "${_TMP_STDIN}";
+ register_title "-";
+ return "$_GOOD";
+ ;;
+ */*) # with directory part; so no man search
+ sequence="File";
+ ;;
+ *)
+ if is_yes "${_MAN_ENABLE}"; then
+ if is_yes "${_OPT_MAN}"; then
+ _sequence="Manpage File";
+ else
+ _sequence="File Manpage";
+ fi;
+ else
+ _sequence="File";
fi;
- done;
- # actual $1 has closing quote
- _quoted_block="$(append_args $_quoted_block $1)";
- set -- $_quoted_block;
- _number="$#";
- else
- _number=1;
- fi;
- output $_number;
+ ;;
+ esac;
+ for _mode in ${_sequence}; do
+ case "${_mode}" in
+ File)
+ if test -f "${_filespec}"; then
+ if test ! -r "${_filespec}"; then
+ echo2 "could not read \`${_filespec}'";
+ return "$_BAD";
+ fi;
+ to_tmp "${_filespec}";
+ register_title "$(base_name "${_filespec}")";
+ return "$_GOOD";
+ else
+ continue;
+ fi;
+ ;;
+ Manpage) # parse filespec as man page
+ if is_not_yes "$_MAN_IS_SETUP"; then
+ man_setup;
+ fi;
+ if man_do_filespec "${_filespec}"; then
+ return "$_GOOD";
+ else
+ continue;
+ fi;
+ ;;
+ esac;
+ done;
+ return "$_BAD";
}
########################################################################
-# del_all_leading_from (<regexp> <string>)
-#
-# Delete every occurence of `regexp' at the beginning of `string'.
+# do_nothing ()
#
-# Arguments : 2
-# Output : the corrected string
+# Dummy function.
#
-del_all_leading_from()
+do_nothing()
{
- if [ "$#" != 2 ]; then
- error 1 'Function "del_all_leading_from" needs 2 args.';
- fi
- output "$2" | sed -e '\|^\('"$1"'\)\+|s|||';
+ return "$_OK";
}
########################################################################
-# del_ext_from (<extension> <filename>)
+# echo2 (<text>*)
#
-# Delete `extension' from the end of `filename'.
+# Print to standard error with final line break.
#
-# Arguments : 2
-# Output : the corrected string
+# defined above
+
+
+########################################################################
+# echo2n (<text>*)
+#
+# Print to standard error without final line break.
+#
+# defined above
+
+
+########################################################################
+# error (<text>*)
#
-del_ext_from()
+# Print error message and exit with error code.
+#
+# defined above
+
+
+########################################################################
+# get_first_essential (<arg>*)
+#
+# Retrieve first non-empty argument.
+#
+# Return : `1' if all arguments are empty, `0' if found.
+# Output : the retrieved non-empty argument.
+#
+get_first_essential()
{
- if [ "$#" != 2 ]; then
- error 1 'Function "del_ext_from" needs 2 args.';
- fi
- output "$2" | sed -e "\|^ *\('\?.*\)$1\('\?\) *"'$|s||\1\2|';
+ local _i;
+ if test "$#" -eq 0; then
+ return "$_OK";
+ fi;
+ for _i in "$@"; do
+ if is_not_empty "${_i}"; then
+ echo -n "${_i}";
+ return "$_OK";
+ fi;
+ done;
}
########################################################################
-# echo2 (<text>*)
+# is_dir (<name>)
#
-# Output to stderr.
+# Test whether `name' is a directory.
#
-# Arguments : arbitrary text.
+# Arguments : 1
+# Return : `0' if arg1 is a directory, `1' otherwise.
#
-echo2()
+is_dir()
{
- echo "$*" >&2;
+ if is_not_empty "$1" && test -d "$1" && test -r "$1"; then
+ return "$_GOOD";
+ else
+ return "$_BAD";
+ fi;
}
########################################################################
-# error (<err_no> <text>*)
+# is_empty (<string>)
#
-# Output argurments to stderr and abort.
+# Test whether `string' is empty.
#
-# Arguments : arbitrary text
+# Arguments : <=1
+# Return : `0' if arg1 is empty or does not exist, `1' otherwise.
#
-error()
+is_empty()
{
- local _errno;
- case "$#" in
- 0) set -- 'unknown error'; ;;
- esac;
- echo2 "groffer error : $*";
- clean_up;
- kill "$PROCESS_ID" >/dev/null 2>&1;
- kill -9 "$PROCESS_ID" >/dev/null 2>&1;
- exit 1;
+ if test "$#" -ne 1; then
+ error "is_empty() needs 1 argument.";
+ return "$_ERROR";
+ fi;
+ if test -z "$1"; then
+ return "$_YES";
+ else
+ return "$_NO";
+ fi;
}
########################################################################
-# get_manpath ()
+# is_equal (<string1> <string2>)
#
-# Determine search path for man-pages (only needed when no `man -w').
+# Test whether `string1' is equal to <string2>.
#
-# Return : `0' if a valid path was retrieved.
-# Output : path as space-separated list (intended for $MAN_PATH).
-# Globals : system : $MANPATH $LC_ALL $LANG
-# file : $OPT_MANPATH $MAN_PATH
+# Arguments : 2
+# Return : `0' both arguments are equal strings, `1' otherwise.
#
-get_manpath()
+is_equal()
{
- local _files;
- local _dirs;
- local _i;
- local _d;
- local _p;
- local _all;
- local _manpath;
- if [ "$OPT_MANPATH" != "" ]; then # --manpath was set
- MANPATH="$OPT_MANPATH";
- fi;
- if [ "$MANPATH" = "" ]; then # try `manpath' program
- _dirs="$(manpath 2>/dev/null)";
- if [ "$?" = 0 -a "$_dirs" != "" ]; then
- MANPATH="$_dirs";
- fi
- fi
- if [ "$MANPATH" = "" ]; then # set some default path
- _manpath="/usr/local/share/man /usr/local/man \
- /usr/share/man /usr/man \
- /usr/X11R6/man /usr/openwin/man \
- /opt/man /opt/gnome/man /opt/kde/man";
- else
- _manpath="$(echo -n $MANPATH | tr : ' ')";
+ if test "$#" -ne 2; then
+ error "is_equal() needs 2 arguments.";
+ return "$_ERROR";
fi;
- if [ "$_manpath" = "" ]; then
- return 1;
+ if test "$1" = "$2"; then
+ return "$_YES";
+ else
+ return "$_NO";
fi;
- _dirs="";
- for _p in $_manpath; do # remove non-existing directories
- if [ -d "$_p" -a -r "$_p" -a -x "$_p" ]; then
- _dirs="$(append_args $_dirs $_p)";
- fi;
- done;
- _manpath="$_dirs";
- if [ "$_manpath" = "" ]; then
- return 1;
+}
+
+
+########################################################################
+# is_file (<name>)
+#
+# Test whether `name' is a readable file.
+#
+# Arguments : 1
+# Return : `0' if arg1 is a readable file, `1' otherwise.
+#
+is_file()
+{
+ if is_not_empty "$1" && test -f "$1" && test -r "$1"; then
+ return "$_GOOD";
+ else
+ return "$_BAD";
fi;
- if [ "$LC_ALL" = "" -a "$LANG" = "" ]; then
- MAN_PATH="$_manpath";
- else # language-specific directories
- MAN_PATH="";
- if [ "$LC_ALL" != "" ]; then
- _lang_var="$LC_ALL";
- else
- _lang_var="$LANG";
- fi
- # two-letter version of $LANG
- _short_code="$(echo $_lang_var | sed -e '\|^\(..\).*$|s||\1|')";
- for _p in $_manpath; do
- _langdir="${_p}/${_lang_var}";
- _all="$(ls -d "${_p}/${_short_code}"* 2>/dev/null)";
- # all dirs with this 2-letter lang code
- _langs="";
- if [ "$_all" != "" ]; then
- for _d in $_all; do
- if [ "$_d" != "$_langdir" -a -d "$_d" ]; then
- _langs="$(append_args "$_langs" "$_d")";
- fi;
- done;
- if [ -d "$_langdir" ]; then
- _langs="$(append_args "$_langdir" $_langs)";
- fi;
- fi;
- MAN_PATH="$(append_args "$_langs" $_p)";
- done;
+}
+
+
+########################################################################
+# is_not_empty (<string>)
+#
+# Test whether `string' is not empty.
+#
+# Arguments : <=1
+# Return : `0' if arg1 exists and is not empty, `1' otherwise.
+#
+is_not_empty()
+{
+ if test "$#" -ne 1; then
+ error "is_not_empty() needs 1 argument.";
+ return "$_ERROR";
fi;
- if [ "$MAN_PATH" = "" ]; then
- return 1;
+ if test -n "$1"; then
+ return "$_YES";
+ else
+ return "$_NO";
fi;
- output "$MAN_PATH";
}
########################################################################
-# get_next_quoted (<arg>*)
+# is_not_equal (<string1> <string2>)
#
-# Expects single-quoted arguments, returns the first quoted argument.
+# Test whether `string1' is not equal to <string2>.
#
-# Arguments : single-quoted, evt. with included spaces.
-# Output : everything up to the next arg terminated by a quote;
-# the enclosing quotes are removed.
-# Return : `1' if arguments are not single-quoted, `0' otherwise.
+# Arguments : 2
+# Return : `0' the arguments are different strings, `1' otherwise.
#
-get_next_quoted()
+is_not_equal()
{
- local _args="$*";
- local _number="$(count_next_quoted $_args)";
- shift $_number;
- output $_args | sed -e '\|^\(.*\)'"$*"'$|s||\1|' |
- sed -e "\|^ *'\(.*\)' *"'$|s||\1|';
+ if test "$#" -ne 2; then
+ error "is_not_equal() needs 2 arguments.";
+ return "$_ERROR";
+ fi;
+ if test "$1" != "$2"; then
+ return "$_YES";
+ else
+ return "$_NO";
+ fi;
}
########################################################################
-# is_substring_of (<part> <string>)
+# is_not_yes (<string>)
#
-# Test whether `part' is contained in `string'.
+# Test whether `string' is not "yes".
#
-# Arguments : 2 text arguments.
-# Return : `0' if arg1 is substring of arg2, `1' otherwise.
+# Arguments : <=1
+# Return : `0' if arg1 is `yes', `1' otherwise.
#
-is_substring_of()
+is_not_yes()
{
- if [ "$#" != 2 ]; then
- false;
- error "is_substring_of needs 2 arguments.";
+ if test "$#" -ne 1; then
+ error "is_not_yes() needs 1 argument.";
+ return "$_ERROR";
fi;
- if output "$2" | grep -e "$1" >/dev/null 2>&1; then
- return 0;
+ if test "$1" != "yes"; then
+ return "$_GOOD";
else
- return 1;
+ return "$_BAD";
fi;
}
########################################################################
-# leave ()
+# is_prog (<name>)
#
-# Clean exit without an error.
+# Determine whether arg is a program in $PATH
#
-leave()
+# Arguments : 1 (empty allowed)
+# Return : `0' if arg is a program in $PATH, `1' otherwise.
+#
+is_prog()
{
- clean_up;
- exit 0;
+ where "$@" >/dev/null;
}
########################################################################
-# make_title ()
+# is_yes (<string>)
#
-# Create title for X from the different possibilities.
-# Delete $TMP_TITLE file.
+# Test whether `string' has value "yes".
#
-# Globals : $TMP_TITLE $OPT_XRDB $OPT_TITLE
-# Output : retrieved title
+# Arguments : <=1
+# Return : `0' if arg1 is `yes', `1' otherwise.
#
-make_title()
+is_yes()
{
- if [ "$OPT_TITLE" != "" ]; then
- # title was set by option --title
- output "$OPT_TITLE";
- elif is_substring_of "-title" "$OPT_XRDB"; then
- # $OPT_XRDB is handled anyway, so no extra output from here
- true;
- else
- # no title was supplied on the command line, take the default title
- # constisting of the processed filespecs, stored in file $TMP_TITLE.
- if [ "$TMP_TITLE" != "" ]; then
- cat "$TMP_TITLE";
- fi;
+ if test "$#" -ne 1; then
+ error "is_yes() needs 1 argument.";
+ return "$_ERROR";
fi;
- if [ "$TMP_TITLE" != "" ]; then
- rm -f "$TMP_TITLE";
+ if is_equal "$1" 'yes'; then
+ return "$_GOOD";
+ else
+ return "$_BAD";
fi;
}
########################################################################
-# manpage_search_filespec (<filespec>)
+# leave ()
#
-# check argument with `man -w'
+# Clean exit without an error.
#
-# Arguments : exactly 1 argument of the form `name.section',
-# `man:name', or `man:name(section)'.
-# Several args indicate an embedded space character.
+leave()
+{
+ clean_up;
+ exit "$_OK";
+}
+
+
+########################################################################
+# man_do_filespec (<filespec>)
+#
+# Print suitable man page(s) for filespec to $_TMP_CAT.
+#
+# Arguments : 2
+# <filespec>: argument of the form `man:name.section', `man:name',
+# `man:name(section)', `name.section', `name'.
+#
+# Globals : $_OPT_ALL
#
-# Output : filename of man page, if any.
+# Output : none.
# Return : `0' if man page was found, `1' else.
#
-# Only called from supercat().
+# Only called from do_fileargs(), checks on $MANPATH and
+# $_MAN_ENABLE are assumed.
#
-manpage_search_filespec()
+man_do_filespec()
{
- local _file="";
- local _arg;
+ local _got_one;
local _name;
+ local _prevsec;
+ local _res;
+ local _s;
local _section;
- if [ "$#" -ne 1 ]; then
- return 1;
+ local _spec;
+ local _string;
+ if is_empty "${MANPATH}"; then
+ return "$_BAD";
fi;
- _arg="$1";
- case "$_arg" in
- */*) # contains directory part, not handled
- return 1;
+ case "$#" in
+ 1) true; ;;
+ *)
+ error "man_do_filespec() needs exactly 1 argument.";
+ return "$_ERROR";
;;
+ esac;
+ if is_empty "$1"; then
+ return "$_BAD";
+ fi;
+ _spec="$1";
+ _name='';
+ _section='';
+ case "${_spec}" in
man:?*\(?*\)) # man:name(section)
- _name="$(output "$_arg" |
- sed -e '\|^man:\([^(]\+\)(\(.*\))$|s||\1|')";
- _section="$(output $_arg |
- sed -e '\|^man:\([^(]\+\)(\(.*\))$|s||\2|')";
- if _file="$(manpage_search_name "$_name" "$_section")" &&
- [ "$_file" != "" ]; then
- output "$_file";
- return 0;
- fi;
- return 1;
+ _string="$(string_del_leading "${_spec}" 'man:')";
+ _string="$(string_del_trailing "${_string}" ')')";
+ _name="$(string_del_trailing "${_string}" '(.\+')";
+ _section="$(string_del_leading "${_string}" "${_name}"'(')";
;;
- man:?*.?*) # man:name.section
- _name="$(output "$_arg" |
- sed -e '\|^man:\([^.]\+\)\.\(.*\)$|s||\1|')";
- _section="$(output $_arg |
- sed -e '\|^man:\([^.]\+\)\.\(.*\)$|s||\2|')";
- if _file="$(manpage_search_name "$_name" "$_section")" &&
- [ "$_file" != "" ]; then
- output "$_file";
- return 0;
- fi;
- return 1;
+ man:?*.[^.]*) # man:name.section
+ _string="$(string_del_leading "${_spec}" 'man:')";
+ _name="$(string_del_trailing "${_string}" '\.[^.]*')";
+ _section="$(string_del_leading "${_string}" "${_name}"'\.')";
;;
man:?*) # man:name
- _name="$(output "$_arg" | sed -e '\|^man:|s|||')";
- if _file="$(manpage_search_name "$_name")"; then
- output "$_file";
- return 0;
- else
- return 1;
- fi;
+ _name="$(string_del_leading "${_spec}" 'man:')";
;;
- ?*.?*) # name.section
- _name="$(output "$_arg" |
- sed -e '\|^\([^.]\+\)\.\([^.]\+\)$|s||\1|')";
- _section="$(output "$_arg" |
- sed -e '\|^\([^.]\+\)\.\([^.]\+\)$|s||\2|')";
- _file="$(manpage_search_name "$_name" "$_section")";
- if [ "$?" -eq 0 -a "$_file" != "" ]; then
- output "$_file";
- return 0;
- fi;
- _file="$(manpage_search_name "$_arg")"
- if [ "$?" -eq 0 -a "$_file" != "" ]; then
- output "$_file";
- return 0;
- fi;
- return 1;
+ ?*\(?*\)) # name(section)
+ _string="$(string_del_trailing "${_spec}" ')')";
+ _name="$(string_del_trailing "${_string}" '(.\+')";
+ _section="$(string_del_leading "${_string}" "${_name}"'(')";
+ ;;
+ *.[^.]*) # name.section
+ _name="$(string_del_trailing "${_spec}" '\.[^.]\+')";
+ _section="$(string_del_leading "${_spec}" "${_name}"'\.')";
;;
?*)
- _file="$(manpage_search_name "$_arg")";
- if [ "$?" -eq 0 -a "$_file" != "" ]; then
- output "$_file";
- return 0;
- fi;
- return 1;
+ _name="${_filespec}";
;;
esac;
- return 1;
+ if is_empty "${_name}"; then
+ return "$_BAD";
+ fi;
+ _got_one='no';
+ if is_empty "${_section}"; then
+ for _s in $_MAN_AUTO_SEC; do
+ if man_search_section "$_name" "$_s"; then # found
+ if is_yes "$_MAN_ALL"; then
+ _got_one='yes';
+ else
+ return "$_GOOD";
+ fi;
+ fi;
+ done;
+ else
+ man_search_section "$_name" "$_section";
+ return "$?";
+ fi;
+ if is_yes "$_MAN_ALL" && is_yes "$_got_one"; then
+ return "$_GOOD";
+ fi;
+ return "$_BAD";
}
########################################################################
-# manpage_search_name (<name> <section>?)
+# man_is_setup ()
+#
+# Setup the variables $_MAN_* needed for man page searching.
#
-# Get position of man-page `name(section)', or just `name' in the
-# lowest section using `man -w'.
+# Globals:
+# in: $_OPT_*, $_MANOPT_*, $LANG, $LC_MESSAGES, $LC_ALL,
+# $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM, $MANOPT.
+# out: $_MAN_PATH, $_MAN_LANG, $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2,
+# $_MAN_SEC, $_MAN_ALL
+# in/out: $_MAN_ENABLE
#
-# Arguments : either 2 (`name' `section') or 1 (`name').
-# Globals : $MAN_PATH must be preset as space-separated list of dirs.
-# Output : the file position for the man-page
+# The precedence for the variables related to `man' is that of GNU
+# `man', i.e.
#
-# Only called from man_page_filespec().
+# $LANG; overridden by
+# $LC_MESSAGES; overridden by
+# $LC_ALL; this has the same precedence as
+# $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM; overridden by
+# $MANOPT; overridden by
+# the groffer command line options.
#
-if [ "$HAS_MANW" = "yes" ]; then # use man -w
+man_setup()
+{
+ local _lang;
- manpage_search_name()
- {
- local _i;
- local _name;
- local _section;
- if [ "$MAN_PATH" = "" ]; then
- return 0;
- fi;
- case "$#" in
- 1)
- _name="$1";
- _section="";
+ if is_yes "$_MAN_IS_SETUP"; then
+ return "$_GOOD";
+ fi;
+ _MAN_IS_SETUP='yes';
+
+ if is_not_yes "${_MAN_ENABLE}"; then
+ return "$_GOOD";
+ fi;
+
+ # determine basic path for man pages
+ _MAN_PATH="$(get_first_essential \
+ "${_OPT_MANPATH}" "${_MANOPT_PATH}" "${MANPATH}")";
+ if is_empty "${_MAN_PATH}"; then
+ _MAN_PATH="$(manpath 2>/dev/null)"; # not on all systems available
+ fi;
+ if is_empty "${_MAN_PATH}"; then
+ manpath_set_from_path;
+ else
+ _MAN_PATH="$(path_clean "${_MAN_PATH}")";
+ fi;
+ if is_empty "${_MAN_PATH}"; then
+ _MAN_ENABLE="no";
+ return;
+ fi;
+
+ _MAN_ALL="$(get_first_essential "${_OPT_ALL}" "${_MANOPT_ALL}")";
+ if is_empty "$_MAN_ALL"; then
+ _MAN_ALL='no';
+ fi;
+
+ _MAN_SYS="$(get_first_essential \
+ "${_OPT_SYSTEMS}" "${_MANOPT_SYS}" "${SYSTEM}")";
+ _lang="$(get_first_essential \
+ "${_OPT_LANG}" "${LC_ALL}" "${LC_MESSAGES}" "${LANG}")";
+ case "${_lang}" in
+ C|POSIX)
+ _MAN_LANG="";
+ _MAN_LANG2="";
;;
- 2)
- _name="$1";
- _section="$2";
+ ?)
+ _MAN_LANG="${_lang}";
+ _MAN_LANG2="";
;;
*)
- error "manpage_search_name : needs 1 or 2 arguments.";
+ _MAN_LANG="${_lang}";
+ _MAN_LANG2="$(string_get_leading "${_lang}" '..')";
;;
- esac;
- for _i in $(man -w $_section "$_name" 2>/dev/null); do
- if [ -f "$_i" -a -r "$_i" ] &&
- (catz "$_i" | grog | grep -e '-man') >/dev/null 2>&1;
- then
- output "$_i";
- return 0;
- fi
- done;
- return 1;
- }
+ esac;
+ # from now on, use only $_LANG, forget about $_OPT_LANG, $LC_*.
-else # manually search man-page
+ manpath_add_lang_sys;
- manpage_search_name()
- {
- local _name;
- local _section;
- local _p;
- if [ "$MAN_PATH" = "" ]; then
- return 0;
- fi;
- case "$#" in
+ _MAN_SEC="$(get_first_essential \
+ "${_OPT_SECT}" "${_MANOPT_SEC}" "${MANSEC}")";
+ if is_empty "${_MAN_PATH}"; then
+ _MAN_ENABLE="no";
+ return;
+ fi;
+
+ _MAN_EXT="$(get_first_essential \
+ "${_OPT_EXTENSION}" "${_MANOPT_EXTENSION}")";
+}
+
+
+########################################################################
+# man_parse_name (<filespec>)
+#
+# Parse the man page name part off from a filespec
+#
+# Arguments: 1, 2, or 3; maybe empty
+# Output: none
+#
+man_parse_name()
+{
+ return;
+}
+
+
+########################################################################
+# man_register_file (<file> [<name> [<section>]])
+#
+# Write a found man page file and register the title element.
+#
+# Arguments: 1, 2, or 3; maybe empty
+# Output: none
+#
+man_register_file()
+{
+ case "$#" in
1)
- _name="$1";
- _section="";
- ;;
+ if is_empty "$1"; then
+ error 'man_register_file(): file name is empty';
+ else
+ to_tmp "$1";
+ return "${_OK}";
+ fi;
+ ;;
2)
- _name="$1";
- _section="$2";
- ;;
- *)
- error "man_search_name : needs 1 or 2 arguments.";
- ;;
- esac;
- for _p in $MAN_PATH; do
- set -- "$(ls -d "${_p}/man${_section}"*"/${_name}.${_section}"* \
- 2>/dev/null)";
- while [ "$#" -gt 0 ]; do
- if [ -f "$1" -a -r "$1" ]; then
- output "$1";
- return 0;
+ if is_not_empty "$1"; then
+ to_tmp "$1";
+ fi;
+ register_title "man:$2";
+ return "${_OK}";
+ ;;
+ 3)
+ if is_not_empty "$1"; then
+ to_tmp "$1";
+ fi;
+ register_title "$2($3)";
+ return "${_OK}";
+ ;;
+ *) error 'man_register_file(): wrong number of arguments'; ;;
+ esac;
+}
+
+
+########################################################################
+# man_search_section (<name> <section>)
+#
+# Retrieve man pages.
+#
+# Arguments : 2
+# Globals : $_MAN_PATH, $_MAN_EXT
+# Return : 0 if found, 1 otherwise
+#
+man_search_section()
+{
+ local _d;
+ local _dir;
+ local _ext;
+ local _got_one;
+ local _f;
+ local _name;
+ local _prefix
+ local _section;
+ if is_empty "${_MAN_PATH}"; then
+ return "${_BAD}";
+ fi;
+ if test "$#" -ne 2; then
+ error "man_sec_first() needs 2 arguments.";
+ return "${_ERROR}";
+ fi;
+ if is_empty "$1"; then
+ return "${_BAD}";
+ fi;
+ if is_empty "$2"; then
+ return "${_BAD}";
+ fi;
+ _name="$1";
+ _section="$2";
+ IFS=:
+ set -- ${_MAN_PATH}
+ unset IFS;
+ _got_one='no';
+ if is_empty "$_MAN_EXT"; then
+ for _d in "$@"; do
+ _dir="$(dirname_append "${_d}" "man${_section}")";
+ if is_dir "$_dir"; then
+ _prefix="$(dirname_append "$_dir" "${_name}.${_section}")";
+ for _f in $(echo -n ${_prefix}*); do
+ if is_file "$_f"; then
+ man_register_file "$_f" "$_name" "$_section";
+ if is_not_empty "$_MAN_ALL"; then
+ _got_one='yes';
+ return "$_GOOD";
+ fi;
+ fi;
+ done;
+ fi;
+ done;
+ else
+ _ext="${_MAN_EXT}";
+ # check for directory name having trailing extension
+ for _d in "$@"; do
+ _dir="$(dirname_append ${_d} man${_section}${_ext})";
+ if is_dir "$_dir"; then
+ _prefix="$(dirname_append "$_dir" "${_name}.${_section}")";
+ for _f in ${_prefix}*; do
+ if is_file "$_f"; then
+ man_register_file "$_f" "$_name" "$_section";
+ if is_not_empty "$_MAN_ALL"; then
+ _got_one='yes';
+ return "$_GOOD";
+ fi;
+ fi;
+ done;
+ fi;
+ done;
+ # check for files with extension in directories without extension
+ for _d in "$@"; do
+ _dir="$(dirname_append "${_d}" "man${_section}")";
+ if is_dir "$_dir"; then
+ _prefix="$(dirname_append "$_dir" \
+ "${_name}.${_section}${_ext}")";
+ for _f in ${_prefix}*; do
+ if is_file "$_f"; then
+ man_register_file "$_f" "$_name" "$_section";
+ if is_not_empty "$_MAN_ALL"; then
+ _got_one='yes';
+ return "$_GOOD";
+ fi;
+ fi;
+ done;
+ fi;
+ done;
+ fi;
+ if is_yes "$_MAN_ALL" && is_yes "$_got_one"; then
+ return "$_GOOD";
+ fi;
+ return "$_BAD";
+}
+
+
+########################################################################
+# manpath_add_lang_sys ()
+#
+# Add language and operating system specific directories to man path.
+#
+# Arguments : 0
+# Output : none
+# Globals:
+# in: $_MAN_SYS: has the form `os1,os2,...', a comma separated
+# list of names of operating systems.
+# $_MAN_LANG and $_MAN_LANG2: each a single name
+# in/out: $_MAN_PATH: has the form `dir1:dir2:...', a colon
+# separated list of directories.
+#
+manpath_add_lang_sys()
+{
+ local _p;
+ local _mp;
+ if test "$#" -ne 0; then
+ error "manpath_add_system() does not have arguments.";
+ return "$_ERROR";
+ fi;
+ if is_empty "${_MAN_PATH}"; then
+ return "${_GOOD}";
+ fi;
+ # twice test both sys and lang
+ IFS=:
+ set -- ${_MAN_PATH};
+ unset IFS;
+ _mp='';
+ for _p in "$@"; do # loop on man path directories
+ _mp="$(_manpath_add_lang_sys_single "$_mp" "$_p")";
+ done;
+ IFS=:
+ set -- ${_mp};
+ unset IFS;
+ for _p in "$@"; do # loop on man path directories
+ _mp="$(_manpath_add_lang_sys_single "$_mp" "$_p")";
+ done;
+ _MAN_PATH="$(path_chop "${_mp}")";
+}
+
+
+_manpath_add_lang_sys_single()
+{
+ # To the directory in $1 append existing sys/lang subdirectories
+ # Function is necessary to split the OS list.
+ #
+ # globals: in: $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2
+ # argument: 2: `man_path' and `dir'
+ # output: colon-separated path of the retrieved subdirectories
+ #
+ local _d;
+ _res="$1";
+ _parent="$2";
+ IFS=,
+ set -- ${_MAN_SYS} ;
+ unset IFS;
+ for _d in "$@" "$_MAN_LANG" "$_MAN_LANG2"; do
+ _dir="$(dirname_append "$_parent" "$_d")";
+ if path_not_contains "$_res" "$_dir" && is_dir "$_dir"; then
+ _res="${_res}:${_dir}";
+ fi;
+ done;
+ if path_not_contains "$_res" "$_parent"; then
+ _res="${_res}:${_parent}";
+ fi;
+ path_chop "$_res";
+}
+
+
+########################################################################
+# manpath_set_from_path ()
+#
+# Determine basic search path for man pages from $PATH.
+#
+# Return: `0' if a valid man path was retrieved.
+# Output: none
+# Globals:
+# in: $PATH
+# out: $_MAN_PATH
+#
+manpath_set_from_path()
+{
+ local _base;
+ local _d;
+ local _mandir;
+ local _manpath;
+ _manpath='';
+
+ # get a basic man path from $PATH
+ if is_not_empty "${PATH}"; then
+ IFS=:
+ set -- ${PATH}
+ unset IFS;
+ for _d in "$@"; do
+ _base="$(string_del_trailing "${_d}" '/\+bin/*')";
+ for _e in /share/man /man; do
+ _mandir="${_base}${_e}";
+ if test -d "${_mandir}" && test -r "${_mandir}"; then
+ _manpath="${_manpath}:${_mandir}";
fi;
- shift;
done;
done;
- return 1;
- }
+ fi;
-fi;
+ # append some default directories
+ for _d in /usr/local/share/man /usr/local/man \
+ /usr/share/man /usr/man \
+ /usr/X11R6/man /usr/openwin/man \
+ /opt/share/man /opt/man \
+ /opt/gnome/man /opt/kde/man; do
+ if path_not_contains "${_manpath}" "${_d}" && is_dir "${_d}"; then
+ _manpath="${_manpath}:${_d}";
+ fi;
+ done;
+
+ _MAN_PATH="${_manpath}";
+}
########################################################################
-# normalize_args (<arg>+)
+# normalize_args (<shortopts> <longopts> <arg>+)
#
# Display arguments in the normalized form of GNU `getopt'.
#
-# Arguments : if no arguments are given, $* is parsed instead
-# Globals : $ALL_LONGOPTS $ALL_SHORTOPTS
-# Output : arguments in normalized form
+# Arguments : if no arguments are given, `-' is assumed
+# Globals : in: $_OPTS_LONG, $_OPTS_SHORT
+# Output : arguments in normalized form; these must be processed by
+# eval set -- "$(normalize_args ...)"
#
-if [ "$HAS_OPTS_GNU" = "yes" ]; then
+if is_yes "${_HAS_OPTS_GNU}"; then
normalize_args()
{
- local _args;
- local _long_opts="";
+ local _long_opts;
+ local _short_opts;
local _i;
local _res;
- if [ "$#" -eq 0 ]; then
- set -- -;
+ if test "$#" -lt 2; then
+ error "normalize_args() needs at least 2 arguments";
+ return "$_ERROR";
fi;
+ _short_opts="$1";
_long_opts="";
- for _i in ${ALL_LONGOPTS}; do
- _long_opts="$(append_args $_long_opts -l "$_i")";
- done;
- if _res="$(getopt -l "$_long_opts" "$ALL_SHORTOPTS" "$@")"; then
- output "$_res";
- return 0;
+ if is_not_empty "$2"; then
+ for _i in $2; do
+ _long_opts="${_long_opts} -l '${_i}'";
+ done;
+ fi;
+ shift 2;
+ if test "$#" -eq 0; then
+ set -- -;
+ fi;
+ if _res="$(eval getopt "${_long_opts}" -o \"${_short_opts}\" \
+ -- '"$@"')"; then
+ echo -n "${_res}";
+ return "$_GOOD";
else
- error 'wrong option';
+ error 'normalize_args(): wrong option';
+ return "$_ERROR";
fi;
}
-elif [ "$HAS_OPTS_POSIX" = "yes" ]; then # POSIX getopts
+elif is_yes "${_HAS_OPTS_POSIX}"; then # POSIX getopts
normalize_args()
{
- local _args;
- local _long_opts="";
- local _i;
- local _res;
local _opt;
local _param;
- if [ "$#" -eq 0 ]; then
+ local _res;
+ local _short_opts;
+ if test "$#" -lt 2; then
+ error "normalize_args() needs at least 2 arguments";
+ return "$_ERROR";
+ fi;
+ _short_opts="$1";
+ # ignore long options in $2
+ shift 2;
+ if test "$#" -eq 0; then
set -- -;
fi;
- case "--[^ ]" in
- "$_args") error "long options are only available in GNU."; ;;
- esac;
OPTIND=1;
OPTARG="";
+ OPTERR=0; # set silent mode for getopts
_res="";
- while getopts ":$ALL_SHORTOPTS" _opt $_args; do
- if [ "$_opt" = ":" ]; then
- if [ "$OPTARG" = "-" ]; then
- error "your system does not allow GNU long options.";
- else
- error "unknown option.";
- fi;
- fi;
- _res="$(append_args $_res -"$_opt")";
- if [ "$OPTARG" != "" ]; then
- _res="$(append_args $_res "'$OPTARG'")";
- # option args are quoted;
+ # synopsis: getopts <optstring> <variable_for_optchar> <arg>*
+ while getopts "${_short_opts}" _opt "$@"; do
+ # getopts() does not fail when a wrong option is encountered.
+ case "${_opt}" in
+ \?) # wrong option found
+ if is_equal "${OPTARG}" '-'; then
+ error \
+ "your system does not support long options; use \`-W'.";
+ else
+ error "unknown option \`-${OPTARG}'.";
+ fi;
+ return "$_ERROR";
+ ;;
+ :) # argument not found (in silent mode)
+ error "no argument found for option \`-${OPTARG}'.";
+ return "$_ERROR";
+ ;;
+ esac;
+ _res="${_res} -${_opt}";
+ if is_not_empty "${OPTARG}"; then
+ _res="${_res} '${OPTARG}'";
OPTARG="";
fi;
done;
- if [ "$_opt" == '?' ]; then # end of options
+ if is_equal "${_opt}" '?'; then # end of options
# non-option parameters are quoted in the output
- _param="";
- set -- $_args;
- if [ "$OPTIND" -le "$#" ]; then
- _res="$(append_args $_res "--")";
- eval _param=${"$OPTIND"};
- if [ "$_param" != "--" ]; then
- _res="$(append_args $_res "'$_param'")";
+ _res="${_res} --";
+ if test "${OPTIND}" -le "$#"; then
+ # first non-option parameter
+ eval _param='"$'${OPTIND}'"';
+ if test "${_param}" != "--"; then
+ # save before shifting
+ _res="${_res} '${_param}'";
fi;
- shift "$OPTIND";
- while [ "$#" -gt 0 ]; do
- _res="$(append_args $_res "'$1'")";
+ shift "${OPTIND}";
+ while test "$#" -gt 0; do
+ _res="${_res} '$1'";
+ shift;
done;
fi;
- output $_res;
- return 0;
+ echo -n "${_res}"
+ return "$_OK";
else
error 'error in option parsing';
+ return "$_ERROR";
fi;
}
else
- error 'no option processor abvailable.';
+ error 'no option processor available.';
+ return "$_ERROR";
fi;
########################################################################
-# output (<text>*)
+# path_chop (<path>)
#
-# Print arguments to standard output, if there are any.
-# Handle `echo' programs that can have only 1 arg.
+# Remove unnecessary colons from path.
#
-# Arguments : any.
-# Output : the list of the arguments without a line break.
+# Argument: 1, a colon separated path.
+# Output: path without leading, double, or trailing colons.
#
-output()
+path_chop()
{
- if [ "$#" -ge 1 ]; then
- echo -n "$*";
+ local _res;
+ if test "$#" -ne 1; then
+ error 'path_chop() needs 1 argument.';
+ return "$_ERROR";
fi;
+
+# _res="$1";
+# _res="$(string_flatten "$_res" ':')";
+# _res="$(string_del_leading "$_res" ':')";
+# _res="$(string_del_trailing "$_res" ':')";
+# echo -n "$_res";
+
+ echo -n "$1" | sed -e '\|::\+|s||:|g' |
+ sed -e '\|^:*|s|||' |
+ sed -e '\|:*$|s|||';
+}
+
+
+########################################################################
+# path_clean (<path>)
+#
+# Remove non-existing directories from a colon-separated list.
+#
+# Argument: 1, a colon separated path.
+# Output: colon-separated list of existing directories.
+#
+path_clean()
+{
+ local _arg;
+ local _dir;
+ local _res;
+ if test "$#" -ne 1; then
+ error 'path_clean() needs 1 argument.';
+ return "$_ERROR";
+ fi;
+ _arg="$1";
+ IFS=:
+ set -- ${_arg};
+ unset IFS;
+ _res="";
+ for _i in "$@"; do
+ if is_not_empty "$_i" \
+ && path_not_contains "${_res}" "$_i" \
+ && is_dir "$_i";
+ then
+ _dir="$(dirname_chop "$_i")";
+ _res="${_res}:${_dir}";
+ fi;
+ done;
+ path_chop "${_res}";
+}
+
+
+########################################################################
+# path_contains (<path> <dir>)
+#-
+# Test whether `dir' is contained in `path', a list separated by `:'.
+#
+# Arguments : 2 arguments.
+# Return : `0' if arg2 is substring of arg1, `1' otherwise.
+#
+path_contains()
+{
+ if test "$#" -ne 2; then
+ error "path_contains() needs 2 arguments.";
+ return "$_ERROR";
+ fi;
+ case ":$1:" in
+ *":$2:"*) return "$_YES"; ;;
+ *) return "$_NO"; ;;
+ esac;
+}
+
+
+########################################################################
+# path_not_contains (<path> <dir>)
+#-
+# Test whether `dir' is not contained in colon separated `path'.
+#
+# Arguments : 2 arguments.
+# Return : `1' if arg2 is substring of arg1, `0' otherwise.
+#
+path_not_contains()
+{
+ if test "$#" -ne 2; then
+ error "path_not_contains() needs 2 arguments.";
+ return "$_ERROR";
+ fi;
+ case ":$1:" in
+ *":$2:"*) return "$_NO"; ;;
+ *) return "$_YES"; ;;
+ esac;
}
########################################################################
# register_title (<filespec>)
#
-# Transform argument into a title element and append to $TMP_TITLE file.
+# Create title element from <filespec> and append to $_REGISTERED_TITLE
+#
+# Globals: $_REGISTERED_TITLE (rw)
+#
+register_title()
+{
+ local _t;
+ if test "$#" -ne 1; then
+ error "register_title() needs exactly 1 argument.";
+ return "$_ERROR";
+ fi;
+ if is_empty "$1"; then
+ return "$_OK";
+ fi;
+ _t="$(base_name "$1")"; # remove directory part
+ _t="$(string_del_trailing "${_t}" '\.gz')"; # remove .gz
+ _t="$(string_del_trailing "${_t}" '\.Z')"; # remove .Z
+ if is_empty "${_t}"; then
+ return "$_OK";
+ fi;
+ _REGISTERED_TITLE="${_REGISTERED_TITLE} ${_t}";
+}
+
+
+########################################################################
+# save_stdin ()
+#
+# Store standard input to temporary file.
#
-# This is defined in the main:temporary section
+save_stdin()
+{
+ cat | catz - >"${_TMP_STDIN}"; # using `cat' first is safer
+}
+########################################################################
+# string_contains (<string> <part>)
+#
+# Test whether `part' is contained in `string'.
+#
+# Arguments : 2 text arguments.
+# Return : `0' if arg2 is substring of arg1, `1' otherwise.
+#
+string_contains()
+{
+ if test "$#" != 2; then
+ error 'string_contains() needs 2 arguments.';
+ return "$_ERROR";
+ fi;
+ case "$1" in
+ *"$2"*) return "$_YES"; ;;
+ *) return "$_NO"; ;;
+ esac;
+}
+
########################################################################
-# save_stdin_if_any ()
+# string_del_leading (<string> <regex>)
+#
+# Delete the beginning <regex> of <string>, if any.
#
-# Check if stdin is needed; if so, store to temporary file.
-# Globals : $FILE_ARGS
+# Arguments: 2
+# <string>: arbitrary sequence of characters.
+# <regex>: is a BRE like in `sed';
+# Do not worry about the address delimiter, the program escapes them.
+# Output: the replaced string.
#
-save_stdin_if_any()
+string_del_leading()
{
- local _a
- set -- $FILE_ARGS
- for _a in "$@"; do
- if [ "$_a" = "'-'" ]; then
- cat | catz - >"$TMP_INPUT"; # using `cat' first is safer
- break;
+ local _del;
+ local _result;
+ local _string;
+ if test "$#" -ne 2; then
+ error "string_del_leading() needs 2 arguments.";
+ return "$_ERROR";
+ fi;
+ _string="$1";
+ _del="$2";
+ if is_empty "${_string}"; then
+ if is_empty "${_del}"; then
+ return "${_GOOD}";
+ else
+ return "${_BAD}";
fi;
- done;
+ fi;
+ if is_empty "${_del}"; then
+ echo -n "${_string}";
+ return "${_GOOD}";
+ fi;
+ _result="$(string_sed_s "${_string}" '^'"${_del}" '')";
+ echo -n "${_result}";
+ if is_equal "${_result}" "${_string}"; then
+ return "${_BAD}";
+ else
+ return "${_GOOD}";
+ fi;
+}
+
+
+########################################################################
+# string_del_trailing (<string> <regex>)
+#
+# Delete the final <regex> of <string>, if any.
+#
+# Arguments: 2
+# <string>: arbitrary sequence of characters.
+# <regex>: is a BRE like in `sed';
+# Do not worry about the address delimiter, the program escapes them.
+# Output: the replaced string.
+#
+string_del_trailing()
+{
+ local _del;
+ local _result;
+ local _string;
+ if test "$#" -ne 2; then
+ error "string_del_trailing() needs 2 arguments.";
+ return "$_ERROR";
+ fi;
+ _string="$1";
+ _del="$2";
+ if is_empty "${_string}"; then
+ if is_empty "${_del}"; then
+ return "$_GOOD";
+ else
+ return "$_BAD";
+ fi;
+ fi;
+ if is_empty "${_del}"; then
+ echo -n "${_string}";
+ return "$_GOOD";
+ fi;
+ _result="$(string_sed_s "${_string}" "${_del}"'$' '')";
+ echo -n "${_result}";
+ if is_equal "${_result}" "${_string}"; then
+ return "$_BAD";
+ else
+ return "$_GOOD";
+ fi;
}
########################################################################
-# shift_quoted (<arg>*)
+# string_flatten (<string> <char>)
#
-# Expects single-quoted arguments, strips the first quoted argument.
+# Reduce multiple occurences of character <char> in <string> to one.
#
-# Arguments : single-quoted, evt. with included spaces.
-# Output : delete everything up to the next arg terminated by a
-# quote and the following space, output the rest.
-# Return : `1' if arguments are not single-quoted, `0' otherwise.
+# Arguments: 2
+# <string>: arbitrary sequence of characters.
+# <char>: a character, or escaped character for sed.
+# Do not worry about the address delimiter, the program escapes them.
+# Output: the retrieved string.
#
-shift_quoted()
+string_flatten()
{
- local _args="$*";
- shift "$(count_next_quoted $_args)";
- output $*;
+ if test "$#" -ne 2; then
+ error "string_flatten() needs 2 arguments.";
+ return "$_ERROR";
+ fi;
+ _string="$1";
+ _char="$2";
+ string_replace_all "$_string" "${_char}${_char}\+" "$_char";
}
########################################################################
-# supercat (<filearg>*)
+# string_get_leading (<string> <regex>)
#
-# Output the concatenation of files, man-pages, or standard input to
-# standard output. All parts that are stored in the gzip or Z
-# compression format are decompressed. No other modifications.
-# All processed arguments are added to the global variable
-# $ARGS_DONE.
+# Get the beginning <regex> of <string>, if any.
#
-# Arguments :
-# All arguments are expected to be surrounded by single quotes.
-# - names of existing files.
-# - '-' to represent standard input (several times allowed).
-# - 'man:name.(section)' the man-page for `name' in `section'.
-# - 'man:name' the man-page for `name' in the lowest `section'.
-# - 'name.section' the man-page for `name' in `section'.
-# - 'name' the man-page for `name' in the lowest `section'.
-# Globals :
-# $TMP_INPUT : (read-only)
-# $ARGS_DONE : (read-write) arguments with a corresponding file
-# are added to variable ARGS_DONE.
-# Output : the decompressed files corresponding to the arguments
-# Return : 0 always, all errors are tolerated or fatal.
+# Arguments: 2
+# <string>: arbitrary sequence of characters.
+# <regex>: is a BRE like in `sed';
+# Do not worry about the address delimiter, the program escapes them.
+# Output: the retrieved string.
#
-supercat()
+string_get_leading()
{
- local _file;
- local _filespec;
- local _args;
- local _mode;
- local _sequence;
- if [ "$#" -eq 0 ]; then
- error 1 "supercat needs at least 1 arg";
- fi;
- # remove enclosing quotes and space characters
- _args="$(output $* | grep -e "^ *'.\+'"'$' |
- sed -e '\|^ *\(.*\) *$|s||\1|')";
- if [ "$_args" = "" ]; then
- error 1 "supercat : arguments are not quoted.";
- fi;
- while [ "$_args" != "" ]; do
- _filespec="$(get_next_quoted $_args)";
- _args="$(shift_quoted $_args)";
- if [ "$_filespec" = "" ]; then
- continue;
- fi;
- if [ "$_filespec" = "-" ]; then
- catz "$TMP_INPUT";
- register_title "-";
- continue;
- fi
- if [ "$ENABLE_MANPAGES" = "yes" ]; then
- if [ "$OPT_MAN" = "yes" ]; then
- _sequence="Manpage File";
- else
- _sequence="File Manpage";
- fi;
+ local _del;
+ local _result;
+ local _string;
+ if test "$#" -ne 2; then
+ error "string_get_leading() needs 2 arguments.";
+ return "$_ERROR";
+ fi;
+ _string="$1";
+ _get="$2";
+ if is_empty "${_string}"; then
+ if is_empty "${_get}"; then
+ return "${_GOOD}";
else
- _sequence="File";
+ return "${_BAD}";
fi;
- _done="no";
- for _mode in $_sequence; do
- case "$_mode" in
- File)
- if [ -f "$_filespec" -a -r "$_filespec" ]; then
- catz "$_filespec";
- register_title "$_filespec";
- _done="yes";
- break;
- fi;
- ;;
- Manpage)
- _manfile="$(manpage_search_filespec "$_filespec")";
- if [ "$?" -eq 0 ]; then
- catz "$_manfile";
- register_title "$_manfile";
- _done="yes";
- break;
- fi;
- ;;
- esac;
- done;
- if [ "$_done" != "yes" ]; then
- echo2 \"$_filespec\" is neither a file nor a man-page.;
+ fi;
+ if is_empty "${_get}"; then
+ echo -n "${_string}";
+ return "${_GOOD}";
+ fi;
+ _result="$(string_sed_s "${_string}" '^\('"${_get}"'\).*$' '\1')";
+ echo -n "${_result}";
+ if is_equal "${_result}" "${_string}"; then
+ return "${_BAD}";
+ else
+ return "${_GOOD}";
+ fi;
+}
+
+
+########################################################################
+# string_replace_all (<string> <regex> <replace>)
+#
+# Replace <regex> by <replace> in <string>. Interface to `sed s'.
+#
+# Arguments: 3
+# <regex>: is a BRE like in `sed';
+# <replace>: like the last element in `sed s', honors \1, etc.
+# <string>: no special characters, no restrictions.
+# Do not worry about the address delimiter, the program escapes them.
+# Output: the replaced string.
+# Return: `1', if no replace; `0' otherwise.
+#
+string_replace_all()
+{
+ if test "$#" -ne 3; then
+ error "string_replace_all() needs exactly 3 arguments.";
+ return "$_ERROR";
+ fi;
+ string_sed_s "$@" 'g';
+}
+
+
+########################################################################
+# string_sed_s (<string> <regex> [<replace> [<flag>]])
+#
+# Feed command `sed s' independently of delimiter.
+#
+# Equivalent to:
+# echo -n <string> | sed -e '/<regex>/s//<replace>/<flag>';
+#
+# Arguments: do not worry about the deliniter character `/'.
+# 2: <replace>='', <flag>=''
+# 3: <flag>=''
+# 4: with sed flag, e.g. `g' for global
+# Output: the resulting string.
+#
+string_sed_s()
+{
+ local _flag;
+ local _regex;
+ local _replace;
+ local _string;
+ case "$#" in
+ 2)
+ _replace='';
+ _flag='';
+ ;;
+ 3)
+ _replace="$(_string_sed_s_esc_slash "$3")";
+ _flag='';
+ ;;
+ 4)
+ _replace="$(_string_sed_s_esc_slash "$3")";
+ _flag="$4";
+ ;;
+ *)
+ error "string_sed_s() needs 2, 3, or 4 arguments.";
+ return "$_ERROR";
+ ;;
+ esac;
+ _string="$1";
+ _regex="$(_string_sed_s_esc_slash "$2")";
+ if is_empty "${_string}"; then
+ return "$_OK";
+ fi;
+ if is_empty "${_string}"; then
+ error "string_sed_s(): empty regular expression";
+ return "$_ERROR";
+ fi;
+ echo -n "${_string}" | \
+ eval sed -e \'/"${_regex}"/s//"${_replace}"/"${_flag}"\';
+} # string_sed_s()
+
+
+_string_sed_s_esc_slash()
+{
+ # Replace each slash `/' by `\/' outside of `[]' as in `sed s'.
+ # This makes the `sed' input independent of the delimiter '/'.
+ #
+ # Argument: 1, arbitrary string, may even contain line breaks.
+ # Output: the replaced string.
+ #
+ local _append;
+ local _last;
+ _append='Z';
+ if test "$#" -ne 1; then
+ error '_string_sed_s_esc_slash() requires 1 argument.';
+ return "$_ERROR";
+ fi;
+ if is_empty "$1"; then
+ return "$_GOOD";
+ fi;
+ # append a character to the argument to cover a final line break
+ unset IFS;
+ set -- "${1}${_append}";
+ # split at line breaks
+ IFS="${_NEWLINE}"
+ set -- $1;
+ unset IFS;
+ while test "$#" -ge 2; do
+ _string_sed_s_esc_slash_line "$1";
+ shift;
+ done;
+ if test "$#" -ne 1; then
+ error "string_sed_s_esc_slash() unexpected \`$#'";
+ return "$_ERROR";
+ fi;
+ if is_equal "${_last}" "${_append}"; then
+ echo;
+ return "$_GOOD";
+ fi;
+ _last=$(echo -n "$1" | eval sed -e \''/'"${_append}"'$/s///'\');
+ _string_sed_s_esc_slash_line "${_last}";
+} # _string_sed_s_esc_slash()
+
+
+_string_sed_s_esc_slash_line()
+{
+ # In a text line replace each slash `/' by `\/', but not within `[]'.
+ local _beginning;
+ local _bracketed;
+ local _end;
+ local _rest;
+ local _result;
+ local _s;
+ if test "$#" -ne 1; then
+ error '_string_sed_s_esc_slash_line() requires 1 argument.';
+ return "$_ERROR";
+ fi;
+ _rest="$1";
+ _result='';
+ while true; do
+ if ! string_contains "${_rest}" '/'; then
+ _result="${_result}${_rest}";
+ echo -n "${_result}";
+ return "$_GOOD";
+ fi;
+ if ! string_contains "${_rest}" '['; then
+ _result="${_result}$(_string_sed_s_esc_slash_unbracketed \
+ "${_rest}")";
+ echo -n "${_result}";
+ return "$_GOOD";
+ fi;
+ # split at first bracket.
+ _beginning="$(echo -n "${_rest}" | sed -e '/^\([^[]*\).*$/s//\1/')";
+ _rest="$(echo -n "${_rest}" | sed -e '/^[^[]*/s///')";
+ if is_not_empty "${_beginning}"; then
+ _s="$(_string_sed_s_esc_slash_unbracketed "${_beginning}")";
+ _result="${_result}${_s}";
+ fi;
+ if ! string_contains "${_rest}" '/'; then
+ _result="${_result}${_rest}";
+ echo -n "${_result}";
+ return "$_GOOD";
+ fi;
+ case "${_rest}" in
+ \[\]*\]*) # `[]...]' construct
+ _bracketed="$(echo -n "${_rest}" | \
+ sed -e '/^\(\[\][^]]*\]\).*$/s//\1/')";
+ _rest="$(echo -n "${_rest}" | \
+ sed -e '/^\(\[\][^]]*\]\)\(.*\)$/s//\2/')";
+ ;;
+ \[^\]*\]*) # `[^]...]' construct
+ _bracketed="$(echo -n "${_rest}" | \
+ sed -e '/^\(\[^\][^]]*\]\).*$/s//\1/')";
+ _rest="$(echo -n "${_rest}" | \
+ sed -e '/^\(\[^\][^]]*\]\)\(.*\)$/s//\2/')";
+ ;;
+ \[*\]*) # `[...]' construct
+ _bracketed="$(echo -n "${_rest}" | \
+ sed -e '/^\(\[[^]]*\]\).*$/s//\1/')";
+ _rest="$(echo -n "${_rest}" | \
+ sed -e '/^\(\[[^]]*\]\)\(.*\)$/s//\2/')";
+ ;;
+ *)
+ error \
+ '_string_sed_s_esc_slash(): $_rest must start with a bracket';
+ return "$_ERROR";
+ ;;
+ esac;
+ _result="${_result}${_bracketed}";
+ if ! string_contains "${_rest}" '/'; then
+ echo -n "${_result}${_rest}";
+ return "$_GOOD";
fi;
done;
-}
+} # _string_sed_s_esc_slash_line()
+
+
+_string_sed_s_esc_slash_unbracketed()
+{
+ # Do the escaping of slashes in strings that do not contain a bracket.
+ #
+ # Argument: 1, may not contain a `[' nor line breaks.
+ # Output: precede each slash in the argument by a backslash.
+ # Return: 1, if argument has a `['; 0 otherwise.
+ #
+ local _arg;
+ local _result;
+ local _separator;
+ local _i;
+ if test "$#" -ne 1; then
+ error \
+'_string_sed_s_esc_slash_unbracketed() needs 1 argument).';
+ return "$_ERROR";
+ fi;
+ _arg="$1";
+ if string_contains "$_arg" '['; then
+ error "_string_sed_s_esc_slash(): no bracket allowed in argument.";
+ return "$_ERROR";
+ fi;
+ case "${_arg}" in
+ /)
+ echo -n '\/';
+ return "$_OK";
+ ;;
+ */*)
+ _result="";
+ # split argument at `/' into the positional parameters
+ IFS=/
+ set -- $(echo -n "${_arg}");
+ unset IFS;
+ _result="";
+ _separator="";
+ while test "$#" -ge 1; do
+ _result="${_result}${_separator}$1";
+ _separator='\/';
+ shift;
+ done;
+ case "${_arg}" in # IFS character at the end is omitted
+ */)
+ _result="${_result}\/";
+ ;;
+ esac;
+ echo -n "${_result}";
+ return "$_OK";
+ ;;
+ *)
+ echo -n "${_arg}";
+ return "$_OK";
+ ;;
+ esac;
+} # _string_sed_s_esc_slash_unbracketed()
########################################################################
@@ -1126,7 +2346,7 @@ supercat()
#
tmp_cat()
{
- cat "$TMP_CAT";
+ cat "${_TMP_CAT}";
}
@@ -1143,38 +2363,36 @@ tmp_cat()
tmp_create()
{
- local _i;
- local _tmp="";
- _tmp="${TEMP_PREFIX}${PROCESS_ID}$1";
- echo -n >"$_tmp";
- output "$_tmp";
+ local _tmp;
+ _tmp="${_TMP_PREFIX}${_PROCESS_ID}$1";
+ echo -n >"${_tmp}";
+ echo -n "${_tmp}";
}
########################################################################
-# unquote (<arg>*)
-#
-# Remove quotes around each argument and escape all space characters
-# by a backslash `\'.
+# to_tmp (<filename>)
#
-# Output : the same number of arguments, but each processed.
-#
-unquote()
+# print file (decompressed) to the temporary cat file
+to_tmp()
{
- local _res;
- local _a;
- local _args;
- [ "$#" = 0 ] && return;
- _res="";
- for _a in "$@"; do
- _unq="$(eval output $_a | sed -e '\| |s||\\ |g')";
- if [ "$_res" = "" ]; then
- _res="$_unq";
+ if test "$#" -ne 1; then
+ error "to_tmp() expects 1 file argument."
+ return "$_ERROR";
+ fi;
+ if is_file "$1"; then
+ if is_yes "$_OPT_LOCATION"; then
+ echo2 "$1";
+ fi;
+ if is_yes "$_OPT_WHATIS"; then
+ what_is "$1" >>"${_TMP_CAT}";
else
- _res="$_res $_unq";
+ catz "$1" >>"${_TMP_CAT}";
fi;
- done;
- output "$_res";
+ else
+ error "to_tmp(): could not read file \`$1'.";
+ return "$_ERROR";
+ fi;
}
@@ -1185,15 +2403,22 @@ unquote()
#
usage()
{
+ local _header;
+ local _gap;
+ _header="Usage: ${_PROGRAM_NAME}";
+ _gap="$(string_replace_all "${_header}" '\.' ' ')";
echo2;
- local _gap="$(echo -n $PROGRAM_NAME | sed -e '/./s// /g')";
version;
cat >&2 <<EOF
Copyright (C) 2001 Free Software Foundation, Inc.
This is free software licensed under the GNU General Public License.
-Usage : $PROGRAM_NAME [options] [file] [-] [[man:]manpage.x]
- $_gap [[man:]manpage(x)] [[man:]manpage]...
+EOF
+
+ echo2 "${_header} [options] [file] [-] [[man:]manpage.x]";
+ echo2 "${_gap} [[man:]manpage(x)] [[man:]manpage]...";
+
+ cat >&2 <<EOF
Display roff files, standard input, and/or Unix manual pages with
in a X window viewer or in a text pager.
@@ -1206,17 +2431,23 @@ All input is decompressed on-the-fly (by gzip).
-T --device=name set device for X or tty output.
-v --version print version information.
--dpi=res set resolution to "res" ("75" or "100" (default)).
+--extension=ext restrict man pages to section suffix.
+--local-file same as --no-man.
+--locale=lang preset the language for man pages.
--man check file parameters first whether they are man pages.
--manpath=path preset path for searching man-pages.
--no-man disable man-page facility.
+--pager=program preset the paging program for tty mode.
+--system=os1,... search man pages for different operating systems.
--title='text' set the title of the viewer window in X.
--tty force paging on text terminal even when in X.
--xrdb=opt pass "opt" as option to gxditview (several allowed).
-All other options are interpreted as "groff" parameters and transferred
-unmodified to "grog".
+
+All other short options are interpreted as "groff" parameters and
+transferred unmodified.
EOF
- if [ "$HAS_OPTS_GNU" != "yes" ]; then
+ if is_yes "${_HAS_OPTS_GNU}"; then
cat >&2 <<EOF
Your system does not support GNU long options. You can use the POSIX
@@ -1238,7 +2469,106 @@ EOF
#
version()
{
- echo2 "$PROGRAM_NAME $PROGRAM_VERSION of $LAST_UPDATE";
+ echo2 "${_PROGRAM_NAME} ${_PROGRAM_VERSION} of ${_LAST_UPDATE}";
+}
+
+
+########################################################################
+# warning (<string>)
+#
+# Print warning to stderr
+#
+warning()
+{
+ echo2 "warning: $*";
+}
+
+
+########################################################################
+# what_is (<filename>)
+what_is ()
+{
+ local _res;
+ local _dot;
+ if test "$#" -ne 1; then
+ error "to_tmp() expects 1 file argument."
+ return "$_ERROR";
+ fi;
+ if ! is_file "$1"; then
+ error "to_tmp(): argument is not a readable file."
+ return "$_ERROR";
+ fi;
+ _dot='^\.[ ]*';
+ echo '.br';
+ echo "$1: ";
+ echo '.br';
+ echo -n ' ';
+ _res="$(catz "$1" | sed -e '/'"$_dot"'TH /p
+d')";
+ if is_not_empty "$_res"; then # traditional man style
+ catz "$1" | sed -e '1,/'"$_dot"'SH/d' \
+ | sed -e '1,/'"$_dot"'SH/p
+d' \
+ | sed -e '/'"$_dot"'SH/d';
+ return "$_GOOD";
+ fi;
+ _res="$(catz "$1" | grep "$_dot"'Dd ')";
+ if is_not_empty "$_res"; then # BSD doc style
+ catz "$1" | sed -e '/'"$_dot"'Nd /p
+d' \
+ | sed -e '2q' \
+ | sed -e '/'"$_dot"'Nd *\(.*\)$/s//\1/';
+ return "$_GOOD";
+ fi;
+ echo 'is not a man page.';
+ return "$_BAD";
+}
+
+
+########################################################################
+# where (<program>)
+#
+# Print path of a program if in $PATH
+#
+# Arguments : 1 (empty allowed)
+# Return : `0' if arg1 is a program in $PATH, `1' otherwise.
+#
+where()
+{
+ local _p;
+ local _file;
+ local _arg;
+ if test "$#" -ne 1; then
+ error "where() needs 1 argument.";
+ return "$_ERROR";
+ fi;
+ _arg="$1";
+ if is_empty "${_arg}"; then
+ return "$_BAD";
+ fi;
+ case "${_arg}" in
+ /*)
+ if test -f "${_arg}" && test -x "${_arg}"; then
+ return "$_GOOD";
+ else
+ return "$_BAD";
+ fi;
+ ;;
+ esac;
+ IFS=:
+ set -- ${PATH}
+ unset IFS
+ for _p in "$@"; do
+ case "${_p}" in
+ */) _file=${_p}${_arg}; ;;
+ *) _file=${_p}/${_arg}; ;;
+ esac;
+ if test -f "${_file}" && test -x "${_file}"; then
+ echo -n "${_file}";
+ return "$_GOOD";
+ fi;
+ done;
+ return "$_BAD";
}
@@ -1247,285 +2577,684 @@ version()
########################################################################
# The main area contains the following parts:
-# - argument parsing
-# - setup for display mode
-# - setup for man-pages
-# - temporary files
-# - display
+# - main_init(): initialize temporary files and set exit trap
+# - main_parse_args(): argument parsing
+# - determine display mode
+# - setup display mode
+# - parse $MANOPT
+# - process filespecs
+# - do the displaying
+
+# These parts are implemented as functions, being defined below in the
+# sequence they are called in the main() function.
+#######################################################################
+# main_init ()
+#
+# set exit trap and create temporary files
+#
+# Globals: $_TMP_CAT, $_TMP_STDIN
+#
+main_init()
+{
+ # call clean_up() on any signal
+ trap clean_up 2>/dev/null || true;
+
+ _TMP_CAT="$(tmp_create)";
+ _TMP_STDIN="$(tmp_create i)";
+}
+
########################################################################
-# argument parsing (main)
+# main_parse_args (<command_line_args>*)
+#
+# Parse arguments; process options and filespec parameters
#
-set -- $(normalize_args "$@");
+# Arguments: pass the command line arguments unaltered.
+# Globals:
+# in: $_OPTS_*
+# out: $_OPT_*, $_ADDOPTS, $_FILEARGS
+#
+main_parse_args()
+{
+ local _arg;
+ local _code;
+ local _dpi;
+ local _longopt;
+ local _mode;
+ local _opt;
+ local _optchar;
+ local _optarg;
+ local _opts;
+ local _stdin_done;
+ local _string;
+ local _stripped;
+ local _warg;
+
+ eval set -- "${GROFFER_OPT}" '"$@"';
+ eval set -- "$(normalize_args \
+ "${_OPTS_CMDLINE_SHORT}" "${_OPTS_CMDLINE_LONG}" "$@")";
+
+# By the call of `eval', unnecessary quoting was removed. So the
+# positional shell parameters ($1, $2, ...) are now guaranteed to
+# represent an option or an argument to the previous option, if any;
+# then a `--' argument for separating options and
+# parameters; followed by the filespec parameters if any.
+
+# Note, the existence of arguments to options has already been checked.
+# So a check for `$#' or `--' should not be done for arguments.
+
+ until test "$#" -le 0 || is_equal "$1" '--'; do
+ _opt="$1"; # $_opt is fed into the option handler
+ shift;
-# $* is garanteed to have a "--" argument, separating opts and params.
-# Note that all arguments to options and all non-option parameters are
-# enclosed in single quotes, while options are not quoted. The quotes
-# must be removed before being used, see function `unqote'. For example,
-# -X -m 'www' -- 'file1' '-' 'file2'
-# parse options
-until [ "$1" = "--" -o "$1" = "'--'" ]; do
- # Note: arguments to options are quoted; these quotes must be handled.
- #
- _opt="$1";
- shift;
- if [ "$_opt" = "-W" ]; then
- _arg="$(get_next_quoted $*)";
- if echo "$GROFFER_LONGOPTS" | tr " " '
-' | grep "^$_arg"'$' >/dev/null 2>&1; then
- # long option without argument triggered
- _opt="--$_arg";
- set -- $(shift_quoted $*);
- elif is_substring_of "[^=]=" "$_arg"; then
- # possibly long option with argument
- _argopt="$(echo "$_arg" | sed -e '\|^\([^=]\+\)=.*$|s||\1|')";
- _argarg="$(echo "$_arg" | sed -e '\|^[^=]\+=\(.*\)$|s||\1|')";
- if echo "$GROFFER_ARG_LONGS" | tr " " '
-' | grep "^$_argopt"':$' >/dev/null 2>&1; then
- # long option with argument triggered
- _opt="--$_argopt";
- set -- "'$_argarg'" $(shift_quoted $*);
- fi
- fi
- fi; # else -W does not mean a long option
-
- case "$_opt" in
- -h|--help)
- usage;
- leave;
+# The special option `-W warg' can introduce a long groffer option
+# (when `warg' starts with `--') or it is passed to groff (otherwise).
+# It is worked on as follows.
+#
+# 1) If `warg' does not start with `--', `-W warg' is to be passed to
+# groff as the groff no-warning option, so
+# - store `-W warg' to `$_ADDOPTS';
+# - get to the next option by a `continue'.
+#
+# Otherwise, `warg' starts with `--'; so check whether `warg' can
+# represent a long option by the following steps:
+#
+# 2) If `warg' is exactly a long groffer option without an argument then
+# - store `warg' to `$_opt' (with the leading `--');
+# - go to the option handler.
+# 3) If `warg' is exactly a long option that needs an argument then
+# the argument for this option is the argument of the next `-W'
+# command, which must follow immadiately; so
+# - store `warg' to `$_opt';
+# - if the next positional parameter is not `-W', then error;
+# - just skip the next `-W'; the wanted option argument is now `$1';
+# - go to the option handler.
+# 4) If `arg' contains a `=' (equal sign) and the part before the
+# first `=' is a long option that needs an argument, then
+# - store this option to `$_opt';
+# - put the argument back as `$1' before the remaining positional
+# parameters;
+# - go to the option handler.
+# Otherwise, error.
+# 5) Otherwise, error.
+
+ if is_equal "${_opt}" '-W'; then
+ _warg="$1";
+ shift;
+ case "${_warg}" in
+ --*) # test on long option (steps 2-5)
+ _stripped="$(string_del_leading "${_warg}" '--')";
+ if string_contains " ${_OPTS_CMDLINE_LONG_NA} " \
+ " ${_stripped} ";
+ then # long option without argument (step 2)
+ _opt="--${_stripped}";
+ elif string_contains \
+ " ${_OPTS_CMDLINE_LONG_ARG} " " ${_stripped}: ";
+ then # separate argument expected (step 3)
+ _opt="--${_stripped}";
+ if "$#" -eq 0; then
+ error "no argument found for \`${_opt}'";
+ return "$_ERROR";
+ fi
+ if is_equal "$1" '-W'; then
+ shift; # long option argument is now $1
+ else
+ error "no argument found for \`${_opt}'";
+ return "$_ERROR";
+ fi
+ else # test on `=' (step 4)
+ case "${_stripped}" in
+ ?*=*) # has embedded `='
+ # split off option before first `='
+ _longopt="$(string_del_trailing "${_stripped}" '=.*')";
+ if is_substring_of \
+ " ${_OPTS_CMDLINE_LONG_ARG} " " ${_longopt}: ";
+ then # `opt=arg' verified (step 4)
+ # split off argument after first `='
+ _optarg="$(string_del_leading \
+ "${_stripped}" "${_longopt}=")";
+ _opt="--${_longopt}";
+ set -- "${_optarg}" "$@";
+ else
+ error "wrong option \`-W ${_warg}'";
+ return "$_ERROR";
+ fi;
+ ;;
+ *)
+ error "wrong option \`-W ${_warg}'";
+ return "$_ERROR";
+ ;;
+ esac;
+ fi;
+ ;;
+ *) # argument is a warning
+ _ADDOPTS_GROFF="${_ADDOPTS_GROFF} -W '${_warg}'";
+ if test "$#" -le 0 || is_equal "$1" '--' ]; then
+ break;
+ else
+ _opt="$1";
+ shift;
+ fi;
+ ;;
+ esac;
+ else # not `-W'
+ do_nothing;
+ fi;
+ # now $_opt contains the option; $1 is its argument if needed.
+
+ # handle options
+ case "${_opt}" in
+ -h|--help)
+ usage;
+ leave;
+ ;;
+ -P|--to-postproc) # option for postprocessor, arg;
+ _arg="$1";
+ shift;
+ _ADDOPTS_POST="${_ADDOPTS_POST} -P '${_arg}'";
+ ;;
+ -Q|--source) # output source code (`Quellcode').
+ _OPT_MODE="source";
+ ;;
+ -T|--device|--troff-device)
+ # device; arg
+ _arg="$1";
+ shift;
+ _OPT_DEVICE="${_arg}";
+ ;;
+ -v|--version)
+ version;
+ leave;
+ ;;
+ -X)
+ _OPT_MODE="X";
+ ;;
+ -Z|--ditroff|--intermediate-output)
+ # groff intermediate output
+ _OPT_MODE="intermediate-output";
+ ;;
+ -?)
+ _optchar="$(string_del_leading "${_opt}" '-')";
+ if string_contains "${_OPTS_GROFF_SHORT_NA}" "${_optchar}"; then
+ _ADDOPTS_GROFF="${_ADDOPTS_GROFF} '${_opt}'";
+ elif string_contains "${_OPTS_GROFF_SHORT_ARG}" "${_optchar}";
+ then
+ _arg="$1";
+ shift;
+ _ADDOPTS_GROFF="${_ADDOPTS_GROFF} '${_opt}' '${_arg}'";
+ else
+ error "Unknown option : \`$1'";
+ return "$_ERROR";
+ fi;
+ ;;
+ --all)
+ _OPT_ALL="yes";
+ ;;
+ --apropos)
+ _OPT_APROPOS="yes";
+ ;;
+ --bg) # background color for gxditview, arg;
+ _arg="$1";
+ shift;
+ _ADDOPTS_X="${_ADDOPTS_X} -P -bg -P '${_arg}'";
+ ;;
+ --display) # set X display, arg
+ DISPLAY="$1";
+ shift;
+ ;;
+ --dpi) # set resolution for X devices, arg
+ _arg="$1";
+ shift;
+ case "${_arg}" in
+ 75|75dpi)
+ _dpi=75;
+ ;;
+ 100|100dpi)
+ _dpi=100;
+ ;;
+ *)
+ error "only resoutions of 75 or 100 dpi are supported";
+ return "$_ERROR";
+ ;;
+ esac;
+ _string="-P -resolution -P '${_dpi}'";
+ _ADDOPTS_X="${_ADDOPTS_X} ${_string}";
+ ;;
+ --extension) # the extension for man pages, arg
+ _OPT_EXTENSION="$1";
+ shift;
+ ;;
+ --fg) # foreground color for gxditview, arg;
+ _arg="$1";
+ shift;
+ _ADDOPTS_X="${_ADDOPTS_X} -P -fg -P '${_arg}'";
+ ;;
+ --geometry) # geometry for gxditview window, arg;
+ _arg="$1";
+ shift;
+ _ADDOPTS_X="${_ADDOPTS_X} -P -geometry -P '${_arg}'";
+ ;;
+ --lang|--locale) # set language for man pages, arg
+ # argument is xx[_territory[.codeset[@modifier]]] (ISO 639,...)
+ _OPT_LANG="$1";
+ shift;
+ ;;
+ --local-file) # force local files; same as `--no-man'
+ _MAN_FORCE="no";
+ _MAN_ENABLE="no";
+ ;;
+ --location|where) # print file locations to stderr
+ _OPT_LOCATION='yes';
+ ;;
+ --man) # force all file params to be man pages
+ _MAN_ENABLE="yes";
+ _MAN_FORCE="yes";
+ ;;
+ --manpath) # specify search path for man pages, arg
+ # arg is colon-separated list of directories
+ _OPT_MANPATH="$1";
+ shift;
+ ;;
+ --mode) # display mode
+ _arg="$1";
+ shift;
+ case "${_arg}" in
+ auto|default|"") # default
+ _mode="";
+ ;;
+ X|tty) # processed output
+ _mode="${_arg}";
+ ;;
+ Q|source) # display source code
+ _mode="source";
+ ;;
+ Z|intermediate-output) # generate only intermediate output
+ _mode="intermediate-output";
+ ;;
+ *)
+ error "unknown mode ${_arg}";
+ return "$_ERROR";
+ ;;
+ esac;
+ _OPT_MODE="${_mode}";
+ ;;
+ --no-location) # disable former call to `--location'
+ _OPT_LOCATION='yes';
+ ;;
+ --no-man) # disable search for man pages
+ # the same as --local-file
+ _MAN_FORCE="no";
+ _MAN_ENABLE="no";
+ ;;
+ --pager) # set paging program for tty mode, arg
+ _OPT_PAGER="$1";
+ shift;
+ ;;
+ --PX) # pass option to gxditview, arg;
+ _arg="$1";
+ shift;
+ _ADDOPTS_X="${_ADDOPTS_X} -P '${_arg}'";
+ ;;
+ --sections) # specify sections for man pages, arg
+ # arg is colon-separated list of section names
+ _OPT_SECTIONS="$1";
+ shift;
+ ;;
+ --systems) # man pages for different OS's, arg
+ # argument is a comma-separated list
+ _OPT_SYSTEMS="$1";
+ shift;
+ ;;
+ --title) # title for X, arg; OBSOLETE by -P
+ _arg="$1";
+ _ADDOPTS_X="${_ADDOPTS_X} -P -title -P '${_arg}'";
+ shift;
+ ;;
+ --tty)
+ _OPT_MODE="tty";
+ ;;
+ --whatis)
+ _OPT_WHATIS='yes';
+ ;;
+ --xrm) # pass X resource string, arg;
+ _arg="$1";
+ shift;
+ _ADDOPTS_X="${_ADDOPTS_X} -P -xrm -P '${_arg}'";
+ ;;
+ *)
+ error "error on argument parsing : \`$*'";
+ return "$_ERROR";
+ ;;
+ esac;
+ done;
+ shift; # remove `--' argument
+ # Remaining arguments are file names (filespecs).
+
+ # Save filespecs to $_FILEARGS; must be retrieved with
+ # `eval set -- $_FILEARGS'
+ if test "$#" -eq 0; then # use "-" for standard input
+ _FILEARGS="'-'";
+ save_stdin;
+ else
+ if is_yes "$_OPT_APROPOS"; then
+ apropos "$@";
+ _code="$?";
+ clean_up;
+ exit "$_code";
+ fi;
+
+ _FILEARGS="";
+ _stdin_done="no";
+ while test "$#" -gt 0 && is_not_yes "${_stdin_done}"; do
+ if is_equal "$1" '-'; then
+ save_stdin;
+ _stdin_done="yes";
+ fi;
+ _FILEARGS="${_FILEARGS} '$1'";
+ shift;
+ done;
+ fi;
+}
+
+
+########################################################################
+# main_set_mode ()
+#
+# Determine the display mode.
+#
+# Globals:
+# in: $DISPLAY, $_OPT_MODE, $_OPT_DEVICE
+# out: $_DISPLAY_MODE
+#
+main_set_mode()
+{
+ case "${_OPT_MODE}" in
+ source|intermediate-output)
+ _DISPLAY_MODE="${_OPT_MODE}";
;;
- -Q|--source) # output source code (`Quellcode').
- OPT_SOURCE="yes";
+ X)
+ if is_empty "${DISPLAY}"; then
+ error "you must be in X Window for this mode.";
+ return "$_ERROR";
+ fi;
+ _DISPLAY_MODE="X";
;;
- -T|--device) # device, non-X* go to stdout, arg
- _arg="$(get_next_quoted $*)";
- set -- $(shift_quoted $*);
- case "$_arg" in
- X75)
- OPT_DEVICE="";
- OPT_DPI=75;
+ tty)
+ case "${_OPT_DEVICE}" in
+ "")
+ _DISPLAY_MODE="tty";
;;
- X100)
- OPT_DEVICE="";
- OPT_DPI=100;
+ X*)
+ error "cannot display X device in a text terminal."
+ return "$_ERROR";
;;
*)
- OPT_DEVICE="$_arg";
- OPT_DPI="";
+ _DISPLAY_MODE="device";
;;
esac;
;;
- -v|--version)
- version;
- leave;
- ;;
- --dpi) # set resolution for X devices, arg
- _arg="$(get_next_quoted $*)";
- set -- $(shift_quoted $*);
- case "$_arg" in
- 75|75dpi)
- OPT_DEVICE="";
- OPT_DPI=75;
+ "")
+ case "${_OPT_DEVICE}" in
+ "")
+ if is_empty "${DISPLAY}"; then
+ _DISPLAY_MODE="tty";
+ else
+ _DISPLAY_MODE="X";
+ fi;
;;
- 100|100dpi)
- OPT_DEVICE="";
- OPT_DPI=100;
+ X*)
+ if is_empty "${DISPLAY}"; then
+ error "cannot display X device in a text terminal."
+ return "$_ERROR";
+ else
+ _DISPLAY_MODE="X";
+ fi;
;;
*)
- error "only resoutions of 75 or 100 dpi are supported";
+ _DISPLAY_MODE="device";
;;
esac;
;;
- --man) # interpret all file params as man-pages
- OPT_MAN="yes";
- if [ "$ENABLE_MANPAGES" != "yes" ] ; then
- error "empty path for man-pages.";
+ esac;
+}
+
+########################################################################
+# main_parse_MANOPT ()
+#
+# Parse $MANOPT.
+#
+# Globals:
+# in: $MANOPT, $_OPTS_MAN_*
+# out: $_MANOPT_*
+# in/out: $_MAN_ENABLE
+#
+main_parse_MANOPT()
+{
+ local _arg;
+ local _opt;
+ if is_not_yes "${_MAN_ENABLE}"; then
+ return "$_GOOD";
+ fi;
+ eval set -- "$(normalize_args "${_OPTS_MAN_SHORT}" \
+ "${_OPTS_MAN_LONG}" "${MANOPT}")";
+ until test "$#" -le 0 || is_equal "$1" '--'; do
+ _opt="$1";
+ shift;
+ case "${_opt}" in
+ -a|--all)
+ _OPT_ALL="yes";
+ ;;
+ -D|--default)
+ # undo all man configuration so far (env vars and options)
+ : TODO;
+ ;;
+ -e|--extension)
+ _arg="$1";
+ shift;
+ _MANOPT_EXTENSION="${_arg}";
+ ;;
+ -l|--local-file)
+ _MAN_ENABLE="no";
+ break;
+ ;;
+ -L|--locale)
+ _arg="$1";
+ shift;
+ _MANOPT_LANG="${_arg}";
+ ;;
+ -m|--systems)
+ _arg="$1";
+ shift;
+ _MANOPT_SYS="${_arg}";
+ ;;
+ -M|--manpath)
+ _arg="$1";
+ shift;
+ _MANOPT_PATH="${_arg}";
+ ;;
+ -P|--pager)
+ _arg="$1";
+ shift;
+ _MANOPT_PAGER="${_arg}";
+ ;;
+ -S|--sections)
+ _arg="$1";
+ shift;
+ _MANOPT_SEC="${_arg}";
+ ;;
+ -w|--where|--location)
+ _OPT_LOCATION='yes';
+ ;;
+ # ignore all other options
+ esac
+ done
+}
+
+
+#######################################################################
+# main_do_fileargs ()
+#
+# Process filespec arguments in $_FILEARGS.
+#
+# Globals:
+# in: $_FILEARGS
+#
+main_do_fileargs()
+{
+ local _filespec;
+ local _name;
+ local _ok;
+ local _sec;
+ eval set -- ${_FILEARGS};
+ unset _FILEARGS;
+ # temporary storage of all input to $_TMP_CAT
+ while test "$#" -gt 0; do
+ _filespec="$1";
+ shift;
+
+ # test for `s name' arguments, with `s' a 1-char standard section
+ while true; do # just to allow `break'
+ _sec="$_filespec";
+ if ! string_contains "$_MAN_AUTO_SEC" "$_sec"; then
+ break;
fi;
- ;;
- --manpath) # specify search path for man-pages, arg
- OPT_MANPATH="$(get_next_quoted $*)";
- set -- $(shift_quoted $*);
- if [ "$OPT_MANPATH" = "" ]; then
- ENABLE_MANPAGES="no";
- if [ "$OPT_MAN" = "yes" ] ; then
- error "empty path for man-pages.";
- fi;
+ case "$_sec" in
+ [^\ ]) do_nothing; ;; # non-space character
+ *) break; ;;
+ esac;
+ if test "$#" -le 0; then
+ break;
+ fi;
+ _name="$1";
+ case "$_name" in
+ */*|man:*|*\(*\)|*."$_sec") break; ;;
+ esac;
+ if do_filearg "man:${_name}(${_sec})"; then
+ shift;
+ _filespec="$1";
+ continue;
else
- ENABLE_MANPAGES="yes";
+ break;
fi;
- HAS_MANW="";
+ done; # end of `s name' test
+
+ do_filearg "$_filespec";
+ if test "$?" != "$_GOOD"; then
+ echo2 "\`${1}' is neither a file nor a man-page.";
+ fi;
+ done;
+}
+
+########################################################################
+# main_display ()
+#
+# Do the actual display of the whole thing.
+#
+# Globals:
+# in: $_DISPLAY_MODE, $_OPT_DEVICE,
+# $_ADDOPTS_GROFF, $_ADDOPTS_POST, $_ADDOPTS_X,
+# $_REGISTERED_TITLE, $_TMP_PREFIX, $_TMP_CAT,
+# $_OPT_PAGER $PAGER $_MANOPT_PAGER
+#
+main_display()
+{
+ local _addopts;
+ local _options;
+ local _groggy;
+ local _title;
+ local _old_tmp;
+ local _p;
+ local _pager;
+ export _addopts;
+ export _groggy;
+ case "${_DISPLAY_MODE}" in
+ source)
+ tmp_cat;
+ clean_up;
;;
- --no-man) # interpret all file params as man-pages
- OPT_MAN="no";
- ENABLE_MANPAGES="no";
+ intermediate-output)
+ _options="-Z";
+ if is_not_empty "${_OPT_DEVICE}"; then
+ _options="$_options -T'${_OPT_DEVICE}'";
+ fi;
+ _groggy="$(tmp_cat | eval grog "${_options}")";
+ tmpcat | eval "${_groggy}" "${_ADDOPTS_GROFF}";
+ clean_up;
;;
- --title)
- OPT_TITLE="$(get_next_quoted $*)";
- set -- $(shift_quoted $*);
+ device)
+ _groggy="$(tmp_cat | grog -T"${_OPT_DEVICE}")";
+ tmp_cat | eval "${_groggy}" "${_ADDOPTS_GROFF}";
+ clean_up;
;;
- --tty)
- OPT_TTY="yes";
+ X)
+ _addopts="${_ADDOPTS_GROFF} ${_ADDOPTS_POST} ${_ADDOPTS_X}";
+ if is_not_empty "${_REGISTERED_TITLE}"; then
+ _title="${_REGISTERED_TITLE}";
+ _addopts="-P -title -P '${_title}' $_addopts";
+ fi;
+ if ! is_empty "${_OPT_DEVICE}"; then
+ _addopts="-T '${_OPT_DEVICE}' ${_addopts}";
+ fi;
+ clean_up_secondary;
+ _groggy="$(tmp_cat | grog -X)";
+ trap "" EXIT 2>/dev/null || true;
+ # start a new shell program to get another process ID.
+ sh -c '
+ set -e;
+ _PROCESS_ID="$$";
+ _old_tmp="${_TMP_CAT}";
+ _TMP_CAT="${_TMP_PREFIX}${_PROCESS_ID}";
+ rm -f "${_TMP_CAT}";
+ mv "$_old_tmp" "${_TMP_CAT}";
+ cat "${_TMP_CAT}" | \
+ (
+ clean_up()
+ {
+ rm -f "${_TMP_CAT}";
+ }
+ trap clean_up EXIT 2>/dev/null || true;
+ eval "${_groggy}" "${_addopts}";
+ ) &'
;;
- --xrdb) # add X resource for gxditview, arg
- _arg="$(get_next_quoted $*)";
- set -- $(shift_quoted $*);
- OPT_XRDB="$(append_args "$OPT_XRDB" "$_arg")";
+ tty)
+ _addopts="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}";
+ _groggy="$(tmp_cat | grog -Tlatin1)";
+ _pager="";
+ for _p in "${_OPT_PAGER}" "${PAGER}" "less" "${_MANOPT_PAGER}"; do
+ if is_prog "${_p}"; then
+ _pager="${_p}";
+ break;
+ fi;
+ done;
+ tmp_cat | eval "${_groggy}" "${_addopts}" | \
+ eval "${_pager}";
+ clean_up;
;;
- -?)
- _opt_char="$(output $_opt | sed -e '\|-.|s|-||')";
- if is_substring_of "$_opt_char" "${GROFF_SHORTOPTS}"; then
- OTHER_OPTIONS="$(append_args "$OTHER_OPTIONS" "$_opt")";
- elif is_substring_of "$_opt_char" "${GROFF_ARG_SHORTS}"; then
- _arg="$(get_next_quoted $*)";
- OTHER_OPTIONS="$(\
- append_args $OTHER_OPTIONS "${_opt}${_arg}")";
- set -- $(shift_quoted $*);
- else
- error 1 "Unknown option : $1";
- fi;
+ *)
+ clean_up;
;;
- *) error 1 "main : error on argument parsing : $*"; ;;
esac;
-done;
-shift; # remove `--' argument
-
-unset _arg
-unset _opt
-
-# Remaining arguments are file names, each enclosed in single quotes.
-# Function supercat expects such arguments.
-
-if [ "$#" -eq 0 ]; then # use "-" for standard input
- set -- "'-'";
-fi;
-FILE_ARGS="$*"; # all file parameters; do not change
+}
########################################################################
-# setup for display mode (main)
+# main (<command_line_args>*)
#
-DISPLAY_MODE="";
-if [ "$OPT_SOURCE" = "yes" ]; then
- DISPLAY_MODE="source"; # output source code
-elif [ "$OPT_DEVICE" != "" ]; then
- DISPLAY_MODE="device"; # non-X device, cat to stdout
-elif [ "$DISPLAY" != "" -a "$OPT_TTY" != "yes" ]; then
- DISPLAY_MODE="X"; # X
-else
- DISPLAY_MODE="tty"; # tty
-fi;
-
-
-########################################################################
-# setup for man-pages (main)
+# The main function for groffer.
#
-if [ "$ENABLE_MANPAGES" = "yes" ]; then
- MAN_PATH="$(get_manpath)";
- if [ "$MAN_PATH" = "" ]; then
- ENABLE_MANPAGES="no";
- fi;
-fi;
-
-
-#######################################################################
-# temporary files (main)
+# Arguments:
#
+main()
+{
+ # Do not change the sequence of the following functions!
+ main_init;
+ main_parse_args "$@";
+ main_set_mode;
+ main_parse_MANOPT;
+ main_do_fileargs;
+ main_display;
+}
-trap clean_up 2>/dev/null || true;
-
-# save standard input
-TMP_INPUT="$(tmp_create i)";
-save_stdin_if_any;
-
-# built up title consisting of processed filespecs
-if [ "$DISPLAY_MODE" = "X" ]; then
- TMP_TITLE="$(tmp_create t)";
- output "$PROGRAM_NAME :" > $TMP_TITLE;
-
- register_title()
- {
- set -- $(base_name "$*"); # remove directory part
- set -- $(del_ext_from .gz "$*"); # remove .hz
- set -- $(del_ext_from .Z "$*"); # remove .Z
- case "$#" in
- 0) return; ;;
- 1) _res="$1"; ;;
- *) _res="'$*'"; ;;
- esac;
- output " $_res" >> "$TMP_TITLE";
- }
-
-else
-
- register_title()
- {
- true; # dummy
- }
-
-fi;
-
-# temporary storage of all input
-TMP_CAT="$(tmp_create)";
-supercat $FILE_ARGS >"$TMP_CAT"; # this does the main work
-
-if [ "$TMP_INPUT" != "" ]; then
- rm -f "$TMP_INPUT";
-fi;
-
-
-########################################################################
-# display (main)
-#
-case "$DISPLAY_MODE" in
- source)
- tmp_cat;
- clean_up;
- ;;
- device)
- _groggy="$(tmp_cat | grog $OTHER_OPTIONS -T"${OPT_DEVICE}")";
- tmp_cat | eval $_groggy;
- clean_up;
- ;;
- X)
- _title="$(make_title)";
- if [ "$OPT_DPI" = "" ]; then
- OPT_DPI="$(check_dpi)"; # sanity check for using 100 dpi default
- fi;
- _groggy="$(tmp_cat | grog $OTHER_OPTIONS -TX"${OPT_DPI}" -Z )";
- trap "" EXIT 2>/dev/null || true;
- # start a new shell program to get another process ID.
- sh -c '
- clean_up()
- {
- if [ "$TMP_CAT" != "" ]; then
- rm -f "$TMP_CAT";
- fi;
- }
- PROCESS_ID="$$";
- _old_tmp="$TMP_CAT";
- TMP_CAT="${TEMP_PREFIX}${PROCESS_ID}";
- rm -f "$TMP_CAT";
- mv "$_old_tmp" "$TMP_CAT";
- cat "$TMP_CAT" | eval $_groggy | \
- (
- trap clean_up EXIT 2>/dev/null || true;
- gxditview $OPT_XRDB -title "$_title" -;
- rm -f ;
- ) &'
- ;;
- tty)
- _groggy="$(tmp_cat | grog $OTHER_OPTIONS -Tlatin1)";
- if [ "$PAGER" = "" ]; then
- _pager=less;
- else
- _pager=$PAGER;
- fi;
- tmp_cat | eval $_groggy | $_pager;
- clean_up;
- ;;
- *)
- clean_up;
- ;;
-esac;
+main "$@";