% altnline.sty    Version - 1.1
%
% Disclaimer - Use at your own risk.
%
% James Fortune                 
% Oakland University            
% jafortun@vela.acs.oakland.edu 
%
% Based upon the TUGboat article ``Output Routines: Examples and Techniques.''
% that appeared in Volume 11 (1990), Nos. 1, 3 and 4.
%
% This version incorporates suggestions made by Michal Jaegermann, namely:
%
% * Include explicit reference to the TUGboat article
% * ``You can use \def in style files without violating LaTeX spirit.
%     If you are writing style it is assumed that you know what you are
%     doing. :-)'' --- I don't know what I'm doing so I left the \newcommand
%   and \renewcommand commands as is.
% * Internal macros from style file should be protected against name conflicts
%   with user stuff by inclusion of '@' character in names. --- This is quite
%   reasonable so command names that the user is not expected to use in a
%   LaTeX file have been changed to include the '@' character.
% * He sent a new appendline command that adds numbers on a left margin
%   only that was also inspired by the Salomon article.  He left it as an
%   exercise for me to modify it for two-sided printing.  I probably shouldn't
%   have picked something from the double dangerous bend signs for my first
%   serious attempt at hacking on a style file :-).
% * A global linesSoFar so that lineCount may be set to linesSoFar to deal
%   with box255 being broken from the bottom up.  countlines (or its
%   equivalent) advances linesSoFar by a count of lines on a current page.
% * Use of a decremented remainder variable to determine when to add a number
%   to a line. --- I'm trying to get all the lines first.
% * He advised not trying to combine the countlines and duplicate operations
%   into a single loop.  ``I am afraid that you really have to first count
%   how many lines you have on a page and later use this value to produce
%   line numbers.''
%
% Changes to version 1.1 - Michal Jaegermann, ntomczak@vega.math.ualberta.ca
%
% * Added logic to print line numbers only every \lineCountInterval
% * Added a way to set up ONE range of numbered lines; use \nlinesBoundary
%   to do that. (It is possible to sprinkle your text with \nlinesBoundary
%   commands and they may even do the right thing if you will put them
%   in right places - but this is a hack.)
% * Miscellaneous cleanup
% * Every implicit or explicit \clearpage will still cause
%   'Output routine didn't use all of \box255' message.  Any volunteers
%   who know enough about LaTeX output routine to repair that?
%
   
% \font\sevenrm=cmr7

% Rainer showed me how to save the previous \output.  Thanks Rainer.
\newtoks\LaTeX@output
\LaTeX@output = \expandafter{\the\output}

\newcommand\zero@ToSp{\parskip=\@ne sp plus\@ne pt
  \renewcommand\vfil{\vskip1sp plus1fil}
  \renewcommand\vfill{\vskip1sp plus1fill}
  \abovedisplayshortskip=\@ne sp plus3pt
  \postdisplaypenalty=\@ne
  \interlinepenalty=\@ne}

\zero@ToSp


\newcount\lin@CountInit  % used to establish lineCount of first line on page
\lin@CountInit=\z@
\newcount\lineCountInterval  % used to determine how often lin@Count is printed
\lineCountInterval=5
%
\newcount\lin@CountStart  % don't print line numbers below this value
\lin@CountStart=\@ne
\newcount\lin@CountFinish  % don't print line numbers higher than this
\lin@CountFinish=\m@ne
%
% A command to set boundaries for line numbering.  Use as:
%   \nlinesBoundary{12}, or \nlinesBoundary[50]{12}
%   \nlinesBoundary[<optional upper limit>]<lower limit>
% Any negative number for an upper limit means number to the very end.
% This is a default!
%
\def\nlinesBoundary{\@ifnextchar[{\nlin@sBoundary}{\nlin@sBoundary[\m@ne]}}
\edef\nlin@sBoundary[#1]#2{%
  \global\lin@CountFinish=#1\relax
  \global\lin@CountStart=#2\relax}

\newif\ifa@@lnum  % do we really want to print that line number?

\newcount\lin@sSoFar
% remainder from division of \lin@sSoFar by \lineCountInterval
\newcount\total@Rem
% current value of remainder used to produce line numbers
\newcount\lin@rem
% these calculations allow to start with \lin@CountInit different from 0
\newcommand\resetlin@sSoFar{%
  \global\lin@sSoFar=\lin@CountInit
  \total@Rem=\lin@CountInit
  \divide\total@Rem by\lineCountInterval
  \multiply\total@Rem by-\lineCountInterval
  \global\advance\total@Rem by\lin@CountInit}

\resetlin@sSoFar

\newcount\lin@Count
\newif\ifAnyleft \newcount\pen
\newcommand\count@lines{%
  \global\lin@Count=\lin@sSoFar
  \loop \Anyleftfalse
    \ifdim\lastskip=\z@ \ifdim\lastkern=\z@ \ifnum\lastpenalty=\z@
      \setbox0=\lastbox
    \ifvoid0
    \else \Anylefttrue \global\advance\lin@Count by\@ne
                       \global\advance\total@Rem by\@ne
                       \ifnum\total@Rem=\lineCountInterval
                          \global\total@Rem=\z@
                       \fi\fi
    \else \Anylefttrue \unpenalty \fi
    \else \Anylefttrue \unkern \fi
    \else \Anylefttrue \unskip \fi
  \ifAnyleft \repeat}

\newcommand\@duplicate{%
  \loop \Anyleftfalse
    \ifdim\lastskip=\z@ \ifdim\lastkern=\z@ \ifnum\lastpenalty=\z@
      \global\setbox0=\lastbox \ifvoid0 % end of breakup loop
    \else \Anylefttrue                  % box present
      \ifnum\lin@rem=0                  % if remainder non-zero we do not care
        \lin@rem=\lineCountInterval
        \ifnum\lin@Count<\lin@CountStart
          \a@@lnumfalse
        \else
          \ifnum\lin@CountFinish<0      % no upper bound
            \a@@lnumtrue                % print it
          \else
            \ifnum\lin@Count>\lin@CountFinish
              \a@@lnumfalse
            \else
              \a@@lnumtrue              % this is the ticket
            \fi
          \fi
        \fi
      \else
         \a@@lnumfalse
      \fi
      \ifa@@lnum
         \append@line
      \else
         \global\setbox1=\vbox{\box0\unvbox1}
      \fi
      \advance\lin@Count\m@ne
      \advance\lin@rem by\m@ne\fi
    \else \Anylefttrue                  % penalty present
      \pen=\lastpenalty
      \global\setbox1=\vbox{\penalty\pen\unvbox1}\unpenalty\fi
    \else \Anylefttrue                  % kern present
      \dimen0=\lastkern
      \global\setbox1=\vbox{\kern\dimen0\unvbox1}\unkern \fi
    \else \Anylefttrue                  % skip present
      \skip0=\lastskip
      \global\setbox1=\vbox{\vskip\skip0\unvbox1}\unskip \fi
    \ifAnyleft \repeat}

\newcommand\append@line{%  attach line number
  \setbox2=\vbox to \z@{\smash{\footnotesize\the\lin@Count}}
  \wd2=25pt                           % that much of space for a line number
  \ifodd\count0                       % on the right margin for odd pages
     \setbox0=\hbox{\box0\rlap{\rule{\wd2}{\z@}\box2}}  
  \else                               % and on the left for even
     \setbox0=\hbox{\llap{\box2}\box0}
  \fi
  \global\setbox1=\vbox{\box0\unvbox1}} % add this to a reconstructed page

\newbox\brk    % Use old output definition if page is not to be output
\output={\ifnum\outputpenalty <-\@M
  \output={\LaTeX@output}
\else
  \lin@Count=\lin@sSoFar
  \setbox\brk=\vbox{\unvcopy\@cclv\count@lines}
           \global\setbox1=\vbox{}
           \lin@rem=\total@Rem
  \global\lin@sSoFar=\lin@Count
  \setbox\brk=\vbox{\unvcopy\@cclv\@duplicate}
  \ifdim\ht\brk>\z@\message{Incomplete breakup}\fi
  \ht1=\z@\dp1=\z@
  \global\setbox\@cclv=\vbox to\vsize{\unvbox1}% attempt to get glues back
  \@makecol\@opcol
\fi}
\endinput