1 # The Evaluator -- Shell Function Library
2 # (c) 2001--2008 Martin Mares <mj@ucw.cz>
8 # File handles used: fd1=log, fd2=progress
33 # Report an internal error
35 [ -n "$HAVE_LOG" ] && echo "Fatal error: $@"
41 # Report a fatal error in the program being tested
43 [ -n "$HAVE_LOG" ] && echo "Fatal error: $@"
49 ln $1 $2 2>/dev/null || cp $1 $2
52 # Given a <prefix>, override each variable <x> by <prefix>_<x>
54 function override-vars
60 OR=($(set | sed "s/^$1_//;t;d")) || true
62 for V in "${OR[@]}" ; do
71 pstart "Preparing sandbox... "
72 if [ -z "$TEST_USER" -o "$TEST_USER" == $EVAL_USER ] ; then
73 pcont "running locally (INSECURE), "
79 pcont "used account $TEST_USER, "
80 BOXDIR=$MO_ROOT/eval/$TEST_USER
81 BOXCMD=bin/box-$TEST_USER
83 [ -d $BOXDIR -a -f $BOXCMD ] || die "Sandbox set up incorrectly"
84 BOXCMD="$BOXCMD -c$BOXDIR"
85 echo "Sandbox directory: $BOXDIR"
86 echo "Sandbox command: $BOXCMD"
93 [ -n "$BOXCMD" ] || die "box-init not called"
97 # Initialization of testing directories
101 pstart "Initializing... "
103 PDIR=problems/$PROBLEM
104 SDIR=solutions/$CONTESTANT/$PROBLEM
105 TDIR=testing/$CONTESTANT/$PROBLEM
107 [ -d $PDIR ] || die "Problem $PROBLEM not known"
108 [ -d $SDIR ] || fatal "Solution of $PROBLEM not found"
109 mkdir -p $TDIR $TMPDIR
111 mkdir -p $TDIR $TMPDIR
113 Testing solution of $PROBLEM by $CONTESTANT
114 Test started at `date`
115 Contestant's solution directory: $SDIR
116 Problem directory: $PDIR
117 Testing directory: $TDIR
122 # Locate source file.
123 # If no parameter is given, locate it in SDIR and return name as SRCN and extension as SRCEXT
124 # Or a file name can be given and then SDIR, SRCN and SRCEXT are set.
125 # Beware, SDIR and SRCN can contain spaces and other strange user-supplied characters.
127 function locate-source
129 pstart "Finding source... "
131 if [ -n "$1" ] ; then
133 local S=`basename "$1"`
134 SBASE=$(echo "$S" | sed 's/\.\([^.]\+\)//')
135 SRCEXT=$(echo "$S" | sed '/\./!d; s/.*\.\([^.]\+\)/\1/')
136 if [ -n "$SRCEXT" ] ; then
137 # Full name given, so just check the extension and existence
139 [ -f "$SDIR/$SRCN" ] || die "Cannot find source file $SDIR/$SRCN"
141 for a in $EXTENSIONS ; do
142 if [ $a == $SRCEXT ] ; then
144 echo "Explicitly set source file: $SDIR/$SRCN"
148 die "Unknown extension .$SRCEXT"
153 for a in $EXTENSIONS ; do
154 if [ -f "$SDIR/$SBASE.$a" ] ; then
155 [ -z "$SRCN" ] || die "Multiple source files found: $SDIR/$PROBLEM.$a and $SDIR/$SRCN. Please fix."
160 [ -n "$SRCN" ] || fatal "NOT FOUND"
162 echo "Found source file: $SDIR/$SRCN"
165 # Compilation (compile SDIR/SRCN with PDIR/COMP_EXTRAS to EXE=TDIR/PROBLEM)
169 pstart "Compiling... "
170 override-vars "EXT_$SRCEXT"
171 # Beware, the original SRCN can be a strange user-supplied name
173 cp "$SDIR/$SRCN" $TDIR/$SRC
174 if [ -n "$COMP_EXTRAS" ] ; then
175 echo "Extras: $COMP_EXTRAS"
176 for a in $COMP_EXTRAS ; do cp $PDIR/$a $TDIR/ ; done
179 for a in $SRC $COMP_EXTRAS ; do cp $TDIR/$a $BOXDIR/ ; done
182 CCMD=`eval echo ${!CCMD}`
183 COMP_SANDBOX_OPTS=`eval echo $COMP_SANDBOX_OPTS`
184 echo "Compiler command: $CCMD"
185 echo "Compiler sandbox options: $COMP_SANDBOX_OPTS"
186 eval $COMP_SANDBOX_INIT
188 echo "Compiler input files:"
190 echo "Compiler output:"
191 if ! $BOXCMD $COMP_SANDBOX_OPTS -- $CCMD 2>$TDIR/compile.out ; then
192 COMPILE_MSG="`cat $TDIR/compile.out`"
193 pend "FAILED: $COMPILE_MSG"
197 cat $TDIR/compile.out
199 echo "Compiler output files:"
201 if [ ! -f $BOXDIR/$PROBLEM ] ; then
202 pend "FAILED: Missing executable file"
203 echo "Missing executable file"
207 cp -a $BOXDIR/$PROBLEM $EXE
208 echo "Compiled OK, result copied to $EXE"
212 # Running of test program according to current task type (returns exit code and TEST_MSG)
216 [ -f $PDIR/$TEST.config ] && . $PDIR/$TEST.config
217 override-vars "TEST_$TEST"
229 if [ -s $TDIR/$TEST.pts ] ; then
230 P=`cat $TDIR/$TEST.pts`
234 # Translate signal numbers to readable strings
235 SG=${M#Caught fatal signal }
236 SG=${SG#Committed suicide by signal }
237 if [ "$SG" != "$M" ] ; then
238 SG=`perl -MConfig -e '@s=split / /,$Config{sig_name}; print $s[$ARGV[0]]' $SG`
239 [ -z "$SG" ] || M="$M (SIG$SG)"
242 # Translate Free Pascal runtime errors to readable strings
243 RE=${M#Exited with error status }
244 if [ "$FREE_PASCAL_RTE" == 1 -a "$RE" != "$M" ] ; then
245 N="Runtime error $RE"
247 200) M="$N: Division by zero" ;;
248 201) M="$N: Range check error" ;;
249 202) M="$N: Stack overflow" ;;
250 203) M="$N: Heap overflow" ;;
251 205) M="$N: Floating point overflow" ;;
252 215) M="$N: Arithmetic overflow" ;;
253 216) M="$N: Segmentation fault" ;;
267 echo "Executable file: $TDIR/$PROBLEM"
268 if [ ! -x $TDIR/$PROBLEM ] ; then
269 test-result 0 "Compile error"
271 cp $TDIR/$PROBLEM $BOXDIR/
273 IN_TYPE=${IN_TYPE:-$IO_TYPE}
274 OUT_TYPE=${OUT_TYPE:-$IO_TYPE}
276 file) echo "Input file: $PROBLEM.in (from $PDIR/$TEST.in)"
277 try-ln $PDIR/$TEST.in $TDIR/$TEST.in
278 cp $PDIR/$TEST.in $BOXDIR/$PROBLEM.in
279 [ $TASK_TYPE == interactive ] || BOX_EXTRAS="$BOX_EXTRAS -i/dev/null"
281 stdio) echo "Input file: <stdin> (from $PDIR/$TEST.in)"
282 try-ln $PDIR/$TEST.in $TDIR/$TEST.in
283 cp $PDIR/$TEST.in $BOXDIR/.stdin
284 BOX_EXTRAS="$BOX_EXTRAS -i.stdin"
286 none) echo "Input file: <none>"
288 *) die "Unknown IN_TYPE $IN_TYPE"
291 if [ -n "$EV_PEDANT" -a $IN_TYPE != none ] ; then
293 if [ "$EV_PEDANT" = 1 ] ; then
296 bin/pedant <$TDIR/$TEST.in >$TDIR/$TEST.pedant $EV_PEDANT
297 if [ -s $TDIR/$TEST.pedant ] ; then
299 sed 's/^/\t/' <$TDIR/$TEST.pedant >&2
304 file) echo "Output file: $PROBLEM.out"
305 [ $TASK_TYPE == interactive ] || BOX_EXTRAS="$BOX_EXTRAS -o/dev/null"
307 stdio) echo "Output file: <stdout>"
308 BOX_EXTRAS="$BOX_EXTRAS -o.stdout"
310 none) echo "Output file: <none>"
312 *) die "Unknown OUT_TYPE $OUT_TYPE"
315 echo "Timeout: $TIME_LIMIT s"
316 echo "Memory: $MEM_LIMIT KB"
318 echo "Sandbox contents before start:"
324 echo "Sandbox contents after exit:"
326 case ${OUT_TYPE:-$IO_TYPE} in
327 file) [ -f $BOXDIR/$PROBLEM.out ] || test-result 0 "No output file"
328 cp $BOXDIR/$PROBLEM.out $TDIR/$TEST.out
330 stdio) [ -f $BOXDIR/.stdout ] || test-result 0 "No output file"
331 cp $BOXDIR/.stdout $TDIR/$TEST.out
335 if [ -n "$OUTPUT_FILTER" -a "$OUT_TYPE" != none -a -z "$EV_NOFILTER" ] ; then
337 FILTER=`eval echo \"$OUTPUT_FILTER\"`
338 echo "Output filter command: $FILTER"
339 mv $TDIR/$TEST.out $TDIR/$TEST.raw
340 if ! eval $FILTER 2>$TMPDIR/exec.out ; then
342 MSG=`tail -1 $TMPDIR/exec.out`
343 if [ -z "$MSG" ] ; then MSG="Filter failed" ; fi
350 # Running of test program with file input/output
352 function test-run-file
356 BOXOPTS="`eval echo $TEST_SANDBOX_OPTS`$BOX_EXTRAS"
357 echo "Sandbox options: $BOXOPTS"
358 if ! $BOXCMD $BOXOPTS -- ./$PROBLEM 2>$TMPDIR/exec.out ; then
360 MSG=`tail -1 $TMPDIR/exec.out`
367 # Running of interactive test programs
369 function test-run-interactive
373 BOXOPTS="`eval echo $TEST_SANDBOX_OPTS`$BOX_EXTRAS"
374 echo "Sandbox options: $BOXOPTS"
375 ICCMD=`eval echo $IA_CHECK`
376 echo "Interactive checker: $ICCMD"
377 if ! $HDIR/bin/iwrapper $BOXCMD $BOXOPTS -- ./$PROBLEM @@ $ICCMD 2>$TMPDIR/exec.out ; then
379 MSG="`head -1 $TMPDIR/exec.out`"
386 # "Running" of open-data problems
388 function test-run-open-data
390 [ -f $SDIR/$TEST.out ] || test-result 0 "No solution"
391 ln $SDIR/$TEST.out $TDIR/$TEST.out
396 function syntax-check
398 [ -n "$SYNTAX_CHECK" ] || return 0
399 [ -z "$EV_NOCHECK" ] || return 0
401 SCHECK=`eval echo \"$SYNTAX_CHECK\"`
402 echo "Syntax check command: $SCHECK"
403 if ! eval $SCHECK 2>$TMPDIR/exec.out ; then
405 MSG=`tail -1 $TMPDIR/exec.out`
406 if [ -z "$MSG" ] ; then MSG="Wrong syntax" ; fi
414 function output-check
417 if [ -n "$OUTPUT_CHECK" -a "$OUT_TYPE" != none -a -z "$EV_NOCHECK" ] ; then
419 [ -f $PDIR/$TEST.out ] && ln $PDIR/$TEST.out $TDIR/$TEST.ok
420 OCHECK=`eval echo \"$OUTPUT_CHECK\"`
421 echo "Output check command: $OCHECK"
422 if ! eval $OCHECK 2>$TMPDIR/exec.out ; then
424 MSG=`tail -1 $TMPDIR/exec.out`
425 if [ -z "$MSG" ] ; then MSG="Wrong answer" ; fi
429 MSG=`tail -1 $TMPDIR/exec.out`
431 if [ -z "$MSG" ] ; then MSG="OK" ; fi
432 test-result $POINTS_PER_TEST "$MSG"
435 # Setup of public commands
437 function public-setup
440 PDIR=$MO_ROOT/problems/$PROBLEM
444 [ -d $PDIR ] || die "Unknown problem $PROBLEM"
446 pstart "Initializing... "
452 BOXCMD="$MO_ROOT/bin/box -c$BOXDIR"
454 pend "OK (see 'check-log' for details)"
457 # Locate output of open data problem, test case TEST
458 # Beware, SDIR and SRCN can contain spaces and other strange user-supplied characters.
462 [ -f $PDIR/$TEST.in ] || die "Unknown test $TEST"
463 if [ -n "$1" ] ; then
467 SRCN=$SDIR/$PROBLEM$TEST.out
469 [ -f "$SDIR/$SRCN" ] || fatal "Output file $SRCN not found"