gbranden pushed a commit to branch master
in repository groff.
commit 2548c4659cf7ceaa43bde7d9b5857a3e1412f553
Author: G. Branden Robinson <[email protected]>
AuthorDate: Sat Sep 21 20:32:04 2024 -0500
[troff]: Interpret spec'l chars in `device` reqs.
* src/roff/troff/input.cpp (device_request): Add extensive new logic to
subvert copy mode so as to interpret special character escape
sequences. We don't yet support _composite_ special character escape
sequences.
* src/roff/groff/tests/device-control-special-character-handling.sh:
Update and expand test cases. Comment out one new case that doesn't
yet work.
This change is in further service of the grueling march toward
resolution of <https://savannah.gnu.org/bugs/?63074>.
What's it called when you put _yourself_ on a death march?
---
ChangeLog | 13 ++++
.../device-control-special-character-handling.sh | 87 ++++++++++++++++++----
src/roff/troff/input.cpp | 50 ++++++++++++-
3 files changed, 131 insertions(+), 19 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 059f74b95..130f94c67 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2024-09-21 G. Branden Robinson <[email protected]>
+
+ * src/roff/troff/input.cpp (device_request): Add extensive new
+ logic to subvert copy mode so as to interpret special character
+ escape sequences. We don't yet support _composite_ special
+ character escape sequences.
+ * src/roff/groff/tests/
+ device-control-special-character-handling.sh: Update and expand
+ test cases. Comment out one new case that doesn't yet work.
+
+ This change is in further service of the grueling march toward
+ resolution of <https://savannah.gnu.org/bugs/?63074>.
+
2024-09-21 G. Branden Robinson <[email protected]>
* src/roff/groff/groff.cpp (main): Clarify verbose output.
diff --git a/src/roff/groff/tests/device-control-special-character-handling.sh
b/src/roff/groff/tests/device-control-special-character-handling.sh
index 62a8c25b3..320fb71ef 100755
--- a/src/roff/groff/tests/device-control-special-character-handling.sh
+++ b/src/roff/groff/tests/device-control-special-character-handling.sh
@@ -100,42 +100,97 @@ echo "$output" | grep -Fqx 'x X bogus5: {||}~' || wail
# A more practical case, suggested by Deri James.
input='.
-.ds h Caf\[e aa] Hyphen-Minus and \[rs]\[u2010]
-\X"ps:exec 1:\\X [/Dest /pdf:bm1 /Title (\*[h]) /Level 1 /OUT pdfmark"
-\!x X ps:exec 2:\! [/Dest /pdf:bm1 /Title (\*[h]) /Level 1 /OUT pdfmark
+.ds h Caf\['"'"'e] Hyphen-Minus and \[rs]\[u2010]
+\X"ps:exec 1:\\X [/Dest /pdf:bm1 /Title (\*[h]) /Level 1 /OUT pdfmark"
+.fl
+\!x X ps:exec 2:\! [/Dest /pdf:bm1 /Title (\*[h]) /Level 1 /OUT pdfmark
.device ps:exec 3:device [/Dest /pdf:bm1 /Title (\*[h]) /Level 1 /OUT pdfmark
+.fl
.output x X ps:exec 4:output [/Dest /pdf:bm1 /Title (\*[h]) /Level 1 /OUT
pdfmark
.'
output=$(printf '%s\n' "$input" | "$groff" -T pdf -Z 2> /dev/null \
| grep '^x X')
-echo "$output"
+error=$(printf '%s\n' "$input" | "$groff" -ww -T pdf -z)
+echo "$error"
+printf "%s\n" "$output"
# Expected:
#
-# x X ps:exec 2:\! [/Dest /pdf:bm1 /Title (Caf\[e aa] Hyphen-Minus and
\[rs]\[u2010]) /Level 1 /OUT pdfmark
-# x X ps:exec 4:output [/Dest /pdf:bm1 /Title (Caf\[e aa] Hyphen-Minus and
\[rs]\[u2010]) /Level 1 /OUT pdfmark
-# x X ps:exec 1:\X [/Dest /pdf:bm1 /Title (Caf\[u00E9] Hyphen-Minus and
\[u2010]) /Level 1 /OUT pdfmark
-# x X ps:exec 3:device [/Dest /pdf:bm1 /Title (Caf\[u00E9] Hyphen-Minus and
\[rs]\[u2010]) /Level 1 /OUT pdfmark
+# x X ps:exec 2:\! [/Dest /pdf:bm1 /Title (Caf\['e] Hyphen-Minus and
\[rs]\[u2010]) /Level 1 /OUT pdfmark
+# x X ps:exec 4:output [/Dest /pdf:bm1 /Title (Caf\['e] Hyphen-Minus and
\[rs]\[u2010]) /Level 1 /OUT pdfmark
+# x X ps:exec 1:\X [/Dest /pdf:bm1 /Title (Caf\[u00E9] Hyphen-Minus and
\\[u2010]) /Level 1 /OUT pdfmark
+# x X ps:exec 3:device [/Dest /pdf:bm1 /Title (Caf\[u00E9] Hyphen-Minus and
\\[u2010]) /Level 1 /OUT pdfmark
echo "checking practical bookmarking with \X escape sequence" >&2
-echo "$output" \
- | grep -q '1:\\X.*(Caf\\\[u00E9\] Hyphen-Minus and \\\[u2010\])' \
+# 5 spaces in the pattern below
+printf "%s\n" "$output" \
+ | grep -Fqx 'x X ps:exec 1:\X [/Dest /pdf:bm1 /Title (Caf\[u00E9]
Hyphen-Minus and \\[u2010]) /Level 1 /OUT pdfmark' \
|| wail
echo "checking practical bookmarking with \! escape sequence" >&2
-echo "$output" \
- | grep -q '2:\\!.*(Caf\\\[e aa\] Hyphen-Minus and \\\[rs\]\\\[u2010\])' \
+# 5 spaces in the pattern below
+printf "%s\n" "$output" \
+ | grep -Fqx 'x X ps:exec 2:\! [/Dest /pdf:bm1 /Title (Caf\['"'"'e]
Hyphen-Minus and \[rs]\[u2010]) /Level 1 /OUT pdfmark' \
+ || wail
+
+echo "checking practical bookmarking with device request" >&2
+printf "%s\n" "$output" \
+ | grep -Fqx 'x X ps:exec 3:device [/Dest /pdf:bm1 /Title (Caf\[u00E9]
Hyphen-Minus and \\[u2010]) /Level 1 /OUT pdfmark' \
+ || wail
+
+echo "checking practical bookmarking with output request" >&2
+printf "%s\n" "$output" \
+ | grep -Fqx 'x X ps:exec 4:output [/Dest /pdf:bm1 /Title (Caf\['"'"'e]
Hyphen-Minus and \[rs]\[u2010]) /Level 1 /OUT pdfmark' \
+ || wail
+
+#test -z "$fail"
+#exit
+
+# Test the same thing, but with a composite special character escape
+# sequence.
+
+input='.
+.ds h Caf\[e aa] Hyphen-Minus and \[rs]\[u2010]
+\X"ps:exec 5:\\X [/Dest /pdf:bm1 /Title (\*[h]) /Level 1 /OUT pdfmark"
+.fl
+\!x X ps:exec 6:\! [/Dest /pdf:bm1 /Title (\*[h]) /Level 1 /OUT pdfmark
+.device ps:exec 7:device [/Dest /pdf:bm1 /Title (\*[h]) /Level 1 /OUT pdfmark
+.fl
+.output x X ps:exec 8:output [/Dest /pdf:bm1 /Title (\*[h]) /Level 1 /OUT
pdfmark
+.'
+
+output=$(printf '%s\n' "$input" | "$groff" -T pdf -Z 2> /dev/null \
+ | grep '^x X')
+error=$(printf '%s\n' "$input" | "$groff" -ww -T pdf -z)
+echo "$error"
+printf "%s\n" "$output"
+
+# Expected:
+#
+# x X ps:exec 6:\! [/Dest /pdf:bm1 /Title (Caf\['e] Hyphen-Minus and
\[rs]\[u2010]) /Level 1 /OUT pdfmark
+# x X ps:exec 8:output [/Dest /pdf:bm1 /Title (Caf\['e] Hyphen-Minus and
\[rs]\[u2010]) /Level 1 /OUT pdfmark
+# x X ps:exec 5:\X [/Dest /pdf:bm1 /Title (Caf\[u00E9] Hyphen-Minus and
\[u2010]) /Level 1 /OUT pdfmark
+# x X ps:exec 7:device [/Dest /pdf:bm1 /Title (Caf\[u00E9] Hyphen-Minus and
\[rs]\[u2010]) /Level 1 /OUT pdfmark
+
+echo "checking practical bookmarking with \X escape sequence" >&2
+printf "%s\n" "$output" \
+ | grep -Fqx 'x X ps:exec 5:\X [/Dest /pdf:bm1 /Title (Caf\[u00E9]
Hyphen-Minus and \\[u2010]) /Level 1 /OUT pdfmark' \
+ || wail
+
+echo "checking practical bookmarking with \! escape sequence" >&2
+printf "%s\n" "$output" \
+ | grep -Fqx 'x X ps:exec 6:\! [/Dest /pdf:bm1 /Title (Caf\[e aa]
Hyphen-Minus and \[rs]\[u2010]) /Level 1 /OUT pdfmark' \
|| wail
#echo "checking practical bookmarking with device request" >&2
-#echo "$output" \
-# | grep -q '3:device.*(Caf\\\[u00E9\] Hyphen-Minus and \\\[rs\]\\\[u2010\])'
\
+#printf "%s\n" "$output" \
+# | grep -Fqx 'x X ps:exec 7:device [/Dest /pdf:bm1 /Title (Caf\[u00E9]
Hyphen-Minus and \\[u2010]) /Level 1 /OUT pdfmark' \
# || wail
echo "checking practical bookmarking with output request" >&2
-echo "$output" \
- | grep -q '4:output.*(Caf\\\[e aa\] Hyphen-Minus and \\\[rs\]\\\[u2010\])' \
+printf "%s\n" "$output" \
+ | grep -Fqx 'x X ps:exec 8:output [/Dest /pdf:bm1 /Title (Caf\[e aa]
Hyphen-Minus and \[rs]\[u2010]) /Level 1 /OUT pdfmark' \
|| wail
test -z "$fail"
diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp
index 7e80bc0c6..670fe2eea 100644
--- a/src/roff/troff/input.cpp
+++ b/src/roff/troff/input.cpp
@@ -5987,9 +5987,53 @@ static void device_request()
// Null characters can correspond to node types like vmotion_node that
// are unrepresentable in a device extension command, and got scrubbed
// by `asciify`.
- for (; c != '\0' && c != '\n' && c != EOF;
- c = get_copy(0 /* nullptr */))
- mac.append(c);
+ for (int prevc = c; (c != '\0') && (c != '\n') && (c != EOF);
+ c = get_copy(0 /* nullptr */)) {
+ if (!('\\' == c) && (prevc != '\\'))
+ mac.append(c);
+ else {
+ int c1 = get_copy(0 /* nullptr */);
+ if (c1 != '[')
+ mac.append(c1);
+ else {
+ // Does the input resemble a valid (bracket-form) special
+ // character escape sequence?
+ bool is_valid = false;
+ string sc = "";
+ string scdup; // for composite character ugliness below
+ int c2 = get_copy(0 /* nullptr */);
+ for (; (c2 != '\0') && (c2 != '\n') && (c2 != EOF);
+ c2 = get_copy(0 /* nullptr */)) {
+ // XXX: `map_special_character_for_device_output()` will need
+ // the closing bracket in the iterator we construct, but a
+ // composite character mapping mustn't see it.
+ sc += c2;
+ if (']' == c2) {
+ is_valid = true;
+ break;
+ }
+ }
+ sc += '\0';
+ if (sc.search(' ') > 0) {
+ // XXX: TODO
+ error("composite special character escape sequences not yet"
+ " supported in device extension command arguments");
+ is_valid = false;
+ }
+ if (is_valid) {
+ input_stack::push(make_temp_iterator(sc.contents()));
+ symbol s = read_long_escape_parameters(WITH_ARGS);
+ map_special_character_for_device_output(&mac, s.contents());
+ }
+ else {
+ // We couldn't make sense of it. Write it out as-is.
+ mac.append(c);
+ mac.append(c1);
+ mac.append_str(sc.contents());
+ }
+ }
+ }
+ }
curenv->add_node(new device_extension_node(mac));
tok.next();
}
_______________________________________________
Groff-commit mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/groff-commit