[comp.text] TeXhax Digest V89 #4

TeXhax@cs.washington.edu (TeXhax Digest) (01/17/89)

TeXhax Digest    Monday, January 16, 1989  Volume 89 : Issue 4

Moderators: Tiina Modisett and Pierre MacKay

%%% The TeXhax digest is brought to you as a service of the TeX Users Group %%%
%%%       in cooperation with the UnixTeX distribution service at the       %%%
%%%                      University of Washington                           %%%

Today's Topics:         
%%% This issue of the TeXhax Digest is devoted to Michael Fine's changebar
%%% macros.

 Improved Changebar Macros




---------------------------------------------------------------------------

Date: Thu, 5 Jan 89 11:42:33 PST
From: fine%fine.DEC@decwrl.dec.com (Michael Fine)
Subject: Improved Changebar Macros
Keywords: Changebars

In TeXHax 88-111 Theo de Klerk posted a STY file for changebars in
LaTeX.  Below is an improved version with new features, performance
improvements, and several bug fixes.
 
The original requestor (Mark Eichin, TeXHaX 88-108) asked for macros
that are "portable" meaning that they should not use \specials.  I
believe this is impossible without extensions to TeX.
 
Nevertheless, Paul Koning has writen Postscript procedures to
implement the LN03 specials that changebar.sty uses (and I would
assert that Postscript is portable).  This code is included below
(with Paul's permission) and has been used with Stephen Bechtolsheim's
dvi2ps.
 
	Michael Fine
 
 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%	CHANGEBAR STYLE
%
%
%	Written by:
%		Michael Fine
%		Distributed Systems Architecture.
%		October, 1986.
%
%
%
% USAGE:
% 
%    \cbstart[dimension]
%    \cbend
%	All material between the two macros is barred.  Nested
%	changebars are allowed.  The optional parameter specifies the
%	width of the bar.  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, you 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.
%
%     \cbdelete[dimension]
%	A square rule is put on the page at the position of the
%	changebars.  This is useful fo indicating deleted text.
% 
%     \setlength{\changebarwidth}{dimension}
%     \setlength{\deletebarwidth}{dimention}
% 	Sets the default width of the bar and of the size of the
%	delete rule. 
%
%     \reversechangebars
%       Causes bars to appear on opposite side of page from which they
%       have been appearing on.  Cannot be used while a bar is in
%       progress.
% 
%     \setlength{\changebarsep}{dimension}
% 	Sets the separation between the bar and the left margin of the
% 	text.  Does not take effect until you call \reversechangebars
%       except when used in the preamble.
%
%     \nochangebars
%	Disables the changebar commands.
% 
% 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.
%
%
% PARAMETERS:
%
%    \changebarwidth
%	A LaTeX length parameter that gives the bar width.  It can be
%	changed with the \setlength command.  Changing its value affects
%	all subsequent changebars subject to the scoping rules of
%	\setlength.
%
%    \deletebarwidth
%	Ditto for the size of the square delete rule.
%
%    \changebarsep
%	A LaTeX length parameter that gives the separation of the bar
%	from the left margin of the text.  It can be set with the
%	\setlength command.
%
%
%
% FEATURES:
% 
%	Changebars may be nested within each other.  Each level of
%	nesting can be given a different thickness bar.
% 
% 	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 is margin floats.
% 
% 	Changebars may cross page boundaries.
% 
% 
% 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.)
% 
%	There is a limit of (\cb@maxpoint-\cb@minpoint+1)/4 bars per
%	page (four special points per bar).  Using more than this number
%	yields 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 has not been designed for two column
%	printing.
% 
% 	The algorithms may fail if a floating insertion is split over
% 	multiple pages.  In LaTeX 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'.
% 
% 
% BASIC ALGORITHM
%
%	The changebars are implemented using the \specials of the DVI to
%	LN3 translator.  In essence, the start of changebar defines a
%	\special point in the margin at the current vertical position on
%	the page.  The end of a changebar defines another point and then
%	joins the two using the "connect" \special.
%
%	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 scenerio.
%
%	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 process 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, the necessary artificial end and begin
%	will not be added to page n and n+1, respectively.  Thus, it is
%	not possible to use a flag to signal the output routine that a
%	bar crosses a page break, and some other mechanism is required.
%	
%	The method used with these macros is to create a list 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 list 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 list, 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, but this is required for LaTeX anyway.
%
%	This apprach 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 LaTeX
%	macros check for this condition and add the extra bar.
%
%
%

--------------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%	User Level Commands And Parameters
%
%
%
% \cbstart	\cbend
%
% Start and end a changebar and save state on \cb@currentlist.  Width of
% new bar is determined by adding \changebarwidth to width of current
% bar.  Does not invoke a LaTeX environment.
%
\def\cbstart{\@ifnextchar [{\cb@xstart}{\cb@start\changebarwidth}}
	\def\cb@xstart[#1]{\cb@start{#1}}
 
\def\cbend{\cb@end}
 
%
% \cbdelete
%
% Start and end a square bar of the specified width.  Use width
% \deletebarwidth if none specified.
%
\def\cbdelete{\@ifnextchar [{\cb@delete}{\cb@delete[\deletebarwidth]}}
\def\cb@delete[#1]{\vbox to 0pt{\vss\cb@start{#1}\vskip #1%
			\cb@end}}
 
 
%
% \begin{changebar}  \end{changebar}
%
% Identical to \cbstart and \cbend but invokes a LaTeX environment to
% enforce correct nesting.  Cannot be used in tabular and tabbing
% environments.  Not yet properly implemented.
%
%\newenvironment{changebar}{\@bsphack\cbstart\@esphack}{\@bsphack
%	\cbend\@esphack}
 
 
%
% \nochangebars
%
% Disables the changebar commands.
%
\def\nochangebars{\let\cb@end\relax \def\cb@start##1{}}
 
%
% \changebarwidth \deletebarwidth
%
% LaTeX length parameters that give the width of bars and delete
% squares, respectively.
%
\newlength{\changebarwidth}
\setlength{\changebarwidth}{2pt}
 
\newlength{\deletebarwidth}
\setlength{\deletebarwidth}{4pt}
 
% 
% \reversechangebars
%
% Switches the side of the page on which the bars appear.  It also
% computes the position of the bar and stores in dimension variables
% \cb@dimodd and \cb@dimeven.  Called by modified \document at end of
% preable.
%
\newdimen\cb@dimodd         % position of special point for odd side pages
\newdimen\cb@dimeven	    % ditto for even side pages
\newif\ifcb@side	    % switch for current side of page for bars
 
\def\reversechangebars{\global\cb@dimodd=\hoffset
    \global\cb@dimeven=\hoffset
    \global\advance\cb@dimodd by \oddsidemargin
    \global\advance\cb@dimeven by \evensidemargin
    \global\ifcb@side
      \global\advance\cb@dimodd by -\changebarsep
      \global\advance\cb@dimeven by \textwidth
      \global\advance\cb@dimeven by \changebarsep
      \global\cb@sidefalse
    \else
      \global\advance\cb@dimeven by -\changebarsep
      \global\advance\cb@dimodd by \textwidth
      \global\advance\cb@dimodd by \changebarsep
      \global\cb@sidetrue\fi}    
 
 
%
% \changebarsep
%
% A LaTeX length parameter that gives the separation of the bar from the
% left margin of the text.
%
\newlength{\changebarsep}
\setlength{\changebarsep}{30pt}
 
 

--------------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%	Declarations And Initializations
%
%
 
%
% A version message
%
\typeout{Changebar Style <October 20, 1988>}
 
\let\cb@ig=\ignorespaces %useful abreviation
 
\def\cb@maxpoint{80}		% max value of used special points
\def\cb@minpoint{1}		% ditto for min;
				% MUST BE ODD ****
\def\cb@nil{0}			% a void value for points
 
\newcount\cb@nextpoint		% next value of special point to use
\newcount\cb@currentpoint	% current value in use
\cb@nextpoint=\cb@minpoint	% intially = \cb@minpoint
 
\newcount\cb@page		% count for page value from hist list
\newcount\cb@pagecount		% our internal count of pages output
\cb@pagecount=0			% initially 0 due to timing of increment
 
 

--------------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%	Macros for beginning and ending bars
%
%
 
%
% \cb@start#1		#1 is the dimension of the bar
%
% This macro is used to start 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@currentlist and then sets the
% point by calling \cb@setBeginPoint with the point number.  Finally, it
% writes the aux file.
%
\def\cb@start#1{\cb@currentpoint=\cb@nextpoint
	\@tempdima=#1\cb@ig				% for \cb@push
	\cb@push\cb@currentlist
	\ifvmode \cb@setBeginPoint\cb@currentpoint
	\else \vbox to 0pt{\vskip -\ht\strutbox		%jump up a line to
	\cb@setBeginPoint\cb@currentpoint		%set point
	\vskip \ht\strutbox}\fi
	\cb@writeAux\cb@advancePoint}
 
\def\cb@advancePoint{\global\advance\cb@nextpoint by 4\cb@ig
	\ifnum\cb@nextpoint>\cb@maxpoint
	\global\cb@nextpoint=\cb@minpoint\relax\fi}
 
%
% \cb@end
%
% This macro is used to end a changebar.  It pops the current point and
% nesting level off \cb@currentlist and sets the end point by calling
% \cb@setEndPoint with the parameter corresponding to the BEGINNING
% point number.  It writes the aux file and joins the points.
%
\def\cb@end{\cb@pop\cb@currentlist
        \ifnum\cb@currentpoint=\cb@nil
	\typeout{Changebar Warning: Badly nested changebars; Expect erroneous results.}\else
	\cb@setEndPoint\cb@currentpoint
	\advance\cb@currentpoint by1\cb@writeAux\fi}
 
 
%
% \cb@setBeginPoint#1
%
% Assigns position to points #1 and #1+2.  First computes the position.
%
\def\cb@setBeginPoint#1{\special{ln03:defpoint \the#1(\the
    \cb@dimodd,)}\@tempcnta#1\advance\@tempcnta by2\cb@ig
    \special{ln03:defpoint \the\@tempcnta(\the\cb@dimeven,)}}
 
%
% \cb@setEndPoint#1
%
% Assigns position to point #1+1 and point #1+3.  Then does a connect
% special to join #1 and #1+1 or to join #1+2 and #1+3.  Assumes that
% width of bar is given in \@tempdima
%
\def\cb@setEndPoint#1{\@tempcnta=#1\advance\@tempcnta by1\cb@ig
    \special{ln03:defpoint \the\@tempcnta\space
    \space(\the\cb@dimodd,)}\if@twoside\@tempcntb=#1\advance
    \@tempcntb by3\special{ln03:defpoint \the\@tempcntb\space
    \space(\the\cb@dimeven,)}{\count9=#1\advance\count9 by2\cb@ig
    \special{ln03:connect \the#1/\the\count9\space\space
    \the\@tempcnta/\the\@tempcntb\space\space\the\@tempdima}}\else
    \special{ln03:connect \the#1 \the\@tempcnta\space\space
    \the\@tempdima}\fi}
 
%
% \cb@writeAux
%
% Writes the string
% \cb@barpoint{\cb@currentpoint}{\thepage}{\cb@tempdima} to the aux
% file.  Assumes that width of bar is in \@tempdima.
%
\def\cb@writeAux{\begingroup \edef\point{\the\cb@currentpoint}\cb@ig
	\edef\level{\the\@tempdima}\cb@ig
	\let\the=0\edef\cb@temp{\write\@auxout
	{\string\cb@barpoint{\point}{\the\cb@pagecount}{\level}}}\cb@ig
	\cb@temp\endgroup}
 
 

--------------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%	Macros for Making It Work Across Page Breaks
%
 
 
%
% \@makecol
%
% Modifies the LaTex macros to end the changebars spanning the current
% page (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 to be begun are saved in \cb@beginSaves.
% Increments the changebar-internal page counter so that the value
% corresponds to the number of this page in strictly sequential order
% (the LaTeX page number can be reset).  Then it builds the list
% \cb@spanlist, then calls \cb@processActive to process the elements
% on the list, then it executes the original \@makecol.
%
\let\cb@makecol=\@makecol
\def\@makecol{\setbox255=\vbox{\special{ln03:resetpoints \cb@minpoint
        \space\cb@maxpoint}\cb@beginSaves\unvbox255}\cb@ig
	\gdef\cb@beginSaves{}\global\advance
	\cb@pagecount by 1\cb@buildActive
	\cb@processActive\cb@makecol}
 
%
% \cb@processActive
%
% Processes each element on span list.  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 list
%	if point null (i.e., list 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 list (need to reprocess
%		on next page).
%
\def\cb@processActive{\cb@pop\cb@spanlist
	\ifnum\cb@currentpoint=\cb@nil \else
	\setbox255=\vbox{\unvbox255\cb@setEndPoint\cb@currentpoint}\cb@ig
	\cb@saveBeginPoint\cb@currentpoint \cb@push\cb@history
	\cb@processActive\fi}
 
%
% \cb@saveBeginPoint#1
%
% Saves a \special to begin a point in expanded macro \cb@beginSaves.
% This is then used to start all spanning bars at the top of the next
% page.  It is almost the same as \cb@setBeginPoint
%
\def\cb@saveBeginPoint#1{\xdef\cb@beginSaves{\special{ln03:defpoint
    \the#1(\the\cb@dimodd,)}\cb@beginSaves}\@tempcnta#1\advance
    \@tempcnta by2\xdef\cb@beginSaves{\special{ln03:defpoint
    \the\@tempcnta(\the\cb@dimeven,)}\cb@beginSaves}}
 
\def\cb@beginSaves{}                % initially empty
 
 
 
 
%
% \cb@buildActive
%
% Initializes the spanlist to null.  Pops top of history list.  If point
% is on future page, push back onto history list.  If point on current
% or previous page and odd, add point to span list; if even, pop span
% list since this bar has terminated on current page.
%
\def\cb@buildActive{\cb@initlist\cb@spanlist\cb@pushNextActive}
 
\def\cb@pushNextActive{\cb@pop\cb@history
	\ifnum\cb@currentpoint=\cb@nil \else
	\ifnum\cb@page>\cb@pagecount \cb@push\cb@history \else
	\ifodd\cb@currentpoint \cb@push\cb@spanlist
	\else \cb@pop\cb@spanlist\fi
	\cb@pushNextActive\fi\fi}
 
 
 

--------------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%	Macros For Managing The Lists of Bar points
%
% The macros make use of three lists corresponding to \special
% defpoints.  Each list 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 list \cb@history is built from the log information and initially
% lists all the points.  As pages are processed, points are popped off
% the list and discarded.
%
% The list \cb@spanlist is a temporary list used by the output routine
% and contains the list of all bars crossing the current page (there may
% be more than one with nested bars).  It is built by popping elements
% off the history list.
%
% The list \cb@currentlist contains all the current bars.  A \cb@start
% pushes an element onto this list.  A \cb@end pops the top element off
% the list and uses the info to terminate the bar.
%
% For performance and memory reasons, the history list, which can be
% very long, is special cased and a file is used to store this list
% rather than an internal macro.  The ``external'' interface to this
% list is identical to what is described above.  However, when the
% history list is popped, a line from the file is first read and
% appended to the macro \cb@history.
%
 
%
%  \cb@initlist		% Initialize a list
%
\def\cb@initlist#1{\xdef#1{}}
 
%
%  Initializations, etc.
%
\cb@initlist\cb@history		% the history list; initially empty
\cb@initlist\cb@spanlist	% list of bars spanning current page
\cb@initlist\cb@currentlist	% used to implement nesting without using
				% TeX grouping
%\xdef\@empty{}			% to test if list is empty.  In LaTeX.
 
\newwrite\cb@write		% file for history list
\newread\cb@read
\immediate\openout\cb@write=\jobname.cb	% open for building of history list
 
%
% \cb@pop#1		#1 is name of list (e.g., \cb@history)
%
% This pops the top element off the named list and puts the point value
% into \cb@currentpoint, the page value into \cb@page and the bar width
% into \@tempdima.  If the list is empty, returns a void value (\cb@nil)
% in \cb@currentpoint and sets \cb@page=0.
%
\def\cb@pop#1{\ifx #1\cb@history \ifeof\cb@read \else
    {\endlinechar=-1\read\cb@read to\@temp
    \xdef\cb@history{\cb@history\@temp}}\fi\fi
    \ifx \@empty#1\cb@currentpoint=\cb@nil\cb@page=0\else
    \expandafter\cb@carcdr#1e#1\fi}
 
\def\cb@carcdr#1n#2p#3l#4e#5{\cb@currentpoint=#1\cb@page=#2\@tempdima=#3%
	\xdef#5{#4}}
 
%
% \cb@push#1
%
% Pushes \cb@currentpoint, \cb@page and \@tempdima onto the top of the
% named list
%
\def\cb@push#1{\xdef#1{\the\cb@currentpoint n\the\cb@page p\the\@tempdima l#1}}
 
%
% \cb@barpoint  % For populating history file
%
% Writes one line to .cb file which is equivalent to one <element>
% described above.
\def\cb@barpoint#1#2#3{\immediate\write\cb@write{#1n#2p#3l}}
 
 
%
% \document
%
% Modifies \document to manage history file.  It closes the .cb file
% and opens it for reading.  Also calls \reversechangebars to compute
% the dimensions of the bar positions (thus any changes to margins
% etc. in preamble will be recognised).
%
\let\cb@document=\document
\def\document{\reversechangebars
    \cb@document\immediate\closeout\cb@write
    \immediate\openin\cb@read=\jobname.cb}
 
 
 

--------------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%      Macros For Checking That The .AUX File Is Stable
%
 
%
% \enddocument
%
% Does a \clearpage to flush rest of document.  Then closes .cb file
% and reopens for checking.  Inits history list (to be read from
% file).  Lets \cb@barpoint=\cb@checkhistory for checking.
%
\let\cb@enddocument\enddocument
\def\enddocument{\clearpage\cb@initlist\cb@history
   \immediate\closein\cb@read\immediate\openin\cb@read=\jobname.cb%
   \let\cb@barpoint=\cb@checkHistory\cb@enddocument}
 
%
% \cb@checkHistory
%
% Pops the top of the history list (\jobname.cb) and
% check to see if the point and page numbers are the same as the
% arguements #1 and #2 respectively.  Prints a warning message if
% different. 
%
\def\cb@checkHistory#1#2#3{\cb@pop\cb@history
        \ifnum #1=\cb@currentpoint
	    \ifnum #2=\cb@page        % do nothing
	    \else \cb@error           % page numbers mismatched
	    \fi
	\else \cb@error               % point numbers mismatched
	\fi}
 
\def\cb@error{\message{Changebar Warning: Changebar info has changed. %
Rerun to get right.}\gdef\cb@checkHistory##1##2##3{}\let\cb@barpoint=\cb@checkHistory}
 
 
 
 

--------------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%	Macros For Making It Work With Nested Floats/Footnotes
%		Works for LaTeX 2.09
%
 
%
% \end@float
%
% This is a replacement for the Latex 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 LaTeX \end@float
%
\let\cb@endfloat=\end@float
\def\end@float{\cb@pop\cb@currentlist\ifnum\cb@currentpoint=\cb@nil
	\else \cb@push\cb@currentlist\global\@tempdima=\@tempdima
	\egroup \global\setbox\@currbox
	  \vbox\bgroup \cb@start\@tempdima\unvbox\@currbox\cb@end\fi
	\cb@endfloat}
 
\let\endfigure=\end@float	% need to rebind these to new def
\let\endtable=\end@float
 
%
% \@footnotetext#1
%
% Replacement for the LaTeX macro of the same name.  Simply checks to
% see if changebars are active and if so wraps the macro arguement
% (i.e., the footnote) in changebars.
%
\let\cb@footnote=\@footnotetext
\long\def\@footnotetext#1{\cb@pop\cb@currentlist\ifnum\cb@currentpoint=\cb@nil
	\cb@footnote{#1}\else \cb@push\cb@currentlist
	\edef\cb@temp{\the\@tempdima}\cb@ig
	\cb@footnote{\cb@start{\cb@temp}#1\cb@end}\fi}
 
%
% \@mpfootnotetext#1
%
% Replacement for the LaTeX macro of the same name.  Same thing as
% \@footnotetext.
%
\let\cb@mpfootnote=\@mpfootnotetext
\long\def\@mpfootnotetext#1{\cb@pop\cb@currentlist
        \ifnum\cb@currentpoint=\cb@nil
	\cb@mpfootnote{#1}\else \cb@push\cb@currentlist
	\edef\cb@temp{\the\@tempdima}\cb@ig
	\cb@mpfootnote{\cb@start{\cb@temp}#1\cb@end}\fi}
 

--------------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%	end of changebar style
%
 

--------------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%     the \special command junk
%
%   The structure of the PostScript produced by dvi2ps for \special
%   is: 
%
%         @beginspecial
%           - any random stuff
%         @endspecial
%
%   This file also has the stuff from Paul Koning to implement the
%   LN03 \special commands.
%
%   CAVEAT: To make this work, the @beginspecial and @endspecial
%   commands must be no-ops. 
%
 
 
/@beginspecial          % - @beginspecial -     -- enter special mode
  {
  } def
 
/@endspecial            % - @endspecial -       -- leave special mode
  {
  } def
 
 
 
%
%
%  The Commands to do something with LN03 \specials
%
%
 
/Resolution 300 def		% internal units are pixels (300/inch)
/Inch {Resolution mul} def	% converts inches to internal units
 
/ln03$defs 10 dict def
ln03$defs begin
/points 256 array def
0 1 255 { points exch [ 0 0 ] put } for
/linebuf 100 string def
 
% string -- postfix
% defines /varnum in current dictionary
/getvarnum
{ token not {stop} if			% get token, quit if none left
  exec /varnum exch def			% execute it, save result
} def
 
% string -- postfix
% defines /varnum in current dictionary.
% if input is of the form num/num2, uses num if Pagenum is odd, num2 if
% it is even
/get2varnum
{ { ( ) anchorsearch
    { pop pop }
    {exit} ifelse } loop		% eliminate leading spaces
  ( ) search { exch pop } { () exch } ifelse  % look for terminating space
					% stack is now: -- postfix token
  (/) search				% num1/num2 form?
  { Pagenum 1 and 0 eq			% even page number?
    { pop pop }				% yes, use second entry
    { exch pop exch pop }		% use first number
    ifelse
  } if					% now we have just the number wanted
  cvi /varnum exch def			% convert and save it
} def
 
% string default -- result
/getdimension
{ exch dup length 1 sub 0 1 3 -1 roll	% get length, prepare to scan string
  { pop dup 0 1 getinterval		% get first char
    ( ) eq				% is it a space?
    { dup length 1 sub 1 exch getinterval % yes, drop first char
    } { exit } ifelse
  } for
  dup length 0 eq			% nothing but spaces?
  { pop }				% yes, exit with default
  { exch pop				% no, get rid of default
    dup dup length 2 sub 2 getinterval	% get last two characters
    1					% default multiplier is 1
    [[1 Inch 72 div (pt)]		% point
     [1 Inch (in)]			% inch
     [1 Inch 6 div (pc)]		% pica
     [1 Inch 2.54 div (cm)]		% centimeter
     [1 Inch 25.4 div (mm)]]		% milimeter
    { aload pop				% get multiplier and string
      3 index eq			% compare with suffix
      { exch pop exit }			% match, use this multiplier
      { pop }				% no match, pop unused multiplier
      ifelse
    } forall
    exch pop				% get rid of suffix
    exch dup length 2 sub 0 exch getinterval % get all but last 2 chars
    cvr mul				% convert to a number, and form result
  } ifelse
} def
end
 
/ln03:defpoint
{ ln03$defs begin
  { currentfile linebuf readline
    not {stop} if			% quit if premature eof
    getvarnum				% get variable number
    (\() search				% look for (
    not {stop} if			% quit if missing
    pop pop				% keep only string to its right
    (,) search				% find separator
    not {stop} if			% quit if missing
    currentpoint pop			% default is current x
    getdimension /x exch def		% process it and save result
    pop					% pop the comma
    (\)) search				% search for )
    not {stop} if			% quit if missing
    currentpoint exch pop		% default is current y
    getdimension [ x 3 -1 roll ]	% form [x y] pair
    points varnum 3 -1 roll put		% update the variable
    pop pop				% pop two results from search
  } stopped
  { (?Error in \\special ln03:defpoint) print pstack flush stop
  } if
  end
} def
 
/ln03:connect
{ ln03$defs begin
  { currentfile linebuf readline
    not {stop} if			% quit if premature eof
    get2varnum				% get one of two variable numbers
    /firstvarnum varnum def		% save that one
    get2varnum				% get another variable number
    2 getdimension			% get dimension, default to 2
    gsave				% save current graphics state
    setlinewidth newpath		% initialize the line
    points firstvarnum get		% get first variable
    aload pop moveto			% get (x,y) pair, move there
    points varnum get			% get second variable
    aload pop lineto			% add a line to there
    stroke grestore			% ... and that's all
  } stopped
  { (?Error in \\special ln03:connect) print pstack flush stop
  } if
  end
} def
 
/ln03:resetpoints
{ ln03$defs begin
  { currentfile linebuf readline
    not {stop} if			% quit if premature eof
    /firstvarnum 1 def			% default to 1-n rather than n-m
    getvarnum				% get variable number
    dup token				% is there anything else?
    { pop pop /firstvarnum varnum def	% yes, save first number
      getvarnum				% get another variable number
    }
    { pop }				% no, toss copy of string
    ifelse
    firstvarnum 1 varnum { points exch [ 0 0 ] put } for
  } stopped
  { (?Error in \\special ln03:resetpoints) print pstack flush stop
  } if
  end
} def

-------------------------------------------------------------------------------

%%% The TeXhax digest is brought to you as a service of the TeX Users Group
%%%       in cooperation with the UnixTeX distribution service at the 
%%%                      University of Washington
%%%
%%% Concerning subscriptions, address changes, unsubscribing:
%%%  BITNET: send a one-line mail message to LISTSERV@UWAVM.ACS.WASHINGTON.EDU
%%%         SUBSCRIBE TEXHAX <your name>    % to subscribe
%%%      or UNSUBSCRIBE TEXHAX <your name>
%%%
%%%  All others: send a similar one line mail message to
%%%           TeXhax-request@cs.washington.edu
%%%     Please be sure you send a valid internet address!!
%%%        in the form name@domain or name%routing@domain
%%%     and use the style of the Bitnet one-line message, so that
%%%     we can find your subscription request easily.
%%%
%%% All submissions to: TeXhax@cs.washington.edu
%%%
%%% Back issues available for FTPing as:
%%%          machine:              directory:  filename:
%%%   JUNE.CS.WASHINGTON.EDU         TeXhax/TeXhaxyy.nn
%%%              yy = last two digits of current year
%%%                       nn = issue number
%%%
%%% For further information about TeX Users Group services and publications
%%%  contact Karen at KLB@SEED.AMS.COM or write to TUG at
%%%   TeX Users Group
%%%   P.O. Box 9506
%%%   Providence, R.I. 02940-9506
%%%   Telephone      (401) 751-7760
%%%
%%% Current versions of the software now in general distribution:
%%%    TeX       2.93                  metafont  1.5
%%%    plain.tex 2.92                  plain.mf  1.0   
%%%    LaTeX     2.09 ( 4/26/88)       cmbase.mf see cm85.bug
%%%    SliTeX    2.09                  gftodvi   1.7
%%%    tangle    2.8                   gftopk    1.4 
%%%    weave     2.9                   gftype    2.2
%%%    dvitype   2.9                   pktype    2.2 
%%%    pltotf    2.3                   pktogf    1.0
%%%    tftopl    2.5                   mft       0.3
%%%    BibTeX    0.99c                 dvipage   3.0
%%%\bye
%%%

End of TeXhax Digest
**************************
-------