summaryrefslogtreecommitdiff
path: root/contrib/groffer/groffer.sh
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/groffer/groffer.sh')
-rw-r--r--contrib/groffer/groffer.sh1417
1 files changed, 1417 insertions, 0 deletions
diff --git a/contrib/groffer/groffer.sh b/contrib/groffer/groffer.sh
new file mode 100644
index 00000000..a889d9c4
--- /dev/null
+++ b/contrib/groffer/groffer.sh
@@ -0,0 +1,1417 @@
+#!/bin/sh
+
+PROGRAM_NAME=groffer
+PROGRAM_VERSION="0.3 (alpha)"
+LAST_UPDATE="15 Dec 2001"
+
+# Copyright (C) 2001 Free Software Foundation, Inc.
+# Written by Bernd Warken <bwarken@mayn.de>
+
+# This file 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 file COPYING. If not, write to the Free
+# Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+########################################################################
+# Description
+########################################################################
+
+# Display groff files on X or tty, even when zipped.
+
+# This script tries to avoid features of special shells, so some
+# elements are programmed in a more complicated way than necessary.
+
+########################################################################
+# Debugging
+########################################################################
+# Error handling and exit behavior is complicated by the fact that
+# `exit' can only escape from the current shell. This leads to trouble
+# in `$()' subshells.
+#
+
+
+# for debugging only
+#set -x
+#set -v
+function diag ()
+{
+ echo '>>>>>' "$@" >&2;
+}
+function abort ()
+{
+ [ $# -gt 0 ] && diag "$@";
+ error 2>/dev/null || exit 1;
+}
+
+########################################################################
+# Setup
+########################################################################
+
+set -a
+
+########################################################################
+# Environment Variables
+########################################################################
+
+# Environment variables that are regarded as global to this file are
+# written in upper case letters and can use the underline character
+# inside, e.g. $GLOBAL_VARIABLE; local variables start with an
+# underline and use only lower case letters and underlines, e.g.
+# $_local_variable .
+
+# [A-Z]* system variables, e.g. $MANPATH
+# [A-Z][A_Z_]* global file variables, e.g. $MAN_PATH
+# _[a-z_]* local variables, e.g. $_manpath
+# _[a-z_] local loop variables, e.g. $_i
+
+# global variables
+FILE_ARGS="" # the non-option command line parameters
+HAS_COMPRESSION="" # `yes' if compression is available
+HAS_MANW="" # `yes' if `man -w' is available
+HAS_MKTEMP="" # `yes' if `mktemp' program is available
+HAS_OPTS_GNU="" # `yes' if GNU `getopt' is available
+HAS_OPTS_POSIX="" # `yes' if POSIX `getopts' is available
+MAN_PATH="" # search path for man-pages
+OTHER_OPTIONS="" # given non-native command line options
+OPT_SOURCE="" # source code option (`Quellcode')
+OPT_DEVICE="" # device option
+OPT_DPI="" # groff -X option
+OPT_MAN="" # interpret file params as man-pages
+OPT_MANPATH="" # manual setting of path for man-pages
+OPT_TITLE="" # title for gxditview window
+OPT_XRDB="" # X resource arguments to gxditview
+TEMP_DIR="" # directory for temporary files
+TMP_CAT="" # stores concatenation of everything
+TMP_INPUT="" # stores stdin, if any
+TMP_DONE="" # stores the names of processed args
+
+# command line arguments
+GROFFER_LONGOPTS="device: help man manpath: source title: version \
+ xrdb:";
+GROFFER_SHORTOPTS="hQT:vX";
+GROFF_ARG_SHORTS="d:f:F:I:L:m:M:n:o:P:r:w:W:"; # inhereted from groff
+GROFF_SHORTOPTS="abcegilpstzCEGNRSUVZ"; # inhereted from groff
+ALL_SHORTOPTS=\
+"${GROFFER_SHORTOPTS}${GROFF_SHORTOPTS}${GROFF_ARG_SHORTS}";
+ALL_LONGOPTS="${GROFFER_LONGOPTS}";
+
+PROCESS_ID="$$" # for shutting down the program
+
+ENABLE_MANPAGES=yes # enable search for man-pages
+
+########################################################################
+# System Test
+########################################################################
+
+# Test the availability of the system utilities used in this script.
+
+########################################################################
+# Test of function "test".
+#
+[ "a" = "a" ] || exit 1;
+
+########################################################################
+# Test of function "echo".
+#
+if [ "$(echo -n 'te' && echo -n && echo 'st')" != "test" ]; then
+ echo 'Test of "echo" command failed.' >&2;
+ exit 1;
+fi;
+
+########################################################################
+# Test of function "sed".
+#
+if [ "$(echo teeest | sed -e '\|^teeest$|s|\(e\)\+|\1|')" != "test" ];
+then
+ echo 'Test of "sed" command failed.' >&2;
+ exit 1;
+fi;
+
+########################################################################
+# Test of function "grep".
+#
+if [ "$( (echo no; echo test) | grep -e '^.e..$')" != "test" ]; then
+ echo 'Test of "grep" command failed.' >&2;
+ exit 1;
+fi;
+
+########################################################################
+# Test of function "cat".
+#
+if [ "$(echo test | cat)" != "test" ]; then
+ echo 'Test of "cat" command failed.' >&2;
+ exit 1;
+fi;
+
+########################################################################
+# Test for compression.
+#
+if [ "$(echo test | zcat -f -)" = "test" ]; then
+ HAS_COMPRESSION="yes";
+else
+ HAS_COMPRESSION="no";
+fi;
+
+########################################################################
+# Test for temporary directory and file generating utility
+#
+
+# determine temporary directory into `$TEMP_DIR'
+for _i in "$GROFF_TMPDIR $TMPDIR" "$TMP" "$TEMP" "$TEMPDIR" \
+ "$HOME"/tmp /tmp "$HOME" .;
+do
+ if [ "$_i" != "" ]; then
+ if [ -d "$_i" -a -r "$_i" -a -w "$_i" ]; then
+ TEMP_DIR="$_i";
+ break;
+ fi;
+ fi;
+done
+unset _i
+if [ "$TEMP_DIR" = "" ]; then
+ echo "Couldn't find a directory for storing temorary files." >&2;
+ exit 1;
+fi;
+
+# test whether function `mktemp' is available
+_tmp="$(mktemp "${TEMP_DIR}/.${PROGRAM_NAME}".XXXXXX)" 2>/dev/null;
+if [ "$_tmp" != "" ]; then
+ HAS_MKTEMP="yes";
+ rm -f "$_tmp";
+else
+ HAS_MKTEMP="no";
+fi;
+unset _tmp;
+
+########################################################################
+# Test option parsing programs.
+#
+
+# GNU getopt
+if _res="$(getopt -l GNU: ab: --GNU getopt test 2>/dev/null |
+ sed -e '\|^ *\(.*\) *$|s||\1|')"; then
+ if [ "$_res" = "--GNU 'getopt' -- 'test'" ]; then
+ HAS_OPTS_GNU="yes";
+ fi;
+fi;
+
+# POSIX getopts
+OPTIND=1;
+OPTARG="";
+getopts "t:" _opt -test 2>/dev/null;
+if [ "$?" -eq 0 -a "$_opt" = "t" -a \
+ "$OPTARG" = "est" -a "$OPTIND" -eq 2 ]; then
+ HAS_OPTS_POSIX="yes";
+fi;
+
+if [ "$HAS_OPTS_GNU" = "" -a "$HAS_OPTS_POSIX" = "" ]; then
+ error "No argument parser program available (`getopt' or `getopts').";
+fi;
+
+unset _opt;
+unset _res;
+OPTIND=1;
+OPTARG="";
+
+########################################################################
+# Determine search method for man-pages
+#
+unset HAS_MANW # `yes' if `man -w' is available
+if _files="$(man -w man 2>/dev/null)"; then
+ if [ "$_files" = "" ]; then
+ HAS_MANW="no";
+ else
+ for _i in $_files; do
+ if [ -f "$_i" ]; then
+ HAS_MANW="yes";
+ break;
+ fi;
+ done;
+ fi;
+ if [ "$HAS_MANW" != "yes" ]; then
+ HAS_MANW="no";
+ fi;
+fi;
+if [ "$HAS_MANW" != "yes" ]; then
+ if [ "$MANPATH" = "" ]; then
+ _dirs="$(manpath 2>/dev/null | tr : ' ')";
+ if [ "$?" != 0 -o "$_dirs" = "" ]; then
+ MANPATH="$_dirs";
+ fi
+ fi
+ if [ "$MANPATH" = "" ]; then # set some default path
+ _manpath="/usr/local/share/man /usr/local/man \
+ /usr/share/man /usr/man \
+ /usr/X11R6/man /usr/openwin/man \
+ /opt/man /opt/gnome/man /opt/kde/man";
+ else
+ _manpath="$(echo -n $MANPATH | tr : ' ')";
+ fi;
+ _dirs="";
+ for _p in $_manpath; do
+ if [ -d "$_p" -a -r "$_p" -a -x "$_p" ]; then
+ if [ "$_dirs" = "" ]; then
+ _dirs="$_p";
+ else
+ _dirs="$_dirs $_p";
+ fi;
+ fi;
+ done;
+ _manpath="$_dirs";
+ if [ "$LANG" = "" ]; then
+ MAN_PATH="$_manpath";
+ else # language-specific directories
+ MAN_PATH="";
+ # two-letter version of $LANG
+ _lang_short="$(echo $LANG | sed -e '\|^\(..\).*$|s||\1|')";
+ for _p in $_manpath; do
+ _dirs="${_p}/${_lang_short}*"; # all dirs for 2-letter lang code
+ if [ "$_dirs" != "" ]; then
+ if [ -d "${_p}/${LANG}" ]; then
+ _dirs="$_dirs ${_p}/${LANG}";
+ fi;
+ fi;
+ if [ "$MAN_PATH" = "" ]; then
+ MAN_PATH="$_dirs $_p";
+ else
+ MAN_PATH="$MAN_PATH $_dirs $_p";
+ fi;
+ done;
+ fi;
+fi;
+unset _files;
+unset _dirs;
+unset _i;
+unset _p;
+unset _manpath;
+
+########################################################################
+# Shell Funtions
+########################################################################
+
+# Survey of functions defined here
+
+# The elements specified within paranthesis `(<>)' give hints to what
+# the arguments are meant to be; the argument names are irrelevant.
+# <>? 0 or 1
+# <>* arbitrarily many incl. none
+# <> exactly 1
+
+# append_args (<arg>*)
+# base_name (path)
+# catz (<file>*)
+# check_dpi ()
+# clean_up ()
+# count_next_quoted (<arg>*)
+# del_all_leading_from (<regexp> <string>)
+# del_ext_from (<extension> <filename>)
+# echo2 (<text>*)
+# error (<err_no> <text>*)
+# get_manpath ()
+# get_next_quoted (<arg>*)
+# get_title ()
+# is_substring_of (<part> <string>)
+# leave ()
+# manpage_from_path (<name> <section>?)
+# manpage_search_filespec (<filespec>)
+# manpage_search_name (<name> <section>?)
+# normalize_args (<arg>*)
+# output (<text>*)
+# register_done_file (<filespec>*)
+# save_stdin_if_any ()
+# shift_quoted (<arg>*)
+# supercat (<filearg>*)
+# tmp_cat ()
+# tmp_create ()
+# unquote (<arg>*)
+# usage ()
+# version ()
+
+########################################################################
+# append_args (<arg>*)
+#
+# Append args to `string' separated by a space, omitting empty args.
+#
+# Arguments : >=2
+# Output : the generated string
+#
+append_args()
+{
+ local _res;
+ while [ "$1" = "" ]; do
+ if [ "$#" -eq 0 ]; then
+ return;
+ fi;
+ shift;
+ done;
+ _res="$1";
+ shift;
+ while [ "$#" -ge 1 ]; do
+ if [ "$1" != "" ]; then
+ _res="$_res $1";
+ fi;
+ shift;
+ done;
+ output "$_res";
+}
+
+########################################################################
+# base_name (path)
+#
+# Delete the directory part of `path', i.e. everything up to last `/'
+# at the beginning of `path'.
+#
+# Arguments : 1
+# Output : the corrected string
+#
+base_name()
+{
+ if [ "$#" != 1 ]; then
+ error 1 "Function base_name needs 1 argument.";
+ fi
+ output "$1" | sed -e '\|^\(.*/\)\+|s|||';
+}
+
+########################################################################
+# catz (<file>*)
+#
+# If compression is available decompress standard input and write it to
+# standard output; otherwise copy standard input to standard output.
+#
+catz()
+{
+ if [ "$HAS_COMPRESSION" = "yes" ]; then
+ if [ "$#" = 0 ]; then
+ set -- -;
+ fi;
+ zcat -f "$@";
+ else
+ cat "$@";
+ fi;
+}
+
+########################################################################
+# check_dpi ()
+#
+# Sanity check for having default X resolution 100 dpi (very defensive)
+#
+# Output : generated title
+#
+check_dpi()
+{
+ local _res=100;
+ local _fp;
+ if _fp="$(xset q | grep '/font' 2>/dev/null)"; then
+ case "$_fp" in
+ *100*) : ; ;;
+ *75*) _res=75; ;; # no 100 found in X font path, but 75
+ esac;
+ fi;
+ output "$_res";
+}
+
+########################################################################
+# clean_up () :
+#
+# Clean exit without an error.
+#
+clean_up()
+{
+ rm -f "$TMP_CAT" "$TMP_INPUT" "$TMP_DONE";
+}
+
+########################################################################
+# count_next_quoted (<arg>*)
+#
+# Expects single-quoted arguments, returns the first quoted argument.
+#
+# Arguments : single-quoted, evt. with included spaces.
+# Output : number of arguments within the single-quote.
+# Return : `1' if arguments are not single-quoted, `0' otherwise.
+#
+count_next_quoted()
+{
+ local _args;
+ local _number;
+ local _quoted_block="";
+ if [ "$#" -eq 0 ]; then
+ return 1;
+ fi;
+ if output $1 | grep -e "^'" >/dev/null 2>&1; then
+ # starts with a single quote
+ while ! (output $1 | grep -e \'\$ >/dev/null 2>&1); do
+ # doesn't end with a single quote
+ _quoted_block="$(append_args $_quoted_block $1)";
+ shift;
+ if [ "$#" = 0 ]; then
+ error "count_next_quoted : no closing quote found"
+ return 1;
+ fi;
+ done;
+ # actual $1 has closing quote
+ _quoted_block="$(append_args $_quoted_block $1)";
+ set -- $_quoted_block;
+ _number="$#";
+ else
+ _number=1;
+ fi;
+ output $_number;
+}
+
+########################################################################
+# del_all_leading_from (<regexp> <string>)
+#
+# Delete every occurence of `regexp' at the beginning of `string'.
+#
+# Arguments : 2
+# Output : the corrected string
+#
+del_all_leading_from()
+{
+ if [ "$#" != 2 ]; then
+ error 1 'Function "del_all_leading_from" needs 2 args.';
+ fi
+ output "$2" | sed -e '\|^\('"$1"'\)\+|s|||';
+}
+
+########################################################################
+# del_ext_from (<extension> <filename>)
+#
+# Delete `extension' from the end of `filename'.
+#
+# Arguments : 2
+# Output : the corrected string
+#
+del_ext_from()
+{
+ if [ "$#" != 2 ]; then
+ error 1 'Function "del_ext_from" needs 2 args.';
+ fi
+ output "$2" | sed -e "\|^ *\('\?.*\)$1\('\?\) *"'$|s||\1\2|';
+}
+
+########################################################################
+# echo2 (<text>*)
+#
+# Output to stderr.
+#
+# Arguments : arbitrary text.
+#
+echo2()
+{
+ echo "$*" >&2;
+}
+
+########################################################################
+# error (<err_no> <text>*)
+#
+# Output argurments to stderr and abort.
+#
+# Arguments : arbitrary text
+#
+error()
+{
+ local _errno;
+ case "$#" in
+ 0) set -- 'unknown error'; ;;
+ esac;
+ echo2 "groffer error : $*";
+ clean_up;
+ kill "$PROCESS_ID" >/dev/null 2>&1;
+ kill -9 "$PROCESS_ID" >/dev/null 2>&1;
+ exit 1;
+}
+
+########################################################################
+# get_manpath ()
+#
+# Determine search path for man-pages (only needed when no `man -w').
+#
+# Return : `0' if a valid path was retrieved.
+# Output : path as space-separated list (intended for $MAN_PATH).
+# Globals : system : $MANPATH $LANG
+# file : $OPT_MANPATH $MAN_PATH
+#
+get_manpath()
+{
+ local _files;
+ local _dirs;
+ local _i;
+ local _d;
+ local _p;
+ local _all;
+ local _manpath;
+ if [ "$OPT_MANPATH" != "" ]; then # --manpath was set
+ MANPATH="$OPT_MANPATH";
+ fi;
+ if [ "$MANPATH" = "" ]; then # try `manpath' program
+ _dirs="$(manpath 2>/dev/null)";
+ if [ "$?" = 0 -a "$_dirs" != "" ]; then
+ MANPATH="$_dirs";
+ fi
+ fi
+ if [ "$MANPATH" = "" ]; then # set some default path
+ _manpath="/usr/local/share/man /usr/local/man \
+ /usr/share/man /usr/man \
+ /usr/X11R6/man /usr/openwin/man \
+ /opt/man /opt/gnome/man /opt/kde/man";
+ else
+ _manpath="$(echo -n $MANPATH | tr : ' ')";
+ fi;
+ if [ "$_manpath" = "" ]; then
+ return 1;
+ fi;
+ _dirs="";
+ for _p in $_manpath; do # remove non-existing directories
+ if [ -d "$_p" -a -r "$_p" -a -x "$_p" ]; then
+ _dirs="$(append_args $_dirs $_p)";
+ fi;
+ done;
+ _manpath="$_dirs";
+ if [ "$_manpath" = "" ]; then
+ return 1;
+ fi;
+ if [ "$LANG" = "" ]; then
+ MAN_PATH="$_manpath";
+ else # language-specific directories
+ MAN_PATH="";
+ # two-letter version of $LANG
+ _short_code="$(echo $LANG | sed -e '\|^\(..\).*$|s||\1|')";
+ for _p in $_manpath; do
+ _langdir="${_p}/${LANG}";
+ _all="$(ls -d "${_p}/${_short_code}"* 2>/dev/null)";
+ # all dirs with this 2-letter lang code
+ _langs="";
+ if [ "$_all" != "" ]; then
+ for _d in $_all; do
+ if [ "$_d" != "$_langdir" -a -d "$_d" ]; then
+ _langs="$(append_args "$_langs" "$_d")";
+ fi;
+ done;
+ if [ -d "$_langdir" ]; then
+ _langs="$(append_args "$_langdir" $_langs)";
+ fi;
+ fi;
+ MAN_PATH="$(append_args "$_langs" $_p)";
+ done;
+ fi;
+ if [ "$MAN_PATH" = "" ]; then
+ return 1;
+ fi;
+ output "$MAN_PATH";
+}
+
+
+########################################################################
+# get_next_quoted (<arg>*)
+#
+# Expects single-quoted arguments, returns the first quoted argument.
+#
+# Arguments : single-quoted, evt. with included spaces.
+# Output : everything up to the next arg terminated by a quote;
+# the enclosing quotes are removed.
+# Return : `1' if arguments are not single-quoted, `0' otherwise.
+#
+get_next_quoted()
+{
+ local _args="$*";
+ local _number="$(count_next_quoted $_args)";
+ shift $_number;
+ output $_args | sed -e '\|^\(.*\)'"$*"'$|s||\1|' |
+ sed -e "\|^ *'\(.*\)' *"'$|s||\1|';
+}
+
+########################################################################
+# get_title ()
+#
+# create title for X from the $TMP_DONE file
+#
+# Globals : $TMP_DONE $OPT_XRDB $OPT_TITLE
+# Output : generated title
+#
+get_title()
+{
+ if [ "$OPT_TITLE" != "" ]; then
+ # title was set by option --title
+ output "$OPT_TITLE";
+ return 0;
+ fi;
+ if is_substring_of "-title" "$OPT_XRDB"; then
+ # $OPT_XRDB is handled anyway, so no extra output from here
+ return 0;
+ fi;
+ # no title was supplied on the command line, take the default title
+ # constisting of the processed filespecs, stored in file $TMP_DONE.
+ cat "$TMP_DONE";
+}
+
+########################################################################
+# is_substring_of (<part> <string>)
+#
+# Test whether `part' is contained in `string'.
+#
+# Arguments : 2 text arguments.
+# Return : `0' if arg1 is substring of arg2, `1' otherwise.
+#
+is_substring_of()
+{
+ if [ "$#" != 2 ]; then
+ false;
+ error "is_substring_of needs 2 arguments.";
+ fi;
+ if output "$2" | grep -e "$1" >/dev/null 2>&1; then
+ return 0;
+ else
+ return 1;
+ fi;
+}
+
+########################################################################
+# leave ()
+#
+# Clean exit without an error.
+#
+leave()
+{
+ clean_up;
+ exit 0;
+}
+
+########################################################################
+# manpage_from_path (<name> <section>?)
+#
+# Get position of man-page using the $MAN_PATH variable.
+#
+# Globals : $MAN_PATH must be preset as space-separated list of dirs.
+# $LANG system language preset.
+# Arguments : either 2 (`name' `section') or 1 (`name').
+# Output : the file position for the man-page
+# Return : `0'
+#
+manpage_from_path()
+{
+ local _i;
+ local _p;
+ local _dirs;
+ local _args;
+ local _name="$1";
+ local _section="$2";
+ case "$#" in
+ 1) _args="$1"; ;;
+ 2) _args="$2 $1"; ;;
+ *)
+ false;
+ error 1 "man_from_path : needs 1 or 2 arguments.";
+ ;;
+ esac;
+ if [ "$HAS_MANW" = "yes" ]; then
+ error manpage_from_path : "man -w" is available.
+ fi;
+ if [ "$MAN_PATH" = "" ]; then
+ return 0;
+ fi;
+ for _p in $MAN_PATH; do
+ set -- "$(ls -d "${_p}/man${_section}"*"/${_name}.${_section}"* \
+ 2>/dev/null)";
+ while [ "$#" -gt 0 ]; do
+ if [ -f "$1" -a -r "$1" ]; then
+ output "$1";
+ return 0;
+ fi;
+ shift;
+ done;
+ done;
+ return 1;
+}
+
+########################################################################
+# manpage_search_filespec (<filespec>)
+#
+# check argument with `man -w'
+#
+# Arguments : exactly 1 argument of the form `name.section',
+# `man:name', or `man:name(section)'.
+# Several args indicate an embedded space character.
+#
+# Output : filename of man page, if any.
+# Return : `0' if man page was found, `1' else.
+#
+manpage_search_filespec()
+{
+ local _file="";
+ local _arg;
+ local _name;
+ local _section;
+ if [ "$#" -ne 1 ]; then
+ return 1;
+ fi;
+ _arg="$1";
+# _arg="$(output "$1" | sed -e "\|'\(.*\)'|s||\1|")";
+ case "$_arg" in
+ */*) # contains directory part, not handled
+ return 1;
+ ;;
+ man:?*\(?*\)) # `man:' URL with section
+ _name="$(output "$_arg" |
+ sed -e '\|^man:\([^(]\+\)(\(.*\))$|s||\1|')";
+ _section="$(output $_arg |
+ sed -e '\|^man:\([^(]\+\)(\(.*\))$|s||\2|')";
+ if _file="$(manpage_search_name "$_name" "$_section")" &&
+ [ "$_file" != "" ]; then
+ output "$_file";
+ return 0;
+ fi;
+ return 1;
+ ;;
+ man:?*) # `man:' URL without section
+ _name="$(output "$_arg" | sed -e '\|^man:|s|||')";
+ if _file="$(manpage_search_name "$_name")"; then
+ output "$_file";
+ return 0;
+ else
+ return 1;
+ fi;
+ ;;
+ ?*.?*) # name.section
+ _name="$(output "$_arg" |
+ sed -e '\|^\([^.]\+\)\.\([^.]\+\)$|s||\1|')";
+ _section="$(output "$_arg" |
+ sed -e '\|^\([^.]\+\)\.\([^.]\+\)$|s||\2|')";
+ _file="$(manpage_search_name "$_name" "$_section")";
+ if [ "$?" -eq 0 -a "$_file" != "" ]; then
+ output "$_file";
+ return 0;
+ fi;
+ _file="$(manpage_search_name "$_arg")"
+ if [ "$?" -eq 0 -a "$_file" != "" ]; then
+ output "$_file";
+ return 0;
+ fi;
+ return 1;
+ ;;
+ ?*)
+ _file="$(manpage_search_name "$_arg")";
+ if [ "$?" -eq 0 -a "$_file" != "" ]; then
+ output "$_file";
+ return 0;
+ fi;
+ return 1;
+ ;;
+ esac;
+ return 1;
+}
+
+########################################################################
+# manpage_search_name (<name> <section>?)
+#
+# Get position of man-page `name(section)', or just `name' in the
+# lowest section using `man -w'.
+#
+# Arguments : either 2 (`name' `section') or 1 (`name').
+# Output : the file position for the man-page
+#
+manpage_search_name()
+{
+ local _i;
+ local _name;
+ local _section;
+ case "$#" in
+ 1)
+ _name="$1";
+ _section="";
+ ;;
+ 2)
+ _name="$1";
+ _section="$2";
+ ;;
+ *)
+ error "man_search_name : needs 1 or 2 arguments.";
+ ;;
+ esac;
+ if [ "$HAS_MANW" = "yes" ]; then
+ for _i in $(man -w $_section "$_name" 2>/dev/null); do
+ if [ -f "$_i" -a -r "$_i" ] &&
+ (catz "$_i" | grog | grep -e '-man') >/dev/null 2>&1;
+ then
+ output "$_i";
+ return 0;
+ fi
+ done;
+ else
+ manpage_from_path $_section "$_name";
+ return 0;
+ fi;
+ return 1;
+}
+
+########################################################################
+# normalize_args (<arg>+)
+#
+# Display arguments in the normalized form of GNU `getopt'.
+#
+# Arguments : if no arguments are given, $* is parsed instead
+# Globals : $ALL_LONGOPTS $ALL_SHORTOPTS
+# Output : arguments in normalized form
+#
+normalize_args()
+{
+ local _args;
+ local _long_opts="";
+ local _i;
+ local _res;
+ local _opt;
+ if [ "$#" -eq 0 ]; then
+ set -- -;
+ fi;
+ if [ "$HAS_OPTS_GNU" = "yes" ]; then
+ _long_opts="";
+ for _i in ${ALL_LONGOPTS}; do
+ _long_opts="$(append_args $_long_opts -l "$_i")";
+ done;
+ if _res="$(getopt -l "$_long_opts" "$ALL_SHORTOPTS" "$@")"; then
+ output "$_res";
+ return 0;
+ else
+ error 'wrong option';
+ fi;
+ elif [ "$HAS_OPTS_POSIX" = "yes" ]; then # POSIX getopts
+ case "--[^ ]" in
+ "$_args") error "long options are only available in GNU."; ;;
+ esac;
+ OPTIND=1;
+ OPTARG="";
+ _res="";
+ while getopts ":$ALL_SHORTOPTS" _opt $_args; do
+ if [ "$_opt" = ":" ]; then
+ if [ "$OPTARG" = "-" ]; then
+ error "your system does not allow GNU long options.";
+ else
+ error "unknown option.";
+ fi;
+ fi;
+ _res="$(append_args $_res -"$_opt")";
+ if [ "$OPTARG" != "" ]; then
+ _res="$(append_args $_res "'$OPTARG'")";
+ # option args are quoted;
+ OPTARG="";
+ fi;
+ done;
+ if [ "$_opt" == '?' ]; then # end of options
+ # non-option parameters are quoted in the output
+ _param="";
+ set -- $_args;
+ if [ "$OPTIND" -le "$#" ]; then
+ _res="$(append_args $_res "--")";
+ eval _param=${"$OPTIND"};
+ if [ "$_param" != "--" ]; then
+ _res="$(append_args $_res "'$_param'")";
+ fi;
+ shift "$OPTIND";
+ while [ "$#" -gt 0 ]; do
+ _res="$(append_args $_res "'$1'")";
+ done;
+ fi;
+ output $_res;
+ return 0;
+ else
+ error 'error in option parsing';
+ fi;
+ fi;
+}
+
+########################################################################
+# output (<text>*)
+#
+# Print arguments to standard output, if there are any.
+# Handle `echo' programs that can have only 1 arg.
+#
+# Arguments : any.
+# Output : the list of the arguments without a line break.
+#
+output()
+{
+ if [ "$#" -ge 1 ]; then
+ echo -n "$*";
+ fi;
+}
+
+########################################################################
+# register_done_file (<filespec>)
+#
+# Transform argument into a title element and append to $TMP_DONE file.
+#
+register_done_file() {
+ set -- $(base_name "$*"); # remove directory part
+ set -- $(del_ext_from .gz "$*"); # remove .hz
+ set -- $(del_ext_from .Z "$*"); # remove .Z
+ case "$#" in
+ 0) return; ;;
+ 1) _res="$1"; ;;
+ *) _res="'$*'"; ;;
+ esac;
+ output " $_res" >> "$TMP_DONE";
+}
+
+########################################################################
+# save_stdin_if_any ()
+#
+# Check if stdin is needed; if so, store to temporary file.
+# Globals : $FILE_ARGS
+#
+save_stdin_if_any()
+{
+ local _a
+ set -- $FILE_ARGS
+ for _a in "$@"; do
+ if [ "$_a" = "'-'" ]; then
+ cat | catz - >"$TMP_INPUT"; # using `cat' first is safer
+ break;
+ fi;
+ done;
+}
+
+########################################################################
+# shift_quoted (<arg>*)
+#
+# Expects single-quoted arguments, strips the first quoted argument.
+#
+# Arguments : single-quoted, evt. with included spaces.
+# Output : delete everything up to the next arg terminated by a
+# quote and the following space, output the rest.
+# Return : `1' if arguments are not single-quoted, `0' otherwise.
+#
+shift_quoted()
+{
+ local _args="$*";
+ shift "$(count_next_quoted $_args)";
+ output $*;
+}
+
+########################################################################
+# supercat (<filearg>*)
+#
+# Output the concatenation of files, man-pages, or standard input to
+# standard output. All parts that are stored in the gzip or Z
+# compression format are decompressed. No other modifications.
+# All processed arguments are added to the global variable
+# $ARGS_DONE.
+#
+# Arguments :
+# All arguments are expected to be surrounded by single quotes.
+# - names of existing files.
+# - '-' to represent standard input (several times allowed).
+# - 'man:name.(section)' the man-page for `name' in `section'.
+# - 'man:name' the man-page for `name' in the lowest `section'.
+# - 'name.section' the man-page for `name' in `section'.
+# - 'name' the man-page for `name' in the lowest `section'.
+# Globals :
+# $TMP_INPUT : (read-only)
+# $ARGS_DONE : (read-write) arguments with a corresponding file
+# are added to variable ARGS_DONE.
+# Output : the decompressed files corresponding to the arguments
+# Return : 0 always, all errors are tolerated or fatal.
+#
+supercat()
+{
+ local _file;
+ local _filespec;
+ local _args;
+ local _mode;
+ local _sequence;
+ if [ "$#" -eq 0 ]; then
+ error 1 "supercat needs at least 1 arg";
+ fi;
+ # remove enclosing quotes and space characters
+ _args="$(output $* | grep -e "^ *'.\+'"'$' |
+ sed -e '\|^ *\(.*\) *$|s||\1|')";
+ if [ "$_args" = "" ]; then
+ error 1 "supercat : arguments are not quoted.";
+ fi;
+ while [ "$_args" != "" ]; do
+ _filespec="$(get_next_quoted $_args)";
+ _args="$(shift_quoted $_args)";
+ if [ "$_filespec" = "" ]; then
+ continue;
+ fi;
+ if [ "$_filespec" = "-" ]; then
+ catz "$TMP_INPUT";
+ register_done_file "-";
+ continue;
+ fi
+ if [ "$ENABLE_MANPAGES" = "yes" ]; then
+ if [ "$OPT_MAN" = "yes" ]; then
+ _sequence="Manpage File";
+ else
+ _sequence="File Manpage";
+ fi;
+ else
+ _sequence="File";
+ fi;
+ _done="no";
+ for _mode in $_sequence; do
+ case "$_mode" in
+ File)
+ if [ -f "$_filespec" -a -r "$_filespec" ]; then
+ catz "$_filespec";
+ register_done_file "$_filespec";
+ _done="yes";
+ break;
+ fi;
+ ;;
+ Manpage)
+ _manfile="$(manpage_search_filespec "$_filespec")";
+ if [ "$?" -eq 0 ]; then
+ catz "$_manfile";
+ register_done_file "$_manfile";
+ _done="yes";
+ break;
+ fi;
+ ;;
+ esac;
+ done;
+ if [ "$_done" != "yes" ]; then
+ echo2 \"$_filespec\" is neither a file nor a man-page.;
+ fi;
+ done;
+}
+
+########################################################################
+# tmp_cat ()
+#
+# output the temporary cat file (the concatenation of all input)
+#
+tmp_cat()
+{
+ cat "$TMP_CAT";
+}
+
+########################################################################
+# tmp_create ()
+#
+# create temporary file
+#
+# Output : file generated title
+#
+tmp_create()
+{
+ local _i;
+ local _tmp="";
+ local _prefix="${TEMP_DIR}/.${PROGRAM_NAME}.";
+ if [ "$TEMP_DIR" = "" ]; then
+ error 1 "Temporary directory must be determined first.";
+ fi;
+ if [ "$HAS_MKTEMP" = "yes" ]; then
+ # unquoted is ok, because mktemp output has no space chars
+ _tmp="$(mktemp "${_prefix}.XXXXXX" 2>/dev/null)"; # automatic
+ if [ "$_tmp" = "" ]; then
+ HAS_MKTEMP="no"; # try manually
+ else
+ if [ ! -e "$_tmp" ]; then
+ echo -n >"$_tmp";
+ fi;
+ output "$_tmp";
+ return 0;
+ fi;
+ fi;
+ if [ "$HAS_MKTEMP" != "yes" ]; then
+ _tmp=""; # manual determination
+ for _i in a b c d e f g h i j k l m n o p q r s t u v w x y z \
+ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z; do
+ _tmp="${_prefix}$$${_i}";
+ if [ -e "$_tmp" ]; then
+ _tmp="";
+ continue;
+ else
+ break;
+ fi;
+ done;
+ fi;
+ if [ "$_tmp" = "" ]; then
+ error 1 "Could not manually create temporary file.";
+ fi
+ echo -n >"$_tmp";
+ output "$_tmp";
+}
+
+########################################################################
+# unquote (<arg>*)
+#
+# Remove quotes around each argument and escape all space characters
+# by a backslash `\'.
+#
+# Output : the same number of arguments, but each processed.
+#
+unquote()
+{
+ local _res;
+ local _a;
+ local _args;
+ [ "$#" = 0 ] && return;
+ _res="";
+ for _a in "$@"; do
+ _unq="$(eval output $_a | sed -e '\| |s||\\ |g')";
+ if [ "$_res" = "" ]; then
+ _res="$_unq";
+ else
+ _res="$_res $_unq";
+ fi;
+ done;
+ output "$_res";
+}
+
+########################################################################
+# usage ()
+#
+# print usage information to stderr
+#
+usage()
+{
+ echo2;
+ version;
+ cat >&2 <<EOF
+Copyright (C) 2001 Free Software Foundation, Inc.
+This is free software licensed under the GNU General Public License.
+
+Usage : $PROGRAM_NAME [options] [file] [-]
+ [manpage.x] [man:manpage] [man:manpage(x)] ...
+
+Display groff files, standard input, and/or Unix manual pages with
+gxditview in X window or in a text pager.
+"-" stands for including standard input.
+"manpage" is the name of a man-page, "x" its section.
+All parameters and standard input are decompressed on-the-fly (by zcat).
+
+-c --stdout tty output without a pager
+-h --help print this usage message.
+-Q --source output as roff source.
+-T --device set device for X or tty output.
+-v --version print version information.
+-X --dpi=res set resolution to "res" ("75" or "100" (default)).
+--man check file arguments first on being man-pages.
+--manpath=path preset path for searching man-pages, "" means disable.
+--xrdb=opt pass "opt" as option to gxditview (several allowed).
+All other options are interpreted as "groff" parameters and tranferred
+unmodified to "grog".
+EOF
+
+ if [ "$HAS_OPTS_GNU" != "yes" ]; then
+ cat >&2 <<EOF
+
+Your system does not support GNU long options. All options starting
+with double-minus are not available.
+EOF
+ echo2;
+ fi;
+}
+
+########################################################################
+# version ()
+#
+# print version information to stderr
+#
+version()
+{
+ echo2 "$PROGRAM_NAME $PROGRAM_VERSION of $LAST_UPDATE";
+}
+
+########################################################################
+# main
+########################################################################
+
+# The main area contains the following parts:
+# - argument parsing
+# - temporary files
+# - display
+
+########################################################################
+# main : argument parsing
+#
+set -- $(normalize_args "$@");
+
+# $* is garanteed to have a "--" argument, separating opts and params.
+# Note that all arguments to options and all non-option parameters are
+# enclosed in single quotes, while options are not quoted. The quotes
+# must be removed before being used, see function `unqote'. For example,
+# -X -m 'man' -- 'file1' '-' 'file2'
+
+# parse options
+until [ "$1" = "--" -o "$1" = "'--'" ]; do
+ # Note: arguments to options are quoted; these quotes must be handled.
+ #
+ _opt="$1";
+ shift;
+ case "$_opt" in
+ -h|--help)
+ usage;
+ leave;
+ ;;
+ -Q|--source) # output source code (`Quellcode').
+ OPT_SOURCE="yes";
+ ;;
+ -T|--device) # device, non-X* go to stdout, arg
+ _arg="$(get_next_quoted $*)";
+ set -- $(shift_quoted $*);
+ case "$_arg" in
+ X75)
+ OPT_DEVICE="";
+ OPT_DPI=75;
+ ;;
+ X100)
+ OPT_DEVICE="";
+ OPT_DPI=100;
+ ;;
+ *)
+ OPT_DEVICE="$_arg";
+ OPT_DPI="";
+ ;;
+ esac;
+ ;;
+ -v|--version)
+ version;
+ leave;
+ ;;
+ -X) # set X resolution 75 dpi (default 100).
+ OPT_DEVICE="";
+ OPT_DPI=75;
+ ;;
+ --man) # interpret all file params as man-pages
+ OPT_MAN="yes";
+ if [ "$ENABLE_MANPAGES" != "yes" ] ; then
+ error "confilicting options --man and --manpath.";
+ fi;
+ ;;
+ --manpath) # specify search path for man-pages, arg
+ OPT_MANPATH="$(get_next_quoted $*)";
+ set -- $(shift_quoted $*);
+ if [ "$OPT_MANPATH" = "" ]; then
+ ENABLE_MANPAGES="no";
+ if [ "$OPT_MAN" = "yes" ] ; then
+ error "confilicting options --man and --manpath.";
+ fi;
+ else
+ ENABLE_MANPAGES="yes";
+ fi;
+ HAS_MANW="";
+ ;;
+ --title)
+ OPT_TITLE="$(get_next_quoted $*)";
+ set -- $(shift_quoted $*);
+ ;;
+ --xrdb) # add X resource for gxditview, arg
+ _arg="$(get_next_quoted $*)";
+ set -- $(shift_quoted $*);
+ OPT_XRDB="$(append_args "$OPT_XRDB" "$_arg")";
+ ;;
+ -?)
+ _opt_char="$(output $_opt | sed -e '\|-.|s|-||')";
+ if is_substring_of "$_opt_char" "${GROFF_SHORTOPTS}"; then
+ OTHER_OPTIONS="$(append_args "$OTHER_OPTIONS" "$_opt")";
+ elif is_substring_of "$_opt_char" "${GROFF_ARG_SHORTS}"; then
+ OTHER_OPTIONS="$(\
+ append_args $OTHER_OPTIONS "${1}$(unquote ${2})")";
+ shift; # argument
+ else
+ error 1 "Unknown option : $1";
+ fi;
+ ;;
+ *) error 1 "main : error on argument parsing : $*"; ;;
+ esac;
+done;
+shift; # remove `--' argument
+
+unset _arg
+unset _opt
+
+# Remaining arguments are file names, each enclosed in single quotes.
+# Function supercat expects such arguments.
+
+if [ "$#" -eq 0 ]; then # use "-" for standard input
+ set -- "'-'";
+fi;
+FILE_ARGS="$*"; # all file parameters; do not change
+
+# setup for man-pages
+
+if [ "$ENABLE_MANPAGES" = "yes" -a "$HAS_MANW" != "yes" ]; then
+ MAN_PATH="$(get_manpath)";
+ if [ "$MAN_PATH" = "" ]; then
+ ENABLE_MANPAGES="no";
+ fi;
+fi;
+
+########################################################################
+# main : temporary files
+#
+# save standard input
+TMP_INPUT="$(tmp_create)";
+save_stdin_if_any;
+
+# built up title consisting of processed filespecs
+TMP_DONE="$(tmp_create)";
+output "$PROGRAM_NAME :" > $TMP_DONE;
+
+# output parameter files (and stdin) decompressed into temporary file
+TMP_CAT="$(tmp_create)";
+supercat $FILE_ARGS >"$TMP_CAT"; # this does the main work
+set -- $(ls -l -L "$TMP_CAT"); # check on empty
+if [ "$5" -eq 0 ]; then
+ echo2 "input is empty, nothing to display.";
+ leave;
+fi;
+
+########################################################################
+# main : display
+#
+_mode="";
+if [ "$OPT_SOURCE" = "yes" ]; then # output source code
+ _mode="source";
+elif [ "$OPT_DEVICE" != "" ]; then # non-X device, cat to stdout
+ _mode="device";
+elif [ "$DISPLAY" != "" ]; then # within X window
+ _mode="X";
+else # tty
+ _mode="tty";
+fi;
+
+case "$_mode" in
+ source)
+ tmp_cat;
+ ;;
+ device)
+ _groggy="$(tmp_cat | grog $OTHER_OPTIONS -T"${OPT_DEVICE}")";
+ tmp_cat | eval $_groggy;
+ ;;
+ X)
+ if [ "$OPT_DPI" = "" ]; then
+ OPT_DPI="$(check_dpi)"; # sanity check for using 100 dpi default
+ fi;
+ _groggy="$(tmp_cat | grog $OTHER_OPTIONS -TX"${OPT_DPI}" -Z )";
+ tmp_cat | eval $_groggy | \
+ gxditview $OPT_XRDB -title "$(get_title)" -;
+ ;;
+ tty)
+ if [ "$OPT_DPI" = "" ]; then
+ error 1 "Not in X window, no X device available.";
+ fi;
+ _groggy="$(tmp_cat | grog $OTHER_OPTIONS -Tlatin1)";
+ if [ "$PAGER" = "" ]; then
+ _pager=less;
+ else
+ _pager=$PAGER;
+ fi;
+ tmp_cat | eval $_groggy | $_pager;
+ ;;
+esac;
+clean_up;