% This is CHBARS.DOC			  as of 09 Oct 89
%---------------------------------------------------------
% (c) 1989 by J.Schrod. copy conditions see below.

%
% Macro package for creating changebars in Plain TeX
% MAKEPROG is needed
%
% documented in LaTeX (for Anne and Chris)

%
%	VERSION HISTORY  (MSCF -- most significant change first)
%
% DATE	   PERSON  REMARK
% 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,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}


%%% \title{Changebars without {\tt \bs{}special}'s}
%%% \author{\sc Joachim Schrod}

%%% \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 Plain~\TeX{} but the implementation 
%%% strategy can be used with \LaTeX{}, too.
%%% \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 no strechability or shrinkability on a page on top of the last
%%% mark of a change is supported.	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 titlepages or for similar
%%% constructions.	Changes in floating insertions (footnotes, figures) are
%%% not discovered.

%%% The demonstrated solution is written in Plain \TeX{}, because it was
%%% easier and could be presented better at the Euro\TeX89 conference in
%%% Karlsruhe.  An adaption to \LaTeX{} is possible, but would require
%%% modifications to the \LaTeX{} kernel, i.e.\ the output routine and the
%%% layout parameters of the standard styles.


%%% \sect 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~1, 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,
%%% If you have not received a copy of the \GNU{} General Public License
%%% along with this program, write to the Free Software Foundation,
%%% Inc., 675~Mass Ave, Cambridge, MA~02139, USA.


%%% \sect A changed area is described by two marks, |\beginchange| and
%%% |\endchange|.  The method for writing a change bar consists of three
%%% parts:	First, it will be indicated to the output routine that a change
%%% has occured.  Next, the position of the changed area will be found out
%%% and fixed.  A list of all changed areas is built, that can at last be
%%% marked by the output routine using vertical rules at the right margin.

%%% But before we start 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|.)
%%% With the at sign we can use the ``private'' Plain macros and with the
%%% underscore we can make our own macros more readable.  But as we have to
%%% restore these category codes at the end of this macro file we store
%%% 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.

%%% \beginprog
\chardef\letter=11

\chardef\atcode=\catcode`\@
\chardef\uscode=\catcode`\_

\catcode`\@=\letter
\catcode`\_=\letter
%%% \endprog




%%% \chap Triggering the Output Routine.

%%% \begin{sloppypar}
%%% First, the output routine must know that changes occured.  This is done
%%% by the macros |\beginchange| and |\endchange| that append a reserved
%%% penalty value |\break_penalty| to the current list that is below
%%% $-10\,000$.  The penalty will be in the range $|\change_penalty_group|
%%% \cdot 100 - 99 \ldots |\change_penalty_group| \cdot 100$.
%%% For the output it must be differentiated if the mark indicates
%%% begin or end of the changed area.  This is done with the values
%%% |\change_penalty_begin| and |\change_penalty_end| that are used as the
%%% second-to-last digit of the change penalty.
%%% \end{sloppypar}

%%% It must also be differentiated between the beginning of a mark being in
%%% horizontal or vertical mode.  In horizontal mode, the change bar must
%%% 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 the look-ahead for digits.

%%% These interactions with the output routine adds a lot of dead cycles; we
%%% must therefore increase |\maxdeadcycles| to prevent \TeX{} from grumbling.

%%% \beginprog
\def\change_penalty_group{-101}
\def\change_penalty_begin{0}
\def\change_penalty_end{1}

\maxdeadcycles=100
%%% \endprog


%%% \sect The marks set the change penalty value (including the indication
%%% of begin or end of mark).  The rest (|\trigger_output|) is the same action
%%% for both. An end change mark in horizontal mode can be preceeded by
%%% glue that could cause a line break, thus including the following line to
%%% the change area as well.  To avoid this unwanted behaviour, the space is
%%% saved in |\save_space|, discarded in front of the mark and restored
%%% afterwards.

%%% \beginprog
\newcount\break_penalty
\newskip\save_space

\def\beginchange{%
   \break_penalty=\change_penalty_group\change_penalty_begin0
   \trigger_output
   }
\def\endchange{%
   \ifhmode  \save_space=\lastskip \unskip  \fi
   \break_penalty=\change_penalty_group\change_penalty_end0
   \trigger_output
   \ifhmode  \hskip\save_space	\fi
   }
%%% \endprog


%%% \sect In |\trigger_output| the real output trigger is done.  We must consider
%%% that an |\output|-invocation by our |\break_penalty| can be discarded 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.

%%% Now 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.

%%% \beginprog
\newcount\save_space_factor

\def\trigger_output{%
   \ifinner  \errmessage{Change cannot be marked inside a box}%
   \else
      \ifvmode	\let\do_in_vmode=\relax
	 \advance \break_penalty by -2
      \else  \save_space_factor=\spacefactor
	 \let\do_in_vmode=\vadjust
	 \advance \break_penalty by -3
      \fi
      \do_in_vmode{%
	 \penalty\break_penalty
	 \null
	 \advance \break_penalty by 2  \penalty\break_penalty
	 }%
      \ifhmode	\spacefactor\save_space_factor	\fi
   \fi
   }
%%% \endprog


%%% \sect The usage of the output routine as an information passing system
%%% has always it's difficulties.  One of the real hard parts is the
%%% handling of the page marks, special token lists that are handled by
%%% \TeX{}. These token lists provide informations about text on a page,
%%% they are usually used to create head lines etc.  The user may access
%%% these token lists with 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 have luck: 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 |\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@save_mark@  \@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 |\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\@@mark=\mark
\def\mark{%
   \ifvmode
      \ifinner \else  \global\@save_mark@true \fi % split marks!
   \else  \break_penalty=\mark_penalty_group00   % this will corrupt \vsplit
      \trigger_output
   \fi
   \global\let\mark=\@@mark
   \@@mark
   }
%%% \endprog


%%% \sect 
%%% \begin{sloppypar}
%%% If the output routine is triggered with the mark penalty value
%%% it will call |\start_saving_page_marks|.
%%% \end{sloppypar}

%%% \beginprog
\def\start_saving_page_marks{%	     % this may be executed twice
   \unvbox255
   \global\@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\backup_page_marks{%
   \if@save_mark@
      \mark{\topmark}%
      \xdef\save_firstmark{\firstmark}%
      \xdef\save_botmark{\botmark}%
   \fi
   }

\def\restore_page_marks{%
   \if@save_mark@
      \mark{\save_firstmark}\mark{\save_botmark}%
   \fi
   }
%%% \endprog





%%% \chap Positioning the Change Marks.

%%% Now we must handle the positions of the bars.  |\change_pos| will hold
%%% the position of the actual mark, i.e.\ the distance between top of page
%%% and actual mark.  |\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 |\bar_list| as
%%% an element |\bar(\top_change_pos,\change_pos)|.  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 |\write_bar|.

%%% \noindent The definition of |\bar| to |\relax| allows the concatenation
%%% of new elements to |\bar_list| with |\xdef|.

%%% \beginprog
\newdimen\change_pos
\newdimen\top_change_pos  \top_change_pos=\maxdimen

\let\bar_list=\empty

\let\bar=\relax
\def\write_bar(#1,#2){%
   \setbox0=\hbox{\vrule height -#1  depth #2}%
   \dp0=0pt  \ht0=0pt
   \box0
   }
%%% \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.

%%% \beginprog
\newcount\penalty_group

\output={%
   \boxmaxdepth=\maxdepth
   \penalty_group=\outputpenalty  \divide \penalty_group by 100
   \ifnum \penalty_group=\change_penalty_group\space  \change_handling
   \else
      \ifnum \penalty_group=\mark_penalty_group\space
	 \start_saving_page_marks
      \else \plainoutput
      \fi
   \fi
   }
%%% \endprog


%%% \sect As explained before, the change handling must differentiate
%%% between the kind of the change command (beginning is indicated by
%%% $|\change_cmd|=0$, end by~1) and between the mode (horizontal indicated
%%% by an odd |\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\change_cmd
\newcount\change_mode

\def\change_handling{%
   \change_cmd=-\outputpenalty			   % ==> absolute value
   \advance \change_cmd by \change_penalty_group00 % subtraction
   \change_mode=\change_cmd
   \divide \change_cmd by 10			   % second-to-last digit
   \advance \change_mode by -\number\change_cmd0   % last digit
   \ifnum \change_mode>1  \backup_page
   \else
      \ifcase \change_cmd  \begin_change
      \or \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
%%% |\trigger_output|.  We can therefore throw it away.

%%% \beginprog
\def\begin_change{%
   \restore_page
   \setbox0=\box255
   \ifdim \top_change_pos=\maxdimen
      \global\top_change_pos=\change_pos  \global\change_pos=0pt
   \else \errmessage{Nested change bars are not supported}%
   \fi
   }

\def\end_change{%
   \restore_page
   \setbox0=\box255
   \ifdim \top_change_pos=\maxdimen
      \errmessage{No change is in effect}%
   \else
      \xdef\bar_list{\bar_list \bar(\the\top_change_pos,\the\change_pos)}%
      \global\top_change_pos=\maxdimen	\global\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
%%% |\change_pos| can be set and stored later on in |\top_change_pos| or as
%%% the lower end of a bar in |\bar_list|.

%%% To save the page contents in the first output invocation, we have to
%%% save the page in |\save_page|.	Before that, we store the size of the
%%% box (which equals |\pagegoal|!)\ in |\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 |\change_pos|.	It is fixed by the size
%%% of the |\save_page|, but in case of a begin mark 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 |\change_pos| is initialized to~0pt.

%%% \beginprog
\newbox\save_page

\newdimen\page_goal
\newdimen\save_vsize		\save_vsize=\maxdimen
\newdimen\save_dimen_topins
\newdimen\save_dimen_footins

\def\backup_page{%
   \global\page_goal=\ht255
   \global\setbox\save_page=\vbox{\unvbox255}%
   \ifdim \ht\save_page>\page_goal  \eject_page_so_far	\fi
   \change_pos=\ht\save_page  \global\advance \change_pos by \dp\save_page
   \ifnum \change_cmd=\change_penalty_begin\space
      \ifodd \change_mode  \higher_change_pos  \fi
   \fi
   \global\save_vsize=\vsize  \global\vsize=\maxdimen
   \global\save_dimen_topins=\dimen\topins  \global\dimen\topins=\maxdimen
   \global\save_dimen_footins=\dimen\footins
	 \global\dimen\footins=\maxdimen
   \backup_page_marks
   }

\change_pos=0pt
%%% \endprog


%%% \sect To eject a page as far as it is we restore it from the
%%% |\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 |\save_page|) now.	Then normal
%%% output can be done with box~255.

%%% \beginprog
\def\eject_page_so_far{%
   \begingroup
      \vbadness=20000 % don't complain about underfull vboxes
      \global\setbox255=\vbox to \page_goal{%
	 \unvbox\save_page
	 \ifnum \change_cmd=\change_penalty_begin\space
	    \ifodd \change_mode
	       \global\setbox\save_page=\lastbox
	       \unskip
	    \fi
	 \fi
	 }%
   \endgroup
   \plainoutput
   }
%%% \endprog


%%% \sect 
%%% \begin{sloppypar}
%%% In horizontal mode and at a begin mark, we need the position of
%%% the mark (|\change_pos|) on the upper boundary of the last line in
%%% |\save_page|.  If there is just one line left from a recent eject, the
%%% height is given by the 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,
%%% |\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{sloppypar}

%%% 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 \save_page % rest of page from \eject_page_so_far
      \change_pos=\topskip  \global\advance \change_pos by -\ht\save_page
      \ifdim \change_pos<0pt  \global\change_pos=0pt  \fi
   \else
      \setbox0=\vbox{%
	 \unvcopy\save_page
	 \setbox0=\lastbox % delete last line
	 }%
      \change_pos=\ht0	\global\advance \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 |\save_vsize|).  Now the |\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\restore_page{%
   \ifdim \save_vsize=\maxdimen
   \else  \global\vsize=\save_vsize
      \global\dimen\topins=\save_dimen_topins
      \global\dimen\footins=\save_dimen_footins
      \global\save_vsize=\maxdimen
      \restore_page_marks
   \fi
   \box\save_page % discards stretch- and shrinkability!
   \ifvoid \topins
   \else  \insert\topins{\floatingpenalty=0 \unvbox\topins}%
   \fi
   \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 occured 
%%% 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 treatmend afterwards. Afterwards a 
%%% full triggering process (two output invocations) is executed again and 
%%% alle 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
%%% Plain macro |\pagecontents|.

%%% Below is the new definition, I have just rearranged it a little bit so
%%% that it is more legible.  The line I have inserted is marked with
%%% `|%%%%|'.  |\insert_current_bar| inserts a last element in |\bar_list|
%%% if a changed area is not yet finished, afterwards all bars can be
%%% written.

%%% \beginprog
\def\pagecontents{%
   \ifvoid \topins  \else \unvbox\topins \fi
   \insert_current_bar	\write_all_bars 		 %%%%
   \dimen@=\dp\@cclv \unvbox\@cclv % open up \box255
   \ifvoid \footins
   \else % footnote info is present
      \vskip\skip\footins
      \footnoterule
      \unvbox\footins
   \fi
   \ifr@ggedbottom \kern-\dimen@ \vfil \fi
   }
%%% \endprog


%%% \sect If $|\top_change_pos|=|\maxdimen|$ no change is active.  Otherwise
%%% the current change reaches from the begin mark (|\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\insert_current_bar{%
   \ifdim \top_change_pos=\maxdimen
   \else
      \change_pos=\ht255  \advance\change_pos by \dp255
      \xdef\bar_list{\bar_list \bar(\the\top_change_pos,\the\change_pos)}%
      \global\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 |\bar| to |\write_bar| and execute
%%% |\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.

%%% \noindent |\BarDistance| is the amount of place between the text margin
%%% and the change bars.

%%% \beginprog
\newbox\@bars
\newdimen\BarDistance  \BarDistance=2cc

\def\write_all_bars{%
   \ifx \bar_list\empty
   \else			       % changes exist
      \setbox\@bars=\hbox to \hsize{%
	 \hskip\hsize  \hskip\BarDistance
	 \vbox to 0pt{\offinterlineskip
	    \let\bar=\write_bar  \bar_list
	    }%
	 \hss
	 }%
      \ht\@bars=0pt \dp\@bars=0pt \box\@bars
      \global\let\bar_list=\empty
   \fi
   }
%%% \endprog


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