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