summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2013-10-06 13:32:46 +0000
committerIngo Schwarze <schwarze@openbsd.org>2013-10-06 13:32:46 +0000
commit2bf600fe18958cb7c8e22d9d7989bb68fe489a0f (patch)
tree703342e3aaf6702b6234cd10f798b62abfaf9560
parentf62813aec818d1bcaed673a7433a6d984db22a1c (diff)
downloadmandoc-2bf600fe18958cb7c8e22d9d7989bb68fe489a0f.tar.gz
If there is random stuff inside a .Bl block body before the first .It,
do not throw a FATAL error and do not die, but just throw a WARNING and move the stuff out of the .Bl block. This bug felt completely 2008-ish; meanwhile, such bugs from the Kristaps-doesnt-like-syntax-errors-so-lets-just-give-up--Era are becoming rare, but this was one of the last survivors. Thanks to bentley@ for reminding me to finally fix this.
-rw-r--r--TODO8
-rw-r--r--mdoc_validate.c77
2 files changed, 59 insertions, 26 deletions
diff --git a/TODO b/TODO
index 3f477989..b7eced5a 100644
--- a/TODO
+++ b/TODO
@@ -7,13 +7,7 @@
* crashes
************************************************************************
-- .Bl -tag followed by a text node preceding the first .It should not
- throw a FATAL error, but only a normal ERROR. Putting this into the
- HEAD of an implicit .It might be cleanest, inserting an implicit .Pp
- or just dumping the orphan stuff directly into the BODY of the .Bl
- might be easier to implement, and all options can no doubt be made
- to yield correct (i.e. groff bug-compatible) rendering.
- Anthony J. Bentley on discuss@ Sun, 22 Sep 2013 16:33:21 -0600
+None known.
************************************************************************
* missing features
diff --git a/mdoc_validate.c b/mdoc_validate.c
index 2244cc1b..37dad5f6 100644
--- a/mdoc_validate.c
+++ b/mdoc_validate.c
@@ -1590,32 +1590,71 @@ post_bl_head(POST_ARGS)
static int
post_bl(POST_ARGS)
{
- struct mdoc_node *n;
+ struct mdoc_node *nparent, *nprev; /* of the Bl block */
+ struct mdoc_node *nblock, *nbody; /* of the Bl */
+ struct mdoc_node *nchild, *nnext; /* of the Bl body */
- if (MDOC_HEAD == mdoc->last->type)
- return(post_bl_head(mdoc));
- if (MDOC_BLOCK == mdoc->last->type)
+ nbody = mdoc->last;
+ switch (nbody->type) {
+ case (MDOC_BLOCK):
return(post_bl_block(mdoc));
- if (MDOC_BODY != mdoc->last->type)
+ case (MDOC_HEAD):
+ return(post_bl_head(mdoc));
+ case (MDOC_BODY):
+ break;
+ default:
return(1);
+ }
- for (n = mdoc->last->child; n; n = n->next) {
- switch (n->tok) {
- case (MDOC_Lp):
- /* FALLTHROUGH */
- case (MDOC_Pp):
- mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
- /* FALLTHROUGH */
- case (MDOC_It):
- /* FALLTHROUGH */
- case (MDOC_Sm):
+ nchild = nbody->child;
+ while (NULL != nchild) {
+ if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) {
+ nchild = nchild->next;
continue;
- default:
- break;
}
- mdoc_nmsg(mdoc, n, MANDOCERR_SYNTCHILD);
- return(0);
+ mdoc_nmsg(mdoc, nchild, MANDOCERR_CHILD);
+
+ /*
+ * Move the node out of the Bl block.
+ * First, collect all required node pointers.
+ */
+
+ nblock = nbody->parent;
+ nprev = nblock->prev;
+ nparent = nblock->parent;
+ nnext = nchild->next;
+
+ /*
+ * Unlink this child.
+ */
+
+ assert(NULL == nchild->prev);
+ if (0 == --nbody->nchild) {
+ nbody->child = NULL;
+ nbody->last = NULL;
+ assert(NULL == nnext);
+ } else {
+ nbody->child = nnext;
+ nnext->prev = NULL;
+ }
+
+ /*
+ * Relink this child.
+ */
+
+ nchild->parent = nparent;
+ nchild->prev = nprev;
+ nchild->next = nblock;
+
+ nblock->prev = nchild;
+ nparent->nchild++;
+ if (NULL == nprev)
+ nparent->child = nchild;
+ else
+ nprev->next = nchild;
+
+ nchild = nnext;
}
return(1);