[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
PATCH: add dejagnu(1) multi-launcher [revised]
From: |
Jacob Bachmeyer |
Subject: |
PATCH: add dejagnu(1) multi-launcher [revised] |
Date: |
Thu, 20 Dec 2018 01:05:45 -0600 |
User-agent: |
Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.22) Gecko/20090807 MultiZilla/1.8.3.4e SeaMonkey/1.1.17 Mnenhy/0.7.6.0 |
This patch is the long-promised dejagnu(1) multi-launcher, revised to
include also its first command "dejagnu help" in this patch to ensure
that it works properly.
I had previously mentioned some files that were part of this work that
have been renamed between then and now. Specifically,
"testsuite/lib/dejagnu.exp" is now "testsuite/lib/launcher.exp" and the
entire "testsuite/dejagnu.launcher/" directory has been renamed to
"testsuite/launcher.all/" after I decided that, since the launcher is
run using a LAUNCHER variable rather than a DEJAGNU variable (obvious
potential for confusion with that bad choice that was avoided from the
start), using "--tool launcher" to test the launcher is more appropriate
than using "--tool dejagnu" even though the launcher is installed under
the "dejagnu" name.
Notable differences from the previous version of this patch include a
small change to dejagnu(1) to prevent shellcheck from complaining.
There are also some insignificant changes to doc/dejagnu.1. The new
"dejagnu help" command is included in this patch, complete with
documentation and tests. This patch also includes the update to
Makefile.am that was missing previously.
----
NEWS item:
X. A shell command "dejagnu" is added as a place to hang various auxiliary
commands not directly involved with running tests. The "runtest"
command will remain for that purpose for the forseeable future.
ChangeLog entries:
* Makefile.am (EXTRA_DIST): Add "dejagnu" launcher script and
contents of $(commands_DATA).
(bin_SCRIPTS): Add "dejagnu" launcher script.
(commandsdir): Installation directory for "dejagnu" subcommands is
$(pkgdatadir)/commands.
(commands_DATA): New, contains "commands/help.sh" as initial item.
(TESTSUITE_FILES): Add testsuite for same.
(DEJATOOL): Add "launcher" to list of tools to test.
(dist_man_MANS): Add man pages for "dejagnu" and "dejagnu help".
* doc/dejagnu.texi (Running other DejaGnu commands): New chapter.
(Invoking dejagnu): New node for dejagnu(1) launcher script.
(Invoking dejagnu help): New node.
* doc/dejagnu.1: New man page.
* doc/dejagnu-help.1: New man page.
* dejagnu: New script.
* commands/help.sh: New dejagnu subcommand for reading manpages.
* testsuite/launcher.all/command.exp: New file.
* testsuite/launcher.all/command/commands/bar-baz.awk: New file.
* testsuite/launcher.all/command/commands/bar.awk: New file.
* testsuite/launcher.all/command/commands/bar.sh: New file.
* testsuite/launcher.all/command/commands/baz-quux.gawk: New file.
* testsuite/launcher.all/command/commands/foo.sh: New file.
* testsuite/launcher.all/command/commands/foo.tcl: New file.
* testsuite/launcher.all/help.exp: New file.
* testsuite/launcher.all/interp.exp: New file.
* testsuite/launcher.all/verbose.exp: New file.
* testsuite/lib/launcher.exp: New file.
----
patch:
----
diff --git a/Makefile.am b/Makefile.am
index 1740d1a..1f19846 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-# Copyright (C) 1992-2016 Free Software Foundation, Inc.
+# Copyright (C) 1992-2016, 2018 Free Software Foundation, Inc.
#
# This file is part of DejaGnu.
#
@@ -21,9 +21,10 @@
AUTOMAKE_OPTIONS = dejagnu
export DEJAGNU
-EXTRA_DIST = ChangeLog-1992 MAINTAINERS runtest \
+EXTRA_DIST = ChangeLog-1992 MAINTAINERS dejagnu runtest \
$(pkgdata_DATA) $(config_DATA) $(baseboard_DATA) \
- $(TESTSUITE_FILES) $(XML) $(CONTRIB) $(TEXINFO_TEX)
+ $(commands_DATA) $(TESTSUITE_FILES) $(TEXINFO_TEX)\
+ $(XML) $(CONTRIB)
DISTCLEANFILES = options-init.exp stats-init.exp
@@ -31,7 +32,7 @@ DISTCLEANFILES = options-init.exp stats-init.exp
all-local:
@echo "Done. Now run 'make install'."
-bin_SCRIPTS = runtest
+bin_SCRIPTS = dejagnu runtest
include_HEADERS = dejagnu.h
pkgdata_DATA = \
@@ -57,6 +58,10 @@ pkgdata_DATA = \
lib/tip.exp \
lib/utils.exp
+commandsdir = $(pkgdatadir)/commands
+commands_DATA = \
+ commands/help.sh
+
configdir = $(pkgdatadir)/config
config_DATA = \
config/README \
@@ -142,6 +147,16 @@ CONTRIB = contrib/compare_tests contrib/sum2junit.sh \
# Testsuite.
TESTSUITE_FILES = \
+ testsuite/launcher.all/command.exp \
+ testsuite/launcher.all/command/commands/bar-baz.awk \
+ testsuite/launcher.all/command/commands/bar.awk \
+ testsuite/launcher.all/command/commands/bar.sh \
+ testsuite/launcher.all/command/commands/baz-quux.gawk \
+ testsuite/launcher.all/command/commands/foo.sh \
+ testsuite/launcher.all/command/commands/foo.tcl \
+ testsuite/launcher.all/help.exp \
+ testsuite/launcher.all/interp.exp \
+ testsuite/launcher.all/verbose.exp \
testsuite/runtest.libs/topdir/subdir1/subsubdir1/subsubfile1 \
testsuite/runtest.libs/topdir/subdir1/subfile1 \
testsuite/runtest.libs/topdir/subdir1/subfile2 \
@@ -158,13 +173,14 @@ TESTSUITE_FILES = \
testsuite/runtest.main/options/testsuite/null.test/null.exp \
testsuite/runtest.main/stats.exp \
testsuite/runtest.main/stats/testsuite/stat.test/stats-sub.exp \
+ testsuite/lib/launcher.exp \
testsuite/lib/libdejagnu.exp \
testsuite/lib/libsup.exp \
testsuite/lib/runtest.exp \
testsuite/lib/util-defs.exp \
testsuite/libdejagnu/tunit.exp
-DEJATOOL = libdejagnu runtest
+DEJATOOL = launcher libdejagnu runtest
RUNTEST = ${top_srcdir}/runtest
@@ -175,5 +191,5 @@ unit_SOURCES = testsuite/libdejagnu/unit.cc
# Documentation.
TEXINFO_TEX = doc/texinfo.tex
-dist_man_MANS = doc/runtest.1
+dist_man_MANS = doc/dejagnu.1 doc/dejagnu-help.1 doc/runtest.1
info_TEXINFOS = doc/dejagnu.texi
diff --git a/commands/help.sh b/commands/help.sh
new file mode 100644
index 0000000..7da4d5f
--- /dev/null
+++ b/commands/help.sh
@@ -0,0 +1,78 @@
+#!/bin/sh
+# help.sh -- "dejagnu help" command
+#
+# Copyright (C) 2018 Free Software Foundation, Inc.
+#
+# This file is part of DejaGnu.
+#
+# DejaGnu 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 3 of the License, or
+# (at your option) any later version.
+#
+# DejaGnu 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 DejaGnu; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+# ##help
+# #Usage: dejagnu help [options...] <command>
+# # --verbose, -v Emit additional messages
+# # --path, -w Passed to man(1)
+# # -W Passed to man(1)
+# ##end
+
+# This script was written by Jacob Bachmeyer.
+
+args=
+command=dejagnu
+verbose=0
+for a in "$@"; do
+ case $a in
+ -v|--v|-verb*|--verb*) verbose=$((verbose + 1)) ;;
+ -w|-W|--path) args="${args} ${a}" ;;
+ -*) echo Unrecognized option "\"$a\"" ;;
+ *) command="${command}-${a}" ;;
+ esac
+done
+
+if expr "$verbose" \> 0 > /dev/null ; then
+ echo Verbose level is $verbose
+fi
+
+## Get the location of this script and check for nearby "doc" dir.
+commdir="$(echo "$0" | sed -e 's@/[^/]*$@@')"
+docdir="$(echo "$commdir" | sed -e 's@/[^/]*$@@')/doc"
+
+if expr "$verbose" \> 0 > /dev/null ; then
+ echo Running from "$commdir"
+ if expr "$verbose" \> 1 > /dev/null ; then
+ echo Probing "$docdir"
+ fi
+fi
+
+if test -d "$docdir"; then
+ if expr "$verbose" \> 1 > /dev/null ; then
+ echo Probing "${docdir}/${command}.1"
+ fi
+ if test -r "${docdir}/${command}.1" ; then
+ command="${docdir}/${command}.1"
+ fi
+fi
+
+# Word splitting on the "args" variable is intended.
+# Globbing is not, but ensure that verbose output will show the problem.
+
+if expr "$verbose" \> 0 > /dev/null ; then
+ #shellcheck disable=SC2086
+ echo Forwarding to man $args "\"$command\""
+fi
+
+#shellcheck disable=SC2086
+exec man $args "$command"
+
+#EOF
diff --git a/dejagnu b/dejagnu
new file mode 100755
index 0000000..4b174db
--- /dev/null
+++ b/dejagnu
@@ -0,0 +1,453 @@
+#!/bin/sh
+#
+# Copyright (C) 2018 Free Software Foundation, Inc.
+#
+# This file is part of DejaGnu.
+#
+# DejaGnu 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 3 of the License, or
+# (at your option) any later version.
+#
+# DejaGnu 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 DejaGnu; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Portions from runtest Copyright (C) 1992-2016 Free Software Foundation, Inc.
+
+# This script was written by Jacob Bachmeyer. Portions of this script are
+# adapted from the existing runtest script originally written by Rob Savoye.
+
+# This script finds an implementation for the command given, finds the
+# proper interpreter, and then dispatches the command. This script can
+# either be run with a command name as the first (few) argument(s), via a
+# link from the command name, or some combination of those.
+
+# shellcheck disable=SC2209
+# The shellcheck tool complains about assigning certain constant strings to
+# variables. In this script, the intended meaning is obvious in context.
+
+# ##help
+# #Usage: dejagnu <command> [--help|options...]
+# #Usage: dejagnu --help
+# #Usage: dejagnu --version
+# # --help Print help text
+# # --version Print DejaGnu version
+# ##end
+
+# list of extensions supported for commands in priority order
+readonly Variants="gawk awk tcl exp bash sh"
+
+## Recognize options
+
+# For testing and development
+override_ext=
+if test x"$1" = x--DGTimpl ; then
+ override_ext=$2
+ shift 2
+fi
+
+want_help=false
+want_version=false
+verbose=0
+for a in "$@"; do
+ case $a in
+ --help) want_help=true ;;
+ -v|--v|-verbose|--verbose) verbose=$((verbose + 1)) ;;
+ -V|--V|-version|--version) want_version=true ;;
+ esac
+done
+
+if expr "$verbose" \> 0 > /dev/null ; then
+ echo Verbose level is $verbose
+fi
+
+## Get the file name of this script and deduce @address@hidden
+
+bindir="$(echo "$0" | sed -e 's@/[^/]*$@@')"
+if expr "$verbose" \> 0 > /dev/null ; then
+ echo Running launcher from "$bindir"
+fi
+
+## Find the commands.
+
+# If running from source tree, they are in ./commands/ relative to this script.
+# If installed, they are in @datadir@/dejagnu/commands/ on the system.
+
+# This makes the same assumption as in runtest that one of these holds:
+#
+# @datadir@ == @bindir@/../share
+# @datadir@ == @bindir@/../../share
+# @datadir@ == /usr/share
+# @datadir@ == /usr/local/share
+
+if test -n "$DEJAGNULIBS" ; then
+ commdir="${DEJAGNULIBS}/commands"
+ datadir="${DEJAGNULIBS}"
+elif test -d "${bindir}/commands" && test -f "${bindir}/runtest.exp" ; then
+ if expr "$verbose" \> 1 > /dev/null ; then
+ echo Running from source directory
+ fi
+ commdir="${bindir}/commands"
+ datadir="${bindir}"
+else
+ commdir=
+ for i in \
+ "$(echo "$bindir" | sed -e 's@/[^/]*$@/share/dejagnu@')" \
+ "$(echo "$bindir" | sed -e 's@/[^/]*/[^/]*$@/share/dejagnu@')" \
+ /usr/share/dejagnu /usr/local/share/dejagnu
+ do
+ if expr "$verbose" \> 1 > /dev/null ; then
+ echo Probing directory "$i"/commands
+ fi
+ if test -d "$i"/commands ; then
+ commdir="$i"/commands
+ datadir="$i"
+ break
+ fi
+ done
+fi
+
+if test -z "${commdir}" ; then
+ echo ERROR: could not find command directory.
+ exit 2
+fi
+
+if expr "$verbose" \> 0 > /dev/null ; then
+ echo Looking for commands in "$commdir"
+fi
+
+## Get the name of the requested command.
+
+# Are we just looking for version information?
+if $want_version ; then
+ frame_version=$(grep '^set frame_version' "${datadir}/runtest.exp" \
+ | sed 's/^[^0-9]*//')
+ echo 'dejagnu auxiliary launcher (DejaGnu)' "$frame_version"
+ exit 0
+fi
+
+# Remove any leading autoconf platform prefix and the "dejagnu" prefix.
+command="$(basename "$0" | sed -e 's/^.*-\?dejagnu-\?//')"
+commext=
+
+while true
+do
+ if test -z "${command}" ; then
+ if expr "$1" : - > /dev/null ; then
+ break
+ fi
+ command="$1"
+ shift
+ fi
+ if expr "$verbose" \> 2 > /dev/null ; then
+ echo Looking for "${commdir}/${command}.*"
+ fi
+ for ext in ${Variants}
+ do
+ if test -f "${commdir}/${command}.$ext" ; then
+ commext="$commext $ext"
+ fi
+ done
+ if expr "$1" : - > /dev/null ; then
+ break
+ fi
+ if test -n "$commext" ; then
+ break
+ fi
+ if test -n "$1" ; then
+ command="${command}-$1"
+ shift
+ else
+ break
+ fi
+done
+
+if test -z "$commext" && test -n "$command" ; then
+ echo ERROR: could not resolve command "$command"
+ exit 2
+fi
+
+if expr "$verbose" \> 0 > /dev/null ; then
+ if test -n "$command"; then
+ if expr "$verbose" \> 1 > /dev/null ; then
+ echo Found subcommand "$command" with variants: "$commext"
+ else
+ echo Found subcommand "$command"
+ fi
+ else
+ echo Running nothing.
+ fi
+fi
+
+## Find interpreters.
+
+# Awk and GNU awk
+if test -n "$AWK" ; then
+ awkbin="$AWK"
+elif test -x "${bindir}/awk" ; then
+ awkbin="${bindir}/awk"
+else
+ awkbin=awk
+fi
+if test -n "$GAWK" ; then
+ gawkbin="$GAWK"
+elif test -x "${bindir}/gawk" ; then
+ gawkbin="${bindir}/gawk"
+else
+ gawkbin=gawk
+fi
+if command -v "$awkbin" > /dev/null 2>&1 ; then
+ have_awk=true
+else
+ have_awk=false
+fi
+if command -v "$gawkbin" > /dev/null 2>&1 ; then
+ have_gawk=true
+else
+ have_gawk=false
+fi
+# substitute GNU awk for awk if needed
+if $have_gawk ; then
+ if $have_awk ; then : ; else
+ have_awk=$have_gawk
+ awkbin=$gawkbin
+ fi
+fi
+# is "awk" actually GNU Awk?
+if $have_awk ; then
+ if "$awkbin" --version | sed 1q | grep -qi 'GNU Awk' ; then
+ have_gawk_as_awk=true
+ else
+ have_gawk_as_awk=false
+ fi
+fi
+if expr "$verbose" \> 2 > /dev/null ; then
+ if $have_awk ; then
+ echo Awk interpreter is "$awkbin"
+ else
+ echo Awk interpreter was not found
+ fi
+ if $have_gawk ; then
+ echo GNU Awk interpreter is "$gawkbin"
+ else
+ echo GNU Awk interpreter was not found
+ fi
+fi
+
+
+# Bash
+if test -n "$BASH" ; then
+ bashbin="$BASH"
+elif test -x "${bindir}/bash" ; then
+ bashbin="${bindir}/bash"
+elif test -x /bin/bash ; then
+ bashbin=/bin/bash
+else
+ bashbin=bash
+fi
+if command -v "$bashbin" > /dev/null 2>&1 ; then
+ have_bash=true
+else
+ have_bash=false
+fi
+if expr "$verbose" \> 2 > /dev/null ; then
+ if $have_bash ; then
+ echo Bash interpreter is "$bashbin"
+ else
+ echo Bash interpreter was not found
+ fi
+fi
+
+# Bourne shell
+# This script is running, therefore we have a Bourne shell.
+have_sh=true
+
+# Expect
+# DejaGnu configure bails out if Expect is not available, but this script
+# can be run from the source directory without first running configure.
+if test -n "$EXPECT" ; then
+ expectbin="$EXPECT"
+elif test -x "${bindir}/expect" ; then
+ expectbin="${bindir}/expect"
+else
+ expectbin=expect
+fi
+if command -v "$expectbin" > /dev/null 2>&1 ; then
+ have_expect=true
+else
+ have_expect=false
+fi
+if expr "$verbose" \> 2 > /dev/null ; then
+ if $have_expect ; then
+ echo Expect interpreter is "$expectbin"
+ else
+ echo Expect interpreter was not found
+ fi
+fi
+
+# Tcl
+if test -n "$TCLSH" ; then
+ tclbin="$TCLSH"
+elif test -x "${bindir}/tclsh" ; then
+ tclbin="${bindir}/tclsh"
+else
+ tclbin=tclsh
+fi
+# substitute expect if needed
+if command -v "$tclbin" > /dev/null 2>&1 ; then :
+elif command -v "$expectbin" > /dev/null 2>&1 ; then tclbin="$expectbin"
+fi
+if command -v "$tclbin" > /dev/null 2>&1 ; then
+ have_tcl=true
+else
+ have_tcl=false
+fi
+if expr "$verbose" \> 2 > /dev/null ; then
+ if $have_tcl ; then
+ echo Tcl interpreter is "$tclbin"
+ else
+ echo Tcl interpreter was not found
+ fi
+fi
+
+## Select a variant.
+
+if test -n "$override_ext" ; then
+ selected_ext="$override_ext"
+else
+ selected_ext=
+ for v in $commext
+ do
+ case $v in
+ awk)
+ if $have_awk ; then
+ selected_ext=awk
+ break
+ fi
+ ;;
+ bash)
+ if $have_bash ; then
+ selected_ext=bash
+ break
+ fi
+ ;;
+ exp)
+ if $have_expect ; then
+ selected_ext=exp
+ break
+ fi
+ ;;
+ gawk)
+ if $have_gawk ; then
+ selected_ext=gawk
+ break
+ fi
+ ;;
+ tcl)
+ if $have_tcl ; then
+ selected_ext=tcl
+ break
+ fi
+ ;;
+ sh)
+ selected_ext=sh
+ break
+ ;;
+ *)
+ echo ERROR: '(select-variant)' unrecognized variant "$v"
+ ;;
+ esac
+ done
+ if test -z "$selected_ext" && test -n "$command" ; then
+ echo ERROR: no variant of "$command" was selected
+ exit 2
+ fi
+fi
+
+if test -n "$command" && expr "$verbose" \> 0 > /dev/null ; then
+ if test -n "$override_ext" ; then
+ echo Selected variant "$selected_ext" by override
+ else
+ echo Selected variant "$selected_ext"
+ fi
+fi
+
+## Dispatch to the selected command.
+
+# Are we just looking for a usage message?
+if $want_help ; then
+ if test -z "$command" ; then
+ # want help on the launcher itself
+ help_file=$0
+ else
+ help_file="${commdir}/${command}.${selected_ext}"
+ fi
+ if test ! -r "$help_file" ; then
+ echo ERROR: file "'$help_file'" is not readable
+ exit 2
+ fi
+ if grep -q '#help' "$help_file" \
+ && grep -q '#end' "$help_file"; then : ; else
+ echo ERROR: file "'$help_file'" does not contain a help message
+ exit 2
+ fi
+ help_prefix_pat=$(grep '#help' "$help_file" \
+ | sed 's/#help.*$//;1q' | tr '[:print:][:blank:]' .)
+ if expr "$verbose" \> 1 > /dev/null ; then
+ echo Extracting help from "'$help_file'" with prefix
"'$help_prefix_pat'"
+ fi
+ sed -n < "$help_file" \
+ -e '1,/#help/d' \
+ -e '/^'"$help_prefix_pat"'#end/q' \
+ -e 's/^'"$help_prefix_pat"'//;p'
+ exit 0
+fi
+
+if test -z "$command" ; then
+ if test -n "$override_ext" ; then
+ case $selected_ext in
+ awk) $have_awk; exit $? ;;
+ bash) $have_bash; exit $? ;;
+ exp) $have_expect; exit $? ;;
+ gawk) $have_gawk; exit $? ;;
+ tcl) $have_tcl; exit $? ;;
+ sh) $have_sh; exit $? ;;
+ *) exit 2 ;;
+ esac
+ else
+ echo ERROR: no command given
+ exit 2
+ fi
+fi
+
+case $selected_ext in
+ awk)
+ if $have_gawk_as_awk ; then
+ exec "$awkbin" --posix -f "${commdir}/${command}.awk" -- ${1+"$@"}
+ else
+ exec "$awkbin" -f "${commdir}/${command}.awk" -- ${1+"$@"}
+ fi
+ ;;
+ bash) exec "$bashbin" -- "${commdir}/${command}.bash" ${1+"$@"} ;;
+ exp) exec "$expectbin" -- "${commdir}/${command}.exp" ${1+"$@"} ;;
+ gawk) exec "$gawkbin" -f "${commdir}/${command}.gawk" -- ${1+"$@"} ;;
+ tcl) exec "$tclbin" "${commdir}/${command}.tcl" ${1+"$@"} ;;
+ sh) exec /bin/sh "${commdir}/${command}.sh" ${1+"$@"} ;;
+ echo)
+ echo command: "${command}"
+ echo args: ${1+"$@"}
+ exit 0
+ ;;
+ *)
+ echo ERROR: '(run-variant)' unrecognized variant "$selected_ext"
+ exit 2
+ ;;
+esac
+
+#EOF
diff --git a/doc/dejagnu-help.1 b/doc/dejagnu-help.1
new file mode 100644
index 0000000..110da92
--- /dev/null
+++ b/doc/dejagnu-help.1
@@ -0,0 +1,50 @@
+.\" Copyright (C), 2018 Free Software Foundation, Inc.
+.\" You may distribute this file under the terms of the GNU Free
+.\" Documentation License.
+.Dd December 19, 2018
+.Os GNU
+.Dt DEJAGNU-HELP 1 URM
+.Sh NAME
+.Nm dejagnu\ help
+.Nd display manual pages for DejaGnu auxiliary commands
+.Sh SYNOPSIS
+.Nm dejagnu\ help
+.Op Ar options...
+.Ao Ar command Ac
+.Sh DESCRIPTION
+The
+.Nm
+command displays long-form documentation for DejaGnu auxiliary commands.
+.Sh OPTIONS
+.Bl -tag -width ".Fl v , -verbose"
+.It Fl v , -verbose
+Emit additional output describing the operation of
+.Nm
+itself.
+.It Fl w , -path
+This option is simply passed on to
+.Nm man .
+.It Fl W
+This option is simply passed on to
+.Nm man .
+.El
+.Sh FILES
+The
+.Nm
+command checks for man pages in a
+.Pa doc/
+directory next to the
+.Pa commands/
+directory where this script is located.
+If the page is found there, a full file name is given to
+.Nm man .
+Otherwise, only the command name is given and the search described in
+.Xr man 1
+is performed.
+.Sh SEE ALSO
+.Xr man 1
+.Sh AUTHORS
+Jacob Bachmeyer
+.Sh BUGS
+Currently only supports man pages.
+.\" LocalWords: Dt URM Nm DejaGnu Ao Xr
diff --git a/doc/dejagnu.1 b/doc/dejagnu.1
new file mode 100644
index 0000000..5ece6c1
--- /dev/null
+++ b/doc/dejagnu.1
@@ -0,0 +1,141 @@
+.\" Copyright (C) 2018 Free Software Foundation, Inc.
+.\" You may distribute this file under the terms of the GNU Free
+.\" Documentation License.
+.Dd December 17, 2018
+.Os GNU
+.Dt DEJAGNU 1 URM
+.Sh NAME
+.Nm dejagnu
+.Nd DejaGnu auxiliary command launcher
+.Sh SYNOPSIS
+.Nm dejagnu
+.Ao Ar command Ac
+.Op Fl -help \*(Ba Ar options...
+.Nm
+.Fl -help
+.Nm
+.Fl -version
+.Sh DESCRIPTION
+The
+.Nm
+command finds a script that implements the requested
+.Ar command ,
+selects from multiple implementations if available
+according to a fixed internal list, and executes the command.
+.Sh OPTIONS
+.Bl -tag -width ".Fl -version"
+.It Fl -help
+Print a help message instead of running a command.
+If no command is given, prints brief usage for
+.Nm
+itself.
+.It Fl V , -version
+Print a version banner for the launcher itself including the version of
DejaGnu.
+Any command given is ignored.
+.It Fl v , -verbose
+Emit additional output describing the operation of the
+.Nm
+launcher itself.
+This option is also passed on to the invoked command.
+.El
+.Pp
+All arguments after the command name are passed to the invoked command.
+.Sh ENVIRONMENT
+.Bl -tag -width ".Ev DEJAGNULIBS"
+.It Ev DEJAGNULIBS
+If set, the location of DejaGnu's library in the filesystem.
+The search described in
+.Sx FILES
+does not happen if
+.Ev DEJAGNULIBS
+is set.
+.It Ev AWK
+Full file name for an Awk interpreter that may or may not actually be GNU Awk.
+If not set,
+.Ev PATH
+will be searched for an
+.Nm awk
+program.
+If the Awk interpreter is actually GNU Awk, the
+.Fl -posix
+option will be given if an Awk implementation is used.
+.It Ev GAWK
+Full file name for GNU Awk. If not set,
+.Ev PATH
+will be searched for a
+.Nm gawk
+program.
+.It Ev BASH
+Full file name for GNU Bash. If not set,
+.Ev PATH
+will be searched for a
+.Nm bash
+program.
+Note that Bash itself sets this variable, even when run as
+.Nm sh ,
+even when running a script.
+.It Ev EXPECT
+Full file name for Expect, which is a Tcl interpreter with the Expect
+extension already loaded. If not set,
+.Ev PATH
+will be searched for an
+.Nm expect
+program. Note that the DejaGnu core is written in Expect, so this
+interpreter should always be available.
+.It Ev TCLSH
+Full file name for a Tcl interpreter. If not set,
+.Ev PATH
+will be searched for a
+.Nm tclsh
+program.
+.El
+.Pp
+Note that GNU Awk is considered a superset of Awk and that Expect is
+considered a superset of Tcl, allowing the former to be used to run scripts
+written for the latter.
+This means that, while Awk programs will generally be run with GNU
+extensions disabled using the
+.Fl -posix
+option to GNU Awk, Tcl programs may be run with either
+.Nm tclsh
+or
+.Nm expect
+and should be written accordingly.
+.Sh FILES
+.Bl -tag -width ".Pa $DEJAGNULIBS/commands"
+.It Pa $DEJAGNULIBS/commands
+If
+.Ev DEJAGNULIBS
+is set, all command scripts are expected to be in this directory.
+.El
+Otherwise, the first directory that actually exists in the following list
+is used, where
+.Pa @bindir@
+represents the directory containing
+.Nm
+itself.
+.Bl -item -offset indent
+.It
+.Pa @bindir@/../share/dejagnu/commands
+.It
+.Pa @bindir@/../../share/dejagnu/commands
+.It
+.Pa /usr/share/dejagnu/commands
+.It
+.Pa /usr/local/share/dejagnu/commands
+.El
+.\" .Sh EXAMPLES
+.Sh SEE ALSO
+The full documentation for DejaGnu is maintained as a Texinfo manual.
+If the
+.Nm info
+program is properly installed at your site, the command
+.Li info dejagnu
+should give you access to the complete manual.
+.Sh AUTHORS
+.An "Jacob Bachmeyer"
+.Sh BUGS
+The command name must precede all other arguments due to limitations of the
+shell.
+.\" LocalWords: Dt URM Nm DejaGnu Ao DEJAGNULIBS DejaGnu's Sx awk posix tclsh
+.\" LocalWords: tcl superset bindir usr Texinfo
diff --git a/doc/dejagnu.texi b/doc/dejagnu.texi
index 7058320..e72f38f 100644
--- a/doc/dejagnu.texi
+++ b/doc/dejagnu.texi
@@ -50,6 +50,7 @@ Free Documentation License''.
@menu
* Introduction::
* Running tests::
+* Running other DejaGnu commands::
* Customizing DejaGnu::
* Extending DejaGnu::
* Unit testing::
@@ -75,6 +76,11 @@ Running tests
* Running runtest: Runtest.
* Output files: Output Files.
+Running other DejaGnu commands
+
+* Invoking dejagnu:: Command line options for the launcher itself.
+* Invoking dejagnu help:: Reading man pages for dejagnu subcommands.
+
Customizing DejaGnu
* Global config file::
@@ -421,7 +427,7 @@ tools you want to test; then, in each test directory, run
@emph{make
check} to build auxiliary programs required by some of the tests, and
run the test suites.
address@hidden Running tests, Customizing DejaGnu, Introduction, Top
address@hidden Running tests, Running other DejaGnu commands, Introduction, Top
@chapter Running tests
There are two ways to execute a testsuite. The most common way is when
@@ -1008,7 +1014,109 @@ make the actions for fail-safe patterns produce
messages starting with
@end itemize
address@hidden Customizing DejaGnu, Extending DejaGnu, Running tests, Top
address@hidden Running other DejaGnu commands, Customizing DejaGnu, Running
tests, Top
address@hidden Running other DejaGnu commands
+
+DejaGnu now features auxiliary commands not directly related to
+running tests, but somehow related to the broader purpose of testing.
+
+These commands are run via the @command{dejagnu} multiplex launcher,
+which locates an appropriate script and the required interpreter and
+then runs the requested command.
+
address@hidden
+* Invoking dejagnu:: Command line options for the launcher itself.
+* Invoking dejagnu help:: Reading man pages for dejagnu subcommands.
address@hidden menu
+
address@hidden Invoking dejagnu, Invoking dejagnu help, Running other DejaGnu
commands, Running other DejaGnu commands
address@hidden Invoking @command{dejagnu}
address@hidden dejagnu, invoking
+
+The @command{dejagnu} launcher is primarily designed to pass most
+options on to the scripts that it runs, but does process the
address@hidden and @option{--version} options entirely internally,
+while also recognizing the @option{--verbose} option.
+
address@hidden
address@hidden <command> [options...]
address@hidden --help
address@hidden --version
address@hidden example
+
+Note that the command names may contain multiple words. In this case,
+the command can be given as separate arguments to @command{dejagnu} or
+combined with dashes (@samp{-}); both forms are equivalent.
+
+All words of the command name must appear before any options. The
+search for a command terminates when an option is found.
+
+Note that the first valid command found is used. A longer command
+name can be shadowed by a shorter command name that happens to be a
+prefix of the longer name, if the command name is given as multiple
+arguments. The equivalent form with the longer command name combined
+using dashes into a single argument will correctly refer to the
+otherwise shadowed command.
+
+The @command{dejagnu} launcher can also be run using symbolic links,
+provided that the shell places the name under which @command{dejagnu}
+was invoked in @code{$0}. Any dash-separated words after ``dejagnu''
+in the name of such a link are taken to be the leading words of a
+command name.
+
+The @command{dejagnu} launcher supports alternate implementations
+depending upon available interpreters.
+
+Options for the @command{dejagnu} launcher itself cannot be
+abbreviated, since the launcher has no way to know which abbreviations
+are unique and which would be ambiguous to the invoked command.
+
address@hidden @asis
+
address@hidden @code{--help}
+Print a help message instead of running a command.
+
address@hidden @code{-V}, @code{--version}
+Print a version banner for the launcher itself including the
+version of DejaGnu. Any command given is ignored.
+
address@hidden @code{-v}, @code{--verbose}
+Emit additional output describing the inner workings of the
address@hidden launcher. This option is also passed on to the
+invoked command.
+
address@hidden table
+
+All arguments after the command name are passed to the invoked command.
+
address@hidden Invoking dejagnu help, , Invoking dejagnu, Running other
DejaGnu commands
address@hidden Invoking @command{dejagnu help}
address@hidden dejagnu help, invoking
+
+The @command{dejagnu help} tool displays long-form documentation for
+DejaGnu auxiliary commands that are invoked using the
address@hidden launcher.
+
address@hidden
address@hidden help} [options...] <command>
address@hidden example
+
+Again, command names may contain multiple words. This command forms
+an operand by joining all words in the command name using dashes
+(@samp{-}) and prepending @samp{dejagnu-}. This is then used as the
+name of a manual page and passed to the @command{man} command.
+
+If the manual page is in a particular directory relative to the script
+implementing this command, a full file name is produced, otherwise,
address@hidden performs its normal search.
+
+The @option{--verbose} option causes additional output describing the
+inner workings of the @command{dejagnu help} command to be produced.
+
+The @option{--path}, @option{-w}, and @option{-W} options are passed
+to @command{man}.
+
address@hidden Customizing DejaGnu, Extending DejaGnu, Running other DejaGnu
commands, Top
@chapter Customizing DejaGnu
@cindex customization
@@ -5502,4 +5610,4 @@ This makes @code{runtest} exit. Abbreviation: @kbd{q}.
@bye
@c LocalWords: subdirectory prepend prepended testsuite filename Expect's svn
address@hidden LocalWords: DejaGnu CVS RCS SCCS
address@hidden LocalWords: DejaGnu CVS RCS SCCS prepending subcommands
diff --git a/testsuite/launcher.all/command.exp
b/testsuite/launcher.all/command.exp
new file mode 100644
index 0000000..eb7b219
--- /dev/null
+++ b/testsuite/launcher.all/command.exp
@@ -0,0 +1,210 @@
+# Copyright (C) 2018 Free Software Foundation, Inc.
+#
+# This file is part of DejaGnu.
+#
+# DejaGnu 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 3 of the License, or
+# (at your option) any later version.
+#
+# DejaGnu 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 DejaGnu; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+# This file was written by Jacob Bachmeyer.
+
+# each element: { launcher_alias
+# { name args envars exit_code output_re... }... }
+set tests {
+ { dejagnu
+ { "#" direct calls }
+
+ { "dejagnu foo as Tcl"
+ {foo -v -v} {EXPECT=true TCLSH=true } 0
+ "Found subcommand foo with variants: tcl sh\n"
+ "Selected variant tcl" }
+ { "dejagnu foo as Tcl via Expect"
+ {foo -v -v} {EXPECT=true TCLSH=bogus} 0
+ "Found subcommand foo with variants: tcl sh\n"
+ "Selected variant tcl" }
+ { "dejagnu foo as shell"
+ {foo -v -v} {EXPECT=bogus TCLSH=bogus} 0
+ "Found subcommand foo with variants: tcl sh\n"
+ "Selected variant sh" }
+
+ { "dejagnu bar as Awk"
+ {bar -v -v} {AWK=true GAWK=true } 0
+ "Found subcommand bar with variants: awk sh\n"
+ "Selected variant awk" }
+ { "dejagnu bar as Awk via GNU Awk"
+ {bar -v -v} {AWK=bogus GAWK=true } 0
+ "Found subcommand bar with variants: awk sh\n"
+ "Selected variant awk" }
+ { "dejagnu bar as shell"
+ {bar -v -v} {AWK=bogus GAWK=bogus} 0
+ "Found subcommand bar with variants: awk sh\n"
+ "Selected variant sh" }
+
+ { "dejagnu bar shadows bar-baz"
+ {bar baz -v -v} {AWK=true} 0
+ "Found subcommand bar with variants: awk sh" }
+ { "dejagnu bar-baz works"
+ {bar-baz -v -v} {AWK=true} 0
+ "Found subcommand bar-baz with variants: awk" }
+ { "dejagnu bar-baz fails without Awk"
+ {bar-baz -v -v} {AWK=bogus GAWK=bogus} 2
+ "Found subcommand bar-baz with variants: awk\n"
+ "ERROR: no variant of bar-baz was selected" }
+
+ { "dejagnu baz-quux works"
+ {baz-quux -v -v} {GAWK=true} 0
+ "Found subcommand baz-quux with variants: gawk\n"
+ "Selected variant gawk" }
+ { "dejagnu baz quux works"
+ {baz quux -v -v} {GAWK=true} 0
+ "Found subcommand baz-quux with variants: gawk\n"
+ "Selected variant gawk" }
+
+ { "#" invalid direct calls }
+
+ { "dejagnu -v bar fails" {-v bar} {} 2
+ "Running nothing.\nERROR: no command given" }
+
+ { "dejagnu \"\" bar fails" {"" bar} {} 2 "ERROR: " }
+ { "dejagnu \"\" \"\" bar fails" {"" "" bar} {} 2 "ERROR: " }
+
+ { "dejagnu baz \"\" quux fails" {baz "" quux} {GAWK=true} 2 "ERROR:
" }
+
+ { "dejagnu bar \"\" baz finds bar subcommand"
+ {--DGTimpl echo bar "" baz} {} 0
+ "command: bar\nargs: baz" }
+
+ { "#" help system }
+
+ { "dejagnu --help works" {--help} {} 0 "Usage: dejagnu" }
+
+ { "dejagnu foo --help works if shell variant selected"
+ {foo --help} {EXPECT=bogus TCLSH=bogus} 0
+ "foo.sh help message" }
+ { "dejagnu foo --help fails if Tcl variant selected"
+ {foo --help} {EXPECT=true TCLSH=true } 2
+ "does not contain a help message" }
+ }
+
+ { dejagnu-foo
+ { "#" calls via dejagnu-foo link }
+ { "dejagnu-foo as Tcl"
+ {-v -v} {EXPECT=true TCLSH=true } 0
+ "Found subcommand foo with variants: tcl sh\n"
+ "Selected variant tcl" }
+ { "dejagnu-foo as Tcl via Expect"
+ {-v -v} {EXPECT=true TCLSH=bogus} 0
+ "Found subcommand foo with variants: tcl sh\n"
+ "Selected variant tcl" }
+ { "dejagnu-foo as shell"
+ {-v -v} {EXPECT=bogus TCLSH=bogus} 0
+ "Found subcommand foo with variants: tcl sh\n"
+ "Selected variant sh" }
+ }
+
+ { dejagnu-bar
+ { "#" calls via dejagnu-bar link }
+ { "dejagnu-bar as Awk"
+ {-v -v} {AWK=true GAWK=true } 0
+ "Found subcommand bar with variants: awk sh\n"
+ "Selected variant awk" }
+ { "dejagnu-bar as Awk via GNU Awk"
+ {-v -v} {AWK=bogus GAWK=true } 0
+ "Found subcommand bar with variants: awk sh\n"
+ "Selected variant awk" }
+ { "dejagnu-bar as shell"
+ {-v -v} {AWK=bogus GAWK=bogus} 0
+ "Found subcommand bar with variants: awk sh\n"
+ "Selected variant sh" }
+
+ { "#" false hybrid: bar shadows bar-baz }
+ { "dejagnu-bar as Awk shadows bar-baz"
+ {baz -v -v} {AWK=true} 0
+ "Found subcommand bar with variants: awk sh\n"
+ "Selected variant awk" }
+ }
+
+ { dejagnu-bar-baz
+ { "#" calls via dejagnu-bar-baz link }
+ { "dejagnu-bar-baz as Awk"
+ {-v -v} {AWK=true GAWK=true } 0
+ "Found subcommand bar-baz with variants: awk\n"
+ "Selected variant awk" }
+ { "dejagnu-bar-baz as Awk via GNU Awk"
+ {-v -v} {AWK=bogus GAWK=true } 0
+ "Found subcommand bar-baz with variants: awk\n"
+ "Selected variant awk" }
+ { "dejagnu-bar-baz fails without Awk"
+ {-v -v} {AWK=bogus GAWK=bogus} 2
+ "Found subcommand bar-baz with variants: awk\n"
+ "ERROR: no variant of bar-baz was selected" }
+ }
+
+ { dejagnu-baz
+ { "#" hybrid: link as prefix }
+ { "dejagnu-baz quux as GNU Awk"
+ {quux -v -v} {GAWK=true} 0
+ "Found subcommand baz-quux with variants: gawk\n"
+ "Selected variant gawk" }
+ { "dejagnu-baz quux fails without GNU Awk"
+ {quux -v -v} {GAWK=bogus AWK=true} 2
+ "Found subcommand baz-quux with variants: gawk\n"
+ "ERROR: no variant of baz-quux was selected" }
+ }
+
+}
+
+# Build the test environment.
+
+# This must be done at run-time in the build directory because symbolic
+# links are not allowed in GNU source tarballs.
+
+catch {
+ file link -symbolic \
+ [testsuite file -object -test command share dejagnu commands] \
+ [testsuite file -source -test command commands]
+}
+foreach alias_item $tests {
+ catch {
+ file link -symbolic \
+ [testsuite file -object -test command bin [lindex $alias_item 0]] \
+ $LAUNCHER
+ }
+}
+if { ![file exists \
+ [testsuite file -object -test command share dejagnu commands]] } {
+ foreach alias_set $tests {
+ skip_dejagnu_launcher_tests \
+ "Could not set up test environment." \
+ unsupported [lrange $alias_set 1 end]
+ }
+ return
+}
+
+# Run the tests.
+
+if { [which true] == 0 || [which bogus] != 0 } {
+ foreach alias_set $tests {
+ skip_dejagnu_launcher_tests \
+ "Either 'true' is not on PATH or 'bogus' is." \
+ unresolved [lrange $alias_set 1 end]
+ }
+} else {
+ foreach alias_set $tests {
+ run_dejagnu_launcher_tests \
+ [testsuite file -object -test command bin [lindex $alias_set 0]] \
+ [lrange $alias_set 1 end]
+ }
+}
+
+#EOF
diff --git a/testsuite/launcher.all/command/commands/bar-baz.awk
b/testsuite/launcher.all/command/commands/bar-baz.awk
new file mode 100644
index 0000000..28753c8
--- /dev/null
+++ b/testsuite/launcher.all/command/commands/bar-baz.awk
@@ -0,0 +1 @@
+# empty "hidden" command
diff --git a/testsuite/launcher.all/command/commands/bar.awk
b/testsuite/launcher.all/command/commands/bar.awk
new file mode 100644
index 0000000..1bb8bf6
--- /dev/null
+++ b/testsuite/launcher.all/command/commands/bar.awk
@@ -0,0 +1 @@
+# empty
diff --git a/testsuite/launcher.all/command/commands/bar.sh
b/testsuite/launcher.all/command/commands/bar.sh
new file mode 100755
index 0000000..c52d3c2
--- /dev/null
+++ b/testsuite/launcher.all/command/commands/bar.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exit 0
diff --git a/testsuite/launcher.all/command/commands/baz-quux.gawk
b/testsuite/launcher.all/command/commands/baz-quux.gawk
new file mode 100644
index 0000000..9c4ff45
--- /dev/null
+++ b/testsuite/launcher.all/command/commands/baz-quux.gawk
@@ -0,0 +1 @@
+# empty -*- Awk -*- file
diff --git a/testsuite/launcher.all/command/commands/foo.sh
b/testsuite/launcher.all/command/commands/foo.sh
new file mode 100755
index 0000000..154687f
--- /dev/null
+++ b/testsuite/launcher.all/command/commands/foo.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# ##help
+# #foo.sh help message
+# ##end
+
+exit 0
diff --git a/testsuite/launcher.all/command/commands/foo.tcl
b/testsuite/launcher.all/command/commands/foo.tcl
new file mode 100644
index 0000000..1bb8bf6
--- /dev/null
+++ b/testsuite/launcher.all/command/commands/foo.tcl
@@ -0,0 +1 @@
+# empty
diff --git a/testsuite/launcher.all/help.exp b/testsuite/launcher.all/help.exp
new file mode 100644
index 0000000..34eb68d
--- /dev/null
+++ b/testsuite/launcher.all/help.exp
@@ -0,0 +1,39 @@
+# Copyright (C) 2018 Free Software Foundation, Inc.
+#
+# This file is part of DejaGnu.
+#
+# DejaGnu 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 3 of the License, or
+# (at your option) any later version.
+#
+# DejaGnu 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 DejaGnu; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+# This file was written by Jacob Bachmeyer.
+
+# each element: { name args envars exit_code output_re... }
+set tests {
+ { "dejagnu help selects dejagnu(1) manpage"
+ {help -v} {MANPAGER=echo} 0
+ "Forwarding to man \".*doc/dejagnu\\.1\"" }
+ { "dejagnu help help selects dejagnu-help(1) manpage"
+ {help -v help} {MANPAGER=echo} 0
+ "Forwarding to man \".*doc/dejagnu-help\\.1\"" }
+}
+
+if { ![file isdirectory [file join [file dirname $LAUNCHER] commands]] } {
+ skip_dejagnu_launcher_tests \
+ "The 'commands' directory is not present in the source tree." \
+ unsupported $tests
+} else {
+ run_dejagnu_launcher_tests $LAUNCHER $tests
+}
+
+#EOF
diff --git a/testsuite/launcher.all/interp.exp
b/testsuite/launcher.all/interp.exp
new file mode 100644
index 0000000..02e763e
--- /dev/null
+++ b/testsuite/launcher.all/interp.exp
@@ -0,0 +1,57 @@
+# Copyright (C) 2018 Free Software Foundation, Inc.
+#
+# This file is part of DejaGnu.
+#
+# DejaGnu 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 3 of the License, or
+# (at your option) any later version.
+#
+# DejaGnu 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 DejaGnu; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+# This file was written by Jacob Bachmeyer.
+
+# each element: { name args envars exit_code output_re... }
+set tests {
+ { "have shell, always" {--DGTimpl sh} {} 0 "" }
+ { "report error probing 'echo'" {--DGTimpl echo} {} 2 "" }
+
+ { "have no Awk" {--DGTimpl awk} {AWK=bogus GAWK=bogus} 1 "" }
+ { "have Awk" {--DGTimpl awk} {AWK=true GAWK=bogus} 0 "" }
+
+ { "have no GNU Awk" {--DGTimpl gawk} {GAWK=bogus} 1 "" }
+ { "have GNU Awk" {--DGTimpl gawk} {GAWK=true } 0 "" }
+
+ { "GNU Awk substitutes for Awk"
+ {--DGTimpl awk} {AWK=bogus GAWK=true} 0 "" }
+
+ { "have no Tcl" {--DGTimpl tcl} {TCLSH=bogus EXPECT=bogus} 1 "" }
+ { "have Tcl" {--DGTimpl tcl} {TCLSH=true EXPECT=bogus} 0 "" }
+
+ { "have no Expect" {--DGTimpl exp} {EXPECT=bogus} 1 "" }
+ { "have Expect" {--DGTimpl exp} {EXPECT=true } 0 "" }
+
+ { "Expect substitutes for Tcl"
+ {--DGTimpl tcl} {TCLSH=bogus EXPECT=true} 0 "" }
+}
+
+if { [which true] == 0 || [which bogus] != 0 } {
+ skip_dejagnu_launcher_tests \
+ "Either 'true' is not on PATH or 'bogus' is." \
+ unresolved $tests
+} elseif { ![file isdirectory [file join [file dirname $LAUNCHER] commands]] }
{
+ skip_dejagnu_launcher_tests \
+ "The 'commands' directory is not present in the source tree." \
+ unsupported $tests
+} else {
+ run_dejagnu_launcher_tests $LAUNCHER $tests
+}
+
+#EOF
diff --git a/testsuite/launcher.all/verbose.exp
b/testsuite/launcher.all/verbose.exp
new file mode 100644
index 0000000..a45ca2d
--- /dev/null
+++ b/testsuite/launcher.all/verbose.exp
@@ -0,0 +1,55 @@
+# Copyright (C) 2018 Free Software Foundation, Inc.
+#
+# This file is part of DejaGnu.
+#
+# DejaGnu 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 3 of the License, or
+# (at your option) any later version.
+#
+# DejaGnu 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 DejaGnu; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+# This file was written by Jacob Bachmeyer.
+
+# each element: { name args envars exit_code output_re... }
+set tests {
+ { "empty command" {} {} 2 "ERROR: no command given" }
+ { "empty; verbose 1" {-v} {} 2
+ "Verbose level is 1\nRunning launcher [^\n]*\n"
+ "Looking for commands [^\n]*\nRunning nothing.\n"
+ "ERROR: no command given" }
+ { "empty; verbose 2" {-v -v} {} 2
+ "Verbose level is 2\nRunning launcher [^\n]*\n"
+ "Running from source directory\n"
+ "Looking for commands [^\n]*\nRunning nothing.\n"
+ "ERROR: no command given" }
+ { "empty; verbose 3" {-v -v -v} {} 2
+ "Verbose level is 3\nRunning launcher [^\n]*\n"
+ "Running from source directory\n"
+ "Looking for commands [^\n]*\nRunning nothing.\n"
+ "Awk interpreter [^\n]*\nGNU Awk interpreter [^\n]*\n"
+ "Bash interpreter [^\n]*\n"
+ "Expect interpreter [^\n]*\nTcl interpreter [^\n]*\n"
+ "ERROR: no command given" }
+}
+
+lappend tests [list "check version" {--version} {} 0 \
+ [format "dejagnu auxiliary launcher \\(DejaGnu\\) %s" \
+ $frame_version]]
+
+if { ![file isdirectory [file join [file dirname $LAUNCHER] commands]] } {
+ skip_dejagnu_launcher_tests \
+ "The 'commands' directory is not present in the source tree." \
+ unsupported $tests
+} else {
+ run_dejagnu_launcher_tests $LAUNCHER $tests
+}
+
+#EOF
diff --git a/testsuite/lib/launcher.exp b/testsuite/lib/launcher.exp
new file mode 100644
index 0000000..906f722
--- /dev/null
+++ b/testsuite/lib/launcher.exp
@@ -0,0 +1,110 @@
+# Copyright (C) 2018 Free Software Foundation, Inc.
+#
+# This file is part of DejaGnu.
+#
+# DejaGnu 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 3 of the License, or
+# (at your option) any later version.
+#
+# DejaGnu 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 DejaGnu; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+# This file was written by Jacob Bachmeyer.
+
+if { ![info exists LAUNCHER] } {
+ set LAUNCHER \
+ [file join [file dirname [testsuite file -source -top]] dejagnu]
+}
+verbose "Using LAUNCHER $LAUNCHER" 2
+
+if { [which $LAUNCHER] == 0 } {
+ perror "Can't find LAUNCHER = $LAUNCHER"
+ exit 2
+}
+
+# run dejagnu(1) LAUNCHER with ARGLIST, returning { output exit_code }
+proc dejagnu_run { launcher arglist envlist } {
+ global errorCode
+
+ set exec_cmd [list exec]
+ if { [llength $envlist] > 0 } {
+ lappend exec_cmd env
+ foreach var $envlist { lappend exec_cmd $var }
+ }
+ lappend exec_cmd $launcher
+
+ # reset errorCode
+ catch { error }
+
+ catch { eval $exec_cmd $arglist } output
+
+ if { [lindex $errorCode 0] eq "CHILDSTATUS" } {
+ return [list $output [lindex $errorCode 2]]
+ } else {
+ return [list $output 0]
+ }
+}
+
+# evaluate a test against LAUNCHER, returning true if it passes
+# TEST is a list: { name arglist envlist exit_code output_re... }
+proc try_dejagnu_launcher { launcher test } {
+ foreach part [lrange $test 4 end] { append re $part }
+
+ if { [llength [lindex $test 2]] > 0 } {
+ verbose "Spawning \"env [lindex $test 2] $launcher [lindex $test 1]\"
..."
+ } else {
+ verbose "Spawning \"$launcher [lindex $test 1]\" ..."
+ }
+ verbose "Expecting to match {$re} ..." 2
+ set result [dejagnu_run $launcher [lindex $test 1] [lindex $test 2]]
+ verbose "Exit code [lindex $result 1]; output {[lindex $result 0]}" 2
+
+ if { [regexp $re [lindex $result 0]]
+ && [lindex $test 3] == [lindex $result 1] } {
+ return 1
+ } else {
+ return 0
+ }
+}
+
+proc run_dejagnu_launcher_tests { launcher tests } {
+ foreach test $tests {
+ if { [lindex $test 0] == "#" } {
+ # ignore comments in test list
+ } elseif { [llength $test] == 1 } {
+ # name only is a stub
+ untested [lindex $test 0]
+ } elseif { [try_dejagnu_launcher $launcher $test] } {
+ pass [lindex $test 0]
+ } else {
+ fail [lindex $test 0]
+ }
+ }
+}
+
+proc skip_dejagnu_launcher_tests { why result tests } {
+ perror $why 0
+ foreach test $tests {
+ if { [lindex $test 0] == "#" } {
+ # ignore comments in test list
+ } else {
+ $result [lindex $test 0]
+ }
+ }
+}
+
+# stub: dejagnu(1) itself is non-interactive
+proc dejagnu_exit {} {}
+
+# stub: dejagnu(1) does not have a separate version number
+proc dejagnu_version {} {
+}
+
+#EOF
----
-- Jacob
- PATCH: add dejagnu(1) multi-launcher [revised],
Jacob Bachmeyer <=