If a column list starts with implicit rows (that is, rows without .It)
authorschwarze <schwarze@openbsd.org>
Sat, 20 Aug 2016 14:43:39 +0000 (14:43 +0000)
committerschwarze <schwarze@openbsd.org>
Sat, 20 Aug 2016 14:43:39 +0000 (14:43 +0000)
and roff-level nodes (e.g. tbl or eqn) follow, don't run into an
assertion.  Instead, wrap the roff-level nodes in their own row.
Issue found by tb@ with afl(1).

regress/usr.bin/mandoc/mdoc/Bl/Makefile
regress/usr.bin/mandoc/mdoc/Bl/colNoIt.in [new file with mode: 0644]
regress/usr.bin/mandoc/mdoc/Bl/colNoIt.out_ascii [new file with mode: 0644]
regress/usr.bin/mandoc/tbl/macro/Makefile
regress/usr.bin/mandoc/tbl/macro/column.in [new file with mode: 0644]
regress/usr.bin/mandoc/tbl/macro/column.out_ascii [new file with mode: 0644]
usr.bin/mandoc/mdoc.c
usr.bin/mandoc/mdoc_validate.c

index 9c74055..a40a282 100644 (file)
@@ -1,7 +1,7 @@
-# $OpenBSD: Makefile,v 1.29 2015/10/12 15:27:53 schwarze Exp $
+# $OpenBSD: Makefile,v 1.30 2016/08/20 14:43:39 schwarze Exp $
 
 REGRESS_TARGETS  = item inset diag ohang bullet dash enum hang tag
-REGRESS_TARGETS += column extend nested offset secstart
+REGRESS_TARGETS += column colNoIt extend nested offset secstart
 
 REGRESS_TARGETS += notype multitype badargs
 REGRESS_TARGETS += empty noIt emptyhead emptytag emptyitem multitag
@@ -23,7 +23,7 @@ LINT_TARGETS  += bareIt bareTa break breakingIt broken
 
 SKIP_GROFF ?= notype empty break breakingIt broken emptytag
 
-SKIP_TMAN ?= column multitype multitag bareTa break broken
+SKIP_TMAN ?= column colNoIt multitype multitag bareTa break broken
 
 # Fixing the indentation in long .IP and .TP tags in -man -Tascii
 # caused a minor regression in -Tman that is not trivial to fix,
diff --git a/regress/usr.bin/mandoc/mdoc/Bl/colNoIt.in b/regress/usr.bin/mandoc/mdoc/Bl/colNoIt.in
new file mode 100644 (file)
index 0000000..7c80cf9
--- /dev/null
@@ -0,0 +1,15 @@
+.Dd August 20, 2016
+.Dt BL-COLNOIT 1
+.Os OpenBSD
+.Sh NAME
+.Nm Bl-colNoIt
+.Nd column lists without item macros
+.Sh DESCRIPTION
+.Bl -column "a" "b"
+.Sy a Ta b
+.Em c Ta d
+.El
+.Bl -column "a" "b"
+a      b
+c      d
+.El
diff --git a/regress/usr.bin/mandoc/mdoc/Bl/colNoIt.out_ascii b/regress/usr.bin/mandoc/mdoc/Bl/colNoIt.out_ascii
new file mode 100644 (file)
index 0000000..e61c333
--- /dev/null
@@ -0,0 +1,13 @@
+BL-COLNOIT(1)               General Commands Manual              BL-COLNOIT(1)
+
+N\bNA\bAM\bME\bE
+     B\bBl\bl-\b-c\bco\bol\blN\bNo\boI\bIt\bt - column lists without item macros
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+     a\ba    b
+     _\bc    d
+
+     a    b
+     c    d
+
+OpenBSD                         August 20, 2016                        OpenBSD
index 25e415f..70ec1b3 100644 (file)
@@ -1,11 +1,12 @@
-# $OpenBSD: Makefile,v 1.1.1.1 2015/01/29 23:24:24 schwarze Exp $
+# $OpenBSD: Makefile,v 1.2 2016/08/20 14:43:40 schwarze Exp $
 
-REGRESS_TARGETS         = man nested
+REGRESS_TARGETS         = man nested column
 LINT_TARGETS    = man nested
 
-# trivial difference to groff-1.22.3:
+# trivial differences to groff-1.22.3:
 # .TS in a table causes a blank table line in GNU tbl(1), but not in mandoc.
+# .TS in a column list causes a blank line in mandoc, but not in GNU tbl(1).
 
-SKIP_GROFF      = nested
+SKIP_GROFF      = nested column
 
 .include <bsd.regress.mk>
diff --git a/regress/usr.bin/mandoc/tbl/macro/column.in b/regress/usr.bin/mandoc/tbl/macro/column.in
new file mode 100644 (file)
index 0000000..511025e
--- /dev/null
@@ -0,0 +1,16 @@
+.Dd August 20, 2016
+.Dt TBL-COLUMN 1
+.Os OpenBSD
+.Sh NAME
+.Nm TBL-column
+.Nd tables inside column lists
+.Sh DESCRIPTION
+.Bl -column "a" "b"
+.Sy a Ta b
+.TS
+lll.
+1      2       3
+4      5       6
+.TE
+.Em c Ta d
+.El
diff --git a/regress/usr.bin/mandoc/tbl/macro/column.out_ascii b/regress/usr.bin/mandoc/tbl/macro/column.out_ascii
new file mode 100644 (file)
index 0000000..b4428aa
--- /dev/null
@@ -0,0 +1,13 @@
+TBL-COLUMN(1)               General Commands Manual              TBL-COLUMN(1)
+
+N\bNA\bAM\bME\bE
+     T\bTB\bBL\bL-\b-c\bco\bol\blu\bum\bmn\bn - tables inside column lists
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+     a\ba    b
+     1   2   3
+     4   5   6
+
+     _\bc    d
+
+OpenBSD                         August 20, 2016                        OpenBSD
index 56ae0c9..407f6bb 100644 (file)
@@ -1,7 +1,7 @@
-/*     $OpenBSD: mdoc.c,v 1.145 2015/10/30 19:03:36 schwarze Exp $ */
+/*     $OpenBSD: mdoc.c,v 1.146 2016/08/20 14:43:39 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2016 Ingo Schwarze <schwarze@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -217,29 +217,19 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
        struct roff_node *n;
        char             *c, *ws, *end;
 
-       assert(mdoc->last);
        n = mdoc->last;
 
        /*
-        * Divert directly to list processing if we're encountering a
-        * columnar ROFFT_BLOCK with or without a prior ROFFT_BLOCK entry
-        * (a ROFFT_BODY means it's already open, in which case we should
-        * process within its context in the normal way).
+        * If a column list contains plain text, assume an implicit item
+        * macro.  This can happen one or more times at the beginning
+        * of such a list, intermixed with non-It mdoc macros and with
+        * nodes generated on the roff level, for example by tbl.
         */
 
-       if (n->tok == MDOC_Bl && n->type == ROFFT_BODY &&
-           n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) {
-               /* `Bl' is open without any children. */
-               mdoc->flags |= MDOC_FREECOL;
-               mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
-               return 1;
-       }
-
-       if (n->tok == MDOC_It && n->type == ROFFT_BLOCK &&
-           NULL != n->parent &&
-           MDOC_Bl == n->parent->tok &&
-           LIST_column == n->parent->norm->Bl.type) {
-               /* `Bl' has block-level `It' children. */
+       if ((n->tok == MDOC_Bl && n->type == ROFFT_BODY &&
+            n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) ||
+           (n->parent != NULL && n->parent->tok == MDOC_Bl &&
+            n->parent->norm->Bl.type == LIST_column)) {
                mdoc->flags |= MDOC_FREECOL;
                mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
                return 1;
@@ -391,36 +381,23 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
         * into macro processing.
         */
 
-       if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok) {
-               mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
-               return 1;
-       }
-
        n = mdoc->last;
-       assert(mdoc->last);
-
-       /*
-        * If the first macro of a `Bl -column', open an `It' block
-        * context around the parsed macro.
-        */
-
-       if (n->tok == MDOC_Bl && n->type == ROFFT_BODY &&
-           n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) {
-               mdoc->flags |= MDOC_FREECOL;
-               mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
+       if (n == NULL || tok == MDOC_It || tok == MDOC_El) {
+               mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
                return 1;
        }
 
        /*
-        * If we're following a block-level `It' within a `Bl -column'
-        * context (perhaps opened in the above block or in ptext()),
-        * then open an `It' block context around the parsed macro.
+        * If a column list contains a non-It macro, assume an implicit
+        * item macro.  This can happen one or more times at the
+        * beginning of such a list, intermixed with text lines and
+        * with nodes generated on the roff level, for example by tbl.
         */
 
-       if (n->tok == MDOC_It && n->type == ROFFT_BLOCK &&
-           NULL != n->parent &&
-           MDOC_Bl == n->parent->tok &&
-           LIST_column == n->parent->norm->Bl.type) {
+       if ((n->tok == MDOC_Bl && n->type == ROFFT_BODY &&
+            n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) ||
+           (n->parent != NULL && n->parent->tok == MDOC_Bl &&
+            n->parent->norm->Bl.type == LIST_column)) {
                mdoc->flags |= MDOC_FREECOL;
                mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
                return 1;
index 9d69b6f..d1d9bb4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mdoc_validate.c,v 1.223 2016/08/11 11:39:19 schwarze Exp $ */
+/*     $OpenBSD: mdoc_validate.c,v 1.224 2016/08/20 14:43:39 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2016 Ingo Schwarze <schwarze@openbsd.org>
@@ -1320,11 +1320,41 @@ post_bl(POST_ARGS)
                return;
        }
        while (nchild != NULL) {
+               nnext = nchild->next;
                if (nchild->tok == MDOC_It ||
                    (nchild->tok == MDOC_Sm &&
-                    nchild->next != NULL &&
-                    nchild->next->tok == MDOC_It)) {
-                       nchild = nchild->next;
+                    nnext != NULL && nnext->tok == MDOC_It)) {
+                       nchild = nnext;
+                       continue;
+               }
+
+               /*
+                * In .Bl -column, the first rows may be implicit,
+                * that is, they may not start with .It macros.
+                * Such rows may be followed by nodes generated on the
+                * roff level, for example .TS, which cannot be moved
+                * out of the list.  In that case, wrap such roff nodes
+                * into an implicit row.
+                */
+
+               if (nchild->prev != NULL) {
+                       mdoc->last = nchild;
+                       mdoc->next = ROFF_NEXT_SIBLING;
+                       roff_block_alloc(mdoc, nchild->line,
+                           nchild->pos, MDOC_It);
+                       roff_head_alloc(mdoc, nchild->line,
+                           nchild->pos, MDOC_It);
+                       mdoc->next = ROFF_NEXT_SIBLING;
+                       roff_body_alloc(mdoc, nchild->line,
+                           nchild->pos, MDOC_It);
+                       while (nchild->tok != MDOC_It) {
+                               mdoc_node_relink(mdoc, nchild);
+                               if ((nchild = nnext) == NULL)
+                                       break;
+                               nnext = nchild->next;
+                               mdoc->next = ROFF_NEXT_SIBLING;
+                       }
+                       mdoc->last = nbody;
                        continue;
                }
 
@@ -1340,13 +1370,11 @@ post_bl(POST_ARGS)
                nblock  = nbody->parent;
                nprev   = nblock->prev;
                nparent = nblock->parent;
-               nnext   = nchild->next;
 
                /*
                 * Unlink this child.
                 */
 
-               assert(nchild->prev == NULL);
                nbody->child = nnext;
                if (nnext == NULL)
                        nbody->last  = NULL;