\ifx\QUIRE\relax\endinput\else\let\QUIRE=\relax\fi % \input only once % % quire.tex: Macros for making booklets, printing double pages, and % printing outlines and crop marks. % version: 1.0 release: 19 January 1991 % % copyright (c) 1991 Marcel R. van der Goot % You can use these macros to typeset documents. You may % distribute this file freely, provided that you also distribute % the accompanying documentation. % You may make changes to this file, or extract portions % of it for inclusion in other files, provided that % (1) you change the name of the file; % (2) you give proper credit and include copyright % information where applicable; % (3) explain how an unchanged version can be obtained; and % (4) document the usage of your macros/changes (if usage % of your macros is not worth documenting, they must not % be worth using). % You are not allowed to use the name ``Midnight Macros'' for % any changed files. % The above rules for making changes do not apply where it % is explicitly noted in this file that something can be changed % to conform to your local installation. % % USAGE: % See the file quire.doc % % original: csvax.cs.caltech.edu [131.215.131.131] in pub/tex % (use anonymous ftp). Also in various archives. % % Caltech, Pasadena --- Marcel van der Goot % marcel@cs.caltech.edu % Caltech 256--80 % Pasadena, CA 91125 % USA % (818) 356--4603 % % update history: % version 1.0: This one. % release 19 Jan 1991: This one. % %%%%%% CODE: (you don't need to read this to use the macros) %%%%%%%%%%%%%%% registers accessible by the user % dimens related to pages: \newdimen\vorigin \newdimen\horigin \newdimen\vtotal \newdimen\htotal % also used: dimens \voffset, \hoffset % dimens related to sheets \newdimen\shoutline \newdimen\shstaplewidth \newdimen\shstaplelength \newdimen\shcrop \newdimen\shvoffset \newdimen\shhtotal \newdimen\shthickness \newdimen\shvcorrection \newdimen\shhcorrection % token register related to sheets \newtoks\shfootline %%%%%%%%%%%%%%% the implementation % Private identifiers are prefixed with `q_'; in the comments below, % this prefix is omitted for readability. \shoutline=\catcode`_ sp % minor trick to remember the original catcode \catcode`_=11 % letter %%%%% The stack % A stack of boxes is needed to store pages that cannot be printed yet. % The stack is formed by \stackbox, an hbox storing the stacked boxes, % and \stacktop, the top box on the stack. The stack top can be accessed % by \copy\stacktop or \box\stacktop, but the latter should only be % used if the next stack operation is \pop. There is no stackcounter % implemented, because we don't need it here. \newbox\q_stackbox % an hbox keeping the stacked boxes but one \newbox\q_stacktop % the topmost box \def\q_push#1% #1 = a box {\global\setbox\q_stackbox= \hbox{\unhbox\q_stackbox \box\q_stacktop}% \global\setbox\q_stacktop=#1% } \def\q_pop {\global\setbox\q_stackbox= \hbox{\unhbox\q_stackbox \global\setbox\q_stacktop=\lastbox}% } %%%%% Handling pages % \makepage takes a box representing the printed material (this box is the % argument of \shipout), and makes it into a page. A page is represented % by an hbox with height \vtotal, width \htotal, and depth 0. \def\q_makepage#1% #1 = textpage, return = an hbox (\vtotal+0)*\htotal {\hbox to\htotal {\boxmaxdepth=0pt \advance\vorigin by\voffset \advance\horigin by\hoffset \kern\horigin \vbox to\vtotal {\kern\vorigin #1% \vss }% \hss }% } % \doublepage takes two pages produced by \makepage, and puts them next % to each other in a vbox. Between the two pages there is two times the % space specified by \thickoffset. \doublepage draws lines around the % produced vbox, and draws `staples' in the center. \newdimen\q_thickoffset \def\q_doublepage#1#2% #1 and #2 are page boxes, % return = vbox ((\vtotal+2\shoutline)+0)* % (2(\htotal+\thickoffset+\shoutline)) {\vbox{\vbox to0pt{\vss\q_vcrop\kern3mm}% \hrule height\shoutline depth0pt \hbox{\hbox to0pt{\hss\q_hcrop\kern3mm}% \vrule width\shoutline #1% \kern\q_thickoffset \q_fold \kern\q_thickoffset #2% \vrule width\shoutline \hbox to0pt{\kern3mm\q_hcrop\hss}% }% \hrule height\shoutline depth0pt \vbox to0pt{\kern3mm\q_vcrop\vss}% }% } % \fold returns an hbox containing the two `staples'. The hbox has % width 0 so that it does not interfere with the separation between % double pages. \def\q_fold % return = an hbox (\vtotal+0)*0 {\hbox to0pt {\divide\vtotal by 4 \advance\vtotal by-0.5\shstaplelength \hss \vbox{\kern\vtotal \hrule width\shstaplewidth height\shstaplelength depth0pt \kern 2\vtotal \hrule width\shstaplewidth height\shstaplelength depth0pt \kern\vtotal }% \hss }% } % \vcrop returns an hbox containing the three vertical crop marks, % \hcrop a vbox with the two horizontal marks. \def\q_vcrop % return = an hbox (15mm+0)*(2(\htotal+\thickoffset+\shoutline)) {\hbox{\kern\shoutline \hbox to0pt{\vrule height15mm depth0pt width\shcrop\hss}% \kern\htotal \kern\q_thickoffset \hbox to0pt{\hss\vrule height15mm depth0pt width\shcrop\hss}% \kern\q_thickoffset \kern\htotal \hbox to0pt{\hss\vrule height15mm depth0pt width\shcrop}% \kern\shoutline }% } \def\q_hcrop % return = a vbox (vtotal+0)*15mm {\vbox{\vbox to0pt{\hrule width15mm height\shcrop depth0pt\vss}% \nointerlineskip \kern\vtotal \vbox to0pt{\vss\hrule width15mm height\shcrop depth0pt}% }% } %%%%% Shipout routines % Suppose Q is the number of pages per quire (rounded upwards to the % nearest multiple of 4), then there are Q/2 sheets per quire. The first % Q/2 pages have to be stacked, which is done by the shipout routine % \collect. The next Q/2 pages have to be combined with the stacked ones % into double pages, which are then printed. This is done by the shipout % routine \combine. \goal is the number Q/2, \sheetnr is used to count the % sheets of the current quire, \qnr counts sheets in completed quires % (\count0 is set to the actual sheet number when a sheet is shipped out). % The current shipout routine is held in \ship, \shipbox is the box % that must be shipped out. \oldship is the original \shipout. % In order to print partial quires if there is not enough memory to % store Q/2 pages, the user can specify a range of sheets that should % be printed. This range is tested with \ifrange; sheets that fall % outside the range are counted, but otherwise ignored. % % Normally, \shipout resets \deadcycles to 0 and a call of the output % routine (by TeX's page-breaking mechanism) increments it. We do not % want to reset \deadcycles until enough pages for a quire have been % collected, because as long as \deadcycles is not 0, TeX will produce % more pages. We cannot allow it to be continuously incremented either, % since TeX gives an error message if it becomes too high. Therefore, % we set it to 1 if we need more pages. (Actually, the algorithm below % always requires a full quire, even if only a partial one is printed.) % % In \shfootline we want to be able to print the page number of the % actual pages. To save the page number, we use a ``dirty trick'' % (the only one in these macros, as far as I can tell): we push a box % with the pagenumber as width on the stack. We recover the pagenumber by % using that width as a count, which replaces the dimen (\wd) by its % value in sp. The pagenumbers are also shipped out as \count1 and 2. \newcount\q_sheetnr \newcount\q_qnr \newif\ifq_range \newbox\q_shipbox \def\q_collect {\message{[(\the\count0)]}% \global\advance\q_sheetnr by1 \q_checkrange \ifq_range \q_push{\q_makepage{\box\q_shipbox}}% \q_push{\hbox to\count0 sp{}}% dirty trick \fi \global\deadcycles=1 \ifnum\q_sheetnr=\q_goal \global\q_thickoffset=0pt \global\let\q_ship=\q_combine \fi } \def\q_combine {{\ifq_range \count1=\wd\q_stacktop \q_pop % \firstpageno \count2=\count0 % \secondpageno \ifodd\q_sheetnr % stacktop is an odd page \q_print{\q_makepage{\box\q_shipbox}}{\box\q_stacktop}% \else\q_print{\box\q_stacktop}{\q_makepage{\box\q_shipbox}}% \fi \q_pop \else\message{[(\the\count0)]}% \fi \ifodd\q_sheetnr\global\advance\q_thickoffset by\shthickness\fi \global\advance\q_sheetnr by-1 \q_checkrange \ifnum\q_sheetnr=0 \global\advance\q_qnr by\q_goal \global\let\q_ship=\q_collect \global\deadcycles=\q_cycles \else\global\deadcycles=1 \fi }} \def\q_print#1#2% two page boxes {{\count0=\q_qnr \advance\count0 by\q_sheetnr \setbox0=\hbox to\shhtotal {\hss \boxmaxdepth=0pt \vbox{\offinterlineskip \q_doublepage{#1}{#2}% \kern1pc \hbox{\kern\q_thickoffset \hbox to 2\htotal{\the\shfootline}% }% }% \hss }% \hoffset=-1truein % defeat the annoying 1 inch offset \voffset=\shvoffset \ifodd\count0 \advance\hoffset by\shhcorrection \advance\voffset by\shvcorrection \fi \q_oldship\box0 \xdef\q_cycles{\the\deadcycles}% }} %%%%% shipout % This is perhaps the most obscure part, although it actually has little % to do with the problem at hand. % What I would have liked to do is define the above \collect and \combine % as taking a parameter #1 and then use #1 instead of \shipbox. Then % we could just say \let\shipout=\collect etc. Unfortunately, that doesn't % work: The actual \shipout is not a macro but a built-in command that % must be followed by a . As a result, \shipout\box0 works % fine, but \shipout{\box0} generates an error (because the first `{' is % not the start of a ). On the other hand, \collect\box0 would make % #1 -> \box instead of \box0, and therefore wouldn't work; only % \collect{\box0} would work. It really seemed highly preferrable to make % the shipout replacements work in the same way as the original. Therefore, % \boat will read a box and put it in \shipbox, and then call \ship. % This has the additional advantage that the box is actually constructed % before the shipout replacement does anything (if you do % \collect{\hbox {...}} the box is only constructed when #1 is used). % The routine \boat must be followed by a because of the \setbox. % Again, I would have liked to do % \def\boat{\afterassignment\ship\setbox\shipbox=} % but \afterassignment behaves different for a of the form % \hbox {...} than for one of the form \box0. \tstship tests whether % the assignment has actually taken place, or whether we are at the % beginning of an \hbox { ...} etc. This way of testing % is not perfect, it doesn't work if you try to ship out a void box. However, % that is a strange thing to do, and this is by far the easiest solution % I could come up with. \def\q_boat {{\setbox255=\box\q_shipbox}% makes \shipbox void \afterassignment\q_tstship \global\setbox\q_shipbox= % \boat must be followed by a } \def\q_tstship {\ifvoid\q_shipbox\aftergroup\q_ship \else\q_ship \fi } %%%%% Public routines for making quires % The routine that sets up printing quires is \makequire. It takes 3 % arguments, the number of pages per quire (Q before rounding), the % number of the first sheet in the printing range, and the extend % (in sheet numbers) of the printing range. It uses these numbers to % define \checkrange, used by the output routines. % If there is sufficient memory to print a full quire, then \quire % can be used instead of \makequire. \quire only takes the number of % pages. \def\q_init {\global\q_sheetnr=0\global\q_qnr=0 \global\let\q_oldship=\shipout \global\let\shipout=\q_boat \xdef\q_cycles{\the\deadcycles}% \global\let\endquire=\q_endquire } \def\makequire#1#2#3% #1 = nr of pages, #2 = first sheet, #3 = size of range {{\count0=#1% \advance\count0 by3 \divide\count0 by4 \multiply\count0 by2 \xdef\q_goal{\the\count0}% \count0=#2% \count1=#3\advance\count1 by\count0 \advance\count1 by-1 \let\nox=\noexpand \xdef\q_checkrange {\nox\ifnum \q_sheetnr < \the\count0 \nox\global\nox\q_rangefalse \nox\else\nox\ifnum \the\count1 < \q_sheetnr \nox\global\nox\q_rangefalse \nox\else \nox\global\nox\q_rangetrue \nox\q_parity \nox\fi\nox\fi }% \q_init \global\let\q_ship=\q_collect }} \def\quire#1% #1 = nr of pages {\makequire{#1}{0}{1000}% } % \endquire can be used to finish the quire before the end of the % input is reached. It ships out the current page, then ships out empty % boxes until the quire is finished. \let\endquire=\relax % if \endquire is used when \quire is not \def\q_endquire {{\vfill\supereject \loop \ifnum\q_sheetnr>0 \shipout\vbox{}% \repeat \global\let\shipout=\q_oldship }} % Normally both even and odd sheets are printed. However, one can surpress % one class by using \shonly#1. If #1 = 0, both are printed. Otherwise % only sheets with the same parity as #1 are printed. \def\shonly#1% a number {\ifnum #1=0 \gdef\q_parity{}% \else\ifodd#1% \gdef\q_parity{\ifodd\q_sheetnr\else\global\q_rangefalse\fi}% \else\gdef\q_parity{\ifodd\q_sheetnr\global\q_rangefalse\fi}% \fi\fi } % In LaTeX, \end is redefined to set \deadcycles to 0 before it does the % actual \end. This means that the quire is not actually finished if the % text doesn't have enough pages (see the earlier discussion about % \deadcycles). You cannot solve this by using \endquire, because then % not all output is actually finished (also because of various LaTeX % definitions). Therefore, in \latexquire, we redefine \@@end, which is % what LaTeX thinks is the original \end, to do an \endquire just before % the actual \end. { \catcode`@=11 \gdef\latexquire {\global\let\q_end=\@@end \gdef\@@end{\endquire\q_end}% } } %%%%% Some extras % Quires are not so easy to preview. Therefore we also define % \qtwopages for printing double pages (without reordening them) and % \qonepage for printing single pages (with outlines etc.). Most of % the needed routines were already there anyway. % \two is the shipout routine used for \qtwopages. It uses \qnr to % count pages, \sheetnr to distinguish between the first and the second % page of a pair. (We count with \qnr because \endquire wants \sheetnr % to be 0 at the end. But note that \parity looks at \sheetnr to determine % whether the page must be printed. \def\q_two {{\ifodd\q_sheetnr % second page \global\q_sheetnr=0 \ifq_range \count1=\wd\q_stacktop \q_pop % \firstpageno \count2=\count0 % \secondpageno \q_print{\box\q_stacktop}{\q_makepage{\box\q_shipbox}}% \q_pop \else\message{[(\the\count0)]}% \fi \global\deadcycles=\q_cycles \else % first page \message{[(\the\count0)]}% \global\advance\q_qnr by1 \global\q_sheetnr=\q_qnr \global\q_rangetrue \q_parity \ifq_range \q_push{\q_makepage{\box\q_shipbox}}% \q_push{\hbox to\count0 sp{}}% that same dirty trick again \fi \global\deadcycles=1 \global\q_sheetnr=1 \fi }} \def\qtwopages {\q_init \global\let\q_ship=\q_two \global\q_thickoffset=0pt } % \one is the output routine for \qonepage. \qnr is used to count % the pages (again because of \endquire). \def\q_one {{\global\advance\q_qnr by1 \global\q_sheetnr=\q_qnr \global\q_rangetrue \q_parity \global\q_sheetnr=0 \ifq_range \count1=\count0 \count2=0 \divide\htotal by2 \q_print{\q_makepage{\box\q_shipbox}}{\q_makepage{}}% \else\message{[(\the\count0)]}% \fi \global\deadcycles=\q_cycles }} \def\qonepage {\q_init \global\let\q_ship=\q_one \global\q_thickoffset=0pt \global\let\q_fold=\relax } % restore \catcode`_ to whatever it was \catcode`_=\shoutline \countdef\firstpageno=1 \countdef\secondpageno=2 \shonly0 % to make sure that \parity is defined %%%%% Initial values for user parameters \shfootline={\tenrm\qquad\jobname\qquad\number\count0{} (\number\count1, \number\count2)\hfil} \shhtotal=22in \shthickness=.2mm \shvcorrection=0pt \shhcorrection=0pt \shvoffset=0pt \shoutline=1.5pt \shstaplewidth=1.5pt \shstaplelength=2cm \shcrop=3pt \vorigin=1in \horigin=1in \htotal=8.5in \vtotal=11in %%%%% Local definitions % The above is the standard file quire.tex. % CHANGE: What follows are local definitions; you should replace them with % appropriate values for your own installation. \def\Pmaser {\shhtotal=220.02true mm \shthickness=0.21true mm \message{maser: flip paper so that short sides remain in place, % align closest right-hand corner in tray.}% } \def\Pmaserlandscape {\shhtotal=281true mm \shthickness=0.21true mm \message{maser landscape: flip paper so that long sides remain in place, % align closest right-hand corner in tray.}% } \def\Phaser {\shhtotal=216.4truemm \shthickness=0.21truemm \message{haser: rotate (but do not flip) pages 180 degrees, and reorder.} } \def\Phaserlandscape {\shhtotal=283truemm \shthickness=0.21truemm \message{haser landscape: do not flip or rotate pages, but reorder them.} }