diff options
Diffstat (limited to 'macros/latex209/contrib/chbars/chbars.sty')
-rw-r--r-- | macros/latex209/contrib/chbars/chbars.sty | 1000 |
1 files changed, 1000 insertions, 0 deletions
diff --git a/macros/latex209/contrib/chbars/chbars.sty b/macros/latex209/contrib/chbars/chbars.sty new file mode 100644 index 0000000000..245f9e5459 --- /dev/null +++ b/macros/latex209/contrib/chbars/chbars.sty @@ -0,0 +1,1000 @@ +% 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} + |