gbranden pushed a commit to branch master
in repository groff.
commit 589a724ecae6811a795b661484ef60843565dc8c
Author: G. Branden Robinson <[email protected]>
AuthorDate: Sun Nov 2 13:38:03 2025 -0600
[troff]: Warn on groffish esc seqs in compat mode.
* src/roff/troff/input.cpp (token::next): Throw warnings in category
"syntax" when a document uses GNU troff extension escape sequences
while in compatibility mode.
* doc/groff.texi.in (Warnings):
* src/roff/troff/troff.1.man (Warnings): Document this.
---
ChangeLog | 8 +++++
doc/groff.texi.in | 7 +++--
src/roff/troff/input.cpp | 76 ++++++++++++++++++++++++++++++++++------------
src/roff/troff/troff.1.man | 5 +--
4 files changed, 72 insertions(+), 24 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 522a08a27..2594278a5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2025-11-02 G. Branden Robinson <[email protected]>
+
+ * src/roff/troff/input.cpp (token::next): Throw warnings in
+ category "syntax" when a document uses GNU troff extension
+ escape sequences while in compatibility mode.
+ * doc/groff.texi.in (Warnings):
+ * src/roff/troff/troff.1.man (Warnings): Document this.
+
2025-11-02 G. Branden Robinson <[email protected]>
[troff]: Fix Savannah #67408. As I've observed before in the
diff --git a/doc/groff.texi.in b/doc/groff.texi.in
index 1641b44ac..9ecdd0a4f 100644
--- a/doc/groff.texi.in
+++ b/doc/groff.texi.in
@@ -465,7 +465,7 @@ Documentation License''.
@title groff
@subtitle The GNU implementation of @code{troff}
@subtitle version @VERSION@
-@subtitle October 2025
+@subtitle November 2025
@author Trent@tie{}A.@: Fisher
@author Werner Lemberg
@author G.@tie{}Branden Robinson
@@ -19311,8 +19311,9 @@ empty,
or nonsensical character class;
or a
@code{groff}
-extension conditional expression operator was used
-while in compatibility mode.
+extension escape sequence
+or conditional expression operator
+was used while in compatibility mode.
@item di
@itemx 256
diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp
index bafc62d1b..a1367a30b 100644
--- a/src/roff/troff/input.cpp
+++ b/src/roff/troff/input.cpp
@@ -2280,29 +2280,41 @@ void token::next()
case '^':
goto ESCAPE_CIRCUMFLEX;
case '/':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
type = TOKEN_ITALIC_CORRECTION;
return;
case ',':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
type = TOKEN_NODE;
nd = new left_italic_corrected_node;
return;
case '&':
goto ESCAPE_AMPERSAND;
case ')':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
goto ESCAPE_RIGHT_PARENTHESIS;
case '!':
goto ESCAPE_BANG;
case '?':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
goto ESCAPE_QUESTION;
case '~':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
goto ESCAPE_TILDE;
case ':':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
goto ESCAPE_COLON;
case '"':
while ((cc = input_stack::get(0 /* nullptr */)) != '\n'
@@ -2314,7 +2326,9 @@ void token::next()
type = TOKEN_EOF;
return;
case '#': // Like \" but newline is ignored.
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
while ((cc = input_stack::get(0 /* nullptr */)) != '\n')
if (cc == EOF) {
type = TOKEN_EOF;
@@ -2346,7 +2360,9 @@ void token::next()
type = TOKEN_NODE;
return;
case 'A':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
{
const char *res = do_name_test();
if (0 /* nullptr */ == res)
@@ -2362,7 +2378,9 @@ void token::next()
type = TOKEN_NODE;
return;
case 'B':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
{
const char *res = do_expr_test();
if (0 /* nullptr */ == res)
@@ -2393,7 +2411,9 @@ void token::next()
case 'e':
goto ESCAPE_e;
case 'E':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
goto handle_escape_char;
case 'f':
{
@@ -2403,7 +2423,9 @@ void token::next()
break;
}
case 'F':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
{
curenv->set_family(read_escape_parameter(ALLOW_EMPTY));
have_formattable_input = true;
@@ -2460,13 +2482,17 @@ void token::next()
return;
}
case 'm':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
do_stroke_color(read_escape_parameter(ALLOW_EMPTY));
if (!want_att_compat)
have_formattable_input = true;
break;
case 'M':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
do_fill_color(read_escape_parameter(ALLOW_EMPTY));
if (!want_att_compat)
have_formattable_input = true;
@@ -2491,7 +2517,9 @@ void token::next()
type = TOKEN_NODE;
return;
case 'O':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
nd = do_suppress(read_escape_parameter());
if (0 /* nullptr */ == nd)
break;
@@ -2505,7 +2533,9 @@ void token::next()
nd = new vmotion_node(-curenv->get_size(), curenv->get_fill_color());
return;
case 'R':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
do_register();
if (!want_att_compat)
have_formattable_input = true;
@@ -2538,7 +2568,9 @@ void token::next()
nd = new vmotion_node(x, curenv->get_fill_color());
return;
case 'V':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
{
symbol s = read_escape_parameter();
if (!(s.is_null() || s.is_empty()))
@@ -2561,7 +2593,9 @@ void token::next()
type = TOKEN_NODE;
return;
case 'Y':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
{
symbol s = read_escape_parameter();
if (s.is_null() || s.is_empty())
@@ -2596,7 +2630,9 @@ void token::next()
return;
}
case 'Z':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
nd = do_zero_width_output();
if (0 /* nullptr */ == nd)
break;
@@ -2609,7 +2645,9 @@ void token::next()
case '\n':
break;
case '[':
- // TODO: Reject this GNU troff extension in compatibility mode?
+ if (want_att_compat)
+ warning(WARN_SYNTAX, "an escaped '%1' is not portable to"
+ " AT&T troff", char(cc));
if (!want_att_compat) {
symbol s = read_long_escape_parameters(WITH_ARGS);
if (s.is_null() || s.is_empty())
diff --git a/src/roff/troff/troff.1.man b/src/roff/troff/troff.1.man
index 4e3566e54..e3648507c 100644
--- a/src/roff/troff/troff.1.man
+++ b/src/roff/troff/troff.1.man
@@ -809,8 +809,9 @@ empty,
or nonsensical character class;
or a
.I groff
-extension conditional expression operator was used
-while in compatibility mode.
+extension escape sequence
+or conditional expression operator
+was used while in compatibility mode.
.
.
.TP
_______________________________________________
groff-commit mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/groff-commit