% Copyright 2004-2024, Alexander Shibakov
% This file is part of SPLinT
%
% SPLinT is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% SPLinT is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with SPLinT. If not, see .
% multicolumn output:
% the general layout of the page is similar to the following, where
% the number of columns and the location and the number of `footnote'
% columns can be adjusted.
%%%%%%%%%%% %%%%%%%%%%% %%%%%%%%%%%
%%column1%% %%column2%% %%column3%%
%%%%%%%%%%% ----------- %%%%%%%%%%%
%%%%%%%%%%% %footnotes% %%%%%%%%%%%
\newskip\realfootins
\newskip\footglue
\newskip\adjskip % skip to improve \vboxes
\newcount\linecount
\newcount\noofcolumns
\newcount\fnotesstart
\newcount\fnotesspan
\newdimen\columnwidth
\newdimen\icgap
\newdimen\pagewidth
\newdimen\pageheight
\newdimen\longvsize % the height of all the columns combined
\newdimen\fnoteboxwidth
\newdimen\footvboxht % holds the previous value of the height of the
% box of footnotes
\newbox\partialpage
\newbox\currentcolumn
\newbox\foothbox % holds the footnotes `in one line'
\newbox\foothhbox % holds every footnote in a separate \hbox
\newbox\migrantbox
{\setbox\migrantbox=\box\migrantbox}
\newcount\remaindergaps % the number of gaps between columns after the
% first `footnote column'
\newcount\remaindernonfoots % the number of columns without footnotes
% after the columns with footnotes
\newif\ifoutputnow
\newif\iflastpageup
\maxdeadcycles=600 % this should be approximately half the \pageheight in points
% to handle the case when \enddoublecols is called before the
% last doublecolumn page is full
% setup the page length and the column count
\linecount=53 % number of lines in a page
\fnotesstart=1 % start footnotes under the first column
\fnotesspan=2 % footnotes span two columns
\noofcolumns=2
\realfootins=12pt plus 1pt minus 1pt
\footglue=1em plus.2em minus.1em
\adjskip=0pt plus 6pt
%\topskip=9pt
%\normalbottom % one of these must accompany the use of the macros below
% so that the columns are aligned
%
\def\setmcparams{%
\columnwidth=\hsize
\advance\columnwidth-\noofcolumns\icgap
\advance\columnwidth\icgap
\divide\columnwidth by\noofcolumns
% \advance\linecount\m@ne
% \vsize=\baselineskip
% \multiply\vsize by \linecount
% \advance\vsize by \topskip
% \advance\linecount\@ne
%
\longvsize=\vsize
\advance\longvsize by-\topskip
\advance\longvsize by\baselineskip
\divide\longvsize\baselineskip
\multiply\longvsize\baselineskip
\count\@cclv\noofcolumns
\multiply\longvsize by \count\@cclv
\advance\longvsize-\baselineskip
\advance\longvsize\topskip
}
\setmcparams
\skip\footins=\realfootins
\count\footins=\@m % 1000
\pagewidth=\hsize
\pageheight=\vsize
% some debugging tools (rather primitive)
\def\onpage#1#2{%
{%
\yystringempty{#1}{#2}%
{%
\ifnum#1=\pageno\relax
\showboxbreadth=1000
\showboxdepth=1000
#2%
\fi
}%
}%
}
\def\onpageg#1#2{% make global assignments possible
\yystringempty{#1}{#2}%
{%
\ifnum#1=\pageno\relax
\showboxbreadth=1000
\showboxdepth=1000
#2%
\fi
}%
}
\ifx\testpageno\UNDEFINED
\def\testpageno{-\@M}
\fi
\def\footnote#1{%
\edef\@sf{\spacefactor\the\spacefactor}\setfnmark
\@sf
\insert\footins{\floatingpenalty\@MM % 20000
\setbox\z@=\hbox{\fnfsize\strut\fnmark\localfn\nobreak
\enskip{#1}\penalty-10\hskip\footglue}%
\setfootnoteheight
\box\z@
}%
}
\def\setfnoteparams{%
\fnfsize
% \emergencystretch=10pt
\hbadness\@M % 10000
\hyphenpenalty\z@ \doublehyphendemerits\z@
\exhyphenpenalty\z@ \finalhyphendemerits\z@
\righthyphenmin\z@ \lefthyphenmin=\tw@
\leftskip\z@\rightskip\z@
\adjdemerits\z@ \uchyph=\@ne \pretolerance=-1
}
\let\fnfsize\eightpoint
\def\setfootnoteheight{
\global\setbox\foothbox=\hbox{\unhbox\foothbox\unhcopy\z@}%
\setbox\@ne=\vbox{
\hsize=\fnoteboxwidth
\setfnoteparams
\noindent\unhcopy\foothbox
\par
}%
\dimen\z@=\ht\@ne \advance\dimen\z@ by -\footvboxht
\global\footvboxht=\ht\@ne
\ht\z@=\dimen\z@ \dp\z@=\z@
\global\setbox\foothhbox=\hbox{\copy\z@\unhbox\foothhbox}}
\def\makefootnoteparagraph{
\count\@cclv=\z@
\unvbox\footins
\makehboxofhboxes
\cleanupfootbuffer\readjustfoots
\setbox\z@=\hbox{\unhbox\z@ \removehboxes}
\setfnoteparams
\noindent\unhbox\z@\par
}
\def\makehboxofhboxes{%
\setbox\z@=\hbox{}%
\loop
\setbox\tw@=\lastbox
\ifhbox\tw@
\advance\count\@cclv\@ne
\setbox\z@=\hbox{\box\tw@\unhbox\z@}%
\repeat
}
% the macro below admittedly stretches \TeX's stack capacity but it is rather efficient
% at removing the \hbox packaging in the correct order.
\def\removehboxes{\setbox\z@=\lastbox
\ifhbox\z@{\removehboxes}\unhbox\z@ \fi}
\def\cleanupfootbuffer{% remove the footnotes that made it to the page
% form the buffer
\global\setbox\foothhbox=\hbox{\unhbox\foothhbox\cleanupf@otbuffer}}
\def\cleanupf@otbuffer{%
\ifnum\count\@cclv>\z@
\setbox\z@=\lastbox
\advance\count\@cclv\m@ne
\let\next=\cleanupf@otbuffer
\else
\let\next=\relax
\fi
\next}
\def\readjustfoots{%
\setbox\@ne=\copy\foothhbox % keep the footnotes that did not make it
% in the buffer
\setbox3=\vbox{}%
\global\setbox\foothbox=\hbox{}%
\setbox\@ne=\hbox{\unhbox\@ne\readjustf@ots}%
}
\def\readjustf@ots{%
\setbox\tw@=\lastbox
\ifvoid\tw@
\let\next=\readjustf@@ts
\else
\global\setbox\foothbox=\hbox{\unhbox\foothbox\unhcopy\tw@}%
\setbox3=\vbox{\box2\unvbox3}%
\let\next=\readjustf@ots
\fi
\next
}
\def\readjustf@@ts{%
\setbox\tw@=\vbox{
\hsize=\fnoteboxwidth
\setfnoteparams
\noindent\unhcopy\foothbox\par
}
\global\footvboxht=\ht\tw@
\dimen\z@=\ht\tw@ \advance\dimen\tw@ by -\ht3
\ifnum\dimen\z@=\z@
\else
\global\setbox\footins=\vbox{}%
\advance\dimen\z@ by \m@ne sp
\ht\footins=\dimen\z@ \dp\footins=\@ne sp % to indicate that this is an
% adjustment box for inner (i.e. the ones inserted by \footblock rathar than
% as part of the main output routine) footnotes (looked at by the output routine);
% if the height of the already contributed footnotes needs to be
% adjusted, adjust the height of the \box\footins by that amount
\fi
}
\fnoteboxwidth=\pagewidth % footnotes will spread across the whole page
\newskip\dsskip
\dsskip\smallskipamount
\def\begindoublecols{%
\begingroup
%\normalbottom
\r@ggedbottomfalse % \normalbottom changes \topskip which we do not want
\parindent=0pt
\count\footins=\@m \multiply\count\footins by\fnotesspan
\skip\footins=\fnotesspan\realfootins
\remaindergaps=\noofcolumns
\advance\remaindergaps by -\fnotesstart
\remaindernonfoots=\remaindergaps
\advance\remaindernonfoots by -\fnotesspan
\advance\remaindernonfoots\@ne
\ifnum\noofcolumns>\@ne % typesetting in one column is an exception,
% otherwise ...
% first, calculate the intercolumn skip ...
\dimen\z@=\pagewidth \dimen\@ne=\columnwidth
\multiply\dimen\@ne by\noofcolumns \advance\dimen\z@ by-\dimen\@ne
\count\@cclv=\noofcolumns \advance\count\@cclv\m@ne
\divide\dimen\z@ by\count\@cclv
\count\@cclv=\fnotesspan
\advance\count\@cclv\m@ne
\dimen\@ne=\columnwidth
\multiply\dimen\@ne by\fnotesspan
\advance\dimen\@ne by \count\@cclv\dimen\z@
% ... to get the width of the footnote box
\fnoteboxwidth=\dimen\@ne
\fi
% this final modification is needed due to the fact that the whole
% page is put in \hbox to\hsize{...; without the modification the
% width of the footnote box is not going to match the width of the
% page, and when the footnotes span all the columns there will be no
% `\hfill' to compensate for arithmetic imprecision
\ifnum\fnotesspan=\noofcolumns
\fnoteboxwidth=\pagewidth
\fi
%
\output={
\settopmark % save the \topmark if this is the top of the page
\ifvoid\partialpage
\else % this is a border case: too much material has been contributed, this routine will be called twice
% so output the full page now
\normaloutput{\unvbox\partialpage}\lheader\rheader
\fi
\global\setbox\partialpage=\vbox{\unvbox\@cclv\vskip\dsskip}%
\dimen\z@=\longvsize
\advance\dimen\z@ by -\noofcolumns\ht\partialpage
\ifnum\dimen\z@<\z@ % the amount of material contributed to the current page is more than the
% required \vsize (so that \pageshrink would have to be involved);
% output the page normally
\normaloutput{\unvbox\partialpage}\lheader\rheader
\else % move the footnotes into the buffer, recalculate their size
\migratefootnotes
\fi
}%
\eject
\def\footnoterule{\kern -3\p@ \hrule width \fnoteboxwidth \kern 2.6\p@}%
\outputnowfalse % not ready for immediate output, play with dimensions first
\lastpageupfalse % not the final page yet
\holdinginserts=\@ne
\let\thepage\pagesofar
\hsize=\columnwidth
\output={\multcolumnout}
\mco@computevsize
\ifvoid\migrantbox
\else
\insert\footins{\box\migrantbox}%
\fi
}
\def\mco@computevsize{%
\global\vsize=\pageheight%
\global\advance\vsize by-\ht\partialpage%
\global\divide\vsize\baselineskip
\global\multiply\vsize\baselineskip
\global\multiply\vsize\noofcolumns%
\global\advance\vsize by-\noofcolumns\topskip
\global\advance\vsize by\topskip
\global\advance\vsize by\noofcolumns\baselineskip
\global\advance\vsize by-\baselineskip
}
\newif\ifpenultimatepage
\newif\ifp@nultimatepage
\def\enddoublecols{\par % fire the page buidling routine
\ifnum\pagetotal>\pagegoal
\global\penultimatepagetrue
\eject % if the multicolumn output ended just barely after accumulating a full page
\fi % but before the page is shipped out, output the page with the standard multicolumn output
\dimen7 =\pagegoal
\vsize=\longvsize
% now recalculate all the dimensions assuming that the footnotes stretch across the whole page
\ifnum\footvboxht>\z@
\advance\vsize by \fnotesspan\footvboxht
\advance\dimen7 by \fnotesspan\footvboxht
\advance\vsize by -\noofcolumns\realfootins
\advance\vsize by \fnotesspan\realfootins
\advance\dimen7 by -\noofcolumns\realfootins
\advance\dimen7 by \fnotesspan\realfootins
\fi
\fnotesspan=\noofcolumns
\fnotesstart=\@ne
\remaindergaps=\noofcolumns
\advance\remaindergaps by -\fnotesstart
\remaindernonfoots=\z@
\fnoteboxwidth=\pagewidth
\setbox\z@=\hbox{}\setfootnoteheight
% calculate and adjust the height of the footnotes; this introduces an extra \hbox to \foothhbox
% remember this when in the output routine for the last page!
\advance\vsize by -\noofcolumns\footvboxht
\advance\dimen7 by -\noofcolumns\footvboxht
\pagegoal=\dimen7
%
\lastpageuptrue
\ifp@nultimatepage % everything has been output already
\global\penultimatepagefalse
\global\p@nultimatepagefalse
\else
\global\penultimatepagefalse
\eject
\fi
\endgroup
\holdinginserts=\z@
\global\pagegoal=\pageheight
\global\vsize=\pageheight}
\def\migratefootnotes{%
\ifvoid\footins
\else
\ifdim\dp\footins=\z@ % it is not a correction
\setbox\@ne=\vbox{\unvbox\footins
% similar to \makehboxofhboxes
\setbox\z@=\hbox{}%
\loop
\setbox\tw@=\lastbox
\ifhbox\tw@
\setbox\z@=\hbox{\unhbox\tw@\unhbox\z@}%
\repeat
% ...
\setbox\foothbox=\hbox{}%
\setbox\foothhbox=\hbox{}%
\footvboxht=\z@
\setfootnoteheight\global\setbox\migrantbox=\box\z@
}
\else
{\global\setbox\footins=\box\footins}%
\fi
\fi
}
\def\multcolumnout{%
\settopmark % save the \topmark if this is the top of the page
\splittopskip=\topskip
\splitmaxdepth=\maxdepth
\dimen\z@=\pageheight
\advance\dimen\z@ by-\ht\partialpage
\advance\dimen\z@ by-\dp\partialpage
\ifnum\dimen\z@<\baselineskip % another extreme case: at most one line will fit, so
% the adjustments to \vsize will not change the page layout
% quickly enough resulting in an infinite \deadcycles loop
\normaloutput{\unvbox\partialpage}\lheader\rheader
\unvbox\@cclv \penalty\lastpenalty
\mco@computevsize
\else
\multcolumnout@split
\fi
}
\newtoks\fromword % save the marks
\newtoks\toword
\def\multcolumnout@split{% proceed with splitting and balancing the columns
% normalize the max column height of the collected material first
\divide\dimen\z@\baselineskip \multiply\dimen\z@\baselineskip
\dimen\@ne=\pagegoal % we claculate the maximum allowable height of the
% middle column next
\advance\dimen\@ne by-\vsize
\advance\dimen\@ne by \fnotesspan\dimen\z@
\divide\dimen\@ne by\fnotesspan
%
\balanceallcolumns
%
\ifoutputnow
\global\fromword=\expandafter{\firstmark}
\global\toword=\expandafter{\botmark}
\iflastpageup
\onpage{\testpageno}{\message{outputting last page...}}%
\ifnum\outputpenalty<-9999 % this break was forced (most likely by the \break in \enddouble...)
\ifvoid\footins
\else
\ifdim\dp\footins=\z@ \else
{\setbox\footins=\box\footins}% this was a correcion box after which no new real footnotes
\fi % were contributed
\fi
% a correction (\hbox{}) was added by the \enddouble... command;
% this correction will affect \box\footins (since it will appear
% as a box in \foothhbox, a box that is not a footnote);
% this correction will be translated into an appropriate
% adjustment to \box\footins (since the output routine thinks
% it is a footnote); however, it does throw the footnote count in \foothhbox
% off by one; kill it here; the footnotes will be inserted from the footins box
\setbox\z@=\vbox{\pagesofar}%
\unvbox\z@ \penalty\lastpenalty %?
% since we could not touch \foothhbox above (to keep the footnote height calculations correct),
% the \footins box is messed up; fix it
{\setbox\footins=\box\footins}%
\global\setbox\foothhbox=\hbox{}% to keep the footnote counting
\global\setbox\foothbox=\hbox{}% consistent
\global\footvboxht=\z@
\else
\normaloutput\page\lheader\rheader
%
\global\vsize=\longvsize
\global\outputnowfalse
\global\holdinginserts=\@ne
\fi
\else % this is not the last page, perform normal multicolumn output
\normaloutput\page\lheader\rheader
%
\global\vsize=\longvsize
\global\outputnowfalse
\global\holdinginserts=\@ne
\ifpenultimatepage % page broken at a penalty inserted by \enddoublecols
\global\p@nultimatepagetrue % the next penalty should be removed
\fi
\fi
{\setbox\@cclv=\box\@cclv}% use up \box255 !
\else % do not output yet, see if adjustments worked
\ifnum\dimen\tw@>\dimen\@ne
\global\advance\vsize by -\fnotesspan pt
\else
\global\outputnowtrue
\global\holdinginserts=\z@
\fi
\unvbox\@cclv\relax
\ifnum\outputpenalty=\@M % 10000 the break was not at a penalty item
\else
\ifp@nultimatepage % we already split the page at this penalty
\global\p@nultimatepagefalse % let \enddoublecols insert the penalty
\else
\penalty\outputpenalty
\fi
\fi
\fi
}
% we will change some of the plain TeX macros used by cwebmac
\def\pagebody{%
\vbox to \pageheight{
\boxmaxdepth=\maxdepth \pagecontents
\the\footline
\ifr@ggedbottom
\vskip\adjskip
\fi
}
}
% since the output routine is executed several times for every physical page of output
% we have to make sure that the \topmark value is saved only once;
% the mechanism below relies on \normaloutput being the only physical means of outputting the page
% (more precisely, the only macro that contains the \shipout command and expands \savetopmark)
\newtoks\savedtopmark % keep track of the last mark
\def\settopmark{% this has to be done at the beginning of every \output routine
% it would have been a lot easier if there was an \everyoutput type command available
\yytoksempty\savedtopmark{\global\savedtopmark\expandafter{\topmark}}{}%
\yytoksempty\savedtopmark{\global\savedtopmark{{0}{0}{0}}}{}% make sure the saved topmark is not empty from now on
}
\def\normaloutput#1#2#3{\ifodd\pageno\hoffset=\pageshift\fi
% this is a convenient (although not very refined) way to ivestigate spacing problems
\onpageg{\testpageno}{\tracingoutput=1\relax}%
\shipout\vbox{
\vbox to\fullpageheight{
\iftitle\global\titlefalse
\else\hbox to\pagewidth{\vbox to10pt{}\ifodd\pageno #3\else#2\fi}\fi
\vfill
#1
}
}% parameter #1 is the page itself
\ifnum\outputpenalty=-'10000000000 % this is the \end ...
\everyendofjob
\fi
\global\advance\pageno by1
\global\savedtopmark{}% reset the last mark (the only place where this is done)
}
\def\topsecno{\expandafter\takeone\the\savedtopmark} % the last section on the
% previous page
% we change the original output routine from cwebmac.tex to handle the topmark saving
% mechanism introduced here
% a word of caution about the change below: if dcols.sty is not loaded immediately after
% cwebmac.tex (or at least before the first page is discarded) the output routine below
% must be further adjusted to
% \global\output{\settopmark\normaloutput\page\lheader\rheader}
% so that any `watsit' nodes on the first page (like \write, \open, etc) have a chance to
% execute; one possible (although not perfect) way of automating this choice is to detect
% the horizontal mode here and change the output routine accordingly.
\output{\setbox0=\page % the first page is garbage
\openout\cont=\contentsfile
\write\cont{\catcode `\noexpand\@=11\relax} % \makeatletter
\global\output{\settopmark\normaloutput\page\lheader\rheader}} % make sure the \topmark is nonempty; AS
\let\page\pagebody % this is a cwebmac command but it has to be executed here, after the \pagebody macro is changed
\def\pagecontents{
\ifvoid\topins
\else
\unvbox\topins
\fi
\setbox\z@=\vbox{\thepage}\dimen\z@=\dp\z@ % for \ruggedbottom
\unvbox\z@
\ifr@ggedbottom
\kern-\dimen\z@\vfil
\fi
\ifvoid\footins
\else
\ifnum\dp\footins=\z@ % this is not an adjustment
\vskip\realfootins\footnoterule
\vbox{\hsize=\pagewidth\makefootnoteparagraph}%
\fi
\fi
}
\def\thepage{\unvbox\@cclv}
\def\balanceallcolumns{
\tcthr=\vbadness
\vbadness=1000000 % set \vbadness to the badness of a overfull box
\count\@cclv\z@ % (does not really prevent TeX from reporting one)
\setbox\z@=\vbox{\unvcopy\@cclv}%
\setbox\tw@=\vbox{}%%% this box is changed globally
\b@lanceallcolumns
}
\def\b@lanceallcolumns{
\onpage{\testpageno}{\message{normalized (after partial page) max column ht(dimen0): \the\dimen0}}%
\advance\count\@cclv\@ne
\whichcolumn{\count\@cclv}%
\ifinfoots % if the footnotes go under these columns ...
\dimen\tw@=\ht\z@
\onpage{\testpageno}{\message{total height of remaining collected material, in footnotes(dimen2): \the\dimen2}}%
\advance\dimen\tw@ by -\remaindernonfoots\dimen\z@
\advance\dimen\tw@ by -\remaindergaps\baselineskip
\advance\dimen\tw@ by \remaindergaps\topskip
\divide\dimen\tw@ by \fnotesspan
\onpage{\testpageno}{\message{set footnote column ht(dimen2): \the\dimen2}}%
\let\next=\b@l@nceallcolumns
\else % otherwise, split off the columns ...
\onpage{\testpageno}{\message{total height of remaining collected material, pre footnotes(ht0): \the\ht0}}%
\ifnum\dimen\z@<\topskip
\setbox\@ne=\vsplit\z@ to \topskip
\else
\setbox\@ne=\vsplit\z@ to \dimen\z@
% see a remark below on why this was necessary
\fi
\wd\@ne=\hsize
\setbox\tw@=\vbox{\box\@ne \unvbox\tw@}%%% this box is changed globally
\let\next=\b@lanceallcolumns
\fi
\next
}
\newcount\tcthr
\def\b@l@nceallcolumns{% splitting off the columns after the footnotes start
\count\@cclv=\fnotesstart
\setbox3=\copy\z@
\setbox5=\vbox{}%
\b@l@nc@allcolumns
}
\def\b@l@nc@allcolumns{
% box3 contains a copy of the collected material after the pre footnote columns have been split off
\whichcolumn{\count\@cclv}%
\iflastcolumn
\ifnum\ht3>\dimen\ifinfoots \tw@ \else \z@ \fi
\onpage{\testpageno}{\message{last \ifinfoots (footnote) \fi column too high: \the\ht3 %
\space vs. allowable height(dimen\ifinfoots 2\else 0\fi): \the\dimen\ifinfoots \tw@ \else \z@ \fi}}%
\advance\dimen\tw@ by \@ne pt
\let\next=\b@l@nceallcolumns
\else
\ifinfoots
\else
\ifnum\dimen\z@<\topskip
\onpage{\testpageno}{\message{d0}}%
\setbox3=\vsplit3 to \topskip
\else
\onpage{\testpageno}{\message{d0>=ts--->}}%
\setbox3=\vsplit3 to \dimen\z@
\fi
\fi
\onpage{\testpageno}{\message{last \ifinfoots footnote \fi column height(ht3): \the\ht3 %
\space topskip: \the\topskip, }}%
\onpage{\testpageno}{\message{max column height(dimen0): \the\dimen0}}%
\wd3=\hsize
\setbox\tw@=\vbox{\box3 \unvbox5 \unvbox\tw@}%
%%% \box2 is later changed globally
\vbadness=\tcthr
\let\next=\relax
\fi
\else
\ifnum\dimen\ifinfoots \tw@ \else \z@ \fi<\topskip
\setbox4=\vsplit3 to \topskip
\else
\setbox4=\vsplit3 to \dimen\ifinfoots \tw@ \else \z@ \fi
\fi
% the code above is a replacement for:
% \setbox4=\vsplit3 to \dimen\ifinfoots \tw@ \else \z@ \fi
% \ifnum\badness>\@MM \errmessage{\the\badness:\the\vbadness}\fi
% the replacement was necessary to avoid `Overfull \vbox ... ' warnings
% that (unlike those for underfull boxes) cannot be silenced by raising
% \vbadness
\wd4=\hsize
\setbox5=\vbox{\box4 \unvbox5}%
\advance\count\@cclv\@ne
\let\next=\b@l@nc@allcolumns
\fi
\next
}
\def\pagesofar{%
\unvbox\partialpage
\count\@cclv\z@
\hbox to\pagewidth{\p@gesofar}%
\kern-\prevdepth
\vskip\adjskip
}
\def\p@gesofar{\advance\count\@cclv\@ne
\whichcolumn{\count\@cclv}%
\ifinfoots
\let\next=\footblock
\else
\iflastcolumn
\getnextcolumn\box\currentcolumn
\let\next=\relax
\else
\getnextcolumn\box\currentcolumn\hfil
\let\next=\p@gesofar
\fi
\fi
\next
}
\def\footblock{%
\onpage{\testpageno}{\message{building footnote columns...}}%
\hbox to \fnoteboxwidth{\f@otblock}%
\count\@cclv=\fnotesstart
\advance\count\@cclv by\fnotesspan
\advance\count\@cclv\m@ne
\whichcolumn{\count\@cclv}%
\onpage{\testpageno}{\message{column \the\count\@cclv\space to process...}}%
\iflastcolumn
\let\next=\relax
\onpage{\testpageno}{\message{done...}}%
\else
\hfil
\let\next=\p@gesofar
\onpage{\testpageno}{\message{process columns after the footnotes...}}%
\fi
\next
}
\def\f@otblock{%
\whichcolumn{\count\@cclv}%
\ifinfoots
\iffirstfootcol % put all the footnotes after the first column
\setbox\z@=\rlap{\vbox{
\ifvoid\footins
\else
\ifdim\dp\footins=\z@
% footnote info is present
\vskip\realfootins\footnoterule
\vbox{\hsize=\fnoteboxwidth\makefootnoteparagraph}
\fi
\fi
}}%
\dimen5=\ht\z@
\dimen6=\dimen5
\advance\dimen6 by\dimen\tw@
\setbox\z@=\vbox{
\getnextcolumn\unvbox\currentcolumn\kern-\dimen3
\vskip\adjskip
\box\z@
}%
\ifnum\ht\z@>\baselineskip
\setbox\z@=\vbox to \dimen\iflastpageup 6 \else \z@ \fi{\unvbox\z@}%
\fi
\wd\z@=\hsize
\box\z@
\else
% \onpage{\testpageno}{\showboxbreadth=100 \showboxdepth=100 \showbox\currentcolumn}%
\hfil\setbox\z@=\vbox{
\getnextcolumn\unvbox\currentcolumn\kern-\dimen3
\vskip\adjskip
\hrule width\z@ height \dimen5 depth\z@
}%
\onpage{\testpageno}{\message{topskip: \the\topskip, adjskip: \the\adjskip, bottom rule: wd=0pt, ht=\the\dimen5, dp=0pt}}%
\onpage{\testpageno}{\message{splittopskip: \the\splittopskip}}%
\onpage{\testpageno}{\message{last box height (preadjustment): \the\ht0 }}%
\ifnum\ht\z@<\topskip%>\baselineskip is another option
\else
\setbox\z@=\vbox to \dimen\iflastpageup 6 \else \z@ \fi{\unvbox\z@}%
\fi
\onpage{\testpageno}{\message{last box height: \the\ht0 }}%
\wd\z@=\hsize
\box\z@
\fi
\iflastcolumn
\let\next=\relax
\else
\let\next=\f@otblock
\fi
\else
\let\next=\relax
\fi
\advance\count\@cclv\@ne
\next
}
\def\getnextcolumn{%
\global\setbox\tw@=\vbox{\unvcopy\tw@ \global\setbox\currentcolumn=\lastbox}%
\dimen3=\dp\currentcolumn
}
\newif\ifinfoots
\newif\iflastcolumn
\newif\ifbeforefoots
\newif\iffirstfootcol
\def\whichcolumn#1{%
\infootsfalse
\lastcolumnfalse
\beforefootsfalse
\firstfootcolfalse
\ifnum#1<\fnotesstart
\beforefootstrue
\else
\ifnum#1=\fnotesstart
\firstfootcoltrue
\infootstrue
\else
\advance\fnotesstart by\fnotesspan
\ifnum#1<\fnotesstart
\infootstrue
\fi
\advance\fnotesstart by-\fnotesspan
\fi
\ifnum#1=\noofcolumns
\lastcolumntrue
\fi
\fi
}
% footnote accounting macros using aux stream
\yyuniondeclare\fnoteunion{aux:global:fnotes}
\defp\addfnlabel{}
\defp\addpgendlabel#1{}
\defp\setfniteration#1{}
\toyyunion{aux:global:fnotes:neutral}
\defc\addfnlabel{\expandafter\fnstream\expandafter{\the\fnstream*}}
\defc\addpgendlabel#1{\expandafter\fnstream\expandafter{\the\fnstream|}}
\defc\setfniteration#1{\fniteration=#1 }
\toyyunion{aux:global:fnotes}
\def\yyuniontag{\auxunionctl}
\defp\fnoteunionctl{}% sequence to activate/deactivate/take other action for
% fnote set of macros
\defc\fnoteunionctl{%
\restorecslist{aux:global:fnotes}\fnoteunion
}
\savecs{aux:global:activate}\fnoteunionctl
\defc\fnoteunionctl{%
\restorecslist{aux:global:fnotes:neutral}\fnoteunion
}
\savecs{aux:global:deactivate}\fnoteunionctl
\defc\fnoteunionctl{% this command should not make any page material contributions
\message{footnotes...}%
\fnstream{}%
\restorecslist{aux:global:deactivate}\auxunionctl
\auxunionctl % ignore all other sets
\restorecslist{aux:global:fnotes}\fnoteunion
\restorecs{aux:global:fnotes:neutral}\setfniteration
\input\jobname.aux
\edef\next{\the\fnstream}%
\checkfnprefixx{\savedfnstream}{\the\fnstream}%
{\message{Footnotes are stable ...}}%
{\message{Footnotes may be set incorrectly ...}}%
}
\savecs{aux:global:preend}\fnoteunionctl
\defc\fnoteunionctl{% this command should not make any page material contributions
\message{footnotes...}%
\let\footthenotes\markbottomofpage
\edef\savedfnstream{\the\fnstream}%
\advance\fniteration by\@ne
\toksa\expandafter{\fnoteunion}%
\immediate\write\auxstream{\harmlesscomment\the\toksa}%
\immediate\write\auxstream{\noexpand\setfniteration{\the\fniteration}}%
}
\savecs{aux:global:prestart}\fnoteunionctl
% end footnote accounting macros
% text crossreferencing setup using the aux stream
\yyuniondeclare\textrefunion{aux:global:textrefs}
\defp\refanchor#1#2\end{}
\toyyunion{aux:global:textrefs:neutral}
\defc\refanchor#1#2\end{%
\expandafter\def\csname ref: #1\endcsname{#2}%
}%
\toyyunion{aux:global:textrefs}
\def\yyuniontag{\auxunionctl}
\defp\textrefunionctl{}% sequence to activate/deactivate/take other action for
% fnote set of macros
\defc\textrefunionctl{%
\restorecslist{aux:global:textrefs}\textrefunion
}
\savecs{aux:global:activate}\textrefunionctl
\defc\textrefunionctl{%
\restorecslist{aux:global:textrefs:neutral}\textrefunion
}
\savecs{aux:global:deactivate}\textrefunionctl
\defc\textrefunionctl{% this command should not make any page material contributions
\message{text references...}%
}
\savecs{aux:global:preend}\textrefunionctl
\defc\textrefunionctl{% this command should not make any page material contributions
\message{text references...}%
\toksa\expandafter{\textrefunion}%
\immediate\write\auxstream{\harmlesscomment\the\toksa}%
}
\savecs{aux:global:prestart}\textrefunionctl
% end text cross referencing macros
% macros for adding and using counters for referencing
\def\volatile@counters{1(0){\errmessage{invalid counter!}}}
\def\delayed@counters{1(0){\errmessage{invalid counter!}}}
\def\addvcounter#1#2{% #1 is the name of the counter
% #2 is the access sequence
\counterattach\volatile@counters{#2}{#1}%
}
\def\adddcounter#1#2{% #1 is the name of the counter
% #2 is the access sequence
\counterattach\delayed@counters{#2}{#1}%
}
\def\counterattach#1#2{%
\expandafter\c@unterattach#1\end{#1}{#2}%
}
\def\c@unterattach#1(#2\end#3#4#5{% #1 is the counter top index
% #2 is the counter array
% #3 is the name of the counter array
% #4 is the access sequence of the new counter
% #5 is the name of the counter
\expandafter\def\expandafter#3\expandafter{\number\xincrement{#1}(#2(#1){#4}}% add the counter to the array
\expandafter\def\csname ct:\expandafter\eatone\string#3[#5]\endcsname{#1}% save counter index
\expandafter\def\csname get ct:\expandafter\eatone\string#3[#5]\endcsname##1(#1)##2##3\end{##2}%
}
\def\getcountervalue#1#2#3{% #1 is the name
% #2 is the name of the array
% #3 is the array instance
\csname get ct:\expandafter\eatone\string#2[#1]\endcsname#3\end
}
\addvcounter{section}{\secno}
\adddcounter{page}{\the\pageno}
\def\fulllabel#1{%
{%
\edef\next{\toksa{\volatile@counters}}\next % immediate references
\toksb\expandafter{\delayed@counters}% references to be processed at the page output stage
\edef\next{\write\auxstream{%
\string\refanchor{#1}\the\toksa\string\delayed\the\toksb\end}}\next
}%
}
\def\extractref#1{%
\ifx#1\relax
\yybreak{\ignoreref}%
\else
\yybreak{\expandafter\extractr@f#1}%
\yycontinue
}%
\def\ignoreref#1\end#2\end{{ref \bf ??}}
\def\extractr@f#1\delayed#2\end#3#4\end{%
% #1 is the volatile counters
% #2 is the delayed counters
% #3 is text for the link
% #4 is the reference constructor (like \solrefcompose)
#4{#1}{#2}{#3}%
}
% end crossreferencing setup macros
% helper macros to check if footnotes have been correctly placed
\def\checkfnprefix#1#2{%
\expandafter\ch@ckfnprefix\romannumeral-0\yyprefixmatch{#1}{#2}%
}
\def\ch@ckfnprefix#1#2#3{% #1 is the common prefix, #2 and #3 are remainders
\yystringempty{#2}{%
\yyifrepeatedchar|{#3}{\yyfirstoftwo}{\yysecondoftwo}%
}{%
\yysecondoftwo
}
}
\def\checkfnprefixx#1#2{%
\expandafter\ch@ckfnprefixx\expandafter{#1}{#2}%
}
\def\ch@ckfnprefixx#1#2{%
\expandafter\ch@ckfnpr@fixx\expandafter{#2}{#1}%
}
\def\ch@ckfnpr@fixx#1#2{%
\checkfnprefix{#2}{#1}%
}
% end footnote prefix checking helper macros
\let\footthenotes\empty
\footline{%
\footthenotes % so the footnotes know where to reset
\ifchapterhead
\vbox to 0pt{
\hbox to\pagewidth{\hfil
\mainfont\vrule width 0pt height 2pc\oldstyle\the\pageno
\hfil}
\vss
}%
\global\chapterheadfalse
\fi
}
\def\fnmark#1{{%
\ifnum#1<\@M
\setbox\z@=\hbox{\rm)}\vbox to \ht\z@{\hbox{$\scriptstyle\the#1$}\vss}\box\z@
\else
\setbox\z@=\hbox{\rm)}\setbox2=\hbox{$\scriptstyle0$}%
\setbox\@ne=\hbox{\vrule width\wd2 height\ht2}%
\vbox to \ht\z@{\box\@ne\vss}\box\z@
\fi}}
\newtoks\fnstream % locations of footnotes
\fnstream={}
\newcount\localfn % footnote count
\newcount\fniteration % current footnote calculation iteration count
\fniteration\z@
\def\markbottomofpage{%
\write\auxstream{\noexpand\addpgendlabel{\the\pageno}\harmlesscomment\space bottom of page \the\pageno}%
}
\def\setfnmark{{%
\ifnum\localfn<\@M
\getfntok
\if*\nexttok
\global\advance\localfn\@ne
\else
\global\localfn=\@M
\fi
\fi
\removewhitespace\kern2pt\fnmark\localfn
\write\auxstream{\noexpand\addfnlabel}%
}}
\def\getfntok{\loop\splitfnstream\if|\nexttok\global\localfn=\z@ \repeat}
\def\splitfnstream{%
\edef\tempdefone{\the\fnstream}%
\ifx\tempdefone\empty % no footnote tokens left, although we are expecting one
\def\nexttok{?}\message{You may have to reposition the footnotes ...}%
\else
\expandafter\splitfnstre@m\tempdefone\end
\fi
}
\def\splitfnstre@m#1#2\end{\def\nexttok{#1}\global\fnstream={#2}}