% This is CHBARS.STY                      as of Aug '92
% -*-LaTeX-*-
%---------------------------------------------------------
% (c) 1989 by J.Schrod. copy conditions see below.
 
%
% Macro package for creating changebars in LaTeX.
% MAKEPROG will ``weave'' this file into documentation that can be LaTeX'ed.
%
% documented in LaTeX (for Anne and Chris)
 
%
%       VERSION HISTORY  (MSCF -- most significant change first)
%
% DATE     PERSON  REMARK
% 92-08-15 -rlb    Use change bars in this document to mark major changes;
%                  so now you can see for yourself what they are.
% 92-07-28 -rlb    Run through a spelling checker before distributing.
% 92-01-15 -rlb    1) Keep \maxdeadcycles the same; just 
%                     don't count calls to output for change processing. 
%                  2) Allow setting the change bar width.
%                  3) Some typos and rewording of some of the comments.
%                  4) Allow setting change bar width. Interface copied
%                     from changebars.sty
%                  5) Allow changebars to be on the left as well as
%                     the right.
%                  6) localize some variables global definitions now
%                     start with cb_.
%                  7) Chain onto existing \output routine rather than assume
%                     \plainoutput.
%                  And miscellaneous minor hacks.
% 89-10-09 -js     converted to LaTeX (progltx)
% 89-09-25 -js     repaired \mark processing in horizontal mode
% 89-08    -js     first version (for EuroTeX89 in Karlsruhe)
%
 
% author's current address:
%
%       Detig$\,\cdot\,$Schrod \TeX{}sys
%       Joachim Schrod
%       Kranichweg 1
%
%       D-6074 R\"odermark-Urberach
%       FR Germany
%
%       Tel. (+6074) 1617
%       Bitnet: XITIJSCH@DDATHD21
 
 
 
% should be progtex...
%
%
% These TeX macros were documented with the documentation system
% MAKEPROG and automatically converted to the current form.
% If you have MAKEPROG available you may transform it back to
% the original input: Remove every occurence of three percents
% and one optional blank from the beginning of a line and remove
% every line which starts with four percents.  The following lex
% program will do this:
%
%    %%
%
%    ^%%%\ ?   ;
%    ^%%%%.*\n ;
%
% MAKEPROG may be obtained over the net from the Bitnet-Listserver
% LISTSERV@DHDURZ1 (filelist WEBWARE), from tuglib@science.utah.edu,
% or via ftp from june.cs.washington.edu.
%
%
\documentstyle[progltx,chbars,a4-9]{article}
 
 
%
% local macros
%
 
\let\mc=\small              % for names like GNU
 
\def\PS{{\sc PostScript}}
\def\DVI{{\tt DVI}}
\def\GNU{{\mc GNU}}
 
\chardef\bs=`\\
 
%
 
 
 
\begin{document}
\tableofcontents
 
\title{Changebars without {\tt \bs{}special}'s}
\author{\sc Joachim Schrod}
 
\newcommand{\changedate}{Aug 15, 1992}
\date{Revised last on \changedate\footnote{by {\tt rocky@watson.ibm.com}}\\ 
      Formatted on \today}
\maketitle
 
 
 
\begin{abstract}
It is common practice to use vertical bars in the margins of a
document to mark pieces of text which have changed since the last
version(s) of this document. Such vertical bars are usually
called {\em changebars}. It has often been said that it is
impossible to produce changebars with \TeX{} without the usage of
|\special| commands (driver directives), which extend the
primitives of \TeX{}. This paper presents a \TeX{} macro file
which implements changebars without such a usage. The macro file
is written for the usage with {\sc Plain}~\TeX{} but the implementation 
strategy can be used with \LaTeX{}, too with minor changes.
 
\end{abstract}
 
 
 
\chap Introduction.
 
Changebars are used to mark modified parts in existing documents.  For
the usage in \TeX{} documents, there exist only solutions that use
driver/printer features by the way of inserting |\special| commands in
the \TeX{} source, e.g.\ for \PS{} drivers.  This results in documents
that are no longer as freely interchangeable as the \DVI{} concept would
allow---device dependency is problematic especially for this application
that is useful for multi-authoring or standards development.
 
This macro package offers a pure \TeX{} solution.  Nevertheless, it has
its restrictions, too. The page break will no longer be optimal,
because there is no strechability or shrinkability of a page 
on top of the last
region of change marked. But this seems to be acceptable,
especially as the change bar feature often will be used for proof
reading and not in the final document. This restriction is the reason
why no change marks can be used on title pages or on similar
constructions. Changes in floating insertions (footnotes, figures) are
not handled. Multi-column formats such as a two-column layout
will not work. There is currently no support for nested changes.
 
The method for writing a change bar consists of three
parts: First, the output routine is signalled when the beginning
or end of a change bar setting command is encountered.
Next, the position of the changed area is found out
and fixed; the end-of-change command adds the last change bar
position, length and width to a list of all such positions,
lengths and widths of change bars that is accumulated for the current 
page. Finally, when
the output routine is triggered (either asynchronously in trying
to ship out the page or synchronously when discovering that the
end of a change bar lies off the page), this list of change
bars information is used create vertical rules which are added to the page.
If the change bar is not complete, a ``virtual'' end change is
inserted, and a ``virtual'' begin change is inserted at the
beginning of the next page.
 
\beginchange
The demonstrated solution was originally written in {\sc Plain}
\TeX{}, because it was
easier and could be presented better at the Euro\TeX89 conference in
Karlsruhe.  An adaptation to \LaTeX{} has been done too which
requires minor modifications to the \LaTeX's output routine.
\endchange
 
Some history. The routines were initially written by Joachim
Schrod. Around Jan.\ 1992, R.\ Bernstein added some of the features
coded in |changebars.sty| to combine the best features
of the two (and added a couple of his own). For example, the
ability to specify change bar widths, put the change bars either on the
right or left margin, specifiy the distance from the margin to the
change bar, and chain to on top of a pre-existing modified 
output routine. 
\beginchange
Initially, both the {\TeX} and the {\LaTeX}
versions were put into one file. However, due problems in
dealing with conditional definition of code, in particular
problems with an extra or omitted |\fi| in defining or not
|\ifr@ggedbottom|, the code was split into two. 
\endchange

The |changebars.sty| package
was written by Michael Fine and revised by Johannes Braams
and Neil Winton. One or two ideas from Thomas J.~Reid have been
used.
 
\chap GNU General Public License.
 
This program 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~2, or (at your
option) any later version.
 
This program is distributed in the hope that it will be useful, but
{\bf without any warranty\/}; without even the implied warranty of
{\bf merchantability\/} or {\bf 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 this program; if not, write to the Free Software Foundation,
Inc., 675~Mass Ave, Cambridge, MA~02139, USA.
 
 
\chap User Interface.
 
\begin{newsloppy}
A changed area is described by two marks, |\beginchange| and
|\endchange|. The |\beginchange| can take an optional argument,
the bar thickness, enclosed in brackets. That is, either of the
something like |\beginchange[0.4pt]|, or |\beginchange| is valid. 
In the latter case where no thickness dimension is specified, the value
of |\changebarwidth| is used. Therefore, by setting this you can
change the bar thickness used when none is given. Changing the bar
thickness might be useful in identifying different classes of changes.
 
Another pair of global values that can be set are the 
logical variables 
{\tt \bs chbar\-Right\-true} and {\tt \bs chbar\-Right\-false}. 
These specify whether
changebars should be on the right or left. Say, if one wanted to
have the changebars always appear on the outside margin, one could
change these accordingly on each page.
\end{newsloppy}
 
Finally |\BarDistance| is the amount of place between the text margin
and the change bars. This value should normally be positive. For
change bars on the right this value is added to |\hsize|, while
for change bars on the left this value is {\em subtracted\/} from
|\hoffset|.
 
\beginprog
\newdimen\changebarwidth \changebarwidth=1pt\relax
\newif\ifchbarRight \chbarRightfalse
\newdimen\BarDistance  \BarDistance=2cc
 
\endprog
 
\chap Utility Routines and Programming Conventions.
 
Before we get into the nitty gritty details, we give some common
macros. 

First, we declare some shorthands for category codes.  By
declaring the at sign~(`|@|') as well as the underscore~`(|_|)' as
letters we can use them in our macros. (I agree with D.~Knuth that
|\identifier_several_words_long| is more readable than
|\IdentifierSeveralWordsLong| and in every case better than |\p@@@s|.)
\beginchange
By defining the at sign to be in the letter class,
we can access {\sc Plain} \TeX's ``private''macros. By defining the
underscore to be in the letter class, we make our own private macros more 
readable. But since have to
restore these category codes at the end of this macro file, we store
\endchange
their former values in the control sequences |\atcode| and |\uscode|.
This method is better than to use a group because not all macros have to
be defined global this way.

All {\em global\/} definitions of the package are prefixed by
|cb_|. In this way, they can be easily determined. If other
packages do likewise, it is less likely that definition
names will clash between packages. (Unless the other package uses the
|cb_| prefix too, in which case there is a good chance that many
variable names will clash.)

The {\TeX}book recommends the 255 registers be used for scratch
space, so routines use this value when a spare register is
needed. (See for example |\cb_write_bar|.)

 
\beginprog
\chardef\letter=11
 
\chardef\atcode=\catcode`\@
\chardef\uscode=\catcode`\_
 
\catcode`\@=\letter
\catcode`\_=\letter
 
\endprog
 
\sect Now we are ready to code the top-level routine for indicating the 
beginning of a change. But first we display the banner and
version number associated with this package. If this package has
been loaded already we terminate.

Although one can specify a bar
thickness on the |\beginchange| macro, it is at the |\endchange|
where this thickness is recorded and put on a current list of
change bar entries for the current page. It seems more natural to 
specify the thickness at the beginning of the change rather than
the end. Therefore at the
|\beginchange| we merely save the value given or save the value of
|\changebarwidth| if no thickness was given.
|\cb_changebarwidth| is this saved value. Auxiliary routine
|\cb_xstart| is used to parse off the optional enclosing
brackets. (This weird name was taken from one used in |changebars.sty|.)
 
default value, that is the value when a width is not specified 
is |\changebarwidth|.
 
\beginprog
 
\@ifundefined{cb_xstart}{}{\endinput}
\typeout{Style option `change bars' -- version 1.1a}
 
\newdimen\cb_changebarwidth
 
\def\beginchange{\@ifnextchar [
                    {\cb_xstart}
                    {\beginchange_\changebarwidth}}
\def\cb_xstart[#1]{\beginchange_{#1}}
 
\endprog
 
\chap Triggering the Output Routine.
 
\beginchange
When a change bar is started or completed, we signal the output
routine in the ``usual'' way described below. Why bother the
output routine? The output routine is supposed to be thought of 
as an asynchronous process which has access to the page via the
contents of box register 255. In theory, if we did not perform
actions in the output routine, it might get triggered inadvertantly,
and the output routine might modify this box register on us in the
midst of our work. The information that needs to be recorded
is the position of the beginning and end of the lines containing a
marked change region.

\begin{newsloppy}
The macros |\beginchange| and |\endchange| signal the output
routine. Rather than merely calling the output routine directly,
these routines signal the output routine by setting a low page penalty, i.e.,
one which tells {\TeX} that this is a really good place to break
the page. Of course, we will modify the output routine so that it
doesn't really split the page when it has been called in this fashion.
Again, the reason we signal the output routine in what seems at
first a pretty odd way, is that this is the way it is supposed to
be done. If a low penalty were not set, some 
other action (if we weren't careful) might cause a penalty to be 
set and thus call the output routine (recursively).

So that we can distinguish our calls from others, |\beginchange|
and |\endchange| reserve a range of 
penalty values; he actual value is stored in |\cb_break_penalty|.
This range of values is below 
$-10\,000$, the nominal value for indicating that a page should
occur now. The penalty will be in the range $|\cb_penalty_group|
\cdot 100 - 99 \ldots |\cb_penalty_group| \cdot 100$.
The output routine then decides whether it has been called 
to start or end a change bar or neither.  This is done with the values
|\cb_penalty_begin| and |\cb_penalty_end| that are used as the
second-to-last digit of the change penalty.
\end{newsloppy}
 
The output routine also needs to determine whether
the beginning of change bar starts in horizontal or vertical mode
so it can figure out the exact placement for the beginning of the
bar line. In horizontal mode, the change bar does
not begin at the baseline of the actual text position, but on top of the
actual line.  This is marked in the last digit, an odd digit will be
used in horizontal mode.
 
Note that the values mentioned above are used as digits here that can be
concatenated.  If they are not followed by an other digit they should be
terminated by |\space| to stop {\TeX}'s look-ahead scanning for
digits when reading a number. 
\endchange
 
\beginprog
\def\cb_penalty_group{-101} \def\cb_penalty_begin{0}
\def\cb_penalty_end{1}
 
\endprog
 
 
\sect The calls to start or end a change bar, set an encoded page-break
penalty which includes an
indication of begin or end of a change bar. The variable
|\cb_break_penalty| is used to create such as special value.
The rest (|\cb_trigger_output|) is the same action
for both. The region just before the end of the changed region can be 
in horizontal mode and preceded by
glue that could cause a line break, thus including the following line to
the change area as well.  To avoid this unwanted behavior, the space is
saved in |\save_lastskip|, discarded in front of the mark and restored
afterwards. 
 
\beginprog
\newcount\cb_break_penalty
 
\def\beginchange_#1{%
   \cb_changebarwidth=#1
   \cb_break_penalty=\cb_penalty_group\cb_penalty_begin0
   \cb_trigger_output
   }
\def\endchange{{%
   \skipdef\save_lastskip=255%
   \ifhmode \save_lastskip=\lastskip \unskip \fi%
   \cb_break_penalty=\cb_penalty_group\cb_penalty_end0%
   \cb_trigger_output%
   \ifhmode \hskip\save_lastskip \fi%
   }}%\endchange
\endprog
 
 
\sect The next routine, |\cb_trigger_output|,
triggers calls to the output routine by setting the page-break 
penalty, |\penalty|. {\TeX} may discard an |\output| invocation at
the beginning of a page.  So we trigger the output routine twice, first
with a special penalty value that is 2~less than the correct value
(including the code for horizontal or vertical mode).  After the first
page break, it is asserted that the current list is empty.  The output
routine has to save the former page contents if necessary.
 
Next we set the penalty to the correct value.  The second page break does
the real work, restores the page contents and handles the split
insertions (footnotes, figures,~\dots). 
 
In horizontal mode |\spacefactor| must not be destroyed, so it is
saved and restored via local count register |\save_spacefactor|.
 
\beginprog
 
\def\cb_trigger_output{%
   \ifinner \errmessage{Change cannot be marked inside a box}%
   \else{%
     \countdef\save_spacefactor=255%
     \ifvmode   
       \let\do_in_vmode=\relax
       \advance \cb_break_penalty by -2
     \else 
       \save_spacefactor=\spacefactor
       \let\do_in_vmode=\vadjust
       \advance \cb_break_penalty by -3
     \fi
     \do_in_vmode{%
       \penalty\cb_break_penalty%        first call to \output
       \null
       \advance \cb_break_penalty by 2 
       \penalty\cb_break_penalty%        second call to \output
       }%
     \ifhmode \spacefactor=\save_spacefactor \fi
     }%
   \fi
   }% cb_trigger_output
\endprog
 
 
\sect Using the output routine for passing
information has it's difficulties.  One of the hard parts is 
\beginchange
handling page marks. These are token lists which are set by the
|\mark| command. They record information that can later 
be accessed by the output routine. The canonical example of such
a use of the |\mark| command is in creating 
\endchange
dictionary-style entry headings.

The output routine can access one of three 
token lists through three control sequences:  |\botmark| is the
last page mark given, |\topmark| is the |\botmark| of the previous
page, and |\firstmark| is the first page mark on the actual page or
|\topmark| if none was given.  Here ``page'' is used in the \TeX{}
sense, i.e.\ as the material which has been collected between two
|\output| invocations. Of course, the page marks must not be
destroyed---and that means they must be reinserted after each
special use of the output routine.
 
But we are lucky: A ``special use'' consists of two |\output|
invocations, so we can insert |\topmark| again as a page mark after
the first invocation where it will be the only page mark on that
\TeX{} page.  The second invocation will automatically transform this
page mark into the ``last page mark on the previous page,'' i.e.\ in
|\topmark|---that's what we need!  Furthermore |\firstmark| and
|\botmark| are saved in control sequences during the first invocation,
they will be inserted again, too.
 
There's one situation where this approach doesn't work: in front of
the first page mark. Here, |\topmark|, |\firstmark|, and |\botmark| expand
to an empty token list. If we save them then and insert their old
values we have inserted empty page marks. If other page marks follow
on the same ``real'' page, |\firstmark| will be empty instead of
expanding to the token list of the first page mark.  To prevent this
we must not save and restore page marks before the first |\mark| has
been added to the main vertical list.
 
Well, that can be controlled with a switch---but this switch must be
set very carefully.  If it is set immediately by the first |\mark|
this may be in horizontal mode and special output invocations can
occur above this page mark (i.e., there may be a |\beginchange| in the
same paragraph in front of the |\mark|).  Therefore the setting of the
switch must be delayed until the vertical position of the |\mark|
(precisely:  the position of the |\mark| in the current list) is
reached.  In horizontal mode this can be done with a |\vadjust| and
the output routine! Voil\`a, this is another command group for the
output routine with only one command.
 
\beginprog
\newif\if_cb_save_mark@  \_cb_save_mark@false
 
\def\mark_penalty_group{-102}
\endprog
 
 
\sect We will redefine |\mark| so that the first page mark either sets
the switch to true (in vertical mode all possible special page breaks
are already handled) or forces the |\output| routine to do this at an
appropriate place. In the last case we can use |\cb_trigger_output|
again. Afterwards we restore the original meaning of |\mark| again to
reduce the processing overhead (and the dead cycles).
 
This change of |\mark| has the consequence that the first |\mark| in a
document cannot be used anymore in horizontal mode inside a vertical
box that shall be split afterwards.  But this is only sensible if this
mark shall be used as |\splitfirstmark| because it will almost never
migrate to the outer list---really a rare case!
 
\beginprog
\let\cb_mark=\mark
\def\mark{%
   \ifvmode
     \ifinner \else  \global\_cb_save_mark@true \fi % split marks!
   \else  
     \cb_break_penalty=\mark_penalty_group00 % this will corrupt \vsplit
     \cb_trigger_output
   \fi
   \global\let\mark=\cb_mark
   \cb_mark
   }
\endprog
 
 
\sect 
\begin{newsloppy}
If the output routine is triggered with the mark penalty value,
it will call {\tt \bs cb\_save\discretionary{\_}{}{}page\_marks}.
\end{newsloppy}
 
\beginprog
\def\cb_save_page_marks{%            % this may be executed twice
   \unvbox\@cclv
   \global\_cb_save_mark@true
   }
\endprog
 
 
\sect To finish the treatment of page marks we can formulate the two
macros which are used at the first resp.\ second invocation of a
``special output,'' the principles have already been explained.
 
\beginprog
\def\cb_backup_page_marks{%
   \if_cb_save_mark@
      \mark{\topmark}%
      \xdef\cb_save_firstmark{\firstmark}%
      \xdef\cb_save_botmark{\botmark}%
   \fi
   }
 
\def\cb_restore_page_marks{%
   \if_cb_save_mark@
      \mark{\cb_save_firstmark}\mark{\cb_save_botmark}%
   \fi
   }
\endprog
 
 
 
 
 
\chap Positioning the Change Bars.
 
\begin{newsloppy}
Now we handle the positions of the bars.  
The dimension |\cb_bot_change_pos| will hold
the position of the end of the change bar, i.e.\ the distance between 
top of page the end of the changed area. The dimension
|\cb_top_change_pos| will hold the beginning of a changed
area; a value of |\maxdimen| indicates that no change is in effect.  If
a changed area is completed, it is appended to the list |\cb_bar_list| as
an element {\tt \bs cb\_bar(\bs cb\_top\_change\_pos,
\bs cb\_bot\_change\_pos, \bs changebar\-width)}.  This list contains all
changed areas within the current page so that bars can be written later
on.  A single bar will be produced by |\cb_write_bar|.
 
\noindent The definition of |\cb_bar| to |\relax| allows the concatenation
of new elements to |\cb_bar_list| with |\xdef|.
 
Local dimension register |\halfwidth| is used to center the change bar.
\end{newsloppy}
 
\beginprog
\newdimen\cb_bot_change_pos
\newdimen\cb_top_change_pos  \cb_top_change_pos=\maxdimen
 
\let\cb_bar_list=\empty
 
\let\cb_bar=\relax
\def\cb_write_bar(#1,#2,#3){{%
   \dimendef\halfwidth=255%
   \setbox0=\hbox{\vrule width #3 height -#1  depth #2}%
   \dp0=0pt \ht0=0pt \wd0=0pt%
   \halfwidth=#3 \divide\dimen255 by 2%
   \hskip -\halfwidth%
   \box0%
   \hskip \halfwidth%
   }}
\endprog
 
 
\sect If the output routine was activated by a |\outputpenalty| value
within the range of our reserved penalties, the change handling will
occur, otherwise standard plain output can be done. There may be
a lot of interaction between the routines which set change bars and
the output routine. These interactions should not be recorded in
|\deadcycles| or else \TeX{} will soon grumble. One might consider
doing the same for the|\mark_penalty_group|. But since this 
group is called once it shouldn't matter all that much.
 
One might also consider adding a counter like |\deadcycles| just
to count the change bar interactions as is done for the calls to
|\output|, and have {\TeX} grumble if there are ``too many'' of
them. For now we don't do this---all of this code is correct
anyway!
 
First we save away the old output routine in case the user had redefined
this beforehand.
 
\beginprog
\newtoks\cb_oldoutput
\edef\cb_oldoutput{\the\output}
 
\newcount\penalty_group
 
\output={%
   \boxmaxdepth=\maxdepth
   \penalty_group=\outputpenalty  \divide \penalty_group by 100
   \ifnum \penalty_group=\cb_penalty_group\space  
     {\countdef\new_deadcycles=255% don't count as a dead cycle
      \new_deadcycles=\deadcycles       
      \advance \new_deadcycles by -1
      \deadcycles=\new_deadcycles}
     \cb_change_handling
   \else
      \ifnum \penalty_group=\mark_penalty_group\space
         \cb_save_page_marks
      \else \cb_oldoutput
      \fi
   \fi
   }
\endprog
 
 
\sect As explained before, the change handling must differentiate
between the kind of the change command (beginning is indicated by
$|\cb_change_cmd|=0$, end by~1) and between the mode (horizontal indicated
by an odd |\cb_change_mode| value, vertical by an even).  A change mode
higher than one indicates that we are doing the first page break that
has to backup the page as far as it exists already and results in an
empty current list of page elements.
 
\beginprog
\newcount\cb_change_cmd
\newcount\cb_change_mode
 
\def\cb_change_handling{%
   \cb_change_cmd=-\outputpenalty                  % ==> absolute value
   \advance \cb_change_cmd by \cb_penalty_group00  % subtraction
   \cb_change_mode=\cb_change_cmd
   \divide \cb_change_cmd by 10                    % second-to-last digit
   \advance \cb_change_mode by -\number\cb_change_cmd0   % last digit
   \ifnum \cb_change_mode>1  \cb_backup_page
   \else
      \ifcase \cb_change_cmd  \cb_begin_change
      \or \cb_end_change
      \else \errmessage{Invalid changepenalty}%
      \fi
   \fi
   }
\endprog
 
 
\sect Processing a mark during the second trigger of the output routine
means restoring the page and storing the positions.  At the beginning,
the begin of the change is saved, at the end, we know the bar already
and put it into the bar list.  Then the positioning values are
reinitialized.
 
As within every output invocation, the box 255 must be unboxed.  As we
are here in the second invocation of the output routine the |\box255|
consists only of the empty |\vbox| we have inserted in
|\cb_trigger_output|.  We can therefore throw it away.
 
\beginprog
\def\cb_begin_change{%
   \cb_restore_page
   \setbox0=\box\@cclv
   \ifdim \cb_top_change_pos=\maxdimen
      \global\cb_top_change_pos=\cb_bot_change_pos  
      \global\cb_bot_change_pos=0pt
   \else \errmessage{Nested change bars are not supported}%
   \fi
   }
 
\def\cb_end_change{%
   \cb_restore_page
   \setbox0=\box\@cclv
   \ifdim \cb_top_change_pos=\maxdimen
      \errmessage{No change is in effect}%
   \else
      \xdef\cb_bar_list{\cb_bar_list 
         \cb_bar(\the\cb_top_change_pos,\the\cb_bot_change_pos,
                 \the\cb_changebarwidth)}
      \global\cb_top_change_pos=\maxdimen
      \global\cb_bot_change_pos=0pt
   \fi
   }
\endprog
 
 
\chap Handling the Page Contents.
 
We handle the part of the page that was collected up to now by putting
it into a box. This fixes the position of the change mark so that
|\cb_bot_change_pos| can be set and stored in |\cb_top_change_pos|
later on or as the lower end of a bar in |\cb_bar_list|.
 
In the first output invocation, we save the contents of the 
page in |\cb_save_page|. Before that, we store the size of the
box (which equals |\pagegoal|!)\ in |\cb_page_goal|.  If the unboxing
caused an increase of height (i.e.\ if $|\pagetotal|>|\pagegoal|$),
we eject the page up to the change mark.  Now we have to compute the
current position of our mark in |\cb_bot_change_pos|. It is fixed by the size
of the |\cb_save_page|, but if the change begins in horizontal mode we
must decrease it from the baseline position to the top of the last line.
Finally, we must save the values for the allowed insertions and change
them to the maximal value so that a rest that is split from an insertion
will be appended to the insertion box at the second invocation in every
case.
 
The |\vsize| is initialized to |\maxdimen|.  This allows to control
whether this first output invocation ocurred or if it was discarded.
For the same reason |\cb_bot_change_pos| is initialized to~0pt.
 
\beginprog
\newbox\cb_save_page
 
\newdimen\cb_page_goal
\newdimen\cb_save_vsize         \cb_save_vsize=\maxdimen
\newdimen\cb_save_dimen_topins
\newdimen\cb_save_dimen_footins
 
\def\cb_backup_page{%
   \global\cb_page_goal=\ht\@cclv
   \global\setbox\cb_save_page=\vbox{\unvbox\@cclv}%
   \ifdim \ht\cb_save_page>\cb_page_goal  
      \cb_eject_page_so_far \fi
   \cb_bot_change_pos=\ht\cb_save_page  
   \global\advance \cb_bot_change_pos by \dp\cb_save_page
   \ifnum \cb_change_cmd=\cb_penalty_begin\space
      \ifodd \cb_change_mode \higher_change_pos \fi
   \fi
   \global\cb_save_vsize=\vsize  \global\vsize=\maxdimen
   \global\cb_save_dimen_footins=\dimen\footins
   \global\dimen\footins=\maxdimen
   \cb_backup_page_marks
   }
 
\cb_bot_change_pos=0pt
\endprog
 
 
\sect To eject a page as far as it is we restore it from the
|\cb_save_page| back to box~255.  In horizontal mode and at a begin mark
the last line contains the mark and must not be output.  So we remove it
and the preceding glue from the stored rest, just leaving a single hbox
to be on top of the actual page (in |\cb_save_page|) now. Then normal
output can be done with box~255.
 
\beginprog
\def\cb_eject_page_so_far{%
   \begingroup
     \vbadness=20000 % don't complain about underfull vboxes
     \global\setbox\@cclv=\vbox to \cb_page_goal{%
         \unvbox\cb_save_page
         \ifnum \cb_change_cmd=\cb_penalty_begin\space
            \ifodd \cb_change_mode
               \global\setbox\cb_save_page=\lastbox
               \unskip
            \fi
         \fi
         }%
   \endgroup
   \cb_oldoutput
   }
\endprog
 
 
\sect 
\begin{newsloppy}
In horizontal mode and at a begin mark, we need the position of
the mark ({\tt \bs cb\_bot\discretionary{\_}{}{}change\_pos}) on the upper boundary of 
the last line in
|\cb_save_page|.  If there is just one line left from a recent eject, the
height is given by |\topskip| decreased by the height of this hbox.  If
the height of the box is larger than |\topskip| the skip will not be
inserted and the change position results to~0pt. Otherwise,
|\cb_save_page| is a vbox whose last hbox we delete temporarily using
box~0. Height and depth of the rest are the actual position on the page.
\end{newsloppy}
 
The double of the page we have constructed this way will immediately be
fed back to the garbage collector because it could have become
reasonably large.
 
\beginprog
\def\higher_change_pos{%
   \ifhbox \cb_save_page % rest of page from \cb_eject_page_so_far
      \cb_bot_change_pos=\topskip  
      \global\advance \cb_bot_change_pos by -\ht\cb_save_page
      \ifdim \cb_bot_change_pos<0pt  
         \global\cb_bot_change_pos=0pt  
      \fi
   \else
      \setbox0=\vbox{%
         \unvcopy\cb_save_page
         \setbox0=\lastbox % delete last line
         }%
      \cb_bot_change_pos=\ht0   
      \global\advance \cb_bot_change_pos by \dp0
      \setbox0=\box\voidb@x
   \fi
   }
\endprog
 
 
\sect To restore a page during the second output invocation, we first
restore the saved values, but only if they were really changed (this can
be discovered by the value of |\cb_save_vsize|).  Now the |\cb_save_page| is
appended to the current list as a box, which stops later usage of its
stretch- and shrinkability!  Then the collected insertions can be
inserted again. The page marks have to be inserted, too.
 
\beginprog
\def\cb_restore_page{%
   \ifdim \cb_save_vsize=\maxdimen
   \else  \global\vsize=\cb_save_vsize
     \global\dimen\footins=\cb_save_dimen_footins
     \global\cb_save_vsize=\maxdimen
     \cb_restore_page_marks
   \fi
   \box\cb_save_page % discards stretch- and shrinkability!
   \ifvoid \footins
   \else  \insert\footins{\floatingpenalty=20000 \unvbox\footins}%
   \fi
   }
\endprog
 
 
\sect {\em Please note, that there is still a problem with this concept 
of handling the output trigger:}
 
\bigskip
 
If the first output trigger is discarded because a page break has occurred 
just in front, footnote parts may be juggled around. I.e., if a 
footnote is split in three parts, the first part was just been shipped 
out, the second part is inserted back into the recent contributions by 
the output routine but {\em behind\/} the third part which is saved in 
the ``special place'' (according to the \TeX{}book, p.~125). A solution to
this problem might be to insert a |\do_change| again within the second
output trigger and finishing the treatment afterwards. Afterwards a 
full triggering process (two output invocations) is executed again and 
all insertion parts will be accessible in the insertion box.
 
By the way, the almost same problem appears in \LaTeX{}, too. Almost: in
\LaTeX{} this can happen every time because at the first output invocation
the |\dimen|-values of the footnote insertion is not increased. I leave 
the problem open to the reader\,\dots
 
 
 
 
 
\chap Writing the Stuff.
 
The positions of the bars which mark the changed areas are relative to
the top of the text, i.e.\ the height of the top insertion is not
included.  Therefore it is best to write them just after the top
insertions before the page text---but to do this we have to change the
\beginchange
either the {\sc Plain} {\TeX} macro |\pagecontents| or the {\LaTeX}
macro |\@makecol|.
\endchange
 
Below is the new definition, I have just rearranged it a little bit so
that it is more legible.  The new lines have been marked with
`|%%%%|'.  |\cb_insert_current_bar| inserts a last element in |\cb_bar_list|
if a changed area is not yet finished, afterwards all bars can be
written.
 
\beginprog
\def\@makecol{%
   \ifvoid\footins 
     \setbox\@outputbox
       \vbox{
          %\typeout{write all bars -- no footins}     
          \cb_insert_current_bar \cb_write_all_bars %%%%
          \unvbox\@cclv%
            }
   \else
      \setbox\@outputbox
        \vbox{\boxmaxdepth \maxdepth
          %\typeout{write all bars}     
          \cb_insert_current_bar \cb_write_all_bars %%%%
        \unvbox\@cclv\vskip\skip\footins\footnoterule\unvbox\footins%
             }
   \fi%
   \xdef\@freelist{\@freelist\@midlist}\gdef\@midlist{}\@combinefloats
   \setbox\@outputbox\vbox to\@colht{\boxmaxdepth\maxdepth
      \@texttop\dimen128=\dp\@outputbox\unvbox\@outputbox
      \vskip-\dimen128\@textbottom}%
   \global\maxdepth\@maxdepth}
\endprog
 
\sect If $|\cb_top_change_pos|=|\maxdimen|$ no change is active.  Otherwise
the current change reaches from the begin mark (|\cb_top_change_pos|) to
the end of the page, i.e.\ we insert a virtual end mark.  Because the
change continues on the next page we insert a virtual begin mark on the
top of the page, too.
 
\beginprog
\def\cb_insert_current_bar{%
   \ifdim \cb_top_change_pos=\maxdimen
   \else%
      \cb_bot_change_pos=\ht\@cclv
      \advance\cb_bot_change_pos by \dp\@cclv
      \xdef\cb_bar_list{\cb_bar_list 
                          \cb_bar(\the\cb_top_change_pos,
                                  \the\cb_bot_change_pos,
                                  \the\changebarwidth)}%
      \global\cb_top_change_pos=0pt
   \fi%
   }
\endprog
 
 
\sect Now we can write all bars---if they exist anyway.  It's rather
easy, we just have to define |\cb_bar| to |\cb_write_bar| and execute
|\cb_bar_list|.  The resulting output must not use vertical place.  We must
not forget to delete the list, or we will get the same bars on the next
page again.
 
\beginprog
\newbox\cb_bars
\newdimen\cb_offset
 
\def\cb_write_all_bars{%
   \ifx \cb_bar_list\empty
   \else                           % changes exist
      \ifchbarRight
        \cb_offset = \hsize
        \advance \cb_offset by \BarDistance
      \else
        \cb_offset = \hoffset  
        \advance \cb_offset by -\BarDistance
      \fi
      \setbox\cb_bars=\hbox to \cb_offset{%
         \hskip\cb_offset
         \vbox to 0pt{\offinterlineskip
            \let\cb_bar=\cb_write_bar  \cb_bar_list
            }%
         \hss
         }%
      \ht\cb_bars=0pt \dp\cb_bars=0pt \box\cb_bars
      \global\let\cb_bar_list=\empty
   \fi
   }
\endprog
 
 
\beginchange\chap Cleaning Up.\endchange

We finish the macro file so that garbage (e.g.\ of exchanges
between systems) can come afterwards.
 
\beginprog
\catcode`\@=\atcode
\catcode`\_=\uscode
 
\endinput
\endprog
 
 
 
\end{document}