gbranden pushed a commit to branch master in repository groff. commit 54fb0303cfd59873dd9dc8aab3a47f1e7eff1341 Author: G. Branden Robinson <g.branden.robin...@gmail.com> AuthorDate: Tue Jul 15 23:15:56 2025 -0500
[man]: Fix Savannah #67363 (2/4). Make man page rendering more robust against meddling with the adjustment mode by individual pages. In part this is to ensure that meddling doesn't persist outside the meddlesome document when rendering multiple pages, but it also makes user preferences more reliably discernible. Prompted by a discussion with Russ Allbery in late 2023. * tmac/an.tmac ([initialization]): When rendering a man page, this macro file is read before any man(7) document: therefore, when interpreting a man page package macro file for the first time (which we know thanks to the `andoc*is-initialized` register), if the `AD` string is set, we know it was specified on the command line or by the "man.local" file. Stash its value in new string `andoc*AD` so it can be recovered after meddling by the document. (an*reset-adjustment-mode): New macro assumes responsibility for configuring adjustment. Accept an argument, and if valid, assign its contents to the `AD` string. (an*reset-paragraph-parameters): Stop manipulating adjustment in favor of calling the new macro. (TH): Remove the potentially page-local `AD` string when starting a new document, and call `an*reset-adjustment-mode` interpolating `andoc*AD` as an argument to impose the user's preference (or the package default) at each new document. * tmac/tests/an_adjustment-mode-restoration-works.sh: Add test to verify preservation of document- and user-selected adjustment mode. * tmac/tmac.am (tmac_TESTS): Run test. Fixes <https://savannah.gnu.org/bugs/?67363> (2/4). Thanks to Russ Allbery for posing the challenge. --- ChangeLog | 35 +++++++ tmac/an.tmac | 56 ++++++++++- tmac/tests/an_adjustment-mode-restoration-works.sh | 103 +++++++++++++++++++++ tmac/tmac.am | 1 + 4 files changed, 191 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index f48f133ec..d39d27264 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,38 @@ +2025-07-27 G. Branden Robinson <g.branden.robin...@gmail.com> + + [man]: Make man page rendering more robust against meddling with + the adjustment mode by individual pages. In part this is to + ensure that meddling doesn't persist outside the meddlesome + document when rendering multiple pages, but it also makes user + preferences more reliably discernible. Prompted by a discussion + with Russ Allbery in late 2023. + + * tmac/an.tmac ([initialization]): When rendering a man page, + this macro file is read before any man(7) document: therefore, + when interpreting a man page package macro file for the first + time (which we know thanks to the `andoc*is-initialized` + register), if the `AD` string is set, we know it was specified + on the command line or by the "man.local" file. Stash its value + in new string `andoc*AD` so it can be recovered after meddling + by the document. + (an*reset-adjustment-mode): New macro assumes responsibility for + configuring adjustment. Accept an argument, and if valid, + assign its contents to the `AD` string. + (an*reset-paragraph-parameters): Stop manipulating adjustment in + favor of calling the new macro. + (TH): Remove the potentially page-local `AD` string when + starting a new document, and call `an*reset-adjustment-mode` + interpolating `andoc*AD` as an argument to impose the user's + preference (or the package default) at each new document. + + * tmac/tests/an_adjustment-mode-restoration-works.sh: Add test + to verify preservation of document- and user-selected adjustment + mode. + * tmac/tmac.am (tmac_TESTS): Run test. + + Fixes <https://savannah.gnu.org/bugs/?67363> (2/4). Thanks to + Russ Allbery for posing the challenge. + 2025-07-27 G. Branden Robinson <g.branden.robin...@gmail.com> [man]: Make man page rendering more robust against meddling with diff --git a/tmac/an.tmac b/tmac/an.tmac index d85f0458b..93d2001d7 100644 --- a/tmac/an.tmac +++ b/tmac/an.tmac @@ -152,6 +152,49 @@ . vs \\n[VS]u .. . +.\" Resetting the adjustment mode is a complicated dance. +.\" 1. Man pages sometimes disable adjustment--when they do, they +.\" often forget to put it back the way it was. +.\" 2. When they do remember to put it back, they often fail to do +.\" so correctly because of the `ad` request's quirky semantics +.\" starting from Seventh Edition Unix troff/nroff. Briefly, the +.\" `ad` request without arguments turns adjustment back on after +.\" an `na` even if the previous adjustment mode was `l` (align to +.\" the left with NO adjustment). +.\" 3. The default adjustment mode historically has not been +.\" predictable; it can depend on nroff vs. troff mode and on the +.\" vendor of the *roff system in use. +.\" 4. It's possible (and portable) to obtain the previous adjustment +.\" mode via the `.j` register so that it can be saved prior to +.\" meddling and restored later, but in practice man page authors +.\" neglect to do so. +.\" 5. groff man(7)'s `AD` string isn't supported everywhere. +.\" 6. We want user preferences, if expressed, to override the page +.\" author's. +.\" 7. Even if we didn't want (6), one page author's can override +.\" another's when formatting multiple man(7) documents in +.\" sequence--we thus keep track of the initial adjustment mode. +.\" +.\" So we recover the "page's" preferred adjustment mode, if expressed +.\" via `AD`, at every paragraph (and (sub)sectioning) macro call; and +.\" recover the user's preferred adjustment mode at each new document by +.\" accepting it as an argument (see the `TH` macro definition). Also +.\" see the initialization logic below. +.\" +.\" This macro is at pains to distinguish alignment from adjustment. +.de an*reset-adjustment-mode +. if \\n[.$] .ds AD \\$1\" +. nr an*want-adjustment 1 +. if d AD .if '\?\\*[AD]\?'\?l\?' .nr an*want-adjustment 0 +. if d AD .if '\?\\*[AD]\?'\?c\?' .nr an*want-adjustment 0 +. if d AD .if '\?\\*[AD]\?'\?r\?' .nr an*want-adjustment 0 +. ie \\n[an*want-adjustment] .ds an*adjustment-mode b +. el .ds an*adjustment-mode \\*[AD] +. ad \\*[an*adjustment-mode] +. rm an*adjustment-mode +. rr an*want-adjustment +.. +. .\" Resetting the hyphenation mode is a complicated dance. .\" 1. Man pages sometimes disable automatic hyphenation--when they .\" do, they nearly always forget to put it back the way it was. @@ -198,8 +241,7 @@ .\" between (P, LP, PP, HP) and (IP, TP) paragraphs. .de an*reset-paragraph-parameters . an*reset-text-parameters -. ie d AD .ad \\*[AD] -. el .ad b +. an*reset-adjustment-mode . an*reset-hyphenation-mode .. . @@ -309,10 +351,13 @@ . nr an-was-tbl-failure-reported 0 . . \" When rendering multiple documents, we want to clear any page-local -. \" manipulation of hyphenation mode from the previous document. +. \" manipulation of hyphenation and adjustment modes from the previous +. \" document. . rr HY +. rm AD . . an*reset-hyphenation-mode \\n[andoc*HY] +. an*reset-adjustment-mode \\*[andoc*AD] . an*reset-section-parameters . an*reset-paragraph-parameters . ll \\n[LL]u @@ -1474,10 +1519,13 @@ contains unsupported escape sequence .ie d msoquiet .msoquiet man.local .el .mso man.local . -.\" Save `HY` value configured by {man,mdoc}.local or command line. +.\" Save `HY` value and `AD` contents configured by {man,mdoc}.local or +.\" command line. .if !r andoc*is-initialized \{\ . ie r HY .nr andoc*HY \n[HY] . el .nr andoc*HY 1 +. ie d AD .ds andoc*AD \*[AD]\" +. el .ds andoc*AD b\" . nr andoc*is-initialized 1 .\} . diff --git a/tmac/tests/an_adjustment-mode-restoration-works.sh b/tmac/tests/an_adjustment-mode-restoration-works.sh new file mode 100755 index 000000000..ad613edce --- /dev/null +++ b/tmac/tests/an_adjustment-mode-restoration-works.sh @@ -0,0 +1,103 @@ +#!/bin/sh +# +# Copyright (C) 2025 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" + +fail= + +wail() { + echo ...FAILED >&2 + fail=yes +} + +input='. +.TH foo 1 2025-07-15 "groff test suite" +.ds AD l +.SH Name +foo \- a command with a very short name +.SH Description +This paragraph should not be adjusted. +Sed ut perspiciatis, unde omnis iste natus error sit voluptatem +accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab +illo inventore veritatis et quasi architecto beatae vitae dicta sunt, +explicabo. +.P +This paragraph should also not be adjusted. +Ut enim ad minima veniam, quis nostrum exercitationem ullam +corporis suscipitlaboriosam suscipitlaboriosam suscipitlaboriosam, +nisi ut aliquid ex ea commodi consequatur? +.TH bar 1 2025-07-15 "groff test suite" +.SH Name +bar \- another command with a very short name +.SH Description +This paragraph should be adjusted. +Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur +aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione +voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, +quia dolor sit amet consectetur adipiscivelit, sed quia non-numquam eius +modi tempora incidunt, ut labore et dolore magnam aliquam quaerat +voluptatem. +.ds AD b \" attempt to meddle with next document +.TH baz 1 2025-07-27 "groff test suite" +baz \- you guessed it +.SH Description +This paragraph should not be adjusted. +Quis autem vel eum iure reprehenderit, qui inea voluptate velit esse, +quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo +voluptas nulla pariatur? +.' + +# A line length of 70 makes adjustment obvious on the first line of +# paragraph text in each "Description". +output=$(printf "%s\n" "$input" \ + | "$groff" -rLL=70n -man -T ascii -P -cbou) +echo "$output" + +echo "checking that the first document's first paragraph is not" \ + "adjusted" >&2 +echo "$output" | grep -q 'totam rem aperiam eaque ipsa' || wail + +echo "checking that the first document's second paragraph is not" \ + "adjusted" >&2 +echo "$output" | grep -q 'ullam corporis suscipitlabo-' || wail + +echo "checking that the second document's paragraph is adjusted" >&2 +# Be robust to adjustment parity value. +if ! echo "$output" | grep -Eq 'Nemo enim +ipsam +voluptatem,' \ + && ! echo "$output" | grep -Eq 'This +paragraph +should +be' +then + wail +fi + +output=$(printf "%s\n" "$input" \ + | "$groff" -dAD=l -rLL=78n -man -T ascii -P -cbou) +echo "$output" + +echo "checking that the third document's paragraph is not adjusted" \ + "when disabled by user" >&2 +# Be robust to adjustment parity value. +if ! echo "$output" | grep -q 'vel illum,' \ + && ! echo "$output" | grep -q 'nulla pariatur\?' +then + wail +fi + +test -z "$fail" + +# vim:set ai et sw=4 ts=4 tw=72: diff --git a/tmac/tmac.am b/tmac/tmac.am index 4d0482e10..303103653 100644 --- a/tmac/tmac.am +++ b/tmac/tmac.am @@ -164,6 +164,7 @@ tmac_TESTS = \ tmac/tests/an_X-register-works.sh \ tmac/tests/an_adjust-link-text-correctly.sh \ tmac/tests/an_adjustment-mode-preserved-after-paragraph-tag.sh \ + tmac/tests/an_adjustment-mode-restoration-works.sh \ tmac/tests/an_avoid-two-font-denial-of-service.sh \ tmac/tests/an_degenerate-documents-work.sh \ tmac/tests/an_do-not-abbreviate-escape-using-TH-arguments.sh \ _______________________________________________ groff-commit mailing list groff-commit@gnu.org https://lists.gnu.org/mailman/listinfo/groff-commit