[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));
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [groff] 01/01: Implement new read-only .cp register.,
G. Branden Robinson <=