#!/usr/local/bin/perl # fil 1.0, 30 Mar 1999 # # Purpose: # extract items from a test bank of LaTeX formatted questions, # i.e. it's an enumerated list item filter, hence the name fil # # Usage example (make the file executable): # fil test2j # # Instructions: # command line argument is the name of the version to produce, e.g. test2j # Any filename extension is ignored there, e.g. test2j.num # # Currently the program assumes that the name of the test bank is in the # first five characters of the name provided, plus ".tex" # e.g. If the test bank is test2.tex and the numbers selected are in # test2j.num then the test produced will be test2j.tex # # A file with numbers designating problems to select, one per line, # must have the .num extension, and before each section of numbers # a comment should be inserted which may include text to indicate # which section the following numbers are for. # # Comments are indicated with a pound sign at the beginning of a line. # Multiple comment lines may be grouped together, but none should appear # after the last list of numbers. # Example num file for a two-section test: # # Short Answer # 1 # 4 # 23 # # Extra Credit # 3 # # If you do not wish to choose problems from a particular section, then # put a zero as the only problem number in a section. This might be # the case if you wanted to use Short Answer #23 as an Extra Credit problem. # You can have #23 chosen from the Short Answer section and then edit # the version that is produced and move that problem to the Extra Credit # section. # # Warnings: # assumed that enumerated lists are the only types of lists in the bank # # assumed that there are no enumerated lists outside of the lists of # problems # # \clearpage, \item, \begin{enumerate}, and \end{enumerate} # must appear on separate lines. If such a LaTeX element is included # or excluded from a test version then so is everything else on the same # line # # don't use the Enter key on the numeric keypad to enter numbers or # this program may not recognize the line breaks and won't produce a # complete test version and may need to be interrupted # # Assurances: # can handle a hierarchy of enumerated item lists within problems # # it is expected that \clearpage may have been used to force the printing # of figures near their problems in the test bank. # In a test version these \clearpage commands won't be needed in # the same places, so this script will ommit them # # before each problem written to the test version is a LaTeX comment # that for a problem numbered 23 would look like this: # % P#23 # this is so that problems may be found quickly in post-editing, such # as modifying problems or eliminating problem subitems or eliminating # extra figures when not all are needed # $out = $ARGV[0]; $out =~ s/\..*//g; $in = substr($out,0,5); $testin = $in . '.tex'; $testout = $out . '.tex'; $numfile = $out . '.num'; open (BANK, "$testin") || die "Can't open $testin\n"; open (NUM, $numfile) || die "Can't open $numfile\n"; open (OUT, ">$testout") || die "Can't open $testout\n";; while ($numctr = ) { &processItems; } ©Past("\\\\end{document}"); close(NUM); close(BANK); close(OUT); exit; sub copyPast { # sends lines out until match # terminates with line in $_ following match $target = $_[0]; while (($_ = ) && ! /$target/) { if (/\\clearpage/) { # do nothing with input line } else { print OUT; } } print OUT; $_ = ; } sub rCopyPast { $target = $_[0]; while (($_ = ) &&! /$target/) { if (/\\begin{enumerate}/) { print OUT; &rCopyPast("\\\\end{enumerate}"); } if (/\\clearpage/) { # do nothing with input line } else { print OUT; } } print OUT; $_ = ; } sub rSkipPast { $target = $_[0]; while (($_ = ) &&! /$target/) { if (/\\begin{enumerate}/) { # do nothing with input line &rSkipPast("\\\\end{enumerate}"); } else { # do nothing with input line } } $_ = ; } sub processItems { ©Past("\\\\begin{enumerate}"); while (index($numctr, "#") >= 0) { $numctr=; } $itemctr = 0; $copystate = 0; $status = 1; while ($status) { SWITCH: { if (/\\item/) { $itemctr++; if ($itemctr == $numctr) { $copystate = 1; print OUT "% P#$numctr"; print OUT; $numctr = ; } else { $copystate = 0; #do nothing with input line } $_ = ; last SWITCH; } if (/\\end{enumerate}/) { print OUT; $_ = ; $status = 0; last SWITCH; } if (/\\begin{enumerate}/) { if ($copystate) { print OUT; &rCopyPast("\\\\end{enumerate}"); } else { # do nothing with input line &rSkipPast("\\\\end{enumerate}"); } last SWITCH; } if (/\\clearpage/) { # do nothing with input line $_ = ; last SWITCH; } if ($copystate) { # made it to here because input line didn't match any of above, # so we must have an extra line that's part of an item print OUT; } else { #do nothing with input line } # end with an input line ready to process $_ = ; } } }