% Copyright 2004-2020, 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}

\newtoks\fromword
\newtoks\toword

\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 \enddoublecolumns 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

%

\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\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={
     \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
  \output={\multcolumnout} 
  \hsize=\columnwidth 
  \global\vsize=\pageheight%
  \global\advance\vsize by-\ht\partialpage%
  \global\divide\vsize\baselineskip
  \global\multiply\vsize\baselineskip
  \global\multiply\vsize\noofcolumns%
%\message{starting with vsize at \the\vsize, with pp at \the\ht\partialpage}
  \global\advance\vsize by-\noofcolumns\topskip
  \global\advance\vsize by\topskip
  \global\advance\vsize by\noofcolumns\baselineskip
  \global\advance\vsize by-\baselineskip
%\message{vsize set at \the\vsize}
  \ifvoid\migrantbox
  \else
      \insert\footins{\box\migrantbox}%
  \fi
}

\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{%
    \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
    \fi
    \divide\dimen\z@\baselineskip \multiply\dimen\z@\baselineskip 
%\message{aiming for d0: \the\dimen0}
    \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
%\message{d1: \the\dimen1, d0: \the\dimen0, pageheight: \the\pageheight }%
%\message{(vsize: \the\vsize, pagegoal: \the\pagegoal\space ppage: \the\ht\partialpage)^^J^^J}%
    %
    \balanceallcolumns
    %
    \ifoutputnow
        \global\fromword=\expandafter{\firstmark}
        \global\toword=\expandafter{\botmark}  
        \iflastpageup
            \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 cotributed
                \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 off 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, preform normal multicolumn output
            \normaloutput\page\lheader\rheader
            %
            \global\vsize=\longvsize
            \global\outputnowfalse
            \global\holdinginserts=\@ne
            \ifpenultimatepage               % page broken at a penalty inserted by \enddoublecolumns
                \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
        \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 \enddoublecolumns 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
    }
}

\def\normaloutput#1#2#3{\ifodd\pageno\hoffset=\pageshift\fi
 \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
  \global\advance\pageno by1}

\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{
  \advance\count\@cclv\@ne
  \whichcolumn{\count\@cclv}%
  \ifinfoots % if the footnotes go under these columns ...
      \dimen\tw@=\ht\z@
%\message{set d2(=ht0): \the\dimen2, d0: \the\dimen0; vs. ph: \the\pageheight}%
      \advance\dimen\tw@ by -\remaindernonfoots\dimen\z@
      \advance\dimen\tw@ by -\remaindergaps\baselineskip
      \advance\dimen\tw@ by \remaindergaps\topskip
      \divide\dimen\tw@ by \fnotesspan 
%\message{set d2: \the\dimen2}%
      \let\next=\b@l@nceallcolumns
  \else % otherwise, split off the columns ...
      \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{
  \whichcolumn{\count\@cclv}%
  \iflastcolumn
%\message{box3 height: \the\ht3, box3 depth: \the\dp3, d0: \the\dimen0, d2: \the\dimen2}%
      \ifnum\ht3>\dimen\ifinfoots \tw@ \else \z@ \fi
          \advance\dimen\tw@ by \@ne pt
          \let\next=\b@l@nceallcolumns
      \else
          \ifinfoots
          \else
              \ifnum\dimen\z@<\topskip
                  \setbox3=\vsplit3 to \topskip
              \else
                  \setbox3=\vsplit3 to \dimen\z@ 
              \fi
          \fi 
%\message{**box3 height: \the\ht3, d0: \the\dimen0, bs: \the\baselineskip, ts: \the\topskip}%
          \wd3=\hsize
          \setbox\tw@=\vbox{\box3 \unvbox5 \unvbox\tw@}%
          %%% \box2 is laterchanged 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{%
  \hbox to \fnoteboxwidth{\f@otblock}%
  \count\@cclv=\fnotesstart
  \advance\count\@cclv by\fnotesspan
  \advance\count\@cclv\m@ne
  \whichcolumn{\count\@cclv}%
  \iflastcolumn
      \let\next=\relax
  \else
      \hfil
      \let\next=\p@gesofar
  \fi
  \next
}

\def\f@otblock{%
  \whichcolumn{\count\@cclv}%
  \ifinfoots
      \iffirstfootcol
          \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
          \hfil\setbox\z@=\vbox{
              \getnextcolumn\unvbox\currentcolumn\kern-\dimen3
              \vskip\adjskip
              \hrule width\z@ height \dimen5 depth\z@
          }%
          \ifnum\ht\z@>\baselineskip
              \setbox\z@=\vbox to \dimen\iflastpageup 6 \else \z@ \fi{\unvbox\z@}%
          \fi
          \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 counting 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}}

\def\addfnlabel{\expandafter\fnstream\expandafter{\the\fnstream*}}
\def\addpgendlabel{\expandafter\fnstream\expandafter{\the\fnstream|}}

% the commands above will be exectuted when the .ftn file is loaded below

\newtoks\fnstream % locations of footnotes
\fnstream={}

% before processing the footnotes one by one we have to open an
% auxiliary file (we have to read it in whole because it will be
% rewritten as the document is being typeset); this opening has to be
% done carefully for the file might not be there yet; check for it first.
% as a side note, one should not use the same stream number (at least the
% one allocated by a \new... command) for both the input and the output
% streams, since one might accidentally close a different stream that
% happened to have the same index but allocated by a \new... command as a
% stream of a different type.

\newread\tryfnlabels % to check if the file exists
\newwrite\fnlabels
\newcount\localfn % footnote count
\newcount\fniteration

\def\setupfootnotes{% this macro should be used at the beginning of the file, after a box (preferably)
    \let\footthenotes\markbottomofpage
    \openin\tryfnlabels=\jobname.ftn\relax
    \ifeof\tryfnlabels
        \closein\tryfnlabels\relax
        \fniteration\z@
    \else
        \closein\tryfnlabels\relax
        \input \jobname.ftn\relax
    \fi
    \edef\savedfnstream{\the\fnstream}%
    % now we open the same file for writing ...
    \openout\fnlabels=\jobname.ftn\relax
    \advance\fniteration\@ne
    \write\fnlabels{\noexpand\fniteration\the\fniteration\space}%
}

\def\markbottomofpage{%
    \write\fnlabels{\noexpand\addpgendlabel}%
}

\def\unsetfootnotes{%
    \def\footthenotes{%
        \write\fnlabels{\noexpand\endinput}%
        \closeout\fnlabels
        \global\let\footthenotes\checkfootnotestream%
        % it is tempting to say \input \jobname.ftn
        % at this point to use in the test below but this is not
        % going to work: the \closeout will get invoked during the
        % \shipout, which happens after the page is set and these 
        % macros are expanded.
        % note that using another `stream' sequence for this purpose 
        % would not work either, since a footnote at the bottom of the
        % page might `fire' but would be put on the next page by
        % the epage builder.
    }%
}

\def\checkfootnotestream{% this needs at least one extra page to work correctly ...
    \fnstream{}%
    \input\jobname.ftn
    \edef\next{\the\fnstream}%
    \ifx\next\savedfnstream
        \message{Footnotes are stable ...}%
    \else % this test is too strict, a better way would be to check that
          % \next is a prefix in \savedfnstream and the remaining characters are all `|'
        \message{Footnotes may be set incorrectly ...}%
    \fi
    \global\let\footthenotes\empty
}

\def\setfnmark{{%
  \ifnum\localfn<\@M 
        \getfntok
        \if*\nexttok
            \global\advance\localfn\@ne 
        \else
            \global\localfn=\@M
        \fi
  \fi
  \removewhitespace\kern2pt\fnmark\localfn
  \write\fnlabels{\noexpand\addfnlabel}%
}}

\def\getfntok{\loop\splitfnstream\if|\nexttok\global\localfn=\z@ \repeat}

\def\splitfnstream{\edef\tempdefone{\the\fnstream}%
  \ifx\tempdefone\empty
    \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}}

