gbranden pushed a commit to branch master
in repository groff.
commit d68c68c2602b106736236124d9985ff3cf775ca0
Author: G. Branden Robinson <[email protected]>
AuthorDate: Tue May 19 19:11:18 2026 -0500
[troff]: `pwh` request reports diversion traps.
* src/roff/troff/div.h (class diversion): Declare new pure virtual
member function `print_diversion_trap()` returning `void`.
(class macro_diversion)
(class top_level_diversion): Declare member function
`print_diversion_trap()`.
* src/roff/troff/div.cpp (macro_diversion::print_diversion_trap): New
member function reports properties of a diversion trap if one exists.
(top_level_diversion::print_diversion_trap): New member function
throws assert(3)ion if called. Internal logic should ensure that such
a call is impossible.
(print_traps_request): Call the `print_traps()` member function of
`topdiv` (as before) only if it is the current diversion. Otherwise,
the current diversion is a macro diversion, so call its
`print_diversion_trap()` member function.
* doc/groff.texi.in (Diversion Traps, Debugging):
* man/groff.7.man (Request short reference):
* man/groff_diff.7.man (New requests): Document it.
* src/roff/groff/tests/pwh-request-works.sh: Unit-test request.
* src/roff/groff/groff.am (groff_TESTS): Run test.
Fixes <https://savannah.gnu.org/bugs/?68358>.
---
ChangeLog | 28 ++++++++++
doc/groff.texi.in | 19 +++++--
man/groff.7.man | 9 +++-
man/groff_diff.7.man | 12 +++--
src/roff/groff/groff.am | 1 +
src/roff/groff/tests/pwh-request-works.sh | 87 +++++++++++++++++++++++++++++++
src/roff/troff/div.cpp | 21 +++++++-
src/roff/troff/div.h | 3 ++
8 files changed, 167 insertions(+), 13 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index b1e70ef92..3d6185201 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2026-05-19 G. Branden Robinson <[email protected]>
+
+ * src/roff/troff/div.h (class diversion): Declare new pure
+ virtual member function `print_diversion_trap()` returning
+ `void`.
+ (class macro_diversion)
+ (class top_level_diversion): Declare member function
+ `print_diversion_trap()`.
+ * src/roff/troff/div.cpp
+ (macro_diversion::print_diversion_trap): New member function
+ reports properties of a diversion trap if one exists.
+ (top_level_diversion::print_diversion_trap): New member function
+ throws assert(3)ion if called. Internal logic should ensure
+ that such a call is impossible.
+ (print_traps_request): Call the `print_traps()` member function
+ of `topdiv` (as before) only if it is the current diversion.
+ Otherwise, the current diversion is a macro diversion, so call
+ its `print_diversion_trap()` member function.
+
+ * doc/groff.texi.in (Diversion Traps, Debugging):
+ * man/groff.7.man (Request short reference):
+ * man/groff_diff.7.man (New requests): Document it.
+
+ * src/roff/groff/tests/pwh-request-works.sh: Unit-test request.
+ * src/roff/groff/groff.am (groff_TESTS): Run test.
+
+ Fixes <https://savannah.gnu.org/bugs/?68358>.
+
2026-05-17 G. Branden Robinson <[email protected]>
* src/roff/troff/input.cpp (char_list::get): De-optimize read
diff --git a/doc/groff.texi.in b/doc/groff.texi.in
index a59de62f4..fc73250ca 100644
--- a/doc/groff.texi.in
+++ b/doc/groff.texi.in
@@ -19542,6 +19542,10 @@ request.
A diversion is not formatted in the context of a page, so it lacks page
location traps; instead it can have a @dfn{diversion trap}. There can
exist at most one such vertical position trap per diversion.
+Use the
+@code{pwh}
+request to dump the properties of a diversion trap
+to the standard error stream.@footnote{@xref{Debugging}.}
@Defreq {dt, [@Var{dist} @Var{name}]}
@cindex @code{.t} register, and diversions
@@ -22593,16 +22597,23 @@ represents an empty list.
@cindex listing page location traps (@code{pwh})
@cindex traps, page location, dumping (@code{pwh})
@cindex traps, page location, listing (@code{pwh})
-Report the names and positions of all page location traps to the
-standard error stream. GNU @command{troff} reports empty slots in the
-list, where a trap had been planted but subsequently (re)moved, because
-they can affect the visibility of subsequently planted traps.
+If the top-level diversion is the current diversion,
+report the names and positions of all page location traps
+to the standard error stream.
+GNU
+@command{troff} @c GNU
+reports empty slots in the list,
+where a trap had been planted but subsequently (re)moved,
+because they can affect the visibility of subsequently planted traps.
@c "because they can affect the priority of subsequently planted traps."
@c XXX Is that right? It's useful to print the empty slots, I think,
@c but a trap planted in an "empty" slot with .wh will become active.
@c The slot seems to act as an immobile dummy list head, but does not
@c change the basic list semantics. .wh plants a trap at the head of
@c the trap list at a location, and .ch plants a trap at the tail.
+Otherwise,
+similarly report the name and position of the diversion trap,
+if any.
@endDefreq
@Defreq {fl, }
diff --git a/man/groff.7.man b/man/groff.7.man
index 3cfa5d4ff..e65b5d564 100644
--- a/man/groff.7.man
+++ b/man/groff.7.man
@@ -4968,8 +4968,13 @@ and its mode
.
.TPx
.REQ .pwh
-Report names and positions of all page location traps to the standard
-error stream.
+If the top-level diversion is the current diversion,
+report the names and positions of all page location traps
+to the standard error stream.
+.
+Otherwise,
+similarly report the name and position of the diversion trap,
+if any.
.
.TPx
.REQ .pvs
diff --git a/man/groff_diff.7.man b/man/groff_diff.7.man
index 38f9afc42..80edb721c 100644
--- a/man/groff_diff.7.man
+++ b/man/groff_diff.7.man
@@ -4181,18 +4181,20 @@ and its mode
.
.TP
.B .pwh
-Report the names and vertical positions,
-in basic units,
-of all page location traps
+If the top-level diversion is the current diversion,
+report the names and positions of all page location traps
to the standard error stream.
.
GNU
.I troff \" GNU
reports empty slots in the list,
-where a trap had been planted
-but subsequently (re)moved,
+where a trap had been planted but subsequently (re)moved,
because they can affect the visibility of subsequently planted traps.
.
+Otherwise,
+similarly report the name and position of the diversion trap,
+if any.
+.
.
.TP
.BI .pvs \~\[+-]n
diff --git a/src/roff/groff/groff.am b/src/roff/groff/groff.am
index ce7362f4b..6175e1859 100644
--- a/src/roff/groff/groff.am
+++ b/src/roff/groff/groff.am
@@ -130,6 +130,7 @@ groff_TESTS = \
src/roff/groff/tests/pnr-request-works.sh \
src/roff/groff/tests/po-request-works.sh \
src/roff/groff/tests/ps-device-smoke-test.sh \
+ src/roff/groff/tests/pwh-request-works.sh \
src/roff/groff/tests/recognize-end-of-sentence.sh \
src/roff/groff/tests/regression_savannah_56555.sh \
src/roff/groff/tests/regression_savannah_58153.sh \
diff --git a/src/roff/groff/tests/pwh-request-works.sh
b/src/roff/groff/tests/pwh-request-works.sh
new file mode 100755
index 000000000..52f412ef7
--- /dev/null
+++ b/src/roff/groff/tests/pwh-request-works.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+#
+# Copyright 2026 G. Branden Robinson
+#
+# This file is part of groff, the GNU roff typesetting system.
+#
+# groff 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 3 of the License, or
+# (at your option) any later version.
+#
+# groff is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# 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, see <http://www.gnu.org/licenses/>.
+
+groff="${abs_top_builddir:-.}/test-groff"
+
+fail=
+
+wail () {
+ echo "...FAILED"
+ fail=yes
+}
+
+input='.
+.de PAGE-LOCATION-TRAP
+.tm SPROING
+..
+.de DIVERSION-TRAP
+.tm BOING
+..
+.wh 10v PAGE-LOCATION-TRAP
+.pwh
+.di DIVERSION
+.tm inside diversion; reporting traps
+.pwh
+.tm setting diversion trap
+.dt 2v DIVERSION-TRAP
+.pwh
+.nf
+foo
+bar
+.tm diversion trap should have sprung; reporting traps
+.pwh
+.tm clearing diversion trap and reporting again
+.dt
+.pwh
+.di
+.tm outside diversion; reporting traps
+.pwh
+.'
+
+# Expected error stream output:
+# 1 PAGE-LOCATION-TRAP 120000
+# 2 inside diversion; reporting traps
+# 3 setting diversion trap
+# 4 DIVERSION-TRAP 24000
+# 5 BOING
+# 6 diversion trap should have sprung; reporting traps
+# 7 DIVERSION-TRAP 24000
+# 8 clearing diversion trap and reporting again
+# 9 outside diversion; reporting traps
+# 10 PAGE-LOCATION-TRAP 120000
+
+error=$(printf '%s\n' "$input" | "$groff" 2>&1 >/dev/null | nl -ba \
+ | tr '\t' ' ')
+echo "$error"
+
+echo "checking initial report of page location traps" >&2
+echo "$error" | grep -qx " *1 *PAGE-LOCATION-TRAP *[0-9]*" || wail
+
+echo "checking initial report of diversion trap" >&2
+echo "$error" | grep -qx " *4 *DIVERSION-TRAP *[0-9]*" || wail
+
+echo "checking subsequent report of diversion trap" >&2
+echo "$error" | grep -qx " *7 *DIVERSION-TRAP *[0-9]*" || wail
+
+echo "checking subsequent report of page location traps" >&2
+echo "$error" | grep -qx " *10 *PAGE-LOCATION-TRAP *[0-9]*" || wail
+
+test -z "$fail"
+
+# vim:set autoindent expandtab shiftwidth=4 tabstop=4 textwidth=72:
diff --git a/src/roff/troff/div.cpp b/src/roff/troff/div.cpp
index ceb383a18..555e1be22 100644
--- a/src/roff/troff/div.cpp
+++ b/src/roff/troff/div.cpp
@@ -1,5 +1,5 @@
/* Copyright 1989-2020 Free Software Foundation, Inc.
- 2020-2025 G. Branden Robinson
+ 2020-2026 G. Branden Robinson
Written by James Clark ([email protected])
@@ -977,6 +977,14 @@ void macro_diversion::clear_diversion_trap()
diversion_trap = NULL_SYMBOL;
}
+void macro_diversion::print_diversion_trap()
+{
+ if (diversion_trap != NULL_SYMBOL)
+ errprint("%1\t%2\n", diversion_trap.contents(),
+ diversion_trap_pos.to_units());
+ fflush(stderr);
+}
+
void top_level_diversion::set_diversion_trap(symbol, vunits)
{
error("cannot set diversion trap when not diverting output");
@@ -987,6 +995,12 @@ void top_level_diversion::clear_diversion_trap()
error("cannot clear diversion trap when not diverting output");
}
+void top_level_diversion::print_diversion_trap()
+{
+ assert(0 == "attempting to report diversion trap"
+ " of top-level diversion");
+}
+
static void diversion_trap_request() // .dt
{
vunits n;
@@ -1025,7 +1039,10 @@ static void change_trap_request() // .ch
static void print_traps_request() // .pwh
{
- topdiv->print_traps();
+ if (topdiv == curdiv)
+ topdiv->print_traps();
+ else
+ curdiv->print_diversion_trap();
skip_line();
}
diff --git a/src/roff/troff/div.h b/src/roff/troff/div.h
index c3257d2d9..bbc8c371a 100644
--- a/src/roff/troff/div.h
+++ b/src/roff/troff/div.h
@@ -62,6 +62,7 @@ public:
const char *get_diversion_name() { return nm.contents(); }
virtual void set_diversion_trap(symbol, vunits) = 0;
virtual void clear_diversion_trap() = 0;
+ virtual void print_diversion_trap() = 0;
virtual void copy_file(const char *filename) = 0;
};
@@ -87,6 +88,7 @@ public:
const char *get_next_trap_name();
void set_diversion_trap(symbol, vunits);
void clear_diversion_trap();
+ void print_diversion_trap();
void copy_file(const char *filename);
};
@@ -146,6 +148,7 @@ public:
friend void page_offset();
void set_diversion_trap(symbol, vunits);
void clear_diversion_trap();
+ void print_diversion_trap();
void set_last_page() { last_page_count = page_count; }
};
_______________________________________________
groff-commit mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/groff-commit