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 # Expand occurrences of `$var' in a given variable
59 # Given a <prefix>, override each variable <x> by <prefix>_<x>
61 function override-vars
65 # `${!${1}_@}' does not work, so we have to use eval
66 OR=($(eval echo '${!'$1'_@}'))
67 for V in "${OR[@]}" ; do
77 pstart "Preparing sandbox... "
78 if [ -z "$TEST_USER" -o "$TEST_USER" == $EVAL_USER ] ; then
79 pcont "running locally (INSECURE), "
85 pcont "used account $TEST_USER, "
86 BOXDIR=$MO_ROOT/eval/$TEST_USER
87 BOXCMD=bin/box-$TEST_USER
89 [ -d $BOXDIR -a -f $BOXCMD ] || die "Sandbox set up incorrectly"
90 BOXCMD="$BOXCMD -c$BOXDIR"
91 echo "Sandbox directory: $BOXDIR"
92 echo "Sandbox command: $BOXCMD"
99 [ -n "$BOXCMD" ] || die "box-init not called"
103 # Initialization of testing directories
107 pstart "Initializing... "
109 PDIR=problems/$PROBLEM
110 SDIR=solutions/$CONTESTANT/$PROBLEM
111 TDIR=testing/$CONTESTANT/$PROBLEM
113 [ -d $PDIR ] || die "Problem $PROBLEM not known"
114 [ -d $SDIR ] || fatal "Solution of $PROBLEM not found"
115 mkdir -p $TDIR $TMPDIR
117 mkdir -p $TDIR $TMPDIR
119 Testing solution of $PROBLEM by $CONTESTANT
120 Test started at `date`
121 Contestant's solution directory: $SDIR
122 Problem directory: $PDIR
123 Testing directory: $TDIR
128 # Locate source file.
129 # If no parameter is given, locate it in SDIR and return name as SRCN and extension as SRCEXT
130 # Or a file name can be given and then SDIR, SRCN and SRCEXT are set.
131 # Beware, SDIR and SRCN can contain spaces and other strange user-supplied characters.
133 function locate-source
135 pstart "Finding source... "
137 if [ -n "$1" ] ; then
139 local S=`basename "$1"`
140 SBASE=$(echo "$S" | sed 's/\.\([^.]\+\)//')
141 SRCEXT=$(echo "$S" | sed '/\./!d; s/.*\.\([^.]\+\)/\1/')
142 if [ -n "$SRCEXT" ] ; then
143 # Full name given, so just check the extension and existence
145 [ -f "$SDIR/$SRCN" ] || die "Cannot find source file $SDIR/$SRCN"
147 for a in $EXTENSIONS ; do
148 if [ $a == $SRCEXT ] ; then
150 echo "Explicitly set source file: $SDIR/$SRCN"
154 die "Unknown extension .$SRCEXT"
159 for a in $EXTENSIONS ; do
160 if [ -f "$SDIR/$SBASE.$a" ] ; then
161 [ -z "$SRCN" ] || die "Multiple source files found: $SDIR/$PROBLEM.$a and $SDIR/$SRCN. Please fix."
166 [ -n "$SRCN" ] || fatal "NOT FOUND"
168 echo "Found source file: $SDIR/$SRCN"
171 # Compilation (compile SDIR/SRCN with PDIR/COMP_EXTRAS to EXE=TDIR/PROBLEM)
175 pstart "Compiling... "
176 override-vars "EXT_$SRCEXT"
177 # Beware, the original SRCN can be a strange user-supplied name
179 cp "$SDIR/$SRCN" $TDIR/$SRC
180 if [ -n "$COMP_EXTRAS" ] ; then
181 echo "Extras: $COMP_EXTRAS"
182 for a in $COMP_EXTRAS ; do cp $PDIR/$a $TDIR/ ; done
185 for a in $SRC $COMP_EXTRAS ; do cp $TDIR/$a $BOXDIR/ ; done
187 CCMD=$(expand-var COMP)
188 COMP_SANDBOX_OPTS=$(expand-var COMP_SANDBOX_OPTS)
189 echo "Compiler command: $CCMD"
190 echo "Compiler sandbox options: $COMP_SANDBOX_OPTS"
191 eval $COMP_SANDBOX_INIT
193 echo "Compiler input files:"
195 echo "Compiler output:"
196 if ! $BOXCMD $COMP_SANDBOX_OPTS -- $CCMD 2>$TDIR/compile.out ; then
197 COMPILE_MSG="`cat $TDIR/compile.out`"
198 pend "FAILED: $COMPILE_MSG"
202 cat $TDIR/compile.out
204 echo "Compiler output files:"
206 if [ ! -f $BOXDIR/$PROBLEM ] ; then
207 pend "FAILED: Missing executable file"
208 echo "Missing executable file"
212 cp -a $BOXDIR/$PROBLEM $EXE
213 echo "Compiled OK, result copied to $EXE"
217 # Running of test program according to current task type (returns exit code and TEST_MSG)
221 [ -f $PDIR/$TEST.config ] && . $PDIR/$TEST.config
222 override-vars "TEST_$TEST"
234 if [ -s $TDIR/$TEST.pts ] ; then
235 P=`cat $TDIR/$TEST.pts`
239 # Translate signal numbers to readable strings
240 SG=${M#Caught fatal signal }
241 SG=${SG#Committed suicide by signal }
242 if [ "$SG" != "$M" ] ; then
243 SG=`perl -MConfig -e '@s=split / /,$Config{sig_name}; print $s[$ARGV[0]]' $SG`
244 [ -z "$SG" ] || M="$M (SIG$SG)"
247 # Translate runtime errors to readable strings
248 RE=${M#Exited with error status }
249 if [ -n "$EXIT_CODE_HOOK" -a "$RE" != "$M" ] ; then
250 NEWMSG=`$EXIT_CODE_HOOK $RE`
251 if [ -n "$NEWMSG" ] ; then
252 M="Runtime error $RE: $NEWMSG"
265 echo "Executable file: $TDIR/$PROBLEM"
266 if [ ! -x $TDIR/$PROBLEM ] ; then
267 test-result 0 "Compile error"
269 cp $TDIR/$PROBLEM $BOXDIR/
271 IN_TYPE=${IN_TYPE:-$IO_TYPE}
272 OUT_TYPE=${OUT_TYPE:-$IO_TYPE}
274 file) echo "Input file: $PROBLEM.in (from $PDIR/$TEST.in)"
275 try-ln $PDIR/$TEST.in $TDIR/$TEST.in
276 cp $PDIR/$TEST.in $BOXDIR/$PROBLEM.in
277 [ $TASK_TYPE == interactive ] || BOX_EXTRAS="$BOX_EXTRAS -i/dev/null"
279 stdio) echo "Input file: <stdin> (from $PDIR/$TEST.in)"
280 try-ln $PDIR/$TEST.in $TDIR/$TEST.in
281 cp $PDIR/$TEST.in $BOXDIR/.stdin
282 BOX_EXTRAS="$BOX_EXTRAS -i.stdin"
284 none) echo "Input file: <none>"
286 *) die "Unknown IN_TYPE $IN_TYPE"
289 if [ -n "$EV_PEDANT" -a $IN_TYPE != none ] ; then
291 if [ "$EV_PEDANT" = 1 ] ; then
294 bin/pedant <$TDIR/$TEST.in >$TDIR/$TEST.pedant $EV_PEDANT
295 if [ -s $TDIR/$TEST.pedant ] ; then
297 sed 's/^/\t/' <$TDIR/$TEST.pedant >&2
302 file) echo "Output file: $PROBLEM.out"
303 [ $TASK_TYPE == interactive ] || BOX_EXTRAS="$BOX_EXTRAS -o/dev/null"
305 stdio) echo "Output file: <stdout>"
306 BOX_EXTRAS="$BOX_EXTRAS -o.stdout"
308 none) echo "Output file: <none>"
310 *) die "Unknown OUT_TYPE $OUT_TYPE"
313 echo "Timeout: $TIME_LIMIT s"
314 echo "Memory: $MEM_LIMIT KB"
316 echo "Sandbox contents before start:"
322 echo "Sandbox contents after exit:"
324 case ${OUT_TYPE:-$IO_TYPE} in
325 file) [ -f $BOXDIR/$PROBLEM.out ] || test-result 0 "No output file"
326 cp $BOXDIR/$PROBLEM.out $TDIR/$TEST.out
328 stdio) [ -f $BOXDIR/.stdout ] || test-result 0 "No output file"
329 cp $BOXDIR/.stdout $TDIR/$TEST.out
333 if [ -n "$OUTPUT_FILTER" -a "$OUT_TYPE" != none -a -z "$EV_NOFILTER" ] ; then
335 FILTER=$(expand-var OUTPUT_FILTER)
336 echo "Output filter command: $FILTER"
337 mv $TDIR/$TEST.out $TDIR/$TEST.raw
338 if ! eval $FILTER 2>$TMPDIR/exec.out ; then
340 MSG=`tail -1 $TMPDIR/exec.out`
341 if [ -z "$MSG" ] ; then MSG="Filter failed" ; fi
348 # Running of test program with file input/output
350 function test-run-file
354 BOXOPTS=$(expand-var TEST_SANDBOX_OPTS)
355 echo "Sandbox options: $BOXOPTS"
356 if ! $BOXCMD $BOXOPTS -- ./$PROBLEM 2>$TMPDIR/exec.out ; then
358 MSG=`tail -1 $TMPDIR/exec.out`
365 # Running of interactive test programs
367 function test-run-interactive
371 BOXOPTS=$(expand-var TEST_SANDBOX_OPTS)
372 echo "Sandbox options: $BOXOPTS"
373 ICCMD=$(expand-var IA_CHECK)
374 echo "Interactive checker: $ICCMD"
375 if ! $HDIR/bin/iwrapper $BOXCMD $BOXOPTS -- ./$PROBLEM @@ $ICCMD 2>$TMPDIR/exec.out ; then
377 MSG="`head -1 $TMPDIR/exec.out`"
384 # "Running" of open-data problems
386 function test-run-open-data
388 [ -f $SDIR/$TEST.out ] || test-result 0 "No solution"
389 ln $SDIR/$TEST.out $TDIR/$TEST.out
394 function syntax-check
396 [ -n "$SYNTAX_CHECK" ] || return 0
397 [ -z "$EV_NOCHECK" ] || return 0
399 SCHECK=$(expand-var SYNTAX_CHECK)
400 echo "Syntax check command: $SCHECK"
401 if ! eval $SCHECK 2>$TMPDIR/exec.out ; then
403 MSG=`tail -1 $TMPDIR/exec.out`
404 if [ -z "$MSG" ] ; then MSG="Wrong syntax" ; fi
412 function output-check
415 if [ -n "$OUTPUT_CHECK" -a "$OUT_TYPE" != none -a -z "$EV_NOCHECK" ] ; then
417 [ -f $PDIR/$TEST.out ] && ln $PDIR/$TEST.out $TDIR/$TEST.ok
418 OCHECK=$(expand-var OUTPUT_CHECK)
419 echo "Output check command: $OCHECK"
420 if ! eval $OCHECK 2>$TMPDIR/exec.out ; then
422 MSG=`tail -1 $TMPDIR/exec.out`
423 if [ -z "$MSG" ] ; then MSG="Wrong answer" ; fi
427 MSG=`tail -1 $TMPDIR/exec.out`
429 if [ -z "$MSG" ] ; then MSG="OK" ; fi
430 test-result $POINTS_PER_TEST "$MSG"
433 # Setup of public commands
435 function public-setup
438 PDIR=$MO_ROOT/problems/$PROBLEM
442 [ -d $PDIR ] || die "Unknown problem $PROBLEM"
444 pstart "Initializing... "
450 BOXCMD="$MO_ROOT/bin/box -c$BOXDIR"
452 pend "OK (see 'check-log' for details)"
455 # Locate output of open data problem, test case TEST
456 # Beware, SDIR and SRCN can contain spaces and other strange user-supplied characters.
460 [ -f $PDIR/$TEST.in ] || die "Unknown test $TEST"
461 if [ -n "$1" ] ; then
465 SRCN=$SDIR/$PROBLEM$TEST.out
467 [ -f "$SDIR/$SRCN" ] || fatal "Output file $SRCN not found"
470 # Translation of runtime error codes for various compilers
472 function fpc-exit-code
475 200) echo -n "Division by zero" ;;
476 201) echo -n "Range check error" ;;
477 202) echo -n "Stack overflow" ;;
478 203) echo -n "Heap overflow" ;;
479 205) echo -n "Floating point overflow" ;;
480 215) echo -n "Arithmetic overflow" ;;
481 216) echo -n "Segmentation fault" ;;