% 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 <http://www.gnu.org/licenses/>.

% 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<ts--->}}%
                  \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}}
