1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
|
% This is CHBARS.DOC as of 09 Oct 89
%---------------------------------------------------------
% (c) 1989 by J.Schrod. copy conditions see below.
%
% Macro package for creating changebars in Plain TeX
% MAKEPROG is needed
%
% documented in LaTeX (for Anne and Chris)
%
% VERSION HISTORY (MSCF -- most significant change first)
%
% DATE PERSON REMARK
% 89-10-09 -js converted to LaTeX (progltx)
% 89-09-25 -js repaired \mark processing in horizontal mode
% 89-08 -js first version (for EuroTeX89 in Karlsruhe)
%
% author's current address:
%
% Detig$\,\cdot\,$Schrod \TeX{}sys
% Joachim Schrod
% Kranichweg 1
%
% D-6074 R\"odermark-Urberach
% FR Germany
%
% Tel. (+6074) 1617
% Bitnet: XITIJSCH@DDATHD21
% should be progtex...
%%%%
%%%%
%%%% These TeX macros were documented with the documentation system
%%%% MAKEPROG and automatically converted to the current form.
%%%% If you have MAKEPROG available you may transform it back to
%%%% the original input: Remove every occurence of three percents
%%%% and one optional blank from the beginning of a line and remove
%%%% every line which starts with four percents. The following lex
%%%% program will do this:
%%%%
%%%% %%
%%%%
%%%% ^%%%\ ? ;
%%%% ^%%%%.*\n ;
%%%%
%%%% MAKEPROG may be obtained over the net from the Bitnet-Listserver
%%%% LISTSERV@DHDURZ1 (filelist WEBWARE), from tuglib@science.utah.edu,
%%%% or via ftp from june.cs.washington.edu.
%%%%
%%%%
%%% \documentstyle[progltx,a4-9]{article}
%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% %
%%% % local macros
%%% %
%%% \let\mc=\small % for names like GNU
%%% \def\PS{{\sc PostScript}}
%%% \def\DVI{{\tt DVI}}
%%% \def\GNU{{\mc GNU}}
%%% \chardef\bs=`\\
%%% %
%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% \begin{document}
%%% \title{Changebars without {\tt \bs{}special}'s}
%%% \author{\sc Joachim Schrod}
%%% \maketitle
%%% \begin{abstract}
%%% It is common practice to use vertical bars in the margins of a
%%% document to mark pieces of text which have changed since the last
%%% version(s) of this document. Such vertical bars are usually
%%% called {\em changebars}. It has often been said that it is
%%% impossible to produce changebars with \TeX{} without the usage of
%%% |\special| commands (driver directives), which extend the
%%% primitives of \TeX{}. This paper presents a \TeX{} macro file
%%% which implements changebars without such a usage. The macro file
%%% is written for the usage with Plain~\TeX{} but the implementation
%%% strategy can be used with \LaTeX{}, too.
%%% \end{abstract}
%%% \chap Introduction.
%%% Changebars are used to mark modified parts in existing documents. For
%%% the usage in \TeX{} documents, there exist only solutions that use
%%% driver/printer features by the way of inserting |\special| commands in
%%% the \TeX{} source, e.g.\ for \PS{} drivers. This results in documents
%%% that are no longer as freely interchangeable as the \DVI{} concept would
%%% allow---device dependency is problematic especially for this application
%%% that is useful for multi-authoring or standards development.
%%% This macro package offers a pure \TeX{} solution. Nevertheless, it has
%%% its restrictions, too. The page break will no longer be optimal,
%%% because no strechability or shrinkability on a page on top of the last
%%% mark of a change is supported. But this seems to be acceptable,
%%% especially as the change bar feature often will be used for proof
%%% reading and not in the final document. This restriction is the reason
%%% why no change marks can be used on titlepages or for similar
%%% constructions. Changes in floating insertions (footnotes, figures) are
%%% not discovered.
%%% The demonstrated solution is written in Plain \TeX{}, because it was
%%% easier and could be presented better at the Euro\TeX89 conference in
%%% Karlsruhe. An adaption to \LaTeX{} is possible, but would require
%%% modifications to the \LaTeX{} kernel, i.e.\ the output routine and the
%%% layout parameters of the standard styles.
%%% \sect This program is free software; you can redistribute it and/or
%%% modify it under the terms of the \GNU{} General Public License as
%%% published by the Free Software Foundation; either version~1, or (at your
%%% option) any later version.
%%% This program is distributed in the hope that it will be useful, but
%%% {\bf without any warranty\/}; without even the implied warranty of
%%% {\bf merchantability\/} or {\bf fitness for a particular purpose}. See
%%% the \GNU{} General Public License for more details.
%%% %You should have received a copy of the \GNU{} General Public License
%%% %along with this program; if not, write to the Free Software Foundation,
%%% If you have not received a copy of the \GNU{} General Public License
%%% along with this program, write to the Free Software Foundation,
%%% Inc., 675~Mass Ave, Cambridge, MA~02139, USA.
%%% \sect A changed area is described by two marks, |\beginchange| and
%%% |\endchange|. The method for writing a change bar consists of three
%%% parts: First, it will be indicated to the output routine that a change
%%% has occured. Next, the position of the changed area will be found out
%%% and fixed. A list of all changed areas is built, that can at last be
%%% marked by the output routine using vertical rules at the right margin.
%%% But before we start we declare some shorthands for category codes. By
%%% declaring the at sign~(`|@|') as well as the underscore~`(|_|)' as
%%% letters we can use them in our macros. (I agree with D.~Knuth that
%%% |\identifier_several_words_long| is more readable than
%%% |\IdentifierSeveralWordsLong| and in every case better than |\p@@@s|.)
%%% With the at sign we can use the ``private'' Plain macros and with the
%%% underscore we can make our own macros more readable. But as we have to
%%% restore these category codes at the end of this macro file we store
%%% their former values in the control sequences |\atcode| and |\uscode|.
%%% This method is better than to use a group because not all macros have to
%%% be defined global this way.
%%% \beginprog
\chardef\letter=11
\chardef\atcode=\catcode`\@
\chardef\uscode=\catcode`\_
\catcode`\@=\letter
\catcode`\_=\letter
%%% \endprog
%%% \chap Triggering the Output Routine.
%%% \begin{sloppypar}
%%% First, the output routine must know that changes occured. This is done
%%% by the macros |\beginchange| and |\endchange| that append a reserved
%%% penalty value |\break_penalty| to the current list that is below
%%% $-10\,000$. The penalty will be in the range $|\change_penalty_group|
%%% \cdot 100 - 99 \ldots |\change_penalty_group| \cdot 100$.
%%% For the output it must be differentiated if the mark indicates
%%% begin or end of the changed area. This is done with the values
%%% |\change_penalty_begin| and |\change_penalty_end| that are used as the
%%% second-to-last digit of the change penalty.
%%% \end{sloppypar}
%%% It must also be differentiated between the beginning of a mark being in
%%% horizontal or vertical mode. In horizontal mode, the change bar must
%%% not begin at the baseline of the actual text position, but on top of the
%%% actual line. This is marked in the last digit, an odd digit will be
%%% used in horizontal mode.
%%% Note that the values mentioned above are used as digits here that can be
%%% concatenated. If they are not followed by an other digit they should be
%%% terminated by |\space| to stop the look-ahead for digits.
%%% These interactions with the output routine adds a lot of dead cycles; we
%%% must therefore increase |\maxdeadcycles| to prevent \TeX{} from grumbling.
%%% \beginprog
\def\change_penalty_group{-101}
\def\change_penalty_begin{0}
\def\change_penalty_end{1}
\maxdeadcycles=100
%%% \endprog
%%% \sect The marks set the change penalty value (including the indication
%%% of begin or end of mark). The rest (|\trigger_output|) is the same action
%%% for both. An end change mark in horizontal mode can be preceeded by
%%% glue that could cause a line break, thus including the following line to
%%% the change area as well. To avoid this unwanted behaviour, the space is
%%% saved in |\save_space|, discarded in front of the mark and restored
%%% afterwards.
%%% \beginprog
\newcount\break_penalty
\newskip\save_space
\def\beginchange{%
\break_penalty=\change_penalty_group\change_penalty_begin0
\trigger_output
}
\def\endchange{%
\ifhmode \save_space=\lastskip \unskip \fi
\break_penalty=\change_penalty_group\change_penalty_end0
\trigger_output
\ifhmode \hskip\save_space \fi
}
%%% \endprog
%%% \sect In |\trigger_output| the real output trigger is done. We must consider
%%% that an |\output|-invocation by our |\break_penalty| can be discarded at
%%% the beginning of a page. So we trigger the output routine twice, first
%%% with a special penalty value that is 2~less than the correct value
%%% (including the code for horizontal or vertical mode). After the first
%%% page break it is asserted that the current list is empty. The output
%%% routine has to save the former page contents if necessary.
%%% Now we set the penalty to the correct value. The second page break does
%%% the real work, restores the page contents and handles the split
%%% insertions (footnotes, figures,~\dots)
%%% In horizontal mode |\spacefactor| must not be destroyed.
%%% \beginprog
\newcount\save_space_factor
\def\trigger_output{%
\ifinner \errmessage{Change cannot be marked inside a box}%
\else
\ifvmode \let\do_in_vmode=\relax
\advance \break_penalty by -2
\else \save_space_factor=\spacefactor
\let\do_in_vmode=\vadjust
\advance \break_penalty by -3
\fi
\do_in_vmode{%
\penalty\break_penalty
\null
\advance \break_penalty by 2 \penalty\break_penalty
}%
\ifhmode \spacefactor\save_space_factor \fi
\fi
}
%%% \endprog
%%% \sect The usage of the output routine as an information passing system
%%% has always it's difficulties. One of the real hard parts is the
%%% handling of the page marks, special token lists that are handled by
%%% \TeX{}. These token lists provide informations about text on a page,
%%% they are usually used to create head lines etc. The user may access
%%% these token lists with three control sequences: |\botmark| is the
%%% last page mark given, |\topmark| is the |\botmark| of the previous
%%% page, and |\firstmark| is the first page mark on the actual page or
%%% |\topmark| if none was given. Here ``page'' is used in the \TeX{}
%%% sense, i.e.\ as the material which has been collected between two
%%% |\output| invocations. Of course, the page marks must not be
%%% destroyed---and that means they must be reinserted after each
%%% special use of the output routine.
%%% But we have luck: A ``special use'' consists of two |\output|
%%% invocations, so we can insert |\topmark| again as a page mark after
%%% the first invocation where it will be the only page mark on that
%%% \TeX{} page. The second invocation will automatically transform this
%%% page mark into the ``last page mark on the previous page,'' i.e.\ in
%%% |\topmark|---that's what we need! Furthermore |\firstmark| and
%%% |\botmark| are saved in control sequences during the first invocation,
%%% they will be inserted again, too.
%%% There's one situation where this approach doesn't work: In front of
%%% the first page mark |\topmark|, |\firstmark|, and |\botmark| expand
%%% to an empty token list. If we save them then and insert their old
%%% values we have inserted empty page marks. If other page marks follow
%%% on the same ``real'' page |\firstmark| will be empty instead of
%%% expanding to the token list of the first page mark. To prevent this
%%% we must not save and restore page marks before the first |\mark| has
%%% been added to the main vertical list.
%%% Well, that can be controlled with a switch---but this switch must be
%%% set very carefully. If it is set immediately by the first |\mark|
%%% this may be in horizontal mode and special output invocations can
%%% occur above this page mark (i.e., there may be a |\beginchange| in the
%%% same paragraph in front of the |\mark|). Therefore the setting of the
%%% switch must be delayed until the vertical position of the |\mark|
%%% (precisely: the position of the |\mark| in the current list) is
%%% reached. In horizontal mode this can be done with a |\vadjust| and
%%% the output routine! Voil\`a, this is another command group for the
%%% output routine with only one command.
%%% \beginprog
\newif\if@save_mark@ \@save_mark@false
\def\mark_penalty_group{-102}
%%% \endprog
%%% \sect We will redefine |\mark| so that the first page mark either sets
%%% the switch to true (in vertical mode all possible special page breaks
%%% are already handled) or forces the |\output| routine to do this at an
%%% appropriate place. In the last case we can use |\trigger_output|
%%% again. Afterwards we restore the original meaning of |\mark| again to
%%% reduce the processing overhead (and the dead cycles).
%%% This change of |\mark| has the consequence that the first |\mark| in a
%%% document cannot be used anymore in horizontal mode inside a vertical
%%% box that shall be split afterwards. But this is only sensible if this
%%% mark shall be used as |\splitfirstmark| because it will almost never
%%% migrate to the outer list---really a rare case!
%%% \beginprog
\let\@@mark=\mark
\def\mark{%
\ifvmode
\ifinner \else \global\@save_mark@true \fi % split marks!
\else \break_penalty=\mark_penalty_group00 % this will corrupt \vsplit
\trigger_output
\fi
\global\let\mark=\@@mark
\@@mark
}
%%% \endprog
%%% \sect
%%% \begin{sloppypar}
%%% If the output routine is triggered with the mark penalty value
%%% it will call |\start_saving_page_marks|.
%%% \end{sloppypar}
%%% \beginprog
\def\start_saving_page_marks{% % this may be executed twice
\unvbox255
\global\@save_mark@true
}
%%% \endprog
%%% \sect To finish the treatment of page marks we can formulate the two
%%% macros which are used at the first resp.\ second invocation of a
%%% ``special output,'' the principles have already been explained.
%%% \beginprog
\def\backup_page_marks{%
\if@save_mark@
\mark{\topmark}%
\xdef\save_firstmark{\firstmark}%
\xdef\save_botmark{\botmark}%
\fi
}
\def\restore_page_marks{%
\if@save_mark@
\mark{\save_firstmark}\mark{\save_botmark}%
\fi
}
%%% \endprog
%%% \chap Positioning the Change Marks.
%%% Now we must handle the positions of the bars. |\change_pos| will hold
%%% the position of the actual mark, i.e.\ the distance between top of page
%%% and actual mark. |\top_change_pos| will hold the beginning of a changed
%%% area; a value of |\maxdimen| indicates that no change is in effect. If
%%% a changed area is completed, it is appended to the list |\bar_list| as
%%% an element |\bar(\top_change_pos,\change_pos)|. This list contains all
%%% changed areas within the current page so that bars can be written later
%%% on. A single bar will be produced by |\write_bar|.
%%% \noindent The definition of |\bar| to |\relax| allows the concatenation
%%% of new elements to |\bar_list| with |\xdef|.
%%% \beginprog
\newdimen\change_pos
\newdimen\top_change_pos \top_change_pos=\maxdimen
\let\bar_list=\empty
\let\bar=\relax
\def\write_bar(#1,#2){%
\setbox0=\hbox{\vrule height -#1 depth #2}%
\dp0=0pt \ht0=0pt
\box0
}
%%% \endprog
%%% \sect If the output routine was activated by a |\outputpenalty| value
%%% within the range of our reserved penalties, the change handling will
%%% occur, otherwise standard plain output can be done.
%%% \beginprog
\newcount\penalty_group
\output={%
\boxmaxdepth=\maxdepth
\penalty_group=\outputpenalty \divide \penalty_group by 100
\ifnum \penalty_group=\change_penalty_group\space \change_handling
\else
\ifnum \penalty_group=\mark_penalty_group\space
\start_saving_page_marks
\else \plainoutput
\fi
\fi
}
%%% \endprog
%%% \sect As explained before, the change handling must differentiate
%%% between the kind of the change command (beginning is indicated by
%%% $|\change_cmd|=0$, end by~1) and between the mode (horizontal indicated
%%% by an odd |\change_mode| value, vertical by an even). A change mode
%%% higher than one indicates that we are doing the first page break that
%%% has to backup the page as far as it exists already and results in an
%%% empty current list of page elements.
%%% \beginprog
\newcount\change_cmd
\newcount\change_mode
\def\change_handling{%
\change_cmd=-\outputpenalty % ==> absolute value
\advance \change_cmd by \change_penalty_group00 % subtraction
\change_mode=\change_cmd
\divide \change_cmd by 10 % second-to-last digit
\advance \change_mode by -\number\change_cmd0 % last digit
\ifnum \change_mode>1 \backup_page
\else
\ifcase \change_cmd \begin_change
\or \end_change
\else \errmessage{Invalid changepenalty}%
\fi
\fi
}
%%% \endprog
%%% \sect Processing a mark during the second trigger of the output routine
%%% means restoring the page and storing the positions. At the beginning,
%%% the begin of the change is saved, at the end, we know the bar already
%%% and put it into the bar list. Then the positioning values are
%%% reinitialized.
%%% As within every output invocation, the box 255 must be unboxed. As we
%%% are here in the second invocation of the output routine the |\box255|
%%% consists only of the empty |\vbox| we have inserted in
%%% |\trigger_output|. We can therefore throw it away.
%%% \beginprog
\def\begin_change{%
\restore_page
\setbox0=\box255
\ifdim \top_change_pos=\maxdimen
\global\top_change_pos=\change_pos \global\change_pos=0pt
\else \errmessage{Nested change bars are not supported}%
\fi
}
\def\end_change{%
\restore_page
\setbox0=\box255
\ifdim \top_change_pos=\maxdimen
\errmessage{No change is in effect}%
\else
\xdef\bar_list{\bar_list \bar(\the\top_change_pos,\the\change_pos)}%
\global\top_change_pos=\maxdimen \global\change_pos=0pt
\fi
}
%%% \endprog
%%% \chap Handling the Page Contents.
%%% We handle the part of the page that was collected up to now by putting
%%% it into a box. This fixes the position of the change mark so that
%%% |\change_pos| can be set and stored later on in |\top_change_pos| or as
%%% the lower end of a bar in |\bar_list|.
%%% To save the page contents in the first output invocation, we have to
%%% save the page in |\save_page|. Before that, we store the size of the
%%% box (which equals |\pagegoal|!)\ in |\page_goal|. If the unboxing
%%% caused an increase of height (i.e.\ if $|\pagetotal|>|\pagegoal|$),
%%% we eject the page up to the change mark. Now we have to compute the
%%% current position of our mark in |\change_pos|. It is fixed by the size
%%% of the |\save_page|, but in case of a begin mark in horizontal mode we
%%% must decrease it from the baseline position to the top of the last line.
%%% Finally, we must save the values for the allowed insertions and change
%%% them to the maximal value so that a rest that is split from an insertion
%%% will be appended to the insertion box at the second invocation in every
%%% case.
%%% The |\vsize| is initialized to |\maxdimen|. This allows to control
%%% whether this first output invocation ocurred or if it was discarded.
%%% For the same reason |\change_pos| is initialized to~0pt.
%%% \beginprog
\newbox\save_page
\newdimen\page_goal
\newdimen\save_vsize \save_vsize=\maxdimen
\newdimen\save_dimen_topins
\newdimen\save_dimen_footins
\def\backup_page{%
\global\page_goal=\ht255
\global\setbox\save_page=\vbox{\unvbox255}%
\ifdim \ht\save_page>\page_goal \eject_page_so_far \fi
\change_pos=\ht\save_page \global\advance \change_pos by \dp\save_page
\ifnum \change_cmd=\change_penalty_begin\space
\ifodd \change_mode \higher_change_pos \fi
\fi
\global\save_vsize=\vsize \global\vsize=\maxdimen
\global\save_dimen_topins=\dimen\topins \global\dimen\topins=\maxdimen
\global\save_dimen_footins=\dimen\footins
\global\dimen\footins=\maxdimen
\backup_page_marks
}
\change_pos=0pt
%%% \endprog
%%% \sect To eject a page as far as it is we restore it from the
%%% |\save_page| back to box~255. In horizontal mode and at a begin mark
%%% the last line contains the mark and must not be output. So we remove it
%%% and the preceding glue from the stored rest, just leaving a single hbox
%%% to be on top of the actual page (in |\save_page|) now. Then normal
%%% output can be done with box~255.
%%% \beginprog
\def\eject_page_so_far{%
\begingroup
\vbadness=20000 % don't complain about underfull vboxes
\global\setbox255=\vbox to \page_goal{%
\unvbox\save_page
\ifnum \change_cmd=\change_penalty_begin\space
\ifodd \change_mode
\global\setbox\save_page=\lastbox
\unskip
\fi
\fi
}%
\endgroup
\plainoutput
}
%%% \endprog
%%% \sect
%%% \begin{sloppypar}
%%% In horizontal mode and at a begin mark, we need the position of
%%% the mark (|\change_pos|) on the upper boundary of the last line in
%%% |\save_page|. If there is just one line left from a recent eject, the
%%% height is given by the topskip decreased by the height of this hbox. If
%%% the height of the box is larger than |\topskip| the skip will not be
%%% inserted and the change position results to~0pt. Otherwise,
%%% |\save_page| is a vbox whose last hbox we delete temporarily using
%%% box~0. Height and depth of the rest are the actual position on the page.
%%% \end{sloppypar}
%%% The double of the page we have constructed this way will immediately be
%%% fed back to the garbage collector because it could have become
%%% reasonably large.
%%% \beginprog
\def\higher_change_pos{%
\ifhbox \save_page % rest of page from \eject_page_so_far
\change_pos=\topskip \global\advance \change_pos by -\ht\save_page
\ifdim \change_pos<0pt \global\change_pos=0pt \fi
\else
\setbox0=\vbox{%
\unvcopy\save_page
\setbox0=\lastbox % delete last line
}%
\change_pos=\ht0 \global\advance \change_pos by \dp0
\setbox0=\box\voidb@x
\fi
}
%%% \endprog
%%% \sect To restore a page during the second output invocation, we first
%%% restore the saved values, but only if they were really changed (this can
%%% be discovered by the value of |\save_vsize|). Now the |\save_page| is
%%% appended to the current list as a box, which stops later usage of its
%%% stretch- and shrinkability! Then the collected insertions can be
%%% inserted again. The page marks have to be inserted, too.
%%% \beginprog
\def\restore_page{%
\ifdim \save_vsize=\maxdimen
\else \global\vsize=\save_vsize
\global\dimen\topins=\save_dimen_topins
\global\dimen\footins=\save_dimen_footins
\global\save_vsize=\maxdimen
\restore_page_marks
\fi
\box\save_page % discards stretch- and shrinkability!
\ifvoid \topins
\else \insert\topins{\floatingpenalty=0 \unvbox\topins}%
\fi
\ifvoid \footins
\else \insert\footins{\floatingpenalty=20000 \unvbox\footins}%
\fi
}
%%% \endprog
%%% \sect {\em Please note, that there is still a problem with this concept
%%% of handling the output trigger:}
%%% \bigskip
%%% If the first output trigger is discarded because a page break has occured
%%% just in front, footnote parts may be juggled around. I.e., if a
%%% footnote is split in three parts, the first part was just been shipped
%%% out, the second part is inserted back into the recent contributions by
%%% the output routine but {\em behind\/} the third part which is saved in
%%% the ``special place'' (according to the \TeX{}book, p.~125). A solution to
%%% this problem might be to insert a |\do_change| again within the second
%%% output trigger and finishing the treatmend afterwards. Afterwards a
%%% full triggering process (two output invocations) is executed again and
%%% alle insertion parts will be accessible in the insertion box.
%%% By the way, the almost same problem appears in \LaTeX{}, too. Almost: in
%%% \LaTeX{} this can happen every time because at the first output invocation
%%% the |\dimen|-values of the footnote insertion is not increased. I leave
%%% the problem open to the reader\,\dots
%%% \chap Writing the Stuff.
%%% The positions of the bars which mark the changed areas are relative to
%%% the top of the text, i.e.\ the height of the top insertion is not
%%% included. Therefore it is best to write them just after the top
%%% insertions before the page text---but to do this we have to change the
%%% Plain macro |\pagecontents|.
%%% Below is the new definition, I have just rearranged it a little bit so
%%% that it is more legible. The line I have inserted is marked with
%%% `|%%%%|'. |\insert_current_bar| inserts a last element in |\bar_list|
%%% if a changed area is not yet finished, afterwards all bars can be
%%% written.
%%% \beginprog
\def\pagecontents{%
\ifvoid \topins \else \unvbox\topins \fi
\insert_current_bar \write_all_bars %%%%
\dimen@=\dp\@cclv \unvbox\@cclv % open up \box255
\ifvoid \footins
\else % footnote info is present
\vskip\skip\footins
\footnoterule
\unvbox\footins
\fi
\ifr@ggedbottom \kern-\dimen@ \vfil \fi
}
%%% \endprog
%%% \sect If $|\top_change_pos|=|\maxdimen|$ no change is active. Otherwise
%%% the current change reaches from the begin mark (|\top_change_pos|) to
%%% the end of the page, i.e.\ we insert a virtual end mark. Because the
%%% change continues on the next page we insert a virtual begin mark on the
%%% top of the page, too.
%%% \beginprog
\def\insert_current_bar{%
\ifdim \top_change_pos=\maxdimen
\else
\change_pos=\ht255 \advance\change_pos by \dp255
\xdef\bar_list{\bar_list \bar(\the\top_change_pos,\the\change_pos)}%
\global\top_change_pos=0pt
\fi
}
%%% \endprog
%%% \sect Now we can write all bars---if they exist anyway. It's rather
%%% easy, we just have to define |\bar| to |\write_bar| and execute
%%% |\bar_list|. The resulting output must not use vertical place. We must
%%% not forget to delete the list, or we will get the same bars on the next
%%% page again.
%%% \noindent |\BarDistance| is the amount of place between the text margin
%%% and the change bars.
%%% \beginprog
\newbox\@bars
\newdimen\BarDistance \BarDistance=2cc
\def\write_all_bars{%
\ifx \bar_list\empty
\else % changes exist
\setbox\@bars=\hbox to \hsize{%
\hskip\hsize \hskip\BarDistance
\vbox to 0pt{\offinterlineskip
\let\bar=\write_bar \bar_list
}%
\hss
}%
\ht\@bars=0pt \dp\@bars=0pt \box\@bars
\global\let\bar_list=\empty
\fi
}
%%% \endprog
%%% \sect We finish the macro file so that garbage (e.g.\ of exchanges
%%% between systems) can come afterwards.
%%% \beginprog
\catcode`\@=\atcode
\catcode`\_=\uscode
\endinput
%%% \endprog
%%% \end{document}
|