From 37dca223f8adbfb62ab71687a8b3f306804295c8 Mon Sep 17 00:00:00 2001
From: Ingo Schwarze <schwarze@openbsd.org>
Date: Mon, 7 Nov 2011 01:24:40 +0000
Subject: [PATCH] When the HEAD scope of .TP is broken by another block macro,
 do not abort with a FATAL error, but report a report a WARNING, remove the
 broken .TP from the syntax tree, and prod on. Reported repeatedly by ports
 people, at least by brad@ and jeremy@. Also fixes rendition(4) in Xenocara.
 ok kristaps@

---
 TODO           |  8 ++------
 libman.h       |  3 ++-
 man.c          | 31 +++++++++++++++++++++++++++++--
 man_macro.c    | 24 ++++++++++++------------
 man_validate.c | 37 +++++++++++--------------------------
 mandoc.h       |  3 +--
 read.c         |  3 +--
 7 files changed, 58 insertions(+), 51 deletions(-)

diff --git a/TODO b/TODO
index 231db2ed..c29922aa 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,6 @@
 ************************************************************************
 * Official mandoc TODO.
-* $Id: TODO,v 1.122 2011/09/20 14:20:48 schwarze Exp $
+* $Id: TODO,v 1.123 2011/11/07 01:24:40 schwarze Exp $
 ************************************************************************
 
 ************************************************************************
@@ -12,11 +12,6 @@
   and then triggers an unknown macro error
   reported by naddy@  Sun, 3 Jul 2011 21:52:24 +0200
 
-- .TP before .SH is still FATAL in man(7)
-  reported by brad@  Sat, 15 Jan 2011 15:54:54 -0500
-  also occurs in emulators/pcsxr/patches/patch-doc_pcsx_1
-  jeremy@  commit Wed, 7 Sep 2011 10:00:19 -0600 (MDT)
-
 ************************************************************************
 * formatter bugs
 ************************************************************************
@@ -192,6 +187,7 @@
   .It Em Authentication<tab>Key Length
   ought to render "Key Length" with emphasis, too,
   see OpenBSD iked.conf(5).
+  reported again Nicolas Joly via wiz@ Wed, 12 Oct 2011 00:20:00 +0200
 
 - empty phrases in .Bl column produce too few blanks
   try e.g. .Bl -column It Ta Ta
diff --git a/libman.h b/libman.h
index cacb0275..4bc51282 100644
--- a/libman.h
+++ b/libman.h
@@ -1,4 +1,4 @@
-/*	$Id: libman.h,v 1.54 2011/09/18 14:14:15 schwarze Exp $ */
+/*	$Id: libman.h,v 1.55 2011/11/07 01:24:40 schwarze Exp $ */
 /*
  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -54,6 +54,7 @@ struct	man_macro {
 #define	MAN_FSCOPED	 (1 << 2)	/* See blk_imp(). */
 #define	MAN_NSCOPED	 (1 << 3)	/* See in_line_eoln(). */
 #define	MAN_NOCLOSE	 (1 << 4)	/* See blk_exp(). */
+#define	MAN_BSCOPE	 (1 << 5)	/* Break BLINE scope. */
 };
 
 extern	const struct man_macro *const man_macros;
diff --git a/man.c b/man.c
index 17e002b4..a901c82c 100644
--- a/man.c
+++ b/man.c
@@ -1,4 +1,4 @@
-/*	$Id: man.c,v 1.112 2011/10/06 22:29:12 kristaps Exp $ */
+/*	$Id: man.c,v 1.113 2011/11/07 01:24:40 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -543,12 +543,39 @@ man_pmacro(struct man *m, int ln, char *buf, int offs)
 			n = n->parent;
 
 		mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line, 
-				n->pos, "%s", man_macronames[n->tok]);
+		    n->pos, "%s breaks %s", man_macronames[tok],
+		    man_macronames[n->tok]);
 
 		man_node_delete(m, n);
 		m->flags &= ~MAN_ELINE;
 	}
 
+	/*
+	 * Remove prior BLINE macro that is being clobbered.
+	 */
+	if ((m->flags & MAN_BLINE) &&
+	    (MAN_BSCOPE & man_macros[tok].flags)) {
+		n = m->last;
+		assert(MAN_TEXT != n->type);
+
+		/* Remove element that didn't end BLINE, if any. */
+
+		if ( ! (MAN_BSCOPE & man_macros[n->tok].flags))
+			n = n->parent;
+
+		assert(MAN_HEAD == n->type);
+		n = n->parent;
+		assert(MAN_BLOCK == n->type);
+		assert(MAN_SCOPED & man_macros[n->tok].flags);
+
+		mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line, 
+		    n->pos, "%s breaks %s", man_macronames[tok],
+		    man_macronames[n->tok]);
+
+		man_node_delete(m, n);
+		m->flags &= ~MAN_BLINE;
+	}
+
 	/*
 	 * Save the fact that we're in the next-line for a block.  In
 	 * this way, embedded roff instructions can "remember" state
diff --git a/man_macro.c b/man_macro.c
index 90037b89..a08adf62 100644
--- a/man_macro.c
+++ b/man_macro.c
@@ -1,4 +1,4 @@
-/*	$Id: man_macro.c,v 1.65 2011/09/18 14:14:15 schwarze Exp $ */
+/*	$Id: man_macro.c,v 1.66 2011/11/07 01:24:40 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -52,15 +52,15 @@ static	void		 rew_warn(struct man *,
 
 const	struct man_macro __man_macros[MAN_MAX] = {
 	{ in_line_eoln, MAN_NSCOPED }, /* br */
-	{ in_line_eoln, 0 }, /* TH */
-	{ blk_imp, MAN_SCOPED }, /* SH */
-	{ blk_imp, MAN_SCOPED }, /* SS */
-	{ blk_imp, MAN_SCOPED | MAN_FSCOPED }, /* TP */
-	{ blk_imp, 0 }, /* LP */
-	{ blk_imp, 0 }, /* PP */
-	{ blk_imp, 0 }, /* P */
-	{ blk_imp, 0 }, /* IP */
-	{ blk_imp, 0 }, /* HP */
+	{ in_line_eoln, MAN_BSCOPE }, /* TH */
+	{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */
+	{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */
+	{ blk_imp, MAN_BSCOPE | MAN_SCOPED | MAN_FSCOPED }, /* TP */
+	{ blk_imp, MAN_BSCOPE }, /* LP */
+	{ blk_imp, MAN_BSCOPE }, /* PP */
+	{ blk_imp, MAN_BSCOPE }, /* P */
+	{ blk_imp, MAN_BSCOPE }, /* IP */
+	{ blk_imp, MAN_BSCOPE }, /* HP */
 	{ in_line_eoln, MAN_SCOPED }, /* SM */
 	{ in_line_eoln, MAN_SCOPED }, /* SB */
 	{ in_line_eoln, 0 }, /* BI */
@@ -74,8 +74,8 @@ const	struct man_macro __man_macros[MAN_MAX] = {
 	{ in_line_eoln, 0 }, /* RI */
 	{ in_line_eoln, MAN_NSCOPED }, /* na */
 	{ in_line_eoln, MAN_NSCOPED }, /* sp */
-	{ in_line_eoln, 0 }, /* nf */
-	{ in_line_eoln, 0 }, /* fi */
+	{ in_line_eoln, MAN_BSCOPE }, /* nf */
+	{ in_line_eoln, MAN_BSCOPE }, /* fi */
 	{ blk_close, 0 }, /* RE */
 	{ blk_exp, MAN_EXPLICIT }, /* RS */
 	{ in_line_eoln, 0 }, /* DT */
diff --git a/man_validate.c b/man_validate.c
index 5ab775ac..d39618ff 100644
--- a/man_validate.c
+++ b/man_validate.c
@@ -1,4 +1,4 @@
-/*	$Id: man_validate.c,v 1.77 2011/11/03 20:48:52 schwarze Exp $ */
+/*	$Id: man_validate.c,v 1.78 2011/11/07 01:24:40 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org>
@@ -44,7 +44,6 @@ struct	man_valid {
 	v_check	 *posts;
 };
 
-static	int	  check_bline(CHKARGS);
 static	int	  check_eq0(CHKARGS);
 static	int	  check_le1(CHKARGS);
 static	int	  check_ge2(CHKARGS);
@@ -76,20 +75,19 @@ static	v_check	  posts_sec[] = { post_sec, NULL };
 static	v_check	  posts_sp[] = { post_vs, check_le1, NULL };
 static	v_check	  posts_th[] = { check_ge2, check_le5, post_TH, NULL };
 static	v_check	  posts_uc[] = { post_UC, NULL };
-static	v_check	  pres_bline[] = { check_bline, NULL };
-static	v_check	  pres_sec[] = { check_bline, pre_sec, NULL};
+static	v_check	  pres_sec[] = { pre_sec, NULL };
 
 static	const struct man_valid man_valids[MAN_MAX] = {
 	{ NULL, posts_br }, /* br */
-	{ pres_bline, posts_th }, /* TH */
+	{ NULL, posts_th }, /* TH */
 	{ pres_sec, posts_sec }, /* SH */
 	{ pres_sec, posts_sec }, /* SS */
-	{ pres_bline, NULL }, /* TP */
-	{ pres_bline, posts_par }, /* LP */
-	{ pres_bline, posts_par }, /* PP */
-	{ pres_bline, posts_par }, /* P */
-	{ pres_bline, NULL }, /* IP */
-	{ pres_bline, NULL }, /* HP */
+	{ NULL, NULL }, /* TP */
+	{ NULL, posts_par }, /* LP */
+	{ NULL, posts_par }, /* PP */
+	{ NULL, posts_par }, /* P */
+	{ NULL, NULL }, /* IP */
+	{ NULL, NULL }, /* HP */
 	{ NULL, NULL }, /* SM */
 	{ NULL, NULL }, /* SB */
 	{ NULL, NULL }, /* BI */
@@ -103,8 +101,8 @@ static	const struct man_valid man_valids[MAN_MAX] = {
 	{ NULL, NULL }, /* RI */
 	{ NULL, posts_eq0 }, /* na */ /* FIXME: should warn only. */
 	{ NULL, posts_sp }, /* sp */ /* FIXME: should warn only. */
-	{ pres_bline, posts_nf }, /* nf */
-	{ pres_bline, posts_fi }, /* fi */
+	{ NULL, posts_nf }, /* nf */
+	{ NULL, posts_fi }, /* fi */
 	{ NULL, NULL }, /* RE */
 	{ NULL, posts_part }, /* RS */
 	{ NULL, NULL }, /* DT */
@@ -351,19 +349,6 @@ check_par(CHKARGS)
 }
 
 
-static int
-check_bline(CHKARGS)
-{
-
-	assert( ! (MAN_ELINE & m->flags));
-	if (MAN_BLINE & m->flags) {
-		man_nmsg(m, n, MANDOCERR_SYNTLINESCOPE);
-		return(0);
-	}
-
-	return(1);
-}
-
 static int
 post_TH(CHKARGS)
 {
diff --git a/mandoc.h b/mandoc.h
index d80098e3..01d6df2e 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -1,4 +1,4 @@
-/*	$Id: mandoc.h,v 1.96 2011/10/06 22:29:12 kristaps Exp $ */
+/*	$Id: mandoc.h,v 1.97 2011/11/07 01:24:40 schwarze Exp $ */
 /*
  * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -150,7 +150,6 @@ enum	mandocerr {
 	MANDOCERR_NOTMANUAL, /* manual isn't really a manual */
 	MANDOCERR_COLUMNS, /* column syntax is inconsistent */
 	MANDOCERR_BADDISP, /* NOT IMPLEMENTED: .Bd -file */
-	MANDOCERR_SYNTLINESCOPE, /* line scope broken, syntax violated */
 	MANDOCERR_SYNTARGVCOUNT, /* argument count wrong, violates syntax */
 	MANDOCERR_SYNTCHILD, /* child violates parent syntax */
 	MANDOCERR_SYNTARGCOUNT, /* argument count wrong, violates syntax */
diff --git a/read.c b/read.c
index ab2a7347..2e66757b 100644
--- a/read.c
+++ b/read.c
@@ -1,4 +1,4 @@
-/*	$Id: read.c,v 1.25 2011/10/08 15:42:29 kristaps Exp $ */
+/*	$Id: read.c,v 1.26 2011/11/07 01:24:40 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
@@ -192,7 +192,6 @@ static	const char * const	mandocerrs[MANDOCERR_MAX] = {
 	"not a manual",
 	"column syntax is inconsistent",
 	"NOT IMPLEMENTED: .Bd -file",
-	"line scope broken, syntax violated",
 	"argument count wrong, violates syntax",
 	"child violates parent syntax",
 	"argument count wrong, violates syntax",
-- 
2.47.1