+static void
+rew_scope(struct roff_man *man, enum roff_tok tok)
+{
+ struct roff_node *n;
+
+ /* Preserve empty paragraphs before RS. */
+
+ n = man->last;
+ if (tok == MAN_RS && n->child == NULL &&
+ (n->tok == MAN_P || n->tok == MAN_PP || n->tok == MAN_LP))
+ return;
+
+ for (;;) {
+ if (n->type == ROFFT_ROOT)
+ return;
+ if (n->flags & NODE_VALID) {
+ n = n->parent;
+ continue;
+ }
+ if (n->type != ROFFT_BLOCK) {
+ if (n->parent->type == ROFFT_ROOT) {
+ man_unscope(man, n);
+ return;
+ } else {
+ n = n->parent;
+ continue;
+ }
+ }
+ if (tok != MAN_SH && (n->tok == MAN_SH ||
+ (tok != MAN_SS && (n->tok == MAN_SS ||
+ man_macro(n->tok)->fp == blk_exp))))
+ return;
+ man_unscope(man, n);
+ n = man->last;
+ }
+}
+
+
+/*
+ * Close out a generic explicit macro.
+ */
+void
+blk_close(MACRO_PROT_ARGS)
+{
+ enum roff_tok ctok, ntok;
+ const struct roff_node *nn;
+ char *p;
+ int cline, cpos, nrew, target;
+
+ nrew = 1;
+ switch (tok) {
+ case MAN_RE:
+ ntok = MAN_RS;
+ if ( ! man_args(man, line, pos, buf, &p))
+ break;
+ for (nn = man->last->parent; nn; nn = nn->parent)
+ if (nn->tok == ntok && nn->type == ROFFT_BLOCK)
+ nrew++;
+ target = strtol(p, &p, 10);
+ if (*p != '\0')
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
+ line, p - buf, "RE ... %s", p);
+ if (target == 0)
+ target = 1;
+ nrew -= target;
+ if (nrew < 1) {
+ mandoc_vmsg(MANDOCERR_RE_NOTOPEN, man->parse,
+ line, ppos, "RE %d", target);
+ return;
+ }
+ break;
+ case MAN_YS:
+ ntok = MAN_SY;
+ break;
+ case MAN_UE:
+ ntok = MAN_UR;
+ break;
+ case MAN_ME:
+ ntok = MAN_MT;
+ break;
+ default:
+ abort();
+ }
+
+ for (nn = man->last->parent; nn; nn = nn->parent)
+ if (nn->tok == ntok && nn->type == ROFFT_BLOCK && ! --nrew)
+ break;
+
+ if (nn == NULL) {
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse,
+ line, ppos, roff_name[tok]);
+ rew_scope(man, MAN_PP);
+ return;
+ }
+
+ cline = man->last->line;
+ cpos = man->last->pos;
+ ctok = man->last->tok;
+ man_unscope(man, nn);
+
+ if (tok == MAN_RE && nn->head->aux > 0)
+ roff_setreg(man->roff, "an-margin", nn->head->aux, '-');
+
+ /* Trailing text. */
+
+ if (buf[*pos] != '\0') {
+ roff_word_alloc(man, line, ppos, buf + *pos);
+ man->last->flags |= NODE_DELIMC;
+ }
+
+ /* Move a trailing paragraph behind the block. */
+
+ if (ctok == MAN_LP || ctok == MAN_PP || ctok == MAN_P) {
+ *pos = strlen(buf);
+ blk_imp(man, ctok, cline, cpos, pos, buf);
+ }
+}
+
+void
+blk_exp(MACRO_PROT_ARGS)
+{
+ struct roff_node *head;
+ char *p;
+ int la;
+
+ rew_scope(man, tok);
+ roff_block_alloc(man, line, ppos, tok);
+ head = roff_head_alloc(man, line, ppos, tok);
+
+ la = *pos;
+ if (man_args(man, line, pos, buf, &p)) {
+ roff_word_alloc(man, line, la, p);
+ if (tok == MAN_RS) {
+ if (roff_getreg(man->roff, "an-margin") == 0)
+ roff_setreg(man->roff, "an-margin",
+ 7 * 24, '=');
+ if ((head->aux = strtod(p, NULL) * 24.0) > 0)
+ roff_setreg(man->roff, "an-margin",
+ head->aux, '+');
+ }
+ }
+
+ if (buf[*pos] != '\0')
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, line,
+ *pos, "%s ... %s", roff_name[tok], buf + *pos);
+
+ man_unscope(man, head);
+ roff_body_alloc(man, line, ppos, tok);
+}
+
+/*
+ * Parse an implicit-block macro. These contain a ROFFT_HEAD and a
+ * ROFFT_BODY contained within a ROFFT_BLOCK. Rules for closing out other
+ * scopes, such as `SH' closing out an `SS', are defined in the rew
+ * routines.
+ */
+void
+blk_imp(MACRO_PROT_ARGS)