xref: /openbsd-src/usr.bin/mandoc/mdoc_validate.c (revision 25f90b54fc586187d792f4d69f508f5b665df1c4)
1 /*	$OpenBSD: mdoc_validate.c,v 1.209 2015/09/26 00:53:15 schwarze Exp $ */
2 /*
3  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
5  * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 #include <sys/types.h>
20 #ifndef OSNAME
21 #include <sys/utsname.h>
22 #endif
23 
24 #include <assert.h>
25 #include <ctype.h>
26 #include <limits.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31 
32 #include "mandoc_aux.h"
33 #include "mandoc.h"
34 #include "roff.h"
35 #include "mdoc.h"
36 #include "libmandoc.h"
37 #include "roff_int.h"
38 #include "libmdoc.h"
39 
40 /* FIXME: .Bl -diag can't have non-text children in HEAD. */
41 
42 #define	PRE_ARGS  struct roff_man *mdoc, struct roff_node *n
43 #define	POST_ARGS struct roff_man *mdoc
44 
45 enum	check_ineq {
46 	CHECK_LT,
47 	CHECK_GT,
48 	CHECK_EQ
49 };
50 
51 typedef	void	(*v_pre)(PRE_ARGS);
52 typedef	void	(*v_post)(POST_ARGS);
53 
54 struct	valids {
55 	v_pre	 pre;
56 	v_post	 post;
57 };
58 
59 static	void	 check_text(struct roff_man *, int, int, char *);
60 static	void	 check_argv(struct roff_man *,
61 			struct roff_node *, struct mdoc_argv *);
62 static	void	 check_args(struct roff_man *, struct roff_node *);
63 static	int	 child_an(const struct roff_node *);
64 static	enum roff_sec	a2sec(const char *);
65 static	size_t		macro2len(int);
66 static	void	 rewrite_macro2len(char **);
67 
68 static	void	 post_an(POST_ARGS);
69 static	void	 post_at(POST_ARGS);
70 static	void	 post_bf(POST_ARGS);
71 static	void	 post_bk(POST_ARGS);
72 static	void	 post_bl(POST_ARGS);
73 static	void	 post_bl_block(POST_ARGS);
74 static	void	 post_bl_block_tag(POST_ARGS);
75 static	void	 post_bl_head(POST_ARGS);
76 static	void	 post_bx(POST_ARGS);
77 static	void	 post_d1(POST_ARGS);
78 static	void	 post_defaults(POST_ARGS);
79 static	void	 post_dd(POST_ARGS);
80 static	void	 post_dt(POST_ARGS);
81 static	void	 post_en(POST_ARGS);
82 static	void	 post_es(POST_ARGS);
83 static	void	 post_eoln(POST_ARGS);
84 static	void	 post_ex(POST_ARGS);
85 static	void	 post_fa(POST_ARGS);
86 static	void	 post_fn(POST_ARGS);
87 static	void	 post_fname(POST_ARGS);
88 static	void	 post_fo(POST_ARGS);
89 static	void	 post_hyph(POST_ARGS);
90 static	void	 post_ignpar(POST_ARGS);
91 static	void	 post_it(POST_ARGS);
92 static	void	 post_lb(POST_ARGS);
93 static	void	 post_literal(POST_ARGS);
94 static	void	 post_nd(POST_ARGS);
95 static	void	 post_nm(POST_ARGS);
96 static	void	 post_ns(POST_ARGS);
97 static	void	 post_os(POST_ARGS);
98 static	void	 post_par(POST_ARGS);
99 static	void	 post_root(POST_ARGS);
100 static	void	 post_rs(POST_ARGS);
101 static	void	 post_sh(POST_ARGS);
102 static	void	 post_sh_head(POST_ARGS);
103 static	void	 post_sh_name(POST_ARGS);
104 static	void	 post_sh_see_also(POST_ARGS);
105 static	void	 post_sh_authors(POST_ARGS);
106 static	void	 post_sm(POST_ARGS);
107 static	void	 post_st(POST_ARGS);
108 
109 static	void	 pre_an(PRE_ARGS);
110 static	void	 pre_bd(PRE_ARGS);
111 static	void	 pre_bl(PRE_ARGS);
112 static	void	 pre_dd(PRE_ARGS);
113 static	void	 pre_display(PRE_ARGS);
114 static	void	 pre_dt(PRE_ARGS);
115 static	void	 pre_literal(PRE_ARGS);
116 static	void	 pre_obsolete(PRE_ARGS);
117 static	void	 pre_os(PRE_ARGS);
118 static	void	 pre_par(PRE_ARGS);
119 static	void	 pre_std(PRE_ARGS);
120 
121 static	const struct valids mdoc_valids[MDOC_MAX] = {
122 	{ NULL, NULL },				/* Ap */
123 	{ pre_dd, post_dd },			/* Dd */
124 	{ pre_dt, post_dt },			/* Dt */
125 	{ pre_os, post_os },			/* Os */
126 	{ NULL, post_sh },			/* Sh */
127 	{ NULL, post_ignpar },			/* Ss */
128 	{ pre_par, post_par },			/* Pp */
129 	{ pre_display, post_d1 },		/* D1 */
130 	{ pre_literal, post_literal },		/* Dl */
131 	{ pre_bd, post_literal },		/* Bd */
132 	{ NULL, NULL },				/* Ed */
133 	{ pre_bl, post_bl },			/* Bl */
134 	{ NULL, NULL },				/* El */
135 	{ pre_par, post_it },			/* It */
136 	{ NULL, NULL },				/* Ad */
137 	{ pre_an, post_an },			/* An */
138 	{ NULL, post_defaults },		/* Ar */
139 	{ NULL, NULL },				/* Cd */
140 	{ NULL, NULL },				/* Cm */
141 	{ NULL, NULL },				/* Dv */
142 	{ NULL, NULL },				/* Er */
143 	{ NULL, NULL },				/* Ev */
144 	{ pre_std, post_ex },			/* Ex */
145 	{ NULL, post_fa },			/* Fa */
146 	{ NULL, NULL },				/* Fd */
147 	{ NULL, NULL },				/* Fl */
148 	{ NULL, post_fn },			/* Fn */
149 	{ NULL, NULL },				/* Ft */
150 	{ NULL, NULL },				/* Ic */
151 	{ NULL, NULL },				/* In */
152 	{ NULL, post_defaults },		/* Li */
153 	{ NULL, post_nd },			/* Nd */
154 	{ NULL, post_nm },			/* Nm */
155 	{ NULL, NULL },				/* Op */
156 	{ pre_obsolete, NULL },			/* Ot */
157 	{ NULL, post_defaults },		/* Pa */
158 	{ pre_std, NULL },			/* Rv */
159 	{ NULL, post_st },			/* St */
160 	{ NULL, NULL },				/* Va */
161 	{ NULL, NULL },				/* Vt */
162 	{ NULL, NULL },				/* Xr */
163 	{ NULL, NULL },				/* %A */
164 	{ NULL, post_hyph },			/* %B */ /* FIXME: can be used outside Rs/Re. */
165 	{ NULL, NULL },				/* %D */
166 	{ NULL, NULL },				/* %I */
167 	{ NULL, NULL },				/* %J */
168 	{ NULL, post_hyph },			/* %N */
169 	{ NULL, post_hyph },			/* %O */
170 	{ NULL, NULL },				/* %P */
171 	{ NULL, post_hyph },			/* %R */
172 	{ NULL, post_hyph },			/* %T */ /* FIXME: can be used outside Rs/Re. */
173 	{ NULL, NULL },				/* %V */
174 	{ NULL, NULL },				/* Ac */
175 	{ NULL, NULL },				/* Ao */
176 	{ NULL, NULL },				/* Aq */
177 	{ NULL, post_at },			/* At */
178 	{ NULL, NULL },				/* Bc */
179 	{ NULL, post_bf },			/* Bf */
180 	{ NULL, NULL },				/* Bo */
181 	{ NULL, NULL },				/* Bq */
182 	{ NULL, NULL },				/* Bsx */
183 	{ NULL, post_bx },			/* Bx */
184 	{ pre_obsolete, NULL },			/* Db */
185 	{ NULL, NULL },				/* Dc */
186 	{ NULL, NULL },				/* Do */
187 	{ NULL, NULL },				/* Dq */
188 	{ NULL, NULL },				/* Ec */
189 	{ NULL, NULL },				/* Ef */
190 	{ NULL, NULL },				/* Em */
191 	{ NULL, NULL },				/* Eo */
192 	{ NULL, NULL },				/* Fx */
193 	{ NULL, NULL },				/* Ms */
194 	{ NULL, NULL },				/* No */
195 	{ NULL, post_ns },			/* Ns */
196 	{ NULL, NULL },				/* Nx */
197 	{ NULL, NULL },				/* Ox */
198 	{ NULL, NULL },				/* Pc */
199 	{ NULL, NULL },				/* Pf */
200 	{ NULL, NULL },				/* Po */
201 	{ NULL, NULL },				/* Pq */
202 	{ NULL, NULL },				/* Qc */
203 	{ NULL, NULL },				/* Ql */
204 	{ NULL, NULL },				/* Qo */
205 	{ NULL, NULL },				/* Qq */
206 	{ NULL, NULL },				/* Re */
207 	{ NULL, post_rs },			/* Rs */
208 	{ NULL, NULL },				/* Sc */
209 	{ NULL, NULL },				/* So */
210 	{ NULL, NULL },				/* Sq */
211 	{ NULL, post_sm },			/* Sm */
212 	{ NULL, post_hyph },			/* Sx */
213 	{ NULL, NULL },				/* Sy */
214 	{ NULL, NULL },				/* Tn */
215 	{ NULL, NULL },				/* Ux */
216 	{ NULL, NULL },				/* Xc */
217 	{ NULL, NULL },				/* Xo */
218 	{ NULL, post_fo },			/* Fo */
219 	{ NULL, NULL },				/* Fc */
220 	{ NULL, NULL },				/* Oo */
221 	{ NULL, NULL },				/* Oc */
222 	{ NULL, post_bk },			/* Bk */
223 	{ NULL, NULL },				/* Ek */
224 	{ NULL, post_eoln },			/* Bt */
225 	{ NULL, NULL },				/* Hf */
226 	{ pre_obsolete, NULL },			/* Fr */
227 	{ NULL, post_eoln },			/* Ud */
228 	{ NULL, post_lb },			/* Lb */
229 	{ pre_par, post_par },			/* Lp */
230 	{ NULL, NULL },				/* Lk */
231 	{ NULL, post_defaults },		/* Mt */
232 	{ NULL, NULL },				/* Brq */
233 	{ NULL, NULL },				/* Bro */
234 	{ NULL, NULL },				/* Brc */
235 	{ NULL, NULL },				/* %C */
236 	{ pre_obsolete, post_es },		/* Es */
237 	{ pre_obsolete, post_en },		/* En */
238 	{ NULL, NULL },				/* Dx */
239 	{ NULL, NULL },				/* %Q */
240 	{ NULL, post_par },			/* br */
241 	{ NULL, post_par },			/* sp */
242 	{ NULL, NULL },				/* %U */
243 	{ NULL, NULL },				/* Ta */
244 	{ NULL, NULL },				/* ll */
245 };
246 
247 #define	RSORD_MAX 14 /* Number of `Rs' blocks. */
248 
249 static	const int rsord[RSORD_MAX] = {
250 	MDOC__A,
251 	MDOC__T,
252 	MDOC__B,
253 	MDOC__I,
254 	MDOC__J,
255 	MDOC__R,
256 	MDOC__N,
257 	MDOC__V,
258 	MDOC__U,
259 	MDOC__P,
260 	MDOC__Q,
261 	MDOC__C,
262 	MDOC__D,
263 	MDOC__O
264 };
265 
266 static	const char * const secnames[SEC__MAX] = {
267 	NULL,
268 	"NAME",
269 	"LIBRARY",
270 	"SYNOPSIS",
271 	"DESCRIPTION",
272 	"CONTEXT",
273 	"IMPLEMENTATION NOTES",
274 	"RETURN VALUES",
275 	"ENVIRONMENT",
276 	"FILES",
277 	"EXIT STATUS",
278 	"EXAMPLES",
279 	"DIAGNOSTICS",
280 	"COMPATIBILITY",
281 	"ERRORS",
282 	"SEE ALSO",
283 	"STANDARDS",
284 	"HISTORY",
285 	"AUTHORS",
286 	"CAVEATS",
287 	"BUGS",
288 	"SECURITY CONSIDERATIONS",
289 	NULL
290 };
291 
292 
293 void
294 mdoc_valid_pre(struct roff_man *mdoc, struct roff_node *n)
295 {
296 	v_pre	 p;
297 
298 	switch (n->type) {
299 	case ROFFT_TEXT:
300 		if (n->sec != SEC_SYNOPSIS || n->parent->tok != MDOC_Fd)
301 			check_text(mdoc, n->line, n->pos, n->string);
302 		/* FALLTHROUGH */
303 	case ROFFT_TBL:
304 		/* FALLTHROUGH */
305 	case ROFFT_EQN:
306 		/* FALLTHROUGH */
307 	case ROFFT_ROOT:
308 		return;
309 	default:
310 		break;
311 	}
312 
313 	check_args(mdoc, n);
314 	p = mdoc_valids[n->tok].pre;
315 	if (*p)
316 		(*p)(mdoc, n);
317 }
318 
319 void
320 mdoc_valid_post(struct roff_man *mdoc)
321 {
322 	struct roff_node *n;
323 	v_post p;
324 
325 	n = mdoc->last;
326 	if (n->flags & MDOC_VALID)
327 		return;
328 	n->flags |= MDOC_VALID | MDOC_ENDED;
329 
330 	switch (n->type) {
331 	case ROFFT_TEXT:
332 		/* FALLTHROUGH */
333 	case ROFFT_EQN:
334 		/* FALLTHROUGH */
335 	case ROFFT_TBL:
336 		break;
337 	case ROFFT_ROOT:
338 		post_root(mdoc);
339 		break;
340 	default:
341 
342 		/*
343 		 * Closing delimiters are not special at the
344 		 * beginning of a block, opening delimiters
345 		 * are not special at the end.
346 		 */
347 
348 		if (n->child != NULL)
349 			n->child->flags &= ~MDOC_DELIMC;
350 		if (n->last != NULL)
351 			n->last->flags &= ~MDOC_DELIMO;
352 
353 		/* Call the macro's postprocessor. */
354 
355 		p = mdoc_valids[n->tok].post;
356 		if (*p)
357 			(*p)(mdoc);
358 		break;
359 	}
360 }
361 
362 static void
363 check_args(struct roff_man *mdoc, struct roff_node *n)
364 {
365 	int		 i;
366 
367 	if (NULL == n->args)
368 		return;
369 
370 	assert(n->args->argc);
371 	for (i = 0; i < (int)n->args->argc; i++)
372 		check_argv(mdoc, n, &n->args->argv[i]);
373 }
374 
375 static void
376 check_argv(struct roff_man *mdoc, struct roff_node *n, struct mdoc_argv *v)
377 {
378 	int		 i;
379 
380 	for (i = 0; i < (int)v->sz; i++)
381 		check_text(mdoc, v->line, v->pos, v->value[i]);
382 }
383 
384 static void
385 check_text(struct roff_man *mdoc, int ln, int pos, char *p)
386 {
387 	char		*cp;
388 
389 	if (MDOC_LITERAL & mdoc->flags)
390 		return;
391 
392 	for (cp = p; NULL != (p = strchr(p, '\t')); p++)
393 		mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse,
394 		    ln, pos + (int)(p - cp), NULL);
395 }
396 
397 static void
398 pre_display(PRE_ARGS)
399 {
400 	struct roff_node *node;
401 
402 	if (n->type != ROFFT_BLOCK)
403 		return;
404 
405 	for (node = mdoc->last->parent; node; node = node->parent)
406 		if (node->type == ROFFT_BLOCK)
407 			if (MDOC_Bd == node->tok)
408 				break;
409 
410 	if (node)
411 		mandoc_vmsg(MANDOCERR_BD_NEST,
412 		    mdoc->parse, n->line, n->pos,
413 		    "%s in Bd", mdoc_macronames[n->tok]);
414 }
415 
416 static void
417 pre_bl(PRE_ARGS)
418 {
419 	struct mdoc_argv *argv, *wa;
420 	int		  i;
421 	enum mdocargt	  mdoclt;
422 	enum mdoc_list	  lt;
423 
424 	if (n->type != ROFFT_BLOCK)
425 		return;
426 
427 	/*
428 	 * First figure out which kind of list to use: bind ourselves to
429 	 * the first mentioned list type and warn about any remaining
430 	 * ones.  If we find no list type, we default to LIST_item.
431 	 */
432 
433 	wa = (n->args == NULL) ? NULL : n->args->argv;
434 	mdoclt = MDOC_ARG_MAX;
435 	for (i = 0; n->args && i < (int)n->args->argc; i++) {
436 		argv = n->args->argv + i;
437 		lt = LIST__NONE;
438 		switch (argv->arg) {
439 		/* Set list types. */
440 		case MDOC_Bullet:
441 			lt = LIST_bullet;
442 			break;
443 		case MDOC_Dash:
444 			lt = LIST_dash;
445 			break;
446 		case MDOC_Enum:
447 			lt = LIST_enum;
448 			break;
449 		case MDOC_Hyphen:
450 			lt = LIST_hyphen;
451 			break;
452 		case MDOC_Item:
453 			lt = LIST_item;
454 			break;
455 		case MDOC_Tag:
456 			lt = LIST_tag;
457 			break;
458 		case MDOC_Diag:
459 			lt = LIST_diag;
460 			break;
461 		case MDOC_Hang:
462 			lt = LIST_hang;
463 			break;
464 		case MDOC_Ohang:
465 			lt = LIST_ohang;
466 			break;
467 		case MDOC_Inset:
468 			lt = LIST_inset;
469 			break;
470 		case MDOC_Column:
471 			lt = LIST_column;
472 			break;
473 		/* Set list arguments. */
474 		case MDOC_Compact:
475 			if (n->norm->Bl.comp)
476 				mandoc_msg(MANDOCERR_ARG_REP,
477 				    mdoc->parse, argv->line,
478 				    argv->pos, "Bl -compact");
479 			n->norm->Bl.comp = 1;
480 			break;
481 		case MDOC_Width:
482 			wa = argv;
483 			if (0 == argv->sz) {
484 				mandoc_msg(MANDOCERR_ARG_EMPTY,
485 				    mdoc->parse, argv->line,
486 				    argv->pos, "Bl -width");
487 				n->norm->Bl.width = "0n";
488 				break;
489 			}
490 			if (NULL != n->norm->Bl.width)
491 				mandoc_vmsg(MANDOCERR_ARG_REP,
492 				    mdoc->parse, argv->line,
493 				    argv->pos, "Bl -width %s",
494 				    argv->value[0]);
495 			rewrite_macro2len(argv->value);
496 			n->norm->Bl.width = argv->value[0];
497 			break;
498 		case MDOC_Offset:
499 			if (0 == argv->sz) {
500 				mandoc_msg(MANDOCERR_ARG_EMPTY,
501 				    mdoc->parse, argv->line,
502 				    argv->pos, "Bl -offset");
503 				break;
504 			}
505 			if (NULL != n->norm->Bl.offs)
506 				mandoc_vmsg(MANDOCERR_ARG_REP,
507 				    mdoc->parse, argv->line,
508 				    argv->pos, "Bl -offset %s",
509 				    argv->value[0]);
510 			rewrite_macro2len(argv->value);
511 			n->norm->Bl.offs = argv->value[0];
512 			break;
513 		default:
514 			continue;
515 		}
516 		if (LIST__NONE == lt)
517 			continue;
518 		mdoclt = argv->arg;
519 
520 		/* Check: multiple list types. */
521 
522 		if (LIST__NONE != n->norm->Bl.type) {
523 			mandoc_vmsg(MANDOCERR_BL_REP,
524 			    mdoc->parse, n->line, n->pos,
525 			    "Bl -%s", mdoc_argnames[argv->arg]);
526 			continue;
527 		}
528 
529 		/* The list type should come first. */
530 
531 		if (n->norm->Bl.width ||
532 		    n->norm->Bl.offs ||
533 		    n->norm->Bl.comp)
534 			mandoc_vmsg(MANDOCERR_BL_LATETYPE,
535 			    mdoc->parse, n->line, n->pos, "Bl -%s",
536 			    mdoc_argnames[n->args->argv[0].arg]);
537 
538 		n->norm->Bl.type = lt;
539 		if (LIST_column == lt) {
540 			n->norm->Bl.ncols = argv->sz;
541 			n->norm->Bl.cols = (void *)argv->value;
542 		}
543 	}
544 
545 	/* Allow lists to default to LIST_item. */
546 
547 	if (LIST__NONE == n->norm->Bl.type) {
548 		mandoc_msg(MANDOCERR_BL_NOTYPE, mdoc->parse,
549 		    n->line, n->pos, "Bl");
550 		n->norm->Bl.type = LIST_item;
551 	}
552 
553 	/*
554 	 * Validate the width field.  Some list types don't need width
555 	 * types and should be warned about them.  Others should have it
556 	 * and must also be warned.  Yet others have a default and need
557 	 * no warning.
558 	 */
559 
560 	switch (n->norm->Bl.type) {
561 	case LIST_tag:
562 		if (NULL == n->norm->Bl.width)
563 			mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse,
564 			    n->line, n->pos, "Bl -tag");
565 		break;
566 	case LIST_column:
567 		/* FALLTHROUGH */
568 	case LIST_diag:
569 		/* FALLTHROUGH */
570 	case LIST_ohang:
571 		/* FALLTHROUGH */
572 	case LIST_inset:
573 		/* FALLTHROUGH */
574 	case LIST_item:
575 		if (n->norm->Bl.width)
576 			mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse,
577 			    wa->line, wa->pos, "Bl -%s",
578 			    mdoc_argnames[mdoclt]);
579 		break;
580 	case LIST_bullet:
581 		/* FALLTHROUGH */
582 	case LIST_dash:
583 		/* FALLTHROUGH */
584 	case LIST_hyphen:
585 		if (NULL == n->norm->Bl.width)
586 			n->norm->Bl.width = "2n";
587 		break;
588 	case LIST_enum:
589 		if (NULL == n->norm->Bl.width)
590 			n->norm->Bl.width = "3n";
591 		break;
592 	default:
593 		break;
594 	}
595 	pre_par(mdoc, n);
596 }
597 
598 static void
599 pre_bd(PRE_ARGS)
600 {
601 	struct mdoc_argv *argv;
602 	int		  i;
603 	enum mdoc_disp	  dt;
604 
605 	pre_literal(mdoc, n);
606 
607 	if (n->type != ROFFT_BLOCK)
608 		return;
609 
610 	for (i = 0; n->args && i < (int)n->args->argc; i++) {
611 		argv = n->args->argv + i;
612 		dt = DISP__NONE;
613 
614 		switch (argv->arg) {
615 		case MDOC_Centred:
616 			dt = DISP_centered;
617 			break;
618 		case MDOC_Ragged:
619 			dt = DISP_ragged;
620 			break;
621 		case MDOC_Unfilled:
622 			dt = DISP_unfilled;
623 			break;
624 		case MDOC_Filled:
625 			dt = DISP_filled;
626 			break;
627 		case MDOC_Literal:
628 			dt = DISP_literal;
629 			break;
630 		case MDOC_File:
631 			mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse,
632 			    n->line, n->pos, NULL);
633 			break;
634 		case MDOC_Offset:
635 			if (0 == argv->sz) {
636 				mandoc_msg(MANDOCERR_ARG_EMPTY,
637 				    mdoc->parse, argv->line,
638 				    argv->pos, "Bd -offset");
639 				break;
640 			}
641 			if (NULL != n->norm->Bd.offs)
642 				mandoc_vmsg(MANDOCERR_ARG_REP,
643 				    mdoc->parse, argv->line,
644 				    argv->pos, "Bd -offset %s",
645 				    argv->value[0]);
646 			rewrite_macro2len(argv->value);
647 			n->norm->Bd.offs = argv->value[0];
648 			break;
649 		case MDOC_Compact:
650 			if (n->norm->Bd.comp)
651 				mandoc_msg(MANDOCERR_ARG_REP,
652 				    mdoc->parse, argv->line,
653 				    argv->pos, "Bd -compact");
654 			n->norm->Bd.comp = 1;
655 			break;
656 		default:
657 			abort();
658 		}
659 		if (DISP__NONE == dt)
660 			continue;
661 
662 		if (DISP__NONE == n->norm->Bd.type)
663 			n->norm->Bd.type = dt;
664 		else
665 			mandoc_vmsg(MANDOCERR_BD_REP,
666 			    mdoc->parse, n->line, n->pos,
667 			    "Bd -%s", mdoc_argnames[argv->arg]);
668 	}
669 
670 	if (DISP__NONE == n->norm->Bd.type) {
671 		mandoc_msg(MANDOCERR_BD_NOTYPE, mdoc->parse,
672 		    n->line, n->pos, "Bd");
673 		n->norm->Bd.type = DISP_ragged;
674 	}
675 	pre_par(mdoc, n);
676 }
677 
678 static void
679 pre_an(PRE_ARGS)
680 {
681 	struct mdoc_argv *argv;
682 	size_t	 i;
683 
684 	if (n->args == NULL)
685 		return;
686 
687 	for (i = 1; i < n->args->argc; i++) {
688 		argv = n->args->argv + i;
689 		mandoc_vmsg(MANDOCERR_AN_REP,
690 		    mdoc->parse, argv->line, argv->pos,
691 		    "An -%s", mdoc_argnames[argv->arg]);
692 	}
693 
694 	argv = n->args->argv;
695 	if (argv->arg == MDOC_Split)
696 		n->norm->An.auth = AUTH_split;
697 	else if (argv->arg == MDOC_Nosplit)
698 		n->norm->An.auth = AUTH_nosplit;
699 	else
700 		abort();
701 }
702 
703 static void
704 pre_std(PRE_ARGS)
705 {
706 
707 	if (n->args && 1 == n->args->argc)
708 		if (MDOC_Std == n->args->argv[0].arg)
709 			return;
710 
711 	mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse,
712 	    n->line, n->pos, mdoc_macronames[n->tok]);
713 }
714 
715 static void
716 pre_obsolete(PRE_ARGS)
717 {
718 
719 	if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK)
720 		mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse,
721 		    n->line, n->pos, mdoc_macronames[n->tok]);
722 }
723 
724 static void
725 pre_dt(PRE_ARGS)
726 {
727 
728 	if (mdoc->meta.title != NULL)
729 		mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
730 		    n->line, n->pos, "Dt");
731 	else if (mdoc->meta.os != NULL)
732 		mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
733 		    n->line, n->pos, "Dt after Os");
734 }
735 
736 static void
737 pre_os(PRE_ARGS)
738 {
739 
740 	if (mdoc->meta.os != NULL)
741 		mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
742 		    n->line, n->pos, "Os");
743 	else if (mdoc->flags & MDOC_PBODY)
744 		mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
745 		    n->line, n->pos, "Os");
746 }
747 
748 static void
749 pre_dd(PRE_ARGS)
750 {
751 
752 	if (mdoc->meta.date != NULL)
753 		mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
754 		    n->line, n->pos, "Dd");
755 	else if (mdoc->flags & MDOC_PBODY)
756 		mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
757 		    n->line, n->pos, "Dd");
758 	else if (mdoc->meta.title != NULL)
759 		mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
760 		    n->line, n->pos, "Dd after Dt");
761 	else if (mdoc->meta.os != NULL)
762 		mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
763 		    n->line, n->pos, "Dd after Os");
764 }
765 
766 static void
767 post_bf(POST_ARGS)
768 {
769 	struct roff_node *np, *nch;
770 	enum mdocargt	  arg;
771 
772 	/*
773 	 * Unlike other data pointers, these are "housed" by the HEAD
774 	 * element, which contains the goods.
775 	 */
776 
777 	np = mdoc->last;
778 	if (np->type != ROFFT_HEAD)
779 		return;
780 
781 	assert(np->parent->type == ROFFT_BLOCK);
782 	assert(MDOC_Bf == np->parent->tok);
783 
784 	/* Check the number of arguments. */
785 
786 	nch = np->child;
787 	if (NULL == np->parent->args) {
788 		if (NULL == nch) {
789 			mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse,
790 			    np->line, np->pos, "Bf");
791 			return;
792 		}
793 		nch = nch->next;
794 	}
795 	if (NULL != nch)
796 		mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
797 		    nch->line, nch->pos, "Bf ... %s", nch->string);
798 
799 	/* Extract argument into data. */
800 
801 	if (np->parent->args) {
802 		arg = np->parent->args->argv[0].arg;
803 		if (MDOC_Emphasis == arg)
804 			np->norm->Bf.font = FONT_Em;
805 		else if (MDOC_Literal == arg)
806 			np->norm->Bf.font = FONT_Li;
807 		else if (MDOC_Symbolic == arg)
808 			np->norm->Bf.font = FONT_Sy;
809 		else
810 			abort();
811 		return;
812 	}
813 
814 	/* Extract parameter into data. */
815 
816 	if (0 == strcmp(np->child->string, "Em"))
817 		np->norm->Bf.font = FONT_Em;
818 	else if (0 == strcmp(np->child->string, "Li"))
819 		np->norm->Bf.font = FONT_Li;
820 	else if (0 == strcmp(np->child->string, "Sy"))
821 		np->norm->Bf.font = FONT_Sy;
822 	else
823 		mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse,
824 		    np->child->line, np->child->pos,
825 		    "Bf %s", np->child->string);
826 }
827 
828 static void
829 post_lb(POST_ARGS)
830 {
831 	struct roff_node	*n;
832 	char			*libname;
833 
834 	n = mdoc->last->child;
835 	assert(n->type == ROFFT_TEXT);
836 	mandoc_asprintf(&libname, "library \\(Lq%s\\(Rq", n->string);
837 	free(n->string);
838 	n->string = libname;
839 }
840 
841 static void
842 post_eoln(POST_ARGS)
843 {
844 	const struct roff_node *n;
845 
846 	n = mdoc->last;
847 	if (n->child)
848 		mandoc_vmsg(MANDOCERR_ARG_SKIP,
849 		    mdoc->parse, n->line, n->pos,
850 		    "%s %s", mdoc_macronames[n->tok],
851 		    n->child->string);
852 }
853 
854 static void
855 post_fname(POST_ARGS)
856 {
857 	const struct roff_node	*n;
858 	const char		*cp;
859 	size_t			 pos;
860 
861 	n = mdoc->last->child;
862 	pos = strcspn(n->string, "()");
863 	cp = n->string + pos;
864 	if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*')))
865 		mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse,
866 		    n->line, n->pos + pos, n->string);
867 }
868 
869 static void
870 post_fn(POST_ARGS)
871 {
872 
873 	post_fname(mdoc);
874 	post_fa(mdoc);
875 }
876 
877 static void
878 post_fo(POST_ARGS)
879 {
880 	const struct roff_node	*n;
881 
882 	n = mdoc->last;
883 
884 	if (n->type != ROFFT_HEAD)
885 		return;
886 
887 	if (n->child == NULL) {
888 		mandoc_msg(MANDOCERR_FO_NOHEAD, mdoc->parse,
889 		    n->line, n->pos, "Fo");
890 		return;
891 	}
892 	if (n->child != n->last) {
893 		mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
894 		    n->child->next->line, n->child->next->pos,
895 		    "Fo ... %s", n->child->next->string);
896 		while (n->child != n->last)
897 			roff_node_delete(mdoc, n->last);
898 	}
899 
900 	post_fname(mdoc);
901 }
902 
903 static void
904 post_fa(POST_ARGS)
905 {
906 	const struct roff_node *n;
907 	const char *cp;
908 
909 	for (n = mdoc->last->child; n != NULL; n = n->next) {
910 		for (cp = n->string; *cp != '\0'; cp++) {
911 			/* Ignore callbacks and alterations. */
912 			if (*cp == '(' || *cp == '{')
913 				break;
914 			if (*cp != ',')
915 				continue;
916 			mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse,
917 			    n->line, n->pos + (cp - n->string),
918 			    n->string);
919 			break;
920 		}
921 	}
922 }
923 
924 static void
925 post_nm(POST_ARGS)
926 {
927 	struct roff_node	*n;
928 
929 	n = mdoc->last;
930 
931 	if (n->last != NULL &&
932 	    (n->last->tok == MDOC_Pp ||
933 	     n->last->tok == MDOC_Lp))
934 		mdoc_node_relink(mdoc, n->last);
935 
936 	if (NULL != mdoc->meta.name)
937 		return;
938 
939 	deroff(&mdoc->meta.name, n);
940 
941 	if (NULL == mdoc->meta.name)
942 		mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse,
943 		    n->line, n->pos, "Nm");
944 }
945 
946 static void
947 post_nd(POST_ARGS)
948 {
949 	struct roff_node	*n;
950 
951 	n = mdoc->last;
952 
953 	if (n->type != ROFFT_BODY)
954 		return;
955 
956 	if (n->child == NULL)
957 		mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse,
958 		    n->line, n->pos, "Nd");
959 
960 	post_hyph(mdoc);
961 }
962 
963 static void
964 post_d1(POST_ARGS)
965 {
966 	struct roff_node	*n;
967 
968 	n = mdoc->last;
969 
970 	if (n->type != ROFFT_BODY)
971 		return;
972 
973 	if (n->child == NULL)
974 		mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
975 		    n->line, n->pos, "D1");
976 
977 	post_hyph(mdoc);
978 }
979 
980 static void
981 post_literal(POST_ARGS)
982 {
983 	struct roff_node	*n;
984 
985 	n = mdoc->last;
986 
987 	if (n->type != ROFFT_BODY)
988 		return;
989 
990 	if (n->child == NULL)
991 		mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
992 		    n->line, n->pos, mdoc_macronames[n->tok]);
993 
994 	if (n->tok == MDOC_Bd &&
995 	    n->norm->Bd.type != DISP_literal &&
996 	    n->norm->Bd.type != DISP_unfilled)
997 		return;
998 
999 	mdoc->flags &= ~MDOC_LITERAL;
1000 }
1001 
1002 static void
1003 post_defaults(POST_ARGS)
1004 {
1005 	struct roff_node *nn;
1006 
1007 	/*
1008 	 * The `Ar' defaults to "file ..." if no value is provided as an
1009 	 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
1010 	 * gets an empty string.
1011 	 */
1012 
1013 	if (mdoc->last->child)
1014 		return;
1015 
1016 	nn = mdoc->last;
1017 	mdoc->next = ROFF_NEXT_CHILD;
1018 
1019 	switch (nn->tok) {
1020 	case MDOC_Ar:
1021 		roff_word_alloc(mdoc, nn->line, nn->pos, "file");
1022 		roff_word_alloc(mdoc, nn->line, nn->pos, "...");
1023 		break;
1024 	case MDOC_Pa:
1025 		/* FALLTHROUGH */
1026 	case MDOC_Mt:
1027 		roff_word_alloc(mdoc, nn->line, nn->pos, "~");
1028 		break;
1029 	default:
1030 		abort();
1031 	}
1032 	mdoc->last = nn;
1033 }
1034 
1035 static void
1036 post_at(POST_ARGS)
1037 {
1038 	struct roff_node	*n;
1039 	const char		*std_att;
1040 	char			*att;
1041 
1042 	n = mdoc->last;
1043 	if (n->child == NULL) {
1044 		mdoc->next = ROFF_NEXT_CHILD;
1045 		roff_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX");
1046 		mdoc->last = n;
1047 		return;
1048 	}
1049 
1050 	/*
1051 	 * If we have a child, look it up in the standard keys.  If a
1052 	 * key exist, use that instead of the child; if it doesn't,
1053 	 * prefix "AT&T UNIX " to the existing data.
1054 	 */
1055 
1056 	n = n->child;
1057 	assert(n->type == ROFFT_TEXT);
1058 	if (NULL == (std_att = mdoc_a2att(n->string))) {
1059 		mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse,
1060 		    n->line, n->pos, "At %s", n->string);
1061 		mandoc_asprintf(&att, "AT&T UNIX %s", n->string);
1062 	} else
1063 		att = mandoc_strdup(std_att);
1064 
1065 	free(n->string);
1066 	n->string = att;
1067 }
1068 
1069 static void
1070 post_an(POST_ARGS)
1071 {
1072 	struct roff_node *np, *nch;
1073 
1074 	np = mdoc->last;
1075 	nch = np->child;
1076 	if (np->norm->An.auth == AUTH__NONE) {
1077 		if (nch == NULL)
1078 			mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
1079 			    np->line, np->pos, "An");
1080 	} else if (nch != NULL)
1081 		mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
1082 		    nch->line, nch->pos, "An ... %s", nch->string);
1083 }
1084 
1085 static void
1086 post_en(POST_ARGS)
1087 {
1088 
1089 	if (mdoc->last->type == ROFFT_BLOCK)
1090 		mdoc->last->norm->Es = mdoc->last_es;
1091 }
1092 
1093 static void
1094 post_es(POST_ARGS)
1095 {
1096 
1097 	mdoc->last_es = mdoc->last;
1098 }
1099 
1100 static void
1101 post_it(POST_ARGS)
1102 {
1103 	struct roff_node *nbl, *nit, *nch;
1104 	int		  i, cols;
1105 	enum mdoc_list	  lt;
1106 
1107 	nit = mdoc->last;
1108 	if (nit->type != ROFFT_BLOCK)
1109 		return;
1110 
1111 	nbl = nit->parent->parent;
1112 	lt = nbl->norm->Bl.type;
1113 
1114 	switch (lt) {
1115 	case LIST_tag:
1116 		/* FALLTHROUGH */
1117 	case LIST_hang:
1118 		/* FALLTHROUGH */
1119 	case LIST_ohang:
1120 		/* FALLTHROUGH */
1121 	case LIST_inset:
1122 		/* FALLTHROUGH */
1123 	case LIST_diag:
1124 		if (nit->head->child == NULL)
1125 			mandoc_vmsg(MANDOCERR_IT_NOHEAD,
1126 			    mdoc->parse, nit->line, nit->pos,
1127 			    "Bl -%s It",
1128 			    mdoc_argnames[nbl->args->argv[0].arg]);
1129 		break;
1130 	case LIST_bullet:
1131 		/* FALLTHROUGH */
1132 	case LIST_dash:
1133 		/* FALLTHROUGH */
1134 	case LIST_enum:
1135 		/* FALLTHROUGH */
1136 	case LIST_hyphen:
1137 		if (nit->body == NULL || nit->body->child == NULL)
1138 			mandoc_vmsg(MANDOCERR_IT_NOBODY,
1139 			    mdoc->parse, nit->line, nit->pos,
1140 			    "Bl -%s It",
1141 			    mdoc_argnames[nbl->args->argv[0].arg]);
1142 		/* FALLTHROUGH */
1143 	case LIST_item:
1144 		if (nit->head->child != NULL)
1145 			mandoc_vmsg(MANDOCERR_ARG_SKIP,
1146 			    mdoc->parse, nit->line, nit->pos,
1147 			    "It %s", nit->head->child->string);
1148 		break;
1149 	case LIST_column:
1150 		cols = (int)nbl->norm->Bl.ncols;
1151 
1152 		assert(nit->head->child == NULL);
1153 
1154 		for (i = 0, nch = nit->child; nch; nch = nch->next)
1155 			if (nch->type == ROFFT_BODY)
1156 				i++;
1157 
1158 		if (i < cols || i > cols + 1)
1159 			mandoc_vmsg(MANDOCERR_BL_COL,
1160 			    mdoc->parse, nit->line, nit->pos,
1161 			    "%d columns, %d cells", cols, i);
1162 		break;
1163 	default:
1164 		abort();
1165 	}
1166 }
1167 
1168 static void
1169 post_bl_block(POST_ARGS)
1170 {
1171 	struct roff_node *n, *ni, *nc;
1172 
1173 	/*
1174 	 * These are fairly complicated, so we've broken them into two
1175 	 * functions.  post_bl_block_tag() is called when a -tag is
1176 	 * specified, but no -width (it must be guessed).  The second
1177 	 * when a -width is specified (macro indicators must be
1178 	 * rewritten into real lengths).
1179 	 */
1180 
1181 	n = mdoc->last;
1182 
1183 	if (LIST_tag == n->norm->Bl.type &&
1184 	    NULL == n->norm->Bl.width) {
1185 		post_bl_block_tag(mdoc);
1186 		assert(n->norm->Bl.width);
1187 	}
1188 
1189 	for (ni = n->body->child; ni; ni = ni->next) {
1190 		if (NULL == ni->body)
1191 			continue;
1192 		nc = ni->body->last;
1193 		while (NULL != nc) {
1194 			switch (nc->tok) {
1195 			case MDOC_Pp:
1196 				/* FALLTHROUGH */
1197 			case MDOC_Lp:
1198 				/* FALLTHROUGH */
1199 			case MDOC_br:
1200 				break;
1201 			default:
1202 				nc = NULL;
1203 				continue;
1204 			}
1205 			if (NULL == ni->next) {
1206 				mandoc_msg(MANDOCERR_PAR_MOVE,
1207 				    mdoc->parse, nc->line, nc->pos,
1208 				    mdoc_macronames[nc->tok]);
1209 				mdoc_node_relink(mdoc, nc);
1210 			} else if (0 == n->norm->Bl.comp &&
1211 			    LIST_column != n->norm->Bl.type) {
1212 				mandoc_vmsg(MANDOCERR_PAR_SKIP,
1213 				    mdoc->parse, nc->line, nc->pos,
1214 				    "%s before It",
1215 				    mdoc_macronames[nc->tok]);
1216 				roff_node_delete(mdoc, nc);
1217 			} else
1218 				break;
1219 			nc = ni->body->last;
1220 		}
1221 	}
1222 }
1223 
1224 /*
1225  * If the argument of -offset or -width is a macro,
1226  * replace it with the associated default width.
1227  */
1228 void
1229 rewrite_macro2len(char **arg)
1230 {
1231 	size_t		  width;
1232 	int		  tok;
1233 
1234 	if (*arg == NULL)
1235 		return;
1236 	else if ( ! strcmp(*arg, "Ds"))
1237 		width = 6;
1238 	else if ((tok = mdoc_hash_find(*arg)) == TOKEN_NONE)
1239 		return;
1240 	else
1241 		width = macro2len(tok);
1242 
1243 	free(*arg);
1244 	mandoc_asprintf(arg, "%zun", width);
1245 }
1246 
1247 static void
1248 post_bl_block_tag(POST_ARGS)
1249 {
1250 	struct roff_node *n, *nn;
1251 	size_t		  sz, ssz;
1252 	int		  i;
1253 	char		  buf[24];
1254 
1255 	/*
1256 	 * Calculate the -width for a `Bl -tag' list if it hasn't been
1257 	 * provided.  Uses the first head macro.  NOTE AGAIN: this is
1258 	 * ONLY if the -width argument has NOT been provided.  See
1259 	 * rewrite_macro2len() for converting the -width string.
1260 	 */
1261 
1262 	sz = 10;
1263 	n = mdoc->last;
1264 
1265 	for (nn = n->body->child; nn; nn = nn->next) {
1266 		if (MDOC_It != nn->tok)
1267 			continue;
1268 
1269 		assert(nn->type == ROFFT_BLOCK);
1270 		nn = nn->head->child;
1271 
1272 		if (nn == NULL)
1273 			break;
1274 
1275 		if (nn->type == ROFFT_TEXT) {
1276 			sz = strlen(nn->string) + 1;
1277 			break;
1278 		}
1279 
1280 		if (0 != (ssz = macro2len(nn->tok)))
1281 			sz = ssz;
1282 
1283 		break;
1284 	}
1285 
1286 	/* Defaults to ten ens. */
1287 
1288 	(void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz);
1289 
1290 	/*
1291 	 * We have to dynamically add this to the macro's argument list.
1292 	 * We're guaranteed that a MDOC_Width doesn't already exist.
1293 	 */
1294 
1295 	assert(n->args);
1296 	i = (int)(n->args->argc)++;
1297 
1298 	n->args->argv = mandoc_reallocarray(n->args->argv,
1299 	    n->args->argc, sizeof(struct mdoc_argv));
1300 
1301 	n->args->argv[i].arg = MDOC_Width;
1302 	n->args->argv[i].line = n->line;
1303 	n->args->argv[i].pos = n->pos;
1304 	n->args->argv[i].sz = 1;
1305 	n->args->argv[i].value = mandoc_malloc(sizeof(char *));
1306 	n->args->argv[i].value[0] = mandoc_strdup(buf);
1307 
1308 	/* Set our width! */
1309 	n->norm->Bl.width = n->args->argv[i].value[0];
1310 }
1311 
1312 static void
1313 post_bl_head(POST_ARGS)
1314 {
1315 	struct roff_node *nbl, *nh, *nch, *nnext;
1316 	struct mdoc_argv *argv;
1317 	int		  i, j;
1318 
1319 	nh = mdoc->last;
1320 
1321 	if (nh->norm->Bl.type != LIST_column) {
1322 		if ((nch = nh->child) == NULL)
1323 			return;
1324 		mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
1325 		    nch->line, nch->pos, "Bl ... %s", nch->string);
1326 		while (nch != NULL) {
1327 			roff_node_delete(mdoc, nch);
1328 			nch = nh->child;
1329 		}
1330 		return;
1331 	}
1332 
1333 	/*
1334 	 * Append old-style lists, where the column width specifiers
1335 	 * trail as macro parameters, to the new-style ("normal-form")
1336 	 * lists where they're argument values following -column.
1337 	 */
1338 
1339 	if (nh->child == NULL)
1340 		return;
1341 
1342 	nbl = nh->parent;
1343 	for (j = 0; j < (int)nbl->args->argc; j++)
1344 		if (nbl->args->argv[j].arg == MDOC_Column)
1345 			break;
1346 
1347 	assert(j < (int)nbl->args->argc);
1348 
1349 	/*
1350 	 * Accommodate for new-style groff column syntax.  Shuffle the
1351 	 * child nodes, all of which must be TEXT, as arguments for the
1352 	 * column field.  Then, delete the head children.
1353 	 */
1354 
1355 	argv = nbl->args->argv + j;
1356 	i = argv->sz;
1357 	argv->sz += nh->nchild;
1358 	argv->value = mandoc_reallocarray(argv->value,
1359 	    argv->sz, sizeof(char *));
1360 
1361 	nh->norm->Bl.ncols = argv->sz;
1362 	nh->norm->Bl.cols = (void *)argv->value;
1363 
1364 	for (nch = nh->child; nch != NULL; nch = nnext) {
1365 		argv->value[i++] = nch->string;
1366 		nch->string = NULL;
1367 		nnext = nch->next;
1368 		roff_node_delete(NULL, nch);
1369 	}
1370 	nh->nchild = 0;
1371 	nh->child = NULL;
1372 }
1373 
1374 static void
1375 post_bl(POST_ARGS)
1376 {
1377 	struct roff_node	*nparent, *nprev; /* of the Bl block */
1378 	struct roff_node	*nblock, *nbody;  /* of the Bl */
1379 	struct roff_node	*nchild, *nnext;  /* of the Bl body */
1380 
1381 	nbody = mdoc->last;
1382 	switch (nbody->type) {
1383 	case ROFFT_BLOCK:
1384 		post_bl_block(mdoc);
1385 		return;
1386 	case ROFFT_HEAD:
1387 		post_bl_head(mdoc);
1388 		return;
1389 	case ROFFT_BODY:
1390 		break;
1391 	default:
1392 		return;
1393 	}
1394 
1395 	nchild = nbody->child;
1396 	if (nchild == NULL) {
1397 		mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
1398 		    nbody->line, nbody->pos, "Bl");
1399 		return;
1400 	}
1401 	while (nchild != NULL) {
1402 		if (nchild->tok == MDOC_It ||
1403 		    (nchild->tok == MDOC_Sm &&
1404 		     nchild->next != NULL &&
1405 		     nchild->next->tok == MDOC_It)) {
1406 			nchild = nchild->next;
1407 			continue;
1408 		}
1409 
1410 		mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse,
1411 		    nchild->line, nchild->pos,
1412 		    mdoc_macronames[nchild->tok]);
1413 
1414 		/*
1415 		 * Move the node out of the Bl block.
1416 		 * First, collect all required node pointers.
1417 		 */
1418 
1419 		nblock  = nbody->parent;
1420 		nprev   = nblock->prev;
1421 		nparent = nblock->parent;
1422 		nnext   = nchild->next;
1423 
1424 		/*
1425 		 * Unlink this child.
1426 		 */
1427 
1428 		assert(NULL == nchild->prev);
1429 		if (0 == --nbody->nchild) {
1430 			nbody->child = NULL;
1431 			nbody->last  = NULL;
1432 			assert(NULL == nnext);
1433 		} else {
1434 			nbody->child = nnext;
1435 			nnext->prev = NULL;
1436 		}
1437 
1438 		/*
1439 		 * Relink this child.
1440 		 */
1441 
1442 		nchild->parent = nparent;
1443 		nchild->prev   = nprev;
1444 		nchild->next   = nblock;
1445 
1446 		nblock->prev = nchild;
1447 		nparent->nchild++;
1448 		if (NULL == nprev)
1449 			nparent->child = nchild;
1450 		else
1451 			nprev->next = nchild;
1452 
1453 		nchild = nnext;
1454 	}
1455 }
1456 
1457 static void
1458 post_bk(POST_ARGS)
1459 {
1460 	struct roff_node	*n;
1461 
1462 	n = mdoc->last;
1463 
1464 	if (n->type == ROFFT_BLOCK && n->body->child == NULL) {
1465 		mandoc_msg(MANDOCERR_BLK_EMPTY,
1466 		    mdoc->parse, n->line, n->pos, "Bk");
1467 		roff_node_delete(mdoc, n);
1468 	}
1469 }
1470 
1471 static void
1472 post_sm(struct roff_man *mdoc)
1473 {
1474 	struct roff_node	*nch;
1475 
1476 	nch = mdoc->last->child;
1477 
1478 	if (nch == NULL) {
1479 		mdoc->flags ^= MDOC_SMOFF;
1480 		return;
1481 	}
1482 
1483 	assert(nch->type == ROFFT_TEXT);
1484 
1485 	if ( ! strcmp(nch->string, "on")) {
1486 		mdoc->flags &= ~MDOC_SMOFF;
1487 		return;
1488 	}
1489 	if ( ! strcmp(nch->string, "off")) {
1490 		mdoc->flags |= MDOC_SMOFF;
1491 		return;
1492 	}
1493 
1494 	mandoc_vmsg(MANDOCERR_SM_BAD,
1495 	    mdoc->parse, nch->line, nch->pos,
1496 	    "%s %s", mdoc_macronames[mdoc->last->tok], nch->string);
1497 	mdoc_node_relink(mdoc, nch);
1498 	return;
1499 }
1500 
1501 static void
1502 post_root(POST_ARGS)
1503 {
1504 	struct roff_node *n;
1505 
1506 	/* Add missing prologue data. */
1507 
1508 	if (mdoc->meta.date == NULL)
1509 		mdoc->meta.date = mdoc->quick ?
1510 		    mandoc_strdup("") :
1511 		    mandoc_normdate(mdoc->parse, NULL, 0, 0);
1512 
1513 	if (mdoc->meta.title == NULL) {
1514 		mandoc_msg(MANDOCERR_DT_NOTITLE,
1515 		    mdoc->parse, 0, 0, "EOF");
1516 		mdoc->meta.title = mandoc_strdup("UNTITLED");
1517 	}
1518 
1519 	if (mdoc->meta.vol == NULL)
1520 		mdoc->meta.vol = mandoc_strdup("LOCAL");
1521 
1522 	if (mdoc->meta.os == NULL) {
1523 		mandoc_msg(MANDOCERR_OS_MISSING,
1524 		    mdoc->parse, 0, 0, NULL);
1525 		mdoc->meta.os = mandoc_strdup("");
1526 	}
1527 
1528 	/* Check that we begin with a proper `Sh'. */
1529 
1530 	n = mdoc->first->child;
1531 	while (n != NULL && n->tok != TOKEN_NONE &&
1532 	    mdoc_macros[n->tok].flags & MDOC_PROLOGUE)
1533 		n = n->next;
1534 
1535 	if (n == NULL)
1536 		mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL);
1537 	else if (n->tok != MDOC_Sh)
1538 		mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse,
1539 		    n->line, n->pos, mdoc_macronames[n->tok]);
1540 }
1541 
1542 static void
1543 post_st(POST_ARGS)
1544 {
1545 	struct roff_node	 *n, *nch;
1546 	const char		 *p;
1547 
1548 	n = mdoc->last;
1549 	nch = n->child;
1550 
1551 	assert(nch->type == ROFFT_TEXT);
1552 
1553 	if (NULL == (p = mdoc_a2st(nch->string))) {
1554 		mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse,
1555 		    nch->line, nch->pos, "St %s", nch->string);
1556 		roff_node_delete(mdoc, n);
1557 	} else {
1558 		free(nch->string);
1559 		nch->string = mandoc_strdup(p);
1560 	}
1561 }
1562 
1563 static void
1564 post_rs(POST_ARGS)
1565 {
1566 	struct roff_node *np, *nch, *next, *prev;
1567 	int		  i, j;
1568 
1569 	np = mdoc->last;
1570 
1571 	if (np->type != ROFFT_BODY)
1572 		return;
1573 
1574 	if (np->child == NULL) {
1575 		mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse,
1576 		    np->line, np->pos, "Rs");
1577 		return;
1578 	}
1579 
1580 	/*
1581 	 * The full `Rs' block needs special handling to order the
1582 	 * sub-elements according to `rsord'.  Pick through each element
1583 	 * and correctly order it.  This is an insertion sort.
1584 	 */
1585 
1586 	next = NULL;
1587 	for (nch = np->child->next; nch != NULL; nch = next) {
1588 		/* Determine order number of this child. */
1589 		for (i = 0; i < RSORD_MAX; i++)
1590 			if (rsord[i] == nch->tok)
1591 				break;
1592 
1593 		if (i == RSORD_MAX) {
1594 			mandoc_msg(MANDOCERR_RS_BAD,
1595 			    mdoc->parse, nch->line, nch->pos,
1596 			    mdoc_macronames[nch->tok]);
1597 			i = -1;
1598 		} else if (nch->tok == MDOC__J || nch->tok == MDOC__B)
1599 			np->norm->Rs.quote_T++;
1600 
1601 		/*
1602 		 * Remove this child from the chain.  This somewhat
1603 		 * repeats roff_node_unlink(), but since we're
1604 		 * just re-ordering, there's no need for the
1605 		 * full unlink process.
1606 		 */
1607 
1608 		if ((next = nch->next) != NULL)
1609 			next->prev = nch->prev;
1610 
1611 		if ((prev = nch->prev) != NULL)
1612 			prev->next = nch->next;
1613 
1614 		nch->prev = nch->next = NULL;
1615 
1616 		/*
1617 		 * Scan back until we reach a node that's
1618 		 * to be ordered before this child.
1619 		 */
1620 
1621 		for ( ; prev ; prev = prev->prev) {
1622 			/* Determine order of `prev'. */
1623 			for (j = 0; j < RSORD_MAX; j++)
1624 				if (rsord[j] == prev->tok)
1625 					break;
1626 			if (j == RSORD_MAX)
1627 				j = -1;
1628 
1629 			if (j <= i)
1630 				break;
1631 		}
1632 
1633 		/*
1634 		 * Set this child back into its correct place
1635 		 * in front of the `prev' node.
1636 		 */
1637 
1638 		nch->prev = prev;
1639 
1640 		if (prev == NULL) {
1641 			np->child->prev = nch;
1642 			nch->next = np->child;
1643 			np->child = nch;
1644 		} else {
1645 			if (prev->next)
1646 				prev->next->prev = nch;
1647 			nch->next = prev->next;
1648 			prev->next = nch;
1649 		}
1650 	}
1651 }
1652 
1653 /*
1654  * For some arguments of some macros,
1655  * convert all breakable hyphens into ASCII_HYPH.
1656  */
1657 static void
1658 post_hyph(POST_ARGS)
1659 {
1660 	struct roff_node	*nch;
1661 	char			*cp;
1662 
1663 	for (nch = mdoc->last->child; nch != NULL; nch = nch->next) {
1664 		if (nch->type != ROFFT_TEXT)
1665 			continue;
1666 		cp = nch->string;
1667 		if (*cp == '\0')
1668 			continue;
1669 		while (*(++cp) != '\0')
1670 			if (*cp == '-' &&
1671 			    isalpha((unsigned char)cp[-1]) &&
1672 			    isalpha((unsigned char)cp[1]))
1673 				*cp = ASCII_HYPH;
1674 	}
1675 }
1676 
1677 static void
1678 post_ns(POST_ARGS)
1679 {
1680 
1681 	if (MDOC_LINE & mdoc->last->flags)
1682 		mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse,
1683 		    mdoc->last->line, mdoc->last->pos, NULL);
1684 }
1685 
1686 static void
1687 post_sh(POST_ARGS)
1688 {
1689 
1690 	post_ignpar(mdoc);
1691 
1692 	switch (mdoc->last->type) {
1693 	case ROFFT_HEAD:
1694 		post_sh_head(mdoc);
1695 		break;
1696 	case ROFFT_BODY:
1697 		switch (mdoc->lastsec)  {
1698 		case SEC_NAME:
1699 			post_sh_name(mdoc);
1700 			break;
1701 		case SEC_SEE_ALSO:
1702 			post_sh_see_also(mdoc);
1703 			break;
1704 		case SEC_AUTHORS:
1705 			post_sh_authors(mdoc);
1706 			break;
1707 		default:
1708 			break;
1709 		}
1710 		break;
1711 	default:
1712 		break;
1713 	}
1714 }
1715 
1716 static void
1717 post_sh_name(POST_ARGS)
1718 {
1719 	struct roff_node *n;
1720 	int hasnm, hasnd;
1721 
1722 	hasnm = hasnd = 0;
1723 
1724 	for (n = mdoc->last->child; n != NULL; n = n->next) {
1725 		switch (n->tok) {
1726 		case MDOC_Nm:
1727 			hasnm = 1;
1728 			break;
1729 		case MDOC_Nd:
1730 			hasnd = 1;
1731 			if (n->next != NULL)
1732 				mandoc_msg(MANDOCERR_NAMESEC_ND,
1733 				    mdoc->parse, n->line, n->pos, NULL);
1734 			break;
1735 		case TOKEN_NONE:
1736 			if (hasnm)
1737 				break;
1738 			/* FALLTHROUGH */
1739 		default:
1740 			mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1741 			    n->line, n->pos, mdoc_macronames[n->tok]);
1742 			break;
1743 		}
1744 	}
1745 
1746 	if ( ! hasnm)
1747 		mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse,
1748 		    mdoc->last->line, mdoc->last->pos, NULL);
1749 	if ( ! hasnd)
1750 		mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse,
1751 		    mdoc->last->line, mdoc->last->pos, NULL);
1752 }
1753 
1754 static void
1755 post_sh_see_also(POST_ARGS)
1756 {
1757 	const struct roff_node	*n;
1758 	const char		*name, *sec;
1759 	const char		*lastname, *lastsec, *lastpunct;
1760 	int			 cmp;
1761 
1762 	n = mdoc->last->child;
1763 	lastname = lastsec = lastpunct = NULL;
1764 	while (n != NULL) {
1765 		if (n->tok != MDOC_Xr || n->nchild < 2)
1766 			break;
1767 
1768 		/* Process one .Xr node. */
1769 
1770 		name = n->child->string;
1771 		sec = n->child->next->string;
1772 		if (lastsec != NULL) {
1773 			if (lastpunct[0] != ',' || lastpunct[1] != '\0')
1774 				mandoc_vmsg(MANDOCERR_XR_PUNCT,
1775 				    mdoc->parse, n->line, n->pos,
1776 				    "%s before %s(%s)", lastpunct,
1777 				    name, sec);
1778 			cmp = strcmp(lastsec, sec);
1779 			if (cmp > 0)
1780 				mandoc_vmsg(MANDOCERR_XR_ORDER,
1781 				    mdoc->parse, n->line, n->pos,
1782 				    "%s(%s) after %s(%s)", name,
1783 				    sec, lastname, lastsec);
1784 			else if (cmp == 0 &&
1785 			    strcasecmp(lastname, name) > 0)
1786 				mandoc_vmsg(MANDOCERR_XR_ORDER,
1787 				    mdoc->parse, n->line, n->pos,
1788 				    "%s after %s", name, lastname);
1789 		}
1790 		lastname = name;
1791 		lastsec = sec;
1792 
1793 		/* Process the following node. */
1794 
1795 		n = n->next;
1796 		if (n == NULL)
1797 			break;
1798 		if (n->tok == MDOC_Xr) {
1799 			lastpunct = "none";
1800 			continue;
1801 		}
1802 		if (n->type != ROFFT_TEXT)
1803 			break;
1804 		for (name = n->string; *name != '\0'; name++)
1805 			if (isalpha((const unsigned char)*name))
1806 				return;
1807 		lastpunct = n->string;
1808 		if (n->next == NULL)
1809 			mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse,
1810 			    n->line, n->pos, "%s after %s(%s)",
1811 			    lastpunct, lastname, lastsec);
1812 		n = n->next;
1813 	}
1814 }
1815 
1816 static int
1817 child_an(const struct roff_node *n)
1818 {
1819 
1820 	for (n = n->child; n != NULL; n = n->next)
1821 		if ((n->tok == MDOC_An && n->nchild) || child_an(n))
1822 			return(1);
1823 	return(0);
1824 }
1825 
1826 static void
1827 post_sh_authors(POST_ARGS)
1828 {
1829 
1830 	if ( ! child_an(mdoc->last))
1831 		mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse,
1832 		    mdoc->last->line, mdoc->last->pos, NULL);
1833 }
1834 
1835 static void
1836 post_sh_head(POST_ARGS)
1837 {
1838 	struct roff_node *n;
1839 	const char	*goodsec;
1840 	char		*secname;
1841 	enum roff_sec	 sec;
1842 
1843 	/*
1844 	 * Process a new section.  Sections are either "named" or
1845 	 * "custom".  Custom sections are user-defined, while named ones
1846 	 * follow a conventional order and may only appear in certain
1847 	 * manual sections.
1848 	 */
1849 
1850 	secname = NULL;
1851 	sec = SEC_CUSTOM;
1852 	deroff(&secname, mdoc->last);
1853 	sec = NULL == secname ? SEC_CUSTOM : a2sec(secname);
1854 
1855 	/* The NAME should be first. */
1856 
1857 	if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1858 		mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
1859 		    mdoc->last->line, mdoc->last->pos,
1860 		    "Sh %s", secname);
1861 
1862 	/* The SYNOPSIS gets special attention in other areas. */
1863 
1864 	if (SEC_SYNOPSIS == sec) {
1865 		roff_setreg(mdoc->roff, "nS", 1, '=');
1866 		mdoc->flags |= MDOC_SYNOPSIS;
1867 	} else {
1868 		roff_setreg(mdoc->roff, "nS", 0, '=');
1869 		mdoc->flags &= ~MDOC_SYNOPSIS;
1870 	}
1871 
1872 	/* Mark our last section. */
1873 
1874 	mdoc->lastsec = sec;
1875 
1876 	/*
1877 	 * Set the section attribute for the current HEAD, for its
1878 	 * parent BLOCK, and for the HEAD children; the latter can
1879 	 * only be TEXT nodes, so no recursion is needed.
1880 	 * For other blocks and elements, including .Sh BODY, this is
1881 	 * done when allocating the node data structures, but for .Sh
1882 	 * BLOCK and HEAD, the section is still unknown at that time.
1883 	 */
1884 
1885 	mdoc->last->parent->sec = sec;
1886 	mdoc->last->sec = sec;
1887 	for (n = mdoc->last->child; n; n = n->next)
1888 		n->sec = sec;
1889 
1890 	/* We don't care about custom sections after this. */
1891 
1892 	if (SEC_CUSTOM == sec) {
1893 		free(secname);
1894 		return;
1895 	}
1896 
1897 	/*
1898 	 * Check whether our non-custom section is being repeated or is
1899 	 * out of order.
1900 	 */
1901 
1902 	if (sec == mdoc->lastnamed)
1903 		mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse,
1904 		    mdoc->last->line, mdoc->last->pos,
1905 		    "Sh %s", secname);
1906 
1907 	if (sec < mdoc->lastnamed)
1908 		mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse,
1909 		    mdoc->last->line, mdoc->last->pos,
1910 		    "Sh %s", secname);
1911 
1912 	/* Mark the last named section. */
1913 
1914 	mdoc->lastnamed = sec;
1915 
1916 	/* Check particular section/manual conventions. */
1917 
1918 	if (mdoc->meta.msec == NULL) {
1919 		free(secname);
1920 		return;
1921 	}
1922 
1923 	goodsec = NULL;
1924 	switch (sec) {
1925 	case SEC_ERRORS:
1926 		if (*mdoc->meta.msec == '4')
1927 			break;
1928 		goodsec = "2, 3, 4, 9";
1929 		/* FALLTHROUGH */
1930 	case SEC_RETURN_VALUES:
1931 		/* FALLTHROUGH */
1932 	case SEC_LIBRARY:
1933 		if (*mdoc->meta.msec == '2')
1934 			break;
1935 		if (*mdoc->meta.msec == '3')
1936 			break;
1937 		if (NULL == goodsec)
1938 			goodsec = "2, 3, 9";
1939 		/* FALLTHROUGH */
1940 	case SEC_CONTEXT:
1941 		if (*mdoc->meta.msec == '9')
1942 			break;
1943 		if (NULL == goodsec)
1944 			goodsec = "9";
1945 		mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse,
1946 		    mdoc->last->line, mdoc->last->pos,
1947 		    "Sh %s for %s only", secname, goodsec);
1948 		break;
1949 	default:
1950 		break;
1951 	}
1952 	free(secname);
1953 }
1954 
1955 static void
1956 post_ignpar(POST_ARGS)
1957 {
1958 	struct roff_node *np;
1959 
1960 	switch (mdoc->last->type) {
1961 	case ROFFT_HEAD:
1962 		post_hyph(mdoc);
1963 		return;
1964 	case ROFFT_BODY:
1965 		break;
1966 	default:
1967 		return;
1968 	}
1969 
1970 	if (NULL != (np = mdoc->last->child))
1971 		if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
1972 			mandoc_vmsg(MANDOCERR_PAR_SKIP,
1973 			    mdoc->parse, np->line, np->pos,
1974 			    "%s after %s", mdoc_macronames[np->tok],
1975 			    mdoc_macronames[mdoc->last->tok]);
1976 			roff_node_delete(mdoc, np);
1977 		}
1978 
1979 	if (NULL != (np = mdoc->last->last))
1980 		if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
1981 			mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
1982 			    np->line, np->pos, "%s at the end of %s",
1983 			    mdoc_macronames[np->tok],
1984 			    mdoc_macronames[mdoc->last->tok]);
1985 			roff_node_delete(mdoc, np);
1986 		}
1987 }
1988 
1989 static void
1990 pre_par(PRE_ARGS)
1991 {
1992 
1993 	if (NULL == mdoc->last)
1994 		return;
1995 	if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK)
1996 		return;
1997 
1998 	/*
1999 	 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
2000 	 * block:  `Lp', `Pp', or non-compact `Bd' or `Bl'.
2001 	 */
2002 
2003 	if (MDOC_Pp != mdoc->last->tok &&
2004 	    MDOC_Lp != mdoc->last->tok &&
2005 	    MDOC_br != mdoc->last->tok)
2006 		return;
2007 	if (MDOC_Bl == n->tok && n->norm->Bl.comp)
2008 		return;
2009 	if (MDOC_Bd == n->tok && n->norm->Bd.comp)
2010 		return;
2011 	if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
2012 		return;
2013 
2014 	mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2015 	    mdoc->last->line, mdoc->last->pos,
2016 	    "%s before %s", mdoc_macronames[mdoc->last->tok],
2017 	    mdoc_macronames[n->tok]);
2018 	roff_node_delete(mdoc, mdoc->last);
2019 }
2020 
2021 static void
2022 post_par(POST_ARGS)
2023 {
2024 	struct roff_node *np;
2025 
2026 	np = mdoc->last;
2027 
2028 	if (np->tok == MDOC_sp) {
2029 		if (np->nchild > 1)
2030 			mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
2031 			    np->child->next->line, np->child->next->pos,
2032 			    "sp ... %s", np->child->next->string);
2033 	} else if (np->child != NULL)
2034 		mandoc_vmsg(MANDOCERR_ARG_SKIP,
2035 		    mdoc->parse, np->line, np->pos, "%s %s",
2036 		    mdoc_macronames[np->tok], np->child->string);
2037 
2038 	if (NULL == (np = mdoc->last->prev)) {
2039 		np = mdoc->last->parent;
2040 		if (MDOC_Sh != np->tok && MDOC_Ss != np->tok)
2041 			return;
2042 	} else if (MDOC_Pp != np->tok && MDOC_Lp != np->tok &&
2043 	    (MDOC_br != mdoc->last->tok ||
2044 	     (MDOC_sp != np->tok && MDOC_br != np->tok)))
2045 		return;
2046 
2047 	mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2048 	    mdoc->last->line, mdoc->last->pos,
2049 	    "%s after %s", mdoc_macronames[mdoc->last->tok],
2050 	    mdoc_macronames[np->tok]);
2051 	roff_node_delete(mdoc, mdoc->last);
2052 }
2053 
2054 static void
2055 pre_literal(PRE_ARGS)
2056 {
2057 
2058 	pre_display(mdoc, n);
2059 
2060 	if (n->type != ROFFT_BODY)
2061 		return;
2062 
2063 	/*
2064 	 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
2065 	 * -unfilled' macros set MDOC_LITERAL on entrance to the body.
2066 	 */
2067 
2068 	switch (n->tok) {
2069 	case MDOC_Dl:
2070 		mdoc->flags |= MDOC_LITERAL;
2071 		break;
2072 	case MDOC_Bd:
2073 		if (DISP_literal == n->norm->Bd.type)
2074 			mdoc->flags |= MDOC_LITERAL;
2075 		if (DISP_unfilled == n->norm->Bd.type)
2076 			mdoc->flags |= MDOC_LITERAL;
2077 		break;
2078 	default:
2079 		abort();
2080 	}
2081 }
2082 
2083 static void
2084 post_dd(POST_ARGS)
2085 {
2086 	struct roff_node *n;
2087 	char		 *datestr;
2088 
2089 	if (mdoc->meta.date)
2090 		free(mdoc->meta.date);
2091 
2092 	n = mdoc->last;
2093 	if (NULL == n->child || '\0' == n->child->string[0]) {
2094 		mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
2095 		    mandoc_normdate(mdoc->parse, NULL, n->line, n->pos);
2096 		goto out;
2097 	}
2098 
2099 	datestr = NULL;
2100 	deroff(&datestr, n);
2101 	if (mdoc->quick)
2102 		mdoc->meta.date = datestr;
2103 	else {
2104 		mdoc->meta.date = mandoc_normdate(mdoc->parse,
2105 		    datestr, n->line, n->pos);
2106 		free(datestr);
2107 	}
2108 out:
2109 	roff_node_delete(mdoc, n);
2110 }
2111 
2112 static void
2113 post_dt(POST_ARGS)
2114 {
2115 	struct roff_node *nn, *n;
2116 	const char	 *cp;
2117 	char		 *p;
2118 
2119 	n = mdoc->last;
2120 
2121 	free(mdoc->meta.title);
2122 	free(mdoc->meta.msec);
2123 	free(mdoc->meta.vol);
2124 	free(mdoc->meta.arch);
2125 
2126 	mdoc->meta.title = NULL;
2127 	mdoc->meta.msec = NULL;
2128 	mdoc->meta.vol = NULL;
2129 	mdoc->meta.arch = NULL;
2130 
2131 	/* Mandatory first argument: title. */
2132 
2133 	nn = n->child;
2134 	if (nn == NULL || *nn->string == '\0') {
2135 		mandoc_msg(MANDOCERR_DT_NOTITLE,
2136 		    mdoc->parse, n->line, n->pos, "Dt");
2137 		mdoc->meta.title = mandoc_strdup("UNTITLED");
2138 	} else {
2139 		mdoc->meta.title = mandoc_strdup(nn->string);
2140 
2141 		/* Check that all characters are uppercase. */
2142 
2143 		for (p = nn->string; *p != '\0'; p++)
2144 			if (islower((unsigned char)*p)) {
2145 				mandoc_vmsg(MANDOCERR_TITLE_CASE,
2146 				    mdoc->parse, nn->line,
2147 				    nn->pos + (p - nn->string),
2148 				    "Dt %s", nn->string);
2149 				break;
2150 			}
2151 	}
2152 
2153 	/* Mandatory second argument: section.�*/
2154 
2155 	if (nn != NULL)
2156 		nn = nn->next;
2157 
2158 	if (nn == NULL) {
2159 		mandoc_vmsg(MANDOCERR_MSEC_MISSING,
2160 		    mdoc->parse, n->line, n->pos,
2161 		    "Dt %s", mdoc->meta.title);
2162 		mdoc->meta.vol = mandoc_strdup("LOCAL");
2163 		goto out;  /* msec and arch remain NULL. */
2164 	}
2165 
2166 	mdoc->meta.msec = mandoc_strdup(nn->string);
2167 
2168 	/* Infer volume title from section number. */
2169 
2170 	cp = mandoc_a2msec(nn->string);
2171 	if (cp == NULL) {
2172 		mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse,
2173 		    nn->line, nn->pos, "Dt ... %s", nn->string);
2174 		mdoc->meta.vol = mandoc_strdup(nn->string);
2175 	} else
2176 		mdoc->meta.vol = mandoc_strdup(cp);
2177 
2178 	/* Optional third argument: architecture. */
2179 
2180 	if ((nn = nn->next) == NULL)
2181 		goto out;
2182 
2183 	for (p = nn->string; *p != '\0'; p++)
2184 		*p = tolower((unsigned char)*p);
2185 	mdoc->meta.arch = mandoc_strdup(nn->string);
2186 
2187 	/* Ignore fourth and later arguments. */
2188 
2189 	if ((nn = nn->next) != NULL)
2190 		mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
2191 		    nn->line, nn->pos, "Dt ... %s", nn->string);
2192 
2193 out:
2194 	roff_node_delete(mdoc, n);
2195 }
2196 
2197 static void
2198 post_bx(POST_ARGS)
2199 {
2200 	struct roff_node	*n;
2201 
2202 	/*
2203 	 * Make `Bx's second argument always start with an uppercase
2204 	 * letter.  Groff checks if it's an "accepted" term, but we just
2205 	 * uppercase blindly.
2206 	 */
2207 
2208 	n = mdoc->last->child;
2209 	if (n && NULL != (n = n->next))
2210 		*n->string = (char)toupper((unsigned char)*n->string);
2211 }
2212 
2213 static void
2214 post_os(POST_ARGS)
2215 {
2216 #ifndef OSNAME
2217 	struct utsname	  utsname;
2218 	static char	 *defbuf;
2219 #endif
2220 	struct roff_node *n;
2221 
2222 	n = mdoc->last;
2223 
2224 	/*
2225 	 * Set the operating system by way of the `Os' macro.
2226 	 * The order of precedence is:
2227 	 * 1. the argument of the `Os' macro, unless empty
2228 	 * 2. the -Ios=foo command line argument, if provided
2229 	 * 3. -DOSNAME="\"foo\"", if provided during compilation
2230 	 * 4. "sysname release" from uname(3)
2231 	 */
2232 
2233 	free(mdoc->meta.os);
2234 	mdoc->meta.os = NULL;
2235 	deroff(&mdoc->meta.os, n);
2236 	if (mdoc->meta.os)
2237 		goto out;
2238 
2239 	if (mdoc->defos) {
2240 		mdoc->meta.os = mandoc_strdup(mdoc->defos);
2241 		goto out;
2242 	}
2243 
2244 #ifdef OSNAME
2245 	mdoc->meta.os = mandoc_strdup(OSNAME);
2246 #else /*!OSNAME */
2247 	if (NULL == defbuf) {
2248 		if (-1 == uname(&utsname)) {
2249 			mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse,
2250 			    n->line, n->pos, "Os");
2251 			defbuf = mandoc_strdup("UNKNOWN");
2252 		} else
2253 			mandoc_asprintf(&defbuf, "%s %s",
2254 			    utsname.sysname, utsname.release);
2255 	}
2256 	mdoc->meta.os = mandoc_strdup(defbuf);
2257 #endif /*!OSNAME*/
2258 
2259 out:
2260 	roff_node_delete(mdoc, n);
2261 }
2262 
2263 /*
2264  * If no argument is provided,
2265  * fill in the name of the current manual page.
2266  */
2267 static void
2268 post_ex(POST_ARGS)
2269 {
2270 	struct roff_node *n;
2271 
2272 	n = mdoc->last;
2273 
2274 	if (n->child)
2275 		return;
2276 
2277 	if (mdoc->meta.name == NULL) {
2278 		mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse,
2279 		    n->line, n->pos, "Ex");
2280 		return;
2281 	}
2282 
2283 	mdoc->next = ROFF_NEXT_CHILD;
2284 	roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name);
2285 	mdoc->last = n;
2286 }
2287 
2288 static enum roff_sec
2289 a2sec(const char *p)
2290 {
2291 	int		 i;
2292 
2293 	for (i = 0; i < (int)SEC__MAX; i++)
2294 		if (secnames[i] && 0 == strcmp(p, secnames[i]))
2295 			return((enum roff_sec)i);
2296 
2297 	return(SEC_CUSTOM);
2298 }
2299 
2300 static size_t
2301 macro2len(int macro)
2302 {
2303 
2304 	switch (macro) {
2305 	case MDOC_Ad:
2306 		return(12);
2307 	case MDOC_Ao:
2308 		return(12);
2309 	case MDOC_An:
2310 		return(12);
2311 	case MDOC_Aq:
2312 		return(12);
2313 	case MDOC_Ar:
2314 		return(12);
2315 	case MDOC_Bo:
2316 		return(12);
2317 	case MDOC_Bq:
2318 		return(12);
2319 	case MDOC_Cd:
2320 		return(12);
2321 	case MDOC_Cm:
2322 		return(10);
2323 	case MDOC_Do:
2324 		return(10);
2325 	case MDOC_Dq:
2326 		return(12);
2327 	case MDOC_Dv:
2328 		return(12);
2329 	case MDOC_Eo:
2330 		return(12);
2331 	case MDOC_Em:
2332 		return(10);
2333 	case MDOC_Er:
2334 		return(17);
2335 	case MDOC_Ev:
2336 		return(15);
2337 	case MDOC_Fa:
2338 		return(12);
2339 	case MDOC_Fl:
2340 		return(10);
2341 	case MDOC_Fo:
2342 		return(16);
2343 	case MDOC_Fn:
2344 		return(16);
2345 	case MDOC_Ic:
2346 		return(10);
2347 	case MDOC_Li:
2348 		return(16);
2349 	case MDOC_Ms:
2350 		return(6);
2351 	case MDOC_Nm:
2352 		return(10);
2353 	case MDOC_No:
2354 		return(12);
2355 	case MDOC_Oo:
2356 		return(10);
2357 	case MDOC_Op:
2358 		return(14);
2359 	case MDOC_Pa:
2360 		return(32);
2361 	case MDOC_Pf:
2362 		return(12);
2363 	case MDOC_Po:
2364 		return(12);
2365 	case MDOC_Pq:
2366 		return(12);
2367 	case MDOC_Ql:
2368 		return(16);
2369 	case MDOC_Qo:
2370 		return(12);
2371 	case MDOC_So:
2372 		return(12);
2373 	case MDOC_Sq:
2374 		return(12);
2375 	case MDOC_Sy:
2376 		return(6);
2377 	case MDOC_Sx:
2378 		return(16);
2379 	case MDOC_Tn:
2380 		return(10);
2381 	case MDOC_Va:
2382 		return(12);
2383 	case MDOC_Vt:
2384 		return(12);
2385 	case MDOC_Xr:
2386 		return(10);
2387 	default:
2388 		break;
2389 	};
2390 	return(0);
2391 }
2392