+ return(post_check_children_gt(mdoc, "parameters", 0));
+}
+
+
+static int
+pre_display(struct mdoc *mdoc, struct mdoc_node *node)
+{
+ struct mdoc_node *n;
+
+ if (MDOC_BLOCK != node->type)
+ return(1);
+
+ assert(mdoc->last);
+ /* LINTED */
+ for (n = mdoc->last->parent; n; n = n->parent)
+ if (MDOC_BLOCK == n->type)
+ if (MDOC_Bd == n->tok)
+ break;
+ if (NULL == n)
+ return(1);
+ return(mdoc_nerr(mdoc, node, "displays may not be nested"));
+}
+
+
+static int
+pre_bl(struct mdoc *mdoc, struct mdoc_node *node)
+{
+ int type, err;
+ struct mdoc_arg *argv;
+ size_t i, argc;
+
+ if (MDOC_BLOCK != node->type)
+ return(1);
+ assert(MDOC_Bl == node->tok);
+
+ argv = NULL;
+ argc = node->data.block.argc;
+
+ /* LINTED */
+ for (i = type = err = 0; i < argc; i++) {
+ argv = &node->data.block.argv[(int)i];
+ assert(argv);
+ switch (argv->arg) {
+ case (MDOC_Bullet):
+ /* FALLTHROUGH */
+ case (MDOC_Dash):
+ /* FALLTHROUGH */
+ case (MDOC_Enum):
+ /* FALLTHROUGH */
+ case (MDOC_Hyphen):
+ /* FALLTHROUGH */
+ case (MDOC_Item):
+ /* FALLTHROUGH */
+ case (MDOC_Tag):
+ /* FALLTHROUGH */
+ case (MDOC_Diag):
+ /* FALLTHROUGH */
+ case (MDOC_Hang):
+ /* FALLTHROUGH */
+ case (MDOC_Ohang):
+ /* FALLTHROUGH */
+ case (MDOC_Inset):
+ /* FALLTHROUGH */
+ case (MDOC_Column):
+ if (type)
+ err++;
+ type++;
+ break;
+ default:
+ break;
+ }
+ }
+ if (0 == type)
+ return(mdoc_err(mdoc, "no list type specified"));
+ if (0 == err)
+ return(1);
+ assert(argv);
+ return(mdoc_perr(mdoc, argv->line,
+ argv->pos, "only one list type possible"));
+}
+
+
+static int
+pre_bd(struct mdoc *mdoc, struct mdoc_node *node)
+{
+ int type, err;
+ struct mdoc_arg *argv;
+ size_t i, argc;
+
+ if (MDOC_BLOCK != node->type)
+ return(1);
+ assert(MDOC_Bd == node->tok);
+
+ argv = NULL;
+ argc = node->data.block.argc;
+
+ /* LINTED */
+ for (err = i = type = 0; 0 == err && i < argc; i++) {
+ argv = &node->data.block.argv[(int)i];
+ assert(argv);
+ switch (argv->arg) {
+ case (MDOC_Ragged):
+ /* FALLTHROUGH */
+ case (MDOC_Unfilled):
+ /* FALLTHROUGH */
+ case (MDOC_Filled):
+ /* FALLTHROUGH */
+ case (MDOC_Literal):
+ /* FALLTHROUGH */
+ case (MDOC_File):
+ if (type)
+ err++;
+ type++;
+ break;
+ default:
+ break;
+ }
+ }
+ if (0 == type)
+ return(mdoc_err(mdoc, "no display type specified"));
+ if (0 == err)
+ return(1);
+ assert(argv);
+ return(mdoc_perr(mdoc, argv->line,
+ argv->pos, "only one display type possible"));
+}
+
+
+static int
+pre_ss(struct mdoc *mdoc, struct mdoc_node *node)
+{
+
+ if (MDOC_BLOCK != node->type)
+ return(1);
+ return(pre_check_parent(mdoc, node, MDOC_Sh, MDOC_BODY));
+}
+
+
+static int
+pre_sh(struct mdoc *mdoc, struct mdoc_node *node)
+{
+
+ if (MDOC_BLOCK != node->type)
+ return(1);
+ return(pre_check_parent(mdoc, node, -1, MDOC_ROOT));
+}
+
+
+static int
+pre_st(struct mdoc *mdoc, struct mdoc_node *node)
+{
+
+ assert(MDOC_ELEM == node->type);
+ assert(MDOC_St == node->tok);
+ if (1 == node->data.elem.argc)
+ return(1);
+ return(mdoc_nerr(mdoc, node, "macro must have one argument"));
+}
+
+
+static int
+pre_an(struct mdoc *mdoc, struct mdoc_node *node)
+{
+
+ assert(MDOC_ELEM == node->type);
+ assert(MDOC_An == node->tok);
+ if (1 >= node->data.elem.argc)
+ return(1);
+ return(mdoc_nerr(mdoc, node, "macro may only have one argument"));
+}
+
+
+static int
+pre_rv(struct mdoc *mdoc, struct mdoc_node *node)
+{
+ enum mdoc_msec msecs[2];
+
+ assert(MDOC_ELEM == node->type);
+ assert(MDOC_Rv == node->tok);
+
+ msecs[0] = MSEC_2;
+ msecs[1] = MSEC_3;
+ if ( ! pre_check_msecs(mdoc, node, 2, msecs))
+ return(0);
+ return(pre_check_stdarg(mdoc, node));
+}
+
+
+static int
+pre_ex(struct mdoc *mdoc, struct mdoc_node *node)
+{
+ enum mdoc_msec msecs[3];
+
+ assert(MDOC_ELEM == node->type);
+ assert(MDOC_Ex == node->tok);
+
+ msecs[0] = MSEC_1;
+ msecs[1] = MSEC_6;
+ msecs[2] = MSEC_8;
+ if ( ! pre_check_msecs(mdoc, node, 3, msecs))
+ return(0);
+ return(pre_check_stdarg(mdoc, node));
+}
+
+
+static int
+pre_er(struct mdoc *mdoc, struct mdoc_node *node)
+{
+ enum mdoc_msec msecs[1];
+
+ msecs[0] = MSEC_2;
+ return(pre_check_msecs(mdoc, node, 1, msecs));
+}
+
+
+static int
+pre_cd(struct mdoc *mdoc, struct mdoc_node *node)
+{
+ enum mdoc_msec msecs[1];
+
+ msecs[0] = MSEC_4;
+ return(pre_check_msecs(mdoc, node, 1, msecs));
+}
+
+
+static int
+pre_it(struct mdoc *mdoc, struct mdoc_node *node)
+{
+
+ if (MDOC_BLOCK != node->type)
+ return(1);
+ return(pre_check_parent(mdoc, node, MDOC_Bl, MDOC_BODY));
+}
+
+
+static int
+pre_prologue(struct mdoc *mdoc, struct mdoc_node *node)
+{
+
+ if (SEC_PROLOGUE != mdoc->sec_lastn)
+ return(mdoc_nerr(mdoc, node, "macro may only be invoked in the prologue"));
+ assert(MDOC_ELEM == node->type);
+
+ /* Check for ordering. */
+
+ switch (node->tok) {
+ case (MDOC_Os):
+ if (mdoc->meta.title && mdoc->meta.date)
+ break;
+ return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
+ case (MDOC_Dt):
+ if (NULL == mdoc->meta.title && mdoc->meta.date)
+ break;
+ return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
+ case (MDOC_Dd):
+ if (NULL == mdoc->meta.title && 0 == mdoc->meta.date)
+ break;
+ return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+
+ /* Check for repetition. */
+
+ switch (node->tok) {
+ case (MDOC_Os):
+ if (NULL == mdoc->meta.os)
+ return(1);
+ break;
+ case (MDOC_Dd):
+ if (0 == mdoc->meta.date)
+ return(1);
+ break;
+ case (MDOC_Dt):
+ if (NULL == mdoc->meta.title)
+ return(1);
+ break;
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+
+ return(mdoc_nerr(mdoc, node, "prologue macro repeated"));
+}
+
+
+static int
+post_bf(struct mdoc *mdoc)
+{
+ char *p;
+ struct mdoc_node *head;
+
+ if (MDOC_BLOCK != mdoc->last->type)
+ return(1);
+ assert(MDOC_Bf == mdoc->last->tok);
+ head = mdoc->last->data.block.head;
+ assert(head);
+
+ if (0 == mdoc->last->data.block.argc) {
+ if (head->child) {
+ assert(MDOC_TEXT == head->child->type);
+ p = head->child->data.text.string;
+ if (xstrcmp(p, "Em"))
+ return(1);
+ else if (xstrcmp(p, "Li"))
+ return(1);
+ else if (xstrcmp(p, "Sm"))
+ return(1);
+ return(mdoc_nerr(mdoc, head->child, "invalid font mode"));
+ }
+ return(mdoc_err(mdoc, "macro expects an argument or parameter"));
+ }
+ if (head->child)
+ return(mdoc_err(mdoc, "macro expects an argument or parameter"));
+ if (1 == mdoc->last->data.block.argc)
+ return(1);
+ return(mdoc_err(mdoc, "macro expects an argument or parameter"));
+}
+
+
+static int
+post_nm(struct mdoc *mdoc)
+{
+
+ assert(MDOC_ELEM == mdoc->last->type);
+ assert(MDOC_Nm == mdoc->last->tok);