diff --git a/man/groff.7.man b/man/groff.7.man index fc1c958d..bb244ab3 100644 --- a/man/groff.7.man +++ b/man/groff.7.man @@ -3885,6 +3885,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. @@ -3908,6 +3915,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, +holds the saved value of compatibilty 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 35658306..d406b790 100644 --- a/man/groff_diff.7.man +++ b/man/groff_diff.7.man @@ -2760,6 +2760,15 @@ 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 compatibilty mode (see +.B \[rs]n[.C] +above). +. +.TP .B \[rs]n[.csk] The skew of the last glyph added to the current environment. . @@ -3804,6 +3813,104 @@ escape sequence can be helpful in avoiding these escape sequences in names. . .P +The register +.B \[rs]n[.cp] +is specialized and may require a statement of rationale. +. +When writing your own macro packages or documents that use +.I groff +features and will be sourced by others with the +.B .so +request, +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 temporary register, +say, +.BR _C , +at the beginning of your file, +turn compatibility mode off with +.BR .cp\~0 , +then restore it from that register at the end with the +.B .cp +request. +. +At the same time, +a modular design 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 an outer scope. +. +The two-character register namespace of AT&T +.I troff +is confining and mnemonically difficult; +you may wish to use +.IR groff 's +more capacious namespace. +. +However, +attempting +.RS +.RS +.EX +\&.nr _my_saved_C \[rs]n(.C +.EE +.RE +.RE +will not work in compatibility mode; +the register name is too long. +. +\[lq]This is exactly what +.B .do +is for,\[rq] you think. +.RS +.RS +.EX +\&.do nr _my_saved_C \[rs]n(.C +.EE +.RE +.RE +. +The foregoing will always save zero to your register, +because +.B .do +turns compatibility mode off. +. +It will not serve to have +.B .do +report the saved compatibility mode in +.B \[rs]n(.C +for this special case, +because the request can do anything +(except change compatibility mode in its enclosing scope), +including call macros and source files, +and the value of +.B \[rs]n(.C +must be reliable there. +. +What you need is: +.RS +.RS +.EX +\&.do nr _my_saved_C \[rs]n[.cp] +\&.cp 0 +.EE +.RE +.RE +at the beginning of your file, +followed by +.RS +.RS +.EX +\&.cp _my_saved_C +.EE +.RE +.RE +at the end. +. +.P Fractional point sizes cause one noteworthy incompatibility. . In diff --git a/src/roff/groff/groff.am b/src/roff/groff/groff.am index a7999dc0..86f7acd5 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 00000000..2e3fee19 --- /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 . +# + +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 26394ade..7d3b230c 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));