gbranden pushed a commit to branch master
in repository groff.

commit 1f44ea3be31d8ada3bef8197ff0be6ca7f12e700
Author: G. Branden Robinson <[email protected]>
AuthorDate: Fri Jan 2 00:08:38 2026 -0600

    [troff]: Fix Savannah #64300.
    
    * src/roff/troff/div.cpp (space_request): If the `sp` request is invoked
      with the no-break control character (that is, "'sp") when the drawing
      position is off the page (as when the formatter starts up), ignore the
      request and throw an error diagnostic.  This is inconsistent with AT&T
      troffs (including Heirloom Doctools) and neatroff, but precisely
      consistent with all other requests that have different semantics when
      invoked with the no-break control character.  When invoked thus, none
      of `br`, `brp`, `ce`, `cf`, `fi`, `fl`, `in`, `nf`, or `rj` move the
      drawing position onto the page.
    
    * tmac/doc-old.tmac (Sh): If the formatter claims groff compatibility,
      simply emit a `br` request to start the (next) document instead of
      invoking `sp` with the no-break control character.
    
    * doc/groff.texi (Manipulating Spacing): Document that invoking `'sp`
      in the top-level diversion when the vertical drawing position is
      negative is an error.
    
    * doc/groff.texi (Other Differences):
    * man/groff_diff.7.man: (Other differences): Document difference between
      AT&T and GNU troffs.  (AT&T troff's behavior looks buggy to me...)
    
    Fixes <https://savannah.gnu.org/bugs/?64300>.  Thanks to Dave Kemper for
    the discussion.
---
 ChangeLog              | 32 ++++++++++++++++++++++++++++++++
 doc/groff.texi.in      | 35 +++++++++++++++++++++++++++++++++++
 man/groff_diff.7.man   | 25 +++++++++++++++++++++++++
 src/roff/troff/div.cpp |  7 +++++++
 tmac/doc-old.tmac      |  3 ++-
 5 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index 209f7bada..df1316ed2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+2026-01-02  G. Branden Robinson <[email protected]>
+
+       [troff]: Fix Savannah #64300.
+
+       * src/roff/troff/div.cpp (space_request): If the `sp` request is
+       invoked with the no-break control character (that is, "'sp")
+       when the drawing position is off the page (as when the formatter
+       starts up), ignore the request and throw an error diagnostic.
+       This is inconsistent with AT&T troffs (including Heirloom
+       Doctools) and neatroff, but precisely consistent with all other
+       requests that have different semantics when invoked with the
+       no-break control character.  When invoked thus, none of `br`,
+       `brp`, `ce`, `cf`, `fi`, `fl`, `in`, `nf`, or `rj` move the
+       drawing position onto the page.
+
+       * tmac/doc-old.tmac (Sh): If the formatter claims groff
+       compatibility, simply emit a `br` request to start the (next)
+       document instead of invoking `sp` with the no-break control
+       character.
+
+       * doc/groff.texi (Manipulating Spacing): Document that invoking
+       `'sp` in the top-level diversion when the vertical drawing
+       position is negative is an error.
+
+       * doc/groff.texi (Other Differences):
+       * man/groff_diff.7.man: (Other differences): Document difference
+       between AT&T and GNU troffs.  (AT&T troff's behavior looks buggy
+       to me...)
+
+       Fixes <https://savannah.gnu.org/bugs/?64300>.  Thanks to Dave
+       Kemper for the discussion.
+
 2026-03-06  G. Branden Robinson <[email protected]>
 
        * src/roff/troff/input.cpp: Add `WARN_ESCAPE` to default warning
diff --git a/doc/groff.texi.in b/doc/groff.texi.in
index 9d8708dde..41291d29b 100644
--- a/doc/groff.texi.in
+++ b/doc/groff.texi.in
@@ -10716,6 +10716,17 @@ moves to a position relative to the page top for 
positive
 and the bottom if
 @var{N}
 is negative.
+
+@cindex invoking @code{sp} request with no-break control character while not 
on a page
+@cindex no-break control character, invoking @code{sp} request with, while not 
on a page
+@cindex control character, no-break, invoking @code{sp} request with, while 
not on a page
+Invoking
+@code{sp}
+with the no-break control character
+while ``not on a page''
+(in the top-level diversion at a negative vertical drawing position)
+is an error.@footnote{See @ref{Page Control} and @ref{Other
+Differences}.}
 @endDefreq
 
 @DefreqList {ls, [@Var{count}]}
@@ -22473,6 +22484,30 @@ the @acronym{JSON}-encoded name,
 contents,
 and other properties of each named argument.
 
+@cindex @code{sp} request, incompatibilities with @acronym{AT&T} @code{troff}
+The
+@code{sp}
+request differs from @acronym{AT&T}
+@command{troff}:@: @c AT&T
+invoking
+@code{sp}
+with the no-break control character
+while ``not on a page''---that is,
+when writing output to the top-level diversion
+while the vertical drawing position reported by register
+@code{nl}
+is negative---provokes an error diagnostic
+and does not move the drawing position.
+@acronym{AT&T}
+@command{troff} @c AT&T
+sets the vertical drawing position
+to two basic units fewer than the specified argument
+(or one vee minus one basic unit if no argument is present).
+@c Yes, really.  Try:
+@c printf '.tm \\n(nl\n.c2 $\n$sp\n.tm \\n(nl\n'
+@c printf '.tm \\n(nl\n.c2 $\n.nr nl -1\n$sp\n.tm \\n(nl\n'
+@c ...with DWB, Plan 9, and Heirloom Doctools troffs. --GBR
+
 @cindex @code{ss} request, incompatibilities with @acronym{AT&T} @code{troff}
 AT&T
 @command{troff} @c AT&T
diff --git a/man/groff_diff.7.man b/man/groff_diff.7.man
index d5b44d245..bfa76526d 100644
--- a/man/groff_diff.7.man
+++ b/man/groff_diff.7.man
@@ -6836,6 +6836,31 @@ and other properties of each named argument.
 .
 .
 .P
+The
+.B sp
+request differs from AT&T
+.IR troff : \" AT&T
+invoking
+.B sp
+with the no-break control character
+while \[lq]not on a page\[rq]\[em]that is,
+when writing output to the top-level diversion
+while the vertical drawing position reported by register
+.B nl
+is negative\[em]provokes an error diagnostic
+and does not move the drawing position.
+AT&T
+.I troff \" AT&T
+sets the vertical drawing position
+to two basic units fewer than the specified argument
+(or one vee minus one basic unit if no argument is present).
+.\" Yes, really.  Try:
+.\" printf '.tm \\n(nl\n.c2 $\n$sp\n.tm \\n(nl\n'
+.\" printf '.tm \\n(nl\n.c2 $\n.nr nl -1\n$sp\n.tm \\n(nl\n'
+.\" ...with DWB, Plan 9, and Heirloom Doctools troffs. --GBR
+.
+.
+.P
 AT&T
 .I troff \" AT&T
 ignores the
diff --git a/src/roff/troff/div.cpp b/src/roff/troff/div.cpp
index a619713f3..c8d09d0c0 100644
--- a/src/roff/troff/div.cpp
+++ b/src/roff/troff/div.cpp
@@ -861,6 +861,13 @@ static void space_request() // .sp
   postpone_traps();
   if (was_invoked_with_regular_control_character)
     curenv->do_break();
+  else if ((curdiv == topdiv)
+           && (topdiv->before_first_page_status > 0)) {
+    error("cannot vertically space with the no-break control character"
+         " when not on a page");
+    skip_line();
+    return;
+  }
   vunits n;
   if (!has_arg() || !read_vunits(&n, 'v'))
     n = curenv->get_vertical_spacing();
diff --git a/tmac/doc-old.tmac b/tmac/doc-old.tmac
index b58c1f39b..e00495636 100644
--- a/tmac/doc-old.tmac
+++ b/tmac/doc-old.tmac
@@ -1706,7 +1706,8 @@
 .      in 0
 .\}
 .pL
-'sp
+.ie \n(.g .br
+.el 'sp \" erroneous in GNU troff when the page hasn't started
 .ns
 .ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
 .if !\\n(cR .ne 3

_______________________________________________
groff-commit mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/groff-commit

Reply via email to