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