The Changebar package ^{∗}

Michael Fine Distributed Systems Architecture Johannes Braams Kooienswater 62 2215 AK Zoetermeer The Netherlands

                                   JLBraams@cistron.nl

Printed March 5, 1999

Contents

1 Introduction 1

2 The user interface 2 2.1 The package options … 2 2.2 Macros defined by the

package . . . . . . . . . . 2 2.3 Changebar parameters . . 3

3 Deficiencies and bugs 3

4 The basic algorithm 4

5 The implementation 5

5.1 Declarations And Initializations . . . . . . . . . . 5 5.2 Option Processing …. 7 5.3 User Level Commands

And Parameters . . . . . 8 5.4 Macros for beginning and

ending bars . . . . . . . . 13 5.5 Macros for Making It

Work Across Page Breaks 15 5.6 Macros For Managing

The Stacks of Bar points . 17 5.7 Macros For Checking That The .aux File Is Stable . . . . . . . . . . . 19

5.8 Macros For Making It Work With Nested Floats/Footnotes . . . . . 20

Abstract This package implements a way to indicate modifications in a L^{A}TEXdocument by putting bars in the margin. It realizes this by making use of the \special commands supported by ‘dvi drivers’. Currently four different drivers are supported. More can easily be added.

1 Introduction

Important note Just as with cross references and labels, you usually need to process the document twice (and sometimes three times) to ensure that the changebars come out correctly. However, a warning will be given if another pass is required.

Features

• Changebars may be nested within each other. Each level of nesting can be given a different thickness bar.

∗This file has version number v3.3f, last revised 1998/03/17.

• Changebars may be nested in other environments including floats and footnotes.

• Changebars are applied to all the material within the “barred” environment, including floating bodies regardless of where the floats float to. An exeception to this are margin floats.

• Changebars may cross page boundaries.

• Changebars can appear on the outside of the columns of twocolumn text.

2 The user interface

This package has options to specify some details of its operation, and also defines several macros.

2.1 The package options

One set of package options^{1} specify the driver that will be used to print the document can be indicated. The driver may be one of:

• DVItoLN03

• DVItoPS

• DVIps

• emTEX

The drivers are represented in the normal typewriter method of typing these names, or by the same entirely in lower case.

The position of the bars may either be on the inner edge of the page (the left column on a recto or single-sided page, the right column of a verso page) by use of the innerbars package option (the default), or on the outer edge of the page by use of the the outerbars package option.

Another set of options give the user the posibility to specify that the bars should always come out on the left side of the text (leftbars) or on the right side of the text (rightbars).

The package also implements tracing for its own debugging. The package options traceon and traceoff control tracing.

2.2 Macros defined by the package

\cbstart All material between the macros \cbstart and \cbend is barred. The nesting of

\cbend multiple changebars is allowed. The macro \cbstart has an optional parameter that specifies the width of the bar. The syntax is \cbstart[⟨dimension⟩]. If no width is specified, the current value of the parameter \changebarwidth is used. Note that \cbstart and \cbend can be used anywhere but must be correctly nested with floats and footnotes. That is, one cannot have one end of the bar inside a floating insertion and the other outside, but that would be a meaningless thing to do anyhow.

changebar Apart from the macros \cbstart and \cbend a proper L^{A}TEX environment is defined. The advantage of using the environment whenever possible is that L^{A}TEX will do all the work of checking the correct nesting of different environments.

1For older documents the command \driver is available in the preamble of the document. It takes the options as defined for L^{A}TEX 2ε as argument.

\cbdelete The macro \cbdelete puts a square bar in the margin to indicate that some text was removed from the document. The macro has an optional argument to specify the width of the bar. When no argument is specified the current value of the parameter \deletebarwidth will be used.

\nochangebars The macro \nochangebars disables the changebar commands.

2.3 Changebar parameters

\changebarwidth The width of the changebars is controlled with the L^{A}TEX length parameter \changebarwidth. Its value can be changed with the \setlength command. Changing the value of \changebarwidth affects all subsequent changebars subject to the scoping rules of \setlength.

\deletebarwidth The width of the deletebars is controlled with the L^{A}TEX length parameter \deletebarwidth. Its value can be changed with the \setlength command. Changing the value of \changebarwidth affects all subsequent deletebars subject to the scoping rules of \setlength.

\changebarsep The separation between the text and the changebars is determined by the value

of the L^{A}TEX length parameter \changebarsep.

changebargrey When one of the supported dvi to PostScript translators is used the ‘blackness’ of the bars can be controlled. The L^{A}TEX counter changebargrey is used for this purpose. Its value can be changed with a command like:

    \setcounter{changebargrey}{85}

The value of the counter is a percentage, where the value 0 yields black bars, the value 100 yields white bars.

outerbars The changebars will be printed in the ‘inside’ margin of your document. This means they appear on the left side of the page. When twoside is in effect the bars will be printed on the right side of even pages. This behaviour can be changed by including the command \outerbarstrue in your document.

3 Deficiencies and bugs

• The macros blindly use specials points \cb@minpoint through \cb@maxpoint. If this conflicts with another set of macros, the results will be unpredictable. (What is really needed is a \newspecialpoint, analogous to \newcount etc. — it’s not provided because the use of the points is rather rare.)

• There is a limit of (\cb@maxpoint−\cb@minpoint+1)/4 bars per page (four special points per bar). Using more than this number yeilds unpredictable results (but that could be called a feature for a page with so many bars). This limitation could be increased if desired.

• Internal macro names are all of the form \cb@xxxx. No checking for conflicts with other macros is done.

• This implementation does not work with the multicolumn package.

• The algorithms may fail if a floating insertion is split over multiple pages. In L^{A}TEX floats are not split but footnotes may be. The simplest fix to this is to prevent footnotes from being split but this may make TEX very unhappy.

• The \cbend normally gets “attached” to the token after it rather than the one before it. This may lead to a longer bar than intended. For example, consider the sequence ‘word1 \cbend word2’. If there is a line break between ‘word1’ and ‘word2’ the bar will incorrectly be extended an extra line. This particular case can be fixed with the incantation ‘word1\cbend{} word2’.

4 The basic algorithm

The changebars are implemented using the \specials of various dvi interpreting programs like DVItoLN03 or DVIps. In essence, the start of a changebar defines two \special points in the margins at the current vertical position on the page. The end of a changebar defines another set of two points and then joins (using the “connect” \special) either the two points to the left or the two points to the right of the text, depending on the setting of innerbars, outerbars, leftbars, rightbars and/or twoside.

This works fine as long as the two points being connected lie on the same page. However, if they don’t, the bar must be artificially terminated at the page break and restarted at the top of the next page. The only way to do this (that I can think of) is to modify the output routine so that it checks if any bar is in progress when it ships out a page and, if so, adds the necessary artificial end and begin.

The obvious way to indicate to the output routine that a bar is in progress is to set a flag when the bar is begun and to unset this flag when the bar is ended. This works most of the time but, because of the asynchronous behavior of the output routine, errors occur if the bar begins or ends near a page break. To illustrate, consider the following scenario.

    blah blah blah          % page n
    blah blah blah
    \cbstart                % this does its thing and set the flag
    more blah
               <-------------- pagebreak occurs here
    more blah
    \cbend                  % does its thing and unsets flag
    blah blah

Since TEX processes ahead of the page break before invoking the output routine, it is possible that the \cbend is processed, and the flag unset, before the output routine is called. If this happens, special action is required to generate an artificial end and begin to be added to page n and n + 1 respectively, as it is not possible to use a flag to signal the output routine that a bar crosses a page break.

The method used by these macros is to create a stack of the beginning and end points of each bar in the document together with the page number corresponding to each point. Then, as a page is completed, a modified output routine checks the stack to determine if any bars begun on or before the current page are terminated on subsequent pages, and handles those bars appropriately. To build the stack, information about each changebar is written to the .aux file as bars are processed.

This information is re-read when the document is next processed. Thus, to ensure that changebars are correct, the document must be processed twice. Luckily, this is generally required for L^{A}TEX anyway.

This approach is sufficiently general to allow nested bars, bars in floating insertions, and bars around floating insertions. Bars inside floats and footnotes are handled in the same way as bars in regular text. Bars that encompass floats or footnotes are handled by creating an additional bar that floats with the floating material. Modifications to the appropriate L^{A}TEX macros check for this condition and add the extra bar.

5 The implementation

5.1 Declarations And Initializations

\cb@maxpoint The original version of changebar.sty only supported the DVItoLN03 specials. The LN03 printer has a maximum number of points that can be defined on a page. Also for some PostScript printers the number of points that can be defined can be limited by the amount of memory used. Therefore, the consecutive numbering of points has to be reset when the maximum is reached. This maximum can be adapted to the printers needs.

1 ⟨∗package⟩

 2 \def\cb@maxpoint{80}

\cb@minpoint When resetting the point number we need to know what to reset it to, this is minimum number is stored in \cb@minpoint. This number has to be ODD because the algorithm that decides whether a bar has to be continued on the next page depends on this.

 3 \def\cb@minpoint{1}

\cb@nil Sometimes a void value for a point has to be returned by one of the macros. For this purpose \cb@nil is used.

 4 \def\cb@nil{0}

\cb@nextpoint The number of the next special point is stored in the count register \cb@nextpoint and initially equal to \cb@minpoint.

 5 \newcount\cb@nextpoint
 6 \cb@nextpoint=\cb@minpoint

\cb@topleft \cb@topright \cb@botleft \cb@botright These for counters are used to identify the four special points that specify a changebar. The point defined by \cb@topleft is the one used to identify the changebar; the values of the orther points are derived from it.

 7 \newcount\cb@topleft
 8 \newcount\cb@topright
 9 \newcount\cb@botleft
10 \newcount\cb@botright

\cb@curbarwd The dimension register \cb@curbarwd is used to store the width of the current bar.

11 \newdimen\cb@curbarwd

\cb@page \cb@pagecount The macros need to keep track of the number of pages output so far. To this end the counter \cb@pagecount is used. When a pagenumber is read from the history stack, it is stored in the counter \cb@page. The counter cb@pagecount is initially 0; it gets incremented during the call to \@makebox (see section 5.5).

12 \newcount\cb@page
13 \newcount\cb@pagecount
14 \cb@pagecount=0

outerbars A switch is provided to control where the changebars will be printed.

15 \newif\ifouterbars

@cb@trace A switch to enable tracing of the actions of this package

16 \newif\if@cb@trace

\cb@positions This macro calculates the (horizontal) positions of the changebars.

\cb@odd@left \cb@odd@right \cb@even@left \cb@even@right Because the margins can differ for even and odd pages and because changebars are sometimes on different sides of the paper we need four dimensions to store the result.

17 \newdimen\cb@odd@left
18 \newdimen\cb@odd@right
19 \newdimen\cb@even@left
20 \newdimen\cb@even@right

Since the changebars are drawn with the PostScript command lineto and not as TEX-like rules the reference points lie on the center of the changebar, therefore the calculation has to add or subtract half of the width of the bar to keep \changebarsep whitespace between the bar and the body text.

First the position for odd pages is calculated. I

21 \def\cb@positions{%
22 \global\cb@odd@left=\hoffset
23 \global\cb@even@left\cb@odd@left
24 \global\advance\cb@odd@left by \oddsidemargin
25 \global\cb@odd@right\cb@odd@left
26 \global\advance\cb@odd@right by \textwidth
27 \global\advance\cb@odd@right by \changebarsep
28 \global\advance\cb@odd@right by 0.5\changebarwidth
29 \global\advance\cb@odd@left by -\changebarsep
30 \global\advance\cb@odd@left by -0.5\changebarwidth

On even sided pages we need to use \evensidemargin in the calculations.

31 \global\advance\cb@even@left by \evensidemargin
32 \global\cb@even@right\cb@even@left
33 \global\advance\cb@even@left by -\changebarsep
34 \global\advance\cb@even@left by -0.5\changebarwidth
35 \global\advance\cb@even@right by \textwidth
36 \global\advance\cb@even@right by \changebarsep
37 \global\advance\cb@even@right by 0.5\changebarwidth

38 }

\cb@removedim In PostScript code length specifications are without dimensions. Therefore we need a way to remove the letters ‘pt’ from the result of the operation \the\⟨dimen⟩. This can be done by defining a command that has a delimited argument like:

    \def\cb@removedim#1pt{#1}

We encounter one problem though, the category code of the letters ‘pt’ is 12 when produced as the output from \the\⟨dimen⟩. Thus the characters that delimit the argument of \cb@removedim also have to have category code 12. To keep the changes local the macro \cb@removedim is defined in a group.

39 {\catcode`\p=12\catcode`\t=12 \gdef\cb@removedim#1pt{#1}}

5.2 Option Processing

The user should select the specials that should be used by specifying the driver name as an option to the \usepackage call. Possible choices are:

• DVItoLN03

• DVItoPS

• DVIps

• emTEX

The ambition is that the driver names should be case-insensitive, but the following code doesn’t achieve this: it only permits the forms given above and their lower-case equivalents.

40 \DeclareOption{DVItoLN03}{\global\chardef\cb@driver@setup=0\relax}
41 \DeclareOption{dvitoln03}{\global\chardef\cb@driver@setup=0\relax}
42 \DeclareOption{DVItoPS}{\global\chardef\cb@driver@setup=1\relax}
43 \DeclareOption{dvitops}{\global\chardef\cb@driver@setup=1\relax}
44 \DeclareOption{DVIps}{\global\chardef\cb@driver@setup=2\relax}
45 \DeclareOption{dvips}{\global\chardef\cb@driver@setup=2\relax}
46 \DeclareOption{emTeX}{\global\chardef\cb@driver@setup=3\relax}
47 \DeclareOption{emtex}{\global\chardef\cb@driver@setup=3\relax}
48 \DeclareOption{textures}{\global\chardef\cb@driver@setup=4\relax}
49 \DeclareOption{Textures}{\global\chardef\cb@driver@setup=4\relax}

The new features of L^{A}TEX 2ε make it possible to implement the outerbars option.

50 \DeclareOption{outerbars}{\outerbarstrue}
51 \DeclareOption{innerbars}{\outerbarsfalse}

It is also possible to specify that the change bars should always be printed on either the left or the right side of the text. For this we have the options leftbars and rightbars. Specifying either of these options will overrule a possible twoside option at the document level.

52 \DeclareOption{leftbars}{%
53 \def\cb@positions{%
54  \global\cb@odd@left=\hoffset
55  \global\cb@even@left\cb@odd@left
56  \global\advance\cb@odd@left by \oddsidemargin
57  \global\advance\cb@odd@left by -\changebarsep
58  \global\advance\cb@odd@left by -0.5\changebarwidth
59  \global\advance\cb@even@left by \evensidemargin
60  \global\advance\cb@even@left by -\changebarsep

61  \global\advance\cb@even@left by -0.5\changebarwidth
62  \global\let\cb@odd@right\cb@odd@left
63  \global\let\cb@even@right\cb@even@left
64  }}
65 \DeclareOption{rightbars}{%
66 \def\cb@positions{%
67  \global\cb@odd@right=\hoffset
68  \global\cb@even@right\cb@odd@right
69  \global\advance\cb@odd@right by \oddsidemargin
70  \global\advance\cb@odd@right by \textwidth
71  \global\advance\cb@odd@right by \changebarsep
72  \global\advance\cb@odd@right by 0.5\changebarwidth
73  \global\advance\cb@even@right by \evensidemargin
74  \global\advance\cb@even@right by \textwidth
75  \global\advance\cb@even@right by \changebarsep
76  \global\advance\cb@even@right by 0.5\changebarwidth
77  \global\let\cb@odd@left\cb@odd@right
78  \global\let\cb@even@left\cb@even@right
79  }}

A set of options to control tracing.

80 \DeclareOption{traceon}{\@cb@tracetrue}
81 \DeclareOption{traceoff}{\@cb@tracefalse}

Signal an error if an unknown option was specified.

82 \DeclareOption*{\OptionNotUsed\PackageError
83  {Unrecognised option `\CurrentOption'}%
84  {known options are dvitoln03, dvitops, dvips
85  and emtex,\MessageBreak
86  outerbars, innerbars, leftbars and rightbars.}}

The default is to have the change bars on the left side of the text on odd pages.

87 \ExecuteOptions{innerbars,traceoff,dvips}
88 \ProcessOptions\relax

\cb@trace A macro that formats the tracing messages.

89 \newcommand\cb@trace[1]{%
90 \if@cb@trace
91  \GenericWarning
92  {(changebar)\@spaces\@spaces}%
93  {Package changebar: #1}%
94 \fi

95 }

5.3 User Level Commands And Parameters

\driver The user can select the specials that should be used by calling the command \driver{⟨drivername⟩}. Possible choices are:

• DVItoLN03

• DVItoPS

• DVIps

• emTEX

• TEXtures

This command can only be used in the preamble of the document.

The argument should be case-insensitive, so it is turned into a string containing all uppercase characters. To keep some definitions local, everything is done within a group.

 96 % \changes{v3.3e}{1998/02/24}{Added \cs{Textures}}
 97 \if@compatibility
 98 \def\driver#1{%
 99  \bgroup\edef\next{\def\noexpand\tempa{#1}}%
100  \uppercase\expandafter{\next}%
101  \def\LN{DVITOLN03}%
102  \def\DVItoPS{DVITOPS}%
103  \def\DVIPS{DVIPS}%
104  \def\emTeX{EMTEX}%
105  \def\Textures{TEXTURES}%

The choice has to be communicated to the macro \cb@setup@specials that will be called from within \document. For this puprose the control sequence \cb@driver@setup is used. It receives a numeric value using \chardef.

106  \global\chardef\cb@driver@setup=0\relax
107  \ifx\tempa\LN       \global\chardef\cb@driver@setup=0\fi
108  \ifx\tempa\DVItoPS  \global\chardef\cb@driver@setup=1\fi
109  \ifx\tempa\DVIPS    \global\chardef\cb@driver@setup=2\fi
110  \ifx\tempa\emTeX    \global\chardef\cb@driver@setup=3\fi
111  \ifx\tempa\Textures \global\chardef\cb@driver@setup=4\fi
112  \egroup}

We add \driver to \@preamblecmds, which is a list of commands to be used only in the preamble of a document.

113 {\def\do{\noexpand\do\noexpand}
114  \xdef\@preamblecmds{\@preamblecmds \do\driver}

115 }

116 \fi

\cb@setup@specials The macro \cb@setup@specials defines macros containing the driver specific \special macros. It will be called from within the \begin{document} command.

\cb@trace@defpoint When tracing is on write information about the point being defined to the log file.

117 \def\cb@trace@defpoint#1#2{%
118 \cb@trace{%
119  defining point \the#1 at position \the#2
120  \MessageBreak
121  cb@pagecount: \the\cb@pagecount; page \thepage}}

\cb@trace@connect When tracing is on write information about the points being connected to the log file.

122 \def\cb@trace@connect#1#2#3{%
123 \cb@trace{%
124  connecting points \the#1 and \the#2; barwidth: \the#3
125  \MessageBreak
126  cb@pagecount: \the\cb@pagecount; page \thepage}}

\cb@defpoint The macro \cb@defpoint is used to define one of the two points of a bar. It has two arguments, the number of the point and the distance from the left side of the paper; so its syntax is: \cb@defpoint{⟨number⟩}{⟨length⟩}.

\cb@resetpoints The macro \cb@resetpoints can be used to instruct the printer driver that it should send a corresponding instruction to the printer. This is really only used for the LN03 printer.

\cb@connect The macro \cb@connect is used to instruct the printer driver to connect two points with a bar. The syntax is \cb@connect{⟨number⟩}{⟨number⟩}{⟨length⟩} The two ⟨number⟩s indicate the two points to be connected; the ⟨length⟩ is the width of the bar.

127 \def\cb@setup@specials{%

The control sequence \cb@driver@setup expands to a number which indicates the driver that will be used. The original changebar.sty was written with only the the \special syntax of the program DVItoLN03 (actually one of its predecessors, ln03dvi). Therefore this syntax is defined first.

128 \ifcase\cb@driver@setup
129 \def\cb@defpoint##1##2{%
130  \special{ln03:defpoint \the##1(\the##2,)}%
131  \cb@trace@defpoint##1##2}
132 \def\cb@connect##1##2##3{%
133  \special{ln03:connect \the##1\space\space \the##2\space \the##3}%
134  \cb@trace@connect##1##2##3}
135 \def\cb@resetpoints{%
136  \special{ln03:resetpoints \cb@minpoint \space\cb@maxpoint}}

The first extension to the changebar option was for the \special syntax of the program DVItoPS by James Clark.

137 \or
138 \def\cb@defpoint##1##2{%
139  \special{dvitops: inline
140  \expandafter\cb@removedim\the##2\space 6.5536 mul\space
141  /CBarX\the##1\space exch def currentpoint exch pop
142  /CBarY\the##1\space exch def}%
143  \cb@trace@defpoint##1##2}
144 \def\cb@connect##1##2##3{%
145  \special{dvitops: inline
146  gsave \thechangebargrey\space 100 div setgray
147  \expandafter\cb@removedim\the##3\space 6.5536 mul\space
148  CBarX\the##1\space\space CBarY\the##1\space\space moveto
149  CBarX\the##2\space\space CBarY\the##2\space\space lineto
150  stroke grestore}%
151  \cb@trace@connect##1##2##3}
152 \let\cb@resetpoints\relax

Also the program DVIps by Thomas Rockicki is supported. The PostScript code is nearly the same as for DVItoPS, but the coordinate space has a different dimension. Also this code has been made resolution independent, whereas the code for DVItoPS might still be resolution dependent.

So far all the positions have been calculated in pt units. DVIps uses pixels internally, so we have to convert pts into pixels which of course is done by dividing by 72.27 (pts per inch) and multiplying by Resolution giving the resolution of the PostScript device in use as a PostScript variable.

153 \or
154 \def\cb@defpoint##1##2{%
155  \special{ps:
156  \expandafter\cb@removedim\the##2\space
157  Resolution\space mul\space 72.27\space div\space
158  /CBarX\the##1\space exch def currentpoint exch pop
159  /CBarY\the##1\space exch def}%
160  \cb@trace@defpoint##1##2}
161  \def\cb@connect##1##2##3{%
162  \special{ps:
163  gsave \thechangebargrey\space 100 div setgray
164  \expandafter\cb@removedim\the##3\space
165  Resolution\space mul\space 72.27\space div\space
166  setlinewidth
167  CBarX\the##1\space\space CBarY\the##1\space\space moveto
168  CBarX\the##2\space\space CBarY\the##2\space\space lineto
169  stroke grestore}%
170  \cb@trace@connect##1##2##3}
171  \let\cb@resetpoints\relax

The latest addition is for the drivers written by Eberhard Mattes. The \special syntax used here is supported since version 1.5 of his driver programs.

172 \or
173 \def\cb@defpoint##1##2{%
174  \special{em:point \the##1,\the##2}%
175  \cb@trace@defpoint##1##2}
176 \def\cb@connect##1##2##3{%
177  \special{em:line \the##1,\the##2,\the##3}%
178  \cb@trace@connect##1##2##3}
179 \let\cb@resetpoints\relax

The following definitions are validtested with TEXtures version 1.7.7, but will very likely also work with later releases of TEXtures.

The \cbdelete command seemed to create degenerate lines (i.e., lines of 0 length). PostScript will not render such lines unless the linecap is set to 1, (semicircular ends) in which case a filled circle is shown for such lines.

180 \or
181 \def\cb@defpoint##1##2{%
182  \special{rawpostscript
183  \expandafter\cb@removedim\the##2\space
184  /CBarX\the##1\space exch def currentpoint exch pop
185  /CBarY\the##1\space exch def}%
186  \if@cb@trace\cb@trace@defpoint##1##2\fi}
187  \def\cb@connect##1##2##3{%
188  \special{rawpostscript
189  gsave 1 setlinecap \thechangebargrey\space 100 div setgray
190  \expandafter\cb@removedim\the##3\space
191  setlinewidth
192  CBarX\the##1\space\space CBarY\the##1\space\space moveto
193  CBarX\the##2\space\space CBarY\the##2\space\space lineto
194  stroke grestore}%
195  \if@cb@trace\cb@trace@connect##1##2##3\fi}

196  \let\cb@resetpoints\relax

When code for other drivers should be added it can be inserted here. When someone makes a mistake and somehow selects an unknown driver a warning is issued and the macros are defined to be noops.

197 \else
198 \PackageWarning{Changebar}{changebars not supported in unknown setup}
199 \def\cb@defpoint##1##2{\cb@trace@defpoint##1##2}
200 \def\cb@connect##1##2##3{\cb@trace@connect##1##2##3}
201 \let\cb@resetpoints\relax
202 \fi

The last thing to do is to forget about \cb@setup@specials.

203 \global\let\cb@setup@specials\relax}

\cbstart The macro \cbstart starts a new changebar. It has an (optional) argument that will be used to determine the width of the bar. The default width is

\changebarwidth.
204 \newcommand\cbstart{\@ifnextchar [{\cb@start}%
205  {\cb@start[\changebarwidth]}}

\cbend The macro \cbend (surprisingly) ends a changebar. The macros \cbstart and \cbend can be used when the use of a proper L^{A}TEX environment is not possible.

206 \newcommand\cbend{\cb@end}

\cbdelete The macro \cbdelete inserts a ‘deletebar’ in the margin. It too has an optional argument to determine the width of the bar. The default width (and length) of it

are stored in \deletebarwidth.
207 \newcommand\cbdelete{\@ifnextchar [{\cb@delete}
208  {\cb@delete[\deletebarwidth]}}

\cb@delete Deletebars are implemented as a special ‘change bar’. The bar is started and immediately ended. It is as long as it is wide.

209 \def\cb@delete[#1]{\vbox to \z@{\vss\cb@start[#1]\vskip #1\cb@end}}
\changebar \endchangebar The macros \changebar and \endchangebar have the same function as \cbstart

and \cbend but they can be used as a L^{A}TEX environment to enforce correct nesting. They can not be used in the tabular and tabbing environments.

210 \newenvironment{changebar}%
211  {\@ifnextchar [{\cb@start}%
212  {\cb@start[\changebarwidth]}}%
213  {\cb@end}

\nochangebars To disable changebars altogether without having to remove them from the document the macro \nochangebars is provided. It makes noops from a couple of internal macros.

214 \newcommand\nochangebars{%
215 \def\cb@start[##1]{}%
216 \def\cb@delete[##1]{}%
217 \let\cb@end\relax}

\changebarwidth The default width of the changebars is stored in the dimension register \changebarwidth.

218 \newlength{\changebarwidth}
219 \setlength{\changebarwidth}{2pt}

\deletebarwidth The default width of the deletebars is stored in the dimension register \deletebarwidth.

220 \newlength{\deletebarwidth}
221 \setlength{\deletebarwidth}{4pt}

\changebarsep The default separation between all bars and the text is stored in the dimen register

\changebarsep.
222 \newlength{\changebarsep}
223 \setlength{\changebarsep}{30pt}

changebargrey When the document is printed using one of the PostScript drivers the bars do not need to be black; with PostScript is possible to have grey bars. The pecentage of greyness of the bar is stored in the count register \changebargrey. It can have values between 0 (meaning white) and 100 (meaning black).

224 \newcounter{changebargrey}
225 \setcounter{changebargrey}{65}

5.4 Macros for beginning and ending bars

\cb@start This macro starts a change bar. It assigns a new value to the current point and advances the counter for the next point to be assigned. It pushes this info onto

\cb@currentstack and then sets the point by calling \cb@setBeginPoints with

the point number. Finally, it writes the .aux file.

226 \def\cb@start[#1]{%
227 \cb@topleft=\cb@nextpoint

Store the width of the current bar in \cb@curbarwd.

228 \cb@curbarwd#1\relax
229 \cb@push\cb@currentstack
230 \ifvmode
231  \cb@setBeginPoints
232 \else
233 \vbox to \z@{%

When we are in horizontal mode we jump up a line to set the starting point of the changebar.

234  \vskip -\ht\strutbox
235  \cb@setBeginPoints
236  \vskip \ht\strutbox}\fi
237 \cb@advancePoint}
\cb@advancePoint The macro \cb@advancePoint advances the count register \cb@nextpoint. When

the maximum number is reached, the numbering is reset.

238 \def\cb@advancePoint{%
239 \global\advance\cb@nextpoint by 4\relax
240 \ifnum\cb@nextpoint>\cb@maxpoint
241  \global\cb@nextpoint=\cb@minpoint\relax
242 \fi}

\cb@end This macro ends a changebar. It pops the current point and nesting level off \cb@currentstack and sets the end point by calling \cb@setEndPoints with the parameter corresponding to the beginning point number. It writes the .aux file and joins the points.

243 \def\cb@end{%
244 \cb@pop\cb@currentstack
245 \ifnum\cb@topleft=\cb@nil
246  \PackageWarning{Changebar}%
247  {Badly nested changebars; Expect erroneous results}%
248 \else
249  \cb@setEndPoints
250 \fi
251 \ignorespaces}

\cb@setBeginPoints The macro \cb@setBeginPoints assigns a position to the top left and top ight points. It determines wether the point is on an even or an odd page and uses the right dimension to position the point. Keep in mind that the value of \cb@pagecount is one less than the value of \c@page unless the latter has been reset by the user.

The top left point is used to write an entry on the .aux file to create the history stack on the next run.

252 \def\cb@setBeginPoints{%
253 \cb@topright=\cb@topleft\advance\cb@topright by\@ne
254 \ifodd\cb@pagecount
255  \cb@defpoint\cb@topleft\cb@even@left
256  \cb@defpoint\cb@topright\cb@even@right
257 \else
258  \cb@defpoint\cb@topleft\cb@odd@left
259  \cb@defpoint\cb@topright\cb@odd@right
260 \fi
261 \cb@writeAux\cb@topleft

262 }

\cb@setEndPoints The macro \cb@setEndPoints assigns positions to the bottom points for a change bar. It then instructs the driver to connect two points with a bar. The macro assumes that the width of the bar is stored in \cb@curbarwd.

The bottom right point is used to write to the .aux file to signal the end of the current bar on the history stack.

263 \def\cb@setEndPoints{%
264 \cb@topright=\cb@topleft\advance\cb@topright by\@ne
265 \cb@botleft=\cb@topleft\advance\cb@botleft by\tw@
266 \cb@botright=\cb@topleft\advance\cb@botright by\thr@@
267 \ifodd\cb@pagecount
268  \cb@defpoint\cb@botleft\cb@even@left
269  \cb@defpoint\cb@botright\cb@even@right
270 \else
271  \cb@defpoint\cb@botleft\cb@odd@left
272  \cb@defpoint\cb@botright\cb@odd@right
273 \fi
274 \cb@writeAux\cb@botright
275 \edef\cb@leftbar{%
276  \noexpand\cb@connect{\cb@topleft}{\cb@botleft}{\cb@curbarwd}}%
277 \edef\cb@rightbar{%
278  \noexpand\cb@connect{\cb@topright}{\cb@botright}{\cb@curbarwd}}%
279 \if@twocolumn
280  \if@firstcolumn\cb@leftbar\else\cb@rightbar\fi
281 \fi

282 \ifouterbars
283  \ifodd\cb@pagecount\cb@leftbar\else\cb@rightbar\fi
284 \else
285  \ifodd\cb@pagecount\cb@rightbar\else\cb@leftbar\fi
286 \fi

287 }%

\cb@writeAux The macro \cb@writeAux writes information about a changebar point to the auxiliary file. The number of the point, the pagenumber and the width of the bar are written out as arguments to \cb@barpoint. This latter macro will be expanded when the auxiliary file is read in. The macro assumes that the width of bar is

stored in \cb@curbarwd.

The code is only executed when auxiliary files are enabled, as there’s no sense in trying to write to an unopened file.

288 \def\cb@writeAux#1{%
289 \if@filesw
290  \begingroup
291  \edef\point{\the#1}%
292  \edef\level{\the\cb@curbarwd}%
293  \let\the=0%
294  \edef\cb@temp{\write\@auxout
295  {\string\cb@barpoint{\point}{\the\cb@pagecount}{\level}}}%
296  \cb@temp
297  \endgroup
298 \fi}

5.5 Macros for Making It Work Across Page Breaks

\@makecol \@vtryfc Modifies the L^{A}TEX macros to end the changebars spanning the current page break (if any) and restart them on the next page. Does the following: It resets special points for this page. Adds begin bars to top of box255. The bars carried over from the previous page, and hence to be restarted on this page, have been saved on the stack \cb@beginstack. This stack is used to define new starting points for the change bars, which are added to the top of box \@cclv. Then the stack \cb@endstack is built and processed by \cb@processActive. Finaly the original

\@makecol (saved as \cb@makecol) is executed.
299 \let\cb@makecol\@makecol
300 \def\@makecol{%
301 \let\cb@writeAux\@gobble
302 \setbox\@cclv \vbox{%
303  \cb@resetpoints
304  \cb@startSpanBars
305  \unvbox\@cclv
306  \boxmaxdepth\maxdepth}%
307 \global\advance\cb@pagecount by\@ne
308 \cb@buildstack\cb@processActive
309 \cb@makecol}

When L^{A}TEX makes a page with only floats it doesn’t use \@makecol; instead it calls \@vtryfc, so we have to modify this macro as well.

310 \let\cb@vtryfc\@vtryfc
311 \def\@vtryfc{%

312 \let\cb@writeAux\@gobble
313 \setbox\@outputbox \vbox{%
314  \cb@resetpoints
315  \cb@startSpanBars
316  \unvbox\@cclv
317  \boxmaxdepth\maxdepth}%
318 \global\advance\cb@pagecount by \@ne
319 \cb@buildstack\cb@processActive
320 \cb@vtryfc}

\cb@processActive Processes each element on span stack. Each element represents a bar that crosses the page break. There could be more than one if bars are nested. Works as folows:

     pop top element of span stack
     if point null (i.e., stack empty) then done
     else
       do an end bar on box255
       save start for new bar at top of next page in \cb@startSaves
       push active point back onto history stack (need to reprocess
          on next page).

321 \def\cb@processActive{%
322 \cb@pop\cb@endstack
323 \ifnum\cb@topleft=\cb@nil
324 \else
325  \setbox\@cclv\vbox{%
326  \unvbox\@cclv
327  \boxmaxdepth\maxdepth
328  \advance\cb@pagecount by -1\relax
329  \cb@setEndPoints}%
330  \cb@push\cb@historystack
331  \cb@push\cb@beginstack
332  \expandafter\cb@processActive
333 \fi}

\cb@startSpanBars This macro defines new points for each bar that was pushed on the \cb@beginstack. The bars are pushed on \cb@currentstack. Afterwards \cb@beginstack is empty.

334 \def\cb@startSpanBars{%
335 \cb@pop\cb@beginstack
336 \ifnum\cb@topleft=\cb@nil
337 \else
338  \cb@setBeginPoints
339  \cb@push\cb@currentstack
340  \expandafter\cb@startSpanBars
341 \fi

342 }

\cb@buildstack \cb@endstack Initialize the stack with open bars and starts populating it.

343 \def\cb@buildstack{%
344 \cb@initstack\cb@endstack
345 \cb@pushNextActive}

\cb@pushNextActive This macro pops the top element off the history stack (\cb@historystack). If the top left point is on a future page, it is pushed back onto the history stack and processing stops. If the point on the current or a previous page and it has an odd number, the point is pushed on the stack with end points \cb@endstack); if the point has an even number, it is popped off the stack with end points since the bar to which it belongs has terminated on the current page.

346 \def\cb@pushNextActive{%
347 \cb@pop\cb@historystack
348 \ifnum\cb@topleft=\cb@nil
349 \else
350  \ifnum\cb@page>\cb@pagecount
351  \cb@push\cb@historystack
352  \else
353  \ifodd\cb@topleft
354  \cb@push\cb@endstack
355  \else
356  \cb@pop\cb@endstack
357  \fi
358  \expandafter\expandafter\expandafter\cb@pushNextActive
359  \fi
360 \fi}

5.6 Macros For Managing The Stacks of Bar points

The macros make use of four stacks corresponding to \special defpoints. Each

stack takes the form <element> ...  <element>

Each element is of the form xxxnyyypzzzl where xxx is the number of the special point, yyy is the page on which this point is set, and zzz is the dimension used when connecting this point.

The stack \cb@historystack is built from the log information and initially lists all the points. As pages are processed, points are popped off the stack and discarded.

The stack \cb@endstack and \cb@beginstack are tow temporary stacks used by the output routine and contain the stack with definitions for of all bars crossing the current pagebreak (there may be more than one with nested bars). They are built by popping elements off the history stack.

The stack \cb@currentstack contains all the current bars. A \cb@start pushes an element onto this stack. A \cb@end pops the top element off the stack and uses the info to terminate the bar.

For performance and memory reasons, the history stack, which can be very long, is special cased and a file is used to store this stack rather than an internal macro. The “external” interface to this stack is identical to what is described above. However, when the history stack is popped, a line from the file is first read and appended to the macro \cb@historystack.

\cb@initstack A macro to (globally) initialize a stack.

361 \def\cb@initstack#1{\xdef#1{}}

\cb@historystack \cb@write \cb@read We need to initialise a stack to store the entries read from the external history file.

362 \cb@initstack\cb@historystack

We also need to allocate a read and a write stream for the history file.

363 \newwrite\cb@write
364 \newread\cb@read

And we open the history file for writing (which is done when the .aux file is read in).

365 \immediate\openout\cb@write=\jobname.cb\relax

\cb@endstack \cb@beginstack Allocate two stacks for the bars that span the current page break.

366 \cb@initstack\cb@endstack
367 \cb@initstack\cb@beginstack

\cb@currentstack And we allocate an extra stack that is needed to implement nesting without having to rely on TEX’s grouping mechanism.

368 \cb@initstack\cb@currentstack

\cb@pop This pops the top element off the named stack and puts the point value into \cb@topleft, the page value into \cb@page and the bar width into \cb@curbarwd. If the stack is empty, returns a void value (\cb@nil) in \cb@topleft and sets

\cb@page=0.
369 \def\cb@pop#1{%
370 \ifx #1\cb@historystack
371  \ifeof\cb@read
372  \else
373  {\endlinechar=-1\read\cb@read to\@temp
374  \xdef\cb@historystack{\cb@historystack\@temp}%

375 }%

376  \fi
377 \fi
378 \ifx#1\@empty
379  \cb@topleft=\cb@nil\cb@page=0\relax
380 \else
381  \expandafter\cb@carcdr#1e#1%
382 \fi}

\cb@carcdr Used to ‘decode’ a stack entry.

383 \def\cb@carcdr#1n#2p#3l#4e#5{%
384 \cb@topleft=#1\cb@page=#2\relax\cb@curbarwd=#3\xdef#5{#4}}
\cb@push Pushes \cb@topleft, \cb@page and \cb@curbarwd onto the top of the named

stack.

385 \def\cb@push#1{%
386 \xdef#1{\the\cb@topleft n\the\cb@page p\the\cb@curbarwd l#1}}

\cb@barpoint For populating the history file. Writes one line to .cb file which is equivalent to one ⟨element⟩ described above.

387 \def\cb@barpoint#1#2#3{\immediate\write\cb@write{#1n#2p#3l}}

5.7 Macros For Checking That The .aux File Is Stable

\AtBeginDocument While reading the .aux-file L^{A}TEX has created the history stack in a separate file. We need to close that file and open it for reading. Also the ‘initialisation’ of the \special commands has to take place. While we are modifying the macro we also include the computation of the possible positions of the changebars

For these actions we need to add to the L^{A}TEX begin-document hook.

388 \AtBeginDocument{%
389 \cb@setup@specials
390 \cb@positions
391 \immediate\closeout\cb@write
392 \immediate\openin\cb@read=\jobname.cb}

\AtEndDocument Does a \clearpage to flush rest of document. (Note that I believe there is contention in this area: are there in fact situations in which the end-document hooks need to be called before the final \clearpage? — the documentation of L^{A}TEX itself implies that there are.) Then closes .cb file and reopens it for checking. Inits history stack (to be read from file). Lets \cb@barpoint=\cb@checkHistory for checking.

393 \AtEndDocument{%
394 \clearpage
395 \cb@initstack\cb@historystack
396 \immediate\closein\cb@read
397 \immediate\openin\cb@read=\jobname.cb%
398 \let\cb@barpoint=\cb@checkHistory}

\cb@checkHistory Pops the top of the history stack (\jobname.cb) and checks to see if the point and page numbers are the same as the arguments #1 and #2 respectively. Prints a warning message if different.

399 \def\cb@checkHistory#1#2#3{%
400 \cb@pop\cb@historystack
401 \ifnum #1=\cb@topleft\relax
402  \ifnum #2=\cb@page\relax

Both page and point numbers are equal; do nothing,

403  \else

but generate a warning when page numbers don’t mach, or

404  \cb@error
405  \fi
406 \else

when point numbers don’t mach.

407  \cb@error
408 \fi}

\cb@error When a mismatch between the changebar information in the auxiliary file and the history stack is detected a warning is issued; further checking is disabled.

409 \def\cb@error{%
410 \PackageWarning{Changebar}%
411  {Changebar info has changed.\MessageBreak
412  Rerun to get the bars right}
413 \gdef\cb@checkHistory##1##2##3{}%
414 \let\cb@barpoint=\cb@checkHistory}

5.8 Macros For Making It Work With Nested Floats/Footnotes

\end@float This is a replacement for the L^{A}TEX-macro of the same name. All it does is check to see if changebars are active and, if so, it puts changebars around the box containing the float. Then it calls the original L^{A}TEX \end@float.

415 \let\cb@endfloat=\end@float
416 \def\end@float{%
417 \cb@pop\cb@currentstack
418 \ifnum\cb@topleft=\cb@nil
419 \else
420  \cb@push\cb@currentstack
421  \global\cb@curbarwd=\cb@curbarwd
422  \egroup
423  \global\setbox\@currbox=%
424  \vbox\bgroup\cb@start[\cb@curbarwd]\unvbox\@currbox\cb@end
425 \fi
426 \cb@endfloat}

This only works if this new version of \end@float is really used. With L^{A}TEX2.09 the documentstyles used to contain:

     \let\endfigure\end@float

In that case this binding has to be repeated after the redefinition of \end@float. However, the L^{A}TEX 2ε class files use \newenvironment to define the figure and table environments. In that case there is no need to rebind \endfigure.

\@footnotetext Replacement for the L^{A}TEX macro of the same name. Simply checks to see if changebars are active and if so wraps the macro argument (i.e., the footnote) in changebars.

427 \let\cb@footnote=\@footnotetext
428 \long\def\@footnotetext#1{%
429 \cb@pop\cb@currentstack
430 \ifnum\cb@topleft=\cb@nil
431  \cb@footnote{#1}%
432 \else
433  \cb@push\cb@currentstack
434  \edef\cb@temp{\the\cb@curbarwd}%
435  \cb@footnote{\cb@start[\cb@temp]#1\cb@end}%
436 \fi}

\@mpfootnotetext Replacement for the L^{A}TEX macro of the same name. Same thing as \@footnotetext.

437 \let\cb@mpfootnote=\@mpfootnotetext
438 \long\def\@mpfootnotetext#1{%
439 \cb@pop\cb@currentstack
440 \ifnum\cb@topleft=\cb@nil
441  \cb@mpfootnote{#1}%
442 \else
443  \cb@push\cb@currentstack
444  \edef\cb@temp{\the\cb@curbarwd}%
445  \cb@mpfootnote{\cb@start[\cb@temp]#1\cb@end}%
446 \fi}

447 ⟨/package⟩