#!/bin/sh

set -e

declare -i exitval=0
declare -i interactive=0
declare -i verbose=0
declare -i exitfail=0

die () { echo $* >&2; exit 1; }

cleanup()
{
    rm -f "$stoppattern" "$scriptfile" "$errfile" "$dir"/stoptest "$dirfile" "$gdbfile"
}

handler_quit () { touch $dir/stoptest; }
trap handler_quit SIGINT
trap handler_quit SIGQUIT 
trap handler_quit SIGTERM 

while getopts "vB:k:d:n:iX:meS:P:" option
do
    case "$option" in
    B) bash_exe="$OPTARG" ;;
    k) known_bugs="$OPTARG" ;;
    P) process_bugs="$OPTARG" ;;
    S) stoplist="$OPTARG" ;;
    d) dir="$OPTARG" ;;
    n) number_of_tests="$OPTARG" ;;
    i) interactive=1 ;;
    X) xpcomp="$OPTARG" ;;
    v) verbose=1 ;;
    e) exitfail=1 ;;
    esac
done

olddir=$(pwd)

if test -n "$bash_exe"; then
    test -x "$bash_exe" || die "not an executable: $bash"
else
    bash_exe=$(which bash)
fi

if test -z "$dir"; then dir=/tmp; fi
if test ! -d "$dir"; then die "No such directory: $dir"; fi
cd $dir
dir=$(pwd)
cd $olddir

if test "$process_bugs"
then
    if test ! -x "$process_bugs"
    then 
	die "Not found: $process_bugs"
    else
	cd "$(dirname $process_bugs)"
	process_bugs="$(pwd)/$(basename $process_bugs)"
	cd "$olddir"
    fi
    test -n "$known_bugs" || known_bugs=$dir/known_bugs
    if test ! -d "$known_bugs"
    then 
	die "No such directory: $known_bugs"
    else
	cd "$known_bugs"
	known_bugs=$(pwd)
	cd "$olddir"
    fi
fi

scriptfile="$dir"/script$$
errfile="$dir"/err$$
stoppattern="$dir"/stoppattern$$
dirfile="$dir"/dirlist$$

cleanup

test $interactive -eq 1 && bash_args=-i

bash_args="$bash_args <$scriptfile 2>>$errfile >&2"

find /home/ingo/texte -type d 2>/dev/null | awk "BEGIN {srand()} {printf \"%08i %s\n\", rand()*100000000 ,\$1}" | sort | cut -c10- > "$dirfile"

if test -n "$GDB"; then
    gdbfile=$dir/gdb$$
    cat <<EOF > $gdbfile
set confirm off
disable
file $bash_exe
set symbol-reloading on
EOF
    cat <<EOF >> $gdbfile
run $bash_args
enable
set confirm on
handle SIGINT pass nostop
handle SIGQUIT pass nostop
EOF
fi

echo "\
$0: Each testing cycle is going to ignore the controlling terminal.
So if you hit ^C or ^\ to stop, it may take a while until the current 
test cycle is finished and the test script can exit."

declare -i loop=0
declare -i dir_no=1

while test ! -f "$dir/stoptest"
do
    test_dir=$(tail +$dir_no "$dirfile" | head -1)
    dir_no=$(($dir_no+1))
    if test -z "$test_dir"
    then
	dir_no=0
	continue
    fi

    loop=$(($loop+1))
    timestamp=$(date +%Y-%m-%d_%H:%M:%S)

    rm -f "$errfile"
    
    if test $verbose -eq 1
    then
	touch "$errfile"
	tail -f "$errfile" &
    else
	printf "\r%4i.  %s  %-50.50s" $loop $timestamp "$test_dir"
    fi

    if test ! -x "$test_dir"
    then
	loop=$(($loop-1))
	continue
    fi

    cat  > "$scriptfile" << EOF
# this is the ubiquitous self-feeding xpcomp test script
# (created by $0 pid=$$ on $(date -R))

test_dir=$test_dir
unset PROMPT_COMMAND
trap '' SIGINT
trap '' SIGQUIT 
set -o emacs
bind 'set completion-query-items 99999'
bind 'set show-all-if-ambiguous on'
bind 'set bell-style none'
bind 'set page-completions off'

enable -f $xpcomp xpcomptest
xpcomptest random
# before feeding this script to bash -i on stdin
# comment the two previous lines and uncomment the following line:
#xpcomptest() { :; }

# starting test
EOF

    exitval=0
    rm -f $errfile
    if test -z "$GDB"; then
	eval "$bash_exe $bash_args" || exitval=$?
    else
	${GDB} -q --command=$gdbfile
    fi 2>/dev/null
    cd $olddir

    tail +20 "$errfile" | grep -a -F -f "$stoplist" > "$stoppattern" || true

    if test $exitval -eq 0 -a ! -s "$stoppattern"
    then 
	continue
    fi

    savedir="$dir"/$timestamp
    mkdir "$savedir"

    echo "$test_dir" > "$savedir"/testdir
    if test $exitval -ne 0; then echo $exitval > "$savedir"/exitval; fi
    if test -s $stoppattern; then cp $stoppattern "$savedir"/stoppattern; fi
    cp $errfile "$savedir"/err
    cp $scriptfile "$savedir"/script

    rm -f $stoppattern
    if test -n "$process_bugs"
    then
	printf "\r%79s\r%4i.  " '' $loop
	cd "$dir"
	eval "$process_bugs '$known_bugs' '$timestamp'"
	cd "$olddir"
    fi
    if test $exitfail -eq 1; then cleanup; echo; exit $exitval; fi
done

if test $exitval -eq 0; then echo; fi
cleanup
exit 0
