]> git.cameronkatri.com Git - mandoc.git/commitdiff
Fix three bugs regarding the interaction of \z and \h:
authorIngo Schwarze <schwarze@openbsd.org>
Wed, 27 Apr 2022 13:41:13 +0000 (13:41 +0000)
committerIngo Schwarze <schwarze@openbsd.org>
Wed, 27 Apr 2022 13:41:13 +0000 (13:41 +0000)
1. The combination \z\h is a no-op whatever the argument may be.
In the past, the \z only affected the first space character generated
by the \h, which was wrong.

2. For the conbination \zX\h with a positive argument, the first
space resulting from the \h is not printed but consumed by the \z.

3. For the combination \zX\h with a negative argument, application
of the \z needs to be completed before the \h can be started.
In the past, if this combination occurred at the beginning of an
output line, the \h backed up to the beginning of the line and
after that, the \z attempted to back up even further, triggering
an assertion.

Bugs found during an audit of assignments to termp->col that i
started after the bugfix tbl_term.c rev. 1.65.  The assertion
triggered by bug 3 was *not* yet found by afl(1).

regress/roff/esc/Makefile
regress/roff/esc/hneg.in [new file with mode: 0644]
regress/roff/esc/hneg.out_ascii [new file with mode: 0644]
regress/roff/esc/z.in
regress/roff/esc/z.out_ascii
term.c

index 4c152fc4fa773ad334c26c6dd09cbbe6903f5023..f00aa4d3a9f4df1eb557d2d4660a2578e458e8bb 100644 (file)
@@ -1,8 +1,15 @@
-# $OpenBSD: Makefile,v 1.18 2022/04/13 13:11:33 schwarze Exp $
+# $OpenBSD: Makefile,v 1.19 2022/04/27 13:30:19 schwarze Exp $
 
 
-REGRESS_TARGETS         = one two multi B bs_man bs_mdoc c c_man E1 e f h l O1 o p w z
+REGRESS_TARGETS         = one two multi
+REGRESS_TARGETS        += B bs_man bs_mdoc c c_man E1 e f h hneg l O1 o p w z
 REGRESS_TARGETS        += ignore invalid unsupp
 HTML_TARGETS    = f
 LINT_TARGETS    = B h l O1 w ignore invalid unsupp
 
 REGRESS_TARGETS        += ignore invalid unsupp
 HTML_TARGETS    = f
 LINT_TARGETS    = B h l O1 w ignore invalid unsupp
 
+# mandoc defect:
+# - \h with a negative argument replaces output characters
+#   instead of overstriking them
+
+SKIP_GROFF      = hneg
+
 .include <bsd.regress.mk>
 .include <bsd.regress.mk>
diff --git a/regress/roff/esc/hneg.in b/regress/roff/esc/hneg.in
new file mode 100644 (file)
index 0000000..cd085af
--- /dev/null
@@ -0,0 +1,11 @@
+.\" $OpenBSD: hneg.in,v 1.1 2022/04/27 13:30:19 schwarze Exp $
+.Dd $Mdocdate: April 27 2022 $
+.Dt ESC-HNEG 1
+.Os
+.Sh NAME
+.Nm esc-hneg
+.Nd the roff escape h sequence with a negative argument
+.Sh DESCRIPTION
+simple: >abc\h'-3'd<
+.br
+after z escape: >ab\zc\h'-2'd<
diff --git a/regress/roff/esc/hneg.out_ascii b/regress/roff/esc/hneg.out_ascii
new file mode 100644 (file)
index 0000000..000082f
--- /dev/null
@@ -0,0 +1,10 @@
+ESC-HNEG(1)                 General Commands Manual                ESC-HNEG(1)
+
+N\bNA\bAM\bME\bE
+     e\bes\bsc\bc-\b-h\bhn\bne\beg\bg - the roff escape h sequence with a negative argument
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+     simple: >d<c
+     after z escape: >d<c
+
+OpenBSD                         April 27, 2022                         OpenBSD
index ab4c5ab336e6a5328b4c0c55012ba99354154290..252cfc0bdd53f8e937e285df5af3dc9fc2e56d5a 100644 (file)
@@ -1,5 +1,5 @@
-.\" $OpenBSD: z.in,v 1.3 2017/07/04 14:53:27 schwarze Exp $
-.Dd $Mdocdate: July 4 2017 $
+.\" $OpenBSD: z.in,v 1.4 2022/04/27 13:30:19 schwarze Exp $
+.Dd $Mdocdate: April 27 2022 $
 .Dt ESC-Z 1
 .Os
 .Sh NAME
 .Dt ESC-Z 1
 .Os
 .Sh NAME
@@ -20,6 +20,12 @@ new line<
 .br
 single z with overstrike: >\z\o'ab'c<
 .br
 .br
 single z with overstrike: >\z\o'ab'c<
 .br
+single z with h escape: >\z\h'3'm\z\h'-3'<
+.br
+single z with char and h with positive argument: >\za\h'3'b<
+.br
+single z with char and h with zero argument: >\za\h'0'b<
+.br
 single z near the end of the line: >\z<
 .br
 double z: >\z\zx<
 single z near the end of the line: >\z<
 .br
 double z: >\z\zx<
index da26817633029e705553501640aeed504aa68403..0566c7a66f99101ec1c2a5e8c203cd5f336f6184 100644 (file)
@@ -10,7 +10,10 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
      single z with font escape: >x\bx\bb\bbo\bol\bld\bd<
      single z with nospace escape: > new line<
      single z with overstrike: >a\bb\bc<
      single z with font escape: >x\bx\bb\bbo\bol\bld\bd<
      single z with nospace escape: > new line<
      single z with overstrike: >a\bb\bc<
+     single z with h escape: >m<
+     single z with char and h with positive argument: >a  b<
+     single z with char and h with zero argument: >a\bb<
      single z near the end of the line: ><
      double z: >x\b<
 
      single z near the end of the line: ><
      double z: >x\b<
 
-OpenBSD                          July 4, 2017                          OpenBSD
+OpenBSD                         April 27, 2022                         OpenBSD
diff --git a/term.c b/term.c
index 70ca20c440c57a0cfac04e7a67c9310c42581dec..b7c2363fd8e91858b1cd2f68845bd5ef01357c0c 100644 (file)
--- a/term.c
+++ b/term.c
@@ -1,4 +1,4 @@
-/* $Id: term.c,v 1.285 2022/01/10 18:01:35 schwarze Exp $ */
+/* $Id: term.c,v 1.286 2022/04/27 13:41:13 schwarze Exp $ */
 /*
  * Copyright (c) 2010-2022 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
 /*
  * Copyright (c) 2010-2022 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -628,6 +628,10 @@ term_word(struct termp *p, const char *word)
                                encode(p, "utf8", 4);
                        continue;
                case ESCAPE_HORIZ:
                                encode(p, "utf8", 4);
                        continue;
                case ESCAPE_HORIZ:
+                       if (p->flags & TERMP_BACKAFTER) {
+                               p->flags &= ~TERMP_BACKAFTER;
+                               continue;
+                       }
                        if (*seq == '|') {
                                seq++;
                                uc = -p->col;
                        if (*seq == '|') {
                                seq++;
                                uc = -p->col;
@@ -636,12 +640,22 @@ term_word(struct termp *p, const char *word)
                        if (a2roffsu(seq, &su, SCALE_EM) == NULL)
                                continue;
                        uc += term_hen(p, &su);
                        if (a2roffsu(seq, &su, SCALE_EM) == NULL)
                                continue;
                        uc += term_hen(p, &su);
-                       if (uc > 0) {
+                       if (uc >= 0) {
                                while (uc > 0) {
                                while (uc > 0) {
-                                       bufferc(p, ASCII_NBRSP);
                                        uc -= term_len(p, 1);
                                        uc -= term_len(p, 1);
+                                       if (p->flags & TERMP_BACKBEFORE)
+                                               p->flags &= ~TERMP_BACKBEFORE;
+                                       else
+                                               bufferc(p, ASCII_NBRSP);
                                }
                                }
-                       } else if (p->col > (size_t)(-uc)) {
+                               continue;
+                       }
+                       if (p->flags & TERMP_BACKBEFORE) {
+                               p->flags &= ~TERMP_BACKBEFORE;
+                               assert(p->col > 0);
+                               p->col--;
+                       }
+                       if (p->col >= (size_t)(-uc)) {
                                p->col += uc;
                        } else {
                                uc += p->col;
                                p->col += uc;
                        } else {
                                uc += p->col;