3 % A LaTeX2e document class for preparing exams.
6 %% Copyright (c) 1994, 1997, 2000, 2004, 2008, 2011,
7 %% 2015, 2017 Philip S. Hirschhorn
9 % This work may be distributed and/or modified under the
10 % conditions of the LaTeX Project Public License, either version 1.3
11 % of this license or (at your option) any later version.
12 % The latest version of this license is in
13 % http://www.latex-project.org/lppl.txt
14 % and version 1.3 or later is part of all distributions of LaTeX
15 % version 2003/12/01 or later.
17 % This work has the LPPL maintenance status "author-maintained".
19 % This work consists of the files exam.cls and examdoc.tex.
22 % The user's guide for exam.cls is in the file examdoc.tex.
26 %%% Department of Mathematics
28 %%% Wellesley, MA 02481
31 % The newest version of this documentclass should always be available
32 % from my web page: http://www-math.mit.edu/~psh/
35 \def\fileversion{2.603}
36 \def\filedate{2017/12/17}
37 %---------------------------------------------------------------------
38 %---------------------------------------------------------------------
40 % If there's some feature that you'd like that this file doesn't
41 % provide, tell me about it.
49 % Piet van Oostrum, from whose excellent ``fancyheadings.sty'' we
50 % shamelessly stole most of the code for setting the headers and
53 % Mate Wierdl <mw@wierdlmpc.msci.memphis.edu>, who contributed the
54 % code so that if the number of points is ``1'', then the default
55 % value of \pointname will print ``1 point'' instead of ``1 points''.
57 % Tom Brikowski <brikowi@utdallas.edu>, who contributed the code for
58 % making the number of points and number of questions available as
59 % macros (as well as the idea of putting the number of points in a
60 % box, instead of in parentheses). (I changed his code to make this
61 % all optional, so if there are errors there, it's my fault and not
64 % Ottmar Beucher <beucher@fh-karlsruhe.de>, Dan Drake
65 % <drake@math.umn.edu>, and Justus Piater <Justus.Piater@ULg.ac.be> who
66 % contributed ideas and code for the \pointsofquestion and \gradetable
67 % commands for printing a Grading Table. (I changed all the code to
68 % make this compatible with hyperref.sty, so if there are errors there,
69 % it's my fault and not theirs.)
71 % Justus Piater <Justus.Piater@ULg.ac.be>, who contributed the code for
72 % the solution environment. (I changed his code to allow page breaks
73 % inside solutions so, once again, if it's buggy, it's my fault.)
75 % Donald Arseneau <asnd@triumf.ca>, who created the excellent
76 % ``framed.sty'' and generously allowed me to include basically the
77 % whole thing in exam.cls, making the few changes needed for it to
78 % work well with question environments:
79 % framed.sty v 0.8a 21-Jul-2003
80 % Copyright (C) 1992-2003 by Donald Arseneau
81 % These macros may be freely transmitted, reproduced, or modified
82 % provided that this notice is left intact.
84 %--------------------------------------------------------------------
85 %--------------------------------------------------------------------
86 % Changelog since version 2.4:
88 %--------------------------------------------------------------------
89 % Version 2.603, 2017/12/15
93 %--------------------------------------------------------------------
94 % Version 2.602$\beta$, 2017/12/15
96 % We changed the code for multicolumn grade and point tables to remove
97 % the incompatibility with colortbl.sty and other packages that load
98 % colortbl.sty (e.g., xcolor.sty with the "table" option).
100 %--------------------------------------------------------------------
101 % Version 2.601$\beta$, 2017/09/22
103 % We changed command and environment names in the code from framed.sty
104 % that's included (slightly modified) in exam.cls so that the user can
105 % say \usepackage{framed} without creating conflicts. This also allows
106 % the user to use packages, such as minted.sty, that load framed.sty
108 %--------------------------------------------------------------------
109 % Version 2.6, 2017/09/19
111 % No longer betatest.
113 %--------------------------------------------------------------------
114 % Version 2.510$\beta$, 2016/10/11
116 % Bugfix: We changed \@setheadheight and \@setfootheight to fix a bug
117 % that was introduced by the bugfix in version 2.306beta, 2009/03/28:
118 % If the second page has a different \textheight (because of a change
119 % in either headheight or footheight between pages 1 and 2), then page
120 % 2 would use the \textheight of page 1. Pages 3 and beyond would get
121 % the correct \textheight. The original version of this set \@colroom
122 % and \vsize to the new \textheight, but that had a bug in that if a
123 % float appeared at the top of a page, there would be no notice taken
124 % of the space lost to the float, and so the text would overrun the
125 % bottom of the page. The bugfix in version 2.306beta eliminated the
126 % changes to \@colht and \vsize. In this bugfix, we adjust \@colroom,
127 % \@colht, and \vsize in the same way that we adjust \textheight.
129 %--------------------------------------------------------------------
130 % Version 2.509$\beta$, 2016/09/12
132 % Multicolumn grade and point tables, and a new syntax for multirow
133 % grade and point tables (which were introduced in version
136 % Multicolumn tables are vertically oriented, while multirow tables
137 % are horizontally oriented, and so they do not take the optional
138 % argument choosing between horizontal and vertical. They all take
139 % one required argument specifying the number of columns (for
140 % multicolumn) or the number of rows (for multirow).
144 % grade tables or point tables,
146 % plain, bonus, or combined,
148 % indexed by questions or by pages,
150 % complete or partial.
152 % As usual, if you omit the optional argument that chooses between
153 % questions and pages, you get questions.
155 % The new commands are:
157 % \def\multirowgradetable{numrows}[questions or pages]
158 % \def\multirowpointtable{numrows}[questions or pages]
159 % \def\multirowbonusgradetable{numrows}[questions or pages]
160 % \def\multirowbonuspointtable{numrows}[questions or pages]
161 % \def\multirowcombinedgradetable{numrows}[questions or pages]
162 % \def\multirowcombinedpointtable{numrows}[questions or pages]
164 % \def\multirowpartialgradetable{numrows}{rangename}[questions or pages]
165 % \def\multirowpartialpointtable{numrows}{rangename}[questions or pages]
166 % \def\multirowpartialbonusgradetable{numrows}{rangename}[questions or pages]
167 % \def\multirowpartialbonuspointtable{numrows}{rangename}[questions or pages]
168 % \def\multirowpartialcombinedgradetable{numrows}{rangename}[questions or pages]
169 % \def\multirowpartialcombinedpointtable{numrows}{rangename}[questions or pages]
171 % \def\multicolumngradetable{numcols}[questions or pages]
172 % \def\multicolumnpointtable{numcols}[questions or pages]
173 % \def\multicolumnbonusgradetable{numcols}[questions or pages]
174 % \def\multicolumnbonuspointtable{numcols}[questions or pages]
175 % \def\multicolumncombinedgradetable{numcols}[questions or pages]
176 % \def\multicolumncombinedpointtable{numcols}[questions or pages]
178 % \def\multicolumnpartialgradetable{numcols}{rangename}[questions or pages]
179 % \def\multicolumnpartialpointtable{numcols}{rangename}[questions or pages]
180 % \def\multicolumnpartialbonusgradetable{numcols}{rangename}[questions or pages]
181 % \def\multicolumnpartialbonuspointtable{numcols}{rangename}[questions or pages]
182 % \def\multicolumnpartialcombinedgradetable{numcols}{rangename}[questions or pages]
183 % \def\multicolumnpartialcombinedpointtable{numcols}{rangename}[questions or pages]
185 % The older grade and point table commands can still be used. For
186 % example, the commands
188 % \gradetable[h][questions]
189 % \multirowgradetable{1}[questions]
193 % The distance between the rows of a multirow table and between the
194 % columns of a multicolumn table is \doublerulesep, the default value
195 % of which is 2.0pt. You can change that using a \setlength command,
198 % \setlength{\doublerulesep}{0.5in}
200 %--------------------------------------------------------------------
201 % Version 2.508$\beta$, 2016/08/06
203 % New commands: Multirow grade and point tables.
205 % These are all horizontally oriented tables, and so do not take the
206 % optional argument choosing between horizontal and vertical. They all
207 % take one required argument specifying the number of columns, which is
208 % the number of columns used for the point values (including the total),
209 % but not counting the column of row headings.
211 % Note: The syntax was changed in version 2.509beta, so that you now
212 % specify the number of *rows* rather than the number of *columns*! For
213 % example, the first command below should now be
215 % \multirowgradetable{numrows}[questions or pages]
219 % grade tables or point tables,
221 % plain, bonus, or combined,
223 % indexed by questions or by pages,
225 % complete or partial.
227 % The new commands are:
230 % \multirowgradetable{numcols}[questions or pages]
231 % \multirowpointtable{numcols}[questions or pages]
232 % \multirowbonusgradetable{numcols}[questions or pages]
233 % \multirowbonuspointtable{numcols}[questions or pages]
234 % \multirowcombinedgradetable{numcols}[questions or pages]
235 % \multirowcombinedpointtable{numcols}[questions or pages]
237 % \multirowpartialgradetable{numcols}{rangename}[questions or pages]
238 % \multirowpartialpointtable{numcols}{rangename}[questions or pages]
239 % \multirowpartialbonusgradetable{numcols}{rangename}[questions or pages]
240 % \multirowpartialbonuspointtable{numcols}{rangename}[questions or pages]
241 % \multirowpartialcombinedgradetable{numcols}{rangename}[questions or pages]
242 % \multirowpartialcombinedpointtable{numcols}{rangename}[questions or pages]
244 %--------------------------------------------------------------------
245 % Version 2.507$\beta$, 2016/07/14
250 % \pointstwosidedreversed
252 % The first causes points to be in the right margin on odd numbered
253 % pages and in the left margin on even numbered pages.
255 % The second causes points to be in the left margin on odd numbered
256 % pages and in the right margin on even numbered pages.
258 % Also: Some minor edits (e.g., deleting the unused \thebonuspoints).
260 %--------------------------------------------------------------------
261 % Version 2.506$\beta$, 2016/05/12
263 % Fixed an obscure bug that arose only when \CorrectChoiceEmphasis
264 % used color and a \CorrectChoice (in a choices or checkboxes
265 % environment) followed a \choice whose text completely filled its
266 % last line, and which was not separated from the \CorrectChoice by a
267 % blank line, in which case an extra (blank) line was inserted by that
268 % \choice. We fixed this by adding an improvised "\leavehmode"
269 % (styled after \leavevmode) to the \CorrectChoice command in both the
270 % choices and checkboxes environments, which caused the text of the
271 % previous \choice to be broken into lines *before* the \special
272 % inserted by the \color command was added.
274 %--------------------------------------------------------------------
275 % Version 2.505$\beta$, 2016/05/10
277 % We fixed a bug in the choices and checkboxes environments that arose
278 % only when \CorrectChoiceEmphasis used color. If it did, and if the
279 % text of a correct choice exactly filled a line, and if there was no
280 % blank line in the latex file separating this correct choice from the
281 % following choice, there would be an extra blank line inserted after
282 % the correct choice. We did this by inserting \color@begingroup and
283 % \color@endgroup as needed. (We're pretty sure the actual fix was
284 % the \endgraf in the expansion of \color@endgroup.)
286 %--------------------------------------------------------------------
287 % Version 2.504$\beta$, 2016/05/09
289 % We fixed a bug in the solutionbox environment that caused enumerate,
290 % itemize, or description environments to have their text stick into
291 % the right margin. We did this by resetting \@totalleftmargin and
292 % \linewidth in the box containing the solution.
294 %--------------------------------------------------------------------
295 % Version 2.503$\beta$, 2016/03/25
299 % \colorfillwithlines
300 % \colorfillwithdottedlines
302 % The first causes the lines drawn by the \fillwithlines command to be
303 % drawn in color. The default color is set by the command
305 % \definecolor{FillWithLinesColor}{gray}{0.8}
307 % and the color can be changed by giving a new \definecolor command.
308 % You can return to black lines by giving the command
310 % \nocolorfillwithlines
312 % \colorfillwithdottedlines causes the lines drawn by the
313 % \fillwithdottedlines command to be drawn in color. The default
314 % color is set by the command
316 % \definecolor{FillWithDottedLinesColor}{gray}{0.8}
318 % and the color can be changed by giving a new \definecolor command.
319 % You can return to black dotted lines by giving the command
321 % \nocolorfillwithdottedlines
323 %--------------------------------------------------------------------
324 % Version 2.502$\beta$, 2016/03/23
328 % \colorsolutionboxes
330 % that was created in version 2.501beta now affects not only the boxes
331 % created by \solutionbox, but also by \makeemptybox, \solutionorbox,
332 % and all of the boxes printed by all of the various solution
333 % environments when solutions are being printed surrounded by a box.
335 %--------------------------------------------------------------------
336 % Version 2.501$\beta$, 2016/02/08
338 % Changed the \solutionbox environment so that it works correctly
341 % Also: The \solutionbox frame can now be printed in color, as long as
342 % you load color.sty in the preamble.
348 % in the preamble, and then give the command
350 % \colorsolutionboxes
352 % to have the frame around a solutionbox in color. The default color
353 % was created by the command
355 % \definecolor{SolutionBoxColor}{gray}{0.8}
357 % and you can change the color by giving a new \definecolor command
358 % (which must be done *after* the \colorsolutionboxes command).
360 % To cancel color solutionbox frames and return to black, give the
363 % \nocolorsolutionboxes
365 %--------------------------------------------------------------------
366 % Version 2.5 2015/05/07
368 % No longer betatest.
370 %--------------------------------------------------------------------
371 % Version 2.408$\beta$ 2013/11/17
375 % \firstqinrange{whatever}
376 % \lastqinrange{whatever}
377 % \numqinrange{whatever}
379 % where ``whatever'' is the name of a grading range.
381 % \firstqinrange{whatever} prints the number of the first question in
384 % \lastqinrange{whatever} prints the number of the last question in the
387 % \numqinrange{whatever} prints the number of questions in the range.
389 % We changed a couple of internal command name related to grading
390 % ranges. If the user defines the range `myrange', then we now use
392 % \range@myrange@firstp
393 % \range@myrange@lastp
394 % \range@myrange@firstq
395 % \range@myrange@lastq
397 % where we used to use
399 % \tbl@myrange@firstp
401 % \tbl@myrange@firstq
404 %--------------------------------------------------------------------
405 % Version 2.407$\beta$ 2012/12/19
411 % The solutionbox environment is different from the other solution
412 % environments (solution, solutionorbox, solutionorlines,
413 % solutionordottedlines, and solutionorgrid), in that
415 % (1) The box is always printed, whether answers are being printed
418 % (2) The argument giving the size of the box is a required
419 % argument, not an optional argument, and so it should be enclosed
420 % in braces, not in brackets. It can be either a length or
423 % (3) We make no use of the TheSolution environment; the solutionbox
424 % environment is completely freestanding.
426 % If answers are not being printed then only the box is printed, with
427 % nothing in it. If answers are being printed, then the solution is
428 % printed inside of the box.
430 % Note: It's the user's responsibility to be sure that the box is
431 % large enough to hold the solution! If the solution takes up too
432 % much vertical space, then it will spill out of the bottom of the
433 % box, overwriting whatever follows the box.
435 %--------------------------------------------------------------------
436 % Version 2.406$\beta$, 2012/12/16
440 % \noquestionsonthispage
442 % This command tells the \ifcontinuation and \ifincomplete commands
443 % to assume that no part of any question is on this page. This is
444 % similar to the job done by the \nomorequestions command for the
445 % pages that follow the end of all of the questions.
448 % If you give the command \noquestionsonthispage on a page, then
450 % (1) \ifcontinuation on that page will expand to its second
452 % (2) \ifincomplete on that page will expand to its second
454 % (3) an \ifincomplete on an earlier page will not assume that a
455 % question from that earlier page continues onto this page.
457 % The way that this command affects the \ifincomplete command on
458 % earlier pages is as follows: If there is a page with no questions or
459 % parts or subparts or subsubparts, then the last page before that
460 % with a question (or part, etc.) would normally be deemed incomplete;
461 % if, however, the page with no questions (or parts, etc.) (along with
462 % all adjacent pages with no questions or parts etc.) has a
463 % \noquestionsonthispage command, then that last page with a question
464 % (or part, etc.) will not be deemed incomplete.
466 % Note that if you're tempted to use this command on a page that follows
467 % the end of all of the questions, then you should probably use the
468 % command \nomorequestions instead.
470 %--------------------------------------------------------------------
471 % Version 2.405$\beta$, 2012/10/21
473 % It is now possible to use a parts, subparts, or subsubparts
474 % environment inside one of the solution environments (solution,
475 % solutionorbox, solutionorlines, solutionordottedlines, or
476 % solutionorgrid) without getting problems from multiply defined
477 % labels or having its points (if any) counted as being actual points
480 % Any \part, \subpart, or \subsubpart command inside one of the
481 % solution environments now writes a \PgInfo command in the .aux file
482 % of the form question2@object3, but no labels and no other \PgInfo
483 % commands. In addition, if there are points assigned to any of these
484 % commands inside any of the solution environments, those points are
485 % not added to the points of the question or the points on the page,
486 % and do not affect any gradetables or pointtables.
488 %--------------------------------------------------------------------
489 % Version 2.404$\beta$, 2012/09/03
493 % \fillwithgrid{length}
499 % These are similar to the \fillwithlines command and the
500 % solutionorlines environment.
502 % By default, the created grids are in black. However, if you give the
508 % then the grids will be in color, by default a light gray. That
509 % default color was defined by the command
511 % \definecolor{GridColor}{gray}{0.8}
513 % You can change the color by redefining the color GridColor, and you
514 % can return to using black grids by giving the command
518 % The default grid size and grid line thickness were set by the
521 % \setlength{\gridsize}{5mm}
522 % \setlength{\gridlinewidth}{0.1pt}
524 % You can change either or both of those by giving new \setlength
525 % commands. The period of the grid is \gridsize (both horizontally
526 % and vertically). That is, the horizontal distance from the left
527 % edge of one vertical line to the left edge of the next vertical line
528 % is \gridsize, as is the vertical distance from the top edge of one
529 % horizontal line to the top edge of the next horizontal line. Thus,
530 % each square has outer side length equal to \gridsize+\gridlinewidth.
532 %--------------------------------------------------------------------
533 % Version 2.403$\beta$, 2012/08/29:
535 % We changed the code for the command \fillin (which had been modified
536 % in version 2.402beta) so that if only one optional argument is used,
537 % a space following that optional argument will not be ignored. We
538 % did this in such a way that the second optional argument will be
539 % recognized even when spaces appear in between the optional
542 %--------------------------------------------------------------------
543 % Version 2.402$\beta$, 2012/08/21:
545 % We modified the command \fillin that we had created in version
546 % 2.401beta. \fillin now takes two optional arguments (and no required
549 % \fillin can take two optional arguments, as in
551 % \fillin[Answer][Length]
553 % The first optional argument is the answer to be printed above the line
554 % when \printanswers is in effect; the default value is empty. That
555 % line is printed a distance of \answerclearance below the baseline.
557 % The second optional argument is the length of the line that we print;
558 % the default value is \fillinlinelength. The value of
559 % \fillinlinelength is set with the command
561 % \setlength\fillinlinelength{1in}
563 % and can be changed by giving a new \setlength command.
565 % When answers are being printed, the first optional argument is
566 % printed subject to the declarations in the argument of the last
567 % \CorrectChoiceEmphasis command. It is centered on the line unless
568 % it is too long, in which case it extends to the right of the line.
570 %--------------------------------------------------------------------
571 % Version 2.401$\beta$, 2012/08/20:
576 % \fillin[CorrectAnswer]{width}
578 % This is for use in fill in the blank questions. This command inserts
579 % a blank line of width ``width''. If answers are being printed and if
580 % the optional argument ``CorrectAnswer'' appears, then the optional
581 % argument is printed subject to the declarations in the argument of the
582 % last \CorrectChoiceEmphasis command, and it is printed a distance of
583 % \answerclearance above the line. It is centered on the line unless it
584 % is too long, in which case it extends to the right of the line.
586 % Note: We changed this command in version 2.401beta.
588 %--------------------------------------------------------------------
589 %--------------------------------------------------------------------
590 %--------------------------------------------------------------------
592 \NeedsTeXFormat{LaTeX2e}
594 \ProvidesClass{exam}[\filedate\space Version \fileversion\space by
597 \RequirePackage{ifthen}
599 \newif\ifprintanswers
601 \DeclareOption{answers}{\printanswerstrue}
602 \DeclareOption{noanswers}{\printanswersfalse}
606 \DeclareOption{cancelspace}{\cancelspacetrue}
607 \DeclareOption{nocancelspace}{\cancelspacefalse}
609 % The following keeps track of whether the user has requested that we
610 % add up the points on the exam. We make the default false so that
611 % users who put other than numbers into the points argument of a
612 % question (or part, or subpart) won't get error messages.
613 % We use \if@printtotalpoints as a flag to signal that we are counting
614 % points, so that we will know to print the total on the screen (and
615 % in the log file). We use this separate flag so that the user can
616 % use both \addpoints and \noaddpoints to count some points and not
617 % others, but still have the total printed when we finish the file no
618 % matter what the state of \if@addpoints.
620 \newif\if@printtotalpoints
621 \def\addpoints{\global\@addpointstrue\global\@printtotalpointstrue}
622 \def\noaddpoints{\global\@addpointsfalse}
624 \@printtotalpointsfalse
625 \DeclareOption{addpoints}{\addpoints}
629 \PassOptionsToClass{\CurrentOption}{article}%
631 \ProcessOptions\relax
642 % We set the parameters in terms of \paperwidth and \paperheight
643 % so that the options
655 \setlength{\textwidth}{\paperwidth}
656 \addtolength{\textwidth}{-2in}
657 \setlength{\oddsidemargin}{0pt}
658 \setlength{\evensidemargin}{0pt}
660 \setlength{\headheight}{15pt}
661 \setlength{\headsep}{15pt}
662 \setlength{\topmargin}{0in}
663 \addtolength{\topmargin}{-\headheight}
664 \addtolength{\topmargin}{-\headsep}
665 \setlength{\footskip}{29pt}
666 \setlength{\textheight}{\paperheight}
667 \addtolength{\textheight}{-2.2in}
669 \setlength{\marginparwidth}{.5in}
670 \setlength{\marginparsep}{5pt}
672 %--------------------------------------------------------------------
678 \newlength\@extrawidth
680 % \@rightmargin is needed for \pointsinrightmargin and
681 % \pointsdroppedatright, so that we can right justify the points:
682 \newlength\@rightmargin
683 \setlength{\@rightmargin}{1in}
685 % We put the argument of \extrawidth into a length so that it will
686 % work correctly even if it's negative:
690 \advance \textwidth by \@extrawidth
691 \divide\@extrawidth by 2
692 \advance\oddsidemargin by -\@extrawidth
693 \advance\evensidemargin by -\@extrawidth
694 % Bug fix, 13 April 2004:
695 %\advance\@rightmargin by \@extrawidth
696 \advance\@rightmargin by -\@extrawidth
699 %--------------------------------------------------------------------
700 %--------------------------------------------------------------------
701 % Making room for large headers and footers
703 % The following are used to save the effect of any changes to
704 % \topmargin and \textheight caused by \extraheadheight or
705 % \extrafootheight commands. They hold the values currently in effect.
706 % We put them into lengths so that it will work correctly even if the
707 % argument is negative:
709 \newlength\@extrahead
710 \newlength\@extrafoot
711 \setlength{\@extrahead}{0in}
712 \setlength{\@extrafoot}{0in}
714 % The following are used to hold the requested values for extrahead and
715 % extrafoot, first page and all pages after the first, and then the
716 % similar things requested for the cover pages:
721 \newlength\covrun@exhd
722 \newlength\covfp@exhd
723 \newlength\covrun@exft
724 \newlength\covfp@exft
726 \setlength{\run@exhd}{0in}
727 \setlength{\fp@exhd}{0in}
728 \setlength{\run@exft}{0in}
729 \setlength{\fp@exft}{0in}
730 \setlength{\covrun@exhd}{0in}
731 \setlength{\covfp@exhd}{0in}
732 \setlength{\covrun@exft}{0in}
733 \setlength{\covfp@exft}{0in}
735 \newcommand*\adj@hdht@ftht{%
737 \ifnum\value{page}=1\relax
738 \@setheadheight{\covfp@exhd}%
739 \@setfootheight{\covfp@exft}%
741 \@setheadheight{\covrun@exhd}%
742 \@setfootheight{\covrun@exft}%
745 \ifnum\value{page}=1\relax
746 \@setheadheight{\fp@exhd}%
747 \@setfootheight{\fp@exft}%
749 \@setheadheight{\run@exhd}%
750 \@setfootheight{\run@exft}%
755 \newcommand*\extraheadheight{%
756 \@ifnextchar[{\@xtrahd}{\@ytrahd}%
760 \setlength{\fp@exhd}{#1}%
761 \setlength{\run@exhd}{#2}%
766 \setlength{\fp@exhd}{#1}%
767 \setlength{\run@exhd}{#1}%
771 \newcommand*\extrafootheight{%
772 \@ifnextchar[{\@xtraft}{\@ytraft}%
776 \setlength{\fp@exft}{#1}%
777 \setlength{\run@exft}{#2}%
782 \setlength{\fp@exft}{#1}%
783 \setlength{\run@exft}{#1}%
787 \newcommand*\coverextraheadheight{%
788 \@ifnextchar[{\cov@xtrahd}{\cov@ytrahd}%
791 \def\cov@xtrahd[#1]#2{%
792 \setlength{\covfp@exhd}{#1}%
793 \setlength{\covrun@exhd}{#2}%
798 \setlength{\covfp@exhd}{#1}%
799 \setlength{\covrun@exhd}{#1}%
803 \newcommand*\coverextrafootheight{%
804 \@ifnextchar[{\cov@xtraft}{\cov@ytraft}%
807 \def\cov@xtraft[#1]#2{%
808 \setlength{\covfp@exft}{#1}%
809 \setlength{\covrun@exft}{#2}%
814 \setlength{\covfp@exft}{#1}%
815 \setlength{\covrun@exft}{#1}%
819 \def\@appendoutput#1{%
820 \output=\expandafter{\the\output #1}%
823 \@appendoutput{\adj@hdht@ftht}
825 %--------------------------------------------------------------------
826 % \@setheadheight and \@setfootheight:
828 \def\@setheadheight#1{%
829 \begingroup % Avoid trouble from using \@temp and \@spaces
830 % Reset the effect of the most recent change:
831 \global\advance\topmargin by -\@extrahead
832 \global\advance\textheight by \@extrahead
833 % Bugfix, Version 2.510beta, 2016/10/11:
834 \global\advance\@colroom by \@extrahead
835 \global\advance\@colht by \@extrahead
836 \global\advance\vsize by \@extrahead
838 % Save the newly set value:
842 \global\@extrahead=0in
845 \global\@extrahead=0in
847 \global\@extrahead=#1
850 % Set the new values:
851 \global\advance\topmargin by \@extrahead
852 \global\advance\textheight by -\@extrahead
853 % Bugfix, Version 2.510beta, 2016/10/11:
854 \global\advance\@colroom by -\@extrahead
855 \global\advance\@colht by -\@extrahead
856 \global\advance\vsize by -\@extrahead
858 % Bugfix, Version 2.510beta, 2016/10/11:
859 % We're fixing a bug that was introduced by the bugfix in version
860 % 2.306beta, 2009/03/28: If the second page has a different
861 % \textheight (because of a change in either headheight or
862 % footheight between pages 1 and 2), then page 2 would use the
863 % \textheight of page 1. Pages 3 and beyond would get the correct
865 % The original version of this set \@colroom and \vsize to the new
866 % \textheight, but that had a bug in that if a float appeared at
867 % the top of a page, there would be no notice taken of the space
868 % lost to the float, and so the text would overrun the bottom of
870 % In this bugfix, we adjust \@colroom, \@colht, and \vsize in the
871 % same way that we adjust \textheight.
873 % Make it take effect RIGHT NOW!:
874 % (The following stuff isn't necessary if \@setheadheight is
875 % executed only in the preamble or as we return from the output
876 % routine, but we're leaving it in so that this will still work if
877 % we use this at some random point in the middle of composing a
879 % Bugfix, Version 2.306beta, 2009/03/28:
881 % If the user had a figure environment that floated to the
882 % top of a page, then this would cause that page to run
883 % over the footer and off the bottom of the page, because
884 % this somehow caused a full page's worth of stuff to be
885 % placed after the figure, as if the figure wasn't taking
886 % up space on the page.
887 % We *do* need to put \@colht at the correct new value, though,
888 % apparently because \@colht is set near the end of the
890 % \global\@colht=\textheight
892 % \global\@colroom=\textheight
893 % \global\vsize=\textheight
894 % \global\pagegoal=\textheight
898 \def\@setfootheight#1{%
899 \begingroup % Avoid trouble from using \@temp and \@spaces
900 % Reset the effect of the most recent change:
901 \global\advance\textheight by \@extrafoot
902 % Bugfix, Version 2.510beta, 2016/10/11:
903 \global\advance\@colroom by \@extrafoot
904 \global\advance\@colht by \@extrafoot
905 \global\advance\vsize by \@extrafoot
907 % Save the newly set value:
911 \global\@extrafoot=0in
914 \global\@extrafoot=0in
916 \global\@extrafoot=#1
919 % Set the new values:
920 \global\advance\textheight by -\@extrafoot
921 % Bugfix, Version 2.510beta, 2016/10/11:
922 \global\advance\@colroom by -\@extrafoot
923 \global\advance\@colht by -\@extrafoot
924 \global\advance\vsize by -\@extrafoot
926 % Bugfix, Version 2.510beta, 2016/10/11:
927 % We're fixing a bug that was introduced by the bugfix in version
928 % 2.306beta, 2009/03/28: If the second page has a different
929 % \textheight (because of a change in either headheight or
930 % footheight between pages 1 and 2), then page 2 would use the
931 % \textheight of page 1. Pages 3 and beyond would get the correct
933 % The original version of this set \@colroom and \vsize to the new
934 % \textheight, but that had a bug in that if a float appeared at
935 % the top of a page, there would be no notice taken of the space
936 % lost to the float, and so the text would overrun the bottom of
938 % In this bugfix, we adjust \@colroom, \@colht, and \vsize in the
939 % same way that we adjust \textheight.
941 % Make it take effect RIGHT NOW!:
942 % (The following stuff isn't necessary if \@setfootheight is
943 % executed only in the preamble or as we return from the output
944 % routine, but we're leaving it in so that this will still work if
945 % we use this at some random point in the middle of composing a
947 % Bugfix, Version 2.306beta, 2009/03/28:
949 % If the user had a figure environment that floated to the
950 % top of a page, then this would cause that page to run
951 % over the footer and off the bottom of the page, because
952 % this somehow caused a full page's worth of stuff to be
953 % placed after the figure, as if the figure wasn't taking
954 % up space on the page.
955 % We *do* need to put \@colht at the correct new value, though,
956 % apparently because \@colht is set near the end of the
958 % \global\@colht=\textheight
960 % \global\@colroom=\textheight
961 % \global\vsize=\textheight
962 % \global\pagegoal=\textheight
967 %---------------------------------------------------------------------
969 % *************************
970 % ** HEADERS AND FOOTERS **
971 % *************************
973 % The pagestyles available are head, foot, headandfoot, and empty.
974 % \pagestyle{head} prints the head, and gives an empty foot.
975 % \pagestyle{foot} prints the foot, and gives an empty head.
976 % \pagestyle{headandfoot} prints both the head and the foot.
977 % \pagestyle{empty} gives an empty head and an empty foot.
982 \newcommand*\ps@head{%
987 \newcommand*\ps@headandfoot{%
992 \newcommand*\ps@foot{%
997 % \ps@empty is already defined by article.cls, so we'll
998 % say \def instead of \newcommand*:
1004 \newif\if@coverpages
1007 \newcounter{num@coverpages}
1008 % We'll set this to zero in case there is no coverpages environment:
1009 \setcounter{num@coverpages}{0}
1011 \newenvironment{coverpages}{%
1012 \ifnum \value{numquestions}>0\relax
1014 Coverpages cannot be used after questions have begun.\MessageBreak
1016 All question, part, subpart, and subsubpart environments
1018 must begin after the cover pages are complete.\MessageBreak
1022 \pagenumbering{roman}%
1026 \setcounter{num@coverpages}{\value{page}}%
1027 \addtocounter{num@coverpages}{-1}%
1028 \pagenumbering{arabic}%
1029 % Bugfix, Version 2.307\beta, 2009/06/11:
1030 % We have to say \@coverpagesfalse before \adj@hdht@ftht
1031 % because we're still inside the group created by the
1032 % coverpages environment and we want to set the
1033 % extraheadheight and extrafootheight to the values correct
1034 % for the first non-cover page:
1039 \newcommand*\cover@question@error{%
1041 No questions are allowed in the cover pages.\MessageBreak
1043 All question, part, subpart, and subsubpart environments
1045 must begin after the cover pages are complete.\MessageBreak
1049 \newcommand*\@dohead{%
1052 \ifnum\value{page}=1\relax
1058 \ifnum\value{page}=1\relax
1065 \let\@evenhead=\@oddhead
1068 \newcommand*\@dofoot{%
1071 \ifnum\value{page}=1\relax
1077 \ifnum\value{page}=1\relax
1084 \let\@evenfoot=\@oddfoot
1087 \newcommand*\@nohead{%
1089 \let\@evenhead=\@oddhead
1092 \newcommand*\@nofoot{%
1094 \let\@evenfoot=\@oddfoot
1097 %--------------------------------------------------------------------
1098 % \@fullhead, \run@fullhead, \@fullfoot, and \run@fullfoot:
1100 \newcommand*\@fullhead{%
1101 \vbox to \headheight{%
1103 \hbox to \textwidth{%
1104 \normalfont\rlap{\parbox[b]{\textwidth}{\raggedright\@lhead\strut}}%
1105 \hss\parbox[b]{\textwidth}{\centering\@chead\strut}\hss
1106 \llap{\parbox[b]{\textwidth}{\raggedleft\@rhead\strut}}%
1111 % an invisible hrule, to keep positioning constant:
1117 \newcommand*\run@fullhead{%
1118 \vbox to \headheight{%
1120 \hbox to \textwidth{%
1121 \normalfont\rlap{\parbox[b]{\textwidth}{\raggedright\run@lhead\strut}}%
1122 \hss\parbox[b]{\textwidth}{\centering\run@chead\strut}\hss
1123 \llap{\parbox[b]{\textwidth}{\raggedleft\run@rhead\strut}}%
1128 % an invisible hrule, to keep positioning constant:
1134 % We arrange it so that the very top of first line of text in the
1135 % foot is at a fixed position on the page, whether or not there's
1138 \newcommand*\@fullfoot{%
1143 % an invisible hrule, to keep positioning constant:
1147 \hbox to \textwidth{%
1148 \normalfont\rlap{\parbox[t]{\textwidth}{\raggedright\@lfoot}}%
1149 \hss\parbox[t]{\textwidth}{\centering\@cfoot}\hss
1150 \llap{\parbox[t]{\textwidth}{\raggedleft\@rfoot}}%
1156 \newcommand*\run@fullfoot{%
1161 % an invisible hrule, to keep positioning constant:
1165 \hbox to \textwidth{%
1166 \normalfont\rlap{\parbox[t]{\textwidth}{\raggedright\run@lfoot}}%
1167 \hss\parbox[t]{\textwidth}{\centering\run@cfoot}\hss
1168 \llap{\parbox[t]{\textwidth}{\raggedleft\run@rfoot}}%
1174 %--------------------------------------------------------------------
1175 % \cov@fullhead, \covrun@fullhead, \cov@fullfoot, and
1178 \newcommand*\cov@fullhead{%
1179 \vbox to \headheight{%
1181 \hbox to \textwidth{%
1182 \normalfont\rlap{\parbox[b]{\textwidth}{\raggedright\cov@lhead\strut}}%
1183 \hss\parbox[b]{\textwidth}{\centering\cov@chead\strut}\hss
1184 \llap{\parbox[b]{\textwidth}{\raggedleft\cov@rhead\strut}}%
1189 % an invisible hrule, to keep positioning constant:
1195 \newcommand*\covrun@fullhead{%
1196 \vbox to \headheight{%
1198 \hbox to \textwidth{%
1199 \normalfont\rlap{\parbox[b]{\textwidth}{\raggedright\covrun@lhead\strut}}%
1200 \hss\parbox[b]{\textwidth}{\centering\covrun@chead\strut}\hss
1201 \llap{\parbox[b]{\textwidth}{\raggedleft\covrun@rhead\strut}}%
1206 % an invisible hrule, to keep positioning constant:
1212 % We arrange it so that the very top of first line of text in the
1213 % foot is at a fixed position on the page, whether or not there's
1216 \newcommand*\cov@fullfoot{%
1221 % an invisible hrule, to keep positioning constant:
1225 \hbox to \textwidth{%
1226 \normalfont\rlap{\parbox[t]{\textwidth}{\raggedright\cov@lfoot}}%
1227 \hss\parbox[t]{\textwidth}{\centering\cov@cfoot}\hss
1228 \llap{\parbox[t]{\textwidth}{\raggedleft\cov@rfoot}}%
1234 \newcommand*\covrun@fullfoot{%
1239 % an invisible hrule, to keep positioning constant:
1243 \hbox to \textwidth{%
1244 \normalfont\rlap{\parbox[t]{\textwidth}{\raggedright\covrun@lfoot}}%
1245 \hss\parbox[t]{\textwidth}{\centering\covrun@cfoot}\hss
1246 \llap{\parbox[t]{\textwidth}{\raggedleft\covrun@rfoot}}%
1252 %--------------------------------------------------------------------
1253 %--------------------------------------------------------------------
1255 % ********************************************
1256 % ** COMMANDS TO DEFINE HEADERS AND FOOTERS **
1257 % ********************************************
1259 % \lhead[#1]{#2} sets the first page left head to #1, and the
1260 % running left head to #2
1262 % \lhead{#1} sets both the first page left head and the running
1265 % \chead, \rhead, \lfoot, \cfoot, and \rfoot work similarly.
1268 % \@lhead is the left head for Page 1
1269 % \run@lhead is the running left head
1270 % (i.e., for all pages other than the first)
1272 % \@chead is the center head for Page 1
1273 % \run@chead is the running center head
1274 % (i.e., for all pages other than the first)
1278 % Alternative commands are:
1279 % \firstpageheader{LEFT}{CENTER}{RIGHT}
1280 % \runningheader{LEFT}{CENTER}{RIGHT}
1282 % \header{LEFT}{CENTER}{RIGHT}
1283 % which is equivalent to the two commands
1284 % \firstpageheader{LEFT}{CENTER}{RIGHT}
1285 % \runningheader{LEFT}{CENTER}{RIGHT}
1287 % Alternative commands are:
1288 % \firstpagefooter{LEFT}{CENTER}{RIGHT}
1289 % \runningfoother{LEFT}{CENTER}{RIGHT}
1291 % \footer{LEFT}{CENTER}{RIGHT}
1292 % which is equivalent to the two commands
1293 % \firstpagefooter{LEFT}{CENTER}{RIGHT}
1294 % \runningfoother{LEFT}{CENTER}{RIGHT}
1296 \def\firstpageheader#1#2#3{%
1302 \def\runningheader#1#2#3{%
1309 \firstpageheader{#1}{#2}{#3}%
1310 \runningheader{#1}{#2}{#3}%
1313 \def\firstpagefooter#1#2#3{%
1319 \def\runningfooter#1#2#3{%
1326 \firstpagefooter{#1}{#2}{#3}%
1327 \runningfooter{#1}{#2}{#3}%
1330 \def\lhead{\@ifnextchar[{\@xlhead}{\@ylhead}}
1331 \def\@xlhead[#1]#2{\def\@lhead{#1}\def\run@lhead{#2}}
1332 \def\@ylhead#1{\def\run@lhead{#1}\def\@lhead{#1}}
1334 \def\chead{\@ifnextchar[{\@xchead}{\@ychead}}
1335 \def\@xchead[#1]#2{\def\@chead{#1}\def\run@chead{#2}}
1336 \def\@ychead#1{\def\run@chead{#1}\def\@chead{#1}}
1338 \def\rhead{\@ifnextchar[{\@xrhead}{\@yrhead}}
1339 \def\@xrhead[#1]#2{\def\@rhead{#1}\def\run@rhead{#2}}
1340 \def\@yrhead#1{\def\run@rhead{#1}\def\@rhead{#1}}
1342 \def\lfoot{\@ifnextchar[{\@xlfoot}{\@ylfoot}}
1343 \def\@xlfoot[#1]#2{\def\@lfoot{#1}\def\run@lfoot{#2}}
1344 \def\@ylfoot#1{\def\run@lfoot{#1}\def\@lfoot{#1}}
1346 \def\cfoot{\@ifnextchar[{\@xcfoot}{\@ycfoot}}
1347 \def\@xcfoot[#1]#2{\def\@cfoot{#1}\def\run@cfoot{#2}}
1348 \def\@ycfoot#1{\def\run@cfoot{#1}\def\@cfoot{#1}}
1350 \def\rfoot{\@ifnextchar[{\@xrfoot}{\@yrfoot}}
1351 \def\@xrfoot[#1]#2{\def\@rfoot{#1}\def\run@rfoot{#2}}
1352 \def\@yrfoot#1{\def\run@rfoot{#1}\def\@rfoot{#1}}
1355 % Initialize head and foot:
1357 \pagestyle{headandfoot}
1363 \cfoot[]{Page \thepage}
1366 %--------------------------------------------------------------------
1367 % Coverpage headers and footers
1369 % \coverlhead[#1]{#2} sets the first cover page left head to #1, and the
1370 % running cover left head to #2
1372 % \coverlhead{#1} sets both the first cover page left head and the running
1373 % cover left head to #1
1375 % \coverchead, \coverrhead, \coverlfoot, \covercfoot, and \coverrfoot
1379 % \cov@lhead is the left head for Page 1
1380 % \covrun@lhead is the running left head
1381 % (i.e., for all pages other than the first)
1383 % \cov@chead is the center head for Page 1
1384 % \covrun@chead is the running center head
1385 % (i.e., for all pages other than the first)
1389 % Alternative commands are:
1390 % \coverfirstpageheader{LEFT}{CENTER}{RIGHT}
1391 % \coverrunningheader{LEFT}{CENTER}{RIGHT}
1393 % \coverheader{LEFT}{CENTER}{RIGHT}
1394 % which is equivalent to the two commands
1395 % \coverfirstpageheader{LEFT}{CENTER}{RIGHT}
1396 % \coverrunningheader{LEFT}{CENTER}{RIGHT}
1398 % Alternative commands are:
1399 % \coverfirstpagefooter{LEFT}{CENTER}{RIGHT}
1400 % \coverrunningfoother{LEFT}{CENTER}{RIGHT}
1402 % \coverfooter{LEFT}{CENTER}{RIGHT}
1403 % which is equivalent to the two commands
1404 % \coverfirstpagefooter{LEFT}{CENTER}{RIGHT}
1405 % \coverrunningfoother{LEFT}{CENTER}{RIGHT}
1407 \def\coverfirstpageheader#1#2#3{%
1413 \def\coverrunningheader#1#2#3{%
1414 \def\covrun@lhead{#1}%
1415 \def\covrun@chead{#2}%
1416 \def\covrun@rhead{#3}%
1419 \def\coverheader#1#2#3{%
1420 \coverfirstpageheader{#1}{#2}{#3}%
1421 \coverrunningheader{#1}{#2}{#3}%
1424 \def\coverfirstpagefooter#1#2#3{%
1430 \def\coverrunningfooter#1#2#3{%
1431 \def\covrun@lfoot{#1}%
1432 \def\covrun@cfoot{#2}%
1433 \def\covrun@rfoot{#3}%
1436 \def\coverfooter#1#2#3{%
1437 \coverfirstpagefooter{#1}{#2}{#3}%
1438 \coverrunningfooter{#1}{#2}{#3}%
1441 \def\coverlhead{\@ifnextchar[{\cov@xlhead}{\cov@ylhead}}
1442 \def\cov@xlhead[#1]#2{\def\cov@lhead{#1}\def\covrun@lhead{#2}}
1443 \def\cov@ylhead#1{\def\covrun@lhead{#1}\def\cov@lhead{#1}}
1445 \def\coverchead{\@ifnextchar[{\cov@xchead}{\cov@ychead}}
1446 \def\cov@xchead[#1]#2{\def\cov@chead{#1}\def\covrun@chead{#2}}
1447 \def\cov@ychead#1{\def\covrun@chead{#1}\def\cov@chead{#1}}
1449 \def\coverrhead{\@ifnextchar[{\cov@xrhead}{\cov@yrhead}}
1450 \def\cov@xrhead[#1]#2{\def\cov@rhead{#1}\def\covrun@rhead{#2}}
1451 \def\cov@yrhead#1{\def\covrun@rhead{#1}\def\cov@rhead{#1}}
1453 \def\coverlfoot{\@ifnextchar[{\cov@xlfoot}{\cov@ylfoot}}
1454 \def\cov@xlfoot[#1]#2{\def\cov@lfoot{#1}\def\covrun@lfoot{#2}}
1455 \def\cov@ylfoot#1{\def\covrun@lfoot{#1}\def\cov@lfoot{#1}}
1457 \def\covercfoot{\@ifnextchar[{\cov@xcfoot}{\cov@ycfoot}}
1458 \def\cov@xcfoot[#1]#2{\def\cov@cfoot{#1}\def\covrun@cfoot{#2}}
1459 \def\cov@ycfoot#1{\def\covrun@cfoot{#1}\def\cov@cfoot{#1}}
1461 \def\coverrfoot{\@ifnextchar[{\cov@xrfoot}{\cov@yrfoot}}
1462 \def\cov@xrfoot[#1]#2{\def\cov@rfoot{#1}\def\covrun@rfoot{#2}}
1463 \def\cov@yrfoot#1{\def\covrun@rfoot{#1}\def\cov@rfoot{#1}}
1466 % Initialize coverpage head and foot:
1478 %--------------------------------------------------------------------
1479 %--------------------------------------------------------------------
1481 % Headrules and footrules:
1484 \newif\ifrun@headrule
1486 \def\firstpageheadrule{\@headruletrue}
1487 \def\nofirstpageheadrule{\@headrulefalse}
1489 \def\runningheadrule{\run@headruletrue}
1490 \def\norunningheadrule{\run@headrulefalse}
1492 \def\headrule{\@headruletrue\run@headruletrue}
1493 \def\noheadrule{\@headrulefalse\run@headrulefalse}
1496 \newif\ifrun@footrule
1498 \def\firstpagefootrule{\@footruletrue}
1499 \def\nofirstpagefootrule{\@footrulefalse}
1501 \def\runningfootrule{\run@footruletrue}
1502 \def\norunningfootrule{\run@footrulefalse}
1504 \def\footrule{\@footruletrue\run@footruletrue}
1505 \def\nofootrule{\@footrulefalse\run@footrulefalse}
1512 % Cover page headrules and footrules:
1514 \newif\ifcov@headrule
1515 \newif\ifcovrun@headrule
1517 \def\coverfirstpageheadrule{\cov@headruletrue}
1518 \def\nocoverfirstpageheadrule{\cov@headrulefalse}
1520 \def\coverrunningheadrule{\covrun@headruletrue}
1521 \def\nocoverrunningheadrule{\covrun@headrulefalse}
1523 \def\coverheadrule{\cov@headruletrue\covrun@headruletrue}
1524 \def\nocoverheadrule{\cov@headrulefalse\covrun@headrulefalse}
1526 \newif\ifcov@footrule
1527 \newif\ifcovrun@footrule
1529 \def\coverfirstpagefootrule{\cov@footruletrue}
1530 \def\nocoverfirstpagefootrule{\cov@footrulefalse}
1532 \def\coverrunningfootrule{\covrun@footruletrue}
1533 \def\nocoverrunningfootrule{\covrun@footrulefalse}
1535 \def\coverfootrule{\cov@footruletrue\covrun@footruletrue}
1536 \def\nocoverfootrule{\cov@footrulefalse\covrun@footrulefalse}
1543 %--------------------------------------------------------------------
1544 %--------------------------------------------------------------------
1546 % \numpages, \iflastpage, and \oddeven
1547 % Also: \numpoints, \numquestions, \numparts, and \numsubparts
1548 % Also also: \pointsofquestion
1549 % Also: \numcoverpages and \totalnumpages
1551 % Make the number of pages available as the macro \numpages,
1552 % the number of points as \numpoints,
1553 % the number of questions as \numquestions,
1554 % the number of parts as \numparts, and
1555 % the number of subparts as \numsubparts
1557 % This was previously done with \pageref commands. When I stopped
1558 % using \pageref for this (in order to make this compatible with
1559 % hyperref.sty), this stuff was created:
1561 % \gdef commands for exam@lastpage, exam@numpoints,
1562 % exam@numbonuspoints, exam@numquestions, exam@numparts,
1563 % exam@numsubparts and exam@numsubsubparts are written to the .aux
1564 % file via \AtEndDocument.
1566 % \gdef commands for pointsofq@i, pointsofq@ii, etc. and
1567 % bonuspointsofq@i, bonuspointsofq@ii, etc. are written to the .aux
1568 % file as each question is completed (see the definition of the
1569 % questions environment).
1571 % \gdef commands for pointsonpage@i, pointsonpage@ii, etc. and
1572 % bonuspointsonpage@i, bonuspointsonpage@ii, etc. are written to the
1573 % .aux file as we encounter points defined for a later page, and for
1574 % the last such page with AtEndDocument.
1576 \def\numpages{\@ifundefined{exam@lastpage}%
1577 {\mbox{\normalfont\bfseries ??}}%
1581 % Change 2011/04/01: We added a ``0'' in front of the
1582 % mbox when \exam@lastcoverpage isn't defined. This is
1583 % so that the construction \romannumeral\numcoverpages
1584 % won't generate an error on the first run of latex.
1585 \def\numcoverpages{\@ifundefined{exam@lastcoverpage}%
1586 {0\mbox{\normalfont\bfseries ??}}%
1590 \def\totalnumpages{\@ifundefined{exam@totalpages}%
1591 {\mbox{\normalfont\bfseries ??}}%
1595 \def\numpoints{\@ifundefined{exam@numpoints}%
1596 {\mbox{\normalfont\bfseries ??}}%
1599 \def\numbonuspoints{\@ifundefined{exam@numbonuspoints}%
1600 {\mbox{\normalfont\bfseries ??}}%
1601 \exam@numbonuspoints
1604 \def\numquestions{\@ifundefined{exam@numquestions}%
1605 {\mbox{\normalfont\bfseries ??}}%
1609 \def\numparts{\@ifundefined{exam@numparts}%
1610 {\mbox{\normalfont\bfseries ??}}%
1614 \def\numsubparts{\@ifundefined{exam@numsubparts}%
1615 {\mbox{\normalfont\bfseries ??}}%
1619 \def\numsubsubparts{\@ifundefined{exam@numsubsubparts}%
1620 {\mbox{\normalfont\bfseries ??}}%
1621 \exam@numsubsubparts
1624 \def\pointsofquestion#1{\@ifundefined{pointsofq@\romannumeral #1}%
1625 {\mbox{\normalfont\bfseries ??}}%
1626 {\csname pointsofq@\romannumeral #1\endcsname}%
1628 \def\bonuspointsofquestion#1{\@ifundefined{bonuspointsofq@\romannumeral #1}%
1629 {\mbox{\normalfont\bfseries ??}}%
1630 {\csname bonuspointsofq@\romannumeral #1\endcsname}%
1631 }% bonuspointsofquestion
1633 % For use in \combinedgradetable and \combinedpointtable, we're
1634 % changing the defintions of \pointsonpage and \bonuspointsonpage
1635 % so that when, e.g., pointsonpage@ii is undefined, we just produce
1636 % 0. This comes up because the final page of the exam may have either
1637 % points with no bonus point or bonus points with no points, in which
1638 % case the combined table will try to list both points and bonus points
1639 % for that last page, and one of those will be undefined.
1641 % \def\pointsonpage#1{\@ifundefined{pointsonpage@\romannumeral #1}%
1642 % {\mbox{\normalfont\bfseries ??}}%
1643 % {\csname pointsonpage@\romannumeral #1\endcsname}%
1645 % \def\bonuspointsonpage#1{\@ifundefined{bonuspointsonpage@\romannumeral #1}%
1646 % {\mbox{\normalfont\bfseries ??}}%
1647 % {\csname bonuspointsonpage@\romannumeral #1\endcsname}%
1648 % }% bonuspointsonpage
1650 % spanish.ldf redefines \@roman, so we'll avoid using \roman:
1651 \def\pointsonpage#1{\@ifundefined{pointsonpage@\romannumeral #1}%
1653 {\csname pointsonpage@\romannumeral #1\endcsname}%
1655 \def\bonuspointsonpage#1{\@ifundefined{bonuspointsonpage@\romannumeral #1}%
1657 {\csname bonuspointsonpage@\romannumeral #1\endcsname}%
1658 }% bonuspointsonpage
1661 \newif\if@pointschanged
1662 \@pointschangedfalse
1664 \newcommand*{\CheckIfChanged@hlf}[2]{%
1665 % The first argument is the name of a half counter.
1666 % The second argument expands to the name (without the escape
1667 % character, and not assumed to be defined) of the control sequence
1668 % holding the previous value.
1670 {\global\@pointschangedtrue}%
1672 % OK; it's defined. See if it's changed:
1674 \set@hlfcntr{tmp@hlfcntr}{\csname #2\endcsname}%
1675 \edef\othpt@check{\prtaux@hlfcntr{tmp@hlfcntr}}%
1676 \edef\pt@check{\prtaux@hlfcntr{#1}}%
1677 \ifx \pt@check \othpt@check
1680 \global\@pointschangedtrue
1684 }% CheckIfChanged@hlf
1687 %%%\let\@realenddocument=\enddocument
1688 %%%\def\enddocument{\clearpage
1690 %%% {\advance\c@page-1 \immediate\write\@mainaux
1691 %%% {\string\newlabel{@lastpage}{{}{\arabic{page}}}}%
1694 %%% \@realenddocument
1701 \immediate\write\@mainaux
1702 {\string\gdef\string\exam@lastpage{\arabic{page}}}%
1703 \immediate\write\@mainaux
1704 {\string\gdef\string\exam@lastcoverpage{\arabic{num@coverpages}}}%
1705 % We can now trash the value of num@coverpages:
1706 \addtocounter{num@coverpages}{\value{page}}%
1707 \immediate\write\@mainaux
1708 {\string\gdef\string\exam@totalpages{\arabic{num@coverpages}}}%
1709 \advance\c@page+1 % In case some other package looks at \c@page
1711 \immediate\write\@mainaux
1712 {\string\gdef\string\exam@numpoints{%
1713 \prtaux@hlfcntr{numpoints}}}%
1714 % See if this has changed from the last run of LaTeX:
1715 \CheckIfChanged@hlf{numpoints}{exam@numpoints}%
1716 \immediate\write\@mainaux
1717 {\string\gdef\string\exam@numbonuspoints{%
1718 \prtaux@hlfcntr{numbonuspoints}}}%
1719 % See if this has changed from the last run of LaTeX:
1720 \CheckIfChanged@hlf{numbonuspoints}{exam@numbonuspoints}%
1721 \immediate\write\@mainaux
1722 {\string\gdef\string\exam@numquestions{\thenumquestions}}%
1723 \immediate\write\@mainaux
1724 {\string\gdef\string\exam@numparts{\thenumparts}}%
1725 \immediate\write\@mainaux
1726 {\string\gdef\string\exam@numsubparts{\thenumsubparts}}%
1727 \immediate\write\@mainaux
1728 {\string\gdef\string\exam@numsubsubparts{\thenumsubsubparts}}%
1729 \ifnum \thepageof@pagepoints > 0\relax
1730 \immediate\write\@mainaux
1731 {\string\gdef\string\pointsonpage@\romannumeral
1732 \csname c@pageof@pagepoints\endcsname
1733 {\prtaux@hlfcntr{@pagepoints}}}%
1734 % See if this has changed from the last run of LaTeX:
1735 \CheckIfChanged@hlf{@pagepoints}{pointsonpage@\romannumeral
1736 \csname c@pageof@pagepoints\endcsname}%
1738 \ifnum \thepageof@pagebonuspoints > 0\relax
1739 \immediate\write\@mainaux
1740 {\string\gdef\string\bonuspointsonpage@\romannumeral
1741 \csname c@pageof@pagebonuspoints\endcsname
1742 {\prtaux@hlfcntr{@pagebonuspoints}}}%
1743 \CheckIfChanged@hlf{@pagebonuspoints}{bonuspointsonpage@\romannumeral
1744 \csname c@pageof@pagebonuspoints\endcsname}%
1746 \immediate\write\@mainaux
1747 {\string\gdef\string\lastpage@withpoints{\page@withpoints}}%
1748 % See if this has changed from the last run of LaTeX:
1749 \@ifundefined{lastpage@withpoints}%
1750 {\global\@pointschangedtrue}%
1752 % OK; it's defined. See if it's changed:
1754 \edef\othpt@check{\page@withpoints}%
1755 \edef\pt@check{\lastpage@withpoints}%
1756 \ifx \pt@check \othpt@check
1759 \global\@pointschangedtrue
1763 \immediate\write\@mainaux
1764 {\string\gdef\string\lastpage@withbonuspoints{\page@withbonuspoints}}%
1765 % See if this has changed from the last run of LaTeX:
1766 \@ifundefined{lastpage@withbonuspoints}%
1767 {\global\@pointschangedtrue}%
1769 % OK; it's defined. See if it's changed:
1771 \edef\othpt@check{\page@withbonuspoints}%
1772 \edef\pt@check{\lastpage@withbonuspoints}%
1773 \ifx \pt@check \othpt@check
1776 \global\@pointschangedtrue
1781 % Echo numbers of questions, parts, and subparts:
1782 \typeout{This exam contains \thenumquestions\space questions
1783 with \thenumparts\space parts, \thenumsubparts\space subparts,
1784 and \thenumsubsubparts\space subsubparts.}
1785 % If counting points, echo total points:
1786 \if@printtotalpoints
1794 \typeout{This exam has a total of \typ@expnd\space points.}
1797 \ifnumbonuspoints@half
1801 \typeout{This exam has a total of \typ@expnd\space bonus points.}
1805 \ClassWarningNoLine{exam}{Point totals have changed.
1806 Rerun to get point totals right}%
1811 % We define \iflastpage so that it can safely be used
1812 % in headers and footers:
1813 \def\iflastpage#1#2{%
1814 \@ifundefined{exam@lastpage}{\def\@@lastpage{-1}}%
1815 {\edef\@@lastpage{\exam@lastpage}}%
1816 \ifnum\value{page}=\@@lastpage\relax
1824 % The macro \oddeven takes two arguments. If the page number is odd,
1825 % then you get the first argument; otherwise, you get the second
1837 %--------------------------------------------------------------------
1838 %--------------------------------------------------------------------
1839 % \ifcontinuation, \ContinuedQuestion,
1840 % \ifincomplete, and \IncompleteQuestion
1842 % The commands \ifcontinuation, \ContinuedQuestion, \ifincomplete, and
1843 % \IncompleteQuestion assume that there is only one questions
1844 % environment in the entire document. (Actually, \ContinuedQuestion
1845 % should work even if there are multiple questions environments, but
1846 % none of the other three will work in general.)
1850 % \PgInfo@write, \PgInfo and \PgInfo@get are our replacements
1851 % for \label, \newlabel, and \pageref. (We're avoiding using
1852 % \label, \newlabel, and \pageref so that we will be compatible
1853 % with hyperref.sty, which redefines those commands.)
1855 % We use \PgInfo, \PgInfo@write, and \PgInfo@get to know on which page
1856 % each question, part, subpart, subsubpart, and choice appears.
1858 % We use \PgInfo@write to write \PgInfo commands to the .aux file. The
1859 % \PgInfo command takes two arguments: A question (or part, or subpart,
1860 % or subsubpart) label, and the number of the page on which it appears.
1862 % The label for a question is of the form `question@2' (if it's question
1865 % The label for a part is of the form `part@2@1' (if it's part a of
1868 % The label for a subpart is of the form `subpart@2@1@3' (if it's
1869 % subpart iii of part a of question 2).
1871 % The label for a subsubpart is of the form `subsubpart@2@1@3@4' (if
1872 % it's subsubpart $\delta$ of subpart iii of part a of question 2).
1874 % Each question, part, subpart, subsubpart, and choice also gets a
1875 % \PgInfo@write command using a label of the form question2@object3 (if
1876 % it's the third object of the second question).
1878 % Inside one of the solution environments (solution, solutionorbox,
1879 % etc.) each part, subpart, subsubpart, and choice get only the
1880 % \PgInfo@write command using a label of the form question2@object3
1881 % (if it's the third object of the second question).
1883 % When read in from the .aux file, the \PgInfo command defines a
1884 % control sequence of the form `Pg@label' that expands to the page
1885 % number for the corresponding question. For example,
1886 % \PgInfo{subsubpart@2@1@3@4}{7} defines \csname
1887 % Pg@subsubpart@2@1@3@4\endcsname to expand to 7.
1889 % The \PgInfo@get{label} command returns the value of the macro Pg@label,
1890 % but it *doesn't* check whether that macro is defined. Thus, it's
1891 % important to check that the macro Pg@label is defined before giving the
1892 % command \PgInfo@get{label}.
1896 % The token list to a \write command isn't expanded until
1897 % it's shipped out. Since the argument to PgInfo@write
1898 % generally contains macros, we want to expand those macros
1899 % now, rather than waiting until this is shipped out, at which
1900 % point the macros may have different values. Thus, we use
1901 % \edef to force expansion of the argument, and we put
1902 % a \noexpand in front of \thepage so that the \thepage
1903 % will not be expanded now. (This may not get shipped out
1904 % until a later page, and so we want the \thepage to be expanded
1905 % only when it's shipped out.)
1906 % We use the \begingroup \endgroup pair so that our use
1907 % of \reserved@a won't affect its use anywhere else.
1908 \def\PgInfo@write#1{%
1910 \edef\reserved@a{\write\@mainaux
1911 {\string\PgInfo{#1}{\noexpand\thepage}}}%
1916 %\PgInfo commands are written to the .aux file by the \PgInfo@write
1917 %command; that's the only place that \PgInfo commands appear.
1918 \def\PgInfo#1#2{\expandafter\gdef\csname Pg@#1\endcsname{#2}}
1920 % Note: PgInfo@get assumes that the control sequence being
1921 % constructed is already defined; you have to make sure of this
1922 % *before* calling \Pginfo@get
1923 \def\PgInfo@get#1{\csname Pg@#1\endcsname}
1925 % \set@counter@to@pageof takes two arguments: The first is the name of a
1926 % counter, and the second (expands to) the label of a question, part,
1927 % subpart, subsubpart, or choice. If that label exists, then we set the
1928 % counter equal to the page on which the question (or part, etc.)
1929 % appears. If that label doesn't exist, we set the counter equal to -1.
1930 % (No labels exist on the first run of LaTeX on the file, and if a new
1931 % question (or part, etc.) was created by editing the file, then the
1932 % label will not exist until the run of LaTeX after that.)
1933 \def\set@counter@to@pageof#1#2{%
1934 \@ifundefined{Pg@#2}%
1935 {\setcounter{#1}{-1}}%
1936 {\setcounter{#1}{\csname Pg@#2\endcsname}}%
1940 %--------------------------------------------------------------------
1942 % \ifcontinuation#1#2 expands to #2 if either:
1943 % (1) The command \noquestionsonthispage has been given on this page,
1945 % (2) The current page is before the page containing question number
1947 % (3) A question begins on this page before any part, subpart,
1948 % subsubpart, or choice begins, or
1949 % (4) The current page is later than a page with the \nomorequestions
1951 % Otherwise, it expands to #1.
1953 % Thus, for example, if there are no questions, parts, subparts,
1954 % subsubparts, or choices on this page, and no \noquestionsonthispage
1955 % command, and we're not before question 1, and not after a
1956 % \nomorequestions command, then \ifcontinuation will expand to #1.
1959 \def\ifcontinuation#1#2{%
1960 % If there's a \noquestionsonthispage command on this page, then
1961 % we assume that we're not continuing anything:
1962 \@ifundefined{No@Questions@Pg@\thepage}%
1963 {\chk@contin{#1}{#2}}%
1967 \def\chk@contin#1#2{%
1968 % We check whether we're on a page *before* the page on which the
1969 % first question appears. If we don't yet know which page has
1970 % question number 1, then we must be doing an early run of LaTeX,
1971 % and we'll assume we're not a continuation.
1972 \expandafter\ifx\csname Pg@question@1\endcsname\relax
1973 % No page info yet; assume not a continuation
1976 % Note: The ``\relax'' at the end of the following \ifnum
1977 % serves an entirely different purpose from the one at the
1978 % end of the above \expandafter\ifx. That one (above)
1979 % is one of the things being compared, whereas the
1980 % one we're about to use is just to clearly mark the
1981 % end of the second number being compared by the \ifnum
1982 % (since it's conceivable that the ``#2'' would begin
1984 \ifnum \thepage < \csname Pg@question@1\endcsname\relax
1985 % We're before the page with question 1:
1988 % The current page begins a new question if Contin@\thepage
1989 % has been defined as a macro that expands to \relax (Note
1990 % that this is different from if Contin@\thepage has never
1991 % been defined at all, in which case it will be let equal to
1992 % \relax (temporarily) by the \csname command.)
1993 \expandafter\ifx\csname Contin@\thepage\endcsname\ref@relax
1996 % See if we're after a \nomorequestions command:
1997 \@ifundefined{Pg@@endquestions}%
1999 {\ifnum \thepage > \PgInfo@get{@endquestions}\relax
2000 % We're after a \nomorequestions:
2003 % We actually are incomplete:
2012 \def\nomorequestions{%
2013 \PgInfo@write{@endquestions}%
2016 \def\noquestionsonthispage{%
2017 \write\@mainaux{\string\expandafter\string\gdef
2018 \string\csname\space No@Questions@Pg@\thepage\string\endcsname
2019 {No questions here}}%
2020 }% noquestionsonthispage
2023 %--------------------------------------------------------------------
2024 % \ContinuedQuestion is for use in headers and footers, where we can
2025 % assume that \thepage is the number of the page on which we'll
2028 % \ContinuedQuestion expands to the number of the question that
2029 % continues onto this page, or to -1 if this page begins with a new
2032 % ACTUALLY: \ContinuedQuestion expands to a positive number if either
2033 % (1) this page doesn't contain the beginning of any question, part,
2034 % subpart, subsubpart, or choice, or (2) this page has a part, subpart,
2035 % subsubpart, or choice that appears before any question. That means
2036 % that if the current page actually begins with space for a continuation
2037 % of the previous question (but doesn't begin any part, subpart,
2038 % subsubpart, or choice of that question) and then has a question, then
2039 % we'll be asserting that this page begins with a new question, but the
2040 % actual top of the page will begin with some blank space that's
2041 % intended for the previous question.
2043 % \ContinuedQuestion works by examining the value of the macro
2044 % Contin@\thepage. If this page starts with a question (i.e., if no
2045 % question continues onto this page), then the macro Contin@\thepage
2046 % will be defined, and will expand to `\relax' (and so an \ifx between
2047 % \csname Contin@\thepage\endcsname and \ref@relax will be true).
2049 % If Contin@\thepage is undefined, then when it is used in an \ifx
2050 % command it will be temporarily set equal to \relax (which is
2051 % *different* from being a macro that expands to \relax); in this case,
2052 % there is no question, part, subpart, subsubpart, or choice that begins
2053 % on this page, and so \ContinuedQuestion will be set equal to the last
2054 % question that was begun on a page before this one.
2056 % The last possibility is that this page begins with either a part,
2057 % subpart, subsubpart, or choice. In this case, Contin@\thepage is
2058 % defined, and it expands to the number of the question that is
2059 % continued onto this page.
2062 \def\ref@relax{\relax}
2064 \def\ContinuedQuestion{%
2065 \expandafter\ifx\csname Contin@\thepage\endcsname\relax
2066 % We get here if there's no question, part, subpart,
2067 % subsubpart, or choice on this page, and so Contin@\thepage has
2068 % never been defined at all. In that case, this page
2069 % continues whichever question was last begun on or
2074 \expandafter\ifx\csname Contin@\thepage\endcsname\ref@relax
2075 % We get here if this page begins with a new question,
2076 % which is why Contin@\thepage has been defined to be
2077 % a macro that expands to \relax.
2078 % ACTUALLY: We get here if this page has a question that
2079 % appears before any part, subpart, subsubpart, or choice. That
2080 % means that if the current page actually begins with space
2081 % for a continuation of the previous question but doesn't begin
2082 % any part, subpart, subsubpart, or choice of that question, then
2083 % we'll be asserting that this page begins with a new question,
2084 % but the actual top of the page will begin with some space
2085 % that's intended for the previous question.
2088 % We get here if we didn't get anywhere above. This happens
2089 % if Contin@\thepage has been defined to be a macro that expands
2090 % to something other than \relax, in which case it has been
2091 % defined to be a macro that expands to the number of the
2092 % question that continues onto this page.
2093 \csname Contin@\thepage\endcsname
2098 %--------------------------------------------------------------------
2099 % \find@latestques is for use in headers and footers, where we can
2100 % assume that \thepage actually equals the page on which we'll appear.
2101 % We find the last question that was started on or before the current
2104 \newcounter{latest@ques}
2106 \newcommand\find@latestques{%
2107 % \find@latestques is for use in headers and footers.
2108 % \find@latestques will set the counter latest@ques
2109 % to the number of the last question
2110 % that was begun on the exam from page 1 through the current
2111 % page. This may well be the value of the question counter,
2112 % but it may be less than that if the page following this one
2113 % begins a new question and that question beginning was
2114 % typeset before the present page was shipped out.
2115 % Note: This macro is called both by \ContinuedQuestion and by
2116 % \find@quesend, which is why it has to find the last question
2117 % begun on or before the current page, rather than just before
2119 \ifnum 1 > \value{question}\relax
2120 % Oops; probably because we're before the first question
2121 % Just set latest@ques to -1:
2122 \setcounter{latest@ques}{-1}%
2124 % If question latest@ques actually begins on this page (rather
2125 % than on the next page, but early enough on the next page
2126 % that the counter was advanced before we ran off into the
2127 % output routine to output the page and set the header and
2128 % footer), then that's the correct question number.
2129 \expandafter\ifx\csname Pg@question@\arabic{question}\endcsname\relax
2130 % We don't know what page that question is on;
2131 % this must be an early run, before the aux file
2132 % is helpful. Just set it equal to -1 and wait until the next
2133 % run to get it right.
2134 \setcounter{latest@ques}{-1}%
2136 % We now know that \PgInfo@get can tell us the page number
2137 % of \arabic{question} and of all earlier questions.
2138 % Set latest@ques equal to the current question number, and
2139 % then call \decr@latest@ques to recursively decrement
2140 % latest@ques as needed to find a question that begins on
2141 % or before the current page:
2142 \setcounter{latest@ques}{\value{question}}%
2148 \def\decr@latest@ques{%
2149 % If we get here, then we've already checked that the reference
2150 % Pg@question@\thelatest@ques is defined at least for a value of
2151 % \thelatest@ques greater than or equal to it's present value,
2152 % so we assume it's defined for all lesser values as well:
2153 \ifnum \thepage < \PgInfo@get{question@\thelatest@ques}\relax
2154 % Nope; latest@ques starts on a later page
2155 % Decrement latest@ques and see if that one's right:
2156 \addtocounter{latest@ques}{-1}%
2157 \ifnum \thelatest@ques < 1\relax
2158 \setcounter{latest@ques}{-1}%
2159 \let\next@dlq=\relax
2161 \let\next@dlq=\decr@latest@ques
2164 % latest@ques starts on this page or earlier, so
2165 % that's the correct question number! Exit:
2166 \let\next@dlq=\relax
2171 %--------------------------------------------------------------------
2172 %--------------------------------------------------------------------
2173 %--------------------------------------------------------------------
2174 \newcounter{ques@end}
2175 \newcounter{last@object}
2178 % We find the last question started on or before the current page
2179 % and then find the page containing the last part (or subpart, or
2180 % subsubpart, or choice) of that question, and set the counter
2181 % ques@end to that page number.
2182 % Set latest@ques equal to the correct question number:
2184 \ifnum \value{latest@ques} < 0\relax
2185 % This must be an early run of LaTeX, before we have
2186 % \PgInfo commands in the .aux file:
2187 \setcounter{ques@end}{-1}%
2189 % We now know that this question has at least one object (since
2190 % we know that latest@ques isn't negative).
2191 % We'll find its highest numbered object by setting last@object
2192 % equal to 2 and then calling \find@lastobject to recursively
2193 % test whether that object number exists and, if so, incrementing
2194 % last@object to test for a higher numbered one:
2195 \setcounter{last@object}{2}%
2197 \setcounter{ques@end}{\PgInfo@get{question\thelatest@ques
2198 @object\thelast@object}}%
2202 \def\find@lastobject{%
2203 % We check whether this question has an object numbered last@object
2204 % and recursively increment last@object to find the highest
2205 % numbered value for which the object exists:
2206 \@ifundefined{Pg@question\thelatest@ques @object\thelast@object}%
2207 {\addtocounter{last@object}{-1}%
2208 \let\nextfind@lastobject=\relax
2210 {\addtocounter{last@object}{1}%
2211 \let\nextfind@lastobject=\find@lastobject
2213 \nextfind@lastobject
2218 %--------------------------------------------------------------------
2219 %--------------------------------------------------------------------
2220 %--------------------------------------------------------------------
2222 \newcounter{incmp@ques}
2224 \def\IncompleteQuestion{%
2226 % If there's no incomplete question, the counter incmp@ques will be
2231 \def\Find@Incmp@ques{%
2232 % If we're on the last page, then there's no incomplete question:
2233 \iflastpage{\setcounter{incmp@ques}{-1}}{\chk@incomp}%
2235 \newcounter{next@ques}
2236 \newcounter{next@page}
2239 % If we get here, we're not on the last page.
2240 % \find@quesend calls \find@latestques to set the counter
2241 % latest@ques equal to the number of the last question begun on or
2242 % before the current page, and then it sets the counter ques@end to
2243 % the page containing the last ques@object of that question:
2245 \ifnum \theques@end > \thepage\relax
2246 % This question has a part (or sub...) starting on a later page
2247 \setcounter{incmp@ques}{\value{latest@ques}}%
2254 % If there are any pages after the current one and before the next
2255 % question (if there is a next question) that lack a
2256 % \noquestionsonthispage and that aren't following the page of a
2257 % \nomorequestions command, then question latest@ques is incomplete.
2258 % Otherwise, there is no incomplete question:
2259 \setcounter{next@ques}{\thelatest@ques}%
2260 \addtocounter{next@ques}{1}%
2261 % We use next@page as a scratch counter. We start by setting it
2262 % to the last page we want to check for a \noquestionsonthispage
2264 \expandafter\ifx\csname Pg@question@\thenext@ques \endcsname\relax
2265 % This isn't the last page but there is no next question:
2267 \@ifundefined{exam@lastpage}%
2268 {\setcounter{next@page}{-1}}%
2269 {\setcounter{next@page}{\exam@lastpage}}%
2271 % \setcounter{next@page}{\exam@lastpage}%
2273 \setcounter{next@page}{\PgInfo@get{question@\thenext@ques}}%
2274 \addtocounter{next@page}{-1}%
2276 % See if that's after a \nomorequestions command:
2277 \@ifundefined{Pg@@endquestions}%
2279 {\ifnum \PgInfo@get{@endquestions} < \value{next@page}\relax
2280 \setcounter{next@page}{\PgInfo@get{@endquestions}}%
2283 % OK, the counter next@page now contains the last page to check.
2288 \ifnum \value{next@page} > \value{page}\relax
2289 % We need to check the page next@page:
2290 \@ifundefined{No@Questions@Pg@\arabic{next@page}}%
2291 {\setcounter{incmp@ques}{\value{latest@ques}}%
2292 \let\next@incompii=\relax
2294 {\addtocounter{next@page}{-1}%
2295 \let\next@incompii = \chk@incompii
2298 % There's no incomplete question:
2299 \setcounter{incmp@ques}{-1}%
2300 \let\next@incompii=\relax
2305 \def\ifincomplete#1#2{%
2306 % We need to pass the arguments to \chk@ifincomp; we save them in
2307 % macros so they won't be messed up by the call to \Find@Incmp@ques:
2308 \def\incomp@first{#1}%
2309 \def\incomp@second{#2}%
2310 % If there's a \noquestionsonthispage command on this page, then
2311 % we assume nothing from this page is incomplete:
2312 \@ifundefined{No@Questions@Pg@\thepage}%
2319 % If there's no incomplete question, \Find@Incmp@ques sets the
2320 % counter incmp@ques to -1:
2321 \ifnum \theincmp@ques < 0\relax
2324 % Are we after a page with \nomorequestions?
2325 \@ifundefined{Pg@@endquestions}%
2327 {\ifnum \thepage < \PgInfo@get{@endquestions}\relax
2336 %--------------------------------------------------------------------
2337 % These are the commands for dealing with hlfcntr's, i.e., the things
2338 % used to count points.
2340 % A point value is a nonnegative integer with an optional half integer.
2341 % A hlfcntr consists of a regular counter together with an \if: If the
2342 % regular counter is called ``counter'', then the \if is called
2343 % ``\ifcounter@half''; it's set true by ``\counter@halftrue'' and set
2344 % false by ``\counter@halffalse''.
2348 % \new@hlfcntr{countername}
2349 % \set@hlfcntr{countername}{value}
2350 % \copy@hlfcntr{tocounter}{fromcounter}
2351 % \addto@hlfcntr{countername}{value}
2352 % \add@hlfcntrtohlfcntr{getsaddedto}{whatsadded}
2353 % \ifhlfcntr@pos{countername}
2354 % \prtaux@hlfcntr{countername}
2355 % \prt@hlfcntr{countername}
2357 % ``value'' can be either a (nonnegative) integer, an integer followed by
2358 % ``\half'', or just plain ``\half''. (Actually, ``value'' can be empty
2359 % (although the braces must be present), in which case it's interpreted
2362 % Examples of valid values:
2371 % Note on using ``\global'': LaTeX's \setcounter and \addtocounter
2372 % commands are already \global (i.e., you don't have to say
2373 % ``\global''), but \somethingtrue and \somethingfalse (used to set
2374 % \ifsomething) aren't. Thus, we need to say ``\global'' when setting
2377 % To create a hlfcntr:
2378 \newcommand*\new@hlfcntr[1]{%
2380 \expandafter\newif\csname if#1@half\endcsname
2384 % A scratch hlfcntr:
2385 \new@hlfcntr{tmp@hlfcntr}
2387 \newcommand*\horiz@half{$\frac{1}{2}$}
2388 \newcommand*\slanted@half{%
2389 $\raise0.6ex\hbox{$\scriptstyle 1$}\kern -.2em/\kern -.2em
2390 \raise-0.5ex\hbox{$\scriptstyle 2$}$%
2392 \newcommand*\useslantedhalf{\global\let\half\slanted@half}
2393 \newcommand*\usehorizontalhalf{\global\let\half\horiz@half}
2394 \newcommand*\half{\slanted@half}
2397 \newcommand*\set@hlfcntr[2]{%
2399 \global\csname #1@halffalse\endcsname
2400 % If there as a `\half' present, it will be executed
2401 % right after the assignment of the digit part of #2
2402 % to the counter #1.
2404 \global\csname #1@halftrue\endcsname
2406 % We insert a `0' in case there are no digits present:
2407 % We avoid using \setcounter, because calc.sty redefines
2408 % \setcounter in a way that conflicts with the \half trick
2410 % \setcounter{#1}{0#2}\relax
2411 \global\csname c@#1\endcsname 0#2\relax
2415 \newcommand*\copy@hlfcntr[2]{%
2416 % We set #1 to the value of #2
2417 \setcounter{#1}{\value{#2}}%
2418 \csname if#2@half\endcsname
2419 \global\csname #1@halftrue\endcsname
2421 \global\csname #1@halffalse\endcsname
2425 \newcommand*\addto@hlfcntr[2]{%
2426 % We add the valueandhalf #2 to hlfcntr #1
2428 \def\half{\add@half{#1}}%
2429 % We insert a `0' in case there are no digits present:
2430 % We avoid using \addtocounter, because calc.sty redefines
2431 % \addtocounter in a way that conflicts with the \half trick
2433 % \addtocounter{#1}{0#2}\relax
2434 \global\advance\csname c@#1\endcsname 0#2\relax
2438 \newcommand*\add@hlfcntrtohlfcntr[2]{%
2439 % We add the hlfcntr #2 to the hlfcntr #1
2440 \addtocounter{#1}{\value{#2}}%
2441 \csname if#2@half\endcsname
2444 }% add@hlfcntrtohlfcntr
2446 \newcommand*\add@half[1]{%
2447 % We add one half to hlfcntr #1:
2448 \csname if#1@half\endcsname
2449 \addtocounter{#1}{1}%
2450 \global\csname #1@halffalse\endcsname
2452 \global\csname #1@halftrue\endcsname
2456 % Important reminder about \ifhlfcntr@pos: Do not use it inside
2457 % another conditional! The construction
2458 % \ifhlfcntr@pos{somecounter}
2461 % is perfectly fine as long as it's expanded, but: If it's inside
2462 % another conditional, and the condition is not satisfied, then it's
2463 % read through without expansion. In that case, TeX sees the
2464 % \ifhlfcntr@pos but does *not* recognize it as being part of a
2465 % conditional, but when it sees the concluding \fi it does recognize
2466 % that, and so TeX completes the outer conditional at that \fi, which
2468 \newcounter{ifpos@cntr}
2469 \def\ifhlfcntr@pos#1{%
2470 % The argument must be a hlfcntr (which, of course,
2471 % can never be negative); we'll be true if and only if
2472 % that halfcntr is positive:
2473 \setcounter{ifpos@cntr}{\value{#1}}%
2474 \csname if#1@half\endcsname
2475 \addtocounter{ifpos@cntr}{1}%
2477 \ifnum \value{ifpos@cntr} > 0\relax
2480 % \prtaux@hlfcntr is used inside the argument of a \write command for
2481 % writing to the .aux file:
2482 \newcommand*\prtaux@hlfcntr[1]{%
2483 % We don't want a \relax after the 0 in the following
2484 % line, because it would sometimes appear in the aux file:
2485 \ifnum \value{#1} = 0
2486 % We have to make the following a macro, because if we
2487 % don't do this part, the \fi will cause confusion, since
2488 % there's no \if visible until the \csname is expanded:
2489 \prtaux@halforzero{#1}%
2492 % We have to make the following a macro, because if we
2493 % don't do this part, the \fi will cause confusion, since
2494 % there's no \if visible until the \csname is expanded:
2495 \prtaux@halforblank{#1}%
2498 \newcommand*\prtaux@halforzero[1]{%
2499 \csname if#1@half\endcsname
2505 \newcommand*\prtaux@halforblank[1]{%
2506 \csname if#1@half\endcsname
2509 }% prtaux@halforblank
2511 \newcommand*\prt@hlfcntr[1]{%
2512 % We don't want a \relax after the 0 in the following
2513 % line, because it would sometimes appear in the aux file:
2514 \ifnum \value{#1} = 0
2515 % We have to make the following a macro, because if we
2516 % don't do this part, the \fi will cause confusion, since
2517 % there's no \if visible until the \csname is expanded:
2518 \prt@halforzero{#1}%
2521 % We have to make the following a macro, because if we
2522 % don't do this part, the \fi will cause confusion, since
2523 % there's no \if visible until the \csname is expanded:
2524 \prt@halforblank{#1}%
2527 \newcommand*\prt@halforzero[1]{%
2528 \csname if#1@half\endcsname
2534 \newcommand*\prt@halforblank[1]{%
2535 \csname if#1@half\endcsname
2540 % End of the commands for dealing with hlfcntr's
2542 %--------------------------------------------------------------------
2543 %---------------------------------------------------------------------
2545 % ***************************
2546 % ** QUESTION ENVIRONMENTS **
2547 % ***************************
2552 % We define the command \part only inside of a parts environment, so
2553 % that we don't interfere with the meaning of the standard article
2554 % documentclass command \part if that is used inside of a questions
2555 % environment. The commands \question, \subpart, and \subsubpart are
2556 % defined everywhere inside of a questions environment. If the user
2557 % accidentally gives a \subpart command outside of a subparts
2558 % environment, then an error will be created.
2563 % We use the counter name `partno' for the parts environment so that
2564 % we will not interfere with the counter `part' used by the article
2567 \newcounter{question}
2569 \newcounter{subpart}
2570 \newcounter{subsubpart}
2572 \new@hlfcntr{numpoints}
2573 \set@hlfcntr{numpoints}{0}
2574 \new@hlfcntr{numbonuspoints}
2575 \set@hlfcntr{numbonuspoints}{0}
2576 \new@hlfcntr{pointsof@thisquestion}
2577 \set@hlfcntr{pointsof@thisquestion}{0}
2578 \new@hlfcntr{bonuspointsof@thisquestion}
2579 \set@hlfcntr{bonuspointsof@thisquestion}{0}
2580 \newcounter{numquestions}
2581 \newcounter{numparts}
2582 \newcounter{numsubparts}
2583 \newcounter{numsubsubparts}
2584 \newcounter{Curr@Page}
2586 % @pagepoints accumulates the points on a single page:
2587 \new@hlfcntr{@pagepoints}
2588 \set@hlfcntr{@pagepoints}{0}
2589 \new@hlfcntr{@pagebonuspoints}
2590 \set@hlfcntr{@pagebonuspoints}{0}
2591 \newcounter{pageof@pagepoints}
2592 \setcounter{pageof@pagepoints}{0}
2593 \newcounter{pageof@pagebonuspoints}
2594 \setcounter{pageof@pagebonuspoints}{0}
2596 % latest@points is a holding area for points until we know
2597 % whether they'll land on the same page as the points
2598 % currently counted in @pagepoints:
2599 \new@hlfcntr{latest@points}
2600 \set@hlfcntr{latest@points}{0}
2601 \new@hlfcntr{latest@bonuspoints}
2602 \set@hlfcntr{latest@bonuspoints}{0}
2604 % Whenever we meet a new page on which points are defined, we'll
2605 % redefine \page@withpoints to expand to that page. At the end of the
2606 % document, it will hold the last page that has points, and we'll write
2607 % a \gdef\lastpage@withpoints command to the .aux file.
2608 % We initialize \page@withpoints here:
2609 \def\page@withpoints{0}%
2610 \def\page@withbonuspoints{0}%
2612 % \pageinfo@commands is used by each question, part, subpart, and
2613 % subsubpart to insert into everypar the \PgInfo@write command to put
2614 % its page number into the .aux file, the \PgInfo@get command to read
2615 % the page number into the counter Curr@Page, and to test and set
2616 % \Contin@\theCurr@Page. \temp@toks is used by part, subpart, and
2617 % subsubpart to append all that to \pageinfo@commands, rather than
2618 % deleting whatever may have been put into \pageinfo@commands by the
2619 % current question and/or part and/or subpart.
2620 \newtoks\pageinfo@commands
2623 % \pagepoint@commands holds the commands to manage the counting of the
2624 % number of points defined on each page.
2625 \newtoks\pagepoint@commands
2627 % \point@toks holds the commands to print the points at the proper
2628 % location on the page (except that it's not used by the \qformat
2632 % We'll use \greeknum to number subsubparts
2633 \def\greeknum#1{\expandafter\lc@greek\csname c@#1\endcsname}
2635 \ifcase #1\or $\alpha$\or $\beta$\or $\gamma$\or $\delta$\or
2636 $\epsilon$\or $\zeta$\or $\eta$\or $\theta$\or $\iota$\or
2637 $\kappa$\or $\lambda$\or $\mu$\or $\nu$\or $\xi$\or o\or $\pi$\or
2638 $\rho$\or $\sigma$\or $\tau$\or $\upsilon$\or $\phi$\or $\chi$\or
2639 $\psi$\or $\omega$\else \@ctrerr
2644 % The following macros are a variation on a trick from Victor
2645 % Eijkhout's ``TeX by Topic'', page 142:
2646 % Both \prepend@toklist and \append@toklist take two arguments,
2647 % both of which should be token lists.
2648 % \prepend@toklist prepends #2 to #1
2649 % \append@toklist appends #2 to #1
2651 \def\prepend@toklist#1#2{%
2652 \edef\do@it{\noexpand#1={\the#2\the#1}}%
2656 \def\append@toklist#1#2{%
2657 \edef\do@it{\noexpand#1={\the#1\the#2}}%
2662 % The command \qformat is provided for the user who wants to
2663 % design a nonstandard question line. If this command is used,
2664 % then the usual line containing the question number and the beginning
2665 % of the question will be replaced by the line specified by the
2666 % \qformat command, and the question will begin on the following
2668 % Within the argument of the \qformat command:
2669 % \thequestion will be replaced by the question number, and
2670 % \thepoints will be replaced by ``\@points \@pointname'' if the
2671 % number of points has been specified for this question, and otherwise
2672 % it inserts nothing at all. (The conditional @placepoints is used to
2673 % determine if there were points specified for this question.)
2674 % The argument to the \qformat command *must* contain some
2675 % stretch, i.e., at least one \hfil or \dotfill or ...
2677 % The command \noqformat cancels the effect of \qformat and returns us
2678 % to the default situation.
2680 % The commands \bonusqformat and \nobonusformat are analogous.
2683 \newif\if@bonusqformat
2687 \global\@qformattrue
2688 \gdef\@questionformat{#1}%
2690 \def\bonusqformat#1{%
2691 \global\@bonusqformattrue
2692 \gdef\@bonusquestionformat{#1}%
2695 \newcommand\noqformat{%
2696 \global\@qformatfalse
2698 \newcommand\nobonusqformat{%
2699 \global\@bonusqformatfalse
2703 % \thepoints is for use in either a \qformat command
2704 % or a \pointformat command (or a \bonusqformat command).
2705 % It needs to have the
2706 % \if@placepoints so that if it's used in a \qformat command
2707 % it won't print anything if there are no points:
2708 \newcommand\thepoints{%
2711 \@points \@bonuspointname
2713 \@points \@pointname
2718 % \themarginpoints is for use only in a \pointformat command,
2719 % and so it doesn't need the \if@placepoints bit in \thepoints:
2720 \newcommand\themarginpoints{%
2722 \@points \@marginbonuspointname
2724 \@points \@marginpointname
2728 % We define the \subpart and \subsubpart commands when we enter a
2729 % questions environment (rather than waiting until we enter a subparts
2730 % of subsubparts environment) so that we can signal an error if a
2731 % \subpart or \subsubpart command appears outside of the corresponding
2732 % environment. (We don't do this for the \part command so that the user
2733 % can use the standard sectioning \part command outside of a parts
2736 % The counter ques@object will count the items in each question, where
2737 % an item is defined as either the question itself, or a part, or a
2738 % subpart, or a subsubpart, or a choice. This will be used by
2739 % \find@quesend to find the last page occupied by the last question
2740 % begun on or before the current page:
2741 \newcounter{ques@object}
2743 % \first@questionobject will be used by the \question command.
2744 % That is, it will be used only once, but we want to keep its
2745 % definition here, near the definitions of \addquestionobject and
2746 % \questionobject@pluspagecheck.
2747 \newcommand{\first@questionobject}{%
2748 \setcounter{ques@object}{1}%
2749 % \PgInfo@write expands it's argument, so we don't need edef:
2750 % \edef\q@object@label{%
2751 % question\arabic{question}@object\arabic{ques@object}}%
2752 % \PgInfo@write{\q@object@label}%
2753 \PgInfo@write{question\arabic{question}@object\arabic{ques@object}}%
2754 }% first@questionobject
2756 % \addquestionobject will be used by each part, subpart, and
2757 % subsubpart, and can also be used by the user to mark the end of a
2758 % question that spills over onto the next page without any part,
2759 % subpart, etc. starting on that page:
2760 \newcommand{\addquestionobject}{%
2761 \addtocounter{ques@object}{1}%
2762 % \PgInfo@write expands it's argument, so we don't need edef:
2763 % \edef\q@object@label{%
2764 % question\arabic{question}@object\arabic{ques@object}}%
2765 % \PgInfo@write{\q@object@label}%
2766 \PgInfo@write{question\arabic{question}@object\arabic{ques@object}}%
2767 }% addquestionobject
2769 % \questionobject@pluspagecheck will be used by each choice, as well
2770 % as by any \part, \subpart, or \subsubpart that's inside of a
2771 % solution. It uses the questionobject to check if we're the first
2772 % one on the current page, since choices (and questions etc. inside of
2773 % solution environments) don't have labels the way that questions,
2774 % parts, subparts, and subsubparts do (those things use the label to
2775 % check if they're the first thing on the page).
2776 \newcommand{\questionobject@pluspagecheck}{%
2777 % We don't want to do any of this if we're both inside a solution
2778 % environment and not printing answers (because we want to avoid
2779 % incrementing ques@object):
2787 }% questionobject@pluspagecheck
2788 \newcommand{\doqobj@ppchk}{%
2789 \addtocounter{ques@object}{1}%
2790 % We need the edef because we check the page of \q@object@label:
2791 \edef\q@object@label{%
2792 question\arabic{question}@object\arabic{ques@object}}%
2793 \PgInfo@write{\q@object@label}%
2794 \set@counter@to@pageof{Curr@Page}{\q@object@label}%
2795 \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax
2796 % We're the first \question, \part, \subpart, \subsubpart,
2797 % or choice on this page:
2798 \global\expandafter\edef\csname
2799 Contin@\theCurr@Page\endcsname{\arabic{question}}%
2805 % if@bonus will be true when we're doing a bonusquestion or bonuspart
2806 % or etc., and it will also be used also to distinguish between
2807 % \gradetable and \bonusgradetable (and between \pointtable and
2808 % \bonuspointtable, etc.), and also to distinguish between
2809 % \pointsinrange and \bonuspointsinrange:
2813 % The following are for advanced users who want to customize the list
2814 % parameters (\topsep, \partopsep, \itemsep, \parsep, etc.) for the
2815 % lists that these environments create. They are all defined to be
2816 % empty, but the user can change them using \renewcommand.
2817 \newcommand\questionshook{}
2818 \newcommand\partshook{}
2819 \newcommand\subpartshook{}
2820 \newcommand\subsubpartshook{}
2821 \newcommand\choiceshook{}
2822 \newcommand\checkboxeshook{}
2825 \newenvironment{questions}{%
2826 % \@queslevel is used for two purposes:
2827 % (1) We check that every \question, \part, \subpart, and
2828 % \subsubpart command appears inside the appropriate environment,
2829 % and generate an error if one appears in the wrong place.
2830 % (2) If a \qformat is being used and if \@queslevel tells us
2831 % that we're currently processing a question, then we set
2832 % \global \point@toks={} to avoid setting the points for a
2833 % question other than via the qformat command.
2834 \def\@queslevel{question}%
2835 \def\titledquestion##1{%
2837 \def\thequestiontitle{##1}%
2840 \def\bonustitledquestion##1{%
2842 \def\thequestiontitle{##1}%
2847 \def\thequestiontitle{\csname p@question\endcsname
2848 \csname thequestion\endcsname}%
2851 \def\bonusquestion{%
2853 \def\thequestiontitle{\csname p@question\endcsname
2854 \csname thequestion\endcsname}%
2857 \def\process@question{%
2859 \cover@question@error
2861 \@checkqueslevel{question}%
2862 \addtocounter{numquestions}{1}%
2863 % Write the sum of points of the previous question (if any)
2864 % to the .aux file. (At this point, the question counter
2865 % has not yet been incremented, so \value{question} is the
2866 % number of the question that was just completed.)
2868 \ifnum \value{question} > 0\relax
2869 % First do regular points:
2870 \immediate\write\@mainaux
2871 {\string\gdef\string\pointsofq@
2872 \romannumeral \csname c@question\endcsname
2873 {\prtaux@hlfcntr{pointsof@thisquestion}}}%
2874 % See if this has changed from the last run of LaTeX:
2875 \CheckIfChanged@hlf{pointsof@thisquestion}{pointsofq@\romannumeral
2876 \csname c@question\endcsname}%
2877 % Now do bonus points:
2878 \immediate\write\@mainaux
2879 {\string\gdef\string\bonuspointsofq@
2880 \romannumeral \csname c@question\endcsname
2881 {\prtaux@hlfcntr{bonuspointsof@thisquestion}}}%
2882 % See if this has changed from the last run of LaTeX:
2883 \CheckIfChanged@hlf{bonuspointsof@thisquestion}%
2884 {bonuspointsofq@\romannumeral
2885 \csname c@question\endcsname}%
2888 \set@hlfcntr{pointsof@thisquestion}{0}%
2889 \set@hlfcntr{bonuspointsof@thisquestion}{0}%
2890 % If there was a question with points immediately preceding
2891 % this question (i.e., there were no parts in the previous
2892 % question), then @placepoints will still be true, and we need to
2893 % cancel it. (We used to do this inside of the \thepoints macro,
2894 % but that allowed for an error if the user specified points for a
2895 % question but had a \qformat that didn't mention \thepoints.) We
2896 % also set @placepoints to be false when entering a parts
2898 \global \@placepointsfalse
2899 % point@toks will normally be empty at this point, but it might be
2900 % nonempty if there were points somewhere in the previous question
2901 % that never made it onto the page because we never entered
2902 % horizontal mode (perhaps because the user was weird and let the
2903 % text of a question (or part, etc.) consist entirely of an
2904 % enumerate environment, or description environment, or etc.).
2905 \global \point@toks={}%
2906 % Important: Don't leave any blank lines inside of
2907 % \pageinfo@commands!! This token list will be dumped into
2908 % horizontal mode by \everypar, and so any blank lines will
2909 % cause paragraph breaks.
2910 \pageinfo@commands={%
2911 \edef\@queslabel{question@\arabic{section}@\arabic{subsection}@\arabic{question}}%
2912 \PgInfo@write{\@queslabel}%
2913 \first@questionobject
2914 % In addition to the \PgInfo@write we use an actual \label
2915 % command. We do this in order to make the question numbers in
2916 % the grade tables into \ref's, so that if the user says
2917 % \usepackage{hyperref}, those question numbers will be clickable.
2919 % A further purpose of these labels (which we actually do for all
2920 % questions, parts, subparts, and subsubparts) is that if a
2921 % question (or part, etc.) is, e.g., moved from one page to
2922 % another, LaTeX will notice this and warn the user that LaTeX
2923 % must be run one more time to be sure everything is correct.
2925 % We need to do this even though we've already included code to
2926 % check when point totals change because questions (and parts,
2927 % etc.) know what page they're on from reading the info written to
2928 % the .aux file on the previous run. Thus, if a question (or
2929 % part, etc.) is moved to a different page, then the pointsonpage
2930 % totals won't notice until the *second* subsequent run of LaTeX,
2931 % and so there'll be no warning to the user on the *first* run.
2932 % Including these labels gives the user a warning on that first
2935 % Further futzing required: Since this is being put into the
2936 % token list \pageinfo@commands, the contents of which won't
2937 % actually be executed until we enter horizontal mode (which
2938 % may well be in the first part of a parts environment), we need
2939 % to make sure that \@currentlabel is the number of the
2941 \begingroup % to confine the change to \@currentlabel
2942 % \def\@currentlabel{\csname p@question\endcsname
2943 % \csname thequestion\endcsname}%
2944 \def\@currentlabel{\thequestiontitle}%
2945 \label{\@queslabel}%
2947 \set@counter@to@pageof{Curr@Page}{\@queslabel}%
2948 \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax
2949 % We're the first \question, \part, \subpart, \subsubpart,
2950 % or choice on this page:
2951 \global\expandafter\edef
2952 \csname Contin@\theCurr@Page\endcsname{\relax}%
2954 \the\pagepoint@commands
2955 \global \pageinfo@commands={}%
2956 }% pageinfo@commands
2958 % Remove any skips at the end of the previous paragraph
2959 % that might cause a blank line, and then end that paragraph:
2972 \def\process@subpart{%
2974 \cover@question@error
2976 \@checkqueslevel{subpart}%
2978 % We don't count this subpart, so no addtocounter{numsubparts}.
2980 \questionobject@pluspagecheck
2981 \global \pageinfo@commands={}%
2982 % We omit the pagepoint@commands
2985 \addtocounter{numsubparts}{1}%
2986 % Important: Don't leave any blank lines inside of
2987 % \pageinfo@commands!! This token list will be dumped into
2988 % horizontal mode by \everypar, and so any blank lines will
2989 % cause paragraph breaks.
2991 \edef\@subpartlabel{subpart@\arabic{section}@\arabic{subsection}@\arabic{question}%
2992 @\arabic{partno}@\arabic{subpart}}%
2993 \PgInfo@write{\@subpartlabel}%
2995 % In addition to the \PgInfo@write we use an actual \label
2996 % command. We do this in order to make the question numbers in
2997 % the grade tables into \ref's, so that if the user says
2998 % \usepackage{hyperref}, those question numbers will be clickable.
3000 % A further purpose of these labels (which we actually do for all
3001 % questions, parts, subparts, and subsubparts) is that if a
3002 % question (or part, etc.) is, e.g., moved from one page to
3003 % another, LaTeX will notice this and warn the user that LaTeX
3004 % must be run one more time to be sure everything is correct.
3006 % We need to do this even though we've already included code to
3007 % check when point totals change because questions (and parts,
3008 % etc.) know what page they're on from reading the info written to
3009 % the .aux file on the previous run. Thus, if a question (or
3010 % part, etc.) is moved to a different page, then the pointsonpage
3011 % totals won't notice until the *second* subsequent run of LaTeX,
3012 % and so there'll be no warning to the user on the *first* run.
3013 % Including these labels gives the user a warning on that first
3015 \label{\@subpartlabel}%
3016 \set@counter@to@pageof{Curr@Page}{\@subpartlabel}%
3017 \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax
3018 % We're the first \question, \part, \subpart, \subsubpart,
3019 % or choice on this page:
3020 \global\expandafter\edef\csname
3021 Contin@\theCurr@Page\endcsname{\arabic{question}}%
3023 \the\pagepoint@commands
3024 \global \pageinfo@commands={}%
3027 \append@toklist \pageinfo@commands \temp@toks
3029 % Remove any skips at the end of the previous paragraph
3030 % that might cause a blank line, and then end that paragraph:
3039 \def\bonussubsubpart{%
3043 \def\process@subsubpart{%
3045 \cover@question@error
3047 \@checkqueslevel{subsubpart}%
3049 % We don't count this subsubpart, so no addtocounter{numsubsubparts}.
3051 \questionobject@pluspagecheck
3052 \global \pageinfo@commands={}%
3053 % We omit the pagepoint@commands
3056 \addtocounter{numsubsubparts}{1}%
3057 % Important: Don't leave any blank lines inside of
3058 % \pageinfo@commands!! This token list will be dumped into
3059 % horizontal mode by \everypar, and so any blank lines will
3060 % cause paragraph breaks.
3062 \edef\@subsubpartlabel{subsubpart@\arabic{section}@\arabic{subsection}@\arabic{question}%
3063 @\arabic{partno}@\arabic{subpart}@\arabic{subsubpart}}%
3064 \PgInfo@write{\@subsubpartlabel}%
3066 % In addition to the \PgInfo@write we use an actual \label
3067 % command. We do this in order to make the question numbers in
3068 % the grade tables into \ref's, so that if the user says
3069 % \usepackage{hyperref}, those question numbers will be clickable.
3071 % A further purpose of these labels (which we actually do for all
3072 % questions, parts, subparts, and subsubparts) is that if a
3073 % question (or part, etc.) is, e.g., moved from one page to
3074 % another, LaTeX will notice this and warn the user that LaTeX
3075 % must be run one more time to be sure everything is correct.
3077 % We need to do this even though we've already included code to
3078 % check when point totals change because questions (and parts,
3079 % etc.) know what page they're on from reading the info written to
3080 % the .aux file on the previous run. Thus, if a question (or
3081 % part, etc.) is moved to a different page, then the pointsonpage
3082 % totals won't notice until the *second* subsequent run of LaTeX,
3083 % and so there'll be no warning to the user on the *first* run.
3084 % Including these labels gives the user a warning on that first
3086 \label{\@subsubpartlabel}%
3087 \set@counter@to@pageof{Curr@Page}{\@subsubpartlabel}%
3088 \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax
3089 % We're the first \question, \part, \subpart, \subsubpart,
3090 % or choice on this page:
3091 \global\expandafter\edef\csname
3092 Contin@\theCurr@Page\endcsname{\arabic{question}}%
3094 \the\pagepoint@commands
3095 \global \pageinfo@commands={}%
3098 \append@toklist \pageinfo@commands \temp@toks
3100 % Remove any skips at the end of the previous paragraph
3101 % that might cause a blank line, and then end that paragraph:
3105 }% process@subsubpart
3106 \list{\question@number}%
3107 {\usecounter{question}%
3108 % We use the default definition of \makelabel
3109 % so as not to interfere with \qformat commands.
3110 % \def\makelabel##1{\hss\llap{##1}}%
3111 \settowidth{\leftmargin}{10.\hskip\labelsep}%
3112 \labelwidth\leftmargin\advance\labelwidth-\labelsep
3116 }% End of the first argument of \newenvironment{questions}
3119 % Write the number of points of the final question
3122 \ifnum \value{question} > 0\relax
3123 % First do the regular points:
3124 \immediate\write\@mainaux
3125 {\string\gdef\string\pointsofq@\romannumeral
3126 \csname c@question\endcsname
3127 {\prtaux@hlfcntr{pointsof@thisquestion}}}%
3128 % See if this has changed from the last run of LaTeX:
3129 \CheckIfChanged@hlf{pointsof@thisquestion}%
3130 {pointsofq@\romannumeral
3131 \csname c@question\endcsname}%
3132 % Now do the bonus points:
3133 \immediate\write\@mainaux
3134 {\string\gdef\string\bonuspointsofq@\romannumeral
3135 \csname c@question\endcsname
3136 {\prtaux@hlfcntr{bonuspointsof@thisquestion}}}%
3137 % See if this has changed from the last run of LaTeX:
3138 \CheckIfChanged@hlf{bonuspointsof@thisquestion}%
3139 {bonuspointsofq@\romannumeral
3140 \csname c@question\endcsname}%
3143 }% End of the second argument of \newenvironment{questions}
3145 % \question@number is used as the label in the question list (instead
3146 % of \questionlabel) so that if the user uses a \qformat command,
3147 % we'll use the \@questionformat specified by the \qformat command:
3149 \def\question@number{%
3152 \makebox[\hsize][s]{\@bonusquestionformat}\hskip-\labelsep
3158 \makebox[\hsize][s]{\@questionformat}\hskip-\labelsep
3164 \newcommand\questionlabel{\thequestion.}
3166 % We want the \part command to be defined *only* inside of a parts
3167 % environment, so that the user can use the standard sectioning \part
3168 % command inside of a questions environment (as long as it's outside of
3169 % a parts environment).
3171 \newenvironment{parts}{%
3172 \def\@queslevel{part}%
3173 % If the question numbers are being inserted via a \qformat,
3174 % and if a question is beginning with a parts environment, then
3175 % we need to enter horizonal mode to get the qformat printed
3176 % on the page, rather than saving up the question label (and
3177 % possible points) to be combined with the label of the first
3178 % part. (\if@inlabel tells us if we are still waiting to enter
3179 % horizontal mode after seeing a \question command.)
3186 % The following is just in case the question had points,
3187 % in which case @placepoints will still be true.
3188 % (We used to do this inside of the \thepoints macro,
3189 % but that allowed for an error if the user specified points for
3190 % a question but had a \qformat that didn't mention \thepoints.)
3191 % We also set @placepoints to be false in the \question command,
3192 % in case one queation follows a previous one that had no parts.
3193 \global \@placepointsfalse
3201 % The following is just in case the question had points,
3202 % in which case @placepoints will still be true.
3203 % (We used to do this inside of the \thepoints macro,
3204 % but that allowed for an error if the user specified points for
3205 % a question but had a \qformat that didn't mention \thepoints.)
3206 % We also set @placepoints to be false in the \question command,
3207 % in case one queation follows a previous one that had no parts.
3208 \global \@placepointsfalse
3221 \cover@question@error
3223 \@checkqueslevel{part}%
3225 % We don't count this part, so no addtocounter{numparts}.
3227 \questionobject@pluspagecheck
3228 \global \pageinfo@commands={}%
3229 % We omit the pagepoint@commands
3232 \addtocounter{numparts}{1}%
3233 % Important: Don't leave any blank lines inside of
3234 % \pageinfo@commands!! This token list will be dumped into
3235 % horizontal mode by \everypar, and so any blank lines will
3236 % cause paragraph breaks.
3238 \edef\@partlabel{part@\arabic{question}@\arabic{partno}}%
3239 \PgInfo@write{\@partlabel}%
3241 % In addition to the \PgInfo@write we use an actual \label
3242 % command. We do this in order to make the question numbers in
3243 % the grade tables into \ref's, so that if the user says
3244 % \usepackage{hyperref}, those question numbers will be clickable.
3246 % A further purpose of these labels (which we actually do for all
3247 % questions, parts, subparts, and subsubparts) is that if a
3248 % question (or part, etc.) is, e.g., moved from one page to
3249 % another, LaTeX will notice this and warn the user that LaTeX
3250 % must be run one more time to be sure everything is correct.
3252 % We need to do this even though we've already included code to
3253 % check when point totals change because questions (and parts,
3254 % etc.) know what page they're on from reading the info written to
3255 % the .aux file on the previous run. Thus, if a question (or
3256 % part, etc.) is moved to a different page, then the pointsonpage
3257 % totals won't notice until the *second* subsequent run of LaTeX,
3258 % and so there'll be no warning to the user on the *first* run.
3259 % Including these labels gives the user a warning on that first
3261 \label{\@partlabel}%
3262 \set@counter@to@pageof{Curr@Page}{\@partlabel}%
3263 \expandafter\ifx\csname Contin@\theCurr@Page\endcsname\relax
3264 \global\expandafter\edef\csname
3265 Contin@\theCurr@Page\endcsname{\arabic{question}}%
3267 \the\pagepoint@commands
3268 \global \pageinfo@commands={}%
3271 \append@toklist \pageinfo@commands \temp@toks
3273 % Remove any skips at the end of the previous paragraph
3274 % that might cause a blank line, and then end that paragraph:
3281 \usecounter{partno}\def\makelabel##1{\hss\llap{##1}}%
3282 \settowidth{\leftmargin}{(m)\hskip\labelsep}%
3283 \labelwidth\leftmargin\advance\labelwidth-\labelsep
3288 }% newenvironment{parts}
3290 \newcommand\partlabel{(\thepartno)}
3291 \def\thepartno{\alph{partno}}
3293 \newenvironment{subparts}{%
3294 \def\@queslevel{subpart}%
3295 \list{\subpartlabel}%
3297 \usecounter{subpart}\def\makelabel##1{\hss\llap{##1}}%
3298 \settowidth{\leftmargin}{vii.\hskip\labelsep}%
3299 \labelwidth\leftmargin\advance\labelwidth-\labelsep
3306 \newcommand\subpartlabel{\thesubpart.}
3307 \def\thesubpart{\roman{subpart}}
3309 \newenvironment{subsubparts}{%
3310 \def\@queslevel{subsubpart}%
3311 \list{\subsubpartlabel}%
3313 \usecounter{subsubpart}\def\makelabel##1{\hss\llap{##1}}%
3314 \settowidth{\leftmargin}{($\psi$)\hskip\labelsep}%
3315 \labelwidth\leftmargin\advance\labelwidth-\labelsep
3322 \newcommand\subsubpartlabel{\thesubsubpart)}
3323 \def\thesubsubpart{\greeknum{subsubpart}}
3328 \pagepoint@commands={%
3329 \ifhlfcntr@pos{latest@points}%
3330 % We're putting a question (or part, etc.)
3331 % with points onto this page:
3332 \ifnum \theCurr@Page > \thepageof@pagepoints\relax
3333 % These points go on a later page than
3334 % the points currently counted in @pagepoints:
3335 \ifnum \thepageof@pagepoints = 0\relax
3338 \immediate\write\@mainaux
3339 {\string\gdef\string\pointsonpage@
3340 \romannumeral \csname c@pageof@pagepoints\endcsname
3341 {\prtaux@hlfcntr{@pagepoints}}}%
3342 % See if this has changed from the last run of LaTeX:
3343 \CheckIfChanged@hlf{@pagepoints}{pointsonpage@\romannumeral
3344 \csname c@pageof@pagepoints\endcsname}%
3346 % The following is a macro because \theCurr@Page and
3347 % \thepageof@pagepoints might differ by more than 1:
3348 \increment@pageof@pagepoints
3349 % The following label is so that we can make the page
3350 % numbers in a grade table indexed by page into \pageref's
3351 % so that \usepackage{hyperref} and pdflatex will
3352 % make them clickable:
3353 \label{firstpoints@onpage@\arabic{Curr@Page}}%
3355 % These points go on the same page as the points
3356 % currently counted in @pagepoints:
3357 \add@hlfcntrtohlfcntr{@pagepoints}{latest@points}%
3358 \set@hlfcntr{latest@points}{0}%
3361 \ifhlfcntr@pos{latest@bonuspoints}%
3362 % We're putting a question (or part, etc.)
3363 % with bonus points onto this page:
3364 \ifnum \theCurr@Page > \thepageof@pagebonuspoints\relax
3365 % These bonus points go on a later page than
3366 % the points currently counted in @pagebonuspoints:
3367 \ifnum \thepageof@pagebonuspoints = 0\relax
3370 \immediate\write\@mainaux
3371 {\string\gdef\string\bonuspointsonpage@
3372 \romannumeral \csname c@pageof@pagebonuspoints\endcsname
3373 {\prtaux@hlfcntr{@pagebonuspoints}}}%
3374 % See if this has changed from the last run of LaTeX:
3375 \CheckIfChanged@hlf{@pagebonuspoints}%
3376 {bonuspointsonpage@\romannumeral
3377 \csname c@pageof@pagebonuspoints\endcsname}%
3379 % The following is a macro because \theCurr@Page and
3380 % \thepageof@pagebonuspoints might differ by more than 1:
3381 \increment@pageof@pagebonuspoints
3382 % The following label is so that we can make the page
3383 % numbers in a bonus grade table indexed by page into \pageref's
3384 % so that \usepackage{hyperref} and pdflatex will
3385 % make them clickable:
3386 \label{firstbonuspoints@onpage@\arabic{Curr@Page}}%
3388 % These points go on the same page as the points
3389 % currently counted in @pagebonuspoints:
3390 \add@hlfcntrtohlfcntr{@pagebonuspoints}{latest@bonuspoints}%
3391 \set@hlfcntr{latest@bonuspoints}{0}%
3394 }% pagepoint@commands
3395 \def\increment@pageof@pagepoints{%
3396 \addtocounter{pageof@pagepoints}{1}%
3397 \ifnum \theCurr@Page > \thepageof@pagepoints\relax
3398 \immediate\write\@mainaux
3399 {\string\gdef\string\pointsonpage@
3400 \romannumeral \csname c@pageof@pagepoints\endcsname{0}}%
3401 % See if this has changed from the last run of LaTeX:
3402 \@ifundefined{pointsonpage@\romannumeral
3403 \csname c@pageof@pagepoints\endcsname}
3404 {\global\@pointschangedtrue}%
3406 % OK; it's defined. See if it's changed:
3408 \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral
3409 \csname c@pageof@pagepoints\endcsname\endcsname}%
3410 \edef\othpt@check{\prtaux@hlfcntr{tmp@hlfcntr}}%
3412 \ifx \pt@check \othpt@check
3415 \global\@pointschangedtrue
3419 \let\next@incr@pageof = \increment@pageof@pagepoints
3421 \copy@hlfcntr{@pagepoints}{latest@points}%
3422 \set@hlfcntr{latest@points}{0}%
3423 % \page@withpoints will be used to find the last
3424 % page that has points, which will be written to
3425 % the .aux file via \AtEndDocument:
3426 \global\edef\page@withpoints{\thepageof@pagepoints}%
3427 \let\next@incr@pageof = \relax
3430 }% increment@pageof@pagepoints
3431 \def\increment@pageof@pagebonuspoints{%
3432 \addtocounter{pageof@pagebonuspoints}{1}%
3433 \ifnum \theCurr@Page > \thepageof@pagebonuspoints\relax
3434 \immediate\write\@mainaux
3435 {\string\gdef\string\bonuspointsonpage@
3436 \romannumeral \csname c@pageof@pagebonuspoints\endcsname{0}}%
3437 % See if this has changed from the last run of LaTeX:
3438 \@ifundefined{bonuspointsonpage@\romannumeral
3439 \csname c@pageof@pagebonuspoints\endcsname}
3440 {\global\@pointschangedtrue}%
3442 % OK; it's defined. See if it's changed:
3444 \set@hlfcntr{tmp@hlfcntr}{\csname bonuspointsonpage@\romannumeral
3445 \csname c@pageof@pagebonuspoints\endcsname\endcsname}%
3446 \edef\othpt@check{\prtaux@hlfcntr{tmp@hlfcntr}}%
3448 \ifx \pt@check \othpt@check
3451 \global\@pointschangedtrue
3455 \let\next@incr@pageof = \increment@pageof@pagebonuspoints
3457 \copy@hlfcntr{@pagebonuspoints}{latest@bonuspoints}%
3458 \set@hlfcntr{latest@bonuspoints}{0}%
3459 % \page@withbonuspoints will be used to find the last
3460 % page that has bonus points, which will be written to
3461 % the .aux file via \AtEndDocument:
3462 \global\edef\page@withbonuspoints{\thepageof@pagebonuspoints}%
3463 \let\next@incr@pageof = \relax
3466 }% increment@pageof@pagebonuspoints
3473 \def\@checkqueslevel#1{%
3476 \ifx\exam@temp\@queslevel
3477 % Everything's fine; do nothing.
3480 I found a #1 where I expected to find a
3481 \@queslevel\MessageBreak
3483 Both #1 and \@queslevel \space can be used only inside the
3484 correct \MessageBreak \space \space
3485 environment and outside of any smaller environment
3492 \def\@doitem{\@ifnextchar[{\@readpoints}%
3493 {\item@points@pageinfo}%
3496 \def\@readpoints[#1]{%
3497 % We use \def for \@points instead of \edef because we don't want
3498 % \half (if present) to be expanded yet, so that the command \points
3499 % can figure out how to deal with it:
3501 \global \@placepointstrue
3504 \addto@hlfcntr{numbonuspoints}{\@points}%
3505 \addto@hlfcntr{bonuspointsof@thisquestion}{\@points}%
3506 % latest@bonuspoints is a holding area for bonus points to be
3507 % added to @pagepoints after we check whether they're
3508 % on the same page as the points currently counted
3510 \addto@hlfcntr{latest@bonuspoints}{\@points}%
3512 \addto@hlfcntr{numpoints}{\@points}%
3513 \addto@hlfcntr{pointsof@thisquestion}{\@points}%
3514 % latest@points is a holding area for points to be
3515 % added to @pagepoints after we check whether they're
3516 % on the same page as the points currently counted
3518 \addto@hlfcntr{latest@points}{\@points}%
3521 \item@points@pageinfo
3527 % Bug fix, 5 April 2004: \item@points@pageinfo
3528 % Appending \point@toks and \pageinfo@commands to \everypar:
3529 % Instead of appending the contents of \point@toks and
3530 % \pageinfo@commands to \everypar using \append@toklist,
3531 % we instead want to append only the two tokens
3533 % and the two tokens
3534 % \the\pageinfo@commands
3535 % to \everypar. We need to do this because if a questions environment
3536 % immediately follows a \section command, then @nobreak will be true,
3537 % and so the \if@nobreak inside of \everypar will *not* execute the
3538 % \everypar={} that we had been counting on to keep the points from
3539 % being inserted a second time in the second paragraph of a question.
3540 % Since we've put the command \global \point@toks={} inside of
3541 % \point@toks and the command \pageinfo@commands={} inside of
3542 % \pageinfo@commands, when the contents of \point@toks and of
3543 % \pageinfo@commands are executed (when we enter horizontal mode and
3544 % \everypar is dumped in), the contents of \point@toks and
3545 % \pageinfo@commands will be made empty, and so if
3546 % the second paragraph also gets \the\point@toks and
3547 % \the\pageinfo@commands, it won't matter.
3549 \def\item@points@pageinfo{%
3551 % Also: We need to do this here, *after* the \item command, rather
3552 % than inside the macro \@readpoints, because the \item command
3553 % puts the result of the \qformat command into an \hbox (with the
3554 % command ``\sbox\@tempboxa{\makelabel{#1}}%''), expanding the
3555 % argument of \qformat as it does so. Thus, @placepoints will be
3556 % true when the argument of \qformat is expanded, and so if the
3557 % user put a \thepoints command inside that argument it will
3558 % correctly expand to the number of points. (When @placepoints is
3559 % false, \thepoints expands to nothing at all).
3561 % We also want to define \padded@point@block when @placepoints is
3562 % true even if qformat and bonusqformat are true just in case the
3563 % user, for some deranged reason, says \droppoints immediately
3564 % following a \question.
3567 % Since we want the user to be able to say \thepoints in the
3568 % argument to a \pointformat command, we need \@placepointstrue
3569 % when \point@block is expanded so that \thepoints will actually
3570 % print something. (After setting up \point@toks, we do
3571 % \@placepointsfalse, but \point@block isn't actually expanded
3572 % until we enter horizontal mode.) Thus, we define
3573 % \padded@point@block, and use that instead of \point@block. We
3574 % put \begingroup and \endgroup around this to confine the
3575 % effect of \@placepointstrue and also to confine the effect of
3576 % any declarations like, e.g., \bfseries that the user might put
3577 % in the argument of a \pointformat command.
3579 % Note: We first tried using an \edef to expand \point@block right
3580 % here, while @placepoints is true, but that causes problems if
3581 % the user puts a \boldmath declaration in the argument of a
3582 % \pointformat command. Apparently, expanding \boldmath (without
3583 % executing anything) gives you bunches of undefined control
3586 \def\padded@point@block{%
3593 \def\padded@point@block{%
3600 % \setup@point@toks puts commands into \point@toks to place
3601 % \padded@point@block at the correct spot. It doesn't append
3602 % anything to \everypar (we do that in this macro, below).
3604 % If @qformat is true, and if we're currently doing a question (or
3605 % if @bonusqformat is true and we're doing a bonusquestion)
3606 % (rather than a part, subpart, or subsubpart), then we don't want
3607 % to set the points (if any), since the points of a question will
3608 % appear only if the user chooses to cause that by putting a
3609 % \thepoints in the argument of the \qformat command.
3615 \ifx\ques@ref\@queslevel
3625 \ifx\ques@ref\@queslevel
3635 \global \@placepointsfalse
3637 % We *don't* use \append@toklist; see the Bug fixnote above
3638 % (Bug fix, 5 April 2004).
3639 % We can append the tokens ``\the\point@toks'' whether or not we're
3640 % setting any points because if we're not setting them, \point@toks
3642 % Also: It's important to do this *after* the \item command above,
3643 % since the \item command discards the previous contents of
3645 % Version 2.218$\beta$, 2007/10/31 changes:
3646 % Instead of appending
3647 % \the \pageinfo@commands \the \point@toks
3648 % to \everypar, we insert them into the box \@labels. This corrects
3649 % the problem that arose when a question (or part, etc.) begins with
3650 % a list environment (including verbatim, flushleft, center,
3651 % flushright, and possibly others that are implemented as trivlist
3652 % environments). The \item command in those environments throws
3653 % away the previous contents of \everypar, and so the tokens \the
3654 % \pageinfo@commands \the \point@toks didn't get inserted where we
3655 % expected. List environments *do* preserve the contents of the box
3657 \global\setbox\@labels\hbox{\unhbox\@labels
3658 \the \pageinfo@commands
3660 % \edef\append@everypar{\noexpand\everypar={\the\everypar
3661 % \noexpand\the \noexpand\pageinfo@commands
3662 % \noexpand\the \noexpand\point@toks}}%
3672 % Initialize \@points:
3673 % (The only reason I think this is necessary is in case the user uses
3674 % a \qformat command, puts \themarginpoints into the format (which is
3675 % *not* the intended use of \themarginpoints), and then doesn't have
3676 % any points for the first question.)
3680 \def\setup@point@toks{%
3681 % We set the token list \point@toks equal to the sequence of commands
3682 % needed to put \padded@point@block at the correct location, followed
3683 % by the tokens ``\global \point@toks={}''. The \question, \part,
3684 % \subpart, or \subsubpart command then adds the two tokens
3685 % ``\the\point@toks'' to \everypar.
3687 % Note: It is not the *contents* of \point@toks that is added to
3688 % \everypar; just the two tokens ``\the\point@toks''. This difference
3689 % is the bug fix of 2 April 2004, described above (the bug was that in
3690 % earlier versions, we used to append the contents).
3692 % The result of this is that whenever we finally enter horizontal mode
3693 % (because we finally encountered the text of a question, part,
3694 % subpart, or subsubpart) the contents of \point@toks will be dumped
3695 % into horizontal mode and executed, and so the points will be placed
3696 % and the token list \point@toks will be set to empty. Thus, in the
3697 % occasional circumstances in which \everypar is *not* set to empty
3698 % after being added to the first paragraph (which occurs when a
3699 % questions environment immediately follows a \section command), and
3700 % so \everypar will still contain ``\the\point@toks'' when it
3701 % encounters a possible second paragraph of the first question, the
3702 % tokens ``\the\point@toks'' will insert an *empty* token list, which
3706 % Set \csname \q@label \endcsname equal to the thing
3707 % that expands to the page number of the current (question or
3708 % part or subpart or subsubpar; whatever it is), but do it
3709 % carefully because, if we don't yet have page info, then it won't
3711 \ifx\@queslevel\ques@ref
3712 \def\q@label{Pg@question@\arabic{question}}
3714 \ifx\@queslevel\part@ref
3715 \def\q@label{Pg@part@\arabic{question}@\arabic{partno}}
3717 \ifx\@queslevel\subpart@ref
3718 \def\q@label{Pg@subpart@\arabic{question}%
3719 @\arabic{partno}@\arabic{subpart}}
3721 \ifx\@queslevel\subsubpart@ref
3722 \def\q@label{Pg@subsubpart@\arabic{question}%
3723 @\arabic{partno}@\arabic{subpart}@\arabic{subsubpart}}
3726 This can't happen in function \protect\setup@point@toks
3729 An unexplained error occurred in exam.cls;\MessageBreak
3730 please inform the package maintainer, and send along
3732 the LaTeX file that shows the error.\MessageBreak
3739 \expandafter\ifx \csname \q@label \endcsname\relax
3740 % No page info yet; put it into the right margin
3741 \@pointsinrightmargintrue
3742 \@pointsinleftmarginfalse
3744 \ifodd \csname \q@label \endcsname\relax
3745 \if@pointsinoutsidemargin
3746 \@pointsinrightmargintrue
3747 \@pointsinleftmarginfalse
3749 \@pointsinrightmarginfalse
3750 \@pointsinleftmargintrue
3753 \if@pointsinoutsidemargin
3754 \@pointsinrightmarginfalse
3755 \@pointsinleftmargintrue
3757 \@pointsinrightmargintrue
3758 \@pointsinleftmarginfalse
3763 % That ends the \if@pointstwosided.
3764 % Now we actually setup \point@toks:
3765 \if@pointsinleftmargin
3767 \llap{\padded@point@block
3768 \hskip\@totalleftmargin
3769 \hskip\marginpointssep
3771 \global \point@toks={}%
3774 \if@pointsinrightmargin
3776 \rlap{\hskip-\@totalleftmargin
3779 \hskip-\rightpointsmargin
3780 \llap{\padded@point@block}%
3782 \global \point@toks={}%
3785 % The points just go after the question number:
3789 \global \point@toks={}%
3796 \leavevmode\unskip\nobreak\hfill
3797 \rlap{\hskip\rightmargin % Defined by the list environment
3798 \hskip\@rightmargin % Defined by exam.cls
3799 \hskip-\rightpointsmargin
3800 \llap{\padded@point@block}%
3805 \def\droptotalpoints{%
3806 \leavevmode\unskip\nobreak\hfill
3807 \rlap{\hskip\rightmargin % Defined by the list environment
3808 \hskip\@rightmargin % Defined by exam.cls
3809 \hskip-\rightpointsmargin
3810 \llap{\total@block}%
3814 \def\droptotalbonuspoints{%
3815 \leavevmode\unskip\nobreak\hfill
3816 \rlap{\hskip\rightmargin % Defined by the list environment
3817 \hskip\@rightmargin % Defined by exam.cls
3818 \hskip-\rightpointsmargin
3819 \llap{\bonustotal@block}%
3822 }% droptotalbonuspoints
3824 % The following is the default definition;
3825 % it can be changed by a \totalformat command.
3827 Total for Question \thequestion: \totalpoints\@marginpointname
3829 \def\bonustotal@block{%
3830 Total for Question \thequestion: \totalbonuspoints\@marginbonuspointname
3833 \def\totalformat#1{%
3834 \gdef\total@block{\begingroup #1\endgroup}%
3836 \def\bonustotalformat#1{%
3837 \gdef\bonustotal@block{\begingroup #1\endgroup}%
3839 % The following is for use in the argument to a \totalformat command:
3840 \def\totalpoints{\pointsofquestion{\arabic{question}}}
3841 \def\totalbonuspoints{\bonuspointsofquestion{\arabic{question}}}
3845 % @placepoints is set true when we encounter a question (or part, etc.)
3846 % that has points. It is set to false (1) when we set \point@toks equal
3847 % to the sequence of commands required to put the properly formatted
3848 % points onto the page (this happens only if @qformat is false or if
3849 % @qformat is true but we're not doing a question), or (2) by a
3850 % \question command or entering a parts environment (since if we're
3851 % doing a question and @qformat is true, we need to leave @placepoints
3852 % true so that the \thepoints command can tell if it should expand to
3853 % points or to nothing, and encountering a \question command or parts
3854 % environment tells us that we no longer have to deal with a possible
3855 % \thepoints, since we won't be expanding a qformat).
3856 \newif\if@placepoints
3860 % \marginpointssep will be used if the user says
3861 % \pointsinleftmargin. It will be the distance from whatever encloses
3862 % the points (parentheses, brackets, or a box) to the left margin:
3863 \newlength\marginpointssep
3864 \setlength{\marginpointssep}{5pt}
3866 % \rightpointsmargin will be used if the user says \pointsinrightmargin.
3867 % It will be the distance from whatever encloses the point (parentheses,
3868 % brackets, or a box) to the right edge of the paper:
3869 \newlength\rightpointsmargin
3870 \setlength{\rightpointsmargin}{1cm}
3873 \newif\if@pointsdropped
3874 \newif\if@pointsinleftmargin
3875 \newif\if@pointsinrightmargin
3876 \newif\if@pointstwosided
3877 \newif\if@pointsinoutsidemargin
3879 % If we have \@pointstwosidedtrue and \@pointsinoutsidemarginfalse,
3880 % then the points will be printed on the inside margin (left on odd
3881 % numbered pages, right on even numbered pages). If we have
3882 % \@pointstwosidedfalse, then \if@pointsinoutsidemargin is ignored.
3884 % If we have \@pointstwosidedtrue, then both \@pointsinleftmargin and
3885 % \@pointsinrightmargin will be flipped back and forth, as needed, in
3886 % \setup@point@toks.
3888 \def\pointsinleftmargin{\global\@pointsinleftmargintrue
3889 \global\@pointsinrightmarginfalse
3890 \global\@pointsdroppedfalse
3891 \global\@pointstwosidedfalse
3892 \gdef\pt@name{\@marginpointname}%
3893 \gdef\bnspt@name{\@marginbonuspointname}}
3894 \def\pointsinrightmargin{\global\@pointsinrightmargintrue
3895 \global\@pointsinleftmarginfalse
3896 \global\@pointsdroppedfalse
3897 \global\@pointstwosidedfalse
3898 \gdef\pt@name{\@marginpointname}%
3899 \gdef\bnspt@name{\@marginbonuspointname}}
3900 \def\nopointsinmargin{\global\@pointsinleftmarginfalse
3901 \global\@pointsinrightmarginfalse
3902 \global\@pointsdroppedfalse
3903 \global\@pointstwosidedfalse
3904 \gdef\pt@name{\@pointname}%
3905 \gdef\bnspt@name{\@bonuspointname}}
3906 \def\pointsdroppedatright{\global\@pointsdroppedtrue
3907 \global\@pointsinleftmarginfalse
3908 \global\@pointsinrightmarginfalse
3909 \global\@pointstwosidedfalse
3910 \gdef\pt@name{\@marginpointname}%
3911 \gdef\bnspt@name{\@marginbonuspointname}}
3912 \def\pointstwosided{\global\@pointstwosidedtrue
3913 \global\@pointsinoutsidemargintrue
3914 \global\@pointsdroppedfalse
3915 \gdef\pt@name{\@marginpointname}%
3916 \gdef\bnspt@name{\@marginbonuspointname}}
3917 \def\pointstwosidedreversed{\global\@pointstwosidedtrue
3918 \global\@pointsinoutsidemarginfalse
3919 \global\@pointsdroppedfalse
3920 \gdef\pt@name{\@marginpointname}%
3921 \gdef\bnspt@name{\@marginbonuspointname}}
3922 \let\pointsinmargin=\pointsinleftmargin
3923 \let\nopointsinrightmargin=\nopointsinmargin
3924 \let\nopointsinleftmargin=\nopointsinmargin
3929 % Will the points be displayed inside parentheses (the default), or
3930 % will they be boxed or bracketed, or customized using pointformat:
3932 \gdef\point@block{\fbox{\@points\pt@name}}%
3933 \gdef\bonuspoint@block{\fbox{\@points\bnspt@name}}%
3935 \def\noboxedpoints{%
3936 \gdef\point@block{(\@points\pt@name)}%
3937 \gdef\bonuspoint@block{(\@points\bnspt@name)}%
3939 \def\bracketedpoints{%
3940 \gdef\point@block{[\@points\pt@name]}%
3941 \gdef\bonuspoint@block{[\@points\bnspt@name]}%
3943 \let\nobracketedpoints=\noboxedpoints
3945 \def\pointformat#1{%
3946 % We don't have to worry about the user putting things
3947 % like \bfseries, etc. into \point@block, because
3948 % \padded@point@block encloses \point@block in a group,
3949 % which confines the effects of anything here:
3950 \gdef\point@block{#1}%
3953 \def\bonuspointformat#1{%
3954 % We don't have to worry about the user putting things
3955 % like \bfseries, etc. into \point@block, because
3956 % \padded@point@block encloses \point@block in a group,
3957 % which confines the effects of anything here:
3958 \gdef\bonuspoint@block{#1}%
3967 \def\pointname#1{\gdef\@pointname{#1}}
3968 \def\bonuspointname#1{\gdef\@bonuspointname{#1}}
3969 % Initialize to leave a space, and then the word `points':
3970 %%\pointname{ points}
3971 % The following improvement was contributed by
3972 % Mate Wierdl <mw@wierdlmpc.msci.memphis.edu>
3973 % If the number of points is ``1'', then the default value of
3974 % \pointname will print `` point'' instead of `` points'' (and this
3975 % version of the command doesn't generate an error message if the
3976 % points entry is something other than a number):
3977 % Note the space before the \points in the following; it's
3979 \pointname{ \points}
3980 \bonuspointname{ \bonuspoints}
3981 \newcommand\point@sing{point}
3982 \newcommand\point@plur{points}
3983 \newcommand\pointpoints[2]{%
3984 \renewcommand\point@sing{#1}%
3985 \renewcommand\point@plur{#2}%
3987 %\newcommand\bonuspoint@sing{bonus point}
3988 %\newcommand\bonuspoint@plur{bonus points}
3989 \newcommand\bonuspoint@sing{point (bonus)}
3990 \newcommand\bonuspoint@plur{points (bonus)}
3991 \newcommand\bonuspointpoints[2]{%
3992 \renewcommand\bonuspoint@sing{#1}%
3993 \renewcommand\bonuspoint@plur{#2}%
3998 % The command \points:
3999 % We use \ifthenelse and \equal so that if the user types something
4000 % other than a legit point value, there still won't be any error
4001 % messages. We rig it so that if the point value looks like it's
4002 % intended to be One or one or ONE, or some strange way of attempting
4003 % one half, then it will expand to the singular value. Alas, this is
4004 % only useful for English, but I'm hoping few or no users will try doing
4007 % 0 points, one half point, 1 point, 1 and a half points, etc.:
4008 \newcommand\points{%
4011 \edef\pt@string{\@points}%
4012 \ifthenelse{\equal{\pt@string}{1} \or \equal{\pt@string}{\half}}
4013 {\point@sing}{\point@plur}%
4016 \newcommand\bonuspoints{%
4019 \edef\pt@string{\@points}%
4020 \ifthenelse{\equal{\pt@string}{1} \or \equal{\pt@string}{\half}}
4021 {\bonuspoint@sing}{\bonuspoint@plur}%
4024 %\newcommand\points{%
4027 % \edef\pt@string{\@points}%
4028 % \ifthenelse{\equal{\pt@string}{1} \or \equal{\pt@string}{\half} \or
4029 % \equal{\pt@string}{0\half} \or \equal{\pt@string}{0 \half}
4030 % \equal{\pt@string}{one} \or \equal{\pt@string}{One} \or
4031 % \equal{\pt@string}{ONE}}
4032 % {\point@sing}{\point@plur}%
4036 %\newcommand\points{\ifthenelse{\equal{\@points}{1}}{\point@sing}{\point@plur}}
4037 % If we used the following line instead, then you'd get an error
4038 % message if the point value contained something other than a valid
4040 %\pointname{ \ifthenelse{\@points = 1}{point}{points}}
4042 % We used to define a command named \marks that works like \points,
4043 % except that it expands to either ``mark'' or ``marks'', but that
4044 % conflicts with some package or other. Thus, we'll implement
4045 % \marksnotpoints using the \pointpoints command instead:
4046 \newcommand\marksnotpoints{%
4047 \pointpoints{mark}{marks}%
4048 \bonuspointpoints{mark (bonus)}{marks (bonus)}%
4052 % \@marginpointname is used in place of \@pointname if any of
4053 % \@pointsinmargin, \@pointsinrightmargin, and \@pointsdropped are
4055 \def\marginpointname#1{\gdef\@marginpointname{#1}}
4057 \def\marginbonuspointname#1{\gdef\@marginbonuspointname{#1}}
4058 \marginbonuspointname{ (bonus)}
4061 %--------------------------------------------------------------------
4062 % choices (for multiple choice) and checkboxes
4065 \renewcommand\thechoice{\Alph{choice}}
4066 \newcommand\choicelabel{\thechoice.}
4068 % We will have \@correctchoicetrue when we're printing solutions
4069 % and we're printing the correct choice of a choices or
4070 % oneparchoices environment.
4071 % We'll say \begingroup before saying \@correctchoicetrue
4072 % and we'll say \endgroup at either the next \choice or \correctchoice
4073 % or the end of the choices or oneparchoices environment.
4074 % Thus, we'll never again need to say \@correctchoicefalse
4075 \newif\if@correctchoice
4076 \@correctchoicefalse
4078 \newcommand\CorrectChoiceEmphasis[1]{%
4079 \def\CorrectChoice@Emphasis{#1}%
4081 \CorrectChoiceEmphasis{\bfseries}
4082 \let\correctchoiceemphasis\CorrectChoiceEmphasis
4084 % Note: \do@choice@pageinfo is used in both the choices and
4085 % the checkboxes environments.
4086 \newtoks\choice@toks
4087 \def\do@choice@pageinfo{%
4089 \questionobject@pluspagecheck
4092 % Version 2.217-beta changes:
4093 % Instead of appending stuff to \everypar, we insert
4094 % \the \pageinfo@commands and \the \point@toks
4095 % into the box \@labels:
4096 \global\setbox\@labels\hbox{\unhbox\@labels
4098 % \edef\append@everypar{\noexpand\everypar={\the\everypar
4099 % \noexpand\the \noexpand\choice@toks}}%
4101 }% do@choice@pageinfo
4105 % Added 22 April 2004: Increased the \leftmargin by 2.5em,
4106 % so the choices will be visibly indented.
4107 \newenvironment{choices}%
4108 {\list{\choicelabel}%
4109 {\usecounter{choice}\def\makelabel##1{\hss\llap{##1}}%
4110 \settowidth{\leftmargin}{W.\hskip\labelsep\hskip 2.5em}%
4119 \def\CorrectChoice{%
4125 % We can't say \choice here, because that would
4126 % insert an \endgroup:
4127 % 2016/05/10: We say \color@begingroup in addition to
4128 % \begingroup in case \CorrectChoiceEmphasis involves color
4129 % and the text exactly fills the line (which would
4130 % otherwise create a blank line after this choice):
4131 % 2016/05/11: We leave hmode if we're in it,
4132 % i.e., if there's no blank line preceding this
4133 % \CorrectChoice command. (Without this, the
4134 % \special created by a \color{whatever} command that might
4135 % be inserted by \CorrectChoice@Emphasis would be appended
4136 % to the previous \choice, which could cause an extra
4137 % (blank) line to be inserted before this \CorrectChoice.)
4138 % Since \par and \endgraf seem to cancel \@totalleftmargin
4139 % (for reasons I don't understand), we'll do the following:
4140 % Motivated by the def of \leavevmode,
4141 % \def\leavevmode{\unhbox\voidb@x}
4142 % we will now leave hmode (if we're in hmode):
4143 \ifhmode \unskip\unskip\unvbox\voidb@x \fi
4144 \begingroup \color@begingroup \@correctchoicetrue
4145 \CorrectChoice@Emphasis
4150 \let\correctchoice\CorrectChoice
4151 \labelwidth\leftmargin\advance\labelwidth-\labelsep
4157 {\if@correctchoice \color@endgroup \endgroup \fi \endlist}
4159 \newenvironment{oneparchoices}%
4161 \setcounter{choice}{0}%
4163 \if@correctchoice \endgroup \fi
4164 \refstepcounter{choice}%
4165 \ifnum\value{choice}>1\relax
4166 \penalty -50\hskip 1em plus 1em\relax
4169 % No need to put the following into a token string; we just put
4170 % the choicelabel onto the page, so we're at the spot whose page
4171 % number we want to record:
4172 \questionobject@pluspagecheck
4175 \def\CorrectChoice{%
4176 \if@correctchoice \endgroup \fi
4177 \refstepcounter{choice}%
4179 \begingroup \@correctchoicetrue
4180 \CorrectChoice@Emphasis
4182 \ifnum\value{choice}>1\relax
4183 \penalty -50\hskip 1em plus 1em\relax
4186 % No need to put the following into a token string; we just put
4187 % the choicelabel onto the page, so we're at the spot whose page
4188 % number we want to record:
4189 \questionobject@pluspagecheck
4192 \let\correctchoice\CorrectChoice
4194 % If we're continuing the paragraph containing the question,
4195 % then leave a bit of space before the first choice:
4196 \ifvmode\else\enskip\fi
4199 {\if@correctchoice \endgroup \fi}
4201 \newcommand{\checkboxchar}[1]{\def\checkbox@char{#1}}
4202 \newcommand{\checkedchar}[1]{\def\checked@char{#1}}
4203 \checkboxchar{$\bigcirc$}
4204 \checkedchar{$\surd$}
4206 \newenvironment{checkboxes}%
4207 {\list{\checkbox@char}%
4209 \settowidth{\leftmargin}{W.\hskip\labelsep\hskip 2.5em}%
4212 \color@endgroup \endgroup
4217 \def\CorrectChoice{%
4219 \color@endgroup \endgroup
4222 % We can't say \choice here, because that would
4223 % insert an \endgroup.
4224 % 2016/05/10: We say \color@begingroup in addition to
4225 % \begingroup in case \CorrectChoiceEmphasis involves color
4226 % and the text exactly fills the line (which would
4227 % otherwise create a blank line after this choice):
4228 % 2016/05/11: We leave hmode if we're in it,
4229 % i.e., if there's no blank line preceding this
4230 % \CorrectChoice command. (Without this, the
4231 % \special created by a \color{whatever} command that might
4232 % be inserted by \CorrectChoice@Emphasis would be appended
4233 % to the previous \choice, which could cause an extra
4234 % (blank) line to be inserted before this \CorrectChoice.)
4235 % Since \par and \endgraf seem to cancel \@totalleftmargin
4236 % (for reasons I don't understand), we'll do the following:
4237 % Motivated by the def of \leavevmode,
4238 % \def\leavevmode{\unhbox\voidb@x}
4239 % we will now leave hmode (if we're in hmode):
4240 \ifhmode \unskip\unskip\unvbox\voidb@x \fi
4241 \begingroup \color@begingroup \@correctchoicetrue
4242 \CorrectChoice@Emphasis
4243 \item[\checked@char]
4249 \let\correctchoice\CorrectChoice
4250 \labelwidth\leftmargin\advance\labelwidth-\labelsep
4256 {\if@correctchoice \color@endgroup \endgroup \fi \endlist}
4258 \newenvironment{oneparcheckboxes}%
4260 % Although we're not printing numbers for the choices, we use the
4261 % choice counter to keep track of whether a choice is the first
4262 % one (in which case we don't leave any additional space) or a
4263 % later one (in which case we do leave additional space):
4264 \setcounter{choice}{0}%
4266 \if@correctchoice \endgroup \fi
4267 \stepcounter{choice}%
4268 \ifnum\value{choice}>1\relax
4269 \penalty -50\hskip 1em plus 1em\relax
4272 % No need to put the following into a token string; we just put
4273 % \checkbox@char onto the page, so we're at the spot whose page
4274 % number we want to record:
4275 \questionobject@pluspagecheck
4278 \def\CorrectChoice{%
4279 \if@correctchoice \endgroup \fi
4280 \stepcounter{choice}%
4282 \begingroup \@correctchoicetrue
4283 \CorrectChoice@Emphasis
4285 \ifnum\value{choice}>1\relax
4286 \penalty -50\hskip 1em plus 1em\relax
4293 % No need to put the following into a token string; we just put
4294 % the choicelabel onto the page, so we're at the spot whose page
4295 % number we want to record:
4296 \questionobject@pluspagecheck
4299 \let\correctchoice\CorrectChoice
4301 % If we're continuing the paragraph containing the question,
4302 % then leave a bit of space before the first choice:
4303 \ifvmode\else\enskip\fi
4306 {\if@correctchoice \endgroup \fi}
4309 %--------------------------------------------------------------------
4310 % Answer Lines (for short answer questions)
4312 % Note: \ques@ref is also used in \item@points@pageinfo, and all four
4313 % of the following are used in \setup@point@toks
4315 \def\ques@ref{question}
4317 \def\subpart@ref{subpart}
4318 \def\subsubpart@ref{subsubpart}
4320 % Note: \answerclearance is also used by \fillin
4322 \newlength\answerlinelength
4323 \newlength\answerskip
4324 \newlength\answerclearance
4325 \setlength\answerlinelength{1in}
4326 \setlength\answerskip{2ex}
4327 \setlength\answerclearance{0.2ex}
4329 \newcommand\answerline[1][{}]{%
4330 % One optional argument, the default value of which is empty.
4331 \ifx\@queslevel\ques@ref
4332 \let\ans@l=\questionlabel
4334 \ifx\@queslevel\part@ref
4335 \let\ans@l=\partlabel
4337 \ifx\@queslevel\subpart@ref
4338 \let\ans@l=\subpartlabel
4340 \ifx\@queslevel\subsubpart@ref
4341 \let\ans@l=\subsubpartlabel
4343 % Oops; no question level defined.
4344 % We must be outide of the questions environment.
4345 % Just leave out the label, I guess:
4351 \par \nobreak \vskip \answerskip
4354 \ans@l~\hbox to 0pt{\hbox to \answerlinelength{\hrulefill}\hss}%
4355 \raise \answerclearance\hbox to \answerlinelength{%
4356 % 2016/05/10: Added \color@begingroup and \color@endgroup:
4358 \CorrectChoice@Emphasis \hfil #1\hss
4361 \ans@l~\hbox to \answerlinelength{\hrulefill}%
4366 %--------------------------------------------------------------------
4367 % \fillin, for fill-in-the-blank questions
4369 \newlength\fillinlinelength
4370 \setlength\fillinlinelength{1in}
4372 % \fillin can take two optional arguments.
4374 % The first optional argument is the answer to be printed above the line
4375 % when \printanswers is in effect; the default value is empty. That
4376 % line is printed a distance of \answerclearance below the baseline.
4378 % The second optional argument is the length of the line that we print;
4379 % the default value is \fillinlinelength. The value of
4380 % \fillinlinelength is set with the command
4382 % \setlength\fillinlinelength{1in}
4384 % and can be changed by giving a new \setlength command.
4386 % When answers are being printed, the optional argument is printed
4387 % subject to the declarations in the argument of the last
4388 % \CorrectChoiceEmphasis command. It is centered on the line unless it
4389 % is too long, in which case it extends to the right of the line.
4391 % \fillin eats (and ignores) space characters appearing before the
4392 % first optional argument. It also eats (and ignores) space
4393 % characters appearing after the first optional argument and before
4394 % the second optional argument. However, if exactly one optional
4395 % argument appears, and if there are one or more space characters
4396 % following that one optional argument, then those spaces are replaced
4397 % by a single space character, but not eaten.
4399 \newcommand\fillin[1][{}]{%
4400 \def\fillin@ans{#1}%
4404 \newcommand\fillin@relay{%
4405 % We use \exam@ifnextchar, a variation on \@ifnextchar.
4406 % If \exam@ifnextchar encounters one or more space characters
4407 % followed by a [, then those spaces are ignored (just as they would
4408 % be by \@ifnextchar). However, if one or more space characters are
4409 % followed by a non-space character other than [, then
4410 % \exam@ifnextchar inserts a space following the
4411 % {\@fillin@relay[\fillinlinelength]} that is the third argument to
4413 \exam@ifnextchar[{\@fillin@relay}
4414 {\@fillin@relay[\fillinlinelength]}%
4417 \def\@fillin@relay[#1]{%
4418 % The first argument is in \fillin@ans, the second is #1.
4421 \rlap{\raise -\answerclearance \hbox to #1{\hrulefill}}%
4423 \setbox0 \hbox{\color@begingroup
4424 \CorrectChoice@Emphasis \fillin@ans \color@endgroup}%
4425 \ifdim\wd0 > #1\relax
4426 \hbox{\color@begingroup\CorrectChoice@Emphasis \fillin@ans
4429 \hbox to #1{\color@begingroup\CorrectChoice@Emphasis
4430 \hfil \fillin@ans \hfil\color@endgroup}%
4434 \raise -\answerclearance \hbox to #1{\hrulefill}%
4438 % \exam@ifnextchar is used by \fillin.
4439 % \exam@ifnextchar is a variation of \@ifnextchar that does not always
4440 % ignore space tokens. If \exam@ifnextchar encounters one or more
4441 % space tokens, it makes note of that (with the command
4442 % \@tempswatrue). If the first non-space character encountered
4443 % matches argument #1, then any spaces that had been encountered are
4444 % ignored. However, if one or more spaces are encountered and the
4445 % first non-space character found does not match argument #1, then
4446 % \exam@ifnextchar produces argument #3 followed by a space character.
4447 % (This differs from the behavior of \new@ifnextchar in amsgen.sty,
4448 % which does lookahead for any character, including a space.) This
4449 % code (as well as the idea for it) is due to Dan Luecking and Ulrich
4451 \long\def\exam@ifnextchar#1#2#3{%
4453 \def\reserved@a{#2}%
4454 \def\reserved@b{#3}%
4455 % The following says we haven't yet seen any spaces:
4457 \futurelet\@let@token\exam@ifnch
4461 \ifx\@let@token\@sptoken
4462 % Signal that we've found a space:
4464 \let\reserved@c\exam@xifnch % this gobbles the space
4466 \ifx\@let@token\reserved@d
4467 \let\reserved@c\reserved@a
4470 \def\reserved@c{\expandafter\reserved@b\space}%
4472 \let\reserved@c\reserved@b
4479 % The following defines \exam@xifnch so that it will eat a space
4480 % following it and then call \exam@ifnch:
4481 {% keep redefinition of \: local
4482 \def\:{\exam@xifnch}
4483 \expandafter\gdef\: {\futurelet\@let@token\exam@ifnch}
4486 %--------------------------------------------------------------------
4490 % \fillwithlines takes one argument, which is either a length or \fill
4491 % or \stretch{number}, and it fills that much vertical space with
4492 % horizontal lines that run the length of the current line. That is,
4493 % they extend from the current left margin (which depends on whether
4494 % we're in a question, part, subpart, or subsubpart) to the right
4497 % The distance between the lines is \linefillheight, whose default value
4498 % is set with the command
4500 % \setlength\linefillheight{.25in}
4502 % This value can be changed by giving a new \setlength command.
4504 % The thickness of the lines is \linefillthickness, whose default value
4505 % is set with the command
4507 % \setlength\linefillthickness{.1pt}
4509 % This value can be changed by giving a new \setlength command.
4511 % As of version 2.503, 2016/03/25, the lines drawn by the
4512 % \fillwithlines command will be drawn in color if the user has given
4515 % \colorfillwithlines.
4517 % The actual drawing of the lines is now done by the command
4518 % \do@fillwithlines, after the \fillwithlines command decides whether
4519 % they will be in color. The default color is set by the command
4521 % \definecolor{FillWithLinesColor}{gray}{0.8}
4523 % and the color can be changed by giving a new \definecolor command.
4524 % You can return to black lines by giving the command
4526 % \nocolorfillwithlines
4528 \newlength\linefillheight
4529 \newlength\linefillthickness
4530 \setlength\linefillheight{.25in}
4531 \setlength\linefillthickness{0.1pt}
4536 \newif\if@colorfillwithlines
4537 \@colorfillwithlinesfalse
4538 \def\colorfillwithlines{%
4539 \@ifundefined{definecolor}
4542 You must load the color package with the command\MessageBreak
4543 \space\space\protect\usepackage{color}\MessageBreak
4544 in order to use the command \protect\colorfillwithlines
4547 This command makes use of the package color.sty,\MessageBreak
4548 and so you have to load color.sty before your\MessageBreak
4549 \protect\begin{document} command.\MessageBreak
4553 \definecolor{FillWithLinesColor}{gray}{0.8}
4554 \@colorfillwithlinestrue
4556 }% \colorfillwithlines
4557 \def\nocolorfillwithlines{\@colorfillwithlinesfalse}
4559 \newcommand\fillwithlines[1]{%
4560 \if@colorfillwithlines
4562 \color{FillWithLinesColor}%
4563 \do@fillwithlines{#1}%
4566 \do@fillwithlines{#1}%
4570 \newcommand\linefill{\leavevmode
4571 \leaders\hrule height \linefillthickness \hfill\kern\z@}
4573 % \do@fillwithlines is called only by \fillwithlines
4574 \def\do@fillwithlines#1{%
4581 \setbox0=\hbox to \hsize{\hskip \@totalleftmargin
4582 \vrule height \linefillheight depth \z@ width \z@
4584 % We use \cleaders (rather than \leaders) so that a given
4585 % vertical space will always produce the same number of lines
4586 % no matter where on the page it happens to start:
4587 \cleaders \copy0 \vskip #1 \hbox{}%
4589 }% \do@fillwithlines
4591 %--------------------------------------------------------------------
4592 % \fillwithdottedlines
4595 % \fillwithdottedlines is similar to \fillwithlines, except that it
4596 % fills the space with dotted lines (created by \dotfill) rather than
4599 % \fillwithdottedlines takes one argument, which is either a length or
4600 % \fill or \stretch{number}, and it fills that much vertical space
4601 % with dotted lines that run the length of the current line. That is,
4602 % they extend from the current left margin (which depends on whether
4603 % we're in a question, part, subpart, or subsubpart) to the right
4606 % The distance between the lines is \dottedlinefillheight, whose
4607 % default value is set with the command
4609 % \setlength\dottedlinefillheight{.25in}
4611 % This value can be changed by giving a new \setlength command.
4613 % As of version 2.503, 2016/03/25, the dotted lines drawn by the
4614 % \fillwithdottedlines command will be drawn in color if the user has
4617 % \colorfillwithdottedlines.
4619 % The actual drawing of the lines is now done by the command
4620 % \do@fillwithdottedlines, after the \fillwithdottedlines command
4621 % decides whether they will be in color. The default color is set by
4624 % \definecolor{FillWithDottedLinesColor}{gray}{0.8}
4626 % and the color can be changed by giving a new \definecolor command.
4627 % You can return to black lines by giving the command
4629 % \nocolorfillwithdottedlines
4632 \newlength\dottedlinefillheight
4633 \setlength\dottedlinefillheight{.25in}
4635 \newif\if@colorfillwithdottedlines
4636 \@colorfillwithdottedlinesfalse
4637 \def\colorfillwithdottedlines{%
4638 \@ifundefined{definecolor}
4641 You must load the color package with the command\MessageBreak
4642 \space\space\protect\usepackage{color}\MessageBreak
4643 in order to use the command \protect\colorfillwithdottedlines
4646 This command makes use of the package color.sty,\MessageBreak
4647 and so you have to load color.sty before your\MessageBreak
4648 \protect\begin{document} command.\MessageBreak
4652 \definecolor{FillWithDottedLinesColor}{gray}{0.8}
4653 \@colorfillwithdottedlinestrue
4655 }% \colorfillwithdottedlines
4656 \def\nocolorfillwithdottedlines{\@colorfillwithdottedlinesfalse}
4658 \newcommand\fillwithdottedlines[1]{%
4659 \if@colorfillwithdottedlines
4661 \color{FillWithDottedLinesColor}%
4662 \do@fillwithdottedlines{#1}%
4665 \do@fillwithdottedlines{#1}%
4667 }% \fillwithdottedlines
4669 % \do@fillwithdottedlines is called only by \fillwithdottedlines
4670 \def\do@fillwithdottedlines#1{%
4677 \setbox0=\hbox to \hsize{\hskip \@totalleftmargin
4678 \vrule height \dottedlinefillheight depth \z@ width \z@
4680 % We use \cleaders (rather than \leaders) so that a given
4681 % vertical space will always produce the same number of lines
4682 % no matter where on the page it happens to start:
4683 \cleaders \copy0 \vskip #1 \hbox{}%
4685 }% \do@fillwithdottedlines
4687 %--------------------------------------------------------------------
4691 % \fillwithgrid is similar to \fillwithlines, except that it
4692 % fills the space with a grid.
4694 % \fillwithgrid takes one argument, which is either a length or \fill
4695 % or \stretch{number}, and it fills that much vertical space with a
4696 % grid that runs the length of the current line. That is, it extends
4697 % from the current left margin (which depends on whether we're in a
4698 % question, part, subpart, or subsubpart) to the right margin.
4700 % The default grid size and grid line thickness were set by the
4703 % \setlength{\gridsize}{5mm}
4704 % \setlength{\gridlinewidth}{0.1pt}
4706 % You can change either or both of those by giving new \setlength
4707 % commands. The period of the grid is \gridsize (both horizontally
4708 % and vertically). That is, the horizontal distance from the left
4709 % edge of one vertical line to the left edge of the next vertical line
4710 % is \gridsize, as is the vertical distance from the top edge of one
4711 % horizontal line to the top edge of the next horizontal line. Thus,
4712 % each square has outer side length equal to \gridsize+\gridlinewidth.
4714 % By default, the created grids are in black. However, if you give the
4717 % \usepackage{color}
4720 % then the grids will be in color, by default a light gray. That
4721 % default color was defined by the command
4723 % \definecolor{GridColor}{gray}{0.8}
4725 % You can change the color by redefining the color GridColor by giving
4726 % a new \definecolor command.
4728 \newif\if@colorgrids
4729 \newcommand\colorgrids{%
4730 \@ifundefined{definecolor}
4733 You must load the color package with the command\MessageBreak
4734 \space\space\protect\usepackage{color}\MessageBreak
4735 in order to use the command \protect\colorgrids
4737 This command makes use of the package color.sty,\MessageBreak
4738 and so you have to load color.sty before your\MessageBreak
4739 \protect\begin{document} command.\MessageBreak
4743 \definecolor{GridColor}{gray}{0.8}
4747 \newcommand\nocolorgrids{\@colorgridsfalse}
4751 \newlength\gridlinewidth
4752 \setlength{\gridsize}{5mm}
4753 \setlength{\gridlinewidth}{0.1pt}
4755 \def\fillwithgrid#1{%
4763 % We first set box0 equal to an \hbox which, when printed, is a
4764 % square with width and height equal to \gridsize+\gridlinewidth,
4766 % width equal to \gridsize,
4767 % height equal to \gridsize, and
4768 % depth equal to 0pt.
4769 % When we put multiple copies of it together using \leaders or
4770 % \cleaders, the right edge will coincide with the left edge of the
4771 % next box and the bottom edge will coincide with the top edge of
4773 \setlength{\@tempdima}{\gridsize}
4774 \addtolength{\@tempdima}{\gridlinewidth}
4775 \setlength{\@tempdimb}{\gridsize}
4776 \addtolength{\@tempdimb}{-\gridlinewidth}
4778 \rlap{\vrule height \gridsize depth \gridlinewidth width \gridlinewidth}%
4779 \rlap{\vrule height \gridsize depth -\@tempdimb width \@tempdima}%
4780 \vrule height 0pt depth \gridlinewidth width \@tempdima
4781 \llap{\vrule height \gridsize depth \gridlinewidth width \gridlinewidth}%
4785 % Now we set box1 equal to an \hbox containing a single line of
4786 % copies of box0. We use \leaders (instead of \cleaders) so that
4787 % if we use it twice on a page, once with a question and once
4788 % with a part, the boxes will line up vertically. We add a kern of
4789 % \gridlinewidth at the right because the rightmost vertical line
4790 % appears to the right of where the \leaders command thinks that it
4792 \setbox1=\hbox to \textwidth{%
4797 \hskip \@totalleftmargin \leaders\copy0\hfil \kern\gridlinewidth
4800 % Finally: We create the grid, using \cleaders: We use \cleaders
4801 % (rather than \leaders) so that a given vertical space will always
4802 % produce the same number of lines no matter where on the page it
4803 % happens to start. We add a kern of \gridlinewidth because the
4804 % bottommost horizontal line appears below where the \cleaders
4805 % command thinks that it appears.
4806 \cleaders \copy1 \vskip #1 \kern \gridlinewidth \hbox{}%
4810 %--------------------------------------------------------------------
4813 % \makeemptybox takes one argument, which is a length, and it creates
4814 % an empty box of width the length of the current line and of height
4815 % equal to the argument. That is, the box extends from the current
4816 % left margin (which depends on whether we're in a question, part,
4817 % subpart, or subsubpart) to the right margin.
4819 % As of version 2.304, the argument of \makeemptybox can be either
4820 % a length, or \fill, or \stretch{number}.
4822 % \newcommand\makeemptybox[1]{
4825 % \setlength{\fboxsep}{0pt}%
4826 % \framebox[\linewidth]{%
4827 % \vrule height 0pt depth #1 width 0pt
4832 \newlength\minboxheight
4833 \setlength\minboxheight{.1in}
4836 % As of version 2.502, 2016/03/23, the frame drawn by the
4837 % \makeemptybox command will be drawn in color if the user has given
4838 % the command \colorsolutionboxes. The actual drawing of the box is
4839 % now done by the command \do@emptybox, after the \makeemptybox
4840 % command decides whether it will be in color.
4842 \newcommand\makeemptybox[1]{%
4843 \if@colorsolutionboxes
4845 \color{SolutionBoxColor}%
4853 % The command \do@emptybox is called only by \makeemptybox.
4854 \newcommand\do@emptybox[1]{%
4856 \hbox to \hsize{\hskip\@totalleftmargin \leaders\hrule\hfill}%
4859 \setbox0=\hbox to \hsize{\hskip\@totalleftmargin
4860 \vrule height\minboxheight \hfill \vrule}%
4861 % The vertical size desired may not be an exact multiple of
4862 % \minboxheight, and so \cleaders might leave a gap between the
4863 % vertical lines and the horizontal lines above and below it.
4864 % Thus, we put a single copy of \box0 immediately below the
4865 % horizontal line above and we'll also put a single copy of \box0
4866 % immediately above the horizontal line below.
4869 \vskip -\minboxheight
4870 \cleaders \copy0 \vskip #1
4871 \vskip -\minboxheight
4876 \hbox to \hsize{\hskip\@totalleftmargin \leaders\hrule\hfill}%
4879 %--------------------------------------------------------------------
4880 % \uplevel and \fullwidth
4881 % and the EnvUplevel and EnvFullwidth environments:
4883 % \uplevel is used to print text at the indentation level of the
4884 % enclosing environment. For example, to precede a question with
4885 % directions about how that question should be answered, you would
4886 % say \uplevel{Answer this question correctly.}
4888 % \fullwidth is similar, but uses the full page of text on the page.
4890 % The EnvUplevel environment is similar to the \uplevel command, but it
4891 % has the advantage that you can include verbatim material (using, e.g.,
4892 % the \verb command) in the environment. (You can't include verbatim
4893 % material in the argument of an \uplevel command.)
4895 % The EnvFullwidth environment is similar to the \fullwidth command, but
4896 % it has the advantage that you can include verbatim material (using,
4897 % e.g., the \verb command) in the environment. (You can't include
4898 % verbatim material in the argument of an \fullwidth command.)
4901 \long\def\uplevel#1{%
4904 % We entered internal vertical mode, and so we get \parshape=0.
4905 % We set \leftskip to provide the correct left margin for whatever
4906 % is in the argument of the \uplevel command:
4907 \leftskip=\@totalleftmargin
4908 \advance\leftskip-\leftmargin
4909 % We adjust \@totalleftmargin and linewidth in case there's a
4910 % solution environment inside of the argument to the \uplevel:
4911 \advance\@totalleftmargin-\leftmargin
4912 \advance\linewidth\leftmargin
4918 \newenvironment{EnvUplevel}
4919 {\par\bigskip\vbox\bgroup
4920 % We set \leftskip to provide the correct left margin for whatever
4921 % is inside of the environment:
4922 \leftskip=\@totalleftmargin
4923 \advance\leftskip-\leftmargin
4924 % We adjust \@totalleftmargin (and linewidth?) in case there's a
4925 % solution environment inside of the environment:
4926 \advance\@totalleftmargin-\leftmargin
4927 \advance\linewidth\leftmargin
4932 \long\def\fullwidth#1{%
4935 % We entered internal vertical mode, and so we get \parshape=0.
4936 \leftskip=0pt \rightskip=0pt
4937 \advance\linewidth\@totalleftmargin
4938 \@totalleftmargin=0pt
4944 \newenvironment{EnvFullwidth}
4945 {\par\bigskip\vbox\bgroup
4946 % We entered internal vertical mode, and so we get \parshape=0.
4947 \leftskip=0pt \rightskip=0pt
4948 % We adjust \@totalleftmargin (and linewidth?) in case there's a
4949 % solution environment inside of the environment:
4950 \advance\linewidth\@totalleftmargin
4951 \@totalleftmargin=0pt
4956 %--------------------------------------------------------------------
4957 %--------------------------------------------------------------------
4959 % ********************
4960 % ** GRADING TABLES **
4961 % ********************
4965 \newcounter{@iterator}
4966 \newlength\@cellwidth
4968 \def\cellwidth#1{\@cellwidth=#1}
4969 \def\gradetablestretch#1{\def\@gtblstretch{#1}}
4971 % \settabletotalpoints allows the user to specify a total
4972 % number of points to appear in a table that may be different
4973 % from the sum of the points in the table:
4974 \newcommand\prt@tablepoints{\prt@hlfcntr{tbl@points}}
4975 \newcommand\settabletotalpoints[1]{%
4976 \def\prt@tablepoints{#1}%
4977 }% \settabletotalpoints
4979 % \settabletotalbonuspoints is similar to \settabletotalpoints:
4980 \newcommand\prt@tablebonuspoints{\prt@hlfcntr{tbl@bonuspoints}}
4981 \newcommand\settabletotalbonuspoints[1]{%
4982 \def\prt@tablebonuspoints{#1}%
4983 }% \settabletotalbonuspoints
4985 % All of the following that begin with `h' are for horizontal tables,
4986 % and all of them that begin with `v' are for vertical tables:
4987 \def\hqword#1{\def\@hqword{#1}}
4988 \def\hpword#1{\def\@hpword{#1}}
4989 \def\hsword#1{\def\@hsword{#1}}
4990 \def\htword#1{\def\@htword{#1}}
4991 \def\hpgword#1{\def\@hpgword{#1}}
4993 \def\vqword#1{\def\@vqword{#1}}
4994 \def\vpword#1{\def\@vpword{#1}}
4995 \def\vsword#1{\def\@vsword{#1}}
4996 \def\vtword#1{\def\@vtword{#1}}
4997 \def\vpgword#1{\def\@vpgword{#1}}
5000 % The following are the versions for bonusgradetable:
5001 \def\bhqword#1{\def\@bhqword{#1}}
5002 \def\bhpword#1{\def\@bhpword{#1}}
5003 \def\bhsword#1{\def\@bhsword{#1}}
5004 \def\bhtword#1{\def\@bhtword{#1}}
5005 \def\bhpgword#1{\def\@bhpgword{#1}}
5007 \def\bvqword#1{\def\@bvqword{#1}}
5008 \def\bvpword#1{\def\@bvpword{#1}}
5009 \def\bvsword#1{\def\@bvsword{#1}}
5010 \def\bvtword#1{\def\@bvtword{#1}}
5011 \def\bvpgword#1{\def\@bvpgword{#1}}
5013 % The following are the versions for combinedgradetable:
5014 \def\chqword#1{\def\@chqword{#1}}
5015 \def\chpword#1{\def\@chpword{#1}}
5016 \def\chbpword#1{\def\@chbpword{#1}}
5017 \def\chsword#1{\def\@chsword{#1}}
5018 \def\chtword#1{\def\@chtword{#1}}
5019 \def\chpgword#1{\def\@chpgword{#1}}
5021 \def\cvqword#1{\def\@cvqword{#1}}
5022 \def\cvpword#1{\def\@cvpword{#1}}
5023 \def\cvbpword#1{\def\@cvbpword{#1}}
5024 \def\cvsword#1{\def\@cvsword{#1}}
5025 \def\cvtword#1{\def\@cvtword{#1}}
5026 \def\cvpgword#1{\def\@cvpgword{#1}}
5032 \gradetablestretch{1.5}
5047 \bhpword{Bonus Points:}
5052 \bvpword{Bonus Points}
5059 \chbpword{Bonus Points:}
5065 \cvbpword{Bonus Points}
5069 % Before we created multirow and multicolumn tables, he only commands
5070 % here accessible to the user were \gradetable, \bonusgradetable,
5071 % \combinedgradetable, \pointtable, \bonuspointtable,
5072 % \combinedpointtable, \partialgradetable,
5073 % \partialbonusgradetable, \partialcombinedtable, \partialpointtable,
5074 % \partialbonuspointtable, \partialcombinedpointtable,
5075 % \begingradingrange, \endgradingrange, \pointsinrange,
5076 % \bonuspointsinrange, \firstqinrange, \lastqinrange, and
5077 % \numqinrange. The new user commands are
5079 % \def\multirowgradetable
5080 % \def\multirowpointtable
5081 % \def\multirowbonusgradetable
5082 % \def\multirowbonuspointtable
5083 % \def\multirowcombinedgradetable
5084 % \def\multirowcombinedpointtable
5086 % \def\multirowpartialgradetable
5087 % \def\multirowpartialpointtable
5088 % \def\multirowpartialbonusgradetable
5089 % \def\multirowpartialbonuspointtable
5090 % \def\multirowpartialcombinedgradetable
5091 % \def\multirowpartialcombinedpointtable
5093 % \def\multicolumngradetable
5094 % \def\multicolumnpointtable
5095 % \def\multicolumnbonusgradetable
5096 % \def\multicolumnbonuspointtable
5097 % \def\multicolumncombinedgradetable
5098 % \def\multicolumncombinedpointtable
5100 % \def\multicolumnpartialgradetable
5101 % \def\multicolumnpartialpointtable
5102 % \def\multicolumnpartialbonusgradetable
5103 % \def\multicolumnpartialbonuspointtable
5104 % \def\multicolumnpartialcombinedgradetable
5105 % \def\multicolumnpartialcombinedpointtable
5108 % The possibilities are
5110 % \gradetable[v][questions]
5111 % \gradetable[v][pages]
5112 % \gradetable[h][questions]
5113 % \gradetable[h][pages]
5115 % \bonusgradetable[v][questions]
5116 % \bonusgradetable[v][pages]
5117 % \bonusgradetable[h][questions]
5118 % \bonusgradetable[h][pages]
5120 % \combinedgradetable[v][questions]
5121 % \combinedgradetable[v][pages]
5122 % \combinedgradetable[h][questions]
5123 % \combinedgradetable[h][pages]
5125 % \pointtable[v][questions]
5126 % \pointtable[v][pages]
5127 % \pointtable[h][questions]
5128 % \pointtable[h][pages]
5130 % \bonuspointtable[v][questions]
5131 % \bonuspointtable[v][pages]
5132 % \bonuspointtable[h][questions]
5133 % \bonuspointtable[h][pages]
5135 % \combinedpointtable[v][questions]
5136 % \combinedpointtable[v][pages]
5137 % \combinedpointtable[h][questions]
5138 % \combinedpointtable[h][pages]
5140 % \partialgradetable{whatever}[v][questions]
5141 % \partialgradetable{whatever}[v][pages]
5142 % \partialgradetable{whatever}[h][questions]
5143 % \partialgradetable{whatever}[h][pages]
5145 % \partialbonusgradetable{whatever}[v][questions]
5146 % \partialbonusgradetable{whatever}[v][pages]
5147 % \partialbonusgradetable{whatever}[h][questions]
5148 % \partialbonusgradetable{whatever}[h][pages]
5150 % \partialcombinedgradetable{whatever}[v][questions]
5151 % \partialcombinedgradetable{whatever}[v][pages]
5152 % \partialcombinedgradetable{whatever}[h][questions]
5153 % \partialcombinedgradetable{whatever}[h][pages]
5155 % \partialpointtable{whatever}[v][questions]
5156 % \partialpointtable{whatever}[v][pages]
5157 % \partialpointtable{whatever}[h][questions]
5158 % \partialpointtable{whatever}[h][pages]
5160 % \partialbonuspointtable{whatever}[v][questions]
5161 % \partialbonuspointtable{whatever}[v][pages]
5162 % \partialbonuspointtable{whatever}[h][questions]
5163 % \partialbonuspointtable{whatever}[h][pages]
5165 % \partialcombinedpointtable{whatever}[v][questions]
5166 % \partialcombinedpointtable{whatever}[v][pages]
5167 % \partialcombinedpointtable{whatever}[h][questions]
5168 % \partialcombinedpointtable{whatever}[h][pages]
5170 % \begingradingrange{whatever}
5171 % \endgradingrange{whatever}
5173 % \pointsinrange{whatever}
5174 % \bonuspointsinrange{whatever}
5176 % \firstqinrange{whatever}
5177 % \lastqinrange{whatever}
5178 % \numqinrange{whatever}
5180 % where ``whatever'' is a label chosen by the user.
5182 % \def\multirowgradetable{numcols}[questions or pages]
5183 % \def\multirowpointtable{numcols}[questions or pages]
5184 % \def\multirowbonusgradetable{numcols}[questions or pages]
5185 % \def\multirowbonuspointtable{numcols}[questions or pages]
5186 % \def\multirowcombinedgradetable{numcols}[questions or pages]
5187 % \def\multirowcombinedpointtable{numcols}[questions or pages]
5189 % \def\multirowpartialgradetable{numcols}{rangename}[questions or pages]
5190 % \def\multirowpartialpointtable{numcols}{rangename}[questions or pages]
5191 % \def\multirowpartialbonusgradetable{numcols}{rangename}[questions or pages]
5192 % \def\multirowpartialbonuspointtable{numcols}{rangename}[questions or pages]
5193 % \def\multirowpartialcombinedgradetable{numcols}{rangename}[questions or pages]
5194 % \def\multirowpartialcombinedpointtable{numcols}{rangename}[questions or pages]
5196 % \def\multicolumngradetable{numrows}[questions or pages]
5197 % \def\multicolumnpointtable{numrows}[questions or pages]
5198 % \def\multicolumnbonusgradetable{numrows}[questions or pages]
5199 % \def\multicolumnbonuspointtable{numrows}[questions or pages]
5200 % \def\multicolumncombinedgradetable{numrows}[questions or pages]
5201 % \def\multicolumncombinedpointtable{numrows}[questions or pages]
5203 % \def\multicolumnpartialgradetable{numrows}{rangename}[questions or pages]
5204 % \def\multicolumnpartialpointtable{numrows}{rangename}[questions or pages]
5205 % \def\multicolumnpartialbonusgradetable{numrows}{rangename}[questions or pages]
5206 % \def\multicolumnpartialbonuspointtable{numrows}{rangename}[questions or pages]
5207 % \def\multicolumnpartialcombinedgradetable{numrows}{rangename}[questions or pages]
5208 % \def\multicolumnpartialcombinedpointtable{numrows}{rangename}[questions or pages]
5211 % If one or both optional arguments are omitted, the defaults are
5212 % `[v]' and `[questions]'.
5214 % \@scorestrue means we're doing \gradetable
5215 % \@scoresfalse mans we're doing \pointtable
5218 % \@partialtrue means we're doing \partialgradetable,
5219 % \partialbonusgradetable, \partialcombinedgradetable,
5220 % \partialpointtable, \partialbonuspointtable, or
5221 % \partialcombinedpointtable:
5224 % \@combinedtrue means we're doing \combinedgradetable,
5225 % \combinedpointtable, \partialcombinedgradetable, or
5226 % \partialcombinedpointtable:
5229 % It's OK to use the counter num@cols as a scratch counter
5230 % in \begingradingrange and \endgradingrange because
5231 % it's only used in typesetting tables:
5232 \def\begingradingrange#1{%
5233 \setcounter{num@cols}{\value{question}}%
5234 \addtocounter{num@cols}{1}%
5235 \immediate\write\@mainaux
5236 {\string\expandafter\string\gdef
5237 \string\csname\space range@#1@firstq\string\endcsname
5238 {\arabic{num@cols}}}%
5240 {\string\expandafter\string\gdef
5241 \string\csname\space range@#1@firstp\string\endcsname
5243 }% begingradingrange
5245 \def\endgradingrange#1{%
5246 \setcounter{num@cols}{\value{question}}%
5247 \immediate\write\@mainaux
5248 {\string\expandafter\string\gdef
5249 \string\csname\space range@#1@lastq\string\endcsname
5250 {\arabic{num@cols}}}%
5252 {\string\expandafter\string\gdef
5253 \string\csname\space range@#1@lastp\string\endcsname
5258 % Now that grading tables may be for only part of the exam,
5259 % we need the counter tbl@points to add up the total points
5260 % for the questions (or pages) that appear on the table:
5261 \new@hlfcntr{tbl@points}
5263 % We'll use the counter tbl@bonuspoints to add up the total bonus
5264 % points for the questions (or pages) that appear on the table:
5265 \new@hlfcntr{tbl@bonuspoints}
5267 %--------------------------------------------------------------------
5268 % multirow tables, non-partial:
5270 \def\multirowgradetable#1{%
5275 \setcounter{num@rows}{#1}%
5279 \def\multirowpointtable#1{%
5284 \setcounter{num@rows}{#1}%
5288 \def\multirowbonusgradetable#1{%
5293 \setcounter{num@rows}{#1}%
5297 \def\multirowbonuspointtable#1{%
5302 \setcounter{num@rows}{#1}%
5306 \def\multirowcombinedgradetable#1{%
5311 \setcounter{num@rows}{#1}%
5315 \def\multirowcombinedpointtable#1{%
5320 \setcounter{num@rows}{#1}%
5324 %--------------------------------------------------------------------
5325 % multirow tables, partial:
5327 \def\multirowpartialgradetable#1#2{%
5333 \setcounter{num@rows}{#1}%
5337 \def\multirowpartialpointtable#1#2{%
5343 \setcounter{num@rows}{#1}%
5347 \def\multirowpartialbonusgradetable#1#2{%
5353 \setcounter{num@rows}{#1}%
5357 \def\multirowpartialbonuspointtable#1#2{%
5363 \setcounter{num@rows}{#1}%
5367 \def\multirowpartialcombinedgradetable#1#2{%
5373 \setcounter{num@rows}{#1}%
5377 \def\multirowpartialcombinedpointtable#1#2{%
5383 \setcounter{num@rows}{#1}%
5387 %--------------------------------------------------------------------
5388 % multicolumn tables, non-partial:
5390 \def\multicolumngradetable#1{%
5395 \setcounter{num@cols}{#1}%
5399 \def\multicolumnpointtable#1{%
5404 \setcounter{num@cols}{#1}%
5408 \def\multicolumnbonusgradetable#1{%
5413 \setcounter{num@cols}{#1}%
5417 \def\multicolumnbonuspointtable#1{%
5422 \setcounter{num@cols}{#1}%
5426 \def\multicolumncombinedgradetable#1{%
5431 \setcounter{num@cols}{#1}%
5435 \def\multicolumncombinedpointtable#1{%
5440 \setcounter{num@cols}{#1}%
5444 %--------------------------------------------------------------------
5445 % multicolumn tables, partial:
5447 \def\multicolumnpartialgradetable#1#2{%
5453 \setcounter{num@cols}{#1}%
5457 \def\multicolumnpartialpointtable#1#2{%
5463 \setcounter{num@cols}{#1}%
5467 \def\multicolumnpartialbonusgradetable#1#2{%
5473 \setcounter{num@cols}{#1}%
5477 \def\multicolumnpartialbonuspointtable#1#2{%
5483 \setcounter{num@cols}{#1}%
5487 \def\multicolumnpartialcombinedgradetable#1#2{%
5493 \setcounter{num@cols}{#1}%
5497 \def\multicolumnpartialcombinedpointtable#1#2{%
5503 \setcounter{num@cols}{#1}%
5507 %--------------------------------------------------------------------
5508 % partial single row (and column) tables:
5510 \def\partialgradetable#1{%
5516 % We don't yet know if the table is vertical or horizontal, and so
5517 % we don't know if we need to set num@cols or num@rows. We'll set
5518 % them both, and we'll later on just ignore the value of the one
5519 % that we didn't need to set here:
5520 \setcounter{num@cols}{1}%
5521 \setcounter{num@rows}{1}%
5522 % If the user doesn't include the optional argument
5523 % choosing between vertical and horizontal,
5524 % we give them vertical:
5525 \@ifnextchar[{\i@gtable}{\i@gtable[v]}%
5526 }% partialgradetable
5528 \def\partialbonusgradetable#1{%
5534 % We don't yet know if the table is vertical or horizontal, and so
5535 % we don't know if we need to set num@cols or num@rows. We'll set
5536 % them both, and we'll later on just ignore the value of the one
5537 % that we didn't need to set here:
5538 \setcounter{num@cols}{1}%
5539 \setcounter{num@rows}{1}%
5540 % If the user doesn't include the optional argument
5541 % choosing between vertical and horizontal,
5542 % we give them vertical:
5543 \@ifnextchar[{\i@gtable}{\i@gtable[v]}%
5544 }% partialbonusgradetable
5546 \def\partialcombinedgradetable#1{%
5552 % We don't yet know if the table is vertical or horizontal, and so
5553 % we don't know if we need to set num@cols or num@rows. We'll set
5554 % them both, and we'll later on just ignore the value of the one
5555 % that we didn't need to set here:
5556 \setcounter{num@cols}{1}%
5557 \setcounter{num@rows}{1}%
5558 % If the user doesn't include the optional argument
5559 % choosing between vertical and horizontal,
5560 % we give them vertical:
5561 \@ifnextchar[{\i@gtable}{\i@gtable[v]}%
5562 }% partialcombinedgradetable
5564 \def\partialpointtable#1{%
5570 % We don't yet know if the table is vertical or horizontal, and so
5571 % we don't know if we need to set num@cols or num@rows. We'll set
5572 % them both, and we'll later on just ignore the value of the one
5573 % that we didn't need to set here:
5574 \setcounter{num@cols}{1}%
5575 \setcounter{num@rows}{1}%
5576 % If the user doesn't include the optional argument
5577 % choosing between vertical and horizontal,
5578 % we give them vertical:
5579 \@ifnextchar[{\i@gtable}{\i@gtable[v]}%
5580 }% partialpointtable
5582 \def\partialbonuspointtable#1{%
5588 % We don't yet know if the table is vertical or horizontal, and so
5589 % we don't know if we need to set num@cols or num@rows. We'll set
5590 % them both, and we'll later on just ignore the value of the one
5591 % that we didn't need to set here:
5592 \setcounter{num@cols}{1}%
5593 \setcounter{num@rows}{1}%
5594 % If the user doesn't include the optional argument
5595 % choosing between vertical and horizontal,
5596 % we give them vertical:
5597 \@ifnextchar[{\i@gtable}{\i@gtable[v]}%
5598 }% partialbonuspointtable
5600 \def\partialcombinedpointtable#1{%
5606 % We don't yet know if the table is vertical or horizontal, and so
5607 % we don't know if we need to set num@cols or num@rows. We'll set
5608 % them both, and we'll later on just ignore the value of the one
5609 % that we didn't need to set here:
5610 \setcounter{num@cols}{1}%
5611 \setcounter{num@rows}{1}%
5612 % If the user doesn't include the optional argument
5613 % choosing between vertical and horizontal,
5614 % we give them vertical:
5615 \@ifnextchar[{\i@gtable}{\i@gtable[v]}%
5616 }% partialcombinedpointtable
5618 %--------------------------------------------------------------------
5619 % single row (and column) tables, non-partial:
5626 % We don't yet know if the table is vertical or horizontal, and so
5627 % we don't know if we need to set num@cols or num@rows. We'll set
5628 % them both, and we'll later on just ignore the value of the one
5629 % that we didn't need to set here:
5630 \setcounter{num@cols}{1}%
5631 \setcounter{num@rows}{1}%
5632 % If the user doesn't include the optional argument
5633 % choosing between vertical and horizontal,
5634 % we give them vertical:
5635 \@ifnextchar[{\i@gtable}{\i@gtable[v]}%
5638 \def\bonusgradetable{%
5643 % We don't yet know if the table is vertical or horizontal, and so
5644 % we don't know if we need to set num@cols or num@rows. We'll set
5645 % them both, and we'll later on just ignore the value of the one
5646 % that we didn't need to set here:
5647 \setcounter{num@cols}{1}%
5648 \setcounter{num@rows}{1}%
5649 % If the user doesn't include the optional argument
5650 % choosing between vertical and horizontal,
5651 % we give them vertical:
5652 \@ifnextchar[{\i@gtable}{\i@gtable[v]}%
5655 \def\combinedgradetable{%
5660 % We don't yet know if the table is vertical or horizontal, and so
5661 % we don't know if we need to set num@cols or num@rows. We'll set
5662 % them both, and we'll later on just ignore the value of the one
5663 % that we didn't need to set here:
5664 \setcounter{num@cols}{1}%
5665 \setcounter{num@rows}{1}%
5666 % If the user doesn't include the optional argument
5667 % choosing between vertical and horizontal,
5668 % we give them vertical:
5669 \@ifnextchar[{\i@gtable}{\i@gtable[v]}%
5677 % We don't yet know if the table is vertical or horizontal, and so
5678 % we don't know if we need to set num@cols or num@rows. We'll set
5679 % them both, and we'll later on just ignore the value of the one
5680 % that we didn't need to set here:
5681 \setcounter{num@cols}{1}%
5682 \setcounter{num@rows}{1}%
5683 % If the user doesn't include the optional argument
5684 % choosing between vertical and horizontal,
5685 % we give them vertical:
5686 \@ifnextchar[{\i@gtable}{\i@gtable[v]}%
5689 \def\bonuspointtable{%
5694 % We don't yet know if the table is vertical or horizontal, and so
5695 % we don't know if we need to set num@cols or num@rows. We'll set
5696 % them both, and we'll later on just ignore the value of the one
5697 % that we didn't need to set here:
5698 \setcounter{num@cols}{1}%
5699 \setcounter{num@rows}{1}%
5700 % If the user doesn't include the optional argument
5701 % choosing between vertical and horizontal,
5702 % we give them vertical:
5703 \@ifnextchar[{\i@gtable}{\i@gtable[v]}%
5706 \def\combinedpointtable{%
5711 % We don't yet know if the table is vertical or horizontal, and so
5712 % we don't know if we need to set num@cols or num@rows. We'll set
5713 % them both, and we'll later on just ignore the value of the one
5714 % that we didn't need to set here:
5715 \setcounter{num@cols}{1}%
5716 \setcounter{num@rows}{1}%
5717 % If the user doesn't include the optional argument
5718 % choosing between vertical and horizontal,
5719 % we give them vertical:
5720 \@ifnextchar[{\i@gtable}{\i@gtable[v]}%
5723 %--------------------------------------------------------------------
5725 % \i@gtable and \ii@gtable insert any missing optional arguments
5726 % (the defaults being [v] and [questions]) and then make sure
5727 % that the user said \addpoints and that this isn't the
5728 % first run of LaTeX.
5729 % \find@p@or@q@range then branches, depending on whether the user
5730 % selected [questions] or [pages].
5733 % If the user doesn't include the second optional argument,
5734 % which chooses between questions and pages,
5735 % we give them questions:
5736 \@ifnextchar[{\ii@gtable{#1}}{\ii@gtable{#1}[questions]}%
5738 \def\ii@gtable#1[#2]{%
5739 % We get here from \i@gtable.
5740 % We make sure the user said \addpoints, and then make sure
5741 % that this isn't the first run of LaTeX (by checking that
5742 % \exam@numpoints is defined). If both of those are OK,
5743 % we go to \find@p@or@q@range to see whether we're doing a table
5744 % indexed by questions or by pages.
5746 \@ifundefined{exam@numpoints}%
5747 {\ClassWarning{exam}%
5749 You must run LaTeX again to produce the
5752 \fbox{Run \LaTeX{} again to produce the table}%
5754 {\find@p@or@q@range{#1}{#2}}%
5757 You must give the command \protect\addpoints\MessageBreak
5758 \space\space in order to create a grade table.\MessageBreak
5760 If you don't give the command \protect\addpoints\MessageBreak
5761 \space\space then we're not keeping track of point values.
5767 \def\@questionsref{questions}
5768 \def\@pagesref{pages}
5769 \def\find@p@or@q@range#1#2{%
5770 % We get here from \ii@gtable.
5771 % The first argument should be ``v'' or ``h'';
5772 % the second argument should be ``questions'' or ``pages''.
5773 % See whether we're doing a table indexed by
5774 % questions (in which case we go to \find@qrange) or by pages (in
5775 % which case we go to \find@prange):
5777 % We've begun a group that will contain the construction of the
5778 % table, to confine the effect of any \def's that we use.
5780 \ifx\exam@temp\@questionsref
5784 \ifx\exam@temp\@pagesref
5789 Grade and point tables can be indexed\MessageBreak
5790 \space\space by either `questions' or `pages',\MessageBreak
5791 \space\space but not by `#2'.\MessageBreak
5793 Grade tables and point tables can be indexed by questions or
5795 \space\space for others, you're on your own.\MessageBreak
5797 \fbox{\textbf{Error:} grade or point table: Invalid argument
5798 `#2' must be `questions' or `pages'.}%
5802 }% find@p@or@q@range
5804 % \range@undefined can be called from either \find@qrange or
5806 \def\range@undefined{%
5807 \fbox{Warning: grading range `\tbl@range ' not defined;
5808 run \LaTeX{} again.}%
5809 \ClassWarning{exam}{%
5810 Grading range `\tbl@range' not defined.\MessageBreak
5811 \space\space Run LaTeX again to produce the table.\MessageBreak
5816 %--------------------------------------------------------------------
5817 %--------------------------------------------------------------------
5818 % Grade and point tables indexed by question numbers:
5820 % When we get to \find@qrange, we know we're doing a table indexed by
5821 % question numbers and that this is not the first run of latex. The
5822 % argument is either ``v'' or ``h''. If we're not doing a partial
5823 % table, then \find@qrange sets \tbl@firstq and \first@pq@index to 1
5824 % and \tbl@lastq and \last@pq@index to \numquestions. Otherwise,
5825 % \find@qrange makes sure the grading range is defined and that its
5826 % last question isn't before its first question. \find@qrange then
5827 % calls \tbl@v@or@h, passing along the argument that is either ``v''
5830 \def\find@qrange#1{%
5831 % We get here from \find@p@or@q@range.
5832 % We're doing a table indexed by question numbers.
5834 \@ifundefined{range@\tbl@range @firstq}%
5839 \@ifundefined{range@\tbl@range @lastq}%
5844 \edef\tbl@firstq{\csname range@\tbl@range @firstq\endcsname}%
5845 \edef\tbl@lastq{\csname range@\tbl@range @lastq\endcsname}%
5846 \let\first@pq@index=\tbl@firstq
5847 \let\last@pq@index=\tbl@lastq
5848 % Check that firstq precedes or equals lastq:
5849 \ifnum \tbl@firstq > \tbl@lastq\relax
5850 \fbox{\textbf{Error:} Grading Range `\tbl@range':
5851 Last question precedes first question.}%
5853 In grading range `\tbl@range',
5854 the last question\MessageBreak
5855 \space\space comes before the first question.\MessageBreak
5857 \string\begingradingrange \space must precede
5858 \string\endgradingrange \space by at
5859 least one question.\MessageBreak
5868 \let\first@pq@index=\tbl@firstq
5869 % \numquestions is always defined, even if this is the first
5870 % run of LaTeX and \exam@numquestions isn't defined.
5871 % If it's the first run of LaTeX, then its value isn't useful,
5872 % but it's never used until a later run (when its value is useful).
5873 \def\tbl@lastq{\numquestions}%
5874 \let\last@pq@index=\tbl@lastq
5882 % \first@pq@index=\tbl@firstq or \tbl@firstp and
5883 % \last@pq@index=\tbl@lastq or \tbl@lastp have already been set.
5884 % The argument should be either `v' or `h', and we branch
5887 \ifx\exam@temp\@vref
5890 \ifx\exam@temp\@href
5894 Grade or point table: the argument `#1'\MessageBreak
5895 \space\space must be `v' or `h'.
5898 Grade tables and point tables can be either vertical or
5899 horizontal;\MessageBreak
5900 \space\space no diagonals allowed.\MessageBreak
5902 \fbox{\textbf{Error:} grade or point table: Invalid argument
5903 `#1' must be `v' or `h'.}%
5908 %--------------------------------------------------------------------
5909 %--------------------------------------------------------------------
5910 % Grade and point tables indexed by page numbers:
5913 % The only pages listed are those on which there are a nonzero number
5914 % of points. We check pages \tbl@firstp through \tbl@lastp
5915 % Once we've checked that, e.g., \lastpage@withpoints and
5916 % \pointsonpage@\romannumeral{\lastpage@withpoints} are defined, we
5917 % can safely (we think) check \pointsonpage@\romannumeral{n} for all n
5918 % between \tbl@firstp and \tbl@lastp without generating errors.
5920 % Actually: Since we added the notion of half points and half counters
5921 % (a long time ago), there won't be any errors even if
5922 % \pointsonpage@\romannumeral{n} isn't defined, since it's tested by the
5924 % \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral
5925 % \csname c@@iterator\endcsname\endcsname}%
5926 % \ifhlfcntr@pos{tmp@hlfcntr}%
5928 % \csname pointsonpage@\romannumeral
5929 % \csname c@@iterator\endcsname\endcsname
5930 % isn't defined, tmp@hlfcntr gets the value zero (because of the way
5931 % that \set@hlfcntr is written).
5933 % \find@prange makes sure the grading range is defined and that its
5934 % last page isn't before its first page (if it's a partial table). In
5935 % any case, it then sets \tbl@firstp and \tbl@lastp, and calls
5938 \def\find@prange#1{%
5939 % We get here from \find@p@or@q@range.
5940 % We're doing a table indexed by pages.
5941 % The argument is either ``v'' or ``h''.
5942 % We first determine the first and last page of the range, storing
5943 % those in \first@pq@index=\tbl@firstp and
5944 % \last@pq@index=\tbl@lastp. If not a partial table, we set
5945 % \first@pq@index=\tbl@firstp to 1 and \last@pq@index=\tbl@lastp to
5946 % the last page with the appropriate points (and so if it's a
5947 % combined table, it's the last page to have either bonus or
5948 % non-bonus points).
5949 % We then call \check@secondrun, passing it the argument that we
5950 % received (i.e., we say \check@secondrun{#1}) to make sure
5951 % we've done at least two runs of latex (so that we'll have the
5952 % information we need about which pages have points on them).
5954 \@ifundefined{range@\tbl@range @firstp}%
5959 \@ifundefined{range@\tbl@range @lastp}%
5964 \edef\tbl@firstp{\csname range@\tbl@range @firstp\endcsname}%
5965 \edef\tbl@lastp{\csname range@\tbl@range @lastp\endcsname}%
5966 \let\first@pq@index=\tbl@firstp
5967 \let\last@pq@index=\tbl@lastp
5968 % Check that firstp precedes or equals lastp:
5969 \ifnum \tbl@firstp > \tbl@lastp\relax
5970 \fbox{\textbf{Error:} Grading Range `\tbl@range ':
5971 Last page precedes first page.}%
5973 In grading range `\tbl@range', the last page\MessageBreak
5974 \space\space comes before the first page.\MessageBreak
5976 \string\begingradingrange \space must precede
5977 \string\endgradingrange.\MessageBreak
5980 \check@secondrun{#1}%
5985 % It's not a partial table:
5987 \let\first@pq@index=\tbl@firstp
5988 % We never get here on the first run of LaTeX, and
5989 % \lastpage@withbonuspoints is defined on the second and later runs.
5990 \def\tbl@lastp{\lastpage@withpoints}%
5991 \let\last@pq@index=\tbl@lastp
5993 \def\tbl@lastp{\lastpage@withbonuspoints}%
5994 \let\last@pq@index=\tbl@lastp
5997 \ifnum \lastpage@withbonuspoints > \lastpage@withpoints\relax
5998 \def\tbl@lastp{\lastpage@withbonuspoints}%
5999 \let\last@pq@index=\tbl@lastp
6002 \check@secondrun{#1}%
6006 \def\check@secondrun#1{%
6007 % The function \ii@gtable already made sure that this isn't the
6008 % first run of latex. To do a table indexed by pages, though, we
6009 % have to also make sure it's not the second run of latex.
6010 % We get here from \find@prange; the argument is either ``v'' or
6012 % Check that there's enough info from the .aux file to do a page
6013 % indexed grade table. If so, call \tbl@v@or@h{#1}:
6014 \@ifundefined{pointsonpage@\romannumeral
6015 \csname lastpage@withpoints\endcsname}%
6016 {\@ifundefined{bonuspointsonpage@\romannumeral
6017 \csname lastpage@withbonuspoints\endcsname}%
6018 {\ClassWarning{exam}{%
6019 You must run LaTeX again to produce the table.\MessageBreak}%
6020 \fbox{Run \LaTeX{} again to produce the table}%
6029 %--------------------------------------------------------------------
6032 % For a table indexed by pages, we need to know how many pages there
6033 % are with points on them. The argument to \count@pgswpts should be
6034 % the name of a counter; we set that counter equal to the number of
6035 % pages with the appropriate kind of points.
6037 \def\count@pgswpts#1{%
6038 % Set the counter #1 equal to the number of pages in the range with
6039 % the appropriate type of points.
6040 % We're called by \@computenumcols@h and \@computenumrows@v.
6042 \setcounter{@iterator}{\tbl@firstp}%
6043 \addtocounter{@iterator}{-1}%
6045 \docount@pgswbpts{#1}%
6048 \docount@pgswcpts{#1}%
6050 \docount@pgswpts{#1}%
6055 \def\docount@pgswcpts#1{%
6056 % Called by \count@pgswpts
6057 % Count the number of pages in range with any kind of point (bonus
6059 \addtocounter{@iterator}{1}%
6060 \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}%
6061 \ifhlfcntr@pos{tmp@hlfcntr}%
6062 \addtocounter{#1}{1}%
6064 \check@bnsptpage{#1}%
6066 \ifnum \the@iterator < \tbl@lastp\relax
6067 \def\nextdocount@pgswcpts{\docount@pgswcpts{#1}}%
6069 \let\nextdocount@pgswcpts=\relax
6071 \nextdocount@pgswcpts
6073 \def\check@bnsptpage#1{%
6074 % We need to hide this inside of a macro because if \ifhlfcntr@pos
6075 % isn't expanded (because this stuff is being skipped in the outer
6076 % conditional), then TeX doesn't see the \ifnum hidden inside the
6077 % \ifhlfcntr@pos, but it does see the \fi, and so it get confused.
6078 \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}%
6079 \ifhlfcntr@pos{tmp@hlfcntr}%
6080 \addtocounter{#1}{1}%
6084 \def\docount@pgswpts#1{%
6085 % Called by \count@pgswpts.
6086 % Count the number of pages in range with regular points.
6087 \addtocounter{@iterator}{1}%
6088 \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}%
6089 \ifhlfcntr@pos{tmp@hlfcntr}%
6090 \addtocounter{#1}{1}%
6092 \ifnum \the@iterator < \tbl@lastp\relax
6093 \def\nextdocount@pgswpts{\docount@pgswpts{#1}}%
6095 \let\nextdocount@pgswpts=\relax
6097 \nextdocount@pgswpts
6100 \def\docount@pgswbpts#1{%
6101 % Called by \count@pgswpts
6102 % Count the number of pages in range with bonus points.
6103 \addtocounter{@iterator}{1}%
6104 \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\the@iterator}}%
6105 \ifhlfcntr@pos{tmp@hlfcntr}%
6106 \addtocounter{#1}{1}%
6108 \ifnum \the@iterator < \tbl@lastp\relax
6109 \def\nextdocount@pgswbpts{\docount@pgswbpts{#1}}%
6111 \let\nextdocount@pgswbpts=\relax
6113 \nextdocount@pgswbpts
6116 %--------------------------------------------------------------------
6117 %--------------------------------------------------------------------
6118 % Multirow horizontal tables, indexed by question numbers:
6120 \newcounter{pq@index}% In tables indexed by page numbers, it holds a
6121 % page number. In tables indexed by question numbers, it holds a
6124 \newcounter{pq@index@pts}% In horizontal tables, this holds either the
6125 % current page number or the current question number as we put the
6126 % point values for that page or question number into the table. In
6127 % vertical tables, this holds the index for the first column of the
6130 \newcounter{pq@index@bpts}% used to set bonus point values in
6131 % horizontal tables. Often used as scratch elsewhere.
6133 \def\hidden@ampersand{&}% Needed because an ampersand can't appear in
6134 % the replacement text of a conditional.
6137 % \tbl@pgstrue means a table indexed by page numbers
6138 % \tbl@pgsfalse means a table indexed by question numbers
6140 \newcounter{num@cols}
6141 \newcounter{num@rows}
6142 \newcounter{current@row}
6143 \newcounter{cols@done}% Holds the number of columns done in the
6146 %--------------------------------------------------------------------
6147 %--------------------------------------------------------------------
6148 % Stuff to unify tables indexed by questions and tables indexed by
6151 % \first@pq@index and \last@pq@index will hold either \tbl@firstq and
6152 % \tbl@lastq or \tbl@firstp and \tbl@lastp.
6154 \def\increment@index#1{%
6155 % If we're doing a table indexed by question numbers, we increment
6157 % If we're doing a table indexed by page numbers,
6158 % we increase the counter #1 by at least 1 to either the number of the
6159 % next page containing the appropriate kind of points, or to
6160 % something greater than \tbl@lastp.
6162 \find@nextpagewithpoints{#1}%
6164 \addtocounter{#1}{1}%
6168 \def\nextcolumn@index@v#1{%
6169 % Used only for multicolumn tables.
6170 % If we're doing a table indexed by question numbers, we increase
6171 % the counter #1 by num@cols.
6172 % If we're doing a table indexed by page numbers,
6173 % we use \find@nextcolumnpage@v to increment the counter #1 to either
6174 % the (num@rows)'th page number after #1 that contains the
6175 % appropriate kind of points or to a value greater than \tbl@lastp.
6177 \find@nextcolumnpage@v{#1}%
6179 \addtocounter{#1}{\value{num@rows}}%
6181 }% nextcolumn@index@v
6183 \def\pointsof@index#1{%
6185 \pointsonpage{\arabic{#1}}%
6187 \pointsofquestion{\arabic{#1}}%
6191 \def\bonuspointsof@index#1{%
6193 \bonuspointsonpage{\arabic{#1}}%
6195 \bonuspointsofquestion{\arabic{#1}}%
6197 }% bonuspointsof@index
6199 \def\refto@index#1{%
6202 % Need to hide this inside of a macro:
6203 \refto@comb@index{#1}%
6206 \pageref{firstbonuspoints@onpage@\arabic{#1}}%
6208 \pageref{firstpoints@onpage@\arabic{#1}}%
6212 \ref{question@\arabic{#1}}%
6216 \def\refto@comb@index#1{%
6217 % We're called only by \refto@index.
6218 % We can't have the \ifhlfcntr@pos...\fi inside of another
6219 % conditional, so we're hiding it in this macro.
6220 \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\arabic{#1}}}%
6221 \ifhlfcntr@pos{tmp@hlfcntr}%
6222 \pageref{firstpoints@onpage@\arabic{#1}}%
6224 % In theory, there *must* be bonus points on this page, because
6225 % there aren't any plain points, but there are allegedly *some*
6226 % points. We're being brave and assuming that's correct, and not
6227 % checking (which we'd have to hide inside a macro, because it
6228 % would use \ifhlfcntr@pos):
6229 \pageref{firstbonuspoints@onpage@\arabic{#1}}%
6233 %--------------------------------------------------------------------
6234 %--------------------------------------------------------------------
6238 %--------------------------------------------------------------------
6239 % Check that the number of rows is OK, and compute the number of
6242 \def\check@num@rows@h{%
6243 % We get here from \tbl@v@or@h.
6244 % We make sure the number of rows is a positive integer. If it
6245 % is, we go on to \@computenumcols@h
6246 \ifnum \value{num@rows} < 1\relax
6248 The number of rows in a table must be positive.\MessageBreak
6250 The number of rows must be a positive integer.\MessageBreak
6252 \fbox{\textbf{Error:} Multirow table with no rows!}%
6258 \def\@computenumcols@h{%
6259 % We get here from \check@num@rows@h.
6260 % Compute the number of columns.
6261 % First: set num@cols to one more than either (the number of pages
6262 % with the appropriate type of points) or (the number of questions),
6263 % to have slots for the total along with the questions:
6265 \count@pgswpts{num@cols}%
6266 \addtocounter{num@cols}{1}%
6268 \setcounter{num@cols}{\tbl@lastq}%
6269 \addtocounter{num@cols}{-\tbl@firstq}%
6270 \addtocounter{num@cols}{2}%
6272 % Save the number of slots needed in pq@index (used for scratch), to
6273 % check for truncation:
6274 \setcounter{pq@index}{\value{num@cols}}%
6275 % Divide the number of slots needed by num@rows:
6276 \divide \csname c@num@cols\endcsname by
6277 \csname c@num@rows\endcsname
6278 % Division truncates: See if there was truncation.
6279 % Use @iterator as a scratch counter.
6280 \setcounter{@iterator}{\value{num@cols}}%
6281 \multiply \csname c@@iterator\endcsname by
6282 \csname c@num@rows\endcsname
6283 \ifnum \value{@iterator} < \value{pq@index}\relax
6284 % There was truncation; add a column to num@cols:
6285 \addtocounter{num@cols}{1}%
6288 }% @computenumcols@h
6290 %--------------------------------------------------------------------
6291 % Construct the actual table:
6293 \def\@multirowtable{%
6294 % We get here from \@computenumcols@h.
6295 % All multirow tables!
6296 \renewcommand\arraystretch{\@gtblstretch}%
6297 \set@hlfcntr{tbl@points}{0}%
6298 \set@hlfcntr{tbl@bonuspoints}{0}%
6299 \setcounter{pq@index}{\first@pq@index}%
6300 \addtocounter{pq@index}{-1}%
6301 \setcounter{pq@index@pts}{\value{pq@index}}%
6302 \setcounter{pq@index@bpts}{\value{pq@index}}%
6303 \setcounter{current@row}{0}%
6304 \begin{tabular}{|l|*{\value{num@cols}}{c|}}
6315 % Called only by \@multirowtable.
6316 % It's either bonus or regular, but not combined:
6317 \addtocounter{current@row}{1}% Set to the number of the current row
6331 \setcounter{cols@done}{0}%
6333 % When we finish \do@pq@indexloop@h, either we've finished a
6334 % complete row of page numbers (or questions), or we've done all
6335 % the page numbers (or questions) through \last@pq@index, or both:
6336 \ifnum \value{cols@done} < \value{num@cols}\relax
6337 % We've inserted all the page or question numbers, and there's
6338 % room remaining on the current line for \@htword (or \@bhtword):
6339 \ifnum \value{current@row} = \value{num@rows}\relax
6340 % This is the last row; put in the total:
6343 % This isn't the last row. We insert (\value{num@cols} -
6344 % \value{cols@done}) ampersands.
6345 \setcounter{@iterator}{\value{num@cols}}%
6346 \addtocounter{@iterator}{-\value{cols@done}}%
6352 % Point values go here!
6353 \setcounter{cols@done}{0}%
6361 % When we finish \do@ptloop@h or \do@bptloop@h, either
6362 % we've finished a complete row of point values, or we've done all
6363 % the question (or page) numbers through \last@pq@index, or both:
6364 \ifnum \value{cols@done} < \value{num@cols}\relax
6365 % We've inserted all the point values, and there's room
6366 % remaining on the current line for Total Points:
6367 \ifnum \value{current@row} = \value{num@rows}\relax
6368 % This is the last row; put in the total:
6375 % This isn't the last row. We insert (\value{num@cols} -
6376 % \value{cols@done}) ampersands.
6377 \setcounter{@iterator}{\value{num@cols}}%
6378 \addtocounter{@iterator}{-\value{cols@done}}%
6382 % We hold off on putting in the "\\ \hline" because we may want to
6383 % immediately follow it with either an "\end{tabular}" or another
6390 \@bhsword \hidden@ampersand
6392 \@hsword \hidden@ampersand
6394 \setcounter{cols@done}{0}%
6397 \ifnum \value{current@row} = \value{num@rows}\relax
6398 % This is the last line! End the tabular:
6403 % Don't end the tabular:
6407 % Check if we should repeat:
6408 \ifnum \value{current@row} < \value{num@rows}\relax
6409 \let\nextdo@lines@h=\do@lines@h
6411 \let\nextdo@lines@h=\relax
6416 \def\do@comblines@h{%
6417 % Called only by \@multirowtable.
6419 \addtocounter{current@row}{1}% Set to the number of the current row
6425 \setcounter{cols@done}{0}%
6427 % When we finish \do@pq@indexloop@h, either we've finished a
6428 % complete row of page (or question) numbers, or we've done all
6429 % the page (or question) numbers through \last@pq@index, or both:
6430 \ifnum \value{cols@done} < \value{num@cols}\relax
6431 % We've inserted all the question (or page) numbers, and there's
6432 % room remaining on the current line for \@chtword:
6433 \ifnum \value{current@row} = \value{num@rows}\relax
6434 % This is the last row; put in the total:
6437 % This isn't the last row. We insert (\value{num@cols} -
6438 % \value{cols@done}) ampersands.
6439 \setcounter{@iterator}{\value{num@cols}}%
6440 \addtocounter{@iterator}{-\value{cols@done}}%
6446 % Point values go here!
6448 \setcounter{cols@done}{0}%
6450 % When we finish \do@ptloop@h, either we've finished a complete
6451 % row of point values, or we've done all the question (or page)
6452 % numbers through \last@pq@index, or both:
6453 \ifnum \value{cols@done} < \value{num@cols}\relax
6454 % We've inserted all the point values, and there's room
6455 % remaining on the current line for Total Points:
6456 \ifnum \value{current@row} = \value{num@rows}\relax
6457 % This is the last row; put in the total:
6460 % This isn't the last row. We insert (\value{num@cols} -
6461 % \value{cols@done}) ampersands.
6462 \setcounter{@iterator}{\value{num@cols}}%
6463 \addtocounter{@iterator}{-\value{cols@done}}%
6469 % Bonus point values go here!
6471 \setcounter{cols@done}{0}%
6473 % When we finish \do@bptloop@h, either
6474 % we've finished a complete row of point values, or we've done all
6475 % the question (or page) numbers through \last@pq@index, or both:
6476 \ifnum \value{cols@done} < \value{num@cols}\relax
6477 % We've inserted all the point values, and there's room
6478 % remaining on the current line for Total Points:
6479 \ifnum \value{current@row} = \value{num@rows}\relax
6480 % This is the last row; put in the total:
6483 % This isn't the last row. We insert (\value{num@cols} -
6484 % \value{cols@done}) ampersands.
6485 \setcounter{@iterator}{\value{num@cols}}%
6486 \addtocounter{@iterator}{-\value{cols@done}}%
6490 % We hold off on putting in the "\\ \hline" because we may want to
6491 % immediately follow it with either an "\end{tabular}" or another
6497 \@chsword \hidden@ampersand
6498 \setcounter{cols@done}{0}%
6501 \ifnum \value{current@row} = \value{num@rows}\relax
6502 % This is the last line! End the tabular:
6507 % Don't end the tabular:
6511 % Check if we should repeat:
6512 \ifnum \value{current@row} < \value{num@rows}\relax
6513 \let\nextdo@comblines@h=\do@comblines@h
6515 \let\nextdo@comblines@h=\relax
6520 \def\do@pq@indexloop@h{%
6521 % Called by both \do@lines@h and \do@comblines@h.
6522 % We insert at most one row of pq@index:
6523 \increment@index{pq@index}%
6524 \ifnum \value{pq@index} > \last@pq@index\relax
6528 \refto@index{pq@index}%
6529 \addtocounter{cols@done}{1}%
6531 \ifnum \value{pq@index} < \last@pq@index\relax
6532 \ifnum \value{cols@done} < \value{num@cols}\relax
6533 \let\nextdo@pq@indexloop@h=\do@pq@indexloop@h
6535 \let\nextdo@pq@indexloop@h=\relax
6538 \let\nextdo@pq@indexloop@h=\relax
6540 \nextdo@pq@indexloop@h
6541 }% do@pq@indexloop@h
6544 % Called by both \do@lines@h and \do@comblines@h.
6545 % We insert at most one row of non-bonus point values:
6546 \increment@index{pq@index@pts}%
6547 \ifnum \value{pq@index@pts} > \last@pq@index\relax
6551 \addtocounter{cols@done}{1}%
6552 \pointsof@index{pq@index@pts}%
6553 \addto@hlfcntr{tbl@points}{\pointsof@index{pq@index@pts}}%
6555 \ifnum \value{pq@index@pts} < \last@pq@index\relax
6556 \ifnum \value{cols@done} < \value{num@cols}\relax
6557 \let\nextdo@ptloop@h=\do@ptloop@h
6559 \let\nextdo@ptloop@h=\relax
6562 \let\nextdo@ptloop@h=\relax
6568 % Called by both \do@lines@h and \do@comblines@h.
6569 % We insert at most one row of bonus point values:
6570 \increment@index{pq@index@bpts}%
6571 \ifnum \value{pq@index@bpts} > \last@pq@index\relax
6575 \addtocounter{cols@done}{1}%
6576 \bonuspointsof@index{pq@index@bpts}%
6577 \addto@hlfcntr{tbl@bonuspoints}{\bonuspointsof@index{pq@index@bpts}}%
6579 \ifnum \value{pq@index@bpts} < \last@pq@index\relax
6580 \ifnum \value{cols@done} < \value{num@cols}\relax
6581 \let\nextdo@bptloop@h=\do@bptloop@h
6583 \let\nextdo@bptloop@h=\relax
6586 \let\nextdo@bptloop@h=\relax
6592 % Called by both \do@lines@h and \do@comblines@h.
6593 % We insert (\value{num@cols} - \value{cols@done}) ampersands,
6594 % and then either \@htword or \@bhtword or \@chtword:
6595 \setcounter{@iterator}{\value{num@cols}}%
6596 \addtocounter{@iterator}{-\value{cols@done}}%
6609 \def\do@totalpts@h{%
6610 % Called by both \do@lines@h and \do@comblines@h.
6611 % We insert (\value{num@cols} - \value{cols@done}) ampersands
6612 % and then the total points:
6613 \setcounter{@iterator}{\value{num@cols}}%
6614 \addtocounter{@iterator}{-\value{cols@done}}%
6619 \def\do@totalbpts@h{%
6620 % Called by both \do@lines@h and \do@comblines@h.
6621 % We insert (\value{num@cols} - \value{cols@done}) ampersands,
6622 % and then the total bonus points:
6623 \setcounter{@iterator}{\value{num@cols}}%
6624 \addtocounter{@iterator}{-\value{cols@done}}%
6626 \prt@tablebonuspoints
6629 \def\do@emptycols@h{%
6630 % Called by \do@lines@h, \do@comblines@h, \do@htword@h,
6631 % \do@totalpts@h, and \do@totalbpts@h.
6632 % We insert \value{@iterator} ampersands:
6633 \ifnum \value{@iterator} > 0\relax
6635 \addtocounter{@iterator}{-1}%
6636 \let\nextdo@emptycols@h=\do@emptycols@h
6638 \let\nextdo@emptycols@h=\relax
6644 % Called by both \do@lines@h and \do@comblines@h.
6645 % We assume that cols@done has been set to zero.
6646 % We insert num@cols \hbox to \@cellwidth,
6647 % separated by ampersands.
6648 \addtocounter{cols@done}{1}%
6649 \hbox to \@cellwidth{\hfill}%
6650 \ifnum \value{cols@done} < \value{num@cols}\relax
6652 \let\nextdo@sloop@h=\do@sloop@h
6654 \let\nextdo@sloop@h=\relax
6660 %--------------------------------------------------------------------
6661 %--------------------------------------------------------------------
6662 % Multicolumn tables
6665 %--------------------------------------------------------------------
6666 % Here's an example of a multicolumn grade table indexed by questions.
6668 % Every line of \cline's is followed by a
6669 % \noalign{\vskip\arrayrulewidth} to cancel the
6670 % \noalign{\vskip-\arrayrulewidth} that ends the definition of
6673 % \begin{tabular}{*2{|c|c|c|c}}
6674 % \cline{1-3} \cline{5-7}
6675 % \noalign{\vskip\arrayrulewidth}
6679 % & \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
6684 % \cline{1-3} \cline{5-7}
6685 % \noalign{\vskip\arrayrulewidth}
6688 % & \hbox to \@cellwidth{\hfill}%
6689 % & \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
6692 % & \hbox to \@cellwidth{\hfill}%
6694 % \cline{1-3} \cline{5-7}
6695 % \noalign{\vskip\arrayrulewidth}
6698 % & \hbox to \@cellwidth{\hfill}%
6699 % & \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
6702 % & \hbox to \@cellwidth{\hfill}%
6704 % \cline{1-3} \cline{5-7}
6705 % \noalign{\vskip\arrayrulewidth}
6708 % & \hbox to \@cellwidth{\hfill}%
6709 % & \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
6712 % & \hbox to \@cellwidth{\hfill}%
6714 % \cline{1-3} \cline{5-7}
6715 % \noalign{\vskip\arrayrulewidth}
6717 %--------------------------------------------------------------------
6718 %--------------------------------------------------------------------
6719 % Check that the number of cols is OK, and compute the number of rows:
6721 \def\check@num@cols@v{%
6722 % We get here from \tbl@v@or@h.
6723 % We make sure the number of cols is between 1 and 10 (since we
6724 % can't handle more than 10 cols in a multicolumn table).
6725 % If it is, we go on to \@computenumrows@v
6726 \ifnum \value{num@cols} < 1\relax
6728 The number of columns in a table must be positive.\MessageBreak
6730 The number of columns must be a positive integer.\MessageBreak
6732 \fbox{\textbf{Error:} Multicolumn table with no columns!}%
6734 \ifnum \value{num@cols} > 10\relax
6736 Multicolumn tables can have at most 10 columns.\MessageBreak
6738 Multicolumn tables can have at most 10 columns.\MessageBreak
6740 \fbox{\textbf{Error:} Multicolumn table with more than 10 columns!}%
6747 \def\@computenumrows@v{%
6748 % We get here from \check@num@cols@v.
6749 % Compute the number of rows.
6750 % First: set num@rows to one more than the number of either
6751 % (questions) or (pages with the appropriate type of points), to
6752 % have slots for the total along with the questions or page numbers:
6754 \count@pgswpts{num@rows}%
6755 \addtocounter{num@rows}{1}%
6757 \setcounter{num@rows}{\last@pq@index}%
6758 \addtocounter{num@rows}{-\first@pq@index}%
6759 \addtocounter{num@rows}{2}%
6761 % Save the number of slots needed, using pq@index@bpts as a scratch
6762 % counter, to check for truncation on division:
6763 \setcounter{pq@index@bpts}{\value{num@rows}}%
6764 % Divide the number of slots needed by num@cols:
6765 \divide \csname c@num@rows\endcsname by
6766 \csname c@num@cols\endcsname
6767 % Division truncates: See if there was truncation.
6768 % Use the counter @iterator as a scratch counter:
6769 \setcounter{@iterator}{\value{num@rows}}%
6770 \multiply \csname c@@iterator\endcsname by
6771 \csname c@num@cols\endcsname
6772 \ifnum \value{@iterator} < \value{pq@index@bpts}\relax
6773 % There was truncation; add one to num@rows:
6774 \addtocounter{num@rows}{1}%
6777 }% @computenumrows@v
6779 %--------------------------------------------------------------------
6780 % Construct the actual table:
6782 \def\@multicolumntable{%
6783 % We get here from \@computenumrows@v.
6784 % Set \cline@stuff@v equal to the line of \cline's:
6785 \create@cline@stuff@v
6786 \renewcommand\arraystretch{\@gtblstretch}%
6787 \set@hlfcntr{tbl@points}{0}%
6788 \set@hlfcntr{tbl@bonuspoints}{0}%
6791 % combinedgradetable, possibly partial.
6792 % Note: We'll never use the final "c" in the format of the
6793 % tabular, but there's no harm in that.
6794 \begin{tabular}{*{\value{num@cols}}{|c|c|c|c|c}}
6795 % We need to make sure that the \cline@stuff@v commands come
6796 % *immediately* following the \\ or \begin{tabular} (with no
6797 % conditionals evaluated, even if those conditionals expand to
6798 % the empty string)!
6799 % Put in the row of column headings, with \cline@stuff@v above and
6802 \setcounter{@iterator}{0}%
6803 \docolumn@heads@comb@v
6807 % combinedpointtable, possibly partial.
6808 % Note: We'll never use the final "c" in the format of the
6809 % tabular, but there's no harm in that.
6810 \begin{tabular}{*{\value{num@cols}}{|c|c|c|c}}
6811 % We need to make sure that the \cline@stuff@v commands come
6812 % *immediately* following the \\ or \begin{tabular} (with no
6813 % conditionals evaluated, even if those conditionals expand to
6814 % the empty string)!
6815 % Put in the row of column headings, with \cline@stuff@v above and
6818 \setcounter{@iterator}{0}%
6819 \docolumn@heads@comb@noscores@v
6823 % pq@index@pts will hold the question number (or page number) in
6824 % the first column of the row.
6825 \setcounter{pq@index@pts}{\first@pq@index}%
6827 % If we're indexed by pages, we need to make sure there are
6828 % points of the appropriate type on the first page listed:
6829 \addtocounter{pq@index@pts}{-1}%
6830 \find@nextpagewithpoints{pq@index@pts}%
6832 \setcounter{current@row}{0}%
6835 % It's not combined:
6837 % Note: We'll never use the final "c" in the format of the
6838 % tabular, but there's no harm in that.
6839 \begin{tabular}{*{\value{num@cols}}{|c|c|c|c}}
6840 % We need to make sure that the \cline@stuff@v commands come
6841 % *immediately* following the \\ or \begin{tabular} (with no
6842 % conditionals evaluated, even if those conditionals expand to
6843 % the empty string)!
6844 % Put in the row of column headings, with \cline@stuff@v above and
6847 \setcounter{@iterator}{0}%
6852 % Note: We'll never use the final "c" in the format of the
6853 % tabular, but there's no harm in that.
6854 \begin{tabular}{*{\value{num@cols}}{|c|c|c}}
6855 % We need to make sure that the \cline@stuff@v commands come
6856 % *immediately* following the \\ or \begin{tabular} (with no
6857 % conditionals evaluated, even if those conditionals expand to
6858 % the empty string)!
6859 % Put in the row of column headings, with \cline@stuff@v above and
6862 \setcounter{@iterator}{0}%
6863 \docolumn@heads@noscores@v
6867 % pq@index@pts will hold the question number (or page number) in
6868 % the first column of the row.
6869 \setcounter{pq@index@pts}{\first@pq@index}%
6871 % If we're indexed by pages, we need to make sure there are
6872 % points of the appropriate type on the first page listed:
6873 \addtocounter{pq@index@pts}{-1}%
6874 \find@nextpagewithpoints{pq@index@pts}%
6876 \setcounter{current@row}{0}%
6879 }% @multicolumntable
6881 %--------------------------------------------------------------------
6882 % \create@cline@stuff@v
6884 % The function \create@cline@stuff@v defines \cline@stuff@v to be whatever's
6885 % appropriate given the values of num@cols, \if@bonus, \if@combined, and
6888 % We wimped out of generating \cline@stuff@v on the fly because we didn't
6889 % see how to get the correct expansions/nonexpansions without using a
6890 % primitive of e-TeX.
6892 % \clines@ii@whatever is for tables in which a logical column consists
6893 % of two columns; it's used for pointtable and bonuspointtable.
6895 \def\clines@ii@i{\cline{1-2}}
6896 \def\clines@ii@ii{\cline{1-2} \cline{4-5}}
6897 \def\clines@ii@iii{\cline{1-2} \cline{4-5} \cline{7-8}}
6898 \def\clines@ii@iv{\cline{1-2} \cline{4-5} \cline{7-8} \cline{10-11}}
6899 \def\clines@ii@v{\cline{1-2} \cline{4-5} \cline{7-8} \cline{10-11}
6901 \def\clines@ii@vi{\cline{1-2} \cline{4-5} \cline{7-8} \cline{10-11}
6902 \cline{13-14} \cline{16-17}}
6903 \def\clines@ii@vii{\cline{1-2} \cline{4-5} \cline{7-8} \cline{10-11}
6904 \cline{13-14} \cline{16-17} \cline{19-20}}
6905 \def\clines@ii@viii{\cline{1-2} \cline{4-5} \cline{7-8} \cline{10-11}
6906 \cline{13-14} \cline{16-17} \cline{19-20} \cline{22-23}}
6907 \def\clines@ii@vix{\cline{1-2} \cline{4-5} \cline{7-8} \cline{10-11}
6908 \cline{13-14} \cline{16-17} \cline{19-20} \cline{22-23}
6910 \def\clines@ii@x{\cline{1-2} \cline{4-5} \cline{7-8} \cline{10-11}
6911 \cline{13-14} \cline{16-17} \cline{19-20} \cline{22-23}
6912 \cline{25-26} \cline{28-29}}
6914 % \clines@iii@whatever is for tables in which a logical column consists
6915 % of three columns; it's are used for gradetable, bonusgradetable, and
6916 % combinedpointtable:
6918 \def\clines@iii@i{\cline{1-3}}
6919 \def\clines@iii@ii{\cline{1-3} \cline{5-7}}
6920 \def\clines@iii@iii{\cline{1-3} \cline{5-7} \cline{9-11}}
6921 \def\clines@iii@iv{\cline{1-3} \cline{5-7} \cline{9-11} \cline{13-15}}
6922 \def\clines@iii@v{\cline{1-3} \cline{5-7} \cline{9-11} \cline{13-15}
6924 \def\clines@iii@vi{\cline{1-3} \cline{5-7} \cline{9-11} \cline{13-15}
6925 \cline{17-19} \cline{21-23}}
6926 \def\clines@iii@vii{\cline{1-3} \cline{5-7} \cline{9-11} \cline{13-15}
6927 \cline{17-19} \cline{21-23} \cline{25-27}}
6928 \def\clines@iii@viii{\cline{1-3} \cline{5-7} \cline{9-11} \cline{13-15}
6929 \cline{17-19} \cline{21-23} \cline{25-27} \cline{29-31}}
6930 \def\clines@iii@ix{\cline{1-3} \cline{5-7} \cline{9-11} \cline{13-15}
6931 \cline{17-19} \cline{21-23} \cline{25-27} \cline{29-31}
6933 \def\clines@iii@x{\cline{1-3} \cline{5-7} \cline{9-11} \cline{13-15}
6934 \cline{17-19} \cline{21-23} \cline{25-27} \cline{29-31}
6935 \cline{33-35} \cline{37-39}}
6938 % \clines@iv@whatever is for tables in which a logical column
6939 % consists of four columns; it's used for combinedgradetable.
6941 \def\clines@iv@i{\cline{1-4}}
6942 \def\clines@iv@ii{\cline{1-4} \cline{6-9}}
6943 \def\clines@iv@iii{\cline{1-4} \cline{6-9} \cline{11-14}}
6944 \def\clines@iv@iv{\cline{1-4} \cline{6-9} \cline{11-14} \cline{16-19}}
6945 \def\clines@iv@v{\cline{1-4} \cline{6-9} \cline{11-14} \cline{16-19}
6947 \def\clines@iv@vi{\cline{1-4} \cline{6-9} \cline{11-14} \cline{16-19}
6948 \cline{21-24} \cline{26-29}}
6949 \def\clines@iv@vii{\cline{1-4} \cline{6-9} \cline{11-14} \cline{16-19}
6950 \cline{21-24} \cline{26-29} \cline{31-34}}
6951 \def\clines@iv@viii{\cline{1-4} \cline{6-9} \cline{11-14} \cline{16-19}
6952 \cline{21-24} \cline{26-29} \cline{31-34} \cline{36-39}}
6953 \def\clines@iv@ix{\cline{1-4} \cline{6-9} \cline{11-14} \cline{16-19}
6954 \cline{21-24} \cline{26-29} \cline{31-34} \cline{36-39}
6956 \def\clines@iv@x{\cline{1-4} \cline{6-9} \cline{11-14} \cline{16-19}
6957 \cline{21-24} \cline{26-29} \cline{31-34} \cline{36-39}
6958 \cline{41-44} \cline{46-49}}
6960 % The definition of \cline ends with \noalign{\vskip-\arrayrulewidth},
6961 % and so we want to throw in a \noalign{\vskip\arrayrulewidth} to
6963 \def\cline@correction{\noalign{\vskip\arrayrulewidth}}
6965 \def\create@cline@stuff@v{%
6966 % Called by \@multicolumntable.
6969 \edef\cline@stuff@v{\expandafter\noexpand\csname
6970 clines@iv@\romannumeral \c@num@cols\endcsname
6971 \noexpand\cline@correction}%
6973 \edef\cline@stuff@v{\expandafter\noexpand\csname
6974 clines@iii@\romannumeral \c@num@cols\endcsname
6975 \noexpand\cline@correction}%
6979 \edef\cline@stuff@v{\expandafter\noexpand\csname
6980 clines@iii@\romannumeral \c@num@cols\endcsname
6981 \noexpand\cline@correction}%
6983 \edef\cline@stuff@v{\expandafter\noexpand\csname
6984 clines@ii@\romannumeral \c@num@cols\endcsname
6985 \noexpand\cline@correction}%
6988 }% create@cline@stuff@v
6990 %--------------------------------------------------------------------
6991 % The various \docolumn@heads@something@v
6993 \def\docolumn@heads@v{%
6994 % Called by \@multicolumntable.
6995 % multicolumngradetable or multicolumnbonusgradetable, possibly
7020 \addtocounter{@iterator}{1}%
7021 \ifnum \value{@iterator} < \value{num@cols}\relax
7023 \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
7025 \let\nextdocolumn@heads@v=\docolumn@heads@v
7027 \let\nextdocolumn@heads@v=\relax
7029 \nextdocolumn@heads@v
7032 \def\docolumn@heads@noscores@v{%
7033 % Called by \@multicolumntable.
7034 % multicolumnpointtable or multicolumnbonuspointtable, possibly
7055 \addtocounter{@iterator}{1}%
7056 \ifnum \value{@iterator} < \value{num@cols}\relax
7058 \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
7060 \let\nextdocolumn@heads@noscores@v=\docolumn@heads@noscores@v
7062 \let\nextdocolumn@heads@noscores@v=\relax
7064 \nextdocolumn@heads@noscores@v
7065 }% docolumn@heads@noscores@v
7067 \def\docolumn@heads@comb@v{%
7068 % Called by \@multicolumntable.
7069 % multicolumncombinedgradetable, possibly partial.
7078 \addtocounter{@iterator}{1}%
7079 \ifnum \value{@iterator} < \value{num@cols}\relax
7081 \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
7083 \let\nextdocolumn@heads@comb@v=\docolumn@heads@comb@v
7085 \let\nextdocolumn@heads@comb@v=\relax
7087 \nextdocolumn@heads@comb@v
7088 }% docolumn@heads@comb@v
7090 \def\docolumn@heads@comb@noscores@v{%
7091 % Called by \@multicolumntable.
7092 % multicolumncombinedpointtable, possibly partial.
7100 \addtocounter{@iterator}{1}%
7101 \ifnum \value{@iterator} < \value{num@cols}\relax
7103 \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
7105 \let\nextdocolumn@heads@comb@noscores@v=\docolumn@heads@comb@noscores@v
7107 \let\nextdocolumn@heads@comb@noscores@v=\relax
7109 \nextdocolumn@heads@comb@noscores@v
7110 }% docolumn@heads@comb@noscores@v
7112 %--------------------------------------------------------------------
7113 % \do@lines@v is used by *all* multicolumn tables.
7114 % It calls \do@oneline@v for all non-combined tables and
7115 % \do@oneline@comb@v for all combined tables.
7118 % We get here from \@multicolumntable.
7119 % ALL MULTICOLUMN TABLES!!!!
7120 % pq@index@pts holds the question number or page number in the first
7121 % column of the current row.
7122 \addtocounter{current@row}{1}%
7123 \setcounter{pq@index}{\value{pq@index@pts}}%
7124 \setcounter{cols@done}{0}% Number of columns done
7125 % We're doing both grade tables and point tables!!
7131 \increment@index{pq@index@pts}%
7132 % We need the "\\ \cline@stuff@v" to *immediately* precede the
7133 % \end{tabular} (i.e., with no \ifnum separating them), to avoid
7134 % having crap after the \cline@stuff@v that
7135 % causes there to be an extra row at the end of the table. We also
7136 % need there to be nothing between \\ and \cline@stuff@v.
7137 \ifnum \value{current@row} = \value{num@rows}\relax
7141 \let\nextdo@lines@v=\relax
7145 \let\nextdo@lines@v=\do@lines@v
7151 % Called by \do@lines@v.
7152 % Used for all multicolumn non-combined tables.
7153 % pq@index holds the question or page number we're about to do.
7154 \ifnum \value{pq@index} > \last@pq@index\relax
7155 % See if we're in the last column; use pq@index@bpts as a scratch
7157 \setcounter{pq@index@bpts}{\value{cols@done}}%
7158 \addtocounter{pq@index@bpts}{1}%
7159 \ifnum \value{pq@index@bpts} = \value{num@cols}\relax
7160 % We're in the last column; are we in the last row?
7161 \ifnum \value{current@row} = \value{num@rows}\relax
7162 % We're in the last column, last row!
7172 \prt@tablebonuspoints
7177 \hbox to \@cellwidth{\hfill}%
7181 \prt@tablebonuspoints
7187 % Not last column last row; insert empty space:
7188 \hbox to \@cellwidth{\hfill}%
7191 \hbox to \@cellwidth{\hfill}%
7194 \hbox to \@cellwidth{\hfill}%
7197 % Not last column; insert empty space:
7198 \hbox to \@cellwidth{\hfill}%
7201 \hbox to \@cellwidth{\hfill}%
7204 \hbox to \@cellwidth{\hfill}%
7207 % We need to do question (or page) number pq@index:
7208 \refto@index{pq@index}%
7212 \bonuspointsof@index{pq@index}%
7213 \addto@hlfcntr{tbl@bonuspoints}{\bonuspointsof@index{pq@index}}%
7215 \pointsof@index{pq@index}%
7216 \addto@hlfcntr{tbl@points}{\pointsof@index{pq@index}}%
7219 \hbox to \@cellwidth{\hfill}%
7222 \bonuspointsof@index{pq@index}%
7223 \addto@hlfcntr{tbl@bonuspoints}{\bonuspointsof@index{pq@index}}%
7225 \pointsof@index{pq@index}%
7226 \addto@hlfcntr{tbl@points}{\pointsof@index{pq@index}}%
7230 \addtocounter{cols@done}{1}% Number of columns done
7231 \ifnum \value{cols@done} < \value{num@cols}\relax
7233 \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
7234 \nextcolumn@index@v{pq@index}%
7236 \let\nextdo@oneline@v=\do@oneline@v
7238 \let\nextdo@oneline@v=\relax
7243 \def\do@oneline@comb@v{%
7244 % Called by \do@lines@v.
7245 % All combined multicolumn tables.
7246 % pq@index holds the question (or page) we're about to do.
7247 \ifnum \value{pq@index} > \last@pq@index\relax
7248 % See if we're in the last column; use pq@index@bpts as a scratch
7250 \setcounter{pq@index@bpts}{\value{cols@done}}%
7251 \addtocounter{pq@index@bpts}{1}%
7252 \ifnum \value{pq@index@bpts} = \value{num@cols}\relax
7253 % We're in the last column; are we in the last row?
7254 \ifnum \value{current@row} = \value{num@rows}\relax
7255 % We're in the last column, last row!
7262 \prt@tablebonuspoints
7264 \hbox to \@cellwidth{\hfill}%
7266 \prt@tablebonuspoints
7269 % Last column, but not last row; insert empty space:
7270 \hbox to \@cellwidth{\hfill}%
7272 \hbox to \@cellwidth{\hfill}%
7275 \hbox to \@cellwidth{\hfill}%
7278 \hbox to \@cellwidth{\hfill}%
7281 % Not last column; insert empty space:
7282 \hbox to \@cellwidth{\hfill}%
7284 \hbox to \@cellwidth{\hfill}%
7287 \hbox to \@cellwidth{\hfill}%
7290 \hbox to \@cellwidth{\hfill}%
7293 % We need to do question number pq@index:
7294 \refto@index{pq@index}%
7296 \pointsof@index{pq@index}%
7297 \addto@hlfcntr{tbl@points}{\pointsof@index{pq@index}}%
7300 \bonuspointsof@index{pq@index}%
7301 \addto@hlfcntr{tbl@bonuspoints}{\bonuspointsof@index{pq@index}}%
7303 \hbox to \@cellwidth{\hfill}%
7305 \bonuspointsof@index{pq@index}%
7306 \addto@hlfcntr{tbl@bonuspoints}{\bonuspointsof@index{pq@index}}%
7309 \addtocounter{cols@done}{1}% Number of columns done
7310 \ifnum \value{cols@done} < \value{num@cols}\relax
7312 \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
7313 \nextcolumn@index@v{pq@index}%
7315 \let\nextdo@oneline@comb@v=\do@oneline@comb@v
7317 \let\nextdo@oneline@comb@v=\relax
7319 \nextdo@oneline@comb@v
7320 }% do@oneline@comb@v
7322 %--------------------------------------------------------------------
7323 % \find@nextpagewithpoints and \find@nextcolumnpage@v:
7325 \def\find@nextpagewithpoints#1{%
7326 % Called by \dofind@nextcolumnpage@v, \increment@index, and
7327 % \@multicolumntable.
7328 % The argument #1 should be the name of a counter with a nonnegative
7330 % We increase #1 by at least 1 to either the number of the
7331 % next page containing the appropriate kind of points, or to something
7332 % greater than \tbl@lastp.
7333 \addtocounter{#1}{1}%
7335 \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\value{#1}}}%
7336 \addto@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\value{#1}}}%
7337 % The sum is positive when at least one of them is positive.
7340 \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\value{#1}}}%
7342 \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\value{#1}}}%
7345 \ifhlfcntr@pos{tmp@hlfcntr}%
7346 \let\nextfind@nextpagewithpoints=\relax
7348 \ifnum \value{#1} > \tbl@lastp\relax
7349 \let\nextfind@nextpagewithpoints=\relax
7351 \def\nextfind@nextpagewithpoints{\find@nextpagewithpoints{#1}}%
7354 \nextfind@nextpagewithpoints
7355 }% find@nextpagewithpoints
7357 \def\find@nextcolumnpage@v#1{%
7358 % Called by \nextcolumn@index@v.
7359 % This is used for all multicolumn tables that are indexed by
7361 % We use \find@nextpagewithpoints to increment #1 to either
7362 % the (num@rows)'th page number after #1 that contains the
7363 % appropriate kind of points or to a value greater than \tbl@lastp.
7364 % We use pq@index@bpts as a scratch counter.
7365 \setcounter{pq@index@bpts}{0}%
7366 \dofind@nextcolumnpage@v{#1}%
7367 }% find@nextcolumnpage@v
7368 \def\dofind@nextcolumnpage@v#1{%
7369 % Called only by \find@nextcolumnpage@v.
7370 \addtocounter{pq@index@bpts}{1}%
7371 \find@nextpagewithpoints{#1}%
7372 \ifnum \value{pq@index@bpts} = \value{num@rows}\relax
7373 \let\nextdofind@nextcolumnpage@v=\relax
7375 % The following test shouldn't be needed, in theory, because the
7376 % computation of num@cols should prevent trouble, but we're being
7378 \ifnum \value{#1} > \tbl@lastp\relax
7379 \let\nextdofind@nextcolumnpage@v=\relax
7381 % Note: this is a \def, and not a \let, because we need to put
7382 % in the argument #1:
7383 \def\nextdofind@nextcolumnpage@v{\dofind@nextcolumnpage@v{#1}}%
7386 \nextdofind@nextcolumnpage@v
7387 }% dofind@nextcolumnpage@v
7389 %--------------------------------------------------------------------
7390 % \pointsinrange and \bonuspointsinrange, and then
7391 % \firstqinrange, \lastqinrange, and \numqinrange.
7394 % We say either \@bonusfalse or \@bonustrue, and then we check it only
7396 \def\pointsinrange#1{%
7399 \@ifundefined{exam@numpoints}%
7400 {\mbox{\normalfont\bfseries ??}}%
7404 \def\bonuspointsinrange#1{%
7407 \@ifundefined{exam@numpoints}%
7408 {\mbox{\normalfont\bfseries ??}}%
7410 }% bonuspointsinrange
7413 % Called by \read@range, \firstqinrange, \lastqinrange, and
7415 {\mbox{\normalfont\bfseries ??}}%
7416 \ClassWarning{exam}{%
7417 Grading range `\tbl@range' not defined.\MessageBreak
7418 \space\space Run LaTeX again.\MessageBreak
7423 % Called by \pointsinrange and \bonuspointsinrange.
7424 \@ifundefined{range@\tbl@range @firstq}%
7429 \@ifundefined{range@\tbl@range @lastq}%
7434 \edef\tbl@firstq{\csname range@\tbl@range @firstq\endcsname}%
7435 \edef\tbl@lastq{\csname range@\tbl@range @lastq\endcsname}%
7436 % Check that firstq precedes or equals lastq:
7437 \ifnum \tbl@firstq > \tbl@lastq\relax
7438 \fbox{\textbf{Error:} Grading Range `\tbl@range ':
7439 Last question precedes first question.}%
7441 In grading range `\tbl@range ',
7442 the last question\MessageBreak
7443 \space\space comes before the first question.\MessageBreak
7445 \string\begingradingrange \space must precede
7446 \string\endgradingrange \space by at
7447 least one question.\MessageBreak
7450 \count@pointsinrange
7456 \def\count@pointsinrange{%
7457 % Used for both \pointsinrange and \bonuspointsinrange:
7458 \set@hlfcntr{tbl@points}{0}%
7459 \setcounter{@iterator}{\tbl@firstq}%
7460 \addtocounter{@iterator}{-1}\do@countloop
7461 \prt@hlfcntr{tbl@points}%
7462 }% count@pointsinrange
7464 % We check \if@bonus here when needed:
7465 \addtocounter{@iterator}{1}%
7467 \@ifundefined{bonuspointsofq@\romannumeral \c@@iterator}%
7469 {\addto@hlfcntr{tbl@points}
7470 {\csname bonuspointsofq@\romannumeral \c@@iterator\endcsname}}%
7472 \@ifundefined{pointsofq@\romannumeral \c@@iterator}%
7474 {\addto@hlfcntr{tbl@points}
7475 {\csname pointsofq@\romannumeral \c@@iterator\endcsname}}%
7477 \ifnum \value{@iterator} < \tbl@lastq\relax
7478 \let\next@countloop=\do@countloop
7480 \let\next@countloop=\relax
7485 %--------------------------------------------------------------------
7486 % \firstqinrange, \lastqinrange, and \numqinrange.
7488 \newcommand{\firstqinrange}[1]{%
7490 \@ifundefined{range@\tbl@range @firstq}%
7492 {\csname range@#1@firstq\endcsname}%
7495 \newcommand{\lastqinrange}[1]{%
7497 \@ifundefined{range@\tbl@range @lastq}%
7499 {\csname range@#1@lastq\endcsname}%
7502 \newcommand{\numqinrange}[1]{%
7504 \@ifundefined{range@#1@firstq}%
7509 \@ifundefined{range@#1@lastq}%
7514 \setcounter{@iterator}{\csname range@#1@lastq\endcsname}%
7515 \addtocounter{@iterator}{-\csname range@#1@firstq\endcsname}%
7516 \stepcounter{@iterator}%
7523 %--------------------------------------------------------------------
7524 %--------------------------------------------------------------------
7526 % ***************************
7527 % ** SOLUTION ENVIRONMENTS **
7528 % ***************************
7532 % If the documentclass options include ``answers'', then the command
7533 % \printanswerstrue is given at the beginning of the run.
7535 % If the documentclass options include ``noanswers'', then the command
7536 % \printanswersfalse is given at the beginning of the run.
7538 \def\printanswers{\printanswerstrue}
7539 \def\noprintanswers{\printanswersfalse}
7541 % If the documentclass options include ``cancelspace'', then the
7542 % command \cancelspacetrue is given at the beginning of the run.
7544 % If the documentclass options include ``nocancelspace'', then the
7545 % command \cancelspacefalse is given at the beginning of the run.
7547 \def\cancelspace{\cancelspacetrue}
7548 \def\nocancelspace{\cancelspacefalse}
7550 % \if@insolution will be true while we're inside of any of the
7551 % solution environments. This is used to supress \PgInfo@write and
7552 % \label commands generated if there's a parts (or subparts, or
7553 % subsubparts) environment inside of a solution. (It won't suppress
7554 % the labels for the question objects, since a question object is
7555 % never a label that's been used before.)
7556 \newif\if@insolution
7559 \newcommand\SolutionEmphasis[1]{%
7560 \def\Solution@Emphasis{#1}%
7564 % If printanswers is true, we print the solution using a TheSolution
7565 % environment. If printanswers is false and cancelspace is false, we
7566 % insert blank vertical space equal to the optional argument (the
7567 % default value of which is 0pt).
7568 \newenvironment{solution}[1][0pt]%
7570 \@insolutiontrue % cancelled by the end of the environment
7571 \@addpointsfalse % cancelled by the end of the environment
7575 \begin{TheSolution}%
7584 \setbox\z@\vbox\bgroup
7595 % If printanswers is true, we print the solution using a TheSolution
7596 % environment. If printanswers is false and cancelspace is false,
7597 % we insert an empty box of width the current line width and of
7598 % height equal to the optional argument, which can be a length, or
7599 % \fill, or \stretch{number}. If the optional argument is omitted,
7600 % then the box is entirely omitted when printanswers is false.
7601 \newenvironment{solutionorbox}[1][-1pt]%
7603 \@insolutiontrue % cancelled by the end of the environment
7604 \@addpointsfalse % cancelled by the end of the environment
7608 \begin{TheSolution}%
7614 % Note: It's important that the following test be
7615 % ``\ifdim 0pt > #1'' rather than ``\ifdim #1 < 0pt''
7616 % That's because if the user says
7617 % ``\begin{solutionorbox}{\stretch{1}}''
7618 % (or \stretch{anythingelse}), then this will expand to
7619 % ``\ifdim 0pt > \z@ plus 1fill\relax''.
7620 % The \ifdim will be ``\ifdim 0pt > \z@'', and we'll have
7621 % ``plus 1fill\relax'' left over. This is OK because if the
7622 % \ifdim is false, that leftover stuff will be ignored,
7623 % and it will only be true if the user omitted the optional
7624 % argument, in which case there's no \stretch and thus no
7626 % If we said ``\ifdim #1 < 0pt'', then we'd get an error
7627 % when the user used \stretch, since the leftover stuff
7628 % would appear when TeX was looking for <, =, or >.
7635 \setbox\z@\vbox\bgroup
7646 % If printanswers is true, we print the solution using a TheSolution
7647 % environment. If printanswers is false and cancelspace is false,
7648 % we insert lined vertical space equal to the optional argument (the
7649 % default value of which is 0pt).
7650 \newenvironment{solutionorlines}[1][0pt]%
7652 \@insolutiontrue % cancelled by the end of the environment
7653 \@addpointsfalse % cancelled by the end of the environment
7657 \begin{TheSolution}%
7666 \setbox\z@\vbox\bgroup
7677 % If printanswers is true, we print the solution using a TheSolution
7678 % environment. If printanswers is false and cancelspace is false,
7679 % we insert dotted lined vertical space equal to the optional
7680 % argument (the default value of which is 0pt).
7681 \newenvironment{solutionordottedlines}[1][0pt]%
7683 \@insolutiontrue % cancelled by the end of the environment
7684 \@addpointsfalse % cancelled by the end of the environment
7688 \begin{TheSolution}%
7695 \fillwithdottedlines{#1}%
7697 \setbox\z@\vbox\bgroup
7708 % If printanswers is true, we print the solution using a TheSolution
7709 % environment. If printanswers is false and cancelspace is false,
7710 % we insert a grid occupying vertically the optional argument (the
7711 % default value of which is 0pt).
7712 \newenvironment{solutionorgrid}[1][0pt]%
7714 \@insolutiontrue % cancelled by the end of the environment
7715 \@addpointsfalse % cancelled by the end of the environment
7719 \begin{TheSolution}%
7728 \setbox\z@\vbox\bgroup
7740 % The environment TheSolution is called from the solution,
7741 % solutionorbox, solutionorlines, solutionordottedlines, and
7742 % solutionorgrid environments when printanswers is true. It uses
7743 % Donald Arseneau's framed.sty macros (included at the end of this
7744 % file) to allow the solution to be broken across pages and have each
7745 % piece enclosed in an fbox (or a colorbox, if the user has given the
7746 % command \shadedsolutions), (or no box at all, if the user has given
7747 % the command \unframedsolutions).
7749 % Of course, the user can change TheSolution with a \renewenvironment
7751 \newcommand{\solutiontitle}{\noindent\textbf{Solution:}\enspace}
7752 \newenvironment{TheSolution}%
7755 % If we don't set \leftskip and \rightskip to 0pt, then if we
7756 % appear inside of an \uplevel command we'd have indentation
7757 % inside of the solution box:
7760 % If the user said \unframedsolutions, then both
7761 % \if@framedsolutions and \if@shadedsolutions are false:
7763 % We'll use the default \exam@FrameCommand
7766 \def\exam@FrameCommand{\colorbox{SolutionColor}}%
7768 % It's \unframedsolutions:
7769 \def\exam@FrameCommand{}%
7772 \exam@MakeFramed{\advance\hsize-\exam@width}%
7781 \newif\if@framedsolutions
7782 \@framedsolutionstrue
7783 \newif\if@shadedsolutions
7784 \@shadedsolutionsfalse
7785 % If the user said \unframedsolutions, then both
7786 % \if@framedsolutions and \if@shadedsolutions are false.
7788 \def\framedsolutions{\@framedsolutionstrue\@shadedsolutionsfalse}
7789 \def\shadedsolutions{%
7790 \@ifundefined{definecolor}
7793 You must load the color package with the command\MessageBreak
7794 \space\space\protect\usepackage{color}\MessageBreak
7795 in order to use the command \protect\shadedsolutions
7798 This command makes use of the package color.sty,\MessageBreak
7799 and so you have to load color.sty before your\MessageBreak
7800 \protect\begin{document} command.\MessageBreak
7804 \definecolor{SolutionColor}{gray}{0.8}
7805 \@shadedsolutionstrue
7806 \@framedsolutionsfalse
7809 \def\unframedsolutions{\@framedsolutionsfalse\@shadedsolutionsfalse}
7812 % The solutionbox environment is different from the other solution
7813 % environments (solution, solutionorbox, solutionorlines,
7814 % solutionordottedlines, and solutionorgrid), in that
7816 % (1) The box is always printed, whether answers are being printed
7819 % (2) The argument giving the size of the box is a required
7820 % argument, not an optional argument, and so it should be enclosed
7821 % in braces, not in brackets. It can be either a length or
7824 % (3) We make no use of the TheSolution environment; the solutionbox
7825 % environment is completely freestanding.
7827 % If answers are not being printed then only the box is printed, with
7828 % nothing in it. If answers are being printed, then the solution is
7829 % printed inside of the box.
7831 % Note: It's the user's responsibility to be sure that the box is
7832 % large enough to hold the solution! If the solution takes up too
7833 % much vertical space, then it will spill out of the bottom of the
7834 % box, overwriting whatever follows the box.
7836 % 2016/02/08: The solutionbox frame can now be printed in color, as
7837 % long as you load color.sty in the preamble.
7841 % \usepackage{color}
7843 % in the preamble, and then give the command
7845 % \colorsolutionboxes
7847 % to have the frame around a solutionbox in color. The default color
7848 % was created by the command
7850 % \definecolor{SolutionBoxColor}{gray}{0.8}
7852 % and you can change the color by giving a new \definecolor command
7853 % (which must be done *after* the \colorsolutionboxes command).
7855 % To cancel color solutionbox frames and return to black, give the
7858 % \nocolorsolutionboxes
7860 \newif\if@colorsolutionboxes
7861 \@colorsolutionboxesfalse
7862 \def\colorsolutionboxes{%
7863 \@ifundefined{definecolor}
7866 You must load the color package with the command\MessageBreak
7867 \space\space\protect\usepackage{color}\MessageBreak
7868 in order to use the command \protect\colorsolutionboxes
7871 This command makes use of the package color.sty,\MessageBreak
7872 and so you have to load color.sty before your\MessageBreak
7873 \protect\begin{document} command.\MessageBreak
7877 \definecolor{SolutionBoxColor}{gray}{0.8}
7878 \@colorsolutionboxestrue
7881 \def\nocolorsolutionboxes{\@colorsolutionboxesfalse}
7884 \newenvironment{solutionbox}[1]{%
7885 \@insolutiontrue % cancelled by the end of the environment
7886 \@addpointsfalse % cancelled by the end of the environment
7887 \def\solutionbox@size{#1}% saved for end of environment
7888 % Change, 2016/02/08: So that the solutionbox environment will work
7889 % correctly inside of a tabular environment, we use \hsize instead of
7891 % \@tempdima=\textwidth
7893 \advance\@tempdima -\@totalleftmargin
7894 \advance\@tempdima -6\fboxsep
7895 \advance\@tempdima -2\fboxrule
7896 % Confine the \Solution@Emphasis, as well as anything the user puts
7897 % into the solution (e.g., \color{red}, or whatever); don't say
7898 % \endgroup until after using \box\exam@box:
7901 % We save the solution in a box of the proper width. We'll either
7902 % print it (if we're printing solutions) or throw it away by just
7903 % not using it before the environment ends:
7904 \setbox\exam@box=\vtop\bgroup
7909 % Change, 2016/05/09: We change \@totalleftmargin and \linewidth in
7910 % case there are enumerate, itemize, or description environments
7911 % inside the solution:
7912 \@totalleftmargin=0pt
7920 % OK, the solution is now inside \box\exam@box.
7921 % Set the height and depth to 0pt, so that if we use it we won't
7922 % be advancing our position on the page:
7928 % We enclose the \vtop in an \hbox to avoid having the
7929 % indentation of the enclosing list environment (implemented via
7930 % \parshape) shift us to the right when we enter horizontal
7931 % mode. If we don't use this \hbox, then we'd have to comment
7932 % out the \hskip \@totalleftmargin:
7933 % 2016/02/08: Changed \textwidth to \hsize:
7936 \hskip\@totalleftmargin
7937 \hskip3\fboxsep\hskip\fboxrule
7940 \par\nointerlineskip
7942 \endgroup % Finish confining the \Solution@Emphasis
7943 % Starting in version 2.502, 2016/03/23,the decision of whether to
7944 % color the box is made in the \makeemptybox command:
7945 \makeemptybox{\solutionbox@size}
7946 }% End of the second argument of \newenvironment{solutionbox}
7949 %--------------------------------------------------------------------
7950 %--------------------------------------------------------------------
7951 % Added in version 2.502: 2016/03/23, \colorfbox
7953 % The \colorfbox command is used in our modification of framed.sty
7954 % that allows us to print the frame around the solution in color when
7955 % the user has given the command \colorsolutionboxes. It takes two
7956 % arguments, the first being the color for the frame, and the second
7957 % being the stuff to be framed.
7959 % If we had assumed that xcolor.sty was used (instead of just
7960 % color.sty), then the line that saves the current color in
7961 % saved@color could have been just
7963 % \colorlet{saved@color}{.}
7965 % but we wanted to make this work even if color.sty is being used.
7967 % When you define a color mycolor using either color.sty or
7968 % xcolor.sty, a macro \csname\string\color@ mycolor\endcsname is
7969 % defined (i.e., the macro name is \\color@mycolor).
7970 \newcommand{\colorfbox}[2]{%
7971 % Save the current color in saved@color:
7972 \expandafter\let\csname\string\color@saved@color\endcsname\current@color
7973 % Create the box in color #1, with the text in saved@color
7974 % (the braces are to confine the color change commands):
7975 {\color{#1}\fbox{\color{saved@color}#2}}%
7978 %--------------------------------------------------------------------
7979 %--------------------------------------------------------------------
7981 % The following stuff is lifted from:
7983 % framed.sty v 0.8a 21-Jul-2003
7984 % Copyright (C) 1992-2003 by Donald Arseneau
7985 % These macros may be freely transmitted, reproduced, or modified
7986 % provided that this notice is left intact.
7988 % The modifications I made are marked with ``psh'' in a comment:
7990 % Further modifications, 2017-09-21
7991 % I changed the names of many commands by prepending ``exam@'', so
7992 % that the user can use the framed.sty package with exam.cls and not
7993 % have conflicts. (I also renamed the framed, shaded, and leftbar
7994 % environments to examframed, examshaded, and examleftbar.) I didn't
7995 % mark these name changes.
7997 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7998 % Create framed or shaded regions that can break across pages using
7999 % \begin{examframed} ... \end{examframed} -- ordinary frame box
8001 % \begin{examshaded} ... \end{examshaded} -- shaded background
8003 % ... examleftbar ... -- line on left side
8004 % \begin{MakeFramed}{settings} ... \end{MakeFramed}
8005 % -- generic frame (for new environments)
8007 % The "examframed" environment puts the text into "\fbox" with the
8008 % settings "\fboxrule=\exam@FrameRule" and "\fboxsep=\exam@FrameSep".
8009 % You can change these lengths (using "\setlength") and you
8010 % can even change the definition of "\exam@FrameCommand" to use
8011 % much fancier boxes.
8013 % In fact, the "shaded" environment just redefines "\exam@FrameCommand"
8014 % to use "\colorbox{shadecolor}" (and you have to define the
8015 % color "shadecolor": \newcolor{shadecolor}...).
8017 % A page break is allowed, and even encouraged, before the framed
8018 % environment. If you want to attach some text (a box title) to the
8019 % frame, then the text should be inserted by \exam@FrameCommand
8021 % The contents of the framed regions are restricted:
8022 % Floats, footnotes, marginpars and head-line entries will be lost.
8023 % (Some of these may be handled in a later version.)
8024 % This package will not work with the page breaking of multicol.sty,
8025 % or other systems that perform column-balancing.
8027 % The MakeFramed environment does the work. Its "settings" argument
8028 % should contain any adjustments to the text width (applied to \hsize,
8029 % and using the "\exam@width" of the frame itself) as well as a `restore'
8030 % command -- \@parboxrestore or \exam@FrameRestore or something similar.
8033 % \exam@MakeFramed, \endexam@MakeFramed: the "MakeFramed" environment
8034 % \exam@FrameCommand: command to draw the frame around its argument
8035 % \exam@FrameRestore: restore some text settings, but fewer than
8037 % \exam@FrameRule: length register; \fboxrule for default "framed".
8038 % \exam@FrameSep: length register; \fboxsep for default "framed".
8039 % \exam@frameHeightAdjust: macro; height of frame above baseline at
8042 % This is still a `pre-production' version because I can think of many
8043 % features/improvements that should be made. Nevertheless, starting
8044 % with version 0.5 it should be bug-free.
8046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8048 %psh: Commented out \ProvidesPackage:
8049 %\ProvidesPackage{framed}[2003/07/21 v 0.8a:
8050 % framed or shaded text with page breaks]
8052 %psh: Created \saved@totalleftmargin and \@sollistdepth:
8053 \newdimen\saved@totalleftmargin
8054 \newcount\@sollistdepth
8056 \newenvironment{examframed}% using default \exam@FrameCommand
8057 {\exam@MakeFramed {\advance\hsize-\exam@width \exam@FrameRestore}}%
8058 {\endexam@MakeFramed}
8060 \newenvironment{examshaded}{%
8061 \def\exam@FrameCommand{\colorbox{shadecolor}}%
8062 \exam@MakeFramed {\exam@FrameRestore}}%
8063 {\endexam@MakeFramed}
8065 \newenvironment{examleftbar}{%
8066 \def\exam@FrameCommand{\vrule width 3pt \hspace{10pt}}%
8067 \exam@MakeFramed {\advance\hsize-\exam@width \exam@FrameRestore}}%
8068 {\endexam@MakeFramed}
8070 \chardef\exam@FrameRestore=\catcode`\| % for debug
8071 \catcode`\|=\catcode`\% % (debug: insert space after backslash)
8073 \def\exam@MakeFramed#1{\par
8074 % measure added width and height; call result \exam@width and \exam@height
8075 \setbox\z@\vbox{\vskip-1in \hbox{\hskip-1in
8076 \exam@FrameCommand{\hbox{\vrule \@height .7in \@depth.3in \@width 1in}}}%
8078 \def\exam@width{\wd\z@}\def\exam@height{\ht\z@}%
8079 \edef\exam@fb@frw{\the\exam@width}\edef\exam@fb@frh{\the\exam@height}%
8080 % insert pre-penalties and skips
8084 \penalty9999 % updates \page parameters
8085 \ifdim\pagefilstretch=\z@ \ifdim\pagefillstretch=\z@
8086 \edef\@tempa{\the\skip@}%
8087 \ifx\@tempa\exam@zero@glue \penalty-30
8088 \else \vskip-\skip@ \penalty-30 \vskip\skip@
8091 % Give a stretchy breakpoint that will always be taken in preference
8092 % to the \penalty 9999 used to update page parameters. The cube root
8093 % of 10000/100 indicates a multiplier of 0.21545, but the maximum
8094 % calculated badness is really 8192, not 10000, so the multiplier
8096 \advance\skip@ \z@ plus-.5\baselineskip
8097 \advance\skip@ \z@ plus-.231\exam@height
8098 \advance\skip@ \z@ plus-.231\skip@
8099 \advance\skip@ \z@ plus-.231\topsep
8100 \vskip-\skip@ \penalty 1800 \vskip\skip@
8102 \addvspace{\topsep}%
8104 % clear out pending page break
8105 \penalty\@M \vskip 2\baselineskip \vskip\exam@height
8106 \penalty9999 \vskip -2\baselineskip \vskip-\exam@height
8107 \penalty9999 % updates \pagetotal
8108 |\message{After clearout, \pagetotal=\the\pagetotal, \pagegoal=\the\pagegoal. }%
8110 %psh: Added commands:
8111 \advance\hsize-\@totalleftmargin
8112 \saved@totalleftmargin=\@totalleftmargin
8113 \@totalleftmargin=0pt
8115 \let\@listdepth=\@sollistdepth
8118 %psh: end of added commands
8119 \setbox\@tempboxa\vbox\bgroup
8120 #1% Modifications to \hsize (can use \exam@width and \exam@height)
8121 \textwidth\hsize \columnwidth\hsize
8122 %psh: added one line:
8126 \def\endexam@MakeFramed{\par
8127 \kern\z@ \penalty-100 % put depth into height
8129 \begingroup \exam@put@frame \endgroup
8130 %psh: Added one line:
8131 \@totalleftmargin=\saved@totalleftmargin
8134 % \exam@put@frame takes the contents of \@tempboxa and puts all, or a
8135 % piece, of it on the page with a frame (\exam@FrameCommand). It
8136 % recurses until all of \@tempboxa has been used up. (\@tempboxa must
8139 \def\exam@put@frame{\relax
8140 \ifdim\pagegoal=\maxdimen \pagegoal\vsize \fi
8141 | \message{=============== Entering putframe ====================^^J
8142 | \pagegoal=\the\pagegoal, \pagetotal=\the\pagetotal. }%
8144 \dimen@\pagegoal \advance\dimen@-\pagetotal % natural space left on page
8145 \ifdim\dimen@<2\baselineskip
8146 | \message{Page has only \the\dimen@\space room left; eject. }%
8147 \eject \exam@fb@adjheight \exam@put@frame
8148 \else % there's appreciable room left on the page
8149 | \message{\string\pagetotal=\the\pagetotal,
8150 | \string\pagegoal=\the\pagegoal,
8151 | \string\pagestretch=\the\pagestretch,
8152 | \string\pageshrink=\the\pageshrink,
8153 | \string\exam@fb@frh=\exam@fb@frh. \space}
8154 | \message{Box of size \the\ht\@tempboxa\space + \exam@fb@frh}%
8155 \begingroup % temporarily set \dimen@ to be...
8156 \advance\dimen@.8\pageshrink % maximum space available on page
8157 \advance\dimen@-\exam@fb@frh\relax % space available for frame's contents
8158 \expandafter\endgroup
8159 % restore \dimen@ to real room left on page
8160 \ifdim\dimen@>\ht\@tempboxa % whole box does fit
8161 | \message{fits in \the\dimen@. }%
8162 \else % box must be split
8163 | \message{must be split to fit in \the\dimen@. }%
8164 \setbox\@tempboxa\vbox{% simulate frame and flexiblity of the page:
8165 \vskip \exam@fb@frh \@plus\pagestretch \@minus.8\pageshrink
8166 \kern137sp\kern-137sp\penalty-30
8168 \edef\exam@fb@resto@set{\boxmaxdepth\the\boxmaxdepth
8169 \splittopskip\the\splittopskip}%
8170 \boxmaxdepth\z@ \splittopskip\z@
8171 \setbox\tw@\vsplit\@tempboxa to\dimen@
8172 \setbox\tw@\vbox{\unvbox\tw@}% natural-sized
8173 | \message{Box of size \the\ht\@tempboxa\space split to \the\dimen@.
8174 | Natural height of split box is \the\ht\tw@. }%
8175 % If the split-to size > (\vsize-\topskip), then set box to full size
8177 \advance\dimen@\topskip
8178 \expandafter\endgroup
8179 \ifdim\dimen@>\pagegoal
8180 | \message{Frame is big -- Use up the full column. }%
8182 \advance\dimen@ii -\topskip
8183 \advance\dimen@ii \exam@frameHeightAdjust\relax
8184 \else % suspect this is wrong:
8185 % If the split-to size > feasible room_on_page, rebox it smaller.
8186 \advance\dimen@.8\pageshrink
8187 \ifdim\ht\tw@>\dimen@
8188 | \message{Box too tall; rebox it to \the\dimen@. }%
8190 \else % use natural size
8194 % Re-box contents to desired size \dimen@ii
8195 \advance\dimen@ii -\exam@fb@frh
8196 \setbox\tw@\vbox to\dimen@ii \bgroup
8197 % remove simulated frame and page flexibility:
8198 \vskip -\exam@fb@frh \@plus-\pagestretch \@minus-.8\pageshrink
8199 \unvbox\tw@ \unpenalty\unpenalty
8200 \ifdim\lastkern=-137sp % whole box went to next page
8201 | \message{box split at beginning! }%
8202 \egroup \exam@fb@resto@set \eject % (\vskip for frame size
8206 \egroup \exam@fb@resto@set
8207 \ifvoid\@tempboxa % it all fit after all
8208 | \message{box split at end! }%
8209 \setbox\@tempboxa\box\tw@
8210 \else % it really did split
8211 | \message{box split as expected. Its reboxed height is \the\ht\tw@. }%
8213 %psh: Changed the command that inserts the box:
8214 % Instead of \centerline, we shift right by \saved@totalleftmargin:
8215 % \centerline{\exam@FrameCommand{\box\tw@}}% ??? \centerline bad idea
8216 \hbox{\hskip \saved@totalleftmargin\exam@FrameCommand{\box\tw@}}%
8218 | \message{Zero width means likely blank. Don't frame it (guess)}%
8226 \ifvoid\@tempboxa\else
8227 %psh: Changed the command that inserts the box:
8228 % Instead of \centerline, we shift right by \saved@totalleftmargin:
8229 % \centerline{\exam@FrameCommand{\box\@tempboxa}}%
8230 \hbox{\hskip\saved@totalleftmargin\exam@FrameCommand{\box\@tempboxa}}%
8231 \nointerlineskip \null %{\showoutput \showlists}
8232 \penalty-30 \vskip\topsep
8235 \def\exam@fb@adjheight{%
8236 \vbox to\exam@frameHeightAdjust{}% get proper baseline skip from above.
8237 \penalty\@M \nointerlineskip
8238 \vskip-\exam@frameHeightAdjust
8239 \penalty\@M} % useful for tops of pages
8241 \edef\exam@zero@glue{\the\z@skip}
8243 \catcode`\|=\exam@FrameRestore
8245 % Provide configuration commands:
8246 %psh: Version 2.502, 2016/03/23, changed \exam@FrameCommand so that the
8247 % frame is printed in color if the user has said
8248 % \colorsolutionboxes:
8249 %\providecommand\exam@FrameCommand{\fboxrule=\exam@FrameRule
8250 %\fboxsep=\exam@FrameSep \fbox}
8251 \def\exam@FrameCommand{\fboxrule=\exam@FrameRule \fboxsep=\exam@FrameSep
8252 \if@colorsolutionboxes
8253 \def\box@it{\colorfbox{SolutionBoxColor}}%
8258 }% \exam@FrameCommand
8260 \@ifundefined{FrameRule}{\newdimen\exam@FrameRule \exam@FrameRule=\fboxrule}{}
8261 \@ifundefined{FrameSep} {\newdimen\exam@FrameSep \exam@FrameSep =3\fboxsep}{}
8263 % Height of frame above first baseline when frame starts a page:
8264 \providecommand\exam@frameHeightAdjust{6pt}
8266 % \exam@FrameRestore has parts of \@parboxrestore. See how it is used in the
8267 % "settings" argument of \MakeFrame. Previous behavior can be restored by
8268 % using \@parboxrestore there, or redefining:
8269 % \makeatletter \renewcommand\exam@FrameRestore{\@parboxrestore} \makeatother
8270 \def\exam@FrameRestore{%
8271 \let\if@nobreak\iffalse
8272 \let\if@noskipsec\iffalse
8275 \let\'\@acci\let\`\@accii\let\=\@acciii
8276 % \parindent\z@ \parskip\z@skip Definitely omit!
8279 % \@totalleftmargin\z@
8280 % \leftskip\z@skip \rightskip\z@skip \@rightskip\z@skip
8281 % \parfillskip\@flushglue \lineskip\normallineskip
8282 % \baselineskip\normalbaselineskip
8287 % Compatibility with previous versions (temporary!):
8288 % psh: we'll remove this 2017-09-21
8289 %\let\fram@d=\MakeFramed \let\endfram@d=\endMakeFramed
8291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8293 % This ends the stuff that's lifted from:
8294 % % framed.sty v 0.8a 21-Jul-2003
8295 % % Copyright (C) 1992-2003 by Donald Arseneau
8298 %--------------------------------------------------------------------
8299 %--------------------------------------------------------------------
8302 %---------------------------------------------------------------------
8303 %---------------------------------------------------------------------
8304 %---------------------------------------------------------------------
8305 %---------------------------------------------------------------------
8306 %---------------------------------------------------------------------