Follow-up Comment #30, bug #67571 (group groff): At 2025-12-04T15:07:44-0500, Dave wrote: > Follow-up Comment #29, bug #67571 (group groff): > > [comment #22 comment #22:] >> I do want the formatter to diagnose when the input attempts >> to interpolate a character class in any other context > > I'm in favor of that: it's making groff complain when the user attempts > something that's always been explicitly documented as unsupported.
I just happen to have a patch in my Git stash to do exactly this. :)
diff --git a/src/roff/troff/env.cpp b/src/roff/troff/env.cpp
index 1f4e3c054..c625abab7 100644
--- a/src/roff/troff/env.cpp
+++ b/src/roff/troff/env.cpp
@@ -1683,6 +1683,8 @@ void margin_character()
curenv->margin_character_node = 0 /* nullptr */;
}
}
+ else if (ci->is_class())
+ error("cannot use %1 as a margin character", tok.description());
else {
// Call tok.next() only after making the node so that
// .mc \s+9\(br\s0 works.
@@ -3856,6 +3858,12 @@ static void add_hyphenation_exceptions()
skip_line();
return;
}
+ if (ci->is_class()) {
+ error("cannot use %1 in a hyphenation exception word",
+ tok.description());
+ skip_line();
+ return;
+ }
tok.next();
if (ci->get_ascii_code() == '-') {
if (i > 0 && (npos == 0 || pos[npos - 1] != i))
diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp
index b4333a2b6..bf090f05a 100644
--- a/src/roff/troff/input.cpp
+++ b/src/roff/troff/input.cpp
@@ -1673,8 +1673,15 @@ node *do_overstrike() // \o
delete osnode;
return 0 /* nullptr */;
}
+ else if (ci->is_class()) {
+ error("cannot use %1 in overstrike escape sequence",
+ tok.description());
+ delete osnode;
+ return 0 /* nullptr */;
+ }
else {
node *n = curenv->make_char_node(ci);
+ // XXX add assertion here
if (n != 0 /* nullptr */)
osnode->overstrike(n);
}
@@ -1732,8 +1739,15 @@ static node *do_bracket() // \b
delete bracketnode;
return 0 /* nullptr */;
}
+ else if (ci->is_class()) {
+ error("cannot use %1 in bracket-building escape sequence",
+ tok.description());
+ delete bracketnode;
+ return 0 /* nullptr */;
+ }
else {
node *n = curenv->make_char_node(ci);
+ // XXX add assertion here
if (n != 0 /* nullptr */)
bracketnode->bracket(n);
}
@@ -2633,11 +2647,17 @@ void token::next()
break;
}
node *gn = curenv->make_char_node(ci);
+ // XXX add assertion here
if (0 /* nullptr */ == gn) {
assert("make_char_node failed to create a character"
" node");
break;
}
+ if (ci->is_class()) {
+ error("cannot use %1 as argument to zero-width escape"
+ " sequence", tok.description());
+ break;
+ }
nd = new zero_width_node(gn);
type = TOKEN_NODE;
}
@@ -5933,6 +5953,12 @@ static bool get_line_arg(units *n, unsigned char si,
charinfo **cip)
if (!(start_token == tok
&& input_stack::get_level() == start_level)) {
*cip = tok.get_charinfo(true /* required */);
+ // XXX add assertion here
+ if ((*cip != 0 /* nullptr */) && (*cip)->is_class()) {
+ error("cannot use %1 in line-drawing escape sequence",
+ tok.description());
+ return false;
+ }
tok.next();
}
if (!(start_token == tok
@@ -6276,6 +6302,7 @@ void read_title_parts(node **part, hunits *part_width)
token start(tok);
int start_level = input_stack::get_level();
tok.next();
+ // A title has three parts: "'left'center'right'".
for (int i = 0; i < 3; i++) {
while (!tok.is_newline() && !tok.is_eof()) {
if ((tok == start)
@@ -6473,14 +6500,19 @@ static void
map_special_character_for_device_output(macro *mac,
static void encode_special_character_for_device_output(macro *mac)
{
const char *sc;
- if (font::use_charnames_in_special) {
- charinfo *ci = tok.get_charinfo(true /* required */);
- if (ci != 0 /* nullptr */)
- sc = ci->get_symbol()->contents();
- else
- assert(0 == "attempted to encode token without charinfo for"
- " device extension command output");
+ charinfo *ci = tok.get_charinfo(true /* required */);
+ if (0 /* nullptr */ == ci) {
+ assert(0 == "attempted to encode token without charinfo for"
+ " device extension command output");
+ return;
+ }
+ if (ci->is_class()) {
+ error("cannot encode %1 for device extension command output",
+ tok.description());
+ return;
}
+ if (font::use_charnames_in_special)
+ sc = ci->get_symbol()->contents();
else
sc = tok.get_charinfo(true /* required */)->get_symbol()
->contents();
@@ -8865,6 +8897,18 @@ void token::process()
curenv->space();
break;
case TOKEN_SPECIAL_CHAR:
+ {
+ charinfo *ci = get_charinfo();
+ if (0 /* nullptr */ == ci) {
+ assert(0 == "attempted to interpolate special character token"
+ " without charinfo");
+ break;
+ }
+ if (ci->is_class())
+ error("cannot interpolate %1", description());
+ else
+ curenv->add_char(ci);
+ }
// Optimize `curenv->add_char(get_charinfo())` for token type.
curenv->add_char(lookup_charinfo(nm));
break;
_______________________________________________________
Reply to this item at:
<https://savannah.gnu.org/bugs/?67571>
_______________________________________________
Message sent via Savannah
https://savannah.gnu.org/
signature.asc
Description: PGP signature
