xref: /titanic_50/usr/src/cmd/mandoc/mdoc_validate.c (revision 880d797826457b77414b37d531cc3e1aa166ecbe)
1 /*	$Id: mdoc_validate.c,v 1.283 2015/02/23 13:55:55 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 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 			mdoc_node_delete(mdoc, n->last);
907 	}
908 
909 	post_fname(mdoc);
910 }
911 
912 static void
913 post_fa(POST_ARGS)
914 {
915 	const struct mdoc_node *n;
916 	const char *cp;
917 
918 	for (n = mdoc->last->child; n != NULL; n = n->next) {
919 		for (cp = n->string; *cp != '\0'; cp++) {
920 			/* Ignore callbacks and alterations. */
921 			if (*cp == '(' || *cp == '{')
922 				break;
923 			if (*cp != ',')
924 				continue;
925 			mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse,
926 			    n->line, n->pos + (cp - n->string),
927 			    n->string);
928 			break;
929 		}
930 	}
931 }
932 
933 static void
934 post_vt(POST_ARGS)
935 {
936 	const struct mdoc_node *n;
937 
938 	/*
939 	 * The Vt macro comes in both ELEM and BLOCK form, both of which
940 	 * have different syntaxes (yet more context-sensitive
941 	 * behaviour).  ELEM types must have a child, which is already
942 	 * guaranteed by the in_line parsing routine; BLOCK types,
943 	 * specifically the BODY, should only have TEXT children.
944 	 */
945 
946 	if (MDOC_BODY != mdoc->last->type)
947 		return;
948 
949 	for (n = mdoc->last->child; n; n = n->next)
950 		if (MDOC_TEXT != n->type)
951 			mandoc_msg(MANDOCERR_VT_CHILD, mdoc->parse,
952 			    n->line, n->pos, mdoc_macronames[n->tok]);
953 }
954 
955 static void
956 post_nm(POST_ARGS)
957 {
958 	struct mdoc_node	*n;
959 
960 	n = mdoc->last;
961 
962 	if (n->last != NULL &&
963 	    (n->last->tok == MDOC_Pp ||
964 	     n->last->tok == MDOC_Lp))
965 		mdoc_node_relink(mdoc, n->last);
966 
967 	if (NULL != mdoc->meta.name)
968 		return;
969 
970 	mdoc_deroff(&mdoc->meta.name, n);
971 
972 	if (NULL == mdoc->meta.name)
973 		mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse,
974 		    n->line, n->pos, "Nm");
975 }
976 
977 static void
978 post_nd(POST_ARGS)
979 {
980 	struct mdoc_node	*n;
981 
982 	n = mdoc->last;
983 
984 	if (n->type != MDOC_BODY)
985 		return;
986 
987 	if (n->child == NULL)
988 		mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse,
989 		    n->line, n->pos, "Nd");
990 
991 	post_hyph(mdoc);
992 }
993 
994 static void
995 post_d1(POST_ARGS)
996 {
997 	struct mdoc_node	*n;
998 
999 	n = mdoc->last;
1000 
1001 	if (n->type != MDOC_BODY)
1002 		return;
1003 
1004 	if (n->child == NULL)
1005 		mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
1006 		    n->line, n->pos, "D1");
1007 
1008 	post_hyph(mdoc);
1009 }
1010 
1011 static void
1012 post_literal(POST_ARGS)
1013 {
1014 	struct mdoc_node	*n;
1015 
1016 	n = mdoc->last;
1017 
1018 	if (n->type != MDOC_BODY)
1019 		return;
1020 
1021 	if (n->child == NULL)
1022 		mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
1023 		    n->line, n->pos, mdoc_macronames[n->tok]);
1024 
1025 	if (n->tok == MDOC_Bd &&
1026 	    n->norm->Bd.type != DISP_literal &&
1027 	    n->norm->Bd.type != DISP_unfilled)
1028 		return;
1029 
1030 	mdoc->flags &= ~MDOC_LITERAL;
1031 }
1032 
1033 static void
1034 post_defaults(POST_ARGS)
1035 {
1036 	struct mdoc_node *nn;
1037 
1038 	/*
1039 	 * The `Ar' defaults to "file ..." if no value is provided as an
1040 	 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
1041 	 * gets an empty string.
1042 	 */
1043 
1044 	if (mdoc->last->child)
1045 		return;
1046 
1047 	nn = mdoc->last;
1048 	mdoc->next = MDOC_NEXT_CHILD;
1049 
1050 	switch (nn->tok) {
1051 	case MDOC_Ar:
1052 		mdoc_word_alloc(mdoc, nn->line, nn->pos, "file");
1053 		mdoc_word_alloc(mdoc, nn->line, nn->pos, "...");
1054 		break;
1055 	case MDOC_Pa:
1056 		/* FALLTHROUGH */
1057 	case MDOC_Mt:
1058 		mdoc_word_alloc(mdoc, nn->line, nn->pos, "~");
1059 		break;
1060 	default:
1061 		abort();
1062 		/* NOTREACHED */
1063 	}
1064 	mdoc->last = nn;
1065 }
1066 
1067 static void
1068 post_at(POST_ARGS)
1069 {
1070 	struct mdoc_node	*n;
1071 	const char		*std_att;
1072 	char			*att;
1073 
1074 	n = mdoc->last;
1075 	if (n->child == NULL) {
1076 		mdoc->next = MDOC_NEXT_CHILD;
1077 		mdoc_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX");
1078 		mdoc->last = n;
1079 		return;
1080 	}
1081 
1082 	/*
1083 	 * If we have a child, look it up in the standard keys.  If a
1084 	 * key exist, use that instead of the child; if it doesn't,
1085 	 * prefix "AT&T UNIX " to the existing data.
1086 	 */
1087 
1088 	n = n->child;
1089 	assert(MDOC_TEXT == n->type);
1090 	if (NULL == (std_att = mdoc_a2att(n->string))) {
1091 		mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse,
1092 		    n->line, n->pos, "At %s", n->string);
1093 		mandoc_asprintf(&att, "AT&T UNIX %s", n->string);
1094 	} else
1095 		att = mandoc_strdup(std_att);
1096 
1097 	free(n->string);
1098 	n->string = att;
1099 }
1100 
1101 static void
1102 post_an(POST_ARGS)
1103 {
1104 	struct mdoc_node *np, *nch;
1105 
1106 	np = mdoc->last;
1107 	nch = np->child;
1108 	if (np->norm->An.auth == AUTH__NONE) {
1109 		if (nch == NULL)
1110 			mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
1111 			    np->line, np->pos, "An");
1112 	} else if (nch != NULL)
1113 		mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
1114 		    nch->line, nch->pos, "An ... %s", nch->string);
1115 }
1116 
1117 static void
1118 post_en(POST_ARGS)
1119 {
1120 
1121 	if (MDOC_BLOCK == mdoc->last->type)
1122 		mdoc->last->norm->Es = mdoc->last_es;
1123 }
1124 
1125 static void
1126 post_es(POST_ARGS)
1127 {
1128 
1129 	mdoc->last_es = mdoc->last;
1130 }
1131 
1132 static void
1133 post_it(POST_ARGS)
1134 {
1135 	int		  i, cols;
1136 	enum mdoc_list	  lt;
1137 	struct mdoc_node *nbl, *nit, *nch;
1138 
1139 	nit = mdoc->last;
1140 	if (nit->type != MDOC_BLOCK)
1141 		return;
1142 
1143 	nbl = nit->parent->parent;
1144 	lt = nbl->norm->Bl.type;
1145 
1146 	switch (lt) {
1147 	case LIST_tag:
1148 		/* FALLTHROUGH */
1149 	case LIST_hang:
1150 		/* FALLTHROUGH */
1151 	case LIST_ohang:
1152 		/* FALLTHROUGH */
1153 	case LIST_inset:
1154 		/* FALLTHROUGH */
1155 	case LIST_diag:
1156 		if (nit->head->child == NULL)
1157 			mandoc_vmsg(MANDOCERR_IT_NOHEAD,
1158 			    mdoc->parse, nit->line, nit->pos,
1159 			    "Bl -%s It",
1160 			    mdoc_argnames[nbl->args->argv[0].arg]);
1161 		break;
1162 	case LIST_bullet:
1163 		/* FALLTHROUGH */
1164 	case LIST_dash:
1165 		/* FALLTHROUGH */
1166 	case LIST_enum:
1167 		/* FALLTHROUGH */
1168 	case LIST_hyphen:
1169 		if (nit->body == NULL || nit->body->child == NULL)
1170 			mandoc_vmsg(MANDOCERR_IT_NOBODY,
1171 			    mdoc->parse, nit->line, nit->pos,
1172 			    "Bl -%s It",
1173 			    mdoc_argnames[nbl->args->argv[0].arg]);
1174 		/* FALLTHROUGH */
1175 	case LIST_item:
1176 		if (nit->head->child != NULL)
1177 			mandoc_vmsg(MANDOCERR_ARG_SKIP,
1178 			    mdoc->parse, nit->line, nit->pos,
1179 			    "It %s", nit->head->child->string);
1180 		break;
1181 	case LIST_column:
1182 		cols = (int)nbl->norm->Bl.ncols;
1183 
1184 		assert(nit->head->child == NULL);
1185 
1186 		for (i = 0, nch = nit->child; nch; nch = nch->next)
1187 			if (nch->type == MDOC_BODY)
1188 				i++;
1189 
1190 		if (i < cols || i > cols + 1)
1191 			mandoc_vmsg(MANDOCERR_BL_COL,
1192 			    mdoc->parse, nit->line, nit->pos,
1193 			    "%d columns, %d cells", cols, i);
1194 		break;
1195 	default:
1196 		abort();
1197 	}
1198 }
1199 
1200 static void
1201 post_bl_block(POST_ARGS)
1202 {
1203 	struct mdoc_node *n, *ni, *nc;
1204 
1205 	/*
1206 	 * These are fairly complicated, so we've broken them into two
1207 	 * functions.  post_bl_block_tag() is called when a -tag is
1208 	 * specified, but no -width (it must be guessed).  The second
1209 	 * when a -width is specified (macro indicators must be
1210 	 * rewritten into real lengths).
1211 	 */
1212 
1213 	n = mdoc->last;
1214 
1215 	if (LIST_tag == n->norm->Bl.type &&
1216 	    NULL == n->norm->Bl.width) {
1217 		post_bl_block_tag(mdoc);
1218 		assert(n->norm->Bl.width);
1219 	}
1220 
1221 	for (ni = n->body->child; ni; ni = ni->next) {
1222 		if (NULL == ni->body)
1223 			continue;
1224 		nc = ni->body->last;
1225 		while (NULL != nc) {
1226 			switch (nc->tok) {
1227 			case MDOC_Pp:
1228 				/* FALLTHROUGH */
1229 			case MDOC_Lp:
1230 				/* FALLTHROUGH */
1231 			case MDOC_br:
1232 				break;
1233 			default:
1234 				nc = NULL;
1235 				continue;
1236 			}
1237 			if (NULL == ni->next) {
1238 				mandoc_msg(MANDOCERR_PAR_MOVE,
1239 				    mdoc->parse, nc->line, nc->pos,
1240 				    mdoc_macronames[nc->tok]);
1241 				mdoc_node_relink(mdoc, nc);
1242 			} else if (0 == n->norm->Bl.comp &&
1243 			    LIST_column != n->norm->Bl.type) {
1244 				mandoc_vmsg(MANDOCERR_PAR_SKIP,
1245 				    mdoc->parse, nc->line, nc->pos,
1246 				    "%s before It",
1247 				    mdoc_macronames[nc->tok]);
1248 				mdoc_node_delete(mdoc, nc);
1249 			} else
1250 				break;
1251 			nc = ni->body->last;
1252 		}
1253 	}
1254 }
1255 
1256 /*
1257  * If the argument of -offset or -width is a macro,
1258  * replace it with the associated default width.
1259  */
1260 void
1261 rewrite_macro2len(char **arg)
1262 {
1263 	size_t		  width;
1264 	enum mdoct	  tok;
1265 
1266 	if (*arg == NULL)
1267 		return;
1268 	else if ( ! strcmp(*arg, "Ds"))
1269 		width = 6;
1270 	else if ((tok = mdoc_hash_find(*arg)) == MDOC_MAX)
1271 		return;
1272 	else
1273 		width = macro2len(tok);
1274 
1275 	free(*arg);
1276 	mandoc_asprintf(arg, "%zun", width);
1277 }
1278 
1279 static void
1280 post_bl_block_tag(POST_ARGS)
1281 {
1282 	struct mdoc_node *n, *nn;
1283 	size_t		  sz, ssz;
1284 	int		  i;
1285 	char		  buf[24];
1286 
1287 	/*
1288 	 * Calculate the -width for a `Bl -tag' list if it hasn't been
1289 	 * provided.  Uses the first head macro.  NOTE AGAIN: this is
1290 	 * ONLY if the -width argument has NOT been provided.  See
1291 	 * rewrite_macro2len() for converting the -width string.
1292 	 */
1293 
1294 	sz = 10;
1295 	n = mdoc->last;
1296 
1297 	for (nn = n->body->child; nn; nn = nn->next) {
1298 		if (MDOC_It != nn->tok)
1299 			continue;
1300 
1301 		assert(MDOC_BLOCK == nn->type);
1302 		nn = nn->head->child;
1303 
1304 		if (nn == NULL)
1305 			break;
1306 
1307 		if (MDOC_TEXT == nn->type) {
1308 			sz = strlen(nn->string) + 1;
1309 			break;
1310 		}
1311 
1312 		if (0 != (ssz = macro2len(nn->tok)))
1313 			sz = ssz;
1314 
1315 		break;
1316 	}
1317 
1318 	/* Defaults to ten ens. */
1319 
1320 	(void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz);
1321 
1322 	/*
1323 	 * We have to dynamically add this to the macro's argument list.
1324 	 * We're guaranteed that a MDOC_Width doesn't already exist.
1325 	 */
1326 
1327 	assert(n->args);
1328 	i = (int)(n->args->argc)++;
1329 
1330 	n->args->argv = mandoc_reallocarray(n->args->argv,
1331 	    n->args->argc, sizeof(struct mdoc_argv));
1332 
1333 	n->args->argv[i].arg = MDOC_Width;
1334 	n->args->argv[i].line = n->line;
1335 	n->args->argv[i].pos = n->pos;
1336 	n->args->argv[i].sz = 1;
1337 	n->args->argv[i].value = mandoc_malloc(sizeof(char *));
1338 	n->args->argv[i].value[0] = mandoc_strdup(buf);
1339 
1340 	/* Set our width! */
1341 	n->norm->Bl.width = n->args->argv[i].value[0];
1342 }
1343 
1344 static void
1345 post_bl_head(POST_ARGS)
1346 {
1347 	struct mdoc_node *nbl, *nh, *nch, *nnext;
1348 	struct mdoc_argv *argv;
1349 	int		  i, j;
1350 
1351 	nh = mdoc->last;
1352 
1353 	if (nh->norm->Bl.type != LIST_column) {
1354 		if ((nch = nh->child) == NULL)
1355 			return;
1356 		mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
1357 		    nch->line, nch->pos, "Bl ... %s", nch->string);
1358 		while (nch != NULL) {
1359 			mdoc_node_delete(mdoc, nch);
1360 			nch = nh->child;
1361 		}
1362 		return;
1363 	}
1364 
1365 	/*
1366 	 * Append old-style lists, where the column width specifiers
1367 	 * trail as macro parameters, to the new-style ("normal-form")
1368 	 * lists where they're argument values following -column.
1369 	 */
1370 
1371 	if (nh->child == NULL)
1372 		return;
1373 
1374 	nbl = nh->parent;
1375 	for (j = 0; j < (int)nbl->args->argc; j++)
1376 		if (nbl->args->argv[j].arg == MDOC_Column)
1377 			break;
1378 
1379 	assert(j < (int)nbl->args->argc);
1380 
1381 	/*
1382 	 * Accommodate for new-style groff column syntax.  Shuffle the
1383 	 * child nodes, all of which must be TEXT, as arguments for the
1384 	 * column field.  Then, delete the head children.
1385 	 */
1386 
1387 	argv = nbl->args->argv + j;
1388 	i = argv->sz;
1389 	argv->sz += nh->nchild;
1390 	argv->value = mandoc_reallocarray(argv->value,
1391 	    argv->sz, sizeof(char *));
1392 
1393 	nh->norm->Bl.ncols = argv->sz;
1394 	nh->norm->Bl.cols = (void *)argv->value;
1395 
1396 	for (nch = nh->child; nch != NULL; nch = nnext) {
1397 		argv->value[i++] = nch->string;
1398 		nch->string = NULL;
1399 		nnext = nch->next;
1400 		mdoc_node_delete(NULL, nch);
1401 	}
1402 	nh->nchild = 0;
1403 	nh->child = NULL;
1404 }
1405 
1406 static void
1407 post_bl(POST_ARGS)
1408 {
1409 	struct mdoc_node	*nparent, *nprev; /* of the Bl block */
1410 	struct mdoc_node	*nblock, *nbody;  /* of the Bl */
1411 	struct mdoc_node	*nchild, *nnext;  /* of the Bl body */
1412 
1413 	nbody = mdoc->last;
1414 	switch (nbody->type) {
1415 	case MDOC_BLOCK:
1416 		post_bl_block(mdoc);
1417 		return;
1418 	case MDOC_HEAD:
1419 		post_bl_head(mdoc);
1420 		return;
1421 	case MDOC_BODY:
1422 		break;
1423 	default:
1424 		return;
1425 	}
1426 
1427 	nchild = nbody->child;
1428 	if (nchild == NULL) {
1429 		mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
1430 		    nbody->line, nbody->pos, "Bl");
1431 		return;
1432 	}
1433 	while (nchild != NULL) {
1434 		if (nchild->tok == MDOC_It ||
1435 		    (nchild->tok == MDOC_Sm &&
1436 		     nchild->next != NULL &&
1437 		     nchild->next->tok == MDOC_It)) {
1438 			nchild = nchild->next;
1439 			continue;
1440 		}
1441 
1442 		mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse,
1443 		    nchild->line, nchild->pos,
1444 		    mdoc_macronames[nchild->tok]);
1445 
1446 		/*
1447 		 * Move the node out of the Bl block.
1448 		 * First, collect all required node pointers.
1449 		 */
1450 
1451 		nblock  = nbody->parent;
1452 		nprev   = nblock->prev;
1453 		nparent = nblock->parent;
1454 		nnext   = nchild->next;
1455 
1456 		/*
1457 		 * Unlink this child.
1458 		 */
1459 
1460 		assert(NULL == nchild->prev);
1461 		if (0 == --nbody->nchild) {
1462 			nbody->child = NULL;
1463 			nbody->last  = NULL;
1464 			assert(NULL == nnext);
1465 		} else {
1466 			nbody->child = nnext;
1467 			nnext->prev = NULL;
1468 		}
1469 
1470 		/*
1471 		 * Relink this child.
1472 		 */
1473 
1474 		nchild->parent = nparent;
1475 		nchild->prev   = nprev;
1476 		nchild->next   = nblock;
1477 
1478 		nblock->prev = nchild;
1479 		nparent->nchild++;
1480 		if (NULL == nprev)
1481 			nparent->child = nchild;
1482 		else
1483 			nprev->next = nchild;
1484 
1485 		nchild = nnext;
1486 	}
1487 }
1488 
1489 static void
1490 post_bk(POST_ARGS)
1491 {
1492 	struct mdoc_node	*n;
1493 
1494 	n = mdoc->last;
1495 
1496 	if (n->type == MDOC_BLOCK && n->body->child == NULL) {
1497 		mandoc_msg(MANDOCERR_BLK_EMPTY,
1498 		    mdoc->parse, n->line, n->pos, "Bk");
1499 		mdoc_node_delete(mdoc, n);
1500 	}
1501 }
1502 
1503 static void
1504 post_sm(struct mdoc *mdoc)
1505 {
1506 	struct mdoc_node	*nch;
1507 
1508 	nch = mdoc->last->child;
1509 
1510 	if (nch == NULL) {
1511 		mdoc->flags ^= MDOC_SMOFF;
1512 		return;
1513 	}
1514 
1515 	assert(nch->type == MDOC_TEXT);
1516 
1517 	if ( ! strcmp(nch->string, "on")) {
1518 		mdoc->flags &= ~MDOC_SMOFF;
1519 		return;
1520 	}
1521 	if ( ! strcmp(nch->string, "off")) {
1522 		mdoc->flags |= MDOC_SMOFF;
1523 		return;
1524 	}
1525 
1526 	mandoc_vmsg(MANDOCERR_SM_BAD,
1527 	    mdoc->parse, nch->line, nch->pos,
1528 	    "%s %s", mdoc_macronames[mdoc->last->tok], nch->string);
1529 	mdoc_node_relink(mdoc, nch);
1530 	return;
1531 }
1532 
1533 static void
1534 post_root(POST_ARGS)
1535 {
1536 	struct mdoc_node *n;
1537 
1538 	/* Add missing prologue data. */
1539 
1540 	if (mdoc->meta.date == NULL)
1541 		mdoc->meta.date = mdoc->quick ?
1542 		    mandoc_strdup("") :
1543 		    mandoc_normdate(mdoc->parse, NULL, 0, 0);
1544 
1545 	if (mdoc->meta.title == NULL) {
1546 		mandoc_msg(MANDOCERR_DT_NOTITLE,
1547 		    mdoc->parse, 0, 0, "EOF");
1548 		mdoc->meta.title = mandoc_strdup("UNTITLED");
1549 	}
1550 
1551 	if (mdoc->meta.vol == NULL)
1552 		mdoc->meta.vol = mandoc_strdup("LOCAL");
1553 
1554 	if (mdoc->meta.os == NULL) {
1555 		mandoc_msg(MANDOCERR_OS_MISSING,
1556 		    mdoc->parse, 0, 0, NULL);
1557 		mdoc->meta.os = mandoc_strdup("");
1558 	}
1559 
1560 	/* Check that we begin with a proper `Sh'. */
1561 
1562 	n = mdoc->first->child;
1563 	while (n != NULL && mdoc_macros[n->tok].flags & MDOC_PROLOGUE)
1564 		n = n->next;
1565 
1566 	if (n == NULL)
1567 		mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL);
1568 	else if (n->tok != MDOC_Sh)
1569 		mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse,
1570 		    n->line, n->pos, mdoc_macronames[n->tok]);
1571 }
1572 
1573 static void
1574 post_st(POST_ARGS)
1575 {
1576 	struct mdoc_node	 *n, *nch;
1577 	const char		 *p;
1578 
1579 	n = mdoc->last;
1580 	nch = n->child;
1581 
1582 	assert(MDOC_TEXT == nch->type);
1583 
1584 	if (NULL == (p = mdoc_a2st(nch->string))) {
1585 		mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse,
1586 		    nch->line, nch->pos, "St %s", nch->string);
1587 		mdoc_node_delete(mdoc, n);
1588 	} else {
1589 		free(nch->string);
1590 		nch->string = mandoc_strdup(p);
1591 	}
1592 }
1593 
1594 static void
1595 post_rs(POST_ARGS)
1596 {
1597 	struct mdoc_node *np, *nch, *next, *prev;
1598 	int		  i, j;
1599 
1600 	np = mdoc->last;
1601 
1602 	if (np->type != MDOC_BODY)
1603 		return;
1604 
1605 	if (np->child == NULL) {
1606 		mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse,
1607 		    np->line, np->pos, "Rs");
1608 		return;
1609 	}
1610 
1611 	/*
1612 	 * The full `Rs' block needs special handling to order the
1613 	 * sub-elements according to `rsord'.  Pick through each element
1614 	 * and correctly order it.  This is an insertion sort.
1615 	 */
1616 
1617 	next = NULL;
1618 	for (nch = np->child->next; nch != NULL; nch = next) {
1619 		/* Determine order number of this child. */
1620 		for (i = 0; i < RSORD_MAX; i++)
1621 			if (rsord[i] == nch->tok)
1622 				break;
1623 
1624 		if (i == RSORD_MAX) {
1625 			mandoc_msg(MANDOCERR_RS_BAD,
1626 			    mdoc->parse, nch->line, nch->pos,
1627 			    mdoc_macronames[nch->tok]);
1628 			i = -1;
1629 		} else if (nch->tok == MDOC__J || nch->tok == MDOC__B)
1630 			np->norm->Rs.quote_T++;
1631 
1632 		/*
1633 		 * Remove this child from the chain.  This somewhat
1634 		 * repeats mdoc_node_unlink(), but since we're
1635 		 * just re-ordering, there's no need for the
1636 		 * full unlink process.
1637 		 */
1638 
1639 		if ((next = nch->next) != NULL)
1640 			next->prev = nch->prev;
1641 
1642 		if ((prev = nch->prev) != NULL)
1643 			prev->next = nch->next;
1644 
1645 		nch->prev = nch->next = NULL;
1646 
1647 		/*
1648 		 * Scan back until we reach a node that's
1649 		 * to be ordered before this child.
1650 		 */
1651 
1652 		for ( ; prev ; prev = prev->prev) {
1653 			/* Determine order of `prev'. */
1654 			for (j = 0; j < RSORD_MAX; j++)
1655 				if (rsord[j] == prev->tok)
1656 					break;
1657 			if (j == RSORD_MAX)
1658 				j = -1;
1659 
1660 			if (j <= i)
1661 				break;
1662 		}
1663 
1664 		/*
1665 		 * Set this child back into its correct place
1666 		 * in front of the `prev' node.
1667 		 */
1668 
1669 		nch->prev = prev;
1670 
1671 		if (prev == NULL) {
1672 			np->child->prev = nch;
1673 			nch->next = np->child;
1674 			np->child = nch;
1675 		} else {
1676 			if (prev->next)
1677 				prev->next->prev = nch;
1678 			nch->next = prev->next;
1679 			prev->next = nch;
1680 		}
1681 	}
1682 }
1683 
1684 /*
1685  * For some arguments of some macros,
1686  * convert all breakable hyphens into ASCII_HYPH.
1687  */
1688 static void
1689 post_hyph(POST_ARGS)
1690 {
1691 	struct mdoc_node	*nch;
1692 	char			*cp;
1693 
1694 	for (nch = mdoc->last->child; nch != NULL; nch = nch->next) {
1695 		if (nch->type != MDOC_TEXT)
1696 			continue;
1697 		cp = nch->string;
1698 		if (*cp == '\0')
1699 			continue;
1700 		while (*(++cp) != '\0')
1701 			if (*cp == '-' &&
1702 			    isalpha((unsigned char)cp[-1]) &&
1703 			    isalpha((unsigned char)cp[1]))
1704 				*cp = ASCII_HYPH;
1705 	}
1706 }
1707 
1708 static void
1709 post_ns(POST_ARGS)
1710 {
1711 
1712 	if (MDOC_LINE & mdoc->last->flags)
1713 		mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse,
1714 		    mdoc->last->line, mdoc->last->pos, NULL);
1715 }
1716 
1717 static void
1718 post_sh(POST_ARGS)
1719 {
1720 
1721 	post_ignpar(mdoc);
1722 
1723 	switch (mdoc->last->type) {
1724 	case MDOC_HEAD:
1725 		post_sh_head(mdoc);
1726 		break;
1727 	case MDOC_BODY:
1728 		switch (mdoc->lastsec)  {
1729 		case SEC_NAME:
1730 			post_sh_name(mdoc);
1731 			break;
1732 		case SEC_SEE_ALSO:
1733 			post_sh_see_also(mdoc);
1734 			break;
1735 		case SEC_AUTHORS:
1736 			post_sh_authors(mdoc);
1737 			break;
1738 		default:
1739 			break;
1740 		}
1741 		break;
1742 	default:
1743 		break;
1744 	}
1745 }
1746 
1747 static void
1748 post_sh_name(POST_ARGS)
1749 {
1750 	struct mdoc_node *n;
1751 	int hasnm, hasnd;
1752 
1753 	hasnm = hasnd = 0;
1754 
1755 	for (n = mdoc->last->child; n != NULL; n = n->next) {
1756 		switch (n->tok) {
1757 		case MDOC_Nm:
1758 			hasnm = 1;
1759 			break;
1760 		case MDOC_Nd:
1761 			hasnd = 1;
1762 			if (n->next != NULL)
1763 				mandoc_msg(MANDOCERR_NAMESEC_ND,
1764 				    mdoc->parse, n->line, n->pos, NULL);
1765 			break;
1766 		case MDOC_MAX:
1767 			if (hasnm)
1768 				break;
1769 			/* FALLTHROUGH */
1770 		default:
1771 			mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1772 			    n->line, n->pos, mdoc_macronames[n->tok]);
1773 			break;
1774 		}
1775 	}
1776 
1777 	if ( ! hasnm)
1778 		mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse,
1779 		    mdoc->last->line, mdoc->last->pos, NULL);
1780 	if ( ! hasnd)
1781 		mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse,
1782 		    mdoc->last->line, mdoc->last->pos, NULL);
1783 }
1784 
1785 static void
1786 post_sh_see_also(POST_ARGS)
1787 {
1788 	const struct mdoc_node	*n;
1789 	const char		*name, *sec;
1790 	const char		*lastname, *lastsec, *lastpunct;
1791 	int			 cmp;
1792 
1793 	n = mdoc->last->child;
1794 	lastname = lastsec = lastpunct = NULL;
1795 	while (n != NULL) {
1796 		if (n->tok != MDOC_Xr || n->nchild < 2)
1797 			break;
1798 
1799 		/* Process one .Xr node. */
1800 
1801 		name = n->child->string;
1802 		sec = n->child->next->string;
1803 		if (lastsec != NULL) {
1804 			if (lastpunct[0] != ',' || lastpunct[1] != '\0')
1805 				mandoc_vmsg(MANDOCERR_XR_PUNCT,
1806 				    mdoc->parse, n->line, n->pos,
1807 				    "%s before %s(%s)", lastpunct,
1808 				    name, sec);
1809 			cmp = strcmp(lastsec, sec);
1810 			if (cmp > 0)
1811 				mandoc_vmsg(MANDOCERR_XR_ORDER,
1812 				    mdoc->parse, n->line, n->pos,
1813 				    "%s(%s) after %s(%s)", name,
1814 				    sec, lastname, lastsec);
1815 			else if (cmp == 0 &&
1816 			    strcasecmp(lastname, name) > 0)
1817 				mandoc_vmsg(MANDOCERR_XR_ORDER,
1818 				    mdoc->parse, n->line, n->pos,
1819 				    "%s after %s", name, lastname);
1820 		}
1821 		lastname = name;
1822 		lastsec = sec;
1823 
1824 		/* Process the following node. */
1825 
1826 		n = n->next;
1827 		if (n == NULL)
1828 			break;
1829 		if (n->tok == MDOC_Xr) {
1830 			lastpunct = "none";
1831 			continue;
1832 		}
1833 		if (n->type != MDOC_TEXT)
1834 			break;
1835 		for (name = n->string; *name != '\0'; name++)
1836 			if (isalpha((const unsigned char)*name))
1837 				return;
1838 		lastpunct = n->string;
1839 		if (n->next == NULL)
1840 			mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse,
1841 			    n->line, n->pos, "%s after %s(%s)",
1842 			    lastpunct, lastname, lastsec);
1843 		n = n->next;
1844 	}
1845 }
1846 
1847 static int
1848 child_an(const struct mdoc_node *n)
1849 {
1850 
1851 	for (n = n->child; n != NULL; n = n->next)
1852 		if ((n->tok == MDOC_An && n->nchild) || child_an(n))
1853 			return(1);
1854 	return(0);
1855 }
1856 
1857 static void
1858 post_sh_authors(POST_ARGS)
1859 {
1860 
1861 	if ( ! child_an(mdoc->last))
1862 		mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse,
1863 		    mdoc->last->line, mdoc->last->pos, NULL);
1864 }
1865 
1866 static void
1867 post_sh_head(POST_ARGS)
1868 {
1869 	struct mdoc_node *n;
1870 	const char	*goodsec;
1871 	char		*secname;
1872 	enum mdoc_sec	 sec;
1873 
1874 	/*
1875 	 * Process a new section.  Sections are either "named" or
1876 	 * "custom".  Custom sections are user-defined, while named ones
1877 	 * follow a conventional order and may only appear in certain
1878 	 * manual sections.
1879 	 */
1880 
1881 	secname = NULL;
1882 	sec = SEC_CUSTOM;
1883 	mdoc_deroff(&secname, mdoc->last);
1884 	sec = NULL == secname ? SEC_CUSTOM : a2sec(secname);
1885 
1886 	/* The NAME should be first. */
1887 
1888 	if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1889 		mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
1890 		    mdoc->last->line, mdoc->last->pos,
1891 		    "Sh %s", secname);
1892 
1893 	/* The SYNOPSIS gets special attention in other areas. */
1894 
1895 	if (SEC_SYNOPSIS == sec) {
1896 		roff_setreg(mdoc->roff, "nS", 1, '=');
1897 		mdoc->flags |= MDOC_SYNOPSIS;
1898 	} else {
1899 		roff_setreg(mdoc->roff, "nS", 0, '=');
1900 		mdoc->flags &= ~MDOC_SYNOPSIS;
1901 	}
1902 
1903 	/* Mark our last section. */
1904 
1905 	mdoc->lastsec = sec;
1906 
1907 	/*
1908 	 * Set the section attribute for the current HEAD, for its
1909 	 * parent BLOCK, and for the HEAD children; the latter can
1910 	 * only be TEXT nodes, so no recursion is needed.
1911 	 * For other blocks and elements, including .Sh BODY, this is
1912 	 * done when allocating the node data structures, but for .Sh
1913 	 * BLOCK and HEAD, the section is still unknown at that time.
1914 	 */
1915 
1916 	mdoc->last->parent->sec = sec;
1917 	mdoc->last->sec = sec;
1918 	for (n = mdoc->last->child; n; n = n->next)
1919 		n->sec = sec;
1920 
1921 	/* We don't care about custom sections after this. */
1922 
1923 	if (SEC_CUSTOM == sec) {
1924 		free(secname);
1925 		return;
1926 	}
1927 
1928 	/*
1929 	 * Check whether our non-custom section is being repeated or is
1930 	 * out of order.
1931 	 */
1932 
1933 	if (sec == mdoc->lastnamed)
1934 		mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse,
1935 		    mdoc->last->line, mdoc->last->pos,
1936 		    "Sh %s", secname);
1937 
1938 	if (sec < mdoc->lastnamed)
1939 		mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse,
1940 		    mdoc->last->line, mdoc->last->pos,
1941 		    "Sh %s", secname);
1942 
1943 	/* Mark the last named section. */
1944 
1945 	mdoc->lastnamed = sec;
1946 
1947 	/* Check particular section/manual conventions. */
1948 
1949 	if (mdoc->meta.msec == NULL) {
1950 		free(secname);
1951 		return;
1952 	}
1953 
1954 	goodsec = NULL;
1955 	switch (sec) {
1956 	case SEC_ERRORS:
1957 		if (*mdoc->meta.msec == '4')
1958 			break;
1959 		goodsec = "2, 3, 4, 9";
1960 		/* FALLTHROUGH */
1961 	case SEC_RETURN_VALUES:
1962 		/* FALLTHROUGH */
1963 	case SEC_LIBRARY:
1964 		if (*mdoc->meta.msec == '2')
1965 			break;
1966 		if (*mdoc->meta.msec == '3')
1967 			break;
1968 		if (NULL == goodsec)
1969 			goodsec = "2, 3, 9";
1970 		/* FALLTHROUGH */
1971 	case SEC_CONTEXT:
1972 		if (*mdoc->meta.msec == '9')
1973 			break;
1974 		if (NULL == goodsec)
1975 			goodsec = "9";
1976 		mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse,
1977 		    mdoc->last->line, mdoc->last->pos,
1978 		    "Sh %s for %s only", secname, goodsec);
1979 		break;
1980 	default:
1981 		break;
1982 	}
1983 	free(secname);
1984 }
1985 
1986 static void
1987 post_ignpar(POST_ARGS)
1988 {
1989 	struct mdoc_node *np;
1990 
1991 	switch (mdoc->last->type) {
1992 	case MDOC_HEAD:
1993 		post_hyph(mdoc);
1994 		return;
1995 	case MDOC_BODY:
1996 		break;
1997 	default:
1998 		return;
1999 	}
2000 
2001 	if (NULL != (np = mdoc->last->child))
2002 		if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2003 			mandoc_vmsg(MANDOCERR_PAR_SKIP,
2004 			    mdoc->parse, np->line, np->pos,
2005 			    "%s after %s", mdoc_macronames[np->tok],
2006 			    mdoc_macronames[mdoc->last->tok]);
2007 			mdoc_node_delete(mdoc, np);
2008 		}
2009 
2010 	if (NULL != (np = mdoc->last->last))
2011 		if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2012 			mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2013 			    np->line, np->pos, "%s at the end of %s",
2014 			    mdoc_macronames[np->tok],
2015 			    mdoc_macronames[mdoc->last->tok]);
2016 			mdoc_node_delete(mdoc, np);
2017 		}
2018 }
2019 
2020 static void
2021 pre_par(PRE_ARGS)
2022 {
2023 
2024 	if (NULL == mdoc->last)
2025 		return;
2026 	if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
2027 		return;
2028 
2029 	/*
2030 	 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
2031 	 * block:  `Lp', `Pp', or non-compact `Bd' or `Bl'.
2032 	 */
2033 
2034 	if (MDOC_Pp != mdoc->last->tok &&
2035 	    MDOC_Lp != mdoc->last->tok &&
2036 	    MDOC_br != mdoc->last->tok)
2037 		return;
2038 	if (MDOC_Bl == n->tok && n->norm->Bl.comp)
2039 		return;
2040 	if (MDOC_Bd == n->tok && n->norm->Bd.comp)
2041 		return;
2042 	if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
2043 		return;
2044 
2045 	mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2046 	    mdoc->last->line, mdoc->last->pos,
2047 	    "%s before %s", mdoc_macronames[mdoc->last->tok],
2048 	    mdoc_macronames[n->tok]);
2049 	mdoc_node_delete(mdoc, mdoc->last);
2050 }
2051 
2052 static void
2053 post_par(POST_ARGS)
2054 {
2055 	struct mdoc_node *np;
2056 
2057 	np = mdoc->last;
2058 
2059 	if (np->tok == MDOC_sp) {
2060 		if (np->nchild > 1)
2061 			mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
2062 			    np->child->next->line, np->child->next->pos,
2063 			    "sp ... %s", np->child->next->string);
2064 	} else if (np->child != NULL)
2065 		mandoc_vmsg(MANDOCERR_ARG_SKIP,
2066 		    mdoc->parse, np->line, np->pos, "%s %s",
2067 		    mdoc_macronames[np->tok], np->child->string);
2068 
2069 	if (NULL == (np = mdoc->last->prev)) {
2070 		np = mdoc->last->parent;
2071 		if (MDOC_Sh != np->tok && MDOC_Ss != np->tok)
2072 			return;
2073 	} else if (MDOC_Pp != np->tok && MDOC_Lp != np->tok &&
2074 	    (MDOC_br != mdoc->last->tok ||
2075 	     (MDOC_sp != np->tok && MDOC_br != np->tok)))
2076 		return;
2077 
2078 	mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2079 	    mdoc->last->line, mdoc->last->pos,
2080 	    "%s after %s", mdoc_macronames[mdoc->last->tok],
2081 	    mdoc_macronames[np->tok]);
2082 	mdoc_node_delete(mdoc, mdoc->last);
2083 }
2084 
2085 static void
2086 pre_literal(PRE_ARGS)
2087 {
2088 
2089 	pre_display(mdoc, n);
2090 
2091 	if (MDOC_BODY != n->type)
2092 		return;
2093 
2094 	/*
2095 	 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
2096 	 * -unfilled' macros set MDOC_LITERAL on entrance to the body.
2097 	 */
2098 
2099 	switch (n->tok) {
2100 	case MDOC_Dl:
2101 		mdoc->flags |= MDOC_LITERAL;
2102 		break;
2103 	case MDOC_Bd:
2104 		if (DISP_literal == n->norm->Bd.type)
2105 			mdoc->flags |= MDOC_LITERAL;
2106 		if (DISP_unfilled == n->norm->Bd.type)
2107 			mdoc->flags |= MDOC_LITERAL;
2108 		break;
2109 	default:
2110 		abort();
2111 		/* NOTREACHED */
2112 	}
2113 }
2114 
2115 static void
2116 post_dd(POST_ARGS)
2117 {
2118 	struct mdoc_node *n;
2119 	char		 *datestr;
2120 
2121 	if (mdoc->meta.date)
2122 		free(mdoc->meta.date);
2123 
2124 	n = mdoc->last;
2125 	if (NULL == n->child || '\0' == n->child->string[0]) {
2126 		mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
2127 		    mandoc_normdate(mdoc->parse, NULL, n->line, n->pos);
2128 		goto out;
2129 	}
2130 
2131 	datestr = NULL;
2132 	mdoc_deroff(&datestr, n);
2133 	if (mdoc->quick)
2134 		mdoc->meta.date = datestr;
2135 	else {
2136 		mdoc->meta.date = mandoc_normdate(mdoc->parse,
2137 		    datestr, n->line, n->pos);
2138 		free(datestr);
2139 	}
2140 out:
2141 	mdoc_node_delete(mdoc, n);
2142 }
2143 
2144 static void
2145 post_dt(POST_ARGS)
2146 {
2147 	struct mdoc_node *nn, *n;
2148 	const char	 *cp;
2149 	char		 *p;
2150 
2151 	n = mdoc->last;
2152 
2153 	free(mdoc->meta.title);
2154 	free(mdoc->meta.msec);
2155 	free(mdoc->meta.vol);
2156 	free(mdoc->meta.arch);
2157 
2158 	mdoc->meta.title = NULL;
2159 	mdoc->meta.msec = NULL;
2160 	mdoc->meta.vol = NULL;
2161 	mdoc->meta.arch = NULL;
2162 
2163 	/* Mandatory first argument: title. */
2164 
2165 	nn = n->child;
2166 	if (nn == NULL || *nn->string == '\0') {
2167 		mandoc_msg(MANDOCERR_DT_NOTITLE,
2168 		    mdoc->parse, n->line, n->pos, "Dt");
2169 		mdoc->meta.title = mandoc_strdup("UNTITLED");
2170 	} else {
2171 		mdoc->meta.title = mandoc_strdup(nn->string);
2172 
2173 		/* Check that all characters are uppercase. */
2174 
2175 		for (p = nn->string; *p != '\0'; p++)
2176 			if (islower((unsigned char)*p)) {
2177 				mandoc_vmsg(MANDOCERR_TITLE_CASE,
2178 				    mdoc->parse, nn->line,
2179 				    nn->pos + (p - nn->string),
2180 				    "Dt %s", nn->string);
2181 				break;
2182 			}
2183 	}
2184 
2185 	/* Mandatory second argument: section.�*/
2186 
2187 	if (nn != NULL)
2188 		nn = nn->next;
2189 
2190 	if (nn == NULL) {
2191 		mandoc_vmsg(MANDOCERR_MSEC_MISSING,
2192 		    mdoc->parse, n->line, n->pos,
2193 		    "Dt %s", mdoc->meta.title);
2194 		mdoc->meta.vol = mandoc_strdup("LOCAL");
2195 		goto out;  /* msec and arch remain NULL. */
2196 	}
2197 
2198 	mdoc->meta.msec = mandoc_strdup(nn->string);
2199 
2200 	/* Infer volume title from section number. */
2201 
2202 	cp = mandoc_a2msec(nn->string);
2203 	if (cp == NULL) {
2204 		mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse,
2205 		    nn->line, nn->pos, "Dt ... %s", nn->string);
2206 		mdoc->meta.vol = mandoc_strdup(nn->string);
2207 	} else
2208 		mdoc->meta.vol = mandoc_strdup(cp);
2209 
2210 	/* Optional third argument: architecture. */
2211 
2212 	if ((nn = nn->next) == NULL)
2213 		goto out;
2214 
2215 	for (p = nn->string; *p != '\0'; p++)
2216 		*p = tolower((unsigned char)*p);
2217 	mdoc->meta.arch = mandoc_strdup(nn->string);
2218 
2219 	/* Ignore fourth and later arguments. */
2220 
2221 	if ((nn = nn->next) != NULL)
2222 		mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
2223 		    nn->line, nn->pos, "Dt ... %s", nn->string);
2224 
2225 out:
2226 	mdoc_node_delete(mdoc, n);
2227 }
2228 
2229 static void
2230 post_bx(POST_ARGS)
2231 {
2232 	struct mdoc_node	*n;
2233 
2234 	/*
2235 	 * Make `Bx's second argument always start with an uppercase
2236 	 * letter.  Groff checks if it's an "accepted" term, but we just
2237 	 * uppercase blindly.
2238 	 */
2239 
2240 	n = mdoc->last->child;
2241 	if (n && NULL != (n = n->next))
2242 		*n->string = (char)toupper((unsigned char)*n->string);
2243 }
2244 
2245 static void
2246 post_os(POST_ARGS)
2247 {
2248 #ifndef OSNAME
2249 	struct utsname	  utsname;
2250 	static char	 *defbuf;
2251 #endif
2252 	struct mdoc_node *n;
2253 
2254 	n = mdoc->last;
2255 
2256 	/*
2257 	 * Set the operating system by way of the `Os' macro.
2258 	 * The order of precedence is:
2259 	 * 1. the argument of the `Os' macro, unless empty
2260 	 * 2. the -Ios=foo command line argument, if provided
2261 	 * 3. -DOSNAME="\"foo\"", if provided during compilation
2262 	 * 4. "sysname release" from uname(3)
2263 	 */
2264 
2265 	free(mdoc->meta.os);
2266 	mdoc->meta.os = NULL;
2267 	mdoc_deroff(&mdoc->meta.os, n);
2268 	if (mdoc->meta.os)
2269 		goto out;
2270 
2271 	if (mdoc->defos) {
2272 		mdoc->meta.os = mandoc_strdup(mdoc->defos);
2273 		goto out;
2274 	}
2275 
2276 #ifdef OSNAME
2277 	mdoc->meta.os = mandoc_strdup(OSNAME);
2278 #else /*!OSNAME */
2279 	if (NULL == defbuf) {
2280 		if (-1 == uname(&utsname)) {
2281 			mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse,
2282 			    n->line, n->pos, "Os");
2283 			defbuf = mandoc_strdup("UNKNOWN");
2284 		} else
2285 			mandoc_asprintf(&defbuf, "%s %s",
2286 			    utsname.sysname, utsname.release);
2287 	}
2288 	mdoc->meta.os = mandoc_strdup(defbuf);
2289 #endif /*!OSNAME*/
2290 
2291 out:
2292 	mdoc_node_delete(mdoc, n);
2293 }
2294 
2295 /*
2296  * If no argument is provided,
2297  * fill in the name of the current manual page.
2298  */
2299 static void
2300 post_ex(POST_ARGS)
2301 {
2302 	struct mdoc_node *n;
2303 
2304 	n = mdoc->last;
2305 
2306 	if (n->child)
2307 		return;
2308 
2309 	if (mdoc->meta.name == NULL) {
2310 		mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse,
2311 		    n->line, n->pos, "Ex");
2312 		return;
2313 	}
2314 
2315 	mdoc->next = MDOC_NEXT_CHILD;
2316 	mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name);
2317 	mdoc->last = n;
2318 }
2319 
2320 static enum mdoc_sec
2321 a2sec(const char *p)
2322 {
2323 	int		 i;
2324 
2325 	for (i = 0; i < (int)SEC__MAX; i++)
2326 		if (secnames[i] && 0 == strcmp(p, secnames[i]))
2327 			return((enum mdoc_sec)i);
2328 
2329 	return(SEC_CUSTOM);
2330 }
2331 
2332 static size_t
2333 macro2len(enum mdoct macro)
2334 {
2335 
2336 	switch (macro) {
2337 	case MDOC_Ad:
2338 		return(12);
2339 	case MDOC_Ao:
2340 		return(12);
2341 	case MDOC_An:
2342 		return(12);
2343 	case MDOC_Aq:
2344 		return(12);
2345 	case MDOC_Ar:
2346 		return(12);
2347 	case MDOC_Bo:
2348 		return(12);
2349 	case MDOC_Bq:
2350 		return(12);
2351 	case MDOC_Cd:
2352 		return(12);
2353 	case MDOC_Cm:
2354 		return(10);
2355 	case MDOC_Do:
2356 		return(10);
2357 	case MDOC_Dq:
2358 		return(12);
2359 	case MDOC_Dv:
2360 		return(12);
2361 	case MDOC_Eo:
2362 		return(12);
2363 	case MDOC_Em:
2364 		return(10);
2365 	case MDOC_Er:
2366 		return(17);
2367 	case MDOC_Ev:
2368 		return(15);
2369 	case MDOC_Fa:
2370 		return(12);
2371 	case MDOC_Fl:
2372 		return(10);
2373 	case MDOC_Fo:
2374 		return(16);
2375 	case MDOC_Fn:
2376 		return(16);
2377 	case MDOC_Ic:
2378 		return(10);
2379 	case MDOC_Li:
2380 		return(16);
2381 	case MDOC_Ms:
2382 		return(6);
2383 	case MDOC_Nm:
2384 		return(10);
2385 	case MDOC_No:
2386 		return(12);
2387 	case MDOC_Oo:
2388 		return(10);
2389 	case MDOC_Op:
2390 		return(14);
2391 	case MDOC_Pa:
2392 		return(32);
2393 	case MDOC_Pf:
2394 		return(12);
2395 	case MDOC_Po:
2396 		return(12);
2397 	case MDOC_Pq:
2398 		return(12);
2399 	case MDOC_Ql:
2400 		return(16);
2401 	case MDOC_Qo:
2402 		return(12);
2403 	case MDOC_So:
2404 		return(12);
2405 	case MDOC_Sq:
2406 		return(12);
2407 	case MDOC_Sy:
2408 		return(6);
2409 	case MDOC_Sx:
2410 		return(16);
2411 	case MDOC_Tn:
2412 		return(10);
2413 	case MDOC_Va:
2414 		return(12);
2415 	case MDOC_Vt:
2416 		return(12);
2417 	case MDOC_Xr:
2418 		return(10);
2419 	default:
2420 		break;
2421 	};
2422 	return(0);
2423 }
2424