groff-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[groff] 01/01: Implement new read-only .cp register.


From: G. Branden Robinson
Subject: [groff] 01/01: Implement new read-only .cp register.
Date: Thu, 16 Apr 2020 10:08:52 -0400 (EDT)

gbranden pushed a commit to branch master
in repository groff.

commit 6a37bb5f00d881e50856dc5906f03e64dcacd1ec
Author: G. Branden Robinson <address@hidden>
AuthorDate: Fri Apr 17 00:05:15 2020 +1000

    Implement new read-only .cp register.
    
    The register \n[.cp] is specialized and may require a statement of
    rationale.  When writing macro packages or documents that use groff
    features and which may be mixed with other packages or documents that do
    not—common scenarios include serial processing of man pages or use of
    the .so or .mso requests—you may desire correct operation regardless of
    compatibility mode in the surrounding context.  It may occur to you to
    save the existing value of \n(.C into a register, say, _C, at the
    beginning of your file, turn compatibility mode off with “.cp 0”, then
    restore it from that register at the end with “.cp \n(_C”.  At the same
    time, a modular design of a document or macro package may lead you to
    multiple layers of inclusion.  You cannot use the same register name
    everywhere or you risk “clobbering” the value from a preceding or
    enclosing context.  The two‐character register namespace of AT&T troff
    is confining and mnemonically challenging; you may wish to use groff's
    more capacious namespace.  However, attempting “.nr _my_saved_C \n(.C”
    will not work in compatibility mode; the register name is too long.
    “This is exactly what .do is for,” you think, “.do nr _my_saved_C
    \n(.C”.  The foregoing will always save zero to your register, because
    .do turns compatibility mode off while it interprets its argument list.
    What you need is:
        .do nr _my_saved_C \n[.cp]
        .cp 0
    at the beginning of your file, followed by
        .cp _my_saved_C
    at the end.  As in the C language, we all have to share one big
    namespace, so choose a register name that is unlikely to collide with
    other uses.
    
    * src/roff/troff/input.cpp (do_request, init_input_requests): Implement
      it.
    
    * doc/groff.texi:
    * man/groff.7.man:
    * man/groff_diff.7.man: Document it.
    
    * src/roff/groff/groff.am:
    * src/roff/groff/tests/dot-cp_register_works.sh: Test it.
    
    Enables a fix for <https://savannah.gnu.org/bugs/index.php?58162>.
    
    Thanks to John Gardner and Ingo Schwarze for the discussion.
---
 ChangeLog                                     | 59 +++++++++++++++--
 doc/groff.texi                                | 48 +++++++++++++-
 man/groff.7.man                               | 16 +++++
 man/groff_diff.7.man                          | 93 ++++++++++++++++++++++++++-
 src/roff/groff/groff.am                       |  1 +
 src/roff/groff/tests/dot-cp_register_works.sh | 48 ++++++++++++++
 src/roff/troff/input.cpp                      |  8 ++-
 7 files changed, 264 insertions(+), 9 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index ef3ecf6..5566eea 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,52 @@
+2020-04-16  G. Branden Robinson <address@hidden>
+
+       Implement new read-only .cp register.
+
+       The register \n[.cp] is specialized and may require a statement
+       of rationale.  When writing macro packages or documents that use
+       groff features and which may be mixed with other packages or
+       documents that do not—common scenarios include serial processing
+       of man pages or use of the .so or .mso requests—you may desire
+       correct operation regardless of compatibility mode in the
+       surrounding context.  It may occur to you to save the existing
+       value of \n(.C into a register, say, _C, at the beginning of
+       your file, turn compatibility mode off with “.cp 0”, then
+       restore it from that register at the end with “.cp \n(_C”.  At
+       the same time, a modular design of a document or macro package
+       may lead you to multiple layers of inclusion.  You cannot use
+       the same register name everywhere or you risk “clobbering” the
+       value from a preceding or enclosing context.  The two‐character
+       register namespace of AT&T troff is confining and mnemonically
+       challenging; you may wish to use groff's more capacious
+       namespace.  However, attempting “.nr _my_saved_C \n(.C” will not
+       work in compatibility mode; the register name is too long.
+       “This is exactly what .do is for,” you think, “.do nr
+       _my_saved_C \n(.C”.  The foregoing will always save zero to your
+       register, because .do turns compatibility mode off while it
+       interprets its argument list.  What you need is:
+               .do nr _my_saved_C \n[.cp]
+               .cp 0
+       at the beginning of your file, followed by
+               .cp _my_saved_C
+       at the end.  As in the C language, we all have to share one big
+       namespace, so choose a register name that is unlikely to collide
+       with other uses.
+
+       * src/roff/troff/input.cpp (do_request, init_input_requests):
+       Implement it.
+
+       * doc/groff.texi:
+       * man/groff.7.man:
+       * man/groff_diff.7.man: Document it.
+
+       * src/roff/groff/groff.am:
+       * src/roff/groff/tests/dot-cp_register_works.sh: Test it.
+
+       Enables a fix for
+       <https://savannah.gnu.org/bugs/index.php?58162>.
+
+       Thanks to John Gardner and Ingo Schwarze for the discussion.
+
 2020-04-15  G. Branden Robinson <address@hidden>
 
        * doc/groff.texi:
@@ -154,11 +203,11 @@
        Experimentation reveals that .so, .mso, and .pso requests acted
        as barriers to backtracing except when explicitly requested with
        the .backtrace request.  Judging by the git history, this
-       behavior dates back to June 1991 or earlier.  This did not
-       appear to be intended, according to a source comment, which was
-       only to suppress the backtrace output for the line corresponding
-       to the outermost level of the input stack (commonly, a file
-       argument to groff).  Unfortunately, that wasn't its only effect.
+       behavior dates back to June 1991 or earlier.  The intention,
+       according to a source comment, was only to suppress the
+       backtrace output for the line corresponding to the outermost
+       level of the input stack (commonly, a file argument to groff).
+       Unfortunately, that wasn't its only effect.
 
        This change does result in one additional line of output for
        each error or (non-ignored) warning when -b is given.  However,
diff --git a/doc/groff.texi b/doc/groff.texi
index 5d062be..75b08a5 100644
--- a/doc/groff.texi
+++ b/doc/groff.texi
@@ -14319,7 +14319,8 @@ characters.
 
 @DefreqList {cp, [@Var{n}]}
 @DefreqItemx {do, name}
-@DefregListEndx {.C}
+@DefregItemx {.C}
+@DefregListEndx {.cp}
 If @var{n} is missing or non-zero, turn on compatibility mode;
 otherwise, turn it off.
 
@@ -14361,6 +14362,51 @@ compatibility
 .do mac3 \[ti] \" groff syntax accepted in .do arguments
     @result{} FOO groff FOO compatibility c1 ~
 @endExample
+
+The read-only number register @code{.cp}, meaningful only when
+dereferenced from a @code{.do} request, is@tie{}1 if compatibility mode
+was on when the @code{.do} request was encountered, and 0@tie{}if it
+was not.  This register is specialized and may require a statement of
+rationale.
+
+When writing macro packages or documents that use GNU @code{troff}
+features and which may be mixed with other packages or documents that do
+not---common scenarios include serial processing of man pages or use of
+the @code{so} or @code{mso} requests---you may desire correct operation
+regardless of compatibility mode in the surrounding context.  It may
+occur to you to save the existing value of @samp{\n(.C} into a register,
+say, @samp{_C}, at the beginning of your file, turn compatibility mode
+off with @samp{.cp 0}, then restore it from that register at the end
+with @samp{.cp \n(_C}.  At the same time, a modular design of a document
+or macro package may lead you to multiple layers of inclusion.  You
+cannot use the same register name everywhere or you risk ``clobbering''
+the value from a preceding or enclosing context.  The two-character
+register namespace of @acronym{AT&T} @code{troff} is confining and
+mnemonically challenging; you may wish to use the more capacious
+namespace of GNU @code{troff}.  However, attempting @samp{.nr
+_my_saved_C \n(.C} will not work in compatibility mode; the register
+name is too long.  ``This is exactly what @code{do} is for,'' you think,
+@samp{.do nr _my_saved_C \n(.C}.  The foregoing will always save zero to
+your register, because @code{do} turns compatibility mode @emph{off}
+while it interprets its argument list.  What you need is:
+
+@Example
+.do nr _my_saved_C \n[.cp]
+.cp 0
+@endExample
+
+@noindent
+at the beginning of your file, followed by
+
+@Example
+.cp _my_saved_C
+@endExample
+
+@noindent
+at the end.  As in the C language, we all have to share one big
+namespace, so choose a register name that is unlikely to collide with
+other uses.
+
 @endDefreq
 
 @cindex input level in delimited arguments
diff --git a/man/groff.7.man b/man/groff.7.man
index 33eff7b..6f55ffa 100644
--- a/man/groff.7.man
+++ b/man/groff.7.man
@@ -3897,6 +3897,13 @@ Current input line number.
 .REG .C
 1\~if compatibility mode is in effect, 0\~otherwise.
 .
+Always\~0 in a
+.request .do
+request;
+see
+.register .cp
+below.
+.
 .TPx
 .REG .cdp
 The depth of the last glyph added to the current environment.
@@ -3920,6 +3927,15 @@ It is positive if the glyph extends above the baseline.
 1\~if colors are enabled, 0\~otherwise.
 .
 .TPx
+.REG .cp
+Within a
+.request .do
+request,
+the saved value of compatibility mode (see
+.register .C
+above).
+.
+.TPx
 .REG .csk
 The skew of the last glyph added to the current environment.
 .
diff --git a/man/groff_diff.7.man b/man/groff_diff.7.man
index 79e0345..e23dc8d 100644
--- a/man/groff_diff.7.man
+++ b/man/groff_diff.7.man
@@ -2793,6 +2793,16 @@ It is positive if the glyph extends above the baseline.
 1\~if colors are enabled, 0\~otherwise.
 .
 .TP
+.B \[rs]n[.cp]
+Within a
+.B .do
+request,
+holds the saved value of compatibility mode
+(see
+.B \[rs]n[.C]
+above).
+.
+.TP
 .B \[rs]n[.csk]
 The skew of the last glyph added to the current environment.
 .
@@ -3787,7 +3797,9 @@ and,
 above,
 the
 .B .C
-register
+and
+.B .cp
+registers,
 and
 .B .cp
 and
@@ -3796,6 +3808,85 @@ requests for more on compatibility mode.
 .
 .
 .P
+The register
+.B \[rs]n[.cp]
+is specialized and may require a statement of rationale.
+.
+When writing macro packages or documents that use
+.I groff
+features and which may be mixed with other packages or documents that do
+not\[em]common scenarios include serial processing of man pages or use
+of the
+.B .so
+or
+.B .mso
+requests\[em]you may desire correct operation regardless of
+compatibility mode in the surrounding context.
+.
+It may occur to you to save the existing value of
+.B \[rs]n(.C
+into a register,
+say,
+.BR _C ,
+at the beginning of your file,
+turn compatibility mode off with
+.RB \[lq] .cp\~0 \[rq],
+then restore it from that register at the end with
+.RB \[lq] .cp\~\[rs]n(_C \[rq].
+.
+At the same time,
+a modular design of a document or macro package may lead you to multiple
+layers of inclusion.
+.
+You cannot use the same register name everywhere or you risk
+\[lq]clobbering\[rq] the value from a preceding or enclosing context.
+.
+The two-character register namespace of
+.RI AT&T\~ troff
+is confining and mnemonically challenging;
+you may wish to use
+.IR groff 's
+more capacious namespace.
+.
+However,
+attempting
+.RB \[lq] ".nr _my_saved_C \[rs]n(.C" \[rq]
+will not work in compatibility mode;
+the register name is too long.
+.
+\[lq]This is exactly what
+.B .do
+is for,\[rq] you think,
+.RB \[lq] ".do nr _my_saved_C \[rs]n(.C" \[rq].
+.
+The foregoing will always save zero to your register,
+because
+.B .do
+turns compatibility mode
+.IR off
+while it interprets its argument list.
+.
+What you need is:
+.RS
+.EX
+\&.do nr _my_saved_C \[rs]n[.cp]
+\&.cp 0
+.EE
+.RE
+at the beginning of your file,
+followed by
+.RS
+.EX
+\&.cp _my_saved_C
+.EE
+.RE
+at the end.
+.
+As in the C language,
+we all have to share one big namespace,
+so choose a register name that is unlikely to collide with other uses.
+.
+.P
 Normally,
 .I groff
 preserves the input level in delimited arguments,
diff --git a/src/roff/groff/groff.am b/src/roff/groff/groff.am
index a7999dc..86f7acd 100644
--- a/src/roff/groff/groff.am
+++ b/src/roff/groff/groff.am
@@ -41,6 +41,7 @@ groffoptsdir = $(libprogramdir)
 groffopts_DATA = $(GROFF_OPTS_OUTPUT)
 
 groff_TESTS = \
+  src/roff/groff/tests/dot-cp_register_works.sh \
   src/roff/groff/tests/on_latin1_device_oq_is_0x27.sh \
   src/roff/groff/tests/recognize_end_of_sentence.sh \
   src/roff/groff/tests/regression_savannah_56555.sh \
diff --git a/src/roff/groff/tests/dot-cp_register_works.sh 
b/src/roff/groff/tests/dot-cp_register_works.sh
new file mode 100755
index 0000000..2e3fee1
--- /dev/null
+++ b/src/roff/groff/tests/dot-cp_register_works.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+#
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This file is part of groff.
+#
+# groff is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# groff is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+groff="${abs_top_builddir:-.}/test-groff"
+
+DOC='.pl 1v
+A
+.do if 1 \n[.cp] \" Get initial compatibility state (depends on -C).
+B
+.do if 1 \n[.cp] \" Did observing the state change it?
+.cp 1
+C
+.do if 1 \n[.cp] \" Saved compatibility state should be 1 now.
+.cp 0
+D
+.do if 1 \n[.cp] \" Verify 1->0 transition.
+.cp 1
+E
+.do if 1 \n[.cp] \" Verify 0->1 transition.
+.cp 0
+F
+.if !\n[.C] \n[.cp] \" Outside of .do context, should return -1.
+'
+
+set -e
+
+printf "%s" "$DOC" | "$groff" -Tascii \
+    | grep -x "A 0 B 0 C 1 D 0 E 1 F -1"
+
+printf "%s" "$DOC" | "$groff" -C -Tascii \
+    | grep -x "A 1 B 1 C 1 D 0 E 1 F -1"
diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp
index 26394ad..7d3b230 100644
--- a/src/roff/troff/input.cpp
+++ b/src/roff/troff/input.cpp
@@ -103,6 +103,7 @@ static symbol end_macro_name;
 static symbol blank_line_macro_name;
 static symbol leading_spaces_macro_name;
 static int compatible_flag = 0;
+static int do_old_compatible_flag = -1;        // for .do request
 int ascii_output_flag = 0;
 int suppress_output_flag = 0;
 int is_html = 0;
@@ -2640,14 +2641,16 @@ static void trapping_blank_line()
 
 void do_request()
 {
-  int old_compatible_flag = compatible_flag;
+  assert(do_old_compatible_flag == -1);
+  do_old_compatible_flag = compatible_flag;
   compatible_flag = 0;
   symbol nm = get_name();
   if (nm.is_null())
     skip_line();
   else
     interpolate_macro(nm, 1);
-  compatible_flag = old_compatible_flag;
+  compatible_flag = do_old_compatible_flag;
+  do_old_compatible_flag = -1;
   request_or_macro *p = lookup_request(nm);
   macro *m = p->to_macro();
   if (m)
@@ -8297,6 +8300,7 @@ void init_input_requests()
   number_reg_dictionary.define(".$", new nargs_reg);
   number_reg_dictionary.define(".br", new break_flag_reg);
   number_reg_dictionary.define(".C", new constant_int_reg(&compatible_flag));
+  number_reg_dictionary.define(".cp", new 
constant_int_reg(&do_old_compatible_flag));
   number_reg_dictionary.define(".O", new variable_reg(&begin_level));
   number_reg_dictionary.define(".c", new lineno_reg);
   number_reg_dictionary.define(".color", new constant_int_reg(&color_flag));



reply via email to

[Prev in Thread] Current Thread [Next in Thread]