sanity.sh   [plain text]


#! /bin/sh
:
#	sanity.sh -- a growing testsuite for cvs.
#
# The copyright notice said: "Copyright (C) 1992, 1993 Cygnus Support"
# I'm not adding new copyright notices for new years as our recent 
# practice has been to include copying terms without copyright notices.
#
# This program 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.
#
# This program 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.
#
# Original Author: K. Richard Pixley

# usage:
usage ()
{
    echo "Usage: `basename $0` --help"
    echo "Usage: `basename $0` [--eklr] [-c CONFIG-FILE] [-f FROM-TEST] \\"
    echo "                 [-h HOSTNAME] [-s CVS-FOR-CVS-SERVER] CVS-TO-TEST \\"
    echo "                 [TESTS-TO-RUN...]"
}

exit_usage ()
{
    usage 1>&2
    exit 2
}

exit_help ()
{
    usage
    echo
    echo "-H|--help	display this text"
    echo "-c CONFIG-FILE"
    echo "--config=CONFIG_FILE"
    echo "		use an alternate test suite config file (defaults to"
    echo "		\`sanity.config.sh' in the same directory as"
    echo "		CVS-TO-TEST is found in)"
    echo "-e|--skipfail Treat tests that would otherwise be nonfatally skipped"
    echo "              for reasons like missing tools as failures, exiting"
    echo "              with an error message.  Also treat warnings as"
    echo "		failures."
    echo "-f FROM-TEST"
    echo "--from-test=FROM-TEST"
    echo "		run TESTS-TO-RUN, skipping all tests in the list before"
    echo "		FROM-TEST"
    echo "-h HOSTNAME"
    echo "--hostname HOSTNAME"
    echo "              Use :ext:HOSTNAME to run remote tests rather than"
    echo "              :fork:.  Implies --remote and assumes that \$TESTDIR"
    echo "              resolves to the same directory on both the client and"
    echo "              the server."
    echo "-k|--keep	try to keep directories created by individual tests"
    echo "		around, exiting after the first test which supports"
    echo "		--keep"
    echo "-l|--link-root"
    echo "		test CVS using a symlink to a real CVSROOT"
    echo "-n|--noredirect"
    echo "              test a secondary/primary CVS server (writeproxy)"
    echo "              configuration with the Redirect response disabled"
    echo "              (implies --proxy)."
    echo "-p|--proxy	test a secondary/primary CVS server (writeproxy)"
    echo "              configuration (implies --remote)."
    echo "-r|--remote	test client/server, as opposed to local, CVS"
    echo "-s CVS-FOR-CVS-SERVER"
    echo "--server=CVS-FOR-CVS-SERVER"
    echo "		use CVS-FOR-CVS-SERVER as the path to the CVS SERVER"
    echo "		executable to be tested (defaults to CVS-TO-TEST and"
    echo "		implies --remote)"
    echo
    echo "CVS-TO-TEST	the path to the CVS executable to be tested; used as"
    echo "		the path to the CVS client when CVS-FOR-CVS-SERVER is"
    echo "		specified"
    echo "TESTS-TO-RUN	the names of the tests to run (defaults to all tests)"
    exit 2
}

checklongoptarg()
{
    if test "x$1" != xoptional && test -z "$OPTARG"; then
	echo "option \`--$LONGOPT' requires an argument" >&2
	exit_usage
    fi
}

# See TODO list at end of file.

# required to make this script work properly.
unset CVSREAD

# We want to invoke a predictable set of i18n behaviors, not whatever
# the user running this script might have set.
# In particular:
#   'sort' and tabs and spaces (LC_COLLATE).
#   Messages from getopt (LC_MESSAGES) (in the future, CVS itself might 
#     also alter its messages based on LC_MESSAGES).
LANG=C
export LANG
LC_ALL=C
export LC_ALL

# And a few tests want a predictable umask.
umask 0002

#
# Initialize the test counts.
#
passed=0
skipped=0
warnings=0



#
# read our options
#
unset configfile
unset fromtest
unset remotehost
unset rootoptions
keep=false
linkroot=false
noredirect=false
proxy=false
remote=false
servercvs=false
skipfail=false
while getopts Hc:ef:h:klnprs:-: option ; do
    # convert the long opts to short opts
    if test x$option = x-;  then
	# remove any argument
	if echo "$OPTARG" |grep = >/dev/null; then
	    LONGOPT=`echo "$OPTARG" |sed 's/=.*$//'`
	    OPTARG=`echo "$OPTARG" |sed -e 's/^.*=//'`
	else
	    LONGOPT=$OPTARG
	    OPTARG=
	fi
	# Convert LONGOPT to lower case
	LONGOPT=`echo "$LONGOPT" |sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
	case "$LONGOPT" in
	    c|co|con|conf|confi|config)
		option=c
		checklongoptarg
		;;
	    f|fr|fro|from|from-|from-t|from-te|from-tes|from-test)
		option=f
		checklongoptarg
		;;
	    h)
		echo "\`--h' is ambiguous.  Could mean \`--help' or \`--hostname'" >&2
		exit_usage
		;;
	    he|hel|help)
		option=H
		OPTARG=
		;;
	    ho|hos|host|hostn|hostna|hostnam|hostname)
		option=h
		checklongoptarg
		;;
	    k|ke|kee|keep)
		option=k
		OPTARG=
		;;
	    l|li|lin|link|link-|link-r]|link-ro|link-roo|link-root)
		option=l
		OPTARG=
		;;
	    n|no|nor|nore|nored|noredi|noredir|noredire|noredirec|noredirect)
		option=n
		OPTARG=
		;;
	    p|pr|pro|prox|proxy)
		option=p
		OPTARG=
		;;
	    r|re|rem|remo|remot|remote)
		option=r
		OPTARG=
		;;
	    s)
		echo "\`--s' is ambiguous.  Could mean \`--server' or \`--skipfail'" >&2
		exit_usage
		;;
	    se|ser|serv|serve|server)
		option=s
		checklongoptarg
		;;
	    sk|ski|skip|skipf|skipfa|skipfai|skipfail)
		option=e
		OPTARG=
		;;
	    *)
		option=\?
		OPTARG=
	esac
    fi
    case "$option" in
	c)
	    configfile="$OPTARG"
	    ;;
	e)
	    skipfail=:
	    ;;
	f)
	    fromtest="$OPTARG"
	    ;;
	h)
	    # Set a remotehost to run the remote tests on via :ext:
	    # Implies `-r' and assumes that $TESTDIR resolves to the same
	    # directory on the client and the server.
	    remotehost="$OPTARG"
	    remote=:
	    ;;
	H)
	    exit_help
	    ;;
	k)
	    # The -k (keep) option will eventually cause all the tests to
	    # leave around the contents of the /tmp directory; right now only
	    # some implement it.  Not originally intended to be useful with
	    # more than one test, but this should work if each test uses a
	    # uniquely named dir (use the name of the test).
	    keep=:
	    ;;
	l)
	    linkroot=:
	    ;;
        n)
	    proxy=:
	    noredirect=:
	    remote=:
	    ;;
        p)
	    proxy=:
	    remote=:
	    ;;
	r)
	    remote=:
	    ;;
        s)
	    servercvs="$OPTARG"
	    remote=:
	    ;;
	\?)
	    exit_usage
	    ;;
    esac
done

# boot the arguments we used above
while test $OPTIND -gt 1 ; do
    shift
    OPTIND=`expr $OPTIND - 1`
done

# Use full path for CVS executable, so that CVS_SERVER gets set properly
# for remote.
case $1 in
"")
  exit_usage
  ;;
/*)
  testcvs=$1
  ;;
*)
  testcvs=`pwd`/$1
  ;;
esac
shift

# Verify that $testcvs looks like CVS.
# we can't use test -x since BSD 4.3 doesn't support it.
if test ! -f $testcvs || test ! -r $testcvs; then
  echo "No such file or file not readable: $testcvs" >&2
  exit 1
fi
if $testcvs --version </dev/null 2>/dev/null |
     grep '^Concurrent Versions System' >/dev/null 2>&1; then :; else
  echo "Not a CVS executable: $testcvs" >&2
  exit 1
fi

# If $remotehost is set, warn if $TESTDIR isn't since we are pretty sure
# that its default value of `/tmp/cvs-sanity' will not resolve to the same
# directory on two different machines.
if test -n "$remotehost" && test -z "$TESTDIR"; then
    echo "WARNING: CVS server hostname is set and \$TESTDIR is not.  If" >&2
    echo "$remotehost is not the local machine, then it is unlikely that" >&2
    echo "the default value assigned to \$TESTDIR will resolve to the same" >&2
    echo "directory on both this client and the CVS server." >&2
fi

# Read our config file if we can find it.
#
# The config file should always be located in the same directory as the CVS
# executable, unless we are testing an executable outside of the build
# directory.  In this case, we echo a warning and attempt to assume the most
# portable configuration.
if test -z "$configfile"; then
	configfile=`dirname $testcvs`/sanity.config.sh
fi
if test -r "$configfile"; then
	. "$configfile"
else
	echo "WARNING: Failed to locate test suite config file" >&2
	echo "         \`$configfile'." >&2
fi



# Set a default value for $CVS_RSH. The sanity.config.sh file will
# have the configured value in the RSH_DFLT variable.
#
: ${CVS_RSH=${RSH_DFLT:-ssh}}; export CVS_RSH

if test -n "$remotehost"; then
    # Verify that $CVS_RSH $remotehost works.
    result=`$CVS_RSH $remotehost 'echo test'`
    if test $? != 0 || test "x$result" != "xtest"; then
	echo "\`$CVS_RSH $remotehost' failed." >&2
	exit 1
    fi
fi

case "$servercvs" in
"")
  exit_usage
  ;;
false)
  ;;
/*)
  ;;
*)
  servercvs=`pwd`/$servercvs
  ;;
esac

if test false != $servercvs; then
  # Allow command line to override $CVS_SERVER
  CVS_SERVER=$servercvs
else
  # default $CVS_SERVER to ${testcvs}
  : ${CVS_SERVER=$testcvs}
  # With the previous command, effectively defaults $servercvs to $CVS_SERVER,
  # then $testcvs
  servercvs=$CVS_SERVER
fi
export CVS_SERVER
servercvs_orig=$servercvs

# Fail in client/server mode if our ${servercvs} does not contain server
# support.
if $remote; then
  if test -n "$remotehost"; then
    if $CVS_RSH $remotehost "test ! -f ${servercvs} || test ! -r ${servercvs}"
    then
      echo "No such file or file not readable: $remotehost:${testcvs}" >&2
      exit 1
    fi
    if $CVS_RSH $remotehost "${servercvs} --version </dev/null 2>/dev/null |
         grep '^Concurrent Versions System' >/dev/null 2>&1"; then :; else
      echo "Not a CVS executable: $remotehost:${servercvs}" >&2
      exit 1
    fi
    if $CVS_RSH $remotehost "${servercvs} --version </dev/null |
         grep '^Concurrent.*(.*server)$' >/dev/null 2>&1"; then :; else
      echo "CVS executable \`$remotehost:${servercvs}' does not contain server support." >&2
      exit 1
    fi
  else
    if test ! -f ${servercvs} || test ! -r ${servercvs}; then
      echo "No such file or file not readable: ${testcvs}" >&2
      exit 1
    fi
    if ${servercvs} --version </dev/null 2>/dev/null |
         grep '^Concurrent Versions System' >/dev/null 2>&1; then :; else
      echo "Not a CVS executable: ${servercvs}" >&2
      exit 1
    fi
    if ${servercvs} --version </dev/null |
         grep '^Concurrent.*(.*server)$' >/dev/null 2>&1; then :; else
      echo "CVS executable \`${servercvs}' does not contain server support." >&2
      exit 1
    fi
  fi
fi

# Fail in client/server mode if our ${testcvs} does not contain client
# support.
if $remote; then
  if ${testcvs} --version </dev/null |
       grep '^Concurrent.*(client.*)$' >/dev/null 2>&1; then :; else
    echo "CVS executable \`${testcvs}' does not contain client support." >&2
    exit 1
  fi
fi

# For the "fork" tests.
if ${testcvs} --version </dev/null |
     grep '^Concurrent.*(.*server)$' >/dev/null 2>&1
then
  testcvs_server_support=:
else
  testcvs_server_support=false
fi



dokeep() 
{ 
    if ${keep}; then
      echo "Keeping ${TESTDIR} for test case \`${what}' and exiting due to --keep"
      exit 0
    fi
}



###
### GUTS
###

# "debugger"
#set -x

echo 'This test should produce no other output than this message, and a final "OK".'
echo '(Note that the test can take an hour or more to run and periodically stops'
echo 'for as long as one minute.  Do not assume there is a problem just because'
echo 'nothing seems to happen for a long time.  If you cannot live without'
echo "running status, try the command: \`tail -f check.log' from another window.)"

# Regexp to match what the CVS client will call itself in output that it prints.
# FIXME: we don't properly quote this--if the name contains . we'll
# just spuriously match a few things; if the name contains other regexp
# special characters we are probably in big trouble.
CPROG=`basename ${testcvs} |sed 's/\.exe$//'`
# And the regexp for the CVS server when we have one.  In local mode, this
# defaults to $CPROG since $servercvs already did.
# FIXCVS: There are a few places in error messages where CVS suggests a command
# and outputs $SPROG as the suggested executable.  This could hopefully use
# MT (tagged text - see doc/cvs-client.texi) to request that the client print
# its own name.
SPROG=`basename ${servercvs} |sed 's/\.exe$//'`


# Match the hostname
hostname="[-_.a-zA-Z0-9]*"

# Regexp to match a commitid
commitid="[a-zA-Z0-9]*"

# Regexp to match the name of a temporary file (from cvs_temp_name).
# This appears in certain diff output.
tempfile="cvs[-a-zA-Z0-9.%_]*"
# $tempname set after $TMPDIR, below.

# Regexp to match a date in RFC822 format (as amended by RFC1123).
RFCDATE="[a-zA-Z0-9 ][a-zA-Z0-9 ]* [0-9:][0-9:]* -0000"
RFCDATE_EPOCH="1 Jan 1970 00:00:00 -0000"

# Special times used in touch -t commands and the regular expresions
# to match them. Now that the tests set TZ=UTC0, it
# should be easier to be more exact in their regexp.
TOUCH1971="197107040343"
# This date regexp was 1971/07/0[3-5] [0-9][0-9]:43:[0-9][0-9]
ISO8601DATE1971="1971-07-04 03:43:[0-9][0-9] [+-]0000"

TOUCH2034="203412251801"
# This date regexp was 2034/12/2[4-6] [0-9][0-9]:01:[0-9][0-9]
ISO8601DATE2034="2034-12-25 18:01:[0-9][0-9] [+-]0000"

# Used in admin tests for exporting RCS files.
# The RAWRCSDATE..... format is for internal ,v files and
# the ISO8601DATE..... format is to allow for a regular expression in
# 'cvs log' output patterns. The tests that use this set of specific
# ${ISO8601DATE.....} variables also force TZ=UTC0 for the test.
RAWRCSDATE2000A="2000.11.24.15.58.37"
RAWRCSDATE1996A="96.11.24.15.57.41"
RAWRCSDATE1996B="96.11.24.15.56.05"
ISO8601DATE2000A="2000-11-24 15:58:37 [+-]0000"
ISO8601DATE1996A="1996-11-24 15:57:41 [+-]0000"
ISO8601DATE1996B="1996-11-24 15:56:05 [+-]0000"

# Regexp to match the date in cvs log command output
# This format has been enhanced in the future to accept either
# old-style cvs log output dates or new-style ISO8601 timezone
# information similar to the ISODATE format. The RCSKEYDATE is
# similar, but uses '/' instead of '-' to sepearate year/month/day
# and does not include the optional timezone offset.
ISO8601DATE="[0-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-6][0-9]:[0-6][0-9] [-+][0-1][0-9][0-6][0-9]"

# Regexp to match the dates found in rcs keyword strings
RCSKEYDATE="[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]"

# Regexp to match the date in the delta section of rcs format files.
# Dates in very old RCS files may not have included the century.
RCSDELTADATE="[0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]"

# Regexp to match a date in standard Unix format as used by rdiff
# FIXCVS: There's no reason for rdiff to use a different date format
# than diff does
DATE="[a-zA-Z]* [a-zA-Z]* [ 1-3][0-9] [0-9:]* [0-9]*"
# ISO 8601 format "yyyy-mm-dd hh:mm -0000"
ISODATE="[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9] [+-][0-9][0-9][0-9][0-9]"
# %p format is not well defined (nil) and hex digits are common. Using
# ..* is a bad idea as the tests take a very long time to run due to
# the complexity of the expressions.  If you run into any other characters
# that are used in a %p format, add them here.
PFMT="[0-9a-zA-Z()][0-9a-zA-Z()]*"

# Which directories should Which and find_tool search for executables?
SEARCHPATH=$PATH:/usr/local/bin:/usr/contrib/bin:/usr/contrib:/usr/gnu/bin:/local/bin:/local/gnu/bin:/gnu/bin:/sw/bin:/usr/pkg/bin

# Do not assume that `type -p cmd` is portable
# Usage: Which [-a] [-x|-f|-r] prog [$SEARCHPATH:/with/directories:/to/search]
Which() {
  # Optional first argument for file type, defaults to -x.
  # Second argument is the file or directory to be found.
  # Third argument is the PATH to search.
  # By default, print only the first file that matches,
  # -a will cause all matches to be printed.
  notevery=:
  if [ "x$1" = "x-a" ]; then notevery=false; shift; fi
  case "$1" in
    -*) t=$1; shift ;;
    *) t=-x ;;
  esac
  case "$1" in
    # FIXME: Someday this may need to be fixed
    # to deal better with C:\some\path\to\ssh values...
    /*) test $t $1 && echo $1 ;;
    *) for d in `IFS=:; echo ${2-$SEARCHPATH}`
       do
         test $t $d/$1 && { echo $d/$1; if $notevery; then break; fi; }
       done
       ;;
  esac
}


# On cygwin32, we may not have /bin/sh.
if test -r /bin/sh; then
  TESTSHELL="/bin/sh"
else
  TESTSHELL=`Which -f sh`
  if test ! -r "$TESTSHELL"; then
    TESTSHELL="/bin/sh"
  fi
fi

# FIXME: try things (what things? checkins?) without -m.
#
# Some of these tests are written to expect -Q.  But testing with
# -Q is kind of bogus, it is not the way users actually use CVS (usually).
# So new tests probably should invoke ${testcvs} directly, rather than ${CVS}.
# and then they've obviously got to do something with the output....
#
CVS="${testcvs} -Q"

LOGFILE=`pwd`/check.log

# Save the previous log in case the person running the tests decides
# they want to look at it.  The extension ".plog" is chosen for consistency
# with dejagnu.
test -f check.plog && mv check.plog check.plog~
test -f check.log && mv check.log check.plog

# Create the log file so check.log can be tailed almost immediately after
# this script is started.  Otherwise it can take up to a minute or two before
# the log file gets created when $remotehost is specified on some systems,
# which makes for a lot of failed `tail -f' attempts.
touch check.log

# Workaround any X11Forwarding by ssh. Otherwise this text:
#   Warning: No xauth data; using fake authentication data for X11 forwarding.
# has been known to end up in the test results below
# causing the test to fail.
[ -n "$DISPLAY" ] && unset DISPLAY
  
# The default value of /tmp/cvs-sanity for TESTDIR is dubious,
# because it loses if two people/scripts try to run the tests
# at the same time.  Some possible solutions:
# 1.  Use /tmp/cvs-test$$.  One disadvantage is that the old
#     cvs-test* directories would pile up, because they wouldn't
#     necessarily get removed.
# 2.  Have everyone/everything running the testsuite set
#     TESTDIR to some appropriate directory.
# 3.  Have the default value of TESTDIR be some variation of
#     `pwd`/cvs-sanity.  The biggest problem here is that we have
#     been fairly careful to test that CVS prints in messages the
#     actual pathnames that we pass to it, rather than a different
#     pathname for the same directory, as may come out of `pwd`.
#     So this would be lost if everything was `pwd`-based.  I suppose
#     if we wanted to get baroque we could start making symlinks
#     to ensure the two are different.
if test -n "$remotehost"; then
        # We need to set $tmp on the server since $TMPDIR is compared against
	# messages generated by the server.
	tmp=`$CVS_RSH $remotehost 'cd /tmp; /bin/pwd || pwd' 2>/dev/null`
	if test $? != 0; then
	    echo "$CVS_RSH $remotehost failed." >&2
	    exit 1
	fi
else
	tmp=`(cd /tmp; /bin/pwd || pwd) 2>/dev/null`
fi

# Now:
#	1) Set TESTDIR if it's not set already
#	2) Remove any old test remnants
#	3) Create $TESTDIR
#	4) Normalize TESTDIR with `cd && (/bin/pwd || pwd)`
#	   (This will match CVS output later)
: ${TESTDIR=$tmp/cvs-sanity}
# clean any old remnants (we need the chmod because some tests make
# directories read-only)
if test -d $TESTDIR; then
    chmod -R a+wx $TESTDIR
    rm -rf $TESTDIR
fi
# These exits are important.  The first time I tried this, if the `mkdir && cd`
# failed then the build directory would get blown away.  Some people probably
# wouldn't appreciate that.
mkdir $TESTDIR || exit 1
cd $TESTDIR || exit 1
# Ensure $TESTDIR is absolute
if echo "$TESTDIR" |grep '^[^/]'; then
    # Don't resolve this unless we have to.  This keeps symlinks intact.  This
    # is important at least when testing using -h $remotehost, because the same
    # value for $TESTDIR must resolve to the same directory on the client and
    # the server and we likely used Samba, and possibly symlinks, to do this.
    TESTDIR=`(/bin/pwd || pwd) 2>/dev/null`
fi

if test -z "$TESTDIR" || echo "$TESTDIR" |grep '^[^/]'; then
    echo "Unable to resolve TESTDIR to an absolute directory." >&2
    exit 1
fi
cd $TESTDIR



: ${TIMING=false}
if $remote; then
    # Now override our CVS_RSH in order to forward variables which affect the
    # test suite through.  This always needs to be done when $remotehost is
    # set, needs to be done in $proxy mode for the crerepos tests, and needs to
    # be done in $remote mode for the writeproxy-ssh tests.
    if $TIMING; then
	time="/usr/bin/time -ao'$TESTDIR/time.out'"
    else
	time=
    fi
    cat >$TESTDIR/ssh-wrapper-env <<EOF
#! $TESTSHELL
while [ \$# -gt 0 ]
do
  case "\$1" in
    *=*)
      eval "\$1"
      var=\`echo "\$1" | sed 's/^\\(.*\\)=.*\$/\\1/'\`
      export \$var
      ;;
    *) break;;
  esac
  shift
done
exec \${1+"\$@"}
EOF
    chmod a+x $TESTDIR/ssh-wrapper-env
    cat >$TESTDIR/ssh-wrapper <<EOF
#! $TESTSHELL
hostname=\$1
shift
exec \
$CVS_RSH \
	 \$hostname \
	 $TESTDIR/ssh-wrapper-env \
	 "CVS_SERVER='\$CVS_SERVER'" \
	 "CVS_SERVER_SLEEP='\$CVS_SERVER_SLEEP'" \
	 "CVS_PARENT_SERVER_SLEEP='\$CVS_PARENT_SERVER_SLEEP'" \
	 "CVS_SERVER_LOG='\$CVS_SERVER_LOG'" \
	 "CVS_SECONDARY_LOG='\$CVS_SECONDARY_LOG'" \
	 "TMPDIR='\$TMPDIR'" \
	 "CVS_RSH='$TESTDIR/ssh-wrapper'" \
	 "CVSUMASK='\$CVSUMASK'" \
	 "CVS_PID='\$CVS_PID'" \
	 $time \
	 \${1+"\$@"}
EOF
    chmod a+x $TESTDIR/ssh-wrapper
    CVS_RSH=$TESTDIR/ssh-wrapper
fi # $remotehost



# Now set $TMPDIR if the user hasn't overridden it.
#
# We use a $TMPDIR under $TESTDIR by default so that two tests may be run at
# the same time without bumping heads without requiring the user to specify
# more than $TESTDIR.  See the test for leftover cvs-serv* directories near the
# end of this script at the end of "The big loop".
: ${TMPDIR=$TESTDIR/tmp}
export TMPDIR
if test -d $TMPDIR; then :; else
    mkdir $TMPDIR
fi


# Regexp to match the the full path to a temporary file (from cvs_temp_name).
# This appears in certain diff output.
tempname=$TMPDIR/$tempfile

# Make sure various tools work the way we expect, or try to find
# versions that do.
: ${AWK=awk}
: ${EXPR=expr}
: ${ID=id}
: ${TR=tr}

# Keep track of tools that are found, but do NOT work as we hope
# in order to avoid them in future
badtools=
set_bad_tool ()
{
   badtools=$badtools:$1
}
is_bad_tool ()
{
   case ":$badtools:" in *:$1:*) return 0 ;; *) return 1 ; esac
}

version_test ()
{
  vercmd=$1
  verbad=:
  if RES=`$vercmd --version </dev/null 2>&1`; then
    if test "X$RES" != "X--version" && test "X$RES" != "X" ; then
      echo "$RES"
      verbad=false
    fi
  fi
  if $verbad; then
    echo "The command \`$vercmd' does not support the --version option."
  fi
  # It does not really matter that --version is not supported
  return 0
}

# Try to find a tool that satisfies all of the tests.
# Usage: list:of:colon:separated:alternatives test1 test2 test3 test4...
# Example: find_tool awk:gawk:nawk awk_tooltest1 awk_tooltest2
find_tool ()
{
  default_TOOL=$1
  echo find_tool: ${1+"$@"} >>$LOGFILE
  cmds="`IFS=:; echo $1`"; shift; tooltests="${1+$@}"
  if test -z "$tooltests"; then tooltests=version_test; fi
  clist=; for cmd in $cmds; do clist="$clist `Which -a $cmd`"; done
  # Make sure the default tool is just the first real command name
  for default_TOOL in $clist `IFS=:; echo $default_TOOL`; do break; done
  TOOL=""
  for trytool in $clist ; do
    pass=:
    for tooltest in $tooltests; do
      result=`eval $tooltest $trytool`
      rc=$?
      echo "Running $tooltest $trytool" >>$LOGFILE
      if test -n "$result"; then
	echo "$result" >>$LOGFILE
      fi
      if test "$rc" = "0"; then
        echo "PASS: $tooltest $trytool" >>$LOGFILE
      elif test "$rc" = "77"; then
        echo "MARGINAL: $tooltest $trytool; rc=$rc" >>$LOGFILE
        TOOL=$trytool
	pass=false
      else
        set_bad_tool $trytool
        echo "FAIL: $tooltest $trytool; rc=$rc" >>$LOGFILE
	pass=false
      fi
    done
    if $pass; then
      echo $trytool
      return 0
    fi
  done
  if test -n "$TOOL"; then
    echo "Notice: The default version of \`$default_TOOL' is defective." >>$LOGFILE
    echo "using \`$TOOL' and hoping for the best." >>$LOGFILE
    echo "Notice: The default version of \`$default_TOOL' is defective." >&2
    echo "using \`$TOOL' and hoping for the best." >&2
    echo $TOOL
  else
    echo $default_TOOL
  fi
}  

id_tool_test ()
{
  id=$1
  if $id -u >/dev/null 2>&1 && $id -un >/dev/null 2>&1; then
    return 0
  else
    echo "Running these tests requires an \`id' program that understands the"
    echo "-u and -n flags.  Make sure that such an id (GNU, or many but not"
    echo "all vendor-supplied versions) is in your path."
    return 1
  fi
}

ID=`find_tool id version_test id_tool_test`
echo "Using ID=$ID" >>$LOGFILE

# You can't run CVS as root; print a nice error message here instead
# of somewhere later, after making a mess.
for pass in false :; do
  case "`$ID -u 2>/dev/null`" in
    "0")
      echo "Test suite does not work correctly when run as root" >&2
      exit 1
      ;;

    *)
      break
      ;;
  esac
done

# Cause NextStep 3.3 users to lose in a more graceful fashion.
expr_tooltest1 ()
{
expr=$1
if $expr 'abc
def' : 'abc
def' >/dev/null; then
  # good, it works
  return 0
else
  echo 'Running these tests requires an "expr" program that can handle'
  echo 'multi-line patterns.  Make sure that such an expr (GNU, or many but'
  echo 'not all vendor-supplied versions) is in your path.'
  return 1
fi
}

# Warn SunOS, SysVr3.2, etc., users that they may be partially losing
# if we can't find a GNU expr to ease their troubles...
expr_tooltest2 ()
{
expr=$1
if $expr 'a
b' : 'a
c' >/dev/null; then
  echo 'Warning: you are using a version of expr that does not correctly'
  echo 'match multi-line patterns.  Some tests may spuriously pass or fail.'
  echo 'You may wish to make sure GNU expr is in your path.'
  return 1
else
  return 0
fi
}

expr_create_bar ()
{
echo 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' >${TESTDIR}/foo
cat ${TESTDIR}/foo ${TESTDIR}/foo ${TESTDIR}/foo ${TESTDIR}/foo >${TESTDIR}/bar
cat ${TESTDIR}/bar ${TESTDIR}/bar ${TESTDIR}/bar ${TESTDIR}/bar >${TESTDIR}/foo
cat ${TESTDIR}/foo ${TESTDIR}/foo ${TESTDIR}/foo ${TESTDIR}/foo >${TESTDIR}/bar
rm -f ${TESTDIR}/foo
}

expr_tooltest3 ()
{
expr=$1
# More SunOS lossage...
test ! -f ${TESTDIR}/bar && expr_create_bar
if $expr "`cat ${TESTDIR}/bar`" : "`cat ${TESTDIR}/bar`" >/dev/null; then
  : good, it works
else
  echo 'Warning: you are using a version of expr that does not correctly'
  echo 'match large patterns.  Some tests may spuriously pass or fail.'
  echo 'You may wish to make sure GNU expr is in your path.'
  return 1
fi
if $expr "`cat ${TESTDIR}/bar`x" : "`cat ${TESTDIR}/bar`y" >/dev/null; then
  echo 'Warning: you are using a version of expr that does not correctly'
  echo 'match large patterns.  Some tests may spuriously pass or fail.'
  echo 'You may wish to make sure GNU expr is in your path.'
  return 1
fi
# good, it works
return 0
}

# That we should have to do this is total bogosity, but GNU expr
# version 1.9.4-1.12 uses the emacs definition of "$" instead of the unix
# (e.g. SunOS 4.1.3 expr) one.  Rumor has it this will be fixed in the
# next release of GNU expr after 1.12 (but we still have to cater to the old
# ones for some time because they are in many linux distributions).
ENDANCHOR="$"
expr_set_ENDANCHOR ()
{
expr=$1
ENDANCHOR="$"
if $expr 'abc
def' : 'abc$' >/dev/null; then
  ENDANCHOR='\'\'
   echo "Notice: An ENDANCHOR of dollar does not work."
   echo "Using a workaround for GNU expr versions 1.9.4 thru 1.12"
fi
return 0
}

# Work around another GNU expr (version 1.10-1.12) bug/incompatibility.
# "." doesn't appear to match a newline (it does with SunOS 4.1.3 expr).
# Note that the workaround is not a complete equivalent of .* because
# the first parenthesized expression in the regexp must match something
# in order for expr to return a successful exit status.
# Rumor has it this will be fixed in the
# next release of GNU expr after 1.12 (but we still have to cater to the old
# ones for some time because they are in many linux distributions).
DOTSTAR='.*'
expr_set_DOTSTAR ()
{
expr=$1
DOTSTAR='.*'
if $expr 'abc
def' : "a${DOTSTAR}f" >/dev/null; then
  : good, it works
else
  DOTSTAR='\(.\|
\)*'
  echo "Notice: DOTSTAR changed from sane \`.*' value to \`$DOTSTAR\`"
  echo "to workaround GNU expr version 1.10 thru 1.12 bug where \`.'"
  echo "does not match a newline."
fi
return 0
}

# Now that we have DOTSTAR, make sure it works with big matches
expr_tooltest_DOTSTAR ()
{
expr=$1
test ! -f ${TESTDIR}/bar && expr_create_bar
if $expr "`cat ${TESTDIR}/bar`" : "${DOTSTAR}xyzABC${DOTSTAR}$" >/dev/null; then
  # good, it works
  return 0
else
  echo 'Warning: you are using a version of expr that does not correctly'
  echo 'match large patterns.  Some tests may spuriously pass or fail.'
  echo 'You may wish to make sure GNU expr is in your path.'
  return 77
fi
}

EXPR=`find_tool ${EXPR}:gexpr \
  version_test expr_tooltest1 expr_tooltest2 expr_tooltest3 \
expr_set_ENDANCHOR expr_set_DOTSTAR expr_tooltest_DOTSTAR`

# Set the ENDANCHOR and DOTSTAR for the chosen expr version.
expr_set_ENDANCHOR ${EXPR} >/dev/null
expr_tooltest_DOTSTAR ${EXPR} >/dev/null

echo "Using EXPR=$EXPR" >>$LOGFILE
echo "Using ENDANCHOR=$ENDANCHOR" >>$LOGFILE
echo "Using DOTSTAR=$DOTSTAR" >>$LOGFILE

# Cleanup
rm -f ${TESTDIR}/bar

# Work around yet another GNU expr (version 1.10) bug/incompatibility.
# "+" is a special character, yet for unix expr (e.g. SunOS 4.1.3)
# it is not.  I doubt that POSIX allows us to use \+ and assume it means
# (non-special) +, so here is another workaround
# Rumor has it this will be fixed in the
# next release of GNU expr after 1.12 (but we still have to cater to the old
# ones for some time because they are in many linux distributions).
PLUS='+'
if $EXPR 'a +b' : "a ${PLUS}b" >/dev/null; then
  : good, it works
else
  PLUS='\+'
fi

# Likewise, for ?
QUESTION='?'
if $EXPR 'a?b' : "a${QUESTION}b" >/dev/null; then
  : good, it works
else
  QUESTION='\?'
fi

# Now test the username to make sure it contains only valid characters
username=`$ID -un`
if $EXPR "${username}" : "${username}" >/dev/null; then
  : good, it works
else
  echo "Test suite does not work correctly when run by a username" >&2
  echo "containing regular expression meta-characters." >&2
  exit 1
fi

# Only 8 characters of $username appear in some output.
if test `echo $username |wc -c` -gt 8; then
  username8=`echo $username |sed 's/^\(........\).*/\1/'`
else
  username8=$username
fi

# Rarely, we need to match any username, not just the name of the user
# running this test.  This variable usually shouldn't be used.  $username
# contains the name of the user actually running this test.
#
# I believe this only ever actually gets compared to usernames created by this
# test.  It used to be compared to the username of the user running this test,
# but this hasn't been true for a long time.  Regardless, I tried to get the
# allowed character set right, based on a list in a private email from Mark
# Baushke, basically the allowed names from Linux systems (plus `.', which is
# only allowed on Gentoo Linux as of 2005-09-13).
anyusername="[_a-zA-Z0-9][-_.$a-zA-Z0-9]*"

# now make sure that tr works on NULs
tr_tooltest1 ()
{
tr=$1
if $EXPR `echo "123" | $tr '2' '\0'` : "123" >/dev/null 2>&1; then
  echo 'Warning: you are using a version of tr which does not correctly'
  echo 'handle NUL bytes.  Some tests may spuriously pass or fail.'
  echo 'You may wish to make sure GNU tr is in your path.'
  return 77
fi
# good, it works
return 0
}

TR=`find_tool ${TR}:gtr version_test tr_tooltest1`
echo "Using TR=$TR" >>$LOGFILE

# MacOS X (10.2.8) has a /bin/ls that does not work correctly in that
# it will return true even if the wildcard argument does not match any
# files.
ls_tooltest ()
{
ls=$1
# Force cleanup
if test -d $TESTDIR/ls-test; then
    chmod -R a+wx $TESTDIR/ls-test
    rm -rf $TESTDIR/ls-test
fi
if $ls $TESTDIR/ls-test >/dev/null 2>&1; then
  echo "Notice: \`$ls' is defective."
  echo 'This is a version of ls which does not correctly'
  echo 'return false for files that do not exist. Some tests may'
  echo 'spuriously pass or fail.'
  echo 'You may wish to put a an ls from GNU coreutils into your path.'
  return 77
else
  return 0
fi
}
LS=`find_tool ls:gls version_test ls_tooltest`
echo "Using LS=$LS" >>$LOGFILE

# Awk testing

awk_tooltest1 ()
{
awk=$1
$awk 'BEGIN {printf("one\ntwo\nthree\nfour\nfive\nsix")}' </dev/null >abc
if $EXPR "`cat abc`" : \
'one
two
three
four
five
six'; then
  rm abc
  return 0
else
  rm abc
  echo "Notice: awk BEGIN clause or printf is not be working properly."
  return 1
fi
}

# Format item %c check
awk_tooltest2 ()
{
awk=$1
$awk 'BEGIN { printf "%c%c%c", 2, 3, 4 }' </dev/null \
  | ${TR} '\002\003\004' '123' >abc
if $EXPR "`cat abc`" : "123" ; then
  : good, found it
else
  echo "Notice: awk format %c string may not be working properly."
  rm abc
  return 77
fi
rm abc
return 0
}

AWK=`find_tool gawk:nawk:awk version_test awk_tooltest1 awk_tooltest2`
echo "Using AWK=$AWK" >>$LOGFILE


###
### Functions used by tests.
###

# Execute a command on the repository, syncing when done if necessary.
#
# Syntax is as `eval'.
modify_repo ()
{
    eval "$*"
    if $proxy; then
	# And now resync the secondary.
	$TESTDIR/sync-secondary "repo modification" modify_repo ALL "$@"
    fi
}

# Restore changes to CVSROOT admin files.
restore_adm ()
{
    modify_repo rm -rf $CVSROOT_DIRNAME/CVSROOT
    modify_repo cp -Rp $TESTDIR/CVSROOT.save $CVSROOT_DIRNAME/CVSROOT
}

# Test that $RSYNC supports the options we need or try to find a
# replacement. If $RSYNC works or we replace it, and return 0.
# Otherwise, set $skipreason and return 77.
require_rsync ()
{
  rsyncworks=false
  # rsync is NOT a GNU tool, so do NOT use find_tool for name munging.
  for rsync in ${RSYNC} `Which -a rsync`;
  do

    if is_bad_tool `Which $rsync` ; then continue ; fi
    # Make some data to test rsync on.
    mkdir $TESTDIR/rsync-test
    mkdir $TESTDIR/rsync-test/Attic && touch $TESTDIR/rsync-test/Attic/6
    mkdir $TESTDIR/rsync-test/otherdir && touch $TESTDIR/rsync-test/otherdir/7
    for file in 1 2 3 4 5; do
      touch $TESTDIR/rsync-test/$file
    done
  
    if test -f "$rsync" && test -r "$rsync" \
      && $rsync -rglop --delete $TESTDIR/rsync-test/ $TESTDIR/rsync-test-copy \
  	      >/dev/null 2>&1 \
      && $rsync -rglop --delete --include Attic --exclude '*/' \
  	      $TESTDIR/rsync-test/ $TESTDIR/rsync-test-copy2 \
  	      >/dev/null 2>&1 \
      && test -f $TESTDIR/rsync-test/5 \
      && mv $TESTDIR/rsync-test/5 $TESTDIR/rsync-test/Attic/5 \
      && test -f $TESTDIR/rsync-test-copy/Attic/6 \
      && $rsync -rglop --delete $TESTDIR/rsync-test/ $TESTDIR/rsync-test-copy \
  	      >/dev/null 2>&1 \
      && $rsync -rglop --delete --include Attic --exclude '*/' \
  	      $TESTDIR/rsync-test/ $TESTDIR/rsync-test-copy2 \
  	      >/dev/null 2>&1 \
      && test ! -f $TESTDIR/rsync-test-copy/5 \
      && test ! -f $TESTDIR/rsync-test-copy2/5 \
      && test -f $TESTDIR/rsync-test-copy2/Attic/5 \
      && test ! -f $TESTDIR/rsync-test-copy2/otherdir/7
    then
      # good, it works
      rsyncworks=:
      RSYNC=$rsync
    else
      # Only use Which because of ${RSYNC} in the for loop.
      set_bad_tool `Which $rsync`
    fi
  
    rm -rf $TESTDIR/rsync-test $TESTDIR/rsync-test-copy \
       $TESTDIR/rsync-test-copy2

    if $rsyncworks; then
      return 0
    else
      (echo $rsync failed to work properly;\
       echo "$rsync --version"; $rsync --version) >>$LOGFILE 2>&1
    fi
  done

  unset RSYNC
  skipreason="unusable or no rsync found"
  return 77
}

# Test that $1 works as a remote shell.  If so, set $host, $CVS_RSH, &
# $save_CVS_RSH to match and return 0.  Otherwise, set $skipreason and return
# 77.
require_rsh ()
{
  host=${remotehost-"`hostname`"}
  result=`$1 $host 'echo test'`
  rc=$?
  if test $? != 0 || test "x$result" != "xtest"; then
    skipreason="\`$1 $host' failed rc=$rc result=$result"
    return 77
  fi

  save_CVS_RSH=$CVS_RSH
  CVS_RSH=$1; export CVS_RSH
  return 0
}

# Find a usable SSH.  When a usable ssh is found, set $host, $CVS_RSH, and
# $save_CVS_RSH and return 0.  Otherwise, set $skipreason and return 77.
require_ssh ()
{
  case "$CVS_RSH" in
    *ssh*|*putty*)
      tryssh=`Which $CVS_RSH`
      if [ ! -n "$tryssh" ]; then
	skipreason="Unable to find CVS_RSH=$CVS_RSH executable"
	return 77
      elif [ ! -x "$tryssh" ]; then
	skipreason="Unable to execute $tryssh program"
	return 77
      fi
      ;;
    *)
      # Look in the user's PATH for "ssh"
      tryssh=`Which ssh`
      if test ! -r "$tryssh"; then
	skipreason="Unable to find ssh program"
	return 77
      fi
      ;;
  esac

  require_rsh "$tryssh"
  return $?
}

pass ()
{
  echo "PASS: $1" >>${LOGFILE}
  passed=`expr $passed + 1`
}

# Like skip(), but don't fail when $skipfail is set.
skip_always ()
{
  echo "SKIP: $1${2+ ($2)}" >>$LOGFILE
  skipped=`expr $skipped + 1`
}

skip ()
{
  if $skipfail; then
    # exits
    fail "$1${2+ ($2)}"
  fi

  skip_always ${1+"$@"}
}

# Convenience function for skipping tests run only in remote mode.
remoteonly ()
{
  skip_always $1 "only tested in remote mode"
}

# Convenience function for skipping tests not run in proxy mode.
notproxy ()
{
  skip_always $1 "not tested in proxy mode"
}

# Convenience function for skipping tests not run in proxy mode.
notnoredirect ()
{
  skip_always $1 "not tested in proxy-noredirect mode"
}

warn ()
{
  if $skipfail; then
    fail "$1${2+ ($2)}"
  else
    echo "WARNING: $1${2+ ($2)}" >>$LOGFILE
  fi
  warnings=`expr $warnings + 1`
}

fail ()
{
  echo "FAIL: $1" | tee -a ${LOGFILE}
  echo "*** Please see the \`TESTS' and \`check.log' files for more information." >&2
  # This way the tester can go and see what remnants were left
  exit 1
}

verify_tmp_empty ()
{
  # Test our temp directory for cvs-serv* directories and cvsXXXXXX temp
  # files.  We would like to not leave any behind.
  if $remote && $LS $TMPDIR/cvs-serv* >/dev/null 2>&1; then
    # A true value means ls found files/directories with these names.
    # Give the server some time to finish, then retry.
    sleep 1
    if $LS $TMPDIR/cvs-serv* >/dev/null 2>&1; then
      warn "$1" "Found cvs-serv* directories in $TMPDIR."
      # The above will exit if $skipfail
      rm -rf $TMPDIR/cvs-serv*
    fi
  fi
  if $LS $TMPDIR/cvs?????? >/dev/null 2>&1; then
    # A true value means ls found files/directories with these names.
    warn "$1" "Found cvsXXXXXX temp files in $TMPDIR."
    # The above will exit if $skipfail
    rm -f ls $TMPDIR/cvs??????
  fi
}

# See dotest and dotest_fail for explanation (this is the parts
# of the implementation common to the two).
dotest_internal ()
{
  if $EXPR "`cat ${TESTDIR}/dotest.tmp`" : "$3${ENDANCHOR}" >/dev/null; then
    # Why, I hear you ask, do we write this to the logfile
    # even when the test passes?  The reason is that the test
    # may give us the regexp which we were supposed to match,
    # but sometimes it may be useful to look at the exact
    # text which was output.  For example, suppose one wants
    # to grep for a particular warning, and make _sure_ that
    # CVS never hits it (even in cases where the tests might
    # match it with .*).  Or suppose one wants to see the exact
    # date format output in a certain case (where the test will
    # surely use a somewhat non-specific pattern).
    cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
    pass "$1"
    verify_tmp_empty "$1"
  # expr can't distinguish between "zero characters matched" and "no match",
  # so special-case it.
  elif test -z "$3" && test ! -s ${TESTDIR}/dotest.tmp; then
    pass "$1"
    verify_tmp_empty "$1"
  elif test x"$4" != x; then
    if $EXPR "`cat ${TESTDIR}/dotest.tmp`" : "$4${ENDANCHOR}" >/dev/null; then
      cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
      pass "$1"
      verify_tmp_empty "$1"
    else
      echo "** expected: " >>${LOGFILE}
      echo "$3" >>${LOGFILE}
      echo "$3" > ${TESTDIR}/dotest.ex1
      echo "** or: " >>${LOGFILE}
      echo "$4" >>${LOGFILE}
      echo "$4" > ${TESTDIR}/dotest.ex2
      echo "** got: " >>${LOGFILE}
      cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
      fail "$1"
    fi
  else
    echo "** expected: " >>${LOGFILE}
    echo "$3" >>${LOGFILE}
    echo "$3" > ${TESTDIR}/dotest.exp
    echo "** got: " >>${LOGFILE}
    cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
    fail "$1"
  fi
}

dotest_all_in_one ()
{
  if $EXPR "`cat ${TESTDIR}/dotest.tmp`" : \
         "`cat ${TESTDIR}/dotest.exp`" >/dev/null; then
    return 0
  fi
  return 1
}

# WARNING: this won't work with REs that match newlines....
#
dotest_line_by_line ()
{
  line=1
  while [ $line -le `wc -l <${TESTDIR}/dotest.tmp` ] ; do
    if $EXPR "`sed -n ${line}p ${TESTDIR}/dotest.tmp`" : \
       "`sed -n ${line}p ${TESTDIR}/dotest.exp`" >/dev/null; then
      :
    elif test -z "`sed -n ${line}p ${TESTDIR}/dotest.tmp`" &&
       test -z "`sed -n ${line}p ${TESTDIR}/dotest.exp`"; then
      :
    else
      echo "Line $line:" >> ${LOGFILE}
      echo "**** expected: " >>${LOGFILE}
      sed -n ${line}p ${TESTDIR}/dotest.exp >>${LOGFILE}
      echo "**** got: " >>${LOGFILE}
      sed -n ${line}p ${TESTDIR}/dotest.tmp >>${LOGFILE}
      unset line
      return 1
    fi
    line=`expr $line + 1`
  done
  unset line
  return 0
}

# If you are having trouble telling which line of a multi-line
# expression is not being matched, replace calls to dotest_internal()
# with calls to this function:
#
dotest_internal_debug ()
{
  if test -z "$3"; then
    if test -s ${TESTDIR}/dotest.tmp; then
      echo "** expected: " >>${LOGFILE}
      echo "$3" >>${LOGFILE}
      echo "$3" > ${TESTDIR}/dotest.exp
      rm -f ${TESTDIR}/dotest.ex2
      echo "** got: " >>${LOGFILE}
      cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
      fail "$1"
    else
      pass "$1"
      verify_tmp_empty "$1"
    fi
  else
    echo "$3" > ${TESTDIR}/dotest.exp
    if dotest_line_by_line "$1" "$2"; then
      pass "$1"
      verify_tmp_empty "$1"
    else
      if test x"$4" != x; then
	mv ${TESTDIR}/dotest.exp ${TESTDIR}/dotest.ex1
	echo "$4" > ${TESTDIR}/dotest.exp
	if dotest_line_by_line "$1" "$2"; then
	  pass "$1"
	  verify_tmp_empty "$1"
	else
	  mv ${TESTDIR}/dotest.exp ${TESTDIR}/dotest.ex2
	  echo "** expected: " >>${LOGFILE}
	  echo "$3" >>${LOGFILE}
	  echo "** or: " >>${LOGFILE}
	  echo "$4" >>${LOGFILE}
	  echo "** got: " >>${LOGFILE}
	  cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
	  fail "$1"
	fi
      else
	echo "** expected: " >>${LOGFILE}
	echo "$3" >>${LOGFILE}
	echo "** got: " >>${LOGFILE}
	cat ${TESTDIR}/dotest.tmp >>${LOGFILE}
	fail "$1"
      fi
    fi
  fi
}

# This function allows the test output to be filtered before being verified.
# The dotest_* functions all call this function, which runs the command
# in the env var $TEST_FILTER on its argument if $TEST_FILTER is set.  If
# $TEST_FILTER is not set, this function does nothing.
#
# I found this primarily useful when running the test suite on a CVS
# executable linked with memory and function profilers which can generate
# spurious output.
run_filter ()
{
  if test -n "$TEST_FILTER"; then
    # Make sure there is an EOL
    echo >>$1
    sed '${/^$/d}' <$1 >$1.filter1
    # Run the filter
    eval "$TEST_FILTER" <$1.filter1 >$1.filter2
    diff -u $1 $1.filter2 \
	    >$1.diff
    mv $1.filter2 $1
    rm $1.filter1
  fi
}

# Usage:
#  dotest TESTNAME COMMAND OUTPUT [OUTPUT2]
# TESTNAME is the name used in the log to identify the test.
# COMMAND is the command to run; for the test to pass, it exits with
# exitstatus zero.
# OUTPUT is a regexp which is compared against the output (stdout and
# stderr combined) from the test.  It is anchored to the start and end
# of the output, so should start or end with ".*" if that is what is desired.
# Trailing newlines are stripped from the command's actual output before
# matching against OUTPUT.
# If OUTPUT2 is specified and the output matches it, then it is also
# a pass (partial workaround for the fact that some versions of expr
# lack \|).
dotest ()
{
  rm -f $TESTDIR/dotest.ex? 2>&1
  eval "$2" >$TESTDIR/dotest.tmp 2>&1
  status=$?
  run_filter $TESTDIR/dotest.tmp
  if test "$status" != 0; then
    cat $TESTDIR/dotest.tmp >>$LOGFILE
    echo "exit status was $status" >>${LOGFILE}
    fail "$1"
  fi
  dotest_internal "$@"
}

# Like dotest except only 2 args and result must exactly match stdin
dotest_lit ()
{
  rm -f $TESTDIR/dotest.ex? 2>&1
  eval "$2" >$TESTDIR/dotest.tmp 2>&1
  status=$?
  run_filter $TESTDIR/dotest.tmp
  if test "$status" != 0; then
    cat $TESTDIR/dotest.tmp >>$LOGFILE
    echo "exit status was $status" >>$LOGFILE
    fail "$1"
  fi
  cat >$TESTDIR/dotest.exp
  if cmp $TESTDIR/dotest.exp $TESTDIR/dotest.tmp >/dev/null 2>&1; then
    pass "$1"
    verify_tmp_empty "$1"
  else
    echo "** expected: " >>$LOGFILE
    cat $TESTDIR/dotest.exp >>$LOGFILE
    echo "** got: " >>$LOGFILE
    cat $TESTDIR/dotest.tmp >>$LOGFILE
    fail "$1"
  fi
}

# Like dotest except exitstatus should be nonzero.
dotest_fail ()
{
  rm -f $TESTDIR/dotest.ex? 2>&1
  eval "$2" >$TESTDIR/dotest.tmp 2>&1
  status=$?
  run_filter $TESTDIR/dotest.tmp
  if test "$status" = 0; then
    cat $TESTDIR/dotest.tmp >>$LOGFILE
    echo "exit status was $status" >>$LOGFILE
    fail "$1"
  fi
  dotest_internal "$@"
}

# Like dotest except output is sorted.
dotest_sort ()
{
  rm -f $TESTDIR/dotest.ex? 2>&1
  eval "$2" >$TESTDIR/dotest.tmp1 2>&1
  status=$?
  run_filter $TESTDIR/dotest.tmp1
  if test "$status" != 0; then
    cat $TESTDIR/dotest.tmp1 >>$LOGFILE
    echo "exit status was $status" >>$LOGFILE
    fail "$1"
  fi
  $TR '	' ' ' < $TESTDIR/dotest.tmp1 | sort > $TESTDIR/dotest.tmp
  dotest_internal "$@"
}

# Like dotest_fail except output is sorted.
dotest_fail_sort ()
{
  rm -f $TESTDIR/dotest.ex? 2>&1
  eval "$2" >$TESTDIR/dotest.tmp1 2>&1
  status=$?
  run_filter $TESTDIR/dotest.tmp1
  if test "$status" = 0; then
    cat $TESTDIR/dotest.tmp1 >>$LOGFILE
    echo "exit status was $status" >>$LOGFILE
    fail "$1"
  fi
  $TR '	' ' ' < $TESTDIR/dotest.tmp1 | sort > $TESTDIR/dotest.tmp
  dotest_internal "$@"
}

# A function for fetching the timestamp of a revison of a file
getrlogdate () {
    ${testcvs} -n rlog -N ${1+"$@"} |
    while read token value; do
	case "$token" in
	date:)
	    echo $value | sed "s,;.*,,"
	    break;
            ;;
	esac
    done
}

# Avoid picking up any stray .cvsrc, etc., from the user running the tests
mkdir home
HOME=$TESTDIR/home; export HOME

# Make sure this variable is not defined to anything that would
# change the format of rcs dates.  Otherwise people using e.g.,
# RCSINIT=-zLT get lots of spurious failures.
RCSINIT=; export RCSINIT

# Remaining arguments are the names of tests to run.
#
# The testsuite is broken up into (hopefully manageably-sized)
# independently runnable tests, so that one can quickly get a result
# from a cvs or testsuite change, and to facilitate understanding the
# tests.

if test x"$*" = x; then
	# Basic/miscellaneous functionality
	tests="version basica basicb basicc basic1 deep basic2 ls"
	tests="$tests parseroot parseroot2 parseroot3 files spacefiles"
	tests="${tests} commit-readonly commit-add-missing"
	tests="${tests} status"
	# Branching, tagging, removing, adding, multiple directories
	tests="${tests} rdiff rdiff-short"
	tests="${tests} rdiff2 diff diffnl death death2"
	tests="${tests} rm-update-message rmadd rmadd2 rmadd3 resurrection"
	tests="${tests} dirs dirs2 branches branches2 branches3"
	tests="${tests} branches4 tagc tagf tag-space"
	tests="${tests} rcslib multibranch import importb importc importX"
	tests="$tests importX2 import-CVS import-quirks"
	tests="${tests} update-p import-after-initial branch-after-import"
	tests="${tests} join join2 join3 join4 join5 join6 join7"
	tests="${tests} join-readonly-conflict join-admin join-admin-2"
	tests="${tests} join-rm"
	tests="${tests} new newb conflicts conflicts2 conflicts3"
	tests="${tests} clean"
	tests="${tests} keywordexpand"
	# Checking out various places (modules, checkout -d, &c)
	tests="${tests} modules modules2 modules3 modules4 modules5 modules6"
	tests="${tests} modules7 mkmodules co-d"
	tests="${tests} cvsadm emptydir abspath abspath2 toplevel toplevel2"
        tests="${tests} rstar-toplevel trailingslashes checkout_repository"
	# Log messages, error messages.
	tests="${tests} mflag editor env errmsg1 errmsg2 adderrmsg opterrmsg"
	tests="${tests} errmsg3"
	tests="${tests} close-stdout"
	tests="$tests debug-log-nonfatal"
	# Watches, binary files, history browsing, &c.
	tests="${tests} devcom devcom2 devcom3 watch4 watch5 watch6-0 watch6"
        tests="${tests} edit-check"
	tests="${tests} unedit-without-baserev"
	tests="${tests} ignore ignore-on-branch binfiles binfiles2 binfiles3"
	tests="${tests} mcopy binwrap binwrap2"
	tests="${tests} binwrap3 mwrap info taginfo posttag"
	tests="$tests config config2 config3 config4"
	tests="${tests} serverpatch log log2 logopt ann ann-id"
	# Repository Storage (RCS file format, CVS lock files, creating
	# a repository without "cvs init", &c).
	tests="${tests} crerepos rcs rcs2 rcs3 rcs4 rcs5"
	tests="$tests lockfiles backuprecover"
	tests="${tests} sshstdio"
	# More history browsing, &c.
	tests="${tests} history"
	tests="${tests} big modes modes2 modes3 stamps"
	# PreservePermissions stuff: permissions, symlinks et al.
	# tests="${tests} perms symlinks symlinks2 hardlinks"
	# More tag and branch tests, keywords.
	tests="${tests} sticky keyword keywordlog keywordname keyword2"
	tests="${tests} head tagdate multibranch2 tag8k"
	# "cvs admin", reserved checkouts.
	tests="${tests} admin reserved"
	# Nuts and bolts of diffing/merging (diff library, &c)
	tests="${tests} diffmerge1 diffmerge2"
	# Release of multiple directories
	tests="${tests} release"
	tests="${tests} recase"
	# Multiple root directories and low-level protocol tests.
	tests="${tests} multiroot multiroot2 multiroot3 multiroot4"
	tests="${tests} rmroot reposmv pserver server server2 client"
	tests="${tests} dottedroot fork commit-d template"
	tests="${tests} writeproxy writeproxy-noredirect writeproxy-ssh"
	tests="${tests} writeproxy-ssh-noredirect"
else
	tests="$*"
fi

# Now check the -f argument for validity.
if test -n "$fromtest"; then
	# Don't allow spaces - they are our delimiters in tests
	count=0
	for sub in $fromtest; do
	  count=`expr $count + 1`
	done
	if test $count != 1; then
		echo "No such test \`$fromtest'." >&2
		exit 2
	fi
	# make sure it is in $tests
	case " $tests " in
		*" $fromtest "*)
			;;
		*)
			echo "No such test \`$fromtest'." >&2
			exit 2
			;;
	esac
fi



# a simple function to compare directory contents
#
# Returns: 0 for same, 1 for different
#
directory_cmp ()
{
	OLDPWD=`pwd`
	DIR_1=$1
	DIR_2=$2

	cd $DIR_1
	find . -print | fgrep -v /CVS | sort > $TESTDIR/dc$$d1

	# go back where we were to avoid symlink hell...
	cd $OLDPWD
	cd $DIR_2
	find . -print | fgrep -v /CVS | sort > $TESTDIR/dc$$d2

	if diff $TESTDIR/dc$$d1 $TESTDIR/dc$$d2 >/dev/null 2>&1
	then
		:
	else
		return 1
	fi
	cd $OLDPWD
	while read a
	do
		if test -f $DIR_1/"$a" ; then
			cmp -s $DIR_1/"$a" $DIR_2/"$a"
			if test $? -ne 0 ; then
				return 1
			fi
		fi
	done < $TESTDIR/dc$$d1
	rm -f $TESTDIR/dc$$*
	return 0
}



#
# The following 4 functions are used by the diffmerge1 test case.  They set up,
# respectively, the four versions of the files necessary:
#
#	1.  Ancestor revisions.
#	2.  "Your" changes.
#	3.  "My" changes.
#	4.  Expected merge result.
#

# Create ancestor revisions for diffmerge1
diffmerge_create_older_files() {
	  # This test case was supplied by Noah Friedman:
	  cat >testcase01 <<EOF
// Button.java

package random.application;

import random.util.*;

public class Button
{
  /* Instantiates a Button with origin (0, 0) and zero width and height.
   * You must call an initializer method to properly initialize the Button.
   */
  public Button ()
  {
    super ();

    _titleColor = Color.black;
    _disabledTitleColor = Color.gray;
    _titleFont = Font.defaultFont ();
  }

  /* Convenience constructor for instantiating a Button with
   * bounds x, y, width, and height.  Equivalent to
   *     foo = new Button ();
   *     foo.init (x, y, width, height);
   */
  public Button (int x, int y, int width, int height)
  {
    this ();
    init (x, y, width, height);
  }
}
EOF

	  # This test case was supplied by Jacob Burckhardt:
	  cat >testcase02 <<EOF
a
a
a
a
a
EOF

	  # This test case was supplied by Karl Tomlinson who also wrote the
	  # patch which lets CVS correctly handle this and several other cases:
	  cat >testcase03 <<EOF
x
s
a
b
s
y
EOF

	  # This test case was supplied by Karl Tomlinson:
	  cat >testcase04 <<EOF
s
x
m
m
x
s
v
s
x
m
m
x
s
EOF

	  # This test case was supplied by Karl Tomlinson:
	  cat >testcase05 <<EOF
s
x
m
m
x
x
x
x
x
x
x
x
x
x
s
s
s
s
s
s
s
s
s
s
v
EOF

	  # This test case was supplied by Jacob Burckhardt:
	  cat >testcase06 <<EOF
g











i
EOF

	  # This test is supposed to verify that the horizon lines are the same
	  # for both 2-way diffs, but unfortunately, it does not fail with the
	  # old version of cvs.  However, Karl Tomlinson still thought it would
	  # be good to test it anyway:
	  cat >testcase07 <<EOF
h
f









g
r



i










i
EOF

	  # This test case was supplied by Jacob Burckhardt:
	  cat >testcase08 <<EOF
Both changes move this line to the end of the file.

no
changes
here

First change will delete this line.

First change will also delete this line.

    no
    changes
    here

Second change will change it here.

        no
        changes
        here
EOF

	  # This test case was supplied by Jacob Burckhardt.  Note that I do not
	  # think cvs has ever failed with this case, but I include it anyway,
	  # since I think it is a hard case.  It is hard because Peter Miller's
	  # fmerge utility fails on it:
	  cat >testcase09 <<EOF
m
a
{
}
b
{
}
EOF

	  # This test case was supplied by Martin Dorey and simplified by Jacob
	  # Burckhardt:
	  cat >testcase10 <<EOF

    petRpY ( MtatRk );
    fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG );

    MtatRk = MQfr_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_KRLIep * jfle_Uecopd_MfJe_fY_nEtek );
    OjZy MtatRk = Uead_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_MfJe_fY_nEtek, nRVVep );

    Bloke_GttpfIRte_MtpeaL ( &acI );
MTGTXM Uead_Ktz_qjT_jfle_Uecopd ( fYt Y, uofd *nRVVep )
{
    fV ( Y < 16 )
    {
        petRpY ( Uead_Mectopk ( noot_Uecopd.qVtHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
                                                      Y * jfle_Uecopd_MfJe_fY_Mectopk,
                                jfle_Uecopd_MfJe_fY_Mectopk,
                                nRVVep ) );
    }
    elke
    {
        petRpY ( Uead_Mectopk ( noot_Uecopd.qVtqfppHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
                                                 ( Y - 16 ) * jfle_Uecopd_MfJe_fY_Mectopk,
                                jfle_Uecopd_MfJe_fY_Mectopk,
                                nRVVep ) );
    }

}


/****************************************************************************
*                                                                           *
*   Uead Mectopk ( Uelatfue to tze cRppeYt raptftfoY )                      *
*                                                                           *
****************************************************************************/

MTGTXM Uead_Mectopk ( RfYt64 Mtapt_Mectop, RfYt64 KRL_Mectopk, uofd *nRVVep )
{
MTGTXM MtatRk = Zy;

    MtatRk = Uead_HfkQ ( FaptftfoY_TaIle.Uelatfue_Mectop + Mtapt_Mectop, KRL_Mectopk, nRVVep );

    petRpY ( MtatRk );

}
    HfkQipfte ( waYdle,                 /*  waYdle                         */
                waYdleFok,              /*  ZVVket VpoL ktapt oV dfkQ      */
                (coYkt RfYt8*) nRVVep,  /*  nRVVep                         */
                0,                      /*  MRrepVlRoRk KfxoYfkL           */
                beYgtz                  /*  nEtek to Apfte                 */
              );

    petRpY ( Zy );
}
EOF
}

# Create "your" revisions for diffmerge1
diffmerge_create_your_files() {
	  # remove the Button() method
	  cat >testcase01 <<\EOF
// Button.java

package random.application;

import random.util.*;

public class Button
{
  /* Instantiates a Button with origin (0, 0) and zero width and height.
   * You must call an initializer method to properly initialize the Button.
   */
  public Button ()
  {
    super ();

    _titleColor = Color.black;
    _disabledTitleColor = Color.gray;
    _titleFont = Font.defaultFont ();
  }
}
EOF

	  cat >testcase02 <<\EOF
y
a
a
a
a
EOF

	  cat >testcase03 <<\EOF
x
s
a
b
s
b
s
y
EOF

	  cat >testcase04 <<\EOF
s
m
s
v
s
m
s
EOF

	  cat >testcase05 <<\EOF
v
s
m
s
s
s
s
s
s
s
s
s
s
v
EOF

	  # Test case 6 and test case 7 both use the same input files, but they
	  # order the input files differently.  In one case, a certain file is
	  # used as the older file, but in the other test case, that same file
	  # is used as the file which has changes.  I could have put echo
	  # commands here, but since the echo lines would be the same as those
	  # in the previous function, I decided to save space and avoid repeating
	  # several lines of code.  Instead, I merely swap the files:
	  mv testcase07 tmp
	  mv testcase06 testcase07
	  mv tmp testcase06

	  # Make the date newer so that cvs thinks that the files are changed:
	  touch testcase06 testcase07

	  cat >testcase08 <<\EOF
no
changes
here

First change has now added this in.

    no
    changes
    here

Second change will change it here.

        no
        changes
        here

Both changes move this line to the end of the file.
EOF

	  cat >testcase09 <<\EOF

m
a
{
}
b
{
}
c
{
}
EOF

	  cat >testcase10 <<\EOF

    fV ( BzQkV_URYYfYg ) (*jfle_Uecopdk)[0].jfle_Uecopd_KRLIep = ZpfgfYal_jUK;

    petRpY ( MtatRk );
    fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG );

    fV ( jfle_Uecopd_KRLIep < 16 )
    {
        MtatRk = Uead_Ktz_qjT_jfle_Uecopd ( jfle_Uecopd_KRLIep, (uofd*)nRVVep );
    }
    elke
    {
        MtatRk = ZreY_GttpfIRte_MtpeaL ( qjT_jfle_Uecopdk, qjT_jfle_Uecopd_BoRYt, HGTG_TvFD, KXbb, KXbb, &acI );
        fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG );

        MtatRk = MQfr_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_KRLIep * jfle_Uecopd_MfJe_fY_nEtek );
        OjZy MtatRk = Uead_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_MfJe_fY_nEtek, nRVVep );

    Bloke_GttpfIRte_MtpeaL ( &acI );
MTGTXM Uead_Ktz_qjT_jfle_Uecopd ( fYt Y, uofd *nRVVep )
{
MTGTXM MtatRk = Zy;

    fV ( Y < 16 )
    {
        petRpY ( Uead_Mectopk ( noot_Uecopd.qVtHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
                                                      Y * jfle_Uecopd_MfJe_fY_Mectopk,
                                jfle_Uecopd_MfJe_fY_Mectopk,
                                nRVVep ) );
    }
    elke
    {
        petRpY ( Uead_Mectopk ( noot_Uecopd.qVtqfppHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
                                                 ( Y - 16 ) * jfle_Uecopd_MfJe_fY_Mectopk,
                                jfle_Uecopd_MfJe_fY_Mectopk,
                                nRVVep ) );
    }

    petRpY ( MtatRk );

}


/****************************************************************************
*                                                                           *
*   Uead Mectopk ( Uelatfue to tze cRppeYt raptftfoY )                      *
*                                                                           *
****************************************************************************/

MTGTXM Uead_Mectopk ( RfYt64 Mtapt_Mectop, RfYt64 KRL_Mectopk, uofd *nRVVep )
{
MTGTXM MtatRk = Zy;

    MtatRk = Uead_HfkQ ( FaptftfoY_TaIle.Uelatfue_Mectop + Mtapt_Mectop, KRL_Mectopk, nRVVep );

    petRpY ( MtatRk );

}
    HfkQipfte ( waYdle,                 /*  waYdle                         */
                waYdleFok,              /*  ZVVket VpoL ktapt oV dfkQ      */
                (coYkt RfYt8*) nRVVep,  /*  nRVVep                         */
                0,                      /*  MRrepVlRoRk KfxoYfkL           */
                beYgtz                  /*  nEtek to Apfte                 */
              );

    petRpY ( Zy );
}

EOF
}

# Create "my" revisions for diffmerge1
diffmerge_create_my_files() {
          # My working copy still has the Button() method, but I
	  # comment out some code at the top of the class.
	  cat >testcase01 <<\EOF
// Button.java

package random.application;

import random.util.*;

public class Button
{
  /* Instantiates a Button with origin (0, 0) and zero width and height.
   * You must call an initializer method to properly initialize the Button.
   */
  public Button ()
  {
    super ();

    // _titleColor = Color.black;
    // _disabledTitleColor = Color.gray;
    // _titleFont = Font.defaultFont ();
  }

  /* Convenience constructor for instantiating a Button with
   * bounds x, y, width, and height.  Equivalent to
   *     foo = new Button ();
   *     foo.init (x, y, width, height);
   */
  public Button (int x, int y, int width, int height)
  {
    this ();
    init (x, y, width, height);
  }
}
EOF

	  cat >testcase02 <<\EOF
a
a
a
a
m
EOF

	  cat >testcase03 <<\EOF
x
s
c
s
b
s
y
EOF

	  cat >testcase04 <<\EOF
v
s
x
m
m
x
s
v
s
x
m
m
x
s
v
EOF

	  # Note that in test case 5, there are no changes in the "mine"
	  # section, which explains why there is no command here which writes to
	  # file testcase05.

	  # no changes for testcase06

	  # The two branches make the same changes:
	  cp ../yours/testcase07 .

	  cat >testcase08 <<\EOF
no
changes
here

First change will delete this line.

First change will also delete this line.

    no
    changes
    here

Second change has now changed it here.

        no
        changes
        here

Both changes move this line to the end of the file.
EOF

	  cat >testcase09 <<\EOF
m
a
{
}
b
{
}
c
{
}
EOF

	  cat >testcase10 <<\EOF

    petRpY ( MtatRk );
    fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG );

    MtatRk = MQfr_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_KRLIep * jfle_Uecopd_MfJe_fY_nEtek );
    OjZy MtatRk = Uead_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_MfJe_fY_nEtek, nRVVep );

    Bloke_GttpfIRte_MtpeaL ( &acI );
MTGTXM Uead_Ktz_qjT_jfle_Uecopd ( fYt Y, uofd *nRVVep )
{
    fV ( Y < 16 )
    {
        petRpY ( Uead_Mectopk ( noot_Uecopd.qVtHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
                                                      Y * jfle_Uecopd_MfJe_fY_Mectopk,
                                jfle_Uecopd_MfJe_fY_Mectopk,
                                nRVVep ) );
    }
    elke
    {
        petRpY ( Uead_Mectopk ( noot_Uecopd.qVtqfppHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
                                                 ( Y - 16 ) * jfle_Uecopd_MfJe_fY_Mectopk,
                                jfle_Uecopd_MfJe_fY_Mectopk,
                                nRVVep ) );
    }

}


/****************************************************************************
*                                                                           *
*   Uead Mectopk ( Uelatfue to tze cRppeYt raptftfoY )                      *
*                                                                           *
****************************************************************************/

MTGTXM Uead_Mectopk ( RfYt64 Mtapt_Mectop, RfYt64 KRL_Mectopk, uofd *nRVVep )
{
MTGTXM MtatRk = Zy;

    MtatRk = Uead_HfkQ ( FaptftfoY_TaIle.Uelatfue_Mectop + Mtapt_Mectop, KRL_Mectopk, nRVVep );

    petRpY ( MtatRk );

}
    HfkQipfte ( waYdle,                 /*  waYdle                         */
                waYdleFok,              /*  ZVVket VpoL ktapt oV dfkQ      */
                (coYkt RfYt8*) nRVVep,  /*  nRVVep                         */
                beYgtz                  /*  nEtek to Apfte                 */
              );

    petRpY ( Zy );
}

EOF
}

# Create expected results of merge for diffmerge1
diffmerge_create_expected_files() {
	  cat >testcase01 <<\EOF
// Button.java

package random.application;

import random.util.*;

public class Button
{
  /* Instantiates a Button with origin (0, 0) and zero width and height.
   * You must call an initializer method to properly initialize the Button.
   */
  public Button ()
  {
    super ();

    // _titleColor = Color.black;
    // _disabledTitleColor = Color.gray;
    // _titleFont = Font.defaultFont ();
  }
}
EOF

	  cat >testcase02 <<\EOF
y
a
a
a
m
EOF

	  cat >testcase03 <<\EOF
x
s
c
s
b
s
b
s
y
EOF

	  cat >testcase04 <<\EOF
v
s
m
s
v
s
m
s
v
EOF

	  # Since there are no changes in the "mine" section, just take exactly
	  # the version in the "yours" section:
	  cp ../yours/testcase05 .

	  cp ../yours/testcase06 .

	  # Since the two branches make the same changes, the result should be
	  # the same as both branches.  Here, I happen to pick yours to copy from,
	  # but I could have also picked mine, since the source of the copy is
	  # the same in either case.  However, the mine has already been
	  # altered by the update command, so don't use it.  Instead, use the
	  # yours section which has not had an update on it and so is unchanged:
	  cp ../yours/testcase07 .

	  cat >testcase08 <<\EOF
no
changes
here

First change has now added this in.

    no
    changes
    here

Second change has now changed it here.

        no
        changes
        here

Both changes move this line to the end of the file.
EOF

	  cat >testcase09 <<\EOF

m
a
{
}
b
{
}
c
{
}
EOF

	  cat >testcase10 <<\EOF

    fV ( BzQkV_URYYfYg ) (*jfle_Uecopdk)[0].jfle_Uecopd_KRLIep = ZpfgfYal_jUK;

    petRpY ( MtatRk );
    fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG );

    fV ( jfle_Uecopd_KRLIep < 16 )
    {
        MtatRk = Uead_Ktz_qjT_jfle_Uecopd ( jfle_Uecopd_KRLIep, (uofd*)nRVVep );
    }
    elke
    {
        MtatRk = ZreY_GttpfIRte_MtpeaL ( qjT_jfle_Uecopdk, qjT_jfle_Uecopd_BoRYt, HGTG_TvFD, KXbb, KXbb, &acI );
        fV ( MtatRk != Zy ) UDTXUK_DUUZU ( BGKT_ZFDK_qjT_HGTG );

        MtatRk = MQfr_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_KRLIep * jfle_Uecopd_MfJe_fY_nEtek );
        OjZy MtatRk = Uead_GttpfIRte_MtpeaL ( &acI, jfle_Uecopd_MfJe_fY_nEtek, nRVVep );

    Bloke_GttpfIRte_MtpeaL ( &acI );
MTGTXM Uead_Ktz_qjT_jfle_Uecopd ( fYt Y, uofd *nRVVep )
{
MTGTXM MtatRk = Zy;

    fV ( Y < 16 )
    {
        petRpY ( Uead_Mectopk ( noot_Uecopd.qVtHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
                                                      Y * jfle_Uecopd_MfJe_fY_Mectopk,
                                jfle_Uecopd_MfJe_fY_Mectopk,
                                nRVVep ) );
    }
    elke
    {
        petRpY ( Uead_Mectopk ( noot_Uecopd.qVtqfppHatabcY0 * noot_Uecopd.MectopkFepBlRktep +
                                                 ( Y - 16 ) * jfle_Uecopd_MfJe_fY_Mectopk,
                                jfle_Uecopd_MfJe_fY_Mectopk,
                                nRVVep ) );
    }

    petRpY ( MtatRk );

}


/****************************************************************************
*                                                                           *
*   Uead Mectopk ( Uelatfue to tze cRppeYt raptftfoY )                      *
*                                                                           *
****************************************************************************/

MTGTXM Uead_Mectopk ( RfYt64 Mtapt_Mectop, RfYt64 KRL_Mectopk, uofd *nRVVep )
{
MTGTXM MtatRk = Zy;

    MtatRk = Uead_HfkQ ( FaptftfoY_TaIle.Uelatfue_Mectop + Mtapt_Mectop, KRL_Mectopk, nRVVep );

    petRpY ( MtatRk );

}
    HfkQipfte ( waYdle,                 /*  waYdle                         */
                waYdleFok,              /*  ZVVket VpoL ktapt oV dfkQ      */
                (coYkt RfYt8*) nRVVep,  /*  nRVVep                         */
                beYgtz                  /*  nEtek to Apfte                 */
              );

    petRpY ( Zy );
}

EOF
}



# Echo a new CVSROOT based on $1, $remote, and $remotehost
newroot() {
  if $remote; then
    if test -n "$remotehost"; then
      echo :ext$rootoptions:$remotehost$1
    else
      echo :fork$rootoptions:$1
    fi
  else
    echo $1
  fi
}



# Set up CVSROOT (the crerepos tests will test operating without CVSROOT set).
#
# Currently we test :fork: and :ext: (see crerepos test).  There is a
# known difference between the two in modes-15 (see comments there).
#
# :ext: can be tested against a remote machine if:
#
#    1. $remotehost is set using the `-h' option to this script.
#    2. ${CVS_RSH=rsh} $remotehost works.
#    3. The path to $TESTDIR is the same on both machines (symlinks are okay)
#    4. The path to $testcvs is the same on both machines (symlinks are okay)
#       or $CVS_SERVER is overridden in this script's environment to point to
#       a working CVS exectuable on the remote machine.
#
# Testing :pserver: would be hard (inetd issues).  (How about using tcpserver
# and some high port number?  DRP)

if $linkroot; then
    mkdir ${TESTDIR}/realcvsroot
    ln -s realcvsroot ${TESTDIR}/cvsroot
fi
CVSROOT_DIRNAME=${TESTDIR}/cvsroot
CVSROOT=`newroot $CVSROOT_DIRNAME`; export CVSROOT



###
### Initialize the repository
###
dotest init-1 "$testcvs init"

# Now hide the primary root behind a secondary if requested.
if $proxy; then
    # Save the primary root.
    PRIMARY_CVSROOT=$CVSROOT
    PRIMARY_CVSROOT_DIRNAME=$CVSROOT_DIRNAME
    # Where the secondary root will be
    SECONDARY_CVSROOT_DIRNAME=$TESTDIR/secondary_cvsroot
    if $noredirect; then
	rootoptions=";Redirect=no"
	SECONDARY_CVSROOT=`newroot $PRIMARY_CVSROOT_DIRNAME`
    else
	SECONDARY_CVSROOT=`newroot $SECONDARY_CVSROOT_DIRNAME`
    fi
    # Now set the global CVSROOT to use the secondary.
    CVSROOT=$SECONDARY_CVSROOT; export CVSROOT

    require_rsync
    if test $? -eq 77; then
	echo "Unable to test in proxy mode: $skipreason" >&2
	skip all "missing or broken rsync command."
	exit 0
    fi

    if $noredirect; then
	# Wrap the CVS server to allow --primary-root to be set by the
	# secondary.
	cat <<EOF >$TESTDIR/secondary-wrapper
#! $TESTSHELL
CVS_SERVER=$TESTDIR/primary-wrapper
export CVS_SERVER

# No need to check the PID of the last client since we are testing with
# Redirect disabled.
proot_arg="--allow-root=$SECONDARY_CVSROOT_DIRNAME"
exec $CVS_SERVER \$proot_arg "\$@"
EOF
	cat <<EOF >$TESTDIR/primary-wrapper
#! $TESTSHELL
if test -n "$CVS_SERVER_LOG"; then
  CVS_SERVER_LOG=`dirname "$CVS_SERVER_LOG"`/cvsprimarylog
  export CVS_SERVER_LOG
fi
exec $CVS_SERVER "\$@"
EOF

	CVS_SERVER_secondary=$TESTDIR/secondary-wrapper
	CVS_SERVER=$CVS_SERVER_secondary

	chmod a+x $TESTDIR/secondary-wrapper \
	          $TESTDIR/primary-wrapper
    fi

    # Script to sync the secondary root.
    cat >$TESTDIR/sync-secondary <<EOF
#! $TESTSHELL
# date >>$TESTDIR/update-log

ps=\$1
cmd=\$2
dir=\$3
shift
shift
shift

# echo "updating from \$ps for command \\\`\$cmd' in dir \\\`\$dir'" \${1+"\$@"} \\
#      >>$TESTDIR/update-log

# If multiple CVS executables could attempt to access the repository, we would
# Need to lock for this sync and sleep
case "\$dir" in
  ALL)
    # This is a hack to allow a few of the tests to play with the
    # UseNewInfoFmtStrings key in CVSROOT/config.  It's inefficient, but there
    # aren't many tests than need it and the alternative is an awful lot of
    # special casing.
    $RSYNC -rglop --delete --exclude '#cvs.*' \\
           $PRIMARY_CVSROOT_DIRNAME/ \\
           $SECONDARY_CVSROOT_DIRNAME
    ;;

  *)
    # For the majority of the tests we will only sync the directories that
    # were written to.
    case "\$cmd" in
      add|import)
	# For \`add', we need a recursive update due to quirks in rsync syntax,
	# but it shouldn't affect efficiency since any new dir should be empty.
	#
	# For \`import', a recursive update is necessary since subdirs may have
	# been added underneath the root dir we were passed. 
        $RSYNC -rglop \\
	       $PRIMARY_CVSROOT_DIRNAME/"\$dir" \\
	       $SECONDARY_CVSROOT_DIRNAME/\`dirname -- "\$dir"\`
        ;;

      tag)
	# \`tag' may have changed CVSROOT/val-tags too.
        $RSYNC -glop \\
               $PRIMARY_CVSROOT_DIRNAME/CVSROOT/val-tags \\
               $SECONDARY_CVSROOT_DIRNAME/CVSROOT
	# Otherwise it is identical to other write commands.
        $RSYNC -rglop --delete \\
               --include Attic --include CVS \
               --exclude '#cvs.*' --exclude '*/' \\
               $PRIMARY_CVSROOT_DIRNAME/"\$dir"/ \\
               $SECONDARY_CVSROOT_DIRNAME/"\$dir"
        ;;

      *)
	# By default, sync just what changed.
        $RSYNC -rglop --delete \\
               --include Attic --include CVS \
               --exclude '#cvs.*' --exclude '*/' \\
               $PRIMARY_CVSROOT_DIRNAME/"\$dir"/ \\
               $SECONDARY_CVSROOT_DIRNAME/"\$dir"
        ;;
    esac # \$cmd

    # And keep the history file up to date for all commands.
    $RSYNC -glop \\
           $PRIMARY_CVSROOT_DIRNAME/CVSROOT/history \\
           $SECONDARY_CVSROOT_DIRNAME/CVSROOT
    ;; # \$dir = *
esac # \$dir

# Avoid timestamp comparison issues with rsync.
sleep 1
EOF
    chmod a+x $TESTDIR/sync-secondary

    # And now init the secondary.
    $TESTDIR/sync-secondary "- no, before - create secondary root" \
                            sanity-setup ALL

    # Initialize the primary repository
    mkdir proxy-init; cd proxy-init
    dotest proxy-init-1 "$testcvs -Qd$PRIMARY_CVSROOT co CVSROOT"
    cd CVSROOT
    cat >>config <<EOF
PrimaryServer=$PRIMARY_CVSROOT
EOF
    cat >>loginfo <<EOF
ALL $TESTDIR/sync-secondary loginfo %c %p %{sVv}
EOF
    cat >>postadmin <<EOF
ALL $TESTDIR/sync-secondary postadmin %c %p
EOF
    cat >>posttag <<EOF
ALL $TESTDIR/sync-secondary posttag %c %p %o %b %t %{sVv}
EOF
    cat >>postwatch <<EOF
ALL $TESTDIR/sync-secondary postwatch %c %p
EOF
    dotest proxy-init-2 \
"$testcvs -Q ci -mconfigure-writeproxy"

    # Save these files for later reference
    cp config $TESTDIR/config-clean
    cp loginfo $TESTDIR/loginfo-clean
    cp postadmin $TESTDIR/postadmin-clean
    cp posttag $TESTDIR/posttag-clean
    cp postwatch $TESTDIR/postwatch-clean

    # done in here
    cd ../..
    rm -rf proxy-init
else # !$proxy
    # Set this even when not testing $proxy to match messages, like $SPROG.
    SECONDARY_CVSROOT_DIRNAME=$CVSROOT_DIRNAME
fi # $proxy

# Save a copy of the initial repository so that it may be restored after the
# tests that alter it.
cp -Rp $CVSROOT_DIRNAME/CVSROOT $TESTDIR/CVSROOT.save


###
### The tests
###
dotest init-2 "$testcvs init"



###
### The big loop
###
for what in $tests; do
	if test -n "$fromtest" ; then
	    if test $fromtest = $what ; then
		unset fromtest
	    else
		continue
	    fi
	fi
	case $what in

	version)
	  # We've had cases where the version command started dumping core,
	  # so we might as well test it
	  dotest version-1 "${testcvs} --version" \
'
Concurrent Versions System (CVS) [0-9.]*.*

Copyright (C) [0-9]* Free Software Foundation, Inc.

Senior active maintainers include Larry Jones, Derek R. Price,
and Mark D. Baushke.  Please see the AUTHORS and README files from the CVS
distribution kit for a complete list of contributors and copyrights.

CVS may be copied only under the terms of the GNU General Public License,
a copy of which can be found with the CVS distribution kit.

Specify the --help option for further information about CVS'

# Maybe someday...
#	  if $proxy; then
#		dotest version-2r "${testcvs} version" \
#'Client: Concurrent Versions System (CVS) [0-9p.]* (client.*)
#Server: Concurrent Versions System (CVS) [0-9p.]* (.*server)
#Secondary Server: Concurrent Versions System (CVS) [0-9p.]* (.*server)'
	  if $remote; then
		dotest version-2r "${testcvs} version" \
'Client: Concurrent Versions System (CVS) [0-9p.]* (client.*)
Server: Concurrent Versions System (CVS) [0-9p.]* (.*server)'
	  else
		dotest version-2 "${testcvs} version" \
'Concurrent Versions System (CVS) [0-9.]*.*'
	  fi
	  ;;



	basica)
	  # Similar in spirit to some of the basic1, and basic2
	  # tests, but hopefully a lot faster.  Also tests operating on
	  # files two directories down *without* operating on the parent dirs.

	  # Tests basica-0a and basica-0b provide the equivalent of the:
	  #    mkdir ${CVSROOT_DIRNAME}/first-dir
	  # used by many of the tests.  It is "more official" in the sense
	  # that is does everything through CVS; the reason most of the
	  # tests don't use it is mostly historical.
	  mkdir 1; cd 1
	  dotest basica-0a "$testcvs -q co -l ."
	  mkdir first-dir
	  dotest basica-0b "$testcvs add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
	  cd ..
	  rm -r 1

	  dotest basica-1 "$testcvs -q co first-dir" ''
	  cd first-dir

	  # Test a few operations, to ensure they gracefully do
	  # nothing in an empty directory.
	  dotest basica-1a0 "$testcvs -q update"
	  dotest basica-1a1 "$testcvs -q diff -c"
	  dotest basica-1a2 "$testcvs -q status"
	  dotest basica-1a3 "$testcvs -q update ."
	  dotest basica-1a4 "$testcvs -q update ./"

	  mkdir sdir
	  # Remote CVS gives the "cannot open CVS/Entries" error, which is
	  # clearly a bug, but not a simple one to fix.
	  dotest basica-1a10 "$testcvs -n add sdir" \
"Directory $CVSROOT_DIRNAME/first-dir/sdir added to the repository" \
"$SPROG add: cannot open CVS/Entries for reading: No such file or directory
Directory $CVSROOT_DIRNAME/first-dir/sdir added to the repository"
	  dotest_fail basica-1a11 \
	    "test -d $CVSROOT_DIRNAME/first-dir/sdir"
	  dotest basica-2 "$testcvs add sdir" \
"Directory $CVSROOT_DIRNAME/first-dir/sdir added to the repository"
	  cd sdir
	  mkdir ssdir
	  dotest basica-3 "$testcvs add ssdir" \
"Directory $CVSROOT_DIRNAME/first-dir/sdir/ssdir added to the repository"
	  cd ssdir
	  echo ssfile >ssfile

	  # Trying to commit it without a "cvs add" should be an error.
	  # The "use `cvs add' to create an entry" message is the one
	  # that I consider to be more correct, but local cvs prints the
	  # "nothing known" message and noone has gotten around to fixing it.
	  dotest_fail basica-notadded "${testcvs} -q ci ssfile" \
"${CPROG} commit: use .${CPROG} add. to create an entry for \`ssfile'
${CPROG}"' \[commit aborted\]: correct above errors first!' \
"${CPROG}"' commit: nothing known about `ssfile'\''
'"${CPROG}"' \[commit aborted\]: correct above errors first!'

	  dotest basica-4 "${testcvs} add ssfile" \
"${SPROG}"' add: scheduling file `ssfile'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
	  dotest_fail basica-4a "${testcvs} tag tag0 ssfile" \
"${SPROG} tag: nothing known about ssfile
${SPROG} "'\[tag aborted\]: correct the above errors first!'
	  cd ../..
	  dotest basica-5 "${testcvs} -q ci -m add-it" \
"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v  <--  sdir/ssdir/ssfile
initial revision: 1\.1"
	  dotest_fail basica-5a \
	    "${testcvs} -q tag BASE sdir/ssdir/ssfile" \
"${SPROG} tag: Attempt to add reserved tag name BASE
${SPROG} \[tag aborted\]: failed to set tag BASE to revision 1\.1 in ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v"
	  dotest basica-5b "${testcvs} -q tag NOT_RESERVED" \
'T sdir/ssdir/ssfile'

	  dotest basica-6 "${testcvs} -q update" ''
	  echo "ssfile line 2" >>sdir/ssdir/ssfile
	  dotest_fail basica-6.2 "${testcvs} -q diff -c" \
"Index: sdir/ssdir/ssfile
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
retrieving revision 1\.1
diff -c -r1\.1 ssfile
\*\*\* sdir/ssdir/ssfile	${RFCDATE}	1\.1
--- sdir/ssdir/ssfile	${RFCDATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
--- 1,2 ----
  ssfile
${PLUS} ssfile line 2"
	  dotest_fail basica-6.3 "${testcvs} -q diff -c -rBASE" \
"Index: sdir/ssdir/ssfile
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
retrieving revision 1\.1
diff -c -r1\.1 ssfile
\*\*\* sdir/ssdir/ssfile	${RFCDATE}	1\.1
--- sdir/ssdir/ssfile	${RFCDATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
--- 1,2 ----
  ssfile
${PLUS} ssfile line 2"
	  dotest_fail basica-6.4 "${testcvs} -q diff -c -rBASE -C3isacrowd" \
"Index: sdir/ssdir/ssfile
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
retrieving revision 1\.1
diff -c -C 3isacrowd -r1\.1 ssfile
${SPROG} diff: invalid context length argument"
	  dotest basica-7 "${testcvs} -q ci -m modify-it" \
"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v  <--  sdir/ssdir/ssfile
new revision: 1\.2; previous revision: 1\.1"
	  dotest_fail basica-nonexist "${testcvs} -q ci nonexist" \
"${CPROG}"' commit: nothing known about `nonexist'\''
'"${CPROG}"' \[commit aborted\]: correct above errors first!'
	  dotest basica-8 "${testcvs} -q update ." ''

	  # Test the -f option to ci
	  cd sdir/ssdir
	  dotest basica-8a0 "${testcvs} -q ci -m not-modified ssfile" ''
	  dotest basica-8a "${testcvs} -q ci -f -m force-it" \
"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v  <--  ssfile
new revision: 1\.3; previous revision: 1\.2"
	  dotest basica-8a1 "${testcvs} -q ci -m bump-it -r 2.0" \
"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v  <--  ssfile
new revision: 2\.0; previous revision: 1\.3"
	  dotest basica-8a1a "${testcvs} -q ci -m bump-it -r 2.9" \
"${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v  <--  ssfile
new revision: 2\.9; previous revision: 2\.0"
	  # Test string-based revion number increment rollover
	  dotest basica-8a1b "${testcvs} -q ci -m bump-it -f -r 2" \
"${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v  <--  ssfile
new revision: 2\.10; previous revision: 2\.9"
	  dotest basica-8a1c "${testcvs} -q ci -m bump-it -r 2.99" \
"${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v  <--  ssfile
new revision: 2\.99; previous revision: 2\.10"
	  # Test string-based revion number increment rollover
	  dotest basica-8a1d "${testcvs} -q ci -m bump-it -f -r 2" \
"${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v  <--  ssfile
new revision: 2\.100; previous revision: 2\.99"
	  dotest basica-8a1e "${testcvs} -q ci -m bump-it -r 2.1099" \
"${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v  <--  ssfile
new revision: 2\.1099; previous revision: 2\.100"
	  # Test string-based revion number increment rollover
	  dotest basica-8a1f "${testcvs} -q ci -m bump-it -f -r 2" \
"${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v  <--  ssfile
new revision: 2\.1100; previous revision: 2\.1099"
	  # -f should not be necessary, but it should be harmless.
	  # Also test the "-r 3" (rather than "-r 3.0") usage.
	  dotest basica-8a2 "${testcvs} -q ci -m bump-it -f -r 3" \
"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v  <--  ssfile
new revision: 3\.1; previous revision: 2\.1100"

	  # Test using -r to create a branch
	  dotest_fail basica-8a3 "${testcvs} -q ci -m bogus -r 3.0.0" \
"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v  <--  ssfile
$SPROG commit: $CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v: can't find branch point 3\.0
$SPROG commit: could not check in ssfile"
	  dotest basica-8a4 "${testcvs} -q ci -m valid -r 3.1.2" \
"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v  <--  ssfile
new revision: 3\.1\.2\.1; previous revision: 3\.1"
	  # now get rid of the sticky tag and go back to the trunk
	  dotest basica-8a5 "${testcvs} -q up -A ./" "[UP] ssfile"

	  cd ../..
	  dotest basica-8b "${testcvs} -q diff -r1.2 -r1.3"

	  dotest basica-8b1 "${testcvs} -q diff -r1.2 -r1.3 -C 3isacrowd"

	  # The .* here will normally be "No such file or directory",
	  # but if memory serves some systems (AIX?) have a different message.
:	  dotest_fail basica-9 \
	    "${testcvs} -q -d ${TESTDIR}/nonexist update" \
"${SPROG}: cannot access cvs root ${TESTDIR}/nonexist: .*"
	  dotest_fail basica-9a \
	    "${testcvs} -q -d ${TESTDIR}/nonexist update" \
"${CPROG} \[update aborted\]: ${TESTDIR}/nonexist/CVSROOT: .*"

	  dotest basica-10 "${testcvs} annotate" \
'
Annotations for sdir/ssdir/ssfile
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
1\.1          .'"$username8"' *[0-9a-zA-Z-]*.: ssfile
1\.2          .'"$username8"' *[0-9a-zA-Z-]*.: ssfile line 2'

	  # Test resurrecting with strange revision numbers
	  cd sdir/ssdir
	  dotest basica-r1 "${testcvs} rm -f ssfile" \
"${SPROG} remove: scheduling .ssfile. for removal
${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
	  dotest basica-r2 "${testcvs} -q ci -m remove" \
"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v  <--  ssfile
new revision: delete; previous revision: 3\.1"
	  dotest basica-r3 "${testcvs} -q up -p -r 3.1 ./ssfile >ssfile" ""
	  dotest basica-r4 "${testcvs} add ssfile" \
"${SPROG} add: Re-adding file .ssfile. after dead revision 3\.2\.
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest basica-r5 "${testcvs} -q ci -m resurrect" \
"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v  <--  ssfile
new revision: 3\.3; previous revision: 3\.2"
	  cd ../..

	  # As long as we have a file with a few revisions, test
	  # a few "cvs admin -o" invocations.
	  cd sdir/ssdir
	  dotest_fail basica-o1 "${testcvs} admin -o 1.2::1.2" \
"${CPROG} admin: while processing more than one file:
${CPROG} \[admin aborted\]: attempt to specify a numeric revision"
	  dotest basica-o2 "${testcvs} admin -o 1.2::1.2 ssfile" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
done"
	  dotest basica-o2a "${testcvs} admin -o 1.1::NOT_RESERVED ssfile" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
done"
	  dotest_fail basica-o2b "${testcvs} admin -o 1.1::NOT_EXIST ssfile" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
${SPROG} admin: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v: Revision NOT_EXIST doesn't exist.
${SPROG} admin: RCS file for .ssfile. not modified\."
	  dotest basica-o3 "${testcvs} admin -o 1.2::1.3 ssfile" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
done"
	  dotest basica-o4 "${testcvs} admin -o 3.1:: ssfile" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
deleting revision 3\.3
deleting revision 3\.2
done"
	  dotest basica-o5 "${testcvs} admin -o ::1.1 ssfile" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
done"
	  dotest basica-o5a "${testcvs} -n admin -o 1.2::3.1 ssfile" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
deleting revision 2\.1100
deleting revision 2\.1099
deleting revision 2\.100
deleting revision 2\.99
deleting revision 2\.10
deleting revision 2\.9
deleting revision 2\.0
deleting revision 1\.3
done"
	  dotest basica-o6 "${testcvs} admin -o 1.2::3.1 ssfile" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
deleting revision 2\.1100
deleting revision 2\.1099
deleting revision 2\.100
deleting revision 2\.99
deleting revision 2\.10
deleting revision 2\.9
deleting revision 2\.0
deleting revision 1\.3
done"
	  dotest basica-o6a "${testcvs} admin -o 3.1.2: ssfile" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
deleting revision 3\.1\.2\.1
done"
	  dotest basica-o7 "${testcvs} log -N ssfile" "
RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
Working file: ssfile
head: 3\.1
branch:
locks: strict
access list:
keyword substitution: kv
total revisions: 3;	selected revisions: 3
description:
----------------------------
revision 3\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0;  commitid: ${commitid};
bump-it
----------------------------
revision 1\.2
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  commitid: ${commitid};
modify-it
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
add-it
============================================================================="
	  dotest basica-o8 "${testcvs} -q update -p -r 1.1 ./ssfile" "ssfile"
	  cd ../..

	  cd ..

	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  rm -r first-dir
	  ;;



	basicb)
	  # More basic tests, including non-branch tags and co -d.
	  mkdir 1; cd 1
	  dotest basicb-0a "${testcvs} -q co -l ." ''
	  touch topfile
	  dotest basicb-0b "${testcvs} add topfile" \
"${SPROG} add: scheduling file .topfile. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest basicb-0c "${testcvs} -q ci -m add-it topfile" \
"$CVSROOT_DIRNAME/topfile,v  <--  topfile
initial revision: 1\.1"
	  cd ..
	  rm -r 1
	  mkdir 2; cd 2
	  dotest basicb-0d "${testcvs} -q co -l ." "U topfile"
	  # Now test the ability to run checkout on an existing working
	  # directory without having it lose its mind.  I don't know
	  # whether this is tested elsewhere in sanity.sh.  A more elaborate
	  # test might also have modified files, make sure it works if
	  # the modules file was modified to add new directories to the
	  # module, and such.
	  dotest basicb-0d0 "${testcvs} -q co -l ." ""
	  mkdir first-dir
	  dotest basicb-0e "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
	  cd ..
	  rm -r 2

	  dotest basicb-1 "${testcvs} -q co first-dir" ''

	  # The top-level CVS directory is not created by default.
	  # I'm leaving basicb-1a and basicb-1b untouched, mostly, in
	  # case we decide that the default should be reversed...

	  dotest_fail basicb-1a "test -d CVS" ''

	  dotest basicb-1c "cat first-dir/CVS/Repository" "first-dir"

	  cd first-dir
	  # Note that the name Emptydir is chosen to test that CVS just
	  # treats it like any other directory name.  It should be
	  # special only when it is directly in $CVSROOT/CVSROOT.
	  mkdir Emptydir sdir2
	  dotest basicb-2 "${testcvs} add Emptydir sdir2" \
"Directory ${CVSROOT_DIRNAME}/first-dir/Emptydir added to the repository
Directory ${CVSROOT_DIRNAME}/first-dir/sdir2 added to the repository"
	  cd Emptydir
	  echo sfile1 starts >sfile1
	  dotest basicb-2a10 "${testcvs} -n add sfile1" \
"${SPROG} add: scheduling file .sfile1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest basicb-2a11 "${testcvs} status sfile1" \
"${SPROG} status: use \`${SPROG} add' to create an entry for \`sfile1'
===================================================================
File: sfile1           	Status: Unknown

   Working revision:	No entry for sfile1
   Repository revision:	No revision control file"
	  dotest basicb-3 "${testcvs} add sfile1" \
"${SPROG} add: scheduling file .sfile1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest basicb-3a1 "${testcvs} status sfile1" \
"===================================================================
File: sfile1           	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"

	  cd ../sdir2
	  echo sfile2 starts >sfile2
	  dotest basicb-4 "${testcvs} add sfile2" \
"${SPROG} add: scheduling file .sfile2. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest basicb-4a "${testcvs} -q ci CVS" \
"${CPROG} commit: warning: directory CVS specified in argument
${CPROG} commit: but CVS uses CVS for its own purposes; skipping CVS directory"
	  cd ..
	  dotest basicb-5 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/Emptydir/sfile1,v  <--  Emptydir/sfile1
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/sdir2/sfile2,v  <--  sdir2/sfile2
initial revision: 1\.1"
	  echo sfile1 develops >Emptydir/sfile1
	  dotest basicb-6 "${testcvs} -q ci -m modify" \
"$CVSROOT_DIRNAME/first-dir/Emptydir/sfile1,v  <--  Emptydir/sfile1
new revision: 1\.2; previous revision: 1\.1"
	  dotest basicb-7 "${testcvs} -q tag release-1" 'T Emptydir/sfile1
T sdir2/sfile2'
	  echo not in time for release-1 >sdir2/sfile2
	  dotest basicb-8 "${testcvs} -q ci -m modify-2" \
"$CVSROOT_DIRNAME/first-dir/sdir2/sfile2,v  <--  sdir2/sfile2
new revision: 1\.2; previous revision: 1\.1"
	  # See if CVS can correctly notice when an invalid numeric
	  # revision is specified.
	  # Commented out until we get around to fixing CVS
:	  dotest basicb-8a0 "${testcvs} diff -r 1.5 -r 1.7 sfile2" 'error msg'
	  cd ..

	  # Test that we recurse into the correct directory when checking
	  # for existing files, even if co -d is in use.
	  touch first-dir/extra
	  dotest basicb-cod-1 "${testcvs} -q co -d first-dir1 first-dir" \
'U first-dir1/Emptydir/sfile1
U first-dir1/sdir2/sfile2'
	  rm -r first-dir1

	  rm -r first-dir

	  # FIXME? basicb-9 used to check things out like this:
	  #   U newdir/Emptydir/sfile1
	  #   U newdir/sdir2/sfile2
	  # but that's difficult to do.  The whole "shorten" thing
	  # is pretty bogus, because it will break on things
	  # like "cvs co foo/bar baz/quux".  Unless there's some
	  # pretty detailed expansion and analysis of the command-line
	  # arguments, we shouldn't do "shorten" stuff at all.

	  dotest basicb-9 \
"${testcvs} -q co -d newdir -r release-1 first-dir/Emptydir first-dir/sdir2" \
'U newdir/first-dir/Emptydir/sfile1
U newdir/first-dir/sdir2/sfile2'

	  # basicb-9a and basicb-9b: see note about basicb-1a

	  dotest_fail basicb-9a "test -d CVS" ''

	  dotest basicb-9c "cat newdir/CVS/Repository" "\."
	  dotest basicb-9d "cat newdir/first-dir/CVS/Repository" \
"${CVSROOT_DIRNAME}/first-dir" \
"first-dir"
	  dotest basicb-9e "cat newdir/first-dir/Emptydir/CVS/Repository" \
"${CVSROOT_DIRNAME}/first-dir/Emptydir" \
"first-dir/Emptydir"
	  dotest basicb-9f "cat newdir/first-dir/sdir2/CVS/Repository" \
"${CVSROOT_DIRNAME}/first-dir/sdir2" \
"first-dir/sdir2"

	  dotest basicb-10 "cat newdir/first-dir/Emptydir/sfile1 newdir/first-dir/sdir2/sfile2" \
"sfile1 develops
sfile2 starts"

	  rm -r newdir

	  # Hmm, this might be a case for CVSNULLREPOS, but CVS doesn't
	  # seem to deal with it...
	  if false; then
	  dotest basicb-11 "${testcvs} -q co -d sub1/sub2 first-dir" \
"U sub1/sub2/Emptydir/sfile1
U sub1/sub2/sdir2/sfile2"
	  cd sub1
	  dotest basicb-12 "${testcvs} -q update ./." ''
	  touch xx
	  dotest basicb-13 "${testcvs} add xx" fixme
	  cd ..
	  rm -r sub1
	  # to test: sub1/sub2/sub3
	  fi # end of tests commented out.

	  # Create a second directory.
	  mkdir 1
	  cd 1
	  dotest basicb-14 "${testcvs} -q co -l ." 'U topfile'
	  mkdir second-dir
	  dotest basicb-15 "${testcvs} add second-dir" \
"Directory ${CVSROOT_DIRNAME}/second-dir added to the repository"
	  cd second-dir
	  touch aa
	  dotest basicb-16 "${testcvs} add aa" \
"${SPROG} add: scheduling file .aa. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest basicb-17 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/second-dir/aa,v  <--  aa
initial revision: 1\.1"
	  cd ..

	  # Try to remove all revisions in a file.
	  dotest_fail basicb-o1 "${testcvs} admin -o1.1 topfile" \
"RCS file: ${CVSROOT_DIRNAME}/topfile,v
deleting revision 1\.1
${SPROG} \[admin aborted\]: attempt to delete all revisions"
	  dotest basicb-o2 "${testcvs} -q update -d first-dir" \
"U first-dir/Emptydir/sfile1
U first-dir/sdir2/sfile2"
	  dotest_fail basicb-o3 \
"${testcvs} admin -o1.1:1.2 first-dir/sdir2/sfile2" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir2/sfile2,v
deleting revision 1\.2
deleting revision 1\.1
${SPROG} \[admin aborted\]: attempt to delete all revisions"
	  cd ..
	  rm -r 1

	  mkdir 1; cd 1
	  # Note that -H is an invalid option.
	  # I suspect that the choice between "illegal" and "invalid"
	  # depends on the user's environment variables, the phase
	  # of the moon (weirdness with optind), and who knows what else.
	  # I've been seeing "illegal"...
	  # And I switched it to "invalid". -DRP
	  # POSIX 1003.2 specifies the format should be 'illegal option'
	  # many other folks are still using the older 'invalid option'
	  # lib/getopt.c will use POSIX when __posixly_correct
	  # otherwise the other, so accept both of them. -- mdb
	  dotest_fail basicb-21 "${testcvs} -q admin -H" \
"admin: invalid option -- H
${CPROG} \[admin aborted\]: specify ${CPROG} -H admin for usage information" \
"admin: illegal option -- H
${CPROG} \[admin aborted\]: specify ${CPROG} -H admin for usage information"
	  cd ..
	  rmdir 1

	  if $keep; then
	    echo Keeping ${TESTDIR} and exiting due to --keep
	    exit 0
	  fi

	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
			     $CVSROOT_DIRNAME/second-dir
	  modify_repo rm -f $CVSROOT_DIRNAME/topfile,v
	  ;;



	basicc)
	  # More tests of basic/miscellaneous functionality.
	  mkdir 1; cd 1
	  dotest_fail basicc-1 "$testcvs diff" \
"$CPROG diff: in directory \.:
$CPROG \[diff aborted\]: there is no version here; run .$CPROG checkout. first"
	  dotest basicc-2 "$testcvs -q co -l ."
	  mkdir first-dir second-dir
	  dotest basicc-3 "${testcvs} add first-dir second-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository
Directory ${CVSROOT_DIRNAME}/second-dir added to the repository"
	  # Old versions of CVS often didn't create this top-level CVS
	  # directory in the first place.  I think that maybe the only
	  # way to get it to work currently is to let CVS create it,
	  # and then blow it away (don't complain if it does not
	  # exist).  But that is perfectly valid; people who are used
	  # to the old behavior especially may be interested.
	  # FIXME: this test is intended for the TopLevelAdmin=yes case;
	  # should adjust/move it accordingly.
	  rm -rf CVS
	  dotest basicc-4 "echo *" "first-dir second-dir"
	  dotest basicc-5 "${testcvs} update" \
"${SPROG} update: Updating first-dir
${SPROG} update: Updating second-dir" \
"${SPROG} update: Updating \.
${SPROG} update: Updating first-dir
${SPROG} update: Updating second-dir"

	  cd first-dir
	  dotest basicc-6 "${testcvs} release -d" ""
	  dotest basicc-7 "test -d ../first-dir" ""
	  # The Linux 2.2 kernel lets you delete ".".  That's OK either way,
	  # the point is that CVS must not mess with anything *outside* "."
	  # the way that CVS 1.10 and older tried to.
	  dotest basicc-8 "${testcvs} -Q release -d ." \
"" "${CPROG} release: deletion of directory \. failed: .*"
	  dotest basicc-9 "test -d ../second-dir" ""
	  # For CVS to make a syntactic check for "." wouldn't suffice.
	  # On Linux 2.2 systems, the cwd may be gone, so we recreate it
          # to allow basicc-11 to actually happen 
	  if test ! -d ../first-dir; then
	    # Apparently `cd ..' doesn't work with Linux 2.2 & Bash 2.05b.
	    cd $TESTDIR/1
	    mkdir ./first-dir
            cd ./first-dir
	  fi
	  dotest basicc-11 "${testcvs} -Q release -d ./." \
"" "${CPROG} release: deletion of directory \./\. failed: .*"
	  dotest basicc-11a "test -d ../second-dir" ""

	  cd ../..

	  mkdir 2; cd 2
	  dotest basicc-12 "${testcvs} -Q co ." ""
	  # actual entries can be in either Entries or Entries.log, do
	  # an update to get them consolidated into Entries
	  dotest basicc-12a "${testcvs} -Q up" ""
	  dotest basicc-12b "cat CVS/Entries" \
"D/CVSROOT////
D/first-dir////
D/second-dir////"
	  dotest basicc-13 "echo *" "CVS CVSROOT first-dir second-dir"
	  dotest basicc-14 "${testcvs} -Q release first-dir second-dir" ""
	  # a normal release shouldn't affect the Entries file
	  dotest basicc-14b "cat CVS/Entries" \
"D/CVSROOT////
D/first-dir////
D/second-dir////"
	  # FIXCVS: but release -d probably should
	  dotest basicc-15 "${testcvs} -Q release -d first-dir second-dir" ""
	  dotest basicc-16 "echo *" "CVS CVSROOT"
	  dotest basicc-17 "cat CVS/Entries" \
"D/CVSROOT////
D/first-dir////
D/second-dir////"
	  # FIXCVS: if not, update should notice the missing directories
	  # and update Entries accordingly
	  dotest basicc-18 "${testcvs} -Q up" ""
	  dotest basicc-19 "cat CVS/Entries" \
"D/CVSROOT////
D/first-dir////
D/second-dir////"

	  cd ..
	  rm -r 1 2
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
			     $CVSROOT_DIRNAME/second-dir
	  ;;



	basic1)
	  # first dive - add a files, first singly, then in a group.
	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  mkdir basic1; cd basic1
	  # check out an empty directory
	  dotest basic1-1 "${testcvs} -q co first-dir" ''

	  cd first-dir
	  echo file2 >file2
	  echo file3 >file3
	  echo file4 >file4
	  echo file5 >file5

	  dotest basic1-14-add-add "${testcvs} add file2 file3 file4 file5" \
"${SPROG} add: scheduling file \`file2' for addition
${SPROG} add: scheduling file \`file3' for addition
${SPROG} add: scheduling file \`file4' for addition
${SPROG} add: scheduling file \`file5' for addition
${SPROG} add: use .${SPROG} commit. to add these files permanently"
	  dotest basic1-15-add-add \
"${testcvs} -q update file2 file3 file4 file5" \
"A file2
A file3
A file4
A file5"
	  dotest basic1-16-add-add "${testcvs} -q update" \
"A file2
A file3
A file4
A file5"
	  dotest basic1-17-add-add "${testcvs} -q status" \
"===================================================================
File: file2            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file3            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file4            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file5            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
	  dotest basic1-18-add-add "${testcvs} -q log" \
"${SPROG} log: file2 has been added, but not committed
${SPROG} log: file3 has been added, but not committed
${SPROG} log: file4 has been added, but not committed
${SPROG} log: file5 has been added, but not committed"
	  cd ..
	  dotest basic1-21-add-add "${testcvs} -q update" \
"A first-dir/file2
A first-dir/file3
A first-dir/file4
A first-dir/file5"
	  # FIXCVS?  Shouldn't this read first-dir/file2 instead of file2?
	  dotest basic1-22-add-add "${testcvs} log first-dir" \
"${SPROG} log: Logging first-dir
${SPROG} log: file2 has been added, but not committed
${SPROG} log: file3 has been added, but not committed
${SPROG} log: file4 has been added, but not committed
${SPROG} log: file5 has been added, but not committed"
	  dotest basic1-23-add-add "${testcvs} status first-dir" \
"${SPROG} status: Examining first-dir
===================================================================
File: file2            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file3            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file4            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file5            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
	  dotest basic1-24-add-add "${testcvs} update first-dir" \
"${SPROG} update: Updating first-dir
A first-dir/file2
A first-dir/file3
A first-dir/file4
A first-dir/file5"
	  dotest basic1-27-add-add "${testcvs} co first-dir" \
"${SPROG} checkout: Updating first-dir
A first-dir/file2
A first-dir/file3
A first-dir/file4
A first-dir/file5"
	  cd first-dir
	  dotest basic1-14-add-ci \
"$testcvs commit -m test file2 file3 file4 file5" \
"$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file3,v  <--  file3
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file5,v  <--  file5
initial revision: 1\.1"
	  dotest basic1-15-add-ci \
"${testcvs} -q update file2 file3 file4 file5" ''
	  dotest basic1-16-add-ci "${testcvs} -q update" ''
	  dotest basic1-17-add-ci "${testcvs} -q status" \
"===================================================================
File: file2            	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file2,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file3            	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file3,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file4            	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file4,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file5            	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file5,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
	  # The "log" tests and friends probably already test the output 
	  # from log quite adequately.
	  # Note: using dotest fails here.  It seems to be related
	  # to the output being sufficiently large (Red Hat 4.1).
	  # dotest basic1-18-add-ci "${testcvs} log" "${DOTSTAR}"
	  if ${testcvs} -q log >>${LOGFILE}; then
	    pass basic1-18-add-ci
	  else
	    pass basic1-18-add-ci
	  fi
	  cd ..
	  dotest basic1-21-add-ci "${testcvs} -q update" ''
	  # See test basic1-18-add-ci for explanation of non-use of dotest.
	  if ${testcvs} -q log first-dir >>${LOGFILE}; then
	    pass basic1-22-add-ci
	  else
	    pass basic1-22-add-ci
	  fi
	  # At least for the moment I am going to consider 17-add-ci
	  # an adequate test of the output here.
	  # See test basic1-18-add-ci for explanation of non-use of dotest.
	  if ${testcvs} -q status first-dir >>${LOGFILE}; then
	    pass basic1-23-add-ci
	  else
	    pass basic1-23-add-ci
	  fi
	  dotest basic1-24-add-ci "${testcvs} -q update first-dir" ''
	  dotest basic1-27-add-ci "${testcvs} -q co first-dir" ''

	  cd first-dir
	  rm file2 file3 file4 file5
	  dotest basic1-14-rm-rm "${testcvs} rm file2 file3 file4 file5" \
"${SPROG} remove: scheduling .file2. for removal
${SPROG} remove: scheduling .file3. for removal
${SPROG} remove: scheduling .file4. for removal
${SPROG} remove: scheduling .file5. for removal
${SPROG} remove: use .${SPROG} commit. to remove these files permanently"
	  # 15-rm-rm was commented out.  Why?
	  dotest basic1-15-rm-rm \
"${testcvs} -q update file2 file3 file4 file5" \
"R file2
R file3
R file4
R file5"
	  dotest basic1-16-rm-rm "${testcvs} -q update" \
"R file2
R file3
R file4
R file5"
	  dotest basic1-17-rm-rm "${testcvs} -q status" \
"===================================================================
File: no file file2		Status: Locally Removed

   Working revision:	-1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file2,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: no file file3		Status: Locally Removed

   Working revision:	-1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file3,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: no file file4		Status: Locally Removed

   Working revision:	-1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file4,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: no file file5		Status: Locally Removed

   Working revision:	-1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file5,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
	  # Would be nice to test that real logs appear (with dead state
	  # and all), either here or someplace like log2 tests.
	  if ${testcvs} -q log >>${LOGFILE}; then
	    pass basic1-18-rm-rm
	  else
	    fail basic1-18-rm-rm
	  fi
	  cd ..
	  dotest basic1-21-rm-rm "${testcvs} -q update" \
"R first-dir/file2
R first-dir/file3
R first-dir/file4
R first-dir/file5"
	  if ${testcvs} -q log first-dir >>${LOGFILE}; then
	    pass basic1-22-rm-rm
	  else
	    fail basic1-22-rm-rm
	  fi
	  if ${testcvs} -q status first-dir >>${LOGFILE}; then
	    pass basic1-23-rm-rm
	  else
	    fail basic1-23-rm-rm
	  fi
	  dotest basic1-24-rm-rm "${testcvs} -q update first-dir" \
"R first-dir/file2
R first-dir/file3
R first-dir/file4
R first-dir/file5"
	  dotest basic1-27-rm-rm "${testcvs} -q co first-dir" \
"R first-dir/file2
R first-dir/file3
R first-dir/file4
R first-dir/file5"
	  cd first-dir
	  dotest basic1-14-rm-ci "${testcvs} -q commit -m test" \
"$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
new revision: delete; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file3,v  <--  file3
new revision: delete; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: delete; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file5,v  <--  file5
new revision: delete; previous revision: 1\.1"
	  dotest basic1-15-rm-ci \
"${testcvs} -q update file2 file3 file4 file5" ''
	  dotest basic1-16-rm-ci "${testcvs} -q update" ''
	  dotest basic1-17-rm-ci "${testcvs} -q status" ''
	  # Would be nice to test that real logs appear (with dead state
	  # and all), either here or someplace like log2 tests.
	  if ${testcvs} -q log >>${LOGFILE}; then
	    pass basic1-18-rm-ci
	  else
	    fail basic1-18-rm-ci
	  fi
	  cd ..
	  dotest basic1-21-rm-ci "${testcvs} -q update" ''
	  if ${testcvs} -q log first-dir >>${LOGFILE}; then
	    pass basic1-22-rm-ci
	  else
	    fail basic1-22-rm-ci
	  fi
	  if ${testcvs} -q status first-dir >>${LOGFILE}; then
	    pass basic1-23-rm-ci
	  else
	    fail basic1-23-rm-ci
	  fi
	  dotest basic1-24-rm-ci "${testcvs} -q update first-dir" ''
	  dotest basic1-27-rm-ci "${testcvs} -q co first-dir" ''
	  cd first-dir
	  # All the files are removed, so nothing gets tagged.
	  dotest basic1-28 "${testcvs} -q tag first-dive" ''
	  cd ..
	  cd ..

	  if $keep; then
	    echo Keeping ${TESTDIR} and exiting due to --keep
	    exit 0
	  fi

	  rm -r basic1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	deep)
	  # Test the ability to operate on directories nested rather deeply.
	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  dotest deep-1 "${testcvs} -q co first-dir" ''
	  cd first-dir
	  for i in dir1 dir2 dir3 dir4 dir5 dir6 dir7 dir8; do
	    mkdir $i
	    dotest deep-2-$i "${testcvs} add $i" \
"Directory ${CVSROOT_DIRNAME}/first-dir/dir1[/dir0-9]* added to the repository"
	    cd $i
	    echo file1 >file1
	    dotest deep-3-$i "${testcvs} add file1" \
"${SPROG}"' add: scheduling file `file1'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
	  done
	  cd ../../../../../../../../..
	  dotest_lit deep-4 "$testcvs -q ci -m add-them first-dir" <<HERE
$CVSROOT_DIRNAME/first-dir/dir1/file1,v  <--  first-dir/dir1/file1
initial revision: 1.1
$CVSROOT_DIRNAME/first-dir/dir1/dir2/file1,v  <--  first-dir/dir1/dir2/file1
initial revision: 1.1
$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/file1,v  <--  first-dir/dir1/dir2/dir3/file1
initial revision: 1.1
$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/file1,v  <--  first-dir/dir1/dir2/dir3/dir4/file1
initial revision: 1.1
$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/file1,v  <--  first-dir/dir1/dir2/dir3/dir4/dir5/file1
initial revision: 1.1
$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/file1,v  <--  first-dir/dir1/dir2/dir3/dir4/dir5/dir6/file1
initial revision: 1.1
$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/file1,v  <--  first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/file1
initial revision: 1.1
$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/file1,v  <--  first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/file1
initial revision: 1.1
HERE

	  cd first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8
	  rm file1
	  dotest deep-4a0 "$testcvs rm file1" \
"$SPROG remove: scheduling .file1. for removal
$SPROG remove: use .$SPROG commit. to remove this file permanently"
	  dotest deep-4a1 "$testcvs -q ci -m rm-it" \
"$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/file1,v  <--  file1
new revision: delete; previous revision: 1\.1"
	  cd ../../..
	  dotest deep-4a2 "${testcvs} -q update -P dir6/dir7" ''
	  # Should be using "test -e", but it's not portable enough -
	  # Solaris 2.5 does not have it.
	  dotest_fail deep-4a3 "test -d dir6/dir7/dir8" ''

	  # Test that if we remove the working directory, CVS does not
	  # recreate it.  (I realize that this behavior is what the
	  # users expect, but in the longer run we might want to
	  # re-think it.  The corresponding behavior for a file is that
	  # CVS *will* recreate it, and we might want to make it so
	  # that "cvs release -d" is the way to delete the directory
	  # and have it stay gone -kingdon, Oct1996).
	  rm -r dir6
	  dotest deep-4b0a "${testcvs} -q diff"
	  dotest deep-4b0b "${testcvs} -q ci"
	  dotest deep-4b1 "${testcvs} -q update"
	  dotest deep-4b2 "${testcvs} -q update -d -P" \
'U dir6/file1
U dir6/dir7/file1'

	  # Test what happens if one uses -P when there are files removed
	  # but not committed.
	  cd dir6/dir7
	  dotest deep-rm1 "${testcvs} rm -f file1" \
"${SPROG} remove: scheduling .file1. for removal
${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
	  cd ..
	  dotest deep-rm2 "${testcvs} -q update -d -P" 'R dir7/file1'
	  dotest deep-rm3 "test -d dir7" ''
	  dotest deep-rm4 "$testcvs -q ci -m rm-it" \
"$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/dir7/file1,v  <--  dir7/file1
new revision: delete; previous revision: 1\.1"
	  dotest deep-rm5 "${testcvs} -q update -d -P" ''
	  dotest_fail deep-rm6 "test -d dir7" ''

	  # Test rm -f -R.
	  cd ../..
	  dotest deep-rm7 "${testcvs} rm -f -R dir5" \
"${SPROG} remove: Removing dir5
${SPROG} remove: scheduling .dir5/file1. for removal
${SPROG} remove: Removing dir5/dir6
${SPROG} remove: scheduling .dir5/dir6/file1. for removal
${SPROG} remove: use .${SPROG} commit. to remove these files permanently"
	  dotest deep-rm8 "${testcvs} -q ci -m rm-it" \
"$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/file1,v  <--  dir5/file1
new revision: delete; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/dir1/dir2/dir3/dir4/dir5/dir6/file1,v  <--  dir5/dir6/file1
new revision: delete; previous revision: 1\.1"
	  dotest deep-rm9 "${testcvs} -q update -d -P" ''
	  dotest_fail deep-rm10 "test -d dir5"

	  cd ../../../../..

	  if echo "yes" | $testcvs release -d first-dir >>$LOGFILE 2>&1; then
	    pass deep-5
	  else
	    fail deep-5
	  fi
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	basic2)
		# Test rtag, import, history, various miscellaneous operations

		# NOTE: this section has reached the size and
		# complexity where it is getting to be a good idea to
		# add new tests to a new section rather than
		# continuing to piggyback them onto the tests here.

		# First empty the history file
		modify_repo rm -rf $CVSROOT_DIRNAME/CVSROOT/history
		modify_repo touch $CVSROOT_DIRNAME/CVSROOT/history

		modify_repo mkdir $CVSROOT_DIRNAME/first-dir
		dotest basic2-1 "$testcvs -q co first-dir"
		for i in first-dir dir1 dir2 ; do
			if test ! -d $i ; then
				mkdir $i
				dotest basic2-2-$i "${testcvs} add $i" \
"Directory ${CVSROOT_DIRNAME}/.*/$i added to the repository"
			fi

			cd $i

			for j in file6 file7; do
				echo $j > $j
			done

			dotest basic2-3-$i "${testcvs} add file6 file7" \
"${SPROG} add: scheduling file .file6. for addition
${SPROG} add: scheduling file .file7. for addition
${SPROG} add: use .${SPROG} commit. to add these files permanently"

		done
		cd ../../..
		dotest basic2-4 "${testcvs} update first-dir" \
"${SPROG} update: Updating first-dir
A first-dir/file6
A first-dir/file7
${SPROG} update: Updating first-dir/dir1
A first-dir/dir1/file6
A first-dir/dir1/file7
${SPROG} update: Updating first-dir/dir1/dir2
A first-dir/dir1/dir2/file6
A first-dir/dir1/dir2/file7"

		# fixme: doesn't work right for added files.
		dotest basic2-5 "${testcvs} log first-dir" \
"${SPROG} log: Logging first-dir
${SPROG} log: file6 has been added, but not committed
${SPROG} log: file7 has been added, but not committed
${SPROG} log: Logging first-dir/dir1
${SPROG} log: file6 has been added, but not committed
${SPROG} log: file7 has been added, but not committed
${SPROG} log: Logging first-dir/dir1/dir2
${SPROG} log: file6 has been added, but not committed
${SPROG} log: file7 has been added, but not committed"

		dotest basic2-6 "${testcvs} status first-dir" \
"${SPROG} status: Examining first-dir
===================================================================
File: file6            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file7            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

${SPROG} status: Examining first-dir/dir1
===================================================================
File: file6            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file7            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

${SPROG} status: Examining first-dir/dir1/dir2
===================================================================
File: file6            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file7            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"

# XXX why is this commented out???
#		if ${CVS} diff -u first-dir   >> ${LOGFILE} || test $? = 1 ; then
#		    pass 34
#		else
#		    fail 34
#		fi

		dotest basic2-8 "${testcvs} -q ci -m 'second dive' first-dir" \
"$CVSROOT_DIRNAME/first-dir/file6,v  <--  first-dir/file6
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file7,v  <--  first-dir/file7
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/dir1/file6,v  <--  first-dir/dir1/file6
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/dir1/file7,v  <--  first-dir/dir1/file7
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/dir1/dir2/file6,v  <--  first-dir/dir1/dir2/file6
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/dir1/dir2/file7,v  <--  first-dir/dir1/dir2/file7
initial revision: 1\.1"

		dotest basic2-9 "${testcvs} tag second-dive first-dir" \
"${SPROG} tag: Tagging first-dir
T first-dir/file6
T first-dir/file7
${SPROG} tag: Tagging first-dir/dir1
T first-dir/dir1/file6
T first-dir/dir1/file7
${SPROG} tag: Tagging first-dir/dir1/dir2
T first-dir/dir1/dir2/file6
T first-dir/dir1/dir2/file7"

		# third dive - in bunch o' directories, add bunch o' files,
		# delete some, change some.

		for i in first-dir dir1 dir2 ; do
			cd $i

			# modify a file
			echo file6 >>file6

			# delete a file
			rm file7

			dotest basic2-10-$i "${testcvs} rm file7" \
"${SPROG} remove: scheduling .file7. for removal
${SPROG} remove: use .${SPROG} commit. to remove this file permanently"

			# and add a new file
			echo file14 >file14

			dotest basic2-11-$i "${testcvs} add file14" \
"${SPROG} add: scheduling file .file14. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
		done

		cd ../../..
		dotest basic2-12 "${testcvs} update first-dir" \
"${SPROG} update: Updating first-dir
A first-dir/file14
M first-dir/file6
R first-dir/file7
${SPROG} update: Updating first-dir/dir1
A first-dir/dir1/file14
M first-dir/dir1/file6
R first-dir/dir1/file7
${SPROG} update: Updating first-dir/dir1/dir2
A first-dir/dir1/dir2/file14
M first-dir/dir1/dir2/file6
R first-dir/dir1/dir2/file7"

		# FIXME: doesn't work right for added files
		dotest basic2-13 "${testcvs} log first-dir" \
"${SPROG} log: Logging first-dir
${SPROG} log: file14 has been added, but not committed

RCS file: ${CVSROOT_DIRNAME}/first-dir/file6,v
Working file: first-dir/file6
head: 1\.1
branch:
locks: strict
access list:
symbolic names:
	second-dive: 1\.1
keyword substitution: kv
total revisions: 1;	selected revisions: 1
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
second dive
=============================================================================

RCS file: ${CVSROOT_DIRNAME}/first-dir/file7,v
Working file: first-dir/file7
head: 1\.1
branch:
locks: strict
access list:
symbolic names:
	second-dive: 1\.1
keyword substitution: kv
total revisions: 1;	selected revisions: 1
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
second dive
=============================================================================
${SPROG} log: Logging first-dir/dir1
${SPROG} log: file14 has been added, but not committed

RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/file6,v
Working file: first-dir/dir1/file6
head: 1\.1
branch:
locks: strict
access list:
symbolic names:
	second-dive: 1\.1
keyword substitution: kv
total revisions: 1;	selected revisions: 1
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
second dive
=============================================================================

RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/file7,v
Working file: first-dir/dir1/file7
head: 1\.1
branch:
locks: strict
access list:
symbolic names:
	second-dive: 1\.1
keyword substitution: kv
total revisions: 1;	selected revisions: 1
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
second dive
=============================================================================
${SPROG} log: Logging first-dir/dir1/dir2
${SPROG} log: file14 has been added, but not committed

RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file6,v
Working file: first-dir/dir1/dir2/file6
head: 1\.1
branch:
locks: strict
access list:
symbolic names:
	second-dive: 1\.1
keyword substitution: kv
total revisions: 1;	selected revisions: 1
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
second dive
=============================================================================

RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file7,v
Working file: first-dir/dir1/dir2/file7
head: 1\.1
branch:
locks: strict
access list:
symbolic names:
	second-dive: 1\.1
keyword substitution: kv
total revisions: 1;	selected revisions: 1
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
second dive
============================================================================="

		dotest basic2-14 "${testcvs} status first-dir" \
"${SPROG} status: Examining first-dir
===================================================================
File: file14           	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file6            	Status: Locally Modified

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file6,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: no file file7		Status: Locally Removed

   Working revision:	-1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file7,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

${SPROG} status: Examining first-dir/dir1
===================================================================
File: file14           	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file6            	Status: Locally Modified

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/dir1/file6,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: no file file7		Status: Locally Removed

   Working revision:	-1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/dir1/file7,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

${SPROG} status: Examining first-dir/dir1/dir2
===================================================================
File: file14           	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file6            	Status: Locally Modified

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file6,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: no file file7		Status: Locally Removed

   Working revision:	-1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file7,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)${DOTSTAR}"

# XXX why is this commented out?
#		if ${CVS} diff -u first-dir  >> ${LOGFILE} || test $? = 1 ; then
#		    pass 42
#		else
#		    fail 42
#		fi

		dotest basic2-16 "${testcvs} ci -m 'third dive' first-dir" \
"${CPROG} commit: Examining first-dir
${CPROG} commit: Examining first-dir/dir1
${CPROG} commit: Examining first-dir/dir1/dir2
${CVSROOT_DIRNAME}/first-dir/file14,v  <--  first-dir/file14
initial revision: 1\.1
${CVSROOT_DIRNAME}/first-dir/file6,v  <--  first-dir/file6
new revision: 1\.2; previous revision: 1\.1
${CVSROOT_DIRNAME}/first-dir/file7,v  <--  first-dir/file7
new revision: delete; previous revision: 1\.1
${CVSROOT_DIRNAME}/first-dir/dir1/file14,v  <--  first-dir/dir1/file14
initial revision: 1\.1
${CVSROOT_DIRNAME}/first-dir/dir1/file6,v  <--  first-dir/dir1/file6
new revision: 1\.2; previous revision: 1\.1
${CVSROOT_DIRNAME}/first-dir/dir1/file7,v  <--  first-dir/dir1/file7
new revision: delete; previous revision: 1\.1
${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file14,v  <--  first-dir/dir1/dir2/file14
initial revision: 1\.1
${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file6,v  <--  first-dir/dir1/dir2/file6
new revision: 1\.2; previous revision: 1\.1
${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file7,v  <--  first-dir/dir1/dir2/file7
new revision: delete; previous revision: 1\.1"
		dotest basic2-17 "${testcvs} -q update first-dir" ''

		dotest basic2-18 "${testcvs} tag third-dive first-dir" \
"${SPROG} tag: Tagging first-dir
T first-dir/file14
T first-dir/file6
${SPROG} tag: Tagging first-dir/dir1
T first-dir/dir1/file14
T first-dir/dir1/file6
${SPROG} tag: Tagging first-dir/dir1/dir2
T first-dir/dir1/dir2/file14
T first-dir/dir1/dir2/file6"

		dotest basic2-19 "echo yes | ${testcvs} release -d first-dir" \
"You have \[0\] altered files in this repository\.
Are you sure you want to release (and delete) directory .first-dir.: "

		# end of third dive
		dotest_fail basic2-20 "test -d first-dir" ""

		# now try some rtags

		# rtag HEADS
		dotest basic2-21 "${testcvs} rtag rtagged-by-head first-dir" \
"${SPROG} rtag: Tagging first-dir
${SPROG} rtag: Tagging first-dir/dir1
${SPROG} rtag: Tagging first-dir/dir1/dir2"

		dotest basic2-21b "${testcvs} co -p -r rtagged-by-head first-dir/file6" \
"===================================================================
Checking out first-dir/file6
RCS:  $CVSROOT_DIRNAME/first-dir/file6,v
VERS: 1\.2
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
file6
file6"
		# see what happens when val-tags is removed
		modify_repo mv $CVSROOT_DIRNAME/CVSROOT/val-tags \
				$CVSROOT_DIRNAME/CVSROOT/val-tags.save
		# The output for this used to be something like:
		# "${SPROG} checkout: cannot open CVS/Entries for reading: No such file or directory
		# ${SPROG} \[checkout aborted\]: no such tag \`rtagged-by-head'"

		dotest basic2-21c \
"${testcvs} co -p -r rtagged-by-head first-dir/file6" \
"===================================================================
Checking out first-dir/file6
RCS:  $CVSROOT_DIRNAME/first-dir/file6,v
VERS: 1\.2
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
file6
file6"
		modify_repo mv $CVSROOT_DIRNAME/CVSROOT/val-tags.save \
				$CVSROOT_DIRNAME/CVSROOT/val-tags

		# tag by tag
		dotest basic2-22 "${testcvs} rtag -r rtagged-by-head rtagged-by-tag first-dir" \
"${SPROG} rtag: Tagging first-dir
${SPROG} rtag: Tagging first-dir/dir1
${SPROG} rtag: Tagging first-dir/dir1/dir2"

		# tag by revision
		dotest basic2-23 "${testcvs} rtag -r1.1 rtagged-by-revision first-dir" \
"${SPROG} rtag: Tagging first-dir
${SPROG} rtag: Tagging first-dir/dir1
${SPROG} rtag: Tagging first-dir/dir1/dir2"

		# rdiff by revision
		dotest basic2-24 "${testcvs} rdiff -r1.1 -rrtagged-by-head first-dir" \
"${SPROG} rdiff: Diffing first-dir
Index: first-dir/file6
diff -c first-dir/file6:1\.1 first-dir/file6:1\.2
\*\*\* first-dir/file6:1\.1	${DATE}
--- first-dir/file6	${DATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
--- 1,2 ----
  file6
${PLUS} file6
Index: first-dir/file7
diff -c first-dir/file7:1\.1 first-dir/file7:removed
\*\*\* first-dir/file7:1.1	${DATE}
--- first-dir/file7	${DATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
- file7
--- 0 ----
${SPROG} rdiff: Diffing first-dir/dir1
Index: first-dir/dir1/file6
diff -c first-dir/dir1/file6:1\.1 first-dir/dir1/file6:1\.2
\*\*\* first-dir/dir1/file6:1\.1	${DATE}
--- first-dir/dir1/file6	${DATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
--- 1,2 ----
  file6
${PLUS} file6
Index: first-dir/dir1/file7
diff -c first-dir/dir1/file7:1\.1 first-dir/dir1/file7:removed
\*\*\* first-dir/dir1/file7:1\.1	${DATE}
--- first-dir/dir1/file7	${DATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
- file7
--- 0 ----
${SPROG} rdiff: Diffing first-dir/dir1/dir2
Index: first-dir/dir1/dir2/file6
diff -c first-dir/dir1/dir2/file6:1\.1 first-dir/dir1/dir2/file6:1\.2
\*\*\* first-dir/dir1/dir2/file6:1\.1	${DATE}
--- first-dir/dir1/dir2/file6	${DATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
--- 1,2 ----
  file6
${PLUS} file6
Index: first-dir/dir1/dir2/file7
diff -c first-dir/dir1/dir2/file7:1\.1 first-dir/dir1/dir2/file7:removed
\*\*\* first-dir/dir1/dir2/file7:1\.1	${DATE}
--- first-dir/dir1/dir2/file7	${DATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
- file7
--- 0 ----"
		dotest basic2-24a "${testcvs} rdiff -l -r1.1 -rrtagged-by-head first-dir" \
"${SPROG} rdiff: Diffing first-dir
Index: first-dir/file6
diff -c first-dir/file6:1\.1 first-dir/file6:1\.2
\*\*\* first-dir/file6:1\.1	${DATE}
--- first-dir/file6	${DATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
--- 1,2 ----
  file6
${PLUS} file6
Index: first-dir/file7
diff -c first-dir/file7:1\.1 first-dir/file7:removed
\*\*\* first-dir/file7:1.1	${DATE}
--- first-dir/file7	${DATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
- file7
--- 0 ----"
		# now export by rtagged-by-head and rtagged-by-tag and compare.
		dotest basic2-25 "${testcvs} export -r rtagged-by-head -d 1dir first-dir" \
"${SPROG} export: Updating 1dir
U 1dir/file14
U 1dir/file6
${SPROG} export: Updating 1dir/dir1
U 1dir/dir1/file14
U 1dir/dir1/file6
${SPROG} export: Updating 1dir/dir1/dir2
U 1dir/dir1/dir2/file14
U 1dir/dir1/dir2/file6"
		dotest_fail basic2-25a "test -d 1dir/CVS"
		dotest_fail basic2-25b "test -d 1dir/dir1/CVS"
		dotest_fail basic2-25c "test -d 1dir/dir1/dir2/CVS"

		dotest basic2-26 "${testcvs} export -r rtagged-by-tag first-dir" \
"${SPROG} export: Updating first-dir
U first-dir/file14
U first-dir/file6
${SPROG} export: Updating first-dir/dir1
U first-dir/dir1/file14
U first-dir/dir1/file6
${SPROG} export: Updating first-dir/dir1/dir2
U first-dir/dir1/dir2/file14
U first-dir/dir1/dir2/file6"
		dotest_fail basic2-26a "test -d first-dir/CVS"
		dotest_fail basic2-26b "test -d first-dir/dir1/CVS"
		dotest_fail basic2-26c "test -d first-dir/dir1/dir2/CVS"

		dotest basic2-27 "directory_cmp 1dir first-dir"
		rm -r 1dir first-dir

		# checkout by revision vs export by rtagged-by-revision and compare.
		mkdir export-dir
		dotest basic2-28 "${testcvs} export -rrtagged-by-revision -d export-dir first-dir" \
"${SPROG} export: Updating export-dir
U export-dir/file14
U export-dir/file6
U export-dir/file7
${SPROG} export: Updating export-dir/dir1
U export-dir/dir1/file14
U export-dir/dir1/file6
U export-dir/dir1/file7
${SPROG} export: Updating export-dir/dir1/dir2
U export-dir/dir1/dir2/file14
U export-dir/dir1/dir2/file6
U export-dir/dir1/dir2/file7"
		dotest_fail basic2-28a "test -d export-dir/CVS"
		dotest_fail basic2-28b "test -d export-dir/dir1/CVS"
		dotest_fail basic2-28c "test -d export-dir/dir1/dir2/CVS"

		dotest basic2-29 "${testcvs} co -r1.1 first-dir" \
"${SPROG} checkout: Updating first-dir
U first-dir/file14
U first-dir/file6
U first-dir/file7
${SPROG} checkout: Updating first-dir/dir1
U first-dir/dir1/file14
U first-dir/dir1/file6
U first-dir/dir1/file7
${SPROG} checkout: Updating first-dir/dir1/dir2
U first-dir/dir1/dir2/file14
U first-dir/dir1/dir2/file6
U first-dir/dir1/dir2/file7"

		# directory copies are done in an oblique way in order to avoid a bug in sun's tmp filesystem.
		mkdir first-dir.cpy ; (cd first-dir ; tar cf - . | (cd ../first-dir.cpy ; tar xf -))

		dotest basic2-30 "directory_cmp first-dir export-dir"

		# interrupt, while we've got a clean 1.1 here, let's import it
		# into a couple of other modules.
		cd export-dir
		dotest_sort basic2-31 \
"$testcvs import -m first-import second-dir first-immigration immigration1 immigration1_0" \
"

N second-dir/dir1/dir2/file14
N second-dir/dir1/dir2/file6
N second-dir/dir1/dir2/file7
N second-dir/dir1/file14
N second-dir/dir1/file6
N second-dir/dir1/file7
N second-dir/file14
N second-dir/file6
N second-dir/file7
No conflicts created by this import
${SPROG} import: Importing ${CVSROOT_DIRNAME}/second-dir/dir1
${SPROG} import: Importing ${CVSROOT_DIRNAME}/second-dir/dir1/dir2"
		cd ..

		dotest basic2-32 "${testcvs} export -r HEAD second-dir" \
"${SPROG} export: Updating second-dir
U second-dir/file14
U second-dir/file6
U second-dir/file7
${SPROG} export: Updating second-dir/dir1
U second-dir/dir1/file14
U second-dir/dir1/file6
U second-dir/dir1/file7
${SPROG} export: Updating second-dir/dir1/dir2
U second-dir/dir1/dir2/file14
U second-dir/dir1/dir2/file6
U second-dir/dir1/dir2/file7"

		dotest basic2-33 "directory_cmp first-dir second-dir"

		rm -r second-dir

		rm -r export-dir first-dir
		mkdir first-dir
		(cd first-dir.cpy ; tar cf - . | (cd ../first-dir ; tar xf -))

		# update the top, cancelling sticky tags, retag, update other copy, compare.
		cd first-dir
		dotest basic2-34 "${testcvs} update -A -l *file*" \
"[UP] file6
${SPROG} update: \`file7' is no longer in the repository"

		# If we don't delete the tag first, cvs won't retag it.
		# This would appear to be a feature.
		dotest basic2-35 "${testcvs} tag -l -d rtagged-by-revision" \
"${SPROG} tag: Untagging \.
D file14
D file6"
		dotest basic2-36 "${testcvs} tag -l rtagged-by-revision" \
"${SPROG} tag: Tagging \.
T file14
T file6"

		cd ..
		mv first-dir 1dir
		mv first-dir.cpy first-dir
		cd first-dir

		dotest basic2-37 "${testcvs} -q diff -u" ''

		dotest basic2-38 "${testcvs} update" \
"${SPROG} update: Updating .
${SPROG} update: Updating dir1
${SPROG} update: Updating dir1/dir2"

		cd ..

		#### FIXME: is this expected to work???  Need to investigate
		#### and fix or remove the test.
#		dotest basic2-39 "directory_cmp 1dir first-dir"

		rm -r 1dir first-dir

		# Test the cvs history command.
		#
		# Just skip these in write proxy mode for now.  We should only
		# see write commands and maybe the last few reads in the
		# secondary history file the way we currently sync, but I'm not
		# going to try and test this yet.
		if $proxy; then :; else

		# The reason that there are two patterns rather than using
		# \(${TESTDIR}\|<remote>\) is that we are trying to
		# make this portable.  Perhaps at some point we should
		# ditch that notion and require GNU expr (or dejagnu or....)
		# since it seems to be so painful.

		dotest basic2-64 "${testcvs} his -x TOFWUPCGMAR -a" \
"O [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir           =first-dir= ${TESTDIR}/\*
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6     first-dir           == ${TESTDIR}
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7     first-dir           == ${TESTDIR}
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6     first-dir/dir1      == ${TESTDIR}
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7     first-dir/dir1      == ${TESTDIR}
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6     first-dir/dir1/dir2 == ${TESTDIR}
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7     first-dir/dir1/dir2 == ${TESTDIR}
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14    first-dir           == ${TESTDIR}
M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6     first-dir           == ${TESTDIR}
R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7     first-dir           == ${TESTDIR}
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14    first-dir/dir1      == ${TESTDIR}
M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6     first-dir/dir1      == ${TESTDIR}
R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7     first-dir/dir1      == ${TESTDIR}
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14    first-dir/dir1/dir2 == ${TESTDIR}
M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6     first-dir/dir1/dir2 == ${TESTDIR}
R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7     first-dir/dir1/dir2 == ${TESTDIR}
F [0-9-]* [0-9:]* ${PLUS}0000 ${username}                     =first-dir= ${TESTDIR}/\*
T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-head:A\]
T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-tag:rtagged-by-head\]
T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-revision:1\.1\]
O [0-9-]* [0-9:]* ${PLUS}0000 ${username} \[1\.1\] first-dir           =first-dir= ${TESTDIR}/\*
U [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6     first-dir           == ${TESTDIR}/first-dir
W [0-9-]* [0-9:]* ${PLUS}0000 ${username}     file7     first-dir           == ${TESTDIR}/first-dir" \
"O [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir           =first-dir= <remote>/\*
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6     first-dir           == <remote>
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7     first-dir           == <remote>
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6     first-dir/dir1      == <remote>
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7     first-dir/dir1      == <remote>
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6     first-dir/dir1/dir2 == <remote>
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7     first-dir/dir1/dir2 == <remote>
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14    first-dir           == <remote>
M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6     first-dir           == <remote>
R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7     first-dir           == <remote>
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14    first-dir/dir1      == <remote>
M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6     first-dir/dir1      == <remote>
R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7     first-dir/dir1      == <remote>
A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14    first-dir/dir1/dir2 == <remote>
M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6     first-dir/dir1/dir2 == <remote>
R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7     first-dir/dir1/dir2 == <remote>
F [0-9-]* [0-9:]* ${PLUS}0000 ${username}                     =first-dir= <remote>/\*
T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-head:A\]
T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-tag:rtagged-by-head\]
T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-revision:1\.1\]
O [0-9-]* [0-9:]* ${PLUS}0000 ${username} \[1\.1\] first-dir           =first-dir= <remote>/\*
P [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6     first-dir           == <remote>
W [0-9-]* [0-9:]* ${PLUS}0000 ${username}     file7     first-dir           == <remote>"
	  fi

	  dokeep
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
			     $CVSROOT_DIRNAME/second-dir
	  ;;



	ls)
	  # Test the ls & rls commands.  There are some tests of
	  # Interaction of ls, rls, and branches in branches2.
	  mkdir ls; cd ls
	  dotest ls-init-1 "$testcvs -Q co -dtop ."
	  cd top
	  dotest ls-1 "$testcvs ls CVSROOT" \
"checkoutlist
commitinfo
config
cvswrappers
loginfo
modules
notify
postadmin
postproxy
posttag
postwatch
preproxy
rcsinfo
taginfo
verifymsg"
	  dotest ls-2 "$testcvs ls -R" \
"\.:
CVSROOT

CVSROOT:
checkoutlist
commitinfo
config
cvswrappers
loginfo
modules
notify
postadmin
postproxy
posttag
postwatch
preproxy
rcsinfo
taginfo
verifymsg"
	  # This used to cause a fatal error.
	  modify_repo mkdir $CVSROOT_DIRNAME/notcheckedout
	  dotest ls-3 "$testcvs ls -RP" \
"\.:
CVSROOT
notcheckedout

CVSROOT:
checkoutlist
commitinfo
config
cvswrappers
loginfo
modules
notify
postadmin
postproxy
posttag
postwatch
preproxy
rcsinfo
taginfo
verifymsg"

	  # Make sure the previous command did not create the notcheckedout
	  # directory.
	  dotest_fail ls-4 "test -d notcheckedout"

	  dotest ls-5 "$testcvs ls -R" \
"\.:
CVSROOT
notcheckedout

CVSROOT:
checkoutlist
commitinfo
config
cvswrappers
loginfo
modules
notify
postadmin
postproxy
posttag
postwatch
preproxy
rcsinfo
taginfo
verifymsg

notcheckedout:"
	  dotest_fail ls-6 "test -d notcheckedout"

	  # Several test for ls -d, which shows dead revisions

	  # Set up the dead files
	  mkdir cemetery
	  dotest ls-d-init-1 "$testcvs -Q add cemetery"
	  cd cemetery
	  touch dead living
	  dotest ls-d-init-2 "$testcvs -Q add dead living"
	  dotest ls-d-init-3 "$testcvs -Q ci -mm dead living"
	  dotest ls-d-init-4 "$testcvs -Q tag -b branch"
	  dotest ls-d-init-5 "$testcvs -Q up -A"
	  rm dead
	  dotest ls-d-init-6 "$testcvs -Q rm dead"
	  dotest ls-d-init-7 "$testcvs -Q ci -mm dead"
	  dotest ls-d-init-8 "$testcvs -Q up -r branch"
	  rm dead
	  dotest ls-d-init-9 "$testcvs -Q rm dead"
	  dotest ls-d-init-10 "$testcvs -Q ci -mm dead"

	  # Possible output
	  output_living="living"
	  output_dead="dead
living"

	  # The basic test is to make sure that dead revisions are shown if and
	  # only if -d is speficified (and that live revisions are always
	  # shown).  The following test cases cover all combinations of these
	  # factors:
	  #
	  #    + Working directory is on branch or trunk
	  #    + ls or rls
	  #    + implicit branch, explicit trunk, or explicit branch
	  #    + -d present or absent

	  # Working directory on trunk
	  $testcvs -Q up -A

	  ## ls
	  dotest ls-d-1 "$testcvs ls" "$output_living"
	  dotest ls-d-2 "$testcvs ls -d" "$output_dead"

	  dotest ls-d-3 "$testcvs ls -rHEAD" "$output_living"
	  dotest ls-d-4 "$testcvs ls -drHEAD" "$output_dead"

	  dotest ls-d-5 "$testcvs ls -rbranch" "$output_living"
	  dotest ls-d-6 "$testcvs ls -drbranch" "$output_dead"

	  ## rls
	  dotest ls-d-7 "$testcvs rls cemetery" \
"$SPROG rls: Listing module: \`cemetery'
$output_living"
	  dotest ls-d-8 "$testcvs rls -d cemetery" \
"$SPROG rls: Listing module: \`cemetery'
$output_dead"

	  dotest ls-d-9 "$testcvs -q rls -rHEAD cemetery" "$output_living"
	  dotest ls-d-10 "$testcvs -q rls -drHEAD cemetery" "$output_dead"

	  dotest ls-d-11 "$testcvs -q rls -rbranch cemetery" "$output_living"
	  dotest ls-d-12 "$testcvs -q rls -drbranch cemetery" "$output_dead"

	  # Working directory on branch
	  $testcvs -Q up -r branch

	  ## ls
	  dotest ls-d-13 "$testcvs ls" "$output_living"
	  dotest ls-d-14 "$testcvs ls -d" "$output_dead"

	  dotest ls-d-15 "$testcvs ls -r HEAD" "$output_living"
	  dotest ls-d-16 "$testcvs ls -d -r HEAD" "$output_dead"

	  dotest ls-d-17 "$testcvs ls -r branch" "$output_living"
	  dotest ls-d-18 "$testcvs ls -d -r branch" "$output_dead"

	  ## rls
	  dotest ls-d-19 "$testcvs -q rls cemetery" "$output_living"
	  dotest ls-d-20 "$testcvs -q rls -d cemetery" "$output_dead"

	  dotest ls-d-21 "$testcvs -q rls -rHEAD cemetery" "$output_living"
	  dotest ls-d-22 "$testcvs -q rls -drHEAD cemetery" "$output_dead"

	  dotest ls-d-23 "$testcvs -q rls -rbranch cemetery" "$output_living"
	  dotest ls-d-24 "$testcvs -q rls -drbranch cemetery" "$output_dead"

	  # Some tests to cover specifying a file name as an option
	  # Combinations of factors:
	  #
	  #  + file in CVS/Entries or not
	  #  + current directory or subdirectory
	  #  + file dead or not

	  # Switch back to the trunk
	  $testcvs -Q up -A

	  ## file in CVS/Entries
	  dotest ls-filename-1 "$testcvs ls dead"

	  # ls'ing a file that already exists once caused an assertion failure.
	  dotest ls-filename-2 "$testcvs ls living" "living"

	  cd ..
	  dotest ls-filename-3 "$testcvs ls cemetery/dead"

	  # ls'ing a file that already exists once caused an assertion failure.
	  dotest ls-filename-4 "$testcvs ls cemetery/living" "cemetery/living"
	  cd cemetery

	  ## file not in CVS/Entries
	  echo D > CVS/Entries

	  dotest ls-filename-5 "$testcvs ls dead"

	  # ls'ing a file that already exists once caused an assertion failure.
	  dotest ls-filename-6 "$testcvs ls living" "living"

	  cd ..
	  dotest ls-filename-7 "$testcvs ls cemetery/dead"

	  # ls'ing a file that already exists once caused an assertion failure.
	  dotest ls-filename-8 "$testcvs ls cemetery/living" "cemetery/living"

	  cd cemetery

	  # Test the -D date option to cvs ls

	  # try and list a file before it's created, during an old revision, in
	  # a period when it was dead and in the future
	  time_prebirth=`date '+%Y-%m-%d %H:%M:%S'` ; sleep 1
	  touch dated
	  dotest ls-D-init-1 "$testcvs -Q add dated"
	  dotest ls-D-init-2 "$testcvs -Q ci -mm dated"
	  time_newborn=`date '+%Y-%m-%d %H:%M:%S'` ; sleep 1
	  echo mm >> dated
	  dotest ls-D-init-2 "$testcvs -Q ci -mm dated"
	  time_predeath=`date '+%Y-%m-%d %H:%M:%S'` ; sleep 1
	  rm dated
	  dotest ls-D-init-3 "$testcvs -Q rm dated"
	  dotest ls-D-init-4 "$testcvs -Q ci -mm dated"
	  time_postdeath=`date '+%Y-%m-%d %H:%M:%S'`

	  dotest ls-D-1 "$testcvs ls -D '$time_prebirth' -e dated"

	  # ls'ing a file that already exists once caused an assertion failure.
	  dotest ls-D-2 "$testcvs ls -D '$time_newborn' -e dated" \
"/dated/1\.1/.*"

	  # ls'ing a file that already exists once caused an assertion failure.
	  dotest ls-D-3 "$testcvs ls -D '$time_predeath' -e dated" \
"/dated/1.2/.*"

	  dotest ls-D-4 "$testcvs ls -D '$time_postdeath' -e dated"

	  dokeep
	  cd ../../..
	  rm -r ls
	  modify_repo rm -rf $CVSROOT_DIRNAME/notcheckedout \
			     $CVSROOT_DIRNAME/cemetery
	  unset output_living output_dead
	  ;;



	parseroot)
	  mkdir 1; cd 1
	  # Test odd cases involving CVSROOT.  At the moment, that means we
	  # are testing roots with '/'s on the end, which CVS should parse off.
	  CVSROOT_save=${CVSROOT}
	  CVSROOT="${CVSROOT}/////"
	  dotest parseroot-1 "${testcvs} -q co CVSROOT/modules" \
"U CVSROOT/modules"
	  dotest parseroot-2 "${testcvs} -q ci -fmnull-change CVSROOT/modules" \
"$CVSROOT_DIRNAME/CVSROOT/modules,v  <--  CVSROOT/modules
new revision: 1\.2; previous revision: 1\.1
$SPROG commit: Rebuilding administrative file database"

	  if $remote; then
	    # I only test these when testing remote in case CVS was compiled
	    # without client support.

	    # logout does not try to contact the server.
	    CVSROOT=":pserver;proxy=localhost;proxyport=8080:localhost/dev/null"
	    dotest parseroot-3r "$testcvs -d'$CVSROOT' logout" \
"Logging out of :pserver:$username@localhost:2401/dev/null
$CPROG logout: warning: failed to open $HOME/\.cvspass for reading: No such file or directory
$CPROG logout: Entry not found."
	    CVSROOT=":pserver;proxyport=8080:localhost/dev/null"
	    dotest_fail parseroot-4r "$testcvs -d'$CVSROOT' logout" \
"$CPROG logout: Proxy port specified in CVSROOT without proxy host\.
$CPROG \[logout aborted\]: Bad CVSROOT: \`:pserver;proxyport=8080:localhost/dev/null'\."
	    CVSROOT=":pserver;optionnoarg:localhost/dev/null"
	    dotest_fail parseroot-5r "$testcvs -d'$CVSROOT' logout" \
"$CPROG logout: Option (\`optionnoarg') has no argument in CVSROOT\.
$CPROG \[logout aborted\]: Bad CVSROOT: \`:pserver;optionnoarg:localhost/dev/null'\."
	    CVSROOT=":pserver;notanoption=anything:localhost/dev/null"
	    dotest_fail parseroot-6r "$testcvs -d'$CVSROOT' logout" \
"$CPROG logout: Unknown option (\`notanoption') in CVSROOT\.
$CPROG \[logout aborted\]: Bad CVSROOT: \`:pserver;notanoption=anything:localhost/dev/null'\."
	    CVSROOT=":local;proxy=localhost:/dev/null"
	    dotest_fail parseroot-7r "$testcvs -d'$CVSROOT' logout" \
"$CPROG logout: CVSROOT proxy specification is only valid for gserver and
$CPROG logout: pserver connection methods\.
$CPROG \[logout aborted\]: Bad CVSROOT: \`:local;proxy=localhost:/dev/null'\."
	    CVSROOT="::pserver@anonymous@test.org:/cvs"
	    dotest_fail parseroot-8r "$testcvs -d'$CVSROOT' co test" \
"$CPROG checkout: Unknown method (\`') in CVSROOT\.
$CPROG \[checkout aborted\]: Bad CVSROOT: \`$CVSROOT'\."
	  fi

	  dokeep

	  # Clean up
	  CVSROOT=$CVSROOT_save
	  cd ..
	  rm -r 1
	  ;;



	files)
	  # Test of how we specify files on the command line
	  # (recurse.c and that sort of thing).  Vaguely similar to
	  # tests like basic* and deep.  See modules and such tests
	  # for what happens when we throw in modules and co -d, &c.

	  # This particular test is fairly carefully crafted, to spot
	  # one particular issue with remote.
	  mkdir 1; cd 1
	  dotest files-1 "${testcvs} -q co -l ." ""
	  mkdir first-dir
	  dotest files-2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
	  cd first-dir
	  touch tfile
	  dotest files-3 "${testcvs} add tfile" \
"${SPROG} add: scheduling file .tfile. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest files-4 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/tfile,v  <--  tfile
initial revision: 1\.1"
	  dotest files-5 "${testcvs} -q tag -b C" "T tfile"
	  dotest files-6 "${testcvs} -q update -r C" ""
	  mkdir dir
	  dotest files-7 "${testcvs} add dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir/dir added to the repository
--> Using per-directory sticky tag .C'"
	  cd dir
	  touch .file
	  dotest files-7b "${testcvs} add .file" \
"${SPROG} add: scheduling file .\.file' for addition on branch .C.
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  mkdir sdir
	  dotest files-7c "${testcvs} add sdir" \
"Directory ${CVSROOT_DIRNAME}/first-dir/dir/sdir added to the repository
--> Using per-directory sticky tag .C'"
	  cd sdir
	  mkdir ssdir
	  dotest files-8 "${testcvs} add ssdir" \
"Directory ${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir added to the repository
--> Using per-directory sticky tag .C'"
	  cd ssdir
	  touch .file
	  dotest files-9 "${testcvs} add .file" \
"${SPROG} add: scheduling file .\.file' for addition on branch .C.
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  cd ../..
	  dotest files-10 "${testcvs} -q ci -m test" \
"$CVSROOT_DIRNAME/first-dir/dir/Attic/\.file,v  <--  \.file
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/dir/sdir/ssdir/Attic/\.file,v  <--  sdir/ssdir/\.file
new revision: 1\.1\.2\.1; previous revision: 1\.1"
	  dotest files-11 \
"${testcvs} commit -m test -f ./.file ./sdir/ssdir/.file" \
"${CVSROOT_DIRNAME}/first-dir/dir/Attic/\.file,v  <--  \.file
new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1
${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir/Attic/\.file,v  <--  \./sdir/ssdir/\.file
new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
	  if $remote; then
	    # FIXCVS:
	    # This is a bug, looks like that toplevel_repos cruft in
	    # client.c is coming back to haunt us.
	    # May want to think about the whole issue, toplevel_repos
	    # has always been crufty and trying to patch it up again
	    # might be a mistake.
	    dotest files-12r \
"$testcvs commit -f -m test ./sdir/ssdir/.file ./.file" \
"$CVSROOT_DIRNAME/first-dir/dir/sdir/ssdir/Attic/\.file,v  <--  \./sdir/ssdir/\.file
new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2"

	    # Sync up the version numbers so that the rest of the
	    # tests don't need to expect different numbers based
	    # local or remote.
	    dotest files-12rworkaround \
"$testcvs commit -f -m test .file" \
"$CVSROOT_DIRNAME/first-dir/dir/Attic/\.file,v  <--  \.file
new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2"
	  else
	    dotest files-12 \
"${testcvs} commit -f -m test ./sdir/ssdir/.file ./.file" \
"${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir/Attic/\.file,v  <--  \./sdir/ssdir/\.file
new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2
${CVSROOT_DIRNAME}/first-dir/dir/Attic/\.file,v  <--  \.file
new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2"
	  fi
	  dotest files-13 \
"${testcvs} commit -fmtest ./sdir/../sdir/ssdir/..///ssdir/.file" \
"${CVSROOT_DIRNAME}/first-dir/dir/sdir/ssdir/Attic/\.file,v  <--  \./sdir/\.\./sdir/ssdir/\.\.///ssdir/\.file
new revision: 1\.1\.2\.4; previous revision: 1\.1\.2\.3"
	  dotest files-14 \
"${testcvs} commit -fmtest ../../first-dir/dir/.file" \
"${CVSROOT_DIRNAME}/first-dir/dir/Attic/\.file,v  <--  \.\./\.\./first-dir/dir/\.file
new revision: 1\.1\.2\.4; previous revision: 1\.1\.2\.3"

	  dokeep
	  cd ../../..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	spacefiles)
	  # More filename tests, in particular spaces in file names.
	  # (it might be better to just change a few of the names in
	  # basica or some other test instead, always good to keep the
	  # testsuite concise).

	  mkdir 1; cd 1
	  dotest spacefiles-1 "${testcvs} -q co -l ." ""
	  touch ./-c
	  dotest spacefiles-2 "${testcvs} add -- -c" \
"${SPROG} add: scheduling file .-c. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest spacefiles-3 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/-c,v  <--  -c
initial revision: 1\.1"
	  mkdir 'first dir'
	  dotest spacefiles-4 "${testcvs} add 'first dir'" \
"Directory ${CVSROOT_DIRNAME}/first dir added to the repository"
	  mkdir ./-b
	  dotest spacefiles-5 "${testcvs} add -- -b" \
"Directory ${CVSROOT_DIRNAME}/-b added to the repository"
	  cd 'first dir'
	  touch 'a file'
	  dotest spacefiles-6 "${testcvs} add 'a file'" \
"${SPROG} add: scheduling file .a file. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest spacefiles-7 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first dir/a file,v  <--  a file
initial revision: 1\.1"
	  dotest spacefiles-8 "${testcvs} -q tag new-tag" "T a file"
	  cd ../..

	  mkdir 2; cd 2
	  dotest spacefiles-10 "${testcvs} co -- -b" \
"${SPROG} checkout: Updating -b"
	  dotest spacefiles-11 "${testcvs} -q co -- -c" "U \./-c"
	  rm ./-c
	  dotest spacefiles-13 "${testcvs} -q co 'first dir'" \
"U first dir/a file"
	  cd ..

	  mkdir 3; cd 3
	  dotest spacefiles-14 "${testcvs} -q co 'first dir/a file'" \
"U first dir/a file"
	  cd ..

	  rm -r 1 2 3
	  modify_repo rm -rf "'$CVSROOT_DIRNAME/first dir'" \
			     $CVSROOT_DIRNAME/-b $CVSROOT_DIRNAME/-c,v
	  ;;



	commit-readonly)
	  mkdir 1; cd 1
	  module=x

	  : > junk
	  dotest commit-readonly-1 "$testcvs -Q import -m . $module X Y" ''
	  dotest commit-readonly-2 "$testcvs -Q co $module" ''
	  cd $module

	  file=m

	  # Include an rcs keyword to be expanded.
	  echo '$Id''$' > $file

	  dotest commit-readonly-3 "$testcvs add $file" \
"$SPROG add: scheduling file .$file. for addition
$SPROG add: use .$SPROG commit. to add this file permanently"
	  dotest commit-readonly-4 "$testcvs -Q ci -m . $file"

	  echo line2 >> $file
	  # Make the file read-only.
	  chmod a-w $file

	  dotest commit-readonly-5 "$testcvs -Q ci -m . $file"

	  dokeep
	  cd ../..
	  rm -rf 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/"$module"
	  ;;



	status)
		# This tests for a bug in the status command which failed to
		# notice resolved conflicts.
		mkdir status; cd status
		dotest status-init-1 "$testcvs -q co -l ."
		mkdir first-dir
		dotest status-init-2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
		cd first-dir
		echo a line >tfile
		dotest status-init-3 "${testcvs} add tfile" \
"${SPROG} add: scheduling file .tfile. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
		dotest status-init-4 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/tfile,v  <--  tfile
initial revision: 1\.1"
		cd ..
		dotest status-init-5 "${testcvs} -q co -dsecond-dir first-dir" \
"U second-dir/tfile"
		cd second-dir
		echo some junk >>tfile
		dotest status-init-6 "${testcvs} -q ci -maline" \
"$CVSROOT_DIRNAME/first-dir/tfile,v  <--  tfile
new revision: 1\.2; previous revision: 1\.1"
		cd ../first-dir
		echo force a conflict >>tfile
		dotest status-init-7 "${testcvs} -q up" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/tfile,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into tfile
rcsmerge: warning: conflicts during merge
${SPROG} update: conflicts found in tfile
C tfile"

		# Now note our status
		dotest status-1 "${testcvs} status tfile" \
"===================================================================
File: tfile            	Status: Unresolved Conflict

   Working revision:	1\.2.*
   Repository revision:	1\.2	${CVSROOT_DIRNAME}/first-dir/tfile,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"

		# touch the file, leaving conflict markers in place
		# and note our status
		touch tfile
		dotest status-2 "${testcvs} status tfile" \
"===================================================================
File: tfile            	Status: File had conflicts on merge

   Working revision:	1\.2.*
   Repository revision:	1\.2	${CVSROOT_DIRNAME}/first-dir/tfile,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"

		# resolve the conflict
		echo resolution >tfile
		dotest status-3 "${testcvs} status tfile" \
"===================================================================
File: tfile            	Status: Locally Modified

   Working revision:	1\.2.*
   Repository revision:	1\.2	${CVSROOT_DIRNAME}/first-dir/tfile,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"

		# Check that there are no problems just using CVS/Root too.
		save_CVSROOT=$CVSROOT
		unset CVSROOT
		dotest status-3a "${testcvs} status tfile" \
"===================================================================
File: tfile            	Status: Locally Modified

   Working revision:	1\.2.*
   Repository revision:	1\.2	${CVSROOT_DIRNAME}/first-dir/tfile,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
		CVSROOT=$save_CVSROOT
		export CVSROOT

		# FIXCVS:
		# Update is supposed to re-Register() the file when it
		# finds resolved conflicts:
		dotest status-4 "grep 'Result of merge' CVS/Entries" \
"/tfile/1\.2/Result of merge${PLUS}[a-zA-Z0-9 :]*//"

                cd ..
                mkdir fourth-dir
                dotest status-init-8 "$testcvs add fourth-dir" \
"Directory $CVSROOT_DIRNAME/fourth-dir added to the repository"
                cd fourth-dir
                echo yet another line >t3file
                dotest status-init-9 "$testcvs add t3file" \
"$SPROG add: scheduling file .t3file. for addition
$SPROG add: use .$SPROG commit. to add this file permanently"
                dotest status-init-10 "$testcvs -q ci -m add" \
"$CVSROOT_DIRNAME/fourth-dir/t3file,v  <--  t3file
initial revision: 1\.1"
                cd ../first-dir
                mkdir third-dir
                dotest status-init-11 "$testcvs add third-dir" \
"Directory $CVSROOT_DIRNAME/first-dir/third-dir added to the repository"
                cd third-dir
                echo another line >t2file
                dotest status-init-12 "$testcvs add t2file" \
"$SPROG add: scheduling file .t2file. for addition
$SPROG add: use .$SPROG commit. to add this file permanently"
                dotest status-init-13 "$testcvs -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/third-dir/t2file,v  <--  t2file
initial revision: 1\.1"
                dotest status-5 "$testcvs status ../tfile" \
"===================================================================
File: tfile            	Status: Locally Modified

   Working revision:	1\.2.*
   Repository revision:	1\.2	$CVSROOT_DIRNAME/first-dir/tfile,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
                dotest status-6 "$testcvs status ../../fourth-dir/t3file" \
"===================================================================
File: t3file           	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	$CVSROOT_DIRNAME/fourth-dir/t3file,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"

		dokeep
		cd ../../..
		rm -rf status
		modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
				   $CVSROOT_DIRNAME/fourth-dir
		;;



	commit-readonlyfs)
	  mkdir 1; cd 1
	  module=x
	  : > junk
	  dotest commit-readonlyfs-1 "${testcvs} -Q import -m . $module X Y" ''
	  if $remote; then
	    dotest_fail commit-readonlyfs-2r1 "${testcvs} -Q -R co $module" \
"${CPROG} \[checkout aborted\]: Read-only repository feature unavailable with remote roots (cvsroot = ${CVSROOT_DIRNAME})"
	    dotest commit-readonlyfs-2r2 "${testcvs} -Q co $module" ''
          else
	    dotest commit-readonlyfs-2 "${testcvs} -Q -R co $module" ''
	    rm -rf $module
	    dotest commit-readonlyfs-2r3 "${testcvs} -q -R co $module" \
"U $module/junk"
	    rm -rf $module
	    dotest commit-readonlyfs-2r4 "${testcvs} -R co $module" \
"${SPROG}: WARNING: Read-only repository access mode selected via \`cvs -R'\.
Using this option to access a repository which some users write to may
cause intermittent sandbox corruption\.
${SPROG} checkout: Updating $module
U $module/junk"
          fi
	  cd $module
	  echo test > junk
	  if $remote; then
	    dotest_fail commit-readonlyfs-3r "${testcvs} -Q -R ci -m. junk" \
"${SPROG} \[commit aborted\]: Read-only repository feature unavailable with remote roots (cvsroot = ${CVSROOT_DIRNAME})"
	  else
	    dotest_fail commit-readonlyfs-3 "${testcvs} -Q -R ci -m. junk" \
"${SPROG} commit: write lock failed\.
WARNING: Read-only repository access mode selected via \`cvs -R'\.
Attempting to write to a read-only filesystem is not allowed\.
${SPROG} \[commit aborted\]: lock failed - giving up"
          fi

	  dokeep
	  cd ../..
	  rm -rf 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/"$module"
	  ;;



	rdiff)
		# Test rdiff
		# XXX for now this is just the most essential test...
		cd ${TESTDIR}

		mkdir testimport
		cd testimport
		echo '$''Id$' > foo
		echo '$''Name$' >> foo
		echo '$''Id$' > bar
		echo '$''Name$' >> bar
		dotest_sort rdiff-1 \
		  "${testcvs} import -I ! -m test-import-with-keyword trdiff TRDIFF T1" \
'

N trdiff/bar
N trdiff/foo
No conflicts created by this import'
		dotest rdiff-2 \
		  "${testcvs} co -ko trdiff" \
"${SPROG} checkout: Updating trdiff
U trdiff/bar
U trdiff/foo"
		cd trdiff
		echo something >> foo
		dotest rdiff-3 \
		  "${testcvs} ci -m added-something foo" \
"${CVSROOT_DIRNAME}/trdiff/foo,v  <--  foo
new revision: 1\.2; previous revision: 1\.1"
		echo '#ident	"@(#)trdiff:$''Name$:$''Id$"' > new
		echo "new file" >> new
		dotest rdiff-4 \
		  "${testcvs} add -m new-file-description new" \
"${SPROG} add: scheduling file \`new' for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
		dotest rdiff-5 \
		  "${testcvs} commit -m added-new-file new" \
"${CVSROOT_DIRNAME}/trdiff/new,v  <--  new
initial revision: 1\.1"
		dotest rdiff-6 \
		  "${testcvs} tag local-v0" \
"${SPROG} tag: Tagging .
T bar
T foo
T new"
		dotest rdiff-7 \
		  "${testcvs} status -v foo" \
"===================================================================
File: foo              	Status: Up-to-date

   Working revision:	1\.2.*
   Repository revision:	1\.2	${CVSROOT_DIRNAME}/trdiff/foo,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	-ko

   Existing Tags:
	local-v0                 	(revision: 1\.2)
	T1                       	(revision: 1\.1\.1\.1)
	TRDIFF                   	(branch: 1\.1\.1)"

		cd ..
		rm -r trdiff

		dotest rdiff-8 \
		  "${testcvs} rdiff -r T1 -r local-v0 trdiff" \
"${SPROG}"' rdiff: Diffing trdiff
Index: trdiff/foo
diff -c trdiff/foo:1\.1\.1\.1 trdiff/foo:1\.2
\*\*\* trdiff/foo:1\.1\.1\.1	'"${DATE}"'
--- trdiff/foo	'"${DATE}"'
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1,2 \*\*\*\*
! \$''Id: foo,v 1\.1\.1\.1 [0-9/]* [0-9:]* '"${username}"' Exp \$
! \$''Name: T1 \$
--- 1,3 ----
! \$''Id: foo,v 1\.2 [0-9/]* [0-9:]* '"${username}"' Exp \$
! \$''Name: local-v0 \$
! something
Index: trdiff/new
diff -c /dev/null trdiff/new:1\.1
\*\*\* /dev/null	'"${DATE}"'
--- trdiff/new	'"${DATE}"'
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 0 \*\*\*\*
--- 1,2 ----
'"${PLUS}"' #ident	"@(#)trdiff:\$''Name: local-v0 \$:\$''Id: new,v 1\.1 [0-9/]* [0-9:]* '"${username}"' Exp \$"
'"${PLUS}"' new file'

		dokeep
		cd ..
		rm -r testimport
		modify_repo rm -rf $CVSROOT_DIRNAME/trdiff
		;;



	rdiff-short)
	  # Test that the short patch behaves as expected
	  #   1) Added file.
	  #   2) Removed file.
	  #   3) Different revision number with no difference.
	  #   4) Different revision number with changes.
	  #   5) Against trunk.
	  #   6) Same revision number (no difference).
	  mkdir rdiff-short; cd rdiff-short
	  mkdir abc
	  dotest rdiff-short-init-1 \
"${testcvs} -q import -I ! -m initial-import abc vendor initial" \
'
No conflicts created by this import'

	  dotest rdiff-short-init-2 "${testcvs} -q get abc" ''
	  cd abc
	  echo "abc" >file1.txt
	  dotest rdiff-short-init-3 "${testcvs} add file1.txt" \
"${SPROG} add: scheduling file .file1\.txt' for addition
${SPROG} add: use \`${SPROG} commit' to add this file permanently"
	  dotest rdiff-short-init-4 \
"${testcvs} commit -madd-file1 file1.txt" \
"${CVSROOT_DIRNAME}/abc/file1\.txt,v  <--  file1\.txt
initial revision: 1\.1"
	  echo def >>file1.txt
	  dotest rdiff-short-init-5 \
"${testcvs} commit -mchange-file1 file1.txt" \
"${CVSROOT_DIRNAME}/abc/file1\.txt,v  <--  file1\.txt
new revision: 1\.2; previous revision: 1\.1"
	  echo "abc" >file1.txt
	  dotest rdiff-short-init-6 \
"${testcvs} commit -mrestore-file1-rev1 file1.txt" \
"${CVSROOT_DIRNAME}/abc/file1\.txt,v  <--  file1\.txt
new revision: 1\.3; previous revision: 1\.2"
	  dotest rdiff-short-init-7 \
"${testcvs} tag -r 1.1 tag1 file1.txt" \
"T file1\.txt"
	  dotest rdiff-short-init-8 \
"${testcvs} tag -r 1.2 tag2 file1.txt" \
"T file1\.txt"
	  dotest rdiff-short-init-9 \
"${testcvs} tag -r 1.3 tag3 file1.txt" \
"T file1\.txt"
	  echo "abc" >file2.txt
	  dotest rdiff-short-init-10 \
"${testcvs} add file2.txt" \
"${SPROG} add: scheduling file .file2\.txt' for addition
${SPROG} add: use \`${SPROG} commit' to add this file permanently"
	  dotest rdiff-add-remove-nodiff-init-11 \
"${testcvs} commit -madd-file2 file2.txt" \
"${CVSROOT_DIRNAME}/abc/file2\.txt,v  <--  file2\.txt
initial revision: 1\.1"
	  dotest rdiff-short-init-12 \
"${testcvs} tag -r 1.1 tag4 file2.txt" \
"T file2\.txt"
	  dotest rdiff-short-init-13 \
"${testcvs} tag -r 1.1 tag5 file2.txt" \
"T file2\.txt"
	  cd ../..
	  rm -fr rdiff-short

	  # 3) Different revision number with no difference.
	  dotest rdiff-short-no-real-change \
"${testcvs} -q rdiff -s -r tag1 -r tag3 abc"

	  # 4) Different revision number with changes.
	  dotest rdiff-short-real-change \
"${testcvs} -q rdiff -s -r tag1 -r tag2 abc" \
'File abc/file1.txt changed from revision 1\.1 to 1\.2'

	  # 1) Added file.
	  # 2) Removed file.
	  dotest_sort rdiff-short-remove-add \
"${testcvs} -q rdiff -s -r tag2 -r tag4 abc" \
'File abc/file1\.txt is removed; tag2 revision 1\.2
File abc/file2\.txt is new; tag4 revision 1\.1'

	  # 6) Same revision number (no difference).
	  dotest rdiff-short-no-change \
"${testcvs} -q rdiff -s -r tag4 -r tag5 abc"

	  # 5) Against trunk.
	  # Check that the messages change when we diff against the trunk
	  # rather than a tag or date.
	  dotest rdiff-short-against-trunk-1 \
"${testcvs} -q rdiff -s -rtag4 abc" \
"File abc/file1\.txt is new; current revision 1\.3"

	  dotest rdiff-short-against-trunk-2 \
"${testcvs} -q rdiff -s -rtag2 abc" \
"File abc/file1\.txt changed from revision 1\.2 to 1\.3
File abc/file2\.txt is new; current revision 1\.1"

	  modify_repo rm -rf $CVSROOT_DIRNAME/abc
	  ;;



	rdiff2)
	  # Test for the segv problem reported by James Cribb
	  # Somewhere to work
	  mkdir rdiff2; cd rdiff2	  
	  # Create a module "m" with files "foo" and "d/bar"
	  mkdir m; cd m
	  echo foo >foo
	  mkdir d
	  echo bar >d/bar
	  dotest_sort  rdiff2-1 \
"${testcvs} -q import -I ! -m initial-import m vendor initial" \
'

N m/d/bar
N m/foo
No conflicts created by this import'

	  cd ..
	  rm -r m
	  
	  # Remove "foo"
	  dotest rdiff2-2 "${testcvs} get m" \
"${SPROG} checkout: Updating m
U m/foo
${SPROG} checkout: Updating m/d
U m/d/bar"
	  cd m
	  dotest rdiff2-3 "${testcvs} rm -f foo" \
"${SPROG} remove: scheduling .foo. for removal
${SPROG} remove: use .${SPROG} commit. to remove this file permanently"

	  dotest rdiff2-4 "${testcvs} commit -m Removed foo" \
"${CVSROOT_DIRNAME}/m/foo,v  <--  foo
new revision: delete; previous revision: 1\.1\.1\.1"

	  # Modify "d/bar"
	  echo foo >d/bar
	  dotest rdiff2-5 "${testcvs} commit -m Changed d/bar" \
"${CVSROOT_DIRNAME}/m/d/bar,v  <--  d/bar
new revision: 1\.2; previous revision: 1\.1"
	  
	  # Crash before showing d/bar diffs
	  dotest_fail rdiff2-6 "${testcvs} rdiff -t m" \
"${SPROG} rdiff: Diffing m
${SPROG} rdiff: Diffing m/d
Index: m/d/bar
diff -c m/d/bar:1\.1\.1\.1 m/d/bar:1\.2
\*\*\* m/d/bar:1\.1\.1\.1	${DATE}
--- m/d/bar	${DATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
! bar
--- 1 ----
! foo"

	  dokeep
	  cd ../..
	  rm -rf rdiff2
	  modify_repo rm -rf $CVSROOT_DIRNAME/m
	  ;;



	diff)
	  # Various tests specific to the "cvs diff" command.
	  # Related tests:
	  #   death2: -N
	  #   rcslib: cvs diff and $Name.
	  #   rdiff: cvs rdiff.
	  #   diffmerge*: nuts and bolts (stuff within diff library)
	  mkdir 1; cd 1
	  dotest diff-1 "$testcvs -q co -l ."
	  mkdir first-dir
	  dotest diff-2 "$testcvs add first-dir" \
"Directory $CVSROOT_DIRNAME/first-dir added to the repository"
	  cd first-dir

	  # diff is anomalous.  Most CVS commands print the "nothing
	  # known" message (or worse yet, no message in some cases) but
	  # diff says "I know nothing".  Shrug.
	  dotest_fail diff-3 "${testcvs} diff xyzpdq" \
"${SPROG} diff: I know nothing about xyzpdq"
	  touch abc
	  dotest diff-4 "${testcvs} add abc" \
"${SPROG} add: scheduling file .abc. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest diff-5 "${testcvs} -q ci -mtest" \
"$CVSROOT_DIRNAME/first-dir/abc,v  <--  abc
initial revision: 1\.1"
	  echo "extern int gethostname ();" >abc
	  dotest diff-6 "${testcvs} -q ci -mtest" \
"$CVSROOT_DIRNAME/first-dir/abc,v  <--  abc
new revision: 1\.2; previous revision: 1\.1"
	  echo "#include <winsock.h>" >abc
	  # check the behavior of the --ifdef=MACRO option
	  dotest_fail diff-7 "${testcvs} -q diff --ifdef=HAVE_WINSOCK_H" \
"Index: abc
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
retrieving revision 1\.2
diff --ifdef HAVE_WINSOCK_H -r1\.2 abc
#ifndef HAVE_WINSOCK_H
extern int gethostname ();
#else /\* HAVE_WINSOCK_H \*/
#include <winsock\.h>
#endif /\* HAVE_WINSOCK_H \*/"

	  dokeep
	  cd ../..
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  rm -r 1
	  ;;



	diffnl)
	  # Test handling of 'cvs diff' of files without newlines
	  mkdir 1; cd 1
	  dotest diffnl-000 "${testcvs} -q co -l ." ''
	  mkdir first-dir
	  dotest diffnl-001 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
          cd first-dir

	  ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nfive\nsix")}' </dev/null >abc
	  dotest diffnl-002 "${testcvs} add abc" \
"${SPROG} add: scheduling file .abc. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
          dotest diffnl-003 "${testcvs} -q ci -mtest" \
"$CVSROOT_DIRNAME/first-dir/abc,v  <--  abc
initial revision: 1\.1"

	  # change to line near EOF
	  ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nsix")}' </dev/null >abc
	  dotest_fail diffnl-100 "${testcvs} diff abc" \
"Index: abc
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
retrieving revision 1\.1
diff -r1\.1 abc
5d4
< five"
          dotest_fail diffnl-101 "${testcvs} diff -u abc" \
"Index: abc
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
retrieving revision 1\.1
diff -u -r1\.1 abc
--- abc	${RFCDATE}	1\.1
+++ abc	${RFCDATE}
@@ -2,5 +2,4 @@
 two
 three
 four
-five
 six
\\\\ No newline at end of file"
          dotest diffnl-102 "${testcvs} -q ci -mtest abc" \
"$CVSROOT_DIRNAME/first-dir/abc,v  <--  abc
new revision: 1\.2; previous revision: 1\.1"

          # Change to last line
	  ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nseven")}' </dev/null >abc
          dotest_fail diffnl-200 "${testcvs} diff abc" \
"Index: abc
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
retrieving revision 1\.2
diff -r1\.2 abc
5c5
< six
\\\\ No newline at end of file
---
> seven
\\\\ No newline at end of file"
	  dotest_fail diffnl-201 "${testcvs} diff -u abc" \
"Index: abc
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
retrieving revision 1\.2
diff -u -r1\.2 abc
--- abc	${RFCDATE}	1\.2
+++ abc	${RFCDATE}
@@ -2,4 +2,4 @@
 two
 three
 four
-six
\\\\ No newline at end of file
+seven
\\\\ No newline at end of file"
	  dotest diffnl-202 "${testcvs} ci -mtest abc" \
"${CVSROOT_DIRNAME}/first-dir/abc,v  <--  abc
new revision: 1\.3; previous revision: 1\.2"

	  # Addition of newline
	  echo "one
two
three
four
seven" > abc
	  dotest_fail diffnl-300 "${testcvs} diff abc" \
"Index: abc
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
retrieving revision 1\.3
diff -r1\.3 abc
5c5
< seven
\\\\ No newline at end of file
---
> seven"
	  dotest_fail diffnl-301 "${testcvs} diff -u abc" \
"Index: abc
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
retrieving revision 1\.3
diff -u -r1\.3 abc
--- abc	${RFCDATE}	1\.3
+++ abc	${RFCDATE}
@@ -2,4 +2,4 @@
 two
 three
 four
-seven
\\\\ No newline at end of file
+seven"
	  dotest diffnl-302 "${testcvs} ci -mtest abc" \
"${CVSROOT_DIRNAME}/first-dir/abc,v  <--  abc
new revision: 1\.4; previous revision: 1\.3"

	  # Removal of newline
	  ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nseven")}' </dev/null >abc
	  dotest_fail diffnl-400 "${testcvs} diff abc" \
"Index: abc
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
retrieving revision 1\.4
diff -r1\.4 abc
5c5
< seven
---
> seven
\\\\ No newline at end of file"
	  dotest_fail diffnl-401 "${testcvs} diff -u abc" \
"Index: abc
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
retrieving revision 1\.4
diff -u -r1\.4 abc
--- abc	${RFCDATE}	1\.4
+++ abc	${RFCDATE}
@@ -2,4 +2,4 @@
 two
 three
 four
-seven
+seven
\\\\ No newline at end of file"

	  dokeep
	  cd ../..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	death)
		# next dive.  test death support.

		# NOTE: this section has reached the size and
		# complexity where it is getting to be a good idea to
		# add new death support tests to a new section rather
		# than continuing to piggyback them onto the tests here.

		modify_repo mkdir $CVSROOT_DIRNAME/first-dir
		dotest death-init-1 "$testcvs -Q co first-dir"

		cd first-dir

		# Create a directory with only dead files, to make sure CVS
		# doesn't get confused by it.
		mkdir subdir
		dotest 65a0 "${testcvs} add subdir" \
"Directory ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository"
		cd subdir
		echo file in subdir >sfile
		dotest 65a1 "${testcvs} add sfile" \
"${SPROG}"' add: scheduling file `sfile'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
		dotest 65a2 "${testcvs} -q ci -m add-it" \
"$CVSROOT_DIRNAME/first-dir/subdir/sfile,v  <--  sfile
initial revision: 1\.1"
		rm sfile
		dotest 65a3 "${testcvs} rm sfile" \
"${SPROG}"' remove: scheduling `sfile'\'' for removal
'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove this file permanently'
		dotest 65a4 "${testcvs} -q ci -m remove-it" \
"$CVSROOT_DIRNAME/first-dir/subdir/sfile,v  <--  sfile
new revision: delete; previous revision: 1\.1"
		cd ..
		dotest 65a5 "${testcvs} -q update -P" ''
		dotest_fail 65a6 "test -d subdir" ''

		# add a file.
		touch file1
		if ${CVS} add file1  2>> ${LOGFILE}; then
		    pass 66
		else
		    fail 66
		fi

		# commit
		if ${CVS} ci -m test  >> ${LOGFILE} 2>&1; then
		    pass 67
		else
		    fail 67
		fi

		# remove
		rm file1
		if ${CVS} rm file1  2>> ${LOGFILE}; then
		    pass 68
		else
		    fail 68
		fi

		# commit
		if ${CVS} ci -m test  >>${LOGFILE} ; then
		    pass 69
		else
		    fail 69
		fi

		dotest_fail 69a0 "test -f file1" ''
		# get the old contents of file1 back
		if ${testcvs} update -p -r 1.1 file1 >file1 2>>${LOGFILE}; then
		  pass 69a1
		else
		  fail 69a1
		fi
		dotest 69a2 "cat file1" ''

		# create second file
		touch file2
		if ${CVS} add file1 file2  2>> ${LOGFILE}; then
		    pass 70
		else
		    fail 70
		fi

		# commit
		if ${CVS} ci -m test  >> ${LOGFILE} 2>&1; then
		    pass 71
		else
		    fail 71
		fi

		# log
		if ${CVS} log file1  >> ${LOGFILE}; then
		    pass 72
		else
		    fail 72
		fi

		# file4 will be dead at the time of branching and stay dead.
		echo file4 > file4
		dotest death-file4-add "${testcvs} add file4" \
"${SPROG}"' add: scheduling file `file4'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
		dotest death-file4-ciadd "${testcvs} -q ci -m add file4" \
"$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
initial revision: 1\.1"
		rm file4
		dotest death-file4-rm "${testcvs} remove file4" \
"${SPROG}"' remove: scheduling `file4'\'' for removal
'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove this file permanently'
		dotest death-file4-cirm "${testcvs} -q ci -m remove file4" \
"$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: delete; previous revision: 1\.1"

		# Tag the branchpoint.
		dotest death-72a "${testcvs} -q tag bp_branch1" 'T file1
T file2'

		# branch1
		if ${CVS} tag -b branch1  ; then
		    pass 73
		else
		    fail 73
		fi

		# and move to the branch.
		if ${CVS} update -r branch1  ; then
		    pass 74
		else
		    fail 74
		fi

		dotest_fail death-file4-3 "test -f file4" ''

		# add a file in the branch
		echo line1 from branch1 >> file3
		if ${CVS} add file3  2>> ${LOGFILE}; then
		    pass 75
		else
		    fail 75
		fi

		# commit
		if ${CVS} ci -m test  >> ${LOGFILE} 2>&1; then
		    pass 76
		else
		    fail 76
		fi

		dotest death-76a0 \
"${testcvs} -q rdiff -r bp_branch1 -r branch1 first-dir" \
"Index: first-dir/file3
diff -c /dev/null first-dir/file3:1\.1\.2\.1
\*\*\* /dev/null	${DATE}
--- first-dir/file3	${DATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 0 \*\*\*\*
--- 1 ----
${PLUS} line1 from branch1"
		dotest death-76a1 \
"${testcvs} -q rdiff -r branch1 -r bp_branch1 first-dir" \
"Index: first-dir/file3
diff -c first-dir/file3:1\.1\.2\.1 first-dir/file3:removed
\*\*\* first-dir/file3:1\.1\.2\.1	${DATE}
--- first-dir/file3	${DATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
- line1 from branch1
--- 0 ----"

		# remove
		rm file3
		if ${CVS} rm file3  2>> ${LOGFILE}; then
		    pass 77
		else
		    fail 77
		fi

		# commit
		if ${CVS} ci -m test  >>${LOGFILE} ; then
		    pass 78
		else
		    fail 78
		fi

		# add again
		echo line1 from branch1 >> file3
		if ${CVS} add file3  2>> ${LOGFILE}; then
		    pass 79
		else
		    fail 79
		fi

		# commit
		if ${CVS} ci -m test  >> ${LOGFILE} 2>&1; then
		    pass 80
		else
		    fail 80
		fi

		# change the first file
		echo line2 from branch1 >> file1

		# commit
		if ${CVS} ci -m test  >> ${LOGFILE} 2>&1; then
		    pass 81
		else
		    fail 81
		fi

		# remove the second
		rm file2
		if ${CVS} rm file2  2>> ${LOGFILE}; then
		    pass 82
		else
		    fail 82
		fi

		# commit
		if ${CVS} ci -m test  >>${LOGFILE}; then
		    pass 83
		else
		    fail 83
		fi

		# back to the trunk.
		if ${CVS} update -A  2>> ${LOGFILE}; then
		    pass 84
		else
		    fail 84
		fi

		dotest_fail death-file4-4 "test -f file4" ''

		if test -f file3 ; then
		    fail 85
		else
		    pass 85
		fi

		# join
		dotest death-86 "$testcvs -q update -j branch1" \
"RCS file: $CVSROOT_DIRNAME/first-dir/file1,v
retrieving revision 1\.3
retrieving revision 1\.3\.2\.1
Merging differences between 1\.3 and 1\.3\.2\.1 into file1
${SPROG} update: scheduling \`file2' for removal
U file3"

		dotest_fail death-file4-5 "test -f file4" ''

		if test -f file3 ; then
		    pass 87
		else
		    fail 87
		fi

		# Make sure that we joined the correct change to file1
		if echo line2 from branch1 | cmp - file1 >/dev/null; then
		    pass 87a
		else
		    fail 87a
		fi

		# update
		if ${CVS} update  ; then
		    pass 88
		else
		    fail 88
		fi

		# commit
		dotest 89 "${testcvs} -q ci -m test" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.4; previous revision: 1\.3
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
new revision: delete; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file3,v  <--  file3
new revision: 1\.2; previous revision: 1\.1"
		cd ..
		mkdir 2
		cd 2
		dotest 89a "${testcvs} -q co first-dir" 'U first-dir/file1
U first-dir/file3'
		cd ..
		rm -r 2
		cd first-dir

		# remove first file.
		rm file1
		if ${CVS} rm file1  2>> ${LOGFILE}; then
		    pass 90
		else
		    fail 90
		fi

		# commit
		if ${CVS} ci -m test  >>${LOGFILE}; then
		    pass 91
		else
		    fail 91
		fi

		if test -f file1 ; then
		    fail 92
		else
		    pass 92
		fi

		# typo; try to get to the branch and fail
		dotest_fail 92.1a "$testcvs update -r brnach1" \
		  "$SPROG \[update aborted\]: no such tag \`brnach1'"
		# Make sure we are still on the trunk
		if test -f file1 ; then
		    fail 92.1b
		else
		    pass 92.1b
		fi
		if test -f file3 ; then
		    pass 92.1c
		else
		    fail 92.1c
		fi

		# back to branch1
		if ${CVS} update -r branch1  2>> ${LOGFILE}; then
		    pass 93
		else
		    fail 93
		fi

		dotest_fail death-file4-6 "test -f file4" ''

		if test -f file1 ; then
		    pass 94
		else
		    fail 94
		fi

		# and join
		dotest 95 "${testcvs} -q update -j HEAD" \
"${SPROG}"' update: file file1 has been modified, but has been removed in revision HEAD
'"${SPROG}"' update: file file3 exists, but has been added in revision HEAD'

		dotest_fail death-file4-7 "test -f file4" ''

		# file2 should not have been recreated.  It was
		# deleted on the branch, and has not been modified on
		# the trunk.  That means that there have been no
		# changes between the greatest common ancestor (the
		# trunk version) and HEAD.
		dotest_fail death-file2-1 "test -f file2" ''

		dokeep
		cd ..
		rm -r first-dir
		modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
		;;



	death2)
	  # More tests of death support.
	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  dotest death2-1 "$testcvs -q co first-dir"

	  cd first-dir

	  # Add two files on the trunk.
	  echo "first revision" > file1
	  echo "file4 first revision" > file4
	  dotest death2-2 "${testcvs} add file1 file4" \
"${SPROG}"' add: scheduling file `file1'\'' for addition
'"${SPROG}"' add: scheduling file `file4'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'

	  dotest death2-3 "${testcvs} -q commit -m add" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
initial revision: 1\.1"

	  # Make a branch and a non-branch tag.
	  dotest death2-4 "${testcvs} -q tag -b branch" \
'T file1
T file4'
	  dotest death2-5 "${testcvs} -q tag tag" \
'T file1
T file4'

	  # Switch over to the branch.
	  dotest death2-6 "${testcvs} -q update -r branch" ''

	  # Delete the file on the branch.
	  rm file1
	  dotest death2-7 "${testcvs} rm file1" \
"${SPROG} remove: scheduling .file1. for removal
${SPROG} remove: use .${SPROG} commit. to remove this file permanently"

	  # Test diff of the removed file before it is committed.
	  dotest_fail death2-diff-1 "${testcvs} -q diff file1" \
"${SPROG} diff: file1 was removed, no comparison available"

	  dotest_fail death2-diff-2 "${testcvs} -q diff -N -c file1" \
"Index: file1
===================================================================
RCS file: file1
diff -N file1
\*\*\* file1	${RFCDATE}	[0-9.]*
--- /dev/null	${RFCDATE_EPOCH}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
- first revision
--- 0 ----"

	  dotest death2-8 "${testcvs} -q ci -m removed" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: delete; previous revision: 1\.1"

	  # Test diff of a dead file.
	  dotest_fail death2-diff-3 \
"${testcvs} -q diff -r1.1 -rbranch -c file1" \
"${SPROG} diff: Tag branch refers to a dead (removed) revision in file .file1.\.
${SPROG} diff: No comparison available\.  Pass .-N. to .${SPROG} diff.${QUESTION}"
	  # and in reverse
	  dotest_fail death2-diff-3a \
"${testcvs} -q diff -rbranch -r1.1 -c file1" \
"${SPROG} diff: Tag branch refers to a dead (removed) revision in file .file1.\.
${SPROG} diff: No comparison available\.  Pass .-N. to .${SPROG} diff.${QUESTION}"

	  dotest_fail death2-diff-4 \
"${testcvs} -q diff -r1.1 -rbranch -N -c file1" \
"Index: file1
===================================================================
RCS file: file1
diff -N file1
\*\*\* file1	${RFCDATE}	[0-9.]*
--- /dev/null	${RFCDATE_EPOCH}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
- first revision
--- 0 ----"
	  # and in reverse
	  dotest_fail death2-diff-4a \
"${testcvs} -q diff -rbranch -r1.1 -N -c file1" \
"Index: file1
===================================================================
RCS file: file1
diff -N file1
\*\*\* /dev/null	${RFCDATE_EPOCH}
--- file1	${RFCDATE}	[0-9.]*
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 0 \*\*\*\*
--- 1 ----
+ first revision"


	  dotest_fail death2-diff-5 "${testcvs} -q diff -rtag -c ." \
"${SPROG} diff: file1 no longer exists, no comparison available"

	  dotest_fail death2-diff-6 "${testcvs} -q diff -rtag -N -c ." \
"Index: file1
===================================================================
RCS file: file1
diff -N file1
\*\*\* file1	[-a-zA-Z0-9: ]*	[0-9.]*
--- /dev/null	${RFCDATE_EPOCH}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
- first revision
--- 0 ----"

	  # Test rdiff of a dead file.
	  dotest death2-rdiff-1 \
"${testcvs} -q rtag -rbranch rdiff-tag first-dir" ''

	  dotest death2-rdiff-2 "${testcvs} -q rdiff -rtag -rbranch first-dir" \
"Index: first-dir/file1
diff -c first-dir/file1:1\.1 first-dir/file1:removed
\*\*\* first-dir/file1:1\.1	[a-zA-Z0-9: ]*
--- first-dir/file1	[a-zA-Z0-9: ]*
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
- first revision
--- 0 ----"

	  # Readd the file to the branch.
	  echo "second revision" > file1
	  dotest death2-9 "${testcvs} add file1" \
"${SPROG} add: Re-adding file \`file1' on branch \`branch' after dead revision 1\.1\.2\.1\.
${SPROG} add: use \`${SPROG} commit' to add this file permanently"

	  # Test diff of the added file before it is committed.
	  dotest_fail death2-diff-7 "${testcvs} -q diff file1" \
"${SPROG} diff: file1 is a new entry, no comparison available"

	  dotest_fail death2-diff-8 "${testcvs} -q diff -N -c file1" \
"Index: file1
===================================================================
RCS file: file1
diff -N file1
\*\*\* /dev/null	${RFCDATE_EPOCH}
--- file1	${RFCDATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 0 \*\*\*\*
--- 1 ----
${PLUS} second revision"

	  dotest death2-10 "${testcvs} -q commit -m add" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"

	  # Delete file4 from the branch
	  dotest death2-10a "${testcvs} rm -f file4" \
"${SPROG} remove: scheduling .file4. for removal
${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
	  dotest death2-10b "${testcvs} -q ci -m removed" \
"$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: delete; previous revision: 1\.1"

	  # Back to the trunk.
	  dotest death2-11 "${testcvs} -q update -A" \
"[UP] file1
U file4"

	  # Add another file on the trunk.
	  echo "first revision" > file2
	  dotest death2-12 "${testcvs} add file2" \
"${SPROG}"' add: scheduling file `file2'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
	  dotest death2-13 "${testcvs} -q commit -m add" \
"$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
initial revision: 1\.1"

	  # Modify file4 on the trunk.
	  echo "new file4 revision" > file4
	  dotest death2-13a "${testcvs} -q commit -m mod" \
"$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: 1\.2; previous revision: 1\.1"

	  # Back to the branch.
	  # The ``no longer in the repository'' message doesn't really
	  # look right to me, but that's what CVS currently prints for
	  # this case.
	  dotest death2-14 "${testcvs} -q update -r branch" \
"[UP] file1
${SPROG} update: \`file2' is no longer in the repository
${SPROG} update: \`file4' is no longer in the repository"

	  # Add a file on the branch with the same name.
	  echo "branch revision" > file2
	  dotest death2-15 "${testcvs} add file2" \
"${SPROG}"' add: scheduling file `file2'\'' for addition on branch `branch'\''
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
	  dotest death2-16 "${testcvs} -q commit -m add" \
"$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"

	  # Add a new file on the branch.
	  echo "first revision" > file3
	  dotest death2-17 "${testcvs} add file3" \
"${SPROG}"' add: scheduling file `file3'\'' for addition on branch `branch'\''
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
	  dotest death2-18 "${testcvs} -q commit -m add" \
"$CVSROOT_DIRNAME/first-dir/Attic/file3,v  <--  file3
new revision: 1\.1\.2\.1; previous revision: 1\.1"

	  # Test diff of a nonexistent tag
	  dotest_fail death2-diff-9 "$testcvs -q diff -rtag -c file3" \
"$SPROG diff: tag tag is not in file file3"

	  dotest_fail death2-diff-10 "${testcvs} -q diff -rtag -N -c file3" \
"Index: file3
===================================================================
RCS file: file3
diff -N file3
\*\*\* /dev/null	${RFCDATE_EPOCH}
--- file3	${RFCDATE}	[0-9.]*
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 0 \*\*\*\*
--- 1 ----
${PLUS} first revision"

	  dotest_fail death2-diff-11 "${testcvs} -q diff -rtag -c ." \
"Index: file1
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
retrieving revision 1\.1
retrieving revision 1\.1\.2\.2
diff -c -r1\.1 -r1\.1\.2\.2
\*\*\* file1	${RFCDATE}	[0-9.]*
--- file1	${RFCDATE}	[0-9.]*
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
! first revision
--- 1 ----
! second revision
${SPROG} diff: tag tag is not in file file2
${SPROG} diff: tag tag is not in file file3
${SPROG} diff: file4 no longer exists, no comparison available"

	  dotest_fail death2-diff-12 "${testcvs} -q diff -rtag -c -N ." \
"Index: file1
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
retrieving revision 1\.1
retrieving revision 1\.1\.2\.2
diff -c -r1\.1 -r1\.1\.2\.2
\*\*\* file1	${RFCDATE}	[0-9.]*
--- file1	${RFCDATE}	[0-9.]*
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
! first revision
--- 1 ----
! second revision
Index: file2
===================================================================
RCS file: file2
diff -N file2
\*\*\* /dev/null	${RFCDATE_EPOCH}
--- file2	${RFCDATE}	[0-9.]*
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 0 \*\*\*\*
--- 1 ----
${PLUS} branch revision
Index: file3
===================================================================
RCS file: file3
diff -N file3
\*\*\* /dev/null	${RFCDATE_EPOCH}
--- file3	${RFCDATE}	[0-9.]*
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 0 \*\*\*\*
--- 1 ----
${PLUS} first revision
Index: file4
===================================================================
RCS file: file4
diff -N file4
\*\*\* file4	${RFCDATE}	[0-9.]*
--- /dev/null	${RFCDATE_EPOCH}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
- file4 first revision
--- 0 ----"

	  # Switch to the nonbranch tag.
	  dotest death2-19 "${testcvs} -q update -r tag" \
"[UP] file1
${SPROG} update: \`file2' is no longer in the repository
${SPROG} update: \`file3' is no longer in the repository
U file4"

	  dotest_fail death2-20 "test -f file2"

	  # Make sure diff only reports appropriate files.
	  dotest_fail death2-diff-13 "${testcvs} -q diff -r rdiff-tag" \
"${SPROG} diff: Tag rdiff-tag refers to a dead (removed) revision in file .file1.\.
${SPROG} diff: No comparison available\.  Pass .-N. to .${SPROG} diff.${QUESTION}"

	  dotest_fail death2-diff-14 "${testcvs} -q diff -r rdiff-tag -c -N" \
"Index: file1
===================================================================
RCS file: file1
diff -N file1
\*\*\* /dev/null	${RFCDATE_EPOCH}
--- file1	${RFCDATE}	[0-9.]*
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 0 \*\*\*\*
--- 1 ----
${PLUS} first revision"

	  # now back to the trunk
	  dotest death2-21 "${testcvs} -q update -A" \
"U file2
[UP] file4"

	  # test merging with a dead file
	  dotest death2-22 "${testcvs} -q co first-dir" \
"U first-dir/file1
U first-dir/file2
U first-dir/file4"

	  cd first-dir
	  dotest death2-23 "${testcvs} rm -f file4" \
"${SPROG} remove: scheduling .file4. for removal
${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
	  dotest death2-24 "${testcvs} -q ci -m removed file4" \
"$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: delete; previous revision: 1\.2"
	  cd ..
	  echo "new stuff" >file4
	  dotest_fail death2-25 "${testcvs} up file4" \
"${SPROG} update: conflict: \`file4' is modified but no longer in the repository
C file4"

	  dokeep
	  cd ..
	  rm -r first-dir
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	rm-update-message)
	  # FIXME
	  # local CVS prints a warning message when update notices a missing
	  # file and client/server CVS doesn't.  These should be identical.
	  mkdir rm-update-message; cd rm-update-message
	  modify_repo mkdir $CVSROOT_DIRNAME/rm-update-message
	  dotest rm-update-message-setup-1 "$testcvs -q co rm-update-message" ''
	  cd rm-update-message
	  file=x
	  echo >$file
	  dotest rm-update-message-setup-2 "$testcvs -q add $file" \
"${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest rm-update-message-setup-3 "$testcvs -q ci -mcreate $file" \
"$CVSROOT_DIRNAME/rm-update-message/$file,v  <--  $file
initial revision: 1\.1"

	  rm $file
	  dotest rm-update-message-1 "$testcvs up $file" \
"${SPROG} update: warning: \`$file' was lost
U $file"

	  dokeep
	  cd ../..
	  rm -r rm-update-message
	  modify_repo rm -rf $CVSROOT_DIRNAME/rm-update-message
	  ;;



	rmadd)
	  # More tests of adding and removing files.
	  # In particular ci -r.
	  # Other ci -r tests:
	  #   * editor-9: checking in a modified file,
	  #     where "ci -r" means a branch.
	  #   * basica-8a1: checking in a modified file with numeric revision.
	  #   * basica-8a2: likewise.
	  #   * keywordlog-4: adding a new file with numeric revision.
	  mkdir 1; cd 1
	  dotest rmadd-1 "$testcvs -q co -l ."
	  mkdir first-dir
	  dotest rmadd-2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
	  cd first-dir
	  echo first file1 >file1
	  dotest rmadd-3 "${testcvs} add file1" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"

	  dotest_fail rmadd-4 "${testcvs} -q ci -r 1.2.2.4 -m add" \
"${SPROG} commit: cannot add file .file1' with revision .1\.2\.2\.4'; must be on trunk
${SPROG} \[commit aborted\]: correct above errors first!"
	  dotest_fail rmadd-5 "${testcvs} -q ci -r 1.2.2 -m add" \
"${SPROG} commit: cannot add file .file1' with revision .1\.2\.2'; must be on trunk
${SPROG} \[commit aborted\]: correct above errors first!"
	  dotest_fail rmadd-6 "$testcvs -q ci -r mybranch -m add" \
"$SPROG \[commit aborted\]: no such tag \`mybranch'"

	  # The thing with the trailing periods strikes me as a very
	  # bizarre behavior, but it would seem to be intentional
	  # (see commit.c).  It probably could go away....
	  dotest rmadd-7 "${testcvs} -q ci -r 7.... -m add" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 7\.1"
	  if $remote; then
	    # I guess remote doesn't set a sticky tag in this case.
	    # Kind of odd, in the sense that rmadd-24a does set one
	    # both local and remote.
	    dotest_fail rmadd-7a "test -f CVS/Tag"
	    echo T7 >CVS/Tag
	  else
	    dotest rmadd-7a "cat CVS/Tag" "T7"
	  fi

	  dotest rmadd-8 "${testcvs} -q tag -b mybranch" "T file1"
	  dotest rmadd-9 "${testcvs} -q tag mynonbranch" "T file1"

	  touch file2
	  # The previous "cvs ci -r" set a sticky tag of '7'.  Seems a
	  # bit odd, and I guess commit.c (findmaxrev) makes '7' sticky
	  # tags unnecessary (?).  I kind of suspect that it should be
	  # saying "sticky tag is not a branch" like keywordlog-4b.
	  # Or something.
	  dotest rmadd-10 "${testcvs} add file2" \
"${SPROG} add: scheduling file .file2. for addition on branch .7'
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  # As in the previous example, CVS is confused....
	  dotest rmadd-11 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
initial revision: 7\.1"

	  dotest rmadd-12 "${testcvs} -q update -A" ""
	  touch file3
	  dotest rmadd-13 "${testcvs} add file3" \
"${SPROG} add: scheduling file .file3. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  # Huh?  file2 is not up to date?  Seems buggy to me....
	  dotest_fail rmadd-14 "${testcvs} -q ci -r mybranch -m add" \
"${SPROG} commit: Up-to-date check failed for .file2'
${SPROG} \[commit aborted\]: correct above errors first!"
	  # Whatever, let's not let file2 distract us....
	  dotest rmadd-15 "${testcvs} -q ci -r mybranch -m add file3" \
"$CVSROOT_DIRNAME/first-dir/Attic/file3,v  <--  file3
new revision: 1\.1\.2\.1; previous revision: 1\.1"

	  touch file4
	  dotest rmadd-16 "${testcvs} add file4" \
"${SPROG} add: scheduling file .file4. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  # Prior to CVS 1.12.10, this would fail with a, "no such tag" message
	  # since val-tags used to be updated the first time the tag was used
	  # rather than when it was created.

	  # Try to make CVS write val-tags.
	  if $proxy; then :; else
	    # First remove the tag.
	    grep -v mynonbranch $CVSROOT_DIRNAME/CVSROOT/val-tags \
	         >$CVSROOT_DIRNAME/CVSROOT/val-tags-tmp
	    mv $CVSROOT_DIRNAME/CVSROOT/val-tags-tmp \
	       $CVSROOT_DIRNAME/CVSROOT/val-tags

	    dotest rmadd-18 "$testcvs -q update -p -r mynonbranch file1" \
"first file1"
	    # Oops, -p suppresses writing val-tags (probably a questionable
	    # behavior).
	    dotest_fail rmadd-19 \
"$testcvs -q ci -r mynonbranch -m add file4" \
"$SPROG \[commit aborted\]: no such tag \`mynonbranch'"
	    # Now make CVS write val-tags for real.
	    dotest rmadd-20 "$testcvs -q update -r mynonbranch file1"
	  fi # !$proxy

	  # Oops - CVS isn't distinguishing between a branch tag and
	  # a non-branch tag.
	  dotest rmadd-21 \
"${testcvs} -q ci -r mynonbranch -m add file4" \
"$CVSROOT_DIRNAME/first-dir/Attic/file4,v  <--  file4
new revision: 1\.1\.2\.1; previous revision: 1\.1"

	  # OK, we add this one in a vanilla way, but then check in
	  # a modification with ci -r and sniff around for sticky tags.
	  echo file5 >file5
	  dotest rmadd-22 "${testcvs} add file5" \
"${SPROG} add: scheduling file .file5. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  if $remote; then
	    # Interesting bug (or missing feature) here.  findmaxrev
	    # gets the major revision from the Entries.  Well, remote
	    # doesn't send the entries for files which are not involved.
	    dotest rmadd-23r "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/file5,v  <--  file5
initial revision: 1\.1"
	    dotest rmadd-23-workaroundr \
"${testcvs} -q ci -r 7 -m bump-it file5" \
"$CVSROOT_DIRNAME/first-dir/file5,v  <--  file5
new revision: 7\.1; previous revision: 1\.1"
	  else
	    dotest rmadd-23 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/file5,v  <--  file5
initial revision: 7\.1"
	  fi
	  echo change it >file5
	  dotest_fail rmadd-24 "$testcvs -q ci -r 4.8 -m change file5" \
"$CVSROOT_DIRNAME/first-dir/file5,v  <--  file5
$SPROG commit: $CVSROOT_DIRNAME/first-dir/file5,v: revision 4\.8 too low; must be higher than 7\.1
$SPROG commit: could not check in file5"
	  dotest rmadd-24a "${testcvs} -q ci -r 8.4 -m change file5" \
"$CVSROOT_DIRNAME/first-dir/file5,v  <--  file5
new revision: 8\.4; previous revision: 7\.1"
	  # I'm not really sure that a sticky tag make sense here.
	  # It seems to be longstanding behavior for what that is worth.
	  dotest rmadd-25 "${testcvs} status file5" \
"===================================================================
File: file5            	Status: Up-to-date

   Working revision:	8\.4.*
   Repository revision:	8\.4	${CVSROOT_DIRNAME}/first-dir/file5,v
   Commit Identifier:	${commitid}
   Sticky Tag:		8\.4
   Sticky Date:		(none)
   Sticky Options:	(none)"

	  # now try forced revision with recursion
	  mkdir sub
	  dotest rmadd-26 "${testcvs} -q add sub" \
"Directory ${CVSROOT_DIRNAME}/first-dir/sub added to the repository"
	  echo hello >sub/subfile
	  dotest rmadd-27 "${testcvs} -q add sub/subfile" \
"${SPROG} add: use .${SPROG} commit. to add this file permanently"

	  dotest rmadd-28 "${testcvs} -q ci -m. sub" \
"$CVSROOT_DIRNAME/first-dir/sub/subfile,v  <--  sub/subfile
initial revision: 1\.1"

	  # lose the branch
	  dotest rmadd-29 "${testcvs} -q up -A" \
"${SPROG} update: \`file3' is no longer in the repository
${SPROG} update: \`file4' is no longer in the repository"

	  # -f disables recursion
	  dotest rmadd-30 "${testcvs} -q ci -f -r9 -m." \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 9\.1; previous revision: 7\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
new revision: 9\.1; previous revision: 7\.1
$CVSROOT_DIRNAME/first-dir/file5,v  <--  file5
new revision: 9\.1; previous revision: 8\.4"

	  # add -R to force recursion
	  dotest rmadd-31 "${testcvs} -q ci -f -r9 -R -m." \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 9\.2; previous revision: 9\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
new revision: 9\.2; previous revision: 9\.1
$CVSROOT_DIRNAME/first-dir/file5,v  <--  file5
new revision: 9\.2; previous revision: 9\.1
$CVSROOT_DIRNAME/first-dir/sub/subfile,v  <--  sub/subfile
new revision: 9\.1; previous revision: 1\.1"

	  if $remote; then
	    # as noted above, remote doesn't set a sticky tag
	    :
	  else
	    dotest rmadd-32 "cat CVS/Tag" "T9"
	    dotest rmadd-33 "cat sub/CVS/Tag" "T9"
	  fi

	  dokeep
	  cd ../..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	rmadd2)
	  # Tests of undoing commits, including in the presence of
	  # adding and removing files.  See join for a list of -j tests.
	  mkdir 1; cd 1
	  dotest rmadd2-1 "${testcvs} -q co -l ." ''
	  mkdir first-dir
	  dotest rmadd2-2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
	  cd first-dir
	  echo 'initial contents' >file1
	  dotest rmadd2-3 "${testcvs} add file1" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest rmadd2-4 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1"
	  dotest rmadd2-4a "${testcvs} -Q tag tagone" ""
	  dotest rmadd2-5 "${testcvs} rm -f file1" \
"${SPROG} remove: scheduling .file1. for removal
${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
	  dotest rmadd2-6 "${testcvs} -q ci -m remove" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: delete; previous revision: 1\.1"
	  dotest rmadd2-7 "$testcvs -q update -j 1.2 -j 1.1 file1" "U file1"
	  dotest rmadd2-8 "${testcvs} -q ci -m readd" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.3; previous revision: 1\.2"
	  echo 'new contents' >file1
	  dotest rmadd2-9 "${testcvs} -q ci -m modify" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.4; previous revision: 1\.3"
	  dotest rmadd2-10 "${testcvs} -q update -j 1.4 -j 1.3 file1" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
retrieving revision 1\.4
retrieving revision 1\.3
Merging differences between 1\.4 and 1\.3 into file1"
	  dotest rmadd2-11 "${testcvs} -q ci -m undo" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.5; previous revision: 1\.4"
	  dotest rmadd2-12 "cat file1" "initial contents"
	  dotest rmadd2-13 "${testcvs} -q update -p -r 1.3" "initial contents"

	  # Hmm, might be a bit odd that this works even if 1.3 is not
	  # the head.
	  dotest rmadd2-14 "${testcvs} -q update -j 1.3 -j 1.2 file1" \
"${SPROG} update: scheduling \`file1' for removal"

	  # Check that -p can get arbitrary revisions of a removed file
	  dotest rmadd2-14a "${testcvs} -q update -p" "initial contents"
	  dotest rmadd2-14b "${testcvs} -q update -p -r 1.5" "initial contents"
	  dotest rmadd2-14c "${testcvs} -q update -p -r 1.3" "initial contents"

	  dotest rmadd2-15 "${testcvs} -q ci -m re-remove" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: delete; previous revision: 1\.5"
	  dotest rmadd2-16 "${testcvs} log -h file1" "
RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
Working file: file1
head: 1\.6
branch:
locks: strict
access list:
symbolic names:
	tagone: 1\.1
keyword substitution: kv
total revisions: 6
============================================================================="
	  dotest rmadd2-17 "${testcvs} status -v file1" \
"===================================================================
File: no file file1		Status: Up-to-date

   Working revision:	No entry for file1
   Repository revision:	1\.6	${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
   Commit Identifier:	${commitid}

   Existing Tags:
	tagone                   	(revision: 1.1)"

	  dokeep
	  cd ../..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	rmadd3)
          # This test demonstrates that CVS notices that file1 exists rather
	  # that deleting or writing over it after:
	  #
	  #   cvs remove -f file1; touch file1; cvs add file1.
	  #
          # According to the manual, this should work for:
	  #
	  #   rm file1; cvs remove file1; cvs add file1
	  #
	  # but in past version of CVS, new content in file1 would be
	  # erroneously deleted when file1 reappeared between the remove and
	  # the add.
	  #
	  # Later versions of CVS would refuse to perform the add, but still
	  # allow a subsequent local commit to erase the file from the
	  # workspace, possibly losing data.
	  mkdir 1; cd 1
	  dotest rmadd3-init1 "${testcvs} -q co -l ." ''
	  mkdir first-dir
	  dotest rmadd3-init2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
	  cd first-dir

	  echo initial content for file1 >file1
	  dotest rmadd3-init3 "${testcvs} add file1" \
"${SPROG} add: scheduling file \`file1' for addition
${SPROG} add: use \`${SPROG} commit' to add this file permanently"
	  dotest rmadd3-init4 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1"

	  # Here begins the guts of this test, as detailed above.
	  dotest rmadd3-1 "${testcvs} rm -f file1" \
"${SPROG} remove: scheduling \`file1' for removal
${SPROG} remove: use \`${SPROG} commit' to remove this file permanently"

          # Now recreate the file:
	  echo desired future contents for file1 >file1

	  # And attempt to resurrect it at the same time:
	  dotest_fail rmadd3-2 "${testcvs} add file1" \
"${SPROG} add: \`file1' should be removed and is still there (or is back again)"

	  # Now prove that commit knows that it shouldn't erase files.
	  dotest_fail rmadd3-3 "${testcvs} -q ci -m." \
"$CPROG commit: \`file1' should be removed and is still there (or is back again)
$CPROG \[commit aborted\]: correct above errors first!"

	  # Then these should pass too:
	  dotest rmadd3-4 "test -f file1"
	  dotest rmadd3-5 "cat file1" "desired future contents for file1"

	  if $keep; then
	    echo Keeping ${TESTDIR} and exiting due to --keep
	    exit 0
	  fi

	  dokeep
	  cd ../..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	resurrection)
	  # This test tests a few file resurrection scenarios.
	  mkdir 1; cd 1
	  dotest resurrection-init1 "$testcvs -q co -l ." ''
	  mkdir first-dir
	  dotest resurrection-init2 "$testcvs add first-dir" \
"Directory $CVSROOT_DIRNAME/first-dir added to the repository"
	  cd first-dir

	  echo initial content for file1 >file1
	  dotest resurrection-init3 "$testcvs add file1" \
"$SPROG add: scheduling file \`file1' for addition
$SPROG add: use \`$SPROG commit' to add this file permanently"
	  dotest resurrection-init4 "$testcvs -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1"

	  dotest resurrection-init5 "$testcvs -Q rm -f file1"

	  # The first test is that `cvs add' will resurrect a file before its
	  # removal has been committed.
	  dotest_sort resurrection-1 "$testcvs add file1" \
"U file1
$SPROG add: \`file1', version 1\.1, resurrected"
	  dotest resurrection-2 "$testcvs -Q diff file1" ""

	  dotest resurrection-init6 "$testcvs -Q tag -b resurrection"
	  dotest resurrection-init7 "$testcvs -Q rm -f file1"
	  dotest resurrection-init8 "$testcvs -Q ci -mrm"

	  # The next test is that CVS will resurrect a committed removal.
	  dotest_sort resurrection-3 "$testcvs add file1" \
"U file1
$SPROG add: Re-adding file \`file1' after dead revision 1\.2\.
$SPROG add: Resurrecting file \`file1' from revision 1\.1\.
$SPROG add: use \`$SPROG commit' to add this file permanently"
	  dotest resurrection-4 "$testcvs -q diff -r1.1 file1" ""
	  dotest resurrection-5 "$testcvs -q ci -mreadd" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.3; previous revision: 1\.2"

	  dotest resurrection-init9 "$testcvs -Q up -rresurrection"
	  dotest resurrection-init10 "$testcvs -Q rm -f file1"
	  dotest resurrection-init11 "$testcvs -Q ci -mrm-on-resurrection"

	  # The next test is that CVS will resurrect a committed removal to a
	  # branch.
	  dotest_sort resurrection-6 "$testcvs -r add file1" \
"U file1
$SPROG add: Re-adding file \`file1' on branch \`resurrection' after dead revision 1\.1\.2\.1\.
$SPROG add: Resurrecting file \`file1' from revision 1\.1\.
$SPROG add: use \`$SPROG commit' to add this file permanently"
	  # If the file is modified, it had better be read-write
	  # regardless of what the user has requested with the CVSREAD
	  # environment variable or the global -r switch
          dotest resurrection-6b 'test -w file1' ''
	  dotest resurrection-7 "$testcvs -Q diff -r1.1 file1" ""
	  dotest resurrection-8 "$testcvs -q ci -mreadd" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"

	  # The next few tests verify that an attempted resurrection of a file
	  # with no previous revision on the trunk fails.
	  touch file2
	  dotest resurrection-9 "$testcvs -Q add file2"
	  dotest resurrection-10 "$testcvs -Q ci -mnew-file2"
	  dotest resurrection-11 "$testcvs -Q up -A"

	  # This command once caused an assertion failure.
	  dotest resurrection-12 "$testcvs add file2" \
"$SPROG add: File \`file2' has no previous revision to resurrect\."

	  # Check what 'cvs -r add' does with resurrected files.
	  dotest resurrection-13 "$testcvs -Q rm -f file1"
	  dotest_sort resurrection-14 "$testcvs -r add file1" \
"U file1
$SPROG add: \`file1', version 1\.3, resurrected"
	  dotest_fail resurrection-15 'test -w file1' ''

	  dokeep
	  cd ../..
	  rm -rf 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	dirs)
	  # Tests related to removing and adding directories.
	  # See also:
	  #   conflicts (especially dir1 in conflicts-130): What happens if
	  #     directory exists in repository and a non-CVS-controlled
	  #     directory in the working directory?
	  #   conflicts3-15.  More cases, especially where CVS directory
	  #     exists but without CVS/Repository and friends.
	  #   conflicts3-22.  Similar to conflicts-130 but there is a file
	  #     in the directory.
	  #   dirs2.  Sort of similar to conflicts3-22 but somewhat different.
	  mkdir imp-dir; cd imp-dir
	  echo file1 >file1
	  mkdir sdir
	  echo sfile >sdir/sfile
	  dotest_sort dirs-1 \
"${testcvs} import -m import-it dir1 vend rel" "

N dir1/file1
N dir1/sdir/sfile
No conflicts created by this import
${SPROG} import: Importing ${CVSROOT_DIRNAME}/dir1/sdir"
	  cd ..

	  mkdir 1; cd 1
	  dotest dirs-2 "$testcvs -Q co dir1" ""

	  # Various CVS administrators are in the habit of removing
	  # the repository directory for things they don't want any
	  # more.  I've even been known to do it myself (on rare
	  # occasions).  Not the usual recommended practice, but we want
	  # to try to come up with some kind of reasonable/documented/sensible
	  # behavior.
	  modify_repo rm -rf $CVSROOT_DIRNAME/dir1/sdir

	  dotest dirs-3 "${testcvs} update" \
"${SPROG} update: Updating dir1
${SPROG} update: Updating dir1/sdir
${SPROG} update: cannot open directory ${CVSROOT_DIRNAME}/dir1/sdir: No such file or directory
${SPROG} update: skipping directory dir1/sdir"
	  dotest dirs-3a "${testcvs} update -d" \
"${SPROG} update: Updating dir1
${SPROG} update: Updating dir1/sdir
${SPROG} update: cannot open directory ${CVSROOT_DIRNAME}/dir1/sdir: No such file or directory
${SPROG} update: skipping directory dir1/sdir"

	  # If we say "yes", then CVS gives errors about not being able to
	  # create lock files.
	  # The fact that it says "skipping directory " rather than
	  # "skipping directory dir1/sdir" is some kind of bug.
	  dotest dirs-4 "echo no | ${testcvs} release -d dir1/sdir" \
"${SPROG} update: cannot open directory ${CVSROOT_DIRNAME}/dir1/sdir: No such file or directory
${SPROG} update: skipping directory 
You have \[0\] altered files in this repository\.
Are you sure you want to release (and delete) directory .dir1/sdir': .. .release' aborted by user choice."

	  # OK, if "cvs release" won't help, we'll try it the other way...
	  rm -r dir1/sdir

	  dotest dirs-5 "cat dir1/CVS/Entries" \
"/file1/1.1.1.1/[a-zA-Z0-9 :]*//
D/sdir////"
	  dotest dirs-6 "${testcvs} update" "${SPROG} update: Updating dir1"
	  dotest dirs-7 "cat dir1/CVS/Entries" \
"/file1/1.1.1.1/[a-zA-Z0-9 :]*//
D/sdir////"
	  dotest dirs-8 "${testcvs} update -d dir1" \
"${SPROG} update: Updating dir1"

	  dokeep
	  cd ..
	  rm -r imp-dir 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/dir1
	  ;;



	dirs2)
	  # See "dirs" for a list of tests involving adding and
	  # removing directories.
	  mkdir 1; cd 1
	  dotest dirs2-1 "$testcvs -q co -l ."
	  mkdir first-dir
	  dotest dirs2-2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
	  cd first-dir
	  mkdir sdir
	  dotest dirs2-3 "${testcvs} add sdir" \
"Directory ${CVSROOT_DIRNAME}/first-dir/sdir added to the repository"
	  touch sdir/file1
	  dotest dirs2-4 "${testcvs} add sdir/file1" \
"${SPROG} add: scheduling file .sdir/file1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest dirs2-5 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/sdir/file1,v  <--  sdir/file1
initial revision: 1\.1"
	  rm -r sdir/CVS
	  if $remote; then
	    # This is just like conflicts3-23
	    dotest_fail dirs2-6r "${testcvs} update -d" \
"${QUESTION} sdir
${SPROG} update: Updating \.
${SPROG} update: Updating sdir
${CPROG} update: move away \`sdir/file1'; it is in the way
C sdir/file1"
	    rm sdir/file1
	    rm -r sdir/CVS

	    # This is where things are not just like conflicts3-23
	    dotest dirs2-7r "${testcvs} update -d" \
"${QUESTION} sdir
${SPROG} update: Updating \.
${SPROG} update: Updating sdir
U sdir/file1"
	  else
	    dotest dirs2-6 "${testcvs} update -d" \
"${CPROG} update: Updating \.
${QUESTION} sdir"
	    rm sdir/file1
	    dotest dirs2-7 "${testcvs} update -d" \
"${CPROG} update: Updating \.
${QUESTION} sdir"
	  fi
	  cd ../..

	  # Now, the same thing (more or less) on a branch.
	  mkdir 2; cd 2
	  dotest dirs2-8 "${testcvs} -q co first-dir" 'U first-dir/sdir/file1'
	  cd first-dir
	  dotest dirs2-9 "${testcvs} -q tag -b br" "T sdir/file1"
	  rm -r sdir/CVS

	  if $remote; then
	    # val-tags used to have a cute little quirk; if an update didn't
	    # recurse into the directories where the tag is defined, val-tags
	    # wouldn't get updated.  This is no longer a problem as of 1.12.10.
	    dotest_fail dirs2-10-againr "$testcvs update -d -r br" \
"$QUESTION sdir
$SPROG update: Updating \.
$SPROG update: Updating sdir
$CPROG update: move away \`sdir/file1'; it is in the way
C sdir/file1"
	  else
	    dotest dirs2-10 "${testcvs} update -d -r br" \
"$SPROG update: Updating \.
$QUESTION sdir"
# This is what used to happen.  I'm not sure why it changed with 1.12.10, but
# as near as I can tell from the comments in update_direntproc, the new
# behavior was the intended behavior.
#"$CPROG update: in directory \`sdir':
#$CPROG \[update aborted\]: there is no version here; do \`$CPROG checkout' first"
	  fi
	  cd ../..

	  # OK, the above tests make the situation somewhat harder
	  # than it might be, in the sense that they actually have a
	  # file which is alive on the branch we are updating.  Let's
	  # try it where it is just a directory where all the files
	  # have been removed.
	  mkdir 3; cd 3
	  dotest dirs2-11 "${testcvs} -q co -r br first-dir" \
"U first-dir/sdir/file1"
	  cd first-dir
	  # Hmm, this doesn't mention the branch like add does.  That's
	  # an odd non-orthogonality.
	  dotest dirs2-12 "${testcvs} rm -f sdir/file1" \
"${SPROG} remove: scheduling .sdir/file1. for removal
${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
	  dotest dirs2-13 "${testcvs} -q ci -m remove" \
"$CVSROOT_DIRNAME/first-dir/sdir/file1,v  <--  sdir/file1
new revision: delete; previous revision: 1\.1"
	  cd ../../2/first-dir
	  if $remote; then
	    dotest dirs2-14 "${testcvs} update -d -r br" \
"${QUESTION} sdir/file1
${SPROG} update: Updating \.
${SPROG} update: Updating sdir"
	  else
	    dotest dirs2-14 "${testcvs} update -d -r br" \
"${CPROG} update: Updating \.
${QUESTION} sdir"
	  fi

	  dokeep
	  cd ../..
	  rm -r 1 2 3
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	branches)
	  # More branch tests, including branches off of branches
	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  dotest branches-1 "$testcvs -q co first-dir"
	  cd first-dir
	  echo 1:ancest >file1
	  echo 2:ancest >file2
	  echo 3:ancest >file3
	  echo 4:trunk-1 >file4
	  dotest branches-2 "${testcvs} add file1 file2 file3 file4" \
"$SPROG add: scheduling file \`file1' for addition
$SPROG add: scheduling file \`file2' for addition
$SPROG add: scheduling file \`file3' for addition
$SPROG add: scheduling file \`file4' for addition
$SPROG add: use .$SPROG commit. to add these files permanently"
	  dotest branches-2a "$testcvs -n -q ci -m dont-commit"
	  dotest_lit branches-3 "$testcvs -q ci -m add-it" <<HERE
$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
initial revision: 1.1
${CVSROOT_DIRNAME}/first-dir/file3,v  <--  file3
initial revision: 1.1
${CVSROOT_DIRNAME}/first-dir/file4,v  <--  file4
initial revision: 1.1
HERE
	  echo 4:trunk-2 >file4
	  dotest branches-3.2 "${testcvs} -q ci -m trunk-before-branch" \
"$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: 1\.2; previous revision: 1\.1"
	  # The "cvs log file4" in test branches-14.3 will test that we
	  # didn't really add the tag.
	  dotest branches-3.3 "${testcvs} -qn tag dont-tag" \
"T file1
T file2
T file3
T file4"
	  # Modify this file before branching, to deal with the case where
	  # someone is hacking along, says "oops, I should be doing this on
	  # a branch", and only then creates the branch.
	  echo 1:br1 >file1
	  dotest branches-4 "${testcvs} tag -b br1" "${SPROG}"' tag: Tagging \.
T file1
T file2
T file3
T file4'
	  dotest branches-5 "${testcvs} update -r br1" \
"${SPROG} update: Updating \.
M file1"
	  echo 2:br1 >file2
	  echo 4:br1 >file4
	  dotest branches-6 "${testcvs} -q ci -m modify" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: 1\.2\.2\.1; previous revision: 1\.2"
	  dotest branches-7 "${testcvs} -q tag -b brbr" 'T file1
T file2
T file3
T file4'
	  dotest branches-8 "${testcvs} -q update -r brbr" ''
	  echo 1:brbr >file1
	  echo 4:brbr >file4
	  dotest branches-9 "${testcvs} -q ci -m modify" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.1\.2\.1\.2\.1; previous revision: 1\.1\.2\.1
$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: 1\.2\.2\.1\.2\.1; previous revision: 1\.2\.2\.1"
	  dotest branches-10 "cat file1 file2 file3 file4" '1:brbr
2:br1
3:ancest
4:brbr'
	  dotest branches-11 "${testcvs} -q update -r br1" \
'[UP] file1
[UP] file4'
	  dotest branches-12 "cat file1 file2 file3 file4" '1:br1
2:br1
3:ancest
4:br1'
	  echo 4:br1-2 >file4
	  dotest branches-12.2 "${testcvs} -q ci -m change-on-br1" \
"$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: 1\.2\.2\.2; previous revision: 1\.2\.2\.1"
	  dotest branches-13 "${testcvs} -q update -A" '[UP] file1
[UP] file2
[UP] file4'
	  dotest branches-14 "cat file1 file2 file3 file4" '1:ancest
2:ancest
3:ancest
4:trunk-2'
	  echo 4:trunk-3 >file4
	  dotest branches-14.2 \
	    "${testcvs} -q ci -m trunk-change-after-branch" \
"$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: 1\.3; previous revision: 1\.2"
	  dotest branches-14.3 "${testcvs} log file4" \
"
RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v
Working file: file4
head: 1\.3
branch:
locks: strict
access list:
symbolic names:
	brbr: 1\.2\.2\.1\.0\.2
	br1: 1\.2\.0\.2
keyword substitution: kv
total revisions: 6;	selected revisions: 6
description:
----------------------------
revision 1\.3
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  commitid: ${commitid};
trunk-change-after-branch
----------------------------
revision 1\.2
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  commitid: ${commitid};
branches:  1\.2\.2;
trunk-before-branch
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
add-it
----------------------------
revision 1\.2\.2\.2
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  commitid: ${commitid};
change-on-br1
----------------------------
revision 1\.2\.2\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  commitid: ${commitid};
branches:  1\.2\.2\.1\.2;
modify
----------------------------
revision 1\.2\.2\.1\.2\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  commitid: ${commitid};
modify
============================================================================="
	  dotest_fail branches-14.4 \
	    "${testcvs} diff -c -r 1.1 -r 1.3 file4" \
"Index: file4
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v
retrieving revision 1\.1
retrieving revision 1\.3
diff -c -r1\.1 -r1\.3
\*\*\* file4	${RFCDATE}	1\.1
--- file4	${RFCDATE}	1\.3
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
! 4:trunk-1
--- 1 ----
! 4:trunk-3"
	  dotest_fail branches-14.5 \
	    "${testcvs} diff -c -r 1.1 -r 1.2.2.1 file4" \
"Index: file4
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v
retrieving revision 1\.1
retrieving revision 1\.2\.2\.1
diff -c -r1\.1 -r1\.2\.2\.1
\*\*\* file4	${RFCDATE}	1\.1
--- file4	${RFCDATE}	1\.2\.2\.1
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*\*\* 1 \*\*\*\*
! 4:trunk-1
--- 1 ----
! 4:br1"
	  dotest branches-15 \
	    "${testcvs} update -j 1.1.2.1 -j 1.1.2.1.2.1 file1" \
	    "RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
retrieving revision 1\.1\.2\.1
retrieving revision 1\.1\.2\.1\.2\.1
Merging differences between 1\.1\.2\.1 and 1\.1\.2\.1\.2\.1 into file1
rcsmerge: warning: conflicts during merge"
	  dotest branches-16 "cat file1" '<<<<<<< file1
1:ancest
[=]======
1:brbr
[>]>>>>>> 1\.1\.2\.1\.2\.1'

	  dotest branches-o1 "${testcvs} -q admin -o ::brbr" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
done
RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
done
RCS file: ${CVSROOT_DIRNAME}/first-dir/file3,v
done
RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v
done"

	  dokeep
	  cd ..
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  rm -r first-dir
	  ;;



	branches2)
	  # More branch tests.
	  # Test that when updating a new subdirectory in a directory
	  # which was checked out on a branch, the new subdirectory is
	  # created on the appropriate branch.  Test this when joining
	  # as well.

	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  mkdir trunk; cd trunk

	  # Create a file.
	  dotest branches2-1 "${testcvs} -q co first-dir"
	  cd first-dir
	  echo "file1 first revision" > file1
	  dotest branches2-2 "${testcvs} add file1" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest branches2-3 "${testcvs} commit -m add file1" \
"${CVSROOT_DIRNAME}/first-dir/file1,v  <--  file1
initial revision: 1\.1"

	  # Tag the file.
	  dotest branches2-4 "${testcvs} -q tag tag1" 'T file1'

	  # Make two branches.
	  dotest branches2-5 "${testcvs} -q rtag -b -r tag1 b1 first-dir" ''
	  dotest branches2-6 "${testcvs} -q rtag -b -r tag1 b2 first-dir" ''

	  # Create some files and a subdirectory on branch b1.
	  cd ../..
	  mkdir b1; cd b1
	  dotest branches2-7 "${testcvs} -q co -r b1 first-dir" \
"U first-dir/file1"
	  cd first-dir
	  echo "file2 first revision" > file2
	  dotest branches2-8 "${testcvs} add file2" \
"${SPROG}"' add: scheduling file `file2'\'' for addition on branch `b1'\''
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
	  mkdir dir1
	  dotest branches2-9 "${testcvs} add dir1" \
"Directory ${CVSROOT_DIRNAME}/first-dir/dir1 added to the repository
--> Using per-directory sticky tag "'`'"b1'"
	  echo "file3 first revision" > dir1/file3
	  dotest branches2-10 "${testcvs} add dir1/file3" \
"${SPROG}"' add: scheduling file `dir1/file3'\'' for addition on branch `b1'\''
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
	  dotest branches2-11 "${testcvs} -q ci -madd ." \
"$CVSROOT_DIRNAME/first-dir/Attic/file2,v  <--  file2
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/dir1/Attic/file3,v  <--  dir1/file3
new revision: 1\.1\.2\.1; previous revision: 1\.1"

	  # Check out the second branch, and update the working
	  # directory to the first branch, to make sure the right
	  # happens with dir1.
	  cd ../..
	  mkdir b2; cd b2
	  dotest branches2-12 "${testcvs} -q co -r b2 first-dir" \
'U first-dir/file1'
	  cd first-dir
	  dotest branches2-13 "${testcvs} update -d -r b1 dir1" \
"${SPROG} update: Updating dir1
U dir1/file3"
	  dotest branches2-14 "${testcvs} -q status" \
"===================================================================
File: file1            	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file1,v
   Commit Identifier:	${commitid}
   Sticky Tag:		b2 (branch: 1\.1\.4)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file3            	Status: Up-to-date

   Working revision:	1\.1\.2\.1.*
   Repository revision:	1\.1\.2\.1	${CVSROOT_DIRNAME}/first-dir/dir1/Attic/file3,v
   Commit Identifier:	${commitid}
   Sticky Tag:		b1 (branch: 1\.1\.2)
   Sticky Date:		(none)
   Sticky Options:	(none)"

	  # Test some calls to rls here because we can.  These should probably
	  # be somewhere else, but we already have some directories set up.
          dotest branches2-14-rls-1 "$testcvs rls" \
"$SPROG rls: Listing module: \`.'
CVSROOT
first-dir"
          dotest branches2-14-rls-2 "$testcvs rls -R" \
"$SPROG rls: Listing module: \`.'
\.:
CVSROOT
first-dir

CVSROOT:
checkoutlist
commitinfo
config
cvswrappers
loginfo
modules
notify
postadmin
postproxy
posttag
postwatch
preproxy
rcsinfo
taginfo
verifymsg
Emptydir

CVSROOT/Emptydir:

first-dir:
file1
dir1

first-dir/dir1:"
          dotest branches2-14-rls-3 "$testcvs rls -l -R" \
"$SPROG rls: Listing module: \`.'
\.:
d--- $ISO8601DATE            CVSROOT
d--- $ISO8601DATE            first-dir

CVSROOT:
---- $ISO8601DATE 1\.[0-9][0-9]*        checkoutlist
---- $ISO8601DATE 1\.[0-9][0-9]*        commitinfo
---- $ISO8601DATE 1\.[0-9][0-9]*        config
---- $ISO8601DATE 1\.[0-9][0-9]*        cvswrappers
---- $ISO8601DATE 1\.[0-9][0-9]*        loginfo
---- $ISO8601DATE 1\.[0-9][0-9]*        modules
---- $ISO8601DATE 1\.[0-9][0-9]*        notify
---- $ISO8601DATE 1\.[0-9][0-9]*        postadmin
---- $ISO8601DATE 1\.[0-9][0-9]*        postproxy
---- $ISO8601DATE 1\.[0-9][0-9]*        posttag
---- $ISO8601DATE 1\.[0-9][0-9]*        postwatch
---- $ISO8601DATE 1\.[0-9][0-9]*        preproxy
---- $ISO8601DATE 1\.[0-9][0-9]*        rcsinfo
---- $ISO8601DATE 1\.[0-9][0-9]*        taginfo
---- $ISO8601DATE 1\.[0-9][0-9]*        verifymsg
d--- $ISO8601DATE            Emptydir

CVSROOT/Emptydir:

first-dir:
---- $ISO8601DATE 1\.1        file1
d--- $ISO8601DATE            dir1

first-dir/dir1:"
          dotest branches2-14-rls-4 "$testcvs rls -eR" \
"$SPROG rls: Listing module: \`.'
\.:
D/CVSROOT////
D/first-dir////

CVSROOT:
/checkoutlist/1\.[0-9][0-9]*/$DATE//
/commitinfo/1\.[0-9][0-9]*/$DATE//
/config/1\.[0-9][0-9]*/$DATE//
/cvswrappers/1\.[0-9][0-9]*/$DATE//
/loginfo/1\.[0-9][0-9]*/$DATE//
/modules/1\.[0-9][0-9]*/$DATE//
/notify/1\.[0-9][0-9]*/$DATE//
/postadmin/1\.[0-9][0-9]*/$DATE//
/postproxy/1\.[0-9][0-9]*/$DATE//
/posttag/1\.[0-9][0-9]*/$DATE//
/postwatch/1\.[0-9][0-9]*/$DATE//
/preproxy/1\.[0-9][0-9]*/$DATE//
/rcsinfo/1\.[0-9][0-9]*/$DATE//
/taginfo/1\.[0-9][0-9]*/$DATE//
/verifymsg/1\.[0-9][0-9]*/$DATE//
D/Emptydir////

CVSROOT/Emptydir:

first-dir:
/file1/1\.1/$DATE//
D/dir1////

first-dir/dir1:"
          dotest branches2-14-rls-5 "$testcvs -q rls -R" \
"\.:
CVSROOT
first-dir

CVSROOT:
checkoutlist
commitinfo
config
cvswrappers
loginfo
modules
notify
postadmin
postproxy
posttag
postwatch
preproxy
rcsinfo
taginfo
verifymsg
Emptydir

CVSROOT/Emptydir:

first-dir:
file1
dir1

first-dir/dir1:"
          dotest branches2-14-rls-6 "$testcvs -q rls -lRrb1" \
"\.:
d--- $ISO8601DATE            CVSROOT
d--- $ISO8601DATE            first-dir

CVSROOT:
d--- $ISO8601DATE            Emptydir

CVSROOT/Emptydir:

first-dir:
---- $ISO8601DATE 1\.1        file1
---- $ISO8601DATE 1\.1\.2\.1    file2
d--- $ISO8601DATE            dir1

first-dir/dir1:
---- $ISO8601DATE 1\.1\.2\.1    file3"
          dotest branches2-14-rls-7 "$testcvs -q rls -lRrb2" \
"\.:
d--- $ISO8601DATE            CVSROOT
d--- $ISO8601DATE            first-dir

CVSROOT:
d--- $ISO8601DATE            Emptydir

CVSROOT/Emptydir:

first-dir:
---- $ISO8601DATE 1\.1        file1
d--- $ISO8601DATE            dir1

first-dir/dir1:"

	  # Now some calls to ls.  These are more appropriate here.
	  dotest branches2-14-ls-1 "$testcvs ls" \
"file1
dir1"
	  dotest branches2-14-ls-2 "$testcvs ls -e" \
"/file1/1\.1/$DATE//
D/dir1////"
	  dotest branches2-14-ls-3 "$testcvs ls -R" \
"\.:
file1
dir1

dir1:
file3"
	  dotest branches2-14-ls-4 "$testcvs ls -eRrHEAD" \
"\.:
/file1/1\.1/$DATE//THEAD
D/dir1////

dir1:"
	  dotest branches2-14-ls-5 "$testcvs ls -eRrb1" \
"\.:
/file1/1\.1/$DATE//Tb1
/file2/1\.1\.2\.1/$DATE//Tb1
D/dir1////

dir1:
/file3/1\.1\.2\.1/$DATE//Tb1"
	  dotest branches2-14-ls-6 "$testcvs ls -eRrb2" \
"\.:
/file1/1.1/$DATE//Tb2
D/dir1////

dir1:"
	  # Nonexistant tags used to cause assertion failures.
	  dotest_fail branches2-14-ls-7 "$testcvs ls -eRrnosuchtag" \
"$SPROG \[ls aborted\]: no such tag \`nosuchtag'"

	  # FIXME: Just clobbering the directory like this is a bit
	  # tacky, although people generally expect it to work.  Maybe
	  # we should release it instead.  We do it a few other places
	  # below as well.
	  rm -r dir1
	  dotest branches2-15 "${testcvs} update -d -j b1 dir1" \
"${SPROG} update: Updating dir1
U dir1/file3"
	  # FIXCVS: The `No revision control file' stuff seems to be
	  # CVS's way of telling us that we're adding the file on a
	  # branch, and the file is not on that branch yet.  This
	  # should be nicer.
	  dotest branches2-16 "${testcvs} -q status" \
"===================================================================
File: file1            	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file1,v
   Commit Identifier:	${commitid}
   Sticky Tag:		b2 (branch: 1\.1\.4)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file3            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	No revision control file
   Sticky Tag:		b2 - MISSING from RCS file!
   Sticky Date:		(none)
   Sticky Options:	(none)"

	  cd ../../trunk/first-dir
	  dotest branches2-17 "${testcvs} update -d -P dir1" \
"${SPROG} update: Updating dir1"
	  dotest_fail branches2-18 "test -d dir1"
	  dotest branches2-19 "${testcvs} update -d -P -r b1 dir1" \
"${SPROG} update: Updating dir1
U dir1/file3"
	  dotest branches2-20 "${testcvs} -q status" \
"===================================================================
File: file1            	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file1,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file3            	Status: Up-to-date

   Working revision:	1\.1\.2\.1.*
   Repository revision:	1\.1\.2\.1	${CVSROOT_DIRNAME}/first-dir/dir1/Attic/file3,v
   Commit Identifier:	${commitid}
   Sticky Tag:		b1 (branch: 1\.1\.2)
   Sticky Date:		(none)
   Sticky Options:	(none)"

	  rm -r dir1
	  dotest branches2-21 "${testcvs} update -d -P -j b1 dir1" \
"${SPROG} update: Updating dir1
U dir1/file3"
	  dotest branches2-22 "${testcvs} -q status" \
"===================================================================
File: file1            	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file1,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: file3            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/dir1/Attic/file3,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"

	  cd ../..
	  rm -r b1 b2

	  # Check out branch b1 twice.  Crate a new directory in one
	  # working directory, then do a cvs update in the other
	  # working directory and see if the tags are right.
	  mkdir b1a
	  mkdir b1b
	  cd b1b
	  dotest branches2-23 "${testcvs} -q co -r b1 first-dir" \
'U first-dir/file1
U first-dir/file2
U first-dir/dir1/file3'
	  cd ../b1a
	  dotest branches2-24 "${testcvs} -q co -r b1 first-dir" \
'U first-dir/file1
U first-dir/file2
U first-dir/dir1/file3'
	  cd first-dir
	  mkdir dir2
	  dotest branches2-25 "${testcvs} add dir2" \
"Directory ${CVSROOT_DIRNAME}/first-dir/dir2 added to the repository
--> Using per-directory sticky tag "'`'"b1'"
	  echo "file4 first revision" > dir2/file4
	  dotest branches2-26 "${testcvs} add dir2/file4" \
"${SPROG}"' add: scheduling file `dir2/file4'\'' for addition on branch `b1'\''
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
	  dotest branches2-27 "${testcvs} -q commit -madd" \
"$CVSROOT_DIRNAME/first-dir/dir2/Attic/file4,v  <--  dir2/file4
new revision: 1\.1\.2\.1; previous revision: 1\.1"

	  cd ../../b1b/first-dir
	  dotest branches2-28 "${testcvs} update -d dir2" \
"${SPROG} update: Updating dir2
U dir2/file4"
	  cd dir2
	  dotest branches2-29 "${testcvs} -q status" \
"===================================================================
File: file4            	Status: Up-to-date

   Working revision:	1\.1\.2\.1.*
   Repository revision:	1\.1\.2\.1	${CVSROOT_DIRNAME}/first-dir/dir2/Attic/file4,v
   Commit Identifier:	${commitid}
   Sticky Tag:		b1 (branch: 1\.1\.2)
   Sticky Date:		(none)
   Sticky Options:	(none)"
	  dotest branches2-30 "cat CVS/Tag" 'Tb1'

	  # Test update -A on a subdirectory
	  cd ..
	  rm -r dir2
	  dotest branches2-31 "${testcvs} update -A -d dir2" \
"${SPROG} update: Updating dir2"
	  cd dir2
	  dotest branches2-32 "${testcvs} -q status" ''
	  dotest_fail branches2-33 "test -f CVS/Tag"

	  # Add a file on the trunk.
	  echo "file5 first revision" > file5
	  dotest branches2-34 "${testcvs} add file5" \
"${SPROG}"' add: scheduling file `file5'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
	  dotest branches2-35 "${testcvs} -q commit -madd" \
"$CVSROOT_DIRNAME/first-dir/dir2/file5,v  <--  file5
initial revision: 1\.1"

	  cd ../../../trunk/first-dir
	  dotest branches2-36 "${testcvs} -q update -d dir2" 'U dir2/file5'
	  cd dir2
	  dotest branches2-37 "${testcvs} -q status" \
"===================================================================
File: file5            	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/dir2/file5,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
	  dotest_fail branches2-38 "test -f CVS/status"

          dotest branches2-39 "$testcvs rls -rb1 -l -R first-dir" \
"$SPROG rls: Listing module: \`first-dir'
first-dir:
---- $ISO8601DATE 1\.1        file1
---- $ISO8601DATE 1\.1\.2\.1    file2
d--- $ISO8601DATE            dir1
d--- $ISO8601DATE            dir2

first-dir/dir1:
---- $ISO8601DATE 1\.1\.2\.1    file3

first-dir/dir2:
---- $ISO8601DATE 1\.1\.2\.1    file4"

	  dokeep
	  cd ../../..
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  rm -r trunk b1a b1b
	  ;;



	branches3)
	  # test local branch number support

	  # This test is skipped in $remotehost mode since the
	  # CVS_LOCAL_BRANCH_NUM is not inherited by the server process as it
	  # is with :fork:, for hopefully obvious reasons.
	  #
	  # FIXCVS?  Is this correct?  Should CVS_LOCAL_BRANCH_NUM be sent as
	  # a protocol extension or is it reasonable to only want this set on
	  # the server?

	  if test -n "$remotehost"; then :;else
	    modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	    mkdir branches3; cd branches3

	    dotest branches3-1 "$testcvs -q co first-dir"
	    cd first-dir
	    echo "file1 first revision" > file1
	    dotest branches3-2 "${testcvs} add file1" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	    dotest branches3-3 "${testcvs} commit -m add file1" \
"${CVSROOT_DIRNAME}/first-dir/file1,v  <--  file1
initial revision: 1\.1"

	    # Tag the file using a CVS_LOCAL_BRANCH_NUM of 1000
	    CVS_LOCAL_BRANCH_NUM=1000; export CVS_LOCAL_BRANCH_NUM
	    dotest branches3-4 "${testcvs} -q tag -b tag1" 'T file1'
	    unset CVS_LOCAL_BRANCH_NUM
	    dotest branches3-5 "${testcvs} -q log file1" \
"
RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
Working file: file1
head: 1\.1
branch:
locks: strict
access list:
symbolic names:
	tag1: 1\.1\.0\.1000
keyword substitution: kv
total revisions: 1;	selected revisions: 1
description:
----------------------------
revision 1.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
add
============================================================================="

	    dokeep
	    cd ../..
	    modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	    rm -r branches3
	  fi # !$remotehost
	  ;;



	branches4)
	  # test where a tag is a branch tag in some files and a revision
	  # tag in others

	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  mkdir branches4; cd branches4

	  dotest branches4-1 "$testcvs -q co first-dir"
	  cd first-dir
	  mkdir branches mixed mixed2 versions
	  dotest branches4-2 "${testcvs} -q add branches mixed mixed2 versions" \
"Directory ${CVSROOT_DIRNAME}/first-dir/branches added to the repository
Directory ${CVSROOT_DIRNAME}/first-dir/mixed added to the repository
Directory ${CVSROOT_DIRNAME}/first-dir/mixed2 added to the repository
Directory ${CVSROOT_DIRNAME}/first-dir/versions added to the repository"

	  echo file1 >branches/file1
	  echo file2 >branches/file2
	  echo file3 >branches/file3
	  echo file4 >branches/file4
	  cp branches/file* mixed
	  cp branches/file* mixed2
	  cp branches/file* versions

	  dotest branches4-3 "${testcvs} -q add */file*" \
"${SPROG} add: use .${SPROG} commit. to add these files permanently"
	  dotest branches4-3a "${testcvs} -Q ci -m."

	  dotest branches4-4 "${testcvs} -q tag xxx versions/file* mixed*/file1 mixed*/file3" \
"T versions/file1
T versions/file2
T versions/file3
T versions/file4
T mixed/file1
T mixed/file3
T mixed2/file1
T mixed2/file3"

	  dotest branches4-5 "${testcvs} -q tag -b xxx branches/file* mixed*/file2 mixed*/file4" \
"T branches/file1
T branches/file2
T branches/file3
T branches/file4
T mixed/file2
T mixed/file4
T mixed2/file2
T mixed2/file4"

	  # make sure we get the appropriate warnings when updating	  
	  dotest branches4-6 "${testcvs} update -r xxx" \
"${SPROG} update: Updating \.
${SPROG} update: Updating branches
${SPROG} update: Updating mixed
${SPROG} update: warning: xxx is a branch tag in some files and a revision tag in others\.
${SPROG} update: Updating mixed2
${SPROG} update: warning: xxx is a branch tag in some files and a revision tag in others\.
${SPROG} update: Updating versions"

	  # make sure we don't get warned in quiet modes
	  dotest branches4-7 "${testcvs} -q update -A"
	  dotest branches4-8 "${testcvs} -q update -r xxx"
	  dotest branches4-9 "${testcvs} -q update -A"
	  dotest branches4-10 "${testcvs} -Q update -r xxx"

	  # make sure the Tag files are correct
	  dotest branches4-11 "cat branches/CVS/Tag" "Txxx"
	  dotest branches4-12 "cat mixed/CVS/Tag" "Nxxx"
	  dotest branches4-13 "cat mixed2/CVS/Tag" "Nxxx"
	  dotest branches4-14 "cat versions/CVS/Tag" "Nxxx"

	  # We only warn if there's mixed usage in a single directory.
	  # We may want to consider changing that in the future.
	  dotest branches4-15 "${testcvs} update -r xxx branches versions" \
"${SPROG} update: Updating branches
${SPROG} update: Updating versions"

	  dokeep
	  cd ../..
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  rm -r branches4
	  ;;



	tagc)
	  # Test the tag -c option.
	  mkdir 1; cd 1
	  dotest tagc-1 "${testcvs} -q co -l ." ''
	  mkdir first-dir
	  dotest tagc-2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
	  cd first-dir
	  touch file1 file2
	  dotest tagc-3 "${testcvs} add file1 file2" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: scheduling file .file2. for addition
${SPROG} add: use .${SPROG} commit. to add these files permanently"
	  dotest tagc-4 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
initial revision: 1\.1"
	  dotest tagc-5 "${testcvs} -q tag -c tag1" \
"T file1
T file2"
	  touch file1 file2
	  dotest tagc-6 "${testcvs} -q tag -c tag2" \
"T file1
T file2"
	  # Avoid timestamp granularity bugs (FIXME: CVS should be
	  # doing the sleep, right?).
	  sleep 1
	  echo myedit >>file1
	  dotest tagc-6a "${testcvs} rm -f file2" \
"${SPROG} remove: scheduling .file2. for removal
${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
	  touch file3
	  dotest tagc-6b "${testcvs} add file3" \
"${SPROG} add: scheduling file .file3. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest_fail tagc-7 "${testcvs} -q tag -c tag3" \
"${SPROG} tag: file1 is locally modified
${SPROG} tag: file2 is locally modified
${SPROG} tag: file3 is locally modified
${SPROG} \[tag aborted\]: correct the above errors first!"
	  cd ../..
	  mkdir 2
	  cd 2
	  dotest tagc-8 "${testcvs} -q co first-dir" \
"U first-dir/file1
U first-dir/file2"
	  cd ../1/first-dir
	  dotest tagc-9 "${testcvs} -q ci -m modify" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.2; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
new revision: delete; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file3,v  <--  file3
initial revision: 1\.1"
	  cd ../../2/first-dir
	  dotest tagc-10 "${testcvs} -q tag -c tag4" \
"${SPROG} tag: \`file2' is no longer in the repository
T file1
T file2"

	  dokeep
	  cd ../..
	  rm -r 1 2
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	update-p)
	  # Make sure `cvs update -p -rT FILE' works from a branch when
	  # FILE is already on the trunk and is being added to that branch.

	  mkdir 1; cd 1
	  module=x

	  echo > unused-file

	  # Create the module.
	  dotest update-p-1 \
	    "$testcvs -Q import -m. $module X Y" ''

	  file=F
	  # Check it out and tag it.
	  dotest update-p-2 "$testcvs -Q co $module" ''
	  cd $module
	  dotest update-p-3 "$testcvs -Q tag -b B" ''
	  echo v1 > $file
	  dotest update-p-4 "$testcvs -Q add $file" ''
	  dotest update-p-5 "$testcvs -Q ci -m. $file"
	  dotest update-p-6 "$testcvs -Q tag T $file" ''
	  dotest update-p-7 "$testcvs -Q update -rB" ''

	  # This merge effectively adds file F on branch B.
	  dotest update-p-8 "$testcvs -Q update -jT" ''

	  # Before the fix that prompted the addition of this test,
	  # the following command would fail with this diagnostic:
	  # cvs update: conflict: F created independently by second party
	  dotest update-p-9 "$testcvs update -p -rT $file" \
"===================================================================
Checking out $file
RCS:  ${CVSROOT_DIRNAME}/$module/$file,v
VERS: 1\.1
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
v1"

	  # Repeat the above, but with $file removed.
	  # This exercises a slightly different code path.
	  rm $file
	  # Before the fix that prompted the addition of this test,
	  # the following command would fail with this diagnostic:
	  # cvs update: warning: new-born \`F' has disappeared
	  dotest update-p-10 "$testcvs update -p -rT $file" \
"===================================================================
Checking out $file
RCS:  ${CVSROOT_DIRNAME}/$module/$file,v
VERS: 1\.1
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
v1"

	  # Exercise yet another code path:
	  # the one that involves reviving a `dead' file.
	  # And a little more, for good measure...
	  touch new
	  dotest update-p-a1 "$testcvs -Q add new" ''
	  dotest update-p-a2 "$testcvs -Q update -p new" ''
	  dotest update-p-a3 "$testcvs -Q rm -f new" ''

	  # Both an update -A, *and* the following update are required
	  # to return to the state of being on the trunk with a $file
	  # that we can then remove.
	  dotest update-p-undead-0 "$testcvs update -A" \
"${SPROG} update: Updating \.
${SPROG} update: warning: new-born \`$file' has disappeared"
	  dotest update-p-undead-1 "$testcvs update" \
"${SPROG} update: Updating \.
U $file"
	  dotest update-p-undead-2 "$testcvs -Q update -p -rT $file" v1
	  dotest update-p-undead-3 "$testcvs -Q rm -f $file" ''
	  dotest update-p-undead-4 "$testcvs -Q update -p -rT $file" v1
	  dotest update-p-undead-5 "$testcvs -Q ci -m. $file"
	  dotest update-p-undead-6 "$testcvs -Q update -p -rT $file" v1
	  echo v2 > $file
	  dotest update-p-undead-7 "$testcvs -Q update -p -rT $file" v1
	  dotest update-p-undead-8 "$testcvs add $file" \
"$SPROG add: Re-adding file .$file. after dead revision 1\.2\.
$SPROG add: use \`$SPROG commit' to add this file permanently"

	  dotest update-p-undead-9 "$testcvs -Q update -p -rT $file" v1

	  dokeep
	  cd ../..
	  rm -rf 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/$module
	  ;;



	tagf)
	  # More tagging tests, including using tag -F -B to convert a
	  # branch tag to a regular tag and recovering thereof.

	  # Setup; check in first-dir/file1
	  mkdir 1; cd 1
	  dotest tagf-1 "${testcvs} -q co -l ." ''
	  mkdir first-dir
	  dotest tagf-2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
	  cd first-dir
	  touch file1 file2
	  dotest tagf-3 "${testcvs} add file1 file2" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: scheduling file .file2. for addition
${SPROG} add: use .${SPROG} commit. to add these files permanently"
	  dotest tagf-4 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
initial revision: 1\.1"

	  # Now create a branch and commit a revision there.
	  dotest tagf-5 "${testcvs} -q tag -b br" "T file1
T file2"
	  dotest tagf-6 "${testcvs} -q update -r br" ""
	  echo brmod >> file1
	  echo brmod >> file2
	  dotest tagf-7 "${testcvs} -q ci -m modify" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
new revision: 1\.1\.2\.1; previous revision: 1\.1"
	  # Here we try to make it a non-branch tag, but will
	  # succeed in getting only warnings, even with -F 
	  # because converting a branch tag to non-branch 
	  # is potentially catastrophic.
	  dotest tagf-8a "${testcvs} -q tag -F br" \
"${SPROG} tag: file1: Not moving branch tag .br. from 1\.1\.2\.1 to 1\.1\\.2\.1\.
${SPROG} tag: file2: Not moving branch tag .br. from 1\.1\.2\.1 to 1\.1\.2\.1\."
	  # however, if we *really* are sure we want to move a branch tag,
	  # "-F -B" will do the trick
	  dotest tagf-8 "${testcvs} -q tag -F -B br" "T file1
T file2"
	  echo moremod >> file1
	  echo moremod >> file2
	  dotest tagf-9 "${testcvs} -q status -v file1" \
"===================================================================
File: file1            	Status: Locally Modified

   Working revision:	1\.1\.2\.1.*
   Repository revision:	1\.1\.2\.1	${CVSROOT_DIRNAME}/first-dir/file1,v
   Commit Identifier:	${commitid}
   Sticky Tag:		br (revision: 1\.1\.2\.1)
   Sticky Date:		(none)
   Sticky Options:	(none)

   Existing Tags:
	br                       	(revision: 1\.1\.2\.1)"

	  # Now, how do we recover?
	  dotest tagf-10 "${testcvs} -q tag -d br" "D file1
D file2"
	  # This creates a new branch, 1.1.4.  See the code in RCS_magicrev
	  # which will notice that there is a (non-magic) 1.1.2 and thus
	  # skip that number.
	  dotest tagf-11 "${testcvs} -q tag -r 1.1 -b br file1" "T file1"
	  # Fix it with admin -n (cf admin-18, admin-26-4).
	  dotest tagf-12 "${testcvs} -q admin -nbr:1.1.2 file2" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
done"
	  # Another variation on the file2 test would be to use two working
	  # directories so that the update -r br would need to
	  # a merge to get from 1.1.2.1 to the head of the 1.1.2 branch.
	  dotest tagf-13 "${testcvs} -q update -r br" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
retrieving revision 1\.1\.2\.1
retrieving revision 1\.1
Merging differences between 1\.1\.2\.1 and 1\.1 into file1
rcsmerge: warning: conflicts during merge
${SPROG} update: conflicts found in file1
C file1
M file2"
	  # CVS is giving a conflict because we are trying to get back to
	  # 1.1.4.  I'm not sure why it is a conflict rather than just
	  # "M file1".
	  dotest tagf-14 "cat file1" \
"<<<<<<< file1
brmod
moremod
[=]======
[>]>>>>>> 1\.1"
	  echo resolve >file1
	  dotest tagf-15 "${testcvs} -q ci -m recovered" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.1\.4\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
	  # try accidentally deleting branch tag, "tag -d"
	  dotest_fail tagf-16 "${testcvs} tag -d br" \
"${SPROG} tag: Untagging \.
${SPROG} tag: Not removing branch tag .br. from .${CVSROOT_DIRNAME}/first-dir/file1,v.\.
${SPROG} tag: Not removing branch tag .br. from .${CVSROOT_DIRNAME}/first-dir/file2,v.\."
	  # try accidentally deleting branch tag, "rtag -d"
	  dotest_fail tagf-17 "${testcvs} rtag -d br first-dir" \
"${SPROG} rtag: Untagging first-dir
${SPROG} rtag: Not removing branch tag .br. from .${CVSROOT_DIRNAME}/first-dir/file1,v.\.
${SPROG} rtag: Not removing branch tag .br. from .${CVSROOT_DIRNAME}/first-dir/file2,v.\."
	  # try accidentally converting branch tag to non-branch tag "tag -F"
	  dotest tagf-18 "${testcvs} tag -r1.1 -F br file1" \
"${SPROG} tag: file1: Not moving branch tag .br. from 1\.1\.4\.1 to 1\.1\."
	  # try accidentally converting branch tag to non-branch tag "rtag -F"
	  dotest tagf-19 "${testcvs} rtag -r1.1 -F br first-dir" \
"${SPROG} rtag: Tagging first-dir
${SPROG} rtag: first-dir/file1: Not moving branch tag .br. from 1\.1\.4\.1 to 1\.1\.
${SPROG} rtag: first-dir/file2: Not moving branch tag .br. from 1\.1\.2\.2 to 1\.1\."
	  # create a non-branch tag
	  dotest tagf-20 "${testcvs} rtag regulartag first-dir" \
"${SPROG} rtag: Tagging first-dir"
	  # try accidentally converting non-branch tag to branch tag (tag -F -B -b)
	  dotest tagf-21 "${testcvs} tag -F -B -b regulartag file1" \
"${SPROG} tag: file1: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.4\.1\.0\.2 due to .-B. option\."
	  # try accidentally converting non-branch tag to branch rtag (rtag -F -B -b)
	  dotest tagf-22 "${testcvs} rtag -F -B -b regulartag first-dir" \
"${SPROG} rtag: Tagging first-dir
${SPROG} rtag: first-dir/file1: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.0\.6 due to .-B. option\.
${SPROG} rtag: first-dir/file2: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.0\.4 due to .-B. option\."
	  # Try accidentally deleting non-branch: (tag -d -B)
	  dotest_fail tagf-23 "${testcvs} tag -d -B regulartag file1" \
"${SPROG} tag: Not removing non-branch tag .regulartag. from .${CVSROOT_DIRNAME}/first-dir/file1,v. due to .-B. option\."
	  # Try accidentally deleting non-branch: (rtag -d -B)
	  dotest_fail tagf-24 \
		"${testcvs} rtag -d -B regulartag first-dir" \
"${SPROG} rtag: Untagging first-dir
${SPROG} rtag: Not removing non-branch tag .regulartag. from .${CVSROOT_DIRNAME}/first-dir/file1,v. due to .-B. option\.
${SPROG} rtag: Not removing non-branch tag .regulartag. from .${CVSROOT_DIRNAME}/first-dir/file2,v. due to .-B. option\."

	  # the following tests (throught the next commit) keep moving the same
	  # tag back and forth between 1.1.6 & 1.1.8  in file1 and between
	  # 1.1.4 and 1.1.6 in file2 since nothing was checked in on some of
	  # these branches and CVS only tracks branches via tags unless they contain data.

	  # try intentionally converting non-branch tag to branch tag (tag -F -b)
	  dotest tagf-25a "${testcvs} tag -F -b regulartag file1" "T file1"
	  # try intentionally moving a branch tag to a newly created branch (tag -F -b -B)
	  dotest tagf-25b "${testcvs} tag -F -B -b -r1.1 regulartag file1" \
"T file1"
	  # try intentionally converting mixed tags to branch tags (rtag -F -b)
	  dotest tagf-26a "${testcvs} rtag -F -b regulartag first-dir" \
"${SPROG} rtag: Tagging first-dir
${SPROG} rtag: first-dir/file1: Not moving branch tag .regulartag. from 1\.1 to 1\.1\.0\.8\."
	  # try intentionally converting a branch to a new branch tag (rtag -F -b -B)
	  dotest tagf-26b "${testcvs} rtag -F -B -b -r1.1 regulartag first-dir" \
"${SPROG} rtag: Tagging first-dir"
	  # update to our new branch
	  dotest tagf-27 "${testcvs} update -r regulartag" \
"${SPROG} update: Updating \.
U file1
U file2"
	  # commit some changes and see that all rev numbers look right
	  echo changes >> file1
	  echo changes >> file2
	  dotest tagf-28 "${testcvs} ci -m changes" \
"${CPROG} commit: Examining \.
${CVSROOT_DIRNAME}/first-dir/file1,v  <--  file1
new revision: 1\.1\.8\.1; previous revision: 1\.1
${CVSROOT_DIRNAME}/first-dir/file2,v  <--  file2
new revision: 1\.1\.6\.1; previous revision: 1\.1"
	  # try intentional branch to non-branch (tag -F -B)
	  dotest tagf-29 "${testcvs} tag -F -B -r1.1 regulartag file1" \
"T file1"
	  # try non-branch to non-branch (tag -F -B)
	  dotest tagf-29a "${testcvs} tag -F -B -r br regulartag file1" \
"${SPROG} tag: file1: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.4\.1 due to .-B. option\."
	  # try mixed-branch to non-branch (rtag -F -B )
	  dotest tagf-29b "${testcvs} rtag -F -B -r br regulartag first-dir" \
"${SPROG} rtag: Tagging first-dir
${SPROG} rtag: first-dir/file1: Not moving non-branch tag .regulartag. from 1\.1 to 1\.1\.4\.1 due to .-B. option\."
	  # at this point, regulartag is a regular tag within
	  # file1 and file2

	  # try intentional branch to non-branch (rtag -F -B)
	  dotest tagf-30 "${testcvs} rtag -F -B -r1.1 br first-dir"  \
"${SPROG} rtag: Tagging first-dir"
	  # create a branch tag so we can try to delete it.
	  dotest tagf-31 "${testcvs} rtag -b brtag first-dir"  \
"${SPROG} rtag: Tagging first-dir"
	
	  # try intentinal deletion of branch tag (tag -d -B)
	  dotest tagf-32 "${testcvs} tag -d -B brtag file1" "D file1"
	  # try intentinal deletion of branch tag (rtag -d -B)
	  dotest tagf-33 "${testcvs} rtag -d -B brtag first-dir" \
"${SPROG} rtag: Untagging first-dir"

	  dokeep
	  cd ../..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	tag-space)
	  # Test tags with spaces in the names.
	  #
	  # Prior to releases 1.11.18 & 1.12.10, some commands used with
	  # tags with spaces in the names could hang CVS.

	  # Setup; check in first-dir/file1
	  mkdir 1; cd 1
	  dotest tag-space-init-1 "$testcvs -q co -l ."
	  mkdir first-dir
	  dotest tag-space-init-2 "$testcvs add first-dir" \
"Directory $CVSROOT_DIRNAME/first-dir added to the repository"
	  cd first-dir
	  touch file1
	  dotest tag-space-init-3 "$testcvs add file1" \
"$SPROG add: scheduling file \`file1' for addition
$SPROG add: use \`$SPROG commit' to add this file permanently"
	  dotest tag-space-init-4 "$testcvs -Q ci -m add"

	  # Reportedly, the following two tags make it past WinCVS.
	  dotest_fail tag-space-1 "$testcvs tag ' spacetag '" \
"$SPROG \[tag aborted\]: tag \` spacetag ' must start with a letter"
	  dotest_fail tag-space-2 "$testcvs tag 'spacetag '" \
"$SPROG \[tag aborted\]: tag \`spacetag ' has non-visible graphic characters"

	  if $remote; then
	    # Verify that this isn't a client check.
	    dotest tag-space-3 "$testcvs server" \
"E $SPROG \[tag aborted\]: tag \` spacetag ' must start with a letter
error  " <<EOF
Root $CVSROOT_DIRNAME
UseUnchanged
Argument --
Argument  spacetag 
Directory .
$CVSROOT_DIRNAME/first-dir
Entry /file1/1.1///
Unchanged file1
tag
EOF

	    dotest tag-space-4 "$testcvs server" \
"E $SPROG \[tag aborted\]: tag \`spacetag ' has non-visible graphic characters
error  " <<EOF
Root $CVSROOT_DIRNAME
UseUnchanged
Argument --
Argument spacetag 
Directory .
$CVSROOT_DIRNAME/first-dir
Entry /file1/1.1///
Unchanged file1
tag
EOF
	  fi # $remote

	  # Any number of normal tags and branches were handled correctly.
	  dotest tag-space-5 "$testcvs -Q tag t1"
	  dotest tag-space-5b "$testcvs -Q tag t2"
	  dotest tag-space-5c "$testcvs -Q tag -b b1"

	  cd ../..
	  mkdir 2; cd 2

	  # But once a vendor branch exists, it's all over.
	  mkdir project; cd project
	  touch file1
	  dotest tag-space-init-4 \
"$testcvs -Q import -mimport second-dir VENDOR RELEASE"

	  cd ..

	  dotest_fail tag-space-6 "$testcvs -Q co -r ' spacetag ' first-dir" \
"$SPROG \[checkout aborted\]: tag \` spacetag ' must start with a letter"

	  # But when any files were imported, this test hung prior to CVS
	  # versions 1.11.18 & 1.12.10.
	  dotest_fail tag-space-7 "$testcvs -Q co -r ' spacetag ' second-dir" \
"$SPROG \[checkout aborted\]: tag \` spacetag ' must start with a letter"

	  if $remote; then
	    # I based the client input in the next two tests on actual input
	    # from WinCVS 1.2.
	    dotest tag-space-8 "$testcvs server" \
"E $SPROG \[checkout aborted\]: tag \` spacetag ' must start with a letter
error  " <<EOF
Root $CVSROOT_DIRNAME
Argument -P
Argument -r
Argument  spacetag 
Argument first-dir
Directory .
$CVSROOT_DIRNAME
co
EOF

	    # Verify the test is not on the client side.
	    dotest tag-space-9 "$testcvs server" \
"E $SPROG \[checkout aborted\]: tag \` spacetag ' must start with a letter
error  " <<EOF
Root $CVSROOT_DIRNAME
Argument -P
Argument -r
Argument  spacetag 
Argument second-dir
Directory .
$CVSROOT_DIRNAME
co
EOF
	  fi # $remote

	  dotest tag-space-10 "$testcvs -Q co second-dir"
	  cd second-dir

	  # This test would also hang.
	  dotest_fail tag-space-11 "$testcvs -Q up -r ' spacetag '" \
"$SPROG \[update aborted\]: tag \` spacetag ' must start with a letter"

	  if $remote; then
	    dotest tag-space-12 "$testcvs server" \
"E $SPROG \[update aborted\]: tag \` spacetag ' must start with a letter
error  " <<EOF
Root $CVSROOT_DIRNAME
Argument -r
Argument  spacetag 
Argument -u
Argument --
Directory .
$CVSROOT_DIRNAME
Unchanged file1
update
EOF
	  fi # $remote

	  # I'm skipping tests for other commands that may have had the same
	  # problem.  Hopefully, if a new issue arises, one of the above tests
	  # will catch the problem.

	  if $keep; then
	    echo Keeping $TESTDIR and exiting due to --keep
	    exit 0
	  fi

	  cd ../..
	  rm -r 1 2
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
	                     $CVSROOT_DIRNAME/second-dir
	  ;;



	rcslib)
	  # Test librarification of RCS.
	  # First: test whether `cvs diff' handles $Name expansion
	  # correctly.	We diff two revisions with their symbolic tags;
	  # neither tag should be expanded in the output.  Also diff
	  # one revision with the working copy.

	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  dotest rcsdiff-1 "${testcvs} -q co first-dir" ''
	  cd first-dir
	  echo "I am the first foo, and my name is $""Name$." > foo.c
	  dotest rcsdiff-2 "${testcvs} add -m new-file foo.c" \
"${SPROG} add: scheduling file .foo\.c. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest rcsdiff-3 "${testcvs} commit -m rev1 foo.c" \
"${CVSROOT_DIRNAME}/first-dir/foo.c,v  <--  foo\.c
initial revision: 1\.1"
	  dotest rcsdiff-4 "${testcvs} tag first foo.c" "T foo\.c"
	  dotest rcsdiff-5 "${testcvs} update -p -r first foo.c" \
"===================================================================
Checking out foo\.c
RCS:  ${CVSROOT_DIRNAME}/first-dir/foo\.c,v
VERS: 1\.1
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
I am the first foo, and my name is \$""Name: first \$\."

	  echo "I am the second foo, and my name is $""Name$." > foo.c
	  dotest rcsdiff-6 "${testcvs} commit -m rev2 foo.c" \
"${CVSROOT_DIRNAME}/first-dir/foo\.c,v  <--  foo\.c
new revision: 1\.2; previous revision: 1\.1"
	  dotest rcsdiff-7 "${testcvs} tag second foo.c" "T foo\.c"
	  dotest rcsdiff-8 "${testcvs} update -p -r second foo.c" \
"===================================================================
Checking out foo\.c
RCS:  ${CVSROOT_DIRNAME}/first-dir/foo\.c,v
VERS: 1\.2
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
I am the second foo, and my name is \$""Name: second \$\."

	dotest_fail rcsdiff-9 "${testcvs} diff -r first -r second" \
"${SPROG} diff: Diffing \.
Index: foo\.c
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/foo\.c,v
retrieving revision 1\.1
retrieving revision 1\.2
diff -r1\.1 -r1\.2
1c1
< I am the first foo, and my name is \$""Name:  \$\.
---
> I am the second foo, and my name is \$""Name:  \$\."

	  echo "I am the once and future foo, and my name is $""Name$." > foo.c
	  dotest_fail rcsdiff-10 "${testcvs} diff -r first" \
"${SPROG} diff: Diffing \.
Index: foo\.c
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/foo\.c,v
retrieving revision 1\.1
diff -r1\.1 foo\.c
1c1
< I am the first foo, and my name is \$""Name:  \$\.
---
> I am the once and future foo, and my name is \$""Name\$\."

	  # Test handling of libdiff options.  diff gets quite enough
	  # of a workout elsewhere in sanity.sh, so we assume that it's
	  # mostly working properly if it passes all the other tests.
	  # The main one we want to try is regex handling, since we are
	  # using CVS's regex matcher and not diff's.

	  cat >rgx.c <<EOF
test_regex (whiz, bang)
{
foo;
bar;
baz;
grumble;
}
EOF

	  dotest rcslib-diffrgx-1 "${testcvs} -q add -m '' rgx.c" \
"${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest rcslib-diffrgx-2 "${testcvs} -q ci -m '' rgx.c" \
"$CVSROOT_DIRNAME/first-dir/rgx\.c,v  <--  rgx\.c
initial revision: 1\.1"
	  cat >rgx.c <<EOF
test_regex (whiz, bang)
{
foo;
bar;
baz;
mumble;
}
EOF
	  # Use dotest_fail because exit status from `cvs diff' must be 1.
	  #
	  # Incidentally test that CVS no longer splits diff arguments on
	  # spaces.
	  dotest_fail rcslib-diffrgx-3 "$testcvs diff -c -F'.* (' rgx.c" \
"Index: rgx\.c
===================================================================
RCS file: ${CVSROOT_DIRNAME}/first-dir/rgx\.c,v
retrieving revision 1\.1
diff -c -F '\.\* (' -r1\.1 rgx\.c
\*\*\* rgx\.c	${RFCDATE}	1\.1
--- rgx\.c	${RFCDATE}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* test_regex (whiz, bang)
\*\*\* 3,7 \*\*\*\*
  foo;
  bar;
  baz;
! grumble;
  }
--- 3,7 ----
  foo;
  bar;
  baz;
! mumble;
  }"

	  # Tests of rcsmerge/diff3.  Merge operations get a good general
	  # workout elsewhere; we want to make sure that options are still
	  # handled properly.  Try merging two branches with -kv, to test
	  # both -j and -k switches.

	  cd ..

	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  rm -r first-dir

	  mkdir 1; cd 1
	  dotest rcslib-merge-1 "$testcvs -q co -l ."
	  mkdir first-dir
	  dotest rcslib-merge-2 "$testcvs -q add first-dir" \
"Directory $CVSROOT_DIRNAME.*/first-dir added to the repository"
	  cd ..; rm -r 1

	  dotest rcslib-merge-3 "$testcvs -q co first-dir" ""
	  cd first-dir

	  echo '$''Revision$' > file1
	  echo '2' >> file1
	  echo '3' >> file1
	  dotest rcslib-merge-4 "${testcvs} -q add file1" \
"${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest rcslib-merge-5 "${testcvs} -q commit -m '' file1" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1"
	  sed -e 's/2/two/' file1 > f; mv f file1
	  dotest rcslib-merge-6 "${testcvs} -q commit -m '' file1" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.2; previous revision: 1\.1"
	  dotest rcslib-merge-7 "${testcvs} -q tag -b -r 1.1 patch1" "T file1"
	  dotest rcslib-merge-8 "${testcvs} -q update -r patch1" "[UP] file1"
	  dotest rcslib-merge-9 "${testcvs} -q status" \
"===================================================================
File: file1            	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file1,v
   Commit Identifier:	${commitid}
   Sticky Tag:		patch1 (branch: 1\.1\.2)
   Sticky Date:		(none)
   Sticky Options:	(none)"
	  dotest rcslib-merge-10 "cat file1" \
'$''Revision: 1\.1 $
2
3'
	  sed -e 's/3/three/' file1 > f; mv f file1
	  dotest rcslib-merge-11 "${testcvs} -q commit -m '' file1" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.1\.2\.1; previous revision: 1\.1"
	  dotest rcslib-merge-12 "${testcvs} -q update -kv -j1.2" \
"U file1
RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into file1
rcsmerge: warning: conflicts during merge"
	  dotest rcslib-merge-13 "cat file1" \
"<<<<<<< file1
1\.1\.2\.1
2
three
[=]======
1\.2
two
3
[>]>>>>>> 1\.2"

	  # Test behavior of symlinks in the repository.
	  if test -n "$remotehost"; then
	    # Create the link on the remote system.  This is because Cygwin's
	    # Windows support creates *.lnk files for Windows.  When creating
	    # these in an SMB share from UNIX, these links won't work from the
	    # UNIX side.
	    modify_repo $CVS_RSH $remotehost "'ln -s file1,v $CVSROOT_DIRNAME/first-dir/file2,v'"
	  else
	    modify_repo ln -s file1,v $CVSROOT_DIRNAME/first-dir/file2,v
	  fi
	  dotest rcslib-symlink-2 "$testcvs update file2" "U file2"
	  echo "This is a change" >> file2
	  dotest rcslib-symlink-3 "$testcvs ci -m because file2" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file2
new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"

	  # Switch as for rcslib-symlink-1
	  if test -n "$remotehost"; then
	    dotest rcslib-symlink-4 "$CVS_RSH $remotehost 'ls -l $CVSROOT_DIRNAME/first-dir/file2,v'" \
".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v"
	  else
	    dotest rcslib-symlink-4 "ls -l $CVSROOT_DIRNAME/first-dir/file2,v" \
".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v"
	  fi

	  # CVS was failing to check both the symlink and the file
	  # for timestamp changes for a while.  Test that.
	  rm file1
	  dotest rcslib-symlink-3a "${testcvs} -q up file1" \
"${SPROG} update: warning: \`file1' was lost
U file1"
	  echo "This is a change" >> file1
	  dotest rcslib-symlink-3b "${testcvs} ci -m because file1" \
"${CVSROOT_DIRNAME}/first-dir/file1,v  <--  file1
new revision: 1\.1\.2\.[0-9]*; previous revision: 1\.1\.2\.[0-9]*"
	  dotest rcslib-symlink-3c "${testcvs} update file2" "[UP] file2"

	  echo some new text >file3
	  dotest rcslib-symlink-3d "${testcvs} -Q add file3" ''
	  dotest rcslib-symlink-3e "$testcvs -Q ci -mtest file3"

	  rm -f ${CVSROOT_DIRNAME}/first-dir/file2,v
	  # As for rcslib-symlink-1
	  if test -n "$remotehost"; then
	    modify_repo "$CVS_RSH $remotehost 'ln -s Attic/file3,v $CVSROOT_DIRNAME/first-dir/file2,v'"
	  else
	    modify_repo ln -s Attic/file3,v $CVSROOT_DIRNAME/first-dir/file2,v
	  fi

	  dotest rcslib-symlink-3g "$testcvs update file2" "U file2"

	  # restore the link to file1 for the following tests
	  dotest rcslib-symlink-3i "$testcvs -Q rm -f file3" ''
	  dotest rcslib-symlink-3j "$testcvs -Q ci -mwhatever file3"
	  rm -f $CVSROOT_DIRNAME/first-dir/file2,v
	  rm -f $CVSROOT_DIRNAME/first-dir/Attic/file3,v
	  # As for rcslib-symlink-1
	  if test -n "$remotehost"; then
	    modify_repo "$CVS_RSH $remotehost 'ln -s file1,v $CVSROOT_DIRNAME/first-dir/file2,v'"
	  else
	    modify_repo ln -s file1,v $CVSROOT_DIRNAME/first-dir/file2,v
	  fi

	  # Test 5 reveals a problem with having symlinks in the
	  # repository.  CVS will try to tag both of the files
	  # separately.  After processing one, it will do the same
	  # operation to the other, which is actually the same file,
	  # so the tag will already be there.  FIXME: do we bother
	  # changing operations to notice cases like this?  This
	  # strikes me as a difficult problem.  -Noel
	  dotest rcslib-symlink-5 "$testcvs tag the_tag" \
"$SPROG tag: Tagging .
T file1
W file2 : the_tag already exists on version 1.1.2.3 : NOT MOVING tag to version 1.1.2.1"
	  # As for rcslib-symlink-1
	  if test -n "$remotehost"; then
	    dotest rcslib-symlink-6 "$CVS_RSH $remotehost 'ls -l $CVSROOT_DIRNAME/first-dir/file2,v'" \
".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v"
	  else
	    dotest rcslib-symlink-6 "ls -l $CVSROOT_DIRNAME/first-dir/file2,v" \
".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v"
	  fi

	  # Symlinks tend to interact poorly with the Attic.
	  cd ..
	  mkdir 2; cd 2
	  dotest rcslib-symlink-7 "$testcvs -q co first-dir" \
"U first-dir/file1
U first-dir/file2"
	  cd first-dir
	  dotest rcslib-symlink-8 "$testcvs rm -f file2" \
"$SPROG remove: scheduling .file2. for removal
$SPROG remove: use .$SPROG commit. to remove this file permanently"
	  dotest rcslib-symlink-9 "$testcvs -q ci -m rm-it" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file2
new revision: delete; previous revision: 1\.2"
	  # OK, why this message happens twice is relatively clear
	  # (the check_* and rtag_* calls to start_recursion).
	  # Why it happens a third time I didn't try to find out.
	  #
	  # DRP: One of the error messages disappeared while I was making
	  # proxy modifications.  Until I detect a deeper issue, I'm not
	  # going to stress over it.
	  #
	  # DRP: Both messages disappear starting with glibc 2.3.3 due to a bug
	  # in the glob function which causes it to fail to return broken
	  # symlinks.  I'm submitting a bug fix to glibc which will hopefully
	  # be released with glibc 2.3.6.  Once it is released and versions
	  # 2.3.3-2.3.5 of glibc become uncommon, the first, empty case below
	  # should be removed again.
	  dotest rcslib-symlink-10 \
"$testcvs -q rtag -b -r the_tag brtag first-dir" "" \
"$SPROG rtag: could not read RCS file for first-dir/file2
$SPROG rtag: could not read RCS file for first-dir/file2"

	  # Restore file1 for the next test.
	  dotest rcslib-long-symlink-init-1 "$testcvs -Q up -A"
	  dotest rcslib-long-symlink-init-2 "$testcvs -Q add file1"
	  dotest rcslib-long-symlink-init-3 "$testcvs -Q ci -mback"

	  cd ../..  # $TESTDIR

	  # CVS has a hard-coded default link path size of 127 characters.
	  # Make sure it knows how to exceed that.
	  longpath=$CVSROOT_DIRNAME
	  count=0
	  while test $count -lt 10; do
	    # 10 * 30 characters + len $CVSROOT_DIRNAME
	    count=`expr $count + 1`
	    longpath=$longpath/123456789012345678901234567890
	    modify_repo mkdir $longpath
	  done
	  modify_repo cp $CVSROOT_DIRNAME/first-dir/file1,v $longpath
	  modify_repo mkdir $CVSROOT_DIRNAME/second-dir

	  # Switch as for rcslib-symlink-1
	  if test -n "$remotehost"; then
	    modify_repo $CVS_RSH $remotehost \
	    'ln -s $longpath/file1,v $CVSROOT_DIRNAME/second-dir/fileX,v'
	  else
	    modify_repo ln -s $longpath/file1,v \
			      $CVSROOT_DIRNAME/second-dir/fileX,v
	  fi

	  dotest rcslib-long-symlink-2 "$testcvs co second-dir" \
"$SPROG checkout: Updating second-dir
U second-dir/fileX"

	  cd second-dir
	  echo change-it >>fileX

	  # Writes actually cause symlinks to be resolved.
	  dotest rcslib-long-symlink-3 "$testcvs -q ci -mwrite-it" \
"$CVSROOT_DIRNAME/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/file1,v  <--  fileX
new revision: 1\.5; previous revision: 1\.4"

	  dokeep
	  cd ..

	  # Must remove the symlink first.  Samba doesn't appear to show
	  # broken symlink across the SMB share, and rm -rf by itself
	  # will remove file1,v first and leave file2,v a broken link and the
	  # rm -rf will fail since it doesn't find file2,v and it still gets
	  # directory not empty errors removing cvsroot/first-dir.
	  #
	  # I'm not sure why I need to do this on $remotehost.  The rm above
	  # rcslib-symlink-3j works fine, but the next one doesn't unless run
	  # remotely under Cygwin and using a TESTDIR on a Samba share.
	  if test -n "$remotehost"; then
	    $CVS_RSH $remotehost \
"rm -f $CVSROOT_DIRNAME/first-dir/file2,v $CVSROOT_DIRNAME/second-dir/fileX,v"
	  fi
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
			     $CVSROOT_DIRNAME/second-dir \
			     $CVSROOT_DIRNAME/123456789012345678901234567890
	  rm -r first-dir second-dir 2
	  ;;



	multibranch)
	  # Test the ability to have several branchpoints coming off the
	  # same revision.
	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  dotest multibranch-1 "${testcvs} -q co first-dir" ''
	  cd first-dir
	  echo 1:trunk-1 >file1
	  dotest multibranch-2 "${testcvs} add file1" \
"${SPROG}"' add: scheduling file `file1'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
	  dotest_lit multibranch-3 "${testcvs} -q ci -m add-it" <<HERE
$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1.1
HERE
	  dotest multibranch-4 "${testcvs} tag -b br1" \
"${SPROG} tag: Tagging \.
T file1"
	  dotest multibranch-5 "${testcvs} tag -b br2" \
"${SPROG} tag: Tagging \.
T file1"
	  dotest multibranch-6 "${testcvs} -q update -r br1" ''
	  echo on-br1 >file1
	  dotest multibranch-7 "${testcvs} -q ci -m modify-on-br1" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.1\.2\.1; previous revision: 1\.1"
	  dotest multibranch-8 "${testcvs} -q update -r br2" '[UP] file1'
	  echo br2 adds a line >>file1
	  dotest multibranch-9 "${testcvs} -q ci -m modify-on-br2" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.1\.4\.1; previous revision: 1\.1"
	  dotest multibranch-10 "${testcvs} -q update -r br1" '[UP] file1'
	  dotest multibranch-11 "cat file1" 'on-br1'
	  dotest multibranch-12 "${testcvs} -q update -r br2" '[UP] file1'
	  dotest multibranch-13 "cat file1" '1:trunk-1
br2 adds a line'

	  dotest multibranch-14 "${testcvs} log file1" \
"
RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
Working file: file1
head: 1\.1
branch:
locks: strict
access list:
symbolic names:
	br2: 1\.1\.0\.4
	br1: 1\.1\.0\.2
keyword substitution: kv
total revisions: 3;	selected revisions: 3
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
branches:  1\.1\.2;  1\.1\.4;
add-it
----------------------------
revision 1\.1\.4\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  commitid: ${commitid};
modify-on-br2
----------------------------
revision 1\.1\.2\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  commitid: ${commitid};
modify-on-br1
============================================================================="

	  dokeep
	  cd ..
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  rm -r first-dir
	  ;;



	import) # test death after import
		# Tests of "cvs import":
		# basic2
		# rdiff  -- imports with keywords
		# import  -- more tests of imports with keywords
		# importb  -- -b option.
		# importc -- bunch o' files in bunch o' directories
		# importX  -- -X option.
		# importX2 -- CVSROOT/config ImportNewFilesToVendorBranchOnly
		#             flag
		# modules3
		# mflag -- various -m messages
		# ignore  -- import and cvsignore
		# binwrap -- import and -k wrappers
		# info -- imports which are rejected by verifymsg
		# head -- intended to test vendor branches and HEAD,
		#   although it doesn't really do it yet.
		# import-CVS -- refuse to import directories named "CVS".
		# import-quirks -- short tests of import quirks.

		# import
		mkdir import-dir ; cd import-dir

		for i in 1 2 3 4 ; do
		  echo imported file"$i" > imported-f"$i"
		done

		# This directory should be on the default ignore list,
		# so it shouldn't get imported.
		mkdir RCS
		echo ignore.me >RCS/ignore.me

		echo 'import should not expand $''Id$' >>imported-f2
		cp imported-f2 ../imported-f2-orig.tmp

		dotest_sort import-96 \
"${testcvs} import -m first-import first-dir vendor-branch junk-1_0" \
"

I first-dir/RCS
N first-dir/imported-f1
N first-dir/imported-f2
N first-dir/imported-f3
N first-dir/imported-f4
No conflicts created by this import"

		dotest import-96.5 "cmp ../imported-f2-orig.tmp imported-f2" ''

		cd ..

		# co
		dotest import-97 "${testcvs} -q co first-dir" \
"U first-dir/imported-f1
U first-dir/imported-f2
U first-dir/imported-f3
U first-dir/imported-f4"

		cd first-dir

		for i in 1 2 3 4 ; do
		  dotest import-98-$i "test -f imported-f$i" ''
		done
		dotest_fail import-98.5 "test -d RCS" ''

		# remove
		rm imported-f1
		dotest import-99 "${testcvs} rm imported-f1" \
"${SPROG}"' remove: scheduling `imported-f1'\'' for removal
'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove this file permanently'

		# change
		echo local-change >> imported-f2

		# commit
		dotest import-100 "${testcvs} ci -m local-changes" \
"${CPROG} commit: Examining .
${CVSROOT_DIRNAME}/first-dir/imported-f1,v  <--  imported-f1
new revision: delete; previous revision: 1\.1\.1\.1
${CVSROOT_DIRNAME}/first-dir/imported-f2,v  <--  imported-f2
new revision: 1\.2; previous revision: 1\.1"

		# log
		dotest import-101 "${testcvs} log imported-f1" \
"
RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/imported-f1,v
Working file: imported-f1
head: 1\.2
branch:
locks: strict
access list:
symbolic names:
	junk-1_0: 1\.1\.1\.1
	vendor-branch: 1\.1\.1
keyword substitution: kv
total revisions: 3;	selected revisions: 3
description:
----------------------------
revision 1\.2
date: ${ISO8601DATE};  author: ${username};  state: dead;  lines: ${PLUS}0 -0;  commitid: ${commitid};
local-changes
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
branches:  1\.1\.1;
Initial revision
----------------------------
revision 1\.1\.1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0;  commitid: ${commitid};
first-import
============================================================================="

		# update into the vendor branch.
		dotest import-102 "${testcvs} update -rvendor-branch" \
"${SPROG} update: Updating .
[UP] imported-f1
[UP] imported-f2"

		# remove file4 on the vendor branch
		rm imported-f4
		dotest import-103 "${testcvs} rm imported-f4" \
"${SPROG}"' remove: scheduling `imported-f4'\'' for removal
'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove this file permanently'

		# commit
		dotest import-104 \
"${testcvs} ci -m vendor-removed imported-f4" \
"${CVSROOT_DIRNAME}/first-dir/imported-f4,v  <--  imported-f4
new revision: delete; previous revision: 1\.1\.1\.1"

		# update to main line
		dotest import-105 "${testcvs} -q update -A" \
"${SPROG} update: \`imported-f1' is no longer in the repository
[UP] imported-f2"

		# second import - file4 deliberately unchanged
		cd ../import-dir
		for i in 1 2 3 ; do
		  echo rev 2 of file $i >> imported-f"$i"
		done
		cp imported-f2 ../imported-f2-orig.tmp

		dotest_sort import-106 \
"${testcvs} import -m second-import first-dir vendor-branch junk-2_0" \
"


 ${CPROG} checkout -j<prev_rel_tag> -jjunk-2_0 first-dir
2 conflicts created by this import.
C first-dir/imported-f1
C first-dir/imported-f2
I first-dir/RCS
U first-dir/imported-f3
U first-dir/imported-f4
Use the following command to help the merge:"

		dotest import-106.5 "cmp ../imported-f2-orig.tmp imported-f2" \
''

		cd ..

		rm imported-f2-orig.tmp

		# co
		dotest import-107 "${testcvs} co first-dir" \
"${SPROG} checkout: Updating first-dir
[UP] first-dir/imported-f3
[UP] first-dir/imported-f4"

		cd first-dir

		dotest_fail import-108 "test -f imported-f1" ''

		for i in 2 3 ; do
		  dotest import-109-$i "test -f imported-f$i" ''
		done

		# check vendor branch for file4
		dotest import-110 "${testcvs} -q update -rvendor-branch" \
"[UP] imported-f1
[UP] imported-f2"

		dotest import-111 "test -f imported-f4" ''

		# update to main line
		dotest import-112 "${testcvs} -q update -A" \
"${SPROG} update: \`imported-f1' is no longer in the repository
[UP] imported-f2"

		cd ..

		dotest import-113 \
"${testcvs} -q co -jjunk-1_0 -jjunk-2_0 first-dir" \
"${SPROG} checkout: file first-dir/imported-f1 does not exist, but is present in revision junk-2_0
RCS file: ${CVSROOT_DIRNAME}/first-dir/imported-f2,v
retrieving revision 1\.1\.1\.1
retrieving revision 1\.1\.1\.2
Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into imported-f2
rcsmerge: warning: conflicts during merge
first-dir/imported-f3 already contains the differences between 1\.1\.1\.1 and 1\.1\.1\.2
first-dir/imported-f4 already contains the differences between 1\.1\.1\.1 and 1\.1\.1\.3"

		cd first-dir

		dotest_fail import-114 "test -f imported-f1" ''

		for i in 2 3 ; do
		  dotest import-115-$i "test -f imported-f$i" ''
		done

		dotest import-116 'cat imported-f2' \
'imported file2
[<]<<<<<< imported-f2
import should not expand \$''Id: imported-f2,v 1\.2 [0-9/]* [0-9:]* '"${username}"' Exp \$
local-change
[=]======
import should not expand \$''Id: imported-f2,v 1\.1\.1\.2 [0-9/]* [0-9:]* '"${username}"' Exp \$
rev 2 of file 2
[>]>>>>>> 1\.1\.1\.2'

		dokeep
		cd ..
		rm -r first-dir
		modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
		rm -r import-dir
		;;



	importb)
	  # More cvs import tests, especially -b option.

	  # OK, first we get some sources from the NetMunger project, and
	  # import them into the 1.1.1 vendor branch.
	  mkdir imp-dir
	  cd imp-dir
	  echo 'OpenMunger sources' >file1
	  echo 'OpenMunger sources' >file2
	  dotest_sort importb-1 \
"${testcvs} import -m add first-dir openmunger openmunger-1_0" \
"

N first-dir/file1
N first-dir/file2
No conflicts created by this import"
	  cd ..
	  rm -r imp-dir

	  # Now we put the sources we get from FreeMunger into 1.1.3
	  mkdir imp-dir
	  cd imp-dir
	  echo 'FreeMunger sources' >file1
	  echo 'FreeMunger sources' >file2
	  # Not completely sure how the conflict detection is supposed to
	  # be working here (haven't really thought about it).
	  # We use an explicit -d option to test that it is reflected
	  # in the suggested checkout.
	  dotest_sort importb-2 \
"$testcvs -d '$CVSROOT' import -m add -b 1.1.3 \
          first-dir freemunger freemunger-1_0" \
"


 ${CPROG} -d ${CVSROOT} checkout -j<prev_rel_tag> -jfreemunger-1_0 first-dir
2 conflicts created by this import.
C first-dir/file1
C first-dir/file2
Use the following command to help the merge:"
	  cd ..
	  rm -r imp-dir

	  # Now a test of main branch import (into second-dir, not first-dir).
	  mkdir imp-dir
	  cd imp-dir
	  echo 'my own stuff' >mine1.c
	  echo 'my own stuff' >mine2.c
	  dotest_fail importb-3 \
"${testcvs} import -m add -b 1 second-dir dummy really_dumb_y" \
"$CPROG \[import aborted\]: Only numeric branch specifications with two dots are
supported by import, not \`1'\.  For example: \`1\.1\.1'\."
	  : when we implement main-branch import, should be \
"N second-dir/mine1\.c
N second-dir/mine2\.c

No conflicts created by this import"
	  cd ..
	  rm -r imp-dir

	  mkdir 1
	  cd 1
	  # when we implement main branch import, will want to 
	  # add "second-dir" here.
	  dotest importb-4 "${testcvs} -q co first-dir" \
"U first-dir/file1
U first-dir/file2"
	  cd first-dir
	  dotest importb-5 "${testcvs} -q log file1" "
RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
Working file: file1
head: 1\.1
branch: 1\.1\.1
locks: strict
access list:
symbolic names:
	freemunger-1_0: 1\.1\.3\.1
	freemunger: 1\.1\.3
	openmunger-1_0: 1\.1\.1\.1
	openmunger: 1\.1\.1
keyword substitution: kv
total revisions: 3;	selected revisions: 3
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
branches:  1\.1\.1;  1\.1\.3;
Initial revision
----------------------------
revision 1\.1\.3\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  commitid: ${commitid};
add
----------------------------
revision 1\.1\.1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0;  commitid: ${commitid};
add
============================================================================="

	  dokeep
	  cd ../..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
			     $CVSROOT_DIRNAME/second-dir
	  ;;



	importc)
	  # Test importing a bunch o' files in a bunch o' directories.
	  # Also the -d option.

	  # Set a predictable time zone for these tests.
	  save_TZ=$TZ
	  TZ=UTC0; export TZ

	  mkdir 1; cd 1
	  mkdir adir bdir cdir
	  mkdir adir/sub1 adir/sub2
	  mkdir adir/sub1/ssdir
	  mkdir bdir/subdir
	  touch adir/sub1/file1 adir/sub2/file2 adir/sub1/ssdir/ssfile
	  touch -t ${TOUCH1971} bdir/subdir/file1
	  touch -t ${TOUCH2034} cdir/cfile
	  dotest_sort importc-1 \
"${testcvs} import -d -m import-it first-dir vendor release" \
"

N first-dir/adir/sub1/file1
N first-dir/adir/sub1/ssdir/ssfile
N first-dir/adir/sub2/file2
N first-dir/bdir/subdir/file1
N first-dir/cdir/cfile
No conflicts created by this import
${SPROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/adir
${SPROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/adir/sub1
${SPROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/adir/sub1/ssdir
${SPROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/adir/sub2
${SPROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/bdir
${SPROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/bdir/subdir
${SPROG} import: Importing ${CVSROOT_DIRNAME}/first-dir/cdir"
	  cd ..
	  mkdir 2; cd 2
	  dotest importc-2 "${testcvs} -q co first-dir" \
"U first-dir/adir/sub1/file1
U first-dir/adir/sub1/ssdir/ssfile
U first-dir/adir/sub2/file2
U first-dir/bdir/subdir/file1
U first-dir/cdir/cfile"
	  cd first-dir
	  dotest importc-3 "${testcvs} update adir/sub1" \
"${SPROG} update: Updating adir/sub1
${SPROG} update: Updating adir/sub1/ssdir"
	  dotest importc-4 "${testcvs} update adir/sub1 bdir/subdir" \
"${SPROG} update: Updating adir/sub1
${SPROG} update: Updating adir/sub1/ssdir
${SPROG} update: Updating bdir/subdir"

	  echo modify >>cdir/cfile
	  dotest importc-5 \
"${testcvs} -q rtag -b -r release wip_test first-dir" ""
	  dotest importc-6 "${testcvs} -q update -r wip_test" "M cdir/cfile"

	  # This used to fail in local mode
	  dotest importc-7 "${testcvs} -q ci -m modify -r wip_test" \
"$CVSROOT_DIRNAME/first-dir/cdir/cfile,v  <--  cdir/cfile
new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1"

	  # TODO: should also be testing "import -d" when we update
	  # an existing file.
	  dotest importc-8 "${testcvs} -q log cdir/cfile" "
RCS file: ${CVSROOT_DIRNAME}/first-dir/cdir/cfile,v
Working file: cdir/cfile
head: 1\.1
branch: 1\.1\.1
locks: strict
access list:
symbolic names:
	wip_test: 1\.1\.1\.1\.0\.2
	release: 1\.1\.1\.1
	vendor: 1\.1\.1
keyword substitution: kv
total revisions: 3;	selected revisions: 3
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE2034};  author: ${username};  state: Exp;  commitid: ${commitid};
branches:  1\.1\.1;
Initial revision
----------------------------
revision 1\.1\.1\.1
date: ${ISO8601DATE2034};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0;  commitid: ${commitid};
branches:  1\.1\.1\.1\.2;
import-it
----------------------------
revision 1\.1\.1\.1\.2\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  commitid: ${commitid};
modify
============================================================================="

	  dotest importc-9 "${testcvs} -q log bdir/subdir/file1" "
RCS file: ${CVSROOT_DIRNAME}/first-dir/bdir/subdir/file1,v
Working file: bdir/subdir/file1
head: 1\.1
branch: 1\.1\.1
locks: strict
access list:
symbolic names:
	wip_test: 1\.1\.1\.1\.0\.2
	release: 1\.1\.1\.1
	vendor: 1\.1\.1
keyword substitution: kv
total revisions: 2;	selected revisions: 2
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE1971};  author: ${username};  state: Exp;  commitid: ${commitid};
branches:  1\.1\.1;
Initial revision
----------------------------
revision 1\.1\.1\.1
date: ${ISO8601DATE1971};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0;  commitid: ${commitid};
import-it
============================================================================="
	  cd ..

	  # Now tests of absolute pathnames and .. as repository directory.
	  cd ../1
	  dotest_fail importc-10 \
"${testcvs} import -m imp ../other vendor release2" \
"${CPROG} \[import aborted\]: directory \.\./other not relative within the repository"
	  dotest_fail importc-11 \
"${testcvs} import -m imp ${TESTDIR}/other vendor release3" \
"${CPROG} \[import aborted\]: directory ${TESTDIR}/other not relative within the repository"
	  dotest_fail importc-12 "test -d ${TESTDIR}/other" ""

	  dokeep
	  TZ=$save_TZ
	  cd ..
	  rm -r 1 2
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	importX)
	  # More cvs import tests, especially -X option.

	  # OK, first we get some sources from the Munger version 0.9,
	  # and import them into the 1.1.1 vendor branch (w/o -X).  (This
	  # will be used to test subsequent imports of the same file
	  # with -X.)
	  mkdir imp-dir
	  cd imp-dir
	  echo 'Munger sources 0.9' >file0
	  dotest_sort importX-1 \
"${testcvs} import -m add first-dir munger munger-0_9" \
"

N first-dir/file0
No conflicts created by this import"
	  cd ..
	  rm -r imp-dir

	  # Now we put the sources we get from Munger version 1.0 on
	  # to the 1.1.1 vendor branch using -X.  (This imports a new
	  # version of file0, and imports all-new files file1 and file2.)
	  mkdir imp-dir
	  cd imp-dir
	  echo 'Munger sources' >file0
	  echo 'Munger sources' >file1
	  echo 'Munger sources' >file2
	  dotest_sort importX-2 \
"${testcvs} import -X -m add first-dir munger munger-1_0" \
"


 ${CPROG} checkout -j<prev_rel_tag> -jmunger-1_0 first-dir
N first-dir/file1
N first-dir/file2
No conflicts created by this import.
U first-dir/file0
Use the following command to help the merge:"
	  cd ..
	  rm -r imp-dir

	  # Now we put the sources we get from Munger version 1.1 on
	  # to the 1.1.1 vendor branch using -X.  (This imports unchanged
	  # versions of file0 and file2, a changed version of file1, and
	  # an all-new file3.)
	  mkdir imp-dir
	  cd imp-dir
	  echo 'Munger sources' >file0
	  echo 'Munger sources 1.1' >file1
	  echo 'Munger sources' >file2
	  echo 'Munger sources 1.1' >file3
	  dotest_sort importX-3 \
"$testcvs -d '$CVSROOT' import -X -m add first-dir munger munger-1_1" \
"


 ${CPROG} -d ${CVSROOT} checkout -j<prev_rel_tag> -jmunger-1_1 first-dir
1 conflicts created by this import.
C first-dir/file1
N first-dir/file3
U first-dir/file0
U first-dir/file2
Use the following command to help the merge:"
	  cd ..
	  rm -r imp-dir

	  mkdir 1
	  cd 1
	  # only file0 should be checked out
	  dotest importX-4 "${testcvs} -q co first-dir" \
"U first-dir/file0"
	  cd first-dir

	  dotest importX-5 "${testcvs} -q log file0" "
RCS file: ${CVSROOT_DIRNAME}/first-dir/file0,v
Working file: file0
head: 1\.1
branch: 1\.1\.1
locks: strict
access list:
symbolic names:
	munger-1_1: 1\.1\.1\.2
	munger-1_0: 1\.1\.1\.2
	munger-0_9: 1\.1\.1\.1
	munger: 1\.1\.1
keyword substitution: kv
total revisions: 3;	selected revisions: 3
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
branches:  1\.1\.1;
Initial revision
----------------------------
revision 1\.1\.1\.2
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  commitid: ${commitid};
add
----------------------------
revision 1\.1\.1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0;  commitid: ${commitid};
add
============================================================================="

	  dotest importX-6 "${testcvs} -q log file1" "
RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
Working file: file1
head: 1\.2
branch:
locks: strict
access list:
symbolic names:
	munger-1_1: 1\.1\.1\.2
	munger-1_0: 1\.1\.1\.1
	munger: 1\.1\.1
keyword substitution: kv
total revisions: 4;	selected revisions: 4
description:
----------------------------
revision 1\.2
date: ${ISO8601DATE};  author: ${username};  state: dead;  lines: ${PLUS}0 -0;  commitid: ${commitid};
Revision 1\.1 was added on the vendor branch\.
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
branches:  1\.1\.1;
Initial revision
----------------------------
revision 1\.1\.1\.2
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  commitid: ${commitid};
add
----------------------------
revision 1\.1\.1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0;  commitid: ${commitid};
add
============================================================================="

	  cd ../..
	  rm -r 1
	  modify_repo rm -rf ${CVSROOT_DIRNAME}/first-dir
	  ;;



	importX2)
	  # Test ImportNewFilesToVendorBranchOnly config file option.

	  # On Windows, we can't check out CVSROOT, because the case
	  # insensitivity means that this conflicts with cvsroot.
	  mkdir wnt
	  cd wnt

	  dotest importX2-1 "${testcvs} -q co CVSROOT" "[UP] CVSROOT${DOTSTAR}"
	  cd CVSROOT
          echo "ImportNewFilesToVendorBranchOnly=yes" >> config

	  dotest importX2-2 "$testcvs -q ci -m force-cvs-import-X" \
"$TESTDIR/cvsroot/CVSROOT/config,v  <--  config
new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
$SPROG commit: Rebuilding administrative file database"

	  cd ../..

	  # Import a sources file, but do NOT specify -X.  The new file
	  # should be killed, anyway (because of the config option).
	  mkdir imp-dir
	  cd imp-dir
	  echo 'source' >file1
	  dotest_sort importX2-3 \
"${testcvs} import -m add first-dir source source-1_0" \
"


 ${CPROG} checkout -j<prev_rel_tag> -jsource-1_0 first-dir
N first-dir/file1
No conflicts created by this import.
Use the following command to help the merge:"
	  cd ..
	  rm -r imp-dir

	  mkdir 1
	  cd 1
	  # **nothing** should be checked out**
	  dotest importX2-4 "${testcvs} -q co first-dir" ""

	  cd first-dir
	  dotest importX2-5 "${testcvs} -q log file1" "
RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file1,v
Working file: file1
head: 1\.2
branch:
locks: strict
access list:
symbolic names:
	source-1_0: 1\.1\.1\.1
	source: 1\.1\.1
keyword substitution: kv
total revisions: 3;	selected revisions: 3
description:
----------------------------
revision 1\.2
date: ${ISO8601DATE};  author: ${username};  state: dead;  lines: ${PLUS}0 -0;  commitid: ${commitid};
Revision 1\.1 was added on the vendor branch\.
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
branches:  1\.1\.1;
Initial revision
----------------------------
revision 1\.1\.1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0;  commitid: ${commitid};
add
============================================================================="

	  dokeep
	  cd ../..
	  restore_adm
	  rm -r 1
	  rm -r wnt
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	import-CVS)
	  mkdir import-CVS
	  cd import-CVS
	  touch file1 file2 file3
	  dotest_fail import-CVS-1 "$testcvs import CVS vtag rtag" \
"$CPROG import: The word \`CVS' is reserved by CVS and may not be used
$CPROG \[import aborted\]: as a directory in a path or as a file name\."
	  mkdir sdir
	  mkdir sdir/CVS
	  touch sdir/CVS/file4 sdir/CVS/file5 sdir/file6 sdir/file7
	  # Calling the imported directory import-CVS is dual purpose in the
	  # following test.  It makes sure the path test which matched above
	  # wasn't too strict.
	  dotest_sort import-CVS-2 \
"$testcvs import -I! -mimport import-CVS vtag rtag" \
"

I import-CVS/sdir/CVS
N import-CVS/file1
N import-CVS/file2
N import-CVS/file3
N import-CVS/sdir/file6
N import-CVS/sdir/file7
No conflicts created by this import
$SPROG import: Importing $CVSROOT_DIRNAME/import-CVS/sdir"

	  dokeep
	  cd ..
	  rm -r import-CVS
	  modify_repo rm -rf $CVSROOT_DIRNAME/import-CVS
	  ;;



	import-quirks)
	  # Short tests of quirky import behavior.
	  #
	  # For a list of other import tests with short descriptions, see the
	  # comment header of the "import" test.
	  mkdir import-quirks
	  cd import-quirks
	  touch file1 file2 file3

	  # CVS prior to 1.11.18 and 1.12.10 used to happily import to
	  # "branch 1.1", creating RCS archives with revisions like,
	  # "1.1..1".  That double-dot is *not* a typo.
	  dotest_fail import-quirks-1 \
"$testcvs import -b1.1. -mbad-bad-bad import-quirks VB RT" \
"$CPROG \[import aborted\]: Only numeric branch specifications with two dots are
supported by import, not \`1\.1\.'\.  For example: \`1\.1\.1'\."

	  dotest_fail import-quirks-2 \
"$testcvs import -b1.1.1.. -mbad-bad-bad import-quirks VB RT" \
"$CPROG \[import aborted\]: Only numeric branch specifications with two dots are
supported by import, not \`1\.1\.1\.\.'\.  For example: \`1\.1\.1'\."

	  # Try a few odd numbers.  This is hardly comprehensive.
	  dotest_sort import-quirks-2 \
"$testcvs import -b10.10.101 -mthis-ones-ok import-quirks-2 VB RT" \
"

N import-quirks-2/file1
N import-quirks-2/file2
N import-quirks-2/file3
No conflicts created by this import"

	  dotest_sort import-quirks-3 \
"$testcvs import -b2345678901.2345678901.2345678901 -mthis-ones-ok import-quirks-3 VB RT" \
"

N import-quirks-3/file1
N import-quirks-3/file2
N import-quirks-3/file3
No conflicts created by this import"

	  dotest_sort import-quirks-4 \
"$testcvs import -b1.1.2 -mthis-ones-ok import-quirks-4 VB RT" \
"

N import-quirks-4/file1
N import-quirks-4/file2
N import-quirks-4/file3
No conflicts created by this import"

	  dokeep
	  cd ..
	  rm -r import-quirks
	  rm -rf $CVSROOT_DIRNAME/import-quirks-2 \
		 $CVSROOT_DIRNAME/import-quirks-3 \
		 $CVSROOT_DIRNAME/import-quirks-4
	  ;;



	import-after-initial)
	  # Properly handle the case in which the first version of a
	  # file is created by a regular cvs add and commit, and there
	  # is a subsequent cvs import of the same file.  cvs update with
	  # a date tag must resort to searching the vendor branch only if
	  # the initial version of the file was created at the same time
	  # as the initial version on the vendor branch.

	  mkdir 1; cd 1
	  module=x

	  echo > unused-file

	  # Create the module.
	  dotest import-after-initial-1 \
	    "$testcvs -Q import -m. $module X Y" ''

	  file=m
	  # Check it out and add a file.
	  dotest import-after-initial-2 "$testcvs -Q co $module" ''
	  cd $module
	  echo original > $file
	  dotest import-after-initial-3 "${testcvs} -Q add $file" ""
	  dotest import-after-initial-4 "$testcvs -Q ci -m. $file"

	  # Delay a little so the following import isn't done in the same
	  # second as the preceding commit.
	  sleep 2

	  # Do the first import of $file *after* $file already has an
	  # initial version.
	  mkdir sub
	  cd sub
	  echo newer-via-import > $file
	  dotest import-after-initial-5 \
	    "$testcvs -Q import -m. $module X Y2" ''
	  cd ..

	  # Sleep a second so we're sure to be after the second of the import.
	  sleep 1

	  dotest import-after-initial-6 \
	    "$testcvs -Q update -p -D now $file" 'original'

	  dokeep
	  cd ../..
	  rm -rf 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/$module
	  ;;



        branch-after-import)
	  # Test branching after an import via both cvs tag -b and
	  # cvs add to verify that the HEAD remains at 1.1.1.1
	  # This was a FreeBSD bug documented at the URL:
	  # http://www.freebsd.org/cgi/query-pr.cgi?pr=4033

	  mkdir branch-after-import
	  cd branch-after-import

	  # OK, first we get some sources from the NetMunger project,
	  # and import them into the 1.1.1 vendor branch.
	  mkdir imp-dir
	  cd imp-dir
	  echo 'OpenMunger sources' >file1
	  echo 'OpenMunger sources' >file2
	  dotest_sort branch-after-import-1 \
"${testcvs} import -m add first-dir openmunger openmunger-1_0" \
'

N first-dir/file1
N first-dir/file2
No conflicts created by this import'
	  cd ..

	  # Next checkout the new module
	  dotest branch-after-import-2 \
"${testcvs} -q co first-dir" \
'U first-dir/file1
U first-dir/file2'
	  cd first-dir
	  # Branch tag the file1 and cvs add file2,
	  # the branch should remain the same in both cases
	  # such that a new import will not require a conflict
	  # resolution.
	  dotest branch-after-import-3 \
"${testcvs} tag -b TESTTOTRON file1" \
'T file1'
	  dotest branch-after-import-4 \
"${testcvs} -q update -r TESTTOTRON" \
"${SPROG} update: \`file2' is no longer in the repository"

	  cp ../imp-dir/file2 .
	  dotest branch-after-import-5 \
"${testcvs} add file2" \
"${SPROG} add: scheduling file .file2. for addition on branch .TESTTOTRON.
${SPROG} add: use .${SPROG} commit. to add this file permanently"

	  dotest branch-after-import-6 \
"$testcvs commit -m cvs-add file2" \
"$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
new revision: 1\.1\.1\.1\.2\.2; previous revision: 1\.1\.1\.1\.2\.1"

	  dokeep
	  cd ../..
	  rm -r branch-after-import
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	join)
	  # Test doing joins which involve adding and removing files.
	  #   Variety of scenarios (see list below), in the context of:
	  #     * merge changes from T1 to T2 into the main line
	  #     * merge changes from branch 'branch' into the main line
	  #     * merge changes from branch 'branch' into branch 'br2'.
	  # See also binfile2, which does similar things with binary files.
	  # See also join2, which tests joining (and update -A) on only
	  # a single file, rather than a directory.
	  # See also rmadd2, which tests -j cases not involving branches
	  #   (e.g. undoing a commit)
	  # See also join3, which tests some cases involving the greatest
	  # common ancestor.  Here is a list of tests according to branch
	  # topology:
	  #
	  # --->bp---->trunk          too many to mention
	  #     \----->branch
	  #
	  #     /----->branch1
	  # --->bp---->trunk          multibranch, multibranch2
	  #     \----->branch2
	  #
	  # --->bp1----->bp2---->trunk   join3
	  #     \->br1   \->br2
	  #
	  # --->bp1----->trunk
	  #     \----bp2---->branch                branches
	  #          \------>branch-of-branch

	  # We check merging changes from T1 to T2 into the main line.
	  # Here are the interesting cases I can think of:
	  #   1) File added between T1 and T2, not on main line.
	  #      File should be marked for addition.
	  #   2) File added between T1 and T2, also added on main line.
	  #      Conflict.
	  #   3) File removed between T1 and T2, unchanged on main line.
	  #      File should be marked for removal.
	  #   4) File removed between T1 and T2, modified on main line.
	  #      If mod checked in, file should be marked for removal.
	  #	 If mod still in working directory, conflict.
	  #   5) File removed between T1 and T2, was never on main line.
	  #      Nothing should happen.
	  #   6) File removed between T1 and T2, also removed on main line.
	  #      Nothing should happen.
	  #   7) File not added between T1 and T2, added on main line.
	  #      Nothing should happen.
	  #   8) File not modified between T1 and T2, removed on main line.
	  #      Nothing should happen.
	  #   9) File modified between T1 and T2, removed on main line.
	  #      Conflict.
	  #  10) File was never on branch, removed on main line.
	  #      Nothing should happen.

	  # We also check merging changes from a branch into the main
	  # line.  Here are the interesting cases:
	  #   1) File added on branch, not on main line.
	  #      File should be marked for addition.
	  #   2) File added on branch, also added on main line.
	  #      Conflict.
	  #   3) File removed on branch, unchanged on main line.
	  #      File should be marked for removal.
	  #   4) File removed on branch, modified on main line.
	  #      Conflict.
	  #   5) File removed on branch, was never on main line.
	  #      Nothing should happen.
	  #   6) File removed on branch, also removed on main line.
	  #      Nothing should happen.
	  #   7) File added on main line, not added on branch.
	  #      Nothing should happen.
	  #   8) File removed on main line, not modified on branch.
	  #      Nothing should happen.
	  #   9) File modified on branch, removed on main line.
	  #      Conflict.
	  #  10) File was never on branch, removed on main line.
	  #      Nothing should happen.

	  # In the tests below, fileN represents case N in the above
	  # lists.

	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  mkdir 1
	  cd 1
	  dotest join-1 "$testcvs -q co first-dir"

	  cd first-dir

	  # Add two files.
	  echo 'first revision of file3' > file3
	  echo 'first revision of file4' > file4
	  echo 'first revision of file6' > file6
	  echo 'first revision of file8' > file8
	  echo 'first revision of file9' > file9
	  dotest join-2 "${testcvs} add file3 file4 file6 file8 file9" \
"${SPROG}"' add: scheduling file `file3'\'' for addition
'"${SPROG}"' add: scheduling file `file4'\'' for addition
'"${SPROG}"' add: scheduling file `file6'\'' for addition
'"${SPROG}"' add: scheduling file `file8'\'' for addition
'"${SPROG}"' add: scheduling file `file9'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'

	  dotest join-3 "${testcvs} -q commit -m add" \
"$CVSROOT_DIRNAME/first-dir/file3,v  <--  file3
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file6,v  <--  file6
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file8,v  <--  file8
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file9,v  <--  file9
initial revision: 1\.1"

	  # Make a branch.
	  dotest join-4 "${testcvs} -q tag -b branch ." \
'T file3
T file4
T file6
T file8
T file9'

	  # Add file2, file7, and file10, modify file4, and remove
	  # file6, file8, and file9.
	  echo 'first revision of file2' > file2
	  echo 'second revision of file4' > file4
	  echo 'first revision of file7' > file7
	  rm file6 file8 file9
	  echo 'first revision of file10' > file10
	  dotest join-5 "${testcvs} add file2 file7 file10" \
"${SPROG}"' add: scheduling file `file2'\'' for addition
'"${SPROG}"' add: scheduling file `file7'\'' for addition
'"${SPROG}"' add: scheduling file `file10'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'
	  dotest join-6 "${testcvs} rm file6 file8 file9" \
"${SPROG}"' remove: scheduling `file6'\'' for removal
'"${SPROG}"' remove: scheduling `file8'\'' for removal
'"${SPROG}"' remove: scheduling `file9'\'' for removal
'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove these files permanently'
	  dotest join-7 "${testcvs} -q ci -mx ." \
"$CVSROOT_DIRNAME/first-dir/file10,v  <--  file10
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: 1\.2; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file6,v  <--  file6
new revision: delete; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file7,v  <--  file7
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file8,v  <--  file8
new revision: delete; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file9,v  <--  file9
new revision: delete; previous revision: 1\.1"

	  # Remove file10
	  dotest join-7a "${testcvs} rm -f file10" \
"${SPROG}"' remove: scheduling `file10'\'' for removal
'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove this file permanently'
	  dotest join-7b "${testcvs} -q ci -mx ." \
"$CVSROOT_DIRNAME/first-dir/file10,v  <--  file10
new revision: delete; previous revision: 1\.1"

	  # Check out the branch.
	  cd ../..
	  mkdir 2
	  cd 2
	  dotest join-8 "${testcvs} -q co -r branch first-dir" \
'U first-dir/file3
U first-dir/file4
U first-dir/file6
U first-dir/file8
U first-dir/file9'

	  cd first-dir

	  # Modify the files on the branch, so that T1 is not an
	  # ancestor of the main line, and add file5
	  echo 'first branch revision of file3' > file3
	  echo 'first branch revision of file4' > file4
	  echo 'first branch revision of file5' > file5
	  echo 'first branch revision of file6' > file6
	  echo 'first branch revision of file9' > file9
	  dotest join-9 "${testcvs} add file5" \
"${SPROG}"' add: scheduling file `file5'\'' for addition on branch `branch'\''
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
	  dotest join-10 "${testcvs} -q ci -mx ." \
"$CVSROOT_DIRNAME/first-dir/file3,v  <--  file3
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/Attic/file5,v  <--  file5
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/Attic/file6,v  <--  file6
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/Attic/file9,v  <--  file9
new revision: 1\.1\.2\.1; previous revision: 1\.1"

	  # Tag the current revisions on the branch.
	  dotest join-11 "${testcvs} -q tag T1 ." \
'T file3
T file4
T file5
T file6
T file8
T file9'

	  # Add file1 and file2, modify file9, and remove the other files.
	  echo 'first branch revision of file1' > file1
	  echo 'first branch revision of file2' > file2
	  echo 'second branch revision of file9' > file9
	  rm file3 file4 file5 file6
	  dotest join-12 "${testcvs} add file1 file2" \
"${SPROG}"' add: scheduling file `file1'\'' for addition on branch `branch'\''
'"${SPROG}"' add: scheduling file `file2'\'' for addition on branch `branch'\''
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'
	  dotest join-13 "${testcvs} rm file3 file4 file5 file6" \
"${SPROG}"' remove: scheduling `file3'\'' for removal
'"${SPROG}"' remove: scheduling `file4'\'' for removal
'"${SPROG}"' remove: scheduling `file5'\'' for removal
'"${SPROG}"' remove: scheduling `file6'\'' for removal
'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove these files permanently'
	  dotest join-14 "${testcvs} -q ci -mx ." \
"$CVSROOT_DIRNAME/first-dir/Attic/file1,v  <--  file1
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1
$CVSROOT_DIRNAME/first-dir/file3,v  <--  file3
new revision: delete; previous revision: 1\.1\.2\.1
$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: delete; previous revision: 1\.1\.2\.1
$CVSROOT_DIRNAME/first-dir/Attic/file5,v  <--  file5
new revision: delete; previous revision: 1\.1\.2\.1
$CVSROOT_DIRNAME/first-dir/Attic/file6,v  <--  file6
new revision: delete; previous revision: 1\.1\.2\.1
$CVSROOT_DIRNAME/first-dir/Attic/file9,v  <--  file9
new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"

	  # Tag the current revisions on the branch.
	  dotest join-15 "${testcvs} -q tag T2 ." \
'T file1
T file2
T file8
T file9'

	  # Do a checkout with a merge.
	  cd ../..
	  mkdir 3
	  cd 3
	  dotest join-16 "${testcvs} -q co -jT1 -jT2 first-dir" \
"U first-dir/file1
U first-dir/file2
${SPROG} checkout: file first-dir/file2 exists, but has been added in revision T2
U first-dir/file3
${SPROG} checkout: scheduling \`first-dir/file3' for removal
U first-dir/file4
${SPROG} checkout: scheduling \`first-dir/file4' for removal
U first-dir/file7
${SPROG} checkout: file first-dir/file9 does not exist, but is present in revision T2"

	  # Verify that the right changes have been scheduled.
	  cd first-dir
	  dotest join-17 "${testcvs} -q update" \
'A file1
R file3
R file4'

	  # Modify file4 locally, and do an update with a merge.
	  cd ../../1/first-dir
	  echo 'third revision of file4' > file4
	  dotest join-18 "${testcvs} -q update -jT1 -jT2 ." \
"U file1
$SPROG update: file file2 exists, but has been added in revision T2
$SPROG update: scheduling \`file3' for removal
M file4
$SPROG update: file file4 is locally modified, but has been removed in revision T2
$SPROG update: file file9 does not exist, but is present in revision T2"

	  # Verify that the right changes have been scheduled.
	  dotest join-19 "${testcvs} -q update" \
'A file1
R file3
M file4'

	  # Do a checkout with a merge from a single revision.

	  # FIXME: CVS currently gets this wrong.  file2 has been
	  # added on both the branch and the main line, and so should
	  # be regarded as a conflict.  However, given the way that
	  # CVS sets up the RCS file, there is no way to distinguish
	  # this case from the case of file2 having existed before the
	  # branch was made.  This could be fixed by reserving
	  # a revision somewhere, perhaps 1.1, as an always dead
	  # revision which can be used as the source for files added
	  # on branches.
	  cd ../../3
	  rm -r first-dir
	  dotest join-20 "${testcvs} -q co -jbranch first-dir" \
"U first-dir/file1
U first-dir/file2
RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
retrieving revision 1\.1
retrieving revision 1\.1\.2\.2
Merging differences between 1\.1 and 1\.1\.2\.2 into file2
U first-dir/file3
${SPROG} checkout: scheduling \`first-dir/file3' for removal
U first-dir/file4
${SPROG} checkout: file first-dir/file4 has been modified, but has been removed in revision branch
U first-dir/file7
${SPROG} checkout: file first-dir/file9 does not exist, but is present in revision branch"

	  # Verify that the right changes have been scheduled.
	  # The M file2 line is a bug; see above join-20.
	  cd first-dir
	  dotest join-21 "${testcvs} -q update" \
'A file1
M file2
R file3'

	  # Checkout the main line again.
	  cd ../../1
	  rm -r first-dir
	  dotest join-22 "${testcvs} -q co first-dir" \
'U first-dir/file2
U first-dir/file3
U first-dir/file4
U first-dir/file7'

	  # Modify file4 locally, and do an update with a merge from a
	  # single revision.
	  # The file2 handling is a bug; see above join-20.
	  cd first-dir
	  echo 'third revision of file4' > file4
	  dotest join-23 "${testcvs} -q update -jbranch ." \
"U file1
RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
retrieving revision 1\.1
retrieving revision 1\.1\.2\.2
Merging differences between 1\.1 and 1\.1\.2\.2 into file2
${SPROG} update: scheduling \`file3' for removal
M file4
${SPROG} update: file file4 is locally modified, but has been removed in revision branch
${SPROG} update: file file9 does not exist, but is present in revision branch"

	  # Verify that the right changes have been scheduled.
	  # The M file2 line is a bug; see above join-20
	  dotest join-24 "${testcvs} -q update" \
'A file1
M file2
R file3
M file4'

	  cd ..

	  # Checkout the main line again and make a new branch which we
	  # merge to.
	  rm -r first-dir
	  dotest join-25 "${testcvs} -q co first-dir" \
'U first-dir/file2
U first-dir/file3
U first-dir/file4
U first-dir/file7'
	  cd first-dir
	  dotest join-26 "${testcvs} -q tag -b br2" \
"T file2
T file3
T file4
T file7"
	  dotest join-27 "${testcvs} -q update -r br2" ""
	  # The handling of file8 and file9 here look fishy to me.  I don't
	  # see why it should be different from the case where we merge to
	  # the trunk (e.g. join-23).
	  dotest join-28 "${testcvs} -q update -j branch" \
"U file1
RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
retrieving revision 1.1
retrieving revision 1.1.2.2
Merging differences between 1.1 and 1.1.2.2 into file2
${SPROG} update: scheduling \`file3' for removal
${SPROG} update: file file4 has been modified, but has been removed in revision branch
U file8
U file9"
	  # Verify that the right changes have been scheduled.
	  dotest join-29 "${testcvs} -q update" \
"A file1
M file2
R file3
A file8
A file9"

	  # Checkout the mainline again to try updating and merging between two
	  # branches in the same step
	  # this seems a likely scenario - the user finishes up on branch and
	  # updates to br2 and merges in the same step - and there was a bug
	  # once that if the file was removed in the update then it wouldn't be
	  # readded in the merge
	  cd ..
	  rm -r first-dir
	  dotest join-twobranch-1 "${testcvs} -q co -rbranch first-dir" \
'U first-dir/file1
U first-dir/file2
U first-dir/file8
U first-dir/file9'
	  cd first-dir
	  dotest join-twobranch-2 "${testcvs} -q update -rbr2 -jbranch" \
"${SPROG} update: \`file1' is no longer in the repository
U file1
U file2
RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
retrieving revision 1\.1
retrieving revision 1\.1\.2\.2
Merging differences between 1\.1 and 1\.1\.2\.2 into file2
U file3
${SPROG} update: scheduling \`file3' for removal
U file4
${SPROG} update: file file4 has been modified, but has been removed in revision branch
U file7
${SPROG} update: \`file8' is no longer in the repository
U file8
${SPROG} update: \`file9' is no longer in the repository
U file9"
	  # Verify that the right changes have been scheduled.
	  dotest join-twobranch-3 "${testcvs} -q update" \
"A file1
M file2
R file3
A file8
A file9"

	  # Checkout the mainline again to try merging from the trunk
	  # to a branch.
	  cd ..
	  rm -r first-dir
	  dotest join-30 "${testcvs} -q co first-dir" \
'U first-dir/file2
U first-dir/file3
U first-dir/file4
U first-dir/file7'
	  cd first-dir

	  # Tag the current revisions on the trunk.
	  dotest join-31 "${testcvs} -q tag T3 ." \
'T file2
T file3
T file4
T file7'

	  # Modify file7.
	  echo 'second revision of file7' > file7
	  dotest join-32 "${testcvs} -q ci -mx ." \
"$CVSROOT_DIRNAME/first-dir/file7,v  <--  file7
new revision: 1\.2; previous revision: 1\.1"

	  # And Tag again.
	  dotest join-33 "${testcvs} -q tag T4 ." \
'T file2
T file3
T file4
T file7'

	  # Now update branch to T3.
	  cd ../../2/first-dir
	  dotest join-34 "${testcvs} -q up -jT3" \
"${SPROG} update: file file4 does not exist, but is present in revision T3
U file7"

	  # Verify that the right changes have been scheduled.
	  dotest join-35 "${testcvs} -q update" \
'A file7'

	  # Now update to T4.
	  # This is probably a bug, although in this particular case it just
	  # happens to do the right thing; see above join-20.
	  dotest join-36 "${testcvs} -q up -j T3 -j T4" \
"A file7
RCS file: ${CVSROOT_DIRNAME}/first-dir/file7,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into file7"

	  # Verify that the right changes have been scheduled.
	  dotest join-37 "${testcvs} -q update" \
'A file7'

	  dokeep
	  cd ../..
	  rm -r 1 2 3
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	join2)
	  # More joining tests.

	  # First the usual setup; create a directory first-dir, a file
	  # first-dir/file1, and a branch br1.
	  mkdir 1; cd 1
	  dotest join2-1 "${testcvs} -q co -l ." ''
	  mkdir first-dir
	  dotest join2-2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
          cd first-dir
	  echo 'initial contents of file1' >file1
	  dotest join2-3 "${testcvs} add file1" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest join2-4 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1"
	  dotest join2-5 "${testcvs} -q tag -b br1" "T file1"
	  dotest join2-6 "${testcvs} -q update -r br1" ""
	  echo 'modify on branch' >>file1
	  touch bradd
	  dotest join2-6a "${testcvs} add bradd" \
"${SPROG} add: scheduling file .bradd. for addition on branch .br1.
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest join2-7 "${testcvs} -q ci -m modify" \
"$CVSROOT_DIRNAME/first-dir/Attic/bradd,v  <--  bradd
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.1\.2\.1; previous revision: 1\.1"

	  # Here is the unusual/pathological part.  We switch back to
	  # the trunk *for file1 only*, not for the whole directory.
	  dotest join2-8 "${testcvs} -q update -A file1" '[UP] file1'
	  dotest join2-9 "${testcvs} -q status file1" \
"===================================================================
File: file1            	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file1,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
	  dotest join2-10 "cat CVS/Tag" "Tbr1"

	  dotest join2-11 "${testcvs} -q update -j br1 file1" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
retrieving revision 1\.1
retrieving revision 1\.1\.2\.1
Merging differences between 1\.1 and 1\.1\.2\.1 into file1"
	  dotest join2-12 "cat file1" "initial contents of file1
modify on branch"
	  # We should have no sticky tag on file1
	  dotest join2-13 "${testcvs} -q status file1" \
"===================================================================
File: file1            	Status: Locally Modified

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/file1,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
	  dotest join2-14 "cat CVS/Tag" "Tbr1"
	  # And the checkin should go to the trunk
	  dotest join2-15 "${testcvs} -q ci -m modify file1" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.2; previous revision: 1\.1"

	  # OK, the above is all well and good and has worked for some
	  # time.  Now try the case where the file had been added on
	  # the branch.
	  dotest join2-16 "${testcvs} -q update -r br1" "[UP] file1"
	  # The workaround is to update the whole directory.
	  # The non-circumvented version won't work.  The reason is that
	  # update removes the entry from CVS/Entries, so of course we get
	  # the tag from CVS/Tag and not Entries.  I suppose maybe
	  # we could invent some new format in Entries which would handle
	  # this, but doing so, and handling it properly throughout
	  # CVS, would be a lot of work and I'm not sure this case justifies
	  # it.
	  dotest join2-17-circumvent "${testcvs} -q update -A" \
"${SPROG} update: \`bradd' is no longer in the repository
[UP] file1"
:	  dotest join2-17 "${testcvs} -q update -A bradd" \
"${SPROG} update: warning: \`bradd' is not (any longer) pertinent"
	  dotest join2-18 "${testcvs} -q update -j br1 bradd" "U bradd"
	  dotest join2-19 "${testcvs} -q status bradd" \
"===================================================================
File: bradd            	Status: Locally Added

   Working revision:	New file!
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/Attic/bradd,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
	  dotest join2-20 "${testcvs} -q ci -m modify bradd" \
"$CVSROOT_DIRNAME/first-dir/bradd,v  <--  bradd
new revision: 1\.2; previous revision: 1\.1"

	  dokeep
	  cd ../..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	join3)
	  # See "join" for a list of other joining/branching tests.
	  # First the usual setup; create a directory first-dir, a file
	  # first-dir/file1, and a branch br1.
	  mkdir 1; cd 1
	  dotest join3-1 "${testcvs} -q co -l ." ''
	  mkdir first-dir
	  dotest join3-2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
	  cd first-dir
	  echo 'initial contents of file1' >file1
	  dotest join3-3 "${testcvs} add file1" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest join3-4 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1"
	  dotest join3-5 "${testcvs} -q tag -b br1" "T file1"
	  dotest join3-6 "${testcvs} -q update -r br1" ""
	  echo 'br1:line1' >>file1
	  dotest join3-7 "${testcvs} -q ci -m modify" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.1\.2\.1; previous revision: 1\.1"

	  # Now back to the trunk for:
	  # another revision and another branch for file1.
	  # add file2, which will exist on trunk and br2 but not br1.
	  dotest join3-8 "${testcvs} -q update -A" "[UP] file1"
	  echo 'trunk:line1' > file2
	  dotest join3-8a "${testcvs} add file2" \
"${SPROG} add: scheduling file .file2. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  echo 'trunk:line1' >>file1
	  dotest join3-9 "${testcvs} -q ci -m modify" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.2; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
initial revision: 1\.1"
	  dotest join3-10 "${testcvs} -q tag -b br2" "T file1
T file2"

	  # Before we actually have any revision on br2, let's try a join
	  dotest join3-11 "${testcvs} -q update -r br1" "[UP] file1
${SPROG} update: \`file2' is no longer in the repository"
	  dotest join3-12 "${testcvs} -q update -j br2" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into file1
rcsmerge: warning: conflicts during merge
U file2"
	  dotest join3-13 "cat file1" \
"initial contents of file1
[<]<<<<<< file1
br1:line1
[=]======
trunk:line1
[>]>>>>>> 1\.2"
	  rm file1

	  # OK, we'll try the same thing with a revision on br2.
	  dotest join3-14 "${testcvs} -q update -r br2 file1" \
"${SPROG} update: warning: \`file1' was lost
U file1" "U file1"
	  echo 'br2:line1' >>file1
	  dotest join3-15 "${testcvs} -q ci -m modify file1" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.2\.2\.1; previous revision: 1\.2"

	  # OK, now we can join br2 to br1
	  dotest join3-16 "${testcvs} -q update -r br1 file1" "[UP] file1"
	  # It may seem odd, to merge a higher branch into a lower
	  # branch, but in fact CVS defines the ancestor as 1.1
	  # and so it merges both the 1.1->1.2 and 1.2->1.2.2.1 changes.
	  # This seems like a reasonably plausible behavior.
	  dotest join3-17 "${testcvs} -q update -j br2 file1" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
retrieving revision 1\.1
retrieving revision 1\.2\.2\.1
Merging differences between 1\.1 and 1\.2\.2\.1 into file1
rcsmerge: warning: conflicts during merge"
	  dotest join3-18 "cat file1" \
"initial contents of file1
[<]<<<<<< file1
br1:line1
[=]======
trunk:line1
br2:line1
[>]>>>>>> 1\.2\.2\.1"

	  dokeep
	  cd ../..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	join4)
	  # Like join, but with local (uncommitted) modifications.

	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  mkdir 1
	  cd 1
	  dotest join4-1 "${testcvs} -q co first-dir" ''

	  cd first-dir

	  # Add two files.
	  echo 'first revision of file3' > file3
	  echo 'first revision of file4' > file4
	  echo 'first revision of file6' > file6
	  echo 'first revision of file8' > file8
	  echo 'first revision of file9' > file9
	  dotest join4-2 "${testcvs} add file3 file4 file6 file8 file9" \
"${SPROG}"' add: scheduling file `file3'\'' for addition
'"${SPROG}"' add: scheduling file `file4'\'' for addition
'"${SPROG}"' add: scheduling file `file6'\'' for addition
'"${SPROG}"' add: scheduling file `file8'\'' for addition
'"${SPROG}"' add: scheduling file `file9'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'

	  dotest join4-3 "${testcvs} -q commit -m add" \
"$CVSROOT_DIRNAME/first-dir/file3,v  <--  file3
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file6,v  <--  file6
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file8,v  <--  file8
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file9,v  <--  file9
initial revision: 1\.1"

	  # Make a branch.
	  dotest join4-4 "${testcvs} -q tag -b branch ." \
'T file3
T file4
T file6
T file8
T file9'

	  # Add file10
	  echo 'first revision of file10' > file10
	  dotest join4-7a "${testcvs} add file10" \
"${SPROG}"' add: scheduling file `file10'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
	  dotest join4-7b "${testcvs} -q ci -mx ." \
"$CVSROOT_DIRNAME/first-dir/file10,v  <--  file10
initial revision: 1\.1"

	  # Add file2 and file7, modify file4, and remove
	  # file6, file8, file9, and file10.
	  echo 'first revision of file2' > file2
	  echo 'second revision of file4' > file4
	  echo 'first revision of file7' > file7
	  rm file6 file8 file9 file10
	  dotest join4-5 "${testcvs} add file2 file7" \
"${SPROG}"' add: scheduling file `file2'\'' for addition
'"${SPROG}"' add: scheduling file `file7'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'
	  dotest join4-6 "${testcvs} rm file6 file8 file9 file10" \
"${SPROG}"' remove: scheduling `file6'\'' for removal
'"${SPROG}"' remove: scheduling `file8'\'' for removal
'"${SPROG}"' remove: scheduling `file9'\'' for removal
'"${SPROG}"' remove: scheduling `file10'\'' for removal
'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove these files permanently'

	  # Check out the branch.
	  cd ../..
	  mkdir 2
	  cd 2
	  dotest join4-8 "${testcvs} -q co -r branch first-dir" \
'U first-dir/file3
U first-dir/file4
U first-dir/file6
U first-dir/file8
U first-dir/file9'

	  cd first-dir

	  # Modify the files on the branch, so that T1 is not an
	  # ancestor of the main line, and add file5
	  echo 'first branch revision of file3' > file3
	  echo 'first branch revision of file4' > file4
	  echo 'first branch revision of file5' > file5
	  echo 'first branch revision of file6' > file6
	  echo 'first branch revision of file9' > file9
	  dotest join4-9 "${testcvs} add file5" \
"${SPROG}"' add: scheduling file `file5'\'' for addition on branch `branch'\''
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
	  dotest join4-10 "${testcvs} -q ci -mx ." \
"$CVSROOT_DIRNAME/first-dir/file3,v  <--  file3
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/Attic/file5,v  <--  file5
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file6,v  <--  file6
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file9,v  <--  file9
new revision: 1\.1\.2\.1; previous revision: 1\.1"

	  # Tag the current revisions on the branch.
	  dotest join4-11 "${testcvs} -q tag T1 ." \
'T file3
T file4
T file5
T file6
T file8
T file9'

	  # Add file1 and file2, modify file9, and remove the other files.
	  echo 'first branch revision of file1' > file1
	  echo 'first branch revision of file2' > file2
	  echo 'second branch revision of file9' > file9
	  rm file3 file4 file5 file6
	  dotest join4-12 "${testcvs} add file1 file2" \
"${SPROG}"' add: scheduling file `file1'\'' for addition on branch `branch'\''
'"${SPROG}"' add: scheduling file `file2'\'' for addition on branch `branch'\''
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'
	  dotest join4-13 "${testcvs} rm file3 file4 file5 file6" \
"${SPROG}"' remove: scheduling `file3'\'' for removal
'"${SPROG}"' remove: scheduling `file4'\'' for removal
'"${SPROG}"' remove: scheduling `file5'\'' for removal
'"${SPROG}"' remove: scheduling `file6'\'' for removal
'"${SPROG}"' remove: use .'"${SPROG}"' commit. to remove these files permanently'
	  dotest join4-14 "${testcvs} -q ci -mx ." \
"$CVSROOT_DIRNAME/first-dir/Attic/file1,v  <--  file1
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/Attic/file2,v  <--  file2
new revision: 1\.1\.2\.1; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file3,v  <--  file3
new revision: delete; previous revision: 1\.1\.2\.1
$CVSROOT_DIRNAME/first-dir/file4,v  <--  file4
new revision: delete; previous revision: 1\.1\.2\.1
$CVSROOT_DIRNAME/first-dir/Attic/file5,v  <--  file5
new revision: delete; previous revision: 1\.1\.2\.1
$CVSROOT_DIRNAME/first-dir/file6,v  <--  file6
new revision: delete; previous revision: 1\.1\.2\.1
$CVSROOT_DIRNAME/first-dir/file9,v  <--  file9
new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"

	  # Tag the current revisions on the branch.
	  dotest join4-15 "${testcvs} -q tag T2 ." \
'T file1
T file2
T file8
T file9'

	  # Modify file4 locally, and do an update with a merge.
	  cd ../../1/first-dir
	  echo 'third revision of file4' > file4
	  dotest join4-18 "${testcvs} -q update -jT1 -jT2 ." \
"U file1
R file10
A file2
${SPROG} update: file file2 exists, but has been added in revision T2
${SPROG} update: scheduling \`file3' for removal
M file4
${SPROG} update: file file4 is locally modified, but has been removed in revision T2
R file6
A file7
R file8
R file9
${SPROG} update: file file9 does not exist, but is present in revision T2"

	  # Verify that the right changes have been scheduled.
	  dotest join4-19 "${testcvs} -q update" \
'A file1
R file10
A file2
R file3
M file4
R file6
A file7
R file8
R file9'

	  dokeep
	  cd ../..
	  rm -r 1 2
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	join5)
	  # This test verifies that CVS can handle filenames starting with a
	  # dash (`-') properly.  What used to happen was that CVS handled it
	  # just fine, until it went to pass them as arguments to the diff
	  # library, at which point it neglected to pass `--' before the file
	  # list, causing the diff library to attempt to interpret the file
	  # name as an argument.
	  mkdir join5; cd join5
	  mkdir 1; cd 1
	  dotest join5-init-1 "${testcvs} -Q co -l ."
	  mkdir join5
	  dotest join5-init-2 "${testcvs} -Q add join5"
	  cd join5
	  echo "there once was a file from harrisburg" >-file
	  echo "who's existance it seems was quiteabsurd" >>-file
	  dotest join5-init-3 "${testcvs} -Q add -- -file"
	  dotest join5-init-4 "${testcvs} -q ci -minitial" \
"$CVSROOT_DIRNAME/join5/-file,v  <--  -file
initial revision: 1\.1"
	  cd ../..

	  mkdir 2; cd 2
	  dotest join5-init-5 "${testcvs} -Q co join5"
	  cd join5
	  echo "it tested for free" >>-file
	  echo "when paid it should be" >>-file
	  dotest join5-init-4 "${testcvs} -q ci -msecond" \
"$CVSROOT_DIRNAME/join5/-file,v  <--  -file
new revision: 1\.2; previous revision: 1\.1"
	  cd ../..

	  cd 1/join5
	  echo "but maybe it could charge bytheword" >>-file
	  # This is the test that used to spew complaints from diff3:
	  dotest join5 "${testcvs} up" \
"${SPROG} update: Updating \.
RCS file: ${CVSROOT_DIRNAME}/join5/-file,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into -file
rcsmerge: warning: conflicts during merge
${SPROG} update: conflicts found in -file
C -file"

	  dokeep
	  cd ../../..
	  rm -r join5
	  modify_repo rm -rf $CVSROOT_DIRNAME/join5
	  ;;



        join6)
	  mkdir join6; cd join6
          mkdir 1; cd 1
	  dotest join6-init-1 "${testcvs} -Q co -l ."
	  mkdir join6
	  dotest join6-init-2 "${testcvs} -Q add join6"
	  cd join6
          echo aaa >temp.txt
	  echo bbb >>temp.txt
	  echo ccc >>temp.txt
	  dotest join6-1 "${testcvs} -Q add temp.txt"
	  dotest join6-2 "${testcvs} -q commit -minitial temp.txt" \
"$CVSROOT_DIRNAME/join6/temp\.txt,v  <--  temp\.txt
initial revision: 1\.1"
	  cp temp.txt temp2.txt
	  echo ddd >>temp.txt
	  dotest join6-3 "${testcvs} -q commit -madd temp.txt" \
"$CVSROOT_DIRNAME/join6/temp.txt,v  <--  temp\.txt
new revision: 1\.2; previous revision: 1\.1"

	  # The case where the merge target is up-to-date and its base revision
	  # matches the second argument to -j: CVS doesn't bother attempting
	  # the merge since it already knows that the target contains the
	  # change.
	  dotest join6-3.3 "${testcvs} update -j1.1 -j1.2 temp.txt" \
"temp\.txt already contains the differences between 1\.1 and 1\.2"
	  dotest join6-3.4 "${testcvs} diff temp.txt" ""

	  # The case where the merge target is modified but already contains
	  # the change.
	  echo bbb >temp.txt
	  echo ccc >>temp.txt
	  echo ddd >>temp.txt
	  dotest join6-3.5 "${testcvs} update -j1.1 -j1.2 temp.txt" \
"M temp\.txt
RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into temp\.txt
temp\.txt already contains the differences between 1\.1 and 1\.2"
	  dotest_fail join6-3.6 "${testcvs} diff temp.txt" \
"Index: temp\.txt
===================================================================
RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
retrieving revision 1\.2
diff -r1\.2 temp.txt
1d0
< aaa"

	  cp temp2.txt temp.txt
	  dotest_fail join6-4 "${testcvs} diff temp.txt" \
"Index: temp.txt
===================================================================
RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
retrieving revision 1\.2
diff -r1\.2 temp\.txt
4d3
< ddd"

	  dotest join6-5 "${testcvs} update -j1.1 -j1.2 temp.txt" \
"M temp\.txt
RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into temp\.txt"
	  dotest join6-6 "${testcvs} diff temp.txt" ""
	  mv temp.txt temp3.txt
	  dotest join6-7 "sed 's/ddd/dddd/' < temp3.txt > temp.txt" ""
	  dotest join6-8 "${testcvs} update -j1.1 -j1.2 temp.txt" \
"M temp\.txt
RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into temp\.txt
rcsmerge: warning: conflicts during merge"
	  dotest_fail join6-9 "${testcvs} diff temp.txt" \
"Index: temp\.txt
===================================================================
RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
retrieving revision 1\.2
diff -r1\.2 temp\.txt
3a4,6
> <<<<<<< temp\.txt
> dddd
> =======
4a8
> >>>>>>> 1\.2"
	  cp temp2.txt temp.txt
	  dotest join6-10 "${testcvs} -q ci -m del temp.txt" \
"$CVSROOT_DIRNAME/join6/temp.txt,v  <--  temp\.txt
new revision: 1\.3; previous revision: 1\.2"
          cp temp3.txt temp.txt
	  dotest_fail join6-11 "${testcvs} diff temp.txt" \
"Index: temp\.txt
===================================================================
RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
retrieving revision 1\.3
diff -r1\.3 temp\.txt
3a4
> ddd"
	  dotest join6-12 "${testcvs} update -j1.2 -j1.3 temp.txt" \
"M temp\.txt
RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
retrieving revision 1\.2
retrieving revision 1\.3
Merging differences between 1\.2 and 1\.3 into temp\.txt"
	  dotest join6-13 "${testcvs} diff temp.txt" ""

	  # The case where the merge target wasn't created until after the
	  # first tag was applied
	  rm temp2.txt temp3.txt
	  dotest join6-20 "${testcvs} -q tag -r1.1 t1" \
"T temp.txt"
	  echo xxx >temp2.txt
	  dotest join6-21 "${testcvs} -Q add temp2.txt"
	  dotest join6-22 "${testcvs} -q ci -m." \
"$CVSROOT_DIRNAME/join6/temp2\.txt,v  <--  temp2\.txt
initial revision: 1\.1"
	  dotest join6-23 "${testcvs} -q tag t2" \
"T temp.txt
T temp2.txt"
	  echo xxx >>temp.txt
	  dotest join6-24 "${testcvs} -q ci -m." \
"$CVSROOT_DIRNAME/join6/temp.txt,v  <--  temp\.txt
new revision: 1\.4; previous revision: 1\.3"
	  dotest join6-25 "${testcvs} -q up -jt1 -jt2" \
"RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
retrieving revision 1\.1
retrieving revision 1\.3
Merging differences between 1\.1 and 1\.3 into temp.txt
temp.txt already contains the differences between 1\.1 and 1\.3
temp2.txt already contains the differences between creation and 1\.1"

	  # Now for my next trick: delete the file, recreate it, and
	  # try to merge
	  dotest join6-30 "${testcvs} -q rm -f temp2.txt" \
"${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
	  dotest join6-31 "${testcvs} -q ci -m. temp2.txt" \
"$CVSROOT_DIRNAME/join6/temp2\.txt,v  <--  temp2\.txt
new revision: delete; previous revision: 1\.1"
	  echo new >temp2.txt
	  # FIXCVS: Local and remote really shouldn't be different and there
	  # really shouldn't be two different status lines for temp2.txt
	  if $remote; then
	    dotest_fail join6-32 "${testcvs} -q up -jt1 -jt2" \
"? temp2\.txt
RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
retrieving revision 1\.1
retrieving revision 1\.3
Merging differences between 1\.1 and 1\.3 into temp.txt
temp.txt already contains the differences between 1\.1 and 1\.3
$CPROG update: move away .\./temp2\.txt.; it is in the way
C temp2\.txt"
	  else
	    dotest join6-32 "${testcvs} -q up -jt1 -jt2" \
"RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
retrieving revision 1\.1
retrieving revision 1\.3
Merging differences between 1\.1 and 1\.3 into temp.txt
temp.txt already contains the differences between 1\.1 and 1\.3
${SPROG} update: use .${SPROG} add. to create an entry for .temp2\.txt.
U temp2\.txt
? temp2\.txt"
	  fi

	  dokeep
	  cd ../../..
	  rm -r join6
	  modify_repo rm -rf $CVSROOT_DIRNAME/join6
	  ;;



	join7)
	  # This test deals with joins that happen with the -n switch
	  mkdir join7; cd join7
	  mkdir impdir; cd impdir
          echo aaa >temp.txt
	  echo bbb >>temp.txt
	  echo ccc >>temp.txt
	  dotest join7-1 \
"${testcvs} -Q import -minitial join7 vendor vers-1" \
""
	  cd ..
	  dotest join7-2 "${testcvs} -Q co join7" ""
	  cd join7
	  echo ddd >> temp.txt
	  dotest join7-3 "${testcvs} -Q ci -madded-line temp.txt" ""
	  cd ../impdir
	  echo aaaa >temp.txt
	  echo bbbb >>temp.txt
	  echo ccc >>temp.txt
	  echo eee >>temp.txt
	  dotest join7-4 \
"${testcvs} -Q import -minitial join7 vendor vers-2" \
""
	  cd ../join7
	  dotest join7-5 \
"${testcvs} -n update -jvers-1 -jvers-2 temp.txt" \
"RCS file: $CVSROOT_DIRNAME/join7/temp.txt,v
retrieving revision 1\.1\.1\.1
retrieving revision 1\.1\.1\.2
Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into temp.txt
rcsmerge: warning: conflicts during merge"
	  touch temp.txt
	  dotest join7-6 "${testcvs} -n update -jvers-1 -jvers-2 temp.txt" \
"RCS file: $CVSROOT_DIRNAME/join7/temp.txt,v
retrieving revision 1\.1\.1\.1
retrieving revision 1\.1\.1\.2
Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into temp.txt
rcsmerge: warning: conflicts during merge" \
"RCS file: $CVSROOT_DIRNAME/join7/temp.txt,v
retrieving revision 1\.1\.1\.1
retrieving revision 1\.1\.1\.2
Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into temp.txt
rcsmerge: warning: conflicts during merge"

	  dokeep
	  cd ../..
	  rm -r join7
	  modify_repo rm -rf $CVSROOT_DIRNAME/join7
	  ;;



	join-readonly-conflict)
	  # Previously, only tests 1 & 11 were being tested.  I added the
	  # intermediate dotest's to try and diagnose a different failure
	  #
	  # Demonstrate that cvs-1.9.29 can fail on 2nd and subsequent
	  # conflict-evoking join attempts.
	  # Even with that version of CVS, This test failed only in
	  # client-server mode, and would have been noticed in normal
	  # operation only for files that were read-only (either due to
	  # use of cvs' global -r option, setting the CVSREAD envvar,
	  # or use of watch lists).
	  mkdir join-readonly-conflict; cd join-readonly-conflict
	  dotest join-readonly-conflict-1 "$testcvs -q co -l ." ''
	  module=join-readonly-conflict
	  mkdir $module
	  $testcvs -q add $module >>$LOGFILE 2>&1
	  cd $module

	  file=m
	  echo trunk > $file
	  dotest join-readonly-conflict-2 "$testcvs -Q add $file" ''

	  dotest join-readonly-conflict-3 "$testcvs -q ci -m . $file" \
"$CVSROOT_DIRNAME/$module/$file,v  <--  $file
initial revision: 1\.1"

	  dotest join-readonly-conflict-4 "$testcvs tag -b B $file" "T $file"
	  dotest join-readonly-conflict-5 "$testcvs -q update -rB $file" ''
	  echo branch B > $file
	  dotest join-readonly-conflict-6 "$testcvs -q ci -m . $file" \
"$CVSROOT_DIRNAME/$module/$file,v  <--  $file
new revision: 1\.1\.2\.1; previous revision: 1\.1"

	  rm $file
	  dotest join-readonly-conflict-7 "$testcvs -Q update -A $file" ''
	  # Make sure $file is read-only.  This can happen more realistically
	  # via patch -- which could be used to apply a delta, yet would
	  # preserve a file's read-only permissions.
	  echo conflict > $file; chmod u-w $file
	  dotest join-readonly-conflict-8 "$testcvs update -r B $file" \
"RCS file: $CVSROOT_DIRNAME/$module/$file,v
retrieving revision 1\.1
retrieving revision 1\.1\.2\.1
Merging differences between 1\.1 and 1\.1\.2\.1 into $file
rcsmerge: warning: conflicts during merge
${SPROG} update: conflicts found in $file
C $file"

	  # restore to the trunk
	  rm -f $file
	  dotest join-readonly-conflict-9 "$testcvs -Q update -A $file" ''

	  # This one would fail because cvs couldn't open the existing
	  # (and read-only) .# file for writing.
	  echo conflict > $file

	  # verify that the backup file is not writable
	  if test -w ".#$file.1.1"; then
	    fail "join-readonly-conflict-10 : .#$file.1.1 is writable"
	  else
	    pass "join-readonly-conflict-10"
	  fi
	  dotest join-readonly-conflict-11 "$testcvs update -r B $file" \
"RCS file: $CVSROOT_DIRNAME/$module/$file,v
retrieving revision 1\.1
retrieving revision 1\.1\.2\.1
Merging differences between 1\.1 and 1\.1\.2\.1 into $file
rcsmerge: warning: conflicts during merge
${SPROG} update: conflicts found in $file
C m"

	  dokeep
	  cd ../..
	  rm -r join-readonly-conflict
	  modify_repo rm -rf $CVSROOT_DIRNAME/$module
	  ;;



	join-admin)
	  mkdir 1; cd 1
	  dotest join-admin-0-1 "$testcvs -q co -l ."
	  module=x
	  mkdir $module
	  dotest join-admin-0-2 "$testcvs -q add $module" \
"Directory $CVSROOT_DIRNAME/$module added to the repository"
	  cd $module

	  # Create a file so applying the first tag works.
	  echo foo > a
	  dotest join-admin-0-3 "$testcvs -Q add a" ''
	  dotest join-admin-0-4 "$testcvs -Q ci -m. a" ''

	  dotest join-admin-0-5 "$testcvs -Q tag -b B" ''
	  dotest join-admin-0-6 "$testcvs -Q tag -b M1" ''
	  echo '$''Id$' > b
	  dotest join-admin-0-7 "$testcvs -Q add b" ''
	  dotest join-admin-0-8 "$testcvs -Q ci -m. b" ''
	  dotest join-admin-0-9 "$testcvs -Q tag -b M2" ''

	  dotest join-admin-0-10 "$testcvs -Q update -r B" ''
	  dotest join-admin-0-11 "$testcvs -Q update -kk -jM1 -jM2" ''
	  dotest join-admin-0-12 "$testcvs -Q ci -m. b" ''

	  dotest join-admin-0-13 "$testcvs -Q update -A" ''

	  # Verify that the -kk flag from the update did not
	  # propagate to the repository.
	  dotest join-admin-1 "$testcvs status b" \
"===================================================================
File: b                	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/x/b,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"

	  dokeep
	  cd ../..
	  rm -rf 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/$module
	  ;;



	join-admin-2)
	  # Show that when a merge (via update -kk -jtag1 -jtag2) first
	  # removes a file, then modifies another containing an $Id...$ line,
	  # the resulting file contains the unexpanded `$Id.$' string, as
	  # -kk requires.
	  mkdir 1; cd 1
	  dotest join-admin-2-1 "$testcvs -q co -l ." ''
	  module=x
	  mkdir $module
	  dotest join-admin-2-2 "$testcvs -q add $module" \
"Directory ${CVSROOT_DIRNAME}/x added to the repository"
	  cd $module

	  # Create a file so applying the first tag works.
	  echo '$''Id$' > e0
	  cp e0 e
	  dotest join-admin-2-3 "$testcvs -Q add e"
	  dotest join-admin-2-4 "$testcvs -Q ci -m. e"

	  dotest join-admin-2-5 "$testcvs -Q tag -b T" '' "${QUESTION} e0"
	  dotest join-admin-2-6 "$testcvs -Q update -r T" '' "${QUESTION} e0"
	  cp e0 e
	  dotest join-admin-2-7 "$testcvs -Q ci -m. e"

	  dotest join-admin-2-8 "$testcvs -Q update -A" '' "${QUESTION} e0"
	  dotest join-admin-2-9 "$testcvs -Q tag -b M1" '' "${QUESTION} e0"

	  echo '$''Id$' > b
	  dotest join-admin-2-10 "$testcvs -Q add b" ''
	  cp e0 e
	  dotest join-admin-2-11 "$testcvs -Q ci -m. b e"

	  dotest join-admin-2-12 "$testcvs -Q tag -b M2" '' "${QUESTION} e0"

	  dotest join-admin-2-13 "$testcvs -Q update -r T" '' "${QUESTION} e0"
	  dotest join-admin-2-14 "$testcvs update -kk -jM1 -jM2" \
"${SPROG} update: Updating .
U b
U e
RCS file: ${CVSROOT_DIRNAME}/x/e,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into e
e already contains the differences between 1\.1 and 1\.2
${QUESTION} e0" \
"${QUESTION} e0
${SPROG} update: Updating .
U b
U e
RCS file: ${CVSROOT_DIRNAME}/x/e,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into e
e already contains the differences between 1\.1 and 1\.2"

	  # Verify that the $Id.$ string is not expanded.
	  dotest join-admin-2-15 "cat e" '$''Id$'

	  dokeep
	  cd ../..
	  rm -rf 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/$module
	  ;;



	join-rm)
	  # This first half of this test checks that a single-argument merge
	  # from a branch is capable of removing files.
	  #
	  # The second half verifies that an update to another location with an
	  # uncommitted removal will transfer the destination branch of the
	  # removal.

	  module=join-rm
	  mkdir $module; cd $module

	  dotest join-rm-init-1 "$testcvs -q co -l ." ''
	  mkdir $module
	  dotest join-rm-init-2 "$testcvs -q add $module" \
"Directory $CVSROOT_DIRNAME/$module added to the repository"
	  cd $module

	  # add some files.
	  touch a b c d e f g
	  dotest join-rm-init-3 "$testcvs -Q add a b c d e f g"
	  dotest join-rm-init-4 "$testcvs -Q ci -m add-em"
	  
	  # create the branch and update to it
	  dotest join-rm-init-5 "$testcvs -Q tag -b br"
	  dotest join-rm-init-6 "$testcvs -Q up -rbr"

	  # remove a few files from the branch
	  dotest join-rm-init-7 "$testcvs -Q rm -f b d g"
	  dotest join-rm-init-8 "$testcvs -Q ci -mrm"

	  # update to the trunk
	  dotest join-rm-init-9 "$testcvs -Q up -A"

	  # now for the test - try and merge the removals.
	  dotest join-rm-1 "$testcvs -q up -jbr" \
"$SPROG update: scheduling \`b' for removal
$SPROG update: scheduling \`d' for removal
$SPROG update: scheduling \`g' for removal"

	  # And make sure the merge took
	  dotest join-rm-2 "$testcvs -qn up" \
"R b
R d
R g"

	  dotest join-rm-3 "$testcvs -q ci -m 'save the merge'" \
"$CVSROOT_DIRNAME/join-rm/b,v  <--  b
new revision: delete; previous revision: 1\.1
$CVSROOT_DIRNAME/join-rm/d,v  <--  d
new revision: delete; previous revision: 1\.1
$CVSROOT_DIRNAME/join-rm/g,v  <--  g
new revision: delete; previous revision: 1\.1"

	  # and verify that it was the head revision which was removed.
	  dotest join-rm-4 "$testcvs -q log b"  "
RCS file: $CVSROOT_DIRNAME/join-rm/Attic/b,v
Working file: b
head: 1\.2
branch:
locks: strict
access list:
symbolic names:
	br: 1\.1\.0\.2
keyword substitution: kv
total revisions: 3;	selected revisions: 3
description:
----------------------------
revision 1\.2
date: ${ISO8601DATE};  author: $username;  state: dead;  lines: ${PLUS}0 -0;  commitid: ${commitid};
save the merge
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
branches:  1.1.2;
add-em
----------------------------
revision 1\.1\.2\.1
date: ${ISO8601DATE};  author: $username;  state: dead;  lines: ${PLUS}0 -0;  commitid: ${commitid};
rm
============================================================================="

	  # go back to the branch to set up for the second set of tests
	  dotest join-rm-init-10 "$testcvs -Q up -rbr"
	  dotest join-rm-init-11 "$testcvs -Q rm -f a"
	  dotest join-rm-init-12 "$testcvs -Q ci -m rma"

	  # now the test: update to the trunk
	  #
	  # FIXCVS: This update should merge the removal to the trunk.  It does
	  # not.
	  dotest join-rm-5 "$testcvs -q up -A" "U a"

	  # and verify that there is no sticky tag
	  dotest join-rm-6 "$testcvs status a" \
"===================================================================
File: a                	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	$CVSROOT_DIRNAME/join-rm/a,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"

	  dokeep
	  cd ../..
	  modify_repo rm -rf $CVSROOT_DIRNAME/$module
	  rm -r $module
	  ;;



	new) # look for stray "no longer pertinent" messages.
	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  dotest new-init-1 "$testcvs -Q co first-dir"

	  cd first-dir
	  touch a

	  dotest new-1 "$testcvs -Q add a"

	  dotest new-2 "$testcvs -Q ci -m added"
	  rm a

	  dotest new-3 "$testcvs -Q rm a"
	  dotest new-4 "$testcvs -Q ci -m removed"
	  dotest new-5 "$testcvs -Q update -A"
	  dotest new-6 "$testcvs -Q update -rHEAD"

	  dokeep
	  cd ..
	  rm -r first-dir
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	newb)
	  # Test removing a file on a branch and then checking it out.

	  # We call this "newb" only because it, like the "new" tests,
	  # has something to do with "no longer pertinent" messages.
	  # Not necessarily the most brilliant nomenclature.

	  # Create file 'a'.
	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  dotest newb-123a "${testcvs} -q co first-dir" ''
	  cd first-dir
	  touch a
	  dotest newb-123b "${testcvs} add a" \
"${SPROG} add: scheduling file .a. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest newb-123c "${testcvs} -q ci -m added" \
"$CVSROOT_DIRNAME/first-dir/a,v  <--  a
initial revision: 1\.1"

	  # Make a branch.
	  dotest newb-123d "${testcvs} -q tag -b branch" "T a"

	  # Check out the branch.
	  cd ..
	  rm -r first-dir
	  mkdir 1
	  cd 1
	  dotest newb-123e "${testcvs} -q co -r branch first-dir" \
"U first-dir/a"

	  # Remove 'a' on another copy of the branch.
	  cd ..
	  mkdir 2
	  cd 2
	  dotest newb-123f "${testcvs} -q co -r branch first-dir" \
"U first-dir/a"
	  cd first-dir
	  rm a
	  dotest newb-123g "${testcvs} rm a" \
"${SPROG} remove: scheduling .a. for removal
${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
	  dotest newb-123h "${testcvs} -q ci -m removed" \
"$CVSROOT_DIRNAME/first-dir/a,v  <--  a
new revision: delete; previous revision: 1\.1"

	  # Check out the file on the branch.  This should report
	  # that the file is not pertinent, but it should not
	  # say anything else.
	  cd ..
	  rm -r first-dir
	  dotest newb-123i "${testcvs} -q co -r branch first-dir/a" \
"${SPROG} checkout: warning: \`first-dir/a' is not (any longer) pertinent"

	  # Update the other copy, and make sure that a is removed.
	  cd ../1/first-dir
	  # "Entry Invalid" is a rather strange output here.  Something like
	  # "Removed in Repository" would make more sense.
	  dotest newb-123j0 "${testcvs} status a" \
"${SPROG} status: \`a' is no longer in the repository
===================================================================
File: a                	Status: Entry Invalid

   Working revision:	1\.1.*
   Repository revision:	1\.1\.2\.1	${CVSROOT_DIRNAME}/first-dir/a,v
   Commit Identifier:	${commitid}
   Sticky Tag:		branch (branch: 1\.1\.2)
   Sticky Date:		(none)
   Sticky Options:	(none)${DOTSTAR}"
	  dotest newb-123j "${testcvs} -q update" \
"${SPROG} update: \`a' is no longer in the repository"

	  if test -f a; then
	    fail newb-123k
	  else
	    pass newb-123k
	  fi

	  dokeep
	  cd ../..
	  rm -r 1 2
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	conflicts)
		modify_repo mkdir $CVSROOT_DIRNAME/first-dir

		mkdir 1
		cd 1

		dotest conflicts-124 "${testcvs} -q co first-dir" ''

		cd first-dir
		touch a

		dotest conflicts-125 "${testcvs} add a" \
"${SPROG} add: scheduling file .a. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
		dotest conflicts-126 "${testcvs} -q ci -m added" \
"$CVSROOT_DIRNAME/first-dir/a,v  <--  a
initial revision: 1\.1"

		cd ../..
		mkdir 2
		cd 2

		dotest conflicts-126.5 "${testcvs} co -p first-dir" \
"${SPROG} checkout: Updating first-dir
===================================================================
Checking out first-dir/a
RCS:  ${CVSROOT_DIRNAME}/first-dir/a,v
VERS: 1\.1
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*"
		dotest conflicts-127 "${testcvs} -Q co first-dir" ''
		cd first-dir
		dotest conflicts-127a "test -f a" ''

		cd ../../1/first-dir
		echo add a line >>a
		mkdir dir1
		dotest conflicts-127b "${testcvs} add dir1" \
"Directory ${CVSROOT_DIRNAME}/first-dir/dir1 added to the repository"
		dotest conflicts-128 "${testcvs} -q ci -m changed" \
"$CVSROOT_DIRNAME/first-dir/a,v  <--  a
new revision: 1\.2; previous revision: 1\.1"
		cd ../..

		# Similar to conflicts-126.5, but now the file has nonempty
		# contents.
		mkdir 3
		cd 3
		dotest conflicts-128.5 "${testcvs} co -p -l first-dir" \
"${SPROG} checkout: Updating first-dir
===================================================================
Checking out first-dir/a
RCS:  ${CVSROOT_DIRNAME}/first-dir/a,v
VERS: 1\.2
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
add a line"
		cd ..
		rmdir 3

		# Now go over the to the other working directory and
		# start testing conflicts
		cd 2/first-dir
		echo add a conflicting line >>a
		dotest_fail conflicts-129 "${testcvs} -q ci -m changed" \
"${SPROG}"' commit: Up-to-date check failed for `a'\''
'"${SPROG}"' \[commit aborted\]: correct above errors first!'
		mkdir dir1
		mkdir sdir
		dotest conflicts-status-0 "${testcvs} status a" \
"===================================================================
File: a                	Status: Needs Merge

   Working revision:	1\.1.*
   Repository revision:	1\.2	${CVSROOT_DIRNAME}/first-dir/a,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
		dotest conflicts-129a "${testcvs} -nq update a" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into a
rcsmerge: warning: conflicts during merge
${SPROG} update: conflicts found in a
C a"
		dotest conflicts-130 "${testcvs} -q update" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into a
rcsmerge: warning: conflicts during merge
${SPROG} update: conflicts found in a
C a
${QUESTION} dir1
${QUESTION} sdir" \
"${QUESTION} dir1
${QUESTION} sdir
RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into a
rcsmerge: warning: conflicts during merge
${SPROG} update: conflicts found in a
C a"
		rmdir dir1 sdir

		dotest conflicts-status-1 "${testcvs} status a" \
"===================================================================
File: a                	Status: Unresolved Conflict

   Working revision:	1\.2.*
   Repository revision:	1\.2	${CVSROOT_DIRNAME}/first-dir/a,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
		dotest_fail conflicts-131 "${testcvs} -q ci -m try" \
"${SPROG} commit: file .a. had a conflict and has not been modified
${SPROG} \[commit aborted\]: correct above errors first!"

		# Try to check in the file with the conflict markers in it.
		# Make sure we detect any one of the three conflict markers
		mv a aa
		grep '^<<<<<<<' aa >a
		dotest conflicts-status-2 "${testcvs} -nq ci -m try a" \
"${SPROG} commit: warning: file .a. seems to still contain conflict indicators"

		grep '^=======' aa >a
		dotest conflicts-status-3 "${testcvs} -nq ci -m try a" \
"${SPROG} commit: warning: file .a. seems to still contain conflict indicators"

		grep '^>>>>>>>' aa >a
		dotest conflicts-status-4 "${testcvs} -qn ci -m try a" \
"${SPROG} commit: warning: file .a. seems to still contain conflict indicators"

		mv aa a
		echo lame attempt at resolving it >>a
		dotest conflicts-status-5 "${testcvs} status a" \
"===================================================================
File: a                	Status: File had conflicts on merge

   Working revision:	1\.2.*
   Repository revision:	1\.2	${CVSROOT_DIRNAME}/first-dir/a,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
		dotest conflicts-132 "$testcvs -q ci -m try" \
"$SPROG commit: warning: file .a. seems to still contain conflict indicators
$CVSROOT_DIRNAME/first-dir/a,v  <--  a
new revision: 1\.3; previous revision: 1\.2"

		# OK, the user saw the warning (good user), and now
		# resolves it for real.
		echo resolve conflict >a
		dotest conflicts-status-6 "${testcvs} status a" \
"===================================================================
File: a                	Status: Locally Modified

   Working revision:	1\.3.*
   Repository revision:	1\.3	${CVSROOT_DIRNAME}/first-dir/a,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
		dotest conflicts-133 "${testcvs} -q ci -m resolved" \
"$CVSROOT_DIRNAME/first-dir/a,v  <--  a
new revision: 1\.4; previous revision: 1\.3"
		dotest conflicts-status-7 "${testcvs} status a" \
"===================================================================
File: a                	Status: Up-to-date

   Working revision:	1\.4.*
   Repository revision:	1\.4	${CVSROOT_DIRNAME}/first-dir/a,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"

		# Now test that we can add a file in one working directory
		# and have an update in another get it.
		cd ../../1/first-dir
		echo abc >abc
		if ${testcvs} add abc >>${LOGFILE} 2>&1; then
		    pass 134
		else
		    fail 134
		fi
		if ${testcvs} ci -m 'add abc' abc >>${LOGFILE} 2>&1; then
		    pass 135
		else
		    fail 135
		fi
		cd ../../2
		mkdir first-dir/dir1 first-dir/sdir
		dotest conflicts-136 "${testcvs} -q update first-dir" \
'[UP] first-dir/abc
'"${QUESTION}"' first-dir/dir1
'"${QUESTION}"' first-dir/sdir' \
''"${QUESTION}"' first-dir/dir1
'"${QUESTION}"' first-dir/sdir
[UP] first-dir/abc'
		dotest conflicts-137 'test -f first-dir/abc' ''
		rmdir first-dir/dir1 first-dir/sdir

		# Now test something similar, but in which the parent directory
		# (not the directory in question) has the Entries.Static flag
		# set.
		cd ../1/first-dir
		mkdir subdir
		dotest conflicts-138 "${testcvs} add subdir" "${DOTSTAR}"
		cd ../..
		mkdir 3
		cd 3
		dotest conflicts-139 \
"${testcvs} -q co first-dir/abc first-dir/subdir" "${DOTSTAR}"
		cd ../1/first-dir/subdir
		echo sss >sss
		dotest conflicts-140 "${testcvs} add sss" "${DOTSTAR}"
		dotest conflicts-140a "${testcvs} ci -m adding sss" \
"${DOTSTAR}"
		cd ../../../3/first-dir
		dotest conflicts-141 "${testcvs} -q update" "${DOTSTAR}"
		dotest conflicts-142 "test -f subdir/sss"

		dokeep
		cd ../..
		rm -r 1 2 3
		modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
		restore_adm
		;;



	conflicts2)
	  # More conflicts tests; separate from conflicts to keep each
	  # test a manageable size.
	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir

	  mkdir 1
	  cd 1

	  dotest conflicts2-142a1 "${testcvs} -q co first-dir" ''

	  cd first-dir
	  touch a abc

	  dotest conflicts2-142a2 "${testcvs} add a abc" \
"${SPROG} add: scheduling file .a. for addition
${SPROG} add: scheduling file .abc. for addition
${SPROG} add: use .${SPROG} commit. to add these files permanently"
	  dotest conflicts2-142a3 "${testcvs} -q ci -m added" \
"$CVSROOT_DIRNAME/first-dir/a,v  <--  a
initial revision: 1\.1
${CVSROOT_DIRNAME}/first-dir/abc,v  <--  abc
initial revision: 1\.1"

	  cd ../..
	  mkdir 2
	  cd 2

	  dotest conflicts2-142a4 "${testcvs} -q co first-dir" 'U first-dir/a
U first-dir/abc'
	  cd ..

	  # BEGIN TESTS USING THE FILE A
	  # FIXME: would be cleaner to separate them out into their own
	  # tests; conflicts2 is getting long.
	  # Now test that if one person modifies and commits a
	  # file and a second person removes it, it is a
	  # conflict
	  cd 1/first-dir
	  echo modify a >>a
	  dotest conflicts2-142b2 "${testcvs} -q ci -m modify-a" \
"$CVSROOT_DIRNAME/first-dir/a,v  <--  a
new revision: 1\.2; previous revision: 1\.1"
	  cd ../../2/first-dir
	  rm a
	  dotest conflicts2-142b3 "${testcvs} rm a" \
"${SPROG} remove: scheduling .a. for removal
${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
	  dotest_fail conflicts2-142b4 "${testcvs} -q update" \
"${SPROG} update: conflict: removed \`a' was modified by second party
C a"
	  # Resolve the conflict by deciding not to remove the file
	  # after all.
	  dotest_sort conflicts2-142b5 "$testcvs add a" "U a
${SPROG} add: \`a', version 1\.1, resurrected"
	  dotest conflicts2-142b5b1 "$testcvs status a" \
"===================================================================
File: a                	Status: Needs Patch

   Working revision:	1\.1.*
   Repository revision:	1\.2	$CVSROOT_DIRNAME/first-dir/a,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"
	  dotest conflicts2-142b6 "$testcvs -q update" 'U a'

	  # Now one level up.
	  cd ..
	  dotest conflicts2-142b7 "${testcvs} rm -f first-dir/a" \
"${SPROG} remove: scheduling \`first-dir/a' for removal
${SPROG} remove: use \`${SPROG} commit' to remove this file permanently"

	  if $remote; then
	    # Haven't investigated this one.
	    dotest_fail conflicts2-142b8r "$testcvs add first-dir/a" \
"${CPROG} add: in directory \`\.':
${CPROG} \[add aborted\]: there is no version here; do \`${CPROG} checkout' first"
	    cd first-dir
	  else
	    dotest conflicts2-142b8 "${testcvs} add first-dir/a" \
"U first-dir/a
$SPROG add: \`first-dir/a', version 1\.2, resurrected"
	    cd first-dir
	    # Now recover from the damage that the 142b8 test did.
	    dotest conflicts2-142b9 "${testcvs} rm -f a" \
"${SPROG} remove: scheduling \`a' for removal
${SPROG} remove: use \`${SPROG} commit' to remove this file permanently"
	  fi

	  # As before, 1.2 instead of 1.1 is a bug.
	  dotest_sort conflicts2-142b10 "$testcvs add a" "U a
${SPROG} add: \`a', version 1\.2, resurrected"
	  # As with conflicts2-142b6, check that things are normal again.
	  dotest conflicts2-142b11 "${testcvs} -q update" ''
	  cd ../..
	  # END TESTS USING THE FILE A

	  # Now test that if one person removes a file and
	  # commits it, and a second person removes it, is it
	  # not a conflict.
	  cd 1/first-dir
	  rm abc
	  dotest conflicts2-142c0 "${testcvs} rm abc" \
"${SPROG} remove: scheduling \`abc' for removal
${SPROG} remove: use \`${SPROG} commit' to remove this file permanently"
	  dotest conflicts2-142c1 "${testcvs} -q ci -m remove-abc" \
"$CVSROOT_DIRNAME/first-dir/abc,v  <--  abc
new revision: delete; previous revision: 1\.1"
	  cd ../../2/first-dir
	  rm abc
	  dotest conflicts2-142c2 "${testcvs} rm abc" \
"${SPROG} remove: scheduling \`abc' for removal
${SPROG} remove: use \`${SPROG} commit' to remove this file permanently"
	  dotest conflicts2-142c3 "${testcvs} update" \
"${SPROG} update: Updating \."
	  cd ../..

	  # conflicts2-142d*: test that if one party adds a file, and another
	  # party has a file of the same name, cvs notices
	  cd 1/first-dir
	  touch aa.c
	  echo 'contents unchanged' >same.c
	  dotest conflicts2-142d0 "${testcvs} add aa.c same.c" \
"${SPROG} add: scheduling file .aa\.c. for addition
${SPROG} add: scheduling file .same\.c. for addition
${SPROG} add: use .${SPROG} commit. to add these files permanently"
	  dotest conflicts2-142d1 "${testcvs} -q ci -m added" \
"$CVSROOT_DIRNAME/first-dir/aa\.c,v  <--  aa\.c
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/same\.c,v  <--  same\.c
initial revision: 1\.1"

	  # Test the case where the second user manages the add before the
	  # first commits
	  touch bb.c
	  dotest conflicts2-142d1a "$testcvs add bb.c" \
"$SPROG add: scheduling file .bb\.c. for addition
$SPROG add: use .$SPROG commit. to add this file permanently"
	  cd ../../2/first-dir
	  echo "don't you dare obliterate this text" >bb.c
	  dotest conflicts2-142d1b "$testcvs add bb.c" \
"$SPROG add: scheduling file .bb\.c. for addition
$SPROG add: use .$SPROG commit. to add this file permanently"
	  cd ../../1/first-dir
	  dotest conflicts2-142d1c "$testcvs -q ci -m added" \
"$CVSROOT_DIRNAME/first-dir/bb\.c,v  <--  bb\.c
initial revision: 1\.1"

	  cd ../../2/first-dir
	  echo "don't you dare obliterate this text either" >aa.c
	  echo 'contents unchanged' >same.c
	  # Note the discrepancy between local and remote in the handling
	  # of same.c.  I kind
	  # of suspect that the local CVS behavior is the more useful one
	  # although I do sort of wonder whether we should make people run
	  # cvs add just to get them in that habit (also, trying to implement
	  # the local CVS behavior for remote without the cvs add seems 
	  # pretty difficult).
	  if $remote; then
	    dotest_fail conflicts2-142d2r "${testcvs} -q update" \
"${QUESTION} aa\.c
${QUESTION} same\.c
${CPROG} update: move away \`\./aa\.c'; it is in the way
C aa\.c
${SPROG} update: conflict: \`bb\.c' created independently by second party
C bb\.c
${CPROG} update: move away \`\./same\.c'; it is in the way
C same\.c"
	  else
	    dotest_fail conflicts2-142d2 "${testcvs} -q update" \
"${CPROG} update: move away \`aa\.c'; it is in the way
C aa\.c
${CPROG} update: conflict: \`bb\.c' created independently by second party
C bb\.c
U same\.c"
	  fi
	  dotest conflicts2-142d3 "${testcvs} -q status aa.c" \
"${SPROG} status: move away \`aa\.c'; it is in the way
===================================================================
File: aa\.c             	Status: Unresolved Conflict

   Working revision:	No entry for aa\.c
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/aa\.c,v
   Commit Identifier:	${commitid}"
	  dotest conflicts2-142d3a "${testcvs} -q status bb.c" \
"${SPROG} status: conflict: \`bb\.c' created independently by second party
===================================================================
File: bb\.c             	Status: Unresolved Conflict

   Working revision:	New file!
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/bb\.c,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)"

	  # FIXCVS
	  # This message seems somewhat bogus.  I mean, parallel development
	  # means that we get to work in parallel if we choose, right?  And
	  # then at commit time it would be a conflict.
	  #
	  # Well, the status is "Unresolved conflict" before _and_ after
	  # the update/merge (when conflicts happen, not at commit time).
	  # It is possible that this message could be changed to something
	  # more infomrative to novice users, like "File of same name exists
	  # in repository", or "File of same name committed independantly by
	  # second party", but these two messages look too long for the Status
	  # field and the move away & added independantly error messages _are_
	  # displayed.  Still, we get a lot of questions about this on the
	  # email lists.  Somehow we need to get more information to users
	  # via these messages and the ones generated by update. -DRP
	  dotest_fail conflicts2-142d4 "${testcvs} -q add aa.c" \
"${SPROG} add: \`aa.c' added independently by second party"

	  # The user might want to see just what the conflict is.
	  # Don't bother, diff seems to kind of lose its mind, with or
	  # without -N.  This is a CVS bug(s).
	  #dotest conflicts2-142d5 \
	  #"${testcvs} -q diff -r HEAD -N aa.c" FIXCVS THEN FIXME

	  # Now: "how can the user resolve this conflict", I hear you cry.
	  # Well, one way is to forget about the file in the working
	  # directory.
	  # Since it didn't let us do the add in conflicts2-142d4, there
	  # is no need to run cvs rm here.
	  #dotest conflicts2-142d6 "${testcvs} -q rm -f aa.c" fixme
	  dotest conflicts2-142d6 "rm aa.c" ''
	  dotest conflicts2-142d7 "${testcvs} -q update aa.c" "U aa\.c"
	  dotest conflicts2-142d8 "cat aa.c" ''

	  # The other way is to use the version from the working directory
	  # instead of the version from the repository.  Unfortunately,
	  # there doesn't seem to be any particularly clear way to do
	  # this (?).

	  dokeep
	  cd ../..
	  rm -r 1 2
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	conflicts3)
	  # More tests of conflicts and/or multiple working directories
	  # in general.

	  mkdir 1; cd 1
	  dotest conflicts3-1 "$testcvs -q co -l ."
	  mkdir first-dir
	  dotest conflicts3-2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
	  cd ..
	  mkdir 2; cd 2
	  dotest conflicts3-3 "${testcvs} -q co -l first-dir" ''
	  cd ../1/first-dir
	  touch file1 file2
	  dotest conflicts3-4 "${testcvs} add file1 file2" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: scheduling file .file2. for addition
${SPROG} add: use .${SPROG} commit. to add these files permanently"
	  dotest conflicts3-5 "${testcvs} -q ci -m add-them" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
initial revision: 1\.1"
	  cd ../../2/first-dir
	  # Check that -n doesn't make CVS lose its mind as it creates
	  # (or rather, doesn't) a new file.
	  dotest conflicts3-6 "${testcvs} -nq update" \
"U file1
U file2"
	  dotest_fail conflicts3-7 "test -f file1" ''
	  dotest conflicts3-8 "${testcvs} -q update" \
"U file1
U file2"
	  dotest conflicts3-9 "test -f file2" ''

	  # OK, now remove two files at once
	  dotest conflicts3-10 "${testcvs} rm -f file1 file2" \
"${SPROG} remove: scheduling .file1. for removal
${SPROG} remove: scheduling .file2. for removal
${SPROG} remove: use .${SPROG} commit. to remove these files permanently"
	  dotest conflicts3-11 "${testcvs} -q ci -m remove-them" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: delete; previous revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
new revision: delete; previous revision: 1\.1"
	  cd ../../1/first-dir
	  dotest conflicts3-12 "${testcvs} -n -q update" \
"${SPROG} update: \`file1' is no longer in the repository
${SPROG} update: \`file2' is no longer in the repository"
	  dotest conflicts3-13 "${testcvs} -q update" \
"${SPROG} update: \`file1' is no longer in the repository
${SPROG} update: \`file2' is no longer in the repository"

	  # OK, now add a directory to both working directories
	  # and see that CVS doesn't lose its mind.
	  mkdir sdir
	  dotest conflicts3-14 "${testcvs} add sdir" \
"Directory ${CVSROOT_DIRNAME}/first-dir/sdir added to the repository"
	  touch sdir/sfile
	  dotest conflicts3-14a "${testcvs} add sdir/sfile" \
"${SPROG} add: scheduling file .sdir/sfile. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest conflicts3-14b "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/sdir/sfile,v  <--  sdir/sfile
initial revision: 1\.1"

	  cd ../../2/first-dir

	  # Create a CVS directory without the proper administrative
	  # files in it.  This can happen for example if you hit ^C
	  # in the middle of a checkout.
	  mkdir sdir
	  mkdir sdir/CVS
	  # OK, in the local case CVS sees that the directory exists
	  # in the repository and recurses into it.  In the remote case
	  # CVS can't see the repository and has no way of knowing
	  # that sdir is even a directory (stat'ing everything would be
	  # too slow).  The remote behavior makes more sense to me (but
	  # would this affect other cases?).
	  if $remote; then
	    dotest conflicts3-15 "${testcvs} -q update" \
"${QUESTION} sdir"
	  else
	    dotest conflicts3-15 "${testcvs} -q update" \
"${QUESTION} sdir
${SPROG} update: ignoring sdir (CVS/Repository missing)"
	    touch sdir/CVS/Repository
	    dotest conflicts3-16 "${testcvs} -q update" \
"${QUESTION} sdir
${SPROG} update: ignoring sdir (CVS/Entries missing)"
	    cd ..
	    dotest conflicts3-16a "${testcvs} -q update first-dir" \
"${QUESTION} first-dir/sdir
${SPROG} update: ignoring first-dir/sdir (CVS/Entries missing)"
	    cd first-dir
	  fi
	  rm -r sdir

	  # OK, now the same thing, but the directory doesn't exist
	  # in the repository.
	  mkdir newdir
	  mkdir newdir/CVS
	  dotest conflicts3-17 "${testcvs} -q update" "${QUESTION} newdir"
	  echo "D/newdir////" >> CVS/Entries
	  dotest conflicts3-18 "${testcvs} -q update" \
"${CPROG} update: ignoring newdir (CVS/Repository missing)"
	  touch newdir/CVS/Repository
	  dotest conflicts3-19 "${testcvs} -q update" \
"${CPROG} update: ignoring newdir (CVS/Entries missing)"
	  cd ..
	  dotest conflicts3-20 "${testcvs} -q update first-dir" \
"${CPROG} update: ignoring first-dir/newdir (CVS/Entries missing)"
	  cd first-dir
	  rm -r newdir

	  # The previous tests have left CVS/Entries in something of a mess.
	  # While we "should" be able to deal with that (maybe), for now
	  # we just start over.
	  cd ..
	  rm -r first-dir
	  dotest conflicts3-20a "${testcvs} -q co -l first-dir" ''
	  cd first-dir

	  dotest conflicts3-21 "${testcvs} -q update -d sdir" "U sdir/sfile"
	  rm -r sdir/CVS
	  dotest conflicts3-22 "${testcvs} -q update" "${QUESTION} sdir"
	  if $remote; then
	    dotest_fail conflicts3-23 "${testcvs} -q update -PdA" \
"${QUESTION} sdir
${CPROG} update: move away \`sdir/sfile'; it is in the way
C sdir/sfile"
	  else
	    dotest conflicts3-23 "${testcvs} -q update -PdA" \
"${QUESTION} sdir"
	  fi

	  # Not that it should really affect much, but let's do the case
	  # where sfile has been removed.  For example, suppose that sdir
	  # had been a CVS-controlled directory which was then removed
	  # by removing each file (and using update -P or some such).  Then
	  # suppose that the build process creates an sdir directory which
	  # is not supposed to be under CVS.
	  rm -r sdir
	  dotest conflicts3-24 "${testcvs} -q update -d sdir" "U sdir/sfile"
	  rm sdir/sfile
	  dotest conflicts3-25 "${testcvs} rm sdir/sfile" \
"${SPROG} remove: scheduling .sdir/sfile. for removal
${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
	  dotest conflicts3-26 "${testcvs} ci -m remove sdir/sfile" \
"${CVSROOT_DIRNAME}/first-dir/sdir/sfile,v  <--  sdir/sfile
new revision: delete; previous revision: 1\.1"
	  rm -r sdir/CVS
	  dotest conflicts3-27 "${testcvs} -q update" "${QUESTION} sdir"
	  dotest conflicts3-28 "${testcvs} -q update -PdA" \
"${QUESTION} sdir"

	  dokeep
	  cd ../..
	  rm -r 1 2
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	clean)
	  # Test update -C (overwrite local mods w/ repository copies)
	  mkdir 1; cd 1
	  dotest clean-1 "${testcvs} -q co -l ." ''
	  mkdir first-dir
	  dotest clean-2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
	  cd first-dir
	  echo "The usual boring test text." > cleanme.txt
          dotest clean-3 "${testcvs} add cleanme.txt" \
"${SPROG} add: scheduling file .cleanme\.txt. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest clean-4 "${testcvs} -q ci -m clean-3" \
"$CVSROOT_DIRNAME/first-dir/cleanme\.txt,v  <--  cleanme\.txt
initial revision: 1\.1"
          # Okay, preparation is done, now test.
          # Check that updating an unmodified copy works.
	  dotest clean-5 "${testcvs} -q update" ''
          # Check that updating -C an unmodified copy works.
	  dotest clean-6 "${testcvs} -q update -C" ''
          # Check that updating a modified copy works.
	  echo "fish" >> cleanme.txt
	  dotest clean-7 "${testcvs} -q update" 'M cleanme\.txt'
          # Check that updating -C a modified copy works.
	  dotest clean-8 "${testcvs} -q update -C" \
"(Locally modified cleanme\.txt moved to \.#cleanme\.txt\.1\.1)
U cleanme\.txt"
	  # And check that the backup copy really was made.
	  dotest clean-9 "cat .#cleanme.txt.1.1" \
"The usual boring test text\.
fish"

          # Do it all again, this time naming the file explicitly.
	  rm .#cleanme.txt.1.1
	  dotest clean-10 "${testcvs} -q update cleanme.txt" ''
	  dotest clean-11 "${testcvs} -q update -C cleanme.txt" ''
	  echo "bluegill" >> cleanme.txt
	  dotest clean-12 "${testcvs} -q update cleanme.txt" 'M cleanme\.txt'
	  dotest clean-13 "${testcvs} -q update -C cleanme.txt" \
"(Locally modified cleanme\.txt moved to \.#cleanme\.txt\.1\.1)
U cleanme\.txt"
	  # And check that the backup copy really was made.
	  dotest clean-14 "cat .#cleanme.txt.1.1" \
"The usual boring test text\.
bluegill"

	  # Now try with conflicts
	  cd ..
	  dotest clean-15 "${testcvs} -q co -d second-dir first-dir" \
'U second-dir/cleanme\.txt'
	  cd second-dir
	  echo "conflict test" >> cleanme.txt
	  dotest clean-16 "${testcvs} -q ci -m." \
"$CVSROOT_DIRNAME/first-dir/cleanme\.txt,v  <--  cleanme\.txt
new revision: 1\.2; previous revision: 1\.1"
	  cd ../first-dir
	  echo "fish" >> cleanme.txt
	  dotest clean-17 "${testcvs} -nq update" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/cleanme\.txt,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into cleanme\.txt
rcsmerge: warning: conflicts during merge
${SPROG} update: conflicts found in cleanme\.txt
C cleanme\.txt"
	  dotest clean-18 "${testcvs} -q update -C" \
"(Locally modified cleanme\.txt moved to \.#cleanme\.txt\.1\.1)
U cleanme\.txt"
	  dotest clean-19 "cat .#cleanme.txt.1.1" \
"The usual boring test text\.
fish"
	  
          # Done.  Clean up.
	  dokeep
	  cd ../..
          rm -rf 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	keywordexpand)
	  # Tests of the original *BSD tag= and keywordexpand= features
	  # are done via the LocalKeyword= and KeywordExpand features.

	  # Skip this in noredirect mode because it is too easy for the primary
	  # and secondary error messages to get out of sync when the
	  # CVSROOT/config files are broken.  This is intentional, since it is
	  # possible and even likely that an administrator might want to set up
	  # different configurations on the two servers and the paths to the
	  # config files on the secondary and primary were intentionally left
	  # intact even though they might be different.
	  if $noredirect; then
            notnoredirect keywordexpand
	    continue
	  fi

	  mkdir keywordexpand; cd keywordexpand

	  dotest keywordexpand-1 "${testcvs} -q co CVSROOT" \
'U CVSROOT/checkoutlist
U CVSROOT/commitinfo
U CVSROOT/config
U CVSROOT/cvswrappers
U CVSROOT/loginfo
U CVSROOT/modules
U CVSROOT/notify
U CVSROOT/postadmin
U CVSROOT/postproxy
U CVSROOT/posttag
U CVSROOT/postwatch
U CVSROOT/preproxy
U CVSROOT/rcsinfo
U CVSROOT/taginfo
U CVSROOT/verifymsg'
	  cd CVSROOT
	  echo LocalKeyword=MyBSD=CVSHeader >> config
	  # First do not expand any keywords
	  echo KeywordExpand=i >> config
	  dotest keywordexpand-2 "${testcvs} -Q ci -mkeywordexpand config"

	  cd ..

	  mkdir testimport; cd testimport
	  echo '$''Author$' > file1
	  echo '$''Date$' >> file1
	  echo '$''CVSHeader$' >> file1
	  echo '$''Header$' >> file1
	  echo '$''Id$' >> file1
	  echo '$''Locker$' >> file1
	  echo '$''Log$' >> file1
	  echo '$''Name$' >> file1
	  echo '$''RCSfile$' >> file1
	  echo '$''Revision$' >> file1
	  echo '$''Source$' >> file1
	  echo '$''State$' >> file1
	  echo '$''MyBSD$' >> file1
	  dotest keywordexpand-3 \
"${testcvs} -Q import -I ! -m test-import-with-bsd-keyword keywordexpand vendor v1" \
''
	  cd ..

	  dotest keywordexpand-4 "${testcvs} -Q checkout keywordexpand" ''
	  cd keywordexpand
	  dotest keywordexpand-5 "cat file1" \
"\$""Author\$
\$""Date\$
\$""CVSHeader\$
\$""Header\$
\$""Id\$
\$""Locker\$
\$""Log\$
\$""Name\$
\$""RCSfile\$
\$""Revision\$
\$""Source\$
\$""State\$
\$MyBSD\$"
	  cd ../CVSROOT
	  # Now expand just the MyBSD and Id keywords
	  mv config config.old
	  sed -e 's/KeywordExpand=i/KeywordExpand=iMyBSD,Id/' < config.old > config
	  rm -f config.old
	  dotest keywordexpand-6 "${testcvs} -Q ci -mkeywordexpand config"
	  cd ../keywordexpand
	  echo 'a change' >> file1
	  dotest keywordexpand-7 "${testcvs} -Q ci -madd"
	  dotest keywordexpand-8 "cat file1" \
"\$""Author\$
\$""Date\$
\$""CVSHeader\$
\$""Header\$
\$""Id: file1,v 1\.2 [0-9/]* [0-9:]* ${username} Exp \$
\$""Locker\$
\$""Log\$
\$""Name\$
\$""RCSfile\$
\$""Revision\$
\$""Source\$
\$""State\$
\$MyBSD: keywordexpand/file1,v 1\.2 [0-9/]* [0-9:]* ${username} Exp \$
a change"

	  cd ../CVSROOT
	  mv config config.old
	  sed -e 's/LocalKeyword=MyBSD/LocalKeyword=My_BSD/' \
	      <config.old >config
	  dotest keywordexpand-9 "$testcvs -Q ci -minvalidlocalkeyword config"
	  dotest keywordexpand-10 "$testcvs -Q update config" \
"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Bad character \`_' in key \`My_BSD'"
	  cp config.old config
	  dotest keywordexpand-11 "$testcvs -Q ci -mfixit config" \
"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Bad character \`_' in key \`My_BSD'" \
"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Bad character \`_' in key \`My_BSD'
$SPROG [a-z]*: $CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Bad character \`_' in key \`My_BSD'"
	  dotest keywordexpand-12 "$testcvs -Q update config"
	  sed -e 's/LocalKeyword=MyBSD=CVSHeader/LocalKeyword=MyBSD=Name/' \
	      <config.old >config
	  dotest keywordexpand-13 \
"$testcvs -Q ci -minvalidlocalkeyword2 config"
	  dotest keywordexpand-14 "$testcvs -Q update config" \
"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Unknown LocalId mode: \`Name'"
	  cp config.old config
	  dotest keywordexpand-15 "$testcvs -Q ci -mfixit2 config" \
"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Unknown LocalId mode: \`Name'" \
"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Unknown LocalId mode: \`Name'
$SPROG [a-z]*: $CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: LocalKeyword ignored: Unknown LocalId mode: \`Name'"
	  dotest keywordexpand-16 "$testcvs -Q update config"

	  dokeep
	  # Done. Clean up.
	  cd ../..
	  rm -rf $TESTDIR/keywordexpand
          modify_repo rm -rf $CVSROOT_DIRNAME/keywordexpand
	  restore_adm
	  ;;



	modules)
	  # Tests of various ways to define and use modules.
	  # Roadmap to various modules tests:
	  # -a:
	  #   error on incorrect placement: modules
	  #   error combining with other options: modules2-a*
	  #   infinite loops: modules148a1.1 - modules148a1.2
	  #   use to specify a file more than once: modules3
	  #   use with ! feature: modules4
	  # regular modules: modules, modules2, cvsadm
	  # ampersand modules: modules2
	  # -s: modules.
	  # -d: modules, modules3, cvsadm
	  # -i, -o, -u, -e, -t: modules5
	  # slashes in module names: modules3
	  # invalid module definitions: modules6

	  ############################################################
	  # These tests are to make sure that administrative files get
	  # rebuilt, regardless of how and where files are checked
	  # out.
	  ############################################################
	  # Check out the whole repository
	  mkdir 1; cd 1
	  dotest modules-1 "${testcvs} -q co ." 'U CVSROOT/checkoutlist
U CVSROOT/commitinfo
U CVSROOT/config
U CVSROOT/cvswrappers
U CVSROOT/loginfo
U CVSROOT/modules
U CVSROOT/notify
U CVSROOT/postadmin
U CVSROOT/postproxy
U CVSROOT/posttag
U CVSROOT/postwatch
U CVSROOT/preproxy
U CVSROOT/rcsinfo
U CVSROOT/taginfo
U CVSROOT/verifymsg'
	  echo "# made a change" >>CVSROOT/modules
	  dotest modules-1d "${testcvs} -q ci -m add-modules" \
"$CVSROOT_DIRNAME/CVSROOT/modules,v  <--  CVSROOT/modules
new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
$SPROG commit: Rebuilding administrative file database"
	  cd ..
	  rm -rf 1

	  ############################################################
	  # Check out CVSROOT
	  mkdir 1; cd 1
	  dotest modules-2 "${testcvs} -q co CVSROOT" 'U CVSROOT/checkoutlist
U CVSROOT/commitinfo
U CVSROOT/config
U CVSROOT/cvswrappers
U CVSROOT/loginfo
U CVSROOT/modules
U CVSROOT/notify
U CVSROOT/postadmin
U CVSROOT/postproxy
U CVSROOT/posttag
U CVSROOT/postwatch
U CVSROOT/preproxy
U CVSROOT/rcsinfo
U CVSROOT/taginfo
U CVSROOT/verifymsg'
	  echo "# made a change" >>CVSROOT/modules
	  dotest modules-2d "${testcvs} -q ci -m add-modules" \
"$CVSROOT_DIRNAME/CVSROOT/modules,v  <--  CVSROOT/modules
new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
$SPROG commit: Rebuilding administrative file database"
	  cd ..
	  rm -rf 1

	  ############################################################
	  # Check out CVSROOT in some other directory
	  modify_repo mkdir $CVSROOT_DIRNAME/somedir
	  mkdir 1; cd 1
	  dotest modules-3 "${testcvs} -q co somedir" ''
	  cd somedir
	  dotest modules-3d "${testcvs} -q co CVSROOT" 'U CVSROOT/checkoutlist
U CVSROOT/commitinfo
U CVSROOT/config
U CVSROOT/cvswrappers
U CVSROOT/loginfo
U CVSROOT/modules
U CVSROOT/notify
U CVSROOT/postadmin
U CVSROOT/postproxy
U CVSROOT/posttag
U CVSROOT/postwatch
U CVSROOT/preproxy
U CVSROOT/rcsinfo
U CVSROOT/taginfo
U CVSROOT/verifymsg'
	  echo "# made a change" >>CVSROOT/modules
	  dotest modules-3g "${testcvs} -q ci -m add-modules" \
"$CVSROOT_DIRNAME/CVSROOT/modules,v  <--  CVSROOT/modules
new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
$SPROG commit: Rebuilding administrative file database"
	  cd ../..
	  rm -rf 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/somedir
	  ############################################################
	  # end rebuild tests
	  ############################################################


	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir

	  mkdir 1
	  cd 1

	  dotest modules-143 "${testcvs} -q co first-dir" ""

	  cd first-dir
	  mkdir subdir
	  dotest modules-143a "${testcvs} add subdir" \
"Directory ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository"

	  cd subdir
	  mkdir ssdir
	  dotest modules-143b "${testcvs} add ssdir" \
"Directory ${CVSROOT_DIRNAME}/first-dir/subdir/ssdir added to the repository"

	  touch a b

	  dotest modules-144 "${testcvs} add a b" \
"${SPROG} add: scheduling file .a. for addition
${SPROG} add: scheduling file .b. for addition
${SPROG} add: use .${SPROG} commit. to add these files permanently"

	  dotest modules-145 "$testcvs ci -m added" \
"$CPROG commit: Examining .
$CPROG commit: Examining ssdir
$CVSROOT_DIRNAME/first-dir/subdir/a,v  <--  a
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/subdir/b,v  <--  b
initial revision: 1\.1"

	  cd ..
	  dotest modules-146 "$testcvs -q co CVSROOT" \
"U CVSROOT/checkoutlist
U CVSROOT/commitinfo
U CVSROOT/config
U CVSROOT/cvswrappers
U CVSROOT/loginfo
U CVSROOT/modules
U CVSROOT/notify
U CVSROOT/postadmin
U CVSROOT/postproxy
U CVSROOT/posttag
U CVSROOT/postwatch
U CVSROOT/preproxy
U CVSROOT/rcsinfo
U CVSROOT/taginfo
U CVSROOT/verifymsg"

	  # Here we test that CVS can deal with CVSROOT (whose repository
	  # is at top level) in the same directory as subdir (whose repository
	  # is a subdirectory of first-dir).  TODO: Might want to check that
	  # files can actually get updated in this state.
	  dotest modules-147 "$testcvs -q update"

	  cat >CVSROOT/modules <<EOF
realmodule first-dir/subdir a
dirmodule first-dir/subdir
namedmodule -d nameddir first-dir/subdir
aliasmodule -a first-dir/subdir/a
aliasnested -a first-dir/subdir/ssdir
topfiles -a first-dir/file1 first-dir/file2
world -a .
statusmod -s Mungeable
# Check for ability to block infinite loops.
infinitealias -a infinitealias
# Prior to 1.11.12 & 1.12.6, the infinite alias loop check didn't strip
# slashes or work if a module called a module which then called itself
# (A -> A was blocked, but not A -> B -> A or deeper).
infinitealias2 -a infinitealias2/
infinitealias3 -a infinitealias4/
infinitealias4 -a aliasmodule infinitealias5
infinitealias5 -a infinitealias3/
# Options must come before arguments.  It is possible this should
# be relaxed at some point (though the result would be bizarre for
# -a); for now test the current behavior.
bogusalias first-dir/subdir/a -a
EOF
	  dotest modules-148 "$testcvs ci -m 'add modules' CVSROOT/modules" \
"$CVSROOT_DIRNAME/CVSROOT/modules,v  <--  CVSROOT/modules
new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
$SPROG commit: Rebuilding administrative file database"

	  cd ..
	  # The "statusmod" module contains an error; trying to use it
	  # will produce "modules file missing directory" I think.
	  # However, that shouldn't affect the ability of "cvs co -c" or
	  # "cvs co -s" to do something reasonable with it.
	  dotest modules-148a0 "$testcvs co -c" \
'aliasmodule  -a first-dir/subdir/a
aliasnested  -a first-dir/subdir/ssdir
bogusalias   first-dir/subdir/a -a
dirmodule    first-dir/subdir
infinitealias -a infinitealias
infinitealias2 -a infinitealias2/
infinitealias3 -a infinitealias4/
infinitealias4 -a aliasmodule infinitealias5
infinitealias5 -a infinitealias3/
namedmodule  -d nameddir first-dir/subdir
realmodule   first-dir/subdir a
statusmod    -s Mungeable
topfiles     -a first-dir/file1 first-dir/file2
world        -a \.'
	  # There is code in modules.c:save_d which explicitly skips
	  # modules defined with -a, which is why aliasmodule is not
	  # listed.
	  dotest modules-148a1 "${testcvs} co -s" \
'statusmod    Mungeable  
bogusalias   NONE        first-dir/subdir/a -a
dirmodule    NONE        first-dir/subdir
namedmodule  NONE        first-dir/subdir
realmodule   NONE        first-dir/subdir a'

	  # Check that infinite loops are avoided
	  dotest modules-148a1.1 "${testcvs} co infinitealias" \
"$CPROG checkout: module \`infinitealias' in modules file contains infinite loop" \
"$SPROG server: module \`infinitealias' in modules file contains infinite loop
$SPROG checkout: module \`infinitealias' in modules file contains infinite loop"
	  # Prior to 1.11.12 & 1.12.6, the inifinte alias loop check did not
	  # strip slashes.
	  dotest modules-148a1.2 "${testcvs} co infinitealias2" \
"$CPROG checkout: module \`infinitealias2' in modules file contains infinite loop" \
"$SPROG server: module \`infinitealias2' in modules file contains infinite loop
$SPROG checkout: module \`infinitealias2' in modules file contains infinite loop"
	  # Prior to 1.11.12 & 1.12.6, the inifinte alias loop check did not
	  # notice when A -> B -> A, it only noticed A -> A.
	  dotest modules-148a1.3 "${testcvs} co infinitealias3/" \
"$CPROG checkout: module \`infinitealias3' in modules file contains infinite loop" \
"$SPROG server: module \`infinitealias3' in modules file contains infinite loop
$SPROG checkout: module \`infinitealias3' in modules file contains infinite loop"

	  # Test that real modules check out to realmodule/a, not subdir/a.
	  dotest modules-149a1 "${testcvs} co realmodule" "U realmodule/a"
	  dotest modules-149a2 "test -d realmodule && test -f realmodule/a" ""
	  dotest_fail modules-149a3 "test -f realmodule/b" ""
	  dotest modules-149a4 "${testcvs} -q co realmodule" ""
	  dotest modules-149a5 "echo yes | ${testcvs} release -d realmodule" \
"You have \[0\] altered files in this repository\.
Are you sure you want to release (and delete) directory .realmodule.: "

	  dotest_fail modules-149b1 "${testcvs} co realmodule/a" \
"${SPROG}"' checkout: module `realmodule/a'\'' is a request for a file in a module which is not a directory' \
"${SPROG}"' server: module `realmodule/a'\'' is a request for a file in a module which is not a directory
'"${CPROG}"' \[checkout aborted\]: cannot expand modules'

	  # Now test the ability to check out a single file from a directory
	  dotest modules-150c "${testcvs} co dirmodule/a" "U dirmodule/a"
	  dotest modules-150d "test -d dirmodule && test -f dirmodule/a" ""
	  dotest_fail modules-150e "test -f dirmodule/b" ""
	  dotest modules-150f "echo yes | ${testcvs} release -d dirmodule" \
"You have \[0\] altered files in this repository\.
Are you sure you want to release (and delete) directory .dirmodule.: "
	  # Now test the ability to correctly reject a non-existent filename.
	  # For maximum studliness we would check that an error message is
	  # being output.
	  # We accept a zero exit status because it is what CVS does
	  # (Dec 95).  Probably the exit status should be nonzero,
	  # however.
	  dotest modules-150g1 "${testcvs} co dirmodule/nonexist" \
"${SPROG} checkout: warning: new-born \`dirmodule/nonexist' has disappeared"
	  # We tolerate the creation of the dirmodule directory, since that
	  # is what CVS does, not because we view that as preferable to not
	  # creating it.
	  dotest_fail modules-150g2 "test -f dirmodule/a || test -f dirmodule/b" ""
	  rm -r dirmodule

	  # Now test that a module using -d checks out to the specified
	  # directory.
	  dotest modules-150h1 "${testcvs} -q co namedmodule" \
'U nameddir/a
U nameddir/b'
	  dotest modules-150h2 "test -f nameddir/a && test -f nameddir/b" ""
	  echo add line >>nameddir/a
	  dotest modules-150h3 "${testcvs} -q co namedmodule" 'M nameddir/a'
	  rm nameddir/a
	  dotest modules-150h4 "${testcvs} -q co namedmodule" 'U nameddir/a'
	  dotest modules-150h99 "echo yes | ${testcvs} release -d nameddir" \
"You have \[0\] altered files in this repository\.
Are you sure you want to release (and delete) directory .nameddir.: "

	  # Now test that alias modules check out to subdir/a, not
	  # aliasmodule/a.
	  dotest modules-151 "${testcvs} co aliasmodule" ""
	  dotest_fail modules-152 "test -d aliasmodule" ""
	  echo abc >>first-dir/subdir/a
	  dotest modules-153 "${testcvs} -q co aliasmodule" "M first-dir/subdir/a"

	  cd ..
	  rm -r 1

	  mkdir 2
	  cd 2
	  dotest modules-155a0 "${testcvs} co aliasnested" \
"${SPROG} checkout: Updating first-dir/subdir/ssdir"
	  dotest modules-155a1 "test -d first-dir" ''
	  dotest modules-155a2 "test -d first-dir/subdir" ''
	  dotest modules-155a3 "test -d first-dir/subdir/ssdir" ''
	  # Test that nothing extraneous got created.
	  dotest modules-155a4 "ls" "first-dir" \
"CVS
first-dir"
	  cd ..
	  rm -r 2

	  # Test checking out everything.
	  mkdir 1
	  cd 1
	  dotest modules-155b "${testcvs} -q co world" \
"U CVSROOT/${DOTSTAR}
U first-dir/subdir/a
U first-dir/subdir/b"
	  cd ..
	  rm -r 1

	  # Test checking out a module which lists at least two
	  # specific files twice.  At one time, this failed over
	  # remote CVS.
	  mkdir 1
	  cd 1
	  dotest modules-155c1 "${testcvs} -q co first-dir" \
"U first-dir/subdir/a
U first-dir/subdir/b"

	  cd first-dir
	  echo 'first revision' > file1
	  echo 'first revision' > file2
	  dotest modules-155c2 "${testcvs} add file1 file2" \
"${SPROG}"' add: scheduling file `file1'\'' for addition
'"${SPROG}"' add: scheduling file `file2'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'
	  dotest modules-155c3 "${testcvs} -q ci -m add-it" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
initial revision: 1\.1"

	  cd ..
	  rm -r first-dir
	  dotest modules-155c4 "${testcvs} -q co topfiles" \
"U first-dir/file1
U first-dir/file2"
	  dotest modules-155c5 "${testcvs} -q co topfiles" ""

	  # Make sure the right thing happens if we remove a file.
	  cd first-dir
	  dotest modules-155c6 "${testcvs} -q rm -f file1" \
"${SPROG} remove: use .${SPROG} commit. to remove this file permanently"
	  dotest modules-155c7 "${testcvs} -q ci -m remove-it" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: delete; previous revision: 1\.1"
	  cd ..
	  rm -r first-dir
	  dotest modules-155c8 "${testcvs} -q co topfiles" \
"${SPROG} checkout: warning: \`first-dir/file1' is not (any longer) pertinent
U first-dir/file2"

	  dokeep
	  cd ..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	modules2)
	  # More tests of modules, in particular the & feature.
	  mkdir 1; cd 1
	  dotest modules2-setup-1 "${testcvs} -q co -l ." ''
	  mkdir first-dir second-dir third-dir
	  dotest modules2-setup-2 \
"${testcvs} add first-dir second-dir third-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository
Directory ${CVSROOT_DIRNAME}/second-dir added to the repository
Directory ${CVSROOT_DIRNAME}/third-dir added to the repository"
	  cd third-dir
	  touch file3
	  dotest modules2-setup-3 "${testcvs} add file3" \
"${SPROG} add: scheduling file .file3. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest modules2-setup-4 "${testcvs} -q ci -m add file3" \
"$CVSROOT_DIRNAME/third-dir/file3,v  <--  file3
initial revision: 1\.1"
	  cd ../..
	  rm -r 1

	  mkdir 1
	  cd 1

	  dotest modules2-1 "${testcvs} -q co CVSROOT/modules" \
'U CVSROOT/modules'
	  cd CVSROOT
	  cat >> modules << EOF
ampermodule &first-dir &second-dir
combmodule third-dir file3 &first-dir
ampdirmod -d newdir &first-dir &second-dir
badmod -d newdir
messymod first-dir &messymodchild
messymodchild -d sdir/child second-dir
EOF
	  # Depending on whether the user also ran the modules test
	  # we will be checking in revision 1.2 or 1.3.
	  dotest modules2-2 "${testcvs} -q ci -m add-modules" \
"$CVSROOT_DIRNAME/CVSROOT/modules,v  <--  modules
new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
$SPROG commit: Rebuilding administrative file database"

	  cd ..

	  dotest modules2-3 "${testcvs} -q co ampermodule" ''
	  dotest modules2-4 "test -d ampermodule/first-dir" ''
	  dotest modules2-5 "test -d ampermodule/second-dir" ''

	  # Test ability of cvs release to handle multiple arguments
	  # See comment at "release" for list of other cvs release tests.
	  cd ampermodule
	  if ${testcvs} release -d first-dir second-dir <<EOF >>${LOGFILE}
yes
yes
EOF
	  then
	    pass modules2-6
	  else
	    fail modules2-6
	  fi
	  dotest_fail modules2-7 "test -d first-dir" ''
	  dotest_fail modules2-8 "test -d second-dir" ''

	  cd ..

	  # There used to be a nasty-hack that made CVS skip creation of the
	  # module dir (in this case ampermodule) when -n was specified
	  dotest modules2-ampermod-1 "${testcvs} -q co -n ampermodule" ''
	  dotest modules2-ampermod-2 "test -d ampermodule/first-dir" ''
	  dotest modules2-ampermod-3 "test -d ampermodule/second-dir" ''

	  # Test release of a module
	  if echo yes |${testcvs} release -d ampermodule >>${LOGFILE}; then
	    pass modules2-ampermod-release-1
	  else
	    fail modules2-ampermod-release-1
	  fi
	  dotest_fail modules2-ampermod-release-2 "test -d ampermodule" ''

	  # and the '-n' test again, but in conjunction with '-d'
	  dotest modules2-ampermod-4 "${testcvs} -q co -n -d newname ampermodule" ''
	  dotest modules2-ampermod-5 "test -d newname/first-dir" ''
	  dotest modules2-ampermod-6 "test -d newname/second-dir" ''
	  rm -rf newname

	  # Now we create another directory named first-dir and make
	  # sure that CVS doesn't get them mixed up.
	  mkdir first-dir
	  # Note that this message should say "Updating ampermodule/first-dir"
	  # I suspect.  This is a long-standing behavior/bug....
	  dotest modules2-9 "${testcvs} co ampermodule" \
"${SPROG} checkout: Updating first-dir
${SPROG} checkout: Updating second-dir"
	  touch ampermodule/first-dir/amper1
	  cd ampermodule
	  dotest modules2-10 "${testcvs} add first-dir/amper1" \
"${SPROG} add: scheduling file .first-dir/amper1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  cd ..

	  # As with the "Updating xxx" message, the "U first-dir/amper1"
	  # message (instead of "U ampermodule/first-dir/amper1") is
	  # rather fishy.
	  dotest modules2-12 "${testcvs} co ampermodule" \
"${SPROG} checkout: Updating first-dir
A first-dir/amper1
${SPROG} checkout: Updating second-dir"

	  if $remote; then
	    dotest modules2-13r "$testcvs -q ci -m add-it ampermodule" \
"$CVSROOT_DIRNAME/first-dir/amper1,v  <--  ampermodule/first-dir/amper1
initial revision: 1\.1"
	  else
	    # Trying this as above led to a "protocol error" message.
	    # Work around this bug.
	    cd ampermodule
	    dotest modules2-13 "$testcvs -q ci -m add-it" \
"$CVSROOT_DIRNAME/first-dir/amper1,v  <--  first-dir/amper1
initial revision: 1\.1"
	    cd ..
	  fi
	  cd ..
	  rm -r 1

	  # Now test the "combmodule" module (combining regular modules
	  # and ampersand modules in the same module definition).
	  mkdir 1; cd 1
	  dotest modules2-14 "${testcvs} co combmodule" \
"U combmodule/file3
${SPROG} checkout: Updating first-dir
U first-dir/amper1"
	  dotest modules2-15 "test -f combmodule/file3" ""
	  dotest modules2-16 "test -f combmodule/first-dir/amper1" ""
	  cd combmodule
	  rm -r first-dir
	  # At least for now there is no way to tell CVS that
	  # some files/subdirectories come from one repository directory,
	  # and others from another.
	  # This seems like a pretty sensible behavior to me, in the
	  # sense that first-dir doesn't "really" exist within
	  # third-dir, so CVS just acts as if there is nothing there
	  # to do.
	  dotest modules2-17 "${testcvs} update -d" \
"${SPROG} update: Updating \."

	  cd ..
	  dotest modules2-18 "${testcvs} -q co combmodule" \
"U first-dir/amper1"
	  dotest modules2-19 "test -f combmodule/first-dir/amper1" ""
	  cd ..
	  rm -r 1

	  # Now test the "ampdirmod" and "badmod" modules to be sure that
	  # options work with ampersand modules but don't prevent the
	  # "missing directory" error message.
	  mkdir 1; cd 1
	  dotest modules2-20 "${testcvs} co ampdirmod" \
"${SPROG} checkout: Updating first-dir
U first-dir/amper1
${SPROG} checkout: Updating second-dir"
	  dotest modules2-21 "test -f newdir/first-dir/amper1" ""
	  dotest modules2-22 "test -d newdir/second-dir" ""
	  dotest_fail modules2-23 "${testcvs} co badmod" \
"${SPROG} checkout: modules file missing directory for module badmod" \
"${SPROG} server: modules file missing directory for module badmod
${CPROG} \[checkout aborted\]: cannot expand modules"
	  cd ..
	  rm -r 1

	  # Confirm that a rename with added depth nested in an ampersand
	  # module works.
	  mkdir 1; cd 1
	  dotest modules2-nestedrename-1 "${testcvs} -q co messymod" \
"U messymod/amper1"
	  dotest modules2-nestedrename-2 "test -d messymod/sdir" ''
	  dotest modules2-nestedrename-3 "test -d messymod/sdir/CVS" ''
	  dotest modules2-nestedrename-4 "test -d messymod/sdir/child" ''
	  dotest modules2-nestedrename-5 "test -d messymod/sdir/child/CVS" ''
	  cd ..; rm -r 1

	  # FIXME:  client/server has a bug.  It should be working like a local
	  # repository in this case, but fails to check out the second module
	  # in the list when a branch is specified.
	  mkdir 1; cd 1
	  dotest modules2-ampertag-setup-1 \
"${testcvs} -Q rtag tag first-dir second-dir third-dir" \
''
	  dotest modules2-ampertag-1 "${testcvs} -q co -rtag ampermodule" \
"U first-dir/amper1"
	  if $remote; then
	    dotest_fail modules2-ampertag-2 "test -d ampermodule/second-dir" ''
	    dotest_fail modules2-ampertag-3 "test -d ampermodule/second-dir/CVS" ''
	  else
	    dotest modules2-ampertag-2 "test -d ampermodule/second-dir" ''
	    dotest modules2-ampertag-3 "test -d ampermodule/second-dir/CVS" ''
	  fi
	  cd ..; rm -r 1

	  # Test for tag files when an ampermod is renamed with more path
	  # elements than it started with.
	  #
	  # FIXME: This is currently broken in the remote case, possibly only
	  # because the messymodchild isn't being checked out at all.
	  mkdir 1; cd 1
#	  dotest modules2-tagfiles-setup-1 \
#"${testcvs} -Q rtag -b branch first-dir second-dir" \
#''
	  dotest modules2-tagfiles-1 "${testcvs} -q co -rtag messymod" \
"U messymod/amper1"
	  if $remote; then
	    dotest_fail modules2-tagfiles-2r "test -d messymod/sdir" ''
	  else
	    dotest modules2-tagfiles-2 "cat messymod/sdir/CVS/Tag" 'Ttag'
	  fi
	  cd ..; rm -r 1

	  # Test that CVS gives an error if one combines -a with
	  # other options.
	  # Probably would be better to break this out into a separate
	  # test.  Although it is short, it shares no files/state with
	  # the rest of the modules2 tests.
	  mkdir 1; cd 1
	  dotest modules2-a0.5 "${testcvs} -q co CVSROOT/modules" \
'U CVSROOT/modules'
	  cd CVSROOT
	  echo 'aliasopt -a -d onedir first-dir' >modules
	  dotest modules2-a0 "${testcvs} -q ci -m add-modules" \
"$CVSROOT_DIRNAME/CVSROOT/modules,v  <--  modules
new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
$SPROG commit: Rebuilding administrative file database"
	  cd ..
	  dotest_fail modules2-a1 "${testcvs} -q co aliasopt" \
"${SPROG} checkout: -a cannot be specified in the modules file along with other options" \
"${SPROG} server: -a cannot be specified in the modules file along with other options
${CPROG} \[checkout aborted\]: cannot expand modules"
	  cd ..;  rm -r 1

	  # Clean up.
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
			     $CVSROOT_DIRNAME/second-dir \
			     $CVSROOT_DIRNAME/third-dir
	  ;;



	modules3)
	  # More tests of modules, in particular what happens if several
	  # modules point to the same file.

	  # First just set up a directory first-dir and a file file1 in it.
	  mkdir 1; cd 1

	  dotest modules3-0 "$testcvs -q co -l ."
	  mkdir first-dir
	  dotest modules3-1 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"

	  cd first-dir
	  echo file1 >file1
	  dotest modules3-2 "${testcvs} add file1" \
"${SPROG} add: scheduling file \`file1' for addition
${SPROG} add: use \`${SPROG} commit' to add this file permanently"
	  dotest modules3-3 "${testcvs} -q ci -m add-it" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1"
	  cd ..

	  dotest modules3-4 "${testcvs} -q update -d CVSROOT" \
"U CVSROOT${DOTSTAR}"
	  cd CVSROOT
	  cat >modules <<EOF
mod1 -a first-dir/file1
bigmod -a mod1 first-dir/file1
namednest -d src/sub/dir first-dir
nestdeeper -d src/sub1/sub2/sub3/dir first-dir
nestshallow -d src/dir second-dir/suba/subb
path/in/modules &mod1
another/path/test -d another/path/test first-dir
EOF
	  dotest modules3-5 "${testcvs} -q ci -m add-modules" \
"$CVSROOT_DIRNAME/CVSROOT/modules,v  <--  modules
new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
$SPROG commit: Rebuilding administrative file database"
	  cd ..

	  dotest modules3-6 "${testcvs} -q co bigmod" ''
	  rm -r first-dir
	  dotest modules3-7 "${testcvs} -q co bigmod" 'U first-dir/file1'
	  cd ..
	  rm -r 1

	  mkdir 1; cd 1
	  mkdir suba
	  mkdir suba/subb
	  # This fails to work remote (it doesn't notice the directories,
	  # I suppose because they contain no files).  Bummer, especially
	  # considering this is a documented technique and everything.
	  dotest modules3-7a \
"${testcvs} import -m add-dirs second-dir tag1 tag2" \
"${SPROG} import: Importing ${CVSROOT_DIRNAME}/second-dir/suba
${SPROG} import: Importing ${CVSROOT_DIRNAME}/second-dir/suba/subb

No conflicts created by this import" "
No conflicts created by this import"
	  cd ..; rm -r 1
	  mkdir 1; cd 1
	  dotest modules3-7b "${testcvs} co second-dir" \
"${SPROG} checkout: Updating second-dir
${SPROG} checkout: Updating second-dir/suba
${SPROG} checkout: Updating second-dir/suba/subb" \
"${SPROG} checkout: Updating second-dir"

	  if $remote; then
	    cd second-dir
	    mkdir suba
	    dotest modules3-7-workaround1 "${testcvs} add suba" \
"Directory ${CVSROOT_DIRNAME}/second-dir/suba added to the repository"
	    cd suba
	    mkdir subb
	    dotest modules3-7-workaround2 "${testcvs} add subb" \
"Directory ${CVSROOT_DIRNAME}/second-dir/suba/subb added to the repository"
	    cd ../..
	  fi

	  cd second-dir/suba/subb
	  touch fileb
	  dotest modules3-7c "${testcvs} add fileb" \
"${SPROG} add: scheduling file .fileb. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest modules3-7d "${testcvs} -q ci -m add-it" \
"$CVSROOT_DIRNAME/second-dir/suba/subb/fileb,v  <--  fileb
initial revision: 1\.1"
	  cd ../../..
	  cd ..; rm -r 1

	  mkdir 1
	  cd 1
	  dotest modules3-8 "${testcvs} -q co namednest" \
'U src/sub/dir/file1'
	  dotest modules3-9 "test -f src/sub/dir/file1" ''
	  cd ..
	  rm -r 1

	  # Try the same thing, but with the directories nested even
	  # deeper (deeply enough so they are nested more deeply than
	  # the number of directories from / to ${TESTDIR}).
	  mkdir 1
	  cd 1
	  dotest modules3-10 "${testcvs} -q co nestdeeper" \
'U src/sub1/sub2/sub3/dir/file1'
	  dotest modules3-11 "test -f src/sub1/sub2/sub3/dir/file1" ''

	  # While we are doing things like twisted uses of '/' (e.g.
	  # modules3-12), try this one.
	  if $remote; then
	    dotest_fail modules3-11b \
"${testcvs} -q update ${TESTDIR}/1/src/sub1/sub2/sub3/dir/file1" \
"absolute pathnames invalid for server (specified .${TESTDIR}/1/src/sub1/sub2/sub3/dir.)"
	  fi # end of remote-only tests

	  cd ..
	  rm -r 1

	  # This one is almost too twisted for words.  The pathname output
	  # in the message from "co" doesn't include the "path/in/modules",
	  # but those directories do get created (with no CVSADM except
	  # in "modules" which has a CVSNULLREPOS).
	  # I'm not sure anyone is relying on this nonsense or whether we
	  # need to keep doing it, but it is what CVS currently does...
	  # Skip it for remote; the remote code has the good sense to
	  # not deal with it (on the minus side it gives
	  # "internal error: repository string too short." (CVS 1.9) or
	  # "warning: server is not creating directories one at a time" (now)
	  # instead of a real error).
	  # I'm tempted to just make it a fatal error to have '/' in a
	  # module name.  But see comments at modules3-16.
	  if $remote; then :; else
	    mkdir 1; cd 1
	    dotest modules3-12 "${testcvs} -q co path/in/modules" \
"U first-dir/file1"
	    dotest modules3-13 "test -f path/in/modules/first-dir/file1" ''
	    cd ..; rm -r 1
	  fi # end of tests skipped for remote

	  # Now here is where it used to get seriously bogus.
	  mkdir 1; cd 1
	  dotest modules3-14 \
"${testcvs} -q rtag tag1 path/in/modules" ''
	  # CVS used to create this even though rtag should *never* affect
	  # the directory current when it is called!
	  dotest_fail modules3-15 "test -d path/in/modules" ''
	  # Just for trivia's sake, rdiff was not similarly vulnerable
	  # because it passed 0 for run_module_prog to do_module.
	  cd ..; rm -r 1

	  # Some people seem to want this to work.  I still suspect there
	  # are dark corners in slashes in module names.  This probably wants
	  # more thought before we start hacking on CVS (one way or the other)
	  # or documenting this.
	  mkdir 2; cd 2
	  dotest modules3-16 "${testcvs} -q co another/path/test" \
"U another/path/test/file1"
	  dotest modules3-17 "cat another/path/test/file1" 'file1'

	  dokeep
	  cd ..; rm -r 2
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
			     $CVSROOT_DIRNAME/second-dir
	  ;;



	modules4)
	  # Some tests using the modules file with aliases that
	  # exclude particular directories.

	  mkdir 1; cd 1

	  dotest modules4-1 "${testcvs} -q co -l ." ''
	  mkdir first-dir
	  dotest modules4-2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"

	  cd first-dir
          mkdir subdir subdir_long
          dotest modules4-3 "${testcvs} add subdir subdir_long" \
"Directory ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository
Directory ${CVSROOT_DIRNAME}/first-dir/subdir_long added to the repository"

	  echo file1 > file1
	  dotest modules4-4 "${testcvs} add file1" \
"${SPROG}"' add: scheduling file `file1'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'

	  echo file2 > subdir/file2
	  dotest modules4-5 "${testcvs} add subdir/file2" \
"${SPROG}"' add: scheduling file `subdir/file2'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'

	  echo file3 > subdir_long/file3
	  dotest modules4-6 "${testcvs} add subdir_long/file3" \
"${SPROG}"' add: scheduling file `subdir_long/file3'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'

	  dotest modules4-7 "${testcvs} -q ci -m add-it" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/subdir/file2,v  <--  subdir/file2
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/subdir_long/file3,v  <--  subdir_long/file3
initial revision: 1\.1"

	  cd ..

	  dotest modules4-8 "${testcvs} -q update -d CVSROOT" \
"U CVSROOT${DOTSTAR}"
	  cd CVSROOT
	  cat >modules <<EOF
all -a first-dir
some -a !first-dir/subdir first-dir
other -a !first-dir/subdir !first-dir/subdir_long first-dir
somewhat -a first-dir !first-dir/subdir
EOF
	  dotest modules4-9 "${testcvs} -q ci -m add-modules" \
"$CVSROOT_DIRNAME/CVSROOT/modules,v  <--  modules
new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
$SPROG commit: Rebuilding administrative file database"
	  cd ..

	  cd ..
	  mkdir 2; cd 2

	  dotest modules4-10 "${testcvs} -q co all" \
"U first-dir/file1
U first-dir/subdir/file2
U first-dir/subdir_long/file3"
	  rm -r first-dir

	  dotest modules4-11 "${testcvs} -q co some" \
"U first-dir/file1
U first-dir/subdir_long/file3"
	  dotest_fail modules4-12 "test -d first-dir/subdir" ''
	  dotest modules4-13 "test -d first-dir/subdir_long" ''
	  rm -r first-dir

	  if $remote; then
	    # But remote seems to do it the other way.
	    dotest modules4-14r-1 "${testcvs} -q co somewhat" \
"U first-dir/file1
U first-dir/subdir_long/file3"
	    dotest_fail modules4-14r-2 "test -d first-dir/subdir" ''
	    dotest modules4-14r-3 "test -d first-dir/subdir_long" ''
	  else
	    # This is strange behavior, in that the order of the
	    # "!first-dir/subdir" and "first-dir" matter, and it isn't
	    # clear that they should.  I suspect it is long-standing
	    # strange behavior but I haven't verified that.
	    dotest modules4-14-1 "${testcvs} -q co somewhat" \
"U first-dir/file1
U first-dir/subdir/file2
U first-dir/subdir_long/file3"
	    dotest modules4-14-2 "test -d first-dir/subdir" ''
	    dotest modules4-14-3 "test -d first-dir/subdir_long" ''
	  fi
	  rm -r first-dir

	  dotest modules4-15 "${testcvs} -q co other" \
"U first-dir/file1"
	  dotest_fail modules4-16 "test -d first-dir/subdir" ''
	  dotest_fail modules4-17 "test -d first-dir/subdir_long" ''
	  rm -r first-dir

	  cd ..
	  rm -r 2

	  dotest modules4-18 "${testcvs} rtag tag some" \
"${SPROG} rtag: Tagging first-dir
${SPROG} rtag: Ignoring first-dir/subdir
${SPROG} rtag: Tagging first-dir/subdir_long"

	  cd 1/first-dir/subdir
	  dotest modules4-19 "${testcvs} log file2" "
RCS file: ${CVSROOT_DIRNAME}/first-dir/subdir/file2,v
Working file: file2
head: 1\.1
branch:
locks: strict
access list:
symbolic names:
keyword substitution: kv
total revisions: 1;	selected revisions: 1
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
add-it
============================================================================="

	  dokeep
	  cd ../../..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	modules5)
	  # Test module programs

	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  mkdir 1
	  cd 1
	  dotest modules5-1 "$testcvs -q co first-dir"
	  cd first-dir
	  mkdir subdir
	  dotest modules5-2 "${testcvs} add subdir" \
"Directory ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository"
	  cd subdir
	  mkdir ssdir
	  dotest modules5-3 "${testcvs} add ssdir" \
"Directory ${CVSROOT_DIRNAME}/first-dir/subdir/ssdir added to the repository"
	  touch a b
	  dotest modules5-4 "${testcvs} add a b" \
"${SPROG} add: scheduling file .a. for addition
${SPROG} add: scheduling file .b. for addition
${SPROG} add: use .${SPROG} commit. to add these files permanently"

	  dotest modules5-5 "${testcvs} ci -m added" \
"${CPROG} commit: Examining .
${CPROG} commit: Examining ssdir
${CVSROOT_DIRNAME}/first-dir/subdir/a,v  <--  a
initial revision: 1\.1
${CVSROOT_DIRNAME}/first-dir/subdir/b,v  <--  b
initial revision: 1\.1"

	  cd ..
	  dotest modules5-6 "${testcvs} -q co CVSROOT" \
"U CVSROOT/checkoutlist
U CVSROOT/commitinfo
U CVSROOT/config
U CVSROOT/cvswrappers
U CVSROOT/loginfo
U CVSROOT/modules
U CVSROOT/notify
U CVSROOT/postadmin
U CVSROOT/postproxy
U CVSROOT/posttag
U CVSROOT/postwatch
U CVSROOT/preproxy
U CVSROOT/rcsinfo
U CVSROOT/taginfo
U CVSROOT/verifymsg"

	  # FIXCVS: The sleep in the following script helps avoid out of
	  # order messages, but we really need to figure out how to fix
	  # cvs to prevent them in the first place.
	  for i in checkout export tag; do
	    cat >> ${CVSROOT_DIRNAME}/$i.sh <<EOF
#! $TESTSHELL
sleep 1
echo "$i script invoked in \`pwd\`"
echo "args: \$@"
EOF
	    # Cygwin doesn't set premissions correctly over the Samba share.
	    if test -n "$remotehost"; then
	      $CVS_RSH $remotehost "chmod +x ${CVSROOT_DIRNAME}/$i.sh"
	    else
	      chmod +x ${CVSROOT_DIRNAME}/$i.sh
	    fi
	  done

	  OPTS="-o${CVSROOT_DIRNAME}/checkout.sh -e ${CVSROOT_DIRNAME}/export.sh -t${CVSROOT_DIRNAME}/tag.sh"
	  cat >CVSROOT/modules <<EOF
realmodule ${OPTS} first-dir/subdir a
dirmodule ${OPTS} first-dir/subdir
namedmodule -d nameddir ${OPTS} first-dir/subdir
EOF

	  dotest modules5-7 "$testcvs -Q ci -m 'add modules' CVSROOT/modules"

	  cd ..
	  rm -rf first-dir

	  # Test that real modules check out to realmodule/a, not subdir/a.
	  if $remote; then
	    # FIXCVS?
	    # Mac OSX 10.3 (Darwin ppc-osx1 5.5) fails here when $TMPDIR
	    # contains a symlink (it does not fail the local modules5-8).
	    # Since no other platforms are exhibiting the same problem, I
	    # suspect an issue with OSX and fork() or the like dereferencing
	    # the symlink, but it is possible it is something that could be
	    # fixed or worked around in CVS.
	    dotest modules5-8r "$testcvs co realmodule" \
"U realmodule/a
${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .realmodule..
checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: realmodule"
	  else
	    dotest modules5-8 "${testcvs} co realmodule" \
"U realmodule/a
${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .realmodule..
checkout script invoked in ${TESTDIR}/1
args: realmodule"
	  fi
	  dotest modules5-9 "test -d realmodule && test -f realmodule/a" ""
	  dotest_fail modules5-10 "test -f realmodule/b" ""
	  if $remote; then
	    dotest modules5-11 "${testcvs} -q co realmodule" \
"checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: realmodule"
	    dotest modules5-12 "${testcvs} -q update" ''
	    echo "change" >>realmodule/a
	    dotest modules5-13 "${testcvs} -q ci -m." \
"$CVSROOT_DIRNAME/first-dir/subdir/a,v  <--  realmodule/a
new revision: 1\.2; previous revision: 1\.1"
	  else
	    dotest modules5-11 "${testcvs} -q co realmodule" \
"checkout script invoked in ${TESTDIR}/1
args: realmodule"
	    dotest modules5-12 "${testcvs} -q update" ''
	    echo "change" >>realmodule/a
	    dotest modules5-13 "${testcvs} -q ci -m." \
"$CVSROOT_DIRNAME/first-dir/subdir/a,v  <--  realmodule/a
new revision: 1\.2; previous revision: 1\.1"
	  fi
	  dotest modules5-14 "echo yes | ${testcvs} release -d realmodule" \
"You have \[0\] altered files in this repository\.
Are you sure you want to release (and delete) directory .realmodule.: "
	  dotest modules5-15 "${testcvs} -q rtag -Dnow MYTAG realmodule" \
"tag script invoked in ${TESTDIR}/1
args: realmodule MYTAG" \
"tag script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: realmodule MYTAG"
	  if $remote; then
	    dotest modules5-16 "${testcvs} -q export -r MYTAG realmodule" \
"U realmodule/a
export script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: realmodule"
	  else
	    dotest modules5-16 "${testcvs} -q export -r MYTAG realmodule" \
"U realmodule/a
export script invoked in ${TESTDIR}/1
args: realmodule"
	  fi
	  rm -r realmodule

	  dotest_fail modules5-17 "${testcvs} co realmodule/a" \
"${SPROG}"' checkout: module `realmodule/a'\'' is a request for a file in a module which is not a directory' \
"${SPROG}"' server: module `realmodule/a'\'' is a request for a file in a module which is not a directory
'"${CPROG}"' \[checkout aborted\]: cannot expand modules'

	  # Now test the ability to check out a single file from a directory
	  if $remote; then
	    dotest modules5-18 "${testcvs} co dirmodule/a" \
"U dirmodule/a
${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .dirmodule..
checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: dirmodule"
	  else
	    dotest modules5-18 "${testcvs} co dirmodule/a" \
"U dirmodule/a
${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .dirmodule..
checkout script invoked in ${TESTDIR}/1
args: dirmodule"
	  fi
	  dotest modules5-19 "test -d dirmodule && test -f dirmodule/a" ""
	  dotest_fail modules5-20 "test -f dirmodule/b" ""
	  dotest modules5-21 "echo yes | ${testcvs} release -d dirmodule" \
"You have \[0\] altered files in this repository\.
Are you sure you want to release (and delete) directory .dirmodule.: "

	  # Now test the ability to correctly reject a non-existent filename.
	  # For maximum studliness we would check that an error message is
	  # being output.
	  # We accept a zero exit status because it is what CVS does
	  # (Dec 95).  Probably the exit status should be nonzero,
	  # however.
	  if $remote; then
	    dotest modules5-22 "${testcvs} co dirmodule/nonexist" \
"${SPROG} checkout: warning: new-born \`dirmodule/nonexist' has disappeared
${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .dirmodule..
checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: dirmodule"
	  else
	    dotest modules5-22 "${testcvs} co dirmodule/nonexist" \
"${SPROG} checkout: warning: new-born \`dirmodule/nonexist' has disappeared
${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .dirmodule..
checkout script invoked in ${TESTDIR}/1
args: dirmodule"
	  fi
	  # We tolerate the creation of the dirmodule directory, since that
	  # is what CVS does, not because we view that as preferable to not
	  # creating it.
	  dotest_fail modules5-23 "test -f dirmodule/a || test -f dirmodule/b" ""
	  rm -r dirmodule

	  # Now test that a module using -d checks out to the specified
	  # directory.
	  if $remote; then
	    dotest modules5-24 "${testcvs} -q co namedmodule" \
"U nameddir/a
U nameddir/b
checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: nameddir"
	  else
	    dotest modules5-24 "${testcvs} -q co namedmodule" \
"U nameddir/a
U nameddir/b
checkout script invoked in ${TESTDIR}/1
args: nameddir"
	  fi
	  dotest modules5-25 "test -f nameddir/a && test -f nameddir/b" ""
	  echo add line >>nameddir/a
	  # This seems suspicious: when we checkout an existing directory,
	  # the checkout script gets executed in addition to the update
	  # script.  Is that by design or accident?
	  if $remote; then
	    dotest modules5-26 "${testcvs} -q co namedmodule" \
"M nameddir/a
checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: nameddir"
	  else
	    dotest modules5-26 "${testcvs} -q co namedmodule" \
"M nameddir/a
checkout script invoked in ${TESTDIR}/1
args: nameddir"
	  fi
	  rm nameddir/a

	  if $remote; then
	    dotest modules5-27 "${testcvs} -q co namedmodule" \
"U nameddir/a
checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: nameddir"
	  else
	    dotest modules5-27 "${testcvs} -q co namedmodule" \
"U nameddir/a
checkout script invoked in ${TESTDIR}/1
args: nameddir"
	  fi
	  dotest modules5-28 "echo yes | ${testcvs} release -d nameddir" \
"You have \[0\] altered files in this repository\.
Are you sure you want to release (and delete) directory .nameddir.: "

	  # Now try the same tests with -d on command line
	  # FIXCVS?  The manual says the modules programs get the module name,
	  # but they really get the directory name.
	  if $remote; then
	    dotest modules5-29 "${testcvs} co -d mydir realmodule" \
"U mydir/a
${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir..
checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: mydir"
	  else
	    dotest modules5-29 "${testcvs} co -d mydir realmodule" \
"U mydir/a
${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir..
checkout script invoked in ${TESTDIR}/1
args: mydir"
	  fi
	  dotest modules5-30 "test -d mydir && test -f mydir/a" ""
	  dotest_fail modules5-31 "test -d realmodule || test -f mydir/b" ""
	  if $remote; then
	    dotest modules5-32 "${testcvs} -q co -d mydir realmodule" \
"checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: mydir"
	    dotest modules5-33 "${testcvs} -q update" ''
	    echo "change" >>mydir/a
	    dotest modules5-34 "${testcvs} -q ci -m." \
"$CVSROOT_DIRNAME/first-dir/subdir/a,v  <--  mydir/a
new revision: 1\.3; previous revision: 1\.2"
	  else
	    dotest modules5-32 "${testcvs} -q co -d mydir realmodule" \
"checkout script invoked in ${TESTDIR}/1
args: mydir"
	    dotest modules5-33 "${testcvs} -q update" ''
	    echo "change" >>mydir/a
	    dotest modules5-34 "${testcvs} -q ci -m." \
"$CVSROOT_DIRNAME/first-dir/subdir/a,v  <--  mydir/a
new revision: 1\.3; previous revision: 1\.2"
	  fi
	  dotest modules5-35 "echo yes | ${testcvs} release -d mydir" \
"You have \[0\] altered files in this repository\.
Are you sure you want to release (and delete) directory .mydir.: "
	  if $remote; then
	    dotest modules5-36 "${testcvs} -q rtag -Dnow MYTAG2 realmodule" \
"tag script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: realmodule MYTAG2"
	    dotest modules5-37 "${testcvs} -q export -r MYTAG2 -d mydir realmodule" \
"U mydir/a
export script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: mydir"
	  else
	    dotest modules5-36 "${testcvs} -q rtag -Dnow MYTAG2 realmodule" \
"tag script invoked in ${TESTDIR}/1
args: realmodule MYTAG2"
	    dotest modules5-37 "${testcvs} -q export -r MYTAG2 -d mydir realmodule" \
"U mydir/a
export script invoked in ${TESTDIR}/1
args: mydir"
	  fi
	  rm -r mydir

	  # Now test the ability to check out a single file from a directory
	  if $remote; then
	    dotest modules5-38 "${testcvs} co -d mydir dirmodule/a" \
"U mydir/a
${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir..
checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: mydir"
	  else
	    dotest modules5-38 "${testcvs} co -d mydir dirmodule/a" \
"U mydir/a
${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir..
checkout script invoked in ${TESTDIR}/1
args: mydir"
	  fi
	  dotest modules5-39 "test -d mydir && test -f mydir/a" ""
	  dotest_fail modules5-40 "test -d dirmodule || test -f mydir/b" ""
	  dotest modules5-41 "echo yes | ${testcvs} release -d mydir" \
"You have \[0\] altered files in this repository\.
Are you sure you want to release (and delete) directory .mydir.: "

	  # Now test the ability to correctly reject a non-existent filename.
	  # For maximum studliness we would check that an error message is
	  # being output.
	  # We accept a zero exit status because it is what CVS does
	  # (Dec 95).  Probably the exit status should be nonzero,
	  # however.
	  if $remote; then
	    dotest modules5-42 "${testcvs} co -d mydir dirmodule/nonexist" \
"${SPROG} checkout: warning: new-born \`mydir/nonexist' has disappeared
${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir..
checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: mydir"
	  else
	    dotest modules5-42 "${testcvs} co -d mydir dirmodule/nonexist" \
"${SPROG} checkout: warning: new-born \`mydir/nonexist' has disappeared
${SPROG} checkout: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .mydir..
checkout script invoked in ${TESTDIR}/1
args: mydir"
	  fi
	  # We tolerate the creation of the mydir directory, since that
	  # is what CVS does, not because we view that as preferable to not
	  # creating it.
	  dotest_fail modules5-43 "test -f mydir/a || test -f mydir/b" ""
	  rm -r mydir

	  if $remote; then
	    dotest modules5-44 "${testcvs} -q co -d mydir namedmodule" \
"U mydir/a
U mydir/b
checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: mydir"
	  else
	    dotest modules5-44 "${testcvs} -q co -d mydir namedmodule" \
"U mydir/a
U mydir/b
checkout script invoked in ${TESTDIR}/1
args: mydir"
	  fi
	  dotest modules5-45 "test -f mydir/a && test -f mydir/b" ""
	  dotest_fail modules5-46 "test -d namedir"
	  echo add line >>mydir/a
	  # This seems suspicious: when we checkout an existing directory,
	  # the checkout script gets executed in addition to the update
	  # script.  Is that by design or accident?
	  if $remote; then
	    dotest modules5-47 "${testcvs} -q co -d mydir namedmodule" \
"M mydir/a
checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: mydir"
	  else
	    dotest modules5-47 "${testcvs} -q co -d mydir namedmodule" \
"M mydir/a
checkout script invoked in ${TESTDIR}/1
args: mydir"
	  fi
	  rm mydir/a

	  if $remote; then
	    dotest modules5-48 "${testcvs} -q co -d mydir namedmodule" \
"U mydir/a
checkout script invoked in ${TMPDIR}/cvs-serv[0-9a-z]*
args: mydir"
	  else
	    dotest modules5-48 "${testcvs} -q co -d mydir namedmodule" \
"U mydir/a
checkout script invoked in ${TESTDIR}/1
args: mydir"
	  fi
	  dotest modules5-49 "echo yes | ${testcvs} release -d mydir" \
"You have \[0\] altered files in this repository\.
Are you sure you want to release (and delete) directory .mydir.: "

	  dokeep
	  cd ..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
			     $CVSROOT_DIRNAME/*.sh
	  ;;



	modules6)
	  #
	  # Test invalid module definitions
	  #
	  # See the header comment for the `modules' test for an index of
	  # the complete suite of modules tests.
	  #

	  #
	  # There was a bug in CVS through 1.11.1p1 where a bad module name
	  # would cause the previous line to be parsed as the module
	  # definition.  This test proves this doesn't happen anymore.
	  #
	  mkdir modules6
	  cd modules6
	  dotest module6-setup-1 "${testcvs} -Q co CVSROOT" ""
	  cd CVSROOT
	  echo "longmodulename who cares" >modules
	  echo "badname" >>modules
	  # This test almost isn't setup since it generates the error message
	  # we are looking for if `-Q' isn't specified, but I want to test the
	  # filename in the message later.
	  dotest modules6-setup-2 "$testcvs -Q ci -mbad-modules"

	  # Here's where CVS would report not being able to find `lename'
	  cd ..
	  dotest_fail modules6-1 "${testcvs} -q co badname" \
"${SPROG} checkout: warning: NULL value for key .badname. at line 2 of .${CVSROOT_DIRNAME}/CVSROOT/modules.
${SPROG} checkout: cannot find module .badname. - ignored" \
"${SPROG} server: warning: NULL value for key .badname. at line 2 of .${CVSROOT_DIRNAME}/CVSROOT/modules.
${SPROG} server: cannot find module .badname. - ignored
${CPROG} \[checkout aborted\]: cannot expand modules"

	  dokeep
	  restore_adm
	  cd ..
	  rm -r modules6
	  ;;



	modules7)
	  #
	  # Test tag problems vs an empty CVSROOT/val-tags file
	  #
	  # See the header comment for the `modules' test for an index of
	  # the complete suite of modules tests.
	  #
	  mkdir modules7
	  cd modules7
	  dotest modules7-1 "$testcvs -Q co -d top ."
	  cd top
	  mkdir zero one
	  dotest modules7-2 "$testcvs -Q add zero one"
	  cd one
	  echo 'file1 contents' > file1
	  dotest modules7-2 "$testcvs -Q add file1"
	  dotest modules7-3 "$testcvs -Q ci -mnew file1"
	  dotest modules7-4 "$testcvs -Q tag mytag file1"
	  cd ../CVSROOT
	  echo 'all -a zero one' > modules
	  dotest modules7-5 "$testcvs -Q ci -mall-module"
	  cd ../..
	  mkdir myexport
	  cd myexport

	  # This failed prior to CVS version 1.12.10.
	  dotest modules7-7 "$testcvs export -rmytag all" \
"$SPROG export: Updating zero
$SPROG export: Updating one
U one/file1"
	  dotest modules7-8 'cat one/file1' 'file1 contents'

	  dokeep

	  # cleanup
	  restore_adm
	  cd ../..
	  rm -fr modules7
	  rm -rf $CVSROOT_DIRNAME/zero $CVSROOT_DIRNAME/one
	  ;;



	mkmodules)
	  # When a file listed in checkoutlist doesn't exist, cvs-1.10.4
	  # would fail to remove the CVSROOT/.#[0-9]* temporary file it
	  # creates while mkmodules is in the process of trying to check
	  # out the missing file.

	  mkdir 1; cd 1
	  dotest mkmodules-temp-file-removal-1 "${testcvs} -Q co CVSROOT" ''
	  cd CVSROOT
	  echo no-such-file >> checkoutlist
	  dotest mkmodules-temp-file-removal-2 "$testcvs -Q ci -m. checkoutlist"

	  dotest mkmodules-temp-file-removal-3 \
"echo $CVSROOT_DIRNAME/CVSROOT/.#[0-9]*" \
"$CVSROOT_DIRNAME/CVSROOT/\.#\[0-9\]\*"

	  # Versions 1.11.6 & 1.12.1 and earlier of CVS printed most of the
	  # white space included before error messages in checkoutlist.
	  echo "no-such-file     Failed to update no-such-file." >checkoutlist
	  dotest mkmodules-error-message-1 "$testcvs -Q ci -m. checkoutlist" \
"$SPROG commit: Failed to update no-such-file\."

	  # Versions 1.11.6 & 1.12.1 and earlier of CVS used the error string
	  # from the checkoutlist file as the format string passed to error()'s
	  # printf.  Check that this is no longer the case by verifying that
	  # printf format patterns remain unchanged.
	  echo "no-such-file     Failed to update %s %lx times because %s happened %d times." >checkoutlist
	  dotest mkmodules-error-message-2 "$testcvs -Q ci -m. checkoutlist" \
"$SPROG commit: Failed to update %s %lx times because %s happened %d times\."

	  dotest mkmodules-cleanup-1 \
"$testcvs -Q up -pr1.1 checkoutlist >checkoutlist"
	  dotest mkmodules-cleanup-2 "$testcvs -Q ci -m. checkoutlist"

	  dokeep
	  cd ../..
	  rm -r 1
	  ;;



	co-d)
	  # Some tests of various permutations of co-d when directories exist
	  # and checkouts lengthen.
	  #
	  # Interestingly enough, these same tests pass when the directory
	  # lengthening happens via the modules file.  Go figure.
	  module=co-d
	  mkdir $module; cd $module
	  mkdir top; cd top
	  dotest co-d-init-1 "$testcvs -Q co -l ."
	  mkdir $module
	  dotest co-d-init-2 "$testcvs -Q add $module"
	  cd $module
	  echo content >file1
	  echo different content >file2
	  dotest co-d-init-3 "$testcvs -Q add file1 file2"
	  dotest co-d-init-4 "$testcvs -Q ci -madd-em"
	  cd ../..

	  mkdir 2; cd 2
	  dotest co-d-1 "$testcvs -q co -d dir $module" \
"U dir/file1
U dir/file2"
	  dotest co-d-1.2 "cat dir/CVS/Repository" "$module"

	  dotest co-d-2 "$testcvs -q co -d dir2/sdir $module" \
"U dir2/sdir/file1
U dir2/sdir/file2"
	  dotest co-d-2.2 "cat dir2/CVS/Repository" "."
	  dotest co-d-2.3 "cat dir2/sdir/CVS/Repository" "$module"

	  dotest co-d-2.4 "$testcvs -q co -d dir2.4/sdir/sdir2 $module" \
"U dir2.4/sdir/sdir2/file1
U dir2.4/sdir/sdir2/file2"
	  dotest co-d-2.4.2 "cat dir2.4/CVS/Repository" "CVSROOT/Emptydir"
	  dotest co-d-2.4.3 "cat dir2.4/sdir/CVS/Repository" "."
	  dotest co-d-2.4.3 "cat dir2.4/sdir/sdir2/CVS/Repository" "$module"

	  mkdir dir3
	  dotest co-d-3 "$testcvs -q co -d dir3 $module" \
"U dir3/file1
U dir3/file2"
	  dotest co-d-3.2 "cat dir3/CVS/Repository" "$module"

	  mkdir dir4
	  dotest co-d-4 "$testcvs -q co -d dir4/sdir $module" \
"U dir4/sdir/file1
U dir4/sdir/file2"

	  # CVS is only supposed to create administration directories in
	  # directories it also creates, and in the directory specified by
	  # the last portion of the path passed to -d regardless.  This is
	  #
	  # FIXCVS:
	  # This is broken in client/server mode because the server does not
	  # know the client's directory structure and has to create
	  # everything.
	  if $remote; then
	    dotest co-d-4.2r "cat dir4/CVS/Repository" "."
	  else
	    dotest_fail co-d-4.2 "test -d dir4/CVS"
	  fi

	  dotest co-d-4.3 "cat dir4/sdir/CVS/Repository" "$module"

	  mkdir dir5
	  mkdir dir5/sdir
	  dotest co-d-5 "$testcvs -q co -d dir5/sdir $module" \
"U dir5/sdir/file1
U dir5/sdir/file2"
	    # FIXCVS as for co-d-4.2r.
	  if $remote; then
	    dotest co-d-5.2 "cat dir5/CVS/Repository" "."
	  else
	    dotest_fail co-d-5.2 "test -d dir5/CVS"
	  fi

	  dotest co-d-5.3 "cat dir5/sdir/CVS/Repository" "$module"

	  # clean up
	  dokeep
	  cd ../..
	  modify_repo rm -rf $CVSROOT_DIRNAME/$module
	  rm -r $module
	  ;;



	cvsadm)
	  # These test check the content of CVS' administrative
	  # files as they are checked out in various configurations.
	  # (As a side note, I'm not using the "-q" flag in any of
	  # this code, which should provide some extra checking for
          # those messages which don't seem to be checked thoroughly
	  # anywhere else.)  To do a thorough test, we need to make
	  # a bunch of modules in various configurations.
	  #
	  # <1mod> is a directory at the top level of cvsroot
	  #    ``foo bar''
	  # <2mod> is a directory at the second level of cvsroot
	  #    ``foo bar/baz''
	  # <1d1mod> is a directory at the top level which is
	  #   checked out into another directory
	  #     ``foo -d bar baz''
	  # <1d2mod> is a directory at the second level which is
	  #   checked out into another directory
	  #     ``foo -d bar baz/quux''
	  # <2d1mod> is a directory at the top level which is
	  #   checked out into a directory that is two deep
	  #     ``foo -d bar/baz quux''
	  # <2d2mod> is a directory at the second level which is
	  #   checked out into a directory that is two deep
	  #     ``foo -d bar/baz quux''
	  #
	  # The tests do each of these types separately and in twos.
	  # We also repeat each test -d flag for 1-deep and 2-deep
	  # directories.
	  #
	  # Each test should check the output for the Repository
	  # file, since that is the one which varies depending on 
	  # the directory and how it was checked out.
	  #
	  # Yes, this is verbose, but at least it's very thorough.

	  # convenience variables
	  REP=${CVSROOT}

	  # First, set TopLevelAdmin=yes so we're sure to get
	  # top-level CVS directories.
	  mkdir 1; cd 1
	  dotest cvsadm-setup-1 "${testcvs} -q co CVSROOT/config" \
"U CVSROOT/config"
	  cd CVSROOT
	  echo "TopLevelAdmin=yes" >>config
	  dotest cvsadm-setup-2 "${testcvs} -q ci -m yes-top-level" \
"$CVSROOT_DIRNAME/CVSROOT/config,v  <--  config
new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
$SPROG commit: Rebuilding administrative file database"
	  cd ../..
	  rm -r 1

	  # Second, check out the modules file and edit it.
	  mkdir 1; cd 1
	  dotest cvsadm-1 "${testcvs} co CVSROOT/modules" \
"U CVSROOT/modules"

	  # Test CVS/Root once.  Since there is only one part of
	  # the code which writes CVS/Root files (Create_Admin),
	  # there is no point in testing this every time.
	  dotest cvsadm-1a "cat CVS/Root" ${REP}
	  dotest cvsadm-1b "cat CVS/Repository" "\."
	  dotest cvsadm-1c "cat CVSROOT/CVS/Root" ${REP}
	  dotest cvsadm-1d "cat CVSROOT/CVS/Repository" "CVSROOT"
          # All of the defined module names begin with a number.
	  # All of the top-level directory names begin with "dir".
	  # All of the subdirectory names begin with "sub".
	  # All of the top-level modules begin with "mod".
	  echo "# Module defs for cvsadm tests" > CVSROOT/modules
	  echo "1mod mod1" >> CVSROOT/modules
	  echo "1mod-2 mod1-2" >> CVSROOT/modules
	  echo "2mod mod2/sub2" >> CVSROOT/modules
	  echo "2mod-2 mod2-2/sub2-2" >> CVSROOT/modules
	  echo "1d1mod -d dir1d1 mod1" >> CVSROOT/modules
	  echo "1d1mod-2 -d dir1d1-2 mod1-2" >> CVSROOT/modules
	  echo "1d2mod -d dir1d2 mod2/sub2" >> CVSROOT/modules
	  echo "1d2mod-2 -d dir1d2-2 mod2-2/sub2-2" >> CVSROOT/modules
	  echo "2d1mod -d dir2d1/sub2d1 mod1" >> CVSROOT/modules
	  echo "2d1mod-2 -d dir2d1-2/sub2d1-2 mod1-2" >> CVSROOT/modules
	  echo "2d2mod -d dir2d2/sub2d2 mod2/sub2" >> CVSROOT/modules
	  echo "2d2mod-2 -d dir2d2-2/sub2d2-2 mod2-2/sub2-2" >> CVSROOT/modules
	  dotest cvsadm-1e "${testcvs} ci -m add-modules" \
"${CPROG} commit: Examining .
${CPROG} commit: Examining CVSROOT
${CVSROOT_DIRNAME}/CVSROOT/modules,v  <--  CVSROOT/modules
new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
${SPROG} commit: Rebuilding administrative file database" \
"${CPROG} commit: Examining .
${CPROG} commit: Examining CVSROOT"
	  rm -rf CVS CVSROOT;

	  # Create the various modules
	  dotest cvsadm-2 "${testcvs} -q co -l ." ''
	  mkdir mod1
	  mkdir mod1-2
	  mkdir mod2
	  mkdir mod2/sub2
	  mkdir mod2-2
	  mkdir mod2-2/sub2-2
	  dotest cvsadm-2a "${testcvs} add mod1 mod1-2 mod2 mod2/sub2 mod2-2 mod2-2/sub2-2" \
"Directory ${CVSROOT_DIRNAME}/mod1 added to the repository
Directory ${CVSROOT_DIRNAME}/mod1-2 added to the repository
Directory ${CVSROOT_DIRNAME}/mod2 added to the repository
Directory ${CVSROOT_DIRNAME}/mod2/sub2 added to the repository
Directory ${CVSROOT_DIRNAME}/mod2-2 added to the repository
Directory ${CVSROOT_DIRNAME}/mod2-2/sub2-2 added to the repository"

	  # Populate the directories for the halibut
	  echo "file1" > mod1/file1
	  echo "file1-2" > mod1-2/file1-2
	  echo "file2" > mod2/sub2/file2
	  echo "file2-2" > mod2-2/sub2-2/file2-2
	  dotest cvsadm-2aa "${testcvs} add mod1/file1 mod1-2/file1-2 mod2/sub2/file2 mod2-2/sub2-2/file2-2" \
"${SPROG} add: scheduling file .mod1/file1. for addition
${SPROG} add: scheduling file .mod1-2/file1-2. for addition
${SPROG} add: scheduling file .mod2/sub2/file2. for addition
${SPROG} add: scheduling file .mod2-2/sub2-2/file2-2. for addition
${SPROG} add: use \`${SPROG} commit' to add these files permanently"

	  dotest cvsadm-2b "${testcvs} ci -m yup mod1 mod1-2 mod2 mod2-2" \
"${CPROG} commit: Examining mod1
${CPROG} commit: Examining mod1-2
${CPROG} commit: Examining mod2
${CPROG} commit: Examining mod2/sub2
${CPROG} commit: Examining mod2-2
${CPROG} commit: Examining mod2-2/sub2-2
${CVSROOT_DIRNAME}/mod1/file1,v  <--  mod1/file1
initial revision: 1.1
${CVSROOT_DIRNAME}/mod1-2/file1-2,v  <--  mod1-2/file1-2
initial revision: 1.1
${CVSROOT_DIRNAME}/mod2/sub2/file2,v  <--  mod2/sub2/file2
initial revision: 1.1
${CVSROOT_DIRNAME}/mod2-2/sub2-2/file2-2,v  <--  mod2-2/sub2-2/file2-2
initial revision: 1.1"
	  # Finished creating the modules -- clean up.
	  rm -rf CVS mod1 mod1-2 mod2 mod2-2
	  # Done.

	  ##################################################
	  ## Start the dizzying array of possibilities.
	  ## Begin with each module type separately.
	  ##################################################
	  
	  # Pattern -- after each checkout, first check the top-level
	  # CVS directory.  Then, check the directories in numerical
	  # order.

	  dotest cvsadm-3 "${testcvs} co 1mod" \
"${SPROG} checkout: Updating 1mod
U 1mod/file1"
	  dotest cvsadm-3b "cat CVS/Repository" "\."
	  dotest cvsadm-3d "cat 1mod/CVS/Repository" "mod1"
	  rm -rf CVS 1mod

	  dotest cvsadm-4 "${testcvs} co 2mod" \
"${SPROG} checkout: Updating 2mod
U 2mod/file2"
	  dotest cvsadm-4b "cat CVS/Repository" "\."
	  dotest cvsadm-4d "cat 2mod/CVS/Repository" "mod2/sub2"
	  rm -rf CVS 2mod

	  dotest cvsadm-5 "${testcvs} co 1d1mod" \
"${SPROG} checkout: Updating dir1d1
U dir1d1/file1"
	  dotest cvsadm-5b "cat CVS/Repository" "\."
	  dotest cvsadm-5d "cat dir1d1/CVS/Repository" "mod1"
	  rm -rf CVS dir1d1

	  dotest cvsadm-6 "${testcvs} co 1d2mod" \
"${SPROG} checkout: Updating dir1d2
U dir1d2/file2"
	  dotest cvsadm-6b "cat CVS/Repository" "\."
	  dotest cvsadm-6d "cat dir1d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir1d2

	  dotest cvsadm-7 "${testcvs} co 2d1mod" \
"${SPROG} checkout: Updating dir2d1/sub2d1
U dir2d1/sub2d1/file1"
	  dotest cvsadm-7b "cat CVS/Repository" "\."
	  dotest cvsadm-7d "cat dir2d1/CVS/Repository" "\."
	  dotest cvsadm-7f "cat dir2d1/sub2d1/CVS/Repository" "mod1"
	  rm -rf CVS dir2d1

	  dotest cvsadm-8 "${testcvs} co 2d2mod" \
"${SPROG} checkout: Updating dir2d2/sub2d2
U dir2d2/sub2d2/file2"
	  dotest cvsadm-8b "cat CVS/Repository" "\."
	  dotest cvsadm-8d "cat dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-8f "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir2d2

	  ##################################################
	  ## You are in a shell script of twisted little
	  ## module combination statements, all alike.
	  ##################################################

	  ### 1mod
	  
	  dotest cvsadm-9 "${testcvs} co 1mod 1mod-2" \
"${SPROG} checkout: Updating 1mod
U 1mod/file1
${SPROG} checkout: Updating 1mod-2
U 1mod-2/file1-2"
	  # the usual for the top level
	  dotest cvsadm-9b "cat CVS/Repository" "\."
	  # the usual for 1mod
	  dotest cvsadm-9d "cat 1mod/CVS/Repository" "mod1"
	  # the usual for 1mod copy
	  dotest cvsadm-9f "cat 1mod-2/CVS/Repository" "mod1-2"
	  rm -rf CVS 1mod 1mod-2

	  # 1mod 2mod redmod bluemod
	  dotest cvsadm-10 "${testcvs} co 1mod 2mod" \
"${SPROG} checkout: Updating 1mod
U 1mod/file1
${SPROG} checkout: Updating 2mod
U 2mod/file2"
	  # the usual for the top level
	  dotest cvsadm-10b "cat CVS/Repository" "\."
	  # the usual for 1mod
	  dotest cvsadm-10d "cat 1mod/CVS/Repository" "mod1"
	  # the usual for 2dmod
	  dotest cvsadm-10f "cat 2mod/CVS/Repository" "mod2/sub2"
	  rm -rf CVS 1mod 2mod

	  dotest cvsadm-11 "${testcvs} co 1mod 1d1mod" \
"${SPROG} checkout: Updating 1mod
U 1mod/file1
${SPROG} checkout: Updating dir1d1
U dir1d1/file1"
	  # the usual for the top level
	  dotest cvsadm-11b "cat CVS/Repository" "\."
	  # the usual for 1mod
	  dotest cvsadm-11d "cat 1mod/CVS/Repository" "mod1"
	  # the usual for 1d1mod
	  dotest cvsadm-11f "cat dir1d1/CVS/Repository" "mod1"
	  rm -rf CVS 1mod dir1d1

	  dotest cvsadm-12 "${testcvs} co 1mod 1d2mod" \
"${SPROG} checkout: Updating 1mod
U 1mod/file1
${SPROG} checkout: Updating dir1d2
U dir1d2/file2"
	  # the usual for the top level
	  dotest cvsadm-12b "cat CVS/Repository" "\."
	  # the usual for 1mod
	  dotest cvsadm-12d "cat 1mod/CVS/Repository" "mod1"
	  # the usual for 1d2mod
	  dotest cvsadm-12f "cat dir1d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS 1mod dir1d2

	  dotest cvsadm-13 "${testcvs} co 1mod 2d1mod" \
"${SPROG} checkout: Updating 1mod
U 1mod/file1
${SPROG} checkout: Updating dir2d1/sub2d1
U dir2d1/sub2d1/file1"
	  # the usual for the top level
	  dotest cvsadm-13b "cat CVS/Repository" "\."
	  # the usual for 1mod
	  dotest cvsadm-13d "cat 1mod/CVS/Repository" "mod1"
	  # the usual for 2d1mod
	  dotest cvsadm-13f "cat dir2d1/CVS/Repository" "\."
	  dotest cvsadm-13h "cat dir2d1/sub2d1/CVS/Repository" "mod1"
	  rm -rf CVS 1mod dir2d1

	  dotest cvsadm-14 "${testcvs} co 1mod 2d2mod" \
"${SPROG} checkout: Updating 1mod
U 1mod/file1
${SPROG} checkout: Updating dir2d2/sub2d2
U dir2d2/sub2d2/file2"
	  # the usual for the top level
	  dotest cvsadm-14b "cat CVS/Repository" "\."
	  # the usual for 1mod
	  dotest cvsadm-14d "cat 1mod/CVS/Repository" "mod1"
	  # the usual for 2d2mod
	  dotest cvsadm-14f "cat dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-14h "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS 1mod dir2d2


	  ### 2mod
	  
	  dotest cvsadm-15 "${testcvs} co 2mod 2mod-2" \
"${SPROG} checkout: Updating 2mod
U 2mod/file2
${SPROG} checkout: Updating 2mod-2
U 2mod-2/file2-2"
	  # the usual for the top level
	  dotest cvsadm-15b "cat CVS/Repository" "\."
	  # the usual for 2mod
	  dotest cvsadm-15d "cat 2mod/CVS/Repository" "mod2/sub2"
	  # the usual for 2mod copy
	  dotest cvsadm-15f "cat 2mod-2/CVS/Repository" "mod2-2/sub2-2"
	  rm -rf CVS 2mod 2mod-2


	  dotest cvsadm-16 "${testcvs} co 2mod 1d1mod" \
"${SPROG} checkout: Updating 2mod
U 2mod/file2
${SPROG} checkout: Updating dir1d1
U dir1d1/file1"
	  # the usual for the top level
	  dotest cvsadm-16b "cat CVS/Repository" "\."
	  # the usual for 2mod
	  dotest cvsadm-16d "cat 2mod/CVS/Repository" "mod2/sub2"
	  # the usual for 1d1mod
	  dotest cvsadm-16f "cat dir1d1/CVS/Repository" "mod1"
	  rm -rf CVS 2mod dir1d1

	  dotest cvsadm-17 "${testcvs} co 2mod 1d2mod" \
"${SPROG} checkout: Updating 2mod
U 2mod/file2
${SPROG} checkout: Updating dir1d2
U dir1d2/file2"
	  # the usual for the top level
	  dotest cvsadm-17b "cat CVS/Repository" "\."
	  # the usual for 2mod
	  dotest cvsadm-17d "cat 2mod/CVS/Repository" "mod2/sub2"
	  # the usual for 1d2mod
	  dotest cvsadm-17f "cat dir1d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS 2mod dir1d2

	  dotest cvsadm-18 "${testcvs} co 2mod 2d1mod" \
"${SPROG} checkout: Updating 2mod
U 2mod/file2
${SPROG} checkout: Updating dir2d1/sub2d1
U dir2d1/sub2d1/file1"
	  # the usual for the top level
	  dotest cvsadm-18b "cat CVS/Repository" "\."
	  # the usual for 2mod
	  dotest cvsadm-18d "cat 2mod/CVS/Repository" "mod2/sub2"
	  # the usual for 2d1mod
	  dotest cvsadm-18f "cat dir2d1/CVS/Repository" "\."
	  dotest cvsadm-18h "cat dir2d1/sub2d1/CVS/Repository" "mod1"
	  rm -rf CVS 2mod dir2d1

	  dotest cvsadm-19 "${testcvs} co 2mod 2d2mod" \
"${SPROG} checkout: Updating 2mod
U 2mod/file2
${SPROG} checkout: Updating dir2d2/sub2d2
U dir2d2/sub2d2/file2"
	  # the usual for the top level
	  dotest cvsadm-19b "cat CVS/Repository" "\."
	  # the usual for 2mod
	  dotest cvsadm-19d "cat 2mod/CVS/Repository" "mod2/sub2"
	  # the usual for 2d2mod
	  dotest cvsadm-19f "cat dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-19h "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS 2mod dir2d2


	  ### 1d1mod

	  dotest cvsadm-20 "${testcvs} co 1d1mod 1d1mod-2" \
"${SPROG} checkout: Updating dir1d1
U dir1d1/file1
${SPROG} checkout: Updating dir1d1-2
U dir1d1-2/file1-2"
	  # the usual for the top level
	  dotest cvsadm-20b "cat CVS/Repository" "\."
	  # the usual for 1d1mod
	  dotest cvsadm-20d "cat dir1d1/CVS/Repository" "mod1"
	  # the usual for 1d1mod copy
	  dotest cvsadm-20f "cat dir1d1-2/CVS/Repository" "mod1-2"
	  rm -rf CVS dir1d1 dir1d1-2

	  dotest cvsadm-21 "${testcvs} co 1d1mod 1d2mod" \
"${SPROG} checkout: Updating dir1d1
U dir1d1/file1
${SPROG} checkout: Updating dir1d2
U dir1d2/file2"
	  # the usual for the top level
	  dotest cvsadm-21b "cat CVS/Repository" "\."
	  # the usual for 1d1mod
	  dotest cvsadm-21d "cat dir1d1/CVS/Repository" "mod1"
	  # the usual for 1d2mod
	  dotest cvsadm-21f "cat dir1d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir1d1 dir1d2

	  dotest cvsadm-22 "${testcvs} co 1d1mod 2d1mod" \
"${SPROG} checkout: Updating dir1d1
U dir1d1/file1
${SPROG} checkout: Updating dir2d1/sub2d1
U dir2d1/sub2d1/file1"
	  # the usual for the top level
	  dotest cvsadm-22b "cat CVS/Repository" "\."
	  # the usual for 1d1mod
	  dotest cvsadm-22d "cat dir1d1/CVS/Repository" "mod1"
	  # the usual for 2d1mod
	  dotest cvsadm-22f "cat dir2d1/CVS/Repository" "\."
	  dotest cvsadm-22h "cat dir2d1/sub2d1/CVS/Repository" "mod1"
	  rm -rf CVS dir1d1 dir2d1

	  dotest cvsadm-23 "${testcvs} co 1d1mod 2d2mod" \
"${SPROG} checkout: Updating dir1d1
U dir1d1/file1
${SPROG} checkout: Updating dir2d2/sub2d2
U dir2d2/sub2d2/file2"
	  # the usual for the top level
	  dotest cvsadm-23b "cat CVS/Repository" "\."
	  # the usual for 1d1mod
	  dotest cvsadm-23d "cat dir1d1/CVS/Repository" "mod1"
	  # the usual for 2d2mod
	  dotest cvsadm-23f "cat dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-23h "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir1d1 dir2d2


	  ### 1d2mod

	  dotest cvsadm-24 "${testcvs} co 1d2mod 1d2mod-2" \
"${SPROG} checkout: Updating dir1d2
U dir1d2/file2
${SPROG} checkout: Updating dir1d2-2
U dir1d2-2/file2-2"
	  # the usual for the top level
	  dotest cvsadm-24b "cat CVS/Repository" "\."
	  # the usual for 1d2mod
	  dotest cvsadm-24d "cat dir1d2/CVS/Repository" "mod2/sub2"
	  # the usual for 1d2mod copy
	  dotest cvsadm-24f "cat dir1d2-2/CVS/Repository" "mod2-2/sub2-2"
	  rm -rf CVS dir1d2 dir1d2-2

	  dotest cvsadm-25 "${testcvs} co 1d2mod 2d1mod" \
"${SPROG} checkout: Updating dir1d2
U dir1d2/file2
${SPROG} checkout: Updating dir2d1/sub2d1
U dir2d1/sub2d1/file1"
	  # the usual for the top level
	  dotest cvsadm-25b "cat CVS/Repository" "\."
	  # the usual for 1d2mod
	  dotest cvsadm-25d "cat dir1d2/CVS/Repository" "mod2/sub2"
	  # the usual for 2d1mod
	  dotest cvsadm-25f "cat dir2d1/CVS/Repository" "\."
	  dotest cvsadm-25h "cat dir2d1/sub2d1/CVS/Repository" "mod1"
	  rm -rf CVS dir1d2 dir2d1

	  dotest cvsadm-26 "${testcvs} co 1d2mod 2d2mod" \
"${SPROG} checkout: Updating dir1d2
U dir1d2/file2
${SPROG} checkout: Updating dir2d2/sub2d2
U dir2d2/sub2d2/file2"
	  # the usual for the top level
	  dotest cvsadm-26b "cat CVS/Repository" "\."
	  # the usual for 1d2mod
	  dotest cvsadm-26d "cat dir1d2/CVS/Repository" "mod2/sub2"
	  # the usual for 2d2mod
	  dotest cvsadm-26f "cat dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-26h "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir1d2 dir2d2


	  # 2d1mod

	  dotest cvsadm-27 "${testcvs} co 2d1mod 2d1mod-2" \
"${SPROG} checkout: Updating dir2d1/sub2d1
U dir2d1/sub2d1/file1
${SPROG} checkout: Updating dir2d1-2/sub2d1-2
U dir2d1-2/sub2d1-2/file1-2"
	  # the usual for the top level
	  dotest cvsadm-27b "cat CVS/Repository" "\."
	  # the usual for 2d1mod
	  dotest cvsadm-27d "cat dir2d1/CVS/Repository" "\."
	  dotest cvsadm-27f "cat dir2d1/sub2d1/CVS/Repository" "mod1"
	  # the usual for 2d1mod
	  dotest cvsadm-27h "cat dir2d1-2/CVS/Repository" "\."
	  dotest cvsadm-27j "cat dir2d1-2/sub2d1-2/CVS/Repository" "mod1-2"
	  rm -rf CVS dir2d1 dir2d1-2

	  dotest cvsadm-28 "${testcvs} co 2d1mod 2d2mod" \
"${SPROG} checkout: Updating dir2d1/sub2d1
U dir2d1/sub2d1/file1
${SPROG} checkout: Updating dir2d2/sub2d2
U dir2d2/sub2d2/file2"
	  # the usual for the top level
	  dotest cvsadm-28b "cat CVS/Repository" "\."
	  # the usual for 2d1mod
	  dotest cvsadm-28d "cat dir2d1/CVS/Repository" "\."
	  dotest cvsadm-28f "cat dir2d1/sub2d1/CVS/Repository" "mod1"
	  # the usual for 2d2mod
	  dotest cvsadm-28h "cat dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-28j "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir2d1 dir2d2

	  
	  # 2d2mod

	  dotest cvsadm-29 "${testcvs} co 2d2mod 2d2mod-2" \
"${SPROG} checkout: Updating dir2d2/sub2d2
U dir2d2/sub2d2/file2
${SPROG} checkout: Updating dir2d2-2/sub2d2-2
U dir2d2-2/sub2d2-2/file2-2"
	  # the usual for the top level
	  dotest cvsadm-29b "cat CVS/Repository" "\."
	  # the usual for 2d2mod
	  dotest cvsadm-29d "cat dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-29f "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
	  # the usual for 2d2mod
	  dotest cvsadm-29h "cat dir2d2-2/CVS/Repository" "mod2-2"
	  dotest cvsadm-29j "cat dir2d2-2/sub2d2-2/CVS/Repository" \
"mod2-2/sub2-2"
	  rm -rf CVS dir2d2 dir2d2-2

	  ##################################################
	  ## And now, all of that again using the "-d" flag
	  ## on the command line.
	  ##################################################

	  dotest cvsadm-1d3 "${testcvs} co -d dir 1mod" \
"${SPROG} checkout: Updating dir
U dir/file1"
	  dotest cvsadm-1d3b "cat CVS/Repository" "\."
	  dotest cvsadm-1d3d "cat dir/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  dotest cvsadm-1d4 "${testcvs} co -d dir 2mod" \
"${SPROG} checkout: Updating dir
U dir/file2"
	  dotest cvsadm-1d4b "cat CVS/Repository" "\."
	  dotest cvsadm-1d4d "cat dir/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  dotest cvsadm-1d5 "${testcvs} co -d dir 1d1mod" \
"${SPROG} checkout: Updating dir
U dir/file1"
	  dotest cvsadm-1d5b "cat CVS/Repository" "\."
	  dotest cvsadm-1d5d "cat dir/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  dotest cvsadm-1d6 "${testcvs} co -d dir 1d2mod" \
"${SPROG} checkout: Updating dir
U dir/file2"
	  dotest cvsadm-1d6b "cat CVS/Repository" "\."
	  dotest cvsadm-1d6d "cat dir/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  dotest cvsadm-1d7 "${testcvs} co -d dir 2d1mod" \
"${SPROG} checkout: Updating dir
U dir/file1"
	  dotest cvsadm-1d7b "cat CVS/Repository" "\."
	  dotest cvsadm-1d7d "cat dir/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  dotest cvsadm-1d8 "${testcvs} co -d dir 2d2mod" \
"${SPROG} checkout: Updating dir
U dir/file2"
	  dotest cvsadm-1d8b "cat CVS/Repository" "\."
	  dotest cvsadm-1d8d "cat dir/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  ##################################################
	  ## Los Combonaciones
	  ##################################################

	  ### 1mod

	  dotest cvsadm-1d9 "${testcvs} co -d dir 1mod 1mod-2" \
"${SPROG} checkout: Updating dir/1mod
U dir/1mod/file1
${SPROG} checkout: Updating dir/1mod-2
U dir/1mod-2/file1-2"
	  # the usual for the top level
	  dotest cvsadm-1d9b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d9d "cat dir/CVS/Repository" "\."
	  # the usual for 1mod
	  dotest cvsadm-1d9f "cat dir/1mod/CVS/Repository" "mod1"
	  # the usual for 1mod copy
	  dotest cvsadm-1d9h "cat dir/1mod-2/CVS/Repository" "mod1-2"
	  rm -rf CVS dir

	  # 1mod 2mod redmod bluemod
	  dotest cvsadm-1d10 "${testcvs} co -d dir 1mod 2mod" \
"${SPROG} checkout: Updating dir/1mod
U dir/1mod/file1
${SPROG} checkout: Updating dir/2mod
U dir/2mod/file2"
	  dotest cvsadm-1d10b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d10d "cat dir/CVS/Repository" "\."
	  # the usual for 1mod
	  dotest cvsadm-1d10f "cat dir/1mod/CVS/Repository" "mod1"
	  # the usual for 2dmod
	  dotest cvsadm-1d10h "cat dir/2mod/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  dotest cvsadm-1d11 "${testcvs} co -d dir 1mod 1d1mod" \
"${SPROG} checkout: Updating dir/1mod
U dir/1mod/file1
${SPROG} checkout: Updating dir/dir1d1
U dir/dir1d1/file1"
	  dotest cvsadm-1d11b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d11d "cat dir/CVS/Repository" "\."
	  # the usual for 1mod
	  dotest cvsadm-1d11f "cat dir/1mod/CVS/Repository" "mod1"
	  # the usual for 1d1mod
	  dotest cvsadm-1d11h "cat dir/dir1d1/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  dotest cvsadm-1d12 "${testcvs} co -d dir 1mod 1d2mod" \
"${SPROG} checkout: Updating dir/1mod
U dir/1mod/file1
${SPROG} checkout: Updating dir/dir1d2
U dir/dir1d2/file2"
	  dotest cvsadm-1d12b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d12d "cat dir/CVS/Repository" "\."
	  # the usual for 1mod
	  dotest cvsadm-1d12f "cat dir/1mod/CVS/Repository" "mod1"
	  # the usual for 1d2mod
	  dotest cvsadm-1d12h "cat dir/dir1d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  dotest cvsadm-1d13 "${testcvs} co -d dir 1mod 2d1mod" \
"${SPROG} checkout: Updating dir/1mod
U dir/1mod/file1
${SPROG} checkout: Updating dir/dir2d1/sub2d1
U dir/dir2d1/sub2d1/file1"
	  dotest cvsadm-1d13b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d13d "cat dir/CVS/Repository" "\."
	  # the usual for 1mod
	  dotest cvsadm-1d13f "cat dir/1mod/CVS/Repository" "mod1"
	  # the usual for 2d1mod
	  dotest cvsadm-1d13h "cat dir/dir2d1/CVS/Repository" "\."
	  dotest cvsadm-1d13j "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  dotest cvsadm-1d14 "${testcvs} co -d dir 1mod 2d2mod" \
"${SPROG} checkout: Updating dir/1mod
U dir/1mod/file1
${SPROG} checkout: Updating dir/dir2d2/sub2d2
U dir/dir2d2/sub2d2/file2"
	  dotest cvsadm-1d14b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d14d "cat dir/CVS/Repository" "\."
	  # the usual for 1mod
	  dotest cvsadm-1d14f "cat dir/1mod/CVS/Repository" "mod1"
	  # the usual for 2d2mod
	  dotest cvsadm-1d14h "cat dir/dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-1d14j "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir


	  ### 2mod

	  dotest cvsadm-1d15 "${testcvs} co -d dir 2mod 2mod-2" \
"${SPROG} checkout: Updating dir/2mod
U dir/2mod/file2
${SPROG} checkout: Updating dir/2mod-2
U dir/2mod-2/file2-2"
	  dotest cvsadm-1d15b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d15d "cat dir/CVS/Repository" "mod2"
	  # the usual for 2mod
	  dotest cvsadm-1d15f "cat dir/2mod/CVS/Repository" "mod2/sub2"
	  # the usual for 2mod copy
	  dotest cvsadm-1d15h "cat dir/2mod-2/CVS/Repository" "mod2-2/sub2-2"
	  rm -rf CVS dir

	  dotest cvsadm-1d16 "${testcvs} co -d dir 2mod 1d1mod" \
"${SPROG} checkout: Updating dir/2mod
U dir/2mod/file2
${SPROG} checkout: Updating dir/dir1d1
U dir/dir1d1/file1"
	  dotest cvsadm-1d16b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d16d "cat dir/CVS/Repository" "mod2"
	  # the usual for 2mod
	  dotest cvsadm-1d16f "cat dir/2mod/CVS/Repository" "mod2/sub2"
	  # the usual for 1d1mod
	  dotest cvsadm-1d16h "cat dir/dir1d1/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  dotest cvsadm-1d17 "${testcvs} co -d dir 2mod 1d2mod" \
"${SPROG} checkout: Updating dir/2mod
U dir/2mod/file2
${SPROG} checkout: Updating dir/dir1d2
U dir/dir1d2/file2"
	  dotest cvsadm-1d17b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d17d "cat dir/CVS/Repository" "mod2"
	  # the usual for 2mod
	  dotest cvsadm-1d17f "cat dir/2mod/CVS/Repository" "mod2/sub2"
	  # the usual for 1d2mod
	  dotest cvsadm-1d17h "cat dir/dir1d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  dotest cvsadm-1d18 "${testcvs} co -d dir 2mod 2d1mod" \
"${SPROG} checkout: Updating dir/2mod
U dir/2mod/file2
${SPROG} checkout: Updating dir/dir2d1/sub2d1
U dir/dir2d1/sub2d1/file1"
	  dotest cvsadm-1d18b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d18d "cat dir/CVS/Repository" "mod2"
	  # the usual for 2mod
	  dotest cvsadm-1d18f "cat dir/2mod/CVS/Repository" "mod2/sub2"
	  # the usual for 2d1mod
	  dotest cvsadm-1d18h "cat dir/dir2d1/CVS/Repository" "\."
	  dotest cvsadm-1d18j "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  dotest cvsadm-1d19 "${testcvs} co -d dir 2mod 2d2mod" \
"${SPROG} checkout: Updating dir/2mod
U dir/2mod/file2
${SPROG} checkout: Updating dir/dir2d2/sub2d2
U dir/dir2d2/sub2d2/file2"
	  dotest cvsadm-1d19b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d19d "cat dir/CVS/Repository" "mod2"
	  # the usual for 2mod
	  dotest cvsadm-1d19f "cat dir/2mod/CVS/Repository" "mod2/sub2"
	  # the usual for 2d2mod
	  dotest cvsadm-1d19h "cat dir/dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-1d19j "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir


	  ### 1d1mod

	  dotest cvsadm-1d20 "${testcvs} co -d dir 1d1mod 1d1mod-2" \
"${SPROG} checkout: Updating dir/dir1d1
U dir/dir1d1/file1
${SPROG} checkout: Updating dir/dir1d1-2
U dir/dir1d1-2/file1-2"
	  dotest cvsadm-1d20b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d20d "cat dir/CVS/Repository" "\."
	  # the usual for 1d1mod
	  dotest cvsadm-1d20f "cat dir/dir1d1/CVS/Repository" "mod1"
	  # the usual for 1d1mod copy
	  dotest cvsadm-1d20h "cat dir/dir1d1-2/CVS/Repository" "mod1-2"
	  rm -rf CVS dir

	  dotest cvsadm-1d21 "${testcvs} co -d dir 1d1mod 1d2mod" \
"${SPROG} checkout: Updating dir/dir1d1
U dir/dir1d1/file1
${SPROG} checkout: Updating dir/dir1d2
U dir/dir1d2/file2"
	  dotest cvsadm-1d21b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d21d "cat dir/CVS/Repository" "\."
	  # the usual for 1d1mod
	  dotest cvsadm-1d21f "cat dir/dir1d1/CVS/Repository" "mod1"
	  # the usual for 1d2mod
	  dotest cvsadm-1d21h "cat dir/dir1d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  dotest cvsadm-1d22 "${testcvs} co -d dir 1d1mod 2d1mod" \
"${SPROG} checkout: Updating dir/dir1d1
U dir/dir1d1/file1
${SPROG} checkout: Updating dir/dir2d1/sub2d1
U dir/dir2d1/sub2d1/file1"
	  dotest cvsadm-1d22b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d22d "cat dir/CVS/Repository" "\."
	  # the usual for 1d1mod
	  dotest cvsadm-1d22f "cat dir/dir1d1/CVS/Repository" "mod1"
	  # the usual for 2d1mod
	  dotest cvsadm-1d22h "cat dir/dir2d1/CVS/Repository" "\."
	  dotest cvsadm-1d22j "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  dotest cvsadm-1d23 "${testcvs} co -d dir 1d1mod 2d2mod" \
"${SPROG} checkout: Updating dir/dir1d1
U dir/dir1d1/file1
${SPROG} checkout: Updating dir/dir2d2/sub2d2
U dir/dir2d2/sub2d2/file2"
	  dotest cvsadm-1d23b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d23d "cat dir/CVS/Repository" "\."
	  # the usual for 1d1mod
	  dotest cvsadm-1d23f "cat dir/dir1d1/CVS/Repository" "mod1"
	  # the usual for 2d2mod
	  dotest cvsadm-1d23h "cat dir/dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-1d23j "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir


	  ### 1d2mod

	  dotest cvsadm-1d24 "${testcvs} co -d dir 1d2mod 1d2mod-2" \
"${SPROG} checkout: Updating dir/dir1d2
U dir/dir1d2/file2
${SPROG} checkout: Updating dir/dir1d2-2
U dir/dir1d2-2/file2-2"
	  dotest cvsadm-1d24b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d24d "cat dir/CVS/Repository" "mod2"
	  # the usual for 1d2mod
	  dotest cvsadm-1d24f "cat dir/dir1d2/CVS/Repository" "mod2/sub2"
	  # the usual for 1d2mod copy
	  dotest cvsadm-1d24h "cat dir/dir1d2-2/CVS/Repository" "mod2-2/sub2-2"
	  rm -rf CVS dir

	  dotest cvsadm-1d25 "${testcvs} co -d dir 1d2mod 2d1mod" \
"${SPROG} checkout: Updating dir/dir1d2
U dir/dir1d2/file2
${SPROG} checkout: Updating dir/dir2d1/sub2d1
U dir/dir2d1/sub2d1/file1"
	  dotest cvsadm-1d25b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d25d "cat dir/CVS/Repository" "mod2"
	  # the usual for 1d2mod
	  dotest cvsadm-1d25f "cat dir/dir1d2/CVS/Repository" "mod2/sub2"
	  # the usual for 2d1mod
	  dotest cvsadm-1d25h "cat dir/dir2d1/CVS/Repository" "\."
	  dotest cvsadm-1d25j "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  dotest cvsadm-1d26 "${testcvs} co -d dir 1d2mod 2d2mod" \
"${SPROG} checkout: Updating dir/dir1d2
U dir/dir1d2/file2
${SPROG} checkout: Updating dir/dir2d2/sub2d2
U dir/dir2d2/sub2d2/file2"
	  dotest cvsadm-1d26b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d26d "cat dir/CVS/Repository" "mod2"
	  # the usual for 1d2mod
	  dotest cvsadm-1d26f "cat dir/dir1d2/CVS/Repository" "mod2/sub2"
	  # the usual for 2d2mod
	  dotest cvsadm-1d26h "cat dir/dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-1d26j "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir


	  # 2d1mod

	  dotest cvsadm-1d27 "${testcvs} co -d dir 2d1mod 2d1mod-2" \
"${SPROG} checkout: Updating dir/dir2d1/sub2d1
U dir/dir2d1/sub2d1/file1
${SPROG} checkout: Updating dir/dir2d1-2/sub2d1-2
U dir/dir2d1-2/sub2d1-2/file1-2"
	  dotest cvsadm-1d27b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d27d "cat dir/CVS/Repository" "CVSROOT/Emptydir"
	  # the usual for 2d1mod
	  dotest cvsadm-1d27f "cat dir/dir2d1/CVS/Repository" "\."
	  dotest cvsadm-1d27h "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1"
	  # the usual for 2d1mod
	  dotest cvsadm-1d27j "cat dir/dir2d1-2/CVS/Repository" "\."
	  dotest cvsadm-1d27l "cat dir/dir2d1-2/sub2d1-2/CVS/Repository" \
"mod1-2"
	  rm -rf CVS dir

	  dotest cvsadm-1d28 "${testcvs} co -d dir 2d1mod 2d2mod" \
"${SPROG} checkout: Updating dir/dir2d1/sub2d1
U dir/dir2d1/sub2d1/file1
${SPROG} checkout: Updating dir/dir2d2/sub2d2
U dir/dir2d2/sub2d2/file2"
	  dotest cvsadm-1d28b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d28d "cat dir/CVS/Repository" "CVSROOT/Emptydir"
	  # the usual for 2d1mod
	  dotest cvsadm-1d28f "cat dir/dir2d1/CVS/Repository" "\."
	  dotest cvsadm-1d28h "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1"
	  # the usual for 2d2mod
	  dotest cvsadm-1d28j "cat dir/dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-1d28l "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  
	  # 2d2mod

	  dotest cvsadm-1d29 "${testcvs} co -d dir 2d2mod 2d2mod-2" \
"${SPROG} checkout: Updating dir/dir2d2/sub2d2
U dir/dir2d2/sub2d2/file2
${SPROG} checkout: Updating dir/dir2d2-2/sub2d2-2
U dir/dir2d2-2/sub2d2-2/file2-2"
	  dotest cvsadm-1d29b "cat CVS/Repository" "\."
	  # the usual for the dir level
	  dotest cvsadm-1d29d "cat dir/CVS/Repository" "\."
	  # the usual for 2d2mod
	  dotest cvsadm-1d29f "cat dir/dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-1d29h "cat dir/dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
	  # the usual for 2d2mod
	  dotest cvsadm-1d29j "cat dir/dir2d2-2/CVS/Repository" "mod2-2"
	  dotest cvsadm-1d29l "cat dir/dir2d2-2/sub2d2-2/CVS/Repository" \
"mod2-2/sub2-2"
	  rm -rf CVS dir

	  ##################################################
	  ## And now, some of that again using the "-d" flag
	  ## on the command line, but use a longer path.
	  ##################################################

	  dotest cvsadm-2d3-1 "$testcvs co -d dir/dir2 1mod" \
"$SPROG checkout: Updating dir/dir2
U dir/dir2/file1"

	  # Remote couldn't handle this, even with the "mkdir dir", before
	  # CVS 1.11.14.
	  dotest cvsadm-2d3b "cat CVS/Repository" "\."
	  dotest cvsadm-2d3d "cat dir/CVS/Repository" "."
	  dotest cvsadm-2d3f "cat dir/dir2/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  mkdir dir
	  dotest cvsadm-2d4 "$testcvs co -d dir/dir2 2mod" \
"$SPROG checkout: Updating dir/dir2
U dir/dir2/file2"
	  dotest cvsadm-2d4b "cat CVS/Repository" "\."
	  dotest cvsadm-2d4f "cat dir/dir2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  mkdir dir
	  dotest cvsadm-2d5 "$testcvs co -d dir/dir2 1d1mod" \
"$SPROG checkout: Updating dir/dir2
U dir/dir2/file1"
	  dotest cvsadm-2d5b "cat CVS/Repository" "\."
	  dotest cvsadm-2d5f "cat dir/dir2/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  mkdir dir
	  dotest cvsadm-2d6 "$testcvs co -d dir/dir2 1d2mod" \
"$SPROG checkout: Updating dir/dir2
U dir/dir2/file2"
	  dotest cvsadm-2d6b "cat CVS/Repository" "\."
	  dotest cvsadm-2d6f "cat dir/dir2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  mkdir dir
	  dotest cvsadm-2d7 "$testcvs co -d dir/dir2 2d1mod" \
"$SPROG checkout: Updating dir/dir2
U dir/dir2/file1"
	  dotest cvsadm-2d7b "cat CVS/Repository" "\."
	  dotest cvsadm-2d7f "cat dir/dir2/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  mkdir dir
	  dotest cvsadm-2d8 "$testcvs co -d dir/dir2 2d2mod" \
"$SPROG checkout: Updating dir/dir2
U dir/dir2/file2"
	  dotest cvsadm-2d8b "cat CVS/Repository" "\."
	  dotest cvsadm-2d8f "cat dir/dir2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  ##################################################
	  ## And now, a few of those tests revisited to
	  ## test the behavior of the -N flag.
	  ##################################################

	  dotest cvsadm-N3 "$testcvs co -N 1mod" \
"$SPROG checkout: Updating 1mod
U 1mod/file1"
	  dotest cvsadm-N3b "cat CVS/Repository" "\."
	  dotest cvsadm-N3d "cat 1mod/CVS/Repository" "mod1"
	  rm -rf CVS 1mod

	  dotest cvsadm-N4 "$testcvs co -N 2mod" \
"$SPROG checkout: Updating 2mod
U 2mod/file2"
	  dotest cvsadm-N4b "cat CVS/Repository" "\."
	  dotest cvsadm-N4d "cat 2mod/CVS/Repository" "mod2/sub2"
	  rm -rf CVS 2mod

	  dotest cvsadm-N5 "$testcvs co -N 1d1mod" \
"$SPROG checkout: Updating dir1d1
U dir1d1/file1"
	  dotest cvsadm-N5b "cat CVS/Repository" "\."
	  dotest cvsadm-N5d "cat dir1d1/CVS/Repository" "mod1"
	  rm -rf CVS dir1d1

	  dotest cvsadm-N6 "$testcvs co -N 1d2mod" \
"$SPROG checkout: Updating dir1d2
U dir1d2/file2"
	  dotest cvsadm-N6b "cat CVS/Repository" "\."
	  dotest cvsadm-N6d "cat dir1d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir1d2

	  dotest cvsadm-N7 "$testcvs co -N 2d1mod" \
"$SPROG checkout: Updating dir2d1/sub2d1
U dir2d1/sub2d1/file1"
	  dotest cvsadm-N7b "cat CVS/Repository" "\."
	  dotest cvsadm-N7d "cat dir2d1/CVS/Repository" "\."
	  dotest cvsadm-N7f "cat dir2d1/sub2d1/CVS/Repository" "mod1"
	  rm -rf CVS dir2d1

	  dotest cvsadm-N8 "$testcvs co -N 2d2mod" \
"$SPROG checkout: Updating dir2d2/sub2d2
U dir2d2/sub2d2/file2"
	  dotest cvsadm-N8b "cat CVS/Repository" "\."
	  dotest cvsadm-N8d "cat dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-N8f "cat dir2d2/sub2d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir2d2

	  ## the ones in one-deep directories

	  dotest cvsadm-N1d3 "$testcvs co -N -d dir 1mod" \
"$SPROG checkout: Updating dir/1mod
U dir/1mod/file1"
	  dotest cvsadm-N1d3b "cat CVS/Repository" "\."
	  dotest cvsadm-N1d3d "cat dir/CVS/Repository" "\."
	  dotest cvsadm-N1d3f "cat dir/1mod/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  dotest cvsadm-N1d4 "$testcvs co -N -d dir 2mod" \
"$SPROG checkout: Updating dir/2mod
U dir/2mod/file2"
	  dotest cvsadm-N1d4b "cat CVS/Repository" "\."
	  dotest cvsadm-N1d4d "cat dir/CVS/Repository" "mod2"
	  dotest cvsadm-N1d4f "cat dir/2mod/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  dotest cvsadm-N1d5 "$testcvs co -N -d dir 1d1mod" \
"$SPROG checkout: Updating dir/dir1d1
U dir/dir1d1/file1"
	  dotest cvsadm-N1d5b "cat CVS/Repository" "\."
	  dotest cvsadm-N1d5d "cat dir/CVS/Repository" "\."
	  dotest cvsadm-N1d5d "cat dir/dir1d1/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  dotest cvsadm-N1d6 "$testcvs co -N -d dir 1d2mod" \
"$SPROG checkout: Updating dir/dir1d2
U dir/dir1d2/file2"
	  dotest cvsadm-N1d6b "cat CVS/Repository" "\."
	  dotest cvsadm-N1d6d "cat dir/CVS/Repository" "mod2"
	  dotest cvsadm-N1d6f "cat dir/dir1d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  dotest cvsadm-N1d7 "$testcvs co -N -d dir 2d1mod" \
"$SPROG checkout: Updating dir/dir2d1/sub2d1
U dir/dir2d1/sub2d1/file1"
	  dotest cvsadm-N1d7b "cat CVS/Repository" "\."
	  dotest cvsadm-N1d7d "cat dir/CVS/Repository" "CVSROOT/Emptydir"
	  dotest cvsadm-N1d7f "cat dir/dir2d1/CVS/Repository" "\."
	  dotest cvsadm-N1d7h "cat dir/dir2d1/sub2d1/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  dotest cvsadm-N1d8 "$testcvs co -N -d dir 2d2mod" \
"$SPROG checkout: Updating dir/dir2d2/sub2d2
U dir/dir2d2/sub2d2/file2"
	  dotest cvsadm-N1d8b "cat CVS/Repository" "\."
	  dotest cvsadm-N1d8d "cat dir/CVS/Repository" "\."
	  dotest cvsadm-N1d8d "cat dir/dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-N1d8d "cat dir/dir2d2/sub2d2/CVS/Repository" \
"mod2/sub2"
	  rm -rf CVS dir

	  ## the ones in two-deep directories

	  mkdir dir
	  dotest cvsadm-N2d3 "$testcvs co -N -d dir/dir2 1mod" \
"$SPROG checkout: Updating dir/dir2/1mod
U dir/dir2/1mod/file1"
	  dotest cvsadm-N2d3b "cat CVS/Repository" "\."
	  dotest cvsadm-N2d3f "cat dir/dir2/CVS/Repository" "\."
	  dotest cvsadm-N2d3h "cat dir/dir2/1mod/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  mkdir dir
	  dotest cvsadm-N2d4 "$testcvs co -N -d dir/dir2 2mod" \
"$SPROG checkout: Updating dir/dir2/2mod
U dir/dir2/2mod/file2"
	  dotest cvsadm-N2d4b "cat CVS/Repository" "\."
	  dotest cvsadm-N2d4f "cat dir/dir2/CVS/Repository" "mod2"
	  dotest cvsadm-N2d4h "cat dir/dir2/2mod/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  mkdir dir
	  dotest cvsadm-N2d5 "$testcvs co -N -d dir/dir2 1d1mod" \
"$SPROG checkout: Updating dir/dir2/dir1d1
U dir/dir2/dir1d1/file1"
	  dotest cvsadm-N2d5b "cat CVS/Repository" "\."
	  dotest cvsadm-N2d5f "cat dir/dir2/CVS/Repository" "\."
	  dotest cvsadm-N2d5h "cat dir/dir2/dir1d1/CVS/Repository" "mod1"
	  rm -rf CVS dir

	  mkdir dir
	  dotest cvsadm-N2d6 "$testcvs co -N -d dir/dir2 1d2mod" \
"$SPROG checkout: Updating dir/dir2/dir1d2
U dir/dir2/dir1d2/file2"
	  dotest cvsadm-N2d6b "cat CVS/Repository" "\."
	  dotest cvsadm-N2d6f "cat dir/dir2/CVS/Repository" "mod2"
	  dotest cvsadm-N2d6h "cat dir/dir2/dir1d2/CVS/Repository" "mod2/sub2"
	  rm -rf CVS dir

	  mkdir dir
	  dotest cvsadm-N2d7 "$testcvs co -N -d dir/dir2 2d1mod" \
"$SPROG checkout: Updating dir/dir2/dir2d1/sub2d1
U dir/dir2/dir2d1/sub2d1/file1"
	  dotest cvsadm-N2d7b "cat CVS/Repository" "\."
	  dotest cvsadm-N2d7f "cat dir/dir2/CVS/Repository" "CVSROOT/Emptydir"
	  dotest cvsadm-N2d7g "cat dir/dir2/dir2d1/CVS/Repository" "\."
	  dotest cvsadm-N2d7h "cat dir/dir2/dir2d1/sub2d1/CVS/Repository" \
"mod1"
	  rm -rf CVS dir

	  mkdir dir
	  dotest cvsadm-N2d8 "$testcvs co -N -d dir/dir2 2d2mod" \
"$SPROG checkout: Updating dir/dir2/dir2d2/sub2d2
U dir/dir2/dir2d2/sub2d2/file2"
	  dotest cvsadm-N2d8b "cat CVS/Repository" "\."
	  dotest cvsadm-N2d8f "cat dir/dir2/CVS/Repository" "\."
	  dotest cvsadm-N2d8h "cat dir/dir2/dir2d2/CVS/Repository" "mod2"
	  dotest cvsadm-N2d8j "cat dir/dir2/dir2d2/sub2d2/CVS/Repository" \
"mod2/sub2"
	  rm -rf CVS dir
	  # End of test that didn't work for remote prior to CVS 1.11.14.

	  ##################################################
	  ## That's enough of that, thank you very much.
	  ##################################################

	  dokeep
	  restore_adm

	  # remove our junk
	  cd ..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/1mod $CVSROOT_DIRNAME/1mod-2 \
			     $CVSROOT_DIRNAME/2mod $CVSROOT_DIRNAME/2mod-2 \
			     $CVSROOT_DIRNAME/mod1 $CVSROOT_DIRNAME/mod1-2 \
			     $CVSROOT_DIRNAME/mod2 $CVSROOT_DIRNAME/mod2-2
	  ;;



	emptydir)
	  # Various tests of the Emptydir (CVSNULLREPOS) code.  See also:
	  #   cvsadm: tests of Emptydir in various module definitions
	  #   basicb: Test that "Emptydir" is non-special in ordinary contexts

	  mkdir 1; cd 1
	  dotest emptydir-1 "${testcvs} co CVSROOT/modules" \
"U CVSROOT/modules"
	  echo "# Module defs for emptydir tests" > CVSROOT/modules
	  echo "2d1mod -d dir2d1/sub/sub2d1 mod1" >> CVSROOT/modules
	  echo "2d1moda -d dir2d1/suba moda/modasub" >> CVSROOT/modules
	  echo "2d1modb -d dir2d1/suba mod1" >> CVSROOT/modules
	  echo "comb -a 2d1modb 2d1moda" >> CVSROOT/modules

	  dotest emptydir-2 "${testcvs} ci -m add-modules" \
"${CPROG} commit: Examining CVSROOT
${CVSROOT_DIRNAME}/CVSROOT/modules,v  <--  CVSROOT/modules
new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
${SPROG} commit: Rebuilding administrative file database" \
"${CPROG} commit: Examining CVSROOT"
	  rm -rf CVS CVSROOT

	  modify_repo mkdir $CVSROOT_DIRNAME/mod1 $CVSROOT_DIRNAME/moda
	  # Populate.  Not sure we really need to do this.
	  dotest emptydir-3 "$testcvs -q co -l ."
	  dotest emptydir-3a "${testcvs} co mod1 moda" \
"${SPROG} checkout: Updating mod1
${SPROG} checkout: Updating moda"
	  echo "file1" > mod1/file1
	  mkdir moda/modasub
	  dotest emptydir-3b "${testcvs} add moda/modasub" \
"Directory ${CVSROOT_DIRNAME}/moda/modasub added to the repository"
	  echo "filea" > moda/modasub/filea
	  dotest emptydir-4 "${testcvs} add mod1/file1 moda/modasub/filea" \
"${SPROG} add: scheduling file .mod1/file1. for addition
${SPROG} add: scheduling file .moda/modasub/filea. for addition
${SPROG} add: use \`${SPROG} commit' to add these files permanently"
	  dotest emptydir-5 "${testcvs} -q ci -m yup" \
"$CVSROOT_DIRNAME/mod1/file1,v  <--  mod1/file1
initial revision: 1\.1
${CVSROOT_DIRNAME}/moda/modasub/filea,v  <--  moda/modasub/filea
initial revision: 1\.1"
	  rm -rf mod1 moda CVS
	  # End Populate.

	  dotest emptydir-6 "${testcvs} co 2d1mod" \
"${SPROG} checkout: Updating dir2d1/sub/sub2d1
U dir2d1/sub/sub2d1/file1"
	  cd dir2d1
	  touch emptyfile
	  # It doesn't make any sense to add a file (or do much of anything
	  # else) in Emptydir; Emptydir is a placeholder indicating that
	  # the working directory doesn't correspond to anything in
	  # the repository.
	  dotest_fail emptydir-7 "${testcvs} add emptyfile" \
"${SPROG} \[add aborted]: cannot add to \`${CVSROOT_DIRNAME}/CVSROOT/Emptydir'"
	  mkdir emptydir
	  dotest_fail emptydir-8 "${testcvs} add emptydir" \
"${CPROG} \[add aborted]: cannot add to \`${CVSROOT_DIRNAME}/CVSROOT/Emptydir'"
	  cd ..
	  rm -rf CVS dir2d1

	  # OK, while we have an Emptydir around, test a few obscure
	  # things about it.
	  mkdir edir; cd edir
	  dotest emptydir-9 "${testcvs} -q co -l CVSROOT" \
"U CVSROOT${DOTSTAR}"
	  cd CVSROOT
	  dotest_fail emptydir-10 "test -d Emptydir" ''
	  # This tests the code in find_dirs which skips Emptydir.
	  dotest emptydir-11 "${testcvs} -q -n update -d -P" ''
	  cd ../..
	  rm -r edir
	  cd ..

	  # Now start playing with moda.
	  mkdir 2; cd 2
	  dotest emptydir-12 "${testcvs} -q co 2d1moda" \
"U dir2d1/suba/filea"
	  # OK, this is the crux of the matter.  This used to show "Emptydir",
	  # but everyone seemed to think it should show "moda".  This
	  # usually works better, but not always as shown by the following
	  # test.
	  dotest emptydir-13 "cat dir2d1/CVS/Repository" "moda"
	  dotest_fail emptydir-14 "${testcvs} co comb" \
"${SPROG} checkout: existing repository ${CVSROOT_DIRNAME}/moda/modasub does not match ${CVSROOT_DIRNAME}/mod1
${SPROG} checkout: ignoring module 2d1modb
${SPROG} checkout: Updating dir2d1/suba"
	  dotest emptydir-15 "cat dir2d1/CVS/Repository" "moda"
	  cd ..

	  # Test the effect of a non-cvs directory already existing with the
	  # same name as one in the modules file.
	  mkdir 3; cd 3
	  mkdir dir2d1
	  dotest emptydir-16 "${testcvs} co 2d1mod" \
"${SPROG} checkout: Updating dir2d1/sub/sub2d1
U dir2d1/sub/sub2d1/file1"

	  if $remote; then
	    dotest emptydir-17 "cat dir2d1/CVS/Repository" "CVSROOT/Emptydir"
	  else
	    dotest_fail emptydir-17 "test -d dir2d1/CVS"
	  fi

	  dokeep
	  cd ..
	  rm -r 1 2 3
	  modify_repo rm -rf $CVSROOT_DIRNAME/mod1 $CVSROOT_DIRNAME/moda
	  # I guess for the moment the convention is going to be
	  # that we don't need to remove $CVSROOT_DIRNAME/CVSROOT/Emptydir
	  ;;



	abspath)
	
	  # These tests test the thituations thin thwitch thoo theck
	  # things thout twith thabsolute thaths.  Threally.

	  #
	  # CHECKOUTS
	  #

	  # Create a few modules to use
	  modify_repo mkdir $CVSROOT_DIRNAME/mod1 $CVSROOT_DIRNAME/mod2
	  dotest abspath-1a "${testcvs} co mod1 mod2" \
"${SPROG} checkout: Updating mod1
${SPROG} checkout: Updating mod2"

	  # Populate the module
	  echo "file1" > mod1/file1
	  echo "file2" > mod2/file2
	  cd mod1
	  dotest abspath-1ba "${testcvs} add file1" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: use \`${SPROG} commit' to add this file permanently"
          cd ..
          cd mod2
	  dotest abspath-1bb "${testcvs} add file2" \
"${SPROG} add: scheduling file .file2. for addition
${SPROG} add: use \`${SPROG} commit' to add this file permanently"
          cd ..

	  dotest abspath-1c "${testcvs} ci -m yup mod1 mod2" \
"${CPROG} commit: Examining mod1
${CPROG} commit: Examining mod2
${CVSROOT_DIRNAME}/mod1/file1,v  <--  mod1/file1
initial revision: 1.1
${CVSROOT_DIRNAME}/mod2/file2,v  <--  mod2/file2
initial revision: 1.1"
	  # Finished creating the module -- clean up.
	  rm -rf CVS mod1 mod2
	  # Done.
	  
	  # Try checking out the module in a local directory
	  if $remote; then
	    dotest_fail abspath-2a "${testcvs} co -d ${TESTDIR}/1 mod1" \
"${SPROG} \[checkout aborted\]: absolute pathnames invalid for server (specified .${TESTDIR}/1.)"
	    dotest abspath-2a-try2 "${testcvs} co -d 1 mod1" \
"${SPROG} checkout: Updating 1
U 1/file1"
	  else
	    dotest abspath-2a "${testcvs} co -d ${TESTDIR}/1 mod1" \
"${SPROG} checkout: Updating ${TESTDIR}/1
U ${TESTDIR}/1/file1"
	  fi # remote workaround

	  dotest abspath-2b "cat ${TESTDIR}/1/CVS/Repository" "mod1"

	  # Done.  Clean up.
	  rm -r $TESTDIR/1


	  # Now try in a subdirectory.  We're not covering any more
	  # code here, but we might catch a future error if someone
	  # changes the checkout code.

	  # Since CVS 1.11.14, CVS will create leading directories specified
	  # via co -d.
	  # I am unsure that this wasn't the behavior prior to CVS 1.9, but the
	  # comment that used to be here leads me to believe it was not.
	  if $remote; then :; else
	    dotest abspath-3.1 "$testcvs -q co -d $TESTDIR/1/2 mod1" \
"U $TESTDIR/1/2/file1"
	    rm -r $TESTDIR/1
	  fi
	  dotest abspath-3.2 "$testcvs -q co -d 1/2 mod1" \
"U 1/2/file1"
	  rm -r 1

	  # We don't to mess with an existing directory just to traverse it,
	  # for example by creating a CVS directory, but currently we can't
	  # avoid this in client/server mode.
	  mkdir 1
	  if $remote; then
	    dotest abspath-3ar "$testcvs co -d 1/2 mod1" \
"$SPROG checkout: Updating 1/2
U 1/2/file1"
	    dotest abspath-3br "cat 1/CVS/Repository" .
	  else
	    dotest abspath-3a "$testcvs co -d $TESTDIR/1/2 mod1" \
"$SPROG checkout: Updating $TESTDIR/1/2
U $TESTDIR/1/2/file1"
	    dotest_fail abspath-3b "test -d ${TESTDIR}/1/CVS"
	  fi

	  dotest abspath-3c "cat ${TESTDIR}/1/2/CVS/Repository" mod1


	  # Done.  Clean up.
	  rm -rf ${TESTDIR}/1


	  # Now try someplace where we don't have permission.
	  mkdir ${TESTDIR}/barf
	  chmod -w ${TESTDIR}/barf
	  dotest_fail abspath-4r "${testcvs} co -d ${TESTDIR}/barf/sub mod1" \
"${SPROG} \[checkout aborted\]: cannot make directory sub: Permission denied" \
"${SPROG} \[checkout aborted\]: absolute pathnames invalid for server (specified .${TESTDIR}/barf/sub.)"
	  chmod +w ${TESTDIR}/barf
	  rmdir ${TESTDIR}/barf
	  # Done.  Nothing to clean up.


	  # Try checking out two modules into the same directory.
	  if $remote; then
	    dotest abspath-5ar "${testcvs} co -d 1 mod1 mod2" \
"${SPROG} checkout: Updating 1/mod1
U 1/mod1/file1
${SPROG} checkout: Updating 1/mod2
U 1/mod2/file2"
	  else
	    dotest abspath-5a "${testcvs} co -d ${TESTDIR}/1 mod1 mod2" \
"${SPROG} checkout: Updating ${TESTDIR}/1/mod1
U ${TESTDIR}/1/mod1/file1
${SPROG} checkout: Updating ${TESTDIR}/1/mod2
U ${TESTDIR}/1/mod2/file2"
	  fi # end remote workaround
	  dotest abspath-5b "cat ${TESTDIR}/1/CVS/Repository" "\."
	  dotest abspath-5c "cat ${TESTDIR}/1/mod1/CVS/Repository" "mod1"
	  dotest abspath-5d "cat ${TESTDIR}/1/mod2/CVS/Repository" "mod2"
	  # Done.  Clean up.
	  rm -rf $TESTDIR/1


	  # Try checking out the top-level module.
	  if $remote; then
	    dotest abspath-6ar "$testcvs co -d 1 ." \
"$SPROG checkout: Updating 1
$SPROG checkout: Updating 1/CVSROOT
$DOTSTAR
$SPROG checkout: Updating 1/mod1
U 1/mod1/file1
$SPROG checkout: Updating 1/mod2
U 1/mod2/file2"
	  else
	    dotest abspath-6a "${testcvs} co -d ${TESTDIR}/1 ." \
"${SPROG} checkout: Updating ${TESTDIR}/1
${SPROG} checkout: Updating ${TESTDIR}/1/CVSROOT
${DOTSTAR}
${SPROG} checkout: Updating ${TESTDIR}/1/mod1
U ${TESTDIR}/1/mod1/file1
${SPROG} checkout: Updating ${TESTDIR}/1/mod2
U ${TESTDIR}/1/mod2/file2"
	  fi # end of remote workaround
	  dotest abspath-6b "cat ${TESTDIR}/1/CVS/Repository" "\."
	  dotest abspath-6c "cat ${TESTDIR}/1/CVSROOT/CVS/Repository" "CVSROOT"
	  dotest abspath-6c "cat ${TESTDIR}/1/mod1/CVS/Repository" "mod1"
	  dotest abspath-6d "cat ${TESTDIR}/1/mod2/CVS/Repository" "mod2"
	  # Done.  Clean up.
	  rm -rf ${TESTDIR}/1

	  # Test that an absolute pathname to some other directory
	  # doesn't mess with the current working directory.
	  mkdir 1
	  cd 1
	  if $remote; then
	    dotest_fail abspath-7ar "${testcvs} -q co -d ../2 mod2" \
"${SPROG} checkout: protocol error: .\.\./2. contains more leading \.\.
${SPROG} \[checkout aborted\]: than the 0 which Max-dotdot specified"
	    cd ..
	    dotest abspath-7a-try2r "${testcvs} -q co -d 2 mod2" \
"U 2/file2"
	    cd 1
	  else
	    dotest abspath-7a "${testcvs} -q co -d ${TESTDIR}/2 mod2" \
"U ${TESTDIR}/2/file2"
	  fi # remote workaround
	  dotest abspath-7b "ls" ""
	  dotest abspath-7c "${testcvs} -q co mod1" \
"U mod1/file1"
	  cd mod1
	  if $remote; then
	    cd ../..
	    dotest abspath-7dr "${testcvs} -q co -d 3 mod2" \
"U 3/file2"
	    cd 1/mod1
	  else
	    dotest abspath-7d "${testcvs} -q co -d ${TESTDIR}/3 mod2" \
"U ${TESTDIR}/3/file2"
	  fi # remote workaround
	  dotest abspath-7e "${testcvs} -q update -d"

	  #
	  # FIXME: do other functions here (e.g. update /tmp/foo)
	  #

	  # Finished with all tests.  Cleanup.
	  dokeep
	  cd ../..
	  rm -r 1 2 3
	  modify_repo rm -rf $CVSROOT_DIRNAME/mod1 $CVSROOT_DIRNAME/mod2
	  ;;



	abspath2)
	  # More absolute path checks.  The following used to attempt to create
	  # directories in /:
	  #
	  # $ cvs -d:fork:/cvsroot co /foo
	  # cvs checkout: warning: cannot make directory CVS in /: Permission denied
	  # cvs [checkout aborted]: cannot make directory /foo: Permission denied
	  # $
	  #
	  # The -z9 in this test also checks for an old server bug where the
	  # server would block indefinitely attempting to read an EOF from the
	  # client in the compression buffer shutdown routine.
	  dotest_fail abspath2-1 "$testcvs -z9 co /foo" \
"$CPROG \[checkout aborted\]: Absolute module reference invalid: \`/foo'" \
"$SPROG \[server aborted\]: Absolute module reference invalid: \`/foo'
$CPROG \[checkout aborted\]: end of file from server (consult above messages if any)"
	  ;;



	toplevel)
	  # test the feature that cvs creates a CVS subdir also for
	  # the toplevel directory

	  # First set the TopLevelAdmin setting.
	  mkdir 1; cd 1
	  dotest toplevel-1a "${testcvs} -q co CVSROOT/config" \
"U CVSROOT/config"
	  cd CVSROOT
	  echo "TopLevelAdmin=yes" >>config
	  dotest toplevel-1b "${testcvs} -q ci -m yes-top-level" \
"$CVSROOT_DIRNAME/CVSROOT/config,v  <--  config
new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
$SPROG commit: Rebuilding administrative file database"
	  cd ../..
	  rm -r 1

	  mkdir 1; cd 1
	  dotest toplevel-1 "${testcvs} -q co -l ." ''
	  mkdir top-dir second-dir
	  dotest toplevel-2 "${testcvs} add top-dir second-dir" \
"Directory ${CVSROOT_DIRNAME}/top-dir added to the repository
Directory ${CVSROOT_DIRNAME}/second-dir added to the repository"
	  cd top-dir

	  touch file1
	  dotest toplevel-3 "${testcvs} add file1" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest toplevel-4 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/top-dir/file1,v  <--  file1
initial revision: 1\.1"
	  cd ..

	  cd second-dir
	  touch file2
	  dotest toplevel-3s "${testcvs} add file2" \
"${SPROG} add: scheduling file .file2. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest toplevel-4s "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/second-dir/file2,v  <--  file2
initial revision: 1\.1"

	  cd ../..
	  rm -r 1; mkdir 1; cd 1
	  dotest toplevel-5 "${testcvs} co top-dir" \
"${SPROG} checkout: Updating top-dir
U top-dir/file1"

	  dotest toplevel-6 "${testcvs} update top-dir" \
"${SPROG} update: Updating top-dir"
	  dotest toplevel-7 "${testcvs} update"  \
"${SPROG} update: Updating \.
${SPROG} update: Updating top-dir"

	  dotest toplevel-8 "${testcvs} update -d top-dir" \
"${SPROG} update: Updating top-dir"
	  # There is some sentiment that
	  #   "${SPROG} update: Updating \.
          #   ${SPROG} update: Updating top-dir"
	  # is correct but it isn't clear why that would be correct instead
	  # of the remote CVS behavior (which also updates CVSROOT).
	  #
	  # The DOTSTAR matches of a bunch of lines like
	  # "U CVSROOT/checkoutlist".  Trying to match them more precisely
	  # seemed to cause trouble.  For example CVSROOT/cvsignore will
	  # be present or absent depending on whether we ran the "ignore"
	  # test or not.
	  dotest toplevel-9 "${testcvs} update -d" \
"${SPROG} update: Updating \.
${SPROG} update: Updating CVSROOT
${DOTSTAR}
${SPROG} update: Updating top-dir"

	  cd ..
	  rm -r 1; mkdir 1; cd 1
	  dotest toplevel-10 "${testcvs} co top-dir" \
"${SPROG} checkout: Updating top-dir
U top-dir/file1"

	  # This tests more or less the same thing, in a particularly
	  # "real life" example.
	  dotest toplevel-11 "${testcvs} -q update -d second-dir" \
"U second-dir/file2"

	  # Now remove the CVS directory (people may do this manually,
	  # especially if they formed their habits with CVS
	  # 1.9 and older, which didn't create it.  Or perhaps the working
	  # directory itself was created with 1.9 or older).
	  rm -r CVS
	  # Now set the permissions so we can't recreate it.
	  if test -n "$remotehost"; then
	    # Cygwin again.
	    $CVS_RSH $remotehost "chmod -w $TESTDIR/1"
	  else
	    chmod -w ../1
	  fi
	  # Now see whether CVS has trouble because it can't create CVS.
	  # First string is for local, second is for remote.
	  dotest toplevel-12 "${testcvs} co top-dir" \
"${SPROG} checkout: warning: cannot make directory CVS in \.: Permission denied
${SPROG} checkout: Updating top-dir" \
"${CPROG} checkout: warning: cannot make directory CVS in \.: Permission denied
${CPROG} checkout: in directory \.:
${CPROG} checkout: cannot open CVS/Entries for reading: No such file or directory
${SPROG} checkout: Updating top-dir"

	  chmod +w ../1

	  dokeep
	  restore_adm
	  cd ..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/top-dir \
			     $CVSROOT_DIRNAME/second-dir
	  ;;



	toplevel2)
	  # Similar to toplevel, but test the case where TopLevelAdmin=no.

	  # First set the TopLevelAdmin setting.
	  mkdir 1; cd 1
	  dotest toplevel2-1a "${testcvs} -q co CVSROOT/config" \
"U CVSROOT/config"
	  cd CVSROOT
	  echo "TopLevelAdmin=no" >>config
	  dotest toplevel2-1b "$testcvs -q ci -m no-top-level" \
"$CVSROOT_DIRNAME/CVSROOT/config,v  <--  config
new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
$SPROG commit: Rebuilding administrative file database"
	  cd ../..
	  rm -r 1

	  # Now set up some directories and subdirectories
	  mkdir 1; cd 1
	  dotest toplevel2-1 "${testcvs} -q co -l ." ''
	  mkdir top-dir second-dir
	  dotest toplevel2-2 "${testcvs} add top-dir second-dir" \
"Directory ${CVSROOT_DIRNAME}/top-dir added to the repository
Directory ${CVSROOT_DIRNAME}/second-dir added to the repository"
	  cd top-dir

	  touch file1
	  dotest toplevel2-3 "${testcvs} add file1" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest toplevel2-4 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/top-dir/file1,v  <--  file1
initial revision: 1\.1"
	  cd ..

	  cd second-dir
	  touch file2
	  dotest toplevel2-3s "${testcvs} add file2" \
"${SPROG} add: scheduling file .file2. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest toplevel2-4s "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/second-dir/file2,v  <--  file2
initial revision: 1\.1"

	  cd ../..
	  rm -r 1; mkdir 1; cd 1
	  dotest toplevel2-5 "${testcvs} co top-dir" \
"${SPROG} checkout: Updating top-dir
U top-dir/file1"

	  dotest toplevel2-6 "${testcvs} update top-dir" \
"${SPROG} update: Updating top-dir"
	  dotest toplevel2-7 "${testcvs} update"  \
"${SPROG} update: Updating top-dir"

	  dotest toplevel2-8 "${testcvs} update -d top-dir" \
"${SPROG} update: Updating top-dir"
	  # Contrast this with toplevel-9, which has TopLevelAdmin=yes.
	  dotest toplevel2-9 "${testcvs} update -d" \
"${SPROG} update: Updating top-dir"

	  cd ..
	  rm -r 1; mkdir 1; cd 1
	  dotest toplevel2-10 "${testcvs} co top-dir" \
"${SPROG} checkout: Updating top-dir
U top-dir/file1"
	  # This tests more or less the same thing, in a particularly
	  # "real life" example.  With TopLevelAdmin=yes, this command
	  # would give us second-dir and CVSROOT directories too.
	  dotest toplevel2-11 "${testcvs} -q update -d" ""

	  dokeep
	  cd ..
	  restore_adm
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/top-dir \
			     $CVSROOT_DIRNAME/second-dir
	  ;;



	rstar-toplevel)
	  # This test used to confirm a bug that existed in the r* commands
	  # run against the top-level project prior to CVS 1.11.18 & 1.12.10.
	  #
	  # The assertion failure was something like:
	  # do_recursion: Assertion \`strstr (repository, \"/\./\") == ((void \*)0)' failed\..*"
	  dotest rstar-toplevel-1 "$testcvs -q rlog ." \
"
RCS file: $CVSROOT_DIRNAME/CVSROOT$DOTSTAR"

	  dokeep
	;;



	trailingslashes)
	  # Some tests of CVS's reactions to path specifications containing
	  # trailing slashes.
	  mkdir trailingslashes; cd trailingslashes
	  dotest trailingslashes-init-1 "$testcvs -Q co -ldt ."
	  dotest trailingslashes-init-2 "$testcvs -Q co -dt2 ."
	  cd t
	  echo "Ahh'll be baaack." >topfile
	  dotest trailingslashes-init-3 "$testcvs -Q add topfile"
	  dotest trailingslashes-init-4 "$testcvs -Q ci -mto-top"

	  # First, demonstrate the usual case.
	  cd ../t2
	  dotest trailingslashes-1 "$testcvs -q up CVSROOT"
	  dotest_fail trailingslashes-1a "test -f topfile"

	  # FIXCVS:
	  # Now the one that fails in remote mode.
	  # This highlights one of the failure cases mentioned in TODO item
	  # #205.
	  if $remote; then
		  dotest trailingslashes-2 "$testcvs -q up CVSROOT/" \
"U topfile"
		  dotest trailingslashes-2a "test -f topfile"
	  else
		  dotest trailingslashes-2 "$testcvs -q up CVSROOT/"
		  dotest_fail trailingslashes-2a "test -f topfile"
	  fi

	  dokeep
	  cd ../..
	  rm -rf trailingslashes
	  modify_repo rm -rf $CVSROOT_DIRNAME/topfile,v
	  ;;



        checkout_repository)
          dotest_fail checkout_repository-1 \
"${testcvs} co -d ${CVSROOT_DIRNAME} CVSROOT" \
"${CPROG} \[checkout aborted\]: Cannot check out files into the repository itself" \
"${SPROG} \[checkout aborted\]: absolute pathnames invalid for server (specified \`${CVSROOT_DIRNAME}')"

	  # The behavior of the client/server test below should be correct.
	  # The CVS client currently has no way of knowing that the client and
	  # server are the same machine and thus skips the $CVSROOT checks.
	  # I think checking for this case in CVS would be bloat since this
	  # should be a fairly rare occurance.
	  cd ${CVSROOT_DIRNAME}
          dotest_fail checkout_repository-2 "${testcvs} co CVSROOT" \
"${CPROG} \[checkout aborted\]: Cannot check out files into the repository itself" \
"${SPROG} checkout: Updating CVSROOT
${CPROG} checkout: move away \`CVSROOT/checkoutlist'; it is in the way
C CVSROOT/checkoutlist
${CPROG} checkout: move away \`CVSROOT/commitinfo'; it is in the way
C CVSROOT/commitinfo
${CPROG} checkout: move away \`CVSROOT/config'; it is in the way
C CVSROOT/config
${CPROG} checkout: move away \`CVSROOT/cvswrappers'; it is in the way
C CVSROOT/cvswrappers
${CPROG} checkout: move away \`CVSROOT/loginfo'; it is in the way
C CVSROOT/loginfo
${CPROG} checkout: move away \`CVSROOT/modules'; it is in the way
C CVSROOT/modules
${CPROG} checkout: move away \`CVSROOT/notify'; it is in the way
C CVSROOT/notify
${CPROG} checkout: move away \`CVSROOT/postadmin'; it is in the way
C CVSROOT/postadmin
${CPROG} checkout: move away \`CVSROOT/postproxy'; it is in the way
C CVSROOT/postproxy
${CPROG} checkout: move away \`CVSROOT/posttag'; it is in the way
C CVSROOT/posttag
${CPROG} checkout: move away \`CVSROOT/postwatch'; it is in the way
C CVSROOT/postwatch
${CPROG} checkout: move away \`CVSROOT/preproxy'; it is in the way
C CVSROOT/preproxy
${CPROG} checkout: move away \`CVSROOT/rcsinfo'; it is in the way
C CVSROOT/rcsinfo
${CPROG} checkout: move away \`CVSROOT/taginfo'; it is in the way
C CVSROOT/taginfo
${CPROG} checkout: move away \`CVSROOT/verifymsg'; it is in the way
C CVSROOT/verifymsg"

          dotest checkout_repository-3 \
"${testcvs} co -p CVSROOT/modules >/dev/null" \
"===================================================================
Checking out CVSROOT/modules
RCS:  ${CVSROOT_DIRNAME}/CVSROOT/modules,v
VERS: 1\.[0-9]*
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*"

	  dokeep
	  cd $TESTDIR
          ;;



	mflag)
	  for message in '' ' ' '	
           ' '    	  	test' ; do
	    # Set up
	    mkdir a-dir; cd a-dir
	    # Test handling of -m during import
	    echo testa >>test
	    if ${testcvs} import -m "$message" a-dir A A1 >>${LOGFILE} 2>&1;then
	        pass 156
	    else
		fail 156
	    fi
	    # Must import twice since the first time uses inline code that
	    # avoids RCS call.
	    echo testb >>test
	    if ${testcvs} import -m "$message" a-dir A A2 >>${LOGFILE} 2>&1;then
		pass 157
	    else
		fail 157
	    fi
	    # Test handling of -m during ci
	    cd ..; rm -r a-dir
	    if ${testcvs} co a-dir >>${LOGFILE} 2>&1; then
		pass 158
	    else
		fail 158
	    fi
	    cd a-dir
	    echo testc >>test
	    if ${testcvs} ci -m "$message" >>${LOGFILE} 2>&1; then
		pass 159
	    else
		fail 159
	    fi
	    # Test handling of -m during rm/ci
	    rm test;
	    if ${testcvs} rm test >>${LOGFILE} 2>&1; then
		pass 160
	    else
		fail 160
	    fi
	    if ${testcvs} ci -m "$message" >>${LOGFILE} 2>&1; then
		pass 161
	    else
		fail 161
	    fi

	    dokeep
	    # Clean up
	    cd ..
	    rm -r a-dir
	    modify_repo rm -rf $CVSROOT_DIRNAME/a-dir
	  done
	  ;;



	editor)
	  # More tests of log messages, in this case the ability to
	  # run an external editor.
	  # TODO:
	  #   * also test $EDITOR, $CVSEDITOR, &c.
	  #   * test what happens if up-to-date check fails.

	  # Our "editor" puts "x" at the start of each line, so we
	  # can see the "CVS:" lines.
	  cat >${TESTDIR}/editme <<EOF
#!${TESTSHELL}
sleep 1
sed <\$1 -e 's/^/x/' >${TESTDIR}/edit.new
mv ${TESTDIR}/edit.new \$1
exit 0
EOF
	  chmod +x ${TESTDIR}/editme

	  mkdir 1; cd 1
	  dotest editor-1 "${testcvs} -q co -l ." ''
	  mkdir first-dir
	  dotest editor-2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
	  cd first-dir
	  touch file1 file2
	  dotest editor-3 "${testcvs} add file1 file2" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: scheduling file .file2. for addition
${SPROG} add: use .${SPROG} commit. to add these files permanently"
	  dotest editor-4 "${testcvs} -e ${TESTDIR}/editme -q ci" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
initial revision: 1\.1"
	  dotest editor-5 "${testcvs} -q tag -b br" "T file1
T file2"
	  dotest editor-6 "${testcvs} -q update -r br" ''
	  echo modify >>file1
	  dotest editor-7 "${testcvs} -e ${TESTDIR}/editme -q ci" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.1\.2\.1; previous revision: 1\.1"
	  # OK, now we want to make sure "ci -r" puts in the branch
	  # where appropriate.  Note that we can check in on the branch
	  # without being on the branch, because there is not a revision
	  # already on the branch.  If there were a revision on the branch,
	  # CVS would correctly give an up-to-date check failed.
	  dotest editor-8 "${testcvs} -q update -A" "U file1"
	  echo add a line >>file2
	  dotest editor-9 "${testcvs} -q -e ${TESTDIR}/editme ci -rbr file2" \
"$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
new revision: 1\.1\.2\.1; previous revision: 1\.1"

	  dotest editor-log-file1 "${testcvs} log -N file1" "
RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
Working file: file1
head: 1\.1
branch:
locks: strict
access list:
keyword substitution: kv
total revisions: 2;	selected revisions: 2
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
branches:  1\.1\.2;
xCVS: ----------------------------------------------------------------------
xCVS: Enter Log.  Lines beginning with .CVS:. are removed automatically
xCVS:
xCVS: Committing in .
xCVS:
xCVS: Added Files:
xCVS: 	file1 file2
xCVS: ----------------------------------------------------------------------
----------------------------
revision 1\.1\.2\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  commitid: ${commitid};
xCVS: ----------------------------------------------------------------------
xCVS: Enter Log.  Lines beginning with .CVS:. are removed automatically
xCVS:
xCVS: Committing in .
xCVS:
xCVS: Modified Files:
xCVS:  Tag: br
xCVS: 	file1
xCVS: ----------------------------------------------------------------------
============================================================================="

	  # The only difference between the two expect strings is the
	  # presence or absence of "Committing in ." for 1.1.2.1.
	  dotest editor-log-file2 "${testcvs} log -N file2" "
RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
Working file: file2
head: 1\.1
branch:
locks: strict
access list:
keyword substitution: kv
total revisions: 2;	selected revisions: 2
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
branches:  1\.1\.2;
xCVS: ----------------------------------------------------------------------
xCVS: Enter Log.  Lines beginning with .CVS:. are removed automatically
xCVS:
xCVS: Committing in .
xCVS:
xCVS: Added Files:
xCVS: 	file1 file2
xCVS: ----------------------------------------------------------------------
----------------------------
revision 1\.1\.2\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  commitid: ${commitid};
xCVS: ----------------------------------------------------------------------
xCVS: Enter Log.  Lines beginning with .CVS:. are removed automatically
xCVS:
xCVS: Modified Files:
xCVS:  Tag: br
xCVS: 	file2
xCVS: ----------------------------------------------------------------------
=============================================================================" "
RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
Working file: file2
head: 1\.1
branch:
locks: strict
access list:
keyword substitution: kv
total revisions: 2;	selected revisions: 2
description:
----------------------------
revision 1\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: ${commitid};
branches:  1\.1\.2;
xCVS: ----------------------------------------------------------------------
xCVS: Enter Log.  Lines beginning with .CVS:. are removed automatically
xCVS:
xCVS: Committing in .
xCVS:
xCVS: Added Files:
xCVS: 	file1 file2
xCVS: ----------------------------------------------------------------------
----------------------------
revision 1\.1\.2\.1
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  commitid: ${commitid};
xCVS: ----------------------------------------------------------------------
xCVS: Enter Log.  Lines beginning with .CVS:. are removed automatically
xCVS:
xCVS: Committing in .
xCVS:
xCVS: Modified Files:
xCVS:  Tag: br
xCVS: 	file2
xCVS: ----------------------------------------------------------------------
============================================================================="

	  # Test CVS's response to an unchanged log message
	  cat >${TESTDIR}/editme <<EOF
#!${TESTSHELL}
sleep 1
exit 0
EOF
	  chmod +x ${TESTDIR}/editme
	  dotest_fail editor-emptylog-1 "echo a |${testcvs} -e ${TESTDIR}/editme ci -f file1" \
"
Log message unchanged or not specified
a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs
Action: (continue) ${CPROG} \[commit aborted\]: aborted by user"

	  # Test CVS's response to an empty log message
	  cat >${TESTDIR}/editme <<EOF
#!${TESTSHELL}
sleep 1
cat /dev/null >\$1
exit 0
EOF
	  chmod +x ${TESTDIR}/editme
	  dotest_fail editor-emptylog-1a "echo a |${testcvs} -e ${TESTDIR}/editme ci -f file1" \
"
Log message unchanged or not specified
a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs
Action: (continue) ${CPROG} \[commit aborted\]: aborted by user"

	  # Test CVS's response to a log message with one blank line
	  cat >${TESTDIR}/editme <<EOF
#!${TESTSHELL}
sleep 1
echo >\$1
exit 0
EOF
	  chmod +x ${TESTDIR}/editme
	  dotest_fail editor-emptylog-1b "echo a |${testcvs} -e ${TESTDIR}/editme ci -f file1" \
"
Log message unchanged or not specified
a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs
Action: (continue) ${CPROG} \[commit aborted\]: aborted by user"

	  # Test CVS's response to a log message with only comments
	  cat >${TESTDIR}/editme <<EOF
#!${TESTSHELL}
sleep 1
cat \$1 >${TESTDIR}/edit.new
mv ${TESTDIR}/edit.new \$1
exit 0
EOF
	  chmod +x ${TESTDIR}/editme
	  dotest_fail editor-emptylog-1c "echo a |${testcvs} -e ${TESTDIR}/editme ci -f file1" \
"
Log message unchanged or not specified
a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs
Action: (continue) ${CPROG} \[commit aborted\]: aborted by user"

	  # Test CVS's response to a log message that is zero bytes
	  # in length. This caused core dumps in cvs 1.11.5 on Solaris
	  # hosts.
	  cd ..
	  dotest editor-emptylog-continue-1 "${testcvs} -q co CVSROOT/loginfo" \
"U CVSROOT/loginfo"

          cd CVSROOT
	  cat <<\EOF >>loginfo
DEFAULT (echo Start-Log;cat;echo End-Log) >> $CVSROOT/CVSROOT/commitlog
EOF
	  dotest editor-emptylog-continue-2 "$testcvs -Q ci -mloggem"

	  cd ../first-dir
	  cat >${TESTDIR}/editme <<EOF
#!${TESTSHELL}
sleep 1
cp /dev/null \$1
exit 1
EOF
	  chmod +x ${TESTDIR}/editme
	  dotest editor-emptylog-continue-3 "echo c |${testcvs} -e ${TESTDIR}/editme ci -f file1" \
"${CPROG} commit: warning: editor session failed

Log message unchanged or not specified
a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs
Action: (continue) ${CVSROOT_DIRNAME}/first-dir/file1,v  <--  file1
new revision: 1\.2; previous revision: 1\.1"
	  # The loginfo Log message should be an empty line and not "(null)"
	  # which is what some fprintf() implementations do with "%s"
	  # format and a NULL pointer...
	  if $remote; then
	    dotest editor-emptylog-continue-4r \
"cat $CVSROOT_DIRNAME/CVSROOT/commitlog" \
"Start-Log
Update of $CVSROOT_DIRNAME/CVSROOT
In directory $hostname:$TMPDIR/cvs-serv[0-9a-z]*

Modified Files:
	loginfo 
Log Message:
loggem
End-Log
Start-Log
Update of $CVSROOT_DIRNAME/first-dir
In directory $hostname:$TMPDIR/cvs-serv[0-9a-z]*

Modified Files:
	file1 
Log Message:

End-Log"
          else
	    dotest editor-emptylog-continue-4 \
"cat $CVSROOT_DIRNAME/CVSROOT/commitlog" \
"Start-Log
Update of $CVSROOT_DIRNAME/CVSROOT
In directory $hostname:$TESTDIR/1/CVSROOT

Modified Files:
	loginfo 
Log Message:
loggem
End-Log
Start-Log
Update of $CVSROOT_DIRNAME/first-dir
In directory $hostname:$TESTDIR/1/first-dir

Modified Files:
	file1 
Log Message:

End-Log"
         fi
	  # There should have an empty log message at this point
	  dotest editor-emptylog-continue-5 "${testcvs} log -N -r1.2 file1" \
"
RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
Working file: file1
head: 1\.2
branch:
locks: strict
access list:
keyword substitution: kv
total revisions: 3;	selected revisions: 1
description:
----------------------------
revision 1\.2
date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: +0 -0;  commitid: ${commitid};
\*\*\* empty log message \*\*\*
============================================================================="

	  # clean up
	  dokeep
	  # restore the default loginfo script
	  restore_adm
	  cd ../..
	  rm -r 1
	  rm $TESTDIR/editme
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	env)
	  # Test to see if the CVS_PID environment variable is being set
	  mkdir ${TESTDIR}/env
	  cd ${TESTDIR}/env
	  dotest env-1 "${testcvs} -Q co . >>${LOGFILE}" ''

	  cat > ${TESTDIR}/env/test-cvs-pid <<EOF
#!${TESTSHELL}
if test "x\$CVS_PID" != "x"; then
  # In local mode, there is no directory with the pid in it for use.
  # In remote mode the CVS_PID will be the parent process of the
  # cvs process that runs the commitinfo script.
  if test "x$remote" = "x:" ; then
    ppid=\`pwd | sed -e 's,.*/cvs-serv,,'\`
  else
    # This assumes that the -l switch puts PPID in the banner and does
    # not run the elements together such that whitespace surrounds the
    # pid and ppid in the output. This could be made slightly simpler
    # if all hosts had a 'ps' command that supported the -p switch,
    # but Solaris 7 /usr/ucb/ps does not and that may be the one we use.
    # It is because this is so messy that the CVS_PID feature exists.
    pid=\$\$
    pidcmd="ps -o pid,ppid -p \$pid || ps -el || ps -al"
    if echo \$pidcmd | sh >pid.stdout 2> pid.stderr; then
      ppid=\`cat pid.stdout |\\
      awk '/PPID/ { for (i=1; i <= NF; i++) {
                      if (\$i == "PPID") ppidx = i; 
                      if (\$i == "PID") pidx = i;
		    }
                    next; 
                  }
                  { print \$pidx " " \$ppidx }' |\\
      grep "^\$pid " |\\
      awk '{ print \$NF }'\`
    else
      ppid=unkown
    fi
  fi
  if test "x\$ppid" = "x\${CVS_PID}"; then
    # The PID looks okay to me
    # Clean up any temporary files
    rm -f pid.stdout pid.stderr
    exit 0
  else
    echo The environment variable CVS_PID is not properly set.
    echo It should have been set to \'\$ppid\' but instead was \'\$CVS_PID\'
    echo It is possible that this test is broken for your host.
    echo Current pid: \$pid
    [ -n "\$pidcmd" ] && echo "Command: \$pidcmd"
    [ -s pid.stdout ] && echo Standard Out: && cat pid.stdout
    [ -s pid.stderr ] && echo Standard Error: && cat pid.stderr
    exit 1
  fi
else
  echo The environment variable CVS_PID is not set.
  exit 1
fi
EOF
	  if test -n "$remotehost"; then
	    $CVS_RSH $remotehost "chmod +x ${TESTDIR}/env/test-cvs-pid"
	  else
	    chmod +x ${TESTDIR}/env/test-cvs-pid
	  fi
	  cd CVSROOT
	  echo "^env ${TESTDIR}/env/test-cvs-pid %r/%p %s" >>commitinfo
	  dotest env-2 "${testcvs} -q ci -m test-pid commitinfo" \
"${CVSROOT_DIRNAME}/CVSROOT/commitinfo,v  <--  commitinfo
new revision: 1\.2; previous revision: 1\.1
${SPROG} commit: Rebuilding administrative file database"
	  cd ..
	  mkdir env
	  dotest env-3 "${testcvs} -q add env" \
"Directory ${CVSROOT_DIRNAME}/env added to the repository"
	  cd env
	  echo testing >file1
	  dotest env-4 "${testcvs} add file1" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest env-5 "${testcvs} -q commit -m test-pid" \
"${CVSROOT_DIRNAME}/env/file1,v  <--  file1
initial revision: 1\.1"

	  dokeep
	  # undo commitinfo changes
	  restore_adm
	  cd ../..
	  rm -fr $TESTDIR/env
	  modify_repo rm -rf $CVSROOT_DIRNAME/env
	  ;;



	errmsg1)
	  modify_repo mkdir $CVSROOT_DIRNAME/1dir
	  mkdir 1
	  cd 1
	  dotest errmsg1-init-1 "$testcvs -Q co 1dir"
	  cd 1dir
	  touch foo
	  dotest errmsg-init-2 "$testcvs -Q add foo"
	  if ${testcvs} ci -m added >>${LOGFILE} 2>&1; then
	      pass 164
	  else
	      fail 164
	  fi
	  cd ../..
	  mkdir 2
	  cd 2
	  if ${testcvs} -q co 1dir >>${LOGFILE}; then
	      pass 165
	  else
	      fail 165
	  fi
	  chmod a-w 1dir
	  cd ../1/1dir
	  rm foo;
	  if ${testcvs} rm foo >>${LOGFILE} 2>&1; then
	      pass 166
	  else
	      fail 166
	  fi
	  if ${testcvs} ci -m removed >>${LOGFILE} 2>&1; then
	      pass 167
	  else
	      fail 167
	  fi

	  cd ../../2/1dir
	  # The second case in the local and remote versions of errmsg1-168
	  # below happens on Cygwin under Windows, where write privileges
	  # aren't enforced properly.
	  if $remote; then
	    dotest errmsg1-168r "${testcvs} -q update" \
"${SPROG} update: \`foo' is no longer in the repository
$CPROG update: unable to remove \./foo: Permission denied" \
"${SPROG} update: \`foo' is no longer in the repository"
	  else
	    dotest errmsg1-168 "${testcvs} -q update" \
"${SPROG} update: \`foo' is no longer in the repository
${SPROG} update: unable to remove foo: Permission denied" \
"${SPROG} update: \`foo' is no longer in the repository"
	  fi

	  dokeep
	  cd ..
	  chmod u+w 1dir
	  cd ..
	  rm -r 1 2
	  modify_repo rm -rf $CVSROOT_DIRNAME/1dir
	  ;;



	errmsg2)
	  # More tests of various miscellaneous error handling,
	  # and cvs add behavior in general.
	  # See also test basicb-4a, concerning "cvs ci CVS".
	  # Too many tests to mention test the simple cases of
	  # adding files and directories.
	  # Test basicb-2a10 tests cvs -n add.

	  # First the usual setup; create a directory first-dir.
	  mkdir 1; cd 1
	  dotest errmsg2-1 "$testcvs -q co -l ."
	  mkdir first-dir
	  dotest errmsg2-2 "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
          cd first-dir
	  dotest_fail errmsg2-3 "${testcvs} add CVS" \
"${CPROG} add: cannot add special file .CVS.; skipping"
	  touch file1
	  # For the most part add returns a failure exitstatus if
	  # there are any errors, even if the remaining files are
	  # processed without incident.  The "cannot add
	  # special file" message fits this pattern, at
	  # least currently.
	  dotest_fail errmsg2-4 "${testcvs} add CVS file1" \
"${CPROG} add: cannot add special file .CVS.; skipping
${SPROG} add: scheduling file .file1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  # I'm not sure these tests completely convey the various strange
	  # behaviors that CVS had before it specially checked for "." and
	  # "..".  Suffice it to say that these are unlikely to work right
	  # without a special case.
	  dotest_fail errmsg2-5 "${testcvs} add ." \
"${CPROG} add: cannot add special file .\..; skipping"
	  dotest_fail errmsg2-6 "${testcvs} add .." \
"${CPROG} add: cannot add special file .\.\..; skipping"
	  # Make sure that none of the error messages left droppings
	  # which interfere with normal operation.
	  dotest errmsg2-7 "${testcvs} -q ci -m add-file1" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1"
	  mkdir sdir
	  cd ..
	  dotest errmsg2-8 "${testcvs} add first-dir/sdir" \
"Directory ${CVSROOT_DIRNAME}/first-dir/sdir added to the repository"
	  # while we're here... check commit with no CVS directory
	  dotest_fail errmsg2-8a "${testcvs} -q ci first-dir nonexistant" \
"${CPROG} commit: nothing known about .nonexistant'
${CPROG} \[commit aborted\]: correct above errors first!"
	  dotest_fail errmsg2-8b "$testcvs -q ci nonexistant first-dir" \
"$CPROG commit: nothing known about .nonexistant'
$CPROG \[commit aborted\]: correct above errors first!"
	  dotest errmsg2-8c "$testcvs -q ci first-dir"

	  cd first-dir

	  touch file10
	  mkdir sdir10
	  dotest errmsg2-10 "${testcvs} add file10 sdir10" \
"${SPROG} add: scheduling file .file10. for addition
Directory ${CVSROOT_DIRNAME}/first-dir/sdir10 added to the repository
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest errmsg2-11 "${testcvs} -q ci -m add-file10" \
"$CVSROOT_DIRNAME/first-dir/file10,v  <--  file10
initial revision: 1\.1"
	  # Try to see that there are no droppings left by
	  # any of the previous tests.
	  dotest errmsg2-12 "${testcvs} -q update" ""

	  # Now test adding files with '/' in the name, both one level
	  # down and more than one level down.
	  cd ..
	  mkdir first-dir/sdir10/ssdir
	  dotest errmsg2-13 "${testcvs} add first-dir/sdir10/ssdir" \
"Directory ${CVSROOT_DIRNAME}/first-dir/sdir10/ssdir added to the repository"

	  touch first-dir/sdir10/ssdir/ssfile
	  dotest errmsg2-14 \
	    "${testcvs} add first-dir/sdir10/ssdir/ssfile" \
"${SPROG} add: scheduling file .first-dir/sdir10/ssdir/ssfile. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  touch first-dir/file15
	  dotest errmsg2-15 "${testcvs} add first-dir/file15" \
"${SPROG} add: scheduling file .first-dir/file15. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"

	  # Now the case where we try to give it a directory which is not
	  # under CVS control.
	  mkdir bogus-dir
	  touch bogus-dir/file16
	  # FIXCVS: The first message, from local CVS, is nice.  The second one
	  # is not nice; would be good to fix remote CVS to give a clearer
	  # message (e.g. the one from local CVS).  But at least it is an
	  # error message.
	  dotest_fail errmsg2-16 "${testcvs} add bogus-dir/file16" \
"${SPROG} add: in directory \`bogus-dir':
${SPROG} \[add aborted\]: there is no version here; do .${SPROG} checkout. first" \
"${CPROG} add: cannot open CVS/Entries for reading: No such file or directory
${CPROG} \[add aborted\]: no repository"
	  rm -r bogus-dir

	  # One error condition we don't test for is trying to add a file
	  # or directory which already is there.

	  dotest errmsg2-17 "${testcvs} -q ci -m checkin" \
"$CVSROOT_DIRNAME/first-dir/file15,v  <--  first-dir/file15
initial revision: 1\.1
$CVSROOT_DIRNAME/first-dir/sdir10/ssdir/ssfile,v  <--  first-dir/sdir10/ssdir/ssfile
initial revision: 1\.1"
	  dotest errmsg2-18 "${testcvs} -Q tag test" ''

	  # trying to import the repository

	  if $remote; then :; else
	    cd ${CVSROOT_DIRNAME}
	    dotest_fail errmsg2-20 "${testcvs} import -mtest . A B" \
"${SPROG} \[import aborted\]: attempt to import the repository"
	    dotest_fail errmsg2-21 "${testcvs} import -mtest first-dir A B" \
"${SPROG} \[import aborted\]: attempt to import the repository"
	  fi

	  dokeep
	  cd ..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	errmsg3)
	  # Test the *PANIC* message caused by missing administration files
	  mkdir errmsg3
	  cd errmsg3
	  mkdir CVS
	  dotest_fail errmsg3-1 "${testcvs} -q up" \
"${CPROG} update: in directory \`.':
${CPROG} update: CVS directory found without administrative files\.
${CPROG} update: Use CVS to create the CVS directory, or rename the
${CPROG} update: directory if it is intended to store something
${CPROG} update: besides CVS administrative files\.
${CPROG} \[update aborted\]: \*PANIC\* administration files missing!"

	  dokeep
	  cd ..
	  rm -r errmsg3
	  ;;



	close-stdout)
	  # Ensure that cvs update -p FILE > /dev/full fails
	  # Perform this test IFF /dev/full is a writable character device.
	  if test -w /dev/full && test -c /dev/full; then
	    mkdir close-stdout
	    cd close-stdout
	    echo a > file
	    dotest close-stdout-1 "$testcvs -Q import -m. closeout X Y" ''
	    dotest close-stdout-2 "$testcvs -Q co closeout" ''
	    # Match either a bare `write error' or
	    # `write error: No space left on device',
	    # since closeout.c can produce both.
	    dotest_fail close-stdout-3 \
		"${testcvs} -Q update -p closeout/file > /dev/full" \
		"${CPROG} \[update aborted\]: write error.*"

	    dokeep
	    cd ..
	    rm -r close-stdout
	    modify_repo rm -rf $CVSROOT_DIRNAME/closeout
	  else
	    skip close-stdout '/dev/full is not available'
	  fi
	  ;;



	debug-log-nonfatal)
	  # Once upon a time, failure to create the debug log could be fatal.
          if $remote; then :; else
            remoteonly debug-log-nonfatal
	    continue
	  fi

	  mkdir $TESTDIR/unwritable
	  chmod a-w $TESTDIR/unwritable
	  if test -n "$CVS_CLIENT_LOG"; then
              save_CVS_CLIENT_LOG=$CVS_CLIENT_LOG
	  fi
	  CVS_CLIENT_LOG=$TESTDIR/unwritable/cvsclientlog
	  export CVS_CLIENT_LOG

	  dotest debug-log-nonfatal-1 \
"$testcvs -Q co -p CVSROOT/config >/dev/null" \
"$CPROG checkout: opening to-server logfile $TESTDIR/unwritable/cvsclientlog.in: Permission denied
$CPROG checkout: opening from-server logfile $TESTDIR/unwritable/cvsclientlog.out: Permission denied"

	  dokeep
	  rm -rf $TESTDIR/unwritable
	  unset CVS_CLIENT_LOG
	  if test -n "$save_CVS_CLIENT_LOG"; then
	      CVS_CLIENT_LOG=$save_CVS_CLIENT_LOG
	  fi
	  ;;



	adderrmsg)
	  # Test some of the error messages the 'add' command can return and
	  # their reactions to '-q'.

	  # First the usual setup; create a directory first-dir.
	  mkdir 1; cd 1
	  dotest adderrmsg-init1 "${testcvs} -q co -l ." ''
	  mkdir adderrmsg-dir
	  dotest adderrmsg-init2 "${testcvs} add adderrmsg-dir" \
"Directory ${CVSROOT_DIRNAME}/adderrmsg-dir added to the repository"
          cd adderrmsg-dir

	  # try to add the admin dir
	  dotest_fail adderrmsg-1 "${testcvs} add CVS" \
"${CPROG} add: cannot add special file .CVS.; skipping"
	  # might not want to see this message when you 'cvs add *'
	  dotest_fail adderrmsg-2 "${testcvs} -q add CVS" ""

	  # to test some other messages
	  touch file1
	  dotest adderrmsg-3 "${testcvs} add file1" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"

	  # add it twice
	  dotest_fail adderrmsg-4 "${testcvs} add file1" \
"${SPROG} add: \`file1' has already been entered"
	  dotest_fail adderrmsg-5 "${testcvs} -q add file1" ""

	  dotest adderrmsg-6 "${testcvs} -q ci -madd" \
"$CVSROOT_DIRNAME/adderrmsg-dir/file1,v  <--  file1
initial revision: 1\.1"

	  # file in Entries & repository
	  dotest_fail adderrmsg-7 "${testcvs} add file1" \
"${SPROG} add: \`file1' already exists, with version number 1\.1"
	  dotest_fail adderrmsg-8 "${testcvs} -q add file1" ""

	  # clean up
	  dokeep
	  cd ../..
	  rm -r 1
	  modify_repo rm -rf $CVSROOT_DIRNAME/adderrmsg-dir
	  ;;



	opterrmsg)
	  # Test some option parsing error messages

	  # No init is necessary since these error messages are printed b4
	  # CVS looks for a sandbox or repository

	  # -z used to accept non-numeric arguments.  This bit someone who
	  # attempted `cvs -z -n up' when the -n was read as the argument to
	  # -z.
	  dotest_fail opterrmsg-1 "${testcvs} -z -n up" \
"${CPROG}: gzip compression level must be between 0 and 9"

	  # Some general -z checks
	  dotest_fail opterrmsg-2 "${testcvs} -z -1 up" \
"${CPROG}: gzip compression level must be between 0 and 9"
	  dotest_fail opterrmsg-3 "${testcvs} -z10 up" \
"${CPROG}: gzip compression level must be between 0 and 9"
	  ;;



	devcom)
	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  mkdir 1
	  cd 1
	  dotest devcom-1 "$testcvs -q co first-dir"

	  cd first-dir
	  echo abb >abb
	  dotest devcom-2 "$testcvs add abb" \
"$SPROG add: scheduling file \`abb' for addition
$SPROG add: use \`$SPROG commit' to add this file permanently"

	  dotest devcom-3 "$testcvs -q ci -m added" \
"$CVSROOT_DIRNAME/first-dir/abb,v  <--  abb
initial revision: 1\.1"

	  dotest_fail devcom-4 "$testcvs watch" "Usage$DOTSTAR"

	  dotest devcom-5 "$testcvs watch on"

	  echo abc >abc
	  dotest devcom-6 "$testcvs add abc" \
"$SPROG add: scheduling file \`abc' for addition
$SPROG add: use \`$SPROG commit' to add this file permanently"

	  dotest devcom-7 "$testcvs -q ci -m added" \
"$CVSROOT_DIRNAME/first-dir/abc,v  <--  abc
initial revision: 1\.1"

	  cd ../..
	  mkdir 2
	  cd 2

	  dotest devcom-8 "$testcvs -q co first-dir" \
"U first-dir/abb
U first-dir/abc"

	  cd first-dir
	  dotest_fail devcom-9 "test -w abb"
	  dotest_fail devcom-9b "test -w abc"

	  dotest devcom-10 "$testcvs editors"
	  dotest devcom-11 "$testcvs edit abb"

	  # Here we test for the traditional ISO C ctime() date format.
	  # We assume the C locale; I guess that works provided we set
	  # LC_ALL at the start of this script but whether these
	  # strings should vary based on locale does not strike me as
	  # self-evident.
	  dotest devcom-12 "$testcvs editors" \
"abb	${username}	[SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000	[-a-zA-Z_.0-9]*	${TESTDIR}/2/first-dir"

	  echo aaaa >>abb
	  dotest devcom-13 "$testcvs ci -m modify abb" \
"${CVSROOT_DIRNAME}/first-dir/abb,v  <--  abb
new revision: 1\.2; previous revision: 1\.1"

	  # Unedit of a file not being edited should be a noop.
	  dotest devcom-14 "$testcvs unedit abb" ''

	  dotest devcom-15 "$testcvs editors" ""

	  dotest_fail devcom-16 "test -w abb"

	  dotest devcom-17 "$testcvs edit abc"

	  # Unedit of an unmodified file.
	  dotest devcom-18 "$testcvs unedit abc"
	  dotest devcom-19 "$testcvs edit abc"

	  echo changedabc >abc
	  # Try to unedit a modified file; cvs should ask for confirmation
	  dotest devcom-20 "echo no | $testcvs unedit abc" \
"abc has been modified; revert changes? "

	  dotest devcom-21 "echo changedabc | cmp - abc"

	  # OK, now confirm the unedit
	  dotest devcom-22 "echo yes |$testcvs unedit abc" \
"abc has been modified; revert changes? "

	  dotest devcom-23 "echo abc |cmp - abc"

	  dotest devcom-24 "$testcvs watchers" ''

	  # FIXME: This probably should be an error message instead
	  # of silently succeeding and printing nothing.
	  dotest devcom-a-nonexist "$testcvs watchers nonexist" ''

	  dotest devcom-a1 "$testcvs watch add" ''
	  dotest devcom-a2 "$testcvs watchers" \
"abb	$username	edit	unedit	commit
abc	$username	edit	unedit	commit"
	  dotest devcom-a3 "$testcvs watch remove -a unedit abb" ''
	  dotest devcom-a4 "$testcvs watchers abb" \
"abb	$username	edit	commit"

	  # Check tagging and checking out while we have a CVS
	  # directory in the repository.
	  dotest devcom-t0 "${testcvs} -q tag tag" \
'T abb
T abc'
	  cd ../..
	  mkdir 3
	  cd 3

	  # Test commented out because the bug it tests for is not fixed
	  # The error is:
	  # cvs watchers: cannot open CVS/Entries for reading: No such file or directory
	  # cvs: ../../work/ccvs/src/fileattr.c:75: fileattr_read: Assertion `fileattr_stored_repos != ((void *)0)' failed.
:	  dotest devcom-t-nonexist "${testcvs} watchers nonexist" fixme

	  dotest devcom-t1 "${testcvs} -q co -rtag first-dir/abb" \
'U first-dir/abb'
	  cd ..
	  # Since first-dir/abb is readonly, use -f.
	  rm -rf 3

	  # Test checking out the directory rather than the file.
	  mkdir 3
	  cd 3
	  dotest devcom-t2 "${testcvs} -q co -rtag first-dir" \
'U first-dir/abb
U first-dir/abc'
	  cd ..
	  # Since the files are readonly, use -f.
	  rm -rf 3

	  # Now do it again, after removing the val-tags file created
	  # by devcom-t1 to force CVS to search the repository
	  # containing CVS directories.
	  rm ${CVSROOT_DIRNAME}/CVSROOT/val-tags
	  mkdir 3
	  cd 3
	  dotest devcom-t3 "${testcvs} -q co -rtag first-dir" \
'U first-dir/abb
U first-dir/abc'
	  cd ..
	  # Since the files are readonly, use -f.
	  rm -rf 3

	  # Now remove all the file attributes
	  cd 2/first-dir
	  dotest devcom-b0 "${testcvs} watch off" ''
	  dotest devcom-b1 "${testcvs} watch remove" ''
	  # Test that CVS 1.6 and earlier can handle the repository.
	  dotest_fail devcom-b2 "test -d ${CVSROOT_DIRNAME}/first-dir/CVS"

	  # Now test watching just some, not all, files.
	  dotest devcom-some0 "${testcvs} watch on abc" ''
	  cd ../..
	  mkdir 3
	  cd 3
	  dotest devcom-some1 "${testcvs} -q co first-dir" 'U first-dir/abb
U first-dir/abc'
	  dotest devcom-some2 "test -w first-dir/abb" ''
	  dotest_fail devcom-some3 "test -w first-dir/abc" ''

	  dokeep
	  cd ..
	  # Use -f because of the readonly files.
	  rm -rf 1 2 3
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	devcom2)
	  # More watch tests, most notably setting watches on
	  # files in various different states.
	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  mkdir 1
	  cd 1
	  dotest devcom2-1 "${testcvs} -q co first-dir" ''
	  cd first-dir

	  # This should probably be an error; setting a watch on a totally
	  # unknown file is more likely to be a typo than intentional.
	  # But that isn't the currently implemented behavior.
	  dotest devcom2-2 "${testcvs} watch on w1" ''

	  touch w1 w2 w3 nw1
	  dotest devcom2-3 "${testcvs} add w1 w2 w3 nw1" "${DOTSTAR}"
	  # Letting the user set the watch here probably can be considered
	  # a feature--although it leads to a few potentially strange
	  # consequences like one user can set the watch and another actually
	  # adds the file.
	  dotest devcom2-4 "${testcvs} watch on w2" ''
	  dotest devcom2-5 "${testcvs} -Q ci -m add-them"

	  # Note that this test differs in a subtle way from devcom-some0;
	  # in devcom-some0 the watch is creating a new fileattr file, and
	  # here we are modifying an existing one.
	  dotest devcom2-6 "${testcvs} watch on w3" ''

	  # Now test that all the watches got set on the correct files
	  # FIXME: CVS should have a way to report whether watches are
	  # set, I think.  The "check it out and see if it read-only" is
	  # sort of OK, but is complicated by CVSREAD and doesn't help
	  # if the file is added and not yet committed or some such.
	  # Probably "cvs status" should report "watch: on" if watch is on
	  # (and nothing if watch is off, so existing behavior is preserved).
	  cd ../..
	  mkdir 2
	  cd 2
	  dotest devcom2-7 "${testcvs} -q co first-dir" 'U first-dir/nw1
U first-dir/w1
U first-dir/w2
U first-dir/w3'
	  dotest devcom2-8 "test -w first-dir/nw1" ''
	  dotest_fail devcom2-9 "test -w first-dir/w1" ''
	  dotest_fail devcom2-10 "test -w first-dir/w2" ''
	  dotest_fail devcom2-11 "test -w first-dir/w3" ''

	  cd first-dir
	  # OK, now we want to try files in various states with cvs edit.
	  dotest_fail devcom2-12 "$testcvs edit w4" \
"${CPROG} edit: no such file w4; ignored"
	  # Try the same thing with a per-directory watch set.
	  dotest devcom2-13 "${testcvs} watch on" ''
	  dotest_fail devcom2-14 "$testcvs edit w5" \
"${CPROG} edit: no such file w5; ignored"
	  dotest devcom2-15 "${testcvs} editors" ''
	  dotest devcom2-16 "${testcvs} editors w4" ''
	  # Make sure there are no droppings lying around
	  dotest devcom2-17 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \
"Fw1	_watched=
Fw2	_watched=
Fw3	_watched=
Fnw1	_watched=
D	_watched="
	  cd ..

	  # Do a little error testing
	  dotest devcom2-18 "${testcvs} -q co -d first+dir first-dir" \
"U first${PLUS}dir/nw1
U first${PLUS}dir/w1
U first${PLUS}dir/w2
U first${PLUS}dir/w3"
	  cd first+dir
	  dotest_fail devcom2-19 "${testcvs} edit" \
"${CPROG} \[edit aborted\]: current directory (${TESTDIR}/2/first${PLUS}dir) contains an invalid character (${PLUS},>;=\\\\t\\\\n)"

	  # Make sure there are no droppings lying around
	  dotest devcom2-20 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \
"Fw1	_watched=
Fw2	_watched=
Fw3	_watched=
Fnw1	_watched=
D	_watched="

	  dokeep
	  cd ../..
	  # Use -f because of the readonly files.
	  rm -rf 1 2
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	devcom3)
	  # More watch tests, most notably handling of features designed
	  # for future expansion.
	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  mkdir 1
	  cd 1

	  # Set up logging via the postwatch script hook.  See the `info' test
	  # for a list of tests where other script hooks are tested.
	  dotest devcom3-init-1 "$testcvs -Q co CVSROOT"
	  cd CVSROOT
	  echo "ALL $TESTDIR/1/loggit %r %p %c" >>postwatch
	  dotest devcom3-init-2 "$testcvs -Q ci -mlog-watch"
	  cd .. # 1

	  cat >loggit <<EOF
#!$TESTSHELL
echo \${1+"\$@"} >>$TESTDIR/1/watch-log
EOF
	  # #^@&!^@ Cygwin.
	  if test -n "$remotehost"; then
	    $CVS_RSH $remotehost "chmod +x $TESTDIR/1/loggit"
	  else
	    chmod +x loggit
	  fi
	
	

	  dotest devcom3-1 "$testcvs -q co first-dir"
	  cd first-dir

	  touch w1 w2
	  dotest devcom3-2 "${testcvs} add w1 w2" "${DOTSTAR}"
	  dotest devcom3-3 "${testcvs} watch on w1 w2" ''
	  dotest devcom3-4 "${testcvs} -Q ci -m add-them"

	  # OK, since we are about to delve into CVS's internals, make
	  # sure that we seem to be correct about how they work.
	  dotest devcom3-5 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \
"Fw1	_watched=
Fw2	_watched="
	  # Now write a few more lines, just as if we were a newer version
	  # of CVS implementing some new feature.
	  cat <<'EOF' >>${CVSROOT_DIRNAME}/first-dir/CVS/fileattr
Enew	line	here
G@#$^!@#=&
EOF
	  # Now get CVS to write to the fileattr file....
	  dotest devcom3-6 "${testcvs} watch off w1" ''
	  # ...and make sure that it hasn't clobbered our new lines.
	  # Note that writing these lines in another order would be OK
	  # too.
	  dotest devcom3-7 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \
"Fw2	_watched=
G@#..!@#=&
Enew	line	here"

	  # See what CVS does when a file name is duplicated.  The
	  # behavior of all versions of CVS since file attributes were
	  # implemented is that it nukes the duplications.  This seems
	  # reasonable enough, although it means it isn't clear how
	  # useful duplicates would be for purposes of future
	  # expansion.  But in the interests of keeping behaviors
	  # predictable, might as well test for it, I guess.
	  echo 'Fw2	duplicate=' >>${CVSROOT_DIRNAME}/first-dir/CVS/fileattr
	  dotest devcom3-8 "${testcvs} watch on w1" ''
	  dotest devcom3-9 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \
"Fw2	_watched=
Fw1	_watched=
Enew	line	here
G@#..!@#=&"

	  # Now test disconnected "cvs edit" and the format of the 
	  # CVS/Notify file.
	  if $remote; then
	    CVS_SERVER_save=$CVS_SERVER
	    CVS_SERVER=$TESTDIR/cvs-none; export CVS_SERVER

	    # The ${DOTSTAR} below matches the exact CVS server error message,
	    # which in :fork: mode is:
	    # "$SPROG \[edit aborted\]: cannot exec $TESTDIR/cvs-none: ${DOTSTAR}",
	    # but which is:
	    # "bash2: line 1: $TESTDIR/cvs-none: No such file or directory"
	    # when testing across an :ext:/ssh link to my Linux 2.4 box.
	    #
	    # I can't even test for the second part of the error message,
	    # from the client, which varies more consistently, usually either
	    # "end of file from server" (if the process doing the exec exits
	    # before the parent gets around to sending data to it) or
	    # "received broken pipe signal" (if it is the other way around),
	    # since HP-UX fails to output it.
	    dotest_fail devcom3-9ar "$testcvs edit w1 2>/dev/null"
	    dotest devcom3-9br "test -w w1"
	    dotest devcom3-9cr "cat CVS/Notify" \
"Ew1	[SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000	[-a-zA-Z_.0-9]*	${TESTDIR}/1/first-dir	EUC"
	    CVS_SERVER=${CVS_SERVER_save}; export CVS_SERVER
	    if $proxy; then
	      dotest_fail devcom3-9dp "$testcvs -q update" \
"This CVS server does not support disconnected \`cvs edit'\.  For now, remove all \`CVS/Notify' files in your workspace and try your command again\."
	      dotest devcom3-9ep "test -f CVS/Notify"
	      rm CVS/Notify
	      dotest devcom3-9hp "$testcvs watchers w1"
	    else
	      dotest devcom3-9dr "$testcvs -q update"
	      dotest_fail devcom3-9er "test -f CVS/Notify"
	      dotest devcom3-9fr "$testcvs watchers w1" \
"w1	$username	tedit	tunedit	tcommit"
	    fi
	    dotest devcom3-9gr "$testcvs unedit w1"
	    dotest devcom3-9hr "$testcvs watchers w1"
	  fi

	  cd ../..
	  # OK, now change the tab to a space, and see that CVS gives
	  # a reasonable error (this is database corruption but CVS should
	  # not lose its mind).
	  sed -e 's/Fw2	/Fw2 /' <$CVSROOT_DIRNAME/first-dir/CVS/fileattr \
	    >$CVSROOT_DIRNAME/first-dir/CVS/fileattr.new
	  modify_repo mv $CVSROOT_DIRNAME/first-dir/CVS/fileattr.new \
			 $CVSROOT_DIRNAME/first-dir/CVS/fileattr
	  mkdir 2; cd 2
	  dotest_fail devcom3-10 "${testcvs} -Q co ." \
"${SPROG} \[checkout aborted\]: file attribute database corruption: tab missing in ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr"

	  notifyworks=false
	  if $remote; then
	    if $proxy; then :; else
	      notifyworks=:
	    fi
	  fi
	  if $notifyworks; then
	    dotest devcom3-postwatch-examine-1r "cat $TESTDIR/1/watch-log" \
"$CVSROOT_DIRNAME first-dir watch
$CVSROOT_DIRNAME first-dir watch
$CVSROOT_DIRNAME first-dir watch
$CVSROOT_DIRNAME first-dir update
$CVSROOT_DIRNAME first-dir server"
	  else
	    dotest devcom3-postwatch-examine-1 "cat $TESTDIR/1/watch-log" \
"$CVSROOT_DIRNAME first-dir watch
$CVSROOT_DIRNAME first-dir watch
$CVSROOT_DIRNAME first-dir watch"
	  fi

	  dokeep
	  restore_adm
	  cd ..
	  # Use -f because of the readonly files.
	  rm -rf 1 2
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	watch4)
	  # More watch tests, including adding directories.
	  mkdir 1; cd 1
	  dotest watch4-0a "${testcvs} -q co -l ." ''
	  mkdir first-dir
	  dotest watch4-0b "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"

	  cd first-dir
	  dotest watch4-1 "${testcvs} watch on" ''
	  # This is just like the 173 test
	  touch file1
	  dotest watch4-2 "$testcvs add file1" \
"$SPROG add: scheduling file .file1. for addition
$SPROG add: use .$SPROG commit. to add this file permanently"
	  dotest watch4-3 "$testcvs -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1"
	  # Now test the analogous behavior for directories.
	  mkdir subdir
	  dotest watch4-4 "${testcvs} add subdir" \
"Directory ${CVSROOT_DIRNAME}/first-dir/subdir added to the repository"
	  cd subdir
	  touch sfile
	  dotest watch4-5 "${testcvs} add sfile" \
"${SPROG} add: scheduling file .sfile. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest watch4-6 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/subdir/sfile,v  <--  sfile
initial revision: 1\.1"
	  cd ../../..
	  mkdir 2; cd 2
	  dotest watch4-7 "${testcvs} -q co first-dir" "U first-dir/file1
U first-dir/subdir/sfile"
	  dotest_fail watch4-8 "test -w first-dir/file1" ''
	  dotest_fail watch4-9 "test -w first-dir/subdir/sfile" ''
	  cd first-dir
	  dotest watch4-10 "${testcvs} edit file1" ''
	  echo 'edited in 2' >file1
	  cd ../..

	  cd 1/first-dir

            # NOTE: I'm leaving in '' as acceptable
            #  to maintain partial compatibility with CVS versions
            #  prior to the edit check patch.
          editorsLineRE="file1	$username	[SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000	$hostname	$TESTDIR/2/first-dir"
	  dotest watch4-11 "$testcvs edit file1" "$editorsLineRE"

	  echo 'edited in 1' >file1
	  dotest watch4-12 "${testcvs} -q ci -m edit-in-1" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.2; previous revision: 1\.1"
	  cd ../..
	  cd 2/first-dir
	  dotest watch4-13 "${testcvs} -q update" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
retrieving revision 1\.1
retrieving revision 1\.2
Merging differences between 1\.1 and 1\.2 into file1
rcsmerge: warning: conflicts during merge
${SPROG} update: conflicts found in file1
C file1"
	  if (echo yes | ${testcvs} unedit file1) >>${LOGFILE}; then
	    pass watch4-14
	  else
	    fail watch4-15
	  fi
	  # This could plausibly be defined to either go back to the revision
	  # which was cvs edit'd (the status quo), or back to revision 1.2
	  # (that is, the merge could update CVS/Base/file1).  We pick the
	  # former because it is easier to implement, not because we have
	  # thought much about which is better.
	  dotest watch4-16 "cat file1" ''
	  # Make sure CVS really thinks we are at 1.1.
	  dotest watch4-17 "${testcvs} -q update" "U file1"
	  dotest watch4-18 "cat file1" "edited in 1"
	  cd ../..

	  # As a sanity check, make sure we are in the right place.
	  dotest watch4-cleanup-1 "test -d 1"
	  dotest watch4-cleanup-1 "test -d 2"

	  dokeep
	  # Specify -f because of the readonly files.
	  rm -rf 1 2
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	watch5)
	  # This test was designed to catch a problem in server
	  # mode where an 'cvs edit'd file disappeared from the
	  # CVS/Base directory when 'cvs status' or 'cvs update'
	  # was called on the file after the file was touched.
	  #
	  # This test is still here to prevent the bug from
	  # being reintroduced.
	  #
	  # The rationale for having CVS/Base stay around is that
	  # CVS/Base should be there if "cvs edit" has been run (this
	  # may be helpful as a "cvs editors" analogue, it is
	  # client-side and based on working directory not username;
	  # but more importantly, it isn't clear why a "cvs status"
	  # would act like an unedit, and even if it does, it would
	  # need to make the file read-only again).

	  mkdir watch5; cd watch5
	  dotest watch5-0a "${testcvs} -q co -l ." ''
	  mkdir first-dir
	  dotest watch5-0b "${testcvs} add first-dir" \
"Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"

	  cd first-dir
	  dotest watch5-1 "${testcvs} watch on" ''
	  # This is just like the 173 test
	  touch file1
	  dotest watch5-2 "${testcvs} add file1" \
"${SPROG} add: scheduling file .file1. for addition
${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest watch5-3 "${testcvs} -q ci -m add" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1"
	  dotest watch5-4 "${testcvs} edit file1" ''
	  dotest watch5-5 "test -f CVS/Base/file1" ''
	  if ${testcvs} status file1 >>${LOGFILE} 2>&1; then
		pass watch5-6
	  else
		fail watch5-6
	  fi
	  dotest watch5-7 "test -f CVS/Base/file1" ''

	  # Here's where the file used to dissappear
	  touch file1
	  if ${testcvs} status file1 >>${LOGFILE} 2>&1; then
		pass watch5-8
	  else
		fail watch5-8
	  fi
	  dotest watch5-10 "test -f CVS/Base/file1" ''

	  # Make sure update won't remove the file either
	  touch file1
	  dotest watch5-11 "${testcvs} -q up" ''
	  dotest watch5-12 "test -f CVS/Base/file1" ''

	  dokeep
	  cd ../..
	  rm -r watch5
	  modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
	  ;;



	watch6-0)

	  # Make sure that default attributes are being set properly.
	  # Specifying a directory has, it seems, never worked,
	  # and 1.12.10 broke it completely.
	  mkdir watch6-0; cd watch6-0

	  dotest watch6-0-setup-1 "$testcvs -Q co -ldtop ."
	  cd top
	  mkdir watch6-0
	  dotest watch6-0-setup-2 "$testcvs -Q add watch6-0"
	  cd watch6-0
	  dotest watch6-0-1 "$testcvs watch add"
	  dotest watch6-0-2 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/CVS/fileattr"
	  dotest watch6-0-3 "$testcvs watch remove"
	  dotest_fail watch6-0-4 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/CVS/fileattr 2>/dev/null"

	  dotest watch6-0-5 "$testcvs watch add ."
	  dotest watch6-0-6 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/CVS/fileattr"
	  dotest watch6-0-7 "$testcvs watch remove ."
	  dotest_fail watch6-0-8 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/CVS/fileattr 2>/dev/null"

	  # OK, basic add/remove work. Now, make sure it works with named directories
	  mkdir dir1
	  mkdir dir2
	  mkdir dir3
	  echo afile>afile
	  $testcvs -Q add afile dir1 dir2 dir3
	  $testcvs -Q ci -m "Adding test files"

	  # Current directory should not be watched, but there should be a watch on the file,
	  # and on dir1 & dir2, but not on dir3.
	  dotest watch6-0-9 "$testcvs -Q watch add afile dir1 dir2"
	  dotest_fail watch6-0-10 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/CVS/fileattr 2>/dev/null"
	  dotest watch6-0-11 "grep -qE '^Fafile' $CVSROOT_DIRNAME/watch6-0/CVS/fileattr"
	  dotest watch6-0-12 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/dir1/CVS/fileattr"
	  dotest watch6-0-13 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/dir2/CVS/fileattr"
	  dotest_fail watch6-0-12 "grep -qE '^D' $CVSROOT_DIRNAME/watch6-0/dir3/CVS/fileattr 2>/dev/null"

	  dokeep
	  cd ../../..
	  rm -rf watch6-0
	  modify_repo rm -rf $CVSROOT_DIRNAME/watch6-0
	  ;;



	watch6)
	  # Check that `cvs watch on' does not reset the fileattr file.
	  mkdir watch6; cd watch6

	  dotest watch6-setup-1 "$testcvs -Q co -ldtop ."
	  cd top
	  mkdir watch6
	  dotest watch6-setup-2 "$testcvs -Q add watch6"

	  # I don't recall why I had these next 3 lines.
	  cd ..
	  dotest watch6-setup-3 "$testcvs -Q co watch6"
	  cd watch6

	  mkdir subdir
	  dotest watch6-setup-4 "$testcvs -Q add subdir"
	  cd subdir

	  # START watch add/remove sequence
	  dotest watch6-1 "$testcvs -Q watch add"
	  dotest watch6-2 \
"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"

	  dotest watch6-3 "$testcvs watch on"
	  dotest watch6-4 \
"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"
	  dotest watch6-5 \
"grep '_watched' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"

	  dotest watch6-6 "$testcvs watch off"
	  dotest watch6-7 \
"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"
	  dotest_fail watch6-8 \
"grep '_watched' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"

	  dotest watch6-9 "$testcvs watch remove"
	  dotest_fail watch6-10 \
"test -d $CVSROOT_DIRNAME/test-directory/subdir/CVS"
	  dotest_fail watch6-11 \
"test -f $CVSROOT_DIRNAME/test-directory/subdir/CVS/fileattr"
	  # END watch add/remove sequence

	  echo Hi there >afile
	  dotest watch6-12 "$testcvs -Q add afile"
	  dotest watch6-13 "$testcvs ci -m 'A file' afile" \
"$CVSROOT_DIRNAME/watch6/subdir/afile,v  <--  afile
initial revision: 1.1"

	  # START watch add/remove sequence
	  dotest watch6-14 "$testcvs -Q watch add"
	  dotest watch6-15 \
"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"

	  dotest watch6-16 "$testcvs watch on"
	  dotest watch6-17 \
"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"
	  dotest watch6-18 \
"grep '_watched' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"

	  dotest watch6-19 "$testcvs watch off"
	  dotest watch6-20 \
"grep '_watchers' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"
	  dotest_fail watch6-21 \
"grep '_watched' $CVSROOT_DIRNAME/watch6/subdir/CVS/fileattr >/dev/null"

	  dotest watch6-22 "$testcvs watch remove"
	  dotest_fail watch6-23 \
"test -d $CVSROOT_DIRNAME/test-directory/subdir/CVS"
	  dotest_fail watch6-24 \
"test -f $CVSROOT_DIRNAME/test-directory/subdir/CVS/fileattr"
	  # END watch add/remove sequence

	  if $keep; then
	    echo Keeping $TESTDIR and exiting due to --keep
	    exit 0
	  fi
	  cd ../../..
	  rm -r watch6
	  modify_repo rm -rf $CVSROOT_DIRNAME/watch6
	  ;;



        edit-check)
          # This tests the edit -c/-f and related features.

	  mkdir edit-check; cd edit-check
	  dotest edit-check-0a "$testcvs -q co -l ."
	  mkdir first-dir
	  dotest edit-check-0b "$testcvs add first-dir" \
"Directory $CVSROOT_DIRNAME/first-dir added to the repository"

	  cd first-dir
	  dotest edit-check-1 "$testcvs watch on"

          echo foo > file1
          dotest edit-check-2a "$testcvs add -minitial file1" \
"$SPROG [a-z]*: scheduling file .file1. for addition
$SPROG [a-z]*: use .$SPROG commit. to add this file permanently"

          dotest edit-check-2b "$testcvs commit -m 'c1' file1" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
initial revision: 1\.1"

          editorsLineRE="file1	$username	[SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000	$hostname	$TESTDIR/edit-check/first-dir"

          R_editorsLineRE="first-dir/file1	$username	[SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000	$hostname	$TESTDIR/edit-check"
          F3_editorsLineRE="second-dir/file3	$username	[SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000	$hostname	$TESTDIR/edit-check/first-dir"

          A_editorsLineRE="file1	[-a-zA-Z0-9_]*	[SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000	$hostname	$TESTDIR[0-9]*/edit-check/first-dir"

          AF_editorsLineRE="file[12]	[-a-zA-Z0-9_]*	[SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000	$hostname	$TESTDIR/edit-check/first-dir"

          NF_editorsLineRE="	[-a-zA-Z0-9_]*	[SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000	$hostname	$TESTDIR/edit-check/first-dir"

          dotest edit-check-3 "$testcvs edit file1"
          dotest edit-check-4 "$testcvs edit file1" "$editorsLineRE"

          dotest_fail edit-check-5a "$testcvs edit -c file1" \
"$editorsLineRE
$SPROG edit: Skipping file \`file1' due to existing editors\."

          dotest edit-check-5b "$testcvs editors" "$editorsLineRE"

          dotest edit-check-6a "$testcvs edit -c -f file1" "$editorsLineRE"
          dotest edit-check-6b "$testcvs editors" "$editorsLineRE"

          dotest edit-check-7a "cat file1" "foo"
          echo "bar" > file1
          dotest_fail edit-check-7b "$testcvs edit -c file1" \
"$editorsLineRE
$SPROG edit: Skipping file \`file1' due to existing editors\."
          dotest edit-check-7c "cat file1" "bar"

            # edit-check-8a has issues.  It copies the current (modified)
            # version of the file into CVS/Base, so that edit-check-9a and
            # edit-check-9b don't get the expected results.
            #   Maybe unedit is *supposed* to return it to the state
            # it was in before the edit (even if it was modified),
            # but while that has a certain symetry, it doesn't seem
            # to pass the intuitive-usability test.
            #   This aspect of the general problem could
            # be fixed by not overwriting pre-existing Base versions,
            # but it still wouldn't fix it if the user manually
            # modified the file before doing the first edit.
            #   Because of the possibility that this is working as
            # intended, I'm just commenting out the test, not fixing
            # the issue.
          #dotest edit-check-8a "${testcvs} edit -c -f file1" \
          #   "${editorsLineRE}"
          dotest edit-check-8b "$testcvs editors" "$editorsLineRE"

          dotest edit-check-9a "echo yes | $testcvs unedit file1" \
"file1 has been modified; revert changes? "
          dotest edit-check-9b "$testcvs editors"
          dotest edit-check-9c "cat file1" "foo"

          dotest edit-check-10 "$testcvs edit -c file1"
          dotest_fail edit-check-11 "$testcvs edit -c file1" \
"$editorsLineRE
$SPROG edit: Skipping file \`file1' due to existing editors\."

          echo "morefoo" > file1
          dotest edit-check-12a "$testcvs commit -m 'c2' -c file1" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.2; previous revision: 1\.1"
          dotest edit-check-12b "$testcvs editors file1"

          chmod u+w file1
          echo "morebar" > file1
          dotest_fail edit-check-13a "$testcvs commit -m 'c3' -c file1" \
"$SPROG [a-z]*: Valid edit does not exist for file1
$SPROG \[[a-z]* aborted\]: correct above errors first!"
          dotest edit-check-13b "$testcvs editors file1"

          dotest edit-check-14a "$testcvs commit -m 'c4' -c -f file1" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.3; previous revision: 1\.2"
          dotest edit-check-14b "$testcvs editors file1"

          dotest edit-check-15 "$testcvs edit -c file1"
          cd ..

          dotest edit-check-16a "echo yes | $testcvs release -d first-dir" \
"You have \[0\] altered files in this repository.
Are you sure you want to release (and delete) directory \`first-dir': "
          dotest edit-check-16b "$testcvs -q update -d first-dir" \
             "U first-dir/file1"
          cd first-dir
          dotest edit-check-16c "$testcvs editors file1"

          cd ..
          dotest edit-check-17a "$testcvs edit -c"
          dotest_fail edit-check-17b "$testcvs edit -c" \
"$R_editorsLineRE
$SPROG edit: Skipping file \`first-dir/file1' due to existing editors\."
          dotest edit-check-17c "$testcvs edit -c -f" "$R_editorsLineRE"

          echo "more changes" > first-dir/file1
          dotest edit-check-18a "$testcvs -q commit -m 'c5' -c" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  first-dir/file1
new revision: 1\.4; previous revision: 1\.3"
          dotest edit-check-18b "$testcvs editors"

          cd first-dir

            # Manually fake another editor:

            # Try to gaurantee a seperate name for an "other" user editting
            # the file.
          otherUser="dummyUser"
          if [ x"$USER" = x"$otherUser" ]  ; then
            otherUser="dummyUser2"
          fi
          if [ x"$LOGNAME" = x"$otherUser" ] ; then
            otherUser="dummyUser3"
          fi
          tabChar='	'

          backupFileattrName="$CVSROOT_DIRNAME/first-dir/CVS/bak.fileattr.$$"
          mv $CVSROOT_DIRNAME/first-dir/CVS/fileattr $backupFileattrName

          otherDir="`pwd | sed 's%/edit-check/%2/edit-check/%'`"
          echo \
"Ffile1${tabChar}_watched=;_editors=$otherUser>Sat Oct  6 04:25:00 2001 -0000+`hostname`+$otherDir;_watchers=$otherUser>tedit+tunedit+tcommit
D${tabChar}_watched=" > $CVSROOT_DIRNAME/first-dir/CVS/fileattr 

          editFileattrName="$CVSROOT_DIRNAME/first-dir/CVS/edit.fileattr.$$"
          cp $CVSROOT_DIRNAME/first-dir/CVS/fileattr $editFileattrName

          O_editorsLineRE="file1	$otherUser	[SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000	$hostname	$TESTDIR[0-9]/edit-check/first-dir"

          dotest edit-check-19a "$testcvs edit file1" "$O_editorsLineRE"
          dotest edit-check-19b "$testcvs editors" \
"$A_editorsLineRE
$NF_editorsLineRE"

          dotest edit-check-20a "$testcvs unedit file1"
          dotest edit-check-20b "$testcvs editors" "$O_editorsLineRE"

          dotest_fail edit-check-21a "$testcvs edit -c file1" \
"$O_editorsLineRE
$SPROG edit: Skipping file \`file1' due to existing editors\."
          dotest edit-check-21b "$testcvs editors" "$O_editorsLineRE"

          dotest edit-check-22a "$testcvs edit -c -f file1" "$O_editorsLineRE"
          dotest edit-check-22b "$testcvs editors" \
"$A_editorsLineRE
$NF_editorsLineRE"

          echo "Yet another change" >file1

          dotest_fail edit-check-23a "$testcvs edit -c" \
"$A_editorsLineRE
$NF_editorsLineRE
$SPROG edit: Skipping file \`file1' due to existing editors\."

          dotest edit-check-23b "$testcvs editors" \
"$A_editorsLineRE
$NF_editorsLineRE"

          dotest edit-check-24a "echo y | $testcvs unedit" \
             "file1 has been modified; revert changes? "
          dotest edit-check-24b "$testcvs editors" "$O_editorsLineRE"
          dotest edit-check-24c "cat file1" "more changes"

          dotest edit-check-25a "$testcvs unedit"
          dotest edit-check-25b "$testcvs editors" "$O_editorsLineRE"
          dotest_fail edit-check-25c "test -w file1"

          dotest edit-check-26a "$testcvs edit file1" "$O_editorsLineRE"
          dotest edit-check-26b "$testcvs editors file1" \
"$A_editorsLineRE
$NF_editorsLineRE"
          dotest edit-check-26c "test -w file1"

          echo "Yet more changes" >file1
          dotest edit-check-27a "$testcvs -q commit -mmsg -c file1" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.5; previous revision: 1\.4"
          dotest edit-check-27b "$testcvs editors" "$O_editorsLineRE"

          chmod u+w file1
          echo "unofficial change" >file1

          dotest_fail edit-check-28a "$testcvs -q commit -mmsg -c" \
"$SPROG commit: Valid edit does not exist for file1
$SPROG \[commit aborted\]: correct above errors first!"
          dotest edit-check-28b "$testcvs editors" "$O_editorsLineRE"

          dotest edit-check-29a "$testcvs -q commit -mmsg -c -f" \
"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
new revision: 1\.6; previous revision: 1\.5"
          dotest edit-check-29b "$testcvs editors" "$O_editorsLineRE"
          dotest edit-check-29c "cat file1" "unofficial change"

          modify_repo cp "$backupFileattrName" \
			 $CVSROOT_DIRNAME/first-dir/CVS/fileattr
          dotest edit-check-30 "$testcvs editors"

          # Make sure earlier unreported editors are reported properly
          # with the edit-check code running.
          if $remote; then
            CVS_SERVER_SAVED=$CVS_SERVER
            CVS_SERVER=$TESTDIR/cvs-none; export CVS_SERVER

            # The $DOTSTAR matches the exact exec error message
            # (which varies) and either "end of file from server"
            # (if the process doing the exec exits before the parent
            # gets around to sending data to it) or "broken pipe" (if it
            # is the other way around).
            dotest_fail edit-check-31ar "$testcvs edit file1" \
"$SPROG \[edit aborted\]: cannot exec $TESTDIR/cvs-none: $DOTSTAR"
            dotest edit-check-31br "test -w file1"
            dotest edit-check-31cr "cat CVS/Notify" \
"Efile1	[SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000	[-a-zA-Z_.0-9]*	$TESTDIR/edit-check/first-dir	EUC"
            CVS_SERVER=$CVS_SERVER_SAVED; export CVS_SERVER

            dotest_fail edit-check-31dr "$testcvs edit -c file1" \
"$editorsLineRE
$SPROG edit: Skipping file \`file1' due to existing editors\."
            dotest edit-check-31er "$testcvs editors file1" "$editorsLineRE"
            dotest edit-check-31fr "$testcvs unedit file1"
          fi

           # Make sure it isn't confused by handling multiple files at
           # the same time:
          echo file2Data >file2

          dotest edit-check-32a "$testcvs add file2" \
"$SPROG [a-z]*: scheduling file .file2. for addition
$SPROG [a-z]*: use .$SPROG commit. to add this file permanently"

          dotest edit-check-32b "$testcvs commit -m 'c1' file2" \
"$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
initial revision: 1\.1"

          mkdir second-dir
          dotest edit-check-32c "$testcvs add second-dir" \
"Directory $CVSROOT_DIRNAME/first-dir/second-dir added to the repository"
          cd second-dir
          echo ThirdFile >file3

          dotest edit-check-32d "$testcvs add file3" \
"$SPROG [a-z]*: scheduling file .file3. for addition
$SPROG [a-z]*: use .$SPROG commit. to add this file permanently"

          dotest edit-check-32f "$testcvs commit -m 'c1' file3" \
"$CVSROOT_DIRNAME/first-dir/second-dir/file3,v  <--  file3
initial revision: 1\.1"
          dotest_fail edit-check-32g "test -w file3"

          cd ..

          dotest edit-check-33a "$testcvs edit -c"

          dotest edit-check-33b "$testcvs editors" \
"$AF_editorsLineRE
$AF_editorsLineRE
$F3_editorsLineRE"
          dotest edit-check-33c "test -w second-dir/file3"

          dotest_fail edit-check-34a "$testcvs edit -c file1 file2" \
"$AF_editorsLineRE
$SPROG edit: Skipping file \`file1' due to existing editors\.
$AF_editorsLineRE
$SPROG edit: Skipping file \`file2' due to existing editors\."

          dotest edit-check-34b "$testcvs editors file1 file2" \
"$editorsLineRE
$AF_editorsLineRE"

          dotest edit-check-35a "$testcvs unedit file1"
          dotest edit-check-35b "$testcvs editors" \
"$AF_editorsLineRE
$F3_editorsLineRE"
          dotest edit-check-35c "test -w second-dir/file3"

          dotest edit-check-36a "$testcvs unedit"
          dotest edit-check-36b "$testcvs editors"
          dotest_fail edit-check-36c "test -w second-dir/file3"

	  dokeep
          cd ../..
          rm -rf edit-check
          rm -rf $CVSROOT_DIRNAME/first-dir
          ;;



	unedit-without-baserev)
	  mkdir 1; cd 1
	  module=x

	  file=m
	  echo foo > $file
	  dotest unedit-without-baserev-1 \
	    "$testcvs -Q import -m . $module X Y" ''
	  dotest unedit-without-baserev-2 "$testcvs -Q co $module" ''
	  cd $module

	  dotest unedit-without-baserev-3 "$testcvs -Q edit $file" ''

	  echo add a line >> $file
	  rm -f CVS/Baserev

	  # This will fail on most systems.
	  dotest unedit-without-baserev-4 "echo yes |${testcvs} -Q unedit $file" \
"m has been modified; revert changes${QUESTION} ${CPROG} unedit: m not mentioned in CVS/Baserev
${CPROG} unedit: run update to complete the unedit"

	  # SunOS4.1.4 systems make it this far, but with a corrupted
	  # CVS/Entries file.  Demonstrate the corruption!
	  dotest unedit-without-baserev-5 "cat CVS/Entries" \
	    "/$file/1\.1\.1\.1/${DOTSTAR}"

	  dotest unedit-without-baserev-6 "${testcvs} -q update" \
"$SPROG update: warning: \`m' was lost
U m"

	  # OK, those were the easy cases.  Now tackle the hard one
	  # (the reason that CVS/Baserev was invented rather than just
	  # getting the revision from CVS/Entries).  This is very
	  # similar to watch4-10 through watch4-18 but with Baserev
	  # missing.
	  cd ../..
	  mkdir 2; cd 2
	  dotest unedit-without-baserev-7 "${testcvs} -Q co x" ''
	  cd x

	  dotest unedit-without-baserev-10 "${testcvs} edit m" ''
	  echo 'edited in 2' >m
	  cd ../..

	  cd 1/x

          editorsLineRE="m	$username	[SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000	$hostname	$TESTDIR/2/x"
	  dotest unedit-without-baserev-11 "$testcvs edit m" "$editorsLineRE"

	  echo 'edited in 1' >m
	  dotest unedit-without-baserev-12 "${testcvs} -q ci -m edit-in-1" \
"$CVSROOT_DIRNAME/x/m,v  <--  m
new revision: 1\.2; previous revision: 1\.1"
	  cd ../..
	  cd 2/x
	  dotest unedit-without-baserev-13 "${testcvs} -q update" \
"RCS file: ${CVSROOT_DIRNAME}/x/m,v
retrieving revision 1\.1\.1\.1
retrieving revision 1\.2
Merging differences between 1\.1\.1\.1 and 1\.2 into m
rcsmerge: warning: conflicts during merge
${SPROG} update: conflicts found in m
C m"
	  rm CVS/Baserev
	  dotest unedit-without-baserev-14 "echo yes |${testcvs} unedit m" \
"m has been modified; revert changes${QUESTION} ${CPROG} unedit: m not mentioned in CVS/Baserev
${CPROG} unedit: run update to complete the unedit"
	  dotest unedit-without-baserev-15 "${testcvs} -q update" \
"$SPROG update: warning: \`m' was lost
U m"
	  # The following tests are kind of degenerate compared with
	  # watch4-16 through watch4-18 but might as well make sure that
	  # nothing seriously wrong has happened to the working directory.
	  dotest unedit-without-baserev-16 "cat m" 'edited in 1'
	  # Make sure CVS really thinks we are at 1.2.
	  dotest unedit-without-baserev-17 "${testcvs} -q update" ""
	  dotest unedit-without-baserev-18 "cat m" "edited in 1"

	  dokeep
	  cd ../..
	  rm -rf 1
	  rm -r 2
	  modify_repo rm -rf $CVSROOT_DIRNAME/$module
	  ;;



	ignore)
	  # On Windows, we can't check out CVSROOT, because the case
	  # insensitivity means that this conflicts with cvsroot.
	  mkdir ignore
	  cd ignore

	  dotest ignore-1 "${testcvs} -q co CVSROOT" "U CVSROOT/${DOTSTAR}"
	  cd CVSROOT
	  echo rootig.c >cvsignore
	  dotest ignore-2 "${testcvs} add cvsignore" "${SPROG}"' add: scheduling file `cvsignore'"'"' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'

	  dotest ignore-3 " ${testcvs} ci -m added" \
"${CPROG} commit: Examining \.
${CVSROOT_DIRNAME}/CVSROOT/cvsignore,v  <--  cvsignore
initial revision: 1\.1
${SPROG} commit: Rebuilding administrative file database"

	  cd ..
	  if echo "yes" | ${testcvs} release -d CVSROOT >>${LOGFILE} ; then
	      pass ignore-4
	  else
	      fail ignore-4
	  fi

	  # CVS looks at the home dir from getpwuid, not HOME (is that correct
	  # behavior?), so this is hard to test and we won't try.
	  # echo foobar.c >${HOME}/.cvsignore
	  CVSIGNORE=envig.c; export CVSIGNORE
	  mkdir dir-to-import
	  cd dir-to-import
	  touch foobar.c bar.c rootig.c defig.o envig.c optig.c
	  # We use sort because we can't predict the order in which
	  # the files will be listed.
	  dotest_sort ignore-5 "${testcvs} import -m m -I optig.c ignore/first-dir tag1 tag2" \
'

I ignore/first-dir/defig.o
I ignore/first-dir/envig.c
I ignore/first-dir/optig.c
I ignore/first-dir/rootig.c
N ignore/first-dir/bar.c
N ignore/first-dir/foobar.c
No conflicts created by this import'
	  dotest_sort ignore-6 "${testcvs} import -m m -I ! ignore/second-dir tag3 tag4" \
'

N ignore/second-dir/bar.c
N ignore/second-dir/defig.o
N ignore/second-dir/envig.c
N ignore/second-dir/foobar.c
N ignore/second-dir/optig.c
N ignore/second-dir/rootig.c
No conflicts created by this import'
	  cd ..
	  rm -r dir-to-import

	  mkdir 1
	  cd 1
	  dotest ignore-7 "${testcvs} -q co -dsecond-dir ignore/second-dir" \
'U second-dir/bar.c
U second-dir/defig.o
U second-dir/envig.c
U second-dir/foobar.c
U second-dir/optig.c
U second-dir/rootig.c'
	  dotest ignore-8 "${testcvs} -q co -dfirst-dir ignore/first-dir" 'U first-dir/bar.c
U first-dir/foobar.c'
	  cd first-dir
	  touch rootig.c defig.o envig.c optig.c notig.c
	  dotest ignore-9 "${testcvs} -q update -I optig.c" "${QUESTION} notig.c"
	  # The fact that CVS requires us to specify -I CVS here strikes me
	  # as a bug.
	  dotest_sort ignore-10 "${testcvs} -q update -I ! -I CVS" \
"${QUESTION} defig.o
${QUESTION} envig.c
${QUESTION} notig.c
${QUESTION} optig.c
${QUESTION} rootig.c"

	  # Now test that commands other than update also print "? notig.c"
	  # where appropriate.  Only test this for remote, because local
	  # CVS only prints it on update.
	  rm optig.c
	  if $remote; then
	    dotest ignore-11r "$testcvs -q diff" "$QUESTION notig.c"

	    # Force the server to be contacted.  Ugh.  Having CVS
	    # contact the server for the sole purpose of checking
	    # the CVSROOT/cvsignore file does not seem like such a
	    # good idea, so I imagine this will continue to be
	    # necessary.  Oh well, at least we test CVS's ablity to
	    # handle a file with a modified timestamp but unmodified
	    # contents.
	    touch bar.c

	    dotest ignore-11ar "$testcvs -q ci -m commit-it" \
"$QUESTION notig.c"
	  fi

	  # now test .cvsignore files
	  cd ..
	  echo notig.c >first-dir/.cvsignore
	  echo foobar.c >second-dir/.cvsignore
	  touch first-dir/notig.c second-dir/notig.c second-dir/foobar.c
	  dotest_sort ignore-12 "${testcvs} -qn update" \
"${QUESTION} first-dir/.cvsignore
${QUESTION} second-dir/.cvsignore
${QUESTION} second-dir/notig.c"
	  dotest_sort ignore-13 "${testcvs} -qn update -I! -I CVS" \
"${QUESTION} first-dir/.cvsignore
${QUESTION} first-dir/defig.o
${QUESTION} first-dir/envig.c
${QUESTION} first-dir/rootig.c
${QUESTION} second-dir/.cvsignore
${QUESTION} second-dir/notig.c"

	  echo yes | dotest ignore-14 "${testcvs} release -d first-dir" \
"${QUESTION} \.cvsignore
You have \[0\] altered files in this repository.
Are you sure you want to release (and delete) directory .first-dir': "

	  echo add a line >>second-dir/foobar.c
	  rm second-dir/notig.c second-dir/.cvsignore
	  echo yes | dotest ignore-15 "${testcvs} release -d second-dir" \
"M foobar.c
You have \[1\] altered files in this repository.
Are you sure you want to release (and delete) directory .second-dir': "

	  dokeep
	  cd ../..
	  rm -r ignore
	  modify_repo rm -rf $CVSROOT_DIRNAME/ignore
	  ;;



	ignore-on-branch)
	  # Test that CVS _doesn't_ ignore files on branches because they were
	  # added to the trunk.
	  mkdir ignore-on-branch; cd ignore-on-branch
	  modify_repo mkdir $CVSROOT_DIRNAME/ignore-on-branch

	  # create file1 & file2 on trunk
	  dotest ignore-on-branch-setup-1 "$testcvs -q co -dsetup ignore-on-branch" ''
	  cd setup
	  echo file1 >file1 
	  dotest ignore-on-branch-setup-2 "$testcvs -q add file1" \
"${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest ignore-on-branch-setup-3 "$testcvs -q ci -mfile1 file1" \
"$CVSROOT_DIRNAME/ignore-on-branch/file1,v  <--  file1
initial revision: 1\.1"
	  dotest ignore-on-branch-setup-4 "$testcvs -q tag -b branch" 'T file1'
	  echo file2 >file2 
	  dotest ignore-on-branch-setup-5 "$testcvs -q add file2" \
"${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest ignore-on-branch-setup-6 "$testcvs -q ci -mtrunk file2" \
"$CVSROOT_DIRNAME/ignore-on-branch/file2,v  <--  file2
initial revision: 1\.1"

	  cd ..

	  # Check out branch.
	  #
	  # - This was the original failure case - file2 would not be flagged
	  #   with a '?'
	  dotest ignore-on-branch-1 "$testcvs -q co -rbranch ignore-on-branch" \
'U ignore-on-branch/file1'
	  cd ignore-on-branch
	  echo file2 on branch >file2 
	  dotest ignore-on-branch-2 "$testcvs -nq update" '? file2'

	  # Now set up for a join.  One of the original fixes for this would
	  # print out a 'U' and a '?' during a join which added a file.
	  if $remote; then
	    dotest ignore-on-branch-3 "$testcvs -q tag -b branch2" \
'? file2
T file1'
	  else
	    dotest ignore-on-branch-3 "$testcvs -q tag -b branch2" 'T file1'
	  fi
	  dotest ignore-on-branch-4 "$testcvs -q add file2" \
"${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest ignore-on-branch-5 "$testcvs -q ci -mbranch file2" \
"$CVSROOT_DIRNAME/ignore-on-branch/file2,v  <--  file2
new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
	  dotest ignore-on-branch-6 "$testcvs -q up -rbranch2" \
"${SPROG} update: \`file2' is no longer in the repository"
	  dotest ignore-on-branch-7 "$testcvs -q up -jbranch" 'U file2'

	  dokeep
	  cd ../..
	  rm -r ignore-on-branch
	  modify_repo rm -rf $CVSROOT_DIRNAME/ignore-on-branch
	  ;;



	binfiles)
	  # Test cvs's ability to handle binary files.
	  # List of binary file tests:
	  #   * conflicts, "cvs admin": binfiles
	  #   * branching and joining: binfiles2
	  #   * adding and removing files: binfiles3
	  #   * -k wrappers: binwrap, binwrap2, binwrap3
	  #   * "cvs import" and wrappers: binwrap, binwrap2, binwrap3
	  #   * -k option to "cvs import": none yet, as far as I know.
	  modify_repo mkdir $CVSROOT_DIRNAME/first-dir
	  mkdir 1; cd 1
	  dotest binfiles-1 "${testcvs} -q co first-dir" ''
	  ${AWK} 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \
	    </dev/null | ${TR} '@' '\000' >binfile.dat
	  cat binfile.dat binfile.dat >binfile2.dat
	  cd first-dir
	  cp ../binfile.dat binfile
	  dotest binfiles-2 "${testcvs} add -kb binfile" \
"${SPROG}"' add: scheduling file `binfile'\'' for addition
'"${SPROG}"' add: use .'"${SPROG}"' commit. to add this file permanently'
	  dotest binfiles-3 "${testcvs} -q ci -m add-it" \
"$CVSROOT_DIRNAME/first-dir/binfile,v  <--  binfile
initial revision: 1\.1"
	  cd ../..
	  mkdir 2; cd 2
	  dotest binfiles-4 "${testcvs} -q co first-dir" 'U first-dir/binfile'
	  cd first-dir
	  dotest binfiles-5 "cmp ../../1/binfile.dat binfile" ''
	  # Testing that sticky options is -kb is the closest thing we have
	  # to testing that binary files work right on non-unix machines
	  # (until there is automated testing for such machines, of course).
	  dotest binfiles-5.5 "${testcvs} status binfile" \
"===================================================================
File: binfile          	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/binfile,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	-kb"

	  # Test that "-kk" does not override "-kb"
	  cd ../..
	  mkdir 2a; cd 2a
	  dotest binfiles-4 "${testcvs} -q co -kk first-dir" 'U first-dir/binfile'
	  cd first-dir
	  # Testing that sticky options is -kb is the closest thing we have
	  # to testing that binary files work right on non-unix machines
	  # (until there is automated testing for such machines, of course).
	  dotest binfiles-5.5 "${testcvs} status binfile" \
"===================================================================
File: binfile          	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/binfile,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	-kb"

	  # Test whether the default options from the RCS file are
	  # also used when operating on files instead of whole
	  # directories
          cd ../..
	  rm -r 2a
	  mkdir 3; cd 3
	  dotest binfiles-5.5b0 "${testcvs} -q co first-dir/binfile" \
'U first-dir/binfile'
	  cd first-dir
	  dotest binfiles-5.5b1 "${testcvs} status binfile" \
"===================================================================
File: binfile          	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/binfile,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	-kb"
	  cd ../..
	  rm -r 3
	  # test that "-kk" does not override "-kb"
	  mkdir 3; cd 3
	  dotest binfiles-5.5b0 "${testcvs} -q co -kk first-dir/binfile" \
'U first-dir/binfile'
	  cd first-dir
	  dotest binfiles-5.5b1 "${testcvs} status binfile" \
"===================================================================
File: binfile          	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/binfile,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	-kb"
	  cd ../..
	  rm -r 3
	  cd 2/first-dir

	  cp ../../1/binfile2.dat binfile
	  dotest binfiles-6 "${testcvs} -q ci -m modify-it" \
"$CVSROOT_DIRNAME/first-dir/binfile,v  <--  binfile
new revision: 1\.2; previous revision: 1\.1"
	  cd ../../1/first-dir
	  dotest binfiles-7 "${testcvs} -q update" '[UP] binfile'
	  dotest binfiles-8 "cmp ../binfile2.dat binfile" ''

	  # Now test handling of conflicts with binary files.
	  cp ../binfile.dat binfile
	  dotest binfiles-con0 "${testcvs} -q ci -m modify-it" \
"$CVSROOT_DIRNAME/first-dir/binfile,v  <--  binfile
new revision: 1\.3; previous revision: 1\.2"
	  cd ../../2/first-dir
	  echo 'edits in dir 2' >binfile
	  dotest binfiles-con1 "${testcvs} -q update" \
"$SPROG update: nonmergeable file needs merge
$SPROG update: revision 1\.3 from repository is now in binfile
$SPROG update: file from working directory is now in \.#binfile\.1\.2
C binfile"

	  dotest_fail binfiles-con1b "$testcvs -q up" "C binfile"

	  dotest binfiles-con2 "cmp binfile ../../1/binfile.dat" ''
	  dotest binfiles-con3 "cat .#binfile.1.2" 'edits in dir 2'

	  cp ../../1/binfile2.dat binfile
	  dotest binfiles-con4 "$testcvs -q ci -m resolve-it" \
"$CVSROOT_DIRNAME/first-dir/binfile,v  <--  binfile
new revision: 1\.4; previous revision: 1\.3"
	  cd ../../1/first-dir
	  dotest binfiles-con5 "${testcvs} -q update" '[UP] binfile'

	  dotest binfiles-9 "${testcvs} -q update -A" ''
	  # "-kk" no longer does anything with "-kb"
	  dotest binfiles-10 "${testcvs} -q update -kk" ''
	  dotest binfiles-11 "${testcvs} -q update" ''
	  # "-kk" no longer does anything with "-kb"
	  dotest binfiles-12 "${testcvs} -q update -A" ''
	  dotest binfiles-13 "${testcvs} -q update -A" ''

	  cd ../..

	  mkdir 3
	  cd 3
	  dotest binfiles-13a0 "${testcvs} -q co -r HEAD first-dir" \
'U first-dir/binfile'
	  cd first-dir
	  dotest binfiles-13a1 "${testcvs} status binfile" \
"===================================================================
File: binfile          	Status: Up-to-date

   Working revision:	1\.4.*
   Repository revision:	1\.4	${CVSROOT_DIRNAME}/first-dir/binfile,v
   Commit Identifier:	${commitid}
   Sticky Tag:		HEAD (revision: 1\.4)
   Sticky Date:		(none)
   Sticky Options:	-kb"
	  cd ../..
	  rm -r 3

	  cd 2/first-dir
	  echo 'this file is $''RCSfile$' >binfile
	  dotest binfiles-14a "${testcvs} -q ci -m modify-it" \
"$CVSROOT_DIRNAME/first-dir/binfile,v  <--  binfile
new revision: 1\.5; previous revision: 1\.4"
	  dotest binfiles-14b "cat binfile" 'this file is $''RCSfile$'
	  # See binfiles-5.5 for discussion of -kb.
	  dotest binfiles-14c "${testcvs} status binfile" \
"===================================================================
File: binfile          	Status: Up-to-date

   Working revision:	1\.5.*
   Repository revision:	1\.5	${CVSROOT_DIRNAME}/first-dir/binfile,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	-kb"
	  dotest binfiles-14d "${testcvs} admin -kv binfile" \
"RCS file: ${CVSROOT_DIRNAME}/first-dir/binfile,v
done"
	  # cvs admin doesn't change the checked-out file or its sticky
	  # kopts.  There probably should be a way which does (but
	  # what if the file is modified?  And do we try to version
	  # control the kopt setting?)
	  dotest binfiles-14e "cat binfile" 'this file is $''RCSfile$'
	  dotest binfiles-14f "${testcvs} status binfile" \
"===================================================================
File: binfile          	Status: Up-to-date

   Working revision:	1\.5.*
   Repository revision:	1\.5	${CVSROOT_DIRNAME}/first-dir/binfile,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	-kb"
	  dotest binfiles-14g "${testcvs} -q update -A" '[UP] binfile'
	  dotest binfiles-14h "cat binfile" 'this file is binfile,v'
	  dotest binfiles-14i "${testcvs} status binfile" \
"===================================================================
File: binfile          	Status: Up-to-date

   Working revision:	1\.5.*
   Repository revision:	1\.5	${CVSROOT_DIRNAME}/first-dir/binfile,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	-kv"

	  # Do sticky options work when used with 'cvs update'?
	  echo "Not a binary file." > nibfile
	  dotest binfiles-sticky1 "${testcvs} -q add nibfile" \
"${SPROG} add: use .${SPROG} commit. to add this file permanently"
	  dotest binfiles-sticky2 "${testcvs} -q ci -m add-it nibfile" \
"$CVSROOT_DIRNAME/first-dir/nibfile,v  <--  nibfile
initial revision: 1\.1"
	  dotest binfiles-sticky3 "${testcvs} -q update -kb nibfile" \
	    '[UP] nibfile'
	  dotest binfiles-sticky4 "${testcvs} -q status nibfile" \
"===================================================================
File: nibfile          	Status: Up-to-date

   Working revision:	1\.1.*
   Repository revision:	1\.1	${CVSROOT_DIRNAME}/first-dir/nibfile,v
   Commit Identifier:	${commitid}
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	-kb"

	  # Now test that -A can clear the sticky option.
	  dotest binfiles-sticky5 "${testcvs} -q update -A nibfile" \
"[UP] nibfile"
	  dotes