% PURPOSE:

% This TeX macro package provides numbering of lines in the output file.
% It is intended for manuscripts in a draft stadium, to facilitate
% reference to passages in communication between authors and referees,
% for example.
%
% I have successfully tried these macros with plain TeX, AMS-TeX,
% LaTeX 2.09, and LaTeX-2e.
%

% WHAT THE USER CAN SPECIFY:

% - the font and appearance of the line numbers;
% - whether they are reset at every page;
% - how the procedure determines what boxes to count as lines;

% POSSIBLE FUTURE EXTENSIONS:
% - switching line numbering on and off;
%   (can now be done on a page-per-page basis by temporarily redefining
%         \def\checktobecounted {\tobecountedfalse}
% - resetting the counter at arbitrary places.
% This could be incorporated by generating special penalties which are
% recognized by the breakup routine.
%
% - opening vboxes like figures or tables, \parboxes, to
%   number lines within such sub-boxes.
% - integrating with twocolumn-style of the multicol package.
%   (It would probably not make sense to number lines when more
%   than two columns are used.)
% - maybe this package should be converted to docstrip format.
% - change 0 to \z@ etc. to make processing faster (but make the
%   macros harder to read)


% COMPARISON TO THE "lineno" PACKAGE
%
% There is a package called lineno by Stephan B\"ottcher and
% Uwe L\"uck, which offers the same basic functionality.
% The two packages use complementary strategies.
% lineno attaches the line numbers as soon as the lines are generated,
% i.e., moved from the paragraph to the current page,
% and it has to modify the internals of some LaTeX macros.
% By contrast, linenum attaches the numbers as an "afterthought" after
% the page is finished.
% As a consequence, some things that are "hard" for lineno, like
% starting the numbers from 1 one every page, numbering in the
% outside margins in two-column format, or including footnotes in the
% numbering, are straightforward for linenum.
% Other things that are "easy" for lineno, like selectively switching
% numbers on and off or resetting the numbers in a particular place of
% the text, would be harder for linenum. Some things that lineno can
% do, like referencing line numbers in the text itself, would require
% a major effort for linenum.
%
% I am certain that the structure of pages and page breaks are not
% changed when linenum is switched on or off.
%
% lineno has some unique features, in particular, the possibility to
% refer to line numbers via the \ref-mechanism.
% It has some comfortable interface to control the behavior of line
% numbering via LaTeX macros, whereas the control of linenum requires
% to write (easy) plain-TeX macros. (Examples are given in this
% documentation.)
% On the other hand, especially in connection with math formulas,
% lineno sometimes omits numbers for whole paragraphs and longer passages.
% linenum also omits lines on occasion, as detailed below under the
% heading "BUGS", but these are usually just one or two consecutive lines.
% linenum works also with plain TeX.

% MY RECOMMENDATION:
% For attaching line numbers for the purpose of easy reference to
% lines from OUTSIDE the text, e.g. for reviewing, when the line
% numbers will be removed for final publication, I recommend linenum
% for the reason that is misses fewer lines.
% On the other hand, lineno is better suited when the numbers are part
% of the published text, like poetry editions of transcripts of an
% interview.
%
% On can use lineno and linenum simultaneously.

% ============================================
% Author: G\"unter Rote, rote@inf.fu-berlin.de
%
% This package was developed starting from a rudimentary version
% of the \breakup macro that I found in David Salomon's
% "advanced TeXbook" (1995).
% The documentation has been updated in Feb. 2015
% ============================================

%%% "PUBLIC PART": MACROS THAT CAN BE MODIFIED BY THE USER.
%
%
% APPEARANCE OF THE COUNTER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\font \linenumfont=cmr7               %% This is the font which is used.

\def\linenumber{\number\linecount}    %% This macro is used for generating
                                      %% the number. The result will be
                                      %% put in an \hbox.

\newcount\linecount % The actual line number is
                    % stored in the counter \linecount.

% If you want to include the page number with the line number,
% you can for example say:
%
%  \def\linenumber{\number\count0:\ifnum\linecount<10 0\fi \number\linecount}
%
% Another possibility:
%
%  \def\linenumber  %% for numbering only every fifth line,
%                   %% as in philological critical source editions
%  {{\ifnum\linecount=1 \number\linecount
%    \else \count255=\linecount \divide\count255 by 5 \multiply\count255 by 5
%          \advance\count255 by -\linecount
%          \ifnum\count255=0 \number\linecount \fi
%    \fi}}          % (For such editions, however, the EDMAC
%                   % macro package is more approproate.)

% Line numbers are usually attached in a right-justified column in the left
% margin, separated 30pt from the main text.

\newdimen\linenumberseparation
\linenumberseparation= 30 pt

\newif\iflinenumbersonright

% If you want to have the numbers on the right side,
% (left justified), simply set
%
%   \linenumbersonrighttrue
%
% The macro \determinewhichside is called at the beginning of
% every page. To get the numbers on the right side for odd pages
% and on the left side for even ones, (like for the LaTeX twoside
% style option), define
%
%   \def \determinewhichside
%      {\ifodd \count0 \linenumbersonrighttrue
%       \else \linenumbersonrightfalse \fi}
%
% The default is to number all pages on the same side:

\let\determinewhichside=\relax

% In LaTeX two-column output, line numbers are in the outer margins.
% The macro \determinewhichside is not used.
% This does not work with the multicol package.
%

% For testing the positioning of the line numbers, I used the following
% settings:
%
%    \linenumberseparation=1pt
%    \def\linenumber{\number\linecount\vrule height 0.1pt depth 0pt width 3pt}

%% HOW THE COUNTER COUNTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% The following command is used to reset the line counter
% on every page:
%
\def \resetlinecount {\linecount=0}

% If lines should be counted continuously, disable the resetting of
% the counter by setting:
%
%   \let\resetlinecount=\relax
%
% Another possibility:
%    \def \resetlinecount          %% This is for having
%    {\linecount=\count0           %% the page number in
%    \multiply \linecount by 100}  %% the hundreds digit.
%
% In LaTeX two-column format, this macro is called only at
% the beginning of the first (left) column.

%% WHAT THE COUNTER COUNTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% the following macro \checktobecounted is used to decide
% which boxes are lines to be numbered.
% The "line" is contained in \box0, and the macro should
% make its decision based on the contents and the dimensions of
% the box, executing either \tobecountedtrue or \tobecountedfalse.
% The default procedure just looks at the height and depth of the box.
% For example, a large figure or a large \parbox
% (like an abstract, in some formats) is not numbered.
% Apparently, LaTeX puts such things into boxes.
%
% More elaborate procedures that check whether the box is an
% hbox or a vbox, or examine the contents of the box, are conceivable.

\newif\iftobecounted
\def\checktobecounted  % try to guess whether \box0 is a line to be counted
                   % The dimensions of box0 must be left intact.
{\tobecountedfalse
 \ifdim\ht0>3pt
 \dimen0=\ht0 \advance\dimen0\dp0
 \ifdim\dimen0<60pt % otherwise probably just a large figure or parbox
    \tobecountedtrue
 \fi\fi
}


% HOW IT IS DONE: ================================================
%
% This macro package does not use special penalty values to
% communicate with the output routine; instead it (temporarily)
% changes the output routine.
%
% After the \pagebody is constructed in the output routine,
% the linenum package intervenes and ADDS
% an additional vbox with line numbers to the \pagebody.
% The original \outputbox is left INTACT.
% and will have the same dimensions as before the modification.
% This means that we need not worry about \moveleft-shifted lines
% or displayed equations. (When such boxes are removed from a
% vertical box by the \lastbox command, information about
% horizontal adjustment is lost.)
%
% First, the box \@outputbox, which contains the assembled material
% for a page or column (including footnotes) is dismantled step by
% step from the end by using the mechanisms \lastpenalty/\unpenalty,
% \lastskip/\unskip, \lastbox etc. The contents are analyzed, and
% simultaneously another box \b@ildnums mirroring the contents of
% \@outputbox is built.
% This box contains the same glue and kern items as \@outputbox.
% The penalties in \@outputbox are of course discarded
% because they are not needed for formatting the numbers.
% Each box in \@outputbox is represented by an empty hbox of
% the same height and depth. (However, if the procedure \checktobecounted
% decides that a box does not represent a "line", the box is
% represented by the appropriate amount of kerning.)
% During this step the number of lines is counted.
%
% After box \b@ildnums has been built in this way, it is again
% broken into pieces, and the empty boxes are filled with line numbers.
% This breakup step is much easier, since care has been taken that
% box \b@ildnums contains no glue or kern with (natural) length 0.
% The line numbers are accumulated in box \br@@k (which was originally
% used to store the partial contents of box \@outputbox).
% The glue of this box is reset to match the total dimensions of
% box \@outputbox, and the result is adjutted to \@outputbox,
% without changing the dimensions of \@outputbox.
%
%
% One problem is the treatment of \write's (for cross-references)
% \specials's, \mark's (for page headings), and other whatsits,
% which resist breaking by \lastbox, \unpenalty, etc. commands
%
% There are two options:
% A. redefine everything so that \write's, \mark's etc. are
%    contained in boxes (maybe this destroys the operation of marks?)
%    or disabled.
%    This disables the generation of output files other than the log-file
%    and the dvi-file. For example, aux-files or index files that are
%    usually written (or updated) would not be generated (or would be
%    left intact).
% B. use the \vsplit operation to break a part from the bottom of
%    the current page.
%    In this case, however, glue (and penalty) that occurs after
%    the break is discarded.
%    The natural length of glue can be found without problem,
%    as the difference between dimensions before and after splitting.
%    But the stretch and shrink components are not readily available.
%    So we have to reconstruct this glue otherwise.
%    There are again two options:
%    B1. experiment with adding some stretchability and shrinkability
%        to the vbox, resetting it to various heights, and
%        to determining the badness; For example, binary search
%        can find the finite stretch and shrink components to
%        1sp precision in this way.
%        The drawback of this solution is that infinite stretch
%        components cannot be found in this way. (This should not
%        be a problem for reasonable pages, probably.)
%    B2. Use TeX's built-in \pagestretch, \pagefilstretch, etc.
%        parameters.
%        The drawback of this solution is that these parameters
%        work only for the "current page",
%        Therefore, modification of the output routine is required,
%        and the solution becomes less portable.
%        (It must be adapted to each version of LaTeX or TeX.)
%
% I have chosen to implement B2.

% Occasionally the vbox that is split off the last part of
% the page during a \vsplit operation gives no clue where the
% baseline of some hbox{text line} lies within it.
% For example, in LaTeX,
%
%     \section{Introduction}\label{section1}
%
% produces a vertical list
%
%     \hbox{1. Introduction},\nobreak,\vspace,\write{\newlabel..},
%
% which is unsplittable.
% Even accessing the height of the first box via the height
% of a \vtop is impossible because there will always be a
% \splittopskip before the \hbox.
% In this case, (more generally, when the box has no depth,)
% we determine the height of the first hbox by
% varying \splittopskip.
% (Perhaps this trick can be carried into the lineno package?)


% BUGS ===============================================
%
% 1. Here is a situation in LaTeX for which the mechanism of
% this package fails:
%
%     \section{Introduction}\subsection{Notation}
%
% produces a vertical list
%
%     \hbox{1 Introduction},\write{..toc..},\nobreak,\vspace,
%     \hbox{1.1 Notation},  \write{..toc..},\nobreak,\nobreak,\vspace, 
%
% Not only can the list not be broken between the two "lines" (\hboxes)
% but the "\write" whatsit after the second line prevents
% the list from being dismantled by \lastbox etc. commands.
% In this case, the second line is not numbered (or the first line when
% this situation occurs at the top of a page.)
% A similar situation happens when a Theorem or Lemma starts near the
% beginning of a section.

% 2. In connection with the {align*} environment of the amsmath package,
% a line may get two numbers printed on top of each other.
% The package produced an empty box for some reasons. Probably this
% could be detected by linenum and fixed.

% ==================================================
%%% "PRIVATE PART":

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% save current category code of `@'
\chardef\atcode=\catcode`\@
\catcode`\@=11 % in case we have plain TeX

% ALTERNATIVE:
% \begingroup
% \def\gdef{\global\def}
% % make all definitions local except when explicitly defined global

\newif\if@nyleft \newcount\@mptytrials
\newif\ifn@skip

\newif\ifn@rmaloutputoperation \n@rmaloutputoperationtrue


\newbox \save@outputbox
\newbox \save@marks
\newbox \b@ildnums
\newbox\br@@k
\newbox\c@mpensate
\newdimen\save@vsize@forlinenum

\def\checkn@skip %% check if lastskip is any skip other than \vskip 0
{\n@skiptrue     %% (A replacement for \ifskip)
 \ifdim\lastskip=0pt
  \skip0=\lastskip
  \bgroup \hfuzz=\maxdimen\hbadness=10000
  \setbox0=\hbox to 1sp {\hskip\skip0}%
  \ifnum\badness=10000
   \setbox0=\hbox to -1sp {\hskip\skip0}%
   \ifnum\badness=1000000
    \setbox0=\hbox to 1sp {\hskip\skip0 \hskip 0pt plus 1sp}%
    \ifnum\badness=100
     \setbox0=\hbox to -1sp {\hskip\skip0 \hskip 0pt minus 1sp}%
     \ifnum\badness=100
       \egroup \n@skiptrue
     \else \egroup \n@skipfalse \fi
    \else \egroup \n@skipfalse \fi
   \else \egroup \n@skipfalse \fi
  \else \egroup \n@skipfalse \fi
 \else \n@skipfalse \fi
}

\def\break@up
{\@mptytrials = 0
 \loop
   \@nylefttrue
   \ifdim\lastkern=0pt \ifnum\lastpenalty=0 \checkn@skip \ifn@skip
     \setbox0=\lastbox
   \ifvoid0 \@nyleftfalse
   \else \app@ndline \fi
   \else \skip0=\lastskip
     \ifdim\skip0=0pt % avoid generating 0 skips
       \advance\skip0 by 1sp
       \global\setbox\b@ildnums=\vbox{\vskip\skip0 \kern -1sp \unvbox\b@ildnums}
     \else
       \global\setbox\b@ildnums=\vbox{\vskip\skip0 \unvbox\b@ildnums}
     \fi
                                                      \unskip \fi
   \else                                           \unpenalty \fi
   \else \dimen0=\lastkern
       \global\setbox\b@ildnums=\vbox{\kern\dimen0 \unvbox\b@ildnums}
                                                      \unkern \fi
 \if@nyleft \@mptytrials = 0
 \else
   \advance \@mptytrials by 1
   \ifn@skip \unskip \fi
   \ifdim\lastkern=0pt \unkern \fi
   \ifnum\lastpenalty=0 \unpenalty \fi
   \ifnum\@mptytrials<10 \@nylefttrue \fi
      %% 10 = max number of consecutive \penalty 0, \vskip 0pt etc.
 \fi
 \if@nyleft \repeat}


\def\app@ndline % process \box0
                % leaves local variables unchanged
{{\checktobecounted
 \global\setbox\b@ildnums=\vbox{
   \iftobecounted
     \global\advance\linecount by 1
     \setbox2=\null \ht2=\ht0 \dp2=\dp0
     \box2
   \else
     \dimen0=\ht0 \advance\dimen0 by \dp0
     \ifdim \dimen0=0pt \else \kern\dimen0 \fi
   \fi
 \unvbox\b@ildnums}}}

\def \app@ndvbox@line  % modify height and depth of \box0 after
                       % "difficult" splitting, to reflect the
                       % probable baseline.
{{\checktobecounted
   \iftobecounted
    \ifdim\dp0=0pt % no depth; try to find the height of the first hbox:
      \dimen0=\ht0 % this height was generated without splittopskip.
%    \tracingonline=1
      \splittopskip=\maxdimen
      \advance \splittopskip by -\ht0
      \setbox2=\vbox{\break \unvcopy0}
      \setbox4=\vsplit 2 to 0pt
      \ifdim \ht2=0pt %% TEST THIS!
                        % Then apparently \box0 contains no boxes at all
        \dimen2=0pt
      \else
        \dimen2= \maxdimen
        \advance\dimen2 by -\ht2 % If \box0 contains any boxes at all,
                                 % then \dimen2 is now the height of the
                                 % first box in \box0.
                               % [ (If this is too small, then this
                               % is probably not a line, and we
                               % should probably do something else. ]
      \fi
      \advance\dimen0 by -\dimen2
      \advance\dimen0 by \dp0
      \ht0=\dimen2 \dp0=\dimen0
    \fi
   \fi
 }
 \app@ndline}

\def \s@vestretches % store the NEGATIVE current page size (including
                    % stretch and shrink components in \box\c@mpensate
{\global\setbox\c@mpensate=\vbox{
   \ifdim \pagetotal=0pt % avoid generating \vskip 0pt
                \vskip -1sp plus -\pagestretch minus -\pageshrink \vskip 1sp
   \else \vskip -\pagetotal plus -\pagestretch minus -\pageshrink \fi
   \s@vefilstretch \pagefilstretch {fil}
   \s@vefilstretch \pagefillstretch {fill}
   \s@vefilstretch \pagefilllstretch {filll}}}

\def \s@vefilstretch #1#2{\ifdim#1=0pt \else
      \skip0=0pt plus -0,000017 #2
      \multiply\skip0 by #1
      \advance\skip0 by 1sp
      \kern -1sp \vskip\skip0
  \fi}

\def \ch@ngepagecontents
 % input:  \@outputbox     ... a vbox whose lines are to be numbered
 % output: \box\b@ildnums  ... a vbox with line numbers, of depth + width 0,
 %                      reference point at the top corner,
 %                      right-aligned if \align@linenum=\rlap
 %                      left-aligned  if \align@linenum=\hbox
 % in \finish@contents this box is combined with \@outputbox
 %
%
{{\initialize@page % reset \linecount and determine side for counters
  \global\linecount=\linecount % beware for argless users
  \iflinenumbersonright
        \global\let \align@linenum=\hbox \global\linenumbersonrighttrue
  \else \global\let \align@linenum=\llap \global\linenumbersonrightfalse \fi}
 \global\setbox\b@ildnums=\vbox{}
 \global\setbox\br@@k=\vbox{\null \unvcopy \@outputbox}
     % insert a height-0 box at the top, to freeze topskip from
     % disappearing from the top of a page
     % and to know what the first item in the box is.
 \do@breakup
}

\def \initialize@page        % This will be modified for LaTeX
{\determinewhichside\relax   % to take into account two-column output
 \resetlinecount\relax}



\def\do@breakup
{\global\setbox\br@@k=\vbox{\unvbox\br@@k \break@up}
 \ifdim\ht\br@@k>0pt % then try harder (see also \do@breakup@four)
    %% \message{try harder:} \showbox\br@@k
   \save@for@linenum.sty
   \global\vsize=\maxdimen
   \unvcopy \br@@k
   \hrule height 0pt % to ensure that \pagedepth=0pt
                     % [ Apparently \pagedepth does not survive
                     %   into the \output routine, for some
                     %   strange reasons. ]
   \eject % put all of this on the current page in order to
          % determine stretchability and shrinkabiliy
   \global \n@rmaloutputoperationfalse % skip the rest of the current
                                       % output routine
   \global \output={\do@breakup@}
 \aftergroup \huhu  % can achieve marvellous effects with this
%                    % construction, which takes place after
%                    % the output routine has finished.
%                    %    (Am I sure about this?)
%                    % For example, we might try to keep changes
%                    % to \vsize etc. local, making
%                    % parts of \save@for@linenum.sty superfluous.
%                    % Unfortunately I didn't have the nerve to
%                    % work on this.
% % Don't forget to restore \aftergroup at the end!
% % (Or is it restored automatically after execution?)
 \else
   \finish@contents
 \fi
}

 \def\huhu{}%\begingroup \maxdepth=3.12345pt \tracingpages=1\relax}

\def \do@breakup@
 {\setbox0=\box255 % discard page
  \s@vestretches   % (Only the dimensions of the page are interesting.)
  \dimen8=\pageshrink
  \dimen0=\ht\br@@k
  \setbox0=\vbox{\penalty 9999 % ensure that a legal breakpoint exists
                 \vskip 1sp minus -\pageshrink % neutralize the shrink
                 \unvbox\br@@k}
%
  \vfuzz=\maxdimen \vbadness=10000
  \splittopskip=-\maxdimen
  \splitmaxdepth=\maxdimen
  \global \setbox\br@@k=\vsplit 0 to \dimen0 % \dimen0 is 1sp shorter
  %       ================================== % than \box0
  \ifvoid 0 % then possibly no progress has been made.
            % watch for deadcycles
                    \errmessage{box 0 ist ler}\showbox\br@@k
  \else
    \deadcycles=0
    \app@ndvbox@line
  \fi
  %
  % now find out discarded glue and kern
  %
  % Remark: \box\br@@k is never void if \box0 was non-void initially.
  % but it may be empty.
%  {\boxmaxdepth=0pt \global\setbox\br@@k = \vbox{\unvbox\br@@k}} % reset glue.
%  \ifdim\ht\br@@k=0pt
%      % box is apparently empty; breakup is finished.
%      % take no special precautions.
%  \else
    \unvcopy \br@@k %% previously added initial glue disappears automatically
                    %% at the beginning of the page
    \hrule height \topskip depth -\topskip % in case \br@@k contains no boxes.
    \kern \ht0 \kern \dp0 \unvbox\c@mpensate \eject
      % the new page length =
      %    (remaining page length after splitting)
      %  + (box 0, which was split off)
      %  - (page before splitting)
    \global \output={\do@breakup@three}
    \global \setbox\br@@k =
      \vbox{\vskip -1sp minus \dimen8 \unvbox\br@@k}
%  \fi
}

\def \do@breakup@three
{{\setbox0=\box255}% discard page
  \s@vestretches
      % length of \box\c@mpensate =
      % =    [page before splitting]
      %    - [ (remaining page length after splitting)
      %        + (box 0, which was split off) ]
      % = total length of missing glue and kern
  % \showbox\c@mpensate
  \global\setbox\b@ildnums=\vbox{\unvbox\c@mpensate \unvbox\b@ildnums}
  \do@breakup@four
}

\def\do@breakup@four
{\global\setbox\br@@k=\vbox{\unvbox\br@@k \break@up}
 \ifdim\ht\br@@k>0pt % then continue to try hard
   \unvcopy \br@@k
   \hrule height 0pt % to ensure that \pagedepth=0pt
   \eject
   \global \output={\do@breakup@}
 \else
   \restore@for@linenum.sty
   \finish@contents
 \fi
}

\def \finish@contents
  % We know that \ht\br@@k <= 0pt
{\ifdim \ht\br@@k<0pt
        % this looks a bit strange, but let's make the best out of it.
     \global \setbox \b@ildnums=\vbox{\kern \ht\br@@k \unvbox \b@ildnums}
 \fi
 \ifdim \dp\br@@k=0pt \else
     \global \setbox \b@ildnums=\vbox{\kern \dp\br@@k \unvbox \b@ildnums}
 \fi
%
 \global\setbox\br@@k=\vbox{}
 {\setbox0=\vbox{\unvbox \b@ildnums \make@counters}}
         % changes to \linecount are kept local to this group
 \dimen0=\ht\@outputbox  \advance\dimen0 by \dp \@outputbox
 \global\setbox\br@@k=\vbox to \dimen0
   {\boxmaxdepth 0pt \unvcopy\br@@k \kern 0pt}
 \ht\br@@k=0pt \dp\br@@k=0pt \wd\br@@k=0pt
 \modify@outputbox
}

\def\make@counters  % This is a trimmed-down version of \break@up.
              % The box in question consists only of non-zero \glue, \kern,
              % and \hboxes; the hboxes will be filled with line numbers.
 {\@nylefttrue
  \loop
    \ifdim\lastkern=0pt
    \ifdim\lastskip=0pt
       \setbox0=\lastbox
    \ifvoid0 \@nyleftfalse
    \else
       \setbox2=\align@linenum {\linenumfont \linenumber}
       \advance\linecount by -1
       \ht2=\ht0 \dp2=\dp0
       \global\setbox\br@@k=\vbox{ \box2 \unvbox\br@@k} \fi
    \else \skip0=\lastskip
       \global\setbox\br@@k=\vbox{\vskip\skip0 \unvbox\br@@k} \unskip \fi
    \else \dimen0=\lastkern
       \global\setbox\br@@k=\vbox{\kern\dimen0 \unvbox\br@@k} \unkern \fi
  \if@nyleft \repeat}

\def \modify@outputbox
{\iflinenumbersonright
   \dimen0=\wd\@outputbox
   \global \setbox\@outputbox \vbox {
      \advance\dimen0 by \linenumberseparation
      \moveright \dimen0 \box\br@@k
             \nointerlineskip \box\@outputbox}
   \wd\@outputbox=\dimen0
 \else
   \global \setbox\@outputbox \vbox {
      \moveleft \linenumberseparation \box\br@@k
             \nointerlineskip \box\@outputbox}
\fi}

\def \save@for@linenum.sty{%
   \global\setbox\save@outputbox=\box\@outputbox
   \global\save@vsize@forlinenum=\vsize
   % save the marks; they will be reestablished later.
   \global\setbox\save@marks=\vbox{
      \toks0=\expandafter{\topmark}  \mark{\the\toks0}\eject
      \toks0=\expandafter{\firstmark}\mark{\the\toks0}
      \toks0=\expandafter{\botmark}  \mark{\the\toks0}}
}

\def\restore@for@linenum.sty{%
 \global\setbox\@outputbox =\box\save@outputbox
 \global\vsize=\save@vsize@forlinenum
   % let's hope that there were no local assignments to \vsize
 \global \output={{\setbox0=\box255}% discard 1 page and then continue
                  \global \output={\modifiedoutput}%
 \aftergroup \relax
                 }
 \null % ensure that page is nonempty
 \unvbox\save@marks \null % restore marks
 \eject % trigger continuation of normal output routine.
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% FIND OUT WHICH (LA)TEX VERSION WE HAVE %%
%% AND SET \output ACCORDINGLY            %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begingroup
\edef \originaloutput{\the\output}
\global \output={\modifiedoutput}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The remainder of this file is concerned with sneaking    %
% the \ch@ngepagecontents command into the \output routine %
% after one column of text has been built,                 %
% and modifying the output routine so that the part before %
% or after this change point can be selectively skipped.   %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% This macro package does not use special penalty values to communicate with
% the output routine; instead it (temporarily) changes the output routine.
%
% For \LaTeX, the selective skipping of the output routine
% after calling \@makecol could also be achieved by generating the
% missing \fi and gobbling the remaining tokens of the output routine.
% We would only have to wrap \@makecol or \@opcol by some additional code.
% Maybe I will try this out when too many other \LaTeX versions come up.
% This method has a drawback: it may conflict with other packages
% which modify \@makecol, in particular the ftnright package,
% (unless linenum is used at the very end).
%
% Other \TeX\ versions, in particular plain \TeX, start with \shipout{...,
% which we cannot interrupt; so we have to change the sequence of
% operations (but hopefully not the logic), saving partial results
% in boxes, and shipping out only at the very end.

%\output {% LaTeX2e original, copied from latex.ltx
\def \templateoutput {{% extra "{" is automatically supplied by TeX
  \let \par \@@par
  \ifnum \outputpenalty<-\@M
    \@specialoutput
  \else
    \@makecol
    \@opcol
    \@startcolumn
    \@whilesw \if@fcolmade \fi
      {\@opcol\@startcolumn}%
  \fi
  \ifnum \outputpenalty>-\@Miv
    \ifdim \@colroom<1.5\baselineskip
      \ifdim \@colroom<\textheight
        \@latex@warning@no@line {Text page \thepage\space
                               contains only floats}%
        \@emptycol
%        \if@twocolumn         % these lines were removed between
%          \if@firstcolumn     % version 1997/06/01 and version 1997/12/01
%          \else
%            \@emptycol
%          \fi
%        \fi
      \else
        \global \vsize \@colroom
      \fi
    \else
      \global \vsize \@colroom
    \fi
  \else
    \global \vsize \maxdimen
  \fi
}}

\def \initialize@page@for@LaTeX
{\if@twocolumn
  \if@firstcolumn
    \resetlinecount\relax
    \linenumbersonrightfalse
  \else
    \linenumbersonrighttrue
  \fi
 \else
  \resetlinecount\relax
  \determinewhichside\relax
 \fi
}


\catcode`\|=0  %   "|" becomes new escape character
\catcode`\\=14 %   "\" becomes comment character
% This means we can skip over \def's without worrying about possibly
% undefined (and hence unbalanced) \if@fcolmade's or disallowed \newboxes.

|ifx |originaloutput|templateoutput
|catcode`|\=0

%\ProvidesPackage{linenum}[line numbering in the output file]
\ProvidesPackage{linenum}[2000/07/01 initial release]

% The additions are everything which starts in column 1.
%
\global\def\modifiedoutput {% LaTeX2e
  \let \par \@@par
  \ifnum \outputpenalty<-\@M
    \@specialoutput
  \else
\ifn@rmaloutputoperation
    \@makecol
\ch@ngepagecontents
\else
\global\n@rmaloutputoperationtrue
{\setbox0=\box255}% \box255 should be void after \@makecol
                  %% \global\setbox255=\box\savebox@xxlv
\fi
%
% ALTERNATIVE?
% \ifn@rmaloutputoperation \let\next\relax
% \else
%     \let\next=\gobbleuntil@closingbrace
%     \csname fi\endcsname
%       % generate the matching \fi for \ifnum \outputpenalty<-\@M
% \fi
% \aftergroup{\@end}
% \next
%
\ifn@rmaloutputoperation
    \@opcol
    \@startcolumn
    \@whilesw \if@fcolmade \fi
      {\@opcol\@startcolumn}%
\fi
  \fi
\ifn@rmaloutputoperation
  \ifnum \outputpenalty>-\@Miv
    \ifdim \@colroom<1.5\baselineskip
      \ifdim \@colroom<\textheight
        \@latex@warning@no@line {Text page \thepage\space
                               contains only floats}%
        \@emptycol
%        \if@twocolumn
%          \if@firstcolumn
%          \else
%            \@emptycol
%          \fi
%        \fi
      \else
        \global \vsize \@colroom
      \fi
    \else
      \global \vsize \@colroom
    \fi
  \else
    \global \vsize \maxdimen
  \fi
\fi
}

\global\let\initialize@page = \initialize@page@for@LaTeX

\fi\endgroup
\catcode`\@=\atcode % return to previous catcode
\endinput % skip the remainder of the file
|fi

|catcode`|\=0

%\output {% LaTeX 2.09 original, copied from latex.ltex
%\everyjob{\typeout{LaTeX Version 2.09 <25 March 1992>}}
\def \templateoutput {%
{\let\par\@@par
  \ifnum\outputpenalty <-\@M\@specialoutput\else
  \@makecol\@opcol\@floatplacement\@startcolumn
  \@whilesw\if@fcolmade \fi{\@opcol\@startcolumn}\fi
  \global\vsize\ifnum\outputpenalty >-\@Miv \@colroom
                  \else \maxdimen\fi}}

\catcode`\\=14
|ifx |originaloutput|templateoutput
|catcode`|\=0

\global\def\modifiedoutput % LaTeX 2.09
{\let\par\@@par
  \ifnum\outputpenalty <-\@M\@specialoutput\else
\ifn@rmaloutputoperation
  \@makecol
  \ch@ngepagecontents
\else
\global\n@rmaloutputoperationtrue
{\setbox0=\box255}% \box255 should be void after \@makecol
                  %\global\setbox255=\box\saveboxx
\fi
\ifn@rmaloutputoperation
  \@opcol\@floatplacement\@startcolumn
  \@whilesw\if@fcolmade \fi{\@opcol\@startcolumn}%
\fi
  \fi
\ifn@rmaloutputoperation
  \global\vsize\ifnum\outputpenalty >-\@Miv \@colroom
                  \else \maxdimen\fi
\fi
  }

\global\let\initialize@page = \initialize@page@for@LaTeX

\fi\endgroup
\catcode`\@=\atcode % return to previous catcode
\endinput
|fi

% FOR Plain TeX
%\output {% plain TeX original, copied from plain.tex
%\def\fmtname{plain}\def\fmtversion{3.0}
|def |templateoutput {{|plainoutput}}

|ifx |originaloutput|templateoutput % seems to be plain TeX
|catcode`|\=0
  \def \templateplainoutput
  {\shipout\vbox{\makeheadline\pagebody\makefootline}%
  \advancepageno
  \ifnum\outputpenalty>-\@MM \else\dosupereject\fi}

\catcode`\\=14
  |ifx |plainoutput|templateplainoutput % seems to be plain TeX
|catcode`|\=0

\global\def\modifiedoutput {% plain TeX
  % \def\plainoutput
\ifn@rmaloutputoperation
  \global \setbox\saveheadlinebox =\vbox{\makeheadline}
  \global \setbox\@outputbox=\pagebody
  \ch@ngepagecontents
\else
\global\n@rmaloutputoperationtrue
{\setbox0=\box255}% \box255 ought to be void after \pagebody
                  % (\pagebody seems to be the same as in plain TeX.)
\fi
\ifn@rmaloutputoperation
  \shipout\vbox{\unvbox\saveheadlinebox \box\@outputbox\makefootline}%
  \advancepageno
  \ifnum\outputpenalty>-\@MM \else\dosupereject\fi
\fi
  }

\newbox \@outputbox
\newbox \saveheadlinebox

   \catcode`\\=14
   |else
   |catcode`|\=0
 %unknown \output routine
 \errmessage{linenum.sty:
 I don't know the \output routine of this TeX format.^^J%
 This seems to be some version of plain TeX.^^J%
 This is format \fmtname, version \fmtversion.^^J%
 I know plain Tex, version 3.0 (and some LaTeX versions).^^J%
 No lines will be numbered%
 }

 \global\output=\originaloutput
      % \originaloutput already contains an extra pair of braces.
 |fi

\fi\endgroup
\catcode`\@=\atcode % return to previous catcode
\endinput % skip the remainder of the file
|fi

% FOR AMS-TeX amsppt.sty version 2.1a (1992)
%\output {% AMS-TeX original, copied from amsppt.sty
%\def\filename{amsppt.sty}\def\fileversion{2.1a} \def\filedate{22-JAN-1992}
|def |templateoutput {{|output@}}

|catcode`|\=14
|ifx |originaloutput|templateoutput % seems to be AMS-TeX
|catcode`|\=0

 \def \templateamsoutput
 {\shipout\vbox{%
 \iffirstpage@ \global\firstpage@false
  \pagebody \logo@ \makefootline%
 \else \ifrunheads@ \makeheadline \pagebody
       \else \pagebody \makefootline \fi
 \fi}%
 \advancepageno \ifnum\outputpenalty>-\@MM\else\dosupereject\fi}

\catcode`\\=14
  |ifx |output@|templateamsoutput % seems to be AMS-TeX
|catcode`|\=0

\global\def\modifiedoutput {% AMS-TeX, amsppt.sty
% \def\output@{% A variation of the original that ought to work equivalently
%    \iffirstpage@ \else \ifrunheads@
%      \global \setbox\saveheadlinebox =\vbox{\makeheadline}
%    \fi\fi
%    \global \setbox\@outputbox=\pagebody
%  % \ch@ngepagecontents
%    \shipout\vbox{%
%    \iffirstpage@ \global\firstpage@false
%        \box\@outputbox \logo@ \makefootline%
%    \else \ifrunheads@ \box\saveheadlinebox \box\@outputbox
%        \else \box\@outputbox \makefootline \fi
%    \fi}%
%    \advancepageno \ifnum\outputpenalty>-\@MM\else\dosupereject\fi}
\ifn@rmaloutputoperation
   \iffirstpage@ \else \ifrunheads@
     \global \setbox\saveheadlinebox =\vbox{\makeheadline}
   \fi\fi
   \global \setbox\@outputbox=\pagebody
   \ch@ngepagecontents
\else
\global\n@rmaloutputoperationtrue
{\setbox0=\box255}% \box255 ought to be void after \pagebody
\fi
\ifn@rmaloutputoperation
   \shipout\vbox{%
   \iffirstpage@ \global\firstpage@false
       \box\@outputbox \logo@ \makefootline%
   \else \ifrunheads@ \box\saveheadlinebox \box\@outputbox
       \else \box\@outputbox \makefootline \fi
   \fi}%
   \advancepageno \ifnum\outputpenalty>-\@MM\else\dosupereject\fi
\fi
   }

\newbox \@outputbox
\newbox \saveheadlinebox

   \catcode`\\=14
   |else
   |catcode`|\=0
 %unknown \output routine
 \errmessage{linenum.sty:
 I don't know the \output routine of this TeX format.^^J%
 This seems to be some version of AMS-TeX.^^J%
 This is format file \filename, version \fileversion,
    date \filedate.^^J%
 I know the AMS-Tex preprint style version 2.1a
 (and some LaTeX versions).^^J%
 No lines will be numbered%
 }

 \global\output=\originaloutput
      % \originaloutput already contains an extra pair of braces.
  |fi


|catcode`|\=0
\fi\endgroup
\catcode`\@=\atcode % return to previous catcode
\endinput % skip the remainder of the file
|fi

|catcode`|\=0

% unknown \output routine
 \errmessage{linenum.sty:
 I don't know the \output routine of this TeX format.^^J%
 I know plain Tex, version 3.0, AMS-TeX version 2.0,^^J%
 LaTeX, version 2.09, and LaTeX2e, version 1997/12/01.^^J%
 No lines will be numbered%
 }

 \global\output=\originaloutput
 \showthe\output %?%

|endgroup

\catcode`\@=\atcode % return to previous catcode

\endinput
