]> git.donarmstrong.com Git - lib.git/blob - texmf/tex/latex/exam.cls
use yasnippet from straight
[lib.git] / texmf / tex / latex / exam.cls
1 % exam.cls
2 %
3 % A LaTeX2e document class for preparing exams.
4
5 %% exam.cls
6 %% Copyright (c) 1994, 1997, 2000, 2004, 2008, 2011,
7 %% 2015, 2017 Philip S. Hirschhorn
8 %
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.
16 %
17 % This work has the LPPL maintenance status "author-maintained".
18
19 % This work consists of the files exam.cls and examdoc.tex.
20
21
22 % The user's guide for exam.cls is in the file examdoc.tex.
23
24
25 %%% Philip Hirschhorn
26 %%% Department of Mathematics
27 %%% Wellesley College
28 %%% Wellesley, MA 02481
29 %%% psh@math.mit.edu
30
31 % The newest version of this documentclass should always be available
32 % from my web page: http://www-math.mit.edu/~psh/
33
34
35 \def\fileversion{2.603}
36 \def\filedate{2017/12/17}
37 %---------------------------------------------------------------------
38 %---------------------------------------------------------------------
39
40 % If there's some feature that you'd like that this file doesn't
41 % provide, tell me about it.
42
43 %
44 %
45 %
46 %
47 % Thanks to:
48 %
49 % Piet van Oostrum, from whose excellent ``fancyheadings.sty'' we
50 % shamelessly stole most of the code for setting the headers and
51 % footers.
52 %
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''.
56 %
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
62 % his.)
63 %
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.)
70 %
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.) 
74 %
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.
83 %
84 %--------------------------------------------------------------------
85 %--------------------------------------------------------------------
86 %                    Changelog since version 2.4:
87
88 %--------------------------------------------------------------------
89 % Version 2.603, 2017/12/15
90
91 % No longer betatest.
92
93 %--------------------------------------------------------------------
94 % Version 2.602$\beta$, 2017/12/15
95
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).
99
100 %--------------------------------------------------------------------
101 % Version 2.601$\beta$, 2017/09/22
102
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
107
108 %--------------------------------------------------------------------
109 % Version 2.6, 2017/09/19
110
111 % No longer betatest.
112
113 %--------------------------------------------------------------------
114 % Version 2.510$\beta$, 2016/10/11
115
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.
128
129 %--------------------------------------------------------------------
130 % Version 2.509$\beta$, 2016/09/12
131
132 % Multicolumn grade and point tables, and a new syntax for multirow
133 % grade and point tables (which were introduced in version
134 % 2.508beta).
135
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).
141
142 % The tables can be:
143
144 %   grade tables or point tables,
145
146 %   plain, bonus, or combined,
147
148 %   indexed by questions or by pages,
149
150 %   complete or partial.
151
152 % As usual, if you omit the optional argument that chooses between
153 % questions and pages, you get questions.
154
155 % The new commands are:
156
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]
163
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]
170
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]
177
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]
184
185 % The older grade and point table commands can still be used.  For
186 % example, the commands
187
188 %   \gradetable[h][questions]
189 %   \multirowgradetable{1}[questions]
190
191 % are equivalent.
192
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,
196 % as in
197
198 %   \setlength{\doublerulesep}{0.5in}
199
200 %--------------------------------------------------------------------
201 % Version 2.508$\beta$, 2016/08/06
202
203 % New commands: Multirow grade and point tables.
204
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.
210
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
214
215 % \multirowgradetable{numrows}[questions or pages]
216
217 % The tables can be:
218
219 %   grade tables or point tables,
220
221 %   plain, bonus, or combined,
222
223 %   indexed by questions or by pages,
224
225 %   complete or partial.
226
227 % The new commands are:
228
229
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]
236
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]
243
244 %--------------------------------------------------------------------
245 % Version 2.507$\beta$, 2016/07/14
246
247 % New commands:
248
249 %   \pointstwosided
250 %   \pointstwosidedreversed
251
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.
254
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.
257
258 % Also: Some minor edits (e.g., deleting the unused \thebonuspoints).
259
260 %--------------------------------------------------------------------
261 % Version 2.506$\beta$, 2016/05/12
262
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.
273
274 %--------------------------------------------------------------------
275 % Version 2.505$\beta$, 2016/05/10
276
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.)
285
286 %--------------------------------------------------------------------
287 % Version 2.504$\beta$, 2016/05/09
288
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.
293
294 %--------------------------------------------------------------------
295 % Version 2.503$\beta$, 2016/03/25
296
297 % New commands:
298
299 %      \colorfillwithlines
300 %      \colorfillwithdottedlines
301
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 
304
305 %      \definecolor{FillWithLinesColor}{gray}{0.8}
306
307 % and the color can be changed by giving a new \definecolor command.
308 % You can return to black lines by giving the command
309
310 %      \nocolorfillwithlines
311
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 
315
316 %      \definecolor{FillWithDottedLinesColor}{gray}{0.8}
317
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
320
321 %      \nocolorfillwithdottedlines
322
323 %--------------------------------------------------------------------
324 % Version 2.502$\beta$, 2016/03/23
325
326 % The command
327
328 %   \colorsolutionboxes
329
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.
334
335 %--------------------------------------------------------------------
336 % Version 2.501$\beta$, 2016/02/08
337
338 % Changed the \solutionbox environment so that it works correctly
339 % inside a tabular.
340
341 % Also: The \solutionbox frame can now be printed in color, as long as
342 % you load color.sty in the preamble.
343 %
344 %  Usage: Say
345 %
346 %   \usepackage{color}
347 %
348 % in the preamble, and then give the command
349 %
350 %   \colorsolutionboxes
351 %
352 % to have the frame around a solutionbox in color.  The default color
353 % was created by the command
354 %
355 %   \definecolor{SolutionBoxColor}{gray}{0.8}
356 %
357 % and you can change the color by giving a new \definecolor command
358 % (which must be done *after* the \colorsolutionboxes command).
359 %
360 % To cancel color solutionbox frames and return to black, give the
361 % command
362 %
363 %   \nocolorsolutionboxes
364
365 %--------------------------------------------------------------------
366 % Version 2.5 2015/05/07
367
368 % No longer betatest.
369
370 %--------------------------------------------------------------------
371 % Version 2.408$\beta$ 2013/11/17
372
373 % New commands:
374 %
375 %   \firstqinrange{whatever}
376 %   \lastqinrange{whatever}
377 %   \numqinrange{whatever}
378 %
379 % where ``whatever'' is the name of a grading range.
380 %
381 % \firstqinrange{whatever} prints the number of the first question in
382 % the range.
383 %
384 % \lastqinrange{whatever} prints the number of the last question in the
385 % range.
386 %
387 % \numqinrange{whatever} prints the number of questions in the range.
388 %
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
391
392 %   \range@myrange@firstp
393 %   \range@myrange@lastp
394 %   \range@myrange@firstq
395 %   \range@myrange@lastq
396 %
397 % where we used to use
398 %
399 %   \tbl@myrange@firstp
400 %   \tbl@myrange@lastp
401 %   \tbl@myrange@firstq
402 %   \tbl@myrange@lastq
403
404 %--------------------------------------------------------------------
405 % Version 2.407$\beta$ 2012/12/19
406
407 % New environment:
408 %
409 %   solutionbox
410 %
411 % The solutionbox environment is different from the other solution
412 % environments (solution, solutionorbox, solutionorlines,
413 % solutionordottedlines, and solutionorgrid), in that
414 %
415 %   (1) The box is always printed, whether answers are being printed
416 %   or not.
417 %
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
421 %   \stretch{number}.
422 %
423 %   (3) We make no use of the TheSolution environment; the solutionbox
424 %   environment is completely freestanding.
425 %
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.
429 %
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.
434 %
435 %--------------------------------------------------------------------
436 % Version 2.406$\beta$, 2012/12/16
437 %
438 % New command:
439 %
440 %   \noquestionsonthispage
441 %
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.
446 %
447 %
448 % If you give the command \noquestionsonthispage on a page, then
449 %
450 %   (1) \ifcontinuation on that page will expand to its second
451 %   argument,
452 %   (2) \ifincomplete on that page will expand to its second
453 %   argument, and
454 %   (3) an \ifincomplete on an earlier page will not assume that a
455 %   question from that earlier page continues onto this page.
456 %
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.
465 %
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.
469 %
470 %--------------------------------------------------------------------
471 % Version 2.405$\beta$, 2012/10/21
472 %
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
478 % on the exam.
479 %
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.
487 %
488 %--------------------------------------------------------------------
489 % Version 2.404$\beta$, 2012/09/03
490 %
491 % New command:
492 %
493 %   \fillwithgrid{length}
494 %
495 % New environment:
496 %
497 %   solutionorgrid
498 %
499 % These are similar to the \fillwithlines command and the
500 % solutionorlines environment.
501 %
502 % By default, the created grids are in black.  However, if you give the
503 % commands
504 %
505 % \usepackage{color}
506 % \colorgrids
507 %
508 % then the grids will be in color, by default a light gray.  That
509 % default color was defined by the command
510 %
511 % \definecolor{GridColor}{gray}{0.8}
512 %
513 % You can change the color by redefining the color GridColor, and you
514 % can return to using black grids by giving the command
515 %
516 % \nocolorgrids
517 %
518 % The default grid size and grid line thickness were set by the
519 % commands
520 %
521 % \setlength{\gridsize}{5mm}
522 % \setlength{\gridlinewidth}{0.1pt}
523 %
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.
531 %
532 %--------------------------------------------------------------------
533 % Version 2.403$\beta$, 2012/08/29:
534 %
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
540 % arguments.
541 %
542 %--------------------------------------------------------------------
543 % Version 2.402$\beta$, 2012/08/21:
544 %
545 % We modified the command \fillin that we had created in version
546 % 2.401beta.  \fillin now takes two optional arguments (and no required
547 % arguments).
548 %
549 % \fillin can take two optional arguments, as in
550 %
551 % \fillin[Answer][Length]
552 %
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.
556 %
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
560 %
561 %   \setlength\fillinlinelength{1in}
562 %
563 % and can be changed by giving a new \setlength command.
564 %
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.
569 %
570 %--------------------------------------------------------------------
571 % Version 2.401$\beta$, 2012/08/20:
572 %
573 %
574 % New command:
575 %
576 %   \fillin[CorrectAnswer]{width}
577 %
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.
585 %
586 % Note: We changed this command in version 2.401beta.
587 %
588 %--------------------------------------------------------------------
589 %--------------------------------------------------------------------
590 %--------------------------------------------------------------------
591
592 \NeedsTeXFormat{LaTeX2e}
593
594 \ProvidesClass{exam}[\filedate\space Version \fileversion\space by
595   Philip Hirschhorn]
596
597 \RequirePackage{ifthen}
598
599 \newif\ifprintanswers
600 \printanswersfalse
601 \DeclareOption{answers}{\printanswerstrue}
602 \DeclareOption{noanswers}{\printanswersfalse}
603
604 \newif\ifcancelspace
605 \cancelspacefalse
606 \DeclareOption{cancelspace}{\cancelspacetrue}
607 \DeclareOption{nocancelspace}{\cancelspacefalse}
608
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.
619 \newif\if@addpoints
620 \newif\if@printtotalpoints
621 \def\addpoints{\global\@addpointstrue\global\@printtotalpointstrue}
622 \def\noaddpoints{\global\@addpointsfalse}
623 \@addpointsfalse
624 \@printtotalpointsfalse
625 \DeclareOption{addpoints}{\addpoints}
626
627
628 \DeclareOption*{%
629   \PassOptionsToClass{\CurrentOption}{article}%
630 }
631 \ProcessOptions\relax
632 \LoadClass{article}
633
634
635
636
637 %                         *****************
638 %                         ** PAGE LAYOUT **
639 %                         *****************
640
641
642 % We set the parameters in terms of \paperwidth and \paperheight
643 % so that the options
644
645 % a4paper
646 % a5paper
647 % b5paper
648 % letterpaper
649 % legalpaper
650 % executivepaper
651 % landscape
652
653 % will all work:
654
655 \setlength{\textwidth}{\paperwidth}
656 \addtolength{\textwidth}{-2in}
657 \setlength{\oddsidemargin}{0pt}
658 \setlength{\evensidemargin}{0pt}
659
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}
668
669 \setlength{\marginparwidth}{.5in}
670 \setlength{\marginparsep}{5pt}
671
672 %--------------------------------------------------------------------
673
674 %                          ****************
675 %                          ** EXTRAWIDTH **
676 %                          ****************
677
678 \newlength\@extrawidth
679
680 % \@rightmargin is needed for \pointsinrightmargin and
681 % \pointsdroppedatright, so that we can right justify the points:
682 \newlength\@rightmargin
683 \setlength{\@rightmargin}{1in}
684
685 % We put the argument of \extrawidth into a length so that it will
686 % work correctly even if it's negative:
687
688 \def\extrawidth#1{%
689   \@extrawidth=#1
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
697 }
698
699 %--------------------------------------------------------------------
700 %--------------------------------------------------------------------
701 %             Making room for large headers and footers
702
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:
708
709 \newlength\@extrahead
710 \newlength\@extrafoot
711 \setlength{\@extrahead}{0in}
712 \setlength{\@extrafoot}{0in}
713
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:
717 \newlength\run@exhd
718 \newlength\fp@exhd
719 \newlength\run@exft
720 \newlength\fp@exft
721 \newlength\covrun@exhd
722 \newlength\covfp@exhd
723 \newlength\covrun@exft
724 \newlength\covfp@exft
725
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}
734
735 \newcommand*\adj@hdht@ftht{%
736   \if@coverpages
737     \ifnum\value{page}=1\relax
738       \@setheadheight{\covfp@exhd}%
739       \@setfootheight{\covfp@exft}%
740     \else
741       \@setheadheight{\covrun@exhd}%
742       \@setfootheight{\covrun@exft}%
743     \fi
744   \else
745     \ifnum\value{page}=1\relax
746       \@setheadheight{\fp@exhd}%
747       \@setfootheight{\fp@exft}%
748     \else
749       \@setheadheight{\run@exhd}%
750       \@setfootheight{\run@exft}%
751     \fi
752   \fi
753 }
754
755 \newcommand*\extraheadheight{%
756   \@ifnextchar[{\@xtrahd}{\@ytrahd}%
757 }
758
759 \def\@xtrahd[#1]#2{%
760   \setlength{\fp@exhd}{#1}%
761   \setlength{\run@exhd}{#2}%
762   \adj@hdht@ftht
763 }
764
765 \def\@ytrahd#1{%
766   \setlength{\fp@exhd}{#1}%
767   \setlength{\run@exhd}{#1}%
768   \adj@hdht@ftht
769 }
770
771 \newcommand*\extrafootheight{%
772   \@ifnextchar[{\@xtraft}{\@ytraft}%
773 }
774
775 \def\@xtraft[#1]#2{%
776   \setlength{\fp@exft}{#1}%
777   \setlength{\run@exft}{#2}%
778   \adj@hdht@ftht
779 }
780
781 \def\@ytraft#1{%
782   \setlength{\fp@exft}{#1}%
783   \setlength{\run@exft}{#1}%
784   \adj@hdht@ftht
785 }
786
787 \newcommand*\coverextraheadheight{%
788   \@ifnextchar[{\cov@xtrahd}{\cov@ytrahd}%
789 }
790
791 \def\cov@xtrahd[#1]#2{%
792   \setlength{\covfp@exhd}{#1}%
793   \setlength{\covrun@exhd}{#2}%
794   \adj@hdht@ftht
795 }
796
797 \def\cov@ytrahd#1{%
798   \setlength{\covfp@exhd}{#1}%
799   \setlength{\covrun@exhd}{#1}%
800   \adj@hdht@ftht
801 }
802
803 \newcommand*\coverextrafootheight{%
804   \@ifnextchar[{\cov@xtraft}{\cov@ytraft}%
805 }
806
807 \def\cov@xtraft[#1]#2{%
808   \setlength{\covfp@exft}{#1}%
809   \setlength{\covrun@exft}{#2}%
810   \adj@hdht@ftht
811 }
812
813 \def\cov@ytraft#1{%
814   \setlength{\covfp@exft}{#1}%
815   \setlength{\covrun@exft}{#1}%
816   \adj@hdht@ftht
817 }
818
819 \def\@appendoutput#1{%
820   \output=\expandafter{\the\output #1}%
821 }
822
823 \@appendoutput{\adj@hdht@ftht}
824
825 %--------------------------------------------------------------------
826 %                 \@setheadheight and \@setfootheight:
827
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
837     %
838     % Save the newly set value:
839     \def\@temp{#1}
840     \def\@spaces{ }
841     \ifx\@temp\@empty
842       \global\@extrahead=0in
843     \else
844       \ifx\@temp\@spaces
845         \global\@extrahead=0in
846       \else
847         \global\@extrahead=#1
848       \fi
849     \fi
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
857     %
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
864     % \textheight.
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
869     % the page.
870     % In this bugfix, we adjust \@colroom, \@colht, and \vsize in the
871     % same way that we adjust \textheight.
872     %
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
878     % page).
879     % Bugfix, Version 2.306beta, 2009/03/28:
880     % We don't do this!!
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
889     % output routine.
890 %     \global\@colht=\textheight
891 %
892 %     \global\@colroom=\textheight
893 %     \global\vsize=\textheight
894 %     \global\pagegoal=\textheight
895   \endgroup
896 }% @setheadheight
897
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
906     %
907     % Save the newly set value:
908     \def\@temp{#1}
909     \def\@spaces{ }
910     \ifx\@temp\@empty
911       \global\@extrafoot=0in
912     \else
913       \ifx\@temp\@spaces
914         \global\@extrafoot=0in
915       \else
916         \global\@extrafoot=#1
917       \fi
918     \fi
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
925     %
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
932     % \textheight.
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
937     % the page.
938     % In this bugfix, we adjust \@colroom, \@colht, and \vsize in the
939     % same way that we adjust \textheight.
940     %
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
946     % page). 
947     % Bugfix, Version 2.306beta, 2009/03/28:
948     % We don't do this!!
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
957     % output routine.
958 %     \global\@colht=\textheight
959 %
960 %     \global\@colroom=\textheight
961 %     \global\vsize=\textheight
962 %     \global\pagegoal=\textheight
963   \endgroup
964 }% @setfootheight
965
966
967 %---------------------------------------------------------------------
968 %
969 %                      *************************
970 %                      ** HEADERS AND FOOTERS **
971 %                      *************************
972
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.
978
979
980 %                            Pagestyles:
981
982 \newcommand*\ps@head{%
983   \@dohead
984   \@nofoot
985 }
986
987 \newcommand*\ps@headandfoot{%
988   \@dohead
989   \@dofoot
990 }
991
992 \newcommand*\ps@foot{%
993   \@nohead
994   \@dofoot
995 }
996
997 % \ps@empty is already defined by article.cls, so we'll
998 % say \def instead of \newcommand*:
999 \def\ps@empty{%
1000   \@nohead
1001   \@nofoot
1002 }
1003
1004 \newif\if@coverpages
1005 \@coverpagesfalse
1006
1007 \newcounter{num@coverpages}
1008 % We'll set this to zero in case there is no coverpages environment:
1009 \setcounter{num@coverpages}{0}
1010
1011 \newenvironment{coverpages}{%
1012     \ifnum \value{numquestions}>0\relax
1013       \ClassError{exam}{%
1014         Coverpages cannot be used after questions have begun.\MessageBreak
1015       }{%
1016         All question, part, subpart, and subsubpart environments
1017         \MessageBreak
1018         must begin after the cover pages are complete.\MessageBreak
1019       }%
1020     \fi
1021     \@coverpagestrue
1022     \pagenumbering{roman}%
1023     \adj@hdht@ftht
1024   }{%
1025     \clearpage
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:
1035     \@coverpagesfalse
1036     \adj@hdht@ftht
1037 }
1038
1039 \newcommand*\cover@question@error{%
1040   \ClassError{exam}{%
1041     No questions are allowed in the cover pages.\MessageBreak
1042   }{%
1043     All question, part, subpart, and subsubpart environments
1044     \MessageBreak
1045     must begin after the cover pages are complete.\MessageBreak
1046   }%
1047 }
1048
1049 \newcommand*\@dohead{%
1050   \def\@oddhead{%
1051     \if@coverpages
1052       \ifnum\value{page}=1\relax
1053         \cov@fullhead
1054       \else
1055         \covrun@fullhead
1056       \fi
1057     \else
1058       \ifnum\value{page}=1\relax
1059         \@fullhead
1060       \else
1061         \run@fullhead
1062       \fi
1063     \fi
1064   }% @oddhead
1065   \let\@evenhead=\@oddhead
1066 }
1067
1068 \newcommand*\@dofoot{%
1069   \def\@oddfoot{%
1070     \if@coverpages
1071       \ifnum\value{page}=1\relax
1072         \cov@fullfoot
1073       \else
1074         \covrun@fullfoot
1075       \fi
1076     \else
1077       \ifnum\value{page}=1\relax
1078         \@fullfoot
1079       \else
1080         \run@fullfoot
1081       \fi
1082     \fi
1083   }% @oddfoot
1084   \let\@evenfoot=\@oddfoot
1085 }
1086
1087 \newcommand*\@nohead{%
1088   \def\@oddhead{}%
1089   \let\@evenhead=\@oddhead
1090 }
1091
1092 \newcommand*\@nofoot{%
1093   \def\@oddfoot{}%
1094   \let\@evenfoot=\@oddfoot
1095 }
1096
1097 %--------------------------------------------------------------------
1098 %       \@fullhead, \run@fullhead, \@fullfoot, and \run@fullfoot:
1099
1100 \newcommand*\@fullhead{%
1101   \vbox to \headheight{%
1102     \vss
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}}%
1107     }% hbox
1108     \if@headrule
1109       \hrule
1110     \else
1111       % an invisible hrule, to keep positioning constant:
1112       \hrule width 0pt
1113     \fi
1114   }% vbox
1115 }
1116
1117 \newcommand*\run@fullhead{%
1118   \vbox to \headheight{%
1119     \vss
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}}%
1124     }% hbox
1125     \ifrun@headrule
1126       \hrule
1127     \else
1128       % an invisible hrule, to keep positioning constant:
1129       \hrule width 0pt
1130     \fi
1131   }% vbox
1132 }
1133
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
1136 % a footrule:
1137
1138 \newcommand*\@fullfoot{%
1139   \vbox to 0pt{%
1140     \if@footrule
1141       \hrule
1142     \else
1143       % an invisible hrule, to keep positioning constant:
1144       \hrule width 0pt
1145     \fi
1146     \vskip 3pt
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}}%
1151     }% hbox
1152     \vss
1153   }% vbox
1154 }
1155
1156 \newcommand*\run@fullfoot{%
1157   \vbox to 0pt{%
1158     \ifrun@footrule
1159       \hrule
1160     \else
1161       % an invisible hrule, to keep positioning constant:
1162       \hrule width 0pt
1163     \fi
1164     \vskip 3pt
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}}%
1169     }% hbox
1170     \vss
1171   }% vbox
1172 }
1173
1174 %--------------------------------------------------------------------
1175 %       \cov@fullhead, \covrun@fullhead, \cov@fullfoot, and
1176 %       \covrun@fullfoot: 
1177
1178 \newcommand*\cov@fullhead{%
1179   \vbox to \headheight{%
1180     \vss
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}}%
1185     }% hbox
1186     \ifcov@headrule
1187       \hrule
1188     \else
1189       % an invisible hrule, to keep positioning constant:
1190       \hrule width 0pt
1191     \fi
1192   }% vbox
1193 }
1194
1195 \newcommand*\covrun@fullhead{%
1196   \vbox to \headheight{%
1197     \vss
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}}%
1202     }% hbox
1203     \ifcovrun@headrule
1204       \hrule
1205     \else
1206       % an invisible hrule, to keep positioning constant:
1207       \hrule width 0pt
1208     \fi
1209   }% vbox
1210 }
1211
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
1214 % a footrule:
1215
1216 \newcommand*\cov@fullfoot{%
1217   \vbox to 0pt{%
1218     \ifcov@footrule
1219       \hrule
1220     \else
1221       % an invisible hrule, to keep positioning constant:
1222       \hrule width 0pt
1223     \fi
1224     \vskip 3pt
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}}%
1229     }% hbox
1230     \vss
1231   }% vbox
1232 }
1233
1234 \newcommand*\covrun@fullfoot{%
1235   \vbox to 0pt{%
1236     \ifcovrun@footrule
1237       \hrule
1238     \else
1239       % an invisible hrule, to keep positioning constant:
1240       \hrule width 0pt
1241     \fi
1242     \vskip 3pt
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}}%
1247     }% hbox
1248     \vss
1249   }% vbox
1250 }
1251
1252 %--------------------------------------------------------------------
1253 %--------------------------------------------------------------------
1254 %
1255 %            ********************************************
1256 %            ** COMMANDS TO DEFINE HEADERS AND FOOTERS **
1257 %            ********************************************
1258 %
1259 % \lhead[#1]{#2} sets the first page left head to #1, and the
1260 %   running left head to #2
1261
1262 % \lhead{#1} sets both the first page left head and the running
1263 %   left head to #1
1264
1265 % \chead, \rhead, \lfoot, \cfoot, and \rfoot work similarly.
1266
1267
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)
1271
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)
1275
1276 % etc.
1277
1278 % Alternative commands are:
1279 % \firstpageheader{LEFT}{CENTER}{RIGHT}
1280 % \runningheader{LEFT}{CENTER}{RIGHT}
1281 % or
1282 % \header{LEFT}{CENTER}{RIGHT}
1283 % which is equivalent to the two commands
1284 %          \firstpageheader{LEFT}{CENTER}{RIGHT}
1285 %          \runningheader{LEFT}{CENTER}{RIGHT}
1286
1287 % Alternative commands are:
1288 % \firstpagefooter{LEFT}{CENTER}{RIGHT}
1289 % \runningfoother{LEFT}{CENTER}{RIGHT}
1290 % or
1291 % \footer{LEFT}{CENTER}{RIGHT}
1292 % which is equivalent to the two commands
1293 %          \firstpagefooter{LEFT}{CENTER}{RIGHT}
1294 %          \runningfoother{LEFT}{CENTER}{RIGHT}
1295
1296 \def\firstpageheader#1#2#3{%
1297   \def\@lhead{#1}%
1298   \def\@chead{#2}%
1299   \def\@rhead{#3}%
1300 }
1301
1302 \def\runningheader#1#2#3{%
1303   \def\run@lhead{#1}%
1304   \def\run@chead{#2}%
1305   \def\run@rhead{#3}%
1306 }
1307
1308 \def\header#1#2#3{%
1309   \firstpageheader{#1}{#2}{#3}%
1310   \runningheader{#1}{#2}{#3}%
1311 }
1312
1313 \def\firstpagefooter#1#2#3{%
1314   \def\@lfoot{#1}%
1315   \def\@cfoot{#2}%
1316   \def\@rfoot{#3}%
1317 }
1318
1319 \def\runningfooter#1#2#3{%
1320   \def\run@lfoot{#1}%
1321   \def\run@cfoot{#2}%
1322   \def\run@rfoot{#3}%
1323 }
1324
1325 \def\footer#1#2#3{%
1326   \firstpagefooter{#1}{#2}{#3}%
1327   \runningfooter{#1}{#2}{#3}%
1328 }
1329
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}}
1333
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}}
1337
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}}
1341
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}}
1345
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}}
1349
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}}
1353
1354
1355 %                    Initialize head and foot:
1356
1357 \pagestyle{headandfoot}
1358
1359 \lhead{}
1360 \chead{}
1361 \rhead{}
1362 \lfoot{}
1363 \cfoot[]{Page \thepage}
1364 \rfoot{}
1365
1366 %--------------------------------------------------------------------
1367 %                    Coverpage headers and footers
1368 %
1369 % \coverlhead[#1]{#2} sets the first cover page left head to #1, and the
1370 %   running cover left head to #2
1371
1372 % \coverlhead{#1} sets both the first cover page left head and the running
1373 %   cover left head to #1
1374
1375 % \coverchead, \coverrhead, \coverlfoot, \covercfoot, and \coverrfoot
1376 % work similarly.
1377
1378
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)
1382
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)
1386
1387 % etc.
1388
1389 % Alternative commands are:
1390 % \coverfirstpageheader{LEFT}{CENTER}{RIGHT}
1391 % \coverrunningheader{LEFT}{CENTER}{RIGHT}
1392 % or
1393 % \coverheader{LEFT}{CENTER}{RIGHT}
1394 % which is equivalent to the two commands
1395 %          \coverfirstpageheader{LEFT}{CENTER}{RIGHT}
1396 %          \coverrunningheader{LEFT}{CENTER}{RIGHT}
1397
1398 % Alternative commands are:
1399 % \coverfirstpagefooter{LEFT}{CENTER}{RIGHT}
1400 % \coverrunningfoother{LEFT}{CENTER}{RIGHT}
1401 % or
1402 % \coverfooter{LEFT}{CENTER}{RIGHT}
1403 % which is equivalent to the two commands
1404 %          \coverfirstpagefooter{LEFT}{CENTER}{RIGHT}
1405 %          \coverrunningfoother{LEFT}{CENTER}{RIGHT}
1406
1407 \def\coverfirstpageheader#1#2#3{%
1408   \def\cov@lhead{#1}%
1409   \def\cov@chead{#2}%
1410   \def\cov@rhead{#3}%
1411 }
1412
1413 \def\coverrunningheader#1#2#3{%
1414   \def\covrun@lhead{#1}%
1415   \def\covrun@chead{#2}%
1416   \def\covrun@rhead{#3}%
1417 }
1418
1419 \def\coverheader#1#2#3{%
1420   \coverfirstpageheader{#1}{#2}{#3}%
1421   \coverrunningheader{#1}{#2}{#3}%
1422 }
1423
1424 \def\coverfirstpagefooter#1#2#3{%
1425   \def\cov@lfoot{#1}%
1426   \def\cov@cfoot{#2}%
1427   \def\cov@rfoot{#3}%
1428 }
1429
1430 \def\coverrunningfooter#1#2#3{%
1431   \def\covrun@lfoot{#1}%
1432   \def\covrun@cfoot{#2}%
1433   \def\covrun@rfoot{#3}%
1434 }
1435
1436 \def\coverfooter#1#2#3{%
1437   \coverfirstpagefooter{#1}{#2}{#3}%
1438   \coverrunningfooter{#1}{#2}{#3}%
1439 }
1440
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}}
1444
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}}
1448
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}}
1452
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}}
1456
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}}
1460
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}}
1464
1465
1466 %                 Initialize coverpage head and foot:
1467
1468 \coverlhead{}
1469 \coverchead{}
1470 \coverrhead{}
1471 \coverlfoot{}
1472 \covercfoot{}
1473 \coverrfoot{}
1474
1475
1476
1477
1478 %--------------------------------------------------------------------
1479 %--------------------------------------------------------------------
1480
1481 %                      Headrules and footrules:
1482
1483 \newif\if@headrule
1484 \newif\ifrun@headrule
1485
1486 \def\firstpageheadrule{\@headruletrue}
1487 \def\nofirstpageheadrule{\@headrulefalse}
1488
1489 \def\runningheadrule{\run@headruletrue}
1490 \def\norunningheadrule{\run@headrulefalse}
1491
1492 \def\headrule{\@headruletrue\run@headruletrue}
1493 \def\noheadrule{\@headrulefalse\run@headrulefalse}
1494
1495 \newif\if@footrule
1496 \newif\ifrun@footrule
1497
1498 \def\firstpagefootrule{\@footruletrue}
1499 \def\nofirstpagefootrule{\@footrulefalse}
1500
1501 \def\runningfootrule{\run@footruletrue}
1502 \def\norunningfootrule{\run@footrulefalse}
1503
1504 \def\footrule{\@footruletrue\run@footruletrue}
1505 \def\nofootrule{\@footrulefalse\run@footrulefalse}
1506
1507 %                             Initialize:
1508
1509 \noheadrule
1510 \nofootrule
1511
1512 %                 Cover page headrules and footrules:
1513
1514 \newif\ifcov@headrule
1515 \newif\ifcovrun@headrule
1516
1517 \def\coverfirstpageheadrule{\cov@headruletrue}
1518 \def\nocoverfirstpageheadrule{\cov@headrulefalse}
1519
1520 \def\coverrunningheadrule{\covrun@headruletrue}
1521 \def\nocoverrunningheadrule{\covrun@headrulefalse}
1522
1523 \def\coverheadrule{\cov@headruletrue\covrun@headruletrue}
1524 \def\nocoverheadrule{\cov@headrulefalse\covrun@headrulefalse}
1525
1526 \newif\ifcov@footrule
1527 \newif\ifcovrun@footrule
1528
1529 \def\coverfirstpagefootrule{\cov@footruletrue}
1530 \def\nocoverfirstpagefootrule{\cov@footrulefalse}
1531
1532 \def\coverrunningfootrule{\covrun@footruletrue}
1533 \def\nocoverrunningfootrule{\covrun@footrulefalse}
1534
1535 \def\coverfootrule{\cov@footruletrue\covrun@footruletrue}
1536 \def\nocoverfootrule{\cov@footrulefalse\covrun@footrulefalse}
1537
1538 %                             Initialize:
1539
1540 \nocoverheadrule
1541 \nocoverfootrule
1542
1543 %--------------------------------------------------------------------
1544 %--------------------------------------------------------------------
1545
1546 %                \numpages, \iflastpage, and \oddeven
1547 %     Also: \numpoints, \numquestions, \numparts, and \numsubparts
1548 %                    Also also: \pointsofquestion
1549 %     Also: \numcoverpages and \totalnumpages
1550
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
1556
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:
1560
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.
1565
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).
1570
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.
1575
1576 \def\numpages{\@ifundefined{exam@lastpage}%
1577   {\mbox{\normalfont\bfseries ??}}%
1578   \exam@lastpage
1579 }% numpages
1580
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 ??}}%
1587   \exam@lastcoverpage
1588 }% numpages
1589
1590 \def\totalnumpages{\@ifundefined{exam@totalpages}%
1591   {\mbox{\normalfont\bfseries ??}}%
1592   \exam@totalpages
1593 }% numpages
1594
1595 \def\numpoints{\@ifundefined{exam@numpoints}%
1596   {\mbox{\normalfont\bfseries ??}}%
1597   \exam@numpoints
1598 }% numpoints
1599 \def\numbonuspoints{\@ifundefined{exam@numbonuspoints}%
1600   {\mbox{\normalfont\bfseries ??}}%
1601   \exam@numbonuspoints
1602 }% numbonuspoints
1603
1604 \def\numquestions{\@ifundefined{exam@numquestions}%
1605   {\mbox{\normalfont\bfseries ??}}%
1606   \exam@numquestions
1607 }% numquestions
1608
1609 \def\numparts{\@ifundefined{exam@numparts}%
1610   {\mbox{\normalfont\bfseries ??}}%
1611   \exam@numparts
1612 }% numparts
1613
1614 \def\numsubparts{\@ifundefined{exam@numsubparts}%
1615   {\mbox{\normalfont\bfseries ??}}%
1616   \exam@numsubparts
1617 }% numsubparts
1618
1619 \def\numsubsubparts{\@ifundefined{exam@numsubsubparts}%
1620   {\mbox{\normalfont\bfseries ??}}%
1621   \exam@numsubsubparts
1622 }% numsubsubparts
1623
1624 \def\pointsofquestion#1{\@ifundefined{pointsofq@\romannumeral #1}%
1625   {\mbox{\normalfont\bfseries ??}}%
1626   {\csname pointsofq@\romannumeral #1\endcsname}%
1627 }% pointsofquestion
1628 \def\bonuspointsofquestion#1{\@ifundefined{bonuspointsofq@\romannumeral #1}%
1629   {\mbox{\normalfont\bfseries ??}}%
1630   {\csname bonuspointsofq@\romannumeral #1\endcsname}%
1631 }% bonuspointsofquestion
1632
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.
1640 %
1641 % \def\pointsonpage#1{\@ifundefined{pointsonpage@\romannumeral #1}%
1642 %   {\mbox{\normalfont\bfseries ??}}%
1643 %   {\csname pointsonpage@\romannumeral #1\endcsname}%
1644 % }% pointsonpage
1645 % \def\bonuspointsonpage#1{\@ifundefined{bonuspointsonpage@\romannumeral #1}%
1646 %   {\mbox{\normalfont\bfseries ??}}%
1647 %   {\csname bonuspointsonpage@\romannumeral #1\endcsname}%
1648 % }% bonuspointsonpage
1649 %
1650 % spanish.ldf redefines \@roman, so we'll avoid using \roman:
1651 \def\pointsonpage#1{\@ifundefined{pointsonpage@\romannumeral #1}%
1652   {0}%
1653   {\csname pointsonpage@\romannumeral #1\endcsname}%
1654 }% pointsonpage
1655 \def\bonuspointsonpage#1{\@ifundefined{bonuspointsonpage@\romannumeral #1}%
1656   {0}%
1657   {\csname bonuspointsonpage@\romannumeral #1\endcsname}%
1658 }% bonuspointsonpage
1659
1660
1661 \newif\if@pointschanged
1662 \@pointschangedfalse
1663
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.
1669   \@ifundefined{#2}%
1670     {\global\@pointschangedtrue}%
1671     {%
1672     % OK; it's defined.  See if it's changed:
1673     \begingroup
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
1678         % Do nothing
1679       \else
1680         \global\@pointschangedtrue
1681       \fi
1682     \endgroup
1683     }%
1684 }% CheckIfChanged@hlf
1685
1686
1687 %%%\let\@realenddocument=\enddocument
1688 %%%\def\enddocument{\clearpage
1689 %%%   \if@filesw 
1690 %%%     {\advance\c@page-1 \immediate\write\@mainaux
1691 %%%       {\string\newlabel{@lastpage}{{}{\arabic{page}}}}%
1692 %%%     }
1693 %%%   \fi
1694 %%%   \@realenddocument
1695 %%%}
1696
1697 \AtEndDocument{%
1698   \clearpage
1699   \if@filesw
1700     \advance\c@page-1
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
1710     %
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}%
1737     \fi
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}%
1745     \fi
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}%
1751       {%
1752       % OK; it's defined.  See if it's changed:
1753       \begingroup
1754         \edef\othpt@check{\page@withpoints}%
1755         \edef\pt@check{\lastpage@withpoints}%
1756         \ifx \pt@check \othpt@check
1757           % Do nothing
1758         \else
1759           \global\@pointschangedtrue
1760         \fi
1761       \endgroup
1762       }%
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}%
1768       {%
1769       % OK; it's defined.  See if it's changed:
1770       \begingroup
1771         \edef\othpt@check{\page@withbonuspoints}%
1772         \edef\pt@check{\lastpage@withbonuspoints}%
1773         \ifx \pt@check \othpt@check
1774           % Do nothing
1775         \else
1776           \global\@pointschangedtrue
1777         \fi
1778       \endgroup
1779       }%
1780   \fi
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
1787     \begingroup
1788       \def\typ@expnd{%
1789         \thenumpoints
1790         \ifnumpoints@half
1791           \space and a half%
1792         \fi
1793       }
1794       \typeout{This exam has a total of \typ@expnd\space points.}
1795       \def\typ@expnd{%
1796         \thenumbonuspoints
1797         \ifnumbonuspoints@half
1798           \space and a half%
1799         \fi
1800       }
1801       \typeout{This exam has a total of \typ@expnd\space bonus points.}
1802     \endgroup
1803   \fi
1804   \if@pointschanged
1805     \ClassWarningNoLine{exam}{Point totals have changed.
1806                Rerun to get point totals right}%
1807   \fi
1808 }% AtEndDocument
1809
1810
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
1817     #1%
1818   \else
1819     #2%
1820   \fi
1821 }% iflastpage
1822
1823
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
1826 % argument.
1827 \def\oddeven#1#2{%
1828   \ifodd\value{page}%
1829     #1%
1830   \else
1831     #2%
1832   \fi
1833 }% oddeven
1834
1835
1836
1837 %--------------------------------------------------------------------
1838 %--------------------------------------------------------------------
1839 %                 \ifcontinuation, \ContinuedQuestion,
1840 %                \ifincomplete, and \IncompleteQuestion
1841
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.)
1847
1848
1849
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.)
1854
1855 % We use \PgInfo, \PgInfo@write, and \PgInfo@get to know on which page
1856 % each question, part, subpart, subsubpart, and choice appears.
1857
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.
1861
1862 % The label for a question is of the form `question@2' (if it's question
1863 % 2).
1864
1865 % The label for a part is of the form `part@2@1' (if it's part a of
1866 % question 2).
1867
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).
1870
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).
1873
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).
1877
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).
1882
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.
1888
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}.
1893
1894
1895
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{%
1909   \begingroup
1910     \edef\reserved@a{\write\@mainaux
1911       {\string\PgInfo{#1}{\noexpand\thepage}}}%
1912     \reserved@a
1913   \endgroup
1914 }
1915
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}}
1919
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}
1924
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}}%
1937 }
1938
1939
1940 %--------------------------------------------------------------------
1941
1942 % \ifcontinuation#1#2 expands to #2 if either:
1943 % (1) The command \noquestionsonthispage has been given on this page,
1944 % or
1945 % (2) The current page is before the page containing question number
1946 % 1, or
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
1950 % command.
1951 % Otherwise, it expands to #1.
1952 %
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.
1957
1958
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}}%
1964     {#2}%
1965 }% \ifcontinuation
1966
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
1974     #2%
1975   \else
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
1983     % with a digit).
1984     \ifnum \thepage < \csname Pg@question@1\endcsname\relax
1985       % We're before the page with question 1:
1986       #2%
1987     \else
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
1994         #2%
1995       \else
1996         % See if we're after a \nomorequestions command:
1997         \@ifundefined{Pg@@endquestions}%
1998         {#1}%
1999         {\ifnum \thepage > \PgInfo@get{@endquestions}\relax
2000           % We're after a \nomorequestions:
2001           #2%
2002          \else
2003            % We actually are incomplete:
2004            #1%
2005          \fi
2006         }%
2007       \fi
2008     \fi 
2009   \fi
2010 }% chk@contin
2011
2012 \def\nomorequestions{%
2013   \PgInfo@write{@endquestions}%
2014 }% nomorequestions
2015
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
2021
2022
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
2026 % actually appear.
2027
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
2030 % question.
2031
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.
2042
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).
2048
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.
2055
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.
2060
2061
2062 \def\ref@relax{\relax}
2063
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 
2070     % before this page.
2071     \find@latestques
2072     \thelatest@ques
2073   \else
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.
2086       -1\relax
2087     \else
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
2094     \fi
2095   \fi
2096 }
2097
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
2102 % page.
2103
2104 \newcounter{latest@ques}
2105
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
2118   % the current page.
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}%
2123   \else
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}%
2135     \else
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}}%
2143       \decr@latest@ques
2144     \fi
2145   \fi
2146 }
2147
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
2160     \else
2161       \let\next@dlq=\decr@latest@ques
2162     \fi
2163   \else
2164     % latest@ques starts on this page or earlier, so
2165     % that's the correct question number!  Exit:
2166     \let\next@dlq=\relax
2167   \fi
2168   \next@dlq
2169 }
2170
2171 %--------------------------------------------------------------------
2172 %--------------------------------------------------------------------
2173 %--------------------------------------------------------------------
2174 \newcounter{ques@end}
2175 \newcounter{last@object}
2176
2177 \def\find@quesend{%
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:
2183   \find@latestques
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}%
2188   \else
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}%
2196     \find@lastobject
2197     \setcounter{ques@end}{\PgInfo@get{question\thelatest@ques
2198                @object\thelast@object}}%
2199   \fi
2200 }% find@quesend
2201
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
2209     }%
2210     {\addtocounter{last@object}{1}%
2211       \let\nextfind@lastobject=\find@lastobject
2212     }%
2213   \nextfind@lastobject
2214 }% find@lastobject
2215
2216
2217
2218 %--------------------------------------------------------------------
2219 %--------------------------------------------------------------------
2220 %--------------------------------------------------------------------
2221
2222 \newcounter{incmp@ques}
2223
2224 \def\IncompleteQuestion{%
2225   \Find@Incmp@ques
2226   % If there's no incomplete question, the counter incmp@ques will be
2227   % set to -1:
2228   \theincmp@ques
2229 }
2230
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}%
2234 }% Find@Incmp@ques
2235 \newcounter{next@ques}
2236 \newcounter{next@page}
2237
2238 \def\chk@incomp{%
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:
2244   \find@quesend
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}}%
2248   \else
2249     \chk@incompi
2250   \fi
2251 }% chk@incomp
2252
2253 \def\chk@incompi{%
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
2263   % command:
2264   \expandafter\ifx\csname Pg@question@\thenext@ques \endcsname\relax
2265     % This isn't the last page but there is no next question:
2266 %
2267     \@ifundefined{exam@lastpage}%
2268       {\setcounter{next@page}{-1}}%
2269       {\setcounter{next@page}{\exam@lastpage}}%
2270 %
2271 %    \setcounter{next@page}{\exam@lastpage}%
2272   \else
2273     \setcounter{next@page}{\PgInfo@get{question@\thenext@ques}}%
2274     \addtocounter{next@page}{-1}%
2275   \fi
2276   % See if that's after a \nomorequestions command:
2277   \@ifundefined{Pg@@endquestions}%
2278     {}%
2279     {\ifnum \PgInfo@get{@endquestions} < \value{next@page}\relax
2280        \setcounter{next@page}{\PgInfo@get{@endquestions}}%
2281      \fi
2282     }%
2283   % OK, the counter next@page now contains the last page to check.
2284   \chk@incompii
2285 }% chk@incompi
2286
2287 \def\chk@incompii{%
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
2293     }%
2294     {\addtocounter{next@page}{-1}%
2295       \let\next@incompii = \chk@incompii
2296     }%
2297   \else
2298     % There's no incomplete question:
2299     \setcounter{incmp@ques}{-1}%
2300     \let\next@incompii=\relax
2301   \fi
2302   \next@incompii
2303 }% chk@incompii
2304
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}%
2313     {\chk@ifincomp}%
2314     {\incomp@second}%
2315 }% ifincomplete
2316
2317 \def\chk@ifincomp{%
2318   \Find@Incmp@ques
2319   % If there's no incomplete question, \Find@Incmp@ques sets the
2320   % counter incmp@ques to -1:
2321   \ifnum \theincmp@ques < 0\relax
2322     \incomp@second
2323   \else
2324     % Are we after a page with \nomorequestions?
2325     \@ifundefined{Pg@@endquestions}%
2326       {\incomp@first}%
2327       {\ifnum \thepage < \PgInfo@get{@endquestions}\relax
2328          \incomp@first
2329        \else
2330          \incomp@second
2331        \fi
2332       }%
2333   \fi
2334 }% chk@ifincomp
2335
2336 %--------------------------------------------------------------------
2337 % These are the commands for dealing with hlfcntr's, i.e., the things
2338 % used to count points.
2339 %
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''.
2345 %
2346 % The commands:
2347 %
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}
2356 %
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
2360 % as ``0''.)
2361 %
2362 % Examples of valid values:
2363 %   0
2364 %   0\half
2365 %   1
2366 %   1\half
2367 %   2
2368 %   2\half
2369 % etc.
2370
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
2375 % these things.
2376
2377 % To create a hlfcntr:
2378 \newcommand*\new@hlfcntr[1]{%
2379   \newcounter{#1}%
2380   \expandafter\newif\csname if#1@half\endcsname
2381 }% new@hlfcntr
2382
2383
2384 % A scratch hlfcntr:
2385 \new@hlfcntr{tmp@hlfcntr}
2386
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$}$%
2391 }% slanted@half
2392 \newcommand*\useslantedhalf{\global\let\half\slanted@half}
2393 \newcommand*\usehorizontalhalf{\global\let\half\horiz@half}
2394 \newcommand*\half{\slanted@half}
2395
2396
2397 \newcommand*\set@hlfcntr[2]{%
2398   \begingroup
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.
2403     \def\half{%
2404       \global\csname #1@halftrue\endcsname
2405     }%
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
2409     % we're using:
2410     %    \setcounter{#1}{0#2}\relax
2411     \global\csname c@#1\endcsname 0#2\relax
2412   \endgroup
2413 }% set@hlfcntr
2414
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
2420   \else
2421     \global\csname #1@halffalse\endcsname
2422   \fi
2423 }% copy@hlfcntr
2424
2425 \newcommand*\addto@hlfcntr[2]{%
2426   % We add the valueandhalf #2 to hlfcntr #1
2427   \begingroup
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
2432     % we're using:
2433     %    \addtocounter{#1}{0#2}\relax
2434     \global\advance\csname c@#1\endcsname 0#2\relax
2435   \endgroup
2436 }% addto@hlfcntr
2437
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
2442     \add@half{#1}%
2443   \fi
2444 }% add@hlfcntrtohlfcntr
2445
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
2451   \else
2452     \global\csname #1@halftrue\endcsname
2453   \fi
2454 }% add@half
2455
2456 % Important reminder about \ifhlfcntr@pos: Do not use it inside
2457 % another conditional!  The construction
2458 %  \ifhlfcntr@pos{somecounter}
2459 %    do some stuff...
2460 %  \fi
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
2467 % causes an error.
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}%
2476   \fi
2477   \ifnum \value{ifpos@cntr} > 0\relax
2478 }% ifhlfnctr@pos
2479
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}%
2490   \else
2491     \arabic{#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}%
2496   \fi
2497 }% prtaux@hlfcntr
2498 \newcommand*\prtaux@halforzero[1]{%
2499   \csname if#1@half\endcsname
2500     \string\half
2501   \else
2502     0%
2503   \fi
2504 }% prtaux@hlforzero
2505 \newcommand*\prtaux@halforblank[1]{%
2506   \csname if#1@half\endcsname
2507     \string\half
2508   \fi
2509 }% prtaux@halforblank
2510
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}%
2519   \else
2520     \arabic{#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}%
2525   \fi
2526 }% prt@hlfcntr
2527 \newcommand*\prt@halforzero[1]{%
2528   \csname if#1@half\endcsname
2529     \half
2530   \else
2531     0%
2532   \fi
2533 }% prt@hlforzero
2534 \newcommand*\prt@halforblank[1]{%
2535   \csname if#1@half\endcsname
2536     \half
2537   \fi
2538 }% prt@halforblank
2539
2540 % End of the commands for dealing with hlfcntr's
2541
2542 %--------------------------------------------------------------------
2543 %---------------------------------------------------------------------
2544 %
2545 %                    ***************************
2546 %                    ** QUESTION ENVIRONMENTS **
2547 %                    ***************************
2548 %
2549 %
2550 %
2551
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.
2559
2560
2561
2562
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
2565 % document class.
2566
2567 \newcounter{question}
2568 \newcounter{partno}
2569 \newcounter{subpart}
2570 \newcounter{subsubpart}
2571 \newcounter{choice}
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}
2585
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}
2595
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}
2603
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}%
2611
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
2621 \newtoks\temp@toks
2622
2623 % \pagepoint@commands holds the commands to manage the counting of the
2624 % number of points defined on each page.
2625 \newtoks\pagepoint@commands
2626
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
2629 % option).
2630 \newtoks\point@toks
2631
2632 % We'll use \greeknum to number subsubparts
2633 \def\greeknum#1{\expandafter\lc@greek\csname c@#1\endcsname}
2634 \def\lc@greek#1{%
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
2640   \fi
2641 }% lc@greek
2642
2643
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
2650
2651 \def\prepend@toklist#1#2{%
2652   \edef\do@it{\noexpand#1={\the#2\the#1}}%
2653   \do@it
2654 }% prepend@toklist
2655
2656 \def\append@toklist#1#2{%
2657   \edef\do@it{\noexpand#1={\the#1\the#2}}%
2658   \do@it
2659 }% append@toklist
2660
2661
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
2667 % line.
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 ...
2676 %
2677 % The command \noqformat cancels the effect of \qformat and returns us
2678 % to the default situation.
2679 %
2680 % The commands \bonusqformat and \nobonusformat are analogous.
2681 \newif\if@qformat
2682 \@qformatfalse
2683 \newif\if@bonusqformat
2684 \@bonusqformatfalse
2685
2686 \def\qformat#1{%
2687   \global\@qformattrue
2688   \gdef\@questionformat{#1}%
2689 }% qformat
2690 \def\bonusqformat#1{%
2691   \global\@bonusqformattrue
2692   \gdef\@bonusquestionformat{#1}%
2693 }% bonusqformat
2694
2695 \newcommand\noqformat{%
2696   \global\@qformatfalse
2697 }% noqformat
2698 \newcommand\nobonusqformat{%
2699   \global\@bonusqformatfalse
2700 }% nobonusqformat
2701
2702
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{%
2709   \if@placepoints
2710     \if@bonus
2711       \@points \@bonuspointname
2712     \else
2713       \@points \@pointname
2714     \fi
2715   \fi
2716 }% thepoints
2717
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{%
2721   \if@bonus
2722     \@points \@marginbonuspointname
2723   \else
2724     \@points \@marginpointname
2725   \fi
2726 }% themarginpoints
2727
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
2734 % environment.)
2735
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}
2742
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
2755
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
2768
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):
2780   \if@insolution
2781     \ifprintanswers
2782       \doqobj@ppchk
2783     \fi
2784   \else
2785     \doqobj@ppchk
2786   \fi
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}}%
2800   \fi
2801 }% doqobj@ppchk                               
2802
2803
2804
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:
2810 \newif\if@bonus
2811 \@bonusfalse
2812
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{}
2823
2824
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{%
2836     \@bonusfalse
2837     \def\thequestiontitle{##1}%
2838     \process@question
2839   }%
2840   \def\bonustitledquestion##1{%
2841     \@bonustrue
2842     \def\thequestiontitle{##1}%
2843     \process@question
2844   }%
2845   \def\question{%
2846     \@bonusfalse
2847     \def\thequestiontitle{\csname p@question\endcsname
2848                           \csname thequestion\endcsname}%
2849     \process@question
2850   }%
2851   \def\bonusquestion{%
2852     \@bonustrue
2853     \def\thequestiontitle{\csname p@question\endcsname
2854                           \csname thequestion\endcsname}%
2855     \process@question
2856   }%
2857   \def\process@question{%
2858     \if@coverpages
2859       \cover@question@error
2860     \fi
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.)
2867     \if@filesw
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}%
2886       \fi
2887     \fi
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
2897     % environment. 
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.
2918       % 
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.
2924       % 
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
2933       % run.
2934       %
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
2940       % question:
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}%
2946       \endgroup
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}%
2953       \fi
2954       \the\pagepoint@commands
2955       \global \pageinfo@commands={}%
2956     }% pageinfo@commands
2957     \ifhmode
2958       % Remove any skips at the end of the previous paragraph
2959       % that might cause a blank line, and then end that paragraph:
2960       \unskip\unskip \par
2961     \fi
2962     \@doitem
2963   }% process@question
2964   \def\subpart{%
2965     \@bonusfalse
2966     \process@subpart
2967   }%
2968   \def\bonussubpart{%
2969     \@bonustrue
2970     \process@subpart
2971   }%
2972   \def\process@subpart{%
2973     \if@coverpages
2974       \cover@question@error
2975     \fi
2976     \@checkqueslevel{subpart}%
2977     \if@insolution
2978       % We don't count this subpart, so no addtocounter{numsubparts}.
2979       \temp@toks={%
2980         \questionobject@pluspagecheck
2981         \global \pageinfo@commands={}%
2982         % We omit the pagepoint@commands
2983       }% temp@toks
2984     \else
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. 
2990       \temp@toks={%
2991         \edef\@subpartlabel{subpart@\arabic{section}@\arabic{subsection}@\arabic{question}%
2992           @\arabic{partno}@\arabic{subpart}}%
2993         \PgInfo@write{\@subpartlabel}%
2994         \addquestionobject
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.
2999         % 
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.
3005         % 
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
3014         % run.
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}}%
3022         \fi
3023         \the\pagepoint@commands
3024         \global \pageinfo@commands={}%
3025       }% temp@toks
3026     \fi
3027     \append@toklist \pageinfo@commands \temp@toks
3028     \ifhmode
3029       % Remove any skips at the end of the previous paragraph
3030       % that might cause a blank line, and then end that paragraph:
3031       \unskip\unskip \par
3032     \fi
3033     \@doitem
3034   }% process@subpart
3035   \def\subsubpart{%
3036     \@bonusfalse
3037     \process@subsubpart
3038   }%
3039   \def\bonussubsubpart{%
3040     \@bonustrue
3041     \process@subsubpart
3042   }%
3043   \def\process@subsubpart{%
3044     \if@coverpages
3045       \cover@question@error
3046     \fi
3047     \@checkqueslevel{subsubpart}%
3048     \if@insolution
3049       % We don't count this subsubpart, so no addtocounter{numsubsubparts}.
3050       \temp@toks={%
3051         \questionobject@pluspagecheck
3052         \global \pageinfo@commands={}%
3053         % We omit the pagepoint@commands
3054       }% temp@toks
3055     \else
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. 
3061       \temp@toks={%
3062         \edef\@subsubpartlabel{subsubpart@\arabic{section}@\arabic{subsection}@\arabic{question}%
3063           @\arabic{partno}@\arabic{subpart}@\arabic{subsubpart}}%
3064         \PgInfo@write{\@subsubpartlabel}%
3065         \addquestionobject
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.
3070         % 
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.
3076         % 
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
3085         % run.
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}}%
3093         \fi
3094         \the\pagepoint@commands
3095         \global \pageinfo@commands={}%
3096       }% temp@toks
3097     \fi
3098     \append@toklist \pageinfo@commands \temp@toks
3099     \ifhmode
3100       % Remove any skips at the end of the previous paragraph
3101       % that might cause a blank line, and then end that paragraph:
3102       \unskip\unskip \par
3103     \fi
3104     \@doitem
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
3113     \partopsep=0pt
3114     \questionshook
3115     }%
3116   }% End of the first argument of \newenvironment{questions}
3117   {%
3118     \endlist
3119     % Write the number of points of the final question
3120     % to the .aux file:
3121     \if@filesw
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}%
3141       \fi
3142     \fi
3143   }% End of the second argument of \newenvironment{questions}
3144   
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:
3148
3149 \def\question@number{%
3150   \if@bonus
3151     \if@bonusqformat
3152       \makebox[\hsize][s]{\@bonusquestionformat}\hskip-\labelsep
3153     \else
3154       \questionlabel
3155     \fi
3156   \else
3157     \if@qformat
3158       \makebox[\hsize][s]{\@questionformat}\hskip-\labelsep
3159     \else
3160       \questionlabel
3161     \fi
3162   \fi
3163 }
3164 \newcommand\questionlabel{\thequestion.}
3165      
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).
3170
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.)
3180   \if@bonus
3181     \if@bonusqformat
3182       \if@inlabel
3183         \leavevmode
3184         \@inlabelfalse
3185       \fi
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
3194     \fi
3195   \else
3196     \if@qformat
3197       \if@inlabel
3198         \leavevmode
3199         \@inlabelfalse
3200       \fi
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
3209     \fi
3210   \fi
3211   \def\part{%
3212     \@bonusfalse
3213     \process@part
3214   }%
3215   \def\bonuspart{%
3216     \@bonustrue
3217     \process@part
3218   }%
3219   \def\process@part{%
3220     \if@coverpages
3221       \cover@question@error
3222     \fi
3223     \@checkqueslevel{part}%
3224     \if@insolution
3225       % We don't count this part, so no addtocounter{numparts}.
3226       \temp@toks={%
3227         \questionobject@pluspagecheck
3228         \global \pageinfo@commands={}%
3229         % We omit the pagepoint@commands
3230       }% temp@toks
3231     \else
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. 
3237       \temp@toks={%
3238         \edef\@partlabel{part@\arabic{question}@\arabic{partno}}%
3239         \PgInfo@write{\@partlabel}%
3240         \addquestionobject
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.
3245         % 
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.
3251         % 
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
3260         % run.
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}}%
3266         \fi
3267         \the\pagepoint@commands
3268         \global \pageinfo@commands={}%
3269       }% temp@toks
3270     \fi
3271     \append@toklist \pageinfo@commands \temp@toks
3272     \ifhmode
3273       % Remove any skips at the end of the previous paragraph
3274       % that might cause a blank line, and then end that paragraph:
3275       \unskip\unskip \par
3276     \fi
3277     \@doitem
3278   }% process@part
3279   \list{\partlabel}%
3280     {%
3281     \usecounter{partno}\def\makelabel##1{\hss\llap{##1}}%
3282     \settowidth{\leftmargin}{(m)\hskip\labelsep}%
3283     \labelwidth\leftmargin\advance\labelwidth-\labelsep
3284     \topsep=0pt
3285     \partopsep=0pt
3286     \partshook
3287     }%
3288   }% newenvironment{parts}
3289   {\endlist}
3290 \newcommand\partlabel{(\thepartno)}
3291 \def\thepartno{\alph{partno}}
3292
3293 \newenvironment{subparts}{%
3294   \def\@queslevel{subpart}%
3295   \list{\subpartlabel}%
3296     {%
3297     \usecounter{subpart}\def\makelabel##1{\hss\llap{##1}}%
3298     \settowidth{\leftmargin}{vii.\hskip\labelsep}%
3299     \labelwidth\leftmargin\advance\labelwidth-\labelsep
3300     \topsep=0pt
3301     \partopsep=0pt
3302     \subpartshook
3303     }%
3304   }%
3305   {\endlist}
3306 \newcommand\subpartlabel{\thesubpart.}
3307 \def\thesubpart{\roman{subpart}}
3308
3309 \newenvironment{subsubparts}{%
3310   \def\@queslevel{subsubpart}%
3311   \list{\subsubpartlabel}%
3312     {%
3313     \usecounter{subsubpart}\def\makelabel##1{\hss\llap{##1}}%
3314     \settowidth{\leftmargin}{($\psi$)\hskip\labelsep}%
3315     \labelwidth\leftmargin\advance\labelwidth-\labelsep
3316     \topsep=0pt
3317     \partopsep=0pt
3318     \subsubpartshook
3319     }%
3320   }%
3321   {\endlist}
3322 \newcommand\subsubpartlabel{\thesubsubpart)}
3323 \def\thesubsubpart{\greeknum{subsubpart}}
3324
3325
3326
3327
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
3336         % Do nothing...
3337       \else
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}%
3345       \fi
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}}%
3354     \else
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}%
3359     \fi
3360   \fi
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
3368         % Do nothing...
3369       \else
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}%
3378       \fi
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}}%
3387     \else
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}%
3392     \fi
3393   \fi
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}%
3405       {%
3406       % OK; it's defined.  See if it's changed:
3407       \begingroup
3408         \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral 
3409                   \csname c@pageof@pagepoints\endcsname\endcsname}%
3410         \edef\othpt@check{\prtaux@hlfcntr{tmp@hlfcntr}}%
3411         \def\pt@check{0}%
3412         \ifx \pt@check \othpt@check
3413           % Do nothing
3414         \else
3415           \global\@pointschangedtrue
3416         \fi
3417       \endgroup
3418       }%
3419     \let\next@incr@pageof = \increment@pageof@pagepoints
3420   \else
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
3428   \fi
3429   \next@incr@pageof
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}%
3441       {%
3442       % OK; it's defined.  See if it's changed:
3443       \begingroup
3444         \set@hlfcntr{tmp@hlfcntr}{\csname bonuspointsonpage@\romannumeral 
3445                   \csname c@pageof@pagebonuspoints\endcsname\endcsname}%
3446         \edef\othpt@check{\prtaux@hlfcntr{tmp@hlfcntr}}%
3447         \def\pt@check{0}%
3448         \ifx \pt@check \othpt@check
3449           % Do nothing
3450         \else
3451           \global\@pointschangedtrue
3452         \fi
3453       \endgroup
3454       }%
3455     \let\next@incr@pageof = \increment@pageof@pagebonuspoints
3456   \else
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
3464   \fi
3465   \next@incr@pageof
3466 }% increment@pageof@pagebonuspoints
3467
3468
3469
3470
3471
3472
3473 \def\@checkqueslevel#1{%
3474   \begingroup
3475     \def\exam@temp{#1}%
3476     \ifx\exam@temp\@queslevel
3477       % Everything's fine; do nothing.
3478     \else
3479       \ClassError{exam}{%
3480         I found a #1 where I expected to find a
3481         \@queslevel\MessageBreak
3482       }{%
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
3486         \MessageBreak
3487       }%
3488     \fi
3489   \endgroup
3490 }
3491
3492 \def\@doitem{\@ifnextchar[{\@readpoints}%
3493                           {\item@points@pageinfo}%
3494 }
3495
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:
3500   \def\@points{#1}%
3501   \global \@placepointstrue
3502   \if@addpoints
3503     \if@bonus
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
3509       % by @pagepoints:
3510       \addto@hlfcntr{latest@bonuspoints}{\@points}%
3511     \else
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
3517       % by @pagepoints:
3518       \addto@hlfcntr{latest@points}{\@points}%
3519     \fi
3520   \fi
3521   \item@points@pageinfo
3522 }
3523
3524
3525
3526
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
3532 %   \the\point@toks
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.
3548
3549 \def\item@points@pageinfo{%
3550   \item
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).
3560   %
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.
3565   %
3566   \if@placepoints
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.
3578     %
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
3584     % sequence errors.
3585     \if@bonus
3586       \def\padded@point@block{%
3587         \begingroup
3588           \@placepointstrue
3589           \bonuspoint@block
3590         \endgroup
3591       }%
3592     \else
3593       \def\padded@point@block{%
3594         \begingroup
3595           \@placepointstrue
3596           \point@block
3597         \endgroup
3598       }%
3599     \fi
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). 
3603     %
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.
3610     \if@pointsdropped
3611       % Do nothing!
3612     \else
3613       \if@bonus
3614         \if@bonusqformat
3615           \ifx\ques@ref\@queslevel
3616             % Do nothing
3617           \else
3618             \setup@point@toks
3619           \fi
3620         \else
3621           \setup@point@toks
3622         \fi
3623       \else
3624         \if@qformat
3625           \ifx\ques@ref\@queslevel
3626             % Do nothing
3627           \else
3628             \setup@point@toks
3629           \fi
3630         \else
3631           \setup@point@toks
3632         \fi
3633       \fi
3634     \fi
3635     \global \@placepointsfalse
3636   \fi
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
3641   % will be empty.
3642   % Also: It's important to do this *after* the \item command above,
3643   % since the \item command discards the previous contents of
3644   % \everypar.
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
3656   % \@labels, though.
3657   \global\setbox\@labels\hbox{\unhbox\@labels
3658     \the \pageinfo@commands
3659     \the \point@toks}%
3660   %   \edef\append@everypar{\noexpand\everypar={\the\everypar
3661   %                         \noexpand\the \noexpand\pageinfo@commands
3662   %                         \noexpand\the \noexpand\point@toks}}%
3663   %   \append@everypar
3664 }
3665
3666
3667
3668
3669
3670
3671
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.)
3677 \def\@points{0}
3678
3679
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.
3686 %
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).
3691 %
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
3703 % will do no harm.
3704 %
3705   \if@pointstwosided
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
3710     % be defined:
3711     \ifx\@queslevel\ques@ref
3712       \def\q@label{Pg@question@\arabic{question}}
3713     \else
3714       \ifx\@queslevel\part@ref
3715         \def\q@label{Pg@part@\arabic{question}@\arabic{partno}}
3716       \else
3717         \ifx\@queslevel\subpart@ref
3718           \def\q@label{Pg@subpart@\arabic{question}%
3719             @\arabic{partno}@\arabic{subpart}}
3720         \else
3721           \ifx\@queslevel\subsubpart@ref
3722             \def\q@label{Pg@subsubpart@\arabic{question}%
3723               @\arabic{partno}@\arabic{subpart}@\arabic{subsubpart}}
3724           \else
3725             \ClassError{exam}{%
3726               This can't happen in function \protect\setup@point@toks
3727               \MessageBreak
3728             }{%
3729               An unexplained error occurred in exam.cls;\MessageBreak
3730               please inform the package maintainer, and send along
3731               \MessageBreak
3732               the LaTeX file that shows the error.\MessageBreak
3733             }%
3734           \fi
3735         \fi
3736       \fi
3737     \fi
3738     % 
3739     \expandafter\ifx \csname \q@label \endcsname\relax
3740       % No page info yet; put it into the right margin
3741       \@pointsinrightmargintrue
3742       \@pointsinleftmarginfalse
3743     \else
3744       \ifodd \csname \q@label \endcsname\relax
3745         \if@pointsinoutsidemargin
3746           \@pointsinrightmargintrue
3747           \@pointsinleftmarginfalse
3748         \else
3749           \@pointsinrightmarginfalse
3750           \@pointsinleftmargintrue
3751         \fi
3752       \else
3753         \if@pointsinoutsidemargin
3754           \@pointsinrightmarginfalse
3755           \@pointsinleftmargintrue
3756         \else
3757           \@pointsinrightmargintrue
3758           \@pointsinleftmarginfalse
3759         \fi
3760       \fi
3761     \fi
3762   \fi
3763   % That ends the \if@pointstwosided.
3764   % Now we actually setup \point@toks:
3765   \if@pointsinleftmargin
3766     \point@toks={%
3767           \llap{\padded@point@block 
3768                 \hskip\@totalleftmargin
3769                 \hskip\marginpointssep
3770           }%
3771           \global \point@toks={}%
3772     }%
3773   \else
3774     \if@pointsinrightmargin
3775       \point@toks={%
3776             \rlap{\hskip-\@totalleftmargin
3777                   \hskip\textwidth
3778                   \hskip\@rightmargin
3779                   \hskip-\rightpointsmargin
3780                   \llap{\padded@point@block}%
3781             }%
3782             \global \point@toks={}%
3783       }%
3784     \else
3785       % The points just go after the question number:
3786       \point@toks={%
3787             \padded@point@block
3788             \enspace
3789             \global \point@toks={}%
3790       }%
3791     \fi
3792   \fi
3793 }% setup@point@toks
3794
3795 \def\droppoints{%
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}%
3801   }% rlap
3802   \par
3803 }
3804
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}%
3811   }% rlap
3812   \par
3813 }% droptotalpoints
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}%
3820   }% rlap
3821   \par
3822 }% droptotalbonuspoints
3823
3824 % The following is the default definition;
3825 % it can be changed by a \totalformat command.
3826 \def\total@block{%
3827   Total for Question \thequestion: \totalpoints\@marginpointname
3828 }% total@block
3829 \def\bonustotal@block{%
3830   Total for Question \thequestion: \totalbonuspoints\@marginbonuspointname
3831 }% bonustotal@block
3832
3833 \def\totalformat#1{%
3834   \gdef\total@block{\begingroup #1\endgroup}%
3835 }% totalformat
3836 \def\bonustotalformat#1{%
3837   \gdef\bonustotal@block{\begingroup #1\endgroup}%
3838 }% bonustotalformat
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}}}
3842
3843
3844
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
3857 \@placepointsfalse
3858
3859
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}
3865
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}
3871
3872
3873 \newif\if@pointsdropped
3874 \newif\if@pointsinleftmargin
3875 \newif\if@pointsinrightmargin
3876 \newif\if@pointstwosided
3877 \newif\if@pointsinoutsidemargin
3878
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.
3883
3884 % If we have \@pointstwosidedtrue, then both \@pointsinleftmargin and
3885 % \@pointsinrightmargin will be flipped back and forth, as needed, in
3886 % \setup@point@toks.
3887
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
3925
3926 \nopointsinmargin
3927
3928
3929 % Will the points be displayed inside parentheses (the default), or
3930 % will they be boxed or bracketed, or customized using pointformat:
3931 \def\boxedpoints{%
3932   \gdef\point@block{\fbox{\@points\pt@name}}%
3933   \gdef\bonuspoint@block{\fbox{\@points\bnspt@name}}%
3934 }
3935 \def\noboxedpoints{%
3936   \gdef\point@block{(\@points\pt@name)}%
3937   \gdef\bonuspoint@block{(\@points\bnspt@name)}%
3938 }
3939 \def\bracketedpoints{%
3940   \gdef\point@block{[\@points\pt@name]}%
3941   \gdef\bonuspoint@block{[\@points\bnspt@name]}%
3942 }
3943 \let\nobracketedpoints=\noboxedpoints
3944
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}%
3951 }
3952
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}%
3959 }
3960
3961 %Initialize:
3962 \noboxedpoints
3963
3964
3965
3966
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
3978 % intentional!)
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}%
3986 }
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}%
3994 }
3995
3996
3997
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
4005 % this anyway.
4006
4007 % 0 points, one half point, 1 point, 1 and a half points, etc.:
4008 \newcommand\points{%
4009   \begingroup
4010     \let\half=\relax
4011     \edef\pt@string{\@points}%
4012     \ifthenelse{\equal{\pt@string}{1} \or \equal{\pt@string}{\half}}
4013           {\point@sing}{\point@plur}%
4014   \endgroup
4015 }% \points
4016 \newcommand\bonuspoints{%
4017   \begingroup
4018     \let\half=\relax
4019     \edef\pt@string{\@points}%
4020     \ifthenelse{\equal{\pt@string}{1} \or \equal{\pt@string}{\half}}
4021           {\bonuspoint@sing}{\bonuspoint@plur}%
4022   \endgroup
4023 }% \bonuspoints
4024 %\newcommand\points{%
4025 %  \begingroup
4026 %    \let\half=\relax
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}%
4033 %  \endgroup
4034 %}
4035
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
4039 % integer:
4040 %\pointname{ \ifthenelse{\@points = 1}{point}{points}}
4041
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)}%
4049 }% \marksnotpoints
4050
4051
4052 % \@marginpointname is used in place of \@pointname if any of
4053 % \@pointsinmargin, \@pointsinrightmargin, and \@pointsdropped are
4054 % true:
4055 \def\marginpointname#1{\gdef\@marginpointname{#1}}
4056 \marginpointname{}
4057 \def\marginbonuspointname#1{\gdef\@marginbonuspointname{#1}}
4058 \marginbonuspointname{ (bonus)}
4059
4060
4061 %--------------------------------------------------------------------
4062 %         choices (for multiple choice) and checkboxes
4063
4064
4065 \renewcommand\thechoice{\Alph{choice}}
4066 \newcommand\choicelabel{\thechoice.}
4067
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
4077
4078 \newcommand\CorrectChoiceEmphasis[1]{%
4079   \def\CorrectChoice@Emphasis{#1}%
4080 }
4081 \CorrectChoiceEmphasis{\bfseries}
4082 \let\correctchoiceemphasis\CorrectChoiceEmphasis
4083
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{%
4088   \choice@toks={%
4089     \questionobject@pluspagecheck
4090     \choice@toks={}%
4091   }%
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
4097     \the \choice@toks}%
4098   %   \edef\append@everypar{\noexpand\everypar={\the\everypar
4099   %                         \noexpand\the \noexpand\choice@toks}}%
4100   %   \append@everypar
4101 }% do@choice@pageinfo
4102
4103
4104
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}%
4111        \def\choice{%
4112          \if@correctchoice
4113            \color@endgroup
4114            \endgroup
4115          \fi
4116          \item
4117          \do@choice@pageinfo
4118        } % choice
4119        \def\CorrectChoice{%
4120          \if@correctchoice
4121            \color@endgroup
4122            \endgroup
4123          \fi
4124          \ifprintanswers
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
4146          \fi
4147          \item
4148          \do@choice@pageinfo
4149        } % CorrectChoice
4150        \let\correctchoice\CorrectChoice
4151        \labelwidth\leftmargin\advance\labelwidth-\labelsep
4152        \topsep=0pt
4153        \partopsep=0pt
4154        \choiceshook
4155      }%
4156   }%
4157   {\if@correctchoice \color@endgroup \endgroup \fi \endlist}
4158
4159 \newenvironment{oneparchoices}%
4160   {%
4161     \setcounter{choice}{0}%
4162     \def\choice{%
4163       \if@correctchoice \endgroup \fi
4164       \refstepcounter{choice}%
4165       \ifnum\value{choice}>1\relax
4166         \penalty -50\hskip 1em plus 1em\relax
4167       \fi
4168       \choicelabel
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
4173       \nobreak\enskip
4174     }% choice
4175     \def\CorrectChoice{%
4176       \if@correctchoice \endgroup \fi
4177       \refstepcounter{choice}%
4178       \ifprintanswers
4179         \begingroup \@correctchoicetrue 
4180         \CorrectChoice@Emphasis
4181       \fi
4182       \ifnum\value{choice}>1\relax
4183         \penalty -50\hskip 1em plus 1em\relax
4184       \fi
4185       \choicelabel
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
4190       \nobreak\enskip
4191     }% CorrectChoice
4192     \let\correctchoice\CorrectChoice
4193     \let\par\@empty
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
4197     \ignorespaces
4198   }%
4199   {\if@correctchoice \endgroup \fi}
4200
4201 \newcommand{\checkboxchar}[1]{\def\checkbox@char{#1}}
4202 \newcommand{\checkedchar}[1]{\def\checked@char{#1}}
4203 \checkboxchar{$\bigcirc$}
4204 \checkedchar{$\surd$}
4205
4206 \newenvironment{checkboxes}%
4207   {\list{\checkbox@char}%
4208      {%
4209        \settowidth{\leftmargin}{W.\hskip\labelsep\hskip 2.5em}%
4210        \def\choice{%
4211          \if@correctchoice
4212            \color@endgroup \endgroup
4213          \fi
4214          \item
4215          \do@choice@pageinfo
4216        } % choice
4217        \def\CorrectChoice{%
4218          \if@correctchoice
4219            \color@endgroup \endgroup
4220          \fi
4221          \ifprintanswers
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]
4244          \else
4245            \item
4246          \fi
4247          \do@choice@pageinfo
4248        } % CorrectChoice
4249        \let\correctchoice\CorrectChoice
4250        \labelwidth\leftmargin\advance\labelwidth-\labelsep
4251        \topsep=0pt
4252        \partopsep=0pt
4253        \checkboxeshook
4254      }%
4255   }%
4256   {\if@correctchoice \color@endgroup \endgroup \fi \endlist}
4257
4258 \newenvironment{oneparcheckboxes}%
4259   {%
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}%
4265     \def\choice{%
4266       \if@correctchoice \endgroup \fi
4267       \stepcounter{choice}%
4268       \ifnum\value{choice}>1\relax
4269         \penalty -50\hskip 1em plus 1em\relax
4270       \fi
4271       \checkbox@char
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
4276       \nobreak\enskip
4277     }% choice
4278     \def\CorrectChoice{%
4279       \if@correctchoice \endgroup \fi
4280       \stepcounter{choice}%
4281       \ifprintanswers
4282         \begingroup \@correctchoicetrue 
4283         \CorrectChoice@Emphasis
4284       \fi
4285       \ifnum\value{choice}>1\relax
4286         \penalty -50\hskip 1em plus 1em\relax
4287       \fi
4288       \ifprintanswers
4289         \checked@char
4290       \else
4291         \checkbox@char
4292       \fi
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
4297       \nobreak\enskip
4298     }% CorrectChoice
4299     \let\correctchoice\CorrectChoice
4300     \let\par\@empty
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
4304     \ignorespaces
4305   }%
4306   {\if@correctchoice \endgroup \fi}
4307
4308
4309 %--------------------------------------------------------------------
4310 %             Answer Lines (for short answer questions)
4311
4312 % Note: \ques@ref is also used in \item@points@pageinfo, and all four
4313 % of the following are used in \setup@point@toks
4314
4315 \def\ques@ref{question}
4316 \def\part@ref{part}
4317 \def\subpart@ref{subpart}
4318 \def\subsubpart@ref{subsubpart}
4319
4320 % Note: \answerclearance is also used by \fillin
4321
4322 \newlength\answerlinelength
4323 \newlength\answerskip
4324 \newlength\answerclearance
4325 \setlength\answerlinelength{1in}
4326 \setlength\answerskip{2ex}
4327 \setlength\answerclearance{0.2ex}
4328
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
4333   \else
4334     \ifx\@queslevel\part@ref
4335       \let\ans@l=\partlabel
4336     \else
4337       \ifx\@queslevel\subpart@ref
4338         \let\ans@l=\subpartlabel
4339       \else
4340         \ifx\@queslevel\subsubpart@ref
4341           \let\ans@l=\subsubpartlabel
4342         \else
4343           % Oops; no question level defined.
4344           % We must be outide of the questions environment.
4345           % Just leave out the label, I guess:
4346           \def\ans@l{}%
4347         \fi
4348       \fi
4349     \fi
4350   \fi
4351   \par \nobreak \vskip \answerskip
4352   \hfill 
4353   \ifprintanswers
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:
4357       \color@begingroup
4358       \CorrectChoice@Emphasis \hfil #1\hss
4359       \color@endgroup}%
4360   \else
4361     \ans@l~\hbox to \answerlinelength{\hrulefill}%
4362   \fi
4363   \par
4364 }% answerline
4365
4366 %--------------------------------------------------------------------
4367 %               \fillin, for fill-in-the-blank questions
4368
4369 \newlength\fillinlinelength
4370 \setlength\fillinlinelength{1in}
4371
4372 % \fillin can take two optional arguments.
4373 %
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.
4377 %
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
4381 %
4382 %   \setlength\fillinlinelength{1in}
4383 %
4384 % and can be changed by giving a new \setlength command.
4385 %
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.
4390 %
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.
4398
4399 \newcommand\fillin[1][{}]{%
4400    \def\fillin@ans{#1}%
4401    \fillin@relay
4402 }% fillin
4403
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
4412   % \exam@ifnextchar.
4413   \exam@ifnextchar[{\@fillin@relay}
4414                    {\@fillin@relay[\fillinlinelength]}%
4415 }% fillin@relay
4416
4417 \def\@fillin@relay[#1]{%
4418   % The first argument is in \fillin@ans, the second is #1.
4419   \leavevmode
4420   \ifprintanswers
4421     \rlap{\raise -\answerclearance \hbox to #1{\hrulefill}}%
4422     \begingroup
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
4427               \color@endgroup}%
4428       \else
4429         \hbox to #1{\color@begingroup\CorrectChoice@Emphasis 
4430                     \hfil \fillin@ans \hfil\color@endgroup}%
4431       \fi
4432     \endgroup
4433   \else
4434     \raise -\answerclearance \hbox to #1{\hrulefill}%
4435   \fi
4436 }% @fillin@relay
4437
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
4450 % Diez.
4451 \long\def\exam@ifnextchar#1#2#3{%
4452   \let\reserved@d=#1%
4453   \def\reserved@a{#2}%
4454   \def\reserved@b{#3}%
4455   % The following says we haven't yet seen any spaces:
4456   \@tempswafalse
4457   \futurelet\@let@token\exam@ifnch
4458 }% exam@ifnextchar
4459
4460 \def\exam@ifnch{%
4461   \ifx\@let@token\@sptoken
4462     % Signal that we've found a space:
4463     \@tempswatrue
4464     \let\reserved@c\exam@xifnch % this gobbles the space
4465   \else
4466     \ifx\@let@token\reserved@d
4467       \let\reserved@c\reserved@a
4468     \else
4469       \if@tempswa
4470         \def\reserved@c{\expandafter\reserved@b\space}%
4471       \else 
4472         \let\reserved@c\reserved@b
4473       \fi
4474     \fi
4475   \fi
4476   \reserved@c
4477 }% exam@ifnch
4478
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}
4484 }
4485
4486 %--------------------------------------------------------------------
4487 %                            \fillwithlines
4488
4489
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
4495 % margin.
4496 %
4497 % The distance between the lines is \linefillheight, whose default value
4498 % is set with the command
4499 %
4500 % \setlength\linefillheight{.25in}
4501 %
4502 % This value can be changed by giving a new \setlength command.
4503 %
4504 % The thickness of the lines is \linefillthickness, whose default value
4505 % is set with the command
4506 %
4507 % \setlength\linefillthickness{.1pt}
4508 %
4509 % This value can be changed by giving a new \setlength command.
4510 %
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
4513 % the command
4514 %
4515 %      \colorfillwithlines.
4516 %
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
4520 %
4521 %      \definecolor{FillWithLinesColor}{gray}{0.8}
4522 %
4523 % and the color can be changed by giving a new \definecolor command.
4524 % You can return to black lines by giving the command
4525 %
4526 %      \nocolorfillwithlines
4527
4528 \newlength\linefillheight
4529 \newlength\linefillthickness
4530 \setlength\linefillheight{.25in}
4531 \setlength\linefillthickness{0.1pt}
4532
4533
4534
4535
4536 \newif\if@colorfillwithlines
4537 \@colorfillwithlinesfalse
4538 \def\colorfillwithlines{%
4539   \@ifundefined{definecolor}
4540   {%
4541     \ClassError{exam}{%
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
4545       \MessageBreak
4546       }{%
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
4550       }%
4551   }%
4552   {%
4553     \definecolor{FillWithLinesColor}{gray}{0.8}
4554     \@colorfillwithlinestrue
4555   }%
4556 }% \colorfillwithlines
4557 \def\nocolorfillwithlines{\@colorfillwithlinesfalse}
4558
4559 \newcommand\fillwithlines[1]{%
4560   \if@colorfillwithlines
4561     \color@begingroup
4562       \color{FillWithLinesColor}%
4563       \do@fillwithlines{#1}%
4564     \color@endgroup
4565   \else
4566     \do@fillwithlines{#1}%
4567   \fi
4568 }% \fillwithlines
4569
4570 \newcommand\linefill{\leavevmode
4571     \leaders\hrule height \linefillthickness \hfill\kern\z@}
4572
4573 % \do@fillwithlines is called only by \fillwithlines
4574 \def\do@fillwithlines#1{%
4575   \begingroup
4576   \ifhmode
4577     \par
4578   \fi
4579   \hrule height \z@
4580   \nobreak
4581   \setbox0=\hbox to \hsize{\hskip \@totalleftmargin
4582           \vrule height \linefillheight depth \z@ width \z@
4583           \linefill}%
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{}%
4588   \endgroup
4589 }% \do@fillwithlines
4590
4591 %--------------------------------------------------------------------
4592 %                         \fillwithdottedlines
4593
4594
4595 % \fillwithdottedlines is similar to \fillwithlines, except that it
4596 % fills the space with dotted lines (created by \dotfill) rather than
4597 % with solid lines.
4598
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
4604 % margin.
4605 %
4606 % The distance between the lines is \dottedlinefillheight, whose
4607 % default value is set with the command
4608 %
4609 % \setlength\dottedlinefillheight{.25in}
4610 %
4611 % This value can be changed by giving a new \setlength command.
4612
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
4615 % given the command
4616 %
4617 %      \colorfillwithdottedlines.
4618 %
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
4622 % the command 
4623 %
4624 %      \definecolor{FillWithDottedLinesColor}{gray}{0.8}
4625 %
4626 % and the color can be changed by giving a new \definecolor command.
4627 % You can return to black lines by giving the command
4628 %
4629 %      \nocolorfillwithdottedlines
4630
4631
4632 \newlength\dottedlinefillheight
4633 \setlength\dottedlinefillheight{.25in}
4634
4635 \newif\if@colorfillwithdottedlines
4636 \@colorfillwithdottedlinesfalse
4637 \def\colorfillwithdottedlines{%
4638   \@ifundefined{definecolor}
4639   {%
4640     \ClassError{exam}{%
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
4644       \MessageBreak
4645       }{%
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
4649       }%
4650   }%
4651   {%
4652     \definecolor{FillWithDottedLinesColor}{gray}{0.8}
4653     \@colorfillwithdottedlinestrue
4654   }%
4655 }% \colorfillwithdottedlines
4656 \def\nocolorfillwithdottedlines{\@colorfillwithdottedlinesfalse}
4657
4658 \newcommand\fillwithdottedlines[1]{%
4659   \if@colorfillwithdottedlines
4660     \color@begingroup
4661       \color{FillWithDottedLinesColor}%
4662       \do@fillwithdottedlines{#1}%
4663     \color@endgroup
4664   \else
4665     \do@fillwithdottedlines{#1}%
4666   \fi
4667 }% \fillwithdottedlines
4668
4669 % \do@fillwithdottedlines is called only by \fillwithdottedlines
4670 \def\do@fillwithdottedlines#1{%
4671   \begingroup
4672   \ifhmode
4673     \par
4674   \fi
4675   \hrule height \z@
4676   \nobreak
4677   \setbox0=\hbox to \hsize{\hskip \@totalleftmargin
4678           \vrule height \dottedlinefillheight depth \z@ width \z@
4679           \dotfill}%
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{}%
4684   \endgroup
4685 }% \do@fillwithdottedlines
4686
4687 %--------------------------------------------------------------------
4688 %                            \fillwithgrid
4689
4690
4691 % \fillwithgrid is similar to \fillwithlines, except that it
4692 % fills the space with a grid.
4693
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.
4699 %
4700 % The default grid size and grid line thickness were set by the
4701 % commands
4702 %
4703 % \setlength{\gridsize}{5mm}
4704 % \setlength{\gridlinewidth}{0.1pt}
4705 %
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.
4713
4714 % By default, the created grids are in black.  However, if you give the
4715 % commands
4716 %
4717 % \usepackage{color}
4718 % \colorgrids
4719 %
4720 % then the grids will be in color, by default a light gray.  That
4721 % default color was defined by the command
4722 %
4723 % \definecolor{GridColor}{gray}{0.8}
4724 %
4725 % You can change the color by redefining the color GridColor by giving
4726 % a new \definecolor command.
4727
4728 \newif\if@colorgrids
4729 \newcommand\colorgrids{%
4730   \@ifundefined{definecolor}
4731   {%
4732     \ClassError{exam}{%
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
4736       }{%
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
4740       }%
4741   }%
4742   {%
4743     \definecolor{GridColor}{gray}{0.8}
4744     \@colorgridstrue
4745   }%
4746 }% \colorgrids
4747 \newcommand\nocolorgrids{\@colorgridsfalse}
4748 \nocolorgrids
4749
4750 \newlength\gridsize
4751 \newlength\gridlinewidth
4752 \setlength{\gridsize}{5mm}
4753 \setlength{\gridlinewidth}{0.1pt}
4754
4755 \def\fillwithgrid#1{%
4756   \begingroup
4757   \ifhmode
4758     \par
4759   \fi
4760   \hrule height \z@
4761   \nobreak
4762
4763   % We first set box0 equal to an \hbox which, when printed, is a
4764   % square with width and height equal to \gridsize+\gridlinewidth,
4765   % but which has
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
4772   % the box below it.
4773   \setlength{\@tempdima}{\gridsize}
4774   \addtolength{\@tempdima}{\gridlinewidth}
4775   \setlength{\@tempdimb}{\gridsize}
4776   \addtolength{\@tempdimb}{-\gridlinewidth}
4777   \setbox0=\hbox{%
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}%
4782   }%
4783   \wd0=\gridsize
4784   \dp0=0pt
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
4791   % appears.
4792   \setbox1=\hbox to \textwidth{%
4793     \color@begingroup
4794     \if@colorgrids
4795       \color{GridColor}%
4796     \fi
4797     \hskip \@totalleftmargin \leaders\copy0\hfil \kern\gridlinewidth
4798     \color@endgroup
4799   }%
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{}%
4807   \endgroup
4808 }% fillwithgrid
4809
4810 %--------------------------------------------------------------------
4811 %                            \makeemptybox
4812
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.
4818
4819 % As of version 2.304, the argument of \makeemptybox can be either
4820 % a length, or \fill, or \stretch{number}.
4821
4822 % \newcommand\makeemptybox[1]{
4823 %   \par
4824 %   \begingroup
4825 %     \setlength{\fboxsep}{0pt}%
4826 %     \framebox[\linewidth]{%
4827 %       \vrule height 0pt depth #1 width 0pt
4828 %     }%
4829 %   \endgroup
4830 % }
4831
4832 \newlength\minboxheight
4833 \setlength\minboxheight{.1in}
4834
4835
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.
4841
4842 \newcommand\makeemptybox[1]{%
4843   \if@colorsolutionboxes
4844     \color@begingroup
4845       \color{SolutionBoxColor}%
4846       \do@emptybox{#1}%
4847     \color@endgroup
4848   \else
4849     \do@emptybox{#1}%
4850   \fi
4851 }
4852
4853 % The command \do@emptybox is called only by \makeemptybox.
4854 \newcommand\do@emptybox[1]{%
4855   \par
4856   \hbox to \hsize{\hskip\@totalleftmargin \leaders\hrule\hfill}%
4857   \nointerlineskip
4858   \begingroup
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.
4867     \copy0
4868     \nobreak
4869     \vskip -\minboxheight
4870     \cleaders \copy0 \vskip #1
4871     \vskip -\minboxheight
4872     \nointerlineskip
4873     \copy0
4874   \endgroup
4875   \nointerlineskip
4876   \hbox to \hsize{\hskip\@totalleftmargin \leaders\hrule\hfill}%
4877 }
4878
4879 %--------------------------------------------------------------------
4880 %                      \uplevel and \fullwidth
4881 %           and the EnvUplevel and EnvFullwidth environments:
4882
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.}
4887
4888 % \fullwidth is similar, but uses the full page of text on the page.
4889
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.)
4894
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.)
4899
4900
4901 \long\def\uplevel#1{%
4902   \par\bigskip
4903   \vbox{%
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
4913     #1%
4914   }% vbox
4915   \nobreak
4916 }
4917
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
4928   }
4929   {\egroup\nobreak}
4930
4931
4932 \long\def\fullwidth#1{%
4933   \par\bigskip
4934   \vbox{%
4935     % We entered internal vertical mode, and so we get \parshape=0.
4936     \leftskip=0pt \rightskip=0pt
4937     \advance\linewidth\@totalleftmargin
4938     \@totalleftmargin=0pt
4939     #1%
4940   }% vbox
4941   \nobreak
4942 }
4943
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
4952   }
4953   {\egroup\nobreak}
4954
4955
4956 %--------------------------------------------------------------------
4957 %--------------------------------------------------------------------
4958 %
4959 %                        ********************
4960 %                        ** GRADING TABLES **
4961 %                        ********************
4962
4963
4964
4965 \newcounter{@iterator}
4966 \newlength\@cellwidth
4967
4968 \def\cellwidth#1{\@cellwidth=#1}
4969 \def\gradetablestretch#1{\def\@gtblstretch{#1}}
4970
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
4978
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
4984
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}}
4992
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}}
4998
4999
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}}
5006
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}}
5012
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}}
5020
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}}
5027
5028
5029
5030 % Initialize:
5031 \cellwidth{2em}
5032 \gradetablestretch{1.5}
5033
5034 \hqword{Question:}
5035 \hpgword{Page:}
5036 \hpword{Points:}
5037 \hsword{Score:}
5038 \htword{Total}
5039 \vpword{Points}
5040 \vsword{Score}
5041 \vtword{Total:}
5042 \vqword{Question}
5043 \vpgword{Page}
5044
5045 \bhqword{Question:}
5046 \bhpgword{Page:}
5047 \bhpword{Bonus Points:}
5048 \bhsword{Score:}
5049 \bhtword{Total}
5050 \bvqword{Question}
5051 \bvpgword{Page}
5052 \bvpword{Bonus Points}
5053 \bvsword{Score}
5054 \bvtword{Total:}
5055
5056 \chqword{Question:}
5057 \chpgword{Page:}
5058 \chpword{Points:}
5059 \chbpword{Bonus Points:}
5060 \chsword{Score:}
5061 \chtword{Total}
5062 \cvqword{Question}
5063 \cvpgword{Page}
5064 \cvpword{Points}
5065 \cvbpword{Bonus Points}
5066 \cvsword{Score}
5067 \cvtword{Total:}
5068
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
5078
5079 % \def\multirowgradetable
5080 % \def\multirowpointtable
5081 % \def\multirowbonusgradetable
5082 % \def\multirowbonuspointtable
5083 % \def\multirowcombinedgradetable
5084 % \def\multirowcombinedpointtable
5085
5086 % \def\multirowpartialgradetable
5087 % \def\multirowpartialpointtable
5088 % \def\multirowpartialbonusgradetable
5089 % \def\multirowpartialbonuspointtable
5090 % \def\multirowpartialcombinedgradetable
5091 % \def\multirowpartialcombinedpointtable
5092
5093 % \def\multicolumngradetable
5094 % \def\multicolumnpointtable
5095 % \def\multicolumnbonusgradetable
5096 % \def\multicolumnbonuspointtable
5097 % \def\multicolumncombinedgradetable
5098 % \def\multicolumncombinedpointtable
5099
5100 % \def\multicolumnpartialgradetable
5101 % \def\multicolumnpartialpointtable
5102 % \def\multicolumnpartialbonusgradetable
5103 % \def\multicolumnpartialbonuspointtable
5104 % \def\multicolumnpartialcombinedgradetable
5105 % \def\multicolumnpartialcombinedpointtable
5106
5107
5108 % The possibilities are
5109
5110 %   \gradetable[v][questions]
5111 %   \gradetable[v][pages]
5112 %   \gradetable[h][questions]
5113 %   \gradetable[h][pages]
5114
5115 %   \bonusgradetable[v][questions]
5116 %   \bonusgradetable[v][pages]
5117 %   \bonusgradetable[h][questions]
5118 %   \bonusgradetable[h][pages]
5119
5120 %   \combinedgradetable[v][questions]
5121 %   \combinedgradetable[v][pages]
5122 %   \combinedgradetable[h][questions]
5123 %   \combinedgradetable[h][pages]
5124
5125 %   \pointtable[v][questions]
5126 %   \pointtable[v][pages]
5127 %   \pointtable[h][questions]
5128 %   \pointtable[h][pages]
5129
5130 %   \bonuspointtable[v][questions]
5131 %   \bonuspointtable[v][pages]
5132 %   \bonuspointtable[h][questions]
5133 %   \bonuspointtable[h][pages]
5134
5135 %   \combinedpointtable[v][questions]
5136 %   \combinedpointtable[v][pages]
5137 %   \combinedpointtable[h][questions]
5138 %   \combinedpointtable[h][pages]
5139
5140 %   \partialgradetable{whatever}[v][questions]
5141 %   \partialgradetable{whatever}[v][pages]
5142 %   \partialgradetable{whatever}[h][questions]
5143 %   \partialgradetable{whatever}[h][pages]
5144
5145 %   \partialbonusgradetable{whatever}[v][questions]
5146 %   \partialbonusgradetable{whatever}[v][pages]
5147 %   \partialbonusgradetable{whatever}[h][questions]
5148 %   \partialbonusgradetable{whatever}[h][pages]
5149
5150 %   \partialcombinedgradetable{whatever}[v][questions]
5151 %   \partialcombinedgradetable{whatever}[v][pages]
5152 %   \partialcombinedgradetable{whatever}[h][questions]
5153 %   \partialcombinedgradetable{whatever}[h][pages]
5154
5155 %   \partialpointtable{whatever}[v][questions]
5156 %   \partialpointtable{whatever}[v][pages]
5157 %   \partialpointtable{whatever}[h][questions]
5158 %   \partialpointtable{whatever}[h][pages]
5159
5160 %   \partialbonuspointtable{whatever}[v][questions]
5161 %   \partialbonuspointtable{whatever}[v][pages]
5162 %   \partialbonuspointtable{whatever}[h][questions]
5163 %   \partialbonuspointtable{whatever}[h][pages]
5164
5165 %   \partialcombinedpointtable{whatever}[v][questions]
5166 %   \partialcombinedpointtable{whatever}[v][pages]
5167 %   \partialcombinedpointtable{whatever}[h][questions]
5168 %   \partialcombinedpointtable{whatever}[h][pages]
5169
5170 %   \begingradingrange{whatever}
5171 %   \endgradingrange{whatever}
5172 %
5173 %   \pointsinrange{whatever}
5174 %   \bonuspointsinrange{whatever}
5175 %
5176 %    \firstqinrange{whatever}
5177 %    \lastqinrange{whatever}
5178 %    \numqinrange{whatever}
5179 %
5180 % where ``whatever'' is a label chosen by the user.
5181
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]
5188
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]
5195
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]
5202
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]
5209
5210
5211 % If one or both optional arguments are omitted, the defaults are
5212 % `[v]' and `[questions]'.
5213
5214 % \@scorestrue means we're doing \gradetable
5215 % \@scoresfalse mans we're doing \pointtable
5216 \newif\if@scores
5217
5218 % \@partialtrue means we're doing \partialgradetable,
5219 % \partialbonusgradetable, \partialcombinedgradetable,
5220 % \partialpointtable, \partialbonuspointtable, or
5221 % \partialcombinedpointtable:
5222 \newif\if@partial
5223
5224 % \@combinedtrue means we're doing \combinedgradetable,
5225 % \combinedpointtable, \partialcombinedgradetable, or
5226 % \partialcombinedpointtable:
5227 \newif\if@combined
5228
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}}}%
5239   \write\@mainaux
5240   {\string\expandafter\string\gdef
5241     \string\csname\space range@#1@firstp\string\endcsname
5242       {\thepage}}%
5243 }% begingradingrange
5244
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}}}%
5251   \write\@mainaux
5252   {\string\expandafter\string\gdef
5253     \string\csname\space range@#1@lastp\string\endcsname
5254       {\thepage}}%
5255 }% endgradingrange
5256
5257
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}
5262
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}
5266
5267 %--------------------------------------------------------------------
5268 % multirow tables, non-partial:
5269
5270 \def\multirowgradetable#1{%
5271   \@scorestrue
5272   \@bonusfalse
5273   \@partialfalse
5274   \@combinedfalse
5275   \setcounter{num@rows}{#1}%
5276   \i@gtable[h]%
5277 }
5278
5279 \def\multirowpointtable#1{%
5280   \@scoresfalse
5281   \@bonusfalse
5282   \@partialfalse
5283   \@combinedfalse
5284   \setcounter{num@rows}{#1}%
5285   \i@gtable[h]%
5286 }
5287
5288 \def\multirowbonusgradetable#1{%
5289   \@scorestrue
5290   \@bonustrue
5291   \@partialfalse
5292   \@combinedfalse
5293   \setcounter{num@rows}{#1}%
5294   \i@gtable[h]%
5295 }
5296
5297 \def\multirowbonuspointtable#1{%
5298   \@scoresfalse
5299   \@bonustrue
5300   \@partialfalse
5301   \@combinedfalse
5302   \setcounter{num@rows}{#1}%
5303   \i@gtable[h]%
5304 }
5305
5306 \def\multirowcombinedgradetable#1{%
5307   \@scorestrue
5308   \@bonusfalse
5309   \@partialfalse
5310   \@combinedtrue
5311   \setcounter{num@rows}{#1}%
5312   \i@gtable[h]%
5313 }
5314
5315 \def\multirowcombinedpointtable#1{%
5316   \@scoresfalse
5317   \@bonusfalse
5318   \@partialfalse
5319   \@combinedtrue
5320   \setcounter{num@rows}{#1}%
5321   \i@gtable[h]%
5322 }
5323
5324 %--------------------------------------------------------------------
5325 % multirow tables, partial:
5326
5327 \def\multirowpartialgradetable#1#2{%
5328   \@scorestrue
5329   \@bonusfalse
5330   \@partialtrue
5331   \@combinedfalse
5332   \def\tbl@range{#2}%
5333   \setcounter{num@rows}{#1}%
5334   \i@gtable[h]%
5335 }
5336
5337 \def\multirowpartialpointtable#1#2{%
5338   \@scoresfalse
5339   \@bonusfalse
5340   \@partialtrue
5341   \@combinedfalse
5342   \def\tbl@range{#2}%
5343   \setcounter{num@rows}{#1}%
5344   \i@gtable[h]%
5345 }
5346
5347 \def\multirowpartialbonusgradetable#1#2{%
5348   \@scorestrue
5349   \@bonustrue
5350   \@partialtrue
5351   \@combinedfalse
5352   \def\tbl@range{#2}%
5353   \setcounter{num@rows}{#1}%
5354   \i@gtable[h]%
5355 }
5356
5357 \def\multirowpartialbonuspointtable#1#2{%
5358   \@scoresfalse
5359   \@bonustrue
5360   \@partialtrue
5361   \@combinedfalse
5362   \def\tbl@range{#2}%
5363   \setcounter{num@rows}{#1}%
5364   \i@gtable[h]%
5365 }
5366
5367 \def\multirowpartialcombinedgradetable#1#2{%
5368   \@scorestrue
5369   \@bonusfalse
5370   \@partialtrue
5371   \@combinedtrue
5372   \def\tbl@range{#2}%
5373   \setcounter{num@rows}{#1}%
5374   \i@gtable[h]%
5375 }
5376
5377 \def\multirowpartialcombinedpointtable#1#2{%
5378   \@scoresfalse
5379   \@bonusfalse
5380   \@partialtrue
5381   \@combinedtrue
5382   \def\tbl@range{#2}%
5383   \setcounter{num@rows}{#1}%
5384   \i@gtable[h]%
5385 }
5386
5387 %--------------------------------------------------------------------
5388 %  multicolumn tables, non-partial:
5389
5390 \def\multicolumngradetable#1{%
5391   \@scorestrue
5392   \@bonusfalse
5393   \@partialfalse
5394   \@combinedfalse
5395   \setcounter{num@cols}{#1}%
5396   \i@gtable[v]%
5397 }
5398
5399 \def\multicolumnpointtable#1{%
5400   \@scoresfalse
5401   \@bonusfalse
5402   \@partialfalse
5403   \@combinedfalse
5404   \setcounter{num@cols}{#1}%
5405   \i@gtable[v]%
5406 }
5407
5408 \def\multicolumnbonusgradetable#1{%
5409   \@scorestrue
5410   \@bonustrue
5411   \@partialfalse
5412   \@combinedfalse
5413   \setcounter{num@cols}{#1}%
5414   \i@gtable[v]%
5415 }
5416
5417 \def\multicolumnbonuspointtable#1{%
5418   \@scoresfalse
5419   \@bonustrue
5420   \@partialfalse
5421   \@combinedfalse
5422   \setcounter{num@cols}{#1}%
5423   \i@gtable[v]%
5424 }
5425
5426 \def\multicolumncombinedgradetable#1{%
5427   \@scorestrue
5428   \@bonusfalse
5429   \@partialfalse
5430   \@combinedtrue
5431   \setcounter{num@cols}{#1}%
5432   \i@gtable[v]%
5433 }
5434
5435 \def\multicolumncombinedpointtable#1{%
5436   \@scoresfalse
5437   \@bonusfalse
5438   \@partialfalse
5439   \@combinedtrue
5440   \setcounter{num@cols}{#1}%
5441   \i@gtable[v]%
5442 }
5443
5444 %--------------------------------------------------------------------
5445 % multicolumn tables, partial:
5446
5447 \def\multicolumnpartialgradetable#1#2{%
5448   \@scorestrue
5449   \@bonusfalse
5450   \@partialtrue
5451   \@combinedfalse
5452   \def\tbl@range{#2}%
5453   \setcounter{num@cols}{#1}%
5454   \i@gtable[v]%
5455 }
5456
5457 \def\multicolumnpartialpointtable#1#2{%
5458   \@scoresfalse
5459   \@bonusfalse
5460   \@partialtrue
5461   \@combinedfalse
5462   \def\tbl@range{#2}%
5463   \setcounter{num@cols}{#1}%
5464   \i@gtable[v]%
5465 }
5466
5467 \def\multicolumnpartialbonusgradetable#1#2{%
5468   \@scorestrue
5469   \@bonustrue
5470   \@partialtrue
5471   \@combinedfalse
5472   \def\tbl@range{#2}%
5473   \setcounter{num@cols}{#1}%
5474   \i@gtable[v]%
5475 }
5476
5477 \def\multicolumnpartialbonuspointtable#1#2{%
5478   \@scoresfalse
5479   \@bonustrue
5480   \@partialtrue
5481   \@combinedfalse
5482   \def\tbl@range{#2}%
5483   \setcounter{num@cols}{#1}%
5484   \i@gtable[v]%
5485 }
5486
5487 \def\multicolumnpartialcombinedgradetable#1#2{%
5488   \@scorestrue
5489   \@bonusfalse
5490   \@partialtrue
5491   \@combinedtrue
5492   \def\tbl@range{#2}%
5493   \setcounter{num@cols}{#1}%
5494   \i@gtable[v]%
5495 }
5496
5497 \def\multicolumnpartialcombinedpointtable#1#2{%
5498   \@scoresfalse
5499   \@bonusfalse
5500   \@partialtrue
5501   \@combinedtrue
5502   \def\tbl@range{#2}%
5503   \setcounter{num@cols}{#1}%
5504   \i@gtable[v]%
5505 }
5506
5507 %--------------------------------------------------------------------
5508 % partial single row (and column) tables:
5509
5510 \def\partialgradetable#1{%
5511   \@scorestrue
5512   \@bonusfalse
5513   \@partialtrue
5514   \@combinedfalse
5515   \def\tbl@range{#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
5527
5528 \def\partialbonusgradetable#1{%
5529   \@scorestrue
5530   \@bonustrue
5531   \@partialtrue
5532   \@combinedfalse
5533   \def\tbl@range{#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
5545
5546 \def\partialcombinedgradetable#1{%
5547   \@scorestrue
5548   \@bonusfalse
5549   \@partialtrue
5550   \@combinedtrue
5551   \def\tbl@range{#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
5563
5564 \def\partialpointtable#1{%
5565   \@scoresfalse
5566   \@bonusfalse
5567   \@partialtrue
5568   \@combinedfalse
5569   \def\tbl@range{#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
5581
5582 \def\partialbonuspointtable#1{%
5583   \@scoresfalse
5584   \@bonustrue
5585   \@partialtrue
5586   \@combinedfalse
5587   \def\tbl@range{#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
5599
5600 \def\partialcombinedpointtable#1{%
5601   \@scoresfalse
5602   \@bonusfalse
5603   \@partialtrue
5604   \@combinedtrue
5605   \def\tbl@range{#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
5617
5618 %--------------------------------------------------------------------
5619 % single row (and column) tables, non-partial:
5620
5621 \def\gradetable{%
5622   \@scorestrue
5623   \@bonusfalse
5624   \@partialfalse
5625   \@combinedfalse
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]}%
5636 }% gradetable
5637
5638 \def\bonusgradetable{%
5639   \@scorestrue
5640   \@bonustrue
5641   \@partialfalse
5642   \@combinedfalse
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]}%
5653 }% bonusgradetable
5654
5655 \def\combinedgradetable{%
5656   \@scorestrue
5657   \@bonusfalse
5658   \@partialfalse
5659   \@combinedtrue
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]}%
5670 }% bonusgradetable
5671
5672 \def\pointtable{%
5673   \@scoresfalse
5674   \@bonusfalse
5675   \@partialfalse
5676   \@combinedfalse
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]}%
5687 }% pointtable
5688
5689 \def\bonuspointtable{%
5690   \@scoresfalse
5691   \@bonustrue
5692   \@partialfalse
5693   \@combinedfalse
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]}%
5704 }% bonuspointtable
5705
5706 \def\combinedpointtable{%
5707   \@scoresfalse
5708   \@bonusfalse
5709   \@partialfalse
5710   \@combinedtrue
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]}%
5721 }% bonuspointtable
5722
5723 %--------------------------------------------------------------------
5724
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].
5731
5732 \def\i@gtable[#1]{%
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]}%
5737 }
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.
5745   \if@addpoints
5746     \@ifundefined{exam@numpoints}%
5747       {\ClassWarning{exam}%
5748         {%
5749           You must run LaTeX again to produce the
5750             table.\MessageBreak
5751         }%
5752         \fbox{Run \LaTeX{} again to produce the table}%
5753       }%
5754       {\find@p@or@q@range{#1}{#2}}%
5755   \else
5756     \ClassError{exam}{%
5757       You must give the command \protect\addpoints\MessageBreak
5758       \space\space in order to create a grade table.\MessageBreak
5759       }{%
5760       If you don't give the command \protect\addpoints\MessageBreak
5761       \space\space then we're not keeping track of point values.
5762       \MessageBreak
5763       }%
5764   \fi
5765 }% ii@gtable
5766
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):
5776   \begingroup
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.
5779     \def\exam@temp{#2}%
5780     \ifx\exam@temp\@questionsref
5781       \tbl@pgsfalse
5782       \find@qrange{#1}%
5783     \else
5784       \ifx\exam@temp\@pagesref
5785         \tbl@pgstrue
5786         \find@prange{#1}%
5787       \else
5788         \ClassError{exam}{%
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
5792         }{%
5793           Grade tables and point tables can be indexed by questions or
5794           pages;\MessageBreak
5795           \space\space for others, you're on your own.\MessageBreak
5796         }%
5797         \fbox{\textbf{Error:} grade or point table: Invalid argument
5798               `#2' must be `questions' or `pages'.}%
5799       \fi
5800     \fi
5801   \endgroup
5802 }% find@p@or@q@range
5803
5804 % \range@undefined can be called from either \find@qrange or
5805 % \find@prange
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
5812   }%
5813 }% range@undefined
5814
5815
5816 %--------------------------------------------------------------------
5817 %--------------------------------------------------------------------
5818 % Grade and point tables indexed by question numbers:
5819
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''
5828 % or ``h''.
5829
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.
5833   \if@partial
5834     \@ifundefined{range@\tbl@range @firstq}%
5835       {%
5836         \range@undefined
5837       }%
5838       {%
5839         \@ifundefined{range@\tbl@range @lastq}%
5840           {%
5841             \range@undefined
5842           }%
5843           {%
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.}%
5852               \ClassError{exam}{%
5853                 In grading range `\tbl@range',
5854                                 the last question\MessageBreak
5855                 \space\space comes before the first question.\MessageBreak
5856                 }{%
5857                   \string\begingradingrange \space must precede
5858                   \string\endgradingrange \space by at
5859                              least one question.\MessageBreak
5860                 }%
5861             \else
5862               \tbl@v@or@h{#1}%
5863             \fi
5864           }%
5865       }%
5866   \else
5867     \def\tbl@firstq{1}%
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
5875     \tbl@v@or@h{#1}%
5876   \fi
5877 }% find@qrange
5878
5879 \def\@vref{v}
5880 \def\@href{h}
5881 \def\tbl@v@or@h#1{%
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
5885   % accordingly.
5886   \def\exam@temp{#1}%
5887   \ifx\exam@temp\@vref
5888     \check@num@cols@v
5889   \else
5890     \ifx\exam@temp\@href
5891       \check@num@rows@h
5892     \else
5893       \ClassError{exam}{%
5894         Grade or point table: the argument `#1'\MessageBreak
5895         \space\space must be `v' or `h'.
5896         \MessageBreak
5897       }{%
5898         Grade tables and point tables can be either vertical or
5899         horizontal;\MessageBreak
5900         \space\space no diagonals allowed.\MessageBreak
5901       }%
5902       \fbox{\textbf{Error:} grade or point table: Invalid argument
5903             `#1' must be `v' or `h'.}%
5904     \fi
5905   \fi
5906 }% tbl@v@or@h
5907
5908 %--------------------------------------------------------------------
5909 %--------------------------------------------------------------------
5910 % Grade and point tables indexed by page numbers:
5911
5912
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.
5919 %
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
5923 % lines:
5924 %   \set@hlfcntr{tmp@hlfcntr}{\csname pointsonpage@\romannumeral
5925 %                          \csname c@@iterator\endcsname\endcsname}%
5926 %   \ifhlfcntr@pos{tmp@hlfcntr}%
5927 % and if 
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).
5932
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
5936 % \check@secondrun.
5937
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).
5953   \if@partial
5954     \@ifundefined{range@\tbl@range @firstp}%
5955       {%
5956         \range@undefined
5957       }%
5958       {%
5959         \@ifundefined{range@\tbl@range @lastp}%
5960           {%
5961             \range@undefined
5962           }%
5963           {%
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.}%
5972               \ClassError{exam}{%
5973                 In grading range `\tbl@range', the last page\MessageBreak
5974                 \space\space comes before the first page.\MessageBreak
5975                 }{%
5976                   \string\begingradingrange \space must precede
5977                   \string\endgradingrange.\MessageBreak
5978                 }%
5979             \else
5980               \check@secondrun{#1}%
5981             \fi
5982           }%
5983       }%
5984   \else
5985     % It's not a partial table:
5986     \def\tbl@firstp{1}%
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
5992     \if@bonus
5993       \def\tbl@lastp{\lastpage@withbonuspoints}%
5994       \let\last@pq@index=\tbl@lastp
5995     \fi
5996     \if@combined
5997       \ifnum \lastpage@withbonuspoints > \lastpage@withpoints\relax
5998         \def\tbl@lastp{\lastpage@withbonuspoints}%
5999         \let\last@pq@index=\tbl@lastp
6000       \fi        
6001     \fi
6002     \check@secondrun{#1}%
6003   \fi
6004 }% find@prange
6005
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
6011   % ``h''.
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}%
6021         }%
6022         {\tbl@v@or@h{#1}%
6023         }%
6024     }%
6025     {\tbl@v@or@h{#1}%
6026     }%
6027 }% check@secondrun
6028
6029 %--------------------------------------------------------------------
6030 % Indexed by pages:
6031
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.
6036
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.
6041   \setcounter{#1}{0}%
6042   \setcounter{@iterator}{\tbl@firstp}%
6043   \addtocounter{@iterator}{-1}%
6044   \if@bonus
6045     \docount@pgswbpts{#1}%
6046   \else
6047     \if@combined
6048       \docount@pgswcpts{#1}%
6049     \else
6050       \docount@pgswpts{#1}%
6051     \fi
6052   \fi
6053 }% count@pgswpts
6054
6055 \def\docount@pgswcpts#1{%
6056   % Called by \count@pgswpts
6057   % Count the number of pages in range with any kind of point (bonus
6058   % or non-bonus):
6059   \addtocounter{@iterator}{1}%
6060   \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\the@iterator}}%
6061   \ifhlfcntr@pos{tmp@hlfcntr}%
6062     \addtocounter{#1}{1}%
6063   \else
6064     \check@bnsptpage{#1}%
6065   \fi
6066   \ifnum \the@iterator < \tbl@lastp\relax
6067     \def\nextdocount@pgswcpts{\docount@pgswcpts{#1}}%
6068   \else
6069     \let\nextdocount@pgswcpts=\relax
6070   \fi
6071   \nextdocount@pgswcpts
6072 }% docount@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}%
6081   \fi
6082 }% check@bnsptpage
6083
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}%
6091   \fi
6092   \ifnum \the@iterator < \tbl@lastp\relax
6093     \def\nextdocount@pgswpts{\docount@pgswpts{#1}}%
6094   \else
6095     \let\nextdocount@pgswpts=\relax
6096   \fi
6097   \nextdocount@pgswpts
6098 }% docount@pgswpts
6099
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}%
6107   \fi
6108   \ifnum \the@iterator < \tbl@lastp\relax
6109     \def\nextdocount@pgswbpts{\docount@pgswbpts{#1}}%
6110   \else
6111     \let\nextdocount@pgswbpts=\relax
6112   \fi
6113   \nextdocount@pgswbpts
6114 }% docount@pgswbpts
6115
6116 %--------------------------------------------------------------------
6117 %--------------------------------------------------------------------
6118 % Multirow horizontal tables, indexed by question numbers:
6119
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
6122 % question number.
6123
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
6128 % current row.
6129
6130 \newcounter{pq@index@bpts}% used to set bonus point values in
6131 % horizontal tables.  Often used as scratch elsewhere.
6132
6133 \def\hidden@ampersand{&}% Needed because an ampersand can't appear in
6134 % the replacement text of a conditional.
6135
6136 \newif\iftbl@pgs
6137 % \tbl@pgstrue means a table indexed by page numbers
6138 % \tbl@pgsfalse means a table indexed by question numbers
6139
6140 \newcounter{num@cols}
6141 \newcounter{num@rows}
6142 \newcounter{current@row}
6143 \newcounter{cols@done}% Holds the number of columns done in the
6144 % current row.
6145
6146 %--------------------------------------------------------------------
6147 %--------------------------------------------------------------------
6148 % Stuff to unify tables indexed by questions and tables indexed by
6149 % pages:
6150
6151 % \first@pq@index and \last@pq@index will hold either \tbl@firstq and
6152 % \tbl@lastq or \tbl@firstp and \tbl@lastp.
6153
6154 \def\increment@index#1{%
6155   % If we're doing a table indexed by question numbers, we increment
6156   % the counter #1.
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.
6161   \iftbl@pgs
6162     \find@nextpagewithpoints{#1}%
6163   \else
6164     \addtocounter{#1}{1}%
6165   \fi
6166 }% increment@index
6167
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.
6176   \iftbl@pgs
6177     \find@nextcolumnpage@v{#1}%
6178   \else
6179     \addtocounter{#1}{\value{num@rows}}%
6180   \fi
6181 }% nextcolumn@index@v
6182
6183 \def\pointsof@index#1{%
6184   \iftbl@pgs
6185     \pointsonpage{\arabic{#1}}%
6186   \else
6187     \pointsofquestion{\arabic{#1}}%
6188   \fi
6189 }% pointsof@index
6190
6191 \def\bonuspointsof@index#1{%
6192   \iftbl@pgs
6193     \bonuspointsonpage{\arabic{#1}}%
6194   \else
6195     \bonuspointsofquestion{\arabic{#1}}%
6196   \fi
6197 }% bonuspointsof@index
6198
6199 \def\refto@index#1{%
6200   \iftbl@pgs
6201     \if@combined
6202       % Need to hide this inside of a macro:
6203       \refto@comb@index{#1}%
6204     \else
6205       \if@bonus
6206         \pageref{firstbonuspoints@onpage@\arabic{#1}}%
6207       \else
6208         \pageref{firstpoints@onpage@\arabic{#1}}%
6209       \fi
6210     \fi
6211   \else
6212     \ref{question@\arabic{#1}}%
6213   \fi
6214 }% refto@index
6215
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}}%
6223   \else
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}}%
6230   \fi
6231 }% refto@comb@index
6232
6233 %--------------------------------------------------------------------
6234 %--------------------------------------------------------------------
6235 % Multirow tables:
6236
6237
6238 %--------------------------------------------------------------------
6239 % Check that the number of rows is OK, and compute the number of
6240 % columns:
6241
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
6247     \ClassError{exam}{%
6248       The number of rows in a table must be positive.\MessageBreak
6249     }{%
6250       The number of rows must be a positive integer.\MessageBreak
6251     }%
6252     \fbox{\textbf{Error:} Multirow table with no rows!}%
6253   \else
6254     \@computenumcols@h
6255   \fi
6256 }% check@num@rows@h
6257
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:
6264   \iftbl@pgs
6265     \count@pgswpts{num@cols}%
6266     \addtocounter{num@cols}{1}%
6267   \else
6268     \setcounter{num@cols}{\tbl@lastq}%
6269     \addtocounter{num@cols}{-\tbl@firstq}%
6270     \addtocounter{num@cols}{2}%
6271   \fi
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}%
6286   \fi
6287   \@multirowtable
6288 }% @computenumcols@h
6289
6290 %--------------------------------------------------------------------
6291 % Construct the actual table:
6292
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|}}
6305     \hline
6306     \if@combined
6307       \do@comblines@h
6308     \else
6309       \do@lines@h
6310     \fi
6311 }% @multirowtable
6312
6313
6314 \def\do@lines@h{%
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
6318   \iftbl@pgs
6319     \if@bonus
6320       \@bhpgword
6321     \else
6322       \@hpgword
6323     \fi
6324   \else
6325     \if@bonus
6326       \@bhqword
6327     \else
6328       \@hqword
6329     \fi
6330   \fi
6331   \setcounter{cols@done}{0}%
6332   \do@pq@indexloop@h
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:
6341       \do@htword@h
6342     \else
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}}%
6347       \do@emptycols@h
6348     \fi
6349   \fi
6350   \\
6351   \hline
6352   % Point values go here!
6353   \setcounter{cols@done}{0}%
6354   \if@bonus
6355     \@bhpword
6356     \do@bptloop@h
6357   \else
6358     \@hpword
6359     \do@ptloop@h
6360   \fi
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:
6369       \if@bonus
6370         \do@totalbpts@h
6371       \else
6372         \do@totalpts@h
6373       \fi
6374     \else
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}}%
6379       \do@emptycols@h
6380     \fi
6381   \fi
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
6384   % "\hline".
6385   % Scores?
6386   \if@scores
6387     \\
6388     \hline
6389     \if@bonus
6390       \@bhsword \hidden@ampersand
6391     \else
6392       \@hsword \hidden@ampersand
6393     \fi
6394     \setcounter{cols@done}{0}%
6395     \do@sloop@h
6396   \fi
6397   \ifnum \value{current@row} = \value{num@rows}\relax
6398     % This is the last line!  End the tabular:
6399     \\
6400     \hline
6401     \end{tabular}%
6402   \else
6403     % Don't end the tabular:
6404     \\
6405     \hline\hline
6406   \fi
6407   % Check if we should repeat:
6408   \ifnum \value{current@row} < \value{num@rows}\relax
6409     \let\nextdo@lines@h=\do@lines@h
6410   \else
6411     \let\nextdo@lines@h=\relax
6412   \fi
6413   \nextdo@lines@h
6414 }% do@lines@h
6415
6416 \def\do@comblines@h{%
6417   % Called only by \@multirowtable.
6418   % Combined tables.
6419   \addtocounter{current@row}{1}% Set to the number of the current row
6420   \iftbl@pgs
6421     \@chpgword
6422   \else
6423     \@chqword
6424   \fi
6425   \setcounter{cols@done}{0}%
6426   \do@pq@indexloop@h
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:
6435       \do@htword@h
6436     \else
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}}%
6441       \do@emptycols@h
6442     \fi
6443   \fi
6444   \\
6445   \hline
6446   % Point values go here!
6447   \@chpword
6448   \setcounter{cols@done}{0}%
6449   \do@ptloop@h
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:
6458       \do@totalpts@h
6459     \else
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}}%
6464       \do@emptycols@h
6465     \fi
6466   \fi
6467   \\
6468   \hline
6469   % Bonus point values go here!
6470   \@chbpword
6471   \setcounter{cols@done}{0}%
6472   \do@bptloop@h
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:
6481       \do@totalbpts@h
6482     \else
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}}%
6487       \do@emptycols@h
6488     \fi
6489   \fi
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
6492   % "\hline".
6493   % Scores?
6494   \if@scores
6495     \\
6496     \hline
6497     \@chsword \hidden@ampersand
6498     \setcounter{cols@done}{0}%
6499     \do@sloop@h
6500   \fi
6501   \ifnum \value{current@row} = \value{num@rows}\relax
6502     % This is the last line!  End the tabular:
6503     \\
6504     \hline
6505     \end{tabular}%
6506   \else
6507     % Don't end the tabular:
6508     \\
6509     \hline\hline
6510   \fi
6511   % Check if we should repeat:
6512   \ifnum \value{current@row} < \value{num@rows}\relax
6513     \let\nextdo@comblines@h=\do@comblines@h
6514   \else
6515     \let\nextdo@comblines@h=\relax
6516   \fi
6517   \nextdo@comblines@h
6518 }% do@comblines@h
6519
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
6525     % Do nothing!
6526   \else
6527     \hidden@ampersand
6528     \refto@index{pq@index}%
6529     \addtocounter{cols@done}{1}%
6530   \fi
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
6534     \else
6535       \let\nextdo@pq@indexloop@h=\relax
6536     \fi
6537   \else
6538     \let\nextdo@pq@indexloop@h=\relax
6539   \fi
6540   \nextdo@pq@indexloop@h
6541 }% do@pq@indexloop@h
6542
6543 \def\do@ptloop@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
6548     % Do nothing!
6549   \else
6550     \hidden@ampersand
6551     \addtocounter{cols@done}{1}%
6552     \pointsof@index{pq@index@pts}%
6553     \addto@hlfcntr{tbl@points}{\pointsof@index{pq@index@pts}}%
6554   \fi
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
6558     \else
6559       \let\nextdo@ptloop@h=\relax
6560     \fi
6561   \else
6562     \let\nextdo@ptloop@h=\relax
6563   \fi
6564   \nextdo@ptloop@h
6565 }% do@ptloop@h
6566
6567 \def\do@bptloop@h{%
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
6572     % Do nothing!
6573   \else
6574     \hidden@ampersand
6575     \addtocounter{cols@done}{1}%
6576     \bonuspointsof@index{pq@index@bpts}%
6577     \addto@hlfcntr{tbl@bonuspoints}{\bonuspointsof@index{pq@index@bpts}}%
6578   \fi
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
6582     \else
6583       \let\nextdo@bptloop@h=\relax
6584     \fi
6585   \else
6586     \let\nextdo@bptloop@h=\relax
6587   \fi
6588   \nextdo@bptloop@h
6589 }% do@bptloop@h
6590
6591 \def\do@htword@h{%
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}}%
6597   \do@emptycols@h
6598   \if@combined
6599     \@chtword
6600   \else
6601     \if@bonus
6602       \@bhtword
6603     \else
6604       \@htword
6605     \fi
6606   \fi
6607 }% do@htword@h
6608
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}}%
6615   \do@emptycols@h
6616   \prt@tablepoints
6617 }% do@totalpts@h
6618
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}}%
6625   \do@emptycols@h
6626   \prt@tablebonuspoints
6627 }% do@totalbpts@h
6628
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
6634     \hidden@ampersand
6635     \addtocounter{@iterator}{-1}%
6636     \let\nextdo@emptycols@h=\do@emptycols@h
6637   \else
6638     \let\nextdo@emptycols@h=\relax
6639   \fi
6640   \nextdo@emptycols@h
6641 }% do@emptycols@h
6642
6643 \def\do@sloop@h{%
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
6651     \hidden@ampersand
6652     \let\nextdo@sloop@h=\do@sloop@h
6653   \else
6654     \let\nextdo@sloop@h=\relax
6655   \fi
6656   \nextdo@sloop@h
6657 }% do@sloop@h
6658
6659
6660 %--------------------------------------------------------------------
6661 %--------------------------------------------------------------------
6662 % Multicolumn tables
6663
6664
6665 %--------------------------------------------------------------------
6666 % Here's an example of a multicolumn grade table indexed by questions.
6667
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
6671 % \cline.
6672
6673 % \begin{tabular}{*2{|c|c|c|c}}
6674 %   \cline{1-3} \cline{5-7}
6675 %   \noalign{\vskip\arrayrulewidth}
6676 %   Question%
6677 %   & Points%
6678 %   & Score%
6679 %   & \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
6680 %   & Question%
6681 %   & Points%
6682 %   & Score%
6683 %   \\
6684 %   \cline{1-3} \cline{5-7}
6685 %   \noalign{\vskip\arrayrulewidth}
6686 %   1%
6687 %   & 5%
6688 %   & \hbox to \@cellwidth{\hfill}%
6689 %   & \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
6690 %   & 4%
6691 %   & 20%
6692 %   & \hbox to \@cellwidth{\hfill}%
6693 %   \\
6694 %   \cline{1-3} \cline{5-7}
6695 %   \noalign{\vskip\arrayrulewidth}
6696 %   2%
6697 %   & 10%
6698 %   & \hbox to \@cellwidth{\hfill}%
6699 %   & \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
6700 %   & 5%
6701 %   & 25%
6702 %   & \hbox to \@cellwidth{\hfill}%
6703 %   \\
6704 %   \cline{1-3} \cline{5-7}
6705 %   \noalign{\vskip\arrayrulewidth}
6706 %   3%
6707 %   & 15%
6708 %   & \hbox to \@cellwidth{\hfill}%
6709 %   & \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
6710 %   & Total:%
6711 %   & 75%
6712 %   & \hbox to \@cellwidth{\hfill}%
6713 %   \\
6714 %   \cline{1-3} \cline{5-7}
6715 %   \noalign{\vskip\arrayrulewidth}
6716 % \end{tabular}
6717 %--------------------------------------------------------------------
6718 %--------------------------------------------------------------------
6719 % Check that the number of cols is OK, and compute the number of rows:
6720
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
6727     \ClassError{exam}{%
6728       The number of columns in a table must be positive.\MessageBreak
6729     }{%
6730       The number of columns must be a positive integer.\MessageBreak
6731     }%
6732     \fbox{\textbf{Error:} Multicolumn table with no columns!}%
6733   \else
6734     \ifnum \value{num@cols} > 10\relax
6735       \ClassError{exam}{%
6736         Multicolumn tables can have at most 10 columns.\MessageBreak
6737       }{%
6738         Multicolumn tables can have at most 10 columns.\MessageBreak
6739       }%
6740       \fbox{\textbf{Error:} Multicolumn table with more than 10 columns!}%
6741     \else
6742       \@computenumrows@v
6743     \fi
6744   \fi
6745 }% check@num@cols@v
6746
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:
6753   \iftbl@pgs
6754     \count@pgswpts{num@rows}%
6755     \addtocounter{num@rows}{1}%
6756   \else
6757     \setcounter{num@rows}{\last@pq@index}%
6758     \addtocounter{num@rows}{-\first@pq@index}%
6759     \addtocounter{num@rows}{2}%
6760   \fi
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}%
6775   \fi
6776   \@multicolumntable
6777 }% @computenumrows@v
6778
6779 %--------------------------------------------------------------------
6780 % Construct the actual table:
6781
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}%
6789   \if@combined
6790     \if@scores
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
6800       % below:
6801       \cline@stuff@v  
6802       \setcounter{@iterator}{0}%
6803       \docolumn@heads@comb@v
6804       \\
6805       \cline@stuff@v
6806     \else
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
6816       % below:
6817       \cline@stuff@v  
6818       \setcounter{@iterator}{0}%
6819       \docolumn@heads@comb@noscores@v
6820       \\
6821       \cline@stuff@v
6822     \fi
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}%
6826     \iftbl@pgs
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}%
6831     \fi
6832     \setcounter{current@row}{0}%
6833     \do@lines@v
6834   \else
6835     % It's not combined:
6836     \if@scores
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
6845       % below:
6846       \cline@stuff@v  
6847       \setcounter{@iterator}{0}%
6848       \docolumn@heads@v
6849       \\
6850       \cline@stuff@v
6851     \else
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
6860       % below:
6861       \cline@stuff@v  
6862       \setcounter{@iterator}{0}%
6863       \docolumn@heads@noscores@v
6864       \\
6865       \cline@stuff@v
6866     \fi
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}%
6870     \iftbl@pgs
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}%
6875     \fi
6876     \setcounter{current@row}{0}%
6877     \do@lines@v
6878   \fi
6879 }% @multicolumntable
6880
6881 %--------------------------------------------------------------------
6882 % \create@cline@stuff@v
6883
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
6886 % \if@scores.
6887
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.
6891
6892 % \clines@ii@whatever is for tables in which a  logical column consists
6893 % of two columns; it's used for pointtable and bonuspointtable.
6894
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}
6900   \cline{13-14}}
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}
6909   \cline{25-26}}
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}}
6913
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:
6917
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}
6923   \cline{17-19}}
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}
6932   \cline{33-35}}
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}}
6936
6937
6938 % \clines@iv@whatever is for tables in which a  logical column
6939 % consists of four columns; it's used for combinedgradetable.
6940
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}
6946   \cline{21-24}}
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}
6955   \cline{41-44}}
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}}
6959
6960 % The definition of \cline ends with \noalign{\vskip-\arrayrulewidth},
6961 % and so we want to throw in a \noalign{\vskip\arrayrulewidth} to
6962 % cancel that.
6963 \def\cline@correction{\noalign{\vskip\arrayrulewidth}}
6964
6965 \def\create@cline@stuff@v{%
6966   % Called by \@multicolumntable.
6967   \if@combined
6968     \if@scores
6969       \edef\cline@stuff@v{\expandafter\noexpand\csname
6970         clines@iv@\romannumeral \c@num@cols\endcsname
6971         \noexpand\cline@correction}%
6972     \else
6973       \edef\cline@stuff@v{\expandafter\noexpand\csname
6974         clines@iii@\romannumeral \c@num@cols\endcsname
6975         \noexpand\cline@correction}%
6976     \fi
6977   \else
6978     \if@scores
6979       \edef\cline@stuff@v{\expandafter\noexpand\csname
6980         clines@iii@\romannumeral \c@num@cols\endcsname
6981         \noexpand\cline@correction}%
6982     \else
6983       \edef\cline@stuff@v{\expandafter\noexpand\csname
6984         clines@ii@\romannumeral \c@num@cols\endcsname
6985         \noexpand\cline@correction}%
6986     \fi
6987   \fi
6988 }% create@cline@stuff@v
6989
6990 %--------------------------------------------------------------------
6991 % The various \docolumn@heads@something@v
6992
6993 \def\docolumn@heads@v{%
6994   % Called by \@multicolumntable.
6995   % multicolumngradetable or multicolumnbonusgradetable, possibly
6996   % partial.
6997     \iftbl@pgs
6998       \if@bonus
6999         \@bvpgword
7000       \else
7001         \@vpgword
7002       \fi
7003     \else
7004       \if@bonus
7005         \@bvqword
7006       \else
7007         \@vqword
7008       \fi
7009     \fi
7010   & \if@bonus
7011       \@bvpword
7012     \else
7013       \@vpword
7014     \fi
7015   & \if@bonus
7016       \@bvsword
7017     \else
7018       \@vsword
7019     \fi
7020   \addtocounter{@iterator}{1}%
7021   \ifnum \value{@iterator} < \value{num@cols}\relax
7022     \hidden@ampersand
7023     \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
7024     \hidden@ampersand
7025     \let\nextdocolumn@heads@v=\docolumn@heads@v
7026   \else
7027     \let\nextdocolumn@heads@v=\relax
7028   \fi
7029   \nextdocolumn@heads@v
7030 }% docolumn@heads@v
7031
7032 \def\docolumn@heads@noscores@v{%
7033   % Called by \@multicolumntable.
7034   % multicolumnpointtable or multicolumnbonuspointtable, possibly
7035   % partial.
7036     \iftbl@pgs
7037       \if@bonus
7038         \@bvpgword
7039       \else
7040         \@vpgword
7041       \fi
7042     \else
7043       \if@bonus
7044         \@bvqword
7045       \else
7046         \@vqword
7047       \fi
7048     \fi
7049     &
7050     \if@bonus
7051       \@bvpword
7052     \else
7053       \@vpword
7054     \fi
7055   \addtocounter{@iterator}{1}%
7056   \ifnum \value{@iterator} < \value{num@cols}\relax
7057     \hidden@ampersand
7058     \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
7059     \hidden@ampersand
7060     \let\nextdocolumn@heads@noscores@v=\docolumn@heads@noscores@v
7061   \else
7062     \let\nextdocolumn@heads@noscores@v=\relax
7063   \fi
7064   \nextdocolumn@heads@noscores@v
7065 }% docolumn@heads@noscores@v
7066
7067 \def\docolumn@heads@comb@v{%
7068   % Called by \@multicolumntable.
7069   % multicolumncombinedgradetable, possibly partial.
7070     \iftbl@pgs
7071       \@cvpgword
7072     \else
7073       \@cvqword
7074     \fi
7075   & \@cvpword
7076   & \@cvbpword
7077   &  \@cvsword
7078   \addtocounter{@iterator}{1}%
7079   \ifnum \value{@iterator} < \value{num@cols}\relax
7080     \hidden@ampersand
7081     \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
7082     \hidden@ampersand
7083     \let\nextdocolumn@heads@comb@v=\docolumn@heads@comb@v
7084   \else
7085     \let\nextdocolumn@heads@comb@v=\relax
7086   \fi
7087   \nextdocolumn@heads@comb@v
7088 }% docolumn@heads@comb@v
7089
7090 \def\docolumn@heads@comb@noscores@v{%
7091   % Called by \@multicolumntable.
7092   % multicolumncombinedpointtable, possibly partial.
7093     \iftbl@pgs
7094       \@cvpgword
7095     \else
7096       \@cvqword
7097     \fi
7098   & \@vpword
7099   & \@bvpword
7100   \addtocounter{@iterator}{1}%
7101   \ifnum \value{@iterator} < \value{num@cols}\relax
7102     \hidden@ampersand
7103     \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
7104     \hidden@ampersand
7105     \let\nextdocolumn@heads@comb@noscores@v=\docolumn@heads@comb@noscores@v
7106   \else
7107     \let\nextdocolumn@heads@comb@noscores@v=\relax
7108   \fi
7109   \nextdocolumn@heads@comb@noscores@v
7110 }% docolumn@heads@comb@noscores@v
7111
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.
7116
7117 \def\do@lines@v{%
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!!
7126   \if@combined
7127     \do@oneline@comb@v
7128   \else
7129     \do@oneline@v
7130   \fi
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
7138     \\
7139     \cline@stuff@v
7140     \end{tabular}%
7141     \let\nextdo@lines@v=\relax
7142   \else
7143     \\
7144     \cline@stuff@v
7145     \let\nextdo@lines@v=\do@lines@v
7146   \fi
7147   \nextdo@lines@v
7148 }% do@lines@v
7149
7150 \def\do@oneline@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
7156     % counter: 
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!
7163         % Print the total:
7164           \if@bonus
7165             \@bvtword
7166           \else
7167             \@vtword
7168           \fi
7169           \hidden@ampersand
7170         \if@scores
7171             \if@bonus
7172               \prt@tablebonuspoints
7173             \else
7174               \prt@tablepoints
7175             \fi
7176           \hidden@ampersand
7177             \hbox to \@cellwidth{\hfill}%
7178         \else
7179             \hspace*{\fill}%
7180             \if@bonus
7181               \prt@tablebonuspoints
7182             \else
7183               \prt@tablepoints
7184             \fi
7185         \fi
7186       \else
7187         % Not last column last row; insert empty space:
7188           \hbox to \@cellwidth{\hfill}%
7189         \if@scores
7190           \hidden@ampersand
7191             \hbox to \@cellwidth{\hfill}%
7192         \fi
7193         \hidden@ampersand
7194           \hbox to \@cellwidth{\hfill}%
7195       \fi
7196     \else
7197       % Not last column; insert empty space:
7198       \hbox to \@cellwidth{\hfill}%
7199       \if@scores
7200         \hidden@ampersand
7201           \hbox to \@cellwidth{\hfill}%
7202       \fi
7203       \hidden@ampersand
7204         \hbox to \@cellwidth{\hfill}%
7205     \fi
7206   \else
7207     % We need to do question (or page) number pq@index:
7208       \refto@index{pq@index}%
7209     \hidden@ampersand
7210       \if@scores
7211         \if@bonus
7212           \bonuspointsof@index{pq@index}%
7213           \addto@hlfcntr{tbl@bonuspoints}{\bonuspointsof@index{pq@index}}%
7214         \else
7215           \pointsof@index{pq@index}%
7216           \addto@hlfcntr{tbl@points}{\pointsof@index{pq@index}}%
7217         \fi
7218       \hidden@ampersand
7219         \hbox to \@cellwidth{\hfill}%
7220     \else
7221       \if@bonus
7222         \bonuspointsof@index{pq@index}%
7223         \addto@hlfcntr{tbl@bonuspoints}{\bonuspointsof@index{pq@index}}%
7224       \else
7225         \pointsof@index{pq@index}%
7226         \addto@hlfcntr{tbl@points}{\pointsof@index{pq@index}}%
7227       \fi
7228     \fi
7229   \fi
7230   \addtocounter{cols@done}{1}% Number of columns done
7231   \ifnum \value{cols@done} < \value{num@cols}\relax
7232     \hidden@ampersand
7233       \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
7234       \nextcolumn@index@v{pq@index}%
7235     \hidden@ampersand
7236       \let\nextdo@oneline@v=\do@oneline@v
7237   \else
7238     \let\nextdo@oneline@v=\relax
7239   \fi
7240   \nextdo@oneline@v
7241 }% do@oneline@v
7242
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
7249     % counter: 
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!
7256         % Print the total:
7257         \@cvtword
7258         \hidden@ampersand
7259           \prt@tablepoints
7260         \hidden@ampersand
7261         \if@scores
7262             \prt@tablebonuspoints
7263           \hidden@ampersand
7264             \hbox to \@cellwidth{\hfill}%
7265         \else
7266           \prt@tablebonuspoints
7267         \fi
7268       \else
7269         % Last column, but not last row; insert empty space:
7270           \hbox to \@cellwidth{\hfill}%
7271         \hidden@ampersand
7272           \hbox to \@cellwidth{\hfill}%
7273         \if@scores
7274           \hidden@ampersand
7275             \hbox to \@cellwidth{\hfill}%
7276         \fi
7277         \hidden@ampersand
7278           \hbox to \@cellwidth{\hfill}%
7279       \fi
7280     \else
7281       % Not last column; insert empty space:
7282         \hbox to \@cellwidth{\hfill}%
7283       \hidden@ampersand
7284         \hbox to \@cellwidth{\hfill}%
7285       \if@scores
7286         \hidden@ampersand
7287           \hbox to \@cellwidth{\hfill}%
7288       \fi
7289       \hidden@ampersand
7290         \hbox to \@cellwidth{\hfill}%
7291     \fi
7292   \else
7293     % We need to do question number pq@index:
7294       \refto@index{pq@index}%
7295     \hidden@ampersand
7296       \pointsof@index{pq@index}%
7297       \addto@hlfcntr{tbl@points}{\pointsof@index{pq@index}}%
7298     \hidden@ampersand
7299     \if@scores
7300         \bonuspointsof@index{pq@index}%
7301         \addto@hlfcntr{tbl@bonuspoints}{\bonuspointsof@index{pq@index}}%
7302       \hidden@ampersand
7303         \hbox to \@cellwidth{\hfill}%
7304     \else
7305       \bonuspointsof@index{pq@index}%
7306       \addto@hlfcntr{tbl@bonuspoints}{\bonuspointsof@index{pq@index}}%
7307     \fi
7308   \fi
7309   \addtocounter{cols@done}{1}% Number of columns done
7310   \ifnum \value{cols@done} < \value{num@cols}\relax
7311     \hidden@ampersand
7312     \hspace*{-\arrayrulewidth}\hspace*{\doublerulesep}%
7313     \nextcolumn@index@v{pq@index}%
7314     \hidden@ampersand
7315     \let\nextdo@oneline@comb@v=\do@oneline@comb@v
7316   \else
7317     \let\nextdo@oneline@comb@v=\relax
7318   \fi
7319   \nextdo@oneline@comb@v
7320 }% do@oneline@comb@v
7321
7322 %--------------------------------------------------------------------
7323 % \find@nextpagewithpoints and \find@nextcolumnpage@v:
7324
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
7329   % value.
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}%
7334   \if@combined
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.
7338   \else
7339     \if@bonus
7340       \set@hlfcntr{tmp@hlfcntr}{\bonuspointsonpage{\value{#1}}}%
7341     \else
7342       \set@hlfcntr{tmp@hlfcntr}{\pointsonpage{\value{#1}}}%
7343     \fi
7344   \fi
7345   \ifhlfcntr@pos{tmp@hlfcntr}%
7346     \let\nextfind@nextpagewithpoints=\relax
7347   \else
7348     \ifnum \value{#1} > \tbl@lastp\relax
7349       \let\nextfind@nextpagewithpoints=\relax
7350     \else
7351       \def\nextfind@nextpagewithpoints{\find@nextpagewithpoints{#1}}%
7352     \fi
7353   \fi
7354   \nextfind@nextpagewithpoints
7355 }% find@nextpagewithpoints
7356
7357 \def\find@nextcolumnpage@v#1{%
7358   % Called by \nextcolumn@index@v.
7359   % This is used for all multicolumn tables that are indexed by
7360   % pages.
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
7374   \else
7375     % The following test shouldn't be needed, in theory, because the
7376     % computation of num@cols should prevent trouble, but we're being
7377     % paranoid.
7378     \ifnum \value{#1} > \tbl@lastp\relax
7379       \let\nextdofind@nextcolumnpage@v=\relax
7380     \else
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}}%
7384     \fi
7385   \fi
7386   \nextdofind@nextcolumnpage@v
7387 }% dofind@nextcolumnpage@v
7388
7389 %--------------------------------------------------------------------
7390 % \pointsinrange and \bonuspointsinrange, and then
7391 % \firstqinrange, \lastqinrange, and \numqinrange.
7392
7393
7394 % We say either \@bonusfalse or \@bonustrue, and then we check it only
7395 % in \do@countloop:
7396 \def\pointsinrange#1{%
7397   \@bonusfalse
7398   \def\tbl@range{#1}%
7399   \@ifundefined{exam@numpoints}%
7400     {\mbox{\normalfont\bfseries ??}}%
7401     {\read@range}%
7402 }% pointsinrange
7403
7404 \def\bonuspointsinrange#1{%
7405   \@bonustrue
7406   \def\tbl@range{#1}%
7407   \@ifundefined{exam@numpoints}%
7408     {\mbox{\normalfont\bfseries ??}}%
7409     {\read@range}%
7410 }% bonuspointsinrange
7411
7412 \def\bad@range{%
7413   % Called by \read@range, \firstqinrange, \lastqinrange, and
7414   % \numqinrange.
7415   {\mbox{\normalfont\bfseries ??}}%
7416   \ClassWarning{exam}{%
7417     Grading range `\tbl@range' not defined.\MessageBreak
7418     \space\space Run LaTeX again.\MessageBreak
7419   }%
7420 }% bad@range
7421
7422 \def\read@range{%
7423   % Called by \pointsinrange and \bonuspointsinrange.
7424   \@ifundefined{range@\tbl@range @firstq}%
7425   {%
7426     \bad@range
7427   }%
7428   {%
7429     \@ifundefined{range@\tbl@range @lastq}%
7430     {%
7431       \bad@range
7432     }%
7433     {%
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.}%
7440         \ClassError{exam}{%
7441           In grading range `\tbl@range ',
7442           the last question\MessageBreak
7443           \space\space comes before the first question.\MessageBreak
7444         }{%
7445           \string\begingradingrange \space must precede
7446           \string\endgradingrange \space by at
7447           least one question.\MessageBreak
7448         }%
7449       \else
7450         \count@pointsinrange
7451       \fi
7452     }%
7453   }%
7454 }% read@range
7455
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
7463 \def\do@countloop{%
7464   % We check \if@bonus here when needed:
7465   \addtocounter{@iterator}{1}%
7466   \if@bonus
7467     \@ifundefined{bonuspointsofq@\romannumeral \c@@iterator}%
7468       {}%
7469       {\addto@hlfcntr{tbl@points}
7470          {\csname bonuspointsofq@\romannumeral \c@@iterator\endcsname}}%
7471   \else
7472     \@ifundefined{pointsofq@\romannumeral \c@@iterator}%
7473       {}%
7474       {\addto@hlfcntr{tbl@points}
7475          {\csname pointsofq@\romannumeral \c@@iterator\endcsname}}%
7476   \fi
7477   \ifnum \value{@iterator} < \tbl@lastq\relax
7478     \let\next@countloop=\do@countloop
7479   \else
7480     \let\next@countloop=\relax
7481   \fi
7482   \next@countloop
7483 }% do@countloop
7484
7485 %--------------------------------------------------------------------
7486 % \firstqinrange, \lastqinrange, and \numqinrange.
7487
7488 \newcommand{\firstqinrange}[1]{%
7489   \def\tbl@range{#1}%
7490   \@ifundefined{range@\tbl@range @firstq}%
7491   {\bad@range}%
7492   {\csname range@#1@firstq\endcsname}%
7493 }% firstqinrange
7494
7495 \newcommand{\lastqinrange}[1]{%
7496   \def\tbl@range{#1}%
7497   \@ifundefined{range@\tbl@range @lastq}%
7498   {\bad@range}%
7499   {\csname range@#1@lastq\endcsname}%
7500 }% lastqinrange
7501
7502 \newcommand{\numqinrange}[1]{%
7503   \def\tbl@range{#1}%
7504   \@ifundefined{range@#1@firstq}%
7505   {%
7506     \bad@range
7507   }%
7508   {%
7509     \@ifundefined{range@#1@lastq}%
7510     {%
7511       \bad@range
7512     }%
7513     {%
7514       \setcounter{@iterator}{\csname range@#1@lastq\endcsname}%
7515       \addtocounter{@iterator}{-\csname range@#1@firstq\endcsname}%
7516       \stepcounter{@iterator}%
7517       \arabic{@iterator}%
7518     }%
7519   }%
7520 }% numqinrange
7521
7522
7523 %--------------------------------------------------------------------
7524 %--------------------------------------------------------------------
7525 %
7526 %                     ***************************
7527 %                     ** SOLUTION ENVIRONMENTS **
7528 %                     ***************************
7529
7530
7531
7532 % If the documentclass options include ``answers'', then the command
7533 % \printanswerstrue is given at the beginning of the run.
7534
7535 % If the documentclass options include ``noanswers'', then the command
7536 % \printanswersfalse is given at the beginning of the run.
7537
7538 \def\printanswers{\printanswerstrue}
7539 \def\noprintanswers{\printanswersfalse}
7540
7541 % If the documentclass options include ``cancelspace'', then the
7542 % command \cancelspacetrue is given at the beginning of the run.
7543
7544 % If the documentclass options include ``nocancelspace'', then the
7545 % command \cancelspacefalse is given at the beginning of the run.
7546
7547 \def\cancelspace{\cancelspacetrue}
7548 \def\nocancelspace{\cancelspacefalse}
7549
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
7557 \@insolutionfalse
7558
7559 \newcommand\SolutionEmphasis[1]{%
7560   \def\Solution@Emphasis{#1}%
7561 }
7562 \SolutionEmphasis{}
7563
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]%
7569   {%
7570     \@insolutiontrue % cancelled by the end of the environment
7571     \@addpointsfalse % cancelled by the end of the environment
7572     \ifprintanswers
7573       \begingroup
7574       \Solution@Emphasis
7575       \begin{TheSolution}%
7576     \else
7577       \ifcancelspace
7578         % Do nothing
7579       \else
7580         \par
7581         \penalty 0
7582         \vspace*{#1}%
7583       \fi
7584       \setbox\z@\vbox\bgroup
7585     \fi
7586   }{%
7587     \ifprintanswers
7588       \end{TheSolution}%
7589       \endgroup
7590     \else
7591       \egroup
7592     \fi
7593   }%
7594
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]%
7602   {%
7603     \@insolutiontrue % cancelled by the end of the environment
7604     \@addpointsfalse % cancelled by the end of the environment
7605     \ifprintanswers
7606       \begingroup
7607       \Solution@Emphasis
7608       \begin{TheSolution}%
7609     \else
7610       \ifcancelspace
7611         % Do nothing
7612       \else
7613         \par
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
7625         % left over part.
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 >.
7629         \ifdim 0pt > #1
7630           % do nothing
7631         \else
7632           \makeemptybox{#1}%
7633         \fi
7634       \fi
7635       \setbox\z@\vbox\bgroup
7636     \fi
7637   }{%
7638     \ifprintanswers
7639       \end{TheSolution}%
7640       \endgroup
7641     \else
7642       \egroup
7643     \fi
7644   }%
7645   
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]%
7651   {%
7652     \@insolutiontrue % cancelled by the end of the environment
7653     \@addpointsfalse % cancelled by the end of the environment
7654     \ifprintanswers
7655       \begingroup
7656       \Solution@Emphasis
7657       \begin{TheSolution}%
7658     \else
7659       \ifcancelspace
7660         % Do nothing
7661       \else
7662         \par
7663         \penalty 0
7664         \fillwithlines{#1}%
7665       \fi
7666       \setbox\z@\vbox\bgroup
7667     \fi
7668   }{%
7669     \ifprintanswers
7670       \end{TheSolution}%
7671       \endgroup
7672     \else
7673       \egroup
7674     \fi
7675   }%
7676   
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]%
7682   {%
7683     \@insolutiontrue % cancelled by the end of the environment
7684     \@addpointsfalse % cancelled by the end of the environment
7685     \ifprintanswers
7686       \begingroup
7687       \Solution@Emphasis
7688       \begin{TheSolution}%
7689     \else
7690       \ifcancelspace
7691         % Do nothing
7692       \else
7693         \par
7694         \penalty 0
7695         \fillwithdottedlines{#1}%
7696       \fi
7697       \setbox\z@\vbox\bgroup
7698     \fi
7699   }{%
7700     \ifprintanswers
7701       \end{TheSolution}%
7702       \endgroup
7703     \else
7704       \egroup
7705     \fi
7706   }%
7707
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]%
7713   {%
7714     \@insolutiontrue % cancelled by the end of the environment
7715     \@addpointsfalse % cancelled by the end of the environment
7716     \ifprintanswers
7717       \begingroup
7718       \Solution@Emphasis
7719       \begin{TheSolution}%
7720     \else
7721       \ifcancelspace
7722         % Do nothing
7723       \else
7724         \par
7725         \penalty 0
7726         \fillwithgrid{#1}%
7727       \fi
7728       \setbox\z@\vbox\bgroup
7729     \fi
7730   }{%
7731     \ifprintanswers
7732       \end{TheSolution}%
7733       \endgroup
7734     \else
7735       \egroup
7736     \fi
7737   }%
7738
7739
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).
7748
7749 % Of course, the user can change TheSolution with a \renewenvironment
7750 % command.
7751 \newcommand{\solutiontitle}{\noindent\textbf{Solution:}\enspace}
7752 \newenvironment{TheSolution}%
7753   {%
7754     \vspace{\parskip}%
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:
7758     \leftskip=0pt
7759     \rightskip=0pt
7760     % If the user said \unframedsolutions, then both
7761     % \if@framedsolutions and \if@shadedsolutions are false:
7762     \if@framedsolutions
7763       % We'll use the default \exam@FrameCommand
7764     \else
7765       \if@shadedsolutions
7766         \def\exam@FrameCommand{\colorbox{SolutionColor}}%
7767       \else
7768         % It's \unframedsolutions:
7769         \def\exam@FrameCommand{}%
7770       \fi
7771     \fi
7772     \exam@MakeFramed{\advance\hsize-\exam@width}%
7773     \solutiontitle
7774     \ignorespaces
7775   }%
7776   {%
7777     \unskip
7778     \endexam@MakeFramed
7779   }%
7780
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.
7787
7788 \def\framedsolutions{\@framedsolutionstrue\@shadedsolutionsfalse}
7789 \def\shadedsolutions{%
7790   \@ifundefined{definecolor}
7791   {%
7792     \ClassError{exam}{%
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
7796       \MessageBreak
7797       }{%
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
7801       }%
7802   }%
7803   {%
7804     \definecolor{SolutionColor}{gray}{0.8}
7805     \@shadedsolutionstrue
7806     \@framedsolutionsfalse
7807   }%
7808 }
7809 \def\unframedsolutions{\@framedsolutionsfalse\@shadedsolutionsfalse}
7810
7811
7812 % The solutionbox environment is different from the other solution
7813 % environments (solution, solutionorbox, solutionorlines,
7814 % solutionordottedlines, and solutionorgrid), in that
7815 %
7816 %   (1) The box is always printed, whether answers are being printed
7817 %   or not.
7818 %
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
7822 %   \stretch{number}.
7823 %
7824 %   (3) We make no use of the TheSolution environment; the solutionbox
7825 %   environment is completely freestanding.
7826 %
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.
7830 %
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.
7835
7836 % 2016/02/08: The solutionbox frame can now be printed in color, as
7837 % long as you load color.sty in the preamble.
7838 %
7839 %  Usage: Say
7840 %
7841 % \usepackage{color}
7842 %
7843 % in the preamble, and then give the command
7844 %
7845 %   \colorsolutionboxes
7846 %
7847 % to have the frame around a solutionbox in color.  The default color
7848 % was created by the command
7849 %
7850 %     \definecolor{SolutionBoxColor}{gray}{0.8}
7851 %
7852 % and you can change the color by giving a new \definecolor command
7853 % (which must be done *after* the \colorsolutionboxes command).
7854 %
7855 % To cancel color solutionbox frames and return to black, give the
7856 % command
7857 %
7858 %   \nocolorsolutionboxes
7859
7860 \newif\if@colorsolutionboxes
7861 \@colorsolutionboxesfalse
7862 \def\colorsolutionboxes{%
7863   \@ifundefined{definecolor}
7864   {%
7865     \ClassError{exam}{%
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
7869       \MessageBreak
7870       }{%
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
7874       }%
7875   }%
7876   {%
7877     \definecolor{SolutionBoxColor}{gray}{0.8}
7878     \@colorsolutionboxestrue
7879   }%
7880 }
7881 \def\nocolorsolutionboxes{\@colorsolutionboxesfalse}
7882
7883 \newbox\exam@box
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
7890 % \textwidth:
7891 %  \@tempdima=\textwidth
7892   \@tempdima=\hsize
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:
7899   \begingroup 
7900     \Solution@Emphasis
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
7905       \hsize=\@tempdima
7906       \leftskip=0pt
7907       \rightskip=0pt
7908       \vskip 2\fboxsep
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
7913       \linewidth=\hsize
7914       \solutiontitle
7915       \ignorespaces
7916   }%
7917   {%
7918     \unskip
7919     \egroup
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:
7923     \ht\exam@box=0pt
7924     \dp\exam@box=0pt
7925     \par
7926     \vspace{\parskip}
7927     \ifprintanswers
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:
7934       \hbox to \hsize{%
7935         \noindent
7936         \hskip\@totalleftmargin
7937         \hskip3\fboxsep\hskip\fboxrule
7938         \box\exam@box\hfill
7939       }%
7940       \par\nointerlineskip
7941     \fi
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}
7947
7948
7949 %--------------------------------------------------------------------
7950 %--------------------------------------------------------------------
7951 % Added in version 2.502: 2016/03/23, \colorfbox
7952
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.
7958
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
7962
7963 %   \colorlet{saved@color}{.}
7964
7965 % but we wanted to make this work even if color.sty is being used.
7966
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}}%
7976 }% colorfbox
7977
7978 %--------------------------------------------------------------------
7979 %--------------------------------------------------------------------
7980
7981 % The following stuff is lifted from:
7982 %
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.
7987 %
7988 % The modifications I made are marked with ``psh'' in a comment:
7989 %
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.
7996
7997 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7998 % Create framed or shaded regions that can break across pages using 
7999 % \begin{examframed} ... \end{examframed}    -- ordinary frame box
8000 % (box at margin)
8001 % \begin{examshaded} ... \end{examshaded}    -- shaded background
8002 % (into margin)
8003 %    ... examleftbar ...                 -- line on left side
8004 % \begin{MakeFramed}{settings} ... \end{MakeFramed}
8005 %                        -- generic frame (for new environments)
8006 %
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.
8012 %
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}...).
8016 %
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
8020 %
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.
8026 %
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.
8031
8032 % Expert commands:
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
8036 % \@parboxrestore 
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
8040 % top of page
8041
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.
8045 %
8046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8047
8048 %psh: Commented out \ProvidesPackage:
8049 %\ProvidesPackage{framed}[2003/07/21 v 0.8a: 
8050 %   framed or shaded text with page breaks]
8051
8052 %psh: Created \saved@totalleftmargin and \@sollistdepth:
8053 \newdimen\saved@totalleftmargin
8054 \newcount\@sollistdepth
8055
8056 \newenvironment{examframed}% using default \exam@FrameCommand
8057   {\exam@MakeFramed {\advance\hsize-\exam@width \exam@FrameRestore}}%
8058   {\endexam@MakeFramed}
8059
8060 \newenvironment{examshaded}{%
8061   \def\exam@FrameCommand{\colorbox{shadecolor}}%
8062   \exam@MakeFramed {\exam@FrameRestore}}%
8063  {\endexam@MakeFramed}
8064
8065 \newenvironment{examleftbar}{%
8066   \def\exam@FrameCommand{\vrule width 3pt \hspace{10pt}}%
8067   \exam@MakeFramed {\advance\hsize-\exam@width \exam@FrameRestore}}%
8068  {\endexam@MakeFramed}
8069
8070 \chardef\exam@FrameRestore=\catcode`\| % for debug
8071 \catcode`\|=\catcode`\% % (debug: insert space after backslash)
8072
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}}}%
8077    \vskip\z@skip}%
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
8081  \begingroup
8082  \skip@\lastskip
8083  \if@nobreak\else 
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@
8089     \fi\fi\fi
8090     \penalty\z@
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
8095     % is 0.2301. 
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@
8101  \fi
8102  \addvspace{\topsep}%
8103  \endgroup
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. }%
8109  \exam@fb@adjheight 
8110 %psh: Added commands:
8111   \advance\hsize-\@totalleftmargin
8112   \saved@totalleftmargin=\@totalleftmargin
8113   \@totalleftmargin=0pt
8114   \parshape 0
8115   \let\@listdepth=\@sollistdepth
8116   \@sollistdepth=0
8117   \leftmargin=0pt
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:
8123    \linewidth=\hsize
8124 }
8125
8126 \def\endexam@MakeFramed{\par
8127      \kern\z@ \penalty-100 % put depth into height
8128  \egroup
8129  \begingroup \exam@put@frame \endgroup
8130 %psh: Added one line:
8131  \@totalleftmargin=\saved@totalleftmargin
8132 }
8133
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
8137 % have zero depth.)
8138
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. }%
8143  \ifinner \else
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
8167            \unvbox\@tempboxa}%
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
8176         \begingroup
8177           \advance\dimen@\topskip
8178           \expandafter\endgroup
8179         \ifdim\dimen@>\pagegoal
8180 |         \message{Frame is big -- Use up the full column. }%
8181           \dimen@ii\pagegoal
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@. }%
8189             \dimen@ii\dimen@
8190           \else % use natural size
8191             \dimen@ii\ht\tw@
8192           \fi
8193         \fi
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
8203                                              % was discarded)  
8204            \exam@fb@adjheight
8205         \else %
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@. }%
8212               \ifdim\wd\tw@>\z@
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@}}%
8217               \else
8218 |               \message{Zero width means likely blank. Don't frame it (guess)}%
8219                 \box\tw@
8220               \fi
8221               \hrule \@height\z@
8222               \eject
8223               \exam@fb@adjheight
8224               \exam@put@frame
8225   \fi\fi\fi\fi\fi
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
8233   \fi}
8234
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
8240
8241 \edef\exam@zero@glue{\the\z@skip}
8242
8243 \catcode`\|=\exam@FrameRestore
8244
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}}%
8254   \else
8255     \def\box@it{\fbox}%
8256   \fi
8257   \box@it
8258 }% \exam@FrameCommand
8259
8260 \@ifundefined{FrameRule}{\newdimen\exam@FrameRule \exam@FrameRule=\fboxrule}{}
8261 \@ifundefined{FrameSep} {\newdimen\exam@FrameSep  \exam@FrameSep =3\fboxsep}{}
8262
8263 % Height of frame above first baseline when frame starts a page:
8264 \providecommand\exam@frameHeightAdjust{6pt}
8265
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
8273 %  \let\par\@@par  ??
8274   \let\-\@dischyph
8275   \let\'\@acci\let\`\@accii\let\=\@acciii
8276 %  \parindent\z@ \parskip\z@skip    Definitely omit!
8277 %  \everypar{}%  ??
8278   \linewidth\hsize
8279 %  \@totalleftmargin\z@
8280 %  \leftskip\z@skip \rightskip\z@skip \@rightskip\z@skip
8281 %  \parfillskip\@flushglue \lineskip\normallineskip
8282 %  \baselineskip\normalbaselineskip
8283   \sloppy
8284 %  \let\\\@normalcr
8285 }
8286
8287 %  Compatibility with previous versions (temporary!):
8288 % psh: we'll remove this 2017-09-21
8289 %\let\fram@d=\MakeFramed  \let\endfram@d=\endMakeFramed
8290
8291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
8292
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
8296
8297
8298 %--------------------------------------------------------------------
8299 %--------------------------------------------------------------------
8300
8301 \endinput
8302 %---------------------------------------------------------------------
8303 %---------------------------------------------------------------------
8304 %---------------------------------------------------------------------
8305 %---------------------------------------------------------------------
8306 %---------------------------------------------------------------------