From 1026bf8cf7773dad92367f2ad81598536dd6d3da Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Fri, 8 May 2015 22:18:17 +0000 Subject: exam (8may15) git-svn-id: svn://tug.org/texlive/trunk@37279 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/tex/latex/exam/exam.cls | 1526 +++++++++++++++++------------ 1 file changed, 924 insertions(+), 602 deletions(-) (limited to 'Master/texmf-dist/tex/latex') diff --git a/Master/texmf-dist/tex/latex/exam/exam.cls b/Master/texmf-dist/tex/latex/exam/exam.cls index 1f4fc6358fc..5ea596ca0a3 100644 --- a/Master/texmf-dist/tex/latex/exam/exam.cls +++ b/Master/texmf-dist/tex/latex/exam/exam.cls @@ -3,7 +3,7 @@ % A LaTeX2e document class for preparing exams. %% exam.cls -%% Copyright (c) 1994, 1997, 2000, 2004, 2008 Philip S. Hirschhorn +%% Copyright (c) 1994, 1997, 2000, 2004, 2008, 2011, 2015 Philip S. Hirschhorn % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 @@ -31,8 +31,8 @@ % from my web page: http://www-math.mit.edu/~psh/ -\def\fileversion{2.4} -\def\filedate{2011/05/22} +\def\fileversion{2.5} +\def\filedate{2015/05/07} %--------------------------------------------------------------------- %--------------------------------------------------------------------- % @@ -82,460 +82,230 @@ % %-------------------------------------------------------------------- %-------------------------------------------------------------------- -% Changelog since version 2.3: +% Changelog since version 2.4: %-------------------------------------------------------------------- -% Version 2.4, 2011/05/22: -% +% Version 2.5 2015/05/07 + % No longer betatest. -% -%-------------------------------------------------------------------- -% Version 2.321$\beta$, 2011/05/15: -% -% New environments: EnvUplevel and EnvFullwidth -% -% The EnvUplevel environment is similar to the command \uplevel, -% except that \uplevel is a command taking one argument. The -% EnvUplevel environment has the advantage that you can include -% verbatim material (using, e.g., the \verb command) in the -% environment. (You can't include verbatim material in the argument -% of an \uplevel command.) -% -% The EnvFullwidth environment is similar to the command \fullwidth, -% except that \fullwidth is a command taking one argument. The -% EnvFullwidth environment has the advantage that you can include -% verbatim material (using, e.g., the \verb command) in the -% environment. (You can't include verbatim material in the argument -% of a \fullwidth command.) -% -%-------------------------------------------------------------------- -% Version 2.320$\beta$, 2011/04/16: -% -% New document class options: cancelspace -% nocancelspace -% New commands: \cancelspace -% \nocancelspace -% -% Using the document class option cancelspace is equivalent to giving -% the command \cancelspace at the beginning of the file. The default is -% \nocancelspace. Thus, the document class option nocancelspace has no -% effect, but is there to avoid errors if a user is confused. -% -% If the user uses the document class option cancelspace and if -% solutions are not being printed, then any space that would be added by -% an optional argument to the solution, solutionorbox, solutionorlines, -% or solutionordottedlines environments will not be added. -% -% If solutions are being printed (because the user used the document -% class option answers or gave the command \printanswers), then the -% option cancelspace (and the command \cancelspace) will have no -% effect. -% -%-------------------------------------------------------------------- -% Version 2.319$\beta$, 2011/04/11: -% -% We fixed an obscure bug, in which if the user gives a \qformat -% command, in which case they shouldn't want to give a \droppoints -% command, but they *do* give a \droppoints command, there is an -% error (\padded@point@block undefined). -% -%-------------------------------------------------------------------- -% Version 2.318$\beta$, 2011/04/05: -% -% \qformat and \bonusqformat are now totally independent. -% That is: \qformat doesn't affect bonus questions, and \noqformat -% no longer cancels \bonusqformat. -% -% New command: \nobonusqformat -% \nobonusqformat does for \bonusqformat what \noqformat does for -% \qformat. -% -%-------------------------------------------------------------------- -% Version 2.317$\beta$, 2011/04/02: -% -% We changed the definition of \numcoverpages so that on the first run -% of latex (when \exam@lastcoverpage isn't yet defined), \numcoverpages -% will expand to -% 0\mbox{\normalfont\bf ??} -% instead of -% \mbox{\normalfont\bf ??} -% so that the construction \romannumeral\numcoverpages will not generate -% an error on the first run of latex. -% -% We also made changes and corrections to comments. -% -%-------------------------------------------------------------------- -% Version 2.316$\beta$, 2010/12/22: -% -% -% New commands: -% -% \pointsinrange{rangename} -% \bonuspointsinrange{rangename} -% -% If `rangename' is the name of a grading range defined using -% \begingradingrange{rangename} and \endgradingrange{rangename}, then -% \pointsinrange{rangename} expands to the number of points in that -% grading range and \bonuspointsinrange{rangename} expands to the number -% of bonus points in that grading range. -% We also changed the checkboxes and oneparcheckboxes environments so -% that, when solutions are being printed, a \CorrectChoice will be -% printed with \CorrectChoiceEmphasis (along with the \checkedchar -% that marks the \CorrectChoice). This brings the behavior in line -% with that of the choices and oneparchoices environments. -% %-------------------------------------------------------------------- -% Version 2.315$\beta$, 2010/12/21: -% +% Version 2.408$\beta$ 2013/11/17 + % New commands: % -% \settabletotalpoints -% \settabletotalbonuspoints -% -% Each of those takes one argument. After giving the command -% \settabletotalpoints{numpoints}, any grade or point table (partial -% or full) will list the total points as numpoints instead of the -% actual total number of points in the table. -% -% After giving the command \settabletotalbonuspoints{numbonuspoints}, -% any grade or point table will list the total bonus points as -% numbonuspoints instead of the actual total number of bonus points in -% the table. +% \firstqinrange{whatever} +% \lastqinrange{whatever} +% \numqinrange{whatever} % -% These commands are intended for exams in which students are asked to -% do some subset of the problems, but not all of them, and so the -% total number of points possible is less than the sum of the points -% for all of the questions. +% where ``whatever'' is the name of a grading range. % +% \firstqinrange{whatever} prints the number of the first question in +% the range. % -% To have one of these commands affect only a single table, confine the -% command and the \gradetable command inside of a group, as in +% \lastqinrange{whatever} prints the number of the last question in the +% range. % -% \begingroup -% \settabletotalpoints{100} -% \gradetable[v][questions] -% \endgroup +% \numqinrange{whatever} prints the number of questions in the range. % -% or even just +% We changed a couple of internal command name related to grading +% ranges. If the user defines the range `myrange', then we now use + +% \range@myrange@firstp +% \range@myrange@lastp +% \range@myrange@firstq +% \range@myrange@lastq % -% \begin{center} -% \settabletotalpoints{100} -% \gradetable[v][questions] -% \end{center} +% where we used to use % +% \tbl@myrange@firstp +% \tbl@myrange@lastp +% \tbl@myrange@firstq +% \tbl@myrange@lastq + %-------------------------------------------------------------------- -% Version 2.314$\beta$, 2010/12/01: -% -% New user command: -% -% \addquestionobject -% -% This is for when some of a question spills onto the next page, but -% that page doesn't have any parts, subparts, subsubparts, or choices -% beginning on theat page (which means that the \ifincomplete command -% won't know that any of that question is on that page). If you say -% \addquestionobject at the very end of the question, it will write a -% questionobject to the .aux file so that \ifincomplete will work -% correctly. +% Version 2.407$\beta$ 2012/12/19 + +% New environment: % -% New commands used only internally: +% solutionbox % -% \first@questionobject -% \questionobject@pluspagecheck +% The solutionbox environment is different from the other solution +% environments (solution, solutionorbox, solutionorlines, +% solutionordottedlines, and solutionorgrid), in that % -% These were just to clean up some of the internal code. +% (1) The box is always printed, whether answers are being printed +% or not. % -%-------------------------------------------------------------------- -% Version 2.313$\beta$, 2010/02/18: +% (2) The argument giving the size of the box is a required +% argument, not an optional argument, and so it should be enclosed +% in braces, not in brackets. It can be either a length or +% \stretch{number}. % -% Bug fix: When solutions are not being printed, the solution, -% solutionorlines, and solutionordottedlines environments disallow -% pagebreaks before the environment, which can pull the last line of -% the question (or part, or etc.) preceding the environment onto the -% next page, even when leaving a rather large space before the -% pagebreak. We insert +% (3) We make no use of the TheSolution environment; the solutionbox +% environment is completely freestanding. % -% \penalty 0 +% If answers are not being printed then only the box is printed, with +% nothing in it. If answers are being printed, then the solution is +% printed inside of the box. % -% to allow a pagebreak before the environment. We make no change to -% the solutionorbox environment, since it didn't have this problem. +% Note: It's the user's responsibility to be sure that the box is +% large enough to hold the solution! If the solution takes up too +% much vertical space, then it will spill out of the bottom of the +% box, overwriting whatever follows the box. % %-------------------------------------------------------------------- -% Version 2.312$\beta$, 2010/01/17: +% Version 2.406$\beta$, 2012/12/16 % -% New commands: -% -% \combinedgradetable -% \combinedpointtable -% \partialcombinedgradetable -% \partialcombinedpointtable -% -% These are similar to \gradetable, \pointable, \bonusgradetable, -% \bonuspointtable, \partialgradetable, \partialpointtable, -% \partialbonusgradetable, and \partialbonuspointtable except that -% these new commands list both the points and the bonus points. -% -% \partialcombinedgradetable and \partialcombinedpointtable take one -% required argument, which is the name of the grading range. All four -% of these commands take two optional arguments, the first being either -% ``v'' or ``h'' and the second being either ``questions'' or -% ``pages''. The possibilities are thus +% New command: % -% \combinedgradetable[v][questions] -% \combinedgradetable[v][pages] -% \combinedgradetable[h][questions] -% \combinedgradetable[h][pages] -% \partialcombinedgradetable{rangename}[v][questions] -% \partialcombinedgradetable{rangename}[v][pages] -% \partialcombinedgradetable{rangename}[h][questions] -% \partialcombinedgradetable{rangename}[h][pages] -% -% The defaults are ``v'' and ``questions''. -% -% The horizontal tables have separate rows for the points and bonus -% points. The vertical tables have separate columns for the points and -% bonus points. -% -% The default values for the words that appear in the tables are set by -% the commands -% -% \chqword{Question:} -% \chpgword{Page:} -% \chpword{Points:} -% \chbpword{Bonus Points:} -% \chsword{Score:} -% \chtword{Total} -% \cvqword{Question} -% \cvpgword{Page} -% \cvpword{Points} -% \cvbpword{Bonus Points} -% \cvsword{Score} -% \cvtword{Total:} -% -% The words in the table can be changed by giving any of these -% commands with the desired word as argument. +% \noquestionsonthispage % -%-------------------------------------------------------------------- -% Version 2.311$\beta$, 2010/01/10: +% This command tells the \ifcontinuation and \ifincomplete commands +% to assume that no part of any question is on this page. This is +% similar to the job done by the \nomorequestions command for the +% pages that follow the end of all of the questions. % -% New environment: oneparcheckboxes % -% The oneparcheckboxes environment is to the checkboxes environment as -% the oneparchoices environment is to the choices environment. That is, -% each choice is begun with either a \choice or a \correctchoice -% command, and these will all be printed as a single paragraph. When -% answers are not being printed, each choice will have a label -% consisting of a box that the student can check, created by the -% argument to the last \checkboxchar command. The default value is -% created by the command +% If you give the command \noquestionsonthispage on a page, then % -% \checkboxchar{$\bigcirc$} +% (1) \ifcontinuation on that page will expand to its second +% argument, +% (2) \ifincomplete on that page will expand to its second +% argument, and +% (3) an \ifincomplete on an earlier page will not assume that a +% question from that earlier page continues onto this page. % -% (Note the dollar signs, since \bigcirc can appear only in math -% mode.) When answers are being printed, then any choice created -% using the \correctchoice command will be labelled by the argument to -% the last \checkedchar command, the default value of which is created -% by the command +% The way that this command affects the \ifincomplete command on +% earlier pages is as follows: If there is a page with no questions or +% parts or subparts or subsubparts, then the last page before that +% with a question (or part, etc.) would normally be deemed incomplete; +% if, however, the page with no questions (or parts, etc.) (along with +% all adjacent pages with no questions or parts etc.) has a +% \noquestionsonthispage command, then that last page with a question +% (or part, etc.) will not be deemed incomplete. % -% \checkedchar{$\surd$} +% Note that if you're tempted to use this command on a page that follows +% the end of all of the questions, then you should probably use the +% command \nomorequestions instead. % %-------------------------------------------------------------------- -% Version 2.310$\beta$, 2010/01/09: -% -% New command: \bonusqformat -% -% The \bonusqformat command takes one argument, with the same -% description as for the argument of the \qformat command. +% Version 2.405$\beta$, 2012/10/21 +% +% It is now possible to use a parts, subparts, or subsubparts +% environment inside one of the solution environments (solution, +% solutionorbox, solutionorlines, solutionordottedlines, or +% solutionorgrid) without getting problems from multiply defined +% labels or having its points (if any) counted as being actual points +% on the exam. +% +% Any \part, \subpart, or \subsubpart command inside one of the +% solution environments now writes a \PgInfo command in the .aux file +% of the form question2@object3, but no labels and no other \PgInfo +% commands. In addition, if there are points assigned to any of these +% commands inside any of the solution environments, those points are +% not added to the points of the question or the points on the page, +% and do not affect any gradetables or pointtables. % -% Note added 2011/04/05: Version 2.318$\beta$ changes the behavior so -% that \qformat and \bonusqformat are now completely independent! -% -% If the user gives a \qformat command, then the argument of that -% command is used to format both questions and bonusquestions. If, -% after giving the \qformat command, the user gives a \bonusqformat -% command, then the argument of the \bonusqformat command will be used -% to format bonus questions. -% -% Note: The \bonusqformat command must be given *after* the \qformat -% command, or else the \bonusqformat command will have no effect. -% -% Note: If the user hasn't given a \qformat command, then a -% \bonusqformat command will have no effect. -% -% Note: If the user gives a \qformat command and a \bonusqformat -% command, and then later says \noqformat, then the arguments of both -% the \qformat and \bonusqformat commands are no longer usable. That -% is, if the user later on once again says \qformat, and wants the bonus -% questions to have a different format from the questions, then another -% \bonusqformat command must be given. -% -% Note added 2011/04/05:: The above is changed in version 2.318$\beta$. -% \qformat and \bonusqformat are now completely independent. -% \noqformat cancels only \qformat, and the new command -% \nobonusqformat cancels \bonusqformat. -% %-------------------------------------------------------------------- -% Version 2.309$\beta$, 2009/11/30: +% Version 2.404$\beta$, 2012/09/03 % -% New environment: checkboxes -% New commands: \checkboxeshook -% \checkboxchar -% \checkedchar +% New command: % -% The checkboxes environment is similar to the choices environment, -% except that choices are not numbered. Instead of numbers, each -% choice has a label consisting of a box that the student can check, -% created by the argument to the last \checkboxchar command. The -% default value is created by the command +% \fillwithgrid{length} % -% \checkboxchar{$\bigcirc$} +% New environment: % -% (Note the dollar signs, since \bigcirc can appear only in math -% mode.) When answers are being printed, then any choice created -% using the \correctchoice command will be labelled by the argument to -% the last \checkedchar command, the default value of which is created -% by the command +% solutionorgrid % -% \checkedchar{$\surd$} +% These are similar to the \fillwithlines command and the +% solutionorlines environment. % -% The list parameters used in the checkboxes environment can be -% customized by redefining \checkboxeshook, the default value of which -% is empty. (This is similar to using \choiceshook to alter the -% choices environment.) +% By default, the created grids are in black. However, if you give the +% commands % -%-------------------------------------------------------------------- -% Version 2.308$\beta$, 2009/11/26: +% \usepackage{color} +% \colorgrids % -% We fixed a bug that caused \bonussubpart to act like \subpart and -% \bonussubsubpart to act like \subsubpart. +% then the grids will be in color, by default a light gray. That +% default color was defined by the command % -%-------------------------------------------------------------------- -% Version 2.307$\beta$, 2009/06/11: +% \definecolor{GridColor}{gray}{0.8} % -% We fixed a bug that arose only when there were cover pages and the -% first page of the cover pages used a different extraheadheight or -% extrafootheight from that used on the first page of the regular pages. -% The bug caused the first page of the regular pages to use the -% extraheadheight and extrafootheight intended only for the first cover -% page. +% You can change the color by redefining the color GridColor, and you +% can return to using black grids by giving the command % -%-------------------------------------------------------------------- -% Version 2.306$\beta$, 2009/03/28: +% \nocolorgrids % -% We fixed a bug that arose only when the user used a figure or -% table environment that floated to the top of a page. If that -% happened, then a full page's worth of text was placed below -% the figure or table, makeing the text run over the footline and off -% the bottom of the page. +% The default grid size and grid line thickness were set by the +% commands % -% We fixed this by commenting out several lines at the end of -% \@setheadheight and @setfootheight. +% \setlength{\gridsize}{5mm} +% \setlength{\gridlinewidth}{0.1pt} % -%-------------------------------------------------------------------- -% Version 2.305$\beta$, 2009/01/30: -% -% We fixed a bug to keep page breaks from occurring inside of -% \makeemptybox. We also added \begingroup \endgroup for the off -% chance that someone was using box0 and didn't want us to change it. -% -% We also fixed a bug in the solutionorbox environment that showed -% itself when the user used \stretch in the optional argument. +% You can change either or both of those by giving new \setlength +% commands. The period of the grid is \gridsize (both horizontally +% and vertically). That is, the horizontal distance from the left +% edge of one vertical line to the left edge of the next vertical line +% is \gridsize, as is the vertical distance from the top edge of one +% horizontal line to the top edge of the next horizontal line. Thus, +% each square has outer side length equal to \gridsize+\gridlinewidth. % %-------------------------------------------------------------------- -% Version 2.304$\beta$, 2009/01/22: -% -% We rewrote the definition of \makeemptybox and the solutionorbox -% environment (created in version 2.303). -% -% The argument to \makeemptybox can now be either a length, or \fill, or -% \stretch{number}. -% -% The optional argument to the solutionorbox environment can also be -% either a length, or \fill, or \stretch{number}. If the optional -% argument is omitted, then no box is printed when printanswers is -% false. -% -% The minimum box height is \minboxheight, whose value is set by the -% command +% Version 2.403$\beta$, 2012/08/29: % -% \setlength\minboxheight{.1in} -% -% This can be changed by giving a new setlength command, but it's not -% likely that anyone actually wants a box of height less than .1 inch. +% We changed the code for the command \fillin (which had been modified +% in version 2.402beta) so that if only one optional argument is used, +% a space following that optional argument will not be ignored. We +% did this in such a way that the second optional argument will be +% recognized even when spaces appear in between the optional +% arguments. % %-------------------------------------------------------------------- -% Version 2.303$\beta$, 2009/01/21: +% Version 2.402$\beta$, 2012/08/21: % -% New command: \makeemptybox -% New environment: solutionorbox +% We modified the command \fillin that we had created in version +% 2.401beta. \fillin now takes two optional arguments (and no required +% arguments). % -% \makeemptybox takes one argument, which is a length, and it creates -% an empty box of width the length of the current line and of height -% equal to the argument. That is, the box extends from the current -% left margin (which depends on whether we're in a question, part, -% subpart, or subsubpart) to the right margin. -% -% The solutionorbox environment is similar to the solution -% environment, except that if printanswers is false and an optional -% argument is specified, then instead of leaving that much blank space -% we print an empty box of that height. The optional argument must be -% a dimension; it can not be \fill. If the optional argument is -% missing or equal to 0pt, then when printanswers is false we print -% nothing at all. +% \fillin can take two optional arguments, as in % -% Note: This is changed in version 2.304. As of that version, the -% argument can be a length, or \fill, or \stretch{number}. +% \fillin[Answer][Length] % -%-------------------------------------------------------------------- -% Version 2.302$\beta$, 2008/10/18: +% The first optional argument is the answer to be printed above the line +% when \printanswers is in effect; the default value is empty. That +% line is printed a distance of \answerclearance below the baseline. % -% New commands: \numcoverpages and \totalnumpages +% The second optional argument is the length of the line that we print; +% the default value is \fillinlinelength. The value of +% \fillinlinelength is set with the command % -% \numcoverpages inserts the number of pages occupied by the -% coverpages environment. If there is no coverpages environment, -% it inserts 0. +% \setlength\fillinlinelength{1in} % -% \totalnumpages inserts the sum of \numcoverpages and \numpages. -% Note that if there are pages preceding a coverpages environment, then -% those pages will not be counted by \totalnumpages. +% and can be changed by giving a new \setlength command. % -% We also added \relax after some \ifnum comparisons and commented -% out some line endings to remove, e.g., an unwanted space inserted -% by \ifcontinuation when the page is a continuation. +% When answers are being printed, the first optional argument is +% printed subject to the declarations in the argument of the last +% \CorrectChoiceEmphasis command. It is centered on the line unless +% it is too long, in which case it extends to the right of the line. % %-------------------------------------------------------------------- -% Version 2.301$\beta$, 2008/09/22: -% -% All solution, solutionorlines, and solutionordotteslines -% environments are now enclosed in a group which is begun -% with the argument of the command -% -% \SolutionEmphasis +% Version 2.401$\beta$, 2012/08/20: % -% the default value of which is determined by the command % -% \SolutionEmphasis{} +% New command: % -% That is, the default is that nothing is inserted. -% For example, if the command +% \fillin[CorrectAnswer]{width} % -% \SolutionEmphasis{\itshape\small} +% This is for use in fill in the blank questions. This command inserts +% a blank line of width ``width''. If answers are being printed and if +% the optional argument ``CorrectAnswer'' appears, then the optional +% argument is printed subject to the declarations in the argument of the +% last \CorrectChoiceEmphasis command, and it is printed a distance of +% \answerclearance above the line. It is centered on the line unless it +% is too long, in which case it extends to the right of the line. % -% is used, the solutions will be set in italics, in small type. -% -% -% New command: \unframedsolutions -% -% This causes solutions to be printed as normal text, without any -% framing or shading. Anyone using this command should use the -% \SolutionEmphasis command so that the solutions will be -% distinguishable from the rest of the exam. -% -%-------------------------------------------------------------------- -% Version 2.3, 2008/07/16: -% -% Minor typographic corrections to comments. +% Note: We changed this command in version 2.401beta. % %-------------------------------------------------------------------- %-------------------------------------------------------------------- @@ -1777,11 +1547,16 @@ % \PgInfo@write command using a label of the form question2@object3 (if % it's the third object of the second question). -% The \PgInfo command defines a control sequence of the form `Pg@label' -% that expands to the page number for the corresponding question. For -% example, \PgInfo{subsubpart@2@1@3@4}{7} defines -% \csname Pg@subsubpart@2@1@3@4\endcsname -% to expand to 7. +% Inside one of the solution environments (solution, solutionorbox, +% etc.) each part, subpart, subsubpart, and choice get only the +% \PgInfo@write command using a label of the form question2@object3 +% (if it's the third object of the second question). + +% When read in from the .aux file, the \PgInfo command defines a +% control sequence of the form `Pg@label' that expands to the page +% number for the corresponding question. For example, +% \PgInfo{subsubpart@2@1@3@4}{7} defines \csname +% Pg@subsubpart@2@1@3@4\endcsname to expand to 7. % The \PgInfo@get{label} command returns the value of the macro Pg@label, % but it *doesn't* check whether that macro is defined. Thus, it's @@ -1836,17 +1611,35 @@ %-------------------------------------------------------------------- -% \ifcontinuation#1#2 expands to #2 if either: (1) The current page is -% before the page containing question number 1, or (2) A question begins -% on this page before any part, subpart, subsubpart, or choice begins, -% or (3) The current page is later than a page with the \nomorequestions -% command. Otherwise, it expands to #1. +% \ifcontinuation#1#2 expands to #2 if either: +% (1) The command \noquestionsonthispage has been given on this page, +% or +% (2) The current page is before the page containing question number +% 1, or +% (3) A question begins on this page before any part, subpart, +% subsubpart, or choice begins, or +% (4) The current page is later than a page with the \nomorequestions +% command. +% Otherwise, it expands to #1. +% +% Thus, for example, if there are no questions, parts, subparts, +% subsubparts, or choices on this page, and no \noquestionsonthispage +% command, and we're not before question 1, and not after a +% \nomorequestions command, then \ifcontinuation will expand to #1. \def\ifcontinuation#1#2{% - % We need to first check whether we're on a page *before* the page on - % which the first question appears. If we don't yet know which page - % has question number 1, then we must be doing an early run of LaTeX, + % If there's a \noquestionsonthispage command on this page, then + % we assume that we're not continuing anything: + \@ifundefined{No@Questions@Pg@\thepage}% + {\chk@contin{#1}{#2}}% + {#2}% +}% \ifcontinuation + +\def\chk@contin#1#2{% + % We check whether we're on a page *before* the page on which the + % first question appears. If we don't yet know which page has + % question number 1, then we must be doing an early run of LaTeX, % and we'll assume we're not a continuation. \expandafter\ifx\csname Pg@question@1\endcsname\relax % No page info yet; assume not a continuation @@ -1865,10 +1658,10 @@ #2% \else % The current page begins a new question if Contin@\thepage - % has been defined as a macro that expands to \relax - % (Note that this is different from if Contin@\thepage - % has never been defined at all, in which case it will - % be let equal to \relax (temporarily) by the \csname command.) + % has been defined as a macro that expands to \relax (Note + % that this is different from if Contin@\thepage has never + % been defined at all, in which case it will be let equal to + % \relax (temporarily) by the \csname command.) \expandafter\ifx\csname Contin@\thepage\endcsname\ref@relax #2% \else @@ -1886,11 +1679,18 @@ \fi \fi \fi -} +}% chk@contin -\def\nomorequestions{ +\def\nomorequestions{% \PgInfo@write{@endquestions}% -} +}% nomorequestions + +\def\noquestionsonthispage{% + \write\@mainaux{\string\expandafter\string\gdef + \string\csname\space No@Questions@Pg@\thepage\string\endcsname + {No questions here}}% +}% noquestionsonthispage + %-------------------------------------------------------------------- % \ContinuedQuestion is for use in headers and footers, where we can @@ -1928,7 +1728,7 @@ % The last possibility is that this page begins with either a part, % subpart, subsubpart, or choice. In this case, Contin@\thepage is % defined, and it expands to the number of the question that is -% continues onto this page. +% continued onto this page. \def\ref@relax{\relax} @@ -2095,55 +1895,115 @@ \def\IncompleteQuestion{% \Find@Incmp@ques + % If there's no incomplete question, the counter incmp@ques will be + % set to -1: \theincmp@ques } \def\Find@Incmp@ques{% + % If we're on the last page, then there's no incomplete question: \iflastpage{\setcounter{incmp@ques}{-1}}{\chk@incomp}% -} +}% Find@Incmp@ques \newcounter{next@ques} -\newcounter{nextq@page} +\newcounter{next@page} + \def\chk@incomp{% + % If we get here, we're not on the last page. + % \find@quesend calls \find@latestques to set the counter + % latest@ques equal to the number of the last question begun on or + % before the current page, and then it sets the counter ques@end to + % the page containing the last ques@object of that question: \find@quesend \ifnum \theques@end > \thepage\relax % This question has a part (or sub...) starting on a later page \setcounter{incmp@ques}{\value{latest@ques}}% \else - \setcounter{next@ques}{\thelatest@ques}% - \addtocounter{next@ques}{1}% - \expandafter\ifx\csname Pg@question@\thenext@ques \endcsname\relax - % This isn't the last page but there is no next question: - \setcounter{incmp@ques}{\thelatest@ques}% - \else - % This isn't the last page and there is a next question: - \setcounter{nextq@page}{\PgInfo@get{question@\thenext@ques}}% - \addtocounter{nextq@page}{-1}% - \ifnum \thenextq@page > \thepage\relax - \setcounter{incmp@ques}{\thelatest@ques}% - \else - \setcounter{incmp@ques}{-1}% - \fi - \fi + \chk@incompi \fi -} +}% chk@incomp + +\def\chk@incompi{% + % If there are any pages after the current one and before the next + % question (if there is a next question) that lack a + % \noquestionsonthispage and that aren't following the page of a + % \nomorequestions command, then question latest@ques is incomplete. + % Otherwise, there is no incomplete question: + \setcounter{next@ques}{\thelatest@ques}% + \addtocounter{next@ques}{1}% + % We use next@page as a scratch counter. We start by setting it + % to the last page we want to check for a \noquestionsonthispage + % command: + \expandafter\ifx\csname Pg@question@\thenext@ques \endcsname\relax + % This isn't the last page but there is no next question: +% + \@ifundefined{exam@lastpage}% + {\setcounter{next@page}{-1}}% + {\setcounter{next@page}{\exam@lastpage}}% +% +% \setcounter{next@page}{\exam@lastpage}% + \else + \setcounter{next@page}{\PgInfo@get{question@\thenext@ques}}% + \addtocounter{next@page}{-1}% + \fi + % See if that's after a \nomorequestions command: + \@ifundefined{Pg@@endquestions}% + {}% + {\ifnum \PgInfo@get{@endquestions} < \value{next@page}\relax + \setcounter{next@page}{\PgInfo@get{@endquestions}}% + \fi + }% + % OK, the counter next@page now contains the last page to check. + \chk@incompii +}% chk@incompi + +\def\chk@incompii{% + \ifnum \value{next@page} > \value{page}\relax + % We need to check the page next@page: + \@ifundefined{No@Questions@Pg@\arabic{next@page}}% + {\setcounter{incmp@ques}{\value{latest@ques}}% + \let\next@incompii=\relax + }% + {\addtocounter{next@page}{-1}% + \let\next@incompii = \chk@incompii + }% + \else + % There's no incomplete question: + \setcounter{incmp@ques}{-1}% + \let\next@incompii=\relax + \fi + \next@incompii +}% chk@incompii \def\ifincomplete#1#2{% + % We need to pass the arguments to \chk@ifincomp; we save them in + % macros so they won't be messed up by the call to \Find@Incmp@ques: \def\incomp@first{#1}% \def\incomp@second{#2}% + % If there's a \noquestionsonthispage command on this page, then + % we assume nothing from this page is incomplete: + \@ifundefined{No@Questions@Pg@\thepage}% + {\chk@ifincomp}% + {\incomp@second}% +}% ifincomplete + +\def\chk@ifincomp{% \Find@Incmp@ques + % If there's no incomplete question, \Find@Incmp@ques sets the + % counter incmp@ques to -1: \ifnum \theincmp@ques < 0\relax \incomp@second \else - \@ifundefined{Pg@@endquestions}% - {\incomp@first}% - {\ifnum \thepage < \PgInfo@get{@endquestions}\relax - \incomp@first - \else - \incomp@second - \fi - }% + % Are we after a page with \nomorequestions? + \@ifundefined{Pg@@endquestions}% + {\incomp@first}% + {\ifnum \thepage < \PgInfo@get{@endquestions}\relax + \incomp@first + \else + \incomp@second + \fi + }% \fi -} +}% chk@ifincomp %-------------------------------------------------------------------- % These are the commands for dealing with hlfcntr's, i.e., the things @@ -2546,9 +2406,11 @@ % \questionobject@pluspagecheck. \newcommand{\first@questionobject}{% \setcounter{ques@object}{1}% - \edef\q@object@label{% - question\arabic{question}@object\arabic{ques@object}}% - \PgInfo@write{\q@object@label}% + % \PgInfo@write expands it's argument, so we don't need edef: +% \edef\q@object@label{% +% question\arabic{question}@object\arabic{ques@object}}% +% \PgInfo@write{\q@object@label}% + \PgInfo@write{question\arabic{question}@object\arabic{ques@object}}% }% first@questionobject % \addquestionobject will be used by each part, subpart, and @@ -2557,18 +2419,35 @@ % subpart, etc. starting on that page: \newcommand{\addquestionobject}{% \addtocounter{ques@object}{1}% - \edef\q@object@label{% - question\arabic{question}@object\arabic{ques@object}}% - \PgInfo@write{\q@object@label}% + % \PgInfo@write expands it's argument, so we don't need edef: +% \edef\q@object@label{% +% question\arabic{question}@object\arabic{ques@object}}% +% \PgInfo@write{\q@object@label}% + \PgInfo@write{question\arabic{question}@object\arabic{ques@object}}% }% addquestionobject -% \questionobject@pluspagecheck will be used by each choice. It uses -% the questionobject to check if we're the first one on the current -% page, since choices don't have labels the way that questions, parts, -% subparts, and subsubparts do (those things use the label to check if -% they're the first thing on the page). +% \questionobject@pluspagecheck will be used by each choice, as well +% as by any \part, \subpart, or \subsubpart that's inside of a +% solution. It uses the questionobject to check if we're the first +% one on the current page, since choices (and questions etc. inside of +% solution environments) don't have labels the way that questions, +% parts, subparts, and subsubparts do (those things use the label to +% check if they're the first thing on the page). \newcommand{\questionobject@pluspagecheck}{% + % We don't want to do any of this if we're both inside a solution + % environment and not printing answers (because we want to avoid + % incrementing ques@object): + \if@insolution + \ifprintanswers + \doqobj@ppchk + \fi + \else + \doqobj@ppchk + \fi +}% questionobject@pluspagecheck +\newcommand{\doqobj@ppchk}{% \addtocounter{ques@object}{1}% + % We need the edef because we check the page of \q@object@label: \edef\q@object@label{% question\arabic{question}@object\arabic{ques@object}}% \PgInfo@write{\q@object@label}% @@ -2579,7 +2458,7 @@ \global\expandafter\edef\csname Contin@\theCurr@Page\endcsname{\arabic{question}}% \fi -}% questionobject@pluspagecheck +}% doqobj@ppchk @@ -2755,47 +2634,56 @@ \cover@question@error \fi \@checkqueslevel{subpart}% - \addtocounter{numsubparts}{1}% - % Important: Don't leave any blank lines inside of - % \pageinfo@commands!! This token list will be dumped into - % horizontal mode by \everypar, and so any blank lines will - % cause paragraph breaks. - \temp@toks={% - \edef\@subpartlabel{subpart@\arabic{question}% - @\arabic{partno}@\arabic{subpart}}% - \PgInfo@write{\@subpartlabel}% - \addquestionobject - % In addition to the \PgInfo@write we use an actual \label - % command. We do this in order to make the question numbers in - % the grade tables into \ref's, so that if the user says - % \usepackage{hyperref}, those question numbers will be clickable. - % - % A further purpose of these labels (which we actually do for all - % questions, parts, subparts, and subsubparts) is that if a - % question (or part, etc.) is, e.g., moved from one page to - % another, LaTeX will notice this and warn the user that LaTeX - % must be run one more time to be sure everything is correct. - % - % We need to do this even though we've already included code to - % check when point totals change because questions (and parts, - % etc.) know what page they're on from reading the info written to - % the .aux file on the previous run. Thus, if a question (or - % part, etc.) is moved to a different page, then the pointsonpage - % totals won't notice until the *second* subsequent run of LaTeX, - % and so there'll be no warning to the user on the *first* run. - % Including these labels gives the user a warning on that first - % run. - \label{\@subpartlabel}% - \set@counter@to@pageof{Curr@Page}{\@subpartlabel}% - \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax - % We're the first \question, \part, \subpart, \subsubpart, - % or choice on this page: - \global\expandafter\edef\csname - Contin@\theCurr@Page\endcsname{\arabic{question}}% - \fi - \the\pagepoint@commands - \global \pageinfo@commands={}% - }% temp@toks + \if@insolution + % We don't count this subpart, so no addtocounter{numsubparts}. + \temp@toks={% + \questionobject@pluspagecheck + \global \pageinfo@commands={}% + % We omit the pagepoint@commands + }% temp@toks + \else + \addtocounter{numsubparts}{1}% + % Important: Don't leave any blank lines inside of + % \pageinfo@commands!! This token list will be dumped into + % horizontal mode by \everypar, and so any blank lines will + % cause paragraph breaks. + \temp@toks={% + \edef\@subpartlabel{subpart@\arabic{question}% + @\arabic{partno}@\arabic{subpart}}% + \PgInfo@write{\@subpartlabel}% + \addquestionobject + % In addition to the \PgInfo@write we use an actual \label + % command. We do this in order to make the question numbers in + % the grade tables into \ref's, so that if the user says + % \usepackage{hyperref}, those question numbers will be clickable. + % + % A further purpose of these labels (which we actually do for all + % questions, parts, subparts, and subsubparts) is that if a + % question (or part, etc.) is, e.g., moved from one page to + % another, LaTeX will notice this and warn the user that LaTeX + % must be run one more time to be sure everything is correct. + % + % We need to do this even though we've already included code to + % check when point totals change because questions (and parts, + % etc.) know what page they're on from reading the info written to + % the .aux file on the previous run. Thus, if a question (or + % part, etc.) is moved to a different page, then the pointsonpage + % totals won't notice until the *second* subsequent run of LaTeX, + % and so there'll be no warning to the user on the *first* run. + % Including these labels gives the user a warning on that first + % run. + \label{\@subpartlabel}% + \set@counter@to@pageof{Curr@Page}{\@subpartlabel}% + \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax + % We're the first \question, \part, \subpart, \subsubpart, + % or choice on this page: + \global\expandafter\edef\csname + Contin@\theCurr@Page\endcsname{\arabic{question}}% + \fi + \the\pagepoint@commands + \global \pageinfo@commands={}% + }% temp@toks + \fi \append@toklist \pageinfo@commands \temp@toks \ifhmode % Remove any skips at the end of the previous paragraph @@ -2817,47 +2705,56 @@ \cover@question@error \fi \@checkqueslevel{subsubpart}% - \addtocounter{numsubsubparts}{1}% - % Important: Don't leave any blank lines inside of - % \pageinfo@commands!! This token list will be dumped into - % horizontal mode by \everypar, and so any blank lines will - % cause paragraph breaks. - \temp@toks={% - \edef\@subsubpartlabel{subsubpart@\arabic{question}% - @\arabic{partno}@\arabic{subpart}@\arabic{subsubpart}}% - \PgInfo@write{\@subsubpartlabel}% - \addquestionobject - % In addition to the \PgInfo@write we use an actual \label - % command. We do this in order to make the question numbers in - % the grade tables into \ref's, so that if the user says - % \usepackage{hyperref}, those question numbers will be clickable. - % - % A further purpose of these labels (which we actually do for all - % questions, parts, subparts, and subsubparts) is that if a - % question (or part, etc.) is, e.g., moved from one page to - % another, LaTeX will notice this and warn the user that LaTeX - % must be run one more time to be sure everything is correct. - % - % We need to do this even though we've already included code to - % check when point totals change because questions (and parts, - % etc.) know what page they're on from reading the info written to - % the .aux file on the previous run. Thus, if a question (or - % part, etc.) is moved to a different page, then the pointsonpage - % totals won't notice until the *second* subsequent run of LaTeX, - % and so there'll be no warning to the user on the *first* run. - % Including these labels gives the user a warning on that first - % run. - \label{\@subsubpartlabel}% - \set@counter@to@pageof{Curr@Page}{\@subsubpartlabel}% - \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax - % We're the first \question, \part, \subpart, \subsubpart, - % or choice on this page: - \global\expandafter\edef\csname - Contin@\theCurr@Page\endcsname{\arabic{question}}% - \fi - \the\pagepoint@commands - \global \pageinfo@commands={}% - }% temp@toks + \if@insolution + % We don't count this subsubpart, so no addtocounter{numsubsubparts}. + \temp@toks={% + \questionobject@pluspagecheck + \global \pageinfo@commands={}% + % We omit the pagepoint@commands + }% temp@toks + \else + \addtocounter{numsubsubparts}{1}% + % Important: Don't leave any blank lines inside of + % \pageinfo@commands!! This token list will be dumped into + % horizontal mode by \everypar, and so any blank lines will + % cause paragraph breaks. + \temp@toks={% + \edef\@subsubpartlabel{subsubpart@\arabic{question}% + @\arabic{partno}@\arabic{subpart}@\arabic{subsubpart}}% + \PgInfo@write{\@subsubpartlabel}% + \addquestionobject + % In addition to the \PgInfo@write we use an actual \label + % command. We do this in order to make the question numbers in + % the grade tables into \ref's, so that if the user says + % \usepackage{hyperref}, those question numbers will be clickable. + % + % A further purpose of these labels (which we actually do for all + % questions, parts, subparts, and subsubparts) is that if a + % question (or part, etc.) is, e.g., moved from one page to + % another, LaTeX will notice this and warn the user that LaTeX + % must be run one more time to be sure everything is correct. + % + % We need to do this even though we've already included code to + % check when point totals change because questions (and parts, + % etc.) know what page they're on from reading the info written to + % the .aux file on the previous run. Thus, if a question (or + % part, etc.) is moved to a different page, then the pointsonpage + % totals won't notice until the *second* subsequent run of LaTeX, + % and so there'll be no warning to the user on the *first* run. + % Including these labels gives the user a warning on that first + % run. + \label{\@subsubpartlabel}% + \set@counter@to@pageof{Curr@Page}{\@subsubpartlabel}% + \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax + % We're the first \question, \part, \subpart, \subsubpart, + % or choice on this page: + \global\expandafter\edef\csname + Contin@\theCurr@Page\endcsname{\arabic{question}}% + \fi + \the\pagepoint@commands + \global \pageinfo@commands={}% + }% temp@toks + \fi \append@toklist \pageinfo@commands \temp@toks \ifhmode % Remove any skips at the end of the previous paragraph @@ -2984,44 +2881,53 @@ \cover@question@error \fi \@checkqueslevel{part}% - \addtocounter{numparts}{1}% - % Important: Don't leave any blank lines inside of - % \pageinfo@commands!! This token list will be dumped into - % horizontal mode by \everypar, and so any blank lines will - % cause paragraph breaks. - \temp@toks={% - \edef\@partlabel{part@\arabic{question}@\arabic{partno}}% - \PgInfo@write{\@partlabel}% - \addquestionobject - % In addition to the \PgInfo@write we use an actual \label - % command. We do this in order to make the question numbers in - % the grade tables into \ref's, so that if the user says - % \usepackage{hyperref}, those question numbers will be clickable. - % - % A further purpose of these labels (which we actually do for all - % questions, parts, subparts, and subsubparts) is that if a - % question (or part, etc.) is, e.g., moved from one page to - % another, LaTeX will notice this and warn the user that LaTeX - % must be run one more time to be sure everything is correct. - % - % We need to do this even though we've already included code to - % check when point totals change because questions (and parts, - % etc.) know what page they're on from reading the info written to - % the .aux file on the previous run. Thus, if a question (or - % part, etc.) is moved to a different page, then the pointsonpage - % totals won't notice until the *second* subsequent run of LaTeX, - % and so there'll be no warning to the user on the *first* run. - % Including these labels gives the user a warning on that first - % run. - \label{\@partlabel}% - \set@counter@to@pageof{Curr@Page}{\@partlabel}% - \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax - \global\expandafter\edef\csname - Contin@\theCurr@Page\endcsname{\arabic{question}}% - \fi - \the\pagepoint@commands - \global \pageinfo@commands={}% - }% + \if@insolution + % We don't count this part, so no addtocounter{numparts}. + \temp@toks={% + \questionobject@pluspagecheck + \global \pageinfo@commands={}% + % We omit the pagepoint@commands + }% temp@toks + \else + \addtocounter{numparts}{1}% + % Important: Don't leave any blank lines inside of + % \pageinfo@commands!! This token list will be dumped into + % horizontal mode by \everypar, and so any blank lines will + % cause paragraph breaks. + \temp@toks={% + \edef\@partlabel{part@\arabic{question}@\arabic{partno}}% + \PgInfo@write{\@partlabel}% + \addquestionobject + % In addition to the \PgInfo@write we use an actual \label + % command. We do this in order to make the question numbers in + % the grade tables into \ref's, so that if the user says + % \usepackage{hyperref}, those question numbers will be clickable. + % + % A further purpose of these labels (which we actually do for all + % questions, parts, subparts, and subsubparts) is that if a + % question (or part, etc.) is, e.g., moved from one page to + % another, LaTeX will notice this and warn the user that LaTeX + % must be run one more time to be sure everything is correct. + % + % We need to do this even though we've already included code to + % check when point totals change because questions (and parts, + % etc.) know what page they're on from reading the info written to + % the .aux file on the previous run. Thus, if a question (or + % part, etc.) is moved to a different page, then the pointsonpage + % totals won't notice until the *second* subsequent run of LaTeX, + % and so there'll be no warning to the user on the *first* run. + % Including these labels gives the user a warning on that first + % run. + \label{\@partlabel}% + \set@counter@to@pageof{Curr@Page}{\@partlabel}% + \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax + \global\expandafter\edef\csname + Contin@\theCurr@Page\endcsname{\arabic{question}}% + \fi + \the\pagepoint@commands + \global \pageinfo@commands={}% + }% temp@toks + \fi \append@toklist \pageinfo@commands \temp@toks \ifhmode % Remove any skips at the end of the previous paragraph @@ -3952,6 +3858,8 @@ \def\subpart@ref{subpart} \def\subsubpart@ref{subsubpart} +% Note: \answerclearance is also used by \fillin + \newlength\answerlinelength \newlength\answerskip \newlength\answerclearance @@ -3993,15 +3901,134 @@ \par }% answerline +%-------------------------------------------------------------------- +% \fillin, for fill-in-the-blank questions + +\newlength\fillinlinelength +\setlength\fillinlinelength{1in} + +% \fillin can take two optional arguments. +% +% The first optional argument is the answer to be printed above the line +% when \printanswers is in effect; the default value is empty. That +% line is printed a distance of \answerclearance below the baseline. +% +% The second optional argument is the length of the line that we print; +% the default value is \fillinlinelength. The value of +% \fillinlinelength is set with the command +% +% \setlength\fillinlinelength{1in} +% +% and can be changed by giving a new \setlength command. +% +% When answers are being printed, the optional argument is printed +% subject to the declarations in the argument of the last +% \CorrectChoiceEmphasis command. It is centered on the line unless it +% is too long, in which case it extends to the right of the line. +% +% \fillin eats (and ignores) space characters appearing before the +% first optional argument. It also eats (and ignores) space +% characters appearing after the first optional argument and before +% the second optional argument. However, if exactly one optional +% argument appears, and if there are one or more space characters +% following that one optional argument, then those spaces are replaced +% by a single space character, but not eaten. + +\newcommand\fillin[1][{}]{% + \def\fillin@ans{#1}% + \fillin@relay +}% fillin + +\newcommand\fillin@relay{% + % We use \exam@ifnextchar, a variation on \@ifnextchar. + % If \exam@ifnextchar encounters one or more space characters + % followed by a [, then those spaces are ignored (just as they would + % be by \@ifnextchar). However, if one or more space characters are + % followed by a non-space character other than [, then + % \exam@ifnextchar inserts a space following the + % {\@fillin@relay[\fillinlinelength]} that is the third argument to + % \exam@ifnextchar. + \exam@ifnextchar[{\@fillin@relay} + {\@fillin@relay[\fillinlinelength]}% +}% fillin@relay + +\def\@fillin@relay[#1]{% + % The first argument is in \fillin@ans, the second is #1. + \leavevmode + \ifprintanswers + \rlap{\raise -\answerclearance \hbox to #1{\hrulefill}}% + \begingroup + \setbox0 \hbox{\color@begingroup + \CorrectChoice@Emphasis \fillin@ans \color@endgroup}% + \ifdim\wd0 > #1\relax + \hbox{\CorrectChoice@Emphasis \fillin@ans}% + \else + \hbox to #1{\CorrectChoice@Emphasis \hfil \fillin@ans \hfil}% + \fi + \endgroup + \else + \raise -\answerclearance \hbox to #1{\hrulefill}% + \fi +}% @fillin@relay + +% \exam@ifnextchar is used by \fillin. +% \exam@ifnextchar is a variation of \@ifnextchar that does not always +% ignore space tokens. If \exam@ifnextchar encounters one or more +% space tokens, it makes note of that (with the command +% \@tempswatrue). If the first non-space character encountered +% matches argument #1, then any spaces that had been encountered are +% ignored. However, if one or more spaces are encountered and the +% first non-space character found does not match argument #1, then +% \exam@ifnextchar produces argument #3 followed by a space character. +% (This differs from the behavior of \new@ifnextchar in amsgen.sty, +% which does lookahead for any character, including a space.) This +% code (as well as the idea for it) is due to Dan Luecking and Ulrich +% Diez. +\long\def\exam@ifnextchar#1#2#3{% + \let\reserved@d=#1% + \def\reserved@a{#2}% + \def\reserved@b{#3}% + % The following says we haven't yet seen any spaces: + \@tempswafalse + \futurelet\@let@token\exam@ifnch +}% exam@ifnextchar + +\def\exam@ifnch{% + \ifx\@let@token\@sptoken + % Signal that we've found a space: + \@tempswatrue + \let\reserved@c\exam@xifnch % this gobbles the space + \else + \ifx\@let@token\reserved@d + \let\reserved@c\reserved@a + \else + \if@tempswa + \def\reserved@c{\expandafter\reserved@b\space}% + \else + \let\reserved@c\reserved@b + \fi + \fi + \fi + \reserved@c +}% exam@ifnch + +% The following defines \exam@xifnch so that it will eat a space +% following it and then call \exam@ifnch: +{% keep redefinition of \: local + \def\:{\exam@xifnch} + \expandafter\gdef\: {\futurelet\@let@token\exam@ifnch} +} + %-------------------------------------------------------------------- % \fillwithlines -% \fillwithlines takes one argument, which is either a length or \fill, -% and it fills that much vertical space with horizontal lines that run -% the length of the current line. That is, they extend from the -% current left margin (which depends on whether we're in a question, -% part, subpart, or subsubpart) to the right margin. +% \fillwithlines takes one argument, which is either a length or \fill +% or \stretch{number}, and it fills that much vertical space with +% horizontal lines that run the length of the current line. That is, +% they extend from the current left margin (which depends on whether +% we're in a question, part, subpart, or subsubpart) to the right +% margin. % % The distance between the lines is \linefillheight, whose default value % is set with the command @@ -4053,10 +4080,11 @@ % with solid lines. % \fillwithdottedlines takes one argument, which is either a length or -% \fill, and it fills that much vertical space with dotted lines that -% run the length of the current line. That is, they extend from the -% current left margin (which depends on whether we're in a question, -% part, subpart, or subsubpart) to the right margin. +% \fill or \stretch{number}, and it fills that much vertical space +% with dotted lines that run the length of the current line. That is, +% they extend from the current left margin (which depends on whether +% we're in a question, part, subpart, or subsubpart) to the right +% margin. % % The distance between the lines is \dottedlinefillheight, whose % default value is set with the command @@ -4083,7 +4111,130 @@ % no matter where on the page it happens to start: \cleaders \copy0 \vskip #1 \hbox{}% \endgroup -} +}% fillwithdottedlines + +%-------------------------------------------------------------------- +% \fillwithgrid + + +% \fillwithgrid is similar to \fillwithlines, except that it +% fills the space with a grid. + +% \fillwithgrid takes one argument, which is either a length or \fill +% or \stretch{number}, and it fills that much vertical space with a +% grid that runs the length of the current line. That is, it extends +% from the current left margin (which depends on whether we're in a +% question, part, subpart, or subsubpart) to the right margin. +% +% The default grid size and grid line thickness were set by the +% commands +% +% \setlength{\gridsize}{5mm} +% \setlength{\gridlinewidth}{0.1pt} +% +% You can change either or both of those by giving new \setlength +% commands. The period of the grid is \gridsize (both horizontally +% and vertically). That is, the horizontal distance from the left +% edge of one vertical line to the left edge of the next vertical line +% is \gridsize, as is the vertical distance from the top edge of one +% horizontal line to the top edge of the next horizontal line. Thus, +% each square has outer side length equal to \gridsize+\gridlinewidth. + +% By default, the created grids are in black. However, if you give the +% commands +% +% \usepackage{color} +% \colorgrids +% +% then the grids will be in color, by default a light gray. That +% default color was defined by the command +% +% \definecolor{GridColor}{gray}{0.8} +% +% You can change the color by redefining the color GridColor by giving +% a new \definecolor command. + +\newif\if@colorgrids +\newcommand\colorgrids{% + \@ifundefined{definecolor} + {% + \ClassError{exam}{% + You must load the color package with the command\MessageBreak + \space\space\protect\usepackage{color}\MessageBreak + in order to use the command \protect\colorgrids + }{% + This command makes use of the package color.sty,\MessageBreak + and so you have to load color.sty before your\MessageBreak + \protect\begin{document} command.\MessageBreak + }% + }% + {% + \definecolor{GridColor}{gray}{0.8} + \@colorgridstrue + }% +}% \colorgrids +\newcommand\nocolorgrids{\@colorgridsfalse} +\nocolorgrids + +\newlength\gridsize +\newlength\gridlinewidth +\setlength{\gridsize}{5mm} +\setlength{\gridlinewidth}{0.1pt} + +\def\fillwithgrid#1{% + \begingroup + \ifhmode + \par + \fi + \hrule height \z@ + \nobreak + + % We first set box0 equal to an \hbox which, when printed, is a + % square with width and height equal to \gridsize+\gridlinewidth, + % but which has + % width equal to \gridsize, + % height equal to \gridsize, and + % depth equal to 0pt. + % When we put multiple copies of it together using \leaders or + % \cleaders, the right edge will coincide with the left edge of the + % next box and the bottom edge will coincide with the top edge of + % the box below it. + \setlength{\@tempdima}{\gridsize} + \addtolength{\@tempdima}{\gridlinewidth} + \setlength{\@tempdimb}{\gridsize} + \addtolength{\@tempdimb}{-\gridlinewidth} + \setbox0=\hbox{% + \rlap{\vrule height \gridsize depth \gridlinewidth width \gridlinewidth}% + \rlap{\vrule height \gridsize depth -\@tempdimb width \@tempdima}% + \vrule height 0pt depth \gridlinewidth width \@tempdima + \llap{\vrule height \gridsize depth \gridlinewidth width \gridlinewidth}% + }% + \wd0=\gridsize + \dp0=0pt + % Now we set box1 equal to an \hbox containing a single line of + % copies of box0. We use \leaders (instead of \cleaders) so that + % if we use it twice on a page, once with a question and once + % with a part, the boxes will line up vertically. We add a kern of + % \gridlinewidth at the right because the rightmost vertical line + % appears to the right of where the \leaders command thinks that it + % appears. + \setbox1=\hbox to \textwidth{% + \color@begingroup + \if@colorgrids + \color{GridColor}% + \fi + \hskip \@totalleftmargin \leaders\copy0\hfil \kern\gridlinewidth + \color@endgroup + }% + % Finally: We create the grid, using \cleaders: We use \cleaders + % (rather than \leaders) so that a given vertical space will always + % produce the same number of lines no matter where on the page it + % happens to start. We add a kern of \gridlinewidth because the + % bottommost horizontal line appears below where the \cleaders + % command thinks that it appears. + \cleaders \copy1 \vskip #1 \kern \gridlinewidth \hbox{}% + \endgroup +}% fillwithgrid %-------------------------------------------------------------------- % \makeemptybox @@ -4331,8 +4482,9 @@ % \bonuspointtable, \combinedpointtable, \partialgradetable, % \partialbonusgradetable, \partialcombinedtable, \partialpointtable, % \partialbonuspointtable, \partialcombinedpointtable, -% \begingradingrange, \endgradingrange, \pointsinrange, and -% \bonuspointsinrange. +% \begingradingrange, \endgradingrange, \pointsinrange, +% \bonuspointsinrange, \firstqinrange, \lastqinrange, and +% \numqinrange. % The possibilities are @@ -4402,6 +4554,10 @@ % \pointsinrange{whatever} % \bonuspointsinrange{whatever} % +% \firstqinrange{whatever} +% \lastqinrange{whatever} +% \numqinrange{whatever} +% % where ``whatever'' is a label chosen by the user. % If one or both optional arguments are omitted, the defaults are @@ -4429,11 +4585,11 @@ \addtocounter{num@cols}{1}% \immediate\write\@mainaux {\string\expandafter\string\gdef - \string\csname\space tbl@#1@firstq\string\endcsname + \string\csname\space range@#1@firstq\string\endcsname {\arabic{num@cols}}}% \write\@mainaux {\string\expandafter\string\gdef - \string\csname\space tbl@#1@firstp\string\endcsname + \string\csname\space range@#1@firstp\string\endcsname {\thepage}}% }% begingradingrange @@ -4441,11 +4597,11 @@ \setcounter{num@cols}{\value{question}}% \immediate\write\@mainaux {\string\expandafter\string\gdef - \string\csname\space tbl@#1@lastq\string\endcsname + \string\csname\space range@#1@lastq\string\endcsname {\arabic{num@cols}}}% \write\@mainaux {\string\expandafter\string\gdef - \string\csname\space tbl@#1@lastp\string\endcsname + \string\csname\space range@#1@lastp\string\endcsname {\thepage}}% }% endgradingrange @@ -4706,18 +4862,18 @@ \def\find@qrange#1{% % We're doing a table indexed by question numbers. \if@partial - \@ifundefined{tbl@\tbl@range @firstq}% + \@ifundefined{range@\tbl@range @firstq}% {% \range@undefined }% {% - \@ifundefined{tbl@\tbl@range @lastq}% + \@ifundefined{range@\tbl@range @lastq}% {% \range@undefined }% {% - \edef\tbl@firstq{\csname tbl@\tbl@range @firstq\endcsname}% - \edef\tbl@lastq{\csname tbl@\tbl@range @lastq\endcsname}% + \edef\tbl@firstq{\csname range@\tbl@range @firstq\endcsname}% + \edef\tbl@lastq{\csname range@\tbl@range @lastq\endcsname}% % Check that firstq precedes or equals lastq: \ifnum \tbl@firstq > \tbl@lastq\relax \fbox{Error: Grading Range `\tbl@range ': @@ -5231,18 +5387,18 @@ % combined table, it's the last page to have either bonus or % non-bonus points). \if@partial - \@ifundefined{tbl@\tbl@range @firstp}% + \@ifundefined{range@\tbl@range @firstp}% {% \range@undefined }% {% - \@ifundefined{tbl@\tbl@range @lastp}% + \@ifundefined{range@\tbl@range @lastp}% {% \range@undefined }% {% - \edef\tbl@firstp{\csname tbl@\tbl@range @firstp\endcsname}% - \edef\tbl@lastp{\csname tbl@\tbl@range @lastp\endcsname}% + \edef\tbl@firstp{\csname range@\tbl@range @firstp\endcsname}% + \edef\tbl@lastp{\csname range@\tbl@range @lastp\endcsname}% % Check that firstp precedes or equals lastp: \ifnum \tbl@firstp > \tbl@lastp\relax \fbox{Error: Grading Range `\tbl@range ': @@ -6068,18 +6224,18 @@ }% bad@range \def\read@range{% - \@ifundefined{tbl@\tbl@range @firstq}% + \@ifundefined{range@\tbl@range @firstq}% {% \bad@range }% {% - \@ifundefined{tbl@\tbl@range @lastq}% + \@ifundefined{range@\tbl@range @lastq}% {% \bad@range }% {% - \edef\tbl@firstq{\csname tbl@\tbl@range @firstq\endcsname}% - \edef\tbl@lastq{\csname tbl@\tbl@range @lastq\endcsname}% + \edef\tbl@firstq{\csname range@\tbl@range @firstq\endcsname}% + \edef\tbl@lastq{\csname range@\tbl@range @lastq\endcsname}% % Check that firstq precedes or equals lastq: \ifnum \tbl@firstq > \tbl@lastq\relax \fbox{Error: Grading Range `\tbl@range ': @@ -6129,7 +6285,39 @@ \next@countloop }% do@countloop +%-------------------------------------------------------------------- +% \firstqinrange, \lastqinrange, and \numqinrange. +\newcommand{\firstqinrange}[1]{% + \@ifundefined{range@#1@firstq}% + {\mbox{\normalfont\bf ??}}% + {\csname range@#1@firstq\endcsname}% +}% firstqinrange + +\newcommand{\lastqinrange}[1]{% + \@ifundefined{range@#1@lastq}% + {\mbox{\normalfont\bf ??}}% + {\csname range@#1@lastq\endcsname}% +}% lastqinrange + +\newcommand{\numqinrange}[1]{% + \@ifundefined{range@#1@firstq}% + {% + \mbox{\normalfont\bf ??}% + }% + {% + \@ifundefined{range@#1@lastq}% + {% + \mbox{\normalfont\bf ??}% + }% + {% + \setcounter{@iterator}{\csname range@#1@lastq\endcsname}% + \addtocounter{@iterator}{-\csname range@#1@firstq\endcsname}% + \stepcounter{@iterator}% + \arabic{@iterator}% + }% + }% +}% numqinrange %-------------------------------------------------------------------- %-------------------------------------------------------------------- @@ -6158,6 +6346,15 @@ \def\cancelspace{\cancelspacetrue} \def\nocancelspace{\cancelspacefalse} +% \if@insolution will be true while we're inside of any of the +% solution environments. This is used to supress \PgInfo@write and +% \label commands generated if there's a parts (or subparts, or +% subsubparts) environment inside of a solution. (It won't suppress +% the labels for the question objects, since a question object is +% never a label that's been used before.) +\newif\if@insolution +\@insolutionfalse + \newcommand\SolutionEmphasis[1]{% \def\Solution@Emphasis{#1}% } @@ -6169,6 +6366,8 @@ % default value of which is 0pt). \newenvironment{solution}[1][0pt]% {% + \@insolutiontrue % cancelled by the end of the environment + \@addpointsfalse % cancelled by the end of the environment \ifprintanswers \begingroup \Solution@Emphasis @@ -6200,6 +6399,8 @@ % then the box is entirely omitted when printanswers is false. \newenvironment{solutionorbox}[1][-1pt]% {% + \@insolutiontrue % cancelled by the end of the environment + \@addpointsfalse % cancelled by the end of the environment \ifprintanswers \begingroup \Solution@Emphasis @@ -6247,6 +6448,8 @@ % default value of which is 0pt). \newenvironment{solutionorlines}[1][0pt]% {% + \@insolutiontrue % cancelled by the end of the environment + \@addpointsfalse % cancelled by the end of the environment \ifprintanswers \begingroup \Solution@Emphasis @@ -6276,6 +6479,8 @@ % argument (the default value of which is 0pt). \newenvironment{solutionordottedlines}[1][0pt]% {% + \@insolutiontrue % cancelled by the end of the environment + \@addpointsfalse % cancelled by the end of the environment \ifprintanswers \begingroup \Solution@Emphasis @@ -6299,14 +6504,47 @@ \fi }% +% If printanswers is true, we print the solution using a TheSolution +% environment. If printanswers is false and cancelspace is false, +% we insert a grid occupying vertically the optional argument (the +% default value of which is 0pt). +\newenvironment{solutionorgrid}[1][0pt]% + {% + \@insolutiontrue % cancelled by the end of the environment + \@addpointsfalse % cancelled by the end of the environment + \ifprintanswers + \begingroup + \Solution@Emphasis + \begin{TheSolution}% + \else + \ifcancelspace + % Do nothing + \else + \par + \penalty 0 + \fillwithgrid{#1}% + \fi + \setbox\z@\vbox\bgroup + \fi + }{% + \ifprintanswers + \end{TheSolution}% + \endgroup + \else + \egroup + \fi + }% + + % The environment TheSolution is called from the solution, -% solutionorbox, solutionorlines, and solutionordottedlines -% environments when printanswers is true. It uses Donald Arseneau's -% framed.sty macros (included at the end of this file) to allow the -% solution to be broken across pages and have each piece enclosed in -% an fbox (or a colorbox, if the user has given the command -% \shadedsolutions), (or no box at all, if the user has given the -% command \unframedsolutions). +% solutionorbox, solutionorlines, solutionordottedlines, and +% solutionorgrid environments when printanswers is true. It uses +% Donald Arseneau's framed.sty macros (included at the end of this +% file) to allow the solution to be broken across pages and have each +% piece enclosed in an fbox (or a colorbox, if the user has given the +% command \shadedsolutions), (or no box at all, if the user has given +% the command \unframedsolutions). + % Of course, the user can change TheSolution with a \renewenvironment % command. \newcommand{\solutiontitle}{\noindent\textbf{Solution:}\enspace} @@ -6369,6 +6607,90 @@ } \def\unframedsolutions{\@framedsolutionsfalse\@shadedsolutionsfalse} + +% The solutionbox environment is different from the other solution +% environments (solution, solutionorbox, solutionorlines, +% solutionordottedlines, and solutionorgrid), in that +% +% (1) The box is always printed, whether answers are being printed +% or not. +% +% (2) The argument giving the size of the box is a required +% argument, not an optional argument, and so it should be enclosed +% in braces, not in brackets. It can be either a length or +% \stretch{number}. +% +% (3) We make no use of the TheSolution environment; the solutionbox +% environment is completely freestanding. +% +% If answers are not being printed then only the box is printed, with +% nothing in it. If answers are being printed, then the solution is +% printed inside of the box. +% +% Note: It's the user's responsibility to be sure that the box is +% large enough to hold the solution! If the solution takes up too +% much vertical space, then it will spill out of the bottom of the +% box, overwriting whatever follows the box. + +\newbox\exam@box +\newenvironment{solutionbox}[1]{% + \@insolutiontrue % cancelled by the end of the environment + \@addpointsfalse % cancelled by the end of the environment + \def\solutionbox@size{#1}% saved for end of environment + \@tempdima=\textwidth + \advance\@tempdima -\@totalleftmargin + \advance\@tempdima -6\fboxsep + \advance\@tempdima -2\fboxrule + % Confine the \Solution@Emphasis, as well as anything the user puts + % into the solution (e.g., \color{red}, or whatever); don't say + % \endgroup until after using \box\exam@box: + \begingroup + \Solution@Emphasis + % We save the solution in a box of the proper width. We'll either + % print it (if we're printing solutions) or throw it away by just + % not using it before the environment ends: + \setbox\exam@box=\vtop\bgroup + \hsize=\@tempdima + \leftskip=0pt + \rightskip=0pt + \vskip 2\fboxsep + \solutiontitle + \ignorespaces + }% + {% + \unskip + \egroup + % OK, the solution is now inside \box\exam@box. + % Set the height and depth to 0pt, so that if we use it we won't + % be advancing our position on the page: + \ht\exam@box=0pt + \dp\exam@box=0pt + \par + \vspace{\parskip} + \ifprintanswers + % We enclose the \vtop in an \hbox to avoid having the + % indentation of the enclosing list environment (implemented via + % \parshape) shift us to the right when we enter horizontal + % mode. If we don't use this \hbox, then we'd have to comment + % out the \hskip \@totalleftmargin: + \hbox to \textwidth{% + \noindent + \hskip\@totalleftmargin + \hskip3\fboxsep\hskip\fboxrule + \box\exam@box\hfill + }% + \par\nointerlineskip + \fi + \endgroup % Finish confining the \Solution@Emphasis + \makeemptybox{\solutionbox@size}% + } + + + + + + + %-------------------------------------------------------------------- %-------------------------------------------------------------------- -- cgit v1.2.3