From 1c503eed9fd35658fbd7077d5ea3b5553e61103c Mon Sep 17 00:00:00 2001 From: Werner LEMBERG Date: Mon, 24 Jun 2002 18:08:06 +0000 Subject: [PATCH] * release of groffer 0.8 * Makefile.sub: add copyright section * groffer.man: - Document the new options. - Revise the documentation of the modes. - Document the configuration files in new section `FILES'. - Redesign section `EXAMPLES'. - Remove documentation for `-W'. * groffer.sh: new debugging features - Disabled by default; enabled by environment variables. - Add landmark() to catch typos with quotes. - Add a function call stack for suitable functions; implemented as within the argument checker func_check(). - This implies the need to provide `return' with some clean-up facility; implemented as `eval "$_return_..."'. - Add option `--debug' to enable debugging at run-time. - Actually, the groffer script uses only shell builtins found in `ash' (a subset of POSIX) and POSIX `sed' as the only external shell utility. * groffer.sh: customization of viewers - In `groff' mode, the groffer viewing facilities are disabled. - The postprocessor option `-P' costumizes the viewer only in some situations in the `groff' mode, so a new infrastructure for viewer customization is necessary. - Allow to specify arguments to the viewer programs specified in `--*-viewer()'. - Implement some of the essential X Toolkit resource options in groffer, but with use a leading double minus. -> `--bd': set border color. -> `--bg', `--background': set background color. -> `--bw': set border width. -> `--display': set X display. -> `--geometry': set size and position of viewer window. -> `--fg', `--foreground': set foreground color. -> `--ft', `--font': set font. -> `--resolution': set X resolution in dpi. -> `--title': set viewer window title. -> `--xrm': set X resource. - Remove misnamed option `--xrdb'. * groffer.sh: new mode structure - New Postcript mode `ps' (`--ps'): -> default viewers: gv,ghostview,gs_x11,gs; -> `--ps-viewer' sets the Postscript viewer. - New mode `www' (`--www') for displaying in a web browser: -> default browsers: mozilla,netscape,opera,amaya,arena; -> `--www-viewer' sets the web browser. - New dvi mode (`--dvi'); default viewer `xdvi': -> default viewers: xdvi,dvilx; -> `--dvi-viewer' sets the dvi viewer. - New mode `auto': -> active if no other mode is given or by new option `--auto'; -> selects from a sequence of modes that are tested until one of them succeeds. -> the default mode sequence is actually `ps', `x', `tty'. -> `--default-modes' sets this mode sequence as a comma separated string of program names, optionally each one with arguments). - New mode `groff': -> process input like groff, ignore viewing options. -> activated by new option `--groff'. -> automatically active with one of `-V', `-X', `-Z'. - Revise `tty' mode: -> allow several text devices. -> - Reorganize the mode management: -> new mode setting option `--mode'. -> logically separate source, groff, and display modes. -> intermediate output mode is now part of mode groff; remove any special features around `-Z'. - Update usage() to reflect the new option structure. * groffer.sh: add configuration files - `/etc/groff/groffer.conf' system-wide configuration. - `${HOME}/.groff/groffer.conf' user configuration. - The configuration file are shell scripts for now; later implementations can identify this from the `#! /bin/sh' line. * groffer.sh: new data structure `list': - Implement a `list' data structure as a string consisting of single-quoted elements, separated by a space character; embedded single-quotes are escaped. * groffer.sh: new option parser based on `list': - Write new option parser based on `list', compatible to both POSIX getopts() and GNU getopt(). - Long options are now available on GNU and non-GNU systems. - Get rid of POSIX getopts() and GNU getopt(). - the `-W--longopt' construct is now obsolete; remove it. - add test/function for `unset'. - Option strings are now implemented as `list's in order to allow unusual characters in options. - Parse $MANOPT first; translate essential arguments into groffer options. * groffer.man: - determine prompt length for `.Shell_cmd'* dynamically. - naming scheme for static strings and registers changed to `namespace:macro.variable'. * groffer.sh: Implement man option `--ascii' by `-mtty-char'. --- contrib/groffer/ChangeLog | 123 +- contrib/groffer/{TODO => Makefile.sub} | 41 +- contrib/groffer/TODO | 27 +- contrib/groffer/groffer.man | 1544 +++++++++----- contrib/groffer/groffer.sh | 3467 +++++++++++++++++++++----------- 5 files changed, 3405 insertions(+), 1797 deletions(-) copy contrib/groffer/{TODO => Makefile.sub} (51%) diff --git a/contrib/groffer/ChangeLog b/contrib/groffer/ChangeLog index 3a3a8cf8..2b8a3b71 100644 --- a/contrib/groffer/ChangeLog +++ b/contrib/groffer/ChangeLog @@ -1,13 +1,127 @@ +2002-06-23 Bernd Warken + ________________________________________________________________ + * release of groffer 0.8 + + * Makefile.sub: add copyright section + + * groffer.man: + - Document the new options. + - Revise the documentation of the modes. + - Document the configuration files in new section `FILES'. + - Redesign section `EXAMPLES'. + - Remove documentation for `-W'. + + * groffer.sh: new debugging features + - Disabled by default; enabled by environment variables. + - Add landmark() to catch typos with quotes. + - Add a function call stack for suitable functions; implemented + as within the argument checker func_check(). + - This implies the need to provide `return' with some clean-up + facility; implemented as `eval "$_return_..."'. + - Add option `--debug' to enable debugging at run-time. + - Actually, the groffer script uses only shell builtins found + in `ash' (a subset of POSIX) and POSIX `sed' as the only + external shell utility. + + * groffer.sh: customization of viewers + - In `groff' mode, the groffer viewing facilities are disabled. + - The postprocessor option `-P' costumizes the viewer only in + some situations in the `groff' mode, so a new infrastructure + for viewer customization is necessary. + - Allow to specify arguments to the viewer programs specified + in `--*-viewer()'. + - Implement some of the essential X Toolkit resource options in + groffer, but with use a leading double minus. + -> `--bd': set border color. + -> `--bg', `--background': set background color. + -> `--bw': set border width. + -> `--display': set X display. + -> `--geometry': set size and position of viewer window. + -> `--fg', `--foreground': set foreground color. + -> `--ft', `--font': set font. + -> `--resolution': set X resolution in dpi. + -> `--title': set viewer window title. + -> `--xrm': set X resource. + - Remove misnamed option `--xrdb'. + + * groffer.sh: new mode structure + - New Postcript mode `ps' (`--ps'): + -> default viewers: gv,ghostview,gs_x11,gs; + -> `--ps-viewer' sets the Postscript viewer. + - New mode `www' (`--www') for displaying in a web browser: + -> default browsers: mozilla,netscape,opera,amaya,arena; + -> `--www-viewer' sets the web browser. + - New dvi mode (`--dvi'); default viewer `xdvi': + -> default viewers: xdvi,dvilx; + -> `--dvi-viewer' sets the dvi viewer. + - New mode `auto': + -> active if no other mode is given or by new option `--auto'; + -> selects from a sequence of modes that are tested until one + of them succeeds. + -> the default mode sequence is actually `ps', `x', `tty'. + -> `--default-modes' sets this mode sequence as a comma + separated string of program names, optionally each one + with arguments). + - New mode `groff': + -> process input like groff, ignore viewing options. + -> activated by new option `--groff'. + -> automatically active with one of `-V', `-X', `-Z'. + - Revise `tty' mode: + -> allow several text devices. + -> + - Reorganize the mode management: + -> new mode setting option `--mode'. + -> logically separate source, groff, and display modes. + -> intermediate output mode is now part of mode groff; remove + any special features around `-Z'. + - Update usage() to reflect the new option structure. + + * groffer.sh: add configuration files + - `/etc/groff/groffer.conf' system-wide configuration. + - `${HOME}/.groff/groffer.conf' user configuration. + - The configuration file are shell scripts for now; later + implementations can identify this from the `#! /bin/sh' line. + + * groffer.sh: new data structure `list': + - Implement a `list' data structure as a string consisting of + single-quoted elements, separated by a space character; + embedded single-quotes are escaped. + + * groffer.sh: new option parser based on `list': + - Write new option parser based on `list', compatible to both + POSIX getopts() and GNU getopt(). + - Long options are now available on GNU and non-GNU systems. + - Get rid of POSIX getopts() and GNU getopt(). + - the `-W--longopt' construct is now obsolete; remove it. + - add test/function for `unset'. + - Option strings are now implemented as `list's in order to + allow unusual characters in options. + - Parse $MANOPT first; translate essential arguments into + groffer options. + + * groffer.man: + - determine prompt length for `.Shell_cmd'* dynamically. + - naming scheme for static strings and registers changed to + `namespace:macro.variable'. + + +2002-06-16 Werner Lemberg + + * groffer.sh: + Implement man option `--ascii' by `-mtty-char'. + + 2002-05-31 Werner LEMBERG - * groffer.man (@.Shell_cmd_width): Increase to 4m (we use `sh#' as - the prompt). + * groffer.man (@.Shell_cmd_width): + Increase to 4m (we use `sh#' as the prompt). + 2002-05-31 Bernd Warken ________________________________________________________________ * release of groffer 0.7 - * groffer.sh: remove incompatibility with the `ash' shell: + * groffer.sh: remove incompatibilities with the `ash' shell: - do not use `!command': -> use `else' -> write `_not_' equivalents for some functions @@ -24,12 +138,13 @@ - trouble with exporting external `$GROFF_*' variables: -> hope that they were exported in the calling shell. - not smart about additional blanks: - -> remove unnecessary withe space. + -> remove unnecessary white space. * groffer.sh: improve run-time speed: - `ash' more than doubles the speed of `bash'. - speed-up `man_setup()'. + 2002-05-30 Werner Lemberg * groffer.man: diff --git a/contrib/groffer/TODO b/contrib/groffer/Makefile.sub similarity index 51% copy from contrib/groffer/TODO copy to contrib/groffer/Makefile.sub index 666384fd..4be6846f 100644 --- a/contrib/groffer/TODO +++ b/contrib/groffer/Makefile.sub @@ -1,11 +1,11 @@ -# TODO file for `groffer' +# Makefile.sub for `groffer' (integration into the groff source tree) -# File position: /contrib/groffer/TODO +# File position: /contrib/groffer/Makefile.sub -# Last update: 31 May 2002 +# Last update: 23 June 2002 # Copyright (C) 2001,2002 Free Software Foundation, Inc. -# Written by Bernd Warken +# Written by Werner Lemberg # This file is part of groff. @@ -26,25 +26,22 @@ ######################################################################## -TODO +MAN1=groffer.n +CLEANADD=groffer -Optimization: -- Optimize for speed (`case' instead of `sed' interface?). +all: groffer -Features: -- For each postprocessor, register its options for checking against -P. - Maybe this should rather be done within groff. -- Support bzip. +groffer: groffer.sh + rm -f $@; \ + sed -e "s|@g@|$(g)|g" \ + -e "s|@VERSION@|$(version)$(revision)|" \ + -e $(SH_SCRIPT_SED_CMD) $(srcdir)/groffer.sh >$@; \ + chmod +x $@ -Revision: -- Should there be a native implementation for `--apropos'? -- Revise the `--all' feature to better reflect GNU man. +install_data: groffer + -test -d $(bindir) || $(mkinstalldirs) $(bindir) + -rm -f $(bindir)/groffer + $(INSTALL_SCRIPT) groffer $(bindir)/groffer -Documentation: -- Write a README file. -- Document the search algorithm for man pages in both the `groffer.sh' -script and the man page `groffer.man'. -- In `groff.man', add more documentation for parts that were taken over -from GNU `man'. -- Some documentations for function definitions in `groffer' need an -update. +uninstall_sub: + -rm -f $(bindir)/groffer diff --git a/contrib/groffer/TODO b/contrib/groffer/TODO index 666384fd..a4475809 100644 --- a/contrib/groffer/TODO +++ b/contrib/groffer/TODO @@ -2,7 +2,7 @@ # File position: /contrib/groffer/TODO -# Last update: 31 May 2002 +# Last update: 23 June 2002 # Copyright (C) 2001,2002 Free Software Foundation, Inc. # Written by Bernd Warken @@ -29,22 +29,29 @@ TODO Optimization: -- Optimize for speed (`case' instead of `sed' interface?). +- Optimize man path determination in manpath_add_lang_sys() for speed + by building-up the man path only by and by as far as necessary + (not trivial). Features: -- For each postprocessor, register its options for checking against -P. - Maybe this should rather be done within groff. -- Support bzip. +- Support for bzip. +- Consider using `shopt' (OOP for `sh'). +- Revise option handling of `grog'. +- `gxditview' needs a complete shower. Revision: - Should there be a native implementation for `--apropos'? - Revise the `--all' feature to better reflect GNU man. +- string_sed_s() has trouble with arguments that have embedded quotes, + but it is good enough for the script so far. +- Consider to replace string_sed_s() and friends in favor of native sed + commands or to write suitable C++ utils. Documentation: - Write a README file. -- Document the search algorithm for man pages in both the `groffer.sh' -script and the man page `groffer.man'. +- Improve the documentation of the search algorithm for man pages in + both the groffer script and the man page `groffer.man'. - In `groff.man', add more documentation for parts that were taken over -from GNU `man'. -- Some documentations for function definitions in `groffer' need an -update. + from GNU `man'. +- The documentation in the headers for some function definitions in + `groffer.sh' needs to be updated. diff --git a/contrib/groffer/groffer.man b/contrib/groffer/groffer.man index cf8370a4..09e1cb9b 100644 --- a/contrib/groffer/groffer.man +++ b/contrib/groffer/groffer.man @@ -2,16 +2,20 @@ .SH NAME groffer \- display groff files and man\~pages on X and tty . +.SH "SYNOPSIS" +.\" The .SH was moved to this place in order to appease `apropos'. . .\" -------------------------------------------------------------------- .\" Legalize .\" -------------------------------------------------------------------- . .ig -groffer.man - man page for groffer (section 1). +groffer.1 - man page for groffer (section 1). + +File position: /contrib/groffer/groffer.man -Version : groffer 0.7 -Last update : 31 May 2002 +Version : groffer 0.8 +Last update : 23 June 2002 This file is part of groff, the GNU roff type-setting system. @@ -54,27 +58,88 @@ FDL in the main directory of the groff source package. .ds @i- "\f[CI]-\f[]\"" .ds @i-- "\f[CI]--\f[]\"" . -.ds Ellpisis .\|.\|.\" +.ds Ellipsis .\|.\|.\" . -./" static registers (@+...) used for inter-macro communication" -.nr @.Shell_cmd_width 4m\" total width of prompt +.\" -------------------------------------------------------------------- +.\" setup for the macro definitions below +.\" +.\" naming: namespace:cathegory_macro.variable_name (experimental) . -.nr @+Synopsis_level 0 +.\" -------------------------------------------------------------------- +.\" configuration of prompt for `.Shell_cmd'* macros +.ds groffer:Shell_cmd.prompt_text sh#\" prompt for shell commands +.ds groffer:Shell_cmd+.prompt_text >\" prompt on continuation lines +.ds groffer:Shell_cmd_base.prompt_font I\" font for prompts +. +.\" automatically determine setup from the configuration above +.als @f groffer:Shell_cmd_base.prompt_font\" +.als @t groffer:Shell_cmd.prompt_text\" +.als @t+ groffer:Shell_cmd+.prompt_text\" +.ds groffer:Shell_cmd.prompt \f[\*[@f]]\*[@t]\f[]\" needed +.ds groffer:Shell_cmd+.prompt \f[\*[@f]]\*[@t+]\f[]\" needed +.nr @w \w'\*[groffer:Shell_cmd.prompt]'\" +.nr @w+ \w'\*[groffer:Shell_cmd+.prompt]'\" +.ft \*[@f] +.\" Full prompt width is maximum of texts plus 1m +.nr groffer:Shell_cmd_base.prompt_width (\n[@w]>?\n[@w+]+1m)\" needed +.ft +.rm @f +.rm @f+ +.rm @t +.rm @t+ +.rr @w +.rr @w+ . -.nr @+TP_level 0 -.rr @+TP_header -.rr @+TP_body -.rr @+TP_indent +.\" -------------------------------------------------------------------- +.\" static register for inter-macro communication in `.Synopsis'* +.nr groffer:Synopsis.level 0 +. +.\" -------------------------------------------------------------------- +.\" static registers for inter-macro communication in `.TP'* +.nr groffer:TP.level 0 +.rr groffer:TP_header.flag +.rr groffer:TP_body.flag +.rr groffer:TP.indent . . .\" -------------------------------------------------------------------- -.\" Start macro definitions +.\" Macro definitions . .\" Ignore all arguments like a comment, even after a .eo call. .c .de c .. .c -------------------------------------------------------------------- +.c .CB (...) +.c +.c Print in constant-width bold font. +.c +.de CB +. ft CB +. Text \\$* +. ft +.. +.c -------------------------------------------------------------------- +.c .CI (...) +.c +.c Print in constant-width italic font. +.c +.de CI +. ft CI +. Text \\$* +. ft +.. +.c -------------------------------------------------------------------- +.c .CR (...) +.c +.c Print in constant-width roman font. +.c +.de CR +. ft CR +. Text \\$* +. ft +.. +.c -------------------------------------------------------------------- .c .Error (...) .c .c Print error message to terminal and abort. @@ -360,7 +425,7 @@ FDL in the main directory of the groff source package. .c result: the same as the previous example .c .de Shell_cmd -. Shell_cmd_base "sh#" \\$@ +. groffer:Shell_cmd_base "\*[groffer:Shell_cmd.prompt]" \\$@ .. .c -------------------------------------------------------------------- .c .Shell_cmd+ ( [] ...) @@ -368,23 +433,24 @@ FDL in the main directory of the groff source package. .c A continuation line for .Shell_cmd. .c .de Shell_cmd+ -. Shell_cmd_base ">" \\$@ +. groffer:Shell_cmd_base "\*[groffer:Shell_cmd+.prompt]" \\$@ .. .c -------------------------------------------------------------------- .c .Shell_cmd_base ( [ [] ...]) .c .c A shell command line; display args alternating in fonts CR and CI. +.c Internal, do not use directly. .c .c Globals: read-only register @.Shell_cmd_width .c -.de Shell_cmd_base +.de groffer:Shell_cmd_base . if (\\n[.$] <= 0) \ . return . nr @+font \\n[.f]\" -. ds @prompt \f[I]\\$1\" +. ds @prompt \\$1\" . ft CR -. nr @+gap \\n[@.Shell_cmd_width]\" -. nr @+gap -\\w'\\*[@prompt]'\" gap between prompt and command +. c gap between prompt and command +. nr @+gap \\n[groffer:Shell_cmd_base.prompt_width]-\\w'\\*[@prompt]'\" . ds @res \\*[@prompt]\h'\\n[@+gap]u'\" . shift . ds @cf CR\" @@ -412,28 +478,12 @@ FDL in the main directory of the groff source package. . rm @res .. .c -------------------------------------------------------------------- -.c .Opt_short ([ []]) -.c -.c Print `-name' somewhere in the Text; optional punctuation. -.c -.de Opt_short -. Opt_alt - "\\$1" "" "\\$2" -.. -.c -------------------------------------------------------------------- -.c .Opt_[short] ([name [punct]]) -.c -.c Print `[-name]' somewhere in the Text; optional punctuation. -.c -.de Opt_[short] -. 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) \ +. if (\\n[groffer:Synopsis.level] > 0) \ . Error .\\$0: previous .Synopsis was not closed by ./Synopsis. . nh . ds @1 \\$1\" @@ -444,7 +494,7 @@ FDL in the main directory of the groff source package. . B \\*[@1]\0\c . rr @old_indent . rm @1 -. nr @+Synopsis_level +1\" marker for ./Synopsis +. nr groffer:Synopsis.level +1\" marker for ./Synopsis .. .c -------------------------------------------------------------------- .c ./Synopsis () @@ -452,13 +502,13 @@ FDL in the main directory of the groff source package. .c Close a synopsis section opened by the previous .Synopsis macro. .c .de /Synopsis -. if (\\n[@+Synopsis_level] <= 0) \ +. if (\\n[groffer:Synopsis.level] <= 0) \ . Error .\\$0: no previous call of .Synopsis . br . ad . in . hy -. nr @+Synopsis_level -1 +. nr groffer:Synopsis.level -1 .. .c -------------------------------------------------------------------- .c .Text (...) @@ -500,15 +550,15 @@ FDL in the main directory of the groff source package. .c Start a multi-line header for a .TP-like paragraph .c .de TP_header -. if (\\n[@+TP_level] < 0) \ +. if (\\n[groffer:TP.level] < 0) \ . Error .\\$0: wrong level. -. nr @+TP_level +1 +. nr groffer:TP.level +1 . P . ie (\\n[.$] == 0) \ -. rr @+TP_indent +. rr groffer:TP.indent . el \ -. nr @+TP_indent \\$1 -. nr @+TP_header 1 +. nr groffer:TP.indent \\$1 +. nr groffer:TP_header.flag 1 .. .c -------------------------------------------------------------------- .c .TP_body ([]) @@ -516,23 +566,23 @@ FDL in the main directory of the groff source package. .c End a previous .TP-header and beging the body of the paragraph. .c .de TP_body -. if !r@+TP_header \ +. if !rgroffer:TP_header.flag \ . Error .\\$0: no previous call of .TP_header -. if (\\n[@+TP_level] <= 0) \ +. if (\\n[groffer:TP.level] <= 0) \ . Error .\\$0: wrong level. . br . ie (\\n[.$] == 0) \{\ -. ie r@+TP_indent \{\ -. RS \\n[@+TP_indent]u +. ie rgroffer:TP.indent \{\ +. RS \\n[groffer:TP.indent]u . \} . el \ . RS . \} . el \ . RS \\$1u -. rr @+TP_indent -. rr @+TP_header -. nr @+TP_body 1 +. rr groffer:TP.indent +. rr groffer:TP_header.flag +. nr groffer:TP_body.flag 1 .. .c -------------------------------------------------------------------- .c TP_end () @@ -540,14 +590,14 @@ FDL in the main directory of the groff source package. .c End of former .TP_body paragraph. .c .de TP_end -. if !r@+TP_body \ +. if !rgroffer:TP_body.flag \ . Error .\\$0: no previous .TP_body. -. if (\\n[@+TP_level] <= 0) \ +. if (\\n[groffer:TP.level] <= 0) \ . Error TP_end: wrong level. -. nr @+TP_level -1 -. rr @+TP_indent -. rr @+TP_header -. rr @+TP_body +. nr groffer:TP.level -1 +. rr grogger:TP.indent +. rr groffer:TP_header.flag +. rr groffer:TP_body.flag . br . RE .. @@ -556,12 +606,12 @@ FDL in the main directory of the groff source package. . . .\" -------------------------------------------------------------------- -.SH "SYNOPSIS" +.\" SH "SYNOPSIS" .\" -------------------------------------------------------------------- . .ad l .Synopsis groffer -.RI [ mode_options ] +.RI [ viewing_options ] .RI [ man_options ] .RI [ groff_options ] .Opt_[--] @@ -578,27 +628,98 @@ FDL in the main directory of the groff source package. . . .TP -.I mode_options +.I viewing_options These options determine and configure the display mode. . -They are all compatible with the options in both +They were synchronized with the options of both .BR groff (@MAN1EXT@) and GNU .BR man (1). +As groff uses almost any letter in its option set, only long option +names are available for most features. +. +If none of these options is used groffer tries to find a suitable +display mode automatically. +. . .P .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] - T -- device device +.Opt_[alt] -- debug +.Opt_[alt] -- default +.Opt_[alt] -- default-modes mode1,mode2,\*[Ellipsis] +.Opt_[alt] -- dvi +.Opt_[alt] -- dvi-viewer prog +.Opt_[alt] -- groff +.Opt_[alt] -- location .Opt_[alt] -- mode display_mode .Opt_[alt] -- pager program -.Opt_[alt] -- title string +.Opt_[alt] -- ps +.Opt_[alt] -- ps-viewer prog .Opt_[alt] -- tty +.Opt_[alt] -- www +.Opt_[alt] -- www-viewer prog +.Opt_[alt] -- x +.Opt_[alt] -- x-viewer prog +. +. +.P +The following long options were adapted from the corresponding X +Toolkit options with a single leading minus; see +.BR X (1). +. +. +.P +.RS +.Opt_[alt] -- bd +.Opt_[alt] -- bg -- background +.Opt_[alt] -- bw +.Opt_[alt] -- display +.Opt_[alt] -- fg -- foreground +.Opt_[alt] -- ft -- font +.Opt_[alt] -- geometry size_pos +.Opt_[alt] -- resolution value +.Opt_[alt] -- rv +.Opt_[alt] -- title string +.Opt_[alt] -- xrm X_resource +.RE +. +. +.TP +.I groff_options +Any combination of (short) options from the +.BR groff (@MAN1EXT@) +program is accepted; the options that are not explicitly handled by +groffer are transparently passed to groff. +. +Due to the automatism in groffer, none of these groff options should +be necessary, except for advanced usage. +. +.RS +.P +Because of the special outputting behavior of the groff options +.Opt_short V, +.Opt_short X, +and +.Opt_short Z, +groffer was designed to be switched into +.I groff +mode by each of these options; in this mode, the groffer viewing +features are disabled. +. +.P +The other groff options do not switch the mode, but allow to customize +the formatting process. +. +Useful groff formatting options include +.Opt_short m +(to add macro files that cannot be recognized by grog), and +.Opt_short T +(to specify an alternative device for the modes +.I tty +and +.IR x ). .RE . . @@ -614,46 +735,43 @@ program. .P .RS .Opt_[alt] -- all +.Opt_[alt] -- ascii .Opt_[alt] -- apropos +.Opt_[alt] -- ditroff .Opt_[alt] -- extension suffix -.Opt_[alt] -- lang -- locale language +.Opt_[alt] -- locale language .Opt_[alt] -- local-file -.Opt_[alt] -- location -- where .Opt_[alt] -- man -.Opt_[alt] -- manpath man_page_dirs +.Opt_[alt] -- manpath dir1:dir2:\*[Ellipsis] .Opt_[alt] -- no-location .Opt_[alt] -- no-man -.Opt_[alt] -- sections colon_list -.Opt_[alt] -- systems comma_list +.Opt_[alt] -- sections sec1:sec2:\*[Ellipsis] +.Opt_[alt] -- systems sys1,sys2,\*[Ellipsis] +.Opt_[alt] -- troff-device device .Opt_[alt] -- whatis .RE . +The GNU +.I man +long options that are not mentioned are recognized, but they are just +ignored because of alternative implementations. +. The full set of long and short options of the GNU man program can be passed via the environment variable -.Env_var $MANOPT , +.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 -is a sequence of file names or template parameters for searching +is a sequence of file names or templates for searching man\~pages, see -.BR man (1), -having one of the following forms. +.BR man (1). +A +.I filespec +can have one of the following forms. . . .RS @@ -739,33 +857,35 @@ For details on the options, see section . The .I groffer -program is able to display files written in the -.IR "roff formatting language" ; -see -.BR roff (@MAN7EXT@) -and +program is part of .BR groff (@MAN7EXT@). -When called from within the X window system the input is displayed -using the graphical viewer program +It can be used to display arbitrary documents written in the +.BR roff (@MAN7EXT@) +formatting language in several different ways, in an X window viewer +program of in a text terminal. +. +The viewer programs can be chosen as the groff native viewer .BR gxditview (@MAN1EXT@), -otherwise text output is displayed in a pager on the terminal. +a Postcript or dvi display program, or a web browser. . . .P -A search facility for manual pages (man\~pages) is provided. +A search facility for manual pages ( +.IR 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. +This makes the groffer program a valuable tool on systems with a poor +.I man +system. . . .P The program always concatenates all input specified by the non-option -parameters of the calling command line, or standard input if none are -given. +parameters of the calling command line or standard input. . Compressed standard input or files are decompressed on-the-fly. . @@ -781,225 +901,248 @@ the roff source code is displayed without formatting. . . .P -The +The formatting process can be regulated by all options that are +available groff. +. +By using the .Opt_short T -option allows to produce output for any output devices provided by -groff. +option, groffer can be switched to behave exactly like groff without +using its viewer facilities, but additionally with the search and +decompression features. . -This is like groff, but additionally with the search and decompression -facilities. . .P -Internally, the program uses the +All necessary options can be determined automatically. +. +For example, the groffer program internally uses the .BR grog (@MAN1EXT@) -program to determine from the source which preprocessors should be run -and which macro files should be included. +program to determine from the unformatted document which preprocessors +should be run and which macro files should be included. . -This can be controlled manually by providing suitable options from the -.BR groff (@MAN1EXT@) -program. +But all parts of the program can be controlled manually by suitable +options. . . .\" -------------------------------------------------------------------- .SH OPTIONS .\" -------------------------------------------------------------------- . -If your system does not support GNU long options you can use the -.Opt_short W -to simulate long options. +The groffer program provides its own parser for command line options +that is compatible to both POSIX +.BR getopts (1) +and GNU +.BR getopt (1). +The command line behaves as usually. . -POSIX has reserved this option for such uses. +For completeness, the details are provided here. . . -.P -All -.B groff -options are valid for groffer. +.\" -------------------------------------------------------------------- +.SS "Option Parsing" +.\" -------------------------------------------------------------------- . -The groff options that are transparently transferred to groff are not -documented here. +The following types of options are supported, equally on all systems +that are able to run the groffer program: . -The following options are caught by groffer and have a special -meaning. . +.Topic +single character options are always preceded by a single minus +character, for example, +.Opt_short c . . -.Opt_def - h -Print usage message to standard error and exit. . +.Topic +the argument for a single character option is the next command line +argument, for example, +.Opt_alt - o\~ arg , +or can be appended to the option character within the same argument +.Opt_alt - o arg . . -.Opt_def - Q -Output the roff source code of the input files unprocessed. . +.Topic +clusters of such single character options without an argument, +eventually terminated by a single character option with an argument; +for example, +.Opt_alt - abo arg +is equivalent to +.Opt_short a\~\c +.Opt_short b\~\c +.Opt_short o\~\c +.I arg . . -.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 -.Opt_short P . +.Topic +Long options, that means option with names longer than one character +are always prededed by a double minus; an option argument can either +go to the next command line argument or be appended with an equal sign +to the argument; for example, +.Opt_alt -- long= arg +is equivalent to +.Opt_alt -- long\~ arg . . -If the postprocessor option needs an argument this must be specified -as the argument of another, directly following -.Opt_short P -option. . +.Topic +An argument of +.Opt_-- +ends option parsing; all further command line arguments are +interpreted as filespec arguments. . -.RS . -.Opt_def - P \*[@i-]opt -Pass -.I \*[@i-]opt -unchanged to the actual postprocessor. +.Topic +By default, all command line arguments that are neither options nor +option arguments are interpreted as filespec parameters and stored +until option parsing has finished. . +For example, the command line +.Shell_cmd "groffer file1 -a -o arg file 2" +is, by default, equivalent to +.Shell_cmd "groffer -a -o arg -- file1 file 2" . -.Opt_def - P \*[@i--]opt -Pass -.I \*[@i--]opt -unchanged to the actual postprocessor. . +.Topic +This behavior can be changed by setting the environment variable +.Env_var $POSIXLY_CORRECT +to a non-empty value; in this case, option processing is stopped as +soon as the first non-option argument is found. . -.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 +For example, in POSIXLY_CORRECT mode, the command line +.Shell_cmd "groffer file1 -a -o arg file 2" +is equivalent to +.Shell_cmd "groffer -- file1 -a -o arg file 2" +As this leads to unwanted behavior in most cases, most people do not +want to set +.Env_var $POSIXLY_CORRECT . . . -.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 +.\" -------------------------------------------------------------------- +.SS "Compatibility with Options from other Programs" +.\" -------------------------------------------------------------------- . -.RE +All short options of +.I groffer +are compatible with the short options of +.BR groff (@MAN1EXT@). . +Some of the +.I groff +options were given a special meaning within +.IR groffer . . -See also section -.BR EXAMPLES . +All other +.I groff +options are supported by +.IR groffer , +but they are just transparently transferred to +.I groff +without any intervention. . +Therefore these transparent options are not documented here, but in +.BR groff (@MAN1EXT@). . -.Opt_def - T devname -Use -.I devname -as the output device, just like in plain groff. . -The allowed device names are listed in -.BR groff (@MAN1EXT@). +.P +All long options of +.I groffer +are compatible with the long options of +.BR man (1). . -All device names that do begin with the letter -.I X -force displaying in an X window using gxditview. +Most of the +.I man +long options were implemented as native options into +.IR groffer . . -All other device names generate output for the specified device; this -is printed onto standard output without a pager. +These options are documented in the following; the other +.I man +options are recognized, but ignored. . . -.Opt_def - v -Print version information onto standard error. +.\" -------------------------------------------------------------------- +.SS "Native groffer Options" +.\" -------------------------------------------------------------------- . +.Opt_def - h +Print usage message to standard error and exit. . -.Opt_def - W arg -There are two applications for this option. . -If the argument -.I arg -starts with a -.Opt_-- -(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 -.Opt_short W -to groff (disable a warning), see -.BR troff (@MAN1EXT@). +.Opt_def - Q +Output the roff source code of the input files unprocessed. . +This is the equivalent +.Opt_long mode\~source . . -.RS . -.TP -.Opt_alt - W "\*[@i--]longopt" -is equivalent to the groffer long option -.Opt_long longopt -without an argument. +.Opt_def - T devname +Switch to +.Opt_long mode\~device , . +thus disabling the +.I groffer +viewing. . -.TP_header -.Opt_alt - W "\*[@i--]longopt\f[CR]=\f[]optarg" -.br -.Opt_alt - W "\*[@i--]longopt" -.Opt_alt - W optarg -.TP_body -are both equivalent to the groffer long option -.Opt_long longopt -with the argument -.IR optarg . -.TP_end +Instead, the input is formatted and postprocessed using plain +.I groff +with +.I devname +as the output device. . +The allowed device names are listed in +.BR groff (@MAN1EXT@). . -.TP -.Opt_alt - W warning -is equivalent to the groff/troff option -.Opt_short W -.I warning -(disable the warning named -.IR warning ); -internally, this is sent transparently to groff. -. -More exactly, an argument to -.Opt_short W -that is supposed to represent long options must always be specified -together with a leading -.Opt_-- -(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 -.Opt_short W -option. +Note that this forces all device names that begin with the letter +.I X +to be displayed with +.BR gxditview (@MAN1EXT@); +all other device names generate output for the specified device; this +is printed onto standard output without a pager. . . -.P -An argument to -.Opt_short W -that does not start with a leading -.Opt_-- -(double minus) is interpreted as a groff warning option. +.Opt_def - v +Print version information onto standard error. . -.RE . +.Opt_def - V +Switch into +.I groff +mode and format the input with groff option +.Opt_short V ; +this produces the groff calling pipe without formatting the input. . -.Opt_def - X -Force displaying in an X window using gxditview. +This an advanced option from +.BR groff (@MAN1EXT@) , +useful for debugging. . -This option was adapted from groff. . +.Opt_def - X +Switch into +.I groff +mode and format the input with groff option +.Opt_short X ; +actually, this formats the input and displays it with +.BR gxditview (@MAN1EXT@) . +. +This differs from groffer's mode +.I x +because groffer's viewer options are not used, but the viewer is +configured like in groff with the groff option +.Opt_short P . +This option is inhereted from +.BR groff (@MAN1EXT@) . . -.Opt_def - Z -Display the groff intermediate output instead of the formatted input; -equivalent to -.Opt_alt -- mode Z . . -The short option -.Opt_short Z -is inhereted from +.Opt_def - Z +Switch into +.I groff +mode and format the input with groff option +.Opt_short Z ; +this produces the groff intermediate output without postprocessing; see +.BR groff_out (@MAN1EXT@) . +This an advanced option from .BR groff (@MAN1EXT@) , -while the name of the long option -.Opt_long ditroff -originates from -.BR man (1) -and was only implemented for compatibility. +useful for debugging. . . .Opt_def -- all -In searching man pages, retrieve all suitable ones. +In searching man pages, retrieve all suitable ones instead of only one. . . .Opt_def -- apropos @@ -1007,22 +1150,70 @@ 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. +.Opt_def -- background color +This is equivalent to +.Opt_long bg . +. +. +.Opt_def -- bd pixels +Specifies the color of the border surrounding the viewer +window. +. +This is an adaption of the X Toolkit option +.Opt_short bd . . 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 -- bg color +Set the background color of the viewer window. +. +This is an adaption of the X Toolkit option +.Opt_short bg . . -.Opt_def -- display X-diplay -Set the X display on which gxditview should be started, see +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 -- bw pixels +Specifies the width in pixels of the border surrounding the viewer +window (not available for all viewers). +. +This is an adaption of the X Toolkit option +.Opt_short bw . +. +. +.Opt_def -- debug +Print debugging information. +. +Actually, a function call stack is printed if an error occurs. +. +. +.Opt_def -- default +Reset all configuration from previously processed command line options +to the default values. +. +This is useful to wipe out all effects of former options and restart +option processing using only the rest of the command line. +. +. +.Opt_def -- default-modes mode1,mode2,\*[Ellipsis] +Set the sequence of modes for default mode to the comma separated list +given in the argument. +. +. +.Opt_def -- device +Eqivalent to +.Opt_short T . +. +. +.Opt_def -- display X-display +Set the X display on which the viewer program shall be started, see +.BR X (1) +for the syntax of the argument. . . .Opt_def -- ditroff @@ -1032,18 +1223,25 @@ This is kept for compatibiliy with GNU .BR man (1). . . -.Opt_def -- dpi value -Set resolution of the X viewer -.BR gxditview (@MAN_EXT1@). +.Opt_def -- dvi +Choose dvi mode; the formatted input is displayed with the +by default, the formatted input is displayed with the +.BR xdvi (1) +program. . -The only supported dpi values are -.B 75 +. +.Opt_def -- dvi-viewer prog +Set the viewer program for dvi mode. +. +This can be a file name or a program to be searched in +.Env_var $PATH . +. +Known dvi viewers inlude +.BR xdvi (1) and -.BR 100 . -The resolution can also be forced by specifying option -.Opt_alt - TX value . +.BR dvilx (1) . -If the actual display mode is not X then this option is ignored. +In each case, arguments can be provided additionally. . . .Opt_def -- extension suffix @@ -1060,19 +1258,36 @@ Originates from GNU .IR man . . . +.Opt_def -- foreground color +This is equivalent to +.Opt_short fg . +. +. .Opt_def -- fg color -Set foreground color of display window. +Set the foreground color of the viewer window. +. +This is an adaption of the X Toolkit option +.Opt_short bg . . 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 -- font font_name +This is equivalent to +.Opt_short ft . . -.Opt_def -- device -Eqivalent to -.Opt_short T . +. +.Opt_def -- ft font_name +Set the font used by the viewer window. +. +This is an adaption of the X Toolkit option +.Opt_short ft . +. +The argument is an X font name, see +.BR (1) +for details. . . .Opt_def -- geometry size_pos @@ -1080,25 +1295,27 @@ Set the geometry of the display window, that means its size and its starting position. . See -.BR (1) +.BR X (1) for details on the syntax of the argument. . If the actual display mode is not X then this option is ignored. . . -.Opt_def -- help -Eqivalent to -.Opt_short h . -. +.Opt_def -- groff +Set +.I groff +mode. . -.Opt_def -- intermediate-output -Equivalent to -.Opt_short Z . +Switch groffer to process the input like +.BR groff (@MAN1EXT@). . +This disables the groffer viewing features, all groffer viewing +options are ignored. . -.Opt_def -- lang language . -Set the language for man pages. +.Opt_def -- help +Eqivalent to +.Opt_short h . . . .Opt_def -- location @@ -1107,8 +1324,7 @@ Print the location of the retrieved files to standard error. . .Opt_def -- locale language . -Equivalent to -.Opt_long lang . +Set the language for man pages. . This option originates from GNU .BR man (1). @@ -1138,52 +1354,97 @@ The following mode values are recognized: . .RS . +. .TP -.B auto -Let groffer choose where to display; this is the default. +.B default +Display in the default manner; this actually means to try the modes +.IR ps , +.IR x , +and +.I tty +in this sequence. +. +Useful for restoring default mode when a different mode was specified +with +.Env_var $GROFFER_OPT . . . .TP -.B tty -Display in a text terminal; same as -.Opt_long tty . +.B dvi +Display formatted input in a dvi viewer program, +.BR xdvi (1) +by default; equivalent to +.Opt_long dvi . . . .TP -.B X -Display in a X window; same as -.Opt_short X . +.B ps +Display formatted input in a Postscript viewer program, +.BR ghostview (1) +by default; equivalent to +.Opt_long ps . . . .TP -.BR Q -Display source code; same as -.Opt_short Q . +.B tty +Display formatted input in a text terminal; equivalent to +.Opt_long tty . . . .TP -.B source -Display source code; same as -.Opt_short Q . +.B www +Display formatted input in a internet browser program, +.BR mozilla (1) +by default; equivalent to +.Opt_long www . . . .TP -.B Z -Display groff intermediate output; same as -.Opt_short Z . +.B x +Display formatted input in a native roff viewer such as +.BR gxditview (@MAN1EXT@), +which is distributed together with groff, or with +.BR xditview (1), +which is distributed as a standard X tool. +. +The only devices that are compatible with this mode are +.IR X75 , +.IR X100 , +.IR X75-12 , +.IR X100-12 , +and +.I ps +(the default device). +. +. +.P +The following modes do not use the +.I groffer +viewing features. +. +They are only interesting for advanced applications. . . .TP -.B intermediate-output -Display groff intermediate output; same as -.Opt_short Z . +.B groff +Generate device output with plain +.I groff +without using the special viewing features of +.IR groffer . +If no device was specified by option +.Opt_short T +the +.I groff +default +.B ps +is assumed. . . .TP -.B default -Display in the default manner, being actually -.IR auto . -Useful for restoring default behavior when other options are active. +.B source +Display source code; same as +.Opt_short Q . +. . .RE . @@ -1203,6 +1464,55 @@ Set the pager program in tty mode; default is .IR less . . . +.Opt_def -- ps +Choose ps mode (Postscript). +. +By default, the formatted input is displayed with the +.BR ghostview (@MAN1EXT@) +program; this can be configured with option +.Opt_long viewer-ps . +. +The only device that is compatible to this mode is +.IR ps , +which is also the default when no device is specified. +. +. +.Opt_def -- ps-viewer prog +Set the viewer program for +.I ps +mode. +. +This can be a file name or a program to be searched in +.Env_var $PATH . +. +Common Postscript viewers inlude +.BR gv (1), +.BR ghostview (1), +and +.BR gs (1), +. +In each case, arguments can be provided additionally. +. +. +.Opt_def -- resolution value +Set X resolution in dpi (dots per inch) in some viewer programs. +. +The only supported dpi values are +.B 75 +and +.BR 100 . +This is an adaption of the X Toolkit option +.Opt_short resolution . +. +. +.Opt_def -- rv +Reverse foreground and background color of the viewer window. +. +This is an adaption of the X Toolkit option +.Opt_short rv . +This feature is not available in all viewer programs. +. +. .Opt_def -- sections Restrict searching for man pages to the given .IR sections , @@ -1220,10 +1530,10 @@ Search for man pages for the given operating systems; the argument is a comma-separated list. . . -.Opt_def -- title "'this is my title'" -Set the title for the diplay window. +.Opt_def -- title "'some text'" +Set the title for the viewer window. . -This effects only the X mode. +This feature is not available in all viewer programs. . . .Opt_def -- to-postproc opt_or_arg @@ -1239,7 +1549,7 @@ This option is only kept for compatibility with GNU . . .Opt_def -- tty -Choose tty display mode, that means use output on a text pager even +Choose tty display mode, that means displaying in a text pager even when in X; eqivalent to .Opt_long mode\~tty . . @@ -1259,6 +1569,59 @@ Eqivalent to .Opt_long location . . . +.Opt_def -- www +Choose www mode (html), display in a web browser program, which can be +specified with option +.Opt_long www-viewer . +By default, the existence of a sequence of standard web browsers is +tested, starting with +.BR mozilla (1) +and +.BR netscape (1) +. +. +.Opt_def -- www-viewer prog +Set the web browser program for viewing in +.I www +mode. +. +Each program that accepts html input and allows the +.BI file://localhost/ dir / file +syntax on the command line is suitable; it can be the path name of an +executable file or a program in +.Env_var $PATH . +. +In each case, arguments can be provided additionally. +. +. +.Opt_def -- x +Choose +.I x +mode (view in X roff viewer). +. +By default, the formatted input is displayed with the +.BR gxditview (@MAN1EXT@) +program; this can be configured with option +.Opt_long x-viewer . +. +. + +.Opt_def -- x-viewer prog +Set the viewer program for +.I x +mode. +. +Suitable viewer programs are +.BR gxditview (@MAN1EXT@) +and +.BR xditview (1). +. +But the argument can be any executable file or a program in +.Env_var $PATH . +. +In each case, arguments can be provided additionally. +. +. .TP .Opt_-- Signals the end of option processing; all remaining arguments are @@ -1287,115 +1650,117 @@ automatically chooses a suitable display mode, but the user can also choose between the following modes: . .Topic -graphical display in X window with gxditview, +graphically display the formatted input with an X window program, +including . +.RS .Topic -text display in a pager on the text terminal (tty), +with X window roff viewers such as +.BR gxditview (@MAN1EXT@) +.RI ( x +mode), . .Topic -generate output for a given device, +in a dvi viewer program +.RI ( dvi +mode), . .Topic -source code streamed onto standard output, +in a Postscript viewer +.RI ( ps +mode), . .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 "Displaying in X window" -.\" -------------------------------------------------------------------- -. -The X mode can be chosen by the following methods: -. +in a web browser +.RI ( www +mode), +.RE . .Topic -Automatically, if the environment variable -.Env_var $DISPLAY -is set and no other mode was forced; -. +display formatted input in a pager on the text terminal +.RI ( tty +mode), . .Topic -by the options -.Opt_short X , -.Opt_long X , -or -.Opt_alt -- mode X ; -. +run groffer like groff, but with decompression and man\~page searching +.RI ( groff +mode); this includes things like generating the groff intermediate +output. . .Topic -by specifying one of the groff X* devices with option -.Opt_short T . +stream the unformatted source code of the input onto standard output +.RI ( source +mode), . . .P -In X mode, the formatted input is displayed with the -.BR gxditview (@MAN1EXT@) -program, which can use two resolutions, -.I 75 dpi -or -.IR "100 dpi" , -where -.I dpi -means -.IR "dots per inch" . -By default, groffer follows groff, which actually chooses 75 dpi. +By +.IR default , +.I groffer +first tries whether +.B x +mode is possible, then +.B ps +mode, and finally +.B tty +mode. +. +This mode testing sequence for +.B default +mode can be changed by specifying a comma separated list of modes +with the option +.Opt_long default-modes. . . .P -This resolution can be changed to 100 dpi by one of the following -options: +The searching for man\~pages and the decompression of the input are +active in every mode. . -.Topic -.Opt_alt -- dpi\~100 . -.Topic -.Opt_alt - T\~X100 +.\" -------------------------------------------------------------------- +.SS "Graphical Display Modes" +.\" -------------------------------------------------------------------- . -.Topic -.Opt_alt - T\~X100-12 +The graphical display modes work only in the X window environment (or +similar implementations within other windowing environments). . -.Topic -.Opt_alt - P\~resolution - P\~100 +The environment variable +.Env_var $DISPLAY +or the option +.Opt_long display +are used for specifying the X display to be used; if neither is +specified, groffer assumes that no X is running. . . .P -By replacing -.I 100 -by -.I 75 -in these options, the corresponding 75 dpi mode is activated. -. +A certain graphical display mode can be selected by one of the options +.Opt_long dvi , +.Opt_long ps , +.Opt_short X , +and +.Opt_long www . . -.P -The resolution can be preset to a fixed value for all calls to groffer -by including the option -.Opt_long 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. +By default, some graphical modes are tried first. If none succeeds +groffer switches to +.B tty +mode. . . .P -Note that the -.Opt_alt - TX ... -options force displaying in X, while the -.Opt_long dpi -is ignored when not displaying in X. +The graphical modes can be customized by options that were named +according to the resource options in the +.BR X (1) +Toolkit but using a leading double minus instead of the single minus +used by X. +. +These include +.Opt_long background , +.Opt_long foreground , +.Opt_long geometry , +.Opt_long resolution , +.Opt_long title , +.Opt_long xrm , +etc. . . .\" -------------------------------------------------------------------- @@ -1404,13 +1769,11 @@ is ignored when not displaying in X. . If the variable .Env_var $DISPLAY -is not set or empty groffer assumes that it should produce output on a -text terminal. +is not set or empty, groffer assumes that it should produce output on +a text terminal. . -This mode can be enforced by the options -.Opt_long tty -or -.Opt_alt -- mode tty . +This mode can also be forced by option +.Opt_long tty . . . .P @@ -1418,7 +1781,14 @@ In the actual implementation, the groff output device .I latin1 is chosen and the processed output is piped into a pager program. . -The pager can be specified by the environment variable +This can be changed by specifying option +.Opt_long tty-device . +. +. +.P +The pager to be used can be specified by option +.Opt_long pager +by the environment variable .Env_var $PAGER . If this is not set or empty the .BR less (1) @@ -1426,45 +1796,51 @@ program is used as the default pager. . . .\" -------------------------------------------------------------------- -.SS "Displaying roff Source Files" +.SS "Non-displaying Modes" .\" -------------------------------------------------------------------- . -Instead of the formatted output, it is also possible to have the -source code displayed. +There are some special modes that do not display the formatted output +in a viewer program. . -This mode must deliberately be requested by one of the options -.Opt_short Q , -.Opt_long source , -.Opt_long "mode Q" , -.Opt_long "mode source" . +These modes are regarded as advanced, they are useful for debugging +purposes. . . -.P -The retrieved source files are decompressed and streamed to standard -output without any pager or further processing. +.TP +.I source mode +Instead of displaying the formatted output, it is also possible to +have the roff source code streamed onto the standard output. . +This mode must be requested by one of the options +.Opt_short Q +or +.Opt_long source . . -.\" -------------------------------------------------------------------- -.SS "Output for a specific Device" -.\" -------------------------------------------------------------------- . -If a device other than the -.B X -devices is specified with the -.Opt_short T -then the input is formatted for this device and then send to standard -output without further actions. +.TP +.I groff mode +This mode disables the groffer viewing facilities. . -This enables the user save the generated output into a file of pipe it -into some kind of postprocessing. +The input is handled as usual with decompression and man\~page +searching, but then it is passed to groff using only the options +provided by groff. . +This enables the user to save the generated output into a file or pipe +it into another program. . -.P -Output for some devices, such as -.BR ps , -or -.B dvi -is not directly displayable without a special viewer. +In this mode, the input is formatted, but not postprocessed; see +.BR groff_out (@MAN5EXT@) +for details. +. +This mode is activated automatically by the three groff options +.Opt_short V +(print roff pipe, no formatting), +.Opt_short X +(display with gxditview in groff's native way, using +.Opt_short P +for customization), and +.Opt_short Z +(disable post-processing, thus producing the groff intermediate output). . . .\" -------------------------------------------------------------------- @@ -1494,7 +1870,7 @@ man\~pages. .TP .Opt_long no-man .TP+ -.Opt_long local_file +.Opt_long local-file disable the man searching; so only local files are displayed. . . @@ -1650,11 +2026,9 @@ environment variables and command line options. . . .P -The locale is determined like in GNU man, that is from highest to -lowest precedence: +The locale (language) is determined like in GNU man, that is from +highest to lowest precedence: .Topic -.Opt_long lang -and .Opt_long locale . .Topic @@ -1678,7 +2052,11 @@ The language locale is usually specified in the POSIX 1003.1 based format: .P \f[I]\f[][\f[CB]_\f[]\f[I]\f[][\f[CB].\f[]\ -\f[I]\f[][\f[CB],\f[]\f[I]\f[]]]]. +\f[I]\f[][\f[CB],\f[]\f[I]\f[]]]], +.P +but the two-letter code in +.I +is sufficient for most purposes. . . .P @@ -1797,7 +2175,7 @@ and some standard system variables are honored. .\" -------------------------------------------------------------------- . .TP -.Env_var GROFFER_OPT +.Env_var $GROFFER_OPT Store options for a run of groffer. . The options specified in this variable are overridden by the options @@ -1822,7 +2200,7 @@ The following variables have a special meaning for groffer. . . .TP -.Env_var DISPLAY +.Env_var $DISPLAY If this variable is set this indicates that the X window system is running. . @@ -1838,11 +2216,11 @@ second monitor by the command . . .TP -.Env_var LC_ALL +.Env_var $LC_ALL .TP+ -.Env_var LC_MESSAGES +.Env_var $LC_MESSAGES .TP+ -.Env_var LANG +.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. @@ -1876,7 +2254,7 @@ This is the same behavior as when all 3\~variables are unset. . . .TP -.Env_var 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 @@ -1887,7 +2265,7 @@ program . . .TP -.Env_var PATH +.Env_var $PATH All programs within the groffer shell script are called without a fixed path. . @@ -1895,6 +2273,15 @@ Thus this environment variable determines the set of programs used within the run of groffer. . . +.TP +.Env_var $POSIXLY_CORRECT +If set to a non-empty value this chooses the POSIX mode for option +processing, that means that option processing will be finished as soon +as a non-option argument is found. +. +Usually, you do not want to set this environment variable. +. +. .\" -------------------------------------------------------------------- .SS "Groff Variables" .\" -------------------------------------------------------------------- @@ -1907,7 +2294,7 @@ are internally used within groffer as well; see there for details. The following variables have a direct meaning for the groffer program. . .TP -.Env_var GROFF_TMPDIR +.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. . @@ -1924,12 +2311,12 @@ 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 , +.Env_var $MANOPT , which in turn is overwritten by the command line. . . .TP -.Env_var EXTENSION +.Env_var $EXTENSION Restrict the search for man\~pages to files having this extension. . This is overridden by option @@ -1938,7 +2325,7 @@ see there for details. . . .TP -.Env_var MANOPT +.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 @@ -1952,7 +2339,7 @@ given on the command line. . . .TP -.Env_var MANPATH +.Env_var $MANPATH If set, this variable contains the directories in which the man\~page trees are stored. . @@ -1961,7 +2348,7 @@ This is overridden by option . . .TP -.Env_var MANSECT +.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. . @@ -1970,7 +2357,7 @@ This is overridden by option . . .TP -.Env_var SYSTEM +.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. . @@ -1981,12 +2368,108 @@ see there for details. . .P The environment variable -.Env_var MANROFFSEQ +.Env_var $MANROFFSEQ is ignored by groffer because the necessary preprocessors are determined automatically. . . .\" -------------------------------------------------------------------- +.SH "FILES" +.\" -------------------------------------------------------------------- +. +The groffer program can be preconfigured by two configuration files. +. +Both of them are shell scripts that are called at the beginning of +groffer using the `\c +.CB .\~\c +.IR filename ' +syntax. +. +. +.TP +.CB /etc/groff/groffer.conf +System-wide configuration file for groffer. +. +. +.TP +.CB $HOME/.groff/groffer.conf +User-specific configuration file for groffer, where +.Env_var $HOME +denotes the user's home directory. +. +This script is called after the system-wide configuration file to +enable overriding by the user. +. +. +.P +It makes sense to use these configuration files for the following +tasks: +. +.Topic +Preset environment variables recognized by groffer; preferably a +variable should only be set when it is unset in order not to override +a user-provided value. +. +.Topic +Preset command line options by prepending them to +.Env_var $GROFFER_OPT ; +prepending should be preferred to appending and setting in order not +to delete the environment variable provided by the +. +.Topic +Write functions for calling viewer programs in a special way and feed +them into the +.Opt_long \f[I]*\f[]-viewer +options. +. +Note that the name of such a function must coincide with some existing +program in the system path +.Env_var $PATH +in order to be recognized by groffer. +. +. +.P +As an example, consider the following configuration file. +. +.P +.ft CR +.nh +.nf +#! /bin/sh +# ~/.groff/groffer.conf +if test "$DISPLAY" = ""; then + DISPLAY='localhost:0.0'; +fi; +GROFF_OPT="--resolution=100 $GROFF_OPT"; +gxditview() +{ + /usr/local/bin/gxditview --fg DarkBlue "$@"; +} +.fi +.hy +.ft +. +. +.P +This has the following effects: +.Topic +allows to start groffer in a graphical mode even from a text +terminal; +.Topic +all graphical modes use a resolution of 100 dpi where applicable; +.Topic +the +.BR gxditview (@MAN1EXT@) +program is told to use +.I DarkBlue +as the text color. +. +These configurations can be overridden by command line options and by +environment variable +.Env_var $GROFFER_OPT . +. +. +.\" -------------------------------------------------------------------- .SH "EXAMPLES" .\" -------------------------------------------------------------------- . @@ -1999,29 +2482,27 @@ capabilities. . . .TP -.Shell_cmd "groffer\~/usr/local/share/doc/groff/meintro.ms" -Format and display the file -.I meintro.ms +.Shell_cmd "groffer\~/usr/local/share/doc/groff/meintro.ms.gz" +Decompress, format and display the compressed file +.I meintro.ms.gz in the directory .IR /usr/local/share/doc/groff , -using a graphical viewer when in X window, or the +using a default graphical viewer when in X window, or the .BR less (1) pager program when not in X. . . .TP -.Shell_cmd "groffer\~groff.7\~groff\~\[cq]troff(1)\[cq]\~man:gxditview" +.Shell_cmd "groffer\~groff.7\~groff\~\[cq]troff(1)\[cq]\~man:roff" . -If none of the arguments is an existing file then lookup the four -man\~pages named +The arguments that are not existing files are looked-up as the +following man\~pages: .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). @@ -2039,13 +2520,14 @@ The formatted files are concatenated and displayed in one piece. . . .TP -.Shell_cmd "LANG=de\~groffer\~--man\~-Thtml\~ls\~>ls.html" +.Shell_cmd "LANG=de\~groffer\~--man\~--www\~--www-viever=netscape\~ls" . -Lookup the German manual page for the +Retrieve the German man\~page for the .B ls -program, decompress it, convert it into html format and write the -result into the file -.IR ls.html . +program (or the English one if there is a German version), decompress +it, format it into the html format and view the result in the default +web browser +.I netscape . The option .Opt_long man guarantees that the man\~page is retrieved, even when a local file @@ -2054,71 +2536,30 @@ exists in the actual directory. . . .TP -.Shell_cmd "cat\~stdin.1.gz\~|" -.TP+ -.Shell_cmd+ "PAGER=more\~groffer\~--tty\~a.ms\~-\~b.ms.Z" +.Shell_cmd "groffer\~-Q\~'man:roff(7)'" . -Display existing files -.IR a.ms , -.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 -.BR more -as pager program instead of the default pager -.BR less . +Print the unformatted content of the man\~page called +.I roff +in section 7 on standard output. . . .TP -.Shell_cmd "groffer\~-X\~-W--title\~-W\~hello\~-W\~mac\~file" -. -The first two -.Opt_short W -options simulate groffer's long option -.Opt_long title -with its argument -.IR hello . -. -But as -.I mac -does not start with a minus sign, the third -.Opt_short 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 -.Shell_cmd "groffer\~-X\~--title=hello\~-Wmac\~file" +.Shell_cmd "groffer\~-Z\~-mfoo" +. +Decompress the standard input, switch to +.I groff +mode, format the input with groff using the macro package foo, but do +not postprocess the result, thus producing the intermediate output. . . .TP .Shell_cmd "echo\~'\[rs]f[CB]WOW!'\~|" .TP+ -.Shell_cmd+ "groffer TX100 --bg red --fg yellow --geometry 200x100" +.Shell_cmd+ "groffer --x --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. . -If your shell does not have long options the options must be written as -.br -\f[CR]-TX100\~\:-W--bg\~\:-Wred\~\:-W--fg\~\:-Wyellow\~\:-W\c ---geometry\\~\:200x100\f[]. -.br -The equivalent options when using -.Opt_short P -are -.br -\f[CR]-TX100\~\:-P-bg\~\:-Pred\~\:-P-fg\~\:-Pyellow\~\:-P\c --geometry 200x100\f[]. -. . .\" -------------------------------------------------------------------- .SH "COMPATIBILITY" @@ -2138,33 +2579,26 @@ work on most actual commercial and free operating systems. . . .P -Common implementations of the POSIX shell -.BR sh (1) -include +The groffer shell script was tested with the following common +implementations of the POSIX shell: +.BR sh (1), +.BR ash (1), .BR bash (1), .BR ksh (1), and others. . +The best performance is provided by the +.I ash +shell. +. 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 -On systems without GNU -.BR getopt (1), -long options might not be available. -. -In these cases, the groffer option -.Opt_short W -can be used to specify long options nevertheless; the option character -.B W -was reserved by the POSIX standard for applications like this. -. -. -.P The groffer program can handle option arguments and file names that -contain any white space characters. +contain white space and a large set of special characters. . . .\" -------------------------------------------------------------------- @@ -2173,36 +2607,58 @@ contain any white space characters. . .TP .BR groff (@MAN1EXT@) -the GNU roff program. -. -.TP +.TP+ .BR troff (@MAN1EXT@) -details on some options, environment variables and the warnings used -in groff. +Details on the options and environment variables available in groff; +all of them can be used with groffer. . .TP .BR grog (@MAN1EXT@) -tries to guess the groff command line options for given input files. +Internally, groffer tries to guess the groff command line options from +the input using this program. +. +.TP +.BR groff_out (@MAN5EXT@) +Documentation on the groff intermediate output (ditroff output). +. +.TP +.BR xdvi (1) +.TP+ +.BR dvilx (1) +Viewers for groffer's +.I dvi +mode. +. +.TP +.BR gv (1) +.TP+ +.BR ghostview (1) +.TP +.BR gs (1) +Viewers for groffer's +.I ps +mode. . .TP .BR gxditview (@MAN1EXT@) -the GNU version of the roff viewer +.TP+ .BR xditview (1) -distributed with the the X window system. +Viewers for groffer's +.I x +mode. . .TP .BR gzip (1) -decompression of .gz or .Z files. +Decompression of .gz or .Z files. . .TP .BR man (1) -the standard way to diplay man\~pages. +The standard program to diplay man\~pages. . -The -.I man -options and environment variables that are supported by groffer refer -to -.IR "GNU man" . +This is only useful if it is the man\~page for +.IR "GNU\~man" . +Then it documents the options and environment variables that are +supported by groffer. . . .\" -------------------------------------------------------------------- diff --git a/contrib/groffer/groffer.sh b/contrib/groffer/groffer.sh index 391478e2..1269b11b 100644 --- a/contrib/groffer/groffer.sh +++ b/contrib/groffer/groffer.sh @@ -28,9 +28,17 @@ export _PROGRAM_NAME; export _PROGRAM_VERSION; export _LAST_UPDATE; -_PROGRAM_NAME=groffer -_PROGRAM_VERSION="0.7" -_LAST_UPDATE="31 May 2002" +_PROGRAM_NAME='groffer'; +_PROGRAM_VERSION='0.8'; +_LAST_UPDATE='23 June 2002'; + +export _DEBUG; +_DEBUG='no'; # disable debugging information +#_DEBUG='yes'; # enable debugging information + +export _DEBUG_LM; +_DEBUG_LM='no'; # disable landmark messages +#_DEBUG_LM='yes'; # enable landmark messages ######################################################################## @@ -47,13 +55,16 @@ _LAST_UPDATE="31 May 2002" # 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. +# The following displaying modes are available: +# - Display formatted input with the X roff viewer `gxditview', +# - with a Prostcript viewer, +# - with a dvi viewer, +# - with a web browser. +# - Display formatted input in a text terminal using a text device. +# - Generate output for some groff device on stdout without a viewer. +# - Output only the source code without any groff processing. +# - 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. @@ -64,40 +75,29 @@ _LAST_UPDATE="31 May 2002" # `exit' can only escape from the current shell; trouble occurs in # subshells. This was solved by sending kill signals, see # $_PROCESS_ID and error(). -# - -### 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. - - -######################################################################## -# Compatibility -######################################################################## +### Compatibility -# 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. +# This shell script is compatible to the both the GNU and the POSIX +# shell and utilities. 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. -# 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. +# The only non-builtin used here is POSIX `sed'. This script was +# tested under `bash', `ash', and `ksh'. The speed under `ash' is +# more than double when compared to the larger shells. +# This script provides its own option parser. It is compatible to the +# usual GNU style command line (option clusters, long options, mixing +# of options and non-option file names), except that it is not +# possible to abbreviate long option names. -######################################################################## -# General Setup -######################################################################## +# The mixing of options and file names can be prohibited by setting +# the environment variable `$POSIXLY_CORRECT' to a non-empty value. +# This enables the rather wicked POSIX behavior to terminate option +# parsing when the first non-option command line argument is found. -# set -a -# set -x -# set -v ######################################################################## # Survey of functions defined in this document @@ -136,14 +136,25 @@ _LAST_UPDATE="31 May 2002" # is_not_empty () # is_not_equal ( ) # is_not_file () +# is_not_prog () # is_prog () # is_yes () # leave () +# landmark () +# list_append ( ...) +# list_check () +# list_from_args (...) +# list_from_cmdline ( [...]) +# list_from_split ( ) +# list_has ( ) +# list_has_not ( ) +# list_length () # main_*(), see after the functions # man_do_filespec () # man_setup () # man_register_file ( [ [
]]) # man_search_section (
) +# man_set() # manpath_add_lang( ) # manpath_add_system() # manpath_from_path () @@ -155,6 +166,7 @@ _LAST_UPDATE="31 May 2002" # path_split () # register_file () # register_title () +# reset () # save_stdin () # string_contains ( ) # string_del_append () @@ -164,7 +176,6 @@ _LAST_UPDATE="31 May 2002" # string_not_contains ( ) # string_replace_all ( ) # string_sed_s ( [ []]) -# string_split ( ) # tmp_cat () # tmp_create (?) # to_tmp () @@ -195,21 +206,18 @@ _LAST_UPDATE="31 May 2002" ######################################################################## -# External envirnoment variables +# External environment variables # If these variables are exported here then the `ash' shell coughs # when calling `groff' in `main_display()'. -_export_externals='no'; -if test "${_export_externals}" = 'yes'; then +if test "${GROFFER_EXPORT_EXTERNALS}" = 'yes'; then # 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). @@ -227,17 +235,16 @@ if test "${_export_externals}" = 'yes'; then # all GNU man environment variables are used, see man(1). export MANOPT; # Preset options for man pages. export MANPATH; # Search path for man pages (: list). + export MANROFFSEQ; # Ignored because of grog guessing. export MANSECT; # Search man pages only in sections (:). export SYSTEM; # Man pages for different OS's (, list). - export MANROFFSEQ; # Ignored because of grog guessing. fi; -unset _export_externals; - ######################################################################## # read-only variables (global to this file) +######################################################################## # characters @@ -266,14 +273,48 @@ _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. +_ERROR='255'; # for syntax errors; no `-1' in `ash' _NO="${_BAD}"; _YES="${_GOOD}"; _OK="${_GOOD}"; -export _PROCESS_ID; # for shutting down the program -_PROCESS_ID="$$"; +# quasi-functions, call with `eval' +export return_ok; +export return_good; +export return_bad; +export return_yes; +export return_no; +export return_error; +return_ok="func_pop; return ${_OK}"; +return_good="func_pop; return ${_GOOD}"; +return_bad="func_pop; return ${_BAD}"; +return_yes="func_pop; return ${_YES}"; +return_no="func_pop; return ${_NO}"; +return_error="func_pop; return ${_ERROR}"; + + +export _CONFFILES; +_CONFFILES="/etc/groff/groffer.conf ${HOME}/.groff/groffer.conf"; + +export _DEFAULT_MODES; +_DEFAULT_MODES='X,ps,tty'; +export _DEFAULT_RESOLUTION; +_DEFAULT_RESOLUTION='100'; + +export _DEFAULT_TTY_DEVICE; +_DEFAULT_TTY_DEVICE='latin1'; + +# _VIEWER_* viewer programs for different modes (only X is necessary) +# _VIEWER_* a comma-separated list of viewer programs (with options) +export _VIEWER_DVI; # viewer program for dvi mode +export _VIEWER_PS; # viewer program for ps mode +export _VIEWER_WWW_X; # viewer program for www mode in X +export _VIEWER_WWW_TTY; # viewer program for www mode in tty +_VIEWER_DVI='xdvi,dvilx'; +_VIEWER_PS='gv,ghostview,gs_x11,gs'; +_VIEWER_WWW='mozilla,netscape,opera,amaya,arena'; +_VIEWER_X='gxditview,xditview'; # Search automatically in standard sections `1' to `8', and in the # traditional sections `9', `n', and `o'. On many systems, there @@ -281,10 +322,13 @@ _PROCESS_ID="$$"; # 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" +_MAN_AUTO_SEC="'1' '2' '3' '4' '5' '6' '7' '8' '9' 'n' 'o'" +export _PROCESS_ID; # for shutting down the program +_PROCESS_ID="$$"; -############ the command line options of several programs + +############ the command line options of the involved programs # # The naming scheme for the options environment names is # $_OPTS__[_] @@ -298,84 +342,89 @@ _MAN_AUTO_SEC="1 2 3 4 5 6 7 8 9 n o" # Each option that takes an argument must be specified with a # trailing : (colon). - -###### native groffer options - +# exports export _OPTS_GROFFER_SHORT_NA; export _OPTS_GROFFER_SHORT_ARG; export _OPTS_GROFFER_LONG_NA; export _OPTS_GROFFER_LONG_ARG; +export _OPTS_GROFF_SHORT_NA; +export _OPTS_GROFF_SHORT_ARG; +export _OPTS_GROFF_LONG_NA; +export _OPTS_GROFF_LONG_ARG; +export _OPTS_MAN_SHORT_ARG; +export _OPTS_MAN_SHORT_NA; +export _OPTS_MAN_LONG_ARG; +export _OPTS_MAN_LONG_NA; +export _OPTS_GROFFER_LONG; +export _OPTS_GROFFER_SHORT; +export _OPTS_GROFF_LONG; +export _OPTS_GROFF_SHORT; +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_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"; +###### native groffer options -_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:"; +_OPTS_GROFFER_SHORT_NA="'h' 'Q' 'v' 'V' 'X' 'Z'"; +_OPTS_GROFFER_SHORT_ARG="'T'"; -##### options inhereted from groff +_OPTS_GROFFER_LONG_NA="'all' 'apropos' 'ascii' 'auto' 'default' 'dvi' \ +'groff' 'help' 'intermediate-output' 'local-file' 'location' 'man' \ +'no-location' 'no-man' 'ps' 'rv' 'source' 'tty' 'tty-device' \ +'version' 'whatis' 'where' 'www' 'x'"; -export _OPTS_GROFF_SHORT_NA; -export _OPTS_GROFF_SHORT_ARG; -export _OPTS_GROFF_LONG_NA; -export _OPTS_GROFF_LONG_ARG; +_OPTS_GROFFER_LONG_ARG="'background' 'bd' 'bg' 'bw' 'default-modes' \ +'device' 'display' 'dvi-viewer' 'extension' 'fg' 'fn' 'font' \ +'foreground' 'geometry' \ +'locale' 'manpath' 'mode' 'pager' 'ps-viewer' 'resolution' 'sections' \ +'systems' 'title' 'troff-device' 'www-viewer' 'xrm' 'x-viewer'"; + +##### options inhereted from groff -_OPTS_GROFF_SHORT_NA="abcegilpstzCEGNRSUV"; -_OPTS_GROFF_SHORT_ARG="d:f:F:I:L:m:M:n:o:r:w:"; +_OPTS_GROFF_SHORT_NA="'a' 'b' 'c' 'e' 'g' 'i' 'l' 'p' 's' 't' 'z' \ +'C' 'E' 'G' 'N' 'R' 'S' 'U' 'V'"; +_OPTS_GROFF_SHORT_ARG="'d' 'f' 'F' 'I' 'L' 'm' 'M' 'n' 'o' 'P' 'r' \ +'w' '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_NA="'7' 'a' 'c' 'd' 'D' 'f' 'h' 'k' 'l' 't' 'u' \ +'V' 'w' 'Z'"; +_OPTS_MAN_SHORT_ARG="'e' 'L' 'm' 'M' 'p' 'P' 'r' 'S' 'T'"; -_OPTS_MAN_SHORT_ARG="e:L:m:M:p:P:r:S:T:"; -_OPTS_MAN_SHORT_NA="acdDfhkltuVwZ"; +_OPTS_MAN_LONG_NA="'all' 'ascii' 'apropos' 'catman' 'debug' 'default' \ +'ditroff' 'help' 'local-file' 'location' 'troff' 'update' 'version' \ +'whatis' 'where'"; -_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"; +_OPTS_MAN_LONG_ARG="'extension' 'locale' 'manpath' \ +'pager' 'preprocessor' 'prompt' 'sections' 'systems' 'troff-device'"; ###### 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}"; +"${_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}"; +_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_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_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}"; @@ -386,30 +435,22 @@ _OPTS_CMDLINE_LONG="${_OPTS_GROFFER_LONG} ${_OPTS_GROFF_LONG}"; ######################################################################## # read-write variables (global to this file) +######################################################################## export _ADDOPTS_GROFF; # Transp. options for groff (`eval'). export _ADDOPTS_POST; # Transp. options postproc (`eval'). export _ADDOPTS_X; # Transp. options X postproc (`eval'). -export _DISPLAY_MODE; # From command line arguments. -export _DISPLAY_PAGER; # Pager to be used on tty. +export _DEFAULT_MODES; # Set default modes. +export _DISPLAY_MODE; # Display mode. +export _DISPLAY_PROG; # Viewer program to be used for display. +export _DISPLAY_ARGS; # X resources for the viewer program. export _FILEARGS; # Stores filespec parameters. +export _FUNC_STACK; # Store debugging information. 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 @@ -423,19 +464,6 @@ 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 @@ -444,57 +472,53 @@ 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_ALL; # display all suitable man pages. +export _OPT_APROPOS; # branch to `apropos' program. +export _OPT_BD; # set border color in some modes. +export _OPT_BG; # set background color in some modes. +export _OPT_BW; # set border width in some modes. +export _OPT_DEBUG; # print debugging information on stderr. +export _OPT_DEFAULT_MODES; # `,'-list of modes when no mode given. +export _OPT_DEVICE; # device option. +export _OPT_DISPLAY; # set X display. +export _OPT_FG; # set foreground color in some modes. +export _OPT_FN; # set font in some modes. +export _OPT_GEOMETRY; # set size and position of viewer in X. 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_RESOLUTION; # set X resolution in dpi +export _OPT_RV; # reverse fore- and background colors. 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_TTY_DEVICE; # set device for tty mode. +export _OPT_V; # groff option -V. +export _OPT_VIEWER_DVI; # viewer program for dvi mode +export _OPT_VIEWER_PS; # viewer program for ps mode +export _OPT_VIEWER_WWW; # viewer program for www mode +export _OPT_VIEWER_X; # viewer program for x mode 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=''; - +export _OPT_X; # groff option -X. +export _OPT_XRM; # specify X resource. +export _OPT_Z; # groff option -Z. # _TMP_* temporary files export _TMP_DIR; # directory for temporary files export _TMP_CAT; # stores concatenation of everything export _TMP_PREFIX; # dir and base name for temporary files export _TMP_STDIN; # stores stdin, if any -_TMP_DIR=''; -_TMP_CAT=''; -_TMP_PREFIX=''; -_TMP_STDIN=''; + +# these variables are preset in section `Preset' after the rudim. test ######################################################################## # Test of rudimentary shell functionality ######################################################################## + ######################################################################## # Test of `test'. # @@ -504,59 +528,153 @@ test "a" = "a" || exit 1; ######################################################################## # Test of `echo' and the `$()' construct. # -echo -n '' >/dev/null || exit -1; +echo -n '' >/dev/null || exit "${_ERROR}"; if test "$(echo -n 'te' && echo -n '' && echo -n 'st')" != "test"; then - exit -1; + exit "${_ERROR}"; fi; ######################################################################## # Test of function definitions. # -_test_func() +_t_e_s_t_f_u_n_c_() { return "${_OK}"; } -if _test_func; then +if _t_e_s_t_f_u_n_c_ 2>/dev/null; then : else echo 'shell does not support function definitions.' >&2; - exit -1; + exit "${_ERROR}"; fi; ######################################################################## -# Test of builtin `local' -# -_global='outside'; +# Preset and reset of read-write global variables +######################################################################## + + +# For variables that can be reset by option `--default', see reset(). + +_FILEARGS=''; + +# _HAS_* from availability tests +_HAS_COMPRESSION=''; +_HAS_OPTS_GNU=''; +_HAS_OPTS_POSIX=''; + +# _TMP_* temporary files +_TMP_DIR=''; +_TMP_CAT=''; +_TMP_PREFIX=''; +_TMP_STDIN=''; + -test_local() +######################################################################## +# reset () +# +# Reset the variables that can be affected by options to their default. +# +reset() { - _global='inside'; - local _local >/dev/null 2>&1 || return "${_BAD}"; -} + if test "$#" -ne 0; then + error "reset() does not have arguments."; + return "${_ERROR}"; + fi; -if test_local; then - : -else - local() - { - return "${_OK}"; - } -fi; + _ADDOPTS_GROFF=''; + _ADDOPTS_POST=''; + _ADDOPTS_X=''; + _DISPLAY_ARGS=''; + _DISPLAY_MODE=''; + _DISPLAY_PROG=''; + _REGISTERED_TITLE=''; + + # _MAN_* finally used configuration of man searching + _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 + _MANOPT_ALL='no'; + _MANOPT_EXTENSION=''; + _MANOPT_LANG=''; + _MANOPT_PATH=''; + _MANOPT_PAGER=''; + _MANOPT_SEC=''; + _MANOPT_SYS=''; + + # _OPT_* as parsed from groffer command line + _OPT_ALL='no'; + _OPT_APROPOS='no'; + _OPT_BD=''; + _OPT_BG=''; + _OPT_BW=''; + _OPT_DEBUG='no'; + _OPT_DEFAULT_MODES=''; + _OPT_DEVICE=''; + _OPT_DISPLAY=''; + _OPT_FG=''; + _OPT_FN=''; + _OPT_GEOMETRY=''; + _OPT_LANG=''; + _OPT_LOCATION='no'; + _OPT_MODE=''; + _OPT_MANPATH=''; + _OPT_PAGER=''; + _OPT_RESOLUTION=''; + _OPT_RV=''; + _OPT_SECTIONS=''; + _OPT_SYSTEMS=''; + _OPT_TITLE=''; + _OPT_TTY_DEVICE=''; + _OPT_V='no'; + _OPT_VIEWER_DVI=''; + _OPT_VIEWER_PS=''; + _OPT_VIEWER_WWW=''; + _OPT_VIEWER_X=''; + _OPT_WHATIS='no'; + _OPT_X='no'; + _OPT_XRM=''; + _OPT_Z='no'; -if test "${_global}" != 'inside'; then - error "Cannot assign to global variables from within functions."; -fi; +} -unset _global; +reset; ######################################################################## # Functions for error handling and debugging ######################################################################## + +############## +# landmark () +# +# Print to standard error as a debugging aid. +# +# Globals: $_DEBUG_LM +# +landmark() +{ + if test "${_DEBUG_LM}" = 'yes'; then + echo ">>> $*" >&2; + fi; +} + +landmark "1: debugging functions"; + + ############## # clean_up () # @@ -624,8 +742,9 @@ diag() # error() { + local i; local _code; - _code=-1; + _code="${_ERROR}"; case "$#" in 0) true; ;; 1) echo2 'groffer error: '"$1"; ;; @@ -635,6 +754,9 @@ error() ;; *) echo2 'groffer error: wrong number of arguments in error().'; ;; esac; + if test "${_DEBUG}" = 'yes'; then + func_stack_dump; + fi; clean_up; kill "${_PROCESS_ID}" >/dev/null 2>&1; kill -9 "${_PROCESS_ID}" >/dev/null 2>&1; @@ -654,15 +776,181 @@ abort() } +############# +# func_check ( "$@") +# +# Check number of arguments and register to _FUNC_STACK. +# +# Arguments: >=3 +# : name of the calling function. +# : a relational operator: = != < > <= >= +# : number of arguments to be checked against +# "$@": the arguments of the calling function. +# +func_check() +{ + local _comp; + local _fname; + local _nargs; + local _op; + local _s; + if test "$#" -lt 3; then + error 'func_check() needs at least 3 arguments.'; + fi; + _fname="$1"; + case "$3" in + 1) + _nargs="$3"; + _s=''; + ;; + 0|[2-9]) + _nargs="$3"; + _s='s'; + ;; + *) + error "func_check(): third argument must be a digit."; + ;; + esac; + case "$2" in + '='|'-eq') + _op='-eq'; + _comp='exactly'; + ;; + '>='|'-ge') + _op='-ge'; + _comp='at least'; + ;; + '<='|'-le') + _op='-le'; + _comp='at most'; + ;; + '<'|'-lt') + _op='-lt'; + _comp='less than'; + ;; + '>'|'-gt') + _op='-gt'; + _comp='more than'; + ;; + '!='|'-ne') + _op='-ne'; + _comp='not'; + ;; + *) + error \ + "func_check(): second argument is not a relational operator."; + ;; + esac; + shift 3; + if test "$#" "${_op}" "${_nargs}"; then + do_nothing; + else + error \ + "${_fname}"'() needs '"${_comp} ${_nargs}"' argument'"${_s}"'.'; + fi; + if test "${_DEBUG}" = 'yes'; then + func_push "${_fname} $*"; + fi; +} + + +############# +# func_pop () +# +# Retrieve the top element from the stack. +# +# Arguments: 1 +# +func_pop() +{ + if test "${_DEBUG}" = 'yes'; then + if test "$#" -ne 0; then + error 'func_pop() does not have arguments.'; + fi; + case "${_FUNC_STACK}" in + '') + error 'func_pop(): stack is empty.'; + ;; + *!*) +# echo2 '>> pop: ('"$(echo -n "${_FUNC_STACK}" \ +# | sed -e 's/^\([^ !]*\).*$/\1/')"')'; + _FUNC_STACK="$(echo -n ${_FUNC_STACK} \ + | sed -e 's/^[^!]*!//')"; + ;; + *) + _FUNC_STACK=''; + ;; + esac; + fi; +} + + +############# +# func_push () +# +# Store another element to stack. +# +# Arguments: 1 +# +func_push() +{ + local _element; + if test "${_DEBUG}" = 'yes'; then + if test "$#" -ne 1; then + error 'func_push() needs 1 argument.'; + fi; + case "$1" in + *'!'*) + _element="$(echo -n "$1" | sed -e 's/!//g')"; + ;; + *) + _element="$1"; + ;; + esac; +# echo2 '>> push: '"$_element"; + if test "${_FUNC_STACK}" = ''; then + _FUNC_STACK="${_element}"; + else + _FUNC_STACK="${_element}!${_FUNC_STACK}"; + fi; + fi; +} + + +############# +# func_stack_dump () +# +# Print the content of the stack. Ignore the arguments. +# +func_stack_dump() +{ + diag 'call stack:'; + case "${_FUNC_STACK}" in + *!*) + _rest="${_FUNC_STACK}"; + while test "${_rest}" != ''; do + diag "$(echo -n "${_rest}" | sed -e 's/^\([^!]*\)!.*$/\1/')"; + _rest="$(echo -n "${_rest}" | sed -e 's/^!*[^!]*!*//')"; + done; + ;; + *) + diag "${_FUNC_STACK}"; + ;; + esac; +} + + ######################################################################## # System Test ######################################################################## +landmark "2: system test"; + # Test the availability of the system utilities used in this script. ######################################################################## -# Test of function `true'. +# Test of `true'. # if true >/dev/null 2>&1; then true; @@ -680,9 +968,71 @@ fi; ######################################################################## +# Test of `unset'. +# +_test='test'; +if unset _test >/dev/null 2>&1 && test "${_test}" = ''; then + true; +else + unset() + { + for v in "$@"; do + eval "$v"=''; + done; + } +fi; +unset _test; + +######################################################################## +# Test of builtin `local' +# + +_t_e_s_t_f_u_n_c_() +{ + local _test >/dev/null 2>&1 || return "${_BAD}"; +} + +if _t_e_s_t_f_u_n_c_; then + : +else + local() + { + if test "$1" != ''; then + error "overriding global variable \`$1' with local value."; + fi; + } +fi; + + +######################################################################## +# Test of global setting in functions +# +_global='outside'; +_clobber='outside'; + +_t_e_s_t_f_u_n_c_() +{ + local _clobber; + _global='inside'; + _clobber='inside'; +} + +_t_e_s_t_f_u_n_c_; +if test "${_global}" != 'inside' || test "${_clobber}" != 'outside'; +then + error "Cannot assign to global variables from within functions."; +fi; + +unset _global; +unset _clobber; + + +######################################################################## # Test of function `sed'. # -if test "$(echo teeest | sed -e '\|^teeest$|s|\(e\)\+|\1|')" != "test"; +if test "$(echo xTesTx \ + | sed -e 's/^.\([Tt]e*x*sT\+\).*$/\1/' \ + | sed -e '\|T|s||t|g')" != 'test'; then error 'Test of "sed" command failed.'; fi; @@ -707,67 +1057,24 @@ fi; ######################################################################## -# Test for temporary directory and file generating utility. -# +_t_e_s_t_f_u_n_c_() +{ + : +} -# determine temporary directory into `$_TMP_DIR' -for d in "${GROFF_TMPDIR}" "${TMPDIR}" "${TMP}" "${TEMP}" \ - "${TEMPDIR}" "${HOME}"/tmp /tmp "${HOME}" .; -do - if test "$d" != ""; then - if test -d "$d" && test -r "$d" && test -w "$d"; then - _TMP_DIR="$d"; - break; - fi; - fi; -done; -unset d; -if test "${_TMP_DIR}" = ""; then - error "Couldn't find a directory for storing temorary files."; -fi; -_TMP_PREFIX="${_TMP_DIR}/${_PROGRAM_NAME}"; +######################################################################## +# Definition of normal Functions +######################################################################## +landmark "3: functions"; ######################################################################## -# Test option parsing programs. +# abort (*) +# +# Unconditionally terminate the program with error code; +# useful for debugging. # - -# GNU getopt -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; - -OPTIND=1; -OPTARG=""; - - -######################################################################## -# Definition of Functions -######################################################################## - - -######################################################################## -# abort (*) -# -# Unconditionally terminate the program with error code; -# useful for debugging. -# -# defined above +# defined above ######################################################################## @@ -781,11 +1088,9 @@ OPTARG=""; # base_name() { - if test "$#" != 1; then - error "base_name() needs 1 argument."; - return "${_ERROR}"; - fi; + func_check base_name = 1 "$@"; string_sed_s "$1" '^.*/\([^/]*\)$' '\1'; + eval "${return_ok}"; } @@ -798,20 +1103,19 @@ base_name() if test "${_HAS_COMPRESSION}" = 'yes'; then catz() { - if test "$#" -ne 1; then - error "catz() needs exactly 1 argument."; - return "${_ERROR}"; - fi; + func_check catz = 1 "$@"; cat "$1" | gzip -c -d -f 2>/dev/null; + eval "${return_ok}"; } else catz() { + func_check catz = 1 "$@"; if test "$#" -ne 1; then error "catz() needs exactly 1 argument."; - return "${_ERROR}"; fi; cat "$1"; + eval "${return_ok}"; } fi; @@ -841,6 +1145,10 @@ fi; ######################################################################## +landmark '4: dirname()*'; +######################################################################## + +####################################################################### # dirname_append ( ) # # Append `name' to `dir' with clean handling of `/'. @@ -850,20 +1158,17 @@ fi; # dirname_append() { + func_check dirname_append = 2 "$@"; local _res; - if test "$#" -ne 2; then - error "dir_append() needs 2 arguments."; - return "${_ERROR}"; - fi; if is_empty "$1"; then error "dir_append(): first argument is empty."; - return "${_ERROR}"; fi; if is_empty "$2"; then echo -n "$1"; - return "${_OK}"; + else + dirname_chop "$1"/"$2"; fi; - dirname_chop "$1"/"$2"; + eval "${return_ok}"; } @@ -877,18 +1182,16 @@ dirname_append() # dirname_chop() { + func_check dirname_chop = 1 "$@"; 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; + eval "${return_ok}"; } @@ -915,21 +1218,18 @@ dirname_chop() # do_filearg() { + func_check do_filearg = 1 "$@"; local _filespec; local i; - if test "$#" -ne 1; then - error "do_filearg() expects 1 argument."; - return "${_ERROR}"; - fi; _filespec="$1"; # store sequence positional parameters case "${_filespec}" in '') - return "${_GOOD}"; + eval "${return_good}"; ;; '-') register_file '-'; - return "${_GOOD}"; + eval "${return_good}"; ;; */*) # with directory part; so no man search set -- 'File'; @@ -952,10 +1252,10 @@ do_filearg() if test -f "${_filespec}"; then if test -r "${_filespec}"; then register_file "${_filespec}"; - return "${_GOOD}"; + eval "${return_good}"; else echo2 "could not read \`${_filespec}'"; - return "${_BAD}"; + eval "${return_bad}"; fi; else continue; @@ -966,14 +1266,14 @@ do_filearg() man_setup; fi; if man_do_filespec "${_filespec}"; then - return "${_GOOD}"; + eval "${return_good}"; else continue; fi; ;; esac; done; - return "${_BAD}"; + eval "${return_bad}"; } # do_filearg() @@ -1013,6 +1313,43 @@ do_nothing() ######################################################################## +# func_check ( "$@") +# +# Check number of arguments and register to _FUNC_STACK. +# +# Arguments: >=3 +# : name of the calling function. +# : a relational operator: = != < > <= >= +# : number of arguments to be checked against +# "$@": the arguments of the calling function. +# +# defined above + +######################################################################### +# func_pop () +# +# Delete the top element from the function call stack. +# +# defined above + + +######################################################################## +# func_push () +# +# Store another element to function call stack. +# +# defined above + + +######################################################################## +# func_stack_dump () +# +# Print the content of the stack. +# +# defined above + + +######################################################################## # get_first_essential (*) # # Retrieve first non-empty argument. @@ -1022,21 +1359,26 @@ do_nothing() # get_first_essential() { + func_check get_first_essential '>=' 0 "$@"; local i; if test "$#" -eq 0; then - return "${_OK}"; + eval "${return_ok}"; fi; for i in "$@"; do if is_not_empty "$i"; then echo -n "$i"; - return "${_OK}"; + eval "${return_ok}"; fi; done; - return "${_BAD}"; + eval "${return_bad}"; } ######################################################################## +landmark '5: is_*()'; +######################################################################## + +######################################################################## # is_dir () # # Test whether `name' is a directory. @@ -1046,15 +1388,13 @@ get_first_essential() # is_dir() { - if test "$#" -ne 1; then - error "is_dir() needs 1 argument."; - return "${_ERROR}"; - fi; + func_check is_dir = 1 "$@"; if is_not_empty "$1" && test -d "$1" && test -r "$1"; then - return "${_YES}"; + eval "${return_yes}"; else - return "${_NO}"; + eval "${return_no}"; fi; + eval "${return_ok}"; } @@ -1068,15 +1408,13 @@ is_dir() # is_empty() { - if test "$#" -ne 1; then - error "is_empty() needs 1 argument."; - return "${_ERROR}"; - fi; + func_check is_empty = 1 "$@"; if test -z "$1"; then - return "${_YES}"; + eval "${return_yes}"; else - return "${_NO}"; + eval "${return_no}"; fi; + eval "${return_ok}"; } @@ -1090,15 +1428,13 @@ is_empty() # is_equal() { - if test "$#" -ne 2; then - error "is_equal() needs 2 arguments."; - return "${_ERROR}"; - fi; + func_check is_equal = 2 "$@"; if test "$1" = "$2"; then - return "${_YES}"; + eval "${return_yes}"; else - return "${_NO}"; + eval "${return_no}"; fi; + eval "${return_ok}"; } @@ -1112,15 +1448,13 @@ is_equal() # is_file() { - if test "$#" -ne 1; then - error "is_file() needs 1 argument."; - return "${_ERROR}"; - fi; + func_check is_file = 1 "$@"; if is_not_empty "$1" && test -f "$1" && test -r "$1"; then - return "${_YES}"; + eval "${return_yes}"; else - return "${_NO}"; + eval "${return_no}"; fi; + eval "${return_ok}"; } @@ -1134,15 +1468,13 @@ is_file() # is_not_dir() { - if test "$#" -ne 1; then - error "is_not_dir() needs 1 argument."; - return "${_ERROR}"; - fi; + func_check is_not_dir = 1 "$@"; if is_dir "$1"; then - return "${_NO}"; + eval "${return_no}"; else - return "${_YES}"; + eval "${return_yes}"; fi; + eval "${return_ok}"; } @@ -1156,15 +1488,13 @@ is_not_dir() # is_not_empty() { - if test "$#" -ne 1; then - error "is_not_empty() needs 1 argument."; - return "${_ERROR}"; - fi; + func_check is_not_empty = 1 "$@"; if is_empty "$1"; then - return "${_NO}"; + eval "${return_no}"; else - return "${_YES}"; + eval "${return_yes}"; fi; + eval "${return_ok}"; } @@ -1177,15 +1507,13 @@ is_not_empty() # is_not_equal() { - if test "$#" -ne 2; then - error "is_not_equal() needs 2 arguments."; - return "${_ERROR}"; - fi; + func_check is_not_equal = 2 "$@"; if is_equal "$1" "$2"; then - return "${_NO}"; + eval "${return_no}"; else - return "${_YES}"; + eval "${return_yes}"; fi; + eval "${return_ok}"; } @@ -1194,19 +1522,37 @@ is_not_equal() # # Test whether `name' is a not readable file. # -# Arguments : 1 +# Arguments : >=1 (empty allowed), more args are ignored # is_not_file() { - if test "$#" -ne 1; then - error "is_not_file() needs 1 argument."; - return "${_ERROR}"; - fi; + func_check is_not_file '>=' 1 "$@"; if is_file "$1"; then - return "${_NO}"; + eval "${return_no}"; + else + eval "${return_yes}"; + fi; + eval "${return_ok}"; +} + + +######################################################################## +# is_not_prog () +# +# Verify that arg is a not program in $PATH. +# +# Arguments : >=1 (empty allowed) +# more args are ignored, this allows to specify progs with arguments +# +is_not_prog() +{ + func_check is_not_prog '>=' 1 "$@"; + if where "$1" >/dev/null; then + eval "${return_no}"; else - return "${_YES}"; + eval "${return_yes}"; fi; + eval "${return_ok}"; } @@ -1219,15 +1565,13 @@ is_not_file() # is_not_yes() { - if test "$#" -ne 1; then - error "is_not_yes() needs 1 argument."; - return "${_ERROR}"; - fi; - if is_yes "$1"; then - return "${_NO}"; + func_check is_not_yes = 1 "$@"; + if test "$1" = 'yes'; then + eval "${return_no}"; else - return "${_YES}"; + eval "${return_yes}"; fi; + eval "${return_ok}"; } @@ -1236,19 +1580,18 @@ is_not_yes() # # Determine whether arg is a program in $PATH # -# Arguments : 1 (empty allowed) +# Arguments : >=1 (empty allowed) +# more args are ignored, this allows to specify progs with arguments # is_prog() { - if test "$#" -ne 1; then - error "is_prog() needs 1 argument."; - return "${_ERROR}"; - fi; + func_check is_prog '>=' 1 "$@"; if where "$1" >/dev/null; then - return "${_YES}"; + eval "${return_yes}"; else - return "${_NO}"; + eval "${return_no}"; fi; + eval "${return_ok}"; } @@ -1262,19 +1605,27 @@ is_prog() # is_yes() { - if test "$#" -ne 1; then - error "is_yes() needs 1 argument."; - return "${_ERROR}"; - fi; - if is_equal "$1" 'yes'; then - return "${_YES}"; + func_check is_yes = 1 "$@"; + if test "$1" = 'yes'; then + eval "${return_yes}"; else - return "${_NO}"; + eval "${return_no}"; fi; + eval "${return_ok}"; } ######################################################################## +# landmark () +# +# Print debugging information on standard error if $_DEBUG_LM is `yes'. +# +# Globals: $_DEBUG_LM +# +# Defined in section `Debugging functions'. + + +######################################################################## # leave () # # Clean exit without an error. @@ -1287,181 +1638,584 @@ leave() ######################################################################## -# man_do_filespec () +landmark '6: list_*()'; +######################################################################## + +######################################################################## +# list_append ( ...) # -# Print suitable man page(s) for filespec to $_TMP_CAT. +# Arguments: >=2 +# : a space-separated list of single-quoted elements. +# : some sequence of characters. +# Output: +# if is empty: "'' '...'" +# otherwise: " '' ..." # -# Arguments : 2 -# : argument of the form `man:name.section', `man:name', -# `man:name(section)', `name.section', `name'. +list_append() +{ + func_check list_append '>=' 2 "$@"; + local _element; + local _res; + _res="$1"; + shift; + for s in "$@"; do + # escape each single quote. + case "$s" in + *\'*) + _element="$(echo -n "$s" | sed -e s/\'/'&\\&&'/g)"; + ;; + *) + _element="$s"; + ;; + esac; + _res="${_res} '${_element}'"; + done; + echo -n "${_res}"; + eval "${return_ok}"; +} + + +######################################################################## +# list_check () # -# Globals : $_OPT_ALL +# Check whether is a space-separated list of '-quoted elements. # -# Output : none. -# Return : `0' if man page was found, `1' else. +# If the test fails an error is raised. +# If the test succeeds the argument is echoed. # -# Only called from do_fileargs(), checks on $MANPATH and -# $_MAN_ENABLE are assumed. +# Testing criteria: +# A list has the form "'first' 'second' '...' 'last'". +# So it has a leading and a final quote and the elements are separated +# by "' '" constructs. If these are all removed there should not be +# any single-quotes left. Watch out for "\'". # -man_do_filespec() +# Arguments: 1 +# Output: the argument unchanged, it the check succeeded. +# +list_check() { - local _got_one; - local _name; - local _prevsec; - local _res; - local _section; - local _spec; - local _string; - local s; - if is_empty "${MANPATH}"; then - return "${_BAD}"; + func_check list_check = 1 "$@"; + local _list; + if is_empty "$1"; then + eval "${return_ok}"; fi; - case "$#" in - 1) true; ;; + case "$1" in + \'*\') _list="$1"; ;; *) - error "man_do_filespec() needs exactly 1 argument."; - return "${_ERROR}"; + error "list_check() bad list: $1" ;; esac; - if is_empty "$1"; then - return "${_BAD}"; - fi; - _spec="$1"; - _name=''; - _section=''; - case "${_spec}" in - man:?*\(?*\)) # man:name(section) - _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 - _string="$(string_del_leading "${_spec}" 'man:')"; - _name="$(string_del_trailing "${_string}" '\.[^.]*')"; - _section="$(string_del_leading "${_string}" "${_name}"'\.')"; - ;; - man:?*) # man:name - _name="$(string_del_leading "${_spec}" 'man:')"; - ;; - ?*\(?*\)) # 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}"'\.')"; - ;; - ?*) - _name="${_filespec}"; + _list="$(echo -n "${_list}" \ + | sed -e s/^"[']"'\(.*\)'"[']"'$/\1/' \ + | sed -e s/"[']"'[\]'"['][']"'//g' \ + | sed -e 's/\([^\]\)'"'"' *'"'"'/\1/g')"; # ' (for emacs) + case "${_list}" in + *\'*) + error "list_check() bad list: ${_list}" ;; esac; - if is_empty "${_name}"; then - return "${_BAD}"; - fi; - _got_one='no'; - if is_empty "${_section}"; then - eval set -- "${_MAN_AUTO_SEC}"; - for s in "$@"; 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}"; -} # man_do_filespec() + echo -n "$1"; + eval "${return_ok}"; +} ######################################################################## -# man_parse_name () -# -# Parse the man page name part off from a filespec +# list_element_from_arg () # -# Arguments: 1, 2, or 3; maybe empty -# Output: none +# Arguments: 1 +# : some sequence of characters (also single quotes allowed). +# Output: the list element generated from . # -man_parse_name() +list_element_from_arg() { - return; + func_check list_element_from_arg = 1 "$@"; + local _res; + echo -n "'"; + # replace each single quote "'" by "'\''". + echo -n "$1" | sed -e 's/'\''/&\\&&/g'; # ' for emacs + echo -n "'"; + eval "${return_ok}"; } ######################################################################## -# man_register_file ( [
]) +# list_from_args (...) # -# Write a found man page file and register the title element. +# Generate a space-separated list of single-quoted elements from args. # -# Arguments: 1, 2, or 3; maybe empty -# Output: none +# Arguments: +# : some sequence of characters. +# Output: "'' '...'" # -man_register_file() +list_from_args() { - case "$#" in - 2|3) do_nothing; ;; - *) - error "man_register_file() expects 1 argument."; - return "${_ERROR}"; - ;; - esac; - if is_empty "$1"; then - error 'man_register_file(): file name is empty'; - fi; - to_tmp "$1"; - case "$#" in - 2) - register_title "man:$2"; - return "${_OK}"; - ;; - 3) - register_title "$2($3)"; - return "${_OK}"; - ;; - esac; + func_check list_from_args '>=' 1 "$@"; + local _list; + _list=""; + for s in "$@"; do + _list="$(list_append "${_list}" "$s")"; + done; + echo -n "${_list}"; + eval "${return_ok}"; } ######################################################################## -# man_search_section (
) -# -# Retrieve man pages. -# -# Arguments : 2 -# Globals : $_MAN_PATH, $_MAN_EXT -# Return : 0 if found, 1 otherwise -# -man_search_section() +# list_from_cmdline ( [...]) +# +# Transform command line arguments into a normalized form. +# +# Options, option arguments, and file parameters are identified and +# output each as a single-quoted argument of its own. Options and +# file parameters are separated by a '--' argument. +# +# Arguments: >=4 +# : space-separated list of short options without an arg. +# : space-separated list of short options that have an arg. +# : space-separated list of long options without an arg. +# : space-separated list of long options that have an arg. +# ...: the arguments from the command line (by "$@"). +# +# Globals: $POSIXLY_CORRECT (only kept for compatibility). +# +# Output: ['-[-]opt' ['optarg']]... '--' ['filename']... +# +# Example: +# list_normalize 'a b' 'c' '' 'long' -a f1 -bcarg --long=larg f2 +# will result in printing: +# '-a' '-b' '-c' 'arg' '--long' 'larg' '--' 'f1' 'f2' +# If $POSIXLY_CORRECT is not empty, the result will be: +# '-a' '--' 'f1' '-bcarg' '--long=larg' 'f2' +# +# Rationale: +# In POSIX, the first non-option ends the option processing. +# In GNU mode (default), non-options are sorted behind the options. +# +# Use this function only in the following way: +# eval set -- "$(args_norm '...' '...' '...' '...' "$@")"; +# while test "$1" != '--'; do +# case "$1" in +# ... +# esac; +# shift; +# done; +# shift; #skip '--' +# # all positional parameters ("$@") left are file name parameters. +# +list_from_cmdline() { - local _dir; - local _ext; - local _got_one; - local _name; - local _prefix - local _section; - local d; - local f; - if is_empty "${_MAN_PATH}"; then - return "${_BAD}"; + func_check list_from_cmdline '>=' 4 "$@"; + local _fparams; + local _result; + if is_empty "${FUNCNAME}"; then + local FUNCNAME; + FUNCNAME='list_from_cmdline'; fi; - if test "$#" -ne 2; then - error "man_sec_first() needs 2 arguments."; - return "${_ERROR}"; + _short_n="$(list_check "$1")"; # short options, no argument + _short_a="$(list_check "$2")"; # short options with argument + _long_n="$(list_check "$3")"; # long options, no argument + _long_a="$(list_check "$4")"; # long options with argument + shift 4; + if test "$#" -eq 0; then + echo -n "'--'"; + eval "${return_ok}"; + fi; + _fparams=''; + _result=''; + while test "$#" -ge 1; do + _arg="$1"; + shift; + case "$_arg" in + --) break; ;; + --?*) + _opt="$(string_del_leading "${_arg}" "--")"; + if list_has "$_long_n" "${_opt}"; then + # long option, no argument + _result="$(list_append "${_result}" "--${_opt}")"; + continue; + fi; + if list_has "${_long_a}" "${_opt}"; then + # long option with argument + _result="$(list_append "${_result}" "--${_opt}")"; + if test "$#" -le 0; then + error "${FUNCNAME}(): no argument for option --${_opt}." + fi; + _result="$(list_append "${_result}" "$1")"; + shift; + continue; + fi; + # test on `--opt=arg' + if string_contains "${_opt}" "="; then + _lopt="$(string_del_trailing "${_opt}" '=.*')"; + if list_has "${_long_a}" "${_lopt}"; then + _optarg="$(string_del_leading "${_opt}" "${_lopt}=")"; + _result="$(list_append "${_result}" \ + "--${_lopt}" "${_optarg}")"; + continue; + fi; + fi; + error "${FUNCNAME}(): --${_opt} is not an option." + ;; + -*) # short option (cluster) + _rest="$(string_del_leading "${_arg}" "-")"; + while is_not_empty "${_rest}"; do + _optchar="$(string_get_leading "${_rest}" '.')"; + _rest="$(string_del_leading "${_rest}" '.')"; + if list_has "${_short_n}" "${_optchar}"; then + _result="$(list_append "${_result}" "-${_optchar}")"; + continue; + elif list_has "${_short_a}" "${_optchar}"; then + _rest="$(string_del_leading "${_rest}" "${_optchar}")"; + if is_empty "${_rest}"; then + if test "$#" -ge 1; then + _result="$(list_append "${_result}" \ + "-${_optchar}" "$1")"; + shift; + continue; + else + error \ + "${FUNCNAME}(): no argument for option -${_optchar}." + fi; + else # rest is the argument + _result="$(list_append "${_result}" \ + "-${_optchar}" "${_rest}")"; + _rest=''; + continue; + fi; + else + error "${FUNCNAME}(): unknown option -${_optchar}." + fi; + done; + ;; + *) + # Here, $_arg is not an option, so a file parameter. + # When $POSIXLY_CORRECT is set this ends option parsing; + # otherwise, the argument is stored as a file parameter and + # option processing is continued. + _fparams="$(list_append "${_fparams}" "${_arg}")"; + if is_not_empty "$POSIXLY_CORRECT"; then + break; + fi; + ;; + esac; + done; + _result="$(list_append "${_result}" "--")"; + if is_not_empty "${_fparams}"; then + _result="${_result} ${_fparams}"; + fi; + if test "$#" -gt 0; then + _result="$(list_append "${_result}" "$@")"; + fi; + echo -n "$_result"; + eval "${return_ok}"; +} # list_from_cmdline() + + +######################################################################## +# list_from_lists ( ...) +# +# Generate a list from the concatenation of the lists in the arguments. +# +# Arguments: >=2 +# : string of space-separated single-quoted elements. +# Output: "'' ..." +# +list_from_lists() +{ + func_check list_from_lists '>=' 2 "$@"; + _list=''; + echo -n "$*"; + eval "${return_ok}"; +} + + +######################################################################## +# list_from_split ( ) +# +# In escape white space and replace each by space. +# +# Arguments: 2: a that is to be split into parts divided by +# +# Output: the resulting string +# +list_from_split() +{ + func_check list_from_split = 2 "$@"; + string_replace_all \ + "$(string_replace_all \ + "$1" \ + '\(['"${_SPACE}${_TAB}"']\)' \ + '\\\1')" \ + "$2" \ + ' '; + eval "${return_ok}"; +} + + +######################################################################## +# list_has ( ) +# +# Arguments: 2 +# : a space-separated list of single-quoted elements. +# : some sequence of characters. +# Output: +# if is empty: "'' '...'" +# otherwise: " '' ..." +# +list_has() +{ + func_check list_has = 2 "$@"; + if is_empty "$1"; then + eval "${return_no}"; + fi; + _list="$1"; + _element="$2"; + case "$2" in + \'*\') _element="$2"; ;; + *) _element="'$2'"; ;; + esac; + if string_contains "${_list}" "${_element}"; then + eval "${return_yes}"; + else + eval "${return_no}"; fi; + eval "${return_ok}"; +} + + +######################################################################## +# list_has_not ( ) +# +# Arguments: 2 +# : a space-separated list of single-quoted elements. +# : some sequence of characters. +# Output: +# if is empty: "'' '...'" +# otherwise: " '' ..." +# +list_has_not() +{ + func_check list_has_not = 2 "$@"; if is_empty "$1"; then - return "${_BAD}"; + eval "${return_yes}"; + fi; + _list="$1"; + _element="$2"; + case "$2" in + \'*\') _element="$2"; ;; + *) _element="'$2'"; ;; + esac; + if string_contains "${_list}" "${_element}"; then + eval "${return_no}"; + else + eval "${return_yes}"; + fi; + eval "${return_ok}"; +} + + +######################################################################## +# list_length () +# +# Arguments: 1 +# : a space-separated list of single-quoted elements. +# Output: the number of elements in +# +list_length() +{ + func_check list_length = 1 "$@"; + eval set -- "$1"; + echo -n "$#"; + eval "${return_ok}"; +} + + +######################################################################## +# list_prepend ( ...) +# +# Arguments: >=2 +# : a space-separated list of single-quoted elements. +# : some sequence of characters. +# Output: +# if is empty: "'' ..." +# otherwise: "'' ... " +# +list_prepend() +{ + func_check list_prepend '>=' 2 "$@"; + local _res; + _res="$1"; + shift; + for s in "$@"; do + # escape each single quote. + _element="$(echo -n "$s" | sed -e 's/'\''/&\\&&/g')"; + _res="'${_element}' ${_res}"; + done; + echo -n "${_res}"; + eval "${return_ok}"; +} + +######################################################################## +landmark '7: man_*()'; +######################################################################## + +######################################################################## +# man_do_filespec () +# +# Print suitable man page(s) for filespec to $_TMP_CAT. +# +# Arguments : 2 +# : argument of the form `man:name.section', `man:name', +# `man:name(section)', `name.section', `name'. +# +# Globals : $_OPT_ALL +# +# Output : none. +# Return : `0' if man page was found, `1' else. +# +# Only called from do_fileargs(), checks on $MANPATH and +# $_MAN_ENABLE are assumed. +# +man_do_filespec() +{ + func_check man_do_filespec = 1 "$@"; + local _got_one; + local _name; + local _prevsec; + local _res; + local _section; + local _spec; + local _string; + local s; + if is_empty "${MANPATH}"; then + eval "${return_bad}"; + fi; + if is_empty "$1"; then + eval "${return_bad}"; + fi; + _spec="$1"; + _name=''; + _section=''; + case "${_spec}" in + man:?*\(?*\)) # man:name(section) + _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 + _string="$(string_del_leading "${_spec}" 'man:')"; + _name="$(string_del_trailing "${_string}" '\.[^.]*')"; + _section="$(string_del_leading "${_string}" "${_name}"'\.')"; + ;; + man:?*) # man:name + _name="$(string_del_leading "${_spec}" 'man:')"; + ;; + ?*\(?*\)) # 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}"'\.')"; + ;; + ?*) + _name="${_filespec}"; + ;; + esac; + if is_empty "${_name}"; then + eval "${return_bad}"; + fi; + _got_one='no'; + if is_empty "${_section}"; then + eval set -- "${_MAN_AUTO_SEC}"; + for s in "$@"; do + if man_search_section "${_name}" "$s"; then # found + if is_yes "${_MAN_ALL}"; then + _got_one='yes'; + else + eval "${return_good}"; + fi; + fi; + done; + else + if man_search_section "${_name}" "${_section}"; then + eval "${return_good}"; + else + eval "${return_bad}"; + fi; + fi; + if is_yes "${_MAN_ALL}" && is_yes "${_got_one}"; then + eval "${return_good}"; + fi; + eval "${return_bad}"; +} # man_do_filespec() + + +######################################################################## +# man_register_file ( [
]) +# +# Write a found man page file and register the title element. +# +# Arguments: 1, 2, or 3; maybe empty +# Output: none +# +man_register_file() +{ + func_check man_register_file '>=' 2 "$@"; + case "$#" in + 2|3) do_nothing; ;; + *) + error "man_register_file() expects 2 or 3 arguments."; + ;; + esac; + if is_empty "$1"; then + error 'man_register_file(): file name is empty'; + fi; + to_tmp "$1"; + case "$#" in + 2) + register_title "man:$2"; + eval "${return_ok}"; + ;; + 3) + register_title "$2($3)"; + eval "${return_ok}"; + ;; + esac; + eval "${return_ok}"; +} + + +######################################################################## +# man_search_section (
) +# +# Retrieve man pages. +# +# Arguments : 2 +# Globals : $_MAN_PATH, $_MAN_EXT +# Return : 0 if found, 1 otherwise +# +man_search_section() +{ + func_check man_search_section = 2 "$@"; + local _dir; + local _ext; + local _got_one; + local _name; + local _prefix + local _section; + local d; + local f; + if is_empty "${_MAN_PATH}"; then + eval "${return_bad}"; + fi; + if is_empty "$1"; then + eval "${return_bad}"; fi; if is_empty "$2"; then - return "${_BAD}"; + eval "${return_bad}"; fi; _name="$1"; _section="$2"; @@ -1480,7 +2234,7 @@ man_search_section() man_register_file "$f" "${_name}"; else man_register_file "$f" "${_name}" "${_section}"; - return "${_GOOD}"; + eval "${return_good}"; fi; _got_one='yes'; fi; @@ -1502,7 +2256,7 @@ man_search_section() man_register_file "$f" "${_name}"; else man_register_file "$f" "${_name}" "${_section}"; - return "${_GOOD}"; + eval "${return_good}"; fi; _got_one='yes'; fi; @@ -1523,7 +2277,7 @@ man_search_section() man_register_file "$f" "${_name}"; else man_register_file "$f" "${_name}" "${_section}"; - return "${_GOOD}"; + eval "${return_good}"; fi; _got_one='yes'; fi; @@ -1532,9 +2286,9 @@ man_search_section() done; fi; if is_yes "${_MAN_ALL}" && is_yes "${_got_one}"; then - return "${_GOOD}"; + eval "${return_good}"; fi; - return "${_BAD}"; + eval "${return_bad}"; } # man_search_section() @@ -1562,15 +2316,16 @@ man_search_section() # man_setup() { + func_check main_man_setup = 0 "$@"; local _lang; if is_yes "${_MAN_IS_SETUP}"; then - return "${_GOOD}"; + eval "${return_ok}"; fi; _MAN_IS_SETUP='yes'; if is_not_yes "${_MAN_ENABLE}"; then - return "${_BAD}"; + eval "${return_ok}"; fi; # determine basic path for man pages @@ -1578,7 +2333,7 @@ man_setup() "${_OPT_MANPATH}" "${_MANOPT_PATH}" "${MANPATH}")"; if is_empty "${_MAN_PATH}"; then if is_prog 'manpath'; then - _MAN_PATH="$(manpath 2>/dev/null)"; # not on all systems available + _MAN_PATH="$(manpath 2>/dev/null)"; # not always available fi; fi; if is_empty "${_MAN_PATH}"; then @@ -1588,7 +2343,7 @@ man_setup() fi; if is_empty "${_MAN_PATH}"; then _MAN_ENABLE="no"; - return; + eval "${return_ok}"; fi; _MAN_ALL="$(get_first_essential "${_OPT_ALL}" "${_MANOPT_ALL}")"; @@ -1616,21 +2371,26 @@ man_setup() esac; # from now on, use only $_LANG, forget about $_OPT_LANG, $LC_*. - manpath_add_lang_sys; + manpath_add_lang_sys; # this is very slow _MAN_SEC="$(get_first_essential \ "${_OPT_SECT}" "${_MANOPT_SEC}" "${MANSEC}")"; if is_empty "${_MAN_PATH}"; then _MAN_ENABLE="no"; - return; + eval "${return_ok}"; fi; _MAN_EXT="$(get_first_essential \ "${_OPT_EXTENSION}" "${_MANOPT_EXTENSION}")"; + eval "${return_ok}"; } # man_setup() ######################################################################## +landmark '8: manpath_*()'; +######################################################################## + +######################################################################## # manpath_add_lang_sys () # # Add language and operating system specific directories to man path. @@ -1646,14 +2406,11 @@ man_setup() # manpath_add_lang_sys() { + func_check manpath_add_lang_sys = 0 "$@"; 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}"; + eval "${return_ok}"; fi; # twice test both sys and lang eval set -- "$(path_split "${_MAN_PATH}")"; @@ -1666,6 +2423,7 @@ manpath_add_lang_sys() _mp="$(_manpath_add_lang_sys_single "${_mp}" "$p")"; done; _MAN_PATH="$(path_chop "${_mp}")"; + eval "${return_ok}"; } @@ -1681,11 +2439,10 @@ _manpath_add_lang_sys_single() local d; # if test "$#" -ne 2; then # error "manpath_add_system_single() needs 2 arguments."; -# return "${_ERROR}"; # fi; _res="$1"; _parent="$2"; - eval set -- "$(string_split "${_MAN_SYS}" ',')"; + eval set -- "$(list_from_split "${_MAN_SYS}" ',')"; for d in "$@" "${_MAN_LANG}" "${_MAN_LANG2}"; do _dir="$(dirname_append "${_parent}" "$d")"; if path_not_contains "${_res}" "${_dir}" && is_dir "${_dir}"; then @@ -1714,6 +2471,7 @@ _manpath_add_lang_sys_single() # manpath_set_from_path() { + func_check manpath_set_from_path = 0 "$@"; local _base; local _mandir; local _manpath; @@ -1747,129 +2505,13 @@ manpath_set_from_path() done; _MAN_PATH="${_manpath}"; + eval "${return_ok}"; } # manpath_set_from_path() ######################################################################## -# normalize_args ( +) -# -# Display arguments in the normalized form of GNU `getopt'. -# -# 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 is_yes "${_HAS_OPTS_GNU}"; then - - normalize_args() - { - local _long_opts; - local _short_opts; - local _res; - local i; - if test "$#" -lt 2; then - error "normalize_args() needs at least 2 arguments"; - return "${_ERROR}"; - fi; - _short_opts="$1"; - _long_opts=""; - 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 'normalize_args(): wrong option'; - return "${_ERROR}"; - fi; - } - -elif is_yes "${_HAS_OPTS_POSIX}"; then # POSIX getopts - - normalize_args() - { - local _opt; - local _param; - 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; - OPTIND=1; - OPTARG=""; - OPTERR=0; # set silent mode for getopts - _res=""; - # synopsis: getopts * - 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 is_equal "${_opt}" '?'; then # end of options - # non-option parameters are quoted in the output - _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 test "$#" -gt 0; do - _res="${_res} '$1'"; - shift; - done; - fi; - echo -n "${_res}" - return "${_OK}"; - else - error 'error in option parsing'; - return "${_ERROR}"; - fi; - } - -else - error 'no option processor available.'; - return "${_ERROR}"; -fi; - -# end normalize_args() - +landmark '9: path_*()'; +######################################################################## ######################################################################## # path_chop () @@ -1881,11 +2523,8 @@ fi; # path_chop() { + func_check path_chop = 1 "$@"; local _res; - if test "$#" -ne 1; then - error 'path_chop() needs 1 argument.'; - return "${_ERROR}"; - fi; # _res="$1"; # _res="$(string_flatten "${_res}" ':')"; @@ -1893,9 +2532,10 @@ path_chop() # _res="$(string_del_trailing "${_res}" ':')"; # echo -n "${_res}"; - echo -n "$1" | sed -e '\|::\+|s||:|g' | - sed -e '\|^:*|s|||' | - sed -e '\|:*$|s|||'; + echo -n "$1" | sed -e 's/::\+/:/g' | + sed -e 's/^:*//' | + sed -e 's/:*$//'; + eval "${return_ok}"; } @@ -1909,13 +2549,13 @@ path_chop() # path_clean() { + func_check path_clean = 1 "$@"; local _arg; local _dir; local _res; local i; if test "$#" -ne 1; then error 'path_clean() needs 1 argument.'; - return "${_ERROR}"; fi; _arg="$1"; eval set -- "$(path_split "${_arg}")"; @@ -1931,7 +2571,11 @@ path_clean() esac; fi; done; - path_chop "${_res}"; + if path_chop "${_res}"; then + eval "${return_ok}"; + else + eval "${return_badk}"; + fi; } @@ -1945,14 +2589,16 @@ path_clean() # path_contains() { - if test "$#" -ne 2; then - error "path_contains() needs 2 arguments."; - return "${_ERROR}"; - fi; + func_check path_contains = 2 "$@"; case ":$1:" in - *":$2:"*) return "${_YES}"; ;; - *) return "${_NO}"; ;; + *":$2:"*) + eval "${return_yes}"; + ;; + *) + eval "${return_no}"; + ;; esac; + eval "${return_ok}"; } @@ -1965,15 +2611,13 @@ path_contains() # path_not_contains() { - if test "$#" -ne 2; then - error "path_not_contains() needs 2 arguments."; - return "${_ERROR}"; - fi; + func_check path_not_contains = 2 "$@"; if path_contains "$1" "$2"; then - return "${_NO}"; + eval "${return_no}"; else - return "${_YES}"; + eval "${return_yes}"; fi; + eval "${return_ok}"; } @@ -1983,19 +2627,30 @@ path_not_contains() # In `path' escape white space and replace each colon by a space. # # Arguments: 1: a colon-separated path -# Output: the resulting string +# Output: the resulting list, process with `eval set --' # path_split() { - if test "$#" -ne 1; then - error "path_split() needs 1 argument."; - return "${_ERROR}"; - fi; - string_split "$1" ':'; + func_check path_split = 1 "$@"; + list_from_split "$1" ':'; + eval "${return_ok}"; } ######################################################################## +# reset () +# +# Reset the variables that can be affected by options to their default. +# +# +# Defined in section `Preset' after the rudimentary shell tests. + + +######################################################################## +landmark '10: register_*()'; +######################################################################## + +######################################################################## # register_file () # # Write a found file and register the title element. @@ -2005,13 +2660,9 @@ path_split() # register_file() { - if test "$#" -ne 1; then - error 'register_file() needs 1 argument'; - return "${_ERROR}"; - fi; + func_check register_file = 1 "$@"; if is_empty "$1"; then error 'register_file(): file name is empty'; - return "${_ERROR}"; fi; if is_equal "$1" '-'; then to_tmp "${_TMP_STDIN}"; @@ -2020,6 +2671,7 @@ register_file() to_tmp "$1"; register_title "$(base_name "$1")"; fi; + eval "${return_ok}"; } @@ -2032,21 +2684,19 @@ register_file() # register_title() { + func_check register_title = 1 "$@"; local _title; - if test "$#" -ne 1; then - error "register_title() needs exactly 1 argument."; - return "${_ERROR}"; - fi; if is_empty "$1"; then - return "${_OK}"; + eval "${return_ok}"; fi; _title="$(base_name "$1")"; # remove directory part _title="$(string_del_trailing "${_title}" '\.gz')"; # remove .gz _title="$(string_del_trailing "${_title}" '\.Z')"; # remove .Z if is_empty "${_title}"; then - return "${_OK}"; + eval "${return_ok}"; fi; _REGISTERED_TITLE="${_REGISTERED_TITLE} ${_title}"; + eval "${return_ok}"; } @@ -2057,11 +2707,17 @@ register_title() # save_stdin() { + func_check save_stdin = 0 "$@"; cat | catz - >"${_TMP_STDIN}"; # using `cat' first is safer + eval "${return_ok}"; } ######################################################################## +landmark '11: stack_*()'; +######################################################################## + +######################################################################## # string_contains ( ) # # Test whether `part' is contained in `string'. @@ -2071,14 +2727,16 @@ save_stdin() # string_contains() { - if test "$#" != 2; then - error 'string_contains() needs 2 arguments.'; - return "${_ERROR}"; - fi; + func_check string_contains = 2 "$@"; case "$1" in - *"$2"*) return "${_YES}"; ;; - *) return "${_NO}"; ;; + *"$2"*) + eval "${return_yes}"; + ;; + *) + eval "${return_no}"; + ;; esac; + eval "${return_ok}"; } @@ -2096,17 +2754,17 @@ string_contains() # string_del_append() { - if test "$#" -ne 1; then - error "string_del_append() needs 1 argument."; - return "${_ERROR}"; - fi; + func_check string_del_append = 1 "$@"; case "$1" in *"$_APPEND") echo -n "$1" | sed -e 's/'"$_APPEND"'$//' - return "${_GOOD}"; + eval "${return_good}"; + ;; + *) + eval "${return_bad}"; ;; - *) return "${_BAD}"; ;; esac; + eval "${return_ok}"; } @@ -2123,33 +2781,31 @@ string_del_append() # string_del_leading() { + func_check string_del_leading = 2 "$@"; 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}"; + eval "${return_good}"; else - return "${_BAD}"; + eval "${return_bad}"; fi; fi; if is_empty "${_del}"; then echo -n "${_string}"; - return "${_GOOD}"; + eval "${return_ok}"; fi; _result="$(string_sed_s "${_string}" '^'"${_del}" '')"; echo -n "${_result}"; if is_equal "${_result}" "${_string}"; then - return "${_BAD}"; + eval "${return_bad}"; else - return "${_GOOD}"; + eval "${return_ok}"; fi; + eval "${return_ok}"; } @@ -2166,33 +2822,31 @@ string_del_leading() # string_del_trailing() { + func_check string_del_trailing = 2 "$@"; 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}"; + eval "${return_ok}"; else - return "${_BAD}"; + eval "${return_bad}"; fi; fi; if is_empty "${_del}"; then echo -n "${_string}"; - return "${_GOOD}"; + eval "${return_good}"; fi; _result="$(string_sed_s "${_string}" "${_del}"'$' '')"; echo -n "${_result}"; if is_equal "${_result}" "${_string}"; then - return "${_BAD}"; + eval "${return_bad}"; else - return "${_GOOD}"; + eval "${return_ok}"; fi; + eval "${return_ok}"; } @@ -2209,13 +2863,51 @@ string_del_trailing() # string_flatten() { - if test "$#" -ne 2; then - error "string_flatten() needs 2 arguments."; - return "${_ERROR}"; - fi; + func_check string_flatten = 2 "$@"; _string="$1"; _char="$2"; string_replace_all "${_string}" "${_char}${_char}\+" "${_char}"; + eval "${return_ok}"; +} + + +######################################################################## +# string_get_before ( ) +# +# Get the beginning of , if any. +# +# Arguments: 2 +# : arbitrary sequence of characters. +# : is a BRE like in `sed'; +# Do not worry about the address delimiter, the program escapes them. +# Output: the retrieved string. +# +string_get_before() +{ + func_check string_get_before = 2 "$@"; + local _del; + local _regex; + local _res; + local _string; + if is_empty "$1"; then + if is_empty "$2"; then + eval "${return_ok}"; + else + eval "${return_bad}"; + fi; + fi; + if is_empty "$2"; then + echo -n "$1"; + eval "${return_ok}"; + fi; + _res="$(string_sed_s "$1" "$2"'.*$' '')"; + echo -n "${_res}"; + if is_equal "${_res}" "$1"; then + eval "${return_bad}"; + else + eval "${return_ok}"; + fi; + eval "${return_ok}"; } @@ -2232,33 +2924,31 @@ string_flatten() # string_get_leading() { + func_check string_get_leading = 2 "$@"; 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}"; + eval "${return_ok}"; else - return "${_BAD}"; + eval "${return_bad}"; fi; fi; if is_empty "${_get}"; then echo -n "${_string}"; - return "${_GOOD}"; + eval "${return_ok}"; fi; _result="$(string_sed_s "${_string}" '^\('"${_get}"'\).*$' '\1')"; echo -n "${_result}"; if is_equal "${_result}" "${_string}"; then - return "${_BAD}"; + eval "${return_bad}"; else - return "${_GOOD}"; + eval "${return_ok}"; fi; + eval "${return_ok}"; } @@ -2272,15 +2962,13 @@ string_get_leading() # string_not_contains() { - if test "$#" != 2; then - error 'string_not_contains() needs 2 arguments.'; - return "${_ERROR}"; - fi; + func_check string_not_contains = 2 "$@"; if string_contains "$1" "$2"; then - return "${_NO}"; + eval "${return_no}"; else - return "${_YES}"; + eval "${return_yes}"; fi; + eval "${return_ok}"; } @@ -2299,11 +2987,9 @@ string_not_contains() # string_replace_all() { - if test "$#" -ne 3; then - error "string_replace_all() needs exactly 3 arguments."; - return "${_ERROR}"; - fi; + func_check string_replace_all = 3 "$@"; string_sed_s "$@" 'g'; + eval "${return_ok}"; } @@ -2323,6 +3009,7 @@ string_replace_all() # string_sed_s() { + func_check string_sed_s '>=' 2 "$@"; local _flag; local _regex; local _replace; @@ -2342,20 +3029,19 @@ string_sed_s() ;; *) 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}"; + eval "${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}"\'; + eval sed -e \'s/"${_regex}"/"${_replace}"/"${_flag}"\'; + eval "${return_ok}"; } # string_sed_s() @@ -2371,7 +3057,6 @@ _string_sed_s_esc_slash() local _str; # if test "$#" -ne 1; then # error '_string_sed_s_esc_slash() requires 1 argument.'; -# return "${_ERROR}"; # fi; if is_empty "$1"; then return "${_GOOD}"; @@ -2394,7 +3079,7 @@ _string_sed_s_esc_slash() fi; # split at first bracket. _beginning="$(echo -n "${_rest}" | sed -e '/^\([^[]*\).*$/s//\1/')"; - _rest="$(echo -n "${_rest}" | sed -e '/^[^[]*/s///')"; + _rest="$(echo -n "${_rest}" | sed -e 's/^[^[]*//')"; if is_not_empty "${_beginning}"; then _str="$(_string_sed_s_esc_slash_unbracketed "${_beginning}")"; _result="${_result}${_str}"; @@ -2406,26 +3091,25 @@ _string_sed_s_esc_slash() case "${_rest}" in \[\]*\]*) # `[]...]' construct _bracketed="$(echo -n "${_rest}" | \ - sed -e '/^\(\[\][^]]*\]\).*$/s//\1/')"; + sed -e 's/^\(\[\][^]]*\]\).*$/\1/')"; _rest="$(echo -n "${_rest}" | \ - sed -e '/^\(\[\][^]]*\]\)\(.*\)$/s//\2/')"; + sed -e 's/^\(\[\][^]]*\]\)\(.*\)$/\2/')"; ;; \[^\]*\]*) # `[^]...]' construct _bracketed="$(echo -n "${_rest}" | \ - sed -e '/^\(\[^\][^]]*\]\).*$/s//\1/')"; + sed -e 's/^\(\[^\][^]]*\]\).*$/\1/')"; _rest="$(echo -n "${_rest}" | \ - sed -e '/^\(\[^\][^]]*\]\)\(.*\)$/s//\2/')"; + sed -e 's/^\(\[^\][^]]*\]\)\(.*\)$/\2/')"; ;; \[*\]*) # `[...]' construct _bracketed="$(echo -n "${_rest}" | \ - sed -e '/^\(\[[^]]*\]\).*$/s//\1/')"; + sed -e 's/^\(\[[^]]*\]\).*$/\1/')"; _rest="$(echo -n "${_rest}" | \ - sed -e '/^\(\[[^]]*\]\)\(.*\)$/s//\2/')"; + sed -e 's/^\(\[[^]]*\]\)\(.*\)$/\2/')"; ;; *) error \ '_string_sed_s_esc_slash(): $_rest must start with a bracket'; - return "${_ERROR}"; ;; esac; _result="$(string_del_trailing "${_result}${_bracketed}" \ @@ -2446,11 +3130,9 @@ _string_sed_s_esc_slash_unbracketed() # if test "$#" -ne 1; then # error \ # '_string_sed_s_esc_slash_unbracketed() needs 1 argument).'; -# return "${_ERROR}"; # fi; # if string_contains "$1" '['; then # error "_string_sed_s_esc_slash(): no bracket allowed in argument."; -# return "${_ERROR}"; # fi; case "$1" in */*) @@ -2466,29 +3148,8 @@ _string_sed_s_esc_slash_unbracketed() ######################################################################## -# string_split ( ) -# -# In escape white space and replace each by space. -# -# Arguments: 2: a that is to be split into parts divided by -# -# Output: the resulting string -# -string_split() -{ - if test "$#" -ne 2; then - error "string_split() needs 2 arguments."; - return "${_ERROR}"; - fi; - string_replace_all \ - "$(string_replace_all \ - "$1" \ - '\(['"${_SPACE}${_TAB}"']\)' \ - '\\\1')" \ - "$2" \ - ' '; -} - +landmark '12: tmp_*()'; +######################################################################## ######################################################################## # tmp_cat () @@ -2511,13 +3172,14 @@ tmp_cat() # # Output : name of created file # - tmp_create() { + func_check tmp_create '<=' 1 "$@"; local _tmp; _tmp="${_TMP_PREFIX}${_PROCESS_ID}$1"; echo -n >"${_tmp}"; echo -n "${_tmp}"; + eval "${return_ok}"; } @@ -2528,10 +3190,7 @@ tmp_create() # to_tmp() { - if test "$#" -ne 1; then - error "to_tmp() expects 1 file argument." - return "${_ERROR}"; - fi; + func_check to_tmp = 1 "$@"; if is_file "$1"; then if is_yes "${_OPT_LOCATION}"; then echo2 "$1"; @@ -2543,8 +3202,8 @@ to_tmp() fi; else error "to_tmp(): could not read file \`$1'."; - return "${_ERROR}"; fi; + eval "${return_ok}"; } @@ -2555,6 +3214,7 @@ to_tmp() # usage() { + func_check usage = 0 "$@"; local _header; local _gap; _header="Usage: ${_PROGRAM_NAME}"; @@ -2580,37 +3240,49 @@ All input is decompressed on-the-fly (by gzip). -h --help print this usage message. -Q --source output as roff source. --T --device=name set device for X or tty output. +-T --device=name pass to groff using output device "name". +-X force X mode like in groff; display with "gxditview". -v --version print version information. ---dpi=res set resolution to "res" ("75" or "100" (default)). +-Z --intermediate-output + generate intermediate output without post-processing. + +All other short options are interpreted as "groff" parameters and +transferred unmodified. The most important long options are + +--default-modes=mode1,mode2,... + set sequence of automatically tried modes. +--bg set background color (not for all modes). +--default reset effects of option processing so far. +--display set the X device when displaying in X. +--dpi=res set resolution to "res" ("75" (default) or "100"). +--dvi display in a viewer for TeX device independent format. +--dvi-viewer choose the viewer program for dvi mode. --extension=ext restrict man pages to section suffix. +--fg set foreground color (not for all modes). +--geometry=geom set the window size and position when displaying in X. --local-file same as --no-man. --locale=lang preset the language for man pages. +--location print file locations additionally to standard error. --man check file parameters first whether they are man pages. ---manpath=path preset path for searching man-pages. +--mode=auto|dvi|groff|ps|source|tty|www + choose display mode. +--no-location disable former call to "--location". --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. +--ps display in a Postscript viewer. +--ps-viewer choose the viewer program for ps mode. +--systems=os1,os2,... + search man pages for different operating systems. +--title='text' set the title of the viewer window (not in all modes. --tty force paging on text terminal even when in X. ---xrdb=opt pass "opt" as option to gxditview (several allowed). - -All other short options are interpreted as "groff" parameters and -transferred unmodified. -EOF +--www display in a web browser. +--www-viewer choose the web browser for www mode. +--x display in an X roff viewer. +--x-viewer choose viewer program for x mode. +--xrm='resource' set X resouce. - if is_yes "${_HAS_OPTS_GNU}"; then - cat >&2 <) what_is() { + func_check what_is = 1 "$@"; local _res; local _dot; - if test "$#" -ne 1; then - error "what_is() expects 1 file argument." - return "${_ERROR}"; - fi; if is_not_file "$1"; then error "what_is(): argument is not a readable file." - return "${_ERROR}"; fi; _dot='^\.[ ]*'; echo '.br'; @@ -2662,48 +3330,46 @@ d')"; | sed -e '1,/'"${_dot}"'SH/p d' \ | sed -e '/'"${_dot}"'SH/d'; - return "${_GOOD}"; + eval "${return_ok}"; 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}"; + | sed -e 's/'"${_dot}"'Nd *\(.*\)$/\1/'; + eval "${return_ok}"; fi; echo 'is not a man page.'; - return "${_BAD}"; + eval "${return_bad}"; } ######################################################################## # where () # -# Print path of a program if in $PATH +# Output path of a program if in $PATH. # -# Arguments : 1 (empty allowed) +# Arguments : >=1 (empty allowed) +# more args are ignored, this allows to specify progs with arguments # Return : `0' if arg1 is a program in $PATH, `1' otherwise. # where() { + func_check where '>=' 1 "$@"; local _file; local _arg; local p; - if test "$#" -ne 1; then - error "where() needs 1 argument."; - return "${_ERROR}"; - fi; _arg="$1"; if is_empty "${_arg}"; then - return "${_BAD}"; + eval "${return_bad}"; fi; case "${_arg}" in /*) if test -f "${_arg}" && test -x "${_arg}"; then - return "${_GOOD}"; + eval "${return_ok}"; else - return "${_BAD}"; + eval "${return_bad}"; fi; ;; esac; @@ -2715,10 +3381,10 @@ where() esac; if test -f "${_file}" && test -x "${_file}"; then echo -n "${_file}"; - return "${_GOOD}"; + eval "${return_ok}"; fi; done; - return "${_BAD}"; + eval "${return_bad}"; } @@ -2728,11 +3394,11 @@ where() # The main area contains the following parts: # - main_init(): initialize temporary files and set exit trap +# - parse $MANOPT # - main_parse_args(): argument parsing # - determine display mode -# - setup display mode -# - parse $MANOPT -# - process filespecs +# - process filespec arguments +# - setup X resources # - do the displaying # These parts are implemented as functions, being defined below in the @@ -2746,262 +3412,328 @@ where() # # Globals: $_TMP_CAT, $_TMP_STDIN # +landmark '13: main_init()'; main_init() { + func_check main_init = 0 "$@"; # call clean_up() on any signal trap clean_up 2>/dev/null || true; + for f in ${_CONFFILES}; do + if is_file "$f"; then + . "$f"; + fi; + done; + + # determine temporary directory + for d in "${GROFF_TMPDIR}" "${TMPDIR}" "${TMP}" "${TEMP}" \ + "${TEMPDIR}" "${HOME}"/tmp /tmp "${HOME}" .; + do + if test "$d" != ""; then + if test -d "$d" && test -r "$d" && test -w "$d"; then + _TMP_DIR="$d"; + break; + fi; + fi; + done; + unset d; + if test "${_TMP_DIR}" = ""; then + error "Couldn't find a directory for storing temorary files."; + fi; + _TMP_PREFIX="${_TMP_DIR}/${_PROGRAM_NAME}"; + _TMP_CAT="$(tmp_create)"; _TMP_STDIN="$(tmp_create i)"; -} + eval "${return_ok}"; +} # main_init() + ######################################################################## -# main_parse_args (*) +# main_parse_MANOPT () # -# Parse arguments; process options and filespec parameters +# Parse $MANOPT. # -# Arguments: pass the command line arguments unaltered. # Globals: -# in: $_OPTS_* -# out: $_OPT_*, $_ADDOPTS, $_FILEARGS +# in: $MANOPT, $_OPTS_MAN_* +# out: $_MANOPT_* +# in/out: $GROFFER_OPT # -main_parse_args() +landmark '14: main_parse_MANOPT()'; +main_parse_MANOPT() { - local _arg; - local _code; - local _dpi; - local _longopt; - local _mode; + func_check main_parse_MANOPT = 0 "$@"; 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. - + local _list; + _list=''; + # feed in $MANOPT + eval set -- "$(list_from_cmdline \ + "${_OPTS_MAN_SHORT_NA}" "${_OPTS_MAN_SHORT_ARG}" \ + "${_OPTS_MAN_LONG_NA}" "${_OPTS_MAN_LONG_ARG}" \ + "${MANOPT}")"; until test "$#" -le 0 || is_equal "$1" '--'; do - _opt="$1"; # $_opt is fed into the option handler + _opt="$1"; shift; - - -# 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; + -7|--ascii) + _list="$(list_append "${_list}" '--ascii')"; + ;; + -a|--all) + _list="$(list_append "${_list}" '--all')"; ;; - -P|--to-postproc) # option for postprocessor, arg; - _arg="$1"; + -c|--catman) + do_nothing; shift; - _ADDOPTS_POST="${_ADDOPTS_POST} -P '${_arg}'"; ;; - -Q|--source) # output source code (`Quellcode'). - _OPT_MODE="source"; + -d|--debug) + _list="$(list_append "${_list}" '--debug')"; ;; - -T|--device|--troff-device) - # device; arg - _arg="$1"; + -D|--default) + # undo all man options so far + _list=''; + ;; + -e|--extension) + _list="$(list_append "${_list}" '--extension')"; shift; - _OPT_DEVICE="${_arg}"; ;; - -v|--version) - version; - leave; + -f|--whatis) + _list="$(list_append "${_list}" '--whatis')"; + shift; ;; - -X) - _OPT_MODE="X"; + -h|--help) + do_nothing; + shift; + ;; + -k|--apropos) + _list="$(list_append "${_list}" '--apropos')"; + shift; + ;; + -l|--local-file) + _list="$(list_append "${_list}" '--local-file')"; + ;; + -L|--locale) + _list="$(list_append "${_list}" '--locale' "$1")"; + shift; + ;; + -m|--systems) + _list="$(list_append "${_list}" '--systems' "$1")"; + shift; + ;; + -M|--manpath) + _list="$(list_append "${_list}" '--manpath' "$1")"; + shift; + ;; + -p|--preprocessor) + do_nothing; + shift; + ;; + -P|--pager) + _list="$(list_append "${_list}" '--pager' "$1")"; + shift; + ;; + -r|--prompt) + do_nothing; + shift; + ;; + -S|--sections) + _list="$(list_append "${_list}" '--sections' "$1")"; + shift; + ;; + -t|--troff) + do_nothing; + shift; + ;; + -T|--device) + _list="$(list_append "${_list}" '-T' "$1")"; + shift; + ;; + -u|--update) + do_nothing; + shift; + ;; + -V|--version) + do_nothing; + ;; + -w|--where|--location) + _list="$(list_append "${_list}" '--location')"; + ;; + -Z|--ditroff) + _list="$(list_append "${_list}" '-Z' "$1")"; + shift; + ;; + # ignore all other options + esac; + done; + GROFFER_OPT="$(list_from_lists "${_list}" "${GROFFER_OPT}")"; + eval "${return_ok}"; +} # main_parse_MANOPT() + + +######################################################################## +# main_parse_args (*) +# +# Parse arguments; process options and filespec parameters +# +# Arguments: pass the command line arguments unaltered. +# Globals: +# in: $_OPTS_* +# out: $_OPT_*, $_ADDOPTS, $_FILEARGS +# +landmark '15: main_parse_args()'; +main_parse_args() +{ + func_check main_parse_args '>=' 0 "$@"; + local _arg; + local _code; + local _dpi; + local _longopt; + local _mode; + local _opt; + local _optchar; + local _optarg; + local _opts; + local _string; + + eval set -- "${GROFFER_OPT}" '"$@"'; + + eval set -- "$(list_from_cmdline \ + "$_OPTS_CMDLINE_SHORT_NA" "$_OPTS_CMDLINE_SHORT_ARG" \ + "$_OPTS_CMDLINE_LONG_NA" "$_OPTS_CMDLINE_LONG_ARG" \ + "$@")"; + +# 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; + case "${_opt}" in + -h|--help) + usage; + leave; + ;; + -Q|--source) # output source code (`Quellcode'). + _OPT_MODE='source'; + ;; + -T|--device|--troff-device) + # device; arg + _OPT_DEVICE="$1"; + shift; + ;; + -v|--version) + version; + leave; + ;; + -V) + _OPT_V='yes'; + ;; + -X) + _OPT_X='yes'; ;; -Z|--ditroff|--intermediate-output) # groff intermediate output - _OPT_MODE="intermediate-output"; + _OPT_Z='yes'; ;; -?) _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}"; + if list_has "${_OPTS_GROFF_SHORT_NA}" "${_optchar}"; then - _arg="$1"; - shift; - _ADDOPTS_GROFF="${_ADDOPTS_GROFF} '${_opt}' '${_arg}'"; + _ADDOPTS_GROFF="$(list_append "${_ADDOPTS_GROFF}" \ + "${_opt}")"; + elif list_has "${_OPTS_GROFF_SHORT_ARG}" "${_optchar}"; + then + _ADDOPTS_GROFF="$(list_append "${_ADDOPTS_GROFF}" \ + "${_opt}" "$1")"; + shift; else error "Unknown option : \`$1'"; - return "${_ERROR}"; fi; ;; --all) _OPT_ALL="yes"; ;; + --ascii) + _ADDOPTS_GROFF="$(list_append "${_ADDOPTS_GROFF}" \ + '-mtty-char')"; + ;; --apropos) - _OPT_APROPOS="yes"; - ;; - --bg) # background color for gxditview, arg; - _arg="$1"; + _OPT_APROPOS="yes"; + ;; + --auto) # the default automatic mode + _mode='auto'; + ;; + --bd) # border color for viewers, arg; + _OPT_BD="$1"; + shift; + ;; + --bg|--backgroud) # background color for viewers, arg; + _OPT_BG="$1"; + shift; + ;; + --bw) # border width for viewers, arg; + _OPT_BW="$1"; shift; - _ADDOPTS_X="${_ADDOPTS_X} -P -bg -P '${_arg}'"; + ;; + --default) # reset variables to default + reset; + ;; + --default-modes) # sequence of modes in auto mode; arg + _OPT_DEFAULT_MODES="$1"; + shift; + ;; + --debug) # sequence of modes in auto mode; arg + _OPT_DEBUG='yes'; ;; --display) # set X display, arg - DISPLAY="$1"; - shift; - ;; - --dpi) # set resolution for X devices, arg - _arg="$1"; + _OPT_DISPLAY="$1"; + shift; + ;; + --dvi) + _OPT_MODE='dvi'; + ;; + --dvi-viewer) # viewer program for dvi mode; arg + _OPT_VIEWER_DVI="$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"; + --fg|--foreground) # foreground color for viewers, arg; + _OPT_FG="$1"; shift; - _ADDOPTS_X="${_ADDOPTS_X} -P -fg -P '${_arg}'"; ;; - --geometry) # geometry for gxditview window, arg; - _arg="$1"; + --fn|--font) # set font for viewers, arg; + _OPT_FN="$1"; + shift; + ;; + --geometry) # window geometry for viewers, arg; + _OPT_GEOMETRY="$1"; shift; - _ADDOPTS_X="${_ADDOPTS_X} -P -geometry -P '${_arg}'"; ;; - --lang|--locale) # set language for man pages, arg + --groff) + _OPT_MODE='groff'; + ;; + --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"; + _MAN_FORCE='no'; + _MAN_ENABLE='no'; ;; - --location|where) # print file locations to stderr + --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"; + _MAN_ENABLE='yes'; + _MAN_FORCE='yes'; ;; --manpath) # specify search path for man pages, arg # arg is colon-separated list of directories @@ -3012,21 +3744,29 @@ main_parse_args() _arg="$1"; shift; case "${_arg}" in - auto|default|"") # default - _mode=""; + auto|"") # the default automatic mode + _mode='auto'; + ;; + groff) # pass input to plain groff + _mode='groff'; + ;; + dvi) # display with xdvi viewer + _mode='dvi'; + ;; + ps) # display with Postscript viewer + _mode='ps'; + ;; + X|x) # output on X roff viewer + _mode='x'; ;; - X|tty) # processed output - _mode="${_arg}"; + tty) # output on terminal + _mode='tty'; ;; 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}"; @@ -3043,10 +3783,31 @@ main_parse_args() _OPT_PAGER="$1"; shift; ;; - --PX) # pass option to gxditview, arg; + --ps) + _OPT_MODE='ps'; + ;; + --ps-viewer) # viewer program for ps mode; arg + _OPT_VIEWER_PS="$1"; + shift; + ;; + --resolution) # set resolution for X devices, arg _arg="$1"; shift; - _ADDOPTS_X="${_ADDOPTS_X} -P '${_arg}'"; + case "${_arg}" in + 75|75dpi) + _dpi=75; + ;; + 100|100dpi) + _dpi=100; + ;; + *) + error "only resoutions of 75 or 100 dpi are supported"; + ;; + esac; + _OPT_RESOLUTION="${_dpi}"; + ;; + --rv) + _OPT_RV='yes'; ;; --sections) # specify sections for man pages, arg # arg is colon-separated list of section names @@ -3058,56 +3819,63 @@ main_parse_args() _OPT_SYSTEMS="$1"; shift; ;; - --title) # title for X, arg; OBSOLETE by -P - _arg="$1"; - _ADDOPTS_X="${_ADDOPTS_X} -P -title -P '${_arg}'"; + --title) # title for X viewers; arg + _OPT_TITLE="$1"; shift; ;; --tty) _OPT_MODE="tty"; ;; + --tty-device) # device for tty mode; arg + _OPT_TTY_DEVICE="$1"; + shift; + ;; --whatis) _OPT_WHATIS='yes'; ;; + --www) # display with web browser + _OPT_MODE='www'; + ;; + --www-viewer) # viewer program for www mode; arg + _OPT_VIEWER_WWW="$1"; + shift; + ;; + --x) + _OPT_MODE='x'; + ;; --xrm) # pass X resource string, arg; - _arg="$1"; + _OPT_XRM="$(list_append "${_OPT_XRM}" "$1")"; + shift; + ;; + --x-viewer) # viewer program for x mode; arg + _OPT_VIEWER_X="$1"; shift; - _ADDOPTS_X="${_ADDOPTS_X} -P -xrm -P '${_arg}'"; ;; *) error "error on argument parsing : \`$*'"; - return "${_ERROR}"; ;; esac; done; shift; # remove `--' argument + if test "${_DEBUG}" != 'yes'; then + if test "${_OPT_DEBUG}" = 'yes'; then + _DEBUG='yes'; + fi; + fi; + # Remaining arguments are file names (filespecs). - # Save them to $_FILEARGS + # Save them to list $_FILEARGS if test "$#" -eq 0; then # use "-" for standard input - _FILEARGS="'-'"; + set -- '-'; + fi; + _FILEARGS="$(list_from_args "$@")"; + if list_has "$_FILEARGS" '-'; then save_stdin; - else - if is_yes "${_OPT_APROPOS}"; then - apropos "$@"; - _code="$?"; - clean_up; - exit "${_code}"; - fi; - - _FILEARGS=""; - _stdin_done="no"; - for i in "$@"; do - if is_equal "$1" '-' && is_not_yes "${_stdin_done}"; then - save_stdin; - _stdin_done="yes"; - fi; - _FILEARGS="${_FILEARGS} '$1'"; - shift; - done; fi; - # $_FILEARGS must be retrieved with `eval set -- $_FILEARGS' -} + # $_FILEARGS must be retrieved with `eval set -- "$_FILEARGS"' + eval "${return_ok}"; +} # main_parse_args() ######################################################################## @@ -3119,130 +3887,191 @@ main_parse_args() # in: $DISPLAY, $_OPT_MODE, $_OPT_DEVICE # out: $_DISPLAY_MODE # + +# _get_first_prog () +# +# Retrieve first argument that represents an existing program in $PATH. +# Local function for main_set_mode(). +# +# Arguments: 1; a comma-separated list of commands (with options), +# like $_VIEWER_*. +# +# Return : `1' if none found, `0' if found. +# Output : the argument that succeded. +# +landmark '16: main_set_mode()'; main_set_mode() { + func_check main_set_mode = 0 "$@"; + local m; + local _modes; + local _viewer; + local _viewers; + + # handle apropos + if is_yes "${_OPT_APROPOS}"; then + apropos "$@"; + _code="$?"; + clean_up; + exit "${_code}"; + fi; + + # set display + if is_not_empty "${_OPT_DISPLAY}"; then + DISPLAY="${_OPT_DISPLAY}"; + fi; + + if is_yes "${_OPT_V}"; then + _DISPLAY_MODE='groff'; + _ADDOPTS_GROFF="$(list_append "${_ADDOPTS_GROFF}" '-V')"; + fi; + if is_yes "${_OPT_X}"; then + _DISPLAY_MODE='groff'; + _ADDOPTS_GROFF="$(list_append "${_ADDOPTS_GROFF}" '-X')"; + fi; + if is_yes "${_OPT_Z}"; then + _DISPLAY_MODE='groff'; + _ADDOPTS_GROFF="$(list_append "${_ADDOPTS_GROFF}" '-Z')"; + fi; + if is_equal "${_OPT_MODE}" 'groff'; then + _DISPLAY_MODE='groff'; + fi; + if is_equal "${_DISPLAY_MODE}" 'groff'; then + eval "${return_ok}"; + fi; + + if is_equal "${_DISPLAY_MODE}" 'source'; then + _DISPLAY_MODE="${_OPT_MODE}"; + eval "${return_ok}"; + fi; + case "${_OPT_MODE}" in - source|intermediate-output) - _DISPLAY_MODE="${_OPT_MODE}"; - ;; - X) - if is_empty "${DISPLAY}"; then - error "you must be in X Window for this mode."; - return "${_ERROR}"; - fi; - _DISPLAY_MODE="X"; - ;; - tty) - case "${_OPT_DEVICE}" in - "") - _DISPLAY_MODE="tty"; - ;; - X*) - error "cannot display X device in a text terminal." - return "${_ERROR}"; - ;; - *) - _DISPLAY_MODE="device"; - ;; - esac; - ;; - "") + auto|'') # automatic mode case "${_OPT_DEVICE}" in - "") - if is_empty "${DISPLAY}"; then - _DISPLAY_MODE="tty"; - else - _DISPLAY_MODE="X"; - fi; - ;; X*) if is_empty "${DISPLAY}"; then - error "cannot display X device in a text terminal." - return "${_ERROR}"; - else - _DISPLAY_MODE="X"; + error "no X display found for device ${_OPT_DEVICE}"; fi; - ;; - *) - _DISPLAY_MODE="device"; + _DISPLAY_MODE='x'; + eval "${return_ok}"; ;; esac; + if is_empty "${DISPLAY}"; then + _DISPLAY_MODE='tty'; + eval "${return_ok}"; + fi; + + if is_empty "${_OPT_DEFAULT_MODES}"; then + _modes="${_DEFAULT_MODES}"; + else + _modes="${_OPT_DEFAULT_MODES}"; + fi; + ;; + tty) + _DISPLAY_MODE='tty'; + eval "${return_ok}"; + ;; + *) # display mode was given + if is_empty "${DISPLAY}"; then + error "you must be in X Window for ${_OPT_MODE} mode."; + fi; + _modes="${_OPT_MODE}"; ;; 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"; + # only viewer modes are left + eval set -- "$(list_from_split "${_modes}" ',')"; + while test "$#" -gt 0; do + m="$1"; shift; - case "${_opt}" in - -a|--all) - _MANOPT_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}"; + case "$m" in + tty) + _DISPLAY_MODE='tty'; + eval "${return_ok}"; ;; - -m|--systems) - _arg="$1"; - shift; - _MANOPT_SYS="${_arg}"; - ;; - -M|--manpath) - _arg="$1"; - shift; - _MANOPT_PATH="${_arg}"; + x) + if is_not_empty "${_OPT_VIEWER_X}"; then + _viewers="${_OPT_VIEWER_X}"; + else + _viewers="${_VIEWER_X}"; + fi; + _viewer="$(_get_first_prog "${_viewers}")"; + if test "$?" -ne 0; then + continue; + fi; + _DISPLAY_PROG="${_viewer}"; + _DISPLAY_MODE='x'; + eval "${return_ok}"; ;; - -P|--pager) - _arg="$1"; - shift; - _MANOPT_PAGER="${_arg}"; + dvi) + if is_not_empty "${_OPT_VIEWER_DVI}"; then + _viewers="${_OPT_VIEWER_DVI}"; + else + _viewers="${_VIEWER_DVI}"; + fi; + _viewer="$(_get_first_prog "${_viewers}")"; + if test "$?" -ne 0; then + continue; + fi; + _DISPLAY_PROG="${_viewer}"; + _DISPLAY_MODE="dvi"; + eval "${return_ok}"; ;; - -S|--sections) - _arg="$1"; - shift; - _MANOPT_SEC="${_arg}"; + ps) + if is_not_empty "${_OPT_VIEWER_PS}"; then + _viewers="${_OPT_VIEWER_PS}"; + else + _viewers="${_VIEWER_PS}"; + fi; + _viewer="$(_get_first_prog "${_viewers}")"; + if test "$?" -ne 0; then + continue; + fi; + _DISPLAY_PROG="${_viewer}"; + _DISPLAY_MODE="ps"; + eval "${return_ok}"; ;; - -w|--where|--location) - _OPT_LOCATION='yes'; + www) + if is_not_empty "${_OPT_VIEWER_WWW}"; then + _viewers="${_OPT_VIEWER_WWW}"; + else + _viewers="${_VIEWER_WWW}"; + fi; + _viewer="$(_get_first_prog "${_viewers}")"; + if test "$?" -ne 0; then + continue; + fi; + _DISPLAY_PROG="${_viewer}"; + _DISPLAY_MODE="www"; + eval "${return_ok}"; ;; - # ignore all other options - esac - done + esac; + done; + error "no suitable display mode found."; } +_get_first_prog() +{ + local i; + if test "$#" -eq 0; then + error "_get_first_prog() needs 1 argument."; + fi; + if is_empty "$1"; then + return "${_BAD}"; + fi; + eval set -- "$(list_from_split "$1" ',')"; + for i in "$@"; do + if is_empty "$i"; then + continue; + fi; + if is_prog "$(get_first_essential $i)"; then + echo -n "$i"; + return "${_GOOD}"; + fi; + done; + return "${_BAD}"; +} # main_set_mode() + ####################################################################### # main_do_fileargs () @@ -3252,62 +4081,184 @@ main_parse_MANOPT() # Globals: # in: $_FILEARGS (process with `eval set -- "$_FILEARGS"') # +landmark '17: main_do_fileargs()'; main_do_fileargs() { + func_check main_do_fileargs = 0 "$@"; + local _exitcode; local _filespec; local _name; - local _ok; - local _sec; + _exitcode="${_BAD}"; eval set -- "${_FILEARGS}"; unset _FILEARGS; # temporary storage of all input to $_TMP_CAT - while test "$#" -gt 0; do + while test "$#" -ge 2; do # test for `s name' arguments, with `s' a 1-char standard section - while true; do # `break' means not such an s - if test "$#" -le 0; then - break; - fi; - _filespec="$1"; - shift; - case "${_filespec}" in - '') continue; ;; - '-') - register_file '-'; - continue; - ;; - ?) - if test "$#" -le 0; then - break; - fi; - _sec="${_filespec}"; - if string_not_contains "${_MAN_AUTO_SEC}" "${_sec}"; then - break; + _filespec="$1"; + shift; + case "${_filespec}" in + '') + continue; + ;; + '-') + if register_file '-'; then + _exitcode="${_GOOD}"; + fi; + continue; + ;; + ?) + if list_has_not "${_MAN_AUTO_SEC}" "${_filespec}"; then + if do_filearg "${_filespec}"; then + _exitcode="${_GOOD}"; fi; - _name="$1"; - case "${_name}" in - */*) break; ;; - man:*) break; ;; - *\(*\)) break; ;; - *."${_sec}") break; ;; - esac; - if do_filearg "man:${_name}(${_sec})"; then + continue; + fi; + _name="$1"; + case "${_name}" in + */*|man:*|*\(*\)|*."${_filespec}") + if do_filearg "${_filespec}"; then + _exitcode="${_GOOD}"; + fi; continue; - else - break; + ;; + esac; + if do_filearg "man:${_name}(${_filespec})"; then + _exitcode="${_GOOD}"; + shift; + continue; + else + if do_filearg "${_filespec}"; then + _exitcode="${_GOOD}"; fi; - ;; - *) break; ;; - esac; - done; # end of `s name' test - do_filearg "${_filespec}"; - if test "$?" != "${_GOOD}"; then - warning "\`${_filespec}' is neither a file nor a man-page."; - fi; - if test "$#" -eq 0; then - return "$_OK"; + continue; + fi; + ;; + *) + if do_filearg "${_filespec}"; then + _exitcode="${_GOOD}"; + fi; + continue; + ;; + esac; + done; # end of `s name' test + while test "$#" -gt 0; do + _filespec="$1"; + shift; + if do_filearg "${_filespec}"; then + _exitcode="${_GOOD}"; fi; done; -} + clean_up_secondary; + if is_equal "${_exitcode}" "${_BAD}"; then + eval "${return_bad}"; + fi; + eval "${return_ok}"; +} # main_do_fileargs() + + +######################################################################## +# main_set_resources () +# +# Determine options for setting X resources with $_DISPLAY_PROG. +# +landmark '18: main_set_resources()'; +main_set_resources() +{ + func_check main_set_resources = 0 "$@"; + local _prog; # viewer program + local _rl; # resource list + _rl=''; + if is_empty "${_DISPLAY_PROG}"; then + eval "${return_ok}"; + fi; + set -- ${_DISPLAY_PROG}; + _prog="$(base_name "$1")"; + if is_not_empty "${_OPT_BD}"; then + case "${_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + _rl="$(list_append "$_rl" '-bd' "${_OPT_BD}")"; + ;; + esac; + fi; + if is_not_empty "${_OPT_BG}"; then + case "${_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + _rl="$(list_append "$_rl" '-bg' "${_OPT_BG}")"; + ;; + esac; + fi; + if is_not_empty "${_OPT_BW}"; then + case "${_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + _rl="$(list_append "$_rl" '-bw' "${_OPT_BW}")"; + ;; + esac; + fi; + if is_not_empty "${_OPT_FG}"; then + case "${_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + _rl="$(list_append "$_rl" '-fg' "${_OPT_FG}")"; + ;; + esac; + fi; + if is_not_empty "${_OPT_FN}"; then + case "${_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + _rl="$(list_append "$_rl" '-fn' "${_OPT_FN}")"; + ;; + esac; + fi; + if is_not_empty "${_OPT_GEOMETRY}"; then + case "${_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + _rl="$(list_append "$_rl" '-geometry' "${_OPT_GEOMETRY}")"; + ;; + esac; + fi; + if is_empty "${_OPT_RESOLUTION}"; then + case "${_prog}" in + gxditview|xditview) + _rl="$(list_append "$_rl" \ + '-resolution' "${_DEFAULT_RESOLUTION}")"; + ;; + esac; + else + case "${_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + _rl="$(list_append "$_rl" '-resolution' "${_OPT_RESOLUTION}")"; + ;; + esac; + fi; + if is_not_empty "${_OPT_RV}"; then + case "${_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + _rl="$(list_append "$_rl" '-rv')"; + ;; + esac; + fi; + if is_not_empty "${_OPT_XRM}"; then + case "${_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + eval set -- "{$_OPT_XRM}"; + for i in "$@"; do + _rl="$(list_append "$_rl" '-xrm' "$i")"; + done; + ;; + esac; + fi; + _title="$(get_first_essential \ + "${_OPT_TITLE}" "${_REGISTERED_TITLE}")"; + if is_not_empty "${_title}"; then + case "${_prog}" in + gxditview|xditview) + _rl="$(list_append "$_rl" '-title' "${_title}")"; + ;; + esac; + fi; + _DISPLAY_ARGS="${_rl}"; + eval "${return_ok}"; +} # main_set_resources + ######################################################################## # main_display () @@ -3320,88 +4271,163 @@ main_do_fileargs() # $_REGISTERED_TITLE, $_TMP_PREFIX, $_TMP_CAT, # $_OPT_PAGER $PAGER $_MANOPT_PAGER # +landmark '19: main_display()'; main_display() { + func_check main_display = 0 "$@"; + local p; local _addopts; - local _options; + local _device; local _groggy; - local _title; - local _old_tmp; + local _modefile; + local _options; local _pager; + local _title; export _addopts; export _groggy; - local p; + export _modefile; case "${_DISPLAY_MODE}" in - source) - tmp_cat; - clean_up; - ;; - intermediate-output) - _options="-Z"; + groff) + _ADDOPTS_GROFF="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}"; if is_not_empty "${_OPT_DEVICE}"; then - _options="${_options} -T'${_OPT_DEVICE}'"; + _ADDOPTS_GROFF="${_ADDOPTS_GROFF} -T${_OPT_DEVICE}"; fi; - - _groggy="$(eval grog "${_options}" "${_ADDOPTS_GROFF}" \ - "${_TMP_CAT}" )"; _groggy="$(tmp_cat | eval grog "${_options}")"; - tmp_cat | eval "${_groggy}" "${_ADDOPTS_GROFF}"; - clean_up; - ;; - device) - _groggy="$(tmp_cat | grog -T"${_OPT_DEVICE}")"; - tmp_cat | eval "${_groggy}" "${_ADDOPTS_GROFF}"; - clean_up; - ;; - 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_not_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}"; + _modefile="${_TMP_DIR}/${_PROGRAM_NAME}${_PROCESS_ID}"; + rm -f "${_modefile}"; + mv "${_TMP_CAT}" "${_modefile}"; rm -f "${_TMP_CAT}"; - mv "${_old_tmp}" "${_TMP_CAT}"; - cat "${_TMP_CAT}" | \ + cat "${_modefile}" | \ ( clean_up() { - rm -f "${_TMP_CAT}"; + rm -f "${_modefile}"; } trap clean_up EXIT 2>/dev/null || true; - eval "${_groggy}" "${_addopts}"; + eval "${_groggy}" "${_ADDOPTS_GROFF}"; ) &' ;; tty) + case "${_OPT_DEVICE}" in + '') + _device="$(get_first_essential \ + "${_OPT_TTY_DEVICE}" "${_DEFAULT_TTY_DEVICE}")"; + ;; + ascii|cp1047|latin1|utf8) + _device="${_OPT_DEVICE}"; + ;; + *) + warning \ + "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; + ;; + esac; _addopts="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}"; - _groggy="$(tmp_cat | grog -Tlatin1)"; - _pager=""; -# TODO ? - for p in "${_OPT_PAGER}" "${PAGER}" "less" "${_MANOPT_PAGER}"; do + _groggy="$(tmp_cat | grog -T${_device})"; + _pager=''; + for p in "${_OPT_PAGER}" "${PAGER}" "${_MANOPT_PAGER}" \ + 'less' 'more' 'cat'; do if is_prog "$p"; then _pager="$p"; break; fi; done; + if is_empty "${_pager}"; then + error 'no pager program found for tty mode'; + fi; tmp_cat | eval "${_groggy}" "${_addopts}" | \ eval "${_pager}"; clean_up; ;; - *) + + #### viewer modes + + dvi) + case "${_OPT_DEVICE}" in + dvi) do_nothing; ;; + *) + warning \ + "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; + ;; + esac; + _groggy="$(tmp_cat | grog -Tdvi)"; + _do_display; + ;; + ps) + case "${_OPT_DEVICE}" in + ''|ps) + do_nothing; + ;; + *) + warning \ + "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; + ;; + esac; + _groggy="$(tmp_cat | grog -Tps)"; + _do_display; + ;; + source) + tmp_cat; clean_up; ;; + www) + case "${_OPT_DEVICE}" in + ''|html) do_nothing; ;; + *) + warning \ + "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; + ;; + esac; + _groggy="$(tmp_cat | grog -Thtml)"; + _do_display; + ;; + x) + case "${_OPT_DEVICE}" in + '') + _groggy="$(tmp_cat | grog -Z)"; + ;; + X*|ps) + _groggy="$(tmp_cat | grog -T"${_OPT_DEVICE}" -Z)"; + ;; + *) + warning \ + "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; + _groggy="$(tmp_cat | grog -Z)"; + ;; + esac; + _do_display; + ;; + *) + error "unknown mode \`${_DISPLAY_MODE}'"; + ;; esac; + eval "${return_ok}"; +} # main_display() + +_do_display() +{ + trap "" EXIT 2>/dev/null || true; + # start a new shell program to get another process ID. + sh -c ' + set -e; + _PROCESS_ID="$$"; + _modefile="${_TMP_DIR}/${_PROGRAM_NAME}${_PROCESS_ID}"; + rm -f "${_modefile}"; + cat "${_TMP_CAT}" | \ + eval "${_groggy}" "${_ADDOPTS_GROFF}" > "${_modefile}"; + rm -f "${_TMP_CAT}"; + ( + clean_up() + { + rm -f "${_modefile}"; + } + trap clean_up EXIT 2>/dev/null || true; + eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "${_modefile}"; + ) &' } @@ -3414,13 +4440,20 @@ main_display() # main() { + func_check main '>=' 0 "$@"; # Do not change the sequence of the following functions! main_init; + main_parse_MANOPT; main_parse_args "$@"; main_set_mode; - main_parse_MANOPT; main_do_fileargs; + main_set_resources; main_display; + eval "${return_ok}"; } +landmark '20: end of function definitions'; + +######################################################################## + main "$@"; -- 2.11.4.GIT