+static void rew_scope(struct roff_man *, enum roff_tok);
+
+static const struct man_macro man_macros[MAN_MAX - MAN_TH] = {
+ { 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 }, /* TP */
+ { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* TQ */
+ { 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 | MAN_JOIN }, /* SM */
+ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SB */
+ { in_line_eoln, 0 }, /* BI */
+ { in_line_eoln, 0 }, /* IB */
+ { in_line_eoln, 0 }, /* BR */
+ { in_line_eoln, 0 }, /* RB */
+ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* R */
+ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* B */
+ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* I */
+ { in_line_eoln, 0 }, /* IR */
+ { in_line_eoln, 0 }, /* RI */
+ { in_line_eoln, MAN_NSCOPED }, /* nf */
+ { in_line_eoln, MAN_NSCOPED }, /* fi */
+ { blk_close, MAN_BSCOPE }, /* RE */
+ { blk_exp, MAN_BSCOPE }, /* RS */
+ { in_line_eoln, 0 }, /* DT */
+ { in_line_eoln, 0 }, /* UC */
+ { in_line_eoln, MAN_NSCOPED }, /* PD */
+ { in_line_eoln, 0 }, /* AT */
+ { in_line_eoln, MAN_NSCOPED }, /* in */
+ { blk_exp, MAN_BSCOPE }, /* SY */
+ { blk_close, MAN_BSCOPE }, /* YS */
+ { in_line_eoln, 0 }, /* OP */
+ { in_line_eoln, MAN_BSCOPE }, /* EX */
+ { in_line_eoln, MAN_BSCOPE }, /* EE */
+ { blk_exp, MAN_BSCOPE }, /* UR */
+ { blk_close, MAN_BSCOPE }, /* UE */
+ { blk_exp, MAN_BSCOPE }, /* MT */
+ { blk_close, MAN_BSCOPE }, /* ME */
+};
+
+
+const struct man_macro *
+man_macro(enum roff_tok tok)
+{
+ assert(tok >= MAN_TH && tok <= MAN_MAX);
+ return man_macros + (tok - MAN_TH);
+}
+
+void
+man_unscope(struct roff_man *man, const struct roff_node *to)
+{
+ struct roff_node *n;
+
+ to = to->parent;
+ n = man->last;
+ while (n != to) {
+
+ /* Reached the end of the document? */
+
+ if (to == NULL && ! (n->flags & NODE_VALID)) {
+ if (man->flags & (MAN_BLINE | MAN_ELINE) &&
+ man_macro(n->tok)->flags & MAN_SCOPED) {
+ mandoc_vmsg(MANDOCERR_BLK_LINE,
+ man->parse, n->line, n->pos,
+ "EOF breaks %s", roff_name[n->tok]);
+ if (man->flags & MAN_ELINE)
+ man->flags &= ~MAN_ELINE;
+ else {
+ assert(n->type == ROFFT_HEAD);
+ n = n->parent;
+ man->flags &= ~MAN_BLINE;
+ }
+ man->last = n;
+ n = n->parent;
+ roff_node_delete(man, man->last);
+ continue;
+ }
+ if (n->type == ROFFT_BLOCK &&
+ man_macro(n->tok)->fp == blk_exp)
+ mandoc_msg(MANDOCERR_BLK_NOEND,
+ man->parse, n->line, n->pos,
+ roff_name[n->tok]);
+ }
+
+ /*
+ * We might delete the man->last node
+ * in the post-validation phase.
+ * Save a pointer to the parent such that
+ * we know where to continue the iteration.
+ */