All troffs known to me to date do kind of a weird thing when you give
the `dt` ("diversion trap") request a syntactically invalid argument.
They assume that you wanted to remove an existing diversion trap. And
of course (except for GNU troff) they emit no diagnostic of any kind.
This is a fairly dusty corner of *roff to people who write documents
instead of macro packages, so here's a refresher/primer.
groff(7):
Diversions
In roff systems it is possible to format text as if for output, but
instead of writing it immediately, one can divert the formatted
text into a named storage area. It is retrieved later by
specifying its name after a control character. The formatter uses
the same name space for such diversions as for strings and macros;
see section “Identifiers” above. Such text is sometimes said to be
“stored in a macro”, but this coinage obscures the important
distinction between macros and strings on one hand and diversions
on the other; the former store unformatted input text, and the
latter capture formatted output. Diversions also do not interpret
arguments. Applications of diversions include footnotes, tables of
contents, indices, and “keeps” (preventing a page break from
occurring at an inconvenient place by forcing a set of output lines
to be set as a group). For orthogonality it is said that GNU troff
populates the top‐level diversion if no diversion is active (that
is, formatted output is being “diverted” directly to the output
device). The top‐level diversion has no name.
I haven't yet ported material on Traps from our Texinfo manual into
groff(7), so I'll quote the Texinfo for that.
5.29 Traps
==========
"Traps" are locations in the output, or conditions on the input that,
when reached or fulfilled, call a specified macro. These traps can
occur at a given location either on the page or in the current diversion
(together, these are known as vertical position traps), at a blank line,
at a line with leading space characters, after a quantity of input
lines, or at the end of input. Setting a trap is also called "planting"
one. It is said that a trap is "sprung" if its condition is fulfilled.
The formatter passes no arguments to macros called by traps.
5.29.1 Vertical Position Traps
------------------------------
A "vertical position trap" calls a macro when the formatter's vertical
drawing position reaches or passes, in the downward direction, a certain
location on the output page or in a diversion. Its applications include
setting page headers and footers, body text in multiple columns, and
footnotes.
...
5.29.1.3 Diversion Traps
........................
A diversion is not formatted in the context of a page, so it lacks page
location traps; instead it can have a "diversion trap". There can exist
at most one such vertical position trap per diversion.
-- Request: .dt [dist name]
Set a trap _within_ a diversion at location DIST, which is
interpreted relative to diversion rather than page boundaries. If
invoked with fewer than two arguments, any diversion trap in the
current diversion is removed. The register '.t' works within
diversions. It is an error to invoke 'dt' in the top-level
diversion. *Note Diversions::.
Proposal
========
What I propose is to make GNU troff's `dt` request handler throw an
error diagnostic if `dist` is not a valid vertical position expression,
and ignore the request. As a bonus, this change should also assist the
user in cases where they forget the request's syntax and try to give
the arguments in the wrong order (_and_ they haven't chosen a macro name
that happens to also be a valid vertical position expression, like "3i"
or "22v" or "66v-1u").
Traditionally and elsewhere in the language grammar, *roffs ignore
syntactically invalid requests, treating them as no-ops. But not here,
so, strictly speaking, this change would be a compatibility break.
Illustration
============
$ cat ATTIC/dt-bogus.roff
.de TT
WHOOPS
.br
..
.di DD
.dt 3v TT
.nf
foo
bar
.dt \e
.sp
baz
.di
.DD
$ dwb nroff ATTIC/dt-bogus.roff | cat -s
foo
bar
baz
(Same for "9 nroff" and "heirloom nroof".)
Historically, GNU troff _has_ warned in this situation, albeit not
altogether clearly about the consequences of the bogus argument. (I
reckon because in other contexts, there _are_ no other consequences.)
$ ~/groff-1.22.3/bin/nroff ATTIC/dt-bogus.roff | cat -s
ATTIC/dt-bogus.roff:10: warning: numeric expression expected (got `\e')
foo
bar
baz
$ ~/groff-1.22.4/bin/nroff ATTIC/dt-bogus.roff | cat -s
troff: ATTIC/dt-bogus.roff:10: warning: numeric expression expected (got '\e')
foo
bar
baz
$ ~/groff-1.23.0/bin/nroff ATTIC/dt-bogus.roff | cat -s
troff:ATTIC/dt-bogus.roff:10: warning: expected numeric expression, got an
escaped 'e'
foo
bar
baz
$ ~/groff-1.24.0/bin/nroff ATTIC/dt-bogus.roff | cat -s
troff:ATTIC/dt-bogus.roff:10: error: ignoring invalid numeric expression
containing an escaped 'e'
foo
bar
baz
We can see that GNU troff's diagnostic messages have steadily improved
over time (in my interest-conflicted opinion), but even the latest
release doesn't tell the user what's going to happen. Since `dt`
optionally accepts two arguments, is the first ignored but the second
(naming the trap macro) somehow honored? No. Instead both arguments
are ignored: the request behaves as if it were given no arguments.
Let's inspect that scenario a little more closely.
$ cat ATTIC/dt-bogus2.roff
.de TT
WHOOPS
.br
..
.di DD
.dt 3v TT
.tm register .t=\n(.t
.nf
foo
bar
.dt \e DD
.tm register .t=\n(.t
.sp
baz
.di
.DD
$ ~/groff-1.24.0/bin/nroff ATTIC/dt-bogus2.roff | cat -s
register .t=120
troff:ATTIC/dt-bogus2.roff:11: error: ignoring invalid numeric expression
starting with an escaped 'e'
register .t=53687080
foo
bar
baz
A person really familiar with diversion trap semantics can infer that
the `.dt \e DD` request removed the diversion trap.[1]
Planned change:
$ ./build/test-groff -T ascii ATTIC/dt-bogus.roff | cat -s
troff:ATTIC/dt-bogus.roff:10: error: ignoring invalid numeric expression
containing an escaped 'e'
foo
bar
WHOOPS
baz
Naturally I'll have an automated test for this behavior. I was writing
one for the `dt` request (attached), and a piece of control flow
puzzled me, and that's how I came to discover this issue.
Regards,
Branden
[1] What's up with the value of the `.t` register?
Back to the groff Texinfo manual:
-- Register: \n[.t]
The read-only register '.t' holds the distance to the next vertical
position trap. If no such traps exist between the drawing position
and the bottom of the page, it contains the distance to the page
bottom. Within a diversion, in the absence of a diversion trap,
this distance is the maximum possible vertical position supported
by the output device.
signature.asc
Description: PGP signature
