gbranden pushed a commit to branch master
in repository groff.

commit 190d01502ec8f8caab05bd3eb11ee04411c1e332
Author: G. Branden Robinson <[email protected]>
AuthorDate: Mon Mar 4 00:14:39 2024 -0600

    Revert "[troff]: Fix Savannah #64484."
    
    This reverts commit 9dbf227a5b3870a19c1e6d90e5b619c4ae3e7f3e.
    
    Reopens Savannah #64484.
    
    Test src/roff/groff/tests/device-control-special-character-handling.sh
    fails at this commit.
---
 ChangeLog                | 26 -----------------
 NEWS                     | 17 ------------
 doc/groff.texi.in        | 31 +++++++++++----------
 man/groff.7.man          |  3 +-
 src/roff/troff/input.cpp | 72 +++++++++++++++++++++++-------------------------
 5 files changed, 52 insertions(+), 97 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 0ffdd0403..af982750a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1170,32 +1170,6 @@
        necessary.  Restores the ability for some PDF viewers to accept
        "#label" as suffix to the file name.
 
-2024-01-13  G. Branden Robinson <[email protected]>
-
-       [troff]: Fix Savannah #64484.
-
-       * src/roff/troff/input.cpp (encode_char_for_troff_output):
-       Annotate the function's purpose.  Initially assume the character
-       to be encoded as valid.  If the current token is a plain space,
-       write a space (U+0020) to the output.  (This is necessary
-       because the `device` request no longer reads its arguments in
-       copy mode; see below.)  Move the `sc` local variable to a higher
-       scope.  Update the new `is_char_valid` Boolean instead of
-       issuing an error diagnostic at each point of validation failure.
-       When done processing the character, test `is_char_valid` and
-       emit different diagnostics depending on whether the input was a
-       special character escape sequence we can't handle, or something
-       else.  Emit a self-quoted escape character _as a backslash_, not
-       as the current *roff escape character.
-       (device_request): Rewrite to operate in interpretation mode, not
-       copy mode.
-
-       * doc/groff.texi (Postprocessor Access):
-       * man/groff.7.man (Request short reference):
-       * NEWS: Document it.
-
-       Fixes <https://savannah.gnu.org/bugs/?64484>.
-
 2024-01-13  G. Branden Robinson <[email protected]>
 
        * src/roff/groff/tests/\
diff --git a/NEWS b/NEWS
index b1d8f65b4..168e802da 100644
--- a/NEWS
+++ b/NEWS
@@ -84,23 +84,6 @@ o The read-only registers `.m` and `.M` now interpolate 
"default" when
   the default color is selected as the stroke or fill color,
   respectively, rather than interpolating nothing.
 
-o The `device` request no longer reads its arguments in copy mode; this
-  change makes it more consistent with the `\X` device control command
-  escape sequence.
-
-o The `device` request and `\X` escape sequence no longer emit a
-  self-quoted *roff escape character as itself, but instead as a
-  backslash, because troff's input and output languges are not the same
-  thing, and to avoid the need to extend the *roff output language to
-  support a configurable escape character.
-
-  This and the previous change are to enable postprocessors to reliably
-  interpret device control commands that wish to express arbitrary
-  character sequences (using whatever escaping convention they prefer)
-  without requiring different syntax for the arguments to the `device`
-  request and `\X` escape sequences.  For example, PDF bookmarks need to
-  be expressed in UTF-16LE.
-
 eqn
 ---
 
diff --git a/doc/groff.texi.in b/doc/groff.texi.in
index f80a21650..dda99b83a 100644
--- a/doc/groff.texi.in
+++ b/doc/groff.texi.in
@@ -16542,18 +16542,15 @@ returned by the function @cite{getenv@r{(3)}}.
 @cindex access to postprocessor
 
 Two escape sequences and two requests enable documents to pass
-information directly to an output driver or other postprocessor.  These
-are useful for exercising device-specific capabilities that the
-@code{groff} language does not abstract or generalize; examples include
-the embedding of hyperlinks and image files.  Device-specific functions
-are documented in each output driver's man page, such as
-@cite{gropdf@r{(1)}}, @cite{grops@r{(1)}}, or @cite{grotty@r{(1)}}.
+information directly to a postprocessor.  These are useful for
+exercising device-specific capabilities that the @code{groff} language
+does not abstract or generalize; examples include the embedding of
+hyperlinks and image files.  Device-specific functions are documented in
+each output driver's man page, such as @cite{gropdf@r{(1)}},
+@cite{grops@r{(1)}}, or @cite{grotty@r{(1)}}.
 
 @DefreqList {device, [@code{"}]@Var{contents}}
-@c XXX: Can't mark the parameters with @Var because @Var gets called
-@c recursively if we do.
-@c @DefescListEndx {\\X, @code{'}, @Var{contents}, @code{'}}
-@DefescListEndx {\\X, @code{'}, contents, @code{'}}
+@DefescListEndx {\\X, @code{'}, contents @r{@dots{}}, @code{'}}
 Embed @var{contents} into GNU @command{troff} output as parameters to an
 @w{@samp{x X}} device control command.@footnote{@xref{gtroff Output}.}
 The interpretation of such parameters is determined by the output driver
@@ -16562,6 +16559,12 @@ or other postprocessor.
 The @code{device} request strips a leading neutral double quote from
 @var{contents} to allow embedding of leading spaces.
 
+@cindex @code{device} request, and copy mode
+@cindex copy mode, and @code{device} request
+@cindex mode, copy, and @code{device} request
+The @code{device} request processes its arguments in copy mode
+(@pxref{Copy Mode}).  An initial neutral double quote in @var{contents}
+is stripped to allow embedding of leading spaces.
 @cindex @code{\&}, in device control commands
 @cindex @code{\)}, in device control commands
 @cindex @code{\%}, in device control commands
@@ -16571,7 +16574,7 @@ The @code{device} request strips a leading neutral 
double quote from
 @ifinfo
 @cindex @code{\@r{<colon>}}, in device control commands
 @end ifinfo
-Within a device control command, the escape sequences @code{\&},
+By contrast, within @code{\X} arguments, the escape sequences @code{\&},
 @code{\)}, @code{\%}, and @code{\:} are ignored; @code{\@key{SPC}} and
 @code{\~} are converted to single space characters; and a self-escaped
 escape character is output as a backslash @code{\}.  So that the basic
@@ -16584,10 +16587,8 @@ characters; see the @cite{groff_char@r{(7)}} man page. 
 For this
 transformation, character translations and special character definitions
 are ignored.@footnote{They are bypassed because these parameters are not
 rendered as glyphs in the output; instead, they remain abstract
-characters---in a PDF bookmark or a URL, for example.}
-
-Escape sequences other than the foregoing in device control command
-may be ignored, or produce an error.
+characters---in a PDF bookmark or a URL, for example.}  The use of any
+other escape sequence in @code{\X} parameters is normally an error.
 
 A device control command issued with the @code{device} request will not
 be reflected in the output unless a partially collected line exists at
diff --git a/man/groff.7.man b/man/groff.7.man
index 0c0a8f7f0..0278e0df2 100644
--- a/man/groff.7.man
+++ b/man/groff.7.man
@@ -3008,7 +3008,8 @@ with compatibility mode disabled when the macro is 
interpreted.
 .TPx
 .REQ .device contents
 Write
-.I contents
+.IR contents ,
+read in copy mode,
 to
 .I @g@troff
 output as a device control command.
diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp
index c1f22b5d9..fdf14d0f1 100644
--- a/src/roff/troff/input.cpp
+++ b/src/roff/troff/input.cpp
@@ -5616,19 +5616,14 @@ static node *do_non_interpreted()
   return new non_interpreted_node(mac);
 }
 
-// In troff output, we translate the escape character to '\', but it is
-// up to the postprocessor to interpret it as such.  (This mostly
-// matters for device control commands.)
 static void encode_char_for_troff_output(macro *mac, const char c)
 {
-  bool is_char_valid = true;
-  const char *sc = 0 /* nullptr */;
   if ('\0' == c) {
-    if (tok.is_space()
-       || tok.is_stretchable_space()
-       || tok.is_unstretchable_space())
+    if (tok.is_stretchable_space()
+            || tok.is_unstretchable_space())
       mac->append(' ');
     else if (tok.is_special()) {
+      const char *sc;
       if (font::use_charnames_in_special) {
        charinfo *ci = tok.get_char(true /* required */);
        sc = ci->get_symbol()->contents();
@@ -5662,34 +5657,29 @@ static void encode_char_for_troff_output(macro *mac, 
const char c)
            mac->append(']');
          }
          else
-           is_char_valid = false;
+           error("special character '%1' cannot be used within a"
+                 " device control escape sequence", sc);
        }
        else
-         is_char_valid = false;
+         error("special character '%1' cannot be used within a device"
+               " control escape sequence", sc);
       }
     }
     else if (tok.is_hyphen_indicator()
               || tok.is_dummy()
               || tok.is_transparent_dummy()
               || tok.is_zero_width_break())
-      /* silently ignore */;
-    else
-      is_char_valid = false;
-    if (!is_char_valid) {
-      if (sc != 0 /* nullptr */)
-       error("special character '%1' is invalid within a device"
-             " control command", sc);
-      else
-       error("%1 is invalid within a device control command",
-             tok.description());
-    }
+      error("%1 is invalid within device control escape sequence",
+           tok.description());
   }
   else {
-    if (c == escape_char) {
-      mac->append('\\');
-    }
-    else
+    if ((font::use_charnames_in_special) && ('\\' == c)) {
+      /*
+       * add escape escape sequence
+       */
       mac->append(c);
+    }
+    mac->append(c);
   }
 }
 
@@ -5733,28 +5723,34 @@ static node *do_special()
 
 static void device_request()
 {
-  if (!has_arg()) {
-    warning(WARN_MISSING, "device request expects arguments");
-    skip_line();
-    return;
+  // We can't use `has_arg()` here because we want to read in copy mode.
+  int c;
+  for (;;) {
+    c = input_stack::peek();
+    if (' ' == c)
+      (void) get_copy(0 /* nullptr */);
+    else
+      break;
   }
-  if (tok.is_newline() || tok.is_eof()) {
-    warning(WARN_MISSING, "device request expects arguments");
+  if (('\n' == c) || (EOF == c)) {
+    warning(WARN_MISSING, "device control request expects arguments");
     skip_line();
     return;
   }
-  if ('"' == tok.ch()) {
-    tok.next();
-  }
   macro mac;
   for (;;) {
-    if (tok.is_newline() || tok.is_eof())
+    c = get_copy(0 /* nullptr */);
+    if ('"' == c) {
+      c = get_copy(0 /* nullptr */);
+      break;
+    }
+    if (c != ' ' && c != '\t')
       break;
-    encode_char_for_troff_output(&mac, tok.ch());
-    tok.next();
   }
+  for (; c != '\n' && c != EOF; c = get_copy(0 /* nullptr */))
+    mac.append(c);
   curenv->add_node(new special_node(mac));
-  skip_line();
+  tok.next();
 }
 
 static void device_macro_request()

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

Reply via email to