#! /usr/local/bin/perl
#
# Given:
#	* a program to run (1st arg)
# 	* some "command-line opts" ( -O<opt1> -O<opt2> ... )
#	    [default: anything on the cmd line this script doesn't recognise ]
#	  the first opt not starting w/ "-" is taken to be an input
#	  file and (if it exists) is grepped for "what's going on here"
#	  comments (^--!!!).
#	* a file to feed to stdin ( -i<file> ) [default: /dev/null ]
#	* a "time" command to use (-t <cmd>).
#
#	* alternatively, a "-script <script>" argument says: run the
#   	  named Bourne-shell script to do the test.  It's passed the
#	  pgm-to-run as the one-and-only arg.
#
# Run the program with those options and that input, and check:
# if we get...
# 
# 	* an expected exit status ( -x <val> ) [ default 0 ]
# 	* expected output on stdout ( -o1 <file> ) [ default /dev/null ]
# 	* expected output on stderr ( -o2 <file> ) [ default /dev/null ]
#
#	(if the expected-output files' names end in .Z, then
#	 they are uncompressed before doing the comparison)
# 
# (This is supposed to be a "prettier" replacement for runstdtest.)
#
($Pgm = $0) =~ s|.*/||;
$Verbose = 0;
$Status = 0;
@PgmArgs = ();
$PgmExitStatus = 0;
$PgmStdinFile  = '/dev/null';
$PgmStdoutFile = '/dev/null';
$PgmStderrFile = '/dev/null';
$AltScript = '';
$TimeCmd = '';

die "$Pgm: program to run not given as first argument\n" if $#ARGV < 0;
$ToRun = $ARGV[0]; shift(@ARGV);
# avoid picking up same-named thing from somewhere else on $PATH...
$ToRun = "./$ToRun" if $ToRun !~ /^\//;

arg: while ($_ = $ARGV[0]) {
    shift(@ARGV);
    
    /^-v$/	&& do { $Verbose = 1; next arg; };
    /^-O(.*)/	&& do { push(@PgmArgs, &grab_arg_arg('-O',$1)); next arg; };
    /^-i(.*)/	&& do { $PgmStdinFile = &grab_arg_arg('-i',$1);
			$Status++,
			print STDERR "$Pgm: bogus -i input file: $PgmStdinFile\n"
			    if ! -f $PgmStdinFile;
			next arg; };
    /^-x(.*)/	&& do { $PgmExitStatus = &grab_arg_arg('-x',$1);
			$Status++ ,
			print STDERR "$Pgm: bogus -x expected exit status: $PgmExitStatus\n"
			    if $PgmExitStatus !~ /^\d+$/;
			next arg; };
    /^-o1(.*)/	&& do { $PgmStdoutFile = &grab_arg_arg('-o1',$1);
			$Status++ ,
			print STDERR "$Pgm: bogus -o1 expected-output file: $PgmStdoutFile\n"
			    if ! -f $PgmStdoutFile;
			next arg; };
    /^-o2(.*)/	&& do { $PgmStderrFile = &grab_arg_arg('-o2',$1);
			$Status++,
			print STDERR "$Pgm: bogus -o2 expected-stderr file: $PgmStderrFile\n"
			    if ! -f $PgmStderrFile;
			next arg; };
    /^-script(.*)/ && do { $AltScript = &grab_arg_arg('-script',$1);
			next arg; };
    /^-t(.*)/	&& do { $TimeCmd = &grab_arg_arg('-t', $1); next arg; };

    # anything else is taken to be a pgm arg
    push(@PgmArgs, $_);
}
exit 1 if $Status;

# tidy up the pgm args:
# (1) look for the "first input file"
#     and grep it for "interesting" comments (--!!! )
# (2) quote any args w/ whitespace in them.
$grep_done = 0;
foreach $a ( @PgmArgs ) {
    if (! $grep_done && $a !~ /^-/ && -f $a) {
	print `egrep "^--!!!" $a`;
	$grep_done = 1;
    }
    if ($a =~ /\s/ || $a =~ /'/) {
	$a =~ s/'/\\'/g;    # backslash the quotes;
	$a = "\"$a\"";	    # quote the arg
    }
}

if ($AltScript ne '') {
    local($to_do);
    $to_do = `cat $AltScript`;
    # glue in pgm to run...
    $* = 1;
    $to_do =~ s/^\$1 /$ToRun /;
    &run_something($to_do);
    exit 0;
#    exec "$AltScript $ToRun";
#    print STDERR "Failed to exec!!! $AltScript $ToRun\n";
#    exit 1;
}

# OK, so we're gonna do the normal thing...

$Script = <<EOSCRIPT;
#! /bin/sh
myexit=0
diffsShown=0
$TimeCmd /bin/sh -c \'$ToRun @PgmArgs < $PgmStdinFile 1> $(TMPDIR)/runtest$$.1 2> $(TMPDIR)/runtest$$.2\'
progexit=\$?
if [ \$progexit -ne $PgmExitStatus ]; then
    echo $ToRun @PgmArgs \\< $PgmStdinFile
    echo expected exit status $PgmExitStatus not seen \\; got \$progexit
    myexit=1
else
    if cmp -s $PgmStdoutFile $(TMPDIR)/runtest$$.1 ; then
	echo -n "" # no-op
    else
	echo $ToRun @PgmArgs \\< $PgmStdinFile
	echo expected stdout not matched by reality
	diff -c1 $PgmStdoutFile $(TMPDIR)/runtest$$.1
	myexit=1
	diffsShown=1
    fi
fi
if cmp -s $PgmStderrFile $(TMPDIR)/runtest$$.2 ; then
    echo -n "" # no-op
else
    echo $ToRun @PgmArgs \\< $PgmStdinFile
    echo expected stderr not matched by reality
    diff -c1 $PgmStderrFile $(TMPDIR)/runtest$$.2
    myexit=1
    diffsShown=1
fi
$(RM) core $(TMPDIR)/runtest$$.1 $(TMPDIR)/runtest$$.2
exit \$myexit
EOSCRIPT

&run_something($Script);
# print $Script if $Verbose;
# open(SH, "| /bin/sh") || die "Can't open shell pipe\n";
# print SH $Script;
# close(SH);

exit 0;

sub grab_arg_arg {
    local($option, $rest_of_arg) = @_;
    
    if ($rest_of_arg) {
	return($rest_of_arg);
    } elsif ($#ARGV >= 0) {
	local($temp) = $ARGV[0]; shift(@ARGV); 
	return($temp);
    } else {
	print STDERR "$Pgm: no argument following $option option\n";
	$Status++;
    }
}

sub run_something {
    local($str_to_do) = @_;

    print STDERR "$str_to_do\n" if $Verbose;

    local($return_val) = 0;
    system($str_to_do);
    $return_val = $?;

    if ($return_val != 0) {
#ToDo: this return-value mangling is wrong
#	local($die_msg) = "$Pgm: execution of the $tidy_name had trouble";
#	$die_msg .= " (program not found)" if $return_val == 255;
#	$die_msg .= " ($!)" if $Verbose && $! != 0;
#	$die_msg .= "\n";

	exit (($return_val == 0) ? 0 : 1);
    }
}
