X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=bin%2Flib;h=f0476f2ec699acbdf8f77cc47feb4211a7822a89;hb=107b5e8dc73f0180e2b3f35f8ed031662bbc57fb;hp=a042892982df4ec6fcd0946128333b6b83bb8b41;hpb=0ef7fd9921eb6018b54793ced6592d15979edbc0;p=moe.git diff --git a/bin/lib b/bin/lib index a042892..f0476f2 100644 --- a/bin/lib +++ b/bin/lib @@ -1,5 +1,5 @@ # The Evaluator -- Shell Function Library -# (c) 2001--2004 Martin Mares +# (c) 2001--2008 Martin Mares # General settings shopt -s dotglob @@ -44,6 +44,32 @@ function fatal exit 1 } +function try-ln +{ + ln $1 $2 2>/dev/null || cp $1 $2 +} + +# Expand occurrences of `$var' in a given variable + +function expand-var +{ + eval echo ${!1} +} + +# Given a , override each variable by _ + +function override-vars +{ + local OR V W + declare -a OR + # `${!${1}_@}' does not work, so we have to use eval + OR=($(eval echo '${!'$1'_@}')) + for V in "${OR[@]}" ; do + W=${V##$1_} + eval $W='"$'$V'"' + done +} + # Sandbox subroutines function box-init @@ -52,7 +78,7 @@ function box-init if [ -z "$TEST_USER" -o "$TEST_USER" == $EVAL_USER ] ; then pcont "running locally (INSECURE), " TEST_USER=$EVAL_USER - BOXDIR=box + BOXDIR=`pwd`/box BOXCMD=bin/box mkdir -p box else @@ -99,16 +125,41 @@ EOF pend "OK" } -# Locating source file in SDIR, pass name in SRCN (without path) and extension in SRCEXT +# Locate source file. +# If no parameter is given, locate it in SDIR and return name as SRCN and extension as SRCEXT +# Or a file name can be given and then SDIR, SRCN and SRCEXT are set. +# Beware, SDIR and SRCN can contain spaces and other strange user-supplied characters. function locate-source { pstart "Finding source... " - SBASE=${1:-$PROBLEM} + local SBASE + if [ -n "$1" ] ; then + SDIR=`dirname "$1"` + local S=`basename "$1"` + SBASE=$(echo "$S" | sed 's/\.\([^.]\+\)//') + SRCEXT=$(echo "$S" | sed '/\./!d; s/.*\.\([^.]\+\)/\1/') + if [ -n "$SRCEXT" ] ; then + # Full name given, so just check the extension and existence + SRCN="$S" + [ -f "$SDIR/$SRCN" ] || die "Cannot find source file $SDIR/$SRCN" + SRCEXT_OK= + for a in $EXTENSIONS ; do + if [ $a == $SRCEXT ] ; then + pend $SDIR/$SRCN + echo "Explicitly set source file: $SDIR/$SRCN" + return 0 + fi + done + die "Unknown extension .$SRCEXT" + fi + else + SBASE=$PROBLEM + fi for a in $EXTENSIONS ; do - if [ -f $SDIR/$SBASE.$a ] ; then + if [ -f "$SDIR/$SBASE.$a" ] ; then [ -z "$SRCN" ] || die "Multiple source files found: $SDIR/$PROBLEM.$a and $SDIR/$SRCN. Please fix." - SRCN=$SBASE.$a + SRCN="$SBASE.$a" SRCEXT=$a fi done @@ -122,18 +173,19 @@ function locate-source function compile { pstart "Compiling... " - cp -a $SDIR/$SRCN $TDIR/$SRCN + override-vars "EXT_$SRCEXT" + # Beware, the original SRCN can be a strange user-supplied name + SRC=$PROBLEM.$SRCEXT + cp "$SDIR/$SRCN" $TDIR/$SRC if [ -n "$COMP_EXTRAS" ] ; then echo "Extras: $COMP_EXTRAS" for a in $COMP_EXTRAS ; do cp $PDIR/$a $TDIR/ ; done fi box-clean - for a in $SRCN $COMP_EXTRAS ; do cp $TDIR/$a $BOXDIR/ ; done - SRC=$SRCN + for a in $SRC $COMP_EXTRAS ; do cp $TDIR/$a $BOXDIR/ ; done EXE=$PROBLEM - CCMD=COMP_$SRCEXT - CCMD=`eval echo ${!CCMD}` - COMP_SANDBOX_OPTS=`eval echo $COMP_SANDBOX_OPTS` + CCMD=$(expand-var COMP) + COMP_SANDBOX_OPTS=$(expand-var COMP_SANDBOX_OPTS) echo "Compiler command: $CCMD" echo "Compiler sandbox options: $COMP_SANDBOX_OPTS" eval $COMP_SANDBOX_INIT @@ -164,6 +216,12 @@ function compile # Running of test program according to current task type (returns exit code and TEST_MSG) +function test-config +{ + [ -f $PDIR/$TEST.config ] && . $PDIR/$TEST.config + override-vars "TEST_$TEST" +} + function test-run { test-run-$TASK_TYPE @@ -177,6 +235,31 @@ function test-result P=`cat $TDIR/$TEST.pts` rm $TDIR/$TEST.pts fi + + # Translate signal numbers to readable strings + SG=${M#Caught fatal signal } + SG=${SG#Committed suicide by signal } + if [ "$SG" != "$M" ] ; then + SG=`perl -MConfig -e '@s=split / /,$Config{sig_name}; print $s[$ARGV[0]]' $SG` + [ -z "$SG" ] || M="$M (SIG$SG)" + fi + + # Translate Free Pascal runtime errors to readable strings + RE=${M#Exited with error status } + if [ "$FREE_PASCAL_RTE" == 1 -a "$RE" != "$M" ] ; then + N="Runtime error $RE" + case "$RE" in + 200) M="$N: Division by zero" ;; + 201) M="$N: Range check error" ;; + 202) M="$N: Stack overflow" ;; + 203) M="$N: Heap overflow" ;; + 205) M="$N: Floating point overflow" ;; + 215) M="$N: Arithmetic overflow" ;; + 216) M="$N: Segmentation fault" ;; + ???) M="$N" ;; + esac + fi + echo "Verdict: $M" echo "Points: $P" test-verdict $P "$M" @@ -188,7 +271,7 @@ function test-prolog box-clean echo "Executable file: $TDIR/$PROBLEM" if [ ! -x $TDIR/$PROBLEM ] ; then - test-result 0 "Compile error." + test-result 0 "Compile error" fi cp $TDIR/$PROBLEM $BOXDIR/ BOX_EXTRAS= @@ -196,26 +279,38 @@ function test-prolog OUT_TYPE=${OUT_TYPE:-$IO_TYPE} case $IN_TYPE in file) echo "Input file: $PROBLEM.in (from $PDIR/$TEST.in)" - ln $PDIR/$TEST.in $TDIR/$TEST.in + try-ln $PDIR/$TEST.in $TDIR/$TEST.in cp $PDIR/$TEST.in $BOXDIR/$PROBLEM.in - BOX_EXTRAS="$BOX_EXTRAS -i/dev/null" + [ $TASK_TYPE == interactive ] || BOX_EXTRAS="$BOX_EXTRAS -i/dev/null" ;; stdio) echo "Input file: (from $PDIR/$TEST.in)" - ln $PDIR/$TEST.in $TDIR/$TEST.in - cp $PDIR/$TEST.in $BOXDIR/$PROBLEM.in - BOX_EXTRAS="$BOX_EXTRAS -i$PROBLEM.in" + try-ln $PDIR/$TEST.in $TDIR/$TEST.in + cp $PDIR/$TEST.in $BOXDIR/.stdin + BOX_EXTRAS="$BOX_EXTRAS -i.stdin" ;; none) echo "Input file: " ;; *) die "Unknown IN_TYPE $IN_TYPE" ;; esac + if [ -n "$EV_PEDANT" -a $IN_TYPE != none ] ; then + pcont " " + if [ "$EV_PEDANT" = 1 ] ; then + EV_PEDANT=" " + fi + bin/pedant <$TDIR/$TEST.in >$TDIR/$TEST.pedant $EV_PEDANT + if [ -s $TDIR/$TEST.pedant ] ; then + pend + sed 's/^/\t/' <$TDIR/$TEST.pedant >&2 + pstart -e '\t' + fi + fi case $OUT_TYPE in file) echo "Output file: $PROBLEM.out" - BOX_EXTRAS="$BOX_EXTRAS -o/dev/null" + [ $TASK_TYPE == interactive ] || BOX_EXTRAS="$BOX_EXTRAS -o/dev/null" ;; stdio) echo "Output file: " - BOX_EXTRAS="$BOX_EXTRAS -o$PROBLEM.out" + BOX_EXTRAS="$BOX_EXTRAS -o.stdout" ;; none) echo "Output file: " ;; @@ -234,13 +329,27 @@ function test-epilog echo "Sandbox contents after exit:" ls -Al $BOXDIR case ${OUT_TYPE:-$IO_TYPE} in - file) [ -f $BOXDIR/$PROBLEM.out ] || test-result 0 "No output file." + file) [ -f $BOXDIR/$PROBLEM.out ] || test-result 0 "No output file" cp $BOXDIR/$PROBLEM.out $TDIR/$TEST.out ;; - stdio) [ -f $BOXDIR/$PROBLEM.out ] || test-result 0 "No output file." - cp $BOXDIR/$PROBLEM.out $TDIR/$TEST.out + stdio) [ -f $BOXDIR/.stdout ] || test-result 0 "No output file" + cp $BOXDIR/.stdout $TDIR/$TEST.out ;; esac + + if [ -n "$OUTPUT_FILTER" -a "$OUT_TYPE" != none -a -z "$EV_NOFILTER" ] ; then + pcont " " + FILTER=$(expand-var OUTPUT_FILTER) + echo "Output filter command: $FILTER" + mv $TDIR/$TEST.out $TDIR/$TEST.raw + if ! eval $FILTER 2>$TMPDIR/exec.out ; then + cat $TMPDIR/exec.out + MSG=`tail -1 $TMPDIR/exec.out` + if [ -z "$MSG" ] ; then MSG="Filter failed" ; fi + test-result 0 "$MSG" + fi + cat $TMPDIR/exec.out + fi } # Running of test program with file input/output @@ -249,10 +358,11 @@ function test-run-file { test-prolog pcont " " - BOXOPTS="`eval echo $TEST_SANDBOX_OPTS`$BOX_EXTRAS" + BOXOPTS=$(expand-var TEST_SANDBOX_OPTS) echo "Sandbox options: $BOXOPTS" if ! $BOXCMD $BOXOPTS -- ./$PROBLEM 2>$TMPDIR/exec.out ; then - MSG=`head -1 $TMPDIR/exec.out` + cat $TMPDIR/exec.out + MSG=`tail -1 $TMPDIR/exec.out` test-result 0 "$MSG" fi cat $TMPDIR/exec.out @@ -265,11 +375,12 @@ function test-run-interactive { test-prolog pcont " " - BOXOPTS="`eval echo $TEST_SANDBOX_OPTS`$BOX_EXTRAS" + BOXOPTS=$(expand-var TEST_SANDBOX_OPTS) echo "Sandbox options: $BOXOPTS" - ICCMD=`eval echo $IA_CHECK` + ICCMD=$(expand-var IA_CHECK) echo "Interactive checker: $ICCMD" if ! $HDIR/bin/iwrapper $BOXCMD $BOXOPTS -- ./$PROBLEM @@ $ICCMD 2>$TMPDIR/exec.out ; then + cat $TMPDIR/exec.out MSG="`head -1 $TMPDIR/exec.out`" test-result 0 "$MSG" fi @@ -277,17 +388,27 @@ function test-run-interactive test-epilog } +# "Running" of open-data problems + +function test-run-open-data +{ + [ -f $SDIR/$TEST.out ] || test-result 0 "No solution" + ln $SDIR/$TEST.out $TDIR/$TEST.out +} + # Syntax checks function syntax-check { [ -n "$SYNTAX_CHECK" ] || return 0 + [ -z "$EV_NOCHECK" ] || return 0 pcont " " - SCHECK=`eval echo $SYNTAX_CHECK` + SCHECK=$(expand-var SYNTAX_CHECK) echo "Syntax check command: $SCHECK" if ! eval $SCHECK 2>$TMPDIR/exec.out ; then - MSG=`head -1 $TMPDIR/exec.out` - if [ -z "$MSG" ] ; then MSG="Wrong syntax." ; fi + cat $TMPDIR/exec.out + MSG=`tail -1 $TMPDIR/exec.out` + if [ -z "$MSG" ] ; then MSG="Wrong syntax" ; fi test-result 0 "$MSG" fi cat $TMPDIR/exec.out @@ -297,17 +418,21 @@ function syntax-check function output-check { - [ -n "$OUTPUT_CHECK" ] || return 0 - pcont " " - [ -f $PDIR/$TEST.out ] && ln $PDIR/$TEST.out $TDIR/$TEST.ok - OCHECK=`eval echo $OUTPUT_CHECK` - echo "Output check command: $OCHECK" - if ! eval $OCHECK 2>$TMPDIR/exec.out ; then - MSG=`head -1 $TMPDIR/exec.out` - if [ -z "$MSG" ] ; then MSG="Wrong answer." ; fi - test-result 0 "$MSG" + MSG= + if [ -n "$OUTPUT_CHECK" -a "$OUT_TYPE" != none -a -z "$EV_NOCHECK" ] ; then + pcont " " + [ -f $PDIR/$TEST.out ] && ln $PDIR/$TEST.out $TDIR/$TEST.ok + OCHECK=$(expand-var OUTPUT_CHECK) + echo "Output check command: $OCHECK" + if ! eval $OCHECK 2>$TMPDIR/exec.out ; then + cat $TMPDIR/exec.out + MSG=`tail -1 $TMPDIR/exec.out` + if [ -z "$MSG" ] ; then MSG="Wrong answer" ; fi + test-result 0 "$MSG" + fi + cat $TMPDIR/exec.out + MSG=`tail -1 $TMPDIR/exec.out` fi - MSG=`head -1 $TMPDIR/exec.out` if [ -z "$MSG" ] ; then MSG="OK" ; fi test-result $POINTS_PER_TEST "$MSG" } @@ -316,8 +441,8 @@ function output-check function public-setup { - HDIR=$MO_PUBLIC - PDIR=$MO_PUBLIC/problems/$PROBLEM + HDIR=$MO_ROOT + PDIR=$MO_ROOT/problems/$PROBLEM SDIR=. TDIR=~/.test TMPDIR=~/.test @@ -329,16 +454,22 @@ function public-setup BOXDIR=~/.box mkdir -p $BOXDIR rm -rf $BOXDIR/* - BOXCMD="$MO_PUBLIC/bin/box -c$BOXDIR" - exec >log - pend "OK (see 'log' for details)" + BOXCMD="$MO_ROOT/bin/box -c$BOXDIR" + exec >check-log + pend "OK (see 'check-log' for details)" } # Locate output of open data problem, test case TEST +# Beware, SDIR and SRCN can contain spaces and other strange user-supplied characters. function open-locate { [ -f $PDIR/$TEST.in ] || die "Unknown test $TEST" - SRCN=$SDIR/$PROBLEM$TEST.out - [ -f $SRCN ] || fatal "Output file $SRCN not found" + if [ -n "$1" ] ; then + SDIR=`dirname "$1"` + SRCN=`basename "$1"` + else + SRCN=$SDIR/$PROBLEM$TEST.out + fi + [ -f "$SDIR/$SRCN" ] || fatal "Output file $SRCN not found" }