]> mj.ucw.cz Git - moe.git/blobdiff - bin/lib
Use per-extension overrides for setting of compilation commands.
[moe.git] / bin / lib
diff --git a/bin/lib b/bin/lib
index faf6d038d830561453d4a53395beaae29a398f4f..981b01002a93e3ae4544d19285786059732d5148 100644 (file)
--- a/bin/lib
+++ b/bin/lib
@@ -1,5 +1,5 @@
 # The Evaluator -- Shell Function Library
-# (c) 2001--2004 Martin Mares <mj@ucw.cz>
+# (c) 2001--2008 Martin Mares <mj@ucw.cz>
 
 # General settings
 shopt -s dotglob
@@ -44,6 +44,26 @@ function fatal
        exit 1
 }
 
+function try-ln
+{
+       ln $1 $2 2>/dev/null || cp $1 $2
+}
+
+# Given a <prefix>, override each variable <x> by <prefix>_<x>
+
+function override-vars
+{
+       local OR V OLDIFS
+       declare -a OR
+       OLDIFS="$IFS"
+       IFS=$'\n'
+       OR=($(set | sed "s/^$1_//;t;d")) || true
+       IFS="$OLDIFS"
+       for V in "${OR[@]}" ; do
+               eval "$V"
+       done
+}
+
 # Sandbox subroutines
 
 function box-init
@@ -52,7 +72,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,21 +119,23 @@ 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... "
+       local SBASE
        if [ -n "$1" ] ; then
-               SRCBASE=$(echo $1 | sed 's/\.\([^.]\+\)//')
-               SRCEXT=$(echo $1 | sed 's/.*\.\([^.]\+\)/\1/')
+               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=$1
-                       if [ ${SRCN:0:1} == / ] ; then
-                               SRCN=${SRCN:1}
-                               SDIR=
-                       fi
+                       SRCN="$S"
                        [ -f "$SDIR/$SRCN" ] || die "Cannot find source file $SDIR/$SRCN"
                        SRCEXT_OK=
                        for a in $EXTENSIONS ; do
@@ -129,9 +151,9 @@ function locate-source
                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
@@ -145,9 +167,10 @@ function locate-source
 function compile
 {
        pstart "Compiling... "
+       override-vars "EXT_$SRCEXT"
        # Beware, the original SRCN can be a strange user-supplied name
        SRC=$PROBLEM.$SRCEXT
-       cp -a $SDIR/$SRCN $TDIR/$SRC
+       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
@@ -155,8 +178,7 @@ function compile
        box-clean
        for a in $SRC $COMP_EXTRAS ; do cp $TDIR/$a $BOXDIR/ ; done
        EXE=$PROBLEM
-       CCMD=COMP_$SRCEXT
-       CCMD=`eval echo ${!CCMD}`
+       CCMD=`eval echo $COMP`
        COMP_SANDBOX_OPTS=`eval echo $COMP_SANDBOX_OPTS`
        echo "Compiler command: $CCMD"
        echo "Compiler sandbox options: $COMP_SANDBOX_OPTS"
@@ -188,6 +210,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
@@ -201,6 +229,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"
@@ -212,7 +265,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=
@@ -220,12 +273,12 @@ 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: <stdin> (from $PDIR/$TEST.in)"
-                       ln $PDIR/$TEST.in $TDIR/$TEST.in
+                       try-ln $PDIR/$TEST.in $TDIR/$TEST.in
                        cp $PDIR/$TEST.in $BOXDIR/.stdin
                        BOX_EXTRAS="$BOX_EXTRAS -i.stdin"
                        ;;
@@ -234,9 +287,21 @@ function test-prolog
                *)      die "Unknown IN_TYPE $IN_TYPE"
                        ;;
        esac
+       if [ -n "$EV_PEDANT" -a $IN_TYPE != none ] ; then
+               pcont "<pedant> "
+               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: <stdout>"
                        BOX_EXTRAS="$BOX_EXTRAS -o.stdout"
@@ -258,13 +323,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/.stdout ] || test-result 0 "No output file."
+               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> "
+               FILTER=`eval echo \"$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
@@ -296,25 +375,34 @@ function test-run-interactive
        echo "Interactive checker: $ICCMD"
        if ! $HDIR/bin/iwrapper $BOXCMD $BOXOPTS -- ./$PROBLEM @@ $ICCMD 2>$TMPDIR/exec.out ; then
                cat $TMPDIR/exec.out
-               MSG="`tail -1 $TMPDIR/exec.out`"
+               MSG="`head -1 $TMPDIR/exec.out`"
                test-result 0 "$MSG"
        fi
        cat $TMPDIR/exec.out
        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 "<syntax> "
-       SCHECK=`eval echo $SYNTAX_CHECK`
+       SCHECK=`eval echo \"$SYNTAX_CHECK\"`
        echo "Syntax check command: $SCHECK"
        if ! eval $SCHECK 2>$TMPDIR/exec.out ; then
                cat $TMPDIR/exec.out
                MSG=`tail -1 $TMPDIR/exec.out`
-               if [ -z "$MSG" ] ; then MSG="Wrong syntax." ; fi
+               if [ -z "$MSG" ] ; then MSG="Wrong syntax" ; fi
                test-result 0 "$MSG"
        fi
        cat $TMPDIR/exec.out
@@ -324,19 +412,21 @@ function syntax-check
 
 function output-check
 {
-       [ -n "$OUTPUT_CHECK" ] || return 0
-       pcont "<check> "
-       [ -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=
+       if [ -n "$OUTPUT_CHECK" -a "$OUT_TYPE" != none -a -z "$EV_NOCHECK" ] ; then
+               pcont "<check> "
+               [ -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
+                       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`
-               if [ -z "$MSG" ] ; then MSG="Wrong answer." ; fi
-               test-result 0 "$MSG"
        fi
-       cat $TMPDIR/exec.out
-       MSG=`tail -1 $TMPDIR/exec.out`
        if [ -z "$MSG" ] ; then MSG="OK" ; fi
        test-result $POINTS_PER_TEST "$MSG"
 }
@@ -359,19 +449,21 @@ function public-setup
        mkdir -p $BOXDIR
        rm -rf $BOXDIR/*
        BOXCMD="$MO_ROOT/bin/box -c$BOXDIR"
-       exec >log
-       pend "OK  (see 'log' for details)"
+       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"
        if [ -n "$1" ] ; then
-               SRCN=$1
+               SDIR=`dirname "$1"`
+               SRCN=`basename "$1"`
        else
                SRCN=$SDIR/$PROBLEM$TEST.out
        fi
-       [ -f $SRCN ] || fatal "Output file $SRCN not found"
+       [ -f "$SDIR/$SRCN" ] || fatal "Output file $SRCN not found"
 }