[comp.text] troff and avoiding traps

msb@sq.com (Mark Brader) (03/20/89)

[Sorry if you get this twice - transient local problem.]

About a week ago I posted an article about "troff and eof" in which I
explained how troff handles end-of-input, and why, and how to work around
the default termination if you don't want it.  I said, among other things,
that if you wanted the effect of a 'bp in your end-macro with a guarantee
against troff terminating on the page transition, then you should precede
the 'bp with a line consisting only of a \c escape sequence.

I did not, however, discuss what you should do if you want the effect of
a .bp in your end-macro.  You might think that since .bp is equivalent to
.br followed by 'bp, that all you need to say is

	.br
	\c
	'bp

But in fact this only works some of the time.  The problem is that the .br
will often cause an output line to be produced.  If that action causes your
bottom-of-page trap to be sprung, then you've reached the end of the page
before the \c happened, and your buffers are empty (because of the .br),
and so troff shuts down.

The following trick will sometimes avoid that problem.  Replace the ZZ
with the name of an available number register, of course.

	.pl +1
	.mk ZZ
	.sp |\n(ZZu
	.pl -1
	\c
	'bp


The assumption here is that the bottom-of-page trap has had its position
set relative to the bottom of the page, e.g. ".wh -1i BT" rather than
".wh 10i BT" which would be relative to the top of the page.  If this
assumption is true (as it is in -ms, for instance) then the .pl +1 will
drag the trap position down, along with the bottom of the page, and the
.pl -1 will move them back up to where they were.  If there are no other
traps in the vicinity, the production of one line of output while the
page length is extended therefore cannot possibly spring a trap.

And therefore we now really could do .br in safety.  However, we don't
want to cause unnecessary baseline motion, and in particular, we want to
restore the page length (.pl -1) before falling off the page.  So instead
of .br we do a .sp (which, remember, causes the equivalent of .br as a
side-effect) that will return the baseline to where it was before it
started.

The .mk-.sp pair looks like a no-op at first glance, but it isn't;
the trick is that the argument of .sp is evaluated only after any
output line forced out by its break-causing effect has appeared.
So in this case, if an output line is produced, the .sp is equivalent
to a .sp -1.  (If no output line is produced, it's equivalent to .sp 0,
so the .mk-.sp combination really is a no-op then.)

So the above sequence is a replacement for .bp in the end-macro, if
     (a) your macros set their traps in the way I described, and
     (b) your page transition macros do not switch environments.
If your page transition macros switch environments, then the \c has
to be used within them.


This trap-avoiding trick is useful elsewhere than in end-macros.
I will discuss in a separate message its use in connection with
the "aligning with the right margin" problem discussed lately
in this newsgroup.


In our version of troff, sqtroff, you don't have to assume anything about
the macro package.  This is because we have added a request .vpt, which
disables and re-enables traps set by .ch, .wh, or .dt.  (vpt = Vertical
Position Traps).  So in sqtroff, the above code becomes:

	.vpt off
	.mk ZZ
	.sp |\n(ZZu
	.vpt on
	\c
	'bp

And this will work regardless of what traps are set.

Mark Brader, SoftQuad Inc., Toronto, 416-963-8337, from US 800-387-2777
{ uunet!attcan | linus | decvax | watmath | pyramid } !utzoo!sq!msb
msb@sq.com		decwrl!utcsri!sq!msb