summaryrefslogtreecommitdiff
path: root/macros/plain/contrib/chbar/chbars.doc
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/plain/contrib/chbar/chbars.doc
Initial commit
Diffstat (limited to 'macros/plain/contrib/chbar/chbars.doc')
-rw-r--r--macros/plain/contrib/chbar/chbars.doc738
1 files changed, 738 insertions, 0 deletions
diff --git a/macros/plain/contrib/chbar/chbars.doc b/macros/plain/contrib/chbar/chbars.doc
new file mode 100644
index 0000000000..77610d2db3
--- /dev/null
+++ b/macros/plain/contrib/chbar/chbars.doc
@@ -0,0 +1,738 @@
+% 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...
+\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}