diff -ruN groff-1.18.1.1/ChangeLog groff-1.18.1.2/ChangeLog --- groff-1.18.1.1/ChangeLog 2002-10-08 09:12:41.000000000 +0200 +++ groff-1.18.1.2/ChangeLog 2006-10-04 06:01:22.000000000 +0200 @@ -1,5 +1,22 @@ +2006-10-04 Werner LEMBERG + +Version 1.18.1.2 released +========================= + + * NEWS: Updated. + +2004-06-19 Werner LEMBERG + +Version 1.18.1.1 released +========================= + + * NEWS: Updated. + 2002-10-08 Werner LEMBERG +Version 1.18.1 released +======================= + * doc/webpage.ms, NEWS: Updated. 2002-10-07 Werner LEMBERG diff -ruN groff-1.18.1.1/contrib/groffer/ChangeLog groff-1.18.1.2/contrib/groffer/ChangeLog --- groff-1.18.1.1/contrib/groffer/ChangeLog 2004-06-15 03:45:11.000000000 +0200 +++ groff-1.18.1.2/contrib/groffer/ChangeLog 2006-09-26 23:24:06.000000000 +0200 @@ -1,3 +1,1182 @@ +2006-09-26 Bernd Warken + ________________________________________________________________ + * release of groffer 0.9.27 + + * Makefile.sub: Add Emacs setting at the end of the file. + + * TODO: Remove this file because it does not contain any actual + entries. + + * groffer2.sh: + - main_set_mode(): Remove too early test of modes on X. Fix pdf + mode. + - where_is_prog(): Fix this function to detect files in the + current directory. + - _get_prog_args() of main_set_mode(): Fix return; + - _get_first_prog() of main_set_mode(): Fix call of exit_test(). + - cat_z(): Make it a single function and add file test. + - whatis_setup(): Rename whatis_header(). Fix display title to + `whatis'. + - apropos_setup(): Fix display title to `apropos'. + - Globals: Fix this section in the description of several + functions. + - apropos_filespec(): Fix variable $s and the corresponding sed + call. + - man_setup(): Add $EXTENSION. + - _do_man_so() of to_tmp(): Fix variables. + - $_ALL_EXIT: Remove unused variable. + - $_TITLE_ELT: Remove unused variable. + - man_set_resources(): Fix setting of $_DISPLAY_ARGS. + - main_display(): Fix description. Remove $md_options. Let + $MANOPT override system variables. + +2006-09-16 Bernd Warken + ________________________________________________________________ + * release of groffer 0.9.26 + + ### Simplification of main_set_mode() + + * groffer2.sh: + - _get_first_prog() of main_set_mode(): Rewrite this function + such that it does not have an output, but set the variables + $_DISPLAY_PROG and $_DISPLAY_ARGS. + - _check_prog_on_list() of main_set_mode(): Rename and rewrite + _check_X_prog(). Suitable for being called for $_VIEWER__X + and $_VIEWER__TTY. No output, but set the variables + $_DISPLAY_PROG and $_DISPLAY_ARGS. + - _obj_set_vars() of main_set_mode(): Remove this function. It is + no longer necessary because its variables are set by the other + functions. + - _get_prog_args() of main_set_mode(): New function that + simplifies the loop in main_set_mode() and handles both + $_VIEWER__X and $_VIEWER__TTY. + - _process_mode() of main_set_mode(): Remove this function. + - main_set_mode(): Remove case for calling _process_mode(). In + the loop, use _get_prog_args() for simplification. + - main_parse_args(): Make ---viewer equivalent to + ---viewer-tty to make _process_mode() unnecessary. + - $_VIEWER_BACKGROUND: Start with `no'. + + ### Extend the documentation + + * groffer2.sh: + - Environment Variables: Add information on the naming of + variables in functions. + - $_ADDOPTS_POST, $_ADDOPTS_X: Remove these unused variables. + - apropos_setup(), apropos_setup (), base_name(), dir_name(), + echo1(), echo2(), func_check(), func_pop(), func_push(), + is_greater_than(), list_append(), list_from_split(), + _manpath_add_sys() of manpath_add_lang_sys(), rm_tree(), + special_filespec(), special_setup(), tmp_create(), to_tmp_line(), + usage(), version(), where_is_prog(), main_set_mode(): + Fix and extend the description. Many other function descriptions + were just fixed without being mentioned. + - landmark 7: man_*(): Add information on the search of `man' + pages. + + * groffer.man: + - GNU `man' option overview: Add --location, --no-location, and + --where. + - GNU `man' options: Add the GNU `man' long options that are + accepted by `groffer', but just ignored. + - MAN PAGE SEARCHING: Correct and extend this section. + + * TODO: + - Remove entry on function headers. + - Remove entry on GNU `man' options. + - Remove entry on search algorithm for `man' pages. + + ### Other fixes + + * groffer2.sh: + - man_get(): On `man' page search with given name and section + handle also files with extension when no files without extension + are found. + +2006-09-11 Bernd Warken + ________________________________________________________________ + * release of groffer 0.9.25 + + ### Version information + + * groffer2.sh: + - version(): Add groffer to the version information; replace the + call of `groff --version'. + + ### Configuration Files + + * groffer.sh: Fix the configuration handling by removing all + quotes. Arguments are ended by the end of the line. + + * groffer.man: Fix the section on the configuration files. + + ### Options + + * groffer2.sh: + - $_OPTS_GROFF_SHORT_NA: Add `-k' as new groff option. + - main_pars_args(): Add X options `--ft', `--bordercolor', + `--borderwidth'. + - usage(): Add `--debug-filenames'. Remove `*-viewer-tty'. + Correct first line after call of version(). + - main_parse_MANOPT(): Fix `-h', `-t', and `-u' as options without + argument. + + * groffer.man: + - Add documentation to `--fn', `--ft', `--bordercolor', + `--borderwidth'. + - Remove the `--*-viewer-tty' options. These options are still + supported by the groffer program, but they aren't needed any + more. + + ### soelim: Allow manpath and compressed files in .so requests, as + ### man does. + + * groffer2.sh: + - $_FILESPEC_IS_MAN: New variable for storing if a filespec is for + searching a man page. + - to_tmp(): Rewrite. For existing file as filespec argument, add + call of `soelim' with the corresponding `-I dir' before the call + of `grog'. For man paged, uncompress and store the files from .so + requests; replace the requests with the stored file names. + - _do_man_so() of to_tmp(): New function to handle the file of a + .so request. + - man_get(): For man pages without extension, add special search + strategy. + + * README: Add the .so handling to the Compatiblity section. + + ### Print file names debug + + * groffer2.sh: + - $_OPT_LOCATION: Replace this variable by + $_DEBUG_PRINT_FILENAMES. + - register_file(): Move file name printing and call to basename to + register_title(). + - _do_man_so() of to_tmp(): Add file name printing for man pages. + + ### modes + + * groffer2.sh: + - $_DEFAULT_MODES: New set of default modes in the sequence 'pdf', + 'html', 'ps', 'x', 'dvi', and 'tty'. That is done because the `x' + mode viewers `gxditview' and `xditview' are very bad programs. + - _make_pdf() of main_display(): If pdf format can not be + generated use Postscript mode (ps) instead for display. + - $_PDF_DID_NOT_WORK, $_PDF_HAS_PS2PDF, $_PDF_HAS_GS: New + variables for pdf mode to avoid several runs. + - $_VIEWER_TTY_TTY, $_VIEWER_TTY_X: Add these variables for the + viewers in tty mode. + - main_display(): Rewrite tty mode by using where_is_prog() to add + options to `less' from the command line. + + * groffer.man: + - Add this information. + - Adjust the viewers in `SEE ALSO'. + + ### Check viewer option for programs running in X Window + + * groffer2.sh: + - _check_X_prog() of main_set_mode(): New function for checking if + a program of a command line argument is in the list for X for this + mode. + - _get_first_prog() of main_set_mode(): Use where_is_prog(); + change the output to the same 3-element list as _check_X_prog(). + - _obj_set_vars() of main_set_mode(): New function for setting + some variables in several modes. Argument is the 3-element list + from _check_X_prog() or _get_first_prog(). + - _process_mode() of main_set_mode(): Remove part with + list_has_not_prog(). This is better done by _check_X_prog(). + - main_set_mode(): Use _check_X_prog() in different modes. + Correct several modes. Add reset of $_VIEWER_BACKGROUND at the + beginning of the loop of default modes. + + ### Allow man pages with space characters + + * groffer2.sh: + - man_is_man(): Fix grep calls. + - list_from_file(): New function that reads the lines of a file as + list elements. + - man_get(): Fix `case' applications by double-quoting all + variables. Use list_from_file() instead of setting with `cat'. + Add further tests. + - _do_man_so() of to_tmp(): Use list_from_file() instead of + setting with `cat'. + + ### Allow program names with space + + * groffer2.sh: + - is_prog(), is_not_program(): Change to exactly one argument with + possible spaces and arguments. Fix all calls. + - where_is_prog(): Change to exactly one argument. Change + variable prefix to `wip'. Rewrite it to support programs with + spaces and arguments. Return a list with 3 elements: the + program's directory, the program name, and the given arguments. + - main_display(): Correct tty mode. + + ### Further fixes + + * groffer2.sh: + - main_setup(): Fix func_check. + - clean_up(): Add variable to avoid several prints. + - where_is_prog(): Remove possible arguments from program + argument. + - obj_from_output(): As return value take the return value of the + called function. + - is_not_empty(): Rename of is_non_emtpy(). + - $_VIEWER_BACKGROUND: Rename $_VIEWER_TERMINAL and reverse its + values. + - list_has_prog(), list_has_not_prog(): Remove these functions, + they are no longer needed. + + * groffer.man: + - Add `--print' in OPTION OVERVIEW. + - Correct many entries with the non-breaking `\%' construct. + +2006-07-28 Bernd Warken + ________________________________________________________________ + * release of groffer 0.9.24 + + ### Extent long option abbreviation to abbreviations before each `-'. + + * groffer2.sh: + - list_from_cmdline_with_minus(): New function, the same as + list_from_cmdline() with multiple abbreviations around `-'. + - _search_abbrev(): Subfunction of list_from_cmdline_with_minus(). + - main_parse_args(): Use list_from_cmdline_with_minus() for + getting the double abbreviation, but keep main_parse_MANOPT() + to list_from_cmdline() for simple abbreviation of long options. + - For the debug test at the beginning, add the double abbreviation + functionality. + + * README_SH, groffer.man: Document the multiple set of + abbreviations by `-'. + + ### Fix handling of `--apropos*' and `--whatis' + + * groffer2.sh: + - apropos_filespec(): Fix handling of `/' and `.' in sed; add `\&' + at the beginning of each non-macro groff line in sed. + - main_parse_args(): Set $_MAN_OPT to `yes' if --whatis is called. + - main_do_fileargs(): Fix dealing with `apropos' for several + cases. + - apropos_*(), special_*(), whatis_*(): Add two different return + values. + - $_SPECIAL_SETUP: New variable to test whether apropos_setup() or + whatis_header() had been run. + - Add language locale to --whatis, the `whatis' program does not + support this. + + ### Handle several macro packages + + * groffer2.sh: + - $_MACROS: New variable to store the actual macro package. + - $_MACRO_PACKAGES: New variable for the full macro packages of + groff (man, mdoc, me, mm, mom, ms). + - to_tmp(): Add test for different macro packages. Ignore files + with a different one. + - main_do_fileargs(): Add different macro check before doing man + pages. + + ### Rewrite the man page search + + * groffer2.sh: + - $_MAN_SEC_CHARS, $_MAN_SEC_LIST: New variables from $_MAN_SEC. + Add these to man_setup(). + - man_get(): New function that finally gets the man page or man + pages for a filespec. Avoid double files. + - man_is_man(): New function that checks whether a name goes as + man page. + - manpath_add_lang_sys(): Fix handling of language addition for + short language names. + - main_parse_args(): Move handling of `-' to main_do_fileargs(). + - do_filearg(), man_do_filespec(), man_register_file(), + man_search_section(): Remove these functions. + - main_do_fileargs(): Rewrite this function together with + the removed functions. + - list_uniq(): New function to remove the multiple elements from a + list. + + ### Version handling. + + * version.sh: New file for $_PROGRAM_VERSION, $_LAST_UPDATE, and + $_GROFF_VERSION_PRESET. + + * groffer.sh: + - Add running of version.sh with `.'. + - Remove $_PROGRAM_VERSION and $_LAST_UPDATE. + - Run groffer2.sh with `.' instead of `exec'. This allows to have + groffer2.sh without executive access permission. + - Determine $_BEFORE_MAKE by @VERSION@, use this variable on more + places. + + * groffer2.sh: + - Remove executive access permission. + - version(): Write a version information without calling groff. + + * Makefile.sub: + - Add version.sh. Use $(INSTALL_DATA) instead of + $(INSTALL_SCRIPT) for version.sh and groffer2.sh. + - Add $(DESTDIR) to some elements of `sed' call in `groffer:'. + + ### viewers for different modes + + * groffer2.sh: + - $_VIEWER_HTML_X: Add `epiphany' as browser. + - $_VIEWER_PDF_X: Add `kpdf' and `evince' as pdf viewer for X. + Make `kpdf', `acroread', `evince', and `xpdf' the first automatic + pdf viewers for X because they support searching. Add `gpdf'. + - $_VIEWER_PS_X: Add `kpdf' and `evince' as ps viewer for X; make + `kpdf' the first automatic ps viewer for X because it supports + searching even for Postscript. + + ### pdf mode + + * groffer2.sh: + - _make_pdf() of main_display(): add `ps2pdf' as secondary + transformer. + - main_set_resources(): Allow setting of resolution for `xpdf' + only if option -z is not set for `xpdf'. + + ### Revise $_VIEWER_* + + * groffer2.sh: + - $_VIEWER__TTY: Add this variable to each mode even if it + is only empty. + - $_VIEWER__X: Rename $_VIEWER_ to this for each + mode. + + ### Other fixes + + * groffer2.sh: + - is_empty_file(): New function. + - obj_from_output(): Quote arguments by building a list. + - path_list(): Output path list with unique elements. + - where_is_prog(): Rename where_is(). Handle all file names + having a slash somewhere instead of only those that start with a + slash. + - $_REG_TITLE_LIST: Replace $_REGISTERED_TITLE and make it a + list. + - $_OPT_TITLE: Make it a list with at most 1 element. + - Remove double quotes in case patterns. + - _func_test(): For the function test at the beginning, add this + function for output check with $() construct. + - usage(): Add --shell. + - $_VIEWER_HTML_X: Add `firefox' and `mosaic'. + - list_get(): Remove this unused function. + - Fix func_check() calls in all functions. + + * groffer.sh: Adjust groff version to 19.3. + + * README: Add information list of the source files. + +2006-02-26 Claudio Fontana + + * Makefile.sub: Add DESTDIR to install and uninstall targets + to support staged installations. + +2005-09-14 Bernd Warken + ________________________________________________________________ + * release of groffer 0.9.23 + + ### Increase the speed for the search of man pages + + Run `find' on all man directories and ask this with `grep' instead + of scanning through many `ls'. + + * groffer2.sh: + - $_TMP_MAN: New variable with the name of the file that stores + the `find' of the man path. + - $_TMP_MANSPEC: New variable with the name of the file that + stores the man page file names for each filespec. + - man_setup(): Do the `find' of the man path with $_TMP_MAN. + - man_do_filespec(): Add creation of $_TMP_MANSPEC. + - man_search_section(): Rewrite it to use $_TMP_MANSPEC. + + * TODO: The demand on the increase of speed for man pages is now + removed. + + ### Increase speed by enhancement of debug + + * groffer.sh: $_BEFORE_MAKE: New variable that stores whether the + @...@ constructs are still available or already transformed by + `make'. + + * groffer2.sh: + - $_DEBUG_FUNC_CHECK: New debug variable that regulates the check + calls at the beginning and end of most functions done by the + functions func_(). By default, this is enabled before the + run of `make', and disabled after. $_DEBUG_STACKS and + $_DEBUG_USER_WITH_STACK enable this variable automatically. + - --debug-func: New option for setting $_DEBUG_FUNC_CHECK. + - usage(), main_parse_args(): Add information for --debug-func. + - func_(): Disable these functions if $_DEBUG_FUNC_CHECK is + not `yes'. + + * groffer.man: + - Add information on --debug-func. + - Move the sections on options for development to the end of + option processing. + + ### Fixes of man page search + + - man_search_section(): Repair it such that extensions do not + occur in the directory name. + - manpath_set_from_path(): Rewrite it. Add `.../MAN/...' + subdirectories additionally to `.../man/...'. + - manpath_add_lang_sys(): Rewrite it to overwrite _MAN_PATH by + systems parameter if any. Then _MAN_PATH is prepended by the + language part. + - _manpath_add_sys(): New subfunction of manpath_add_lang_sys() to + handle the sytems part. + - man_search_section: Fix it to handle section names that have + more than one character (an extension). + - $_MAN_PATH: Now stores man path as a list. This is done in + man_setup() and manpath_set_from_path(), and used in + manpath_add_lang_sys(). + - $_MAN_SYS: Now stores man systems parameter as a list. This is + done in man_setup() and used in manpath_add_lang_sys(). + - $_MAN_SEC_DONE, $_MAN_SYS_DONE, $_MAN_LANG_DONE: Remove these + variables. + + ### Reorder the beginning of groffer2.sh + + * groffer2.sh: + - func_(): Move these functions to the functions in + alphabetical order. + - main_init(): Move "Test for compression" to this function. + - Move the "System Test" and function landmark() to the beginning + "Test of rudimentary shell functionality". Change landmarks 1 and + 2 to new positions. + + ### Fix the mode when not in X + + * groffer2.sh: + - main_parse_args(): Accept modes even when not in X, hoping for a + program given by option. Add $_OPT_VIEWER__TTY. Remove + $_VIEWER_TERMINAL. + - main_set_mode(): Add a section to set $_VIEWER_TERMINAL and move + the value of $_OPT_VIEWER__TTY to $_OPT_VIEWER_. When + not in X and no terminal programs are set remove $_OPT_MODE. All + unknown programs are treated as terminal programs. + - usage(): Comment out options ---viewer-tty. They exist + and are handled by `groffer', but they are no longer documented. + - $_OPT_VIEWER__TTY: New variables for option + ---viewer-tty. + - $_DEFAULT_MODE, $_VIEWER_: Change it from , separation to + a list. Rewrite _get_first_prog() of main_set_mode() to get + around with this. + + * groffer.man: Remove information on ---viewer-tty. + + ### Debug + + * groffer2.sh: + - $_DEBUG_PRINT_FILENAMES: New variable for printing the file + names that are displayed by `groffer'. + - --debug-filenames: The corresponding option. It is used in + man_register_file(), register_file(), and main_parse_args(). + + * groffer.man: Add information on --debug-filenames. + + ### Other changements + + * groffer2.sh: + - is_greater_than(): New function. Use it where suitable. + - lists_combine(): New function to combine several lists to a + single list. + - list_from_split(): Rewrite it to output a list with quoted + elements. + - list_has_prog(), list_has_not_prog(): New functions to check the + list on an element that starts with a given word. + - obj_from_output(): Use this function at many places instead of + `var="$(...)"'; this makes the usage of exit_test() unnecessary. + - path_clean(): Fix assignment. + - path_list(): Rename path_split(). + - tmp_create(): Add check of temporary file. + - usage(): Fix. + + * README_SH: + - Fix section `Error handling'. + - Add section `Speed'. + +2005-08-22 Bernd Warken + ________________________________________________________________ + * release of groffer 0.9.22 + + ### `--whatis' + + Produce a `groff' output and allow wild cards on filespec + parameters for `--whatis'. + + * groffer2.sh: + - $_FILESPEC_ARG: New variable for storing the actual filespec + parameter. + - main_do_fileargs(): Set $_FILESPEC_ARG and add + what_is_filespec(). + - main_parse_args(): Add --all to --whatis. + - to_tmp_line(): New function to write the arguments to the + temorary cat file. + - whatis_filename(): Rename of what_is(). Construct a better + printout using $_FILESPEC_ARG. Repair the sed sequneces. + - whatis_filespec(): New function to print the filespec once + during the `whatis' process. + - whatis_header(): New funtion for printing the header of the + `whatis' output. + + * groffer.man: Revise the documentation of --whatis. + + ### `--apropos*' + + Produce `groff' for `--apropos*'. Allow `--sections' for + `--apropos', ignore it with `--apropos-*'. + + * groffer2.sh: + - --apropos*: Make these options without argument. + - $_APROPOS_PROG: New variable for the program that is is used for + `apropos'. + - $_APROPOS_SECTIONS: New variable to determine the sections that + are filtered out of `apropos' output depending on `--apropos-*'. + - apropos_filespec(): Handling of apropos at the filespec level. + - apropos_run(): Remove it. + - apropos_setup(): New function. + - main_set_mode(): Remove handling of $_OPT_APROPOS*. + + * groffer.man: + - Revise the documentation of `--apropos*'. + - Split section 'options for GNU man' into two sections `options + for man pages' and `long options taken over from GNU man'. + - Move `--apropos*', `--whatis', `--man', and `--no-man' to + section `options for man pages'. + + ### special display (apropos and whatis) + + * groffer2.sh: + - special_setup(): New function that chooses the setup between + apropos and whatis. + - special_filespec(): New function that does the output at the + filespec level for apropos or whatis. + + ### handle `--sections' for man page searching + + * groffer2.sh: + - man_do_filespec(): Use $_OPT_SECTIONS of --sections instead of + $_MAN_AUTO_SEC if non-empty. If a section was given on the + filespec parameter $_OPT_SECTIONS is ignored. This differs from + `man' which always uses the restricted sections of --sections. + This function works for both normal man page search and whatis. + - apropos_filespec(): Use --sections for --apropos, but not for + --apropos-* because these provide already their own sections. + + ### wildcards in filespec arguments + + * groffer2.sh: Wildcards are now accepted. In `--apropos*' and + `--whatis' they are interpreted as wildcard search elements; but + in normal display they are only handled as their own character. + + ### development; new option + + * groffer2.sh: + - --print: New option that prints just its argument for parameter + check. + - usage(): Add new option. + - $_OPT_DO_NOTHING: New variable for do_nothing(). Handle it at + the end of main_parse_Args(). + + * groffer.man: Add information on --print. + + ### safe exit + + * groffer2.sh: + - error(): Always exit with $_ERROR. + - exit_test(): New function to exit when first exit was hidden by + (). Call it after each $(). + + ### automatic shell determination + + * groffer.sh: + - If no option --shell is given perform a test of several shells + to automatically start some shell for groffer2.sh. `ksh' is used + first because it can be safely terminated by Ctrl-C. + - This can be cancelled by providing --shell=''. + - Add test on `sed' program. + + * groffer.man: Revise information on --shell. + + ### trap + + * groffer2.sh: + - trap_set(): Remove argument. Instead of $_ALL_EXIT use only + signal 0. + - trap_unset(): Rename trap_clean(). Instead of $_ALL_EXIT use + only signal 0. + - $_ALL_EXIT: Remove this variable. + - Replace all direct `trap' calls by trap_set(). + + * README_SH: New section `Bugs' on `trap'.. + + ### user errors, error output without function stack + + * groffer2.sh: + - error_user(): New function for user errors. + - error(): Remove call of clean_up() because the trap will do it + with the exit. Remove the `kill' commands. Create a temporary + file `.error' that can be tested by exit_test() for a better exit + test (especially for shell `ksh'). + - $_DEBUG_USER_WITH_STACK: New variable to enable function stack + output in error_user(). + - list_from_cmdline(), list_single_from_abbrev(), main_set_mode(): + Use error_user(). + + ### test modes on X and tty + + * groffer2,sh: + - is_X(), is_not_X(): New functions for checking on X Window. + - $_VIEWER_HTML_TTY, $_VIEWER_HTML_X: New variables that split + $_VIEWER_HTML. Add `galeon'. + - main_parse_args(): Allow mode change for graphical modes only + when in X Window. + - _do_display() of main_display(): Create a special run for + viewers that run on the terminal; `lynx' is the only one so far. + + ### add $GROFFER_MODE to command line + + * groffer.sh: + - After the handling of the configuration files integrate + $GROFFER_OPT to the command line. + - This makes a `set' in the shell determination unnecessary. + + * groffer2.sh: + - The debug test gets simpler because quotes are vanished without + $GROFFER_OPT. + - main_parse_MANOPT(): Prepend $mpm_list to the command line. + - main_parse_args(): `set' is unnecessary. + + ### debug; new options + + * groffer2.sh: + - --debug-all, --debug-lm, --debug-params, --debug-shell, + --debug-stacks, --debug-tmpdir, --debug-user: New options. + - --debug: Enable all debug variables except $_DEBUG_STACKS and + $_DEBUG_LM. By the new options the smallest abbreviation is now + `--debug'. + - $_DEBUG_STACKS: Rename $_DEBUG. + - $_DEBUG_PRINT_TMPDIR: New debug variable for printing the name + of the temporary directory in main_init(). + - $_OPT_DEBUG: Remove this variable because debug is handled at + the early part of the script. + - clean_up(): Enlarge $_DEBUG_KEEP_FILES to not deleting the + temporary directory. + - usage(): Move all development options on a section of its own. + - Move the test of rudimentary shell functionality at the + beginning of the script. Add test on `sed'. + - Follow this by the debug section. The determination of all + --debug* options can be done without a function. + + * groffer.man: Revise information on --debug and add new options. + + ### variables + + * groffer.sh: + - $_ERROR: Move the definition of this variable here. + - $_GROFF_VERSION: New variable, is set over @...@ construct. + - $_OUTPUT_FILE_NAME: Move this variable to groffer2.sh. + + * groffer2.sh: + - $_MAN_AUTO_SEC_LIST: Rename $_MAN_AUTO_SEC because it represents + a list. + - $_MAN_AUTO_SEC_CHARS: New read-only variable for storing + $_MAN_AUTO_SEC_LIST in [] construct. Use it in man_do_filespec() + and whatis_filename(). + - $_SPACE_CASE: New read-only variable with [] on space characters + with \ for `case' patterns. Use it in several functions. + - $_SPACE_SED: New read-only variable with [] on space characters + for `sed'. Use it in several functions. + + ### options and display + + * groffer2.sh: + - list_from_cmdline(): Add test whether the same abbreviation is + part of long options with and without arguments. Give handling of + `=' a `case' pattern of its own. + - main_display(): Remove unnecessary calls of `clean_up' in order + to use `mozilla' without problems. In _do_display(): Fix -X by + providing a different process when $_DISPLAY_PROG is empty. + - main_set_mode(): Accept options for viewers as is, without check + for program. Add test whether no program is given for a mode. + This avoids unnecessary empty $_DISPLAY_PROG in main_display(). + + ### viewer programs that run on the terminal (tty); new options + + * groffer2.sh: + - $_VIEWER_TERMINAL: New variable that stores whether a viewer was + supposed to run on tty. + - --dvi-viewer-tty, --html-viewer-tty, --pdf-viewer-tty, + --ps-viewer-tty, --tty-viewer-tty, --X-viewer-tty, --x-viewer-tty, + --www-viewer-tty: New options for viewers that run on a terminal. + - main_parse_args(), _do_display() of main_display(): Use the new + options and the new variable. + - usage(): Add the new options. + + * groffer.man: Add information on options --*-viewer-tty. + + ### other fixes + + * groffer2.sh: + - _do_display() of main_display(): Bear errors of `groff' run. + - is_not_file: Fix to have exactly one argument. + - is_not_prog(): Handle no arguments. + - list_has_not(): Fix. + - main_do_fileargs(): Remove $mdfa_exitcode. + - register_title(): Limit title to 4 elements. + - version(): Print the version information to standard output just + like `groff' does. + - --no-special: New option to disable former calls of `--all', + `--apropos*', and `whatis. + - --title: Make it an option with argument. + +2005-08-07 Keith Marshall + + * contrib/groffer/Makefile.sub (install): Reference groffer2.sh + as $(srcdir)/groffer2.sh, so it will install when building in a + different directory from the source. + +2005-08-02 Bernd Warken + ________________________________________________________________ + * release of groffer 0.9.21 + + ### @...@ constructs + + * groffer.sh: + - $_AT: New variable for `@'. + - @...@: Replace the @...@ constructs by variables _AT_..._AT. + These constructs are transformed by `make' to useful information. + Keep all of these constructs in the first part of groffer.sh. For + a run before a `make' call, the script sets these variables to + special values for testing purpose. + - $_GROFFER_LIBDIR: Variable pointing to the groffer library + directory @libdir@/groff/groffer. + + ### Configuration files + + * groffer.sh: + - Add test for `$()' construct. + - Read and transform the configuration files and execute the + emerging commands. The `sed' script was heavily enlarged to + handle line with spaces and quotes. The emerging script is now + called by `eval', so no temporary file is needed. + - $_CONF_FILE_ETC, $_CONF_FILE_HOME: New variables for the config + files. + - $_SQ, $_SP: Move variables for characters before the handling of + the configuration files. Rename $_SQUOTE to $_SQ and $_SPACE to + $_SP. + - $GROFFER_OPT: Remove cleaning of this variable before the + reading of the configuration files. + + * groffer2.sh: + - main_init(): Remove the getting of the configuration files. + + ### Rewrite the shell determination + + * groffer.sh: + - Get rid of all functions in `groffer.sh'. Rewrite the shell + determination with `` and $(). + - --shell: Shortest abbreviation is `--sh'. Allow arguments for + the shell name. + - Allow an empty argument for --shell as shell name to overwrite a + specified shell; an empty shell name gets back to the default + shell. + - The shell determination now inludes the full handling of the + config files. The `--shell' option needs no longer a line + starting with `-'. + + ### Test of unset + + * groffer.sh: + - Remove test of `unset'. + - Remove all calls of `unset'. + - Use one character names for all variables that are meant to be + local in this script. + + * groffer2.sh: + - Move the test of `unset' to the testing of rudimentary shell + functionality without change. + + ### Allow abbreviations for long options + + * groffer2.sh: + - list_has_abbrev(): New function for checking a list having an + element with a given abbreviation. + - list_get_single_from_abbrev(): New function to retrieve the + element having a given abbreviation. + - list_from_cmd_line(): For an option abbreviation determine the + corresponding long option. + - From the man option lists remove the elements that are also in + a groffer list. + - Allow abbreviation for the early test of --debug. + + * groffer.sh: Allow abbreviation for the early test on --shell. + - get_opt_shell(): Rewrite _get_opt_shell() and the shell test + around it. + - test_on_shell(): Rename function _test_on_shell(). + - $_SHELL: global variable for the shell to run groffer2.sh. + + ### Get rid of `sh -c' + + * groffer2.sh: + - main_display(), _do_display(): Remove the `sh -c' calls. Make + the cleanup working without it. + - _do_display(): Extend _do_display() such that it can be used for + the pdf mode as well. + - _make_pdf(): New subfunction of main_display() for running the + additional parts of pdf mode in _do_display(). + - rm_file(), rm_file_with_debug(), rm_tree(): New functions for + removing files and directories. + + ### Change directory + + * groffer2.sh: + - $_START_DIR: New variable to store the directory at the starting + time of the script. + - main_display(): Go to the groffer temporary directory to be able + to process internal `groff' data like pictures. + - clean_up(): Get back to the starting directory. + + ### Compatibility with strange shells + + * groffer2.sh: + - clean_up(): `zsh' and `posh' had difficulties with `eval'. + - is_*(): Add test on empty argument. Some shells return true on + `test -d' etc. with empty argument, while most shells return + false. + - echo1(); New function to print single line `cat <file' for generating an empty file. + - rmdir: Replace `rmdir' by `rm -f -r'. + - eval: Add `eval' to many commands with variable arguments. + + * groffer.sh: repair `debug' + - Print all debug output to stderr. + - $_FUNC_STACK: Built function call stack even when $_DEBUG is not + set. Now the arguments are not added. + - $_DEBUG: If set to `yes' print 3 call stack events: the function + that is added with its arguments is printed with `+++ ' + (func_push()); the call stack after the addition is printed with + `>>> ' (func_push()); the call stack after the removing is printed + with `<<< ' (func_pop()). + - error(): Always print the function call stack on errors. + + * groffer.sh: Corrections + - $_groffer_run: Rename to $_GROFFER_RUN. + - $unset: Rename to $_UNSET. + - Repair test of `unset'. + - Repair test for `--shell'. The script is now rerun under the + shell specified in the option argument. This can increase the + speed. + + * README_SH: `zsh' now works. + + * groffer.man: + - Reformulate the information for the `groffer' specific details + of option `-V'. + - Add information on the debug process. + - Add information on the default devices in `x mode'. + - Minor corrections. + +2005-07-01 Bernd Warken + ________________________________________________________________ + * release of groffer 0.9.18 + + * groffer.sh: further shell compatibility + - `echo': Remove options and possible options of `echo' by + preceding the argument with a character `x' that is removed by + `sed' or replace `echo' by `cat </README_SH - + ******* Extension of the `apropos' handling The output of man's `apropos' has grown immensely meanwhile, so it @@ -141,7 +1320,7 @@ specify function arguments and the calling syntax in a simpler way by letting the first argument be a variable name, usable for input or output. - + Such an object type is `list', the string value of a shell variable arranged in space-separated single-quoted elements, such as $GROFFER_OPT internally. @@ -163,7 +1342,7 @@ spaces at the beginning.of the line are omitted. - all other lines are interpreted as a shell command and executed in the current shell of the groffer call. - + Precedence: - The command line and the external environment variables such as $GROFFER_OPT of the groffer call have the highest precedence. @@ -171,8 +1350,8 @@ directory. - The system configuration file in /etc has the lowest precedence. - - * groffer.sh: + + * groffer.sh: The configuration files are now called after the determination of the temporary files in main_init(). @@ -189,7 +1368,7 @@ - Force the script to be called as an executable file, so $0 must contain the program name. - + ******* Improved temporary file names Just like groff, groffer mixes all file parameters into a single @@ -197,7 +1376,7 @@ list built from the file name arguments without a leading comma. So a leading comma can be used for the internal temporary file names. - + * groffer.sh: - $_OUTPUT_FILE_NAME: new global variable as basis for the output file name; it is set in main_set_resources(). @@ -262,9 +1441,9 @@ - man_search_section(): correction of some `for' loops. - Remove export of external non-groffer variables. - + ******* Documentation - + * groffer.man: - Reorder the option details according to the option origin as groffer, groff, X, and man options. @@ -274,19 +1453,19 @@ * README_SH: new file Move large parts of the documentation in `groffer.sh' into this file. - + * groffer.sh: usage(): - Change the output for `--help' to standard output. - Restructure the information for this help output. - + ******* Removement of the author's email address - + Because of the extreme spam attacks, the author removed all occurencies of his email address in every file of the groffer source. -2003-01-22 Bernd Warken +2003-01-22 Bernd Warken ________________________________________________________________ * release of groffer 0.9.4 @@ -303,11 +1482,11 @@ - Test existence of directory before deleting it in the `clean_up' definitions. - Correct help output in `usage' (called by `--help'). - + * TODO: Remove mention of `shoop' and `apropos'. -2002-10-21 Bernd Warken +2002-10-21 Bernd Warken ________________________________________________________________ * release of groffer 0.9.3 @@ -330,8 +1509,8 @@ * TODO: think about... - writing part of groffer in C/C++. - handling several files with different macro packages. - -2002-10-17 Bernd Warken + +2002-10-17 Bernd Warken ________________________________________________________________ * fixes of groffer 0.9.2 @@ -343,12 +1522,12 @@ - New macro ".Header_CB" for CB font in .TP headers; used for definition of variables in option --mode. - Fix some option references to refer to long options. - + * README: New file for general information on the groffer source; it is not installed. - -2002-10-14 Bernd Warken + +2002-10-14 Bernd Warken * Makefile.sub: add replacement "@BINDIR@" to "$(bindir)" for "groffer:" @@ -360,7 +1539,7 @@ * groffer.man: Remove double definition of filespec parameters. -2002-10-13 Bernd Warken +2002-10-13 Bernd Warken ________________________________________________________________ * release of groffer 0.9.2 @@ -382,16 +1561,16 @@ - New macro for file names ".File_name". - "Option Parsing" is moved to section "COMPATIBILITY". - Fix some "EXAMPLES". - -2002-09-30 Bernd Warken + +2002-09-30 Bernd Warken ________________________________________________________________ * release of groffer 0.9.1 - + * TODO: remove done entries - Remove request for different shells. - Remove the 'sed' complaints. -2002-07-15 Bernd Warken +2002-07-15 Bernd Warken * groffer.sh: replace `sed' interface by direct `sed' - This improves the performance of the shell programming parts @@ -415,7 +1594,7 @@ groffer was called from the command line, or with the shell name in the first line of the script, actually `/bin/sh'. -2002-07-12 Bernd Warken +2002-07-12 Bernd Warken ________________________________________________________________ * fixes for groffer 0.9.0 @@ -425,7 +1604,7 @@ - the string `is part of ' - groff's version information (version number and copyright), but not groff's `called subprograms' information. - + * groffer.sh: minor fixes - Fix the argument parser to process argument `-' correctly. - Some display programs have trouble with empty input; feed a @@ -435,7 +1614,7 @@ * TODO: fix entry `shoop' (not 'shopt'). -2002-06-28 Bernd Warken +2002-06-28 Bernd Warken ________________________________________________________________ * release of groffer 0.9.0 @@ -448,25 +1627,25 @@ - New options `--pdf', `--pdf-viewer', `--mode pdf'. - Standard pdf viewers `xpdf' and `acroread'. - For `xpdf', choose zoom `z 3' for 100 dpi, `z 2' for 75 dpi. - + * groffer.sh: support bzip2 decompression - add test for `bzip2' with necessary options - extend functions `catz()' and `save_stdin()'. * TODO remove entry on `bzip' decompression (done). - + * groffer.man: - Document new `pdf' features. - Document new `bzip2' decompression. - Fix documentation for `--auto-modes'. - + * groffer.sh: minor fixes - Improve device tests in `tty' and `dvi' modes. - Internally, map mode `auto' to '' to facilitate tests. - Fix auto mode sequence to: `ps,x,tty' as was intended. -2002-06-25 Bernd Warken +2002-06-25 Bernd Warken * groffer.sh: Fix `source' mode. @@ -474,7 +1653,7 @@ * groffer.man: Fix some indentations. -2002-06-23 Bernd Warken +2002-06-23 Bernd Warken ________________________________________________________________ * release of groffer 0.8 @@ -486,7 +1665,7 @@ - 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. @@ -498,7 +1677,7 @@ - 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 @@ -519,7 +1698,7 @@ -> `--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; @@ -544,7 +1723,7 @@ -> 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. @@ -557,7 +1736,7 @@ - `${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; @@ -574,18 +1753,18 @@ 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 @@ -593,7 +1772,7 @@ Increase to 4m (we use `sh#' as the prompt). -2002-05-31 Bernd Warken +2002-05-31 Bernd Warken ________________________________________________________________ * release of groffer 0.7 @@ -629,14 +1808,14 @@ - fix TP_header. -2002-05-28 Bernd Warken +2002-05-28 Bernd Warken ________________________________________________________________ * release of groffer 0.6 This is almost a complete rewrite since groffer 0.5 . ________________________________________________________________ * Documentation - + * groffer.man: - Apply the changes done in www.tmac (.URL and .MTO) - Replace \fP by \f[]. @@ -669,7 +1848,7 @@ - The only external programs used are POSIX `sed' and the fallback to `apropos'. All other program calls were replaced by shell builtins and functions. - + ________________________________________________________________ * Cosmetics @@ -721,10 +1900,10 @@ characters in file names). - Fix and complement usage(). - The filespec parsers gets a function of its own do_manpage(). - - -2002-01-08 Bernd Warken - + + +2002-01-08 Bernd Warken + * groffer 0.5 (beta) released * groffer.man: @@ -733,7 +1912,7 @@ - Examples of shell commands now print in font CR instead of CB. - Remove documentation for option `-X'. - Add documentation for option `--dpi'. - + * groffer.sh: - New method for creating temporary files, based on process IDs. This is reliable enough and suitable for GNU and POSIX. @@ -750,15 +1929,15 @@ - Implement option `--dpi' for setting the resolution for the X viewer, which had already been documented in earlier versions. -2002-01-07 Bernd Warken +2002-01-07 Bernd Warken * groffer 0.4 (beta) released (as groff `contrib') - + * groffer.man: - New features documented. - Macros stream-lined. - Section EXAMPLES added. - + * groffer.sh: - System tests added/optimized. - Speed/memory optimizations by defining some shell functions @@ -789,7 +1968,7 @@ * groffer.man (OptDef): Add missing backslashes. Update copyright. -2001-12-15 Bernd Warken +2001-12-15 Bernd Warken * groffer 0.3 (alpha) released (still stand-alone package). @@ -807,20 +1986,20 @@ * Recognize the following filespecs as man-page parameters: man:name(section), man:name, name.section, name. - -2001-12-03 Bernd Warken + +2001-12-03 Bernd Warken * Stand-alone package for groffer 0.2 (alpha) created Files: groffer, groffer.man, Makefile, TODO, ChangeLog - -2001-12-02 Bernd Warken + +2001-12-02 Bernd Warken * groffer 0.2 (alpha) program released. * Name changed from `groffview' to `groffer'. * Comments added. - + * Name changed from `groffview' to `groffer'. * Options harmonized with groff. @@ -832,26 +2011,30 @@ * Bugs with temporary files fixed. * Code restructured and comments added. - -2001-11-28 Bernd Warken + +2001-11-28 Bernd Warken ***** groffview 0.1 (experimental) and groffview.man released (predecessor of groffer, shell script) * Options : -h --help, -v --version - + * Search for man-pages based on $MANPATH * development of `groffview' shell script started 2001-11-28 Bernd Warken + ________________________________________________________________ License - Copyright (C) 2001,2002,2003,2004 Free Software Foundation, Inc. + Copyright (C) 2001,2002,2003,2004,2005,2006 + Free Software Foundation, Inc. Written by Bernd Warken + Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. - This file is part of groffer, which is part of the groff project. + This file is part of `groffer', which is part of the `groff' + project. diff -ruN groff-1.18.1.1/contrib/groffer/groffer2.sh groff-1.18.1.2/contrib/groffer/groffer2.sh --- groff-1.18.1.1/contrib/groffer/groffer2.sh 1970-01-01 01:00:00.000000000 +0100 +++ groff-1.18.1.2/contrib/groffer/groffer2.sh 2006-09-26 23:24:06.000000000 +0200 @@ -0,0 +1,7191 @@ +#! /bin/sh + +# groffer - display groff files + +# Source file position: /contrib/groffer/groffer2.sh +# Installed position: /lib/groff/groffer/groffer2.sh + +# This file should not be run independently. It is called by +# `groffer.sh' in the source or by the installed `groffer' program. + +# Copyright (C) 2001,2002,2003,2004,2005,2006 +# Free Software Foundation, Inc. +# Written by Bernd Warken + +# Last update: 26 Sep 2006 + +# This file is part of `groffer', which is part of `groff'. + +# `groff' is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# `groff' is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with `groff'; see the files COPYING and LICENSE in the top +# directory of the `groff' source. If not, write to the Free Software +# Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, +# USA. + + +######################################################################## +# Test of rudimentary shell functionality +######################################################################## + + +######################################################################## +# Test of `unset' +# +export _UNSET; +export _foo; +_foo=bar; +_res="$(unset _foo 2>&1)"; +if unset _foo >${_NULL_DEV} 2>&1 && \ + test _"${_res}"_ = __ && test _"${_foo}"_ = __ +then + _UNSET='unset'; + eval "${_UNSET}" _foo; + eval "${_UNSET}" _res; +else + _UNSET=':'; +fi; + + +######################################################################## +# Test of `test'. +# +if test a = a && test a != b && test -f "${_GROFFER_SH}" +then + :; +else + echo '"test" did not work.' >&2; + exit "${_ERROR}"; +fi; + + +######################################################################## +# Test of `echo' and the `$()' construct. +# +if echo '' >${_NULL_DEV} +then + :; +else + echo '"echo" did not work.' >&2; + exit "${_ERROR}"; +fi; +if test _"$(t1="$(echo te)" && + t2="$(echo '')" && + t3="$(echo 'st')" && + echo "${t1}${t2}${t3}")"_ \ + != _test_ +then + echo 'The "$()" construct did not work' >&2; + exit "${_ERROR}"; +fi; + + +######################################################################## +# Test of sed program; test in groffer.sh is not valid here. +# +if test _"$(echo xTesTx \ + | sed -n -e 's/^.\([Tt]e*x*sTT*\).*$/\1/p' \ + | sed -e 's|T|t|g')"_ != _test_ +then + echo 'The sed program did not work.' >&2; + exit "${_ERROR}"; +fi; + + +######################################################################## +# Test of `cat'. +# +if test _"$(echo test | cat)"_ != _test_ +then + error 'Test of "cat" command failed.'; +fi; + + +######################################################################## +# Test of function definitions. +# +_t_e_s_t_f_u_n_c_() +{ + return 0; +} + +_test_func() +{ + echo test; +} + +if _t_e_s_t_f_u_n_c_ 2>${_NULL_DEV} && \ + test _"$(_test_func 2>${_NULL_DEV})"_ = _test_ +then + :; +else + echo 'Shell '"${_SHELL}"' does not support function definitions.' >&2; + exit "${_ERROR}"; +fi; + + +######################################################################## +# landmark () +# +# Print to standard error as a debugging aid. +# +# Globals: $_DEBUG_LM +# +landmark() +{ + if test _"${_DEBUG_LM}"_ = _yes_ + then + echo "LM: $*" >&2; + fi; +} # landmark() + + +######################################################################## +# test for compression. +# +export _HAS_COMPRESSION; +export _HAS_BZIP; +if test _"$(echo 'test' | gzip -c -d -f - 2>${_NULL_DEV})"_ = _test_ +then + _HAS_COMPRESSION='yes'; + if echo 'test' | bzip2 -c 2>${_NULL_DEV} | bzip2 -t 2>${_NULL_DEV} \ + && test _"$(echo 'test' | bzip2 -c 2>${_NULL_DEV} \ + | bzip2 -d -c 2>${_NULL_DEV})"_ \ + = _test_ + then + _HAS_BZIP='yes'; + else + _HAS_BZIP='no'; + fi; +else + _HAS_COMPRESSION='no'; + _HAS_BZIP='no'; +fi; + + +######################################################################## +# debug - diagnostic messages +######################################################################## + +export _DEBUG_FUNC_CHECK; +if test _"${_BEFORE_MAKE}"_ = _yes_ +then + _DEBUG_FUNC_CHECK='yes'; +else + _DEBUG_FUNC_CHECK='no'; +fi; +_DEBUG_FUNC_CHECK='no'; # disable function checking +#_DEBUG_FUNC_CHECK='yes'; # enable function checking + +export _DEBUG_STACKS; +_DEBUG_STACKS='no'; # disable stack output in each function +#_DEBUG_STACKS='yes'; # enable stack output in each function + +export _DEBUG_USER_WITH_STACK; +_DEBUG_USER_WITH_STACK='no'; # disable stack dump in error_user() +#_DEBUG_USER_WITH_STACK='yes'; # enable stack dump in error_user() + +export _DEBUG_LM; +_DEBUG_LM='no'; # disable landmark messages +#_DEBUG_LM='yes'; # enable landmark messages + +export _DEBUG_KEEP_FILES; +_DEBUG_KEEP_FILES='no' # disable file keeping in temporary dir +#_DEBUG_KEEP_FILES='yes' # enable file keeping in temporary dir + +export _DEBUG_PRINT_PARAMS; +_DEBUG_PRINT_PARAMS='no'; # disable printing of all parameters +#_DEBUG_PRINT_PARAMS='yes'; # enable printing of all parameters + +export _DEBUG_PRINT_SHELL; +_DEBUG_PRINT_SHELL='no'; # disable printing of the shell name +#_DEBUG_PRINT_SHELL='yes'; # enable printing of the shell name + +export _DEBUG_PRINT_TMPDIR; +_DEBUG_PRINT_TMPDIR='no'; # disable printing of the temporary dir +#_DEBUG_PRINT_TMPDIR='yes'; # enable printing of the temporary dir + +export _DEBUG_PRINT_FILENAMES; +_DEBUG_PRINT_FILENAMES='no'; # disable printing of the found file names +#_DEBUG_PRINT_FILENAMES='yes'; # enable printing of the found file names + +# determine all --debug* options +case " $*" in +*\ --deb*|*\ --d*-*) + # --debug-* options + d=' --debug-all --debug-filenames --debug-func --debug-not-func '\ +'--debug-keep --debug-lm --debug-params --debug-shell --debug-stacks '\ +'--debug-tmpdir --debug-user '; + # non-debug options with scheme --d*-* + n=' --do-nothing --default-modes --dvi-viewer --dvi-viewer-tty '; + for i + do + case "$i" in + --deb|--debu|--debug) + _DEBUG_FUNC_CHECK='yes'; + # _DEBUG_STACKS='yes'; + _DEBUG_USER_WITH_STACK='yes'; + # _DEBUG_LM='yes'; + _DEBUG_KEEP_FILES='yes'; + _DEBUG_PRINT_PARAMS='yes'; + _DEBUG_PRINT_SHELL='yes'; + _DEBUG_PRINT_TMPDIR='yes'; + _DEBUG_PRINT_FILENAMES='yes'; + continue; + ;; + --d*-*) + # before `-' + b="$(echo x"$i" | sed -e 's/^x--\([^-]*\)-.*$/\1/')"; + # after `-' + a="$(echo x"$i" | sed -e 's/^x--[^-]*-\(.*\)$/\1/')"; + ;; + *) + continue; + ;; + esac; + case "$n" in + *\ --$b*-$a*) + continue; + ;; + esac; + case "$d" in + *\ --$b*-$a*) + case "$a" in + f|s) # double --debug-* options + continue; + ;; + esac; + # extract whole word of double abbreviation + s="$(cat <&2; +fi; + +if test _"${_DEBUG_PRINT_SHELL}"_ = _yes_ +then + if test _"${_SHELL}"_ = __ + then + if test _"${POSIXLY_CORRECT}"_ = _y_ + then + echo 'shell: bash as /bin/sh (none specified)' >&2; + else + echo 'shell: /bin/sh (none specified)' >&2; + fi; + else + echo "shell: ${_SHELL}" >&2; + fi; +fi; + + +######################################################################## +# Environment Variables +######################################################################## + +landmark "1: environment variables"; + +# Environment variables that exist only for this file start with an +# underscore letter. Global variables to this file are written in +# upper case letters, e.g. $_GLOBAL_VARIABLE; temporary variables +# start with an underline and use only lower case letters and +# underlines, e.g. $_local_variable. + +# [A-Z]* system variables, e.g. $MANPATH +# _[A-Z_]* global file variables, e.g. $_MAN_PATH +# _[a-z_]* temporary variables, e.g. $_manpath + +# Due to incompatibilities of the `ash' shell, the name of loop +# variables in `for' must be a single character. +# [a-z] local loop variables, e.g. $i + +# In functions, other writings are used for variables. As some shells +# do not support the `local' command a unique prefix in lower case is +# constructed for each function, most are the abbreviation of the +# function name. All variable names start with this prefix. +# ${prefix}_[a-z_]* variable name in a function, e.g. $msm_modes + + +######################################################################## +# read-only variables (global to this file) +######################################################################## + +# function return values; `0' means ok; other values are error codes +export _BAD; +export _GOOD; +export _NO; +export _OK; +export _YES; + +_GOOD='0'; # return ok +_BAD='1'; # return negatively, error code `1' +# $_ERROR was already defined as `7' in groffer.sh. + +_NO="${_BAD}"; +_YES="${_GOOD}"; +_OK="${_GOOD}"; + +# quasi-functions, call with `eval', e.g `eval "${return_ok}"' +export return_ok; +export return_good; +export return_bad; +export return_yes; +export return_no; +export return_error; +export return_var; +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}"; +return_var="func_pop; return"; # add number, e.g. `eval "${return_var} $n' + + +export _DEFAULT_MODES; +_DEFAULT_MODES="'pdf' 'html' 'ps' 'x' 'dvi' 'tty'"; +export _DEFAULT_RESOLUTION; +_DEFAULT_RESOLUTION='75'; + +export _DEFAULT_TTY_DEVICE; +_DEFAULT_TTY_DEVICE='latin1'; + +# _VIEWER_* viewer programs for different modes constructed as lists +export _VIEWER_DVI_TTY; # viewer program for dvi mode in tty +export _VIEWER_DVI_X; # viewer program for dvi mode in X +export _VIEWER_HTML_TTY; # viewer program for html mode in tty +export _VIEWER_HTML_X; # viewer program for html mode in X +export _VIEWER_PDF_TTY; # viewer program for pdf mode in tty +export _VIEWER_PDF_X; # viewer program for pdf mode in X +export _VIEWER_PS_TTY; # viewer program for ps mode in tty +export _VIEWER_PS_X; # viewer program for ps mode in X +export _VIEWER_TTY_TTY; # viewer program for X/x mode in tty +export _VIEWER_TTY_X; # viewer program for X/x mode in X +export _VIEWER_X_TTY; # viewer program for X/x mode in tty +export _VIEWER_X_X; # viewer program for X/x mode in X +_VIEWER_DVI_TTY=""; +_VIEWER_DVI_X="'kdvi' 'xdvi' 'dvilx'"; +_VIEWER_HTML_TTY="'lynx' 'w3m'"; +_VIEWER_HTML_X="'konqueror' 'epiphany' 'mozilla-firefox' 'firefox' 'mozilla' \ +'netscape' 'galeon' 'opera' 'amaya' 'arena' 'mosaic'"; +_VIEWER_PDF_TTY=""; +_VIEWER_PDF_X="'kpdf' 'acroread' 'evince' 'xpdf -z 150' 'gpdf' \ +'kghostview --scale 1.45' 'ggv'"; +_VIEWER_PS_TTY=""; +_VIEWER_PS_X="'kpdf' 'kghostview --scale 1.45' 'evince' 'ggv' 'gv' \ +'ghostview' 'gs_x11,gs'"; +_VIEWER_TTY_TTY="'less -r -R' 'more' 'pager'"; +_VIEWER_TTY_X="'xless'"; +_VIEWER_X_TTY=""; +_VIEWER_X_X="'gxditview' 'xditview'"; + +# Search automatically in standard sections `1' to `8', and in the +# traditional sections `9', `n', and `o'. On many systems, there +# exist even more sections, mostly containing a set of man pages +# special to a specific program package. These aren't searched for +# automatically, but must be specified on the command line. +export _MAN_AUTO_SEC_LIST; +_MAN_AUTO_SEC_LIST="'1' '2' '3' '4' '5' '6' '7' '8' '9' 'n' 'o'"; +export _MAN_AUTO_SEC_CHARS; +_MAN_AUTO_SEC_CHARS='[123456789no]'; + +export _SPACE_SED; +_SPACE_SED='['"${_SP}${_TAB}"']'; + +export _SPACE_CASE; +_SPACE_CASE='[\'"${_SP}"'\'"${_TAB}"']'; + +export _PROCESS_ID; # for shutting down the program +_PROCESS_ID="$$"; + +export _START_DIR; # directory at start time of the script +_START_DIR="$(pwd)"; + + +############ the command line options of the involved programs +# +# The naming scheme for the options environment names is +# $_OPTS__[_] +# +# : program name GROFFER, GROFF, or CMDLINE (for all +# command line options) +# : LONG (long options) or SHORT (single character options) +# : ARG for options with argument, NA for no argument; +# without _ both the ones with and without arg. +# +# Each option that takes an argument must be specified with a +# trailing : (colon). + +# 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_X_SHORT_ARG; +export _OPTS_X_SHORT_NA; +export _OPTS_X_LONG_ARG; +export _OPTS_X_LONG_NA; +export _OPTS_MAN_SHORT_ARG; +export _OPTS_MAN_SHORT_NA; +export _OPTS_MAN_LONG_ARG; +export _OPTS_MAN_LONG_NA; +export _OPTS_MANOPT_SHORT_ARG; +export _OPTS_MANOPT_SHORT_NA; +export _OPTS_MANOPT_LONG_ARG; +export _OPTS_MANOPT_LONG_NA; +export _OPTS_CMDLINE_SHORT_NA; +export _OPTS_CMDLINE_SHORT_ARG; +export _OPTS_CMDLINE_LONG_NA; +export _OPTS_CMDLINE_LONG_ARG; + +###### groffer native options + +_OPTS_GROFFER_SHORT_NA="'h' 'Q' 'v' 'V' 'X' 'Z'"; +_OPTS_GROFFER_SHORT_ARG="'T'"; + +_OPTS_GROFFER_LONG_NA="'auto' \ +'apropos' 'apropos-data' 'apropos-devel' 'apropos-progs' \ +'debug' 'debug-all' 'debug-filenames' \ +'debug-func' 'debug-not-func' 'debug-keep' 'debug-lm' \ +'debug-params' 'debug-shell' 'debug-stacks' 'debug-tmpdir' 'debug-user' \ +'default' 'do-nothing' 'dvi' 'groff' 'help' 'intermediate-output' 'html' \ +'man' 'no-location' 'no-man' 'no-special' 'pdf' 'ps' 'rv' 'source' \ +'text' 'text-device' 'tty' 'tty-device' \ +'version' 'whatis' 'www' 'x' 'X'"; + +_OPTS_GROFFER_LONG_ARG="\ +'default-modes' 'device' 'dvi-viewer' 'dvi-viewer-tty' 'extension' 'fg' \ +'fn' 'font' 'foreground' 'html-viewer' 'html-viewer-tty' 'mode' \ +'pdf-viewer' 'pdf-viewer-tty' 'print' 'ps-viewer' 'ps-viewer-tty' 'shell' \ +'title' 'tty-viewer' 'tty-viewer-tty' 'www-viewer' 'www-viewer-tty' \ +'x-viewer' 'x-viewer-tty' 'X-viewer' 'X-viewer-tty'"; + +##### groffer options inhereted from groff + +_OPTS_GROFF_SHORT_NA="'a' 'b' 'c' 'C' 'e' 'E' 'g' 'G' 'i' 'k' 'l' 'N' 'p' \ +'R' 's' 'S' 't' 'U' 'z'"; +_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=""; + +##### groffer options inhereted from the X Window toolkit + +_OPTS_X_SHORT_NA=""; +_OPTS_X_SHORT_ARG=""; + +_OPTS_X_LONG_NA="'iconic' 'rv'"; + +_OPTS_X_LONG_ARG="'background' 'bd' 'bg' 'bordercolor' 'borderwidth' \ +'bw' 'display' 'fg' 'fn' 'font' 'foreground' 'ft' 'geometry' \ +'resolution' 'title' 'xrm'"; + +###### groffer options inherited from man + +_OPTS_MAN_SHORT_NA=""; +_OPTS_MAN_SHORT_ARG=""; + +_OPTS_MAN_LONG_NA="'all' 'ascii' 'catman' 'ditroff' \ +'local-file' 'location' 'troff' 'update' 'where'"; + +_OPTS_MAN_LONG_ARG="'locale' 'manpath' \ +'pager' 'preprocessor' 'prompt' 'sections' 'systems' 'troff-device'"; + +###### additional options for parsing $MANOPT only + +_OPTS_MANOPT_SHORT_NA="'7' 'a' 'c' 'd' 'D' 'f' 'h' 'k' 'l' 't' 'u' \ +'V' 'w' 'Z'"; +_OPTS_MANOPT_SHORT_ARG="'e' 'L' 'm' 'M' 'p' 'P' 'r' 'S' 'T'"; + +_OPTS_MANOPT_LONG_NA="${_OPTS_MAN_LONG_NA} \ +'apropos' 'debug' 'default' 'help' 'html' 'ignore-case' 'location-cat' \ +'match-case' 'troff' 'update' 'version' 'whatis' 'where' 'where-cat'"; + +_OPTS_MANOPT_LONG_ARG="${_OPTS_MAN_LONG_NA} \ +'config_file' 'encoding' 'extension' 'locale'"; + +###### collections of command line options + +_OPTS_CMDLINE_SHORT_NA="${_OPTS_GROFFER_SHORT_NA} \ +${_OPTS_GROFF_SHORT_NA} ${_OPTS_X_SHORT_NA} ${_OPTS_MAN_SHORT_NA}"; +_OPTS_CMDLINE_SHORT_ARG="${_OPTS_GROFFER_SHORT_ARG} \ +${_OPTS_GROFF_SHORT_ARG} ${_OPTS_X_SHORT_ARG} ${_OPTS_MAN_SHORT_ARG}"; + +_OPTS_CMDLINE_LONG_NA="${_OPTS_GROFFER_LONG_NA} \ +${_OPTS_GROFF_LONG_NA} ${_OPTS_X_LONG_NA} ${_OPTS_MAN_LONG_NA}"; +_OPTS_CMDLINE_LONG_ARG="${_OPTS_GROFFER_LONG_ARG} \ +${_OPTS_GROFF_LONG_ARG} ${_OPTS_MAN_LONG_ARG} ${_OPTS_X_LONG_ARG}"; + + +######################################################################## +# read-write variables (global to this file) +######################################################################## + +export _ALL_PARAMS; # All options and file name parameters +export _ADDOPTS_GROFF; # Transp. options for groff (`eval'). +export _APROPOS_PROG; # Program to run apropos. +export _APROPOS_SECTIONS; # Sections for different --apropos-*. +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 _FILESPEC_ARG; # Stores the actual filespec parameter. +export _FILESPEC_IS_MAN; # filespec is for searching a man page +export _FUNC_STACK; # Store debugging information. +export _MACRO_PACKAGES; # groff's macro packages. +export _MACRO_PKG; # Macro package for each found file. +export _NO_FILESPECS; # Yes, if there are no filespec arguments. +export _REG_TITLE_LIST; # Processed file names. +export _SPECIAL_FILESPEC; # Filespec ran for apropos or whatis. +export _SPECIAL_SETUP; # Test on setup for apropos or whatis. +# _MAN_* finally used configuration of man searching +export _MAN_ALL; # search all man pages per filespec +export _MAN_ENABLE; # enable search for man pages +export _MAN_EXT; # extension for man pages +export _MAN_FORCE; # force file parameter to be man pages +export _MAN_IS_SETUP; # setup man variables only once +export _MAN_LANG; # language for man pages +export _MAN_LANG2; # language for man pages +export _MAN_PATH; # search path for man pages as a list +export _MAN_SEC; # sections for man pages; sep. `:' +export _MAN_SEC_CHARS; # sections for man pages as [] construct +export _MAN_SEC_LIST; # sections for man pages as a list +export _MAN_SYS; # system names for man pages as a list +# _MANOPT_* as parsed from $MANOPT +export _MANOPT_ALL; # $MANOPT --all +export _MANOPT_EXTENSION; # $MANOPT --extension +export _MANOPT_LANG; # $MANOPT --locale +export _MANOPT_PATH; # $MANOPT --manpath +export _MANOPT_PAGER; # $MANOPT --pager +export _MANOPT_SEC; # $MANOPT --sections +export _MANOPT_SYS; # $MANOPT --systems +# variables for mode pdf +export _PDF_DID_NOT_WORK; +export _PDF_HAS_GS; +export _PDF_HAS_PS2PDF; +# _OPT_* as parsed from groffer command line +export _OPT_ALL; # display all suitable man pages. +export _OPT_APROPOS; # call `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_DEFAULT_MODES; # `,'-list of modes when no mode given. +export _OPT_DEVICE; # device option. +export _OPT_DO_NOTHING; # do nothing in main_display(). +export _OPT_DISPLAY; # set X display. +export _OPT_EXTENSION; # set extension for man page search. +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_ICONIC; # -iconic option for X viewers. +export _OPT_LANG; # set language for man pages +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_TEXT_DEVICE; # set device for tty mode. +export _OPT_V; # groff option -V. +export _OPT_VIEWER_DVI; # viewer program for dvi mode +export _OPT_VIEWER_HTML; # viewer program for html mode +export _OPT_VIEWER_PDF; # viewer program for pdf mode +export _OPT_VIEWER_PS; # viewer program for ps mode +export _OPT_VIEWER_X; # viewer program for x mode +export _OPT_WHATIS; # print the man description +export _OPT_XRM; # specify X resource. +export _OPT_Z; # groff option -Z. +export _OUTPUT_FILE_NAME; # output generated, see main_set_res..() +export _VIEWER_BACKGROUND; # viewer shall be run in the background or not +# _TMP_* temporary directory and files +export _TMP_DIR; # groffer directory for temporary files +export _TMP_CAT; # stores concatenation of everything +export _TMP_MAN; # stores find of man path +export _TMP_MANSPEC; # filters man pages with filespec +export _TMP_STDIN; # stores stdin, if any + +# these variables are preset in section `Preset' after the rudim. test + + +######################################################################## +# Preset and reset of read-write global variables +######################################################################## + +# For variables that can be reset by option `--default', see reset(). + +_FILEARGS=''; +_MACRO_PACKAGES="'-man' '-mdoc' '-me' '-mm' '-mom' '-ms'"; +_SPECIAL_FILESPEC='no'; +_SPECIAL_SETUP='no'; + +# _TMP_* temporary files +_TMP_DIR=''; +_TMP_CAT=''; +_TMP_MAN=''; +_TMP_CONF=''; +_TMP_STDIN=''; + +# variables for mode pdf +_PDF_DID_NOT_WORK='no'; +_PDF_HAS_GS='no'; +_PDF_HAS_PS2PDF='no'; + +######################################################################## +# reset () +# +# Reset the variables that can be affected by options to their default. +# +reset() +{ + if test "$#" -ne 0 + then + error "reset() does not have arguments."; + fi; + + _ADDOPTS_GROFF=''; + _APROPOS_PROG=''; + _APROPOS_SECTIONS=''; + _DISPLAY_ARGS=''; + _DISPLAY_MODE=''; + _DISPLAY_PROG=''; + _MACRO_PKG=''; + _NO_FILESPECS=''; + _REG_TITLE_LIST=''; + + # _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_LANG2=''; + _MAN_PATH=''; + _MAN_SEC=''; + _MAN_SEC_CHARS=''; + _MAN_SEC_LIST=''; + _MAN_SYS=''; + + # _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_DEFAULT_MODES=''; + _OPT_DEVICE=''; + _OPT_DISPLAY=''; + _OPT_DO_NOTHING='no'; + _OPT_EXTENSION=''; + _OPT_FG=''; + _OPT_FN=''; + _OPT_GEOMETRY=''; + _OPT_ICONIC='no'; + _OPT_LANG=''; + _OPT_MODE=''; + _OPT_MANPATH=''; + _OPT_PAGER=''; + _OPT_RESOLUTION=''; + _OPT_RV='no'; + _OPT_SECTIONS=''; + _OPT_SYSTEMS=''; + _OPT_TITLE=''; + _OPT_TEXT_DEVICE=''; + _OPT_V='no'; + _OPT_VIEWER_DVI=''; + _OPT_VIEWER_PDF=''; + _OPT_VIEWER_PS=''; + _OPT_VIEWER_HTML=''; + _OPT_VIEWER_X=''; + _OPT_WHATIS='no'; + _OPT_XRM=''; + _OPT_Z='no'; + _VIEWER_BACKGROUND='no'; +} + +reset; + + +######################################################################## +# Preliminary functions for error handling +######################################################################## + +landmark "2: preliminary functions"; + +# These functions do not have a func-check frame. Basically they could be +# moved to the functions in alphabetical order. + +############## +# echo1 (*) +# +# Output to stdout with final line break. +# +# Arguments : arbitrary text including `-'. +# +echo1() +{ + cat <*) +# +# Output to stderr with final line break. +# +# Arguments : arbitrary text including `-'. +# +echo2() +{ + cat >&2 <"${_NULL_DEV}" 2>&1; + if test _${_DEBUG_KEEP_FILES}_ = _yes_ + then + if test _"$cu_already"_ = _yes_ + then + eval "${return_ok}"; + fi; + cu_already=yes; + echo2 "Kept temporary directory ${_TMP_DIR}." + else + if test _"${_TMP_DIR}"_ != __ + then + if test -e "${_TMP_DIR}" + then + rm -f -r "${_TMP_DIR}" >${_NULL_DEV} 2>&1; + fi; + fi; + fi; + eval "${return_ok}"; +} # clean_up() + + +############# +# diag (text>*) +# +# Output a diagnostic message to stderr. +# +diag() +{ + echo2 '>>>>>'"$*"; +} # diag() + + +############# +# error (*) +# +# Print an error message to standard error, print the function stack, +# exit with an error condition. The argument should contain the name +# of the function from which it was called. This is for system errors. +# +error() +{ + case "$#" in + 1) echo2 'groffer error: '"$1"; ;; + *) echo2 'groffer error: wrong number of arguments in error().'; ;; + esac; + func_stack_dump; + if test _"${_TMP_DIR}"_ != __ && test -d "${_TMP_DIR}" + then + : >"${_TMP_DIR}"/,error; + fi; + exit "${_ERROR}"; +} # error() + + +############# +# error_user (*) +# +# Print an error message to standard error; exit with an error condition. +# The error is supposed to be produced by the user. So the funtion stack +# is omitted. +# +error_user() +{ + case "$#" in + 1) + echo2 'groffer error: '"$1"; + ;; + *) + echo2 'groffer error: wrong number of arguments in error_user().'; + ;; + esac; + if test _"${_DEBUG_USER_WITH_STACK}"_ = _yes_ + then + func_stack_dump; + fi; + if test _"${_TMP_DIR}"_ != __ && test -d "${_TMP_DIR}" + then + : >"${_TMP_DIR}"/,error; + fi; + exit "${_ERROR}"; +} # error_user() + + + +############# +# exit_test () +# +# Test whether the former command ended with error(). Exit again. +# +# Globals: $_ERROR +# +exit_test() +{ + if test "$?" = "${_ERROR}" + then + exit ${_ERROR}; + fi; + if test _"${_TMP_DIR}"_ != __ && test -f "${_TMP_DIR}"/,error + then + exit ${_ERROR}; + fi; +} # exit_test() + + +######################################################################## +# Definition of normal Functions in alphabetical order +######################################################################## + +landmark "3: functions"; + +######################################################################## +# apropos_filespec () +# +# Compose temporary file for filspec. +# +# Globals: in: $_OPT_APROPOS, $_SPECIAL_SETUP, $_FILESPEC_ARG, +# $_APROPOS_PROG, $_APROPOS_SECTIONS, $_OPT_SECTIONS +# out: $_SPECIAL_FILESPEC +# +# Variable prefix: af +# +apropos_filespec() +{ + + func_check apropos_filespec '=' 0 "$@"; + if obj _OPT_APROPOS is_yes + then + if obj _SPECIAL_SETUP is_not_yes + then + error 'apropos_filespec(): apropos_setup() must be run first.'; + fi; + _SPECIAL_FILESPEC='yes'; + if obj _NO_FILESPECS is_yes + then + to_tmp_line '.SH no filespec'; + eval "${_APROPOS_PROG}" | sed -e 's/^/\\\&/' >>"${_TMP_CAT}"; + eval "${return_ok}"; + fi; + eval to_tmp_line \ + "'.SH $(echo1 "${_FILESPEC_ARG}" | sed 's/[^\\]-/\\-/g')'"; + exit_test; + if obj _APROPOS_SECTIONS is_empty + then + if obj _OPT_SECTIONS is_empty + then + s='^.*(..*).*$'; + else + s='^.*(['"$(echo1 "${_OPT_SECTIONS}" | sed -e 's/://g')"']'; + fi; + else + s='^.*(['"${_APROPOS_SECTIONS}"']'; + fi; +### apropos_filespec() + af_filespec="$(echo1 "${_FILESPEC_ARG}" | sed -e ' +s,/,\\/,g +s/\./\\./g +')"; + eval "${_APROPOS_PROG}" "'${_FILESPEC_ARG}'" | \ + sed -n -e ' +/^'"${af_filespec}"': /s/^\(.*\)$/\\\&\1/p +/'"$s"'/p +' | \ + sort |\ + sed -e ' +s/^\(.*(..*).*\) *- *\(.*\)$/\.br\n\.TP 15\n\.BR \"\1\"\n\\\&\2/ +' >>"${_TMP_CAT}"; + eval ${_UNSET} af_filespec; + eval "${return_ok}"; + else + eval "${return_bad}"; + fi; +} # apropos_filespec() + + +######################################################################## +# apropos_setup () +# +# Setup for the --apropos* options, just 2 global variables are set. +# +# Globals: in: $_OPT_APROPOS +# out: $_SPECIAL_SETUP, $_APROPOS_PROG +# +apropos_setup() +{ + func_check apropos_setup '=' 0 "$@"; + if obj _OPT_APROPOS is_yes + then + if is_prog apropos + then + _APROPOS_PROG='apropos'; + elif is_prog man + then + if man --apropos man >${_NULL_DEV} 2>${_NULL_DEV} + then + _APROPOS_PROG='man --apropos'; + elif man -k man >${_NULL_DEV} 2>${_NULL_DEV} + then + _APROPOS_PROG='man -k'; + fi; + fi; + if obj _APROPOS_PROG is_empty + then + error 'apropos_setup(): no apropos program available.'; + fi; + to_tmp_line '.TH GROFFER APROPOS'; + _SPECIAL_SETUP='yes'; + if obj _OPT_TITLE is_empty + then + _OPT_TITLE='apropos'; + fi; + eval "${return_ok}"; + else + eval "${return_bad}"; + fi; +} # apropos_setup() + + +######################################################################## +# base_name () +# +# Get the file name part of , i.e. delete everything up to last +# `/' from the beginning of . Remove final slashes, too, to get +# a non-empty output. The output is constructed according the shell +# program `basename'. +# +# Arguments : 1 +# Output : the file name part (without slashes) +# +# Variable prefix: bn +# +base_name() +{ + func_check base_name = 1 "$@"; + bn_name="$1"; + case "${bn_name}" in + */) + # delete all final slashes + bn_name="$(echo1 "${bn_name}" | sed -e 's|//*$||')"; + exit_test; + ;; + esac; + case "${bn_name}" in + '') + eval ${_UNSET} bn_name; + eval "${return_bad}"; + ;; + /) + # this is like `basename' does + echo1 '/'; + ;; + */*) + # delete everything before and including the last slash `/'. + echo1 "${bn_name}" | sed -e 's|^.*//*\([^/]*\)$|\1|'; + ;; + *) + obj bn_name echo1; + ;; + esac; + eval ${_UNSET} bn_name; + eval "${return_ok}"; +} # base_name() + + +######################################################################## +# cat_z () +# +# Decompress if possible or just print to standard output. +# gzip, bzip2, and .Z decompression is supported. +# +# Arguments: 1, a file name. +# Output: the content of , possibly decompressed. +# +cat_z() +{ + func_check cat_z = 1 "$@"; + case "$1" in + '') + error 'cat_z(): empty file name.'; + ;; + '-') + error 'cat_z(): for standard input use save_stdin().'; + ;; + esac; + if is_file "$1" + then + :; + else + error 'cat_z(): argument $1 is not a file.'; + fi; + if test -s "$1" + then + :; + else + eval "${return_ok}"; + fi; + if obj _HAS_COMPRESSION is_yes + then + if obj _HAS_BZIP is_yes + then + # test whether being compressed with bz2 + if bzip2 -t "$1" 2>${_NULL_DEV} + then + bzip2 -c -d "$1" 2>${_NULL_DEV}; + eval "${return_ok}"; + fi; + fi; + # if not compressed gzip acts like `cat' + gzip -c -d -f "$1" 2>${_NULL_DEV}; + else + cat "$1"; + fi; + eval "${return_ok}"; +} # cat_z() + + +######################################################################## +# clean_up () +# +# Do the final cleaning up before exiting; used by the trap calls. +# +# defined above + + +######################################################################## +# diag (*) +# +# Print marked message to standard error; useful for debugging. +# +# defined above + + +######################################################################## +landmark '4: dir_name()*'; +######################################################################## + +####################################################################### +# dir_name () +# +# Get the directory name of . The output is constructed +# according to the shell program `dirname'. +# +# Arguments : 1 +# Output : the directory part of +# +# Variable prefix: dn +# +dir_name() +{ + func_check dir_name = 1 "$@"; + obj_from_output dn_name dir_name_chop "$1"; + case "${dn_name}" in + ''|.) + echo1 '.'; + ;; + /) + echo1 '/'; + ;; + */*) + echo1 "$(echo1 "${dn_name}" | sed 's#/*[^/][^/]*$##')"; + ;; + *) + echo1 "${dn_name}"; + ;; + esac; + eval "${return_ok}"; +} # dir_name() + + +####################################################################### +# dir_name_append ( ) +# +# Append `name' to `dir' with clean handling of `/'. +# +# Arguments : 2 +# Output : the generated new directory name / +# +dir_name_append() +{ + func_check dir_name_append = 2 "$@"; + if is_empty "$1" + then + echo1 "$2"; + elif is_empty "$2" + then + echo1 "$1"; + else + dir_name_chop "$1"/"$2"; + fi; + eval "${return_ok}"; +} # dir_name_append() + + +######################################################################## +# dir_name_chop () +# +# Remove unnecessary slashes from directory name. +# +# Argument: 1, a directory name. +# Output: path without double, or trailing slashes. +# +# Variable prefix: dc +# +dir_name_chop() +{ + func_check dir_name_chop = 1 "$@"; + # replace all multiple slashes by a single slash `/'. + dc_res="$(echo1 "$1" | sed -e 's|///*|/|g')"; + exit_test; + case "${dc_res}" in + ?*/) + # remove trailing slash '/'; + echo1 "${dc_res}" | sed -e 's|/$||'; + ;; + *) + obj dc_res echo1 + ;; + esac; + eval ${_UNSET} dc_res; + eval "${return_ok}"; +} # dir_name_chop() + + +######################################################################## +# do_nothing () +# +# Dummy function that does nothing. +# +do_nothing() +{ + eval return "${_OK}"; +} # do_nothing() + + +######################################################################## +# echo1 (*) +# +# Print to standard output with final line break. +# +# defined above + + +######################################################################## +# echo2 (*) +# +# Print to standard error with final line break. +# +# defined above + + + +######################################################################## +# error (*) +# +# Print error message and exit with error code. +# +# defined above + + +######################################################################## +# exit_test () +# +# Test whether the former command ended with error(). Exit again. +# +# defined above + + +if test _"${_DEBUG_FUNC_CHECK}"_ = _yes_ +then + + ############# + # func_check ( "$@") + # + # This is called at the first line of each function. It checks the + # number of arguments of function and registers the + # function call 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. + # + # Variable prefix: fc + # + func_check() + { + if test "$#" -lt 3 + then + error 'func_check() needs at least 3 arguments.'; + fi; + fc_fname="$1"; + case "$3" in + 1) + fc_nargs="$3"; + fc_s=''; + ;; + 0|[2-9]) + fc_nargs="$3"; + fc_s='s'; + ;; + *) + error "func_check(): third argument must be a digit."; + ;; + esac; +### func_check() + case "$2" in + '='|'-eq') + fc_op='-eq'; + fc_comp='exactly'; + ;; + '>='|'-ge') + fc_op='-ge'; + fc_comp='at least'; + ;; + '<='|'-le') + fc_op='-le'; + fc_comp='at most'; + ;; + '<'|'-lt') + fc_op='-lt'; + fc_comp='less than'; + ;; + '>'|'-gt') + fc_op='-gt'; + fc_comp='more than'; + ;; + '!='|'-ne') + fc_op='-ne'; + fc_comp='not'; + ;; +### func_check() + *) + error \ + 'func_check(): second argument is not a relational operator.'; + ;; + esac; + shift; + shift; + shift; + if test "$#" "${fc_op}" "${fc_nargs}" + then + do_nothing; + else + error "func_check(): \ +${fc_fname}"'() needs '"${fc_comp} ${fc_nargs}"' argument'"${fc_s}"'.'; + fi; + func_push "${fc_fname}"; + if test _"${_DEBUG_STACKS}"_ = _yes_ + then + echo2 '+++ '"${fc_fname} $@"; + echo2 '>>> '"${_FUNC_STACK}"; + fi; + eval ${_UNSET} fc_comp; + eval ${_UNSET} fc_fname; + eval ${_UNSET} fc_nargs; + eval ${_UNSET} fc_op; + eval ${_UNSET} fc_s; + } # func_check() + + + ############# + # func_pop () + # + # Retrieve the top element from the function stack. This is called + # by every return variable in each function. + # + # The stack elements are separated by `!'; the popped element is + # identical to the original element, except that all `!' characters + # were removed. + # + # Arguments: 1 + # + func_pop() + { + if test "$#" -ne 0 + then + error 'func_pop() does not have arguments.'; + fi; + case "${_FUNC_STACK}" in + '') + if test _"${_DEBUG_STACKS}"_ = _yes_ + then + error 'func_pop(): stack is empty.'; + fi; + ;; + *!*) + # split at first bang `!'. + _FUNC_STACK="$(echo1 "${_FUNC_STACK}" | sed -e 's/^[^!]*!//')"; + exit_test; + ;; + *) + _FUNC_STACK=''; + ;; + esac; + if test _"${_DEBUG_STACKS}"_ = _yes_ + then + echo2 '<<< '"${_FUNC_STACK}"; + fi; + } # func_pop() + + + ############# + # func_push () + # + # Store another element to the function stack. This is called by + # func_check() at the beginning of each function. + # + # The stack elements are separated by `!'; if contains a `!' + # it is removed first. + # + # Arguments: 1 + # + # Variable prefix: fp + # + func_push() + { + if test "$#" -ne 1 + then + error 'func_push() needs 1 argument.'; + fi; + case "$1" in + *'!'*) + # remove all bangs `!'. + fp_element="$(echo1 "$1" | sed -e 's/!//g')"; + exit_test; + ;; + *) + fp_element="$1"; + ;; + esac; + if test _"${_FUNC_STACK}"_ = __ + then + _FUNC_STACK="${fp_element}"; + else + _FUNC_STACK="${fp_element}!${_FUNC_STACK}"; + fi; + eval ${_UNSET} fp_element; + } # func_push() + + + ############# + # func_stack_dump () + # + # Print the content of the function stack. Ignore the arguments. + # + func_stack_dump() + { + diag 'call stack(): '"${_FUNC_STACK}"; + } # func_stack_dump() + +else # $_DEBUG_FUNC_CHECK is not `yes' + + func_check() { return; } + func_pop() { return; } + func_push() { return; } + func_stack_dump() { return; } + +fi; # test of $_DEBUG_FUNC_CHECK + + +######################################################################## +# get_first_essential (*) +# +# Retrieve first non-empty argument. +# +# Return : `1' if all arguments are empty, `0' if found. +# Output : the retrieved non-empty argument. +# +# Variable prefix: gfe +# +get_first_essential() +{ + func_check get_first_essential '>=' 0 "$@"; + if is_equal "$#" 0 + then + eval "${return_ok}"; + fi; + for i + do + gfe_var="$i"; + if obj gfe_var is_not_empty + then + obj gfe_var echo1; + eval ${_UNSET} gfe_var; + eval "${return_ok}"; + fi; + done; + eval ${_UNSET} gfe_var; + eval "${return_bad}"; +} # get_first_essential() + + +######################################################################## +landmark '5: is_*()'; +######################################################################## + +######################################################################## +# is_dir () +# +# Test whether `name' is a readable directory. +# +# Arguments : 1 +# Return : `0' if arg1 is a directory, `1' otherwise. +# +is_dir() +{ + func_check is_dir '=' 1 "$@"; + if is_not_empty "$1" && test -d "$1" && test -r "$1" + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_dir() + + +######################################################################## +# is_empty () +# +# Test whether is empty. +# +# Arguments : <=1 +# Return : `0' if arg1 is empty or does not exist, `1' otherwise. +# +is_empty() +{ + func_check is_empty '=' 1 "$@"; + if test _"$1"_ = __ + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_empty() + + +######################################################################## +# is_empty_file () +# +# Test whether is an empty existing file. +# +# Arguments : <=1 +# Return : +# `0' if arg1 is an empty existing file +# `1' otherwise +# +is_empty_file() +{ + func_check is_empty_file '=' 1 "$@"; + if is_file "$1" + then + if test -s "$1" + then + eval "${return_no}"; + else + eval "${return_yes}"; + fi; + fi; + eval "${return_no}"; +} # is_empty_file() + + +######################################################################## +# is_equal ( ) +# +# Test whether is equal to . +# +# Arguments : 2 +# Return : `0' both arguments are equal strings, `1' otherwise. +# +is_equal() +{ + func_check is_equal '=' 2 "$@"; + if test _"$1"_ = _"$2"_ + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_equal() + + +######################################################################## +# is_existing () +# +# Test whether is an existing file or directory. Solaris 2.5 does +# not have `test -e'. +# +# Arguments : 1 +# Return : `0' if arg1 exists, `1' otherwise. +# +is_existing() +{ + func_check is_existing '=' 1 "$@"; + if is_empty "$1" + then + eval "${return_no}"; + fi; + if test -f "$1" || test -d "$1" || test -c "$1" + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_existing() + + +######################################################################## +# is_file () +# +# Test whether is a readable file. +# +# Arguments : 1 +# Return : `0' if arg1 is a readable file, `1' otherwise. +# +is_file() +{ + func_check is_file '=' 1 "$@"; + if is_not_empty "$1" && test -f "$1" && test -r "$1" + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_file() + + +######################################################################## +# is_greater_than ( ) +# +# Test whether is greater than . +# +# Arguments : 2 +# Return : `0' if is a greater integer than , +# `1' otherwise. +# +is_greater_than() +{ + func_check is_greater_than '=' 2 "$@"; + if is_integer "$1" && is_integer "$2" && test "$1" -gt "$2" + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_greater_than() + + +######################################################################## +# is_integer () +# +# Test whether `string' is an integer. +# +# Arguments : 1 +# Return : `0' if argument is an integer, `1' otherwise. +# +is_integer() +{ + func_check is_integer '=' 1 "$@"; + if is_equal "$(echo1 "$1" | sed -n -e ' +s/^[0-9][0-9]*$/ok/p +s/^[-+][0-9][0-9]*$/ok/p +')" 'ok' + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_integer() + + +######################################################################## +# is_not_empty_file () +# +# Test whether is a non-empty existing file. +# +# Arguments : <=1 +# Return : +# `0' if arg1 is a non-empty existing file +# `1' otherwise +# +is_not_empty_file() +{ + func_check is_not_empty_file '=' 1 "$@"; + if is_file "$1" && test -s "$1" + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_not_empty_file() + + +######################################################################## +# is_not_dir () +# +# Test whether is not a readable directory. +# +# Arguments : 1 +# Return : `0' if arg1 is a directory, `1' otherwise. +# +is_not_dir() +{ + func_check is_not_dir '=' 1 "$@"; + if is_dir "$1" + then + eval "${return_no}"; + fi; + eval "${return_yes}"; +} # is_not_dir() + + +######################################################################## +# is_not_empty () +# +# Test whether is not empty. +# +# Arguments : <=1 +# Return : `0' if arg1 exists and is not empty, `1' otherwise. +# +is_not_empty() +{ + func_check is_not_empty '=' 1 "$@"; + if is_empty "$1" + then + eval "${return_no}"; + fi; + eval "${return_yes}"; +} # is_not_empty() + + +######################################################################## +# is_not_equal ( ) +# +# Test whether differs from . +# +# Arguments : 2 +# +is_not_equal() +{ + func_check is_not_equal '=' 2 "$@"; + if is_equal "$1" "$2" + then + eval "${return_no}"; + fi + eval "${return_yes}"; +} # is_not_equal() + + +######################################################################## +# is_not_file () +# +# Test whether is a not readable file. +# +# Arguments : 1 (empty allowed) +# +is_not_file() +{ + func_check is_not_file '=' 1 "$@"; + if is_file "$1" + then + eval "${return_no}"; + fi; + eval "${return_yes}"; +} # is_not_file() + + +######################################################################## +# is_not_prog () +# +# Verify that is not a command in $PATH. +# +# Arguments : 1, can have spaces and arguments. +# +is_not_prog() +{ + func_check is_not_prog '=' 1 "$@"; + if where_is_prog "$1" >${_NULL_DEV} + then + eval "${return_no}"; + fi; + eval "${return_yes}"; +} # is_not_prog() + + +######################################################################## +# is_not_writable () +# +# Test whether is not a writable file or directory. +# +# Arguments : >=1 (empty allowed), more args are ignored +# +is_not_writable() +{ + func_check is_not_writable '>=' 1 "$@"; + if is_writable "$1" + then + eval "${return_no}"; + fi; + eval "${return_yes}"; +} # is_not_writable() + + +######################################################################## +# is_not_X () +# +# Test whether the script is not running in X Window by checking $DISPLAY. +# +is_not_X() +{ + func_check is_not_X '=' 0 "$@"; + if obj DISPLAY is_empty + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_not_X() + + +######################################################################## +# is_not_yes () +# +# Test whether is not `yes'. +# +# Arguments : 1 +# +is_not_yes() +{ + func_check is_not_yes = 1 "$@"; + if is_yes "$1" + then + eval "${return_no}"; + fi; + eval "${return_yes}"; +} # is_not_yes() + + +######################################################################## +# is_prog () +# +# Determine whether is a program in $PATH. +# +# Arguments : 1, can have spaces and arguments. +# +is_prog() +{ + func_check is_prog '=' 1 "$@"; + if where_is_prog "$1" >${_NULL_DEV} + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_prog() + + +######################################################################## +# is_writable () +# +# Test whether is a writable file or directory. +# +# Arguments : >=1 (empty allowed), more args are ignored +# +is_writable() +{ + func_check is_writable '>=' 1 "$@"; + if is_empty "$1" + then + eval "${return_no}"; + fi; + if test -r "$1" + then + if test -w "$1" + then + eval "${return_yes}"; + fi; + fi; + eval "${return_no}"; +} # is_writable() + + +######################################################################## +# is_X () +# +# Test whether the script is running in X Window by checking $DISPLAY. +# +is_X() +{ + func_check is_X '=' 0 "$@"; + if obj DISPLAY is_not_empty + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_X() + + +######################################################################## +# is_yes () +# +# Test whether has value `yes'. +# +# Return : `0' if arg1 is `yes', `1' otherwise. +# +is_yes() +{ + func_check is_yes '=' 1 "$@"; + if is_equal "$1" 'yes' + then + eval "${return_yes}"; + fi; + eval "${return_no}"; +} # is_yes() + + +######################################################################## +# 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 or with error . +# +leave() +{ + clean_up; + if test $# = 0 + then + exit "${_OK}"; + else + exit "$1"; + fi; +} # leave() + + +######################################################################## +landmark '6: list_*()'; +######################################################################## +# +# `list' is an object class that represents an array or list. Its +# data consists of space-separated single-quoted elements. So a list +# has the form "'first' 'second' '...' 'last'". See list_append() for +# more details on the list structure. The array elements of `list' +# can be get by `eval set x "$list"; shift`. + + +######################################################################## +# list_append ( ...) +# +# Add one or more elements to an existing list. may also be +# empty. +# +# Arguments: >=2 +# : a variable name for a list of single-quoted elements +# : some sequence of characters. +# Output: none, but $ is set to +# if is empty: "'' '...'" +# otherwise: "$list '' ..." +# +# Variable prefix: la +# +list_append() +{ + func_check list_append '>=' 2 "$@"; + la_name="$1"; + eval la_list='"${'"$1"'}"'; + shift; + for s + do + la_s="$s"; + case "${la_s}" in + *\'*) + # escape each single quote by replacing each + # "'" (squote) by "'\''" (squote bslash squote squote); + # note that the backslash must be doubled in the following `sed' + la_element="$(echo1 "${la_s}" | sed -e 's/'"${_SQ}"'/&\\&&/g')"; + exit_test; + ;; + '') + la_element=""; + ;; + *) + la_element="${la_s}"; + ;; + esac; +### list_append() + if obj la_list is_empty + then + la_list="'${la_element}'"; + else + la_list="${la_list} '${la_element}'"; + fi; + done; + eval "${la_name}"='"${la_list}"'; + eval ${_UNSET} la_element; + eval ${_UNSET} la_list; + eval ${_UNSET} la_name; + eval ${_UNSET} la_s; + eval "${return_ok}"; +} # list_append() + + +######################################################################## +# 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: >=1 +# : common part of a set of 4 environment variable names: +# $_SHORT_NA: list of short options without an arg. +# $_SHORT_ARG: list of short options that have an arg. +# $_LONG_NA: list of long options without an arg. +# $_LONG_ARG: list of long options that have an arg. +# ...: the arguments from a command line, such as "$@", +# the content of a variable, or direct arguments. +# +# Output: ['-[-]opt' ['optarg']]... '--' ['filename']... +# +# Example: +# list_from_cmdline PRE -a f1 -bcarg --lon=larg f2 low larg2 +# PRE_SHORT_NA="'a' 'b'" +# PRE_SHORT_ARG="'c' 'd'" +# PRE_LONG_NA="'help' 'version'" +# PRE_LONG_ARG="'longer' 'lower'" +# This will result in printing: +# '-a' '-b' '-c' 'arg' '--longer' 'larg' '--lower' 'larg2' '--' 'f1' 'f2' +# +# Use this function in the following way: +# eval set x "$(list_from_cmdline PRE_NAME "$@")"; +# shift; +# while test "$1" != '--'; do +# case "$1" in +# ... +# esac; +# shift; +# done; +# shift; #skip '--' +# # all positional parameters ("$@") left are file name parameters. +# +# Variable prefix: lfc +# +list_from_cmdline() +{ + func_check list_from_cmdline '>=' 1 "$@"; + # short options, no argument + obj_from_output lfc_short_n obj_data "$1"_SHORT_NA; + # short options, with argument + obj_from_output lfc_short_a obj_data "$1"_SHORT_ARG; + # long options, no argument + obj_from_output lfc_long_n obj_data "$1"_LONG_NA; + # long options, with argument + obj_from_output lfc_long_a obj_data "$1"_LONG_ARG; + if obj lfc_short_n is_empty + then + error 'list_from_cmdline(): no $'"$1"'_SHORT_NA options.'; + fi; + if obj lfc_short_a is_empty + then + error 'list_from_cmdline(): no $'"$1"'_SHORT_ARG options.'; + fi; + if obj lfc_long_n is_empty + then + error 'list_from_cmdline(): no $'"$1"'_LONG_NA options.'; + fi; + if obj lfc_long_a is_empty + then + error 'list_from_cmdline(): no $'"$1"'_LONG_ARG options.'; + fi; + shift; + + if is_equal "$#" 0 + then + echo1 "'--'" + eval ${_UNSET} lfc_fparams; + eval ${_UNSET} lfc_short_a; + eval ${_UNSET} lfc_short_n; +### list_from_cmdline() + eval ${_UNSET} lfc_long_a; + eval ${_UNSET} lfc_long_n; + eval ${_UNSET} lfc_result; + eval "${return_ok}"; + fi; + + lfc_fparams=''; + lfc_result=''; + while is_greater_than "$#" 0 + do + lfc_arg="$1"; + shift; + case "${lfc_arg}" in + --) break; ;; + --*=*) + # delete leading '--'; + lfc_with_equal="$(echo1 "${lfc_arg}" | sed -e 's/^--//')"; + # extract option by deleting from the first '=' to the end + lfc_abbrev="$(echo1 "${lfc_with_equal}" | \ + sed -e 's/^\([^=]*\)=.*$/\1/')"; + obj_from_output lfc_opt \ + list_single_from_abbrev lfc_long_a "${lfc_abbrev}"; + if obj lfc_opt is_empty + then + error_user "--${lfc_abbrev} is not an option."; + else + # get the option argument by deleting up to first `=' + lfc_optarg="$(echo1 "${lfc_with_equal}" | sed -e 's/^[^=]*=//')"; + exit_test; + list_append lfc_result "--${lfc_opt}" "${lfc_optarg}"; + continue; + fi; +### list_from_cmdline() + ;; + --*) + # delete leading '--'; + lfc_abbrev="$(echo1 "${lfc_arg}" | sed -e 's/^--//')"; + if list_has lfc_long_n "${lfc_abbrev}" + then + lfc_opt="${lfc_abbrev}"; + else + obj_from_output lfc_opt \ + list_single_from_abbrev lfc_long_n "${lfc_abbrev}"; + if obj lfc_opt is_not_empty && is_not_equal "$#" 0 + then + obj_from_output a \ + list_single_from_abbrev lfc_long_a "${lfc_abbrev}"; + if obj a is_not_empty + then + error_user "The abbreviation ${lfc_arg} \ +has multiple options: --${lfc_opt} and --${a}."; + fi; + fi; + fi; # if list_has lfc_long_n "${lfc_abbrev}" + if obj lfc_opt is_not_empty + then + # long option, no argument + list_append lfc_result "--${lfc_opt}"; + continue; + fi; + obj_from_output lfc_opt \ + list_single_from_abbrev lfc_long_a "${lfc_abbrev}"; + if obj lfc_opt is_not_empty + then +### list_from_cmdline() + # long option with argument + if is_equal "$#" 0 + then + error_user "no argument for option --${lfc_opt}." + fi; + list_append lfc_result "--${lfc_opt}" "$1"; + shift; + continue; + fi; # if obj lfc_opt is_not_empty + error_user "${lfc_arg} is not an option."; + ;; + -?*) # short option (cluster) + # delete leading `-'; + lfc_rest="$(echo1 "${lfc_arg}" | sed -e 's/^-//')"; + exit_test; + while obj lfc_rest is_not_empty + do + # get next short option from cluster (first char of $lfc_rest) + lfc_optchar="$(echo1 "${lfc_rest}" | sed -e 's/^\(.\).*$/\1/')"; + # remove first character from ${lfc_rest}; + lfc_rest="$(echo1 "${lfc_rest}" | sed -e 's/^.//')"; + exit_test; + if list_has lfc_short_n "${lfc_optchar}" + then + list_append lfc_result "-${lfc_optchar}"; + continue; + elif list_has lfc_short_a "${lfc_optchar}" + then + if obj lfc_rest is_empty + then + if is_greater_than "$#" 0 + then +### list_from_cmdline() + list_append lfc_result "-${lfc_optchar}" "$1"; + shift; + continue; + else + error_user "no argument for option -${lfc_optchar}."; + fi; + else # rest is the argument + list_append lfc_result "-${lfc_optchar}" "${lfc_rest}"; + lfc_rest=''; + continue; + fi; # if obj lfc_rest is_empty + else + error_user "unknown option -${lfc_optchar}."; + fi; # if list_has lfc_short_n "${lfc_optchar}" + done; # while obj lfc_rest is_not_empty + ;; + *) + # Here, $lfc_arg is not an option, so a file parameter. + list_append lfc_fparams "${lfc_arg}"; + + # Ignore the strange POSIX option handling to end option + # parsing after the first file name argument. To reuse it, do + # a `break' here if $POSIXLY_CORRECT of `bash' is not empty. + # When `bash' is called as `sh' $POSIXLY_CORRECT is set + # automatically to `y'. + ;; + esac; # case "${lfc_arg}" in + done; # while is_greater_than "$#" 0 + list_append lfc_result '--'; + if obj lfc_fparams is_not_empty + then + lfc_result="${lfc_result} ${lfc_fparams}"; + fi; +### list_from_cmdline() + if is_greater_than "$#" 0 + then + list_append lfc_result "$@"; + fi; + obj lfc_result echo1; + eval ${_UNSET} lfc_abbrev; + eval ${_UNSET} lfc_fparams; + eval ${_UNSET} lfc_short_a; + eval ${_UNSET} lfc_short_n; + eval ${_UNSET} lfc_long_a; + eval ${_UNSET} lfc_long_n; + eval ${_UNSET} lfc_result; + eval ${_UNSET} lfc_arg; + eval ${_UNSET} lfc_opt; + eval ${_UNSET} lfc_opt_arg; + eval ${_UNSET} lfc_opt_char; + eval ${_UNSET} lfc_with_equal; + eval ${_UNSET} lfc_rest; + eval "${return_ok}"; +} # list_from_cmdline() + + +######################################################################## +# list_from_cmdline_with_minus ( [...]) +# +# Transform command line arguments into a normalized form with a double +# abbreviation before and after an internal `-' sign. +# +# 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: >=1 +# : common part of a set of 4 environment variable names: +# $_SHORT_NA: list of short options without an arg. +# $_SHORT_ARG: list of short options that have an arg. +# $_LONG_NA: list of long options without an arg. +# $_LONG_ARG: list of long options that have an arg. +# ...: the arguments from a command line, such as "$@", +# the content of a variable, or direct arguments. +# +# Output: ['-[-]opt' ['optarg']]... '--' ['filename']... +# +# Example: +# list_from_cmdline PRE -a f1 -bcarg --lon=larg --h-n f2 low larg2 +# PRE_SHORT_NA="'a' 'b'" +# PRE_SHORT_ARG="'c' 'd'" +# PRE_LONG_NA="'help' 'version' 'hi-non-arg'" +# PRE_LONG_ARG="'long-arg' 'low-arg'" +# This will result in printing: +# '-a' '-b' '-c' 'arg' '--long-arg' 'larg' '--hi-non-arg' \ +# '--low-arg' 'larg2' '--' 'f1' 'f2' +# +# Use this function in the following way: +# eval set x "$(list_from_cmdline_with_minus PRE_NAME "$@")"; +# shift; +# while test "$1" != '--'; do +# case "$1" in +# ... +# esac; +# shift; +# done; +# shift; #skip '--' +# # all positional parameters ("$@") left are file name parameters. +# +# Variable prefix: lfcwm +# +list_from_cmdline_with_minus() +{ + func_check list_from_cmdline_with_minus '>=' 1 "$@"; + # short options, no argument + obj_from_output lfcwm_short_n obj_data "$1"_SHORT_NA; + # short options, with argument + obj_from_output lfcwm_short_a obj_data "$1"_SHORT_ARG; + # long options, no argument + obj_from_output lfcwm_long_n obj_data "$1"_LONG_NA; + # long options, with argument + obj_from_output lfcwm_long_a obj_data "$1"_LONG_ARG; + if obj lfcwm_short_n is_empty + then + error 'list_from_cmdline(): no $'"$1"'_SHORT_NA options.'; + fi; + if obj lfcwm_short_a is_empty + then + error 'list_from_cmdline(): no $'"$1"'_SHORT_ARG options.'; + fi; + if obj lfcwm_long_n is_empty + then + error 'list_from_cmdline(): no $'"$1"'_LONG_NA options.'; + fi; + if obj lfcwm_long_a is_empty + then + error 'list_from_cmdline(): no $'"$1"'_LONG_ARG options.'; + fi; + shift; + + if is_equal "$#" 0 + then + echo1 "'--'"; + eval ${_UNSET} lfcwm_short_a; + eval ${_UNSET} lfcwm_short_n; +### list_from_cmdline_with_minus() + eval ${_UNSET} lfcwm_long_a; + eval ${_UNSET} lfcwm_long_n; + eval "${return_ok}"; + fi; + obj_from_output lfcwm_long_both lists_combine lfcwm_long_a lfcwm_long_n; + lfcwm_fparams=''; + lfcwm_result=''; + while is_greater_than "$#" 0 # command line arguments + do + lfcwm_arg="$1"; + shift; + lfcwm_optarg=''; + case "${lfcwm_arg}" in + --) + break; + ;; + --*=*) + # delete leading '--'; + lfcwm_with_equal="$(echo1 "${lfcwm_arg}" | sed -e 's/^--//')"; + # extract option by deleting from the first '=' to the end + lfcwm_abbrev="$(echo1 "${lfcwm_with_equal}" | \ + sed -e 's/^\([^=]*\)=.*$/\1/')"; + # extract option argument by deleting up to the first '=' + lfcwm_optarg="$(echo1 "${lfcwm_with_equal}" | \ + sed -e 's/^[^=]*=\(.*\)$/\1/')"; +### list_from_cmdline_with_minus() + if list_has lfcwm_long_a "${lfcwm_abbrev}" + then + lfcwm_opt="${lfcwm_abbrev}"; + else + obj_from_output lfcwm_opt \ + _search_abbrev lfcwm_long_a "${lfcwm_abbrev}"; + fi; + list_append lfcwm_result "--${lfcwm_opt}" "${lfcwm_optarg}"; + continue; + ;; + --*) + # delete leading '--'; + lfcwm_abbrev="$(echo1 "${lfcwm_arg}" | sed -e 's/^--//')"; + if list_has lfcwm_long_both "${lfcwm_abbrev}" + then + lfcwm_opt="${lfcwm_abbrev}"; + else + obj_from_output lfcwm_opt \ + _search_abbrev lfcwm_long_both "${lfcwm_abbrev}"; + fi; +### list_from_cmdline_with_minus() + if list_has lfcwm_long_a "${lfcwm_opt}" + then + if is_equal "$#" 0 + then + error_user "Option ${lfcwm_opt} needs an argument."; + fi; + lfcwm_optarg="$1"; + shift; + list_append lfcwm_result "--${lfcwm_opt}" "${lfcwm_optarg}"; + else + list_append lfcwm_result "--${lfcwm_opt}"; + fi; + continue; + ;; + -?*) # short option (cluster) + # delete leading '-'; + lfcwm_rest="$(echo1 "${lfcwm_arg}" | sed -e 's/^-//')"; + while obj lfcwm_rest is_not_empty + do + # get next short option from cluster (first char of $lfcwm_rest) + lfcwm_optchar="$(echo1 "${lfcwm_rest}" | sed -e 's/^\(.\).*$/\1/')"; + # remove first character from ${lfcwm_rest}; + lfcwm_rest="$(echo1 "${lfcwm_rest}" | sed -e 's/^.//')"; + if list_has lfcwm_short_n "${lfcwm_optchar}" + then + list_append lfcwm_result "-${lfcwm_optchar}"; + continue; + elif list_has lfcwm_short_a "${lfcwm_optchar}" + then + if obj lfcwm_rest is_empty + then + if is_greater_than "$#" 0 + then +### list_from_cmdline_with_minus() + list_append lfcwm_result "-${lfcwm_optchar}" "$1"; + shift; + continue; + else + error_user "no argument for option -${lfcwm_optchar}."; + fi; + else # rest is the argument + list_append lfcwm_result "-${lfcwm_optchar}" "${lfcwm_rest}"; + lfcwm_rest=''; + continue; + fi; # if obj lfcwm_rest is_empty + else + error_user "unknown option -${lfcwm_optchar}."; + fi; # if list_has lfcwm_short_n "${lfcwm_optchar}" + done; # while obj lfcwm_rest is_not_empty + ;; + *) + # Here, $lfcwm_arg is not an option, so a file parameter. + list_append lfcwm_fparams "${lfcwm_arg}"; + + # Ignore the strange POSIX option handling to end option + # parsing after the first file name argument. To reuse it, do + # a `break' here if $POSIXLY_CORRECT of `bash' is not empty. + # When `bash' is called as `sh' $POSIXLY_CORRECT is set + # automatically to `y'. + ;; + esac; + done; + + list_append lfcwm_result '--'; + if obj lfcwm_fparams is_not_empty + then + lfcwm_result="${lfcwm_result} ${lfcwm_fparams}"; + fi; +### list_from_cmdline_with_minus() + if is_greater_than "$#" 0 + then + list_append lfcwm_result "$@"; + fi; + obj lfcwm_result echo1; + eval ${_UNSET} lfcwm_abbrev; + eval ${_UNSET} lfcwm_fparams; + eval ${_UNSET} lfcwm_short_a; + eval ${_UNSET} lfcwm_short_n; + eval ${_UNSET} lfcwm_long_a; + eval ${_UNSET} lfcwm_long_both; + eval ${_UNSET} lfcwm_long_n; + eval ${_UNSET} lfcwm_result; + eval ${_UNSET} lfcwm_arg; + eval ${_UNSET} lfcwm_opt; + eval ${_UNSET} lfcwm_optarg; + eval ${_UNSET} lfcwm_optchar; + eval ${_UNSET} lfcwm_with_equal; + eval ${_UNSET} lfcwm_rest; + eval "${return_ok}"; +} # list_from_cmdline_with_minus() + + +# _search_abbrev ( ) +# +# Check whether has an element constructed from the abbreviation +# . All `-' in are replaced by `-*'. This construction +# is searched first with `[^-]*'. If there is more than a +# single element an error is created. If none is found `*' +# is searched. Again an error is created for several results. +# This function was constructed from the former function +# list_single_from_abbrev(). +# +# This is a local function of list_from_cmdline_with_minus(). +# +# Arguments: 2 +# : a variable name for a list of single-quoted elements +# : some sequence of characters. +# +# Output: the found element (always not empty), error when none found. +# +# Variable prefix: _sa +# +_search_abbrev() +{ + func_check _search_abbrev '=' 2 "$@"; + eval _sa_list='"${'$1'}"'; + if obj _sa_list is_empty + then + error "_search_abbrev(): list is empty."; + fi; + + _sa_abbrev="$2"; + if obj _sa_abbrev is_empty + then + error "_search_abbrev(): abbreviation argument is empty."; + fi; + + _sa_case="$(echo1 "${_sa_abbrev}" | sed -e 's/-/\*-/g')"; + _sa_opt=''; + case " ${_sa_list}" in + *\ \'${_sa_case}*) # list has the abbreviation + _sa_m1=''; + _sa_m2=''; + _sa_nm=''; + eval set x "${_sa_list}"; + shift; + for i # over the option list + do + _sa_i="$i"; +### _search_abbrev() of list_from_cmdline_with_minus() + case "${_sa_i}" in + ${_sa_case}*-*) + if obj _sa_m1 is_empty + then + _sa_m1="${_sa_i}"; + continue; + fi; + _sa_m2="${_sa_i}"; + continue; + ;; + ${_sa_case}*) + if obj _sa_nm is_empty + then + _sa_nm="${_sa_i}"; + continue; + fi; + error_user "The abbreviation --${_sa_abbrev} has multiple options "\ +"--${_sa_nm} and --${_sa_i}."; + ;; + esac; + done; + if obj _sa_nm is_empty + then + if obj _sa_m2 is_not_empty + then + error_user "The abbreviation --${_sa_abbrev} has multiple options "\ +"--${_sa_m1} and --${_sa_m2}."; + fi; +### _search_abbrev() of list_from_cmdline_with_minus() + if obj _sa_m1 is_not_empty + then + _sa_opt="${_sa_m1}"; + fi; + else + _sa_opt="${_sa_nm}"; + fi; + ;; + esac; + if obj _sa_opt is_empty + then + error_user "--${_sa_abbrev} is not an option."; + fi; + obj _sa_opt echo1; + eval "${_UNSET}" _sa_abbrev; + eval "${_UNSET}" _sa_case; + eval "${_UNSET}" _sa_i; + eval "${_UNSET}" _sa_list; + eval "${_UNSET}" _sa_m1; + eval "${_UNSET}" _sa_m2; + eval "${_UNSET}" _sa_nm; + eval "${_UNSET}" _sa_opt; + eval "${return_ok}"; +} # _search_abbrev() of list_from_cmdline_with_minus() + + +######################################################################## +# list_from_file ( ) +# +# Extrect the lines from and store them as elements to list +# . +# +# Arguments: 2 +# : a variable name for output, a list of single-quoted elts +# : the name of an existing file +# +# Variable prefix: lff +# +list_from_file() +{ + func_check list_from_file '=' 2 "$@"; + if is_not_file "$2" + then + eval "${return_bad}"; + fi; + lff_n="$(wc -l "$2" | eval sed -e "'s/^[ ${_TAB}]*\([0-9]\+\).*$/\1/'")"; + eval "$1"="''"; + if obj lff_n is_equal 0 + then + eval "${return_good}"; + fi; + lff_i=0; + while obj lff_i is_not_equal "${lff_n}" + do + lff_i="$(expr "${lff_i}" + 1)"; + list_append "$1" "$(eval sed -n -e "'${lff_i}p +${lff_i}q'" "'$2'")"; + done; + eval "${_UNSET}" lff_i; + eval "${_UNSET}" lff_n; + eval "${return_good}"; +} # list_from_file() + + +######################################################################## +# list_from_split ( ) +# +# Split by into a list, omitting the separator. +# +# Arguments: 2: a that is to be split into parts divided by +# character +# Output: the resulting list string +# +# Variable prefix: lfs +# +list_from_split() +{ + func_check list_from_split = 2 "$@"; + if is_empty "$1" + then + eval "${return_ok}"; + fi; + case "$2" in + ?) + lfs_splitter="$2"; + ;; + '\:') + lfs_splitter=':'; + ;; + *) + error "list_from_split(): split argument $2 must be a single character."; + ;; + esac; + lfs_list=''; + lfs_rest="$1"; + while : + do + case "${lfs_rest}" in + *${lfs_splitter}*) + case "${lfs_splitter}" in + /) + lfs_elt="$(echo1 ${lfs_rest} | sed -e \ + 's|^\([^'"${lfs_splitter}"']*\)'"${lfs_splitter}"'.*|\1|')"; + lfs_rest="$(echo1 ${lfs_rest} | sed -e \ + 's|^[^'"${lfs_splitter}"']*'"${lfs_splitter}"'\(.*\)$|\1|')"; + ;; + *) +### list_from_split() + lfs_elt="$(echo1 ${lfs_rest} | sed -e \ + 's/^\([^'"${lfs_splitter}"']*\)'"${lfs_splitter}"'.*/\1/')"; + lfs_rest="$(echo1 ${lfs_rest} | sed -e \ + 's/^[^'"${lfs_splitter}"']*'"${lfs_splitter}"'\(.*\)$/\1/')"; + ;; + esac; + list_append lfs_list "${lfs_elt}" + continue; + ;; + *) + list_append lfs_list "${lfs_rest}" + break + ;; + esac; + done + echo1 "${lfs_list}"; + + eval ${_UNSET} lfs_elt; + eval ${_UNSET} lfs_list; + eval ${_UNSET} lfs_rest; + eval ${_UNSET} lfs_splitter; + eval "${return_ok}"; +} # list_from_split() + + +######################################################################## +# list_has ( ) +# +# Test whether the list has the element . +# +# Arguments: 2 +# : a variable name for a list of single-quoted elements +# : some sequence of characters. +# +# Variable prefix: lh +# +list_has() +{ + func_check list_has = 2 "$@"; + eval lh_list='"${'$1'}"'; + if obj lh_list is_empty + then + eval "${_UNSET}" lh_list; + eval "${return_no}"; + fi; + case "$2" in + \'*\') lh_element=" $2 "; ;; + *) lh_element=" '$2' "; ;; + esac; + if string_contains " ${lh_list} " "${lh_element}" + then + eval "${_UNSET}" lh_list; + eval "${_UNSET}" lh_element; + eval "${return_yes}"; + else + eval "${_UNSET}" lh_list; + eval "${_UNSET}" lh_element; + eval "${return_no}"; + fi; +} # list_has() + + +######################################################################## +# list_has_abbrev ( ) +# +# Test whether the list of has an element starting with +# . +# +# Arguments: 2 +# : a variable name for a list of single-quoted elements +# : some sequence of characters. +# +# Variable prefix: lha +# +list_has_abbrev() +{ + func_check list_has_abbrev '=' 2 "$@"; + eval lha_list='"${'$1'}"'; + if obj lha_list is_empty + then + eval "${_UNSET}" lha_list; + eval "${return_no}"; + fi; + case "$2" in + \'*) + lha_element="$(echo1 "$2" | sed -e 's/'"${_SQ}"'$//')"; + ;; + *) + lha_element="'$2"; + ;; + esac; + if string_contains " ${lha_list}" " ${lha_element}" + then + eval "${_UNSET}" lha_list; + eval "${_UNSET}" lha_element; + eval "${return_yes}"; + else + eval "${_UNSET}" lha_list; + eval "${_UNSET}" lha_element; + eval "${return_no}"; + fi; + eval "${return_ok}"; +} # list_has_abbrev() + + +######################################################################## +# list_has_not ( ) +# +# Test whether has no . +# +# Arguments: 2 +# : a space-separated list of single-quoted elements. +# : some sequence of characters. +# +# Variable prefix: lhn +# +list_has_not() +{ + func_check list_has_not = 2 "$@"; + eval lhn_list='"${'$1'}"'; + if obj lhn_list is_empty + then + eval "${_UNSET}" lhn_list; + eval "${return_yes}"; + fi; + case "$2" in + \'*\') lhn_element=" $2 "; ;; + *) lhn_element=" '$2' "; ;; + esac; + if string_contains " ${lhn_list} " "${lhn_element}" + then + eval "${_UNSET}" lhn_list; + eval "${_UNSET}" lhn_element; + eval "${return_no}"; + else + eval "${_UNSET}" lhn_list; + eval "${_UNSET}" lhn_element; + eval "${return_yes}"; + fi; +} # list_has_not() + + +######################################################################## +# list_single_from_abbrev ( ) +# +# Check whether the list has an element starting with . If +# there are more than a single element an error is raised. +# +# Arguments: 2 +# : a variable name for a list of single-quoted elements +# : some sequence of characters. +# +# Output: the found element. +# +# Variable prefix: lsfa +# +list_single_from_abbrev() +{ + func_check list_single_from_abbrev '=' 2 "$@"; + eval lsfa_list='"${'$1'}"'; + if obj lsfa_list is_empty + then + eval "${_UNSET}" lsfa_list; + eval "${return_no}"; + fi; + lsfa_abbrev="$2"; + if list_has lsfa_list "${lsfa_abbrev}" + then + obj lsfa_abbrev echo1; + eval "${_UNSET}" lsfa_abbrev; + eval "${_UNSET}" lsfa_list; + eval "${return_yes}"; + fi; + if list_has_abbrev lsfa_list "${lsfa_abbrev}" + then + lsfa_element=''; + eval set x "${lsfa_list}"; + shift; +### list_single_from_abbrev() + for i + do + case "$i" in + ${lsfa_abbrev}*) + if obj lsfa_element is_not_empty + then + error_user "The abbreviation --${lsfa_abbrev} \ +has multiple options: --${lsfa_element} and --${i}."; + fi; + lsfa_element="$i"; + ;; + esac; + done; + obj lsfa_element echo1; + eval "${_UNSET}" lsfa_abbrev; + eval "${_UNSET}" lsfa_element; + eval "${_UNSET}" lsfa_list; + eval "${return_yes}"; + else + eval "${_UNSET}" lsfa_abbrev; + eval "${_UNSET}" lsfa_element; + eval "${_UNSET}" lsfa_list; + eval "${return_no}"; + fi; +} # list_single_from_abbrev() + + +######################################################################## +# list_uniq () +# +# Generate a list with only unique elements. +# +# Output: the corrected list +# +# Variable prefix: lu +# +list_uniq() +{ + func_check list_uniq '=' 1 "$@"; + if is_empty "$1" + then + eval "${return_ok}"; + fi; + eval a='"${'"$1"'}"'; + if obj a is_empty + then + eval "${return_ok}"; + fi; + eval set x "$a"; + shift; + lu_list=''; + for i + do + lu_i="$i"; + if list_has lu_list "${lu_i}" + then + continue; + else + list_append lu_list ${lu_i}; + fi; + done; + obj lu_list echo1; + eval "${_UNSET}" lu_i; + eval "${_UNSET}" lu_list; + eval "${return_ok}"; +} # list_uniq() + + +######################################################################## +# lists_combine ( ...) +# +# Combine several lists to a single list. All arguments are list names. +# +# Output: the combined list +# +# Variable prefix: lc +# +lists_combine() +{ + func_check lists_combine '>=' 2 "$@"; + lc_list=''; + for i + do + eval lc_arg='"${'"$i"'}"'; + case "${lc_arg}" in + '') :; ;; + "'"*"'") + if obj lc_list is_empty + then + lc_list="${lc_arg}"; + else + lc_list="${lc_list} ${lc_arg}"; + fi; + ;; + *) + error 'lists_combine(): $'"$i"' is not a list.'; + ;; + esac; + done; + obj lc_list echo1; + eval "${_UNSET}" lc_arg; + eval "${_UNSET}" lc_list; + eval "${return_ok}"; +} # lists_combine() + + +######################################################################## +landmark '7: man_*()'; +######################################################################## + +######################################################################## +# Information on the search of man pages in groffer + +# The search of man pages is based on a set of directories. That +# starts with the so-called man path. This is determined in function +# man_setup() either by the command-line option --manpath, by $MANOPT, +# or by $MANPATH. There is also a program `manpath'. If all of this +# does not work a man path is created from $PATH with function +# manpath_set_from_path(). We now have a set of existing directories +# for the search of man pages; usually they end with `/man'. + +# The directory set of the man path can be changed in 2 ways. If +# operating system names are given in $SYSTEM or by --systems on the +# command-line all man path directory will be appended by these names. +# The appended system names replace the original man path; but if no +# system name is set, the original man path is kept. In `groffer', +# this is done by the function manpath_add_lang_sys() in man_setup(). + +# The next addition for directories is the language. It is specified +# by --locale or by one of the environment variables $LC_ALL, +# $LC_MESSAGES, and $LANG. The language name of `C' or `POSIX' means +# the return to the default language (usually English); this deletes +# former language specifications. The language name and its +# abbreviation with 2 characters is appended to the man page +# directories. But these new arising directories are added to the man +# page, they do not replace it such as the system names did. This is +# done by function manpath_add_lang_sys() in man_setup() as well. + +# Now we have the basic set of directories for the search of man pages +# for given filespec arguments. The real directories with the man +# page source files are gotten by appending `man
' to each +# directory, where section is a single character of the form +# `[1-9on]'. + +# There you find files named according to the form +# .
[][], where `[]' means +# optional this time. is the name of the man page;
+# is the single character from the last paragraphe; the optional +# consists of some letters denoting special aspects for +# the section; and the optional is something like `.gz', +# `.Z', or `.bz2', meaning that the file is compressed. + +# If name, section. and extension are specified on the command-line +# the file of the form .
with or without +# are handled. The first one found according to the +# directory set for the section is shown. + +# If just name and section are specified on the command-line then +# first .
with or without are searched. +# If no matching file was found, .
with or +# without are searched for all possible extensions. + +# If only name is specified on the command-line then the section +# directories are searched by and by, starting with section `1', until +# a file is matched. + +# The function man_is_man() determines all suitable man files for a +# command-line argument, while man_get() searches the single matching +# file for display. + + +######################################################################## +# man_get ( [
[]]) +# +# Write a man page to the temporary file. +# +# Globals in: $_TMP_MANSPEC, $_MAN_SEC_CHARS, $_MAN_EXT, $_MAN_ALL +# +# Arguments: 1, 2, or 3 +# +# Variable prefix: mg +# +man_get() +{ + func_check man_get '>=' 1 "$@"; + if obj _TMP_MANSPEC is_empty + then + error 'man_get(): man_is_man() must be run first on '"$*".; + fi; + mg_name="$1"; + mg_sec="$2"; + if is_empty "$2" + then + mg_sec="${_MAN_SEC_CHARS}"; # take care it is not a single section + fi; + mg_ext="$3"; + if is_empty "$3" + then + mg_ext="${_MAN_EXT}"; + fi; + if obj _TMP_MANSPEC is_not_equal "${_TMP_DIR}/,man.${mg_sec}${mg_ext}:$1" + then + error 'man_get(): $_TMP_MANSPEC does not suit to the arguments '"$*".; + fi; +### man_get() + + if obj _MAN_ALL is_yes + then + list_from_file mg_list "${_TMP_MANSPEC}"; + eval set x ${mg_list}; + shift; + mg_ok='no'; + mg_list=''; + for f + do + mg_f="$f"; + if list_has mg_list "${mg_f}" + then + continue; + else + list_append mg_list "${mg_f}"; + fi; +### man_get() + if obj mg_f is_file + then + to_tmp "${mg_f}" && mg_ok='yes'; + fi; + done; + if obj mg_ok is_yes + then + register_title man:"${mg_name}"; + fi; + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_sec; + eval "${return_ok}"; + else # $_MAN_ALL is not 'yes' + if is_empty "$2" + then # no section from command line + if obj _MAN_SEC_LIST is_empty + then + m="${_MAN_AUTO_SEC_LIST}"; # list of all sections + else + m="${_MAN_SEC_LIST}"; # from --sections + fi; +### man_get() + for s in $(eval set x $m; shift; echo1 "$@") + do + mg_s="$s"; + list_from_file mg_list "${_TMP_MANSPEC}"; + eval set x ${mg_list}; + shift; + if obj mg_ext is_empty + then + for f + do + mg_f="$f"; + case "${mg_f}" in +*/man"${mg_s}"/"${mg_name}"."${mg_s}"|*/man"${mg_s}"/"${mg_name}"."${mg_s}".*) + if obj mg_f is_file + then + to_tmp "${mg_f}" && register_title "${mg_name}(${mg_s})"; + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_s; + eval ${_UNSET} mg_sec; + eval "${return_ok}"; + fi; + ;; + esac; # "$mg_f" + done; # for f + fi; # mg_ext is_empty +### man_get() + for f + do + mg_f="$f"; + case "${mg_f}" in + */man"${mg_s}"/"${mg_name}"."${mg_s}""${mg_ext}"*) + if obj mg_f is_file + then + to_tmp "${mg_f}" && register_title "${mg_name}(${mg_s})"; + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_s; + eval ${_UNSET} mg_sec; + eval "${return_ok}"; + fi; + ;; + esac; # "$mg_f" + done; # for f + done; # for s + else # $mg_sec is not empty, do with section + list_from_file mg_list "${_TMP_MANSPEC}"; + eval set x ${mg_list}; + shift; + if obj mg_ext is_empty + then + for f + do + mg_f="$f"; +### man_get() + case "${mg_f}" in +*/man"${mg_sec}"/"${mg_name}"."${mg_sec}"|\ +*/man"${mg_sec}"/"${mg_name}"."${mg_sec}".*) + if obj mg_f is_file + then + obj mg_f to_tmp && \ + register_title "${mg_name}(${mg_sec})"; + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_s; + eval ${_UNSET} mg_sec; + eval "${return_ok}"; + fi; + ;; + esac; + done; # for f + for f + do + mg_f="$f"; +### man_get() + case "${mg_f}" in +*/man"${mg_sec}"/"${mg_name}"."${mg_sec}"*) + if obj mg_f is_file + then + obj mg_f to_tmp && \ + register_title "${mg_name}(${mg_sec})"; + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_s; + eval ${_UNSET} mg_sec; + eval "${return_ok}"; + fi; + ;; + esac; + done; # for f + else # mg_ext is not empty + for f + do + mg_f="$f"; +### man_get() + case "${mg_f}" in +*/man"${mg_sec}"/"${mg_name}"."${mg_sec}""${mg_ext}"|\ +*/man"${mg_sec}"/"${mg_name}"."${mg_sec}""${mg_ext}".*) + if obj mg_f is_file + then + obj mg_f to_tmp && \ + register_title "${mg_name}(${mg_sec}${mg_ext})"; + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_s; + eval ${_UNSET} mg_sec; + eval "${return_ok}"; + fi; + ;; + esac; + done; # for f + for f + do + mg_f="$f"; +### man_get() + case "${mg_f}" in + */man"${mg_sec}"/"${mg_name}"."${mg_sec}""${mg_ext}"*) + if obj mg_f is_file + then + obj mg_f to_tmp && \ + register_title "${mg_name}(${mg_sec}${mg_ext})"; + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_s; + eval ${_UNSET} mg_sec; + eval "${return_ok}"; + fi; + ;; + esac; + done; # for f + fi; + fi; # $mg_sec + fi; # $_MAN_ALL + + eval ${_UNSET} mg_ext; + eval ${_UNSET} mg_f; + eval ${_UNSET} mg_list; + eval ${_UNSET} mg_name; + eval ${_UNSET} mg_sec; + eval ${_UNSET} mg_s; + eval "${return_ok}"; +} # man_get() + + +######################################################################## +# man_is_man ( [
[]]) +# +# Test whether exists as man page. +# +# Globals: in: $_TMP_MAN, $_MAN_SEC_CHARS, $_TMP_DIR, $_MAN_EXT, +# $_MAN_AUTO_SEC_CHARS +# out: $_TMP_MANSPEC +# +# Arguments: 1, 2, or 3 +# +# Variable prefix: mim +# +man_is_man() +{ + func_check man_is_man '>=' 1 "$@"; + if is_empty "$1" + then + _TMP_MANSPEC=''; + eval "${return_no}"; + fi; + if obj _TMP_DIR is_empty + then + error 'man_is_man(): main_init() must be run first.'; + fi; + if obj _MAN_IS_SETUP is_not_yes + then + error 'man_is_man(): man_setup() must be run first.'; + fi; + mim_sec="$2"; + if is_empty "$2" + then + mim_sec="${_MAN_SEC_CHARS}"; + fi; + if is_empty "$3" + then + mim_ext="${_MAN_EXT}"; + else + mim_ext="$3"; + fi; + _TMP_MANSPEC="${_TMP_DIR}/,man.${mim_sec}${mim_ext}:$1"; +### man_is_man() + if obj _TMP_MANSPEC is_not_file + then + if obj mim_sec is_empty + then + m="${_MAN_AUTO_SEC_CHARS}"; + eval grep "'/man$m/$1\.$m${mim_ext}'" \ + "${_TMP_MAN}" > "${_TMP_MANSPEC}"; + else + eval grep "'/man${mim_sec}/$1\.${mim_sec}${mim_ext}'" \ + "${_TMP_MAN}" > "${_TMP_MANSPEC}"; + fi; + fi; + eval ${_UNSET} mim_ext; + eval ${_UNSET} mim_sec; + if obj _TMP_MANSPEC is_empty_file + then + eval "${return_no}"; + else + eval "${return_yes}"; + fi; +} # man_is_man() + + +######################################################################## +# man_setup () +# +# Setup the variables $_MAN_* needed for man page searching. +# +# Globals: +# in: $_OPT_*, $_MANOPT_*, $LANG, $LC_MESSAGES, $LC_ALL, +# $MANPATH, $MANSEC, $PAGER, $SYSTEM, $MANOPT. +# out: $_MAN_PATH, $_MAN_LANG, $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2, +# $_MAN_SEC, $_MAN_ALL, $_TMP_MAN +# in/out: $_MAN_ENABLE +# +# The precedence for the variables related to `man' is that of GNU +# `man', i.e. +# +# $LANG; overridden by +# $LC_MESSAGES; overridden by +# $LC_ALL; this has the same precedence as +# $MANPATH, $MANSEC, $PAGER, $SYSTEM; overridden by +# $MANOPT; overridden by +# the groffer command line options. +# +# $MANROFFSEQ is ignored because grog determines the preprocessors. +# +# Variable prefix: ms +# +man_setup() +{ + func_check man_setup '=' 0 "$@"; + + if obj _MAN_IS_SETUP is_yes + then + eval "${return_ok}"; + fi; + _MAN_IS_SETUP='yes'; + + if obj _MAN_ENABLE is_not_yes + then + eval "${return_ok}"; + fi; + + # determine basic path for man pages + obj_from_output ms_path \ + get_first_essential "${_OPT_MANPATH}" "${_MANOPT_PATH}" "${MANPATH}"; + if obj ms_path is_empty && is_prog 'manpath' + then + obj_from_output ms_path manpath 2>${_NULL_DEV}; # not always available + fi; + if obj ms_path is_empty + then + manpath_set_from_path; + else + obj_from_output _MAN_PATH path_list "${ms_path}"; + fi; + if obj _MAN_PATH is_empty + then + _MAN_ENABLE="no"; + echo2 "man_setup(): man path is empty"; + eval ${_UNSET} ms_path; + eval "${return_ok}"; + fi; + obj_from_output _MAN_PATH list_uniq _MAN_PATH; +### man_setup() + + if obj _MAN_ALL is_not_yes + then + if obj _OPT_ALL is_yes || obj _MANOPT_ALL is_yes + then + _MAN_ALL='yes'; + else + _MAN_ALL='no'; + fi; + fi; + + ms_sys="$(get_first_essential \ + "${_OPT_SYSTEMS}" "${_MANOPT_SYS}" "${SYSTEM}")"; + if obj ms_sys is_not_empty + then + obj_from_output _MAN_SYS list_from_split "${ms_sys}" ','; + fi; + + obj_from_output ms_lang get_first_essential \ + "${_OPT_LANG}" "${LC_ALL}" "${LC_MESSAGES}" "${LANG}"; + case "${ms_lang}" in + C|POSIX) + _MAN_LANG=""; + _MAN_LANG2=""; + ;; + ?) + _MAN_LANG="${ms_lang}"; + _MAN_LANG2=""; + ;; + ??) + _MAN_LANG="${ms_lang}"; + _MAN_LANG2="${ms_lang}"; + ;; +### man_setup() + *) + _MAN_LANG="${ms_lang}"; + # get first two characters of $ms_lang + _MAN_LANG2="$(echo1 "${ms_lang}" | sed -e 's/^\(..\).*$/\1/')"; + exit_test; + ;; + esac; + # from now on, use only $_MAN_LANG*, forget about $_OPT_LANG, $LC_*. + + manpath_add_lang_sys; + obj_from_output _MAN_PATH list_uniq _MAN_PATH; + + obj_from_output _MAN_SEC get_first_essential \ + "${_OPT_SECTIONS}" "${_MANOPT_SEC}" "${MANSEC}"; + _MAN_SEC_LIST=""; + _MAN_SEC_CHARS=""; + case "${_MAN_SEC}" in + *:*) + eval set x "$(list_from_split "${_MAN_SEC}" :)"; + shift; + for s + do + if list_has _MAN_AUTO_SEC_LIST "$s" + then + list_append _MAN_SEC_LIST "$s"; + _MAN_SEC_CHARS="${_MAN_SEC_CHARS}$s"; + fi; + done + if obj _MAN_SEC_CHARS is_not_empty + then + _MAN_SEC_CHARS="[${_MAN_SEC_CHARS}]"; + fi; + ;; + *) + if list_has _MAN_AUTO_SEC_LIST "${_MAN_SEC}" + then + list_append _MAN_SEC_LIST "${_MAN_SEC}"; + _MAN_SEC_CHARS="[${_MAN_SEC}]"; + fi; + ;; + esac; + +### man_setup() + obj_from_output _MAN_EXT get_first_essential \ + "${_OPT_EXTENSION}" "${_MANOPT_EXTENSION}" "${EXTENSION}"; + + _TMP_MAN="$(tmp_create man)"; + + eval set x "${_MAN_PATH}"; + shift; + if is_not_equal "$#" 0 + then + for i + do + for j in "$i"/man* + do + find "$j" >>"${_TMP_MAN}"; + done + done; + fi; + + eval ${_UNSET} ms_lang; + eval ${_UNSET} ms_list; + eval ${_UNSET} ms_path; + eval ${_UNSET} ms_sys; + eval "${return_ok}"; +} # man_setup() + + +######################################################################## +landmark '8: manpath_*()'; +######################################################################## + +######################################################################## +# manpath_add_lang_sys () +# +# Add language and operating system specific directories to man path. +# +# Arguments : 0 +# Output : none +# Globals: +# in: $_MAN_SYS: a list of names of operating systems. +# $_MAN_LANG and $_MAN_LANG2: each a single name +# in/out: $_MAN_PATH: list of directories which shall have the `man?' +# subdirectories. +# +# Variable prefix: mals +# +manpath_add_lang_sys() +{ + func_check manpath_add_lang_sys '=' 0 "$@"; + if obj _MAN_PATH is_empty + then + eval "${return_ok}"; + fi; + if obj _MAN_SYS is_empty + then + mals_mp="${_MAN_PATH}"; + else + mals_mp=''; + eval set x "${_MAN_SYS}"; + shift; + for s + do + _manpath_add_sys "$s"; + done; + fi; + + if obj mals_mp is_not_empty + then + mals_lang_path=''; + if is_equal "$_MAN_LANG" "$_MAN_LANG2" + then + mals_man_lang2=''; + else + mals_man_lang2="${_MAN_LANG2}"; + fi; + for i in "${_MAN_LANG}" "${mals_man_lang2}" + do + if obj i is_empty + then + continue; + fi; +### manpath_add_lang_sys() + mals_lang="$i"; + eval set x "${mals_mp}"; + shift; + for p + do + obj_from_output mals_dir dir_name_append "${p}" "${mals_lang}"; + if obj mals_dir is_dir + then + list_append mals_lang_path "${mals_dir}"; + fi; + done; + done; + obj_from_output mals_mp lists_combine mals_lang_path mals_mp; + fi; + + _MAN_PATH="${mals_mp}"; + eval ${_UNSET} mals_dir; + eval ${_UNSET} mals_lang; + eval ${_UNSET} mals_lang_path; + eval ${_UNSET} mals_man_lang2; + eval ${_UNSET} mals_mp; + eval "${return_ok}"; +} # manpath_add_lang_sys() + + +# _manpath_add_sys () +# +# Append the existing subdirectories of man path directories to +# the list $mals_mp. +# +# Local function to manpath_add_lang_sys(). +# +# Argument: 1, a operating system name (for appending to a man path +# directory) +# +# Globals in: $_MAN_PATH +# Globals in/out: $mals_mp +# +# Variable prefix: _mas +# +_manpath_add_sys() +{ + func_check _manpath_add_sys '=' 1 "$@"; + case "$1" in + '') + :; + ;; + man) + obj_from_output mals_mp lists_combine mals_mp _MAN_PATH; + ;; + *) + _mas_sys="$1"; + eval set x "${_MAN_PATH}"; + shift; + for p + do + obj_from_output _mas_dir dir_name_append "${p}" "${_mas_sys}"; + if obj _mas_dir is_dir + then + list_append mals_mp "${_mas_dir}"; + fi; + done; + ;; + esac; + eval ${_UNSET} _mas_dir; + eval ${_UNSET} _mas_sys; + eval "${return_ok}"; +} # _manpath_add_sys() of manpath_add_lang_sys() + + +######################################################################## +# manpath_set_from_path () +# +# Determine basic search path for man pages from $PATH. +# +# Return: `0' if a valid man path was retrieved. +# Output: none +# Globals: +# in: $PATH +# out: $_MAN_PATH +# +# Variable prefix: msfp +# +manpath_set_from_path() +{ + func_check manpath_set_from_path '=' 0 "$@"; + + msfp_manpath=''; + + # get a basic man path from $PATH + if obj PATH is_not_empty + then + # delete the final `/bin' part + p="$(echo1 "${PATH}" | sed -e 's|//*bin/*:|:|g')"; + obj_from_output msfp_list path_list "$p"; + # append some default directories + for b in /usr/local /usr/local /usr /usr \ + /usr/X11R6 /usr/openwin \ + /opt /opt/gnome /opt/kde + do + msfp_base="$b"; + if list_has_not msfp_list "${msfp_base}" && obj msfp_base is_dir + then + list_append msfp_list "${msfp_base}"; + fi; + done; + eval set x "${msfp_list}"; + shift; + for d + do + # including empty for former `/bin'. + msfp_base="$d"; + for e in /share/man /share/MAN /man /MAN + do + msfp_mandir="${msfp_base}$e"; + if obj msfp_mandir is_dir + then + list_append msfp_manpath "${msfp_mandir}"; + fi; + done; + done; + fi; + + _MAN_PATH="${msfp_manpath}"; + eval ${_UNSET} msfp_base; + eval ${_UNSET} msfp_list; + eval ${_UNSET} msfp_mandir; + eval ${_UNSET} msfp_manpath; + eval "${return_ok}"; +} # manpath_set_from_path() + + +######################################################################## +landmark '9: obj_*()'; +######################################################################## + +######################################################################## +# obj ( ...) +# +# This works like a method (object function) call for an object. +# Run " $ ...". +# +# The first argument represents an object name whose data is given as +# first argument to (). +# +# Argument: >=2 +# : variable name +# : a program or function name +# +# Variable prefix: o +# +obj() +{ + func_check obj '>=' 2 "$@"; + eval o_arg1='"${'$1'}"'; + if is_empty "$2" + then + error "obj(): function name is empty." + else + o_func="$2"; + fi; + shift; + shift; + eval "${o_func}"' "${o_arg1}" "$@"'; + n="$?"; + eval ${_UNSET} o_arg1; + eval ${_UNSET} o_func; + eval "${return_var} $n"; +} # obj() + + +######################################################################## +# obj_data () +# +# Print the data of , i.e. the content of $. +# For possible later extensions. +# +# Arguments: 1 +# : a variable name +# Output: the data of +# +# Variable prefix: od +# +obj_data() +{ + func_check obj_data '=' 1 "$@"; + if is_empty "$1" + then + error "obj_data(): object name is empty." + fi; + eval od_res='"${'"$1"'}"'; + obj od_res echo1; + eval ${_UNSET} od_res; + eval "${return_ok}"; +} # obj_data() + + +######################################################################## +# obj_from_output ( ...) +# +# Run '$="$( ...)"' to set the result of a +# function call to a global variable. Variables are not stored. +# +# Arguments: >=2 +# : a variable name +# : the name of a function or program +# : optional argument to +# Output: none +# +# Variable prefix: ofo +# +obj_from_output() +{ + func_check obj_from_output '>=' 2 "$@"; + if is_empty "$1" + then + error "obj_from_output(): variable name is empty."; + fi; + if is_empty "$2" + then + error "obj_from_output(): function name is empty." + fi; + ofo_result_name="$1"; + shift; + ofo_return=0; + if is_equal "$#" 0 + then + eval "${ofo_result_name}"'=""'; + else + ofo_list=''; + for i + do + list_append ofo_list "$i"; + done; + eval "${ofo_result_name}"'="$('"${ofo_list}"')"'; + ofo_return="$?"; + exit_test; + fi; + r="${ofo_return}"; + eval ${_UNSET} ofo_list; + eval ${_UNSET} ofo_return; + eval ${_UNSET} ofo_result_name; + eval "${return_var} $r"; +} # obj_from_output() + + +######################################################################## +# obj_set ( ) +# +# Set the data of , i.e. call "$=". +# +# Arguments: 2 +# : a variable name +# : a string +# Output:: none +# +obj_set() +{ + func_check obj_set '=' 2 "$@"; + if is_empty "$1" + then + error "obj_set(): object name is empty." + fi; + eval "$1"='"$2"'; + eval "${return_ok}"; +} # obj_set() + + +######################################################################## +# path_chop () +# +# Remove unnecessary colons from path. +# +# Argument: 1, a colon separated path. +# Output: path without leading, double, or trailing colons. +# +path_chop() +{ + func_check path_chop = 1 "$@"; + + # replace multiple colons by a single colon `:' + # remove leading and trailing colons + echo1 "$1" | sed -e ' +s/^:*// +s/:::*/:/g +s/:*$// +'; + eval "${return_ok}"; +} # path_chop() + + +######################################################################## +# path_clean () +# +# Remove non-existing directories from a colon-separated list. +# +# Argument: 1, a colon separated path. +# Output: colon-separated list of existing directories. +# +# Variable prefix: pc +# +path_clean() +{ + func_check path_clean = 1 "$@"; + if is_not_equal "$#" 1 + then + error 'path_clean() needs 1 argument.'; + fi; + pc_arg="$1"; + eval set x "$(path_list "${pc_arg}")"; + exit_test; + shift; + pc_res=""; + for i + do + pc_i="$i"; + if obj pc_i is_not_empty \ + && obj pc_res path_not_contains "${pc_i}" \ + && obj pc_i is_dir + then + case "${pc_i}" in + ?*/) + pc_res="${pc_res}:$(dir_name_chop "${pc_i}")"; + exit_test; + ;; + *) + pc_res="${pc_res}:${pc_i}"; + ;; + esac; + fi; + done; + path_chop "${pc_res}"; + eval ${_UNSET} pc_arg; + eval ${_UNSET} pc_i; + eval ${_UNSET} pc_res; + eval "${return_ok}"; +} # path_clean() + + +######################################################################## +# path_contains ( ) +# +# Test whether is contained in , a list separated by `:'. +# +# Arguments : 2 +# Return : `0' if arg2 is substring of arg1, `1' otherwise. +# +path_contains() +{ + func_check path_contains = 2 "$@"; + case ":$1:" in + *:${2}:*) + eval "${return_yes}"; + ;; + *) + eval "${return_no}"; + ;; + esac; + eval "${return_ok}"; +} # path_contains() + + +######################################################################## +# path_not_contains ( ) +# +# Test whether is not contained in colon separated . +# +# Arguments : 2 +# +path_not_contains() +{ + func_check path_not_contains = 2 "$@"; + if path_contains "$1" "$2" + then + eval "${return_no}"; + else + eval "${return_yes}"; + fi; + eval "${return_ok}"; +} # path_not_contains() + + +######################################################################## +# path_list () +# +# From a `:' separated path generate a list with unique elements. +# +# Arguments: 1: a colon-separated path +# Output: the resulting list, process it with `eval set' +# +# Variable prefix: pl +# +path_list() +{ + func_check path_list = 1 "$@"; + eval set x "$(list_from_split "$1" '\:')"; + shift; + pl_list=''; + for e + do + pl_elt="$e"; + if list_has pl_list "${pl_elt}" + then + continue; + else + list_append pl_list "${pl_elt}"; + fi; + done; + obj pl_list echo1; + eval ${_UNSET} pl_elt; + eval ${_UNSET} pl_list; + eval "${return_ok}"; +} # path_list() + + +######################################################################## +landmark '10: register_*()'; +######################################################################## + +######################################################################## +# register_file () +# +# Write a found file and register the title element. +# +# Arguments: 1: a file name +# Output: none +# +register_file() +{ + func_check register_file = 1 "$@"; + if is_empty "$1" + then + error 'register_file(): file name is empty'; + fi; + if is_equal "$1" '-' + then + to_tmp "${_TMP_STDIN}" && register_title 'stdin'; + else + to_tmp "$1" && register_title "$1"; + exit_test; + fi; + eval "${return_ok}"; +} # register_file() + + +######################################################################## +# register_title () +# +# Create title element from and append to $_REG_TITLE_LIST. +# Basename is created. +# +# Globals: $_REG_TITLE_LIST (rw) +# +# Variable prefix: rt +# +register_title() +{ + func_check register_title '=' 1 "$@"; + if is_empty "$1" + then + eval "${return_ok}"; + fi; + + if obj _DEBUG_PRINT_FILENAMES is_yes + then + if is_equal "$1" 'stdin' + then + echo2 "file: standard input"; + else + if obj _FILESPEC_IS_MAN is_yes + then + echo2 "file title: $1"; + else + echo2 "file: $1"; + fi; + fi; + fi; + + case "${_REG_TITLE_LIST}" in + *\ *\ *\ *) + eval "${return_ok}"; + ;; + esac; + + # remove directory part + obj_from_output rt_title base_name "$1"; + # replace space characters by `_' + rt_title="$(echo1 "${rt_title}" | sed -e 's/[ ]/_/g')"; + # remove extension `.bz2' + rt_title="$(echo1 "${rt_title}" | sed -e 's/\.bz2$//')"; + # remove extension `.gz' + rt_title="$(echo1 "${rt_title}" | sed -e 's/\.gz$//')"; + # remove extension `.Z' + rt_title="$(echo1 "${rt_title}" | sed -e 's/\.Z$//')"; + + if obj rt_title is_empty + then + eval ${_UNSET} rt_title; + eval "${return_ok}"; + fi; + list_append _REG_TITLE_LIST "${rt_title}"; + eval ${_UNSET} rt_title; + eval "${return_ok}"; +} # register_title() + + +######################################################################## +# reset () +# +# Reset the variables that can be affected by options to their default. +# +# +# Defined in section `Preset' after the rudimentary shell tests. + + +######################################################################## +# rm_file () +# +# Remove file. +# +rm_file() +{ + func_check rm_file '=' 1 "$@"; + if is_file "$1" + then + rm -f "$1" >${_NULL_DEV} 2>&1; + fi; + if is_existing "$1" + then + eval "${return_bad}"; + else + eval "${return_good}"; + fi; +} # rm_file() + + +######################################################################## +# rm_file_with_debug () +# +# Remove file if $_DEBUG_KEEP_FILES allows it. +# +# Globals: $_DEBUG_KEEP_FILES +# +rm_file_with_debug() +{ + func_check rm_file_with_debug '=' 1 "$@"; + if obj _DEBUG_KEEP_FILES is_not_yes + then + if is_file "$1" + then + rm -f "$1" >${_NULL_DEV} 2>&1; + fi; + fi; + if is_existing "$1" + then + eval "${return_bad}"; + else + eval "${return_good}"; + fi; +} # rm_file_with_debug() + + +######################################################################## +# rm_tree () +# +# Remove a file or a complete directory tree. +# +# Globals: $_DEBUG_KEEP_FILES +# +rm_tree() +{ + func_check rm_tree '=' 1 "$@"; + if is_existing "$1" + then + rm -f -r "$1" >${_NULL_DEV} 2>&1; + fi; + if is_existing "$1" + then + eval "${return_bad}"; + else + eval "${return_good}"; + fi; +} # rm_tree() + + +######################################################################## +# save_stdin () +# +# Store standard input to temporary file (with decompression). +# +# Variable prefix: ss +# +if obj _HAS_COMPRESSION is_yes +then + save_stdin() + { + func_check save_stdin '=' 0 "$@"; + ss_f="${_TMP_DIR}"/INPUT; + cat >"${ss_f}"; + cat_z "${ss_f}" >"${_TMP_STDIN}"; + rm_file "${ss_f}"; + eval ${_UNSET} ss_f; + eval "${return_ok}"; + } # save_stdin() +else # no compression + save_stdin() + { + func_check save_stdin '=' 0 "$@"; + cat >"${_TMP_STDIN}"; + eval "${return_ok}"; + } # save_stdin() +fi; + + +######################################################################## +# special_filespec () +# +# Handle special modes like whatis and apropos. Run their filespec +# functions if suitable. +# +# Globals: in: $_OPT_APROPOS, $_OPT_WHATIS, $_SPECIAL_SETUP +# out: $_SPECIAL_FILESPEC (internal) +# +special_filespec() +{ + func_check special_filespec '=' 0 "$@"; + if obj _OPT_APROPOS is_not_yes && obj _OPT_WHATIS is_not_yes + then + eval "${return_bad}"; + fi; + if obj _OPT_APROPOS is_yes && obj _OPT_WHATIS is_yes + then + error \ + 'special_filespec(): $_OPT_APROPOS and $_OPT_WHATIS are both "yes"'; + fi; + if obj _SPECIAL_SETUP is_not_yes + then + error 'special_filespec(): setup for apropos or whatis must be run first.'; + fi; + if apropos_filespec || whatis_filespec; + then + eval "${return_ok}"; + else + eval "${return_bad}"; + fi; +} # special_filespec() + + +######################################################################## +# special_setup () +# +# Handle special modes like whatis and apropos. Run their setup +# functions if suitable. +# +special_setup() +{ + func_check special_setup '=' 0 "$@"; + if obj _OPT_APROPOS is_yes && obj _OPT_WHATIS is_yes + then + error \ + 'special_setup(): $_OPT_APROPOS and $_OPT_WHATIS are both "yes"'; + fi; + if apropos_setup || whatis_setup + then + eval "${return_ok}"; + else + eval "${return_bad}"; + fi; +} # special_setup() + + +######################################################################## +landmark '11: stack_*()'; +######################################################################## + +######################################################################## +# string_contains ( ) +# +# Test whether is contained in . +# +# Arguments : 2 text arguments. +# Return : `0' if arg2 is substring of arg1, `1' otherwise. +# +string_contains() +{ + func_check string_contains '=' 2 "$@"; + case "$1" in + *${2}*) + eval "${return_yes}"; + ;; + *) + eval "${return_no}"; + ;; + esac; + eval "${return_ok}"; +} # string_contains() + + +######################################################################## +# string_not_contains ( ) +# +# Test whether is not substring of . +# +# Arguments : 2 text arguments. +# Return : `0' if arg2 is substring of arg1, `1' otherwise. +# +string_not_contains() +{ + func_check string_not_contains '=' 2 "$@"; + if string_contains "$1" "$2" + then + eval "${return_no}"; + else + eval "${return_yes}"; + fi; + eval "${return_ok}"; +} # string_not_contains() + + +######################################################################## +landmark '12: tmp_*()'; +######################################################################## + +######################################################################## +# tmp_cat () +# +# Output the temporary cat file (the concatenation of all input). +# +tmp_cat() +{ + func_check tmp_cat '=' 0 "$@"; + cat "${_TMP_CAT}"; + eval "${return_var}" "$?"; +} # tmp_cat() + + +######################################################################## +# tmp_create (?) +# +# Create temporary file. The generated name is `,' followed by +# . +# +# Argument: 0 or 1 +# +# Globals: $_TMP_DIR +# +# Output : name of created file +# +# Variable prefix: tc +# +tmp_create() +{ + func_check tmp_create '<=' 1 "$@"; + if obj _TMP_DIR is_empty || obj _TMP_DIR is_not_dir + then + error 'tmp_create(): there is no temporary directory.'; + else + # the output file does not have `,' as first character, so these are + # different names from the output file. + tc_tmp="${_TMP_DIR}/,$1"; + obj tc_tmp rm_file; + : >"${tc_tmp}" + obj tc_tmp echo1; + fi; + eval ${_UNSET} tc_tmp; + eval "${return_ok}"; +} # tmp_create() + + +######################################################################## +# to_tmp () +# +# Print file (decompressed) to the temporary cat file. +# +# Variable prefix: tt +# +to_tmp() +{ + func_check to_tmp '=' 1 "$@"; + if obj _TMP_CAT is_empty + then + error 'to_tmp(): $_TMP_CAT is not yet set'; + fi; + tt_1="$1"; + if is_file "${tt_1}" + then + tt_dir="$(dir_name "${tt_1}")"; + if obj _OPT_WHATIS is_yes + then + whatis_filename "${tt_1}" >>"${_TMP_CAT}"; + else + tt_file="${_TMP_DIR}/,file"; + if obj _FILESPEC_IS_MAN is_yes + then + if obj _DEBUG_PRINT_FILENAMES is_yes + then + echo2 "file: ${tt_1}"; + fi; + tt_tmp="${_TMP_DIR}/,tmp"; + cat_z "${tt_1}" >"${tt_file}"; + tt_sofile="${_TMP_DIR}/,so:"; + grep '^\.[ ]*so[ ]' "${tt_file}" | + sed -e 's/^\.[ ]*so[ ]*//' >"${tt_tmp}"; + list_from_file tt_list "${tt_tmp}"; + eval set x ${tt_list}; + shift; + for i in "$@" + do + tt_i="$i"; + tt_sofile="${tt_sofile}"'x'; + _do_man_so "${tt_i}"; + done; + rm_file "${tt_tmp}"; + mv "${tt_file}" "${tt_tmp}"; + cat "${tt_tmp}" | soelim -I "${tt_dir}" >"${tt_file}"; + rm_file "${tt_tmp}"; + else # $_FILESPEC_IS_MAN ist not yes + cat_z "${tt_1}" | soelim -I "${tt_dir}" >"${tt_file}"; + fi; +### to_tmp() + obj_from_output tt_grog grog "${tt_file}"; + case " ${tt_grog} " in + *\ -m*) + eval set x "$(echo1 " ${tt_grog} " | sed -e ' +s/'"${_TAB}"'/ /g +s/ */ /g +s/ -m / -m/g +s/ -mm\([^ ]\)/ -m\1/g +')"; + shift; + for i + do + tt_i="$i"; + case "${tt_i}" in + -m*) + if list_has _MACRO_PACKAGES "${tt_i}" + then + case "${_MACRO_PKG}" in + '') + _MACRO_PKG="${tt_i}"; + ;; + ${tt_i}) + :; + ;; + -m*) + echo2 "Ignore ${tt_1} because it needs ${tt_i} instead "\ +"of ${_MACRO_PKG}." + rm_file_with_debug "${tt_file}"; + eval ${_UNSET} tt_1; + eval ${_UNSET} tt_dir; + eval ${_UNSET} tt_file; + eval ${_UNSET} tt_grog; + eval ${_UNSET} tt_i; + eval ${_UNSET} tt_sofound; + eval ${_UNSET} tt_list; + eval ${_UNSET} tt_tmp; + eval "${return_bad}"; + ;; +### to_tmp() + *) + error \ +'to_tmp(): $_MACRO_PKG does not start with -m: '"${_MACRO_PKG}"; + ;; + esac; + fi; + ;; + esac; + done; + ;; + esac; + cat "${tt_file}" >>"${_TMP_CAT}"; + rm_file_with_debug "${tt_file}"; + fi; + else + error "to_tmp(): could not read file \`${tt_1}'."; + fi; + eval ${_UNSET} tt_1; + eval ${_UNSET} tt_dir; + eval ${_UNSET} tt_file; + eval ${_UNSET} tt_grog; + eval ${_UNSET} tt_i; + eval ${_UNSET} tt_sofound; + eval ${_UNSET} tt_list; + eval ${_UNSET} tt_tmp; + eval "${return_ok}"; +} # to_tmp() + + +############# +# _do_man_so () +# +# Handle single .so file name for man pages. +# +# Local function to to_tmp(). +# +# Globals from to_tmp(): $tt_tmp, $tt_sofile, $tt_file +# Globals: $_TMP_MAN +# +# Variable prefix: dms +# +_do_man_so() { + func_check _do_man_so '=' 1 "$@"; + _dms_so="$1"; # evt. with `\ ' + _dms_soname="$(echo $1 | sed -e 's/\\[ ]/ /g')"; # without `\ ' + case "${_dms_soname}" in + /*) # absolute path + if test -f "${_dms_soname}" + then + eval "${return_ok}"; + fi; + if test -f "${_dms_soname}"'.gz' + then + _dms_sofound="${_dms_soname}"'.gz'; + elif test -f "${_dms_soname}"'.Z' + then + _dms_sofound="${_dms_soname}"'.Z'; + elif test -f "${_dms_soname}"'.bz2' + then + _dms_sofound="${_dms_soname}"'.bz2'; + else + eval ${_UNSET} _dms_so; + eval ${_UNSET} _dms_soname; + eval "${return_ok}"; + fi; + ;; +### _do_man_so() of to_tmp() + *) # relative to man path + eval grep "'/${_dms_soname}\$'" "${_TMP_MAN}" >"${tt_tmp}"; + if is_empty_file "${tt_tmp}" + then + eval grep "'/${_dms_soname}.gz\$'" "${_TMP_MAN}" >"${tt_tmp}"; + if is_empty_file "${tt_tmp}" + then + eval grep "'/${_dms_soname}.Z\$'" "${_TMP_MAN}" >"${tt_tmp}"; + if is_empty_file "${tt_tmp}" + then + eval grep "'/${_dms_soname}.bz2\$'" "${_TMP_MAN}" >"${tt_tmp}"; + fi; + fi; + fi; + if is_empty_file "${tt_tmp}" + then + eval "${return_ok}"; + fi; + _dms_done='no'; + list_from_file _dms_list "${tt_tmp}"; + eval set x ${_dms_list}; + shift; + for i + do + _dms_sofound="$i"; + if obj _dms_sofound is_empty + then + continue; + fi; + _dms_done='yes'; + break; + done; +### _do_man_so() of to_tmp() + if obj _dms_done is_not_yes + then + eval ${_UNSET} _dms_done; + eval ${_UNSET} _dms_sofound; + eval "${return_ok}"; + fi; + ;; + esac; + if obj _DEBUG_PRINT_FILENAMES is_yes + then + echo2 "file from .so: ${_dms_so}"; + fi; + cat_z "${_dms_sofound}" >"${tt_sofile}"; + _dms_esc="$(echo ${_dms_so} | sed -e 's/\\/\\\\/g')"; + cat "${tt_file}" | eval sed -e \ +"'s#^\\.[ ]*so[ ]*\(${_dms_so}\|${_dms_esc}\|${_dms_soname}\)[ ]*\$'"\ +"'#.so ${tt_sofile}#'" \ + >"${tt_tmp}"; + rm_file "${tt_file}"; + mv "${tt_tmp}" "${tt_file}"; + eval ${_UNSET} _dms_done; + eval ${_UNSET} _dms_esc; + eval ${_UNSET} _dms_so; + eval ${_UNSET} _dms_sofound; + eval ${_UNSET} _dms_soname; + eval "${return_ok}"; +} # _do_man_so() of to_tmp() + + +######################################################################## +# to_tmp_line (...) +# +# Print single line with to the temporary cat file. +# +to_tmp_line() +{ + func_check to_tmp_line '>=' 1 "$@"; + if obj _TMP_CAT is_empty + then + error 'to_tmp_line(): $_TMP_CAT is not yet set'; + fi; + echo1 "$*" >>"${_TMP_CAT}"; + eval "${return_ok}"; +} # to_tmp_line() + + +######################################################################## +# trap_set +# +# Call function on signal 0. +# +trap_set() +{ + func_check trap_set '=' 0 "$@"; + trap 'clean_up' 0 2>${_NULL_DEV} || :; + eval "${return_ok}"; +} # trap_set() + + +######################################################################## +# trap_unset () +# +# Disable trap on signal 0. +# +trap_unset() +{ + func_check trap_unset '=' 0 "$@"; + trap '' 0 2>${_NULL_DEV} || :; + eval "${return_ok}"; +} # trap_unset() + + +######################################################################## +# usage () +# +# Print usage information to standard output; for groffer option --help. +# +usage() +{ + func_check usage = 0 "$@"; + echo; + version; + cat <) +# +# Print warning to stderr. +# +warning() +{ + echo2 "warning: $*"; +} # warning() + + +######################################################################## +# whatis_filename () +# +# Interpret as a man page and display its `whatis' +# information as a fragment written in the groff language. +# +# Globals: in: $_OPT_WHATIS, $_SPECIAL_SETUP, $_SPECIAL_FILESPEC, +# $_FILESPEC_ARG +# +# Variable prefix: wf +# +whatis_filename() +{ + func_check whatis_filename = 1 "$@"; + if obj _OPT_WHATIS is_not_yes + then + error 'whatis_filename(): $_OPT_WHATIS is not yes.'; + fi; + if obj _SPECIAL_SETUP is_not_yes + then + error \ + 'whatis_filename(): setup for whatis whatis_setup() must be run first.'; + fi; + if obj _SPECIAL_FILESPEC is_not_yes + then + error 'whatis_filename(): whatis_filespec() must be run first.'; + fi; + wf_arg="$1"; + if obj wf_arg is_not_file + then + error "whatis_filename(): argument is not a readable file." + fi; + wf_dot='^\.'"${_SPACE_SED}"'*'; +### whatis_filename() + if obj _FILESPEC_ARG is_equal '-' + then + wf_arg='stdin'; + fi; + cat <) +# +# Output path of a program and the given arguments if in $PATH. +# +# Arguments : 1, can have spaces and arguments. +# Output : list of 2 elements: prog name (with directory) and arguments +# Return : `0' if arg1 is a program in $PATH, `1' otherwise. +# +# Variable prefix: wip +# +where_is_prog() +{ + func_check where_is_prog '=' 1 "$@"; + if is_empty "$1" + then + eval "${return_bad}"; + fi; + + # Remove disturbing multiple spaces and tabs + wip_1="$(echo1 "$1" | sed -e 's/[ ][ ]*/ /g' | \ + sed -e 's/\(\\\)* / /g' | sed -e 's/^ //' | sed -e 's/ $//')"; + wip_noarg="$(echo1 "${wip_1}" | sed -e 's/ -.*$//')"; + exit_test; + + if obj wip_noarg is_empty + then + eval ${_UNSET} wip_1; + eval ${_UNSET} wip_noarg; + eval "${return_bad}"; + fi; + + case "${wip_1}" in + *\ -*) + wip_args="$(echo1 "${wip_1}" | + eval sed -e "'s#^${wip_noarg} ##'")"; + exit_test; + ;; + *) + wip_args=''; + ;; + esac; + + wip_result=''; +### where_is_prog() + + if test -f "${wip_noarg}" && test -x "${wip_noarg}" + then + list_append wip_result "${wip_noarg}" "${wip_args}"; + exit_test; + obj wip_result echo1; + exit_test; + eval ${_UNSET} wip_1; + eval ${_UNSET} wip_args; + eval ${_UNSET} wip_noarg; + eval ${_UNSET} wip_result; + eval "${return_ok}"; + fi; + + # test whether $wip_noarg has directory, so it is not tested with $PATH + case "${wip_noarg}" in + */*) + # now $wip_noarg (with /) is not an executable file + + # test name with space + obj_from_output wip_name base_name "${wip_noarg}"; + obj_from_output wip_dir dir_name "${wip_noarg}"; + case "${wip_name}" in + *\ *) + wip_base="$(echo1 "${wip_name}" | sed -e 's/ .*$//')"; + exit_test; + obj_from_output wip_file dir_name_append "${wip_dir}" "${wip_base}"; + exit_test; +### where_is_prog() + if test -f "${wip_file}" && test -x "${wip_file}" + then + wip_baseargs="$(echo1 "${wip_name}" | + eval sed -e "'s#^${wip_base} ##'")"; + exit_test; + if obj wip_args is_empty + then + wip_args="${wip_baseargs}"; + else + wip_args="${wip_baseargs} ${wip_args}"; + fi; + + list_append wip_result "${wip_file}" "${wip_args}"; + exit_test; + obj wip_result echo1; + exit_test; + eval ${_UNSET} wip_1; + eval ${_UNSET} wip_args; + eval ${_UNSET} wip_base; + eval ${_UNSET} wip_baseargs; + eval ${_UNSET} wip_dir; + eval ${_UNSET} wip_file; + eval ${_UNSET} wip_name; + eval ${_UNSET} wip_noarg; + eval ${_UNSET} wip_result; + eval "${return_ok}"; + fi; # test ${wip_file} + ;; + esac; # end of test name with space + +### where_is_prog() + eval ${_UNSET} wip_1; + eval ${_UNSET} wip_args; + eval ${_UNSET} wip_base; + eval ${_UNSET} wip_dir; + eval ${_UNSET} wip_name; + eval ${_UNSET} wip_noarg; + eval ${_UNSET} wip_result; + eval "${return_bad}"; + ;; + esac; # test of $wip_noarg on path with directory + + + # now $wip_noarg does not have a /, so it is checked with $PATH. + + eval set x "$(path_list "${PATH}")"; + exit_test; + shift; + + # test path with $win_noarg, evt. with spaces + for d + do + wip_dir="$d"; + obj_from_output wip_file dir_name_append "${wip_dir}" "${wip_noarg}"; +### where_is_prog() + + # test $win_file on executable file + if test -f "${wip_file}" && test -x "${wip_file}" + then + list_append wip_result "${wip_file}" "${wip_args}"; + exit_test; + obj wip_result echo1; + exit_test; + eval ${_UNSET} wip_1; + eval ${_UNSET} wip_dir; + eval ${_UNSET} wip_file; + eval ${_UNSET} wip_noarg; + eval ${_UNSET} wip_result; + eval "${return_ok}"; + fi; # test $win_file on executable file + done; # test path with $win_prog with spaces + + case "${wip_noarg}" in + *\ *) + # test on path with base name without space + wip_base="$(echo1 "${wip_noarg}" | sed -e 's/^\([^ ]*\) .*$/\1/')"; + exit_test; + for d + do + wip_dir="$d"; + obj_from_output wip_file dir_name_append "${wip_dir}" "${wip_base}"; + exit_test; +### where_is_prog() + + # test $win_file on executable file + if test -f "${wip_file}" && test -x "${wip_file}" + then + wip_baseargs="$(echo1 "${wip_noarg}" | + sed -e 's/[^ ]* \(.*\)$/\1/')"; + exit_test; + if obj wip_args is_empty + then + wip_args="${wip_baseargs}"; + else + wip_args="${wip_args} ${wip_baseargs}"; + fi; + list_append wip_result "${wip_file}" "${wip_args}"; + exit_test; + obj wip_result echo1; + exit_test; + eval ${_UNSET} wip_1; + eval ${_UNSET} wip_args; + eval ${_UNSET} wip_base; + eval ${_UNSET} wip_baseargs; + eval ${_UNSET} wip_dir; + eval ${_UNSET} wip_file; + eval ${_UNSET} wip_name; + eval ${_UNSET} wip_noarg; + eval ${_UNSET} wip_result; + eval "${return_ok}"; + fi; # test of $wip_file on executable file + done; # test path with base name without space +### where_is_prog() + ;; + esac; # test of $wip_noarg on space + + eval ${_UNSET} wip_1; + eval ${_UNSET} wip_args; + eval ${_UNSET} wip_base; + eval ${_UNSET} wip_baseargs; + eval ${_UNSET} wip_dir; + eval ${_UNSET} wip_file; + eval ${_UNSET} wip_name; + eval ${_UNSET} wip_noarg; + eval ${_UNSET} wip_result; + eval "${return_bad}"; +} # where_is_prog() + + +######################################################################## +# main* Functions +######################################################################## + +# The main area contains the following parts: +# - main_init(): initialize temporary files and set exit trap +# - main_parse_MANOPT(): parse $MANOPT +# - main_parse_args(): argument parsing +# - main_set_mode (): determine the display mode +# - main_do_fileargs(): process filespec arguments +# - main_set_resources(): setup X resources +# - main_display(): do the displaying +# - main(): the main function that calls all main_*() + + +####################################################################### +# main_init () +# +# Set exit trap and create temporary directory and some temporary files. +# +# Globals: $_TMP_DIR, $_TMP_CAT, $_TMP_STDIN +# +# Variable prefix: mi +# +main_init() +{ + func_check main_init = 0 "$@"; + # call clean_up() on shell termination. + trap_set; + + # create temporary directory + umask 0022; + _TMP_DIR=''; + for d in "${GROFF_TMPDIR}" "${TMPDIR}" "${TMP}" "${TEMP}" \ + "${TEMPDIR}" "${HOME}"'/tmp' '/tmp' "${HOME}" '.' + do + mi_dir="$d"; + if obj mi_dir is_empty || obj mi_dir is_not_dir || \ + obj mi_dir is_not_writable + then + continue; + fi; + + case "${mi_dir}" in + */) + _TMP_DIR="${mi_dir}"; + ;; + *) + _TMP_DIR="${mi_dir}"'/'; + ;; + esac; + _TMP_DIR="${_TMP_DIR}groffer${_PROCESS_ID}"; + if obj _TMP_DIR rm_tree + then + : + else + mi_tdir_="${_TMP_DIR}"_; + mi_n=1; + mi_tdir_n="${mi_tdir_}${mi_n}"; +### main_init() + while obj mi_tdir_n is_existing + do + if obj mi_tdir_n rm_tree + then + # directory could not be removed + mi_n="$(expr "${mi_n}" + 1)"; + mi_tdir_n="${mi_tdir_}${mi_n}"; + continue; + fi; + done; + _TMP_DIR="${mi_tdir_n}"; + fi; + eval mkdir "${_TMP_DIR}"; + if is_not_equal "$?" 0 + then + obj _TMP_DIR rm_tree; + _TMP_DIR=''; + continue; + fi; + if obj _TMP_DIR is_dir && obj _TMP_DIR is_writable + then + # $_TMP_DIR can now be used as temporary directory + break; + fi; + obj _TMP_DIR rm_tree; + _TMP_DIR=''; + continue; + done; + if obj _TMP_DIR is_empty + then + error "main_init(): \ +Couldn't create a directory for storing temporary files."; + fi; +### main_init() + if obj _DEBUG_PRINT_TMPDIR is_yes + then + echo2 "temporary directory: ${_TMP_DIR}"; + fi; + + obj_from_output _TMP_CAT tmp_create groffer_cat; + obj_from_output _TMP_STDIN tmp_create groffer_input; + + eval ${_UNSET} mi_dir; + eval ${_UNSET} mi_n; + eval ${_UNSET} mi_tdir_; + eval ${_UNSET} mi_tdir_n; + eval "${return_ok}"; +} # main_init() + + +######################################################################## +# main_parse_MANOPT () +# +# Parse $MANOPT to retrieve man options, but only if it is a non-empty +# string; found man arguments can be overwritten by the command line. +# +# Globals: +# in: $MANOPT, $_OPTS_MANOPT_* +# out: $_MANOPT_* +# +# Variable prefix: mpm +# +main_parse_MANOPT() +{ + func_check main_parse_MANOPT = 0 "$@"; + + if obj MANOPT is_not_empty + then + # Delete leading and final spaces + MANOPT="$(echo1 "${MANOPT}" | sed -e ' +s/^'"${_SPACE_SED}"'*// +s/'"${_SPACE_SED}"'*$// +')"; + exit_test; + fi; + if obj MANOPT is_empty + then + eval "${return_ok}"; + fi; + + mpm_list=''; + # add arguments in $MANOPT by mapping them to groffer options + eval set x "$(list_from_cmdline _OPTS_MANOPT "${MANOPT}")"; + exit_test; + shift; + until test "$#" -le 0 || is_equal "$1" '--' + do + mpm_opt="$1"; + shift; + case "${mpm_opt}" in + -7|--ascii) + list_append mpm_list '--ascii'; + ;; + -a|--all) + list_append mpm_list '--all'; + ;; +### main_parse_MANOPT() + -c|--catman) + do_nothing; + shift; + ;; + -d|--debug) + do_nothing; + ;; + -D|--default) + # undo all man options so far + mpm_list=''; + ;; + -e|--extension) + list_append mpm_list '--extension'; + shift; + ;; + -f|--whatis) + list_append mpm_list '--whatis'; + shift; + ;; + -h|--help) + do_nothing; + ;; + -k|--apropos) + # groffer's --apropos takes an argument, but man's does not, so + do_nothing; + ;; + -l|--local-file) + do_nothing; + ;; + -L|--locale) + list_append mpm_list '--locale' "$1"; + shift; + ;; +### main_parse_MANOPT() + -m|--systems) + list_append mpm_list '--systems' "$1"; + shift; + ;; + -M|--manpath) + list_append mpm_list '--manpath' "$1"; + shift; + ;; + -p|--preprocessor) + do_nothing; + shift; + ;; + -P|--pager) + list_append mpm_list '--pager' "$1"; + shift; + ;; + -r|--prompt) + do_nothing; + shift; + ;; + -S|--sections) + list_append mpm_list '--sections' "$1"; + shift; + ;; + -t|--troff) + do_nothing; + ;; + -T|--device) + list_append mpm_list '-T' "$1"; + shift; + ;; +### main_parse_MANOPT() + -u|--update) + do_nothing; + ;; + -V|--version) + do_nothing; + ;; + -w|--where|--location) + list_append mpm_list '--location'; + ;; + -Z|--ditroff) + do_nothing; + ;; + # ignore all other options + esac; + done; + + # prepend $mpm_list to the command line + if obj mpm_list is_not_empty + then + eval set x "${mpm_list}" '"$@"'; + shift; + fi; + + eval ${_UNSET} mpm_list; + eval ${_UNSET} mpm_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 +# +# Variable prefix: mpa +# +main_parse_args() +{ + func_check main_parse_args '>=' 0 "$@"; + obj_from_output _ALL_PARAMS list_from_cmdline_with_minus _OPTS_CMDLINE "$@"; + if obj _DEBUG_PRINT_PARAMS is_yes + then + echo2 "parameters: ${_ALL_PARAMS}"; + fi; + eval set x "${_ALL_PARAMS}"; + shift; + + # 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 + mpa_opt="$1"; # $mpa_opt is fed into the option handler + shift; + case "${mpa_opt}" in + -h|--help) + usage; + leave; + ;; + -Q|--source) # output source code (`Quellcode'). + _OPT_MODE='source'; + ;; +### main_parse_args() + -T|--device|--troff-device) # device; arg + _OPT_DEVICE="$1"; + _check_device_with_mode; + shift; + ;; + -v|--version) + version; + leave; + ;; + -V) + _OPT_V='yes'; + ;; + -Z|--ditroff|--intermediate-output) # groff intermediate output + _OPT_Z='yes'; + ;; + -X) + _OPT_MODE=X; + ;; + -?) + # delete leading `-' + mpa_optchar="$(echo1 "${mpa_opt}" | sed -e 's/^-//')"; + exit_test; + if list_has _OPTS_GROFF_SHORT_NA "${mpa_optchar}" + then + list_append _ADDOPTS_GROFF "${mpa_opt}"; + elif list_has _OPTS_GROFF_SHORT_ARG "${mpa_optchar}" + then + list_append _ADDOPTS_GROFF "${mpa_opt}" "$1"; + shift; +### main_parse_args() + else + error "main_parse_args(): Unknown option : \`$1'"; + fi; + ;; + --all) + _OPT_ALL='yes'; + ;; + --apropos) # run `apropos' + _OPT_APROPOS='yes'; + _APROPOS_SECTIONS=''; + _OPT_WHATIS='no'; + ;; + --apropos-data) # run `apropos' for data sections + _OPT_APROPOS='yes'; + _APROPOS_SECTIONS='457'; + _OPT_WHATIS='no'; + ;; + --apropos-devel) # run `apropos' for development sections + _OPT_APROPOS='yes'; + _APROPOS_SECTIONS='239'; + _OPT_WHATIS='no'; + ;; + --apropos-progs) # run `apropos' for program sections + _OPT_APROPOS='yes'; + _APROPOS_SECTIONS='168'; + _OPT_WHATIS='no'; + ;; +### main_parse_args() + --ascii) + list_append _ADDOPTS_GROFF '-mtty-char'; + if obj _OPT_MODE is_empty + then + _OPT_MODE='text'; + fi; + ;; + --auto) # the default automatic mode + _OPT_MODE=''; + ;; + --bd|--bordercolor) # border color for viewers, arg; + _OPT_BD="$1"; + shift; + ;; + --bg|--backgroud) # background color for viewers, arg; + _OPT_BG="$1"; + shift; + ;; + --bw|--borderwidth) # border width for viewers, arg; + _OPT_BW="$1"; + shift; + ;; + --debug|--debug-all|--debug-filenames|--debug-func|--debug-not-func|\ +--debug-keep|--debug-lm|--debug-params|--debug-shell|--debug-stacks|\ +--debug-tmpdir|--debug-user) + # debug is handled at the beginning + :; + ;; + --default) # reset variables to default + reset; + ;; +### main_parse_args() + --default-modes) # sequence of modes in auto mode; arg + _OPT_DEFAULT_MODES="$1"; + shift; + ;; + --display) # set X display, arg + _OPT_DISPLAY="$1"; + shift; + ;; + --do-nothing) + _OPT_DO_NOTHING='yes'; + ;; + --dvi) + _OPT_MODE='dvi'; + ;; + --dvi-viewer|--dvi-viewer-tty) # viewer program for dvi mode; arg + _OPT_VIEWER_DVI="$1"; + shift; + ;; + --extension) # the extension for man pages, arg + _OPT_EXTENSION="$1"; + shift; + ;; +### main_parse_args() + --fg|--foreground) # foreground color for viewers, arg; + _OPT_FG="$1"; + shift; + ;; + --fn|--ft|--font) # set font for viewers, arg; + _OPT_FN="$1"; + shift; + ;; + --geometry) # window geometry for viewers, arg; + _OPT_GEOMETRY="$1"; + shift; + ;; + --groff) + _OPT_MODE='groff'; + ;; + --html|--www) # display with web browser + _OPT_MODE=html; + ;; + --html-viewer|--www-viewer|--html-viewer-tty|--www-viewer-tty) + # viewer program for html mode; arg + _OPT_VIEWER_HTML="$1"; + shift; + ;; + --iconic) # start viewers as icons + _OPT_ICONIC='yes'; + ;; +### main_parse_args() + --locale) # set language for man pages, arg + # argument is xx[_territory[.codeset[@modifier]]] (ISO 639,...) + _OPT_LANG="$1"; + shift; + ;; + --local-file) # force local files; same as `--no-man' + _MAN_FORCE='no'; + _MAN_ENABLE='no'; + ;; + --location|--where) # print file locations to stderr + _DEBUG_PRINT_FILENAMES='yes'; + ;; + --man) # force all file params to be man pages + _MAN_ENABLE='yes'; + _MAN_FORCE='yes'; + ;; + --manpath) # specify search path for man pages, arg + # arg is colon-separated list of directories + _OPT_MANPATH="$1"; + shift; + ;; + --mode) # display mode + mpa_arg="$1"; + shift; + case "${mpa_arg}" in + auto|'') # search mode automatically among default + _OPT_MODE=''; + ;; + groff) # pass input to plain groff + _OPT_MODE='groff'; + ;; +### main_parse_args() + html|www) # display with a web browser + _OPT_MODE='html'; + ;; + dvi) # display with xdvi viewer + _OPT_MODE='dvi'; + ;; + pdf) # display with PDF viewer + _OPT_MODE='pdf'; + ;; + ps) # display with Postscript viewer + _OPT_MODE='ps'; + ;; + text) # output on terminal + _OPT_MODE='text'; + ;; + tty) # output on terminal + _OPT_MODE='tty'; + ;; + X|x) # output on X roff viewer + _OPT_MODE='x'; + ;; +### main_parse_args() + Q|source) # display source code + _OPT_MODE="source"; + ;; + *) + error "main_parse_args(): unknown mode ${mpa_arg}"; + ;; + esac; + ;; + --no-location) # disable former call to `--location' + _DEBUG_PRINT_FILENAMES='no'; + ;; + --no-man) # disable search for man pages + # the same as --local-file + _MAN_FORCE='no'; + _MAN_ENABLE='no'; + ;; + --no-special) # disable some special former calls + _OPT_ALL='no' + _OPT_APROPOS='no' + _OPT_WHATIS='no' + ;; + --pager|--tty-viewer|--tty-viewer-tty) + # set paging program for tty mode, arg + _OPT_PAGER="$1"; + shift; + ;; + --pdf) + _OPT_MODE='pdf'; + ;; +### main_parse_args() + --pdf-viewer|--pdf-viewer-tty) # viewer program for pdf mode; arg + _OPT_VIEWER_PDF="$1"; + shift; + ;; + --print) # for argument test + echo2 "$1"; + shift; + ;; + --ps) + _OPT_MODE='ps'; + ;; + --ps-viewer|--ps-viewer-tty) # viewer program for ps mode; arg + _OPT_VIEWER_PS="$1"; + shift; + ;; +### main_parse_args() + --resolution) # set resolution for X devices, arg + mpa_arg="$1"; + shift; + case "${mpa_arg}" in + 75|75dpi) + mpa_dpi=75; + ;; + 100|100dpi) + mpa_dpi=100; + ;; + *) + error "main_parse_args(): \ +only resoutions of 75 or 100 dpi are supported"; + ;; + esac; + _OPT_RESOLUTION="${mpa_dpi}"; + ;; + --rv) + _OPT_RV='yes'; + ;; + --sections) # specify sections for man pages, arg + # arg is colon-separated list of section names + _OPT_SECTIONS="$1"; + shift; + ;; + --shell) + # already done during the first run; so ignore the argument + shift; + ;; +### main_parse_args() + --systems) # man pages for different OS's, arg + # argument is a comma-separated list + _OPT_SYSTEMS="$1"; + shift; + ;; + --text) # text mode without pager + _OPT_MODE=text; + ;; + --title) # title for X viewers; arg + if is_not_empty "$1" + then + list_append _OPT_TITLE "$1"; + fi; + shift; + ;; + --tty) # tty mode, text with pager + _OPT_MODE=tty; + ;; + --text-device|--tty-device) # device for tty mode; arg + _OPT_TEXT_DEVICE="$1"; + shift; + ;; + --whatis) + _OPT_WHATIS='yes'; + _OPT_APROPOS='no'; + ;; + --X|--x) + _OPT_MODE=x; + ;; +### main_parse_args() + --xrm) # pass X resource string, arg; + list_append _OPT_XRM "$1"; + shift; + ;; + --x-viewer|--X-viewer|--x-viewer-tty|--X-viewer-tty) + # viewer program for x mode; arg + _OPT_VIEWER_X="$1"; + shift; + ;; + *) + error 'main_parse_args(): unknown option '"\`${mpa_opt}'."; + ;; + esac; + done; + shift; # remove `--' argument + + if obj _OPT_WHATIS is_yes + then + _MAN_ALL='yes'; + _APROPOS_SECTIONS=''; + fi; + + if obj _OPT_DO_NOTHING is_yes + then + leave; + fi; + +### main_parse_args() + case "$_OPT_DEFAULT_MODES" in + '') :; ;; + *,*) + obj_from_output _OPT_DEFAULT_MODES \ + obj _OPT_DEFAULT_MODES list_from_split ','; + ;; + *) :; ;; + esac; + + # Remaining arguments are file names (filespecs). + # Save them to list $_FILEARGS + if is_equal "$#" 0 + then # use "-" for standard input + _NO_FILESPECS='yes'; + set x '-'; + shift; + fi; + _FILEARGS=''; + list_append _FILEARGS "$@"; + # $_FILEARGS must be retrieved with `eval set x "$_FILEARGS"; shift;' + eval ${_UNSET} mpa_arg; + eval ${_UNSET} mpa_dpi; + eval ${_UNSET} mpa_opt; + eval ${_UNSET} mpa_optchar; + eval "${return_ok}"; +} # main_parse_args() + + +# Called from main_parse_args() because double `case' is not possible. +# Globals: $_OPT_DEVICE, $_OPT_MODE +_check_device_with_mode() +{ + func_check _check_device_with_mode = 0 "$@"; + case "${_OPT_DEVICE}" in + dvi) + _OPT_MODE=dvi; + eval "${return_ok}"; + ;; + html) + _OPT_MODE=html; + eval "${return_ok}"; + ;; + lbp|lj4) + _OPT_MODE=groff; + eval "${return_ok}"; + ;; + ps) + _OPT_MODE=ps; + eval "${return_ok}"; + ;; + ascii|cp1047|latin1|utf8) + if obj _OPT_MODE is_not_equal text + then + _OPT_MODE=tty; # default text mode + fi; + eval "${return_ok}"; + ;; + X*) + _OPT_MODE=x; + eval "${return_ok}"; + ;; + *) # unknown device, go to groff mode + _OPT_MODE=groff; + eval "${return_ok}"; + ;; + esac; + eval "${return_error}"; +} # _check_device_with_mode() of main_parse_args() + + +######################################################################## +# main_set_mode () +# +# Determine the display mode and the corresponding viewer program. +# +# Globals: +# in: $DISPLAY, $_OPT_MODE, $_OPT_DEVICE +# out: $_DISPLAY_MODE +# +# Variable prefix: msm +# +main_set_mode() +{ + func_check main_set_mode = 0 "$@"; + + # set display + if obj _OPT_DISPLAY is_not_empty + then + DISPLAY="${_OPT_DISPLAY}"; + fi; + + if obj _OPT_V is_yes + then + list_append _ADDOPTS_GROFF '-V'; + fi; + if obj _OPT_Z is_yes + then + _DISPLAY_MODE='groff'; + list_append _ADDOPTS_GROFF '-Z'; + fi; + if obj _OPT_MODE is_equal 'groff' + then + _DISPLAY_MODE='groff'; + fi; + if obj _DISPLAY_MODE is_equal 'groff' + then + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + fi; + +### main_set_mode() + + case "${_OPT_MODE}" in + '') # automatic mode + case "${_OPT_DEVICE}" in + X*) + if is_not_X + then + error_user "no X display found for device ${_OPT_DEVICE}"; + fi; + _DISPLAY_MODE='x'; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + ascii|cp1047|latin1|utf8) + if obj _DISPLAY_MODE is_not_equal 'text' + then + _DISPLAY_MODE='tty'; + fi; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; +### main_set_mode() + esac; + if is_not_X + then + _DISPLAY_MODE='tty'; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + fi; + + if obj _OPT_DEFAULT_MODES is_empty + then + msm_modes="${_DEFAULT_MODES}"; + else + msm_modes="${_OPT_DEFAULT_MODES}"; + fi; + ;; + source) + _DISPLAY_MODE='source'; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + text) + _DISPLAY_MODE='text'; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + tty) + _DISPLAY_MODE='tty'; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; +### main_set_mode() + html) + _DISPLAY_MODE='html'; + msm_modes="${_OPT_MODE}"; + ;; + *) # display mode was given + msm_modes="${_OPT_MODE}"; + ;; + esac; + + eval set x "${msm_modes}"; + shift; + while is_greater_than "$#" 0 + do + msm_1="$1"; + shift; + + _VIEWER_BACKGROUND='no'; + + case "${msm_1}" in + dvi) + _get_prog_args DVI; + if is_not_equal "$?" 0 + then + continue; + fi; + if obj _DISPLAY_PROG is_empty + then + if is_equal "$#" 0 + then + error 'main_set_mode(): No viewer for dvi mode available.'; + else + continue; + fi; + fi; +### main_set_mode() + _DISPLAY_MODE="dvi"; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + html) + _get_prog_args HTML; + if is_not_equal "$?" 0 + then + continue; + fi; + if obj _DISPLAY_PROG is_empty + then + if is_equal "$#" 0 + then + error 'main_set_mode(): No viewer for html mode available.'; + else + continue; + fi; + fi; +### main_set_mode() + _DISPLAY_MODE=html; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + pdf) + if obj _PDF_DID_NOT_WORK is_yes + then + if is_equal "$#" 0 + then + error 'main_set_mode(): pdf mode did not work.'; + else + continue; + fi; + fi; + if obj _PDF_HAS_PS2PDF is_not_yes + then + if is_prog ps2pdf + then + _PDF_HAS_PS2PDF='yes'; + fi; + fi; + if obj _PDF_HAS_GS is_not_yes + then + if is_prog gs + then + _PDF_HAS_GS='yes'; + fi; + fi; + _get_prog_args PDF; + if is_not_equal "$?" 0 + then + _PDF_DID_NOT_WORK='yes'; + continue; + fi; + if obj _DISPLAY_PROG is_empty + then + _PDF_DID_NOT_WORK='yes'; + if is_equal "$#" 0 + then + error 'main_set_mode(): No viewer for pdf mode available.'; + else + continue; + fi; + fi; + _DISPLAY_MODE="pdf"; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; +### main_set_mode() + ps) + _get_prog_args PS; + if is_not_equal "$?" 0 + then + continue; + fi; + if obj _DISPLAY_PROG is_empty + then + if is_equal "$#" 0 + then + error 'main_set_mode(): No viewer for ps mode available.'; + else + continue; + fi; + fi; + _DISPLAY_MODE="ps"; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + text) + _DISPLAY_MODE='text'; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; +### main_set_mode() + tty) + _DISPLAY_MODE='tty'; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + x) + _get_prog_args x; + if is_not_equal "$?" 0 + then + continue; + fi; + if obj _DISPLAY_PROG is_empty + then + if is_equal "$#" 0 + then + error 'main_set_mode(): No viewer for x mode available.'; + else + continue; + fi; + fi; + _DISPLAY_MODE='x'; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; +### main_set_mode() + X) + _DISPLAY_MODE='X'; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + eval "${return_ok}"; + ;; + esac; + done; + eval ${_UNSET} msm_1; + eval ${_UNSET} msm_modes; + eval ${_UNSET} msm_viewers; + error_user "No suitable display mode found."; +} # main_set_mode() + + +# _get_prog_args () +# +# Simplification for loop in main_set_mode(). +# +# Globals in/out: $_VIEWER_BACKGROUND +# Globals in : $_OPT_VIEWER_, $_VIEWER__X, $_VIEWER__TTY +# +# Variable prefix: _gpa +# +_get_prog_args() +{ + func_check _get_prog_args '=' 1 "$@"; + + eval _gpa_opt='"${_OPT_VIEWER_'"$1"'}"'; + _gpa_xlist=_VIEWER_"$1"_X; + _gpa_ttylist=_VIEWER_"$1"_TTY; + + if obj _gpa_opt is_empty + then + _VIEWER_BACKGROUND='no'; + if is_X + then + _get_first_prog "${_gpa_xlist}"; + x="$?"; + if is_equal "$x" 0 + then + _VIEWER_BACKGROUND='yes'; + fi; + else + _get_first_prog "${_gpa_ttylist}"; + x="$?"; + fi; + exit_test; + eval ${_UNSET} _gpa_opt; + eval ${_UNSET} _gpa_prog; + eval ${_UNSET} _gpa_ttylist; + eval ${_UNSET} _gpa_xlist; + eval "${return_var} $x"; +### _get_prog_args() of main_set_mode() + else # $_gpa_opt is not empty + obj_from_output _gpa_prog where_is_prog "${_gpa_opt}"; + if is_not_equal "$?" 0 || obj _gpa_prog is_empty + then + exit_test; + echo2 "_get_prog_args(): '${_gpa_opt}' is not an existing program."; + eval ${_UNSET} _gpa_opt; + eval ${_UNSET} _gpa_prog; + eval ${_UNSET} _gpa_ttylist; + eval ${_UNSET} _gpa_xlist; + eval "${return_bad}"; + fi; + exit_test; + + # $_gpa_prog from opt is an existing program + +### _get_prog_args() of main_set_mode() + if is_X + then + eval _check_prog_on_list ${_gpa_prog} ${_gpa_xlist}; + if is_equal "$?" 0 + then + _VIEWER_BACKGROUND='yes'; + else + _VIEWER_BACKGROUND='no'; + eval _check_prog_on_list ${_gpa_prog} ${_gpa_ttylist}; + fi; + else # is not X + _VIEWER_BACKGROUND='no'; + eval _check_prog_on_list ${_gpa_prog} ${_gpa_ttylist}; + fi; # is_X + fi; # test of $_gpa_opt + eval ${_UNSET} _gpa_opt; + eval ${_UNSET} _gpa_prog; + eval ${_UNSET} _gpa_ttylist; + eval ${_UNSET} _gpa_xlist; + eval "${return_good}"; +} # _get_prog_args() of main_set_mode() + + +# _get_first_prog () +# +# Retrieve from the elements of the list in the argument the first +# existing program in $PATH. +# +# Local function for main_set_mode(). +# +# Return : `1' if none found, `0' if found. +# Output : none +# +# Variable prefix: _gfp +# +_get_first_prog() +{ + func_check _get_first_prog '=' 1 "$@"; + eval x='"${'"$1"'}"'; + eval set x "$x"; + shift; + for i + do + _gfp_i="$i"; + if obj _gfp_i is_empty + then + continue; + fi; + obj_from_output _gfp_result where_is_prog "${_gfp_i}"; + if is_equal "$?" 0 && obj _gfp_result is_not_empty + then + exit_test; + eval set x ${_gfp_result}; + shift; + _DISPLAY_PROG="$1"; + _DISPLAY_ARGS="$2"; + eval ${_UNSET} _gfp_i; + eval ${_UNSET} _gfp_result; + eval "${return_good}"; + fi; + exit_test; + done; + eval ${_UNSET} _gfp_i; + eval ${_UNSET} _gfp_result; + eval "${return_bad}"; +} # _get_first_prog() of main_set_mode() + + +# _check_prog_on_list ( ) +# +# Check whether the content of is in the list . +# The globals are set correspondingly. +# +# Local function for main_set_mode(). +# +# Arguments: 3 +# +# Return : `1' if not a part of the list, `0' if found in the list. +# Output : none +# +# Globals in : $_VIEWER__X, $_VIEWER__TTY +# Globals in/out: $_DISPLAY_PROG, $_DISPLAY_ARGS +# +# Variable prefix: _cpol +# +_check_prog_on_list() +{ + func_check _check_prog_on_list '=' 3 "$@"; + _DISPLAY_PROG="$1"; + _DISPLAY_ARGS="$2"; + + eval _cpol_3='"${'"$3"'}"'; + eval set x "${_cpol_3}"; + shift; + eval ${_UNSET} _cpol_3; + + for i + do + _cpol_i="$i"; + obj_from_output _cpol_list where_is_prog "${_cpol_i}"; + if is_not_equal "$?" 0 || obj _cpol_list is_empty + then + exit_test; + continue; + fi; + exit_test; + _cpol_prog="$(eval set x ${_cpol_list}; shift; echo1 "$1")"; + + if is_not_equal "${_DISPLAY_PROG}" "${_cpol_prog}" + then + exit_test; + continue; + fi; + exit_test; +### _check_prog_on_list() of main_set_mode() + + # equal, prog found + + _cpol_args="$(eval set x ${_cpol_list}; shift; echo1 "$2")"; + eval ${_UNSET} _cpol_list; + if obj _cpol_args is_not_empty + then + if obj _DISPLAY_ARGS is_empty + then + _DISPLAY_ARGS="${_cpol_args}"; + else + _DISPLAY_ARGS="${_cpol_args} ${_DISPLAY_ARGS}"; + fi; + fi; + + eval ${_UNSET} _cpol_i; + eval ${_UNSET} _cpol_args; + eval ${_UNSET} _cpol_prog; + eval "${return_good}"; + done; # for vars in list + + # prog was not in the list + eval ${_UNSET} _cpol_i; + eval ${_UNSET} _cpol_args; + eval ${_UNSET} _cpol_list; + eval ${_UNSET} _cpol_prog; + eval "${return_bad}"; +} # _check_prog_on_list() of main_set_mode() + + +####################################################################### +# main_do_fileargs () +# +# Process filespec arguments. +# +# Globals: +# in: $_FILEARGS (process with `eval set x "$_FILEARGS"; shift;') +# +# Variable prefix: mdfa +# +main_do_fileargs() +{ + func_check main_do_fileargs = 0 "$@"; + special_setup; + if obj _OPT_APROPOS is_yes + then + if obj _NO_FILESPECS is_yes + then + apropos_filespec; + eval "${return_ok}"; + fi; + else + if list_has _FILEARGS '-' + then + save_stdin; + fi; + fi; + eval set x "${_FILEARGS}"; + shift; + eval ${_UNSET} _FILEARGS; +### main_do_fileargs() + while is_greater_than "$#" 0 + do + mdfa_filespec="$1"; + _FILESPEC_ARG="$1"; + shift; + _FILESPEC_IS_MAN='no'; + _TMP_MANSPEC=''; + _SPECIAL_FILESPEC='no'; + + case "${mdfa_filespec}" in + '') + continue; + ;; + esac; + special_filespec; + + # check for file + case "${mdfa_filespec}" in + '-') + if obj _OPT_APROPOS is_yes + then + continue; + fi; + register_file '-'; + continue; + ;; +### main_do_fileargs() + */*) + if obj _OPT_APROPOS is_yes + then + continue; + fi; + if obj mdfa_filespec is_file + then + obj mdfa_filespec register_file; + else + echo2 "The argument ${mdfa_filespec} is not a file."; + fi; + continue; + ;; + *) + if obj _OPT_APROPOS is_yes + then + continue; + fi; + # check whether filespec is an existing file + if obj _MAN_FORCE is_not_yes + then + if obj mdfa_filespec is_file + then + obj mdfa_filespec register_file; + continue; + fi; + fi; + ;; + # now it must be a man page pattern + esac; +### main_do_fileargs() + if obj _MACRO_PKG is_not_empty && obj _MACRO_PKG is_not_equal '-man' + then + echo2 "${mdfa_filespec} is not a file, man pages are ignored "\ +"due to ${_MACRO_PKG}."; + continue; + fi; + + # check for man page + if obj _MAN_ENABLE is_not_yes + then + echo2 "The argument ${mdfa_filespec} is not a file."; + continue; + fi; + if obj _MAN_FORCE is_yes + then + mdfa_errmsg='is not a man page.'; + else + mdfa_errmsg='is neither a file nor a man page.'; + fi; +### main_do_fileargs() + man_setup; + _FILESPEC_IS_MAN='yes'; + + # check whether filespec is a man page + if obj mdfa_filespec man_is_man + then + obj mdfa_filespec man_get; + continue; + fi; + + # test filespec with `man:...' or `...(...)' on man page + mdfa_name=''; + mdfa_section=''; + mdfa_ext=''; + case "${mdfa_filespec}" in + *\(*\)) + mdfa_section="$(obj mdfa_filespec echo1 | \ + sed -e 's/^[^(]*(\(.\).*)$/\1/')"; + if list_has_not _MAN_AUTO_SEC_LIST "${mdfa_section}" + then + echo2 "${mdfa_section} in ${mdfa_filespec} is not a man page section." + continue; + fi; + mdfa_name="$(obj mdfa_filespec echo1 | \ + sed -e 's/^\([^(]*\)(.*)$/\1/')"; + if obj mdfa_name is_empty + then + echo2 "${mdfa_filespec} ${mdfa_errmsg}"; + continue; + fi; + mdfa_ext="$(obj mdfa_filespec echo1 | \ + sed -e 's/^[^(]*(.\(.*\))$/\1/')"; + if man_is_man "${mdfa_name}" "${mdfa_section}" "${mdfa_ext}" + then + man_get "${mdfa_name}" "${mdfa_section}" "${mdfa_ext}"; + continue; + fi; +### main_do_fileargs() + case "${mdfa_name}" in + man:*) + mdfa_name="$(obj mdfa_name echo1 | sed -e 's/^man://')"; + if man_is_man "${mdfa_name}" "${mdfa_section}" "${mdfa_ext}" + then + man_get "${mdfa_name}" "${mdfa_section}" "${mdfa_ext}"; + continue; + fi; + ;; + esac; + echo2 "${mdfa_filespec} ${mdfa_errmsg}"; + continue; + ;; + man:*) + mdfa_name="$(obj mdfa_filespec echo1 | sed -e 's/^man://')"; + if man_is_man "${mdfa_name}" + then + man_get "${mdfa_name}"; + continue; + fi; + echo2 "${mdfa_name} ${mdfa_errmsg}"; + continue; + ;; + *.${_MAN_AUTO_SEC_CHARS}*) + mdfa_name="$(obj mdfa_filespec echo1 | \ + sed -e 's/^\(.*\)\.'"${_MAN_AUTO_SEC_CHARS}"'.*$/\1/')"; + mdfa_section="$(obj mdfa_filespec echo1 | \ + sed -e 's/^.*\.\('"${_MAN_AUTO_SEC_CHARS}"'\).*$/\1/')"; + mdfa_ext="$(obj mdfa_filespec echo1 | \ + sed -e 's/^.*\.'"${_MAN_AUTO_SEC_CHARS}"'\(.*\)$/\1/')"; + if man_is_man "${mdfa_name}" "${mdfa_section}" "${mdfa_ext}" + then + man_get "${mdfa_name}" "${mdfa_section}" "${mdfa_ext}"; + continue; + fi; + ;; + esac; +### main_do_fileargs() + + # check on "s name", where "s" is a section with or without an extension + if is_not_empty "$1" + then + mdfa_name="$1"; + case "${mdfa_filespec}" in + ${_MAN_AUTO_SEC_CHARS}) + mdfa_section="${mdfa_filespec}"; + ;; + ${_MAN_AUTO_SEC_CHARS}*) + mdfa_section="$(echo1 "${mdfa_filespec}" | \ + sed -e 's/^\(.\).*$/\1/')"; + mdfa_ext="$(echo1 "${mdfa_filespec}" | \ + sed -e 's/^.\(.*\)$/\1/')"; + ;; + *) + echo2 "${mdfa_filespec} ${mdfa_errmsg}"; + continue; + ;; + esac; + shift; + if man_is_man "${mdfa_name}" "${mdfa_section}" "${mdfa_ext}" + then + man_get "${mdfa_name}" "${mdfa_section}" "${mdfa_ext}"; + continue; + else + echo2 "No man page for ${mdfa_name} with section ${mdfa_filespec}."; + continue; + fi; + fi; + +### main_do_fileargs() + echo2 "${mdfa_filespec} ${mdfa_errmsg}"; + continue; + done; + + obj _TMP_STDIN rm_file_with_debug; + eval ${_UNSET} mdfa_filespec; + eval ${_UNSET} mdfa_name; + eval "${return_ok}"; +} # main_do_fileargs() + + +######################################################################## +# main_set_resources () +# +# Determine options for setting X resources with $_DISPLAY_PROG. +# +# Globals: $_DISPLAY_PROG, $_OUTPUT_FILE_NAME +# +# Variable prefix: msr +# +main_set_resources() +{ + func_check main_set_resources = 0 "$@"; + # $msr_prog viewer program + # $msr_rl resource list + obj_from_output msr_title \ + get_first_essential "${_OPT_TITLE}" "${_REG_TITLE_LIST}"; + _OUTPUT_FILE_NAME=''; + eval set x "${msr_title}"; + shift; + until is_equal "$#" 0 + do + msr_n="$1"; + case "${msr_n}" in + '') + continue; + ;; + ,*) + msr_n="$(echo1 "$1" | sed -e 's/^,,*//')"; + exit_test; + ;; + esac; + if obj msr_n is_empty + then + continue; + fi; + if obj _OUTPUT_FILE_NAME is_not_empty + then + _OUTPUT_FILE_NAME="${_OUTPUT_FILE_NAME}"','; + fi; + _OUTPUT_FILE_NAME="${_OUTPUT_FILE_NAME}${msr_n}"; + shift; + done; # until $# is 0 +### main_set_resources() + + case "${_OUTPUT_FILE_NAME}" in + '') + _OUTPUT_FILE_NAME='-'; + ;; + ,*) + error "main_set_resources(): ${_OUTPUT_FILE_NAME} starts with a comma."; + ;; + esac; + _OUTPUT_FILE_NAME="${_TMP_DIR}/${_OUTPUT_FILE_NAME}"; + + if obj _DISPLAY_PROG is_empty + then # for example, for groff mode + _DISPLAY_ARGS=''; + eval ${_UNSET} msr_n; + eval ${_UNSET} msr_prog; + eval ${_UNSET} msr_rl; + eval ${_UNSET} msr_title; + eval "${return_ok}"; + fi; + + eval set x "${_DISPLAY_PROG}"; + shift; + obj_from_output msr_prog base_name "$1"; + shift; + if is_greater_than $# 0 + then + if obj _DISPLAY_ARGS is_empty + then + _DISPLAY_ARGS="$*"; + else + _DISPLAY_ARGS="$* ${_DISPLAY_ARGS}"; + fi; + fi; +### main_set_resources() + msr_rl=''; + if obj _OPT_BD is_not_empty + then + case "${msr_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + list_append msr_rl '-bd' "${_OPT_BD}"; + ;; + esac; + fi; + if obj _OPT_BG is_not_empty + then + case "${msr_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + list_append msr_rl '-bg' "${_OPT_BG}"; + ;; + kghostview) + list_append msr_rl '--bg' "${_OPT_BG}"; + ;; + xpdf) + list_append msr_rl '-papercolor' "${_OPT_BG}"; + ;; + esac; + fi; + if obj _OPT_BW is_not_empty + then + case "${msr_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + _list_append msr_rl '-bw' "${_OPT_BW}"; + ;; + esac; + fi; +### main_set_resources() + if obj _OPT_FG is_not_empty + then + case "${msr_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + list_append msr_rl '-fg' "${_OPT_FG}"; + ;; + kghostview) + list_append msr_rl '--fg' "${_OPT_FG}"; + ;; + esac; + fi; + if is_not_empty "${_OPT_FN}" + then + case "${msr_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + list_append msr_rl '-fn' "${_OPT_FN}"; + ;; + kghostview) + list_append msr_rl '--fn' "${_OPT_FN}"; + ;; + esac; + fi; + if is_not_empty "${_OPT_GEOMETRY}" + then + case "${msr_prog}" in + ghostview|gv|gxditview|xditview|xdvi|xpdf) + list_append msr_rl '-geometry' "${_OPT_GEOMETRY}"; + ;; + kghostview) + list_append msr_rl '--geometry' "${_OPT_GEOMETRY}"; + ;; + esac; + fi; +### main_set_resources() + if is_empty "${_OPT_RESOLUTION}" + then + _OPT_RESOLUTION="${_DEFAULT_RESOLUTION}"; + case "${msr_prog}" in + gxditview|xditview) + list_append msr_rl '-resolution' "${_DEFAULT_RESOLUTION}"; + ;; + xpdf) + case "${_DISPLAY_PROG}" in + *-z*) + :; + ;; + *) # if xpdf does not have option -z + case "${_DEFAULT_RESOLUTION}" in + 75) + # 72dpi is '100' + list_append msr_rl '-z' '104'; + ;; + 100) + list_append msr_rl '-z' '139'; + ;; + esac; + ;; + esac; + ;; + esac; + else + case "${msr_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + list_append msr_rl '-resolution' "${_OPT_RESOLUTION}"; + ;; + xpdf) + case "${_DISPLAY_PROG}" in + *-z*) + :; + ;; + *) # if xpdf does not have option -z + case "${_OPT_RESOLUTION}" in + 75) + list_append msr_rl '-z' '104'; + # '100' corresponds to 72dpi + ;; +### main_set_resources() + 100) + list_append msr_rl '-z' '139'; + ;; + esac; + ;; + esac; + ;; + esac; + fi; + if is_yes "${_OPT_ICONIC}" + then + case "${msr_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + list_append msr_rl '-iconic'; + ;; + esac; + fi; + if is_yes "${_OPT_RV}" + then + case "${msr_prog}" in + ghostview|gv|gxditview|xditview|xdvi) + list_append msr_rl '-rv'; + ;; + esac; + fi; + if is_not_empty "${_OPT_XRM}" + then + case "${msr_prog}" in + ghostview|gv|gxditview|xditview|xdvi|xpdf) + eval set x "${_OPT_XRM}"; + shift; + for i + do + list_append msr_rl '-xrm' "$i"; + done; +### main_set_resources() + ;; + esac; + fi; + if is_not_empty "${msr_title}" + then + case "${msr_prog}" in + gxditview|xditview) + list_append msr_rl '-title' "${msr_title}"; + ;; + esac; + fi; + if obj _DISPLAY_ARGS is_empty + then + _DISPLAY_ARGS="${msr_rl}"; + else + _DISPLAY_ARGS="${msr_l} ${_DISPLAY_ARGS}"; + fi; + eval ${_UNSET} msr_n; + eval ${_UNSET} msr_prog; + eval ${_UNSET} msr_rl; + eval ${_UNSET} msr_title; + eval "${return_ok}"; +} # main_set_resources + + +######################################################################## +# main_display () +# +# Do the actual display of the whole thing. +# +# Globals: +# in: $_DISPLAY_MODE, $_OPT_DEVICE, $_ADDOPTS_GROFF, +# $_TMP_CAT, $_OPT_PAGER, $_MANOPT_PAGER, $_OUTPUT_FILE_NAME +# +# Variable prefix: md +# +main_display() +{ + func_check main_display = 0 "$@"; + + export md_addopts; + export md_groggy; + export md_modefile; + + if obj _TMP_CAT is_empty_file + then + echo2 'groffer: empty input.'; + clean_up; + eval "${return_ok}"; + fi; + + md_modefile="${_OUTPUT_FILE_NAME}"; + + # go to the temporary directory to be able to access internal data files + cd "${_TMP_DIR}" >"${_NULL_DEV}" 2>&1; + + case "${_DISPLAY_MODE}" in + groff) + if obj _OPT_DEVICE is_not_empty + then + _ADDOPTS_GROFF="${_ADDOPTS_GROFF} -T${_OPT_DEVICE}"; + fi; + md_groggy="$(tmp_cat | eval grog)"; + exit_test; + _do_opt_V; + +### main_display() + obj md_modefile rm_file; + mv "${_TMP_CAT}" "${md_modefile}"; + trap_unset; + cat "${md_modefile}" | \ + { + trap_set; + eval "${md_groggy}" "${_ADDOPTS_GROFF}"; + } & + ;; + text|tty) + case "${_OPT_DEVICE}" in + '') + obj_from_output md_device \ + get_first_essential "${_OPT_TEXT_DEVICE}" "${_DEFAULT_TTY_DEVICE}"; + ;; + ascii|cp1047|latin1|utf8) + md_device="${_OPT_DEVICE}"; + ;; + *) + warning "main_display(): \ +wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; + ;; + esac; + md_addopts="${_ADDOPTS_GROFF}"; + md_groggy="$(tmp_cat | grog -T${md_device})"; + exit_test; + if obj _DISPLAY_MODE is_equal 'text' + then + _do_opt_V; + tmp_cat | eval "${md_groggy}" "${md_addopts}"; + else # $_DISPLAY_MODE is 'tty' +### main_display() + md_pager=''; + for p in "${_OPT_PAGER}" "${_MANOPT_PAGER}" "${PAGER}" + do + if obj p is_empty + then + continue; + fi; + obj_from_output md_pager where_is_prog "$p"; + if is_not_equal "$?" 0 || obj md_pager is_empty + then + md_pager=''; + continue; + fi; + eval set x $md_pager; + shift; + case "$1" in + */less) + if is_empty "$2" + then + md_pager="$1"' -r -R'; + else + md_pager="$1"' -r -R '"$2"; + fi; + ;; +### main_display() + *) + if is_empty "$2" + then + md_pager="$1"; + else + md_pager="$1 $2"; + fi; + ;; + esac; + break; + done; + if obj md_pager is_empty + then + eval set x ${_VIEWER_TTY_TTY} ${_VIEWER_TTY_X} 'cat'; + shift; + # that is: 'less -r -R' 'more' 'pager' 'xless' 'cat' + for p + do + if obj p is_empty + then + continue; + fi; + md_p="$p"; + if is_prog "${md_p}" + then + md_pager="${md_p}"; + break; + fi; + done; + fi; +### main_display() + if obj md_pager is_empty + then + error 'main_display(): no pager program found for tty mode'; + fi; + _do_opt_V; + tmp_cat | eval "${md_groggy}" "${md_addopts}" | \ + eval "${md_pager}"; + fi; # $_DISPLAY_MODE + clean_up; + ;; # text|tty) + source) + tmp_cat; + clean_up; + ;; + + #### viewer modes + +### main_display() + dvi) + case "${_OPT_DEVICE}" in + ''|dvi) do_nothing; ;; + *) + warning "main_display(): \ +wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}" + ;; + esac; + md_modefile="${md_modefile}".dvi; + md_groggy="$(tmp_cat | grog -Tdvi)"; + exit_test; + _do_display; + ;; + html) + case "${_OPT_DEVICE}" in + ''|html) do_nothing; ;; + *) + warning "main_display(): \ +wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; + ;; + esac; + md_modefile="${md_modefile}".html; + md_groggy="$(tmp_cat | grog -Thtml)"; + exit_test; + _do_display; + ;; +### main_display() + pdf) + case "${_OPT_DEVICE}" in + ''|ps) + do_nothing; + ;; + *) + warning "main_display(): \ +wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; + ;; + esac; + md_groggy="$(tmp_cat | grog -Tps)"; + exit_test; + _do_display _make_pdf; + ;; + ps) + case "${_OPT_DEVICE}" in + ''|ps) + do_nothing; + ;; + *) + warning "main_display(): \ +wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; + ;; + esac; + md_modefile="${md_modefile}".ps; + md_groggy="$(tmp_cat | grog -Tps)"; + exit_test; + _do_display; + ;; +### main_display() + x) + case "${_OPT_DEVICE}" in + X*) + md_device="${_OPT_DEVICE}" + ;; + *) + case "${_OPT_RESOLUTION}" in + 100) + md_device='X100'; + if obj _OPT_GEOMETRY is_empty + then + case "${_DISPLAY_PROG}" in + gxditview|xditview) + # add width of 800dpi for resolution of 100dpi to the args + list_append _DISPLAY_ARGS '-geometry' '800'; + ;; + esac; + fi; + ;; + *) + md_device='X75-12'; + ;; + esac + esac; + md_groggy="$(tmp_cat | grog -T${md_device} -Z)"; + exit_test; + _do_display; + ;; +### main_display() + X) + case "${_OPT_DEVICE}" in + '') + md_groggy="$(tmp_cat | grog -X)"; + exit_test; + ;; + X*|dvi|html|lbp|lj4|ps) + # these devices work with + md_groggy="$(tmp_cat | grog -T"${_OPT_DEVICE}" -X)"; + exit_test; + ;; + *) + warning "main_display(): \ +wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; + md_groggy="$(tmp_cat | grog -Z)"; + exit_test; + ;; + esac; + _do_display; + ;; + *) + error "main_display(): unknown mode \`${_DISPLAY_MODE}'"; + ;; + esac; + eval ${_UNSET} md_addopts; + eval ${_UNSET} md_device; + eval ${_UNSET} md_groggy; + eval ${_UNSET} md_modefile; + eval ${_UNSET} md_p; + eval ${_UNSET} md_pager; + eval "${return_ok}"; +} # main_display() + + +######################## +# _do_display ([]) +# +# Perform the generation of the output and view the result. If an +# argument is given interpret it as a function name that is called in +# the midst (actually only for `pdf'). +# +# Globals: $md_modefile, $md_groggy (from main_display()) +# +_do_display() +{ + func_check _do_display '>=' 0 "$@"; + _do_opt_V; + if obj _DISPLAY_PROG is_empty + then + trap_unset; + { + trap_set; + eval "${md_groggy}" "${_ADDOPTS_GROFF}" "${_TMP_CAT}"; + } & + else + obj md_modefile rm_file; + cat "${_TMP_CAT}" | \ + eval "${md_groggy}" "${_ADDOPTS_GROFF}" > "${md_modefile}"; + if is_not_empty "$1" + then + eval "$1"; + fi; + obj _TMP_CAT rm_file_with_debug; + if obj _VIEWER_BACKGROUND is_not_yes # for programs that run on tty + then + eval "'${_DISPLAY_PROG}'" ${_DISPLAY_ARGS} "\"${md_modefile}\""; + else + trap_unset; + { + trap_set; + eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "\"${md_modefile}\""; + } & + fi; + fi; + eval "${return_ok}"; +} # _do_display() of main_display() + + +############# +# _do_opt_V () +# +# Check on option `-V'; if set print the corresponding output and leave. +# +# Globals: $_ALL_PARAMS, $_ADDOPTS_GROFF, $_DISPLAY_MODE, $_DISPLAY_PROG, +# $_DISPLAY_ARGS, $md_groggy, $md_modefile +# +# Variable prefix: _doV +# +_do_opt_V() +{ + func_check _do_opt_V '=' 0 "$@"; + if obj _OPT_V is_yes + then + _OPT_V='no'; + echo1 "Parameters: ${_ALL_PARAMS}"; + echo1 "Display mode: ${_DISPLAY_MODE}"; + echo1 "Output file: ${md_modefile}"; + echo1 "Display prog: ${_DISPLAY_PROG} ${_DISPLAY_ARGS}"; + a="$(eval echo1 "'${_ADDOPTS_GROFF}'")"; + exit_test; + echo1 "Output of grog: ${md_groggy} $a"; + _doV_res="$(eval "${md_groggy}" "${_ADDOPTS_GROFF}")"; + exit_test; + echo1 "groff -V: ${_doV_res}" + leave; + fi; + eval "${return_ok}"; +} # _do_opt_V() of main_display() + + +############## +# _make_pdf () +# +# Transform to pdf format; for pdf mode in _do_display(). +# +# Globals: $md_modefile (from main_display()) +# +# Variable prefix: _mp +# +_make_pdf() +{ + func_check _make_pdf '=' 0 "$@"; + _mp_psfile="${md_modefile}"; + md_modefile="${md_modefile}.pdf"; + obj md_modefile rm_file; + if obj _PDF_HAS_PS2PDF is_yes && ps2pdf "${_mp_psfile}" "${md_modefile}"; + then + :; + elif obj _PDF_HAS_GS && gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \ + -sOutputFile="${md_modefile}" -c save pop -f "${_mp_psfile}"; + then + :; + else + _PDF_DID_NOT_WORK='yes'; + echo2 '_make_pdf(): Could not transform into pdf format. '\ +'The Postscript mode (ps) is used instead.'; + _OPT_MODE='ps'; + main_set_mode; + main_set_resources; + main_display; + exit; + fi; + obj _mp_psfile rm_file_with_debug; + eval ${_UNSET} _mp_psfile; + eval "${return_ok}"; +} # _make_pdf() of main_display() + + +######################################################################## +# main (*) +# +# The main function for groffer. +# +# Arguments: +# +main() +{ + func_check main '>=' 0 "$@"; + # Do not change the sequence of the following functions! + landmark '13: main_init()'; + main_init; + landmark '14: main_parse_MANOPT()'; + main_parse_MANOPT; + landmark '15: main_parse_args()'; + main_parse_args "$@"; + landmark '16: main_set_mode()'; + main_set_mode; + landmark '17: main_do_fileargs()'; + main_do_fileargs; + landmark '18: main_set_resources()'; + main_set_resources; + landmark '19: main_display()'; + main_display; + eval "${return_ok}"; +} + + +######################################################################## + +main "$@"; diff -ruN groff-1.18.1.1/contrib/groffer/groffer.man groff-1.18.1.2/contrib/groffer/groffer.man --- groff-1.18.1.1/contrib/groffer/groffer.man 2004-06-02 17:11:09.000000000 +0200 +++ groff-1.18.1.2/contrib/groffer/groffer.man 2006-09-26 23:24:06.000000000 +0200 @@ -15,32 +15,51 @@ Source file position: /contrib/groffer/groffer.man Installed position: $prefix/share/man/man1/groffer.1 -Last update : 12 May 2004 +Last update: 16 Sep 2006 Source file position: /contrib/groffer/groffer.man .. .de author -This file was written by Bernd Warken. +This file was written by +.MTO "" "Bernd Warken" . .. .de copyleft -Copyright (C) 2001,2002,2004 Free Software Foundation, Inc. +Copyright (C) 2001,2002,2004,2005,2006 Free Software Foundation, Inc. . .P -This file is part of groff, a free software project. +This file is part of +.IR \%groffer , +which is part of +.IR \%groff , +a free software project. . -You can redistribute it and/or modify it under the terms of the GNU -General Public License as published by the Free Software Foundation; +You can redistribute it and/or modify it under the terms of the +.nh +.B GNU General Public License +.hy +as published by the +.nh +.BR "Free Software Foundation" , +.hy either version 2, or (at your option) any later version. . .P -You should have received a copy of the GNU General Public License -along with groff, see the files COPYING and LICENSE in the top -directory of the groff source package. +You should have received a copy of the \f[CR]GNU General Public +License\f[] along with +.IR groff , +see the files \%\f[CB]COPYING\f[] and \%\f[CB]LICENSE\f[] in the top +directory of the +.I groff +source package. . -Or read the man page +Or read the +.I man\~page .BR gpl (1). -You can also write to the Free Software Foundation, 59 Temple Place - -Suite 330, Boston, MA 02111-1307, USA. +You can also write to the +.nh +.B Free Software Foundation, 51 Franklin St - Fifth Floor, Boston, +.BR "MA 02110-1301, USA" . +.hy .. . .\" -------------------------------------------------------------------- @@ -60,15 +79,6 @@ . ftr CB CW .\} . -.ds @- "\-\"" -.ds @-- "\-\^\-\"" -. -.ds @b- "\f[CB]-\f[]\"" -.ds @b-- "\f[CB]--\f[]\"" -. -.ds @i- "\f[CI]-\f[]\"" -.ds @i-- "\f[CI]--\f[]\"" -. .ds Ellipsis ".\|.\|.\"" . .\" -------------------------------------------------------------------- @@ -190,7 +200,7 @@ .c -------------------------------------------------------------------- .c .Opt_- ([]) .c -.c Print `-' (minus sign); optional punctuation. +.c Print `-' (minus sign); optional punctuation. .c .de Opt_- . ie (\\n[.$] == 0) \ @@ -201,7 +211,7 @@ .c -------------------------------------------------------------------- .c .Opt_[-] ([]) .c -.c Print `Opt_[-]' (minus sign in brackets); optional punctuation. +.c Print `Opt_[-]' (minus sign in brackets); optional punctuation. .c .de Opt_[-] . ie (\\n[.$] == 0) \ @@ -212,7 +222,7 @@ .c -------------------------------------------------------------------- .c .Opt_-- ([]) .c -.c Print `--' (double minus); optional punctuation. +.c Print `--' (double minus); optional punctuation. .c .de Opt_-- . ie (\\n[.$] == 0) \ @@ -223,7 +233,7 @@ .c -------------------------------------------------------------------- .c .Opt_[--] ([]) .c -.c Print `Opt_[--]' (double minus in brackets); optional punctuation. +.c Print `Opt_[--]' (double minus in brackets); optional punctuation. .c .de Opt_[--] . ie (\\n[.$] == 0) \ @@ -286,7 +296,7 @@ .c Alternating options; base macro for many others; do not use directly. .c .c Arguments: -.c
: prefix, resulted is preceded by this.
+.c   
: prefix, result is preceded by this.
 .c   : separator between minus/opt pairs.
 .c   : postfix, is appended to the result.
 .c   : either `-' or `--' (font CB).
@@ -296,7 +306,8 @@
 .c Result:
 .c   String `
' followed by the / argument pairs, each
 .c   separated by string `', optionally add '', separated by
-.c   a single space ` ', followed by the string `'.
+.c   a single space ` ', followed by the string `'.  Terminated
+.c   by the optional punctuation .
 .c
 .de Opt_alt_base
 .  nr @font \\n[.f]\"
@@ -316,9 +327,13 @@
 .    \}
 .    c                                  separator
 .    if (\\n[@count] > 0) \
-.      as @res \f[CR]\\*[@sep]\"
+.      as @res \f[CR]\\*[@sep]\:\"
 .    nr @count +1
-.    as @res \f[CB]\\$1\\$2\:\"         combine minus with option name
+.    c                                  combine minus with option name
+.    as @res \f[CB]\\-\"
+.    if '\\$1'--' \
+.      as @res \\-\"
+.    as @res \\$2\"
 .    shift 2
 .  \}
 .  if (\\n[.$] >= 3) \
@@ -555,7 +570,9 @@
 .de Text
 .  if (\\n[.$] == 0) \
 .    return
+.  nh
 .  nop \)\\$*\)
+.  hy
 ..
 .c --------------------------------------------------------------------
 .c .Topic  ([])
@@ -650,11 +667,7 @@
 .Synopsis groffer
 .RI [ option... ]
 .Opt_[--]
-.RI [ "filespec" "\*[Ellipsis]]"
-./Synopsis
-.
-.Synopsis groffer
-.Opt_alt -- apropos -- apropos-data -- apropos-devel -- apropos-progs name
+.RI [ "\%filespec" "\*[Ellipsis]]"
 ./Synopsis
 .
 .Synopsis groffer
@@ -671,62 +684,83 @@
 .\" --------------------------------------------------------------------
 .
 The
-.I groffer
+.B \%groffer
 program is the easiest way to use
-.BR groff (@MAN1EXT@).
+.BR \%groff (@MAN1EXT@).
 It can display arbitrary documents written in the
-.BR groff (@MAN7EXT@)
-language or other
-.BR roff (@MAN7EXT@)
-languages that are compatible to the original troff language.
+.I \%groff
+language, see
+.BR \%groff (@MAN7EXT@),
+or other
+.I \%roff
+languages, see
+.BR \%roff (@MAN7EXT@),
+that are compatible to the original
+.I \%troff
+language.
 .
 The
-.I groffer
+.B \%groffer
 program also includes many of the features for finding and displaying
-the UNIX manual pages
+the \%\f[CR]Unix\f[] manual pages
+.nh
 .RI ( man\~pages ),
+.hy
 such that it can be used as a replacement for a
-.BR man (1)
+.BR \%man (1)
 program.
 .
 Moreover, compressed files that can be handled by
-.BR gzip (1)
+.BR \%gzip (1)
 or
-.BR bzip2 (1)
+.BR \%bzip2 (1)
 are decompressed on-the-fly.
 .
 .
 .P
 The normal usage is quite simple by supplying a file name or name of a
-man\~page without further options.
+.I \%man\~page
+without further options.
 .
 But the option handling has many possibilities for creating special
 behaviors.
 .
-This can be done in configuration files, with the shell environment
-variable
-.BR $GROFFER_OPT ,
+This can be done either in configuration files, with the shell
+environment variable
+.Env_var \%$GROFFER_OPT ,
 or on the command line.
 .
 .
 .P
 The output can be generated and viewed in several different ways
 available for
-.IR groff .
+.IR \%groff .
 .
-This includes the groff native X viewer
-.BR gxditview (@MAN1EXT@),
-each Postcript or dvi display program, a web browser by generating
-html in www-mode, or several text modes in text terminals.
+This includes the
+.I \%groff
+native \%\f[CR]X\~Window\f[] viewer
+.BR \%gxditview (@MAN1EXT@),
+each
+.IR \%Postcript ,
+.IR \%pdf ,
+or
+.I \%dvi
+display program, a web browser by generating
+.I \%html
+in
+.IR \%www\~mode ,
+or several
+.I \%text\~modes
+in text terminals.
 .
 .
 .P
 Most of the options that must be named when running
-.I groff
+.B \%groff
 directly are determined automatically for
-.IR groffer ,
+.BR \%groffer ,
 due to the internal usage of the
-.BR grog (@MAN1EXT@)
+.BR \%grog (@MAN1EXT@)
 program.
 .
 But all parts can also be controlled manually by arguments.
@@ -736,7 +770,20 @@
 Several file names can be specified on the command line arguments.
 .
 They are transformed into a single document in the normal way of
-.IR groff .
+.BR \%groff .
+.
+.
+.P
+Option handling is done in \f[CR]GNU\f[] style.
+.
+Options and file names can be mixed freely.
+.
+The option
+.RB ` \-\- '
+closes the option handling, all following arguments are treated as
+file names.
+.
+Long options can be abbreviated in several ways.
 .
 .
 .\" --------------------------------------------------------------------
@@ -747,88 +794,65 @@
 .I breaking options
 .RS
 .P
-.Opt_[alt] -- apropos name
-.Opt_[alt] -- apropos-data name
-.Opt_[alt] -- apropos-devel name
-.Opt_[alt] -- apropos-progs name
 .Opt_[alt] - h -- help
 .Opt_[alt] - v -- version
 .RE
 .
 .
 .TP
-.I groffer mode options
+.I \%groffer mode options
 .RS
 .P
 .Opt_[alt] -- auto
 .Opt_[alt] -- default
-.Opt_[alt] -- default-modes mode1,mode2,\*[Ellipsis]
+.Opt_[alt] -- default\-modes mode1,mode2,\*[Ellipsis]
 .Opt_[alt] -- dvi
-.Opt_[alt] -- dvi-viewer prog
+.Opt_[alt] -- dvi\-viewer prog
 .Opt_[alt] -- groff
 .Opt_[alt] -- html
-.Opt_[alt] -- html-viewer prog
-.Opt_[alt] -- man
+.Opt_[alt] -- html\-viewer prog
 .Opt_[alt] -- mode display_mode
-.Opt_[alt] -- no-man
 .Opt_[alt] -- pdf
-.Opt_[alt] -- pdf-viewer prog
+.Opt_[alt] -- pdf\-viewer prog
 .Opt_[alt] -- ps
-.Opt_[alt] -- ps-viewer prog
+.Opt_[alt] -- ps\-viewer prog
 .Opt_[alt] -- text
 .Opt_[alt] -- tty
-.Opt_[alt] -- tty-viewer prog
+.Opt_[alt] -- tty\-viewer prog
 .Opt_[alt] -- www
-.Opt_[alt] -- www-viewer prog
+.Opt_[alt] -- www\-viewer prog
 .Opt_[alt] -- x -- X
-.Opt_[alt] -- x-viewer -- X-viewer prog
-.RE
-.
-.
-.TP
-.I development options
-.RS
-.P
-.Opt_[alt] -- debug
-.Opt_[alt] -- shell
+.Opt_[alt] -- x\-viewer -- X\-viewer prog
 .RE
 .
 .
 .TP
-.I options related to groff
+.I options related to \%groff
 .RS
 .P
-.Opt_[alt] - P -- postproc-arg opt_or_arg
-.Opt_[alt] - Q -- source
 .Opt_[alt] - T -- device device
-.Opt_[alt] - Z -- intermediate-output -- ditroff
+.Opt_[alt] - Z -- intermediate\-output -- ditroff
 .P
 All further
-.I groff
+.B \%groff
 short options are accepted.
 .RE
 .
 .
 .TP
-.I X Window toolkit options
-.RS
-.P
-.Opt_[alt] -- bd pixels
-.Opt_[alt] -- bg -- background color
-.Opt_[alt] -- bw pixels
-.Opt_[alt] -- display X-display
-.Opt_[alt] -- fg -- foreground color
-.Opt_[alt] -- ft -- font font_name
-.Opt_[alt] -- geometry size_pos
-.Opt_[alt] -- resolution value
-.Opt_[alt] -- rv
-.Opt_[alt] -- title string
-.Opt_[alt] -- xrm X_resource
-.RE
+.I options for man\~pages
+.Opt_[alt] -- apropos
+.Opt_[alt] -- apropos\-data
+.Opt_[alt] -- apropos\-devel
+.Opt_[alt] -- apropos\-progs
+.Opt_[alt] -- man
+.Opt_[alt] -- no-man
+.Opt_[alt] -- no-special
+.Opt_[alt] -- whatis
 .
 .
 .TP
-.I options from man
+.I long options taken over from GNU man
 .RS
 .P
 .Opt_[alt] -- all
@@ -837,25 +861,67 @@
 .Opt_[alt] -- extension suffix
 .Opt_[alt] -- locale language
 .Opt_[alt] -- local-file
+.Opt_[alt] -- location -- where
 .Opt_[alt] -- manpath dir1:dir2:\*[Ellipsis]
+.Opt_[alt] -- no-location
 .Opt_[alt] -- pager program
 .Opt_[alt] -- sections sec1:sec2:\*[Ellipsis]
 .Opt_[alt] -- systems sys1,sys2,\*[Ellipsis]
 .Opt_[alt] -- troff-device device
-.Opt_[alt] -- whatis
 .P
-Further long options of GNU
-.I man
+Further long options of \f[CR]GNU\f[]
+.B man
 are accepted as well.
 .RE
 .
 .
 .TP
-.I filespec argument
+.I X Window Toolkit options
+.RS
+.P
+.Opt_[alt] -- bd -- bordercolor pixels
+.Opt_[alt] -- bg -- background color
+.Opt_[alt] -- bw -- borderwidth pixels
+.Opt_[alt] -- display X-display
+.Opt_[alt] -- fg -- foreground color
+.Opt_[alt] -- fn -- ft -- font font_name
+.Opt_[alt] -- geometry size_pos
+.Opt_[alt] -- resolution value
+.Opt_[alt] -- rv
+.Opt_[alt] -- title string
+.Opt_[alt] -- xrm X-resource
+.RE
+.
+.
+.TP
+.I options for development
+.RS
+.P
+.Opt_[alt] -- debug
+.Opt_[alt] -- debug\-all
+.Opt_[alt] -- debug\-filenames
+.Opt_[alt] -- debug\-func
+.Opt_[alt] -- debug\-keep
+.Opt_[alt] -- debug\-lm
+.Opt_[alt] -- debug\-params
+.Opt_[alt] -- debug\-shell
+.Opt_[alt] -- debug\-stacks
+.Opt_[alt] -- debug\-tmpdir
+.Opt_[alt] -- debug\-user
+.Opt_[alt] -- do\-nothing
+.Opt_[alt] -- print text
+.Opt_[alt] -- shell prog
+.Opt_[alt] - Q -- source
+.Opt_[alt] - V
+.RE
+.
+.
+.TP
+.I \%filespec arguments
 .RS
 .P
 No
-.I filespec
+.I \%filespec
 parameters means standard input.
 .
 .
@@ -873,9 +939,9 @@
 .BI man: name ( section )
 .TP+
 .IB name ( section )
-search the man\~page
-.I name
-in man\~section\~\c
+search the \%man\~page
+.I \%name
+in \%man\~section
 .IR section .
 .
 .
@@ -886,17 +952,17 @@
 if
 .I s
 is a character in
-.BR [1-9on] ,
-search for a man\~page
-.I name
-in man\~section
+.BR \%[1-9on] ,
+search for a \%man\~page
+.I \%name
+in \%man\~section
 .IR s .
 .
 .
 .TP
 .BI man: name
-man\~page in the lowest man\~section that has
-.IR name .
+\%man\~page in the lowest \%man\~section that has
+.IR \%name .
 .
 .
 .TP
@@ -904,19 +970,19 @@
 if
 .I s
 is a character in
-.BR [1-9on] ,
-search for a man\~page
-.I name
-in man\~section
+.BR \%[1-9on] ,
+search for a \%man\~page
+.I \%name
+in \%man\~section
 .IR s .
 .
 .
 .TP
 .I name
-if 
-.I name
+if
+.I \%name
 is not an existing file search for the man\~page
-.I name
+.I \%name
 in the lowest man\~section.
 .
 .RE
@@ -927,7 +993,7 @@
 .\" --------------------------------------------------------------------
 .
 The
-.I groffer
+.B \%groffer
 program can usually be run with very few options.
 .
 But for special purposes, it supports many options.
@@ -937,66 +1003,49 @@
 .
 .P
 All short options of
-.I groffer
+.B \%groffer
 are compatible with the short options of
-.BR groff (@MAN1EXT@).
+.BR \%groff (@MAN1EXT@).
 .
 All long options of
-.I groffer
+.B \%groffer
 are compatible with the long options of
-.BR man (1).
-.
-.
-.\" --------------------------------------------------------------------
-.SS "groffer breaking Options"
-.\" --------------------------------------------------------------------
+.BR \%man (1).
 .
-As soon as one of these options is found on the command line it is
-executed, printed to standard output, and the running
-.I groffer
-is terminated thereafter.
-.
-All other arguments are ignored.
 .
+.P
+Arguments for long option names can be abbreviated in several ways.
 .
-.Opt_def -- apropos name
-Start the
-.BR apropos (1)
-command for searching within man page
-descriptions.
+First, the argument is checked whether it can be prolonged as is.
 .
-That slightly differs from the strange behavior of the
-.Opt_long apropos
-program of
-.BR man (1),
-which has no argument of its own, but takes the file arguments
-instead.
+Furthermore, each minus sign
+.Opt_short
+is considered as a starting point for a new abbreviation.
 .
-Practically both concepts are compatible.
+This leads to a set of multiple abbreviations for a single argument.
 .
+For example,
+.Opt_long de\-n\-f
+can be used as an abbreviation for
+.Opt_long debug\-not\-func ,
+but
+.Opt_long de\-n
+works as well.
 .
-.Opt_def -- apropos-data name
-Show only the
-.BR apropos (1)
-descriptions for data documents, in the
-.BR man (7)
-sections 4, 5, and 7.
+If the abbreviation of the argument leads to several resulting options
+an error is raised.
 .
 .
-.Opt_def -- apropos-devel name
-Show only the
-.BR apropos (1)
-descriptions for development documents, in the
-.BR man (7)
-sections 2, 3, and 9.
+.\" --------------------------------------------------------------------
+.SS "groffer breaking Options"
+.\" --------------------------------------------------------------------
 .
+As soon as one of these options is found on the command line it is
+executed, printed to standard output, and the running
+.B \%groffer
+is terminated thereafter.
 .
-.Opt_def -- apropos-progs name
-Show only the
-.BR apropos (1)
-descriptions for documents on programs, in the
-.BR man (7)
-sections 1, 6, and 8.
+All other arguments are ignored.
 .
 .
 .Opt_def - h -- help
@@ -1016,9 +1065,62 @@
 options.
 .
 If none of these mode and viewer options is specified
-.I groffer
+.B \%groffer
 tries to find a suitable display mode automatically.
 .
+The default modes are
+.IR "mode pdf" ,
+.IR "mode ps" ,
+.IR "mode html" ,
+.IR "mode x" ,
+and
+.I "mode dvi"
+in \%\f[CR]X\~Window\f[] with different viewers and
+.I mode tty
+with device
+.I latin1
+under
+.B less
+on a terminal; other modes are tested if the programs for the main
+default mode do not exist.
+.
+.
+.P
+In \%\f[CR]X\~Window\f[],
+many programs create their own window when called.
+.B \%groffer
+can run these viewers as an independent program in the background.
+.
+As this does not work in text mode on a terminal (tty) there must be a
+way to know which viewers are \%\f[CR]X\~Window\f[] graphical
+programs.
+.
+The
+.B \%groffer
+script has a small set of information on some viewer names.
+.
+If a viewer argument of the command\-line chooses an element that is
+kept as \%\f[CR]X\~Window\f[] program in this list it is treated as a
+viewer that can run in the background.
+.
+All other, unknown viewer calls are not run in the background.
+.
+.
+.P
+For each mode, you are free to choose whatever viewer you want.
+.
+That need not be some graphical viewer suitable for this mode.
+.
+There is a chance to view the output source; for example, the
+combination of the options
+.Opt_long mode=ps
+and
+.Opt_long ps\-viewer=less
+shows the content of the
+.I Postscript
+output, the source code, with the pager
+.BR less .
+.
 .
 .Opt_def -- auto
 Equivalent to
@@ -1030,13 +1132,13 @@
 to the default values.
 .
 This is useful to wipe out all former options of the configuration, in
-.Env_var $GROFFER_OPT ,
+.Env_var \%$GROFFER_OPT ,
 and restart option processing using only the rest of the command line.
 .
 .
-.Opt_def -- default-modes mode1,mode2,\*[Ellipsis]
+.Opt_def -- default\-modes mode1,mode2,\*[Ellipsis]
 Set the sequence of modes for
-.I auto mode
+.I \%auto\~mode
 to the comma separated list given in the argument.
 .
 See
@@ -1046,26 +1148,29 @@
 .IR x ,
 .IR ps ,
 and
-.I tty
+.I \%tty
 in this sequence.
 .
 .
 .
 .Opt_def -- dvi
 Equivalent to
-.Opt_long_arg mode dvi .
+.Opt_long_arg mode \%dvi .
 .
 .
-.Opt_def -- dvi-viewer prog
-Set the viewer program for dvi mode.
+.Opt_def -- dvi\-viewer prog
+Choose a viewer program for
+.IR \%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)
+Known \%\f[CR]X\~Window\f[]
+.I \%dvi
+viewers include
+.BR \%xdvi (1)
 and
-.BR dvilx (1)
+.BR \%dvilx (1)
 .
 In each case, arguments can be provided additionally.
 .
@@ -1080,9 +1185,14 @@
 .Opt_long_arg mode html .
 .
 .
-.Opt_def -- html-viewer
-Equivalent to
-.Opt_long www-viewer .
+.Opt_def -- html\-viewer
+Choose a web browser program for viewing in
+.IR \%html\~mode .
+.
+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 -- mode value
@@ -1098,21 +1208,22 @@
 Select the automatic determination of the display mode.
 .
 The sequence of modes that are tried can be set with the
-.Opt_long default-modes
+.Opt_long default\-modes
 option.
 .
-Useful for restoring the default mode when a different mode was
-specified before.
+Useful for restoring the
+.I \%default\~mode
+when a different mode was specified before.
 .
 .
 .TP
 .Header_CB dvi
 Display formatted input in a
-.I dvi
+.I \%dvi
 viewer program.
 .
 By default, the formatted input is displayed with the
-.BR xdvi (1)
+.BR \%xdvi (1)
 program.
 .Opt_long dvi .
 .
@@ -1120,13 +1231,13 @@
 .TP
 .Header_CB groff
 After the file determination, switch
-.I groffer
+.B \%groffer
 to process the input like
-.BR groff (@MAN1EXT@)
-would do .
+.BR \%groff (@MAN1EXT@)
+would do.
 .
 This disables the
-.I groffer
+.I \%groffer
 viewing features.
 .
 .
@@ -1137,54 +1248,55 @@
 .
 By default, the existence of a sequence of standard web browsers is
 tested, starting with
-.BR konqueror (1)
+.BR \%konqueror (1)
 and
-.BR mozilla (1).
+.BR \%mozilla (1).
 The text html viewer is
-.BR lynx (1).
+.BR \%lynx (1).
 .
 .
 .TP
 .Header_CB pdf
 Display formatted input in a
-.I PDF
+.I \%PDF
 (Portable Document Format) viewer
 program.
 .
-By default, the input is formatted by groff using the Postscript
-device, then it is transformed into the PDF file format using
-.BR gs (1),
-and finally displayed either with the
-.BR xpdf (1)
-or the
-.BR acroread (1)
-program.
+By default, the input is formatted by
+.B \%groff
+using the Postscript device, then it is transformed into the PDF file
+format using
+.BR \%gs (1),
+or
+.BR ps2pdf (1).
+If that's not possible, the
+.I Postscript mode (ps)
+is used instead.
 .
-PDF has a big advantage because the text is displayed graphically and
-is searchable as well.
+Finally it is displayed using different viewer programs.
 .
-But as the transformation takes a considerable amount of time, this
-mode is not suitable as a default device for the auto mode.
+.I \%pdf
+has a big advantage because the text is displayed graphically and
+is searchable as well.
 .
 .
 .TP
 .Header_CB ps
 Display formatted input in a Postscript viewer program.
 .
-By default, the formatted input is displayed with the
-.BR ghostview (@MAN1EXT@)
-program.
+By default, the formatted input is displayed in one of many viewer
+programs.
 .
 .
 .TP
 .Header_CB text
 Format in a
-.I groff
-text mode and write the result to standard output without a pager or
-viewer program.
+.I \%groff\~text\~mode
+and write the result to standard output without a pager or viewer
+program.
 .
 The text device,
-.I latin1
+.I \%latin1
 by default, can be chosen with option
 .Opt_short T .
 .
@@ -1192,37 +1304,68 @@
 .TP
 .Header_CB tty
 Format in a
-.I groff
-text mode and write the result to standard output using a text pager
-program, even when in X Window.
+.I \%groff\~text\~mode
+and write the result to standard output using a text pager program,
+even when in \%\f[CR]X\~Window\f[].
 .
 .
 .TP
 .Header_CB www
 Equivalent to
-.Opt_long www .
+.Opt_long_arg mode html .
 .
 .
 .TP
-.Header_CB X
-Display formatted input in a native roff viewer.
+.Header_CB x
+Display the formatted input in a native
+.I roff
+viewer.
 .
 By default, the formatted input is displayed with the
-.BR gxditview (@MAN1EXT@)
-program, being distributed together with groff, or with
-.BR xditview (1),
-which is distributed as a standard X tool.
+.BR \%gxditview (@MAN1EXT@)
+program being distributed together with
+.BR \%groff .
+But the standard \%\f[CR]X\~Window\f[] tool
+.BR \%xditview (1)
+can also be chosen with the option
+.Opt_long x\-viewer .
+The default resolution is
+.BR 75\~dpi ,
+but
+.B 100\~dpi
+are also possible.
+.
+The default
+.I groff
+device
+for the resolution of
+.B 75\~dpi
+is
+.BR X75\-12 ,
+for
+.B 100\~dpi
+it is
+.BR X100 .
+.
+The corresponding
+.I "groff intermediate output"
+for the actual device is generated and the result is displayed.
+.
+For a resolution of
+.BR 100\~dpi ,
+the default width of the geometry of the display program is chosen to
+.BR 850\~dpi .
 .
 .
 .TP
-.Header_CB x
+.Header_CB X
 Equivalent to
-.Opt_long_arg mode X .
+.Opt_long_arg mode x .
 .
 .
 .P
 The following modes do not use the
-.I groffer
+.I \%groffer
 viewing features.
 .
 They are only interesting for advanced applications.
@@ -1231,15 +1374,15 @@
 .TP
 .Header_CB groff
 Generate device output with plain
-.I groff
+.I \%groff
 without using the special viewing features of
-.IR groffer .
+.IR \%groffer .
 If no device was specified by option
 .Opt_short T
 the
-.I groff
+.I \%groff
 default
-.B ps
+.B \%ps
 is assumed.
 .
 .
@@ -1257,15 +1400,13 @@
 .Opt_long_arg mode pdf .
 .
 .
-.Opt_def -- pdf-viewer prog
-Set the viewer program for
-.I pdf
-mode.
+.Opt_def -- pdf\-viewer prog
+Choose a viewer program for
+.IR \%pdf\~mode .
 .
 This can be a file name or a program to be searched in
-.Env_var $PATH .
-.
-In each case, arguments can be provided additionally.
+.Env_var $PATH ;
+arguments can be provided additionally.
 .
 .
 .Opt_def -- ps
@@ -1273,19 +1414,18 @@
 .Opt_long_arg mode ps .
 .
 .
-.Opt_def -- ps-viewer prog
-Set the viewer program for
-.I ps
-mode.
+.Opt_def -- ps\-viewer prog
+Choose a viewer program for
+.IR \%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),
+.BR \%gv (1),
+.BR \%ghostview (1),
 and
-.BR gs (1),
+.BR \%gs (1),
 .
 In each case, arguments can be provided additionally.
 .
@@ -1300,164 +1440,123 @@
 .Opt_long_arg mode tty .
 .
 .
-.Opt_def -- tty-viewer
-Choose tty display mode, that means displaying in a text pager even
-when in X; eqivalent to
-.Opt_long_arg mode tty .
+.Opt_def -- tty\-viewer prog
+Choose a text pager for mode
+.IR tty .
+The standard pager is
+.BR less (1).
+This option is eqivalent to
+.I man
+option
+.Opt_long_arg pager prog .
+The option argument can be a file name or a program to be searched in
+.Env_var $PATH ;
+arguments can be provided additionally.
 .
 .
 .Opt_def -- www
 Equivalent to
-.Opt_long_arg mode www .
-.
+.Opt_long_arg mode html .
 .
-.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 as viewer program; 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 -- www\-viewer prog
+Equivalent to
+.Opt_long html\-viewer .
 .
 .
-.Opt_def - X -- X -- x
+.Opt_def -- X -- x
 Equivalent to
-.Opt_long_arg mode X .
+.Opt_long_arg mode x .
 .
 .
-.Opt_def -- X-viewer -- x-viewer prog
-Set the viewer program for
-.I x
-mode.
-.
+.Opt_def -- X\-viewer -- x\-viewer prog
+Choose a viewer program for
+.IR \%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.
+.BR \%gxditview (@MAN1EXT@)
+which is the default and
+.BR \%xditview (1).
+The argument can be any executable file or a program in
+.Env_var $PATH ;
+arguments can be provided additionally.
 .
 .
 .TP
 .Opt_--
 Signals the end of option processing; all remaining arguments are
 interpreted as
-.I filespec
+.I \%filespec
 parameters.
 .
 .
 .P
 Besides these,
-.I groffer
-accepts all arguments that are valid for the
-.BR groff (@MAN1EXT@)
+.B \%groffer
+accepts all short options that are valid for the
+.BR \%groff (@MAN1EXT@)
 program.
 .
-All non-groffer options are sent unmodified via
-.I grog
+All
+.RB \%non- groffer
+options are sent unmodified via
+.B \%grog
 to
-.IR groff .
+.BR \%groff .
 .
-Postprocessors, macro packages, compatibility with classical
-.IR troff ,
+So postprocessors, macro packages, compatibility with
+.I classical
+.IR \%troff ,
 and much more can be manually specified.
 .
 .
 .\" --------------------------------------------------------------------
-.SH "Options for Development"
-.\" --------------------------------------------------------------------
-.
-.Opt_def -- debug
-Print debugging information for development only.
-.
-Actually, a function call stack is printed if an error occurs.
-.
-.
-.Opt_def -- shell "shell_program"
-Specify the shell under which the groffer script should be run.
-.
-The script first tests whether this option is set (either by
-configuration, within
-.Env_var $GROFF_OPT
-or as a command line option); if so, the script is rerun under the
-shell program specified with the option argument.
-.
-.
-.Opt_def - Q -- source
-Output the roff source code of the input files without further
-processing.
-.
-This is the equivalent
-.Opt_long_arg mode source .
-.
-.
-.P
-Other useful debugging options are the
-.I groff
-options
-.Opt_short V
-and
-.Opt_short Z
-and option
-.Opt_long_arg mode groff .
-.
-.
-.\" --------------------------------------------------------------------
-.SH "Options related to groff"
+.SS "Options related to groff"
 .\" --------------------------------------------------------------------
 .
 All short options of
-.I groffer
+.B \%groffer
 are compatible with the short options of
-.BR groff (@MAN1EXT@).
+.BR \%groff (@MAN1EXT@).
 .
 The following of
-.I groff
+.B \%groff
 options have either an additional special meaning within
-.I groffer
+.B \%groffer
 or make sense for normal usage.
 .
 .
 .P
 Because of the special outputting behavior of the
-.I groff
-options
-.Opt_short V
-and
+.B \%groff
+option
 .Opt_short Z
-.I groffer
+.B \%groffer
 was designed to be switched into
-.I groff
-mode by these; the
-.I groffer
+.I \%groff\~mode ;
+the
+.I \%groffer
 viewing features are disabled there.
 .
 The other
-.I groff
+.B \%groff
 options do not switch the mode, but allow to customize the formatting
 process.
 .
 .
 .Opt_def - a
-This generates an ascii approximation of output in text modes.
+This generates an ascii approximation of output in the
+.IR \%text\~modes .
 .
 That could be important when the text pager has problems with control
-sequences.
+sequences in
+.IR "tty mode" .
 .
 .
 .Opt_def - m file
 Add
-.I file
+.I \%file
 as a
-.I groff
+.I \%groff
 macro file.
 .
 This is useful in case it cannot be recognized automatically.
@@ -1465,146 +1564,457 @@
 .
 .Opt_def - P opt_or_arg
 Send the argument
-.I opt_or_arg
+.I \%opt_or_arg
 as an option or option argument to the actual
-.I groff
+.B \%groff
 postprocessor.
 .
 .
 .Opt_def - T -- device devname
 .
 This option determines
-.IR groff 's
+.BR \%groff 's
 output device.
 .
 The most important devices are the text output devices for referring
 to the different character sets, such as
-.BR ascii ,
-.BR utf8 ,
-.BR latin1 ,
+.BR \%ascii ,
+.BR \%utf8 ,
+.BR \%latin1 ,
 and others.
 .
 Each of these arguments switches
-.I groffer
-into a text mode using this device, to
-.I mode tty
-if the actual mode is not a text mode.
+.B \%groffer
+into a
+.I \%text\~mode
+using this device, to
+.I \%mode\~tty
+if the actual mode is not a
+.IR \%text\~mode .
 .
 The following
-.I devname
+.I \%devname
 arguments are mapped to the corresponding
-.I groffer
+.B \%groffer
 .Opt_long_arg mode \fIdevname\fR
 option:
-.BR dvi ,
-.BR html ,
+.BR \%dvi ,
+.BR \%html ,
 and
-.BR ps .
+.BR \%ps .
 All
-.B X*
-arguments are mapped to mode
-.BR X .
+.B \%X*
+arguments are mapped to
+.IR \%mode\~x .
 Each other
-.I devname
+.I \%devname
 argument switches to
-.I mode groff
+.I \%mode\~groff
 using this device.
 .
 .
-.Opt_def - V
-Switch into
-.I groff
-mode and show only the
-.I groff
-calling pipe without formatting the input.
-.
-This an advanced option from
-.BR groff (@MAN1EXT@) ,
-only useful for debugging.
-.
-.
 .Opt_def - X
-was made equivalent to
-.Opt_long_arg mode x ;
-this slightly enhances the facility of
-.IR groff 's
-option.
+is equivalent to
+.BR "groff \-X" .
+It displays the
+.I groff intermediate output
+with
+.BR gxditview .
+As the quality is relatively bad this option is deprecated; use
+.Opt_long X
+instead because the
+.I \%x\~mode
+uses an
+.IR X *
+device for a better display.
 .
 .
 .Opt_def - Z -- intermediate-output -- ditroff
 Switch into
-.I groff
-mode and format the input with
-.I groff
-intermediate output without postprocessing; see
-.BR groff_out (@MAN1EXT@).
+.I \%groff\~mode
+and format the input with the
+.I \%groff intermediate output
+without postprocessing; see
+.BR \%groff_out (@MAN5EXT@).
 This is equivalent to option
 .Opt_long ditroff
 of
-.IR man ,
+.IR \%man ,
 which can be used as well.
 .
 .
 .P
 All other
-.I groff
+.B \%groff
 options are supported by
-.IR groffer ,
+.BR \%groffer ,
 but they are just transparently transferred to
-.I groff
+.B \%groff
 without any intervention.
 .
 The options that are not explicitly handled by
-.I groffer
+.B \%groffer
 are transparently passed to
-.IR groff .
+.BR \%groff .
 .
 Therefore these transparent options are not documented here, but in
-.BR groff (@MAN1EXT@).
+.BR \%groff (@MAN1EXT@).
 Due to the automatism in
-.IR groffer ,
+.BR \%groffer ,
 none of these
-.I groff
+.B \%groff
 options should be needed, except for advanced usage.
 .
 .
 .\" --------------------------------------------------------------------
-.SS "X Window toolkit Options"
+.SS "Options for man\~pages"
 .\" --------------------------------------------------------------------
 .
-The following long options were adapted from the corresponding X
-Toolkit options.
+.Opt_def -- apropos
+Start the
+.BR \%apropos (1)
+command or facility of
+.BR \%man (1)
+for searching the
+.I \%filespec
+arguments within all
+.I \%man\~page
+descriptions.
 .
-.I groffer
-will pass them to the actual viewer program if it is an X Window
-program.
+Each
+.I \%filespec
+argument is taken for search as it is;
+.I section
+specific parts are not handled, such that
+.B 7 groff
+searches for the two arguments
+.B 7
+and
+.BR groff ,
+with a large result; for the
+.I \%filespec
+.B groff.7
+nothing will be found.
 .
-Otherwise these options are ignored.
+The
+.I language
+locale is handled only when the called programs do support this; the
+GNU
+.B apropos
+and
+.B man \-k
+do not.
 .
+The display differs from the
+.B \%apropos
+program by the following concepts:
+.RS
+.Topic
+Construct a
+.I \%groff
+frame similar to a
+.I \%man\~page
+to the output of
+.BR \%apropos ,
+.Topic
+each
+.I \%filespec
+argument is searched on its own.
+.Topic
+The restriction by
+.Opt_long sections
+is handled as well,
+.Topic
+wildcard characters are allowed and handled without a further option.
+.RE
 .
-.P
-Unfortunately these options use the old style of a single minus for
-long options.
 .
-For
-.I groffer
-that was changed to the standard with using a double minus for long
-options, for example,
-.I groffer
-uses the option
-.Opt_long font
-for the
-.I X
-option
-.Opt_short font .
+.Opt_def -- apropos\-data
+Show only the
+.B \%apropos
+descriptions for data documents, these are the
+.BR \%man (7)
+.IR sections\~4 ", " 5 ", and " 7 .
 .
+Direct
+.I section
+declarations are ignored, wildcards are accepted.
 .
-.P
+.
+.Opt_def -- apropos\-devel
+Show only the
+.B \%apropos
+descriptions for development documents, these are the
+.BR man (7)
+.IR sections\~2 ", " 3 ", and " 9 .
+.
+Direct
+.I section
+declarations are ignored, wildcards are accepted.
+.
+.
+.Opt_def -- apropos\-progs
+Show only the
+.B \%apropos
+descriptions for documents on programs, these are the
+.BR \%man (7)
+.IR sections\~1 ", " 6 ", and " 8 .
+.
+Direct
+.I section
+declarations are ignored, wildcards are accepted.
+.
+.
+.Opt_def -- whatis
+For each
+.I \%filespec
+argument search all
+.I \%man\~pages
+and display their description \[em] or say that it is not a
+.IR \%man\~page .
+This is written from anew, so it differs from
+.IR man 's
+.B whatis
+output by the following concepts
+.RS
+.Topic
+each retrieved file name is added,
+.Topic
+local files are handled as well,
+.Topic
+the \fIlanguage\fP and \fIsystem\fP locale is supported,
+.Topic
+the display is framed by a
+.I groff
+output format similar to a
+.IR \%man\~page ,
+.Topic
+wildcard characters are allowed without a further option.
+.RE
+.
+.
+.P
+The following options were added to
+.B \%groffer
+for choosing whether the file name arguments are interpreted as names
+for local files or as a search pattern for
+.IR \%man\~pages .
+.
+The default is looking up for local files.
+.
+.
+.Opt_def -- man
+Check the non-option command line arguments
+.nh
+.RI ( filespecs )
+.hy
+first on being
+.IR \%man\~pages ,
+then whether they represent an existing file.
+.
+By default, a
+.I \%filespec
+is first tested whether it is an existing file.
+.
+.
+.Opt_def -- no-man -- local-file
+Do not check for
+.IR \%man\~pages .
+.
+.Opt_long local-file
+is the corresponding
+.B man
+option.
+.
+.
+.Opt_def -- no-special
+Disable former calls of
+.Opt_long all ,
+.Opt_long apropos* ,
+and
+.Opt_long whatis .
+.
+.
+.\" --------------------------------------------------------------------
+.SS "Long options taken over from GNU man"
+.\" --------------------------------------------------------------------
+.
+The long options of
+.B \%groffer
+were synchronized with the long options of \f[CR]GNU\f[]
+.BR man .
+.
+All long options of \f[CR]GNU\f[]
+.B man
+are recognized, but not all of these options are important to
+.BR \%groffer ,
+so most of them are just ignored.
+.
+These ignored
+.B man
+options are
+.Opt_long catman ,
+.Opt_long troff ,
+and
+.Opt_long update .
+.
+.
+.P
+In the following, the
+.B man
+options that have a special meaning for
+.B \%groffer
+are documented.
+.
+.
+.P
+If your system has \f[CR]GNU\f[]
+.B man
+installed the full set of long and short options of the \f[CR]GNU\f[]
+.B man
+program can be passed via the environment variable
+.Env_var \%$MANOPT ;
+see
+.BR \%man (1).
+.
+.
+.Opt_def -- all
+In searching
+.IR \%man\~pages ,
+retrieve all suitable documents instead of only one.
+.
+.
+.Opt_def - 7 -- ascii
+In
+.IR \%text\~modes ,
+display ASCII translation of special characters for critical environment.
+.
+This is equivalent to
+.BR "groff -mtty_char" ;
+see
+.BR groff_tmac (@MAN5EXT@).
+.
+.
+.Opt_def -- ditroff
+Produce
+.IR "groff intermediate output" .
+This is equivalent to
+.B \%groffer
+.Opt_short Z .
+.
+.
+.Opt_def -- extension suffix
+Restrict
+.I \%man\~page
+search to file names that have
+.I \%suffix
+appended to their section element.
+.
+For example, in the file name
+.I \%/usr/share/man/man3/terminfo.3ncurses.gz
+the
+.I \%man\~page
+extension is
+.IR \%ncurses .
+.
+.
+.Opt_def -- locale language
+.
+Set the language for
+.IR \%man\~pages .
+.
+This has the same effect, but overwrites
+.Env_var $LANG
+.
+.
+.Opt_def -- location
+Print the location of the retrieved files to standard error.
+.
+.
+.Opt_def -- no-location
+Do not display the location of retrieved files; this resets a former
+call to
+.Opt_long location .
+.
+This was added by
+.BR \%groffer .
+.
+.
+.Opt_def -- manpath "'dir1:dir2:\*[Ellipsis]'"
+Use the specified search path for retrieving
+.I \%man\~pages
+instead of the program defaults.
+.
+If the argument is set to the empty string "" the search for
+.I \%man\~page
+is disabled.
+.
+.
+.Opt_def -- pager
+Set the pager program in
+.IR \%tty\~mode ;
+default is
+.BR \%less .
+This is equivalent to
+.Opt_long tty\-viewer .
+.
+.
+.Opt_def -- sections "'sec1:sec2:\*[Ellipsis]'"
+Restrict searching for
+.I \%man\~pages
+to the given
+.IR sections ,
+a colon-separated list.
+.
+.
+.Opt_def -- systems "'sys1,sys2,\*[Ellipsis]'"
+Search for
+.I \%man\~pages
+for the given operating systems; the argument
+.I \%systems
+is a comma-separated list.
+.
+.
+.Opt_def -- where
+Eqivalent to
+.Opt_long location .
+.
+.
+.\" --------------------------------------------------------------------
+.SS "X\~\%Window\~\%Toolkit Options"
+.\" --------------------------------------------------------------------
+.
+The following long options were adapted from the corresponding
+\%\f[CR]X\~\Window\~Toolkit\f[] options.
+.
+.B \%groffer
+will pass them to the actual viewer program if it is an
+\%\f[CR]X\~Window\f[] program.
+.
+Otherwise these options are ignored.
+.
+.
+.P
+Unfortunately these options use the old style of a single minus for
+long options.
+.
+For
+.B \%groffer
+that was changed to the standard with using a double minus for long
+options, for example,
+.B \%groffer
+uses the option
+.Opt_long font
+for the \%\f[CR]X\~Window\f[] option
+.Opt_short font .
+.
+.
+.P
 See
-.BR X (1),
-.BR X (7),
-and the documentation on the X toolkit options for more details on
-these options and their arguments.
+.BR \%X (1),
+.BR \%X (7),
+and the documentation on the \%\f[CR]X\~Window\~Toolkit\f[] options
+for more details on these options and their arguments.
 .
 .
 .Opt_def -- background color
@@ -1612,7 +2022,8 @@
 .
 .
 .Opt_def -- bd pixels
-Specifies the color of the border surrounding the viewer window.
+This is equivalent to
+.Opt_long bordercolor .
 .
 .
 .Opt_def -- bg color
@@ -1621,14 +2032,23 @@
 .
 .
 .Opt_def -- bw pixels
+This is equivalent to
+.Opt_long borderwidth .
+.
+.
+.Opt_def -- bordercolor pixels
+Specifies the color of the border surrounding the viewer window.
+.
+.
+.Opt_def -- borderwidth pixels
 Specifies the width in pixels of the border surrounding the viewer
 window.
 .
 .
 .Opt_def -- display X-display
-Set the X display on which the viewer program shall be started, see the
-.I X Window
-documentation for the syntax of the argument.
+Set the \%\f[CR]X\~Window\f[] display on which the viewer program
+shall be started, see the \%\f[CR]X\~Window\f[] documentation for the
+syntax of the argument.
 .
 .
 .Opt_def -- foreground color
@@ -1640,15 +2060,20 @@
 .Opt_short foreground .
 .
 .
+.Opt_def -- fn font_name
+This is equivalent to
+.Opt_long font .
+.
+.
 .Opt_def -- font font_name
 Set the font used by the viewer window.
 .
-The argument is an X font name.
+The argument is an \%\f[CR]X\~Window\f[] font name.
 .
 .
 .Opt_def -- ft font_name
 This is equivalent to
-.Opt_long ft .
+.Opt_long font .
 .
 .
 .Opt_def -- geometry size_pos
@@ -1656,12 +2081,13 @@
 starting position.
 .
 See
-.BR X (7)
+.BR \%X (7)
 for the syntax of the argument.
 .
 .
 .Opt_def -- resolution value
-Set X resolution in dpi (dots per inch) in some viewer programs.
+Set \%\f[CR]X\~Window\f[] resolution in dpi (dots per inch) in some
+viewer programs.
 .
 The only supported dpi values are
 .B 75
@@ -1669,9 +2095,11 @@
 .BR 100 .
 .
 Actually, the default resolution for
-.I groffer
+.B \%groffer
 is set to
-.BR 75 .
+.BR 75\~dpi .
+The resolution also sets the default device in
+.IR "mode x" .
 .
 .
 .Opt_def -- rv
@@ -1683,162 +2111,165 @@
 .
 .
 .Opt_def -- xrm "'resource'"
-Set X resource.
+Set \f[CR]\%X\~Window\f[] resource.
 .
 .
 .\" --------------------------------------------------------------------
-.SS "Options from man"
+.SS "Options for Development"
 .\" --------------------------------------------------------------------
 .
-The long options of
-.I groffer
-were synchronized with the long options of
-.IR GNU man .
+.Opt_def -- debug
+Enable seven debugging informations.
 .
-All long options of
-.I GNU man
-are recognized, but not all of these options are important to
-.IR groffer ,
-so most of them are just ignored.
+The temporary files are kept and not deleted, the name of the
+temporary directory and the shell name for
+.File_name groffer2.sh
+are printed, the displayed file names are printed, the parameters are
+printed at several steps of development, and a function stack is
+output with function \f[CR]error_user()\f[] as well.
 .
+Neither the function call stack at the opening and closing of each
+function call nor the landmark information to determine how far the
+program is running are printed.
 .
-.P
-The following two options were added by
-.I groffer
-for choosing whether the file name arguments are interpreted as names
-for local files or as a search pattern for man pages.
+These seem to be the most useful parts among all debugging options.
 .
-The default is looking up for local files.
 .
+.Opt_def -- debug\-all
+Enable all nine debugging informations including the function call
+stack and the landmark information.
 .
-.Opt_def -- man
-Check the non-option command line arguments
-.RI ( filespecs )
-first on being man\~pages, then whether they represent an existing
-file.
 .
-By default, a
-.I filespec
-is first tested whether it is an existing file.
+.Opt_def -- debug\-filenames
+Print the names of the files and
+.I \%man\~pages
+that are displayed by
+.BR \&groffer .
 .
 .
-.Opt_def -- no-man -- local-file
-Do not check for man\~pages.
+.Opt_def -- debug\-func
+Enable the basic debugging information for checking the functions on
+the beginning and end of each call.
 .
-.Opt_long local-file
-is the corresponding
-.I man
-option.
+The options
+.Opt_long debug\-stacks
+and
+.Opt_long debug\-user
+enable this option automatically.
 .
+This option is important for the development, but it decreases the
+speed of
+.B groffer
+by large amounts.
 .
-.P
-In the following, the
-.I man
-options that have a special meaning for
-.I groffer
-are documented.
 .
+.Opt_def -- debug\-keep
+Enable two debugging informations, the printing of the name of the
+temporary directory and the keeping of the temporary files.
 .
-.P
-The full set of long and short options of the
-.I GNU man
-program can be passed via the environment variable
-.Env_var $MANOPT ;
-see
-.BR man (1)
-if your system has
-.I GNU man
-installed.
 .
+.Opt_def -- debug\-lm
+Enable one debugging information, the landmark information.
 .
-.Opt_def -- all
-In searching man\~pages, retrieve all suitable documents instead of
-only one.
 .
+.Opt_def -- debug\-params
+Enable one debugging information, the parameters at several steps.
 .
-.Opt_def - 7 -- ascii
-In text modes, display ASCII translation of special characters.
 .
+.Opt_def -- debug\-shell
+Enable one debugging information, the shell name for
+.File_name groffer2.sh .
 .
-.Opt_def -- ditroff
-Eqivalent to
-.I groffer
-.Opt_short Z .
 .
+.Opt_def -- debug\-stacks
+Enable one debugging information, the function call stack.
 .
-.Opt_def -- extension suffix
-Restrict man\~page search to file names that have
-.I suffix
-appended to their section element.
 .
-For example, in the file name
-.I /usr/share/man/man3/terminfo.3ncurses.gz
-the man\~page extension is
-.IR ncurses .
+.Opt_def -- debug\-tmpdir
+Enable one debugging information, the name of the temporary directory.
 .
 .
-.Opt_def -- locale language
+.Opt_def -- debug\-user
+Enable one debugging information, the function stack with
+\f[CR]error_user()\f[].
 .
-Set the language for man pages.
 .
-This has the same effect, but overwrites
-.Env_var $LANG
+.Opt_def -- do-nothing
+This is like
+.Opt_long version ,
+but without the output; no viewer is started.
 .
+This makes only sense in development.
 .
-.Opt_def -- location
-Print the location of the retrieved files to standard error.
 .
+.Opt_def -- print=text
+Just print the argument to standard error.
 .
-.Opt_def -- no-location
-Do not display the location of retrieved files; this resets a former
-call to
-.Opt_long location .
+This is good for parameter check.
 .
-This was added by
-.IR groffer .
 .
+.Opt_def -- shell "shell_program"
+Specify the shell under which the
+.File_name \%groffer2.sh
+script should be run.
 .
-.Opt_def -- manpath "'dir1:dir2:\*[Ellipsis]'"
-Use the specified search path for retrieving man\~pages instead of the
-program defaults.
+This option overwrites the automatic shell determination of the
+program.
 .
-If the argument is set to the empty string "" the search for man\~page
-is disabled.
+If the argument
+.I shell_program
+is empty a former shell option and the automatic shell determination
+is cancelled and the default shell is restored.
 .
+Some shells run considerably faster than the standard shell.
 .
-.Opt_def -- pager
-Set the pager program in tty mode; default is
-.IR less .
-This is equivalent to
-.Opt_long tty-viewer .
 .
+.Opt_def - Q -- source
+Output the roff source code of the input files without further
+processing.
 .
-.Opt_def -- sections "'sec1:sec2:\*[Ellipsis]'"
-Restrict searching for man\~pages to the given
-.IR sections ,
-a colon-separated list.
+This is the equivalent
+.Opt_long_arg mode source .
 .
 .
-.Opt_def -- systems "'sys1,sys2,\*[Ellipsis]'"
-Search for man pages for the given operating systems; the argument
-.I systems
-is a comma-separated list.
+.Opt_def - V
+This is an advanced option for debugging only.
 .
+Instead of displaying the formatted input, a lot of
+.I \%groffer
+specific information is printed to standard output:
 .
-.Opt_def -- whatis
-Instead of displaying the content, get the one-liner description from
-the retrieved man\~page files \[em] or say that it is not a man\~page.
+.RS
+.Topic
+the output file name in the temporary directory,
 .
+.Topic
+the display mode of the actual
+.B \%groffer
+run,
 .
-.Opt_def -- where
-Eqivalent to
-.Opt_long location .
+.Topic
+the display program for viewing the output with its arguments,
+.
+.Topic
+the active parameters from the config files, the arguments in
+.Env_var \%$GROFFER_OPT ,
+and the arguments of the command line,
+.
+.Topic
+the pipeline that would be run by the
+.B \%groff
+program, but without executing it.
+.RE
 .
 .
 .P
-Additionally, the following short option of
-.I man
-is supported as well.
+Other useful debugging options are the
+.B \%groff
+option
+.Opt_short Z
+and
+.Opt_long_arg mode groff .
 .
 .
 .\" --------------------------------------------------------------------
@@ -1846,63 +2277,48 @@
 .\" --------------------------------------------------------------------
 .
 A
-.I filespec
-parameter is an argument meaning an input source, such as a file name
-or template for searching man\~pages.
+.I \%filespec
+parameter is an argument that is not an option or option argument.
+.
+It means an input source.
+.
+In
+.BR \%groffer ,
+.I \%filespec
+parameters are a file name or a template for searching
+.IR \%man\~pages .
 .
 These input sources are collected and composed into a single output
 file such as
-.I groff
+.B \%groff
 does.
 .
 .
 .P
-The strange POSIX behavior that maps all arguments behind the first
-non-option argument into
-.I filespec
+The strange \%\f[CR]POSIX\f[] behavior to regard all arguments behind
+the first non-option argument as
+.I \%filespec
 arguments is ignored.
 .
-The GNU behavior to recognize options even when mixed with
-.I filespec
+The \f[CR]GNU\f[] behavior to recognize options even when mixed with
+.I \%filespec
 arguments is used througout.
 .
 But, as usual, the double minus argument
 .Opt_long
-still takes all following arguments as
-.IR filespecs .
-.
-.
-.P
-Each
-.I filespec
-parameters can have one of the following forms.
-.
-.
-.P
-No
-.I filespec
-parameters means that
-.I groffer
-waits for standard input.
-.
-The minus option
-.Opt_short ""
-stands for standard input, too, but can occur several times.
-.
-Next
-.I filespec
-is tested whether it is the path name of an existing file.
-.
-Otherwise it is assumed as a searching pattern for a man\~page.
+ends the option handling and interprets all following arguments as
+.I \%filespec
+arguments; so the \%\f[CR]POSIX\f[] behavior can be easily adopted.
 .
 .
 .P
-On each system, the man pages are sorted according to their content
-into several sections.
+For the following, it is necessary to know that on each system the
+.I \%man\~pages
+are sorted according to their content into several sections.
 .
 The
 .I classical man sections
-have a single-character name, either are a digit from
+have a single-character name, either a digit from
 .B 1
 to
 .B 9
@@ -1913,49 +2329,84 @@
 .
 In the following, a stand-alone character
 .I s
-means this scheme.
-.
-.
-.P
+stands for a
+.IR "classical man section" .
 The internal precedence of
-.I man
-for searching man pages with the same name within several sections
-goes according to the classical single-character sequence.
+.B \%man
+for searching
+.I \%man\~pages
+with the same name within several sections goes according to the
+classical single-character sequence.
 .
 On some systems, this single character can be extended by a following
 string.
 .
 But the special
-.I groffer
-man page facility is based on the classical single character sections.
+.B \%groffer
+.I \%man\~page
+facility is based on the classical single character sections.
 .
 .
 .P
-.BI man: name ( section )
+Each
+.I \%filespec
+parameter can have one of the following forms in decreasing sequence.
+.
+.
+.Topic
+No
+.I \%filespec
+parameters means that
+.B \%groffer
+waits for standard input.
+.
+The minus option
+.Opt_short ""
+always stands for standard input; it can occur several times.
+.
+If you want to look up a
+.I \%man\~page
+called
+.Opt_short ""
+use the argument
+.BR "man:\-" .
+.
+.
+.Topic
+Next a
+.I \%filespec
+is tested whether it is the path name of an existing file.
+.
+Otherwise it is assumed to be a searching pattern for a
+.IR \%man\~page .
+.
+.
+.Topic
+.BI \%man: name ( section )
 and
-.IB name ( section )
-search the man\~page
-.I name
-in man\~section\~\c
-.IR section ,
+.IB \%name ( section )
+search the \%man\~page
+.I \%name
+in \%man\~section\~\c
+.IR \%section ,
 where
-.I section
+.I \%section
 can be any string, but it must exist in the
-.I man
+.I \%man
 system.
 .
 .
-.P
+.Topic
 Next some patterns based on the
 .I classical man sections
-were constructed.
+are checked.
 .
-.BI man: name . s
+.BI \%man: name . s
 and
-.IB name . s
-search for a man\~page
-.I name
-in man\~section
+.IB \%name . s
+search for a \%man\~page
+.I \%name
+in \%man\~section
 .I s
 if
 .I s
@@ -1963,67 +2414,87 @@
 .I classical man section
 mentioned above.
 .
-Otherwise search for a man\~page named
-.IR name.s
-in the lowest
-.I man
-section.
+Otherwise a
+.I \%man\~page
+named
+.IR \%name.s
+is searched in the lowest
+.B man\~section .
 .
 .
-.P
+.Topic
 Now
-.BI man: name
-searches for a man\~page in the lowest man\~section that has a
-document called
-.IR name .
+.BI \%man: name
+searches for a
+.I \%man\~page
+in the lowest
+.I \%man\~section
+that has a document called
+.IR \%name .
 .
 .
-.P
+.Topic
 The pattern
-.I "s name"
+.I \%s\~name
 originates from a strange argument parsing of the
-.I man
+.B man
 program.
 .
 If
 .I s
 is a
 .I classical man section
-interpret it as a search for a man\~page called
-.I name
+interpret it as a search for a
+.I \%man\~page
+called
+.I \%name
 in man\~section
 .IR s ,
-otherwise interpret
+otherwise interpret both
 .I s
-as a file argument and
-.I name
-as another
-.I filespec
-argument.
+and
+.I \%name
+as two independent
+.I \%filespec
+arguments.
 .
 .
-.P
+.Topic
 We are left with the argument
-.I name
+.I \%name
 which is not an existing file.
 .
-So this searches for the man\~page called
-.I name
-in the lowest man\~section that has a document for this name.
+So this searches for the
+.I \%man\~page
+called
+.I \%name
+in the lowest
+.I \%man\~section
+that has a document for this name.
+.
+.
+.P
+Wildcards in
+.I \%filespec
+arguments are only accepted for
+.Opt_long apropos*
+and
+.Opt_long whatis ;
+for normal display, they are interpreted as characters.
 .
 .
 .P
 Several file name arguments can be supplied.
 .
 They are mixed by
-.I groff
+.B \%groff
 into a single document.
 .
 Note that the set of option arguments must fit to all of these file
 arguments.
 .
 So they should have at least the same style of the
-.I groff
+.I \%groff
 language.
 .
 .
@@ -2032,19 +2503,19 @@
 .\" --------------------------------------------------------------------
 .
 By default, the
-.I groffer
+.B \%groffer
 program collects all input into a single file, formats it with the
-.I groff
+.B \%groff
 program for a certain device, and then chooses a suitable viewer
 program.
 .
 The device and viewer process in
-.I groffer
+.B \%groffer
 is called a
-.IR mode .
+.IR \%mode .
 .
 The mode and viewer of a running
-.I groffer
+.B \%groffer
 program is selected automatically, but the user can also choose it
 with options.
 .
@@ -2056,104 +2527,111 @@
 .Opt_long \fIanymode .
 Most of these modes have a viewer program, which can be chosen by an
 option that is constructed like
-.Opt_long \fIanymode\fR-viewer .
+.Opt_long \fIanymode\fR\-viewer .
 .
 .
 .P
-Several different modes are offered, graphical X modes, text modes,
+Several different modes are offered, graphical modes for
+\f[CR]\%X\~Window\f[],
+.IR \%text\~modes ,
 and some direct
-.I groff
-modes for debugging and development.
+.I \%groff\~modes
+for debugging and development.
 .
 .
 .P
 By default,
-.I groffer
+.B \%groffer
 first tries whether
-.B x
-mode is possible, then
-.B ps
-mode, and finally
-.B tty
-mode.
+.I \%x\~mode
+is possible, then
+.IR \%ps\~mode ,
+and finally
+.IR \%tty\~mode .
 .
 This mode testing sequence for
-.B auto
-mode can be changed by specifying a comma separated list of modes
-with the option
+.I \%auto\~mode
+can be changed by specifying a comma separated list of modes with the
+option
 .Opt_long default\-modes.
 .
 .
 .P
-The searching for man\~pages and the decompression of the input are
-active in every mode.
+The searching for
+.I \%man\~pages
+and the decompression of the input are active in every mode.
 .
 .
 .\" --------------------------------------------------------------------
 .SS "Graphical Display Modes"
 .\" --------------------------------------------------------------------
 .
-The graphical display modes work only in the X Window environment (or
-similar implementations within other windowing environments).
+The graphical display modes work mostly in the \%\f[CR]X\~Window\f[]
+environment (or similar implementations within other windowing
+environments).
 .
 The environment variable
-.Env_var $DISPLAY
+.Env_var \%$DISPLAY
 and the option
 .Opt_long display
-are used for specifying the X display to be used.
+are used for specifying the \%\f[CR]X\~Window\f[] display to be used.
 .
-If neither is given,
-.I groffer
-assumes that no X and changes to one text mode.
+If this environment variable is empty
+.B \%groffer
+assumes that no \%\f[CR]X\~Window\f[] is running and changes to a
+.IR \%text\~mode .
 .
 You can change this automatic behavior by the option
 .Opt_long default\-modes .
 .
 .
 .P
-Known viewers for the graphical display modes and their standard X
-Window viewer progams are
+Known viewers for the graphical display modes and their standard
+\%\f[CR]X\~Window\f[] viewer progams are
 .
 .Topic
-X Window roff viewers such as
-.BR gxditview (@MAN1EXT@)
+\%\f[CR]X\~Window\f[]
+.I roff
+viewers such as
+.BR \%gxditview (@MAN1EXT@)
 or
-.BR xditview (1)
+.BR \%xditview (1)
 (in
-.I x
-or
-.I X
-mode),
+.IR \%x\~mode ),
 .
 .Topic
 in a Postscript viewer
-.RI ( ps
-mode),
+.nh
+.RI ( \%ps\~mode ),
+.hy
 .
 .Topic
 in a dvi viewer program
-.RI ( dvi
-mode),
+.nh
+.RI ( \%dvi\~mode ),
+.hy
 .
 .Topic
 in a PDF viewer
-.RI ( pdf
-mode),
+.nh
+.RI ( \%pdf\~mode ),
+.hy
 .
 .Topic
 in a web browser
+.nh
 .RI ( html
 or
-.I www
-mode),
+.IR \%www\~mode ).
+.hy
 .RE
 .
 .
 .P
 The
-.I pdf
-mode has a major advantage \[em] it is the only graphical diplay mode
-that allows to search for text within the viewer; this can be a really
+.I \%pdf\~mode
+has a major advantage \[em] it is the only graphical diplay mode that
+allows to search for text within the viewer; this can be a really
 important feature.
 .
 Unfortunately, it takes some time to transform the input into the PDF
@@ -2161,38 +2639,42 @@
 .
 .
 .P
-These graphical viewers can be customized by options of the X Window
-Toolkit.
+These graphical viewers can be customized by options of the
+\%\f[CR]X\~Window\~Toolkit\f[].
 .
 But the
-.I groffer
+.B \%groffer
 options use a leading double minus instead of the single minus used by
-the X Window Toolkit.
+the \%\f[CR]X\~Window\~Toolkit\f[].
 .
 .
 .\" --------------------------------------------------------------------
-.SS "Text mode"
+.SS "Text modes"
 .\" --------------------------------------------------------------------
 .
-There are to modes for text output, mode
-.I text
-for plain output without a pager and mode
-.I tty
+There are two modes for text output,
+.I \%mode\~text
+for plain output without a pager and
+.I \%mode\~tty
 for a text output on a text terminal using some pager program.
 .
 .
 .P
 If the variable
-.Env_var $DISPLAY
-is not set or empty, groffer assumes that it should use
-.I tty
-mode.
+.Env_var \%$DISPLAY
+is not set or empty,
+.B \%groffer
+assumes that it should use
+.IR \%tty\~\%mode .
 .
 .
 .P
-In the actual implementation, the groff output device
-.I latin1
-is chosen for text modes.
+In the actual implementation, the
+.I groff
+output device
+.I \%latin1
+is chosen for
+.IR \%text\~modes .
 .
 This can be changed by specifying option
 .Opt_short T
@@ -2204,11 +2686,11 @@
 The pager to be used can be specified by one of the options
 .Opt_long pager
 and
-.Opt_long tty-viewer ,
+.Opt_long tty\-viewer ,
 or by the environment variable
-.Env_var $PAGER .
+.Env_var \%$PAGER .
 If all of this is not used the
-.BR less (1)
+.BR \%less (1)
 program with the option
 .Opt_short r
 for correctly displaying control sequences is used as the default
@@ -2220,13 +2702,13 @@
 .\" --------------------------------------------------------------------
 .
 These modes use the
-.I groffer
+.I \%groffer
 file determination and decompression.
 .
 This is combined into a single input file that is fed directly into
-.I groff
+.B \%groff
 with different strategy without the
-.I groffer
+.I \%groffer
 viewing facilities.
 .
 These modes are regarded as advanced, they are useful for debugging
@@ -2235,15 +2717,21 @@
 .
 .P
 The
-.I source
-mode with just displays the generated input.
+.I \%source\~mode
+with option
+.Opt_short Q
+and
+.Opt_long source
+just displays the decompressed input.
 .
+.
+.P
 The
-.I groff
-mode passes the input to
-.I groff
+.I \%groff\~mode
+passes the input to
+.B \%groff
 using only some suitable options provided to
-.IR groffer .
+.BR \%groffer .
 .
 This enables the user to save the generated output into a file or pipe
 it into another program.
@@ -2251,249 +2739,641 @@
 .
 .P
 In
-.I groff
-mode, the option
+.IR \%groff\~\%mode ,
+the option
 .Opt_short Z
 disables post-processing, thus producing the
+.nh
 .I groff intermediate
 .IR output .
+.hy
 .
 In this mode, the input is formatted, but not postprocessed; see
-.BR groff_out (@MAN5EXT@)
+.BR \%groff_out (@MAN5EXT@)
 for details.
 .
 .
 .P
 All
-.I groff
+.B \%groff
 short options are supported by
-.IR groffer .
+.BR \%groffer .
 .
 .
 .\" --------------------------------------------------------------------
 .SH "MAN\~PAGE\~SEARCHING"
 .\" --------------------------------------------------------------------
 .
-The default behavior of groffer is to first test whether a file
-parameter represents a local file; if it is not an existing file name,
-it is assumed to represent a name of a man\~page.
-.
-This behavior can be modified by the following options.
-.
+The default behavior of
+.B \%groffer
+is to first test whether a file parameter represents a local file; if
+it is not an existing file name, it is assumed to represent the name
+of a
+.IR \%man\~page .
+The following options can be used to determine whether the arguments
+should be handled as file name or
+.I \%man\~page
+arguments.
 .
 .TP
 .Opt_long man
-forces to interpret all file parameters as filespecs for searching
-man\~pages.
+forces to interpret all file parameters as
+.I \%filespecs
+for searching
+.IR \%man\~pages .
 .
 .TP
 .Opt_long no\-man
 .TP+
 .Opt_long local\-file
-disable the man searching; so only local files are displayed.
+disable the
+.I man
+searching; so only local files are displayed.
 .
 .
 .P
-If neither a local file nor a man\~page was retrieved for some file
-parameter a warning is issued on standard error, but processing is
-continued.
+If neither a local file nor a
+.I \%man\~page
+was retrieved for some file parameter a warning is issued on standard
+error, but processing is continued.
 .
 .
-.P
-The groffer program provides a search facility for man\~pages.
+.\" --------------------------------------------------------------------
+.SS "Search Algoritm"
+.\" --------------------------------------------------------------------
+.
+Let us now assume that a
+.I \%man\~page
+should be searched.
+.
+The
+.B \%groffer
+program provides a search facility for
+.IR \%man\~pages .
 .
 All long options, all environment variables, and most of the
-functionality of the GNU
-.BR man (1)
+functionality of the \f[CR]GNU\fP
+.BR \%man (1)
 program were implemented.
 .
-This inludes the extended file names of man\~pages, for example,
-the man\~page of
-.I groff
-in man\~section 7 may be stored under
-.File_name /usr/share/man/man7/groff.7.gz ,
-where
-.File_name /usr/share/man/
-is part of the man\~path, the subdirectory
-.I man7
-and the file extension
-.I .7
-refer to the man\~section 7;
-.I .gz
-shows the compression of the file.
+The search algorithm shall determine which file is displayed for a given
+.IR \%man\~page .
+The process can be modified by options and environment variables.
+.
+.
+.P
+The only
+.I man
+action that is omitted in
+.B \%groffer
+are the preformatted
+.IR \%man\~pages ,
+also called
+.IR cat\~pages .
+.
+With the excellent performance of the actual computers, the
+preformatted
+.I \%man\~pages
+aren't necessary any longer.
+.
+Additionally,
+.B \%groffer
+is a
+.I roff
+program; it wants to read
+.I roff
+source files and format them itself.
 .
 .
 .P
+The algorithm for retrieving the file for a
+.I \%man\~page
+needs first a set of directories.
+.
+This set starts with the so-called
+.I man\~path
+that is modified later on by adding names of
+.I operating system
+and
+.IR language .
+.
+This arising set is used for adding the section directories which
+contain the
+.I \%man\~page
+files.
+.
+.
+.P
+The
+.I man\~path
+is a list of directories that are separated by colon.
+.
+It is generated by the following methods.
+.
+.Topic
+The environment variable
+.Env_var \%$MANPATH
+can be set.
+.
+.Topic
+It can be read from the arguments of the environment variable
+.Env_var \%$MANOPT .
+.
+.Topic
 The
-.I cat\~pages
-(preformatted man\~pages) are intentionally excluded from the search
-because groffer is a roff program that wants to format by its own.
+.I man\~path
+can be manually specified by using the option
+.Opt_long manpath .
+An empty argument disables the
+.I \%man\~page
+searching.
+.
+.Topic
+When no
+.I man\~path
+was set the
+.BR \%manpath (1)
+program is tried to determine one.
+.
+.Topic
+If this does not work a reasonable default path from
+.Env_var $PATH
+is determined.
+.
+.
+.P
+We now have a starting set of directories.
+.
+The first way to change this set is by adding names of
+.I operating
+.IR systems .
+.
+This assumes that
+.I \%man\~pages
+for several
+.I operating systems
+are installed.
+.
+This is not always true.
+.
+The names of such
+.I operating systems
+can be provided by 3 methods.
+.
+.Topic
+The environment variable
+.Env_var \%$SYSTEM
+has the lowest precedence.
+.
+.Topic
+This can be overridden by an option in
+.Env_var \%$MANOPT .
+.
+.Topic
+This again is overridden by the command line option
+.Opt_long systems .
+.
+.
+.P
+Several names of
+.I operating systems
+can be given by appending their names, separated by a comma.
+.
+.
+.P
+The
+.I man\~path
+is changed by appending each
+.I system
+name as subdirectory at the end of each directory of the set.
+.
+No directory of the
+.I man\~path
+set is kept.
+.
+But if no
+.I system
+name is specified the
+.I man\~path
+is left unchanged.
+.
+.
+.P
+After this, the actual set of directories can be changed by
+.I language
+information.
+.
+This assumes that there exist
+.I man\~pages
+in different languages.
+.
+The wanted
+.I language
+can be chosen by several methods.
+.
+.Topic
+Enviroment variable
+.Env_var $LANG .
+.
+.Topic
+This is overridden by
+.Env_var \%$LC_MESSAGES .
+.
+.Topic
+This is overridden by
+.Env_var $LC_ALL .
+.
+.Topic
+This can be overridden by providing an option in
+.Env_var \%$MANOPT .
+.
+.Topic
+All these environment variables are overridden by the command line
+option
+.Opt_long locale .
+.
+.
+.P
+The
+.I default language
+can be specified by specifying one of the pseudo-language parameters
+\f[CR]C\fP or \f[CR]\%POSIX\fP.
+.
+This is like deleting a formerly given
+.I language
+information.
+.
+The
+.I \%man\~pages
+in the
+.I default language
+are usually in English.
+.
+.
+.P
+Of course, the
+.I language
+name is determined by
+.BR man .
+In \f[CR]GNU\fP
+.BR man ,
+it is specified in the \%\f[CR]POSIX\~1003.1\fP based format:
+.P
+.nh
+\f[I]\f[][\f[CB]_\f[]\f[I]\f[][\f[CB].\fP\
+\f[I]\f[][\f[CB],\fP\f[I]\fP]]],
+.hy
+.P
+but the two-letter code in
+.nh
+.I 
+.hy
+is sufficient for most purposes.
+.
+If for a complicated
+.I language
+formulation no
+.I \%man\~pages
+are found
+.B \%groffer
+searches the country part consisting of these first two characters as
+well.
+.
+.
+.P
+The actual directory set is copied thrice.
+.
+The
+.I language
+name is appended as subdirectory to each directory in the first copy
+of the actual directory set (this is only done when a language
+information is given).
+.
+Then the 2-letter abbreviation of the
+.I language
+name is appended as subdirectories to the second copy of the directory
+set (this is only done when the given language name has more than 2
+letters).
+.
+The third copy of the directory set is kept unchanged (if no
+.I language
+information is given this is the kept directory set).
 .
-With the excellent performance of the actual computers, the
-preformatted man\~pages aren't necessary any longer.
+These maximally 3 copies are appended to get the new directory set.
 .
 .
 .P
-The algorithm for retrieving man\~pages uses five search methods.
-.
-They are successively tried until a method works.
+We now have a complete set of directories to work with.
 .
+In each of these directories, the
+.I man
+files are separated in
+.IR sections .
 .
-.Topic
-The search path can be manually specified by using the option
-.Opt_long manpath .
-An empty argument disables the man\~page searching.
+The name of a
+.I section
+is represented by a single character, a digit between
+.I 1
+and
+.IR 9 ,
+or the character
+.I o
+or
+.IR n ,
+in this order.
 .
-This overwrites the other methods.
 .
+.P
+For each available
+.IR section ,
+a subdirectory
+.File_name man \fI
\fP +exists containing all +.I man +files for this +.IR section , +where +.I
+is a single character as described before. . -.Topic -If this is not available the environment variable -.Env_var $MANPATH -is searched. +Each +.I man +file in a +.I section +directory has the form +.IR \%\f[CB]man\fP
\f[CB]/\fP\f[CB].\fP
\ +[][\f[CB].\fP] , +where +.I \% +and +.I \% +are optional. . +.I \% +is the name of the +.I \%man\~page +that is also specified as filespec argument on the command line. . -.Topic -If this is empty, the program tries to read it from the environment -variable -.Env_var $MANOPT . . +.P +The +.I extension +is an addition to the section. . -.Topic -If this does not work a reasonable default path from -.Env_var $PATH -is searched for man\~pages. +This postfix acts like a subsection. . +An +.I extension +occurs only in the file name, not in name of the +.I section +subdirectory. . -.Topic -If this does not work, the -.BR manpath (1) -program for determining a path of man directories is tried. +It can be specified on the command line. . . .P -After this, the path elements for the language (locale) and operating -system specific man\~pages are added to the man\~path; their sequence -is determined automatically. -. -For example, both -.I /usr/share/man/linux/fr -and -.I /usr/share/man/fr/linux -for french linux man\~pages are found. +On the other hand, the +.I compression +is just an information on how the file is compressed. . -The language and operating system names are determined from both -environment variables and command line options. +This is not important for the user, such that it cannot be specified +on the command line. . . .P -The locale (language) is determined like in GNU man, that is from -highest to lowest precedence: -.Topic -.Opt_long locale -. -.Topic -.Env_var $GROFFER_OPT +There are 4 methods to specify a +.I section +on the command line: . .Topic -.Env_var $MANOPT +Environment variable +.Env_var \%$MANSECT . .Topic -.Env_var $LCALL +Command line option +.Opt_long sections . .Topic -.Env_var $LC_MESSAGES +Appendix to the +.I name +argument in the form +.I .
. .Topic -.Env_var $LANG . +Preargument before the +.I name +argument in the form +.I
. . .P -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[]]]], -.P -but the two-letter code in -.I -is sufficient for most purposes. +It is also possible to specify several +.I sections +by appending the single characters separated by colons. . +One can imagine that this means to restrict the +.I \%man\~page +search to only some +.IR sections . . -.P -If no man\~pages for a complicated locale are found the country part -consisting of the first two characters (without the `\f[CB]_\f[]', -`\f[CB].\f[]', and `\f[CB],\f[]', parts) of the locale is searched as -well. +The multiple +.I sections +are only possible for +.Env_var \%$MANSECT +and +.Opt_long sections . . . .P -If still not found the corresponding man\~page in the default language -is used instead. -. -As usual, this default can be specified by one of \f[CR]C\f[] or -\f[CR]POSIX\f[]. -. -The man\~pages in the default language are usually in English. +If no +.I section +is specified all +.I sections +are searched one after the other in the given order, starting with +.IR section\~1 , +until a suitable file is found. . . .P -Several operating systems can be given by appending their names, -separated by a comma. +There are 4 methods to specify an +.I extension +on the command line. . -This is then specified by the environment variable -.Env_var $SYSTEM -or by the command line option -.Opt_long systems . -The precedence is similar to the locale case above from highest to -lowest precedence: +But it is not necessary to provide the whole extension name, some +abbreviation is good enough in most cases. . -Topic -.Opt_long systems +.Topic +Environment variable +.Env_var \%$EXTENSION . .Topic -.Env_var $GROFFER_OPT +Command line option +.Opt_long extension . .Topic -.Env_var $MANOPT +Appendix to the +.I .
+argument in the form +.I .
. .Topic -.Env_var $SYSTEM . +Preargument before the +.I name +argument in the form +.I
. . .P -When searching for man\~pages this man\~path with the additional -language and system specific directories is used. +For further details on +.I \%man\~page +searching, see +.BR \%man (1). . . -.P -The search can further be restricted by limiting it to certain -sections. +.\" -------------------------------------------------------------------- +.SS "Examples of man files" +.\" -------------------------------------------------------------------- . -A single section can be specified within each filespec argument, -several sections as a colon-separated list in command line option -.Opt_long sections -or environment variable -.Env_var $MANSECT . +.TP +.File_name /usr/share/man/man1/groff.1 +This is an uncompressed file for the +.I \%man\~page +\f[CR]groff\fP in +.IR section\~1 . +. +It can be called by +.Shell_cmd "groffer\~groff" +No +.I section +is specified here, so all +.I sections +should be searched, but as +.I section\~1 +is searched first this file will be found first. +. +The file name is composed of the following components. +.File_name /usr/share/man +must be part of the +.IR \%man\~path ; +the subdirectory +.File_name man1/ +and the part +.File_name .1 +stand for the +.IR section ; +.File_name groff +is the name of the +.IR \%man\~page . . -When no section was specified a set of standard sections is searched -until a suitable man\~page was found. . +.TP +.File_name /usr/local/share/man/man7/groff.7.gz +The file name is composed of the following components. +.File_name /usr/local/share/man +must be part of the +.IR \%man\~path ; +the subdirectory +.File_name man7/ +and the part +.File_name .7 +stand for the +.IR section ; +.File_name groff +is the name of the +.IR \%man\~page ; +the final part +.File_name .gz +stands for a compression with +.BR gzip (1). +As the +.I section +is not the first one it must be specified as well. . -.P -Finally, the search can be restricted to a so-called -.IR extension . -This is a postfix that acts like a subsection. +This can be done by one of the following commands. +.Shell_cmd "groffer\~groff.7" +.Shell_cmd "groffer\~7\~groff" +.Shell_cmd "groffer\~\-\-sections=7\~groff" . -It can be specified by -.Opt_long extension -or environment variable -.Env_var $EXTENSION . +. +.TP +.File_name /usr/local/man/man1/ctags.1emacs21.bz2 +Here +.File_name /usr/local/man +must be in +.IR \%man\~path ; +the subdirectory +.File_name man1/ +and the file name part +.File_name .1 +stand for +.IR section\~1 ; +the name of the +.I \%man\~page +is +.File_name ctags ; +the section has an extension +.File_name emacs21 ; +and the file is compressed as +.File_name .bz2 +with +.BR bzip2 (1). +The file can be viewed with one of the following commands +.Shell_cmd "groffer\~ctags.1e" +.Shell_cmd "groffer\~1e\~ctags" +.Shell_cmd "groffer\~\-\-extension=e\~\-\-sections=1\~ctags" +where \f[CR]e\fP works as an abbreviation for the extension +\f[CR]emacs21\fP. . . -.P -For further details on man\~page searching, see -.BR man (1). +.TP +.File_name /usr/man/linux/de/man7/man.7.Z +The directory +.File_name /usr/man +is now part of the +.IR \%man\~path ; +then there is a subdirectory for an +.I operating system +name +.File_name linux/ ; +next comes a subdirectory +.File_name de/ +for the German +.IR language ; +the +.I section +names +.File_name man7 +and +.File_name .7 +are known so far; +.File_name man +is the name of the +.IR \%man\~page ; +and +.File_name .Z +signifies the compression that can be handled by +.BR gzip (1). +We want now show how to provide several values for some options. +. +That is possible for +.I sections +and +.I operating system +names. +. +So we use as +.I sections\~5 +and +.I 7 +and as +.I system +names +.I linux +and +.IR aix . +The command is then +.Shell_cmd groffer\~\-\-locale=de\~\-\-sections=5:7\~\-\-systems=linux,aix\~man +.Shell_cmd LANG=de\~MANSECT=5:7\~SYSTEM=linux,aix\~groffer\~man . . .\" -------------------------------------------------------------------- @@ -2504,16 +3384,16 @@ . If standard input or a file that was retrieved from the command line parameters is compressed with a format that is supported by either -.BR gzip (1) +.BR \%gzip (1) or -.BR bzip2 (1) +.BR \%bzip2 (1) it is decompressed on-the-fly. . -This includes the GNU -.BR .gz , -.BR .bz2 , +This includes the \f[CR]GNU\fP +.BR \%.gz , +.BR \%.bz2 , and the traditional -.B .Z +.B \%.Z compression. . The program displays the concatenation of all decompressed input in @@ -2524,13 +3404,15 @@ .SH "ENVIRONMENT" .\" -------------------------------------------------------------------- . -The groffer programs supports many system variables, most of them by -courtesy of other programs. +The +.B \%groffer +program supports many system variables, most of them by courtesy of +other programs. . All environment variables of -.BR groff (@MAN1EXT@) -and GNU -.BR man (1) +.BR \%groff (@MAN1EXT@) +and \f[CR]GNU\fP +.BR \%man (1) and some standard system variables are honored. . . @@ -2539,8 +3421,9 @@ .\" -------------------------------------------------------------------- . .TP -.Env_var $GROFFER_OPT -Store options for a run of groffer. +.Env_var \%$GROFFER_OPT +Store options for a run of +.BR \%groffer . . The options specified in this variable are overridden by the options given on the command line. @@ -2549,47 +3432,59 @@ so arguments containing white-space or special shell characters should be quoted. . +Do not forget to export this variable, otherwise it does not exist +during the run of +.BR groffer . +. . .\" -------------------------------------------------------------------- .SS "System Variables" .\" -------------------------------------------------------------------- . -The groffer program is a shell script that is run through -.BR /bin/sh , +The +.B \%groffer +program is a shell script that is run through +.File_name /bin/sh , which can be internally linked to programs like -.BR bash (1). +.BR \%bash (1). The corresponding system environment is automatically effective. . -The following variables have a special meaning for groffer. +The following variables have a special meaning for +.BR \%groffer . . . .TP -.Env_var $DISPLAY -If this variable is set this indicates that the X Window system is -running. +.Env_var \%$DISPLAY +If this variable is set this indicates that the \%\f[CR]X\~Window\fP +system is running. . Testing this variable decides on whether graphical or text output is generated. . This variable should not be changed by the user carelessly, but it can -be used to start the graphical groffer on a remote X terminal. -. -For example, depending on your system, groffer can be started on the -second monitor by the command +be used to start the graphical +.B \%groffer +on a remote \%\f[CR]X\~Window\fP terminal. +. +For example, depending on your system, +.B \%groffer +can be started on the second monitor by the command .Shell_cmd DISPLAY=:0.1\~groffer\~ what.ever & . . .TP -.Env_var $LC_ALL +.Env_var \%$LC_ALL .TP+ -.Env_var $LC_MESSAGES +.Env_var \%$LC_MESSAGES .TP+ .Env_var $LANG If one of these variables is set (in the above sequence), its content is interpreted as the locale, the language to be used, especially when -retrieving man\~pages. +retrieving +\IR \%man\~pages . . A locale name is typically of the form +.nh .IR language [\c .B _\c .IR territory [\c @@ -2597,100 +3492,102 @@ .IR codeset [\c .B @\c .IR modifier ]]], +.hy where -.I language +.I \%language is an ISO 639 language code, -.I territory +.I \%territory is an ISO 3166 country code, and -.I codeset +.I \%codeset is a character set or encoding identifier like ISO-8859-1 or UTF-8; see -.BR setlocale (3). +.BR \%setlocale (3). . -The locale values\~\c -.B C -and -.B POSIX -stand for the default, i.e. the man\~page directories without a -language prefix. +The locale values \f[CR]C\fP and \%\f[CR]POSIX\fP +stand for the default, i.e. the +.I \%man\~page +directories without a language prefix. . 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 variable to the -.BR cat (1) +.BR \%cat (1) program .Shell_cmd PAGER=cat\~groffer\~ anything . . .TP .Env_var $PATH -All programs within the groffer shell script are called without a -fixed path. +All programs within the +.B \%groffer +shell script are called without a fixed path. . 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. -. -This is done internally by some shells. -. -.I groffer -ignores the bad POSIX behavior for option processing, that means that -option processing will be finished as soon as a non-option argument is -found. -. -Instead the GNU behavior of freely mixing options and -.I filespec -arguments is used in any case. -. -Usually, you do not want to set this environment variable externally. +within the run of +.BR \%groffer . . . .\" -------------------------------------------------------------------- .SS "Groff Variables" .\" -------------------------------------------------------------------- . -The groffer program internally calls groff, so all environment -variables documented in -.BR groff (@MAN1EXT@) -are internally used within groffer as well. +The +.B \%groffer +program internally calls +.BR \%groff , +so all environment variables documented in +.BR \%groff (@MAN1EXT@) +are internally used within +.B \%groffer +as well. . -The following variables have a direct meaning for the groffer program. +The following variable has a direct meaning for the +.B \%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. +.B \%groffer +uses it for storing its temporary files, just as +.B groff +does. . . .\" -------------------------------------------------------------------- .SS "Man Variables" .\" -------------------------------------------------------------------- . -Parts of the functionality of the man\~program were implemented in -groffer; support for all environment variables documented in -.BR man (1) -was added to groffer, but the meaning was slightly modified due to the -different approach in groffer; but the user interface is the same. +Parts of the functionality of the +.B man +program were implemented in +.BR \%groffer ; +support for all environment variables documented in +.BR \%man (1) +was added to +.BR \%groffer , +but the meaning was slightly modified due to the different approach in +.BR \%groffer ; +but the user interface is the same. . -The man environment variables can be overwritten by options provided -with -.Env_var $MANOPT , +The +.B man +environment variables can be overwritten by options provided with +.Env_var \%$MANOPT , which in turn is overwritten by the command line. . . .TP -.Env_var $EXTENSION -Restrict the search for man\~pages to files having this extension. +.Env_var \%$EXTENSION +Restrict the search for +.I \%man\~pages +to files having this extension. . This is overridden by option .Opt_long extension ; @@ -2698,22 +3595,25 @@ . . .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 -of its value are extracted. +.BR \%man (1). +As not all of these are relevant for +.B \%groffer +only the essential parts of its value are extracted. . The options specified in this variable overwrite the values of the -other environment variables taht are specific to man. +other environment variables that are specific to +.IR man . . All options specified in this variable are overridden by the options given on the command line. . . .TP -.Env_var $MANPATH -If set, this variable contains the directories in which the man\~page +.Env_var \%$MANPATH +If set, this variable contains the directories in which the +.I \%man\~page trees are stored. . This is overridden by option @@ -2721,18 +3621,21 @@ . . .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. +.I \%man\~pages +is restricted to those manual sections in that order. . This is overridden by option .Opt_long sections . . . .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. +as +.I \%man\~page +trees for different operating systems. . This variable can be overwritten by option .Opt_long systems ; @@ -2741,9 +3644,10 @@ . .P The environment variable -.Env_var $MANROFFSEQ -is ignored by groffer because the necessary preprocessors are -determined automatically. +.Env_var \%$MANROFFSEQ +is ignored by +.B \%groffer +because the necessary preprocessors are determined automatically. . . .\" -------------------------------------------------------------------- @@ -2751,58 +3655,82 @@ .\" -------------------------------------------------------------------- . The -.I groffer +.B \%groffer program can be preconfigured by two configuration files. . -This configuration can be overridden at each program start by command -line options or by the environment variable -.Env_var $GROFFER_OPT . -. . .TP -.File_name /etc/groff/groffer.conf -System-wide configuration file for groffer. +.File_name \%/etc/groff/groffer.conf +System-wide configuration file for +.BR \%groffer . . . .TP -.File_name $HOME/.groff/groffer.conf -User-specific configuration file for groffer, where -.Env_var $HOME +.File_name \%$HOME/.groff/groffer.conf +User-specific configuration file for +.BR \%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. +This file is called after the system-wide configuration file to enable +overriding by the user. +. +. +.P +Both files are handled for the configuration, but the configuration +file in +.File_name /etc +comes first; it is overwritten by the configuration file in the home +directory; both configuration files are overwritten by the environment +variable +.Env_var \%$GROFFER_OPT ; +everything is overwritten by the command line arguments. . . .P -Their lines either start with a minus character or are shell commands. +In the configuration files, arbitrary spaces are allowed at the +beginning of each line, they are just ignored. +. +Apart from that, the lines of the configuration lines either start +with a minus character, all other lines are interpreted as shell +commands. . -Arbitrary spaces are allowed at the beginning, they are just ignored. . -The lines with the beginning minus are appended to the existing value -of $GROFFER_OPT. +.P +The lines with the beginning minus are interpreted as +.B groffer +options. . This easily allows to set general -.I groffer -options that are used with any call of -.IR groffer . +.B \%groffer +options that should be used with any call of +.BR \%groffer . . . .P -After the transformation of the minus lines the emerging shell scripts -that are called by -.I groffer -using the `\c -.CB .\~\c -.IR filename ' -syntax. +If a lines starts with a double minus it represents a +.B \%groffer +long option; everything behind the first equal sign +.RB ` = ' +or space character up to the end of the line is interpreted as its +argument. +. +A line starting with a single minus represents a short options cluster +with or without a final argument. +. +It is not necessary to use quotes in these lines; quotes are just +ignored. . . .P -The only option that needs a minus line in the configuration files is -.Opt_long shell . -The reason is that its argument must be called at a very early stage -before the whole syntax of the configuration can be transformed. +The lines starting with a minus are changed into a prepend to the +existing value of +.Env_var \%$GROFFER_OPT . +. +So the configuration files will be transferred into a shell script +that is called within +.BR \%groffer . . . .P @@ -2810,28 +3738,38 @@ tasks: . .Topic -Preset command line options by writing them into lines starting with a -minus sign. +Preset command line options, such as choosing a +.I \%mode +or a viewer. +. +These are written into lines starting with a single or double minus +sign, followed by the option name. . .Topic -Preset environment variables recognized by groffer. +Preset environment variables recognized by +.BR \%groffer ; +but do not forget to export them. . .Topic -Write a function for calling a viewer program for a special -.I mode -and feed this name into its corresponding -.Opt_long \f[I]mode\f[]\-viewer +You can also write a shell function for calling, for example a viewer +program for some +.IR \%mode . +Such a function can be fed into a corresponding +.Opt_long \f[I]mode\fP\-viewer option. . -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. +.Topic +Enter +.Opt_long shell +to specify a shell for the run of +.File_name groffer2.sh . +Some shells run much faster than the standard shell. . . .P As an example, consider the following configuration file in -~/.groff/groffer.conf, say. +.File_name \%~/.groff/groffer.conf , +say. . .P .ft CR @@ -2840,14 +3778,14 @@ # groffer configuration file # # groffer options that are used in each call of groffer ---shell=/bin/bash ---resolution=100 ---foreground=DarkBlue ---x-viewer='gxditview -geometry 850x800' +\-\-shell=ksh +\-\-foreground=DarkBlue +\-\-resolution=100 +\-\-x\-viewer=gxditview \-geometry 900x1200 # # some shell commands if test "$DISPLAY" = ""; then - DISPLAY='localhost:0.0' + export DISPLAY='localhost:0.0' fi date >>~/mygroffer.log .fi @@ -2856,63 +3794,76 @@ . . .P +The lines starting with +.B # +are command lines. +. This configuration sets four -.I groffer -options and runs two shell commands. +.B \%groffer +options (the lines starting with `\-') and runs two shell commands (the +rest of the script). . This has the following effects: . . .Topic -Lines starting with a -.B # -character -are +Use +.B ksh +as the shell to run the +.B \%groffer +script; if it works it should be faster than the usual +.BR sh . . . .Topic -Use -.B /bin/bash -as the shell to run the -.I groffer -script. +Use a text color of +.B \%DarkBlue +in all viewers that support this, such as +.BR \%gxditview . . . .Topic -Take a resolution of -.B 100 dpi -and a text color of -.B DarkBlue -in all viewers that support this. +Use a resolution of +.B 100\~dpi +in all viewers that support this, such as +.BR \%gxditview . +. +By this, the default device in +.I x mode +is set to +.BR X100 . . . .Topic Force -.BR gxditview (@MAN1EXT@) -as the X-mode viewer using the geometry option for setting the width -to -.B 850 dpi +.BR \%gxditview (@MAN1EXT@) +as the +.I \%x-mode +viewer using the geometry option for setting the width to +.B 900\~dpi and the height to -.B 800 -.BR dpi . +.BR 1200\~dpi . +This geometry is suitable for a resolution of +.BR 100\~dpi . . . .Topic -The variable -.Env_var $DISPLAY -is set to -.IR localhost:0.0 -which allows to start -.I groffer -in the standard X display, even when the program is called from a text -console. +If the environment variable +.Env_var \%$DISPLAY +is empty set it to +.IR localhost:0.0 . +. +That allows to start +.B \%groffer +in the standard \%\f[CR]X\~Window\fP display, even when the program +is called from a text console. . . .Topic Just for fun, the date of each -.I groffer +.B \%groffer start is written to the file -.B mygroffer.log +.File_name mygroffer.log in the home directory. . . @@ -2920,44 +3871,54 @@ .SH "EXAMPLES" .\" -------------------------------------------------------------------- . -The usage of groffer is very easy. -. -Usually, it is just called with a file name or man\~page. -. -The following examples, however, show that groffer has much more fancy -capabilities. +The usage of +.B \%groffer +is very easy. +. +Usually, it is just called with a file name or +.IR \%man\~page . +. +The following examples, however, show that +.B \%groffer +has much more fancy capabilities. . . .TP .Shell_cmd "groffer\~/usr/local/share/doc/groff/meintro.ms.gz" Decompress, format and display the compressed file -.I meintro.ms.gz +.File_name meintro.ms.gz in the directory -.IR /usr/local/share/doc/groff , -using -.I gxditview -as graphical viewer when in X Window, or the -.BR less (1) -pager program when not in X. +.File_name /usr/local/share/doc/groff , +using the standard viewer +.B \%gxditview +as graphical viewer when in \%\f[CR]X\~Window\fP, or the +.BR \%less (1) +pager program when not in \%\f[CR]X\~Window\fP. . . .TP .Shell_cmd "groffer\~groff" If the file -.I ./groff +.File_name \%./groff exists use it as input. . -Otherwise interpret the argument as a search for the man\~page named -.I groff -in the smallest possible man\~section, being secion 1 in this case. +Otherwise interpret the argument as a search for the +.I \%man\~page +named +.B \%groff +in the smallest possible +.IR \%man\~section , +being section 1 in this case. . . .TP .Shell_cmd "groffer\~man:groff" -search for the man\~page of -.I groff +search for the +.I \%man\~page +of +.B \%groff even when the file -.I ./groff +.File_name ./groff exists. . . @@ -2965,9 +3926,12 @@ .Shell_cmd "groffer\~groff.7" .TP+ .Shell_cmd "groffer\~7\~groff" -search the man\~page of -.I groff -in man\~section +search the +.I \%man\~page +of +.B \%groff +in +.I \%man\~section .BR 7 . This section search works only for a digit or a single character from a small set. @@ -2976,31 +3940,36 @@ .TP .Shell_cmd "groffer\~fb.modes" If the file -.I ./fb.modes -does not exist interpret this as a search for the man\~page of -.IR fb.modes . +.File_name ./fb.modes +does not exist interpret this as a search for the +.I \%man\~page +of +.BR fb.modes . As the extension -.I modes +.I \%modes is not a single character in classical section style the argument is not split to a search for -.IR fb . +.BR fb . . . .TP .Shell_cmd "groffer\~groff\~\[cq]troff(1)\[cq]\~man:roff" . The arguments that are not existing files are looked-up as the -following man\~pages: -.I groff -(automatic search, should be found in man\~section\~1), -.I troff +following +.IR \%man\~pages : +.B \%groff +(automatic search, should be found in \fIman\fP\~section\~1), +.B \%troff (in section\~1), and -.I roff +.B \%roff (in the section with the lowest number, being\~7 in this case). . The quotes around +.nh .I \[cq]troff(1)\[cq] +.hy are necessary because the paranthesis are special shell characters; escaping them with a backslash character .I \[rs]( @@ -3012,44 +3981,65 @@ . . .TP -.Shell_cmd "LANG=de\~groffer\~--man\~--www\~--www-viever=mozilla\~ls" +.Shell_cmd "LANG=de\~groffer\~--man\~--www\~--www-viever=galeon\~ls" . -Retrieve the German man\~page (language +Retrieve the German +.I \%man\~page +(language .IR de ) for the .B ls program, decompress it, format it to -.I html +.I \%html format -.RI ( www -mode) and view the result in the web browser -.I galeon . +.nh +.RI ( \%www\~mode ) +.hy +and view the result in the web browser +.BR \%galeon . The option .Opt_long man -guarantees that the man\~page is retrieved, even when a local file -.I ls +guarantees that the +.I \%man\~page +is retrieved, even when a local file +.File_name \%ls exists in the actual directory. . . .TP .Shell_cmd "groffer\~--source\~'man:roff(7)'" . -Get the man\~page called -.I roff -in man\~section 7, decompress it, and print its unformatted content, -its source code. +Get the +.I \%man\~page +called +.I \%roff +in \fIman\fP\~section 7, decompress it, and print its unformatted +content, its source code. +. +. +.TP +.Shell_cmd "groffer\~--de-p\~--in\~--ap" +This is a set of abbreviated arguments, it is determined as +.br +.Shell_cmd "groffer\~--debug-params\~--intermediate-output\~--apropos" . . .TP .Shell_cmd "cat\~file.gz\~|\~groffer\~-Z\~-mfoo" . -Decompress the standard input, send this to -.I groff -intermediate mode without post-processing (groff option +The file +.File_name file.gz +is sent to standard input, this is decompressed, and then this is +transported to the +.I \%groff intermediate output mode +without post-processing +.RB ( groff +option .Opt_short Z ), -using macro package by -.I foo -(groff option +using macro package +.I \%foo +.RB ( groff +option .Opt_short m ) . . . @@ -3058,7 +4048,7 @@ .TP+ .Shell_cmd+ "groffer --x --bg red --fg yellow --geometry 200x100 -" . -Display the word \f[CB]WOW!\f[] in a small window in constant-width +Display the word \f[CB]WOW!\fP in a small window in constant-width bold font, using color yellow on red background. . . @@ -3067,78 +4057,109 @@ .\" -------------------------------------------------------------------- . The -.B groffer -shell script is compatible with both GNU and POSIX. +.B \%groffer +program consists of two shell scripts. +. . -POSIX compatibility refers to -.B IEEE P1003.2/D11.2 -of September 1991, a very early version of the POSIX standard that is -still freely available in the internet. +.P +The starting script is the file +.File_name \%groffer +that is installed in a +.File_name bin +directory. . -Unfortunately, this version of the standard has `local' for shell -function variables removed. +It is generated from the source file +.File_name \%groffer.sh . . -As `local' is needed for serious programming this temporary POSIX -deprecation was ignored. +It is just a short starting script without any functions such that it +can run on very poor shells. . . .P -Most GNU shells are compatible with this interpretation of POSIX, but -provide much more facilities. -. -Nevertheless this script uses only a restricted set of shell language -elements and shell builtins. +The main part of the +.B \%groffer +program is the file +.File_name groffer2.sh +that is installed in the +.I groff +library directory. . -The groffer script should work on most actual free and commercial -operating systems. +This script can be run under a different shell by using the +.B \%groffer +option +.Opt_long shell . . . .P -The groffer program provides its own parser for command line options; -it can handle option arguments and file names containing white space -and a large set of special characters. +Both scripts are compatible with both +\f[CR]GNU\fP and \%\f[CR]POSIX\fP. +. +\%\f[CR]POSIX\fP compatibility refers to +\%\f[CR]IEEE\~P1003.2/D11.2\fP of September 1991, a very early +version of the \%\f[CR]POSIX\fP standard that is still freely +available in the internet at +.URL http://\:www.funet.fi/\:pub/\:doc/\:posix/\:p1003.2/\:d11.2/\:all \ +"\%POSIX\~P1003.2\~draft\~11.2" . . . .P -The groffer shell script was tested with the following common -implementations of the GNU shells: -POSIX -.BR sh (1), -.BR bash (1), -and others. +Only a restricted set of shell language elements and shell builtins is +used to achieve even compatibility with some Bourne shells that are +not fully \%\f[CR]POSIX\fP compatible. . -Free POSIX compatible shells and shell utilities for most operating -systems are available at the -.URL http://\:www.gnu.org/software/ "GNU software archive" . +The +.B \%groffer +shell scripts were tested on many shells, including the following +Bourne shells: +.BR \%ash (1), +.BR \%bash (1), +.BR \%dash (1), +.BR \%ksh (1), +.BR \%pdksh (1), +.BR \%posh (1), +and +.BR \%zsh (1). +So it should work on most actual free and commercial operating +systems. . . .P -The shell can be chosen by the option -.Opt_long shell . -This option can also be given to the environment variable +The shell for the run of +.File_name groffer2.sh +can be chosen by the option +.Opt_long shell +on the command line or the environment variable .Env_var $GROFF_OPT . -If you want to write it to one of the -.I groffer -configuration files you must use the single option style, a line -starting with +If you want to add it to one of the +.B \%groffer +configuration files you must write a line starting with .Opt_long shell . . . .P -The groffer program provides its own parser for command line arguments -that is compatible to both POSIX -.BR getopts (1) -and GNU -.BR getopt (1) -except for shortcuts of long options. +The +.B \%groffer +program provides its own parser for command line arguments that is +compatible to both \%\f[CR]POSIX\fP +.BR \%getopts (1) +and \%\f[CR]GNU\fP +.BR \%getopt (1). +It can handle option arguments and file names containing white space +and a large set of special characters. . The following standard types of options are supported. . . .Topic -A single minus always refers to single character option or a -combination thereof, for example, the -.I groffer +The option consisiting of a single minus +.Opt_short +refers to standard input. +. +. +.Topic +A single minus followed by characters refers to a single character +option or a combination thereof; for example, the +.B \%groffer short option combination .Opt_short Qmfoo is equivalent to @@ -3147,7 +4168,7 @@ . .Topic Long options are options with names longer than one character; they -are always prededed by a double minus. +are always preceded 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, @@ -3160,136 +4181,224 @@ An argument of .Opt_-- ends option parsing; all further command line arguments are -interpreted as file name arguments. +interpreted as +.I \%filespec +parameters, i.e. file names or constructs for searching +.IR \%man\~pages ). . . .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. +All command line arguments that are neither options nor option +arguments are interpreted as +.I \%filespec +parameters and stored until option parsing has finished. . For example, the command line .Shell_cmd "groffer file1 -a -o arg file2" -is, by default, equivalent to +is equivalent to .Shell_cmd "groffer -a -o arg -- file1 file2" . . .P -This behavior can be changed by setting the environment variable -.Env_var $POSIXLY_CORRECT -to a non-empty value. -. -Then the strange POSIX non-option behavior is adopted, i. e. option -processing is stopped as soon as the first non-option argument is -found and each following argument is taken as a file name. +The free mixing of options and +.I \%filespec +parameters follows the GNU principle. . -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 . +That does not fulfill the strange option behavior of \%\f[CR]POSIX\fP +that ends option processing as soon as the first non-option argument +has been reached. +. +The end of option processing can be forced by the option +.RB ` \-\- ' +anyway. +. +. +.\" -------------------------------------------------------------------- +.SH "BUGS" +.\" -------------------------------------------------------------------- +. +Report bugs to the +.MTO bug-groff@gnu.org "bug-groff mailing list" . +. +Include a complete, self-contained example that will allow the bug to +be reproduced, and say which version of +.B \%groffer +you are using. +. +. +.P +You can also use the +.MTO groff@gnu.org "groff mailing list" , +but you must first subscribe to this list. +. +You can do that by visiting the +.URL http://\:lists.gnu.org/\:mailman/\:listinfo/\:groff \ +"groff mailing list web page" . +. +. +.P +See +.BR \%groff (@MAN1EXT@) +for information on availability. . . .\" -------------------------------------------------------------------- .SH "SEE ALSO" .\" -------------------------------------------------------------------- . -.TP -.BR groff (@MAN1EXT@) -.TP+ -.BR troff (@MAN1EXT@) +.P +.BR \%groff (@MAN1EXT@), +.BR \%@g@troff (@MAN1EXT@) +.RS Details on the options and environment variables available in -.IR groff ; -all of them can be used with groffer. +.BR \%groff ; +all of them can be used with +.BR \%groffer . +.RE . . .TP -.BR man (1) -The standard program to diplay man\~pages. -. -The information there 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. +.BR \%groff (@MAN7EXT@) +Documentation of the +.I \%groff +language. . . .TP -.BR gxditview (@MAN1EXT@) -.TP+ -.BR xditview (1x) -Viewers for groffer's -.I x -mode. +.BR \%grog (@MAN1EXT@) +Internally, +.B \%groffer +tries to guess the +.B \%groff +command line options from the input using this program. . . .TP -.BR gv (1) -.TP+ -.BR ghostview (1) -Viewers for groffer's -.I ps -mode. +.BR groff_out (@MAN5EXT@) +Documentation on the +.I \%groff intermediate output +.nh +.RI ( ditroff +output). +.hy . . -.TP+ -.BR gs (1) -Transformer from -.I ps -to -.IR pdf ; -and a -.I ps -viewer. +.TP +.BR groff_tmac (@MAN5EXT@) +Documentation on the +.I \%groff +macro files. . . .TP -.BR xpdf (1) +.BR \%man (1) +The standard program to display +.IR \%man\~pages . +. +The information there is only useful if it is the +.I \%man\~page +for GNU +.BR man . +Then it documents the options and environment variables that are +supported by +.BR \%groffer . +. +. +.P +.BR \%ash (1), +.BR \%bash (1), +.BR \%dash (1), +.BR \%ksh (1), +.BR \%pdksh (1), +.BR \%posh (1), +.BR \%sh (1), +.BR \%zsh (1) +.RS +Bourne shells that were tested with +.BR \%groffer . +.RE +. +. +.P +.BR \%gxditview (@MAN1EXT@), +.BR \%xditview (1x) +.RS Viewers for -.I pdf -files. +.BR \%groffer 's +.IR \%x\~mode . +.RE . . -.TP -.BR xdvi (1) -.TP+ -.BR dvilx (1) -Viewers for groffer's -.I dvi -mode. +.P +.BR \%kpdf (1), +.BR \%kghostview (1), +.BR \%evince (1), +.BR \%ggv (1), +.BR \%gv (1), +.BR \%ghostview (1), +.BR \%gs (1) +.RS +Viewers for +.BR \%groffer 's +.IR \%ps\~mode . +.RE . . -.TP -.BR less (1) -Standard pager program for the -.I tty -.IR mode . +.P +.BR \%kpdf (1), +.BR \%acroread (1), +.BR \%evince (1), +.BR \%xpdf (1), +.BR \%gpdf (1), +.BR \%kghostview (1), +.BR \%ggv (1) +.RS +Viewers for +.BR \%groffer 's +.IR \%pdf\~mode . +.RE . . -.TP -.BR gzip (1) -.TP+ -.BR bzip2 (1) -The decompression programs supported by groffer. +.P +.BR \%kdvi (1), +.BR \%xdvi (1), +.BR \%dvilx (1) +.RS +Viewers for +.BR \%groffer 's +.IR \%dvi\~mode . +.RE . . -.TP -.BR groff (@MAN7EXT@) -Documentation of the -.I groff -language. +.P +.BR \%konqueror (1), +.BR \%epiphany (1), +.BR \%firefox (1), +.BR \%mozilla (1), +.BR \%netscape (1), +.BR \%lynx (1) +.RS +Web-browsers for +.BR \%groffer 's +.I \%html +or +.IR \%www\~mode . +.RE . . .TP -.BR grog (@MAN1EXT@) -Internally, groffer tries to guess the groff command line options from -the input using this program. +.BR \%less (1) +Standard pager program for the +.I \%tty\~mode . . . -.TP -.BR groff_out (@MAN5EXT@) -Documentation on the groff intermediate output (ditroff output). +.P +.BR \%gzip (1), +.BR \%bzip2 (1) +.RS +The decompression programs supported by +.BR \%groffer . +.RE . . .\" -------------------------------------------------------------------- @@ -3304,7 +4413,7 @@ .copyleft . . -\" -------------------------------------------------------------------- +.\" -------------------------------------------------------------------- .\" Emacs settings .\" -------------------------------------------------------------------- . diff -ruN groff-1.18.1.1/contrib/groffer/groffer.sh groff-1.18.1.2/contrib/groffer/groffer.sh --- groff-1.18.1.1/contrib/groffer/groffer.sh 2004-06-15 03:44:50.000000000 +0200 +++ groff-1.18.1.2/contrib/groffer/groffer.sh 2006-09-11 21:41:00.000000000 +0200 @@ -1,4541 +1,314 @@ -#!/bin/sh +#! /bin/sh # groffer - display groff files # Source file position: /contrib/groffer/groffer.sh +# Installed position: /bin/groffer -# Copyright (C) 2001,2002,2003,2004 Free Software Foundation, Inc. +# Copyright (C) 2001,2002,2003,2004,2005,2006 +# Free Software Foundation, Inc. # Written by Bernd Warken -# This file is part of groff version @VERSION@. +# Last update: 14 Aug 2006 -# groff is free software; you can redistribute it and/or modify it +# This file is part of `groffer', which is part of `groff'. + +# `groff' is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. -# groff is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -# License for more details. +# `groff' is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. # You should have received a copy of the GNU General Public License -# along with groff; see the files COPYING and LICENSE in the top -# directory of the groff source. If not, write to the Free Software -# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -_PROGRAM_NAME='groffer'; -_PROGRAM_VERSION='0.9.11'; -_LAST_UPDATE='15 June 2004'; - - -######################################################################## -# Determine the shell under which to run this script from the command -# line arguments or $GROFF_OPT; if none is specified, just go on with -# the starting shell. - -if test _"${_groffer_run}"_ = __; then - # only reached during the first run of the script - - export _groffer_run; # counter for the runs of groffer - _groffer_run='first'; - - export _PROGRAM_NAME; - export _PROGRAM_VERSION; - export _LAST_UPDATE; - - export GROFFER_OPT; # option environment for groffer - export _GROFFER_SH; # file name of this shell script - export _OUTPUT_FILE_NAME; # output generated, see main_set_res..() - - export _CONFFILES; # configuration files - _CONFFILES="/etc/groff/groffer.conf ${HOME}/.groff/groffer.conf"; - - case "$0" in - *${_PROGRAM_NAME}*) - _GROFFER_SH="$0"; - # was: _GROFFER_SH="@BINDIR@/${_PROGRAM_NAME}"; - ;; - *) - echo "The ${_PROGRAM_NAME} script should be started directly." >&2 - exit 1; - ;; - esac; - - ########################### - # _get_opt_shell ("$@") - # - # Determine whether `--shell' was specified in $GROFF_OPT or in $*; - # if so echo its argument. - # - _get_opt_shell() - { - local i; - local _sh; - case " ${GROFFER_OPT} $*" in - *\ --shell\ *|*\ --shell=*) - ( - eval set -- "${GROFFER_OPT}" '"$@"'; - _sh=''; - for i in "$@"; do - case "$1" in - --shell) - if test "$#" -ge 2; then - _sh="$2"; - shift; - fi; - ;; - --shell=?*) - # delete up to first `=' character - _sh="$(echo -n "$1" | sed -e 's/^[^=]*=//')"; - ;; - esac; - shift; - done; - echo -n "${_sh}"; - ) - ;; - esac; - } - - - ########################### - # _test_on_shell () - # - # Test whether is a shell program of Bourne type (POSIX sh). - # - _test_on_shell() - { - if test "$#" -le 0 || test _"$1"_ = __; then - return 1; - fi; - # do not quote $1 to allow arguments - test _"$($1 -c 's=ok; echo -n "$s"' 2>/dev/null)"_ = _ok_; - } - - # do the shell determination from command line and $GROFFER_OPT - _shell="$(_get_opt_shell "$@")"; - - if test _"${_shell}"_ = __; then - # none found, so look at the `--shell' lines in configuration files - export f; - for f in ${_CONFFILES}; do - if test -f $f; then - _all="$(cat $f | sed -n -e '/^--shell[= ] *\([^ ]*\)$/s//\1/p')" - for s in ${_all}; do - _shell=$s; - done; - fi; - done; - unset f; - unset s; - unset _all; - fi; - - # restart the script with the last found $_shell, if it is a shell - if _test_on_shell "${_shell}"; then - _groffer_run='second'; - # do not quote $_shell to allow arguments - exec ${_shell} "${_GROFFER_SH}" "$@"; - exit; - fi; - - _groffer_run='second'; - unset _shell; - -fi; # end of first run - -if test _"${_groffer_run}"_ != _second_; -then - echo "$_groffer_run should be 'second' here." >&2 - exit 1 -fi; - -unset _groffer_run - - -######################################################################## -# diagnostic messages -# -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 - +# along with `groff'; see the files COPYING and LICENSE in the top +# directory of the `groff' source. If not, write to the Free Software +# Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, +# USA. ######################################################################## -# Environment Variables -######################################################################## - -# Environment variables that exist only for this file start with an -# underscore letter. Global variables to this file are written in -# upper case letters, e.g. $_GLOBAL_VARIABLE; temporary variables -# start with an underline and use only lower case letters and -# underlines, e.g. $_local_variable . - -# [A-Z]* system variables, e.g. $MANPATH -# _[A-Z_]* global file variables, e.g. $_MAN_PATH -# _[a-z_]* temporary variables, e.g. $_manpath - -# Due to incompatibilities of the `ash' shell, the name of loop -# variables in `for' must be single character -# [a-z] local loop variables, e.g. $i +export GROFFER_OPT; # option environment for groffer -######################################################################## -# read-only variables (global to this file) -######################################################################## +export _CONF_FILE_ETC; # configuration file in /etc +export _CONF_FILE_HOME; # configuration file in $HOME +export _CONF_FILES; # configuration files +_CONF_FILE_ETC='/etc/groff/groffer.conf'; +_CONF_FILE_HOME="${HOME}/.groff/groffer.conf"; +_CONF_FILES="${_CONF_FILE_ETC} ${_CONF_FILE_HOME}"; # characters -export _BQUOTE; -export _BSLASH; -export _DQUOTE; -export _NEWLINE; -export _LBRACK; -export _LPAR; -export _RBRACK; -export _RPAR; -export _SPACE; -export _SQUOTE; +export _AT; +export _SP; +export _SQ; export _TAB; -_BQUOTE='`'; -_BSLASH='\'; -_DQUOTE='"'; -_NEWLINE=' -'; -_LBRACK='['; -_LPAR='('; -_RBRACK=']'; -_RPAR=')'; -_SPACE=' '; -_SQUOTE="'"; +_AT='@'; +_SP=' '; +_SQ="'"; _TAB=' '; -# function return values; `0' means ok; other values are error codes -export _ALL_EXIT; -export _BAD; export _ERROR; -export _GOOD; -export _NO; -export _OK; -export _YES; - -_GOOD='0'; # return ok -_BAD='1'; # return negatively, error code `1' _ERROR='7'; # for syntax errors; no `-1' in `ash' -_ALL_EXIT="${_GOOD} ${_BAD} ${_ERROR}"; # all exit codes (for `trap_set') - -_NO="${_BAD}"; -_YES="${_GOOD}"; -_OK="${_GOOD}"; - -# 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 _DEFAULT_MODES; -_DEFAULT_MODES='x,ps,tty'; -export _DEFAULT_RESOLUTION; -_DEFAULT_RESOLUTION='75'; - -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_HTML_X; # viewer program for html mode in X -export _VIEWER_HTML_TTY; # viewer program for html mode in tty -_VIEWER_DVI='xdvi,dvilx'; -_VIEWER_PDF='xpdf,acroread'; -_VIEWER_PS='gv,ghostview,gs_x11,gs'; -_VIEWER_HTML='konqueror,mozilla,netscape,opera,amaya,arena,lynx'; -_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 -# exist even more sections, mostly containing a set of man pages -# special to a specific program package. These aren't searched for -# automatically, but must be specified on the command line. -export _MAN_AUTO_SEC; -_MAN_AUTO_SEC="'1' '2' '3' '4' '5' '6' '7' '8' '9' 'n' 'o'" - -export _PROCESS_ID; # for shutting down the program -_PROCESS_ID="$$"; - - -############ the command line options of the involved programs -# -# The naming scheme for the options environment names is -# $_OPTS__[_] -# -# : program name GROFFER, GROFF, or CMDLINE (for all -# command line options) -# : LONG (long options) or SHORT (single character options) -# : ARG for options with argument, NA for no argument; -# without _ both the ones with and without arg. -# -# Each option that takes an argument must be specified with a -# trailing : (colon). - -# 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_X_SHORT_ARG; -export _OPTS_X_SHORT_NA; -export _OPTS_X_LONG_ARG; -export _OPTS_X_LONG_NA; -export _OPTS_MAN_SHORT_ARG; -export _OPTS_MAN_SHORT_NA; -export _OPTS_MAN_LONG_ARG; -export _OPTS_MAN_LONG_NA; -export _OPTS_MANOPT_SHORT_ARG; -export _OPTS_MANOPT_SHORT_NA; -export _OPTS_MANOPT_LONG_ARG; -export _OPTS_MANOPT_LONG_NA; -export _OPTS_CMDLINE_SHORT_NA; -export _OPTS_CMDLINE_SHORT_ARG; -export _OPTS_CMDLINE_LONG_NA; -export _OPTS_CMDLINE_LONG_ARG; - -###### groffer native options - -_OPTS_GROFFER_SHORT_NA="'h' 'Q' 'v' 'V' 'X' 'Z'"; -_OPTS_GROFFER_SHORT_ARG="'T'"; - -_OPTS_GROFFER_LONG_NA="'auto' 'debug' 'default' 'dvi' \ -'groff' 'help' 'intermediate-output' 'html' 'man' \ -'no-location' 'no-man' 'pdf' 'ps' 'rv' 'source' 'text' 'text-device' \ -'title' 'tty' 'tty-device' 'version' 'whatis' 'where' 'www' 'x' 'X'"; - -_OPTS_GROFFER_LONG_ARG="\ -'apropos' 'apropos-data' 'apropos-devel' 'apropos-progs' \ -'default-modes' 'dvi-viewer' 'extension' 'fg' 'fn' 'font' \ -'foreground' 'html-viewer' 'mode' 'pdf-viewer' 'ps-viewer' 'shell' \ -'tty-viewer' 'www-viewer' 'x-viewer' 'X-viewer'"; - -##### groffer options inhereted from groff - -_OPTS_GROFF_SHORT_NA="'a' 'b' 'c' 'C' 'e' 'E' 'g' 'G' 'i' 'l' 'N' 'p' \ -'R' 's' 'S' 't' 'U' 'V' 'z'"; -_OPTS_GROFF_SHORT_ARG="'d' 'f' 'F' 'I' 'L' 'm' 'M' 'n' 'o' 'P' 'r' \ -'w' 'W'"; -_OPTS_GROFF_LONG_NA="'source'"; -_OPTS_GROFF_LONG_ARG="'device' 'macro-file'"; - -##### groffer options inhereted from the X Window toolkit - -_OPTS_X_SHORT_NA=""; -_OPTS_X_SHORT_ARG=""; - -_OPTS_X_LONG_NA="'iconic' 'rv'"; - -_OPTS_X_LONG_ARG="'background' 'bd' 'bg' 'bordercolor' 'borderwidth' \ -'bw' 'display' 'fg' 'fn' 'font' 'foreground' 'ft', 'geometry' -'resolution' 'title' 'xrm'"; - -###### groffer options inherited from man - -_OPTS_MAN_SHORT_NA=""; -_OPTS_MAN_SHORT_ARG=""; - -_OPTS_MAN_LONG_NA="'all' 'ascii' 'catman' 'debug' 'ditroff' 'help' \ -'local-file' 'location' 'pager' 'troff' 'update' 'version' \ -'whatis' 'where'"; - -_OPTS_MAN_LONG_ARG="'extension' 'locale' 'manpath' \ -'pager' 'preprocessor' 'prompt' 'sections' 'systems' 'troff-device'"; - -###### additional options for parsing $MANOPT only - -_OPTS_MANOPT_SHORT_NA="'7' 'a' 'c' 'd' 'D' 'f' 'h' 'k' 'l' 't' 'u' \ -'V' 'w' 'Z'"; -_OPTS_MANOPT_SHORT_ARG="'e' 'L' 'm' 'M' 'p' 'P' 'r' 'S' 'T'"; - -_OPTS_MANOPT_LONG_NA="${_OPTS_MAN_LONG_NA} \ -'apropos' 'debug' 'default' 'html' 'ignore-case' 'location-cat' \ -'match-case' 'troff' 'update' 'version' 'where-cat'"; - -_OPTS_MANOPT_LONG_ARG="${_OPTS_MAN_LONG_NA} \ -'config_file' 'encoding' 'locale'"; - -###### collections of command line options - -_OPTS_CMDLINE_SHORT_NA="${_OPTS_GROFFER_SHORT_NA}\ -${_OPTS_GROFF_SHORT_NA} ${_OPTS_X_SHORT_NA} ${_OPTS_MAN_SHORT_NA}"; -_OPTS_CMDLINE_SHORT_ARG="${_OPTS_GROFFER_SHORT_ARG} \ -${_OPTS_GROFF_SHORT_ARG} ${_OPTS_X_SHORT_ARG} ${_OPTS_MAN_SHORT_ARG}"; - -_OPTS_CMDLINE_LONG_NA="${_OPTS_GROFFER_LONG_NA} \ -${_OPTS_GROFF_LONG_NA} ${_OPTS_X_LONG_NA} ${_OPTS_MAN_LONG_NA}"; -_OPTS_CMDLINE_LONG_ARG="${_OPTS_GROFFER_LONG_ARG} \ -${_OPTS_GROFF_LONG_ARG} ${_OPTS_MAN_LONG_ARG} ${_OPTS_X_LONG_ARG}"; - - -######################################################################## -# read-write variables (global to this file) -######################################################################## +# @...@ constructs -export _ADDOPTS_GROFF; # Transp. options for groff (`eval'). -export _ADDOPTS_POST; # Transp. options postproc (`eval'). -export _ADDOPTS_X; # Transp. options X postproc (`eval'). -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. -# _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 -# _MAN_* finally used configuration of man searching -export _MAN_ALL; # search all man pages per filespec -export _MAN_ENABLE; # enable search for man pages -export _MAN_EXT; # extension for man pages -export _MAN_FORCE; # force file parameter to be man pages -export _MAN_IS_SETUP; # setup man variables only once -export _MAN_LANG; # language for man pages -export _MAN_LANG_DONE; # language dirs added to man path -export _MAN_PATH; # search path for man pages -export _MAN_SEC; # sections for man pages; sep. `:' -export _MAN_SEC_DONE; # sections added to man path -export _MAN_SYS; # system names for man pages; sep. `,' -export _MAN_SYS; # system names added to man path -# _MANOPT_* as parsed from $MANOPT -export _MANOPT_ALL; # $MANOPT --all -export _MANOPT_EXTENSION; # $MANOPT --extension -export _MANOPT_LANG; # $MANOPT --locale -export _MANOPT_PATH; # $MANOPT --manpath -export _MANOPT_PAGER; # $MANOPT --pager -export _MANOPT_SEC; # $MANOPT --sections -export _MANOPT_SYS; # $MANOPT --systems -# _OPT_* as parsed from groffer command line -export _OPT_ALL; # display all suitable man pages. -export _OPT_APROPOS; # call `apropos' program. -export _OPT_APROPOS_DATA; # `apropos' for man sections 4, 5, 7 -export _OPT_APROPOS_DEVEL; # `apropos' for man sections 2, 3, 9 -export _OPT_APROPOS_PROGS; # `apropos' for man sections 1, 6, 8 -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_ICONIC; # -iconic option for X viewers. -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_TEXT_DEVICE; # set device for tty mode. -export _OPT_V; # groff option -V. -export _OPT_VIEWER_DVI; # viewer program for dvi mode -export _OPT_VIEWER_PDF; # viewer program for pdf mode -export _OPT_VIEWER_PS; # viewer program for ps mode -export _OPT_VIEWER_HTML; # viewer program for html mode -export _OPT_VIEWER_X; # viewer program for x mode -export _OPT_WHATIS; # print the one-liner man info -export _OPT_XRM; # specify X resource. -export _OPT_Z; # groff option -Z. -# _TMP_* temporary files -export _TMP_DIR; # groff directory for temporary files -export _TMP_DIR_SUB; # groffer directory for temporary files -export _TMP_CAT; # stores concatenation of everything -export _TMP_STDIN; # stores stdin, if any - -# these variables are preset in section `Preset' after the rudim. test +export _BEFORE_MAKE; +if test _@VERSION@_ = _${_AT}VERSION${_AT}_ +then + # script before `make' + _BEFORE_MAKE='yes'; +else + _BEFORE_MAKE='no'; +fi; +export _AT_BINDIR_AT; +export _AT_G_AT; +export _AT_LIBDIR_AT; +export _GROFFER_LIBDIR; +case "${_BEFORE_MAKE}" in +yes) + _AT_BINDIR_AT='.'; + _AT_G_AT=''; + _AT_LIBDIR_AT=''; + _GROFFER_LIBDIR='.'; + ;; +no) + _AT_BINDIR_AT='@BINDIR@'; + _AT_G_AT='@g@'; + _AT_LIBDIR_AT='@libdir@'; + _GROFFER_LIBDIR="${_AT_LIBDIR_AT}"'/groff/groffer'; + ;; +esac; -######################################################################## -# Test of rudimentary shell functionality -######################################################################## +if test -f "${_GROFFER_LIBDIR}"/version.sh +then + . "${_GROFFER_LIBDIR}"/version.sh; +fi; +export _GROFF_VERSION; +case "${_BEFORE_MAKE}" in +yes) + _GROFF_VERSION="${_GROFF_VERSION_PRESET}"; + ;; +no) + _GROFF_VERSION='@VERSION@'; + ;; +esac; + +export _GROFFER2_SH; # file name of the script that follows up +_GROFFER2_SH="${_GROFFER_LIBDIR}"/groffer2.sh; + +export _GROFFER_SH; # file name of this shell script +case "$0" in +*groffer*) + _GROFFER_SH="$0"; + # was: _GROFFER_SH="${_AT_BINDIR_AT}/groffer"; + ;; +*) + echo 'The groffer script should be started directly.' >&2 + exit 1; + ;; +esac; -######################################################################## -# Test of `test'. -# -test "a" = "a" || exit 1; +export _NULL_DEV; +if test -c /dev/null +then + _NULL_DEV="/dev/null"; +else + _NULL_DEV="NUL"; +fi; -######################################################################## -# Test of `echo' and the `$()' construct. -# -echo -n '' >/dev/null || exit "${_ERROR}"; -if test _"$(echo -n 'te' && echo -n '' && echo -n 'st')"_ != _test_; then +# Test of the `$()' construct. +if test _"$(echo "$(echo 'test')")"_ \ + != _test_ +then + echo 'The "$()" construct did not work.' >&2; exit "${_ERROR}"; fi; - -######################################################################## -# Test of function definitions. -# -_t_e_s_t_f_u_n_c_() -{ - return "${_OK}"; -} - -if _t_e_s_t_f_u_n_c_ 2>/dev/null; then - : -else - echo 'shell does not support function definitions.' >&2; +# Test of sed program +if test _"$(echo red | sed -e 's/r/s/')"_ != _sed_ +then + echo 'The sed program did not work.' >&2; exit "${_ERROR}"; fi; -######################################################################## -# 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_DIR_SUB=''; -_TMP_CAT=''; -_TMP_STDIN=''; +########################### configuration - -######################################################################## -# reset () -# -# Reset the variables that can be affected by options to their default. -# -reset() -{ - if test "$#" -ne 0; then - error "reset() does not have arguments."; - 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=''; - _OPT_APROPOS_DATA=''; - _OPT_APROPOS_DEVEL=''; - _OPT_APROPOS_PROGS=''; - _OPT_BD=''; - _OPT_BG=''; - _OPT_BW=''; - _OPT_DEBUG='no'; - _OPT_DEFAULT_MODES=''; - _OPT_DEVICE=''; - _OPT_DISPLAY=''; - _OPT_FG=''; - _OPT_FN=''; - _OPT_GEOMETRY=''; - _OPT_ICONIC='no'; - _OPT_LANG=''; - _OPT_LOCATION='no'; - _OPT_MODE=''; - _OPT_MANPATH=''; - _OPT_PAGER=''; - _OPT_RESOLUTION=''; - _OPT_RV='no'; - _OPT_SECTIONS=''; - _OPT_SYSTEMS=''; - _OPT_TITLE=''; - _OPT_TEXT_DEVICE=''; - _OPT_V='no'; - _OPT_VIEWER_DVI=''; - _OPT_VIEWER_PDF=''; - _OPT_VIEWER_PS=''; - _OPT_VIEWER_HTML=''; - _OPT_VIEWER_X=''; - _OPT_WHATIS='no'; - _OPT_XRM=''; - _OPT_Z='no'; - -} - -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 () -# -# Clean up at exit. -# -clean_up() -{ - if test -d "${_TMP_DIR}"; then - rm -f "${_TMP_DIR}"/*; - rmdir "${_TMP_DIR}"; - fi; -} - - -############## -# echo2 (*) -# -# Output to stderr. -# -# Arguments : arbitrary text. -# -echo2() -{ - echo "$*" >&2; -} - - -############## -# echo2n (*) -# -# Output to stderr. -# -# Arguments : arbitrary text. -# -echo2n() -{ - echo -n "$*" >&2; -} - - -############# -# diag (text>*) -# -# Output a diagnostic message to stderr -# -diag() -{ - echo2 '>>>>>'"$*"; -} - - -############# -# error (*) -# -# Print an error message to standard error; exit with an error condition -# -error() -{ - local i; - local _code; - _code="${_ERROR}"; - case "$#" in - 0) true; ;; - 1) echo2 'groffer error: '"$1"; ;; - 2) - echo2 'groffer error: '"$1"; - _code="$2"; - ;; - *) echo2 'groffer error: wrong number of arguments in error().'; ;; - esac; - if test _"${_DEBUG}"_ = _yes_; then - func_stack_dump; +# read and transform the configuration files, execute the arising commands +for f in "${_CONF_FILE_HOME}" "${_CONF_FILE_ETC}" +do + if test -f "$f" + then + o=""; # $o means groffer option + # use "" quotes because of ksh and posh + eval "$(cat "$f" | sed -n -e ' +# Ignore comments +/^['"${_SP}${_TAB}"']*#/d +# Delete leading and final space +s/^['"${_SP}${_TAB}"']*// +s/['"${_SP}${_TAB}"']*$// +# Print all lines with shell commands, those not starting with - +/^[^-]/p +# Remove all single and double quotes +s/['"${_SQ}"'"]//g +# Replace empty arguments +s/^\(-[^ ]*\)=$/o="${o} \1 '"${_SQ}${_SQ}"'"/p +# Replace division between option and argument by single space +s/[='"${_SP}${_TAB}"']['"${_SP}${_TAB}"']*/'"${_SP}"'/ +# Handle lines without spaces +s/^\(-[^'"${_SP}"']*\)$/o="${o} \1"/p +# Encircle the remaining arguments with single quotes +s/^\(-[^ ]*\) \(.*\)$/o="${o} \1 '"${_SQ}"'\2'"${_SQ}"'"/p +')" + + # Remove leading space + o="$(echo "$o" | sed -e 's/^ *//')"; + if test _"${o}"_ != __ + then + if test _"{GROFFER_OPT}"_ = __ + then + GROFFER_OPT="${o}"; + else + GROFFER_OPT="${o} ${GROFFER_OPT}"; + fi; + fi; fi; - clean_up; - kill "${_PROCESS_ID}" >/dev/null 2>&1; - kill -9 "${_PROCESS_ID}" >/dev/null 2>&1; - exit "${_code}"; -} +done; - -############# -# abort (*) -# -# Terminate program with error condition -# -abort() -{ - error "Program aborted."; - exit 1; -} +# integrate $GROFFER_OPT into the command line; it isn't needed any more +if test _"${GROFFER_OPT}"_ != __ +then + eval set x "${GROFFER_OPT}" '"$@"'; + shift; + GROFFER_OPT=''; +fi; -############# -# 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; -} +########################### Determine the shell +export _SHELL; -############# -# func_pop () -# -# Retrieve the top element from the stack. -# -# The stack elements are separated by `!'; the popped element is -# identical to the original element, except that all `!' characters -# were removed. -# -# 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.'; +# use "``" instead of "$()" for using the case ")" construct +# do not use "" quotes because of ksh +_SHELL=` + # $x means list. + # $s means shell. + # The command line arguments are taken over. + # Shifting herein does not have an effect outside. + export x; + case " $*" in + *\ --sh*) # abbreviation for --shell + x=''; + s=''; + # determine all --shell arguments, store them in $x in reverse order + while test $# != 0 + do + case "$1" in + --shell|--sh|--she|--shel) + if test "$#" -ge 2 + then + s="$2"; + shift; + fi; ;; - *!*) - # split at first bang `!'. - _FUNC_STACK="$(echo -n ${_FUNC_STACK} \ - | sed -e 's/^[^!]*!//')"; + --shell=*|--sh=*|--she=*|--shel=*) + # delete up to first "=" character + s="$(echo x"$1" | sed -e 's/^x[^=]*=//')"; ;; *) - _FUNC_STACK=''; - ;; - esac; - fi; -} - + shift; + continue; + esac; + if test _"${x}"_ = __ + then + x="'${s}'"; + else + x="'${s}' ${x}"; + fi; + shift; + done; -############# -# func_push () -# -# Store another element to stack. -# -# The stack elements are separated by `!'; if contains a `!' -# it is removed first. -# -# 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 - *'!'*) - # remove all bangs `!'. - _element="$(echo -n "$1" | sed -e 's/!//g')"; - ;; - *) - _element="$1"; - ;; - esac; - if test _"${_FUNC_STACK}"_ = __; then - _FUNC_STACK="${_element}"; - else - _FUNC_STACK="${_element}!${_FUNC_STACK}"; + # from all possible shells in $x determine the first being a shell + # or being empty + s="$( + # "" quotes because of posh + eval set x "${x}"; + shift; + if test $# != 0 + then + for i + do + if test _"$i"_ = __ + then + # use the empty argument as the default shell + echo empty; + break; + else + # test $i on being a shell program; + # use this kind of quoting for posh + if test _"$(eval "$i -c 'echo ok'" 2>${_NULL_DEV})"_ = _ok_ >&2 + then + # shell found + cat </dev/null 2>&1; then - true; -else - true() - { - return "${_GOOD}"; - } - - false() - { - return "${_BAD}"; - } -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}"; -} +########################### test fast shells for automatic run -if _t_e_s_t_f_u_n_c_; then - : -else - local() - { - if test _"$1"_ != __; then - error "overriding global variable \`$1' with local value."; +if test _"${_SHELL}"_ = __ +then + for s in ksh ash dash pdksh zsh posh + do + if test _"$(eval "$s -c 'echo ok'" 2>${_NULL_DEV})"_ = _ok_ >&2 + then + _SHELL="$s"; + break; fi; - } + done; 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'; -} +########################### start groffer2.sh -_t_e_s_t_f_u_n_c_; -if test _"${_global}"_ != _inside_ || test _"${_clobber}"_ != _outside_; +if test _"${_SHELL}"_ = _empty_ then - error "Cannot assign to global variables from within functions."; + _SHELL=''; fi; -unset _global; -unset _clobber; - - -######################################################################## -# Test of function `sed'. -# - -if test _"$(echo xTesTx \ - | sed -e 's/^.\([Tt]e*x*sTT*\).*$/\1/' \ - | sed -e '\|T|s|T|t|g')"_ != _test_; +if test _"${_SHELL}"_ = __ then - error 'Test of "sed" command failed.'; -fi; - - -######################################################################## -# Test of function `cat'. -# -if test _"$(echo test | cat)"_ != _test_; then - error 'Test of "cat" command failed.'; -fi; - - -######################################################################## -# Test for compression. -# -if test _"$(echo 'test' | gzip -c -d -f - 2>/dev/null)"_ = _test_; then - _HAS_COMPRESSION='yes'; - if echo 'test' | bzip2 -c 2>/dev/null | bzip2 -t 2>/dev/null \ - && test _"$(echo 'test' | bzip2 -c 2>/dev/null \ - | bzip2 -d -c 2>/dev/null)"_ \ - = _test_; then - _HAS_BZIP='yes'; - else - _HAS_BZIP='no'; - fi; -else - _HAS_COMPRESSION='no'; - _HAS_BZIP='no'; -fi; - - -######################################################################## -_t_e_s_t_f_u_n_c_() -{ - : -} - - -######################################################################## -# Definition of normal Functions -######################################################################## -landmark "3: functions"; - -######################################################################## -# abort (*) -# -# Unconditionally terminate the program with error code; -# useful for debugging. -# -# defined above - - -######################################################################## -# apropos_run () -# -# -apropos_run() { - func_check apropos_run = 1 "$@"; - if apropos apropos >/dev/null 2>/dev/null; then - apropos "$1"; - elif man --apropos man >/dev/null 2>/dev/null; then - man --apropos "$1"; - elif man -k man >/dev/null 2>/dev/null; then - man -k "$1"; - fi; -} - - -######################################################################## -# base_name () -# -# Get the file name part of , i.e. delete everything up to last -# `/' from the beginning of . Remove final slashes, too, to get a -# non-empty output. -# -# Arguments : 1 -# Output : the file name part (without slashes) -# -base_name() -{ - func_check base_name = 1 "$@"; - local f; - f="$1"; - case "$f" in - */) - # delete all final slashes - f="$(echo -n "$f" | sed -e '\|.*|s|//*$||')"; - ;; - esac; - case "$f" in - /|'') - eval "${return_bad}"; - ;; - */*) - # delete everything before and including the last slash `/'. - echo -n "$f" | sed -e '\|.*|s|^.*//*\([^/]*\)$|\1|'; - ;; - *) - echo -n "$f"; - ;; - esac; - eval "${return_ok}"; -} - - -######################################################################## -# catz () -# -# Decompress if possible or just print to standard output. -# -# gzip, bzip2, and .Z decompression is supported. -# -# Arguments: 1, a file name. -# Output: the content of , possibly decompressed. -# -if test _"${_HAS_COMPRESSION}"_ = _yes_; then - catz() - { - func_check catz = 1 "$@"; - case "$1" in - '') - error 'catz(): empty file name'; - ;; - '-') - error 'catz(): for standard input use save_stdin()'; - ;; - esac; - if obj _HAS_BZIP is_yes; then - if bzip2 -t "$1" 2>/dev/null; then - bzip2 -c -d "$1" 2>/dev/null; - eval "${return_ok}"; - fi; - fi; - gzip -c -d -f "$1" 2>/dev/null; - eval "${return_ok}"; - } + # no shell found, so start groffer2.sh normally + eval . "'${_GROFFER2_SH}'" '"$@"'; + exit; else - catz() - { - func_check catz = 1 "$@"; - cat "$1"; - eval "${return_ok}"; - } + # start groffer2.sh with the found $_SHELL + # do not quote $_SHELL to allow arguments + eval exec "${_SHELL} '${_GROFFER2_SH}'" '"$@"'; + exit; fi; - - -######################################################################## -# clean_up () -# -# Do the final cleaning up before exiting; used by the trap calls. -# -# defined above - - -######################################################################## -# diag (*) -# -# Print marked message to standard error; useful for debugging. -# -# defined above - - -######################################################################## -landmark '4: dirname()*'; -######################################################################## - -####################################################################### -# dirname_append ( ) -# -# Append `name' to `dir' with clean handling of `/'. -# -# Arguments : 2 -# Output : the generated new directory name / -# -dirname_append() -{ - func_check dirname_append = 2 "$@"; - local _res; - if is_empty "$1"; then - error "dir_append(): first argument is empty."; - fi; - if is_empty "$2"; then - echo -n "$1"; - else - dirname_chop "$1"/"$2"; - fi; - eval "${return_ok}"; -} - - -######################################################################## -# dirname_chop () -# -# Remove unnecessary slashes from directory name. -# -# Argument: 1, a directory name. -# Output: path without double, or trailing slashes. -# -dirname_chop() -{ - func_check dirname_chop = 1 "$@"; - local _arg; - local _res; - local _sep; - # replace all multiple slashes by a single slash `/'. - _res="$(echo -n "$1" | sed -e '\|.*|s|///*|/|g')"; - case "${_res}" in - ?*/) - # remove trailing slash '/'; - echo -n "${_res}" | sed -e '\|.*|s|/$||'; - ;; - *) echo -n "${_res}"; ;; - esac; - eval "${return_ok}"; -} - - -######################################################################## -# do_filearg () -# -# Append the file, man-page, or standard input corresponding to the -# argument to the temporary file. If this is compressed in the gzip -# or Z format it is decompressed. A title element is generated. -# -# Argument either: -# - name of an existing files. -# - `-' to represent standard input (several times allowed). -# - `man:name.(section)' the man-page for `name' in `section'. -# - `man:name.section' the man-page for `name' in `section'. -# - `man:name' the man-page for `name' in the lowest `section'. -# - `name.section' the man-page for `name' in `section'. -# - `name' the man-page for `name' in the lowest `section'. -# Globals : -# $_TMP_STDIN, $_MAN_ENABLE, $_MAN_IS_SETUP, $_OPT_MAN -# -# Output : none -# Return : $_GOOD if found, ${_BAD} otherwise. -# -do_filearg() -{ - func_check do_filearg = 1 "$@"; - local _filespec; - local i; - _filespec="$1"; - # store sequence into positional parameters - case "${_filespec}" in - '') - eval "${return_good}"; - ;; - '-') - register_file '-'; - eval "${return_good}"; - ;; - */*) # with directory part; so no man search - set -- 'File'; - ;; - *) - if obj _MAN_ENABLE is_yes; then - if obj _MAN_FORCE is_yes; then - set -- 'Manpage' 'File'; - else - set -- 'File' 'Manpage'; - fi; - else - set -- 'File'; - fi; - ;; - esac; - for i in "$@"; do - case "$i" in - File) - if test -f "${_filespec}"; then - if test -r "${_filespec}"; then - register_file "${_filespec}"; - eval "${return_good}"; - else - echo2 "could not read \`${_filespec}'"; - eval "${return_bad}"; - fi; - else - continue; - fi; - ;; - Manpage) # parse filespec as man page - if obj _MAN_IS_SETUP is_not_yes; then - man_setup; - fi; - if man_do_filespec "${_filespec}"; then - eval "${return_good}"; - else - continue; - fi; - ;; - esac; - done; - eval "${return_bad}"; -} # do_filearg() - - -######################################################################## -# do_nothing () -# -# Dummy function. -# -do_nothing() -{ - return "${_OK}"; -} - - -######################################################################## -# echo2 (*) -# -# Print to standard error with final line break. -# -# defined above - - -######################################################################## -# echo2n (*) -# -# Print to standard error without final line break. -# -# defined above - - -######################################################################## -# error (*) -# -# Print error message and exit with error code. -# -# defined above - - -######################################################################## -# 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. -# -# Return : `1' if all arguments are empty, `0' if found. -# Output : the retrieved non-empty argument. -# -get_first_essential() -{ - func_check get_first_essential '>=' 0 "$@"; - local i; - if is_equal "$#" 0; then - eval "${return_ok}"; - fi; - for i in "$@"; do - if obj i is_not_empty; then - echo -n "$i"; - eval "${return_ok}"; - fi; - done; - eval "${return_bad}"; -} - - -######################################################################## -landmark '5: is_*()'; -######################################################################## - -######################################################################## -# is_dir () -# -# Test whether `name' is a directory. -# -# Arguments : 1 -# Return : `0' if arg1 is a directory, `1' otherwise. -# -is_dir() -{ - func_check is_dir = 1 "$@"; - if test -d "$1" && test -r "$1"; then - eval "${return_yes}"; - fi; - eval "${return_no}"; -} - - -######################################################################## -# is_empty () -# -# Test whether `string' is empty. -# -# Arguments : <=1 -# Return : `0' if arg1 is empty or does not exist, `1' otherwise. -# -is_empty() -{ - func_check is_empty = 1 "$@"; - if test _"$1"_ = __; then - eval "${return_yes}"; - fi; - eval "${return_no}"; -} - - -######################################################################## -# is_equal ( ) -# -# Test whether `string1' is equal to . -# -# Arguments : 2 -# Return : `0' both arguments are equal strings, `1' otherwise. -# -is_equal() -{ - func_check is_equal = 2 "$@"; - if test _"$1"_ = _"$2"_; then - eval "${return_yes}"; - fi; - eval "${return_no}"; -} - - -######################################################################## -# is_file () -# -# Test whether `name' is a readable file. -# -# Arguments : 1 -# Return : `0' if arg1 is a readable file, `1' otherwise. -# -is_file() -{ - func_check is_file = 1 "$@"; - if test -f "$1" && test -r "$1"; then - eval "${return_yes}"; - fi; - eval "${return_no}"; -} - - -######################################################################## -# is_non_empty_file () -# -# Test whether `file_name' is a non-empty existing file. -# -# Arguments : <=1 -# Return : -# `0' if arg1 is a non-empty existing file -# `1' otherwise -# -is_non_empty_file() -{ - func_check is_empty = 1 "$@"; - if is_file "$1"; then - if is_not_empty "$(cat "$1" | sed -e '/./q')"; then - eval "${return_yes}"; - fi; - fi; - eval "${return_no}"; -} - - -######################################################################## -# is_not_dir () -# -# Test whether `name' is not a readable directory. -# -# Arguments : 1 -# Return : `0' if arg1 is a directory, `1' otherwise. -# -is_not_dir() -{ - func_check is_not_dir = 1 "$@"; - if is_dir "$1"; then - eval "${return_no}"; - fi; - eval "${return_yes}"; -} - - -######################################################################## -# is_not_empty () -# -# Test whether `string' is not empty. -# -# Arguments : <=1 -# Return : `0' if arg1 exists and is not empty, `1' otherwise. -# -is_not_empty() -{ - func_check is_not_empty = 1 "$@"; - if is_empty "$1"; then - eval "${return_no}"; - fi; - eval "${return_yes}"; -} - - -######################################################################## -# is_not_equal ( ) -# -# Test whether `string1' differs from `string2'. -# -# Arguments : 2 -# -is_not_equal() -{ - func_check is_not_equal = 2 "$@"; - if is_equal "$1" "$2"; then - eval "${return_no}"; - fi - eval "${return_yes}"; -} - - -######################################################################## -# is_not_file () -# -# Test whether `name' is a not readable file. -# -# Arguments : >=1 (empty allowed), more args are ignored -# -is_not_file() -{ - func_check is_not_file '>=' 1 "$@"; - if is_file "$1"; then - eval "${return_no}"; - fi; - eval "${return_yes}"; -} - - -######################################################################## -# 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}"; - fi; - eval "${return_yes}"; -} - - -######################################################################## -# is_not_writable () -# -# Test whether `name' is a not a writable file or directory. -# -# Arguments : >=1 (empty allowed), more args are ignored -# -is_not_writable() -{ - func_check is_not_writable '>=' 1 "$@"; - if is_writable "$1"; then - eval "${return_no}"; - fi; - eval "${return_yes}"; -} - - -######################################################################## -# is_not_yes () -# -# Test whether `string' is not "yes". -# -# Arguments : 1 -# -is_not_yes() -{ - func_check is_not_yes = 1 "$@"; - if is_yes "$1"; then - eval "${return_no}"; - fi; - eval "${return_yes}"; -} - - -######################################################################## -# is_prog () -# -# Determine whether arg is a program in $PATH -# -# Arguments : >=0 (empty allowed) -# more args are ignored, this allows to specify progs with arguments -# -is_prog() -{ - func_check is_prog '>=' 0 "$@"; - case "$#" in - 0) - eval "${return_no}"; - ;; - *) - if where "$1" >/dev/null; then - eval "${return_yes}"; - fi; - ;; - esac - eval "${return_no}"; -} - - -######################################################################## -# is_writable () -# -# Test whether `name' is a writable file or directory. -# -# Arguments : >=1 (empty allowed), more args are ignored -# -is_writable() -{ - func_check is_writable '>=' 1 "$@"; - if test -r "$1"; then - if test -w "$1"; then - eval "${return_yes}"; - fi; - fi; - eval "${return_no}"; -} - - -######################################################################## -# is_yes () -# -# Test whether `string' has value "yes". -# -# Arguments : <=1 -# Return : `0' if arg1 is `yes', `1' otherwise. -# -is_yes() -{ - func_check is_yes = 1 "$@"; - if is_equal "$1" 'yes'; then - eval "${return_yes}"; - fi; - eval "${return_no}"; -} - - -######################################################################## -# 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. -# -leave() -{ - clean_up; - exit "${_OK}"; -} - - -######################################################################## -landmark '6: list_*()'; -######################################################################## -# -# `list' is an object class that represents an array or list. Its -# data consists of space-separated single-quoted elements. So a list -# has the form "'first' 'second' '...' 'last'". See list_append() for -# more details on the list structure. The array elements of `list' -# can be get by `set -- $list`. - - -######################################################################## -# list_append ( ...) -# -# Arguments: >=2 -# : a variable name for a list of single-quoted elements -# : some sequence of characters. -# Output: none, but $ is set to -# if is empty: "'' '...'" -# otherwise: "$list '' ..." -# -list_append() -{ - func_check list_append '>=' 2 "$@"; - local _element; - local _list; - local _name; - _name="$1"; - eval _list='"${'$1'}"'; - shift; - for s in "$@"; do - case "$s" in - *\'*) - # escape each single quote by replacing each - # "'" (squote) by "'\''" (squote bslash squote squote); - # note that the backslash must be doubled in the following `sed' - _element="$(echo -n "$s" | sed -e 's/'"${_SQUOTE}"'/&\\&&/g')"; - ;; - '') - _element=""; - ;; - *) - _element="$s"; - ;; - esac; - if obj _list is_empty; then - _list="'${_element}'"; - else - _list="${_list} '${_element}'"; - fi; - done; - eval "${_name}"='"${_list}"'; - eval "${return_ok}"; -} - - -######################################################################## -# 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: >=1 -# : common part of a set of 4 environment variable names: -# $_SHORT_NA: list of short options without an arg. -# $_SHORT_ARG: list of short options that have an arg. -# $_LONG_NA: list of long options without an arg. -# $_LONG_ARG: list of long options that have an arg. -# ...: the arguments from a command line, such as "$@", -# the content of a variable, or direct arguments. -# -# Output: ['-[-]opt' ['optarg']]... '--' ['filename']... -# -# Example: -# list_from_cmdline PRE 'a b' 'c' '' 'long' -a f1 -bcarg --long=larg f2 -# If $PRE_SHORT_NA, $PRE_SHORT_ARG, $PRE_LONG_NA, and $PRE_LONG_ARG are -# none-empty option lists, this will result in printing: -# '-a' '-b' '-c' 'arg' '--long' 'larg' '--' 'f1' 'f2' -# -# Use this function in the following way: -# eval set -- "$(args_norm PRE_NAME "$@")"; -# while test "$1" != '--'; do -# case "$1" in -# ... -# esac; -# shift; -# done; -# shift; #skip '--' -# # all positional parameters ("$@") left are file name parameters. -# -list_from_cmdline() -{ - func_check list_from_cmdline '>=' 1 "$@"; - local _fparams; - local _fn; - local _short_a; - local _short_n; - local _long_a; - local _long_n; - local _result; - _short_n="$(obj_data "$1"_SHORT_NA)"; # short options, no argument - _short_a="$(obj_data "$1"_SHORT_ARG)"; # short options, with argument - _long_n="$(obj_data "$1"_LONG_NA)"; # long options, no argument - _long_a="$(obj_data "$1"_LONG_ARG)"; # long options, with argument - if obj _short_n is_empty; then - error 'list_from_cmdline(): no $'"$1"'_SHORT_NA options.'; - fi; - if obj _short_a is_empty; then - error 'list_from_cmdline(): no $'"$1"'_SHORT_ARG options.'; - fi; - if obj _long_n is_empty; then - error 'list_from_cmdline(): no $'"$1"'_LONG_NA options.'; - fi; - if obj _long_a is_empty; then - error 'list_from_cmdline(): no $'"$1"'_LONG_ARG options.'; - fi; - shift; - _fn='list_from_cmdline():'; # for error messages - if is_equal "$#" 0; then - echo -n "'--'"; - eval "${return_ok}"; - fi; - _fparams=''; - _result=''; - while test "$#" -ge 1; do - _arg="$1"; - shift; - case "$_arg" in - --) break; ;; - --?*) - # delete leading '--'; - _opt="$(echo -n "${_arg}" | sed -e 's/^..//')"; - if list_has _long_n "${_opt}"; then - # long option, no argument - list_append _result "--${_opt}"; - continue; - fi; - # test on `--opt=arg' - if string_contains "${_opt}" '='; then - # extract option by deleting from the first '=' to the end - _lopt="$(echo -n "${_opt}" | sed -e 's/=.*$//')"; - if list_has _long_a "${_lopt}"; then - # get the option argument by deleting up to first `=' - _optarg="$(echo -n "${_opt}" | sed -e 's/^[^=]*=//')"; - list_append _result "--${_lopt}" "${_optarg}"; - continue; - fi; - fi; - if list_has _long_a "${_opt}"; then - # long option with argument - if test "$#" -le 0; then - error "${_fn} no argument for option --${_opt}." - fi; - list_append _result "--${_opt}" "$1"; - shift; - continue; - fi; - error "${_fn} --${_opt} is not an option." - ;; - -?*) # short option (cluster) - # delete leading `-'; - _rest="$(echo -n "${_arg}" | sed -e 's/^-//')"; - while obj _rest is_not_empty; do - # get next short option from cluster (first char of $_rest) - _optchar="$(echo -n "${_rest}" | sed -e 's/^\(.\).*$/\1/')"; - # remove first character from ${_rest}; - _rest="$(echo -n "${_rest}" | sed -e 's/^.//')"; - if list_has _short_n "${_optchar}"; then - list_append _result "-${_optchar}"; - continue; - elif list_has _short_a "${_optchar}"; then - if obj _rest is_empty; then - if test "$#" -ge 1; then - list_append _result "-${_optchar}" "$1"; - shift; - continue; - else - error \ - "${_fn}"' no argument for option -'"${_optchar}." - fi; - else # rest is the argument - list_append _result "-${_optchar}" "${_rest}"; - _rest=''; - continue; - fi; - else - error "${_fn} unknown option -${_optchar}." - fi; - done; - ;; - *) - # Here, $_arg is not an option, so a file parameter. - list_append _fparams "${_arg}"; - - # Ignore the strange option handling of $POSIXLY_CORRECT to - # end option parsing after the first file name argument. To - # reuse it, do a `break' here if $POSIXLY_CORRECT is - # non-empty. - ;; - esac; - done; - list_append _result '--'; - if obj _fparams is_not_empty; then - _result="${_result} ${_fparams}"; - fi; - if test "$#" -gt 0; then - list_append _result "$@"; - fi; - echo -n "$_result"; - eval "${return_ok}"; -} # list_from_cmdline() - - -######################################################################## -# list_from_split ( ) -# -# In , escape all white space characters and replace each -# by space. -# -# Arguments: 2: a that is to be split into parts divided by -# -# Output: the resulting list string -# -list_from_split() -{ - func_check list_from_split = 2 "$@"; - local _s; - - # precede each space or tab by a backslash `\' (doubled for `sed') - _s="$(echo -n "$1" | sed -e 's/\(['"${_SPACE}${_TAB}"']\)/\\\1/g')"; - - # replace split character of string by the list separator ` ' (space). - case "$2" in - /) # cannot use normal `sed' separator - echo -n "${_s}" | sed -e '\|.*|s|'"$2"'| |g'; - ;; - ?) # use normal `sed' separator - echo -n "${_s}" | sed -e 's/'"$2"'/ /g'; - ;; - ??*) - error 'list_from_split(): separator must be a single character.'; - ;; - esac; - eval "${return_ok}"; -} - - -######################################################################## -# list_get () -# -# Check whether is a space-separated list of '-quoted elements. -# -# If the test fails an error is raised. -# If the test succeeds the argument is echoed. -# -# 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 -# unescaped single-quotes left. Watch out for escaped single -# quotes; they have the form '\'' (sq bs sq sq). - -# Arguments: 1 -# Output: the argument unchanged, if the check succeeded. -# -list_get() -{ - func_check list_get = 1 "$@"; - local _list; - eval _list='"${'$1'}"'; - # remove leading and final space characters - _list="$(echo -n "${_list}" | \ - sed -e 's/^['"${_SPACE}${_TAB}"']*//' | \ - sed -e 's/['"${_SPACE}${_TAB}"']*$//')"; - case "${_list}" in - '') - eval "${return_ok}"; - ;; - \'*\') - echo -n "${_list}"; - eval "${return_ok}"; - ;; - *) - error "list_get(): bad list: $1" - ;; - esac; - eval "${return_ok}"; -} - - -######################################################################## -# list_has ( ) -# -# Arguments: 2 -# : a variable name for a list of single-quoted elements -# : some sequence of characters. -# Output: -# if is empty: "'' '...'" -# otherwise: "list '' ..." -# -list_has() -{ - func_check list_has = 2 "$@"; - eval _list='"${'$1'}"'; - if obj _list is_empty; then - eval "${return_no}"; - fi; - _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 "$@"; - eval _list='"${'$1'}"'; - if obj _list is_empty; then - eval "${return_yes}"; - fi; - _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}"; -} - - -######################################################################## -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 obj _MAN_PATH is_empty; then - eval "${return_bad}"; - fi; - if is_empty "$1"; then - eval "${return_bad}"; - fi; - _spec="$1"; - _name=''; - _section=''; - case "${_spec}" in - */*) # not a man spec when it contains '/' - eval "${return_bad}"; - ;; - man:?*\(?*\)) # man:name(section) - _name="$(echo -n "${_spec}" \ - | sed -e 's/^man:\(..*\)(\(..*\))$/\1/')"; - _section="$(echo -n "${_spec}" \ - | sed -e 's/^man:\(..*\)(\(..*\))$/\2/')"; - ;; - man:?*.[0-9on]) # man:name.section - _name="$(echo -n "${_spec}" \ - | sed -e 's/^man:\(..*\)\..$/\1/')"; - _section="$(echo -n "${_spec}" \ - | sed -e 's/^.*\(.\)$/\1/')"; - ;; - man:?*) # man:name - _name="$(echo -n "${_spec}" | sed -e 's/^man://')"; - ;; - ?*\(?*\)) # name(section) - _name="$(echo -n "${_spec}" \ - | sed -e 's/^\(..*\)(\(..*\))$/\1/')"; - _section="$(echo -n "${_spec}" \ - | sed -e 's/^\(..*\)(\(..*\))$/\2/')"; - ;; - ?*.[0-9on]) # name.section - _name="$(echo -n "${_spec}" \ - | sed -e 's/^\(..*\)\..$/\1/')"; - _section="$(echo -n "${_spec}" \ - | sed -e 's/^.*\(.\)$/\1/')"; - ;; - ?*) - _name="${_filespec}"; - ;; - esac; - if obj _name is_empty; then - eval "${return_bad}"; - fi; - _got_one='no'; - if obj _section is_empty; then - eval set -- "${_MAN_AUTO_SEC}"; - for s in "$@"; do - if man_search_section "${_name}" "$s"; then # found - if obj _MAN_ALL is_yes; 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 obj _MAN_ALL is_yes && 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 obj _MAN_PATH is_empty; then - eval "${return_bad}"; - fi; - if is_empty "$1"; then - eval "${return_bad}"; - fi; - if is_empty "$2"; then - eval "${return_bad}"; - fi; - _name="$1"; - _section="$2"; - eval set -- "$(path_split "${_MAN_PATH}")"; - _got_one='no'; - if obj _MAN_EXT is_empty; then - for d in "$@"; do - _dir="$(dirname_append "$d" "man${_section}")"; - if obj _dir is_dir; then - _prefix="$(dirname_append "${_dir}" "${_name}.${_section}")"; - for f in $(echo -n ${_prefix}*); do - if obj f is_file; then - if is_yes "${_got_one}"; then - register_file "$f"; - elif obj _MAN_ALL is_yes; then - man_register_file "$f" "${_name}"; - else - man_register_file "$f" "${_name}" "${_section}"; - eval "${return_good}"; - fi; - _got_one='yes'; - fi; - done; - fi; - done; - else - _ext="${_MAN_EXT}"; - # check for directory name having trailing extension - for d in "$@"; do - _dir="$(dirname_append $d man${_section}${_ext})"; - if obj _dir is_dir; then - _prefix="$(dirname_append "${_dir}" "${_name}.${_section}")"; - for f in ${_prefix}*; do - if obj f is_file; then - if is_yes "${_got_one}"; then - register_file "$f"; - elif obj _MAN_ALL is_yes; then - man_register_file "$f" "${_name}"; - else - man_register_file "$f" "${_name}" "${_section}"; - eval "${return_good}"; - fi; - _got_one='yes'; - fi; - done; - fi; - done; - # check for files with extension in directories without extension - for d in "$@"; do - _dir="$(dirname_append "$d" "man${_section}")"; - if obj _dir is_dir; then - _prefix="$(dirname_append "${_dir}" \ - "${_name}.${_section}${_ext}")"; - for f in ${_prefix}*; do - if obj f is_file; then - if is_yes "${_got_one}"; then - register_file "$f"; - elif obj _MAN_ALL is_yes; then - man_register_file "$f" "${_name}"; - else - man_register_file "$f" "${_name}" "${_section}"; - eval "${return_good}"; - fi; - _got_one='yes'; - fi; - done; - fi; - done; - fi; - if obj _MAN_ALL is_yes && is_yes "${_got_one}"; then - eval "${return_good}"; - fi; - eval "${return_bad}"; -} # man_search_section() - - -######################################################################## -# man_setup () -# -# Setup the variables $_MAN_* needed for man page searching. -# -# Globals: -# in: $_OPT_*, $_MANOPT_*, $LANG, $LC_MESSAGES, $LC_ALL, -# $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM, $MANOPT. -# out: $_MAN_PATH, $_MAN_LANG, $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2, -# $_MAN_SEC, $_MAN_ALL -# in/out: $_MAN_ENABLE -# -# The precedence for the variables related to `man' is that of GNU -# `man', i.e. -# -# $LANG; overridden by -# $LC_MESSAGES; overridden by -# $LC_ALL; this has the same precedence as -# $MANPATH, $MANROFFSEQ, $MANSEC, $PAGER, $SYSTEM; overridden by -# $MANOPT; overridden by -# the groffer command line options. -# -man_setup() -{ - func_check main_man_setup = 0 "$@"; - local _lang; - - if obj _MAN_IS_SETUP is_yes; then - eval "${return_ok}"; - fi; - _MAN_IS_SETUP='yes'; - - if obj _MAN_ENABLE is_not_yes; then - eval "${return_ok}"; - fi; - - # determine basic path for man pages - _MAN_PATH="$(get_first_essential \ - "${_OPT_MANPATH}" "${_MANOPT_PATH}" "${MANPATH}")"; - if obj _MAN_PATH is_empty; then - manpath_set_from_path; - else - _MAN_PATH="$(path_clean "${_MAN_PATH}")"; - fi; - if obj _MAN_PATH is_empty; then - if is_prog 'manpath'; then - _MAN_PATH="$(manpath 2>/dev/null)"; # not always available - fi; - fi; - if obj _MAN_PATH is_empty; then - _MAN_ENABLE="no"; - eval "${return_ok}"; - fi; - - _MAN_ALL="$(get_first_essential "${_OPT_ALL}" "${_MANOPT_ALL}")"; - if obj _MAN_ALL is_empty; then - _MAN_ALL='no'; - fi; - - _MAN_SYS="$(get_first_essential \ - "${_OPT_SYSTEMS}" "${_MANOPT_SYS}" "${SYSTEM}")"; - _lang="$(get_first_essential \ - "${_OPT_LANG}" "${LC_ALL}" "${LC_MESSAGES}" "${LANG}")"; - case "${_lang}" in - C|POSIX) - _MAN_LANG=""; - _MAN_LANG2=""; - ;; - ?) - _MAN_LANG="${_lang}"; - _MAN_LANG2=""; - ;; - *) - _MAN_LANG="${_lang}"; - # get first two characters of $_lang - _MAN_LANG2="$(echo -n "${_lang}" | sed -e 's/^\(..\).*$/\1/')"; - ;; - esac; - # from now on, use only $_LANG, forget about $_OPT_LANG, $LC_*. - - manpath_add_lang_sys; # this is very slow - - _MAN_SEC="$(get_first_essential \ - "${_OPT_SECT}" "${_MANOPT_SEC}" "${MANSEC}")"; - if obj _MAN_PATH is_empty; then - _MAN_ENABLE="no"; - 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. -# -# Arguments : 0 -# Output : none -# Globals: -# in: $_MAN_SYS: has the form `os1,os2,...', a comma separated -# list of names of operating systems. -# $_MAN_LANG and $_MAN_LANG2: each a single name -# in/out: $_MAN_PATH: has the form `dir1:dir2:...', a colon -# separated list of directories. -# -manpath_add_lang_sys() -{ - func_check manpath_add_lang_sys = 0 "$@"; - local p; - local _mp; - if obj _MAN_PATH is_empty; then - eval "${return_ok}"; - fi; - # twice test both sys and lang - eval set -- "$(path_split "${_MAN_PATH}")"; - _mp=''; - for p in "$@"; do # loop on man path directories - _mp="$(_manpath_add_lang_sys_single "${_mp}" "$p")"; - done; - eval set -- "$(path_split "${_mp}")"; - for p in "$@"; do # loop on man path directories - _mp="$(_manpath_add_lang_sys_single "${_mp}" "$p")"; - done; - _MAN_PATH="$(path_chop "${_mp}")"; - eval "${return_ok}"; -} - - -_manpath_add_lang_sys_single() -{ - # To the directory in $1 append existing sys/lang subdirectories - # Function is necessary to split the OS list. - # - # globals: in: $_MAN_SYS, $_MAN_LANG, $_MAN_LANG2 - # argument: 2: `man_path' and `dir' - # output: colon-separated path of the retrieved subdirectories - # - func_check _manpath_add_lang_sys_single = 2 "$@"; - local d; - _res="$1"; - _parent="$2"; - eval set -- "$(list_from_split "${_MAN_SYS}" ',')"; - for d in "$@" "${_MAN_LANG}" "${_MAN_LANG2}"; do - _dir="$(dirname_append "${_parent}" "$d")"; - if obj _res path_not_contains "${_dir}" && obj _dir is_dir; then - _res="${_res}:${_dir}"; - fi; - done; - if path_not_contains "${_res}" "${_parent}"; then - _res="${_res}:${_parent}"; - fi; - path_chop "${_res}"; -} - -# end manpath_add_lang_sys () - - -######################################################################## -# manpath_set_from_path () -# -# Determine basic search path for man pages from $PATH. -# -# Return: `0' if a valid man path was retrieved. -# Output: none -# Globals: -# in: $PATH -# out: $_MAN_PATH -# -manpath_set_from_path() -{ - func_check manpath_set_from_path = 0 "$@"; - local _base; - local _mandir; - local _manpath; - local d; - local e; - _manpath=''; - - # get a basic man path from $PATH - if obj PATH is_not_empty; then - eval set -- "$(path_split "${PATH}")"; - for d in "$@"; do - # delete the final `/bin' part - _base="$(echo -n "$d" | sed -e '\|.*|s|//*bin/*$||')"; - for e in /share/man /man; do - _mandir="${_base}$e"; - if test -d "${_mandir}" && test -r "${_mandir}"; then - _manpath="${_manpath}:${_mandir}"; - fi; - done; - done; - fi; - - # append some default directories - for d in /usr/local/share/man /usr/local/man \ - /usr/share/man /usr/man \ - /usr/X11R6/man /usr/openwin/man \ - /opt/share/man /opt/man \ - /opt/gnome/man /opt/kde/man; do - if obj _manpath path_not_contains "$d" && obj d is_dir; then - _manpath="${_manpath}:$d"; - fi; - done; - - _MAN_PATH="${_manpath}"; - eval "${return_ok}"; -} # manpath_set_from_path() - - -######################################################################## -landmark '9: obj_*()'; -######################################################################## - -######################################################################## -# obj ( ...) -# -# This works like a method (object function) call for an object. -# Run " $ ...". -# -# The first argument represents an object whose data is given as first -# argument to (). -# -# Argument: >=2 -# : variable name -# : a program or function name -# -obj() -{ - func_check obj '>=' 2 "$@"; - local func; - local var; - if is_empty "$2"; then - error "obj(): function name is empty." - else - func="$2"; - fi; - eval arg1='"${'$1'}"'; - shift; - shift; - eval "${func}"' "${arg1}" "$@"'; -} - - -######################################################################## -# obj_data () -# -# Print the data of , i.e. the content of $. -# For possible later extensions. -# -# Arguments: 1 -# : a variable name -# Output: the data of -# -obj_data() -{ - func_check obj '=' 1 "$@"; - if is_empty "$1"; then - error "obj_data(): object name is empty." - fi; - eval echo -n '"${'$1'}"'; -} - - -######################################################################## -# obj_from_output ( ...) -# -# Run '$="$( ...)"' to set the result of a -# function call to a global variable. -# -# Arguments: >=2 -# : a variable name -# : the name of a function or program -# : optional argument to -# Output: none -# -obj_from_output() -{ - func_check obj_from_output '>=' 2 "$@"; - local result_name; - if is_empty "$1"; then - error "res(): variable name is empty."; - elif is_empty "$2"; then - error "res(): function name is empty." - else - result_name="$1"; - fi; - shift; - eval "${result_name}"'="$('"$@"')"'; -} - - -######################################################################## -# obj_set ( ) -# -# Set the data of , i.e. call "$=". -# -# Arguments: 2 -# : a variable name -# : a string -# Output:: none -# -obj_set() -{ - func_check obj_set '=' 2 "$@"; - if is_empty "$1"; then - error "obj_set(): object name is empty." - fi; - eval "$1"='"$2"'; -} - - -######################################################################## -# path_chop () -# -# Remove unnecessary colons from path. -# -# Argument: 1, a colon separated path. -# Output: path without leading, double, or trailing colons. -# -path_chop() -{ - func_check path_chop = 1 "$@"; - local _res; - - # replace multiple colons by a single colon `:' - # remove leading and trailing colons - echo -n "$1" | sed -e 's/:::*/:/g' | - sed -e 's/^:*//' | - sed -e 's/:*$//'; - eval "${return_ok}"; -} - - -######################################################################## -# path_clean () -# -# Remove non-existing directories from a colon-separated list. -# -# Argument: 1, a colon separated path. -# Output: colon-separated list of existing directories. -# -path_clean() -{ - func_check path_clean = 1 "$@"; - local _arg; - local _dir; - local _res; - local i; - if is_not_equal "$#" 1; then - error 'path_clean() needs 1 argument.'; - fi; - _arg="$1"; - eval set -- "$(path_split "${_arg}")"; - _res=""; - for i in "$@"; do - if obj i is_not_empty \ - && obj _res path_not_contains "$i" \ - && obj i is_dir; - then - case "$i" in - ?*/) _res="${_res}$(dirname_chop "$i")"; ;; - *) _res="${_res}:$i"; - esac; - fi; - done; - if path_chop "${_res}"; then - eval "${return_ok}"; - else - eval "${return_badk}"; - fi; -} - - -######################################################################## -# path_contains ( ) -#- -# Test whether `dir' is contained in `path', a list separated by `:'. -# -# Arguments : 2 arguments. -# Return : `0' if arg2 is substring of arg1, `1' otherwise. -# -path_contains() -{ - func_check path_contains = 2 "$@"; - case ":$1:" in - *":$2:"*) - eval "${return_yes}"; - ;; - *) - eval "${return_no}"; - ;; - esac; - eval "${return_ok}"; -} - - -######################################################################## -# path_not_contains ( ) -#- -# Test whether `dir' is not contained in colon separated `path'. -# -# Arguments : 2 arguments. -# -path_not_contains() -{ - func_check path_not_contains = 2 "$@"; - if path_contains "$1" "$2"; then - eval "${return_no}"; - else - eval "${return_yes}"; - fi; - eval "${return_ok}"; -} - - -######################################################################## -# path_split () -# -# In `path' escape white space and replace each colon by a space. -# -# Arguments: 1: a colon-separated path -# Output: the resulting list, process with `eval set --' -# -path_split() -{ - func_check path_split = 1 "$@"; - list_from_split "$1" ':'; - eval "${return_ok}"; -} - - -######################################################################## -landmark '10: register_*()'; -######################################################################## - -######################################################################## -# register_file () -# -# Write a found file and register the title element. -# -# Arguments: 1: a file name -# Output: none -# -register_file() -{ - func_check register_file = 1 "$@"; - if is_empty "$1"; then - error 'register_file(): file name is empty'; - fi; - if is_equal "$1" '-'; then - to_tmp "${_TMP_STDIN}"; - register_title '-'; - else - to_tmp "$1"; - register_title "$(base_name "$1")"; - fi; - eval "${return_ok}"; -} - - -######################################################################## -# register_title () -# -# Create title element from and append to $_REGISTERED_TITLE -# -# Globals: $_REGISTERED_TITLE (rw) -# -register_title() -{ - func_check register_title = 1 "$@"; - local _title; - if is_empty "$1"; then - eval "${return_ok}"; - fi; - _title="$(base_name "$1")"; # remove directory part - - # remove extension `.gz' - _title="$(echo -n "${_title}" | sed -e 's/\.gz$//')"; - # remove extension `.Z' - _title="$(echo -n "${_title}" | sed -e 's/\.Z$//')"; - - if obj _title is_empty; then - eval "${return_ok}"; - fi; - _REGISTERED_TITLE="${_REGISTERED_TITLE} ${_title}"; - 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. - - -######################################################################## -# save_stdin () -# -# Store standard input to temporary file (with decompression). -# -if obj _HAS_COMPRESSION is_yes; then - save_stdin() - { - local _f; - func_check save_stdin = 0 "$@"; - _f="${_TMP_DIR}"/INPUT; - cat >"${_f}"; - catz "${_f}" >"${_TMP_STDIN}"; - rm -f "${_f}"; - eval "${return_ok}"; - } -else - save_stdin() - { - func_check save_stdin = 0 "$@"; - cat >"${_TMP_STDIN}"; - eval "${return_ok}"; - } -fi; - - -######################################################################## -landmark '11: stack_*()'; -######################################################################## - -######################################################################## -# string_contains ( ) -# -# Test whether `part' is contained in `string'. -# -# Arguments : 2 text arguments. -# Return : `0' if arg2 is substring of arg1, `1' otherwise. -# -string_contains() -{ - func_check string_contains = 2 "$@"; - case "$1" in - *"$2"*) - eval "${return_yes}"; - ;; - *) - eval "${return_no}"; - ;; - esac; - eval "${return_ok}"; -} - - -######################################################################## -# string_not_contains ( ) -# -# Test whether `part' is not substring of `string'. -# -# Arguments : 2 text arguments. -# Return : `0' if arg2 is substring of arg1, `1' otherwise. -# -string_not_contains() -{ - func_check string_not_contains = 2 "$@"; - if string_contains "$1" "$2"; then - eval "${return_no}"; - else - eval "${return_yes}"; - fi; - eval "${return_ok}"; -} - - -######################################################################## -landmark '12: tmp_*()'; -######################################################################## - -######################################################################## -# tmp_cat () -# -# output the temporary cat file (the concatenation of all input) -# -tmp_cat() -{ - cat "${_TMP_CAT}"; -} - - -######################################################################## -# tmp_create (?) -# -# create temporary file -# -# It's safe to use the shell process ID together with a suffix to -# have multiple temporary files. -# -# Output : name of created file -# -tmp_create() -{ - func_check tmp_create '<=' 1 "$@"; - local _tmp; - # the output file does not have `,' as first character - _tmp="${_TMP_DIR}/,$1"; - echo -n >"${_tmp}"; - echo -n "${_tmp}"; # output file name - eval "${return_ok}"; -} - - -######################################################################## -# to_tmp () -# -# print file (decompressed) to the temporary cat file -# -to_tmp() -{ - func_check to_tmp = 1 "$@"; - if is_file "$1"; then - if obj _OPT_LOCATION is_yes; then - echo2 "$1"; - fi; - if obj _OPT_WHATIS is_yes; then - what_is "$1" >>"${_TMP_CAT}"; - else - catz "$1" >>"${_TMP_CAT}"; - fi; - else - error "to_tmp(): could not read file \`$1'."; - fi; - eval "${return_ok}"; -} - - -######################################################################## -# trap_clean () -# -# disable trap on all exit codes ($_ALL_EXIT) -# -# Arguments: 0 -# Globals: $_ALL_EXIT -# -trap_clean() -{ - func_check trap_clean = 0 "$@"; - local i; - for i in ${_ALL_EXIT}; do - trap "" "$i" 2>/dev/null || true; - done; - eval "${return_ok}"; -} - - -######################################################################## -# trap_set () -# -# call function on all exit codes ($_ALL_EXIT) -# -# Arguments: 1 (name of a shell function) -# Globals: $_ALL_EXIT -# -trap_set() -{ - func_check trap_set = 1 "$@"; - local i; - for i in ${_ALL_EXIT}; do - trap "$1" "$i" 2>/dev/null || true; - done; - eval "${return_ok}"; -} - - -######################################################################## -# usage () -# -# print usage information to stderr; for groffer option --help. -# -usage() -{ - func_check usage = 0 "$@"; - echo; - version; - echo 'Usage: '"${_PROGRAM_NAME}"' [option]... [filespec]...'; - cat <&1 | sed -e '/^ *$/q' | sed -e '1s/^/is part of /' >&2; -} - - -######################################################################## -# warning () -# -# Print warning to stderr -# -warning() -{ - echo2 "warning: $*"; -} - - -######################################################################## -# what_is () -# -# Interpret as a man page and display its `whatis' -# information as a fragment written in the groff language. -# -what_is() -{ - func_check what_is = 1 "$@"; - local _res; - local _dot; - if is_not_file "$1"; then - error "what_is(): argument is not a readable file." - fi; - _dot='^\.['"${_SPACE}${_TAB}"']*'; - echo '.br'; - echo "$1: "; - echo '.br'; - echo -n ' '; - # grep the line containing `.TH' macro, if any - _res="$(catz "$1" | sed -e '/'"${_dot}"'TH /p -d')"; - if obj _res is_not_empty; then # traditional man style - # get the text between the first and the second `.SH' macro, by - # - delete up to first .SH; - # - of this, print everything up to next .SH, and delete the rest; - # - of this, delete the final .SH line; - catz "$1" | sed -e '1,/'"${_dot}"'SH/d' \ - | sed -e '1,/'"${_dot}"'SH/p -d' \ - | sed -e '/'"${_dot}"'SH/d'; - eval "${return_ok}"; - fi; - # grep the line containing `.Dd' macro, if any - _res="$(catz "$1" | sed -e '/'"${_dot}"'Dd /p -d')"; - if obj _res is_not_empty; then # BSD doc style - # get the text between the first and the second `.Nd' macro, by - # - delete up to first .Nd; - # - of this, print everything up to next .Nd, and delete the rest; - # - of this, delete the final .Nd line; - catz "$1" | sed -e '1,/'"${_dot}"'Nd/d' \ - | sed -e '1,/'"${_dot}"'Nd/p -d' \ - | sed -e '/'"${_dot}"'Nd/d'; - eval "${return_ok}"; - fi; - echo 'is not a man page.'; - eval "${return_bad}"; -} - - -######################################################################## -# where () -# -# Output path of a program if in $PATH. -# -# 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; - _arg="$1"; - if obj _arg is_empty; then - eval "${return_bad}"; - fi; - case "${_arg}" in - /*) - if test -f "${_arg}" && test -x "${_arg}"; then - eval "${return_ok}"; - else - eval "${return_bad}"; - fi; - ;; - esac; - eval set -- "$(path_split "${PATH}")"; - for p in "$@"; do - case "$p" in - */) _file=${p}${_arg}; ;; - *) _file=${p}/${_arg}; ;; - esac; - if test -f "${_file}" && test -x "${_file}"; then - echo -n "${_file}"; - eval "${return_ok}"; - fi; - done; - eval "${return_bad}"; -} - - -######################################################################## -# main -######################################################################## - -# 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 -# - process filespec arguments -# - setup X resources -# - do the displaying - -# These parts are implemented as functions, being defined below in the -# sequence they are called in the main() function. - - -####################################################################### -# main_init () -# -# set exit trap and create temporary files -# -# Globals: $_TMP_CAT, $_TMP_STDIN -# -landmark '13: main_init()'; -main_init() -{ - func_check main_init = 0 "$@"; - # call clean_up() on any signal - trap_set clean_up; - - # determine temporary directory - umask 000; - _TMP_DIR=''; - for d in "${GROFF_TMPDIR}" "${TMPDIR}" "${TMP}" "${TEMP}" \ - "${TEMPDIR}" "${HOME}"'/tmp' '/tmp' "${HOME}" '.'; - do - if is_not_empty "$d"; then - if obj d is_dir && obj d is_writable; then - _TMP_DIR="${d}/${_PROGRAM_NAME}${_PROCESS_ID}"; - if obj _TMP_DIR is_dir; then - rm -f "${_TMP_DIR}"/*; - break; - else - mkdir "${_TMP_DIR}"; - if obj _TMP_DIR is_not_dir; then - _TMP_DIR=''; - continue; - fi; - break; - fi; - fi; - if obj _TMP_DIR is_not_writable; then - _TMP_DIR=''; - continue; - fi; - fi; - done; - unset d; - if obj _TMP_DIR is_empty; then - error "Couldn't create a directory for storing temporary files."; - fi; - - _TMP_CAT="$(tmp_create groffer_cat)"; - _TMP_STDIN="$(tmp_create groffer_input)"; - - # groffer configuration files - for f in ${_CONFFILES}; do - if obj f is_file; then - echo '_groffer_opt=""' >>${_TMP_CAT}; - # collect the lines starting with a minus - cat "$f" | sed -e \ - 's/^[ ]*\(-.*\)$/_groffer_opt="${_groffer_opt} \1"'/ \ - >>${_TMP_CAT}; - # prepend the collected information to $GROFFER_OPT - echo 'GROFFER_OPT="${_groffer_opt} ${GROFFER_OPT}"' >>${_TMP_CAT}; - fi; - done; - . "${_TMP_CAT}"; - _TMP_CAT="$(tmp_create groffer_cat)"; - - eval "${return_ok}"; -} # main_init() - - -######################################################################## -# main_parse_MANOPT () -# -# Parse $MANOPT to retrieve man options, but only if it is a non-empty -# string; found man arguments can be overwritten by the command line. -# -# Globals: -# in: $MANOPT, $_OPTS_MANOPT_* -# out: $_MANOPT_* -# in/out: $GROFFER_OPT -# -landmark '14: main_parse_MANOPT()'; -main_parse_MANOPT() -{ - func_check main_parse_MANOPT = 0 "$@"; - local _opt; - local _list; - _list=''; - if obj MANOPT is_not_empty; then - MANOPT="$(echo -n "${MANOPT}" | \ - sed -e 's/^'"${_SPACE}${_SPACE}"'*//')"; - fi; - if obj MANOPT is_empty; then - eval "${return_ok}"; - fi; - # add arguments in $MANOPT by mapping them to groffer options - eval set -- "$(list_from_cmdline _OPTS_MANOPT "${MANOPT}")"; - until test "$#" -le 0 || is_equal "$1" '--'; do - _opt="$1"; - shift; - case "${_opt}" in - -7|--ascii) - list_append _list '--ascii'; - ;; - -a|--all) - list_append _list '--all'; - ;; - -c|--catman) - do_nothing; - shift; - ;; - -d|--debug) - list_append _list '--debug'; - ;; - -D|--default) - # undo all man options so far - _list=''; - ;; - -e|--extension) - list_append _list '--extension'; - shift; - ;; - -f|--whatis) - list_append _list '--whatis'; - shift; - ;; - -h|--help) - do_nothing; - shift; - ;; - -k|--apropos) - # groffer's --apropos takes an argument, but man's does not, so - do_nothing; - shift; - ;; - -l|--local-file) - list_append _list '--local-file'; - ;; - -L|--locale) - list_append _list '--locale' "$1"; - shift; - ;; - -m|--systems) - list_append _list '--systems' "$1"; - shift; - ;; - -M|--manpath) - list_append _list '--manpath' "$1"; - shift; - ;; - -p|--preprocessor) - do_nothing; - shift; - ;; - -P|--pager|--tty-viewer) - list_append _list '--pager' "$1"; - shift; - ;; - -r|--prompt) - do_nothing; - shift; - ;; - -S|--sections) - list_append _list '--sections' "$1"; - shift; - ;; - -t|--troff) - do_nothing; - shift; - ;; - -T|--device) - list_append _list '-T' "$1"; - shift; - ;; - -u|--update) - do_nothing; - shift; - ;; - -V|--version) - do_nothing; - ;; - -w|--where|--location) - list_append _list '--location'; - ;; - -Z|--ditroff) - list_append _list '-Z' "$1"; - shift; - ;; - # ignore all other options - esac; - done; - # append the 2 lists in $_list and $GROFFER_OPT to $GROFFER_OPT - if obj GROFFER_OPT is_empty; then - GROFFER_OPT="${_list}"; - elif obj _list is_not_empty; then - GROFFER_OPT="${_list} ${GROFFER_OPT}"; - fi; - 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 "$@")"; - -# 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"; - _check_device_with_mode; - shift; - ;; - -v|--version) - version; - leave; - ;; - -V) - _OPT_V='yes'; - ;; - -Z|--ditroff|--intermediate-output) # groff intermediate output - _OPT_Z='yes'; - ;; - -X|--X|--x) - _OPT_MODE=x; - ;; - -?) - # delete leading `-' - _optchar="$(echo -n "${_opt}" | sed -e 's/^.//')"; - if list_has _OPTS_GROFF_SHORT_NA "${_optchar}"; - then - list_append _ADDOPTS_GROFF "${_opt}"; - elif list_has _OPTS_GROFF_SHORT_ARG "${_optchar}"; - then - list_append _ADDOPTS_GROFF "${_opt}" "$1"; - shift; - else - error "Unknown option : \`$1'"; - fi; - ;; - --all) - _OPT_ALL="yes"; - ;; - --apropos) # run `apropos' - apropos_run "$1"; - _code="$?"; - clean_up; - exit "${_code}"; - ;; - --apropos-data) # run `apropos' for data sections - apropos_run "$1" | grep '^[^(]*([457][^)]*)'; - _code="$?"; - clean_up; - exit "${_code}"; - ;; - --apropos-devel) # run `apropos' for development sections - apropos_run "$1" | grep '^[^(]*([239][^)]*)'; - _code="$?"; - clean_up; - exit "${_code}"; - ;; - --apropos-progs) # run `apropos' for program sections - apropos_run "$1" | grep '^[^(]*([168][^)]*)'; - _code="$?"; - clean_up; - exit "${_code}"; - ;; - --ascii) - list_append _ADDOPTS_GROFF '-mtty-char'; - if obj _mode is_empty; then - _mode='text'; - fi; - ;; - --auto) # the default automatic mode - _mode=''; - ;; - --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; - ;; - --default) # reset variables to default - reset; - ;; - --default-modes) # sequence of modes in auto mode; arg - _OPT_DEFAULT_MODES="$1"; - shift; - ;; - --debug) # buggy, only for development - _OPT_DEBUG='yes'; - ;; - --display) # set X display, arg - _OPT_DISPLAY="$1"; - shift; - ;; - --dvi) - _OPT_MODE='dvi'; - ;; - --dvi-viewer) # viewer program for dvi mode; arg - _OPT_VIEWER_DVI="$1"; - shift; - ;; - --extension) # the extension for man pages, arg - _OPT_EXTENSION="$1"; - shift; - ;; - --fg|--foreground) # foreground color for viewers, arg; - _OPT_FG="$1"; - shift; - ;; - --fn|--font) # set font for viewers, arg; - _OPT_FN="$1"; - shift; - ;; - --geometry) # window geometry for viewers, arg; - _OPT_GEOMETRY="$1"; - shift; - ;; - --groff) - _OPT_MODE='groff'; - ;; - --html|--www) # display with web browser - _OPT_MODE=html; - ;; - --html-viewer|--www-viewer) # viewer program for html mode; arg - _OPT_VIEWER_HTML="$1"; - shift; - ;; - --iconic) # start viewers as icons - _OPT_ICONIC='yes'; - ;; - --locale) # set language for man pages, arg - # argument is xx[_territory[.codeset[@modifier]]] (ISO 639,...) - _OPT_LANG="$1"; - shift; - ;; - --local-file) # force local files; same as `--no-man' - _MAN_FORCE='no'; - _MAN_ENABLE='no'; - ;; - --location|--where) # print file locations to stderr - _OPT_LOCATION='yes'; - ;; - --man) # force all file params to be man pages - _MAN_ENABLE='yes'; - _MAN_FORCE='yes'; - ;; - --manpath) # specify search path for man pages, arg - # arg is colon-separated list of directories - _OPT_MANPATH="$1"; - shift; - ;; - --mode) # display mode - _arg="$1"; - shift; - case "${_arg}" in - auto|'') # search mode automatically among default - _mode=''; - ;; - groff) # pass input to plain groff - _mode='groff'; - ;; - html|www) # display with a web browser - _mode='html'; - ;; - dvi) # display with xdvi viewer - _mode='dvi'; - ;; - pdf) # display with PDF viewer - _mode='pdf'; - ;; - ps) # display with Postscript viewer - _mode='ps'; - ;; - text) # output on terminal - _mode='text'; - ;; - tty) # output on terminal - _mode='tty'; - ;; - X|x) # output on X roff viewer - _mode='x'; - ;; - Q|source) # display source code - _mode="source"; - ;; - *) - error "unknown mode ${_arg}"; - ;; - esac; - _OPT_MODE="${_mode}"; - ;; - --no-location) # disable former call to `--location' - _OPT_LOCATION='yes'; - ;; - --no-man) # disable search for man pages - # the same as --local-file - _MAN_FORCE="no"; - _MAN_ENABLE="no"; - ;; - --pager) # set paging program for tty mode, arg - _OPT_PAGER="$1"; - shift; - ;; - --pdf) - _OPT_MODE='pdf'; - ;; - --pdf-viewer) # viewer program for ps mode; arg - _OPT_VIEWER_PDF="$1"; - shift; - ;; - --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; - 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 - _OPT_SECTIONS="$1"; - shift; - ;; - --shell) - # already done during the first run; so ignore the argument - shift; - ;; - --systems) # man pages for different OS's, arg - # argument is a comma-separated list - _OPT_SYSTEMS="$1"; - shift; - ;; - --text) # text mode without pager - _OPT_MODE=text; - ;; - --title) # title for X viewers; arg - _OPT_TITLE="$1"; - shift; - ;; - --tty) # tty mode, text with pager - _OPT_MODE=tty; - ;; - --text-device|--tty-device) # device for tty mode; arg - _OPT_TEXT_DEVICE="$1"; - shift; - ;; - --whatis) - _OPT_WHATIS='yes'; - ;; - --xrm) # pass X resource string, arg; - list_append _OPT_XRM "$1"; - shift; - ;; - --x-viewer|--X-viewer) # viewer program for x mode; arg - _OPT_VIEWER_X="$1"; - shift; - ;; - *) - error 'error on argument parsing : '"\`$*'"; - ;; - esac; - done; - shift; # remove `--' argument - - if obj _DEBUG is_not_yes; then - if obj _OPT_DEBUG is_yes; then - _DEBUG='yes'; - fi; - fi; - - # Remaining arguments are file names (filespecs). - # Save them to list $_FILEARGS - if is_equal "$#" 0; then # use "-" for standard input - set -- '-'; - fi; - _FILEARGS=''; - list_append _FILEARGS "$@"; - if list_has _FILEARGS '-'; then - save_stdin; - fi; - # $_FILEARGS must be retrieved with `eval set -- "$_FILEARGS"' - eval "${return_ok}"; -} # main_parse_args() - -# Called from main_parse_args() because double `case' is not possible. -# Globals: $_OPT_DEVICE, $_OPT_MODE -_check_device_with_mode() -{ - func_check _check_device_with_mode = 0 "$@"; - case "${_OPT_DEVICE}" in - dvi) - _OPT_MODE=dvi; - eval "${return_ok}"; - ;; - html) - _OPT_MODE=html; - eval "${return_ok}"; - ;; - lbp|lj4) - _OPT_MODE=groff; - eval "${return_ok}"; - ;; - ps) - _OPT_MODE=ps; - eval "${return_ok}"; - ;; - ascii|cp1047|latin1|utf8) - if obj _OPT_MODE is_not_equal text; then - _OPT_MODE=tty; # default text mode - fi; - eval "${return_ok}"; - ;; - X*) - _OPT_MODE=x; - eval "${return_ok}"; - ;; - *) # unknown device, go to groff mode - _OPT_MODE=groff; - eval "${return_ok}"; - ;; - esac; - eval "${return_error}"; -} - - -######################################################################## -# main_set_mode () -# -# Determine the display mode. -# -# Globals: -# 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 obj _OPT_APROPOS is_not_empty; then - apropos "${_OPT_APROPOS}"; - _code="$?"; - clean_up; - exit "${_code}"; - fi; - if obj _OPT_APROPOS_DATA is_not_empty; then - apropos "$@" | grep '^[^(]*([457])'; - _code="$?"; - clean_up; - exit "${_code}"; - fi; - if obj _OPT_APROPOS_DEVEL is_not_empty; then - apropos "$@" | grep '^[^(]*([239])'; - _code="$?"; - clean_up; - exit "${_code}"; - fi; - if obj _OPT_APROPOS_PROGS is_not_empty; then - apropos "$@" | grep '^[^(]*([168])'; - _code="$?"; - clean_up; - exit "${_code}"; - fi; - - # set display - if obj _OPT_DISPLAY is_not_empty; then - DISPLAY="${_OPT_DISPLAY}"; - fi; - - if obj _OPT_V is_yes; then - _DISPLAY_MODE='groff'; - list_append _ADDOPTS_GROFF '-V'; - fi; - if obj _OPT_Z is_yes; then - _DISPLAY_MODE='groff'; - list_append _ADDOPTS_GROFF '-Z'; - fi; - if obj _OPT_MODE is_equal 'groff'; then - _DISPLAY_MODE='groff'; - fi; - if obj _DISPLAY_MODE is_equal 'groff'; then - eval "${return_ok}"; - fi; - - if obj _OPT_MODE is_equal 'source'; then - _DISPLAY_MODE='source'; - eval "${return_ok}"; - fi; - - case "${_OPT_MODE}" in - '') # automatic mode - case "${_OPT_DEVICE}" in - X*) - if obj DISPLAY is_empty; then - error "no X display found for device ${_OPT_DEVICE}"; - fi; - _DISPLAY_MODE='x'; - eval "${return_ok}"; - ;; - ascii|cp1047|latin1|utf8) - if obj _DISPLAY_MODE is_not_equal 'text'; then - _DISPLAY_MODE='tty'; - fi; - eval "${return_ok}"; - ;; - esac; - if obj DISPLAY is_empty; then - _DISPLAY_MODE='tty'; - eval "${return_ok}"; - fi; - - if obj _OPT_DEFAULT_MODES is_empty; then - _modes="${_DEFAULT_MODES}"; - else - _modes="${_OPT_DEFAULT_MODES}"; - fi; - ;; - text) - _DISPLAY_MODE='text'; - eval "${return_ok}"; - ;; - tty) - _DISPLAY_MODE='tty'; - eval "${return_ok}"; - ;; - *) # display mode was given - if obj DISPLAY is_empty; then - error "you must be in X Window for ${_OPT_MODE} mode."; - fi; - _modes="${_OPT_MODE}"; - ;; - esac; - - # only viewer modes are left - eval set -- "$(list_from_split "${_modes}" ',')"; - while test "$#" -gt 0; do - m="$1"; - shift; - case "$m" in - text) - _DISPLAY_MODE='text'; - eval "${return_ok}"; - ;; - tty) - _DISPLAY_MODE='tty'; - eval "${return_ok}"; - ;; - x) - if obj _OPT_VIEWER_X is_not_empty; then - _viewers="${_OPT_VIEWER_X}"; - else - _viewers="${_VIEWER_X}"; - fi; - _viewer="$(_get_first_prog "${_viewers}")"; - if is_not_equal "$?" 0; then - continue; - fi; - _DISPLAY_PROG="${_viewer}"; - _DISPLAY_MODE='x'; - eval "${return_ok}"; - ;; - dvi) - if obj _OPT_VIEWER_DVI is_not_empty; then - _viewers="${_OPT_VIEWER_DVI}"; - else - _viewers="${_VIEWER_DVI}"; - fi; - _viewer="$(_get_first_prog "${_viewers}")"; - if is_not_equal "$?" 0; then - continue; - fi; - _DISPLAY_PROG="${_viewer}"; - _DISPLAY_MODE="dvi"; - eval "${return_ok}"; - ;; - pdf) - if obj _OPT_VIEWER_PDF is_not_empty; then - _viewers="${_OPT_VIEWER_PDF}"; - else - _viewers="${_VIEWER_PDF}"; - fi; - _viewer="$(_get_first_prog "${_viewers}")"; - if is_not_equal "$?" 0; then - continue; - fi; - _DISPLAY_PROG="${_viewer}"; - _DISPLAY_MODE="pdf"; - eval "${return_ok}"; - ;; - ps) - if obj _OPT_VIEWER_PS is_not_empty; then - _viewers="${_OPT_VIEWER_PS}"; - else - _viewers="${_VIEWER_PS}"; - fi; - _viewer="$(_get_first_prog "${_viewers}")"; - if is_not_equal "$?" 0; then - continue; - fi; - _DISPLAY_PROG="${_viewer}"; - _DISPLAY_MODE="ps"; - eval "${return_ok}"; - ;; - html) - if obj _OPT_VIEWER_HTML is_not_empty; then - _viewers="${_OPT_VIEWER_HTML}"; - else - _viewers="${_VIEWER_HTML}"; - fi; - _viewer="$(_get_first_prog "${_viewers}")"; - if is_not_equal "$?" 0; then - continue; - fi; - _DISPLAY_PROG="${_viewer}"; - _DISPLAY_MODE=html; - eval "${return_ok}"; - ;; - esac; - done; - error "no suitable display mode found."; -} - -_get_first_prog() -{ - local i; - if is_equal "$#" 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 obj i is_empty; 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 () -# -# Process filespec arguments in $_FILEARGS. -# -# 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; - _exitcode="${_BAD}"; - eval set -- "${_FILEARGS}"; - unset _FILEARGS; - # temporary storage of all input to $_TMP_CAT - while test "$#" -ge 2; do - # test for `s name' arguments, with `s' a 1-char standard section - _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; - continue; - fi; - _name="$1"; - case "${_name}" in - */*|man:*|*\(*\)|*."${_filespec}") - if do_filearg "${_filespec}"; then - _exitcode="${_GOOD}"; - fi; - continue; - ;; - esac; - if do_filearg "man:${_name}(${_filespec})"; then - _exitcode="${_GOOD}"; - shift; - continue; - else - if do_filearg "${_filespec}"; then - _exitcode="${_GOOD}"; - fi; - 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; - rm -f "${_TMP_STDIN}"; - 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. -# -# Globals: $_DISPLAY_PROG, $_OUTPUT_FILE_NAME -# -landmark '18: main_set_resources()'; -main_set_resources() -{ - func_check main_set_resources = 0 "$@"; - local _prog; # viewer program - local _rl; # resource list - local n; - _title="$(get_first_essential \ - "${_OPT_TITLE}" "${_REGISTERED_TITLE}")"; - _OUTPUT_FILE_NAME=''; - set -- ${_title}; - until is_equal "$#" 0; do - n="$1"; - case "$n" in - '') - continue; - ;; - ,*) - n="$(echo -n "$1" | sed -e 's/^,,*//')"; - ;; - esac - if obj n is_empty; then - continue; - fi; - if obj _OUTPUT_FILE_NAME is_not_empty; then - _OUTPUT_FILE_NAME="${_OUTPUT_FILE_NAME},"; - fi; - _OUTPUT_FILE_NAME="${_OUTPUT_FILE_NAME}$n"; - shift; - done; - case "${_OUTPUT_FILE_NAME}" in - '') - _OUTPUT_FILE_NAME='-'; - ;; - ,*) - error "$_OUTPUT_FILE_NAME starts with a comma."; - ;; - esac; - _OUTPUT_FILE_NAME="${_TMP_DIR}/${_OUTPUT_FILE_NAME}"; - - if obj _DISPLAY_PROG is_empty; then # for example, for groff mode - _DISPLAY_ARGS=''; - eval "${return_ok}"; - fi; - - set -- ${_DISPLAY_PROG}; - _prog="$(base_name "$1")"; - _rl=''; - if obj _OPT_BD is_not_empty; then - case "${_prog}" in - ghostview|gv|gxditview|xditview|xdvi) - list_append _rl '-bd' "${_OPT_BD}"; - ;; - esac; - fi; - if obj _OPT_BG is_not_empty; then - case "${_prog}" in - ghostview|gv|gxditview|xditview|xdvi) - list_append _rl '-bg' "${_OPT_BG}"; - ;; - xpdf) - list_append _rl '-papercolor' "${_OPT_BG}"; - ;; - esac; - fi; - if obj _OPT_BW is_not_empty; then - case "${_prog}" in - ghostview|gv|gxditview|xditview|xdvi) - _list_append _rl '-bw' "${_OPT_BW}"; - ;; - esac; - fi; - if obj _OPT_FG is_not_empty; then - case "${_prog}" in - ghostview|gv|gxditview|xditview|xdvi) - list_append _rl '-fg' "${_OPT_FG}"; - ;; - esac; - fi; - if is_not_empty "${_OPT_FN}"; then - case "${_prog}" in - ghostview|gv|gxditview|xditview|xdvi) - list_append _rl '-fn' "${_OPT_FN}"; - ;; - esac; - fi; - if is_not_empty "${_OPT_GEOMETRY}"; then - case "${_prog}" in - ghostview|gv|gxditview|xditview|xdvi|xpdf) - list_append _rl '-geometry' "${_OPT_GEOMETRY}"; - ;; - esac; - fi; - if is_empty "${_OPT_RESOLUTION}"; then - _OPT_RESOLUTION="${_DEFAULT_RESOLUTION}"; - case "${_prog}" in - gxditview|xditview) - list_append _rl '-resolution' "${_DEFAULT_RESOLUTION}"; - ;; - xpdf) - case "${_DEFAULT_RESOLUTION}" in - 75) - # 72dpi is '100' - list_append _rl '-z' '104'; - ;; - 100) - list_append _rl '-z' '139'; - ;; - esac; - ;; - esac; - else - case "${_prog}" in - ghostview|gv|gxditview|xditview|xdvi) - list_append _rl '-resolution' "${_OPT_RESOLUTION}"; - ;; - xpdf) - case "${_OPT_RESOLUTION}" in - 75) - list_append _rl '-z' '104'; - # '100' corresponds to 72dpi - ;; - 100) - list_append _rl '-z' '139'; - ;; - esac; - ;; - esac; - fi; - if is_yes "${_OPT_ICONIC}"; then - case "${_prog}" in - ghostview|gv|gxditview|xditview|xdvi) - list_append _rl '-iconic'; - ;; - esac; - fi; - if is_yes "${_OPT_RV}"; then - case "${_prog}" in - ghostview|gv|gxditview|xditview|xdvi) - list_append _rl '-rv'; - ;; - esac; - fi; - if is_not_empty "${_OPT_XRM}"; then - case "${_prog}" in - ghostview|gv|gxditview|xditview|xdvi|xpdf) - eval set -- "{$_OPT_XRM}"; - for i in "$@"; do - list_append _rl '-xrm' "$i"; - done; - ;; - esac; - fi; - if is_not_empty "${_title}"; then - case "${_prog}" in - gxditview|xditview) - list_append _rl '-title' "${_title}"; - ;; - esac; - fi; - _DISPLAY_ARGS="${_rl}"; - - eval "${return_ok}"; -} # main_set_resources - - -######################################################################## -# main_display () -# -# Do the actual display of the whole thing. -# -# Globals: -# in: $_DISPLAY_MODE, $_OPT_DEVICE, -# $_ADDOPTS_GROFF, $_ADDOPTS_POST, $_ADDOPTS_X, -# $_REGISTERED_TITLE, $_TMP_CAT, -# $_OPT_PAGER $PAGER $_MANOPT_PAGER -# -landmark '19: main_display()'; -main_display() -{ - func_check main_display = 0 "$@"; - local p; - local _addopts; - local _device; - local _groggy; - local _modefile; - local _options; - local _pager; - local _title; - export _addopts; - export _groggy; - export _modefile; - - if obj _TMP_CAT is_non_empty_file; then - _modefile="${_OUTPUT_FILE_NAME}"; - else - clean_up; - eval "${return_ok}"; - fi; - case "${_DISPLAY_MODE}" in - groff) - _ADDOPTS_GROFF="${_ADDOPTS_GROFF} ${_ADDOPTS_POST}"; - if obj _OPT_DEVICE is_not_empty; then - _ADDOPTS_GROFF="${_ADDOPTS_GROFF} -T${_OPT_DEVICE}"; - fi; - _groggy="$(tmp_cat | eval grog "${_options}")"; - trap_clean; - # start a new shell program to get another process ID. - sh -c ' - set -e; - test -f "${_modefile}" && rm -f "${_modefile}"; - mv "${_TMP_CAT}" "${_modefile}"; - cat "${_modefile}" | \ - ( - clean_up() - { - if test -d "${_TMP_DIR}"; then - rm -f "${_TMP_DIR}"/* || true; - rmdir "${_TMP_DIR}"; - fi; - } - trap clean_up 0 2>/dev/null || true; - eval "${_groggy}" "${_ADDOPTS_GROFF}"; - ) &' - ;; - text|tty) - case "${_OPT_DEVICE}" in - '') - _device="$(get_first_essential \ - "${_OPT_TEXT_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 -T${_device})"; - if obj _DISPLAY_MODE is_equal 'text'; then - tmp_cat | eval "${_groggy}" "${_addopts}"; - else - _pager=''; - for p in "${_OPT_PAGER}" "${PAGER}" "${_MANOPT_PAGER}" \ - 'less -r -R' 'more' 'pager' 'cat'; do - if is_prog $p; then # no "" for is_prog() allows args for $p - _pager="$p"; - break; - fi; - done; - if obj _pager is_empty; then - error 'no pager program found for tty mode'; - fi; - tmp_cat | eval "${_groggy}" "${_addopts}" | \ - eval "${_pager}"; - fi; - 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; - ;; - html) - case "${_OPT_DEVICE}" in - ''|html) do_nothing; ;; - *) - warning \ - "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; - ;; - esac; - _modefile="${_modefile}".html - _groggy="$(tmp_cat | grog -Thtml)"; - _do_display; - ;; - pdf) - case "${_OPT_DEVICE}" in - ''|ps) - do_nothing; - ;; - *) - warning \ - "wrong device for ${_DISPLAY_MODE} mode: ${_OPT_DEVICE}"; - ;; - esac; - _modefile="${_modefile}" - _groggy="$(tmp_cat | grog -Tps)"; - trap_clean; - # start a new shell program to get another process ID. - sh -c ' - set -e; - _psfile="${_modefile}.ps"; - _modefile="${_modefile}.pdf"; - test -f "${_psfile}" && rm -f "${_psfile}"; - test -f "${_modefile}" && rm -f "${_modefile}"; - cat "${_TMP_CAT}" | \ - eval "${_groggy}" "${_ADDOPTS_GROFF}" > "${_psfile}"; - gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \ - -sOutputFile="${_modefile}" -c save pop -f "${_psfile}"; - test -f "${_psfile}" && rm -f "${_psfile}"; - test -f "${_TMP_CAT}" && rm -f "${_TMP_CAT}"; - ( - clean_up() { - rm -f "${_modefile}"; - if test -d "${_TMP_DIR}"; then - rm -f "${_TMP_DIR}"/* || true; - rmdir "${_TMP_DIR}"; - fi; - } - trap clean_up 0 2>/dev/null || true; - eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "${_modefile}"; - ) &' - ;; - 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; - ;; - 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() -{ - func_check _do_display = 0 "$@"; - trap_clean; - # start a new shell program for another process ID and better - # cleaning-up of the temporary files. - sh -c ' - set -e; - test -f "${_modefile}" && rm -f "${_modefile}"; - cat "${_TMP_CAT}" | \ - eval "${_groggy}" "${_ADDOPTS_GROFF}" > "${_modefile}"; - rm -f "${_TMP_CAT}"; - ( - clean_up() { - if test -d "${_TMP_DIR}"; then - rm -f "${_TMP_DIR}"/* || true; - rmdir "${_TMP_DIR}"; - fi; - } - trap clean_up 0 2>/dev/null || true; - eval "${_DISPLAY_PROG}" ${_DISPLAY_ARGS} "${_modefile}"; - ) &' -} - - -######################################################################## -# main (*) -# -# The main function for groffer. -# -# Arguments: -# -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_do_fileargs; - main_set_resources; - main_display; - eval "${return_ok}"; -} - -landmark '20: end of function definitions'; - -######################################################################## - -main "$@"; diff -ruN groff-1.18.1.1/contrib/groffer/Makefile.sub groff-1.18.1.2/contrib/groffer/Makefile.sub --- groff-1.18.1.1/contrib/groffer/Makefile.sub 2004-04-28 01:40:39.000000000 +0200 +++ groff-1.18.1.2/contrib/groffer/Makefile.sub 2006-09-26 23:24:06.000000000 +0200 @@ -1,47 +1,72 @@ -# Makefile.sub for `groffer' (integration into the groff source tree) +# Makefile.sub for `groffer' (integration into the `groff' source tree) # File position: /contrib/groffer/Makefile.sub -# Last update: 21 October 2002 +# Copyright (C) 2001,2002,2005,2006 Free Software Foundation, Inc. +# Written by Werner Lemberg and Bernd Warken. -# Copyright (C) 2001,2002 Free Software Foundation, Inc. -# Written by Werner Lemberg +# Last update: 17 Sep 2006 -# This file is part of groff. +# This file is part of `groffer' which is part of `groff'. -# groff is free software; you can redistribute it and/or modify it +# `groff' is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. -# groff is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -# License for more details. +# `groff' is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. # You should have received a copy of the GNU General Public License -# along with groff; see the files COPYING and LICENSE in the top -# directory of the groff source. If not, write to the Free Software -# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# along with `groff'; see the files COPYING and LICENSE in the top +# directory of the `groff' source. If not, write to the Free Software +# Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. ######################################################################## MAN1=groffer.n CLEANADD=groffer +# not all make programs have $(RM) predefined. +RM=rm -f + all: groffer -groffer: groffer.sh - rm -f $@; \ - sed -e "s|@BINDIR@|$(bindir)|g" \ +groffer: groffer.sh groffer2.sh version.sh $(SH_DEPS_SED_SCRIPT) + $(RM) $@; + sed -f $(SH_DEPS_SED_SCRIPT) \ + -e "s|@g@|$(g)|g" \ + -e "s|@BINDIR@|$(DESTDIR)$(bindir)|g" \ + -e "s|@libdir@|$(DESTDIR)$(libdir)|g" \ -e "s|@VERSION@|$(version)$(revision)|g" \ - -e $(SH_SCRIPT_SED_CMD) $(srcdir)/groffer.sh >$@; \ + -e $(SH_SCRIPT_SED_CMD) $(srcdir)/groffer.sh >$@; chmod +x $@ install_data: groffer - -test -d $(bindir) || $(mkinstalldirs) $(bindir) - -rm -f $(bindir)/groffer - $(INSTALL_SCRIPT) groffer $(bindir)/groffer + -test -d $(DESTDIR)$(bindir) || $(mkinstalldirs) $(DESTDIR)$(bindir) + -$(RM) $(DESTDIR)$(bindir)/groffer + $(INSTALL_SCRIPT) groffer $(DESTDIR)$(bindir)/groffer + -test -d $(DESTDIR)$(libdir)/groff/groffer || \ + $(mkinstalldirs) $(DESTDIR)$(libdir)/groff/groffer + -$(RM) $(DESTDIR)$(libdir)/groff/groffer/groffer2.sh + $(INSTALL_SCRIPT) $(srcdir)/groffer2.sh \ + $(DESTDIR)$(libdir)/groff/groffer/groffer2.sh + -$(RM) $(DESTDIR)$(libdir)/groff/groffer/version.sh + $(INSTALL_DATA) $(srcdir)/version.sh \ + $(DESTDIR)$(libdir)/groff/groffer/version.sh uninstall_sub: - -rm -f $(bindir)/groffer + -$(RM) $(DESTDIR)$(bindir)/groffer + -$(RM) $(DESTDIR)$(libdir)/groff/groffer/groffer2.sh + -$(RM) $(DESTDIR)$(libdir)/groff/groffer/version.sh + -rmdir $(DESTDIR)$(libdir)/groff/groffer + +######################################################################## +# Emacs settings +######################################################################## +# +# Local Variables: +# mode: makefile +# End: diff -ruN groff-1.18.1.1/contrib/groffer/README groff-1.18.1.2/contrib/groffer/README --- groff-1.18.1.1/contrib/groffer/README 2004-06-02 20:55:04.000000000 +0200 +++ groff-1.18.1.2/contrib/groffer/README 2006-09-11 21:41:00.000000000 +0200 @@ -1,44 +1,121 @@ +README + The `groffer' program is the easiest way to read documents written in some `roff' language, such as the `man pages', the manual pages in many operating systems. -All input is sent to `grog' and then to `groff' such that no special -`groff' arguments must be determined, but all `groff' options can be -specified. - -`groffer' also has many built-in `man' functionalities to find and -read the manual pages on UNIX and similar operating systems. It -accepts the information from an installed `man' program, but tries to -find a man path by itself. -So far, `groffer' is a shell script. It should run on any POSIX or -Bourne style shell. +Source files + +ChangeLog information on all changements +Makefile.sub groff make file +README this file, general description of the program +README_SH description of the shell version of the program +TODO information on what is left to be done +groffer2.sh main script of groffer +groffer.man manual page of groffer +groffer.sh starting script of groffer +version.sh script that handles the version information + + +Input + +Input comes from either standard input or command line parameters that +represent names of exisiting roff files or standardized specifications +for searching man pages. All of these can be compressed in a format +that is decompressible by `gzip', including `.gz', `bz2', and `.Z'. + +`groffer' has many built-in `man' functionalities to find and read the +manual pages on UNIX and similar operating systems. It accepts the +information from an installed `man' program, but tries to find a man +path by itself. + +`groffer' bundles all filespec parameters into a single output file in +the same way as `groff'. The disadvantage of this is that all file +name arguments must use the same groff language. To change this, the +option parsing must be revised for large parts. It seems that this +would create incompatibilities, so the actual option strategy is kept. + + +Output + +All input is first sent to `grog' to determine the necessary `groff' +options and then to `groff'. So no special `groff' arguments must be +given. But all `groff' options can be specified when this seems to be +appropriate. + +The following displaying modes for the output are available: +- Display formatted input with +-- the X `roff' viewer `gxditview', +-- a Postcript viewer, +-- a PDF viewer, +-- a DVI viewer, +-- a web browser, +-- a pager in a text terminal (tty). +- Generate `groff' output on stdout without a viewer. +- Generate the `groff intermediate output' on standard output without + postprocessing. +- Output the source code without any `groff' processing. +- There are some information outputs without `groff' processing, such + as by option `-V' and the `man' like `whatis' and `apropos' + outputs. + +By default, the program tries to display with `gxditview' as graphical +device in X; on non-X text terminals, the `tty' text mode with a pager +is tried by default. + + +Compatibility + +`groffer' consists of two shell scripts. It should run on any POSIX +or Bourne style shell that supports shell functions. See file +`README_SH' for more information. + +`groffer' is compatible with the `man' program. It supports .so +requests based on the man path and compressed files. That's more than +`groff' does. + + +Mailing lists For reporting bugs of `groffer', groff's free mailing list - can be used. For a general discussion, the -mailing list is more useful; see the `README' file in -the top directory of the `groff' source package for more details on -these mailing lists. + can be used. + +For a general discussion, the mailing list is more +useful, but one has to subscribe to this list at +http://lists.gnu.org/mailman/listinfo/groff. + +See the `README' file in the top directory of the `groff' source +package for more details on these mailing lists. ####### License -Copyright (C) 2003,2004 Free Software Foundation, Inc. -Written by Bernd Warken +Last update: 04 Sep 2006 + +Copyright (C) 2003,2004,2005,2006 Free Software Foundation, Inc. +Written by Bernd Warken. -This file is part of groffer, which is part of groff. +This file is part of `groffer', which is part of `groff'. -groff is free software; you can redistribute it and/or modify it +`groff' is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. -groff is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -License for more details. +`groff' is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. You should have received a copy of the GNU General Public License -along with groff; see the files COPYING and LICENSE in the top -directory of the groff source. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +along with `groff'; see the files COPYING and LICENSE in the top +directory of the `groff' source. If not, write to the Free Software +Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. + + +####### Emacs settings + +Local Variables: +mode: text +End: diff -ruN groff-1.18.1.1/contrib/groffer/README_SH groff-1.18.1.2/contrib/groffer/README_SH --- groff-1.18.1.1/contrib/groffer/README_SH 2004-06-02 20:41:43.000000000 +0200 +++ groff-1.18.1.2/contrib/groffer/README_SH 2006-07-30 16:06:15.000000000 +0200 @@ -1,66 +1,36 @@ -Description of groffer.sh, the shell version of groffer +Additional description for the shell version of `groffer' -Display groff files and man pages on X or tty, even when compressed. +Scripts -Usage +The shell version of `groffer' contains two files, `groffer.sh' and +`groffer2.sh'. -Input comes from either standard input or command line parameters that -represent names of exisiting roff files or standardized specifications -for searching man pages. All of these can be compressed in a format -that is decompressible by `gzip', including `.gz', `bz2', and `.Z'. - -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 plain text mode. -- Run a pager on the formatted input in a text terminal (tty). -- 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' as graphical -device, `tty' mode with a pager is tried as text display. - - -Several File Arguments - -So far, `groffer' bundles all filespec parameters into a single output -file in the same way as `groff'. The disadvantage of this is that all -file name arguments must have the same groff language. - -To change this, the option parsing must be revised for large parts. -It seems that this would create incompatibilities, so the actual -option strategy is kept. - - -Error Handling - -Error handling and exit behavior is complicated by the fact that -`exit' can only escape from the current shell; trouble occurs in -subshells. This was solved by sending kill signals, see $_PROCESS_ID -and error(). - - -Shell Compatibility - -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. - -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. The new version of `ash' -taken from `dash' produces strange errors, so the automatic call of -`ash' was removed. - -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. +`groffer.sh' is a short introductory script without any functions. I +can be run with a very poor Bourne shell. It just contains some basic +variables, the reading of the configuration files, and the +determination of the shell for `groffer2.sh'. This script is +transformed by `make' into `groffer' which will be installed into +@bindir@, which is usually /usr/local/bin. + +`groffer2.sh' is a long main script with all functions; it is called +by `groffer.sh' (`groffer' after installation). It is installed +unchanged into @libdir@/groff/groffer, which is usually +/usr/local/lib/groff/groffer. This script can be called with a +different shell, using the `groffer' option `--shell'. + + +Options + +The `groffer' script provides its own option parser. It is compatible +to the usual GNU style command line This includes long option names +with two signs such as `--option', clusters of short options, the +mixing of options and non-option file names, the option `--' to close +the option handling, and it is possible to abbreviate the long option +names. The abbreviation of long options is enhanced by letting each +internal `-' sign generate a new center of abbreviation. So each +command line argument starting with `--' can represent a multiple set +of abbreviations. The flexible mixing of options and file names in GNU style is always possible, even if the environment variable `$POSIXLY_CORRECT' is set @@ -69,92 +39,41 @@ argument is found. -Survey of Functions defined in groffer.sh +Error Handling -The elements specified within paranthesis `(<>)' give hints to what -the arguments are meant to be; the argument names are irrelevant. -<>? 0 or 1 -<>* arbitrarily many such arguments, incl. none -<>+ one or more such arguments -<> exactly 1 +Error handling and exit behavior is complicated by the fact that +`exit' can only escape from the current shell; trouble occurs in +subshells. This was solved by adding a temporary error file that is +tested by function exit_test() and by replacing `var=$(...)' by +function obj_from_output(). + + +Function Definitions in `groffer2.sh' + +Each funtion in groffer2.sh has a description that starts with the +function name and symbols for its arguments in paranthesis `()'. Each +`<>' construction gives an argument name that just gives a hint on +what the argument is meant to be; these argument names are otherwise +irrelevant. The `>' sign can be followed by another character that +shows how many of these arguments are possible. + + exactly 1 of this argument +? 0 or 1 of these arguments +* arbitrarily many such arguments, incl. none ++ one or more such arguments +... one or more such arguments +[...] optional arguments A function that starts with an underscore `_' is an internal function -for some function. The internal functions are defined just after -their corresponding function; they are not mentioned in the following. +for some other function. The internal functions are defined just +after their corresponding function. -abort (text>*) -base_name (path) -catz () -clean_up () -diag (text>*) -dirname_append ( []) -dirname_chop () -do_filearg () -do_nothing () -echo2 (*) -echo2n (*) -error (*) -get_first_essential (*) -is_dir () -is_empty () -is_equal ( ) -is_file () -is_non_empty_file () -is_not_dir () -is_not_empty () -is_not_equal ( ) -is_not_file () -is_not_prog () -is_not_writable () -is_not_yes () -is_prog () -is_yes () -leave () -landmark () -list_append ( ...) -list_from_cmdline ( [...]) -list_from_split ( ) -list_get () -list_has ( ) -list_has_not ( ) -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 () -normalize_args ( *) -path_chop () -path_clean () -path_contains ( ) -path_not_contains ( ) -path_split () -register_file () -register_title () -res ( ...) -reset () -save_stdin () -string_contains ( ) -string_not_contains ( ) -tmp_cat () -tmp_create (?) -to_tmp () -trap_clean () -trap_set () -usage () -version () -warning () -whatis () -where () +External Environment Variables -External non-groffer Environment Variables - -If these variables are exported in the script the `ash' shell coughs -when calling `groff' in `main_display()'. +The groffer.sh script uses the following external system variables. +It is supposed that these variables are already exported outside of +groffer.sh; otherwise they do not have a value within the script. external system environment variables that are explicitly used $DISPLAY: Presets the X display. @@ -162,7 +81,7 @@ $LC_ALL: For language specific man pages. $LC_MESSAGES: For language specific man pages. $PAGER: Paging program for tty mode. -$PATH: Path for the programs called (: list). +$PATH: Path for the programs called (`:' separated list). groffer native environment variables $GROFFER_OPT preset options for groffer. @@ -198,24 +117,168 @@ The class `list' represents an array structure, see list_*(). +Speed + +The major speed gain is the disabling of all debug features. This is +the default for the installed version of `groffer'. Before the run of +`make', the debug feature of $_DEBUG_FUNC_CHECK, corresponding to +option --debug-func, is enabled by default. The resulting heavy +slowing down should be regarded as a temporary feature. + +Another increase of speed was the replacement of the many `ls' calls +by analysing a `find' of manpath with `grep'. + + +Shell Compatibility + +The `groffer' shell scripts are compatible to 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. This draft is +available at http://www.funet.fi/pub/doc/posix/p1003.2/d11.2 in the +internet. + +The POSIX draft does not include `local' variables for functions. So +this concept was replaced by global variables with a prefix that +differs for each function. The prefix is chosen from the function +name. These quasi-local variables are unset before each return of the +function. + +The `groffer' scripts were tested under the shells `ash', `bash', +`bash-minimal', `dash', 'ksh', `mksh', `pdksh', 'posh', and `zsh' +without problems in Linux Debian. A shell can be tested by the +`groffer' option `--shell', but that will run only with groffer2.sh. +To start it directly from the beginning under this shell the following +command can be used. + + groffer.sh --shell= ... + + +Some shells are not fully POSIX compatible. For them the following +restrictions were done. For more information look at the +documentation `Portable shells' in the `info' page of `autoconf' +(look-up in Emacs-Help-Manuals_Info). + +- The command parts `then', `else', and `do' must be written each on a + line of their own. + +- Replace `for i in "$@"' by `for i' and remove internal `;' (kah). + +- Replace `set -- ...' by `set x ...; shift'. After the first + non-option argument, all arguments including those starting with `-' + are accepted as non-option. For variables or `$()' constructs with + line-breaks, use `eval set' without quotes. That transforms a + line-break within a variable to a space. + +- The name of the variable in `for' is chosen as a single character + (old ash). The content of such variables is not safe because it can + also occur in other functions. So it is often stored in an + additional quasi-local variable. + +- `echo' is not portable on options; some `echo' commands have many + options, others have none. So `echo -n' cannot be used, such that + the output of each function has complete lines. There are two + methods to avoid having `-' as the first character of any argument. + Either a character such as `x' can be prepended to the argument; + this must later on be removed by `sed'. Otherwise, `echo' can be + replaced by `cat </contrib/groffer/TODO - - -####### TODO - -Revision: -- Revise the `--all' feature to better reflect GNU man. -- The debug function stack is buggy (no effect on normal operation). -- Check main_parse_MANOPT(), not too important. -- Add long option shortcuts. -- The actual replacement `dash' of the POSIX `ash' shell produces - strange errors with the groffer script, while the former `ash' - worked successfully. Are these errors just bugs of `dash'? - -Optimization: -- 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). -- To increase the running speed write part of the groffer shell script - in C/C++. -- Split the groffer.sh shell script into several files for better tests - of the shell compatibility. - -Features of external programs: -- Revise option handling of `grog'. -- `gxditview' needs a complete shower. - -Documentation: -- 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'. -- The documentation in the headers for some function definitions in - `groffer.sh' needs to be updated. - - -####### License - -Copyright (C) 2003,2004 Free Software Foundation, Inc. -Written by Bernd Warken - -This file is part of groffer, which is part of groff. - -groff is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -groff is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -License for more details. - -You should have received a copy of the GNU General Public License -along with groff; see the files COPYING and LICENSE in the top -directory of the groff source. If not, write to the Free Software -Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. diff -ruN groff-1.18.1.1/contrib/groffer/version.sh groff-1.18.1.2/contrib/groffer/version.sh --- groff-1.18.1.1/contrib/groffer/version.sh 1970-01-01 01:00:00.000000000 +0100 +++ groff-1.18.1.2/contrib/groffer/version.sh 2006-09-26 23:24:06.000000000 +0200 @@ -0,0 +1,41 @@ +#! /bin/sh + +# groffer - display groff files + +# Source file position: /contrib/groffer/version.sh +# Installed position: /lib/groff/groffer/version.sh + +# Copyright (C) 2001,2002,2003,2004,2005,2006 +# Free Software Foundation, Inc. +# Written by Bernd Warken + +# This file is part of `groffer', which is part of `groff'. + +# `groff' is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# `groff' is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with `groff'; see the files COPYING and LICENSE in the top +# directory of the `groff' source. If not, write to the Free Software +# Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, +# USA. + +######################################################################## + +export _PROGRAM_VERSION; +export _LAST_UPDATE; + +_PROGRAM_VERSION='0.9.27'; +_LAST_UPDATE='26 Sep 2006'; + +# this setting of the groff version is only used before make is run, +# otherwise @VERSION@ will set it, see groffer.sh. +export _GROFF_VERSION_PRESET; +_GROFF_VERSION_PRESET='1.19.3preset'; diff -ruN groff-1.18.1.1/NEWS groff-1.18.1.2/NEWS --- groff-1.18.1.1/NEWS 2004-06-19 13:05:46.000000000 +0200 +++ groff-1.18.1.2/NEWS 2006-10-04 05:59:31.000000000 +0200 @@ -1,6 +1,30 @@ This file describes recent user-visible changes in groff. Bug fixes are not described. There are more details in the man and info pages. +VERSION 1.18.1.2 +================ + +This is the same as 1.18.1.1 but with an updated version of the `groffer' +script. + +Groffer +------- + +o A security problem (reported as CAN-2004-0969) has been fixed. + +o This version is a rewrite of groffer in many parts, but it is kept in + the old single script style. + + New options: --text, --mode text, --tty-viewer, --X, --mode X, + --X-viewer, --html, --mode html, --html-view, --apropos-data, + --apropos-devel, --apropos-progs. + + New documentation file: README_SH. + + Enhancement of the configuration files and the `apropos' handling. + + + VERSION 1.18.1.1 ================