#!/usr/bin/perl # grader / Min-Yen Kan / Version 1.0 / Wed May 12 13:10:26 EDT 1999 # # Fixed version from yee fan # # Looks for commands such as (time) (max) (score) (mailto:email@address) # in input files. Tallies scores based on (+/-number%?), e.g. (-5%) or (+5). # maximum scores are specified by square brackets [25 points] or [25]. # # Other features # - A "BUG" in the input file will cause the file in question to # not be processed in the current run, so you can fix it later. # - Ignores lines starting with "#" # - Calculates score, # of submissions, avg, and standard # deviation on STDERR # # Changed by Min (Mon Dec 17 20:49:21 SGT 2012) # - Added debugging output via command-line opt "-d" # require "getopts.pl"; ### USER customizable section $tmpfile .= $0; $tmpfile =~ s/[\.\/]//g; $tmpfile = "/tmp/" . $tmpfile . $$ . time; $0 =~ /([^\/]+)$/; $progname = $1; $mailtoCommandLoc = "/usr/bin/mail"; # you may have to change this $defaultSubject = "Your grade"; ### END user customizable section ### Ctrl-C handler sub quitHandler { print STDERR "\n# $progname fatal - received a 'SIGINT'\n# $progname - exiting cleanly\n"; `/bin/rm $tmpfile`; exit; } ### HELP Sub-procedure sub Help { print STDERR "usage: $progname -h\t\t\t\t[invokes help]\n"; print STDERR " $progname -v\t\t\t\t[invokes version]\n"; print STDERR " $progname [-qm] [-s ] filename(s)...\n"; print STDERR "Options:\n"; print STDERR "\t-q\tQuiet Mode (don't echo license)\n"; print STDERR "\t-m\tProcess mailto commands\n"; print STDERR "\t-s \tAssign mail subject (default: $defaultSubject)\n"; print STDERR "\n"; print STDERR "Will accept input on STDIN as a single file.\n"; print STDERR "\n"; } ### VERSION Sub-procedure sub Version { open (IF, $0); while () { if (/^\#/) { if (/^\#\!/) { next; } else { s/^\#//; print STDERR $_; } } else { last; } } } sub License { print STDERR "# Copyright 1999,2003 \251 by Min-Yen Kan\n"; } ### ### MAIN program ### $SIG{'INT'} = 'quitHandler'; &Getopts ('dhmqs:v'); if (!$opt_q) { &License; } # call License, if asked for if ($opt_v) { &Version; exit(0); } # call Version, if asked for if ($opt_h) { &Help; exit (0); } # call help, if asked for my $subject = (defined $opt_s) ? $opt_s : $defaultSubject; my $multi = 0; if (scalar (@ARGV) > 2) { $multi = 1; } @grades = (); ## standardize input stream (either STDIN on first arg on command line) if ($filename = shift) { NEWFILE: if (!(-e $filename)) { die "# $progname crash\t\tFile \"$filename\" doesn't exist"; } open (IF, $filename) || die "# $progname crash\t\tCan't open \"$filename\""; $fh = "IF"; } else { $filename = ""; $fh = "STDIN"; } $i = 0; $time = localtime(time()); @mailto = (); my $max = 0; my $score = 0; my $percent = 100; my $bug = 0; while (<$fh>) { if (/^\#/) { next; } # skip comments s/ //; s/\(time\)/$time/g; # get the current, grading time if (/\(mailto\:(.+)\)/g) { # get the email address, if defined push (@mailto, $1); if (!defined $opt_m) { print STDERR "# $progname warning\t\tNo mailing switch (-m) on command line, ignoring mailtos...\n"; } } if (/BUG/) { # check whether can be done $bug = 1; print STDERR "# $progname warning\t\t\"BUG\" keyword found in text \"$filename\", not going to process\n"; } while (/\(([+-])(\d+)(%?)\)/g) { # add or subtract a (percentage) grade $sign = $1; $val = $2; $percentage = $3; if ($percentage eq "") { if ($sign eq '-') { $score -= $val; if ($opt_d) { print STDERR "[- $val: $score]"; } } else { $score += $val; if ($opt_d) { print STDERR "[+ $val: $score]"; } } } else { if ($sign eq '-') { $percent -= $val; if ($opt_d) { print STDERR "[- $val %: $percent %]"; } } else { $percent += $val; if ($opt_d) { print STDERR "[+ $val %: $percent %]"; } } } } while (/\[(\d+) point(s?)\]/g) { # compile maximum score $max += $1; $score += $1; if ($opt_d) { print STDERR "[acc $1: $score / max: $max]"; } } $lines[$i++] = $_; # store annotated template file } close ($fh); # recalculate raw score from percentage. $score = int (($percent/100) * $score); ## 2nd pass if (defined @mailto && scalar (@mailto) != 0) { open (OF, ">$tmpfile"); $fh = "OF"; } else { $fh = "stdout"; } if ($bug == 1) { print $fh "BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG\n"; } if (defined @mailto && scalar (@mailto) != 0) { unshift (@lines, "If you are not the intended recipient of this automated grade e-mail,\n", "please simply reply to this e-mail, and then delete it. Thank you.\n\n\n"); unshift (@lines, "Subject: $subject\n\n"); } push (@grades, $score); for ($i = 0; $i <= $#lines; $i++) { $lines[$i] =~ s/\(score\)/$score/g; $lines[$i] =~ s/\(max\)/$max/g; print $fh $lines[$i]; if ($fh eq "OF") { print $lines[$i]; } } if (defined @mailto && scalar (@mailto) != 0 && $opt_m) { close ($fh); for (my $i = 0; $i <= $#mailto; $i++) { system ("$mailtoCommandLoc $mailto[$i] < $tmpfile"); } `rm $tmpfile`; } if ($bug == 1) { print $fh "BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG\n"; } if ($multi == 1) { print STDERR "# $progname info\t\t$filename : $score\n"; } if ($filename = shift) { print "--------------------------------------------------------------------------------\n"; $i = 0; undef @lines; goto NEWFILE; } if ($multi == 1) { my $sum = 0; for (my $i = 0; $i <= $#grades; $i++) { $sum += $grades[$i]; } my $avg = $sum / scalar (@grades); print STDERR "# $progname info\t\tNumber of assignments = " . scalar (@grades) . "\n"; print STDERR "# $progname info\t\tAverage grade = $avg\n"; my $diff = 0; for (my $i = 0; $i <= $#grades; $i++) { $diff += (abs($avg - $grades[$i]) * abs($avg - $grades[$i])); } my $std = $diff / (scalar (@grades) - 1); my $std = sqrt ($std); print STDERR "# $progname info\t\tStandard Deviation = $std\n"; } ### ### END of main program ###