#!/bin/sh

#  This file is part of GNU c++-suite.
#  
#  GNU c++-suite 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 1, or (at your option)
#  any later version.
#  
#  GNU c++-suite is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#  
#  You should have received a copy of the GNU General Public License
#  along with GNU c++-suite; see the file COPYING.  If not, write to
#  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

pname=`basename $0`

current_dir=`pwd`
test_class=`basename ${current_dir}`

if [ "x${COMPILER}" = "x" ] ; then
	echo $pname\: must define environment variable COMPILER
	exit 1
fi

if [ "x${VERBOSE}" = "x" ] ; then
	echo $pname\: must define environment variable VERBOSE
	exit 1
fi

if [ "x${COMPILER_DIR}" != "x" ] ; then
	compile_cmd="${COMPILER_DIR}${COMPILER} -B${COMPILER_DIR}"
	link_search="-L${COMPILER_DIR}"
else
	compile_cmd="${COMPILER}"
	link_search=""
fi

script_args="$*"

very_verbose_flag=0
test_verbose_flag=0
keep_failed_flag=0
keep_all_flag=0

num_src_files=0
src_files=''
for this_arg in ${script_args}; do
	case ${this_arg} in
	-V)
		very_verbose_flag=1
		test_verbose_flag=1
		;;
	-v)
		test_verbose_flag=1
		;;
	-K)
		keep_all_flag=1
		;;
	-k)
		keep_failed_flag=1
		;;
	-*)
		echo invalid option\: ${this_arg}
		exit 1
		;;
	*)
		num_src_files=`expr ${num_src_files} + 1`
		if [ `basename ${this_arg} .C`.C = `basename ${this_arg}` ] ; then
			echo ERROR\: test names cannot end in .C
		else
			src_files="${src_files} ${this_arg}.C"
		fi
		;;
	esac
done

if [ ${num_src_files} -eq 0 ] ; then
	src_files=`find * -name \*.C -print`
fi

for src_file in ${src_files}; do
	root=`basename ${src_file} .C`
	unset -u
	rm -f ${root} ${root}.o ${root}.s a.out C++.hack* core ${root}.*_log ${root}.*_msgs ${root}.*_lines_*
	set -u
	test_passed=0
	gppflags="`fgrep 'Options:' ${src_file} | sed 's%^.*Options:%%'`"
	if [ ${very_verbose_flag} -eq 1 ] ; then
		comp_verbose="${VERBOSE}"
	else
		comp_verbose=''
	fi
	if [ ${test_verbose_flag} -ne 0 ] ; then
		echo ${compile_cmd} ${gppflags} ${comp_verbose} -S ${src_file}
	fi
	if ${compile_cmd} ${gppflags} ${comp_verbose} -S ${src_file} > ${root}.compile_log 2>&1; then
		compile_status=0
	else
		compile_status=1
	fi
	if [ ${very_verbose_flag} -ne 0 ] ; then
		cat ${root}.compile_log
	fi
	if [ `fgrep 'got fatal signal' ${root}.compile_log | wc -l` -ne 0 ] ; then
		echo ${root}\: FAILED `fgrep 'got fatal signal' ${root}.compile_log | sed 's/^.*: //'`
		new_test_class='fake_for_cleanup'
	else
		new_test_class=${test_class}
	fi
	case ${new_test_class} in
	a | c )
		if [ ${compile_status} -ne 0 ] ; then
			echo ${root}\: FAILED compilation
		else
			if [ ${test_verbose_flag} -ne 0 ] ; then
				echo ${compile_cmd} ${gppflags} ${comp_verbose} -c ${root}.s
			fi
			if ${compile_cmd} ${gppflags} ${comp_verbose} -c ${root}.s > ${root}.asm_log 2>&1; then
				assemble_status=0
			else
				assemble_status=1
			fi
			if [ ${very_verbose_flag} -ne 0 ] ; then
				cat ${root}.asm_log
			fi
			if [ ${assemble_status} -ne 0 ] ; then
				echo ${root}\: FAILED assembly
			else
				if [ ${test_verbose_flag} -ne 0 ] ; then
					echo ${compile_cmd} ${gppflags} ${comp_verbose} ${link_search} ${root}.o -o ${root}
				fi
				if ${compile_cmd} ${gppflags} ${comp_verbose} ${link_search} ${root}.o -o ${root} > ${root}.link_log 2>&1; then
					link_status=0
				else
					link_status=1
				fi
				if [ ${very_verbose_flag} -ne 0 ] ; then
					cat ${root}.link_log
				fi
				if [ \( ${link_status} -ne 0 \) -o \( \! -x ${root} \) ] ; then
					echo ${root}\: FAILED linking
				else
					if [ ${test_verbose_flag} -ne 0 ] ; then
						echo ./${root}
					fi
					if ./${root} > ${root}.exec_log 2>&1; then
						exec_status=0
					else
						exec_status=1
					fi
					if [ ${very_verbose_flag} -ne 0 ] ; then
						cat ${root}.exec_log
					fi
					if [ ${exec_status} -ne 0 ] ; then
						echo ${root}\: FAILED execution
					else
						echo ${root}\: PASSED
						test_passed=1
					fi
				fi
			fi
		fi
		;;

	b)
		fgrep -n 'ERROR' ${src_file} | sed 's/:.*$//' > ${root}.err_lines_expected
		grep '^'${src_file}':[0-9]*:' ${root}.compile_log \
			| grep -v ':[0-9]*: warning:' > ${root}.err_msgs
		awk -F: '{print $2}' ${root}.err_msgs | sort -u -n > ${root}.err_lines_got
		diff ${root}.err_lines_expected ${root}.err_lines_got > ${root}.err_lines_diffs
		missed_err_lines="`grep '^<' ${root}.err_lines_diffs | sed 's/^< //'`"
		if [ ${test_verbose_flag} -ne 0 ] ; then
			excess_err_lines="`grep '^>' ${root}.err_lines_diffs | sed 's/^> //'`"
			if [ `echo ${excess_err_lines} | wc -w` -ne 0 ] ; then
				echo ${root} 'had excess error(s) as follows:'
				for line in ${excess_err_lines}; do
					grep '^'${src_file}':'${line}':' ${root}.err_msgs | sed 's/^/	/'
				done
			fi
		fi
		if [ `echo ${missed_err_lines} | wc -w` -ne 0 ] ; then
			if [ ${test_verbose_flag} -ne 0 ] ; then
				echo ${root} 'had missed error(s) as follows:'
				for line in ${missed_err_lines}; do
					awk "NR == ${line} {printf "'"\t%4d: "'", ${line} } NR == ${line} {print}" ${src_file}
				done
			fi
			echo $root\: FAILED
		else
			echo $root\: PASSED
			test_passed=1
		fi
		;;

	w)
		fgrep -n 'WARNING' ${src_file} | sed 's/:.*$//' > ${root}.warn_lines_expected
		grep '^'${src_file}':[0-9]*:' ${root}.compile_log \
			| grep ':[0-9]*: warning:' > ${root}.warn_msgs
		awk -F: '{print $2}' ${root}.warn_msgs | sort -u -n > ${root}.warn_lines_got
		diff ${root}.warn_lines_expected ${root}.warn_lines_got > ${root}.warn_lines_diffs
		missed_warn_lines="`grep '^<' ${root}.warn_lines_diffs | sed 's/^< //'`"
		if [ ${test_verbose_flag} -ne 0 ] ; then
			excess_warn_lines="`grep '^>' ${root}.warn_lines_diffs | sed 's/^> //'`"
			if [ `echo ${excess_warn_lines} | wc -w` -ne 0 ] ; then
				echo ${root} 'had excess warning(s) as follows:'
				for line in ${excess_warn_lines}; do
					grep '^'${src_file}':'${line}':' ${root}.warn_msgs | sed 's/^/	/'
				done
			fi
		fi
		if [ `echo ${missed_warn_lines} | wc -w` -ne 0 ] ; then
			if [ ${test_verbose_flag} -ne 0 ] ; then
				echo ${root} 'had missed warning(s) as follows:'
				for line in ${missed_warn_lines}; do
					awk "NR == ${line} {printf "'"\t%4d: "'", ${line} } NR == ${line} {print}" ${src_file}
				done
			fi
			echo $root\: FAILED
		else
			echo $root\: PASSED
			test_passed=1
		fi
		;;

	fake_for_cleanup)
		;;

	*)
		echo ERROR\: invalid test class ${test_class}
		;;
	esac
	if [ \( ${keep_all_flag} -eq 0 \) -a \( \( ${keep_failed_flag} -eq 0 \) -o \( ${test_passed} -eq 1 \) \) ] ; then
		unset -u
		rm -f ${root} ${root}.o ${root}.s a.out C++.hack* core ${root}.*_log ${root}.*_msgs ${root}.*_lines_*
		set -u
	fi
done
